File indexing completed on 2024-12-15 04:52:24
0001 /* 0002 Copyright (c) 2018 Christian Mollekopf <mollekopf@kolabsys.com> 0003 0004 This library is free software; you can redistribute it and/or modify it 0005 under the terms of the GNU Library General Public License as published by 0006 the Free Software Foundation; either version 2 of the License, or (at your 0007 option) any later version. 0008 0009 This library is distributed in the hope that it will be useful, but WITHOUT 0010 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 0011 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 0012 License for more details. 0013 0014 You should have received a copy of the GNU Library General Public License 0015 along with this library; see the file COPYING.LIB. If not, write to the 0016 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 0017 02110-1301, USA. 0018 */ 0019 #include "extensionapi.h" 0020 0021 #include <KMime/KMimeMessage> 0022 #include <QStandardPaths> 0023 #include <QDataStream> 0024 #include <QSettings> 0025 #include <QVariantMap> 0026 #include <QVariant> 0027 #include <QMap> 0028 0029 #include <sink/store.h> 0030 #include <sink/log.h> 0031 0032 #include <mailtemplates.h> 0033 #include <sink/crypto.h> 0034 0035 static void send(const QByteArray &message, const QByteArray &accountId) 0036 { 0037 using namespace Sink; 0038 using namespace Sink::ApplicationDomain; 0039 0040 Q_ASSERT(!accountId.isEmpty()); 0041 Query query; 0042 query.containsFilter<SinkResource::Capabilities>(ResourceCapabilities::Mail::transport); 0043 query.filter<SinkResource::Account>(accountId); 0044 auto job = Store::fetchAll<SinkResource>(query) 0045 .then([=](const QList<SinkResource::Ptr> &resources) { 0046 if (!resources.isEmpty()) { 0047 auto resourceId = resources[0]->identifier(); 0048 SinkLog() << "Sending message via resource: " << resourceId; 0049 Mail mail(resourceId); 0050 mail.setMimeMessage(message); 0051 return Store::create(mail) 0052 .then<void>([=] { 0053 //Trigger a sync, but don't wait for it. 0054 Store::synchronize(Sink::SyncScope{}.resourceFilter(resourceId)).exec(); 0055 }); 0056 } 0057 SinkWarning() << "Failed to find a mailtransport resource"; 0058 return KAsync::error("Failed to find a MailTransport resource."); 0059 }) 0060 .then([&] (const KAsync::Error &) { 0061 SinkLog() << "Message was sent: "; 0062 }); 0063 job.exec(); 0064 } 0065 0066 static QStringList toStringList(const QVariantList &list) 0067 { 0068 QStringList s; 0069 for (const auto &e : list) { 0070 s << e.toString(); 0071 } 0072 return s; 0073 } 0074 0075 Q_INVOKABLE void ExtensionApi::forwardMail(const QVariantMap &map) 0076 { 0077 SinkLog() << "Forwarding mail " << map; 0078 auto mailObject = map.value("mail").value<Sink::ApplicationDomain::Mail::Ptr>(); 0079 Q_ASSERT(mailObject); 0080 KMime::Message::Ptr msg(new KMime::Message); 0081 msg->setContent(KMime::CRLFtoLF(mailObject->getMimeMessage())); 0082 msg->parse(); 0083 0084 MailTemplates::forward(msg, [map] (const KMime::Message::Ptr &fwdMessage) { 0085 auto msg = fwdMessage; 0086 msg->subject()->fromUnicodeString(map.value("subject").toString(), "utf8"); 0087 auto list = toStringList(map.value("to").toList()); 0088 for (const auto &address : list) { 0089 KMime::Types::Mailbox mb; 0090 mb.fromUnicodeString(address); 0091 msg->to()->addAddress(mb); 0092 } 0093 msg->assemble(); 0094 send(msg->encodedContent(true), map.value("accountId").toByteArray()); 0095 }); 0096 } 0097 0098 void ExtensionApi::storeSecret(const QByteArray &accountId, const QByteArray &keyId, const QVariantMap &secret) 0099 { 0100 QByteArray secretBA; 0101 QDataStream stream(&secretBA, QIODevice::WriteOnly); 0102 stream << secret; 0103 auto result = Crypto::signAndEncrypt(secretBA, Crypto::findKeys({{keyId}}, true), {}); 0104 if (result) { 0105 QSettings settings(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QString("/kube/secrets.ini"), QSettings::IniFormat); 0106 settings.setValue(accountId, result.value()); 0107 } else { 0108 SinkWarning() << "Failed to encrypt account secret " << accountId << keyId; 0109 } 0110 } 0111 0112 void ExtensionApi::loadSecret(const QByteArray &accountId) 0113 { 0114 QSettings settings(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QString("/kube/secrets.ini"), QSettings::IniFormat); 0115 0116 QByteArray secretBA; 0117 decryptAndVerify(Crypto::OpenPGP, settings.value(accountId).value<QByteArray>(), secretBA); 0118 0119 QVariantMap map; 0120 QDataStream stream(&secretBA, QIODevice::ReadOnly); 0121 stream >> map; 0122 0123 emit secretAvailable(accountId, map); 0124 }