diff options
| author | saturneric <[email protected]> | 2024-11-28 08:25:22 +0000 | 
|---|---|---|
| committer | saturneric <[email protected]> | 2024-11-28 08:25:22 +0000 | 
| commit | 22558e2948065c771023e90b4adf86b31a959e50 (patch) | |
| tree | 77678968f50756a2a2a6ae7d85621ffe1e868f49 /src/m_email | |
| parent | feat: support email encryption (diff) | |
| download | Modules-22558e2948065c771023e90b4adf86b31a959e50.tar.gz Modules-22558e2948065c771023e90b4adf86b31a959e50.zip  | |
refactor: improve code structure
Diffstat (limited to 'src/m_email')
| -rw-r--r-- | src/m_email/EMAilHelper.cpp | 16 | ||||
| -rw-r--r-- | src/m_email/EMailBasicGpgOpera.cpp | 519 | ||||
| -rw-r--r-- | src/m_email/EMailBasicGpgOpera.h | 59 | ||||
| -rw-r--r-- | src/m_email/EMailHelper.h | 12 | ||||
| -rw-r--r-- | src/m_email/EMailMetaDataDialog.cpp | 550 | ||||
| -rw-r--r-- | src/m_email/EMailMetaDataDialog.h | 9 | ||||
| -rw-r--r-- | src/m_email/EMailModel.h | 40 | ||||
| -rw-r--r-- | src/m_email/EMailModule.cpp | 52 | 
8 files changed, 706 insertions, 551 deletions
diff --git a/src/m_email/EMAilHelper.cpp b/src/m_email/EMAilHelper.cpp index ff544ab..7d19dad 100644 --- a/src/m_email/EMAilHelper.cpp +++ b/src/m_email/EMAilHelper.cpp @@ -32,6 +32,9 @@  #include "GFModuleCommonUtils.hpp" +static const QRegularExpression kNameEmailStringRegex{ +    R"(^\s*(.*)\s*<\s*([^<>@\s]+@[^<>@\s]+)\s*>\s*$)"}; +  auto IsValidMicalgFormat(const QString& prm_micalg_value) -> bool {    QRegularExpression regex("^pgp-(\\w+)$");    QRegularExpressionMatch match = regex.match(prm_micalg_value); @@ -152,3 +155,16 @@ auto ExtractFieldValueDateTime(const vmime::shared_ptr<vmime::header>& header,    return datetime;  } + +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; +}
\ No newline at end of file diff --git a/src/m_email/EMailBasicGpgOpera.cpp b/src/m_email/EMailBasicGpgOpera.cpp new file mode 100644 index 0000000..bf60d1c --- /dev/null +++ b/src/m_email/EMailBasicGpgOpera.cpp @@ -0,0 +1,519 @@ +/** + * 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 "EMailBasicGpgOpera.h" + +#include <GFSDKGpg.h> + +// +#include <QCryptographicHash> + +#include "EMailHelper.h" +#include "GFModuleCommonUtils.hpp" + +auto EncryptEMLData(int channel, const QStringList& keys, +                    const EMailMetaData& meta_data, const QByteArray& body_data, +                    QString& eml_data) -> int { +  auto from = meta_data.from; +  auto recipient_list = meta_data.to; +  auto cc_list = meta_data.cc; +  auto bcc_list = meta_data.bcc; +  auto subject = meta_data.subject; + +  QString name; +  QString email; + +  try { +    vmime::messageBuilder plaintext_msg_builder; + +    if (ParseEmailString(from, name, email)) { +      plaintext_msg_builder.setExpeditor( +          vmime::mailbox(vmime::text(name.toStdString()), email.toStdString())); +    } else { +      plaintext_msg_builder.setExpeditor(vmime::mailbox(from.toStdString())); +    } + +    for (const QString& recipient : recipient_list) { +      auto trimmed_recipient = recipient.trimmed(); +      if (ParseEmailString(trimmed_recipient, name, email)) { +        plaintext_msg_builder.getRecipients().appendAddress( +            vmime::make_shared<vmime::mailbox>(vmime::text(name.toStdString()), +                                               email.toStdString())); +      } else { +        plaintext_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)) { +        plaintext_msg_builder.getCopyRecipients().appendAddress( +            vmime::make_shared<vmime::mailbox>(vmime::text(name.toStdString()), +                                               email.toStdString())); +      } else { +        plaintext_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)) { +        plaintext_msg_builder.getBlindCopyRecipients().appendAddress( +            vmime::make_shared<vmime::mailbox>(vmime::text(name.toStdString()), +                                               email.toStdString())); +      } else { +        plaintext_msg_builder.getBlindCopyRecipients().appendAddress( +            vmime::make_shared<vmime::mailbox>( +                trimmed_recipient.toStdString())); +      } +    } + +    plaintext_msg_builder.setSubject(vmime::text(subject.toStdString())); + +    vmime::shared_ptr<vmime::message> plaintext_msg = +        plaintext_msg_builder.construct(); + +    auto plaintext_msg_header = plaintext_msg->getHeader(); + +    auto plaintext_msg_content_type_header_field = +        plaintext_msg_header->getField<vmime::contentTypeField>( +            vmime::fields::CONTENT_TYPE); +    plaintext_msg_content_type_header_field->setValue("text/plain"); +    plaintext_msg_content_type_header_field->appendParameter( +        vmime::make_shared<vmime::parameter>("charset", "UTF-8")); +    plaintext_msg_content_type_header_field->appendParameter( +        vmime::make_shared<vmime::parameter>("format", "flowed")); + +    auto plaintext_msg_content_trans_encode_field = +        plaintext_msg_header->getField( +            vmime::fields::CONTENT_TRANSFER_ENCODING); +    plaintext_msg_content_trans_encode_field->setValue("base64"); + +    auto plaintext_msg_body = plaintext_msg->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)); +    plaintext_msg_body->setContents(mime_part_body_content); + +    auto plaintext_eml_data = +        Q_SC(plaintext_msg->generate(vmime::lineLengthLimits::infinite)); + +    GFGpgEncryptionResult* enc_result = nullptr; +    auto ret = GFGpgEncryptData(channel, QListToCharArray(keys), keys.size(), +                                QDUP(plaintext_eml_data), 1, &enc_result); + +    if (ret != 0) { +      eml_data = "Encryption Failed"; +      return -1; +    } + +    auto encrypted_data = UDUP(enc_result->encrypted_data); +    GFFreeMemory(enc_result); + +    vmime::messageBuilder msg_builder; + +    if (ParseEmailString(from, name, email)) { +      msg_builder.setExpeditor(vmime::mailbox(email.toStdString())); +    } else { +      msg_builder.setExpeditor(vmime::mailbox(from.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>(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>(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>(email.toStdString())); +      } else { +        msg_builder.getBlindCopyRecipients().appendAddress( +            vmime::make_shared<vmime::mailbox>( +                trimmed_recipient.toStdString())); +      } +    } + +    msg_builder.setSubject(vmime::text("...")); + +    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/encrypted"); +    content_type_header_field->appendParameter( +        vmime::make_shared<vmime::parameter>("protocol", +                                             "application/pgp-encrypted")); + +    auto root_part_boundary = vmime::body::generateRandomBoundaryString(); +    content_type_header_field->setBoundary(root_part_boundary); + +    auto root_body_part = vmime::make_shared<vmime::body>(); +    auto control_info_part = vmime::make_shared<vmime::bodyPart>(); +    auto encrypted_data_part = vmime::make_shared<vmime::bodyPart>(); + +    root_body_part->appendPart(control_info_part); +    root_body_part->appendPart(encrypted_data_part); +    msg->setBody(root_body_part); + +    root_body_part->setPrologText( +        "This is an OpenPGP/MIME encrypted message (RFC 4880 and 3156)"); + +    auto control_info_part_header = control_info_part->getHeader(); +    auto control_info_content_type_field = +        control_info_part_header->getField<vmime::contentTypeField>( +            vmime::fields::CONTENT_TYPE); +    control_info_content_type_field->setValue("application/pgp-encrypted"); + +    auto control_info_part_content_desc_header_field = +        control_info_part_header->getField(vmime::fields::CONTENT_DESCRIPTION); +    control_info_part_content_desc_header_field->setValue( +        "PGP/MIME version identification"); + +    auto control_info_body = control_info_part->getBody(); +    auto control_info_content = +        vmime::make_shared<vmime::stringContentHandler>("Version: 1"); +    control_info_body->setContents(control_info_content); + +    auto encrypted_data_part_header = encrypted_data_part->getHeader(); +    auto encrypted_data_content_type_field = +        encrypted_data_part_header->getField<vmime::contentTypeField>( +            vmime::fields::CONTENT_TYPE); +    encrypted_data_content_type_field->setValue("application/octet-stream"); +    encrypted_data_content_type_field->appendParameter( +        vmime::make_shared<vmime::parameter>("name", "encrypted.asc")); + +    auto encrypted_data_content_desc_header_field = +        encrypted_data_part_header->getField( +            vmime::fields::CONTENT_DESCRIPTION); +    encrypted_data_content_desc_header_field->setValue( +        "OpenPGP encrypted message"); + +    auto encrypted_data_content_disp_header_field = +        encrypted_data_part_header->getField<vmime::contentDispositionField>( +            vmime::fields::CONTENT_DISPOSITION); +    encrypted_data_content_disp_header_field->setValue("inline"); +    encrypted_data_content_disp_header_field->setFilename( +        vmime::word({"encrypted.asc"})); + +    auto encrypted_data_body = encrypted_data_part->getBody(); +    auto encrypted_data_content = +        vmime::make_shared<vmime::stringContentHandler>( +            encrypted_data.toStdString()); +    encrypted_data_body->setContents(encrypted_data_content); + +    eml_data = Q_SC(msg->generate(vmime::lineLengthLimits::infinite)); +    FLOG_DEBUG("EML Data: %1", eml_data); + +    return 0; + +  } catch (const vmime::exception& e) { +    eml_data = QString("VMIME Error: %1").arg(e.what()); +    return -1; +  } + +  eml_data = QString("Unknown Error: %1"); +  return -1; +} + +auto SignEMLData(int channel, const QString& key, +                 const EMailMetaData& meta_data, const QByteArray& body_data, +                 QString& eml_data) -> int { +  auto from = meta_data.from; +  auto recipient_list = meta_data.to; +  auto cc_list = meta_data.cc; +  auto bcc_list = meta_data.bcc; +  auto subject = meta_data.subject; + +  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(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(key), 1)); +    if (public_key.isEmpty()) { +      eml_data = "Get Public Key of Sign Key Failed"; +      return -1; +    } + +    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 = +        Q_SC(container_part->generate(vmime::lineLengthLimits::infinite)); + +    auto container_raw_data_hash = QCryptographicHash::hash( +        container_raw_data.toLatin1(), 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, key); + +    GFGpgSignResult* s; +    auto ret = GFGpgSignData(channel, QListToCharArray({key}), 1, +                             QDUP(container_raw_data), 1, 1, &s); + +    if (ret != 0) { +      eml_data = "Sign Failed"; +      return -1; +    } + +    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); + +    eml_data = Q_SC(msg->generate(vmime::lineLengthLimits::infinite)); + +    FLOG_DEBUG("EML Data: %1", eml_data); + +    return 0; + +  } catch (const vmime::exception& e) { +    eml_data = QString("VMIME Error: %1").arg(e.what()); +    return -1; +  } + +  eml_data = QString("Unknown Error: %1"); +  return -1; +}
\ No newline at end of file diff --git a/src/m_email/EMailBasicGpgOpera.h b/src/m_email/EMailBasicGpgOpera.h new file mode 100644 index 0000000..06753d3 --- /dev/null +++ b/src/m_email/EMailBasicGpgOpera.h @@ -0,0 +1,59 @@ +/** + * 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 "EMailModel.h" + +/** + * @brief + * + * @param channel + * @param keys + * @param meta_data + * @param body_data + * @param eml_data + * @return int + */ +auto EncryptEMLData(int channel, const QStringList& keys, +                    const EMailMetaData& meta_data, const QByteArray& body_data, +                    QString& eml_data) -> int; + +/** + * @brief + * + * @param channel + * @param key + * @param meta_data + * @param body_data + * @param eml_data + * @return int + */ +auto SignEMLData(int channel, const QString& key, +                 const EMailMetaData& meta_data, const QByteArray& body_data, +                 QString& eml_data) -> int;
\ No newline at end of file diff --git a/src/m_email/EMailHelper.h b/src/m_email/EMailHelper.h index 75cffe2..a4a7b77 100644 --- a/src/m_email/EMailHelper.h +++ b/src/m_email/EMailHelper.h @@ -101,3 +101,15 @@ auto ExtractFieldValueAddressList(   */  auto ExtractFieldValueDateTime(const vmime::shared_ptr<vmime::header>& header,                                 const QString& field_name) -> QDateTime; + +/** + * @brief + * + * @param input + * @param name + * @param email + * @return true + * @return false + */ +auto ParseEmailString(const QString& input, QString& name, +                      QString& email) -> bool;
\ No newline at end of file diff --git a/src/m_email/EMailMetaDataDialog.cpp b/src/m_email/EMailMetaDataDialog.cpp index d3ef010..bcabe48 100644 --- a/src/m_email/EMailMetaDataDialog.cpp +++ b/src/m_email/EMailMetaDataDialog.cpp @@ -38,25 +38,9 @@  #include "EMailHelper.h"  #include "ui_EMailMetaDataDialog.h" -static const QRegularExpression kNameEmailStringRegex{ -    R"(^\s*(.*)\s*<\s*([^<>@\s]+@[^<>@\s]+)\s*>\s*$)"}; -  static const QRegularExpression kNameEmailStringValidateRegex(      R"(^\s*(.*\s*)?<\s*([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+)\s*>\s*$|(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$))"); -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; @@ -83,13 +67,8 @@ EMailMetaDataDialog::EMailMetaDataDialog(int mode, QWidget* parent)    ui_->bccEdit->setHidden(true);    ui_->bccLabel->setHidden(true); -  if (mode == 0) { -    connect(ui_->okButton, &QPushButton::clicked, this, -            &EMailMetaDataDialog::slot_sign_eml_data); -  } else { -    connect(ui_->okButton, &QPushButton::clicked, this, -            &EMailMetaDataDialog::slot_encrypt_eml_data); -  } +  connect(ui_->okButton, &QPushButton::clicked, this, +          &EMailMetaDataDialog::slot_parse_eml_meta_data);    connect(ui_->cancelButton, &QPushButton::clicked, this, &QDialog::close); @@ -103,10 +82,8 @@ EMailMetaDataDialog::EMailMetaDataDialog(int mode, QWidget* parent)      ui_->bccLabel->setHidden(!ui_->bccLabel->isHidden());    }); -  connect(this, &EMailMetaDataDialog::SignalEMLDataGenerateSuccess, this, -          &QDialog::close); - -  connect(this, &EMailMetaDataDialog::SignalEMLDataGenerateFailed, this, +  connect(this, &EMailMetaDataDialog::SignalEMLMetaData, this, &QDialog::close); +  connect(this, &EMailMetaDataDialog::SignalNoEMLMetaData, this,            &QDialog::close);    setModal(true); @@ -115,14 +92,17 @@ EMailMetaDataDialog::EMailMetaDataDialog(int mode, QWidget* parent)  }  Q_VARIANT_Q_OBJECT_FACTORY_DEFINE(CreateEMailMetaDataDialog, -                                  [](QVariant data) -> void* { -                                    return new EMailMetaDataDialog(data.toInt(), +                                  [](QVariant mode) -> void* { +                                    return new EMailMetaDataDialog(mode.toInt(),                                                                     nullptr);                                    }); -void EMailMetaDataDialog::slot_sign_eml_data() { +void EMailMetaDataDialog::slot_parse_eml_meta_data() {    // sign key is a must -  if (keys_.isEmpty()) emit SignalEMLDataGenerateFailed("No Sign Key"); +  if (keys_.isEmpty()) { +    emit SignalNoEMLMetaData("No Sign Key"); +    return; +  }    // only allow one sign key    const auto sign_key = keys_.front(); @@ -132,253 +112,26 @@ void EMailMetaDataDialog::slot_sign_eml_data() {    if (!ui_->errorLabel->text().trimmed().isEmpty()) return;    auto from = ui_->fromEdit->text(); -  auto to = ui_->toEdit->text(); -  auto cc = ui_->ccEdit->text(); -  auto bcc = ui_->bccEdit->text(); +  auto raw_to = ui_->toEdit->text(); +  auto raw_cc = ui_->ccEdit->text(); +  auto raw_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); +  auto to = raw_to.split(';', Qt::SkipEmptyParts); +  auto cc = raw_cc.split(';', Qt::SkipEmptyParts); +  auto bcc = raw_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 = -        Q_SC(container_part->generate(vmime::lineLengthLimits::infinite)); - -    auto container_raw_data_hash = QCryptographicHash::hash( -        container_raw_data.toLatin1(), 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(container_raw_data), 1, 1, &s); +  EMailMetaData meta_data; +  meta_data.from = from; +  meta_data.to = to; +  meta_data.cc = cc; +  meta_data.bcc = bcc; +  meta_data.subject = subject; -    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(); +  emit SignalEMLMetaData(meta_data);  }  void EMailMetaDataDialog::slot_export_encrypted_data() {} @@ -480,261 +233,6 @@ void EMailMetaDataDialog::SetBodyData(QByteArray b) {    body_data_ = std::move(b);  } -void EMailMetaDataDialog::slot_encrypt_eml_data() { -  if (keys_.isEmpty()) { -    emit SignalEMLDataGenerateFailed("No Encryption Key Selected"); -    return; -  } - -  const auto encrypt_key = keys_.front(); - -  slot_validate_inputs_and_show_errors(); -  if (!ui_->errorLabel->text().trimmed().isEmpty()) { -    return; -  } - -  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 plaintext_msg_builder; - -    if (ParseEmailString(from, name, email)) { -      plaintext_msg_builder.setExpeditor( -          vmime::mailbox(vmime::text(name.toStdString()), email.toStdString())); -    } else { -      plaintext_msg_builder.setExpeditor(vmime::mailbox(from.toStdString())); -    } - -    for (const QString& recipient : recipient_list) { -      auto trimmed_recipient = recipient.trimmed(); -      if (ParseEmailString(trimmed_recipient, name, email)) { -        plaintext_msg_builder.getRecipients().appendAddress( -            vmime::make_shared<vmime::mailbox>(vmime::text(name.toStdString()), -                                               email.toStdString())); -      } else { -        plaintext_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)) { -        plaintext_msg_builder.getCopyRecipients().appendAddress( -            vmime::make_shared<vmime::mailbox>(vmime::text(name.toStdString()), -                                               email.toStdString())); -      } else { -        plaintext_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)) { -        plaintext_msg_builder.getBlindCopyRecipients().appendAddress( -            vmime::make_shared<vmime::mailbox>(vmime::text(name.toStdString()), -                                               email.toStdString())); -      } else { -        plaintext_msg_builder.getBlindCopyRecipients().appendAddress( -            vmime::make_shared<vmime::mailbox>( -                trimmed_recipient.toStdString())); -      } -    } - -    plaintext_msg_builder.setSubject(vmime::text(subject.toStdString())); - -    vmime::shared_ptr<vmime::message> plaintext_msg = -        plaintext_msg_builder.construct(); - -    auto plaintext_msg_header = plaintext_msg->getHeader(); - -    auto plaintext_msg_content_type_header_field = -        plaintext_msg_header->getField<vmime::contentTypeField>( -            vmime::fields::CONTENT_TYPE); -    plaintext_msg_content_type_header_field->setValue("text/plain"); -    plaintext_msg_content_type_header_field->appendParameter( -        vmime::make_shared<vmime::parameter>("charset", "UTF-8")); -    plaintext_msg_content_type_header_field->appendParameter( -        vmime::make_shared<vmime::parameter>("format", "flowed")); - -    auto plaintext_msg_content_trans_encode_field = -        plaintext_msg_header->getField( -            vmime::fields::CONTENT_TRANSFER_ENCODING); -    plaintext_msg_content_trans_encode_field->setValue("base64"); - -    auto plaintext_msg_body = plaintext_msg->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)); -    plaintext_msg_body->setContents(mime_part_body_content); - -    auto plaintext_eml_data = -        Q_SC(plaintext_msg->generate(vmime::lineLengthLimits::infinite)); - -    GFGpgEncryptionResult* enc_result = nullptr; -    auto ret = GFGpgEncryptData(channel_, QListToCharArray(keys_), keys_.size(), -                                QDUP(plaintext_eml_data), 1, &enc_result); - -    if (ret != 0) { -      emit SignalEMLDataGenerateFailed("Encryption Failed"); -      return; -    } - -    auto encrypted_data = UDUP(enc_result->encrypted_data); -    GFFreeMemory(enc_result); - -    vmime::messageBuilder msg_builder; - -    if (ParseEmailString(from, name, email)) { -      msg_builder.setExpeditor(vmime::mailbox(email.toStdString())); -    } else { -      msg_builder.setExpeditor(vmime::mailbox(from.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>(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>(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>(email.toStdString())); -      } else { -        msg_builder.getBlindCopyRecipients().appendAddress( -            vmime::make_shared<vmime::mailbox>( -                trimmed_recipient.toStdString())); -      } -    } - -    msg_builder.setSubject(vmime::text("...")); - -    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/encrypted"); -    content_type_header_field->appendParameter( -        vmime::make_shared<vmime::parameter>("protocol", -                                             "application/pgp-encrypted")); - -    auto root_part_boundary = vmime::body::generateRandomBoundaryString(); -    content_type_header_field->setBoundary(root_part_boundary); - -    auto root_body_part = vmime::make_shared<vmime::body>(); -    auto control_info_part = vmime::make_shared<vmime::bodyPart>(); -    auto encrypted_data_part = vmime::make_shared<vmime::bodyPart>(); - -    root_body_part->appendPart(control_info_part); -    root_body_part->appendPart(encrypted_data_part); -    msg->setBody(root_body_part); - -    root_body_part->setPrologText( -        "This is an OpenPGP/MIME encrypted message (RFC 4880 and 3156)"); - -    auto control_info_part_header = control_info_part->getHeader(); -    auto control_info_content_type_field = -        control_info_part_header->getField<vmime::contentTypeField>( -            vmime::fields::CONTENT_TYPE); -    control_info_content_type_field->setValue("application/pgp-encrypted"); - -    auto control_info_part_content_desc_header_field = -        control_info_part_header->getField(vmime::fields::CONTENT_DESCRIPTION); -    control_info_part_content_desc_header_field->setValue( -        "PGP/MIME version identification"); - -    auto control_info_body = control_info_part->getBody(); -    auto control_info_content = -        vmime::make_shared<vmime::stringContentHandler>("Version: 1"); -    control_info_body->setContents(control_info_content); - -    auto encrypted_data_part_header = encrypted_data_part->getHeader(); -    auto encrypted_data_content_type_field = -        encrypted_data_part_header->getField<vmime::contentTypeField>( -            vmime::fields::CONTENT_TYPE); -    encrypted_data_content_type_field->setValue("application/octet-stream"); -    encrypted_data_content_type_field->appendParameter( -        vmime::make_shared<vmime::parameter>("name", "encrypted.asc")); - -    auto encrypted_data_content_desc_header_field = -        encrypted_data_part_header->getField( -            vmime::fields::CONTENT_DESCRIPTION); -    encrypted_data_content_desc_header_field->setValue( -        "OpenPGP encrypted message"); - -    auto encrypted_data_content_disp_header_field = -        encrypted_data_part_header->getField<vmime::contentDispositionField>( -            vmime::fields::CONTENT_DISPOSITION); -    encrypted_data_content_disp_header_field->setValue("inline"); -    encrypted_data_content_disp_header_field->setFilename( -        vmime::word({"encrypted.asc"})); - -    auto encrypted_data_body = encrypted_data_part->getBody(); -    auto encrypted_data_content = -        vmime::make_shared<vmime::stringContentHandler>( -            encrypted_data.toStdString()); -    encrypted_data_body->setContents(encrypted_data_content); - -    auto eml_data = Q_SC(msg->generate(vmime::lineLengthLimits::infinite)); -    FLOG_DEBUG("EML Data: %1", eml_data); - -    emit SignalEMLDataGenerateSuccess(eml_data); - -    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()); -    return; -  } - -  emit SignalEMLDataGenerateFailed("Unknown Error"); -} -  void EMailMetaDataDialog::slot_set_to_field_by_encrypt_keys() {    QStringList to_list; diff --git a/src/m_email/EMailMetaDataDialog.h b/src/m_email/EMailMetaDataDialog.h index c4ce5e4..27e8ec6 100644 --- a/src/m_email/EMailMetaDataDialog.h +++ b/src/m_email/EMailMetaDataDialog.h @@ -31,6 +31,7 @@  #include <QDialog>  #include <QSharedPointer> +#include "EMailModel.h"  #include "GFModuleCommonUtils.hpp"  class QWidget; @@ -62,15 +63,13 @@ class EMailMetaDataDialog : public QDialog {   signals: -  void SignalEMLDataGenerateSuccess(QString); +  void SignalEMLMetaData(EMailMetaData meta_data); -  void SignalEMLDataGenerateFailed(QString); +  void SignalNoEMLMetaData(QString error_string);   private slots: -  void slot_sign_eml_data(); - -  void slot_encrypt_eml_data(); +  void slot_parse_eml_meta_data();    void slot_export_encrypted_data(); diff --git a/src/m_email/EMailModel.h b/src/m_email/EMailModel.h new file mode 100644 index 0000000..454645f --- /dev/null +++ b/src/m_email/EMailModel.h @@ -0,0 +1,40 @@ +/** + * 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 <QString> +#include <QStringList> + +struct EMailMetaData { +  QString from; +  QStringList to; +  QStringList cc; +  QStringList bcc; +  QString subject; +};
\ No newline at end of file diff --git a/src/m_email/EMailModule.cpp b/src/m_email/EMailModule.cpp index ee46bb9..9e76689 100644 --- a/src/m_email/EMailModule.cpp +++ b/src/m_email/EMailModule.cpp @@ -52,6 +52,7 @@  #include "GFModuleDefine.h"  // +#include "EMailBasicGpgOpera.h"  #include "EMailHelper.h"  #include "EMailMetaDataDialog.h" @@ -416,7 +417,8 @@ REGISTER_EVENT_HANDLER(EMAIL_SIGN_EML_DATA, [](const MEvent& event) -> int {    FLOG_DEBUG("eml sign key: %1", sign_key); -  auto data = QByteArray::fromBase64(QString(event["body_data"]).toLatin1()); +  auto body_data = +      QByteArray::fromBase64(QString(event["body_data"]).toLatin1());    auto* dialog = GUI_OBJECT(CreateEMailMetaDataDialog, 0);    auto* r_dialog = @@ -426,25 +428,29 @@ REGISTER_EVENT_HANDLER(EMAIL_SIGN_EML_DATA, [](const MEvent& event) -> int {    r_dialog->SetChannel(channel);    r_dialog->SetKeys({sign_key}); -  r_dialog->SetBodyData({data}); +  r_dialog->SetBodyData({body_data});    GFUIShowDialog(dialog, nullptr); +  QObject::connect(r_dialog, &EMailMetaDataDialog::SignalEMLMetaData, r_dialog, +                   [=](const EMailMetaData& meta_data) { +                     QString eml_data; +                     auto ret = SignEMLData(channel, sign_key, meta_data, +                                            body_data, eml_data); +                     if (ret != 0) { +                       CB_ERR(event, -2, eml_data); +                     } -  QObject::connect(r_dialog, &EMailMetaDataDialog::SignalEMLDataGenerateSuccess, -                   r_dialog, [=](QString eml_data) { -                     // callback                       CB(event, GFGetModuleID(),                          {                              {"ret", QString::number(0)},                              {"eml_data", eml_data},                          }); +                     return 0;                     }); -  QObject::connect(r_dialog, &EMailMetaDataDialog::SignalEMLDataGenerateFailed, -                   r_dialog, [=](QString error) { -                     // callback -                     CB_ERR(event, -1, "Generate EML Data Failed: " + error); -                   }); +  QObject::connect( +      r_dialog, &EMailMetaDataDialog::SignalNoEMLMetaData, r_dialog, +      [=](const QString& error_string) { CB_ERR(event, -1, error_string); });    return 0;  }); @@ -460,7 +466,8 @@ REGISTER_EVENT_HANDLER(EMAIL_ENCRYPT_EML_DATA, [](const MEvent& event) -> int {    FLOG_DEBUG("eml encrypt keys: %1", encrypt_keys.join(';')); -  auto data = QByteArray::fromBase64(QString(event["body_data"]).toLatin1()); +  auto body_data = +      QByteArray::fromBase64(QString(event["body_data"]).toLatin1());    auto* dialog = GUI_OBJECT(CreateEMailMetaDataDialog, 1);    auto* r_dialog = @@ -470,25 +477,30 @@ REGISTER_EVENT_HANDLER(EMAIL_ENCRYPT_EML_DATA, [](const MEvent& event) -> int {    r_dialog->SetChannel(channel);    r_dialog->SetKeys(encrypt_keys); -  r_dialog->SetBodyData({data}); +  r_dialog->SetBodyData({body_data});    GFUIShowDialog(dialog, nullptr); -  QObject::connect(r_dialog, &EMailMetaDataDialog::SignalEMLDataGenerateSuccess, -                   r_dialog, [=](QString eml_data) { -                     // callback +  QObject::connect(r_dialog, &EMailMetaDataDialog::SignalEMLMetaData, r_dialog, +                   [=](const EMailMetaData& meta_data) { +                     QString eml_data; +                     auto ret = EncryptEMLData(channel, encrypt_keys, meta_data, +                                               body_data, eml_data); +                     if (ret != 0) { +                       CB_ERR(event, -2, eml_data); +                     } +                       CB(event, GFGetModuleID(),                          {                              {"ret", QString::number(0)},                              {"eml_data", eml_data},                          }); +                     return 0;                     }); -  QObject::connect(r_dialog, &EMailMetaDataDialog::SignalEMLDataGenerateFailed, -                   r_dialog, [=](QString error) { -                     // callback -                     CB_ERR(event, -1, "Generate EML Data Failed: " + error); -                   }); +  QObject::connect( +      r_dialog, &EMailMetaDataDialog::SignalNoEMLMetaData, r_dialog, +      [=](const QString& error_string) { CB_ERR(event, -1, error_string); });    return 0;  });  | 
