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.txt2
-rw-r--r--framework/domain/messageparser.cpp123
-rw-r--r--framework/domain/messageparser.h57
-rw-r--r--framework/domain/messageparser_new.cpp148
-rw-r--r--framework/domain/messageparser_old.cpp140
-rw-r--r--framework/domain/mimetreeparser/CMakeLists.txt5
-rw-r--r--framework/domain/mimetreeparser/interface.cpp14
-rw-r--r--framework/domain/mimetreeparser/interface.h2
-rw-r--r--framework/domain/mimetreeparser/tests/data/openpgp-inline-encrypted+nonenc.mbox31
-rw-r--r--framework/domain/mimetreeparser/tests/interfacetest.cpp27
17 files changed, 528 insertions, 240 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 07f01367..c41da377 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
diff --git a/framework/domain/messageparser.cpp b/framework/domain/messageparser.cpp
index febd1363..ef9fb0d2 100644
--- a/framework/domain/messageparser.cpp
+++ b/framework/domain/messageparser.cpp
@@ -33,125 +33,6 @@
33#include <MimeTreeParser/ObjectTreeParser> 33#include <MimeTreeParser/ObjectTreeParser>
34#include <MimeTreeParser/MessagePart> 34#include <MimeTreeParser/MessagePart>
35 35
36PartModel::PartModel(QSharedPointer<MimeTreeParser::MessagePart> partTree, std::shared_ptr<Parser> parser)
37 : mPartTree(partTree)
38 , mParser(parser)
39{
40}
41
42QHash<int, QByteArray> PartModel::roleNames() const
43{
44 QHash<int, QByteArray> roles;
45 roles[Text] = "text";
46 roles[IsHtml] = "isHtml";
47 roles[IsHidden] = "isHidden";
48 roles[IsEncrypted] = "isEncrypted";
49 roles[IsAttachment] = "isAttachment";
50 roles[HasContent] = "hasContent";
51 roles[Type] = "type";
52 roles[IsHidden] = "isHidden";
53 return roles;
54}
55
56QModelIndex PartModel::index(int row, int column, const QModelIndex &parent) const
57{
58 // qDebug() << "index " << parent << row << column << mPartTree->subParts().size();
59 if (!parent.isValid()) {
60 if (row < mPartTree->subParts().size()) {
61 auto part = mPartTree->subParts().at(row);
62 return createIndex(row, column, part.data());
63 }
64 } else {
65 auto part = static_cast<MimeTreeParser::MessagePart*>(parent.internalPointer());
66 auto subPart = part->subParts().at(row);
67 return createIndex(row, column, subPart.data());
68 }
69 return QModelIndex();
70}
71
72QVariant PartModel::data(const QModelIndex &index, int role) const
73{
74 // qDebug() << "Getting data for index";
75 if (index.isValid()) {
76 auto part = static_cast<MimeTreeParser::MessagePart*>(index.internalPointer());
77 switch (role) {
78 case Text: {
79 // qDebug() << "Getting text: " << part->property("text").toString();
80 // FIXME: we should have a list per part, and not one for all parts.
81 auto text = part->property("htmlContent").toString();
82 auto rx = QRegExp("src=(\"|')cid:([^\1]*)\1");
83 int pos = 0;
84 while ((pos = rx.indexIn(text, pos)) != -1) {
85 auto repl = mParser->getPart(rx.cap(2).toUtf8());
86 if (repl.isValid()) {
87 text.replace(rx.cap(0), QString("src=\"%1\"").arg(repl.toString()));
88 }
89 pos += rx.matchedLength();
90 }
91 return text;
92 }
93 case IsAttachment:
94 return part->property("attachment").toBool();
95 case IsEncrypted:
96 return part->property("isEncrypted").toBool();
97 case IsHtml:
98 return part->property("isHtml").toBool();
99 case HasContent:
100 return !part->property("htmlContent").toString().isEmpty();
101 case Type:
102 return part->metaObject()->className();
103 case IsHidden:
104 return false;
105 //return part->property("isHidden").toBool();
106
107 }
108 }
109 return QVariant();
110}
111
112QModelIndex PartModel::parent(const QModelIndex &index) const
113{
114 // qDebug() << "parent " << index;
115 if (index.isValid()) {
116 auto part = static_cast<MimeTreeParser::MessagePart*>(index.internalPointer());
117 auto parentPart = static_cast<MimeTreeParser::MessagePart*>(part->parentPart());
118 auto row = 0;//get the parents parent to find the index
119 if (!parentPart) {
120 parentPart = mPartTree.data();
121 }
122 int i = 0;
123 for (const auto &p : parentPart->subParts()) {
124 if (p.data() == part) {
125 row = i;
126 break;
127 }
128 i++;
129 }
130 return createIndex(row, index.column(), parentPart);
131 }
132 return QModelIndex();
133}
134
135int PartModel::rowCount(const QModelIndex &parent) const
136{
137 // qDebug() << "Row count " << parent;
138 if (!parent.isValid()) {
139 // qDebug() << "Row count " << mPartTree->subParts().size();
140 return mPartTree->subParts().size();
141 } else {
142 auto part = static_cast<MimeTreeParser::MessagePart*>(parent.internalPointer());
143 if (part) {
144 return part->subParts().size();
145 }
146 }
147 return 0;
148}
149
150int PartModel::columnCount(const QModelIndex &parent) const
151{
152 // qDebug() << "Column count " << parent;
153 return 1;
154}
155 36
156class MessagePartPrivate 37class MessagePartPrivate
157{ 38{
@@ -217,3 +98,7 @@ QAbstractItemModel *MessageParser::partTree() const
217 return new PartModel(d->mPartTree, d->mParser); 98 return new PartModel(d->mPartTree, d->mParser);
218} 99}
219 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 9469f2b5..b3d7537d 100644
--- a/framework/domain/messageparser.h
+++ b/framework/domain/messageparser.h
@@ -32,6 +32,10 @@
32class QAbstractItemModel; 32class QAbstractItemModel;
33 33
34class Parser; 34class Parser;
35class Part;
36typedef std::shared_ptr<Part> PartPtr;
37class Content;
38typedef std::shared_ptr<Content> ContentPtr;
35class MessagePartPrivate; 39class MessagePartPrivate;
36 40
37class MessageParser : public QObject 41class MessageParser : public QObject
@@ -40,6 +44,7 @@ class MessageParser : public QObject
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);
@@ -50,6 +55,7 @@ public:
50 QVariant message() const; 55 QVariant message() const;
51 void setMessage(const QVariant &to); 56 void setMessage(const QVariant &to);
52 QAbstractItemModel *partTree() const; 57 QAbstractItemModel *partTree() const;
58 QAbstractItemModel *newTree() const;
53 59
54signals: 60signals:
55 void htmlChanged(); 61 void htmlChanged();
@@ -87,3 +93,54 @@ private:
87 std::shared_ptr<Parser> mParser; 93 std::shared_ptr<Parser> mParser;
88}; 94};
89 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;
145};
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
index e1c04893..64da2656 100644
--- a/framework/domain/mimetreeparser/CMakeLists.txt
+++ b/framework/domain/mimetreeparser/CMakeLists.txt
@@ -9,4 +9,7 @@ add_library(mimetreeparser SHARED ${mimetreeparser_SRCS})
9qt5_use_modules(mimetreeparser Core Gui) 9qt5_use_modules(mimetreeparser Core Gui)
10target_link_libraries(mimetreeparser KF5::Mime KF5::MimeTreeParser) 10target_link_libraries(mimetreeparser KF5::Mime KF5::MimeTreeParser)
11 11
12add_subdirectory(tests) \ No newline at end of file 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
index c3ecf79c..efa0fd40 100644
--- a/framework/domain/mimetreeparser/interface.cpp
+++ b/framework/domain/mimetreeparser/interface.cpp
@@ -30,6 +30,7 @@
30 30
31#include <QMimeDatabase> 31#include <QMimeDatabase>
32#include <QMimeType> 32#include <QMimeType>
33#include <QTextCodec>
33#include <QDebug> 34#include <QDebug>
34 35
35class MailMimePrivate 36class MailMimePrivate
@@ -356,6 +357,17 @@ QByteArray Content::charset() const
356 return d->mCodec; 357 return d->mCodec;
357} 358}
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
359QByteArray Content::type() const 371QByteArray Content::type() const
360{ 372{
361 return "Content"; 373 return "Content";
@@ -496,7 +508,7 @@ void SinglePartPrivate::fillFrom(MimeTreeParser::TextMessagePart::Ptr part)
496 mContent.clear(); 508 mContent.clear();
497 foreach (const auto &mp, part->subParts()) { 509 foreach (const auto &mp, part->subParts()) {
498 auto d_ptr = new ContentPrivate; 510 auto d_ptr = new ContentPrivate;
499 d_ptr->mContent = part->text().toLocal8Bit(); 511 d_ptr->mContent = mp->text().toLocal8Bit();
500 d_ptr->mParent = q; 512 d_ptr->mParent = q;
501 d_ptr->mCodec = "utf-8"; 513 d_ptr->mCodec = "utf-8";
502 const auto enc = mp.dynamicCast<MimeTreeParser::EncryptedMessagePart>(); 514 const auto enc = mp.dynamicCast<MimeTreeParser::EncryptedMessagePart>();
diff --git a/framework/domain/mimetreeparser/interface.h b/framework/domain/mimetreeparser/interface.h
index 7eadc311..67246f37 100644
--- a/framework/domain/mimetreeparser/interface.h
+++ b/framework/domain/mimetreeparser/interface.h
@@ -125,7 +125,7 @@ public:
125 QString encodedContent() const; 125 QString encodedContent() const;
126 126
127 // overwrite default charset with given charset 127 // overwrite default charset with given charset
128 QString encodedContent(QByteArray charset) const; 128 QString encodedContent(const QByteArray &charset) const;
129 129
130 QVector<SignaturePtr> signatures() const; 130 QVector<SignaturePtr> signatures() const;
131 QVector<EncryptionPtr> encryptions() const; 131 QVector<EncryptionPtr> encryptions() const;
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/interfacetest.cpp b/framework/domain/mimetreeparser/tests/interfacetest.cpp
index ac77b025..5a3cbb87 100644
--- a/framework/domain/mimetreeparser/tests/interfacetest.cpp
+++ b/framework/domain/mimetreeparser/tests/interfacetest.cpp
@@ -198,7 +198,32 @@ private slots:
198 auto contentAttachmentList = parser.collectAttachmentParts(); 198 auto contentAttachmentList = parser.collectAttachmentParts();
199 QCOMPARE(contentAttachmentList.size(), 0); 199 QCOMPARE(contentAttachmentList.size(), 0);
200 } 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 }
201}; 226};
202 227
203QTEST_GUILESS_MAIN(InterfaceTest) 228QTEST_GUILESS_MAIN(InterfaceTest)
204#include "interfacetest.moc" \ No newline at end of file 229#include "interfacetest.moc"