summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/CMakeLists.txt1
-rw-r--r--components/mailviewer/qml/DummyApp.qml55
-rw-r--r--components/mailviewer/qml/HtmlPart.qml2
-rw-r--r--components/mailviewer/qml/MailPart.qml36
-rw-r--r--components/mailviewer/qml/TextPart.qml4
-rw-r--r--components/mailviewer/qml/dummyapp.qml90
-rw-r--r--components/package/contents/ui/MailViewer.qml31
-rw-r--r--framework/domain/CMakeLists.txt6
-rw-r--r--framework/domain/messageparser.cpp144
-rw-r--r--framework/domain/messageparser.h72
-rw-r--r--framework/domain/messageparser_new.cpp148
-rw-r--r--framework/domain/messageparser_old.cpp140
-rw-r--r--framework/domain/mimetreeparser/CMakeLists.txt15
-rw-r--r--framework/domain/mimetreeparser/interface.cpp833
-rw-r--r--framework/domain/mimetreeparser/interface.h368
-rw-r--r--framework/domain/mimetreeparser/interface_p.h56
-rw-r--r--framework/domain/mimetreeparser/objecttreesource.cpp147
-rw-r--r--framework/domain/mimetreeparser/objecttreesource.h56
-rw-r--r--framework/domain/mimetreeparser/stringhtmlwriter.cpp150
-rw-r--r--framework/domain/mimetreeparser/stringhtmlwriter.h71
-rw-r--r--framework/domain/mimetreeparser/tests/CMakeLists.txt12
-rw-r--r--framework/domain/mimetreeparser/tests/data/alternative.mbox28
-rw-r--r--framework/domain/mimetreeparser/tests/data/html.mbox15
-rw-r--r--framework/domain/mimetreeparser/tests/data/openpgp-encrypted-attachment-and-non-encrypted-attachment.mbox115
-rw-r--r--framework/domain/mimetreeparser/tests/data/openpgp-inline-charset-encrypted.mbox40
-rw-r--r--framework/domain/mimetreeparser/tests/data/openpgp-inline-encrypted+nonenc.mbox31
-rw-r--r--framework/domain/mimetreeparser/tests/data/plaintext.mbox13
-rw-r--r--framework/domain/mimetreeparser/tests/data/smime-encrypted.mbox22
-rw-r--r--framework/domain/mimetreeparser/tests/gnupg_home/CMakeLists.txt10
-rw-r--r--framework/domain/mimetreeparser/tests/gnupg_home/dirmngr-cache.d/DIR.txt3
-rw-r--r--framework/domain/mimetreeparser/tests/gnupg_home/dirmngr-cache.d/crl-4E31CEB57DDD4A7B9991AB05507B1ED4293FF952.dbbin0 -> 2130 bytes
-rw-r--r--framework/domain/mimetreeparser/tests/gnupg_home/dirmngr-cache.d/crl-7F2A402CBB016A9146D613568C89D3596A4111AA.dbbin0 -> 2048 bytes
-rw-r--r--framework/domain/mimetreeparser/tests/gnupg_home/dirmngr.conf8
-rw-r--r--framework/domain/mimetreeparser/tests/gnupg_home/gpg-agent.conf.in10
-rw-r--r--framework/domain/mimetreeparser/tests/gnupg_home/gpg.conf244
-rw-r--r--framework/domain/mimetreeparser/tests/gnupg_home/gpgsm.conf.in10
-rwxr-xr-xframework/domain/mimetreeparser/tests/gnupg_home/pinentry-fake.sh9
-rw-r--r--framework/domain/mimetreeparser/tests/gnupg_home/private-keys-v1.d/1AA8BA52430E51AE249AF0DA97D59F869E4101A8.keybin0 -> 528 bytes
-rw-r--r--framework/domain/mimetreeparser/tests/gnupg_home/pubring.gpgbin0 -> 6757 bytes
-rw-r--r--framework/domain/mimetreeparser/tests/gnupg_home/pubring.kbxbin0 -> 2017 bytes
-rw-r--r--framework/domain/mimetreeparser/tests/gnupg_home/scdaemon.conf8
-rw-r--r--framework/domain/mimetreeparser/tests/gnupg_home/secring.gpgbin0 -> 5163 bytes
-rw-r--r--framework/domain/mimetreeparser/tests/gnupg_home/trustdb.gpgbin0 -> 1440 bytes
-rw-r--r--framework/domain/mimetreeparser/tests/gnupg_home/trustlist.txt11
-rw-r--r--framework/domain/mimetreeparser/tests/interfacetest.cpp229
-rw-r--r--framework/domain/mimetreeparser/tests/kdepim_add_gpg_crypto_test.cmake60
-rw-r--r--framework/domain/mimetreeparser/tests/kdepim_generate_crypto_test_wrapper.cmake45
-rw-r--r--framework/domain/mimetreeparser/thoughts.txt148
48 files changed, 3255 insertions, 241 deletions
diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt
index 4fad0387..66e27822 100644
--- a/components/CMakeLists.txt
+++ b/components/CMakeLists.txt
@@ -24,6 +24,7 @@ find_package(KF5 REQUIRED COMPONENTS Package)
24 24
25install(FILES qmldir DESTINATION ${QML_INSTALL_DIR}/org/kube/components) 25install(FILES qmldir DESTINATION ${QML_INSTALL_DIR}/org/kube/components)
26install(DIRECTORY package/contents/ui/ DESTINATION ${QML_INSTALL_DIR}/org/kube/components) 26install(DIRECTORY package/contents/ui/ DESTINATION ${QML_INSTALL_DIR}/org/kube/components)
27install(DIRECTORY mailviewer/qml/ DESTINATION ${QML_INSTALL_DIR}/org/kube/components)
27 28
28include(${CMAKE_SOURCE_DIR}/KF5KirigamiMacros.cmake) 29include(${CMAKE_SOURCE_DIR}/KF5KirigamiMacros.cmake)
29kirigami_package_breeze_icons(ICONS applications-graphics view-list-icons folder-sync view-list-details configure document-edit dialog-cancel document-decrypt mail-reply-sender bookmarks folder) 30kirigami_package_breeze_icons(ICONS applications-graphics view-list-icons folder-sync view-list-details configure document-edit dialog-cancel document-decrypt mail-reply-sender bookmarks folder)
diff --git a/components/mailviewer/qml/DummyApp.qml b/components/mailviewer/qml/DummyApp.qml
new file mode 100644
index 00000000..acb91ac1
--- /dev/null
+++ b/components/mailviewer/qml/DummyApp.qml
@@ -0,0 +1,55 @@
1/*
2 Copyright (C) 2016 Michael Bohlender, <michael.bohlender@kdemail.net>
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17*/
18
19import QtQuick 2.4
20
21Item {
22Column {
23 anchors {
24 top: parent.top
25 left: parent.left
26 right: parent.right
27 margins: 20
28 }
29
30 spacing: 10
31 width: parent.width
32 Repeater {
33 model: messageParser.newTree
34
35 delegate: Column {
36 id: delegateRoot
37
38 width: parent.width
39
40 Loader {
41 id: loader
42 }
43
44 Component.onCompleted: {
45 switch (model.type) {
46 case "AlternativePart":
47 case "SinglePart":
48 loader.source = "MailPart.qml";
49 break;
50 }
51 }
52 }
53 }
54}
55}
diff --git a/components/mailviewer/qml/HtmlPart.qml b/components/mailviewer/qml/HtmlPart.qml
index f1add75c..f812ecb4 100644
--- a/components/mailviewer/qml/HtmlPart.qml
+++ b/components/mailviewer/qml/HtmlPart.qml
@@ -24,7 +24,7 @@ import QtWebEngine 1.2
24 24
25Item { 25Item {
26 id: root 26 id: root
27 property string content: model.htmlContent 27 property string content: model.content
28 property int contentHeight: helperView.contentHeight; 28 property int contentHeight: helperView.contentHeight;
29 //FIXME workaround until QtWebEngine 1.3 with contentsSize 29 //FIXME workaround until QtWebEngine 1.3 with contentsSize
30 30
diff --git a/components/mailviewer/qml/MailPart.qml b/components/mailviewer/qml/MailPart.qml
index 966337cd..d47b4c5f 100644
--- a/components/mailviewer/qml/MailPart.qml
+++ b/components/mailviewer/qml/MailPart.qml
@@ -21,24 +21,22 @@ import QtQuick 2.4
21Item { 21Item {
22 id: root 22 id: root
23 23
24 height: partColumn.height + 40 24 height: partColumn.height + 20
25 width: delegateRoot.width 25 width: delegateRoot.width
26 26
27 Column { 27 Column {
28 id: partColumn 28 id: partColumn
29
30 anchors { 29 anchors {
31 top: parent.top 30 top: parent.top
32 left: parent.left 31 left: parent.left
33 right: parent.right 32 right: parent.right
34 margins: 20 33 margins: 10
35 } 34 }
36 35
37 spacing: 10 36 spacing: 5
38 37
39 Repeater { 38 Repeater {
40 model: content 39 model: contents
41
42 delegate: Column { 40 delegate: Column {
43 id: delegateRoot 41 id: delegateRoot
44 42
@@ -49,23 +47,29 @@ Item {
49 } 47 }
50 48
51 Component.onCompleted: { 49 Component.onCompleted: {
52
53 switch (model.type) { 50 switch (model.type) {
51 case "AlternativePart":
52 case "SinglePart":
53 loader.source = "MailPart.qml";
54 break;
55
56 case "PlainTextContent":
57 case "Content":
58 loader.source = "TextPart.qml";
59 break;
60 case "HtmlContent":
61 loader.source = "HtmlPart.qml";
62 break;
63
64 case "alternativeframe":
65 loader.source = "Frame.qml"
66 break;
54 case "encrypted": 67 case "encrypted":
55 loader.source = "EncryptedPart.qml"; 68 loader.source = "EncryptedPart.qml";
56 break; 69 break;
57 case "embeded": 70 case "embeded":
58 loader.source = "EmbededPart.qml"; 71 loader.source = "EmbededPart.qml";
59 break; 72 break;
60 case "frame":
61 loader.source = "Frame.qml"
62 break;
63 case "plaintext":
64 loader.source = "TextPart.qml";
65 break;
66 case "html":
67 loader.source = "HtmlPart.qml";
68 break;
69 } 73 }
70 } 74 }
71 } 75 }
diff --git a/components/mailviewer/qml/TextPart.qml b/components/mailviewer/qml/TextPart.qml
index 5f183852..0267682f 100644
--- a/components/mailviewer/qml/TextPart.qml
+++ b/components/mailviewer/qml/TextPart.qml
@@ -21,8 +21,8 @@ import QtQuick 2.4
21Text { 21Text {
22 width: delegateRoot.width 22 width: delegateRoot.width
23 23
24 text: model.textContent 24 text: model.content
25 wrapMode: Text.WordWrap 25 wrapMode: Text.WordWrap
26 26
27 color: embeded ? "grey" : "black" 27 color: model.securityLevel //embeded ? "grey" : "black"
28} 28}
diff --git a/components/mailviewer/qml/dummyapp.qml b/components/mailviewer/qml/dummyapp.qml
deleted file mode 100644
index a186f0f1..00000000
--- a/components/mailviewer/qml/dummyapp.qml
+++ /dev/null
@@ -1,90 +0,0 @@
1/*
2 Copyright (C) 2016 Michael Bohlender, <michael.bohlender@kdemail.net>
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17*/
18
19import QtQuick 2.4
20
21Rectangle {
22 id: app
23
24 width: 1200
25 height: 700
26
27 Rectangle {
28 anchors.fill: parent
29
30 color: "black"
31
32 opacity: 0.8
33
34 }
35
36 Rectangle {
37
38 anchors.centerIn: parent
39
40 height: mainColumn.height + 50
41 width: parent.width * 0.9
42
43 Column {
44 id: mainColumn
45
46 anchors.centerIn: parent
47
48 width: parent.width - 50
49
50 spacing: 10
51
52 Repeater {
53 model: MailModel {}
54
55 delegate: Column {
56 id: delegateRoot
57
58 width: mainColumn.width
59
60 Loader {
61 id: loader
62 }
63
64 Component.onCompleted: {
65 switch (model.type) {
66 case "red":
67 loader.source = "Rect2.qml";
68 break;
69 case "green":
70 loader.source = "Rect1.qml";
71 break;
72 case "encrypted":
73 loader.source = "EncryptedPart.qml";
74 break;
75 case "frame":
76 loader.source = "Frame.qml";
77 break;
78 case "plaintext":
79 loader.source = "TextPart.qml";
80 break;
81 case "html":
82 loader.source = "HtmlPart.qml";
83 break;
84 }
85 }
86 }
87 }
88 }
89 }
90}
diff --git a/components/package/contents/ui/MailViewer.qml b/components/package/contents/ui/MailViewer.qml
index 5365be66..347f30de 100644
--- a/components/package/contents/ui/MailViewer.qml
+++ b/components/package/contents/ui/MailViewer.qml
@@ -27,8 +27,8 @@ Item {
27 id: root 27 id: root
28 property variant message; 28 property variant message;
29 property string html; 29 property string html;
30 property bool enablePartTreeView : false 30 property bool enablePartTreeView : true;
31 property int desiredHeight: enablePartTreeView ? topPartLoader.height+450 : topPartLoader.height; 31 property int desiredHeight: enablePartTreeView ? topPartLoader.height + dummyApp.height + mailStructure.height + 50 : topPartLoader.height + dummyApp.height + 50;
32 32
33 Rectangle { 33 Rectangle {
34 id: rootRectangle 34 id: rootRectangle
@@ -41,6 +41,19 @@ Item {
41 verticalScrollBarPolicy: Qt.ScrollBarAlwaysOff 41 verticalScrollBarPolicy: Qt.ScrollBarAlwaysOff
42 Column { 42 Column {
43 spacing:2 43 spacing:2
44 Text {
45 text: "New Mailviewer:"
46 color: "blue"
47 }
48 DummyApp {
49 id: dummyApp
50 height: 800
51 width: rootRectangle.width
52 }
53 Text {
54 text: "Old Mailviewer:"
55 color: "blue"
56 }
44 MessagePartTree { 57 MessagePartTree {
45 id: topPartLoader 58 id: topPartLoader
46 // width: rootRectangle.width 59 // width: rootRectangle.width
@@ -48,6 +61,7 @@ Item {
48 width: topPartLoader.contentWidth >= rootRectangle.width ? topPartLoader.contentWidth : rootRectangle.width 61 width: topPartLoader.contentWidth >= rootRectangle.width ? topPartLoader.contentWidth : rootRectangle.width
49 } 62 }
50 TreeView { 63 TreeView {
64 id: mailStructure
51 visible: enablePartTreeView 65 visible: enablePartTreeView
52 width: rootRectangle.width 66 width: rootRectangle.width
53 height: 400 67 height: 400
@@ -57,16 +71,17 @@ Item {
57 width: 300 71 width: 300
58 } 72 }
59 TableViewColumn { 73 TableViewColumn {
60 role: "isHidden" 74 role: "embeded"
61 title: "Hidden" 75 title: "Embeded"
62 width: 60 76 width: 60
63 } 77 }
64 TableViewColumn { 78 TableViewColumn {
65 role: "text" 79 role: "content"
66 title: "Text" 80 title: "Content"
67 width: 600 81 width: 200
68 } 82 }
69 model: messageParser.partTree 83 //model: messageParser.partTree
84 model: messageParser.newTree
70 } 85 }
71 } 86 }
72 } 87 }
diff --git a/framework/domain/CMakeLists.txt b/framework/domain/CMakeLists.txt
index 804b3ccb..55bc2f24 100644
--- a/framework/domain/CMakeLists.txt
+++ b/framework/domain/CMakeLists.txt
@@ -7,6 +7,8 @@ set(mailplugin_SRCS
7 stringhtmlwriter.cpp 7 stringhtmlwriter.cpp
8 composercontroller.cpp 8 composercontroller.cpp
9 messageparser.cpp 9 messageparser.cpp
10 messageparser_new.cpp
11 messageparser_old.cpp
10 mailtemplates.cpp 12 mailtemplates.cpp
11 retriever.cpp 13 retriever.cpp
12 accountfactory.cpp 14 accountfactory.cpp
@@ -21,9 +23,11 @@ find_package(KF5 REQUIRED COMPONENTS Package)
21add_library(mailplugin SHARED ${mailplugin_SRCS}) 23add_library(mailplugin SHARED ${mailplugin_SRCS})
22 24
23qt5_use_modules(mailplugin Core Quick Qml WebKitWidgets) 25qt5_use_modules(mailplugin Core Quick Qml WebKitWidgets)
24target_link_libraries(mailplugin actionplugin settingsplugin sink KF5::MimeTreeParser KF5::Codecs KF5::Package KF5::Async KF5::IconThemes) 26target_link_libraries(mailplugin actionplugin settingsplugin sink mimetreeparser KF5::MimeTreeParser KF5::Codecs KF5::Package KF5::Async KF5::IconThemes)
25 27
26add_subdirectory(actions/tests) 28add_subdirectory(actions/tests)
27 29
28install(TARGETS mailplugin DESTINATION ${QML_INSTALL_DIR}/org/kube/framework/domain) 30install(TARGETS mailplugin DESTINATION ${QML_INSTALL_DIR}/org/kube/framework/domain)
29install(FILES qmldir DESTINATION ${QML_INSTALL_DIR}/org/kube/framework/domain) 31install(FILES qmldir DESTINATION ${QML_INSTALL_DIR}/org/kube/framework/domain)
32
33add_subdirectory(mimetreeparser) \ No newline at end of file
diff --git a/framework/domain/messageparser.cpp b/framework/domain/messageparser.cpp
index ff763aec..ef9fb0d2 100644
--- a/framework/domain/messageparser.cpp
+++ b/framework/domain/messageparser.cpp
@@ -21,6 +21,10 @@
21#include "stringhtmlwriter.h" 21#include "stringhtmlwriter.h"
22#include "objecttreesource.h" 22#include "objecttreesource.h"
23 23
24#include "mimetreeparser/interface.h"
25
26#include <QRegExp>
27
24#include <QFile> 28#include <QFile>
25#include <QImage> 29#include <QImage>
26#include <QDebug> 30#include <QDebug>
@@ -29,128 +33,32 @@
29#include <MimeTreeParser/ObjectTreeParser> 33#include <MimeTreeParser/ObjectTreeParser>
30#include <MimeTreeParser/MessagePart> 34#include <MimeTreeParser/MessagePart>
31 35
32PartModel::PartModel(QSharedPointer<MimeTreeParser::MessagePart> partTree, QMap<QByteArray, QUrl> embeddedPartMap) : mPartTree(partTree), mEmbeddedPartMap(embeddedPartMap)
33{
34}
35 36
36QHash<int, QByteArray> PartModel::roleNames() const 37class MessagePartPrivate
37{ 38{
38 QHash<int, QByteArray> roles; 39public:
39 roles[Text] = "text"; 40 QSharedPointer<MimeTreeParser::MessagePart> mPartTree;
40 roles[IsHtml] = "isHtml"; 41 QString mHtml;
41 roles[IsHidden] = "isHidden"; 42 QMap<QByteArray, QUrl> mEmbeddedPartMap;
42 roles[IsEncrypted] = "isEncrypted"; 43 std::shared_ptr<MimeTreeParser::NodeHelper> mNodeHelper;
43 roles[IsAttachment] = "isAttachment"; 44 std::shared_ptr<Parser> mParser;
44 roles[HasContent] = "hasContent"; 45};
45 roles[Type] = "type";
46 roles[IsHidden] = "isHidden";
47 return roles;
48}
49 46
50QModelIndex PartModel::index(int row, int column, const QModelIndex &parent) const 47MessageParser::MessageParser(QObject *parent)
51{ 48 : QObject(parent)
52 // qDebug() << "index " << parent << row << column << mPartTree->subParts().size(); 49 , d(std::unique_ptr<MessagePartPrivate>(new MessagePartPrivate))
53 if (!parent.isValid()) {
54 if (row < mPartTree->subParts().size()) {
55 auto part = mPartTree->subParts().at(row);
56 return createIndex(row, column, part.data());
57 }
58 } else {
59 auto part = static_cast<MimeTreeParser::MessagePart*>(parent.internalPointer());
60 auto subPart = part->subParts().at(row);
61 return createIndex(row, column, subPart.data());
62 }
63 return QModelIndex();
64}
65
66QVariant PartModel::data(const QModelIndex &index, int role) const
67{
68 // qDebug() << "Getting data for index";
69 if (index.isValid()) {
70 auto part = static_cast<MimeTreeParser::MessagePart*>(index.internalPointer());
71 switch (role) {
72 case Text: {
73 // qDebug() << "Getting text: " << part->property("text").toString();
74 // FIXME: we should have a list per part, and not one for all parts.
75 auto text = part->property("htmlContent").toString();
76 for (const auto &cid : mEmbeddedPartMap.keys()) {
77 text.replace(QString("src=\"cid:%1\"").arg(QString(cid)), QString("src=\"%1\"").arg(mEmbeddedPartMap.value(cid).toString()));
78 }
79 return text;
80 }
81 case IsAttachment:
82 return part->property("attachment").toBool();
83 case IsEncrypted:
84 return part->property("isEncrypted").toBool();
85 case IsHtml:
86 return part->property("isHtml").toBool();
87 case HasContent:
88 return !part->property("htmlContent").toString().isEmpty();
89 case Type:
90 return part->metaObject()->className();
91 case IsHidden:
92 return false;
93 //return part->property("isHidden").toBool();
94
95 }
96 }
97 return QVariant();
98}
99
100QModelIndex PartModel::parent(const QModelIndex &index) const
101{
102 // qDebug() << "parent " << index;
103 if (index.isValid()) {
104 auto part = static_cast<MimeTreeParser::MessagePart*>(index.internalPointer());
105 auto parentPart = static_cast<MimeTreeParser::MessagePart*>(part->parentPart());
106 auto row = 0;//get the parents parent to find the index
107 if (!parentPart) {
108 parentPart = mPartTree.data();
109 }
110 int i = 0;
111 for (const auto &p : parentPart->subParts()) {
112 if (p.data() == part) {
113 row = i;
114 break;
115 }
116 i++;
117 }
118 return createIndex(row, index.column(), parentPart);
119 }
120 return QModelIndex();
121}
122
123int PartModel::rowCount(const QModelIndex &parent) const
124{ 50{
125 // qDebug() << "Row count " << parent;
126 if (!parent.isValid()) {
127 // qDebug() << "Row count " << mPartTree->subParts().size();
128 return mPartTree->subParts().size();
129 } else {
130 auto part = static_cast<MimeTreeParser::MessagePart*>(parent.internalPointer());
131 if (part) {
132 return part->subParts().size();
133 }
134 }
135 return 0;
136}
137 51
138int PartModel::columnCount(const QModelIndex &parent) const
139{
140 // qDebug() << "Column count " << parent;
141 return 1;
142} 52}
143 53
144 54MessageParser::~MessageParser()
145MessageParser::MessageParser(QObject *parent)
146 : QObject(parent)
147{ 55{
148 56
149} 57}
150 58
151QString MessageParser::html() const 59QString MessageParser::html() const
152{ 60{
153 return mHtml; 61 return d->mHtml;
154} 62}
155 63
156QVariant MessageParser::message() const 64QVariant MessageParser::message() const
@@ -162,6 +70,8 @@ void MessageParser::setMessage(const QVariant &message)
162{ 70{
163 QTime time; 71 QTime time;
164 time.start(); 72 time.start();
73 d->mParser = std::shared_ptr<Parser>(new Parser(message.toByteArray()));
74
165 const auto mailData = KMime::CRLFtoLF(message.toByteArray()); 75 const auto mailData = KMime::CRLFtoLF(message.toByteArray());
166 KMime::Message::Ptr msg(new KMime::Message); 76 KMime::Message::Ptr msg(new KMime::Message);
167 msg->setContent(mailData); 77 msg->setContent(mailData);
@@ -171,20 +81,24 @@ void MessageParser::setMessage(const QVariant &message)
171 // render the mail 81 // render the mail
172 StringHtmlWriter htmlWriter; 82 StringHtmlWriter htmlWriter;
173 //temporary files only have the lifetime of the nodehelper, so we keep it around until the mail changes. 83 //temporary files only have the lifetime of the nodehelper, so we keep it around until the mail changes.
174 mNodeHelper = std::make_shared<MimeTreeParser::NodeHelper>(); 84 d->mNodeHelper = std::make_shared<MimeTreeParser::NodeHelper>();
175 ObjectTreeSource source(&htmlWriter); 85 ObjectTreeSource source(&htmlWriter);
176 MimeTreeParser::ObjectTreeParser otp(&source, mNodeHelper.get()); 86 MimeTreeParser::ObjectTreeParser otp(&source, d->mNodeHelper.get());
177 87
178 otp.parseObjectTree(msg.data()); 88 otp.parseObjectTree(msg.data());
179 mPartTree = otp.parsedPart().dynamicCast<MimeTreeParser::MessagePart>(); 89 d->mPartTree = otp.parsedPart().dynamicCast<MimeTreeParser::MessagePart>();
180 90
181 mEmbeddedPartMap = htmlWriter.embeddedParts(); 91 d->mEmbeddedPartMap = htmlWriter.embeddedParts();
182 mHtml = htmlWriter.html(); 92 d->mHtml = htmlWriter.html();
183 emit htmlChanged(); 93 emit htmlChanged();
184} 94}
185 95
186QAbstractItemModel *MessageParser::partTree() const 96QAbstractItemModel *MessageParser::partTree() const
187{ 97{
188 return new PartModel(mPartTree, mEmbeddedPartMap); 98 return new PartModel(d->mPartTree, d->mParser);
189} 99}
190 100
101QAbstractItemModel *MessageParser::newTree() const
102{
103 return new NewModel(d->mParser);
104}
diff --git a/framework/domain/messageparser.h b/framework/domain/messageparser.h
index 3e0255df..b3d7537d 100644
--- a/framework/domain/messageparser.h
+++ b/framework/domain/messageparser.h
@@ -29,41 +29,45 @@
29#include <memory> 29#include <memory>
30#include <MimeTreeParser/MessagePart> 30#include <MimeTreeParser/MessagePart>
31 31
32namespace MimeTreeParser {
33 class NodeHelper;
34};
35class QAbstractItemModel; 32class QAbstractItemModel;
36 33
34class Parser;
35class Part;
36typedef std::shared_ptr<Part> PartPtr;
37class Content;
38typedef std::shared_ptr<Content> ContentPtr;
39class MessagePartPrivate;
40
37class MessageParser : public QObject 41class MessageParser : public QObject
38{ 42{
39 Q_OBJECT 43 Q_OBJECT
40 Q_PROPERTY (QVariant message READ message WRITE setMessage) 44 Q_PROPERTY (QVariant message READ message WRITE setMessage)
41 Q_PROPERTY (QString html READ html NOTIFY htmlChanged) 45 Q_PROPERTY (QString html READ html NOTIFY htmlChanged)
42 Q_PROPERTY (QAbstractItemModel* partTree READ partTree NOTIFY htmlChanged) 46 Q_PROPERTY (QAbstractItemModel* partTree READ partTree NOTIFY htmlChanged)
47 Q_PROPERTY (QAbstractItemModel* newTree READ newTree NOTIFY htmlChanged)
43 48
44public: 49public:
45 explicit MessageParser(QObject *parent = Q_NULLPTR); 50 explicit MessageParser(QObject *parent = Q_NULLPTR);
51 ~MessageParser();
46 52
47 QString html() const; 53 QString html() const;
48 54
49 QVariant message() const; 55 QVariant message() const;
50 void setMessage(const QVariant &to); 56 void setMessage(const QVariant &to);
51 QAbstractItemModel *partTree() const; 57 QAbstractItemModel *partTree() const;
58 QAbstractItemModel *newTree() const;
52 59
53signals: 60signals:
54 void htmlChanged(); 61 void htmlChanged();
55 62
56private: 63private:
57 QSharedPointer<MimeTreeParser::MessagePart> mPartTree; 64 std::unique_ptr<MessagePartPrivate> d;
58 QString mHtml;
59 QMap<QByteArray, QUrl> mEmbeddedPartMap;
60 std::shared_ptr<MimeTreeParser::NodeHelper> mNodeHelper;
61}; 65};
62 66
63class PartModel : public QAbstractItemModel { 67class PartModel : public QAbstractItemModel {
64 Q_OBJECT 68 Q_OBJECT
65public: 69public:
66 PartModel(QSharedPointer<MimeTreeParser::MessagePart> partTree, QMap<QByteArray, QUrl> embeddedPartMap); 70 PartModel(QSharedPointer<MimeTreeParser::MessagePart> partTree, std::shared_ptr<Parser> parser);
67 71
68public: 72public:
69 enum Roles { 73 enum Roles {
@@ -86,5 +90,57 @@ public:
86private: 90private:
87 QSharedPointer<MimeTreeParser::MessagePart> mPartTree; 91 QSharedPointer<MimeTreeParser::MessagePart> mPartTree;
88 QMap<QByteArray, QUrl> mEmbeddedPartMap; 92 QMap<QByteArray, QUrl> mEmbeddedPartMap;
93 std::shared_ptr<Parser> mParser;
94};
95
96
97class NewContentModel : public QAbstractItemModel {
98 Q_OBJECT
99public:
100 NewContentModel (const PartPtr &part);
101
102public:
103 enum Roles {
104 TypeRole = Qt::UserRole + 1,
105 ContentRole,
106 IsEmbededRole,
107 SecurityLevelRole
108 };
109
110 QHash<int, QByteArray> roleNames() const Q_DECL_OVERRIDE;
111 QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
112 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
113 QModelIndex parent(const QModelIndex &index) const Q_DECL_OVERRIDE;
114 int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
115 int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
116
117private:
118 const PartPtr &mPart;
119};
120
121class NewModel : public QAbstractItemModel {
122 Q_OBJECT
123public:
124 NewModel(std::shared_ptr<Parser> parser);
125
126public:
127 enum Roles {
128 TypeRole = Qt::UserRole + 1,
129 ContentsRole,
130 IsEmbededRole,
131 SecurityLevelRole
132 };
133
134 QHash<int, QByteArray> roleNames() const Q_DECL_OVERRIDE;
135 QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
136 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
137 QModelIndex parent(const QModelIndex &index) const Q_DECL_OVERRIDE;
138 int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
139 int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
140
141private:
142 std::shared_ptr<Parser> mParser;
143 QVector<PartPtr> mParts;
144 QMap<Part *, std::shared_ptr<NewContentModel>> mContentMap;
89}; 145};
90 146
diff --git a/framework/domain/messageparser_new.cpp b/framework/domain/messageparser_new.cpp
new file mode 100644
index 00000000..d1b956f5
--- /dev/null
+++ b/framework/domain/messageparser_new.cpp
@@ -0,0 +1,148 @@
1
2/*
3 This library is free software; you can redistribute it and/or modify it
4 under the terms of the GNU Library General Public License as published by
5 the Free Software Foundation; either version 2 of the License, or (at your
6 option) any later version.
7
8 This library is distributed in the hope that it will be useful, but WITHOUT
9 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
11 License for more details.
12
13 You should have received a copy of the GNU Library General Public License
14 along with this library; see the file COPYING.LIB. If not, write to the
15 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 02110-1301, USA.
17*/
18
19#include "messageparser.h"
20#include "mimetreeparser/interface.h"
21
22#include <QDebug>
23
24NewModel::NewModel(std::shared_ptr<Parser> parser)
25 : mParser(parser)
26{
27 mParts = mParser->collectContentParts();
28 foreach(const auto &part, mParts) {
29 mContentMap.insert(part.get(), std::shared_ptr<NewContentModel>(new NewContentModel(part)));
30 }
31}
32
33QHash<int, QByteArray> NewModel::roleNames() const
34{
35 QHash<int, QByteArray> roles;
36 roles[TypeRole] = "type";
37 roles[ContentsRole] = "contents";
38 roles[IsEmbededRole] = "embeded";
39 roles[SecurityLevelRole] = "securityLevel";
40 return roles;
41}
42
43QModelIndex NewModel::index(int row, int column, const QModelIndex &parent) const
44{
45 if (!parent.isValid()) {
46 if (row < mParts.size()) {
47 auto part = mParts.at(row);
48 return createIndex(row, column, part.get());
49 }
50 }
51 return QModelIndex();
52}
53
54QVariant NewModel::data(const QModelIndex &index, int role) const
55{
56 if (!index.parent().isValid()) {
57 auto part = static_cast<Part *>(index.internalPointer());
58 switch (role) {
59 case TypeRole:
60 return QString::fromLatin1(part->type());
61 case IsEmbededRole:
62 return index.parent().isValid();
63 case SecurityLevelRole:
64 return QStringLiteral("GRAY");
65 case ContentsRole:
66 return QVariant::fromValue<QAbstractItemModel *>(mContentMap.value(part).get());
67 }
68 }
69 return QVariant();
70}
71
72QModelIndex NewModel::parent(const QModelIndex &index) const
73{
74 return QModelIndex();
75}
76
77int NewModel::rowCount(const QModelIndex &parent) const
78{
79 if (!parent.isValid()) {
80 return mParts.size();
81 }
82 return 0;
83}
84
85int NewModel::columnCount(const QModelIndex &parent) const
86{
87 return 1;
88}
89
90NewContentModel::NewContentModel(const Part::Ptr &part)
91 : mPart(part)
92{
93}
94
95QHash<int, QByteArray> NewContentModel::roleNames() const
96{
97 QHash<int, QByteArray> roles;
98 roles[TypeRole] = "type";
99 roles[ContentRole] = "content";
100 roles[IsEmbededRole] = "embeded";
101 roles[SecurityLevelRole] = "securityLevel";
102 return roles;
103}
104
105QModelIndex NewContentModel::index(int row, int column, const QModelIndex &parent) const
106{
107 if (!parent.isValid()) {
108 if (row < mPart->content().size()) {
109 auto part = mPart->content().at(row);
110 return createIndex(row, column, part.get());
111 }
112 }
113 return QModelIndex();
114}
115
116QVariant NewContentModel::data(const QModelIndex &index, int role) const
117{
118 auto content = static_cast<Content *>(index.internalPointer());
119 switch (role) {
120 case TypeRole:
121 return QString::fromLatin1(content->type());
122 case IsEmbededRole:
123 return false;
124 case ContentRole:
125 return content->encodedContent();
126 case SecurityLevelRole:
127 return content->encryptions().size() > mPart->encryptions().size() ? "red": "black"; //test for gpg inline
128 }
129 return QVariant();
130}
131
132QModelIndex NewContentModel::parent(const QModelIndex &index) const
133{
134 return QModelIndex();
135}
136
137int NewContentModel::rowCount(const QModelIndex &parent) const
138{
139 if (!parent.isValid()) {
140 return mPart->content().size();
141 }
142 return 0;
143}
144
145int NewContentModel::columnCount(const QModelIndex &parent) const
146{
147 return 1;
148}
diff --git a/framework/domain/messageparser_old.cpp b/framework/domain/messageparser_old.cpp
new file mode 100644
index 00000000..a364c8ab
--- /dev/null
+++ b/framework/domain/messageparser_old.cpp
@@ -0,0 +1,140 @@
1/*
2 This library is free software; you can redistribute it and/or modify it
3 under the terms of the GNU Library General Public License as published by
4 the Free Software Foundation; either version 2 of the License, or (at your
5 option) any later version.
6
7 This library is distributed in the hope that it will be useful, but WITHOUT
8 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
9 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
10 License for more details.
11
12 You should have received a copy of the GNU Library General Public License
13 along with this library; see the file COPYING.LIB. If not, write to the
14 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 02110-1301, USA.
16*/
17
18#include "messageparser.h"
19#include "mimetreeparser/interface.h"
20
21PartModel::PartModel(QSharedPointer<MimeTreeParser::MessagePart> partTree, std::shared_ptr<Parser> parser)
22 : mPartTree(partTree)
23 , mParser(parser)
24{
25}
26
27QHash<int, QByteArray> PartModel::roleNames() const
28{
29 QHash<int, QByteArray> roles;
30 roles[Text] = "text";
31 roles[IsHtml] = "isHtml";
32 roles[IsHidden] = "isHidden";
33 roles[IsEncrypted] = "isEncrypted";
34 roles[IsAttachment] = "isAttachment";
35 roles[HasContent] = "hasContent";
36 roles[Type] = "type";
37 roles[IsHidden] = "isHidden";
38 return roles;
39}
40
41QModelIndex PartModel::index(int row, int column, const QModelIndex &parent) const
42{
43 // qDebug() << "index " << parent << row << column << mPartTree->subParts().size();
44 if (!parent.isValid()) {
45 if (row < mPartTree->subParts().size()) {
46 auto part = mPartTree->subParts().at(row);
47 return createIndex(row, column, part.data());
48 }
49 } else {
50 auto part = static_cast<MimeTreeParser::MessagePart*>(parent.internalPointer());
51 auto subPart = part->subParts().at(row);
52 return createIndex(row, column, subPart.data());
53 }
54 return QModelIndex();
55}
56
57QVariant PartModel::data(const QModelIndex &index, int role) const
58{
59 // qDebug() << "Getting data for index";
60 if (index.isValid()) {
61 auto part = static_cast<MimeTreeParser::MessagePart*>(index.internalPointer());
62 switch (role) {
63 case Text: {
64 // qDebug() << "Getting text: " << part->property("text").toString();
65 // FIXME: we should have a list per part, and not one for all parts.
66 auto text = part->property("htmlContent").toString();
67 auto rx = QRegExp("src=(\"|')cid:([^\1]*)\1");
68 int pos = 0;
69 while ((pos = rx.indexIn(text, pos)) != -1) {
70 auto repl = mParser->getPart(rx.cap(2).toUtf8());
71 if (repl.isValid()) {
72 text.replace(rx.cap(0), QString("src=\"%1\"").arg(repl.toString()));
73 }
74 pos += rx.matchedLength();
75 }
76 return text;
77 }
78 case IsAttachment:
79 return part->property("attachment").toBool();
80 case IsEncrypted:
81 return part->property("isEncrypted").toBool();
82 case IsHtml:
83 return part->property("isHtml").toBool();
84 case HasContent:
85 return !part->property("htmlContent").toString().isEmpty();
86 case Type:
87 return part->metaObject()->className();
88 case IsHidden:
89 return false;
90 //return part->property("isHidden").toBool();
91
92 }
93 }
94 return QVariant();
95}
96
97QModelIndex PartModel::parent(const QModelIndex &index) const
98{
99 // qDebug() << "parent " << index;
100 if (index.isValid()) {
101 auto part = static_cast<MimeTreeParser::MessagePart*>(index.internalPointer());
102 auto parentPart = static_cast<MimeTreeParser::MessagePart*>(part->parentPart());
103 auto row = 0;//get the parents parent to find the index
104 if (!parentPart) {
105 parentPart = mPartTree.data();
106 }
107 int i = 0;
108 for (const auto &p : parentPart->subParts()) {
109 if (p.data() == part) {
110 row = i;
111 break;
112 }
113 i++;
114 }
115 return createIndex(row, index.column(), parentPart);
116 }
117 return QModelIndex();
118}
119
120int PartModel::rowCount(const QModelIndex &parent) const
121{
122 // qDebug() << "Row count " << parent;
123 if (!parent.isValid()) {
124 // qDebug() << "Row count " << mPartTree->subParts().size();
125 return mPartTree->subParts().size();
126 } else {
127 auto part = static_cast<MimeTreeParser::MessagePart*>(parent.internalPointer());
128 if (part) {
129 return part->subParts().size();
130 }
131 }
132 return 0;
133}
134
135int PartModel::columnCount(const QModelIndex &parent) const
136{
137 // qDebug() << "Column count " << parent;
138 return 1;
139}
140
diff --git a/framework/domain/mimetreeparser/CMakeLists.txt b/framework/domain/mimetreeparser/CMakeLists.txt
new file mode 100644
index 00000000..64da2656
--- /dev/null
+++ b/framework/domain/mimetreeparser/CMakeLists.txt
@@ -0,0 +1,15 @@
1set(mimetreeparser_SRCS
2 interface.cpp
3 objecttreesource.cpp
4 stringhtmlwriter.cpp
5)
6
7add_library(mimetreeparser SHARED ${mimetreeparser_SRCS})
8
9qt5_use_modules(mimetreeparser Core Gui)
10target_link_libraries(mimetreeparser KF5::Mime KF5::MimeTreeParser)
11
12install(TARGETS mimetreeparser
13 DESTINATION ${LIB_INSTALL_DIR})
14
15add_subdirectory(tests)
diff --git a/framework/domain/mimetreeparser/interface.cpp b/framework/domain/mimetreeparser/interface.cpp
new file mode 100644
index 00000000..efa0fd40
--- /dev/null
+++ b/framework/domain/mimetreeparser/interface.cpp
@@ -0,0 +1,833 @@
1/*
2 Copyright (c) 2016 Sandro Knauß <knauss@kolabsystems.com>
3
4 This library is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or (at your
7 option) any later version.
8
9 This library is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12 License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to the
16 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 02110-1301, USA.
18*/
19
20#include "interface.h"
21#include "interface_p.h"
22
23#include "stringhtmlwriter.h"
24#include "objecttreesource.h"
25
26#include <KMime/Content>
27#include <MimeTreeParser/ObjectTreeParser>
28#include <MimeTreeParser/MessagePart>
29#include <MimeTreeParser/NodeHelper>
30
31#include <QMimeDatabase>
32#include <QMimeType>
33#include <QTextCodec>
34#include <QDebug>
35
36class MailMimePrivate
37{
38public:
39 KMime::Content *mNode;
40 MailMime *q;
41};
42
43MailMime::MailMime()
44 : d(std::unique_ptr<MailMimePrivate>(new MailMimePrivate()))
45{
46 d->q = this;
47}
48
49bool MailMime::isFirstTextPart() const
50{
51 if (!d->mNode || !d->mNode->topLevel()) {
52 return false;
53 }
54 return (d->mNode->topLevel()->textContent() == d->mNode);
55}
56
57bool MailMime::isTopLevelPart() const
58{
59 if (!d->mNode) {
60 return false;
61 }
62 return (d->mNode->topLevel() == d->mNode);
63}
64
65MailMime::Disposition MailMime::disposition() const
66{
67 if (!d->mNode) {
68 return Invalid;
69 }
70 const auto cd = d->mNode->contentDisposition(false);
71 if (!cd) {
72 return Invalid;
73 }
74 switch (cd->disposition()){
75 case KMime::Headers::CDinline:
76 return Inline;
77 case KMime::Headers::CDattachment:
78 return Attachment;
79 default:
80 return Invalid;
81 }
82}
83
84QString MailMime::filename() const
85{
86 if (!d->mNode) {
87 return QString();
88 }
89 const auto cd = d->mNode->contentDisposition(false);
90 if (!cd) {
91 return QString();
92 }
93 return cd->filename();
94}
95
96QMimeType MailMime::mimetype() const
97{
98 if (!d->mNode) {
99 return QMimeType();
100 }
101
102 const auto ct = d->mNode->contentType(false);
103 if (!ct) {
104 return QMimeType();
105 }
106
107 QMimeDatabase mimeDb;
108 return mimeDb.mimeTypeForName(ct->mimeType());
109}
110
111class PartPrivate
112{
113public:
114 PartPrivate(Part *part);
115 void appendSubPart(Part::Ptr subpart);
116
117 QVector<Part::Ptr> subParts();
118
119 Part *parent() const;
120
121 const MailMime::Ptr &mailMime() const;
122 void createMailMime(const MimeTreeParser::MimeMessagePart::Ptr &part);
123 void createMailMime(const MimeTreeParser::TextMessagePart::Ptr &part);
124 void createMailMime(const MimeTreeParser::AlternativeMessagePart::Ptr &part);
125 void createMailMime(const MimeTreeParser::HtmlMessagePart::Ptr &part);
126
127 void appendEncryption(const MimeTreeParser::EncryptedMessagePart::Ptr &part);
128 void appendSignature(const MimeTreeParser::SignedMessagePart::Ptr &part);
129
130 void setSignatures(const QVector<Signature::Ptr> &sigs);
131 void setEncryptions(const QVector<Encryption::Ptr> &encs);
132
133 const QVector<Encryption::Ptr> &encryptions() const;
134 const QVector<Signature::Ptr> &signatures() const;
135private:
136 Part *q;
137 Part *mParent;
138 QVector<Part::Ptr> mSubParts;
139 QVector<Encryption::Ptr> mEncryptions;
140 QVector<Signature::Ptr> mSignatures;
141 MailMime::Ptr mMailMime;
142};
143
144PartPrivate::PartPrivate(Part* part)
145 : q(part)
146 , mParent(Q_NULLPTR)
147{
148
149}
150
151void PartPrivate::createMailMime(const MimeTreeParser::HtmlMessagePart::Ptr& part)
152{
153 mMailMime = MailMime::Ptr(new MailMime);
154 mMailMime->d->mNode = part->mNode;
155}
156
157void PartPrivate::createMailMime(const MimeTreeParser::AlternativeMessagePart::Ptr& part)
158{
159 mMailMime = MailMime::Ptr(new MailMime);
160 mMailMime->d->mNode = part->mNode;
161}
162
163void PartPrivate::createMailMime(const MimeTreeParser::TextMessagePart::Ptr& part)
164{
165 mMailMime = MailMime::Ptr(new MailMime);
166 mMailMime->d->mNode = part->mNode;
167}
168
169void PartPrivate::createMailMime(const MimeTreeParser::MimeMessagePart::Ptr& part)
170{
171 mMailMime = MailMime::Ptr(new MailMime);
172 mMailMime->d->mNode = part->mNode;
173}
174
175void PartPrivate::appendSubPart(Part::Ptr subpart)
176{
177 subpart->d->mParent = q;
178 mSubParts.append(subpart);
179}
180
181void PartPrivate::appendEncryption(const MimeTreeParser::EncryptedMessagePart::Ptr& part)
182{
183 mEncryptions.append(Encryption::Ptr(new Encryption));
184}
185
186void PartPrivate::setEncryptions(const QVector< Encryption::Ptr >& encs)
187{
188 mEncryptions = encs;
189}
190
191void PartPrivate::appendSignature(const MimeTreeParser::SignedMessagePart::Ptr& part)
192{
193 mSignatures.append(Signature::Ptr(new Signature));
194}
195
196
197void PartPrivate::setSignatures(const QVector< Signature::Ptr >& sigs)
198{
199 mSignatures = sigs;
200}
201
202Part *PartPrivate::parent() const
203{
204 return mParent;
205}
206
207QVector< Part::Ptr > PartPrivate::subParts()
208{
209 return mSubParts;
210}
211
212const MailMime::Ptr& PartPrivate::mailMime() const
213{
214 return mMailMime;
215}
216
217const QVector< Encryption::Ptr >& PartPrivate::encryptions() const
218{
219 return mEncryptions;
220}
221
222const QVector< Signature::Ptr >& PartPrivate::signatures() const
223{
224 return mSignatures;
225}
226
227Part::Part()
228 : d(std::unique_ptr<PartPrivate>(new PartPrivate(this)))
229{
230
231}
232
233bool Part::hasSubParts() const
234{
235 return !subParts().isEmpty();
236}
237
238QVector<Part::Ptr> Part::subParts() const
239{
240 return d->subParts();
241}
242
243QByteArray Part::type() const
244{
245 return "Part";
246}
247
248QVector<QByteArray> Part::availableContents() const
249{
250 return QVector<QByteArray>();
251}
252
253QVector<Content::Ptr> Part::content() const
254{
255 return content(availableContents().first());
256}
257
258QVector<Content::Ptr> Part::content(const QByteArray& ct) const
259{
260 return QVector<Content::Ptr>();
261}
262
263QVector<Encryption::Ptr> Part::encryptions() const
264{
265 auto ret = d->encryptions();
266 auto parent = d->parent();
267 if (parent) {
268 ret.append(parent->encryptions());
269 }
270 return ret;
271}
272
273QVector<Signature::Ptr> Part::signatures() const
274{
275 auto ret = d->signatures();
276 auto parent = d->parent();
277 if (parent) {
278 ret.append(parent->signatures());
279 }
280 return ret;
281}
282
283MailMime::Ptr Part::mailMime() const
284{
285 return d->mailMime();
286}
287
288class ContentPrivate
289{
290public:
291 QByteArray mContent;
292 QByteArray mCodec;
293 Part *mParent;
294 Content *q;
295 MailMime::Ptr mMailMime;
296 QVector<Encryption::Ptr> mEncryptions;
297 QVector<Signature::Ptr> mSignatures;
298 void appendSignature(const MimeTreeParser::SignedMessagePart::Ptr &sig);
299 void appendEncryption(const MimeTreeParser::EncryptedMessagePart::Ptr &enc);
300};
301
302void ContentPrivate::appendEncryption(const MimeTreeParser::EncryptedMessagePart::Ptr& enc)
303{
304 mEncryptions.append(Encryption::Ptr(new Encryption));
305}
306
307void ContentPrivate::appendSignature(const MimeTreeParser::SignedMessagePart::Ptr& sig)
308{
309 mSignatures.append(Signature::Ptr(new Signature));
310}
311
312
313Content::Content(const QByteArray& content, Part *parent)
314 : d(std::unique_ptr<ContentPrivate>(new ContentPrivate))
315{
316 d->q = this;
317 d->mContent = content;
318 d->mCodec = "utf-8";
319 d->mParent = parent;
320}
321
322Content::Content(ContentPrivate* d_ptr)
323 : d(std::unique_ptr<ContentPrivate>(d_ptr))
324{
325 d->q = this;
326}
327
328Content::~Content()
329{
330}
331
332QVector<Encryption::Ptr> Content::encryptions() const
333{
334 auto ret = d->mEncryptions;
335 if (d->mParent) {
336 ret.append(d->mParent->encryptions());
337 }
338 return ret;
339}
340
341QVector<Signature::Ptr> Content::signatures() const
342{
343 auto ret = d->mSignatures;
344 if (d->mParent) {
345 ret.append(d->mParent->signatures());
346 }
347 return ret;
348}
349
350QByteArray Content::content() const
351{
352 return d->mContent;
353}
354
355QByteArray Content::charset() const
356{
357 return d->mCodec;
358}
359
360QString Content::encodedContent() const
361{
362 return encodedContent(charset());
363}
364
365QString Content::encodedContent(const QByteArray &charset) const
366{
367 QTextCodec *codec = QTextCodec::codecForName(charset);
368 return codec->toUnicode(content());
369}
370
371QByteArray Content::type() const
372{
373 return "Content";
374}
375
376MailMime::Ptr Content::mailMime() const
377{
378 if (d->mMailMime) {
379 return d->mMailMime;
380 } else {
381 return d->mParent->mailMime();
382 }
383}
384
385Part *Content::parent() const
386{
387 return d->mParent;
388}
389
390HtmlContent::HtmlContent(const QByteArray& content, Part* parent)
391 : Content(content, parent)
392{
393
394}
395
396QByteArray HtmlContent::type() const
397{
398 return "HtmlContent";
399}
400
401PlainTextContent::PlainTextContent(const QByteArray& content, Part* parent)
402 : Content(content, parent)
403{
404
405}
406
407PlainTextContent::PlainTextContent(ContentPrivate* d_ptr)
408 : Content(d_ptr)
409{
410
411}
412
413HtmlContent::HtmlContent(ContentPrivate* d_ptr)
414 : Content(d_ptr)
415{
416
417}
418
419
420QByteArray PlainTextContent::type() const
421{
422 return "PlainTextContent";
423}
424
425class AlternativePartPrivate
426{
427public:
428 void fillFrom(MimeTreeParser::AlternativeMessagePart::Ptr part);
429
430 QVector<Content::Ptr> content(const QByteArray &ct) const;
431
432 AlternativePart *q;
433
434 QVector<QByteArray> types() const;
435
436private:
437 QMap<QByteArray, QVector<Content::Ptr>> mContent;
438 QVector<QByteArray> mTypes;
439};
440
441void AlternativePartPrivate::fillFrom(MimeTreeParser::AlternativeMessagePart::Ptr part)
442{
443 mTypes = QVector<QByteArray>() << "html" << "plaintext";
444
445 Content::Ptr content = std::make_shared<HtmlContent>(part->htmlContent().toLocal8Bit(), q);
446 mContent["html"].append(content);
447 content = std::make_shared<PlainTextContent>(part->plaintextContent().toLocal8Bit(), q);
448 mContent["plaintext"].append(content);
449 q->reachParentD()->createMailMime(part);
450}
451
452QVector<QByteArray> AlternativePartPrivate::types() const
453{
454 return mTypes;
455}
456
457QVector<Content::Ptr> AlternativePartPrivate::content(const QByteArray& ct) const
458{
459 return mContent[ct];
460}
461
462AlternativePart::AlternativePart()
463 : d(std::unique_ptr<AlternativePartPrivate>(new AlternativePartPrivate))
464{
465 d->q = this;
466}
467
468AlternativePart::~AlternativePart()
469{
470
471}
472
473QByteArray AlternativePart::type() const
474{
475 return "AlternativePart";
476}
477
478QVector<QByteArray> AlternativePart::availableContents() const
479{
480 return d->types();
481}
482
483QVector<Content::Ptr> AlternativePart::content(const QByteArray& ct) const
484{
485 return d->content(ct);
486}
487
488PartPrivate* AlternativePart::reachParentD() const
489{
490 return Part::d.get();
491}
492
493class SinglePartPrivate
494{
495public:
496 void fillFrom(MimeTreeParser::TextMessagePart::Ptr part);
497 void fillFrom(MimeTreeParser::HtmlMessagePart::Ptr part);
498 void fillFrom(MimeTreeParser::AttachmentMessagePart::Ptr part);
499 SinglePart *q;
500
501 QVector<Content::Ptr> mContent;
502 QByteArray mType;
503};
504
505void SinglePartPrivate::fillFrom(MimeTreeParser::TextMessagePart::Ptr part)
506{
507 mType = "plaintext";
508 mContent.clear();
509 foreach (const auto &mp, part->subParts()) {
510 auto d_ptr = new ContentPrivate;
511 d_ptr->mContent = mp->text().toLocal8Bit();
512 d_ptr->mParent = q;
513 d_ptr->mCodec = "utf-8";
514 const auto enc = mp.dynamicCast<MimeTreeParser::EncryptedMessagePart>();
515 auto sig = mp.dynamicCast<MimeTreeParser::SignedMessagePart>();
516 if (enc) {
517 d_ptr->appendEncryption(enc);
518 const auto s = enc->subParts();
519 if (s.size() == 1) {
520 sig = s[0].dynamicCast<MimeTreeParser::SignedMessagePart>();
521 }
522 }
523 if (sig) {
524 d_ptr->appendSignature(sig);
525 }
526 mContent.append(std::make_shared<PlainTextContent>(d_ptr));
527 q->reachParentD()->createMailMime(part);
528 }
529}
530
531void SinglePartPrivate::fillFrom(MimeTreeParser::HtmlMessagePart::Ptr part)
532{
533 mType = "html";
534 mContent.clear();
535 mContent.append(std::make_shared<HtmlContent>(part->text().toLocal8Bit(), q));
536 q->reachParentD()->createMailMime(part);
537}
538
539void SinglePartPrivate::fillFrom(MimeTreeParser::AttachmentMessagePart::Ptr part)
540{
541 q->reachParentD()->createMailMime(part.staticCast<MimeTreeParser::TextMessagePart>());
542 mType = q->mailMime()->mimetype().name().toUtf8();
543 mContent.clear();
544 mContent.append(std::make_shared<Content>(part->text().toLocal8Bit(), q));
545}
546
547SinglePart::SinglePart()
548 : d(std::unique_ptr<SinglePartPrivate>(new SinglePartPrivate))
549{
550 d->q = this;
551}
552
553SinglePart::~SinglePart()
554{
555
556}
557
558QVector<QByteArray> SinglePart::availableContents() const
559{
560 return QVector<QByteArray>() << d->mType;
561}
562
563QVector< Content::Ptr > SinglePart::content(const QByteArray &ct) const
564{
565 if (ct == d->mType) {
566 return d->mContent;
567 }
568 return QVector<Content::Ptr>();
569}
570
571QByteArray SinglePart::type() const
572{
573 return "SinglePart";
574}
575
576PartPrivate* SinglePart::reachParentD() const
577{
578 return Part::d.get();
579}
580
581class SignaturePrivate
582{
583public:
584 Signature *q;
585};
586
587Signature::Signature()
588 :d(std::unique_ptr<SignaturePrivate>(new SignaturePrivate))
589{
590 d->q = this;
591}
592
593
594Signature::Signature(SignaturePrivate *d_ptr)
595 :d(std::unique_ptr<SignaturePrivate>(d_ptr))
596{
597 d->q = this;
598}
599
600Signature::~Signature()
601{
602
603}
604
605
606class EncryptionPrivate
607{
608public:
609 Encryption *q;
610};
611
612Encryption::Encryption(EncryptionPrivate *d_ptr)
613 :d(std::unique_ptr<EncryptionPrivate>(d_ptr))
614{
615 d->q = this;
616}
617
618Encryption::Encryption()
619 :d(std::unique_ptr<EncryptionPrivate>(new EncryptionPrivate))
620{
621 d->q = this;
622}
623
624Encryption::~Encryption()
625{
626
627}
628
629ParserPrivate::ParserPrivate(Parser* parser)
630 : q(parser)
631 , mNodeHelper(std::make_shared<MimeTreeParser::NodeHelper>())
632{
633
634}
635
636void ParserPrivate::setMessage(const QByteArray& mimeMessage)
637{
638 const auto mailData = KMime::CRLFtoLF(mimeMessage);
639 mMsg = KMime::Message::Ptr(new KMime::Message);
640 mMsg->setContent(mailData);
641 mMsg->parse();
642
643 // render the mail
644 StringHtmlWriter htmlWriter;
645 ObjectTreeSource source(&htmlWriter);
646 MimeTreeParser::ObjectTreeParser otp(&source, mNodeHelper.get());
647
648 otp.parseObjectTree(mMsg.data());
649 mPartTree = otp.parsedPart().dynamicCast<MimeTreeParser::MessagePart>();
650
651 mEmbeddedPartMap = htmlWriter.embeddedParts();
652 mHtml = htmlWriter.html();
653
654 mTree = std::make_shared<Part>();
655 createTree(mPartTree, mTree);
656}
657
658
659void ParserPrivate::createTree(const MimeTreeParser::MessagePart::Ptr &start, const Part::Ptr &tree)
660{
661 foreach (const auto &mp, start->subParts()) {
662 const auto m = mp.dynamicCast<MimeTreeParser::MessagePart>();
663 const auto text = mp.dynamicCast<MimeTreeParser::TextMessagePart>();
664 const auto alternative = mp.dynamicCast<MimeTreeParser::AlternativeMessagePart>();
665 const auto html = mp.dynamicCast<MimeTreeParser::HtmlMessagePart>();
666 const auto attachment = mp.dynamicCast<MimeTreeParser::AttachmentMessagePart>();
667 if (attachment) {
668 auto part = std::make_shared<SinglePart>();
669 part->d->fillFrom(attachment);
670 tree->d->appendSubPart(part);
671 } else if (text) {
672 auto part = std::make_shared<SinglePart>();
673 part->d->fillFrom(text);
674 tree->d->appendSubPart(part);
675 } else if (alternative) {
676 auto part = std::make_shared<AlternativePart>();
677 part->d->fillFrom(alternative);
678 tree->d->appendSubPart(part);
679 } else if (html) {
680 auto part = std::make_shared<SinglePart>();
681 part->d->fillFrom(html);
682 tree->d->appendSubPart(part);
683 } else {
684 const auto enc = mp.dynamicCast<MimeTreeParser::EncryptedMessagePart>();
685 const auto sig = mp.dynamicCast<MimeTreeParser::SignedMessagePart>();
686 if (enc || sig) {
687 auto subTree = std::make_shared<Part>();
688 if (enc) {
689 subTree->d->appendEncryption(enc);
690 }
691 if (sig) {
692 subTree->d->appendSignature(sig);
693 }
694 createTree(m, subTree);
695 foreach(const auto &p, subTree->subParts()) {
696 tree->d->appendSubPart(p);
697 if (enc) {
698 p->d->setEncryptions(subTree->d->encryptions());
699 }
700 if (sig) {
701 p->d->setSignatures(subTree->d->signatures());
702 }
703 }
704 } else {
705 createTree(m, tree);
706 }
707 }
708 }
709}
710
711Parser::Parser(const QByteArray& mimeMessage)
712 :d(std::unique_ptr<ParserPrivate>(new ParserPrivate(this)))
713{
714 d->setMessage(mimeMessage);
715}
716
717Parser::~Parser()
718{
719}
720
721QUrl Parser::getPart(const QByteArray &cid)
722{
723 return d->mEmbeddedPartMap.value(cid);
724}
725
726QVector<Part::Ptr> Parser::collectContentParts() const
727{
728 return collect(d->mTree, [](const Part::Ptr &p){return p->type() != "EncapsulatedPart";},
729 [](const Content::Ptr &content){
730 const auto mime = content->mailMime();
731
732 if (!mime) {
733 return true;
734 }
735
736 if (mime->isFirstTextPart()) {
737 return true;
738 }
739
740 {
741 const auto parent = content->parent();
742 if (parent) {
743 const auto _mime = parent->mailMime();
744 if (_mime && (_mime->isTopLevelPart() || _mime->isFirstTextPart())) {
745 return true;
746 }
747 }
748 }
749 const auto cd = mime->disposition();
750 if (cd && cd == MailMime::Inline) {
751 // explict "inline" disposition:
752 return true;
753 }
754 if (cd && cd == MailMime::Attachment) {
755 // explicit "attachment" disposition:
756 return false;
757 }
758
759 const auto ct = mime->mimetype();
760 if (ct.name().trimmed().toLower() == "text" && ct.name().trimmed().isEmpty() &&
761 (!mime || mime->filename().trimmed().isEmpty())) {
762 // text/* w/o filename parameter:
763 return true;
764 }
765 return false;
766 });
767}
768
769
770QVector<Part::Ptr> Parser::collectAttachmentParts() const
771{
772 return collect(d->mTree, [](const Part::Ptr &p){return p->type() != "EncapsulatedPart";},
773 [](const Content::Ptr &content){
774 const auto mime = content->mailMime();
775
776 if (!mime) {
777 return false;
778 }
779
780 if (mime->isFirstTextPart()) {
781 return false;
782 }
783
784 {
785 const auto parent = content->parent();
786 if (parent) {
787 const auto _mime = parent->mailMime();
788 if (_mime && (_mime->isTopLevelPart() || _mime->isFirstTextPart())) {
789 return false;
790 }
791 }
792 }
793 const auto cd = mime->disposition();
794 if (cd && cd == MailMime::Inline) {
795 // explict "inline" disposition:
796 return false;
797 }
798 if (cd && cd == MailMime::Attachment) {
799 // explicit "attachment" disposition:
800 return true;
801 }
802
803 const auto ct = mime->mimetype();
804 if (ct.name().trimmed().toLower() == "text" && ct.name().trimmed().isEmpty() &&
805 (!mime || mime->filename().trimmed().isEmpty())) {
806 // text/* w/o filename parameter:
807 return false;
808 }
809 return true;
810 });
811}
812QVector<Part::Ptr> Parser::collect(const Part::Ptr &start, std::function<bool(const Part::Ptr &)> select, std::function<bool(const Content::Ptr &)> filter) const
813{
814 QVector<Part::Ptr> ret;
815 foreach (const auto &part, start->subParts()) {
816 QVector<QByteArray> contents;
817 foreach(const auto &ct, part->availableContents()) {
818 foreach(const auto &content, part->content(ct)) {
819 if (filter(content)) {
820 contents.append(ct);
821 break;
822 }
823 }
824 }
825 if (!contents.isEmpty()) {
826 ret.append(part);
827 }
828 if (select(part)){
829 ret += collect(part, select, filter);
830 }
831 }
832 return ret;
833} \ No newline at end of file
diff --git a/framework/domain/mimetreeparser/interface.h b/framework/domain/mimetreeparser/interface.h
new file mode 100644
index 00000000..67246f37
--- /dev/null
+++ b/framework/domain/mimetreeparser/interface.h
@@ -0,0 +1,368 @@
1/*
2 Copyright (c) 2016 Sandro Knauß <knauss@kolabsystems.com>
3
4 This library is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or (at your
7 option) any later version.
8
9 This library is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12 License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to the
16 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 02110-1301, USA.
18*/
19
20#pragma once
21
22#include <functional>
23#include <memory>
24
25#include <QDateTime>
26#include <QUrl>
27#include <QMimeType>
28
29class Part;
30class PartPrivate;
31
32class MailMime;
33class MailMimePrivate;
34
35class AlternativePart;
36class AlternativePartPrivate;
37
38class SinglePart;
39class SinglePartPrivate;
40
41class EncryptionPart;
42class EncryptionPartPrivate;
43
44class EncapsulatedPart;
45class EncapsulatedPartPrivate;
46
47class Content;
48class ContentPrivate;
49
50class CertContent;
51class CertContentPrivate;
52
53class EncryptionError;
54
55class Key;
56class Signature;
57class SignaturePrivate;
58class Encryption;
59class EncryptionPrivate;
60
61typedef std::shared_ptr<Signature> SignaturePtr;
62typedef std::shared_ptr<Encryption> EncryptionPtr;
63
64class Parser;
65class ParserPrivate;
66
67/*
68 * A MessagePart that is based on a KMime::Content
69 */
70class MailMime
71{
72public:
73 typedef std::shared_ptr<MailMime> Ptr;
74 /**
75 * Various possible values for the "Content-Disposition" header.
76 */
77 enum Disposition {
78 Invalid, ///< Default, invalid value
79 Inline, ///< inline
80 Attachment ///< attachment
81 };
82
83 MailMime();
84
85 // interessting header parts of a KMime::Content
86 QMimeType mimetype() const;
87 Disposition disposition() const;
88 QUrl label() const;
89 QByteArray cid() const;
90 QByteArray charset() const;
91 QString filename() const;
92
93 // Unique identifier to ecactly this KMime::Content
94 QByteArray link() const;
95
96 QByteArray content() const;
97 //Use default charset
98 QString encodedContent() const;
99
100 // overwrite default charset with given charset
101 QString encodedContent(QByteArray charset) const;
102
103 bool isFirstTextPart() const;
104 bool isTopLevelPart() const;
105
106private:
107 std::unique_ptr<MailMimePrivate> d;
108
109 friend class PartPrivate;
110};
111
112class Content
113{
114public:
115 typedef std::shared_ptr<Content> Ptr;
116 Content(const QByteArray &content, Part *parent);
117 Content(ContentPrivate *d_ptr);
118 virtual ~Content();
119
120 QByteArray content() const;
121
122 QByteArray charset() const;
123
124 //Use default charset
125 QString encodedContent() const;
126
127 // overwrite default charset with given charset
128 QString encodedContent(const QByteArray &charset) const;
129
130 QVector<SignaturePtr> signatures() const;
131 QVector<EncryptionPtr> encryptions() const;
132 MailMime::Ptr mailMime() const;
133 virtual QByteArray type() const;
134 Part* parent() const;
135private:
136 std::unique_ptr<ContentPrivate> d;
137};
138
139class PlainTextContent : public Content
140{
141public:
142 PlainTextContent(const QByteArray &content, Part *parent);
143 PlainTextContent(ContentPrivate *d_ptr);
144 QByteArray type() const Q_DECL_OVERRIDE;
145};
146
147class HtmlContent : public Content
148{
149public:
150 HtmlContent(const QByteArray &content, Part *parent);
151 HtmlContent(ContentPrivate* d_ptr);
152 QByteArray type() const Q_DECL_OVERRIDE;
153};
154
155/*
156 * importing a cert GpgMe::ImportResult
157 * checking a cert (if it is a valid cert)
158 */
159
160class CertContent : public Content
161{
162public:
163 typedef std::shared_ptr<CertContent> Ptr;
164 CertContent(const QByteArray &content, Part *parent);
165
166 QByteArray type() const Q_DECL_OVERRIDE;
167 enum CertType {
168 Pgp,
169 SMime
170 };
171
172 enum CertSubType {
173 Public,
174 Private
175 };
176
177 CertType certType() const;
178 CertSubType certSubType() const;
179 int keyLength() const;
180
181private:
182 std::unique_ptr<CertContentPrivate> d;
183};
184
185class Part
186{
187public:
188 typedef std::shared_ptr<Part> Ptr;
189 Part();
190 virtual QByteArray type() const;
191
192 virtual QVector<QByteArray> availableContents() const;
193 virtual QVector<Content::Ptr> content(const QByteArray& ct) const;
194 QVector<Content::Ptr> content() const;
195
196 bool hasSubParts() const;
197 QVector<Part::Ptr> subParts() const;
198 Part *parent() const;
199
200 QVector<SignaturePtr> signatures() const;
201 QVector<EncryptionPtr> encryptions() const;
202 virtual MailMime::Ptr mailMime() const;
203protected:
204 std::unique_ptr<PartPrivate> d;
205private:
206 friend class ParserPrivate;
207 friend class PartPrivate;
208};
209
210class AlternativePart : public Part
211{
212public:
213 typedef std::shared_ptr<AlternativePart> Ptr;
214
215 AlternativePart();
216 virtual ~AlternativePart();
217
218 QVector<QByteArray> availableContents() const Q_DECL_OVERRIDE;
219 QVector<Content::Ptr> content(const QByteArray& ct) const Q_DECL_OVERRIDE;
220
221 QByteArray type() const Q_DECL_OVERRIDE;
222
223private:
224 PartPrivate *reachParentD() const;
225 std::unique_ptr<AlternativePartPrivate> d;
226
227 friend class ParserPrivate;
228 friend class AlternativePartPrivate;
229};
230
231class SinglePart : public Part
232{
233 public:
234 typedef std::shared_ptr<SinglePart> Ptr;
235
236 SinglePart();
237 virtual ~SinglePart();
238
239 QVector<Content::Ptr> content(const QByteArray& ct) const Q_DECL_OVERRIDE;
240 QVector<QByteArray> availableContents() const Q_DECL_OVERRIDE;
241
242 QByteArray type() const Q_DECL_OVERRIDE;
243private:
244 PartPrivate *reachParentD() const;
245 std::unique_ptr<SinglePartPrivate> d;
246
247 friend class ParserPrivate;
248 friend class SinglePartPrivate;
249};
250
251
252class EncryptionPart : public Part
253{
254public:
255 typedef std::shared_ptr<EncryptionPart> Ptr;
256 QByteArray type() const Q_DECL_OVERRIDE;
257
258 EncryptionError error() const;
259private:
260 std::unique_ptr<EncryptionPartPrivate> d;
261};
262
263
264/*
265 * we want to request complete headers like:
266 * from/to...
267 */
268
269class EncapsulatedPart : public SinglePart
270{
271public:
272 typedef std::shared_ptr<EncapsulatedPart> Ptr;
273 QByteArray type() const Q_DECL_OVERRIDE;
274
275 //template <class T> QByteArray header<T>();
276private:
277 std::unique_ptr<EncapsulatedPartPrivate> d;
278};
279
280class EncryptionError
281{
282public:
283 int errorId() const;
284 QString errorString() const;
285};
286
287class Key
288{
289 QString keyid() const;
290 QString name() const;
291 QString email() const;
292 QString comment() const;
293 QVector<QString> emails() const;
294 enum KeyTrust {
295 Unknown, Undefined, Never, Marginal, Full, Ultimate
296 };
297 KeyTrust keyTrust() const;
298
299 bool isRevokation() const;
300 bool isInvalid() const;
301 bool isExpired() const;
302
303 std::vector<Key> subkeys();
304 Key parentkey() const;
305};
306
307class Signature
308{
309public:
310 typedef std::shared_ptr<Signature> Ptr;
311 Signature();
312 Signature(SignaturePrivate *);
313 ~Signature();
314
315 Key key() const;
316 QDateTime creationDateTime() const;
317 QDateTime expirationTime() const;
318 bool neverExpires() const;
319
320 //template <> StatusObject<SignatureVerificationResult> verify() const;
321 private:
322 std::unique_ptr<SignaturePrivate> d;
323};
324
325/*
326 * Normally the Keys for encryption are subkeys
327 * for clients the parentkeys are "more interessting", because they store the name, email etc.
328 * but a client may also wants show to what subkey the mail is really encrypted, an if this subkey isRevoked or something else
329 */
330class Encryption
331{
332public:
333 typedef std::shared_ptr<Encryption> Ptr;
334 Encryption();
335 Encryption(EncryptionPrivate *);
336 ~Encryption();
337 std::vector<Key> recipients() const;
338private:
339 std::unique_ptr<EncryptionPrivate> d;
340};
341
342class Parser
343{
344public:
345 typedef std::shared_ptr<Parser> Ptr;
346 Parser(const QByteArray &mimeMessage);
347 ~Parser();
348
349 Part::Ptr getPart(QUrl url);
350 QUrl getPart(const QByteArray &cid);
351
352 QVector<Part::Ptr> collect(const Part::Ptr &start, std::function<bool(const Part::Ptr &)> select, std::function<bool(const Content::Ptr &)> filter) const;
353 QVector<Part::Ptr> collectContentParts() const;
354 QVector<Part::Ptr> collectAttachmentParts() const;
355 //template <> QVector<ContentPart::Ptr> collect<ContentPart>() const;
356
357 //template <> static StatusObject<SignatureVerificationResult> verifySignature(const Signature signature) const;
358 //template <> static StatusObject<Part> decrypt(const EncryptedPart part) const;
359
360signals:
361 void partsChanged();
362
363private:
364 std::unique_ptr<ParserPrivate> d;
365
366 friend class InterfaceTest;
367};
368
diff --git a/framework/domain/mimetreeparser/interface_p.h b/framework/domain/mimetreeparser/interface_p.h
new file mode 100644
index 00000000..55d1a5cc
--- /dev/null
+++ b/framework/domain/mimetreeparser/interface_p.h
@@ -0,0 +1,56 @@
1/*
2 Copyright (c) 2016 Sandro Knauß <knauss@kolabsystems.com>
3
4 This library is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or (at your
7 option) any later version.
8
9 This library is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12 License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to the
16 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 02110-1301, USA.
18*/
19
20#pragma once
21
22#include "interface.h"
23
24#include <QSharedPointer>
25#include <QMap>
26
27namespace KMime
28{
29 class Message;
30 typedef QSharedPointer<Message> MessagePtr;
31}
32
33namespace MimeTreeParser
34{
35 class MessagePart;
36 class NodeHelper;
37 typedef QSharedPointer<MessagePart> MessagePartPtr;
38}
39
40class ParserPrivate
41{
42public:
43 ParserPrivate(Parser *parser);
44
45 void setMessage(const QByteArray &mimeMessage);
46 void createTree(const MimeTreeParser::MessagePartPtr& start, const Part::Ptr& tree);
47
48 Part::Ptr mTree;
49 Parser *q;
50
51 MimeTreeParser::MessagePartPtr mPartTree;
52 KMime::MessagePtr mMsg;
53 std::shared_ptr<MimeTreeParser::NodeHelper> mNodeHelper;
54 QString mHtml;
55 QMap<QByteArray, QUrl> mEmbeddedPartMap;
56}; \ No newline at end of file
diff --git a/framework/domain/mimetreeparser/objecttreesource.cpp b/framework/domain/mimetreeparser/objecttreesource.cpp
new file mode 100644
index 00000000..58667444
--- /dev/null
+++ b/framework/domain/mimetreeparser/objecttreesource.cpp
@@ -0,0 +1,147 @@
1/*
2 Copyright (C) 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net
3 Copyright (c) 2009 Andras Mantia <andras@kdab.net>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18*/
19
20#include "objecttreesource.h"
21
22#include <MimeTreeParser/AttachmentStrategy>
23#include <MimeTreeParser/BodyPartFormatterBaseFactory>
24#include <MimeTreeParser/MessagePart>
25#include <MimeTreeParser/MessagePartRenderer>
26
27class ObjectSourcePrivate
28{
29public:
30 ObjectSourcePrivate()
31 : mWriter(0)
32 , mAllowDecryption(true)
33 , mHtmlLoadExternal(true)
34 , mPreferredMode(MimeTreeParser::Util::Html)
35 {
36
37 }
38 MimeTreeParser::HtmlWriter *mWriter;
39 MimeTreeParser::BodyPartFormatterBaseFactory mBodyPartFormatterBaseFactory;
40 bool mAllowDecryption;
41 bool mHtmlLoadExternal;
42 MimeTreeParser::Util::HtmlMode mPreferredMode;
43};
44
45ObjectTreeSource::ObjectTreeSource(MimeTreeParser::HtmlWriter *writer)
46 : MimeTreeParser::Interface::ObjectTreeSource()
47 , d(new ObjectSourcePrivate)
48 {
49 d->mWriter = writer;
50 }
51
52ObjectTreeSource::~ObjectTreeSource()
53{
54 delete d;
55}
56
57void ObjectTreeSource::setAllowDecryption(bool allowDecryption)
58{
59 d->mAllowDecryption = allowDecryption;
60}
61
62MimeTreeParser::HtmlWriter *ObjectTreeSource::htmlWriter()
63{
64 return d->mWriter;
65}
66
67bool ObjectTreeSource::htmlLoadExternal() const
68{
69 return d->mHtmlLoadExternal;
70}
71
72void ObjectTreeSource::setHtmlLoadExternal(bool loadExternal)
73{
74 d->mHtmlLoadExternal = loadExternal;
75}
76
77bool ObjectTreeSource::decryptMessage() const
78{
79 return d->mAllowDecryption;
80}
81
82bool ObjectTreeSource::showSignatureDetails() const
83{
84 return true;
85}
86
87int ObjectTreeSource::levelQuote() const
88{
89 return 1;
90}
91
92const QTextCodec *ObjectTreeSource::overrideCodec()
93{
94 return Q_NULLPTR;
95}
96
97QString ObjectTreeSource::createMessageHeader(KMime::Message *message)
98{
99 return QString();
100}
101
102const MimeTreeParser::AttachmentStrategy *ObjectTreeSource::attachmentStrategy()
103{
104 return MimeTreeParser::AttachmentStrategy::smart();
105}
106
107QObject *ObjectTreeSource::sourceObject()
108{
109 return Q_NULLPTR;
110}
111
112void ObjectTreeSource::setHtmlMode(MimeTreeParser::Util::HtmlMode mode, const QList<MimeTreeParser::Util::HtmlMode> &availableModes)
113{
114 Q_UNUSED(mode);
115 Q_UNUSED(availableModes);
116}
117
118MimeTreeParser::Util::HtmlMode ObjectTreeSource::preferredMode() const
119{
120 return d->mPreferredMode;
121}
122
123bool ObjectTreeSource::autoImportKeys() const
124{
125 return false;
126}
127
128bool ObjectTreeSource::showEmoticons() const
129{
130 return false;
131}
132
133bool ObjectTreeSource::showExpandQuotesMark() const
134{
135 return false;
136}
137
138const MimeTreeParser::BodyPartFormatterBaseFactory *ObjectTreeSource::bodyPartFormatterFactory()
139{
140 return &(d->mBodyPartFormatterBaseFactory);
141}
142
143MimeTreeParser::Interface::MessagePartRenderer::Ptr ObjectTreeSource::messagePartTheme(MimeTreeParser::Interface::MessagePart::Ptr msgPart)
144{
145 Q_UNUSED(msgPart);
146 return MimeTreeParser::Interface::MessagePartRenderer::Ptr();
147}
diff --git a/framework/domain/mimetreeparser/objecttreesource.h b/framework/domain/mimetreeparser/objecttreesource.h
new file mode 100644
index 00000000..42433e71
--- /dev/null
+++ b/framework/domain/mimetreeparser/objecttreesource.h
@@ -0,0 +1,56 @@
1/*
2 Copyright (C) 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net
3 Copyright (c) 2009 Andras Mantia <andras@kdab.net>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18*/
19
20#ifndef MAILVIEWER_OBJECTTREEEMPTYSOURCE_H
21#define MAILVIEWER_OBJECTTREEEMPTYSOURCE_H
22
23#include <MimeTreeParser/ObjectTreeSource>
24
25class QString;
26
27class ObjectSourcePrivate;
28class ObjectTreeSource : public MimeTreeParser::Interface::ObjectTreeSource
29{
30public:
31 ObjectTreeSource(MimeTreeParser::HtmlWriter *writer);
32 virtual ~ObjectTreeSource();
33 void setHtmlLoadExternal(bool loadExternal);
34 bool decryptMessage() const Q_DECL_OVERRIDE;
35 bool htmlLoadExternal() const Q_DECL_OVERRIDE;
36 bool showSignatureDetails() const Q_DECL_OVERRIDE;
37 void setHtmlMode(MimeTreeParser::Util::HtmlMode mode, const QList<MimeTreeParser::Util::HtmlMode> &availableModes) Q_DECL_OVERRIDE;
38 MimeTreeParser::Util::HtmlMode preferredMode() const Q_DECL_OVERRIDE;
39 void setAllowDecryption(bool allowDecryption);
40 int levelQuote() const Q_DECL_OVERRIDE;
41 const QTextCodec *overrideCodec() Q_DECL_OVERRIDE;
42 QString createMessageHeader(KMime::Message *message) Q_DECL_OVERRIDE;
43 const MimeTreeParser::AttachmentStrategy *attachmentStrategy() Q_DECL_OVERRIDE;
44 MimeTreeParser::HtmlWriter *htmlWriter() Q_DECL_OVERRIDE;
45 QObject *sourceObject() Q_DECL_OVERRIDE;
46 bool autoImportKeys() const Q_DECL_OVERRIDE;
47 bool showEmoticons() const Q_DECL_OVERRIDE;
48 bool showExpandQuotesMark() const Q_DECL_OVERRIDE;
49 const MimeTreeParser::BodyPartFormatterBaseFactory *bodyPartFormatterFactory() Q_DECL_OVERRIDE;
50 MimeTreeParser::Interface::MessagePartRendererPtr messagePartTheme(MimeTreeParser::Interface::MessagePartPtr msgPart) Q_DECL_OVERRIDE;
51private:
52 ObjectSourcePrivate *const d;
53};
54
55#endif
56
diff --git a/framework/domain/mimetreeparser/stringhtmlwriter.cpp b/framework/domain/mimetreeparser/stringhtmlwriter.cpp
new file mode 100644
index 00000000..88034492
--- /dev/null
+++ b/framework/domain/mimetreeparser/stringhtmlwriter.cpp
@@ -0,0 +1,150 @@
1/* -*- c++ -*-
2 filehtmlwriter.cpp
3
4 This file is part of KMail, the KDE mail client.
5 Copyright (c) 2003 Marc Mutz <mutz@kde.org>
6
7 KMail is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License, version 2, as
9 published by the Free Software Foundation.
10
11 KMail is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
20 In addition, as a special exception, the copyright holders give
21 permission to link the code of this program with any edition of
22 the Qt library by Trolltech AS, Norway (or with modified versions
23 of Qt that use the same license as Qt), and distribute linked
24 combinations including the two. You must obey the GNU General
25 Public License in all respects for all of the code used other than
26 Qt. If you modify this file, you may extend this exception to
27 your version of the file, but you are not obligated to do so. If
28 you do not wish to do so, delete this exception statement from
29 your version.
30*/
31
32#include "stringhtmlwriter.h"
33
34#include <QDebug>
35#include <QTextStream>
36#include <QUrl>
37
38StringHtmlWriter::StringHtmlWriter()
39 : MimeTreeParser::HtmlWriter()
40 , mState(Ended)
41{
42}
43
44StringHtmlWriter::~StringHtmlWriter()
45{
46}
47
48void StringHtmlWriter::begin(const QString &css)
49{
50 if (mState != Ended) {
51 qWarning() << "begin() called on non-ended session!";
52 reset();
53 }
54
55 mState = Begun;
56 mExtraHead.clear();
57 mHtml.clear();
58
59 if (!css.isEmpty()) {
60 write(QLatin1String("<!-- CSS Definitions \n") + css + QLatin1String("-->\n"));
61 }
62}
63
64void StringHtmlWriter::end()
65{
66 if (mState != Begun) {
67 qWarning() << "Called on non-begun or queued session!";
68 }
69
70 if (!mExtraHead.isEmpty()) {
71 insertExtraHead();
72 mExtraHead.clear();
73 }
74 resolveCidUrls();
75 mState = Ended;
76}
77
78void StringHtmlWriter::reset()
79{
80 if (mState != Ended) {
81 mHtml.clear();
82 mExtraHead.clear();
83 mState = Begun; // don't run into end()'s warning
84 end();
85 mState = Ended;
86 }
87}
88
89void StringHtmlWriter::write(const QString &str)
90{
91 if (mState != Begun) {
92 qWarning() << "Called in Ended or Queued state!";
93 }
94 mHtml.append(str);
95}
96
97void StringHtmlWriter::queue(const QString &str)
98{
99 write(str);
100}
101
102void StringHtmlWriter::flush()
103{
104 mState = Begun; // don't run into end()'s warning
105 end();
106}
107
108void StringHtmlWriter::embedPart(const QByteArray &contentId, const QString &url)
109{
110 write("<!-- embedPart(contentID=" + contentId + ", url=" + url + ") -->\n");
111 mEmbeddedPartMap.insert(contentId, url);
112}
113
114void StringHtmlWriter::resolveCidUrls()
115{
116 for (const auto &cid : mEmbeddedPartMap.keys()) {
117 mHtml.replace(QString("src=\"cid:%1\"").arg(QString(cid)), QString("src=\"%1\"").arg(mEmbeddedPartMap.value(cid).toString()));
118 }
119}
120
121void StringHtmlWriter::extraHead(const QString &extraHead)
122{
123 if (mState != Ended) {
124 qWarning() << "Called on non-started session!";
125 }
126 mExtraHead.append(extraHead);
127}
128
129
130void StringHtmlWriter::insertExtraHead()
131{
132 const QString headTag(QStringLiteral("<head>"));
133 const int index = mHtml.indexOf(headTag);
134 if (index != -1) {
135 mHtml.insert(index + headTag.length(), mExtraHead);
136 }
137}
138
139QMap<QByteArray, QUrl> StringHtmlWriter::embeddedParts() const
140{
141 return mEmbeddedPartMap;
142}
143
144QString StringHtmlWriter::html() const
145{
146 if (mState != Ended) {
147 qWarning() << "Called on non-ended session!";
148 }
149 return mHtml;
150}
diff --git a/framework/domain/mimetreeparser/stringhtmlwriter.h b/framework/domain/mimetreeparser/stringhtmlwriter.h
new file mode 100644
index 00000000..fa5b760e
--- /dev/null
+++ b/framework/domain/mimetreeparser/stringhtmlwriter.h
@@ -0,0 +1,71 @@
1/* -*- c++ -*-
2
3 Copyright (c) 2016 Sandro Knauß <sknauss@kde.org>
4
5 Kube is free software; you can redistribute it and/or modify it
6 under the terms of the GNU General Public License, version 2, as
7 published by the Free Software Foundation.
8
9 Kube is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
18 In addition, as a special exception, the copyright holders give
19 permission to link the code of this program with any edition of
20 the Qt library by Trolltech AS, Norway (or with modified versions
21 of Qt that use the same license as Qt), and distribute linked
22 combinations including the two. You must obey the GNU General
23 Public License in all respects for all of the code used other than
24 Qt. If you modify this file, you may extend this exception to
25 your version of the file, but you are not obligated to do so. If
26 you do not wish to do so, delete this exception statement from
27 your version.
28*/
29
30#ifndef __KUBE_FRAMEWORK_MAIL_STRINGHTMLWRITER_H__
31#define __KUBE_FRAMEWORK_MAIL_STRINGHTMLWRITER_H__
32
33#include <MimeTreeParser/HtmlWriter>
34
35#include <QFile>
36#include <QTextStream>
37
38class QString;
39
40class StringHtmlWriter : public MimeTreeParser::HtmlWriter
41{
42public:
43 explicit StringHtmlWriter();
44 virtual ~StringHtmlWriter();
45
46 void begin(const QString &cssDefs) Q_DECL_OVERRIDE;
47 void end() Q_DECL_OVERRIDE;
48 void reset() Q_DECL_OVERRIDE;
49 void write(const QString &str) Q_DECL_OVERRIDE;
50 void queue(const QString &str) Q_DECL_OVERRIDE;
51 void flush() Q_DECL_OVERRIDE;
52 void embedPart(const QByteArray &contentId, const QString &url) Q_DECL_OVERRIDE;
53 void extraHead(const QString &str) Q_DECL_OVERRIDE;
54
55 QString html() const;
56 QMap<QByteArray, QUrl> embeddedParts() const;
57private:
58 void insertExtraHead();
59 void resolveCidUrls();
60
61 QString mHtml;
62 QString mExtraHead;
63 enum State {
64 Begun,
65 Queued,
66 Ended
67 } mState;
68 QMap<QByteArray, QUrl> mEmbeddedPartMap;
69};
70
71#endif // __MESSAGEVIEWER_FILEHTMLWRITER_H__
diff --git a/framework/domain/mimetreeparser/tests/CMakeLists.txt b/framework/domain/mimetreeparser/tests/CMakeLists.txt
new file mode 100644
index 00000000..7945c5a0
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/CMakeLists.txt
@@ -0,0 +1,12 @@
1add_subdirectory(gnupg_home)
2add_definitions( -DMAIL_DATA_DIR="${CMAKE_CURRENT_SOURCE_DIR}/data" )
3include(${CMAKE_CURRENT_SOURCE_DIR}/kdepim_add_gpg_crypto_test.cmake)
4include_directories(
5 ${CMAKE_CURRENT_BINARY_DIR}
6 ${CMAKE_CURRENT_SOURCE_DIR}/..
7 )
8
9add_executable(mimetreeparsertest interfacetest.cpp)
10add_gpg_crypto_test(mimetreeparsertest mimetreeparsertest)
11qt5_use_modules(mimetreeparsertest Core Test)
12target_link_libraries(mimetreeparsertest mimetreeparser)
diff --git a/framework/domain/mimetreeparser/tests/data/alternative.mbox b/framework/domain/mimetreeparser/tests/data/alternative.mbox
new file mode 100644
index 00000000..6522c34b
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/data/alternative.mbox
@@ -0,0 +1,28 @@
1Return-Path: <konqi@example.org>
2Date: Wed, 8 Jun 2016 20:34:44 -0700
3From: Konqi <konqi@example.org>
4To: konqi@kde.org
5Subject: A random subject with alternative contenttype
6MIME-Version: 1.0
7Content-Type: multipart/alternative;
8 boundary="----=_Part_12345678_12345678"
9
10
11------=_Part_12345678_12345678
12Content-Type: text/plain; charset=utf-8
13Content-Transfer-Encoding: quoted-printable
14
15If you can see this text it means that your email client couldn't display o=
16ur newsletter properly.
17Please visit this link to view the newsletter on our website: http://www.go=
18g.com/newsletter/
19
20
21------=_Part_12345678_12345678
22Content-Transfer-Encoding: 7Bit
23Content-Type: text/html; charset="windows-1252"
24
25<html><body><p><span>HTML</span> text</p></body></html>
26
27
28------=_Part_12345678_12345678--
diff --git a/framework/domain/mimetreeparser/tests/data/html.mbox b/framework/domain/mimetreeparser/tests/data/html.mbox
new file mode 100644
index 00000000..bf5c685d
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/data/html.mbox
@@ -0,0 +1,15 @@
1From foo@example.com Thu, 26 May 2011 01:16:54 +0100
2From: Thomas McGuire <foo@example.com>
3Subject: HTML test
4Date: Thu, 26 May 2011 01:16:54 +0100
5Message-ID: <1501334.pROlBb7MZF@herrwackelpudding.localhost>
6X-KMail-Transport: GMX
7X-KMail-Fcc: 28
8X-KMail-Drafts: 7
9X-KMail-Templates: 9
10User-Agent: KMail/4.6 beta5 (Linux/2.6.34.7-0.7-desktop; KDE/4.6.41; x86_64; git-0269848; 2011-04-19)
11MIME-Version: 1.0
12Content-Transfer-Encoding: 7Bit
13Content-Type: text/html; charset="windows-1252"
14
15<html><body><p><span>HTML</span> text</p></body></html> \ No newline at end of file
diff --git a/framework/domain/mimetreeparser/tests/data/openpgp-encrypted-attachment-and-non-encrypted-attachment.mbox b/framework/domain/mimetreeparser/tests/data/openpgp-encrypted-attachment-and-non-encrypted-attachment.mbox
new file mode 100644
index 00000000..2d9726ea
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/data/openpgp-encrypted-attachment-and-non-encrypted-attachment.mbox
@@ -0,0 +1,115 @@
1From test@kolab.org Fri May 01 15:12:47 2015
2From: testkey <test@kolab.org>
3To: you@you.com
4Subject: enc & non enc attachment
5Date: Fri, 01 May 2015 17:12:47 +0200
6Message-ID: <13897561.XENKdJMSlR@tabin.local>
7X-KMail-Identity: 1197256126
8User-Agent: KMail/4.13.0.1 (Linux/3.19.1-towo.1-siduction-amd64; KDE/4.14.2; x86_64; git-cd33034; 2015-04-11)
9MIME-Version: 1.0
10Content-Type: multipart/mixed; boundary="nextPart1939768.sIoLGH0PD8"
11Content-Transfer-Encoding: 7Bit
12
13This is a multi-part message in MIME format.
14
15--nextPart1939768.sIoLGH0PD8
16Content-Type: multipart/encrypted; boundary="nextPart2814166.CHKktCGlQ3"; protocol="application/pgp-encrypted"
17
18
19--nextPart2814166.CHKktCGlQ3
20Content-Type: application/pgp-encrypted
21Content-Disposition: attachment
22Content-Transfer-Encoding: 7Bit
23
24Version: 1
25--nextPart2814166.CHKktCGlQ3
26Content-Type: application/octet-stream
27Content-Disposition: inline; filename="msg.asc"
28Content-Transfer-Encoding: 7Bit
29
30-----BEGIN PGP MESSAGE-----
31Version: GnuPG v2
32
33hIwDGJlthTT7oq0BA/9cXFQ6mN9Vxnc2B9M10odS3/6z1tsIY9oJdsiOjpfxqapX
34P7nOzR/jNWdFQanXoG1SjAcY2FeZEN0c3SkxEM6R5QVF1vMh/Xsni1clI+peZyVT
35Z4OSU74YCfYLg+cgDnPCF3kyNPVe6Z1pnfWOCZNCG3rpApw6UVLN63ScWC6eQIUB
36DAMMzkNap8zaOwEIANKHn1svvj+hBOIZYf8R+q2Bw7cd4xEChiJ7uQLnD98j0Fh1
3785v7/8JbZx6rEDDenPp1mCciDodb0aCmi0XLuzJz2ANGTVflfq+ZA+v1pwLksWCs
380YcHLEjOJzjr3KKmvu6wqnun5J2yV69K3OW3qTTGhNvcYZulqQ617pPa48+sFCgh
39nM8TMAD0ElVEwmMtrS3AWoJz52Af+R3YzpAnX8NzV317/JG+b6e2ksl3tR7TWp1q
402FOqC1sXAxuv+DIz4GgRfaK1+xYr2ckkg+H/3HJqa5LmJ7rGCyv+Epfp9u+OvdBG
41PBvuCtO3tm0crmnttMw57Gy35BKutRf/8MpBj/nS6QFX0t7XOLeL4Me7/a2H20wz
42HZsuRGDXMCh0lL0FYCBAwdbbYvvy0gz/5iaNvoADtaIu+VtbFNrTUN0SwuL+AIFS
43+WIiaSbFt4Ng3t9YmqL6pqB7fjxI10S+PK0s7ABqe4pgbzUWWt1yzBcxfk8l/47Q
44JrlvcE7HuDOhNOHfZIgUP2Dbeu+pVvHIJbmLsNWpl4s+nHhoxc9HrVhYG/MTZtQ3
45kkUWviegO6mwEZjQvgBxjWib7090sCxkO847b8A93mfQNHnuy2ZEEJ+9xyk7nIWs
464RsiNR8pYc/SMvdocyAvQMH/qSvmn/IFJ+jHhtT8UJlXJ0bHvXTHjHMqBp6fP69z
47Jh1ERadWQdMaTkzQ+asl+kl/x3p6RZP8MEVbZIl/3pcV+xiFCYcFu2TETKMtbW+b
48NYOlrltFxFDvyu3WeNNp0g9k0nFpD/T1OXHRBRcbUDWE4QF6NWTm6NO9wy2UYHCi
497QTSecBWgMaw7cUdwvnW6chIVoov1pm69BI9D0PoV76zCI7KzpiDsTFxdilKwbQf
50K/PDnv9Adx3ERh0/F8llBHrj2UGsRs4aHSEBDBJIHDCp8+lqtsRcINQBKEU3qIjt
51wf5vizdaVIgQnsD2z8QmBQ7QCCipI0ur6GKl+YWDDOSDLDUs9dK4A6xo/4Q0bsnI
52rH63ti5HslGq6uArfFkewH2MWff/8Li3uGEqzpK5NhP5UpbArelK+QaQQP5SdsmW
53XFwUqDS4QTCKNJXw/5SQMl8UE10l2Xaav3TkiOYTcBcvPNDovYgnMyRff/tTeFa8
5483STkvpGtkULkCntp22fydv5rg6DZ7eJrYfC2oZXdM87hHhUALUO6Y/VtVmNdNYw
55F3Uim4PDuLIKt+mFqRtFqnWm+5X/AslC31qLkjH+Fbb83TY+mC9gbIn7CZGJRCjn
56zzzMX2h15V/VHzNUgx9V/h28T0/z25FxoozZiJxpmhOtqoxMHp+y6nXXfMoIAD1D
57963Pc7u1HS0ny54A7bqc6KKd4W9IF7HkXn3SoBwCyn0IOPoKQTDD8mW3lbBI6+h9
58vP+MAQpfD8s+3VZ9r7OKYCVmUv47ViTRlf428Co6WT7rTHjGM09tqz826fTOXA==
59=6Eu9
60-----END PGP MESSAGE-----
61
62--nextPart2814166.CHKktCGlQ3--
63
64--nextPart1939768.sIoLGH0PD8
65Content-Disposition: attachment; filename="image.png"
66Content-Transfer-Encoding: base64
67Content-Type: image/png; name="image.png"
68
69iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAAlwSFlzAAAb
70rwAAG68BXhqRHAAAAAd0SU1FB9gHFg8aNG8uqeIAAAAGYktHRAD/AP8A/6C9p5MAAAkqSURBVHja
715VV7cFTVGf/OPefeu3fv3t1NdhMSCHkKASEpyEsaGwalWEWntLV1Wu0fdOxAx9Iq0xntAwac6ehY
72p+rwKLbjjLRFh9JadURKRGgFQTTECCYQE9nNgzzYZDe7m33d1+l3tpOOU61T2tF/+s1s7pzn9/t+
73v993Av/3QT6FO6WdO/d+M55Il8rMOdrT0x3Zt++3+c8EgM/nozseeviJiYmpe1zOQdM8BOOCIku/
74lIj1VrQ/0r9n9+78xwLgeAA3w4fHXV1d5Omnn6aapumlJSVVqalUJJvJZRdcu0RSfZQsaW7mjfPm
75cbF9+/btEIlEaq6Z03whXyhIjDFuGIZEKSP5fMFRVcVNT2Vf0jzsmMxYGtel9rff/vM/M8bjcZpM
76Jp1XX32VNDc3e7ovRP3JyZGVNdXVd1FGGwKBQEM8njiWTKV36IHgEACwibGx62LjU/cBd01Zljoc
77p9DHmLbHsmyK1UuKooJt24IMcLE+y3L45eEYLS8LgWH4YXR0bAPZtGmTVFvfoBZMEzKpFKmqqmqp
78qane4DhOteH3L1FkWZVlGSzLAtd1Oe4773C4LxoZvDWXh82OY2MtwAuFvCvSyDIFXdelYDDIvF4d
79xPzA0AgXFStMcWPxBPGoKvXpPh6JDG5hK1Zcv1H36Xc6tsMs21EMQ69CLSts2wGkDygTyW2CP8gX
80TKLIyvx0OrdDUXyLKXVUkdSne4QKtFAwuWmabjAYkDyqAgG/jziORh1EKaonkkQt2yRZRC5JHEGn
81L7OKyopNqqo2IbWQjqWgLOwFBFKsuGDa4PVyIssMk1sCACCjimXbrbquYKW41zJJOpXkeARyeZNQ
82SUKwHEqCKnBuAybkZeFSmssVSDKdhlBpCRgIcnQsdvKPB19sY4rMNIaH0BhQUVHKvXgpIiQF0wK/
834QORnOEayoDzOSBMXK4BSgpeTcMECqiqTDKZHDKmct3LCI55Kp0mQgK/3yDYkgIc3kNhfHzCkRk9
84p6nk+yPD3SmWzeZiKNkciUrg2g5BjQWdSBchiEvQjzoWAFkUYPDrCjBFUEJ8AhSIRyl2jcfjEL9h
85AFJODL8B6H7IZrNIt2g3B1mysShdQhmbT58+ExRdx3L5/PNomGU4kJkuA9ILYn+JP4CXOoDUoWO9
86IBhCSBCLTYCK+rqOg8CKvY6JPQhGxjkX1zyAdwrgAhTKWBDmxTUTC7Tcy5dHBiilL7cdaTsNGAwP
877o32D4Q9HnWTrvsCiqIgdWgqDkJfkKgDU1MZcBGMhbKgj2B0LIle8eNhgiBsoMwFEY7rQDqVwlo5
88esUE/AAR81gUYIUT8UR2//4/rK+pLjs3MhIFEVJN9WwXK2oM+P1BREpQO0hjwkw+BzJWY1oOXB5L
89w9DIOGTQvYS4UFqigR9ZwUqEXFghVop059AjonqcAIZrqCKg31AS3OU66Adf4sabWqKvvHIYpoNh
90y+Vj4xMHVEW93eUuo0izhT4oRbcSIoALbRle4AVVkfBup6g9thwCzRX1VRQmdMeqLVETEIkW2ZNx
91H8oqzqAfXCGJEQ6XBQEgNQ2A7tq1C1a1tvaattOOrVFOqVSLCQhqU6QPx+DTsOU0GavLYUV20Qv4
92rEIymYNQuB48Wkg8QTA0NIQeYKB6NGTgH90jIcJEMikAi1dRRo9NLV583ek33jjpFAGIPw8++IAj
93e9SIRGm5wliraVosnTWLmmemUugBkTiPSS3AtgV8VQA9A8LxdfULYXBoEKv2wMhIn2BHGFR0DZ6d
94glQ6hUDT6A/RWVSSmfx5DjxRV1vzVkdHBzDAWLNmDezc+aQVqqz5dSY52Z63nLn9A33lI9myLXNL
95xv0Fq3gWutMN0BToxcso+AN+cKmOXI5A9P12mKDzYNXcZXDq1F+h+IboFgzb1VAhDULeJpxwC19G
96g/uMgOXVfXW1tbWCYM6mtdi8+YfiM4m/Y1UrHzkergyXz/3czImCnRjuHiW3qxpPqGFPy6SpHJC9
97IR+Sm+2N8i/dcMOMZdGeshcrS/S58+c3zU2Z8oVD50cbVfP8M4pGkymoUxLxsUzOVhtmQ+5432Rg
98oj6QOLFj28/caQk+EjMXraUV1eW+8dH06StQZnlnNbQefGTD92pWfu3I6TOT8oY7brv4hWUt3xiw
992OrlDVVdRslsd2Fd469Q8sUB3c8uOW49SdHX1rbcePhoz3B7feuqlt5oZtBTv+ioSdXc7q3fHQaM
100fwtg6Vd/dEvn8Qssnzg/0Ns56jRcO6Nw4d1Af+/RH0/cdv+O/fRK7KnmBXPWGsQeDPhK9oWC6hdd
101R3pdUcg88Tx7U7Ej1y1qMjreGwjt/cnaF2YtvCXQe7bzxLkj+/sunT0Ry00OwHRI8DERLqeNmqGV
102JZJVC6Yu7UxMOfLFlV9pWQcYp57/013rb1u9ua29b0Ch4bsl4tKLY5P1sgxNJzsHDj136KzS3NTk
1039mTNusPvXJLrbnjUe/b16FDfsZ/3xC8d4/HoCQ4Anwzg91vWPL7+3pvvDM806sTY4IVyMxfrojO3
104BVubbyJMhnVVM3y+l187/nChIJ2ZpSs9hMD4qC6t6x6+0gkAoRC33/Sb8RdmXj9nzvWraivhP47g
105AyHxKb1mfWkRYHCjMb30nafeeWzerU9963w3L3/02c4f7D0y0NXTx3f3D/JTb7bzxpeODu55+PGT
106yy5F+ZmeD/iSrh5efeJd/hGZP5GBux+6cysY3w7H+16IVy65V6trnn3P9JqVjQ3JuSsdHhWW6hIL
107NuhyUpJgEF/ofSVBeLBuVtVjd3y55SHXhQ8UBht0DR4r98Fs+IRg/zrxlz2/2A7p5yYBY93Gu+4f
108H5xojLwOxfjd/WufOHhQ/IcD7eYVC5YyCjFMfkVV4NpMFvpTachoZeDaNryLnliOczsUCv1XBWD8
109YjF5MWJ9kcT757qenR7vf4bDoqWwHCvUUfPNsQQMWSZAZTlsw7nxYQQTcuDrjgQuPn7z/D7YivNt
110nPPfEDzwqcU75/j6SD/f8uG5vXs5dL7Hjb+d4gp8mnF8nAOabjcac+OBAxyuNiT4HyNwGZYgu0RW
111IDt/Icz4zAC0tXE4183rQ6XwU9uBXgLQ5Teg7GIv1+EqgsF/GY4DtCQALZMp2ITttmqoHzpWr756
112o/0d59+Lh3Y1HHcAAAAASUVORK5CYII=
113
114--nextPart1939768.sIoLGH0PD8--
115
diff --git a/framework/domain/mimetreeparser/tests/data/openpgp-inline-charset-encrypted.mbox b/framework/domain/mimetreeparser/tests/data/openpgp-inline-charset-encrypted.mbox
new file mode 100644
index 00000000..8bd06910
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/data/openpgp-inline-charset-encrypted.mbox
@@ -0,0 +1,40 @@
1From test@example.com Thu, 17 Oct 2013 02:13:03 +0200
2Return-Path: <test@example.com>
3Delivered-To: you@you.com
4Received: from localhost (localhost [127.0.0.1])
5 by test@example.com (Postfix) with ESMTP id B30D8120030
6 for <you@you.com>; Thu, 17 Oct 2013 02:13:05 +0200 (CEST)
7From: test <test@example.com>
8To: you@you.com
9Subject: charset
10Date: Thu, 17 Oct 2013 02:13:03 +0200
11Message-ID: <4081645.yGjUJ4o4Se@example.local>
12User-Agent: KMail/4.12 pre (Linux/3.11-4.towo-siduction-amd64; KDE/4.11.2; x86_64; git-f7f14e3; 2013-10-15)
13MIME-Version: 1.0
14Content-Transfer-Encoding: 7Bit
15Content-Type: text/plain; charset="ISO-8859-15"
16
17-----BEGIN PGP MESSAGE-----
18Version: GnuPG v2.0.22 (GNU/Linux)
19
20hIwDGJlthTT7oq0BBACbaRZudMigMTetPZNRgkfEXv4QQowR1jborw0dcgKKqMQ1
216o67NkpxvmXKGJTfTVCLBX3nk6FKYo6NwlPCyU7X9X0DDk8hvaBdR9wGfrdm5YWX
22GKOzcqJY1EypiMsspXeZvjzEW7O8I956c3vBb/2pM3xqYEK1kh8+d9bVH+cjf4UB
23DAMMzkNap8zaOwEH/1rPShyYL8meJN+/GGgS8+Nf1BW5pSHdAPCg0dnX4QCLEx7u
24GkBU6N4JGYayaCBofibOLacQPhYZdnR5Xb/Pvrx03GrzyzyDp0WyeI9nGNfkani7
25sCRWbzlMPsEvGEvJVnMLNRSk4xhPIWumL4APkw+Mgi6mf+Br8z0RhfnGwyMA53Mr
26pG9VQKlq3v7/aaN40pMjAsxiytcHS515jXrb3Ko4pWbTlAr/eytOEfkLRJgSOpQT
27BY7lWs+UQJqiG8Yn65vS9LMDNJgX9EOGx77Z4u9wvv4ZieOxzgbHGg5kYCoae7ba
28hxZeNjYKscH+E6epbOxM/wlTdr4UTiiW9dMsH0zSwMUB891gToeXq+LDGEPTKVSX
29tsJm4HS/kISJBwrCI4EUqWZML6xQ427NkZGmF2z/sD3kmL66GjspIKnb4zHmXacp
3084n2KrI9s7p6AnKnQjsxvB/4/lpXPCIY5GH7KjySEJiMsHECzeN1dJSL6keykBsx
31DtmYDA+dhZ6UWbwzx/78+mjNREhyp/UiSAmLzlJh89OH/xelAPvKcIosYwz4cY9N
32wjralTmL+Y0aHKeZJOeqPLaXADcPFiZrCNPCH65Ey5GEtDpjLpEbjVbykPV9+YkK
337JKW6bwMraOl5zmAoR77PWMo3IoYb9q4GuqDr1V2ZGlb7eMH1gj1nfgfVintKC1X
343jFfy7aK6LIQDVKEwbi0SxVXTKStuliVUy5oX4woDOxmTEotJf1QlKZpn5oF20UP
35tumYrp0SPoP8Bo4EVRVaLupduI5cYce1q/kFj9Iho/wk56MoG9PxMMfsH7oKg3AA
36CqQ6/kM4oJNdN5xIf1EH5HeaNFkDy1jlLznnhwVAZKPo/9ffpg==
37=bPqu
38-----END PGP MESSAGE-----
39
40
diff --git a/framework/domain/mimetreeparser/tests/data/openpgp-inline-encrypted+nonenc.mbox b/framework/domain/mimetreeparser/tests/data/openpgp-inline-encrypted+nonenc.mbox
new file mode 100644
index 00000000..b98dc336
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/data/openpgp-inline-encrypted+nonenc.mbox
@@ -0,0 +1,31 @@
1From test@kolab.org Wed, 25 May 2011 23:49:40 +0100
2From: OpenPGP Test <test@kolab.org>
3To: test@kolab.org
4Subject: inlinepgpencrypted + non enc text
5Date: Wed, 25 May 2011 23:49:40 +0100
6Message-ID: <1786696.yKXrOjjflF@herrwackelpudding.localhost>
7X-KMail-Transport: GMX
8X-KMail-Fcc: 28
9X-KMail-Drafts: 7
10X-KMail-Templates: 9
11User-Agent: KMail/4.6 beta5 (Linux/2.6.34.7-0.7-desktop; KDE/4.6.41; x86_64; git-0269848; 2011-04-19)
12MIME-Version: 1.0
13Content-Transfer-Encoding: 7Bit
14Content-Type: text/plain; charset="us-ascii"
15
16Not encrypted not signed :(
17
18-----BEGIN PGP MESSAGE-----
19Version: GnuPG v2.0.15 (GNU/Linux)
20
21hQEMAwzOQ1qnzNo7AQf/a3aNTLpQBfcUr+4AKsZQLj4h6z7e7a5AaCW8AG0wrbxN
22kBYB7E5jdZh45DX/99gvoZslthWryUCX2kKZ3LtIllxKVjqNuK5hSt+SAuKkwiMR
23Xcbf1KFKENKupgGSO9B2NJRbjoExdJ+fC3mGXnO3dT7xJJAo3oLE8Nivu+Bj1peY
24E1wCf+vcTwVHFrA7SV8eMRb9Z9wBXmU8Q8e9ekJ7ZsRX3tMeBs6jvscVvfMf6DYY
25N14snZBZuGNKT9a3DPny7IC1S0lHcaam34ogWwMi3FxPGJt/Lg52kARlkF5TDhcP
26N6H0EB/iqDRjOOUoEVm8um5XOSR1FpEiAdD0DON3y9JPATnrYq7sgYZz3BVImYY+
27N/jV8fEiN0a34pcOq8NQedMuOsJHNBS5MtbQH/kJLq0MXBpXekGlHo4MKw0trISc
28Rw3pW6/BFfhPJLni29g9tw==
29=fRFW
30-----END PGP MESSAGE-----
31
diff --git a/framework/domain/mimetreeparser/tests/data/plaintext.mbox b/framework/domain/mimetreeparser/tests/data/plaintext.mbox
new file mode 100644
index 00000000..d185b1c1
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/data/plaintext.mbox
@@ -0,0 +1,13 @@
1Return-Path: <konqi@example.org>
2Date: Wed, 8 Jun 2016 20:34:44 -0700
3From: Konqi <konqi@example.org>
4To: konqi@kde.org
5Subject: A random subject with alternative contenttype
6MIME-Version: 1.0
7Content-Type: text/plain; charset=utf-8
8Content-Transfer-Encoding: quoted-printable
9
10If you can see this text it means that your email client couldn't display o=
11ur newsletter properly.
12Please visit this link to view the newsletter on our website: http://www.go=
13g.com/newsletter/
diff --git a/framework/domain/mimetreeparser/tests/data/smime-encrypted.mbox b/framework/domain/mimetreeparser/tests/data/smime-encrypted.mbox
new file mode 100644
index 00000000..6b6d6a0d
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/data/smime-encrypted.mbox
@@ -0,0 +1,22 @@
1From test@example.com Sat, 13 Apr 2013 01:54:30 +0200
2From: test <test@example.com>
3To: you@you.com
4Subject: test
5Date: Sat, 13 Apr 2013 01:54:30 +0200
6Message-ID: <1576646.QQxzHWx8dA@tabin>
7X-KMail-Identity: 505942601
8User-Agent: KMail/4.10.2 (Linux/3.9.0-rc4-experimental-amd64; KDE/4.10.60; x86_64; git-fc9b82c; 2013-04-11)
9MIME-Version: 1.0
10Content-Type: application/pkcs7-mime; name="smime.p7m"; smime-type="enveloped-data"
11Content-Transfer-Encoding: base64
12Content-Disposition: attachment; filename="smime.p7m"
13
14MIAGCSqGSIb3DQEHA6CAMIACAQAxgfwwgfkCAQAwYjBVMQswCQYDVQQGEwJVUzENMAsGA1UECgwE
15S0RBQjEWMBQGA1UEAwwNdW5pdHRlc3QgY2VydDEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxl
16LmNvbQIJANNFIDoYY4XJMA0GCSqGSIb3DQEBAQUABIGAJwmmaOeidXUHSQGOf2OBIsPYafVqdORe
17y54pEXbXiAfSVUWgI4a9CsiWwcDX8vlaX9ZLLr+L2VmOfr6Yc5214yxzausZVvnUFjy6LUXotuEX
18tSar4EW7XI9DjaZc1l985naMsTx9JUa5GyQ9J6PGqhosAKpKMGgKkFAHaOwE1/IwgAYJKoZIhvcN
19AQcBMBQGCCqGSIb3DQMHBAieDfmz3WGbN6CABHgEpsLrNn0PAZTDUfNomDypvSCl5bQH+9cKm80m
20upMV2r8RBiXS7OaP4SpCxq18afDTTPatvboHIoEX92taTbq8soiAgEs6raSGtEYZNvFL0IYqm7MA
21o5HCOmjiEcInyPf14lL3HnPk10FaP3hh58qTHUh4LPYtL7UECOZELYnUfUVhAAAAAAAAAAAAAA==
22
diff --git a/framework/domain/mimetreeparser/tests/gnupg_home/CMakeLists.txt b/framework/domain/mimetreeparser/tests/gnupg_home/CMakeLists.txt
new file mode 100644
index 00000000..9c64a008
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/gnupg_home/CMakeLists.txt
@@ -0,0 +1,10 @@
1configure_file( gpg-agent.conf.in
2 "${CMAKE_CURRENT_BINARY_DIR}/gpg-agent.conf" @ONLY )
3
4configure_file( gpgsm.conf.in
5 "${CMAKE_CURRENT_BINARY_DIR}/gpgsm.conf" @ONLY )
6
7file( COPY
8 ${CMAKE_CURRENT_SOURCE_DIR}
9 DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/../"
10)
diff --git a/framework/domain/mimetreeparser/tests/gnupg_home/dirmngr-cache.d/DIR.txt b/framework/domain/mimetreeparser/tests/gnupg_home/dirmngr-cache.d/DIR.txt
new file mode 100644
index 00000000..1a45a6b3
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/gnupg_home/dirmngr-cache.d/DIR.txt
@@ -0,0 +1,3 @@
1v:1:
2c:4E31CEB57DDD4A7B9991AB05507B1ED4293FF952:CN=Test-ZS 7,O=Intevation GmbH,C=DE:ldap%3A//ca.intevation.org/cn=Test-ZS 7, o=Intevation GmbH, c=DE?certificateRevocationList:20100615T181523:20100707T181523:72FEF3FD88455A1D4C6796A6499D4422::::
3c:7F2A402CBB016A9146D613568C89D3596A4111AA:CN=Wurzel ZS 3,O=Intevation GmbH,C=DE:ldap%3A//ca.intevation.org/cn=Wurzel ZS 3, o=Intevation GmbH, c=DE?certificateRevocationList:20100625T102134:20100814T102134:44E60EEC02EF2FBF7A5C77E9BD565667::::
diff --git a/framework/domain/mimetreeparser/tests/gnupg_home/dirmngr-cache.d/crl-4E31CEB57DDD4A7B9991AB05507B1ED4293FF952.db b/framework/domain/mimetreeparser/tests/gnupg_home/dirmngr-cache.d/crl-4E31CEB57DDD4A7B9991AB05507B1ED4293FF952.db
new file mode 100644
index 00000000..0b7e2dd4
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/gnupg_home/dirmngr-cache.d/crl-4E31CEB57DDD4A7B9991AB05507B1ED4293FF952.db
Binary files differ
diff --git a/framework/domain/mimetreeparser/tests/gnupg_home/dirmngr-cache.d/crl-7F2A402CBB016A9146D613568C89D3596A4111AA.db b/framework/domain/mimetreeparser/tests/gnupg_home/dirmngr-cache.d/crl-7F2A402CBB016A9146D613568C89D3596A4111AA.db
new file mode 100644
index 00000000..47474a26
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/gnupg_home/dirmngr-cache.d/crl-7F2A402CBB016A9146D613568C89D3596A4111AA.db
Binary files differ
diff --git a/framework/domain/mimetreeparser/tests/gnupg_home/dirmngr.conf b/framework/domain/mimetreeparser/tests/gnupg_home/dirmngr.conf
new file mode 100644
index 00000000..a17a0354
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/gnupg_home/dirmngr.conf
@@ -0,0 +1,8 @@
1
2###+++--- GPGConf ---+++###
3debug-level basic
4log-file socket:///home/leo/kde/src/kdepim/messagecomposer/tests/gnupg_home/log-socket
5###+++--- GPGConf ---+++### Tue 29 Jun 2010 10:23:13 AM EDT
6# GPGConf edited this configuration file.
7# It will disable options before this marked block, but it will
8# never change anything below these lines.
diff --git a/framework/domain/mimetreeparser/tests/gnupg_home/gpg-agent.conf.in b/framework/domain/mimetreeparser/tests/gnupg_home/gpg-agent.conf.in
new file mode 100644
index 00000000..ece69255
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/gnupg_home/gpg-agent.conf.in
@@ -0,0 +1,10 @@
1pinentry-program @CMAKE_CURRENT_BINARY_DIR@/pinentry-fake.sh
2###+++--- GPGConf ---+++###
3allow-mark-trusted
4debug-level basic
5faked-system-time 20130110T154812
6log-file @CMAKE_CURRENT_BINARY_DIR@/gpg-agent.log
7###+++--- GPGConf ---+++### Tue 29 Jun 2010 10:23:13 AM EDT
8# GPGConf edited this configuration file.
9# It will disable options before this marked block, but it will
10# never change anything below these lines.
diff --git a/framework/domain/mimetreeparser/tests/gnupg_home/gpg.conf b/framework/domain/mimetreeparser/tests/gnupg_home/gpg.conf
new file mode 100644
index 00000000..f1760823
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/gnupg_home/gpg.conf
@@ -0,0 +1,244 @@
1# Options for GnuPG
2# Copyright 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
3#
4# This file is free software; as a special exception the author gives
5# unlimited permission to copy and/or distribute it, with or without
6# modifications, as long as this notice is preserved.
7#
8# This file is distributed in the hope that it will be useful, but
9# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
10# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11#
12# Unless you specify which option file to use (with the command line
13# option "--options filename"), GnuPG uses the file ~/.gnupg/gpg.conf
14# by default.
15#
16# An options file can contain any long options which are available in
17# GnuPG. If the first non white space character of a line is a '#',
18# this line is ignored. Empty lines are also ignored.
19#
20# See the man page for a list of options.
21
22# Uncomment the following option to get rid of the copyright notice
23
24#no-greeting
25
26# If you have more than 1 secret key in your keyring, you may want to
27# uncomment the following option and set your preferred keyid.
28
29#default-key 621CC013
30
31# If you do not pass a recipient to gpg, it will ask for one. Using
32# this option you can encrypt to a default key. Key validation will
33# not be done in this case. The second form uses the default key as
34# default recipient.
35
36#default-recipient some-user-id
37#default-recipient-self
38
39# Use --encrypt-to to add the specified key as a recipient to all
40# messages. This is useful, for example, when sending mail through a
41# mail client that does not automatically encrypt mail to your key.
42# In the example, this option allows you to read your local copy of
43# encrypted mail that you've sent to others.
44
45#encrypt-to some-key-id
46
47# By default GnuPG creates version 3 signatures for data files. This
48# is not strictly OpenPGP compliant but PGP 6 and most versions of PGP
49# 7 require them. To disable this behavior, you may use this option
50# or --openpgp.
51
52#no-force-v3-sigs
53
54# Because some mailers change lines starting with "From " to ">From "
55# it is good to handle such lines in a special way when creating
56# cleartext signatures; all other PGP versions do it this way too.
57
58#no-escape-from-lines
59
60# If you do not use the Latin-1 (ISO-8859-1) charset, you should tell
61# GnuPG which is the native character set. Please check the man page
62# for supported character sets. This character set is only used for
63# metadata and not for the actual message which does not undergo any
64# translation. Note that future version of GnuPG will change to UTF-8
65# as default character set. In most cases this option is not required
66# as GnuPG is able to figure out the correct charset at runtime.
67
68#charset utf-8
69
70# Group names may be defined like this:
71# group mynames = paige 0x12345678 joe patti
72#
73# Any time "mynames" is a recipient (-r or --recipient), it will be
74# expanded to the names "paige", "joe", and "patti", and the key ID
75# "0x12345678". Note there is only one level of expansion - you
76# cannot make an group that points to another group. Note also that
77# if there are spaces in the recipient name, this will appear as two
78# recipients. In these cases it is better to use the key ID.
79
80#group mynames = paige 0x12345678 joe patti
81
82# Lock the file only once for the lifetime of a process. If you do
83# not define this, the lock will be obtained and released every time
84# it is needed, which is usually preferable.
85
86#lock-once
87
88# GnuPG can send and receive keys to and from a keyserver. These
89# servers can be HKP, email, or LDAP (if GnuPG is built with LDAP
90# support).
91#
92# Example HKP keyserver:
93# hkp://keys.gnupg.net
94# hkp://subkeys.pgp.net
95#
96# Example email keyserver:
97# mailto:pgp-public-keys@keys.pgp.net
98#
99# Example LDAP keyservers:
100# ldap://keyserver.pgp.com
101#
102# Regular URL syntax applies, and you can set an alternate port
103# through the usual method:
104# hkp://keyserver.example.net:22742
105#
106# Most users just set the name and type of their preferred keyserver.
107# Note that most servers (with the notable exception of
108# ldap://keyserver.pgp.com) synchronize changes with each other. Note
109# also that a single server name may actually point to multiple
110# servers via DNS round-robin. hkp://keys.gnupg.net is an example of
111# such a "server", which spreads the load over a number of physical
112# servers. To see the IP address of the server actually used, you may use
113# the "--keyserver-options debug".
114
115keyserver hkp://keys.gnupg.net
116#keyserver mailto:pgp-public-keys@keys.nl.pgp.net
117#keyserver ldap://keyserver.pgp.com
118
119# Common options for keyserver functions:
120#
121# include-disabled : when searching, include keys marked as "disabled"
122# on the keyserver (not all keyservers support this).
123#
124# no-include-revoked : when searching, do not include keys marked as
125# "revoked" on the keyserver.
126#
127# verbose : show more information as the keys are fetched.
128# Can be used more than once to increase the amount
129# of information shown.
130#
131# use-temp-files : use temporary files instead of a pipe to talk to the
132# keyserver. Some platforms (Win32 for one) always
133# have this on.
134#
135# keep-temp-files : do not delete temporary files after using them
136# (really only useful for debugging)
137#
138# http-proxy="proxy" : set the proxy to use for HTTP and HKP keyservers.
139# This overrides the "http_proxy" environment variable,
140# if any.
141#
142# auto-key-retrieve : automatically fetch keys as needed from the keyserver
143# when verifying signatures or when importing keys that
144# have been revoked by a revocation key that is not
145# present on the keyring.
146#
147# no-include-attributes : do not include attribute IDs (aka "photo IDs")
148# when sending keys to the keyserver.
149
150#keyserver-options auto-key-retrieve
151
152# Display photo user IDs in key listings
153
154# list-options show-photos
155
156# Display photo user IDs when a signature from a key with a photo is
157# verified
158
159# verify-options show-photos
160
161# Use this program to display photo user IDs
162#
163# %i is expanded to a temporary file that contains the photo.
164# %I is the same as %i, but the file isn't deleted afterwards by GnuPG.
165# %k is expanded to the key ID of the key.
166# %K is expanded to the long OpenPGP key ID of the key.
167# %t is expanded to the extension of the image (e.g. "jpg").
168# %T is expanded to the MIME type of the image (e.g. "image/jpeg").
169# %f is expanded to the fingerprint of the key.
170# %% is %, of course.
171#
172# If %i or %I are not present, then the photo is supplied to the
173# viewer on standard input. If your platform supports it, standard
174# input is the best way to do this as it avoids the time and effort in
175# generating and then cleaning up a secure temp file.
176#
177# If no photo-viewer is provided, GnuPG will look for xloadimage, eog,
178# or display (ImageMagick). On Mac OS X and Windows, the default is
179# to use your regular JPEG image viewer.
180#
181# Some other viewers:
182# photo-viewer "qiv %i"
183# photo-viewer "ee %i"
184#
185# This one saves a copy of the photo ID in your home directory:
186# photo-viewer "cat > ~/photoid-for-key-%k.%t"
187#
188# Use your MIME handler to view photos:
189# photo-viewer "metamail -q -d -b -c %T -s 'KeyID 0x%k' -f GnuPG"
190
191# Passphrase agent
192#
193# We support the old experimental passphrase agent protocol as well as
194# the new Assuan based one (currently available in the "newpg" package
195# at ftp.gnupg.org/gcrypt/alpha/aegypten/). To make use of the agent,
196# you have to run an agent as daemon and use the option
197#
198# use-agent
199#
200# which tries to use the agent but will fallback to the regular mode
201# if there is a problem connecting to the agent. The normal way to
202# locate the agent is by looking at the environment variable
203# GPG_AGENT_INFO which should have been set during gpg-agent startup.
204# In certain situations the use of this variable is not possible, thus
205# the option
206#
207# --gpg-agent-info=<path>:<pid>:1
208#
209# may be used to override it.
210
211# Automatic key location
212#
213# GnuPG can automatically locate and retrieve keys as needed using the
214# auto-key-locate option. This happens when encrypting to an email
215# address (in the "user@example.com" form), and there are no
216# user@example.com keys on the local keyring. This option takes the
217# following arguments, in the order they are to be tried:
218#
219# cert = locate a key using DNS CERT, as specified in RFC-4398.
220# GnuPG can handle both the PGP (key) and IPGP (URL + fingerprint)
221# CERT methods.
222#
223# pka = locate a key using DNS PKA.
224#
225# ldap = locate a key using the PGP Universal method of checking
226# "ldap://keys.(thedomain)". For example, encrypting to
227# user@example.com will check ldap://keys.example.com.
228#
229# keyserver = locate a key using whatever keyserver is defined using
230# the keyserver option.
231#
232# You may also list arbitrary keyservers here by URL.
233#
234# Try CERT, then PKA, then LDAP, then hkp://subkeys.net:
235#auto-key-locate cert pka ldap hkp://subkeys.pgp.net
236
237###+++--- GPGConf ---+++###
238utf8-strings
239#debug-level basic
240#log-file socket:///home/leo/kde/src/kdepim/messagecomposer/tests/gnupg_home/log-socket
241###+++--- GPGConf ---+++### Tue 29 Jun 2010 10:23:13 AM EDT
242# GPGConf edited this configuration file.
243# It will disable options before this marked block, but it will
244# never change anything below these lines.
diff --git a/framework/domain/mimetreeparser/tests/gnupg_home/gpgsm.conf.in b/framework/domain/mimetreeparser/tests/gnupg_home/gpgsm.conf.in
new file mode 100644
index 00000000..92b6119d
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/gnupg_home/gpgsm.conf.in
@@ -0,0 +1,10 @@
1
2###+++--- GPGConf ---+++###
3disable-crl-checks
4debug-level basic
5faked-system-time 20130110T154812
6log-file @CMAKE_CURRENT_BINARY_DIR@/gpgsm.log
7###+++--- GPGConf ---+++### Tue 29 Jun 2010 10:23:13 AM EDT
8# GPGConf edited this configuration file.
9# It will disable options before this marked block, but it will
10# never change anything below these lines.
diff --git a/framework/domain/mimetreeparser/tests/gnupg_home/pinentry-fake.sh b/framework/domain/mimetreeparser/tests/gnupg_home/pinentry-fake.sh
new file mode 100755
index 00000000..7135a942
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/gnupg_home/pinentry-fake.sh
@@ -0,0 +1,9 @@
1#!/bin/sh
2
3echo "OK Your orders please"
4while :
5do
6 read cmd
7 echo "OK"
8 [ "$cmd" = "BYE" ] && break
9done
diff --git a/framework/domain/mimetreeparser/tests/gnupg_home/private-keys-v1.d/1AA8BA52430E51AE249AF0DA97D59F869E4101A8.key b/framework/domain/mimetreeparser/tests/gnupg_home/private-keys-v1.d/1AA8BA52430E51AE249AF0DA97D59F869E4101A8.key
new file mode 100644
index 00000000..39ac307b
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/gnupg_home/private-keys-v1.d/1AA8BA52430E51AE249AF0DA97D59F869E4101A8.key
Binary files differ
diff --git a/framework/domain/mimetreeparser/tests/gnupg_home/pubring.gpg b/framework/domain/mimetreeparser/tests/gnupg_home/pubring.gpg
new file mode 100644
index 00000000..2e00fa24
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/gnupg_home/pubring.gpg
Binary files differ
diff --git a/framework/domain/mimetreeparser/tests/gnupg_home/pubring.kbx b/framework/domain/mimetreeparser/tests/gnupg_home/pubring.kbx
new file mode 100644
index 00000000..0230f313
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/gnupg_home/pubring.kbx
Binary files differ
diff --git a/framework/domain/mimetreeparser/tests/gnupg_home/scdaemon.conf b/framework/domain/mimetreeparser/tests/gnupg_home/scdaemon.conf
new file mode 100644
index 00000000..a17a0354
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/gnupg_home/scdaemon.conf
@@ -0,0 +1,8 @@
1
2###+++--- GPGConf ---+++###
3debug-level basic
4log-file socket:///home/leo/kde/src/kdepim/messagecomposer/tests/gnupg_home/log-socket
5###+++--- GPGConf ---+++### Tue 29 Jun 2010 10:23:13 AM EDT
6# GPGConf edited this configuration file.
7# It will disable options before this marked block, but it will
8# never change anything below these lines.
diff --git a/framework/domain/mimetreeparser/tests/gnupg_home/secring.gpg b/framework/domain/mimetreeparser/tests/gnupg_home/secring.gpg
new file mode 100644
index 00000000..cfd3387d
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/gnupg_home/secring.gpg
Binary files differ
diff --git a/framework/domain/mimetreeparser/tests/gnupg_home/trustdb.gpg b/framework/domain/mimetreeparser/tests/gnupg_home/trustdb.gpg
new file mode 100644
index 00000000..70089c15
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/gnupg_home/trustdb.gpg
Binary files differ
diff --git a/framework/domain/mimetreeparser/tests/gnupg_home/trustlist.txt b/framework/domain/mimetreeparser/tests/gnupg_home/trustlist.txt
new file mode 100644
index 00000000..bbb0442d
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/gnupg_home/trustlist.txt
@@ -0,0 +1,11 @@
15E:7C:B2:F4:9F:70:05:43:42:32:5D:75:74:70:00:09:B9:D8:08:61 S
2
3
4
5# CN=unittest cert
6# O=KDAB
7# C=US
8# EMail=test@example.com
924:D2:FC:A2:2E:B3:B8:0A:1E:37:71:D1:4C:C6:58:E3:21:2B:49:DC S
10
11
diff --git a/framework/domain/mimetreeparser/tests/interfacetest.cpp b/framework/domain/mimetreeparser/tests/interfacetest.cpp
new file mode 100644
index 00000000..5a3cbb87
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/interfacetest.cpp
@@ -0,0 +1,229 @@
1/*
2 Copyright (c) 2016 Sandro Knauß <knauss@kolabsystems.com>
3
4 This library is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or (at your
7 option) any later version.
8
9 This library is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12 License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to the
16 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 02110-1301, USA.
18*/
19
20#include "interface.h"
21#include "interface_p.h"
22
23#include <QTest>
24
25QByteArray readMailFromFile(const QString &mailFile)
26{
27 QFile file(QLatin1String(MAIL_DATA_DIR) + QLatin1Char('/') + mailFile);
28 file.open(QIODevice::ReadOnly);
29 Q_ASSERT(file.isOpen());
30 return file.readAll();
31}
32
33QByteArray join(QVector<QByteArray> vec, QByteArray sep)
34{
35 QByteArray ret;
36 bool bInit = true;
37 foreach(const auto &entry, vec) {
38 if (!bInit) {
39 ret += sep;
40 }
41 bInit = false;
42 ret += entry;
43 }
44 return ret;
45}
46
47class InterfaceTest : public QObject
48{
49 Q_OBJECT
50private:
51 void printTree(const Part::Ptr &start, QString pre)
52 {
53 foreach (const auto &part, start->subParts()) {
54 qWarning() << QStringLiteral("%1* %2(%3)")
55 .arg(pre)
56 .arg(QString::fromLatin1(part->type()))
57 .arg(QString::fromLatin1(join(part->availableContents(),", ")));
58 printTree(part,pre + QStringLiteral(" "));
59 }
60 }
61
62private slots:
63
64 void testTextMail()
65 {
66 Parser parser(readMailFromFile("plaintext.mbox"));
67 printTree(parser.d->mTree,QString());
68 auto contentPartList = parser.collectContentParts();
69 QCOMPARE(contentPartList.size(), 1);
70 auto contentPart = contentPartList[0];
71 QVERIFY((bool)contentPart);
72 QCOMPARE(contentPart->availableContents(), QVector<QByteArray>() << "plaintext");
73 auto contentList = contentPart->content("plaintext");
74 QCOMPARE(contentList.size(), 1);
75 QCOMPARE(contentList[0]->content(), QStringLiteral("If you can see this text it means that your email client couldn't display our newsletter properly.\nPlease visit this link to view the newsletter on our website: http://www.gog.com/newsletter/").toLocal8Bit());
76 QCOMPARE(contentList[0]->charset(), QStringLiteral("utf-8").toLocal8Bit());
77 QCOMPARE(contentList[0]->encryptions().size(), 0);
78 QCOMPARE(contentList[0]->signatures().size(), 0);
79
80 contentList = contentPart->content("html");
81 QCOMPARE(contentList.size(), 0);
82 auto contentAttachmentList = parser.collectAttachmentParts();
83 QCOMPARE(contentAttachmentList.size(), 0);
84 }
85
86 void testTextAlternative()
87 {
88 Parser parser(readMailFromFile("alternative.mbox"));
89 printTree(parser.d->mTree,QString());
90 auto contentPartList = parser.collectContentParts();
91 QCOMPARE(contentPartList.size(), 1);
92 auto contentPart = contentPartList[0];
93 QVERIFY((bool)contentPart);
94 QCOMPARE(contentPart->availableContents(), QVector<QByteArray>() << "html" << "plaintext");
95 auto contentList = contentPart->content("plaintext");
96 QCOMPARE(contentList.size(), 1);
97 QCOMPARE(contentList[0]->content(), QStringLiteral("If you can see this text it means that your email client couldn't display our newsletter properly.\nPlease visit this link to view the newsletter on our website: http://www.gog.com/newsletter/\n").toLocal8Bit());
98 QCOMPARE(contentList[0]->charset(), QStringLiteral("utf-8").toLocal8Bit());
99 QCOMPARE(contentList[0]->encryptions().size(), 0);
100 QCOMPARE(contentList[0]->signatures().size(), 0);
101
102 contentList = contentPart->content("html");
103 QCOMPARE(contentList.size(), 1);
104 QCOMPARE(contentList[0]->content(), QStringLiteral("<html><body><p><span>HTML</span> text</p></body></html>\n\n").toLocal8Bit());
105 QCOMPARE(contentList[0]->charset(), QStringLiteral("utf-8").toLocal8Bit());
106 QCOMPARE(contentList[0]->encryptions().size(), 0);
107 QCOMPARE(contentList[0]->signatures().size(), 0);
108 auto contentAttachmentList = parser.collectAttachmentParts();
109 QCOMPARE(contentAttachmentList.size(), 0);
110 }
111
112 void testTextHtml()
113 {
114 Parser parser(readMailFromFile("html.mbox"));
115 printTree(parser.d->mTree,QString());
116 auto contentPartList = parser.collectContentParts();
117 QCOMPARE(contentPartList.size(), 1);
118 auto contentPart = contentPartList[0];
119 QVERIFY((bool)contentPart);
120 QCOMPARE(contentPart->availableContents(), QVector<QByteArray>() << "html");
121
122 auto contentList = contentPart->content("plaintext");
123 QCOMPARE(contentList.size(), 0);
124
125 contentList = contentPart->content("html");
126 QCOMPARE(contentList.size(), 1);
127 QCOMPARE(contentList[0]->content(), QStringLiteral("<html><body><p><span>HTML</span> text</p></body></html>").toLocal8Bit());
128 QCOMPARE(contentList[0]->charset(), QStringLiteral("utf-8").toLocal8Bit());
129 QCOMPARE(contentList[0]->encryptions().size(), 0);
130 QCOMPARE(contentList[0]->signatures().size(), 0);
131 auto contentAttachmentList = parser.collectAttachmentParts();
132 QCOMPARE(contentAttachmentList.size(), 0);
133 }
134
135 void testSMimeEncrypted()
136 {
137 Parser parser(readMailFromFile("smime-encrypted.mbox"));
138 printTree(parser.d->mTree,QString());
139 auto contentPartList = parser.collectContentParts();
140 QCOMPARE(contentPartList.size(), 1);
141 auto contentPart = contentPartList[0];
142 QVERIFY((bool)contentPart);
143 QCOMPARE(contentPart->availableContents(), QVector<QByteArray>() << "plaintext");
144 auto contentList = contentPart->content("plaintext");
145 QCOMPARE(contentList.size(), 1);
146 QCOMPARE(contentList[0]->content(), QStringLiteral("The quick brown fox jumped over the lazy dog.").toLocal8Bit());
147 QCOMPARE(contentList[0]->charset(), QStringLiteral("utf-8").toLocal8Bit());
148 QCOMPARE(contentList[0]->encryptions().size(), 1);
149 QCOMPARE(contentList[0]->signatures().size(), 0);
150 auto contentAttachmentList = parser.collectAttachmentParts();
151 QCOMPARE(contentAttachmentList.size(), 0);
152 }
153
154 void testOpenPGPEncryptedAttachment()
155 {
156 Parser parser(readMailFromFile("openpgp-encrypted-attachment-and-non-encrypted-attachment.mbox"));
157 printTree(parser.d->mTree,QString());
158 auto contentPartList = parser.collectContentParts();
159 QCOMPARE(contentPartList.size(), 1);
160 auto contentPart = contentPartList[0];
161 QVERIFY((bool)contentPart);
162 QCOMPARE(contentPart->availableContents(), QVector<QByteArray>() << "plaintext");
163 auto contentList = contentPart->content("plaintext");
164 QCOMPARE(contentList.size(), 1);
165 QCOMPARE(contentList[0]->content(), QStringLiteral("test text").toLocal8Bit());
166 QCOMPARE(contentList[0]->charset(), QStringLiteral("utf-8").toLocal8Bit());
167 QCOMPARE(contentList[0]->encryptions().size(), 1);
168 QCOMPARE(contentList[0]->signatures().size(), 1);
169 auto contentAttachmentList = parser.collectAttachmentParts();
170 QCOMPARE(contentAttachmentList.size(), 2);
171 QCOMPARE(contentAttachmentList[0]->availableContents(), QVector<QByteArray>() << "text/plain");
172 QCOMPARE(contentAttachmentList[0]->content().size(), 1);
173 QCOMPARE(contentAttachmentList[0]->encryptions().size(), 1);
174 QCOMPARE(contentAttachmentList[0]->signatures().size(), 1);
175 QCOMPARE(contentAttachmentList[1]->availableContents(), QVector<QByteArray>() << "image/png");
176 QCOMPARE(contentAttachmentList[1]->content().size(), 1);
177 QCOMPARE(contentAttachmentList[1]->encryptions().size(), 0);
178 QCOMPARE(contentAttachmentList[1]->signatures().size(), 0);
179 }
180
181 void testOpenPPGInline()
182 {
183 Parser parser(readMailFromFile("openpgp-inline-charset-encrypted.mbox"));
184 printTree(parser.d->mTree,QString());
185 auto contentPartList = parser.collectContentParts();
186 QCOMPARE(contentPartList.size(), 1);
187 auto contentPart = contentPartList[0];
188 QVERIFY((bool)contentPart);
189 QCOMPARE(contentPart->availableContents(), QVector<QByteArray>() << "plaintext");
190 QCOMPARE(contentPart->encryptions().size(), 0);
191 QCOMPARE(contentPart->signatures().size(), 0);
192 auto contentList = contentPart->content("plaintext");
193 QCOMPARE(contentList.size(), 1);
194 QCOMPARE(contentList[0]->content(), QStringLiteral("asdasd asd asd asdf sadf sdaf sadf äöü").toLocal8Bit());
195 QCOMPARE(contentList[0]->charset(), QStringLiteral("utf-8").toLocal8Bit());
196 QCOMPARE(contentList[0]->encryptions().size(), 1);
197 QCOMPARE(contentList[0]->signatures().size(), 1);
198 auto contentAttachmentList = parser.collectAttachmentParts();
199 QCOMPARE(contentAttachmentList.size(), 0);
200 }
201
202 void testOpenPPGInlineWithNonEncText()
203 {
204 Parser parser(readMailFromFile("openpgp-inline-encrypted+nonenc.mbox"));
205 printTree(parser.d->mTree,QString());
206 auto contentPartList = parser.collectContentParts();
207 QCOMPARE(contentPartList.size(), 1);
208 auto contentPart = contentPartList[0];
209 QVERIFY((bool)contentPart);
210 QCOMPARE(contentPart->availableContents(), QVector<QByteArray>() << "plaintext");
211 QCOMPARE(contentPart->encryptions().size(), 0);
212 QCOMPARE(contentPart->signatures().size(), 0);
213 auto contentList = contentPart->content("plaintext");
214 QCOMPARE(contentList.size(), 2);
215 QCOMPARE(contentList[0]->content(), QStringLiteral("Not encrypted not signed :(\n\n").toLocal8Bit());
216 QCOMPARE(contentList[0]->charset(), QStringLiteral("utf-8").toLocal8Bit());
217 QCOMPARE(contentList[0]->encryptions().size(), 0);
218 QCOMPARE(contentList[0]->signatures().size(), 0);
219 QCOMPARE(contentList[1]->content(), QStringLiteral("some random text").toLocal8Bit());
220 QCOMPARE(contentList[1]->charset(), QStringLiteral("utf-8").toLocal8Bit());
221 QCOMPARE(contentList[1]->encryptions().size(), 1);
222 QCOMPARE(contentList[1]->signatures().size(), 0);
223 auto contentAttachmentList = parser.collectAttachmentParts();
224 QCOMPARE(contentAttachmentList.size(), 0);
225 }
226};
227
228QTEST_GUILESS_MAIN(InterfaceTest)
229#include "interfacetest.moc"
diff --git a/framework/domain/mimetreeparser/tests/kdepim_add_gpg_crypto_test.cmake b/framework/domain/mimetreeparser/tests/kdepim_add_gpg_crypto_test.cmake
new file mode 100644
index 00000000..17078202
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/kdepim_add_gpg_crypto_test.cmake
@@ -0,0 +1,60 @@
1# Copyright (c) 2013 Sandro Knauß <mail@sandroknauss.de>
2#
3# Redistribution and use is allowed according to the terms of the BSD license.
4# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
5
6set( GNUPGHOME ${CMAKE_BINARY_DIR}/framework/domain/mimetreeparser/tests/gnupg_home )
7add_definitions( -DGNUPGHOME="\\"${GNUPGHOME}\\"" )
8
9macro (ADD_GPG_CRYPTO_TEST _target _testname)
10 if (UNIX)
11 if (APPLE)
12 set(_library_path_variable "DYLD_LIBRARY_PATH")
13 elseif (CYGWIN)
14 set(_library_path_variable "PATH")
15 else (APPLE)
16 set(_library_path_variable "LD_LIBRARY_PATH")
17 endif (APPLE)
18
19 if (APPLE)
20 # DYLD_LIBRARY_PATH does not work like LD_LIBRARY_PATH
21 # OSX already has the RPATH in libraries and executables, putting runtime directories in
22 # DYLD_LIBRARY_PATH actually breaks things
23 set(_ld_library_path "${LIBRARY_OUTPUT_PATH}/${CMAKE_CFG_INTDIR}/")
24 else (APPLE)
25 set(_ld_library_path "${LIBRARY_OUTPUT_PATH}/${CMAKE_CFG_INTDIR}/:${LIB_INSTALL_DIR}:${QT_LIBRARY_DIR}")
26 endif (APPLE)
27 set(_executable "$<TARGET_FILE:${_target}>")
28
29 # use add_custom_target() to have the sh-wrapper generated during build time instead of cmake time
30 add_custom_command(TARGET ${_target} POST_BUILD
31 COMMAND ${CMAKE_COMMAND}
32 -D_filename=${_executable}.shell -D_library_path_variable=${_library_path_variable}
33 -D_ld_library_path="${_ld_library_path}" -D_executable=$<TARGET_FILE:${_target}>
34 -D_gnupghome="${GNUPGHOME}"
35 -P ${CMAKE_SOURCE_DIR}/framework/domain/mimetreeparser/tests/kdepim_generate_crypto_test_wrapper.cmake
36 )
37
38 set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${_executable}.shell" )
39 add_test(NAME ${_testname} COMMAND ${_executable}.shell)
40
41 else (UNIX)
42 # under windows, set the property WRAPPER_SCRIPT just to the name of the executable
43 # maybe later this will change to a generated batch file (for setting the PATH so that the Qt libs are found)
44 set(_ld_library_path "${LIBRARY_OUTPUT_PATH}/${CMAKE_CFG_INTDIR}\;${LIB_INSTALL_DIR}\;${QT_LIBRARY_DIR}")
45 set(_executable "$<TARGET_FILE:${_target}>")
46
47 # use add_custom_target() to have the batch-file-wrapper generated during build time instead of cmake time
48 add_custom_command(TARGET ${_target} POST_BUILD
49 COMMAND ${CMAKE_COMMAND}
50 -D_filename="${_executable}.bat"
51 -D_ld_library_path="${_ld_library_path}" -D_executable="${_executable}"
52 -D_gnupghome="${GNUPGHOME}"
53 -P ${CMAKE_SOURCE_DIR}/framework/domain/mimetreeparser/tests/kdepim_generate_crypto_test_wrapper.cmake
54 )
55
56 add_test(NAME ${_testname} COMMAND ${_executable}.bat)
57
58 endif (UNIX)
59endmacro (ADD_GPG_CRYPTO_TEST)
60
diff --git a/framework/domain/mimetreeparser/tests/kdepim_generate_crypto_test_wrapper.cmake b/framework/domain/mimetreeparser/tests/kdepim_generate_crypto_test_wrapper.cmake
new file mode 100644
index 00000000..e1412f37
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/kdepim_generate_crypto_test_wrapper.cmake
@@ -0,0 +1,45 @@
1# Copyright (c) 2006, Alexander Neundorf, <neundorf@kde.org>
2# Copyright (c) 2013, Sandro Knauß <mail@sandroknauss.de>
3#
4# Redistribution and use is allowed according to the terms of the BSD license.
5# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
6
7
8if (UNIX)
9
10file(WRITE "${_filename}"
11"#!/bin/sh
12# created by cmake, don't edit, changes will be lost
13
14# don't mess with a gpg-agent already running on the system
15unset GPG_AGENT_INFO
16
17${_library_path_variable}=${_ld_library_path}\${${_library_path_variable}:+:\$${_library_path_variable}} GNUPGHOME=${_gnupghome} gpg-agent --daemon \"${_executable}\" \"$@\"
18_result=$?
19_pid=`echo GETINFO pid | GNUPGHOME=${_gnupghome} gpg-connect-agent | grep 'D' | cut -d' ' -f2`
20if [ ! -z \"\$_pid\" ]; then
21 echo \"Waiting for gpg-agent to terminate (PID: $_pid)...\"
22 while kill -0 \"\$_pid\"; do
23 sleep 1
24 done
25fi
26exit \$_result
27")
28
29# make it executable
30# since this is only executed on UNIX, it is safe to call chmod
31exec_program(chmod ARGS ug+x \"${_filename}\" OUTPUT_VARIABLE _dummy )
32
33else (UNIX)
34
35file(TO_NATIVE_PATH "${_ld_library_path}" win_path)
36file(TO_NATIVE_PATH "${_gnupghome}" win_gnupghome)
37
38file(WRITE "${_filename}"
39"
40set PATH=${win_path};$ENV{PATH}
41set GNUPGHOME=${win_gnupghome};$ENV{GNUPGHOME}
42gpg-agent --daemon \"${_executable}\" %*
43")
44
45endif (UNIX)
diff --git a/framework/domain/mimetreeparser/thoughts.txt b/framework/domain/mimetreeparser/thoughts.txt
new file mode 100644
index 00000000..3340347a
--- /dev/null
+++ b/framework/domain/mimetreeparser/thoughts.txt
@@ -0,0 +1,148 @@
1Usecases:
2
3# plaintext msg + attachment
4* ContentPart => cp1
5* AttachmentPart => ap1
6
7(cp1) == collect<ContentPart>(select=NoEncapsulatedMessages)
8(ap1) == collect<AttachmentParts>(select=NoEncapsulatedMessages)
9
10(PlainText) == cp1.availableContent()
11
12# html msg + related attachment + normal attachment
13* ContentPart => cp1
14* AttachmentPart(mimetype="*/related", cid="12345678") => ap1
15* AttachmentPart => ap2
16
17(cp1) == collect<ContentPart>(select=NoEncapsulatedMessages)
18(ap1, ap2) == collect<AttachmentParts>(select=NoEncapsulatedMessages)
19(ap2) == collect<AttachmentParts>(select=NoEncapsulatedMessages, filter=filterelated)
20
21ap1 == getPart("cid:12345678")
22
23(Html) == cp1.availableContent()
24
25# alternative msg + attachment
26* ContentPart(html=[Content("HTML"),], plaintext=[Content("Text"),]) => cp1
27* AttachmentPart => ap1
28
29(cp1) == collect<ContentPart>(select=NoEncapsulatedMessages)
30(ap1) == collect<AttachmentParts>(select=NoEncapsulatedMessages)
31
32(Html, PlainText) == cp1.availableContent()
33[Content("HTML"),] == cp1.content(Html)
34[Content("Text"),] == cp1.content(Plaintext)
35
36# alternative msg with GPGInlin
37* ContentPart(
38 plaintext=[Content("Text"), Content("foo", encryption=(enc1))],
39 html=[Content("HTML"),]
40 ) => cp1
41
42(Html, PlainText) == cp1.availableContent()
43
44[Content("HTML"),] == cp1.content(Html)
45[Content("Text"),Content("foo", encryption=(enc1))] == cp1.content(Plaintext)
46
47
48# encrypted msg (not encrypted/error) with unencrypted attachment
49* EncryptionErrorPart => cp1
50* AttachmentPart => ap1
51
52(cp1) == collect<ContentPart>(select=NoEncapsulatedMessages)
53(ap1) == collect<AttachmentParts>(select=NoEncapsulatedMessages)
54
55#encrypted msg (decrypted with attachment) + unencrypted attachment
56* encrytion=(rec1,rec2) => enc1
57 * ContentPart(encrytion = (enc1,)) => cp1
58 * AttachmentPart(encryption = (enc1,)) => ap1
59* AttachmentPart => ap2
60
61(cp1) == collect<ContentPart>(select=NoEncapsulatedMessages)
62(ap1, ap2) == collect<AttachmentParts>(select=NoEncapsulatedMessages)
63
64#INLINE GPG encrypted msg + attachment
65* ContentPart => cp1 with
66 plaintext=[Content, Content(encrytion = (enc1(rec1,rec2),)), Content(signed = (sig1,)), Content]
67* AttachmentPart => ap1
68
69(cp1) == collect<ContentPart>(select=NoEncapsulatedMessages)
70(ap1) == collect<AttachmentParts>(select=NoEncapsulatedMessages)
71
72[Content, Content(encrytion = (enc1(rec1,rec2),)), Content(signed = (sig1,)), Content] == cp1.content(Plaintext)
73
74#forwared encrypted msg + attachments
75* ContentPart => cp1
76* EncapsulatedPart => ep1
77 * Encrytion=(rec1,rec2) => enc1
78 * Signature => sig1
79 * ContentPart(encrytion = (enc1,), signature = (sig1,)) => cp2
80 * Content(encrytion = (enc1,), signature = (sig1,))
81 * Content(encrytion = (enc1, enc2(rec3,rec4),), signature = (sig1,))
82 * AttachmentPart(encrytion = (enc1,), signature = (sig1,)) => ap1
83* AttachmentPart => ap2
84
85(cp1) = collect<ContentPart>(select=NoEncapsulatedMessages)
86(ap2) = collect<AttachmentParts>(select=NoEncapsulatedMessages)
87
88(cp2) = collect<ContentPart>(ep1, select=NoEncapsulatedMessages)
89(ap1) = collect<AttachmentParts>(ep1, select=NoEncapsulatedMessages)
90
91(cp1, cp2) == collect<ContentPart>()
92(ap1, ap2) == collect<AttachmentParts>()[Content, Content(encrytion = (enc1(rec1,rec2),)), Content(signed = (sig1,)), Content]
93
94
95# plaintext msg + attachment + cert
96* ContentPart => cp1
97* AttachmentPart => ap1
98* CertPart => cep1
99
100(cp1) == collect<ContentPart>(select=NoEncapsulatedMessages)
101(ap1, cep1) == collect<AttachmentPart>(select=NoEncapsulatedMessages)
102(ap1) == collect<AttachmentPart>(select=NoEncapsulatedMessages, filter=filterSubAttachmentParts)
103
104(cep1) == collect<CertPart>(select=NoEncapsulatedMessages)
105
106
107collect function:
108
109bool noEncapsulatedMessages(Part part)
110{
111 if (is<EncapsulatedPart>(part)) {
112 return false;
113 }
114 return true;
115}
116
117bool filterRelated(T part)
118{
119 if (part.mimetype == related && !part.cid.isEmpty()) {
120 return false; //filter out related parts
121 }
122 return true;
123}
124
125bool filterSubAttachmentParts(AttachmentPart part)
126{
127 if (isSubPart<AttachmentPart>(part)) {
128 return false; // filter out CertPart f.ex.
129 }
130 return true;
131}
132
133List<T> collect<T>(Part start, std::function<bool(const Part &)> select, std::function<bool(const std::shared_ptr<T> &)> filter) {
134 List<T> col;
135 if (!select(start)) {
136 return col;
137 }
138
139 if(isOrSubTypeIs<T>(start) && filter(start.staticCast<T>)){
140 col.append(p);
141 }
142 foreach(childs as child) {
143 if (select(child)) {
144 col.expand(collect(child,select,filter);
145 }
146 }
147 return col;
148} \ No newline at end of file