diff options
author | saturneric <[email protected]> | 2024-11-27 20:22:45 +0000 |
---|---|---|
committer | saturneric <[email protected]> | 2024-11-27 20:22:55 +0000 |
commit | 4b846455b7c232b7db63f95c6a1943ccbc7ce15b (patch) | |
tree | f9609ef2a7fb5d6221baa11ff1ed154f32befe80 | |
parent | fix: target_link_libraries with a target (diff) | |
download | Modules-4b846455b7c232b7db63f95c6a1943ccbc7ce15b.tar.gz Modules-4b846455b7c232b7db63f95c6a1943ccbc7ce15b.zip |
feat: support signing email
-rw-r--r-- | include/GFModuleCommonUtils.hpp | 49 | ||||
-rw-r--r-- | src/m_email/AddressListEditorDialog.ui | 70 | ||||
-rw-r--r-- | src/m_email/EMailHelper.h | 3 | ||||
-rw-r--r-- | src/m_email/EMailMetaDataDialog.cpp | 376 | ||||
-rw-r--r-- | src/m_email/EMailMetaDataDialog.h | 79 | ||||
-rw-r--r-- | src/m_email/EMailMetaDataDialog.ui | 373 | ||||
-rw-r--r-- | src/m_email/EMailModule.cpp | 48 | ||||
-rw-r--r-- | src/m_gpg_info/GnuPGInfoGatheringModule.cpp | 2 | ||||
-rw-r--r-- | src/m_gpg_info/GnupgTab.cpp | 2 | ||||
-rw-r--r-- | src/m_ver_check/UpdateTab.cpp | 2 | ||||
-rw-r--r-- | src/m_ver_check/UpdateTab.h | 2 |
11 files changed, 998 insertions, 8 deletions
diff --git a/include/GFModuleCommonUtils.hpp b/include/GFModuleCommonUtils.hpp index 1811ffc..73de58a 100644 --- a/include/GFModuleCommonUtils.hpp +++ b/include/GFModuleCommonUtils.hpp @@ -32,10 +32,11 @@ #include <GFSDKLog.h> #include <GFSDKModule.h> #include <GFSDKUI.h> -#include <qsharedpointer.h> #include <QMap> +#include <QSharedPointer> #include <QString> +#include <QVariant> #include <cstring> #define DUP(v) GFModuleStrDup(v) @@ -394,9 +395,51 @@ inline auto CharArrayToQStringList(char** pl_components, int size) -> QStringList { QStringList list; for (int i = 0; i < size; ++i) { - list.append(QString::fromUtf8(pl_components[i])); - GFFreeMemory(pl_components[i]); + list.append(UDUP(pl_components[i])); } GFFreeMemory(pl_components); return list; } + +inline auto QListToCharArray(const QStringList& list) -> char** { + char** char_array = + static_cast<char**>(GFAllocateMemory(list.size() * sizeof(char*))); + + int index = 0; + for (const QString& item : list) { + QByteArray value = item.toUtf8(); + char_array[index] = static_cast<char*>(GFAllocateMemory(value.size() + 1)); + std::strcpy(char_array[index], value.constData()); + index++; + } + + return char_array; +} + +inline auto ConvertQVariantToVoidPtr(const QVariant& variant) -> void* { + void* mem = GFAllocateMemory(sizeof(QVariant)); + auto* variant_ptr = new (mem) QVariant(variant); + return static_cast<void*>(variant_ptr); +} + +inline auto ConvertVoidPtrToQVariant(void* ptr) -> QVariant { + if (ptr == nullptr) return {}; + + auto* variant_ptr = static_cast<QVariant*>(ptr); + QVariant variant = *variant_ptr; + + GFFreeMemory(variant_ptr); + return variant; +} + +#define Q_VARIANT_Q_OBJECT_FACTORY_DECLARE(name) \ + auto name(void* data_raw_ptr) -> void*; + +#define Q_VARIANT_Q_OBJECT_FACTORY_DEFINE(name, func) \ + auto name(void* data_raw_ptr) -> void* { \ + auto data = ConvertVoidPtrToQVariant(data_raw_ptr); \ + return func(data); \ + } + +#define GUI_OBJECT(factory, data) \ + GFUICreateGUIObject(factory, ConvertQVariantToVoidPtr(data)) diff --git a/src/m_email/AddressListEditorDialog.ui b/src/m_email/AddressListEditorDialog.ui new file mode 100644 index 0000000..c3d074f --- /dev/null +++ b/src/m_email/AddressListEditorDialog.ui @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>AddressListEditorDialog</class> + <widget class="QDialog" name="AddressListEditorDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>606</width> + <height>368</height> + </rect> + </property> + <property name="windowTitle"> + <string>Address List Editor</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QLabel" name="titleLabel"> + <property name="text"> + <string>Address List</string> + </property> + </widget> + </item> + <item> + <widget class="QListWidget" name="addressListWidget"> + <property name="editTriggers"> + <set>QAbstractItemView::EditTrigger::DoubleClicked|QAbstractItemView::EditTrigger::EditKeyPressed</set> + </property> + <property name="dragEnabled"> + <bool>true</bool> + </property> + <property name="isWrapping" stdset="0"> + <bool>false</bool> + </property> + <property name="spacing"> + <number>6</number> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="addAddressButton"> + <property name="text"> + <string>Add Address</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="tipsLabel"> + <property name="text"> + <string>Tips: You can double-click the email address in the edit list, or click the email to pop up the option menu.</string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </item> + </layout> + <action name="actionDelete_Selected_Email_Address"> + <property name="text"> + <string>Delete Selected Email Address</string> + </property> + </action> + </widget> + <resources/> + <connections/> +</ui> diff --git a/src/m_email/EMailHelper.h b/src/m_email/EMailHelper.h index 3a70d0b..75cffe2 100644 --- a/src/m_email/EMailHelper.h +++ b/src/m_email/EMailHelper.h @@ -34,6 +34,9 @@ // vmime #define VMIME_STATIC #include <vmime/vmime.hpp> +// vmime extra +#include <vmime/contentDispositionField.hpp> +#include <vmime/contentTypeField.hpp> auto inline Q_SC(const std::string& s) -> QString { return QString::fromStdString(s); diff --git a/src/m_email/EMailMetaDataDialog.cpp b/src/m_email/EMailMetaDataDialog.cpp new file mode 100644 index 0000000..11583b9 --- /dev/null +++ b/src/m_email/EMailMetaDataDialog.cpp @@ -0,0 +1,376 @@ +/** + * Copyright (C) 2021-2024 Saturneric <[email protected]> + * + * 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. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "EMailMetaDataDialog.h" + +#include <GFSDKGpg.h> + +#include <QCryptographicHash> +#include <QDialog> +#include <QMessageBox> +#include <QRegularExpression> + +#include "EMailHelper.h" +#include "ui_EMailMetaDataDialog.h" + +static const QRegularExpression kNameEmailStringRegex{ + R"(^\s*(.*)\s*<\s*([^<>@\s]+@[^<>@\s]+)\s*>\s*$)"}; + +auto ParseEmailString(const QString& input, QString& name, + QString& email) -> bool { + QRegularExpressionMatch match = kNameEmailStringRegex.match(input); + + if (match.hasMatch()) { + name = match.captured(1).trimmed(); + email = match.captured(2).trimmed(); + return true; + } + + return false; +} + +class ParameterizedHeaderField : public vmime::parameterizedHeaderField { + public: + ParameterizedHeaderField() = default; +}; + +class HeaderField : public vmime::headerField { + public: + HeaderField() = default; +}; + +class ContentTypeField : public vmime::contentTypeField { + public: + ContentTypeField() = default; +}; + +EMailMetaDataDialog::EMailMetaDataDialog(QByteArray body_data, QWidget* parent) + : QDialog(parent), + ui_(QSharedPointer<Ui_EMailMetaDataDialog>::create()), + body_data_(std::move(body_data)) { + ui_->setupUi(this); + + connect(ui_->exportMailButton, &QPushButton::clicked, this, + &EMailMetaDataDialog::slot_export_eml_data); + + setModal(true); + setAttribute(Qt::WA_DeleteOnClose); + setWindowFlags(Qt::Dialog | Qt::Window); +} + +Q_VARIANT_Q_OBJECT_FACTORY_DEFINE(CreateEMailMetaDataDialog, + [](QVariant data) -> void* { + return new EMailMetaDataDialog( + data.toByteArray(), nullptr); + }); + +void EMailMetaDataDialog::slot_export_eml_data() { + // sign key is a must + if (sign_key_.isEmpty()) emit SignalEMLDataGenerateFailed("No Sign Key"); + + auto from = ui_->fromEdit->text(); + auto to = ui_->toEdit->text(); + auto cc = ui_->ccEdit->text(); + auto bcc = ui_->bccEdit->text(); + auto subject = ui_->subjectEdit->text(); + + auto recipient_list = to.split(';', Qt::SkipEmptyParts); + auto cc_list = cc.split(';', Qt::SkipEmptyParts); + auto bcc_list = bcc.split(';', Qt::SkipEmptyParts); + + QString name; + QString email; + + try { + vmime::messageBuilder msg_builder; + + if (ParseEmailString(from, name, email)) { + msg_builder.setExpeditor( + vmime::mailbox(vmime::text(name.toStdString()), email.toStdString())); + } else { + msg_builder.setExpeditor(vmime::mailbox(email.toStdString())); + } + + for (const QString& recipient : recipient_list) { + auto trimmed_recipient = recipient.trimmed(); + + if (ParseEmailString(trimmed_recipient, name, email)) { + msg_builder.getRecipients().appendAddress( + vmime::make_shared<vmime::mailbox>(vmime::text(name.toStdString()), + email.toStdString())); + } else { + msg_builder.getRecipients().appendAddress( + vmime::make_shared<vmime::mailbox>( + trimmed_recipient.toStdString())); + } + } + + for (const QString& recipient : cc_list) { + auto trimmed_recipient = recipient.trimmed(); + if (ParseEmailString(trimmed_recipient, name, email)) { + msg_builder.getCopyRecipients().appendAddress( + vmime::make_shared<vmime::mailbox>(vmime::text(name.toStdString()), + email.toStdString())); + } else { + msg_builder.getCopyRecipients().appendAddress( + vmime::make_shared<vmime::mailbox>( + trimmed_recipient.toStdString())); + } + } + + for (const QString& recipient : bcc_list) { + auto trimmed_recipient = recipient.trimmed(); + if (ParseEmailString(trimmed_recipient, name, email)) { + msg_builder.getBlindCopyRecipients().appendAddress( + vmime::make_shared<vmime::mailbox>(vmime::text(name.toStdString()), + email.toStdString())); + } else { + msg_builder.getBlindCopyRecipients().appendAddress( + vmime::make_shared<vmime::mailbox>( + trimmed_recipient.toStdString())); + } + } + + msg_builder.setSubject(vmime::text(subject.toStdString())); + + vmime::shared_ptr<vmime::message> msg = msg_builder.construct(); + + auto header = msg->getHeader(); + + // no Content-Transfer-Encoding + header->removeField( + header->getField(vmime::fields::CONTENT_TRANSFER_ENCODING)); + + auto content_type_header_field = + header->getField<vmime::contentTypeField>(vmime::fields::CONTENT_TYPE); + content_type_header_field->setValue("multipart/signed"); + auto body_boundary = vmime::body::generateRandomBoundaryString(); + content_type_header_field->appendParameter( + vmime::make_shared<vmime::parameter>("protocol", + "application/pgp-signature")); + content_type_header_field->setBoundary(body_boundary); + + auto root_body_part = vmime::make_shared<vmime::body>(); + auto container_part = vmime::make_shared<vmime::bodyPart>(); + auto mime_part = vmime::make_shared<vmime::bodyPart>(); + auto public_key_part = vmime::make_shared<vmime::bodyPart>(); + auto signature_part = vmime::make_shared<vmime::bodyPart>(); + + root_body_part->appendPart(container_part); + root_body_part->appendPart(signature_part); + msg->setBody(root_body_part); + + root_body_part->setPrologText( + "This is an OpenPGP/MIME signed message (RFC 4880 and 3156)"); + + auto container_boundary = vmime::body::generateRandomBoundaryString(); + auto container_part_header = container_part->getHeader(); + auto container_part_content_ttype_header_field = + container_part_header->getField<vmime::contentTypeField>( + vmime::fields::CONTENT_TYPE); + container_part_content_ttype_header_field->setValue("multipart/mixed"); + container_part_content_ttype_header_field->setBoundary(container_boundary); + + auto container_part_body = container_part->getBody(); + + container_part_body->appendPart(mime_part); + container_part_body->appendPart(public_key_part); + + auto public_key_part_header = public_key_part->getHeader(); + + auto public_key_name = QString("OpenPGP_0x%1.asc").arg(sign_key_.toUpper()); + auto public_key_part_content_type_header_field = + public_key_part_header->getField<vmime::contentTypeField>( + vmime::fields::CONTENT_TYPE); + public_key_part_content_type_header_field->setValue("application/pgp-keys"); + public_key_part_content_type_header_field->appendParameter( + vmime::make_shared<vmime::parameter>("name", + public_key_name.toStdString())); + + auto public_key_part_content_desc_header_field = + public_key_part_header->getField(vmime::fields::CONTENT_DESCRIPTION); + public_key_part_content_desc_header_field->setValue("OpenPGP public key"); + + auto public_key_part_content_trans_encode_field = + public_key_part_header->getField( + vmime::fields::CONTENT_TRANSFER_ENCODING); + public_key_part_content_trans_encode_field->setValue("quoted-printable"); + + auto public_key_part_content_disp_header_field = + public_key_part_header->getField<vmime::contentDispositionField>( + vmime::fields::CONTENT_DISPOSITION); + public_key_part_content_disp_header_field->setValue("attachment"); + public_key_part_content_disp_header_field->setFilename( + vmime::word(public_key_name.toStdString())); + + auto signature_part_header = signature_part->getHeader(); + + auto signature_part_content_type_header_field = + signature_part_header->getField<vmime::contentTypeField>( + vmime::fields::CONTENT_TYPE); + signature_part_content_type_header_field->setValue( + "application/pgp-signature"); + signature_part_content_type_header_field->appendParameter( + vmime::make_shared<vmime::parameter>("name", "OpenPGP_signature.asc")); + + auto signature_part_content_desc_header_field = + signature_part_header->getField(vmime::fields::CONTENT_DESCRIPTION); + signature_part_content_desc_header_field->setValue( + "OpenPGP digital signature"); + + auto signature_part_content_disp_header_field = + signature_part_header->getField<vmime::contentDispositionField>( + vmime::fields::CONTENT_DISPOSITION); + signature_part_content_disp_header_field->setValue("attachment"); + signature_part_content_disp_header_field->setFilename( + vmime::word({"OpenPGP_signature.asc"})); + + auto public_key = UDUP(GFGpgPublicKey(channel_, QDUP(sign_key_), 1)); + if (public_key.isEmpty()) { + emit SignalEMLDataGenerateFailed("Get Public Key of Sign Key Failed"); + return; + } + + auto public_key_part_part_body = public_key_part->getBody(); + auto public_key_part_body_content = + vmime::make_shared<vmime::stringContentHandler>(); + public_key_part_body_content->setData( + public_key.toLatin1().replace('\n', "\r\n").toStdString(), + vmime::encoding(vmime::encodingTypes::QUOTED_PRINTABLE)); + public_key_part_part_body->setContents(public_key_part_body_content); + + auto mime_part_header = mime_part->getHeader(); + + auto mime_part_content_type_header_field = + mime_part_header->getField<vmime::contentTypeField>( + vmime::fields::CONTENT_TYPE); + mime_part_content_type_header_field->setValue("text/plain"); + mime_part_content_type_header_field->appendParameter( + vmime::make_shared<vmime::parameter>("charset", "UTF-8")); + mime_part_content_type_header_field->appendParameter( + vmime::make_shared<vmime::parameter>("format", "flowed")); + auto mime_part_content_trans_encode_field = + mime_part_header->getField(vmime::fields::CONTENT_TRANSFER_ENCODING); + mime_part_content_trans_encode_field->setValue("base64"); + + auto mime_part_part_body = mime_part->getBody(); + auto mime_part_body_content = + vmime::make_shared<vmime::stringContentHandler>(); + mime_part_body_content->setData( + body_data_.toBase64().toStdString(), + vmime::encoding(vmime::encodingTypes::BASE64)); + mime_part_part_body->setContents(mime_part_body_content); + + auto container_raw_data = + container_part->generate(vmime::lineLengthLimits::infinite); + qDebug().noquote() << "\n" << container_raw_data; + + container_raw_data = + container_part->generate(vmime::lineLengthLimits::infinite); + qDebug().noquote() << "\n" << container_raw_data; + + auto container_raw_data_hash = + QCryptographicHash::hash(container_raw_data, QCryptographicHash::Sha1); + FLOG_DEBUG("raw content of signature hash: %1", + container_raw_data_hash.toHex()); + + FLOG_DEBUG("MIME Raw Data For Signature: %1", container_raw_data); + FLOG_DEBUG("Signature Channel: %1, Sign Key: %2", channel_, sign_key_); + + GFGpgSignResult* s; + auto ret = GFGpgSignData(channel_, QListToCharArray({sign_key_}), 1, + QDUP(Q_SC(container_raw_data)), 1, 1, &s); + + if (ret != 0) { + emit SignalEMLDataGenerateFailed("Sign Failed"); + return; + } + + auto signature = UDUP(s->signature); + auto hash_algo = UDUP(s->hash_algo); + + GFFreeMemory(s); + + FLOG_DEBUG("Hash Algo: %1 Signature Data: %2", hash_algo, signature); + content_type_header_field->appendParameter( + vmime::make_shared<vmime::parameter>( + "micalg", + QString("pgp-%1").arg(hash_algo.toLower()).toStdString())); + + auto signature_part_body = signature_part->getBody(); + auto signature_part_body_content = + vmime::make_shared<vmime::stringContentHandler>( + signature.toStdString()); + signature_part_body->setContents(signature_part_body_content); + + auto eml_data = Q_SC(msg->generate(vmime::lineLengthLimits::infinite)); + + FLOG_DEBUG("EML Data: %1", eml_data); + + emit SignalEMLDataGenerateSuccess(eml_data); + this->close(); + return; + + } catch (const vmime::exception& e) { + QMessageBox::critical(this, tr("Error"), + tr("Failed to export EML Data: %1").arg(e.what())); + emit SignalEMLDataGenerateFailed(e.what()); + this->close(); + return; + } + + emit SignalEMLDataGenerateFailed("Unknown Error"); + this->close(); +} + +void EMailMetaDataDialog::slot_export_encrypted_data() {} + +void EMailMetaDataDialog::SetSignKey(QString k) { + sign_key_ = std::move(k); + slot_set_from_field_by_sign_key(); +} + +void EMailMetaDataDialog::SetChannel(int c) { channel_ = c; } + +void EMailMetaDataDialog::slot_set_from_field_by_sign_key() { + GFGpgKeyUID* s; + auto ret = GFGpgKeyPrimaryUID(channel_, QDUP(sign_key_), &s); + if (ret != 0) { + FLOG_WARN("cannot get primary uid from sign key %1, ret: %2", sign_key_, + ret); + return; + } + + from_name_ = UDUP(s->name); + from_email_ = UDUP(s->email); + auto comment = UDUP(s->comment); + + GFFreeMemory(s); + + ui_->fromEdit->setText(QString("%1 <%2>").arg(from_name_).arg(from_email_)); +} diff --git a/src/m_email/EMailMetaDataDialog.h b/src/m_email/EMailMetaDataDialog.h new file mode 100644 index 0000000..983dc0a --- /dev/null +++ b/src/m_email/EMailMetaDataDialog.h @@ -0,0 +1,79 @@ +/** + * Copyright (C) 2021-2024 Saturneric <[email protected]> + * + * 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. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include <QDialog> +#include <QSharedPointer> + +#include "GFModuleCommonUtils.hpp" + +class QWidget; +class Ui_EMailMetaDataDialog; + +class EMailMetaDataDialog : public QDialog { + Q_OBJECT + public: + explicit EMailMetaDataDialog(QByteArray body_data, QWidget *parent); + + /** + * @brief Set the Channel object + * + */ + void SetChannel(int c); + + /** + * @brief Set the Sign Keys object + * + */ + void SetSignKey(QString k); + + signals: + + void SignalEMLDataGenerateSuccess(QString); + + void SignalEMLDataGenerateFailed(QString); + + private slots: + + void slot_export_eml_data(); + + void slot_export_encrypted_data(); + + void slot_set_from_field_by_sign_key(); + + private: + QSharedPointer<Ui_EMailMetaDataDialog> ui_; + QByteArray body_data_; + int channel_; + QString sign_key_; + QString from_name_; + QString from_email_; +}; + +Q_VARIANT_Q_OBJECT_FACTORY_DECLARE(CreateEMailMetaDataDialog);
\ No newline at end of file diff --git a/src/m_email/EMailMetaDataDialog.ui b/src/m_email/EMailMetaDataDialog.ui new file mode 100644 index 0000000..977a535 --- /dev/null +++ b/src/m_email/EMailMetaDataDialog.ui @@ -0,0 +1,373 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>EMailMetaDataDialog</class> + <widget class="QDialog" name="EMailMetaDataDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>599</width> + <height>522</height> + </rect> + </property> + <property name="cursor"> + <cursorShape>ArrowCursor</cursorShape> + </property> + <property name="contextMenuPolicy"> + <enum>Qt::ContextMenuPolicy::NoContextMenu</enum> + </property> + <property name="windowTitle"> + <string>Message</string> + </property> + <property name="sizeGripEnabled"> + <bool>false</bool> + </property> + <property name="modal"> + <bool>false</bool> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QWidget" name="horizontalWidget" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <property name="spacing"> + <number>6</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QLabel" name="senderLabel"> + <property name="text"> + <string>From</string> + </property> + <property name="margin"> + <number>5</number> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="fromEdit"/> + </item> + <item> + <widget class="Line" name="line"> + <property name="toolTipDuration"> + <number>0</number> + </property> + <property name="autoFillBackground"> + <bool>false</bool> + </property> + <property name="lineWidth"> + <number>2</number> + </property> + <property name="orientation"> + <enum>Qt::Orientation::Vertical</enum> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="ccButton"> + <property name="text"> + <string>CC</string> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="bccButton"> + <property name="text"> + <string>BCC</string> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QWidget" name="horizontalWidget_4" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout_4"> + <property name="spacing"> + <number>6</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QLabel" name="recipientLabel"> + <property name="text"> + <string>To</string> + </property> + <property name="margin"> + <number>5</number> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="toEdit"/> + </item> + <item> + <widget class="QPushButton" name="recipientsEditButton"> + <property name="text"> + <string>Edit Recipients(s)</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="Line" name="line_2"> + <property name="orientation"> + <enum>Qt::Orientation::Horizontal</enum> + </property> + </widget> + </item> + <item> + <widget class="QWidget" name="horizontalWidget_5" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout_6"> + <property name="spacing"> + <number>0</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QLabel" name="subjectLabel"> + <property name="text"> + <string>Subject</string> + </property> + <property name="margin"> + <number>5</number> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="subjectEdit"/> + </item> + </layout> + </widget> + </item> + <item> + <widget class="Line" name="line_4"> + <property name="orientation"> + <enum>Qt::Orientation::Horizontal</enum> + </property> + </widget> + </item> + <item> + <widget class="QWidget" name="ccInputWidget" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <property name="spacing"> + <number>6</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QLabel" name="ccLabel"> + <property name="text"> + <string>CC</string> + </property> + <property name="margin"> + <number>5</number> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="ccEdit"/> + </item> + <item> + <widget class="QPushButton" name="ccEditButton"> + <property name="text"> + <string>Edit CC(s)</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QWidget" name="bccInputWidget" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <property name="spacing"> + <number>6</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QLabel" name="bccLabel"> + <property name="text"> + <string>BCC</string> + </property> + <property name="margin"> + <number>5</number> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="bccEdit"/> + </item> + <item> + <widget class="QPushButton" name="bccEditButton"> + <property name="text"> + <string>Edit BCC(s)</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QLabel" name="tipsLabel"> + <property name="text"> + <string>Tips: You can fill in multiple email addresses, please separate them with ";".</string> + </property> + </widget> + </item> + <item> + <widget class="Line" name="line_3"> + <property name="orientation"> + <enum>Qt::Orientation::Horizontal</enum> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_5"/> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_10"> + <item alignment="Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter"> + <widget class="QLabel" name="keysLabel"> + <property name="text"> + <string>GPG Keys:</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="recipientsKeyValueLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string/> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QListWidget" name="keyListWidget"/> + </item> + <item> + <widget class="QLabel" name="errorLabel"> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item> + <widget class="Line" name="line_5"> + <property name="orientation"> + <enum>Qt::Orientation::Horizontal</enum> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_7"> + <item> + <widget class="QCheckBox" name="encryptCheckBox"> + <property name="text"> + <string>Encrypt</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Orientation::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item alignment="Qt::AlignmentFlag::AlignRight"> + <widget class="QPushButton" name="exportMailButton"> + <property name="text"> + <string>Export</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/src/m_email/EMailModule.cpp b/src/m_email/EMailModule.cpp index 582542a..1262c75 100644 --- a/src/m_email/EMailModule.cpp +++ b/src/m_email/EMailModule.cpp @@ -39,6 +39,8 @@ #include <QJsonDocument> #include <QString> +#include "EMailMetaDataDialog.h" + // vmime #define VMIME_STATIC #include <vmime/vmime.hpp> @@ -51,6 +53,7 @@ // #include "EMailHelper.h" +#include "EMailMetaDataDialog.h" GF_MODULE_API_DEFINE_V2("com.bktus.gpgfrontend.module.email", "Email", "1.0.0", "Everything related to E-Mails.", "Saturneric") @@ -62,7 +65,7 @@ auto GFRegisterModule() -> int { LISTEN("EMAIL_VERIFY_EML_DATA"); LISTEN("EMAIL_DECRYPT_EML_DATA"); - + LISTEN("EMAIL_EXPORT_EML_DATA"); return 0; } @@ -185,6 +188,9 @@ REGISTER_EVENT_HANDLER(EMAIL_VERIFY_EML_DATA, [](const MEvent& event) -> int { FLOG_DEBUG("mime part of raw content hash: %1", part_mime_content_hash.toHex()); + FLOG_DEBUG("mime part of raw content: %1", part_mime_content_text); + qDebug().noquote() << "\n" << part_mime_content_text; + if (part_mime_content_text.isEmpty()) CB_ERR(event, -2, "mime raw data part is empty"); @@ -399,6 +405,46 @@ REGISTER_EVENT_HANDLER(EMAIL_DECRYPT_EML_DATA, [](const MEvent& event) -> int { return 0; }); +REGISTER_EVENT_HANDLER(EMAIL_EXPORT_EML_DATA, [](const MEvent& event) -> int { + if (event["body_data"].isEmpty()) CB_ERR(event, -1, "body_data is empty"); + if (event["channel"].isEmpty()) CB_ERR(event, -1, "channel is empty"); + if (event["sign_key"].isEmpty()) CB_ERR(event, -1, "sign_key is empty"); + + auto channel = event.value("channel", "0").toInt(); + auto sign_key = event.value("sign_key", ""); + + FLOG_DEBUG("eml sign key: %1", sign_key); + + auto data = QByteArray::fromBase64(QString(event["body_data"]).toLatin1()); + + auto* dialog = GUI_OBJECT(CreateEMailMetaDataDialog, {data}); + auto* r_dialog = + qobject_cast<EMailMetaDataDialog*>(static_cast<QObject*>(dialog)); + if (r_dialog == nullptr) + CB_ERR(event, -1, "convert dialog to r_dialog failed"); + r_dialog->SetChannel(channel); + r_dialog->SetSignKey(sign_key); + + GFUIShowDialog(dialog, nullptr); + + QObject::connect(r_dialog, &EMailMetaDataDialog::SignalEMLDataGenerateSuccess, + r_dialog, [=](QString eml_data) { + // callback + CB(event, GFGetModuleID(), + { + {"ret", QString::number(0)}, + {"eml_data", eml_data}, + }); + }); + + QObject::connect(r_dialog, &EMailMetaDataDialog::SignalEMLDataGenerateFailed, + r_dialog, [=](QString error) { + // callback + CB_ERR(event, -1, "Generate EML Data Failed: " + error); + }); + + return 0; +}); auto GFDeactivateModule() -> int { return 0; } auto GFUnregisterModule() -> int { diff --git a/src/m_gpg_info/GnuPGInfoGatheringModule.cpp b/src/m_gpg_info/GnuPGInfoGatheringModule.cpp index e882d67..0d02df1 100644 --- a/src/m_gpg_info/GnuPGInfoGatheringModule.cpp +++ b/src/m_gpg_info/GnuPGInfoGatheringModule.cpp @@ -63,7 +63,7 @@ extern void GetGpgOptionInfos(void *, int, const char *, const char *); extern auto StartGatheringGnuPGInfo() -> int; -extern auto GnupgTabFactory(const char *id) -> void *; +extern auto GnupgTabFactory(void *id) -> void *; using Context = struct { QString gpgme_version; diff --git a/src/m_gpg_info/GnupgTab.cpp b/src/m_gpg_info/GnupgTab.cpp index 5123155..6548316 100644 --- a/src/m_gpg_info/GnupgTab.cpp +++ b/src/m_gpg_info/GnupgTab.cpp @@ -331,4 +331,4 @@ void GnupgTab::gather_gnupg_info() { } } -auto GnupgTabFactory(const char* id) -> void* { return new GnupgTab(); }
\ No newline at end of file +auto GnupgTabFactory(void*) -> void* { return new GnupgTab(); }
\ No newline at end of file diff --git a/src/m_ver_check/UpdateTab.cpp b/src/m_ver_check/UpdateTab.cpp index 9dd281e..9946f10 100644 --- a/src/m_ver_check/UpdateTab.cpp +++ b/src/m_ver_check/UpdateTab.cpp @@ -187,4 +187,4 @@ void UpdateTab::slot_show_version_status() { } } -auto UpdateTabFactory(const char* id) -> void* { return new UpdateTab(); }
\ No newline at end of file +auto UpdateTabFactory(void*) -> void* { return new UpdateTab(); }
\ No newline at end of file diff --git a/src/m_ver_check/UpdateTab.h b/src/m_ver_check/UpdateTab.h index 7616200..4003a23 100644 --- a/src/m_ver_check/UpdateTab.h +++ b/src/m_ver_check/UpdateTab.h @@ -72,4 +72,4 @@ class UpdateTab : public QWidget { void SignalReplyFromUpdateServer(QByteArray data); }; -auto UpdateTabFactory(const char* id) -> void*;
\ No newline at end of file +auto UpdateTabFactory(void* id) -> void*;
\ No newline at end of file |