diff options
Diffstat (limited to 'src')
184 files changed, 18878 insertions, 10766 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 200f5beb..d5a713b1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,146 +1,234 @@ -add_subdirectory(gpg) -add_subdirectory(ui) -add_subdirectory(smtp) -add_subdirectory(server) -add_subdirectory(advance) - -aux_source_directory(. BASE_SOURCE) - -set(APP_ICON_RESOURCE_WINDOWS "${CMAKE_SOURCE_DIR}/gpgfrontend.rc") -set_property(SOURCE gpgfrontend.rc APPEND PROPERTY OBJECT_DEPENDS ${CMAKE_SOURCE_DIR}/gpgfrontend.ico) - - -file(GLOB_RECURSE GPGFRONTEND_HEADER_FILES RELACTIVE ${CMAKE_SOURCE_DIR}/include/*.h) -qt5_wrap_cpp(QT5_MOCS ${GPGFRONTEND_HEADER_FILES} TARGET ${AppName}) - -# Set Binary Output Path -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/release) -message(STATUS "CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}") - -# Set Resource Output Path -if(${CMAKE_BUILD_TYPE} STREQUAL "Release") - if(APPLE) - set(RESOURCE_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Resources) - elseif(LINUX) - file(COPY ${CMAKE_SOURCE_DIR}/resource/gpgfrontend DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN) - set(RESOURCE_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/gpgfrontend/usr/share) - else() +if (GPG_CORE) + message(STATUS "Build Gpg Core") + add_subdirectory(gpg) +endif () + +if (UI_CORE) + message(STATUS "Build UI Core") + add_subdirectory(ui) +endif () + +if (SMTP_SUPPORT) + message(STATUS "Build SMTP Support") + add_compile_definitions(SMTP_SUPPORT) + add_subdirectory(smtp) +endif () + +if (SERVER_SUPPORT) + message(STATUS "Build Server Support") + add_compile_definitions(SERVER_SUPPORT) + add_subdirectory(server) +endif () + +if (ADVANCE_SUPPORT) + message(STATUS "Build Advance Support") + add_compile_definitions(ADVANCE_SUPPORT) + add_subdirectory(advance) +endif () + +if (APPLICATION_BUILD) + aux_source_directory(. BASE_SOURCE) + set(APP_ICON_RESOURCE_WINDOWS "${CMAKE_SOURCE_DIR}/gpgfrontend.rc") + set_property(SOURCE gpgfrontend.rc APPEND PROPERTY OBJECT_DEPENDS ${CMAKE_SOURCE_DIR}/gpgfrontend.ico) + + # Set Binary Output Path + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/release) + message(STATUS "CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}") +endif () + + +if (APPLICATION_BUILD) + # Set Resource Output Path + if (${CMAKE_BUILD_TYPE} STREQUAL "Release") + if (APPLE) + set(RESOURCE_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Resources) + elseif (LINUX) + file(COPY ${CMAKE_SOURCE_DIR}/resource/gpgfrontend DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN) + set(RESOURCE_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/gpgfrontend/usr/share) + else () + set(RESOURCE_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) + endif () + else () set(RESOURCE_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) - endif() -else() - set(RESOURCE_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) -endif() -message(STATUS "RESOURCE_OUTPUT_DIRECTORY ${RESOURCE_OUTPUT_DIRECTORY}") + endif () + message(STATUS "RESOURCE_OUTPUT_DIRECTORY ${RESOURCE_OUTPUT_DIRECTORY}") +endif () # Get ALL SOURCE FILES file(GLOB_RECURSE ALL_SOURCE_FILES RELACTIVE ${CMAKE_SOURCE_DIR}/src/*.cpp) -# Set Translation Files -set(QT_TS_FILES - gpgfrontend_en_us.ts gpgfrontend_zh_cn.ts - gpgfrontend_fr.ts gpgfrontend_ru.ts gpgfrontend_es.ts) -list(TRANSFORM QT_TS_FILES PREPEND ${CMAKE_SOURCE_DIR}/resource/ts/) -message(STATUS "QT_TS_FILES ${QT_TS_FILES}") -set(QT_QM_FILES_OUTPUT_DIR ${RESOURCE_OUTPUT_DIRECTORY}/ts) -set_source_files_properties(${QT_TS_FILES} PROPERTIES OUTPUT_LOCATION ${QT_QM_FILES_OUTPUT_DIR}) -QT5_create_translation(QON_QM_FILES ${CMAKE_SOURCE_DIR} ${QT_TS_FILES}) -message(STATUS "QON_QM_FILES ${QON_QM_FILES}") -add_custom_target(translations DEPENDS ${QON_QM_FILES}) - -# Set Build Information -configure_file(${CMAKE_SOURCE_DIR}/include/GpgFrontend.h.in ${CMAKE_SOURCE_DIR}/include/GpgFrontend.h @ONLY) -configure_file(${CMAKE_SOURCE_DIR}/include/GpgFrontendBuildInfo.h.in ${CMAKE_SOURCE_DIR}/include/GpgFrontendBuildInfo.h @ONLY) - -# Copy Resource Files -file(COPY ${CMAKE_SOURCE_DIR}/resource/css DESTINATION ${RESOURCE_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN) -file(COPY ${CMAKE_SOURCE_DIR}/resource/icons DESTINATION ${RESOURCE_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN) -file(COPY ${CMAKE_SOURCE_DIR}/resource/conf DESTINATION ${RESOURCE_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN) - -if(${CMAKE_BUILD_TYPE} STREQUAL "Release") - if(APPLE) - file(COPY ${CMAKE_SOURCE_DIR}/gpgfrontend.icns DESTINATION ${RESOURCE_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN) - # Refresh App Bundle - file(REMOVE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${AppName}.app) - elseif(LINUX) - file(REMOVE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/gpgfrontend/usr/bin/${AppName}) - endif() -endif() - -# Copy Utils Files -if(MINGW) - message(STATUS "Copying Dependent DLL For Windows Runtime Env") - file(COPY ${CMAKE_SOURCE_DIR}/resource/utils/lib/ DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN) - file(COPY ${CMAKE_SOURCE_DIR}/resource/utils/gpgme/ DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN) - file(COPY ${CMAKE_SOURCE_DIR}/resource/utils/bearer DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN) - file(COPY ${CMAKE_SOURCE_DIR}/resource/utils/iconengines DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN) - file(COPY ${CMAKE_SOURCE_DIR}/resource/utils/imageformats DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN) - file(COPY ${CMAKE_SOURCE_DIR}/resource/utils/printsupport DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN) - file(COPY ${CMAKE_SOURCE_DIR}/resource/utils/platforms DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN) - file(COPY ${CMAKE_SOURCE_DIR}/resource/utils/openssl/ DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN) -endif() - -set(RESOURCE_FILES ${CMAKE_SOURCE_DIR}/gpgfrontend.qrc ${APP_ICON_RESOURCE_WINDOWS} ${QON_QM_FILES}) -add_custom_target(resources ALL DEPENDS ${RESOURCE_FILES}) -add_dependencies(resources translations) - -if(${CMAKE_BUILD_TYPE} STREQUAL "Release") - if(MINGW) - add_executable(${AppName} WIN32 ${BASE_SOURCE} ${RESOURCE_FILES} ${QT5_MOCS}) - elseif(APPLE) - add_executable(${AppName} MACOSX_BUNDLE ${ICON_RESOURCE} ${BASE_SOURCE} ${RESOURCE_FILES} ${QT5_MOCS}) - set_target_properties(${AppName} PROPERTIES - BUNDLE True - MACOSX_BUNDLE_GUI_IDENTIFIER pub.gpgfrontend.gpgfrontend - MACOSX_BUNDLE_BUNDLE_NAME ${AppName} - MACOSX_BUNDLE_LONG_VERSION_STRING ${BUILD_VERSION} - MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION} - MACOSX_BUNDLE_BUNDLE_VERSION ${BUILD_VERSION} - MACOSX_BUNDLE_ICON_FILE "gpgfrontend.icns") - add_custom_command(TARGET ${AppName} POST_BUILD - COMMAND /bin/rm -rf ./${AppName}.app/Contents/Resources - WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} - COMMENT "Deleting Resources in App Bundle") - add_custom_command(TARGET ${AppName} POST_BUILD - COMMAND /bin/mv -n ./Resources ./${AppName}.app/Contents/ - WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} - COMMENT "Copying Resources into App Bundle Resource") - elseif(LINUX) - add_executable(${AppName} ${BASE_SOURCE} ${RESOURCE_FILES} ${QT5_MOCS}) - add_custom_command(TARGET ${AppName} POST_BUILD - COMMAND /bin/mkdir ./gpgfrontend/usr/bin && /bin/mv -f ./${AppName} ./gpgfrontend/usr/bin/ - WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} - COMMENT "Copying Binary into App Image") - add_custom_command(TARGET ${AppName} POST_BUILD - COMMAND /bin/mkdir ./gpgfrontend/usr/lib - WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} - COMMENT "Complement to build the required architecture") - else() +# i18n +if (MULTI_LANG_SUPPORT) + message(STATUS "Build Multiply Languages Support") + # Set Translation Files + find_package(Gettext REQUIRED) + FIND_PROGRAM(GETTEXT_MSGFMT_EXECUTABLE msgfmt) + FIND_PROGRAM(GETTEXT_XGETTEXT_EXECUTABLE xgettext) + if (NOT GETTEXT_MSGFMT_EXECUTABLE OR NOT GETTEXT_XGETTEXT_EXECUTABLE) + message(ERROR "msgfmt or xgettext not found. Translations will *not* be installed") + else (NOT GETTEXT_MSGFMT_EXECUTABLE) + message(STATUS "Setting target translations") + add_custom_target(translations) + set(OUTPUT_POT_PATH ${CMAKE_SOURCE_DIR}/resource/locale/template/${PROJECT_NAME}.pot) + add_custom_command( + TARGET translations + COMMAND find ${CMAKE_SOURCE_DIR}/src -iname \"*.cpp\" | xargs xgettext --package-name=${PROJECT_NAME} --copyright-holder=Saturneric --package-version=${PROJECT_VERSION} [email protected] --add-comments="/*" --c++ -k_ -o ${OUTPUT_POT_PATH} + ) + + file(GLOB ALL_PO_FILES ${CMAKE_SOURCE_DIR}/resource/locale/po/*.po) + SET(GMO_FILES) + message(STATUS "ALL_PO_FILES ${ALL_PO_FILES}") + + foreach (_poFile ${ALL_PO_FILES}) + GET_FILENAME_COMPONENT(_poFileName ${_poFile} NAME) + string(REGEX REPLACE "\\.[^.]*$" "" _langName ${_poFileName}) + message(STATUS "_poFileName ${_langName}") + make_directory(${CMAKE_SOURCE_DIR}/resource/locale/out/${_langName}/LC_MESSAGES) + add_custom_command( + TARGET translations + COMMAND echo Processing po LANG ${_langName} + ) + add_custom_command( + TARGET translations + COMMAND msgfmt --check --verbose --output-file ${CMAKE_SOURCE_DIR}/resource/locale/out/${_langName}/LC_MESSAGES/GpgFrontend.mo ${_poFile} + ) + endforeach () + + endif () +endif () + +if (BASIC_ENV_CONFIG) + # Set Build Information + configure_file(${CMAKE_SOURCE_DIR}/src/GpgFrontend.h.in ${CMAKE_SOURCE_DIR}/src/GpgFrontend.h @ONLY) + configure_file(${CMAKE_SOURCE_DIR}/src/GpgFrontendBuildInfo.h.in ${CMAKE_SOURCE_DIR}/src/GpgFrontendBuildInfo.h @ONLY) +endif () + +if (APPLICATION_BUILD) + # Copy Resource Files + file(COPY ${CMAKE_SOURCE_DIR}/resource/css DESTINATION ${RESOURCE_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN) + file(COPY ${CMAKE_SOURCE_DIR}/resource/icons DESTINATION ${RESOURCE_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN) + if (MULTI_LANG_SUPPORT) + make_directory(${RESOURCE_OUTPUT_DIRECTORY}/locales) + file(COPY ${CMAKE_SOURCE_DIR}/resource/locale/out/ DESTINATION ${RESOURCE_OUTPUT_DIRECTORY}/locales FOLLOW_SYMLINK_CHAIN) + endif () +endif () + +if (APPLICATION_BUILD) + if (${CMAKE_BUILD_TYPE} STREQUAL "Release") + if (APPLE) + file(COPY ${CMAKE_SOURCE_DIR}/gpgfrontend.icns DESTINATION ${RESOURCE_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN) + # Refresh App Bundle + file(REMOVE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${AppName}.app) + elseif (LINUX) + file(REMOVE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/gpgfrontend/usr/bin/${AppName}) + endif () + endif () +endif () + +if (APPLICATION_BUILD) + # Copy Utils Files + if (MINGW) + message(STATUS "Copying Dependent DLL For Windows Runtime Env") + file(COPY ${CMAKE_SOURCE_DIR}/resource/utils/lib/ DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN) + file(COPY ${CMAKE_SOURCE_DIR}/resource/utils/gpgme/ DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN) + file(COPY ${CMAKE_SOURCE_DIR}/resource/utils/bearer DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN) + file(COPY ${CMAKE_SOURCE_DIR}/resource/utils/iconengines DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN) + file(COPY ${CMAKE_SOURCE_DIR}/resource/utils/imageformats DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN) + file(COPY ${CMAKE_SOURCE_DIR}/resource/utils/printsupport DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN) + file(COPY ${CMAKE_SOURCE_DIR}/resource/utils/platforms DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN) + file(COPY ${CMAKE_SOURCE_DIR}/resource/utils/openssl/ DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN) + endif () +endif () + +if (APPLICATION_BUILD) + set(RESOURCE_FILES ${CMAKE_SOURCE_DIR}/gpgfrontend.qrc ${APP_ICON_RESOURCE_WINDOWS} ${QON_QM_FILES}) + add_custom_target(resources ALL DEPENDS ${RESOURCE_FILES}) + if (MULTI_LANG_SUPPORT) + add_dependencies(resources translations) + endif () +endif () + +if (APPLICATION_BUILD) + if (${CMAKE_BUILD_TYPE} STREQUAL "Release") + if (MINGW) + add_executable(${AppName} WIN32 ${BASE_SOURCE} ${RESOURCE_FILES} ${QT5_MOCS}) + elseif (APPLE) + add_executable(${AppName} MACOSX_BUNDLE ${ICON_RESOURCE} ${BASE_SOURCE} ${RESOURCE_FILES} ${QT5_MOCS}) + set_target_properties(${AppName} PROPERTIES + BUNDLE True + MACOSX_BUNDLE_GUI_IDENTIFIER pub.gpgfrontend.gpgfrontend + MACOSX_BUNDLE_BUNDLE_NAME ${AppName} + MACOSX_BUNDLE_LONG_VERSION_STRING ${BUILD_VERSION} + MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION} + MACOSX_BUNDLE_BUNDLE_VERSION ${BUILD_VERSION} + MACOSX_BUNDLE_ICON_FILE "gpgfrontend.icns") + add_custom_command(TARGET ${AppName} POST_BUILD + COMMAND /bin/rm -rf ./${AppName}.app/Contents/Resources + WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} + COMMENT "Deleting Resources in App Bundle") + add_custom_command(TARGET ${AppName} POST_BUILD + COMMAND /bin/mv -n ./Resources ./${AppName}.app/Contents/ + WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} + COMMENT "Copying Resources into App Bundle Resource") + elseif (LINUX) + add_executable(${AppName} ${BASE_SOURCE} ${RESOURCE_FILES} ${QT5_MOCS}) + add_custom_command(TARGET ${AppName} POST_BUILD + COMMAND /bin/mkdir -p ./gpgfrontend/usr/bin && /bin/mv -f ./${AppName} ./gpgfrontend/usr/bin/ + WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} + COMMENT "Copying Binary into App Image") + add_custom_command(TARGET ${AppName} POST_BUILD + COMMAND /bin/mkdir -p ./gpgfrontend/usr/lib + WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} + COMMENT "Complement to build the required architecture") + else () + add_executable(${AppName} ${BASE_SOURCE} ${RESOURCE_FILES} ${QT5_MOCS}) + endif () + else () add_executable(${AppName} ${BASE_SOURCE} ${RESOURCE_FILES} ${QT5_MOCS}) - endif() -else() - add_executable(${AppName} ${BASE_SOURCE} ${RESOURCE_FILES} ${QT5_MOCS}) -endif() - -set(GPGFRONTEND_LIBS smtp gpgfrontend-ui advance server gpg) -set(QT_DEPENDENCY_LIBS Qt5::Network Qt5::PrintSupport Qt5::Widgets Qt5::Test Qt5::Core) - -IF (MINGW) - message(STATUS "Link Application Static Library For MINGW") - target_link_libraries(${AppName} - ${GPGFRONTEND_LIBS} - ${QT_DEPENDENCY_LIBS} - crypto ssl) -elseif(APPLE) - message(STATUS "Link Application Static Library For macOS") - target_link_libraries(${AppName} - ${GPGFRONTEND_LIBS} - ${QT_DEPENDENCY_LIBS} - crypto ssl) -else() - message(STATUS "Link Application Static Library For UNIX") - target_link_libraries(${AppName} - ${GPGFRONTEND_LIBS} - ${QT_DEPENDENCY_LIBS} - crypto ssl pthread) -endif() + endif () + + # Make app build with resources + add_dependencies(${AppName} resources) + +endif () + +if (APPLICATION_BUILD) + + if (ADVANCE_SUPPORT) + set(GPGFRONTEND_BEFORE_UI_LIBS ${GPGFRONTEND_BEFORE_UI_LIBS} advance) + endif () + if (ADVANCE_SUPPORT) + set(GPGFRONTEND_BEFORE_UI_LIBS ${GPGFRONTEND_BEFORE_UI_LIBS} server) + endif () + if (SMTP_SUPPORT) + set(GPGFRONTEND_AFTER_UI_LIBS ${GPGFRONTEND_AFTER_UI_LIBS} server) + endif () + + set(GPGFRONTEND_LIBS ${GPGFRONTEND_AFTER_UI_LIBS} gpgfrontend-ui ${GPGFRONTEND_BEFORE_UI_LIBS} gpg_core easy_logging_pp) + set(QT_DEPENDENCY_LIBS Qt5::Network Qt5::PrintSupport Qt5::Widgets Qt5::Test Qt5::Core) + + IF (MINGW) + message(STATUS "Link Application Static Library For MINGW") + find_library(libconfig NAMES libconfig++.a) + find_library(libintl NAMES libintl.a) + find_library(libiconv NAMES libiconv.a) + + target_link_libraries(${AppName} + ${GPGFRONTEND_LIBS} + ${QT_DEPENDENCY_LIBS} + ${libintl} ${libiconv} ${libconfig} crypto ssl) + elseif (APPLE) + message(STATUS "Link Application Static Library For macOS") + target_link_libraries(${AppName} + ${GPGFRONTEND_LIBS} + ${QT_DEPENDENCY_LIBS} + crypto ssl intl) + else () + message(STATUS "Link Application Static Library For UNIX ") + target_link_libraries(${AppName} + ${GPGFRONTEND_LIBS} + ${QT_DEPENDENCY_LIBS} + crypto ssl pthread) + endif () +endif () diff --git a/src/GpgFrontend.h.in b/src/GpgFrontend.h.in new file mode 100644 index 00000000..622c2b07 --- /dev/null +++ b/src/GpgFrontend.h.in @@ -0,0 +1,63 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_H_IN +#define GPGFRONTEND_H_IN + +// i18n +#ifdef WINDOWS +#include <winsock2.h> +#include <windows.h> +#endif + +#include <libintl.h> +#define _(String) gettext (String) +#define gettext_noop(String) String +#define N_(String) gettext_noop (String) + +#ifdef WINDOWS +#include <clocale> +#undef vsnprintf +#endif + +// logging +#define ELPP_DEFAULT_LOGGING_FLAGS 8192 +#include <easyloggingpp/easylogging++.h> + +#define PROJECT_NAME "@CMAKE_PROJECT_NAME@" +#define OS_PLATFORM @OS_PLATFORM@ +#define LOCALE_DIR "@LOCALE_DIR@" + +/** + * Resources File(s) Path Vars + */ +#if defined(MACOS) && defined(RELEASE) +#define RESOURCE_DIR(appDir) (appDir + "/../Resources/") +#elif defined(LINUX) && defined(RELEASE) +#define RESOURCE_DIR(appDir) (appDir + "/../share/") +#else +#define RESOURCE_DIR(appDir) (appDir) +#endif + +#endif // GPGFRONTEND_H_IN diff --git a/src/GpgFrontendBuildInfo.h.in b/src/GpgFrontendBuildInfo.h.in new file mode 100644 index 00000000..eaf0475b --- /dev/null +++ b/src/GpgFrontendBuildInfo.h.in @@ -0,0 +1,54 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_BUILD_INFO_H_IN +#define GPGFRONTEND_BUILD_INFO_H_IN + +/** + * Logic Version (*.*.*) + */ +#define VERSION_MAJOR @CMAKE_PROJECT_VERSION_MAJOR@ +#define VERSION_MINOR @CMAKE_PROJECT_VERSION_MINOR@ +#define VERSION_PATCH @CMAKE_PROJECT_VERSION_PATCH@ + +/** + * Code Version (According to Git) + */ +#define GIT_BRANCH_NAME "@GIT_BRANCH_NAME@" +#define GIT_COMMIT_HASH "@GIT_COMMIT_HASH@" + +/** + * Generated Information (According to CMake) + */ +#define PROJECT_NAME "@PROJECT_NAME@" +#define BUILD_VERSION "@BUILD_VERSION@" +#define GIT_VERSION "@GIT_VERSION@" + +/** + * Build Information + */ +#define BUILD_FLAG @BUILD_FLAG@ +#define BUILD_TIMESTAMP "@BUILD_TIMESTAMP@" + +#endif // GPGFRONTEND_BUILD_INFO_H_IN diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp deleted file mode 100644 index 73f55672..00000000 --- a/src/MainWindow.cpp +++ /dev/null @@ -1,245 +0,0 @@ -/** - * This file is part of GPGFrontend. - * - * GPGFrontend is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Foobar is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see <https://www.gnu.org/licenses/>. - * - * The initial version of the source code is inherited from gpg4usb-team. - * Their source code version also complies with GNU General Public License. - * - * The source code version of this software was modified and released - * by Saturneric<[email protected]> starting on May 12, 2021. - * - */ - -#include "MainWindow.h" -#include "ui/help/VersionCheckThread.h" - -MainWindow::MainWindow() - : appPath(qApp->applicationDirPath()), - settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", - QSettings::IniFormat) { - - networkAccessManager = new QNetworkAccessManager(this); - - auto waitingDialog = new WaitingDialog(tr("Loading Gnupg"), this); - - // Init Gnupg - auto ctx_thread = QThread::create([&]() { mCtx = new GpgME::GpgContext(); }); - ctx_thread->start(); - while (ctx_thread->isRunning()) - QApplication::processEvents(); - waitingDialog->close(); - ctx_thread->deleteLater(); - - QString baseUrl = "https://api.github.com/repos/saturneric/gpgfrontend/releases/latest"; - - QNetworkRequest request; - request.setUrl(QUrl(baseUrl)); - - QNetworkReply *replay = networkAccessManager->get(request); - - auto version_thread = new VersionCheckThread(replay); - - connect(version_thread, SIGNAL(finished()), version_thread, SLOT(deleteLater())); - connect(version_thread, SIGNAL(upgradeVersion(const QString &, const QString &)), this, SLOT(slotVersionUpgrade(const QString &, const QString &))); - - version_thread->start(); - - // Check Context Status - if (!mCtx->isGood()) { - QMessageBox::critical( - nullptr, tr("ENV Loading Failed"), - tr("Gnupg is not installed correctly, please follow the ReadME " - "instructions to install gnupg and then open GPGFrontend.")); - QCoreApplication::quit(); - exit(0); - } - - /* get path were app was started */ - setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea); - setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea); - - edit = new TextEdit(this); - setCentralWidget(edit); - - /* the list of Keys available*/ - mKeyList = new KeyList(mCtx, KeyListRow::SECRET_OR_PUBLIC_KEY, - KeyListColumn::TYPE | KeyListColumn::NAME | - KeyListColumn::EmailAddress | - KeyListColumn::Usage | KeyListColumn::Validity, - this); - mKeyList->setFilter([](const GpgKey &key) -> bool { - if (key.revoked || key.disabled || key.expired) - return false; - else - return true; - }); - mKeyList->slotRefresh(); - - infoBoard = new InfoBoardWidget(this, mCtx, mKeyList); - - /* List of binary Attachments */ - attachmentDockCreated = false; - - /* Variable containing if restart is needed */ - this->slotSetRestartNeeded(false); - - keyMgmt = new KeyMgmt(mCtx, this); - keyMgmt->hide(); - /* test attachmentdir for files alll 15s */ - auto *timer = new QTimer(this); - connect(timer, SIGNAL(timeout()), this, SLOT(slotCheckAttachmentFolder())); - timer->start(5000); - - createActions(); - createMenus(); - createToolBars(); - createStatusBar(); - createDockWindows(); - - connect(edit->tabWidget, SIGNAL(currentChanged(int)), this, - SLOT(slotDisableTabActions(int))); - - mKeyList->addMenuAction(appendSelectedKeysAct); - mKeyList->addMenuAction(copyMailAddressToClipboardAct); - mKeyList->addMenuAction(showKeyDetailsAct); - mKeyList->addSeparator(); - mKeyList->addMenuAction(refreshKeysFromKeyserverAct); - mKeyList->addMenuAction(uploadKeyToServerAct); - - restoreSettings(); - - // open filename if provided as first command line parameter - QStringList args = qApp->arguments(); - if (args.size() > 1) { - if (!args[1].startsWith("-")) { - if (QFile::exists(args[1])) - edit->loadFile(args[1]); - } - } - edit->curTextPage()->setFocus(); - this->setMinimumSize(1200, 700); - this->setWindowTitle(qApp->applicationName()); - this->show(); - - // Show wizard, if the don't show wizard message box wasn't checked - // and keylist doesn't contain a private key - qDebug() << "wizard/showWizard" - << settings.value("wizard/showWizard", true).toBool(); - qDebug() << "wizard/nextPage" << settings.value("wizard/nextPage").isNull(); - if (settings.value("wizard/showWizard", true).toBool() || - !settings.value("wizard/nextPage").isNull()) { - slotStartWizard(); - } - -} - -void MainWindow::restoreSettings() { - // state sets pos & size of dock-widgets - this->restoreState(settings.value("window/windowState").toByteArray()); - - // Restore window size & location - if (settings.value("window/windowSave").toBool()) { - QPoint pos = settings.value("window/pos", QPoint(100, 100)).toPoint(); - QSize size = settings.value("window/size", QSize(800, 450)).toSize(); - this->resize(size); - this->move(pos); - } else { - this->resize(QSize(800, 450)); - this->move(QPoint(100, 100)); - } - - // Iconsize - QSize iconSize = settings.value("toolbar/iconsize", QSize(24, 24)).toSize(); - this->setIconSize(iconSize); - - importButton->setIconSize(iconSize); - fileEncButton->setIconSize(iconSize); - // set list of keyserver if not defined - QStringList *keyServerDefaultList; - keyServerDefaultList = new QStringList("http://keys.gnupg.net"); - keyServerDefaultList->append("https://keyserver.ubuntu.com"); - keyServerDefaultList->append("http://pool.sks-keyservers.net"); - - QStringList keyServerList = - settings.value("keyserver/keyServerList", *keyServerDefaultList) - .toStringList(); - settings.setValue("keyserver/keyServerList", keyServerList); - - // set default keyserver, if it's not set - QString defaultKeyServer = settings - .value("keyserver/defaultKeyServer", - QString("https://keyserver.ubuntu.com")) - .toString(); - settings.setValue("keyserver/defaultKeyServer", defaultKeyServer); - - // Iconstyle - Qt::ToolButtonStyle buttonStyle = static_cast<Qt::ToolButtonStyle>( - settings.value("toolbar/iconstyle", Qt::ToolButtonTextUnderIcon) - .toUInt()); - this->setToolButtonStyle(buttonStyle); - importButton->setToolButtonStyle(buttonStyle); - fileEncButton->setToolButtonStyle(buttonStyle); - - // Checked Keys - if (settings.value("keys/saveKeyChecked").toBool()) { - QStringList keyIds = - settings.value("keys/savedCheckedKeyList").toStringList(); - mKeyList->setChecked(&keyIds); - } -} - -void MainWindow::saveSettings() { - // window position and size - settings.setValue("window/windowState", saveState()); - settings.setValue("window/pos", pos()); - settings.setValue("window/size", size()); - - // keyid-list of private checked keys - if (settings.value("keys/saveKeyChecked").toBool()) { - QStringList *keyIds = mKeyList->getChecked(); - if (!keyIds->isEmpty()) { - settings.setValue("keys/savedCheckedKeyList", *keyIds); - } else { - settings.setValue("keys/savedCheckedKeyList", ""); - } - } else { - settings.remove("keys/savedCheckedKeyList"); - } -} - -void MainWindow::closeAttachmentDock() { - if (!attachmentDockCreated) { - return; - } - attachmentDock->close(); - attachmentDock->deleteLater(); - attachmentDockCreated = false; -} - -void MainWindow::closeEvent(QCloseEvent *event) { - /* - * ask to save changes, if there are - * modified documents in any tab - */ - if (edit->maybeSaveAnyTab()) { - saveSettings(); - event->accept(); - } else { - event->ignore(); - } - - // clear password from memory - mCtx->clearPasswordCache(); -} diff --git a/src/advance/UnknownSignersChecker.cpp b/src/advance/UnknownSignersChecker.cpp index 1b087b5c..fc70ee20 100644 --- a/src/advance/UnknownSignersChecker.cpp +++ b/src/advance/UnknownSignersChecker.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -24,58 +24,52 @@ #include "advance/UnknownSignersChecker.h" - -UnknownSignersChecker::UnknownSignersChecker(GpgME::GpgContext *ctx, gpgme_verify_result_t result) : - appPath(qApp->applicationDirPath()), settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini"), mCtx(ctx), - mResult(result) { - -} +UnknownSignersChecker::UnknownSignersChecker(GpgFrontend::GpgContext *ctx, + gpgme_verify_result_t result) + : appPath(qApp->applicationDirPath()), + settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini"), + mCtx(ctx), + mResult(result) {} void UnknownSignersChecker::start() { + auto sign = mResult->signatures; + bool canContinue = true; - auto sign = mResult->signatures; - bool canContinue = true; - - while (sign && canContinue) { - - switch (gpg_err_code(sign->status)) { - case GPG_ERR_BAD_SIGNATURE: - break; - case GPG_ERR_NO_ERROR: - if (!(sign->status & GPGME_SIGSUM_KEY_MISSING)) - check_signer(sign); - break; - case GPG_ERR_NO_PUBKEY: + while (sign && canContinue) { + switch (gpg_err_code(sign->status)) { + case GPG_ERR_BAD_SIGNATURE: + break; + case GPG_ERR_NO_ERROR: + if (!(sign->status & GPGME_SIGSUM_KEY_MISSING)) check_signer(sign); + break; + case GPG_ERR_NO_PUBKEY: - case GPG_ERR_CERT_REVOKED: - case GPG_ERR_SIG_EXPIRED: - case GPG_ERR_KEY_EXPIRED: - check_signer(sign); - break; - case GPG_ERR_GENERAL: - canContinue = false; - break; - default: - break; - } - sign = sign->next; + case GPG_ERR_CERT_REVOKED: + case GPG_ERR_SIG_EXPIRED: + case GPG_ERR_KEY_EXPIRED: + check_signer(sign); + break; + case GPG_ERR_GENERAL: + canContinue = false; + break; + default: + break; } + sign = sign->next; + } - if(!unknownFprs.isEmpty()) { - PubkeyGetter pubkeyGetter(mCtx, unknownFprs); - pubkeyGetter.start(); - if (!pubkeyGetter.result()) { - - } + if (!unknownFprs.isEmpty()) { + PubkeyGetter pubkeyGetter(mCtx, unknownFprs); + pubkeyGetter.start(); + if (!pubkeyGetter.result()) { } + } } void UnknownSignersChecker::check_signer(gpgme_signature_t sign) { - - auto key = mCtx->getKeyByFpr(sign->fpr); - if (!key.good) { - qDebug() << "Find Unknown FingerPrint " << sign->fpr; - unknownFprs.append(sign->fpr); - } - + auto key = mCtx->getKeyRefByFpr(sign->fpr); + if (!key.good) { + qDebug() << "Find Unknown FingerPrint " << sign->fpr; + unknownFprs.append(sign->fpr); + } } diff --git a/src/gpg/GpgSubKey.cpp b/src/advance/UnknownSignersChecker.h index 4adda132..de07eaf8 100644 --- a/src/gpg/GpgSubKey.cpp +++ b/src/advance/UnknownSignersChecker.h @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -21,31 +21,29 @@ * by Saturneric<[email protected]> starting on May 12, 2021. * */ -#include "gpg/GpgSubKey.h" -GpgSubKey::GpgSubKey(gpgme_subkey_t key) { +#ifndef GPGFRONTEND_ZH_CN_TS_UNKNOWNSIGNERSCHECKER_H +#define GPGFRONTEND_ZH_CN_TS_UNKNOWNSIGNERSCHECKER_H - if (key == nullptr) return; +#include "server/api/PubkeyGetter.h" - id = key->keyid; - pubkey_algo = gpgme_pubkey_algo_name(key->pubkey_algo); - fpr = key->fpr; +class UnknownSignersChecker : public QObject { + Q_OBJECT + public: + UnknownSignersChecker(GpgFrontend::GpgContext *ctx, + gpgme_verify_result_t result); - expired = key->expired; - revoked = key->revoked; - secret = key->secret; + void start(); - disabled = key->disabled; + private: + QString appPath; + QSettings settings; + GpgFrontend::GpgContext *mCtx; + gpgme_verify_result_t mResult; - length = key->length; + QVector<QString> unknownFprs; - can_authenticate = key->can_authenticate; - can_certify = key->can_certify; - can_encrypt = key->can_encrypt; - can_sign = key->can_sign; - is_cardkey = key->is_cardkey; - is_private_key = key->secret; + void check_signer(gpgme_signature_t sign); +}; - timestamp = QDateTime::fromTime_t(key->timestamp); - expires = QDateTime::fromTime_t(key->expires); -} +#endif // GPGFRONTEND_ZH_CN_TS_UNKNOWNSIGNERSCHECKER_H diff --git a/src/gpg/CMakeLists.txt b/src/gpg/CMakeLists.txt index 2bcacade..886f8fdc 100644 --- a/src/gpg/CMakeLists.txt +++ b/src/gpg/CMakeLists.txt @@ -1,28 +1,42 @@ aux_source_directory(./result_analyse GPG_SOURCE) -aux_source_directory(./gpg_context GPG_SOURCE) +aux_source_directory(./function GPG_SOURCE) +aux_source_directory(./model GPG_SOURCE) aux_source_directory(. GPG_SOURCE) -add_library(gpg STATIC ${GPG_SOURCE}) +add_library(gpg_core STATIC ${GPG_SOURCE}) set(UTILS_DIR ${CMAKE_SOURCE_DIR}/utils) set(GPGME_LIB_DIR ${UTILS_DIR}/gpgme/lib) +if (ESAY_LOGGING_PP) + message(STATUS "Link ESAY_LOGGING_PP") + set(THIRD_PARTY_LIBS easy_logging_pp config++) +endif () + +set(BOOST_LIBS Boost::date_time Boost::filesystem) + +message(STATUS "Third Party Libraries " ${THIRD_PARTY_LIBS}) + if (MINGW) message(STATUS "Link GPG Static Library For MINGW") - target_link_libraries(gpg - gpgme gpg-error assuan - Qt5::Network Qt5::PrintSupport Qt5::Widgets Qt5::Test Qt5::Core - wsock32) -elseif(APPLE) + target_link_libraries(gpg_core ${THIRD_PARTY_LIBS} + ${BOOST_LIBS} + gpgme gpg-error assuan wsock32) + target_compile_features(gpg_core PUBLIC cxx_std_17) +elseif (APPLE) + find_library(libgpgme NAMES libgpgme.a) + find_library(libgpg-error NAMES libgpg-error.a) + find_library(libassuan NAMES libassuan.a) message(STATUS "Link GPG Static Library For macOS") - target_link_libraries(gpg - /usr/local/lib/libgpgme.a /usr/local/lib/libgpg-error.a /usr/local/lib/libassuan.a - Qt5::Network Qt5::PrintSupport Qt5::Widgets Qt5::Test Qt5::Core) -else() - + target_link_libraries(gpg_core ${THIRD_PARTY_LIBS} + ${BOOST_LIBS} + ${libgpgme} ${libgpg-error} ${libassuan} + dl) +else () message(STATUS "Link GPG Static Library For Unix") - target_link_libraries(gpg - /usr/local/lib/libgpgme.a /usr/local/lib/libgpg-error.a /usr/local/lib/libassuan.a - Qt5::Network Qt5::PrintSupport Qt5::Widgets Qt5::Test Qt5::Core) -endif() + target_link_libraries(gpg_core ${THIRD_PARTY_LIBS} + libgpgme.a libgpg-error.a libassuan.a + ${BOOST_LIBS} + pthread dl) +endif () diff --git a/src/gpg/GpgConstants.cpp b/src/gpg/GpgConstants.cpp index 1d59dab5..5688287e 100644 --- a/src/gpg/GpgConstants.cpp +++ b/src/gpg/GpgConstants.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -24,11 +24,156 @@ #include "gpg/GpgConstants.h" -const char *GpgConstants::PGP_CRYPT_BEGIN = "-----BEGIN PGP MESSAGE-----"; -const char *GpgConstants::PGP_CRYPT_END = "-----END PGP MESSAGE-----"; -const char *GpgConstants::PGP_SIGNED_BEGIN = "-----BEGIN PGP SIGNED MESSAGE-----"; -const char *GpgConstants::PGP_SIGNED_END = "-----END PGP SIGNATURE-----"; -const char *GpgConstants::PGP_SIGNATURE_BEGIN = "-----BEGIN PGP SIGNATURE-----"; -const char *GpgConstants::PGP_SIGNATURE_END = "-----END PGP SIGNATURE-----"; -const char *GpgConstants::GPG_FRONTEND_SHORT_CRYPTO_HEAD = "GpgF_Scpt://"; +#include <gpg-error.h> +#include <boost/algorithm/string/predicate.hpp> +#include <boost/filesystem.hpp> + +const char* GpgFrontend::GpgConstants::PGP_CRYPT_BEGIN = + "-----BEGIN PGP MESSAGE-----"; +const char* GpgFrontend::GpgConstants::PGP_CRYPT_END = + "-----END PGP MESSAGE-----"; +const char* GpgFrontend::GpgConstants::PGP_SIGNED_BEGIN = + "-----BEGIN PGP SIGNED MESSAGE-----"; +const char* GpgFrontend::GpgConstants::PGP_SIGNED_END = + "-----END PGP SIGNATURE-----"; +const char* GpgFrontend::GpgConstants::PGP_SIGNATURE_BEGIN = + "-----BEGIN PGP SIGNATURE-----"; +const char* GpgFrontend::GpgConstants::PGP_SIGNATURE_END = + "-----END PGP SIGNATURE-----"; +const char* GpgFrontend::GpgConstants::GPG_FRONTEND_SHORT_CRYPTO_HEAD = + "GpgF_Scpt://"; + +gpgme_error_t GpgFrontend::check_gpg_error(gpgme_error_t err) { + if (gpg_err_code(err) != GPG_ERR_NO_ERROR) { + LOG(ERROR) << "[Error " << gpg_err_code(err) + << "] Source: " << gpgme_strsource(err) + << " Description: " << gpgme_strerror(err); + } + return err; +} + +gpg_err_code_t GpgFrontend::check_gpg_error_2_err_code(gpgme_error_t err, + gpgme_error_t predict) { + auto err_code = gpg_err_code(err); + if (err_code != predict) { + LOG(ERROR) << "[Error " << gpg_err_code(err) + << "] Source: " << gpgme_strsource(err) + << " Description: " << gpgme_strerror(err); + } + return err_code; +} + +// error-handling +gpgme_error_t GpgFrontend::check_gpg_error(gpgme_error_t err, + const std::string& comment) { + if (gpg_err_code(err) != GPG_ERR_NO_ERROR) { + LOG(ERROR) << "[Error " << gpg_err_code(err) + << "] Source: " << gpgme_strsource(err) + << " Description: " << gpgme_strerror(err) << " " << comment; + } + return err; +} + +std::string GpgFrontend::beautify_fingerprint( + GpgFrontend::BypeArrayConstRef fingerprint) { + auto _fingerprint = fingerprint; + unsigned len = fingerprint.size(); + if ((len > 0) && (len % 4 == 0)) + for (unsigned n = 0; 4 * (n + 1) < len; ++n) + _fingerprint.insert(static_cast<int>(5u * n + 4u), " "); + return fingerprint; +} + +// trim from start (in place) +static inline void ltrim(std::string& s) { + s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) { + return !std::isspace(ch); + })); +} + +// trim from end (in place) +static inline void rtrim(std::string& s) { + s.erase(std::find_if(s.rbegin(), s.rend(), + [](unsigned char ch) { return !std::isspace(ch); }) + .base(), + s.end()); +} + +// trim from both ends (in place) +static inline std::string trim(std::string& s) { + ltrim(s); + rtrim(s); + return s; +} + +std::string GpgFrontend::read_all_data_in_file(const std::string& path) { + using namespace boost::filesystem; + class path file_info(path.c_str()); + + if (!exists(file_info) || !is_regular_file(path)) + throw std::runtime_error("no permission"); + + std::ifstream in_file; + in_file.open(path, std::ios::in); + if (!in_file.good()) throw std::runtime_error("cannot open file"); + std::istreambuf_iterator<char> begin(in_file); + std::istreambuf_iterator<char> end; + std::string in_buffer(begin, end); + in_file.close(); + return in_buffer; +} + +bool GpgFrontend::write_buffer_to_file(const std::string& path, + const std::string& out_buffer) { + std::ofstream out_file(boost::filesystem::path(path).string(), std::ios::out); + if (!out_file.good()) return false; + out_file.write(out_buffer.c_str(), out_buffer.size()); + out_file.close(); + return true; +} + +std::string GpgFrontend::get_file_extension(const std::string& path) { + // Create a Path object from given string + boost::filesystem::path path_obj(path); + // Check if file name in the path object has extension + if (path_obj.has_extension()) { + // Fetch the extension from path object and return + return path_obj.extension().string(); + } + // In case of no extension return empty string + return {}; +} + +std::string GpgFrontend::get_only_file_name_with_path(const std::string& path) { + // Create a Path object from given string + boost::filesystem::path path_obj(path); + // Check if file name in the path object has extension + if (path_obj.has_filename()) { + // Fetch the extension from path object and return + return (path_obj.parent_path() / path_obj.stem()).string(); + } + // In case of no extension return empty string + throw std::runtime_error("invalid file path"); +} + +/* + * isSigned returns: + * - 0, if text isn't signed at all + * - 1, if text is partially signed + * - 2, if text is completly signed + */ +int GpgFrontend::text_is_signed(GpgFrontend::BypeArrayRef text) { + using boost::algorithm::ends_with; + using boost::algorithm::starts_with; + + auto trim_text = trim(text); + if (starts_with(trim_text, GpgConstants::PGP_SIGNED_BEGIN) && + ends_with(trim_text, GpgConstants::PGP_SIGNED_END)) + return 2; + else if (text.find(GpgConstants::PGP_SIGNED_BEGIN) != std::string::npos && + text.find(GpgConstants::PGP_SIGNED_END) != std::string::npos) + return 1; + else + return 0; +} diff --git a/src/gpg/GpgConstants.h b/src/gpg/GpgConstants.h new file mode 100644 index 00000000..1cd0f64d --- /dev/null +++ b/src/gpg/GpgConstants.h @@ -0,0 +1,101 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPG_CONSTANTS_H +#define GPG_CONSTANTS_H + +#include "GpgFrontend.h" + +#include <gpg-error.h> +#include <gpgme.h> + +#include <cassert> +#include <functional> +#include <memory> +#include <string> + +const int RESTART_CODE = 1000; + +namespace GpgFrontend { + +using ByteArray = std::string; +using ByteArrayPtr = std::unique_ptr<ByteArray>; +using StdBypeArrayPtr = std::unique_ptr<ByteArray>; +using BypeArrayRef = ByteArray&; +using BypeArrayConstRef = const ByteArray&; +using StringArgsPtr = std::unique_ptr<std::vector<std::string>>; +using StringArgsRef = std::vector<std::string>&; + +using GpgError = gpgme_error_t; + +// Result Deletor +struct _result_ref_deletor { + void operator()(void* _result) { + // if (_result != nullptr) + // gpgme_result_unref(_result); + } +}; + +using GpgEncrResult = + std::unique_ptr<struct _gpgme_op_encrypt_result, _result_ref_deletor>; +using GpgDecrResult = + std::unique_ptr<struct _gpgme_op_decrypt_result, _result_ref_deletor>; +using GpgSignResult = + std::unique_ptr<struct _gpgme_op_sign_result, _result_ref_deletor>; +using GpgVerifyResult = + std::unique_ptr<struct _gpgme_op_verify_result, _result_ref_deletor>; + +// Error Info Printer +GpgError check_gpg_error(GpgError err); +GpgError check_gpg_error(GpgError gpgmeError, const std::string& comment); +gpg_err_code_t check_gpg_error_2_err_code( + gpgme_error_t err, gpgme_error_t predict = GPG_ERR_NO_ERROR); + +// Fingerprint +std::string beautify_fingerprint(BypeArrayConstRef fingerprint); + +// File Operation +std::string read_all_data_in_file(const std::string& path); +bool write_buffer_to_file(const std::string& path, + const std::string& out_buffer); + +std::string get_file_extension(const std::string& path); +std::string get_only_file_name_with_path(const std::string& path); + +// Check +int text_is_signed(BypeArrayRef text); + +class GpgConstants { + public: + static const char* PGP_CRYPT_BEGIN; + static const char* PGP_CRYPT_END; + static const char* PGP_SIGNED_BEGIN; + static const char* PGP_SIGNED_END; + static const char* PGP_SIGNATURE_BEGIN; + static const char* PGP_SIGNATURE_END; + static const char* GPG_FRONTEND_SHORT_CRYPTO_HEAD; +}; +} // namespace GpgFrontend + +#endif // GPG_CONSTANTS_H diff --git a/src/gpg/GpgContext.cpp b/src/gpg/GpgContext.cpp new file mode 100644 index 00000000..5d901c3f --- /dev/null +++ b/src/gpg/GpgContext.cpp @@ -0,0 +1,127 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#include "gpg/GpgContext.h" + +#include <gpg-error.h> +#include <gpgme.h> + +#include <functional> +#include <string> + +#include "GpgConstants.h" + +#ifdef _WIN32 +#include <windows.h> +#endif + +#define INT2VOIDP(i) (void*)(uintptr_t)(i) + +namespace GpgFrontend { + +/** + * Constructor + * Set up gpgme-context, set paths to app-run path + */ +GpgContext::GpgContext(bool independent_database, std::string db_path, + int channel) + : SingletonFunctionObject<GpgContext>(channel) { + static bool _first = true; + + if (_first) { + /* Initialize the locale environment. */ + setlocale(LC_ALL, ""); + gpgme_check_version(nullptr); + gpgme_set_locale(nullptr, LC_CTYPE, setlocale(LC_CTYPE, nullptr)); +#ifdef LC_MESSAGES + gpgme_set_locale(nullptr, LC_MESSAGES, setlocale(LC_MESSAGES, nullptr)); +#endif + _first = false; + } + + gpgme_ctx_t _p_ctx; + check_gpg_error(gpgme_new(&_p_ctx)); + _ctx_ref = CtxRefHandler(_p_ctx); + + auto engineInfo = gpgme_ctx_get_engine_info(*this); + + // Check ENV before running + bool check_pass = false, find_openpgp = false, find_gpgconf = false, + find_assuan = false, find_cms = false; + while (engineInfo != nullptr) { + if (engineInfo->protocol == GPGME_PROTOCOL_GPGCONF && + strcmp(engineInfo->version, "1.0.0") != 0) + find_gpgconf = true; + if (engineInfo->protocol == GPGME_PROTOCOL_OpenPGP && + strcmp(engineInfo->version, "1.0.0") != 0) + find_openpgp = true, info.AppPath = engineInfo->file_name, + info.DatabasePath = "default"; + if (engineInfo->protocol == GPGME_PROTOCOL_CMS && + strcmp(engineInfo->version, "1.0.0") != 0) + find_cms = true; + if (engineInfo->protocol == GPGME_PROTOCOL_ASSUAN) find_assuan = true; + engineInfo = engineInfo->next; + } + + if (find_gpgconf && find_openpgp && find_cms && find_assuan) + check_pass = true; + + if (!check_pass) { + good_ = false; + return; + } else { + // Set Independent Database + if (independent_database) { + info.DatabasePath = db_path; + auto err = gpgme_ctx_set_engine_info( + _ctx_ref.get(), GPGME_PROTOCOL_OpenPGP, info.AppPath.c_str(), + info.DatabasePath.c_str()); + assert(check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR); + } + + /** Setting the output type must be done at the beginning */ + /** think this means ascii-armor --> ? */ + gpgme_set_armor(*this, 1); + // Speed up loading process + gpgme_set_offline(*this, 1); + + check_gpg_error(gpgme_set_keylist_mode( + *this, GPGME_KEYLIST_MODE_LOCAL | GPGME_KEYLIST_MODE_WITH_SECRET | + GPGME_KEYLIST_MODE_SIGS | GPGME_KEYLIST_MODE_SIG_NOTATIONS | + GPGME_KEYLIST_MODE_WITH_TOFU)); + good_ = true; + } +} + +bool GpgContext::good() const { return good_; } + +void GpgContext::SetPassphraseCb(decltype(test_passphrase_cb) cb) const { + gpgme_set_passphrase_cb(*this, cb, nullptr); +} + +std::string GpgContext::getGpgmeVersion() { + return {gpgme_check_version(nullptr)}; +} + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/gpg/GpgContext.h b/src/gpg/GpgContext.h new file mode 100644 index 00000000..5812f49f --- /dev/null +++ b/src/gpg/GpgContext.h @@ -0,0 +1,95 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef __SGPGMEPP_CONTEXT_H__ +#define __SGPGMEPP_CONTEXT_H__ + +#include "GpgConstants.h" +#include "GpgFunctionObject.h" +#include "GpgInfo.h" +#include "GpgModel.h" + +namespace GpgFrontend { + +/** + * Custom Encapsulation of GpgME APIs + */ +class GpgContext : public SingletonFunctionObject<GpgContext> { + public: + explicit GpgContext(bool independent_database = false, + std::string path = std::string(), int channel = 0); + + ~GpgContext() override = default; + + [[nodiscard]] bool good() const; + + [[nodiscard]] const GpgInfo& GetInfo() const { return info; } + + static std::string getGpgmeVersion(); + + operator gpgme_ctx_t() const { return _ctx_ref.get(); } + + private: + GpgInfo info; + + struct _ctx_ref_deletor { + void operator()(gpgme_ctx_t _ctx) { + if (_ctx != nullptr) gpgme_release(_ctx); + } + }; + + using CtxRefHandler = std::unique_ptr<struct gpgme_context, _ctx_ref_deletor>; + CtxRefHandler _ctx_ref = nullptr; + + bool good_ = true; + + public: + static gpgme_error_t test_passphrase_cb(void* opaque, const char* uid_hint, + const char* passphrase_info, + int last_was_bad, int fd) { + LOG(INFO) << "test_passphrase_cb Called"; + size_t res; + std::string pass = "abcdefg\n"; + auto pass_len = pass.size(); + + size_t off = 0; + + (void)opaque; + (void)uid_hint; + (void)passphrase_info; + (void)last_was_bad; + + do { + res = gpgme_io_write(fd, &pass[off], pass_len - off); + if (res > 0) off += res; + } while (res > 0 && off != pass_len); + + return off == pass_len ? 0 : gpgme_error_from_errno(errno); + } + + void SetPassphraseCb(decltype(test_passphrase_cb) func) const; +}; +} // namespace GpgFrontend + +#endif // __SGPGMEPP_CONTEXT_H__ diff --git a/src/gpg/GpgFileOpera.cpp b/src/gpg/GpgFileOpera.cpp deleted file mode 100644 index af50c79a..00000000 --- a/src/gpg/GpgFileOpera.cpp +++ /dev/null @@ -1,249 +0,0 @@ -/** - * This file is part of GPGFrontend. - * - * GPGFrontend is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Foobar is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see <https://www.gnu.org/licenses/>. - * - * The initial version of the source code is inherited from gpg4usb-team. - * Their source code version also complies with GNU General Public License. - * - * The source code version of this software was modified and released - * by Saturneric<[email protected]> starting on May 12, 2021. - * - */ -#include "gpg/GpgFileOpera.h" - -gpgme_error_t GpgFileOpera::encryptFile(GpgME::GpgContext *ctx, QVector<GpgKey> &keys, const QString &mPath, - gpgme_encrypt_result_t *result) { - - QFileInfo fileInfo(mPath); - - if (!fileInfo.isFile() || !fileInfo.isReadable()) - throw std::runtime_error("no permission"); - - QFile infile; - infile.setFileName(mPath); - if (!infile.open(QIODevice::ReadOnly)) - throw std::runtime_error("cannot open file"); - - QByteArray inBuffer = infile.readAll(); - auto outBuffer = QByteArray(); - infile.close(); - - auto error = ctx->encrypt(keys, inBuffer, &outBuffer, result); - - if (gpg_err_code(error) != GPG_ERR_NO_ERROR) return error; - - QFile outfile(mPath + ".asc"); - - if (!outfile.open(QFile::WriteOnly)) - throw std::runtime_error("cannot open file"); - - QDataStream out(&outfile); - out.writeRawData(outBuffer.data(), outBuffer.length()); - outfile.close(); - return error; -} - -gpgme_error_t GpgFileOpera::decryptFile(GpgME::GpgContext *ctx, const QString &mPath, gpgme_decrypt_result_t *result) { - - QFileInfo fileInfo(mPath); - - if (!fileInfo.isFile() || !fileInfo.isReadable()) - throw std::runtime_error("no permission"); - - QFile infile; - infile.setFileName(mPath); - if (!infile.open(QIODevice::ReadOnly)) - throw std::runtime_error("cannot open file"); - - QByteArray inBuffer = infile.readAll(); - auto outBuffer = QByteArray(); - infile.close(); - - auto error = ctx->decrypt(inBuffer, &outBuffer, result); - - if (gpgme_err_code(error) != GPG_ERR_NO_ERROR) return error; - - QString outFileName, fileExtension = fileInfo.suffix(); - - if (fileExtension == "asc" || fileExtension == "gpg") { - int pos = mPath.lastIndexOf(QChar('.')); - outFileName = mPath.left(pos); - } else { - outFileName = mPath + ".out"; - } - - QFile outfile(outFileName); - - if (!outfile.open(QFile::WriteOnly)) - throw std::runtime_error("cannot open file"); - - QDataStream out(&outfile); - out.writeRawData(outBuffer.data(), outBuffer.length()); - outfile.close(); - - return error; -} - -gpgme_error_t GpgFileOpera::signFile(GpgME::GpgContext *ctx, QVector<GpgKey> &keys, const QString &mPath, - gpgme_sign_result_t *result) { - - QFileInfo fileInfo(mPath); - - if (!fileInfo.isFile() || !fileInfo.isReadable()) - throw std::runtime_error("no permission"); - - QFile infile; - infile.setFileName(mPath); - if (!infile.open(QIODevice::ReadOnly)) - throw std::runtime_error("cannot open file"); - - - QByteArray inBuffer = infile.readAll(); - auto outBuffer = QByteArray(); - infile.close(); - - auto error = ctx->sign(keys, inBuffer, &outBuffer, GPGME_SIG_MODE_DETACH, result); - - if (gpg_err_code(error) != GPG_ERR_NO_ERROR) return error; - - QFile outfile(mPath + ".sig"); - - if (!outfile.open(QFile::WriteOnly)) - throw std::runtime_error("cannot open file"); - - QDataStream out(&outfile); - out.writeRawData(outBuffer.data(), outBuffer.length()); - outfile.close(); - - return error; -} - -gpgme_error_t GpgFileOpera::verifyFile(GpgME::GpgContext *ctx, const QString &mPath, gpgme_verify_result_t *result) { - - qDebug() << "Verify File Path" << mPath; - - QFileInfo fileInfo(mPath); - - if (!fileInfo.isFile() || !fileInfo.isReadable()) - throw std::runtime_error("no permission"); - - QFile infile; - infile.setFileName(mPath); - if (!infile.open(QIODevice::ReadOnly)) - throw std::runtime_error("cannot open file"); - - QByteArray inBuffer = infile.readAll(); - - if(fileInfo.suffix() == "gpg") { - auto error = ctx->verify(&inBuffer, nullptr, result); - return error; - } - else { - QFile signFile; - signFile.setFileName(mPath + ".sig"); - if (!signFile.open(QIODevice::ReadOnly)) { - throw std::runtime_error("cannot open file"); - } - - auto signBuffer = signFile.readAll(); - infile.close(); - - auto error = ctx->verify(&inBuffer, &signBuffer, result); - return error; - } -} - -gpg_error_t GpgFileOpera::encryptSignFile(GpgME::GpgContext *ctx, QVector<GpgKey> &keys, const QString &mPath, - gpgme_encrypt_result_t *encr_res, - gpgme_sign_result_t *sign_res) { - - qDebug() << "Encrypt Sign File Path" << mPath; - - QFileInfo fileInfo(mPath); - - if (!fileInfo.isFile() || !fileInfo.isReadable()) - throw std::runtime_error("no permission"); - - QFile infile; - infile.setFileName(mPath); - if (!infile.open(QIODevice::ReadOnly)) - throw std::runtime_error("cannot open file"); - - QByteArray inBuffer = infile.readAll(); - auto outBuffer = QByteArray(); - infile.close(); - - QVector<GpgKey> signerKeys; - - // TODO dealing with signer keys - auto error = ctx->encryptSign(keys, signerKeys, inBuffer, &outBuffer, encr_res, sign_res); - - if (gpg_err_code(error) != GPG_ERR_NO_ERROR) - return error; - - QFile outfile(mPath + ".gpg"); - - if (!outfile.open(QFile::WriteOnly)) - throw std::runtime_error("cannot open file"); - - QDataStream out(&outfile); - out.writeRawData(outBuffer.data(), outBuffer.length()); - outfile.close(); - - return error; -} - -gpg_error_t GpgFileOpera::decryptVerifyFile(GpgME::GpgContext *ctx, const QString &mPath, gpgme_decrypt_result_t *decr_res, - gpgme_verify_result_t *verify_res) { - - qDebug() << "Decrypt Verify File Path" << mPath; - - QFileInfo fileInfo(mPath); - - if (!fileInfo.isFile() || !fileInfo.isReadable()) - throw std::runtime_error("no permission"); - - QFile infile; - infile.setFileName(mPath); - if (!infile.open(QIODevice::ReadOnly)) - throw std::runtime_error("cannot open file"); - - QByteArray inBuffer = infile.readAll(); - auto outBuffer = QByteArray(); - infile.close(); - - auto error = ctx->decryptVerify(inBuffer, &outBuffer, decr_res, verify_res); - if (gpg_err_code(error) != GPG_ERR_NO_ERROR) return error; - - QString outFileName, fileExtension = fileInfo.suffix(); - - if (fileExtension == "asc" || fileExtension == "gpg") { - int pos = mPath.lastIndexOf(QChar('.')); - outFileName = mPath.left(pos); - } else { - outFileName = mPath + ".out"; - } - - QFile outfile(outFileName); - - if (!outfile.open(QFile::WriteOnly)) - throw std::runtime_error("cannot open file"); - - QDataStream out(&outfile); - out.writeRawData(outBuffer.data(), outBuffer.length()); - outfile.close(); - - return error; -} diff --git a/src/gpg/GpgFunctionObject.h b/src/gpg/GpgFunctionObject.h new file mode 100644 index 00000000..6f1d60af --- /dev/null +++ b/src/gpg/GpgFunctionObject.h @@ -0,0 +1,138 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_ZH_CN_TS_FUNCTIONOBJECT_H +#define GPGFRONTEND_ZH_CN_TS_FUNCTIONOBJECT_H + +#include <easyloggingpp/easylogging++.h> + +#include <map> +#include <memory> +#include <mutex> +#include <shared_mutex> +#include <stdexcept> +#include <string> + +namespace GpgFrontend { + +template <typename T> +class SingletonFunctionObject { + public: + static T& GetInstance(int channel = 0) { + if (!channel) { + std::lock_guard<std::mutex> guard(_instance_mutex); + if (_instance == nullptr) _instance = std::make_unique<T>(); + return *_instance; + } else { + // read _instances_map + decltype(_instances_map.end()) _it; + { + std::shared_lock lock(_instances_mutex); + _it = _instances_map.find(channel); + } + if (_it != _instances_map.end()) + return *_it->second; + else + return CreateInstance(channel); + } + } + + static T& CreateInstance(int channel, std::unique_ptr<T> p_obj = nullptr) { + if (!channel) return *_instance; + + // read _instances_map + decltype(_instances_map.end()) _it; + { + std::shared_lock lock(_instances_mutex); + _it = _instances_map.find(channel); + } + if (_it == _instances_map.end()) { + { + std::lock_guard<std::mutex> guard(_default_channel_mutex); + int tmp = channel; + std::swap(_default_channel, tmp); + if (p_obj == nullptr) p_obj = std::make_unique<T>(); + std::swap(_default_channel, tmp); + } + T* obj = p_obj.get(); + + // change _instances_map + { + std::unique_lock lock(_instances_mutex); + _instances_map.insert({channel, std::move(p_obj)}); + } + return *obj; + } else { + return *_it->second; + } + } + + static int GetDefaultChannel() { return _default_channel; } + + int GetChannel() const { return channel_; } + + SingletonFunctionObject(T&&) = delete; + + SingletonFunctionObject(const T&) = delete; + + void operator=(const T&) = delete; + + protected: + SingletonFunctionObject() {} + + SingletonFunctionObject(int channel) : channel_(channel) {} + + virtual ~SingletonFunctionObject() = default; + + private: + int channel_ = _default_channel; + static int _default_channel; + static std::mutex _default_channel_mutex; + static std::mutex _instance_mutex; + static std::shared_mutex _instances_mutex; + static std::unique_ptr<T> _instance; + static std::map<int, std::unique_ptr<T>> _instances_map; +}; + +template <typename T> +int SingletonFunctionObject<T>::_default_channel = 0; + +template <typename T> +std::mutex SingletonFunctionObject<T>::_default_channel_mutex; + +template <typename T> +std::mutex SingletonFunctionObject<T>::_instance_mutex; + +template <typename T> +std::shared_mutex SingletonFunctionObject<T>::_instances_mutex; + +template <typename T> +std::unique_ptr<T> SingletonFunctionObject<T>::_instance = nullptr; + +template <typename T> +std::map<int, std::unique_ptr<T>> SingletonFunctionObject<T>::_instances_map; + +} // namespace GpgFrontend + +#endif // GPGFRONTEND_ZH_CN_TS_FUNCTIONOBJECT_H diff --git a/src/gpg/GpgGenKeyInfo.cpp b/src/gpg/GpgGenKeyInfo.cpp index 69da27e3..07708433 100644 --- a/src/gpg/GpgGenKeyInfo.cpp +++ b/src/gpg/GpgGenKeyInfo.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -24,149 +24,149 @@ #include "gpg/GpgGenKeyInfo.h" -const QVector<QString> GenKeyInfo::SupportedKeyAlgo = { - "RSA", - "DSA", - "ED25519" -}; - -const QVector<QString> GenKeyInfo::SupportedSubkeyAlgo = { - "RSA", - "DSA", - "ED25519", - "ELG" -}; - -void GenKeyInfo::setAlgo(const QString &m_algo) { - - qDebug() << "set algo " << m_algo; - - reset_options(); - - if (!this->subKey) { - this->setAllowCertification(true); - } else { - this->setAllowCertification(false); - } - - this->allowChangeCertification = false; - - auto lower_algo = m_algo.toLower(); - - if(lower_algo == "rsa") { - /** - * RSA is the world’s premier asymmetric cryptographic algorithm, - * and is built on the difficulty of factoring extremely large composites. - * GnuPG supports RSA with key sizes of between 1024 and 4096 bits. - */ - suggestMinKeySize = 1024; - suggestMaxKeySize = 4096; - suggestSizeAdditionStep = 1024; - setKeySize(2048); - - } else if (lower_algo == "dsa") { - /** - * Algorithm (DSA) as a government standard for digital signatures. - * Originally, it supported key lengths between 512 and 1024 bits. - * Recently, NIST has declared 512-bit keys obsolete: - * now, DSA is available in 1024, 2048 and 3072-bit lengths. - */ - setAllowEncryption(false); - allowChangeEncryption = false; - - suggestMinKeySize = 1024; - suggestMaxKeySize = 3072; - suggestSizeAdditionStep = 1024; - setKeySize(2048); - - } else if (lower_algo == "ed25519") { - /** - * GnuPG supports the Elgamal asymmetric encryption algorithm in key lengths ranging from 1024 to 4096 bits. - */ - - setAllowEncryption(false); - allowChangeEncryption = false; - - suggestMinKeySize = -1; - suggestMaxKeySize = -1; - suggestSizeAdditionStep = -1; - setKeySize(-1); - } else if (lower_algo == "elg") { - /** - * GnuPG supports the Elgamal asymmetric encryption algorithm in key lengths ranging from 1024 to 4096 bits. - */ - - setAllowAuthentication(false); - allowChangeAuthentication = false; - - setAllowSigning(false); - allowChangeSigning = false; - - suggestMinKeySize = 1024; - suggestMaxKeySize = 4096; - suggestSizeAdditionStep = 1024; - setKeySize(2048); - } - GenKeyInfo::algo = lower_algo; +#include <easyloggingpp/easylogging++.h> + +#include <boost/date_time/gregorian/greg_date.hpp> +#include <boost/date_time/gregorian/greg_duration.hpp> +#include <boost/date_time/gregorian/gregorian_types.hpp> +#include <string> +#include <vector> + +const std::vector<std::string> GpgFrontend::GenKeyInfo::SupportedKeyAlgo = { + "RSA", "DSA", "ED25519"}; + +const std::vector<std::string> GpgFrontend::GenKeyInfo::SupportedSubkeyAlgo = { + "RSA", "DSA", "ED25519", "ELG"}; + +void GpgFrontend::GenKeyInfo::setAlgo(const std::string &m_algo) { + LOG(INFO) << "GpgFrontend::GenKeyInfo::setAlgo m_algo" << m_algo; + + reset_options(); + + if (!this->subKey) { + this->setAllowCertification(true); + } else { + this->setAllowCertification(false); + } + + this->allowChangeCertification = false; + + std::string lower_algo = std::string(m_algo); + boost::algorithm::to_lower(lower_algo); + + LOG(INFO) << "GpgFrontend::GenKeyInfo::setAlgo lower_algo" << lower_algo; + + if (lower_algo == "rsa") { + /** + * RSA is the world’s premier asymmetric cryptographic algorithm, + * and is built on the difficulty of factoring extremely large composites. + * GnuPG supports RSA with key sizes of between 1024 and 4096 bits. + */ + suggestMinKeySize = 1024; + suggestMaxKeySize = 4096; + suggestSizeAdditionStep = 1024; + setKeySize(2048); + + } else if (lower_algo == "dsa") { + /** + * Algorithm (DSA) as a government standard for digital signatures. + * Originally, it supported key lengths between 512 and 1024 bits. + * Recently, NIST has declared 512-bit keys obsolete: + * now, DSA is available in 1024, 2048 and 3072-bit lengths. + */ + setAllowEncryption(false); + allowChangeEncryption = false; + + suggestMinKeySize = 1024; + suggestMaxKeySize = 3072; + suggestSizeAdditionStep = 1024; + setKeySize(2048); + + } else if (lower_algo == "ed25519") { + /** + * GnuPG supports the Elgamal asymmetric encryption algorithm in key lengths + * ranging from 1024 to 4096 bits. + */ + + setAllowEncryption(false); + allowChangeEncryption = false; + + suggestMinKeySize = -1; + suggestMaxKeySize = -1; + suggestSizeAdditionStep = -1; + setKeySize(-1); + } else if (lower_algo == "elg") { + /** + * GnuPG supports the Elgamal asymmetric encryption algorithm in key lengths + * ranging from 1024 to 4096 bits. + */ + + setAllowAuthentication(false); + allowChangeAuthentication = false; + + setAllowSigning(false); + allowChangeSigning = false; + + suggestMinKeySize = 1024; + suggestMaxKeySize = 4096; + suggestSizeAdditionStep = 1024; + setKeySize(2048); + } + this->algo = lower_algo; } -void GenKeyInfo::reset_options() { +void GpgFrontend::GenKeyInfo::reset_options() { + allowChangeEncryption = true; + setAllowEncryption(true); - allowChangeEncryption = true; - setAllowEncryption(true); + allowChangeCertification = true; + setAllowCertification(true); - allowChangeCertification = true; - setAllowCertification(true); + allowChangeSigning = true; + setAllowSigning(true); - allowChangeSigning = true; - setAllowSigning(true); - - allowChangeAuthentication = true; - setAllowAuthentication(true); - - - passPhrase.clear(); + allowChangeAuthentication = true; + setAllowAuthentication(true); + passPhrase.clear(); } -QString GenKeyInfo::getKeySizeStr() const { - if(keySize > 0) { - return QString::number(keySize); - } - else { - return QString(); - } - +std::string GpgFrontend::GenKeyInfo::getKeySizeStr() const { + if (keySize > 0) { + return std::to_string(keySize); + } else { + return {}; + } } -void GenKeyInfo::setKeySize(int m_key_size) { - if (m_key_size < suggestMinKeySize || m_key_size > suggestMaxKeySize) { - return; - } - GenKeyInfo::keySize = m_key_size; +void GpgFrontend::GenKeyInfo::setKeySize(int m_key_size) { + if (m_key_size < suggestMinKeySize || m_key_size > suggestMaxKeySize) { + return; + } + GenKeyInfo::keySize = m_key_size; } -void GenKeyInfo::setExpired(const QDateTime &m_expired) { - auto current = QDateTime::currentDateTime(); - if (isNonExpired() && m_expired < current.addYears(2)) { - GenKeyInfo::expired = m_expired; - } +void GpgFrontend::GenKeyInfo::setExpired( + const boost::gregorian::date &m_expired) { + using namespace boost::gregorian; + auto current = day_clock::local_day(); + if (isNonExpired() && m_expired < current + years(2)) { + GenKeyInfo::expired = m_expired; + } } -void GenKeyInfo::setNonExpired(bool m_non_expired) { - if (!m_non_expired) { - this->expired = QDateTime(QDateTime::fromTime_t(0)); - } - GenKeyInfo::nonExpired = m_non_expired; +void GpgFrontend::GenKeyInfo::setNonExpired(bool m_non_expired) { + using namespace boost::posix_time; + if (!m_non_expired) this->expired = from_time_t(0).date(); + GenKeyInfo::nonExpired = m_non_expired; } -void GenKeyInfo::setAllowEncryption(bool m_allow_encryption) { - if(allowChangeEncryption) - GenKeyInfo::allowEncryption = m_allow_encryption; +void GpgFrontend::GenKeyInfo::setAllowEncryption(bool m_allow_encryption) { + if (allowChangeEncryption) GenKeyInfo::allowEncryption = m_allow_encryption; } -void GenKeyInfo::setAllowCertification(bool m_allow_certification) { - if(allowChangeCertification) - GenKeyInfo::allowCertification = m_allow_certification; +void GpgFrontend::GenKeyInfo::setAllowCertification( + bool m_allow_certification) { + if (allowChangeCertification) + GenKeyInfo::allowCertification = m_allow_certification; } - diff --git a/src/gpg/GpgGenKeyInfo.h b/src/gpg/GpgGenKeyInfo.h new file mode 100644 index 00000000..53b0c9f1 --- /dev/null +++ b/src/gpg/GpgGenKeyInfo.h @@ -0,0 +1,167 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_GPGGENKEYINFO_H +#define GPGFRONTEND_GPGGENKEYINFO_H + +#include <boost/date_time.hpp> +#include <boost/date_time/gregorian/greg_duration_types.hpp> +#include <string> +#include <vector> + +namespace GpgFrontend { + +class GenKeyInfo { + bool subKey = true; + std::string userid; + std::string algo; + int keySize = 2048; + boost::gregorian::date expired = + boost::gregorian::day_clock::local_day() + boost::gregorian::years(2); + bool nonExpired = false; + + bool noPassPhrase = false; + bool allowNoPassPhrase = true; + + int suggestMaxKeySize = 4096; + int suggestSizeAdditionStep = 1024; + int suggestMinKeySize = 1024; + + std::string passPhrase; + + public: + static const std::vector<std::string> SupportedKeyAlgo; + + static const std::vector<std::string> SupportedSubkeyAlgo; + + [[nodiscard]] bool isSubKey() const { return subKey; } + + void setIsSubKey(bool m_sub_key) { GenKeyInfo::subKey = m_sub_key; } + + [[nodiscard]] const std::string &getUserid() const { return userid; } + + void setUserid(const std::string &m_userid) { GenKeyInfo::userid = m_userid; } + + [[nodiscard]] const std::string &getAlgo() const { return algo; } + + void setAlgo(const std::string &m_algo); + + [[nodiscard]] std::string getKeySizeStr() const; + + [[nodiscard]] int getKeySize() const { return keySize; } + + void setKeySize(int m_key_size); + + [[nodiscard]] const boost::gregorian::date &getExpired() const { + return expired; + } + + void setExpired(const boost::gregorian::date &m_expired); + + [[nodiscard]] bool isNonExpired() const { return nonExpired; } + + void setNonExpired(bool m_non_expired); + + [[nodiscard]] bool isNoPassPhrase() const { return this->noPassPhrase; } + + void setNonPassPhrase(bool m_non_pass_phrase) { + GenKeyInfo::noPassPhrase = m_non_pass_phrase; + } + + [[nodiscard]] bool isAllowSigning() const { return allowSigning; } + + [[nodiscard]] bool isAllowNoPassPhrase() const { return allowNoPassPhrase; } + + void setAllowSigning(bool m_allow_signing) { + if (allowChangeSigning) GenKeyInfo::allowSigning = m_allow_signing; + } + + [[nodiscard]] bool isAllowEncryption() const { return allowEncryption; } + + void setAllowEncryption(bool m_allow_encryption); + + [[nodiscard]] bool isAllowCertification() const { return allowCertification; } + + void setAllowCertification(bool m_allow_certification); + + [[nodiscard]] bool isAllowAuthentication() const { + return allowAuthentication; + } + + void setAllowAuthentication(bool m_allow_authentication) { + if (allowChangeAuthentication) + GenKeyInfo::allowAuthentication = m_allow_authentication; + } + + [[nodiscard]] const std::string &getPassPhrase() const { return passPhrase; } + + void setPassPhrase(const std::string &m_pass_phrase) { + GenKeyInfo::passPhrase = m_pass_phrase; + } + + [[nodiscard]] bool isAllowChangeSigning() const { return allowChangeSigning; } + [[nodiscard]] bool isAllowChangeEncryption() const { + return allowChangeEncryption; + } + + [[nodiscard]] bool isAllowChangeCertification() const { + return allowChangeCertification; + } + + [[nodiscard]] bool isAllowChangeAuthentication() const { + return allowChangeAuthentication; + } + + [[nodiscard]] int getSuggestMaxKeySize() const { return suggestMaxKeySize; } + + [[nodiscard]] int getSuggestMinKeySize() const { return suggestMinKeySize; } + + [[nodiscard]] int getSizeChangeStep() const { + return suggestSizeAdditionStep; + } + + private: + bool allowEncryption = true; + bool allowChangeEncryption = true; + + bool allowCertification = true; + bool allowChangeCertification = true; + + bool allowAuthentication = true; + bool allowChangeAuthentication = true; + + bool allowSigning = true; + bool allowChangeSigning = true; + + void reset_options(); + + public: + explicit GenKeyInfo(bool m_is_sub_key = false) : subKey(m_is_sub_key) { + setAlgo("rsa"); + } +}; + +} // namespace GpgFrontend + +#endif // GPGFRONTEND_GPGGENKEYINFO_H diff --git a/src/gpg/GpgInfo.cpp b/src/gpg/GpgInfo.cpp index 00a15ef9..392dcf08 100644 --- a/src/gpg/GpgInfo.cpp +++ b/src/gpg/GpgInfo.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. diff --git a/src/gpg/GpgUID.cpp b/src/gpg/GpgInfo.h index 0dc6abfd..27e13112 100644 --- a/src/gpg/GpgUID.cpp +++ b/src/gpg/GpgInfo.h @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -22,17 +22,22 @@ * */ -#include "gpg/GpgUID.h" +#ifndef GPGFRONTEND_ZH_CN_TS_GPGINFO_H +#define GPGFRONTEND_ZH_CN_TS_GPGINFO_H -GpgUID::GpgUID(gpgme_user_id_t user_id) : - uid(user_id->uid), name(user_id->name), email(user_id->email), comment(user_id->comment), - revoked(user_id->revoked), invalid(user_id->invalid) { +#include <string> - auto sig = user_id->signatures; +/** + * Use to record some info about gnupg + */ +class GpgInfo { + public: + /** + * executable binary path of gnupg + */ + std::string AppPath; - while (sig != nullptr) { - signatures.push_back(GpgKeySignature(sig)); - sig = sig->next; - } + std::string DatabasePath; +}; -}
\ No newline at end of file +#endif // GPGFRONTEND_ZH_CN_TS_GPGINFO_H diff --git a/src/gpg/GpgKey.cpp b/src/gpg/GpgKey.cpp deleted file mode 100644 index cd62fc5d..00000000 --- a/src/gpg/GpgKey.cpp +++ /dev/null @@ -1,274 +0,0 @@ -/** - * This file is part of GPGFrontend. - * - * GPGFrontend is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Foobar is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see <https://www.gnu.org/licenses/>. - * - * The initial version of the source code is inherited from gpg4usb-team. - * Their source code version also complies with GNU General Public License. - * - * The source code version of this software was modified and released - * by Saturneric<[email protected]> starting on May 12, 2021. - * - */ - -#include "gpg/GpgKey.h" - -void GpgKey::parse(gpgme_key_t key) { - - if(key == nullptr) return; - - good = true; - key_refer = key; - gpgme_key_ref(key_refer); - - is_private_key = key->secret; - fpr = key->fpr; - protocol = key->protocol; - expired = (key->expired != 0u); - revoked = (key->revoked != 0u); - - disabled = key->disabled; - - can_authenticate = key->can_authenticate; - can_certify = key->can_certify; - can_encrypt = key->can_encrypt; - can_sign = key->can_sign; - - last_update = QDateTime(QDateTime::fromTime_t(key->last_update)); - - switch (key->owner_trust) { - case GPGME_VALIDITY_UNKNOWN: - owner_trust = "Unknown"; - break; - case GPGME_VALIDITY_UNDEFINED: - owner_trust = "Undefined"; - break; - case GPGME_VALIDITY_NEVER: - owner_trust = "Never"; - break; - case GPGME_VALIDITY_MARGINAL: - owner_trust = "Marginal"; - break; - case GPGME_VALIDITY_FULL: - owner_trust = "FULL"; - break; - case GPGME_VALIDITY_ULTIMATE: - owner_trust = "Ultimate"; - break; - } - - uids.clear(); - auto uid = key->uids; - - while (uid != nullptr) { - uids.push_back(GpgUID(uid)); - uid = uid->next; - } - - if (!uids.isEmpty()) { - name = uids.first().name; - email = uids.first().email; - comment = uids.first().comment; - } - - subKeys.clear(); - auto next = key->subkeys; - - while (next != nullptr) { - subKeys.push_back(GpgSubKey(next)); - next = next->next; - } - - if (!subKeys.isEmpty()) { - id = subKeys.first().id; - expires = subKeys.first().expires; - pubkey_algo = subKeys.first().pubkey_algo; - create_time = subKeys.first().timestamp; - length = subKeys.first().length; - has_master_key = subKeys.first().secret; - } else { - id = ""; - } - -} - -GpgKey::GpgKey(GpgKey &&k) noexcept { - - id = std::move(k.id); - name = std::move(k.name); - email = std::move(k.email); - comment = std::move(k.comment); - fpr = std::move(k.fpr); - protocol = std::move(k.protocol); - owner_trust = std::move(k.owner_trust); - pubkey_algo = std::move(k.pubkey_algo); - last_update = std::move(k.last_update); - expires = std::move(k.expires); - create_time = std::move(k.create_time); - - length = k.length; - k.length = 0; - - can_encrypt = k.can_encrypt; - can_sign = k.can_sign; - can_certify = k.can_certify; - can_authenticate = k.can_authenticate; - - - is_private_key = k.is_private_key; - expired = k.expired; - revoked = k.revoked; - disabled = k.disabled; - k.has_master_key = k.has_master_key; - - good = k.good; - k.good = false; - - subKeys = std::move(k.subKeys); - uids = std::move(k.uids); - - key_refer = k.key_refer; - k.key_refer = nullptr; - -} - -GpgKey &GpgKey::operator=(const GpgKey &k) { - - id = k.id; - name = k.name; - email = k.email; - comment = k.comment; - fpr = k.fpr; - protocol = k.protocol; - owner_trust = k.owner_trust; - pubkey_algo = k.pubkey_algo; - last_update = k.last_update; - expires = k.expires; - create_time = k.create_time; - - length = k.length; - - can_encrypt = k.can_encrypt; - can_sign = k.can_sign; - can_certify = k.can_certify; - can_authenticate = k.can_authenticate; - - is_private_key = k.is_private_key; - expired = k.expired; - revoked = k.revoked; - disabled = k.disabled; - - has_master_key = k.has_master_key; - - good = k.good; - - subKeys = k.subKeys; - uids = k.uids; - - key_refer = k.key_refer; - gpgme_key_ref(key_refer); - - return *this; -} - -GpgKey::GpgKey(const GpgKey &k) : - id(k.id), name(k.name), email(k.email), comment(k.comment), - fpr(k.fpr), protocol(k.protocol), owner_trust(k.owner_trust), - pubkey_algo(k.pubkey_algo), last_update(k.last_update), - expires(k.expires), create_time(k.create_time){ - - length = k.length; - - can_encrypt = k.can_encrypt; - can_sign = k.can_sign; - can_certify = k.can_certify; - can_authenticate = k.can_authenticate; - - is_private_key = k.is_private_key; - expired = k.expired; - revoked = k.revoked; - disabled = k.disabled; - - has_master_key = k.has_master_key; - - good = k.good; - - subKeys = k.subKeys; - uids = k.uids; - - key_refer = k.key_refer; - gpgme_key_ref(key_refer); - -} - -GpgKey &GpgKey::operator=(GpgKey &&k) noexcept { - - id = std::move(k.id); - name = std::move(k.name); - email = std::move(k.email); - comment = std::move(k.comment); - fpr = std::move(k.fpr); - protocol = std::move(k.protocol); - owner_trust = std::move(k.owner_trust); - pubkey_algo = std::move(k.pubkey_algo); - last_update = std::move(k.last_update); - expires = std::move(k.expires); - create_time = std::move(k.create_time); - - length = k.length; - k.length = 0; - - can_encrypt = k.can_encrypt; - can_sign = k.can_sign; - can_certify = k.can_certify; - can_authenticate = k.can_authenticate; - - - is_private_key = k.is_private_key; - expired = k.expired; - revoked = k.revoked; - disabled = k.disabled; - - has_master_key = k.has_master_key; - - good = k.good; - k.good = false; - - subKeys = std::move(k.subKeys); - uids = std::move(k.uids); - - key_refer = k.key_refer; - k.key_refer = nullptr; - - return *this; -} - -GpgKey::~GpgKey() { - if(key_refer != nullptr && good) { - gpgme_key_unref(key_refer); - } -} - -GpgKey::GpgKey(gpgme_key_t key) { - parse(key); -} - -void GpgKey::swapKeyRefer(gpgme_key_t key) { - - if(key == nullptr) return; - - gpgme_key_unref(key_refer); - key_refer = nullptr; - parse(key); -} diff --git a/src/gpg/GpgModel.h b/src/gpg/GpgModel.h new file mode 100644 index 00000000..3e07427c --- /dev/null +++ b/src/gpg/GpgModel.h @@ -0,0 +1,71 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_ZH_CN_TS_GPGMODEL_H +#define GPGFRONTEND_ZH_CN_TS_GPGMODEL_H + +#include "GpgConstants.h" + +#include <list> +#include <utility> + +#include "gpg/model/GpgData.h" +#include "gpg/model/GpgKey.h" + +namespace GpgFrontend { + +using KeyId = std::string; + +using SubkeyId = std::string; + +using KeyIdArgsList = std::vector<KeyId>; + +using KeyIdArgsListPtr = std::unique_ptr<KeyIdArgsList>; + +using UIDArgsList = std::vector<std::string>; + +using UIDArgsListPtr = std::unique_ptr<UIDArgsList>; + +// KeyID/UID +using SignIdArgsList = std::vector<std::pair<std::string, std::string>>; + +using SignIdArgsListPtr = std::unique_ptr<SignIdArgsList>; + +using KeyFprArgsListPtr = std::unique_ptr<std::vector<std::string>>; + +using KeyArgsList = std::vector<GpgKey>; + +using KeyListPtr = std::unique_ptr<KeyArgsList>; + +using GpgKeyLinkList = std::list<GpgFrontend::GpgKey>; + +using KeyLinkListPtr = std::unique_ptr<GpgKeyLinkList>; + +using KeyPtr = std::unique_ptr<GpgKey>; + +using KeyPtrArgsList = const std::initializer_list<KeyPtr>; + +} // namespace GpgFrontend + +#endif // GPGFRONTEND_ZH_CN_TS_GPGMODEL_H diff --git a/src/gpg/function/BasicOperator.cpp b/src/gpg/function/BasicOperator.cpp new file mode 100644 index 00000000..912119e2 --- /dev/null +++ b/src/gpg/function/BasicOperator.cpp @@ -0,0 +1,206 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#include "gpg/function/BasicOperator.h" + +#include <vector> + +#include "gpg/function/GpgKeyGetter.h" + +GpgFrontend::GpgError GpgFrontend::BasicOperator::Encrypt( + KeyListPtr keys, GpgFrontend::BypeArrayRef in_buffer, + GpgFrontend::ByteArrayPtr& out_buffer, GpgFrontend::GpgEncrResult& result) { + // gpgme_encrypt_result_t e_result; + gpgme_key_t recipients[keys->size() + 1]; + + int index = 0; + for (const auto& key : *keys) recipients[index++] = gpgme_key_t(key); + + // Last entry data_in array has to be nullptr + recipients[keys->size()] = nullptr; + + GpgData data_in(in_buffer.data(), in_buffer.size()), data_out; + + gpgme_error_t err = check_gpg_error(gpgme_op_encrypt( + ctx, recipients, GPGME_ENCRYPT_ALWAYS_TRUST, data_in, data_out)); + + auto temp_data_out = data_out.Read2Buffer(); + std::swap(temp_data_out, out_buffer); + + auto temp_result = GpgEncrResult(gpgme_op_encrypt_result(ctx)); + std::swap(result, temp_result); + + return err; +} + +GpgFrontend::GpgError GpgFrontend::BasicOperator::Decrypt( + BypeArrayRef in_buffer, GpgFrontend::ByteArrayPtr& out_buffer, + GpgFrontend::GpgDecrResult& result) { + gpgme_error_t err; + + GpgData data_in(in_buffer.data(), in_buffer.size()), data_out; + err = check_gpg_error(gpgme_op_decrypt(ctx, data_in, data_out)); + + auto temp_data_out = data_out.Read2Buffer(); + std::swap(temp_data_out, out_buffer); + + auto temp_result = GpgDecrResult(gpgme_op_decrypt_result(ctx)); + std::swap(result, temp_result); + + return err; +} + +GpgFrontend::GpgError GpgFrontend::BasicOperator::Verify( + BypeArrayRef& in_buffer, ByteArrayPtr& sig_buffer, + GpgVerifyResult& result) const { + gpgme_error_t err; + + GpgData data_in(in_buffer.data(), in_buffer.size()); + + if (sig_buffer != nullptr) { + GpgData sig_data(sig_buffer->data(), sig_buffer->size()); + err = check_gpg_error(gpgme_op_verify(ctx, sig_data, data_in, nullptr)); + } else + err = check_gpg_error(gpgme_op_verify(ctx, data_in, nullptr, data_in)); + + auto temp_result = GpgVerifyResult(gpgme_op_verify_result(ctx)); + std::swap(result, temp_result); + + return err; +} + +GpgFrontend::GpgError GpgFrontend::BasicOperator::Sign(KeyListPtr keys, + BypeArrayRef in_buffer, + ByteArrayPtr& out_buffer, + gpgme_sig_mode_t mode, + GpgSignResult& result) { + gpgme_error_t err; + + // Set Singers of this opera + SetSigners(*keys); + + GpgData data_in(in_buffer.data(), in_buffer.size()), data_out; + + /** + `GPGME_SIG_MODE_NORMAL' + A normal signature is made, the output includes the plaintext + and the signature. + + `GPGME_SIG_MODE_DETACH' + A detached signature is made. + + `GPGME_SIG_MODE_CLEAR' + A clear text signature is made. The ASCII armor and text + mode settings of the context are ignored. + */ + + err = check_gpg_error(gpgme_op_sign(ctx, data_in, data_out, mode)); + + auto temp_data_out = data_out.Read2Buffer(); + std::swap(temp_data_out, out_buffer); + + auto temp_result = GpgSignResult(gpgme_op_sign_result(ctx)); + + std::swap(result, temp_result); + + return err; +} + +gpgme_error_t GpgFrontend::BasicOperator::DecryptVerify( + BypeArrayRef in_buffer, ByteArrayPtr& out_buffer, + GpgDecrResult& decrypt_result, GpgVerifyResult& verify_result) { + gpgme_error_t err; + + GpgData data_in(in_buffer.data(), in_buffer.size()), data_out; + + err = check_gpg_error(gpgme_op_decrypt_verify(ctx, data_in, data_out)); + + auto temp_data_out = data_out.Read2Buffer(); + std::swap(temp_data_out, out_buffer); + + auto temp_decr_result = GpgDecrResult(gpgme_op_decrypt_result(ctx)); + std::swap(decrypt_result, temp_decr_result); + + auto temp_verify_result = GpgVerifyResult(gpgme_op_verify_result(ctx)); + std::swap(verify_result, temp_verify_result); + + return err; +} + +gpgme_error_t GpgFrontend::BasicOperator::EncryptSign( + KeyListPtr keys, KeyListPtr signers, BypeArrayRef in_buffer, + ByteArrayPtr& out_buffer, GpgEncrResult& encr_result, + GpgSignResult& sign_result) { + gpgme_error_t err; + SetSigners(*signers); + + // gpgme_encrypt_result_t e_result; + gpgme_key_t recipients[keys->size() + 1]; + + // set key for user + int index = 0; + for (const auto& key : *keys) recipients[index++] = gpgme_key_t(key); + + // Last entry dataIn array has to be nullptr + recipients[keys->size()] = nullptr; + + GpgData data_in(in_buffer.data(), in_buffer.size()), data_out; + + // If the last parameter isnt 0, a private copy of data is made + err = check_gpg_error(gpgme_op_encrypt_sign( + ctx, recipients, GPGME_ENCRYPT_ALWAYS_TRUST, data_in, data_out)); + + auto temp_data_out = data_out.Read2Buffer(); + std::swap(temp_data_out, out_buffer); + + auto temp_encr_result = GpgEncrResult(gpgme_op_encrypt_result(ctx)); + swap(encr_result, temp_encr_result); + auto temp_sign_result = GpgSignResult(gpgme_op_sign_result(ctx)); + swap(sign_result, temp_sign_result); + + return err; +} + +void GpgFrontend::BasicOperator::SetSigners(KeyArgsList& keys) { + gpgme_signers_clear(ctx); + for (const GpgKey& key : keys) { + if (key.CanSignActual()) { + auto gpgmeError = gpgme_signers_add(ctx, gpgme_key_t(key)); + check_gpg_error(gpgmeError); + } + } + if (keys.size() != gpgme_signers_count(ctx)) + DLOG(INFO) << "No All Signers Added"; +} + +std::unique_ptr<GpgFrontend::KeyArgsList> +GpgFrontend::BasicOperator::GetSigners() { + auto count = gpgme_signers_count(ctx); + auto signers = std::make_unique<std::vector<GpgKey>>(); + for (auto i = 0u; i < count; i++) { + auto key = GpgKey(gpgme_signers_enum(ctx, i)); + signers->push_back(GpgKey(std::move(key))); + } + return signers; +} diff --git a/src/gpg/function/BasicOperator.h b/src/gpg/function/BasicOperator.h new file mode 100644 index 00000000..39f93668 --- /dev/null +++ b/src/gpg/function/BasicOperator.h @@ -0,0 +1,69 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_ZH_CN_TS_BASICOPERATOR_H +#define GPGFRONTEND_ZH_CN_TS_BASICOPERATOR_H + +#include "gpg/GpgConstants.h" +#include "gpg/GpgContext.h" +#include "gpg/GpgFunctionObject.h" +#include "gpg/GpgModel.h" + +namespace GpgFrontend { + +class BasicOperator : public SingletonFunctionObject<BasicOperator> { + public: + gpg_error_t Encrypt(KeyListPtr keys, BypeArrayRef in_buffer, + ByteArrayPtr& out_buffer, GpgEncrResult& result); + + gpgme_error_t EncryptSign(KeyListPtr keys, KeyListPtr signers, + BypeArrayRef in_buffer, ByteArrayPtr& out_buffer, + GpgEncrResult& encr_result, + GpgSignResult& sign_result); + + gpgme_error_t Decrypt(BypeArrayRef in_buffer, ByteArrayPtr& out_buffer, + GpgDecrResult& result); + + gpgme_error_t DecryptVerify(BypeArrayRef in_buffer, ByteArrayPtr& out_buffer, + GpgDecrResult& decrypt_result, + GpgVerifyResult& verify_result); + + gpgme_error_t Verify(BypeArrayRef in_buffer, ByteArrayPtr& sig_buffer, + GpgVerifyResult& result) const; + + gpg_error_t Sign(KeyListPtr keys, BypeArrayRef in_buffer, + ByteArrayPtr& out_buffer, gpgme_sig_mode_t mode, + GpgSignResult& result); + + void SetSigners(KeyArgsList& keys); + + std::unique_ptr<KeyArgsList> GetSigners(); + + private: + GpgContext& ctx = + GpgContext::GetInstance(SingletonFunctionObject::GetDefaultChannel()); +}; +} // namespace GpgFrontend + +#endif // GPGFRONTEND_ZH_CN_TS_BASICOPERATOR_H diff --git a/src/gpg/function/GpgCommandExecutor.cpp b/src/gpg/function/GpgCommandExecutor.cpp new file mode 100644 index 00000000..9b99b400 --- /dev/null +++ b/src/gpg/function/GpgCommandExecutor.cpp @@ -0,0 +1,59 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ +#include "gpg/function/GpgCommandExecutor.h" +#ifndef WINDOWS +#include <boost/asio.hpp> +#endif + +#ifndef WINDOWS + +using boost::process::async_pipe; + +void GpgFrontend::GpgCommandExecutor::Execute( + StringArgsRef arguments, + const std::function<void(async_pipe& in, async_pipe& out)>& interact_func) { + using namespace boost::process; + + boost::asio::io_service ios; + + std::vector<char> buf; + + async_pipe in_pipe_stream(ios); + async_pipe out_pipe_stream(ios); + + child child_process(ctx.GetInfo().AppPath.c_str(), arguments, + std_out > in_pipe_stream, std_in < out_pipe_stream); + + boost::asio::async_read( + in_pipe_stream, boost::asio::buffer(buf), + [&](const boost::system::error_code& ec, std::size_t size) { + interact_func(in_pipe_stream, out_pipe_stream); + }); + + ios.run(); + child_process.wait(); + child_process.exit_code(); +} + +#endif diff --git a/src/gpg/function/GpgCommandExecutor.h b/src/gpg/function/GpgCommandExecutor.h new file mode 100644 index 00000000..f28caca8 --- /dev/null +++ b/src/gpg/function/GpgCommandExecutor.h @@ -0,0 +1,52 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_ZH_CN_TS_GPGCOMMANDEXECUTOR_H +#define GPGFRONTEND_ZH_CN_TS_GPGCOMMANDEXECUTOR_H + +#ifndef WINDOWS +#include <boost/process.hpp> +#endif + +#include "gpg/GpgContext.h" +#include "gpg/GpgFunctionObject.h" + +namespace GpgFrontend { +class GpgCommandExecutor : public SingletonFunctionObject<GpgCommandExecutor> { + public: + +#ifndef WINDOWS + void Execute(StringArgsRef arguments, + const std::function<void(boost::process::async_pipe &in, + boost::process::async_pipe &out)> + &interact_func); +#endif + + private: + GpgContext &ctx = GpgContext::GetInstance(); +}; + +} // namespace GpgFrontend + +#endif // GPGFRONTEND_ZH_CN_TS_GPGCOMMANDEXECUTOR_H diff --git a/src/gpg/function/GpgFileOpera.cpp b/src/gpg/function/GpgFileOpera.cpp new file mode 100644 index 00000000..c3f75cf8 --- /dev/null +++ b/src/gpg/function/GpgFileOpera.cpp @@ -0,0 +1,162 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ +#include "gpg/function/GpgFileOpera.h" + +#include <memory> +#include <string> + +#include "GpgConstants.h" +#include "gpg/function/BasicOperator.h" + +GpgFrontend::GpgError GpgFrontend::GpgFileOpera::EncryptFile( + KeyListPtr keys, const std::string& path, GpgEncrResult& result) { + std::string in_buffer = read_all_data_in_file(path); + std::unique_ptr<std::string> out_buffer; + + auto err = BasicOperator::GetInstance().Encrypt(std::move(keys), in_buffer, + out_buffer, result); + + if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) + if (!write_buffer_to_file(path + ".asc", *out_buffer)) { + throw std::runtime_error("write_buffer_to_file error"); + }; + + return err; +} + +GpgFrontend::GpgError GpgFrontend::GpgFileOpera::DecryptFile( + const std::string& path, GpgDecrResult& result) { + std::string in_buffer = read_all_data_in_file(path); + std::unique_ptr<std::string> out_buffer; + + auto err = + BasicOperator::GetInstance().Decrypt(in_buffer, out_buffer, result); + + assert(check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR); + + std::string out_file_name = get_only_file_name_with_path(path), + file_extension = get_file_extension(path); + + if (!(file_extension == ".asc" || file_extension == ".gpg")) + out_file_name += ".out"; + + if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) + if (!write_buffer_to_file(out_file_name, *out_buffer)) { + throw std::runtime_error("write_buffer_to_file error"); + }; + + return err; +} + +gpgme_error_t GpgFrontend::GpgFileOpera::SignFile(KeyListPtr keys, + const std::string& path, + GpgSignResult& result) { + auto in_buffer = read_all_data_in_file(path); + std::unique_ptr<std::string> out_buffer; + + auto err = BasicOperator::GetInstance().Sign( + std::move(keys), in_buffer, out_buffer, GPGME_SIG_MODE_DETACH, result); + + if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) + if (!write_buffer_to_file(path + ".sig", *out_buffer)) { + throw std::runtime_error("write_buffer_to_file error"); + }; + + return err; +} + +gpgme_error_t GpgFrontend::GpgFileOpera::VerifyFile(const std::string& path, + GpgVerifyResult& result) { + auto in_buffer = read_all_data_in_file(path); + std::unique_ptr<std::string> sign_buffer = nullptr; + + if (get_file_extension(path) == ".gpg") { + auto err = + BasicOperator::GetInstance().Verify(in_buffer, sign_buffer, result); + assert(check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR); + return err; + } else { + sign_buffer = + std::make_unique<std::string>(read_all_data_in_file(path + ".sig")); + + auto err = + BasicOperator::GetInstance().Verify(in_buffer, sign_buffer, result); + return err; + } +} + +// TODO + +gpg_error_t GpgFrontend::GpgFileOpera::EncryptSignFile( + KeyListPtr keys, KeyListPtr signer_keys, const std::string& path, + GpgEncrResult& encr_res, GpgSignResult& sign_res) { + auto in_buffer = read_all_data_in_file(path); + std::unique_ptr<std::string> out_buffer = nullptr; + + // TODO dealing with signer keys + auto err = BasicOperator::GetInstance().EncryptSign( + std::move(keys), std::move(signer_keys), in_buffer, out_buffer, encr_res, + sign_res); + + auto out_path = path + ".gpg"; + LOG(INFO) << "EncryptSignFile out_path" << out_path; + LOG(INFO) << "EncryptSignFile out_buffer size" << out_buffer->size(); + + if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) + if (!write_buffer_to_file(out_path, *out_buffer)) { + throw std::runtime_error("write_buffer_to_file error"); + }; + + return err; +} + +gpg_error_t GpgFrontend::GpgFileOpera::DecryptVerifyFile( + const std::string& path, GpgDecrResult& decr_res, + GpgVerifyResult& verify_res) { + LOG(INFO) << "GpgFrontend::GpgFileOpera::DecryptVerifyFile Called"; + + auto in_buffer = read_all_data_in_file(path); + + LOG(INFO) << "GpgFrontend::GpgFileOpera::DecryptVerifyFile in_buffer" + << in_buffer.size(); + std::unique_ptr<std::string> out_buffer = nullptr; + + auto err = BasicOperator::GetInstance().DecryptVerify(in_buffer, out_buffer, + decr_res, verify_res); + + std::string out_file_name = get_only_file_name_with_path(path), + file_extension = get_file_extension(path); + + if (!(file_extension == ".asc" || file_extension == ".gpg")) + out_file_name = path + ".out"; + LOG(INFO) << "GpgFrontend::GpgFileOpera::DecryptVerifyFile out_file_name" + << out_file_name; + + if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) + if (!write_buffer_to_file(out_file_name, *out_buffer)) { + throw std::runtime_error("write_buffer_to_file error"); + }; + + return err; +} diff --git a/src/gpg/function/GpgFileOpera.h b/src/gpg/function/GpgFileOpera.h new file mode 100644 index 00000000..4aaf09f1 --- /dev/null +++ b/src/gpg/function/GpgFileOpera.h @@ -0,0 +1,58 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_GPGFILEOPERA_H +#define GPGFRONTEND_GPGFILEOPERA_H + +#include "gpg/GpgConstants.h" +#include "gpg/GpgContext.h" +#include "gpg/GpgModel.h" + +namespace GpgFrontend { + +class GpgFileOpera : public SingletonFunctionObject<GpgFileOpera> { + public: + static GpgError EncryptFile(KeyListPtr keys, const std::string& path, + GpgEncrResult& result); + + static GpgError DecryptFile(const std::string& path, GpgDecrResult& result); + + static GpgError SignFile(KeyListPtr keys, const std::string& path, + GpgSignResult& result); + + static GpgError VerifyFile(const std::string& path, GpgVerifyResult& result); + + static GpgError EncryptSignFile(KeyListPtr keys, KeyListPtr signer_keys, + const std::string& path, + GpgEncrResult& encr_res, + GpgSignResult& sign_res); + + static GpgError DecryptVerifyFile(const std::string& path, + GpgDecrResult& decr_res, + GpgVerifyResult& verify_res); +}; + +} // namespace GpgFrontend + +#endif // GPGFRONTEND_GPGFILEOPERA_H diff --git a/src/gpg/function/GpgKeyGetter.cpp b/src/gpg/function/GpgKeyGetter.cpp new file mode 100644 index 00000000..be27d69e --- /dev/null +++ b/src/gpg/function/GpgKeyGetter.cpp @@ -0,0 +1,75 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#include "gpg/function/GpgKeyGetter.h" + +#include <gpg-error.h> + +#include "GpgConstants.h" + +GpgFrontend::GpgKey GpgFrontend::GpgKeyGetter::GetKey(const std::string& fpr) { + gpgme_key_t _p_key; + gpgme_get_key(ctx, fpr.c_str(), &_p_key, 1); + if (_p_key == nullptr) { + DLOG(WARNING) << "GpgKeyGetter GetKey Private _p_key Null fpr" << fpr; + return GetPubkey(fpr); + } else { + return GpgKey(std::move(_p_key)); + } +} + +GpgFrontend::GpgKey GpgFrontend::GpgKeyGetter::GetPubkey( + const std::string& fpr) { + gpgme_key_t _p_key; + gpgme_get_key(ctx, fpr.c_str(), &_p_key, 0); + if (_p_key == nullptr) + DLOG(WARNING) << "GpgKeyGetter GetKey _p_key Null" << fpr; + return GpgKey(std::move(_p_key)); +} + +GpgFrontend::KeyLinkListPtr GpgFrontend::GpgKeyGetter::FetchKey() { + gpgme_error_t err; + + auto keys_list = std::make_unique<GpgKeyLinkList>(); + + err = gpgme_op_keylist_start(ctx, nullptr, 0); + assert(check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR); + + gpgme_key_t key; + while ((err = gpgme_op_keylist_next(ctx, &key)) == GPG_ERR_NO_ERROR) { + keys_list->push_back(GpgKey(std::move(key))); + } + + assert(check_gpg_error_2_err_code(err, GPG_ERR_EOF) == GPG_ERR_EOF); + + err = gpgme_op_keylist_end(ctx); + + return keys_list; +} +GpgFrontend::KeyListPtr GpgFrontend::GpgKeyGetter::GetKeys( + const KeyIdArgsListPtr& ids) { + auto keys = std::make_unique<KeyArgsList>(); + for (const auto& id : *ids) keys->push_back(GetKey(id)); + return keys; +} diff --git a/src/gpg/function/GpgKeyGetter.h b/src/gpg/function/GpgKeyGetter.h new file mode 100644 index 00000000..c8f5d73a --- /dev/null +++ b/src/gpg/function/GpgKeyGetter.h @@ -0,0 +1,52 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_ZH_CN_TS_GPGKEYGETTER_H +#define GPGFRONTEND_ZH_CN_TS_GPGKEYGETTER_H + +#include "gpg/GpgContext.h" +#include "gpg/GpgFunctionObject.h" +#include "gpg/GpgModel.h" + +namespace GpgFrontend { + +class GpgKeyGetter : public SingletonFunctionObject<GpgKeyGetter> { + public: + GpgKeyGetter() = default; + + GpgKey GetKey(const std::string& fpr); + + KeyListPtr GetKeys(const KeyIdArgsListPtr& ids); + + GpgKey GetPubkey(const std::string& fpr); + + KeyLinkListPtr FetchKey(); + + private: + GpgContext& ctx = + GpgContext::GetInstance(SingletonFunctionObject::GetDefaultChannel()); +}; +} // namespace GpgFrontend + +#endif // GPGFRONTEND_ZH_CN_TS_GPGKEYGETTER_H diff --git a/src/gpg/function/GpgKeyImportExportor.cpp b/src/gpg/function/GpgKeyImportExportor.cpp new file mode 100644 index 00000000..f4b88c60 --- /dev/null +++ b/src/gpg/function/GpgKeyImportExportor.cpp @@ -0,0 +1,117 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#include "gpg/function/GpgKeyImportExportor.h" + +#include "GpgConstants.h" + +/** + * Import key pair + * @param inBuffer input byte array + * @return Import information + */ +GpgFrontend::GpgImportInformation GpgFrontend::GpgKeyImportExportor::ImportKey( + StdBypeArrayPtr in_buffer) { + if (in_buffer->empty()) return GpgImportInformation(); + + GpgData data_in(in_buffer->data(), in_buffer->size()); + auto err = check_gpg_error(gpgme_op_import(ctx, data_in)); + assert(gpgme_err_code(err) == GPG_ERR_NO_ERROR); + gpgme_import_result_t result; + result = gpgme_op_import_result(ctx); + gpgme_import_status_t status = result->imports; + auto import_info = std::make_unique<GpgImportInformation>(result); + while (status != nullptr) { + GpgImportedKey key; + key.import_status = static_cast<int>(status->status); + key.fpr = status->fpr; + import_info->importedKeys.emplace_back(key); + status = status->next; + } + return *import_info; +} + +/** + * Export Key + * @param uid_list key ids + * @param out_buffer output byte array + * @return if success + */ +bool GpgFrontend::GpgKeyImportExportor::ExportKeys( + KeyIdArgsListPtr& uid_list, ByteArrayPtr& out_buffer) const { + if (uid_list->empty()) return false; + + // Alleviate another crash problem caused by an unknown array out-of-bounds + // access + for (size_t i = 0; i < uid_list->size(); i++) { + GpgData data_out; + auto err = gpgme_op_export(ctx, (*uid_list)[i].c_str(), 0, data_out); + assert(gpgme_err_code(err) == GPG_ERR_NO_ERROR); + + DLOG(INFO) << "exportKeys read_bytes" + << gpgme_data_seek(data_out, 0, SEEK_END); + + auto temp_out_buffer = data_out.Read2Buffer(); + std::swap(out_buffer, temp_out_buffer); + } + + return true; +} + +/** + * Export keys + * @param keys keys used + * @param outBuffer output byte array + * @return if success + */ +bool GpgFrontend::GpgKeyImportExportor::ExportKeys( + const KeyArgsList& keys, ByteArrayPtr& out_buffer) const { + KeyIdArgsListPtr key_ids = std::make_unique<std::vector<std::string>>(); + for (const auto& key : keys) key_ids->push_back(key.id()); + return ExportKeys(key_ids, out_buffer); +} + +/** + * Export the secret key of a key pair(including subkeys) + * @param key target key pair + * @param outBuffer output byte array + * @return if successful + */ +bool GpgFrontend::GpgKeyImportExportor::ExportSecretKey( + const GpgKey& key, ByteArrayPtr& out_buffer) const { + DLOG(INFO) << "Export Secret Key" << key.id().c_str(); + + gpgme_key_t target_key[2] = {gpgme_key_t(key), nullptr}; + + GpgData data_out; + + // export private key to outBuffer + gpgme_error_t err = + gpgme_op_export_keys(ctx, target_key, GPGME_EXPORT_MODE_SECRET, data_out); + + auto temp_out_buffer = data_out.Read2Buffer(); + std::swap(out_buffer, temp_out_buffer); + + return check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR; +} diff --git a/src/gpg/function/GpgKeyImportExportor.h b/src/gpg/function/GpgKeyImportExportor.h new file mode 100644 index 00000000..bceb87ef --- /dev/null +++ b/src/gpg/function/GpgKeyImportExportor.h @@ -0,0 +1,100 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef _GPGKEYIMPORTEXPORTOR_H +#define _GPGKEYIMPORTEXPORTOR_H + +#include <string> + +#include "gpg/GpgConstants.h" +#include "gpg/GpgContext.h" +#include "gpg/GpgFunctionObject.h" +#include "gpg/GpgModel.h" + +namespace GpgFrontend { + +class GpgImportedKey { + public: + std::string fpr; + int import_status; +}; + +typedef std::list<GpgImportedKey> GpgImportedKeyList; + +class GpgImportInformation { + public: + GpgImportInformation() = default; + + explicit GpgImportInformation(gpgme_import_result_t result) { + if (result->unchanged) unchanged = result->unchanged; + if (result->considered) considered = result->considered; + if (result->no_user_id) no_user_id = result->no_user_id; + if (result->imported) imported = result->imported; + if (result->imported_rsa) imported_rsa = result->imported_rsa; + if (result->unchanged) unchanged = result->unchanged; + if (result->new_user_ids) new_user_ids = result->new_user_ids; + if (result->new_sub_keys) new_sub_keys = result->new_sub_keys; + if (result->new_signatures) new_signatures = result->new_signatures; + if (result->new_revocations) new_revocations = result->new_revocations; + if (result->secret_read) secret_read = result->secret_read; + if (result->secret_imported) secret_imported = result->secret_imported; + if (result->secret_unchanged) secret_unchanged = result->secret_unchanged; + if (result->not_imported) not_imported = result->not_imported; + } + + int considered = 0; + int no_user_id = 0; + int imported = 0; + int imported_rsa = 0; + int unchanged = 0; + int new_user_ids = 0; + int new_sub_keys = 0; + int new_signatures = 0; + int new_revocations = 0; + int secret_read = 0; + int secret_imported = 0; + int secret_unchanged = 0; + int not_imported = 0; + GpgImportedKeyList importedKeys; +}; + +class GpgKeyImportExportor + : public SingletonFunctionObject<GpgKeyImportExportor> { + public: + GpgImportInformation ImportKey(StdBypeArrayPtr inBuffer); + + bool ExportKeys(KeyIdArgsListPtr& uid_list, ByteArrayPtr& out_buffer) const; + + bool ExportKeys(const KeyArgsList& keys, ByteArrayPtr& outBuffer) const; + + bool ExportSecretKey(const GpgKey& key, ByteArrayPtr& outBuffer) const; + + private: + GpgContext& ctx = + GpgContext::GetInstance(SingletonFunctionObject::GetDefaultChannel()); +}; + +} // namespace GpgFrontend + +#endif // _GPGKEYIMPORTEXPORTOR_H
\ No newline at end of file diff --git a/src/gpg/function/GpgKeyManager.cpp b/src/gpg/function/GpgKeyManager.cpp new file mode 100644 index 00000000..9e24b3d6 --- /dev/null +++ b/src/gpg/function/GpgKeyManager.cpp @@ -0,0 +1,88 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#include "gpg/function/GpgKeyManager.h" + +#include <boost/date_time/posix_time/conversion.hpp> +#include <string> + +#include "gpg/function/BasicOperator.h" +#include "gpg/function/GpgKeyGetter.h" + +bool GpgFrontend::GpgKeyManager::signKey( + const GpgFrontend::GpgKey& target, GpgFrontend::KeyArgsList& keys, + const std::string& uid, + const std::unique_ptr<boost::gregorian::date>& expires) { + using namespace boost::posix_time; + + BasicOperator::GetInstance().SetSigners(keys); + + unsigned int flags = 0; + unsigned int expires_time_t = 0; + + if (expires == nullptr) + flags |= GPGME_KEYSIGN_NOEXPIRE; + else + expires_time_t = to_time_t(ptime(*expires)); + + auto err = check_gpg_error(gpgme_op_keysign( + ctx, gpgme_key_t(target), uid.c_str(), expires_time_t, flags)); + + return check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR; +} + +bool GpgFrontend::GpgKeyManager::revSign( + const GpgFrontend::GpgKey& key, + const GpgFrontend::SignIdArgsListPtr& signature_id) { + auto& key_getter = GpgKeyGetter::GetInstance(); + + for (const auto& sign_id : *signature_id) { + auto signing_key = key_getter.GetKey(sign_id.first); + assert(signing_key.good()); + auto err = check_gpg_error(gpgme_op_revsig(ctx, gpgme_key_t(key), + gpgme_key_t(signing_key), + sign_id.second.c_str(), 0)); + if (check_gpg_error_2_err_code(err) != GPG_ERR_NO_ERROR) return false; + } + return true; +} + +bool GpgFrontend::GpgKeyManager::setExpire( + const GpgFrontend::GpgKey& key, std::unique_ptr<GpgSubKey>& subkey, + std::unique_ptr<boost::gregorian::date>& expires) { + using namespace boost::posix_time; + + unsigned long expires_time = 0; + + if (expires != nullptr) expires_time = to_time_t(ptime(*expires)); + + const char* sub_fprs = nullptr; + + if (subkey != nullptr) sub_fprs = subkey->fpr().c_str(); + + auto err = check_gpg_error( + gpgme_op_setexpire(ctx, gpgme_key_t(key), expires_time, sub_fprs, 0)); + + return check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR; +} diff --git a/src/gpg/function/GpgKeyManager.h b/src/gpg/function/GpgKeyManager.h new file mode 100644 index 00000000..2b07425c --- /dev/null +++ b/src/gpg/function/GpgKeyManager.h @@ -0,0 +1,58 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_ZH_CN_TS_GPGKEYMANAGER_H +#define GPGFRONTEND_ZH_CN_TS_GPGKEYMANAGER_H + +#include "gpg/GpgContext.h" +#include "gpg/GpgFunctionObject.h" +#include "gpg/GpgModel.h" + +namespace GpgFrontend { + +class GpgKeyManager : public SingletonFunctionObject<GpgKeyManager> { + public: + /** + * Sign a key pair(actually a certain uid) + * @param target target key pair + * @param uid target + * @param expires expire date and time of the signature + * @return if successful + */ + bool signKey(const GpgKey& target, KeyArgsList& keys, const std::string& uid, + const std::unique_ptr<boost::gregorian::date>& expires); + + bool revSign(const GpgFrontend::GpgKey& key, + const GpgFrontend::SignIdArgsListPtr& signature_id); + + bool setExpire(const GpgKey& key, std::unique_ptr<GpgSubKey>& subkey, + std::unique_ptr<boost::gregorian::date>& expires); + + private: + GpgContext& ctx = GpgContext::GetInstance(); +}; + +} // namespace GpgFrontend + +#endif // GPGFRONTEND_ZH_CN_TS_GPGKEYMANAGER_H diff --git a/src/gpg/function/GpgKeyOpera.cpp b/src/gpg/function/GpgKeyOpera.cpp new file mode 100644 index 00000000..c60f9157 --- /dev/null +++ b/src/gpg/function/GpgKeyOpera.cpp @@ -0,0 +1,217 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#include "gpg/function/GpgKeyOpera.h" + +#include <boost/asio.hpp> +#include <boost/date_time/posix_time/conversion.hpp> +#include <boost/process/async_pipe.hpp> +#include <memory> +#include <string> +#include <vector> + +#include "gpg/GpgConstants.h" +#include "gpg/GpgGenKeyInfo.h" +#include "gpg/function/GpgCommandExecutor.h" +#include "gpg/function/GpgKeyGetter.h" + +/** + * Delete keys + * @param uidList key ids + */ +void GpgFrontend::GpgKeyOpera::DeleteKeys( + GpgFrontend::KeyIdArgsListPtr key_ids) { + GpgError err; + for (const auto& tmp : *key_ids) { + auto key = GpgKeyGetter::GetInstance().GetKey(tmp); + if (key.good()) { + LOG(INFO) << "GpgKeyOpera DeleteKeys Get Key Good"; + err = check_gpg_error(gpgme_op_delete(ctx, gpgme_key_t(key), 1)); + assert(gpg_err_code(err) == GPG_ERR_NO_ERROR); + } else + LOG(WARNING) << "GpgKeyOpera DeleteKeys Get Key Bad"; + } +} + +/** + * Set the expire date and time of a key pair(actually the master key) or subkey + * @param key target key pair + * @param subkey null if master key + * @param expires date and time + * @return if successful + */ +GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::SetExpire( + const GpgKey& key, const SubkeyId& subkey_fpr, + std::unique_ptr<boost::gregorian::date>& expires) { + unsigned long expires_time = 0; + if (expires != nullptr) { + using namespace boost::posix_time; + using namespace std::chrono; + expires_time = to_time_t(ptime(*expires)) - + system_clock::to_time_t(system_clock::now()); + } + + LOG(INFO) << "GpgFrontend::GpgKeyOpera::SetExpire" << key.id() << subkey_fpr + << expires_time; + + GpgError err; + if (subkey_fpr.empty()) + err = gpgme_op_setexpire(ctx, gpgme_key_t(key), expires_time, nullptr, 0); + else + err = gpgme_op_setexpire(ctx, gpgme_key_t(key), expires_time, + subkey_fpr.c_str(), 0); + + return err; +} + +/** + * Generate revoke cert of a key pair + * @param key target key pair + * @param outputFileName out file name(path) + * @return the process doing this job + */ +void GpgFrontend::GpgKeyOpera::GenerateRevokeCert( + const GpgKey& key, const std::string& output_file_name) { + auto args = std::vector<std::string>{ + "--no-tty", "--command-fd", "0", "--status-fd", "1", "-o", + output_file_name, "--gen-revoke", key.fpr()}; + + using boost::asio::async_write; + using boost::process::async_pipe; +#ifndef WINDOWS + GpgCommandExecutor::GetInstance().Execute( + args, [](async_pipe& in, async_pipe& out) -> void { + // boost::asio::streambuf buff; + // boost::asio::read_until(in, buff, '\n'); + // + // std::istream is(&buff); + // + // while (!is.eof()) { + // std::string line; + // is >> line; + // LOG(INFO) << "line" << line; + // boost::algorithm::trim(line); + // if (line == std::string("[GNUPG:] GET_BOOL + // gen_revoke.okay")) { + // + // } else if (line == + // std::string( + // "[GNUPG:] GET_LINE + // ask_revocation_reason.code")) { + // + // } else if (line == + // std::string( + // "[GNUPG:] GET_LINE + // ask_revocation_reason.text")) { + // + // } else if (line == + // std::string("[GNUPG:] GET_BOOL + // openfile.overwrite.okay")) { + // + // } else if (line == + // std::string( + // "[GNUPG:] GET_BOOL + // ask_revocation_reason.okay")) { + // + // } + // } + }); +#endif +} + +/** + * Generate a new key pair + * @param params key generation args + * @return error information + */ +GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::GenerateKey( + const std::unique_ptr<GenKeyInfo>& params) { + auto userid_utf8 = params->getUserid(); + const char* userid = userid_utf8.c_str(); + auto algo_utf8 = params->getAlgo() + params->getKeySizeStr(); + + LOG(INFO) << "GpgFrontend::GpgKeyOpera::GenerateKey Params" + << params->getAlgo() << params->getKeySizeStr(); + + const char* algo = algo_utf8.c_str(); + unsigned long expires = 0; + { + using namespace boost::posix_time; + using namespace std::chrono; + expires = to_time_t(ptime(params->getExpired())) - + system_clock::to_time_t(system_clock::now()); + } + + unsigned int flags = 0; + + if (!params->isSubKey()) flags |= GPGME_CREATE_CERT; + if (params->isAllowEncryption()) flags |= GPGME_CREATE_ENCR; + if (params->isAllowSigning()) flags |= GPGME_CREATE_SIGN; + if (params->isAllowAuthentication()) flags |= GPGME_CREATE_AUTH; + if (params->isNonExpired()) flags |= GPGME_CREATE_NOEXPIRE; + if (params->isNoPassPhrase()) flags |= GPGME_CREATE_NOPASSWD; + + LOG(INFO) << "GpgFrontend::GpgKeyOpera::GenerateKey Args: " << userid << algo + << expires << flags; + + auto err = gpgme_op_createkey(ctx, userid, algo, 0, expires, nullptr, flags); + return check_gpg_error(err); +} + +/** + * Generate a new subkey of a certain key pair + * @param key target key pair + * @param params opera args + * @return error info + */ +GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::GenerateSubkey( + const GpgKey& key, const std::unique_ptr<GenKeyInfo>& params) { + if (!params->isSubKey()) return GPG_ERR_CANCELED; + + auto algo_utf8 = (params->getAlgo() + params->getKeySizeStr()); + const char* algo = algo_utf8.c_str(); + unsigned long expires = 0; + { + using namespace boost::posix_time; + using namespace std::chrono; + expires = to_time_t(ptime(params->getExpired())) - + system_clock::to_time_t(system_clock::now()); + } + unsigned int flags = 0; + + if (!params->isSubKey()) flags |= GPGME_CREATE_CERT; + if (params->isAllowEncryption()) flags |= GPGME_CREATE_ENCR; + if (params->isAllowSigning()) flags |= GPGME_CREATE_SIGN; + if (params->isAllowAuthentication()) flags |= GPGME_CREATE_AUTH; + if (params->isNonExpired()) flags |= GPGME_CREATE_NOEXPIRE; + + flags |= GPGME_CREATE_NOPASSWD; + + LOG(INFO) << "GpgFrontend::GpgKeyOpera::GenerateSubkey Args: " << key.id() + << algo << expires << flags; + + auto err = + gpgme_op_createsubkey(ctx, gpgme_key_t(key), algo, 0, expires, flags); + return check_gpg_error(err); +}
\ No newline at end of file diff --git a/src/gpg/function/GpgKeyOpera.h b/src/gpg/function/GpgKeyOpera.h new file mode 100644 index 00000000..71e2de8b --- /dev/null +++ b/src/gpg/function/GpgKeyOpera.h @@ -0,0 +1,54 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef _GPGKEYOPERA_H +#define _GPGKEYOPERA_H + +#include "gpg/GpgConstants.h" +#include "gpg/GpgContext.h" +#include "gpg/GpgModel.h" + +namespace GpgFrontend { +class GenKeyInfo; +class GpgKeyOpera : public SingletonFunctionObject<GpgKeyOpera> { + public: + void DeleteKeys(KeyIdArgsListPtr key_ids); + + GpgError SetExpire(const GpgKey& key, const SubkeyId& subkey_fpr, + std::unique_ptr<boost::gregorian::date>& expires); + + static void GenerateRevokeCert(const GpgKey& key, + const std::string& output_file_name); + + GpgFrontend::GpgError GenerateKey(const std::unique_ptr<GenKeyInfo>& params); + + GpgFrontend::GpgError GenerateSubkey( + const GpgKey& key, const std::unique_ptr<GenKeyInfo>& params); + + private: + GpgContext& ctx = GpgContext::GetInstance(); +}; +} // namespace GpgFrontend + +#endif // _GPGKEYOPERA_H
\ No newline at end of file diff --git a/src/gpg/function/UidOperator.cpp b/src/gpg/function/UidOperator.cpp new file mode 100644 index 00000000..d7acc3b1 --- /dev/null +++ b/src/gpg/function/UidOperator.cpp @@ -0,0 +1,64 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#include "gpg/function/UidOperator.h" + +#include "boost/format.hpp" + +bool GpgFrontend::UidOperator::addUID(const GpgFrontend::GpgKey& key, + const std::string& uid) { + auto err = gpgme_op_adduid(ctx, gpgme_key_t(key), uid.c_str(), 0); + if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) + return true; + else + return false; +} + +bool GpgFrontend::UidOperator::revUID(const GpgFrontend::GpgKey& key, + const std::string& uid) { + auto err = + check_gpg_error(gpgme_op_revuid(ctx, gpgme_key_t(key), uid.c_str(), 0)); + if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) + return true; + else + return false; +} + +bool GpgFrontend::UidOperator::setPrimaryUID(const GpgFrontend::GpgKey& key, + const std::string& uid) { + auto err = check_gpg_error(gpgme_op_set_uid_flag( + ctx, gpgme_key_t(key), uid.c_str(), "primary", nullptr)); + if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) + return true; + else + return false; +} +bool GpgFrontend::UidOperator::addUID(const GpgFrontend::GpgKey& key, + const std::string& name, + const std::string& comment, + const std::string& email) { + LOG(INFO) << "GpgFrontend::UidOperator::addUID" << name << comment << email; + auto uid = boost::format("%1%(%2%)<%3%>") % name % comment % email; + return addUID(key, uid.str()); +} diff --git a/src/gpg/function/UidOperator.h b/src/gpg/function/UidOperator.h new file mode 100644 index 00000000..7d5df254 --- /dev/null +++ b/src/gpg/function/UidOperator.h @@ -0,0 +1,76 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_ZH_CN_TS_UIDOPERATOR_H +#define GPGFRONTEND_ZH_CN_TS_UIDOPERATOR_H + +#include "gpg/GpgContext.h" +#include "gpg/GpgModel.h" + +namespace GpgFrontend { + +class UidOperator : public SingletonFunctionObject<UidOperator> { + public: + /** + * create a new uid in certain key pair + * @param key target key pair + * @param uid uid args(combine name&comment&email) + * @return if successful + */ + bool addUID(const GpgKey& key, const std::string& uid); + + /** + * create a new uid in certain key pair + * @param key target key pair + * @param name + * @param comment + * @param email + * @return + */ + bool addUID(const GpgKey& key, const std::string& name, + const std::string& comment, const std::string& email); + + /** + * Revoke(Delete) UID from certain key pair + * @param key target key pair + * @param uid target uid + * @return if successful + */ + bool revUID(const GpgKey& key, const std::string& uid); + + /** + * Set one of a uid of a key pair as primary + * @param key target key pair + * @param uid target uid + * @return if successful + */ + bool setPrimaryUID(const GpgKey& key, const std::string& uid); + + private: + GpgContext& ctx = GpgContext::GetInstance(); +}; + +} // namespace GpgFrontend + +#endif // GPGFRONTEND_ZH_CN_TS_UIDOPERATOR_H diff --git a/src/gpg/gpg_context/GpgContext.cpp b/src/gpg/gpg_context/GpgContext.cpp deleted file mode 100644 index 14b54b32..00000000 --- a/src/gpg/gpg_context/GpgContext.cpp +++ /dev/null @@ -1,410 +0,0 @@ -/** - * This file is part of GPGFrontend. - * - * GPGFrontend is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Foobar is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see <https://www.gnu.org/licenses/>. - * - * The initial version of the source code is inherited from gpg4usb-team. - * Their source code version also complies with GNU General Public License. - * - * The source code version of this software was modified and released - * by Saturneric<[email protected]> starting on May 12, 2021. - * - */ - -#include "gpg/GpgContext.h" -#include "ui/WaitingDialog.h" - -#include <functional> -#include <unistd.h> /* contains read/write */ - -#ifdef _WIN32 - -#include <windows.h> - -#endif - -#define INT2VOIDP(i) (void*)(uintptr_t)(i) - -namespace GpgME { - - /** Constructor - * Set up gpgme-context, set paths to app-run path - */ - GpgContext::GpgContext() { - - /** The function `gpgme_check_version' must be called before any other - * function in the library, because it initializes the thread support - * subsystem in GPGME. (from the info page) */ - gpgme_check_version(nullptr); - - // the locale set here is used for the other setlocale calls which have nullptr - // -> nullptr means use default, which is configured here - setlocale(LC_ALL, settings.value("int/lang").toLocale().name().toUtf8().constData()); - - /** set locale, because tests do also */ - gpgme_set_locale(nullptr, LC_CTYPE, setlocale(LC_CTYPE, nullptr)); - //qDebug() << "Locale set to" << LC_CTYPE << " - " << setlocale(LC_CTYPE, nullptr); -#ifndef _WIN32 - gpgme_set_locale(nullptr, LC_MESSAGES, setlocale(LC_MESSAGES, nullptr)); -#endif - - err = gpgme_new(&mCtx); - checkErr(err); - - gpgme_engine_info_t engineInfo; - engineInfo = gpgme_ctx_get_engine_info(mCtx); - -// Check ENV before running - bool check_pass = false, find_openpgp = false, find_gpgconf = false, find_assuan = false, find_cms = false; - while (engineInfo != nullptr) { - qDebug() << gpgme_get_protocol_name(engineInfo->protocol) << engineInfo->file_name << engineInfo->protocol - << engineInfo->home_dir << engineInfo->version; - if (engineInfo->protocol == GPGME_PROTOCOL_GPGCONF && strcmp(engineInfo->version, "1.0.0") != 0) - find_gpgconf = true; - if (engineInfo->protocol == GPGME_PROTOCOL_OpenPGP && strcmp(engineInfo->version, "1.0.0") != 0) - find_openpgp = true, info.appPath = engineInfo->file_name; - if (engineInfo->protocol == GPGME_PROTOCOL_CMS && strcmp(engineInfo->version, "1.0.0") != 0) - find_cms = true; - if (engineInfo->protocol == GPGME_PROTOCOL_ASSUAN) - find_assuan = true; - - engineInfo = engineInfo->next; - } - - if (find_gpgconf && find_openpgp && find_cms && find_assuan) - check_pass = true; - - if (!check_pass) { - good = false; - return; - } else good = true; - - -/** Setting the output type must be done at the beginning */ -/** think this means ascii-armor --> ? */ - gpgme_set_armor(mCtx, 1); -/** passphrase-callback */ - gpgme_set_passphrase_cb(mCtx, passphraseCb, this); - -/** check if app is called with -d from command line */ - if (qApp->arguments().contains("-d")) { - qDebug() << "gpgme_data_t debug on"; - debug = true; - } else { - debug = false; - } - - connect(this, SIGNAL(signalKeyDBChanged()), - this, SLOT(slotRefreshKeyList()), Qt::DirectConnection); - connect(this, SIGNAL(signalKeyUpdated(QString)), - this, SLOT(slotUpdateKeyList(QString)), Qt::DirectConnection); - slotRefreshKeyList(); - } - - /** Destructor - * Release gpgme-context - */ - GpgContext::~GpgContext() { - if (mCtx) gpgme_release(mCtx); - mCtx = nullptr; - } - - bool GpgContext::isGood() const { - return good; - } - - /** Read gpgme-Data to QByteArray - * mainly from http://basket.kde.org/ (kgpgme.cpp) - */ -#define BUF_SIZE (32 * 1024) - - gpgme_error_t GpgContext::readToBuffer(gpgme_data_t dataIn, QByteArray *outBuffer) { - gpgme_off_t ret; - gpgme_error_t gpgErrNoError = GPG_ERR_NO_ERROR; - - ret = gpgme_data_seek(dataIn, 0, SEEK_SET); - if (ret) { - gpgErrNoError = gpgme_err_code_from_errno(errno); - checkErr(gpgErrNoError, "failed dataseek dataIn readToBuffer"); - } else { - char buf[BUF_SIZE + 2]; - - while ((ret = gpgme_data_read(dataIn, buf, BUF_SIZE)) > 0) { - const size_t size = outBuffer->size(); - outBuffer->resize(static_cast<int>(size + ret)); - memcpy(outBuffer->data() + size, buf, ret); - } - if (ret < 0) { - gpgErrNoError = gpgme_err_code_from_errno(errno); - checkErr(gpgErrNoError, "failed data_read dataIn readToBuffer"); - } - } - return gpgErrNoError; - } - - /** - * The Passphrase window, if not provided by env-Var GPG_AGENT_INFO - * originally copied from http://basket.kde.org/ (kgpgme.cpp), but modified - */ - gpgme_error_t GpgContext::passphraseCb(void *hook, const char *uid_hint, - const char *passphrase_info, - int last_was_bad, int fd) { - auto *gpg = static_cast<GpgContext *>(hook); - return gpg->passphrase(uid_hint, passphrase_info, last_was_bad, fd); - } - - gpgme_error_t GpgContext::passphrase(const char *uid_hint, - const char * /*passphrase_info*/, - int last_was_bad, int fd) { - - gpgme_error_t returnValue = GPG_ERR_CANCELED; - QString passwordDialogMessage; - QString gpgHint = QString::fromUtf8(uid_hint); - bool result; - -#ifdef _WIN32 - DWORD written; - auto hd = INT2VOIDP(fd); -#endif - - if (last_was_bad) { - passwordDialogMessage += "<i>" + tr("Wrong password") + ".</i><br><br>\n\n"; - clearPasswordCache(); - } - - /** if uid provided */ - if (!gpgHint.isEmpty()) { - // remove UID, leave only username & email - gpgHint.remove(0, gpgHint.indexOf(" ")); - passwordDialogMessage += "<b>" + tr("Enter Password for") + "</b><br>" + gpgHint + "<br>"; - } - - if (mPasswordCache.isEmpty()) { - QString password = QInputDialog::getText(QApplication::activeWindow(), tr("Enter Password"), - passwordDialogMessage, QLineEdit::Password, - "", &result); - - if (result) mPasswordCache = password.toUtf8(); - } else result = true; - - if (result) { - -#ifndef _WIN32 - if (write(fd, mPasswordCache.data(), mPasswordCache.length()) == -1) qDebug() << "something is terribly broken"; -#else - WriteFile(hd, mPasswordCache.data(), mPasswordCache.length(), &written, 0); -#endif - returnValue = GPG_ERR_NO_ERROR; - } - -#ifndef _WIN32 - if (write(fd, "\n", 1) == -1) qDebug() << "something is terribly broken"; -#else - WriteFile(hd, "\n", 1, &written, 0); - - /* program will hang on cancel if hd not closed */ - if (!result) CloseHandle(hd); -#endif - - return returnValue; - } - - /** also from kgpgme.cpp, seems to clear password from mem */ - void GpgContext::clearPasswordCache() { - if (mPasswordCache.size() > 0) { - mPasswordCache.fill('\0'); - mPasswordCache.truncate(0); - } - } - - // error-handling - void GpgContext::checkErr(gpgme_error_t gpgmeError, const QString &comment) { - //if (gpgmeError != GPG_ERR_NO_ERROR && gpgmeError != GPG_ERR_CANCELED) { - if (gpgmeError != GPG_ERR_NO_ERROR) { - qDebug() << "[Error " << gpg_err_code(gpgmeError) - << "] Source: " << gpgme_strsource(gpgmeError) << " Description: " << gpgErrString(gpgmeError); - } - } - - void GpgContext::checkErr(gpgme_error_t gpgmeError) { - //if (gpgmeError != GPG_ERR_NO_ERROR && gpgmeError != GPG_ERR_CANCELED) { - if (gpg_err_code(gpgmeError) != GPG_ERR_NO_ERROR) { - qDebug() << "[Error " << gpg_err_code(gpgmeError) - << "] Source: " << gpgme_strsource(gpgmeError) << " Description: " << gpgErrString(gpgmeError); - } - } - - QString GpgContext::gpgErrString(gpgme_error_t err) { - return QString::fromUtf8(gpgme_strerror(err)); - } - - /** return type should be gpgme_error_t*/ - void - GpgContext::executeGpgCommand(const QStringList &arguments, const std::function<void(QProcess *)> &interactFunc) { - QEventLoop looper; - auto dialog = new WaitingDialog(tr("Processing"), nullptr); - dialog->show(); - auto *gpgProcess = new QProcess(&looper); - gpgProcess->setProcessChannelMode(QProcess::MergedChannels); - connect(gpgProcess, qOverload<int, QProcess::ExitStatus>(&QProcess::finished), &looper, &QEventLoop::quit); - connect(gpgProcess, qOverload<int, QProcess::ExitStatus>(&QProcess::finished), dialog, - &WaitingDialog::deleteLater); - connect(gpgProcess, &QProcess::errorOccurred, []() -> void { qDebug("Error in Process"); }); - connect(gpgProcess, &QProcess::errorOccurred, &looper, &QEventLoop::quit); - connect(gpgProcess, &QProcess::started, []() -> void { qDebug() << "Gpg Process Started Success"; }); - connect(gpgProcess, &QProcess::readyReadStandardOutput, [interactFunc, gpgProcess]() { - qDebug() << "Function Called"; - interactFunc(gpgProcess); - }); - gpgProcess->setProgram(info.appPath); - gpgProcess->setArguments(arguments); - gpgProcess->start(); - looper.exec(); - dialog->close(); - - } - - - /* - * if there is no '\n' before the PGP-Begin-Block, but for example a whitespace, - * GPGME doesn't recognise the Message as encrypted. This function adds '\n' - * before the PGP-Begin-Block, if missing. - */ - void GpgContext::preventNoDataErr(QByteArray *in) { - int block_start = in->indexOf(GpgConstants::PGP_CRYPT_BEGIN); - if (block_start > 0 && in->at(block_start - 1) != '\n') { - in->insert(block_start, '\n'); - } - block_start = in->indexOf(GpgConstants::PGP_SIGNED_BEGIN); - if (block_start > 0 && in->at(block_start - 1) != '\n') { - in->insert(block_start, '\n'); - } - } - - /* - * isSigned returns: - * - 0, if text isn't signed at all - * - 1, if text is partially signed - * - 2, if text is completly signed - */ - int GpgContext::textIsSigned(const QByteArray &text) { - if (text.trimmed().startsWith(GpgConstants::PGP_SIGNED_BEGIN) && - text.trimmed().endsWith(GpgConstants::PGP_SIGNED_END)) - return 2; - else if (text.contains(GpgConstants::PGP_SIGNED_BEGIN) && text.contains(GpgConstants::PGP_SIGNED_END)) - return 1; - - else return 0; - } - - QString GpgContext::beautifyFingerprint(QString fingerprint) { - uint len = fingerprint.length(); - if ((len > 0) && (len % 4 == 0)) - for (uint n = 0; 4 * (n + 1) < len; ++n) fingerprint.insert(static_cast<int>(5u * n + 4u), ' '); - return fingerprint; - } - - void GpgContext::slotRefreshKeyList() { - qDebug() << "Refreshing Keys"; - this->fetch_keys(); - emit signalKeyInfoChanged(); - } - - QString GpgContext::getGpgmeVersion() { - return {gpgme_check_version(nullptr)}; - } - - const GpgKeyList &GpgContext::getKeys() const { - return mKeyList; - } - - void GpgContext::getSigners(QVector<GpgKey> &signer, gpgme_ctx_t ctx) { - auto count = gpgme_signers_count(ctx); - signer.clear(); - for (auto i = 0; i < count; i++) { - auto key = gpgme_signers_enum(ctx, i); - auto it = mKeyMap.find(key->subkeys->keyid); - if (it == mKeyMap.end()) { - qDebug() << "Inconsistent state"; - signer.push_back(GpgKey(key)); - } else { - signer.push_back(*it.value()); - } - } - } - - void GpgContext::setSigners(const QVector<GpgKey> &keys, gpgme_ctx_t ctx) { - gpgme_signers_clear(ctx); - for (const auto &key : keys) { - if (checkIfKeyCanSign(key)) { - auto gpgmeError = gpgme_signers_add(ctx, key.key_refer); - checkErr(gpgmeError); - } - } - if (keys.length() != gpgme_signers_count(ctx)) { - qDebug() << "No All Keys Added"; - } - } - - void GpgContext::slotUpdateKeyList(const QString &key_id) { - auto it = mKeyMap.find(key_id); - if (it != mKeyMap.end()) { - gpgme_key_t new_key_refer; - auto gpgmeErr = gpgme_get_key(mCtx, key_id.toUtf8().constData(), &new_key_refer, 0); - - if (gpgme_err_code(gpgmeErr) == GPG_ERR_EOF) { - gpgmeErr = gpgme_get_key(mCtx, key_id.toUtf8().constData(), &new_key_refer, 1); - - if (gpgme_err_code(gpgmeErr) == GPG_ERR_EOF) { - throw std::runtime_error("key_id not found in key database"); - } - - } - - if (new_key_refer != nullptr) { - it.value()->swapKeyRefer(new_key_refer); - emit signalKeyInfoChanged(); - } - - } - } - - bool GpgContext::revSign(const GpgKey &key, const GpgKeySignature &signature) { - - auto signing_key = getKeyById(signature.keyid); - - auto gpgmeError = gpgme_op_revsig(mCtx, key.key_refer, - signing_key.key_refer, - signature.uid.toUtf8().constData(), 0); - if (gpg_err_code(gpgmeError) == GPG_ERR_NO_ERROR) { - emit signalKeyUpdated(key.id); - return true; - } else { - checkErr(gpgmeError); - return false; - } - } - - gpgme_ctx_t GpgME::GpgContext::create_ctx() { - gpgme_ctx_t ctx; - err = gpgme_new(&ctx); - checkErr(err); - - gpgme_set_armor(ctx, 1); - gpgme_set_passphrase_cb(ctx, passphraseCb, this); - return ctx; - } - - -} diff --git a/src/gpg/gpg_context/GpgContextBasicOpera.cpp b/src/gpg/gpg_context/GpgContextBasicOpera.cpp deleted file mode 100644 index d9bf0bdb..00000000 --- a/src/gpg/gpg_context/GpgContextBasicOpera.cpp +++ /dev/null @@ -1,315 +0,0 @@ -/** - * This file is part of GPGFrontend. - * - * GPGFrontend is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Foobar is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see <https://www.gnu.org/licenses/>. - * - * The initial version of the source code is inherited from gpg4usb-team. - * Their source code version also complies with GNU General Public License. - * - * The source code version of this software was modified and released - * by Saturneric<[email protected]> starting on May 12, 2021. - * - */ - -#include "gpg/GpgContext.h" - -/** - * Encrypt data - * @param keys keys used - * @param inBuffer input byte array - * @param outBuffer output byte array - * @param result opera result - * @return error information - */ -gpg_error_t GpgME::GpgContext::encrypt(QVector<GpgKey> &keys, const QByteArray &inBuffer, QByteArray *outBuffer, - gpgme_encrypt_result_t *result) { - - gpgme_data_t dataIn = nullptr, dataOut = nullptr; - outBuffer->resize(0); - - // gpgme_encrypt_result_t e_result; - gpgme_key_t recipients[keys.count() + 1]; - - int index = 0; - for (const auto &key : keys) recipients[index++] = key.key_refer; - - // Last entry dataIn array has to be nullptr - recipients[keys.count()] = nullptr; - - // If the last parameter isnt 0, a private copy of data is made - if (mCtx) { - err = gpgme_data_new_from_mem(&dataIn, inBuffer.data(), inBuffer.size(), 1); - checkErr(err); - if (!err) { - err = gpgme_data_new(&dataOut); - checkErr(err); - if (!err) { - err = gpgme_op_encrypt(mCtx, recipients, GPGME_ENCRYPT_ALWAYS_TRUST, dataIn, dataOut); - checkErr(err); - if (!err) { - err = readToBuffer(dataOut, outBuffer); - checkErr(err); - } - } - } - } - if (dataIn) gpgme_data_release(dataIn); - if (dataOut) gpgme_data_release(dataOut); - - if (result != nullptr) *result = gpgme_op_encrypt_result(mCtx); - return err; -} - -/** - * Decrypt data - * @param keys keys used - * @param inBuffer input byte array - * @param outBuffer output byte array - * @param result opera result - * @return error information - */ -gpgme_error_t GpgME::GpgContext::decrypt(const QByteArray &inBuffer, QByteArray *outBuffer, - gpgme_decrypt_result_t *result) { - gpgme_data_t dataIn = nullptr, dataOut = nullptr; - gpgme_decrypt_result_t m_result = nullptr; - - outBuffer->resize(0); - if (mCtx != nullptr) { - err = gpgme_data_new_from_mem(&dataIn, inBuffer.data(), inBuffer.size(), 1); - if (gpgme_err_code(err) == GPG_ERR_NO_ERROR) { - err = gpgme_data_new(&dataOut); - if (gpgme_err_code(err) == GPG_ERR_NO_ERROR) { - err = gpgme_op_decrypt(mCtx, dataIn, dataOut); - m_result = gpgme_op_decrypt_result(mCtx); - if (gpgme_err_code(err) == GPG_ERR_NO_ERROR) err = readToBuffer(dataOut, outBuffer); - } - } - } - - if (!settings.value("general/rememberPassword").toBool()) clearPasswordCache(); - - if (dataIn) gpgme_data_release(dataIn); - if (dataOut) gpgme_data_release(dataOut); - - if (result != nullptr) *result = m_result; - - return err; -} - -/** - * Verify data - * @param keys keys used - * @param inBuffer input byte array - * @param sigBuffer signature byte array (detected by format) - * @param result opera result - * @return error information - */ -gpgme_error_t GpgME::GpgContext::verify(QByteArray *inBuffer, QByteArray *sigBuffer, gpgme_verify_result_t *result) { - - gpgme_data_t dataIn; - gpgme_error_t gpgmeError; - gpgme_verify_result_t m_result; - - gpgmeError = gpgme_data_new_from_mem(&dataIn, inBuffer->data(), inBuffer->size(), 1); - checkErr(gpgmeError); - - if (sigBuffer != nullptr) { - gpgme_data_t sigdata; - gpgmeError = gpgme_data_new_from_mem(&sigdata, sigBuffer->data(), sigBuffer->size(), 1); - checkErr(gpgmeError); - gpgmeError = gpgme_op_verify(mCtx, sigdata, dataIn, nullptr); - } else { - gpgmeError = gpgme_op_verify(mCtx, dataIn, nullptr, dataIn); - } - - checkErr(gpgmeError); - - m_result = gpgme_op_verify_result(mCtx); - - if (result != nullptr) { - *result = m_result; - } - - return gpgmeError; -} - -/** - * Sign data - * @param keys keys used - * @param inBuffer input byte array - * @param outBuffer output byte array - * @param mode sign mode - * @param result opera result - * @return - */ -gpg_error_t GpgME::GpgContext::sign(const QVector<GpgKey> &keys, const QByteArray &inBuffer, QByteArray *outBuffer, - gpgme_sig_mode_t mode, gpgme_sign_result_t *result, bool default_ctx) { - - gpgme_error_t gpgmeError; - gpgme_data_t dataIn, dataOut; - gpgme_sign_result_t m_result; - - auto _ctx = mCtx; - - if(!default_ctx) - _ctx = create_ctx(); - - if (keys.isEmpty()) { - QMessageBox::critical(nullptr, tr("Key Selection"), tr("No Private Key Selected")); - return false; - } - - // Set Singers of this opera - setSigners(keys, _ctx); - - gpgmeError = gpgme_data_new_from_mem(&dataIn, inBuffer.data(), inBuffer.size(), 1); - checkErr(gpgmeError); - gpgmeError = gpgme_data_new(&dataOut); - checkErr(gpgmeError); - - /** - `GPGME_SIG_MODE_NORMAL' - A normal signature is made, the output includes the plaintext - and the signature. - - `GPGME_SIG_MODE_DETACH' - A detached signature is made. - - `GPGME_SIG_MODE_CLEAR' - A clear text signature is made. The ASCII armor and text - mode settings of the context are ignored. - */ - - gpgmeError = gpgme_op_sign(_ctx, dataIn, dataOut, mode); - checkErr(gpgmeError); - - if (gpgmeError == GPG_ERR_CANCELED) return false; - - if (gpgmeError != GPG_ERR_NO_ERROR) { - QMessageBox::critical(nullptr, tr("Error in signing:"), QString::fromUtf8(gpgme_strerror(gpgmeError))); - return false; - } - - if(default_ctx) - m_result = gpgme_op_sign_result(_ctx); - else m_result = nullptr; - - if (result != nullptr) *result = m_result; - - if(!default_ctx) gpgme_release(_ctx); - - gpgmeError = readToBuffer(dataOut, outBuffer); - checkErr(gpgmeError); - - gpgme_data_release(dataIn); - gpgme_data_release(dataOut); - - // Of no use yet - if (!settings.value("general/rememberPassword").toBool()) clearPasswordCache(); - - return gpgmeError; -} - -/** - * Encrypt and sign data - * @param keys keys used - * @param inBuffer input byte array - * @param outBuffer output byte array - * @param encr_result encrypt opera result - * @param sign_result sign opera result - * @return - */ -gpgme_error_t -GpgME::GpgContext::encryptSign(QVector<GpgKey> &keys, QVector<GpgKey> &signers, const QByteArray &inBuffer, - QByteArray *outBuffer, gpgme_encrypt_result_t *encr_result, - gpgme_sign_result_t *sign_result) { - gpgme_data_t data_in = nullptr, data_out = nullptr; - outBuffer->resize(0); - - setSigners(signers, mCtx); - - //gpgme_encrypt_result_t e_result; - gpgme_key_t recipients[keys.count() + 1]; - - // set key for user - int index = 0; - for (const auto &key : keys) recipients[index++] = key.key_refer; - - // Last entry dataIn array has to be nullptr - recipients[keys.count()] = nullptr; - - // If the last parameter isnt 0, a private copy of data is made - if (mCtx != nullptr) { - err = gpgme_data_new_from_mem(&data_in, inBuffer.data(), inBuffer.size(), 1); - if (gpg_err_code(err) == GPG_ERR_NO_ERROR) { - err = gpgme_data_new(&data_out); - if (gpg_err_code(err) == GPG_ERR_NO_ERROR) { - err = gpgme_op_encrypt_sign(mCtx, recipients, GPGME_ENCRYPT_ALWAYS_TRUST, data_in, data_out); - if (encr_result != nullptr) - *encr_result = gpgme_op_encrypt_result(mCtx); - if (sign_result != nullptr) - *sign_result = gpgme_op_sign_result(mCtx); - if (gpg_err_code(err) == GPG_ERR_NO_ERROR) { - err = readToBuffer(data_out, outBuffer); - } - } - } - } - - if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) checkErr(err); - - if (data_in) gpgme_data_release(data_in); - if (data_out) gpgme_data_release(data_out); - - return err; -} - -/** - * Decrypt and verify data - * @param inBuffer input byte array - * @param outBuffer output byte array - * @param decrypt_result decrypt opera result - * @param verify_result verify opera result - * @return error info - */ -gpgme_error_t GpgME::GpgContext::decryptVerify(const QByteArray &inBuffer, QByteArray *outBuffer, - gpgme_decrypt_result_t *decrypt_result, - gpgme_verify_result_t *verify_result) { - gpgme_data_t data_in = nullptr, data_out = nullptr; - - outBuffer->resize(0); - if (mCtx != nullptr) { - err = gpgme_data_new_from_mem(&data_in, inBuffer.data(), inBuffer.size(), 1); - if (gpgme_err_code(err) == GPG_ERR_NO_ERROR) { - err = gpgme_data_new(&data_out); - if (gpgme_err_code(err) == GPG_ERR_NO_ERROR) { - err = gpgme_op_decrypt_verify(mCtx, data_in, data_out); - if (decrypt_result != nullptr) - *decrypt_result = gpgme_op_decrypt_result(mCtx); - if (verify_result != nullptr) - *verify_result = gpgme_op_verify_result(mCtx); - if (gpgme_err_code(err) == GPG_ERR_NO_ERROR) { - err = readToBuffer(data_out, outBuffer); - } - } - } - } - - if (!settings.value("general/rememberPassword").toBool()) clearPasswordCache(); - - if (data_in) gpgme_data_release(data_in); - if (data_out) gpgme_data_release(data_out); - - return err; -} diff --git a/src/gpg/gpg_context/GpgContextKeyInfo.cpp b/src/gpg/gpg_context/GpgContextKeyInfo.cpp deleted file mode 100644 index f6942e4e..00000000 --- a/src/gpg/gpg_context/GpgContextKeyInfo.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/** - * This file is part of GPGFrontend. - * - * GPGFrontend is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Foobar is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see <https://www.gnu.org/licenses/>. - * - * The initial version of the source code is inherited from gpg4usb-team. - * Their source code version also complies with GNU General Public License. - * - * The source code version of this software was modified and released - * by Saturneric<[email protected]> starting on May 12, 2021. - * - */ - -#include "gpg/GpgContext.h" - -/** - * check if key can sign(actually) - * @param key target key - * @return if key sign - */ -bool GpgME::GpgContext::checkIfKeyCanSign(const GpgKey &key) { - if (std::any_of(key.subKeys.begin(), key.subKeys.end(), [](const GpgSubKey &subkey) -> bool { - return subkey.secret && subkey.can_sign && !subkey.disabled && !subkey.revoked && !subkey.expired; - })) - return true; - else return false; -} - -/** - * check if key can certify(actually) - * @param key target key - * @return if key certify - */ -bool GpgME::GpgContext::checkIfKeyCanCert(const GpgKey &key) { - return key.has_master_key && !key.expired && !key.revoked && !key.disabled; -} - -/** - * check if key can authenticate(actually) - * @param key target key - * @return if key authenticate - */ -bool GpgME::GpgContext::checkIfKeyCanAuth(const GpgKey &key) { - if (std::any_of(key.subKeys.begin(), key.subKeys.end(), [](const GpgSubKey &subkey) -> bool { - return subkey.secret && subkey.can_authenticate && !subkey.disabled && !subkey.revoked && !subkey.expired; - })) - return true; - else return false; -} - -/** - * check if key can encrypt(actually) - * @param key target key - * @return if key encrypt - */ -bool GpgME::GpgContext::checkIfKeyCanEncr(const GpgKey &key) { - if (std::any_of(key.subKeys.begin(), key.subKeys.end(), [](const GpgSubKey &subkey) -> bool { - return subkey.can_encrypt && !subkey.disabled && !subkey.revoked && !subkey.expired; - })) - return true; - else return false; -} - -/** - * Get target key - * @param fpr master key's fingerprint - * @return the key - */ -GpgKey GpgME::GpgContext::getKeyByFpr(const QString &fpr) { - for (const auto &key : mKeyList) { - if (key.fpr == fpr) return key; - else - for (auto &subkey : key.subKeys) { - if (subkey.fpr == fpr) return key; - } - } - return GpgKey(nullptr); -} - - -/** - * Get target key - * @param id master key's id - * @return the key - */ -GpgKey GpgME::GpgContext::getKeyById(const QString &id) { - - for (const auto &key : mKeyList) { - if (key.id == id) return key; - else { - auto sub_keys = key.subKeys; - for (const auto &subkey : sub_keys) { - if (subkey.id == id) return key; - } - } - } - - return GpgKey(nullptr); -} diff --git a/src/gpg/gpg_context/GpgContextKeyOpera.cpp b/src/gpg/gpg_context/GpgContextKeyOpera.cpp deleted file mode 100644 index a224231d..00000000 --- a/src/gpg/gpg_context/GpgContextKeyOpera.cpp +++ /dev/null @@ -1,410 +0,0 @@ -/** - * This file is part of GPGFrontend. - * - * GPGFrontend is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Foobar is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see <https://www.gnu.org/licenses/>. - * - * The initial version of the source code is inherited from gpg4usb-team. - * Their source code version also complies with GNU General Public License. - * - * The source code version of this software was modified and released - * by Saturneric<[email protected]> starting on May 12, 2021. - * - */ - -#include "gpg/GpgContext.h" - -/** - * Import key pair - * @param inBuffer input byte array - * @return Import information - */ -GpgImportInformation GpgME::GpgContext::importKey(QByteArray inBuffer) { - auto *importInformation = new GpgImportInformation(); - err = gpgme_data_new_from_mem(&in, inBuffer.data(), inBuffer.size(), 1); - checkErr(err); - err = gpgme_op_import(mCtx, in); - gpgme_import_result_t result; - - result = gpgme_op_import_result(mCtx); - - if (result->unchanged) importInformation->unchanged = result->unchanged; - if (result->considered) importInformation->considered = result->considered; - if (result->no_user_id) importInformation->no_user_id = result->no_user_id; - if (result->imported) importInformation->imported = result->imported; - if (result->imported_rsa) importInformation->imported_rsa = result->imported_rsa; - if (result->unchanged) importInformation->unchanged = result->unchanged; - if (result->new_user_ids) importInformation->new_user_ids = result->new_user_ids; - if (result->new_sub_keys) importInformation->new_sub_keys = result->new_sub_keys; - if (result->new_signatures) importInformation->new_signatures = result->new_signatures; - if (result->new_revocations) importInformation->new_revocations = result->new_revocations; - if (result->secret_read) importInformation->secret_read = result->secret_read; - if (result->secret_imported) importInformation->secret_imported = result->secret_imported; - if (result->secret_unchanged) importInformation->secret_unchanged = result->secret_unchanged; - if (result->not_imported) importInformation->not_imported = result->not_imported; - - gpgme_import_status_t status = result->imports; - while (status != nullptr) { - GpgImportedKey key; - key.importStatus = static_cast<int>(status->status); - key.fpr = status->fpr; - importInformation->importedKeys.emplace_back(key); - status = status->next; - } - checkErr(err); - emit signalKeyDBChanged(); - gpgme_data_release(in); - return *importInformation; -} - -/** - * Generate a new key pair - * @param params key generation args - * @return error information - */ -gpgme_error_t GpgME::GpgContext::generateKey(GenKeyInfo *params) { - - auto userid_utf8 = params->getUserid().toUtf8(); - const char *userid = userid_utf8.constData(); - auto algo_utf8 = (params->getAlgo() + params->getKeySizeStr()).toUtf8(); - const char *algo = algo_utf8.constData(); - unsigned long expires = QDateTime::currentDateTime().secsTo(params->getExpired()); - unsigned int flags = 0; - - if (!params->isSubKey()) flags |= GPGME_CREATE_CERT; - if (params->isAllowEncryption()) flags |= GPGME_CREATE_ENCR; - if (params->isAllowSigning()) flags |= GPGME_CREATE_SIGN; - if (params->isAllowAuthentication()) flags |= GPGME_CREATE_AUTH; - if (params->isNonExpired()) flags |= GPGME_CREATE_NOEXPIRE; - if (params->isNoPassPhrase()) flags |= GPGME_CREATE_NOPASSWD; - - err = gpgme_op_createkey(mCtx, userid, algo, 0, expires, nullptr, flags); - - if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) { - checkErr(err); - return err; - } else { - emit signalKeyDBChanged(); - return err; - } -} - -/** - * Export Key - * @param uidList key ids - * @param outBuffer output byte array - * @return if success - */ -bool GpgME::GpgContext::exportKeys(QStringList *uidList, QByteArray *outBuffer) { - gpgme_data_t dataOut = nullptr; - outBuffer->resize(0); - - if (uidList->count() == 0) { - QMessageBox::critical(nullptr, "Export Keys Error", "No Keys Selected"); - return false; - } - - // Alleviate another crash problem caused by an unknown array out-of-bounds access - gpgme_ctx_t ctx = create_ctx(); - - for (int i = 0; i < uidList->count(); i++) { - err = gpgme_data_new(&dataOut); - checkErr(err); - - err = gpgme_op_export(ctx, uidList->at(i).toUtf8().constData(), 0, dataOut); - checkErr(err); - - qDebug() << "exportKeys read_bytes" << gpgme_data_seek(dataOut, 0, SEEK_END); - - err = readToBuffer(dataOut, outBuffer); - checkErr(err); - gpgme_data_release(dataOut); - } - - gpgme_release(ctx); - - return true; -} - -/** - * Get and store all key pairs info - */ -void GpgME::GpgContext::fetch_keys() { - - gpgme_error_t gpgmeError; - - gpgme_key_t key; - - qDebug() << "Clear List and Map"; - - mKeyList.clear(); - mKeyMap.clear(); - - auto &keys = mKeyList; - auto &keys_map = mKeyMap; - - qDebug() << "Set Key Listing Mode"; - - gpgmeError = gpgme_set_keylist_mode(mCtx, - GPGME_KEYLIST_MODE_LOCAL - | GPGME_KEYLIST_MODE_WITH_SECRET - | GPGME_KEYLIST_MODE_SIGS - | GPGME_KEYLIST_MODE_SIG_NOTATIONS - | GPGME_KEYLIST_MODE_WITH_TOFU); - if (gpg_err_code(gpgmeError) != GPG_ERR_NO_ERROR) { - checkErr(gpgmeError); - return; - } - - qDebug() << "Operate KeyList Start"; - - gpgmeError = gpgme_op_keylist_start(mCtx, nullptr, 0); - if (gpg_err_code(gpgmeError) != GPG_ERR_NO_ERROR) { - checkErr(gpgmeError); - return; - } - - qDebug() << "Start Loop"; - - while ((gpgmeError = gpgme_op_keylist_next(mCtx, &key)) == GPG_ERR_NO_ERROR) { - if (!key->subkeys) - continue; - - qDebug() << "Append Key" << key->subkeys->keyid; - - keys.emplace_back(key); - keys_map.insert(keys.back().id, &keys.back()); - gpgme_key_unref(key); - } - - - if (gpg_err_code(gpgmeError) != GPG_ERR_EOF) { - checkErr(gpgmeError); - return; - } - - gpgmeError = gpgme_op_keylist_end(mCtx); - if (gpg_err_code(gpgmeError) != GPG_ERR_NO_ERROR) { - checkErr(gpgmeError); - return; - } - - qDebug() << "Operate KeyList End"; - - mKeyList = keys; -} - -/** - * Delete keys - * @param uidList key ids - */ -void GpgME::GpgContext::deleteKeys(QStringList *uidList) { - - gpgme_error_t error; - gpgme_key_t key; - - for (const auto &tmp : *uidList) { - - error = gpgme_op_keylist_start(mCtx, tmp.toUtf8().constData(), 0); - if (error != GPG_ERR_NO_ERROR) { - checkErr(error); - continue; - } - - error = gpgme_op_keylist_next(mCtx, &key); - if (error != GPG_ERR_NO_ERROR) { - checkErr(error); - continue; - } - - error = gpgme_op_keylist_end(mCtx); - if (error != GPG_ERR_NO_ERROR) { - checkErr(error); - continue; - } - - error = gpgme_op_delete(mCtx, key, 1); - if (error != GPG_ERR_NO_ERROR) { - checkErr(error); - continue; - } - - } - emit signalKeyDBChanged(); -} - -/** - * Export keys - * @param keys keys used - * @param outBuffer output byte array - * @return if success - */ -bool GpgME::GpgContext::exportKeys(const QVector<GpgKey> &keys, QByteArray &outBuffer) { - gpgme_data_t data_out = nullptr; - outBuffer.resize(0); - - if (keys.empty()) { - QMessageBox::critical(nullptr, "Export Keys Error", "No Keys Selected"); - return false; - } - - for (const auto &key : keys) { - err = gpgme_data_new(&data_out); - checkErr(err); - - err = gpgme_op_export(mCtx, key.id.toUtf8().constData(), 0, data_out); - checkErr(err); - - gpgme_data_seek(data_out, 0, SEEK_END); - - err = readToBuffer(data_out, &outBuffer); - checkErr(err); - gpgme_data_release(data_out); - } - - return true; -} - -/** - * Set the expire date and time of a key pair(actually the master key) or subkey - * @param key target key pair - * @param subkey null if master key - * @param expires date and time - * @return if successful - */ -bool GpgME::GpgContext::setExpire(const GpgKey &key, const GpgSubKey *subkey, QDateTime *expires) { - unsigned long expires_time = 0; - if (expires != nullptr) { - qDebug() << "Expire Datetime" << expires->toString(); - expires_time = QDateTime::currentDateTime().secsTo(*expires); - } - - const char *subfprs = nullptr; - - if (subkey != nullptr) subfprs = subkey->fpr.toUtf8().constData(); - - auto gpgmeError = gpgme_op_setexpire(mCtx, key.key_refer, - expires_time, subfprs, 0); - if (gpgmeError == GPG_ERR_NO_ERROR) { - emit signalKeyUpdated(key.id); - return true; - } else { - checkErr(gpgmeError); - return false; - } -} - -/** - * Export the secret key of a key pair(including subkeys) - * @param key target key pair - * @param outBuffer output byte array - * @return if successful - */ -bool GpgME::GpgContext::exportSecretKey(const GpgKey &key, QByteArray *outBuffer) { - qDebug() << "Export Secret Key" << key.id; - gpgme_key_t target_key[2] = { - key.key_refer, - nullptr - }; - - gpgme_data_t dataOut; - gpgme_data_new(&dataOut); - - // export private key to outBuffer - gpgme_error_t error = gpgme_op_export_keys(mCtx, target_key, GPGME_EXPORT_MODE_SECRET, dataOut); - - if (gpgme_err_code(error) != GPG_ERR_NO_ERROR) { - checkErr(error); - gpgme_data_release(dataOut); - return false; - } - - readToBuffer(dataOut, outBuffer); - gpgme_data_release(dataOut); - return true; -} - -/** - * Sign a key pair(actually a certain uid) - * @param target target key pair - * @param uid target - * @param expires expire date and time of the signature - * @return if successful - */ -bool GpgME::GpgContext::signKey(const GpgKey &target, const QVector<GpgKey> &keys, const QString &uid, - const QDateTime *expires) { - - setSigners(keys, mCtx); - - unsigned int flags = 0; - - unsigned int expires_time_t = 0; - if (expires == nullptr) flags |= GPGME_KEYSIGN_NOEXPIRE; - else expires_time_t = QDateTime::currentDateTime().secsTo(*expires); - - auto gpgmeError = - gpgme_op_keysign(mCtx, target.key_refer, uid.toUtf8().constData(), expires_time_t, flags); - - if (gpgmeError == GPG_ERR_NO_ERROR) { - emit signalKeyUpdated(target.id); - return true; - } else { - checkErr(gpgmeError); - return false; - } -} - -/** - * Generate revoke cert of a key pair - * @param key target key pair - * @param outputFileName out file name(path) - * @return the process doing this job - */ -void GpgME::GpgContext::generateRevokeCert(const GpgKey &key, const QString &outputFileName) { - executeGpgCommand({ - "--command-fd", - "0", - "--status-fd", - "1", - //"--no-tty", - "-o", - outputFileName, - "--gen-revoke", - key.fpr - }, - [](QProcess *proc) -> void { - qDebug() << "Function Called" << proc; - // Code From Gpg4Win - while (proc->canReadLine()) { - const QString line = QString::fromUtf8(proc->readLine()).trimmed(); - if (line == QLatin1String("[GNUPG:] GET_BOOL gen_revoke.okay")) { - proc->write("y\n"); - } else if (line == QLatin1String( - "[GNUPG:] GET_LINE ask_revocation_reason.code")) { - proc->write("0\n"); - } else if (line == QLatin1String( - "[GNUPG:] GET_LINE ask_revocation_reason.text")) { - proc->write("\n"); - } else if (line == QLatin1String( - "[GNUPG:] GET_BOOL openfile.overwrite.okay")) { - // We asked before - proc->write("y\n"); - } else if (line == QLatin1String( - "[GNUPG:] GET_BOOL ask_revocation_reason.okay")) { - proc->write("y\n"); - } - } - // Code From Gpg4Win - } - ); -} diff --git a/src/gpg/gpg_context/GpgContextSubkeyOpera.cpp b/src/gpg/gpg_context/GpgContextSubkeyOpera.cpp deleted file mode 100644 index 10243f5e..00000000 --- a/src/gpg/gpg_context/GpgContextSubkeyOpera.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/** - * This file is part of GPGFrontend. - * - * GPGFrontend is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Foobar is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see <https://www.gnu.org/licenses/>. - * - * The initial version of the source code is inherited from gpg4usb-team. - * Their source code version also complies with GNU General Public License. - * - * The source code version of this software was modified and released - * by Saturneric<[email protected]> starting on May 12, 2021. - * - */ - -#include "gpg/GpgContext.h" - -/** - * Generate a new subkey of a certain key pair - * @param key target key pair - * @param params opera args - * @return error info - */ -gpgme_error_t GpgME::GpgContext::generateSubkey(const GpgKey &key, GenKeyInfo *params) { - - if (!params->isSubKey()) return GPG_ERR_CANCELED; - - auto algo_utf8 = (params->getAlgo() + params->getKeySizeStr()).toUtf8(); - const char *algo = algo_utf8.constData(); - unsigned long expires = QDateTime::currentDateTime().secsTo(params->getExpired()); - unsigned int flags = 0; - - if (!params->isSubKey()) flags |= GPGME_CREATE_CERT; - if (params->isAllowEncryption()) flags |= GPGME_CREATE_ENCR; - if (params->isAllowSigning()) flags |= GPGME_CREATE_SIGN; - if (params->isAllowAuthentication()) flags |= GPGME_CREATE_AUTH; - if (params->isNonExpired()) flags |= GPGME_CREATE_NOEXPIRE; - - flags |= GPGME_CREATE_NOPASSWD; - - - auto gpgmeError = gpgme_op_createsubkey(mCtx, key.key_refer, - algo, 0, expires, flags); - if (gpgme_err_code(gpgmeError) == GPG_ERR_NO_ERROR) { - emit signalKeyUpdated(key.id); - return gpgmeError; - } else { - checkErr(gpgmeError); - return gpgmeError; - } -} - diff --git a/src/gpg/gpg_context/GpgContextUIDOpera.cpp b/src/gpg/gpg_context/GpgContextUIDOpera.cpp deleted file mode 100644 index b96f5f8f..00000000 --- a/src/gpg/gpg_context/GpgContextUIDOpera.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/** - * This file is part of GPGFrontend. - * - * GPGFrontend is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Foobar is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see <https://www.gnu.org/licenses/>. - * - * The initial version of the source code is inherited from gpg4usb-team. - * Their source code version also complies with GNU General Public License. - * - * The source code version of this software was modified and released - * by Saturneric<[email protected]> starting on May 12, 2021. - * - */ - -#include "gpg/GpgContext.h" - -/** - * create a new uid in certain key pair - * @param key target key pair - * @param uid uid args - * @return if successful - */ -bool GpgME::GpgContext::addUID(const GpgKey &key, const GpgUID &uid) { - QString userid = QString("%1 (%3) <%2>").arg(uid.name, uid.email, uid.comment); - auto gpgmeError = gpgme_op_adduid(mCtx, key.key_refer, userid.toUtf8().constData(), 0); - if (gpgmeError == GPG_ERR_NO_ERROR) { - emit signalKeyUpdated(key.id); - return true; - } else { - checkErr(gpgmeError); - return false; - } - -} - -/** - * Revoke(Delete) UID from certain key pair - * @param key target key pair - * @param uid target uid - * @return if successful - */ -bool GpgME::GpgContext::revUID(const GpgKey &key, const GpgUID &uid) { - auto gpgmeError = gpgme_op_revuid(mCtx, key.key_refer, uid.uid.toUtf8().constData(), 0); - if (gpgmeError == GPG_ERR_NO_ERROR) { - emit signalKeyUpdated(key.id); - return true; - } else { - checkErr(gpgmeError); - return false; - } -} - -/** - * Set one of a uid of a key pair as primary - * @param key target key pair - * @param uid target uid - * @return if successful - */ -bool GpgME::GpgContext::setPrimaryUID(const GpgKey &key, const GpgUID &uid) { - auto gpgmeError = gpgme_op_set_uid_flag(mCtx, key.key_refer, - uid.uid.toUtf8().constData(), "primary", nullptr); - if (gpgmeError == GPG_ERR_NO_ERROR) { - emit signalKeyUpdated(key.id); - return true; - } else { - checkErr(gpgmeError); - return false; - } -} - diff --git a/src/gpg/model/GpgData.cpp b/src/gpg/model/GpgData.cpp new file mode 100644 index 00000000..c6e9b2ce --- /dev/null +++ b/src/gpg/model/GpgData.cpp @@ -0,0 +1,74 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#include "gpg/model/GpgData.h" + +GpgFrontend::GpgData::GpgData() { + gpgme_data_t data; + + auto err = gpgme_data_new(&data); + assert(gpgme_err_code(err) == GPG_ERR_NO_ERROR); + + data_ = + std::unique_ptr<struct gpgme_data, __data_ref_deletor>(std::move(data)); +} + +GpgFrontend::GpgData::GpgData(void* buffer, size_t size, bool copy) { + gpgme_data_t data; + + auto err = gpgme_data_new_from_mem(&data, (const char*)buffer, size, copy); + assert(gpgme_err_code(err) == GPG_ERR_NO_ERROR); + + data_ = + std::unique_ptr<struct gpgme_data, __data_ref_deletor>(std::move(data)); +} + +/** + * Read gpgme-Data to QByteArray + * mainly from http://basket.kde.org/ (kgpgme.cpp) + */ +#define BUF_SIZE (32 * 1024) + +GpgFrontend::ByteArrayPtr GpgFrontend::GpgData::Read2Buffer() { + gpgme_off_t ret = gpgme_data_seek(*this, 0, SEEK_SET); + ByteArrayPtr out_buffer = std::make_unique<std::string>(); + + if (ret) { + gpgme_error_t err = gpgme_err_code_from_errno(errno); + assert(gpgme_err_code(err) == GPG_ERR_NO_ERROR); + } else { + char buf[BUF_SIZE + 2]; + + while ((ret = gpgme_data_read(*this, buf, BUF_SIZE)) > 0) { + const size_t size = out_buffer->size(); + out_buffer->resize(static_cast<int>(size + ret)); + memcpy(out_buffer->data() + size, buf, ret); + } + if (ret < 0) { + gpgme_error_t err = gpgme_err_code_from_errno(errno); + assert(gpgme_err_code(err) == GPG_ERR_NO_ERROR); + } + } + return out_buffer; +}
\ No newline at end of file diff --git a/src/gpg/model/GpgData.h b/src/gpg/model/GpgData.h new file mode 100644 index 00000000..e3202af6 --- /dev/null +++ b/src/gpg/model/GpgData.h @@ -0,0 +1,54 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef _GPGDATA_H +#define _GPGDATA_H + +#include "gpg/GpgConstants.h" + +namespace GpgFrontend { + +class GpgData { + public: + GpgData(); + + GpgData(void* buffer, size_t size, bool copy = true); + + operator gpgme_data_t() { return data_.get(); } + + ByteArrayPtr Read2Buffer(); + + private: + struct __data_ref_deletor { + void operator()(gpgme_data_t _data) { + if (_data != nullptr) gpgme_data_release(_data); + } + }; + + std::unique_ptr<struct gpgme_data, __data_ref_deletor> data_ = nullptr; +}; + +} // namespace GpgFrontend + +#endif // _GPGDATA_H
\ No newline at end of file diff --git a/src/gpg/model/GpgKey.cpp b/src/gpg/model/GpgKey.cpp new file mode 100644 index 00000000..c14edd2d --- /dev/null +++ b/src/gpg/model/GpgKey.cpp @@ -0,0 +1,108 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#include "gpg/model/GpgKey.h" + +GpgFrontend::GpgKey::GpgKey(gpgme_key_t &&key) : _key_ref(std::move(key)) {} + +GpgFrontend::GpgKey::GpgKey(GpgKey &&k) noexcept { swap(_key_ref, k._key_ref); } + +GpgFrontend::GpgKey &GpgFrontend::GpgKey::operator=(GpgKey &&k) noexcept { + swap(_key_ref, k._key_ref); + return *this; +} + +std::unique_ptr<std::vector<GpgFrontend::GpgSubKey>> +GpgFrontend::GpgKey::subKeys() const { + auto p_keys = std::make_unique<std::vector<GpgSubKey>>(); + auto next = _key_ref->subkeys; + while (next != nullptr) { + p_keys->push_back(GpgSubKey(next)); + next = next->next; + } + return p_keys; +} + +std::unique_ptr<std::vector<GpgFrontend::GpgUID>> GpgFrontend::GpgKey::uids() + const { + auto p_uids = std::make_unique<std::vector<GpgUID>>(); + auto uid_next = _key_ref->uids; + while (uid_next != nullptr) { + p_uids->push_back(GpgUID(uid_next)); + uid_next = uid_next->next; + } + return p_uids; +} + +bool GpgFrontend::GpgKey::CanSignActual() const { + auto subkeys = subKeys(); + if (std::any_of(subkeys->begin(), subkeys->end(), + [](const GpgSubKey &subkey) -> bool { + return subkey.secret() && subkey.can_sign() && + !subkey.disabled() && !subkey.revoked() && + !subkey.expired(); + })) + return true; + else + return false; +} + +bool GpgFrontend::GpgKey::CanAuthActual() const { + auto subkeys = subKeys(); + if (std::any_of(subkeys->begin(), subkeys->end(), + [](const GpgSubKey &subkey) -> bool { + return subkey.secret() && subkey.can_authenticate() && + !subkey.disabled() && !subkey.revoked() && + !subkey.expired(); + })) + return true; + else + return false; +} + +/** + * check if key can certify(actually) + * @param key target key + * @return if key certify + */ +bool GpgFrontend::GpgKey::CanCertActual() const { + return has_master_key() && !expired() && !revoked() && !disabled(); +} + +/** + * check if key can encrypt(actually) + * @param key target key + * @return if key encrypt + */ +bool GpgFrontend::GpgKey::CanEncrActual() const { + auto subkeys = subKeys(); + if (std::any_of(subkeys->begin(), subkeys->end(), + [](const GpgSubKey &subkey) -> bool { + return subkey.can_encrypt() && !subkey.disabled() && + !subkey.revoked() && !subkey.expired(); + })) + return true; + else + return false; +} diff --git a/src/gpg/model/GpgKey.h b/src/gpg/model/GpgKey.h new file mode 100644 index 00000000..53c074e8 --- /dev/null +++ b/src/gpg/model/GpgKey.h @@ -0,0 +1,162 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_GPGKEY_H +#define GPGFRONTEND_GPGKEY_H + +#include <boost/date_time.hpp> +#include <boost/date_time/posix_time/conversion.hpp> + +#include "GpgSubKey.h" +#include "GpgUID.h" + +namespace GpgFrontend { + +class GpgKey { + public: + [[nodiscard]] bool good() const { return _key_ref != nullptr; } + + [[nodiscard]] std::string id() const { return _key_ref->subkeys->keyid; } + + [[nodiscard]] std::string name() const { return _key_ref->uids->name; }; + + [[nodiscard]] std::string email() const { return _key_ref->uids->email; } + + [[nodiscard]] std::string comment() const { return _key_ref->uids->comment; } + + [[nodiscard]] std::string fpr() const { return _key_ref->fpr; } + + [[nodiscard]] std::string protocol() const { + return gpgme_get_protocol_name(_key_ref->protocol); + } + + [[nodiscard]] std::string owner_trust() const { + switch (_key_ref->owner_trust) { + case GPGME_VALIDITY_UNKNOWN: + return "Unknown"; + case GPGME_VALIDITY_UNDEFINED: + return "Undefined"; + case GPGME_VALIDITY_NEVER: + return "Never"; + case GPGME_VALIDITY_MARGINAL: + return "Marginal"; + case GPGME_VALIDITY_FULL: + return "FULL"; + case GPGME_VALIDITY_ULTIMATE: + return "Ultimate"; + } + return "Invalid"; + } + + [[nodiscard]] std::string pubkey_algo() const { + return gpgme_pubkey_algo_name(_key_ref->subkeys->pubkey_algo); + } + + [[nodiscard]] boost::gregorian::date last_update() const { + return boost::posix_time::from_time_t( + static_cast<time_t>(_key_ref->last_update)) + .date(); + } + + [[nodiscard]] boost::gregorian::date expires() const { + return boost::posix_time::from_time_t(_key_ref->subkeys->expires).date(); + }; + + [[nodiscard]] boost::gregorian::date create_time() const { + return boost::posix_time::from_time_t(_key_ref->subkeys->timestamp).date(); + }; + + [[nodiscard]] unsigned int length() const { + return _key_ref->subkeys->length; + } + + [[nodiscard]] bool can_encrypt() const { return _key_ref->can_encrypt; } + + [[nodiscard]] bool CanEncrActual() const; + + [[nodiscard]] bool can_sign() const { return _key_ref->can_sign; } + + [[nodiscard]] bool CanSignActual() const; + + [[nodiscard]] bool can_certify() const { return _key_ref->can_certify; } + + [[nodiscard]] bool CanCertActual() const; + + [[nodiscard]] bool can_authenticate() const { + return _key_ref->can_authenticate; + } + + [[nodiscard]] bool CanAuthActual() const; + + [[nodiscard]] bool is_private_key() const { return _key_ref->secret; } + + [[nodiscard]] bool expired() const { return _key_ref->expired; } + + [[nodiscard]] bool revoked() const { return _key_ref->revoked; } + + [[nodiscard]] bool disabled() const { return _key_ref->disabled; } + + [[nodiscard]] bool has_master_key() const { + return _key_ref->subkeys->secret; + } + + [[nodiscard]] std::unique_ptr<std::vector<GpgSubKey>> subKeys() const; + + [[nodiscard]] std::unique_ptr<std::vector<GpgUID>> uids() const; + + GpgKey() = default; + + explicit GpgKey(gpgme_key_t&& key); + + ~GpgKey() = default; + + GpgKey(const gpgme_key_t& key) = delete; + + GpgKey(GpgKey&& k) noexcept; + + GpgKey& operator=(GpgKey&& k) noexcept; + + GpgKey& operator=(const gpgme_key_t& key) = delete; + + bool operator==(const GpgKey& o) const { return o.id() == this->id(); } + + bool operator<=(const GpgKey& o) const { return this->id() < o.id(); } + + explicit operator gpgme_key_t() const { return _key_ref.get(); } + + private: + struct _key_ref_deletor { + void operator()(gpgme_key_t _key) { + if (_key != nullptr) gpgme_key_unref(_key); + } + }; + + using KeyRefHandler = std::unique_ptr<struct _gpgme_key, _key_ref_deletor>; + + KeyRefHandler _key_ref = nullptr; +}; + +} // namespace GpgFrontend + +#endif // GPGFRONTEND_GPGKEY_H diff --git a/src/gpg/model/GpgKeySignature.cpp b/src/gpg/model/GpgKeySignature.cpp new file mode 100644 index 00000000..8f937198 --- /dev/null +++ b/src/gpg/model/GpgKeySignature.cpp @@ -0,0 +1,28 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#include "gpg/model/GpgKeySignature.h" + +GpgFrontend::GpgKeySignature::GpgKeySignature(gpgme_key_sig_t sig) + : _signature_ref(sig, [&](gpgme_key_sig_t signature) {}) {} diff --git a/src/gpg/model/GpgKeySignature.h b/src/gpg/model/GpgKeySignature.h new file mode 100644 index 00000000..70eaeb1c --- /dev/null +++ b/src/gpg/model/GpgKeySignature.h @@ -0,0 +1,85 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_GPGKEYSIGNATURE_H +#define GPGFRONTEND_GPGKEYSIGNATURE_H + +#include <boost/date_time.hpp> +#include <string> + +#include "gpg/GpgConstants.h" + +namespace GpgFrontend { + +class GpgKeySignature { + public: + [[nodiscard]] bool revoked() const { return _signature_ref->revoked; } + [[nodiscard]] bool expired() const { return _signature_ref->expired; } + [[nodiscard]] bool invalid() const { return _signature_ref->invalid; } + [[nodiscard]] bool exportable() const { return _signature_ref->exportable; } + + [[nodiscard]] gpgme_error_t status() const { return _signature_ref->status; } + + [[nodiscard]] std::string keyid() const { return _signature_ref->keyid; } + [[nodiscard]] std::string pubkey_algo() const { + return gpgme_pubkey_algo_name(_signature_ref->pubkey_algo); + } + + [[nodiscard]] boost::gregorian::date create_time() const { + return boost::posix_time::from_time_t(_signature_ref->timestamp).date(); + } + [[nodiscard]] boost::gregorian::date expire_time() const { + return boost::posix_time::from_time_t(_signature_ref->expires).date(); + } + + [[nodiscard]] std::string uid() const { return _signature_ref->uid; } + [[nodiscard]] std::string name() const { return _signature_ref->name; } + [[nodiscard]] std::string email() const { return _signature_ref->email; } + [[nodiscard]] std::string comment() const { return _signature_ref->comment; } + + GpgKeySignature() = default; + + ~GpgKeySignature() = default; + + explicit GpgKeySignature(gpgme_key_sig_t sig); + + GpgKeySignature(GpgKeySignature &&) noexcept = default; + + GpgKeySignature(const GpgKeySignature &) = delete; + + GpgKeySignature &operator=(GpgKeySignature &&) noexcept = default; + + GpgKeySignature &operator=(const GpgKeySignature &) = delete; + + private: + using KeySignatrueRefHandler = + std::unique_ptr<struct _gpgme_key_sig, + std::function<void(gpgme_key_sig_t)>>; + + KeySignatrueRefHandler _signature_ref = nullptr; +}; + +} // namespace GpgFrontend + +#endif // GPGFRONTEND_GPGKEYSIGNATURE_H diff --git a/src/gpg/model/GpgSubKey.cpp b/src/gpg/model/GpgSubKey.cpp new file mode 100644 index 00000000..83fbcaa2 --- /dev/null +++ b/src/gpg/model/GpgSubKey.cpp @@ -0,0 +1,27 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ +#include "gpg/model/GpgSubKey.h" + +GpgFrontend::GpgSubKey::GpgSubKey(gpgme_subkey_t subkey) + : _subkey_ref(subkey, [&](gpgme_subkey_t subkey) {}) {} diff --git a/src/gpg/model/GpgSubKey.h b/src/gpg/model/GpgSubKey.h new file mode 100644 index 00000000..5f65c507 --- /dev/null +++ b/src/gpg/model/GpgSubKey.h @@ -0,0 +1,102 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ +#ifndef GPGFRONTEND_GPGSUBKEY_H +#define GPGFRONTEND_GPGSUBKEY_H + +#include <boost/date_time.hpp> +#include <string> + +#include "gpg/GpgConstants.h" + +namespace GpgFrontend { + +class GpgSubKey { + public: + [[nodiscard]] std::string id() const { return _subkey_ref->keyid; } + + [[nodiscard]] std::string fpr() const { return _subkey_ref->fpr; } + + [[nodiscard]] std::string pubkey_algo() const { + return gpgme_pubkey_algo_name(_subkey_ref->pubkey_algo); + } + + [[nodiscard]] unsigned int length() const { return _subkey_ref->length; } + + [[nodiscard]] bool can_encrypt() const { return _subkey_ref->can_encrypt; } + + [[nodiscard]] bool can_sign() const { return _subkey_ref->can_sign; } + + [[nodiscard]] bool can_certify() const { return _subkey_ref->can_certify; } + + [[nodiscard]] bool can_authenticate() const { + return _subkey_ref->can_authenticate; + } + + [[nodiscard]] bool is_private_key() const { return _subkey_ref->secret; } + + [[nodiscard]] bool expired() const { return _subkey_ref->expired; } + + [[nodiscard]] bool revoked() const { return _subkey_ref->revoked; } + + [[nodiscard]] bool disabled() const { return _subkey_ref->disabled; } + + [[nodiscard]] bool secret() const { return _subkey_ref->secret; } + + [[nodiscard]] bool is_cardkey() const { return _subkey_ref->is_cardkey; } + + [[nodiscard]] boost::gregorian::date timestamp() const { + return boost::posix_time::from_time_t(_subkey_ref->timestamp).date(); + } + + [[nodiscard]] boost::gregorian::date expires() const { + return boost::posix_time::from_time_t(_subkey_ref->expires).date(); + } + + GpgSubKey() = default; + + explicit GpgSubKey(gpgme_subkey_t subkey); + + GpgSubKey(GpgSubKey&& o) noexcept { swap(_subkey_ref, o._subkey_ref); } + + GpgSubKey(const GpgSubKey&) = delete; + + GpgSubKey& operator=(GpgSubKey&& o) noexcept { + swap(_subkey_ref, o._subkey_ref); + return *this; + }; + + GpgSubKey& operator=(const GpgSubKey&) = delete; + + bool operator==(const GpgSubKey& o) const { return fpr() == o.fpr(); } + + private: + using SubkeyRefHandler = std::unique_ptr<struct _gpgme_subkey, + std::function<void(gpgme_subkey_t)>>; + + SubkeyRefHandler _subkey_ref = nullptr; +}; + +} // namespace GpgFrontend + +#endif // GPGFRONTEND_GPGSUBKEY_H diff --git a/src/gpg/model/GpgUID.cpp b/src/gpg/model/GpgUID.cpp new file mode 100644 index 00000000..c0a63bab --- /dev/null +++ b/src/gpg/model/GpgUID.cpp @@ -0,0 +1,28 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#include "gpg/model/GpgUID.h" + +GpgFrontend::GpgUID::GpgUID(gpgme_user_id_t uid) + : _uid_ref(uid, [&](gpgme_user_id_t uid) {}) {}
\ No newline at end of file diff --git a/src/gpg/model/GpgUID.h b/src/gpg/model/GpgUID.h new file mode 100644 index 00000000..66dba321 --- /dev/null +++ b/src/gpg/model/GpgUID.h @@ -0,0 +1,81 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_GPGUID_H +#define GPGFRONTEND_GPGUID_H + +#include "GpgKeySignature.h" + +namespace GpgFrontend { + +class GpgUID { + public: + [[nodiscard]] std::string name() const { return _uid_ref->name; } + + [[nodiscard]] std::string email() const { return _uid_ref->email; } + + [[nodiscard]] std::string comment() const { return _uid_ref->comment; } + + [[nodiscard]] std::string uid() const { return _uid_ref->uid; } + + [[nodiscard]] bool revoked() const { return _uid_ref->revoked; } + + [[nodiscard]] bool invalid() const { return _uid_ref->invalid; } + + [[nodiscard]] std::unique_ptr<std::vector<GpgKeySignature>> signatures() + const { + auto sigs = std::make_unique<std::vector<GpgKeySignature>>(); + auto sig_next = _uid_ref->signatures; + while (sig_next != nullptr) { + sigs->push_back(GpgKeySignature(sig_next)); + sig_next = sig_next->next; + } + return sigs; + } + + GpgUID() = default; + + explicit GpgUID(gpgme_user_id_t uid); + + GpgUID(GpgUID &&o) noexcept { swap(_uid_ref, o._uid_ref); } + + GpgUID(const GpgUID &) = delete; + + GpgUID &operator=(GpgUID &&o) noexcept { + swap(_uid_ref, o._uid_ref); + return *this; + } + + GpgUID &operator=(const GpgUID &) = delete; + + private: + using UidRefHandler = std::unique_ptr<struct _gpgme_user_id, + std::function<void(gpgme_user_id_t)>>; + + UidRefHandler _uid_ref = nullptr; +}; + +} // namespace GpgFrontend + +#endif // GPGFRONTEND_GPGUID_H
\ No newline at end of file diff --git a/src/gpg/result_analyse/DecryptResultAnalyse.cpp b/src/gpg/result_analyse/DecryptResultAnalyse.cpp index b4d0b14f..4ff32c59 100644 --- a/src/gpg/result_analyse/DecryptResultAnalyse.cpp +++ b/src/gpg/result_analyse/DecryptResultAnalyse.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -24,63 +24,68 @@ #include "gpg/result_analyse/DecryptResultAnalyse.h" -DecryptResultAnalyse::DecryptResultAnalyse(GpgME::GpgContext *ctx, gpgme_error_t error, gpgme_decrypt_result_t result) - : mCtx(ctx) { +#include "gpg/function/GpgKeyGetter.h" - stream << tr("[#] Decrypt Operation "); +GpgFrontend::DecryptResultAnalyse::DecryptResultAnalyse(GpgError error, + GpgDecrResult result) + : error(error), result(std::move(result)) {} - if (gpgme_err_code(error) == GPG_ERR_NO_ERROR) { - stream << tr("[Success]") << Qt::endl; - } else { - stream << tr("[Failed] ") << gpgme_strerror(error) << Qt::endl; - setStatus(-1); - if (result != nullptr && result->unsupported_algorithm != nullptr) { - stream << "------------>" << Qt::endl; - stream << tr("Unsupported Algo: ") << result->unsupported_algorithm << Qt::endl; - } - } +void GpgFrontend::DecryptResultAnalyse::do_analyse() { + stream << "[#]" << _("Decrypt Operation"); - if (result != nullptr && result->recipients != nullptr) { - stream << "------------>" << Qt::endl; - if (result->file_name != nullptr) { - stream << tr("File Name: ") << result->file_name << Qt::endl; - stream << Qt::endl; - } + if (gpgme_err_code(error) == GPG_ERR_NO_ERROR) { + stream << "[" << _("Success") << "]" << std::endl; + } else { + stream << "[" << _("Failed") << "] " << gpgme_strerror(error) << std::endl; + setStatus(-1); + if (result != nullptr && result->unsupported_algorithm != nullptr) { + stream << "------------>" << std::endl; + stream << _("Unsupported Algo") << ": " << result->unsupported_algorithm + << std::endl; + } + } - auto reci = result->recipients; - if (reci != nullptr) - stream << tr("Recipient(s): ") << Qt::endl; - while (reci != nullptr) { - printReci(stream, reci); - reci = reci->next; - } - stream << "<------------" << Qt::endl; + if (result != nullptr && result->recipients != nullptr) { + stream << "------------>" << std::endl; + if (result->file_name != nullptr) { + stream << _("File Name") << ": " << result->file_name << std::endl; + stream << std::endl; } - stream << Qt::endl; + auto reci = result->recipients; + if (reci != nullptr) stream << _("Recipient(s)") << ": " << std::endl; + while (reci != nullptr) { + print_reci(stream, reci); + reci = reci->next; + } + stream << "<------------" << std::endl; + } + stream << std::endl; } -bool DecryptResultAnalyse::printReci(QTextStream &stream, gpgme_recipient_t reci) { - bool keyFound = true; - stream << QApplication::tr(" {>} Recipient: "); +bool GpgFrontend::DecryptResultAnalyse::print_reci(std::stringstream &stream, + gpgme_recipient_t reci) { + bool keyFound = true; + stream << " {>} " << _("Recipient") << ": "; - auto key = mCtx->getKeyById(reci->keyid); - if(key.good) { - stream << key.name; - if (!key.email.isEmpty()) { - stream << "<" << key.email << ">"; - } - } else { - stream << "<Unknown>"; - setStatus(0); - keyFound = false; + auto key = GpgFrontend::GpgKeyGetter::GetInstance().GetKey(reci->keyid); + if (key.good()) { + stream << key.name().c_str(); + if (!key.email().empty()) { + stream << "<" << key.email().c_str() << ">"; } + } else { + stream << "<" << _("Unknown") << ">"; + setStatus(0); + keyFound = false; + } - stream << Qt::endl; + stream << std::endl; - stream << tr(" Keu ID: ") << reci->keyid << Qt::endl; - stream << tr(" Public Algo: ") << gpgme_pubkey_algo_name(reci->pubkey_algo) << Qt::endl; + stream << " " << _("Keu ID") << ": " << key.id().c_str() << std::endl; + stream << " " << _("Public Algo") << ": " + << gpgme_pubkey_algo_name(reci->pubkey_algo) << std::endl; - return keyFound; + return keyFound; } diff --git a/src/gpg/result_analyse/DecryptResultAnalyse.h b/src/gpg/result_analyse/DecryptResultAnalyse.h new file mode 100644 index 00000000..0864c23b --- /dev/null +++ b/src/gpg/result_analyse/DecryptResultAnalyse.h @@ -0,0 +1,49 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_DECRYPTRESULTANALYSE_H +#define GPGFRONTEND_DECRYPTRESULTANALYSE_H + +#include "ResultAnalyse.h" +#include "gpg/GpgConstants.h" + +namespace GpgFrontend { + +class DecryptResultAnalyse : public ResultAnalyse { + public: + explicit DecryptResultAnalyse(GpgError error, GpgDecrResult result); + + protected: + void do_analyse() final; + + private: + bool print_reci(std::stringstream &stream, gpgme_recipient_t reci); + + GpgError error; + GpgDecrResult result; +}; + +} // namespace GpgFrontend + +#endif // GPGFRONTEND_DECRYPTRESULTANALYSE_H diff --git a/src/gpg/result_analyse/EncryptResultAnalyse.cpp b/src/gpg/result_analyse/EncryptResultAnalyse.cpp index 1ba685c9..df240a1d 100644 --- a/src/gpg/result_analyse/EncryptResultAnalyse.cpp +++ b/src/gpg/result_analyse/EncryptResultAnalyse.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -24,35 +24,38 @@ #include "gpg/result_analyse/EncryptResultAnalyse.h" -EncryptResultAnalyse::EncryptResultAnalyse(gpgme_error_t error, gpgme_encrypt_result_t result) { - - qDebug() << "Start Encrypt Result Analyse"; - - stream << "[#] Encrypt Operation "; - - if(gpgme_err_code(error) == GPG_ERR_NO_ERROR) - stream << "[Success]" << Qt::endl; - else { - stream << "[Failed] " << gpgme_strerror(error) << Qt::endl; - setStatus(-1); +GpgFrontend::EncryptResultAnalyse::EncryptResultAnalyse(GpgError error, + GpgEncrResult result) + : error(error), result(std::move(result)) {} + +void GpgFrontend::EncryptResultAnalyse::do_analyse() { + LOG(INFO) << _("Start Encrypt Result Analyse"); + + stream << "[#] " << _("Encrypt Operation") << " "; + + if (gpgme_err_code(error) == GPG_ERR_NO_ERROR) + stream << "[" << _("Success") << "]" << std::endl; + else { + stream << "[" << _("Failed") << "] " << gpgme_strerror(error) << std::endl; + setStatus(-1); + } + + if (!~status) { + stream << "------------>" << std::endl; + if (result != nullptr) { + stream << _("Invalid Recipients") << ": " << std::endl; + auto inv_reci = result->invalid_recipients; + while (inv_reci != nullptr) { + stream << _("Fingerprint") << ": " << inv_reci->fpr << std::endl; + stream << _("Reason") << ": " << gpgme_strerror(inv_reci->reason) + << std::endl; + stream << std::endl; + + inv_reci = inv_reci->next; + } } + stream << "<------------" << std::endl; + } - if(!~status) { - stream << "------------>" << Qt::endl; - if (result != nullptr) { - stream << tr("Invalid Recipients: ") << Qt::endl; - auto inv_reci = result->invalid_recipients; - while (inv_reci != nullptr) { - stream << tr("Fingerprint: ") << inv_reci->fpr << Qt::endl; - stream << tr("Reason: ") << gpgme_strerror(inv_reci->reason) << Qt::endl; - stream << Qt::endl; - - inv_reci = inv_reci->next; - } - } - stream << "<------------" << Qt::endl; - } - - stream << Qt::endl; - + stream << std::endl; } diff --git a/src/gpg/result_analyse/EncryptResultAnalyse.h b/src/gpg/result_analyse/EncryptResultAnalyse.h new file mode 100644 index 00000000..e0a411d1 --- /dev/null +++ b/src/gpg/result_analyse/EncryptResultAnalyse.h @@ -0,0 +1,45 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_ENCRYPTRESULTANALYSE_H +#define GPGFRONTEND_ENCRYPTRESULTANALYSE_H + +#include "ResultAnalyse.h" +#include "gpg/GpgConstants.h" + +namespace GpgFrontend { +class EncryptResultAnalyse : public ResultAnalyse { + public: + explicit EncryptResultAnalyse(GpgError error, GpgEncrResult result); + + protected: + void do_analyse() final; + + private: + GpgError error; + GpgEncrResult result; +}; +} // namespace GpgFrontend + +#endif // GPGFRONTEND_ENCRYPTRESULTANALYSE_H diff --git a/src/gpg/result_analyse/ResultAnalyse.cpp b/src/gpg/result_analyse/ResultAnalyse.cpp index 7186d21a..821da2ee 100644 --- a/src/gpg/result_analyse/ResultAnalyse.cpp +++ b/src/gpg/result_analyse/ResultAnalyse.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -24,15 +24,19 @@ #include "gpg/result_analyse/ResultAnalyse.h" -const QString &ResultAnalyse::getResultReport() const{ - return resultText; +const std::string GpgFrontend::ResultAnalyse::getResultReport() const { + return stream.str(); } -int ResultAnalyse::getStatus() const { - return status; +int GpgFrontend::ResultAnalyse::getStatus() const { return status; } + +void GpgFrontend::ResultAnalyse::setStatus(int mStatus) { + if (mStatus < status) status = mStatus; } -void ResultAnalyse::setStatus(int mStatus) { - if(mStatus < status) - status = mStatus; +void GpgFrontend::ResultAnalyse::analyse() { + if (!analysed_) { + do_analyse(); + analysed_ = true; + } } diff --git a/src/gpg/result_analyse/ResultAnalyse.h b/src/gpg/result_analyse/ResultAnalyse.h new file mode 100644 index 00000000..33341b44 --- /dev/null +++ b/src/gpg/result_analyse/ResultAnalyse.h @@ -0,0 +1,57 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ +#ifndef GPGFRONTEND_RESULTANALYSE_H +#define GPGFRONTEND_RESULTANALYSE_H + +#include <sstream> +#include <string> + +#include "gpg/GpgConstants.h" +namespace GpgFrontend { + +class ResultAnalyse { + public: + ResultAnalyse() = default; + + [[nodiscard]] const std::string getResultReport() const; + + [[nodiscard]] int getStatus() const; + + void analyse(); + + protected: + virtual void do_analyse() = 0; + + std::stringstream stream; + + int status = 1; + + bool analysed_ = false; + + void setStatus(int mStatus); +}; + +} // namespace GpgFrontend + +#endif // GPGFRONTEND_RESULTANALYSE_H diff --git a/src/gpg/result_analyse/SignResultAnalyse.cpp b/src/gpg/result_analyse/SignResultAnalyse.cpp index 10d76678..770594ca 100644 --- a/src/gpg/result_analyse/SignResultAnalyse.cpp +++ b/src/gpg/result_analyse/SignResultAnalyse.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -24,73 +24,86 @@ #include "gpg/result_analyse/SignResultAnalyse.h" -SignResultAnalyse::SignResultAnalyse(GpgME::GpgContext *ctx, gpgme_error_t error, gpgme_sign_result_t result) { - - qDebug() << "Start Sign Result Analyse"; - - stream << tr("[#] Sign Operation "); - - if (gpgme_err_code(error) == GPG_ERR_NO_ERROR) - stream << tr("[Success]") << Qt::endl; - else { - stream << tr("[Failed] ") << gpgme_strerror(error) << Qt::endl; - setStatus(-1); +#include "gpg/function/GpgKeyGetter.h" + +GpgFrontend::SignResultAnalyse::SignResultAnalyse(GpgError error, + GpgSignResult result) + : error(error), result(std::move(result)) {} + +void GpgFrontend::SignResultAnalyse::do_analyse() { + LOG(INFO) << _("Start Sign Result Analyse"); + + stream << "[#] " << _("Sign Operation") << " "; + + if (gpgme_err_code(error) == GPG_ERR_NO_ERROR) + stream << "[" << _("Success") << "]" << std::endl; + else { + stream << "[" << _("Failed") << "] " << gpgme_strerror(error) << std::endl; + setStatus(-1); + } + + if (result != nullptr && + (result->signatures != nullptr || result->invalid_signers != nullptr)) { + LOG(INFO) << _("Sign Result Analyse Getting Result"); + stream << "------------>" << std::endl; + auto new_sign = result->signatures; + + while (new_sign != nullptr) { + stream << "[>]" << _("New Signature") << ": " << std::endl; + + LOG(INFO) << _("Signers Fingerprint") << ": " << new_sign->fpr; + + stream << " " << _("Sign Mode") << ": "; + if (new_sign->type == GPGME_SIG_MODE_NORMAL) + stream << _("Normal"); + else if (new_sign->type == GPGME_SIG_MODE_CLEAR) + stream << _("Clear"); + else if (new_sign->type == GPGME_SIG_MODE_DETACH) + stream << _("Detach"); + + stream << std::endl; + + auto singerKey = + GpgFrontend::GpgKeyGetter::GetInstance().GetKey(new_sign->fpr); + if (singerKey.good()) { + stream << " " << _("Signer") << ": " + << singerKey.uids()->front().uid() << std::endl; + } else { + stream << " " << _("Signer") << ": " + << "<unknown>" << std::endl; + } + stream << " " << _("Public Key Algo") << ": " + << gpgme_pubkey_algo_name(new_sign->pubkey_algo) << std::endl; + stream << " " << _("Hash Algo") << ": " + << gpgme_hash_algo_name(new_sign->hash_algo) << std::endl; + stream << " " << _("Date & Time") << ": " + << boost::posix_time::to_iso_string( + boost::posix_time::from_time_t(new_sign->timestamp)) + << std::endl; + + stream << std::endl; + + new_sign = new_sign->next; } - if (result != nullptr && (result->signatures != nullptr || result->invalid_signers != nullptr)) { - - qDebug() << "Sign Result Analyse Getting Result"; - stream << "------------>" << Qt::endl; - auto new_sign = result->signatures; - - while (new_sign != nullptr) { - stream << tr("[>] New Signature: ") << Qt::endl; - - qDebug() << "Signers Fingerprint: " << new_sign->fpr; - - stream << tr(" Sign Mode: "); - if (new_sign->type == GPGME_SIG_MODE_NORMAL) - stream << tr("Normal"); - else if (new_sign->type == GPGME_SIG_MODE_CLEAR) - stream << tr("Clear"); - else if (new_sign->type == GPGME_SIG_MODE_DETACH) - stream << tr("Detach"); + LOG(INFO) << _("Sign Result Analyse Getting Invalid Signer"); - stream << Qt::endl; + auto invalid_signer = result->invalid_signers; - GpgKey singerKey = ctx->getKeyByFpr(new_sign->fpr); - if(singerKey.good) { - stream << tr(" Signer: ") << singerKey.uids.first().uid << Qt::endl; - } else { - stream << tr(" Signer: ") << tr("<unknown>") << Qt::endl; - } - stream << tr(" Public Key Algo: ") << gpgme_pubkey_algo_name(new_sign->pubkey_algo) << Qt::endl; - stream << tr(" Hash Algo: ") << gpgme_hash_algo_name(new_sign->hash_algo) << Qt::endl; - stream << tr(" Date & Time: ") << QDateTime::fromTime_t(new_sign->timestamp).toString() << Qt::endl; + if (invalid_signer != nullptr) + stream << _("Invalid Signers") << ": " << std::endl; - stream << Qt::endl; - - new_sign = new_sign->next; - } - - qDebug() << "Sign Result Analyse Getting Invalid Signer"; - - auto invalid_signer = result->invalid_signers; - - if (invalid_signer != nullptr) - stream << tr("Invalid Signers: ") << Qt::endl; - - while (invalid_signer != nullptr) { - setStatus(0); - stream << tr("[>] Signer: ") << Qt::endl; - stream << tr(" Fingerprint: ") << invalid_signer->fpr << Qt::endl; - stream << tr(" Reason: ") << gpgme_strerror(invalid_signer->reason) << Qt::endl; - stream << Qt::endl; - - invalid_signer = invalid_signer->next; - } - stream << "<------------" << Qt::endl; + while (invalid_signer != nullptr) { + setStatus(0); + stream << "[>] " << _("Signer") << ": " << std::endl; + stream << " " << _("Fingerprint") << ": " << invalid_signer->fpr + << std::endl; + stream << " " << _("Reason") << ": " + << gpgme_strerror(invalid_signer->reason) << std::endl; + stream << std::endl; + invalid_signer = invalid_signer->next; } - -} + stream << "<------------" << std::endl; + } +}
\ No newline at end of file diff --git a/src/gpg/result_analyse/SignResultAnalyse.h b/src/gpg/result_analyse/SignResultAnalyse.h new file mode 100644 index 00000000..988ddf99 --- /dev/null +++ b/src/gpg/result_analyse/SignResultAnalyse.h @@ -0,0 +1,47 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_SIGNRESULTANALYSE_H +#define GPGFRONTEND_SIGNRESULTANALYSE_H + +#include "ResultAnalyse.h" + +namespace GpgFrontend { + +class SignResultAnalyse : public ResultAnalyse { + public: + explicit SignResultAnalyse(GpgError error, GpgSignResult result); + + protected: + void do_analyse(); + + private: + GpgError error; + + GpgSignResult result; +}; + +} // namespace GpgFrontend + +#endif // GPGFRONTEND_SIGNRESULTANALYSE_H diff --git a/src/gpg/result_analyse/VerifyResultAnalyse.cpp b/src/gpg/result_analyse/VerifyResultAnalyse.cpp index 75e07d33..55e50f38 100644 --- a/src/gpg/result_analyse/VerifyResultAnalyse.cpp +++ b/src/gpg/result_analyse/VerifyResultAnalyse.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -22,147 +22,172 @@ * */ -#include "GpgFrontend.h" #include "gpg/result_analyse/VerifyResultAnalyse.h" -VerifyResultAnalyse::VerifyResultAnalyse(GpgME::GpgContext *ctx, gpgme_error_t error, gpgme_verify_result_t result) - : mCtx(ctx) { +#include "GpgFrontend.h" +#include "gpg/GpgConstants.h" +#include "gpg/function/GpgKeyGetter.h" - qDebug() << "Verify Result Analyse Started"; +GpgFrontend::VerifyResultAnalyse::VerifyResultAnalyse(GpgError error, + GpgVerifyResult result) + : error(error), result(std::move(result)) {} - stream << tr("[#] Verify Operation "); +void GpgFrontend::VerifyResultAnalyse::do_analyse() { + LOG(INFO) << _("Verify Result Analyse Started"); - if (gpgme_err_code(error) == GPG_ERR_NO_ERROR) - stream << tr("[Success]") << Qt::endl; - else { - stream << tr("[Failed] ") << gpgme_strerror(error) << Qt::endl; - setStatus(-1); - } + stream << "[#] " << _("Verify Operation") << " "; + if (gpgme_err_code(error) == GPG_ERR_NO_ERROR) + stream << "[" << _("Success") << "]" << std::endl; + else { + stream << "[" << _("Failed") << "] " << gpgme_strerror(error) << std::endl; + setStatus(-1); + } - if (result != nullptr && result->signatures) { - stream << "------------>" << Qt::endl; - auto sign = result->signatures; + if (result != nullptr && result->signatures) { + stream << "------------>" << std::endl; + auto sign = result->signatures; - if (sign == nullptr) { - stream << "[>] Not Signature Found" << Qt::endl; + if (sign == nullptr) { + stream << "[>] " << _("Not Signature Found") << std::endl; + setStatus(0); + return; + } + + stream << "[>] " << _("Signed On") << " " + << boost::posix_time::to_iso_string( + boost::posix_time::from_time_t(sign->timestamp)) + << std::endl; + + stream << std::endl << "[>] " << _("Signatures") << ":" << std::endl; + + bool canContinue = true; + + while (sign && canContinue) { + switch (gpg_err_code(sign->status)) { + case GPG_ERR_BAD_SIGNATURE: + stream << _("One or More Bad Signatures.") << std::endl; + canContinue = false; + setStatus(-1); + break; + case GPG_ERR_NO_ERROR: + stream << _("A") << " "; + if (sign->summary & GPGME_SIGSUM_GREEN) { + stream << _("Good") << " "; + } + if (sign->summary & GPGME_SIGSUM_RED) { + stream << _("Bad") << " "; + } + if (sign->summary & GPGME_SIGSUM_SIG_EXPIRED) { + stream << _("Expired") << " "; + } + if (sign->summary & GPGME_SIGSUM_KEY_MISSING) { + stream << _("Missing Key's") << " "; + } + if (sign->summary & GPGME_SIGSUM_KEY_REVOKED) { + stream << _("Revoked Key's") << " "; + } + if (sign->summary & GPGME_SIGSUM_KEY_EXPIRED) { + stream << _("Expired Key's") << " "; + } + if (sign->summary & GPGME_SIGSUM_CRL_MISSING) { + stream << _("Missing CRL's") << " "; + } + + if (sign->summary & GPGME_SIGSUM_VALID) { + stream << _("Signature Fully Valid.") << std::endl; + } else { + stream << _("Signature Not Fully Valid.") << std::endl; + } + + if (!(sign->status & GPGME_SIGSUM_KEY_MISSING)) { + if (!print_signer(stream, sign)) setStatus(0); + } else { + stream << _("Key is NOT present with ID 0x") << sign->fpr + << std::endl; + } + + setStatus(1); + + break; + case GPG_ERR_NO_PUBKEY: + stream << _("A signature could NOT be verified due to a Missing Key") + << std::endl; + setStatus(-2); + break; + case GPG_ERR_CERT_REVOKED: + stream << _("A signature is valid but the key used to verify the " + "signature has been revoked") + << std::endl; + if (!print_signer(stream, sign)) { + setStatus(0); + } + setStatus(-1); + break; + case GPG_ERR_SIG_EXPIRED: + stream << _("A signature is valid but expired") << std::endl; + if (!print_signer(stream, sign)) { setStatus(0); - return; - } - - stream << "[>] Signed On " << QDateTime::fromTime_t(sign->timestamp).toString() << Qt::endl; - - stream << Qt::endl << "[>] Signatures:" << Qt::endl; - - bool canContinue = true; - - while (sign && canContinue) { - - switch (gpg_err_code(sign->status)) { - case GPG_ERR_BAD_SIGNATURE: - stream << QApplication::tr("One or More Bad Signatures.") << Qt::endl; - canContinue = false; - setStatus(-1); - break; - case GPG_ERR_NO_ERROR: - stream << QApplication::tr("A "); - if (sign->summary & GPGME_SIGSUM_GREEN) { - stream << QApplication::tr("Good "); - } - if (sign->summary & GPGME_SIGSUM_RED) { - stream << QApplication::tr("Bad "); - } - if (sign->summary & GPGME_SIGSUM_SIG_EXPIRED) { - stream << QApplication::tr("Expired "); - } - if (sign->summary & GPGME_SIGSUM_KEY_MISSING) { - stream << QApplication::tr("Missing Key's "); - } - if (sign->summary & GPGME_SIGSUM_KEY_REVOKED) { - stream << QApplication::tr("Revoked Key's "); - } - if (sign->summary & GPGME_SIGSUM_KEY_EXPIRED) { - stream << QApplication::tr("Expired Key's "); - } - if (sign->summary & GPGME_SIGSUM_CRL_MISSING) { - stream << QApplication::tr("Missing CRL's "); - } - - if (sign->summary & GPGME_SIGSUM_VALID) { - stream << QApplication::tr("Signature Fully Valid.") << Qt::endl; - } else { - stream << QApplication::tr("Signature Not Fully Valid.") << Qt::endl; - } - - if (!(sign->status & GPGME_SIGSUM_KEY_MISSING)) { - if (!printSigner(stream, sign)) setStatus(0); - } else { - stream << QApplication::tr("Key is NOT present with ID 0x") << QString(sign->fpr) << Qt::endl; - } - - setStatus(1); - - break; - case GPG_ERR_NO_PUBKEY: - stream << QApplication::tr("A signature could NOT be verified due to a Missing Key\n"); - setStatus(-1); - break; - case GPG_ERR_CERT_REVOKED: - stream << QApplication::tr( - "A signature is valid but the key used to verify the signature has been revoked\n"); - if (!printSigner(stream, sign)) { - setStatus(0); - } - setStatus(-1); - break; - case GPG_ERR_SIG_EXPIRED: - stream << QApplication::tr("A signature is valid but expired\n"); - if (!printSigner(stream, sign)) { - setStatus(0); - } - setStatus(-1); - break; - case GPG_ERR_KEY_EXPIRED: - stream << QApplication::tr( - "A signature is valid but the key used to verify the signature has expired.\n"); - if (!printSigner(stream, sign)) { - setStatus(0); - } - break; - case GPG_ERR_GENERAL: - stream << QApplication::tr( - "There was some other error which prevented the signature verification.\n"); - status = -1; - canContinue = false; - break; - default: - stream << QApplication::tr("Error for key with fingerprint ") << - GpgME::GpgContext::beautifyFingerprint(QString(sign->fpr)); - setStatus(-1); - } - stream << Qt::endl; - sign = sign->next; - } - stream << "<------------" << Qt::endl; + } + setStatus(-1); + break; + case GPG_ERR_KEY_EXPIRED: + stream << _("A signature is valid but the key used to " + "verify the signature has expired.") + << std::endl; + if (!print_signer(stream, sign)) { + setStatus(0); + } + break; + case GPG_ERR_GENERAL: + stream << _("There was some other error which prevented " + "the signature verification.") + << std::endl; + status = -1; + canContinue = false; + break; + default: + auto fpr = std::string(sign->fpr); + stream << _("Error for key with fingerprint") << " " + << GpgFrontend::beautify_fingerprint(fpr); + setStatus(-1); + } + stream << std::endl; + sign = sign->next; } + stream << "<------------" << std::endl; + } } -bool VerifyResultAnalyse::printSigner(QTextStream &stream, gpgme_signature_t sign) { - bool keyFound = true; - auto key = mCtx->getKeyByFpr(sign->fpr); - - key = mCtx->getKeyByFpr(sign->fpr); +bool GpgFrontend::VerifyResultAnalyse::print_signer(std::stringstream &stream, + gpgme_signature_t sign) { + bool keyFound = true; + auto key = GpgFrontend::GpgKeyGetter::GetInstance().GetKey(sign->fpr); + + if (!key.good()) { + stream << " " << _("Signed By") << ": " + << "<" << _("Unknown") << ">" << std::endl; + setStatus(0); + keyFound = false; + } else { + stream << " " << _("Signed By") << ": " << key.uids()->front().uid() + << std::endl; + } + stream << " " << _("Public Key Algo") << ": " + << gpgme_pubkey_algo_name(sign->pubkey_algo) << std::endl; + stream << " " << _("Hash Algo") << ": " + << gpgme_hash_algo_name(sign->hash_algo) << std::endl; + stream << " " << _("Date & Time") << ": " + << boost::posix_time::to_iso_string( + boost::posix_time::from_time_t(sign->timestamp)) + << std::endl; + stream << std::endl; + return keyFound; +} - if (!key.good) { - stream << tr(" Signed By: ") << tr("<unknown>") << Qt::endl; - setStatus(0); - keyFound = false; - } else { - stream << tr(" Signed By: ") << key.uids.first().uid << Qt::endl; - } - stream << tr(" Public Key Algo: ") << gpgme_pubkey_algo_name(sign->pubkey_algo) << Qt::endl; - stream << tr(" Hash Algo: ") << gpgme_hash_algo_name(sign->hash_algo) << Qt::endl; - stream << tr(" Date & Time: ") << QDateTime::fromTime_t(sign->timestamp).toString() << Qt::endl; - stream << Qt::endl; - return keyFound; -}
\ No newline at end of file +gpgme_signature_t GpgFrontend::VerifyResultAnalyse::GetSignatures() { + if (result) + return result->signatures; + else + return nullptr; +} diff --git a/src/gpg/result_analyse/VerifyResultAnalyse.h b/src/gpg/result_analyse/VerifyResultAnalyse.h new file mode 100644 index 00000000..51ce17ac --- /dev/null +++ b/src/gpg/result_analyse/VerifyResultAnalyse.h @@ -0,0 +1,51 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_VERIFYRESULTANALYSE_H +#define GPGFRONTEND_VERIFYRESULTANALYSE_H + +#include "ResultAnalyse.h" +#include "gpg/model/GpgKeySignature.h" + +namespace GpgFrontend { + +class VerifyResultAnalyse : public ResultAnalyse { + public: + explicit VerifyResultAnalyse(GpgError error, GpgVerifyResult result); + + gpgme_signature_t GetSignatures(); + + private: + void do_analyse(); + + private: + bool print_signer(std::stringstream &stream, gpgme_signature_t sign); + + GpgError error; + GpgVerifyResult result; +}; + +} // namespace GpgFrontend + +#endif // GPGFRONTEND_VERIFYRESULTANALYSE_H diff --git a/src/main.cpp b/src/main.cpp index 1ec264e7..ee542ff0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -22,77 +22,149 @@ * */ -#include "MainWindow.h" #include "GpgFrontendBuildInfo.h" +#include "ui/MainWindow.h" +#include "ui/settings/GlobalSettingStation.h" -int main(int argc, char *argv[]) { +// Easy Logging Cpp +INITIALIZE_EASYLOGGINGPP - Q_INIT_RESOURCE(gpgfrontend); +void init_logging(); +void init_locale(); - QApplication app(argc, argv); +int main(int argc, char* argv[]) { + // Qt + Q_INIT_RESOURCE(gpgfrontend); - // get application path - QString appPath = qApp->applicationDirPath(); + // Qt App + QApplication app(argc, argv); - QApplication::setApplicationVersion(BUILD_VERSION); - QApplication::setApplicationName(PROJECT_NAME); + // logging system + init_logging(); - // dont show icons in menus - QApplication::setAttribute(Qt::AA_DontShowIconsInMenus); + // i18n + init_locale(); - // unicode in source - QTextCodec::setCodecForLocale(QTextCodec::codecForName("utf-8")); + // App config + QApplication::setApplicationVersion(BUILD_VERSION); + QApplication::setApplicationName(PROJECT_NAME); -#if OS_PLATFORM == WINDOWS - // load css file - QFile file(RESOURCE_DIR(qApp->applicationDirPath()) + "/css/default.qss"); - file.open(QFile::ReadOnly); - QString styleSheet = QLatin1String(file.readAll()); - qApp->setStyleSheet(styleSheet); - file.close(); + // don't show icons in menus + QApplication::setAttribute(Qt::AA_DontShowIconsInMenus); + + // unicode in source + QTextCodec::setCodecForLocale(QTextCodec::codecForName("utf-8")); + +#ifdef WINDOWS + // css + QFile file(RESOURCE_DIR(qApp->applicationDirPath()) + "/css/default.qss"); + file.open(QFile::ReadOnly); + QString styleSheet = QLatin1String(file.readAll()); + qApp->setStyleSheet(styleSheet); + file.close(); #endif + /** + * internationalisation. loop to restart mainwindow + * with changed translation when settings change. + */ + int return_from_event_loop_code; + + do { + QApplication::setQuitOnLastWindowClosed(true); + /** - * internationalisation. loop to restart mainwindow - * with changed translation when settings change. - */ - if(!QDir(RESOURCE_DIR(appPath) + "/conf").exists()) { - QDir().mkdir(RESOURCE_DIR(appPath) + "/conf"); - } - QSettings::setDefaultFormat(QSettings::IniFormat); - QSettings settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", QSettings::IniFormat); - QTranslator translator, translator2; - int return_from_event_loop_code; - - qDebug() << "Resource Directory" << RESOURCE_DIR(appPath); - - do { - QApplication::removeTranslator(&translator); - QApplication::removeTranslator(&translator2); - - QString lang = settings.value("int/lang", QLocale::system().name()).toString(); - if (lang.isEmpty()) { - lang = QLocale::system().name(); - } - qDebug() << "Language set" << lang; - translator.load(RESOURCE_DIR(appPath) + "/ts/" + "gpgfrontend_" + lang); - qDebug() << "Translator" << translator.filePath(); - QApplication::installTranslator(&translator); - - // set qt translations - translator2.load(RESOURCE_DIR(appPath) + "/ts/qt_" + lang); - qDebug() << "Translator2" << translator2.filePath(); - QApplication::installTranslator(&translator2); - - QApplication::setQuitOnLastWindowClosed(true); - - MainWindow window; - return_from_event_loop_code = QApplication::exec(); - - } while (return_from_event_loop_code == RESTART_CODE); - - return return_from_event_loop_code; + * The function `gpgme_check_version' must be called before any other + * function in the library, because it initializes the thread support + * subsystem in GPGME. (from the info page) */ + gpgme_check_version(nullptr); + + /** set locale, because tests do also */ + gpgme_set_locale(nullptr, LC_CTYPE, setlocale(LC_CTYPE, nullptr)); +#ifndef _WIN32 + gpgme_set_locale(nullptr, LC_MESSAGES, setlocale(LC_MESSAGES, nullptr)); +#endif + + auto main_window = std::make_unique<GpgFrontend::UI::MainWindow>(); + main_window->init(); + main_window->show(); + return_from_event_loop_code = QApplication::exec(); + + } while (return_from_event_loop_code == RESTART_CODE); + + return return_from_event_loop_code; } +void init_logging() { + using namespace boost::posix_time; + using namespace boost::gregorian; + ptime now = second_clock::local_time(); + el::Loggers::addFlag(el::LoggingFlag::AutoSpacing); + el::Configurations defaultConf; + defaultConf.setToDefault(); + el::Loggers::reconfigureLogger("default", defaultConf); + + defaultConf.setGlobally(el::ConfigurationType::Format, + "%datetime %level %func %msg"); + + auto logfile_path = + (GpgFrontend::UI::GlobalSettingStation::GetInstance().GetLogDir() / + to_iso_string(now)); + logfile_path.replace_extension(".log"); + defaultConf.setGlobally(el::ConfigurationType::Filename, + logfile_path.string()); + + el::Loggers::reconfigureLogger("default", defaultConf); + + LOG(INFO) << _("Logfile Path") << logfile_path; +} + +void init_locale() { + auto& settings = + GpgFrontend::UI::GlobalSettingStation::GetInstance().GetUISettings(); + + if (!settings.exists("general") || + settings.lookup("general").getType() != libconfig::Setting::TypeGroup) + settings.add("general", libconfig::Setting::TypeGroup); + + // set system default at first + auto& general = settings["general"]; + if (!general.exists("lang")) + general.add("lang", libconfig::Setting::TypeString) = ""; + + GpgFrontend::UI::GlobalSettingStation::GetInstance().Sync(); + + auto* locale_name = setlocale(LC_ALL, nullptr); + LOG(INFO) << "current system locale" << locale_name; + + // read from settings file + std::string lang; + if (!general.lookupValue("lang", lang)) { + LOG(ERROR) << _("Could not read properly from configure file"); + }; + + LOG(INFO) << "lang" << lang; + LOG(INFO) << "PROJECT_NAME" << PROJECT_NAME; + LOG(INFO) << "locales path" + << GpgFrontend::UI::GlobalSettingStation::GetInstance() + .GetLocaleDir() + .c_str(); + + if (!lang.empty()) lang += ".UTF8"; + // GNU gettext settings + locale_name = setlocale(LC_ALL, lang.c_str()); + if (locale_name == nullptr) { + LOG(WARNING) << "set locale name failed"; + } else { + LOG(INFO) << "locale name now" << locale_name; + } + + bindtextdomain(PROJECT_NAME, + GpgFrontend::UI::GlobalSettingStation::GetInstance() + .GetLocaleDir() + .string() + .c_str()); + textdomain(PROJECT_NAME); +} diff --git a/src/server/BaseAPI.cpp b/src/server/BaseAPI.cpp index be388df9..aa4c3f98 100644 --- a/src/server/BaseAPI.cpp +++ b/src/server/BaseAPI.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -23,48 +23,47 @@ */ #include "server/BaseAPI.h" + #include "rapidjson/writer.h" -BaseAPI::BaseAPI(ComUtils::ServiceType serviceType) : utils(new ComUtils(nullptr)), - reqUrl(utils->getUrl(serviceType)), request(reqUrl) { - request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); +BaseAPI::BaseAPI(ComUtils::ServiceType serviceType) + : utils(new ComUtils(nullptr)), + reqUrl(utils->getUrl(serviceType)), + request(reqUrl) { + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); } -BaseAPI::~BaseAPI() { - utils->deleteLater(); -} +BaseAPI::~BaseAPI() { utils->deleteLater(); } QNetworkReply *BaseAPI::send_json_data() { - rapidjson::StringBuffer sb; - rapidjson::Writer<rapidjson::StringBuffer> writer(sb); - document.Accept(writer); + rapidjson::StringBuffer sb; + rapidjson::Writer<rapidjson::StringBuffer> writer(sb); + document.Accept(writer); - QByteArray postData(sb.GetString()); - qDebug() << "postData" << QString::fromUtf8(postData); + QByteArray postData(sb.GetString()); + qDebug() << "postData" << QString::fromUtf8(postData); - auto reply = utils->getNetworkManager().post(request, postData); + auto reply = utils->getNetworkManager().post(request, postData); - while (reply->isRunning()) QApplication::processEvents(); + while (reply->isRunning()) QApplication::processEvents(); - QByteArray replyData = reply->readAll().constData(); - if (utils->checkServerReply(replyData)) { - good = true, deal_reply(); - } + QByteArray replyData = reply->readAll().constData(); + if (utils->checkServerReply(replyData)) { + good = true, deal_reply(); + } - return reply; + return reply; } void BaseAPI::start() { - construct_json(); - send_json_data()->deleteLater(); + construct_json(); + send_json_data()->deleteLater(); } void BaseAPI::refresh() { - document.Clear(); - utils->clear(); - good = false; + document.Clear(); + utils->clear(); + good = false; } -bool BaseAPI::result() const { - return good; -} +bool BaseAPI::result() const { return good; } diff --git a/src/server/BaseAPI.h b/src/server/BaseAPI.h new file mode 100644 index 00000000..46766fed --- /dev/null +++ b/src/server/BaseAPI.h @@ -0,0 +1,66 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_ZH_CN_TS_BASEAPI_H +#define GPGFRONTEND_ZH_CN_TS_BASEAPI_H + +#include "ComUtils.h" +#include "GpgFrontend.h" +#include "rapidjson/document.h" + +class BaseAPI : public QObject { + Q_OBJECT + public: + explicit BaseAPI(ComUtils::ServiceType serviceType); + + ~BaseAPI() override; + + void start(); + + void refresh(); + + [[nodiscard]] bool result() const; + + private: + ComUtils *utils; + + QUrl reqUrl; + + QNetworkRequest request; + + QNetworkReply *send_json_data(); + + protected: + bool good = false; + + rapidjson::Document document; + + const ComUtils &getUtils() { return *utils; }; + + virtual void construct_json() = 0; + + virtual void deal_reply() = 0; +}; + +#endif // GPGFRONTEND_ZH_CN_TS_BASEAPI_H diff --git a/src/server/ComUtils.cpp b/src/server/ComUtils.cpp index 01be4ea7..6a5ce7b0 100644 --- a/src/server/ComUtils.cpp +++ b/src/server/ComUtils.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -29,67 +29,71 @@ * @param reply reply data in byte array * @return if successful */ -bool ComUtils::checkServerReply(const QByteArray &reply) { - - if(reply.isEmpty()) { - QMessageBox::critical(this, tr("Error"), tr("Nothing Reply. Please check the Internet connection.")); - return false; +bool GpgFrontend::ComUtils::checkServerReply(const QByteArray &reply) { + if (reply.isEmpty()) { + QMessageBox::critical( + this, _("Error"), + _("Nothing Reply. Please check the Internet connection.")); + return false; + } + + qDebug() << "Reply" << reply; + + /** + * Server Reply Format(Except Timeout) + * { + * "status": 200, + * "msg": "OK", + * "timestamp": 1628652783895 + * "data" : { + * ... + * } + * } + */ + + // check if reply is a json object + if (replyDoc.Parse(reply).HasParseError() || !replyDoc.IsObject()) { + QMessageBox::critical(this, _("Error"), _("Unknown Error")); + return false; + } + + // check status(int) and message(string) + if (replyDoc.HasMember("status") && replyDoc.HasMember("msg") && + replyDoc.HasMember("timestamp") && replyDoc.HasMember("data") && + replyDoc["status"].IsNumber() && replyDoc["msg"].IsString() && + replyDoc["timestamp"].IsNumber() && replyDoc["data"].IsObject()) { + int status = replyDoc["status"].GetInt(); + QDateTime time; + time.setMSecsSinceEpoch(replyDoc["timestamp"].GetInt64()); + auto message = replyDoc["msg"].GetString(); + dataVal = replyDoc["data"].GetObject(); + + qDebug() << "Reply Date & Time" << time; + + // check reply timestamp + if (time < QDateTime::currentDateTime().addSecs(-10)) { + QMessageBox::critical(this, _("Network Error"), _("Outdated Reply")); + return false; } - qDebug() << "Reply" << reply; - - /** - * Server Reply Format(Except Timeout) - * { - * "status": 200, - * "msg": "OK", - * "timestamp": 1628652783895 - * "data" : { - * ... - * } - * } - */ - - // check if reply is a json object - if (replyDoc.Parse(reply).HasParseError() || !replyDoc.IsObject()) { - QMessageBox::critical(this, tr("Error"), tr("Unknown Error")); - return false; + // check status code if successful (200-299) + // check data object + if (status / 100 == 2) { + is_good = true; + return true; + } else { + if (dataVal.HasMember("exceptionMessage") && + dataVal["exceptionMessage"].IsString()) + QMessageBox::critical(this, message, + dataVal["exceptionMessage"].GetString()); + else + QMessageBox::critical(this, message, _("Unknown Reason")); } - // check status(int) and message(string) - if (replyDoc.HasMember("status") && replyDoc.HasMember("msg") && replyDoc.HasMember("timestamp") && - replyDoc.HasMember("data") - && replyDoc["status"].IsNumber() && replyDoc["msg"].IsString() && replyDoc["timestamp"].IsNumber() && - replyDoc["data"].IsObject()) { - - int status = replyDoc["status"].GetInt(); - QDateTime time; - time.setMSecsSinceEpoch(replyDoc["timestamp"].GetInt64()); - auto message = replyDoc["msg"].GetString(); - dataVal = replyDoc["data"].GetObject(); - - qDebug() << "Reply Date & Time" << time; - - // check reply timestamp - if (time < QDateTime::currentDateTime().addSecs(-10)) { - QMessageBox::critical(this, tr("Network Error"), tr("Outdated Reply")); - return false; - } - - // check status code if successful (200-299) - // check data object - if (status / 100 == 2) { - is_good = true; - return true; - } else { - if (dataVal.HasMember("exceptionMessage") && dataVal["exceptionMessage"].IsString()) - QMessageBox::critical(this, message, dataVal["exceptionMessage"].GetString()); - else QMessageBox::critical(this, message, tr("Unknown Reason")); - } - - } else QMessageBox::critical(this, tr("Network Error"), tr("Unknown Reply Format")); + } else + QMessageBox::critical(this, _("Network Error"), _("Unknown Reply Format")); - return false; + return false; } /** @@ -97,13 +101,15 @@ bool ComUtils::checkServerReply(const QByteArray &reply) { * @param key key of value * @return value in string format */ -QString ComUtils::getDataValueStr(const QString &key) const { - if (is_good) { - auto k_byte_array = key.toUtf8(); - if (dataVal.HasMember(k_byte_array.data())) { - return dataVal[k_byte_array.data()].GetString(); - } else return {}; - } else return {}; +QString GpgFrontend::ComUtils::getDataValueStr(const QString &key) const { + if (is_good) { + auto k_byte_array = key.toUtf8(); + if (dataVal.HasMember(k_byte_array.data())) { + return dataVal[k_byte_array.data()].GetString(); + } else + return {}; + } else + return {}; } /** @@ -111,87 +117,97 @@ QString ComUtils::getDataValueStr(const QString &key) const { * @param type service which server provides * @return url */ -QString ComUtils::getUrl(ComUtils::ServiceType type) const { - auto host = settings.value("general/currentGpgfrontendServer", - "service.gpgfrontend.pub").toString(); - - auto protocol = QString(); - // Localhost Debug Server - if (host == "localhost") protocol = "http://"; - else protocol = "https://"; - - auto url = protocol + host + ":9049/"; - - switch (type) { - case GetServiceToken: - url += "/user"; - break; - case ShortenCryptText: - url += "/text/new"; - break; - case GetFullCryptText: - url += "/text/get"; - break; - case UploadPubkey: - url += "/key/upload"; - break; - case GetPubkey: - url += "/key/get"; - break; - } - - qDebug() << "ComUtils getUrl" << url; - - return url; +QString GpgFrontend::ComUtils::getUrl(ComUtils::ServiceType type) const { + auto host = + settings + .value("general/currentGpgfrontendServer", "service.gpgfrontend.pub") + .toString(); + + auto protocol = QString(); + // Localhost Debug Server + if (host == "localhost") + protocol = "http://"; + else + protocol = "https://"; + + auto url = protocol + host + ":9049/"; + + switch (type) { + case GetServiceToken: + url += "/user"; + break; + case ShortenCryptText: + url += "/text/new"; + break; + case GetFullCryptText: + url += "/text/get"; + break; + case UploadPubkey: + url += "/key/upload"; + break; + case GetPubkey: + url += "/key/get"; + break; + } + + qDebug() << "ComUtils getUrl" << url; + + return url; } -bool ComUtils::checkDataValueStr(const QString &key) const { - auto key_byte_array_data = key.toUtf8().constData(); - if (is_good) { - return dataVal.HasMember(key_byte_array_data) && dataVal[key_byte_array_data].IsString(); - } else return false; +bool GpgFrontend::ComUtils::checkDataValueStr(const QString &key) const { + auto key_byte_array_data = key.toUtf8().constData(); + if (is_good) { + return dataVal.HasMember(key_byte_array_data) && + dataVal[key_byte_array_data].IsString(); + } else + return false; } -bool ComUtils::checkServiceTokenFormat(const QString &uuid) const { - return re_uuid.match(uuid).hasMatch(); +bool GpgFrontend::ComUtils::checkServiceTokenFormat(const QString &uuid) const { + return re_uuid.match(uuid).hasMatch(); } -QByteArray ComUtils::getSignStringBase64(GpgME::GpgContext *ctx, const QString &str, const GpgKey &key) { - QVector<GpgKey> keys{key}; - QByteArray outSignText; - auto signData = str.toUtf8(); - - // The use of multi-threading brings an improvement in UI smoothness - gpgme_error_t error; - auto thread = QThread::create([&]() { - error = ctx->sign(keys, signData, &outSignText, GPGME_SIG_MODE_NORMAL, nullptr, false); - }); - thread->start(); - while (thread->isRunning()) QApplication::processEvents(); - thread->deleteLater(); - - return outSignText.toBase64(); +QByteArray GpgFrontend::ComUtils::getSignStringBase64( + GpgFrontend::GpgContext *ctx, const QString &str, const GpgKey &key) { + std::vector<GpgKey> keys{key}; + QByteArray outSignText; + auto signData = str.toUtf8(); + + // The use of multi-threading brings an improvement in UI smoothness + gpgme_error_t error; + auto thread = QThread::create([&]() { + error = ctx->sign(keys, signData, &outSignText, GPGME_SIG_MODE_NORMAL, + nullptr, false); + }); + thread->start(); + while (thread->isRunning()) QApplication::processEvents(); + thread->deleteLater(); + + return outSignText.toBase64(); } -const rapidjson::Value &ComUtils::getDataValue(const QString &key) const { - if (is_good) { - auto k_byte_array = key.toUtf8(); - if (dataVal.HasMember(k_byte_array.data())) { - return dataVal[k_byte_array.data()]; - } +const rapidjson::Value &GpgFrontend::ComUtils::getDataValue( + const QString &key) const { + if (is_good) { + auto k_byte_array = key.toUtf8(); + if (dataVal.HasMember(k_byte_array.data())) { + return dataVal[k_byte_array.data()]; } - throw std::runtime_error("Inner Error"); + } + throw std::runtime_error("Inner Error"); } -bool ComUtils::checkDataValue(const QString &key) const{ - auto key_byte_array_data = key.toUtf8().constData(); - if (is_good) { - return dataVal.HasMember(key_byte_array_data); - } else return false; +bool GpgFrontend::ComUtils::checkDataValue(const QString &key) const { + auto key_byte_array_data = key.toUtf8().constData(); + if (is_good) { + return dataVal.HasMember(key_byte_array_data); + } else + return false; } -void ComUtils::clear() { - this->dataVal.Clear(); - this->replyDoc.Clear(); - is_good = false; +void GpgFrontend::ComUtils::clear() { + this->dataVal.Clear(); + this->replyDoc.Clear(); + is_good = false; }
\ No newline at end of file diff --git a/src/server/ComUtils.h b/src/server/ComUtils.h new file mode 100644 index 00000000..f281f256 --- /dev/null +++ b/src/server/ComUtils.h @@ -0,0 +1,88 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_ZH_CN_TS_COMUTILS_H +#define GPGFRONTEND_ZH_CN_TS_COMUTILS_H + +#include "GpgFrontend.h" +#include "gpg/GpgContext.h" +#include "rapidjson/document.h" + +namespace GpgFrontend { + +class ComUtils : public QWidget { + Q_OBJECT + public: + enum ServiceType { + GetServiceToken, + ShortenCryptText, + GetFullCryptText, + UploadPubkey, + GetPubkey + }; + + explicit ComUtils(QWidget *parent) + : QWidget(parent), + appPath(qApp->applicationDirPath()), + settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", + QSettings::IniFormat) {} + + [[nodiscard]] QString getUrl(ServiceType type) const; + + bool checkServerReply(const QByteArray &reply); + + [[nodiscard]] QString getDataValueStr(const QString &key) const; + + [[nodiscard]] bool checkDataValueStr(const QString &key) const; + + [[nodiscard]] const rapidjson::Value &getDataValue(const QString &key) const; + + [[nodiscard]] bool checkDataValue(const QString &key) const; + + [[nodiscard]] bool checkServiceTokenFormat(const QString &serviceToken) const; + + static QByteArray getSignStringBase64(GpgFrontend::GpgContext *ctx, + const QString &str, const GpgKey &key); + + [[nodiscard]] bool good() const { return is_good; } + + QNetworkAccessManager &getNetworkManager() { return networkMgr; } + + void clear(); + + private: + QString appPath; + QSettings settings; + rapidjson::Document replyDoc; + rapidjson::Value dataVal; + QNetworkAccessManager networkMgr; + QRegularExpression re_uuid{ + R"(\b[0-9a-f]{8}\b-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-\b[0-9a-f]{12}\b)"}; + + bool is_good = false; +}; + +} // namespace GpgFrontend + +#endif // GPGFRONTEND_ZH_CN_TS_COMUTILS_H diff --git a/src/server/api/PubkeyGetter.cpp b/src/server/api/PubkeyGetter.cpp index 2ba55d11..e2cb8708 100644 --- a/src/server/api/PubkeyGetter.cpp +++ b/src/server/api/PubkeyGetter.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -24,73 +24,72 @@ #include "server/api/PubkeyGetter.h" -PubkeyGetter::PubkeyGetter(GpgME::GpgContext *ctx, const QVector<QString> &fprs) : BaseAPI(ComUtils::GetPubkey), - mCtx(ctx), mFprs(fprs) { -} +PubkeyGetter::PubkeyGetter(GpgFrontend::GpgContext *ctx, + const QVector<QString> &fprs) + : BaseAPI(ComUtils::GetPubkey), mCtx(ctx), mFprs(fprs) {} void PubkeyGetter::construct_json() { - document.SetArray(); - QStringList keyIds; + document.SetArray(); + QStringList keyIds; - rapidjson::Document::AllocatorType &allocator = document.GetAllocator(); + rapidjson::Document::AllocatorType &allocator = document.GetAllocator(); - for (const auto &fprStr : mFprs) { - rapidjson::Value fpr; + for (const auto &fprStr : mFprs) { + rapidjson::Value fpr; - auto fprByteArray = fprStr.toUtf8(); - fpr.SetString(fprByteArray.constData(), fprByteArray.count()); + auto fprByteArray = fprStr.toUtf8(); + fpr.SetString(fprByteArray.constData(), fprByteArray.count()); - document.PushBack(fpr, allocator); - keyIds.clear(); - } + document.PushBack(fpr, allocator); + keyIds.clear(); + } } void PubkeyGetter::deal_reply() { + const auto &utils = getUtils(); + + /** + * { + * "pubkeys" : [ + * { + * "publicKey" : ..., + * "fpr" : ..., + * "sha" : ... + * }, + * ... + * ] + * } + */ + + if (!utils.checkDataValue("pubkeys")) { + QMessageBox::critical(nullptr, _("Error"), + _("The communication content with the server does " + "not meet the requirements")); + } else { + auto &pubkeys = utils.getDataValue("pubkeys"); + qDebug() << "Pubkey Getter" << pubkeys.IsArray() + << pubkeys.GetArray().Size(); + if (pubkeys.IsArray()) { + for (const auto &pubkey : pubkeys.GetArray()) { + if (pubkey.IsObject() && pubkey.HasMember("publicKey") && + pubkey.HasMember("fpr") && pubkey.HasMember("sha") && + pubkey["publicKey"].IsString() && pubkey["fpr"].IsString() && + pubkey["sha"].IsString()) { + auto pubkeyData = QString(pubkey["publicKey"].GetString()); + + QCryptographicHash shaGen(QCryptographicHash::Sha256); + shaGen.addData(pubkeyData.toUtf8()); + + if (shaGen.result().toHex() == pubkey["sha"].GetString()) { + mCtx->importKey(pubkeyData.toUtf8()); + } + } + } - const auto &utils = getUtils(); - - /** - * { - * "pubkeys" : [ - * { - * "publicKey" : ..., - * "fpr" : ..., - * "sha" : ... - * }, - * ... - * ] - * } - */ - - if (!utils.checkDataValue("pubkeys")) { - QMessageBox::critical(nullptr, tr("Error"), - tr("The communication content with the server does not meet the requirements")); } else { - auto &pubkeys = utils.getDataValue("pubkeys"); - qDebug() << "Pubkey Getter" << pubkeys.IsArray() << pubkeys.GetArray().Size(); - if (pubkeys.IsArray()) { - for (const auto &pubkey : pubkeys.GetArray()) { - if (pubkey.IsObject() - && pubkey.HasMember("publicKey") && pubkey.HasMember("fpr") && pubkey.HasMember("sha") - && pubkey["publicKey"].IsString() && pubkey["fpr"].IsString() && pubkey["sha"].IsString()) { - - auto pubkeyData = QString(pubkey["publicKey"].GetString()); - - QCryptographicHash shaGen(QCryptographicHash::Sha256); - shaGen.addData(pubkeyData.toUtf8()); - - if (shaGen.result().toHex() == pubkey["sha"].GetString()) { - mCtx->importKey(pubkeyData.toUtf8()); - } - - } - } - - } else { - QMessageBox::critical(nullptr, tr("Error"), - tr("The communication content with the server does not meet the requirements")); - } + QMessageBox::critical(nullptr, _("Error"), + _("The communication content with the server does " + "not meet the requirements")); } + } } - - diff --git a/src/server/api/PubkeyGetter.h b/src/server/api/PubkeyGetter.h new file mode 100644 index 00000000..6a3d50e9 --- /dev/null +++ b/src/server/api/PubkeyGetter.h @@ -0,0 +1,52 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_ZH_CN_TS_PUBKEYGETTER_H +#define GPGFRONTEND_ZH_CN_TS_PUBKEYGETTER_H + +#include "GpgFrontend.h" +#include "gpg/GpgContext.h" +#include "server/BaseAPI.h" + +class ComUtils; + +/** + * Get and Import Pubkey from server + */ +class PubkeyGetter : public BaseAPI { + public: + PubkeyGetter(GpgFrontend::GpgContext *ctx, const QVector<QString> &fprs); + + private: + GpgFrontend::GpgContext *mCtx; + + const QVector<QString> &mFprs; + + protected: + void construct_json() final; + + void deal_reply() final; +}; + +#endif // GPGFRONTEND_ZH_CN_TS_PUBKEYGETTER_H diff --git a/src/server/api/PubkeyUploader.cpp b/src/server/api/PubkeyUploader.cpp index c6101c65..35f764d8 100644 --- a/src/server/api/PubkeyUploader.cpp +++ b/src/server/api/PubkeyUploader.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -24,83 +24,83 @@ #include "server/api/PubkeyUploader.h" -PubkeyUploader::PubkeyUploader(GpgME::GpgContext *ctx, const QVector<GpgKey> &keys) : BaseAPI(ComUtils::UploadPubkey), - mCtx(ctx), - mKeys(keys) { -} +PubkeyUploader::PubkeyUploader(GpgFrontend::GpgContext *ctx, + const QVector<GpgKey> &keys) + : BaseAPI(ComUtils::UploadPubkey), mCtx(ctx), mKeys(keys) {} void PubkeyUploader::construct_json() { - document.SetArray(); - QStringList keyIds; - QCryptographicHash shaGen(QCryptographicHash::Sha256); - - auto &allocator = document.GetAllocator(); - - QVector<QByteArray> keysData; - for (const auto &key : mKeys) { - QByteArray keyDataBuf; - keyIds << key.id; - - // The use of multi-threading brings an improvement in UI smoothness - gpgme_error_t error; - auto thread = QThread::create([&]() { - error = mCtx->exportKeys(&keyIds, &keyDataBuf); - }); - thread->start(); - while (thread->isRunning()) QApplication::processEvents(); - thread->deleteLater(); - keysData.push_back(keyDataBuf); - keyIds.clear(); - } - - int index = 0; - for (const auto &keyData : keysData) { - rapidjson::Value publicKeyObj, pubkey, sha, signedFpr; - - shaGen.addData(keyData); - auto shaStr = shaGen.result().toHex(); - shaGen.reset(); - - auto signFprStr = ComUtils::getSignStringBase64(mCtx, mKeys[index].fpr, mKeys[index]); - qDebug() << "signFprStr" << signFprStr; - - pubkey.SetString(keyData.data(), keyData.count(), allocator); - sha.SetString(shaStr.data(), shaStr.count(), allocator); - signedFpr.SetString(signFprStr.data(), signFprStr.count(), allocator); - - publicKeyObj.SetObject(); - publicKeyObj.AddMember("publicKey", pubkey, allocator); - publicKeyObj.AddMember("sha", sha, allocator); - publicKeyObj.AddMember("signedFpr", signedFpr, allocator); - - document.PushBack(publicKeyObj, allocator); - index++; - } + document.SetArray(); + QStringList keyIds; + QCryptographicHash shaGen(QCryptographicHash::Sha256); + + auto &allocator = document.GetAllocator(); + + QVector<QByteArray> keysData; + for (const auto &key : mKeys) { + QByteArray keyDataBuf; + keyIds << key.id; + + // The use of multi-threading brings an improvement in UI smoothness + gpgme_error_t error; + auto thread = QThread::create( + [&]() { error = mCtx->exportKeys(&keyIds, &keyDataBuf); }); + thread->start(); + while (thread->isRunning()) QApplication::processEvents(); + thread->deleteLater(); + keysData.push_back(keyDataBuf); + keyIds.clear(); + } + + int index = 0; + for (const auto &keyData : keysData) { + rapidjson::Value publicKeyObj, pubkey, sha, signedFpr; + + shaGen.addData(keyData); + auto shaStr = shaGen.result().toHex(); + shaGen.reset(); + + auto signFprStr = + ComUtils::getSignStringBase64(mCtx, mKeys[index].fpr, mKeys[index]); + qDebug() << "signFprStr" << signFprStr; + + pubkey.SetString(keyData.data(), keyData.count(), allocator); + sha.SetString(shaStr.data(), shaStr.count(), allocator); + signedFpr.SetString(signFprStr.data(), signFprStr.count(), allocator); + + publicKeyObj.SetObject(); + publicKeyObj.AddMember("publicKey", pubkey, allocator); + publicKeyObj.AddMember("sha", sha, allocator); + publicKeyObj.AddMember("signedFpr", signedFpr, allocator); + + document.PushBack(publicKeyObj, allocator); + index++; + } } void PubkeyUploader::deal_reply() { - - const auto &utils = getUtils(); - - /** - * { - * "strings" : [ - * "...", - * "..." - * ] - * } - */ - - if (!utils.checkDataValue("strings")) { - QMessageBox::critical(nullptr, tr("Error"), - tr("The communication content with the server does not meet the requirements")); + const auto &utils = getUtils(); + + /** + * { + * "strings" : [ + * "...", + * "..." + * ] + * } + */ + + if (!utils.checkDataValue("strings")) { + QMessageBox::critical(nullptr, _("Error"), + _("The communication content with the server does " + "not meet the requirements")); + } else { + auto &strings = utils.getDataValue("strings"); + qDebug() << "Pubkey Uploader" << strings.IsArray() + << strings.GetArray().Size(); + if (strings.IsArray() && strings.GetArray().Size() == mKeys.size()) { + good = true; } else { - auto &strings = utils.getDataValue("strings"); - qDebug() << "Pubkey Uploader" << strings.IsArray() << strings.GetArray().Size(); - if (strings.IsArray() && strings.GetArray().Size() == mKeys.size()) { - good = true; - } else { - good = false; - } + good = false; } + } } diff --git a/src/server/api/PubkeyUploader.h b/src/server/api/PubkeyUploader.h new file mode 100644 index 00000000..efad27ac --- /dev/null +++ b/src/server/api/PubkeyUploader.h @@ -0,0 +1,51 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_ZH_CN_TS_PUBKEYUPLOADER_H +#define GPGFRONTEND_ZH_CN_TS_PUBKEYUPLOADER_H + +#include "GpgFrontend.h" +#include "gpg/GpgContext.h" +#include "rapidjson/document.h" +#include "server/BaseAPI.h" + +/** + * Upload pubkey into server + */ +class PubkeyUploader : public BaseAPI { + public: + PubkeyUploader(GpgFrontend::GpgContext *ctx, const QVector<GpgKey> &keys); + + private: + const QVector<GpgKey> &mKeys; + + GpgFrontend::GpgContext *mCtx; + + protected: + void construct_json() final; + + void deal_reply() final; +}; + +#endif // GPGFRONTEND_ZH_CN_TS_PUBKEYUPLOADER_H diff --git a/src/smtp/SmtpMime b/src/smtp/SmtpMime new file mode 100644 index 00000000..940996b8 --- /dev/null +++ b/src/smtp/SmtpMime @@ -0,0 +1,31 @@ +/* + Copyright (c) 2011-2012 - Tőkés Attila + + This file is part of SmtpClient for Qt. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + See the LICENSE file for more details. +*/ + +#ifndef SMTPMIME_H +#define SMTPMIME_H + +#include "smtpclient.h" +#include "mimepart.h" +#include "mimehtml.h" +#include "mimeattachment.h" +#include "mimemessage.h" +#include "mimetext.h" +#include "mimeinlinefile.h" +#include "mimefile.h" + +#endif // SMTPMIME_H diff --git a/src/smtp/emailaddress.h b/src/smtp/emailaddress.h new file mode 100644 index 00000000..90e4c1e9 --- /dev/null +++ b/src/smtp/emailaddress.h @@ -0,0 +1,63 @@ +/* + Copyright (c) 2011-2012 - Tőkés Attila + + This file is part of SmtpClient for Qt. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + See the LICENSE file for more details. +*/ + +#ifndef EMAILADDRESS_H +#define EMAILADDRESS_H + +#include <QObject> + +#include "smtpexports.h" + +class SMTP_EXPORT EmailAddress : public QObject { +Q_OBJECT +public: + + /* [1] Constructors and Destructors */ + + EmailAddress() = default; + + explicit EmailAddress(const QString &address, const QString &name = ""); + + ~EmailAddress() override; + + /* [1] --- */ + + + /* [2] Getters and Setters */ + void setName(const QString &name); + + void setAddress(const QString &address); + + [[nodiscard]] const QString &getName() const; + + [[nodiscard]] const QString &getAddress() const; + + /* [2] --- */ + + +private: + + /* [3] Private members */ + + QString name; + QString address; + + /* [3] --- */ +}; + +#endif // EMAILADDRESS_H diff --git a/src/smtp/mimeattachment.h b/src/smtp/mimeattachment.h new file mode 100644 index 00000000..6b98a65a --- /dev/null +++ b/src/smtp/mimeattachment.h @@ -0,0 +1,51 @@ +/* + Copyright (c) 2011-2012 - Tőkés Attila + + This file is part of SmtpClient for Qt. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + See the LICENSE file for more details. +*/ + +#ifndef MIMEATTACHMENT_H +#define MIMEATTACHMENT_H + +#include <QFile> +#include "mimepart.h" +#include "mimefile.h" + +#include "smtpexports.h" + +class SMTP_EXPORT MimeAttachment : public MimeFile { +Q_OBJECT +public: + + /* [1] Constructors and Destructors */ + + explicit MimeAttachment(QFile *file); + + MimeAttachment(const QByteArray &stream, const QString &fileName); + + ~MimeAttachment() override; + + /* [1] --- */ + +protected: + + /* [2] Protected methods */ + + void prepare() override; + + /* [2] --- */ +}; + +#endif // MIMEATTACHMENT_H diff --git a/src/smtp/mimecontentformatter.h b/src/smtp/mimecontentformatter.h new file mode 100644 index 00000000..e6e3637f --- /dev/null +++ b/src/smtp/mimecontentformatter.h @@ -0,0 +1,43 @@ +/* + Copyright (c) 2011-2012 - Tőkés Attila + + This file is part of SmtpClient for Qt. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + See the LICENSE file for more details. +*/ + +#ifndef MIMECONTENTFORMATTER_H +#define MIMECONTENTFORMATTER_H + +#include <QObject> +#include <QByteArray> + +#include "smtpexports.h" + +class SMTP_EXPORT MimeContentFormatter : public QObject { +Q_OBJECT +public: + explicit MimeContentFormatter(int max_length = 76); + + void setMaxLength(int l); + + [[nodiscard]] int getMaxLength() const; + + [[nodiscard]] QString format(const QString &content, bool quotedPrintable = false) const; + +protected: + int max_length; + +}; + +#endif // MIMECONTENTFORMATTER_H diff --git a/src/smtp/mimefile.h b/src/smtp/mimefile.h new file mode 100644 index 00000000..46903da9 --- /dev/null +++ b/src/smtp/mimefile.h @@ -0,0 +1,63 @@ +/* + Copyright (c) 2011-2012 - Tőkés Attila + + This file is part of SmtpClient for Qt. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + See the LICENSE file for more details. +*/ + +#ifndef MIMEFILE_H +#define MIMEFILE_H + +#include "mimepart.h" +#include <QFile> + +#include "smtpexports.h" + +class SMTP_EXPORT MimeFile : public MimePart { +Q_OBJECT +public: + + /* [1] Constructors and Destructors */ + + MimeFile(const QByteArray &stream, const QString &fileName); + + explicit MimeFile(QFile *f); + + ~MimeFile() override; + + /* [1] --- */ + + + /* [2] Getters and Setters */ + + /* [2] --- */ + +protected: + + /* [3] Protected members */ + + QFile *file; + + /* [3] --- */ + + + /* [4] Protected methods */ + + void prepare() override; + + /* [4] --- */ + +}; + +#endif // MIMEFILE_H diff --git a/src/smtp/mimehtml.h b/src/smtp/mimehtml.h new file mode 100644 index 00000000..8ce8c454 --- /dev/null +++ b/src/smtp/mimehtml.h @@ -0,0 +1,61 @@ +/* + Copyright (c) 2011-2012 - Tőkés Attila + + This file is part of SmtpClient for Qt. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + See the LICENSE file for more details. +*/ + +#ifndef MIMEHTML_H +#define MIMEHTML_H + +#include "mimetext.h" + +#include "smtpexports.h" + +class SMTP_EXPORT MimeHtml : public MimeText { +Q_OBJECT +public: + + /* [1] Constructors and Destructors */ + + explicit MimeHtml(const QString &html = ""); + + ~MimeHtml() override; + + /* [1] --- */ + + + /* [2] Getters and Setters */ + + void setHtml(const QString &html); + + [[nodiscard]] const QString &getHtml() const; + + /* [2] --- */ + +protected: + + /* [3] Protected members */ + + /* [3] --- */ + + + /* [4] Protected methods */ + + void prepare() override; + + /* [4] --- */ +}; + +#endif // MIMEHTML_H diff --git a/src/smtp/mimeinlinefile.h b/src/smtp/mimeinlinefile.h new file mode 100644 index 00000000..916f7b76 --- /dev/null +++ b/src/smtp/mimeinlinefile.h @@ -0,0 +1,56 @@ +/* + Copyright (c) 2011-2012 - Tőkés Attila + + This file is part of SmtpClient for Qt. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + See the LICENSE file for more details. +*/ + +#ifndef MIMEINLINEFILE_H +#define MIMEINLINEFILE_H + +#include "mimefile.h" + +#include "smtpexports.h" + +class SMTP_EXPORT MimeInlineFile : public MimeFile { +public: + + /* [1] Constructors and Destructors */ + + explicit MimeInlineFile(QFile *f); + + ~MimeInlineFile() override; + + /* [1] --- */ + + + /* [2] Getters and Setters */ + + /* [2] --- */ + +protected: + + /* [3] Protected members */ + + /* [3] --- */ + + + /* [4] Protected methods */ + + void prepare() override; + + /* [4] --- */ +}; + +#endif // MIMEINLINEFILE_H diff --git a/src/smtp/mimemessage.cpp b/src/smtp/mimemessage.cpp index cf653e0a..6c058e89 100644 --- a/src/smtp/mimemessage.cpp +++ b/src/smtp/mimemessage.cpp @@ -17,26 +17,26 @@ */ #include "smtp/mimemessage.h" -#include "smtp/quotedprintable.h" #include <QDateTime> #include <QLocale> #include <typeinfo> +#include "smtp/quotedprintable.h" + /* [1] Constructors and Destructors */ MimeMessage::MimeMessage(bool createAutoMimeContent) - : replyTo(nullptr), hEncoding(MimePart::_8Bit) { - if (createAutoMimeContent) - this->content = new MimeMultiPart(); + : replyTo(nullptr), hEncoding(MimePart::_8Bit) { + if (createAutoMimeContent) this->content = new MimeMultiPart(); - autoMimeContentCreated = createAutoMimeContent; + autoMimeContentCreated = createAutoMimeContent; } MimeMessage::~MimeMessage() { - if (this->autoMimeContentCreated) { - this->autoMimeContentCreated = false; - delete (this->content); - } + if (this->autoMimeContentCreated) { + this->autoMimeContentCreated = false; + delete (this->content); + } } /* [1] --- */ @@ -45,34 +45,34 @@ MimeMessage::~MimeMessage() { MimePart &MimeMessage::getContent() { return *content; } void MimeMessage::setContent(MimePart *content) { - if (this->autoMimeContentCreated) { - this->autoMimeContentCreated = false; - delete (this->content); - } - this->content = content; + if (this->autoMimeContentCreated) { + this->autoMimeContentCreated = false; + delete (this->content); + } + this->content = content; } void MimeMessage::setReplyTo(EmailAddress *rto) { replyTo = rto; } void MimeMessage::setSender(EmailAddress *e) { - this->sender = e; - e->setParent(this); + this->sender = e; + e->setParent(this); } void MimeMessage::addRecipient(EmailAddress *rcpt, RecipientType type) { - switch (type) { - case To: - recipientsTo << rcpt; - break; - case Cc: - recipientsCc << rcpt; - break; - case Bcc: - recipientsBcc << rcpt; - break; - } - - rcpt->setParent(this); + switch (type) { + case To: + recipientsTo << rcpt; + break; + case Cc: + recipientsCc << rcpt; + break; + case Bcc: + recipientsBcc << rcpt; + break; + } + + rcpt->setParent(this); } void MimeMessage::addTo(EmailAddress *rcpt) { this->recipientsTo << rcpt; } @@ -82,36 +82,36 @@ void MimeMessage::addCc(EmailAddress *rcpt) { this->recipientsCc << rcpt; } void MimeMessage::addBcc(EmailAddress *rcpt) { this->recipientsBcc << rcpt; } void MimeMessage::setSubject(const QString &subject) { - this->subject = subject; + this->subject = subject; } void MimeMessage::addPart(MimePart *part) { - if (typeid(*content) == typeid(MimeMultiPart)) { - ((MimeMultiPart *) content)->addPart(part); - }; + if (typeid(*content) == typeid(MimeMultiPart)) { + ((MimeMultiPart *)content)->addPart(part); + }; } void MimeMessage::setInReplyTo(const QString &inReplyTo) { - mInReplyTo = inReplyTo; + mInReplyTo = inReplyTo; } void MimeMessage::setHeaderEncoding(MimePart::Encoding hEnc) { - this->hEncoding = hEnc; + this->hEncoding = hEnc; } const EmailAddress &MimeMessage::getSender() const { return *sender; } -const QList<EmailAddress *> & -MimeMessage::getRecipients(RecipientType type) const { - switch (type) { - default: - case To: - return recipientsTo; - case Cc: - return recipientsCc; - case Bcc: - return recipientsBcc; - } +const QList<EmailAddress *> &MimeMessage::getRecipients( + RecipientType type) const { + switch (type) { + default: + case To: + return recipientsTo; + case Cc: + return recipientsCc; + case Bcc: + return recipientsBcc; + } } const EmailAddress *MimeMessage::getReplyTo() const { return replyTo; } @@ -119,13 +119,13 @@ const EmailAddress *MimeMessage::getReplyTo() const { return replyTo; } const QString &MimeMessage::getSubject() const { return subject; } const QList<MimePart *> &MimeMessage::getParts() const { - if (typeid(*content) == typeid(MimeMultiPart)) { - return ((MimeMultiPart *) content)->getParts(); - } else { - auto *res = new QList<MimePart *>(); - res->append(content); - return *res; - } + if (typeid(*content) == typeid(MimeMultiPart)) { + return ((MimeMultiPart *)content)->getParts(); + } else { + auto *res = new QList<MimePart *>(); + res->append(content); + return *res; + } } /* [2] --- */ @@ -133,176 +133,180 @@ const QList<MimePart *> &MimeMessage::getParts() const { /* [3] Public Methods */ QString MimeMessage::toString() { - QString mime; - - /* =========== MIME HEADER ============ */ - - /* ---------- Sender / From ----------- */ - mime = "From:"; - if (sender->getName() != "") { - switch (hEncoding) { - case MimePart::Base64: - mime += " =?utf-8?B?" + - QByteArray().append(sender->getName().toUtf8()).toBase64() + "?="; - break; - case MimePart::QuotedPrintable: - mime += " =?utf-8?Q?" + - QuotedPrintable::encode( - QByteArray().append(sender->getName().toUtf8())) - .replace(' ', "_") - .replace(':', "=3A") + - "?="; - break; - default: - mime += " " + sender->getName(); - } + QString mime; + + /* =========== MIME HEADER ============ */ + + /* ---------- Sender / From ----------- */ + mime = "From:"; + if (!sender->getName().isEmpty()) { + switch (hEncoding) { + case MimePart::Base64: + mime += " =?utf-8?B?" + + QByteArray().append(sender->getName().toUtf8()).toBase64() + + "?="; + break; + case MimePart::QuotedPrintable: + mime += " =?utf-8?Q?" + + QuotedPrintable::encode( + QByteArray().append(sender->getName().toUtf8())) + .replace(' ', "_") + .replace(':', "=3A") + + "?="; + break; + default: + mime += " " + sender->getName(); } - mime += " <" + sender->getAddress() + ">\r\n"; - /* ---------------------------------- */ - - /* ------- Recipients / To ---------- */ - mime += "To:"; - QList<EmailAddress *>::iterator it; - int i; - for (i = 0, it = recipientsTo.begin(); it != recipientsTo.end(); ++it, ++i) { - if (i != 0) { - mime += ","; - } - - if ((*it)->getName() != "") { - switch (hEncoding) { - case MimePart::Base64: - mime += " =?utf-8?B?" + - QByteArray().append((*it)->getName().toUtf8()).toBase64() + - "?="; - break; - case MimePart::QuotedPrintable: - mime += " =?utf-8?Q?" + - QuotedPrintable::encode( - QByteArray().append((*it)->getName().toUtf8())) - .replace(' ', "_") - .replace(':', "=3A") + - "?="; - break; - default: - mime += " " + (*it)->getName(); - } - } - mime += " <" + (*it)->getAddress() + ">"; + } + mime += " <" + sender->getAddress() + ">\r\n"; + /* ---------------------------------- */ + + /* ------- Recipients / To ---------- */ + mime += "To:"; + QList<EmailAddress *>::iterator it; + int i; + for (i = 0, it = recipientsTo.begin(); it != recipientsTo.end(); ++it, ++i) { + if (i != 0) { + mime += ","; } - mime += "\r\n"; - /* ---------------------------------- */ - /* ------- Recipients / Cc ---------- */ - if (!recipientsCc.empty()) { - mime += "Cc:"; - } - for (i = 0, it = recipientsCc.begin(); it != recipientsCc.end(); ++it, ++i) { - if (i != 0) { - mime += ","; - } - - if ((*it)->getName() != "") { - switch (hEncoding) { - case MimePart::Base64: - mime += " =?utf-8?B?" + - QByteArray().append((*it)->getName().toUtf8()).toBase64() + - "?="; - break; - case MimePart::QuotedPrintable: - mime += " =?utf-8?Q?" + - QuotedPrintable::encode( - QByteArray().append((*it)->getName().toUtf8())) - .replace(' ', "_") - .replace(':', "=3A") + - "?="; - break; - default: - mime += " " + (*it)->getName(); - } - } - mime += " <" + (*it)->getAddress() + ">"; + if (!(*it)->getName().isEmpty()) { + switch (hEncoding) { + case MimePart::Base64: + mime += " =?utf-8?B?" + + QByteArray().append((*it)->getName().toUtf8()).toBase64() + + "?="; + break; + case MimePart::QuotedPrintable: + mime += " =?utf-8?Q?" + + QuotedPrintable::encode( + QByteArray().append((*it)->getName().toUtf8())) + .replace(' ', "_") + .replace(':', "=3A") + + "?="; + break; + default: + mime += " " + (*it)->getName(); + } } - if (!recipientsCc.empty()) { - mime += "\r\n"; + mime += " <" + (*it)->getAddress() + ">"; + } + mime += "\r\n"; + /* ---------------------------------- */ + + /* ------- Recipients / Cc ---------- */ + if (!recipientsCc.empty()) { + mime += "Cc:"; + } + for (i = 0, it = recipientsCc.begin(); it != recipientsCc.end(); ++it, ++i) { + if (i != 0) { + mime += ","; } - /* ---------------------------------- */ - /* ------------ Subject ------------- */ - mime += "Subject: "; - - switch (hEncoding) { + if ((*it)->getName() != "") { + switch (hEncoding) { case MimePart::Base64: - mime += "=?utf-8?B?" + QByteArray().append(subject.toUtf8()).toBase64() + "?="; - break; + mime += " =?utf-8?B?" + + QByteArray().append((*it)->getName().toUtf8()).toBase64() + + "?="; + break; case MimePart::QuotedPrintable: - mime += "=?utf-8?Q?" + - QuotedPrintable::encode(QByteArray().append(subject.toUtf8())) - .replace(' ', "_") - .replace(':', "=3A") + - "?="; - break; + mime += " =?utf-8?Q?" + + QuotedPrintable::encode( + QByteArray().append((*it)->getName().toUtf8())) + .replace(' ', "_") + .replace(':', "=3A") + + "?="; + break; default: - mime += subject; + mime += " " + (*it)->getName(); + } } + mime += " <" + (*it)->getAddress() + ">"; + } + if (!recipientsCc.empty()) { mime += "\r\n"; - /* ---------------------------------- */ - - /* ---------- Reply-To -------------- */ - if (replyTo) { - mime += "Reply-To: "; - if (replyTo->getName() != "") { - switch (hEncoding) { - case MimePart::Base64: - mime += " =?utf-8?B?" + - QByteArray().append(replyTo->getName().toUtf8()).toBase64() + "?="; - break; - case MimePart::QuotedPrintable: - mime += " =?utf-8?Q?" + - QuotedPrintable::encode(QByteArray().append(replyTo->getName().toUtf8())) - .replace(' ', "_") - .replace(':', "=3A") + - "?="; - break; - default: - mime += " " + replyTo->getName(); - } - } - mime += " <" + replyTo->getAddress() + ">\r\n"; - } - - /* ---------------------------------- */ - - mime += "MIME-Version: 1.0\r\n"; - if (!mInReplyTo.isEmpty()) { - mime += "In-Reply-To: <" + mInReplyTo + ">\r\n"; - mime += "References: <" + mInReplyTo + ">\r\n"; + } + /* ---------------------------------- */ + + /* ------------ Subject ------------- */ + mime += "Subject: "; + + switch (hEncoding) { + case MimePart::Base64: + mime += "=?utf-8?B?" + QByteArray().append(subject.toUtf8()).toBase64() + + "?="; + break; + case MimePart::QuotedPrintable: + mime += "=?utf-8?Q?" + + QuotedPrintable::encode(QByteArray().append(subject.toUtf8())) + .replace(' ', "_") + .replace(':', "=3A") + + "?="; + break; + default: + mime += subject; + } + mime += "\r\n"; + /* ---------------------------------- */ + + /* ---------- Reply-To -------------- */ + if (replyTo) { + mime += "Reply-To: "; + if (!replyTo->getName().isEmpty()) { + switch (hEncoding) { + case MimePart::Base64: + mime += " =?utf-8?B?" + + QByteArray().append(replyTo->getName().toUtf8()).toBase64() + + "?="; + break; + case MimePart::QuotedPrintable: + mime += " =?utf-8?Q?" + + QuotedPrintable::encode( + QByteArray().append(replyTo->getName().toUtf8())) + .replace(' ', "_") + .replace(':', "=3A") + + "?="; + break; + default: + mime += " " + replyTo->getName(); + } } - - QDateTime now = QDateTime::currentDateTime(); -#if QT_VERSION_MAJOR < 5 // Qt4 workaround since RFC2822Date isn't defined - QString shortDayName = - QLocale::c().dayName(now.date().dayOfWeek(), QLocale::ShortFormat); - QString shortMonthName = - QLocale::c().monthName(now.date().month(), QLocale::ShortFormat); - int utcOffset = now.secsTo(QDateTime(now.date(), now.time(), Qt::UTC)) / 60; - char timezoneSign = utcOffset >= 0 ? '+' : '-'; - utcOffset = utcOffset >= 0 ? utcOffset : -utcOffset; - QString timezone = QString("%1%2%3") - .arg(timezoneSign) - .arg(utcOffset / 60, 2, 10, QChar('0')) - .arg(utcOffset % 60, 2, 10, QChar('0')); - mime += QString("Date: %1\r\n") - .arg(now.toString("%1, dd %2 yyyy hh:mm:ss %3") - .arg(shortDayName) - .arg(shortMonthName) - .arg(timezone)); -#else // Qt5 supported - mime += QString("Date: %1\r\n").arg(now.toString(Qt::RFC2822Date)); -#endif // support RFC2822Date - - mime += content->toString(); - return mime; + mime += " <" + replyTo->getAddress() + ">\r\n"; + } + + /* ---------------------------------- */ + + mime += "MIME-Version: 1.0\r\n"; + if (!mInReplyTo.isEmpty()) { + mime += "In-Reply-To: <" + mInReplyTo + ">\r\n"; + mime += "References: <" + mInReplyTo + ">\r\n"; + } + + QDateTime now = QDateTime::currentDateTime(); +#if QT_VERSION_MAJOR < 5 // Qt4 workaround since RFC2822Date isn't defined + QString shortDayName = + QLocale::c().dayName(now.date().dayOfWeek(), QLocale::ShortFormat); + QString shortMonthName = + QLocale::c().monthName(now.date().month(), QLocale::ShortFormat); + int utcOffset = now.secsTo(QDateTime(now.date(), now.time(), Qt::UTC)) / 60; + char timezoneSign = utcOffset >= 0 ? '+' : '-'; + utcOffset = utcOffset >= 0 ? utcOffset : -utcOffset; + QString timezone = QString("%1%2%3") + .arg(timezoneSign) + .arg(utcOffset / 60, 2, 10, QChar('0')) + .arg(utcOffset % 60, 2, 10, QChar('0')); + mime += QString("Date: %1\r\n") + .arg(now.toString("%1, dd %2 yyyy hh:mm:ss %3") + .arg(shortDayName) + .arg(shortMonthName) + .arg(timezone)); +#else // Qt5 supported + mime += QString("Date: %1\r\n").arg(now.toString(Qt::RFC2822Date)); +#endif // support RFC2822Date + + mime += content->toString(); + return mime; } /* [3] --- */ diff --git a/src/smtp/mimemessage.h b/src/smtp/mimemessage.h new file mode 100644 index 00000000..24e4f108 --- /dev/null +++ b/src/smtp/mimemessage.h @@ -0,0 +1,110 @@ +/* + Copyright (c) 2011-2012 - Tőkés Attila + + This file is part of SmtpClient for Qt. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + See the LICENSE file for more details. +*/ + +#ifndef MIMEMESSAGE_H +#define MIMEMESSAGE_H + +#include "mimepart.h" +#include "mimemultipart.h" +#include "emailaddress.h" +#include <QList> + +#include "smtpexports.h" + +class SMTP_EXPORT MimeMessage : public QObject { +public: + + enum RecipientType { + To, // primary + Cc, // carbon copy + Bcc // blind carbon copy + }; + + /* [1] Constructors and Destructors */ + + explicit MimeMessage(bool createAutoMimeConent = true); + + ~MimeMessage() override; + + /* [1] --- */ + + + /* [2] Getters and Setters */ + + void setSender(EmailAddress *e); + + void addRecipient(EmailAddress *rcpt, RecipientType type = To); + + void addTo(EmailAddress *rcpt); + + void addCc(EmailAddress *rcpt); + + void addBcc(EmailAddress *rcpt); + + void setSubject(const QString &subject); + + void addPart(MimePart *part); + + void setReplyTo(EmailAddress *rto); + + void setInReplyTo(const QString &inReplyTo); + + void setHeaderEncoding(MimePart::Encoding); + + [[nodiscard]] const EmailAddress &getSender() const; + + [[nodiscard]] const QList<EmailAddress *> &getRecipients(RecipientType type = To) const; + + [[nodiscard]] const QString &getSubject() const; + + [[nodiscard]] const QList<MimePart *> &getParts() const; + + [[nodiscard]] const EmailAddress *getReplyTo() const; + + MimePart &getContent(); + + void setContent(MimePart *content); + /* [2] --- */ + + + /* [3] Public methods */ + + virtual QString toString(); + + /* [3] --- */ + +protected: + + /* [4] Protected members */ + + EmailAddress *sender{}; + EmailAddress *replyTo; + QList<EmailAddress *> recipientsTo, recipientsCc, recipientsBcc; + QString subject; + QString mInReplyTo; + MimePart *content; + bool autoMimeContentCreated; + + MimePart::Encoding hEncoding; + + /* [4] --- */ + + +}; + +#endif // MIMEMESSAGE_H diff --git a/src/smtp/mimemultipart.cpp b/src/smtp/mimemultipart.cpp index 14a813c2..4dd00d1a 100644 --- a/src/smtp/mimemultipart.cpp +++ b/src/smtp/mimemultipart.cpp @@ -17,30 +17,31 @@ */ #include "smtp/mimemultipart.h" + #include <QCryptographicHash> #include <QRandomGenerator> #include <QTime> const QString MULTI_PART_NAMES[] = { - "multipart/mixed", // Mixed - "multipart/digest", // Digest - "multipart/alternative", // Alternative - "multipart/related", // Related - "multipart/report", // Report - "multipart/signed", // Signed - "multipart/encrypted" // Encrypted + "multipart/mixed", // Mixed + "multipart/digest", // Digest + "multipart/alternative", // Alternative + "multipart/related", // Related + "multipart/report", // Report + "multipart/signed", // Signed + "multipart/encrypted" // Encrypted }; MimeMultiPart::MimeMultiPart(MultiPartType type) { - this->type = type; - this->cType = MULTI_PART_NAMES[this->type]; - this->cEncoding = _8Bit; + this->type = type; + this->cType = MULTI_PART_NAMES[this->type]; + this->cEncoding = _8Bit; - QRandomGenerator generator; + QRandomGenerator generator; - QCryptographicHash md5(QCryptographicHash::Md5); - md5.addData(QByteArray().append((char) generator.generate())); - cBoundary = md5.result().toHex(); + QCryptographicHash md5(QCryptographicHash::Md5); + md5.addData(QByteArray().append((char)generator.generate())); + cBoundary = md5.result().toHex(); } void MimeMultiPart::addPart(MimePart *part) { parts.append(part); } @@ -48,23 +49,23 @@ void MimeMultiPart::addPart(MimePart *part) { parts.append(part); } const QList<MimePart *> &MimeMultiPart::getParts() const { return parts; } void MimeMultiPart::prepare() { - QList<MimePart *>::iterator it; + QList<MimePart *>::iterator it; - content = ""; - for (it = parts.begin(); it != parts.end(); it++) { - content += QString("--" + cBoundary + "\r\n").toUtf8(); - (*it)->prepare(); - content += (*it)->toString().toUtf8(); - }; + content.clear(); + for (it = parts.begin(); it != parts.end(); it++) { + content += QString("--" + cBoundary + "\r\n").toUtf8(); + (*it)->prepare(); + content += (*it)->toString().toUtf8(); + }; - content += QString("--" + cBoundary + "--\r\n").toUtf8(); + content += QString("--" + cBoundary + "--\r\n").toUtf8(); - MimePart::prepare(); + MimePart::prepare(); } void MimeMultiPart::setMimeType(const MultiPartType type) { - this->type = type; - this->cType = MULTI_PART_NAMES[type]; + this->type = type; + this->cType = MULTI_PART_NAMES[type]; } MimeMultiPart::MultiPartType MimeMultiPart::getMimeType() const { return type; } diff --git a/src/smtp/mimemultipart.h b/src/smtp/mimemultipart.h new file mode 100644 index 00000000..b829a66f --- /dev/null +++ b/src/smtp/mimemultipart.h @@ -0,0 +1,71 @@ +/* + Copyright (c) 2011-2012 - Tőkés Attila + + This file is part of SmtpClient for Qt. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + See the LICENSE file for more details. +*/ + +#ifndef MIMEMULTIPART_H +#define MIMEMULTIPART_H + +#include "mimepart.h" + +#include "smtpexports.h" + +class SMTP_EXPORT MimeMultiPart : public MimePart { +Q_OBJECT +public: + /* [0] Enums */ + enum MultiPartType { + Mixed = 0, // RFC 2046, section 5.1.3 + Digest = 1, // RFC 2046, section 5.1.5 + Alternative = 2, // RFC 2046, section 5.1.4 + Related = 3, // RFC 2387 + Report = 4, // RFC 6522 + Signed = 5, // RFC 1847, section 2.1 + Encrypted = 6 // RFC 1847, section 2.2 + }; + + /* [0] --- */ + + /* [1] Constructors and Destructors */ + explicit MimeMultiPart(MultiPartType type = Related); + + /* [1] --- */ + + /* [2] Getters and Setters */ + + void setMimeType(MultiPartType type); + + [[nodiscard]] MultiPartType getMimeType() const; + + [[nodiscard]] const QList<MimePart *> &getParts() const; + + /* [2] --- */ + + /* [3] Public methods */ + + void addPart(MimePart *part); + + void prepare() override; + + /* [3] --- */ + +protected: + QList<MimePart *> parts; + + MultiPartType type; +}; + +#endif // MIMEMULTIPART_H diff --git a/src/smtp/mimepart.cpp b/src/smtp/mimepart.cpp index 5d33884d..10aa6cbc 100644 --- a/src/smtp/mimepart.cpp +++ b/src/smtp/mimepart.cpp @@ -17,14 +17,15 @@ */ #include "smtp/mimepart.h" + #include "smtp/quotedprintable.h" /* [1] Constructors and Destructors */ MimePart::MimePart() { - cEncoding = _7Bit; - prepared = false; - cBoundary = ""; + cEncoding = _7Bit; + prepared = false; + cBoundary.clear(); } /* [1] --- */ @@ -32,13 +33,13 @@ MimePart::MimePart() { /* [2] Getters and Setters */ void MimePart::setContent(const QByteArray &content) { - this->content = content; + this->content = content; } void MimePart::setHeader(const QString &header) { this->header = header; } void MimePart::addHeaderLine(const QString &line) { - this->header += line + "\r\n"; + this->header += line + "\r\n"; } const QString &MimePart::getHeader() const { return header; } @@ -66,7 +67,7 @@ void MimePart::setEncoding(Encoding enc) { this->cEncoding = enc; } MimePart::Encoding MimePart::getEncoding() const { return this->cEncoding; } MimeContentFormatter &MimePart::getContentFormatter() { - return this->formatter; + return this->formatter; } /* [2] --- */ @@ -74,10 +75,9 @@ MimeContentFormatter &MimePart::getContentFormatter() { /* [3] Public methods */ QString MimePart::toString() { - if (!prepared) - prepare(); + if (!prepared) prepare(); - return mimeString; + return mimeString; } /* [3] --- */ @@ -85,75 +85,74 @@ QString MimePart::toString() { /* [4] Protected methods */ void MimePart::prepare() { - mimeString = QString(); - - /* === Header Prepare === */ - - /* Content-Type */ - mimeString.append("Content-Type: ").append(cType); - - if (cName != "") - mimeString.append("; name=\"").append(cName).append("\""); - - if (cCharset != "") - mimeString.append("; charset=").append(cCharset); - - if (cBoundary != "") - mimeString.append("; boundary=").append(cBoundary); - - mimeString.append("\r\n"); - /* ------------ */ - - /* Content-Transfer-Encoding */ - mimeString.append("Content-Transfer-Encoding: "); - switch (cEncoding) { - case _7Bit: - mimeString.append("7bit\r\n"); - break; - case _8Bit: - mimeString.append("8bit\r\n"); - break; - case Base64: - mimeString.append("base64\r\n"); - break; - case QuotedPrintable: - mimeString.append("quoted-printable\r\n"); - break; - } - /* ------------------------ */ - - /* Content-Id */ - if (cId != NULL) - mimeString.append("Content-ID: <").append(cId).append(">\r\n"); - /* ---------- */ - - /* Addition header lines */ - - mimeString.append(header).append("\r\n"); - - /* ------------------------- */ - - /* === End of Header Prepare === */ - - /* === Content === */ - switch (cEncoding) { - case _7Bit: - mimeString.append(QString(content).toLatin1()); - break; - case _8Bit: - mimeString.append(content); - break; - case Base64: - mimeString.append(formatter.format(content.toBase64())); - break; - case QuotedPrintable: - mimeString.append(formatter.format(QuotedPrintable::encode(content), true)); - break; - } - mimeString.append("\r\n"); - /* === End of Content === */ - - prepared = true; + mimeString = QString(); + + /* === Header Prepare === */ + + /* Content-Type */ + mimeString.append("Content-Type: ").append(cType); + + if (!cName.isEmpty()) + mimeString.append("; name=\"").append(cName).append("\""); + + if (!cCharset.isEmpty()) mimeString.append("; charset=").append(cCharset); + + if (!cBoundary.isEmpty()) mimeString.append("; boundary=").append(cBoundary); + + mimeString.append("\r\n"); + /* ------------ */ + + /* Content-Transfer-Encoding */ + mimeString.append("Content-Transfer-Encoding: "); + switch (cEncoding) { + case _7Bit: + mimeString.append("7bit\r\n"); + break; + case _8Bit: + mimeString.append("8bit\r\n"); + break; + case Base64: + mimeString.append("base64\r\n"); + break; + case QuotedPrintable: + mimeString.append("quoted-printable\r\n"); + break; + } + /* ------------------------ */ + + /* Content-Id */ + if (cId != nullptr) + mimeString.append("Content-ID: <").append(cId).append(">\r\n"); + /* ---------- */ + + /* Addition header lines */ + + mimeString.append(header).append("\r\n"); + + /* ------------------------- */ + + /* === End of Header Prepare === */ + + /* === Content === */ + switch (cEncoding) { + case _7Bit: + mimeString.append(QString(content).toLatin1()); + break; + case _8Bit: + mimeString.append(content); + break; + case Base64: + mimeString.append(formatter.format(content.toBase64())); + break; + case QuotedPrintable: + mimeString.append( + formatter.format(QuotedPrintable::encode(content), true)); + break; + } + mimeString.append("\r\n"); + /* === End of Content === */ + + prepared = true; } /* [4] --- */ diff --git a/src/smtp/mimepart.h b/src/smtp/mimepart.h new file mode 100644 index 00000000..1a1386de --- /dev/null +++ b/src/smtp/mimepart.h @@ -0,0 +1,110 @@ +/* + Copyright (c) 2011-2012 - Tőkés Attila + + This file is part of SmtpClient for Qt. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + See the LICENSE file for more details. +*/ + +#ifndef MIMEPART_H +#define MIMEPART_H + +#include "mimecontentformatter.h" +#include <QObject> + +#include "smtpexports.h" + +class SMTP_EXPORT MimePart : public QObject { +Q_OBJECT +public: + /* [0] Enumerations */ + enum Encoding { + _7Bit, _8Bit, Base64, QuotedPrintable + }; + + /* [0] --- */ + + /* [1] Constructors and Destructors */ + + MimePart(); + + ~MimePart() = default; + + /* [1] --- */ + + /* [2] Getters and Setters */ + + [[nodiscard]] const QString &getHeader() const; + + [[nodiscard]] const QByteArray &getContent() const; + + void setContent(const QByteArray &content); + + void setHeader(const QString &header); + + void addHeaderLine(const QString &line); + + void setContentId(const QString &cId); + + [[nodiscard]] const QString &getContentId() const; + + void setContentName(const QString &cName); + + [[nodiscard]] const QString &getContentName() const; + + void setContentType(const QString &cType); + + [[nodiscard]] const QString &getContentType() const; + + void setCharset(const QString &charset); + + [[nodiscard]] const QString &getCharset() const; + + void setEncoding(Encoding enc); + + [[nodiscard]] Encoding getEncoding() const; + + MimeContentFormatter &getContentFormatter(); + + /* [2] --- */ + + /* [3] Public methods */ + + virtual QString toString(); + + virtual void prepare(); + + /* [3] --- */ + +protected: + /* [4] Protected members */ + + QString header; + QByteArray content; + + QString cId; + QString cName; + QString cType; + QString cCharset; + QString cBoundary; + Encoding cEncoding; + + QString mimeString; + bool prepared; + + MimeContentFormatter formatter; + + /* [4] --- */ +}; + +#endif // MIMEPART_H diff --git a/src/smtp/mimetext.h b/src/smtp/mimetext.h new file mode 100644 index 00000000..c21a1c5e --- /dev/null +++ b/src/smtp/mimetext.h @@ -0,0 +1,62 @@ +/* + Copyright (c) 2011-2012 - Tőkés Attila + + This file is part of SmtpClient for Qt. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + See the LICENSE file for more details. +*/ + +#ifndef MIMETEXT_H +#define MIMETEXT_H + +#include "mimepart.h" + +#include "smtpexports.h" + +class SMTP_EXPORT MimeText : public MimePart { +public: + + /* [1] Constructors and Destructors */ + + explicit MimeText(const QString &text = ""); + + ~MimeText() override; + + /* [1] --- */ + + + /* [2] Getters and Setters*/ + + void setText(const QString &text); + + [[nodiscard]] const QString &getText() const; + + /* [2] --- */ + +protected: + + /* [3] Protected members */ + + QString text; + /* [3] --- */ + + + /* [4] Protected methods */ + + void prepare() override; + + /* [4] --- */ + +}; + +#endif // MIMETEXT_H diff --git a/src/smtp/quotedprintable.h b/src/smtp/quotedprintable.h new file mode 100644 index 00000000..00ca3cf8 --- /dev/null +++ b/src/smtp/quotedprintable.h @@ -0,0 +1,39 @@ +/* + Copyright (c) 2011-2012 - Tőkés Attila + + This file is part of SmtpClient for Qt. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + See the LICENSE file for more details. +*/ + +#ifndef QUOTEDPRINTABLE_H +#define QUOTEDPRINTABLE_H + +#include <QObject> +#include <QByteArray> + +#include "smtpexports.h" + +class SMTP_EXPORT QuotedPrintable : public QObject { +Q_OBJECT +public: + + static QString encode(const QByteArray &input); + + static QByteArray decode(const QString &input); + +private: + QuotedPrintable(); +}; + +#endif // QUOTEDPRINTABLE_H diff --git a/src/smtp/smtpclient.h b/src/smtp/smtpclient.h new file mode 100644 index 00000000..29c507dc --- /dev/null +++ b/src/smtp/smtpclient.h @@ -0,0 +1,197 @@ +/* + Copyright (c) 2011-2012 - Tőkés Attila + + This file is part of SmtpClient for Qt. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + See the LICENSE file for more details. +*/ + +#ifndef SMTPCLIENT_H +#define SMTPCLIENT_H + +#include <QObject> +#include <QtNetwork/QSslSocket> + +#include "mimemessage.h" +#include "smtpexports.h" + +class SMTP_EXPORT SmtpClient : public QObject { +Q_OBJECT +public: + + /* [0] Enumerations */ + + enum AuthMethod { + AuthPlain, + AuthLogin + }; + + enum SmtpError { + ConnectionTimeoutError, + ResponseTimeoutError, + SendDataTimeoutError, + AuthenticationFailedError, + ServerError, // 4xx smtp error + ClientError // 5xx smtp error + }; + + enum ConnectionType { + TcpConnection, + SslConnection, + TlsConnection // STARTTLS + }; + + /* [0] --- */ + + + /* [1] Constructors and Destructors */ + + explicit SmtpClient(const QString &host = "localhost", int port = 25, ConnectionType ct = TcpConnection); + + ~SmtpClient() override; + + /* [1] --- */ + + + /* [2] Getters and Setters */ + + [[nodiscard]] const QString &getHost() const; + + void setHost(const QString &host); + + [[nodiscard]] int getPort() const; + + void setPort(int port); + + [[nodiscard]] const QString &getName() const; + + void setName(const QString &name); + + [[nodiscard]] ConnectionType getConnectionType() const; + + void setConnectionType(ConnectionType ct); + + [[nodiscard]] const QString &getUser() const; + + void setUser(const QString &user); + + [[nodiscard]] const QString &getPassword() const; + + void setPassword(const QString &password); + + [[nodiscard]] SmtpClient::AuthMethod getAuthMethod() const; + + void setAuthMethod(AuthMethod method); + + [[nodiscard]] const QString &getResponseText() const; + + [[nodiscard]] int getResponseCode() const; + + [[nodiscard]] int getConnectionTimeout() const; + + void setConnectionTimeout(int msec); + + [[nodiscard]] int getResponseTimeout() const; + + void setResponseTimeout(int msec); + + [[nodiscard]] int getSendMessageTimeout() const; + + void setSendMessageTimeout(int msec); + + QTcpSocket *getSocket(); + + + /* [2] --- */ + + + /* [3] Public methods */ + + bool connectToHost(); + + bool login(); + + bool login(const QString &user, const QString &password, AuthMethod method = AuthLogin); + + bool sendMail(MimeMessage &email); + + void quit(); + + + /* [3] --- */ + +protected: + + /* [4] Protected members */ + + QTcpSocket *socket; + + QString host; + int port; + ConnectionType connectionType; + QString name; + + QString user; + QString password; + AuthMethod authMethod; + + int connectionTimeout; + int responseTimeout; + int sendMessageTimeout; + + + QString responseText; + int responseCode; + + + class ResponseTimeoutException : public std::exception { + }; + + class SendMessageTimeoutException : public std::exception { + }; + + /* [4] --- */ + + + /* [5] Protected methods */ + + void waitForResponse(); + + void sendMessage(const QString &text); + + /* [5] --- */ + +protected slots: + + /* [6] Protected slots */ + + void socketStateChanged(QAbstractSocket::SocketState state); + + void socketError(QAbstractSocket::SocketError error); + + void socketReadyRead(); + + /* [6] --- */ + + +signals: + + /* [7] Signals */ + + void smtpError(SmtpClient::SmtpError e); + + /* [7] --- */ + +}; + +#endif // SMTPCLIENT_H diff --git a/src/smtp/smtpexports.h b/src/smtp/smtpexports.h new file mode 100644 index 00000000..4bad0da0 --- /dev/null +++ b/src/smtp/smtpexports.h @@ -0,0 +1,10 @@ +#ifndef SMTPEXPORTS_H +#define SMTPEXPORTS_H + +#ifdef SMTP_BUILD +#define SMTP_EXPORT +#else +#define SMTP_EXPORT +#endif + +#endif // SMTPEXPORTS_H diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index b6552227..b80da2ec 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -5,10 +5,17 @@ aux_source_directory(./keygen UI_SOURCE) aux_source_directory(./main_window UI_SOURCE) aux_source_directory(./help UI_SOURCE) aux_source_directory(./settings UI_SOURCE) +aux_source_directory(./function UI_SOURCE) + +if (SMTP_SUPPORT) + message(STATUS "Build SMTP Support") + aux_source_directory(./smtp UI_SOURCE) +endif () + add_library(gpgfrontend-ui STATIC ${UI_SOURCE}) target_link_libraries(gpgfrontend-ui Qt5::Network Qt5::PrintSupport Qt5::Widgets Qt5::Test Qt5::Core) -message(STATUS "UI SOURCE ${UI_SOURCE}")
\ No newline at end of file +target_compile_features(gpgfrontend-ui PUBLIC cxx_std_17)
\ No newline at end of file diff --git a/src/ui/FileEncryptionDialog.cpp b/src/ui/FileEncryptionDialog.cpp index 23ec0b2a..3e1e9b9a 100755 --- a/src/ui/FileEncryptionDialog.cpp +++ b/src/ui/FileEncryptionDialog.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -24,266 +24,249 @@ #include "ui/FileEncryptionDialog.h" -FileEncryptionDialog::FileEncryptionDialog(GpgME::GpgContext *ctx, QStringList keyList, DialogAction action, - QWidget *parent) - : QDialog(parent), mAction(action), mCtx(ctx){ +#include "gpg/function/BasicOperator.h" +#include "gpg/function/GpgKeyGetter.h" + +namespace GpgFrontend::UI { +FileEncryptionDialog::FileEncryptionDialog(KeyIdArgsListPtr keyList, + DialogAction action, QWidget* parent) + : QDialog(parent), mAction(action) { + if (mAction == Decrypt) { + setWindowTitle(_("Decrypt File")); + } else if (mAction == Encrypt) { + setWindowTitle(_("Encrypt File")); + } else if (mAction == Sign) { + setWindowTitle(_("Sign File")); + } else if (mAction == Verify) { + setWindowTitle(_("Verify File")); + } + + setModal(true); + + auto* buttonBox = + new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + connect(buttonBox, SIGNAL(accepted()), this, SLOT(slotExecuteAction())); + connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + + auto* groupBox1 = new QGroupBox(_("Input Parameters")); + + /* Setup input & Outputfileselection*/ + inputFileEdit = new QLineEdit(); + auto* fb1 = new QPushButton("Select"); + connect(fb1, SIGNAL(clicked()), this, SLOT(slotSelectInputFile())); + auto* fl1 = new QLabel(_("Target File")); + fl1->setBuddy(inputFileEdit); + + outputFileEdit = new QLineEdit(); + auto* fb2 = new QPushButton("Select"); + connect(fb2, SIGNAL(clicked()), this, SLOT(slotSelectOutputFile())); + auto* fl2 = new QLabel(_("Output File")); + fl2->setBuddy(outputFileEdit); + + auto* gLayout = new QGridLayout(); + gLayout->addWidget(fl1, 0, 0); + gLayout->addWidget(inputFileEdit, 0, 1); + gLayout->addWidget(fb1, 0, 2); + signFileEdit = new QLineEdit(); + // verify does not need outfile, but signature file + if (mAction != Verify) { + gLayout->addWidget(fl2, 1, 0); + gLayout->addWidget(outputFileEdit, 1, 1); + gLayout->addWidget(fb2, 1, 2); + } else { + auto* sfb1 = new QPushButton("Select"); + connect(sfb1, SIGNAL(clicked()), this, SLOT(slotSelectSignFile())); + auto* sfl1 = new QLabel(_("Signature File(.sig) Path")); + sfl1->setBuddy(signFileEdit); + + gLayout->addWidget(sfl1, 1, 0); + gLayout->addWidget(signFileEdit, 1, 1); + gLayout->addWidget(sfb1, 1, 2); + } + groupBox1->setLayout(gLayout); + + /*Setup KeyList*/ + mKeyList = new KeyList( + KeyListRow::ONLY_SECRET_KEY, + KeyListColumn::NAME | KeyListColumn::EmailAddress | KeyListColumn::Usage); + if (mAction == Verify) + mKeyList->setFilter([](const GpgKey& key) -> bool { + if (key.disabled() || key.expired() || key.revoked()) + return false; + else + return true; + }); + + if (mAction == Encrypt) + mKeyList->setFilter([](const GpgKey& key) -> bool { + if (!key.CanEncrActual()) + return false; + else + return true; + }); + + if (mAction == Sign) + mKeyList->setFilter([](const GpgKey& key) -> bool { + if (!key.CanSignActual()) + return false; + else + return true; + }); + + if (mAction == Decrypt) mKeyList->setDisabled(true); + + mKeyList->slotRefresh(); + mKeyList->setChecked(keyList); + + statusLabel = new QLabel(); + statusLabel->setStyleSheet("QLabel {color: red;}"); + + auto* vbox2 = new QVBoxLayout(); + vbox2->addWidget(groupBox1); + vbox2->addWidget(mKeyList); + vbox2->addWidget(statusLabel); + vbox2->addWidget(buttonBox); + vbox2->addStretch(0); + setLayout(vbox2); + + this->setMinimumWidth(480); + this->show(); +} - if (mAction == Decrypt) { - setWindowTitle(tr("Decrypt File")); - } else if (mAction == Encrypt) { - setWindowTitle(tr("Encrypt File")); +void FileEncryptionDialog::slotSelectInputFile() { + QString path; + if (inputFileEdit->text().size() > 0) { + path = QFileInfo(inputFileEdit->text()).absolutePath(); + } + + // QString infileName = QFileDialog::getOpenFileName(this, _("Open File"), + // path, _("Files") + _("All Files (*)")); + QString infileName = QFileDialog::getOpenFileName(this, _("Open File"), path); + inputFileEdit->setText(infileName); + + // try to find a matching output-filename, if not yet done + if (!infileName.isEmpty() && outputFileEdit->text().size() == 0 && + signFileEdit->text().size() == 0) { + if (mAction == Encrypt) { + outputFileEdit->setText(infileName + ".asc"); } else if (mAction == Sign) { - setWindowTitle(tr("Sign File")); + outputFileEdit->setText(infileName + ".sig"); } else if (mAction == Verify) { - setWindowTitle(tr("Verify File")); - } - - setModal(true); - - auto *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - connect(buttonBox, SIGNAL(accepted()), this, SLOT(slotExecuteAction())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); - - auto *groupBox1 = new QGroupBox(tr("Input Parameters")); - - /* Setup input & Outputfileselection*/ - inputFileEdit = new QLineEdit(); - auto *fb1 = new QPushButton("Select"); - connect(fb1, SIGNAL(clicked()), this, SLOT(slotSelectInputFile())); - auto *fl1 = new QLabel(tr("Target File")); - fl1->setBuddy(inputFileEdit); - - outputFileEdit = new QLineEdit(); - auto *fb2 = new QPushButton("Select"); - connect(fb2, SIGNAL(clicked()), this, SLOT(slotSelectOutputFile())); - auto *fl2 = new QLabel(tr("Output File")); - fl2->setBuddy(outputFileEdit); - - auto *gLayout = new QGridLayout(); - gLayout->addWidget(fl1, 0, 0); - gLayout->addWidget(inputFileEdit, 0, 1); - gLayout->addWidget(fb1, 0, 2); - signFileEdit = new QLineEdit(); - // verify does not need outfile, but signature file - if (mAction != Verify) { - gLayout->addWidget(fl2, 1, 0); - gLayout->addWidget(outputFileEdit, 1, 1); - gLayout->addWidget(fb2, 1, 2); + signFileEdit->setText(infileName + ".sig"); } else { - auto *sfb1 = new QPushButton("Select"); - connect(sfb1, SIGNAL(clicked()), this, SLOT(slotSelectSignFile())); - auto *sfl1 = new QLabel(tr("Signature File(.sig) Path")); - sfl1->setBuddy(signFileEdit); - - gLayout->addWidget(sfl1, 1, 0); - gLayout->addWidget(signFileEdit, 1, 1); - gLayout->addWidget(sfb1, 1, 2); - } - groupBox1->setLayout(gLayout); - - /*Setup KeyList*/ - mKeyList = new KeyList(mCtx, KeyListRow::ONLY_SECRET_KEY, - KeyListColumn::NAME | KeyListColumn::EmailAddress | KeyListColumn::Usage); - if(mAction == Verify) - mKeyList->setFilter([](const GpgKey &key) -> bool { - if(key.disabled || key.expired || key.revoked) return false; - else return true; - }); - - if(mAction == Encrypt) - mKeyList->setFilter([](const GpgKey &key) -> bool { - if(!GpgME::GpgContext::checkIfKeyCanEncr(key)) return false; - else return true; - }); - - if(mAction == Sign) - mKeyList->setFilter([](const GpgKey &key) -> bool { - if(!GpgME::GpgContext::checkIfKeyCanSign(key)) return false; - else return true; - }); - - if(mAction == Decrypt) - mKeyList->setDisabled(true); - - mKeyList->slotRefresh(); - mKeyList->setChecked(&keyList); - - statusLabel = new QLabel(); - statusLabel->setStyleSheet("QLabel {color: red;}"); - - auto *vbox2 = new QVBoxLayout(); - vbox2->addWidget(groupBox1); - vbox2->addWidget(mKeyList); - vbox2->addWidget(statusLabel); - vbox2->addWidget(buttonBox); - vbox2->addStretch(0); - setLayout(vbox2); - - this->setMinimumWidth(480); - this->show(); - -} - -void FileEncryptionDialog::slotSelectInputFile() { - QString path = ""; - if (inputFileEdit->text().size() > 0) { - path = QFileInfo(inputFileEdit->text()).absolutePath(); - } - -// QString infileName = QFileDialog::getOpenFileName(this, tr("Open File"), path, tr("Files") + tr("All Files (*)")); - QString infileName = QFileDialog::getOpenFileName(this, tr("Open File"), path); - inputFileEdit->setText(infileName); - - // try to find a matching output-filename, if not yet done - if (!infileName.isEmpty() - && outputFileEdit->text().size() == 0 - && signFileEdit->text().size() == 0) { - if (mAction == Encrypt) { - outputFileEdit->setText(infileName + ".asc"); - } else if (mAction == Sign) { - outputFileEdit->setText(infileName + ".sig"); - } else if (mAction == Verify) { - signFileEdit->setText(infileName + ".sig"); - } else { - if (infileName.endsWith(".asc", Qt::CaseInsensitive)) { - QString ofn = infileName; - ofn.chop(4); - outputFileEdit->setText(ofn); - } else { - outputFileEdit->setText(infileName + ".out"); - } - } + if (infileName.endsWith(".asc", Qt::CaseInsensitive)) { + QString ofn = infileName; + ofn.chop(4); + outputFileEdit->setText(ofn); + } else { + outputFileEdit->setText(infileName + ".out"); + } } + } } void FileEncryptionDialog::slotSelectOutputFile() { - QString path = ""; - if (outputFileEdit->text().size() > 0) { - path = QFileInfo(outputFileEdit->text()).absolutePath(); - } - - QString outfileName = QFileDialog::getSaveFileName(this, tr("Save File"), path, nullptr, nullptr, - QFileDialog::DontConfirmOverwrite); - outputFileEdit->setText(outfileName); - + QString path; + if (outputFileEdit->text().size() > 0) { + path = QFileInfo(outputFileEdit->text()).absolutePath(); + } + + QString outfileName = + QFileDialog::getSaveFileName(this, _("Save File"), path, nullptr, nullptr, + QFileDialog::DontConfirmOverwrite); + outputFileEdit->setText(outfileName); } void FileEncryptionDialog::slotSelectSignFile() { - QString path = ""; - if (signFileEdit->text().size() > 0) { - path = QFileInfo(signFileEdit->text()).absolutePath(); - } - - QString signfileName = QFileDialog::getSaveFileName(this, tr("Open File"), path, nullptr, nullptr, - QFileDialog::DontConfirmOverwrite); - signFileEdit->setText(signfileName); - - if (inputFileEdit->text().size() == 0 && signfileName.endsWith(".sig", Qt::CaseInsensitive)) { - QString sfn = signfileName; - sfn.chop(4); - inputFileEdit->setText(sfn); - } - + QString path; + if (signFileEdit->text().size() > 0) { + path = QFileInfo(signFileEdit->text()).absolutePath(); + } + + QString signfileName = + QFileDialog::getSaveFileName(this, _("Open File"), path, nullptr, nullptr, + QFileDialog::DontConfirmOverwrite); + signFileEdit->setText(signfileName); + + if (inputFileEdit->text().size() == 0 && + signfileName.endsWith(".sig", Qt::CaseInsensitive)) { + QString sfn = signfileName; + sfn.chop(4); + inputFileEdit->setText(sfn); + } } void FileEncryptionDialog::slotExecuteAction() { - - QFile infile; - infile.setFileName(inputFileEdit->text()); - if (!infile.open(QIODevice::ReadOnly)) { - statusLabel->setText(tr("Couldn't open file")); - inputFileEdit->setStyleSheet("QLineEdit { background: yellow }"); - return; - } - - QByteArray inBuffer = infile.readAll(); - auto *outBuffer = new QByteArray(); - infile.close(); - - QVector<GpgKey> keys; - mKeyList->getCheckedKeys(keys); - - qDebug() << "slotExecuteAction" << mAction; - - if (mAction == Encrypt) { - qDebug() << "Action Encrypt"; - gpgme_error_t err = mCtx->encrypt(keys, inBuffer, outBuffer, nullptr); - if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) { - qDebug() << "Error" << gpgme_strerror(err); - QMessageBox::warning(this, tr("Error"), - tr("Error Occurred During Encryption")); - return; - } - } - - if (mAction == Decrypt) { - qDebug() << "Action Decrypt"; - gpgme_error_t err = mCtx->decrypt(inBuffer, outBuffer, nullptr); - if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) { - qDebug() << "Error" << gpgme_strerror(err); - QMessageBox::warning(this, tr("Error"), - tr("Error Occurred During Decryption")); - return; - } + QFile infile; + infile.setFileName(inputFileEdit->text()); + if (!infile.open(QIODevice::ReadOnly)) { + statusLabel->setText(_("Couldn't open file")); + inputFileEdit->setStyleSheet("QLineEdit { background: yellow }"); + return; + } + auto in_data = read_all_data_in_file(inputFileEdit->text().toStdString()); + auto out_data = std::make_unique<ByteArray>(); + + auto key_ids = mKeyList->getChecked(); + auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids); + + if (mAction == Encrypt) { + qDebug() << "Action Encrypt"; + GpgEncrResult result = nullptr; + gpgme_error_t err = BasicOperator::GetInstance().Encrypt( + std::move(keys), in_data, out_data, result); + if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) { + qDebug() << "Error" << gpgme_strerror(err); + + QMessageBox::warning(this, _("Error"), + _("Error Occurred During Encryption")); + return; } - - if (mAction == Sign) { - qDebug() << "Action Sign"; - gpgme_error_t err = mCtx->sign(keys, inBuffer, outBuffer, GPGME_SIG_MODE_DETACH, nullptr); - if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) { - qDebug() << "Error" << gpgme_strerror(err); - QMessageBox::warning(this, tr("Error"), - tr("Error Occurred During Signature")); - return; - } + } + + else if (mAction == Decrypt) { + qDebug() << "Action Decrypt"; + GpgDecrResult result = nullptr; + gpgme_error_t err = + BasicOperator::GetInstance().Decrypt(in_data, out_data, result); + if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) { + qDebug() << "Error" << gpgme_strerror(err); + QMessageBox::warning(this, _("Error"), + _("Error Occurred During Decryption")); + return; } - - if (mAction == Verify) { - QFile sign_file; - sign_file.setFileName(signFileEdit->text()); - if (!sign_file.open(QIODevice::ReadOnly)) { - statusLabel->setText(tr("Couldn't open file")); - signFileEdit->setStyleSheet("QLineEdit { background: yellow }"); - return; - } - auto signBuffer = sign_file.readAll(); - gpgme_verify_result_t result; - auto error = mCtx->verify(&inBuffer, &signBuffer, &result); - new VerifyDetailsDialog(this, mCtx, mKeyList, error, result); - return; + } + + else if (mAction == Sign) { + qDebug() << "Action Sign"; + GpgSignResult result = nullptr; + gpgme_error_t err = BasicOperator::GetInstance().Sign( + std::move(keys), in_data, out_data, GPGME_SIG_MODE_DETACH, result); + if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) { + qDebug() << "Error" << gpgme_strerror(err); + QMessageBox::warning(this, _("Error"), + _("Error Occurred During Signature")); + return; } + } - QFile outfile(outputFileEdit->text()); - if (outfile.exists()) { - QMessageBox::StandardButton ret; - ret = QMessageBox::warning(this, tr("File"), - tr("File exists! Do you want to overwrite it?"), - QMessageBox::Ok | QMessageBox::Cancel); - if (ret == QMessageBox::Cancel) { - return; - } - } + if (mAction == Verify) { + auto sign_data = std::make_unique<ByteArray>( + read_all_data_in_file(signFileEdit->text().toStdString())); + GpgVerifyResult result = nullptr; + auto error = + BasicOperator::GetInstance().Verify(in_data, sign_data, result); + new VerifyDetailsDialog(this, mKeyList, error, std::move(result)); + return; + } - if (!outfile.open(QFile::WriteOnly)) { - QMessageBox::warning(this, tr("File"), - tr("Cannot write file %1:\n%2.") - .arg(outputFileEdit->text()) - .arg(outfile.errorString())); - return; - } + write_buffer_to_file(outputFileEdit->text().toStdString(), *out_data); - QDataStream out(&outfile); - out.writeRawData(outBuffer->data(), outBuffer->length()); - outfile.close(); - QMessageBox::information(nullptr, "Done", "Output saved to " + outputFileEdit->text()); - - accept(); + accept(); } -void FileEncryptionDialog::slotShowKeyList() { - mKeyList->show(); -} +void FileEncryptionDialog::slotShowKeyList() { mKeyList->show(); } -void FileEncryptionDialog::slotHideKeyList() { - mKeyList->hide(); -} +void FileEncryptionDialog::slotHideKeyList() { mKeyList->hide(); } + +} // namespace GpgFrontend::UI diff --git a/src/ui/FileEncryptionDialog.h b/src/ui/FileEncryptionDialog.h new file mode 100755 index 00000000..613f84e7 --- /dev/null +++ b/src/ui/FileEncryptionDialog.h @@ -0,0 +1,114 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef __FILEENCRYPTIONDIALOG_H__ +#define __FILEENCRYPTIONDIALOG_H__ + +#include "VerifyDetailsDialog.h" +#include "gpg/GpgContext.h" +#include "ui/GpgFrontendUI.h" +#include "ui/widgets/KeyList.h" + +namespace GpgFrontend::UI { + +/** + * @brief + * + * @class FileEncryptionDialog fileencryptiondialog.h "fileencryptiondialog.h" + */ +class FileEncryptionDialog : public QDialog { + Q_OBJECT + + public: + enum DialogAction { Encrypt, Decrypt, Sign, Verify }; + + /** + * @brief + * + * @fn FileEncryptionDialog + * @param ctx + * @param keyList + * @param parent + */ + FileEncryptionDialog(KeyIdArgsListPtr keyList, DialogAction action, + QWidget* parent = nullptr); + + public slots: + + /** + * @details + * + * @fn selectInputFile + */ + void slotSelectInputFile(); + + /** + * @brief + * + * @fn selectOutputFile + */ + void slotSelectOutputFile(); + + /** + * @brief + * + * @fn selectSignFile + */ + void slotSelectSignFile(); + + /** + * @brief + * + * @fn executeAction + */ + void slotExecuteAction(); + + /** + * @brief + * + * @fn hideKeyList + */ + void slotHideKeyList(); + + /** + * @brief + * + * @fn showKeyList + */ + void slotShowKeyList(); + + private: + QLineEdit* outputFileEdit; + QLineEdit* inputFileEdit; + QLineEdit* signFileEdit; + DialogAction mAction; + QLabel* statusLabel; + + protected: + KeyList* mKeyList; +}; + +} // namespace GpgFrontend::UI + +#endif // __FILEENCRYPTIONDIALOG_H__ diff --git a/src/ui/FindWidget.cpp b/src/ui/FindWidget.cpp index fce62223..6326b119 100644 --- a/src/ui/FindWidget.cpp +++ b/src/ui/FindWidget.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -24,135 +24,140 @@ #include "ui/FindWidget.h" -FindWidget::FindWidget(QWidget *parent, QTextEdit *edit) : - QWidget(parent) -{ - mTextpage = edit; - findEdit = new QLineEdit(this); - auto *closeButton= new QPushButton(this->style()->standardIcon(QStyle::SP_TitleBarCloseButton),"",this); - auto *nextButton= new QPushButton(QIcon(":button_next.png"), ""); - auto *previousButton= new QPushButton(QIcon(":button_previous.png"), ""); - - auto *notificationWidgetLayout = new QHBoxLayout(this); - notificationWidgetLayout->setContentsMargins(10,0,0,0); - notificationWidgetLayout->addWidget(new QLabel(tr("Find:"))); - notificationWidgetLayout->addWidget(findEdit,2); - notificationWidgetLayout->addWidget(nextButton); - notificationWidgetLayout->addWidget(previousButton); - notificationWidgetLayout->addWidget(closeButton); - - this->setLayout(notificationWidgetLayout); - connect(findEdit,SIGNAL(textEdited(QString)),this,SLOT(slotFind())); - connect(findEdit,SIGNAL(returnPressed()),this,SLOT(slotFindNext())); - connect(nextButton,SIGNAL(clicked()),this,SLOT(slotFindNext())); - connect(previousButton,SIGNAL(clicked()),this,SLOT(slotFindPrevious())); - connect(closeButton,SIGNAL(clicked()),this,SLOT(slotClose())); - - // The timer is necessary for setting the focus - QTimer::singleShot(0, findEdit, SLOT(setFocus())); +namespace GpgFrontend::UI { + +FindWidget::FindWidget(QWidget* parent, QTextEdit* edit) : QWidget(parent) { + mTextpage = edit; + findEdit = new QLineEdit(this); + auto* closeButton = new QPushButton( + this->style()->standardIcon(QStyle::SP_TitleBarCloseButton), QString(), + this); + auto* nextButton = new QPushButton(QIcon(":button_next.png"), QString()); + auto* previousButton = new QPushButton(QIcon(":button_previous.png"), ""); + + auto* notificationWidgetLayout = new QHBoxLayout(this); + notificationWidgetLayout->setContentsMargins(10, 0, 0, 0); + notificationWidgetLayout->addWidget(new QLabel(QString(_("Find")) + ": ")); + notificationWidgetLayout->addWidget(findEdit, 2); + notificationWidgetLayout->addWidget(nextButton); + notificationWidgetLayout->addWidget(previousButton); + notificationWidgetLayout->addWidget(closeButton); + + this->setLayout(notificationWidgetLayout); + connect(findEdit, SIGNAL(textEdited(QString)), this, SLOT(slotFind())); + connect(findEdit, SIGNAL(returnPressed()), this, SLOT(slotFindNext())); + connect(nextButton, SIGNAL(clicked()), this, SLOT(slotFindNext())); + connect(previousButton, SIGNAL(clicked()), this, SLOT(slotFindPrevious())); + connect(closeButton, SIGNAL(clicked()), this, SLOT(slotClose())); + + // The timer is necessary for setting the focus + QTimer::singleShot(0, findEdit, SLOT(setFocus())); } -void FindWidget::setBackground() -{ - QTextCursor cursor = mTextpage->textCursor(); - // if match is found set background of QLineEdit to white, otherwise to red - QPalette bgPalette( findEdit->palette() ); - - if (!findEdit->text().isEmpty() && mTextpage->document()->find(findEdit->text()).position() < 0 ) { - bgPalette.setColor( QPalette::Base, "#ececba"); - } else { - bgPalette.setColor( QPalette::Base, Qt::white); - } - findEdit->setPalette(bgPalette); +void FindWidget::setBackground() { + QTextCursor cursor = mTextpage->textCursor(); + // if match is found set background of QLineEdit to white, otherwise to red + QPalette bgPalette(findEdit->palette()); + + if (!findEdit->text().isEmpty() && + mTextpage->document()->find(findEdit->text()).position() < 0) { + bgPalette.setColor(QPalette::Base, "#ececba"); + } else { + bgPalette.setColor(QPalette::Base, Qt::white); + } + findEdit->setPalette(bgPalette); } -void FindWidget::slotFindNext() -{ - QTextCursor cursor = mTextpage->textCursor(); - cursor = mTextpage->document()->find(findEdit->text(), cursor, QTextDocument::FindCaseSensitively); - - // if end of document is reached, restart search from beginning - if (cursor.position() == -1) { - cursor = mTextpage->document()->find(findEdit->text(), cursor, QTextDocument::FindCaseSensitively); - } - - // cursor should not stay at -1, otherwise text is not editable - // todo: check how gedit handles this - if(cursor.position() != -1) { - mTextpage->setTextCursor(cursor); - } - this->setBackground(); +void FindWidget::slotFindNext() { + QTextCursor cursor = mTextpage->textCursor(); + cursor = mTextpage->document()->find(findEdit->text(), cursor, + QTextDocument::FindCaseSensitively); + + // if end of document is reached, restart search from beginning + if (cursor.position() == -1) { + cursor = mTextpage->document()->find(findEdit->text(), cursor, + QTextDocument::FindCaseSensitively); + } + + // cursor should not stay at -1, otherwise text is not editable + // todo: check how gedit handles this + if (cursor.position() != -1) { + mTextpage->setTextCursor(cursor); + } + this->setBackground(); } -void FindWidget::slotFind() -{ - QTextCursor cursor = mTextpage->textCursor(); - - if (cursor.anchor() == -1) { - cursor = mTextpage->document()->find(findEdit->text(), cursor, QTextDocument::FindCaseSensitively); - } else { - cursor = mTextpage->document()->find(findEdit->text(), cursor.anchor(), QTextDocument::FindCaseSensitively); - } - - // if end of document is reached, restart search from beginning - if (cursor.position() == -1) { - cursor = mTextpage->document()->find(findEdit->text(), cursor, QTextDocument::FindCaseSensitively); - } - - // cursor should not stay at -1, otherwise text is not editable - // todo: check how gedit handles this - if(cursor.position() != -1) { - mTextpage->setTextCursor(cursor); - } - this->setBackground(); +void FindWidget::slotFind() { + QTextCursor cursor = mTextpage->textCursor(); + + if (cursor.anchor() == -1) { + cursor = mTextpage->document()->find(findEdit->text(), cursor, + QTextDocument::FindCaseSensitively); + } else { + cursor = mTextpage->document()->find(findEdit->text(), cursor.anchor(), + QTextDocument::FindCaseSensitively); + } + + // if end of document is reached, restart search from beginning + if (cursor.position() == -1) { + cursor = mTextpage->document()->find(findEdit->text(), cursor, + QTextDocument::FindCaseSensitively); + } + + // cursor should not stay at -1, otherwise text is not editable + // todo: check how gedit handles this + if (cursor.position() != -1) { + mTextpage->setTextCursor(cursor); + } + this->setBackground(); } -void FindWidget::slotFindPrevious() -{ - QTextDocument::FindFlags flags; - flags |= QTextDocument::FindBackward; - flags |= QTextDocument::FindCaseSensitively; - - QTextCursor cursor = mTextpage->textCursor(); - cursor = mTextpage->document()->find(findEdit->text(), cursor, flags); - - // if begin of document is reached, restart search from end - if (cursor.position() == -1) { - cursor = mTextpage->document()->find(findEdit->text(), QTextCursor::End, flags); - } - - // cursor should not stay at -1, otherwise text is not editable - // todo: check how gedit handles this - if(cursor.position() != -1) { - mTextpage->setTextCursor(cursor); - } - this->setBackground(); +void FindWidget::slotFindPrevious() { + QTextDocument::FindFlags flags; + flags |= QTextDocument::FindBackward; + flags |= QTextDocument::FindCaseSensitively; + + QTextCursor cursor = mTextpage->textCursor(); + cursor = mTextpage->document()->find(findEdit->text(), cursor, flags); + + // if begin of document is reached, restart search from end + if (cursor.position() == -1) { + cursor = + mTextpage->document()->find(findEdit->text(), QTextCursor::End, flags); + } + + // cursor should not stay at -1, otherwise text is not editable + // todo: check how gedit handles this + if (cursor.position() != -1) { + mTextpage->setTextCursor(cursor); + } + this->setBackground(); } -void FindWidget::keyPressEvent( QKeyEvent* e ) -{ - switch ( e->key() ) - { +void FindWidget::keyPressEvent(QKeyEvent* e) { + switch (e->key()) { case Qt::Key_Escape: - this->slotClose(); - break; + this->slotClose(); + break; case Qt::Key_F3: - if (e->modifiers() & Qt::ShiftModifier) { - this->slotFindPrevious(); - } else { - this->slotFindNext(); - } - break; - } + if (e->modifiers() & Qt::ShiftModifier) { + this->slotFindPrevious(); + } else { + this->slotFindNext(); + } + break; + } } void FindWidget::slotClose() { - QTextCursor cursor = mTextpage->textCursor(); - - if ( cursor.position() == -1) { - cursor.setPosition(0); - mTextpage->setTextCursor(cursor); - } - mTextpage->setFocus(); - close(); + QTextCursor cursor = mTextpage->textCursor(); + + if (cursor.position() == -1) { + cursor.setPosition(0); + mTextpage->setTextCursor(cursor); + } + mTextpage->setFocus(); + close(); } + +} // namespace GpgFrontend::UI diff --git a/src/ui/FindWidget.h b/src/ui/FindWidget.h new file mode 100644 index 00000000..e4cbdaab --- /dev/null +++ b/src/ui/FindWidget.h @@ -0,0 +1,72 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef FINDWIDGET_H +#define FINDWIDGET_H + +#include "ui/GpgFrontendUI.h" +#include "ui/widgets/EditorPage.h" + +namespace GpgFrontend::UI { + +/** + * @brief Class for handling the find widget shown at buttom of a textedit-page + */ +class FindWidget : public QWidget { + Q_OBJECT + + public: + /** + * @brief + * + * @param parent The parent widget + */ + explicit FindWidget(QWidget* parent, QTextEdit* edit); + + private: + void keyPressEvent(QKeyEvent* e) override; + + /** + * @details Set background of findEdit to red, if no match is found (Documents + * textcursor position equals -1), otherwise set it to white. + */ + void setBackground(); + + QTextEdit* mTextpage; /** Textedit associated to the notification */ + QLineEdit* findEdit; /** Label holding the text shown in infoBoard */ + + private slots: + + void slotFindNext(); + + void slotFindPrevious(); + + void slotFind(); + + void slotClose(); +}; + +} // namespace GpgFrontend::UI + +#endif // FINDWIDGET_H diff --git a/src/ui/GpgFrontendUI.h b/src/ui/GpgFrontendUI.h new file mode 100644 index 00000000..01f82822 --- /dev/null +++ b/src/ui/GpgFrontendUI.h @@ -0,0 +1,53 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_GPGFRONTENDUI_H +#define GPGFRONTEND_GPGFRONTENDUI_H + +#include "GpgFrontend.h" + +#include <QtCore> +#include <QtNetwork> +#include <QtPrintSupport> +#include <QtWidgets> + +#undef LIBCONFIGXX_STATIC +#define LIBCONFIGXX_STATIC +#include <libconfig.h++> + +/** + * Resources File(s) Path Vars + */ +#if defined(MACOS) && defined(RELEASE) +#define RESOURCE_DIR(appDir) (appDir + "/../Resources/") +#define RESOURCE_DIR_BOOST_PATH(appDir) (appDir / ".." / "Resources") +#elif defined(LINUX) && defined(RELEASE) +#define RESOURCE_DIR(appDir) (appDir + "/../share/") +#define RESOURCE_DIR_BOOST_PATH(appDir) (appDir / ".." / "share") +#else +#define RESOURCE_DIR(appDir) (appDir) +#define RESOURCE_DIR_BOOST_PATH(appDir) (appDir) +#endif + +#endif // GPGFRONTEND_GPGFRONTENDUI_H diff --git a/src/ui/KeyImportDetailDialog.cpp b/src/ui/KeyImportDetailDialog.cpp index 8d303886..48d1e9ee 100644 --- a/src/ui/KeyImportDetailDialog.cpp +++ b/src/ui/KeyImportDetailDialog.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -22,145 +22,177 @@ * */ -#include <ui/KeyImportDetailDialog.h> +#include "ui/KeyImportDetailDialog.h" -KeyImportDetailDialog::KeyImportDetailDialog(GpgME::GpgContext *ctx, GpgImportInformation result, bool automatic, - QWidget *parent) - : QDialog(parent), mCtx(ctx), mResult(std::move(result)) { +#include "gpg/function/GpgKeyGetter.h" - // If no key for import found, just show a message - if (mResult.considered == 0) { - if(automatic) - QMessageBox::information(nullptr, tr("Key Update Details"), tr("No keys found")); - else - QMessageBox::information(nullptr, tr("Key Import Details"), tr("No keys found to import")); - return; - } - - auto *mvbox = new QVBoxLayout(); +namespace GpgFrontend::UI { +KeyImportDetailDialog::KeyImportDetailDialog(GpgImportInformation result, + bool automatic, QWidget* parent) + : QDialog(parent), mResult(std::move(result)) { + // If no key for import found, just show a message + if (mResult.considered == 0) { + if (automatic) + QMessageBox::information(parent, _("Key Update Details"), + _("No keys found")); + else + QMessageBox::information(parent, _("Key Import Details"), + _("No keys found to import")); + emit finished(0); + this->close(); + this->deleteLater(); + } else { + auto* mv_box = new QVBoxLayout(); this->createGeneralInfoBox(); - mvbox->addWidget(generalInfoBox); + mv_box->addWidget(generalInfoBox); this->createKeysTable(); - mvbox->addWidget(keysTable); + mv_box->addWidget(keysTable); this->createButtonBox(); - mvbox->addWidget(buttonBox); + mv_box->addWidget(buttonBox); - this->setLayout(mvbox); - if(automatic) - this->setWindowTitle(tr("Key Update Details")); + this->setLayout(mv_box); + if (automatic) + this->setWindowTitle(_("Key Update Details")); else - this->setWindowTitle(tr("Key Import Details")); + this->setWindowTitle(_("Key Import Details")); + auto pos = QPoint(100, 100); + LOG(INFO) << "parent" << parent; + if (parent) pos += parent->pos(); + this->move(pos); this->resize(QSize(600, 300)); this->setModal(true); - this->exec(); + this->show(); + } } void KeyImportDetailDialog::createGeneralInfoBox() { - // GridBox for general import information - generalInfoBox = new QGroupBox(tr("General key info")); - auto *generalInfoBoxLayout = new QGridLayout(generalInfoBox); - - generalInfoBoxLayout->addWidget(new QLabel(tr("Considered:")), 1, 0); - generalInfoBoxLayout->addWidget(new QLabel(QString::number(mResult.considered)), 1, 1); - int row = 2; - if (mResult.unchanged != 0) { - generalInfoBoxLayout->addWidget(new QLabel(tr("Public unchanged:")), row, 0); - generalInfoBoxLayout->addWidget(new QLabel(QString::number(mResult.unchanged)), row, 1); - row++; - } - if (mResult.imported != 0) { - generalInfoBoxLayout->addWidget(new QLabel(tr("Imported:")), row, 0); - generalInfoBoxLayout->addWidget(new QLabel(QString::number(mResult.imported)), row, 1); - row++; - } - if (mResult.not_imported != 0) { - generalInfoBoxLayout->addWidget(new QLabel(tr("Not imported:")), row, 0); - generalInfoBoxLayout->addWidget(new QLabel(QString::number(mResult.not_imported)), row, 1); - row++; - } - if (mResult.secret_read != 0) { - generalInfoBoxLayout->addWidget(new QLabel(tr("Private read:")), row, 0); - generalInfoBoxLayout->addWidget(new QLabel(QString::number(mResult.secret_read)), row, 1); - row++; - } - if (mResult.secret_imported != 0) { - generalInfoBoxLayout->addWidget(new QLabel(tr("Private imported:")), row, 0); - generalInfoBoxLayout->addWidget(new QLabel(QString::number(mResult.secret_imported)), row, 1); - row++; - } - if (mResult.secret_unchanged != 0) { - generalInfoBoxLayout->addWidget(new QLabel(tr("Private unchanged:")), row, 0); - generalInfoBoxLayout->addWidget(new QLabel(QString::number(mResult.secret_unchanged)), row, 1); - row++; - } + // GridBox for general import information + generalInfoBox = new QGroupBox(_("General key info")); + auto* generalInfoBoxLayout = new QGridLayout(generalInfoBox); + + generalInfoBoxLayout->addWidget(new QLabel(QString(_("Considered")) + ": "), + 1, 0); + generalInfoBoxLayout->addWidget( + new QLabel(QString::number(mResult.considered)), 1, 1); + int row = 2; + if (mResult.unchanged != 0) { + generalInfoBoxLayout->addWidget( + new QLabel(QString(_("Public unchanged")) + ": "), row, 0); + generalInfoBoxLayout->addWidget( + new QLabel(QString::number(mResult.unchanged)), row, 1); + row++; + } + if (mResult.imported != 0) { + generalInfoBoxLayout->addWidget(new QLabel(QString(_("Imported")) + ": "), + row, 0); + generalInfoBoxLayout->addWidget( + new QLabel(QString::number(mResult.imported)), row, 1); + row++; + } + if (mResult.not_imported != 0) { + generalInfoBoxLayout->addWidget( + new QLabel(QString(_("Not Imported")) + ": "), row, 0); + generalInfoBoxLayout->addWidget( + new QLabel(QString::number(mResult.not_imported)), row, 1); + row++; + } + if (mResult.secret_read != 0) { + generalInfoBoxLayout->addWidget( + new QLabel(QString(_("Private Read")) + ": "), row, 0); + generalInfoBoxLayout->addWidget( + new QLabel(QString::number(mResult.secret_read)), row, 1); + row++; + } + if (mResult.secret_imported != 0) { + generalInfoBoxLayout->addWidget( + new QLabel(QString(_("Private Imported")) + ": "), row, 0); + generalInfoBoxLayout->addWidget( + new QLabel(QString::number(mResult.secret_imported)), row, 1); + row++; + } + if (mResult.secret_unchanged != 0) { + generalInfoBoxLayout->addWidget( + new QLabel(QString(_("Private Unchanged")) + ": "), row, 0); + generalInfoBoxLayout->addWidget( + new QLabel(QString::number(mResult.secret_unchanged)), row, 1); + row++; + } } void KeyImportDetailDialog::createKeysTable() { - keysTable = new QTableWidget(this); - keysTable->setRowCount(0); - keysTable->setColumnCount(4); - keysTable->setEditTriggers(QAbstractItemView::NoEditTriggers); - // Nothing is selectable - keysTable->setSelectionMode(QAbstractItemView::NoSelection); - - QStringList headerLabels; - headerLabels << tr("Name") << tr("Email") << tr("Status") << tr("Fingerprint"); - keysTable->verticalHeader()->hide(); - - keysTable->setHorizontalHeaderLabels(headerLabels); - int row = 0; - for (const auto &impKey : mResult.importedKeys) { - keysTable->setRowCount(row + 1); - GpgKey key = mCtx->getKeyByFpr(impKey.fpr); - if(!key.good) continue; - keysTable->setItem(row, 0, new QTableWidgetItem(key.name)); - keysTable->setItem(row, 1, new QTableWidgetItem(key.email)); - keysTable->setItem(row, 2, new QTableWidgetItem(getStatusString(impKey.importStatus))); - keysTable->setItem(row, 3, new QTableWidgetItem(impKey.fpr)); - row++; - } - keysTable->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents); - keysTable->horizontalHeader()->setStretchLastSection(true); - keysTable->resizeColumnsToContents(); + LOG(INFO) << "KeyImportDetailDialog::createKeysTable() Called"; + + keysTable = new QTableWidget(this); + keysTable->setRowCount(0); + keysTable->setColumnCount(4); + keysTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + // Nothing is selectable + keysTable->setSelectionMode(QAbstractItemView::NoSelection); + + QStringList headerLabels; + headerLabels << _("Name") << _("Email") << _("Status") << _("Fingerprint"); + keysTable->verticalHeader()->hide(); + + keysTable->setHorizontalHeaderLabels(headerLabels); + int row = 0; + for (const auto& imp_key : mResult.importedKeys) { + keysTable->setRowCount(row + 1); + GpgKey key = GpgKeyGetter::GetInstance().GetKey(imp_key.fpr); + if (!key.good()) continue; + keysTable->setItem( + row, 0, new QTableWidgetItem(QString::fromStdString(key.name()))); + keysTable->setItem( + row, 1, new QTableWidgetItem(QString::fromStdString(key.email()))); + keysTable->setItem( + row, 2, new QTableWidgetItem(getStatusString(imp_key.import_status))); + keysTable->setItem( + row, 3, new QTableWidgetItem(QString::fromStdString(imp_key.fpr))); + row++; + } + keysTable->horizontalHeader()->setSectionResizeMode( + 0, QHeaderView::ResizeToContents); + keysTable->horizontalHeader()->setStretchLastSection(true); + keysTable->resizeColumnsToContents(); } QString KeyImportDetailDialog::getStatusString(int keyStatus) { - QString statusString; - // keystatus is greater than 15, if key is private - if (keyStatus > 15) { - statusString.append(tr("private")); - keyStatus = keyStatus - 16; - } else { - statusString.append(tr("public")); - } - if (keyStatus == 0) { - statusString.append(", " + tr("unchanged")); + QString statusString; + // keystatus is greater than 15, if key is private + if (keyStatus > 15) { + statusString.append(_("Private")); + keyStatus = keyStatus - 16; + } else { + statusString.append(_("Public")); + } + if (keyStatus == 0) { + statusString.append(", " + QString(_("Unchanged"))); + } else { + if (keyStatus == 1) { + statusString.append(", " + QString(_("New Key"))); } else { - if (keyStatus == 1) { - statusString.append(", " + tr("new key")); - } else { - if (keyStatus > 7) { - statusString.append(", " + tr("new subkey")); - keyStatus = keyStatus - 8; - } - if (keyStatus > 3) { - statusString.append(", " + tr("new signature")); - keyStatus = keyStatus - 4; - } - if (keyStatus > 1) { - statusString.append(", " + tr("new uid")); - keyStatus = keyStatus - 2; - } - } + if (keyStatus > 7) { + statusString.append(", " + QString(_("New Subkey"))); + keyStatus = keyStatus - 8; + } + if (keyStatus > 3) { + statusString.append(", " + QString(_("New Signature"))); + keyStatus = keyStatus - 4; + } + if (keyStatus > 1) { + statusString.append(", " + QString(_("New UID"))); + keyStatus = keyStatus - 2; + } } - return statusString; + } + return statusString; } void KeyImportDetailDialog::createButtonBox() { - buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok); - connect(buttonBox, SIGNAL(accepted()), this, SLOT(close())); + buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok); + connect(buttonBox, SIGNAL(accepted()), this, SLOT(close())); } +} // namespace GpgFrontend::UI diff --git a/src/ui/KeyImportDetailDialog.h b/src/ui/KeyImportDetailDialog.h new file mode 100644 index 00000000..fe63baaa --- /dev/null +++ b/src/ui/KeyImportDetailDialog.h @@ -0,0 +1,55 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef __KEYIMPORTDETAILSDIALOG_H__ +#define __KEYIMPORTDETAILSDIALOG_H__ + +#include <gpg/function/GpgKeyImportExportor.h> + +#include "gpg/GpgContext.h" +#include "ui/GpgFrontendUI.h" + +namespace GpgFrontend::UI { +class KeyImportDetailDialog : public QDialog { + Q_OBJECT + + public: + KeyImportDetailDialog(GpgImportInformation result, bool automatic, + QWidget* parent = nullptr); + + private: + void createGeneralInfoBox(); + void createKeysTable(); + void createButtonBox(); + static QString getStatusString(int keyStatus); + + QTableWidget* keysTable{}; + QGroupBox* generalInfoBox{}; + QGroupBox* keyInfoBox{}; + QDialogButtonBox* buttonBox{}; + GpgImportInformation mResult; +}; +} // namespace GpgFrontend::UI + +#endif // __KEYIMPORTDETAILSDIALOG_H__ diff --git a/src/ui/KeyMgmt.cpp b/src/ui/KeyMgmt.cpp index 77f3b760..7459906d 100755 --- a/src/ui/KeyMgmt.cpp +++ b/src/ui/KeyMgmt.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -26,331 +26,384 @@ #include <utility> -KeyMgmt::KeyMgmt(GpgME::GpgContext *ctx, QWidget *parent) : - QMainWindow(parent), appPath(qApp->applicationDirPath()), - settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", QSettings::IniFormat) { - mCtx = ctx; +#include "gpg/function/GpgKeyGetter.h" +#include "gpg/function/GpgKeyImportExportor.h" +#include "gpg/function/GpgKeyOpera.h" +#include "ui/SignalStation.h" +#include "ui/UserInterfaceUtils.h" +#include "ui/settings/GlobalSettingStation.h" + +namespace GpgFrontend::UI { +KeyMgmt::KeyMgmt(QWidget* parent) : QMainWindow(parent) { + /* the list of Keys available*/ + mKeyList = new KeyList(); + mKeyList->setColumnWidth(2, 250); + mKeyList->setColumnWidth(3, 250); + setCentralWidget(mKeyList); + mKeyList->setDoubleClickedAction([this](const GpgKey& key, QWidget* parent) { + new KeyDetailsDialog(key, parent); + }); + + createActions(); + createMenus(); + createToolBars(); + connect(this, SIGNAL(signalStatusBarChanged(QString)), this->parent(), + SLOT(slotSetStatusBarText(QString))); + + auto& settings = GlobalSettingStation::GetInstance().GetUISettings(); + + try { + int width = settings.lookup("window.icon_size.width"); + int height = settings.lookup("window.icon_size.height"); + + this->setIconSize(QSize(width, height)); + + } catch (...) { + LOG(ERROR) << _("Setting Operation Error") << _("icon_size"); + } + + // icon_style + try { + int s_icon_style = settings.lookup("window.icon_style"); + auto icon_style = static_cast<Qt::ToolButtonStyle>(s_icon_style); + this->setToolButtonStyle(icon_style); + } catch (...) { + LOG(ERROR) << _("Setting Operation Error") << _("icon_style"); + } + + auto pos = QPoint(50, 50); + LOG(INFO) << "parent" << parent; + if (parent) pos += parent->pos(); + LOG(INFO) << "pos default" << pos.x() << pos.y(); + auto size = QSize(900, 600); + + try { + int x, y, width, height; + x = settings.lookup("window.key_management.position.x"); + y = settings.lookup("window.key_management.position.y"); + width = settings.lookup("window.key_management.size.width"); + height = settings.lookup("window.key_management.size.height"); + pos = QPoint(x, y); + size = QSize(width, height); + + std::string window_state = + settings.lookup("window.key_management.window_state"); - /* the list of Keys available*/ - mKeyList = new KeyList(mCtx); - mKeyList->setColumnWidth(2, 250); - mKeyList->setColumnWidth(3, 250); - setCentralWidget(mKeyList); - mKeyList->setDoubleClickedAction([this](const GpgKey &key, QWidget *parent) { - new KeyDetailsDialog(mCtx, key, parent); - }); - - createActions(); - createMenus(); - createToolBars(); - connect(this, SIGNAL(signalStatusBarChanged(QString)), this->parent(), SLOT(slotSetStatusBarText(QString))); + // state sets pos & size of dock-widgets + this->restoreState( + QByteArray::fromBase64(QByteArray::fromStdString(window_state))); - /* Restore the iconstyle */ - this->settings.sync(); + } catch (...) { + LOG(WARNING) << "cannot read pos or size from settings"; + } - QSize iconSize = settings.value("toolbar/iconsize", QSize(24, 24)).toSize(); - settings.setValue("toolbar/iconsize", iconSize); + this->resize(size); + this->move(pos); - Qt::ToolButtonStyle buttonStyle = static_cast<Qt::ToolButtonStyle>(settings.value("toolbar/iconstyle", - Qt::ToolButtonTextUnderIcon).toUInt()); - this->setIconSize(iconSize); - this->setToolButtonStyle(buttonStyle); + setWindowTitle(_("KeyPair Management")); + mKeyList->addMenuAction(deleteSelectedKeysAct); + mKeyList->addMenuAction(showKeyDetailsAct); - // state sets pos & size of dock-widgets - this->restoreState(this->settings.value("keymgmt/windowState").toByteArray()); - - qDebug() << "windows/windowSave" << this->settings.value("window/windowSave").toBool(); - - // Restore window size & location - if (this->settings.value("keymgmt/setWindowSize").toBool()) { - QPoint pos = settings.value("keymgmt/pos", QPoint(100, 100)).toPoint(); - QSize size = settings.value("keymgmt/size", QSize(900, 600)).toSize(); - qDebug() << "Settings size" << size << "pos" << pos; - this->setMinimumSize(size); - this->move(pos); - } else { - qDebug() << "Use default min windows size and pos"; - QPoint defaultPoint(100, 100); - QSize defaultMinSize(900, 600); - this->setMinimumSize(defaultMinSize); - this->move(defaultPoint); - this->settings.setValue("keymgmt/pos", defaultPoint); - this->settings.setValue("keymgmt/size", defaultMinSize); - this->settings.setValue("keymgmt/setWindowSize", true); - } - - setWindowTitle(tr("Key Pair Management")); - mKeyList->addMenuAction(deleteSelectedKeysAct); - mKeyList->addMenuAction(showKeyDetailsAct); + connect(this, SIGNAL(signalKeyStatusUpdated()), SignalStation::GetInstance(), + SIGNAL(KeyDatabaseRefresh())); } void KeyMgmt::createActions() { - openKeyFileAct = new QAction(tr("&Open"), this); - openKeyFileAct->setShortcut(tr("Ctrl+O")); - openKeyFileAct->setToolTip(tr("Open Key File")); - connect(openKeyFileAct, SIGNAL(triggered()), this, SLOT(slotImportKeyFromFile())); - - closeAct = new QAction(tr("&Close"), this); - closeAct->setShortcut(tr("Ctrl+Q")); - closeAct->setIcon(QIcon(":exit.png")); - closeAct->setToolTip(tr("Close")); - connect(closeAct, SIGNAL(triggered()), this, SLOT(close())); - - generateKeyPairAct = new QAction(tr("New Keypair"), this); - generateKeyPairAct->setShortcut(tr("Ctrl+N")); - generateKeyPairAct->setIcon(QIcon(":key_generate.png")); - generateKeyPairAct->setToolTip(tr("Generate KeyPair")); - connect(generateKeyPairAct, SIGNAL(triggered()), this, SLOT(slotGenerateKeyDialog())); - - generateSubKeyAct = new QAction(tr("New Subkey"), this); - generateSubKeyAct->setShortcut(tr("Ctrl+Shift+N")); - generateSubKeyAct->setIcon(QIcon(":key_generate.png")); - generateSubKeyAct->setToolTip(tr("Generate Subkey For Selected KeyPair")); - connect(generateSubKeyAct, SIGNAL(triggered()), this, SLOT(slotGenerateSubKey())); - - importKeyFromFileAct = new QAction(tr("&File"), this); - importKeyFromFileAct->setIcon(QIcon(":import_key_from_file.png")); - importKeyFromFileAct->setToolTip(tr("Import New Key From File")); - connect(importKeyFromFileAct, SIGNAL(triggered()), this, SLOT(slotImportKeyFromFile())); - - importKeyFromClipboardAct = new QAction(tr("&Clipboard"), this); - importKeyFromClipboardAct->setIcon(QIcon(":import_key_from_clipboard.png")); - importKeyFromClipboardAct->setToolTip(tr("Import New Key From Clipboard")); - connect(importKeyFromClipboardAct, SIGNAL(triggered()), this, SLOT(slotImportKeyFromClipboard())); - - importKeyFromKeyServerAct = new QAction(tr("&Keyserver"), this); - importKeyFromKeyServerAct->setIcon(QIcon(":import_key_from_server.png")); - importKeyFromKeyServerAct->setToolTip(tr("Import New Key From Keyserver")); - connect(importKeyFromKeyServerAct, SIGNAL(triggered()), this, SLOT(slotImportKeyFromKeyServer())); - - exportKeyToClipboardAct = new QAction(tr("Export To &Clipboard"), this); - exportKeyToClipboardAct->setIcon(QIcon(":export_key_to_clipboard.png")); - exportKeyToClipboardAct->setToolTip(tr("Export Selected Key(s) To Clipboard")); - connect(exportKeyToClipboardAct, SIGNAL(triggered()), this, SLOT(slotExportKeyToClipboard())); - - exportKeyToFileAct = new QAction(tr("Export To &File"), this); - exportKeyToFileAct->setIcon(QIcon(":export_key_to_file.png")); - exportKeyToFileAct->setToolTip(tr("Export Selected Key(s) To File")); - connect(exportKeyToFileAct, SIGNAL(triggered()), this, SLOT(slotExportKeyToFile())); - - deleteSelectedKeysAct = new QAction(tr("Delete Selected Key(s)"), this); - deleteSelectedKeysAct->setToolTip(tr("Delete the Selected keys")); - connect(deleteSelectedKeysAct, SIGNAL(triggered()), this, SLOT(slotDeleteSelectedKeys())); - - deleteCheckedKeysAct = new QAction(tr("Delete Checked Key(s)"), this); - deleteCheckedKeysAct->setToolTip(tr("Delete the Checked keys")); - deleteCheckedKeysAct->setIcon(QIcon(":button_delete.png")); - connect(deleteCheckedKeysAct, SIGNAL(triggered()), this, SLOT(slotDeleteCheckedKeys())); - - showKeyDetailsAct = new QAction(tr("Show Key Details"), this); - showKeyDetailsAct->setToolTip(tr("Show Details for this Key")); - connect(showKeyDetailsAct, SIGNAL(triggered()), this, SLOT(slotShowKeyDetails())); + openKeyFileAct = new QAction(_("Open"), this); + openKeyFileAct->setShortcut(QKeySequence(_("Ctrl+O"))); + openKeyFileAct->setToolTip(_("Open Key File")); + connect(importKeyFromFileAct, &QAction::triggered, this, + [&]() { CommonUtils::GetInstance()->slotImportKeyFromFile(this); }); + + closeAct = new QAction(_("Close"), this); + closeAct->setShortcut(QKeySequence(_("Ctrl+Q"))); + closeAct->setIcon(QIcon(":exit.png")); + closeAct->setToolTip(_("Close")); + connect(closeAct, SIGNAL(triggered()), this, SLOT(close())); + + generateKeyPairAct = new QAction(_("New Keypair"), this); + generateKeyPairAct->setShortcut(QKeySequence(_("Ctrl+N"))); + generateKeyPairAct->setIcon(QIcon(":key_generate.png")); + generateKeyPairAct->setToolTip(_("Generate KeyPair")); + connect(generateKeyPairAct, SIGNAL(triggered()), this, + SLOT(slotGenerateKeyDialog())); + + generateSubKeyAct = new QAction(_("New Subkey"), this); + generateSubKeyAct->setShortcut(QKeySequence(_("Ctrl+Shift+N"))); + generateSubKeyAct->setIcon(QIcon(":key_generate.png")); + generateSubKeyAct->setToolTip(_("Generate Subkey For Selected KeyPair")); + connect(generateSubKeyAct, SIGNAL(triggered()), this, + SLOT(slotGenerateSubKey())); + + importKeyFromFileAct = new QAction(_("File"), this); + importKeyFromFileAct->setIcon(QIcon(":import_key_from_file.png")); + importKeyFromFileAct->setToolTip(_("Import New Key From File")); + connect(importKeyFromFileAct, &QAction::triggered, this, + [&]() { CommonUtils::GetInstance()->slotImportKeyFromFile(this); }); + + importKeyFromClipboardAct = new QAction(_("Clipboard"), this); + importKeyFromClipboardAct->setIcon(QIcon(":import_key_from_clipboard.png")); + importKeyFromClipboardAct->setToolTip(_("Import New Key From Clipboard")); + connect(importKeyFromClipboardAct, &QAction::triggered, this, [&]() { + CommonUtils::GetInstance()->slotImportKeyFromClipboard(this); + }); + + importKeyFromKeyServerAct = new QAction(_("Keyserver"), this); + importKeyFromKeyServerAct->setIcon(QIcon(":import_key_from_server.png")); + importKeyFromKeyServerAct->setToolTip(_("Import New Key From Keyserver")); + connect(importKeyFromKeyServerAct, &QAction::triggered, this, [&]() { + CommonUtils::GetInstance()->slotImportKeyFromKeyServer(this); + }); + + exportKeyToClipboardAct = new QAction(_("Export To Clipboard"), this); + exportKeyToClipboardAct->setIcon(QIcon(":export_key_to_clipboard.png")); + exportKeyToClipboardAct->setToolTip(_("Export Selected Key(s) To Clipboard")); + connect(exportKeyToClipboardAct, SIGNAL(triggered()), this, + SLOT(slotExportKeyToClipboard())); + + exportKeyToFileAct = new QAction(_("Export To File"), this); + exportKeyToFileAct->setIcon(QIcon(":export_key_to_file.png")); + exportKeyToFileAct->setToolTip(_("Export Selected Key(s) To File")); + connect(exportKeyToFileAct, SIGNAL(triggered()), this, + SLOT(slotExportKeyToFile())); + + deleteSelectedKeysAct = new QAction(_("Delete Selected Key(s)"), this); + deleteSelectedKeysAct->setToolTip(_("Delete the Selected keys")); + connect(deleteSelectedKeysAct, SIGNAL(triggered()), this, + SLOT(slotDeleteSelectedKeys())); + + deleteCheckedKeysAct = new QAction(_("Delete Checked Key(s)"), this); + deleteCheckedKeysAct->setToolTip(_("Delete the Checked keys")); + deleteCheckedKeysAct->setIcon(QIcon(":button_delete.png")); + connect(deleteCheckedKeysAct, SIGNAL(triggered()), this, + SLOT(slotDeleteCheckedKeys())); + + showKeyDetailsAct = new QAction(_("Show Key Details"), this); + showKeyDetailsAct->setToolTip(_("Show Details for this Key")); + connect(showKeyDetailsAct, SIGNAL(triggered()), this, + SLOT(slotShowKeyDetails())); } void KeyMgmt::createMenus() { - fileMenu = menuBar()->addMenu(tr("&File")); - fileMenu->addAction(openKeyFileAct); - fileMenu->addAction(closeAct); - - keyMenu = menuBar()->addMenu(tr("&Key")); - generateKeyMenu = keyMenu->addMenu(tr("&Generate Key")); - generateKeyMenu->addAction(generateKeyPairAct); - generateKeyMenu->addAction(generateSubKeyAct); - - importKeyMenu = keyMenu->addMenu(tr("&Import Key")); - importKeyMenu->addAction(importKeyFromFileAct); - importKeyMenu->addAction(importKeyFromClipboardAct); - importKeyMenu->addAction(importKeyFromKeyServerAct); - keyMenu->addAction(exportKeyToFileAct); - keyMenu->addAction(exportKeyToClipboardAct); - keyMenu->addSeparator(); - keyMenu->addAction(deleteCheckedKeysAct); + fileMenu = menuBar()->addMenu(_("File")); + fileMenu->addAction(openKeyFileAct); + fileMenu->addAction(closeAct); + + keyMenu = menuBar()->addMenu(_("Key")); + generateKeyMenu = keyMenu->addMenu(_("Generate Key")); + generateKeyMenu->addAction(generateKeyPairAct); + generateKeyMenu->addAction(generateSubKeyAct); + + importKeyMenu = keyMenu->addMenu(_("Import Key")); + importKeyMenu->addAction(importKeyFromFileAct); + importKeyMenu->addAction(importKeyFromClipboardAct); + importKeyMenu->addAction(importKeyFromKeyServerAct); + keyMenu->addAction(exportKeyToFileAct); + keyMenu->addAction(exportKeyToClipboardAct); + keyMenu->addSeparator(); + keyMenu->addAction(deleteCheckedKeysAct); } void KeyMgmt::createToolBars() { - QToolBar *keyToolBar = addToolBar(tr("Key")); - keyToolBar->setObjectName("keytoolbar"); - - // add button with popup menu for import - auto *generateToolButton = new QToolButton(this); - generateToolButton->setMenu(generateKeyMenu); - generateToolButton->setPopupMode(QToolButton::InstantPopup); - generateToolButton->setIcon(QIcon(":key_generate.png")); - generateToolButton->setText(tr("Generate")); - generateToolButton->setToolTip(tr("Generate A New Keypair or Subkey")); - generateToolButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); - keyToolBar->addWidget(generateToolButton); - - // add button with popup menu for import - auto *toolButton = new QToolButton(this); - toolButton->setMenu(importKeyMenu); - toolButton->setPopupMode(QToolButton::InstantPopup); - toolButton->setIcon(QIcon(":key_import.png")); - toolButton->setToolTip(tr("Import key")); - toolButton->setText(tr("Import Key")); - toolButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); - keyToolBar->addWidget(toolButton); - - keyToolBar->addSeparator(); - keyToolBar->addAction(deleteCheckedKeysAct); - keyToolBar->addSeparator(); - keyToolBar->addAction(exportKeyToFileAct); - keyToolBar->addAction(exportKeyToClipboardAct); - -} - -void KeyMgmt::slotImportKeys(QByteArray inBuffer) { - GpgImportInformation result = mCtx->importKey(std::move(inBuffer)); - new KeyImportDetailDialog(mCtx, result, false, this); - -} - -void KeyMgmt::slotImportKeyFromFile() { - QString fileName = QFileDialog::getOpenFileName(this, tr("Open Key"), "", - tr("Key Files") + " (*.asc *.txt);;" + tr("Keyring files") + - " (*.gpg);;All Files (*)"); - if (!fileName.isNull()) { - QFile file; - file.setFileName(fileName); - if (!file.open(QIODevice::ReadOnly)) { - qDebug() << tr("Couldn't Open File: ") + fileName; - return; - } - QByteArray inBuffer = file.readAll(); - slotImportKeys(inBuffer); - file.close(); - } -} - -void KeyMgmt::slotImportKeyFromKeyServer() { - importDialog = new KeyServerImportDialog(mCtx, mKeyList, false, this); - importDialog->show(); -} - -void KeyMgmt::slotImportKeyFromClipboard() { - QClipboard *cb = QApplication::clipboard(); - slotImportKeys(cb->text(QClipboard::Clipboard).toUtf8()); + QToolBar* keyToolBar = addToolBar(_("Key")); + keyToolBar->setObjectName("keytoolbar"); + + // add button with popup menu for import + auto* generateToolButton = new QToolButton(this); + generateToolButton->setMenu(generateKeyMenu); + generateToolButton->setPopupMode(QToolButton::InstantPopup); + generateToolButton->setIcon(QIcon(":key_generate.png")); + generateToolButton->setText(_("Generate")); + generateToolButton->setToolTip(_("Generate A New Keypair or Subkey")); + generateToolButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); + keyToolBar->addWidget(generateToolButton); + + // add button with popup menu for import + auto* toolButton = new QToolButton(this); + toolButton->setMenu(importKeyMenu); + toolButton->setPopupMode(QToolButton::InstantPopup); + toolButton->setIcon(QIcon(":key_import.png")); + toolButton->setToolTip(_("Import key")); + toolButton->setText(_("Import Key")); + toolButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); + keyToolBar->addWidget(toolButton); + + keyToolBar->addSeparator(); + keyToolBar->addAction(deleteCheckedKeysAct); + keyToolBar->addSeparator(); + keyToolBar->addAction(exportKeyToFileAct); + keyToolBar->addAction(exportKeyToClipboardAct); } void KeyMgmt::slotDeleteSelectedKeys() { - deleteKeysWithWarning(mKeyList->getSelected()); + deleteKeysWithWarning(mKeyList->getSelected()); } void KeyMgmt::slotDeleteCheckedKeys() { - deleteKeysWithWarning(mKeyList->getChecked()); + deleteKeysWithWarning(mKeyList->getChecked()); } -void KeyMgmt::deleteKeysWithWarning(QStringList *uidList) { - /** - * TODO: Different Messages for private/public key, check if - * more than one selected... compare to seahorse "delete-dialog" - */ - - if (uidList->isEmpty()) { - return; - } - QString keynames; - for (const auto &uid : *uidList) { - auto key = mCtx->getKeyById(uid); - if (!key.good) continue; - keynames.append(key.name); - keynames.append("<i> <"); - keynames.append(key.email); - keynames.append("> </i><br/>"); - } - - int ret = QMessageBox::warning(this, tr("Deleting Keys"), - "<b>" + tr("Are you sure that you want to delete the following keys?") + - "</b><br/><br/>" + keynames + - +"<br/>" + tr("The action can not be undone."), - QMessageBox::No | QMessageBox::Yes); - - if (ret == QMessageBox::Yes) { - mCtx->deleteKeys(uidList); - } +void KeyMgmt::deleteKeysWithWarning(KeyIdArgsListPtr key_ids) { + /** + * TODO: Different Messages for private/public key, check if + * more than one selected... compare to seahorse "delete-dialog" + */ + + LOG(INFO) << "KeyMgmt::deleteKeysWithWarning Called"; + + if (key_ids->empty()) return; + QString keynames; + for (const auto& key_id : *key_ids) { + auto key = GpgKeyGetter::GetInstance().GetKey(key_id); + if (!key.good()) continue; + keynames.append(QString::fromStdString(key.name())); + keynames.append("<i> <"); + keynames.append(QString::fromStdString(key.email())); + keynames.append("> </i><br/>"); + } + + int ret = QMessageBox::warning( + this, _("Deleting Keys"), + "<b>" + + QString( + _("Are you sure that you want to delete the following keys?")) + + "</b><br/><br/>" + keynames + +"<br/>" + + _("The action can not be undone."), + QMessageBox::No | QMessageBox::Yes); + + if (ret == QMessageBox::Yes) { + GpgKeyOpera::GetInstance().DeleteKeys(std::move(key_ids)); + emit signalKeyStatusUpdated(); + } } void KeyMgmt::slotShowKeyDetails() { - if (mKeyList->getSelected()->isEmpty()) { - return; - } + auto keys_selected = mKeyList->getSelected(); + if (keys_selected->empty()) return; - auto key = mCtx->getKeyById(mKeyList->getSelected()->first()); + auto key = GpgKeyGetter::GetInstance().GetKey(keys_selected->front()); - if (!key.good) { - QMessageBox::critical(nullptr, tr("Error"), tr("Key Not Found.")); - return; - } + if (!key.good()) { + QMessageBox::critical(nullptr, _("Error"), _("Key Not Found.")); + return; + } - new KeyDetailsDialog(mCtx, key); + new KeyDetailsDialog(key); } void KeyMgmt::slotExportKeyToFile() { - auto *keyArray = new QByteArray(); - if (!mCtx->exportKeys(mKeyList->getChecked(), keyArray)) { - delete keyArray; - return; - } - auto key = mCtx->getKeyById(mKeyList->getSelected()->first()); - if (!key.good) { - QMessageBox::critical(nullptr, tr("Error"), tr("Key Not Found.")); - return; - } - QString fileString = key.name + " " + key.email + "(" + key.id + ")_pub.asc"; - - QString fileName = QFileDialog::getSaveFileName(this, tr("Export Key To File"), fileString, - tr("Key Files") + " (*.asc *.txt);;All Files (*)"); - QFile file(fileName); - if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { - delete keyArray; - return; - } - QTextStream stream(&file); - stream << *keyArray; - file.close(); - delete keyArray; - emit signalStatusBarChanged(QString(tr("key(s) exported"))); + ByteArrayPtr key_export_data = nullptr; + auto keys_checked = mKeyList->getChecked(); + if (!GpgKeyImportExportor::GetInstance().ExportKeys(keys_checked, + key_export_data)) { + return; + } + auto key = + GpgKeyGetter::GetInstance().GetKey(mKeyList->getSelected()->front()); + if (!key.good()) { + QMessageBox::critical(nullptr, _("Error"), _("Key Not Found.")); + return; + } + QString fileString = QString::fromStdString(key.name() + " " + key.email() + + "(" + key.id() + ")_pub.asc"); + + QString file_name = QFileDialog::getSaveFileName( + this, _("Export Key To File"), fileString, + QString(_("Key Files")) + " (*.asc *.txt);;All Files (*)"); + + write_buffer_to_file(file_name.toStdString(), *key_export_data); + + emit signalStatusBarChanged(QString(_("key(s) exported"))); } void KeyMgmt::slotExportKeyToClipboard() { - auto *keyArray = new QByteArray(); - QClipboard *cb = QApplication::clipboard(); - if (!mCtx->exportKeys(mKeyList->getChecked(), keyArray)) { - return; - } - cb->setText(*keyArray); - delete keyArray; + ByteArrayPtr key_export_data = nullptr; + auto keys_checked = mKeyList->getChecked(); + if (!GpgKeyImportExportor::GetInstance().ExportKeys(keys_checked, + key_export_data)) { + return; + } + QApplication::clipboard()->setText(QString::fromStdString(*key_export_data)); } void KeyMgmt::slotGenerateKeyDialog() { - auto *keyGenDialog = new KeyGenDialog(mCtx, this); - keyGenDialog->show(); + auto* keyGenDialog = new KeyGenDialog(this); + keyGenDialog->show(); } -void KeyMgmt::closeEvent(QCloseEvent *event) { - QMainWindow::closeEvent(event); +void KeyMgmt::closeEvent(QCloseEvent* event) { + slotSaveWindowState(); + QMainWindow::closeEvent(event); } void KeyMgmt::slotGenerateSubKey() { - auto selectedList = mKeyList->getSelected(); - if (selectedList->empty()) { - QMessageBox::information(nullptr, - tr("Invalid Operation"), - tr("Please select one KeyPair before doing this operation.")); - return; - } - const auto key = mCtx->getKeyById(selectedList->first()); - if (!key.good) { - QMessageBox::critical(nullptr, tr("Error"), tr("Key Not Found.")); - return; - } - if (!key.is_private_key) { - QMessageBox::critical(nullptr, - tr("Invalid Operation"), - tr("If a key pair does not have a private key then it will not be able to generate sub-keys.")); - return; - } - - auto dialog = new SubkeyGenerateDialog(mCtx, key, this); - dialog->show(); + auto keys_selected = mKeyList->getSelected(); + if (keys_selected->empty()) { + QMessageBox::information( + nullptr, _("Invalid Operation"), + _("Please select one KeyPair before doing this operation.")); + return; + } + const auto key = GpgKeyGetter::GetInstance().GetKey(keys_selected->front()); + if (!key.good()) { + QMessageBox::critical(nullptr, _("Error"), _("Key Not Found.")); + return; + } + if (!key.is_private_key()) { + QMessageBox::critical(nullptr, _("Invalid Operation"), + _("If a key pair does not have a private key then " + "it will not be able to generate sub-keys.")); + return; + } + + auto dialog = new SubkeyGenerateDialog(key.id(), this); + dialog->show(); +} +void KeyMgmt::slotSaveWindowState() { + auto& settings = + GpgFrontend::UI::GlobalSettingStation::GetInstance().GetUISettings(); + + if (!settings.exists("window") || + settings.lookup("window").getType() != libconfig::Setting::TypeGroup) + settings.add("window", libconfig::Setting::TypeGroup); + + auto& window = settings["window"]; + + if (!window.exists("key_management") || + window.lookup("key_management").getType() != + libconfig::Setting::TypeGroup) + window.add("key_management", libconfig::Setting::TypeGroup); + + auto& key_management = window["key_management"]; + + if (!key_management.exists("position") || + key_management.lookup("position").getType() != + libconfig::Setting::TypeGroup) { + auto& position = + key_management.add("position", libconfig::Setting::TypeGroup); + position.add("x", libconfig::Setting::TypeInt) = pos().x(); + position.add("y", libconfig::Setting::TypeInt) = pos().y(); + } else { + key_management["position"]["x"] = pos().x(); + key_management["position"]["y"] = pos().y(); + } + + if (!key_management.exists("size") || + key_management.lookup("size").getType() != + libconfig::Setting::TypeGroup) { + auto& size = key_management.add("size", libconfig::Setting::TypeGroup); + size.add("width", libconfig::Setting::TypeInt) = QWidget::width(); + size.add("height", libconfig::Setting::TypeInt) = QWidget::height(); + } else { + key_management["size"]["width"] = QWidget::width(); + key_management["size"]["height"] = QWidget::height(); + } + + if (!key_management.exists("window_state")) + key_management.add("window_state", libconfig::Setting::TypeString) = + saveState().toBase64().toStdString(); + + GlobalSettingStation::GetInstance().Sync(); } + +} // namespace GpgFrontend::UI diff --git a/src/ui/KeyMgmt.h b/src/ui/KeyMgmt.h new file mode 100755 index 00000000..bf1c9b5a --- /dev/null +++ b/src/ui/KeyMgmt.h @@ -0,0 +1,102 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef __KEYMGMT_H__ +#define __KEYMGMT_H__ + +#include "KeyImportDetailDialog.h" +#include "KeyServerImportDialog.h" +#include "ui/GpgFrontendUI.h" +#include "ui/keygen/KeygenDialog.h" +#include "ui/keypair_details/KeyDetailsDialog.h" +#include "ui/widgets/KeyList.h" + +namespace GpgFrontend::UI { + +class KeyMgmt : public QMainWindow { + Q_OBJECT + + public: + explicit KeyMgmt(QWidget* parent = nullptr); + + public slots: + + void slotGenerateSubKey(); + + void slotExportKeyToFile(); + + void slotExportKeyToClipboard(); + + void slotDeleteSelectedKeys(); + + void slotDeleteCheckedKeys(); + + void slotGenerateKeyDialog(); + + void slotShowKeyDetails(); + + void slotSaveWindowState(); + + signals: + + void signalStatusBarChanged(QString); + + void signalKeyStatusUpdated(); + + private: + void createMenus(); + + void createActions(); + + void createToolBars(); + + void deleteKeysWithWarning(GpgFrontend::KeyIdArgsListPtr uidList); + + KeyList* mKeyList; + QMenu* fileMenu{}; + QMenu* keyMenu{}; + QMenu* generateKeyMenu{}; + QMenu* importKeyMenu{}; + QAction* openKeyFileAct{}; + QAction* exportKeyToFileAct{}; + QAction* exportKeyToClipboardAct{}; + QAction* deleteCheckedKeysAct{}; + QAction* deleteSelectedKeysAct{}; + QAction* generateKeyDialogAct{}; + QAction* generateKeyPairAct{}; + QAction* generateSubKeyAct{}; + QAction* importKeyFromClipboardAct{}; + QAction* importKeyFromFileAct{}; + QAction* importKeyFromKeyServerAct{}; + QAction* closeAct{}; + QAction* showKeyDetailsAct{}; + KeyServerImportDialog* importDialog{}; + + protected: + void closeEvent(QCloseEvent* event) override; +}; + +} // namespace GpgFrontend::UI + +#endif // __KEYMGMT_H__ diff --git a/src/ui/KeyServerImportDialog.cpp b/src/ui/KeyServerImportDialog.cpp index a1355120..17db7d65 100644 --- a/src/ui/KeyServerImportDialog.cpp +++ b/src/ui/KeyServerImportDialog.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -26,27 +26,32 @@ #include <utility> -KeyServerImportDialog::KeyServerImportDialog(GpgME::GpgContext *ctx, KeyList *keyList, bool automatic, - QWidget *parent) - : QDialog(parent), appPath(qApp->applicationDirPath()), - settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", QSettings::IniFormat), - mCtx(ctx), mKeyList(keyList), mAutomatic(automatic) { +#include "gpg/function/GpgKeyImportExportor.h" +#include "ui/SignalStation.h" +#include "ui/settings/GlobalSettingStation.h" - if(automatic) { - setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::CustomizeWindowHint); - } +namespace GpgFrontend::UI { + +KeyServerImportDialog::KeyServerImportDialog(bool automatic, QWidget* parent) + : QDialog(parent), mAutomatic(automatic) { + // Layout for messagebox + auto* messageLayout = new QHBoxLayout; + if (automatic) { + setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::CustomizeWindowHint); + } else { // Buttons - closeButton = createButton(tr("&Close"), SLOT(close())); - importButton = createButton(tr("&Import ALL"), SLOT(slotImport())); - searchButton = createButton(tr("&Search"), SLOT(slotSearch())); + closeButton = createButton(_("Close"), SLOT(close())); + importButton = createButton(_("Import ALL"), SLOT(slotImport())); + importButton->setDisabled(true); + searchButton = createButton(_("Search"), SLOT(slotSearch())); // Line edit for search string - searchLabel = new QLabel(tr("Search String:")); + searchLabel = new QLabel(QString(_("Search String")) + _(": ")); searchLineEdit = new QLineEdit(); // combobox for keyserverlist - keyServerLabel = new QLabel(tr("Key Server:")); + keyServerLabel = new QLabel(QString(_("Key Server")) + _(": ")); keyServerComboBox = createComboBox(); // table containing the keys found @@ -56,421 +61,549 @@ KeyServerImportDialog::KeyServerImportDialog(GpgME::GpgContext *ctx, KeyList *ke icon = new QLabel; icon->setFixedHeight(24); - // Network Waiting - waitingBar = new QProgressBar(); - waitingBar->setVisible(false); - waitingBar->setRange(0, 0); - waitingBar->setFixedWidth(200); - - // Layout for messagebox - auto *messageLayout = new QHBoxLayout; messageLayout->addWidget(icon); messageLayout->addWidget(message); - messageLayout->addWidget(waitingBar); messageLayout->addStretch(); + } + + // Network Waiting + waitingBar = new QProgressBar(); + waitingBar->setVisible(false); + waitingBar->setRange(0, 0); + waitingBar->setFixedWidth(200); + messageLayout->addWidget(waitingBar); + + auto* mainLayout = new QGridLayout; + + // 自动化调用界面布局 + if (automatic) { + mainLayout->addLayout(messageLayout, 0, 0, 1, 3); + } else { + mainLayout->addWidget(searchLabel, 1, 0); + mainLayout->addWidget(searchLineEdit, 1, 1); + mainLayout->addWidget(searchButton, 1, 2); + mainLayout->addWidget(keyServerLabel, 2, 0); + mainLayout->addWidget(keyServerComboBox, 2, 1); + mainLayout->addWidget(keysTable, 3, 0, 1, 3); + mainLayout->addLayout(messageLayout, 4, 0, 1, 3); // Layout for import and close button - auto *buttonsLayout = new QHBoxLayout; + auto* buttonsLayout = new QHBoxLayout; buttonsLayout->addStretch(); - if(!automatic) - buttonsLayout->addWidget(importButton); + buttonsLayout->addWidget(importButton); buttonsLayout->addWidget(closeButton); - - auto *mainLayout = new QGridLayout; - - // 自动化调用界面布局 - if(automatic) { - mainLayout->addLayout(messageLayout, 0, 0, 1, 3); - } else { - mainLayout->addWidget(searchLabel, 1, 0); - mainLayout->addWidget(searchLineEdit, 1, 1); - mainLayout->addWidget(searchButton, 1, 2); - mainLayout->addWidget(keyServerLabel, 2, 0); - mainLayout->addWidget(keyServerComboBox, 2, 1); - mainLayout->addWidget(keysTable, 3, 0, 1, 3); - mainLayout->addLayout(messageLayout, 4, 0, 1, 3); - mainLayout->addLayout(buttonsLayout, 6, 0, 1, 3); + mainLayout->addLayout(buttonsLayout, 6, 0, 1, 3); + } + + this->setLayout(mainLayout); + if (automatic) + this->setWindowTitle(_("Update Keys from Keyserver")); + else + this->setWindowTitle(_("Import Keys from Keyserver")); + + if (automatic) { + this->setFixedSize(240, 42); + } else { + auto pos = QPoint(150, 150); + LOG(INFO) << "parent" << parent; + if (parent) pos += parent->pos(); + LOG(INFO) << "pos default" << pos.x() << pos.y(); + auto size = QSize(800, 500); + + try { + auto& settings = GlobalSettingStation::GetInstance().GetUISettings(); + + int x, y, width, height; + x = settings.lookup("window.import_from_keyserver.position.x"); + y = settings.lookup("window.import_from_keyserver.position.y"); + width = settings.lookup("window.import_from_keyserver.size.width"); + height = settings.lookup("window.import_from_keyserver.size.height"); + pos = QPoint(x, y); + size = QSize(width, height); + + } catch (...) { + LOG(WARNING) << "cannot read pos or size from settings"; } - this->setLayout(mainLayout); - if(automatic) - this->setWindowTitle(tr("Update Keys from Keyserver")); - else - this->setWindowTitle(tr("Import Keys from Keyserver")); + this->resize(size); + this->move(pos); + } - if(automatic) { - this->setFixedSize(240, 42); - } else { - // Restore window size & location - if (this->settings.value("ImportKeyFromServer/setWindowSize").toBool()) { - QPoint pos = settings.value("ImportKeyFromServer/pos", QPoint(150, 150)).toPoint(); - QSize size = settings.value("ImportKeyFromServer/size", QSize(500, 300)).toSize(); - qDebug() << "Settings size" << size << "pos" << pos; - this->setMinimumSize(size); - this->move(pos); - } else { - qDebug() << "Use default min windows size and pos"; - QPoint defaultPoint(150, 150); - QSize defaultMinSize(500, 300); - this->setMinimumSize(defaultMinSize); - this->move(defaultPoint); - this->settings.setValue("ImportKeyFromServer/pos", defaultPoint); - this->settings.setValue("ImportKeyFromServer/size", defaultMinSize); - this->settings.setValue("ImportKeyFromServer/setWindowSize", true); - } - } + this->setModal(true); - this->setModal(true); -} + connect(this, SIGNAL(signalKeyImported()), SignalStation::GetInstance(), + SIGNAL(KeyDatabaseRefresh())); -QPushButton *KeyServerImportDialog::createButton(const QString &text, const char *member) { - auto *button = new QPushButton(text); - connect(button, SIGNAL(clicked()), this, member); - return button; + // save window pos and size to configure file + connect(this, SIGNAL(finished(int)), this, SLOT(slotSaveWindowState())); } -QComboBox *KeyServerImportDialog::createComboBox() { - auto *comboBox = new QComboBox; - comboBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); +QPushButton* KeyServerImportDialog::createButton(const QString& text, + const char* member) { + auto* button = new QPushButton(text); + connect(button, SIGNAL(clicked()), this, member); + return button; +} - // Read keylist from ini-file and fill it into combobox - comboBox->addItems(settings.value("keyserver/keyServerList").toStringList()); +QComboBox* KeyServerImportDialog::createComboBox() { + auto* comboBox = new QComboBox; + comboBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); - // set default keyserver in combobox - QString keyserver = settings.value("keyserver/defaultKeyServer").toString(); - comboBox->setCurrentIndex(comboBox->findText(keyserver)); + auto& settings = GlobalSettingStation::GetInstance().GetUISettings(); - return comboBox; + try { + auto& server_list = settings.lookup("keyserver.server_list"); + const auto server_list_size = server_list.getLength(); + for (int i = 0; i < server_list_size; i++) { + std::string server_url = server_list[i]; + comboBox->addItem(server_url.c_str()); + } + } catch (...) { + LOG(ERROR) << _("Setting Operation Error") << _("server_list"); + } + + // set default keyserver in combobox + try { + std::string default_server = settings.lookup("keyserver.default_server"); + comboBox->setCurrentText(default_server.c_str()); + } catch (...) { + LOG(ERROR) << _("Setting Operation Error") << _("default_server"); + } + + return comboBox; } void KeyServerImportDialog::createKeysTable() { - keysTable = new QTableWidget(); - keysTable->setColumnCount(4); + keysTable = new QTableWidget(); + keysTable->setColumnCount(4); - // always a whole row is marked - keysTable->setSelectionBehavior(QAbstractItemView::SelectRows); - keysTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + // always a whole row is marked + keysTable->setSelectionBehavior(QAbstractItemView::SelectRows); + keysTable->setEditTriggers(QAbstractItemView::NoEditTriggers); - // Make just one row selectable - keysTable->setSelectionMode(QAbstractItemView::SingleSelection); + // Make just one row selectable + keysTable->setSelectionMode(QAbstractItemView::SingleSelection); - QStringList labels; - labels << tr("UID") << tr("Creation date") << tr("KeyID") << tr("Tag"); - keysTable->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents); - keysTable->setHorizontalHeaderLabels(labels); - keysTable->verticalHeader()->hide(); + QStringList labels; + labels << _("UID") << _("Creation date") << _("KeyID") << _("Tag"); + keysTable->horizontalHeader()->setSectionResizeMode( + 0, QHeaderView::ResizeToContents); + keysTable->setHorizontalHeaderLabels(labels); + keysTable->verticalHeader()->hide(); - connect(keysTable, SIGNAL(cellActivated(int, int)), - this, SLOT(slotImport())); + connect(keysTable, SIGNAL(cellActivated(int, int)), this, SLOT(slotImport())); } -void KeyServerImportDialog::setMessage(const QString &text, bool error) { - message->setText(text); - if (error) { - icon->setPixmap(QPixmap(":error.png").scaled(QSize(24, 24), Qt::KeepAspectRatio)); - } else { - icon->setPixmap(QPixmap(":info.png").scaled(QSize(24, 24), Qt::KeepAspectRatio)); - } +void KeyServerImportDialog::setMessage(const QString& text, bool error) { + if (mAutomatic) return; + + message->setText(text); + if (error) { + icon->setPixmap( + QPixmap(":error.png").scaled(QSize(24, 24), Qt::KeepAspectRatio)); + } else { + icon->setPixmap( + QPixmap(":info.png").scaled(QSize(24, 24), Qt::KeepAspectRatio)); + } } void KeyServerImportDialog::slotSearch() { + if (searchLineEdit->text().isEmpty()) { + setMessage("<h4>" + QString(_("Text is empty.")) + "</h4>", false); + return; + } - if (searchLineEdit->text().isEmpty()) { - setMessage("<h4>" + tr("Text is empty.") + "</h4>", false); - return; - } - - QUrl urlFromRemote = keyServerComboBox->currentText() + "/pks/lookup?search=" + searchLineEdit->text() + + QUrl url_from_remote = keyServerComboBox->currentText() + + "/pks/lookup?search=" + searchLineEdit->text() + "&op=index&options=mr"; - qnam = new QNetworkAccessManager(this); - QNetworkReply *reply = qnam->get(QNetworkRequest(urlFromRemote)); - - connect(reply, SIGNAL(finished()), - this, SLOT(slotSearchFinished())); - - setLoading(true); - - while (reply->isRunning()) { - QApplication::processEvents(); - } - - setLoading(false); - + qnam = new QNetworkAccessManager(this); + QNetworkReply* reply = qnam->get(QNetworkRequest(url_from_remote)); + + connect(reply, SIGNAL(finished()), this, SLOT(slotSearchFinished())); + + setLoading(true); + this->searchButton->setDisabled(true); + this->keyServerComboBox->setDisabled(true); + this->searchLineEdit->setReadOnly(true); + this->importButton->setDisabled(true); + + while (reply->isRunning()) { + QApplication::processEvents(); + } + + this->searchButton->setDisabled(false); + this->keyServerComboBox->setDisabled(false); + this->searchLineEdit->setReadOnly(false); + this->importButton->setDisabled(false); + setLoading(false); } void KeyServerImportDialog::slotSearchFinished() { - auto *reply = qobject_cast<QNetworkReply *>(sender()); - - keysTable->clearContents(); - keysTable->setRowCount(0); - QString firstLine = QString(reply->readLine(1024)); - - auto error = reply->error(); - if (error != QNetworkReply::NoError) { - qDebug() << "Error From Reply" << reply->errorString(); - switch (error) { - case QNetworkReply::ContentNotFoundError : - setMessage(tr("Not Key Found"), true); - break; - case QNetworkReply::TimeoutError : - setMessage(tr("Timeout"), true); - break; - case QNetworkReply::HostNotFoundError : - setMessage(tr("Key Server Not Found"), true); - break; - default: - setMessage(tr("Connection Error"), true); - } + LOG(INFO) << "KeyServerImportDialog::slotSearchFinished Called"; + + auto* reply = qobject_cast<QNetworkReply*>(sender()); + + keysTable->clearContents(); + keysTable->setRowCount(0); + QString first_line = QString(reply->readLine(1024)); + + auto error = reply->error(); + if (error != QNetworkReply::NoError) { + qDebug() << "Error From Reply" << reply->errorString(); + switch (error) { + case QNetworkReply::ContentNotFoundError: + setMessage(_("Not Key Found"), true); + break; + case QNetworkReply::TimeoutError: + setMessage(_("Timeout"), true); + break; + case QNetworkReply::HostNotFoundError: + setMessage(_("Key Server Not Found"), true); + break; + default: + setMessage(_("Connection Error"), true); + } + return; + } + + if (first_line.contains("Error")) { + QString text = QString(reply->readLine(1024)); + if (text.contains("Too many responses")) { + setMessage( + "<h4>" + QString(_("Too many responses from keyserver!")) + "</h4>", + true); + return; + } else if (text.contains("No keys found")) { + // if string looks like hex string, search again with 0x prepended + QRegExp rx("[0-9A-Fa-f]*"); + QString query = searchLineEdit->text(); + if (rx.exactMatch(query)) { + setMessage( + "<h4>" + + QString(_("No keys found, input may be kexId, retrying search " + "with 0x.")) + + "</h4>", + true); + searchLineEdit->setText(query.prepend("0x")); + this->slotSearch(); return; + } else { + setMessage( + "<h4>" + QString(_("No keys found containing the search string!")) + + "</h4>", + true); + return; + } + } else if (text.contains("Insufficiently specific words")) { + setMessage("<h4>" + QString(_("Insufficiently specific search string!")) + + "</h4>", + true); + return; + } else { + setMessage(text, true); + return; } + } else { + int row = 0; + bool strikeout = false; + while (reply->canReadLine()) { + auto line_buff = reply->readLine().trimmed(); + QString decoded = + QString::fromUtf8(line_buff.constData(), line_buff.size()); + QStringList line = decoded.split(":"); + // TODO: have a look at two following pub lines + if (line[0] == "pub") { + strikeout = false; + + QString flags = line[line.size() - 1]; + keysTable->setRowCount(row + 1); + + // flags can be "d" for disabled, "r" for revoked + // or "e" for expired + if (flags.contains("r") or flags.contains("d") or flags.contains("e")) { + strikeout = true; + if (flags.contains("e")) { + keysTable->setItem(row, 3, + new QTableWidgetItem(QString("expired"))); + } + if (flags.contains("r")) { + keysTable->setItem(row, 3, + new QTableWidgetItem(QString(_("revoked")))); + } + if (flags.contains("d")) { + keysTable->setItem(row, 3, + new QTableWidgetItem(QString(_("disabled")))); + } + } + + QStringList line2 = QString(reply->readLine()).split(":"); - if (firstLine.contains("Error")) { - QString text = QString(reply->readLine(1024)); - if (text.contains("Too many responses")) { - setMessage("<h4>" +tr("Too many responses from keyserver!") + "</h4>", true); - return; - } else if (text.contains("No keys found")) { - // if string looks like hex string, search again with 0x prepended - QRegExp rx("[0-9A-Fa-f]*"); - QString query = searchLineEdit->text(); - if (rx.exactMatch(query)) { - setMessage("<h4>" + tr("No keys found, input may be kexId, retrying search with 0x.") + "</h4>", true); - searchLineEdit->setText(query.prepend("0x")); - this->slotSearch(); - return; - } else { - setMessage("<h4>" +tr("No keys found containing the search string!") + "</h4>", true); - return; - } - } else if (text.contains("Insufficiently specific words")) { - setMessage("<h4>" + tr("Insufficiently specific search string!") + "</h4>", true); - return; - } else { - setMessage(text, true); - return; + auto* uid = new QTableWidgetItem(); + if (line2.size() > 1) { + uid->setText(line2[1]); + keysTable->setItem(row, 0, uid); } - } else { - int row = 0; - bool strikeout = false; - while (reply->canReadLine()) { - auto line_buff = reply->readLine().trimmed(); - QString decoded = QString::fromUtf8(line_buff.constData(), line_buff.size()); - QStringList line = decoded.split(":"); - //TODO: have a look at two following pub lines - if (line[0] == "pub") { - strikeout = false; - - QString flags = line[line.size() - 1]; - keysTable->setRowCount(row + 1); - - // flags can be "d" for disabled, "r" for revoked - // or "e" for expired - if (flags.contains("r") or flags.contains("d") or flags.contains("e")) { - strikeout = true; - if (flags.contains("e")) { - keysTable->setItem(row, 3, new QTableWidgetItem(QString("expired"))); - } - if (flags.contains("r")) { - keysTable->setItem(row, 3, new QTableWidgetItem(QString(tr("revoked")))); - } - if (flags.contains("d")) { - keysTable->setItem(row, 3, new QTableWidgetItem(QString(tr("disabled")))); - } - } - - QStringList line2 = QString(reply->readLine()).split(":"); - - auto *uid = new QTableWidgetItem(); - if (line2.size() > 1) { - uid->setText(line2[1]); - keysTable->setItem(row, 0, uid); - } - auto *creation_date = new QTableWidgetItem( - QDateTime::fromTime_t(line[4].toInt()).toString("dd. MMM. yyyy")); - keysTable->setItem(row, 1, creation_date); - auto *keyid = new QTableWidgetItem(line[1]); - keysTable->setItem(row, 2, keyid); - if (strikeout) { - QFont strike = uid->font(); - strike.setStrikeOut(true); - uid->setFont(strike); - creation_date->setFont(strike); - keyid->setFont(strike); - } - row++; - } else { - if (line[0] == "uid") { - QStringList l; - int height = keysTable->rowHeight(row - 1); - keysTable->setRowHeight(row - 1, height + 16); - QString tmp = keysTable->item(row - 1, 0)->text(); - tmp.append(QString("\n") + line[1]); - auto *tmp1 = new QTableWidgetItem(tmp); - keysTable->setItem(row - 1, 0, tmp1); - if (strikeout) { - QFont strike = tmp1->font(); - strike.setStrikeOut(true); - tmp1->setFont(strike); - } - } - } - setMessage(tr("<h4>%1 keys found. Double click a key to import it.</h4>").arg(row), false); + auto* creation_date = new QTableWidgetItem( + QDateTime::fromTime_t(line[4].toInt()).toString("dd. MMM. yyyy")); + keysTable->setItem(row, 1, creation_date); + auto* keyid = new QTableWidgetItem(line[1]); + keysTable->setItem(row, 2, keyid); + if (strikeout) { + QFont strike = uid->font(); + strike.setStrikeOut(true); + uid->setFont(strike); + creation_date->setFont(strike); + keyid->setFont(strike); + } + row++; + } else { + if (line[0] == "uid") { + QStringList l; + int height = keysTable->rowHeight(row - 1); + keysTable->setRowHeight(row - 1, height + 16); + QString tmp = keysTable->item(row - 1, 0)->text(); + tmp.append(QString("\n") + line[1]); + auto* tmp1 = new QTableWidgetItem(tmp); + keysTable->setItem(row - 1, 0, tmp1); + if (strikeout) { + QFont strike = tmp1->font(); + strike.setStrikeOut(true); + tmp1->setFont(strike); + } } - keysTable->resizeColumnsToContents(); + } + setMessage( + QString("<h4>") + + QString(_("%1 keys found. Double click a key to import it.")) + .arg(row) + + "</h4>", + false); } - reply->deleteLater(); + keysTable->resizeColumnsToContents(); + importButton->setDisabled(keysTable->size().isEmpty()); + } + reply->deleteLater(); } void KeyServerImportDialog::slotImport() { - if (keysTable->currentRow() > -1) { - QString keyid = keysTable->item(keysTable->currentRow(), 2)->text(); - slotImport(QStringList(keyid), keyServerComboBox->currentText()); - } -} - -void KeyServerImportDialog::slotImport(const QStringList& keyIds) { - QString keyserver = settings.value("keyserver/defaultKeyServer").toString(); - qDebug() << "Select Key Server" << keyserver; - slotImport(keyIds, QUrl(keyserver)); + LOG(INFO) << _("Current Row") << keysTable->currentRow(); + if (keysTable->currentRow() > -1) { + QString keyid = keysTable->item(keysTable->currentRow(), 2)->text(); + slotImport(QStringList(keyid), keyServerComboBox->currentText()); + } } -void KeyServerImportDialog::slotImportKey(const QVector<GpgKey>& keys) { - QString keyserver = settings.value("keyserver/defaultKeyServer").toString(); - qDebug() << "Select Key Server" << keyserver; - auto keyIds = QStringList(); - for(const auto &key : keys) { - keyIds.append(key.id); +void KeyServerImportDialog::slotImport(const KeyIdArgsListPtr& keys) { + std::string target_keyserver; + if (keyServerComboBox != nullptr) { + target_keyserver = keyServerComboBox->currentText().toStdString(); + } + if (target_keyserver.empty()) { + try { + auto& settings = GlobalSettingStation::GetInstance().GetUISettings(); + + target_keyserver = settings.lookup("keyserver.default_server").c_str(); + + LOG(INFO) << _("Set target Key Server to default Key Server") + << target_keyserver; + } catch (...) { + LOG(ERROR) << _("Cannot read default_keyserver From Settings"); + QMessageBox::critical( + nullptr, _("Default Keyserver Not Found"), + _("Cannot read default keyserver from your settings, " + "please set a default keyserver first")); + return; } - slotImport(keyIds, QUrl(keyserver)); + } + auto key_ids = QStringList(); + for (const auto& key_id : *keys) + key_ids.append(QString::fromStdString(key_id)); + slotImport(key_ids, QUrl(target_keyserver.c_str())); } +void KeyServerImportDialog::slotImport(const QStringList& keyIds, + const QUrl& keyServerUrl) { + for (const auto& keyId : keyIds) { + QUrl req_url(keyServerUrl.scheme() + "://" + keyServerUrl.host() + + "/pks/lookup?op=get&search=0x" + keyId + "&options=mr"); -void KeyServerImportDialog::slotImport(const QStringList& keyIds, const QUrl &keyServerUrl) { - for (const auto &keyId : keyIds) { - QUrl reqUrl( - keyServerUrl.scheme() + "://" + keyServerUrl.host() + "/pks/lookup?op=get&search=0x" + keyId + - "&options=mr"); - qDebug() << "slotImport reqUrl" << reqUrl; - auto pManager = new QNetworkAccessManager(this); - - QNetworkReply *reply = pManager->get(QNetworkRequest(reqUrl)); - - connect(reply, SIGNAL(finished()), - this, SLOT(slotImportFinished())); - - setLoading(true); - - while(reply->isRunning()) { - QApplication::processEvents(); - } + LOG(INFO) << "request url" << req_url.toString().toStdString(); + auto manager = new QNetworkAccessManager(this); - setLoading(false); - } + QNetworkReply* reply = manager->get(QNetworkRequest(req_url)); + connect(reply, &QNetworkReply::finished, this, + [&, keyId]() { this->slotImportFinished(keyId); }); + LOG(INFO) << "loading start"; + setLoading(true); + while (reply->isRunning()) QApplication::processEvents(); + setLoading(false); + LOG(INFO) << "loading done"; + } } -void KeyServerImportDialog::slotImportFinished() { - auto *reply = qobject_cast<QNetworkReply *>(sender()); - - QByteArray key = reply->readAll(); - - QVariant redirectionTarget = reply->attribute(QNetworkRequest::RedirectionTargetAttribute); - - auto error = reply->error(); - if (error != QNetworkReply::NoError) { - qDebug() << "Error From Reply" << reply->errorString(); - switch (error) { - case QNetworkReply::ContentNotFoundError : - setMessage(tr("Key Not Found"), true); - break; - case QNetworkReply::TimeoutError : - setMessage(tr("Timeout"), true); - break; - case QNetworkReply::HostNotFoundError : - setMessage(tr("Key Server Not Found"), true); - break; - default: - setMessage(tr("Connection Error"), true); - } - if(mAutomatic) { - setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint); - } - return; +void KeyServerImportDialog::slotImportFinished(QString keyid) { + LOG(INFO) << _("Called"); + + auto* reply = qobject_cast<QNetworkReply*>(sender()); + + QByteArray key = reply->readAll(); + + auto error = reply->error(); + if (error != QNetworkReply::NoError) { + LOG(ERROR) << "Error From Reply" << reply->errorString().toStdString(); + if (!mAutomatic) { + switch (error) { + case QNetworkReply::ContentNotFoundError: + setMessage(_("Key Not Found"), true); + break; + case QNetworkReply::TimeoutError: + setMessage(_("Timeout"), true); + break; + case QNetworkReply::HostNotFoundError: + setMessage(_("Key Server Not Found"), true); + break; + default: + setMessage(_("Connection Error"), true); + } + } else { + switch (error) { + case QNetworkReply::ContentNotFoundError: + QMessageBox::critical( + nullptr, _("Public key Not Found"), + QString(_("Public key fingerprint %1 not found in the Keyserver")) + .arg(keyid)); + break; + case QNetworkReply::TimeoutError: + QMessageBox::critical(nullptr, _("Timeout"), "Connection timeout"); + break; + case QNetworkReply::HostNotFoundError: + QMessageBox::critical(nullptr, _("Host Not Found"), + "cannot resolve the default Keyserver"); + break; + default: + QMessageBox::critical(nullptr, _("Connection Error"), + _("General Connection Error")); + } } - - // Add keyserver to list in config-file, if it isn't contained - QStringList keyServerList = settings.value("keyserver/keyServerList").toStringList(); - if (!keyServerList.contains(keyServerComboBox->currentText())) { - keyServerList.append(keyServerComboBox->currentText()); - settings.setValue("keyserver/keyServerList", keyServerList); + if (mAutomatic) { + setWindowFlags(Qt::Window | Qt::WindowTitleHint | + Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint); } - reply->deleteLater(); + return; + } - this->importKeys(key.constData()); - if(mAutomatic) { - setMessage(tr("<h4>Key Updated</h4>"), false); - } else { - setMessage(tr("<h4>Key Imported</h4>"), false); - } + reply->deleteLater(); + this->importKeys(std::make_unique<ByteArray>(key.constData(), key.length())); + if (!mAutomatic) { + setMessage(QString("<h4>") + _("Key Imported") + "</h4>", false); + } } -void KeyServerImportDialog::importKeys(QByteArray inBuffer) { - GpgImportInformation result = mCtx->importKey(std::move(inBuffer)); - if(mAutomatic) { - new KeyImportDetailDialog(mCtx, result, false, this); - this->accept(); - } else { - new KeyImportDetailDialog(mCtx, result, false, this); - } +void KeyServerImportDialog::importKeys(ByteArrayPtr in_data) { + GpgImportInformation result = + GpgKeyImportExportor::GetInstance().ImportKey(std::move(in_data)); + emit signalKeyImported(); + if (mAutomatic) { + auto dialog = new KeyImportDetailDialog(result, true, nullptr); + dialog->show(); + this->accept(); + } else { + auto dialog = new KeyImportDetailDialog(result, false, this); + dialog->exec(); + } } void KeyServerImportDialog::setLoading(bool status) { - if (status) { - waitingBar->setVisible(true); - icon->setVisible(false); - message->setVisible(false); - } else { - waitingBar->setVisible(false); - icon->setVisible(true); - message->setVisible(true); - } + waitingBar->setVisible(status); + if (!mAutomatic) { + icon->setVisible(!status); + message->setVisible(!status); + } } -KeyServerImportDialog::KeyServerImportDialog(GpgME::GpgContext *ctx, QWidget *parent) - : QDialog(parent), appPath(qApp->applicationDirPath()), - settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", QSettings::IniFormat), - mCtx(ctx), mAutomatic(true) { +KeyServerImportDialog::KeyServerImportDialog(QWidget* parent) + : QDialog(parent), mAutomatic(true) { + setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::CustomizeWindowHint); - setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::CustomizeWindowHint); + message = new QLabel; + message->setFixedHeight(24); + icon = new QLabel; + icon->setFixedHeight(24); - message = new QLabel; - message->setFixedHeight(24); - icon = new QLabel; - icon->setFixedHeight(24); + // Network Waiting + waitingBar = new QProgressBar(); + waitingBar->setVisible(false); + waitingBar->setRange(0, 0); + waitingBar->setFixedHeight(24); + waitingBar->setFixedWidth(200); - // Network Waiting - waitingBar = new QProgressBar(); - waitingBar->setVisible(false); - waitingBar->setRange(0, 0); - waitingBar->setFixedHeight(24); - waitingBar->setFixedWidth(200); + // Layout for messagebox + auto* messageLayout = new QHBoxLayout; + messageLayout->addWidget(icon); + messageLayout->addWidget(message); + messageLayout->addWidget(waitingBar); + messageLayout->addStretch(); - // Layout for messagebox - auto *messageLayout = new QHBoxLayout; - messageLayout->addWidget(icon); - messageLayout->addWidget(message); - messageLayout->addWidget(waitingBar); - messageLayout->addStretch(); + keyServerComboBox = createComboBox(); - keyServerComboBox = createComboBox(); + auto* mainLayout = new QGridLayout; - auto *mainLayout = new QGridLayout; + mainLayout->addLayout(messageLayout, 0, 0, 1, 3); - mainLayout->addLayout(messageLayout, 0, 0, 1, 3); + this->setLayout(mainLayout); + this->setWindowTitle(_("Upload Keys from Keyserver")); + this->setFixedSize(200, 42); + this->setModal(true); +} - this->setLayout(mainLayout); - this->setWindowTitle(tr("Upload Keys from Keyserver")); - this->setFixedSize(200, 42); - this->setModal(true); +void KeyServerImportDialog::slotSaveWindowState() { + LOG(INFO) << _("Called"); + + if (mAutomatic) return; + + auto& settings = + GpgFrontend::UI::GlobalSettingStation::GetInstance().GetUISettings(); + + if (!settings.exists("window") || + settings.lookup("window").getType() != libconfig::Setting::TypeGroup) + settings.add("window", libconfig::Setting::TypeGroup); + + auto& window = settings["window"]; + + if (!window.exists("import_from_keyserver") || + window.lookup("import_from_keyserver").getType() != + libconfig::Setting::TypeGroup) + window.add("import_from_keyserver", libconfig::Setting::TypeGroup); + + auto& import_from_keyserver = window["import_from_keyserver"]; + + if (!import_from_keyserver.exists("position") || + import_from_keyserver.lookup("position").getType() != + libconfig::Setting::TypeGroup) { + auto& position = + import_from_keyserver.add("position", libconfig::Setting::TypeGroup); + position.add("x", libconfig::Setting::TypeInt) = pos().x(); + position.add("y", libconfig::Setting::TypeInt) = pos().y(); + } else { + import_from_keyserver["position"]["x"] = pos().x(); + import_from_keyserver["position"]["y"] = pos().y(); + } + + if (!import_from_keyserver.exists("size") || + import_from_keyserver.lookup("size").getType() != + libconfig::Setting::TypeGroup) { + auto& size = + import_from_keyserver.add("size", libconfig::Setting::TypeGroup); + size.add("width", libconfig::Setting::TypeInt) = QWidget::width(); + size.add("height", libconfig::Setting::TypeInt) = QWidget::height(); + } else { + import_from_keyserver["size"]["width"] = QWidget::width(); + import_from_keyserver["size"]["height"] = QWidget::height(); + } + + GlobalSettingStation::GetInstance().Sync(); } + +} // namespace GpgFrontend::UI diff --git a/src/ui/KeyServerImportDialog.h b/src/ui/KeyServerImportDialog.h new file mode 100644 index 00000000..67571f2f --- /dev/null +++ b/src/ui/KeyServerImportDialog.h @@ -0,0 +1,93 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef __KEY_SERVER_IMPORT_DIALOG_H__ +#define __KEY_SERVER_IMPORT_DIALOG_H__ + +#include "KeyImportDetailDialog.h" +#include "gpg/GpgContext.h" +#include "ui/GpgFrontendUI.h" +#include "ui/widgets/KeyList.h" + +namespace GpgFrontend::UI { + +class KeyServerImportDialog : public QDialog { + Q_OBJECT + + public: + KeyServerImportDialog(bool automatic, QWidget* parent); + + KeyServerImportDialog(QWidget* parent); + + void slotImport(const KeyIdArgsListPtr& keys); + + void slotImport(const QStringList& keyIds, const QUrl& keyserverUrl); + + signals: + void signalKeyImported(); + + private slots: + + void slotImport(); + + void slotSearchFinished(); + + void slotImportFinished(QString keyid); + + void slotSearch(); + + void slotSaveWindowState(); + + private: + void createKeysTable(); + + void setMessage(const QString& text, bool error); + + void importKeys(ByteArrayPtr in_data); + + void setLoading(bool status); + + QPushButton* createButton(const QString& text, const char* member); + + QComboBox* createComboBox(); + + bool mAutomatic = false; + + QLineEdit* searchLineEdit{}; + QComboBox* keyServerComboBox{}; + QProgressBar* waitingBar; + QLabel* searchLabel{}; + QLabel* keyServerLabel{}; + QLabel* message{}; + QLabel* icon{}; + QPushButton* closeButton{}; + QPushButton* importButton{}; + QPushButton* searchButton{}; + QTableWidget* keysTable{}; + QNetworkAccessManager* qnam{}; +}; + +} // namespace GpgFrontend::UI + +#endif // __KEY_SERVER_IMPORT_DIALOG_H__ diff --git a/src/ui/KeyUploadDialog.cpp b/src/ui/KeyUploadDialog.cpp index ab38569f..b2bfff6d 100644 --- a/src/ui/KeyUploadDialog.cpp +++ b/src/ui/KeyUploadDialog.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -24,105 +24,117 @@ #include "ui/KeyUploadDialog.h" -KeyUploadDialog::KeyUploadDialog(GpgME::GpgContext *ctx, const QVector<GpgKey> &keys, QWidget *parent) - : appPath(qApp->applicationDirPath()), - settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", QSettings::IniFormat), - mCtx(ctx), - mKeys(keys), - QDialog(parent) { - - - auto *pb = new QProgressBar(); - pb->setRange(0, 0); - pb->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); - pb->setTextVisible(false); - - auto *layout = new QVBoxLayout(); - layout->addWidget(pb); - layout->setContentsMargins(0, 0, 0, 0); - layout->setSpacing(0); - this->setLayout(layout); - - this->setModal(true); - this->setWindowTitle(tr("Uploading Public Key")); - this->setFixedSize(240, 42); +#include <algorithm> + +#include "gpg/function/GpgKeyGetter.h" +#include "gpg/function/GpgKeyImportExportor.h" + +namespace GpgFrontend::UI { + +KeyUploadDialog::KeyUploadDialog(const KeyIdArgsListPtr& keys_ids, + QWidget* parent) + : QDialog(parent), + appPath(qApp->applicationDirPath()), + settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", + QSettings::IniFormat), + mKeys(GpgKeyGetter::GetInstance().GetKeys(keys_ids)) { + auto* pb = new QProgressBar(); + pb->setRange(0, 0); + pb->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + pb->setTextVisible(false); + + auto* layout = new QVBoxLayout(); + layout->addWidget(pb); + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(0); + this->setLayout(layout); + + this->setModal(true); + this->setWindowTitle(_("Uploading Public Key")); + this->setFixedSize(240, 42); } void KeyUploadDialog::slotUpload() { - mCtx->exportKeys(mKeys, mKeyData); - uploadKeyToServer(mKeyData); + auto out_data = std::make_unique<ByteArray>(); + GpgKeyImportExportor::GetInstance().ExportKeys(*mKeys, out_data); + uploadKeyToServer(*out_data); } -void KeyUploadDialog::uploadKeyToServer(QByteArray &keys) { +void KeyUploadDialog::uploadKeyToServer( + const GpgFrontend::ByteArray& keys_data) { + // set default keyserver + QString keyserver = settings.value("keyserver/defaultKeyServer").toString(); - // set default keyserver - QString keyserver = settings.value("keyserver/defaultKeyServer").toString(); + QUrl reqUrl(keyserver + "/pks/add"); + auto qnam = new QNetworkAccessManager(this); - QUrl reqUrl(keyserver + "/pks/add"); - auto qnam = new QNetworkAccessManager(this); + // Building Post Data + QByteArray postData; - // Building Post Data - QByteArray postData; + auto data = std::string(keys_data); - keys.replace("\n", "%0A") - .replace("\r", "%0D") - .replace("(", "%28") - .replace(")", "%29") - .replace("/", "%2F") - .replace(":", "%3A") - .replace("+", "%2B") - .replace('=', "%3D") - .replace(' ', '+'); + boost::algorithm::replace_all(data, "\n", "%0A"); + boost::algorithm::replace_all(data, "\r", "%0D"); + boost::algorithm::replace_all(data, "(", "%28"); + boost::algorithm::replace_all(data, ")", "%29"); + boost::algorithm::replace_all(data, "/", "%2F"); + boost::algorithm::replace_all(data, ":", "%3A"); + boost::algorithm::replace_all(data, "+", "%2B"); + boost::algorithm::replace_all(data, "=", "%3D"); + boost::algorithm::replace_all(data, " ", "+"); - QNetworkRequest request(reqUrl); - request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); + QNetworkRequest request(reqUrl); + request.setHeader(QNetworkRequest::ContentTypeHeader, + "application/x-www-form-urlencoded"); - postData.append("keytext").append("=").append(keys); + postData.append("keytext").append("=").append( + QString::fromStdString(data).toUtf8()); - // Send Post Data - QNetworkReply *reply = qnam->post(request, postData); - connect(reply, SIGNAL(finished()), - this, SLOT(slotUploadFinished())); + // Send Post Data + QNetworkReply* reply = qnam->post(request, postData); + connect(reply, SIGNAL(finished()), this, SLOT(slotUploadFinished())); + // Keep Waiting + while (reply->isRunning()) { + QApplication::processEvents(); + } - // Keep Waiting - while(reply->isRunning()) { - QApplication::processEvents(); - } - - // Done - this->hide(); - this->close(); + // Done + this->hide(); + this->close(); } void KeyUploadDialog::slotUploadFinished() { - auto *reply = qobject_cast<QNetworkReply *>(sender()); - - QByteArray response = reply->readAll(); - qDebug() << "Response: " << response.data(); - - auto error = reply->error(); - if (error != QNetworkReply::NoError) { - qDebug() << "Error From Reply" << reply->errorString(); - QString message; - switch (error) { - case QNetworkReply::ContentNotFoundError : - message = tr("Key Not Found"); - break; - case QNetworkReply::TimeoutError : - message = tr("Timeout"); - break; - case QNetworkReply::HostNotFoundError : - message = tr("Key Server Not Found"); - break; - default: - message = tr("Connection Error"); - } - QMessageBox::critical(this, "Upload Failed", message); - return; - } else { - QMessageBox::information(this, "Upload Success", "Upload Public Key Successfully"); - qDebug() << "Success while contacting keyserver!"; + auto* reply = qobject_cast<QNetworkReply*>(sender()); + + QByteArray response = reply->readAll(); + qDebug() << "Response: " << response.data(); + + auto error = reply->error(); + if (error != QNetworkReply::NoError) { + qDebug() << "Error From Reply" << reply->errorString(); + QString message; + switch (error) { + case QNetworkReply::ContentNotFoundError: + message = _("Key Not Found"); + break; + case QNetworkReply::TimeoutError: + message = _("Timeout"); + break; + case QNetworkReply::HostNotFoundError: + message = _("Key Server Not Found"); + break; + default: + message = _("Connection Error"); } - reply->deleteLater(); + QMessageBox::critical(this, "Upload Failed", message); + return; + } else { + QMessageBox::information(this, "Upload Success", + "Upload Public Key Successfully"); + qDebug() << "Success while contacting keyserver!"; + } + reply->deleteLater(); } + +} // namespace GpgFrontend::UI diff --git a/src/ui/KeyUploadDialog.h b/src/ui/KeyUploadDialog.h new file mode 100644 index 00000000..b607c321 --- /dev/null +++ b/src/ui/KeyUploadDialog.h @@ -0,0 +1,57 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_KEYUPLOADWIDGET_H +#define GPGFRONTEND_KEYUPLOADWIDGET_H + +#include "gpg/GpgContext.h" +#include "ui/GpgFrontendUI.h" + +namespace GpgFrontend::UI { + +class KeyUploadDialog : public QDialog { + Q_OBJECT + public: + explicit KeyUploadDialog(const KeyIdArgsListPtr& keys_ids, QWidget* parent); + + public slots: + + void slotUpload(); + + private slots: + + void uploadKeyToServer(const GpgFrontend::ByteArray& keys_data); + + void slotUploadFinished(); + + private: + QString appPath; + QSettings settings; + KeyListPtr mKeys; + QByteArray mKeyData; +}; + +} // namespace GpgFrontend::UI + +#endif // GPGFRONTEND_KEYUPLOADWIDGET_H diff --git a/src/ui/MainWindow.cpp b/src/ui/MainWindow.cpp new file mode 100644 index 00000000..6b0977fd --- /dev/null +++ b/src/ui/MainWindow.cpp @@ -0,0 +1,380 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#include "MainWindow.h" + +#include "ui/UserInterfaceUtils.h" +#ifdef RELEASE +#include "ui/function/VersionCheckThread.h" +#endif +#include "ui/settings/GlobalSettingStation.h" + +namespace GpgFrontend::UI { + +MainWindow::MainWindow() { + this->setMinimumSize(1200, 700); + this->setWindowTitle(qApp->applicationName()); +} + +void MainWindow::init() noexcept { + try { + // Check Context Status + if (!GpgContext::GetInstance().good()) { + QMessageBox::critical( + nullptr, _("ENV Loading Failed"), + _("Gnupg is not installed correctly, please follow the ReadME " + "instructions to install gnupg and then open GpgFrontend.")); + QCoreApplication::quit(); + exit(0); + } + + networkAccessManager = new QNetworkAccessManager(this); + + /* get path were app was started */ + setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea); + setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea); + + edit = new TextEdit(this); + setCentralWidget(edit); + + /* the list of Keys available*/ + mKeyList = new KeyList(KeyListRow::SECRET_OR_PUBLIC_KEY, + KeyListColumn::TYPE | KeyListColumn::NAME | + KeyListColumn::EmailAddress | + KeyListColumn::Usage | KeyListColumn::Validity, + this); + mKeyList->setFilter([](const GpgKey& key) -> bool { + return !(key.revoked() || key.disabled() || key.expired()); + }); + + mKeyList->slotRefresh(); + + infoBoard = new InfoBoardWidget(this, mKeyList); + + /* List of binary Attachments */ + attachmentDockCreated = false; + + /* Variable containing if restart is needed */ + this->slotSetRestartNeeded(false); + + createActions(); + createMenus(); + createToolBars(); + createStatusBar(); + createDockWindows(); + + connect(edit->tabWidget, SIGNAL(currentChanged(int)), this, + SLOT(slotDisableTabActions(int))); + + mKeyList->addMenuAction(appendSelectedKeysAct); + mKeyList->addMenuAction(copyMailAddressToClipboardAct); + mKeyList->addMenuAction(showKeyDetailsAct); + mKeyList->addSeparator(); + mKeyList->addMenuAction(refreshKeysFromKeyserverAct); + mKeyList->addMenuAction(uploadKeyToServerAct); + + restoreSettings(); + + // open filename if provided as first command line parameter + QStringList args = qApp->arguments(); + if (args.size() > 1) { + if (!args[1].startsWith("-")) { + if (QFile::exists(args[1])) edit->loadFile(args[1]); + } + } + edit->curTextPage()->setFocus(); + + auto& settings = GlobalSettingStation::GetInstance().GetUISettings(); + + if (!settings.exists("wizard") || + settings.lookup("wizard").getType() != libconfig::Setting::TypeGroup) + settings.add("wizard", libconfig::Setting::TypeGroup); + + auto& wizard = settings["wizard"]; + + // Show wizard, if the don't show wizard message box wasn't checked + // and keylist doesn't contain a private key + + if (!wizard.exists("show_wizard")) + wizard.add("show_wizard", libconfig::Setting::TypeBoolean) = true; + + bool show_wizard = true; + wizard.lookupValue("show_wizard", show_wizard); + + LOG(INFO) << "wizard show_wizard" << show_wizard; + + if (show_wizard) { + slotStartWizard(); + } + + emit loaded(); + +#ifdef RELEASE + QString baseUrl = + "https://api.github.com/repos/saturneric/gpgfrontend/releases/latest"; + QNetworkRequest request; + request.setUrl(QUrl(baseUrl)); + auto* replay = networkAccessManager->get(request); + auto version_thread = new VersionCheckThread(replay); + + connect(version_thread, SIGNAL(finished()), version_thread, + SLOT(deleteLater())); + connect(version_thread, + SIGNAL(upgradeVersion(const QString&, const QString&)), this, + SLOT(slotVersionUpgrade(const QString&, const QString&))); + + version_thread->start(); +#endif + } catch (...) { + LOG(FATAL) << _("Critical error occur while loading GpgFrontend."); + QMessageBox::critical(nullptr, _("Loading Failed"), + _("Critical error occur while loading GpgFrontend.")); + QCoreApplication::quit(); + exit(0); + } +} + +void MainWindow::restoreSettings() { + try { + auto& settings = GlobalSettingStation::GetInstance().GetUISettings(); + + if (!settings.exists("window") || + settings.lookup("window").getType() != libconfig::Setting::TypeGroup) + settings.add("window", libconfig::Setting::TypeGroup); + + auto& window = settings["window"]; + + if (!window.exists("window_state")) + window.add("window_state", libconfig::Setting::TypeString) = + saveState().toBase64().toStdString(); + + std::string window_state = settings.lookup("window.window_state"); + // state sets pos & size of dock-widgets + this->restoreState( + QByteArray::fromBase64(QByteArray::fromStdString(window_state))); + + if (!window.exists("window_save")) + window.add("window_save", libconfig::Setting::TypeBoolean) = true; + + bool window_save; + window.lookupValue("window_save", window_save); + + // Restore window size & location + if (window_save) { + if (!window.exists("window_pos")) + window.add("window_pos", libconfig::Setting::TypeGroup); + + auto& window_pos = window["window_pos"]; + + if (!window_pos.exists("x")) + window_pos.add("x", libconfig::Setting::TypeInt) = 100; + + if (!window_pos.exists("y")) + window_pos.add("y", libconfig::Setting::TypeInt) = 100; + + int x, y; + window_pos.lookupValue("x", x); + window_pos.lookupValue("y", y); + + auto pos = QPoint(x, y); + + if (!window.exists("window_size")) + window.add("window_size", libconfig::Setting::TypeGroup); + + auto& window_size = window["window_size"]; + + if (!window_size.exists("width")) + window_size.add("width", libconfig::Setting::TypeInt) = 800; + + if (!window_size.exists("height")) + window_size.add("height", libconfig::Setting::TypeInt) = 450; + + int width, height; + window_size.lookupValue("width", width); + window_size.lookupValue("height", height); + + auto size = QSize(width, height); + this->resize(size); + this->move(pos); + } else { + this->resize(QSize(800, 450)); + this->move(QPoint(100, 100)); + } + + if (!window.exists("icon_size")) + window.add("icon_size", libconfig::Setting::TypeGroup); + + auto& icon_size = window["icon_size"]; + + if (!icon_size.exists("width")) + icon_size.add("width", libconfig::Setting::TypeInt) = 24; + + if (!icon_size.exists("height")) + icon_size.add("height", libconfig::Setting::TypeInt) = 24; + + int width = icon_size["width"], height = icon_size["height"]; + LOG(INFO) << "icon_size" << width << height; + + // info board font size + if (!window.exists("info_font_size")) + window.add("info_font_size", libconfig::Setting::TypeInt) = 10; + + // icons ize + this->setIconSize(QSize(width, height)); + importButton->setIconSize(QSize(width, height)); + fileEncButton->setIconSize(QSize(width, height)); + + if (!settings.exists("keyserver") || + settings.lookup("keyserver").getType() != libconfig::Setting::TypeGroup) + settings.add("keyserver", libconfig::Setting::TypeGroup); + + auto& keyserver = settings["keyserver"]; + + if (!keyserver.exists("server_list")) { + keyserver.add("server_list", libconfig::Setting::TypeList); + + auto& server_list = keyserver["server_list"]; + server_list.add(libconfig::Setting::TypeString) = "http://keys.gnupg.net"; + server_list.add(libconfig::Setting::TypeString) = + "https://keyserver.ubuntu.com"; + server_list.add(libconfig::Setting::TypeString) = + "http://pool.sks-keyservers.net"; + } + + if (!keyserver.exists("default_server")) { + keyserver.add("default_server", libconfig::Setting::TypeString) = + "https://keyserver.ubuntu.com"; + } + + if (!window.exists("icon_style")) { + window.add("icon_style", libconfig::Setting::TypeInt) = + Qt::ToolButtonTextUnderIcon; + } + + int s_icon_style = window.lookup("icon_style"); + + // icon_style + auto icon_style = static_cast<Qt::ToolButtonStyle>(s_icon_style); + this->setToolButtonStyle(icon_style); + importButton->setToolButtonStyle(icon_style); + fileEncButton->setToolButtonStyle(icon_style); + + if (!settings.exists("general") || + settings.lookup("general").getType() != libconfig::Setting::TypeGroup) + settings.add("general", libconfig::Setting::TypeGroup); + + auto& general = settings["general"]; + + if (!general.exists("save_key_checked")) { + general.add("save_key_checked", libconfig::Setting::TypeBoolean) = true; + } + + bool save_key_checked = true; + general.lookupValue("save_key_checked", save_key_checked); + + // Checked Keys + if (save_key_checked) { + if (!general.exists("save_key_checked_key_ids")) { + general.add("save_key_checked_key_ids", libconfig::Setting::TypeList); + } + auto key_ids_ptr = std::make_unique<KeyIdArgsList>(); + ; + auto& save_key_checked_key_ids = general["save_key_checked_key_ids"]; + const auto key_ids_size = + general.lookup("save_key_checked_key_ids").getLength(); + for (auto i = 0; i < key_ids_size; i++) { + std::string key_id = save_key_checked_key_ids[i]; + key_ids_ptr->push_back(key_id); + } + mKeyList->setChecked(key_ids_ptr); + } + } catch (...) { + LOG(ERROR) << "cannot resolve settings"; + } + + GlobalSettingStation::GetInstance().Sync(); +} + +void MainWindow::saveSettings() { + auto& settings = GlobalSettingStation::GetInstance().GetUISettings(); + + try { + // window position and size + settings["window"]["window_state"] = saveState().toBase64().toStdString(); + settings["window"]["window_pos"]["x"] = pos().x(); + settings["window"]["window_pos"]["y"] = pos().y(); + + settings["window"]["window_size"]["width"] = size().width(); + settings["window"]["window_size"]["height"] = size().height(); + + bool save_key_checked = settings.lookup("general.save_key_checked"); + + // keyid-list of private checked keys + if (save_key_checked) { + auto& key_ids = settings.lookup("general.save_key_checked_key_ids"); + const int key_ids_size = key_ids.getLength(); + for (auto i = 0; i < key_ids_size; i++) key_ids.remove(i); + auto key_ids_need_to_store = mKeyList->getChecked(); + + for (size_t i = 0; i < key_ids_need_to_store->size(); i++) { + std::string key_id = (*key_ids_need_to_store)[i]; + key_ids.add(libconfig::Setting::TypeString) = key_id; + } + + } else { + settings["general"].remove("save_key_checked"); + } + } catch (...) { + LOG(ERROR) << "cannot save settings"; + }; + + GlobalSettingStation::GetInstance().Sync(); +} + +void MainWindow::closeAttachmentDock() { + if (!attachmentDockCreated) { + return; + } + attachmentDock->close(); + attachmentDock->deleteLater(); + attachmentDockCreated = false; +} + +void MainWindow::closeEvent(QCloseEvent* event) { + /* + * ask to save changes, if there are + * modified documents in any tab + */ + if (edit->maybeSaveAnyTab()) { + saveSettings(); + event->accept(); + } else { + event->ignore(); + } + + // clear password from memory + // GpgContext::GetInstance().clearPasswordCache(); +} + +} // namespace GpgFrontend::UI diff --git a/src/ui/MainWindow.h b/src/ui/MainWindow.h new file mode 100644 index 00000000..e0bf9f5a --- /dev/null +++ b/src/ui/MainWindow.h @@ -0,0 +1,437 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef __GPGWIN_H__ +#define __GPGWIN_H__ + +#include "gpg/GpgConstants.h" +#include "gpg/result_analyse/DecryptResultAnalyse.h" +#include "gpg/result_analyse/EncryptResultAnalyse.h" +#include "gpg/result_analyse/SignResultAnalyse.h" +#include "ui/FileEncryptionDialog.h" +#include "ui/FindWidget.h" +#include "ui/GpgFrontendUI.h" +#include "ui/KeyMgmt.h" +#include "ui/KeyUploadDialog.h" +#include "ui/WaitingDialog.h" +#include "ui/Wizard.h" +#include "ui/help/AboutDialog.h" +#include "ui/settings/SettingsDialog.h" +#include "ui/widgets/InfoBoardWidget.h" +#include "ui/widgets/TextEdit.h" + +namespace GpgFrontend::UI { +/** + * @brief + * + */ +class MainWindow : public QMainWindow { + Q_OBJECT + + public: + /** + * @brief + * + */ + MainWindow(); + + /** + * ONLY Called from main() + */ + void init() noexcept; + + signals: + void loaded(); + + public slots: + + void slotSetStatusBarText(const QString& text); + + protected: + /** + * @details Close event shows a save dialog, if there are unsaved documents on + * exit. + * @param event + */ + void closeEvent(QCloseEvent* event) override; + + public slots: + + /** + * @details Open a new tab for path + */ + void slotOpenFile(QString& path); + + /** + * @details Open dialog for encrypting file. + */ + void slotFileEncrypt(); + + /** + * @details Open dialog for decrypting file. + */ + void slotFileDecrypt(); + + /** + * @details Open dialog for signing file. + */ + void slotFileSign(); + + /** + * @details Open dialog for verifying file. + */ + void slotFileVerify(); + + /** + * @details Open dialog for signing file. + */ + void slotFileEncryptSign(); + + /** + * @details Open dialog for verifying file. + */ + void slotFileDecryptVerify(); + + private slots: + + /** + * @details encrypt the text of currently active textedit-page + * with the currently checked keys + */ + void slotEncrypt(); + + /** + * @details encrypt and sign the text of currently active textedit-page + * with the currently checked keys + */ + void slotEncryptSign(); + + /** + * @details Show a passphrase dialog and decrypt the text of currently active + * tab. + */ + void slotDecrypt(); + + /** + * @details Sign the text of currently active tab with the checked private + * keys + */ + void slotSign(); + + /** + * @details Verify the text of currently active tab and show verify + * information. If document is signed with a key, which is not in keylist, + * show import missing key from keyserver in Menu of verifynotification. + */ + void slotVerify(); + + /** + * @details decrypt and verify the text of currently active textedit-page + * with the currently checked keys + */ + void slotDecryptVerify(); + + /** + * @details Open dialog for encrypting file. + */ + void slotFileEncryptCustom(); + + /** + * @details Open dialog for decrypting file. + */ + void slotFileDecryptCustom(); + + /** + * @details Open dialog for signing file. + */ + void slotFileSignCustom(); + + /** + * @details Open dialog for verifying file. + */ + void slotFileVerifyCustom(); + + /** + * @details Show the details of the first of the first of selected keys + */ + void slotShowKeyDetails(); + + /** + * @details Refresh key information of selected keys from default keyserver + */ + void refreshKeysFromKeyserver(); + + /** + * @details upload the selected key to the keyserver + */ + void uploadKeyToServer(); + + /** + * @details Open find widget. + */ + void slotFind(); + + /** + * @details start the wizard + */ + void slotStartWizard(); + + /** + * @details Import keys from currently active tab to keylist if possible. + */ + void slotImportKeyFromEdit(); + + /** + * @details Append the selected keys to currently active textedit. + */ + void slotAppendSelectedKeys(); + + /** + * @details Copy the mailaddress of selected key to clipboard. + * Method for keylists contextmenu. + */ + void slotCopyMailAddressToClipboard(); + + /** + * @details Open key management dialog. + */ + void slotOpenKeyManagement(); + + /** + * @details Open about-dialog. + */ + void slotAbout(); + + /** + * @details Open check-update-tab in about-dialog. + */ + void slotCheckUpdate(); + + /** + * @details Open File Opera Tab + */ + void slotOpenFileTab(); + + /** + * @details Open settings-dialog. + */ + void slotOpenSettingsDialog(); + + // /** + // * @details Show a warn message in status bar, if there are files in + // * attachment folder. + // */ + // void slotCheckAttachmentFolder(); + + /** + * @details Replace double linebreaks by single linebreaks in currently active + * tab. + */ + void slotCleanDoubleLinebreaks(); + + /** + * @details Cut the existing PGP header and footer from current tab. + */ + void slotCutPgpHeader(); + + /** + * @details Add PGP header and footer to current tab. + */ + void slotAddPgpHeader(); + + /** + * @details Disable tab related actions, if number of tabs is 0. + * @param number number of the opened tabs and -1, if no tab is opened + */ + void slotDisableTabActions(int number); + + /** + * @details get value of member restartNeeded to needed. + * @param needed true, if application has to be restarted + */ + void slotSetRestartNeeded(bool needed); + + /** + * @details called when need to upgrade. + */ + void slotVersionUpgrade(const QString& currentVersion, + const QString& latestVersion); + + private: + /** + * @details Create actions for the main-menu and the context-menu of the + * keylist. + */ + void createActions(); + + /** + * @details create the menu of the main-window. + */ + void createMenus(); + + /** + * @details Create edit-, crypt- and key-toolbars. + */ + void createToolBars(); + + /** + * @details Create statusbar of mainwindow. + */ + void createStatusBar(); + + /** + * @details Create keylist- and attachment-dockwindows. + */ + void createDockWindows(); + + /** + * @details Create attachment-dockwindow. + */ + void createAttachmentDock(); + + /** + * @details close attachment-dockwindow. + */ + void closeAttachmentDock(); + + /** + * @details Load settings from ini-file. + */ + void restoreSettings(); + + /** + * @details Save settings to ini-file. + */ + void saveSettings(); + +#ifdef ADVANCE_SUPPORT + + /** + * @details Get full crypto text + */ + QString getCryptText(const QString& shortenCryptoText); + + /** + * @details Shorten crypto text + */ + void shortenCryptText(); + +#endif + + /** + * @brief return true, if restart is needed + */ + [[nodiscard]] bool getRestartNeeded() const; + + TextEdit* edit{}; /** Tabwidget holding the edit-windows */ + QMenu* fileMenu{}; /** Submenu for file-operations*/ + QMenu* editMenu{}; /** Submenu for text-operations*/ + QMenu* cryptMenu{}; /** Submenu for crypt-operations */ + QMenu* fileEncMenu{}; /** Submenu for file crypt operations */ + QMenu* helpMenu{}; /** Submenu for help-operations */ + QMenu* keyMenu{}; /** Submenu for key-operations */ + QMenu* viewMenu{}; /** Submenu for view operations */ + QMenu* importKeyMenu{}; /** Sumenu for import operations */ + QMenu* steganoMenu{}; /** Submenu for steganographic operations*/ + QToolBar* cryptToolBar{}; /** Toolbar holding crypt actions */ + QToolBar* fileToolBar{}; /** Toolbar holding file actions */ + QToolBar* editToolBar{}; /** Toolbar holding edit actions */ + QToolBar* specialEditToolBar{}; /** Toolbar holding special edit actions */ + QToolBar* keyToolBar{}; /** Toolbar holding key operations */ + QToolButton* + importButton{}; /** Toolbutton for import dropdown menu in toolbar */ + QToolButton* fileEncButton{}; /** Toolbutton for file cryption dropdown menu + in toolbar */ + QDockWidget* keyListDock{}; /** Encrypt Dock*/ + QDockWidget* attachmentDock{}; /** Attachment Dock */ + QDockWidget* infoBoardDock{}; + + QAction* newTabAct{}; /** Action to create new tab */ + QAction* switchTabUpAct{}; /** Action to switch tab up*/ + QAction* switchTabDownAct{}; /** Action to switch tab down */ + QAction* openAct{}; /** Action to open file */ + QAction* browserAct{}; /** Action to open file browser*/ + QAction* saveAct{}; /** Action to save file */ + QAction* saveAsAct{}; /** Action to save file as */ + QAction* printAct{}; /** Action to print */ + QAction* closeTabAct{}; /** Action to print */ + QAction* quitAct{}; /** Action to quit application */ + QAction* encryptAct{}; /** Action to encrypt text */ + QAction* encryptSignAct{}; /** Action to encrypt and sign text */ + QAction* decryptVerifyAct{}; /** Action to encrypt and sign text */ + QAction* decryptAct{}; /** Action to decrypt text */ + QAction* signAct{}; /** Action to sign text */ + QAction* verifyAct{}; /** Action to verify text */ + QAction* importKeyFromEditAct{}; /** Action to import key from edit */ + QAction* + cleanDoubleLinebreaksAct{}; /** Action to remove double line breaks */ + + QAction* + appendSelectedKeysAct{}; /** Action to append selected keys to edit */ + QAction* + copyMailAddressToClipboardAct{}; /** Action to copy mail to clipboard */ + QAction* openKeyManagementAct{}; /** Action to open key management */ + QAction* copyAct{}; /** Action to copy text */ + QAction* quoteAct{}; /** Action to quote text */ + QAction* cutAct{}; /** Action to cut text */ + QAction* pasteAct{}; /** Action to paste text */ + QAction* selectAllAct{}; /** Action to select whole text */ + QAction* findAct{}; /** Action to find text */ + QAction* undoAct{}; /** Action to undo last action */ + QAction* redoAct{}; /** Action to redo last action */ + QAction* zoomInAct{}; /** Action to zoom in */ + QAction* zoomOutAct{}; /** Action to zoom out */ + QAction* aboutAct{}; /** Action to open about dialog */ + QAction* checkUpdateAct{}; /** Action to open about dialog */ + QAction* fileEncryptAct{}; /** Action to open dialog for encrypting file */ + QAction* fileDecryptAct{}; /** Action to open dialog for decrypting file */ + QAction* fileSignAct{}; /** Action to open dialog for signing file */ + QAction* fileVerifyAct{}; /** Action to open dialog for verifying file */ + QAction* openSettingsAct{}; /** Action to open settings dialog */ + QAction* showKeyDetailsAct{}; /** Action to open key-details dialog */ + QAction* refreshKeysFromKeyserverAct{}; /** Action to refresh a key from + keyserver */ + QAction* uploadKeyToServerAct{}; /** Action to append selected keys to edit */ + QAction* startWizardAct{}; /** Action to open the wizard */ + QAction* cutPgpHeaderAct{}; /** Action for cutting the PGP header */ + QAction* addPgpHeaderAct{}; /** Action for adding the PGP header */ + + QAction* importKeyFromFileAct{}; + QAction* importKeyFromClipboardAct{}; + QAction* importKeyFromKeyServerAct{}; + + QLabel* statusBarIcon{}; /**< TODO */ + + KeyList* mKeyList{}; + InfoBoardWidget* infoBoard{}; + + QNetworkAccessManager* networkAccessManager{}; + + bool attachmentDockCreated{}; + bool restartNeeded{}; +}; + +} // namespace GpgFrontend::UI + +#endif // __GPGWIN_H__ diff --git a/src/ui/QuitDialog.cpp b/src/ui/QuitDialog.cpp index 783a8a61..a5ed7c3f 100755 --- a/src/ui/QuitDialog.cpp +++ b/src/ui/QuitDialog.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -24,109 +24,118 @@ #include "ui/QuitDialog.h" -QuitDialog::QuitDialog(QWidget *parent, const QHash<int, QString>& unsavedDocs) - : QDialog(parent) { - setWindowTitle(tr("Unsaved Files")); - setModal(true); - discarded = false; - - /* - * Table of unsaved documents - */ - QHashIterator<int, QString> i(unsavedDocs); - int row = 0; - mFileList = new QTableWidget(this); - mFileList->horizontalHeader()->hide(); - mFileList->setColumnCount(3); - mFileList->setColumnWidth(0, 20); - mFileList->setColumnHidden(2, true); - mFileList->verticalHeader()->hide(); - mFileList->setShowGrid(false); - mFileList->setEditTriggers(QAbstractItemView::NoEditTriggers); - mFileList->setFocusPolicy(Qt::NoFocus); - mFileList->horizontalHeader()->setStretchLastSection(true); - // fill the table - i.toFront(); //jump to the end of list to fill the table backwards - while (i.hasNext()) { - i.next(); - mFileList->setRowCount(mFileList->rowCount() + 1); - - // checkbox in front of filename - auto *tmp0 = new QTableWidgetItem(); - tmp0->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled); - tmp0->setCheckState(Qt::Checked); - mFileList->setItem(row, 0, tmp0); - - // filename - auto *tmp1 = new QTableWidgetItem(i.value()); - mFileList->setItem(row, 1, tmp1); - - // tab-index in hidden column - auto *tmp2 = new QTableWidgetItem(QString::number(i.key())); - mFileList->setItem(row, 2, tmp2); - ++row; - } - /* - * Warnbox with icon and text - */ - auto pixmap = QPixmap(":error.png"); - pixmap = pixmap.scaled(50, 50, Qt::KeepAspectRatio, Qt::SmoothTransformation); - auto *warn_icon = new QLabel(); - warn_icon->setPixmap(pixmap); - auto *warn_label = new QLabel( - tr("%1 files contain unsaved information.<br/>Save the changes before closing?").arg(row)); - auto *warnBoxLayout = new QHBoxLayout(); - warnBoxLayout->addWidget(warn_icon); - warnBoxLayout->addWidget(warn_label); - warnBoxLayout->setAlignment(Qt::AlignLeft); - auto *warnBox = new QWidget(this); - warnBox->setLayout(warnBoxLayout); - - /* - * Two labels on top and under the filelist - */ - auto *checkLabel = new QLabel(tr("Check the files you want to save:")); - auto *note_label = new QLabel(tr("<b>Note:</b> If you don't save these files, all changes are lost.<br/>")); - - /* - * Buttonbox - */ - auto *buttonBox = new QDialogButtonBox( - QDialogButtonBox::Discard | QDialogButtonBox::Save | QDialogButtonBox::Cancel); - connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); - QPushButton *btnNoKey = buttonBox->button(QDialogButtonBox::Discard); - connect(btnNoKey, SIGNAL(clicked()), SLOT(slotMyDiscard())); - - /* - * Set the layout - */ - auto *vbox = new QVBoxLayout(); - vbox->addWidget(warnBox); - vbox->addWidget(checkLabel); - vbox->addWidget(mFileList); - vbox->addWidget(note_label); - vbox->addWidget(buttonBox); - this->setLayout(vbox); -} +#include <boost/format.hpp> +namespace GpgFrontend::UI { -void QuitDialog::slotMyDiscard() { - discarded = true; - reject(); +QuitDialog::QuitDialog(QWidget* parent, const QHash<int, QString>& unsavedDocs) + : QDialog(parent) { + setWindowTitle(_("Unsaved Files")); + setModal(true); + discarded = false; + + /* + * Table of unsaved documents + */ + QHashIterator<int, QString> i(unsavedDocs); + int row = 0; + mFileList = new QTableWidget(this); + mFileList->horizontalHeader()->hide(); + mFileList->setColumnCount(3); + mFileList->setColumnWidth(0, 20); + mFileList->setColumnHidden(2, true); + mFileList->verticalHeader()->hide(); + mFileList->setShowGrid(false); + mFileList->setEditTriggers(QAbstractItemView::NoEditTriggers); + mFileList->setFocusPolicy(Qt::NoFocus); + mFileList->horizontalHeader()->setStretchLastSection(true); + // fill the table + i.toFront(); // jump to the end of list to fill the table backwards + while (i.hasNext()) { + i.next(); + mFileList->setRowCount(mFileList->rowCount() + 1); + + // checkbox in front of filename + auto* tmp0 = new QTableWidgetItem(); + tmp0->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled); + tmp0->setCheckState(Qt::Checked); + mFileList->setItem(row, 0, tmp0); + + // filename + auto* tmp1 = new QTableWidgetItem(i.value()); + mFileList->setItem(row, 1, tmp1); + + // tab-index in hidden column + auto* tmp2 = new QTableWidgetItem(QString::number(i.key())); + mFileList->setItem(row, 2, tmp2); + ++row; + } + /* + * Warnbox with icon and text + */ + auto pixmap = QPixmap(":error.png"); + pixmap = pixmap.scaled(50, 50, Qt::KeepAspectRatio, Qt::SmoothTransformation); + auto* warn_icon = new QLabel(); + warn_icon->setPixmap(pixmap); + + const auto info = + boost::format(_("%1% files contain unsaved information.<br/>Save the " + "changes before closing?")) % + std::to_string(row); + auto* warn_label = new QLabel(QString::fromStdString(info.str())); + auto* warnBoxLayout = new QHBoxLayout(); + warnBoxLayout->addWidget(warn_icon); + warnBoxLayout->addWidget(warn_label); + warnBoxLayout->setAlignment(Qt::AlignLeft); + auto* warnBox = new QWidget(this); + warnBox->setLayout(warnBoxLayout); + + /* + * Two labels on top and under the filelist + */ + auto* checkLabel = new QLabel(_("Check the files you want to save:")); + auto* note_label = new QLabel( + "<b>" + QString(_("Note")) + ":</b>" + + _("If you don't save these files, all changes are lost.") + "<br/>"); + + /* + * Buttonbox + */ + auto* buttonBox = + new QDialogButtonBox(QDialogButtonBox::Discard | QDialogButtonBox::Save | + QDialogButtonBox::Cancel); + connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); + connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + QPushButton* btnNoKey = buttonBox->button(QDialogButtonBox::Discard); + connect(btnNoKey, SIGNAL(clicked()), SLOT(slotMyDiscard())); + + /* + * Set the layout + */ + auto* vbox = new QVBoxLayout(); + vbox->addWidget(warnBox); + vbox->addWidget(checkLabel); + vbox->addWidget(mFileList); + vbox->addWidget(note_label); + vbox->addWidget(buttonBox); + this->setLayout(vbox); } -bool QuitDialog::isDiscarded() const { - return discarded; +void QuitDialog::slotMyDiscard() { + discarded = true; + reject(); } +bool QuitDialog::isDiscarded() const { return discarded; } + QList<int> QuitDialog::getTabIdsToSave() { - QList<int> tabIdsToSave; - for (int i = 0; i < mFileList->rowCount(); i++) { - if (mFileList->item(i, 0)->checkState() == Qt::Checked) { - tabIdsToSave << mFileList->item(i, 2)->text().toInt(); - } + QList<int> tabIdsToSave; + for (int i = 0; i < mFileList->rowCount(); i++) { + if (mFileList->item(i, 0)->checkState() == Qt::Checked) { + tabIdsToSave << mFileList->item(i, 2)->text().toInt(); } - return tabIdsToSave; + } + return tabIdsToSave; } +} // namespace GpgFrontend::UI diff --git a/src/ui/QuitDialog.h b/src/ui/QuitDialog.h new file mode 100755 index 00000000..2b1dd37f --- /dev/null +++ b/src/ui/QuitDialog.h @@ -0,0 +1,53 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef __QUITDIALOG_H__ +#define __QUITDIALOG_H__ + +#include "ui/GpgFrontendUI.h" + +namespace GpgFrontend::UI { + +class QuitDialog : public QDialog { + Q_OBJECT + + public: + QuitDialog(QWidget* parent, const QHash<int, QString>& unsavedDocs); + + [[nodiscard]] bool isDiscarded() const; + + QList<int> getTabIdsToSave(); + + private slots: + + void slotMyDiscard(); + + private: + bool discarded; + QTableWidget* mFileList; +}; + +} // namespace GpgFrontend::UI + +#endif // __QUITDIALOG_H__ diff --git a/src/ui/SendMailDialog.cpp b/src/ui/SendMailDialog.cpp deleted file mode 100644 index 5bea7cb2..00000000 --- a/src/ui/SendMailDialog.cpp +++ /dev/null @@ -1,173 +0,0 @@ -/** - * This file is part of GPGFrontend. - * - * GPGFrontend is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Foobar is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see <https://www.gnu.org/licenses/>. - * - * The initial version of the source code is inherited from gpg4usb-team. - * Their source code version also complies with GNU General Public License. - * - * The source code version of this software was modified and released - * by Saturneric<[email protected]> starting on May 12, 2021. - * - */ - -#include "ui/SendMailDialog.h" - -#include <utility> -#include "smtp/SmtpMime" - -SendMailDialog::SendMailDialog(QString text, QWidget *parent) - : QDialog(parent), appPath(qApp->applicationDirPath()), - settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", QSettings::IniFormat), mText(std::move(text)) { - - if (smtpAddress.isEmpty()) { - QMessageBox::critical(this, tr("Incomplete configuration"), - tr("The SMTP address is empty, please go to the setting interface to complete the configuration.")); - - deleteLater(); - return; - - } - - senderEdit = new QLineEdit(); - senderEdit->setText(defaultSender); - recipientEdit = new QTextEdit(); - recipientEdit->setPlaceholderText("One or more email addresses. Please use ; to separate."); - subjectEdit = new QLineEdit(); - - errorLabel = new QLabel(); - - qDebug() << "Send Mail Settings" << smtpAddress << username << password << defaultSender << connectionTypeSettings; - - confirmButton = new QPushButton("Confirm"); - - auto layout = new QGridLayout(); - layout->addWidget(new QLabel("Sender"), 0, 0); - layout->addWidget(senderEdit, 0, 1); - layout->addWidget(new QLabel("Recipient"), 1, 0); - layout->addWidget(recipientEdit, 1, 1); - layout->addWidget(new QLabel("Subject"), 2, 0); - layout->addWidget(subjectEdit, 2, 1); - layout->addWidget(confirmButton, 3, 1); - layout->addWidget(errorLabel, 4, 0, 1, 2); - - connect(confirmButton, SIGNAL(clicked(bool)), this, SLOT(slotConfirm())); - - this->setLayout(layout); - this->setWindowTitle("Send Mail"); - this->setModal(true); - this->setFixedWidth(320); - this->show(); -} - -bool SendMailDialog::check_email_address(const QString &str) { - return re_email.match(str).hasMatch(); -} - -void SendMailDialog::slotConfirm() { - - QString errString; - errorLabel->clear(); - - QStringList rcptStringList = recipientEdit->toPlainText().split(';'); - - if (rcptStringList.isEmpty()) { - errString.append(tr(" Recipient cannot be empty \n")); - } else { - for (const auto& reci : rcptStringList) { - qDebug() << "Receiver" << reci.trimmed(); - if (!check_email_address(reci.trimmed())) { - errString.append(tr(" One or more Recipient's Email Address is invalid \n")); - break; - } - } - } - if (senderEdit->text().isEmpty()) { - errString.append(tr(" Sender cannot be empty \n")); - } else if (!check_email_address(senderEdit->text())) { - errString.append(tr(" Sender's Email Address is invalid \n")); - } - - if (!errString.isEmpty()) { - errorLabel->setAutoFillBackground(true); - QPalette error = errorLabel->palette(); - error.setColor(QPalette::Window, "#ff8080"); - errorLabel->setPalette(error); - errorLabel->setText(errString); - return; - } - - SmtpClient::ConnectionType connectionType = SmtpClient::ConnectionType::TcpConnection; - - if (connectionTypeSettings == "SSL") { - connectionType = SmtpClient::ConnectionType::SslConnection; - } else if (connectionTypeSettings == "TLS") { - connectionType = SmtpClient::ConnectionType::TlsConnection; - } else if (connectionTypeSettings == "STARTTLS") { - connectionType = SmtpClient::ConnectionType::TlsConnection; - } else { - connectionType = SmtpClient::ConnectionType::TcpConnection; - } - - SmtpClient smtp(smtpAddress, port, connectionType); - - // We need to set the username (your email address) and the password - // for smtp authentification. - - smtp.setUser(username); - smtp.setPassword(password); - - // Now we create a MimeMessage object. This will be the email. - - MimeMessage message; - - message.setSender(new EmailAddress(senderEdit->text())); - for (const auto &reci : rcptStringList) { - if(!reci.isEmpty()) - message.addRecipient(new EmailAddress(reci.trimmed())); - } - message.setSubject(subjectEdit->text()); - - // Now add some text to the email. - // First we create a MimeText object. - - MimeText text; - - text.setText(mText); - - // Now add it to the mail - message.addPart(&text); - - // Now we can send the mail - if (!smtp.connectToHost()) { - qDebug() << "Connect to SMTP Server Failed"; - QMessageBox::critical(this, tr("Fail"), tr("Fail to Connect SMTP Server")); - return; - } - if (!smtp.login()) { - qDebug() << "Login to SMTP Server Failed"; - QMessageBox::critical(this, tr("Fail"), tr("Fail to Login into SMTP Server")); - return; - } - if (!smtp.sendMail(message)) { - qDebug() << "Send Mail to SMTP Server Failed"; - QMessageBox::critical(this, tr("Fail"), tr("Fail to Send Mail to SMTP Server")); - return; - } - smtp.quit(); - - // Close after sending email - QMessageBox::information(this, tr("Success"), tr("Succeed in Sending Mail to SMTP Server")); - deleteLater(); -} diff --git a/src/ui/ShowCopyDialog.cpp b/src/ui/ShowCopyDialog.cpp index 3286f6c4..0503e079 100644 --- a/src/ui/ShowCopyDialog.cpp +++ b/src/ui/ShowCopyDialog.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -24,30 +24,36 @@ #include "ui/ShowCopyDialog.h" -ShowCopyDialog::ShowCopyDialog(const QString &text, const QString &info, QWidget *parent) : QDialog(parent) { - textEdit = new QTextEdit(); - textEdit->setReadOnly(true); - textEdit->setLineWrapMode(QTextEdit::WidgetWidth); - textEdit->setText(text); - copyButton = new QPushButton("Copy"); - connect(copyButton, SIGNAL(clicked(bool)), this, SLOT(slotCopyText())); - - infoLabel = new QLabel(); - infoLabel->setText(info); - infoLabel->setWordWrap(true); - - auto *layout = new QVBoxLayout(); - layout->addWidget(textEdit); - layout->addWidget(copyButton); - layout->addWidget(infoLabel); - - this->setWindowTitle("Short Ciphertext"); - this->resize(320, 120); - this->setModal(true); - this->setLayout(layout); +namespace GpgFrontend::UI { + +ShowCopyDialog::ShowCopyDialog(const QString& text, const QString& info, + QWidget* parent) + : QDialog(parent) { + textEdit = new QTextEdit(); + textEdit->setReadOnly(true); + textEdit->setLineWrapMode(QTextEdit::WidgetWidth); + textEdit->setText(text); + copyButton = new QPushButton("Copy"); + connect(copyButton, SIGNAL(clicked(bool)), this, SLOT(slotCopyText())); + + infoLabel = new QLabel(); + infoLabel->setText(info); + infoLabel->setWordWrap(true); + + auto* layout = new QVBoxLayout(); + layout->addWidget(textEdit); + layout->addWidget(copyButton); + layout->addWidget(infoLabel); + + this->setWindowTitle("Short Ciphertext"); + this->resize(320, 120); + this->setModal(true); + this->setLayout(layout); } void ShowCopyDialog::slotCopyText() { - QClipboard *cb = QApplication::clipboard(); - cb->setText(textEdit->toPlainText()); + QClipboard* cb = QApplication::clipboard(); + cb->setText(textEdit->toPlainText()); } + +} // namespace GpgFrontend::UI diff --git a/src/ui/ShowCopyDialog.h b/src/ui/ShowCopyDialog.h new file mode 100644 index 00000000..fefef7ab --- /dev/null +++ b/src/ui/ShowCopyDialog.h @@ -0,0 +1,50 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_ZH_CN_TS_SHOWCOPYDIALOG_H +#define GPGFRONTEND_ZH_CN_TS_SHOWCOPYDIALOG_H + +#include "ui/GpgFrontendUI.h" + +namespace GpgFrontend::UI { + +class ShowCopyDialog : public QDialog { + Q_OBJECT + public: + explicit ShowCopyDialog(const QString& text, const QString& info = "", + QWidget* parent = nullptr); + + private slots: + + void slotCopyText(); + + private: + QLabel* infoLabel; + QTextEdit* textEdit; + QPushButton* copyButton; +}; + +} // namespace GpgFrontend::UI + +#endif // GPGFRONTEND_ZH_CN_TS_SHOWCOPYDIALOG_H diff --git a/src/gpg/GpgKeySignature.cpp b/src/ui/SignalStation.cpp index 142d1550..fff2971a 100644 --- a/src/gpg/GpgKeySignature.cpp +++ b/src/ui/SignalStation.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -22,13 +22,13 @@ * */ -#include "gpg/GpgKeySignature.h" +#include "SignalStation.h" -GpgKeySignature::GpgKeySignature(gpgme_key_sig_t key_sig) : - revoked(key_sig->revoked), expired(key_sig->expired), invalid(key_sig->invalid), - exportable(key_sig->exportable), status(key_sig->status), - keyid(key_sig->keyid), pubkey_algo(gpgme_pubkey_algo_name(key_sig->pubkey_algo)), - uid(key_sig->uid), name(key_sig->name), email(key_sig->email), comment(key_sig->comment), - create_time(QDateTime::fromTime_t(key_sig->timestamp)), expire_time(QDateTime::fromTime_t(key_sig->expires)){ +std::unique_ptr<SignalStation> SignalStation::_instance = nullptr; +SignalStation* SignalStation::GetInstance() { + if (_instance == nullptr) { + _instance = std::make_unique<SignalStation>(); + } + return _instance.get(); } diff --git a/src/ui/SignalStation.h b/src/ui/SignalStation.h new file mode 100644 index 00000000..38e55d9f --- /dev/null +++ b/src/ui/SignalStation.h @@ -0,0 +1,41 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_SIGNALSTATION_H +#define GPGFRONTEND_SIGNALSTATION_H + +#include "ui/GpgFrontendUI.h" + +class SignalStation : public QObject { + Q_OBJECT + static std::unique_ptr<SignalStation> _instance; + + public: + static SignalStation* GetInstance(); + + signals: + void KeyDatabaseRefresh(); +}; + +#endif // GPGFRONTEND_SIGNALSTATION_H diff --git a/src/ui/UserInterfaceUtils.cpp b/src/ui/UserInterfaceUtils.cpp new file mode 100644 index 00000000..e8f27d2c --- /dev/null +++ b/src/ui/UserInterfaceUtils.cpp @@ -0,0 +1,171 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#include "UserInterfaceUtils.h" + +#include "gpg/result_analyse/ResultAnalyse.h" +#include "ui/SignalStation.h" +#include "ui/WaitingDialog.h" +#include "ui/widgets/InfoBoardWidget.h" +#include "ui/widgets/TextEdit.h" + +namespace GpgFrontend::UI { + +std::unique_ptr<GpgFrontend::UI::CommonUtils> + GpgFrontend::UI::CommonUtils::_instance = nullptr; + +void refresh_info_board(InfoBoardWidget* info_board, int status, + const std::string& report_text) { + if (status < 0) + info_board->slotRefresh(QString::fromStdString(report_text), + INFO_ERROR_CRITICAL); + else if (status > 0) + info_board->slotRefresh(QString::fromStdString(report_text), INFO_ERROR_OK); + else + info_board->slotRefresh(QString::fromStdString(report_text), + INFO_ERROR_WARN); +} + +void process_result_analyse(TextEdit* edit, InfoBoardWidget* info_board, + const ResultAnalyse& result_analyse) { + info_board->associateTabWidget(edit->tabWidget); + info_board->associateFileTreeView(edit->curFilePage()); + refresh_info_board(info_board, result_analyse.getStatus(), + result_analyse.getResultReport()); +} + +void process_result_analyse(TextEdit* edit, InfoBoardWidget* info_board, + const ResultAnalyse& result_analyse_a, + const ResultAnalyse& result_analyse_b) { + LOG(INFO) << "process_result_analyse Started"; + + info_board->associateTabWidget(edit->tabWidget); + info_board->associateFileTreeView(edit->curFilePage()); + + refresh_info_board( + info_board, + std::min(result_analyse_a.getStatus(), result_analyse_b.getStatus()), + result_analyse_a.getResultReport() + result_analyse_b.getResultReport()); +} + +void process_operation(QWidget* parent, const std::string& waiting_title, + const std::function<void()>& func) { + auto thread = QThread::create(func); + QApplication::connect(thread, SIGNAL(finished()), thread, + SLOT(deleteLater())); + thread->start(); + + auto* dialog = + new WaitingDialog(QString::fromStdString(waiting_title), parent); + while (thread->isRunning()) { + QApplication::processEvents(); + } + dialog->close(); +} + +CommonUtils* CommonUtils::GetInstance() { + if (_instance == nullptr) { + _instance = std::make_unique<CommonUtils>(); + } + return _instance.get(); +} + +CommonUtils::CommonUtils() : QWidget(nullptr) { + connect(this, SIGNAL(signalKeyStatusUpdated()), SignalStation::GetInstance(), + SIGNAL(KeyDatabaseRefresh())); +} + +void CommonUtils::slotImportKeys(QWidget* parent, + const std::string& in_buffer) { + GpgImportInformation result = GpgKeyImportExportor::GetInstance().ImportKey( + std::make_unique<ByteArray>(in_buffer)); + emit signalKeyStatusUpdated(); + new KeyImportDetailDialog(result, false, parent); +} + +void CommonUtils::slotImportKeyFromFile(QWidget* parent) { + QString file_name = QFileDialog::getOpenFileName( + this, _("Open Key"), QString(), + QString(_("Key Files")) + " (*.asc *.txt);;" + _("Keyring files") + + " (*.gpg);;All Files (*)"); + if (!file_name.isNull()) { + slotImportKeys(parent, read_all_data_in_file(file_name.toStdString())); + } +} + +void CommonUtils::slotImportKeyFromKeyServer(QWidget* parent) { + auto dialog = new KeyServerImportDialog(false, parent); + dialog->show(); +} + +void CommonUtils::slotImportKeyFromClipboard(QWidget* parent) { + QClipboard* cb = QApplication::clipboard(); + slotImportKeys(parent, + cb->text(QClipboard::Clipboard).toUtf8().toStdString()); +} + +void CommonUtils::slotExecuteGpgCommand( + const QStringList& arguments, + const std::function<void(QProcess*)>& interact_func) { + QEventLoop looper; + auto dialog = new WaitingDialog(_("Processing"), nullptr); + dialog->show(); + auto* gpgProcess = new QProcess(&looper); + gpgProcess->setProcessChannelMode(QProcess::MergedChannels); + + connect(gpgProcess, qOverload<int, QProcess::ExitStatus>(&QProcess::finished), + &looper, &QEventLoop::quit); + connect(gpgProcess, qOverload<int, QProcess::ExitStatus>(&QProcess::finished), + dialog, &WaitingDialog::deleteLater); + connect(gpgProcess, &QProcess::errorOccurred, &looper, &QEventLoop::quit); + connect(gpgProcess, &QProcess::started, + []() -> void { LOG(ERROR) << "Gpg Process Started Success"; }); + connect(gpgProcess, &QProcess::readyReadStandardOutput, + [interact_func, gpgProcess]() { interact_func(gpgProcess); }); + connect(gpgProcess, &QProcess::errorOccurred, this, [=]() -> void { + LOG(ERROR) << "Error in Process"; + dialog->close(); + QMessageBox::critical(nullptr, _("Failure"), + _("Failed to execute command.")); + }); + connect(gpgProcess, qOverload<int, QProcess::ExitStatus>(&QProcess::finished), + this, [=](int, QProcess::ExitStatus status) { + dialog->close(); + if (status == QProcess::NormalExit) + QMessageBox::information(nullptr, _("Success"), + _("Succeed in executing command.")); + else + QMessageBox::information(nullptr, _("Warning"), + _("Finished executing command.")); + }); + + gpgProcess->setProgram(GpgContext::GetInstance().GetInfo().AppPath.c_str()); + gpgProcess->setArguments(arguments); + gpgProcess->start(); + looper.exec(); + dialog->close(); + dialog->deleteLater(); +} + +} // namespace GpgFrontend::UI
\ No newline at end of file diff --git a/src/ui/UserInterfaceUtils.h b/src/ui/UserInterfaceUtils.h new file mode 100644 index 00000000..df974257 --- /dev/null +++ b/src/ui/UserInterfaceUtils.h @@ -0,0 +1,82 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_USER_INTERFACE_UTILS_H +#define GPGFRONTEND_USER_INTERFACE_UTILS_H + +#include "ui/GpgFrontendUI.h" + +namespace GpgFrontend { +class ResultAnalyse; +} + +namespace GpgFrontend::UI { + +class InfoBoardWidget; +class TextEdit; + +void refresh_info_board(InfoBoardWidget* info_board, int status, + const std::string& report_text); + +void process_result_analyse(TextEdit* edit, InfoBoardWidget* info_board, + const ResultAnalyse& result_analyse); + +void process_result_analyse(TextEdit* edit, InfoBoardWidget* info_board, + const ResultAnalyse& result_analyse_a, + const ResultAnalyse& result_analyse_b); + +void process_operation(QWidget* parent, const std::string& waiting_title, + const std::function<void()>& func); + +class CommonUtils : public QWidget { + Q_OBJECT + public: + static CommonUtils* GetInstance(); + + CommonUtils(); + + signals: + void signalKeyStatusUpdated(); + + public slots: + + void slotImportKeys(QWidget* parent, const std::string& in_buffer); + + void slotImportKeyFromFile(QWidget* parent); + + void slotImportKeyFromKeyServer(QWidget* parent); + + void slotImportKeyFromClipboard(QWidget* parent); + + void slotExecuteGpgCommand( + const QStringList& arguments, + const std::function<void(QProcess*)>& interact_func); + + private: + static std::unique_ptr<CommonUtils> _instance; +}; + +} // namespace GpgFrontend::UI + +#endif // GPGFRONTEND_USER_INTERFACE_UTILS_H diff --git a/src/ui/VerifyDetailsDialog.cpp b/src/ui/VerifyDetailsDialog.cpp index 641c09e9..1ad9d996 100644 --- a/src/ui/VerifyDetailsDialog.cpp +++ b/src/ui/VerifyDetailsDialog.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -24,60 +24,74 @@ #include "ui/VerifyDetailsDialog.h" -VerifyDetailsDialog::VerifyDetailsDialog(QWidget *parent, GpgME::GpgContext *ctx, KeyList *keyList, gpg_error_t error, - gpgme_verify_result_t result) : - QDialog(parent), mCtx(ctx), mKeyList(keyList), sign(result->signatures), error(error) { +#include <boost/format.hpp> +namespace GpgFrontend::UI { - this->setWindowTitle(tr("Signature Details")); +VerifyDetailsDialog::VerifyDetailsDialog(QWidget* parent, KeyList* keyList, + GpgError error, GpgVerifyResult result) + : QDialog(parent), + mKeyList(keyList), + mResult(std::move(result)), + error(error) { + this->setWindowTitle(_("Signature Details")); - connect(mCtx, SIGNAL(signalKeyInfoChanged()), this, SLOT(slotRefresh())); - mainLayout = new QHBoxLayout(); - this->setLayout(mainLayout); + mainLayout = new QHBoxLayout(); + this->setLayout(mainLayout); - slotRefresh(); + slotRefresh(); - this->exec(); + this->exec(); } void VerifyDetailsDialog::slotRefresh() { + mVbox = new QWidget(); + auto* mVboxLayout = new QVBoxLayout(mVbox); + mainLayout->addWidget(mVbox); - mVbox = new QWidget(); - auto *mVboxLayout = new QVBoxLayout(mVbox); - mainLayout->addWidget(mVbox); - - // Button Box for close button - buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(close())); - - mVboxLayout->addWidget(new QLabel(tr("Status: ") + gpgme_strerror(error))); - - if (sign == nullptr) { - mVboxLayout->addWidget(new QLabel(tr("No valid input found"))); - mVboxLayout->addWidget(buttonBox); - return; - } - - // Get timestamp of signature of current text - QDateTime timestamp; - timestamp.setTime_t(sign->timestamp); - - // Set the title widget depending on sign status - if (gpg_err_code(sign->status) == GPG_ERR_BAD_SIGNATURE) { - mVboxLayout->addWidget(new QLabel(tr("Error Validating signature"))); - } else if (mInputSignature != nullptr) { - mVboxLayout->addWidget(new QLabel( - tr("File was signed on %1 <br/> It Contains:<br/><br/>").arg(QLocale::system().toString(timestamp)))); - } else { - mVboxLayout->addWidget(new QLabel(tr("Signed on %1 <br/> It Contains:<br /><br/>").arg( - QLocale::system().toString(timestamp)))); - } - // Add informationbox for every single key - while (sign) { - auto *sbox = new VerifyKeyDetailBox(this, mCtx, mKeyList, sign); - sign = sign->next; - mVboxLayout->addWidget(sbox); - } + // Button Box for close button + buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); + connect(buttonBox, SIGNAL(rejected()), this, SLOT(close())); + mVboxLayout->addWidget(new QLabel(QString::fromStdString( + std::string(_("Status")) + ": " + gpgme_strerror(error)))); + + auto sign = mResult->signatures; + + if (sign == nullptr) { + mVboxLayout->addWidget(new QLabel(_("No valid input found"))); mVboxLayout->addWidget(buttonBox); + return; + } + + // Get timestamp of signature of current text + QDateTime timestamp; + timestamp.setTime_t(sign->timestamp); + + // Set the title widget depending on sign status + if (gpg_err_code(sign->status) == GPG_ERR_BAD_SIGNATURE) { + mVboxLayout->addWidget(new QLabel(_("Error Validating signature"))); + } else if (mInputSignature != nullptr) { + const auto info = (boost::format(_("File was signed on %1%")) % + QLocale::system().toString(timestamp).toStdString()) + .str() + + "<br/>" + _("It Contains") + ": " + "<br/><br/>"; + mVboxLayout->addWidget(new QLabel(info.c_str())); + } else { + const auto info = (boost::format(_("Signed on %1%")) % + QLocale::system().toString(timestamp).toStdString()) + .str() + + "<br/>" + _("It Contains") + ": " + "<br/><br/>"; + mVboxLayout->addWidget(new QLabel(info.c_str())); + } + // Add information box for every single key + while (sign) { + auto* sign_box = new VerifyKeyDetailBox(this, mKeyList, sign); + sign = sign->next; + mVboxLayout->addWidget(sign_box); + } + + mVboxLayout->addWidget(buttonBox); } + +} // namespace GpgFrontend::UI
\ No newline at end of file diff --git a/src/ui/VerifyDetailsDialog.h b/src/ui/VerifyDetailsDialog.h new file mode 100644 index 00000000..3de4a56f --- /dev/null +++ b/src/ui/VerifyDetailsDialog.h @@ -0,0 +1,57 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef __VERIFYDETAILSDIALOG_H__ +#define __VERIFYDETAILSDIALOG_H__ + +#include "ui/GpgFrontendUI.h" +#include "ui/widgets/EditorPage.h" +#include "ui/widgets/VerifyKeyDetailBox.h" + +namespace GpgFrontend::UI { + +class VerifyDetailsDialog : public QDialog { + Q_OBJECT + public: + explicit VerifyDetailsDialog(QWidget* parent, KeyList* keyList, + GpgError error, GpgVerifyResult result); + + private slots: + + void slotRefresh(); + + private: + KeyList* mKeyList; + QHBoxLayout* mainLayout; + QWidget* mVbox{}; + QByteArray* mInputData{}; /** Data to be verified */ + QByteArray* mInputSignature{}; /** Data to be verified */ + QDialogButtonBox* buttonBox{}; + GpgVerifyResult mResult; + gpgme_error_t error; +}; + +} // namespace GpgFrontend::UI + +#endif // __VERIFYDETAILSDIALOG_H__ diff --git a/src/ui/WaitingDialog.cpp b/src/ui/WaitingDialog.cpp index daccc3ca..a83845ab 100644 --- a/src/ui/WaitingDialog.cpp +++ b/src/ui/WaitingDialog.cpp @@ -1,20 +1,73 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + #include "ui/WaitingDialog.h" -WaitingDialog::WaitingDialog(const QString &title, QWidget *parent) : QDialog(parent) { - auto *pb = new QProgressBar(); - pb->setRange(0, 0); - pb->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); - pb->setTextVisible(false); - - auto *layout = new QVBoxLayout(); - layout->setContentsMargins(0, 0, 0, 0); - layout->setSpacing(0); - layout->addWidget(pb); - this->setLayout(layout); - - this->setModal(true); - this->setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::CustomizeWindowHint); - this->setWindowTitle(title); - this->setFixedSize(240, 42); - this->show(); +namespace GpgFrontend::UI { + +WaitingDialog::WaitingDialog(const QString& title, QWidget* parent) + : QDialog(parent) { + auto* pb = new QProgressBar(); + pb->setRange(0, 0); + pb->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + pb->setTextVisible(false); + + auto* layout = new QVBoxLayout(); + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(0); + layout->addWidget(pb); + this->setLayout(layout); + + this->setModal(true); + this->raise(); + this->setWindowFlags(Qt::Window | Qt::WindowTitleHint | + Qt::CustomizeWindowHint); + this->setWindowTitle(title); + this->setAttribute(Qt::WA_DeleteOnClose); + this->setFixedSize(240, 42); + + if (parentWidget() == nullptr) { + auto* screen = QGuiApplication::primaryScreen(); + QRect geo = screen->availableGeometry(); + int screen_width = geo.width(); + int screen_height = geo.height(); + + LOG(INFO) << "primary screen available geometry" << screen_width + << screen_height; + + auto pos = QPoint((screen_width - QWidget::width()) / 2, + (screen_height - QWidget::height()) / 2); + this->move(pos); + + } else { + auto pos = QPoint(parent->x() + (parent->width() - QWidget::width()) / 2, + parent->y() + (parent->height() - QWidget::height()) / 2); + LOG(INFO) << "pos" << pos.x() << pos.y(); + this->move(pos); + } + + this->show(); } + +} // namespace GpgFrontend::UI diff --git a/src/ui/WaitingDialog.h b/src/ui/WaitingDialog.h new file mode 100644 index 00000000..798c2a3c --- /dev/null +++ b/src/ui/WaitingDialog.h @@ -0,0 +1,46 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef __UI_WAITING_DIALOG_H__ +#define __UI_WAITING_DIALOG_H__ + +#include "ui/GpgFrontendUI.h" + +namespace GpgFrontend::UI { + +class WaitingDialog : public QDialog { + Q_OBJECT + public: + WaitingDialog(const QString& title, QWidget* parent); + + public slots: + + private slots: + + private: +}; + +} // namespace GpgFrontend::UI + +#endif // __UI_WAITING_DIALOG_H__ diff --git a/src/ui/Wizard.cpp b/src/ui/Wizard.cpp index 8b482675..de0107c4 100644 --- a/src/ui/Wizard.cpp +++ b/src/ui/Wizard.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -24,234 +24,302 @@ #include "ui/Wizard.h" -Wizard::Wizard(GpgME::GpgContext *ctx, KeyMgmt *keyMgmt, QWidget *parent) - : QWizard(parent), appPath(qApp->applicationDirPath()), - settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", QSettings::IniFormat) { - mCtx = ctx; - mKeyMgmt = keyMgmt; +#include "ui/settings/GlobalSettingStation.h" - setPage(Page_Intro, new IntroPage(this)); - setPage(Page_Choose, new ChoosePage(this)); - setPage(Page_GenKey, new KeyGenPage(mCtx, this)); - setPage(Page_Conclusion, new ConclusionPage(this)); +namespace GpgFrontend::UI { + +Wizard::Wizard(QWidget* parent) : QWizard(parent) { + setPage(Page_Intro, new IntroPage(this)); + setPage(Page_Choose, new ChoosePage(this)); + setPage(Page_GenKey, new KeyGenPage(this)); + setPage(Page_Conclusion, new ConclusionPage(this)); #ifndef Q_WS_MAC - setWizardStyle(ModernStyle); + setWizardStyle(ModernStyle); #endif - setWindowTitle(tr("First Start Wizard")); - - // http://www.flickr.com/photos/laureenp/6141822934/ - setPixmap(QWizard::WatermarkPixmap, QPixmap(":/keys2.jpg")); - setPixmap(QWizard::LogoPixmap, QPixmap(":/logo_small.png")); - setPixmap(QWizard::BannerPixmap, QPixmap(":/banner.png")); - - setStartId(settings.value("wizard/nextPage", -1).toInt()); - settings.remove("wizard/nextPage"); - - connect(this, SIGNAL(accepted()), this, SLOT(slotWizardAccepted())); - + setWindowTitle(_("First Start Wizard")); + + // http://www.flickr.com/photos/laureenp/6141822934/ + setPixmap(QWizard::WatermarkPixmap, QPixmap(":/keys2.jpg")); + setPixmap(QWizard::LogoPixmap, QPixmap(":/logo_small.png")); + setPixmap(QWizard::BannerPixmap, QPixmap(":/banner.png")); + + auto& settings = GlobalSettingStation::GetInstance().GetUISettings(); + int next_page_id = -1; + try { + next_page_id = settings.lookup("wizard.next_page"); + } catch (...) { + LOG(ERROR) << _("Setting Operation Error"); + } + setStartId(next_page_id); + + connect(this, SIGNAL(accepted()), this, SLOT(slotWizardAccepted())); } void Wizard::slotWizardAccepted() { - // Don't show is mapped to show -> negation - settings.setValue("wizard/showWizard", !field("showWizard").toBool()); - - if (field("openHelp").toBool()) { - emit signalOpenHelp("docu.html#content"); - } -} - -IntroPage::IntroPage(QWidget *parent) - : QWizardPage(parent), appPath(qApp->applicationDirPath()), - settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", QSettings::IniFormat) { - setTitle(tr("Getting Started...")); - setSubTitle(tr("... with GPGFrontend")); - - auto *topLabel = new QLabel(tr("Welcome to use GPGFrontend for decrypting and signing text or file!") + - " <br><br><a href='https://gpgfrontend.pub'>GpgFrontend</a> " + - tr("is a Powerful, Easy-to-Use, Compact, Cross-Platform, and Installation-Free OpenPGP Crypto Tool.") + - tr("For brief information have a look at the") + - " <a href='https://gpgfrontend.pub/index.html#/overview'>" + - tr("Overview") + "</a> (" + - tr("by clicking the link, the page will open in the web browser") + - "). <br>"); - topLabel->setTextFormat(Qt::RichText); - topLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); - topLabel->setOpenExternalLinks(true); - topLabel->setWordWrap(true); - - // QComboBox for language selection - auto *langLabel = new QLabel(tr("Choose a Language")); - langLabel->setWordWrap(true); - - languages = SettingsDialog::listLanguages(); - auto *langSelectBox = new QComboBox(); - - for (const auto &l : languages) { - langSelectBox->addItem(l); + LOG(INFO) << _("Called"); + // Don't show is mapped to show -> negation + try { + auto& settings = GlobalSettingStation::GetInstance().GetUISettings(); + if (!settings.exists("wizard")) { + settings.add("wizard", libconfig::Setting::TypeGroup); } - // selected entry from config - QString langKey = settings.value("int/lang").toString(); - QString langValue = languages.value(langKey); - if (langKey != "") { - langSelectBox->setCurrentIndex(langSelectBox->findText(langValue)); + auto& wizard = settings["wizard"]; + if (!wizard.exists("show_wizard")) { + wizard.add("show_wizard", libconfig::Setting::TypeBoolean) = false; + } else { + wizard["show_wizard"] = false; } - - connect(langSelectBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(slotLangChange(QString))); - - // set layout and add widgets - auto *layout = new QVBoxLayout; - layout->addWidget(topLabel); - layout->addWidget(langLabel); - layout->addWidget(langSelectBox); - setLayout(layout); -} - -void IntroPage::slotLangChange(const QString &lang) { - settings.setValue("int/lang", languages.key(lang)); - settings.setValue("wizard/nextPage", this->wizard()->currentId()); - qApp->exit(RESTART_CODE); + GlobalSettingStation::GetInstance().Sync(); + } catch (...) { + LOG(ERROR) << _("Setting Operation Error"); + } + if (field("openHelp").toBool()) { + emit signalOpenHelp("docu.html#content"); + } } -int IntroPage::nextId() const { - return Wizard::Page_Choose; +IntroPage::IntroPage(QWidget* parent) : QWizardPage(parent) { + setTitle(_("Getting Started...")); + setSubTitle(_("... with GpgFrontend")); + + auto* topLabel = new QLabel( + QString(_("Welcome to use GpgFrontend for decrypting and signing text or " + "file!")) + + " <br><br><a href='https://gpgfrontend.pub'>GpgFrontend</a> " + + _("is a Powerful, Easy-to-Use, Compact, Cross-Platform, and " + "Installation-Free OpenPGP Crypto Tool.") + + _("For brief information have a look at the") + + " <a href='https://gpgfrontend.pub/index.html#/overview'>" + + _("Overview") + "</a> (" + + _("by clicking the link, the page will open in the web browser") + + "). <br>"); + topLabel->setTextFormat(Qt::RichText); + topLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); + topLabel->setOpenExternalLinks(true); + topLabel->setWordWrap(true); + + // QComboBox for language selection + auto* langLabel = + new QLabel(_("If it supports the language currently being used in your " + "system, GpgFrontend will automatically set it.")); + langLabel->setWordWrap(true); + + languages = SettingsDialog::listLanguages(); + auto* langSelectBox = new QComboBox(); + + for (const auto& l : languages) { + langSelectBox->addItem(l); + } + // selected entry from config + + // auto lang = ""; + // auto& settings = GlobalSettingStation::GetInstance().GetUISettings(); + // try { + // lang = settings.lookup("general.lang"); + // } catch (...) { + // LOG(INFO) << "Read for general.lang failed"; + // } + // + // QString langKey = lang; + // QString langValue = languages.value(langKey); + // LOG(INFO) << "lang key" << langKey.toStdString() << "lang value" + // << langValue.toStdString(); + // langSelectBox->setCurrentIndex(langSelectBox->findText(langValue)); + + // connect(langSelectBox, SIGNAL(currentIndexChanged(QString)), this, + // SLOT(slotLangChange(QString))); + + // set layout and add widgets + auto* layout = new QVBoxLayout; + layout->addWidget(topLabel); + layout->addStretch(); + layout->addWidget(langLabel); + // layout->addWidget(langSelectBox); + + setLayout(layout); } -ChoosePage::ChoosePage(QWidget *parent) - : QWizardPage(parent) { - setTitle(tr("Choose your action...")); - setSubTitle(tr("...by clicking on the appropriate link.")); - - auto *keygenLabel = new QLabel(tr("If you have never used GPGFrontend before and also don't own a gpg key yet you " - "may possibly want to read how to") + - " <a href=\"https://gpgfrontend.pub/index.html#/manual/generate-key\">" - + tr("Generate Key") + "</a><hr>"); - keygenLabel->setTextFormat(Qt::RichText); - keygenLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); - keygenLabel->setOpenExternalLinks(true); - keygenLabel->setWordWrap(true); - - auto *encrDecyTextLabel = new QLabel( - tr("If you want to learn how to encrypt, decrypt, sign and verify text, you can read ") - + "<a href=\"https://gpgfrontend.pub/index.html#/manual/encrypt-decrypt-text\">" - + tr("Encrypt & Decrypt Text") + "</a> " + tr("or") - + " <a href=\"https://gpgfrontend.pub/index.html#/manual/sign-verify-text\">" - + tr("Sign & Verify Text") - + "</a><hr>"); - - encrDecyTextLabel->setTextFormat(Qt::RichText); - encrDecyTextLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); - encrDecyTextLabel->setOpenExternalLinks(true); - encrDecyTextLabel->setWordWrap(true); - - auto *signVerifyTextLabel = new QLabel(tr("If you want to operate file, you can read ") - + - "<a href=\"https://gpgfrontend.pub/index.html#/manual/encrypt-decrypt-file\">" - + tr("Encrypt & Sign File") + "</a> " + tr("or") - + - " <a href=\"https://gpgfrontend.pub/index.html#/manual/sign-verify-file\">" - + tr("Sign & Verify File") - + "</a><hr>"); - signVerifyTextLabel->setTextFormat(Qt::RichText); - signVerifyTextLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); - signVerifyTextLabel->setOpenExternalLinks(true); - signVerifyTextLabel->setWordWrap(true); - - auto *layout = new QVBoxLayout(); - layout->addWidget(keygenLabel); - layout->addWidget(encrDecyTextLabel); - layout->addWidget(signVerifyTextLabel); - setLayout(layout); - nextPage = Wizard::Page_Conclusion; +// void IntroPage::slotLangChange(const QString& lang) { +// auto& settings = GlobalSettingStation::GetInstance().GetUISettings(); +// +// if (!settings.exists("general") || +// settings.lookup("general").getType() != libconfig::Setting::TypeGroup) +// settings.add("general", libconfig::Setting::TypeGroup); +// +// auto& general = settings["general"]; +// if (!general.exists("lang")) +// general.add("lang", libconfig::Setting::TypeString) = +// languages.key(lang).toStdString(); +// else { +// general["lang"] = languages.key(lang).toStdString(); +// } +// +// if (!settings.exists("wizard") || +// settings.lookup("wizard").getType() != libconfig::Setting::TypeGroup) +// settings.add("wizard", libconfig::Setting::TypeGroup); +// +// auto& wizard = settings["wizard"]; +// if (!wizard.exists("next_page")) +// wizard.add("next_page", libconfig::Setting::TypeInt) = +// this->wizard()->currentId(); +// else { +// wizard["next_page"] = this->wizard()->currentId(); +// } +// +// GlobalSettingStation::GetInstance().Sync(); +// +// qApp->exit(RESTART_CODE); +// } + +int IntroPage::nextId() const { return Wizard::Page_Choose; } + +ChoosePage::ChoosePage(QWidget* parent) : QWizardPage(parent) { + setTitle(_("Choose your action...")); + setSubTitle(_("...by clicking on the appropriate link.")); + + auto* keygenLabel = new QLabel( + QString(_( + "If you have never used GpgFrontend before and also don't own a gpg " + "key yet you " + "may possibly want to read how to")) + + " <a href=\"https://gpgfrontend.pub/index.html#/manual/generate-key\">" + + _("Generate Key") + "</a><hr>"); + keygenLabel->setTextFormat(Qt::RichText); + keygenLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); + keygenLabel->setOpenExternalLinks(true); + keygenLabel->setWordWrap(true); + + auto* encrDecyTextLabel = new QLabel( + QString(_( + "If you want to learn how to encrypt, decrypt, sign and verify text, " + "you can read ")) + + "<a " + "href=\"https://gpgfrontend.pub/index.html#/manual/" + "encrypt-decrypt-text\">" + + _("Encrypt & Decrypt Text") + "</a> " + _("or") + + " <a " + "href=\"https://gpgfrontend.pub/index.html#/manual/sign-verify-text\">" + + _("Sign & Verify Text") + "</a><hr>"); + + encrDecyTextLabel->setTextFormat(Qt::RichText); + encrDecyTextLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); + encrDecyTextLabel->setOpenExternalLinks(true); + encrDecyTextLabel->setWordWrap(true); + + auto* signVerifyTextLabel = new QLabel( + QString(_("If you want to operate file, you can read ")) + + "<a " + "href=\"https://gpgfrontend.pub/index.html#/manual/" + "encrypt-decrypt-file\">" + + _("Encrypt & Sign File") + "</a> " + _("or") + + " <a " + "href=\"https://gpgfrontend.pub/index.html#/manual/sign-verify-file\">" + + _("Sign & Verify File") + "</a><hr>"); + signVerifyTextLabel->setTextFormat(Qt::RichText); + signVerifyTextLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); + signVerifyTextLabel->setOpenExternalLinks(true); + signVerifyTextLabel->setWordWrap(true); + + auto* layout = new QVBoxLayout(); + layout->addWidget(keygenLabel); + layout->addWidget(encrDecyTextLabel); + layout->addWidget(signVerifyTextLabel); + setLayout(layout); + nextPage = Wizard::Page_Conclusion; } -int ChoosePage::nextId() const { - return nextPage; -} +int ChoosePage::nextId() const { return nextPage; } -void ChoosePage::slotJumpPage(const QString &page) { - QMetaObject qmo = Wizard::staticMetaObject; - int index = qmo.indexOfEnumerator("WizardPages"); - QMetaEnum m = qmo.enumerator(index); +void ChoosePage::slotJumpPage(const QString& page) { + QMetaObject qmo = Wizard::staticMetaObject; + int index = qmo.indexOfEnumerator("WizardPages"); + QMetaEnum m = qmo.enumerator(index); - nextPage = m.keyToValue(page.toUtf8().data()); - wizard()->next(); + nextPage = m.keyToValue(page.toUtf8().data()); + wizard()->next(); } -KeyGenPage::KeyGenPage(GpgME::GpgContext *ctx, QWidget *parent) - : QWizardPage(parent) { - mCtx = ctx; - setTitle(tr("Create a keypair...")); - setSubTitle(tr("...for decrypting and signing messages")); - auto *topLabel = new QLabel(tr("You should create a new keypair." - "The pair consists of a public and a private key.<br>" - "Other users can use the public key to encrypt messages for you " - "and verify messages signed by you." - "You can use the private key to decrypt and sign messages.<br>" - "For more information have a look at the offline tutorial (which then is shown in the main window):")); - topLabel->setWordWrap(true); - auto *linkLabel = new QLabel("<a href=""docu_keygen.html#content"">" + tr("Offline tutorial") + "</a>"); - //linkLabel->setOpenExternalLinks(true); - - // connect(linkLabel, SIGNAL(linkActivated(QString)), parentWidget()->parentWidget(), SLOT(openHelp(QString))); - - auto *createKeyButtonBox = new QWidget(this); - auto *createKeyButtonBoxLayout = new QHBoxLayout(createKeyButtonBox); - auto *createKeyButton = new QPushButton(tr("Create New Key")); - createKeyButtonBoxLayout->addWidget(createKeyButton); - createKeyButtonBoxLayout->addStretch(1); - auto *layout = new QVBoxLayout(); - layout->addWidget(topLabel); - layout->addWidget(linkLabel); - layout->addWidget(createKeyButtonBox); - connect(createKeyButton, SIGNAL(clicked(bool)), this, SLOT(slotGenerateKeyDialog())); - - setLayout(layout); +KeyGenPage::KeyGenPage(QWidget* parent) : QWizardPage(parent) { + setTitle(_("Create a keypair...")); + setSubTitle(_("...for decrypting and signing messages")); + auto* topLabel = new QLabel( + _("You should create a new keypair." + "The pair consists of a public and a private key.<br>" + "Other users can use the public key to encrypt messages for you " + "and verify messages signed by you." + "You can use the private key to decrypt and sign messages.<br>" + "For more information have a look at the offline tutorial (which then " + "is shown in the main window):")); + topLabel->setWordWrap(true); + auto* linkLabel = new QLabel( + "<a href=" + "docu_keygen.html#content" + ">" + + QString(_("Offline tutorial")) + "</a>"); + // linkLabel->setOpenExternalLinks(true); + + // connect(linkLabel, SIGNAL(linkActivated(QString)), + // parentWidget()->parentWidget(), SLOT(openHelp(QString))); + + auto* createKeyButtonBox = new QWidget(this); + auto* createKeyButtonBoxLayout = new QHBoxLayout(createKeyButtonBox); + auto* createKeyButton = new QPushButton(_("Create New Key")); + createKeyButtonBoxLayout->addWidget(createKeyButton); + createKeyButtonBoxLayout->addStretch(1); + auto* layout = new QVBoxLayout(); + layout->addWidget(topLabel); + layout->addWidget(linkLabel); + layout->addWidget(createKeyButtonBox); + connect(createKeyButton, SIGNAL(clicked(bool)), this, + SLOT(slotGenerateKeyDialog())); + + setLayout(layout); } -int KeyGenPage::nextId() const { - return Wizard::Page_Conclusion; -} +int KeyGenPage::nextId() const { return Wizard::Page_Conclusion; } void KeyGenPage::slotGenerateKeyDialog() { - qDebug() << "Try Opening KeyGenDialog"; - auto *keyGenDialog = new KeyGenDialog(mCtx, this); - keyGenDialog->show(); - wizard()->next(); + LOG(INFO) << "Try Opening KeyGenDialog"; + (new KeyGenDialog(this))->show(); + wizard()->next(); } -ConclusionPage::ConclusionPage(QWidget *parent) - : QWizardPage(parent) { - setTitle(tr("Ready.")); - setSubTitle(tr("Have fun with GPGFrontend!")); - - auto *bottomLabel = new QLabel(tr("You are ready to use GPGFrontend now.<br><br>") + - "<a href=\"https://saturneric.github.io/GpgFrontend/index.html#/overview\">" - + tr("The Online Document") + "</a>" - + - tr(" will get you started with GPGFrontend. It will open in the main window.<br>")); - - bottomLabel->setTextFormat(Qt::RichText); - bottomLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); - bottomLabel->setOpenExternalLinks(true); - bottomLabel->setWordWrap(true); - - openHelpCheckBox = new QCheckBox(tr("Open offline help.")); - openHelpCheckBox->setChecked(Qt::Checked); - - dontShowWizardCheckBox = new QCheckBox(tr("Dont show the wizard again.")); - dontShowWizardCheckBox->setChecked(Qt::Checked); - - registerField("showWizard", dontShowWizardCheckBox); - // registerField("openHelp", openHelpCheckBox); - - auto *layout = new QVBoxLayout; - layout->addWidget(bottomLabel); - // layout->addWidget(openHelpCheckBox); - layout->addWidget(dontShowWizardCheckBox); - setLayout(layout); - setVisible(true); +ConclusionPage::ConclusionPage(QWidget* parent) : QWizardPage(parent) { + setTitle(_("Ready.")); + setSubTitle(_("Have fun with GpgFrontend!")); + + auto* bottomLabel = + new QLabel(QString(_("You are ready to use GpgFrontend now.<br><br>")) + + "<a " + "href=\"https://saturneric.github.io/GpgFrontend/index.html#/" + "overview\">" + + _("The Online Document") + "</a>" + + _(" will get you started with GpgFrontend. It will open in " + "the main window.") + + "<br>"); + + bottomLabel->setTextFormat(Qt::RichText); + bottomLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); + bottomLabel->setOpenExternalLinks(true); + bottomLabel->setWordWrap(true); + + openHelpCheckBox = new QCheckBox(_("Open offline help.")); + openHelpCheckBox->setChecked(Qt::Checked); + + dontShowWizardCheckBox = new QCheckBox(_("Dont show the wizard again.")); + dontShowWizardCheckBox->setChecked(Qt::Checked); + + registerField("showWizard", dontShowWizardCheckBox); + // registerField("openHelp", openHelpCheckBox); + + auto* layout = new QVBoxLayout; + layout->addWidget(bottomLabel); + // layout->addWidget(openHelpCheckBox); + layout->addWidget(dontShowWizardCheckBox); + setLayout(layout); + setVisible(true); } -int ConclusionPage::nextId() const { - return -1; -} +int ConclusionPage::nextId() const { return -1; } + +} // namespace GpgFrontend::UI diff --git a/src/ui/Wizard.h b/src/ui/Wizard.h new file mode 100644 index 00000000..8d7395db --- /dev/null +++ b/src/ui/Wizard.h @@ -0,0 +1,114 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef WIZARD_H +#define WIZARD_H + +#include "gpg/GpgConstants.h" +#include "ui/GpgFrontendUI.h" +#include "ui/KeyMgmt.h" +#include "ui/keygen/KeygenDialog.h" +#include "ui/settings/SettingsDialog.h" + +namespace GpgFrontend::UI { + +class Wizard : public QWizard { + Q_OBJECT + Q_ENUMS(WizardPages) + + public: + enum WizardPages { Page_Intro, Page_Choose, Page_GenKey, Page_Conclusion }; + + Wizard(QWidget* parent = nullptr); + + private slots: + + void slotWizardAccepted(); + + signals: + + void signalOpenHelp(QString page); +}; + +class IntroPage : public QWizardPage { + Q_OBJECT + + public: + explicit IntroPage(QWidget* parent = nullptr); + + QHash<QString, QString> languages; + + [[nodiscard]] int nextId() const override; + + private: + private slots: + + // void slotLangChange(const QString& lang); +}; + +class ChoosePage : public QWizardPage { + Q_OBJECT + + public: + explicit ChoosePage(QWidget* parent = nullptr); + + private slots: + + void slotJumpPage(const QString& page); + + private: + [[nodiscard]] int nextId() const override; + + int nextPage; +}; + +class KeyGenPage : public QWizardPage { + Q_OBJECT + + public: + explicit KeyGenPage(QWidget* parent = nullptr); + + [[nodiscard]] int nextId() const override; + + private slots: + + void slotGenerateKeyDialog(); +}; + +class ConclusionPage : public QWizardPage { + Q_OBJECT + + public: + explicit ConclusionPage(QWidget* parent = nullptr); + + [[nodiscard]] int nextId() const override; + + private: + QCheckBox* dontShowWizardCheckBox; + QCheckBox* openHelpCheckBox; +}; + +} // namespace GpgFrontend::UI + +#endif diff --git a/src/ui/function/FileReadThread.cpp b/src/ui/function/FileReadThread.cpp new file mode 100644 index 00000000..a5a861ea --- /dev/null +++ b/src/ui/function/FileReadThread.cpp @@ -0,0 +1,68 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * + */ + +#include "FileReadThread.h" + +#include <boost/filesystem.hpp> +#include <utility> + +namespace GpgFrontend::UI { + +FileReadThread::FileReadThread(std::string path) : path(std::move(path)) {} + +void FileReadThread::run() { + LOG(INFO) << "Started"; + boost::filesystem::path read_file_path(this->path); + if (is_regular_file(read_file_path)) { + LOG(INFO) << "Read Open"; + + auto fp = fopen(read_file_path.string().c_str(), "r"); + size_t read_size; + LOG(INFO) << "Thread Start Reading"; + + char buffer[8192]; + while ((read_size = fread(buffer, sizeof(char), sizeof buffer, fp)) > 0) { + // Check isInterruptionRequested + if (QThread::currentThread()->isInterruptionRequested()) { + LOG(INFO) << "Read Thread isInterruptionRequested "; + fclose(fp); + return; + } + LOG(INFO) << "Read Thread Read block size " << read_size; + std::string buffer_str(buffer, read_size); + + emit sendReadBlock(QString::fromStdString(buffer_str)); +#ifdef RELEASE + QThread::msleep(16); +#else + QThread::msleep(24); +#endif + } + fclose(fp); + emit readDone(); + LOG(INFO) << "Thread End Reading"; + } +} + +} // namespace GpgFrontend::UI diff --git a/src/ui/function/FileReadThread.h b/src/ui/function/FileReadThread.h new file mode 100644 index 00000000..ebfcfb3c --- /dev/null +++ b/src/ui/function/FileReadThread.h @@ -0,0 +1,52 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_FILEREADTHREAD_H +#define GPGFRONTEND_FILEREADTHREAD_H + +#include "ui/GpgFrontendUI.h" +namespace GpgFrontend::UI { + +class FileReadThread : public QThread { + Q_OBJECT + + public: + explicit FileReadThread(std::string path); + + signals: + + void sendReadBlock(const QString& block); + + void readDone(); + + protected: + void run() override; + + private: + std::string path; +}; + +} // namespace GpgFrontend::UI + +#endif // GPGFRONTEND_FILEREADTHREAD_H diff --git a/src/ui/function/VersionCheckThread.cpp b/src/ui/function/VersionCheckThread.cpp new file mode 100644 index 00000000..50a4160e --- /dev/null +++ b/src/ui/function/VersionCheckThread.cpp @@ -0,0 +1,77 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#include "VersionCheckThread.h" + +#include "GpgFrontendBuildInfo.h" +#include "rapidjson/document.h" + +using namespace rapidjson; + +namespace GpgFrontend::UI { + +void VersionCheckThread::run() { + LOG(INFO) << "Start Version Thread to get latest version from Github"; + + auto currentVersion = "v" + QString::number(VERSION_MAJOR) + "." + + QString::number(VERSION_MINOR) + "." + + QString::number(VERSION_PATCH); + + while (mNetworkReply->isRunning()) { + QApplication::processEvents(); + } + + if (mNetworkReply->error() != QNetworkReply::NoError) { + LOG(ERROR) << "VersionCheckThread Found Network Error"; + return; + } + + QByteArray bytes = mNetworkReply->readAll(); + + Document d; + d.Parse(bytes.constData()); + + QString latestVersion = d["tag_name"].GetString(); + + LOG(INFO) << "Latest Version From Github" << latestVersion.toStdString(); + + QRegularExpression re(R"(^[vV](\d+\.)?(\d+\.)?(\*|\d+))"); + QRegularExpressionMatch match = re.match(latestVersion); + if (match.hasMatch()) { + latestVersion = match.captured(0); // matched == "23 def" + LOG(INFO) << "Latest Version Matched" << latestVersion.toStdString(); + } else { + latestVersion = currentVersion; + LOG(WARNING) << "Latest Version Unknown" << latestVersion.toStdString(); + } + + if (latestVersion != currentVersion) { + emit upgradeVersion(currentVersion, latestVersion); + } +} + +VersionCheckThread::VersionCheckThread(QNetworkReply* networkReply) + : mNetworkReply(networkReply) {} + +} // namespace GpgFrontend::UI diff --git a/src/ui/function/VersionCheckThread.h b/src/ui/function/VersionCheckThread.h new file mode 100644 index 00000000..181ee947 --- /dev/null +++ b/src/ui/function/VersionCheckThread.h @@ -0,0 +1,52 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_VERSIONCHECKTHREAD_H +#define GPGFRONTEND_VERSIONCHECKTHREAD_H + +#include "ui/GpgFrontendUI.h" + +namespace GpgFrontend::UI { + +class VersionCheckThread : public QThread { + Q_OBJECT + + public: + explicit VersionCheckThread(QNetworkReply* networkReply); + + signals: + + void upgradeVersion(const QString& currentVersion, + const QString& latestVersion); + + protected: + void run() override; + + private: + QNetworkReply* mNetworkReply; +}; + +} // namespace GpgFrontend::UI + +#endif // GPGFRONTEND_VERSIONCHECKTHREAD_H diff --git a/src/ui/help/AboutDialog.cpp b/src/ui/help/AboutDialog.cpp index 8fb504db..7358ced5 100644 --- a/src/ui/help/AboutDialog.cpp +++ b/src/ui/help/AboutDialog.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -23,197 +23,218 @@ */ #include "ui/help/AboutDialog.h" -#include "GpgFrontendBuildInfo.h" +#include "GpgFrontendBuildInfo.h" #include "rapidjson/document.h" #include "rapidjson/writer.h" using namespace rapidjson; -AboutDialog::AboutDialog(int defaultIndex, QWidget *parent) - : QDialog(parent) { - this->setWindowTitle(tr("About ") + qApp->applicationName()); +namespace GpgFrontend::UI { - auto *tabWidget = new QTabWidget; - auto *infoTab = new InfoTab(); - auto *translatorsTab = new TranslatorsTab(); - updateTab = new UpdateTab(); +AboutDialog::AboutDialog(int defaultIndex, QWidget* parent) : QDialog(parent) { + this->setWindowTitle(QString(_("About")) + " " + qApp->applicationName()); - tabWidget->addTab(infoTab, tr("General")); - tabWidget->addTab(translatorsTab, tr("Translators")); - tabWidget->addTab(updateTab, tr("Update")); + auto* tabWidget = new QTabWidget; + auto* infoTab = new InfoTab(); + auto* translatorsTab = new TranslatorsTab(); + updateTab = new UpdateTab(); - connect(tabWidget, &QTabWidget::currentChanged, this, [&](int index) { - qDebug() << "Current Index" << index; - }); + tabWidget->addTab(infoTab, _("General")); + tabWidget->addTab(translatorsTab, _("Translators")); + tabWidget->addTab(updateTab, _("Update")); - if(defaultIndex < tabWidget->count() && defaultIndex >= 0) { - tabWidget->setCurrentIndex(defaultIndex); - } + connect(tabWidget, &QTabWidget::currentChanged, this, + [&](int index) { qDebug() << "Current Index" << index; }); - auto *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok); - connect(buttonBox, SIGNAL(accepted()), this, SLOT(close())); + if (defaultIndex < tabWidget->count() && defaultIndex >= 0) { + tabWidget->setCurrentIndex(defaultIndex); + } - auto *mainLayout = new QVBoxLayout; - mainLayout->addWidget(tabWidget); - mainLayout->addWidget(buttonBox); - setLayout(mainLayout); + auto* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok); + connect(buttonBox, SIGNAL(accepted()), this, SLOT(close())); + + auto* mainLayout = new QVBoxLayout; + mainLayout->addWidget(tabWidget); + mainLayout->addWidget(buttonBox); + setLayout(mainLayout); - this->resize(320, 580); - - this->show(); + this->resize(320, 580); + this->show(); } -void AboutDialog::showEvent(QShowEvent *ev) { - QDialog::showEvent(ev); - updateTab->getLatestVersion(); +void AboutDialog::showEvent(QShowEvent* ev) { + QDialog::showEvent(ev); + updateTab->getLatestVersion(); } -InfoTab::InfoTab(QWidget *parent) - : QWidget(parent) { - auto *pixmap = new QPixmap(":gpgfrontend-logo.png"); - auto *text = new QString("<center><h2>" + qApp->applicationName() + "</h2></center>" - + "<center><b>" + qApp->applicationVersion() + "</b></center>" - + "<center>" + GIT_VERSION + "</center>" - + tr("<br><center>GPGFrontend is an easy-to-use, compact, cross-platform, <br>" - "and installation-free gpg front-end tool.<br>" - "It visualizes most of the common operations of gpg commands.<br>" - "It's licensed under the GPL v3<br><br>" - "<b>Developer:</b><br>" - "Saturneric<br><br>" - "If you have any questions or suggestions, raise an issue<br/>" - "at <a href=\"https://github.com/saturneric/GpgFrontend\">GitHub</a> or send a mail to my mailing list at <a href=\"mailto:[email protected]\">[email protected]</a>.") + - tr("<br><br> Built with Qt ") + qVersion() - + tr(" and GPGME ") + GpgME::GpgContext::getGpgmeVersion() + - tr("<br>Built at ") + BUILD_TIMESTAMP + "</center>"); - - auto *layout = new QGridLayout(); - auto *pixmapLabel = new QLabel(); - pixmapLabel->setPixmap(*pixmap); - layout->addWidget(pixmapLabel, 0, 0, 1, -1, Qt::AlignCenter); - auto *aboutLabel = new QLabel(); - aboutLabel->setText(*text); - aboutLabel->setOpenExternalLinks(true); - layout->addWidget(aboutLabel, 1, 0, 1, -1); - layout->addItem(new QSpacerItem(20, 10, QSizePolicy::Minimum, - QSizePolicy::Fixed), 2, 1, 1, 1); - - setLayout(layout); +InfoTab::InfoTab(QWidget* parent) : QWidget(parent) { + auto* pixmap = new QPixmap(":gpgfrontend-logo.png"); + auto* text = new QString( + "<center><h2>" + qApp->applicationName() + "</h2></center>" + + "<center><b>" + qApp->applicationVersion() + "</b></center>" + + "<center>" + GIT_VERSION + "</center>" + + _("<br><center>GpgFrontend is an easy-to-use, compact, cross-platform, " + "<br>" + "and installation-free gpg front-end tool.<br>" + "It visualizes most of the common operations of gpg commands.<br>" + "It's licensed under the GPL v3<br><br>" + "<b>Developer:</b><br>" + "Saturneric<br><br>" + "If you have any questions or suggestions, raise an issue<br/>" + "at <a href=\"https://github.com/saturneric/GpgFrontend\">GitHub</a> " + "or send a mail to my mailing list at <a " + "href=\"mailto:[email protected]\">[email protected]</a>.") + + "<br><br> " + _("Built with Qt") + " " + qVersion() + " " + + _("and GPGME") + " " + + GpgFrontend::GpgContext::getGpgmeVersion().c_str() + "<br>" + + _("Built at") + " " + BUILD_TIMESTAMP + "</center>"); + + auto* layout = new QGridLayout(); + auto* pixmapLabel = new QLabel(); + pixmapLabel->setPixmap(*pixmap); + layout->addWidget(pixmapLabel, 0, 0, 1, -1, Qt::AlignCenter); + auto* aboutLabel = new QLabel(); + aboutLabel->setText(*text); + aboutLabel->setOpenExternalLinks(true); + layout->addWidget(aboutLabel, 1, 0, 1, -1); + layout->addItem( + new QSpacerItem(20, 10, QSizePolicy::Minimum, QSizePolicy::Fixed), 2, 1, + 1, 1); + + setLayout(layout); } -TranslatorsTab::TranslatorsTab(QWidget *parent) - : QWidget(parent) { - QFile translatorsFile; - translatorsFile.setFileName(qApp->applicationDirPath() + "/About"); - translatorsFile.open(QIODevice::ReadOnly); - QByteArray inBuffer = translatorsFile.readAll(); +TranslatorsTab::TranslatorsTab(QWidget* parent) : QWidget(parent) { + QFile translatorsFile; + translatorsFile.setFileName(qApp->applicationDirPath() + "/About"); + translatorsFile.open(QIODevice::ReadOnly); + QByteArray inBuffer = translatorsFile.readAll(); - auto *label = new QLabel(inBuffer); - auto *mainLayout = new QVBoxLayout(this); - mainLayout->addWidget(label); + auto* label = new QLabel(inBuffer); + auto* mainLayout = new QVBoxLayout(this); + mainLayout->addWidget(label); - setLayout(mainLayout); + setLayout(mainLayout); } -UpdateTab::UpdateTab(QWidget *parent) { - auto *pixmap = new QPixmap(":gpgfrontend-logo.png"); - auto *layout = new QGridLayout(); - auto *pixmapLabel = new QLabel(); - pixmapLabel->setPixmap(*pixmap); - layout->addWidget(pixmapLabel, 0, 0, 1, -1, Qt::AlignCenter); - - currentVersion = "v" + QString::number(VERSION_MAJOR) + "." - + QString::number(VERSION_MINOR) + "." - + QString::number(VERSION_PATCH); - - auto tipsLabel = new QLabel(); - tipsLabel->setText("<center>" + - tr("It is recommended that you always check the version of GpgFrontend and upgrade to the latest version.") + - "</center><br><center>" + - tr("New versions not only represent new features, but also often represent functional and security fixes.") + "</center>"); - tipsLabel->setWordWrap(true); - - currentVersionLabel = new QLabel(); - currentVersionLabel->setText("<center>" + tr("Current Version: ") + "<b>" + currentVersion + "</b></center>"); - currentVersionLabel->setWordWrap(true); - - latestVersionLabel = new QLabel(); - latestVersionLabel->setWordWrap(true); - - upgradeLabel = new QLabel(); - upgradeLabel->setText("<center>" + - tr("The current version is inconsistent with the latest version on github.") + - "</center><br><center>" + - tr("Please click <a href=\"https://github.com/saturneric/GpgFrontend/releases\">here</a> to download the latest version.") + "</center>"); - upgradeLabel->setWordWrap(true); - upgradeLabel->setOpenExternalLinks(true); - upgradeLabel->setHidden(true); - - pb = new QProgressBar(); - pb->setRange(0, 0); - pb->setTextVisible(false); - - layout->addWidget(tipsLabel, 1, 0, 1, -1); - layout->addWidget(currentVersionLabel, 2, 0, 1, -1); - layout->addWidget(latestVersionLabel, 3, 0, 1, -1); - layout->addWidget(upgradeLabel, 4, 0, 1, -1); - layout->addWidget(pb, 5, 0, 1, -1); - layout->addItem(new QSpacerItem(20, 10, QSizePolicy::Minimum, - QSizePolicy::Fixed), 2, 1, 1, 1); - - connect(this, SIGNAL(replyFromUpdateServer(QByteArray)), this, SLOT(processReplyDataFromUpdateServer(QByteArray))); - - setLayout(layout); +UpdateTab::UpdateTab(QWidget* parent) { + auto* pixmap = new QPixmap(":gpgfrontend-logo.png"); + auto* layout = new QGridLayout(); + auto* pixmapLabel = new QLabel(); + pixmapLabel->setPixmap(*pixmap); + layout->addWidget(pixmapLabel, 0, 0, 1, -1, Qt::AlignCenter); + + currentVersion = "v" + QString::number(VERSION_MAJOR) + "." + + QString::number(VERSION_MINOR) + "." + + QString::number(VERSION_PATCH); + + auto tipsLabel = new QLabel(); + tipsLabel->setText( + "<center>" + + QString(_("It is recommended that you always check the version " + "of GpgFrontend and upgrade to the latest version.")) + + "</center><br><center>" + + _("New versions not only represent new features, but " + "also often represent functional and security fixes.") + + "</center>"); + tipsLabel->setWordWrap(true); + + currentVersionLabel = new QLabel(); + currentVersionLabel->setText("<center>" + QString(_("Current Version")) + + _(": ") + "<b>" + currentVersion + + "</b></center>"); + currentVersionLabel->setWordWrap(true); + + latestVersionLabel = new QLabel(); + latestVersionLabel->setWordWrap(true); + + upgradeLabel = new QLabel(); + upgradeLabel->setText( + "<center>" + + QString( + _("The current version is inconsistent with the latest version on " + "github.")) + + "</center><br><center>" + _("Please click") + + " <a " + "href=\"https://github.com/saturneric/GpgFrontend/releases\">here</a> " + + _("to download the latest version.") + "</center>"); + upgradeLabel->setWordWrap(true); + upgradeLabel->setOpenExternalLinks(true); + upgradeLabel->setHidden(true); + + pb = new QProgressBar(); + pb->setRange(0, 0); + pb->setTextVisible(false); + + layout->addWidget(tipsLabel, 1, 0, 1, -1); + layout->addWidget(currentVersionLabel, 2, 0, 1, -1); + layout->addWidget(latestVersionLabel, 3, 0, 1, -1); + layout->addWidget(upgradeLabel, 4, 0, 1, -1); + layout->addWidget(pb, 5, 0, 1, -1); + layout->addItem( + new QSpacerItem(20, 10, QSizePolicy::Minimum, QSizePolicy::Fixed), 2, 1, + 1, 1); + + connect(this, SIGNAL(replyFromUpdateServer(QByteArray)), this, + SLOT(processReplyDataFromUpdateServer(QByteArray))); + + setLayout(layout); } void UpdateTab::getLatestVersion() { + this->pb->setHidden(false); - this->pb->setHidden(false); - - qDebug() << "Try to get latest version"; + qDebug() << "Try to get latest version"; - QString baseUrl = "https://api.github.com/repos/saturneric/gpgfrontend/releases/latest"; + QString baseUrl = + "https://api.github.com/repos/saturneric/gpgfrontend/releases/latest"; - auto manager = new QNetworkAccessManager(this); - - QNetworkRequest request; - request.setUrl(QUrl(baseUrl)); - QNetworkReply *replay = manager->get(request); - auto thread = QThread::create([replay, this]() { - while(replay->isRunning()) QApplication::processEvents(); - emit replyFromUpdateServer(replay->readAll()); - }); - connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); - thread->start(); + auto manager = new QNetworkAccessManager(this); + QNetworkRequest request; + request.setUrl(QUrl(baseUrl)); + QNetworkReply* replay = manager->get(request); + auto thread = QThread::create([replay, this]() { + while (replay->isRunning()) QApplication::processEvents(); + emit replyFromUpdateServer(replay->readAll()); + }); + connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); + thread->start(); } void UpdateTab::processReplyDataFromUpdateServer(const QByteArray& data) { + qDebug() << "Try to Process Reply Data From Update Server"; - qDebug() << "Try to Process Reply Data From Update Server"; - - this->pb->setHidden(true); + this->pb->setHidden(true); - Document d; - if (d.Parse(data.constData()).HasParseError() || !d.IsObject()) { - qDebug() << "VersionCheckThread Found Network Error"; - auto latestVersion = "Unknown"; - latestVersionLabel->setText("<center><b>" + tr("Latest Version From Github: ") + latestVersion + "</b></center>"); - return; - } + Document d; + if (d.Parse(data.constData()).HasParseError() || !d.IsObject()) { + qDebug() << "VersionCheckThread Found Network Error"; + auto latestVersion = "Unknown"; + latestVersionLabel->setText(QString("<center><b>") + + _("Latest Version From Github") + ": " + + latestVersion + "</b></center>"); + return; + } - QString latestVersion = d["tag_name"].GetString(); + QString latestVersion = d["tag_name"].GetString(); - qDebug() << "Latest Version From Github" << latestVersion; + qDebug() << "Latest Version From Github" << latestVersion; - QRegularExpression re(R"(^[vV](\d+\.)?(\d+\.)?(\*|\d+))"); - QRegularExpressionMatch match = re.match(latestVersion); - if (match.hasMatch()) { - latestVersion = match.captured(0); - qDebug() << "Latest Version Matched" << latestVersion; - } else latestVersion = "Unknown"; + QRegularExpression re(R"(^[vV](\d+\.)?(\d+\.)?(\*|\d+))"); + QRegularExpressionMatch match = re.match(latestVersion); + if (match.hasMatch()) { + latestVersion = match.captured(0); + qDebug() << "Latest Version Matched" << latestVersion; + } else + latestVersion = "Unknown"; - latestVersionLabel->setText("<center><b>" + tr("Latest Version From Github: ") + latestVersion + "</b></center>"); + latestVersionLabel->setText("<center><b>" + + QString(_("Latest Version From Github")) + ": " + + latestVersion + "</b></center>"); - if(latestVersion > currentVersion) upgradeLabel->setHidden(false); + if (latestVersion > currentVersion) upgradeLabel->setHidden(false); } + +} // namespace GpgFrontend::UI diff --git a/src/ui/help/AboutDialog.h b/src/ui/help/AboutDialog.h new file mode 100644 index 00000000..a7d7099b --- /dev/null +++ b/src/ui/help/AboutDialog.h @@ -0,0 +1,103 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef __ABOUTDIALOG_H__ +#define __ABOUTDIALOG_H__ + +#include "gpg/GpgContext.h" +#include "ui/GpgFrontendUI.h" +namespace GpgFrontend::UI { + +/** + * @brief Class containing the main tab of about dialog + * + */ +class InfoTab : public QWidget { + Q_OBJECT + + public: + explicit InfoTab(QWidget* parent = nullptr); +}; + +/** + * @brief Class containing the translator tab of about dialog + * + */ +class TranslatorsTab : public QWidget { + Q_OBJECT + + public: + explicit TranslatorsTab(QWidget* parent = nullptr); +}; + +/** + * @brief Class containing the main tab of about dialog + * + */ +class UpdateTab : public QWidget { + Q_OBJECT + + QLabel* currentVersionLabel; + + QLabel* latestVersionLabel; + + QLabel* upgradeLabel; + + QProgressBar* pb; + + QString currentVersion; + + public: + explicit UpdateTab(QWidget* parent = nullptr); + + void getLatestVersion(); + + private slots: + void processReplyDataFromUpdateServer(const QByteArray& data); + ; + + signals: + void replyFromUpdateServer(QByteArray data); +}; + +/** + * @brief Class for handling the about dialog + * + */ +class AboutDialog : public QDialog { + Q_OBJECT + + public: + explicit AboutDialog(int defaultIndex, QWidget* parent); + + protected: + void showEvent(QShowEvent* ev) override; + + private: + UpdateTab* updateTab; +}; + +} // namespace GpgFrontend::UI + +#endif // __ABOUTDIALOG_H__ diff --git a/src/ui/help/VersionCheckThread.cpp b/src/ui/help/VersionCheckThread.cpp deleted file mode 100644 index bf1bbeda..00000000 --- a/src/ui/help/VersionCheckThread.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/** - * This file is part of GPGFrontend. - * - * GPGFrontend is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Foobar is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see <https://www.gnu.org/licenses/>. - * - * The initial version of the source code is inherited from gpg4usb-team. - * Their source code version also complies with GNU General Public License. - * - * The source code version of this software was modified and released - * by Saturneric<[email protected]> starting on May 12, 2021. - * - */ - -#include "ui/help/VersionCheckThread.h" -#include "GpgFrontendBuildInfo.h" -#include "rapidjson/document.h" -#include "rapidjson/writer.h" - -using namespace rapidjson; - -void VersionCheckThread::run() { - qDebug() << "Start Version Thread to get latest version from Github"; - - auto currentVersion = "v" + QString::number(VERSION_MAJOR) + "." - + QString::number(VERSION_MINOR) + "." - + QString::number(VERSION_PATCH); - - while(mNetworkReply->isRunning()) { - QApplication::processEvents(); - } - - if(mNetworkReply->error() != QNetworkReply::NoError) { - qDebug() << "VersionCheckThread Found Network Error"; - return; - } - - QByteArray bytes = mNetworkReply->readAll(); - - Document d; - d.Parse(bytes.constData()); - - QString latestVersion = d["tag_name"].GetString(); - - qDebug() << "Latest Version From Github" << latestVersion; - - QRegularExpression re("^[vV](\\d+\\.)?(\\d+\\.)?(\\*|\\d+)"); - QRegularExpressionMatch match = re.match(latestVersion); - if (match.hasMatch()) { - latestVersion = match.captured(0); // matched == "23 def" - qDebug() << "Latest Version Matched" << latestVersion; - } else { - latestVersion = currentVersion; - qDebug() << "Latest Version Unknown" << latestVersion; - } - - if(latestVersion != currentVersion) { - emit upgradeVersion(currentVersion, latestVersion); - } - -} - -VersionCheckThread::VersionCheckThread(QNetworkReply *networkReply):mNetworkReply(networkReply) { - -} diff --git a/src/ui/keygen/KeygenDialog.cpp b/src/ui/keygen/KeygenDialog.cpp index 98216dc6..382be5cb 100644 --- a/src/ui/keygen/KeygenDialog.cpp +++ b/src/ui/keygen/KeygenDialog.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -23,339 +23,358 @@ */ #include "ui/keygen/KeygenDialog.h" + +#include "gpg/function/GpgKeyOpera.h" +#include "ui/SignalStation.h" #include "ui/WaitingDialog.h" -KeyGenDialog::KeyGenDialog(GpgME::GpgContext *ctx, QWidget *parent) - : QDialog(parent), mCtx(ctx) { +namespace GpgFrontend::UI { - buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); +KeyGenDialog::KeyGenDialog(QWidget* parent) : QDialog(parent) { + buttonBox = + new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - this->setWindowTitle(tr("Generate Key")); - this->setModal(true); - generateKeyDialog(); -} + this->setWindowTitle(_("Generate Key")); + this->setModal(true); -void KeyGenDialog::generateKeyDialog() { + connect(this, SIGNAL(KeyGenerated()), SignalStation::GetInstance(), + SIGNAL(KeyDatabaseRefresh())); - keyUsageGroupBox = create_key_usage_group_box(); + generateKeyDialog(); +} - auto *groupGrid = new QGridLayout(this); - groupGrid->addWidget(create_basic_info_group_box(), 0, 0); - groupGrid->addWidget(keyUsageGroupBox, 1, 0); +void KeyGenDialog::generateKeyDialog() { + keyUsageGroupBox = create_key_usage_group_box(); - auto *nameList = new QWidget(this); - nameList->setLayout(groupGrid); + auto* groupGrid = new QGridLayout(this); + groupGrid->addWidget(create_basic_info_group_box(), 0, 0); + groupGrid->addWidget(keyUsageGroupBox, 1, 0); - auto *vbox2 = new QVBoxLayout(); - vbox2->addWidget(nameList); - vbox2->addWidget(errorLabel); - vbox2->addWidget(buttonBox); + auto* nameList = new QWidget(this); + nameList->setLayout(groupGrid); - this->setLayout(vbox2); + auto* vbox2 = new QVBoxLayout(); + vbox2->addWidget(nameList); + vbox2->addWidget(errorLabel); + vbox2->addWidget(buttonBox); - set_signal_slot(); + this->setLayout(vbox2); - refresh_widgets_state(); + set_signal_slot(); + refresh_widgets_state(); } void KeyGenDialog::slotKeyGenAccept() { - QString errorString = ""; - + std::stringstream error_stream; + + /** + * check for errors in keygen dialog input + */ + if ((nameEdit->text()).size() < 5) { + error_stream << " " << _("Name must contain at least five characters.") + << std::endl; + } + if (emailEdit->text().isEmpty() || !check_email_address(emailEdit->text())) { + error_stream << " " << _("Please give a email address.") << std::endl; + } + + /** + * primary keys should have a reasonable expiration date (no more than 2 years + * in the future) + */ + if (dateEdit->dateTime() > QDateTime::currentDateTime().addYears(2)) { + error_stream << " " << _("Expiration time no more than 2 years.") + << std::endl; + } + + auto err_string = error_stream.str(); + + if (err_string.empty()) { /** - * check for errors in keygen dialog input + * create the string for key generation */ - if ((nameEdit->text()).size() < 5) { - errorString.append(tr(" Name must contain at least five characters. \n")); - } if(emailEdit->text().isEmpty() || !check_email_address(emailEdit->text())) { - errorString.append(tr(" Please give a email address. \n")); - } - /** - * primary keys should have a reasonable expiration date (no more than 2 years in the future) - */ - if(dateEdit->dateTime() > QDateTime::currentDateTime().addYears(2)) { - errorString.append(tr(" Expiration time no more than 2 years. \n")); - } - - if (errorString.isEmpty()) { - /** - * create the string for key generation - */ + genKeyInfo->setUserid( + QString("%1(%3)<%2>") + .arg(nameEdit->text(), emailEdit->text(), commentEdit->text()) + .toStdString()); - genKeyInfo.setUserid(QString("%1 (%3) <%2>").arg(nameEdit->text(), emailEdit->text(), commentEdit->text())); + genKeyInfo->setKeySize(keySizeSpinBox->value()); - genKeyInfo.setKeySize(keySizeSpinBox->value()); - - if (expireCheckBox->checkState()) { - genKeyInfo.setNonExpired(true); - } else { - genKeyInfo.setExpired(dateEdit->dateTime()); - } + if (expireCheckBox->checkState()) { + genKeyInfo->setNonExpired(true); + } else { + genKeyInfo->setExpired( + boost::posix_time::from_time_t(dateEdit->dateTime().toTime_t()) + .date()); + } - gpgme_error_t error = false; - auto thread = QThread::create([&]() { - error = mCtx->generateKey(&genKeyInfo); - }); - thread->start(); + gpgme_error_t error = false; + auto thread = QThread::create( + [&]() { error = GpgKeyOpera::GetInstance().GenerateKey(genKeyInfo); }); + thread->start(); - auto *dialog = new WaitingDialog("Generating", this); - dialog->show(); + auto* dialog = new WaitingDialog("Generating", this); + dialog->show(); - while (thread->isRunning()) { - QCoreApplication::processEvents(); - } + while (thread->isRunning()) { + QCoreApplication::processEvents(); + } - dialog->close(); + dialog->close(); - if(gpgme_err_code(error) == GPG_ERR_NO_ERROR) { - QMessageBox::information(this, tr("Success"), tr("The new key pair has been generated.")); - this->close(); - } - else - QMessageBox::critical(this, tr("Failure"), tr(gpgme_strerror(error))); + if (gpgme_err_code(error) == GPG_ERR_NO_ERROR) { + auto* msg_box = new QMessageBox(nullptr); + msg_box->setAttribute(Qt::WA_DeleteOnClose); + msg_box->setStandardButtons(QMessageBox::Ok); + msg_box->setWindowTitle(_("Success")); + msg_box->setText(_("The new key pair has been generated.")); + msg_box->setModal(false); + msg_box->open(); + emit KeyGenerated(); + this->close(); } else { - /** - * create error message - */ - errorLabel->setAutoFillBackground(true); - QPalette error = errorLabel->palette(); - error.setColor(QPalette::Window, "#ff8080"); - errorLabel->setPalette(error); - errorLabel->setText(errorString); - - this->show(); + QMessageBox::critical(this, _("Failure"), _(gpgme_strerror(error))); } + + } else { + /** + * create error message + */ + errorLabel->setAutoFillBackground(true); + QPalette error = errorLabel->palette(); + error.setColor(QPalette::Window, "#ff8080"); + errorLabel->setPalette(error); + errorLabel->setText(err_string.c_str()); + + this->show(); + } } void KeyGenDialog::slotExpireBoxChanged() { - if (expireCheckBox->checkState()) { - dateEdit->setEnabled(false); - } else { - dateEdit->setEnabled(true); - } + if (expireCheckBox->checkState()) { + dateEdit->setEnabled(false); + } else { + dateEdit->setEnabled(true); + } } -QGroupBox *KeyGenDialog::create_key_usage_group_box() { - - auto *groupBox = new QGroupBox(this); - auto *grid = new QGridLayout(this); +QGroupBox* KeyGenDialog::create_key_usage_group_box() { + auto* groupBox = new QGroupBox(this); + auto* grid = new QGridLayout(this); - groupBox->setTitle(tr("Key Usage")); + groupBox->setTitle(_("Key Usage")); - auto* encrypt = new QCheckBox(tr("Encryption"), groupBox); - encrypt->setTristate(false); + auto* encrypt = new QCheckBox(_("Encryption"), groupBox); + encrypt->setTristate(false); - auto* sign = new QCheckBox(tr("Signing"),groupBox); - sign->setTristate(false); + auto* sign = new QCheckBox(_("Signing"), groupBox); + sign->setTristate(false); - auto* cert = new QCheckBox(tr("Certification"),groupBox); - cert->setTristate(false); + auto* cert = new QCheckBox(_("Certification"), groupBox); + cert->setTristate(false); - auto* auth = new QCheckBox(tr("Authentication"), groupBox); - auth->setTristate(false); + auto* auth = new QCheckBox(_("Authentication"), groupBox); + auth->setTristate(false); - keyUsageCheckBoxes.push_back(encrypt); - keyUsageCheckBoxes.push_back(sign); - keyUsageCheckBoxes.push_back(cert); - keyUsageCheckBoxes.push_back(auth); + keyUsageCheckBoxes.push_back(encrypt); + keyUsageCheckBoxes.push_back(sign); + keyUsageCheckBoxes.push_back(cert); + keyUsageCheckBoxes.push_back(auth); - grid->addWidget(encrypt, 0, 0); - grid->addWidget(sign, 0, 1); - grid->addWidget(cert, 1, 0); - grid->addWidget(auth, 1, 1); + grid->addWidget(encrypt, 0, 0); + grid->addWidget(sign, 0, 1); + grid->addWidget(cert, 1, 0); + grid->addWidget(auth, 1, 1); - groupBox->setLayout(grid); + groupBox->setLayout(grid); - return groupBox; + return groupBox; } void KeyGenDialog::slotEncryptionBoxChanged(int state) { - if(state == 0) { - genKeyInfo.setAllowEncryption(false); - } else { - genKeyInfo.setAllowEncryption(true); - } + if (state == 0) { + genKeyInfo->setAllowEncryption(false); + } else { + genKeyInfo->setAllowEncryption(true); + } } void KeyGenDialog::slotSigningBoxChanged(int state) { - if(state == 0) { - genKeyInfo.setAllowSigning(false); - } else { - genKeyInfo.setAllowSigning(true); - } + if (state == 0) { + genKeyInfo->setAllowSigning(false); + } else { + genKeyInfo->setAllowSigning(true); + } } void KeyGenDialog::slotCertificationBoxChanged(int state) { - if(state == 0) { - genKeyInfo.setAllowCertification(false); - } else { - genKeyInfo.setAllowCertification(true); - } + if (state == 0) { + genKeyInfo->setAllowCertification(false); + } else { + genKeyInfo->setAllowCertification(true); + } } void KeyGenDialog::slotAuthenticationBoxChanged(int state) { - if(state == 0) { - genKeyInfo.setAllowAuthentication(false); - } else { - genKeyInfo.setAllowAuthentication(true); - } + if (state == 0) { + genKeyInfo->setAllowAuthentication(false); + } else { + genKeyInfo->setAllowAuthentication(true); + } } void KeyGenDialog::slotActivatedKeyType(int index) { + qDebug() << "key type index changed " << index; - qDebug() << "key type index changed " << index; - - genKeyInfo.setAlgo(this->keyTypeComboBox->itemText(index)); - refresh_widgets_state(); + genKeyInfo->setAlgo(this->keyTypeComboBox->itemText(index).toStdString()); + refresh_widgets_state(); } void KeyGenDialog::refresh_widgets_state() { - - qDebug() << "refresh_widgets_state called"; - - if(genKeyInfo.isAllowEncryption()) - keyUsageCheckBoxes[0]->setCheckState(Qt::CheckState::Checked); - else - keyUsageCheckBoxes[0]->setCheckState(Qt::CheckState::Unchecked); - - if(genKeyInfo.isAllowChangeEncryption()) - keyUsageCheckBoxes[0]->setDisabled(false); - else - keyUsageCheckBoxes[0]->setDisabled(true); - - - if(genKeyInfo.isAllowSigning()) - keyUsageCheckBoxes[1]->setCheckState(Qt::CheckState::Checked); - else - keyUsageCheckBoxes[1]->setCheckState(Qt::CheckState::Unchecked); - - if(genKeyInfo.isAllowChangeSigning()) - keyUsageCheckBoxes[1]->setDisabled(false); - else - keyUsageCheckBoxes[1]->setDisabled(true); - - - if(genKeyInfo.isAllowCertification()) - keyUsageCheckBoxes[2]->setCheckState(Qt::CheckState::Checked); - else - keyUsageCheckBoxes[2]->setCheckState(Qt::CheckState::Unchecked); - - if(genKeyInfo.isAllowChangeCertification()) - keyUsageCheckBoxes[2]->setDisabled(false); - else - keyUsageCheckBoxes[2]->setDisabled(true); - - - if(genKeyInfo.isAllowAuthentication()) - keyUsageCheckBoxes[3]->setCheckState(Qt::CheckState::Checked); - else - keyUsageCheckBoxes[3]->setCheckState(Qt::CheckState::Unchecked); - - if(genKeyInfo.isAllowChangeAuthentication()) - keyUsageCheckBoxes[3]->setDisabled(false); - else - keyUsageCheckBoxes[3]->setDisabled(true); - - - - if(genKeyInfo.isAllowNoPassPhrase()) - noPassPhraseCheckBox->setDisabled(false); - else - noPassPhraseCheckBox->setDisabled(true); - - - keySizeSpinBox->setRange(genKeyInfo.getSuggestMinKeySize(), genKeyInfo.getSuggestMaxKeySize()); - keySizeSpinBox->setValue(genKeyInfo.getKeySize()); - keySizeSpinBox->setSingleStep(genKeyInfo.getSizeChangeStep()); - - + qDebug() << "refresh_widgets_state called"; + + if (genKeyInfo->isAllowEncryption()) + keyUsageCheckBoxes[0]->setCheckState(Qt::CheckState::Checked); + else + keyUsageCheckBoxes[0]->setCheckState(Qt::CheckState::Unchecked); + + if (genKeyInfo->isAllowChangeEncryption()) + keyUsageCheckBoxes[0]->setDisabled(false); + else + keyUsageCheckBoxes[0]->setDisabled(true); + + if (genKeyInfo->isAllowSigning()) + keyUsageCheckBoxes[1]->setCheckState(Qt::CheckState::Checked); + else + keyUsageCheckBoxes[1]->setCheckState(Qt::CheckState::Unchecked); + + if (genKeyInfo->isAllowChangeSigning()) + keyUsageCheckBoxes[1]->setDisabled(false); + else + keyUsageCheckBoxes[1]->setDisabled(true); + + if (genKeyInfo->isAllowCertification()) + keyUsageCheckBoxes[2]->setCheckState(Qt::CheckState::Checked); + else + keyUsageCheckBoxes[2]->setCheckState(Qt::CheckState::Unchecked); + + if (genKeyInfo->isAllowChangeCertification()) + keyUsageCheckBoxes[2]->setDisabled(false); + else + keyUsageCheckBoxes[2]->setDisabled(true); + + if (genKeyInfo->isAllowAuthentication()) + keyUsageCheckBoxes[3]->setCheckState(Qt::CheckState::Checked); + else + keyUsageCheckBoxes[3]->setCheckState(Qt::CheckState::Unchecked); + + if (genKeyInfo->isAllowChangeAuthentication()) + keyUsageCheckBoxes[3]->setDisabled(false); + else + keyUsageCheckBoxes[3]->setDisabled(true); + + if (genKeyInfo->isAllowNoPassPhrase()) + noPassPhraseCheckBox->setDisabled(false); + else + noPassPhraseCheckBox->setDisabled(true); + + keySizeSpinBox->setRange(genKeyInfo->getSuggestMinKeySize(), + genKeyInfo->getSuggestMaxKeySize()); + keySizeSpinBox->setValue(genKeyInfo->getKeySize()); + keySizeSpinBox->setSingleStep(genKeyInfo->getSizeChangeStep()); } void KeyGenDialog::set_signal_slot() { - - connect(buttonBox, SIGNAL(accepted()), this, SLOT(slotKeyGenAccept())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); - - connect(expireCheckBox, SIGNAL(stateChanged(int)), this, SLOT(slotExpireBoxChanged())); - - connect(keyUsageCheckBoxes[0], SIGNAL(stateChanged(int)), this, SLOT(slotEncryptionBoxChanged(int))); - connect(keyUsageCheckBoxes[1], SIGNAL(stateChanged(int)), this, SLOT(slotSigningBoxChanged(int))); - connect(keyUsageCheckBoxes[2], SIGNAL(stateChanged(int)), this, SLOT(slotCertificationBoxChanged(int))); - connect(keyUsageCheckBoxes[3], SIGNAL(stateChanged(int)), this, SLOT(slotAuthenticationBoxChanged(int))); - - connect(keyTypeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotActivatedKeyType(int))); - - connect(noPassPhraseCheckBox, &QCheckBox::stateChanged, this, [this](int state) -> void { - if(state == 0) { - genKeyInfo.setNonPassPhrase(false); - } else { - genKeyInfo.setNonPassPhrase(true); - } - - }); - + connect(buttonBox, SIGNAL(accepted()), this, SLOT(slotKeyGenAccept())); + connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + + connect(expireCheckBox, SIGNAL(stateChanged(int)), this, + SLOT(slotExpireBoxChanged())); + + connect(keyUsageCheckBoxes[0], SIGNAL(stateChanged(int)), this, + SLOT(slotEncryptionBoxChanged(int))); + connect(keyUsageCheckBoxes[1], SIGNAL(stateChanged(int)), this, + SLOT(slotSigningBoxChanged(int))); + connect(keyUsageCheckBoxes[2], SIGNAL(stateChanged(int)), this, + SLOT(slotCertificationBoxChanged(int))); + connect(keyUsageCheckBoxes[3], SIGNAL(stateChanged(int)), this, + SLOT(slotAuthenticationBoxChanged(int))); + + connect(keyTypeComboBox, SIGNAL(currentIndexChanged(int)), this, + SLOT(slotActivatedKeyType(int))); + + connect(noPassPhraseCheckBox, &QCheckBox::stateChanged, this, + [this](int state) -> void { + if (state == 0) { + genKeyInfo->setNonPassPhrase(false); + } else { + genKeyInfo->setNonPassPhrase(true); + } + }); } -bool KeyGenDialog::check_email_address(const QString &str) { - return re_email.match(str).hasMatch(); +bool KeyGenDialog::check_email_address(const QString& str) { + return re_email.match(str).hasMatch(); } -QGroupBox *KeyGenDialog::create_basic_info_group_box() { - - errorLabel = new QLabel(tr("")); - nameEdit = new QLineEdit(this); - emailEdit = new QLineEdit(this); - commentEdit = new QLineEdit(this); - keySizeSpinBox = new QSpinBox(this); - keyTypeComboBox = new QComboBox(this); - - for(auto &algo : GenKeyInfo::SupportedKeyAlgo) { - keyTypeComboBox->addItem(algo); - } - if(!GenKeyInfo::SupportedKeyAlgo.isEmpty()) { - keyTypeComboBox->setCurrentIndex(0); - } - - QDateTime maxDateTime = QDateTime::currentDateTime().addYears(2); - - dateEdit = new QDateTimeEdit(maxDateTime, this); - dateEdit->setMinimumDateTime(QDateTime::currentDateTime()); - dateEdit->setMaximumDateTime(maxDateTime); - dateEdit->setDisplayFormat("dd/MM/yyyy hh:mm:ss"); - dateEdit->setCalendarPopup(true); - dateEdit->setEnabled(true); - - expireCheckBox = new QCheckBox(this); - expireCheckBox->setCheckState(Qt::Unchecked); - - noPassPhraseCheckBox = new QCheckBox(this); - noPassPhraseCheckBox->setCheckState(Qt::Unchecked); - - auto *vbox1 = new QGridLayout; - - vbox1->addWidget(new QLabel(tr("Name:")), 0, 0); - vbox1->addWidget(new QLabel(tr("Email Address:")), 1, 0); - vbox1->addWidget(new QLabel(tr("Comment:")), 2, 0); - vbox1->addWidget(new QLabel(tr("Expiration Date:")), 3, 0); - vbox1->addWidget(new QLabel(tr("Never Expire")), 3, 3); - vbox1->addWidget(new QLabel(tr("KeySize (in Bit):")), 4, 0); - vbox1->addWidget(new QLabel(tr("Key Type:")), 5, 0); - vbox1->addWidget(new QLabel(tr("Non Pass Phrase")), 6, 0); - - vbox1->addWidget(nameEdit, 0, 1, 1, 3); - vbox1->addWidget(emailEdit, 1, 1, 1, 3); - vbox1->addWidget(commentEdit, 2, 1, 1, 3); - vbox1->addWidget(dateEdit, 3, 1); - vbox1->addWidget(expireCheckBox, 3, 2); - vbox1->addWidget(keySizeSpinBox, 4, 1); - vbox1->addWidget(keyTypeComboBox, 5, 1); - vbox1->addWidget(noPassPhraseCheckBox, 6, 1); - - auto basicInfoGroupBox = new QGroupBox(); - basicInfoGroupBox->setLayout(vbox1); - basicInfoGroupBox->setTitle(tr("Basic Information")); - - return basicInfoGroupBox; +QGroupBox* KeyGenDialog::create_basic_info_group_box() { + errorLabel = new QLabel(); + nameEdit = new QLineEdit(this); + emailEdit = new QLineEdit(this); + commentEdit = new QLineEdit(this); + keySizeSpinBox = new QSpinBox(this); + keyTypeComboBox = new QComboBox(this); + + for (auto& algo : GenKeyInfo::SupportedKeyAlgo) { + keyTypeComboBox->addItem(QString::fromStdString(algo)); + } + if (!GenKeyInfo::SupportedKeyAlgo.empty()) { + keyTypeComboBox->setCurrentIndex(0); + } + + QDateTime maxDateTime = QDateTime::currentDateTime().addYears(2); + + dateEdit = new QDateTimeEdit(maxDateTime, this); + dateEdit->setMinimumDateTime(QDateTime::currentDateTime()); + dateEdit->setMaximumDateTime(maxDateTime); + dateEdit->setDisplayFormat("dd/MM/yyyy hh:mm:ss"); + dateEdit->setCalendarPopup(true); + dateEdit->setEnabled(true); + + expireCheckBox = new QCheckBox(this); + expireCheckBox->setCheckState(Qt::Unchecked); + + noPassPhraseCheckBox = new QCheckBox(this); + noPassPhraseCheckBox->setCheckState(Qt::Unchecked); + + auto* vbox1 = new QGridLayout; + + vbox1->addWidget(new QLabel(QString(_("Name")) + ": "), 0, 0); + vbox1->addWidget(new QLabel(QString(_("Email Address")) + ": "), 1, 0); + vbox1->addWidget(new QLabel(QString(_("Comment")) + ": "), 2, 0); + vbox1->addWidget(new QLabel(QString(_("Expiration Date")) + ": "), 3, 0); + vbox1->addWidget(new QLabel(QString(_("Never Expire")) + ": "), 3, 3); + vbox1->addWidget(new QLabel(QString(_("KeySize (in Bit)")) + ": "), 4, 0); + vbox1->addWidget(new QLabel(QString(_("Key Type")) + ": "), 5, 0); + vbox1->addWidget(new QLabel(QString(_("Non Pass Phrase")) + ": "), 6, 0); + + vbox1->addWidget(nameEdit, 0, 1, 1, 3); + vbox1->addWidget(emailEdit, 1, 1, 1, 3); + vbox1->addWidget(commentEdit, 2, 1, 1, 3); + vbox1->addWidget(dateEdit, 3, 1); + vbox1->addWidget(expireCheckBox, 3, 2); + vbox1->addWidget(keySizeSpinBox, 4, 1); + vbox1->addWidget(keyTypeComboBox, 5, 1); + vbox1->addWidget(noPassPhraseCheckBox, 6, 1); + + auto basicInfoGroupBox = new QGroupBox(); + basicInfoGroupBox->setLayout(vbox1); + basicInfoGroupBox->setTitle(_("Basic Information")); + + return basicInfoGroupBox; } + +} // namespace GpgFrontend::UI diff --git a/src/ui/keygen/KeygenDialog.h b/src/ui/keygen/KeygenDialog.h new file mode 100644 index 00000000..c16a2e76 --- /dev/null +++ b/src/ui/keygen/KeygenDialog.h @@ -0,0 +1,117 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * + */ + +#ifndef __KEYGENDIALOG_H__ +#define __KEYGENDIALOG_H__ + +#include "gpg/GpgContext.h" +#include "gpg/GpgGenKeyInfo.h" +#include "ui/GpgFrontendUI.h" + +namespace GpgFrontend::UI { + +class KeyGenDialog : public QDialog { + Q_OBJECT + + public: + /** + * @details Constructor of this class + * + * @param ctx The current GpgME context + * @param key The key to show details of + * @param parent The parent of this widget + */ + explicit KeyGenDialog(QWidget* parent = nullptr); + + signals: + void KeyGenerated(); + + private: + QGroupBox* create_key_usage_group_box(); + + QGroupBox* create_basic_info_group_box(); + + QRegularExpression re_email{ + R"((?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\]))"}; + + QStringList errorMessages; /** List of errors occuring when checking entries + of lineedits */ + std::unique_ptr<GenKeyInfo> genKeyInfo = std::make_unique<GenKeyInfo>(); + + QDialogButtonBox* buttonBox; /** Box for standard buttons */ + QLabel* errorLabel{}; /** Label containing error message */ + QLineEdit* nameEdit{}; /** Line edit for the keys name */ + QLineEdit* emailEdit{}; /** Line edit for the keys email */ + QLineEdit* commentEdit{}; /** Line edit for the keys comment */ + QSpinBox* keySizeSpinBox{}; /** Spinbox for the keys size (in bit) */ + QComboBox* keyTypeComboBox{}; /** Combobox for Key type */ + QDateTimeEdit* dateEdit{}; /** Date edit for expiration date */ + QCheckBox* expireCheckBox{}; /** Checkbox, if key should expire */ + QCheckBox* noPassPhraseCheckBox{}; + + QGroupBox* keyUsageGroupBox{}; /** Group of Widgets detecting the usage of the + Key **/ + + // ENCR, SIGN, CERT, AUTH + std::vector<QCheckBox*> keyUsageCheckBoxes; + + void generateKeyDialog(); + + /** + * @details Refresh widgets state by GenKeyInfo + */ + void refresh_widgets_state(); + + void set_signal_slot(); + + bool check_email_address(const QString& str); + + private slots: + + /** + * @details when expirebox was checked/unchecked, enable/disable the + * expiration date box + */ + void slotExpireBoxChanged(); + + /** + * @details check all lineedits for false entries. Show error, when there is + * one, otherwise generate the key + */ + void slotKeyGenAccept(); + + void slotEncryptionBoxChanged(int state); + + void slotSigningBoxChanged(int state); + + void slotCertificationBoxChanged(int state); + + void slotAuthenticationBoxChanged(int state); + + void slotActivatedKeyType(int index); +}; + +} // namespace GpgFrontend::UI + +#endif // __KEYGENDIALOG_H__ diff --git a/src/ui/keygen/SubkeyGenerateDialog.cpp b/src/ui/keygen/SubkeyGenerateDialog.cpp index 3d709d81..593b1cae 100644 --- a/src/ui/keygen/SubkeyGenerateDialog.cpp +++ b/src/ui/keygen/SubkeyGenerateDialog.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -23,277 +23,300 @@ */ #include "ui/keygen/SubkeyGenerateDialog.h" + +#include "gpg/function/GpgKeyGetter.h" +#include "gpg/function/GpgKeyOpera.h" +#include "ui/SignalStation.h" #include "ui/WaitingDialog.h" -SubkeyGenerateDialog::SubkeyGenerateDialog(GpgME::GpgContext *ctx, const GpgKey &key, QWidget *parent) - : genKeyInfo(true), mCtx(ctx), mKey(key), QDialog(parent) { +namespace GpgFrontend::UI { - buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); +SubkeyGenerateDialog::SubkeyGenerateDialog(const KeyId& key_id, QWidget* parent) + : QDialog(parent), mKey(GpgKeyGetter::GetInstance().GetKey(key_id)) { + buttonBox = + new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - keyUsageGroupBox = create_key_usage_group_box(); + keyUsageGroupBox = create_key_usage_group_box(); - auto *groupGrid = new QGridLayout(this); - groupGrid->addWidget(create_basic_info_group_box(), 0, 0); - groupGrid->addWidget(keyUsageGroupBox, 1, 0); + auto* groupGrid = new QGridLayout(this); + groupGrid->addWidget(create_basic_info_group_box(), 0, 0); + groupGrid->addWidget(keyUsageGroupBox, 1, 0); - auto *nameList = new QWidget(this); - nameList->setLayout(groupGrid); + auto* nameList = new QWidget(this); + nameList->setLayout(groupGrid); - auto *vbox2 = new QVBoxLayout(); - vbox2->addWidget(nameList); - vbox2->addWidget(errorLabel); - vbox2->addWidget(buttonBox); + auto* vbox2 = new QVBoxLayout(); + vbox2->addWidget(nameList); + vbox2->addWidget(errorLabel); + vbox2->addWidget(buttonBox); - this->setWindowTitle(tr("Generate New Subkey")); + this->setWindowTitle(_("Generate New Subkey")); + this->setLayout(vbox2); + this->setModal(true); - this->setLayout(vbox2); - this->setModal(true); + connect(this, SIGNAL(SubKeyGenerated()), SignalStation::GetInstance(), + SIGNAL(KeyDatabaseRefresh())); - set_signal_slot(); - refresh_widgets_state(); + set_signal_slot(); + refresh_widgets_state(); } -QGroupBox *SubkeyGenerateDialog::create_key_usage_group_box() { - auto *groupBox = new QGroupBox(this); - auto *grid = new QGridLayout(this); +QGroupBox* SubkeyGenerateDialog::create_key_usage_group_box() { + auto* groupBox = new QGroupBox(this); + auto* grid = new QGridLayout(this); - groupBox->setTitle("Key Usage"); + groupBox->setTitle("Key Usage"); - auto* encrypt = new QCheckBox(tr("Encryption"), groupBox); - encrypt->setTristate(false); + auto* encrypt = new QCheckBox(_("Encryption"), groupBox); + encrypt->setTristate(false); - auto* sign = new QCheckBox(tr("Signing"),groupBox); - sign->setTristate(false); + auto* sign = new QCheckBox(_("Signing"), groupBox); + sign->setTristate(false); - auto* cert = new QCheckBox(tr("Certification"),groupBox); - cert->setTristate(false); + auto* cert = new QCheckBox(_("Certification"), groupBox); + cert->setTristate(false); - auto* auth = new QCheckBox(tr("Authentication"), groupBox); - auth->setTristate(false); + auto* auth = new QCheckBox(_("Authentication"), groupBox); + auth->setTristate(false); - keyUsageCheckBoxes.push_back(encrypt); - keyUsageCheckBoxes.push_back(sign); - keyUsageCheckBoxes.push_back(cert); - keyUsageCheckBoxes.push_back(auth); + keyUsageCheckBoxes.push_back(encrypt); + keyUsageCheckBoxes.push_back(sign); + keyUsageCheckBoxes.push_back(cert); + keyUsageCheckBoxes.push_back(auth); - grid->addWidget(encrypt, 0, 0); - grid->addWidget(sign, 0, 1); - grid->addWidget(cert, 1, 0); - grid->addWidget(auth, 1, 1); + grid->addWidget(encrypt, 0, 0); + grid->addWidget(sign, 0, 1); + grid->addWidget(cert, 1, 0); + grid->addWidget(auth, 1, 1); - groupBox->setLayout(grid); + groupBox->setLayout(grid); - return groupBox; + return groupBox; } -QGroupBox *SubkeyGenerateDialog::create_basic_info_group_box() { - errorLabel = new QLabel(tr("")); - keySizeSpinBox = new QSpinBox(this); - keyTypeComboBox = new QComboBox(this); +QGroupBox* SubkeyGenerateDialog::create_basic_info_group_box() { + errorLabel = new QLabel(); + keySizeSpinBox = new QSpinBox(this); + keyTypeComboBox = new QComboBox(this); - for(auto &algo : GenKeyInfo::SupportedSubkeyAlgo) { - keyTypeComboBox->addItem(algo); - } - if(!GenKeyInfo::SupportedKeyAlgo.isEmpty()) { - keyTypeComboBox->setCurrentIndex(0); - } + for (auto& algo : GenKeyInfo::SupportedSubkeyAlgo) { + keyTypeComboBox->addItem(QString::fromStdString(algo)); + } + if (!GenKeyInfo::SupportedKeyAlgo.empty()) { + keyTypeComboBox->setCurrentIndex(0); + } - QDateTime maxDateTime = QDateTime::currentDateTime().addYears(2); + QDateTime maxDateTime = QDateTime::currentDateTime().addYears(2); - dateEdit = new QDateTimeEdit(maxDateTime, this); - dateEdit->setMinimumDateTime(QDateTime::currentDateTime()); - dateEdit->setMaximumDateTime(maxDateTime); - dateEdit->setDisplayFormat("dd/MM/yyyy hh:mm:ss"); - dateEdit->setCalendarPopup(true); - dateEdit->setEnabled(true); + dateEdit = new QDateTimeEdit(maxDateTime, this); + dateEdit->setMinimumDateTime(QDateTime::currentDateTime()); + dateEdit->setMaximumDateTime(maxDateTime); + dateEdit->setDisplayFormat("dd/MM/yyyy hh:mm:ss"); + dateEdit->setCalendarPopup(true); + dateEdit->setEnabled(true); - expireCheckBox = new QCheckBox(this); - expireCheckBox->setCheckState(Qt::Unchecked); + expireCheckBox = new QCheckBox(this); + expireCheckBox->setCheckState(Qt::Unchecked); - auto *vbox1 = new QGridLayout; + auto* vbox1 = new QGridLayout; - vbox1->addWidget(new QLabel(tr("Expiration Date:")), 2, 0); - vbox1->addWidget(new QLabel(tr("Never Expire")), 2, 3); - vbox1->addWidget(new QLabel(tr("KeySize (in Bit):")), 1, 0); - vbox1->addWidget(new QLabel(tr("Key Type:")), 0, 0); + vbox1->addWidget(new QLabel(QString(_("Expiration Date")) + ": "), 2, 0); + vbox1->addWidget(new QLabel(QString(_("Never Expire")) + ": "), 2, 3); + vbox1->addWidget(new QLabel(QString(_("KeySize (in Bit)")) + ": "), 1, 0); + vbox1->addWidget(new QLabel(QString(_("Key Type")) + ": "), 0, 0); - vbox1->addWidget(dateEdit, 2, 1); - vbox1->addWidget(expireCheckBox, 2, 2); - vbox1->addWidget(keySizeSpinBox, 1, 1); - vbox1->addWidget(keyTypeComboBox, 0, 1); + vbox1->addWidget(dateEdit, 2, 1); + vbox1->addWidget(expireCheckBox, 2, 2); + vbox1->addWidget(keySizeSpinBox, 1, 1); + vbox1->addWidget(keyTypeComboBox, 0, 1); - auto basicInfoGroupBox = new QGroupBox(); - basicInfoGroupBox->setLayout(vbox1); - basicInfoGroupBox->setTitle(tr("Basic Information")); + auto basicInfoGroupBox = new QGroupBox(); + basicInfoGroupBox->setLayout(vbox1); + basicInfoGroupBox->setTitle(_("Basic Information")); - return basicInfoGroupBox; + return basicInfoGroupBox; } void SubkeyGenerateDialog::set_signal_slot() { - connect(buttonBox, SIGNAL(accepted()), this, SLOT(slotKeyGenAccept())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); - - connect(expireCheckBox, SIGNAL(stateChanged(int)), this, SLOT(slotExpireBoxChanged())); - - connect(keyUsageCheckBoxes[0], SIGNAL(stateChanged(int)), this, SLOT(slotEncryptionBoxChanged(int))); - connect(keyUsageCheckBoxes[1], SIGNAL(stateChanged(int)), this, SLOT(slotSigningBoxChanged(int))); - connect(keyUsageCheckBoxes[2], SIGNAL(stateChanged(int)), this, SLOT(slotCertificationBoxChanged(int))); - connect(keyUsageCheckBoxes[3], SIGNAL(stateChanged(int)), this, SLOT(slotAuthenticationBoxChanged(int))); - - connect(keyTypeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotActivatedKeyType(int))); + connect(buttonBox, SIGNAL(accepted()), this, SLOT(slotKeyGenAccept())); + connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + + connect(expireCheckBox, SIGNAL(stateChanged(int)), this, + SLOT(slotExpireBoxChanged())); + + connect(keyUsageCheckBoxes[0], SIGNAL(stateChanged(int)), this, + SLOT(slotEncryptionBoxChanged(int))); + connect(keyUsageCheckBoxes[1], SIGNAL(stateChanged(int)), this, + SLOT(slotSigningBoxChanged(int))); + connect(keyUsageCheckBoxes[2], SIGNAL(stateChanged(int)), this, + SLOT(slotCertificationBoxChanged(int))); + connect(keyUsageCheckBoxes[3], SIGNAL(stateChanged(int)), this, + SLOT(slotAuthenticationBoxChanged(int))); + + connect(keyTypeComboBox, SIGNAL(currentIndexChanged(int)), this, + SLOT(slotActivatedKeyType(int))); } void SubkeyGenerateDialog::slotExpireBoxChanged() { - if (expireCheckBox->checkState()) { - dateEdit->setEnabled(false); - } else { - dateEdit->setEnabled(true); - } + if (expireCheckBox->checkState()) { + dateEdit->setEnabled(false); + } else { + dateEdit->setEnabled(true); + } } void SubkeyGenerateDialog::refresh_widgets_state() { - qDebug() << "refresh_widgets_state called"; - - if(genKeyInfo.isAllowEncryption()) - keyUsageCheckBoxes[0]->setCheckState(Qt::CheckState::Checked); - else - keyUsageCheckBoxes[0]->setCheckState(Qt::CheckState::Unchecked); - - if(genKeyInfo.isAllowChangeEncryption()) - keyUsageCheckBoxes[0]->setDisabled(false); - else - keyUsageCheckBoxes[0]->setDisabled(true); - - - if(genKeyInfo.isAllowSigning()) - keyUsageCheckBoxes[1]->setCheckState(Qt::CheckState::Checked); - else - keyUsageCheckBoxes[1]->setCheckState(Qt::CheckState::Unchecked); - - if(genKeyInfo.isAllowChangeSigning()) - keyUsageCheckBoxes[1]->setDisabled(false); - else - keyUsageCheckBoxes[1]->setDisabled(true); - - - if(genKeyInfo.isAllowCertification()) - keyUsageCheckBoxes[2]->setCheckState(Qt::CheckState::Checked); - else - keyUsageCheckBoxes[2]->setCheckState(Qt::CheckState::Unchecked); - - if(genKeyInfo.isAllowChangeCertification()) - keyUsageCheckBoxes[2]->setDisabled(false); - else - keyUsageCheckBoxes[2]->setDisabled(true); - - - if(genKeyInfo.isAllowAuthentication()) - keyUsageCheckBoxes[3]->setCheckState(Qt::CheckState::Checked); - else - keyUsageCheckBoxes[3]->setCheckState(Qt::CheckState::Unchecked); - - if(genKeyInfo.isAllowChangeAuthentication()) - keyUsageCheckBoxes[3]->setDisabled(false); - else - keyUsageCheckBoxes[3]->setDisabled(true); - - - keySizeSpinBox->setRange(genKeyInfo.getSuggestMinKeySize(), genKeyInfo.getSuggestMaxKeySize()); - keySizeSpinBox->setValue(genKeyInfo.getKeySize()); - keySizeSpinBox->setSingleStep(genKeyInfo.getSizeChangeStep()); - + qDebug() << "refresh_widgets_state called"; + + if (genKeyInfo->isAllowEncryption()) + keyUsageCheckBoxes[0]->setCheckState(Qt::CheckState::Checked); + else + keyUsageCheckBoxes[0]->setCheckState(Qt::CheckState::Unchecked); + + if (genKeyInfo->isAllowChangeEncryption()) + keyUsageCheckBoxes[0]->setDisabled(false); + else + keyUsageCheckBoxes[0]->setDisabled(true); + + if (genKeyInfo->isAllowSigning()) + keyUsageCheckBoxes[1]->setCheckState(Qt::CheckState::Checked); + else + keyUsageCheckBoxes[1]->setCheckState(Qt::CheckState::Unchecked); + + if (genKeyInfo->isAllowChangeSigning()) + keyUsageCheckBoxes[1]->setDisabled(false); + else + keyUsageCheckBoxes[1]->setDisabled(true); + + if (genKeyInfo->isAllowCertification()) + keyUsageCheckBoxes[2]->setCheckState(Qt::CheckState::Checked); + else + keyUsageCheckBoxes[2]->setCheckState(Qt::CheckState::Unchecked); + + if (genKeyInfo->isAllowChangeCertification()) + keyUsageCheckBoxes[2]->setDisabled(false); + else + keyUsageCheckBoxes[2]->setDisabled(true); + + if (genKeyInfo->isAllowAuthentication()) + keyUsageCheckBoxes[3]->setCheckState(Qt::CheckState::Checked); + else + keyUsageCheckBoxes[3]->setCheckState(Qt::CheckState::Unchecked); + + if (genKeyInfo->isAllowChangeAuthentication()) + keyUsageCheckBoxes[3]->setDisabled(false); + else + keyUsageCheckBoxes[3]->setDisabled(true); + + keySizeSpinBox->setRange(genKeyInfo->getSuggestMinKeySize(), + genKeyInfo->getSuggestMaxKeySize()); + keySizeSpinBox->setValue(genKeyInfo->getKeySize()); + keySizeSpinBox->setSingleStep(genKeyInfo->getSizeChangeStep()); } void SubkeyGenerateDialog::slotKeyGenAccept() { - QString errorString = ""; - - /** - * primary keys should have a reasonable expiration date (no more than 2 years in the future) - */ - if(dateEdit->dateTime() > QDateTime::currentDateTime().addYears(2)) { - - errorString.append(tr(" Expiration time no more than 2 years. ")); - } + std::stringstream err_stream; - if (errorString.isEmpty()) { + /** + * primary keys should have a reasonable expiration date (no more than 2 years + * in the future) + */ + if (dateEdit->dateTime() > QDateTime::currentDateTime().addYears(2)) { + err_stream << " " << _("Expiration time no more than 2 years.") << " "; + } - genKeyInfo.setKeySize(keySizeSpinBox->value()); + auto err_string = err_stream.str(); - if (expireCheckBox->checkState()) { - genKeyInfo.setNonExpired(true); - } else { - genKeyInfo.setExpired(dateEdit->dateTime()); - } + if (err_string.empty()) { + genKeyInfo->setKeySize(keySizeSpinBox->value()); - gpgme_error_t error = false; - auto thread = QThread::create([&]() { - error = mCtx->generateSubkey(mKey, &genKeyInfo); - }); - thread->start(); - - auto *dialog = new WaitingDialog("Generating", this); - dialog->show(); - - while (thread->isRunning()) { - QCoreApplication::processEvents(); - } + if (expireCheckBox->checkState()) { + genKeyInfo->setNonExpired(true); + } else { + genKeyInfo->setExpired( + boost::posix_time::from_time_t(dateEdit->dateTime().toTime_t()) + .date()); + } - dialog->close(); + GpgError error; + auto thread = QThread::create([&]() { + LOG(INFO) << "SubkeyGenerateDialog::slotKeyGenAccept() Thread Started"; + error = GpgKeyOpera::GetInstance().GenerateSubkey(mKey, genKeyInfo); + }); + thread->start(); - if (gpgme_err_code(error) == GPG_ERR_NO_ERROR) { - QMessageBox::information(nullptr, tr("Success"), tr("The new subkey has been generated.")); - this->close(); - } else - QMessageBox::critical(this, tr("Failure"), tr(gpgme_strerror(error))); + auto* dialog = new WaitingDialog("Generating", this); + dialog->show(); - } else { - /** - * create error message - */ - errorLabel->setAutoFillBackground(true); - QPalette error = errorLabel->palette(); - error.setColor(QPalette::Window, "#ff8080"); - errorLabel->setPalette(error); - errorLabel->setText(errorString); - - this->show(); + while (thread->isRunning()) { + QCoreApplication::processEvents(); } + dialog->close(); + + if (check_gpg_error_2_err_code(error) == GPG_ERR_NO_ERROR) { + auto* msg_box = new QMessageBox(nullptr); + msg_box->setAttribute(Qt::WA_DeleteOnClose); + msg_box->setStandardButtons(QMessageBox::Ok); + msg_box->setWindowTitle(_("Success")); + msg_box->setText(_("The new subkey has been generated.")); + msg_box->setModal(false); + msg_box->open(); + + emit SubKeyGenerated(); + this->close(); + } else + QMessageBox::critical(this, _("Failure"), _(gpgme_strerror(error))); + + } else { + /** + * create error message + */ + errorLabel->setAutoFillBackground(true); + QPalette error = errorLabel->palette(); + error.setColor(QPalette::Window, "#ff8080"); + errorLabel->setPalette(error); + errorLabel->setText(err_string.c_str()); + + this->show(); + } } void SubkeyGenerateDialog::slotEncryptionBoxChanged(int state) { - if(state == 0) { - genKeyInfo.setAllowEncryption(false); - } else { - genKeyInfo.setAllowEncryption(true); - } + if (state == 0) { + genKeyInfo->setAllowEncryption(false); + } else { + genKeyInfo->setAllowEncryption(true); + } } void SubkeyGenerateDialog::slotSigningBoxChanged(int state) { - if(state == 0) { - genKeyInfo.setAllowSigning(false); - } else { - genKeyInfo.setAllowSigning(true); - } + if (state == 0) { + genKeyInfo->setAllowSigning(false); + } else { + genKeyInfo->setAllowSigning(true); + } } void SubkeyGenerateDialog::slotCertificationBoxChanged(int state) { - if(state == 0) { - genKeyInfo.setAllowCertification(false); - } else { - genKeyInfo.setAllowCertification(true); - } + if (state == 0) { + genKeyInfo->setAllowCertification(false); + } else { + genKeyInfo->setAllowCertification(true); + } } void SubkeyGenerateDialog::slotAuthenticationBoxChanged(int state) { - if(state == 0) { - genKeyInfo.setAllowAuthentication(false); - } else { - genKeyInfo.setAllowAuthentication(true); - } + if (state == 0) { + genKeyInfo->setAllowAuthentication(false); + } else { + genKeyInfo->setAllowAuthentication(true); + } } void SubkeyGenerateDialog::slotActivatedKeyType(int index) { - qDebug() << "key type index changed " << index; - genKeyInfo.setAlgo(this->keyTypeComboBox->itemText(index)); - refresh_widgets_state(); + qDebug() << "key type index changed " << index; + genKeyInfo->setAlgo(this->keyTypeComboBox->itemText(index).toStdString()); + refresh_widgets_state(); } + +} // namespace GpgFrontend::UI diff --git a/src/ui/keygen/SubkeyGenerateDialog.h b/src/ui/keygen/SubkeyGenerateDialog.h new file mode 100644 index 00000000..ec7c9fb1 --- /dev/null +++ b/src/ui/keygen/SubkeyGenerateDialog.h @@ -0,0 +1,97 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_SUBKEYGENERATEDIALOG_H +#define GPGFRONTEND_SUBKEYGENERATEDIALOG_H + +#include "gpg/GpgContext.h" +#include "gpg/GpgGenKeyInfo.h" +#include "ui/GpgFrontendUI.h" + +namespace GpgFrontend::UI { + +class SubkeyGenerateDialog : public QDialog { + Q_OBJECT + + public: + explicit SubkeyGenerateDialog(const KeyId& key_id, QWidget* parent); + + signals: + void SubKeyGenerated(); + + private: + GpgKey mKey; + + std::unique_ptr<GenKeyInfo> genKeyInfo = std::make_unique<GenKeyInfo>(true); + + QGroupBox* keyUsageGroupBox{}; + QDialogButtonBox* buttonBox; /** Box for standardbuttons */ + QLabel* errorLabel{}; /** Label containing error message */ + QSpinBox* keySizeSpinBox{}; /** Spinbox for the keys size (in bit) */ + QComboBox* keyTypeComboBox{}; /** Combobox for Keytpe */ + QDateTimeEdit* dateEdit{}; /** Dateedit for expiration date */ + QCheckBox* expireCheckBox{}; /** Checkbox, if key should expire */ + + // ENCR, SIGN, CERT, AUTH + std::vector<QCheckBox*> keyUsageCheckBoxes; + + QGroupBox* create_key_usage_group_box(); + + QGroupBox* create_basic_info_group_box(); + + void set_signal_slot(); + + /** + * @details Refresh widgets state by GenKeyInfo + */ + void refresh_widgets_state(); + + private slots: + + /** + * @details when expirebox was checked/unchecked, enable/disable the + * expiration date box + */ + void slotExpireBoxChanged(); + + /** + * @details check all lineedits for false entries. Show error, when there is + * one, otherwise generate the key + */ + void slotKeyGenAccept(); + + void slotEncryptionBoxChanged(int state); + + void slotSigningBoxChanged(int state); + + void slotCertificationBoxChanged(int state); + + void slotAuthenticationBoxChanged(int state); + + void slotActivatedKeyType(int index); +}; + +} // namespace GpgFrontend::UI + +#endif // GPGFRONTEND_SUBKEYGENERATEDIALOG_H diff --git a/src/ui/keypair_details/EditSubKeyDialog.cpp b/src/ui/keypair_details/EditSubKeyDialog.cpp index e44c987f..6c2e0ce1 100644 --- a/src/ui/keypair_details/EditSubKeyDialog.cpp +++ b/src/ui/keypair_details/EditSubKeyDialog.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. diff --git a/src/ui/keypair_details/EditSubKeyDialog.h b/src/ui/keypair_details/EditSubKeyDialog.h new file mode 100644 index 00000000..51842405 --- /dev/null +++ b/src/ui/keypair_details/EditSubKeyDialog.h @@ -0,0 +1,30 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_EDITSUBKEY_H +#define GPGFRONTEND_EDITSUBKEY_H + +class EditSubKeyDialog {}; + +#endif // GPGFRONTEND_EDITSUBKEY_H diff --git a/src/ui/keypair_details/KeyDetailsDialog.cpp b/src/ui/keypair_details/KeyDetailsDialog.cpp index c80374d4..f3cab771 100644 --- a/src/ui/keypair_details/KeyDetailsDialog.cpp +++ b/src/ui/keypair_details/KeyDetailsDialog.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -24,21 +24,22 @@ #include "ui/keypair_details/KeyDetailsDialog.h" -KeyDetailsDialog::KeyDetailsDialog(GpgME::GpgContext *ctx, const GpgKey& key, QWidget *parent) - : QDialog(parent) { +namespace GpgFrontend::UI { +KeyDetailsDialog::KeyDetailsDialog(const GpgKey& key, QWidget* parent) + : QDialog(parent) { + tabWidget = new QTabWidget(); + tabWidget->addTab(new KeyPairDetailTab(key.id(), tabWidget), _("KeyPair")); + tabWidget->addTab(new KeyPairUIDTab(key.id(), tabWidget), _("UIDs")); + tabWidget->addTab(new KeyPairSubkeyTab(key.id(), tabWidget), _("Subkeys")); - tabWidget = new QTabWidget(); - tabWidget->addTab(new KeyPairDetailTab(ctx, key, tabWidget), tr("KeyPair")); - tabWidget->addTab(new KeyPairUIDTab(ctx, key, tabWidget), tr("UIDs")); - tabWidget->addTab(new KeyPairSubkeyTab(ctx, key, tabWidget), tr("Subkeys")); + auto* mainLayout = new QVBoxLayout; + mainLayout->addWidget(tabWidget); - auto *mainLayout = new QVBoxLayout; - mainLayout->addWidget(tabWidget); - - this->setAttribute(Qt::WA_DeleteOnClose, true); - this->setLayout(mainLayout); - this->setWindowTitle(tr("Key Details")); - this->setModal(true); - this->setMinimumSize(380, 620); - this->show(); -}
\ No newline at end of file + this->setAttribute(Qt::WA_DeleteOnClose, true); + this->setLayout(mainLayout); + this->setWindowTitle(_("Key Details")); + this->setModal(true); + this->setMinimumSize(380, 620); + this->show(); +} +} // namespace GpgFrontend::UI diff --git a/src/ui/keypair_details/KeyDetailsDialog.h b/src/ui/keypair_details/KeyDetailsDialog.h new file mode 100644 index 00000000..51fc01cf --- /dev/null +++ b/src/ui/keypair_details/KeyDetailsDialog.h @@ -0,0 +1,47 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef __KEYDETAILSDIALOG_H__ +#define __KEYDETAILSDIALOG_H__ + +#include "KeyPairDetailTab.h" +#include "KeyPairSubkeyTab.h" +#include "KeyPairUIDTab.h" +#include "gpg/GpgContext.h" +#include "ui/GpgFrontendUI.h" + +namespace GpgFrontend::UI { + +class KeyDetailsDialog : public QDialog { + Q_OBJECT + + public: + explicit KeyDetailsDialog(const GpgKey& key, QWidget* parent = nullptr); + + private: + QTabWidget* tabWidget{}; +}; +} // namespace GpgFrontend::UI + +#endif // __KEYDETAILSDIALOG_H__ diff --git a/src/ui/keypair_details/KeyNewUIDDialog.cpp b/src/ui/keypair_details/KeyNewUIDDialog.cpp index e12af750..809a05f8 100644 --- a/src/ui/keypair_details/KeyNewUIDDialog.cpp +++ b/src/ui/keypair_details/KeyNewUIDDialog.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -24,79 +24,86 @@ #include "ui/keypair_details/KeyNewUIDDialog.h" -KeyNewUIDDialog::KeyNewUIDDialog(GpgME::GpgContext *ctx, const GpgKey &key, QWidget *parent) : - mCtx(ctx), mKey(key), QDialog(parent) { - - name = new QLineEdit(); - name->setMinimumWidth(240); - email = new QLineEdit(); - email->setMinimumWidth(240); - comment = new QLineEdit(); - comment->setMinimumWidth(240); - createButton = new QPushButton("Create"); - errorLabel = new QLabel(); - - auto gridLayout = new QGridLayout(); - gridLayout->addWidget(new QLabel(tr("Name")), 0, 0); - gridLayout->addWidget(new QLabel(tr("Email")), 1, 0); - gridLayout->addWidget(new QLabel(tr("Comment")), 2, 0); - - - gridLayout->addWidget(name, 0 ,1); - gridLayout->addWidget(email, 1 ,1); - gridLayout->addWidget(comment, 2 ,1); - - gridLayout->addWidget(createButton, 3, 0, 1, 2); - gridLayout->addWidget(errorLabel, 4, 0, 1, 2); - - connect(createButton, SIGNAL(clicked(bool)), this, SLOT(slotCreateNewUID())); - - this->setLayout(gridLayout); - this->setWindowTitle(tr("Create New UID")); - this->setAttribute(Qt::WA_DeleteOnClose, true); - this->setModal(true); +#include "gpg/function/GpgKeyGetter.h" +#include "gpg/function/UidOperator.h" +#include "ui/SignalStation.h" + +namespace GpgFrontend::UI { +KeyNewUIDDialog::KeyNewUIDDialog(const KeyId& key_id, QWidget* parent) + : QDialog(parent), mKey(GpgKeyGetter::GetInstance().GetKey(key_id)) { + name = new QLineEdit(); + name->setMinimumWidth(240); + email = new QLineEdit(); + email->setMinimumWidth(240); + comment = new QLineEdit(); + comment->setMinimumWidth(240); + createButton = new QPushButton("Create"); + errorLabel = new QLabel(); + + auto gridLayout = new QGridLayout(); + gridLayout->addWidget(new QLabel(_("Name")), 0, 0); + gridLayout->addWidget(new QLabel(_("Email")), 1, 0); + gridLayout->addWidget(new QLabel(_("Comment")), 2, 0); + + gridLayout->addWidget(name, 0, 1); + gridLayout->addWidget(email, 1, 1); + gridLayout->addWidget(comment, 2, 1); + + gridLayout->addWidget(createButton, 3, 0, 1, 2); + gridLayout->addWidget( + new QLabel(_("Notice: The New UID Created will be set as Primary.")), 4, + 0, 1, 2); + gridLayout->addWidget(errorLabel, 5, 0, 1, 2); + + connect(createButton, SIGNAL(clicked(bool)), this, SLOT(slotCreateNewUID())); + + this->setLayout(gridLayout); + this->setWindowTitle(_("Create New UID")); + this->setAttribute(Qt::WA_DeleteOnClose, true); + this->setModal(true); + + connect(this, SIGNAL(signalUIDCreated()), SignalStation::GetInstance(), + SIGNAL(KeyDatabaseRefresh())); } void KeyNewUIDDialog::slotCreateNewUID() { - - QString errorString = ""; - + std::stringstream error_stream; + + /** + * check for errors in keygen dialog input + */ + if ((name->text()).size() < 5) { + error_stream << " " << _("Name must contain at least five characters.") + << std::endl; + } + if (email->text().isEmpty() || !check_email_address(email->text())) { + error_stream << " " << _("Please give a email address.") << std::endl; + } + auto error_string = error_stream.str(); + if (error_string.empty()) { + if (UidOperator::GetInstance().addUID(mKey, name->text().toStdString(), + comment->text().toStdString(), + email->text().toStdString())) { + emit finished(1); + emit signalUIDCreated(); + } else + emit finished(-1); + + } else { /** - * check for errors in keygen dialog input + * create error message */ - if ((name->text()).size() < 5) { - errorString.append(tr(" Name must contain at least five characters. \n")); - } if(email->text().isEmpty() || !check_email_address(email->text())) { - errorString.append(tr(" Please give a email address. \n")); - } - - if (errorString.isEmpty()) { - GpgUID uid; - uid.name = name->text(); - uid.email = email->text(); - uid.comment = comment->text(); - - if(mCtx->addUID(mKey, uid)) { - emit finished(1); - - } else { - emit finished(-1); - } - - } else { - /** - * create error message - */ - errorLabel->setAutoFillBackground(true); - QPalette error = errorLabel->palette(); - error.setColor(QPalette::Window, "#ff8080"); - errorLabel->setPalette(error); - errorLabel->setText(errorString); - - this->show(); - } + errorLabel->setAutoFillBackground(true); + QPalette error = errorLabel->palette(); + error.setColor(QPalette::Window, "#ff8080"); + errorLabel->setPalette(error); + errorLabel->setText(error_string.c_str()); + + this->show(); + } } -bool KeyNewUIDDialog::check_email_address(const QString &str) { - return re_email.match(str).hasMatch(); +bool KeyNewUIDDialog::check_email_address(const QString& str) { + return re_email.match(str).hasMatch(); } +} // namespace GpgFrontend::UI diff --git a/src/ui/keypair_details/KeyNewUIDDialog.h b/src/ui/keypair_details/KeyNewUIDDialog.h new file mode 100644 index 00000000..2e38a7f4 --- /dev/null +++ b/src/ui/keypair_details/KeyNewUIDDialog.h @@ -0,0 +1,64 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_KEYNEWUIDDIALOG_H +#define GPGFRONTEND_KEYNEWUIDDIALOG_H + +#include "gpg/GpgContext.h" +#include "ui/GpgFrontendUI.h" + +namespace GpgFrontend::UI { +class KeyNewUIDDialog : public QDialog { + Q_OBJECT + + public: + KeyNewUIDDialog(const KeyId& key, QWidget* parent = nullptr); + + signals: + void signalUIDCreated(); + + private slots: + + void slotCreateNewUID(); + + private: + GpgKey mKey; + + QLineEdit* name{}; + QLineEdit* email{}; + QLineEdit* comment{}; + + QPushButton* createButton{}; + + QStringList errorMessages; + QLabel* errorLabel{}; + + QRegularExpression re_email{ + R"((?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\]))"}; + + bool check_email_address(const QString& str); +}; +} // namespace GpgFrontend::UI + +#endif // GPGFRONTEND_KEYNEWUIDDIALOG_H diff --git a/src/ui/keypair_details/KeyPairDetailTab.cpp b/src/ui/keypair_details/KeyPairDetailTab.cpp index c0a2df99..f88e9edc 100644 --- a/src/ui/keypair_details/KeyPairDetailTab.cpp +++ b/src/ui/keypair_details/KeyPairDetailTab.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -23,330 +23,384 @@ */ #include "ui/keypair_details/KeyPairDetailTab.h" + +#include "gpg/function/GpgKeyGetter.h" +#include "gpg/function/GpgKeyImportExportor.h" +#include "ui/SignalStation.h" +#include "ui/UserInterfaceUtils.h" #include "ui/WaitingDialog.h" -KeyPairDetailTab::KeyPairDetailTab(GpgME::GpgContext *ctx, const GpgKey &mKey, QWidget *parent) : mKey(mKey), - QWidget(parent) { - - mCtx = ctx; - keyid = new QString(mKey.id); - - ownerBox = new QGroupBox(tr("Owner")); - keyBox = new QGroupBox(tr("Master Key")); - fingerprintBox = new QGroupBox(tr("Fingerprint")); - additionalUidBox = new QGroupBox(tr("Additional UIDs")); - - nameVarLabel = new QLabel(); - nameVarLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); - emailVarLabel = new QLabel(); - emailVarLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); - - commentVarLabel = new QLabel(); - commentVarLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); - keyidVarLabel = new QLabel(); - keyidVarLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); - - usageVarLabel = new QLabel(); - actualUsageVarLabel = new QLabel(); - - keySizeVarLabel = new QLabel(); - expireVarLabel = new QLabel(); - createdVarLabel = new QLabel(); - algorithmVarLabel = new QLabel(); - - // Show the situation that master key not exists. - masterKeyExistVarLabel = new QLabel(mKey.has_master_key ? tr("Exists") : tr("Not Exists")); - if (!mKey.has_master_key) { - auto paletteExpired = masterKeyExistVarLabel->palette(); - paletteExpired.setColor(masterKeyExistVarLabel->foregroundRole(), Qt::red); - masterKeyExistVarLabel->setPalette(paletteExpired); - } else { - auto paletteValid = masterKeyExistVarLabel->palette(); - paletteValid.setColor(masterKeyExistVarLabel->foregroundRole(), Qt::darkGreen); - masterKeyExistVarLabel->setPalette(paletteValid); +namespace GpgFrontend::UI { +KeyPairDetailTab::KeyPairDetailTab(const std::string& key_id, QWidget* parent) + : QWidget(parent), mKey(GpgKeyGetter::GetInstance().GetKey(key_id)) { + keyid = mKey.id(); + + ownerBox = new QGroupBox(_("Owner")); + keyBox = new QGroupBox(_("Master Key")); + fingerprintBox = new QGroupBox(_("Fingerprint")); + additionalUidBox = new QGroupBox(_("Additional UIDs")); + + nameVarLabel = new QLabel(); + nameVarLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); + emailVarLabel = new QLabel(); + emailVarLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); + + commentVarLabel = new QLabel(); + commentVarLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); + keyidVarLabel = new QLabel(); + keyidVarLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); + + usageVarLabel = new QLabel(); + actualUsageVarLabel = new QLabel(); + + keySizeVarLabel = new QLabel(); + expireVarLabel = new QLabel(); + createdVarLabel = new QLabel(); + algorithmVarLabel = new QLabel(); + + // Show the situation that master key not exists. + masterKeyExistVarLabel = + new QLabel(mKey.has_master_key() ? _("Exists") : _("Not Exists")); + if (!mKey.has_master_key()) { + auto paletteExpired = masterKeyExistVarLabel->palette(); + paletteExpired.setColor(masterKeyExistVarLabel->foregroundRole(), Qt::red); + masterKeyExistVarLabel->setPalette(paletteExpired); + } else { + auto paletteValid = masterKeyExistVarLabel->palette(); + paletteValid.setColor(masterKeyExistVarLabel->foregroundRole(), + Qt::darkGreen); + masterKeyExistVarLabel->setPalette(paletteValid); + } + + if (mKey.expired()) { + auto paletteExpired = expireVarLabel->palette(); + paletteExpired.setColor(expireVarLabel->foregroundRole(), Qt::red); + expireVarLabel->setPalette(paletteExpired); + } else { + auto paletteValid = expireVarLabel->palette(); + paletteValid.setColor(expireVarLabel->foregroundRole(), Qt::darkGreen); + expireVarLabel->setPalette(paletteValid); + } + + auto* mvbox = new QVBoxLayout(); + auto* vboxKD = new QGridLayout(); + auto* vboxOD = new QGridLayout(); + + vboxOD->addWidget(new QLabel(QString(_("Name")) + ": "), 0, 0); + vboxOD->addWidget(new QLabel(QString(_("Email Address")) + ": "), 1, 0); + vboxOD->addWidget(new QLabel(QString(_("Comment")) + ": "), 2, 0); + vboxOD->addWidget(nameVarLabel, 0, 1); + vboxOD->addWidget(emailVarLabel, 1, 1); + vboxOD->addWidget(commentVarLabel, 2, 1); + + vboxKD->addWidget(new QLabel(QString(_("Key ID")) + ": "), 0, 0); + vboxKD->addWidget(new QLabel(QString(_("Algorithm")) + ": "), 1, 0); + vboxKD->addWidget(new QLabel(QString(_("Key Size")) + ": "), 2, 0); + vboxKD->addWidget(new QLabel(QString(_("Nominal Usage")) + ": "), 3, 0); + vboxKD->addWidget(new QLabel(QString(_("Actual Usage")) + ": "), 4, 0); + vboxKD->addWidget(new QLabel(QString(_("Expires on")) + ": "), 5, 0); + vboxKD->addWidget(new QLabel(QString(_("Last Update")) + ": "), 6, 0); + vboxKD->addWidget(new QLabel(QString(_("Secret Key Existence")) + ": "), 7, + 0); + + vboxKD->addWidget(keySizeVarLabel, 2, 1); + vboxKD->addWidget(expireVarLabel, 5, 1); + vboxKD->addWidget(algorithmVarLabel, 1, 1); + vboxKD->addWidget(createdVarLabel, 6, 1); + vboxKD->addWidget(keyidVarLabel, 0, 1); + vboxKD->addWidget(usageVarLabel, 3, 1); + vboxKD->addWidget(actualUsageVarLabel, 4, 1); + vboxKD->addWidget(masterKeyExistVarLabel, 7, 1); + + ownerBox->setLayout(vboxOD); + mvbox->addWidget(ownerBox); + keyBox->setLayout(vboxKD); + mvbox->addWidget(keyBox); + + fingerPrintVarLabel = + new QLabel(beautifyFingerprint(QString::fromStdString(mKey.fpr()))); + fingerPrintVarLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); + fingerPrintVarLabel->setStyleSheet("margin-left: 0; margin-right: 5;"); + auto* hboxFP = new QHBoxLayout(); + + hboxFP->addWidget(fingerPrintVarLabel); + + auto* copyFingerprintButton = new QPushButton(_("Copy")); + copyFingerprintButton->setFlat(true); + copyFingerprintButton->setToolTip(_("copy fingerprint to clipboard")); + connect(copyFingerprintButton, SIGNAL(clicked()), this, + SLOT(slotCopyFingerprint())); + + hboxFP->addWidget(copyFingerprintButton); + + fingerprintBox->setLayout(hboxFP); + mvbox->addWidget(fingerprintBox); + mvbox->addStretch(); + + if (mKey.is_private_key()) { + auto* privKeyBox = new QGroupBox(_("Operations")); + auto* vboxPK = new QVBoxLayout(); + + auto* exportButton = + new QPushButton(_("Export Private Key (Include Subkey)")); + vboxPK->addWidget(exportButton); + connect(exportButton, SIGNAL(clicked()), this, + SLOT(slotExportPrivateKey())); + + if (mKey.has_master_key()) { + auto* editExpiresButton = + new QPushButton(_("Modify Expiration Datetime (Master Key)")); + vboxPK->addWidget(editExpiresButton); + connect(editExpiresButton, SIGNAL(clicked()), this, + SLOT(slotModifyEditDatetime())); + + auto hBoxLayout = new QHBoxLayout(); + auto* keyServerOperaButton = + new QPushButton(_("Key Server Operation (Pubkey)")); + keyServerOperaButton->setStyleSheet("text-align:center;"); + + auto* revokeCertGenButton = + new QPushButton(_("Generate Revoke Certificate")); + connect(revokeCertGenButton, SIGNAL(clicked()), this, + SLOT(slotGenRevokeCert())); + + hBoxLayout->addWidget(keyServerOperaButton); + hBoxLayout->addWidget(revokeCertGenButton); + + vboxPK->addLayout(hBoxLayout); + connect(keyServerOperaButton, SIGNAL(clicked()), this, + SLOT(slotModifyEditDatetime())); + + // Set Menu + createKeyServerOperaMenu(); + keyServerOperaButton->setMenu(keyServerOperaMenu); } - if (mKey.expired) { - auto paletteExpired = expireVarLabel->palette(); - paletteExpired.setColor(expireVarLabel->foregroundRole(), Qt::red); - expireVarLabel->setPalette(paletteExpired); - } else { - auto paletteValid = expireVarLabel->palette(); - paletteValid.setColor(expireVarLabel->foregroundRole(), Qt::darkGreen); - expireVarLabel->setPalette(paletteValid); - } + privKeyBox->setLayout(vboxPK); + mvbox->addWidget(privKeyBox); + } - auto *mvbox = new QVBoxLayout(); - auto *vboxKD = new QGridLayout(); - auto *vboxOD = new QGridLayout(); - - vboxOD->addWidget(new QLabel(tr("Name:")), 0, 0); - vboxOD->addWidget(new QLabel(tr("Email Address:")), 1, 0); - vboxOD->addWidget(new QLabel(tr("Comment:")), 2, 0); - vboxOD->addWidget(nameVarLabel, 0, 1); - vboxOD->addWidget(emailVarLabel, 1, 1); - vboxOD->addWidget(commentVarLabel, 2, 1); - - vboxKD->addWidget(new QLabel(tr("Key ID: ")), 0, 0); - vboxKD->addWidget(new QLabel(tr("Algorithm: ")), 1, 0); - vboxKD->addWidget(new QLabel(tr("Key Size:")), 2, 0); - vboxKD->addWidget(new QLabel(tr("Nominal Usage: ")), 3, 0); - vboxKD->addWidget(new QLabel(tr("Actual Usage: ")), 4, 0); - vboxKD->addWidget(new QLabel(tr("Expires on: ")), 5, 0); - vboxKD->addWidget(new QLabel(tr("Last Update: ")), 6, 0); - vboxKD->addWidget(new QLabel(tr("Secret Key Existence: ")), 7, 0); - - - vboxKD->addWidget(keySizeVarLabel, 2, 1); - vboxKD->addWidget(expireVarLabel, 5, 1); - vboxKD->addWidget(algorithmVarLabel, 1, 1); - vboxKD->addWidget(createdVarLabel, 6, 1); - vboxKD->addWidget(keyidVarLabel, 0, 1); - vboxKD->addWidget(usageVarLabel, 3, 1); - vboxKD->addWidget(actualUsageVarLabel, 4, 1); - vboxKD->addWidget(masterKeyExistVarLabel, 7, 1); - - ownerBox->setLayout(vboxOD); - mvbox->addWidget(ownerBox); - keyBox->setLayout(vboxKD); - mvbox->addWidget(keyBox); - - fingerPrintVarLabel = new QLabel(beautifyFingerprint(mKey.fpr)); - fingerPrintVarLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); - fingerPrintVarLabel->setStyleSheet("margin-left: 0; margin-right: 5;"); - auto *hboxFP = new QHBoxLayout(); - - hboxFP->addWidget(fingerPrintVarLabel); - - auto *copyFingerprintButton = new QPushButton(tr("Copy")); - copyFingerprintButton->setFlat(true); - copyFingerprintButton->setToolTip(tr("copy fingerprint to clipboard")); - connect(copyFingerprintButton, SIGNAL(clicked()), this, SLOT(slotCopyFingerprint())); - - hboxFP->addWidget(copyFingerprintButton); - - fingerprintBox->setLayout(hboxFP); - mvbox->addWidget(fingerprintBox); - mvbox->addStretch(); - - if (mKey.is_private_key) { - auto *privKeyBox = new QGroupBox(tr("Operations")); - auto *vboxPK = new QVBoxLayout(); - - auto *exportButton = new QPushButton(tr("Export Private Key (Include Subkey)")); - vboxPK->addWidget(exportButton); - connect(exportButton, SIGNAL(clicked()), this, SLOT(slotExportPrivateKey())); - - if (mKey.has_master_key) { - auto *editExpiresButton = new QPushButton(tr("Modify Expiration Datetime (Master Key)")); - vboxPK->addWidget(editExpiresButton); - connect(editExpiresButton, SIGNAL(clicked()), this, SLOT(slotModifyEditDatetime())); - - auto hBoxLayout = new QHBoxLayout(); - auto *keyServerOperaButton = new QPushButton(tr("Key Server Operation (Pubkey)")); - keyServerOperaButton->setStyleSheet("text-align:center;"); - - auto *revokeCertGenButton = new QPushButton(tr("Generate Revoke Certificate")); - connect(revokeCertGenButton, SIGNAL(clicked()), this, SLOT(slotGenRevokeCert())); - - hBoxLayout->addWidget(keyServerOperaButton); - hBoxLayout->addWidget(revokeCertGenButton); - - vboxPK->addLayout(hBoxLayout); - connect(keyServerOperaButton, SIGNAL(clicked()), this, SLOT(slotModifyEditDatetime())); - - // Set Menu - createKeyServerOperaMenu(); - keyServerOperaButton->setMenu(keyServerOperaMenu); - } - - privKeyBox->setLayout(vboxPK); - mvbox->addWidget(privKeyBox); - } + if ((mKey.expired()) || (mKey.revoked())) { + auto* expBox = new QHBoxLayout(); + QPixmap pixmap(":warning.png"); - if ((mKey.expired) || (mKey.revoked)) { - auto *expBox = new QHBoxLayout(); - QPixmap pixmap(":warning.png"); - - auto *expLabel = new QLabel(); - auto *iconLabel = new QLabel(); - if (mKey.expired) { - expLabel->setText(tr("Warning: The Master Key has expired.")); - } - if (mKey.revoked) { - expLabel->setText(tr("Warning: The Master Key has been revoked")); - } - - iconLabel->setPixmap(pixmap.scaled(24, 24, Qt::KeepAspectRatio)); - QFont font = expLabel->font(); - font.setBold(true); - expLabel->setFont(font); - expLabel->setAlignment(Qt::AlignCenter); - expBox->addWidget(iconLabel); - expBox->addWidget(expLabel); - mvbox->addLayout(expBox); + auto* expLabel = new QLabel(); + auto* iconLabel = new QLabel(); + if (mKey.expired()) { + expLabel->setText(_("Warning: The Master Key has expired.")); + } + if (mKey.revoked()) { + expLabel->setText(_("Warning: The Master Key has been revoked")); } - mvbox->setContentsMargins(0, 0, 0, 0); - - connect(mCtx, SIGNAL(signalKeyInfoChanged()), this, SLOT(slotRefreshKeyInfo())); - - slotRefreshKeyInfo(); - setAttribute(Qt::WA_DeleteOnClose, true); - setLayout(mvbox); + iconLabel->setPixmap(pixmap.scaled(24, 24, Qt::KeepAspectRatio)); + QFont font = expLabel->font(); + font.setBold(true); + expLabel->setFont(font); + expLabel->setAlignment(Qt::AlignCenter); + expBox->addWidget(iconLabel); + expBox->addWidget(expLabel); + mvbox->addLayout(expBox); + } + + // when key database updated + connect(SignalStation::GetInstance(), SIGNAL(KeyDatabaseRefresh()), this, + SLOT(slotRefreshKey())); + + mvbox->setContentsMargins(0, 0, 0, 0); + + slotRefreshKeyInfo(); + setAttribute(Qt::WA_DeleteOnClose, true); + setLayout(mvbox); } void KeyPairDetailTab::slotExportPrivateKey() { - // Show a information box with explanation about private key - int ret = QMessageBox::information(this, tr("Exporting private Key"), - "<h3>" + tr("You are about to export your") + "<font color=\"red\">" + - tr("PRIVATE KEY") + "</font>!</h3>\n" + - tr("This is NOT your Public Key, so DON'T give it away.") + "<br />" + - tr("Do you REALLY want to export your PRIVATE KEY?"), - QMessageBox::Cancel | QMessageBox::Ok); - - // export key, if ok was clicked - if (ret == QMessageBox::Ok) { - auto *keyArray = new QByteArray(); - - if (!mCtx->exportSecretKey(mKey, keyArray)) { - QMessageBox::critical(this, "Error", "An error occurred during the export operation."); - return; - } - - auto key = mCtx->getKeyById(*keyid); - if (!key.good) { - QMessageBox::critical(nullptr, tr("Error"), tr("Key Not Found.")); - return; - } - QString fileString = key.name + " " + key.email + "(" + - key.id + ")_secret.asc"; - QString fileName = QFileDialog::getSaveFileName(this, tr("Export Key To File"), fileString, - tr("Key Files") + " (*.asc *.txt);;All Files (*)"); - QFile file(fileName); - if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { - QMessageBox::critical(nullptr, tr("Export Error"), tr("Couldn't open %1 for writing").arg(fileName)); - return; - } - QTextStream stream(&file); - stream << *keyArray; - file.close(); - delete keyArray; + // Show a information box with explanation about private key + int ret = QMessageBox::information( + this, _("Exporting private Key"), + "<h3>" + QString(_("You are about to export your")) + + "<font color=\"red\">" + _(" PRIVATE KEY ") + "</font>!</h3>\n" + + _("This is NOT your Public Key, so DON'T give it away.") + "<br />" + + _("Do you REALLY want to export your PRIVATE KEY?"), + QMessageBox::Cancel | QMessageBox::Ok); + + // export key, if ok was clicked + if (ret == QMessageBox::Ok) { + ByteArrayPtr keyArray = nullptr; + + if (!GpgKeyImportExportor::GetInstance().ExportSecretKey(mKey, keyArray)) { + QMessageBox::critical( + this, _("Error"), + _("An error occurred during the export operation.")); + return; + } + + auto key = GpgKeyGetter::GetInstance().GetKey(keyid); + if (!key.good()) { + QMessageBox::critical(nullptr, _("Error"), _("Key Not Found.")); + return; } + auto fileString = + key.name() + " " + key.email() + "(" + key.id() + ")_secret.asc"; + auto fileName = + QFileDialog::getSaveFileName( + this, _("Export Key To File"), QString::fromStdString(fileString), + QString(_("Key Files")) + " (*.asc *.txt);;All Files (*)") + .toStdString(); + + if (!write_buffer_to_file(fileName, *keyArray)) { + QMessageBox::critical( + nullptr, _("Export Error"), + QString(_("Couldn't open %1 for writing")).arg(fileName.c_str())); + return; + } + } } QString KeyPairDetailTab::beautifyFingerprint(QString fingerprint) { - uint len = fingerprint.length(); - if ((len > 0) && (len % 4 == 0)) - for (uint n = 0; 4 * (n + 1) < len; ++n) - fingerprint.insert(static_cast<int>(5u * n + 4u), ' '); - return fingerprint; + uint len = fingerprint.length(); + if ((len > 0) && (len % 4 == 0)) + for (uint n = 0; 4 * (n + 1) < len; ++n) + fingerprint.insert(static_cast<int>(5u * n + 4u), ' '); + return fingerprint; } void KeyPairDetailTab::slotCopyFingerprint() { - QString fpr = fingerPrintVarLabel->text().trimmed().replace(" ", ""); - QClipboard *cb = QApplication::clipboard(); - cb->setText(fpr); + QString fpr = fingerPrintVarLabel->text().trimmed().replace(" ", QString()); + QClipboard* cb = QApplication::clipboard(); + cb->setText(fpr); } void KeyPairDetailTab::slotModifyEditDatetime() { - auto dialog = new KeySetExpireDateDialog(mCtx, mKey, nullptr, this); - dialog->show(); + auto dialog = new KeySetExpireDateDialog(mKey.id(), this); + dialog->show(); } void KeyPairDetailTab::slotRefreshKeyInfo() { + nameVarLabel->setText(QString::fromStdString(mKey.name())); + emailVarLabel->setText(QString::fromStdString(mKey.email())); - nameVarLabel->setText(mKey.name); - emailVarLabel->setText(mKey.email); - - commentVarLabel->setText(mKey.comment); - keyidVarLabel->setText(mKey.id); + commentVarLabel->setText(QString::fromStdString(mKey.comment())); + keyidVarLabel->setText(QString::fromStdString(mKey.id())); - QString usage; - QTextStream usage_steam(&usage); + QString usage; + QTextStream usage_steam(&usage); - if (mKey.can_certify) - usage_steam << "Cert "; - if (mKey.can_encrypt) - usage_steam << "Encr "; - if (mKey.can_sign) - usage_steam << "Sign "; - if (mKey.can_authenticate) - usage_steam << "Auth "; + if (mKey.can_certify()) usage_steam << _("Cert") << " "; + if (mKey.can_encrypt()) usage_steam << _("Encr") << " "; + if (mKey.can_sign()) usage_steam << _("Sign") << " "; + if (mKey.can_authenticate()) usage_steam << _("Auth") << " "; - usageVarLabel->setText(usage); + usageVarLabel->setText(usage); - QString actualUsage; - QTextStream actual_usage_steam(&actualUsage); + QString actualUsage; + QTextStream actual_usage_steam(&actualUsage); - if (GpgME::GpgContext::checkIfKeyCanCert(mKey)) - actual_usage_steam << "Cert "; - if (GpgME::GpgContext::checkIfKeyCanEncr(mKey)) - actual_usage_steam << "Encr "; - if (GpgME::GpgContext::checkIfKeyCanSign(mKey)) - actual_usage_steam << "Sign "; - if (GpgME::GpgContext::checkIfKeyCanAuth(mKey)) - actual_usage_steam << "Auth "; + if (mKey.CanCertActual()) actual_usage_steam << _("Cert") << " "; + if (mKey.CanEncrActual()) actual_usage_steam << _("Encr") << " "; + if (mKey.CanSignActual()) actual_usage_steam << _("Sign") << " "; + if (mKey.CanAuthActual()) actual_usage_steam << _("Auth") << " "; - actualUsageVarLabel->setText(actualUsage); + actualUsageVarLabel->setText(actualUsage); - QString keySizeVal, keyExpireVal, keyCreateTimeVal, keyAlgoVal; + QString keySizeVal, keyExpireVal, keyCreateTimeVal, keyAlgoVal; - keySizeVal = QString::number(mKey.length); - - if (mKey.expires.toTime_t() == 0) { - keyExpireVal = tr("Never Expire"); - } else { - keyExpireVal = mKey.expires.toString(); - } + keySizeVal = QString::number(mKey.length()); - keyAlgoVal = mKey.pubkey_algo; - keyCreateTimeVal = mKey.create_time.toString(); + if (to_time_t(boost::posix_time::ptime(mKey.expires())) == 0) { + keyExpireVal = _("Never Expire"); + } else { + keyExpireVal = + QString::fromStdString(boost::gregorian::to_iso_string(mKey.expires())); + } - keySizeVarLabel->setText(keySizeVal); - expireVarLabel->setText(keyExpireVal); - createdVarLabel->setText(keyCreateTimeVal); - algorithmVarLabel->setText(keyAlgoVal); + keyAlgoVal = QString::fromStdString(mKey.pubkey_algo()); + keyCreateTimeVal = QString::fromStdString(to_iso_string(mKey.create_time())); - fingerPrintVarLabel->setText(beautifyFingerprint(mKey.fpr)); + keySizeVarLabel->setText(keySizeVal); + expireVarLabel->setText(keyExpireVal); + createdVarLabel->setText(keyCreateTimeVal); + algorithmVarLabel->setText(keyAlgoVal); + auto key_fpr = mKey.fpr(); + fingerPrintVarLabel->setText( + QString::fromStdString(beautify_fingerprint(key_fpr))); } void KeyPairDetailTab::createKeyServerOperaMenu() { - keyServerOperaMenu = new QMenu(this); + keyServerOperaMenu = new QMenu(this); - auto *uploadKeyPair = new QAction(tr("Upload Key Pair to Key Server"), this); - connect(uploadKeyPair, SIGNAL(triggered()), this, SLOT(slotUploadKeyToServer())); - auto *updateKeyPair = new QAction(tr("Update Key Pair"), this); - connect(updateKeyPair, SIGNAL(triggered()), this, SLOT(slotUpdateKeyToServer())); + auto* uploadKeyPair = new QAction(_("Upload Key Pair to Key Server"), this); + connect(uploadKeyPair, SIGNAL(triggered()), this, + SLOT(slotUploadKeyToServer())); + auto* updateKeyPair = new QAction(_("Update Key Pair"), this); + connect(updateKeyPair, SIGNAL(triggered()), this, + SLOT(slotUpdateKeyToServer())); - keyServerOperaMenu->addAction(uploadKeyPair); - // TODO Solve Refresh Problem -// keyServerOperaMenu->addAction(updateKeyPair); + keyServerOperaMenu->addAction(uploadKeyPair); + keyServerOperaMenu->addAction(updateKeyPair); } void KeyPairDetailTab::slotUploadKeyToServer() { - QVector<GpgKey> keys; - keys.append(mKey); - auto *dialog = new KeyUploadDialog(mCtx, keys); + auto keys = std::make_unique<KeyIdArgsList>(); + keys->push_back(mKey.id()); + auto* dialog = new KeyUploadDialog(keys, this); + dialog->show(); + dialog->slotUpload(); } void KeyPairDetailTab::slotUpdateKeyToServer() { - QVector<GpgKey> keys; - keys.append(mKey); - auto *dialog = new KeyServerImportDialog(mCtx, this); - dialog->show(); - dialog->slotImportKey(keys); + auto keys = std::make_unique<KeyIdArgsList>(); + keys->push_back(mKey.id()); + auto* dialog = new KeyServerImportDialog(this); + dialog->show(); + dialog->slotImport(keys); } void KeyPairDetailTab::slotGenRevokeCert() { - auto mOutputFileName = QFileDialog::getSaveFileName(this, tr("Generate revocation certificate"), - QString(), - QStringLiteral("%1 (*.rev)").arg( - tr("Revocation Certificates"))); - - if (!mOutputFileName.isEmpty()) - mCtx->generateRevokeCert(mKey, mOutputFileName); - + auto literal = QStringLiteral("%1 (*.rev)").arg(_("Revocation Certificates")); + QString m_output_file_name; + + QFileDialog dialog(this, "Generate revocation certificate", QString(), + literal); + dialog.setDefaultSuffix(".rev"); + dialog.setAcceptMode(QFileDialog::AcceptSave); + + if (dialog.exec()) m_output_file_name = dialog.selectedFiles().front(); + + if (!m_output_file_name.isEmpty()) + CommonUtils::GetInstance()->slotExecuteGpgCommand( + {"--command-fd", "0", "--status-fd", "1", "--no-tty", "-o", + m_output_file_name, "--gen-revoke", mKey.fpr().c_str()}, + [](QProcess* proc) -> void { + // Code From Gpg4Win + while (proc->canReadLine()) { + const QString line = QString::fromUtf8(proc->readLine()).trimmed(); + LOG(INFO) << "line" << line.toStdString(); + if (line == QLatin1String("[GNUPG:] GET_BOOL gen_revoke.okay")) { + proc->write("y\n"); + } else if (line == QLatin1String("[GNUPG:] GET_LINE " + "ask_revocation_reason.code")) { + proc->write("0\n"); + } else if (line == QLatin1String("[GNUPG:] GET_LINE " + "ask_revocation_reason.text")) { + proc->write("\n"); + } else if (line == + QLatin1String( + "[GNUPG:] GET_BOOL openfile.overwrite.okay")) { + // We asked before + proc->write("y\n"); + } else if (line == QLatin1String("[GNUPG:] GET_BOOL " + "ask_revocation_reason.okay")) { + proc->write("y\n"); + } + } + }); +} +void KeyPairDetailTab::slotRefreshKey() { + LOG(INFO) << _("Called"); + this->mKey = GpgKeyGetter::GetInstance().GetKey(mKey.id()); + this->slotRefreshKeyInfo(); } +} // namespace GpgFrontend::UI diff --git a/src/ui/keypair_details/KeyPairDetailTab.h b/src/ui/keypair_details/KeyPairDetailTab.h new file mode 100644 index 00000000..782696ac --- /dev/null +++ b/src/ui/keypair_details/KeyPairDetailTab.h @@ -0,0 +1,105 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_KEYPAIRDETAILTAB_H +#define GPGFRONTEND_KEYPAIRDETAILTAB_H + +#include "KeySetExpireDateDialog.h" +#include "gpg/GpgContext.h" +#include "ui/GpgFrontendUI.h" +#include "ui/KeyServerImportDialog.h" +#include "ui/KeyUploadDialog.h" + +namespace GpgFrontend::UI { + +class KeyPairDetailTab : public QWidget { + Q_OBJECT + + /** + * @details Return QString with a space inserted at every fourth character + * + * @param fingerprint The fingerprint to be beautified + */ + static QString beautifyFingerprint(QString fingerprint); + + void createKeyServerOperaMenu(); + + private slots: + + /** + * @details Export the key to a file, which is choosen in a file dialog + */ + void slotExportPrivateKey(); + + /** + * @details Copy the fingerprint to clipboard + */ + void slotCopyFingerprint(); + + void slotModifyEditDatetime(); + + void slotRefreshKeyInfo(); + + void slotUploadKeyToServer(); + + void slotUpdateKeyToServer(); + + void slotGenRevokeCert(); + + void slotRefreshKey(); + + private: + std::string keyid; /** The id of the key the details should be shown for */ + + GpgKey mKey; + + QGroupBox* ownerBox; /** Groupbox containing owner information */ + QGroupBox* keyBox; /** Groupbox containing key information */ + QGroupBox* fingerprintBox; /** Groupbox containing fingerprint information */ + QGroupBox* additionalUidBox; /** Groupbox containing information about + additional uids */ + + QLabel* nameVarLabel; /** Label containng the keys name */ + QLabel* emailVarLabel; /** Label containng the keys email */ + QLabel* commentVarLabel; /** Label containng the keys commment */ + QLabel* keySizeVarLabel; /** Label containng the keys keysize */ + QLabel* expireVarLabel; /** Label containng the keys expiration date */ + QLabel* createdVarLabel; /** Label containng the keys creation date */ + QLabel* algorithmVarLabel; /** Label containng the keys algorithm */ + QLabel* keyidVarLabel; /** Label containng the keys keyid */ + QLabel* fingerPrintVarLabel; /** Label containng the keys fingerprint */ + QLabel* usageVarLabel; + QLabel* actualUsageVarLabel; + QLabel* masterKeyExistVarLabel; + + QMenu* keyServerOperaMenu{}; + + public: + explicit KeyPairDetailTab(const std::string& key_id, + QWidget* parent = nullptr); +}; + +} // namespace GpgFrontend::UI + +#endif // GPGFRONTEND_KEYPAIRDETAILTAB_H diff --git a/src/ui/keypair_details/KeyPairSubkeyTab.cpp b/src/ui/keypair_details/KeyPairSubkeyTab.cpp index 6a924394..4458be50 100644 --- a/src/ui/keypair_details/KeyPairSubkeyTab.cpp +++ b/src/ui/keypair_details/KeyPairSubkeyTab.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -24,243 +24,278 @@ #include "ui/keypair_details/KeyPairSubkeyTab.h" -KeyPairSubkeyTab::KeyPairSubkeyTab(GpgME::GpgContext *ctx, const GpgKey &key, QWidget *parent) : mCtx(ctx), mKey(key), QWidget(parent) { - - createSubkeyList(); - createSubkeyOperaMenu(); - - listBox = new QGroupBox("Subkey List"); - detailBox = new QGroupBox("Detail of Selected Subkey"); - - auto uidButtonsLayout = new QGridLayout(); - - auto addSubkeyButton = new QPushButton(tr("Generate A New Subkey")); - if(!mKey.is_private_key || !mKey.has_master_key) { - addSubkeyButton->setDisabled(true); - setHidden(addSubkeyButton); - } - - uidButtonsLayout->addWidget(addSubkeyButton, 0, 1); - - auto *baseLayout = new QVBoxLayout(); - - auto subkeyListLayout = new QGridLayout(); - subkeyListLayout->addWidget(subkeyList, 0, 0); - subkeyListLayout->addLayout(uidButtonsLayout, 1, 0); - subkeyListLayout->setContentsMargins(0, 10, 0, 0); - - auto *subkeyDetailLayout = new QGridLayout(); - - subkeyDetailLayout->addWidget(new QLabel(tr("Key ID: ")), 0, 0); - subkeyDetailLayout->addWidget(new QLabel(tr("Algorithm: ")), 1, 0); - subkeyDetailLayout->addWidget(new QLabel(tr("Key Size:")), 2, 0); - subkeyDetailLayout->addWidget(new QLabel(tr("Usage: ")), 3, 0); - subkeyDetailLayout->addWidget(new QLabel(tr("Expires On ")), 4, 0); - subkeyDetailLayout->addWidget(new QLabel(tr("Last Update: ")), 5, 0); - subkeyDetailLayout->addWidget(new QLabel(tr("Existence: ")), 6, 0); - subkeyDetailLayout->addWidget(new QLabel(tr("Fingerprint: ")), 7, 0); - - - keyidVarLabel = new QLabel(); - keySizeVarLabel = new QLabel(); - expireVarLabel = new QLabel(); - algorithmVarLabel = new QLabel(); - createdVarLabel = new QLabel(); - usageVarLabel = new QLabel(); - masterKeyExistVarLabel = new QLabel(); - fingerPrintVarLabel = new QLabel(); - - subkeyDetailLayout->addWidget(keyidVarLabel, 0, 1); - subkeyDetailLayout->addWidget(keySizeVarLabel, 2, 1); - subkeyDetailLayout->addWidget(expireVarLabel, 4, 1); - subkeyDetailLayout->addWidget(algorithmVarLabel, 1, 1); - subkeyDetailLayout->addWidget(createdVarLabel, 5, 1); - subkeyDetailLayout->addWidget(usageVarLabel, 3, 1); - subkeyDetailLayout->addWidget(masterKeyExistVarLabel, 6, 1); - subkeyDetailLayout->addWidget(fingerPrintVarLabel, 7, 1); - - listBox->setLayout(subkeyListLayout); - listBox->setContentsMargins(0, 5, 0, 0); - detailBox->setLayout(subkeyDetailLayout); - - baseLayout->addWidget(listBox); - baseLayout->addWidget(detailBox); - baseLayout->addStretch(); - - connect(addSubkeyButton, SIGNAL(clicked(bool)), this, SLOT(slotAddSubkey())); - connect(mCtx, SIGNAL(signalKeyInfoChanged()), this, SLOT(slotRefreshSubkeyList())); - connect(subkeyList, SIGNAL(itemSelectionChanged()), this, SLOT(slotRefreshSubkeyDetail())); - - baseLayout->setContentsMargins(0, 0, 0, 0); - - setLayout(baseLayout); - setAttribute(Qt::WA_DeleteOnClose, true); - - slotRefreshSubkeyList(); - +#include "gpg/function/GpgKeyGetter.h" +#include "ui/SignalStation.h" + +namespace GpgFrontend::UI { + +KeyPairSubkeyTab::KeyPairSubkeyTab(const std::string& key_id, QWidget* parent) + : QWidget(parent), mKey(GpgKeyGetter::GetInstance().GetKey(key_id)) { + createSubkeyList(); + createSubkeyOperaMenu(); + + listBox = new QGroupBox("Subkey List"); + detailBox = new QGroupBox("Detail of Selected Subkey"); + + auto uidButtonsLayout = new QGridLayout(); + + auto addSubkeyButton = new QPushButton(_("Generate A New Subkey")); + if (!mKey.is_private_key() || !mKey.has_master_key()) { + addSubkeyButton->setDisabled(true); + setHidden(addSubkeyButton); + } + + uidButtonsLayout->addWidget(addSubkeyButton, 0, 1); + + auto* baseLayout = new QVBoxLayout(); + + auto subkeyListLayout = new QGridLayout(); + subkeyListLayout->addWidget(subkeyList, 0, 0); + subkeyListLayout->addLayout(uidButtonsLayout, 1, 0); + subkeyListLayout->setContentsMargins(0, 10, 0, 0); + + auto* subkeyDetailLayout = new QGridLayout(); + + subkeyDetailLayout->addWidget(new QLabel(QString(_("Key ID")) + ": "), 0, 0); + subkeyDetailLayout->addWidget(new QLabel(QString(_("Algorithm")) + ": "), 1, + 0); + subkeyDetailLayout->addWidget(new QLabel(QString(_("Key Size")) + ": "), 2, + 0); + subkeyDetailLayout->addWidget(new QLabel(QString(_("Usage")) + ": "), 3, 0); + subkeyDetailLayout->addWidget(new QLabel(QString(_("Expires On")) + ": "), 4, + 0); + subkeyDetailLayout->addWidget(new QLabel(QString(_("Last Update")) + ": "), 5, + 0); + subkeyDetailLayout->addWidget(new QLabel(QString(_("Existence")) + ": "), 6, + 0); + subkeyDetailLayout->addWidget(new QLabel(QString(_("Fingerprint")) + ": "), 7, + 0); + + keyidVarLabel = new QLabel(); + keySizeVarLabel = new QLabel(); + expireVarLabel = new QLabel(); + algorithmVarLabel = new QLabel(); + createdVarLabel = new QLabel(); + usageVarLabel = new QLabel(); + masterKeyExistVarLabel = new QLabel(); + fingerPrintVarLabel = new QLabel(); + + subkeyDetailLayout->addWidget(keyidVarLabel, 0, 1); + subkeyDetailLayout->addWidget(keySizeVarLabel, 2, 1); + subkeyDetailLayout->addWidget(expireVarLabel, 4, 1); + subkeyDetailLayout->addWidget(algorithmVarLabel, 1, 1); + subkeyDetailLayout->addWidget(createdVarLabel, 5, 1); + subkeyDetailLayout->addWidget(usageVarLabel, 3, 1); + subkeyDetailLayout->addWidget(masterKeyExistVarLabel, 6, 1); + subkeyDetailLayout->addWidget(fingerPrintVarLabel, 7, 1); + + listBox->setLayout(subkeyListLayout); + listBox->setContentsMargins(0, 5, 0, 0); + detailBox->setLayout(subkeyDetailLayout); + + baseLayout->addWidget(listBox); + baseLayout->addWidget(detailBox); + baseLayout->addStretch(); + + connect(addSubkeyButton, SIGNAL(clicked(bool)), this, SLOT(slotAddSubkey())); + connect(subkeyList, SIGNAL(itemSelectionChanged()), this, + SLOT(slotRefreshSubkeyDetail())); + + // key database refresh signal + connect(SignalStation::GetInstance(), SIGNAL(KeyDatabaseRefresh()), this, + SLOT(slotRefreshKeyInfo())); + connect(SignalStation::GetInstance(), SIGNAL(KeyDatabaseRefresh()), this, + SLOT(slotRefreshSubkeyList())); + + baseLayout->setContentsMargins(0, 0, 0, 0); + + setLayout(baseLayout); + setAttribute(Qt::WA_DeleteOnClose, true); + + slotRefreshSubkeyList(); } void KeyPairSubkeyTab::createSubkeyList() { - subkeyList = new QTableWidget(this); + subkeyList = new QTableWidget(this); - subkeyList->setColumnCount(5); - subkeyList->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); - subkeyList->verticalHeader()->hide(); - subkeyList->setShowGrid(false); - subkeyList->setSelectionBehavior(QAbstractItemView::SelectRows); + subkeyList->setColumnCount(5); + subkeyList->horizontalHeader()->setSectionResizeMode( + QHeaderView::ResizeToContents); + subkeyList->verticalHeader()->hide(); + subkeyList->setShowGrid(false); + subkeyList->setSelectionBehavior(QAbstractItemView::SelectRows); - // tableitems not editable - subkeyList->setEditTriggers(QAbstractItemView::NoEditTriggers); + // tableitems not editable + subkeyList->setEditTriggers(QAbstractItemView::NoEditTriggers); - // no focus (rectangle around tableitems) - // may be it should focus on whole row - subkeyList->setFocusPolicy(Qt::NoFocus); - subkeyList->setAlternatingRowColors(true); + // no focus (rectangle around tableitems) + // may be it should focus on whole row + subkeyList->setFocusPolicy(Qt::NoFocus); + subkeyList->setAlternatingRowColors(true); - QStringList labels; - labels << tr("Subkey ID") << tr("Key Size") << tr("Algo") << tr("Create Date") << tr("Expire Date"); + QStringList labels; + labels << _("Subkey ID") << _("Key Size") << _("Algo") << _("Create Date") + << _("Expire Date"); - subkeyList->setHorizontalHeaderLabels(labels); - subkeyList->horizontalHeader()->setStretchLastSection(false); + subkeyList->setHorizontalHeaderLabels(labels); + subkeyList->horizontalHeader()->setStretchLastSection(false); } void KeyPairSubkeyTab::slotRefreshSubkeyList() { - int row = 0; - - subkeyList->setSelectionMode(QAbstractItemView::SingleSelection); - - this->buffered_subkeys.clear(); - - for(const auto &subkeys : mKey.subKeys) { - if(subkeys.disabled || subkeys.revoked) - continue; - this->buffered_subkeys.push_back(&subkeys); + LOG(INFO) << "KeyPairSubkeyTab::slotRefreshSubkeyList Called"; + int row = 0; + + subkeyList->setSelectionMode(QAbstractItemView::SingleSelection); + + this->buffered_subkeys.clear(); + auto sub_keys = mKey.subKeys(); + for (auto& sub_key : *sub_keys) { + if (sub_key.disabled() || sub_key.revoked()) continue; + this->buffered_subkeys.push_back(std::move(sub_key)); + } + + subkeyList->setRowCount(buffered_subkeys.size()); + + for (const auto& subkeys : buffered_subkeys) { + auto* tmp0 = new QTableWidgetItem(QString::fromStdString(subkeys.id())); + tmp0->setTextAlignment(Qt::AlignCenter); + subkeyList->setItem(row, 0, tmp0); + + auto* tmp1 = new QTableWidgetItem(QString::number(subkeys.length())); + tmp1->setTextAlignment(Qt::AlignCenter); + subkeyList->setItem(row, 1, tmp1); + + auto* tmp2 = + new QTableWidgetItem(QString::fromStdString(subkeys.pubkey_algo())); + tmp2->setTextAlignment(Qt::AlignCenter); + subkeyList->setItem(row, 2, tmp2); + + auto* tmp3 = new QTableWidgetItem( + QString::fromStdString(to_iso_string(subkeys.timestamp()))); + tmp3->setTextAlignment(Qt::AlignCenter); + subkeyList->setItem(row, 3, tmp3); + + auto* tmp4 = new QTableWidgetItem( + boost::posix_time::to_time_t( + boost::posix_time::ptime(subkeys.expires())) == 0 + ? _("Never Expire") + : QString::fromStdString(to_iso_string(subkeys.expires()))); + tmp4->setTextAlignment(Qt::AlignCenter); + subkeyList->setItem(row, 4, tmp4); + + if (!row) { + for (auto i = 0; i < subkeyList->columnCount(); i++) { + subkeyList->item(row, i)->setForeground(QColor(65, 105, 255)); + } } - subkeyList->setRowCount(buffered_subkeys.size()); - - for(const auto& subkeys : buffered_subkeys) { + row++; + } - auto *tmp0 = new QTableWidgetItem(subkeys->id); - tmp0->setTextAlignment(Qt::AlignCenter); - subkeyList->setItem(row, 0, tmp0); - - auto *tmp1 = new QTableWidgetItem(QString::number(subkeys->length)); - tmp1->setTextAlignment(Qt::AlignCenter); - subkeyList->setItem(row, 1, tmp1); - - auto *tmp2 = new QTableWidgetItem(subkeys->pubkey_algo); - tmp2->setTextAlignment(Qt::AlignCenter); - subkeyList->setItem(row, 2, tmp2); - - auto *tmp3= new QTableWidgetItem(subkeys->timestamp.toString()); - tmp3->setTextAlignment(Qt::AlignCenter); - subkeyList->setItem(row, 3, tmp3); - - auto *tmp4= new QTableWidgetItem(subkeys->expires.toTime_t() == 0 ? tr("Never Expire") : subkeys->expires.toString()); - tmp4->setTextAlignment(Qt::AlignCenter); - subkeyList->setItem(row, 4, tmp4); - - row++; - } - - if(subkeyList->rowCount() > 0) { - subkeyList->selectRow(0); - } + if (subkeyList->rowCount() > 0) { + subkeyList->selectRow(0); + } } void KeyPairSubkeyTab::slotAddSubkey() { - auto dialog = new SubkeyGenerateDialog(mCtx, mKey, this); - dialog->show(); + auto dialog = new SubkeyGenerateDialog(mKey.id(), this); + dialog->show(); } void KeyPairSubkeyTab::slotRefreshSubkeyDetail() { - - auto key = getSelectedSubkey(); - - keyidVarLabel->setText(key->id); - keySizeVarLabel->setText(QString::number(key->length)); - - expireVarLabel->setText(key->expires.toTime_t() == 0 ? tr("Never Expires") : key->expires.toString()); - if(key->expires.toTime_t() != 0 && key->expires < QDateTime::currentDateTime()) { - auto paletteExpired = expireVarLabel->palette(); - paletteExpired.setColor(expireVarLabel->foregroundRole(), Qt::red); - expireVarLabel->setPalette(paletteExpired); - } else { - auto paletteValid = expireVarLabel->palette(); - paletteValid.setColor(expireVarLabel->foregroundRole(), Qt::darkGreen); - expireVarLabel->setPalette(paletteValid); - } - - algorithmVarLabel->setText(key->pubkey_algo); - createdVarLabel->setText(key->timestamp.toString()); - - QString usage; - QTextStream usage_steam(&usage); - - if(key->can_certify) - usage_steam << "Cert "; - if(key->can_encrypt) - usage_steam << "Encr "; - if(key->can_sign) - usage_steam << "Sign "; - if(key->can_authenticate) - usage_steam << "Auth "; - - usageVarLabel->setText(usage); - - // Show the situation that master key not exists. - masterKeyExistVarLabel->setText(key->secret ? "Exists" : "Not Exists"); - if(!key->secret){ - auto paletteExpired = masterKeyExistVarLabel->palette(); - paletteExpired.setColor(masterKeyExistVarLabel->foregroundRole(), Qt::red); - masterKeyExistVarLabel->setPalette(paletteExpired); - } else { - auto paletteValid = masterKeyExistVarLabel->palette(); - paletteValid.setColor(masterKeyExistVarLabel->foregroundRole(), Qt::darkGreen); - masterKeyExistVarLabel->setPalette(paletteValid); - } - - fingerPrintVarLabel->setText(key->fpr); + auto& subkey = getSelectedSubkey(); + + keyidVarLabel->setText(QString::fromStdString(subkey.id())); + keySizeVarLabel->setText(QString::number(subkey.length())); + + time_t subkey_time_t = + boost::posix_time::to_time_t(boost::posix_time::ptime(subkey.expires())); + + expireVarLabel->setText( + subkey_time_t == 0 + ? _("Never Expires") + : QString::fromStdString(to_iso_string(subkey.expires()))); + if (subkey_time_t != 0 && + subkey.expires() < boost::posix_time::second_clock::local_time().date()) { + auto paletteExpired = expireVarLabel->palette(); + paletteExpired.setColor(expireVarLabel->foregroundRole(), Qt::red); + expireVarLabel->setPalette(paletteExpired); + } else { + auto paletteValid = expireVarLabel->palette(); + paletteValid.setColor(expireVarLabel->foregroundRole(), Qt::darkGreen); + expireVarLabel->setPalette(paletteValid); + } + + algorithmVarLabel->setText(QString::fromStdString(subkey.pubkey_algo())); + createdVarLabel->setText( + QString::fromStdString(to_iso_string(subkey.timestamp()))); + + QString usage; + QTextStream usage_steam(&usage); + + if (subkey.can_certify()) usage_steam << _("Cert") << " "; + if (subkey.can_encrypt()) usage_steam << _("Encr") << " "; + if (subkey.can_sign()) usage_steam << _("Sign") << " "; + if (subkey.can_authenticate()) usage_steam << _("Auth") << " "; + + usageVarLabel->setText(usage); + + // Show the situation that master key not exists. + masterKeyExistVarLabel->setText(subkey.secret() ? _("Exists") + : _("Not Exists")); + if (!subkey.secret()) { + auto paletteExpired = masterKeyExistVarLabel->palette(); + paletteExpired.setColor(masterKeyExistVarLabel->foregroundRole(), Qt::red); + masterKeyExistVarLabel->setPalette(paletteExpired); + } else { + auto paletteValid = masterKeyExistVarLabel->palette(); + paletteValid.setColor(masterKeyExistVarLabel->foregroundRole(), + Qt::darkGreen); + masterKeyExistVarLabel->setPalette(paletteValid); + } + + fingerPrintVarLabel->setText(QString::fromStdString(subkey.fpr())); } void KeyPairSubkeyTab::createSubkeyOperaMenu() { - subkeyOperaMenu = new QMenu(this); - // auto *revokeSubkeyAct = new QAction(tr("Revoke Subkey")); - auto *editSubkeyAct = new QAction(tr("Edit Expire Date")); - connect(editSubkeyAct, SIGNAL(triggered(bool)), this, SLOT(slotEditSubkey())); + subkeyOperaMenu = new QMenu(this); + // auto *revokeSubkeyAct = new QAction(_("Revoke Subkey")); + auto* editSubkeyAct = new QAction(_("Edit Expire Date")); + connect(editSubkeyAct, SIGNAL(triggered(bool)), this, SLOT(slotEditSubkey())); - // subkeyOperaMenu->addAction(revokeSubkeyAct); - subkeyOperaMenu->addAction(editSubkeyAct); + // subkeyOperaMenu->addAction(revokeSubkeyAct); + subkeyOperaMenu->addAction(editSubkeyAct); } void KeyPairSubkeyTab::slotEditSubkey() { - qDebug() << "Slot Edit Subkry"; - auto *subkey = getSelectedSubkey(); - if(subkey == buffered_subkeys[0]) { - subkey = nullptr; - } - auto dialog = new KeySetExpireDateDialog(mCtx, mKey, subkey, this); - dialog->show(); -} - -void KeyPairSubkeyTab::slotRevokeSubkey() { + LOG(INFO) << "KeyPairSubkeyTab::slotEditSubkey Fpr" + << getSelectedSubkey().fpr(); + auto dialog = + new KeySetExpireDateDialog(mKey.id(), getSelectedSubkey().fpr(), this); + dialog->show(); } -void KeyPairSubkeyTab::contextMenuEvent(QContextMenuEvent *event) { - if (!subkeyList->selectedItems().isEmpty()) { - subkeyOperaMenu->exec(event->globalPos()); - } +void KeyPairSubkeyTab::slotRevokeSubkey() {} + +void KeyPairSubkeyTab::contextMenuEvent(QContextMenuEvent* event) { + if (!subkeyList->selectedItems().isEmpty()) { + subkeyOperaMenu->exec(event->globalPos()); + } } -const GpgSubKey *KeyPairSubkeyTab::getSelectedSubkey() { - int row = 0; +const GpgSubKey& KeyPairSubkeyTab::getSelectedSubkey() { + int row = 0; - for(int i = 0 ; i < subkeyList->rowCount(); i++) { - if(subkeyList->item(row, 0)->isSelected()) break; - row++; - } + for (int i = 0; i < subkeyList->rowCount(); i++) { + if (subkeyList->item(row, 0)->isSelected()) break; + row++; + } - return buffered_subkeys[row]; + return buffered_subkeys[row]; } +void KeyPairSubkeyTab::slotRefreshKeyInfo() { + mKey = GpgKeyGetter::GetInstance().GetKey(mKey.id()); +} + +} // namespace GpgFrontend::UI diff --git a/src/ui/keypair_details/KeyPairSubkeyTab.h b/src/ui/keypair_details/KeyPairSubkeyTab.h new file mode 100644 index 00000000..018f6ddc --- /dev/null +++ b/src/ui/keypair_details/KeyPairSubkeyTab.h @@ -0,0 +1,86 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_KEYPAIRSUBKEYTAB_H +#define GPGFRONTEND_KEYPAIRSUBKEYTAB_H + +#include "KeySetExpireDateDialog.h" +#include "gpg/GpgContext.h" +#include "ui/GpgFrontendUI.h" +#include "ui/keygen/SubkeyGenerateDialog.h" + +namespace GpgFrontend::UI { + +class KeyPairSubkeyTab : public QWidget { + Q_OBJECT + + public: + KeyPairSubkeyTab(const std::string& key, QWidget* parent); + + private: + void createSubkeyList(); + + void createSubkeyOperaMenu(); + + const GpgSubKey& getSelectedSubkey(); + + GpgKey mKey; + QTableWidget* subkeyList{}; + std::vector<GpgSubKey> buffered_subkeys; + + QGroupBox* listBox; + QGroupBox* detailBox; + + QMenu* subkeyOperaMenu{}; + + QLabel* keySizeVarLabel; /** Label containng the keys keysize */ + QLabel* expireVarLabel; /** Label containng the keys expiration date */ + QLabel* createdVarLabel; /** Label containng the keys creation date */ + QLabel* algorithmVarLabel; /** Label containng the keys algorithm */ + QLabel* keyidVarLabel; /** Label containng the keys keyid */ + QLabel* fingerPrintVarLabel; /** Label containng the keys fingerprint */ + QLabel* usageVarLabel; + QLabel* masterKeyExistVarLabel; + + private slots: + + void slotAddSubkey(); + + void slotRefreshSubkeyList(); + + void slotRefreshSubkeyDetail(); + + void slotEditSubkey(); + + void slotRevokeSubkey(); + + void slotRefreshKeyInfo(); + + protected: + void contextMenuEvent(QContextMenuEvent* event) override; +}; + +} // namespace GpgFrontend::UI + +#endif // GPGFRONTEND_KEYPAIRSUBKEYTAB_H diff --git a/src/ui/keypair_details/KeyPairUIDTab.cpp b/src/ui/keypair_details/KeyPairUIDTab.cpp index 2954aadb..3d56699a 100644 --- a/src/ui/keypair_details/KeyPairUIDTab.cpp +++ b/src/ui/keypair_details/KeyPairUIDTab.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -24,488 +24,511 @@ #include "ui/keypair_details/KeyPairUIDTab.h" -KeyPairUIDTab::KeyPairUIDTab(GpgME::GpgContext *ctx, const GpgKey &key, QWidget *parent) : QWidget(parent), mKey(key) { +#include "gpg/function/GpgKeyGetter.h" +#include "gpg/function/GpgKeyManager.h" +#include "gpg/function/UidOperator.h" +#include "ui/SignalStation.h" - mCtx = ctx; +namespace GpgFrontend::UI { - createUIDList(); - createSignList(); - createManageUIDMenu(); - createUIDPopupMenu(); - createSignPopupMenu(); +KeyPairUIDTab::KeyPairUIDTab(const std::string& key_id, QWidget* parent) + : QWidget(parent), mKey(GpgKeyGetter::GetInstance().GetKey(key_id)) { + createUIDList(); + createSignList(); + createManageUIDMenu(); + createUIDPopupMenu(); + createSignPopupMenu(); - auto uidButtonsLayout = new QGridLayout(); + auto uidButtonsLayout = new QGridLayout(); - auto addUIDButton = new QPushButton(tr("New UID")); - auto manageUIDButton = new QPushButton(tr("UID Management")); + auto addUIDButton = new QPushButton(_("New UID")); + auto manageUIDButton = new QPushButton(_("UID Management")); - if(mKey.has_master_key) { - manageUIDButton->setMenu(manageSelectedUIDMenu); - } else { - manageUIDButton->setDisabled(true); - } + if (mKey.has_master_key()) { + manageUIDButton->setMenu(manageSelectedUIDMenu); + } else { + manageUIDButton->setDisabled(true); + } + + uidButtonsLayout->addWidget(addUIDButton, 0, 1); + uidButtonsLayout->addWidget(manageUIDButton, 0, 2); - uidButtonsLayout->addWidget(addUIDButton, 0, 1); - uidButtonsLayout->addWidget(manageUIDButton, 0, 2); + auto gridLayout = new QGridLayout(); - auto gridLayout = new QGridLayout(); + gridLayout->addWidget(uidList, 0, 0); + gridLayout->addLayout(uidButtonsLayout, 1, 0); + gridLayout->setContentsMargins(0, 10, 0, 0); - gridLayout->addWidget(uidList, 0, 0); - gridLayout->addLayout(uidButtonsLayout, 1, 0); - gridLayout->setContentsMargins(0, 10, 0, 0); + auto uidGroupBox = new QGroupBox(); + uidGroupBox->setLayout(gridLayout); + uidGroupBox->setTitle(_("UIDs")); - auto uidGroupBox = new QGroupBox(); - uidGroupBox->setLayout(gridLayout); - uidGroupBox->setTitle(tr("UIDs")); + auto signGridLayout = new QGridLayout(); + signGridLayout->addWidget(sigList, 0, 0); + signGridLayout->setContentsMargins(0, 10, 0, 0); - auto signGridLayout = new QGridLayout(); - signGridLayout->addWidget(sigList, 0, 0); - signGridLayout->setContentsMargins(0, 10, 0, 0); + auto signGroupBox = new QGroupBox(); + signGroupBox->setLayout(signGridLayout); + signGroupBox->setTitle(_("Signature of Selected UID")); - auto signGroupBox = new QGroupBox(); - signGroupBox->setLayout(signGridLayout); - signGroupBox->setTitle(tr("Signature of Selected UID")); + auto vboxLayout = new QVBoxLayout(); + vboxLayout->addWidget(uidGroupBox); + vboxLayout->addWidget(signGroupBox); + vboxLayout->setContentsMargins(0, 0, 0, 0); - auto vboxLayout = new QVBoxLayout(); - vboxLayout->addWidget(uidGroupBox); - vboxLayout->addWidget(signGroupBox); - vboxLayout->setContentsMargins(0, 0, 0, 0); + connect(addUIDButton, SIGNAL(clicked(bool)), this, SLOT(slotAddUID())); + connect(uidList, SIGNAL(itemSelectionChanged()), this, + SLOT(slotRefreshSigList())); - connect(addUIDButton, SIGNAL(clicked(bool)), this, SLOT(slotAddUID())); - connect(mCtx, SIGNAL(signalKeyInfoChanged()), this, SLOT(slotRefreshUIDList())); - connect(uidList, SIGNAL(itemSelectionChanged()), this, SLOT(slotRefreshSigList())); + // Key Database Refresh + connect(SignalStation::GetInstance(), SIGNAL(KeyDatabaseRefresh()), this, + SLOT(slotRefreshKey())); - setLayout(vboxLayout); - setAttribute(Qt::WA_DeleteOnClose, true); + connect(this, SIGNAL(signalUpdateUIDInfo()), SignalStation::GetInstance(), + SIGNAL(KeyDatabaseRefresh())); - slotRefreshUIDList(); + setLayout(vboxLayout); + setAttribute(Qt::WA_DeleteOnClose, true); + + slotRefreshUIDList(); } void KeyPairUIDTab::createUIDList() { - - uidList = new QTableWidget(this); - uidList->setColumnCount(4); - uidList->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); - uidList->verticalHeader()->hide(); - uidList->setShowGrid(false); - uidList->setSelectionBehavior(QAbstractItemView::SelectRows); - uidList->setSelectionMode( QAbstractItemView::SingleSelection ); - - // tableitems not editable - uidList->setEditTriggers(QAbstractItemView::NoEditTriggers); - - // no focus (rectangle around tableitems) - // may be it should focus on whole row - uidList->setFocusPolicy(Qt::NoFocus); - uidList->setAlternatingRowColors(true); - - QStringList labels; - labels << tr("Select") << tr("Name") << tr("Email") << tr("Comment"); - uidList->setHorizontalHeaderLabels(labels); - uidList->horizontalHeader()->setStretchLastSection(true); + uidList = new QTableWidget(this); + uidList->setColumnCount(4); + uidList->horizontalHeader()->setSectionResizeMode( + QHeaderView::ResizeToContents); + uidList->verticalHeader()->hide(); + uidList->setShowGrid(false); + uidList->setSelectionBehavior(QAbstractItemView::SelectRows); + uidList->setSelectionMode(QAbstractItemView::SingleSelection); + + // tableitems not editable + uidList->setEditTriggers(QAbstractItemView::NoEditTriggers); + + // no focus (rectangle around tableitems) + // may be it should focus on whole row + uidList->setFocusPolicy(Qt::NoFocus); + uidList->setAlternatingRowColors(true); + + QStringList labels; + labels << _("Select") << _("Name") << _("Email") << _("Comment"); + uidList->setHorizontalHeaderLabels(labels); + uidList->horizontalHeader()->setStretchLastSection(true); } void KeyPairUIDTab::createSignList() { - - sigList = new QTableWidget(this); - sigList->setColumnCount(5); - sigList->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); - sigList->verticalHeader()->hide(); - sigList->setShowGrid(false); - sigList->setSelectionBehavior(QAbstractItemView::SelectRows); - - // table items not editable - sigList->setEditTriggers(QAbstractItemView::NoEditTriggers); - - // no focus (rectangle around table items) - // may be it should focus on whole row - sigList->setFocusPolicy(Qt::NoFocus); - sigList->setAlternatingRowColors(true); - - QStringList labels; - labels << tr("Key ID") << tr("Name") << tr("Email") << tr("Create Date") << tr("Expired Date"); - sigList->setHorizontalHeaderLabels(labels); - sigList->horizontalHeader()->setStretchLastSection(false); - + sigList = new QTableWidget(this); + sigList->setColumnCount(5); + sigList->horizontalHeader()->setSectionResizeMode( + QHeaderView::ResizeToContents); + sigList->verticalHeader()->hide(); + sigList->setShowGrid(false); + sigList->setSelectionBehavior(QAbstractItemView::SelectRows); + + // table items not editable + sigList->setEditTriggers(QAbstractItemView::NoEditTriggers); + + // no focus (rectangle around table items) + // may be it should focus on whole row + sigList->setFocusPolicy(Qt::NoFocus); + sigList->setAlternatingRowColors(true); + + QStringList labels; + labels << _("Key ID") << _("Name") << _("Email") << _("Create Date") + << _("Expired Date"); + sigList->setHorizontalHeaderLabels(labels); + sigList->horizontalHeader()->setStretchLastSection(false); } void KeyPairUIDTab::slotRefreshUIDList() { + int row = 0; - int row = 0; + uidList->setSelectionMode(QAbstractItemView::SingleSelection); - uidList->setSelectionMode(QAbstractItemView::SingleSelection); + this->buffered_uids.clear(); - this->buffered_uids.clear(); - - for(const auto &uid : mKey.uids) { - if(uid.invalid || uid.revoked) { - continue; - } - this->buffered_uids.push_back(&uid); + auto uids = mKey.uids(); + for (auto& uid : *uids) { + if (uid.invalid() || uid.revoked()) { + continue; } + this->buffered_uids.push_back(std::move(uid)); + } - uidList->setRowCount(buffered_uids.size()); - - for(const auto& uid : buffered_uids) { + uidList->setRowCount(buffered_uids.size()); - auto *tmp0 = new QTableWidgetItem(uid->name); - uidList->setItem(row, 1, tmp0); + for (const auto& uid : buffered_uids) { + auto* tmp0 = new QTableWidgetItem(QString::fromStdString(uid.name())); + uidList->setItem(row, 1, tmp0); - auto *tmp1 = new QTableWidgetItem(uid->email); - uidList->setItem(row, 2, tmp1); + auto* tmp1 = new QTableWidgetItem(QString::fromStdString(uid.email())); + uidList->setItem(row, 2, tmp1); - auto *tmp2 = new QTableWidgetItem(uid->comment); - uidList->setItem(row, 3, tmp2); + auto* tmp2 = new QTableWidgetItem(QString::fromStdString(uid.comment())); + uidList->setItem(row, 3, tmp2); - auto *tmp3 = new QTableWidgetItem(QString::number(row)); - tmp3->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable); - tmp3->setTextAlignment(Qt::AlignCenter); - tmp3->setCheckState(Qt::Unchecked); - uidList->setItem(row, 0, tmp3); + auto* tmp3 = new QTableWidgetItem(QString::number(row)); + tmp3->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | + Qt::ItemIsSelectable); + tmp3->setTextAlignment(Qt::AlignCenter); + tmp3->setCheckState(Qt::Unchecked); + uidList->setItem(row, 0, tmp3); - row++; + if (!row) { + for (auto i = 0; i < uidList->columnCount(); i++) { + uidList->item(row, i)->setForeground(QColor(65, 105, 255)); + } } - if(uidList->rowCount() > 0) { - uidList->selectRow(0); - } + row++; + } - slotRefreshSigList(); + if (uidList->rowCount() > 0) { + uidList->selectRow(0); + } + + slotRefreshSigList(); } void KeyPairUIDTab::slotRefreshSigList() { + int uidRow = 0, sigRow = 0; + for (const auto& uid : buffered_uids) { + // Only Show Selected UID Signatures + if (!uidList->item(uidRow++, 0)->isSelected()) { + continue; + } - int uidRow = 0, sigRow = 0; - for(const auto& uid : buffered_uids) { - - // Only Show Selected UID Signatures - if(!uidList->item(uidRow++, 0)->isSelected()) { - continue; - } - - buffered_signatures.clear(); - - for(const auto &sig : uid->signatures) { - if(sig.invalid || sig.revoked) { - continue; - } - buffered_signatures.push_back(&sig); - } - - sigList->setRowCount(buffered_signatures.size()); - - for(const auto &sig : buffered_signatures) { + buffered_signatures.clear(); + auto signatures = uid.signatures(); + for (auto& sig : *signatures) { + if (sig.invalid() || sig.revoked()) { + continue; + } + buffered_signatures.push_back(std::move(sig)); + } - auto *tmp0 = new QTableWidgetItem(sig->keyid); - sigList->setItem(sigRow, 0, tmp0); + sigList->setRowCount(buffered_signatures.size()); - if(gpgme_err_code(sig->status) == GPG_ERR_NO_PUBKEY) { - auto *tmp2 = new QTableWidgetItem("<Unknown>"); - sigList->setItem(sigRow, 1, tmp2); + for (const auto& sig : buffered_signatures) { + auto* tmp0 = new QTableWidgetItem(QString::fromStdString(sig.keyid())); + sigList->setItem(sigRow, 0, tmp0); - auto *tmp3 = new QTableWidgetItem("<Unknown>"); - sigList->setItem(sigRow, 2, tmp3); - } else { - auto *tmp2 = new QTableWidgetItem(sig->name); - sigList->setItem(sigRow, 1, tmp2); + if (gpgme_err_code(sig.status()) == GPG_ERR_NO_PUBKEY) { + auto* tmp2 = new QTableWidgetItem("<Unknown>"); + sigList->setItem(sigRow, 1, tmp2); - auto *tmp3 = new QTableWidgetItem(sig->email); - sigList->setItem(sigRow, 2, tmp3); - } + auto* tmp3 = new QTableWidgetItem("<Unknown>"); + sigList->setItem(sigRow, 2, tmp3); + } else { + auto* tmp2 = new QTableWidgetItem(QString::fromStdString(sig.name())); + sigList->setItem(sigRow, 1, tmp2); - auto *tmp4 = new QTableWidgetItem(sig->create_time.toString()); - sigList->setItem(sigRow, 3, tmp4); + auto* tmp3 = new QTableWidgetItem(QString::fromStdString(sig.email())); + sigList->setItem(sigRow, 2, tmp3); + } - auto *tmp5 = new QTableWidgetItem(sig->expire_time.toTime_t() == 0 ? tr("Never Expires") : sig->expire_time.toString()); - tmp5->setTextAlignment(Qt::AlignCenter); - sigList->setItem(sigRow, 4, tmp5); + auto* tmp4 = new QTableWidgetItem(QString::fromStdString( + boost::gregorian::to_iso_string(sig.create_time()))); + sigList->setItem(sigRow, 3, tmp4); - sigRow++; - } + auto* tmp5 = new QTableWidgetItem( + boost::posix_time::to_time_t( + boost::posix_time::ptime(sig.expire_time())) == 0 + ? _("Never Expires") + : QString::fromStdString( + boost::gregorian::to_iso_string(sig.expire_time()))); + tmp5->setTextAlignment(Qt::AlignCenter); + sigList->setItem(sigRow, 4, tmp5); - break; + sigRow++; } + + break; + } } void KeyPairUIDTab::slotAddSign() { - - QVector<GpgUID> selected_uids; - getUIDChecked(selected_uids); - - if(selected_uids.isEmpty()) { - QMessageBox::information(nullptr, - tr("Invalid Operation"), - tr("Please select one or more UIDs before doing this operation.")); - return; - } - - auto keySignDialog = new KeyUIDSignDialog(mCtx, mKey, selected_uids, this); - keySignDialog->show(); + auto selected_uids = getUIDChecked(); + + if (selected_uids->empty()) { + QMessageBox::information( + nullptr, _("Invalid Operation"), + _("Please select one or more UIDs before doing this operation.")); + return; + } + + auto keySignDialog = + new KeyUIDSignDialog(mKey, std::move(selected_uids), this); + keySignDialog->show(); } - - -void KeyPairUIDTab::getUIDChecked(QVector<GpgUID> &selected_uids) { - - auto &uids = buffered_uids; - - for (int i = 0; i < uidList->rowCount(); i++) { - if (uidList->item(i, 0)->checkState() == Qt::Checked) { - selected_uids.push_back(*uids[i]); - } - } +UIDArgsListPtr KeyPairUIDTab::getUIDChecked() { + auto selected_uids = std::make_unique<UIDArgsList>(); + for (int i = 0; i < uidList->rowCount(); i++) { + if (uidList->item(i, 0)->checkState() == Qt::Checked) + selected_uids->push_back(buffered_uids[i].uid()); + } + return selected_uids; } void KeyPairUIDTab::createManageUIDMenu() { + manageSelectedUIDMenu = new QMenu(this); - manageSelectedUIDMenu = new QMenu(this); - - auto *signUIDAct = new QAction(tr("Sign Selected UID(s)"), this); - connect(signUIDAct, SIGNAL(triggered()), this, SLOT(slotAddSign())); - auto *delUIDAct = new QAction(tr("Delete Selected UID(s)"), this); - connect(delUIDAct, SIGNAL(triggered()), this, SLOT(slotDelUID())); + auto* signUIDAct = new QAction(_("Sign Selected UID(s)"), this); + connect(signUIDAct, SIGNAL(triggered()), this, SLOT(slotAddSign())); + auto* delUIDAct = new QAction(_("Delete Selected UID(s)"), this); + connect(delUIDAct, SIGNAL(triggered()), this, SLOT(slotDelUID())); - if(mKey.has_master_key) { - manageSelectedUIDMenu->addAction(signUIDAct); - manageSelectedUIDMenu->addAction(delUIDAct); - } + if (mKey.has_master_key()) { + manageSelectedUIDMenu->addAction(signUIDAct); + manageSelectedUIDMenu->addAction(delUIDAct); + } } void KeyPairUIDTab::slotAddUID() { - auto keyNewUIDDialog = new KeyNewUIDDialog(mCtx, mKey, this); - connect(keyNewUIDDialog, SIGNAL(finished(int)), this, SLOT(slotAddUIDResult(int))); - connect(keyNewUIDDialog, SIGNAL(finished(int)), keyNewUIDDialog, SLOT(deleteLater())); - keyNewUIDDialog->show(); + auto keyNewUIDDialog = new KeyNewUIDDialog(mKey.id(), this); + connect(keyNewUIDDialog, SIGNAL(finished(int)), this, + SLOT(slotAddUIDResult(int))); + connect(keyNewUIDDialog, SIGNAL(finished(int)), keyNewUIDDialog, + SLOT(deleteLater())); + keyNewUIDDialog->show(); } void KeyPairUIDTab::slotAddUIDResult(int result) { - if(result == 1) { - QMessageBox::information(nullptr, - tr("Successful Operation"), - tr("Successfully added a new UID.")); - } else if (result == -1) { - QMessageBox::critical(nullptr, - tr("Operation Failed"), - tr("An error occurred during the operation.")); - } + if (result == 1) { + QMessageBox::information(nullptr, _("Successful Operation"), + _("Successfully added a new UID.")); + } else if (result == -1) { + QMessageBox::critical(nullptr, _("Operation Failed"), + _("An error occurred during the operation.")); + } } void KeyPairUIDTab::slotDelUID() { - - QVector<GpgUID> selected_uids; - getUIDChecked(selected_uids); - - if(selected_uids.isEmpty()) { - QMessageBox::information(nullptr, - tr("Invalid Operation"), - tr("Please select one or more UIDs before doing this operation.")); - return; - } - - QString keynames; - for (const auto &uid : selected_uids) { - keynames.append(uid.name); - keynames.append("<i> <"); - keynames.append(uid.email); - keynames.append("> </i><br/>"); - } - - int ret = QMessageBox::warning(this, tr("Deleting UIDs"), - "<b>"+tr("Are you sure that you want to delete the following uids?")+"</b><br/><br/>"+keynames+ - +"<br/>"+tr("The action can not be undone."), - QMessageBox::No | QMessageBox::Yes); - - - bool if_success = true; - - if (ret == QMessageBox::Yes) { - for(const auto &uid : selected_uids) { - if(!mCtx->revUID(mKey, uid)) { - if_success = false; - } - } - - if(!if_success) { - QMessageBox::critical(nullptr, - tr("Operation Failed"), - tr("An error occurred during the operation.")); - } - + auto selected_uids = getUIDChecked(); + + if (selected_uids->empty()) { + QMessageBox::information( + nullptr, _("Invalid Operation"), + _("Please select one or more UIDs before doing this operation.")); + return; + } + + QString keynames; + for (auto& uid : *selected_uids) { + keynames.append(QString::fromStdString(uid)); + keynames.append("<br/>"); + } + + int ret = QMessageBox::warning( + this, _("Deleting UIDs"), + "<b>" + + QString( + _("Are you sure that you want to delete the following UIDs?")) + + "</b><br/><br/>" + keynames + +"<br/>" + + _("The action can not be undone."), + QMessageBox::No | QMessageBox::Yes); + + if (ret == QMessageBox::Yes) { + for (const auto& uid : *selected_uids) { + LOG(INFO) << "KeyPairUIDTab::slotDelUID UID" << uid; + if (!UidOperator::GetInstance().revUID(mKey, uid)) { + QMessageBox::critical( + nullptr, _("Operation Failed"), + QString(_("An error occurred during the delete %1 operation.")) + .arg(uid.c_str())); + } } + emit signalUpdateUIDInfo(); + } } void KeyPairUIDTab::slotSetPrimaryUID() { - - GpgUID selected_uid; - - if(!getUIDSelected(selected_uid)) { - auto emptyUIDMsg = new QMessageBox(); - emptyUIDMsg->setText("Please select one UID before doing this operation."); - emptyUIDMsg->exec(); - return; - } - - QString keynames; - - keynames.append(selected_uid.name); - keynames.append("<i> <"); - keynames.append(selected_uid.email); - keynames.append("> </i><br/>"); - - int ret = QMessageBox::warning(this, tr("Set Primary UID"), - "<b>"+tr("Are you sure that you want to set the Primary UID to?")+"</b><br/><br/>"+keynames+ - +"<br/>"+tr("The action can not be undone."), - QMessageBox::No | QMessageBox::Yes); - - if (ret == QMessageBox::Yes) { - if(!mCtx->setPrimaryUID(mKey, selected_uid)) { - QMessageBox::critical(nullptr, - tr("Operation Failed"), - tr("An error occurred during the operation.")); - } + auto selected_uids = getUIDSelected(); + + if (selected_uids->empty()) { + auto emptyUIDMsg = new QMessageBox(); + emptyUIDMsg->setText("Please select one UID before doing this operation."); + emptyUIDMsg->exec(); + return; + } + + QString keynames; + + keynames.append(QString::fromStdString(selected_uids->front())); + keynames.append("<br/>"); + + int ret = QMessageBox::warning( + this, _("Set Primary UID"), + "<b>" + + QString(_("Are you sure that you want to set the Primary UID to?")) + + "</b><br/><br/>" + keynames + +"<br/>" + + _("The action can not be undone."), + QMessageBox::No | QMessageBox::Yes); + + if (ret == QMessageBox::Yes) { + if (!UidOperator::GetInstance().setPrimaryUID(mKey, + selected_uids->front())) { + QMessageBox::critical(nullptr, _("Operation Failed"), + _("An error occurred during the operation.")); + } else { + emit signalUpdateUIDInfo(); } + } } -bool KeyPairUIDTab::getUIDSelected(GpgUID &uid) { - auto &uids = buffered_uids; - for (int i = 0; i < uidList->rowCount(); i++) { - if (uidList->item(i, 0)->isSelected()) { - uid = *uids[i]; - return true; - } +UIDArgsListPtr KeyPairUIDTab::getUIDSelected() { + auto uids = std::make_unique<UIDArgsList>(); + for (int i = 0; i < uidList->rowCount(); i++) { + if (uidList->item(i, 0)->isSelected()) { + uids->push_back(buffered_uids[i].uid()); } - return false; + } + return uids; } -bool KeyPairUIDTab::getSignSelected(GpgKeySignature &signature) { - auto &signatures = buffered_signatures; - for (int i = 0; i < sigList->rowCount(); i++) { - if (sigList->item(i, 0)->isSelected()) { - signature = *signatures[i]; - return true; - } +SignIdArgsListPtr KeyPairUIDTab::getSignSelected() { + auto signatures = std::make_unique<SignIdArgsList>(); + for (int i = 0; i < sigList->rowCount(); i++) { + if (sigList->item(i, 0)->isSelected()) { + auto& sign = buffered_signatures[i]; + signatures->push_back({sign.keyid(), sign.uid()}); } - return false; + } + return signatures; } void KeyPairUIDTab::createUIDPopupMenu() { - - uidPopupMenu = new QMenu(this); - - auto *serPrimaryUIDAct = new QAction(tr("Set As Primary"), this); - connect(serPrimaryUIDAct, SIGNAL(triggered()), this, SLOT(slotSetPrimaryUID())); - auto *signUIDAct = new QAction(tr("Sign UID"), this); - connect(signUIDAct, SIGNAL(triggered()), this, SLOT(slotAddSignSingle())); - auto *delUIDAct = new QAction(tr("Delete UID"), this); - connect(delUIDAct, SIGNAL(triggered()), this, SLOT(slotDelUIDSingle())); - - if(mKey.has_master_key) { - uidPopupMenu->addAction(serPrimaryUIDAct); - uidPopupMenu->addAction(signUIDAct); - uidPopupMenu->addAction(delUIDAct); - } + uidPopupMenu = new QMenu(this); + + auto* serPrimaryUIDAct = new QAction(_("Set As Primary"), this); + connect(serPrimaryUIDAct, SIGNAL(triggered()), this, + SLOT(slotSetPrimaryUID())); + auto* signUIDAct = new QAction(_("Sign UID"), this); + connect(signUIDAct, SIGNAL(triggered()), this, SLOT(slotAddSignSingle())); + auto* delUIDAct = new QAction(_("Delete UID"), this); + connect(delUIDAct, SIGNAL(triggered()), this, SLOT(slotDelUIDSingle())); + + if (mKey.has_master_key()) { + uidPopupMenu->addAction(serPrimaryUIDAct); + uidPopupMenu->addAction(signUIDAct); + uidPopupMenu->addAction(delUIDAct); + } } -void KeyPairUIDTab::contextMenuEvent(QContextMenuEvent *event) { - if (uidList->selectedItems().length() > 0 && sigList->selectedItems().isEmpty()) { - uidPopupMenu->exec(event->globalPos()); - } +void KeyPairUIDTab::contextMenuEvent(QContextMenuEvent* event) { + if (uidList->selectedItems().length() > 0 && + sigList->selectedItems().isEmpty()) { + uidPopupMenu->exec(event->globalPos()); + } - if (!sigList->selectedItems().isEmpty()) { - signPopupMenu->exec(event->globalPos()); - } + if (!sigList->selectedItems().isEmpty()) { + signPopupMenu->exec(event->globalPos()); + } } void KeyPairUIDTab::slotAddSignSingle() { - - GpgUID selected_uid; - - if(!getUIDSelected(selected_uid)) { - QMessageBox::information(nullptr, - tr("Invalid Operation"), - tr("Please select one UID before doing this operation.")); - return; - } - - auto selected_uids = QVector<GpgUID>({selected_uid }); - auto keySignDialog = new KeyUIDSignDialog(mCtx, mKey, selected_uids, this); - keySignDialog->show(); + auto selected_uids = getUIDSelected(); + + if (selected_uids->empty()) { + QMessageBox::information( + nullptr, _("Invalid Operation"), + _("Please select one UID before doing this operation.")); + return; + } + + auto keySignDialog = + new KeyUIDSignDialog(mKey, std::move(selected_uids), this); + keySignDialog->show(); } void KeyPairUIDTab::slotDelUIDSingle() { - GpgUID selected_uid; - - if(!getUIDSelected(selected_uid)) { - QMessageBox::information(nullptr, - tr("Invalid Operation"), - tr("Please select one UID before doing this operation.")); - return; - } - - QString keynames; - - keynames.append(selected_uid.name); - keynames.append("<i> <"); - keynames.append(selected_uid.email); - keynames.append("> </i><br/>"); - - int ret = QMessageBox::warning(this, tr("Deleting UID"), - "<b>"+tr("Are you sure that you want to delete the following uid?")+"</b><br/><br/>"+keynames+ - +"<br/>"+tr("The action can not be undone."), - QMessageBox::No | QMessageBox::Yes); - - if (ret == QMessageBox::Yes) { - if(!mCtx->revUID(mKey, selected_uid)) { - QMessageBox::critical(nullptr, - tr("Operation Failed"), - tr("An error occurred during the operation.")); - } + auto selected_uids = getUIDSelected(); + if (selected_uids->empty()) { + QMessageBox::information( + nullptr, _("Invalid Operation"), + _("Please select one UID before doing this operation.")); + return; + } + + QString keynames; + + keynames.append(QString::fromStdString(selected_uids->front())); + keynames.append("<br/>"); + + int ret = QMessageBox::warning( + this, _("Deleting UID"), + "<b>" + + QString( + _("Are you sure that you want to delete the following uid?")) + + "</b><br/><br/>" + keynames + +"<br/>" + + _("The action can not be undone."), + QMessageBox::No | QMessageBox::Yes); + + if (ret == QMessageBox::Yes) { + if (!UidOperator::GetInstance().revUID(mKey, selected_uids->front())) { + QMessageBox::critical(nullptr, _("Operation Failed"), + _("An error occurred during the operation.")); + } else { + emit signalUpdateUIDInfo(); } + } } void KeyPairUIDTab::createSignPopupMenu() { - signPopupMenu = new QMenu(this); + signPopupMenu = new QMenu(this); - auto *delSignAct = new QAction(tr("Delete(Revoke) Key Signature"), this); - connect(delSignAct, SIGNAL(triggered()), this, SLOT(slotDelSign())); + auto* delSignAct = new QAction(_("Delete(Revoke) Key Signature"), this); + connect(delSignAct, SIGNAL(triggered()), this, SLOT(slotDelSign())); - signPopupMenu->addAction(delSignAct); + signPopupMenu->addAction(delSignAct); } void KeyPairUIDTab::slotDelSign() { - GpgKeySignature selected_sign; - - if(!getSignSelected(selected_sign)) { - QMessageBox::information(nullptr, - tr("Invalid Operation"), - tr("Please select one Key Signature before doing this operation.")); - return; - } - - if(gpgme_err_code(selected_sign.status) == GPG_ERR_NO_PUBKEY) { - QMessageBox::critical(nullptr, - tr("Invalid Operation"), - tr("To delete the signature, you need to have its corresponding public key in the local database.")); - return; - } - - QString keynames; - - keynames.append(selected_sign.name); - keynames.append("<i> <"); - keynames.append(selected_sign.email); - keynames.append("> </i><br/>"); - - int ret = QMessageBox::warning(this, tr("Deleting Key Signature"), - "<b>"+tr("Are you sure that you want to delete the following signature?")+"</b><br/><br/>"+keynames+ - +"<br/>"+tr("The action can not be undone."), - QMessageBox::No | QMessageBox::Yes); - - if (ret == QMessageBox::Yes) { - if(!mCtx->revSign(mKey, selected_sign)) { - QMessageBox::critical(nullptr, - tr("Operation Failed"), - tr("An error occurred during the operation.")); - } + auto selected_signs = getSignSelected(); + if (selected_signs->empty()) { + QMessageBox::information( + nullptr, _("Invalid Operation"), + _("Please select one Key Signature before doing this operation.")); + return; + } + + if (!GpgKeyGetter::GetInstance() + .GetKey(selected_signs->front().first) + .good()) { + QMessageBox::critical( + nullptr, _("Invalid Operation"), + _("To delete the signature, you need to have its corresponding public " + "key in the local database.")); + return; + } + + QString keynames; + + keynames.append(QString::fromStdString(selected_signs->front().second)); + keynames.append("<br/>"); + + int ret = + QMessageBox::warning(this, _("Deleting Key Signature"), + "<b>" + + QString(_("Are you sure that you want to delete " + "the following signature?")) + + "</b><br/><br/>" + keynames + +"<br/>" + + _("The action can not be undone."), + QMessageBox::No | QMessageBox::Yes); + + if (ret == QMessageBox::Yes) { + if (!GpgKeyManager::GetInstance().revSign(mKey, selected_signs)) { + QMessageBox::critical(nullptr, _("Operation Failed"), + _("An error occurred during the operation.")); } + } } +void KeyPairUIDTab::slotRefreshKey() { + this->mKey = GpgKeyGetter::GetInstance().GetKey(this->mKey.id()); + this->slotRefreshUIDList(); + this->slotRefreshSigList(); +} + +} // namespace GpgFrontend::UI diff --git a/src/ui/keypair_details/KeyPairUIDTab.h b/src/ui/keypair_details/KeyPairUIDTab.h new file mode 100644 index 00000000..6dece8d5 --- /dev/null +++ b/src/ui/keypair_details/KeyPairUIDTab.h @@ -0,0 +1,100 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_KEYPAIRUIDTAB_H +#define GPGFRONTEND_KEYPAIRUIDTAB_H + +#include "KeyNewUIDDialog.h" +#include "KeyUIDSignDialog.h" +#include "gpg/GpgContext.h" +#include "ui/GpgFrontendUI.h" + +namespace GpgFrontend::UI { + +class KeyPairUIDTab : public QWidget { + Q_OBJECT + + public: + KeyPairUIDTab(const std::string& key_id, QWidget* parent); + + signals: + void signalUpdateUIDInfo(); + + private: + GpgKey mKey; + QTableWidget* uidList{}; + QTableWidget* sigList{}; + QMenu* manageSelectedUIDMenu{}; + QMenu* uidPopupMenu{}; + QMenu* signPopupMenu{}; + std::vector<GpgUID> buffered_uids; + std::vector<GpgKeySignature> buffered_signatures; + + void createUIDList(); + + void createSignList(); + + void createManageUIDMenu(); + + void createUIDPopupMenu(); + + void createSignPopupMenu(); + + UIDArgsListPtr getUIDChecked(); + + UIDArgsListPtr getUIDSelected(); + + SignIdArgsListPtr getSignSelected(); + + private slots: + + void slotRefreshUIDList(); + + void slotRefreshSigList(); + + void slotAddSign(); + + void slotAddSignSingle(); + + void slotAddUID(); + + void slotDelUID(); + + void slotDelUIDSingle(); + + void slotSetPrimaryUID(); + + void slotDelSign(); + + void slotRefreshKey(); + + static void slotAddUIDResult(int result); + + protected: + void contextMenuEvent(QContextMenuEvent* event) override; +}; + +} // namespace GpgFrontend::UI + +#endif // GPGFRONTEND_KEYPAIRUIDTAB_H diff --git a/src/ui/keypair_details/KeySetExpireDateDialog.cpp b/src/ui/keypair_details/KeySetExpireDateDialog.cpp index f76fa3ab..d197a76b 100644 --- a/src/ui/keypair_details/KeySetExpireDateDialog.cpp +++ b/src/ui/keypair_details/KeySetExpireDateDialog.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -24,51 +24,99 @@ #include "ui/keypair_details/KeySetExpireDateDialog.h" -KeySetExpireDateDialog::KeySetExpireDateDialog(GpgME::GpgContext *ctx, const GpgKey &key, const GpgSubKey *subkey, QWidget *parent) : -QDialog(parent), mKey(key), mSubkey(subkey), mCtx(ctx) { - - QDateTime maxDateTime = QDateTime::currentDateTime().addYears(2); - dateTimeEdit = new QDateTimeEdit(maxDateTime); - dateTimeEdit->setMinimumDateTime(QDateTime::currentDateTime().addSecs(1)); - dateTimeEdit->setMaximumDateTime(maxDateTime); - nonExpiredCheck = new QCheckBox(); - nonExpiredCheck->setTristate(false); - confirmButton = new QPushButton(tr("Confirm")); - - auto *gridLayout = new QGridLayout(); - gridLayout->addWidget(dateTimeEdit, 0, 0, 1, 2); - gridLayout->addWidget(nonExpiredCheck, 0, 2, 1, 1, Qt::AlignRight); - gridLayout->addWidget(new QLabel(tr("Never Expire")), 0, 3); - gridLayout->addWidget(confirmButton, 1, 3); - - connect(nonExpiredCheck, SIGNAL(stateChanged(int)), this, SLOT(slotNonExpiredChecked(int))); - connect(confirmButton, SIGNAL(clicked(bool)), this, SLOT(slotConfirm())); - - this->setLayout(gridLayout); - this->setWindowTitle("Edit Expire Datetime"); - this->setModal(true); - this->setAttribute(Qt::WA_DeleteOnClose, true); +#include <utility> + +#include "gpg/function/GpgKeyGetter.h" +#include "gpg/function/GpgKeyOpera.h" +#include "ui/SignalStation.h" + +namespace GpgFrontend::UI { + +KeySetExpireDateDialog::KeySetExpireDateDialog(const KeyId& key_id, + QWidget* parent) + : QDialog(parent), mKey(GpgKeyGetter::GetInstance().GetKey(key_id)) { + init(); +} + +KeySetExpireDateDialog::KeySetExpireDateDialog(const KeyId& key_id, + std::string subkey_fpr, + QWidget* parent) + : QDialog(parent), + mKey(GpgKeyGetter::GetInstance().GetKey(key_id)), + mSubkey(std::move(subkey_fpr)) { + init(); } void KeySetExpireDateDialog::slotConfirm() { - QDateTime *expires = nullptr; - if(this->nonExpiredCheck->checkState() == Qt::Unchecked) { - expires = new QDateTime(this->dateTimeEdit->dateTime()); - } - - if(!mCtx->setExpire(mKey, mSubkey, expires)) { - QMessageBox::critical(nullptr, - tr("Operation Failed"), - tr("An error occurred during the operation.")); - } - delete expires; - this->close(); + LOG(INFO) << "KeySetExpireDateDialog::slotConfirm Called"; + + std::unique_ptr<boost::gregorian::date> expires = nullptr; + if (this->nonExpiredCheck->checkState() == Qt::Unchecked) { + expires = std::make_unique<boost::gregorian::date>( + boost::posix_time::from_time_t( + this->dateTimeEdit->dateTime().toTime_t()) + .date()); + LOG(INFO) << "KeySetExpireDateDialog::slotConfirm" << mKey.id() << mSubkey + << *expires; + } else { + LOG(INFO) << "KeySetExpireDateDialog::slotConfirm" << mKey.id() << mSubkey + << "Non Expired"; + } + + auto err = GpgKeyOpera::GetInstance().SetExpire(mKey, mSubkey, expires); + + if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) { + auto* msg_box = new QMessageBox(nullptr); + msg_box->setAttribute(Qt::WA_DeleteOnClose); + msg_box->setStandardButtons(QMessageBox::Ok); + msg_box->setWindowTitle(_("Success")); + msg_box->setText(_("The expire date of the key pair has been updated.")); + msg_box->setModal(false); + msg_box->open(); + + emit signalKeyExpireDateUpdated(); + + } else { + QMessageBox::critical(this, _("Failure"), _(gpgme_strerror(err))); + } + + this->close(); +} + +void KeySetExpireDateDialog::init() { + QDateTime maxDateTime = QDateTime::currentDateTime().addYears(2); + dateTimeEdit = new QDateTimeEdit(maxDateTime); + dateTimeEdit->setMinimumDateTime(QDateTime::currentDateTime().addSecs(1)); + dateTimeEdit->setMaximumDateTime(maxDateTime); + nonExpiredCheck = new QCheckBox(); + nonExpiredCheck->setTristate(false); + confirmButton = new QPushButton(_("Confirm")); + + auto* gridLayout = new QGridLayout(); + gridLayout->addWidget(dateTimeEdit, 0, 0, 1, 2); + gridLayout->addWidget(nonExpiredCheck, 0, 2, 1, 1, Qt::AlignRight); + gridLayout->addWidget(new QLabel(_("Never Expire")), 0, 3); + gridLayout->addWidget(confirmButton, 1, 3); + + connect(nonExpiredCheck, SIGNAL(stateChanged(int)), this, + SLOT(slotNonExpiredChecked(int))); + connect(confirmButton, SIGNAL(clicked(bool)), this, SLOT(slotConfirm())); + + this->setLayout(gridLayout); + this->setWindowTitle("Edit Expire Datetime"); + this->setModal(true); + this->setAttribute(Qt::WA_DeleteOnClose, true); + + connect(this, SIGNAL(signalKeyExpireDateUpdated()), + SignalStation::GetInstance(), SIGNAL(KeyDatabaseRefresh())); } void KeySetExpireDateDialog::slotNonExpiredChecked(int state) { - if(state == 0) { - this->dateTimeEdit->setDisabled(false); - } else { - this->dateTimeEdit->setDisabled(true); - } + if (state == 0) { + this->dateTimeEdit->setDisabled(false); + } else { + this->dateTimeEdit->setDisabled(true); + } } + +} // namespace GpgFrontend::UI diff --git a/src/ui/keypair_details/KeySetExpireDateDialog.h b/src/ui/keypair_details/KeySetExpireDateDialog.h new file mode 100644 index 00000000..37a7f7e4 --- /dev/null +++ b/src/ui/keypair_details/KeySetExpireDateDialog.h @@ -0,0 +1,64 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_KEYSETEXPIREDATEDIALOG_H +#define GPGFRONTEND_KEYSETEXPIREDATEDIALOG_H + +#include "gpg/GpgContext.h" +#include "gpg/model/GpgKey.h" +#include "gpg/model/GpgSubKey.h" +#include "ui/GpgFrontendUI.h" + +namespace GpgFrontend::UI { + +class KeySetExpireDateDialog : public QDialog { + Q_OBJECT + public: + explicit KeySetExpireDateDialog(const KeyId& key_id, + QWidget* parent = nullptr); + + explicit KeySetExpireDateDialog(const KeyId& key_id, std::string subkey_fpr, + QWidget* parent = nullptr); + + signals: + void signalKeyExpireDateUpdated(); + + private: + void init(); + + const GpgKey mKey; + const SubkeyId mSubkey; + + QDateTimeEdit* dateTimeEdit{}; + QPushButton* confirmButton{}; + QCheckBox* nonExpiredCheck{}; + + private slots: + void slotConfirm(); + void slotNonExpiredChecked(int state); +}; + +} // namespace GpgFrontend::UI + +#endif // GPGFRONTEND_KEYSETEXPIREDATEDIALOG_H diff --git a/src/ui/keypair_details/KeyUIDSignDialog.cpp b/src/ui/keypair_details/KeyUIDSignDialog.cpp index 9232cfce..6cce116b 100644 --- a/src/ui/keypair_details/KeyUIDSignDialog.cpp +++ b/src/ui/keypair_details/KeyUIDSignDialog.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -24,88 +24,105 @@ #include "ui/keypair_details/KeyUIDSignDialog.h" -KeyUIDSignDialog::KeyUIDSignDialog(GpgME::GpgContext *ctx, const GpgKey &key, const QVector<GpgUID> &uid, QWidget *parent) : - mKey(key), mCtx(ctx), mUids(uid), QDialog(parent) { - - mKeyList = new KeyList(ctx, - KeyListRow::ONLY_SECRET_KEY, - KeyListColumn::NAME | KeyListColumn::EmailAddress, - this); - - mKeyList->setFilter([](const GpgKey &key) -> bool { - if(key.disabled || !key.can_certify || !key.has_master_key || key.expired || key.revoked) return false; - else return true; - }); - mKeyList->setExcludeKeys({key.id}); - mKeyList->slotRefresh(); - - signKeyButton = new QPushButton("Sign"); - - /** - * A DateTime after 5 Years is recommend. - */ - expiresEdit = new QDateTimeEdit(QDateTime::currentDateTime().addYears(5)); - expiresEdit->setMinimumDateTime(QDateTime::currentDateTime()); - - /** - * Note further that the OpenPGP protocol uses 32 bit values for timestamps - * and thus can only encode dates up to the year 2106. - */ - expiresEdit->setMaximumDate(QDate(2106, 1, 1)); - - nonExpireCheck = new QCheckBox("Non Expired"); - nonExpireCheck->setTristate(false); - - connect(nonExpireCheck, &QCheckBox::stateChanged, this, [this] (int state) -> void { - if(state == 0) - expiresEdit->setDisabled(false); - else - expiresEdit->setDisabled(true); - }); - - auto layout = new QGridLayout(); - - auto timeLayout = new QGridLayout(); - - layout->addWidget(mKeyList, 0, 0); - layout->addWidget(signKeyButton, 2, 0, Qt::AlignRight); - timeLayout->addWidget(new QLabel(tr("Expire Date")), 0, 0); - timeLayout->addWidget(expiresEdit, 0, 1); - timeLayout->addWidget(nonExpireCheck, 0, 2); - layout->addLayout(timeLayout, 1, 0); - - connect(signKeyButton, SIGNAL(clicked(bool)), this, SLOT(slotSignKey(bool))); - - this->setLayout(layout); - this->setModal(true); - this->setWindowTitle(tr("Sign For Key's UID(s)")); - this->adjustSize(); - - setAttribute(Qt::WA_DeleteOnClose, true); +#include "gpg/function/GpgKeyGetter.h" +#include "gpg/function/GpgKeyManager.h" +#include "ui/SignalStation.h" + +namespace GpgFrontend::UI { + +KeyUIDSignDialog::KeyUIDSignDialog(const GpgKey& key, UIDArgsListPtr uid, + QWidget* parent) + : QDialog(parent), mUids(std::move(uid)), mKey(key) { + mKeyList = + new KeyList(KeyListRow::ONLY_SECRET_KEY, + KeyListColumn::NAME | KeyListColumn::EmailAddress, this); + + mKeyList->setFilter([](const GpgKey& key) -> bool { + if (key.disabled() || !key.can_certify() || !key.has_master_key() || + key.expired() || key.revoked()) + return false; + else + return true; + }); + mKeyList->setExcludeKeys({key.id()}); + mKeyList->slotRefresh(); + + signKeyButton = new QPushButton("Sign"); + + /** + * A DateTime after 5 Years is recommend. + */ + expiresEdit = new QDateTimeEdit(QDateTime::currentDateTime().addYears(5)); + expiresEdit->setMinimumDateTime(QDateTime::currentDateTime()); + + /** + * Note further that the OpenPGP protocol uses 32 bit values for timestamps + * and thus can only encode dates up to the year 2106. + */ + expiresEdit->setMaximumDate(QDate(2106, 1, 1)); + + nonExpireCheck = new QCheckBox("Non Expired"); + nonExpireCheck->setTristate(false); + + connect(nonExpireCheck, &QCheckBox::stateChanged, this, + [this](int state) -> void { + if (state == 0) + expiresEdit->setDisabled(false); + else + expiresEdit->setDisabled(true); + }); + + auto layout = new QGridLayout(); + + auto timeLayout = new QGridLayout(); + + layout->addWidget(mKeyList, 0, 0); + layout->addWidget(signKeyButton, 2, 0, Qt::AlignRight); + timeLayout->addWidget(new QLabel(_("Expire Date")), 0, 0); + timeLayout->addWidget(expiresEdit, 0, 1); + timeLayout->addWidget(nonExpireCheck, 0, 2); + layout->addLayout(timeLayout, 1, 0); + + connect(signKeyButton, SIGNAL(clicked(bool)), this, SLOT(slotSignKey(bool))); + + this->setLayout(layout); + this->setModal(true); + this->setWindowTitle(_("Sign For Key's UID(s)")); + this->adjustSize(); + + setAttribute(Qt::WA_DeleteOnClose, true); + + connect(this, SIGNAL(signalKeyUIDSignUpdate()), SignalStation::GetInstance(), + SIGNAL(KeyDatabaseRefresh())); } void KeyUIDSignDialog::slotSignKey(bool clicked) { - - // Set Signers - QVector<GpgKey> keys; - mKeyList->getCheckedKeys(keys); - - const auto expires = expiresEdit->dateTime(); - - for(const auto &uid : mUids) { - // Sign For mKey - if (!mCtx->signKey(mKey, keys, uid.uid, &expires)) { - QMessageBox::critical(nullptr, - tr("Unsuccessful Operation"), - QString(tr("Signature operation failed for UID ") + "%1") - .arg(uid.uid)); - } - + LOG(INFO) << "KeyUIDSignDialog::slotSignKey Called"; + + // Set Signers + auto key_ids = mKeyList->getChecked(); + auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids); + + LOG(INFO) << "KeyUIDSignDialog::slotSignKey Key Info Got"; + auto expires = std::make_unique<boost::gregorian::date>( + boost::posix_time::from_time_t(expiresEdit->dateTime().toTime_t()) + .date()); + + LOG(INFO) << "KeyUIDSignDialog::slotSignKey Sign Start"; + for (const auto& uid : *mUids) { + LOG(INFO) << "KeyUIDSignDialog::slotSignKey Sign UID" << uid; + // Sign For mKey + if (!GpgKeyManager::GetInstance().signKey(mKey, *keys, uid, expires)) { + QMessageBox::critical( + nullptr, _("Unsuccessful Operation"), + QString(_("Signature operation failed for UID %1")).arg(uid.c_str())); } + } - QMessageBox::information(nullptr, - tr("Operation Complete"), - tr("The signature operation of the UID is complete")); - - this->close(); + QMessageBox::information(nullptr, _("Operation Complete"), + _("The signature operation of the UID is complete")); + this->close(); + emit signalKeyUIDSignUpdate(); } + +} // namespace GpgFrontend::UI diff --git a/src/ui/keypair_details/KeyUIDSignDialog.h b/src/ui/keypair_details/KeyUIDSignDialog.h new file mode 100644 index 00000000..8a83977a --- /dev/null +++ b/src/ui/keypair_details/KeyUIDSignDialog.h @@ -0,0 +1,64 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_KEYUIDSIGNDIALOG_H +#define GPGFRONTEND_KEYUIDSIGNDIALOG_H + +#include "gpg/GpgContext.h" +#include "ui/GpgFrontendUI.h" +#include "ui/widgets/KeyList.h" + +namespace GpgFrontend::UI { + +class KeyUIDSignDialog : public QDialog { + Q_OBJECT + + public: + explicit KeyUIDSignDialog(const GpgKey& key, UIDArgsListPtr uid, + QWidget* parent = nullptr); + + signals: + void signalKeyUIDSignUpdate(); + + private: + KeyList* mKeyList; + + QPushButton* signKeyButton; + + QDateTimeEdit* expiresEdit; + + QCheckBox* nonExpireCheck; + + UIDArgsListPtr mUids; + + const GpgKey& mKey; + + private slots: + + void slotSignKey(bool clicked); +}; + +} // namespace GpgFrontend::UI + +#endif // GPGFRONTEND_KEYUIDSIGNDIALOG_H diff --git a/src/ui/main_window/MainWindowFileSlotFunction.cpp b/src/ui/main_window/MainWindowFileSlotFunction.cpp index e391c666..25445dcc 100644 --- a/src/ui/main_window/MainWindowFileSlotFunction.cpp +++ b/src/ui/main_window/MainWindowFileSlotFunction.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -23,588 +23,458 @@ */ #include "MainWindow.h" +#include "gpg/function/GpgFileOpera.h" +#include "gpg/function/GpgKeyGetter.h" +#include "ui/UserInterfaceUtils.h" +#include "ui/widgets/SignersPicker.h" + +namespace GpgFrontend::UI { + +bool file_pre_check(QWidget* parent, const QString& path) { + QFileInfo file_info(path); + QFileInfo path_info(file_info.absolutePath()); + if (!file_info.isFile()) { + QMessageBox::critical(parent, _("Error"), + _("Select a file before doing it.")); + return false; + } + if (!file_info.isReadable()) { + QMessageBox::critical(parent, _("Error"), + _("No permission to read this file.")); + return false; + } + if (!path_info.isWritable()) { + QMessageBox::critical(parent, _("Error"), + _("No permission to create file.")); + return false; + } + return true; +} void MainWindow::slotFileEncrypt() { - - auto fileTreeView = edit->slotCurPageFileTreeView(); - auto path = fileTreeView->getSelected(); - - QFileInfo fileInfo(path); - QFileInfo pathInfo(fileInfo.absolutePath()); - - if (!fileInfo.isFile()) { - QMessageBox::critical(this, tr("Error"), tr("Select a file before doing it.")); - return; - } - if (!fileInfo.isReadable()) { - QMessageBox::critical(this, tr("Error"), tr("No permission to read this file.")); - return; - } - if (!pathInfo.isWritable()) { - QMessageBox::critical(this, tr("Error"), tr("No permission to create file.")); - return; - } - if (QFile::exists(path + ".asc")) { - auto ret = QMessageBox::warning(this, - tr("Warning"), - tr("The target file already exists, do you need to overwrite it?"), - QMessageBox::Ok | QMessageBox::Cancel); - - if (ret == QMessageBox::Cancel) - return; - } - - QVector<GpgKey> keys; - - mKeyList->getCheckedKeys(keys); - - if (keys.empty()) { - QMessageBox::critical(this, tr("No Key Selected"), tr("No Key Selected")); - return; - } - - for (const auto &key : keys) { - if (!GpgME::GpgContext::checkIfKeyCanEncr(key)) { - QMessageBox::information(this, - tr("Invalid Operation"), - tr("The selected key contains a key that does not actually have a encrypt usage.<br/>") - + tr("<br/>For example the Following Key: <br/>") + key.uids.first().uid); - return; - - } - } - - gpgme_encrypt_result_t result; - - gpgme_error_t error; - bool if_error = false; - auto thread = QThread::create([&]() { - try { - error = GpgFileOpera::encryptFile(mCtx, keys, path, &result); - } catch (const std::runtime_error &e) { - if_error = true; - } - }); - connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); - thread->start(); - - auto *dialog = new WaitingDialog(tr("Encrypting"), this); - while (thread->isRunning()) { - QApplication::processEvents(); - } - - dialog->close(); - if (!if_error) { - auto resultAnalyse = new EncryptResultAnalyse(error, result); - auto &reportText = resultAnalyse->getResultReport(); - infoBoard->associateTabWidget(edit->tabWidget); - infoBoard->associateFileTreeView(edit->curFilePage()); - - if (resultAnalyse->getStatus() < 0) - infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL); - else if (resultAnalyse->getStatus() > 0) - infoBoard->slotRefresh(reportText, INFO_ERROR_OK); - else - infoBoard->slotRefresh(reportText, INFO_ERROR_WARN); - - delete resultAnalyse; - - fileTreeView->update(); - } else { - QMessageBox::critical(this, tr("Error"), tr("An error occurred during operation.")); - return; - } + auto fileTreeView = edit->slotCurPageFileTreeView(); + auto path = fileTreeView->getSelected(); + + if (!file_pre_check(this, path)) return; + + if (QFile::exists(path + ".asc")) { + auto ret = QMessageBox::warning( + this, _("Warning"), + _("The target file already exists, do you need to overwrite it?"), + QMessageBox::Ok | QMessageBox::Cancel); + + if (ret == QMessageBox::Cancel) return; + } + + auto key_ids = mKeyList->getChecked(); + auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids); + if (keys->empty()) { + QMessageBox::critical(this, _("No Key Selected"), _("No Key Selected")); + return; + } + + for (const auto& key : *keys) { + if (!key.CanEncrActual()) { + QMessageBox::information( + this, _("Invalid Operation"), + QString( + _("The selected key contains a key that does not actually have a " + "encrypt usage.")) + + "<br/><br/>" + _("For example the Following Key:") + " <br/>" + + QString::fromStdString(key.uids()->front().uid())); + return; + } + } + + GpgEncrResult result = nullptr; + GpgError error; + bool if_error = false; + process_operation(this, _("Encrypting"), [&]() { + try { + error = GpgFileOpera::EncryptFile(std::move(keys), path.toStdString(), + result); + } catch (const std::runtime_error& e) { + if_error = true; + } + }); + + if (!if_error) { + auto resultAnalyse = EncryptResultAnalyse(error, std::move(result)); + resultAnalyse.analyse(); + process_result_analyse(edit, infoBoard, resultAnalyse); + fileTreeView->update(); + } else { + QMessageBox::critical(this, _("Error"), + _("An error occurred during operation.")); + return; + } } void MainWindow::slotFileDecrypt() { + auto fileTreeView = edit->slotCurPageFileTreeView(); + auto path = fileTreeView->getSelected(); - auto fileTreeView = edit->slotCurPageFileTreeView(); - auto path = fileTreeView->getSelected(); + if (!file_pre_check(this, path)) return; - QFileInfo fileInfo(path); - QFileInfo pathInfo(fileInfo.absolutePath()); - if (!fileInfo.isFile()) { - QMessageBox::critical(this, tr("Error"), tr("Select a file before doing it.")); - return; - } - if (!fileInfo.isReadable()) { - QMessageBox::critical(this, tr("Error"), tr("No permission to read this file.")); - return; - } - if (!pathInfo.isWritable()) { - QMessageBox::critical(this, tr("Error"), tr("No permission to create file.")); - return; - } + QString outFileName, fileExtension = QFileInfo(path).suffix(); - QString outFileName, fileExtension = fileInfo.suffix(); + if (fileExtension == "asc" || fileExtension == "gpg") { + int pos = path.lastIndexOf(QChar('.')); + outFileName = path.left(pos); + } else { + outFileName = path + ".out"; + } - if (fileExtension == "asc" || fileExtension == "gpg") { - int pos = path.lastIndexOf(QChar('.')); - outFileName = path.left(pos); - } else { - outFileName = path + ".out"; - } + if (QFile::exists(outFileName)) { + auto ret = QMessageBox::warning( + this, _("Warning"), + _("The target file already exists, do you need to overwrite it?"), + QMessageBox::Ok | QMessageBox::Cancel); - if (QFile::exists(outFileName)) { - auto ret = QMessageBox::warning(this, - tr("Warning"), - tr("The target file already exists, do you need to overwrite it?"), - QMessageBox::Ok | QMessageBox::Cancel); + if (ret == QMessageBox::Cancel) return; + } - if (ret == QMessageBox::Cancel) - return; - } - - gpgme_decrypt_result_t result; - gpgme_error_t error; - bool if_error = false; - - auto thread = QThread::create([&]() { - try { - error = GpgFileOpera::decryptFile(mCtx, path, &result); - } catch (const std::runtime_error &e) { - if_error = true; - } - }); - connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); - thread->start(); - - auto *dialog = new WaitingDialog("Decrypting", this); - while (thread->isRunning()) { - QApplication::processEvents(); - } - - dialog->close(); - - if (!if_error) { - auto resultAnalyse = new DecryptResultAnalyse(mCtx, error, result); - auto &reportText = resultAnalyse->getResultReport(); - infoBoard->associateTabWidget(edit->tabWidget); - infoBoard->associateFileTreeView(edit->curFilePage()); - - if (resultAnalyse->getStatus() < 0) - infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL); - else if (resultAnalyse->getStatus() > 0) - infoBoard->slotRefresh(reportText, INFO_ERROR_OK); - else - infoBoard->slotRefresh(reportText, INFO_ERROR_WARN); - - delete resultAnalyse; - - fileTreeView->update(); - } else { - QMessageBox::critical(this, tr("Error"), tr("An error occurred during operation.")); - return; + GpgDecrResult result = nullptr; + gpgme_error_t error; + bool if_error = false; + process_operation(this, _("Decrypting"), [&]() { + try { + error = GpgFileOpera::DecryptFile(path.toStdString(), result); + } catch (const std::runtime_error& e) { + if_error = true; } + }); + if (!if_error) { + auto resultAnalyse = DecryptResultAnalyse(error, std::move(result)); + resultAnalyse.analyse(); + process_result_analyse(edit, infoBoard, resultAnalyse); + fileTreeView->update(); + } else { + QMessageBox::critical(this, _("Error"), + _("An error occurred during operation.")); + return; + } } void MainWindow::slotFileSign() { - - auto fileTreeView = edit->slotCurPageFileTreeView(); - auto path = fileTreeView->getSelected(); - - QFileInfo fileInfo(path); - QFileInfo pathInfo(fileInfo.absolutePath()); - - if (!fileInfo.isFile()) { - QMessageBox::critical(this, tr("Error"), tr("Select a file before doing it.")); - return; - } - if (!fileInfo.isReadable()) { - QMessageBox::critical(this, tr("Error"), tr("No permission to read this file.")); - return; - } - if (!pathInfo.isWritable()) { - QMessageBox::critical(this, tr("Error"), tr("No permission to create file.")); - return; - } - - if (QFile::exists(path + ".sig")) { - auto ret = QMessageBox::warning(this, - tr("Warning"), - tr("The target file already exists, do you need to overwrite it?"), - QMessageBox::Ok | QMessageBox::Cancel); - - if (ret == QMessageBox::Cancel) - return; - } - - QVector<GpgKey> keys; - - mKeyList->getCheckedKeys(keys); - - if (keys.empty()) { - QMessageBox::critical(this, tr("No Key Selected"), tr("No Key Selected")); - return; - } - - for (const auto &key : keys) { - if (!GpgME::GpgContext::checkIfKeyCanEncr(key)) { - QMessageBox::information(this, - tr("Invalid Operation"), - tr("The selected key contains a key that does not actually have a encrypt usage.<br/>") - + tr("<br/>For example the Following Key: <br/>") + key.uids.first().uid); - return; - - } - } - - gpgme_sign_result_t result; - gpgme_error_t error; - bool if_error = false; - - auto thread = QThread::create([&]() { - try { - error = GpgFileOpera::signFile(mCtx, keys, path, &result); - } catch (const std::runtime_error &e) { - if_error = true; - } - }); - connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); - thread->start(); - - auto *dialog = new WaitingDialog(tr("Signing"), this); - while (thread->isRunning()) { - QApplication::processEvents(); - } - - dialog->close(); - - if (!if_error) { - - auto resultAnalyse = new SignResultAnalyse(mCtx, error, result); - auto &reportText = resultAnalyse->getResultReport(); - infoBoard->associateTabWidget(edit->tabWidget); - infoBoard->associateFileTreeView(edit->curFilePage()); - - if (resultAnalyse->getStatus() < 0) - infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL); - else if (resultAnalyse->getStatus() > 0) - infoBoard->slotRefresh(reportText, INFO_ERROR_OK); - else - infoBoard->slotRefresh(reportText, INFO_ERROR_WARN); - - delete resultAnalyse; - - fileTreeView->update(); - - } else { - QMessageBox::critical(this, tr("Error"), tr("An error occurred during operation.")); - return; - } + auto fileTreeView = edit->slotCurPageFileTreeView(); + auto path = fileTreeView->getSelected(); + + if (!file_pre_check(this, path)) return; + + if (QFile::exists(path + ".sig")) { + auto ret = QMessageBox::warning( + this, _("Warning"), + _("The target file already exists, do you need to overwrite it?"), + QMessageBox::Ok | QMessageBox::Cancel); + + if (ret == QMessageBox::Cancel) return; + } + + auto key_ids = mKeyList->getChecked(); + auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids); + + if (keys->empty()) { + QMessageBox::critical(this, _("No Key Selected"), _("No Key Selected")); + return; + } + + for (const auto& key : *keys) { + if (!key.CanSignActual()) { + QMessageBox::information( + this, _("Invalid Operation"), + QString(_("The selected key contains a key that does not actually " + "have a sign usage.")) + + "<br/><br/>" + _("for example the Following Key:") + " <br/>" + + QString::fromStdString(key.uids()->front().uid())); + return; + } + } + + GpgSignResult result = nullptr; + gpgme_error_t error; + bool if_error = false; + + process_operation(this, _("Signing"), [&]() { + try { + error = + GpgFileOpera::SignFile(std::move(keys), path.toStdString(), result); + } catch (const std::runtime_error& e) { + if_error = true; + } + }); + + if (!if_error) { + auto resultAnalyse = SignResultAnalyse(error, std::move(result)); + resultAnalyse.analyse(); + process_result_analyse(edit, infoBoard, resultAnalyse); fileTreeView->update(); + } else { + QMessageBox::critical(this, _("Error"), + _("An error occurred during operation.")); + return; + } + + fileTreeView->update(); } void MainWindow::slotFileVerify() { - - auto fileTreeView = edit->slotCurPageFileTreeView(); - auto path = fileTreeView->getSelected(); - - QFileInfo fileInfo(path); - - QString signFilePath, dataFilePath; - - if (fileInfo.suffix() == "gpg") { - dataFilePath = path; - signFilePath = path; - } else if (fileInfo.suffix() == "sig") { - int pos = path.lastIndexOf(QChar('.')); - dataFilePath = path.left(pos); - signFilePath = path; - } else { - dataFilePath = path; - signFilePath = path + ".sig"; - } - - QFileInfo dataFileInfo(dataFilePath), signFileInfo(signFilePath); - - if (!dataFileInfo.isFile() || !signFileInfo.isFile()) { - QMessageBox::critical(this, tr("Error"), - tr("Please select the appropriate target file or signature file. Ensure that both are in this directory.")); - return; - } - if (!dataFileInfo.isReadable()) { - QMessageBox::critical(this, tr("Error"), tr("No permission to read target file.")); - return; - } - if (!fileInfo.isReadable()) { - QMessageBox::critical(this, tr("Error"), tr("No permission to read signature file.")); - return; - } - - gpgme_verify_result_t result; - - gpgme_error_t error; - bool if_error = false; - auto thread = QThread::create([&]() { - try { - error = GpgFileOpera::verifyFile(mCtx, dataFilePath, &result); - } catch (const std::runtime_error &e) { - if_error = true; + auto fileTreeView = edit->slotCurPageFileTreeView(); + auto path = fileTreeView->getSelected(); + + QFileInfo fileInfo(path); + + QString signFilePath, dataFilePath; + + if (fileInfo.suffix() == "gpg") { + dataFilePath = path; + signFilePath = path; + } else if (fileInfo.suffix() == "sig") { + int pos = path.lastIndexOf(QChar('.')); + dataFilePath = path.left(pos); + signFilePath = path; + } else { + dataFilePath = path; + signFilePath = path + ".sig"; + } + + QFileInfo dataFileInfo(dataFilePath), signFileInfo(signFilePath); + + if (!dataFileInfo.isFile() || !signFileInfo.isFile()) { + QMessageBox::critical( + this, _("Error"), + _("Please select the appropriate target file or signature file. " + "Ensure that both are in this directory.")); + return; + } + if (!dataFileInfo.isReadable()) { + QMessageBox::critical(this, _("Error"), + _("No permission to read target file.")); + return; + } + if (!fileInfo.isReadable()) { + QMessageBox::critical(this, _("Error"), + _("No permission to read signature file.")); + return; + } + + GpgVerifyResult result = nullptr; + gpgme_error_t error; + bool if_error = false; + process_operation(this, _("Verifying"), [&]() { + try { + error = GpgFileOpera::VerifyFile(dataFilePath.toStdString(), result); + } catch (const std::runtime_error& e) { + if_error = true; + } + }); + + if (!if_error) { + auto resultAnalyse = VerifyResultAnalyse(error, std::move(result)); + resultAnalyse.analyse(); + process_result_analyse(edit, infoBoard, resultAnalyse); + + if (resultAnalyse.getStatus() == -2) { + QMessageBox::StandardButton reply; + reply = QMessageBox::question( + this, _("Public key not found locally"), + _("There is no target public key content in local for GpgFrontend to " + "gather enough information about this Signature. Do you want to " + "import the public key from Keyserver now?"), + QMessageBox::Yes | QMessageBox::No); + if (reply == QMessageBox::Yes) { + qDebug() << "Yes was clicked"; + auto dialog = KeyServerImportDialog(true, this); + auto key_ids = std::make_unique<KeyIdArgsList>(); + auto* signature = resultAnalyse.GetSignatures(); + while (signature != nullptr) { + LOG(INFO) << "signature fpr" << signature->fpr; + key_ids->push_back(signature->fpr); + signature = signature->next; } - }); - connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); - thread->start(); + dialog.slotImport(key_ids); + dialog.show(); - auto *dialog = new WaitingDialog(tr("Verifying"), this); - while (thread->isRunning()) { - QApplication::processEvents(); + } else { + qDebug() << "Yes was *not* clicked"; + } } - dialog->close(); - - if (!if_error) { - auto resultAnalyse = new VerifyResultAnalyse(mCtx, error, result); - auto &reportText = resultAnalyse->getResultReport(); - infoBoard->associateTabWidget(edit->tabWidget); - infoBoard->associateFileTreeView(edit->curFilePage()); - - if (resultAnalyse->getStatus() < 0) - infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL); - else if (resultAnalyse->getStatus() > 0) - infoBoard->slotRefresh(reportText, INFO_ERROR_OK); - else - infoBoard->slotRefresh(reportText, INFO_ERROR_WARN); - - if (resultAnalyse->getStatus() >= 0) { - infoBoard->resetOptionActionsMenu(); - infoBoard->addOptionalAction("Show Verify Details", [this, error, result]() { - VerifyDetailsDialog(this, mCtx, mKeyList, error, result); - }); - } - delete resultAnalyse; + // if (resultAnalyse.getStatus() >= 0) { + // infoBoard->resetOptionActionsMenu(); + // infoBoard->addOptionalAction( + // "Show Verify Details", [this, error, &result]() { + // VerifyDetailsDialog(this, mKeyList, error, result); + // }); + // } - fileTreeView->update(); - } else { - QMessageBox::critical(this, tr("Error"), tr("An error occurred during operation.")); - return; - } + fileTreeView->update(); + } else { + QMessageBox::critical(this, _("Error"), + _("An error occurred during operation.")); + return; + } } void MainWindow::slotFileEncryptSign() { - auto fileTreeView = edit->slotCurPageFileTreeView(); - auto path = fileTreeView->getSelected(); - - QFileInfo fileInfo(path); - QFileInfo pathInfo(fileInfo.absolutePath()); - - if (!fileInfo.isFile()) { - QMessageBox::critical(this, tr("Error"), tr("Select a file before doing it.")); - return; - } - if (!fileInfo.isReadable()) { - QMessageBox::critical(this, tr("Error"), tr("No permission to read this file.")); - return; - } - if (!pathInfo.isWritable()) { - QMessageBox::critical(this, tr("Error"), tr("No permission to create file.")); - return; - } - if (QFile::exists(path + ".gpg")) { - auto ret = QMessageBox::warning(this, - tr("Warning"), - tr("The target file already exists, do you need to overwrite it?"), - QMessageBox::Ok | QMessageBox::Cancel); - - if (ret == QMessageBox::Cancel) - return; - } - - QVector<GpgKey> keys; + auto fileTreeView = edit->slotCurPageFileTreeView(); + auto path = fileTreeView->getSelected(); - mKeyList->getCheckedKeys(keys); + if (!file_pre_check(this, path)) return; - if (keys.empty()) { - QMessageBox::critical(this, tr("No Key Selected"), tr("No Key Selected")); - return; - } + if (QFile::exists(path + ".gpg")) { + auto ret = QMessageBox::warning( + this, _("Warning"), + _("The target file already exists, do you need to overwrite it?"), + QMessageBox::Ok | QMessageBox::Cancel); - bool can_sign = false, can_encr = false; + if (ret == QMessageBox::Cancel) return; + } - for (const auto &key : keys) { - bool key_can_sign = GpgME::GpgContext::checkIfKeyCanSign(key); - bool key_can_encr = GpgME::GpgContext::checkIfKeyCanEncr(key); + auto key_ids = mKeyList->getChecked(); + auto p_keys = GpgKeyGetter::GetInstance().GetKeys(key_ids); - if (!key_can_sign && !key_can_encr) { - QMessageBox::critical(nullptr, - tr("Invalid KeyPair"), - tr("The selected keypair cannot be used for signing and encryption at the same time.<br/>") - + tr("<br/>For example the Following Key: <br/>") + key.uids.first().uid); - return; - } + if (p_keys->empty()) { + QMessageBox::critical(this, _("No Key Selected"), _("No Key Selected")); + return; + } - if (key_can_sign) can_sign = true; - if (key_can_encr) can_encr = true; - } + for (const auto& key : *p_keys) { + bool key_can_encrypt = key.CanEncrActual(); - if (!can_encr) { - QMessageBox::critical(nullptr, - tr("Incomplete Operation"), - tr("None of the selected key pairs can provide the encryption function.")); - return; + if (!key_can_encrypt) { + QMessageBox::critical( + nullptr, _("Invalid KeyPair"), + QString(_("The selected keypair cannot be used for encryption.")) + + "<br/><br/>" + _("For example the Following Key:") + " <br/>" + + QString::fromStdString(key.uids()->front().uid())); + return; } + } - if (!can_sign) { - QMessageBox::warning(nullptr, - tr("Incomplete Operation"), - tr("None of the selected key pairs can provide the signature function.")); - } + auto signersPicker = new SignersPicker(this); + QEventLoop loop; + connect(signersPicker, SIGNAL(finished(int)), &loop, SLOT(quit())); + loop.exec(); - gpgme_encrypt_result_t encr_result = nullptr; - gpgme_sign_result_t sign_result = nullptr; + auto signer_key_ids = signersPicker->getCheckedSigners(); + auto p_signer_keys = GpgKeyGetter::GetInstance().GetKeys(signer_key_ids); - gpgme_error_t error; - bool if_error = false; + for (const auto& key : *p_keys) { + LOG(INFO) << "Keys " << key.email(); + } - auto thread = QThread::create([&]() { - try { - error = GpgFileOpera::encryptSignFile(mCtx, keys, path, &encr_result, &sign_result); - } catch (const std::runtime_error &e) { - if_error = true; - } - }); - connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); - thread->start(); + for (const auto& signer : *p_signer_keys) { + LOG(INFO) << "Signers " << signer.email(); + } - auto *dialog = new WaitingDialog(tr("Encrypting and Signing"), this); - while (thread->isRunning()) { - QApplication::processEvents(); - } - dialog->close(); + GpgEncrResult encr_result = nullptr; + GpgSignResult sign_result = nullptr; - if (!if_error) { + gpgme_error_t error; + bool if_error = false; - auto resultAnalyseEncr = new EncryptResultAnalyse(error, encr_result); - auto resultAnalyseSign = new SignResultAnalyse(mCtx, error, sign_result); - int status = std::min(resultAnalyseEncr->getStatus(), resultAnalyseSign->getStatus()); - auto reportText = resultAnalyseEncr->getResultReport() + resultAnalyseSign->getResultReport(); - - infoBoard->associateFileTreeView(edit->curFilePage()); - - if (status < 0) - infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL); - else if (status > 0) - infoBoard->slotRefresh(reportText, INFO_ERROR_OK); - else - infoBoard->slotRefresh(reportText, INFO_ERROR_WARN); + process_operation(this, _("Encrypting and Signing"), [&]() { + try { + error = GpgFileOpera::EncryptSignFile( + std::move(p_keys), std::move(p_signer_keys), path.toStdString(), + encr_result, sign_result); + } catch (const std::runtime_error& e) { + if_error = true; + } + }); - delete resultAnalyseEncr; - delete resultAnalyseSign; + if (!if_error) { + auto encrypt_res = EncryptResultAnalyse(error, std::move(encr_result)); + auto sign_res = SignResultAnalyse(error, std::move(sign_result)); + encrypt_res.analyse(); + sign_res.analyse(); + process_result_analyse(edit, infoBoard, encrypt_res, sign_res); - fileTreeView->update(); + fileTreeView->update(); - } else { - QMessageBox::critical(this, tr("Error"), tr("An error occurred during operation.")); - return; - } + } else { + QMessageBox::critical(this, _("Error"), + _("An error occurred during operation.")); + return; + } } void MainWindow::slotFileDecryptVerify() { - auto fileTreeView = edit->slotCurPageFileTreeView(); - auto path = fileTreeView->getSelected(); - - QFileInfo fileInfo(path); - QFileInfo pathInfo(fileInfo.absolutePath()); - if (!fileInfo.isFile()) { - QMessageBox::critical(this, tr("Error"), tr("Select a file(.gpg/.asc) before doing it.")); - return; - } - if (!fileInfo.isReadable()) { - QMessageBox::critical(this, tr("Error"), tr("No permission to read this file.")); - return; - } - if (!pathInfo.isWritable()) { - QMessageBox::critical(this, tr("Error"), tr("No permission to create file.")); - return; - } - - QString outFileName, fileExtension = fileInfo.suffix(); - - if (fileExtension == "asc" || fileExtension == "gpg") { - int pos = path.lastIndexOf(QChar('.')); - outFileName = path.left(pos); - } else { - outFileName = path + ".out"; - } - - gpgme_decrypt_result_t d_result = nullptr; - gpgme_verify_result_t v_result = nullptr; - - gpgme_error_t error; - bool if_error = false; - - auto thread = QThread::create([&]() { - try { - error = GpgFileOpera::decryptVerifyFile(mCtx, path, &d_result, &v_result); - } catch (const std::runtime_error &e) { - if_error = true; - } - }); - connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); - thread->start(); + auto fileTreeView = edit->slotCurPageFileTreeView(); + auto path = fileTreeView->getSelected(); + + if (!file_pre_check(this, path)) return; + + QString outFileName, fileExtension = QFileInfo(path).suffix(); + + if (fileExtension == "asc" || fileExtension == "gpg") { + int pos = path.lastIndexOf(QChar('.')); + outFileName = path.left(pos); + } else { + outFileName = path + ".out"; + } + + GpgDecrResult d_result = nullptr; + GpgVerifyResult v_result = nullptr; + gpgme_error_t error; + bool if_error = false; + process_operation(this, _("Decrypting and Verifying"), [&]() { + try { + error = GpgFileOpera::DecryptVerifyFile(path.toStdString(), d_result, + v_result); + } catch (const std::runtime_error& e) { + if_error = true; + } + }); + + if (!if_error) { + infoBoard->associateFileTreeView(edit->curFilePage()); + + auto decrypt_res = DecryptResultAnalyse(error, std::move(d_result)); + auto verify_res = VerifyResultAnalyse(error, std::move(v_result)); + decrypt_res.analyse(); + verify_res.analyse(); + process_result_analyse(edit, infoBoard, decrypt_res, verify_res); + + // if (verify_res.getStatus() >= 0) { + // infoBoard->resetOptionActionsMenu(); + // infoBoard->addOptionalAction( + // "Show Verify Details", [this, error, v_result]() { + // VerifyDetailsDialog(this, mCtx, mKeyList, error, v_result); + // }); + // } - - auto *dialog = new WaitingDialog(tr("Decrypting and Verifying"), this); - while (thread->isRunning()) { - QApplication::processEvents(); - } - dialog->close(); - - if (!if_error) { - infoBoard->associateFileTreeView(edit->curFilePage()); - - auto resultAnalyseDecrypt = new DecryptResultAnalyse(mCtx, error, d_result); - auto resultAnalyseVerify = new VerifyResultAnalyse(mCtx, error, v_result); - - int status = std::min(resultAnalyseDecrypt->getStatus(), resultAnalyseVerify->getStatus()); - auto &reportText = resultAnalyseDecrypt->getResultReport() + resultAnalyseVerify->getResultReport(); - if (status < 0) - infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL); - else if (status > 0) - infoBoard->slotRefresh(reportText, INFO_ERROR_OK); - else - infoBoard->slotRefresh(reportText, INFO_ERROR_WARN); - - if (resultAnalyseVerify->getStatus() >= 0) { - infoBoard->resetOptionActionsMenu(); - infoBoard->addOptionalAction("Show Verify Details", [this, error, v_result]() { - VerifyDetailsDialog(this, mCtx, mKeyList, error, v_result); - }); - } - delete resultAnalyseDecrypt; - delete resultAnalyseVerify; - - fileTreeView->update(); - } else { - QMessageBox::critical(this, tr("Error"), tr("An error occurred during operation.")); - return; - } + fileTreeView->update(); + } else { + QMessageBox::critical(this, _("Error"), + _("An error occurred during operation.")); + return; + } } void MainWindow::slotFileEncryptCustom() { - QStringList *keyList; - keyList = mKeyList->getChecked(); - new FileEncryptionDialog(mCtx, *keyList, FileEncryptionDialog::Encrypt, this); + new FileEncryptionDialog(mKeyList->getChecked(), + FileEncryptionDialog::Encrypt, this); } void MainWindow::slotFileDecryptCustom() { - QStringList *keyList; - keyList = mKeyList->getChecked(); - new FileEncryptionDialog(mCtx, *keyList, FileEncryptionDialog::Decrypt, this); + new FileEncryptionDialog(mKeyList->getChecked(), + FileEncryptionDialog::Decrypt, this); } void MainWindow::slotFileSignCustom() { - QStringList *keyList; - keyList = mKeyList->getChecked(); - new FileEncryptionDialog(mCtx, *keyList, FileEncryptionDialog::Sign, this); + new FileEncryptionDialog(mKeyList->getChecked(), FileEncryptionDialog::Sign, + this); } void MainWindow::slotFileVerifyCustom() { - QStringList *keyList; - keyList = mKeyList->getChecked(); - new FileEncryptionDialog(mCtx, *keyList, FileEncryptionDialog::Verify, this); + new FileEncryptionDialog(mKeyList->getChecked(), FileEncryptionDialog::Verify, + this); } + +} // namespace GpgFrontend::UI diff --git a/src/ui/main_window/MainWindowServerSlotFunction.cpp b/src/ui/main_window/MainWindowServerSlotFunction.cpp index 3a7e9f71..17491db7 100644 --- a/src/ui/main_window/MainWindowServerSlotFunction.cpp +++ b/src/ui/main_window/MainWindowServerSlotFunction.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -23,216 +23,240 @@ */ #include "MainWindow.h" -#include "server/ComUtils.h" -#include "ui/ShowCopyDialog.h" +#ifdef SERVER_SUPPORT #include "rapidjson/document.h" #include "rapidjson/prettywriter.h" +#include "server/ComUtils.h" +#endif +#include "ui/ShowCopyDialog.h" + +namespace GpgFrontend::UI { + +#ifdef SERVER_SUPPORT /** * get full size crypt text from server using short crypto text * @param shortenCryptoText short crypto text([GpgFrontend_ShortCrypto]://) * @return */ -QString MainWindow::getCryptText(const QString &shortenCryptoText) { - - QString ownKeyId = settings.value("general/ownKeyId").toString(); - - GpgKey key = mCtx->getKeyById(ownKeyId); - if (!key.good) { - QMessageBox::critical(this, tr("Invalid Own Key"), - tr("Own Key can not be use to do any operation. " - "Please go to the setting interface to select an OwnKey and get a ServiceToken.")); - return {}; - } - - auto utils = new ComUtils(this); +QString MainWindow::getCryptText(const QString& shortenCryptoText) { + QString ownKeyId = settings.value("general/ownKeyId").toString(); + + GpgKey key = mCtx->getKeyRefById(ownKeyId); + if (!key.good) { + QMessageBox::critical(this, _("Invalid Own Key"), + _("Own Key can not be use to do any operation. " + "Please go to the setting interface to select an " + "OwnKey and get a ServiceToken.")); + return {}; + } - QString serviceToken = settings.value("general/serviceToken").toString(); - if (serviceToken.isEmpty() || !utils->checkServiceTokenFormat(serviceToken)) { - QMessageBox::critical(this, tr("Error"), - tr("Please obtain a Service Token from the server in the settings.")); - return {}; - } + auto utils = new ComUtils(this); - QUrl reqUrl(utils->getUrl(ComUtils::GetFullCryptText)); - QNetworkRequest request(reqUrl); - request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); + QString serviceToken = settings.value("general/serviceToken").toString(); + if (serviceToken.isEmpty() || !utils->checkServiceTokenFormat(serviceToken)) { + QMessageBox::critical( + this, _("Error"), + _("Please obtain a Service Token from the server in the settings.")); + return {}; + } - // Sign Shorten Text - auto outSignTextBase64 = ComUtils::getSignStringBase64(mCtx, shortenCryptoText, key); + QUrl reqUrl(utils->getUrl(ComUtils::GetFullCryptText)); + QNetworkRequest request(reqUrl); + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); - rapidjson::Document doc; - doc.SetObject(); + // Sign Shorten Text + auto outSignTextBase64 = + ComUtils::getSignStringBase64(mCtx, shortenCryptoText, key); - rapidjson::Value s, t; + rapidjson::Document doc; + doc.SetObject(); - // Signature - s.SetString(outSignTextBase64.constData(), outSignTextBase64.count()); - // Service Token - const auto t_byte_array = serviceToken.toUtf8(); - t.SetString(t_byte_array.constData(), t_byte_array.count()); + rapidjson::Value s, t; - rapidjson::Document::AllocatorType &allocator = doc.GetAllocator(); + // Signature + s.SetString(outSignTextBase64.constData(), outSignTextBase64.count()); + // Service Token + const auto t_byte_array = serviceToken.toUtf8(); + t.SetString(t_byte_array.constData(), t_byte_array.count()); - doc.AddMember("signature", s, allocator); - doc.AddMember("serviceToken", t, allocator); + rapidjson::Document::AllocatorType& allocator = doc.GetAllocator(); - rapidjson::StringBuffer sb; - rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(sb); - doc.Accept(writer); + doc.AddMember("signature", s, allocator); + doc.AddMember("serviceToken", t, allocator); - QByteArray postData(sb.GetString()); - qDebug() << "postData" << QString::fromUtf8(postData); + rapidjson::StringBuffer sb; + rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(sb); + doc.Accept(writer); - QNetworkReply *reply = utils->getNetworkManager().post(request, postData); + QByteArray postData(sb.GetString()); + qDebug() << "postData" << QString::fromUtf8(postData); - auto dialog = new WaitingDialog(tr("Getting Cpt From Server"), this); - dialog->show(); + QNetworkReply* reply = utils->getNetworkManager().post(request, postData); - while (reply->isRunning()) QApplication::processEvents(); + auto dialog = new WaitingDialog(_("Getting Cpt From Server"), this); + dialog->show(); - dialog->close(); + while (reply->isRunning()) QApplication::processEvents(); - QByteArray replyData = reply->readAll().constData(); - if (utils->checkServerReply(replyData)) { - /** - * { - * "cryptoText" : ... - * "sha": ... - * "serviceToken": ... - * "date": ... - * } - */ + dialog->close(); - if (!utils->checkDataValueStr("cryptoText") - || !utils->checkDataValueStr("sha") - || !utils->checkDataValueStr("serviceToken")) { - QMessageBox::critical(this, tr("Error"), - tr("The communication content with the server does not meet the requirements")); - return {}; - } + QByteArray replyData = reply->readAll().constData(); + if (utils->checkServerReply(replyData)) { + /** + * { + * "cryptoText" : ... + * "sha": ... + * "serviceToken": ... + * "date": ... + * } + */ - auto cryptoText = utils->getDataValueStr("cryptoText"); - auto sha = utils->getDataValueStr("sha"); - auto serviceTokenFromServer = utils->getDataValueStr("serviceToken"); + if (!utils->checkDataValueStr("cryptoText") || + !utils->checkDataValueStr("sha") || + !utils->checkDataValueStr("serviceToken")) { + QMessageBox::critical(this, _("Error"), + _("The communication content with the server does " + "not meet the requirements")); + return {}; + } - QCryptographicHash sha_generator(QCryptographicHash::Sha256); - sha_generator.addData(cryptoText.toUtf8()); + auto cryptoText = utils->getDataValueStr("cryptoText"); + auto sha = utils->getDataValueStr("sha"); + auto serviceTokenFromServer = utils->getDataValueStr("serviceToken"); - if (sha_generator.result().toHex() == sha && serviceToken == serviceTokenFromServer) { - return cryptoText; - } else QMessageBox::critical(this, tr("Error"), tr("Invalid short ciphertext")); + QCryptographicHash sha_generator(QCryptographicHash::Sha256); + sha_generator.addData(cryptoText.toUtf8()); - return {}; - } + if (sha_generator.result().toHex() == sha && + serviceToken == serviceTokenFromServer) { + return cryptoText; + } else + QMessageBox::critical(this, _("Error"), _("Invalid short ciphertext")); return {}; -} + } -void MainWindow::shortenCryptText() { + return {}; +} - // gather information - QString serviceToken = settings.value("general/serviceToken").toString(); - QString ownKeyId = settings.value("general/ownKeyId").toString(); - QByteArray cryptoText = edit->curTextPage()->toPlainText().toUtf8(); +#endif - auto utils = new ComUtils(this); +#ifdef SERVER_SUPPORT - if (serviceToken.isEmpty() || !utils->checkServiceTokenFormat(serviceToken)) { - QMessageBox::critical(this, tr("Invalid Service Token"), - tr("Please go to the setting interface to get a ServiceToken.")); - return; +void MainWindow::shortenCryptText() { + // gather information + QString serviceToken = settings.value("general/serviceToken").toString(); + QString ownKeyId = settings.value("general/ownKeyId").toString(); + QByteArray cryptoText = edit->curTextPage()->toPlainText().toUtf8(); + + auto utils = new ComUtils(this); + + if (serviceToken.isEmpty() || !utils->checkServiceTokenFormat(serviceToken)) { + QMessageBox::critical( + this, _("Invalid Service Token"), + _("Please go to the setting interface to get a ServiceToken.")); + return; + } + + QUrl reqUrl(utils->getUrl(ComUtils::ShortenCryptText)); + QNetworkRequest request(reqUrl); + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); + + GpgKey key = mCtx->getKeyRefById(ownKeyId); + if (!key.good) { + QMessageBox::critical(this, _("Invalid Own Key"), + _("Own Key can not be use to do any operation.")); + return; + } + + QCryptographicHash ch(QCryptographicHash::Md5); + ch.addData(cryptoText); + QString md5 = ch.result().toHex(); + + qDebug() << "md5" << md5; + + QByteArray signText = QString("[%1][%2]").arg(serviceToken, md5).toUtf8(); + + QCryptographicHash sha(QCryptographicHash::Sha256); + sha.addData(signText); + QString shaText = sha.result().toHex(); + + qDebug() << "shaText" << shaText; + + QByteArray outSignTextBase64 = + ComUtils::getSignStringBase64(mCtx, signText, key); + + rapidjson::Value c, s, m, t; + + rapidjson::Document doc; + doc.SetObject(); + + c.SetString(cryptoText.constData(), cryptoText.count()); + auto m_byte_array = shaText.toUtf8(); + m.SetString(m_byte_array.constData(), m_byte_array.count()); + s.SetString(outSignTextBase64.constData(), outSignTextBase64.count()); + auto t_byte_array = serviceToken.toUtf8(); + t.SetString(t_byte_array.constData(), t_byte_array.count()); + + rapidjson::Document::AllocatorType& allocator = doc.GetAllocator(); + + doc.AddMember("cryptoText", c, allocator); + doc.AddMember("sha", m, allocator); + doc.AddMember("sign", s, allocator); + doc.AddMember("serviceToken", t, allocator); + + rapidjson::StringBuffer sb; + rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(sb); + doc.Accept(writer); + + QByteArray postData(sb.GetString()); + qDebug() << "postData" << QString::fromUtf8(postData); + + QNetworkReply* reply = networkAccessManager->post(request, postData); + + auto* dialog = new WaitingDialog(_("Getting Scpt From Server"), this); + dialog->show(); + while (reply->isRunning()) QApplication::processEvents(); + dialog->close(); + + if (utils->checkServerReply(reply->readAll().constData())) { + /** + * { + * "shortenText" : ... + * "md5": ... + * } + */ + + if (!utils->checkDataValueStr("shortenText") || + !utils->checkDataValueStr("md5")) { + QMessageBox::critical(this, _("Error"), + _("The communication content with the server does " + "not meet the requirements")); + return; } - QUrl reqUrl(utils->getUrl(ComUtils::ShortenCryptText)); - QNetworkRequest request(reqUrl); - request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); - - GpgKey key = mCtx->getKeyById(ownKeyId); - if (!key.good) { - QMessageBox::critical(this, tr("Invalid Own Key"), tr("Own Key can not be use to do any operation.")); - return; + QString shortenText = utils->getDataValueStr("shortenText"); + + QCryptographicHash md5_generator(QCryptographicHash::Md5); + md5_generator.addData(shortenText.toUtf8()); + if (md5_generator.result().toHex() == utils->getDataValueStr("md5")) { + auto* dialog = + new ShowCopyDialog(shortenText, + _("Notice: Use Decrypt & Verify operation to " + "decrypt this short crypto text."), + this); + dialog->show(); + } else { + QMessageBox::critical( + this, _("Error"), + _("There is a problem with the communication with the server")); + return; } - - QCryptographicHash ch(QCryptographicHash::Md5); - ch.addData(cryptoText); - QString md5 = ch.result().toHex(); - - qDebug() << "md5" << md5; - - QByteArray signText = QString("[%1][%2]").arg(serviceToken, md5).toUtf8(); - - QCryptographicHash sha(QCryptographicHash::Sha256); - sha.addData(signText); - QString shaText = sha.result().toHex(); - - qDebug() << "shaText" << shaText; - - QByteArray outSignTextBase64 = ComUtils::getSignStringBase64(mCtx, signText, key); - - rapidjson::Value c, s, m, t; - - rapidjson::Document doc; - doc.SetObject(); - - c.SetString(cryptoText.constData(), cryptoText.count()); - auto m_byte_array = shaText.toUtf8(); - m.SetString(m_byte_array.constData(), m_byte_array.count()); - s.SetString(outSignTextBase64.constData(), outSignTextBase64.count()); - auto t_byte_array = serviceToken.toUtf8(); - t.SetString(t_byte_array.constData(), t_byte_array.count()); - - rapidjson::Document::AllocatorType &allocator = doc.GetAllocator(); - - doc.AddMember("cryptoText", c, allocator); - doc.AddMember("sha", m, allocator); - doc.AddMember("sign", s, allocator); - doc.AddMember("serviceToken", t, allocator); - - rapidjson::StringBuffer sb; - rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(sb); - doc.Accept(writer); - - QByteArray postData(sb.GetString()); - qDebug() << "postData" << QString::fromUtf8(postData); - - QNetworkReply *reply = networkAccessManager->post(request, postData); - - auto *dialog = new WaitingDialog(tr("Getting Scpt From Server"), this); - dialog->show(); - while (reply->isRunning()) QApplication::processEvents(); - dialog->close(); - - if (utils->checkServerReply(reply->readAll().constData())) { - - /** - * { - * "shortenText" : ... - * "md5": ... - * } - */ - - if (!utils->checkDataValueStr("shortenText") || !utils->checkDataValueStr("md5")) { - QMessageBox::critical(this, tr("Error"), - tr("The communication content with the server does not meet the requirements")); - return; - } - - QString shortenText = utils->getDataValueStr("shortenText"); - - QCryptographicHash md5_generator(QCryptographicHash::Md5); - md5_generator.addData(shortenText.toUtf8()); - if (md5_generator.result().toHex() == utils->getDataValueStr("md5")) { - auto *dialog = new ShowCopyDialog(shortenText, - tr("Notice: Use Decrypt & Verify operation to decrypt this short crypto text."), - this); - dialog->show(); - } else { - QMessageBox::critical(this, tr("Error"), tr("There is a problem with the communication with the server")); - return; - } - } - + } } +#endif + +} // namespace GpgFrontend::UI diff --git a/src/ui/main_window/MainWindowSlotFunction.cpp b/src/ui/main_window/MainWindowSlotFunction.cpp index 501418d6..205b9440 100644 --- a/src/ui/main_window/MainWindowSlotFunction.cpp +++ b/src/ui/main_window/MainWindowSlotFunction.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -23,559 +23,542 @@ */ #include "MainWindow.h" -#include "ui/SendMailDialog.h" -#include "ui/widgets/SignersPicker.h" -#include "server/api/PubkeyUploader.h" + +#ifdef ADVANCE_SUPPORT #include "advance/UnknownSignersChecker.h" +#endif +#ifdef SERVER_SUPPORT +#include "server/api/PubkeyUploader.h" +#endif +#ifdef SMTP_SUPPORT +#include "ui/smtp/SendMailDialog.h" +#endif +#include "gpg/function/BasicOperator.h" +#include "gpg/function/GpgKeyGetter.h" +#include "gpg/function/GpgKeyImportExportor.h" +#include "ui/UserInterfaceUtils.h" +#include "ui/widgets/SignersPicker.h" + +namespace GpgFrontend::UI { /** * Encrypt Entry(Text & File) */ void MainWindow::slotEncrypt() { + if (edit->tabCount() == 0) return; - if (edit->tabCount() == 0) return; - - if (edit->slotCurPageTextEdit() != nullptr) { + if (edit->slotCurPageTextEdit() != nullptr) { + auto key_ids = mKeyList->getChecked(); - QVector<GpgKey> keys; - mKeyList->getCheckedKeys(keys); - - if (keys.count() == 0) { - QMessageBox::critical(nullptr, tr("No Key Selected"), tr("No Key Selected")); - return; - } - - for (const auto &key : keys) { - if (!GpgME::GpgContext::checkIfKeyCanEncr(key)) { - QMessageBox::information(nullptr, - tr("Invalid Operation"), - tr("The selected key contains a key that does not actually have a encrypt usage.<br/>") - + tr("<br/>For example the Following Key: <br/>") + key.uids.first().uid); - return; - - } - } - - auto tmp = QByteArray(); - - gpgme_encrypt_result_t result = nullptr; + if (key_ids->empty()) { + QMessageBox::critical(nullptr, _("No Key Selected"), + _("No Key Selected")); + return; + } - gpgme_error_t error; + auto key_getter = GpgFrontend::GpgKeyGetter::GetInstance(); + auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids); + for (const auto& key : *keys) { + if (!key.CanEncrActual()) { + QMessageBox::information( + nullptr, _("Invalid Operation"), + QString(_( + "The selected key contains a key that does not actually have a " + "encrypt usage.")) + + "<br/><br/>" + _("For example the Following Key:") + " <br/>" + + QString::fromStdString(key.uids()->front().uid())); + return; + } + } - auto thread = QThread::create([&]() { - error = mCtx->encrypt(keys, edit->curTextPage()->toPlainText().toUtf8(), &tmp, &result); + auto tmp = std::make_unique<ByteArray>(); + + GpgEncrResult result = nullptr; + GpgError error; + bool if_error = false; + process_operation(this, _("Encrypting"), [&]() { + try { + auto buffer = edit->curTextPage()->toPlainText().toUtf8().toStdString(); + error = GpgFrontend::BasicOperator::GetInstance().Encrypt( + std::move(keys), buffer, tmp, result); + } catch (const std::runtime_error& e) { + if_error = true; + } + }); + + if (!if_error) { + auto resultAnalyse = EncryptResultAnalyse(error, std::move(result)); + resultAnalyse.analyse(); + process_result_analyse(edit, infoBoard, resultAnalyse); + + if (check_gpg_error_2_err_code(error) == GPG_ERR_NO_ERROR) + edit->slotFillTextEditWithText(QString::fromStdString(*tmp)); +#ifdef SMTP_SUPPORT + // set optional actions + if (resultAnalyse.getStatus() >= 0) { + infoBoard->resetOptionActionsMenu(); + infoBoard->addOptionalAction("Send Mail", [this]() { + if (settings.value("sendMail/enable", false).toBool()) + new SendMailDialog(edit->curTextPage()->toPlainText(), this); + else { + QMessageBox::warning(nullptr, _("Function Disabled"), + _("Please go to the settings interface to " + "enable and configure this function.")); + } }); - connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); - thread->start(); - - auto *dialog = new WaitingDialog(tr("Encrypting"), this); - - while (thread->isRunning()) - QApplication::processEvents(); - - dialog->close(); - - auto resultAnalyse = new EncryptResultAnalyse(error, result); - auto &reportText = resultAnalyse->getResultReport(); - - auto tmp2 = QString(tmp); - edit->slotFillTextEditWithText(tmp2); - infoBoard->associateTextEdit(edit->curTextPage()); - - // check result analyse status - if (resultAnalyse->getStatus() < 0) - infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL); - else if (resultAnalyse->getStatus() > 0) - infoBoard->slotRefresh(reportText, INFO_ERROR_OK); - else - infoBoard->slotRefresh(reportText, INFO_ERROR_WARN); - - // set optional actions - if (resultAnalyse->getStatus() >= 0) { - infoBoard->resetOptionActionsMenu(); - infoBoard->addOptionalAction("Send Mail", [this]() { - if (settings.value("sendMail/enable", false).toBool()) - new SendMailDialog(edit->curTextPage()->toPlainText(), this); - else { - QMessageBox::warning(nullptr, - tr("Function Disabled"), - tr("Please go to the settings interface to enable and configure this function.")); - } - }); - } + } +#endif - delete resultAnalyse; - } else if (edit->slotCurPageFileTreeView() != nullptr) { - this->slotFileEncrypt(); + } else { + QMessageBox::critical(this, _("Error"), + _("An error occurred during operation.")); + return; } + + } else if (edit->slotCurPageFileTreeView() != nullptr) { + this->slotFileEncrypt(); + } } void MainWindow::slotSign() { + if (edit->tabCount() == 0) return; - if (edit->tabCount() == 0) return; - - if (edit->slotCurPageTextEdit() != nullptr) { - - QVector<GpgKey> keys; - - mKeyList->getPrivateCheckedKeys(keys); - - if (keys.isEmpty()) { - QMessageBox::critical(this, tr("No Key Selected"), tr("No Key Selected")); - return; - } - - for (const auto &key : keys) { - if (!GpgME::GpgContext::checkIfKeyCanSign(key)) { - QMessageBox::information(this, - tr("Invalid Operation"), - tr("The selected key contains a key that does not actually have a signature usage.<br/>") - + tr("<br/>For example the Following Key: <br/>") + key.uids.first().uid); - return; - } - } - - auto tmp = QByteArray(); - - gpgme_sign_result_t result = nullptr; - - gpgme_error_t error; - auto thread = QThread::create([&]() { - error = mCtx->sign(keys, edit->curTextPage()->toPlainText().toUtf8(), &tmp, GPGME_SIG_MODE_CLEAR, &result); - }); - connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); - thread->start(); - - auto *dialog = new WaitingDialog(tr("Signing"), this); - while (thread->isRunning()) { - QApplication::processEvents(); - } - dialog->close(); - - infoBoard->associateTextEdit(edit->curTextPage()); - edit->slotFillTextEditWithText(QString::fromUtf8(tmp)); + if (edit->slotCurPageTextEdit() != nullptr) { + auto key_ids = mKeyList->getPrivateChecked(); - auto resultAnalyse = new SignResultAnalyse(mCtx, error, result); + if (key_ids->empty()) { + QMessageBox::critical(this, _("No Key Selected"), _("No Key Selected")); + return; + } - auto &reportText = resultAnalyse->getResultReport(); - if (resultAnalyse->getStatus() < 0) - infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL); - else if (resultAnalyse->getStatus() > 0) - infoBoard->slotRefresh(reportText, INFO_ERROR_OK); - else - infoBoard->slotRefresh(reportText, INFO_ERROR_WARN); + auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids); + for (const auto& key : *keys) { + if (!key.CanSignActual()) { + QMessageBox::information( + this, _("Invalid Operation"), + QString(_( + "The selected key contains a key that does not actually have a " + "signature usage.")) + + "<br/><br/>" + _("For example the Following Key:") + "<br/>" + + key.uids()->front().uid().c_str()); + return; + } + } - delete resultAnalyse; - } else if (edit->slotCurPageFileTreeView() != nullptr) { - this->slotFileSign(); + auto tmp = std::make_unique<ByteArray>(); + + GpgSignResult result = nullptr; + gpgme_error_t error; + bool if_error = false; + + process_operation(this, _("Signing"), [&]() { + try { + auto buffer = edit->curTextPage()->toPlainText().toUtf8().toStdString(); + error = GpgFrontend::BasicOperator::GetInstance().Sign( + std::move(keys), buffer, tmp, GPGME_SIG_MODE_CLEAR, result); + } catch (const std::runtime_error& e) { + if_error = true; + } + }); + + if (!if_error) { + auto resultAnalyse = SignResultAnalyse(error, std::move(result)); + resultAnalyse.analyse(); + process_result_analyse(edit, infoBoard, resultAnalyse); + + if (check_gpg_error_2_err_code(error) == GPG_ERR_NO_ERROR) + edit->slotFillTextEditWithText(QString::fromStdString(*tmp)); + } else { + QMessageBox::critical(this, _("Error"), + _("An error occurred during operation.")); + return; } + } else if (edit->slotCurPageFileTreeView() != nullptr) { + this->slotFileSign(); + } } void MainWindow::slotDecrypt() { - if (edit->tabCount() == 0) return; - - if (edit->slotCurPageTextEdit() != nullptr) { - - auto decrypted = QByteArray(); - QByteArray text = edit->curTextPage()->toPlainText().toUtf8(); - GpgME::GpgContext::preventNoDataErr(&text); - - if (text.trimmed().startsWith(GpgConstants::GPG_FRONTEND_SHORT_CRYPTO_HEAD)) { - QMessageBox::critical(this, tr("Notice"), tr("Short Crypto Text only supports Decrypt & Verify.")); - return; - } - - gpgme_decrypt_result_t result = nullptr; - - gpgme_error_t error; - auto thread = QThread::create([&]() { - // try decrypt, if fail do nothing, especially don't replace text - error = mCtx->decrypt(text, &decrypted, &result); - }); - connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); - thread->start(); - - auto *dialog = new WaitingDialog(tr("Decrypting"), this); - while (thread->isRunning()) { - QApplication::processEvents(); - } - - dialog->close(); - - infoBoard->associateTextEdit(edit->curTextPage()); - - if (gpgme_err_code(error) == GPG_ERR_NO_ERROR) - edit->slotFillTextEditWithText(QString::fromUtf8(decrypted)); - - auto resultAnalyse = new DecryptResultAnalyse(mCtx, error, result); - - auto &reportText = resultAnalyse->getResultReport(); - if (resultAnalyse->getStatus() < 0) - infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL); - else if (resultAnalyse->getStatus() > 0) - infoBoard->slotRefresh(reportText, INFO_ERROR_OK); - else - infoBoard->slotRefresh(reportText, INFO_ERROR_WARN); + if (edit->tabCount() == 0) return; + + if (edit->slotCurPageTextEdit() != nullptr) { + auto decrypted = std::make_unique<ByteArray>(); + QByteArray text = edit->curTextPage()->toPlainText().toUtf8(); + + if (text.trimmed().startsWith( + GpgConstants::GPG_FRONTEND_SHORT_CRYPTO_HEAD)) { + QMessageBox::critical( + this, _("Notice"), + _("Short Crypto Text only supports Decrypt & Verify.")); + return; + } - delete resultAnalyse; - } else if (edit->slotCurPageFileTreeView() != nullptr) { - this->slotFileDecrypt(); + GpgDecrResult result = nullptr; + gpgme_error_t error; + bool if_error = false; + process_operation(this, _("Decrypting"), [&]() { + try { + auto buffer = text.toStdString(); + error = GpgFrontend::BasicOperator::GetInstance().Decrypt( + buffer, decrypted, result); + } catch (const std::runtime_error& e) { + if_error = true; + } + }); + + if (!if_error) { + auto resultAnalyse = DecryptResultAnalyse(error, std::move(result)); + resultAnalyse.analyse(); + process_result_analyse(edit, infoBoard, resultAnalyse); + + if (check_gpg_error_2_err_code(error) == GPG_ERR_NO_ERROR) + edit->slotFillTextEditWithText(QString::fromStdString(*decrypted)); + } else { + QMessageBox::critical(this, _("Error"), + _("An error occurred during operation.")); + return; } + } else if (edit->slotCurPageFileTreeView() != nullptr) { + this->slotFileDecrypt(); + } } void MainWindow::slotFind() { - if (edit->tabCount() == 0 || edit->curTextPage() == nullptr) { - return; - } - - // At first close verifynotification, if existing - edit->slotCurPageTextEdit()->closeNoteByClass("findwidget"); + if (edit->tabCount() == 0 || edit->curTextPage() == nullptr) { + return; + } - auto *fw = new FindWidget(this, edit->curTextPage()); - edit->slotCurPageTextEdit()->showNotificationWidget(fw, "findWidget"); + // At first close verifynotification, if existing + edit->slotCurPageTextEdit()->closeNoteByClass("findwidget"); + auto* fw = new FindWidget(this, edit->curTextPage()); + edit->slotCurPageTextEdit()->showNotificationWidget(fw, "findWidget"); } void MainWindow::slotVerify() { + if (edit->tabCount() == 0) return; + + if (edit->slotCurPageTextEdit() != nullptr) { + auto text = edit->curTextPage()->toPlainText().toUtf8(); + // TODO(Saturneric) PreventNoDataErr + + auto sig_buffer = std::make_unique<ByteArray>(); + sig_buffer.reset(); + + GpgVerifyResult result = nullptr; + GpgError error; + bool if_error = false; + process_operation(this, _("Verifying"), [&]() { + try { + auto buffer = text.toStdString(); + error = GpgFrontend::BasicOperator::GetInstance().Verify( + buffer, sig_buffer, result); + } catch (const std::runtime_error& e) { + if_error = true; + } + }); + + if (!if_error) { + auto resultAnalyse = VerifyResultAnalyse(error, std::move(result)); + resultAnalyse.analyse(); + process_result_analyse(edit, infoBoard, resultAnalyse); + + // if (resultAnalyse->getStatus() >= 0) { + // infoBoard->resetOptionActionsMenu(); + // infoBoard->addOptionalAction( + // "Show Verify Details", [this, error, result]() { + // VerifyDetailsDialog(this, mCtx, mKeyList, error, result); + // }); + // } - if (edit->tabCount() == 0) return; - - if (edit->slotCurPageTextEdit() != nullptr) { - - QByteArray text = edit->curTextPage()->toPlainText().toUtf8(); - GpgME::GpgContext::preventNoDataErr(&text); - - gpgme_verify_result_t result; - - gpgme_error_t error; - auto thread = QThread::create([&]() { - error = mCtx->verify(&text, nullptr, &result); - }); - connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); - thread->start(); - - auto *dialog = new WaitingDialog(tr("Verifying"), this); - while (thread->isRunning()) - QApplication::processEvents(); - dialog->close(); - - auto resultAnalyse = new VerifyResultAnalyse(mCtx, error, result); - infoBoard->associateTextEdit(edit->curTextPage()); - - auto &reportText = resultAnalyse->getResultReport(); - if (resultAnalyse->getStatus() < 0) - infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL); - else if (resultAnalyse->getStatus() > 0) - infoBoard->slotRefresh(reportText, INFO_ERROR_OK); - else - infoBoard->slotRefresh(reportText, INFO_ERROR_WARN); - - if (resultAnalyse->getStatus() >= 0) { - infoBoard->resetOptionActionsMenu(); - infoBoard->addOptionalAction("Show Verify Details", [this, error, result]() { - VerifyDetailsDialog(this, mCtx, mKeyList, error, result); - }); - } - delete resultAnalyse; - } else if (edit->slotCurPageFileTreeView() != nullptr) { - this->slotFileVerify(); + } else { + QMessageBox::critical(this, _("Error"), + _("An error occurred during operation.")); + return; } + } else if (edit->slotCurPageFileTreeView() != nullptr) { + this->slotFileVerify(); + } } void MainWindow::slotEncryptSign() { + if (edit->tabCount() == 0) return; - if (edit->tabCount() == 0) return; - - if (edit->slotCurPageTextEdit() != nullptr) { - - QVector<GpgKey> keys; - mKeyList->getCheckedKeys(keys); - - if (keys.empty()) { - QMessageBox::critical(nullptr, tr("No Key Selected"), tr("No Key Selected")); - return; - } - - for (const auto &key : keys) { - bool key_can_encr = GpgME::GpgContext::checkIfKeyCanEncr(key); - - if (!key_can_encr) { - QMessageBox::critical(nullptr, - tr("Invalid KeyPair"), - tr("The selected keypair cannot be used for encryption.<br/>") - + tr("<br/>For example the Following Key: <br/>") + key.uids.first().uid); - return; - } - - } + if (edit->slotCurPageTextEdit() != nullptr) { + auto key_ids = mKeyList->getChecked(); - QVector<GpgKey> signerKeys; - - auto signersPicker = new SignersPicker(mCtx, this); - - QEventLoop loop; - connect(signersPicker, SIGNAL(finished(int)), &loop, SLOT(quit())); - loop.exec(); + if (key_ids->empty()) { + QMessageBox::critical(nullptr, _("No Key Selected"), + _("No Key Selected")); + return; + } - signersPicker->getCheckedSigners(signerKeys); + auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids); - for (const auto &key : keys) { - qDebug() << "Keys " << key.email; - } + for (const auto& key : *keys) { + bool key_can_encrypt = key.CanEncrActual(); - for (const auto &signer : signerKeys) { - qDebug() << "Signers " << signer.email; - } + if (!key_can_encrypt) { + QMessageBox::critical( + nullptr, _("Invalid KeyPair"), + QString(_("The selected keypair cannot be used for encryption.")) + + "<br/><br/>" + _("For example the Following Key:") + " <br/>" + + QString::fromStdString(key.uids()->front().uid())); + return; + } + } + auto signersPicker = new SignersPicker(this); + QEventLoop loop; + connect(signersPicker, SIGNAL(finished(int)), &loop, SLOT(quit())); + loop.exec(); - auto tmp = QByteArray(); - gpgme_encrypt_result_t encr_result = nullptr; - gpgme_sign_result_t sign_result = nullptr; + auto signer_key_ids = signersPicker->getCheckedSigners(); + auto signer_keys = GpgKeyGetter::GetInstance().GetKeys(signer_key_ids); - gpgme_error_t error; - auto thread = QThread::create([&]() { - error = mCtx->encryptSign(keys, signerKeys, edit->curTextPage()->toPlainText().toUtf8(), &tmp, - &encr_result, - &sign_result); - }); - connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); - thread->start(); + for (const auto& key : *keys) { + LOG(INFO) << "Keys " << key.email(); + } - auto *dialog = new WaitingDialog(tr("Encrypting and Signing"), this); - while (thread->isRunning()) { - QApplication::processEvents(); - } + for (const auto& signer : *signer_keys) { + LOG(INFO) << "Signers " << signer.email(); + } - if (settings.value("advanced/autoPubkeyExchange").toBool()) { - PubkeyUploader pubkeyUploader(mCtx, signerKeys); - pubkeyUploader.start(); - if (!pubkeyUploader.result()) { - QMessageBox::warning(nullptr, - tr("Automatic Key Exchange Warning"), - tr("Part of the automatic key exchange failed, which may be related to your key.") - + - tr("If possible, try to use the RSA algorithm compatible with the server for signing.")); - } + GpgEncrResult encr_result = nullptr; + GpgSignResult sign_result = nullptr; + GpgError error; + bool if_error = false; + + auto tmp = std::make_unique<ByteArray>(); + process_operation(this, _("Encrypting and Signing"), [&]() { + try { + auto buffer = edit->curTextPage()->toPlainText().toUtf8().toStdString(); + error = GpgFrontend::BasicOperator::GetInstance().EncryptSign( + std::move(keys), std::move(signer_keys), buffer, tmp, encr_result, + sign_result); + } catch (const std::runtime_error& e) { + if_error = true; + } + }); + + if (!if_error) { +#ifdef ADVANCE_SUPPORT + if (settings.value("advanced/autoPubkeyExchange").toBool()) { + PubkeyUploader pubkeyUploader(mCtx, signerKeys); + pubkeyUploader.start(); + if (!pubkeyUploader.result()) { + QMessageBox::warning( + nullptr, _("Automatic Key Exchange Warning"), + _("Part of the automatic key exchange failed, " + "which may be related to your key.") + + _("If possible, try to use the RSA algorithm " + "compatible with the server for signing.")); } - - dialog->close(); - - if (gpgme_err_code(error) == GPG_ERR_NO_ERROR) { - auto tmp2 = QString(tmp); - edit->slotFillTextEditWithText(tmp2); + } +#endif + LOG(INFO) << "ResultAnalyse Started"; + auto encrypt_res = EncryptResultAnalyse(error, std::move(encr_result)); + auto sign_res = SignResultAnalyse(error, std::move(sign_result)); + encrypt_res.analyse(); + sign_res.analyse(); + process_result_analyse(edit, infoBoard, encrypt_res, sign_res); + if (check_gpg_error_2_err_code(error) == GPG_ERR_NO_ERROR) + edit->slotFillTextEditWithText(QString::fromStdString(*tmp)); + +#ifdef SMTP_SUPPORT + infoBoard->resetOptionActionsMenu(); + infoBoard->addOptionalAction("Send Mail", [this]() { + if (settings.value("sendMail/enable", false).toBool()) + new SendMailDialog(edit->curTextPage()->toPlainText(), this); + else { + QMessageBox::warning(nullptr, _("Function Disabled"), + _("Please go to the settings interface to " + "enable and configure this function.")); } - - qDebug() << "Start Analyse Result"; - - auto resultAnalyseEncr = new EncryptResultAnalyse(error, encr_result); - auto resultAnalyseSign = new SignResultAnalyse(mCtx, error, sign_result); - int status = std::min(resultAnalyseEncr->getStatus(), resultAnalyseSign->getStatus()); - auto reportText = resultAnalyseEncr->getResultReport() + resultAnalyseSign->getResultReport(); - - infoBoard->associateTextEdit(edit->curTextPage()); - - if (status < 0) - infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL); - else if (status > 0) - infoBoard->slotRefresh(reportText, INFO_ERROR_OK); - else - infoBoard->slotRefresh(reportText, INFO_ERROR_WARN); - - qDebug() << "End Analyse Result"; - - if (status >= 0) { - infoBoard->resetOptionActionsMenu(); - infoBoard->addOptionalAction("Send Mail", [this]() { - if (settings.value("sendMail/enable", false).toBool()) - new SendMailDialog(edit->curTextPage()->toPlainText(), this); - else { - QMessageBox::warning(nullptr, - tr("Function Disabled"), - tr("Please go to the settings interface to enable and configure this function.")); - } - }); - infoBoard->addOptionalAction("Shorten Ciphertext", [this]() { - if (settings.value("general/serviceToken").toString().isEmpty()) - QMessageBox::warning(nullptr, - tr("Service Token Empty"), - tr("Please go to the settings interface to set Own Key and get Service Token.")); - else { - shortenCryptText(); - } - }); + }); +#endif + +#ifdef ADVANCE_SUPPORT + infoBoard->addOptionalAction("Shorten Ciphertext", [this]() { + if (settings.value("general/serviceToken").toString().isEmpty()) + QMessageBox::warning(nullptr, _("Service Token Empty"), + _("Please go to the settings interface to set " + "Own Key and get Service Token.")); + else { + shortenCryptText(); } + }); +#endif - delete resultAnalyseEncr; - delete resultAnalyseSign; - } else if (edit->slotCurPageFileTreeView() != nullptr) { - this->slotFileEncryptSign(); + } else { + QMessageBox::critical(this, _("Error"), + _("An error occurred during operation.")); + return; } + } else if (edit->slotCurPageFileTreeView() != nullptr) { + this->slotFileEncryptSign(); + } } void MainWindow::slotDecryptVerify() { - - if (edit->tabCount() == 0) return; - - if (edit->slotCurPageTextEdit() != nullptr) { - - auto decrypted = QByteArray(); - QString plainText = edit->curTextPage()->toPlainText(); - - - if (plainText.trimmed().startsWith(GpgConstants::GPG_FRONTEND_SHORT_CRYPTO_HEAD)) { - auto cryptoText = getCryptText(plainText); - if (!cryptoText.isEmpty()) { - plainText = cryptoText; - } - } - - QByteArray text = plainText.toUtf8(); - - GpgME::GpgContext::preventNoDataErr(&text); - - gpgme_decrypt_result_t d_result = nullptr; - gpgme_verify_result_t v_result = nullptr; - - auto *dialog = new WaitingDialog(tr("Decrypting and Verifying"), this); - - // Automatically import public keys that are not stored locally - if (settings.value("advanced/autoPubkeyExchange").toBool()) { - gpgme_verify_result_t tmp_v_result = nullptr; - auto thread = QThread::create([&]() { - mCtx->verify(&text, nullptr, &tmp_v_result); - }); - thread->start(); - while (thread->isRunning()) QApplication::processEvents(); - auto *checker = new UnknownSignersChecker(mCtx, tmp_v_result); - checker->start(); - checker->deleteLater(); - } - - gpgme_error_t error; - auto thread = QThread::create([&]() { - error = mCtx->decryptVerify(text, &decrypted, &d_result, &v_result); - }); - connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); - thread->start(); - - while (thread->isRunning()) QApplication::processEvents(); - - dialog->close(); - - qDebug() << "Start Analyse Result"; - - infoBoard->associateTextEdit(edit->curTextPage()); - - if (gpgme_err_code(error) == GPG_ERR_NO_ERROR) - edit->slotFillTextEditWithText(QString::fromUtf8(decrypted)); - - auto resultAnalyseDecrypt = new DecryptResultAnalyse(mCtx, error, d_result); - auto resultAnalyseVerify = new VerifyResultAnalyse(mCtx, error, v_result); - - int status = std::min(resultAnalyseDecrypt->getStatus(), resultAnalyseVerify->getStatus()); - auto &reportText = resultAnalyseDecrypt->getResultReport() + resultAnalyseVerify->getResultReport(); - if (status < 0) - infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL); - else if (status > 0) - infoBoard->slotRefresh(reportText, INFO_ERROR_OK); - else - infoBoard->slotRefresh(reportText, INFO_ERROR_WARN); - - if (resultAnalyseVerify->getStatus() >= 0) { - infoBoard->resetOptionActionsMenu(); - infoBoard->addOptionalAction("Show Verify Details", [this, error, v_result]() { - VerifyDetailsDialog(this, mCtx, mKeyList, error, v_result); - }); - } - delete resultAnalyseDecrypt; - delete resultAnalyseVerify; - - qDebug() << "End Analyse Result"; - - } else if (edit->slotCurPageFileTreeView() != nullptr) { - this->slotFileDecryptVerify(); + if (edit->tabCount() == 0) return; + + if (edit->slotCurPageTextEdit() != nullptr) { + QString plainText = edit->curTextPage()->toPlainText(); + +#ifdef ADVANCE_SUPPORT + if (plainText.trimmed().startsWith( + GpgConstants::GPG_FRONTEND_SHORT_CRYPTO_HEAD)) { + auto cryptoText = getCryptText(plainText); + if (!cryptoText.isEmpty()) { + plainText = cryptoText; + } + } +#endif + + QByteArray text = plainText.toUtf8(); + + GpgDecrResult d_result = nullptr; + GpgVerifyResult v_result = nullptr; + gpgme_error_t error; + bool if_error = false; + +#ifdef ADVANCE_SUPPORT + // Automatically import public keys that are not stored locally + if (settings.value("advanced/autoPubkeyExchange").toBool()) { + gpgme_verify_result_t tmp_v_result = nullptr; + auto thread = QThread::create( + [&]() { mCtx->verify(&text, nullptr, &tmp_v_result); }); + thread->start(); + while (thread->isRunning()) QApplication::processEvents(); + auto* checker = new UnknownSignersChecker(mCtx, tmp_v_result); + checker->start(); + checker->deleteLater(); + } +#endif + auto decrypted = std::make_unique<ByteArray>(); + process_operation(this, _("Decrypting and Verifying"), [&]() { + try { + auto buffer = text.toStdString(); + error = BasicOperator::GetInstance().DecryptVerify(buffer, decrypted, + d_result, v_result); + } catch (const std::runtime_error& e) { + if_error = true; + } + }); + + if (!if_error) { + infoBoard->associateFileTreeView(edit->curFilePage()); + + auto decrypt_res = DecryptResultAnalyse(error, std::move(d_result)); + auto verify_res = VerifyResultAnalyse(error, std::move(v_result)); + decrypt_res.analyse(); + verify_res.analyse(); + process_result_analyse(edit, infoBoard, decrypt_res, verify_res); + + edit->slotFillTextEditWithText(QString::fromStdString(*decrypted)); + + // if (verify_res.getStatus() >= 0) { + // infoBoard->resetOptionActionsMenu(); + // infoBoard->addOptionalAction( + // "Show Verify Details", [this, error, v_result]() { + // VerifyDetailsDialog(this, mCtx, mKeyList, error, + // v_result); + // }); + // } + } else { + QMessageBox::critical(this, _("Error"), + _("An error occurred during operation.")); + return; } -} + } else if (edit->slotCurPageFileTreeView() != nullptr) { + this->slotFileDecryptVerify(); + } +} /* * Append the selected (not checked!) Key(s) To Textedit */ void MainWindow::slotAppendSelectedKeys() { - if (edit->tabCount() == 0 || edit->slotCurPageTextEdit() == nullptr) { - return; - } + if (edit->tabCount() == 0 || edit->slotCurPageTextEdit() == nullptr) { + return; + } + + auto exported = std::make_unique<ByteArray>(); + auto key_ids = mKeyList->getSelected(); - auto *keyArray = new QByteArray(); - mCtx->exportKeys(mKeyList->getSelected(), keyArray); - edit->curTextPage()->append(*keyArray); + GpgKeyImportExportor::GetInstance().ExportKeys(key_ids, exported); + edit->curTextPage()->append(QString::fromStdString(*exported)); } void MainWindow::slotCopyMailAddressToClipboard() { - if (mKeyList->getSelected()->isEmpty()) { - return; - } - auto key = mCtx->getKeyById(mKeyList->getSelected()->first()); - if (!key.good) { - QMessageBox::critical(nullptr, tr("Error"), tr("Key Not Found.")); - return; - } - QClipboard *cb = QApplication::clipboard(); - QString mail = key.email; - cb->setText(mail); + auto key_ids = mKeyList->getSelected(); + if (key_ids->empty()) return; + + auto key = GpgKeyGetter::GetInstance().GetKey(key_ids->front()); + if (!key.good()) { + QMessageBox::critical(nullptr, _("Error"), _("Key Not Found.")); + return; + } + QClipboard* cb = QApplication::clipboard(); + cb->setText(QString::fromStdString(key.email())); } void MainWindow::slotShowKeyDetails() { - if (mKeyList->getSelected()->isEmpty()) { - return; - } - auto key = mCtx->getKeyById(mKeyList->getSelected()->first()); - if (key.good) { - new KeyDetailsDialog(mCtx, key, this); - } else { - QMessageBox::critical(nullptr, tr("Error"), tr("Key Not Found.")); - } + auto key_ids = mKeyList->getSelected(); + if (key_ids->empty()) return; + + auto key = GpgKeyGetter::GetInstance().GetKey(key_ids->front()); + if (key.good()) { + new KeyDetailsDialog(key, this); + } else { + QMessageBox::critical(nullptr, _("Error"), _("Key Not Found.")); + } } void MainWindow::refreshKeysFromKeyserver() { - if (mKeyList->getSelected()->isEmpty()) { - return; - } - - auto *dialog = new KeyServerImportDialog(mCtx, mKeyList, true, this); - dialog->show(); - dialog->slotImport(*mKeyList->getSelected()); + auto key_ids = mKeyList->getSelected(); + if (key_ids->empty()) return; + auto* dialog = new KeyServerImportDialog(true, this); + dialog->show(); + dialog->slotImport(key_ids); } void MainWindow::uploadKeyToServer() { - QVector<GpgKey> keys; - keys.append(mKeyList->getSelectedKey()); - auto *dialog = new KeyUploadDialog(mCtx, keys, this); - dialog->show(); - dialog->slotUpload(); + auto key_ids = mKeyList->getSelected(); + auto* dialog = new KeyUploadDialog(key_ids, this); + dialog->show(); + dialog->slotUpload(); } - -void MainWindow::slotOpenFile(QString &path) { - edit->slotOpenFile(path); +void MainWindow::slotOpenFile(QString& path) { edit->slotOpenFile(path); } + +void MainWindow::slotVersionUpgrade(const QString& currentVersion, + const QString& latestVersion) { + if (currentVersion < latestVersion) { + QMessageBox::warning( + this, _("Outdated Version"), + QString(_("This version(%1) is out of date, please update " + "the latest version in time. ")) + .arg(currentVersion) + + QString(_("You can download the latest version(%1) on " + "Github Releases Page.<br/>")) + .arg(latestVersion)); + } else if (currentVersion > latestVersion) { + QMessageBox::warning( + this, _("Unreleased Version"), + QString( + _("This version(%1) has not been officially released and is not " + "recommended for use in a production environment. <br/>")) + .arg(currentVersion) + + QString( + _("You can download the latest version(%1) on Github Releases " + "Page.<br/>")) + .arg(latestVersion)); + } } -void MainWindow::slotVersionUpgrade(const QString ¤tVersion, const QString &latestVersion) { - if (currentVersion < latestVersion) { - QMessageBox::warning(this, - tr("Outdated Version"), - tr("This version(%1) is out of date, please update the latest version in time. ").arg( - currentVersion) - + tr("You can download the latest version(%1) on Github Releases Page.<br/>").arg( - latestVersion)); - } else if (currentVersion > latestVersion) { - QMessageBox::warning(this, - tr("Unreleased Version"), - tr("This version(%1) has not been officially released and is not recommended for use in a production environment. <br/>").arg( - currentVersion) - + tr("You can download the latest version(%1) on Github Releases Page.<br/>").arg( - latestVersion)); - } -} +} // namespace GpgFrontend::UI diff --git a/src/ui/main_window/MainWindowSlotUI.cpp b/src/ui/main_window/MainWindowSlotUI.cpp index 7065e41c..35eb74ac 100644 --- a/src/ui/main_window/MainWindowSlotUI.cpp +++ b/src/ui/main_window/MainWindowSlotUI.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -23,198 +23,174 @@ */ #include "MainWindow.h" +#include "ui/UserInterfaceUtils.h" +#include "ui/settings/GlobalSettingStation.h" -void MainWindow::slotAbout() { - new AboutDialog(0, this); -} +namespace GpgFrontend::UI { -void MainWindow::slotCheckUpdate() { - new AboutDialog(2, this); -} +void MainWindow::slotAbout() { new AboutDialog(0, this); } -void MainWindow::slotSetStatusBarText(const QString &text) { - statusBar()->showMessage(text, 20000); -} +void MainWindow::slotCheckUpdate() { new AboutDialog(2, this); } -void MainWindow::slotStartWizard() { - auto *wizard = new Wizard(mCtx, keyMgmt, this); - wizard->show(); - wizard->setModal(true); +void MainWindow::slotSetStatusBarText(const QString& text) { + statusBar()->showMessage(text, 20000); } - -void MainWindow::slotCheckAttachmentFolder() { - // TODO: always check? - if (!settings.value("mime/parseMime").toBool()) { - return; - } - - QString attachmentDir = qApp->applicationDirPath() + "/attachments/"; - // filenum minus . and .. - uint filenum = QDir(attachmentDir).count() - 2; - if (filenum > 0) { - QString statusText; - if (filenum == 1) { - statusText = tr("There is one unencrypted file in attachment folder"); - } else { - statusText = tr("There are ") + QString::number(filenum) + tr(" unencrypted files in attachment folder"); - } - statusBarIcon->setStatusTip(statusText); - statusBarIcon->show(); - } else { - statusBarIcon->hide(); - } +void MainWindow::slotStartWizard() { + auto* wizard = new Wizard(this); + wizard->show(); + wizard->setModal(true); } void MainWindow::slotImportKeyFromEdit() { - if (edit->tabCount() == 0 || edit->slotCurPageTextEdit() == nullptr) - return; - keyMgmt->slotImportKeys(edit->curTextPage()->toPlainText().toUtf8()); + if (edit->tabCount() == 0 || edit->slotCurPageTextEdit() == nullptr) return; + CommonUtils::GetInstance()->slotImportKeys( + this, edit->curTextPage()->toPlainText().toStdString()); } void MainWindow::slotOpenKeyManagement() { - keyMgmt->show(); - keyMgmt->raise(); - keyMgmt->activateWindow(); + auto* dialog = new KeyMgmt(this); + dialog->show(); + dialog->raise(); } -void MainWindow::slotOpenFileTab() { - edit->slotNewFileTab(); -} +void MainWindow::slotOpenFileTab() { edit->slotNewFileTab(); } void MainWindow::slotDisableTabActions(int number) { - bool disable; + bool disable; + + if (number == -1) + disable = true; + else + disable = false; + + if (edit->curFilePage() != nullptr) { + disable = true; + } + + printAct->setDisabled(disable); + saveAct->setDisabled(disable); + saveAsAct->setDisabled(disable); + quoteAct->setDisabled(disable); + cutAct->setDisabled(disable); + copyAct->setDisabled(disable); + pasteAct->setDisabled(disable); + closeTabAct->setDisabled(disable); + selectAllAct->setDisabled(disable); + findAct->setDisabled(disable); + verifyAct->setDisabled(disable); + signAct->setDisabled(disable); + encryptAct->setDisabled(disable); + encryptSignAct->setDisabled(disable); + decryptAct->setDisabled(disable); + decryptVerifyAct->setDisabled(disable); + + redoAct->setDisabled(disable); + undoAct->setDisabled(disable); + zoomOutAct->setDisabled(disable); + zoomInAct->setDisabled(disable); + cleanDoubleLinebreaksAct->setDisabled(disable); + quoteAct->setDisabled(disable); + appendSelectedKeysAct->setDisabled(disable); + importKeyFromEditAct->setDisabled(disable); + + cutPgpHeaderAct->setDisabled(disable); + addPgpHeaderAct->setDisabled(disable); +} - if (number == -1) - disable = true; - else - disable = false; +void MainWindow::slotOpenSettingsDialog() { + auto dialog = new SettingsDialog(this); - if(edit->curFilePage() != nullptr) { - disable = true; - } + connect(dialog, &SettingsDialog::finished, this, [&]() -> void { + LOG(INFO) << "Setting Dialog Finished"; - printAct->setDisabled(disable); - saveAct->setDisabled(disable); - saveAsAct->setDisabled(disable); - quoteAct->setDisabled(disable); - cutAct->setDisabled(disable); - copyAct->setDisabled(disable); - pasteAct->setDisabled(disable); - closeTabAct->setDisabled(disable); - selectAllAct->setDisabled(disable); - findAct->setDisabled(disable); - verifyAct->setDisabled(disable); - signAct->setDisabled(disable); - encryptAct->setDisabled(disable); - encryptSignAct->setDisabled(disable); - decryptAct->setDisabled(disable); - decryptVerifyAct->setDisabled(disable); - - redoAct->setDisabled(disable); - undoAct->setDisabled(disable); - zoomOutAct->setDisabled(disable); - zoomInAct->setDisabled(disable); - cleanDoubleLinebreaksAct->setDisabled(disable); - quoteAct->setDisabled(disable); - appendSelectedKeysAct->setDisabled(disable); - importKeyFromEditAct->setDisabled(disable); - - cutPgpHeaderAct->setDisabled(disable); - addPgpHeaderAct->setDisabled(disable); -} + auto& settings = GlobalSettingStation::GetInstance().GetUISettings(); -void MainWindow::slotOpenSettingsDialog() { + int icon_width = settings["window"]["icon_size"]["width"]; + int icon_height = settings["window"]["icon_size"]["height"]; + + this->setIconSize(QSize(icon_width, icon_height)); + importButton->setIconSize(QSize(icon_width, icon_height)); + fileEncButton->setIconSize(QSize(icon_width, icon_height)); + + // Iconstyle - auto dialog = new SettingsDialog(mCtx, this); - - connect(dialog, &SettingsDialog::finished, this, [&] () -> void { - - qDebug() << "Setting Dialog Finished"; - - // Iconsize - QSize iconSize = settings.value("toolbar/iconsize", QSize(32, 32)).toSize(); - this->setIconSize(iconSize); - importButton->setIconSize(iconSize); - fileEncButton->setIconSize(iconSize); - - // Iconstyle - Qt::ToolButtonStyle buttonStyle = static_cast<Qt::ToolButtonStyle>(settings.value("toolbar/iconstyle", - Qt::ToolButtonTextUnderIcon).toUInt()); - this->setToolButtonStyle(buttonStyle); - importButton->setToolButtonStyle(buttonStyle); - fileEncButton->setToolButtonStyle(buttonStyle); - - // restart mainwindow if necessary - if (getRestartNeeded()) { - if (edit->maybeSaveAnyTab()) { - saveSettings(); - qApp->exit(RESTART_CODE); - } - } - - // steganography hide/show - if (!settings.value("advanced/steganography").toBool()) { - this->menuBar()->removeAction(steganoMenu->menuAction()); - } else { - this->menuBar()->insertAction(viewMenu->menuAction(), steganoMenu->menuAction()); - } - }); + int icon_style = settings["window"]["icon_style"]; + auto button_style = static_cast<Qt::ToolButtonStyle>(icon_style); + this->setToolButtonStyle(button_style); + importButton->setToolButtonStyle(button_style); + fileEncButton->setToolButtonStyle(button_style); + // restart mainwindow if necessary + if (getRestartNeeded()) { + if (edit->maybeSaveAnyTab()) { + saveSettings(); + qApp->exit(RESTART_CODE); + } + } +#ifdef ADVANCED_SUPPORT + // steganography hide/show + if (!settings.value("advanced/steganography").toBool()) { + this->menuBar()->removeAction(steganoMenu->menuAction()); + } else { + this->menuBar()->insertAction(viewMenu->menuAction(), + steganoMenu->menuAction()); + } +#endif + }); } void MainWindow::slotCleanDoubleLinebreaks() { - if (edit->tabCount() == 0 || edit->slotCurPageTextEdit() == nullptr) { - return; - } + if (edit->tabCount() == 0 || edit->slotCurPageTextEdit() == nullptr) { + return; + } - QString content = edit->curTextPage()->toPlainText(); - content.replace("\n\n", "\n"); - edit->slotFillTextEditWithText(content); + QString content = edit->curTextPage()->toPlainText(); + content.replace("\n\n", "\n"); + edit->slotFillTextEditWithText(content); } void MainWindow::slotAddPgpHeader() { - if (edit->tabCount() == 0 || edit->slotCurPageTextEdit() == nullptr) { - return; - } + if (edit->tabCount() == 0 || edit->slotCurPageTextEdit() == nullptr) { + return; + } - QString content = edit->curTextPage()->toPlainText().trimmed(); + QString content = edit->curTextPage()->toPlainText().trimmed(); - content.prepend("\n\n").prepend(GpgConstants::PGP_CRYPT_BEGIN); - content.append("\n").append(GpgConstants::PGP_CRYPT_END); + content.prepend("\n\n").prepend(GpgConstants::PGP_CRYPT_BEGIN); + content.append("\n").append(GpgConstants::PGP_CRYPT_END); - edit->slotFillTextEditWithText(content); + edit->slotFillTextEditWithText(content); } void MainWindow::slotCutPgpHeader() { + if (edit->tabCount() == 0 || edit->slotCurPageTextEdit() == nullptr) { + return; + } - if (edit->tabCount() == 0 || edit->slotCurPageTextEdit() == nullptr) { - return; - } + QString content = edit->curTextPage()->toPlainText(); + int start = content.indexOf(GpgConstants::PGP_CRYPT_BEGIN); + int end = content.indexOf(GpgConstants::PGP_CRYPT_END); - QString content = edit->curTextPage()->toPlainText(); - int start = content.indexOf(GpgConstants::PGP_CRYPT_BEGIN); - int end = content.indexOf(GpgConstants::PGP_CRYPT_END); + if (start < 0 || end < 0) { + return; + } - if (start < 0 || end < 0) { - return; - } + // remove head + int headEnd = content.indexOf("\n\n", start) + 2; + content.remove(start, headEnd - start); - // remove head - int headEnd = content.indexOf("\n\n", start) + 2; - content.remove(start, headEnd - start); + // remove tail + end = content.indexOf(GpgConstants::PGP_CRYPT_END); + content.remove(end, QString(GpgConstants::PGP_CRYPT_END).size()); - // remove tail - end = content.indexOf(GpgConstants::PGP_CRYPT_END); - content.remove(end, QString(GpgConstants::PGP_CRYPT_END).size()); - - edit->slotFillTextEditWithText(content.trimmed()); + edit->slotFillTextEditWithText(content.trimmed()); } void MainWindow::slotSetRestartNeeded(bool needed) { - this->restartNeeded = needed; + this->restartNeeded = needed; } -bool MainWindow::getRestartNeeded() const { - return this->restartNeeded; -} +bool MainWindow::getRestartNeeded() const { return this->restartNeeded; } + +} // namespace GpgFrontend::UI diff --git a/src/ui/main_window/MainWindowUI.cpp b/src/ui/main_window/MainWindowUI.cpp index 21f6e3b7..ee7a1bc0 100644 --- a/src/ui/main_window/MainWindowUI.cpp +++ b/src/ui/main_window/MainWindowUI.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -23,428 +23,476 @@ */ #include "MainWindow.h" +#include "ui/UserInterfaceUtils.h" + +namespace GpgFrontend::UI { void MainWindow::createActions() { - /* Main Menu - */ - newTabAct = new QAction(tr("&New"), this); - newTabAct->setIcon(QIcon(":misc_doc.png")); - QList<QKeySequence> newTabActShortcutList; - newTabActShortcutList.append(QKeySequence(Qt::CTRL + Qt::Key_N)); - newTabActShortcutList.append(QKeySequence(Qt::CTRL + Qt::Key_T)); - newTabAct->setShortcuts(newTabActShortcutList); - newTabAct->setToolTip(tr("Open a new file")); - connect(newTabAct, SIGNAL(triggered()), edit, SLOT(slotNewTab())); - - openAct = new QAction(tr("&Open..."), this); - openAct->setIcon(QIcon(":fileopen.png")); - openAct->setShortcut(QKeySequence::Open); - openAct->setToolTip(tr("Open an existing file")); - connect(openAct, SIGNAL(triggered()), edit, SLOT(slotOpen())); - - browserAct = new QAction(tr("&Browser"), this); - browserAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_B)); - browserAct->setToolTip(tr("Open a file browser")); - connect(browserAct, SIGNAL(triggered()), this, SLOT(slotOpenFileTab())); - - saveAct = new QAction(tr("&Save"), this); - saveAct->setIcon(QIcon(":filesave.png")); - saveAct->setShortcut(QKeySequence::Save); - saveAct->setToolTip(tr("Save the current File")); - connect(saveAct, SIGNAL(triggered()), edit, SLOT(slotSave())); - - saveAsAct = new QAction(tr("Save &As") + "...", this); - saveAsAct->setIcon(QIcon(":filesaveas.png")); - saveAsAct->setShortcut(QKeySequence::SaveAs); - saveAsAct->setToolTip(tr("Save the current File as...")); - connect(saveAsAct, SIGNAL(triggered()), edit, SLOT(slotSaveAs())); - - printAct = new QAction(tr("&Print"), this); - printAct->setIcon(QIcon(":fileprint.png")); - printAct->setShortcut(QKeySequence::Print); - printAct->setToolTip(tr("Print Document")); - connect(printAct, SIGNAL(triggered()), edit, SLOT(slotPrint())); - - closeTabAct = new QAction(tr("&Close"), this); - closeTabAct->setShortcut(QKeySequence::Close); - closeTabAct->setToolTip(tr("Close file")); - connect(closeTabAct, SIGNAL(triggered()), edit, SLOT(slotCloseTab())); - - quitAct = new QAction(tr("&Quit"), this); - quitAct->setShortcut(QKeySequence::Quit); - quitAct->setIcon(QIcon(":exit.png")); - quitAct->setToolTip(tr("Quit Program")); - connect(quitAct, SIGNAL(triggered()), this, SLOT(close())); - - /* Edit Menu - */ - undoAct = new QAction(tr("&Undo"), this); - undoAct->setShortcut(QKeySequence::Undo); - undoAct->setToolTip(tr("Undo Last Edit Action")); - connect(undoAct, SIGNAL(triggered()), edit, SLOT(slotUndo())); - - redoAct = new QAction(tr("&Redo"), this); - redoAct->setShortcut(QKeySequence::Redo); - redoAct->setToolTip(tr("Redo Last Edit Action")); - connect(redoAct, SIGNAL(triggered()), edit, SLOT(slotRedo())); - - zoomInAct = new QAction(tr("Zoom In"), this); - zoomInAct->setShortcut(QKeySequence::ZoomIn); - connect(zoomInAct, SIGNAL(triggered()), edit, SLOT(slotZoomIn())); - - zoomOutAct = new QAction(tr("Zoom Out"), this); - zoomOutAct->setShortcut(QKeySequence::ZoomOut); - connect(zoomOutAct, SIGNAL(triggered()), edit, SLOT(slotZoomOut())); - - pasteAct = new QAction(tr("&Paste"), this); - pasteAct->setIcon(QIcon(":button_paste.png")); - pasteAct->setShortcut(QKeySequence::Paste); - pasteAct->setToolTip(tr("Paste Text From Clipboard")); - connect(pasteAct, SIGNAL(triggered()), edit, SLOT(slotPaste())); - - cutAct = new QAction(tr("Cu&t"), this); - cutAct->setIcon(QIcon(":button_cut.png")); - cutAct->setShortcut(QKeySequence::Cut); - cutAct->setToolTip(tr("Cut the current selection's contents to the " - "clipboard")); - connect(cutAct, SIGNAL(triggered()), edit, SLOT(slotCut())); - - copyAct = new QAction(tr("&Copy"), this); - copyAct->setIcon(QIcon(":button_copy.png")); - copyAct->setShortcut(QKeySequence::Copy); - copyAct->setToolTip(tr("Copy the current selection's contents to the " - "clipboard")); - connect(copyAct, SIGNAL(triggered()), edit, SLOT(slotCopy())); - - quoteAct = new QAction(tr("&Quote"), this); - quoteAct->setIcon(QIcon(":quote.png")); - quoteAct->setToolTip(tr("Quote whole text")); - connect(quoteAct, SIGNAL(triggered()), edit, SLOT(slotQuote())); - - selectAllAct = new QAction(tr("Select &All"), this); - selectAllAct->setIcon(QIcon(":edit.png")); - selectAllAct->setShortcut(QKeySequence::SelectAll); - selectAllAct->setToolTip(tr("Select the whole text")); - connect(selectAllAct, SIGNAL(triggered()), edit, SLOT(slotSelectAll())); - - findAct = new QAction(tr("&Find"), this); - findAct->setShortcut(QKeySequence::Find); - findAct->setToolTip(tr("Find a word")); - connect(findAct, SIGNAL(triggered()), this, SLOT(slotFind())); - - cleanDoubleLinebreaksAct = new QAction(tr("Remove &spacing"), this); - cleanDoubleLinebreaksAct->setIcon(QIcon(":format-line-spacing-triple.png")); - //cleanDoubleLineBreaksAct->setShortcut(QKeySequence::SelectAll); - cleanDoubleLinebreaksAct->setToolTip(tr("Remove double linebreaks, e.g. in pasted text from webmailer")); - connect(cleanDoubleLinebreaksAct, SIGNAL(triggered()), this, SLOT(slotCleanDoubleLinebreaks())); - - openSettingsAct = new QAction(tr("Se&ttings"), this); - openSettingsAct->setToolTip(tr("Open settings dialog")); - openSettingsAct->setShortcut(QKeySequence::Preferences); - connect(openSettingsAct, SIGNAL(triggered()), this, SLOT(slotOpenSettingsDialog())); - - /* Crypt Menu - */ - encryptAct = new QAction(tr("&Encrypt"), this); - encryptAct->setIcon(QIcon(":encrypted.png")); - encryptAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_E)); - encryptAct->setToolTip(tr("Encrypt Message")); - connect(encryptAct, SIGNAL(triggered()), this, SLOT(slotEncrypt())); - - encryptSignAct = new QAction(tr("&Encrypt &Sign"), this); - encryptSignAct->setIcon(QIcon(":encrypted_signed.png")); - encryptSignAct->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_E)); - encryptSignAct->setToolTip(tr("Encrypt and Sign Message")); - connect(encryptSignAct, SIGNAL(triggered()), this, SLOT(slotEncryptSign())); - - decryptAct = new QAction(tr("&Decrypt"), this); - decryptAct->setIcon(QIcon(":decrypted.png")); - decryptAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_D)); - decryptAct->setToolTip(tr("Decrypt Message")); - connect(decryptAct, SIGNAL(triggered()), this, SLOT(slotDecrypt())); - - decryptVerifyAct = new QAction(tr("&Decrypt &Verify"), this); - decryptVerifyAct->setIcon(QIcon(":decrypted_verified.png")); - decryptVerifyAct->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_D)); - decryptVerifyAct->setToolTip(tr("Decrypt and Verify Message")); - connect(decryptVerifyAct, SIGNAL(triggered()), this, SLOT(slotDecryptVerify())); - - /* - * File encryption submenu - */ - fileEncryptAct = new QAction(tr("&Encrypt File"), this); - fileEncryptAct->setToolTip(tr("Encrypt File")); - connect(fileEncryptAct, SIGNAL(triggered()), this, SLOT(slotFileEncryptCustom())); - - fileDecryptAct = new QAction(tr("&Decrypt File"), this); - fileDecryptAct->setToolTip(tr("Decrypt File")); - connect(fileDecryptAct, SIGNAL(triggered()), this, SLOT(slotFileDecryptCustom())); - - fileSignAct = new QAction(tr("&Sign File"), this); - fileSignAct->setToolTip(tr("Sign File")); - connect(fileSignAct, SIGNAL(triggered()), this, SLOT(slotFileSignCustom())); - - fileVerifyAct = new QAction(tr("&Verify File"), this); - fileVerifyAct->setToolTip(tr("Verify File")); - connect(fileVerifyAct, SIGNAL(triggered()), this, SLOT(slotFileVerifyCustom())); - - - signAct = new QAction(tr("&Sign"), this); - signAct->setIcon(QIcon(":signature.png")); - signAct->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_I)); - signAct->setToolTip(tr("Sign Message")); - connect(signAct, SIGNAL(triggered()), this, SLOT(slotSign())); - - verifyAct = new QAction(tr("&Verify"), this); - verifyAct->setIcon(QIcon(":verify.png")); - verifyAct->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_V)); - verifyAct->setToolTip(tr("Verify Message")); - connect(verifyAct, SIGNAL(triggered()), this, SLOT(slotVerify())); - - /* Key Menu - */ - - importKeyFromEditAct = new QAction(tr("&Editor"), this); - importKeyFromEditAct->setIcon(QIcon(":txt.png")); - importKeyFromEditAct->setToolTip(tr("Import New Key From Editor")); - connect(importKeyFromEditAct, SIGNAL(triggered()), this, SLOT(slotImportKeyFromEdit())); - - openKeyManagementAct = new QAction(tr("Manage &Keys"), this); - openKeyManagementAct->setIcon(QIcon(":keymgmt.png")); - openKeyManagementAct->setToolTip(tr("Open Keymanagement")); - connect(openKeyManagementAct, SIGNAL(triggered()), this, SLOT(slotOpenKeyManagement())); - - /* - * About Menu - */ - aboutAct = new QAction(tr("&About"), this); - aboutAct->setIcon(QIcon(":help.png")); - aboutAct->setToolTip(tr("Show the application's About box")); - connect(aboutAct, SIGNAL(triggered()), this, SLOT(slotAbout())); - - /* - * Check Update Menu - */ - checkUpdateAct = new QAction(tr("&Check for Updates"), this); - checkUpdateAct->setIcon(QIcon(":help.png")); - checkUpdateAct->setToolTip(tr("Check for updates")); - connect(checkUpdateAct, SIGNAL(triggered()), this, SLOT(slotCheckUpdate())); - - startWizardAct = new QAction(tr("Open &Wizard"), this); - startWizardAct->setToolTip(tr("Open the wizard")); - connect(startWizardAct, SIGNAL(triggered()), this, SLOT(slotStartWizard())); - - /* Popup-Menu-Action for KeyList - */ - appendSelectedKeysAct = new QAction(tr("Append Selected Key(s) To Text"), this); - appendSelectedKeysAct->setToolTip(tr("Append The Selected Keys To Text in Editor")); - connect(appendSelectedKeysAct, SIGNAL(triggered()), this, SLOT(slotAppendSelectedKeys())); - - copyMailAddressToClipboardAct = new QAction(tr("Copy Email"), this); - copyMailAddressToClipboardAct->setToolTip(tr("Copy selected Email to clipboard")); - connect(copyMailAddressToClipboardAct, SIGNAL(triggered()), this, SLOT(slotCopyMailAddressToClipboard())); - - // TODO: find central place for shared actions, to avoid code-duplication with keymgmt.cpp - showKeyDetailsAct = new QAction(tr("Show Key Details"), this); - showKeyDetailsAct->setToolTip(tr("Show Details for this Key")); - connect(showKeyDetailsAct, SIGNAL(triggered()), this, SLOT(slotShowKeyDetails())); - - refreshKeysFromKeyserverAct = new QAction(tr("Refresh Key From Key Server"), this); - refreshKeysFromKeyserverAct->setToolTip(tr("Refresh key from default key server")); - connect(refreshKeysFromKeyserverAct, SIGNAL(triggered()), this, SLOT(refreshKeysFromKeyserver())); - - uploadKeyToServerAct = new QAction(tr("Upload Public Key(s) To Server"), this); - uploadKeyToServerAct->setToolTip(tr("Upload The Selected Public Keys To Server")); - connect(uploadKeyToServerAct, SIGNAL(triggered()), this, SLOT(uploadKeyToServer())); - - /* Key-Shortcuts for Tab-Switchung-Action - */ - switchTabUpAct = new QAction(this); - switchTabUpAct->setShortcut(QKeySequence::NextChild); - connect(switchTabUpAct, SIGNAL(triggered()), edit, SLOT(slotSwitchTabUp())); - this->addAction(switchTabUpAct); - - switchTabDownAct = new QAction(this); - switchTabDownAct->setShortcut(QKeySequence::PreviousChild); - connect(switchTabDownAct, SIGNAL(triggered()), edit, SLOT(slotSwitchTabDown())); - this->addAction(switchTabDownAct); - - cutPgpHeaderAct = new QAction(tr("Remove PGP Header"), this); - connect(cutPgpHeaderAct, SIGNAL(triggered()), this, SLOT(slotCutPgpHeader())); - - addPgpHeaderAct = new QAction(tr("Add PGP Header"), this); - connect(addPgpHeaderAct, SIGNAL(triggered()), this, SLOT(slotAddPgpHeader())); + /* Main Menu + */ + newTabAct = new QAction(_("New"), this); + newTabAct->setIcon(QIcon(":misc_doc.png")); + QList<QKeySequence> newTabActShortcutList; + newTabActShortcutList.append(QKeySequence(Qt::CTRL + Qt::Key_N)); + newTabActShortcutList.append(QKeySequence(Qt::CTRL + Qt::Key_T)); + newTabAct->setShortcuts(newTabActShortcutList); + newTabAct->setToolTip(_("Open a new file")); + connect(newTabAct, SIGNAL(triggered()), edit, SLOT(slotNewTab())); + + openAct = new QAction(_("Open..."), this); + openAct->setIcon(QIcon(":fileopen.png")); + openAct->setShortcut(QKeySequence::Open); + openAct->setToolTip(_("Open an existing file")); + connect(openAct, SIGNAL(triggered()), edit, SLOT(slotOpen())); + + browserAct = new QAction(_("Browser"), this); + browserAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_B)); + browserAct->setToolTip(_("Open a file browser")); + connect(browserAct, SIGNAL(triggered()), this, SLOT(slotOpenFileTab())); + + saveAct = new QAction(_("Save"), this); + saveAct->setIcon(QIcon(":filesave.png")); + saveAct->setShortcut(QKeySequence::Save); + saveAct->setToolTip(_("Save the current File")); + connect(saveAct, SIGNAL(triggered()), edit, SLOT(slotSave())); + + saveAsAct = new QAction(QString(_("Save As")) + "...", this); + saveAsAct->setIcon(QIcon(":filesaveas.png")); + saveAsAct->setShortcut(QKeySequence::SaveAs); + saveAsAct->setToolTip(_("Save the current File as...")); + connect(saveAsAct, SIGNAL(triggered()), edit, SLOT(slotSaveAs())); + + printAct = new QAction(_("Print"), this); + printAct->setIcon(QIcon(":fileprint.png")); + printAct->setShortcut(QKeySequence::Print); + printAct->setToolTip(_("Print Document")); + connect(printAct, SIGNAL(triggered()), edit, SLOT(slotPrint())); + + closeTabAct = new QAction(_("Close"), this); + closeTabAct->setShortcut(QKeySequence::Close); + closeTabAct->setToolTip(_("Close file")); + connect(closeTabAct, SIGNAL(triggered()), edit, SLOT(slotCloseTab())); + + quitAct = new QAction(_("Quit"), this); + quitAct->setShortcut(QKeySequence::Quit); + quitAct->setIcon(QIcon(":exit.png")); + quitAct->setToolTip(_("Quit Program")); + connect(quitAct, SIGNAL(triggered()), this, SLOT(close())); + + /* Edit Menu + */ + undoAct = new QAction(_("Undo"), this); + undoAct->setShortcut(QKeySequence::Undo); + undoAct->setToolTip(_("Undo Last Edit Action")); + connect(undoAct, SIGNAL(triggered()), edit, SLOT(slotUndo())); + + redoAct = new QAction(_("Redo"), this); + redoAct->setShortcut(QKeySequence::Redo); + redoAct->setToolTip(_("Redo Last Edit Action")); + connect(redoAct, SIGNAL(triggered()), edit, SLOT(slotRedo())); + + zoomInAct = new QAction(_("Zoom In"), this); + zoomInAct->setShortcut(QKeySequence::ZoomIn); + connect(zoomInAct, SIGNAL(triggered()), edit, SLOT(slotZoomIn())); + + zoomOutAct = new QAction(_("Zoom Out"), this); + zoomOutAct->setShortcut(QKeySequence::ZoomOut); + connect(zoomOutAct, SIGNAL(triggered()), edit, SLOT(slotZoomOut())); + + pasteAct = new QAction(_("Paste"), this); + pasteAct->setIcon(QIcon(":button_paste.png")); + pasteAct->setShortcut(QKeySequence::Paste); + pasteAct->setToolTip(_("Paste Text From Clipboard")); + connect(pasteAct, SIGNAL(triggered()), edit, SLOT(slotPaste())); + + cutAct = new QAction(_("Cut"), this); + cutAct->setIcon(QIcon(":button_cut.png")); + cutAct->setShortcut(QKeySequence::Cut); + cutAct->setToolTip( + _("Cut the current selection's contents to the " + "clipboard")); + connect(cutAct, SIGNAL(triggered()), edit, SLOT(slotCut())); + + copyAct = new QAction(_("Copy"), this); + copyAct->setIcon(QIcon(":button_copy.png")); + copyAct->setShortcut(QKeySequence::Copy); + copyAct->setToolTip( + _("Copy the current selection's contents to the " + "clipboard")); + connect(copyAct, SIGNAL(triggered()), edit, SLOT(slotCopy())); + + quoteAct = new QAction(_("Quote"), this); + quoteAct->setIcon(QIcon(":quote.png")); + quoteAct->setToolTip(_("Quote whole text")); + connect(quoteAct, SIGNAL(triggered()), edit, SLOT(slotQuote())); + + selectAllAct = new QAction(_("Select All"), this); + selectAllAct->setIcon(QIcon(":edit.png")); + selectAllAct->setShortcut(QKeySequence::SelectAll); + selectAllAct->setToolTip(_("Select the whole text")); + connect(selectAllAct, SIGNAL(triggered()), edit, SLOT(slotSelectAll())); + + findAct = new QAction(_("Find"), this); + findAct->setShortcut(QKeySequence::Find); + findAct->setToolTip(_("Find a word")); + connect(findAct, SIGNAL(triggered()), this, SLOT(slotFind())); + + cleanDoubleLinebreaksAct = new QAction(_("Remove spacing"), this); + cleanDoubleLinebreaksAct->setIcon(QIcon(":format-line-spacing-triple.png")); + // cleanDoubleLineBreaksAct->setShortcut(QKeySequence::SelectAll); + cleanDoubleLinebreaksAct->setToolTip( + _("Remove double linebreaks, e.g. in pasted text from Web Mailer")); + connect(cleanDoubleLinebreaksAct, SIGNAL(triggered()), this, + SLOT(slotCleanDoubleLinebreaks())); + + openSettingsAct = new QAction(_("Settings"), this); + openSettingsAct->setToolTip(_("Open settings dialog")); + openSettingsAct->setShortcut(QKeySequence::Preferences); + connect(openSettingsAct, SIGNAL(triggered()), this, + SLOT(slotOpenSettingsDialog())); + + /* Crypt Menu + */ + encryptAct = new QAction(_("Encrypt"), this); + encryptAct->setIcon(QIcon(":encrypted.png")); + encryptAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_E)); + encryptAct->setToolTip(_("Encrypt Message")); + connect(encryptAct, SIGNAL(triggered()), this, SLOT(slotEncrypt())); + + encryptSignAct = new QAction(_("Encrypt Sign"), this); + encryptSignAct->setIcon(QIcon(":encrypted_signed.png")); + encryptSignAct->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_E)); + encryptSignAct->setToolTip(_("Encrypt and Sign Message")); + connect(encryptSignAct, SIGNAL(triggered()), this, SLOT(slotEncryptSign())); + + decryptAct = new QAction(_("Decrypt"), this); + decryptAct->setIcon(QIcon(":decrypted.png")); + decryptAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_D)); + decryptAct->setToolTip(_("Decrypt Message")); + connect(decryptAct, SIGNAL(triggered()), this, SLOT(slotDecrypt())); + + decryptVerifyAct = new QAction(_("Decrypt Verify"), this); + decryptVerifyAct->setIcon(QIcon(":decrypted_verified.png")); + decryptVerifyAct->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_D)); + decryptVerifyAct->setToolTip(_("Decrypt and Verify Message")); + connect(decryptVerifyAct, SIGNAL(triggered()), this, + SLOT(slotDecryptVerify())); + + /* + * File encryption submenu + */ + fileEncryptAct = new QAction(_("Encrypt File"), this); + fileEncryptAct->setToolTip(_("Encrypt File")); + connect(fileEncryptAct, SIGNAL(triggered()), this, + SLOT(slotFileEncryptCustom())); + + fileDecryptAct = new QAction(_("Decrypt File"), this); + fileDecryptAct->setToolTip(_("Decrypt File")); + connect(fileDecryptAct, SIGNAL(triggered()), this, + SLOT(slotFileDecryptCustom())); + + fileSignAct = new QAction(_("Sign File"), this); + fileSignAct->setToolTip(_("Sign File")); + connect(fileSignAct, SIGNAL(triggered()), this, SLOT(slotFileSignCustom())); + + fileVerifyAct = new QAction(_("Verify File"), this); + fileVerifyAct->setToolTip(_("Verify File")); + connect(fileVerifyAct, SIGNAL(triggered()), this, + SLOT(slotFileVerifyCustom())); + + signAct = new QAction(_("Sign"), this); + signAct->setIcon(QIcon(":signature.png")); + signAct->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_I)); + signAct->setToolTip(_("Sign Message")); + connect(signAct, SIGNAL(triggered()), this, SLOT(slotSign())); + + verifyAct = new QAction(_("Verify"), this); + verifyAct->setIcon(QIcon(":verify.png")); + verifyAct->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_V)); + verifyAct->setToolTip(_("Verify Message")); + connect(verifyAct, SIGNAL(triggered()), this, SLOT(slotVerify())); + + /* Key Menu + */ + + importKeyFromFileAct = new QAction(_("File"), this); + importKeyFromFileAct->setIcon(QIcon(":import_key_from_file.png")); + importKeyFromFileAct->setToolTip(_("Import New Key From File")); + connect(importKeyFromFileAct, &QAction::triggered, this, + [&]() { CommonUtils::GetInstance()->slotImportKeyFromFile(this); }); + + importKeyFromClipboardAct = new QAction(_("Clipboard"), this); + importKeyFromClipboardAct->setIcon(QIcon(":import_key_from_clipboard.png")); + importKeyFromClipboardAct->setToolTip(_("Import New Key From Clipboard")); + connect(importKeyFromClipboardAct, &QAction::triggered, this, [&]() { + CommonUtils::GetInstance()->slotImportKeyFromClipboard(this); + }); + + importKeyFromKeyServerAct = new QAction(_("Keyserver"), this); + importKeyFromKeyServerAct->setIcon(QIcon(":import_key_from_server.png")); + importKeyFromKeyServerAct->setToolTip(_("Import New Key From Keyserver")); + connect(importKeyFromKeyServerAct, &QAction::triggered, this, [&]() { + CommonUtils::GetInstance()->slotImportKeyFromKeyServer(this); + }); + + importKeyFromEditAct = new QAction(_("Editor"), this); + importKeyFromEditAct->setIcon(QIcon(":txt.png")); + importKeyFromEditAct->setToolTip(_("Import New Key From Editor")); + connect(importKeyFromEditAct, SIGNAL(triggered()), this, + SLOT(slotImportKeyFromEdit())); + + openKeyManagementAct = new QAction(_("Manage Keys"), this); + openKeyManagementAct->setIcon(QIcon(":keymgmt.png")); + openKeyManagementAct->setToolTip(_("Open Key Management")); + connect(openKeyManagementAct, SIGNAL(triggered()), this, + SLOT(slotOpenKeyManagement())); + + /* + * About Menu + */ + aboutAct = new QAction(_("About"), this); + aboutAct->setIcon(QIcon(":help.png")); + aboutAct->setToolTip(_("Show the application's About box")); + connect(aboutAct, SIGNAL(triggered()), this, SLOT(slotAbout())); + + /* + * Check Update Menu + */ + checkUpdateAct = new QAction(_("Check for Updates"), this); + checkUpdateAct->setIcon(QIcon(":help.png")); + checkUpdateAct->setToolTip(_("Check for updates")); + connect(checkUpdateAct, SIGNAL(triggered()), this, SLOT(slotCheckUpdate())); + + startWizardAct = new QAction(_("Open Wizard"), this); + startWizardAct->setToolTip(_("Open the wizard")); + connect(startWizardAct, SIGNAL(triggered()), this, SLOT(slotStartWizard())); + + /* Popup-Menu-Action for KeyList + */ + appendSelectedKeysAct = + new QAction(_("Append Selected Key(s) To Text"), this); + appendSelectedKeysAct->setToolTip( + _("Append The Selected Keys To Text in Editor")); + connect(appendSelectedKeysAct, SIGNAL(triggered()), this, + SLOT(slotAppendSelectedKeys())); + + copyMailAddressToClipboardAct = new QAction(_("Copy Email"), this); + copyMailAddressToClipboardAct->setToolTip( + _("Copy selected Email to clipboard")); + connect(copyMailAddressToClipboardAct, SIGNAL(triggered()), this, + SLOT(slotCopyMailAddressToClipboard())); + + // TODO: find central place for shared actions, to avoid code-duplication with + // keymgmt.cpp + showKeyDetailsAct = new QAction(_("Show Key Details"), this); + showKeyDetailsAct->setToolTip(_("Show Details for this Key")); + connect(showKeyDetailsAct, SIGNAL(triggered()), this, + SLOT(slotShowKeyDetails())); + + refreshKeysFromKeyserverAct = + new QAction(_("Refresh Key From Key Server"), this); + refreshKeysFromKeyserverAct->setToolTip( + _("Refresh key from default key server")); + connect(refreshKeysFromKeyserverAct, SIGNAL(triggered()), this, + SLOT(refreshKeysFromKeyserver())); + + uploadKeyToServerAct = new QAction(_("Upload Public Key(s) To Server"), this); + uploadKeyToServerAct->setToolTip( + _("Upload The Selected Public Keys To Server")); + connect(uploadKeyToServerAct, SIGNAL(triggered()), this, + SLOT(uploadKeyToServer())); + + /* Key-Shortcuts for Tab-Switchung-Action + */ + switchTabUpAct = new QAction(this); + switchTabUpAct->setShortcut(QKeySequence::NextChild); + connect(switchTabUpAct, SIGNAL(triggered()), edit, SLOT(slotSwitchTabUp())); + this->addAction(switchTabUpAct); + + switchTabDownAct = new QAction(this); + switchTabDownAct->setShortcut(QKeySequence::PreviousChild); + connect(switchTabDownAct, SIGNAL(triggered()), edit, + SLOT(slotSwitchTabDown())); + this->addAction(switchTabDownAct); + + cutPgpHeaderAct = new QAction(_("Remove PGP Header"), this); + connect(cutPgpHeaderAct, SIGNAL(triggered()), this, SLOT(slotCutPgpHeader())); + + addPgpHeaderAct = new QAction(_("Add PGP Header"), this); + connect(addPgpHeaderAct, SIGNAL(triggered()), this, SLOT(slotAddPgpHeader())); } void MainWindow::createMenus() { - fileMenu = menuBar()->addMenu(tr("&File")); - fileMenu->addAction(newTabAct); - fileMenu->addAction(browserAct); - fileMenu->addAction(openAct); - fileMenu->addSeparator(); - fileMenu->addAction(saveAct); - fileMenu->addAction(saveAsAct); - fileMenu->addSeparator(); - fileMenu->addAction(printAct); - fileMenu->addSeparator(); - fileMenu->addAction(closeTabAct); - fileMenu->addAction(quitAct); - - editMenu = menuBar()->addMenu(tr("&Edit")); - editMenu->addAction(undoAct); - editMenu->addAction(redoAct); - editMenu->addSeparator(); - editMenu->addAction(zoomInAct); - editMenu->addAction(zoomOutAct); - editMenu->addSeparator(); - editMenu->addAction(copyAct); - editMenu->addAction(cutAct); - editMenu->addAction(pasteAct); - editMenu->addAction(selectAllAct); - editMenu->addAction(findAct); - editMenu->addSeparator(); - editMenu->addAction(quoteAct); - editMenu->addAction(cleanDoubleLinebreaksAct); - editMenu->addSeparator(); - editMenu->addAction(openSettingsAct); - - fileEncMenu = new QMenu(tr("&File...")); - fileEncMenu->addAction(fileEncryptAct); - fileEncMenu->addAction(fileDecryptAct); - fileEncMenu->addAction(fileSignAct); - fileEncMenu->addAction(fileVerifyAct); - - cryptMenu = menuBar()->addMenu(tr("&Crypt")); - cryptMenu->addAction(encryptAct); - cryptMenu->addAction(encryptSignAct); - cryptMenu->addAction(decryptAct); - cryptMenu->addAction(decryptVerifyAct); - cryptMenu->addSeparator(); - cryptMenu->addAction(signAct); - cryptMenu->addAction(verifyAct); - cryptMenu->addSeparator(); - cryptMenu->addMenu(fileEncMenu); - - keyMenu = menuBar()->addMenu(tr("&Keys")); - importKeyMenu = keyMenu->addMenu(tr("&Import Key")); - importKeyMenu->setIcon(QIcon(":key_import.png")); - importKeyMenu->addAction(keyMgmt->importKeyFromFileAct); - importKeyMenu->addAction(importKeyFromEditAct); - importKeyMenu->addAction(keyMgmt->importKeyFromClipboardAct); - importKeyMenu->addAction(keyMgmt->importKeyFromKeyServerAct); - importKeyMenu->addAction(keyMgmt->importKeyFromKeyServerAct); - keyMenu->addAction(openKeyManagementAct); - - steganoMenu = menuBar()->addMenu(tr("&Steganography")); - steganoMenu->addAction(cutPgpHeaderAct); - steganoMenu->addAction(addPgpHeaderAct); - - // Hide menu, when steganography menu is disabled in settings - if (!settings.value("advanced/steganography").toBool()) { - this->menuBar()->removeAction(steganoMenu->menuAction()); - } - - viewMenu = menuBar()->addMenu(tr("&View")); - - helpMenu = menuBar()->addMenu(tr("&Help")); - helpMenu->addAction(startWizardAct); - helpMenu->addSeparator(); - helpMenu->addAction(checkUpdateAct); - helpMenu->addAction(aboutAct); - + fileMenu = menuBar()->addMenu(_("File")); + fileMenu->addAction(newTabAct); + fileMenu->addAction(browserAct); + fileMenu->addAction(openAct); + fileMenu->addSeparator(); + fileMenu->addAction(saveAct); + fileMenu->addAction(saveAsAct); + fileMenu->addSeparator(); + fileMenu->addAction(printAct); + fileMenu->addSeparator(); + fileMenu->addAction(closeTabAct); + fileMenu->addAction(quitAct); + + editMenu = menuBar()->addMenu(_("Edit")); + editMenu->addAction(undoAct); + editMenu->addAction(redoAct); + editMenu->addSeparator(); + editMenu->addAction(zoomInAct); + editMenu->addAction(zoomOutAct); + editMenu->addSeparator(); + editMenu->addAction(copyAct); + editMenu->addAction(cutAct); + editMenu->addAction(pasteAct); + editMenu->addAction(selectAllAct); + editMenu->addAction(findAct); + editMenu->addSeparator(); + editMenu->addAction(quoteAct); + editMenu->addAction(cleanDoubleLinebreaksAct); + editMenu->addSeparator(); + editMenu->addAction(openSettingsAct); + + fileEncMenu = new QMenu(_("File...")); + fileEncMenu->addAction(fileEncryptAct); + fileEncMenu->addAction(fileDecryptAct); + fileEncMenu->addAction(fileSignAct); + fileEncMenu->addAction(fileVerifyAct); + + cryptMenu = menuBar()->addMenu(_("Crypt")); + cryptMenu->addAction(encryptAct); + cryptMenu->addAction(encryptSignAct); + cryptMenu->addAction(decryptAct); + cryptMenu->addAction(decryptVerifyAct); + cryptMenu->addSeparator(); + cryptMenu->addAction(signAct); + cryptMenu->addAction(verifyAct); + cryptMenu->addSeparator(); + cryptMenu->addMenu(fileEncMenu); + + keyMenu = menuBar()->addMenu(_("Keys")); + importKeyMenu = keyMenu->addMenu(_("Import Key")); + importKeyMenu->setIcon(QIcon(":key_import.png")); + importKeyMenu->addAction(importKeyFromFileAct); + importKeyMenu->addAction(importKeyFromEditAct); + importKeyMenu->addAction(importKeyFromClipboardAct); + importKeyMenu->addAction(importKeyFromKeyServerAct); + keyMenu->addAction(openKeyManagementAct); + + steganoMenu = menuBar()->addMenu(_("Steganography")); + steganoMenu->addAction(cutPgpHeaderAct); + steganoMenu->addAction(addPgpHeaderAct); + +#ifdef ADVANCED_SUPPORT + // Hide menu, when steganography menu is disabled in settings + if (!settings.value("advanced/steganography").toBool()) { + this->menuBar()->removeAction(steganoMenu->menuAction()); + } +#endif + + viewMenu = menuBar()->addMenu(_("View")); + + helpMenu = menuBar()->addMenu(_("Help")); + helpMenu->addAction(startWizardAct); + helpMenu->addSeparator(); + helpMenu->addAction(checkUpdateAct); + helpMenu->addAction(aboutAct); } void MainWindow::createToolBars() { - fileToolBar = addToolBar(tr("File")); - fileToolBar->setObjectName("fileToolBar"); - fileToolBar->addAction(newTabAct); - fileToolBar->addAction(openAct); - fileToolBar->addAction(saveAct); - fileToolBar->hide(); - viewMenu->addAction(fileToolBar->toggleViewAction()); - - cryptToolBar = addToolBar(tr("Crypt")); - cryptToolBar->setObjectName("cryptToolBar"); - cryptToolBar->addAction(encryptAct); - cryptToolBar->addAction(encryptSignAct); - cryptToolBar->addAction(decryptAct); - cryptToolBar->addAction(decryptVerifyAct); - cryptToolBar->addAction(signAct); - cryptToolBar->addAction(verifyAct); - viewMenu->addAction(cryptToolBar->toggleViewAction()); - - keyToolBar = addToolBar(tr("Key")); - keyToolBar->setObjectName("keyToolBar"); - keyToolBar->addAction(openKeyManagementAct); - viewMenu->addAction(keyToolBar->toggleViewAction()); - - editToolBar = addToolBar(tr("Edit")); - editToolBar->setObjectName("editToolBar"); - editToolBar->addAction(copyAct); - editToolBar->addAction(pasteAct); - editToolBar->addAction(selectAllAct); - viewMenu->addAction(editToolBar->toggleViewAction()); - - specialEditToolBar = addToolBar(tr("Special Edit")); - specialEditToolBar->setObjectName("specialEditToolBar"); - specialEditToolBar->addAction(quoteAct); - specialEditToolBar->addAction(cleanDoubleLinebreaksAct); - specialEditToolBar->hide(); - viewMenu->addAction(specialEditToolBar->toggleViewAction()); - - // Add dropdown menu for key import to keytoolbar - importButton = new QToolButton(); - importButton->setMenu(importKeyMenu); - importButton->setPopupMode(QToolButton::InstantPopup); - importButton->setIcon(QIcon(":key_import.png")); - importButton->setToolTip(tr("Import key from...")); - importButton->setText(tr("Import key")); - keyToolBar->addWidget(importButton); - - // Add dropdown menu for file encryption/decryption to crypttoolbar - fileEncButton = new QToolButton(); - connect(fileEncButton, SIGNAL(clicked(bool)), this, SLOT(slotOpenFileTab())); - fileEncButton->setPopupMode(QToolButton::InstantPopup); - fileEncButton->setIcon(QIcon(":fileencryption.png")); - fileEncButton->setToolTip(tr("Browser to view and operate file")); - fileEncButton->setText(tr("Browser")); - fileToolBar->addWidget(fileEncButton); - + fileToolBar = addToolBar(_("File")); + fileToolBar->setObjectName("fileToolBar"); + fileToolBar->addAction(newTabAct); + fileToolBar->addAction(openAct); + fileToolBar->addAction(saveAct); + fileToolBar->hide(); + viewMenu->addAction(fileToolBar->toggleViewAction()); + + cryptToolBar = addToolBar(_("Crypt")); + cryptToolBar->setObjectName("cryptToolBar"); + cryptToolBar->addAction(encryptAct); + cryptToolBar->addAction(encryptSignAct); + cryptToolBar->addAction(decryptAct); + cryptToolBar->addAction(decryptVerifyAct); + cryptToolBar->addAction(signAct); + cryptToolBar->addAction(verifyAct); + viewMenu->addAction(cryptToolBar->toggleViewAction()); + + keyToolBar = addToolBar(_("Key")); + keyToolBar->setObjectName("keyToolBar"); + keyToolBar->addAction(openKeyManagementAct); + viewMenu->addAction(keyToolBar->toggleViewAction()); + + editToolBar = addToolBar(_("Edit")); + editToolBar->setObjectName("editToolBar"); + editToolBar->addAction(copyAct); + editToolBar->addAction(pasteAct); + editToolBar->addAction(selectAllAct); + viewMenu->addAction(editToolBar->toggleViewAction()); + + specialEditToolBar = addToolBar(_("Special Edit")); + specialEditToolBar->setObjectName("specialEditToolBar"); + specialEditToolBar->addAction(quoteAct); + specialEditToolBar->addAction(cleanDoubleLinebreaksAct); + specialEditToolBar->hide(); + viewMenu->addAction(specialEditToolBar->toggleViewAction()); + + // Add dropdown menu for key import to keytoolbar + importButton = new QToolButton(); + importButton->setMenu(importKeyMenu); + importButton->setPopupMode(QToolButton::InstantPopup); + importButton->setIcon(QIcon(":key_import.png")); + importButton->setToolTip(_("Import key from...")); + importButton->setText(_("Import key")); + keyToolBar->addWidget(importButton); + + // Add dropdown menu for file encryption/decryption to crypttoolbar + fileEncButton = new QToolButton(); + connect(fileEncButton, SIGNAL(clicked(bool)), this, SLOT(slotOpenFileTab())); + fileEncButton->setPopupMode(QToolButton::InstantPopup); + fileEncButton->setIcon(QIcon(":fileencryption.png")); + fileEncButton->setToolTip(_("Browser to view and operate file")); + fileEncButton->setText(_("Browser")); + fileToolBar->addWidget(fileEncButton); } void MainWindow::createStatusBar() { - auto *statusBarBox = new QWidget(); - auto *statusBarBoxLayout = new QHBoxLayout(); - QPixmap *pixmap; - - // icon which should be shown if there are files in attachments-folder - pixmap = new QPixmap(":statusbar_icon.png"); - statusBarIcon = new QLabel(); - statusBar()->addWidget(statusBarIcon); - - statusBarIcon->setPixmap(*pixmap); - statusBar()->insertPermanentWidget(0, statusBarIcon, 0); - statusBarIcon->hide(); - statusBar()->showMessage(tr("Ready"), 2000); - statusBarBox->setLayout(statusBarBoxLayout); + auto* statusBarBox = new QWidget(); + auto* statusBarBoxLayout = new QHBoxLayout(); + QPixmap* pixmap; + + // icon which should be shown if there are files in attachments-folder + pixmap = new QPixmap(":statusbar_icon.png"); + statusBarIcon = new QLabel(); + statusBar()->addWidget(statusBarIcon); + + statusBarIcon->setPixmap(*pixmap); + statusBar()->insertPermanentWidget(0, statusBarIcon, 0); + statusBarIcon->hide(); + statusBar()->showMessage(_("Ready"), 2000); + statusBarBox->setLayout(statusBarBoxLayout); } void MainWindow::createDockWindows() { - /* KeyList-Dockwindow - */ - keyListDock = new QDockWidget(tr("Key ToolBox"), this); - keyListDock->setObjectName("EncryptDock"); - keyListDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); - keyListDock->setMinimumWidth(460); - addDockWidget(Qt::RightDockWidgetArea, keyListDock); - keyListDock->setWidget(mKeyList); - viewMenu->addAction(keyListDock->toggleViewAction()); - - infoBoardDock = new QDockWidget(tr("Information Board"), this); - infoBoardDock->setObjectName("Information Board"); - infoBoardDock->setAllowedAreas(Qt::BottomDockWidgetArea); - addDockWidget(Qt::BottomDockWidgetArea, infoBoardDock); - infoBoardDock->setWidget(infoBoard); - infoBoardDock->widget()->layout()->setContentsMargins(0, 0, 0, 0); - viewMenu->addAction(infoBoardDock->toggleViewAction()); + /* KeyList-Dock window + */ + keyListDock = new QDockWidget(_("Key ToolBox"), this); + keyListDock->setObjectName("EncryptDock"); + keyListDock->setAllowedAreas(Qt::LeftDockWidgetArea | + Qt::RightDockWidgetArea); + keyListDock->setMinimumWidth(460); + addDockWidget(Qt::RightDockWidgetArea, keyListDock); + keyListDock->setWidget(mKeyList); + viewMenu->addAction(keyListDock->toggleViewAction()); + + infoBoardDock = new QDockWidget(_("Information Board"), this); + infoBoardDock->setObjectName("Information Board"); + infoBoardDock->setAllowedAreas(Qt::BottomDockWidgetArea); + addDockWidget(Qt::BottomDockWidgetArea, infoBoardDock); + infoBoardDock->setWidget(infoBoard); + infoBoardDock->widget()->layout()->setContentsMargins(0, 0, 0, 0); + viewMenu->addAction(infoBoardDock->toggleViewAction()); } + +} // namespace GpgFrontend::UI diff --git a/src/ui/settings/GlobalSettingStation.cpp b/src/ui/settings/GlobalSettingStation.cpp new file mode 100644 index 00000000..e88de93b --- /dev/null +++ b/src/ui/settings/GlobalSettingStation.cpp @@ -0,0 +1,94 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#include "GlobalSettingStation.h" + +std::unique_ptr<GpgFrontend::UI::GlobalSettingStation> + GpgFrontend::UI::GlobalSettingStation::_instance = nullptr; + +GpgFrontend::UI::GlobalSettingStation& +GpgFrontend::UI::GlobalSettingStation::GetInstance() { + if (_instance == nullptr) { + _instance = std::make_unique<GlobalSettingStation>(); + } + return *_instance; +} + +void GpgFrontend::UI::GlobalSettingStation::Sync() noexcept { + using namespace libconfig; + try { + ui_cfg.writeFile(ui_config_path.string().c_str()); + LOG(INFO) << _("Updated ui configuration successfully written to") + << ui_config_path; + + } catch (const FileIOException& fioex) { + LOG(ERROR) << _("I/O error while writing ui configuration file") + << ui_config_path; + } +} + +GpgFrontend::UI::GlobalSettingStation::GlobalSettingStation() noexcept { + using namespace boost::filesystem; + using namespace libconfig; + + el::Loggers::addFlag(el::LoggingFlag::AutoSpacing); + + LOG(INFO) << _("App Path") << app_path; + LOG(INFO) << _("App Configure Path") << app_configure_path; + LOG(INFO) << _("App Data Path") << app_data_path; + LOG(INFO) << _("App Log Path") << app_log_path; + LOG(INFO) << _("App Locale Path") << app_locale_path; + + if (!is_directory(app_configure_path)) create_directory(app_configure_path); + + if (!is_directory(app_data_path)) create_directory(app_data_path); + + if (!is_directory(app_log_path)) create_directory(app_log_path); + + if (!is_directory(ui_config_dir_path)) create_directory(ui_config_dir_path); + + if (!exists(ui_config_path)) { + try { + this->ui_cfg.writeFile(ui_config_path.string().c_str()); + LOG(INFO) << _("UserInterface configuration successfully written to") + << ui_config_path; + + } catch (const FileIOException& fioex) { + LOG(ERROR) + << _("I/O error while writing UserInterface configuration file") + << ui_config_path; + } + } else { + try { + this->ui_cfg.readFile(ui_config_path.string().c_str()); + LOG(INFO) << _("UserInterface configuration successfully read from") + << ui_config_path; + } catch (const FileIOException& fioex) { + LOG(ERROR) << _("I/O error while reading UserInterface configure file"); + } catch (const ParseException& pex) { + LOG(ERROR) << _("Parse error at ") << pex.getFile() << ":" + << pex.getLine() << " - " << pex.getError(); + } + } +} diff --git a/src/ui/settings/GlobalSettingStation.h b/src/ui/settings/GlobalSettingStation.h new file mode 100644 index 00000000..ef2c6a9a --- /dev/null +++ b/src/ui/settings/GlobalSettingStation.h @@ -0,0 +1,90 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_GLOBALSETTINGSTATION_H +#define GPGFRONTEND_GLOBALSETTINGSTATION_H + +#include <boost/filesystem/operations.hpp> +#include <boost/filesystem/path.hpp> + +#include "ui/GpgFrontendUI.h" + +namespace GpgFrontend::UI { + +class GlobalSettingStation : public QObject { + Q_OBJECT + public: + static GlobalSettingStation& GetInstance(); + + GlobalSettingStation() noexcept; + + libconfig::Setting& GetUISettings() noexcept { return ui_cfg.getRoot(); } + + [[nodiscard]] boost::filesystem::path GetAppDir() const { return app_path; } + + [[nodiscard]] boost::filesystem::path GetLogDir() const { + return app_log_path; + } + + [[nodiscard]] boost::filesystem::path GetLocaleDir() const { + return app_locale_path; + } + + void Sync() noexcept; + + private: + // Program Location + boost::filesystem::path app_path = qApp->applicationDirPath().toStdString(); + + // Program Data Location + boost::filesystem::path app_data_path = + QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + .toStdString(); + + // Program Data Location + boost::filesystem::path app_log_path = app_data_path / "logs"; + + // Program Data Location + boost::filesystem::path app_locale_path = + RESOURCE_DIR_BOOST_PATH(app_path) / "locales"; + + // Program Configure Location + boost::filesystem::path app_configure_path = + QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation) + .toStdString(); + + // Configure File Directory Location + boost::filesystem::path ui_config_dir_path = + app_configure_path / "UserInterface"; + + // UI Configure File Location + boost::filesystem::path ui_config_path = ui_config_dir_path / "ui.cfg"; + + libconfig::Config ui_cfg; + + static std::unique_ptr<GlobalSettingStation> _instance; +}; +} // namespace GpgFrontend::UI + +#endif // GPGFRONTEND_GLOBALSETTINGSTATION_H diff --git a/src/ui/settings/SettingsAdvanced.cpp b/src/ui/settings/SettingsAdvanced.cpp index 30414250..b64ec8e9 100644 --- a/src/ui/settings/SettingsAdvanced.cpp +++ b/src/ui/settings/SettingsAdvanced.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -22,46 +22,51 @@ * */ -#include "ui/SettingsDialog.h" +#include "SettingsAdvanced.h" -AdvancedTab::AdvancedTab(QWidget *parent) -: QWidget(parent), appPath(qApp->applicationDirPath()), -settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", - QSettings::IniFormat) { - /***************************************** - * Steganography Box - *****************************************/ - auto *steganoBox = new QGroupBox(tr("Show Steganography Options")); - auto *steganoBoxLayout = new QHBoxLayout(); - steganoCheckBox = new QCheckBox(tr("Show Steganographic Options."), this); - steganoBoxLayout->addWidget(steganoCheckBox); - steganoBox->setLayout(steganoBoxLayout); +namespace GpgFrontend::UI { - auto *pubkeyExchangeBox = new QGroupBox(tr("Pubkey Exchange")); - auto *pubkeyExchangeBoxLayout = new QHBoxLayout(); - autoPubkeyExchangeCheckBox = new QCheckBox(tr("Auto Pubkey Exchange"), this); - pubkeyExchangeBoxLayout->addWidget(autoPubkeyExchangeCheckBox); - pubkeyExchangeBox->setLayout(pubkeyExchangeBoxLayout); +AdvancedTab::AdvancedTab(QWidget* parent) + : QWidget(parent), + appPath(qApp->applicationDirPath()), + settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", + QSettings::IniFormat) { + /***************************************** + * Steganography Box + *****************************************/ + auto* steganoBox = new QGroupBox(_("Show Steganography Options")); + auto* steganoBoxLayout = new QHBoxLayout(); + steganoCheckBox = new QCheckBox(_("Show Steganographic Options."), this); + steganoBoxLayout->addWidget(steganoCheckBox); + steganoBox->setLayout(steganoBoxLayout); - auto *mainLayout = new QVBoxLayout; - mainLayout->addWidget(steganoBox); - mainLayout->addWidget(pubkeyExchangeBox); - setSettings(); - mainLayout->addStretch(1); - setLayout(mainLayout); + auto* pubkeyExchangeBox = new QGroupBox(_("Pubkey Exchange")); + auto* pubkeyExchangeBoxLayout = new QHBoxLayout(); + autoPubkeyExchangeCheckBox = new QCheckBox(_("Auto Pubkey Exchange"), this); + pubkeyExchangeBoxLayout->addWidget(autoPubkeyExchangeCheckBox); + pubkeyExchangeBox->setLayout(pubkeyExchangeBoxLayout); + + auto* mainLayout = new QVBoxLayout; + mainLayout->addWidget(steganoBox); + mainLayout->addWidget(pubkeyExchangeBox); + setSettings(); + mainLayout->addStretch(1); + setLayout(mainLayout); } void AdvancedTab::setSettings() { - if (settings.value("advanced/steganography").toBool()) { - steganoCheckBox->setCheckState(Qt::Checked); - } - if (settings.value("advanced/autoPubkeyExchange").toBool()) { - autoPubkeyExchangeCheckBox->setCheckState(Qt::Checked); - } + if (settings.value("advanced/steganography").toBool()) { + steganoCheckBox->setCheckState(Qt::Checked); + } + if (settings.value("advanced/autoPubkeyExchange").toBool()) { + autoPubkeyExchangeCheckBox->setCheckState(Qt::Checked); + } } void AdvancedTab::applySettings() { - settings.setValue("advanced/steganography", steganoCheckBox->isChecked()); - settings.setValue("advanced/autoPubkeyExchange", autoPubkeyExchangeCheckBox->isChecked()); + settings.setValue("advanced/steganography", steganoCheckBox->isChecked()); + settings.setValue("advanced/autoPubkeyExchange", + autoPubkeyExchangeCheckBox->isChecked()); } +} // namespace GpgFrontend::UI diff --git a/src/ui/settings/SettingsAdvanced.h b/src/ui/settings/SettingsAdvanced.h new file mode 100644 index 00000000..d8ec8089 --- /dev/null +++ b/src/ui/settings/SettingsAdvanced.h @@ -0,0 +1,54 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_SETTINGSADVANCED_H +#define GPGFRONTEND_SETTINGSADVANCED_H + +#include "ui/GpgFrontendUI.h" + +namespace GpgFrontend::UI { +class AdvancedTab : public QWidget { + Q_OBJECT + + public: + explicit AdvancedTab(QWidget* parent = nullptr); + + void setSettings(); + + void applySettings(); + + private: + QString appPath; + QSettings settings; + + QCheckBox* steganoCheckBox; + QCheckBox* autoPubkeyExchangeCheckBox; + + signals: + + void signalRestartNeeded(bool needed); +}; +} // namespace GpgFrontend::UI + +#endif // GPGFRONTEND_SETTINGSADVANCED_H diff --git a/src/ui/settings/SettingsAppearance.cpp b/src/ui/settings/SettingsAppearance.cpp index aeb7ed70..49dc349c 100644 --- a/src/ui/settings/SettingsAppearance.cpp +++ b/src/ui/settings/SettingsAppearance.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -22,84 +22,85 @@ * */ -#include "ui/SettingsDialog.h" - -AppearanceTab::AppearanceTab(QWidget *parent) -: QWidget(parent), appPath(qApp->applicationDirPath()), -settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", - QSettings::IniFormat) { - /***************************************** - * Icon-Size-Box - *****************************************/ - auto *iconSizeBox = new QGroupBox(tr("Iconsize")); - iconSizeGroup = new QButtonGroup(); - iconSizeSmall = new QRadioButton(tr("small")); - iconSizeMedium = new QRadioButton(tr("medium")); - iconSizeLarge = new QRadioButton(tr("large")); - - iconSizeGroup->addButton(iconSizeSmall, 1); - iconSizeGroup->addButton(iconSizeMedium, 2); - iconSizeGroup->addButton(iconSizeLarge, 3); - - auto *iconSizeBoxLayout = new QHBoxLayout(); - iconSizeBoxLayout->addWidget(iconSizeSmall); - iconSizeBoxLayout->addWidget(iconSizeMedium); - iconSizeBoxLayout->addWidget(iconSizeLarge); - - iconSizeBox->setLayout(iconSizeBoxLayout); - - /***************************************** - * Icon-Style-Box - *****************************************/ - auto *iconStyleBox = new QGroupBox(tr("Iconstyle")); - iconStyleGroup = new QButtonGroup(); - iconTextButton = new QRadioButton(tr("just text")); - iconIconsButton = new QRadioButton(tr("just icons")); - iconAllButton = new QRadioButton(tr("text and icons")); - - iconStyleGroup->addButton(iconTextButton, 1); - iconStyleGroup->addButton(iconIconsButton, 2); - iconStyleGroup->addButton(iconAllButton, 3); - - auto *iconStyleBoxLayout = new QHBoxLayout(); - iconStyleBoxLayout->addWidget(iconTextButton); - iconStyleBoxLayout->addWidget(iconIconsButton); - iconStyleBoxLayout->addWidget(iconAllButton); - - iconStyleBox->setLayout(iconStyleBoxLayout); - - /***************************************** - * Window-Size-Box - *****************************************/ - auto *windowSizeBox = new QGroupBox(tr("Windowstate")); - auto *windowSizeBoxLayout = new QHBoxLayout(); - windowSizeCheckBox = - new QCheckBox(tr("Save window size and position on exit."), this); - windowSizeBoxLayout->addWidget(windowSizeCheckBox); - windowSizeBox->setLayout(windowSizeBoxLayout); - - /***************************************** - * Info-Board-Font-Size-Box - *****************************************/ - - auto *infoBoardBox = new QGroupBox(tr("Information Board")); - auto *infoBoardLayout = new QHBoxLayout(); - infoBoardFontSizeSpin = new QSpinBox(); - infoBoardFontSizeSpin->setRange(9, 18); - infoBoardFontSizeSpin->setValue(10); - infoBoardFontSizeSpin->setSingleStep(1); - infoBoardLayout->addWidget(new QLabel(tr(" Front Size"))); - infoBoardLayout->addWidget(infoBoardFontSizeSpin); - infoBoardBox->setLayout(infoBoardLayout); - - auto *mainLayout = new QVBoxLayout; - mainLayout->addWidget(iconSizeBox); - mainLayout->addWidget(iconStyleBox); - mainLayout->addWidget(windowSizeBox); - mainLayout->addWidget(infoBoardBox); - mainLayout->addStretch(1); - setSettings(); - setLayout(mainLayout); +#include "SettingsAppearance.h" + +#include "GlobalSettingStation.h" + +namespace GpgFrontend::UI { + +AppearanceTab::AppearanceTab(QWidget* parent) : QWidget(parent) { + /***************************************** + * Icon-Size-Box + *****************************************/ + auto* iconSizeBox = new QGroupBox(_("Icon Size")); + iconSizeGroup = new QButtonGroup(); + iconSizeSmall = new QRadioButton(_("small")); + iconSizeMedium = new QRadioButton(_("medium")); + iconSizeLarge = new QRadioButton(_("large")); + + iconSizeGroup->addButton(iconSizeSmall, 1); + iconSizeGroup->addButton(iconSizeMedium, 2); + iconSizeGroup->addButton(iconSizeLarge, 3); + + auto* iconSizeBoxLayout = new QHBoxLayout(); + iconSizeBoxLayout->addWidget(iconSizeSmall); + iconSizeBoxLayout->addWidget(iconSizeMedium); + iconSizeBoxLayout->addWidget(iconSizeLarge); + + iconSizeBox->setLayout(iconSizeBoxLayout); + + /***************************************** + * Icon-Style-Box + *****************************************/ + auto* iconStyleBox = new QGroupBox(_("Icon Style")); + iconStyleGroup = new QButtonGroup(); + iconTextButton = new QRadioButton(_("just text")); + iconIconsButton = new QRadioButton(_("just icons")); + iconAllButton = new QRadioButton(_("text and icons")); + + iconStyleGroup->addButton(iconTextButton, 1); + iconStyleGroup->addButton(iconIconsButton, 2); + iconStyleGroup->addButton(iconAllButton, 3); + + auto* iconStyleBoxLayout = new QHBoxLayout(); + iconStyleBoxLayout->addWidget(iconTextButton); + iconStyleBoxLayout->addWidget(iconIconsButton); + iconStyleBoxLayout->addWidget(iconAllButton); + + iconStyleBox->setLayout(iconStyleBoxLayout); + + /***************************************** + * Window-Size-Box + *****************************************/ + auto* windowSizeBox = new QGroupBox(_("Window State")); + auto* windowSizeBoxLayout = new QHBoxLayout(); + windowSizeCheckBox = + new QCheckBox(_("Save window size and position on exit."), this); + windowSizeBoxLayout->addWidget(windowSizeCheckBox); + windowSizeBox->setLayout(windowSizeBoxLayout); + + /***************************************** + * Info-Board-Font-Size-Box + *****************************************/ + + auto* infoBoardBox = new QGroupBox(_("Information Board")); + auto* infoBoardLayout = new QHBoxLayout(); + infoBoardFontSizeSpin = new QSpinBox(); + infoBoardFontSizeSpin->setRange(9, 18); + infoBoardFontSizeSpin->setValue(10); + infoBoardFontSizeSpin->setSingleStep(1); + infoBoardLayout->addWidget(new QLabel(_("Font Size in Information Board"))); + infoBoardLayout->addWidget(infoBoardFontSizeSpin); + infoBoardBox->setLayout(infoBoardLayout); + + auto* mainLayout = new QVBoxLayout; + mainLayout->addWidget(iconSizeBox); + mainLayout->addWidget(iconStyleBox); + mainLayout->addWidget(windowSizeBox); + mainLayout->addWidget(infoBoardBox); + mainLayout->addStretch(1); + setSettings(); + setLayout(mainLayout); } /********************************** @@ -108,47 +109,70 @@ settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", * appropriately **********************************/ void AppearanceTab::setSettings() { - - // Iconsize - QSize iconSize = settings.value("toolbar/iconsize", QSize(24, 24)).toSize(); - switch (iconSize.height()) { - case 12: - iconSizeSmall->setChecked(true); - break; - case 24: - iconSizeMedium->setChecked(true); - break; - case 32: - iconSizeLarge->setChecked(true); - break; - } - // Iconstyle - Qt::ToolButtonStyle iconStyle = static_cast<Qt::ToolButtonStyle>( - settings.value("toolbar/iconstyle", Qt::ToolButtonTextUnderIcon) - .toUInt()); - switch (iconStyle) { - case Qt::ToolButtonTextOnly: - iconTextButton->setChecked(true); - break; - case Qt::ToolButtonIconOnly: - iconIconsButton->setChecked(true); - break; - case Qt::ToolButtonTextUnderIcon: - iconAllButton->setChecked(true); - break; - default: - break; + auto& settings = GlobalSettingStation::GetInstance().GetUISettings(); + + try { + int width = settings.lookup("window.icon_size.width"); + int height = settings.lookup("window.icon_size.height"); + + auto icon_size = QSize(width, height); + + switch (icon_size.height()) { + case 12: + iconSizeSmall->setChecked(true); + break; + case 24: + iconSizeMedium->setChecked(true); + break; + case 32: + iconSizeLarge->setChecked(true); + break; } - // Window Save and Position - if (settings.value("window/windowSave").toBool()) - windowSizeCheckBox->setCheckState(Qt::Checked); + } catch (...) { + LOG(ERROR) << _("Setting Operation Error") << _("icon_size"); + } + + // icon_style + try { + int s_icon_style = settings.lookup("window.icon_style"); + auto icon_style = static_cast<Qt::ToolButtonStyle>(s_icon_style); + + switch (icon_style) { + case Qt::ToolButtonTextOnly: + iconTextButton->setChecked(true); + break; + case Qt::ToolButtonIconOnly: + iconIconsButton->setChecked(true); + break; + case Qt::ToolButtonTextUnderIcon: + iconAllButton->setChecked(true); + break; + default: + break; + } - // infoBoardFontSize - auto infoBoardFontSize = settings.value("informationBoard/fontSize", 10).toInt(); - if (infoBoardFontSize < 9 || infoBoardFontSize > 18) - infoBoardFontSize = 10; - infoBoardFontSizeSpin->setValue(infoBoardFontSize); + } catch (...) { + LOG(ERROR) << _("Setting Operation Error") << _("icon_style"); + } + + // Window Save and Position + try { + bool window_save = settings.lookup("window.window_save"); + if (window_save) windowSizeCheckBox->setCheckState(Qt::Checked); + + } catch (...) { + LOG(ERROR) << _("Setting Operation Error") << _("window_save"); + } + + // info board font size + try { + int info_font_size = settings.lookup("window.info_font_size"); + if (info_font_size < 9 || info_font_size > 18) info_font_size = 10; + infoBoardFontSizeSpin->setValue(info_font_size); + } catch (...) { + LOG(ERROR) << _("Setting Operation Error") << _("info_font_size"); + } } /*********************************** @@ -156,32 +180,70 @@ void AppearanceTab::setSettings() { * write them to settings-file *************************************/ void AppearanceTab::applySettings() { - switch (iconSizeGroup->checkedId()) { - case 1: - settings.setValue("toolbar/iconsize", QSize(12, 12)); - break; - case 2: - settings.setValue("toolbar/iconsize", QSize(24, 24)); - break; - case 3: - settings.setValue("toolbar/iconsize", QSize(32, 32)); - break; - } - - switch (iconStyleGroup->checkedId()) { - case 1: - settings.setValue("toolbar/iconstyle", Qt::ToolButtonTextOnly); - break; - case 2: - settings.setValue("toolbar/iconstyle", Qt::ToolButtonIconOnly); - break; - case 3: - settings.setValue("toolbar/iconstyle", Qt::ToolButtonTextUnderIcon); - break; - } - - settings.setValue("window/windowSave", windowSizeCheckBox->isChecked()); - - settings.setValue("informationBoard/fontSize", infoBoardFontSizeSpin->value()); + auto& settings = + GpgFrontend::UI::GlobalSettingStation::GetInstance().GetUISettings(); + + if (!settings.exists("window") || + settings.lookup("window").getType() != libconfig::Setting::TypeGroup) + settings.add("window", libconfig::Setting::TypeGroup); + + auto& window = settings["window"]; + + int icon_size = 24; + switch (iconSizeGroup->checkedId()) { + case 1: + icon_size = 12; + break; + case 2: + icon_size = 24; + break; + case 3: + icon_size = 32; + break; + } + + if (!window.exists("icon_size")) { + auto& icon_size_settings = + window.add("icon_size", libconfig::Setting::TypeGroup); + icon_size_settings.add("width", libconfig::Setting::TypeInt) = icon_size; + icon_size_settings.add("height", libconfig::Setting::TypeInt) = icon_size; + } else { + window["icon_size"]["width"] = icon_size; + window["icon_size"]["height"] = icon_size; + } + + auto icon_style = Qt::ToolButtonTextUnderIcon; + switch (iconStyleGroup->checkedId()) { + case 1: + icon_style = Qt::ToolButtonTextOnly; + break; + case 2: + icon_style = Qt::ToolButtonIconOnly; + break; + case 3: + icon_style = Qt::ToolButtonTextUnderIcon; + break; + } + + if (!window.exists("icon_style")) { + window.add("icon_style", libconfig::Setting::TypeInt) = icon_style; + } else { + window["icon_style"] = icon_style; + } + + if (!window.exists("window_save")) { + window.add("window_save", libconfig::Setting::TypeBoolean) = + windowSizeCheckBox->isChecked(); + } else { + window["window_save"] = windowSizeCheckBox->isChecked(); + } + + if (!window.exists("info_font_size")) { + window.add("info_font_size", libconfig::Setting::TypeBoolean) = + infoBoardFontSizeSpin->value(); + } else { + window["info_font_size"] = infoBoardFontSizeSpin->value(); + } } +} // namespace GpgFrontend::UI diff --git a/src/ui/settings/SettingsAppearance.h b/src/ui/settings/SettingsAppearance.h new file mode 100644 index 00000000..c0a0247b --- /dev/null +++ b/src/ui/settings/SettingsAppearance.h @@ -0,0 +1,61 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_SETTINGSAPPEARANCE_H +#define GPGFRONTEND_SETTINGSAPPEARANCE_H + +#include "ui/GpgFrontendUI.h" + +namespace GpgFrontend::UI { + +class AppearanceTab : public QWidget { + Q_OBJECT + + public: + explicit AppearanceTab(QWidget* parent = nullptr); + + void setSettings(); + + void applySettings(); + + private: + QButtonGroup* iconStyleGroup; + QRadioButton* iconSizeSmall; + QRadioButton* iconSizeMedium; + QRadioButton* iconSizeLarge; + QButtonGroup* iconSizeGroup; + QRadioButton* iconTextButton; + QRadioButton* iconIconsButton; + QRadioButton* iconAllButton; + QSpinBox* infoBoardFontSizeSpin; + QCheckBox* windowSizeCheckBox; + + signals: + + void signalRestartNeeded(bool needed); +}; + +} // namespace GpgFrontend::UI + +#endif // GPGFRONTEND_SETTINGSAPPEARANCE_H diff --git a/src/ui/settings/SettingsDialog.cpp b/src/ui/settings/SettingsDialog.cpp index 0ca188f7..fcef70c7 100644 --- a/src/ui/settings/SettingsDialog.cpp +++ b/src/ui/settings/SettingsDialog.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -22,184 +22,136 @@ * */ -#include "ui/SettingsDialog.h" -#include "ui/WaitingDialog.h" - -SettingsDialog::SettingsDialog(GpgME::GpgContext *ctx, QWidget *parent) - : QDialog(parent) { - mCtx = ctx; - tabWidget = new QTabWidget; - generalTab = new GeneralTab(mCtx); - appearanceTab = new AppearanceTab; - sendMailTab = new SendMailTab; - keyserverTab = new KeyserverTab; - advancedTab = new AdvancedTab; - gpgPathsTab = new GpgPathsTab; - - tabWidget->addTab(generalTab, tr("General")); - tabWidget->addTab(appearanceTab, tr("Appearance")); - tabWidget->addTab(sendMailTab, tr("Send Mail")); - tabWidget->addTab(keyserverTab, tr("Key Server")); - // tabWidget->addTab(gpgPathsTab, tr("Gpg paths")); - tabWidget->addTab(advancedTab, tr("Advanced")); - - buttonBox = - new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - - connect(buttonBox, SIGNAL(accepted()), this, SLOT(slotAccept())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); - - auto *mainLayout = new QVBoxLayout; - mainLayout->addWidget(tabWidget); - mainLayout->stretch(0); - mainLayout->addWidget(buttonBox); - mainLayout->stretch(0); - setLayout(mainLayout); - - setWindowTitle(tr("Settings")); - - // slots for handling the restartneeded member - this->slotSetRestartNeeded(false); - connect(generalTab, SIGNAL(signalRestartNeeded(bool)), this, - SLOT(slotSetRestartNeeded(bool))); - connect(appearanceTab, SIGNAL(signalRestartNeeded(bool)), this, - SLOT(slotSetRestartNeeded(bool))); - connect(sendMailTab, SIGNAL(signalRestartNeeded(bool)), this, - SLOT(slotSetRestartNeeded(bool))); - connect(keyserverTab, SIGNAL(signalRestartNeeded(bool)), this, - SLOT(slotSetRestartNeeded(bool))); - connect(advancedTab, SIGNAL(signalRestartNeeded(bool)), this, - SLOT(slotSetRestartNeeded(bool))); - - connect(this, SIGNAL(signalRestartNeeded(bool)), parent, - SLOT(slotSetRestartNeeded(bool))); - - this->resize(480, 640); - this->show(); -} +#include "SettingsDialog.h" -bool SettingsDialog::getRestartNeeded() const { return this->restartNeeded; } +#include "GlobalSettingStation.h" +#include "SettingsAdvanced.h" +#include "SettingsAppearance.h" +#include "SettingsGeneral.h" +#include "SettingsKeyServer.h" -void SettingsDialog::slotSetRestartNeeded(bool needed) { - this->restartNeeded = needed; -} +#ifdef SMTP_SUPPORT +#include "SettingsSendMail.h" +#endif -void SettingsDialog::slotAccept() { - generalTab->applySettings(); - sendMailTab->applySettings(); - appearanceTab->applySettings(); - keyserverTab->applySettings(); - advancedTab->applySettings(); - gpgPathsTab->applySettings(); - if (getRestartNeeded()) { - emit signalRestartNeeded(true); - } - close(); -} +namespace GpgFrontend::UI { -// http://www.informit.com/articles/article.aspx?p=1405555&seqNum=3 -// http://developer.qt.nokia.com/wiki/How_to_create_a_multi_language_application -QHash<QString, QString> SettingsDialog::listLanguages() { - QHash<QString, QString> languages; +SettingsDialog::SettingsDialog(QWidget* parent) : QDialog(parent) { + tabWidget = new QTabWidget; + generalTab = new GeneralTab(); + appearanceTab = new AppearanceTab; +#ifdef SMTP_SUPPORT + sendMailTab = new SendMailTab; +#endif + keyserverTab = new KeyserverTab; +#ifdef ADVANCED_SUPPORT + advancedTab = new AdvancedTab; +#endif - languages.insert("", tr("System Default")); + tabWidget->addTab(generalTab, _("General")); + tabWidget->addTab(appearanceTab, _("Appearance")); +#ifdef SMTP_SUPPORT + tabWidget->addTab(sendMailTab, _("Send Mail")); +#endif + tabWidget->addTab(keyserverTab, _("Key Server")); + // tabWidget->addTab(gpgPathsTab, _("Gpg paths")); +#ifdef ADVANCED_SUPPORT + tabWidget->addTab(advancedTab, _("Advanced")); +#endif - QString appPath = qApp->applicationDirPath(); - QDir qmDir = QDir(RESOURCE_DIR(appPath) + "/ts/"); - QStringList fileNames = qmDir.entryList(QStringList("gpgfrontend_*.qm")); + buttonBox = + new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + + connect(buttonBox, SIGNAL(accepted()), this, SLOT(slotAccept())); + connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + + auto* mainLayout = new QVBoxLayout; + mainLayout->addWidget(tabWidget); + mainLayout->stretch(0); + mainLayout->addWidget(buttonBox); + mainLayout->stretch(0); + setLayout(mainLayout); + + setWindowTitle(_("Settings")); + + // slots for handling the restartneeded member + this->slotSetRestartNeeded(false); + connect(generalTab, SIGNAL(signalRestartNeeded(bool)), this, + SLOT(slotSetRestartNeeded(bool))); + connect(appearanceTab, SIGNAL(signalRestartNeeded(bool)), this, + SLOT(slotSetRestartNeeded(bool))); +#ifdef SMTP_SUPPORT + connect(sendMailTab, SIGNAL(signalRestartNeeded(bool)), this, + SLOT(slotSetRestartNeeded(bool))); +#endif + connect(keyserverTab, SIGNAL(signalRestartNeeded(bool)), this, + SLOT(slotSetRestartNeeded(bool))); +#ifdef ADVANCED_SUPPORT + connect(advancedTab, SIGNAL(signalRestartNeeded(bool)), this, + SLOT(slotSetRestartNeeded(bool))); +#endif - for (int i = 0; i < fileNames.size(); ++i) { - QString locale = fileNames[i]; - locale.truncate(locale.lastIndexOf('.')); - locale.remove(0, locale.indexOf('_') + 1); + connect(this, SIGNAL(signalRestartNeeded(bool)), parent, + SLOT(slotSetRestartNeeded(bool))); - // this works in qt 4.8 - QLocale qloc(locale); -#if QT_VERSION < 0x040800 - QString language = - QLocale::languageToString(qloc.language()) + " (" + locale + - ")"; //+ " (" + QLocale::languageToString(qloc.language()) + ")"; -#else - QString language = qloc.nativeLanguageName() + " (" + locale + ")"; -#endif - languages.insert(locale, language); - } - return languages; + this->resize(480, 640); + this->show(); } -GpgPathsTab::GpgPathsTab(QWidget *parent) - : QWidget(parent), appPath(qApp->applicationDirPath()), - settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", - QSettings::IniFormat) { - setSettings(); - - /***************************************** - * Keydb Box - *****************************************/ - auto *keydbBox = new QGroupBox(tr("Relative path to keydb")); - auto *keydbBoxLayout = new QGridLayout(); - - // Label containing the current keydbpath relative to default keydb path - keydbLabel = new QLabel(accKeydbPath, this); - - auto *keydbButton = new QPushButton("Change keydb path", this); - connect(keydbButton, SIGNAL(clicked()), this, SLOT(chooseKeydbDir())); - auto *keydbDefaultButton = new QPushButton("Set keydb to default path", this); - connect(keydbDefaultButton, SIGNAL(clicked()), this, - SLOT(setKeydbPathToDefault())); - - keydbBox->setLayout(keydbBoxLayout); - keydbBoxLayout->addWidget(new QLabel(tr("Current keydb path: ")), 1, 1); - keydbBoxLayout->addWidget(keydbLabel, 1, 2); - keydbBoxLayout->addWidget(keydbButton, 1, 3); - keydbBoxLayout->addWidget(keydbDefaultButton, 2, 3); - keydbBoxLayout->addWidget( - new QLabel(tr("<b>NOTE: </b> Gpg4usb will restart automatically if you " - "change the keydb path!")), - 3, 1, 1, 3); - - auto *mainLayout = new QVBoxLayout; - mainLayout->addWidget(keydbBox); - mainLayout->addStretch(1); - setLayout(mainLayout); +bool SettingsDialog::getRestartNeeded() const { return this->restartNeeded; } + +void SettingsDialog::slotSetRestartNeeded(bool needed) { + this->restartNeeded = needed; } -QString GpgPathsTab::getRelativePath(const QString &dir1, const QString &dir2) { - QDir dir(dir1); - QString s; +void SettingsDialog::slotAccept() { + generalTab->applySettings(); +#ifdef SMTP_SUPPORT + sendMailTab->applySettings(); +#endif + appearanceTab->applySettings(); + keyserverTab->applySettings(); +#ifdef ADVANCED_SUPPORT + advancedTab->applySettings(); +#endif - s = dir.relativeFilePath(dir2); - qDebug() << "relative path: " << s; - if (s.isEmpty()) { - s = "."; - } - return s; -} + // write settings to filesystem + GlobalSettingStation::GetInstance().Sync(); -void GpgPathsTab::setKeydbPathToDefault() { - accKeydbPath = "."; - keydbLabel->setText("."); + if (getRestartNeeded()) { + emit signalRestartNeeded(true); + } + close(); } -QString GpgPathsTab::chooseKeydbDir() { - QString dir = QFileDialog::getExistingDirectory( - this, tr("Choose keydb directory"), accKeydbPath, - QFileDialog::ShowDirsOnly); +QHash<QString, QString> SettingsDialog::listLanguages() { + QHash<QString, QString> languages; - accKeydbPath = getRelativePath(defKeydbPath, dir); - keydbLabel->setText(accKeydbPath); - return ""; -} + languages.insert(QString(), _("System Default")); -void GpgPathsTab::setSettings() { - defKeydbPath = qApp->applicationDirPath() + "/keydb"; + auto locale_path = GlobalSettingStation::GetInstance().GetLocaleDir(); - accKeydbPath = settings.value("gpgpaths/keydbpath").toString(); - if (accKeydbPath.isEmpty()) { - accKeydbPath = "."; - } -} + auto locale_dir = QDir(QString::fromStdString(locale_path.string()) ); + QStringList file_names = locale_dir.entryList(QStringList("*")); + + for (int i = 0; i < file_names.size(); ++i) { + QString locale = file_names[i]; + LOG(INFO) << "locale" << locale.toStdString(); + if (locale == "." || locale == "..") continue; -void GpgPathsTab::applySettings() { - settings.setValue("gpgpaths/keydbpath", accKeydbPath); + // this works in qt 4.8 + QLocale q_locale(locale); + if (q_locale.nativeCountryName().isEmpty()) continue; +#if QT_VERSION < 0x040800 + QString language = + QLocale::languageToString(q_locale.language()) + " (" + locale + + ")"; //+ " (" + QLocale::languageToString(q_locale.language()) + ")"; +#else + auto language = q_locale.nativeLanguageName() + " (" + locale + ")"; +#endif + languages.insert(locale, language); + } + return languages; } + +} // namespace GpgFrontend::UI diff --git a/src/ui/settings/SettingsDialog.h b/src/ui/settings/SettingsDialog.h new file mode 100755 index 00000000..b8277906 --- /dev/null +++ b/src/ui/settings/SettingsDialog.h @@ -0,0 +1,86 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef __SETTINGSDIALOG_H__ +#define __SETTINGSDIALOG_H__ + +#include "ui/GpgFrontendUI.h" +#include "ui/widgets/KeyList.h" + +namespace GpgFrontend::UI { + +class GeneralTab; + +#ifdef SMTP_SUPPORT +class SendMailTab; +#endif + +class AppearanceTab; +class KeyserverTab; + +#ifdef ADVANCED_SUPPORT +class AdvancedTab; +#endif + +class SettingsDialog : public QDialog { + Q_OBJECT + + public: + explicit SettingsDialog(QWidget* parent = nullptr); + + GeneralTab* generalTab; +#ifdef SMTP_SUPPORT + SendMailTab* sendMailTab; +#endif + AppearanceTab* appearanceTab; + KeyserverTab* keyserverTab; +#ifdef ADVANCED_SUPPORT + AdvancedTab* advancedTab; +#endif + + static QHash<QString, QString> listLanguages(); + + public slots: + + void slotAccept(); + + signals: + + void signalRestartNeeded(bool needed); + + private: + QTabWidget* tabWidget; + QDialogButtonBox* buttonBox; + bool restartNeeded{}; + + bool getRestartNeeded() const; + + private slots: + + void slotSetRestartNeeded(bool needed); +}; + +} // namespace GpgFrontend::UI + +#endif // __SETTINGSDIALOG_H__ diff --git a/src/ui/settings/SettingsGeneral.cpp b/src/ui/settings/SettingsGeneral.cpp index bec66154..98610e12 100644 --- a/src/ui/settings/SettingsGeneral.cpp +++ b/src/ui/settings/SettingsGeneral.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -22,122 +22,145 @@ * */ -#include "ui/SettingsDialog.h" -#include "ui/WaitingDialog.h" +#include "SettingsGeneral.h" + +#ifdef SERVER_SUPPORT #include "server/ComUtils.h" +#endif -#include "rapidjson/prettywriter.h" +#ifdef MULTI_LANG_SUPPORT +#include "SettingsDialog.h" +#endif -GeneralTab::GeneralTab(GpgME::GpgContext *ctx, QWidget *parent) - : QWidget(parent), appPath(qApp->applicationDirPath()), - settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", - QSettings::IniFormat) { - mCtx = ctx; - - /***************************************** - * GpgFrontend Server - *****************************************/ - auto *serverBox = new QGroupBox(tr("GpgFrontend Server")); - auto *serverBoxLayout = new QVBoxLayout(); - serverSelectBox = new QComboBox(); - serverBoxLayout->addWidget(serverSelectBox); - serverBoxLayout->addWidget(new QLabel( - tr("Server that provides short key and key exchange services"))); - - serverBox->setLayout(serverBoxLayout); - - /***************************************** - * Save-Checked-Keys-Box - *****************************************/ - auto *saveCheckedKeysBox = new QGroupBox(tr("Save Checked Keys")); - auto *saveCheckedKeysBoxLayout = new QHBoxLayout(); - saveCheckedKeysCheckBox = new QCheckBox( - tr("Save checked private keys on exit and restore them on next start."), - this); - saveCheckedKeysBoxLayout->addWidget(saveCheckedKeysCheckBox); - saveCheckedKeysBox->setLayout(saveCheckedKeysBoxLayout); - - /***************************************** - * Key-Impport-Confirmation Box - *****************************************/ - auto *importConfirmationBox = - new QGroupBox(tr("Confirm drag'n'drop key import")); - auto *importConfirmationBoxLayout = new QHBoxLayout(); - importConfirmationCheckBox = new QCheckBox( - tr("Import files dropped on the keylist without confirmation."), this); - importConfirmationBoxLayout->addWidget(importConfirmationCheckBox); - importConfirmationBox->setLayout(importConfirmationBoxLayout); - - /***************************************** - * Language Select Box - *****************************************/ - auto *langBox = new QGroupBox(tr("Language")); - auto *langBoxLayout = new QVBoxLayout(); - langSelectBox = new QComboBox; - lang = SettingsDialog::listLanguages(); - - for (const auto &l: lang) { langSelectBox->addItem(l); } - - langBoxLayout->addWidget(langSelectBox); - langBoxLayout->addWidget( - new QLabel(tr("<b>NOTE: </b> GpgFrontend will restart automatically if " - "you change the language!"))); - langBox->setLayout(langBoxLayout); - connect(langSelectBox, SIGNAL(currentIndexChanged(int)), this, - SLOT(slotLanguageChanged())); - - /***************************************** - * Own Key Select Box - *****************************************/ - auto *ownKeyBox = new QGroupBox(tr("Own key")); - auto *ownKeyBoxLayout = new QVBoxLayout(); - auto *ownKeyServiceTokenLayout = new QHBoxLayout(); - ownKeySelectBox = new QComboBox; - getServiceTokenButton = new QPushButton(tr("Get Service Token")); - serviceTokenLabel = new QLabel(tr("No Service Token Found")); - serviceTokenLabel->setAlignment(Qt::AlignCenter); - - ownKeyBox->setLayout(ownKeyBoxLayout); - mKeyList = new KeyList(mCtx); - - // Fill the keyid hashmap - keyIds.insert("", tr("<none>")); - - for (const auto &keyid : *mKeyList->getAllPrivateKeys()) { - auto key = mCtx->getKeyById(keyid); - if (!key.good) continue; - keyIds.insert(key.id, key.uids.first().uid); - } - for (const auto &k : keyIds.keys()) { - ownKeySelectBox->addItem(keyIds.find(k).value()); - keyIdsList.append(k); - } - connect(ownKeySelectBox, SIGNAL(currentIndexChanged(int)), this, - SLOT(slotOwnKeyIdChanged())); - connect(getServiceTokenButton, SIGNAL(clicked(bool)), this, - SLOT(slotGetServiceToken())); - - ownKeyBoxLayout->addWidget(new QLabel( - tr("Key pair for synchronization and identity authentication"))); - ownKeyBoxLayout->addWidget(ownKeySelectBox); - ownKeyBoxLayout->addLayout(ownKeyServiceTokenLayout); - ownKeyServiceTokenLayout->addWidget(getServiceTokenButton); - ownKeyServiceTokenLayout->addWidget(serviceTokenLabel); - ownKeyServiceTokenLayout->stretch(0); - - /***************************************** - * Mainlayout - *****************************************/ - auto *mainLayout = new QVBoxLayout; - mainLayout->addWidget(serverBox); - mainLayout->addWidget(saveCheckedKeysBox); - mainLayout->addWidget(importConfirmationBox); - mainLayout->addWidget(langBox); - mainLayout->addWidget(ownKeyBox); - - setSettings(); - mainLayout->addStretch(1); - setLayout(mainLayout); +#include "GlobalSettingStation.h" +#include "gpg/function/GpgKeyGetter.h" +#include "rapidjson/prettywriter.h" +#include "ui/widgets/KeyList.h" + +namespace GpgFrontend::UI { + +GeneralTab::GeneralTab(QWidget* parent) : QWidget(parent) { +#ifdef SERVER_SUPPORT + /***************************************** + * GpgFrontend Server + *****************************************/ + auto* serverBox = new QGroupBox(_("GpgFrontend Server")); + auto* serverBoxLayout = new QVBoxLayout(); + serverSelectBox = new QComboBox(); + serverBoxLayout->addWidget(serverSelectBox); + serverBoxLayout->addWidget(new QLabel( + _("Server that provides short key and key exchange services"))); + + serverBox->setLayout(serverBoxLayout); +#endif + + /***************************************** + * Save-Checked-Keys-Box + *****************************************/ + auto* saveCheckedKeysBox = new QGroupBox(_("Save Checked Keys")); + auto* saveCheckedKeysBoxLayout = new QHBoxLayout(); + saveCheckedKeysCheckBox = new QCheckBox( + _("Save checked private keys on exit and restore them on next start."), + this); + saveCheckedKeysBoxLayout->addWidget(saveCheckedKeysCheckBox); + saveCheckedKeysBox->setLayout(saveCheckedKeysBoxLayout); + + /***************************************** + * Key-Impport-Confirmation Box + *****************************************/ + auto* importConfirmationBox = + new QGroupBox(_("Confirm drag'n'drop key import")); + auto* importConfirmationBoxLayout = new QHBoxLayout(); + importConfirmationCheckBox = new QCheckBox( + _("Import files dropped on the Key List without confirmation."), this); + importConfirmationBoxLayout->addWidget(importConfirmationCheckBox); + importConfirmationBox->setLayout(importConfirmationBoxLayout); + +#ifdef MULTI_LANG_SUPPORT + /***************************************** + * Language Select Box + *****************************************/ + auto* langBox = new QGroupBox(_("Language")); + auto* langBoxLayout = new QVBoxLayout(); + langSelectBox = new QComboBox; + lang = SettingsDialog::listLanguages(); + + for (const auto& l : lang) { + langSelectBox->addItem(l); + } + + langBoxLayout->addWidget(langSelectBox); + langBoxLayout->addWidget(new QLabel( + "<b>" + QString(_("NOTE")) + _(": ") + "</b>" + + _("GpgFrontend will restart automatically if you change the language!"))); + langBox->setLayout(langBoxLayout); + connect(langSelectBox, SIGNAL(currentIndexChanged(int)), this, + SLOT(slotLanguageChanged())); +#endif + +#ifdef SERVER_SUPPORT + /***************************************** + * Own Key Select Box + *****************************************/ + auto* ownKeyBox = new QGroupBox(_("Own key")); + auto* ownKeyBoxLayout = new QVBoxLayout(); + auto* ownKeyServiceTokenLayout = new QHBoxLayout(); + ownKeySelectBox = new QComboBox; + getServiceTokenButton = new QPushButton(_("Get Service Token")); + serviceTokenLabel = new QLabel(_("No Service Token Found")); + serviceTokenLabel->setAlignment(Qt::AlignCenter); + + ownKeyBox->setLayout(ownKeyBoxLayout); + + mKeyList = new KeyList(); + + // Fill the keyid hashmap + keyIds.insert({QString(), "<none>"}); + + auto private_keys = mKeyList->getAllPrivateKeys(); + + for (const auto& keyid : *private_keys) { + auto key = GpgKeyGetter::GetInstance().GetKey(keyid); + if (!key.good()) continue; + keyIds.insert({key.id(), key.uids()->front().uid()}); + } + for (const auto& k : keyIds) { + ownKeySelectBox->addItem(QString::fromStdString(k.second)); + keyIdsList.push_back(k.first); + } + connect(ownKeySelectBox, SIGNAL(currentIndexChanged(int)), this, + SLOT(slotOwnKeyIdChanged())); + connect(getServiceTokenButton, SIGNAL(clicked(bool)), this, + SLOT(slotGetServiceToken())); + + ownKeyBoxLayout->addWidget(new QLabel( + _("Key pair for synchronization and identity authentication"))); + ownKeyBoxLayout->addWidget(ownKeySelectBox); + ownKeyBoxLayout->addLayout(ownKeyServiceTokenLayout); + ownKeyServiceTokenLayout->addWidget(getServiceTokenButton); + ownKeyServiceTokenLayout->addWidget(serviceTokenLabel); + ownKeyServiceTokenLayout->stretch(0); +#endif + + /***************************************** + * Mainlayout + *****************************************/ + auto* mainLayout = new QVBoxLayout; +#ifdef SERVER_SUPPORT + mainLayout->addWidget(serverBox); +#endif + mainLayout->addWidget(saveCheckedKeysBox); + mainLayout->addWidget(importConfirmationBox); +#ifdef MULTI_LANG_SUPPORT + mainLayout->addWidget(langBox); +#endif +#ifdef SERVER_SUPPORT + mainLayout->addWidget(ownKeyBox); +#endif + + setSettings(); + mainLayout->addStretch(1); + setLayout(mainLayout); } /********************************** @@ -146,55 +169,76 @@ GeneralTab::GeneralTab(GpgME::GpgContext *ctx, QWidget *parent) * appropriately **********************************/ void GeneralTab::setSettings() { - // Keysaving - if (settings.value("keys/saveKeyChecked").toBool()) { - saveCheckedKeysCheckBox->setCheckState(Qt::Checked); - } - - auto serverList = settings.value("general/gpgfrontendServerList").toStringList(); - if (serverList.empty()) { - serverList.append("service.gpgfrontend.pub"); - serverList.append("localhost"); - } - for (const auto &s : serverList) - serverSelectBox->addItem(s); - - qDebug() << "Current Gpgfrontend Server" << settings.value("general/currentGpgfrontendServer").toString(); - serverSelectBox->setCurrentText(settings.value("general/currentGpgfrontendServer", - "service.gpgfrontend.pub").toString()); - - connect(serverSelectBox, QOverload<const QString &>::of(&QComboBox::currentTextChanged), - this, [&](const QString ¤t) -> void { - settings.setValue("general/currentGpgfrontendServer", current); - }); - - // Language setting - QString langKey = settings.value("int/lang").toString(); - QString langValue = lang.value(langKey); - if (langKey != "") { - langSelectBox->setCurrentIndex(langSelectBox->findText(langValue)); - } - - QString own_key_id = settings.value("general/ownKeyId").toString(); - qDebug() << "OwnKeyId" << own_key_id; - if (own_key_id.isEmpty()) { - ownKeySelectBox->setCurrentText("<none>"); + auto& settings = GlobalSettingStation::GetInstance().GetUISettings(); + try { + bool save_key_checked = settings.lookup("general.save_key_checked"); + if (save_key_checked) saveCheckedKeysCheckBox->setCheckState(Qt::Checked); + } catch (...) { + LOG(ERROR) << _("Setting Operation Error") << _("save_key_checked"); + } + +#ifdef SERVER_SUPPORT + auto serverList = + settings.value("general/gpgfrontendServerList").toStringList(); + if (serverList.empty()) { + serverList.append("service.gpgfrontend.pub"); + serverList.append("localhost"); + } + for (const auto& s : serverList) serverSelectBox->addItem(s); + + qDebug() << "Current Gpgfrontend Server" + << settings.value("general/currentGpgfrontendServer").toString(); + serverSelectBox->setCurrentText( + settings + .value("general/currentGpgfrontendServer", "service.gpgfrontend.pub") + .toString()); + + connect(serverSelectBox, + QOverload<const QString&>::of(&QComboBox::currentTextChanged), this, + [&](const QString& current) -> void { + settings.setValue("general/currentGpgfrontendServer", current); + }); +#endif + +#ifdef MULTI_LANG_SUPPORT + try { + std::string lang_key = settings.lookup("general.lang"); + QString lang_value = lang.value(lang_key.c_str()); + LOG(INFO) << "lang settings current" << lang_value.toStdString(); + if (!lang.empty()) { + langSelectBox->setCurrentIndex(langSelectBox->findText(lang_value)); } else { - const auto text = keyIds.find(own_key_id).value(); - qDebug() << "OwnKey" << own_key_id << text; - ownKeySelectBox->setCurrentText(text); - } - - serviceToken = settings.value("general/serviceToken").toString(); - qDebug() << "Load Service Token" << serviceToken; - if (!serviceToken.isEmpty()) { - serviceTokenLabel->setText(serviceToken); - } - - // Get own key information from keydb/gpg.conf (if contained) - if (settings.value("general/confirmImportKeys", Qt::Checked).toBool()) { - importConfirmationCheckBox->setCheckState(Qt::Checked); + langSelectBox->setCurrentIndex(0); } + } catch (...) { + LOG(ERROR) << _("Setting Operation Error") << _("lang"); + } +#endif + +#ifdef SERVER_SUPPORT + auto own_key_id = settings.value("general/ownKeyId").toString().toStdString(); + if (own_key_id.empty()) { + ownKeySelectBox->setCurrentText("<none>"); + } else { + const auto uid = keyIds.find(own_key_id)->second; + ownKeySelectBox->setCurrentText(QString::fromStdString(uid)); + } + + serviceToken = + settings.value("general/serviceToken").toString().toStdString(); + if (!serviceToken.empty()) { + serviceTokenLabel->setText(QString::fromStdString(serviceToken)); + } +#endif + + try { + bool confirm_import_keys = settings.lookup("general.confirm_import_keys"); + LOG(INFO) << "confirm_import_keys" << confirm_import_keys; + if (confirm_import_keys) + importConfirmationCheckBox->setCheckState(Qt::Checked); + } catch (...) { + LOG(ERROR) << _("Setting Operation Error") << _("confirm_import_keys"); + } } /*********************************** @@ -202,157 +246,194 @@ void GeneralTab::setSettings() { * write them to settings-file *************************************/ void GeneralTab::applySettings() { - settings.setValue("keys/saveKeyChecked", - saveCheckedKeysCheckBox->isChecked()); - - qDebug() << "serverSelectBox currentText" << serverSelectBox->currentText(); - settings.setValue("general/currentGpgfrontendServer", - serverSelectBox->currentText()); - - auto *serverList = new QStringList(); - for (int i = 0; i < serverSelectBox->count(); i++) - serverList->append(serverSelectBox->itemText(i)); - settings.setValue("general/gpgfrontendServerList", - *serverList); - delete serverList; - - settings.setValue("int/lang", lang.key(langSelectBox->currentText())); - - settings.setValue("general/ownKeyId", - keyIdsList[ownKeySelectBox->currentIndex()]); - - settings.setValue("general/serviceToken", - serviceToken); - - settings.setValue("general/confirmImportKeys", - importConfirmationCheckBox->isChecked()); + auto& settings = + GpgFrontend::UI::GlobalSettingStation::GetInstance().GetUISettings(); + + if (!settings.exists("general") || + settings.lookup("general").getType() != libconfig::Setting::TypeGroup) + settings.add("general", libconfig::Setting::TypeGroup); + + auto& general = settings["general"]; + + if (!general.exists("save_key_checked")) + general.add("save_key_checked", libconfig::Setting::TypeBoolean) = + saveCheckedKeysCheckBox->isChecked(); + else { + general["save_key_checked"] = saveCheckedKeysCheckBox->isChecked(); + } + +#ifdef SERVER_SUPPORT + qDebug() << "serverSelectBox currentText" << serverSelectBox->currentText(); + settings.setValue("general/currentGpgfrontendServer", + serverSelectBox->currentText()); + + auto* serverList = new QStringList(); + for (int i = 0; i < serverSelectBox->count(); i++) + serverList->append(serverSelectBox->itemText(i)); + settings.setValue("general/gpgfrontendServerList", *serverList); + delete serverList; +#endif + +#ifdef MULTI_LANG_SUPPORT + if (!general.exists("lang")) + general.add("lang", libconfig::Setting::TypeBoolean) = + lang.key(langSelectBox->currentText()).toStdString(); + else { + general["lang"] = lang.key(langSelectBox->currentText()).toStdString(); + } +#endif + +#ifdef SERVER_SUPPORT + settings.setValue( + "general/ownKeyId", + QString::fromStdString(keyIdsList[ownKeySelectBox->currentIndex()])); + + settings.setValue("general/serviceToken", + QString::fromStdString(serviceToken)); +#endif + + if (!general.exists("confirm_import_keys")) + general.add("confirm_import_keys", libconfig::Setting::TypeBoolean) = + importConfirmationCheckBox->isChecked(); + else { + general["confirm_import_keys"] = importConfirmationCheckBox->isChecked(); + } } +#ifdef MULTI_LANG_SUPPORT void GeneralTab::slotLanguageChanged() { emit signalRestartNeeded(true); } +#endif +#ifdef SERVER_SUPPORT void GeneralTab::slotOwnKeyIdChanged() { - // Set ownKeyId to currently selected - this->serviceTokenLabel->setText(tr("No Service Token Found")); - serviceToken.clear(); + // Set ownKeyId to currently selected + this->serviceTokenLabel->setText(_("No Service Token Found")); + serviceToken.clear(); } +#endif +#ifdef SERVER_SUPPORT void GeneralTab::slotGetServiceToken() { + auto utils = new ComUtils(this); - auto utils = new ComUtils(this); + QUrl reqUrl(utils->getUrl(ComUtils::GetServiceToken)); + QNetworkRequest request(reqUrl); + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); - QUrl reqUrl(utils->getUrl(ComUtils::GetServiceToken)); - QNetworkRequest request(reqUrl); - request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); + const auto keyId = keyIdsList[ownKeySelectBox->currentIndex()]; + qDebug() << "KeyId" << keyIdsList[ownKeySelectBox->currentIndex()]; - const auto keyId = keyIdsList[ownKeySelectBox->currentIndex()]; + if (keyId.isEmpty()) { + QMessageBox::critical( + this, _("Invalid Operation"), + _("Own Key can not be None while getting service token.")); + return; + } - qDebug() << "KeyId" << keyIdsList[ownKeySelectBox->currentIndex()]; + QStringList selectedKeyIds(keyIdsList[ownKeySelectBox->currentIndex()]); - if (keyId.isEmpty()) { - QMessageBox::critical(this, tr("Invalid Operation"), - tr("Own Key can not be None while getting service token.")); - return; - } + QByteArray keyDataBuf; + mCtx->exportKeys(&selectedKeyIds, &keyDataBuf); - QStringList selectedKeyIds(keyIdsList[ownKeySelectBox->currentIndex()]); + GpgKey key = mCtx->getKeyRefById(keyId); - QByteArray keyDataBuf; - mCtx->exportKeys(&selectedKeyIds, &keyDataBuf); + if (!key.good) { + QMessageBox::critical(this, _("Error"), _("Key Not Exists")); + return; + } - GpgKey key = mCtx->getKeyById(keyId); + qDebug() << "keyDataBuf" << keyDataBuf; - if (!key.good) { - QMessageBox::critical(this, tr("Error"), - tr("Key Not Exists")); - return; - } + /** + * { + * "publicKey" : ... + * "sha": ... + * "signedFpr": ... + * "version": ... + * } + */ - qDebug() << "keyDataBuf" << keyDataBuf; + QCryptographicHash shaGen(QCryptographicHash::Sha256); + shaGen.addData(keyDataBuf); - /** - * { - * "publicKey" : ... - * "sha": ... - * "signedFpr": ... - * "version": ... - * } - */ + auto shaStr = shaGen.result().toHex(); - QCryptographicHash shaGen(QCryptographicHash::Sha256); - shaGen.addData(keyDataBuf); + auto signFprStr = ComUtils::getSignStringBase64(mCtx, key.fpr, key); - auto shaStr = shaGen.result().toHex(); + rapidjson::Value pubkey, ver, sha, signFpr; - auto signFprStr = ComUtils::getSignStringBase64(mCtx, key.fpr, key); + rapidjson::Document doc; + doc.SetObject(); - rapidjson::Value pubkey, ver, sha, signFpr; + pubkey.SetString(keyDataBuf.constData(), keyDataBuf.count()); - rapidjson::Document doc; - doc.SetObject(); + auto version = qApp->applicationVersion(); + ver.SetString(version.toUtf8().constData(), + qApp->applicationVersion().count()); - pubkey.SetString(keyDataBuf.constData(), keyDataBuf.count()); + sha.SetString(shaStr.constData(), shaStr.count()); + signFpr.SetString(signFprStr.constData(), signFprStr.count()); - auto version = qApp->applicationVersion(); - ver.SetString(version.toUtf8().constData(), qApp->applicationVersion().count()); + rapidjson::Document::AllocatorType& allocator = doc.GetAllocator(); - sha.SetString(shaStr.constData(), shaStr.count()); - signFpr.SetString(signFprStr.constData(), signFprStr.count()); + doc.AddMember("publicKey", pubkey, allocator); + doc.AddMember("sha", sha, allocator); + doc.AddMember("signedFpr", signFpr, allocator); + doc.AddMember("version", ver, allocator); - rapidjson::Document::AllocatorType &allocator = doc.GetAllocator(); + rapidjson::StringBuffer sb; + rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(sb); + doc.Accept(writer); - doc.AddMember("publicKey", pubkey, allocator); - doc.AddMember("sha", sha, allocator); - doc.AddMember("signedFpr", signFpr, allocator); - doc.AddMember("version", ver, allocator); + QByteArray postData(sb.GetString()); - rapidjson::StringBuffer sb; - rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(sb); - doc.Accept(writer); + QNetworkReply* reply = utils->getNetworkManager().post(request, postData); - QByteArray postData(sb.GetString()); + // Show Waiting Dailog + auto dialog = new WaitingDialog("Getting Token From Server", this); + dialog->show(); - QNetworkReply *reply = utils->getNetworkManager().post(request, postData); + while (reply->isRunning()) { + QApplication::processEvents(); + } - // Show Waiting Dailog - auto dialog = new WaitingDialog("Getting Token From Server", this); - dialog->show(); + dialog->close(); - while (reply->isRunning()) { - QApplication::processEvents(); - } + if (utils->checkServerReply(reply->readAll().constData())) { + /** + * { + * "serviceToken" : ... + * "fpr": ... + * } + */ - dialog->close(); - - if (utils->checkServerReply(reply->readAll().constData())) { - - /** - * { - * "serviceToken" : ... - * "fpr": ... - * } - */ - - if (!utils->checkDataValueStr("serviceToken") || !utils->checkDataValueStr("fpr")) { - QMessageBox::critical(this, tr("Error"), - tr("The communication content with the server does not meet the requirements")); - return; - } - - QString serviceTokenTemp = utils->getDataValueStr("serviceToken"); - QString fpr = utils->getDataValueStr("fpr"); - auto key = mCtx->getKeyByFpr(fpr); - if (utils->checkServiceTokenFormat(serviceTokenTemp) && key.good) { - serviceToken = serviceTokenTemp; - qDebug() << "Get Service Token" << serviceToken; - // Auto update settings - settings.setValue("general/serviceToken", serviceToken); - serviceTokenLabel->setText(serviceToken); - QMessageBox::information(this, tr("Notice"), - tr("Succeed in getting service token")); - } else { - QMessageBox::critical(this, tr("Error"), tr("There is a problem with the communication with the server")); - } + if (!utils->checkDataValueStr("serviceToken") || + !utils->checkDataValueStr("fpr")) { + QMessageBox::critical(this, _("Error"), + _("The communication content with the server does " + "not meet the requirements")); + return; } + QString serviceTokenTemp = utils->getDataValueStr("serviceToken"); + QString fpr = utils->getDataValueStr("fpr"); + auto key = mCtx->getKeyRefByFpr(fpr); + if (utils->checkServiceTokenFormat(serviceTokenTemp) && key.good) { + serviceToken = serviceTokenTemp; + qDebug() << "Get Service Token" << serviceToken; + // Auto update settings + settings.setValue("general/serviceToken", serviceToken); + serviceTokenLabel->setText(serviceToken); + QMessageBox::information(this, _("Notice"), + _("Succeed in getting service token")); + } else { + QMessageBox::critical( + this, _("Error"), + _("There is a problem with the communication with the server")); + } + } } +#endif + +} // namespace GpgFrontend::UI diff --git a/src/ui/settings/SettingsGeneral.h b/src/ui/settings/SettingsGeneral.h new file mode 100644 index 00000000..7e118f98 --- /dev/null +++ b/src/ui/settings/SettingsGeneral.h @@ -0,0 +1,85 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_SETTINGSGENERAL_H +#define GPGFRONTEND_SETTINGSGENERAL_H + +#include "ui/GpgFrontendUI.h" + +namespace GpgFrontend::UI { +class KeyList; + +class GeneralTab : public QWidget { + Q_OBJECT + + public: + explicit GeneralTab(QWidget* parent = nullptr); + + void setSettings(); + + void applySettings(); + + private: + QCheckBox* saveCheckedKeysCheckBox; + QCheckBox* importConfirmationCheckBox; + +#ifdef MULTI_LANG_SUPPORT + QComboBox* langSelectBox; + QHash<QString, QString> lang; +#endif + +#ifdef SERVER_SUPPORT + QComboBox* serverSelectBox; + QComboBox* ownKeySelectBox; + QPushButton* getServiceTokenButton; + QLabel* serviceTokenLabel; + std::string serviceToken; + std::unordered_map<std::string, std::string> keyIds; +#endif + + std::vector<std::string> keyIdsList; + + KeyList* mKeyList{}; + + private slots: + +#ifdef MULTI_LANG_SUPPORT + + void slotLanguageChanged(); + +#endif + +#ifdef SERVER_SUPPORT + + void slotOwnKeyIdChanged(); + +#endif + + signals: + + void signalRestartNeeded(bool needed); +}; +} // namespace GpgFrontend::UI + +#endif // GPGFRONTEND_SETTINGSGENERAL_H diff --git a/src/ui/settings/SettingsKeyServer.cpp b/src/ui/settings/SettingsKeyServer.cpp index b49eb9e0..f05ad7fb 100644 --- a/src/ui/settings/SettingsKeyServer.cpp +++ b/src/ui/settings/SettingsKeyServer.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -22,68 +22,69 @@ * */ -#include "ui/SettingsDialog.h" - -KeyserverTab::KeyserverTab(QWidget *parent) - : QWidget(parent), appPath(qApp->applicationDirPath()), - settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", - QSettings::IniFormat) { - - auto generalGroupBox = new QGroupBox(tr("General")); - auto generalLayout = new QVBoxLayout(); - - keyServerTable = new QTableWidget(); - keyServerTable->setColumnCount(3); - keyServerTable->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); - keyServerTable->horizontalHeader()->setStretchLastSection(false); - keyServerTable->verticalHeader()->hide(); - keyServerTable->setShowGrid(false); - keyServerTable->sortByColumn(0, Qt::AscendingOrder); - keyServerTable->setSelectionBehavior(QAbstractItemView::SelectRows); - keyServerTable->setSelectionMode(QAbstractItemView::SingleSelection); - - // tableitems not editable - keyServerTable->setEditTriggers(QAbstractItemView::NoEditTriggers); - // no focus (rectangle around tableitems) - // may be it should focus on whole row - keyServerTable->setFocusPolicy(Qt::NoFocus); - keyServerTable->setAlternatingRowColors(true); - - QStringList labels; - labels << tr("No.") << tr("Address") << tr("Available"); - keyServerTable->setHorizontalHeaderLabels(labels); - - auto *mainLayout = new QVBoxLayout(this); - auto *label = new QLabel(tr("Default Key Server for Import:")); - - comboBox = new QComboBox; - comboBox->setEditable(false); - comboBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); - - auto *addKeyServerBox = new QWidget(this); - auto *addKeyServerLayout = new QHBoxLayout(addKeyServerBox); - auto *http = new QLabel("URL: "); - newKeyServerEdit = new QLineEdit(this); - auto *newKeyServerButton = new QPushButton(tr("Add"), this); - connect(newKeyServerButton, SIGNAL(clicked()), this, SLOT(addKeyServer())); - addKeyServerLayout->addWidget(http); - addKeyServerLayout->addWidget(newKeyServerEdit); - addKeyServerLayout->addWidget(newKeyServerButton); - - generalLayout->addWidget(label); - generalLayout->addWidget(comboBox); - generalLayout->addWidget(keyServerTable); - generalLayout->addWidget(addKeyServerBox); - generalLayout->addStretch(0); - - generalGroupBox->setLayout(generalLayout); - mainLayout->addWidget(generalGroupBox); - mainLayout->addStretch(0); - - setLayout(mainLayout); - // Read keylist from ini-file and fill it into combobox - setSettings(); - refreshTable(); +#include "SettingsKeyServer.h" + +#include "GlobalSettingStation.h" + +namespace GpgFrontend::UI { + +KeyserverTab::KeyserverTab(QWidget* parent) : QWidget(parent) { + auto generalGroupBox = new QGroupBox(_("General")); + auto generalLayout = new QVBoxLayout(); + + keyServerTable = new QTableWidget(); + keyServerTable->setColumnCount(3); + keyServerTable->horizontalHeader()->setSectionResizeMode( + QHeaderView::ResizeToContents); + keyServerTable->horizontalHeader()->setStretchLastSection(false); + keyServerTable->verticalHeader()->hide(); + keyServerTable->setShowGrid(false); + keyServerTable->sortByColumn(0, Qt::AscendingOrder); + keyServerTable->setSelectionBehavior(QAbstractItemView::SelectRows); + keyServerTable->setSelectionMode(QAbstractItemView::SingleSelection); + + // tableitems not editable + keyServerTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + // no focus (rectangle around tableitems) + // may be it should focus on whole row + keyServerTable->setFocusPolicy(Qt::NoFocus); + keyServerTable->setAlternatingRowColors(true); + + QStringList labels; + labels << _("No.") << _("Address") << _("Available"); + keyServerTable->setHorizontalHeaderLabels(labels); + + auto* mainLayout = new QVBoxLayout(this); + auto* label = new QLabel(QString(_("Default Key Server for Import")) + ": "); + + comboBox = new QComboBox; + comboBox->setEditable(false); + comboBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + + auto* addKeyServerBox = new QWidget(this); + auto* addKeyServerLayout = new QHBoxLayout(addKeyServerBox); + auto* http = new QLabel("URL: "); + newKeyServerEdit = new QLineEdit(this); + auto* newKeyServerButton = new QPushButton(_("Add"), this); + connect(newKeyServerButton, SIGNAL(clicked()), this, SLOT(addKeyServer())); + addKeyServerLayout->addWidget(http); + addKeyServerLayout->addWidget(newKeyServerEdit); + addKeyServerLayout->addWidget(newKeyServerButton); + + generalLayout->addWidget(label); + generalLayout->addWidget(comboBox); + generalLayout->addWidget(keyServerTable); + generalLayout->addWidget(addKeyServerBox); + generalLayout->addStretch(0); + + generalGroupBox->setLayout(generalLayout); + mainLayout->addWidget(generalGroupBox); + mainLayout->addStretch(0); + + setLayout(mainLayout); + // Read keylist from ini-file and fill it into combobox + setSettings(); + refreshTable(); } /********************************** @@ -92,29 +93,38 @@ KeyserverTab::KeyserverTab(QWidget *parent) * appropriately **********************************/ void KeyserverTab::setSettings() { - - keyServerStrList = settings.value("keyserver/keyServerList").toStringList(); - - for (const auto &keyServer : keyServerStrList) { - comboBox->addItem(keyServer); - qDebug() << "KeyserverTab Get ListItemText" << keyServer; + auto& settings = GlobalSettingStation::GetInstance().GetUISettings(); + + try { + auto& server_list = settings.lookup("keyserver.server_list"); + const auto server_list_size = server_list.getLength(); + for (int i = 0; i < server_list_size; i++) { + std::string server_url = server_list[i]; + comboBox->addItem(server_url.c_str()); + keyServerStrList.append(server_url.c_str()); } - - comboBox->setCurrentText( - settings.value("keyserver/defaultKeyServer").toString()); - + } catch (...) { + LOG(ERROR) << _("Setting Operation Error") << _("server_list"); + } + + try { + std::string default_server = settings.lookup("keyserver.default_server"); + comboBox->setCurrentText(default_server.c_str()); + } catch (...) { + LOG(ERROR) << _("Setting Operation Error") << _("default_server"); + } } void KeyserverTab::addKeyServer() { - QString targetUrl; - if (newKeyServerEdit->text().startsWith("http://") || - newKeyServerEdit->text().startsWith("https://")) - targetUrl = newKeyServerEdit->text(); - else - targetUrl = "http://" + newKeyServerEdit->text(); - keyServerStrList.append(targetUrl); - comboBox->addItem(targetUrl); - refreshTable(); + QString targetUrl; + if (newKeyServerEdit->text().startsWith("http://") || + newKeyServerEdit->text().startsWith("https://")) + targetUrl = newKeyServerEdit->text(); + else + targetUrl = "http://" + newKeyServerEdit->text(); + keyServerStrList.append(targetUrl); + comboBox->addItem(targetUrl); + refreshTable(); } /*********************************** @@ -122,27 +132,51 @@ void KeyserverTab::addKeyServer() { * write them to settings-file *************************************/ void KeyserverTab::applySettings() { - settings.setValue("keyserver/keyServerList", keyServerStrList); - settings.setValue("keyserver/defaultKeyServer", comboBox->currentText()); + auto& settings = GlobalSettingStation::GetInstance().GetUISettings(); + + if (!settings.exists("keyserver") || + settings.lookup("keyserver").getType() != libconfig::Setting::TypeGroup) + settings.add("keyserver", libconfig::Setting::TypeGroup); + + auto& keyserver = settings["keyserver"]; + + if (keyserver.exists("server_list")) + keyserver.remove("server_list"); + + keyserver.add("server_list", libconfig::Setting::TypeList); + + auto& server_list = keyserver["server_list"]; + for (const auto& key_server_url : keyServerStrList) { + server_list.add(libconfig::Setting::TypeString) = + key_server_url.toStdString(); + } + + if (!keyserver.exists("default_server")) { + keyserver.add("default_server", libconfig::Setting::TypeString) = + comboBox->currentText().toStdString(); + } else { + keyserver["default_server"] = comboBox->currentText().toStdString(); + } } void KeyserverTab::refreshTable() { - - qDebug() << "Start Refreshing Key Server Table"; - - keyServerTable->setRowCount(keyServerStrList.size()); - - int index = 0; - for (const auto &server : keyServerStrList) { - auto *tmp1 = new QTableWidgetItem(QString::number(index)); - tmp1->setTextAlignment(Qt::AlignCenter); - keyServerTable->setItem(index, 0, tmp1); - auto *tmp2 = new QTableWidgetItem(server); - tmp2->setTextAlignment(Qt::AlignCenter); - keyServerTable->setItem(index, 1, tmp2); - auto *tmp3 = new QTableWidgetItem(""); - tmp3->setTextAlignment(Qt::AlignCenter); - keyServerTable->setItem(index, 2, tmp3); - index++; - } + LOG(INFO) << "Start Refreshing Key Server Table"; + + keyServerTable->setRowCount(keyServerStrList.size()); + + int index = 0; + for (const auto& server : keyServerStrList) { + auto* tmp1 = new QTableWidgetItem(QString::number(index)); + tmp1->setTextAlignment(Qt::AlignCenter); + keyServerTable->setItem(index, 0, tmp1); + auto* tmp2 = new QTableWidgetItem(server); + tmp2->setTextAlignment(Qt::AlignCenter); + keyServerTable->setItem(index, 1, tmp2); + auto* tmp3 = new QTableWidgetItem(); + tmp3->setTextAlignment(Qt::AlignCenter); + keyServerTable->setItem(index, 2, tmp3); + index++; + } } + +} // namespace GpgFrontend::UI diff --git a/src/ui/settings/SettingsKeyServer.h b/src/ui/settings/SettingsKeyServer.h new file mode 100644 index 00000000..5042aaa5 --- /dev/null +++ b/src/ui/settings/SettingsKeyServer.h @@ -0,0 +1,59 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_SETTINGSKEYSERVER_H +#define GPGFRONTEND_SETTINGSKEYSERVER_H + +#include "ui/GpgFrontendUI.h" + +namespace GpgFrontend::UI { +class KeyserverTab : public QWidget { + Q_OBJECT + + public: + explicit KeyserverTab(QWidget* parent = nullptr); + + void setSettings(); + + void applySettings(); + + private: + QComboBox* comboBox; + QLineEdit* newKeyServerEdit; + QTableWidget* keyServerTable; + QStringList keyServerStrList; + + private slots: + + void addKeyServer(); + + void refreshTable(); + + signals: + + void signalRestartNeeded(bool needed); +}; +} // namespace GpgFrontend::UI + +#endif // GPGFRONTEND_SETTINGSKEYSERVER_H diff --git a/src/ui/settings/SettingsSendMail.cpp b/src/ui/settings/SettingsSendMail.cpp index a5e3274f..2518991d 100644 --- a/src/ui/settings/SettingsSendMail.cpp +++ b/src/ui/settings/SettingsSendMail.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -22,75 +22,80 @@ * */ -#include "ui/SettingsDialog.h" -#include "smtp/SmtpMime" +#include "SettingsSendMail.h" -SendMailTab::SendMailTab(QWidget *parent) - : QWidget(parent), appPath(qApp->applicationDirPath()), - settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", - QSettings::IniFormat) { - - enableCheckBox = new QCheckBox(tr("Enable")); - enableCheckBox->setTristate(false); - - smtpAddress = new QLineEdit(); - username = new QLineEdit(); - password = new QLineEdit(); - password->setEchoMode(QLineEdit::Password); - - portSpin = new QSpinBox(); - portSpin->setMinimum(1); - portSpin->setMaximum(65535); - connectionTypeComboBox = new QComboBox(); - connectionTypeComboBox->addItem("None"); - connectionTypeComboBox->addItem("SSL"); - connectionTypeComboBox->addItem("TLS"); - connectionTypeComboBox->addItem("STARTTLS"); - - defaultSender = new QLineEdit();; - checkConnectionButton = new QPushButton(tr("Check Connection")); - - auto generalGroupBox = new QGroupBox(tr("General")); - auto connectGroupBox = new QGroupBox(tr("Connection")); - auto preferenceGroupBox = new QGroupBox(tr("Preference")); - - auto generalLayout = new QGridLayout(); - generalLayout->addWidget(enableCheckBox); - - auto connectLayout = new QGridLayout(); - connectLayout->addWidget(new QLabel(tr("SMTP Address")), 1, 0); - connectLayout->addWidget(smtpAddress, 1, 1, 1, 4); - connectLayout->addWidget(new QLabel(tr("Username")), 2, 0); - connectLayout->addWidget(username, 2, 1, 1, 4); - connectLayout->addWidget(new QLabel(tr("Password")), 3, 0); - connectLayout->addWidget(password, 3, 1, 1, 4); - connectLayout->addWidget(new QLabel(tr("Port")), 4, 0); - connectLayout->addWidget(portSpin, 4, 1, 1, 1); - connectLayout->addWidget(new QLabel(tr("Connection Security")), 5, 0); - connectLayout->addWidget(connectionTypeComboBox, 5, 1, 1, 1); - connectLayout->addWidget(checkConnectionButton, 6, 0); - - auto preferenceLayout = new QGridLayout(); - - preferenceLayout->addWidget(new QLabel(tr("Default Sender")), 0, 0); - preferenceLayout->addWidget(defaultSender, 0, 1, 1, 4); - - generalGroupBox->setLayout(generalLayout); - connectGroupBox->setLayout(connectLayout); - preferenceGroupBox->setLayout(preferenceLayout); - - auto vBox = new QVBoxLayout(); - vBox->addWidget(generalGroupBox); - vBox->addWidget(connectGroupBox); - vBox->addWidget(preferenceGroupBox); - vBox->addStretch(0); - - connect(enableCheckBox, SIGNAL(stateChanged(int)), this, SLOT(slotCheckBoxSetEnableDisable(int))); - connect(checkConnectionButton, SIGNAL(clicked(bool)), this, SLOT(slotCheckConnection())); - - - this->setLayout(vBox); - setSettings(); +#ifdef SMTP_SUPPORT +#include "smtp/SmtpMime" +#endif + +namespace GpgFrontend::UI { + +SendMailTab::SendMailTab(QWidget* parent) + : QWidget(parent), + appPath(qApp->applicationDirPath()), + settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", + QSettings::IniFormat) { + enableCheckBox = new QCheckBox(_("Enable")); + enableCheckBox->setTristate(false); + + smtpAddress = new QLineEdit(); + username = new QLineEdit(); + password = new QLineEdit(); + password->setEchoMode(QLineEdit::Password); + + portSpin = new QSpinBox(); + portSpin->setMinimum(1); + portSpin->setMaximum(65535); + connectionTypeComboBox = new QComboBox(); + connectionTypeComboBox->addItem("None"); + connectionTypeComboBox->addItem("SSL"); + connectionTypeComboBox->addItem("TLS"); + connectionTypeComboBox->addItem("STARTTLS"); + + defaultSender = new QLineEdit(); + ; + checkConnectionButton = new QPushButton(_("Check Connection")); + + auto generalGroupBox = new QGroupBox(_("General")); + auto connectGroupBox = new QGroupBox(_("Connection")); + auto preferenceGroupBox = new QGroupBox(_("Preference")); + + auto generalLayout = new QGridLayout(); + generalLayout->addWidget(enableCheckBox); + + auto connectLayout = new QGridLayout(); + connectLayout->addWidget(new QLabel(_("SMTP Address")), 1, 0); + connectLayout->addWidget(smtpAddress, 1, 1, 1, 4); + connectLayout->addWidget(new QLabel(_("Username")), 2, 0); + connectLayout->addWidget(username, 2, 1, 1, 4); + connectLayout->addWidget(new QLabel(_("Password")), 3, 0); + connectLayout->addWidget(password, 3, 1, 1, 4); + connectLayout->addWidget(new QLabel(_("Port")), 4, 0); + connectLayout->addWidget(portSpin, 4, 1, 1, 1); + connectLayout->addWidget(new QLabel(_("Connection Security")), 5, 0); + connectLayout->addWidget(connectionTypeComboBox, 5, 1, 1, 1); + connectLayout->addWidget(checkConnectionButton, 6, 0); + + auto preferenceLayout = new QGridLayout(); + + preferenceLayout->addWidget(new QLabel(_("Default Sender")), 0, 0); + preferenceLayout->addWidget(defaultSender, 0, 1, 1, 4); + + generalGroupBox->setLayout(generalLayout); + connectGroupBox->setLayout(connectLayout); + preferenceGroupBox->setLayout(preferenceLayout); + + auto vBox = new QVBoxLayout(); + vBox->addWidget(generalGroupBox); + vBox->addWidget(connectGroupBox); + vBox->addWidget(preferenceGroupBox); + vBox->addStretch(0); + + connect(enableCheckBox, SIGNAL(stateChanged(int)), this, + SLOT(slotCheckBoxSetEnableDisable(int))); + + this->setLayout(vBox); + setSettings(); } /********************************** @@ -99,27 +104,28 @@ SendMailTab::SendMailTab(QWidget *parent) * appropriately **********************************/ void SendMailTab::setSettings() { - - if (settings.value("sendMail/enable", false).toBool()) - enableCheckBox->setCheckState(Qt::Checked); - else { - enableCheckBox->setCheckState(Qt::Unchecked); - smtpAddress->setDisabled(true); - username->setDisabled(true); - password->setDisabled(true); - portSpin->setDisabled(true); - connectionTypeComboBox->setDisabled(true); - defaultSender->setDisabled(true); - checkConnectionButton->setDisabled(true); - } - - smtpAddress->setText(settings.value("sendMail/smtpAddress", QString()).toString()); - username->setText(settings.value("sendMail/username", QString()).toString()); - password->setText(settings.value("sendMail/password", QString()).toString()); - portSpin->setValue(settings.value("sendMail/port", 25).toInt()); - connectionTypeComboBox->setCurrentText(settings.value("sendMail/connectionType", "None").toString()); - defaultSender->setText(settings.value("sendMail/defaultSender", QString()).toString()); - + if (settings.value("sendMail/enable", false).toBool()) + enableCheckBox->setCheckState(Qt::Checked); + else { + enableCheckBox->setCheckState(Qt::Unchecked); + smtpAddress->setDisabled(true); + username->setDisabled(true); + password->setDisabled(true); + portSpin->setDisabled(true); + connectionTypeComboBox->setDisabled(true); + defaultSender->setDisabled(true); + checkConnectionButton->setDisabled(true); + } + + smtpAddress->setText( + settings.value("sendMail/smtpAddress", QString()).toString()); + username->setText(settings.value("sendMail/username", QString()).toString()); + password->setText(settings.value("sendMail/password", QString()).toString()); + portSpin->setValue(settings.value("sendMail/port", 25).toInt()); + connectionTypeComboBox->setCurrentText( + settings.value("sendMail/connectionType", "None").toString()); + defaultSender->setText( + settings.value("sendMail/defaultSender", QString()).toString()); } /*********************************** @@ -127,67 +133,69 @@ void SendMailTab::setSettings() { * write them to settings-file *************************************/ void SendMailTab::applySettings() { - - settings.setValue("sendMail/smtpAddress", smtpAddress->text()); - settings.setValue("sendMail/username", username->text()); - settings.setValue("sendMail/password", password->text()); - settings.setValue("sendMail/port", portSpin->value()); - settings.setValue("sendMail/connectionType", connectionTypeComboBox->currentText()); - settings.setValue("sendMail/defaultSender", defaultSender->text()); - - settings.setValue("sendMail/enable", enableCheckBox->isChecked()); + settings.setValue("sendMail/smtpAddress", smtpAddress->text()); + settings.setValue("sendMail/username", username->text()); + settings.setValue("sendMail/password", password->text()); + settings.setValue("sendMail/port", portSpin->value()); + settings.setValue("sendMail/connectionType", + connectionTypeComboBox->currentText()); + settings.setValue("sendMail/defaultSender", defaultSender->text()); + + settings.setValue("sendMail/enable", enableCheckBox->isChecked()); } +#ifdef SMTP_SUPPORT void SendMailTab::slotCheckConnection() { - - SmtpClient::ConnectionType connectionType; - const auto selectedConnType = connectionTypeComboBox->currentText(); - if (selectedConnType == "SSL") { - connectionType = SmtpClient::ConnectionType::SslConnection; - } else if (selectedConnType == "TLS" || selectedConnType == "STARTTLS") { - connectionType = SmtpClient::ConnectionType::TlsConnection; - } else { - connectionType = SmtpClient::ConnectionType::TcpConnection; - } - - SmtpClient smtp(smtpAddress->text(), portSpin->value(), connectionType); - - smtp.setUser(username->text()); - smtp.setPassword(password->text()); - - bool if_success = true; - - if (!smtp.connectToHost()) { - QMessageBox::critical(this, tr("Fail"), tr("Fail to Connect SMTP Server")); - if_success = false; - } - if (if_success && !smtp.login()) { - QMessageBox::critical(this, tr("Fail"), tr("Fail to Login")); - if_success = false; - } - - if (if_success) - QMessageBox::information(this, tr("Success"), tr("Succeed in connecting and login")); - + SmtpClient::ConnectionType connectionType; + const auto selectedConnType = connectionTypeComboBox->currentText(); + if (selectedConnType == "SSL") { + connectionType = SmtpClient::ConnectionType::SslConnection; + } else if (selectedConnType == "TLS" || selectedConnType == "STARTTLS") { + connectionType = SmtpClient::ConnectionType::TlsConnection; + } else { + connectionType = SmtpClient::ConnectionType::TcpConnection; + } + + SmtpClient smtp(smtpAddress->text(), portSpin->value(), connectionType); + + smtp.setUser(username->text()); + smtp.setPassword(password->text()); + + bool if_success = true; + + if (!smtp.connectToHost()) { + QMessageBox::critical(this, _("Fail"), _("Fail to Connect SMTP Server")); + if_success = false; + } + if (if_success && !smtp.login()) { + QMessageBox::critical(this, _("Fail"), _("Fail to Login")); + if_success = false; + } + + if (if_success) + QMessageBox::information(this, _("Success"), + _("Succeed in connecting and login")); } +#endif void SendMailTab::slotCheckBoxSetEnableDisable(int state) { - if (state == Qt::Checked) { - smtpAddress->setEnabled(true); - username->setEnabled(true); - password->setEnabled(true); - portSpin->setEnabled(true); - connectionTypeComboBox->setEnabled(true); - defaultSender->setEnabled(true); - checkConnectionButton->setEnabled(true); - } else { - smtpAddress->setDisabled(true); - username->setDisabled(true); - password->setDisabled(true); - portSpin->setDisabled(true); - connectionTypeComboBox->setDisabled(true); - defaultSender->setDisabled(true); - checkConnectionButton->setDisabled(true); - } + if (state == Qt::Checked) { + smtpAddress->setEnabled(true); + username->setEnabled(true); + password->setEnabled(true); + portSpin->setEnabled(true); + connectionTypeComboBox->setEnabled(true); + defaultSender->setEnabled(true); + checkConnectionButton->setEnabled(true); + } else { + smtpAddress->setDisabled(true); + username->setDisabled(true); + password->setDisabled(true); + portSpin->setDisabled(true); + connectionTypeComboBox->setDisabled(true); + defaultSender->setDisabled(true); + checkConnectionButton->setDisabled(true); + } } +} // namespace GpgFrontend::UI diff --git a/src/ui/settings/SettingsSendMail.h b/src/ui/settings/SettingsSendMail.h new file mode 100644 index 00000000..ec8f83c9 --- /dev/null +++ b/src/ui/settings/SettingsSendMail.h @@ -0,0 +1,46 @@ +// +// Created by saturneric on 2021/11/28. +// + +#ifndef GPGFRONTEND_SETTINGSSENDMAIL_H +#define GPGFRONTEND_SETTINGSSENDMAIL_H + +#include "ui/GpgFrontendUI.h" + +namespace GpgFrontend::UI { +class SendMailTab : public QWidget { + Q_OBJECT + + public: + explicit SendMailTab(QWidget* parent = nullptr); + + void setSettings(); + + void applySettings(); + + private slots: + + void slotCheckBoxSetEnableDisable(int state); + + private: + QString appPath; + QSettings settings; + + QCheckBox* enableCheckBox; + + QLineEdit* smtpAddress; + QLineEdit* username; + QLineEdit* password; + QSpinBox* portSpin; + QComboBox* connectionTypeComboBox; + QLineEdit* defaultSender; + + QPushButton* checkConnectionButton; + + signals: + + void signalRestartNeeded(bool needed); +}; +} // namespace GpgFrontend::UI + +#endif // GPGFRONTEND_SETTINGSSENDMAIL_H diff --git a/src/ui/smtp/SendMailDialog.cpp b/src/ui/smtp/SendMailDialog.cpp new file mode 100644 index 00000000..7c8933a0 --- /dev/null +++ b/src/ui/smtp/SendMailDialog.cpp @@ -0,0 +1,195 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#include "SendMailDialog.h" + +#include <utility> + +#ifdef STMP_ENABLED +#include "smtp/SmtpMime" +#endif + +namespace GpgFrontend::UI { + +SendMailDialog::SendMailDialog(QString text, QWidget* parent) + : QDialog(parent), + appPath(qApp->applicationDirPath()), + settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", + QSettings::IniFormat), + mText(std::move(text)) { + if (smtpAddress.isEmpty()) { + QMessageBox::critical( + this, _("Incomplete configuration"), + _("The SMTP address is empty, please go to the setting interface to " + "complete the configuration.")); + + deleteLater(); + return; + } + + senderEdit = new QLineEdit(); + senderEdit->setText(defaultSender); + recipientEdit = new QTextEdit(); + recipientEdit->setPlaceholderText( + "One or more email addresses. Please use ; to separate."); + subjectEdit = new QLineEdit(); + + errorLabel = new QLabel(); + + qDebug() << "Send Mail Settings" << smtpAddress << username << password + << defaultSender << connectionTypeSettings; + + confirmButton = new QPushButton("Confirm"); + + auto layout = new QGridLayout(); + layout->addWidget(new QLabel("Sender"), 0, 0); + layout->addWidget(senderEdit, 0, 1); + layout->addWidget(new QLabel("Recipient"), 1, 0); + layout->addWidget(recipientEdit, 1, 1); + layout->addWidget(new QLabel("Subject"), 2, 0); + layout->addWidget(subjectEdit, 2, 1); + layout->addWidget(confirmButton, 3, 1); + layout->addWidget(errorLabel, 4, 0, 1, 2); + +#ifdef STMP_ENABLED + connect(confirmButton, SIGNAL(clicked(bool)), this, SLOT(slotConfirm())); +#endif + + this->setLayout(layout); + this->setWindowTitle("Send Mail"); + this->setModal(true); + this->setFixedWidth(320); + this->show(); +} + +bool SendMailDialog::check_email_address(const QString& str) { + return re_email.match(str).hasMatch(); +} + +#ifdef STMP_ENABLED + +void SendMailDialog::slotConfirm() { + QString errString; + errorLabel->clear(); + + QStringList rcptStringList = recipientEdit->toPlainText().split(';'); + + if (rcptStringList.isEmpty()) { + errString.append(QString(" ") + _("Recipient cannot be empty") + " \n"); + } else { + for (const auto& reci : rcptStringList) { + qDebug() << "Receiver" << reci.trimmed(); + if (!check_email_address(reci.trimmed())) { + errString.append(QString(" ") + + _("One or more Recipient's Email Address is invalid") + + " \n"); + break; + } + } + } + if (senderEdit->text().isEmpty()) { + errString.append(QString(" ") + _("Sender cannot be empty") + " \n"); + } else if (!check_email_address(senderEdit->text())) { + errString.append(QString(" ") + _("Sender's Email Address is invalid") + + " \n"); + } + + if (!errString.isEmpty()) { + errorLabel->setAutoFillBackground(true); + QPalette error = errorLabel->palette(); + error.setColor(QPalette::Window, "#ff8080"); + errorLabel->setPalette(error); + errorLabel->setText(errString); + return; + } + + SmtpClient::ConnectionType connectionType = + SmtpClient::ConnectionType::TcpConnection; + + if (connectionTypeSettings == "SSL") { + connectionType = SmtpClient::ConnectionType::SslConnection; + } else if (connectionTypeSettings == "TLS") { + connectionType = SmtpClient::ConnectionType::TlsConnection; + } else if (connectionTypeSettings == "STARTTLS") { + connectionType = SmtpClient::ConnectionType::TlsConnection; + } else { + connectionType = SmtpClient::ConnectionType::TcpConnection; + } + + SmtpClient smtp(smtpAddress, port, connectionType); + + // We need to set the username (your email address) and the password + // for smtp authentification. + + smtp.setUser(username); + smtp.setPassword(password); + + // Now we create a MimeMessage object. This will be the email. + + MimeMessage message; + + message.setSender(new EmailAddress(senderEdit->text())); + for (const auto& reci : rcptStringList) { + if (!reci.isEmpty()) message.addRecipient(new EmailAddress(reci.trimmed())); + } + message.setSubject(subjectEdit->text()); + + // Now add some text to the email. + // First we create a MimeText object. + + MimeText text; + + text.setText(mText); + + // Now add it to the mail + message.addPart(&text); + + // Now we can send the mail + if (!smtp.connectToHost()) { + qDebug() << "Connect to SMTP Server Failed"; + QMessageBox::critical(this, _("Fail"), _("Fail to Connect SMTP Server")); + return; + } + if (!smtp.login()) { + qDebug() << "Login to SMTP Server Failed"; + QMessageBox::critical(this, _("Fail"), _("Fail to Login into SMTP Server")); + return; + } + if (!smtp.sendMail(message)) { + qDebug() << "Send Mail to SMTP Server Failed"; + QMessageBox::critical(this, _("Fail"), + _("Fail to Send Mail to SMTP Server")); + return; + } + smtp.quit(); + + // Close after sending email + QMessageBox::information(this, _("Success"), + _("Succeed in Sending Mail to SMTP Server")); + deleteLater(); +} + +#endif + +} // namespace GpgFrontend::UI diff --git a/src/ui/smtp/SendMailDialog.h b/src/ui/smtp/SendMailDialog.h new file mode 100644 index 00000000..87dfd81f --- /dev/null +++ b/src/ui/smtp/SendMailDialog.h @@ -0,0 +1,71 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_SENDMAILDIALOG_H +#define GPGFRONTEND_SENDMAILDIALOG_H + +#include "ui/GpgFrontendUI.h" + +namespace GpgFrontend::UI { + +class SendMailDialog : public QDialog { + Q_OBJECT + public: + explicit SendMailDialog(QString text, QWidget* parent = nullptr); + + private slots: + + void slotConfirm(); + + private: + QString appPath; + QSettings settings; + + QLineEdit* senderEdit; + QTextEdit* recipientEdit; + QLineEdit* subjectEdit; + QPushButton* confirmButton; + + QLabel* errorLabel; + QString mText; + + QString smtpAddress = + settings.value("sendMail/smtpAddress", QString()).toString(); + QString username = settings.value("sendMail/username", QString()).toString(); + QString password = settings.value("sendMail/password", QString()).toString(); + QString defaultSender = + settings.value("sendMail/defaultSender", QString()).toString(); + QString connectionTypeSettings = + settings.value("sendMail/connectionType", QString()).toString(); + int port = settings.value("sendMail/port", QString()).toInt(); + + QRegularExpression re_email{ + R"((?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\]))"}; + + bool check_email_address(const QString& str); +}; + +} // namespace GpgFrontend::UI + +#endif // GPGFRONTEND_SENDMAILDIALOG_H diff --git a/src/ui/widgets/EditorPage.cpp b/src/ui/widgets/EditorPage.cpp index beb37b96..94c98036 100644 --- a/src/ui/widgets/EditorPage.cpp +++ b/src/ui/widgets/EditorPage.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -24,84 +24,131 @@ #include "ui/widgets/EditorPage.h" +#include <boost/filesystem.hpp> #include <utility> -EditorPage::EditorPage(QString filePath, QWidget *parent) : QWidget(parent), - fullFilePath(std::move(filePath)) { - // Set the Textedit properties - textPage = new QTextEdit(); - textPage->setAcceptRichText(false); +#include "ui/function/FileReadThread.h" - // Set the layout style - mainLayout = new QVBoxLayout(); - mainLayout->setSpacing(0); - mainLayout->addWidget(textPage); - mainLayout->setContentsMargins(0, 0, 0, 0); - setLayout(mainLayout); +namespace GpgFrontend::UI { - setAttribute(Qt::WA_DeleteOnClose); - textPage->setFocus(); +EditorPage::EditorPage(QString filePath, QWidget* parent) + : QWidget(parent), fullFilePath(std::move(filePath)) { + // Set the Textedit properties + textPage = new QTextEdit(); + textPage->setAcceptRichText(false); - // Front in same width - this->setFont({"Courier"}); -} + // Set the layout style + mainLayout = new QVBoxLayout(); + mainLayout->setSpacing(0); + mainLayout->addWidget(textPage); + mainLayout->setContentsMargins(0, 0, 0, 0); + setLayout(mainLayout); -const QString &EditorPage::getFilePath() const { - return fullFilePath; -} + textPage->setFocus(); -QTextEdit *EditorPage::getTextPage() { - return textPage; + // Front in same width + this->setFont({"Courier"}); + this->setAttribute(Qt::WA_DeleteOnClose); } -void EditorPage::setFilePath(const QString &filePath) { - fullFilePath = filePath; +const QString& EditorPage::getFilePath() const { return fullFilePath; } + +QTextEdit* EditorPage::getTextPage() { return textPage; } + +void EditorPage::setFilePath(const QString& filePath) { + fullFilePath = filePath; } -void EditorPage::showNotificationWidget(QWidget *widget, const char *className) { - widget->setProperty(className, true); - mainLayout->addWidget(widget); +void EditorPage::showNotificationWidget(QWidget* widget, + const char* className) { + widget->setProperty(className, true); + mainLayout->addWidget(widget); } -void EditorPage::closeNoteByClass(const char *className) { - QList<QWidget *> widgets = findChildren<QWidget *>(); - for (QWidget *widget: widgets) { - if (widget->property(className) == true) { - widget->close(); - } +void EditorPage::closeNoteByClass(const char* className) { + QList<QWidget*> widgets = findChildren<QWidget*>(); + for (QWidget* widget : widgets) { + if (widget->property(className) == true) { + widget->close(); } + } } void EditorPage::slotFormatGpgHeader() { + QString content = textPage->toPlainText(); + + // Get positions of the gpg-headers, if they exist + int start = content.indexOf(GpgFrontend::GpgConstants::PGP_SIGNED_BEGIN); + int startSig = + content.indexOf(GpgFrontend::GpgConstants::PGP_SIGNATURE_BEGIN); + int endSig = content.indexOf(GpgFrontend::GpgConstants::PGP_SIGNATURE_END); + + if (start < 0 || startSig < 0 || endSig < 0 || signMarked) { + return; + } + + signMarked = true; + + // Set the fontstyle for the header + QTextCharFormat signFormat; + signFormat.setForeground(QBrush(QColor::fromRgb(80, 80, 80))); + signFormat.setFontPointSize(9); + + // set font style for the signature + QTextCursor cursor(textPage->document()); + cursor.setPosition(startSig, QTextCursor::MoveAnchor); + cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, endSig); + cursor.setCharFormat(signFormat); + + // set the font style for the header + int headEnd = content.indexOf("\n\n", start); + cursor.setPosition(start, QTextCursor::MoveAnchor); + cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, headEnd); + cursor.setCharFormat(signFormat); +} - QString content = textPage->toPlainText(); - - // Get positions of the gpg-headers, if they exist - int start = content.indexOf(GpgConstants::PGP_SIGNED_BEGIN); - int startSig = content.indexOf(GpgConstants::PGP_SIGNATURE_BEGIN); - int endSig = content.indexOf(GpgConstants::PGP_SIGNATURE_END); - - if (start < 0 || startSig < 0 || endSig < 0 || signMarked) { - return; - } - - signMarked = true; - - // Set the fontstyle for the header - QTextCharFormat signFormat; - signFormat.setForeground(QBrush(QColor::fromRgb(80, 80, 80))); - signFormat.setFontPointSize(9); - - // set font style for the signature - QTextCursor cursor(textPage->document()); - cursor.setPosition(startSig, QTextCursor::MoveAnchor); - cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, endSig); - cursor.setCharFormat(signFormat); - - // set the font style for the header - int headEnd = content.indexOf("\n\n", start); - cursor.setPosition(start, QTextCursor::MoveAnchor); - cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, headEnd); - cursor.setCharFormat(signFormat); +void EditorPage::ReadFile() { + LOG(INFO) << "Called"; + + readDone = false; + + auto text_page = this->getTextPage(); + text_page->setReadOnly(true); + auto thread = new FileReadThread(this->fullFilePath.toStdString()); + + connect(thread, &FileReadThread::sendReadBlock, this, + &EditorPage::slotInsertText); + + connect(thread, &FileReadThread::readDone, this, [=]() { + LOG(INFO) << "Thread read done"; + text_page->document()->setModified(false); + text_page->setReadOnly(false); + }); + + connect(thread, &FileReadThread::finished, this, [=]() { + LOG(INFO) << "Thread finished"; + thread->deleteLater(); + readDone = true; + readThread = nullptr; + }); + + connect(this, &EditorPage::destroyed, [=]() { + LOG(INFO) << "RequestInterruption for readThread"; + thread->requestInterruption(); + readThread = nullptr; + }); + this->readThread = thread; + thread->start(); +} +void EditorPage::slotInsertText(const QString& text) { + this->getTextPage()->insertPlainText(text); +} +void EditorPage::PrepareToDestroy() { + if (readThread) { + readThread->requestInterruption(); + readThread = nullptr; + } } + +} // namespace GpgFrontend::UI diff --git a/src/ui/widgets/EditorPage.h b/src/ui/widgets/EditorPage.h new file mode 100644 index 00000000..a0a05dab --- /dev/null +++ b/src/ui/widgets/EditorPage.h @@ -0,0 +1,113 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef __EDITORPAGE_H__ +#define __EDITORPAGE_H__ + +#include "gpg/GpgConstants.h" +#include "ui/GpgFrontendUI.h" + +QT_BEGIN_NAMESPACE +class QVBoxLayout; +class QHBoxLayout; +class QString; +class QLabel; +QT_END_NAMESPACE + +namespace GpgFrontend::UI { + +/** + * @brief Class for handling a single tab of the tabwidget + * + */ +class EditorPage : public QWidget { + Q_OBJECT + public: + /** + * @details Add layout and add plaintextedit + * + * @param filePath Path of the file handled in this tab + * @param parent Pointer to the parent widget + */ + explicit EditorPage(QString filePath = "", QWidget* parent = nullptr); + + /** + * @details Get the filepath of the currently activated tab. + */ + [[nodiscard]] const QString& getFilePath() const; + + /** + * @details Set filepath of currently activated tab. + * + * @param filePath The path to be set + */ + void setFilePath(const QString& filePath); + + /** + * @details Return pointer tp the textedit of the currently activated tab. + */ + QTextEdit* getTextPage(); + + /** + * @details Show additional widget at buttom of currently active tab + * + * @param widget The widget to be added + * @param className The name to handle the added widget + */ + void showNotificationWidget(QWidget* widget, const char* className); + + /** + * @details Hide all widgets with the given className + * + * @param className The classname of the widgets to hide + */ + void closeNoteByClass(const char* className); + + void ReadFile(); + + [[nodiscard]] bool ReadDone() const { return this->readDone; } + + void PrepareToDestroy(); + + private: + QTextEdit* textPage; /** The textedit of the tab */ + QVBoxLayout* mainLayout; /** The layout for the tab */ + QString fullFilePath; /** The path to the file handled in the tab */ + bool signMarked{}; /** true, if the signed header is marked, false if not */ + bool readDone = false; + QThread* readThread = nullptr; + + private slots: + + /** + * @details Format the gpg header in another font-style + */ + void slotFormatGpgHeader(); + + void slotInsertText(const QString& text); +}; + +} // namespace GpgFrontend::UI + +#endif // __EDITORPAGE_H__ diff --git a/src/ui/widgets/FilePage.cpp b/src/ui/widgets/FilePage.cpp index b9602d58..2c8df5e4 100644 --- a/src/ui/widgets/FilePage.cpp +++ b/src/ui/widgets/FilePage.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -24,244 +24,258 @@ #include "ui/widgets/FilePage.h" -#include "MainWindow.h" - -FilePage::FilePage(QWidget *parent) : QWidget(parent) { - - qDebug() << "First Parent" << parent; - firstParent = parent; - - qDebug() << "New File Page"; - - dirModel = new QFileSystemModel(); - dirModel->setRootPath(QDir::currentPath()); - - dirTreeView = new QTreeView(); - dirTreeView->setModel(dirModel); - dirTreeView->setAnimated(true); - dirTreeView->setIndentation(20); - dirTreeView->setRootIndex(dirModel->index(QDir::currentPath())); - dirTreeView->setContextMenuPolicy(Qt::CustomContextMenu); - mPath = dirModel->rootPath(); - - createPopupMenu(); - - - upLevelButton = new QPushButton(); - connect(upLevelButton, SIGNAL(clicked(bool)), this, SLOT(slotUpLevel())); - - QString buttonStyle = "QPushButton{border:none;background-color:rgba(255, 255, 255,100);}"; - - - auto upPixmap = QPixmap(":up.png"); - upPixmap = upPixmap.scaled(18, 18, Qt::KeepAspectRatio, Qt::SmoothTransformation); - QIcon upButtonIcon(upPixmap); - upLevelButton->setIcon(upButtonIcon); - upLevelButton->setIconSize(upPixmap.rect().size()); - upLevelButton->setStyleSheet(buttonStyle); - - refreshButton = new QPushButton("Refresh"); - connect(refreshButton, SIGNAL(clicked(bool)), this, SLOT(slotGoPath())); - - goPathButton = new QPushButton(); - connect(goPathButton, SIGNAL(clicked(bool)), this, SLOT(slotGoPath())); - - auto updatePixmap = QPixmap(":refresh.png"); - updatePixmap = updatePixmap.scaled(18, 18, Qt::KeepAspectRatio, Qt::SmoothTransformation); - QIcon updateButtonIcon(updatePixmap); - goPathButton->setIcon(updateButtonIcon); - goPathButton->setIconSize(updatePixmap.rect().size()); - goPathButton->setStyleSheet(buttonStyle); - - pathEdit = new QLineEdit(); - pathEdit->setText(dirModel->rootPath()); +#include <boost/filesystem.hpp> - auto *menuLayout = new QHBoxLayout(); - menuLayout->addWidget(upLevelButton); - menuLayout->setStretchFactor(upLevelButton, 1); - menuLayout->addWidget(pathEdit); - menuLayout->setStretchFactor(pathEdit, 10); - menuLayout->addWidget(goPathButton); - menuLayout->setStretchFactor(goPathButton, 1); - // menuLayout->addWidget(refreshButton); - // menuLayout->setStretchFactor(refreshButton, 1); - - auto *layout = new QVBoxLayout(); - layout->setContentsMargins(0, 0, 0, 0); - layout->setSpacing(0); - layout->addLayout(menuLayout); - layout->setStretchFactor(menuLayout, 1); - layout->addWidget(dirTreeView); - layout->setStretchFactor(dirTreeView, 8); - - this->setLayout(layout); - - connect(dirTreeView, SIGNAL(clicked(const QModelIndex &)), this, SLOT(fileTreeViewItemClicked(const QModelIndex &))); - connect(dirTreeView, SIGNAL(doubleClicked(const QModelIndex &)), this, SLOT(fileTreeViewItemDoubleClicked(const QModelIndex &))); - connect(dirTreeView, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onCustomContextMenu(const QPoint &))); - - emit pathChanged(mPath); +#include "MainWindow.h" +namespace GpgFrontend::UI { + +FilePage::FilePage(QWidget* parent) : QWidget(parent) { + firstParent = parent; + LOG(INFO) << "New File Page"; + + dirModel = new QFileSystemModel(); + dirModel->setRootPath(QDir::currentPath()); + + dirTreeView = new QTreeView(); + dirTreeView->setModel(dirModel); + dirTreeView->setAnimated(true); + dirTreeView->setIndentation(20); + dirTreeView->setContextMenuPolicy(Qt::CustomContextMenu); + dirTreeView->setColumnWidth(0, 320); + dirTreeView->setRootIndex(dirModel->index(QDir::currentPath())); + mPath = boost::filesystem::path(dirModel->rootPath().toStdString()); + + createPopupMenu(); + + upLevelButton = new QPushButton(); + connect(upLevelButton, SIGNAL(clicked(bool)), this, SLOT(slotUpLevel())); + + QString buttonStyle = + "QPushButton{border:none;background-color:rgba(255, 255, 255, 0);}"; + + auto upPixmap = QPixmap(":up.png"); + upPixmap = + upPixmap.scaled(18, 18, Qt::KeepAspectRatio, Qt::SmoothTransformation); + QIcon upButtonIcon(upPixmap); + upLevelButton->setIcon(upButtonIcon); + upLevelButton->setIconSize(upPixmap.rect().size()); + upLevelButton->setStyleSheet(buttonStyle); + + refreshButton = new QPushButton(_("Refresh")); + connect(refreshButton, SIGNAL(clicked(bool)), this, SLOT(slotGoPath())); + + goPathButton = new QPushButton(); + connect(goPathButton, SIGNAL(clicked(bool)), this, SLOT(slotGoPath())); + + auto updatePixmap = QPixmap(":refresh.png"); + updatePixmap = updatePixmap.scaled(18, 18, Qt::KeepAspectRatio, + Qt::SmoothTransformation); + QIcon updateButtonIcon(updatePixmap); + goPathButton->setIcon(updateButtonIcon); + goPathButton->setIconSize(updatePixmap.rect().size()); + goPathButton->setStyleSheet(buttonStyle); + + pathEdit = new QLineEdit(); + pathEdit->setText(dirModel->rootPath()); + + auto* menuLayout = new QHBoxLayout(); + menuLayout->addWidget(upLevelButton); + menuLayout->setStretchFactor(upLevelButton, 1); + menuLayout->addWidget(pathEdit); + menuLayout->setStretchFactor(pathEdit, 10); + menuLayout->addWidget(goPathButton); + menuLayout->setStretchFactor(goPathButton, 1); + // menuLayout->addWidget(refreshButton); + // menuLayout->setStretchFactor(refreshButton, 1); + + auto* layout = new QVBoxLayout(); + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(0); + layout->addLayout(menuLayout); + layout->setStretchFactor(menuLayout, 1); + layout->addWidget(dirTreeView); + layout->setStretchFactor(dirTreeView, 8); + + this->setLayout(layout); + + connect(dirTreeView, SIGNAL(clicked(const QModelIndex&)), this, + SLOT(fileTreeViewItemClicked(const QModelIndex&))); + connect(dirTreeView, SIGNAL(doubleClicked(const QModelIndex&)), this, + SLOT(fileTreeViewItemDoubleClicked(const QModelIndex&))); + connect(dirTreeView, SIGNAL(customContextMenuRequested(const QPoint&)), this, + SLOT(onCustomContextMenu(const QPoint&))); + + // refresh + slotGoPath(); } -void FilePage::fileTreeViewItemClicked(const QModelIndex &index) { - selectedPath = dirModel->fileInfo(index).absoluteFilePath(); - qDebug() << "selectedPath" << selectedPath; +void FilePage::fileTreeViewItemClicked(const QModelIndex& index) { + selectedPath = boost::filesystem::path( + dirModel->fileInfo(index).absoluteFilePath().toStdString()); + LOG(INFO) << "selected path" << selectedPath; } void FilePage::slotUpLevel() { - QModelIndex currentRoot = dirTreeView->rootIndex(); - - mPath = dirModel->fileInfo(currentRoot).absoluteFilePath(); - QDir dir(mPath); - dir.makeAbsolute(); - dir.setPath(QDir::cleanPath(dir.filePath(QStringLiteral("..")))); - mPath = dir.absolutePath(); - auto fileInfo = QFileInfo(dir.absolutePath()); - if(fileInfo.isDir() && fileInfo.isReadable() && fileInfo.isExecutable()) { - pathEdit->setText(mPath); - slotGoPath(); - } - qDebug() << "Current Root mPath" << mPath; - emit pathChanged(mPath); -} + QModelIndex currentRoot = dirTreeView->rootIndex(); + + mPath = boost::filesystem::path( + dirModel->fileInfo(currentRoot).absoluteFilePath().toStdString()); -void FilePage::fileTreeViewItemDoubleClicked(const QModelIndex &index) { - mPath = dirModel->fileInfo(index).absoluteFilePath(); - auto fileInfo = QFileInfo(mPath); - auto targetModelIndex = dirTreeView->model()->index(index.row(), 0, index.parent()); - if(fileInfo.isDir() && fileInfo.isReadable() && fileInfo.isExecutable()) { - dirTreeView->setRootIndex(targetModelIndex); - pathEdit->setText(mPath); + if (mPath.has_parent_path()) { + mPath = mPath.parent_path(); + auto fileInfo = QFileInfo(QString::fromStdString(mPath.string())); + if (fileInfo.isDir() && fileInfo.isReadable() && fileInfo.isExecutable()) { + pathEdit->setText(QString::fromStdString(mPath.string())); + slotGoPath(); } - qDebug() << "Index mPath" << mPath; - emit pathChanged(mPath); + LOG(INFO) << "Current Root mPath" << mPath; + emit pathChanged(QString::fromStdString(mPath.string())); + } } -QString FilePage::getSelected() const { - return selectedPath; +void FilePage::fileTreeViewItemDoubleClicked(const QModelIndex& index) { + mPath = boost::filesystem::path( + dirModel->fileInfo(index).absoluteFilePath().toStdString()); + auto fileInfo = QFileInfo(QString::fromStdString(mPath.string())); + auto targetModelIndex = + dirTreeView->model()->index(index.row(), 0, index.parent()); + if (fileInfo.isDir() && fileInfo.isReadable() && fileInfo.isExecutable()) { + dirTreeView->setRootIndex(targetModelIndex); + pathEdit->setText(QString::fromStdString(mPath.string())); + } + for (int i = 1; i < dirModel->columnCount(); ++i) + dirTreeView->resizeColumnToContents(i); + LOG(INFO) << "Index mPath" << mPath; + emit pathChanged(QString::fromStdString(mPath.string())); } +QString FilePage::getSelected() const { return QString::fromStdString(selectedPath.string()); } + void FilePage::slotGoPath() { - qDebug() << "getSelected" << pathEdit->text(); - auto fileInfo = QFileInfo(pathEdit->text()); - if(fileInfo.isDir() && fileInfo.isReadable() && fileInfo.isExecutable()) { - mPath = fileInfo.filePath(); - qDebug() << "Set Path" << mPath; - dirTreeView->setRootIndex(dirModel->index(fileInfo.filePath())); - } else { - QMessageBox::critical(this, "Error", "The path is unprivileged or unreachable."); - } - emit pathChanged(mPath); + qDebug() << "getSelected" << pathEdit->text(); + auto fileInfo = QFileInfo(pathEdit->text()); + if (fileInfo.isDir() && fileInfo.isReadable() && fileInfo.isExecutable()) { + mPath = boost::filesystem::path(fileInfo.filePath().toStdString()); + LOG(INFO) << "Set Path" << mPath; + dirTreeView->setRootIndex(dirModel->index(fileInfo.filePath())); + for (int i = 1; i < dirModel->columnCount(); ++i) + dirTreeView->resizeColumnToContents(i); + } else { + QMessageBox::critical(this, "Error", + "The path is unprivileged or unreachable."); + } + emit pathChanged(QString::fromStdString(mPath.string())); } void FilePage::createPopupMenu() { - popUpMenu = new QMenu(); - - auto openItemAct = new QAction(tr("Open"), this); - connect(openItemAct, SIGNAL(triggered()), this, SLOT(slotOpenItem())); - auto deleteItemAct = new QAction(tr("Delete"), this); - connect(deleteItemAct, SIGNAL(triggered()), this, SLOT(slotDeleteItem())); - encryptItemAct = new QAction(tr("Encrypt and Sign"), this); - connect(encryptItemAct, SIGNAL(triggered()), this, SLOT(slotEncryptItem())); - decryptItemAct = new QAction(tr("Decrypt and Verify"), this); - connect(decryptItemAct, SIGNAL(triggered()), this, SLOT(slotDecryptItem())); - signItemAct = new QAction(tr("Only Sign"), this); - connect(signItemAct, SIGNAL(triggered()), this, SLOT(slotSignItem())); - verifyItemAct = new QAction(tr("Only Verify"), this); - connect(verifyItemAct, SIGNAL(triggered()), this, SLOT(slotVerifyItem())); - - popUpMenu->addAction(openItemAct); - popUpMenu->addAction(deleteItemAct); - popUpMenu->addSeparator(); - popUpMenu->addAction(encryptItemAct); - popUpMenu->addAction(decryptItemAct); - popUpMenu->addAction(signItemAct); - popUpMenu->addAction(verifyItemAct); - + popUpMenu = new QMenu(); + + auto openItemAct = new QAction(_("Open"), this); + connect(openItemAct, SIGNAL(triggered()), this, SLOT(slotOpenItem())); + auto deleteItemAct = new QAction(_("Delete"), this); + connect(deleteItemAct, SIGNAL(triggered()), this, SLOT(slotDeleteItem())); + encryptItemAct = new QAction(_("Encrypt and Sign"), this); + connect(encryptItemAct, SIGNAL(triggered()), this, SLOT(slotEncryptItem())); + decryptItemAct = new QAction(_("Decrypt and Verify"), this); + connect(decryptItemAct, SIGNAL(triggered()), this, SLOT(slotDecryptItem())); + signItemAct = new QAction(_("Only Sign"), this); + connect(signItemAct, SIGNAL(triggered()), this, SLOT(slotSignItem())); + verifyItemAct = new QAction(_("Only Verify"), this); + connect(verifyItemAct, SIGNAL(triggered()), this, SLOT(slotVerifyItem())); + + popUpMenu->addAction(openItemAct); + popUpMenu->addAction(deleteItemAct); + popUpMenu->addSeparator(); + popUpMenu->addAction(encryptItemAct); + popUpMenu->addAction(decryptItemAct); + popUpMenu->addAction(signItemAct); + popUpMenu->addAction(verifyItemAct); } -void FilePage::onCustomContextMenu(const QPoint &point) { - QModelIndex index = dirTreeView->indexAt(point); - selectedPath = dirModel->fileInfo(index).absoluteFilePath(); - qDebug() << "Right Click" << selectedPath; - if (index.isValid()) { - QFileInfo info(selectedPath); - encryptItemAct->setEnabled(info.isFile() && (info.suffix() != "gpg" && info.suffix() != "sig")); - decryptItemAct->setEnabled(info.isFile() && info.suffix() == "gpg"); - signItemAct->setEnabled(info.isFile() && (info.suffix() != "gpg" && info.suffix() != "sig")); - verifyItemAct->setEnabled(info.isFile() && (info.suffix() == "sig" || info.suffix() == "gpg")); - - popUpMenu->exec(dirTreeView->viewport()->mapToGlobal(point)); - } +void FilePage::onCustomContextMenu(const QPoint& point) { + QModelIndex index = dirTreeView->indexAt(point); + selectedPath = boost::filesystem::path( + dirModel->fileInfo(index).absoluteFilePath().toStdString()); + LOG(INFO) << "FilePage::onCustomContextMenu Right Click" << selectedPath; + if (index.isValid()) { + QFileInfo info(QString::fromStdString(selectedPath.string())); + encryptItemAct->setEnabled( + info.isFile() && (info.suffix() != "gpg" && info.suffix() != "sig")); + decryptItemAct->setEnabled(info.isFile() && info.suffix() == "gpg"); + signItemAct->setEnabled(info.isFile() && + (info.suffix() != "gpg" && info.suffix() != "sig")); + verifyItemAct->setEnabled( + info.isFile() && (info.suffix() == "sig" || info.suffix() == "gpg")); + + popUpMenu->exec(dirTreeView->viewport()->mapToGlobal(point)); + } } void FilePage::slotOpenItem() { - QFileInfo info(mPath); - if(info.isDir()) { - qDebug() << "getSelected" << pathEdit->text(); - if(info.isReadable() && info.isExecutable()) { - qDebug() << "Set Path" << info.filePath(); - dirTreeView->setRootIndex(dirModel->index(info.filePath())); - } else { - QMessageBox::critical(this, "Error", "The path is unprivileged or unreachable."); - } + QFileInfo info(QString::fromStdString(selectedPath.string())); + if (info.isDir()) { + LOG(INFO) << "FilePage::slotOpenItem getSelected" + << pathEdit->text().toStdString(); + if (info.isReadable() && info.isExecutable()) { + LOG(INFO) << "FilePage::slotOpenItem Set Path" + << info.filePath().toStdString(); + dirTreeView->setRootIndex(dirModel->index(info.filePath())); } else { - auto mainWindow = qobject_cast<MainWindow *>(firstParent); - qDebug() << "Open Item" << mPath; - if (mainWindow != nullptr) - mainWindow->slotOpenFile(mPath); + QMessageBox::critical(this, "Error", + "The path is unprivileged or unreachable."); } + } else { + auto mainWindow = qobject_cast<MainWindow*>(firstParent); + LOG(INFO) << "FilePage::slotOpenItem Open Item" << selectedPath; + auto qt_path = QString::fromStdString(selectedPath.string()); + if (mainWindow != nullptr) mainWindow->slotOpenFile(qt_path); + } } void FilePage::slotDeleteItem() { - QModelIndex index = dirTreeView->currentIndex(); - QVariant data = dirTreeView->model()->data(index); + QModelIndex index = dirTreeView->currentIndex(); + QVariant data = dirTreeView->model()->data(index); - auto ret = QMessageBox::warning(this, - tr("Warning"), - tr("Are you sure you want to delete it?"), - QMessageBox::Ok | QMessageBox::Cancel); + auto ret = QMessageBox::warning(this, _("Warning"), + _("Are you sure you want to delete it?"), + QMessageBox::Ok | QMessageBox::Cancel); - if(ret == QMessageBox::Cancel) - return; + if (ret == QMessageBox::Cancel) return; - qDebug() << "Delete Item" << data.toString(); + qDebug() << "Delete Item" << data.toString(); - if(!dirModel->remove(index)){ - QMessageBox::critical(this, - tr("Error"), - tr("Unable to delete the file or folder.")); - } + if (!dirModel->remove(index)) { + QMessageBox::critical(this, _("Error"), + _("Unable to delete the file or folder.")); + } } void FilePage::slotEncryptItem() { - auto mainWindow = qobject_cast<MainWindow *>(firstParent); - if(mainWindow != nullptr) - mainWindow->slotFileEncryptSign(); + auto mainWindow = qobject_cast<MainWindow*>(firstParent); + if (mainWindow != nullptr) mainWindow->slotFileEncryptSign(); } void FilePage::slotDecryptItem() { - auto mainWindow = qobject_cast<MainWindow *>(firstParent); - if(mainWindow != nullptr) - mainWindow->slotFileDecryptVerify(); + auto mainWindow = qobject_cast<MainWindow*>(firstParent); + if (mainWindow != nullptr) mainWindow->slotFileDecryptVerify(); } void FilePage::slotSignItem() { - auto mainWindow = qobject_cast<MainWindow *>(firstParent); - if(mainWindow != nullptr) - mainWindow->slotFileSign(); + auto mainWindow = qobject_cast<MainWindow*>(firstParent); + if (mainWindow != nullptr) mainWindow->slotFileSign(); } void FilePage::slotVerifyItem() { - auto mainWindow = qobject_cast<MainWindow *>(firstParent); - if(mainWindow != nullptr) - mainWindow->slotFileVerify(); + auto mainWindow = qobject_cast<MainWindow*>(firstParent); + if (mainWindow != nullptr) mainWindow->slotFileVerify(); } -void FilePage::keyPressEvent(QKeyEvent *event) { - qDebug() << "Key Press" << event->key(); - if(event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) { - slotGoPath(); - } +void FilePage::keyPressEvent(QKeyEvent* event) { + qDebug() << "Key Press" << event->key(); + if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) { + slotGoPath(); + } } + +} // namespace GpgFrontend::UI diff --git a/src/ui/widgets/FilePage.h b/src/ui/widgets/FilePage.h new file mode 100644 index 00000000..31be81f3 --- /dev/null +++ b/src/ui/widgets/FilePage.h @@ -0,0 +1,90 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_FILEPAGE_H +#define GPGFRONTEND_FILEPAGE_H + +#include <boost/filesystem.hpp> + +#include "ui/GpgFrontendUI.h" + +namespace GpgFrontend::UI { + +class FilePage : public QWidget { + Q_OBJECT + public: + explicit FilePage(QWidget* parent = nullptr); + + [[nodiscard]] QString getSelected() const; + + void createPopupMenu(); + + signals: + void pathChanged(const QString& path); + + private slots: + + void fileTreeViewItemClicked(const QModelIndex& index); + void fileTreeViewItemDoubleClicked(const QModelIndex& index); + + void slotUpLevel(); + void slotGoPath(); + + void slotOpenItem(); + void slotDeleteItem(); + void slotEncryptItem(); + void slotDecryptItem(); + void slotSignItem(); + void slotVerifyItem(); + + void onCustomContextMenu(const QPoint& point); + + protected: + void keyPressEvent(QKeyEvent* event) override; + + private: + QFileSystemModel* dirModel; + QTreeView* dirTreeView; + QLineEdit* pathEdit; + + // using boost path + boost::filesystem::path mPath; + boost::filesystem::path selectedPath; + + QPushButton* upLevelButton; + QPushButton* goPathButton; + QPushButton* refreshButton; + + QMenu* popUpMenu{}; + QAction* encryptItemAct{}; + QAction* decryptItemAct{}; + QAction* signItemAct{}; + QAction* verifyItemAct{}; + + QWidget* firstParent; +}; + +} // namespace GpgFrontend::UI + +#endif // GPGFRONTEND_FILEPAGE_H diff --git a/src/ui/widgets/GroupKeyList.cpp b/src/ui/widgets/GroupKeyList.cpp new file mode 100644 index 00000000..efba4428 --- /dev/null +++ b/src/ui/widgets/GroupKeyList.cpp @@ -0,0 +1,25 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#include "GroupKeyList.h" diff --git a/src/ui/widgets/GroupKeyList.h b/src/ui/widgets/GroupKeyList.h new file mode 100644 index 00000000..163c7126 --- /dev/null +++ b/src/ui/widgets/GroupKeyList.h @@ -0,0 +1,34 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_GROUPKEYLIST_H +#define GPGFRONTEND_GROUPKEYLIST_H + +#include "ui/GpgFrontendUI.h" + +class GroupKeyList : public QWidget { + Q_OBJECT +}; + +#endif // GPGFRONTEND_GROUPKEYLIST_H diff --git a/src/ui/widgets/HelpPage.cpp b/src/ui/widgets/HelpPage.cpp index e018da81..7b1e86c0 100644 --- a/src/ui/widgets/HelpPage.cpp +++ b/src/ui/widgets/HelpPage.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -26,25 +26,24 @@ #include <utility> -HelpPage::HelpPage(const QString &path, QWidget *parent) : - QWidget(parent) { +namespace GpgFrontend::UI { - browser = new QTextBrowser(); - auto *mainLayout = new QVBoxLayout(); - mainLayout->setSpacing(0); - mainLayout->addWidget(browser); - mainLayout->setContentsMargins(0, 0, 0, 0); - setLayout(mainLayout); - - connect(browser, SIGNAL(anchorClicked(QUrl)), this, SLOT(slotOpenUrl(QUrl))); - browser->setOpenLinks(false); - browser->setSource(localizedHelp(QUrl(path))); - browser->setFocus(); +HelpPage::HelpPage(const QString& path, QWidget* parent) : QWidget(parent) { + browser = new QTextBrowser(); + auto* mainLayout = new QVBoxLayout(); + mainLayout->setSpacing(0); + mainLayout->addWidget(browser); + mainLayout->setContentsMargins(0, 0, 0, 0); + setLayout(mainLayout); + connect(browser, SIGNAL(anchorClicked(QUrl)), this, SLOT(slotOpenUrl(QUrl))); + browser->setOpenLinks(false); + browser->setSource(localizedHelp(QUrl(path))); + browser->setFocus(); } -void HelpPage::slotOpenUrl(const QUrl &url) { - browser->setSource(localizedHelp(url)); +void HelpPage::slotOpenUrl(const QUrl& url) { + browser->setSource(localizedHelp(url)); }; /** @@ -55,29 +54,29 @@ void HelpPage::slotOpenUrl(const QUrl &url) { * @param url * @return */ -QUrl HelpPage::localizedHelp(const QUrl &url) { - QString path = url.toLocalFile(); - QString filename = path.mid(path.lastIndexOf("/") + 1); - QString filepath = path.left(path.lastIndexOf("/") + 1); - QStringList fileparts = filename.split("."); - - //QSettings settings; - QString lang = QSettings().value("int/lang", QLocale::system().name()).toString(); - if (lang.isEmpty()) { - lang = QLocale::system().name(); - } +QUrl HelpPage::localizedHelp(const QUrl& url) { + QString path = url.toLocalFile(); + QString filename = path.mid(path.lastIndexOf("/") + 1); + QString filepath = path.left(path.lastIndexOf("/") + 1); + QStringList fileparts = filename.split("."); - fileparts.insert(1, lang); - QString langfile = filepath + fileparts.join("."); + // QSettings settings; + QString lang = + QSettings().value("int/lang", QLocale::system().name()).toString(); + if (lang.isEmpty()) { + lang = QLocale::system().name(); + } - if (QFile(QUrl(langfile).toLocalFile()).exists()) { - return langfile; - } else { - return path; - } + fileparts.insert(1, lang); + QString langfile = filepath + fileparts.join("."); + if (QFile(QUrl(langfile).toLocalFile()).exists()) { + return langfile; + } else { + return path; + } } -QTextBrowser *HelpPage::getBrowser() { - return browser; -} +QTextBrowser* HelpPage::getBrowser() { return browser; } + +} // namespace GpgFrontend::UI diff --git a/src/ui/widgets/HelpPage.h b/src/ui/widgets/HelpPage.h new file mode 100644 index 00000000..25490557 --- /dev/null +++ b/src/ui/widgets/HelpPage.h @@ -0,0 +1,49 @@ +/* + * helppage.h + * + * Copyright 2008 gpg4usb-team <[email protected]> + * + * This file is part of gpg4usb. + * + * Gpg4usb is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Gpg4usb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with gpg4usb. If not, see <http://www.gnu.org/licenses/> + */ + +#ifndef HELPPAGE_H +#define HELPPAGE_H + +#include "ui/GpgFrontendUI.h" + +namespace GpgFrontend::UI { + +class HelpPage : public QWidget { + Q_OBJECT + public: + explicit HelpPage(const QString& path, QWidget* parent = nullptr); + + QTextBrowser* getBrowser(); + + signals: + + public slots: + + void slotOpenUrl(const QUrl& url); + + private: + QTextBrowser* browser; /** The textbrowser of the tab */ + QUrl localizedHelp(const QUrl& path); +}; + +} // namespace GpgFrontend::UI + +#endif // HELPPAGE_H diff --git a/src/ui/widgets/InfoBoardWidget.cpp b/src/ui/widgets/InfoBoardWidget.cpp index b9372c59..cd469422 100644 --- a/src/ui/widgets/InfoBoardWidget.cpp +++ b/src/ui/widgets/InfoBoardWidget.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -24,170 +24,193 @@ #include "ui/widgets/InfoBoardWidget.h" -InfoBoardWidget::InfoBoardWidget(QWidget *parent, GpgME::GpgContext *ctx, KeyList *keyList) : - QWidget(parent), mCtx(ctx), mKeyList(keyList), appPath(qApp->applicationDirPath()), - settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", - QSettings::IniFormat) { - - infoBoard = new QTextEdit(this); - infoBoard->setReadOnly(true); - infoBoard->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); - infoBoard->setMinimumWidth(480); - infoBoard->setContentsMargins(0, 0, 0, 0); - - connect(mCtx, SIGNAL(signalKeyInfoChanged()), this, SLOT(slotReset())); - - importFromKeyserverAct = new QAction(tr("Import missing key from Keyserver"), this); - connect(importFromKeyserverAct, SIGNAL(triggered()), this, SLOT(slotImportFromKeyserver())); - - detailMenu = new QMenu(this); - detailMenu->addAction(importFromKeyserverAct); - importFromKeyserverAct->setVisible(false); - - auto *actionButtonMenu = new QWidget(); - actionButtonMenu->setContentsMargins(0, 0, 0, 0); - actionButtonMenu->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum); - actionButtonMenu->setFixedHeight(36); - - actionButtonLayout = new QHBoxLayout(); - actionButtonLayout->setContentsMargins(5, 5, 5, 5); - actionButtonLayout->setSpacing(0); - actionButtonMenu->setLayout(actionButtonLayout); - - auto label = new QLabel(tr("Optional Actions")); - label->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); - label->setContentsMargins(0, 0, 0, 0); - - actionButtonLayout->addWidget(label); - actionButtonLayout->addStretch(); - - - QFrame *line; - line = new QFrame(this); - line->setFrameShape(QFrame::HLine); - line->setFrameShadow(QFrame::Sunken); - line->setContentsMargins(0, 0, 0, 0); - - auto *notificationWidgetLayout = new QVBoxLayout(this); - notificationWidgetLayout->setContentsMargins(0, 0, 0, 0); - notificationWidgetLayout->setSpacing(0); - - notificationWidgetLayout->addWidget(infoBoard); - notificationWidgetLayout->setStretchFactor(infoBoard, 10); - notificationWidgetLayout->addWidget(actionButtonMenu); - notificationWidgetLayout->setStretchFactor(actionButtonMenu, 1); - notificationWidgetLayout->addWidget(line); - notificationWidgetLayout->setStretchFactor(line, 1); - notificationWidgetLayout->addStretch(0); - this->setLayout(notificationWidgetLayout); +#include "ui/settings/GlobalSettingStation.h" + +namespace GpgFrontend::UI { + +InfoBoardWidget::InfoBoardWidget(QWidget* parent, KeyList* keyList) + : QWidget(parent), mKeyList(keyList) { + infoBoard = new QTextEdit(this); + infoBoard->setReadOnly(true); + infoBoard->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); + infoBoard->setMinimumWidth(480); + infoBoard->setContentsMargins(0, 0, 0, 0); + + importFromKeyserverAct = + new QAction(_("Import missing key from Keyserver"), this); + connect(importFromKeyserverAct, SIGNAL(triggered()), this, + SLOT(slotImportFromKeyserver())); + + detailMenu = new QMenu(this); + detailMenu->addAction(importFromKeyserverAct); + importFromKeyserverAct->setVisible(false); + + auto* actionButtonMenu = new QWidget(); + actionButtonMenu->setContentsMargins(0, 0, 0, 0); + actionButtonMenu->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum); + actionButtonMenu->setFixedHeight(36); + + actionButtonLayout = new QHBoxLayout(); + actionButtonLayout->setContentsMargins(5, 5, 5, 5); + actionButtonLayout->setSpacing(0); + actionButtonMenu->setLayout(actionButtonLayout); + + auto label = new QLabel(_("Optional Actions")); + label->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); + label->setContentsMargins(0, 0, 0, 0); + + actionButtonLayout->addWidget(label); + actionButtonLayout->addStretch(); + + QFrame* line; + line = new QFrame(this); + line->setFrameShape(QFrame::HLine); + line->setFrameShadow(QFrame::Sunken); + line->setContentsMargins(0, 0, 0, 0); + + auto* notificationWidgetLayout = new QVBoxLayout(this); + notificationWidgetLayout->setContentsMargins(0, 0, 0, 0); + notificationWidgetLayout->setSpacing(0); + + notificationWidgetLayout->addWidget(infoBoard); + notificationWidgetLayout->setStretchFactor(infoBoard, 10); + notificationWidgetLayout->addWidget(actionButtonMenu); + notificationWidgetLayout->setStretchFactor(actionButtonMenu, 1); + notificationWidgetLayout->addWidget(line); + notificationWidgetLayout->setStretchFactor(line, 1); + notificationWidgetLayout->addStretch(0); + this->setLayout(notificationWidgetLayout); + + // set default size + infoBoard->resize(480, 120); + resize(480, 120); } void InfoBoardWidget::slotImportFromKeyserver() { - auto *importDialog = new KeyServerImportDialog(mCtx, mKeyList, false, this); - importDialog->slotImport(*keysNotInList); + auto* importDialog = new KeyServerImportDialog(false, this); + auto key_ids = std::make_unique<KeyIdArgsList>(); + for (const auto& key_id : *keysNotInList) { + key_ids->push_back(key_id.toStdString()); + } + importDialog->slotImport(key_ids); } -void InfoBoardWidget::setInfoBoard(const QString &text, InfoBoardStatus verifyLabelStatus) { - QString color; - infoBoard->clear(); - switch (verifyLabelStatus) { - case INFO_ERROR_OK: - color = "#008000"; - break; - case INFO_ERROR_WARN: - color = "#FF8C00"; - break; - case INFO_ERROR_CRITICAL: - color = "#DC143C"; - break; - default: - break; - } - infoBoard->append(text); - - infoBoard->setAutoFillBackground(true); - QPalette status = infoBoard->palette(); - status.setColor(QPalette::Text, color); - infoBoard->setPalette(status); - auto infoBoardFontSize = settings.value("informationBoard/fontSize", 10).toInt(); - infoBoard->setFont(QFont("Times", infoBoardFontSize)); +void InfoBoardWidget::setInfoBoard(const QString& text, + InfoBoardStatus verifyLabelStatus) { + QString color; + infoBoard->clear(); + switch (verifyLabelStatus) { + case INFO_ERROR_OK: + color = "#008000"; + break; + case INFO_ERROR_WARN: + color = "#FF8C00"; + break; + case INFO_ERROR_CRITICAL: + color = "#DC143C"; + break; + default: + break; + } + infoBoard->append(text); + + infoBoard->setAutoFillBackground(true); + QPalette status = infoBoard->palette(); + status.setColor(QPalette::Text, color); + infoBoard->setPalette(status); + + auto& settings = GlobalSettingStation::GetInstance().GetUISettings(); + + // info board font size + auto info_font_size = 10; + try { + info_font_size = settings.lookup("window.info_font_size"); + if (info_font_size < 9 || info_font_size > 18) info_font_size = 10; + } catch (...) { + LOG(ERROR) << _("Setting Operation Error") << _("info_font_size"); + } + infoBoard->setFont(QFont("Times", info_font_size)); } -void InfoBoardWidget::slotRefresh(const QString &text, InfoBoardStatus status) { - infoBoard->clear(); - setInfoBoard(text, status); - infoBoard->verticalScrollBar()->setValue(0); +void InfoBoardWidget::slotRefresh(const QString& text, InfoBoardStatus status) { + infoBoard->clear(); + setInfoBoard(text, status); + infoBoard->verticalScrollBar()->setValue(0); } -void InfoBoardWidget::associateTextEdit(QTextEdit *edit) { - if (mTextPage != nullptr) - disconnect(mTextPage, SIGNAL(textChanged()), this, SLOT(slotReset())); - this->mTextPage = edit; - connect(edit, SIGNAL(textChanged()), this, SLOT(slotReset())); +void InfoBoardWidget::associateTextEdit(QTextEdit* edit) { + if (mTextPage != nullptr) + disconnect(mTextPage, SIGNAL(textChanged()), this, SLOT(slotReset())); + this->mTextPage = edit; + connect(edit, SIGNAL(textChanged()), this, SLOT(slotReset())); } -void InfoBoardWidget::associateFileTreeView(FilePage *treeView) { -// if (mFileTreeView != nullptr) -// disconnect(mFileTreeView, &FilePage::pathChanged, this, &InfoBoardWidget::slotReset); -// this->mFileTreeView = treeView; -// connect(treeView, &FilePage::pathChanged, this, &InfoBoardWidget::slotReset); +void InfoBoardWidget::associateFileTreeView(FilePage* treeView) { + // if (mFileTreeView != nullptr) + // disconnect(mFileTreeView, &FilePage::pathChanged, this, + // &InfoBoardWidget::slotReset); + // this->mFileTreeView = treeView; + // connect(treeView, &FilePage::pathChanged, this, + // &InfoBoardWidget::slotReset); } -void InfoBoardWidget::associateTabWidget(QTabWidget *tab) { - if (mTextPage != nullptr) - disconnect(mTextPage, SIGNAL(textChanged()), this, SLOT(slotReset())); -// if (mFileTreeView != nullptr) -// disconnect(mFileTreeView, &FilePage::pathChanged, this, &InfoBoardWidget::slotReset); - if (mTabWidget != nullptr) { - disconnect(mTabWidget, SIGNAL(tabBarClicked(int)), this, SLOT(slotReset())); - connect(mTabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(slotReset())); - } - - mTextPage = nullptr; - mFileTreeView = nullptr; - mTabWidget = tab; - connect(tab, SIGNAL(tabBarClicked(int)), this, SLOT(slotReset())); - connect(tab, SIGNAL(tabCloseRequested(int)), this, SLOT(slotReset())); +void InfoBoardWidget::associateTabWidget(QTabWidget* tab) { + if (mTextPage != nullptr) + disconnect(mTextPage, SIGNAL(textChanged()), this, SLOT(slotReset())); + // if (mFileTreeView != nullptr) + // disconnect(mFileTreeView, &FilePage::pathChanged, this, + // &InfoBoardWidget::slotReset); + if (mTabWidget != nullptr) { + disconnect(mTabWidget, SIGNAL(tabBarClicked(int)), this, SLOT(slotReset())); + connect(mTabWidget, SIGNAL(tabCloseRequested(int)), this, + SLOT(slotReset())); + } + + mTextPage = nullptr; + mFileTreeView = nullptr; + mTabWidget = tab; + connect(tab, SIGNAL(tabBarClicked(int)), this, SLOT(slotReset())); + connect(tab, SIGNAL(tabCloseRequested(int)), this, SLOT(slotReset())); } - -void InfoBoardWidget::addOptionalAction(const QString &name, const std::function<void()> &action) { - auto actionButton = new QPushButton(name); - auto layout = new QHBoxLayout(); - layout->setContentsMargins(5, 0, 5, 0); - infoBoard->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); - // set margin from surroundings - layout->addWidget(actionButton); - actionButtonLayout->addLayout(layout); - connect(actionButton, &QPushButton::clicked, this, [=]() { - action(); - }); +void InfoBoardWidget::addOptionalAction(const QString& name, + const std::function<void()>& action) { + auto actionButton = new QPushButton(name); + auto layout = new QHBoxLayout(); + layout->setContentsMargins(5, 0, 5, 0); + infoBoard->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); + // set margin from surroundings + layout->addWidget(actionButton); + actionButtonLayout->addLayout(layout); + connect(actionButton, &QPushButton::clicked, this, [=]() { action(); }); } /** * Delete All item in actionButtonLayout */ void InfoBoardWidget::resetOptionActionsMenu() { - deleteWidgetsInLayout(actionButtonLayout, 2); + deleteWidgetsInLayout(actionButtonLayout, 2); } void InfoBoardWidget::slotReset() { - this->infoBoard->clear(); - resetOptionActionsMenu(); + this->infoBoard->clear(); + resetOptionActionsMenu(); } /** * Try Delete all widget from target layout * @param layout target layout */ -void InfoBoardWidget::deleteWidgetsInLayout(QLayout *layout, int start_index) { - QLayoutItem *item; - while ((item = layout->layout()->takeAt(start_index)) != nullptr) { - layout->removeItem(item); - if (item->layout() != nullptr) - deleteWidgetsInLayout(item->layout()); - else if (item->widget() != nullptr) - delete item->widget(); - delete item; - } +void InfoBoardWidget::deleteWidgetsInLayout(QLayout* layout, int start_index) { + QLayoutItem* item; + while ((item = layout->layout()->takeAt(start_index)) != nullptr) { + layout->removeItem(item); + if (item->layout() != nullptr) + deleteWidgetsInLayout(item->layout()); + else if (item->widget() != nullptr) + delete item->widget(); + delete item; + } } + +} // namespace GpgFrontend::UI diff --git a/src/ui/widgets/InfoBoardWidget.h b/src/ui/widgets/InfoBoardWidget.h new file mode 100644 index 00000000..1a13e1a2 --- /dev/null +++ b/src/ui/widgets/InfoBoardWidget.h @@ -0,0 +1,115 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef __VERIFYNOTIFICATION_H__ +#define __VERIFYNOTIFICATION_H__ + +#include "EditorPage.h" +#include "FilePage.h" +#include "gpg/result_analyse/VerifyResultAnalyse.h" +#include "ui/VerifyDetailsDialog.h" + +namespace GpgFrontend::UI { +/** + * @details Enumeration for the status of Verifylabel + */ +typedef enum { + INFO_ERROR_OK = 0, + INFO_ERROR_WARN = 1, + INFO_ERROR_CRITICAL = 2, + INFO_ERROR_NEUTRAL = 3, +} InfoBoardStatus; + +/** + * @brief Class for handling the verifylabel shown at buttom of a textedit-page + */ +class InfoBoardWidget : public QWidget { + Q_OBJECT + public: + /** + * @brief + * + * @param ctx The GPGme-Context + * @param parent The parent widget + */ + explicit InfoBoardWidget(QWidget* parent, KeyList* keyList); + + void associateTextEdit(QTextEdit* edit); + + void associateFileTreeView(FilePage* treeView); + + void associateTabWidget(QTabWidget* tab); + + void addOptionalAction(const QString& name, + const std::function<void()>& action); + + void resetOptionActionsMenu(); + + /** + * @details Set the text and background-color of verify notification. + * + * @param text The text to be set. + * @param verifyLabelStatus The status of label to set the specified color. + */ + void setInfoBoard(const QString& text, InfoBoardStatus verifyLabelStatus); + + QStringList* keysNotInList; /** List with keys, which are in signature but not + in keylist */ + + public slots: + + /** + * @details Import the keys contained in keysNotInList from keyserver + * + */ + void slotImportFromKeyserver(); + + void slotReset(); + + /** + * @details Refresh the contents of dialog. + */ + void slotRefresh(const QString& text, InfoBoardStatus status); + + private: + QMenu* detailMenu; /** Menu for te Button in verfiyNotification */ + QAction* importFromKeyserverAct; /** Action for importing keys from keyserver + which are notin keylist */ + QTextEdit* infoBoard; + KeyList* mKeyList; /** Table holding the keys */ + + QTextEdit* mTextPage{nullptr}; /** TextEdit associated to the notification */ + FilePage* mFileTreeView{ + nullptr}; /** TreeView associated to the notification */ + QTabWidget* mTabWidget{ + nullptr}; /** TreeView associated to the notification */ + + QHBoxLayout* actionButtonLayout; + + void deleteWidgetsInLayout(QLayout* layout, int start_index = 0); +}; + +} // namespace GpgFrontend::UI + +#endif // __VERIFYNOTIFICATION_H__
\ No newline at end of file diff --git a/src/ui/widgets/KeyList.cpp b/src/ui/widgets/KeyList.cpp index 9c9c6763..f9f33d78 100644 --- a/src/ui/widgets/KeyList.cpp +++ b/src/ui/widgets/KeyList.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -26,394 +26,385 @@ #include <utility> -KeyList::KeyList(GpgME::GpgContext *ctx, - KeyListRow::KeyType selectType, - KeyListColumn::InfoType infoType, - QWidget *parent) - : QWidget(parent), mSelectType(selectType), mInfoType(infoType), appPath(qApp->applicationDirPath()), - settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", QSettings::IniFormat) { - mCtx = ctx; - - - mKeyList = new QTableWidget(this); - mKeyList->setColumnCount(7); - mKeyList->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); - mKeyList->verticalHeader()->hide(); - mKeyList->setShowGrid(false); - mKeyList->sortByColumn(2, Qt::AscendingOrder); - mKeyList->setSelectionBehavior(QAbstractItemView::SelectRows); - mKeyList->setSelectionMode(QAbstractItemView::SingleSelection); - - // tableitems not editable - mKeyList->setEditTriggers(QAbstractItemView::NoEditTriggers); - // no focus (rectangle around tableitems) - // may be it should focus on whole row - mKeyList->setFocusPolicy(Qt::NoFocus); - - mKeyList->setAlternatingRowColors(true); - - // Hidden Column For Purpose - if (!(mInfoType & KeyListColumn::TYPE)) { - mKeyList->setColumnHidden(1, true); - } - if (!(mInfoType & KeyListColumn::NAME)) { - mKeyList->setColumnHidden(2, true); - } - if (!(mInfoType & KeyListColumn::EmailAddress)) { - mKeyList->setColumnHidden(3, true); - } - if (!(mInfoType & KeyListColumn::Usage)) { - mKeyList->setColumnHidden(4, true); - } - if (!(mInfoType & KeyListColumn::Validity)) { - mKeyList->setColumnHidden(5, true); - } - if (!(mInfoType & KeyListColumn::FingerPrint)) { - mKeyList->setColumnHidden(6, true); - } +#include "gpg/function/GpgKeyGetter.h" +#include "ui/SignalStation.h" + +namespace GpgFrontend::UI { + +KeyList::KeyList(KeyListRow::KeyType selectType, + KeyListColumn::InfoType infoType, QWidget* parent) + : QWidget(parent), + appPath(qApp->applicationDirPath()), + settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", + QSettings::IniFormat), + mSelectType(selectType), + mInfoType(infoType) { + mKeyList = new QTableWidget(this); + mKeyList->setColumnCount(7); + mKeyList->horizontalHeader()->setSectionResizeMode( + QHeaderView::ResizeToContents); + mKeyList->verticalHeader()->hide(); + mKeyList->setShowGrid(false); + mKeyList->sortByColumn(2, Qt::AscendingOrder); + mKeyList->setSelectionBehavior(QAbstractItemView::SelectRows); + mKeyList->setSelectionMode(QAbstractItemView::SingleSelection); + + // table items not editable + mKeyList->setEditTriggers(QAbstractItemView::NoEditTriggers); + // no focus (rectangle around table items) + // maybe it should focus on whole row + mKeyList->setFocusPolicy(Qt::NoFocus); + + mKeyList->setAlternatingRowColors(true); + + // Hidden Column For Purpose + if (!(mInfoType & KeyListColumn::TYPE)) { + mKeyList->setColumnHidden(1, true); + } + if (!(mInfoType & KeyListColumn::NAME)) { + mKeyList->setColumnHidden(2, true); + } + if (!(mInfoType & KeyListColumn::EmailAddress)) { + mKeyList->setColumnHidden(3, true); + } + if (!(mInfoType & KeyListColumn::Usage)) { + mKeyList->setColumnHidden(4, true); + } + if (!(mInfoType & KeyListColumn::Validity)) { + mKeyList->setColumnHidden(5, true); + } + if (!(mInfoType & KeyListColumn::FingerPrint)) { + mKeyList->setColumnHidden(6, true); + } + + QStringList labels; + labels << _("Select") << _("Type") << _("Name") << _("Email Address") + << _("Usage") << _("Validity") << _("Finger Print"); + + mKeyList->setHorizontalHeaderLabels(labels); + mKeyList->horizontalHeader()->setStretchLastSection(false); + + auto* layout = new QVBoxLayout; + layout->addWidget(mKeyList); + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(3); + setLayout(layout); + + popupMenu = new QMenu(this); + + // register key database refresh signal + connect(SignalStation::GetInstance(), SIGNAL(KeyDatabaseRefresh()), this, + SLOT(slotRefresh())); + connect(mKeyList, SIGNAL(doubleClicked(const QModelIndex&)), this, + SLOT(slotDoubleClicked(const QModelIndex&))); + + setAcceptDrops(true); + slotRefresh(); +} - QStringList labels; - labels << tr("Select") << tr("Type") << tr("Name") << tr("Email Address") - << tr("Usage") << tr("Validity") << tr("Finger Print"); +void KeyList::slotRefresh() { + LOG(INFO) << "KeyList::slotRefresh Called"; - mKeyList->setHorizontalHeaderLabels(labels); - mKeyList->horizontalHeader()->setStretchLastSection(false); + auto keyList = getChecked(); + // while filling the table, sort enabled causes errors + mKeyList->setSortingEnabled(false); + mKeyList->clearContents(); - auto *layout = new QVBoxLayout; - layout->addWidget(mKeyList); - layout->setContentsMargins(0, 0, 0, 0); - layout->setSpacing(3); - setLayout(layout); + auto keys = GpgKeyGetter::GetInstance().FetchKey(); - popupMenu = new QMenu(this); + auto it = keys->begin(); - connect(mKeyList, SIGNAL(doubleClicked(const QModelIndex &)), - this, SLOT(slotDoubleClicked(const QModelIndex &))); - connect(mCtx, SIGNAL(signalKeyInfoChanged()), this, SLOT(slotRefresh())); - setAcceptDrops(true); - slotRefresh(); -} + int row_count = 0; -void KeyList::slotRefresh() { - QStringList *keyList; - keyList = getChecked(); - // while filling the table, sort enabled causes errors - mKeyList->setSortingEnabled(false); - mKeyList->clearContents(); - - GpgKeyList keys = mCtx->getKeys(); - - auto it = keys.begin(); - - int row_count = 0; - - while (it != keys.end()) { - if (mFilter != nullptr) { - if (!mFilter(*it)) { - it = keys.erase(it); - continue; - } - } - if (!excluded_key_ids.isEmpty()) { - - auto iterator = std::find_if(excluded_key_ids.begin(), excluded_key_ids.end(), - [it](const auto &key_id) -> bool { - if (it->id == key_id) return true; - else return false; - }); - - if (iterator != excluded_key_ids.end()) { - it = keys.erase(it); - continue; - } - } - if (mSelectType == KeyListRow::ONLY_SECRET_KEY && !it->is_private_key) { - it = keys.erase(it); - continue; - } - row_count++; - it++; + while (it != keys->end()) { + if (mFilter != nullptr) { + if (!mFilter(*it)) { + it = keys->erase(it); + continue; + } + } + if (!excluded_key_ids.empty()) { + auto iterator = + std::find_if(excluded_key_ids.begin(), excluded_key_ids.end(), + [it](const auto& key_id) -> bool { + if (it->id() == key_id) + return true; + else + return false; + }); + + if (iterator != excluded_key_ids.end()) { + it = keys->erase(it); + continue; + } + } + if (mSelectType == KeyListRow::ONLY_SECRET_KEY && !it->is_private_key()) { + it = keys->erase(it); + continue; + } + row_count++; + it++; + } + + mKeyList->setRowCount(row_count); + + int row_index = 0; + it = keys->begin(); + buffered_keys.clear(); + + while (it != keys->end()) { + buffered_keys.push_back(GpgKeyGetter::GetInstance().GetKey(it->id())); + + auto* tmp0 = new QTableWidgetItem(QString::number(row_index)); + tmp0->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | + Qt::ItemIsSelectable); + tmp0->setTextAlignment(Qt::AlignCenter); + tmp0->setCheckState(Qt::Unchecked); + mKeyList->setItem(row_index, 0, tmp0); + + QString type_str; + QTextStream type_steam(&type_str); + if (it->is_private_key()) { + type_steam << "pub/sec"; + } else { + type_steam << "pub"; } - mKeyList->setRowCount(row_count); - - int row_index = 0; - it = keys.begin(); - buffered_keys.clear(); - - while (it != keys.end()) { - - buffered_keys.push_back(*it); - - auto *tmp0 = new QTableWidgetItem(QString::number(row_index)); - tmp0->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable); - tmp0->setTextAlignment(Qt::AlignCenter); - tmp0->setCheckState(Qt::Unchecked); - mKeyList->setItem(row_index, 0, tmp0); - - QString type_str; - QTextStream type_steam(&type_str); - if (it->is_private_key) { - type_steam << "pub/sec"; - } else { - type_steam << "pub"; - } - - if (it->is_private_key && !it->has_master_key) { - type_steam << "#"; - } - auto *tmp1 = new QTableWidgetItem(type_str); - mKeyList->setItem(row_index, 1, tmp1); - - auto *tmp2 = new QTableWidgetItem(it->name); - tmp2->setToolTip(it->name); - mKeyList->setItem(row_index, 2, tmp2); - auto *tmp3 = new QTableWidgetItem(it->email); - tmp3->setToolTip(it->email); - mKeyList->setItem(row_index, 3, tmp3); - - QString usage; - QTextStream usage_steam(&usage); - - if (GpgME::GpgContext::checkIfKeyCanCert(*it)) - usage_steam << "C"; - if (GpgME::GpgContext::checkIfKeyCanEncr(*it)) - usage_steam << "E"; - if (GpgME::GpgContext::checkIfKeyCanSign(*it)) - usage_steam << "S"; - if (GpgME::GpgContext::checkIfKeyCanAuth(*it)) - usage_steam << "A"; - - auto *temp_usage = new QTableWidgetItem(usage); - temp_usage->setTextAlignment(Qt::AlignCenter); - mKeyList->setItem(row_index, 4, temp_usage); - - auto *temp_validity = new QTableWidgetItem(it->owner_trust); - temp_validity->setTextAlignment(Qt::AlignCenter); - mKeyList->setItem(row_index, 5, temp_validity); - - auto *temp_fpr = new QTableWidgetItem(it->fpr); - temp_fpr->setTextAlignment(Qt::AlignCenter); - mKeyList->setItem(row_index, 6, temp_fpr); - - // strike out expired keys - if (it->expired || it->revoked) { - QFont strike = tmp2->font(); - strike.setStrikeOut(true); - tmp0->setFont(strike); - temp_usage->setFont(strike); - temp_fpr->setFont(strike); - temp_validity->setFont(strike); - tmp1->setFont(strike); - tmp2->setFont(strike); - tmp3->setFont(strike); - } - - it++; - ++row_index; + if (it->is_private_key() && !it->has_master_key()) { + type_steam << "#"; + } + auto* tmp1 = new QTableWidgetItem(type_str); + mKeyList->setItem(row_index, 1, tmp1); + + auto* tmp2 = new QTableWidgetItem(QString::fromStdString(it->name())); + mKeyList->setItem(row_index, 2, tmp2); + auto* tmp3 = new QTableWidgetItem(QString::fromStdString(it->email())); + mKeyList->setItem(row_index, 3, tmp3); + + QString usage; + QTextStream usage_steam(&usage); + + if (it->CanCertActual()) usage_steam << "C"; + if (it->CanEncrActual()) usage_steam << "E"; + if (it->CanSignActual()) usage_steam << "S"; + if (it->CanAuthActual()) usage_steam << "A"; + + auto* temp_usage = new QTableWidgetItem(usage); + temp_usage->setTextAlignment(Qt::AlignCenter); + mKeyList->setItem(row_index, 4, temp_usage); + + auto* temp_validity = + new QTableWidgetItem(QString::fromStdString(it->owner_trust())); + temp_validity->setTextAlignment(Qt::AlignCenter); + mKeyList->setItem(row_index, 5, temp_validity); + + auto* temp_fpr = new QTableWidgetItem(QString::fromStdString(it->fpr())); + temp_fpr->setTextAlignment(Qt::AlignCenter); + mKeyList->setItem(row_index, 6, temp_fpr); + + // strike out expired keys + if (it->expired() || it->revoked()) { + QFont strike = tmp2->font(); + strike.setStrikeOut(true); + tmp0->setFont(strike); + temp_usage->setFont(strike); + temp_fpr->setFont(strike); + temp_validity->setFont(strike); + tmp1->setFont(strike); + tmp2->setFont(strike); + tmp3->setFont(strike); } + it++; + ++row_index; + } - setChecked(keyList); + setChecked(keyList); } -QStringList *KeyList::getChecked() { - auto *ret = new QStringList(); - for (int i = 0; i < mKeyList->rowCount(); i++) { - if (mKeyList->item(i, 0)->checkState() == Qt::Checked) { - *ret << buffered_keys[i].id; - } +KeyIdArgsListPtr KeyList::getChecked() { + auto ret = std::make_unique<KeyIdArgsList>(); + for (int i = 0; i < mKeyList->rowCount(); i++) { + if (mKeyList->item(i, 0)->checkState() == Qt::Checked) { + ret->push_back(buffered_keys[i].id()); } - return ret; + } + return ret; } -QStringList *KeyList::getAllPrivateKeys() { - auto *ret = new QStringList(); - for (int i = 0; i < mKeyList->rowCount(); i++) { - if (mKeyList->item(i, 1) && buffered_keys[i].is_private_key) { - *ret << buffered_keys[i].id; - } +KeyIdArgsListPtr KeyList::getAllPrivateKeys() { + auto ret = std::make_unique<KeyIdArgsList>(); + for (int i = 0; i < mKeyList->rowCount(); i++) { + if (mKeyList->item(i, 1) && buffered_keys[i].is_private_key()) { + ret->push_back(buffered_keys[i].id()); } - return ret; + } + return ret; } -QStringList *KeyList::getPrivateChecked() { - auto *ret = new QStringList(); - for (int i = 0; i < mKeyList->rowCount(); i++) { - if ((mKeyList->item(i, 0)->checkState() == Qt::Checked) && (mKeyList->item(i, 1))) { - *ret << buffered_keys[i].id; - } +KeyIdArgsListPtr KeyList::getPrivateChecked() { + auto ret = std::make_unique<KeyIdArgsList>(); + for (int i = 0; i < mKeyList->rowCount(); i++) { + if ((mKeyList->item(i, 0)->checkState() == Qt::Checked) && + (mKeyList->item(i, 1))) { + ret->push_back(buffered_keys[i].id()); } - return ret; + } + return ret; } -void KeyList::setChecked(QStringList *keyIds) { - if (!keyIds->isEmpty()) { - for (int i = 0; i < mKeyList->rowCount(); i++) { - if (keyIds->contains(buffered_keys[i].id)) { - mKeyList->item(i, 0)->setCheckState(Qt::Checked); - } - } +void KeyList::setChecked(const KeyIdArgsListPtr& keyIds) { + if (!keyIds->empty()) { + for (int i = 0; i < mKeyList->rowCount(); i++) { + if (std::find(keyIds->begin(), keyIds->end(), buffered_keys[i].id()) != + keyIds->end()) { + mKeyList->item(i, 0)->setCheckState(Qt::Checked); + } } + } } -QStringList *KeyList::getSelected() { - auto *ret = new QStringList(); +KeyIdArgsListPtr KeyList::getSelected() { + auto ret = std::make_unique<KeyIdArgsList>(); - for (int i = 0; i < mKeyList->rowCount(); i++) { - if (mKeyList->item(i, 0)->isSelected() == 1) { - *ret << buffered_keys[i].id; - } + for (int i = 0; i < mKeyList->rowCount(); i++) { + if (mKeyList->item(i, 0)->isSelected() == 1) { + ret->push_back(buffered_keys[i].id()); } - return ret; + } + return ret; } [[maybe_unused]] bool KeyList::containsPrivateKeys() { - for (int i = 0; i < mKeyList->rowCount(); i++) { - if (mKeyList->item(i, 1)) { - return true; - } + for (int i = 0; i < mKeyList->rowCount(); i++) { + if (mKeyList->item(i, 1)) { + return true; } - return false; + } + return false; } void KeyList::setColumnWidth(int row, int size) { - mKeyList->setColumnWidth(row, size); -} - -void KeyList::contextMenuEvent(QContextMenuEvent *event) { - if (mKeyList->selectedItems().length() > 0) { - popupMenu->exec(event->globalPos()); - } - + mKeyList->setColumnWidth(row, size); } -void KeyList::addSeparator() { - popupMenu->addSeparator(); +void KeyList::contextMenuEvent(QContextMenuEvent* event) { + if (mKeyList->selectedItems().length() > 0) { + popupMenu->exec(event->globalPos()); + } } -void KeyList::addMenuAction(QAction *act) { - popupMenu->addAction(act); -} - -void KeyList::dropEvent(QDropEvent *event) { +void KeyList::addSeparator() { popupMenu->addSeparator(); } - auto *dialog = new QDialog(); +void KeyList::addMenuAction(QAction* act) { popupMenu->addAction(act); } - dialog->setWindowTitle(tr("Import Keys")); - QLabel *label; - label = new QLabel( - tr("You've dropped something on the table.\n GpgFrontend will now try to import key(s).") + "\n"); +void KeyList::dropEvent(QDropEvent* event) { + auto* dialog = new QDialog(); - // "always import keys"-CheckBox - auto *checkBox = new QCheckBox(tr("Always import without bothering.")); - if (settings.value("general/confirmImportKeys").toBool()) checkBox->setCheckState(Qt::Unchecked); + dialog->setWindowTitle(_("Import Keys")); + QLabel* label; + label = + new QLabel(QString(_("You've dropped something on the table.")) + "\n " + + _("GpgFrontend " + "will now try to import key(s).") + + "\n"); - // Buttons for ok and cancel - auto *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - connect(buttonBox, SIGNAL(accepted()), dialog, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), dialog, SLOT(reject())); + // "always import keys"-CheckBox + auto* checkBox = new QCheckBox(_("Always import without bothering.")); + if (settings.value("general/confirmImportKeys").toBool()) + checkBox->setCheckState(Qt::Unchecked); - auto *vbox = new QVBoxLayout(); - vbox->addWidget(label); - vbox->addWidget(checkBox); - vbox->addWidget(buttonBox); + // Buttons for ok and cancel + auto* buttonBox = + new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + connect(buttonBox, SIGNAL(accepted()), dialog, SLOT(accept())); + connect(buttonBox, SIGNAL(rejected()), dialog, SLOT(reject())); - dialog->setLayout(vbox); + auto* vbox = new QVBoxLayout(); + vbox->addWidget(label); + vbox->addWidget(checkBox); + vbox->addWidget(buttonBox); - if (settings.value("general/confirmImportKeys", Qt::Checked).toBool()) { - dialog->exec(); - if (dialog->result() == QDialog::Rejected) { - return; - } - if (checkBox->isChecked()) { - settings.setValue("general/confirmImportKeys", false); - } else { - settings.setValue("general/confirmImportKeys", true); + dialog->setLayout(vbox); - } + if (settings.value("general/confirmImportKeys", Qt::Checked).toBool()) { + dialog->exec(); + if (dialog->result() == QDialog::Rejected) { + return; } - - if (event->mimeData()->hasUrls()) { - for (const QUrl &tmp : event->mimeData()->urls()) { - QFile file; - file.setFileName(tmp.toLocalFile()); - if (!file.open(QIODevice::ReadOnly)) { - qDebug() << tr("Couldn't Open File: ") + tmp.toString(); - } - QByteArray inBuffer = file.readAll(); - this->importKeys(inBuffer); - file.close(); - } + if (checkBox->isChecked()) { + settings.setValue("general/confirmImportKeys", false); } else { - QByteArray inBuffer(event->mimeData()->text().toUtf8()); - this->importKeys(inBuffer); + settings.setValue("general/confirmImportKeys", true); } + } + + if (event->mimeData()->hasUrls()) { + for (const QUrl& tmp : event->mimeData()->urls()) { + QFile file; + file.setFileName(tmp.toLocalFile()); + if (!file.open(QIODevice::ReadOnly)) { + LOG(INFO) << _("Couldn't Open File") << ":" + << tmp.toString().toStdString(); + } + QByteArray inBuffer = file.readAll(); + this->importKeys(inBuffer); + file.close(); + } + } else { + QByteArray inBuffer(event->mimeData()->text().toUtf8()); + this->importKeys(inBuffer); + } } -void KeyList::dragEnterEvent(QDragEnterEvent *event) { - event->acceptProposedAction(); +void KeyList::dragEnterEvent(QDragEnterEvent* event) { + event->acceptProposedAction(); } /** set background color for Keys and put them to top * */ -[[maybe_unused]] void KeyList::markKeys(QStringList *keyIds) { - foreach(QString id, *keyIds) { - qDebug() << "marked: " << id; - } -} - -void KeyList::importKeys(QByteArray inBuffer) { - GpgImportInformation result = mCtx->importKey(std::move(inBuffer)); - new KeyImportDetailDialog(mCtx, result, false, this); +[[maybe_unused]] void KeyList::markKeys(QStringList* keyIds) { + foreach (QString id, *keyIds) { qDebug() << "marked: " << id; } } -void KeyList::getCheckedKeys(QVector<GpgKey> &keys) { - keys.clear(); - for (int i = 0; i < mKeyList->rowCount(); i++) { - if (mKeyList->item(i, 0)->checkState() == Qt::Checked) { - keys.push_back(buffered_keys[i]); - } - } +void KeyList::importKeys(const QByteArray& inBuffer) { + auto std_buffer = std::make_unique<ByteArray>(inBuffer.toStdString()); + GpgImportInformation result = + GpgKeyImportExportor::GetInstance().ImportKey(std::move(std_buffer)); + new KeyImportDetailDialog(result, false, this); } -void KeyList::setExcludeKeys(std::initializer_list<QString> key_ids) { - excluded_key_ids.clear(); - for (auto &key_id : key_ids) { - excluded_key_ids.push_back(key_id); - } +void KeyList::setExcludeKeys(std::initializer_list<std::string> key_ids) { + excluded_key_ids.clear(); + for (auto& key_id : key_ids) { + excluded_key_ids.push_back(key_id); + } } -void KeyList::setFilter(std::function<bool(const GpgKey &)> filter) { - this->mFilter = std::move(filter); +void KeyList::setFilter(std::function<bool(const GpgKey&)> filter) { + this->mFilter = std::move(filter); } -void KeyList::slotDoubleClicked(const QModelIndex &index) { - if (mAction != nullptr) { - const auto key = mCtx->getKeyById(buffered_keys[index.row()].id); - mAction(key, this); - } - +void KeyList::slotDoubleClicked(const QModelIndex& index) { + if (mAction != nullptr) { + const auto key = + GpgKeyGetter::GetInstance().GetKey(buffered_keys[index.row()].id()); + mAction(key, this); + } } -void KeyList::setDoubleClickedAction(std::function<void(const GpgKey &, QWidget *)> action) { - this->mAction = std::move(action); +void KeyList::setDoubleClickedAction( + std::function<void(const GpgKey&, QWidget*)> action) { + this->mAction = std::move(action); } -void KeyList::getPrivateCheckedKeys(QVector<GpgKey> &keys) { - keys.clear(); - for (int i = 0; i < mKeyList->rowCount(); i++) { - if (mKeyList->item(i, 0)->checkState() == Qt::Checked && buffered_keys[i].is_private_key) { - keys.push_back(buffered_keys[i]); - } +std::string KeyList::getSelectedKey() { + for (int i = 0; i < mKeyList->rowCount(); i++) { + if (mKeyList->item(i, 0)->isSelected() == 1) { + return buffered_keys[i].id(); } + } + return {}; } -GpgKey KeyList::getSelectedKey() { - for (int i = 0; i < mKeyList->rowCount(); i++) { - if (mKeyList->item(i, 0)->isSelected() == 1) { - return buffered_keys[i]; - } - } - return GpgKey(); -} +} // namespace GpgFrontend::UI diff --git a/src/ui/widgets/KeyList.h b/src/ui/widgets/KeyList.h new file mode 100644 index 00000000..524b2bd0 --- /dev/null +++ b/src/ui/widgets/KeyList.h @@ -0,0 +1,124 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef __KEYLIST_H__ +#define __KEYLIST_H__ + +#include "gpg/GpgContext.h" +#include "ui/KeyImportDetailDialog.h" +namespace GpgFrontend::UI { + +struct KeyListRow { + using KeyType = unsigned int; + + static const KeyType SECRET_OR_PUBLIC_KEY = 0; + static const KeyType ONLY_SECRET_KEY = 1; +}; + +struct KeyListColumn { + using InfoType = unsigned int; + + static constexpr InfoType ALL = ~0; + static constexpr InfoType TYPE = 1 << 0; + static constexpr InfoType NAME = 1 << 1; + static constexpr InfoType EmailAddress = 1 << 2; + static constexpr InfoType Usage = 1 << 3; + static constexpr InfoType Validity = 1 << 4; + static constexpr InfoType FingerPrint = 1 << 5; +}; + +class KeyList : public QWidget { + Q_OBJECT + + public: + explicit KeyList( + KeyListRow::KeyType selectType = KeyListRow::SECRET_OR_PUBLIC_KEY, + KeyListColumn::InfoType infoType = KeyListColumn::ALL, + QWidget* parent = nullptr); + + void setExcludeKeys(std::initializer_list<std::string> key_ids); + + void setFilter(std::function<bool(const GpgKey&)> filter); + + void setDoubleClickedAction( + std::function<void(const GpgKey&, QWidget*)> action); + + void setColumnWidth(int row, int size); + + void addMenuAction(QAction* act); + + void addSeparator(); + + KeyIdArgsListPtr getChecked(); + + KeyIdArgsListPtr getPrivateChecked(); + + KeyIdArgsListPtr getAllPrivateKeys(); + + void setChecked(const KeyIdArgsListPtr& keyIds); + + KeyIdArgsListPtr getSelected(); + + std::string getSelectedKey(); + + [[maybe_unused]] static void markKeys(QStringList* keyIds); + + [[maybe_unused]] bool containsPrivateKeys(); + + public slots: + + void slotRefresh(); + + private: + void importKeys(const QByteArray& inBuffer); + + QString appPath; + QSettings settings; + + QTableWidget* mKeyList; + QMenu* popupMenu; + QNetworkAccessManager* qnam{}; + std::vector<GpgKey> buffered_keys; + KeyListRow::KeyType mSelectType; + KeyListColumn::InfoType mInfoType; + std::vector<std::string> excluded_key_ids; + + std::function<bool(const GpgKey&)> mFilter = nullptr; + std::function<void(const GpgKey&, QWidget*)> mAction = nullptr; + + private slots: + + void slotDoubleClicked(const QModelIndex& index); + + protected: + void contextMenuEvent(QContextMenuEvent* event) override; + + void dragEnterEvent(QDragEnterEvent* event) override; + + void dropEvent(QDropEvent* event) override; +}; + +} // namespace GpgFrontend::UI + +#endif // __KEYLIST_H__ diff --git a/src/ui/widgets/SignersPicker.cpp b/src/ui/widgets/SignersPicker.cpp index 00df5fdd..3e4b3bb5 100644 --- a/src/ui/widgets/SignersPicker.cpp +++ b/src/ui/widgets/SignersPicker.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -24,36 +24,46 @@ #include "ui/widgets/SignersPicker.h" -SignersPicker::SignersPicker(GpgME::GpgContext *ctx, QWidget *parent) : mCtx(ctx), QDialog(parent) { - auto confirmButton = new QPushButton(tr("Confirm")); - connect(confirmButton, SIGNAL(clicked(bool)), this, SLOT(accept())); +namespace GpgFrontend::UI { - /*Setup KeyList*/ - mKeyList = new KeyList(mCtx, KeyListRow::ONLY_SECRET_KEY, - KeyListColumn::NAME | KeyListColumn::EmailAddress | KeyListColumn::Usage); +SignersPicker::SignersPicker(QWidget* parent) : QDialog(parent) { + auto confirmButton = new QPushButton(_("Confirm")); + connect(confirmButton, SIGNAL(clicked(bool)), this, SLOT(accept())); - mKeyList->setFilter([](const GpgKey &key) -> bool { - if (!GpgME::GpgContext::checkIfKeyCanSign(key)) return false; - else return true; - }); + /*Setup KeyList*/ + mKeyList = new KeyList( + KeyListRow::ONLY_SECRET_KEY, + KeyListColumn::NAME | KeyListColumn::EmailAddress | KeyListColumn::Usage); - mKeyList->slotRefresh(); + mKeyList->setFilter([](const GpgKey& key) -> bool { + if (!key.CanSignActual()) + return false; + else + return true; + }); - auto *vbox2 = new QVBoxLayout(); - vbox2->addWidget(new QLabel("Select Signer(s): ")); - vbox2->addWidget(mKeyList); - vbox2->addWidget(confirmButton); - vbox2->addStretch(0); - setLayout(vbox2); + mKeyList->slotRefresh(); - this->setModal(true); - this->setWindowTitle("Signers Picker"); - this->setMinimumWidth(480); - this->show(); + auto* vbox2 = new QVBoxLayout(); + vbox2->addWidget(new QLabel(QString(_("Select Signer(s)")) + ": ")); + vbox2->addWidget(mKeyList); + vbox2->addWidget(new QLabel( + _("Selecting Nothing will eventually use default key to sign."))); + vbox2->addWidget(confirmButton); + vbox2->addStretch(0); + setLayout(vbox2); + this->setWindowFlags(Qt::Window | Qt::WindowTitleHint | + Qt::CustomizeWindowHint); + this->setModal(true); + this->setWindowTitle("Signers Picker"); + this->setMinimumWidth(480); + this->show(); } -void SignersPicker::getCheckedSigners(QVector<GpgKey> &keys) { - mKeyList->getPrivateCheckedKeys(keys); +GpgFrontend::KeyIdArgsListPtr SignersPicker::getCheckedSigners() { + return mKeyList->getPrivateChecked(); } + +} // namespace GpgFrontend::UI diff --git a/src/ui/widgets/SignersPicker.h b/src/ui/widgets/SignersPicker.h new file mode 100644 index 00000000..055b6ef6 --- /dev/null +++ b/src/ui/widgets/SignersPicker.h @@ -0,0 +1,48 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_ZH_CN_TS_SIGNERSPIRCKER_H +#define GPGFRONTEND_ZH_CN_TS_SIGNERSPIRCKER_H + +#include "GpgFrontend.h" +#include "gpg/GpgContext.h" +#include "ui/widgets/KeyList.h" + +namespace GpgFrontend::UI { + +class SignersPicker : public QDialog { + Q_OBJECT + + public: + explicit SignersPicker(QWidget* parent = nullptr); + + GpgFrontend::KeyIdArgsListPtr getCheckedSigners(); + + private: + KeyList* mKeyList; +}; + +} // namespace GpgFrontend::UI + +#endif // GPGFRONTEND_ZH_CN_TS_SIGNERSPIRCKER_H diff --git a/src/ui/widgets/TextEdit.cpp b/src/ui/widgets/TextEdit.cpp index eab0f799..8d4ea4a0 100644 --- a/src/ui/widgets/TextEdit.cpp +++ b/src/ui/widgets/TextEdit.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -24,14 +24,18 @@ #include "ui/widgets/TextEdit.h" -TextEdit::TextEdit(QWidget *parent) : QWidget(parent) { +#include <boost/format.hpp> + +namespace GpgFrontend::UI { + +TextEdit::TextEdit(QWidget* parent) : QWidget(parent) { countPage = 0; tabWidget = new QTabWidget(this); tabWidget->setMovable(true); tabWidget->setTabsClosable(true); tabWidget->setDocumentMode(true); - auto *layout = new QVBoxLayout; + auto* layout = new QVBoxLayout; layout->addWidget(tabWidget); layout->setContentsMargins(0, 0, 0, 0); layout->setSpacing(0); @@ -39,20 +43,14 @@ TextEdit::TextEdit(QWidget *parent) : QWidget(parent) { connect(tabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(removeTab(int))); - connect(this, &TextEdit::insertTargetTextPage, this, - &TextEdit::slotInsertTargetTextPage); - connect(this, &TextEdit::readTargetTextPageStart, this, - &TextEdit::slotReadTargetTextPageStart); - connect(this, &TextEdit::readTargetTextPageDone, this, - &TextEdit::slotReadTargetTextPageDone); slotNewTab(); setAcceptDrops(false); } void TextEdit::slotNewTab() { - QString header = tr("untitled") + QString::number(++countPage) + ".txt"; + QString header = _("untitled") + QString::number(++countPage) + ".txt"; - auto *page = new EditorPage(); + auto* page = new EditorPage(); tabWidget->addTab(page, header); tabWidget->setCurrentIndex(tabWidget->count() - 1); page->getTextPage()->setFocus(); @@ -60,131 +58,59 @@ void TextEdit::slotNewTab() { this, SLOT(slotShowModified())); } -void TextEdit::slotNewHelpTab(const QString &title, const QString &path) const { - - auto *page = new HelpPage(path); +void TextEdit::slotNewHelpTab(const QString& title, const QString& path) const { + auto* page = new HelpPage(path); tabWidget->addTab(page, title); tabWidget->setCurrentIndex(tabWidget->count() - 1); } void TextEdit::slotNewFileTab() const { - - auto *page = new FilePage(qobject_cast<QWidget *>(parent())); + auto* page = new FilePage(qobject_cast<QWidget*>(parent())); tabWidget->addTab(page, "[Browser]"); tabWidget->setCurrentIndex(tabWidget->count() - 1); - connect(page, SIGNAL(pathChanged(const QString &)), this, - SLOT(slotFilePagePathChanged(const QString &))); + connect(page, SIGNAL(pathChanged(const QString&)), this, + SLOT(slotFilePagePathChanged(const QString&))); } -void TextEdit::slotOpenFile(QString &path) { - +void TextEdit::slotOpenFile(QString& path) { QFile file(path); - - if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { - auto *page = new EditorPage(path); - pagesHashMap.insert(page->uuid, page); + LOG(INFO) << " path" << path.toStdString(); + auto result = file.open(QIODevice::ReadOnly | QIODevice::Text); + if (result) { + auto* page = new EditorPage(path); QApplication::setOverrideCursor(Qt::WaitCursor); - - auto read_thread = QThread::create([&, page]() { - QFile targetFile(path); - - if (targetFile.open(QIODevice::ReadOnly | QIODevice::Text)) { - emit readTargetTextPageStart(page->uuid); - QTextStream in(&targetFile); - QString readText; - qDebug() << "Thread Start Reading" << path; - while (!((readText = in.read(8192)).isEmpty())) { - emit insertTargetTextPage(page->uuid, readText); - QThread::msleep(64); - } - targetFile.close(); - emit readTargetTextPageDone(page->uuid); - qDebug() << "Thread End Reading" << path; - } - }); - - page->setFilePath(path); - QTextDocument *document = page->getTextPage()->document(); - document->setModified(false); - tabWidget->addTab(page, strippedName(path)); tabWidget->setCurrentIndex(tabWidget->count() - 1); QApplication::restoreOverrideCursor(); page->getTextPage()->setFocus(); - - file.close(); - read_thread->start(); - + page->ReadFile(); } else { - QMessageBox::warning( - this, tr("Warning"), - tr("Cannot read file %1:\n%2.").arg(path).arg(file.errorString())); + QMessageBox::warning(this, _("Warning"), + (boost::format(_("Cannot read file %1%:\n%2%.")) % + path.toStdString() % file.errorString().toStdString()) + .str() + .c_str()); } -} -void TextEdit::slotInsertTargetTextPage(const QString &pagePtr, - const QString &text) { - auto it = pagesHashMap.find(pagePtr); - if (it != pagesHashMap.end()) { - auto *taregtTextPage = qobject_cast<EditorPage *>(it.value()); - if (taregtTextPage != nullptr) { - taregtTextPage->getTextPage()->insertPlainText(text); - taregtTextPage->getTextPage()->document()->setModified(false); - } - } -} - -void TextEdit::slotReadTargetTextPageStart(const QString &pagePtr) { - auto it = pagesHashMap.find(pagePtr); - if (it != pagesHashMap.end()) { - auto *taregtTextPage = qobject_cast<EditorPage *>(it.value()); - if (taregtTextPage != nullptr) { - qDebug() << "Setting TextEdit At Start" << pagePtr; - taregtTextPage->getTextPage()->setReadOnly(true); - auto index = tabWidget->indexOf(taregtTextPage); - if (index != -1) { - tabWidget->setTabText( - index, "[Loading] " + strippedName(taregtTextPage->getFilePath())); - } - } - } -} - -void TextEdit::slotReadTargetTextPageDone(const QString &pagePtr) { - auto it = pagesHashMap.find(pagePtr); - if (it != pagesHashMap.end()) { - auto *taregtTextPage = qobject_cast<EditorPage *>(it.value()); - if (taregtTextPage != nullptr) { - qDebug() << "Setting TextEdit At End" << pagePtr; - taregtTextPage->getTextPage()->setReadOnly(false); - auto index = tabWidget->indexOf(taregtTextPage); - if (index != -1) { - tabWidget->setTabText(index, - strippedName(taregtTextPage->getFilePath())); - } - taregtTextPage->getTextPage()->document()->setModified(false); - connect(taregtTextPage->getTextPage()->document(), - SIGNAL(modificationChanged(bool)), this, - SLOT(slotShowModified())); - } - } + file.close(); + LOG(INFO) << "done"; } void TextEdit::slotOpen() { QStringList fileNames = - QFileDialog::getOpenFileNames(this, tr("Open file"), QDir::currentPath()); - for (const auto &fileName : fileNames) { + QFileDialog::getOpenFileNames(this, _("Open file"), QDir::currentPath()); + for (const auto& fileName : fileNames) { if (!fileName.isEmpty()) { QFile file(fileName); if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { - auto *page = new EditorPage(fileName); + auto* page = new EditorPage(fileName); QTextStream in(&file); QApplication::setOverrideCursor(Qt::WaitCursor); page->getTextPage()->setPlainText(in.readAll()); page->setFilePath(fileName); - QTextDocument *document = page->getTextPage()->document(); + QTextDocument* document = page->getTextPage()->document(); document->setModified(false); tabWidget->addTab(page, strippedName(fileName)); @@ -197,10 +123,12 @@ void TextEdit::slotOpen() { // enableAction(true) file.close(); } else { - QMessageBox::warning(this, tr("Warning"), - tr("Cannot read file %1:\n%2.") - .arg(fileName) - .arg(file.errorString())); + QMessageBox::warning( + this, _("Warning"), + (boost::format(_("Cannot read file %1%:\n%2%.")) % + fileName.toStdString() % file.errorString().toStdString()) + .str() + .c_str()); } } } @@ -222,7 +150,7 @@ void TextEdit::slotSave() { } } -bool TextEdit::saveFile(const QString &fileName) { +bool TextEdit::saveFile(const QString& fileName) { if (fileName.isEmpty()) { return false; } @@ -230,44 +158,47 @@ bool TextEdit::saveFile(const QString &fileName) { QFile file(fileName); if (file.open(QIODevice::WriteOnly | QIODevice::Text)) { - EditorPage *page = slotCurPageTextEdit(); + EditorPage* page = slotCurPageTextEdit(); QTextStream outputStream(&file); QApplication::setOverrideCursor(Qt::WaitCursor); outputStream << page->getTextPage()->toPlainText(); QApplication::restoreOverrideCursor(); - QTextDocument *document = page->getTextPage()->document(); + QTextDocument* document = page->getTextPage()->document(); document->setModified(false); int curIndex = tabWidget->currentIndex(); tabWidget->setTabText(curIndex, strippedName(fileName)); page->setFilePath(fileName); - // statusBar()->showMessage(tr("File saved"), 2000); + // statusBar()->showMessage(_("File saved"), 2000); file.close(); return true; } else { QMessageBox::warning( - this, tr("File"), - tr("Cannot write file %1:\n%2.").arg(fileName).arg(file.errorString())); + this, _("Warning"), + (boost::format(_("Cannot read file %1%:\n%2%.")) % + fileName.toStdString() % file.errorString().toStdString()) + .str() + .c_str()); return false; } } bool TextEdit::slotSaveAs() { - if (tabWidget->count() == 0 || slotCurPageTextEdit() == 0) { + if (tabWidget->count() == 0 || slotCurPageTextEdit() == nullptr) { return true; } - EditorPage *page = slotCurPageTextEdit(); + EditorPage* page = slotCurPageTextEdit(); QString path; - if (page->getFilePath() != "") { + if (!page->getFilePath().isEmpty()) { path = page->getFilePath(); } else { path = tabWidget->tabText(tabWidget->currentIndex()).remove(0, 2); } - QString fileName = QFileDialog::getSaveFileName(this, tr("Save file"), path); + QString fileName = QFileDialog::getSaveFileName(this, _("Save file"), path); return saveFile(fileName); } @@ -312,34 +243,35 @@ void TextEdit::removeTab(int index) { * If it returns false, the close event should be aborted. */ bool TextEdit::maybeSaveCurrentTab(bool askToSave) { - - EditorPage *page = slotCurPageTextEdit(); + EditorPage* page = slotCurPageTextEdit(); // if this page is no textedit, there should be nothing to save if (page == nullptr) { return true; } - QTextDocument *document = page->getTextPage()->document(); + QTextDocument* document = page->getTextPage()->document(); - if (document->isModified()) { + if (page->ReadDone() && document->isModified()) { QMessageBox::StandardButton result = QMessageBox::Cancel; // write title of tab to docname and remove the leading * QString docname = tabWidget->tabText(tabWidget->currentIndex()); docname.remove(0, 2); - const QString &filePath = page->getFilePath(); + const QString& filePath = page->getFilePath(); if (askToSave) { result = QMessageBox::warning( - this, tr("Unsaved document"), - tr("The document \"%1\" has been modified. Do you want to " - "save your changes?<br/>") + this, _("Unsaved document"), + QString(_("The document \"%1\" has been modified. Do you want to " + "save your changes?")) .arg(docname) + - tr("<b>Note:</b> If you don't save these files, all changes are " - "lost.<br/>"), + "<br/><b>" + _("Note:") + "</b>" + + _("If you don't save these files, all changes are " + "lost.") + + "<br/>", QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); } if ((result == QMessageBox::Save) || (!askToSave)) { - if (filePath == "") { + if (filePath.isEmpty()) { // QString docname = tabWidget->tabText(tabWidget->currentIndex()); // docname.remove(0,2); return slotSaveAs(); @@ -352,6 +284,9 @@ bool TextEdit::maybeSaveCurrentTab(bool askToSave) { return false; } } + + // destroy + page->PrepareToDestroy(); return true; } @@ -381,7 +316,7 @@ bool TextEdit::maybeSaveAnyTab() { if (unsavedDocs.size() > 1) { QHashIterator<int, QString> i(unsavedDocs); - QuitDialog *dialog; + QuitDialog* dialog; dialog = new QuitDialog(this, unsavedDocs); int result = dialog->exec(); @@ -394,28 +329,24 @@ bool TextEdit::maybeSaveAnyTab() { return false; } } else { - bool allsaved = true; + bool all_saved = true; QList<int> tabIdsToSave = dialog->getTabIdsToSave(); - foreach (int tabId, tabIdsToSave) { + for (const auto& tabId : tabIdsToSave) { tabWidget->setCurrentIndex(tabId); if (!maybeSaveCurrentTab(false)) { - allsaved = false; + all_saved = false; } } - if (allsaved) { - return true; - } else { - return false; - } + return all_saved; } } // code should never reach this statement return false; } -QTextEdit *TextEdit::curTextPage() const { - auto *curTextPage = qobject_cast<EditorPage *>(tabWidget->currentWidget()); +QTextEdit* TextEdit::curTextPage() const { + auto* curTextPage = qobject_cast<EditorPage*>(tabWidget->currentWidget()); if (curTextPage != nullptr) { return curTextPage->getTextPage(); } else { @@ -423,8 +354,8 @@ QTextEdit *TextEdit::curTextPage() const { } } -FilePage *TextEdit::curFilePage() const { - auto *curFilePage = qobject_cast<FilePage *>(tabWidget->currentWidget()); +FilePage* TextEdit::curFilePage() const { + auto* curFilePage = qobject_cast<FilePage*>(tabWidget->currentWidget()); if (curFilePage != nullptr) { return curFilePage; } else { @@ -434,13 +365,13 @@ FilePage *TextEdit::curFilePage() const { int TextEdit::tabCount() const { return tabWidget->count(); } -EditorPage *TextEdit::slotCurPageTextEdit() const { - auto *curPage = qobject_cast<EditorPage *>(tabWidget->currentWidget()); +EditorPage* TextEdit::slotCurPageTextEdit() const { + auto* curPage = qobject_cast<EditorPage*>(tabWidget->currentWidget()); return curPage; } -FilePage *TextEdit::slotCurPageFileTreeView() const { - auto *curPage = qobject_cast<FilePage *>(tabWidget->currentWidget()); +FilePage* TextEdit::slotCurPageFileTreeView() const { + auto* curPage = qobject_cast<FilePage*>(tabWidget->currentWidget()); return curPage; } @@ -466,7 +397,7 @@ void TextEdit::slotQuote() const { cursor.endEditBlock(); } -void TextEdit::slotFillTextEditWithText(const QString &text) const { +void TextEdit::slotFillTextEditWithText(const QString& text) const { QTextCursor cursor(curTextPage()->document()); cursor.beginEditBlock(); this->curTextPage()->selectAll(); @@ -474,12 +405,15 @@ void TextEdit::slotFillTextEditWithText(const QString &text) const { cursor.endEditBlock(); } -void TextEdit::loadFile(const QString &fileName) { +void TextEdit::loadFile(const QString& fileName) { QFile file(fileName); if (!file.open(QFile::ReadOnly | QFile::Text)) { QMessageBox::warning( - this, tr("Application"), - tr("Cannot read file %1:\n%2.").arg(fileName).arg(file.errorString())); + this, _("Warning"), + (boost::format(_("Cannot read file %1%:\n%2%.")) % + fileName.toStdString() % file.errorString().toStdString()) + .str() + .c_str()); return; } QTextStream in(&file); @@ -489,10 +423,10 @@ void TextEdit::loadFile(const QString &fileName) { slotCurPageTextEdit()->setFilePath(fileName); tabWidget->setTabText(tabWidget->currentIndex(), strippedName(fileName)); file.close(); - // statusBar()->showMessage(tr("File loaded"), 2000); + // statusBar()->showMessage(_("File loaded"), 2000); } -QString TextEdit::strippedName(const QString &fullFileName) { +QString TextEdit::strippedName(const QString& fullFileName) { return QFileInfo(fullFileName).fileName(); } @@ -502,19 +436,19 @@ void TextEdit::slotPrint() { } #ifndef QT_NO_PRINTER - QTextDocument *document; + QTextDocument* document; if (curTextPage() != nullptr) { document = curTextPage()->document(); } QPrinter printer; - auto *dlg = new QPrintDialog(&printer, this); + auto* dlg = new QPrintDialog(&printer, this); if (dlg->exec() != QDialog::Accepted) { return; } document->print(&printer); - // statusBar()->showMessage(tr("Ready"), 2000); + // statusBar()->showMessage(_("Ready"), 2000); #endif } @@ -549,16 +483,19 @@ void TextEdit::slotSwitchTabDown() const { * return a hash of tabindexes and title of unsaved tabs */ QHash<int, QString> TextEdit::unsavedDocuments() const { - QHash<int, QString> unsavedDocs; // this list could be used to implement gedit - // like "unsaved changed"-dialog + QHash<int, QString> unsavedDocs; // this list could be used to implement + // gedit like "unsaved changed"-dialog for (int i = 0; i < tabWidget->count(); i++) { - auto *ep = qobject_cast<EditorPage *>(tabWidget->widget(i)); - if (ep != nullptr && ep->getTextPage()->document()->isModified()) { - QString docname = tabWidget->tabText(i); + auto* ep = qobject_cast<EditorPage*>(tabWidget->widget(i)); + if (ep != nullptr && ep->ReadDone() && + ep->getTextPage()->document()->isModified()) { + QString doc_name = tabWidget->tabText(i); + LOG(INFO) << "unsaved" << doc_name.toStdString(); + // remove * before name of modified doc - docname.remove(0, 2); - unsavedDocs.insert(i, docname); + doc_name.remove(0, 2); + unsavedDocs.insert(i, doc_name); } } return unsavedDocs; @@ -633,7 +570,7 @@ void TextEdit::slotSelectAll() const { curTextPage()->selectAll(); } -void TextEdit::slotFilePagePathChanged(const QString &path) { +void TextEdit::slotFilePagePathChanged(const QString& path) const { int index = tabWidget->currentIndex(); QString mPath; QFileInfo fileInfo(path); @@ -644,6 +581,7 @@ void TextEdit::slotFilePagePathChanged(const QString &path) { mPath = tPath; } mPath.prepend("[Browser] "); - mPath.append("/"); tabWidget->setTabText(index, mPath); } + +} // namespace GpgFrontend::UI diff --git a/src/ui/widgets/TextEdit.h b/src/ui/widgets/TextEdit.h new file mode 100644 index 00000000..3cff74e7 --- /dev/null +++ b/src/ui/widgets/TextEdit.h @@ -0,0 +1,282 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef __TEXTEDIT_H__ +#define __TEXTEDIT_H__ + +#include "ui/QuitDialog.h" +#include "ui/widgets/EditorPage.h" +#include "ui/widgets/FilePage.h" +#include "ui/widgets/HelpPage.h" + +namespace GpgFrontend::UI { +/** + * @brief TextEdit class + */ +class TextEdit : public QWidget { + Q_OBJECT + public: + /** + * @brief + */ + TextEdit(QWidget* parent); + + /** + * @details Load the content of file into the current textpage + * + * @param fileName QString containing the filename to load + * @return nothing + */ + void loadFile(const QString& fileName); + + /** + * @details Checks if there are unsaved documents in any tab, + * which may need to be saved. Call this function before + * closing the programme or all tabs. + * @return \li false, if the close event should be aborted. + * \li true, otherwise + */ + bool maybeSaveAnyTab(); + + [[nodiscard]] int tabCount() const; + + /** + * @details textpage of the currently activated tab + * @return \li reference to QTextEdit if tab has one + * \li 0 otherwise (e.g. if helppage) + */ + [[nodiscard]] QTextEdit* curTextPage() const; + + [[nodiscard]] FilePage* curFilePage() const; + + /** + * @details List of currently unsaved tabs. + * @returns QHash<int, QString> Hash of tabindexes and title of unsaved tabs. + */ + [[nodiscard]] QHash<int, QString> unsavedDocuments() const; + + QTabWidget* tabWidget; /** Widget containing the tabs of the editor */ + + public slots: + + /** + * @details Return pointer to the currently activated text edit tab page. + * + */ + EditorPage* slotCurPageTextEdit() const; + + /** + * @details Return pointer to the currently activated file treeview tab page. + * + */ + FilePage* slotCurPageFileTreeView() const; + + /** + * @details Insert a ">" at the begining of every line of current textedit. + */ + void slotQuote() const; + + /** + * @details replace the text of currently active textedit with given text. + * @param text to fill on. + */ + void slotFillTextEditWithText(const QString& text) const; + + /** + * @details Saves the content of the current tab, if it has a filepath + * otherwise it calls saveAs for the current tab + */ + void slotSave(); + + /** + * @details Opens a savefiledialog and calls saveFile with the choosen + * filename. + * + * @return Return the return value of the savefile method + */ + bool slotSaveAs(); + + /** + * @details Show an OpenFileDoalog and open the file in a new tab. + * Shows an error dialog, if the open fails. + * Set the focus to the tab of the opened file. + */ + void slotOpen(); + + /** + * @details Open a print-dialog for the current tab + */ + void slotPrint(); + + /** + * @details Adds a new tab with the title "untitled"+countpage+".txt" + * Sets the focus to the new tab. Increase Tab-Count by + * one + */ + void slotNewTab(); + + /** + * @details Adds a new tab with opening file by path + */ + void slotOpenFile(QString& path); + + /** + * @details Adds a new tab with the given title and opens given html file. + * Increase Tab-Count by one + * @param title title for the tab + * @param path path for html file to show + */ + void slotNewHelpTab(const QString& title, const QString& path) const; + + /** + * New File Tab to do file operation + */ + void slotNewFileTab() const; + + /** + * @details put a * in front of current tabs title, if current textedit is + * modified + */ + void slotShowModified() const; + + /** + * @details close the current tab and decrease TabWidget->count by \a 1 + * + */ + void slotCloseTab(); + + /** + * @details Switch to the next tab. + * + */ + void slotSwitchTabUp() const; + + /** + * @details Switch to the previous tab. + * + */ + void slotSwitchTabDown() const; + + private: + /** + * @details return just a filename stripped of a whole path + * + * @param a filename path + * @return QString containing the filename + */ + static QString strippedName(const QString& fullFileName); + + /** + * @brief + * + * @param askToSave + */ + bool maybeSaveCurrentTab(bool askToSave); + + /**************************************************************************************** + * Name: countPage + * Description: int cotaining the number of added tabs + */ + int countPage; /* TODO */ + + private slots: + + void slotFilePagePathChanged(const QString& path) const; + + /** + * @details Remove the tab with given index + * + * @param index Tab-number to remove + */ + void removeTab(int index); + + /** + * @details Cut selected text in current textpage. + */ + void slotCut() const; + + /** + * @details Copy selected text of current textpage to clipboard. + */ + void slotCopy() const; + + /** + * @details Paste text from clipboard to current textpage. + */ + void slotPaste() const; + + /** + * @details Undo last change in current textpage. + * + */ + void slotUndo() const; + /**************************************************************************************** + * Name: redo + * Description: redo last change in current textpage + * Parameters: none + * Return Values: none + * Change on members: none + */ + /** + * @brief + * + */ + void slotRedo() const; + + void slotZoomIn() const; + + void slotZoomOut() const; + /**************************************************************************************** + * Name: selectAll + * Description: select all in current textpage + * Parameters: none + * Return Values: none + * Change on members: none + */ + /** + * @brief + * + */ + void slotSelectAll() const; + + protected: + /**************************************************************************************** + * Name: saveFile + * Description: Saves the content of currentTab to the file filename + * Parameters: QString filename contains the full path of the file to + * save Return Values: true, if the file was saved succesfully false, if + * parameter filename is empty or the saving failed Change on members: sets + * isModified of the current tab to false + */ + /** + * @brief + * + * @param fileName + */ + bool saveFile(const QString& fileName); +}; + +} // namespace GpgFrontend::UI + +#endif // __TEXTEDIT_H__ diff --git a/src/ui/widgets/VerifyKeyDetailBox.cpp b/src/ui/widgets/VerifyKeyDetailBox.cpp index e0f79c3e..cd5b6641 100644 --- a/src/ui/widgets/VerifyKeyDetailBox.cpp +++ b/src/ui/widgets/VerifyKeyDetailBox.cpp @@ -1,7 +1,7 @@ /** - * This file is part of GPGFrontend. + * This file is part of GpgFrontend. * - * GPGFrontend is free software: you can redistribute it and/or modify + * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -24,180 +24,198 @@ #include "ui/widgets/VerifyKeyDetailBox.h" -VerifyKeyDetailBox::VerifyKeyDetailBox(QWidget *parent, GpgME::GpgContext *ctx, KeyList *keyList, - gpgme_signature_t signature) : - QGroupBox(parent), mCtx(ctx), mKeyList(keyList), fpr(signature->fpr) { +#include "gpg/function/GpgKeyGetter.h" - auto *vbox = new QVBoxLayout(); +namespace GpgFrontend::UI { - switch (gpg_err_code(signature->status)) { - case GPG_ERR_NO_PUBKEY: { - this->setTitle("A Error Signature"); - auto *importButton = new QPushButton(tr("Import from keyserver")); - connect(importButton, SIGNAL(clicked()), this, SLOT(slotImportFormKeyserver())); +VerifyKeyDetailBox::VerifyKeyDetailBox(QWidget* parent, KeyList* keyList, + gpgme_signature_t signature) + : QGroupBox(parent), mKeyList(keyList), fpr(signature->fpr) { + auto* vbox = new QVBoxLayout(); - this->setTitle(tr("Key not present with id 0x") + signature->fpr); + switch (gpg_err_code(signature->status)) { + case GPG_ERR_NO_PUBKEY: { + this->setTitle("A Error Signature"); + auto* importButton = new QPushButton(_("Import from keyserver")); + connect(importButton, SIGNAL(clicked()), this, + SLOT(slotImportFormKeyserver())); - auto grid = new QGridLayout(); + this->setTitle(QString(_("Key not present with id 0x")) + signature->fpr); - grid->addWidget(new QLabel(tr("Status:")), 0, 0); - //grid->addWidget(new QLabel(tr("Fingerprint:")), 1, 0); - grid->addWidget(new QLabel(tr("Key not present in keylist")), 0, 1); - //grid->addWidget(new QLabel(signature->fpr), 1, 1); - grid->addWidget(importButton, 2, 0, 2, 1); + auto grid = new QGridLayout(); - vbox->addLayout(grid); - break; - } - case GPG_ERR_NO_ERROR: { - this->setTitle("A Signature:"); - auto gird = createKeyInfoGrid(signature); - if(gird != nullptr) { - vbox->addLayout(gird); - } else { - vbox->addWidget(new QLabel(tr("Key Information is NOT Available"))); - if(signature->fpr != nullptr) { - vbox->addWidget(new QLabel(tr("Fingerprint: ") + QString(signature->fpr))); - } - } - break; + grid->addWidget(new QLabel(QString(_("Status")) + _(":")), 0, 0); + // grid->addWidget(new QLabel(_("Fingerprint:")), 1, 0); + grid->addWidget(new QLabel(_("Key not present in key list")), 0, 1); + // grid->addWidget(new QLabel(signature->fpr), 1, 1); + grid->addWidget(importButton, 2, 0, 2, 1); + + vbox->addLayout(grid); + break; + } + case GPG_ERR_NO_ERROR: { + this->setTitle(QString(_("A Signature")) + ":"); + auto gird = createKeyInfoGrid(signature); + if (gird != nullptr) { + vbox->addLayout(gird); + } else { + vbox->addWidget(new QLabel(_("Key Information is NOT Available"))); + if (signature->fpr != nullptr) { + vbox->addWidget(new QLabel(QString(_("Fingerprint")) + ": " + + QString(signature->fpr))); } - case GPG_ERR_CERT_REVOKED: { - this->setTitle("An Error Signature"); - vbox->addWidget(new QLabel(tr("Status: Cert Revoked"))); - auto gird = createKeyInfoGrid(signature); - if (gird != nullptr) { - vbox->addLayout(gird); - } else { - vbox->addWidget(new QLabel(tr("Key Information is NOT Available"))); - if(signature->fpr != nullptr) { - vbox->addWidget(new QLabel(tr("Fingerprint: ") + QString(signature->fpr))); - } - } - break; + } + break; + } + case GPG_ERR_CERT_REVOKED: { + this->setTitle("An Error Signature"); + vbox->addWidget( + new QLabel(QString(_("Status")) + ":" + _("Cert Revoked"))); + auto gird = createKeyInfoGrid(signature); + if (gird != nullptr) { + vbox->addLayout(gird); + } else { + vbox->addWidget(new QLabel(_("Key Information is NOT Available"))); + if (signature->fpr != nullptr) { + vbox->addWidget(new QLabel(QString(_("Fingerprint")) + ": " + + QString(signature->fpr))); } - case GPG_ERR_SIG_EXPIRED: { - this->setTitle("An Error Signature"); - vbox->addWidget(new QLabel(tr("Status: Signature Expired"))); - auto gird = createKeyInfoGrid(signature); - if (gird != nullptr) { - vbox->addLayout(gird); - } else { - vbox->addWidget(new QLabel(tr("Key Information is NOT Available"))); - if(signature->fpr != nullptr) { - vbox->addWidget(new QLabel(tr("Fingerprint: ") + QString(signature->fpr))); - } - } - break; + } + break; + } + case GPG_ERR_SIG_EXPIRED: { + this->setTitle("An Error Signature"); + vbox->addWidget( + new QLabel(QString(_("Status")) + ":" + _("Signature Expired"))); + auto gird = createKeyInfoGrid(signature); + if (gird != nullptr) { + vbox->addLayout(gird); + } else { + vbox->addWidget(new QLabel(_("Key Information is NOT Available"))); + if (signature->fpr != nullptr) { + vbox->addWidget(new QLabel(QString(_("Fingerprint")) + ": " + + QString(signature->fpr))); } - case GPG_ERR_KEY_EXPIRED: { - this->setTitle("An Error Signature"); - vbox->addWidget(new QLabel(tr("Status: Signature Expired"))); - vbox->addWidget(new QLabel(tr("Status: Key Expired"))); - auto gird = createKeyInfoGrid(signature); - if (gird != nullptr) { - vbox->addLayout(gird); - } else { - vbox->addWidget(new QLabel(tr("Key Information is NOT Available"))); - if(signature->fpr != nullptr) { - vbox->addWidget(new QLabel(tr("Fingerprint: ") + QString(signature->fpr))); - } - } - break; + } + break; + } + case GPG_ERR_KEY_EXPIRED: { + this->setTitle("An Error Signature"); + vbox->addWidget( + new QLabel(QString(_("Status")) + ":" + _("Key Expired"))); + vbox->addWidget( + new QLabel(QString(_("Status")) + ":" + _("Key Expired"))); + auto gird = createKeyInfoGrid(signature); + if (gird != nullptr) { + vbox->addLayout(gird); + } else { + vbox->addWidget(new QLabel(_("Key Information is NOT Available"))); + if (signature->fpr != nullptr) { + vbox->addWidget(new QLabel(QString(_("Fingerprint")) + ": " + + QString(signature->fpr))); } - case GPG_ERR_GENERAL: { - this->setTitle("An Error Signature"); - vbox->addWidget(new QLabel(tr("Status: General Error"))); - auto gird = createKeyInfoGrid(signature); - if (gird != nullptr) { - vbox->addLayout(gird); - } else { - vbox->addWidget(new QLabel(tr("Key Information is NOT Available"))); - if(signature->fpr != nullptr) { - vbox->addWidget(new QLabel(tr("Fingerprint: ") + QString(signature->fpr))); - } - } - break; + } + break; + } + case GPG_ERR_GENERAL: { + this->setTitle("An Error Signature"); + vbox->addWidget( + new QLabel(QString(_("Status")) + ":" + _("General Error"))); + auto gird = createKeyInfoGrid(signature); + if (gird != nullptr) { + vbox->addLayout(gird); + } else { + vbox->addWidget(new QLabel(_("Key Information is NOT Available"))); + if (signature->fpr != nullptr) { + vbox->addWidget(new QLabel(QString(_("Fingerprint")) + ": " + + QString(signature->fpr))); } - default: { - this->setTitle("An Error Signature"); - this->setTitle(tr("Status: Unknown Error")); - auto gird = createKeyInfoGrid(signature); - if (gird != nullptr) { - vbox->addLayout(gird); - } else { - vbox->addWidget(new QLabel(tr("Key Information is NOT Available"))); - if(signature->fpr != nullptr) { - vbox->addWidget(new QLabel(tr("Fingerprint: ") + QString(signature->fpr))); - } - } - break; + } + break; + } + default: { + this->setTitle("An Error Signature"); + this->setTitle(QString(_("Status")) + ":" + _("Unknown Error ")); + auto gird = createKeyInfoGrid(signature); + if (gird != nullptr) { + vbox->addLayout(gird); + } else { + vbox->addWidget(new QLabel(_("Key Information is NOT Available"))); + if (signature->fpr != nullptr) { + vbox->addWidget(new QLabel(QString(_("Fingerprint")) + ": " + + QString(signature->fpr))); } + } + break; } - this->setLayout(vbox); + } + this->setLayout(vbox); } void VerifyKeyDetailBox::slotImportFormKeyserver() { - auto *importDialog = new KeyServerImportDialog(mCtx, mKeyList, false, this); - importDialog->slotImport(QStringList(fpr)); + auto* importDialog = new KeyServerImportDialog(false, this); + auto key_ids = std::make_unique<KeyIdArgsList>(); + key_ids->push_back(fpr.toStdString()); + importDialog->slotImport(key_ids); } QString VerifyKeyDetailBox::beautifyFingerprint(QString fingerprint) { - uint len = fingerprint.length(); - if ((len > 0) && (len % 4 == 0)) - for (uint n = 0; 4 * (n + 1) < len; ++n) - fingerprint.insert(static_cast<int>(5u * n + 4u), ' '); - return fingerprint; + uint len = fingerprint.length(); + if ((len > 0) && (len % 4 == 0)) + for (uint n = 0; 4 * (n + 1) < len; ++n) + fingerprint.insert(static_cast<int>(5u * n + 4u), ' '); + return fingerprint; } -QGridLayout *VerifyKeyDetailBox::createKeyInfoGrid(gpgme_signature_t &signature) { - - auto grid = new QGridLayout(); - GpgKey key = mCtx->getKeyByFpr(signature->fpr); - - if(!key.good) return nullptr; - grid->addWidget(new QLabel(tr("Signer Name:")), 0, 0); - grid->addWidget(new QLabel(tr("Signer Email:")), 1, 0); - grid->addWidget(new QLabel(tr("Key's Fingerprint:")), 2, 0); - grid->addWidget(new QLabel(tr("Valid:")), 3, 0); - grid->addWidget(new QLabel(tr("Flags:")), 4, 0); - - grid->addWidget(new QLabel(key.name), 0, 1); - grid->addWidget(new QLabel(key.email), 1, 1); - grid->addWidget(new QLabel(beautifyFingerprint(signature->fpr)), 2, 1); - - - if(signature->summary & GPGME_SIGSUM_VALID) { - grid->addWidget(new QLabel(tr("Fully Valid")), 3, 1); - } else { - grid->addWidget(new QLabel(tr("NOT Fully Valid")), 3, 1); - } - - QString flags; - QTextStream textStream(&flags); - - if(signature->summary & GPGME_SIGSUM_GREEN) { - textStream << tr("Good "); - } - if(signature->summary & GPGME_SIGSUM_RED) { - textStream << tr("Bad "); - } - if(signature->summary & GPGME_SIGSUM_SIG_EXPIRED) { - textStream << tr("Expired "); - } - if(signature->summary & GPGME_SIGSUM_KEY_MISSING) { - textStream << tr("Missing Key "); - } - if(signature->summary & GPGME_SIGSUM_KEY_REVOKED) { - textStream << tr("Revoked Key "); - } - if(signature->summary & GPGME_SIGSUM_KEY_EXPIRED) { - textStream << tr("Expired Key "); - } - if(signature->summary & GPGME_SIGSUM_CRL_MISSING) { - textStream << tr("Missing CRL "); - } - - grid->addWidget(new QLabel(tr(flags.toUtf8().constData())), 4, 1); - return grid; +QGridLayout* VerifyKeyDetailBox::createKeyInfoGrid( + gpgme_signature_t& signature) { + auto grid = new QGridLayout(); + GpgKey key = GpgKeyGetter::GetInstance().GetKey(signature->fpr); + + if (!key.good()) return nullptr; + grid->addWidget(new QLabel(QString(_("Signer Name")) + ":"), 0, 0); + grid->addWidget(new QLabel(QString(_("Signer Email")) + ":"), 1, 0); + grid->addWidget(new QLabel(QString(_("Key's Fingerprint")) + ":"), 2, 0); + grid->addWidget(new QLabel(QString(_("Valid")) + ":"), 3, 0); + grid->addWidget(new QLabel(QString(_("Flags")) + ":"), 4, 0); + + grid->addWidget(new QLabel(QString::fromStdString(key.name())), 0, 1); + grid->addWidget(new QLabel(QString::fromStdString(key.email())), 1, 1); + grid->addWidget(new QLabel(beautifyFingerprint(signature->fpr)), 2, 1); + + if (signature->summary & GPGME_SIGSUM_VALID) { + grid->addWidget(new QLabel(_("Fully Valid")), 3, 1); + } else { + grid->addWidget(new QLabel(_("NOT Fully Valid")), 3, 1); + } + + QString flags; + QTextStream textStream(&flags); + + if (signature->summary & GPGME_SIGSUM_GREEN) { + textStream << _("Good") << " "; + } + if (signature->summary & GPGME_SIGSUM_RED) { + textStream << _("Bad") << " "; + } + if (signature->summary & GPGME_SIGSUM_SIG_EXPIRED) { + textStream << _("Expired") << " "; + } + if (signature->summary & GPGME_SIGSUM_KEY_MISSING) { + textStream << _("Missing Key") << " "; + } + if (signature->summary & GPGME_SIGSUM_KEY_REVOKED) { + textStream << _("Revoked Key") << " "; + } + if (signature->summary & GPGME_SIGSUM_KEY_EXPIRED) { + textStream << _("Expired Key") << " "; + } + if (signature->summary & GPGME_SIGSUM_CRL_MISSING) { + textStream << _("Missing CRL") << " "; + } + + grid->addWidget(new QLabel(_(flags.toUtf8().constData())), 4, 1); + return grid; } + +} // namespace GpgFrontend::UI
\ No newline at end of file diff --git a/src/ui/widgets/VerifyKeyDetailBox.h b/src/ui/widgets/VerifyKeyDetailBox.h new file mode 100644 index 00000000..c1b26bb2 --- /dev/null +++ b/src/ui/widgets/VerifyKeyDetailBox.h @@ -0,0 +1,55 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef __VERIFYKEYDETAILBOX_H__ +#define __VERIFYKEYDETAILBOX_H__ + +#include "ui/KeyServerImportDialog.h" +#include "ui/widgets/KeyList.h" + +namespace GpgFrontend::UI { + +class VerifyKeyDetailBox : public QGroupBox { + Q_OBJECT + public: + explicit VerifyKeyDetailBox(QWidget* parent, KeyList* mKeyList, + gpgme_signature_t signature); + + private slots: + + void slotImportFormKeyserver(); + + private: + KeyList* mKeyList; + + static QString beautifyFingerprint(QString fingerprint); + + static QGridLayout* createKeyInfoGrid(gpgme_signature_t& signature); + + QString fpr; +}; + +} // namespace GpgFrontend::UI + +#endif // __VERIFYKEYDETAILBOX_H__ |