aboutsummaryrefslogtreecommitdiffstats
path: root/src/m_email/EMailModule.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/m_email/EMailModule.cpp')
-rw-r--r--src/m_email/EMailModule.cpp1239
1 files changed, 673 insertions, 566 deletions
diff --git a/src/m_email/EMailModule.cpp b/src/m_email/EMailModule.cpp
index cb415d5..a1b8049 100644
--- a/src/m_email/EMailModule.cpp
+++ b/src/m_email/EMailModule.cpp
@@ -28,8 +28,6 @@
#include "EMailModule.h"
-#include "GFModuleIdentity.h"
-
#include <GFSDKBasic.h>
#include <GFSDKBuildInfo.h>
#include <GFSDKLog.h>
@@ -39,6 +37,7 @@
#include "EMailImapController.h"
#include "EMailSecret.h"
#include "EMailSendDialog.h"
+#include "GFModuleIdentity.h"
// qt
#include <QApplication>
@@ -453,9 +452,7 @@ auto OnDeactivate() -> GFResult {
return GFResult::Ok();
}
-auto OnUnload() -> void {
- LOG_INFO("email module unregistering");
-}
+auto OnUnload() -> void { LOG_INFO("email module unregistering"); }
namespace {
@@ -597,12 +594,12 @@ auto ErrorHelper(int ret, const QString& err) -> QString {
} // namespace
auto OnKeyDatabaseRefreshDone(const GFEvent& event) -> GFEventResult {
- // A verification that reported a missing key stops
- // being true once that key is imported; open messages
- // work their signatures out again rather than keeping
- // the stale verdict.
- EMailNotifyKeyringChanged();
- return GFEventResult::Ok();
+ // A verification that reported a missing key stops
+ // being true once that key is imported; open messages
+ // work their signatures out again rather than keeping
+ // the stale verdict.
+ EMailNotifyKeyringChanged();
+ return GFEventResult::Ok();
}
namespace {
@@ -697,8 +694,7 @@ auto OnMainwindowMenuMounted(const GFEvent& event) -> GFEventResult {
LOG_ERROR("advance_menu handle invalid or not QMenu");
}
- auto* workspace_menu =
- GFUIObject<QMenu>(event.Str("file_workspace_menu"));
+ auto* workspace_menu = GFUIObject<QMenu>(event.Str("file_workspace_menu"));
if (!workspace_menu) {
LOG_ERROR(
"main window menu mounted: workspace_menu handle invalid or not "
@@ -916,7 +912,8 @@ auto DoVerifyEMLData(int channel, const QByteArray& data, const GFEvent& event,
-> int {
auto ret = VerifyEMLMessage(channel, data, result, error_string);
if (ret != kSUCCESS) {
- event.Answer().Ok({{"result_status", QString::number(-1)}, {"result", ErrorHelper(ret, error_string)}});
+ event.Answer().Ok({{"result_status", QString::number(-1)},
+ {"result", ErrorHelper(ret, error_string)}});
return ret;
}
return kSUCCESS;
@@ -924,86 +921,87 @@ auto DoVerifyEMLData(int channel, const QByteArray& data, const GFEvent& event,
} // namespace
auto OnEditTabTypeEmailOpVerify(const GFEvent& event) -> GFEventResult {
- if (event.Str("channel").isEmpty()) return GFEventResult::Bad("channel is empty");
- if (event.Str("data").isEmpty()) return GFEventResult::Bad("data is empty");
+ if (event.Str("channel").isEmpty())
+ return GFEventResult::Bad("channel is empty");
+ if (event.Str("data").isEmpty()) return GFEventResult::Bad("data is empty");
- auto channel = event.Str("channel").toInt();
- auto data = QByteArray::fromBase64(QString(event.Str("data")).toLatin1());
+ auto channel = event.Str("channel").toInt();
+ auto data = QByteArray::fromBase64(QString(event.Str("data")).toLatin1());
- QString error_string;
- EMailVerificationResult result;
- if (DoVerifyEMLData(channel, data, event, error_string, result) !=
- kSUCCESS) {
- return GFEventResult::Deferred();
- }
+ QString error_string;
+ EMailVerificationResult result;
+ if (DoVerifyEMLData(channel, data, event, error_string, result) != kSUCCESS) {
+ return GFEventResult::Deferred();
+ }
- const auto& meta_data = result.meta;
- const auto result_status = ReportStatusFor(result.overall);
+ const auto& meta_data = result.meta;
+ const auto result_status = ReportStatusFor(result.overall);
- QString email_info;
- email_info.append("# E-Mail Information\n\n");
- email_info.append(QString("- %1: %2\n")
- .arg(QApplication::translate("EMailModule", "From"))
- .arg(meta_data.from));
- email_info.append(QString("- %1: %2\n")
- .arg(QApplication::translate("EMailModule", "To"))
- .arg(meta_data.to.join("; ")));
- email_info.append(
- QString("- %1: %2\n")
- .arg(QApplication::translate("EMailModule", "Subject"))
- .arg(meta_data.subject));
- email_info.append(QString("- %1: %2\n")
- .arg(QApplication::translate("EMailModule", "CC"))
- .arg(meta_data.cc.join("; ")));
- email_info.append(QString("- %1: %2\n")
- .arg(QApplication::translate("EMailModule", "BCC"))
- .arg(meta_data.bcc_header.join("; ")));
- email_info.append(QString("- %1: %2\n")
- .arg(QApplication::translate("EMailModule", "Date"))
- .arg(QLocale().toString(meta_data.datetime)));
+ QString email_info;
+ email_info.append("# E-Mail Information\n\n");
+ email_info.append(QString("- %1: %2\n")
+ .arg(QApplication::translate("EMailModule", "From"))
+ .arg(meta_data.from));
+ email_info.append(QString("- %1: %2\n")
+ .arg(QApplication::translate("EMailModule", "To"))
+ .arg(meta_data.to.join("; ")));
+ email_info.append(QString("- %1: %2\n")
+ .arg(QApplication::translate("EMailModule", "Subject"))
+ .arg(meta_data.subject));
+ email_info.append(QString("- %1: %2\n")
+ .arg(QApplication::translate("EMailModule", "CC"))
+ .arg(meta_data.cc.join("; ")));
+ email_info.append(QString("- %1: %2\n")
+ .arg(QApplication::translate("EMailModule", "BCC"))
+ .arg(meta_data.bcc_header.join("; ")));
+ email_info.append(QString("- %1: %2\n")
+ .arg(QApplication::translate("EMailModule", "Date"))
+ .arg(QLocale().toString(meta_data.datetime)));
- email_info.append("\n");
+ email_info.append("\n");
- email_info.append("# OpenPGP Information\n\n");
+ email_info.append("# OpenPGP Information\n\n");
- email_info.append(
- QString("- %1: %2\n")
- .arg(QApplication::translate(
- "EMailModule", "Digest of Signed MIME Entity (SHA-256)"))
- .arg(meta_data.signed_entity_digest));
- email_info.append(
- QString("- %1: %2\n")
- .arg(QApplication::translate("EMailModule",
- "Declared Signature Hash (micalg)"))
- .arg(meta_data.micalg));
+ email_info.append(
+ QString("- %1: %2\n")
+ .arg(QApplication::translate(
+ "EMailModule", "Digest of Signed MIME Entity (SHA-256)"))
+ .arg(meta_data.signed_entity_digest));
+ email_info.append(QString("- %1: %2\n")
+ .arg(QApplication::translate(
+ "EMailModule", "Declared Signature Hash (micalg)"))
+ .arg(meta_data.micalg));
- // Without this, a message whose line endings were rewritten after
- // signing reads exactly like a forged one, and the user has no way to
- // tell the difference or to know that importing a key cannot help.
- if (meta_data.signed_entity_non_canonical) {
- email_info.append(QString("- %1\n").arg(QApplication::translate(
- "EMailModule",
- "**Note**: the signed part is not in canonical form, "
- "because its line endings are not CRLF. Something rewrote "
- "this message after it was signed, which is usually a "
- "program that changed line endings while saving or "
- "copying it. A signature cannot verify against these "
- "bytes, and importing the sender's key will not change "
- "that.")));
- }
+ // Without this, a message whose line endings were rewritten after
+ // signing reads exactly like a forged one, and the user has no way to
+ // tell the difference or to know that importing a key cannot help.
+ if (meta_data.signed_entity_non_canonical) {
+ email_info.append(QString("- %1\n").arg(QApplication::translate(
+ "EMailModule",
+ "**Note**: the signed part is not in canonical form, "
+ "because its line endings are not CRLF. Something rewrote "
+ "this message after it was signed, which is usually a "
+ "program that changed line endings while saving or "
+ "copying it. A signature cannot verify against these "
+ "bytes, and importing the sender's key will not change "
+ "that.")));
+ }
- email_info.append("\n");
+ email_info.append("\n");
- email_info.append("#" + result.report_detail + "\n");
+ email_info.append("#" + result.report_detail + "\n");
- const auto result_cards_param = BuildResultCardsParam(
- QApplication::translate("EMailModule", "Verify E-Mail"),
- BuildReadMetaCards(meta_data, true), result.report_cards,
- result.report_info_json, ReportDescriptionFor(result));
+ const auto result_cards_param = BuildResultCardsParam(
+ QApplication::translate("EMailModule", "Verify E-Mail"),
+ BuildReadMetaCards(meta_data, true), result.report_cards,
+ result.report_info_json, ReportDescriptionFor(result));
- // callback
- event.Answer().Ok({{"result_status", QString::number(result_status)}, {"result", email_info}, {"result_cards", result_cards_param}, {"verification", EncodeVerificationPayload(result)}});
- return GFEventResult::Deferred();
+ // callback
+ event.Answer().Ok({{"result_status", QString::number(result_status)},
+ {"result", email_info},
+ {"result_cards", result_cards_param},
+ {"verification", EncodeVerificationPayload(result)}});
+ return GFEventResult::Deferred();
}
namespace {
@@ -1019,7 +1017,10 @@ auto DoDecryptEMLData(int channel, const QByteArray& data, const GFEvent& event,
DecryptEMLData(channel, data, meta_data, eml_data, err, capsule_id);
if (ret == kFAILED || ret == kEML_FAILED) {
- event.Answer().Ok({{"data", data}, {"result_status", QString::number(-1)}, {"result", ErrorHelper(ret, QString::fromUtf8(eml_data))}});
+ event.Answer().Ok(
+ {{"data", data},
+ {"result_status", QString::number(-1)},
+ {"result", ErrorHelper(ret, QString::fromUtf8(eml_data))}});
return ret;
}
@@ -1039,12 +1040,22 @@ auto DoDecryptEMLData(int channel, const QByteArray& data, const GFEvent& event,
if (ret == kGPG_FAILED) {
// decrypt failed. The analysis cards built above travel with it: a failure
// is the outcome that most needs explaining, not the one to explain least.
- event.Answer().Ok({{"data", data}, {"result_status", QString::number(result_status)}, {"result", result_detail}, {"result_cards", BuildResultCardsParam( QApplication::translate("EMailModule", "Decrypt E-Mail"), {}, result_cards, decrypt_info_json)}});
+ event.Answer().Ok(
+ {{"data", data},
+ {"result_status", QString::number(result_status)},
+ {"result", result_detail},
+ {"result_cards",
+ BuildResultCardsParam(
+ QApplication::translate("EMailModule", "Decrypt E-Mail"), {},
+ result_cards, decrypt_info_json)}});
return ret;
}
if (ret != kSUCCESS) {
- event.Answer().Ok({{"data", data}, {"result_status", QString::number(-1)}, {"result", ErrorHelper(ret, QString::fromUtf8(eml_data))}});
+ event.Answer().Ok(
+ {{"data", data},
+ {"result_status", QString::number(-1)},
+ {"result", ErrorHelper(ret, QString::fromUtf8(eml_data))}});
return ret;
}
@@ -1054,63 +1065,66 @@ auto DoDecryptEMLData(int channel, const QByteArray& data, const GFEvent& event,
} // namespace
auto OnEditTabTypeEmailOpDecrypt(const GFEvent& event) -> GFEventResult {
- if (event.Str("channel").isEmpty()) return GFEventResult::Bad("channel is empty");
- if (event.Str("data").isEmpty()) return GFEventResult::Bad("data is empty");
+ if (event.Str("channel").isEmpty())
+ return GFEventResult::Bad("channel is empty");
+ if (event.Str("data").isEmpty()) return GFEventResult::Bad("data is empty");
- auto channel = event.Str("channel").toInt();
- auto data = QByteArray::fromBase64(QString(event.Str("data")).toLatin1());
+ auto channel = event.Str("channel").toInt();
+ auto data = QByteArray::fromBase64(QString(event.Str("data")).toLatin1());
- QByteArray eml_data;
- int result_status = 0;
- QString result_detail;
- QString result_cards;
- EMailMetaData meta_data;
- QByteArray decrypt_info_json;
- if (DoDecryptEMLData(channel, data, event, result_status, result_detail,
- result_cards, eml_data, meta_data,
- decrypt_info_json) != kSUCCESS) {
- return GFEventResult::Deferred();
- }
+ QByteArray eml_data;
+ int result_status = 0;
+ QString result_detail;
+ QString result_cards;
+ EMailMetaData meta_data;
+ QByteArray decrypt_info_json;
+ if (DoDecryptEMLData(channel, data, event, result_status, result_detail,
+ result_cards, eml_data, meta_data,
+ decrypt_info_json) != kSUCCESS) {
+ return GFEventResult::Deferred();
+ }
- QString email_info;
- email_info.append("# E-Mail Information\n\n");
- email_info.append(QString("- %1: %2\n")
- .arg(QApplication::translate("EMailModule", "From"))
- .arg(meta_data.from));
- email_info.append(QString("- %1: %2\n")
- .arg(QApplication::translate("EMailModule", "To"))
- .arg(meta_data.to.join("; ")));
- email_info.append(
- QString("- %1: %2\n")
- .arg(QApplication::translate("EMailModule", "Subject"))
- .arg(meta_data.subject));
- email_info.append(QString("- %1: %2\n")
- .arg(QApplication::translate("EMailModule", "CC"))
- .arg(meta_data.cc.join("; ")));
- email_info.append(QString("- %1: %2\n")
- .arg(QApplication::translate("EMailModule", "BCC"))
- .arg(meta_data.bcc_header.join("; ")));
- email_info.append(QString("- %1: %2\n")
- .arg(QApplication::translate("EMailModule", "Date"))
- .arg(QLocale().toString(meta_data.datetime)));
+ QString email_info;
+ email_info.append("# E-Mail Information\n\n");
+ email_info.append(QString("- %1: %2\n")
+ .arg(QApplication::translate("EMailModule", "From"))
+ .arg(meta_data.from));
+ email_info.append(QString("- %1: %2\n")
+ .arg(QApplication::translate("EMailModule", "To"))
+ .arg(meta_data.to.join("; ")));
+ email_info.append(QString("- %1: %2\n")
+ .arg(QApplication::translate("EMailModule", "Subject"))
+ .arg(meta_data.subject));
+ email_info.append(QString("- %1: %2\n")
+ .arg(QApplication::translate("EMailModule", "CC"))
+ .arg(meta_data.cc.join("; ")));
+ email_info.append(QString("- %1: %2\n")
+ .arg(QApplication::translate("EMailModule", "BCC"))
+ .arg(meta_data.bcc_header.join("; ")));
+ email_info.append(QString("- %1: %2\n")
+ .arg(QApplication::translate("EMailModule", "Date"))
+ .arg(QLocale().toString(meta_data.datetime)));
- email_info.append("\n");
+ email_info.append("\n");
- email_info.append("# OpenPGP Information\n\n");
- email_info.append("#" + result_detail + "\n");
+ email_info.append("# OpenPGP Information\n\n");
+ email_info.append("#" + result_detail + "\n");
- auto decrypt_meta_cards = BuildReadMetaCards(meta_data, false);
- const auto recipient_card =
- BuildRecipientCheckCard(meta_data, decrypt_info_json);
- if (!recipient_card.isEmpty()) decrypt_meta_cards.append(recipient_card);
+ auto decrypt_meta_cards = BuildReadMetaCards(meta_data, false);
+ const auto recipient_card =
+ BuildRecipientCheckCard(meta_data, decrypt_info_json);
+ if (!recipient_card.isEmpty()) decrypt_meta_cards.append(recipient_card);
- const auto result_cards_param = BuildResultCardsParam(
- QApplication::translate("EMailModule", "Decrypt E-Mail"),
- decrypt_meta_cards, result_cards);
+ const auto result_cards_param = BuildResultCardsParam(
+ QApplication::translate("EMailModule", "Decrypt E-Mail"),
+ decrypt_meta_cards, result_cards);
- // callback
- event.Answer().Ok({{"data", eml_data}, {"result_status", QString::number(result_status)}, {"result", email_info}, {"result_cards", result_cards_param}});
- return GFEventResult::Deferred();
+ // callback
+ event.Answer().Ok({{"data", eml_data},
+ {"result_status", QString::number(result_status)},
+ {"result", email_info},
+ {"result_cards", result_cards_param}});
+ return GFEventResult::Deferred();
}
namespace {
@@ -1133,7 +1147,10 @@ auto DoSignEMLData(int channel, const QString& sign_key,
ret = SignEMLData(channel, sign_key, message, eml_data, err, capsule_id);
if (ret == kFAILED || ret == kEML_FAILED) {
- event.Answer().Ok({{"data", body_data}, {"result_status", QString::number(-1)}, {"result", ErrorHelper(ret, QString::fromUtf8(eml_data))}});
+ event.Answer().Ok(
+ {{"data", body_data},
+ {"result_status", QString::number(-1)},
+ {"result", ErrorHelper(ret, QString::fromUtf8(eml_data))}});
return ret;
}
@@ -1154,12 +1171,21 @@ auto DoSignEMLData(int channel, const QString& sign_key,
if (ret == kGPG_FAILED) {
// decrypt failed. The analysis cards built above travel with it: a failure
// is the outcome that most needs explaining, not the one to explain least.
- event.Answer().Ok({{"data", body_data}, {"result_status", QString::number(result_status)}, {"result", result_detail}, {"result_cards", BuildResultCardsParam( QApplication::translate("EMailModule", "Sign E-Mail"), {}, result_cards, info_json)}});
+ event.Answer().Ok({{"data", body_data},
+ {"result_status", QString::number(result_status)},
+ {"result", result_detail},
+ {"result_cards",
+ BuildResultCardsParam(QApplication::translate(
+ "EMailModule", "Sign E-Mail"),
+ {}, result_cards, info_json)}});
return ret;
}
if (ret != kSUCCESS) {
- event.Answer().Ok({{"data", body_data}, {"result_status", QString::number(-1)}, {"result", ErrorHelper(ret, QString::fromUtf8(eml_data))}});
+ event.Answer().Ok(
+ {{"data", body_data},
+ {"result_status", QString::number(-1)},
+ {"result", ErrorHelper(ret, QString::fromUtf8(eml_data))}});
return ret;
}
@@ -1177,7 +1203,10 @@ auto DoSignPlainText(int channel, const QString& sign_key,
auto ret = SignPlainText(channel, sign_key, meta_data, body_data, eml_data,
err, capsule_id);
if (ret == kFAILED || ret == kEML_FAILED) {
- event.Answer().Ok({{"data", body_data}, {"result_status", QString::number(-1)}, {"result", ErrorHelper(ret, QString::fromUtf8(eml_data))}});
+ event.Answer().Ok(
+ {{"data", body_data},
+ {"result_status", QString::number(-1)},
+ {"result", ErrorHelper(ret, QString::fromUtf8(eml_data))}});
return ret;
}
@@ -1198,12 +1227,21 @@ auto DoSignPlainText(int channel, const QString& sign_key,
if (ret == kGPG_FAILED) {
// decrypt failed. The analysis cards built above travel with it: a failure
// is the outcome that most needs explaining, not the one to explain least.
- event.Answer().Ok({{"data", body_data}, {"result_status", QString::number(result_status)}, {"result", result_detail}, {"result_cards", BuildResultCardsParam( QApplication::translate("EMailModule", "Sign E-Mail"), {}, result_cards, info_json)}});
+ event.Answer().Ok({{"data", body_data},
+ {"result_status", QString::number(result_status)},
+ {"result", result_detail},
+ {"result_cards",
+ BuildResultCardsParam(QApplication::translate(
+ "EMailModule", "Sign E-Mail"),
+ {}, result_cards, info_json)}});
return ret;
}
if (ret != kSUCCESS) {
- event.Answer().Ok({{"data", body_data}, {"result_status", QString::number(-1)}, {"result", ErrorHelper(ret, QString::fromUtf8(eml_data))}});
+ event.Answer().Ok(
+ {{"data", body_data},
+ {"result_status", QString::number(-1)},
+ {"result", ErrorHelper(ret, QString::fromUtf8(eml_data))}});
return ret;
}
@@ -1213,50 +1251,65 @@ auto DoSignPlainText(int channel, const QString& sign_key,
} // namespace
auto OnEditTabTypeEmailOpSign(const GFEvent& event) -> GFEventResult {
- if (event.Str("body_data").isEmpty()) return GFEventResult::Bad("body_data is empty");
- if (event.Str("channel").isEmpty()) return GFEventResult::Bad("channel is empty");
- if (event.Str("sign_key").isEmpty()) return GFEventResult::Bad("sign_key is empty");
+ if (event.Str("body_data").isEmpty())
+ return GFEventResult::Bad("body_data is empty");
+ if (event.Str("channel").isEmpty())
+ return GFEventResult::Bad("channel is empty");
+ if (event.Str("sign_key").isEmpty())
+ return GFEventResult::Bad("sign_key is empty");
- auto channel = event.Str("channel").toInt();
- auto sign_key = event.Str("sign_key");
+ auto channel = event.Str("channel").toInt();
+ auto sign_key = event.Str("sign_key");
- FLOG_DEBUG("eml sign key: %1", sign_key);
+ FLOG_DEBUG("eml sign key: %1", sign_key);
- auto body_data =
- QByteArray::fromBase64(QString(event.Str("body_data")).toLatin1());
+ auto body_data =
+ QByteArray::fromBase64(QString(event.Str("body_data")).toLatin1());
- vmime::shared_ptr<vmime::message> message;
- if (CheckIfEMLMessage(body_data, message)) {
- int result_status = 0;
- QString result_detail;
- QString result_cards;
- QByteArray eml_data;
- if (DoSignEMLData(channel, sign_key, message, body_data, event,
- result_status, result_detail, result_cards,
- eml_data) != kSUCCESS) {
- return GFEventResult::Deferred();
- }
+ vmime::shared_ptr<vmime::message> message;
+ if (CheckIfEMLMessage(body_data, message)) {
+ int result_status = 0;
+ QString result_detail;
+ QString result_cards;
+ QByteArray eml_data;
+ if (DoSignEMLData(channel, sign_key, message, body_data, event,
+ result_status, result_detail, result_cards,
+ eml_data) != kSUCCESS) {
+ return GFEventResult::Deferred();
+ }
- event.Answer().Ok({{"data", eml_data}, {"result_status", QString::number(result_status)}, {"result", result_detail}, {"result_cards", BuildResultCardsParam( QApplication::translate("EMailModule", "Sign E-Mail"), {}, result_cards)}});
- return GFEventResult::Deferred();
- }
+ event.Answer().Ok({{"data", eml_data},
+ {"result_status", QString::number(result_status)},
+ {"result", result_detail},
+ {"result_cards",
+ BuildResultCardsParam(QApplication::translate(
+ "EMailModule", "Sign E-Mail"),
+ {}, result_cards)}});
+ return GFEventResult::Deferred();
+ }
- // Not a message yet: wrap the text in an envelope derived from the
- // signing key rather than stopping to ask for one.
- const auto meta_data = EnvelopeFromKeys(channel, sign_key, {});
+ // Not a message yet: wrap the text in an envelope derived from the
+ // signing key rather than stopping to ask for one.
+ const auto meta_data = EnvelopeFromKeys(channel, sign_key, {});
- int result_status = 0;
- QString result_detail;
- QString result_cards;
- QByteArray eml_data;
- if (DoSignPlainText(channel, sign_key, meta_data, body_data, event,
- result_status, result_detail, result_cards,
- eml_data) != kSUCCESS) {
- return GFEventResult::Deferred();
- }
+ int result_status = 0;
+ QString result_detail;
+ QString result_cards;
+ QByteArray eml_data;
+ if (DoSignPlainText(channel, sign_key, meta_data, body_data, event,
+ result_status, result_detail, result_cards,
+ eml_data) != kSUCCESS) {
+ return GFEventResult::Deferred();
+ }
- event.Answer().Ok({{"data", eml_data}, {"result_status", QString::number(result_status)}, {"result", result_detail}, {"result_cards", BuildResultCardsParam( QApplication::translate("EMailModule", "Sign E-Mail"), {BuildEMailHeaderCard(meta_data)}, result_cards)}});
- return GFEventResult::Deferred();
+ event.Answer().Ok({{"data", eml_data},
+ {"result_status", QString::number(result_status)},
+ {"result", result_detail},
+ {"result_cards",
+ BuildResultCardsParam(
+ QApplication::translate("EMailModule", "Sign E-Mail"),
+ {BuildEMailHeaderCard(meta_data)}, result_cards)}});
+ return GFEventResult::Deferred();
}
namespace {
@@ -1272,7 +1325,10 @@ auto DoEncryptEMLData(int channel, const QStringList& encrypt_keys,
err, capsule_id);
if (ret == kFAILED || ret == kEML_FAILED) {
- event.Answer().Ok({{"data", DocumentUnchangedOnFailure(body_data)}, {"result_status", QString::number(-1)}, {"result", ErrorHelper(ret, QString::fromUtf8(eml_data))}});
+ event.Answer().Ok(
+ {{"data", DocumentUnchangedOnFailure(body_data)},
+ {"result_status", QString::number(-1)},
+ {"result", ErrorHelper(ret, QString::fromUtf8(eml_data))}});
return ret;
}
@@ -1293,7 +1349,14 @@ auto DoEncryptEMLData(int channel, const QStringList& encrypt_keys,
if (ret == kGPG_FAILED) {
// encrypt failed. The analysis cards built above travel with it: a failure
// is the outcome that most needs explaining, not the one to explain least.
- event.Answer().Ok({{"data", DocumentUnchangedOnFailure(body_data)}, {"result_status", QString::number(result_status)}, {"result", result_detail}, {"result_cards", BuildResultCardsParam( QApplication::translate("EMailModule", "Encrypt E-Mail"), {}, result_cards, info_json)}});
+ event.Answer().Ok(
+ {{"data", DocumentUnchangedOnFailure(body_data)},
+ {"result_status", QString::number(result_status)},
+ {"result", result_detail},
+ {"result_cards",
+ BuildResultCardsParam(
+ QApplication::translate("EMailModule", "Encrypt E-Mail"), {},
+ result_cards, info_json)}});
return ret;
}
@@ -1311,7 +1374,10 @@ auto DoEncryptPlainText(int channel, const QStringList& encrypt_keys,
auto ret = BuildPlainTextEML(meta_data, body_data, plain_text_eml_data);
if (ret != kSUCCESS) {
- event.Answer().Ok({{"data", DocumentUnchangedOnFailure(body_data)}, {"result_status", QString::number(-1)}, {"result", ErrorHelper(ret, QString::fromUtf8(eml_data))}});
+ event.Answer().Ok(
+ {{"data", DocumentUnchangedOnFailure(body_data)},
+ {"result_status", QString::number(-1)},
+ {"result", ErrorHelper(ret, QString::fromUtf8(eml_data))}});
return ret;
}
@@ -1319,7 +1385,10 @@ auto DoEncryptPlainText(int channel, const QStringList& encrypt_keys,
eml_data, err, capsule_id);
if (ret == kFAILED || ret == kEML_FAILED) {
- event.Answer().Ok({{"data", DocumentUnchangedOnFailure(body_data)}, {"result_status", QString::number(-1)}, {"result", ErrorHelper(ret, QString::fromUtf8(eml_data))}});
+ event.Answer().Ok(
+ {{"data", DocumentUnchangedOnFailure(body_data)},
+ {"result_status", QString::number(-1)},
+ {"result", ErrorHelper(ret, QString::fromUtf8(eml_data))}});
return ret;
}
@@ -1340,7 +1409,14 @@ auto DoEncryptPlainText(int channel, const QStringList& encrypt_keys,
if (ret == kGPG_FAILED) {
// encrypt failed. The analysis cards built above travel with it: a failure
// is the outcome that most needs explaining, not the one to explain least.
- event.Answer().Ok({{"data", DocumentUnchangedOnFailure(body_data)}, {"result_status", QString::number(result_status)}, {"result", result_detail}, {"result_cards", BuildResultCardsParam( QApplication::translate("EMailModule", "Encrypt E-Mail"), {}, result_cards, info_json)}});
+ event.Answer().Ok(
+ {{"data", DocumentUnchangedOnFailure(body_data)},
+ {"result_status", QString::number(result_status)},
+ {"result", result_detail},
+ {"result_cards",
+ BuildResultCardsParam(
+ QApplication::translate("EMailModule", "Encrypt E-Mail"), {},
+ result_cards, info_json)}});
return ret;
}
@@ -1349,53 +1425,68 @@ auto DoEncryptPlainText(int channel, const QStringList& encrypt_keys,
}; // namespace
auto OnEditTabTypeEmailOpEncrypt(const GFEvent& event) -> GFEventResult {
- if (event.Str("body_data").isEmpty()) return GFEventResult::Bad("body_data is empty");
- if (event.Str("channel").isEmpty()) return GFEventResult::Bad("channel is empty");
- if (event.Str("encrypt_keys").isEmpty())
- return GFEventResult::Bad("encrypt_keys is empty");
+ if (event.Str("body_data").isEmpty())
+ return GFEventResult::Bad("body_data is empty");
+ if (event.Str("channel").isEmpty())
+ return GFEventResult::Bad("channel is empty");
+ if (event.Str("encrypt_keys").isEmpty())
+ return GFEventResult::Bad("encrypt_keys is empty");
- auto channel = event.Str("channel").toInt();
- auto encrypt_keys = event.Str("encrypt_keys").split(';');
+ auto channel = event.Str("channel").toInt();
+ auto encrypt_keys = event.Str("encrypt_keys").split(';');
- FLOG_DEBUG("eml encrypt keys: %1", encrypt_keys.join(';'));
+ FLOG_DEBUG("eml encrypt keys: %1", encrypt_keys.join(';'));
- auto body_data =
- QByteArray::fromBase64(QString(event.Str("body_data")).toLatin1());
+ auto body_data =
+ QByteArray::fromBase64(QString(event.Str("body_data")).toLatin1());
- vmime::shared_ptr<vmime::message> message;
- if (CheckIfEMLMessage(body_data, message)) {
- QByteArray eml_data;
- int result_status = 0;
- QString result_detail;
- QString result_cards;
- if (DoEncryptEMLData(channel, encrypt_keys, message, body_data, event,
- result_status, result_detail, result_cards,
- eml_data) != kSUCCESS) {
- return GFEventResult::Deferred();
- }
+ vmime::shared_ptr<vmime::message> message;
+ if (CheckIfEMLMessage(body_data, message)) {
+ QByteArray eml_data;
+ int result_status = 0;
+ QString result_detail;
+ QString result_cards;
+ if (DoEncryptEMLData(channel, encrypt_keys, message, body_data, event,
+ result_status, result_detail, result_cards,
+ eml_data) != kSUCCESS) {
+ return GFEventResult::Deferred();
+ }
- event.Answer().Ok({{"data", eml_data}, {"result", result_detail}, {"result_status", QString::number(result_status)}, {"result_cards", BuildResultCardsParam( QApplication::translate("EMailModule", "Encrypt E-Mail"), BuildRecipientCards(channel, encrypt_keys), result_cards)}});
- return GFEventResult::Deferred();
- }
+ event.Answer().Ok(
+ {{"data", eml_data},
+ {"result", result_detail},
+ {"result_status", QString::number(result_status)},
+ {"result_cards",
+ BuildResultCardsParam(
+ QApplication::translate("EMailModule", "Encrypt E-Mail"),
+ BuildRecipientCards(channel, encrypt_keys), result_cards)}});
+ return GFEventResult::Deferred();
+ }
- // Not a message yet: address it to the keys the user picked to encrypt
- // to, rather than stopping to ask for addresses they have just chosen.
- const auto meta_data = EnvelopeFromKeys(channel, {}, encrypt_keys);
+ // Not a message yet: address it to the keys the user picked to encrypt
+ // to, rather than stopping to ask for addresses they have just chosen.
+ const auto meta_data = EnvelopeFromKeys(channel, {}, encrypt_keys);
- QByteArray eml_data;
- int result_status = 0;
- QString result_detail;
- QString result_cards;
- if (DoEncryptPlainText(channel, encrypt_keys, meta_data, body_data, event,
- result_status, result_detail, result_cards,
- eml_data) != kSUCCESS) {
- return GFEventResult::Deferred();
- }
+ QByteArray eml_data;
+ int result_status = 0;
+ QString result_detail;
+ QString result_cards;
+ if (DoEncryptPlainText(channel, encrypt_keys, meta_data, body_data, event,
+ result_status, result_detail, result_cards,
+ eml_data) != kSUCCESS) {
+ return GFEventResult::Deferred();
+ }
- auto meta_cards = BuildRecipientCards(channel, encrypt_keys);
- meta_cards.prepend(BuildEMailHeaderCard(meta_data));
- event.Answer().Ok({{"data", eml_data}, {"result", result_detail}, {"result_status", QString::number(result_status)}, {"result_cards", BuildResultCardsParam( QApplication::translate("EMailModule", "Encrypt E-Mail"), meta_cards, result_cards)}});
- return GFEventResult::Deferred();
+ auto meta_cards = BuildRecipientCards(channel, encrypt_keys);
+ meta_cards.prepend(BuildEMailHeaderCard(meta_data));
+ event.Answer().Ok({{"data", eml_data},
+ {"result", result_detail},
+ {"result_status", QString::number(result_status)},
+ {"result_cards", BuildResultCardsParam(
+ QApplication::translate(
+ "EMailModule", "Encrypt E-Mail"),
+ meta_cards, result_cards)}});
+ return GFEventResult::Deferred();
}
namespace {
@@ -1501,57 +1592,73 @@ auto DoEncryptSignPlainText(int channel, const QStringList& encrypt_keys,
} // namespace
auto OnEditTabTypeEmailOpEncryptSign(const GFEvent& event) -> GFEventResult {
- if (event.Str("body_data").isEmpty()) return GFEventResult::Bad("body_data is empty");
- if (event.Str("channel").isEmpty()) return GFEventResult::Bad("channel is empty");
- if (event.Str("encrypt_keys").isEmpty())
- return GFEventResult::Bad("encrypt_keys is empty");
- if (event.Str("sign_key").isEmpty()) return GFEventResult::Bad("sign_key is empty");
+ if (event.Str("body_data").isEmpty())
+ return GFEventResult::Bad("body_data is empty");
+ if (event.Str("channel").isEmpty())
+ return GFEventResult::Bad("channel is empty");
+ if (event.Str("encrypt_keys").isEmpty())
+ return GFEventResult::Bad("encrypt_keys is empty");
+ if (event.Str("sign_key").isEmpty())
+ return GFEventResult::Bad("sign_key is empty");
- auto channel = event.Str("channel").toInt();
- auto sign_key = event.Str("sign_key");
- auto encrypt_keys = event.Str("encrypt_keys").split(';');
+ auto channel = event.Str("channel").toInt();
+ auto sign_key = event.Str("sign_key");
+ auto encrypt_keys = event.Str("encrypt_keys").split(';');
- FLOG_DEBUG("eml encrypt keys: %1", encrypt_keys.join(';'));
+ FLOG_DEBUG("eml encrypt keys: %1", encrypt_keys.join(';'));
- auto body_data =
- QByteArray::fromBase64(QString(event.Str("body_data")).toLatin1());
+ auto body_data =
+ QByteArray::fromBase64(QString(event.Str("body_data")).toLatin1());
- vmime::shared_ptr<vmime::message> message;
- if (CheckIfEMLMessage(body_data, message)) {
- QByteArray eml_data;
- int result_status = 0;
- QString result_detail;
- QString result_cards;
- if (DoEncryptSignEMLData(channel, encrypt_keys, sign_key, message,
- body_data, event, result_status, result_detail,
- result_cards, eml_data) != kSUCCESS) {
- return GFEventResult::Deferred();
- }
- event.Answer().Ok({{"data", eml_data}, {"result", result_detail}, {"result_status", QString::number(result_status)}, {"result_cards", BuildResultCardsParam( QApplication::translate("EMailModule", "Encrypt and Sign E-Mail"), BuildRecipientCards(channel, encrypt_keys), result_cards)}});
- return GFEventResult::Deferred();
- }
+ vmime::shared_ptr<vmime::message> message;
+ if (CheckIfEMLMessage(body_data, message)) {
+ QByteArray eml_data;
+ int result_status = 0;
+ QString result_detail;
+ QString result_cards;
+ if (DoEncryptSignEMLData(channel, encrypt_keys, sign_key, message,
+ body_data, event, result_status, result_detail,
+ result_cards, eml_data) != kSUCCESS) {
+ return GFEventResult::Deferred();
+ }
+ event.Answer().Ok(
+ {{"data", eml_data},
+ {"result", result_detail},
+ {"result_status", QString::number(result_status)},
+ {"result_cards",
+ BuildResultCardsParam(
+ QApplication::translate("EMailModule", "Encrypt and Sign E-Mail"),
+ BuildRecipientCards(channel, encrypt_keys), result_cards)}});
+ return GFEventResult::Deferred();
+ }
- // Not a message yet: address it from the signing key to the encryption
- // keys, rather than stopping to ask for what the key list already says.
- const auto meta_data = EnvelopeFromKeys(channel, sign_key, encrypt_keys);
+ // Not a message yet: address it from the signing key to the encryption
+ // keys, rather than stopping to ask for what the key list already says.
+ const auto meta_data = EnvelopeFromKeys(channel, sign_key, encrypt_keys);
- QByteArray eml_data;
- int result_status = 0;
- QString result_detail;
- QString result_cards;
- QByteArray body_data_copy = body_data;
+ QByteArray eml_data;
+ int result_status = 0;
+ QString result_detail;
+ QString result_cards;
+ QByteArray body_data_copy = body_data;
- if (DoEncryptSignPlainText(channel, encrypt_keys, sign_key, meta_data,
- body_data_copy, event, result_status,
- result_detail, result_cards,
- eml_data) != kSUCCESS) {
- return GFEventResult::Deferred();
- }
+ if (DoEncryptSignPlainText(
+ channel, encrypt_keys, sign_key, meta_data, body_data_copy, event,
+ result_status, result_detail, result_cards, eml_data) != kSUCCESS) {
+ return GFEventResult::Deferred();
+ }
- auto meta_cards = BuildRecipientCards(channel, encrypt_keys);
- meta_cards.prepend(BuildEMailHeaderCard(meta_data));
- event.Answer().Ok({{"data", eml_data}, {"result", result_detail}, {"result_status", QString::number(result_status)}, {"result_cards", BuildResultCardsParam( QApplication::translate( "EMailModule", "Encrypt and Sign E-Mail"), meta_cards, result_cards)}});
- return GFEventResult::Deferred();
+ auto meta_cards = BuildRecipientCards(channel, encrypt_keys);
+ meta_cards.prepend(BuildEMailHeaderCard(meta_data));
+ event.Answer().Ok(
+ {{"data", eml_data},
+ {"result", result_detail},
+ {"result_status", QString::number(result_status)},
+ {"result_cards",
+ BuildResultCardsParam(
+ QApplication::translate("EMailModule", "Encrypt and Sign E-Mail"),
+ meta_cards, result_cards)}});
+ return GFEventResult::Deferred();
}
namespace {
@@ -1621,361 +1728,361 @@ auto DoDecryptVerifyEMLData(int channel, const QByteArray& data,
} // namespace
auto OnEditTabTypeEmailOpDecryptVerify(const GFEvent& event) -> GFEventResult {
- if (event.Str("channel").isEmpty()) return GFEventResult::Bad("channel is empty");
- if (event.Str("data").isEmpty()) return GFEventResult::Bad("data is empty");
+ if (event.Str("channel").isEmpty())
+ return GFEventResult::Bad("channel is empty");
+ if (event.Str("data").isEmpty()) return GFEventResult::Bad("data is empty");
- auto channel = event.Str("channel").toInt();
- auto data = QByteArray::fromBase64(QString(event.Str("data")).toLatin1());
+ auto channel = event.Str("channel").toInt();
+ auto data = QByteArray::fromBase64(QString(event.Str("data")).toLatin1());
- auto body_data =
- QByteArray::fromBase64(QString(event.Str("body_data")).toLatin1());
+ auto body_data =
+ QByteArray::fromBase64(QString(event.Str("body_data")).toLatin1());
- QByteArray eml_data;
- EMailMetaData meta_data;
- QString error_string;
- int result_status = 0;
- QString result_detail;
- QString result_cards;
+ QByteArray eml_data;
+ EMailMetaData meta_data;
+ QString error_string;
+ int result_status = 0;
+ QString result_detail;
+ QString result_cards;
- QByteArray decrypt_info_json;
- auto plan = EMailPostDecryptPlan::kVERIFY;
- EMailVerificationResult verification;
- if (DoDecryptVerifyEMLData(channel, data, event, result_status,
- result_detail, result_cards, eml_data,
- error_string, meta_data, decrypt_info_json,
- plan, verification) != kSUCCESS) {
- return GFEventResult::Deferred();
- }
- const bool verified = plan == EMailPostDecryptPlan::kVERIFY;
+ QByteArray decrypt_info_json;
+ auto plan = EMailPostDecryptPlan::kVERIFY;
+ EMailVerificationResult verification;
+ if (DoDecryptVerifyEMLData(channel, data, event, result_status, result_detail,
+ result_cards, eml_data, error_string, meta_data,
+ decrypt_info_json, plan,
+ verification) != kSUCCESS) {
+ return GFEventResult::Deferred();
+ }
+ const bool verified = plan == EMailPostDecryptPlan::kVERIFY;
- QString email_info;
- email_info.append("# E-Mail Information\n\n");
- email_info.append(QString("- %1: %2\n")
- .arg(QApplication::translate("EMailModule", "From"))
- .arg(meta_data.from));
- email_info.append(QString("- %1: %2\n")
- .arg(QApplication::translate("EMailModule", "To"))
- .arg(meta_data.to.join("; ")));
- email_info.append(
- QString("- %1: %2\n")
- .arg(QApplication::translate("EMailModule", "Subject"))
- .arg(meta_data.subject));
- email_info.append(QString("- %1: %2\n")
- .arg(QApplication::translate("EMailModule", "CC"))
- .arg(meta_data.cc.join("; ")));
- email_info.append(QString("- %1: %2\n")
- .arg(QApplication::translate("EMailModule", "BCC"))
- .arg(meta_data.bcc_header.join("; ")));
- email_info.append(QString("- %1: %2\n")
- .arg(QApplication::translate("EMailModule", "Date"))
- .arg(QLocale().toString(meta_data.datetime)));
+ QString email_info;
+ email_info.append("# E-Mail Information\n\n");
+ email_info.append(QString("- %1: %2\n")
+ .arg(QApplication::translate("EMailModule", "From"))
+ .arg(meta_data.from));
+ email_info.append(QString("- %1: %2\n")
+ .arg(QApplication::translate("EMailModule", "To"))
+ .arg(meta_data.to.join("; ")));
+ email_info.append(QString("- %1: %2\n")
+ .arg(QApplication::translate("EMailModule", "Subject"))
+ .arg(meta_data.subject));
+ email_info.append(QString("- %1: %2\n")
+ .arg(QApplication::translate("EMailModule", "CC"))
+ .arg(meta_data.cc.join("; ")));
+ email_info.append(QString("- %1: %2\n")
+ .arg(QApplication::translate("EMailModule", "BCC"))
+ .arg(meta_data.bcc_header.join("; ")));
+ email_info.append(QString("- %1: %2\n")
+ .arg(QApplication::translate("EMailModule", "Date"))
+ .arg(QLocale().toString(meta_data.datetime)));
- email_info.append("\n");
+ email_info.append("\n");
- email_info.append("# OpenPGP Information\n\n");
+ email_info.append("# OpenPGP Information\n\n");
- // Only when something actually verified. An unsigned message has no
- // signed entity and no declared hash, and printing those labels with
- // nothing after them reads as a missing answer rather than as the
- // absence of a question.
- if (!verified) {
- email_info.append(QString("- %1\n").arg(QApplication::translate(
- "EMailModule",
- "This message was decrypted. It carries no signature, so nothing "
- "here says who sent it.")));
- } else {
- email_info.append(
- QString("- %1: %2\n")
- .arg(QApplication::translate(
- "EMailModule", "Digest of Signed MIME Entity (SHA-256)"))
- .arg(meta_data.signed_entity_digest));
- email_info.append(
- QString("- %1: %2\n")
- .arg(QApplication::translate(
- "EMailModule", "Declared Signature Hash (micalg)"))
- .arg(meta_data.micalg));
- }
+ // Only when something actually verified. An unsigned message has no
+ // signed entity and no declared hash, and printing those labels with
+ // nothing after them reads as a missing answer rather than as the
+ // absence of a question.
+ if (!verified) {
+ email_info.append(QString("- %1\n").arg(QApplication::translate(
+ "EMailModule",
+ "This message was decrypted. It carries no signature, so nothing "
+ "here says who sent it.")));
+ } else {
+ email_info.append(
+ QString("- %1: %2\n")
+ .arg(QApplication::translate(
+ "EMailModule", "Digest of Signed MIME Entity (SHA-256)"))
+ .arg(meta_data.signed_entity_digest));
+ email_info.append(
+ QString("- %1: %2\n")
+ .arg(QApplication::translate("EMailModule",
+ "Declared Signature Hash (micalg)"))
+ .arg(meta_data.micalg));
+ }
- // Without this, a message whose line endings were rewritten after
- // signing reads exactly like a forged one, and the user has no way to
- // tell the difference or to know that importing a key cannot help.
- if (meta_data.signed_entity_non_canonical) {
- email_info.append(QString("- %1\n").arg(QApplication::translate(
- "EMailModule",
- "**Note**: the signed part is not in canonical form, "
- "because its line endings are not CRLF. Something rewrote "
- "this message after it was signed, which is usually a "
- "program that changed line endings while saving or "
- "copying it. A signature cannot verify against these "
- "bytes, and importing the sender's key will not change "
- "that.")));
- }
+ // Without this, a message whose line endings were rewritten after
+ // signing reads exactly like a forged one, and the user has no way to
+ // tell the difference or to know that importing a key cannot help.
+ if (meta_data.signed_entity_non_canonical) {
+ email_info.append(QString("- %1\n").arg(QApplication::translate(
+ "EMailModule",
+ "**Note**: the signed part is not in canonical form, "
+ "because its line endings are not CRLF. Something rewrote "
+ "this message after it was signed, which is usually a "
+ "program that changed line endings while saving or "
+ "copying it. A signature cannot verify against these "
+ "bytes, and importing the sender's key will not change "
+ "that.")));
+ }
- email_info.append("\n");
+ email_info.append("\n");
- email_info.append("#" + result_detail + "\n");
+ email_info.append("#" + result_detail + "\n");
- auto dv_meta_cards = BuildReadMetaCards(meta_data, verified);
- const auto dv_recipient_card =
- BuildRecipientCheckCard(meta_data, decrypt_info_json);
- if (!dv_recipient_card.isEmpty()) dv_meta_cards.append(dv_recipient_card);
+ auto dv_meta_cards = BuildReadMetaCards(meta_data, verified);
+ const auto dv_recipient_card =
+ BuildRecipientCheckCard(meta_data, decrypt_info_json);
+ if (!dv_recipient_card.isEmpty()) dv_meta_cards.append(dv_recipient_card);
- // The same reason the Verify board gives, when a verification actually
- // happened. A message that carried no signature is not a verification
- // outcome at all, and the note above already says so.
- const auto result_cards_param = BuildResultCardsParam(
- QApplication::translate("EMailModule", "Decrypt and Verify E-Mail"),
- dv_meta_cards, result_cards, verification.report_info_json,
- verified ? ReportDescriptionFor(verification) : QString());
+ // The same reason the Verify board gives, when a verification actually
+ // happened. A message that carried no signature is not a verification
+ // outcome at all, and the note above already says so.
+ const auto result_cards_param = BuildResultCardsParam(
+ QApplication::translate("EMailModule", "Decrypt and Verify E-Mail"),
+ dv_meta_cards, result_cards, verification.report_info_json,
+ verified ? ReportDescriptionFor(verification) : QString());
- // callback
- event.Answer().Ok({{"data", eml_data}, {"result_status", QString::number(result_status)}, {"result", email_info}, {"result_cards", result_cards_param}});
- return GFEventResult::Deferred();
+ // callback
+ event.Answer().Ok({{"data", eml_data},
+ {"result_status", QString::number(result_status)},
+ {"result", email_info},
+ {"result_cards", result_cards_param}});
+ return GFEventResult::Deferred();
}
auto OnEditTabTypeEmailOpSaveFile(const GFEvent& event) -> GFEventResult {
- if (event.Str("page").isEmpty()) return GFEventResult::Bad("page is empty");
+ if (event.Str("page").isEmpty()) return GFEventResult::Bad("page is empty");
- auto* page = GFUIObject<QWidget>(event.Str("page"));
- if (!page) {
- LOG_ERROR("page handler is not a QWidget");
- return GFEventResult::Bad("page handle invalid or not QMainWindow");
- }
+ auto* page = GFUIObject<QWidget>(event.Str("page"));
+ if (!page) {
+ LOG_ERROR("page handler is not a QWidget");
+ return GFEventResult::Bad("page handle invalid or not QMainWindow");
+ }
- auto* tab_widget = GFUIObject<QTabWidget>(event.Str("tab_widget"));
- if (!tab_widget) {
- LOG_ERROR("tab widget handler is not a QTabWidget");
- return GFEventResult::Bad("main_window handle invalid or not QMainWindow");
- }
+ auto* tab_widget = GFUIObject<QTabWidget>(event.Str("tab_widget"));
+ if (!tab_widget) {
+ LOG_ERROR("tab widget handler is not a QTabWidget");
+ return GFEventResult::Bad("main_window handle invalid or not QMainWindow");
+ }
- QString filename;
+ QString filename;
- auto ok = QMetaObject::invokeMethod(page, "GetFilePath",
- Qt::BlockingQueuedConnection,
- Q_RETURN_ARG(QString, filename));
+ auto ok = QMetaObject::invokeMethod(page, "GetFilePath",
+ Qt::BlockingQueuedConnection,
+ Q_RETURN_ARG(QString, filename));
- if (!ok) {
- LOG_ERROR("invoke GetFilePath failed");
- return GFEventResult::Bad("invoke GetFilePath failed");
- }
+ if (!ok) {
+ LOG_ERROR("invoke GetFilePath failed");
+ return GFEventResult::Bad("invoke GetFilePath failed");
+ }
- if (filename.isEmpty()) {
- auto ok = QMetaObject::invokeMethod(
- QCoreApplication::instance(),
- [&]() -> void {
- // Named after the message rather than left blank. The view is
- // the only thing that knows the subject, and it is reached the
- // same way the rest of this module reaches it.
- QString suggested;
- if (auto* view = page->findChild<EMailPageView*>();
- view != nullptr) {
- suggested = view->SuggestedFileName();
- }
- if (suggested.isEmpty())
- suggested = QStringLiteral("untitled.eml");
+ if (filename.isEmpty()) {
+ auto ok = QMetaObject::invokeMethod(
+ QCoreApplication::instance(),
+ [&]() -> void {
+ // Named after the message rather than left blank. The view is
+ // the only thing that knows the subject, and it is reached the
+ // same way the rest of this module reaches it.
+ QString suggested;
+ if (auto* view = page->findChild<EMailPageView*>(); view != nullptr) {
+ suggested = view->SuggestedFileName();
+ }
+ if (suggested.isEmpty()) suggested = QStringLiteral("untitled.eml");
- filename = QFileDialog::getSaveFileName(
- page, QApplication::translate("EMailModule", "Save file"),
- QDir(default_save_dir()).filePath(suggested),
- QApplication::translate("EMailModule",
- "E-Mail Message (*.eml);;All Files "
- "(*)"));
- },
- Qt::BlockingQueuedConnection);
+ filename = QFileDialog::getSaveFileName(
+ page, QApplication::translate("EMailModule", "Save file"),
+ QDir(default_save_dir()).filePath(suggested),
+ QApplication::translate("EMailModule",
+ "E-Mail Message (*.eml);;All Files "
+ "(*)"));
+ },
+ Qt::BlockingQueuedConnection);
- if (!ok) {
- LOG_ERROR("invoke getSaveFileName failed");
- return GFEventResult::Bad("invoke getSaveFileName failed");
- }
- }
+ if (!ok) {
+ LOG_ERROR("invoke getSaveFileName failed");
+ return GFEventResult::Bad("invoke getSaveFileName failed");
+ }
+ }
- if (filename.isEmpty()) {
- LOG_INFO("user cancelled to select file to save");
- return GFEventResult::Ok();
- }
+ if (filename.isEmpty()) {
+ LOG_INFO("user cancelled to select file to save");
+ return GFEventResult::Ok();
+ }
- QFileInfo file_info(filename);
- if (file_info.suffix().toLower() != "eml") {
- file_info.setFile(file_info.path(),
- file_info.completeBaseName() + ".eml");
- filename = file_info.absoluteFilePath();
- FLOG_DEBUG("append .eml suffix to filename: %1", filename);
- }
+ QFileInfo file_info(filename);
+ if (file_info.suffix().toLower() != "eml") {
+ file_info.setFile(file_info.path(), file_info.completeBaseName() + ".eml");
+ filename = file_info.absoluteFilePath();
+ FLOG_DEBUG("append .eml suffix to filename: %1", filename);
+ }
- QPlainTextEdit* text_edit = nullptr;
- ok = QMetaObject::invokeMethod(page, "GetTextPage",
- Qt::BlockingQueuedConnection,
- Q_RETURN_ARG(QPlainTextEdit*, text_edit));
- if (!ok || text_edit == nullptr) {
- LOG_ERROR("invoke GetTextPage failed");
- return GFEventResult::Bad("invoke GetTextPage failed");
- }
+ QPlainTextEdit* text_edit = nullptr;
+ ok = QMetaObject::invokeMethod(page, "GetTextPage",
+ Qt::BlockingQueuedConnection,
+ Q_RETURN_ARG(QPlainTextEdit*, text_edit));
+ if (!ok || text_edit == nullptr) {
+ LOG_ERROR("invoke GetTextPage failed");
+ return GFEventResult::Bad("invoke GetTextPage failed");
+ }
- // Reading a QTextDocument is a GUI-thread operation, and the user may
- // be typing into this one. Only the read hops over; everything done to
- // the text afterwards is ordinary work on a copy.
- QString text;
- RunOnGui([&]() { text = text_edit->toPlainText(); });
+ // Reading a QTextDocument is a GUI-thread operation, and the user may
+ // be typing into this one. Only the read hops over; everything done to
+ // the text afterwards is ordinary work on a copy.
+ QString text;
+ RunOnGui([&]() { text = text_edit->toPlainText(); });
- // Normalize to LF first: the editor may already hold CRLF, and blindly
- // expanding every "\n" then turns each of those into CRCRLF.
- text.replace("\r\n", "\n");
- text.replace("\n", "\r\n");
+ // Normalize to LF first: the editor may already hold CRLF, and blindly
+ // expanding every "\n" then turns each of those into CRCRLF.
+ text.replace("\r\n", "\n");
+ text.replace("\n", "\r\n");
- const auto bytes = text.toUtf8();
+ const auto bytes = text.toUtf8();
- // Last look before the bytes leave. Deliberately after the content is
- // assembled and before anything is written, so what is checked is
- // exactly what would be saved.
- //
- // The inspection runs HERE, on the module thread: it parses and walks a
- // message of whatever size the user has composed, and that is not work
- // to hand the GUI thread. Only the question that follows is a dialog.
- const auto check = CheckBeforeExport(bytes);
- if (!ConfirmExport(page, check)) {
- LOG_INFO("user cancelled the save after the export check");
- return GFEventResult::Ok();
- }
+ // Last look before the bytes leave. Deliberately after the content is
+ // assembled and before anything is written, so what is checked is
+ // exactly what would be saved.
+ //
+ // The inspection runs HERE, on the module thread: it parses and walks a
+ // message of whatever size the user has composed, and that is not work
+ // to hand the GUI thread. Only the question that follows is a dialog.
+ const auto check = CheckBeforeExport(bytes);
+ if (!ConfirmExport(page, check)) {
+ LOG_INFO("user cancelled the save after the export check");
+ return GFEventResult::Ok();
+ }
- // Written binary and through QSaveFile: QIODevice::Text would translate
- // the line endings a second time on Windows, and a plain QFile leaves a
- // truncated .eml behind if the write fails halfway.
- QSaveFile file(filename);
- if (!file.open(QIODevice::WriteOnly)) {
- WarnOnGui(page, QApplication::translate("EMailModule",
- "Cannot write file %1:\n%2.")
- .arg(filename)
- .arg(file.errorString()));
- return GFEventResult::Bad("cannot open file for writing");
- }
+ // Written binary and through QSaveFile: QIODevice::Text would translate
+ // the line endings a second time on Windows, and a plain QFile leaves a
+ // truncated .eml behind if the write fails halfway.
+ QSaveFile file(filename);
+ if (!file.open(QIODevice::WriteOnly)) {
+ WarnOnGui(page, QApplication::translate("EMailModule",
+ "Cannot write file %1:\n%2.")
+ .arg(filename)
+ .arg(file.errorString()));
+ return GFEventResult::Bad("cannot open file for writing");
+ }
- RunOnGui([]() { QApplication::setOverrideCursor(Qt::WaitCursor); });
- const bool written = file.write(bytes) == bytes.size() && file.commit();
- RunOnGui([]() { QApplication::restoreOverrideCursor(); });
+ RunOnGui([]() { QApplication::setOverrideCursor(Qt::WaitCursor); });
+ const bool written = file.write(bytes) == bytes.size() && file.commit();
+ RunOnGui([]() { QApplication::restoreOverrideCursor(); });
- if (!written) {
- WarnOnGui(page, QApplication::translate("EMailModule",
- "Cannot write file %1:\n%2.")
- .arg(filename)
- .arg(file.errorString()));
- return GFEventResult::Bad("writing file failed");
- }
+ if (!written) {
+ WarnOnGui(page, QApplication::translate("EMailModule",
+ "Cannot write file %1:\n%2.")
+ .arg(filename)
+ .arg(file.errorString()));
+ return GFEventResult::Bad("writing file failed");
+ }
- // The document's modified flag and the tab's label are widget state, and
- // the two belong together: a tab renamed without its flag cleared, or the
- // reverse, is a half-saved file as far as the user can see.
- const auto shown = QFileInfo(filename).fileName();
- RunOnGui([&]() {
- text_edit->document()->setModified(false);
- tab_widget->setTabText(tab_widget->currentIndex(), shown);
- });
+ // The document's modified flag and the tab's label are widget state, and
+ // the two belong together: a tab renamed without its flag cleared, or the
+ // reverse, is a half-saved file as far as the user can see.
+ const auto shown = QFileInfo(filename).fileName();
+ RunOnGui([&]() {
+ text_edit->document()->setModified(false);
+ tab_widget->setTabText(tab_widget->currentIndex(), shown);
+ });
- QMetaObject::invokeMethod(page, "SetFilePath",
- Qt::BlockingQueuedConnection,
- Q_ARG(QString, filename));
- QMetaObject::invokeMethod(page, "NotifyFileSaved",
- Qt::BlockingQueuedConnection);
- return GFEventResult::Deferred();
+ QMetaObject::invokeMethod(page, "SetFilePath", Qt::BlockingQueuedConnection,
+ Q_ARG(QString, filename));
+ QMetaObject::invokeMethod(page, "NotifyFileSaved",
+ Qt::BlockingQueuedConnection);
+ return GFEventResult::Deferred();
}
auto OnFileExtEmailOpOpenFile(const GFEvent& event) -> GFEventResult {
- if (event.Str("file_path").isEmpty()) return GFEventResult::Bad("file_path is empty");
+ if (event.Str("file_path").isEmpty())
+ return GFEventResult::Bad("file_path is empty");
- auto file_path = event.Str("file_path");
+ auto file_path = event.Str("file_path");
- // Read HERE, on the module thread, and through the one helper that knows
- // the guards. This is file IO, which is precisely the work not to hand
- // the GUI thread -- and the kind of file has to be settled before the
- // read, because a FIFO, a device node or a /proc entry reports a size of
- // 0 and would then block forever or grow without bound inside it.
- QByteArray raw;
- QString read_error;
- qint64 file_size = 0;
- const auto admission = ReadFileWithin(file_path, kMaxEMLFileSize, raw,
- read_error, file_size);
+ // Read HERE, on the module thread, and through the one helper that knows
+ // the guards. This is file IO, which is precisely the work not to hand
+ // the GUI thread -- and the kind of file has to be settled before the
+ // read, because a FIFO, a device node or a /proc entry reports a size of
+ // 0 and would then block forever or grow without bound inside it.
+ QByteArray raw;
+ QString read_error;
+ qint64 file_size = 0;
+ const auto admission =
+ ReadFileWithin(file_path, kMaxEMLFileSize, raw, read_error, file_size);
- if (admission == EMailFileAdmission::kNOT_REGULAR) {
- WarnOnGui(nullptr,
- QApplication::translate(
- "EMailModule",
- "%1 is not an ordinary file, so it cannot be opened as a "
- "message.")
- .arg(file_path));
- return GFEventResult::Bad("not a regular file");
- }
+ if (admission == EMailFileAdmission::kNOT_REGULAR) {
+ WarnOnGui(nullptr,
+ QApplication::translate(
+ "EMailModule",
+ "%1 is not an ordinary file, so it cannot be opened as a "
+ "message.")
+ .arg(file_path));
+ return GFEventResult::Bad("not a regular file");
+ }
- if (admission == EMailFileAdmission::kTOO_LARGE) {
- WarnOnGui(nullptr,
- QApplication::translate(
- "EMailModule",
- "The file %1 is too large (%2) to be opened. The maximum "
- "allowed size is %3.")
- .arg(file_path)
- .arg(QLocale().formattedDataSize(file_size))
- .arg(QLocale().formattedDataSize(kMaxEMLFileSize)));
- return GFEventResult::Bad("file too large");
- }
+ if (admission == EMailFileAdmission::kTOO_LARGE) {
+ WarnOnGui(nullptr,
+ QApplication::translate(
+ "EMailModule",
+ "The file %1 is too large (%2) to be opened. The maximum "
+ "allowed size is %3.")
+ .arg(file_path)
+ .arg(QLocale().formattedDataSize(file_size))
+ .arg(QLocale().formattedDataSize(kMaxEMLFileSize)));
+ return GFEventResult::Bad("file too large");
+ }
- if (admission != EMailFileAdmission::kOK) {
- WarnOnGui(nullptr, QApplication::translate("EMailModule",
- "Cannot read file %1:\n%2.")
- .arg(file_path)
- .arg(read_error));
- return GFEventResult::Bad("cannot read file");
- }
+ if (admission != EMailFileAdmission::kOK) {
+ WarnOnGui(nullptr, QApplication::translate("EMailModule",
+ "Cannot read file %1:\n%2.")
+ .arg(file_path)
+ .arg(read_error));
+ return GFEventResult::Bad("cannot read file");
+ }
- auto* edit = GFUIObject<QWidget>("main_window_edit");
- if (!edit) {
- LOG_ERROR(
- "main window menu mounted: main_window_edit "
- "handle invalid or not "
- "QWidget");
- return GFEventResult::Bad("main_window_edit handle invalid or not "
- "QWidget");
- }
+ auto* edit = GFUIObject<QWidget>("main_window_edit");
+ if (!edit) {
+ LOG_ERROR(
+ "main window menu mounted: main_window_edit "
+ "handle invalid or not "
+ "QWidget");
+ return GFEventResult::Bad(
+ "main_window_edit handle invalid or not "
+ "QWidget");
+ }
- // Only the tab is built on the GUI thread now: the bytes are already in
- // hand, so nothing here reads a file or blocks on one.
- QMetaObject::invokeMethod(QCoreApplication::instance(), [=]() -> void {
- QWidget* page = nullptr;
+ // Only the tab is built on the GUI thread now: the bytes are already in
+ // hand, so nothing here reads a file or blocks on one.
+ QMetaObject::invokeMethod(QCoreApplication::instance(), [=]() -> void {
+ QWidget* page = nullptr;
- auto ok = QMetaObject::invokeMethod(
- edit, "SlotNewCustomTab", Qt::DirectConnection,
- Q_RETURN_ARG(QWidget*, page), Q_ARG(QString, "email"),
- Q_ARG(QString, QFileInfo(file_path).fileName()),
- Q_ARG(QIcon, QIcon(":/icons/email.png")),
- Q_ARG(QString, ":/icons/email.png"));
+ auto ok = QMetaObject::invokeMethod(
+ edit, "SlotNewCustomTab", Qt::DirectConnection,
+ Q_RETURN_ARG(QWidget*, page), Q_ARG(QString, "email"),
+ Q_ARG(QString, QFileInfo(file_path).fileName()),
+ Q_ARG(QIcon, QIcon(":/icons/email.png")),
+ Q_ARG(QString, ":/icons/email.png"));
- if (!ok || !page) {
- LOG_ERROR("create new email tab page failed");
- event.Answer().Fail("create new email tab page failed");
- return;
- }
+ if (!ok || !page) {
+ LOG_ERROR("create new email tab page failed");
+ event.Answer().Fail("create new email tab page failed");
+ return;
+ }
- QPlainTextEdit* text_edit = nullptr;
- ok =
- QMetaObject::invokeMethod(page, "GetTextPage", Qt::DirectConnection,
- Q_RETURN_ARG(QPlainTextEdit*, text_edit));
- if (!ok || text_edit == nullptr) {
- LOG_ERROR("invoke GetTextPage failed");
- event.Answer().Fail("invoke GetTextPage failed");
- return;
- }
+ QPlainTextEdit* text_edit = nullptr;
+ ok = QMetaObject::invokeMethod(page, "GetTextPage", Qt::DirectConnection,
+ Q_RETURN_ARG(QPlainTextEdit*, text_edit));
+ if (!ok || text_edit == nullptr) {
+ LOG_ERROR("invoke GetTextPage failed");
+ event.Answer().Fail("invoke GetTextPage failed");
+ return;
+ }
- // Handed over as bytes so the page can record which line endings the
- // message arrived with and reproduce them when it is read back or
- // saved. Falls back to the old path on a host that does not offer
- // this, where the endings are lost exactly as they were before.
- if (!QMetaObject::invokeMethod(page, "SetContentFromBytes",
- Qt::DirectConnection,
- Q_ARG(QByteArray, raw))) {
- text_edit->setPlainText(QString::fromUtf8(raw));
- text_edit->document()->setModified(false);
- }
+ // Handed over as bytes so the page can record which line endings the
+ // message arrived with and reproduce them when it is read back or
+ // saved. Falls back to the old path on a host that does not offer
+ // this, where the endings are lost exactly as they were before.
+ if (!QMetaObject::invokeMethod(page, "SetContentFromBytes",
+ Qt::DirectConnection,
+ Q_ARG(QByteArray, raw))) {
+ text_edit->setPlainText(QString::fromUtf8(raw));
+ text_edit->document()->setModified(false);
+ }
- QMetaObject::invokeMethod(page, "SetFilePath", Qt::DirectConnection,
- Q_ARG(QString, file_path));
- });
+ QMetaObject::invokeMethod(page, "SetFilePath", Qt::DirectConnection,
+ Q_ARG(QString, file_path));
+ });
return GFEventResult::Deferred();
}