KDE PIM support for the p≡p engine
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

310 lines
10 KiB

1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
  1. /*
  2. SPDX-FileCopyrightText: 2008 Ingo Klöcker <kloecker@kde.org>
  3. SPDX-FileCopyrightText: 2009 Constantin Berzan <exit3219@gmail.com>
  4. SPDX-License-Identifier: LGPL-2.0-or-later
  5. */
  6. #include "pepagent.h"
  7. #include "pepagent_debug.h"
  8. #include "pep-introspectadaptor.h"
  9. using namespace Akonadi;
  10. PEP_STATUS pEpAgent::messageToSend(::message* msg)
  11. {
  12. qDebug() << "pEp wants to send a message";
  13. return PEP_STATUS_OK;
  14. }
  15. pEpAgent::pEpAgent(const QString &id)
  16. : ResourceBase(id)
  17. {
  18. Q_D(pEpAgent);
  19. PEP_STATUS status;
  20. QDBusConnection dbus = QDBusConnection::sessionBus();
  21. const QString service = Akonadi::ServerManager::self()->agentServiceName(Akonadi::ServerManager::Agent, QStringLiteral("pEpAgent"));
  22. /* -------------- Starting the pEp Engine ------------------- */
  23. status = ::init(&m_session, NULL, NULL, NULL);
  24. /* --------------------- Done ------------------------------- */
  25. /* ------------- Extending DBus functions ------------------- */
  26. m_pEpadaptor = new PepAdaptor(this);
  27. dbus.registerObject(QStringLiteral("/security/pep"), QStringLiteral("security.pep"), this);
  28. dbus.registerService(service);
  29. /* --------------------- Done ------------------------------- */
  30. // pEp management
  31. m_syncThread = new pEpSyncThread(this);
  32. // This here is just bureaucracy:
  33. auto *collectionMonitor = new Akonadi::Monitor(this);
  34. collectionMonitor->setObjectName(QStringLiteral("pEpCollectionMonitor"));
  35. collectionMonitor->fetchCollection(true);
  36. collectionMonitor->ignoreSession(Akonadi::Session::defaultSession());
  37. collectionMonitor->collectionFetchScope().setAncestorRetrieval(Akonadi::CollectionFetchScope::All);
  38. collectionMonitor->setMimeTypeMonitored(KMime::Message::mimeType());
  39. connect(collectionMonitor, &Akonadi::Monitor::collectionAdded, this, &pEpAgent::mailCollectionAdded);
  40. connect(collectionMonitor, qOverload<const Akonadi::Collection &>(&Akonadi::Monitor::collectionChanged), this, &pEpAgent::mailCollectionChanged);
  41. connect(collectionMonitor, &Akonadi::Monitor::collectionRemoved, this, &pEpAgent::mailCollectionRemoved);
  42. connect(Akonadi::AgentManager::self(), &Akonadi::AgentManager::instanceRemoved, this, &pEpAgent::slotInstanceRemoved);
  43. QTimer::singleShot(0, this, &pEpAgent::initializeCollections);
  44. mProgressCounter = 0;
  45. mProgressTimer = new QTimer(this);
  46. itemMonitor = new Akonadi::Monitor(this);
  47. itemMonitor->setObjectName(QStringLiteral("pEpItemMonitor"));
  48. itemMonitor->itemFetchScope().setFetchRemoteIdentification(true);
  49. itemMonitor->itemFetchScope().setAncestorRetrieval(Akonadi::ItemFetchScope::Parent);
  50. connect(itemMonitor, &Akonadi::Monitor::itemChanged, this, &pEpAgent::slotItemChanged);
  51. }
  52. void pEpAgent::initializeCollections()
  53. {
  54. qCDebug(PEPAGENT_LOG) << __FUNCTION__ << " Test";
  55. qDebug() << __FUNCTION__ << " Test";
  56. Akonadi::CollectionFetchJob *job = new Akonadi::CollectionFetchJob(Akonadi::Collection::root(),
  57. Akonadi::CollectionFetchJob::Recursive,
  58. this);
  59. job->fetchScope(); //.setContentMimeTypes({ QStringLiteral("multipart/encrypted") });
  60. connect(job, &Akonadi::CollectionFetchJob::result, this, &pEpAgent::initialCollectionFetchingDone);
  61. }
  62. void pEpAgent::emitProgress(int p)
  63. {
  64. qCDebug(PEPAGENT_LOG) << __FUNCTION__ << " Test";
  65. qDebug() << __FUNCTION__ << " Test";
  66. if (p == 0) {
  67. mProgressTimer->stop();
  68. Q_EMIT status(AgentBase::Idle, QString());
  69. }
  70. mProgressCounter = p;
  71. Q_EMIT percent(p);
  72. }
  73. void pEpAgent::emitProgressMessage(const QString &message)
  74. {
  75. qCDebug(PEPAGENT_LOG) << __FUNCTION__ << " Test";
  76. Q_EMIT status(AgentBase::Running, message);
  77. if (status() == AgentBase::Idle) {
  78. // If still idle after aborting, clear 'aborted' status.
  79. Q_EMIT status(AgentBase::Idle, i18n("Ready to dispatch messages."));
  80. }
  81. }
  82. void pEpAgent::itemsReceiviedForFiltering(const Akonadi::Item::List &items)
  83. {
  84. qDebug() << __FUNCTION__ << " Test";
  85. if (items.isEmpty()) {
  86. qCDebug(PEPAGENT_LOG) << "pEpAgent::itemsReceiviedForFiltering items is empty!";
  87. return;
  88. }
  89. Akonadi::Item item = items.first();
  90. if (!item.hasPayload()) {
  91. qCDebug(PEPAGENT_LOG) << "pEpAgent::itemsReceiviedForFiltering item has no payload!";
  92. return;
  93. }
  94. QString resource = sender()->property("resource").toString();
  95. const Akonadi::Pop3ResourceAttribute *pop3ResourceAttribute = item.attribute<Akonadi::Pop3ResourceAttribute>();
  96. if (pop3ResourceAttribute) {
  97. resource = pop3ResourceAttribute->pop3AccountName();
  98. }
  99. emitProgressMessage(i18n("Filtering in %1", Akonadi::AgentManager::self()->instance(resource).name()));
  100. emitProgress(++mProgressCounter);
  101. mProgressTimer->start(1000);
  102. }
  103. void pEpAgent::clearMessage()
  104. {
  105. }
  106. void pEpAgent::emitStatusReady()
  107. {
  108. if (status() == AgentBase::Idle) {
  109. // If still idle after aborting, clear 'aborted' status.
  110. Q_EMIT status(AgentBase::Idle, i18n("p≡p engine ready"));
  111. }
  112. }
  113. bool pEpAgent::isFilterableCollection(const Akonadi::Collection &collection) const
  114. {
  115. // TODO: Do this smarter
  116. if(QStringLiteral( "INBOX" ) == collection.name()) {
  117. qDebug() << __FUNCTION__ << "Found an INBOX folder";
  118. return true;
  119. }
  120. if( QStringLiteral("inbox") == collection.name() ) {
  121. qDebug() << __FUNCTION__ << "Found an INBOX folder";
  122. return true;
  123. }
  124. qDebug() << __FUNCTION__ << "Not yet supported folder name: " << collection.name();
  125. return false;
  126. }
  127. void pEpAgent::scanCollection(const Akonadi::Collection &collection)
  128. {
  129. }
  130. void pEpAgent::initialCollectionFetchingDone(KJob *job)
  131. {
  132. qDebug() << __FUNCTION__ << " Test";
  133. if (job->error()) {
  134. qDebug() << job->errorString();
  135. return;
  136. }
  137. const auto fetchJob = qobject_cast<Akonadi::CollectionFetchJob *>(job);
  138. const auto pop3ResourceMap = MailCommon::Kernel::pop3ResourceTargetCollection();
  139. const auto lstCols = fetchJob->collections();
  140. for (const Akonadi::Collection &collection : lstCols) { // All the folders of all the accounts
  141. if(isFilterableCollection(collection)) {
  142. qDebug() << "Checking for keys in collection: " << collection.name();
  143. changeRecorder()->setCollectionMonitored(collection, true);
  144. }
  145. }
  146. Q_EMIT status(AgentBase::Idle, i18n("Ready"));
  147. Q_EMIT percent(100);
  148. QTimer::singleShot(2000, this, &pEpAgent::clearMessage);
  149. }
  150. void pEpAgent::slotItemChanged(const Akonadi::Item &item)
  151. {
  152. qDebug() << __FUNCTION__ << " Test";
  153. if (item.remoteId().isEmpty()) {
  154. return;
  155. }
  156. // now we have the remoteId
  157. itemMonitor->setItemMonitored(item, false);
  158. filterItem(item, item.parentCollection());
  159. }
  160. void pEpAgent::filterItem(const Akonadi::Item &item, const Akonadi::Collection &collection)
  161. {
  162. qDebug() << __FUNCTION__;
  163. auto job = new Akonadi::ItemFetchJob(item);
  164. connect(job, &Akonadi::ItemFetchJob::itemsReceived, this, &pEpAgent::itemsReceiviedForFiltering);
  165. job->fetchScope().fetchFullPayload();
  166. job->fetchScope().setAncestorRetrieval(Akonadi::ItemFetchScope::Parent);
  167. job->fetchScope().fetchAttribute<Akonadi::Pop3ResourceAttribute>();
  168. job->setProperty("resource", collection.resource());
  169. // TODO: Error handling?
  170. }
  171. void pEpAgent::mailCollectionRemoved(const Akonadi::Collection &collection)
  172. {
  173. qDebug() << __FUNCTION__;
  174. changeRecorder()->setCollectionMonitored(collection, false);
  175. }
  176. void pEpAgent::mailCollectionChanged(const Akonadi::Collection &collection)
  177. {
  178. qDebug() << __FUNCTION__;
  179. changeRecorder()->setCollectionMonitored(collection, isFilterableCollection(collection));
  180. }
  181. void pEpAgent::mailCollectionAdded(const Akonadi::Collection &collection, const Akonadi::Collection &)
  182. {
  183. qDebug() << __FUNCTION__;
  184. if (isFilterableCollection(collection)) {
  185. changeRecorder()->setCollectionMonitored(collection, true);
  186. }
  187. }
  188. void pEpAgent::slotInstanceRemoved(const Akonadi::AgentInstance &instance)
  189. {
  190. qDebug() << __FUNCTION__;
  191. //m_filterManager->agentRemoved(instance.identifier());
  192. }
  193. void pEpAgent::itemAdded(const Akonadi::Item &item, const Akonadi::Collection &collection)
  194. {
  195. qDebug() << __FUNCTION__;
  196. /* The monitor mimetype filter would override the collection filter, therefor we have to check
  197. * for the mimetype of the item here.
  198. */
  199. if (item.mimeType() != KMime::Message::mimeType()) {
  200. return;
  201. }
  202. if (item.remoteId().isEmpty()) {
  203. itemMonitor->setItemMonitored(item);
  204. } else {
  205. qDebug() << __FUNCTION__ << ": Filter this\n";
  206. filterItem(item, collection);
  207. }
  208. }
  209. void pEpAgent::configure(WId windowId)
  210. {
  211. qDebug() << __FUNCTION__ << "Test";
  212. }
  213. void pEpAgent::retrieveCollections()
  214. {
  215. // TODO: Put information here, like person table content and so:
  216. Akonadi::Collection::List collections;
  217. Akonadi::Collection topLevel;
  218. topLevel.setName(identifier());
  219. topLevel.setRemoteId(identifier());
  220. topLevel.setParentCollection(Akonadi::Collection::root());
  221. topLevel.setContentMimeTypes({Akonadi::Collection::mimeType()});
  222. topLevel.setRights(Akonadi::Collection::ReadOnly);
  223. auto topLevelDisplayAttr = topLevel.attribute<Akonadi::EntityDisplayAttribute>(Akonadi::Collection::AddIfMissing);
  224. topLevelDisplayAttr->setDisplayName(i18n("p≡p Engine"));
  225. topLevelDisplayAttr->setActiveIconName(QStringLiteral("akonadi-pep"));
  226. collections.push_back(topLevel);
  227. collectionsRetrieved(std::move(collections));
  228. }
  229. int pEpAgent::decrypt_message(const QString &src, QString &dst, QStringList &keylist, int &flags)
  230. {
  231. qDebug() << "pEpAgent: Decrypting";
  232. char *ms = src.toLatin1().data();
  233. ::message *m = NULL;
  234. ::message *md = new_message(PEP_dir_incoming);
  235. stringlist_t *kl = new_stringlist("");
  236. PEP_decrypt_flags_t fl = 0;
  237. bool might_be_pep = true;
  238. ::mime_decode_message( ms, src.toLatin1().size(), &m, &might_be_pep );
  239. ::decrypt_message(m_session, m, &md, &kl, &fl);
  240. if(md) {
  241. ::mime_encode_message(md, true, &ms, true);
  242. }
  243. flags = fl;
  244. dst = QLatin1String(ms);
  245. keylist.clear();
  246. while(kl) {
  247. keylist << QLatin1String(kl->value);
  248. kl = kl->next;
  249. }
  250. return 0;
  251. }
  252. AKONADI_RESOURCE_MAIN(pEpAgent)
  253. #include "moc_pepagent.cpp"