summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMinijackson <minijackson@riseup.net>2018-03-02 11:37:28 +0100
committerMinijackson <minijackson@riseup.net>2018-03-08 12:04:48 +0100
commitbcdaa0e86d565ed1623ee217cde3cb8605dad145 (patch)
tree95d5a64069aa278e3717702744da1ba40ac58061
parent1424927cb9a0f5fe79ff5d62da1aa452601a41e9 (diff)
downloadkube-bcdaa0e86d565ed1623ee217cde3cb8605dad145.tar.gz
kube-bcdaa0e86d565ed1623ee217cde3cb8605dad145.zip
Support encrypted mail forwarding
-rw-r--r--framework/src/domain/composercontroller.cpp25
-rw-r--r--framework/src/domain/mime/mailtemplates.cpp83
2 files changed, 92 insertions, 16 deletions
diff --git a/framework/src/domain/composercontroller.cpp b/framework/src/domain/composercontroller.cpp
index 09d4c154..5581dfa9 100644
--- a/framework/src/domain/composercontroller.cpp
+++ b/framework/src/domain/composercontroller.cpp
@@ -99,19 +99,21 @@ class AddresseeController : public Kube::ListPropertyController
99public: 99public:
100 100
101 bool mFoundAllKeys = true; 101 bool mFoundAllKeys = true;
102
102 QSet<QByteArray> mMissingKeys; 103 QSet<QByteArray> mMissingKeys;
103 AddresseeController() 104 AddresseeController() : Kube::ListPropertyController{{"name", "keyFound", "key"}}
104 : Kube::ListPropertyController{{"name", "keyFound", "key"}}
105 { 105 {
106 QObject::connect(this, &Kube::ListPropertyController::added, this, [this] (const QByteArray &id, const QVariantMap &map) { 106 setProperty("foundAllKeys", true);
107 findKey(id, map.value("name").toString()); 107
108 }); 108 QObject::connect(
109 this, &Kube::ListPropertyController::added, this, [this](const QByteArray &id, const QVariantMap &map) {
110 findKey(id, map.value("name").toString());
111 });
112
109 QObject::connect(this, &Kube::ListPropertyController::removed, this, [this] (const QByteArray &id) { 113 QObject::connect(this, &Kube::ListPropertyController::removed, this, [this] (const QByteArray &id) {
110 mMissingKeys.remove(id); 114 mMissingKeys.remove(id);
111 setFoundAllKeys(mMissingKeys.isEmpty()); 115 setFoundAllKeys(mMissingKeys.isEmpty());
112 }); 116 });
113
114
115 } 117 }
116 118
117 bool foundAllKeys() 119 bool foundAllKeys()
@@ -133,12 +135,13 @@ public:
133 mb.fromUnicodeString(addressee); 135 mb.fromUnicodeString(addressee);
134 136
135 SinkLog() << "Searching key for: " << mb.address(); 137 SinkLog() << "Searching key for: " << mb.address();
136 asyncRun<std::vector<GpgME::Key>>(this, [mb] { 138 asyncRun<std::vector<GpgME::Key>>(this,
139 [mb] {
137 return MailCrypto::findKeys(QStringList{} << mb.address(), false, false, MailCrypto::OPENPGP); 140 return MailCrypto::findKeys(QStringList{} << mb.address(), false, false, MailCrypto::OPENPGP);
138 }, 141 },
139 [this, addressee, id](const std::vector<GpgME::Key> &keys) { 142 [this, addressee, id](const std::vector<GpgME::Key> &keys) {
140 if (!keys.empty()) { 143 if (!keys.empty()) {
141 if (keys.size() > 1 ) { 144 if (keys.size() > 1) {
142 SinkWarning() << "Found more than one key, encrypting to all of them."; 145 SinkWarning() << "Found more than one key, encrypting to all of them.";
143 } 146 }
144 SinkLog() << "Found key: " << keys.front().primaryFingerprint(); 147 SinkLog() << "Found key: " << keys.front().primaryFingerprint();
@@ -149,12 +152,14 @@ public:
149 } else { 152 } else {
150 SinkWarning() << "Failed to find key for recipient."; 153 SinkWarning() << "Failed to find key for recipient.";
151 } 154 }
155
156 setProperty("foundAllKeys", mMissingKeys.isEmpty());
152 }); 157 });
153 } 158 }
154 159
155 void set(const QStringList &list) 160 void set(const QStringList &list)
156 { 161 {
157 for (const auto &email: list) { 162 for (const auto &email : list) {
158 add({{"name", email}}); 163 add({{"name", email}});
159 } 164 }
160 } 165 }
diff --git a/framework/src/domain/mime/mailtemplates.cpp b/framework/src/domain/mime/mailtemplates.cpp
index 8e644b34..513f0353 100644
--- a/framework/src/domain/mime/mailtemplates.cpp
+++ b/framework/src/domain/mime/mailtemplates.cpp
@@ -53,6 +53,18 @@ static bool operator==(const KMime::Types::Mailbox &left, const KMime::Types::Ma
53 return (left.addrSpec().asString() == right.addrSpec().asString()); 53 return (left.addrSpec().asString() == right.addrSpec().asString());
54} 54}
55 } 55 }
56
57 Message* contentToMessage(Content* content) {
58 content->assemble();
59 const auto encoded = content->encodedContent();
60
61 auto message = new Message();
62 message->setContent(encoded);
63 message->parse();
64
65 return message;
66 }
67
56} 68}
57 69
58static KMime::Types::Mailbox::List stripMyAddressesFromAddressList(const KMime::Types::Mailbox::List &list, const KMime::Types::AddrSpecList me) 70static KMime::Types::Mailbox::List stripMyAddressesFromAddressList(const KMime::Types::Mailbox::List &list, const KMime::Types::AddrSpecList me)
@@ -223,6 +235,19 @@ KMime::Content *createMultipartAlternativeContent(const QString &plainBody, cons
223 return multipartAlternative; 235 return multipartAlternative;
224} 236}
225 237
238KMime::Message *createMultipartMixedContent(QVector<KMime::Content *> contents)
239{
240 KMime::Message *multiPartMixed = new KMime::Message();
241 multiPartMixed->contentType()->setMimeType("multipart/mixed");
242 multiPartMixed->contentType()->setBoundary(KMime::multiPartBoundary());
243
244 for (const auto &content : contents) {
245 multiPartMixed->addContent(content);
246 }
247
248 return multiPartMixed;
249}
250
226void addProcessedBodyToMessage(const KMime::Message::Ptr &msg, const QString &plainBody, const QString &htmlBody, bool forward) 251void addProcessedBodyToMessage(const KMime::Message::Ptr &msg, const QString &plainBody, const QString &htmlBody, bool forward)
227{ 252{
228 //FIXME 253 //FIXME
@@ -864,27 +889,73 @@ void MailTemplates::reply(const KMime::Message::Ptr &origMsg, const std::functio
864 }); 889 });
865} 890}
866 891
867void MailTemplates::forward(const KMime::Message::Ptr &origMsg, const std::function<void(const KMime::Message::Ptr &result)> &callback) 892void MailTemplates::forward(const KMime::Message::Ptr &origMsg,
893 const std::function<void(const KMime::Message::Ptr &result)> &callback)
868{ 894{
869 KMime::Message::Ptr wrapperMsg(new KMime::Message); 895 KMime::Message::Ptr wrapperMsg(new KMime::Message);
870 896
871 wrapperMsg->to()->clear(); 897 wrapperMsg->to()->clear();
872 wrapperMsg->cc()->clear(); 898 wrapperMsg->cc()->clear();
873 899
874 wrapperMsg->subject()->fromUnicodeString(forwardSubject(origMsg->subject()->asUnicodeString()), "utf-8"); 900 // Decrypt the original message, it will be encrypted again in the composer
901 // for the right recipient
902 KMime::Message::Ptr forwardedMessage;
903 if (isEncrypted(origMsg.data())) {
904 qDebug() << "Original message was encrypted, decrypting it";
905 MimeTreeParser::ObjectTreeParser otp;
906 otp.parseObjectTree(origMsg.data());
907 otp.decryptParts();
875 908
876 const QByteArray refStr = getRefStr(origMsg); 909 auto htmlContent = otp.htmlContent();
910 KMime::Content *recreatedMsg =
911 htmlContent.isEmpty() ? createPlainPartContent(otp.plainTextContent()) :
912 createMultipartAlternativeContent(otp.plainTextContent(), htmlContent);
913
914 if (hasAttachment(origMsg.data())) {
915 QVector<KMime::Content *> contents = {recreatedMsg};
916 contents.append(origMsg->attachments());
917
918 auto msg = createMultipartMixedContent(contents);
919
920 forwardedMessage.reset(KMime::contentToMessage(msg));
921 } else {
922 forwardedMessage.reset(KMime::contentToMessage(recreatedMsg));
923 }
924
925 forwardedMessage->subject()->from7BitString(origMsg->subject()->as7BitString());
926
927 for (const auto &addr : origMsg->to()->mailboxes()) {
928 forwardedMessage->to()->addAddress(addr);
929 }
930
931 for (const auto &addr : origMsg->cc()->mailboxes()) {
932 forwardedMessage->cc()->addAddress(addr);
933 }
934
935 for (const auto &addr : origMsg->bcc()->mailboxes()) {
936 forwardedMessage->bcc()->addAddress(addr);
937 }
938
939 } else {
940 qDebug() << "Original message was not encrypted, using it as-is";
941 forwardedMessage = origMsg;
942 }
943
944 wrapperMsg->subject()->fromUnicodeString(
945 forwardSubject(forwardedMessage->subject()->asUnicodeString()), "utf-8");
946
947 const QByteArray refStr = getRefStr(forwardedMessage);
877 if (!refStr.isEmpty()) { 948 if (!refStr.isEmpty()) {
878 wrapperMsg->references()->fromUnicodeString(QString::fromLocal8Bit(refStr), "utf-8"); 949 wrapperMsg->references()->fromUnicodeString(QString::fromLocal8Bit(refStr), "utf-8");
879 } 950 }
880 951
881 KMime::Content* fwdAttachment = new KMime::Content; 952 KMime::Content *fwdAttachment = new KMime::Content;
882 953
883 fwdAttachment->contentDisposition()->setDisposition(KMime::Headers::CDinline); 954 fwdAttachment->contentDisposition()->setDisposition(KMime::Headers::CDinline);
884 fwdAttachment->contentType()->setMimeType("message/rfc822"); 955 fwdAttachment->contentType()->setMimeType("message/rfc822");
885 fwdAttachment->contentDisposition()->setFilename(origMsg->subject()->asUnicodeString() + ".eml"); 956 fwdAttachment->contentDisposition()->setFilename(forwardedMessage->subject()->asUnicodeString() + ".eml");
886 // The mail was parsed in loadMessage before, so no need to assemble it 957 // The mail was parsed in loadMessage before, so no need to assemble it
887 fwdAttachment->setBody(origMsg->encodedContent()); 958 fwdAttachment->setBody(forwardedMessage->encodedContent());
888 959
889 wrapperMsg->addContent(fwdAttachment); 960 wrapperMsg->addContent(fwdAttachment);
890 wrapperMsg->assemble(); 961 wrapperMsg->assemble();