diff options
Diffstat (limited to 'framework/domain')
33 files changed, 3345 insertions, 0 deletions
diff --git a/framework/domain/CMakeLists.txt b/framework/domain/CMakeLists.txt new file mode 100644 index 00000000..822b2981 --- /dev/null +++ b/framework/domain/CMakeLists.txt | |||
@@ -0,0 +1,32 @@ | |||
1 | set(mailplugin_SRCS | ||
2 | mailplugin.cpp | ||
3 | maillistcontroller.cpp | ||
4 | maillistmodel.cpp | ||
5 | singlemailcontroller.cpp | ||
6 | folderlistmodel.cpp | ||
7 | folderlistcontroller.cpp | ||
8 | actions/sinkactions.cpp | ||
9 | actions/mailactions.cpp | ||
10 | objecttreesource.cpp | ||
11 | stringhtmlwriter.cpp | ||
12 | csshelper.cpp | ||
13 | composer.cpp | ||
14 | messageparser.cpp | ||
15 | mailtransport.cpp | ||
16 | mailtemplates.cpp | ||
17 | retriever.cpp | ||
18 | ) | ||
19 | add_definitions(-DMAIL_DATA_DIR="${CMAKE_CURRENT_SOURCE_DIR}/data") | ||
20 | |||
21 | find_package(CURL 7.20.0 REQUIRED) | ||
22 | |||
23 | include_directories(${CURL_INCLUDE_DIRS}) | ||
24 | |||
25 | add_library(mailplugin SHARED ${mailplugin_SRCS}) | ||
26 | |||
27 | qt5_use_modules(mailplugin Core Quick Qml WebKitWidgets) | ||
28 | |||
29 | target_link_libraries(mailplugin actionplugin settingsplugin sink KF5::Otp KF5::Codecs ${CURL_LIBRARIES}) | ||
30 | |||
31 | install(TARGETS mailplugin DESTINATION ${QML_INSTALL_DIR}/org/kde/kube/mail) | ||
32 | install(FILES qmldir DESTINATION ${QML_INSTALL_DIR}/org/kde/kube/mail) | ||
diff --git a/framework/domain/actions/mailactions.cpp b/framework/domain/actions/mailactions.cpp new file mode 100644 index 00000000..dab0533e --- /dev/null +++ b/framework/domain/actions/mailactions.cpp | |||
@@ -0,0 +1,48 @@ | |||
1 | /* | ||
2 | Copyright (c) 2016 Christian Mollekopf <mollekopf@kolabsys.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 | #include <actions/context.h> | ||
20 | #include <actions/actionhandler.h> | ||
21 | |||
22 | #include "../mailtransport.h" | ||
23 | #include <KMime/Message> | ||
24 | #include <QByteArray> | ||
25 | #include <QVariant> | ||
26 | #include <QDebug> | ||
27 | |||
28 | using namespace Kube; | ||
29 | |||
30 | static ActionHandlerHelper sendMailHandler("org.kde.kube.actions.sendmail", | ||
31 | [](Context *context) -> bool { | ||
32 | auto username = context->property("username").value<QByteArray>(); | ||
33 | auto password = context->property("password").value<QByteArray>(); | ||
34 | auto server = context->property("server").value<QByteArray>(); | ||
35 | auto message = context->property("message").value<KMime::Message::Ptr>(); | ||
36 | return !username.isEmpty() && !password.isEmpty() && !server.isEmpty() && message; | ||
37 | }, | ||
38 | [](Context *context) { | ||
39 | auto username = context->property("username").value<QByteArray>(); | ||
40 | auto password = context->property("password").value<QByteArray>(); | ||
41 | auto server = context->property("server").value<QByteArray>(); | ||
42 | //For ssl use "smtps://mainserver.example.net | ||
43 | QByteArray cacert; // = "/path/to/certificate.pem"; | ||
44 | auto message = context->property("message").value<KMime::Message::Ptr>(); | ||
45 | qWarning() << "Sending a mail: "; | ||
46 | MailTransport::sendMessage(message, server, username, password, cacert); | ||
47 | } | ||
48 | ); | ||
diff --git a/framework/domain/actions/sinkactions.cpp b/framework/domain/actions/sinkactions.cpp new file mode 100644 index 00000000..a19ab149 --- /dev/null +++ b/framework/domain/actions/sinkactions.cpp | |||
@@ -0,0 +1,106 @@ | |||
1 | /* | ||
2 | Copyright (c) 2016 Christian Mollekopf <mollekopf@kolabsys.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 | #include <actions/context.h> | ||
20 | #include <actions/actionhandler.h> | ||
21 | |||
22 | #include <sink/store.h> | ||
23 | |||
24 | using namespace Kube; | ||
25 | |||
26 | static ActionHandlerHelper markAsReadHandler("org.kde.kube.actions.mark-as-read", | ||
27 | [](Context *context) -> bool { | ||
28 | return context->property("mail").isValid(); | ||
29 | }, | ||
30 | [](Context *context) { | ||
31 | auto mail = context->property("mail").value<Sink::ApplicationDomain::Mail::Ptr>(); | ||
32 | if (!mail) { | ||
33 | qWarning() << "Failed to get the mail mail: " << context->property("mail"); | ||
34 | return; | ||
35 | } | ||
36 | mail->setProperty("unread", false); | ||
37 | qDebug() << "Mark as read " << mail->identifier(); | ||
38 | Sink::Store::modify(*mail).exec(); | ||
39 | } | ||
40 | ); | ||
41 | |||
42 | static ActionHandlerHelper deleteHandler("org.kde.kube.actions.delete", | ||
43 | [](Context *context) -> bool { | ||
44 | return context->property("mail").isValid(); | ||
45 | }, | ||
46 | [](Context *context) { | ||
47 | auto mail = context->property("mail").value<Sink::ApplicationDomain::Mail::Ptr>(); | ||
48 | if (!mail) { | ||
49 | qWarning() << "Failed to get the mail mail: " << context->property("mail"); | ||
50 | return; | ||
51 | } | ||
52 | mail->setProperty("unread", false); | ||
53 | qDebug() << "Remove " << mail->identifier(); | ||
54 | Sink::Store::remove(*mail).exec(); | ||
55 | } | ||
56 | ); | ||
57 | |||
58 | static ActionHandlerHelper synchronizeHandler("org.kde.kube.actions.synchronize", | ||
59 | [](Context *context) -> bool { | ||
60 | return context->property("folder").isValid(); | ||
61 | }, | ||
62 | [](Context *context) { | ||
63 | auto folder = context->property("folder").value<Sink::ApplicationDomain::Folder::Ptr>(); | ||
64 | if (!folder) { | ||
65 | qWarning() << "Failed to get the folder: " << context->property("folder"); | ||
66 | return; | ||
67 | } | ||
68 | Sink::Store::synchronize(Sink::Query::ResourceFilter(folder->resourceInstanceIdentifier())).exec(); | ||
69 | } | ||
70 | ); | ||
71 | |||
72 | // static ActionHandlerHelper saveAsDraft("org.kde.kube.actions.save-as-draft", | ||
73 | // [](Context *context) -> bool { | ||
74 | // return context->property("mail").isValid(); | ||
75 | // }, | ||
76 | // [](Context *context) { | ||
77 | // Sink::Query query; | ||
78 | // query += Sink::Query::RequestedProperties(QByteArrayList() << "name") | ||
79 | // //FIXME do something like specialuse? | ||
80 | // query += Sink::Query::PropertyFilter("name", "Drafts"); | ||
81 | // // query += Sink::Query::PropertyContainsFilter("specialuser", "drafts"); | ||
82 | // query += Sink::Query::PropertyFilter("drafts", true); | ||
83 | // //TODO Use drafts folder of that specific account | ||
84 | // Sink::Store::fetchAll<Sink::ApplicationDomain::Folder>(query) | ||
85 | // .then<void, QList<Sink::ApplicationDomain::Folder>>([](const QList<Sink::ApplicationDomain::Folder> folders) { | ||
86 | // if (folders.isEmpty()) { | ||
87 | // return KAsync::start([]() { | ||
88 | // //If message is already existing, modify, otherwise create | ||
89 | // }); | ||
90 | // } | ||
91 | // }); | ||
92 | // //TODO | ||
93 | // // * Find drafts folder | ||
94 | // // * Store KMime::Message on disk for use in blob property | ||
95 | // // * Check if message is already existing and either create or update | ||
96 | // // * | ||
97 | // // auto mail = context->property("mail").value<Sink::ApplicationDomain::Mail::Ptr>(); | ||
98 | // // if (!mail) { | ||
99 | // // qWarning() << "Failed to get the mail mail: " << context->property("mail"); | ||
100 | // // return; | ||
101 | // // } | ||
102 | // // mail->setProperty("unread", false); | ||
103 | // // qDebug() << "Mark as read " << mail->identifier(); | ||
104 | // // Sink::Store::modify(*mail).exec(); | ||
105 | // } | ||
106 | // ); | ||
diff --git a/framework/domain/composer.cpp b/framework/domain/composer.cpp new file mode 100644 index 00000000..2f4fe2e9 --- /dev/null +++ b/framework/domain/composer.cpp | |||
@@ -0,0 +1,199 @@ | |||
1 | /* | ||
2 | Copyright (c) 2016 Michael Bohlender <michael.bohlender@kdemail.net> | ||
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 | |||
21 | #include "composer.h" | ||
22 | #include <actions/context.h> | ||
23 | #include <actions/action.h> | ||
24 | #include <settings/settings.h> | ||
25 | #include <KMime/Message> | ||
26 | #include <KCodecs/KEmailAddress> | ||
27 | #include <QVariant> | ||
28 | #include <QDebug> | ||
29 | |||
30 | #include "mailtemplates.h" | ||
31 | |||
32 | Composer::Composer(QObject *parent) : QObject(parent) | ||
33 | { | ||
34 | m_identityModel << "Kuberich <kuberich@kolabnow.com>" << "Uni <kuberich@university.edu>" << "Spam <hello.spam@spam.to>"; | ||
35 | } | ||
36 | |||
37 | QString Composer::to() const | ||
38 | { | ||
39 | return m_to; | ||
40 | } | ||
41 | |||
42 | void Composer::setTo(const QString &to) | ||
43 | { | ||
44 | if(m_to != to) { | ||
45 | m_to = to; | ||
46 | emit toChanged(); | ||
47 | } | ||
48 | } | ||
49 | |||
50 | QString Composer::cc() const | ||
51 | { | ||
52 | return m_cc; | ||
53 | } | ||
54 | |||
55 | void Composer::setCc(const QString &cc) | ||
56 | { | ||
57 | if(m_cc != cc) { | ||
58 | m_cc = cc; | ||
59 | emit ccChanged(); | ||
60 | } | ||
61 | } | ||
62 | |||
63 | QString Composer::bcc() const | ||
64 | { | ||
65 | return m_bcc; | ||
66 | } | ||
67 | |||
68 | void Composer::setBcc(const QString &bcc) | ||
69 | { | ||
70 | if(m_bcc != bcc) { | ||
71 | m_bcc = bcc; | ||
72 | emit bccChanged(); | ||
73 | } | ||
74 | } | ||
75 | |||
76 | QString Composer::subject() const | ||
77 | { | ||
78 | return m_subject; | ||
79 | } | ||
80 | |||
81 | void Composer::setSubject(const QString &subject) | ||
82 | { | ||
83 | if(m_subject != subject) { | ||
84 | m_subject = subject; | ||
85 | emit subjectChanged(); | ||
86 | } | ||
87 | } | ||
88 | |||
89 | QString Composer::body() const | ||
90 | { | ||
91 | return m_body; | ||
92 | } | ||
93 | |||
94 | void Composer::setBody(const QString &body) | ||
95 | { | ||
96 | if(m_body != body) { | ||
97 | m_body = body; | ||
98 | emit bodyChanged(); | ||
99 | } | ||
100 | } | ||
101 | |||
102 | QStringList Composer::identityModel() const | ||
103 | { | ||
104 | return m_identityModel; | ||
105 | } | ||
106 | |||
107 | int Composer::fromIndex() const | ||
108 | { | ||
109 | return m_fromIndex; | ||
110 | } | ||
111 | |||
112 | void Composer::setFromIndex(int fromIndex) | ||
113 | { | ||
114 | if(m_fromIndex != fromIndex) { | ||
115 | m_fromIndex = fromIndex; | ||
116 | emit fromIndexChanged(); | ||
117 | } | ||
118 | } | ||
119 | |||
120 | QVariant Composer::originalMessage() const | ||
121 | { | ||
122 | return m_originalMessage; | ||
123 | } | ||
124 | |||
125 | void Composer::setOriginalMessage(const QVariant &originalMessage) | ||
126 | { | ||
127 | const auto mailData = KMime::CRLFtoLF(originalMessage.toByteArray()); | ||
128 | if (!mailData.isEmpty()) { | ||
129 | KMime::Message::Ptr mail(new KMime::Message); | ||
130 | mail->setContent(mailData); | ||
131 | mail->parse(); | ||
132 | auto reply = MailTemplates::reply(mail); | ||
133 | //We assume reply | ||
134 | setTo(reply->to(true)->asUnicodeString()); | ||
135 | setCc(reply->cc(true)->asUnicodeString()); | ||
136 | setSubject(reply->subject(true)->asUnicodeString()); | ||
137 | setBody(reply->body()); | ||
138 | m_msg = QVariant::fromValue(reply); | ||
139 | } else { | ||
140 | m_msg = QVariant(); | ||
141 | } | ||
142 | } | ||
143 | |||
144 | KMime::Message::Ptr Composer::assembleMessage() | ||
145 | { | ||
146 | auto mail = m_msg.value<KMime::Message::Ptr>(); | ||
147 | if (!mail) { | ||
148 | mail = KMime::Message::Ptr::create(); | ||
149 | } | ||
150 | for (const auto &to : KEmailAddress::splitAddressList(m_to)) { | ||
151 | QByteArray displayName; | ||
152 | QByteArray addrSpec; | ||
153 | QByteArray comment; | ||
154 | KEmailAddress::splitAddress(to.toUtf8(), displayName, addrSpec, comment); | ||
155 | mail->to(true)->addAddress(addrSpec, displayName); | ||
156 | } | ||
157 | mail->subject(true)->fromUnicodeString(m_subject, "utf-8"); | ||
158 | mail->setBody(m_body.toUtf8()); | ||
159 | mail->assemble(); | ||
160 | return mail; | ||
161 | } | ||
162 | |||
163 | void Composer::send() | ||
164 | { | ||
165 | auto mail = assembleMessage(); | ||
166 | Kube::ApplicationContext settings; | ||
167 | auto account = settings.currentAccount(); | ||
168 | auto identity = account.primaryIdentity(); | ||
169 | auto transport = identity.transport(); | ||
170 | |||
171 | Kube::Context context; | ||
172 | context.setProperty("message", QVariant::fromValue(mail)); | ||
173 | |||
174 | context.setProperty("username", transport.username()); | ||
175 | context.setProperty("password", transport.password()); | ||
176 | context.setProperty("server", transport.server()); | ||
177 | |||
178 | Kube::Action("org.kde.kube.actions.sendmail", context).execute(); | ||
179 | clear(); | ||
180 | } | ||
181 | |||
182 | void Composer::saveAsDraft() | ||
183 | { | ||
184 | auto mail = assembleMessage(); | ||
185 | Kube::Context context; | ||
186 | context.setProperty("message", QVariant::fromValue(mail)); | ||
187 | Kube::Action("org.kde.kube.actions.saveasdraft", context).execute(); | ||
188 | clear(); | ||
189 | } | ||
190 | |||
191 | void Composer::clear() | ||
192 | { | ||
193 | setSubject(""); | ||
194 | setBody(""); | ||
195 | setTo(""); | ||
196 | setCc(""); | ||
197 | setBcc(""); | ||
198 | setFromIndex(-1); | ||
199 | } | ||
diff --git a/framework/domain/composer.h b/framework/domain/composer.h new file mode 100644 index 00000000..dd066b2e --- /dev/null +++ b/framework/domain/composer.h | |||
@@ -0,0 +1,93 @@ | |||
1 | /* | ||
2 | Copyright (c) 2016 Michael Bohlender <michael.bohlender@kdemail.net> | ||
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 <QObject> | ||
23 | #include <QString> | ||
24 | #include <QStringList> | ||
25 | #include <QVariant> | ||
26 | |||
27 | namespace KMime { | ||
28 | class Message; | ||
29 | } | ||
30 | |||
31 | class Composer : public QObject | ||
32 | { | ||
33 | Q_OBJECT | ||
34 | Q_PROPERTY (QVariant originalMessage READ originalMessage WRITE setOriginalMessage) | ||
35 | Q_PROPERTY (QString to READ to WRITE setTo NOTIFY toChanged) | ||
36 | Q_PROPERTY (QString cc READ cc WRITE setCc NOTIFY ccChanged) | ||
37 | Q_PROPERTY (QString bcc READ bcc WRITE setBcc NOTIFY bccChanged) | ||
38 | Q_PROPERTY (QString subject READ subject WRITE setSubject NOTIFY subjectChanged) | ||
39 | Q_PROPERTY (QString body READ body WRITE setBody NOTIFY bodyChanged) | ||
40 | Q_PROPERTY (QStringList identityModel READ identityModel) | ||
41 | Q_PROPERTY (int fromIndex READ fromIndex WRITE setFromIndex NOTIFY fromIndexChanged) | ||
42 | |||
43 | public: | ||
44 | explicit Composer(QObject *parent = Q_NULLPTR); | ||
45 | |||
46 | QString to() const; | ||
47 | void setTo(const QString &to); | ||
48 | |||
49 | QString cc() const; | ||
50 | void setCc(const QString &cc); | ||
51 | |||
52 | QString bcc() const; | ||
53 | void setBcc(const QString &bcc); | ||
54 | |||
55 | QString subject() const; | ||
56 | void setSubject(const QString &subject); | ||
57 | |||
58 | QString body() const; | ||
59 | void setBody(const QString &body); | ||
60 | |||
61 | QStringList identityModel() const; | ||
62 | |||
63 | int fromIndex() const; | ||
64 | void setFromIndex(int fromIndex); | ||
65 | |||
66 | QVariant originalMessage() const; | ||
67 | void setOriginalMessage(const QVariant &originalMessage); | ||
68 | |||
69 | signals: | ||
70 | void subjectChanged(); | ||
71 | void bodyChanged(); | ||
72 | void toChanged(); | ||
73 | void ccChanged(); | ||
74 | void bccChanged(); | ||
75 | void fromIndexChanged(); | ||
76 | |||
77 | public slots: | ||
78 | void send(); | ||
79 | void saveAsDraft(); | ||
80 | void clear(); | ||
81 | |||
82 | private: | ||
83 | QSharedPointer<KMime::Message> assembleMessage(); | ||
84 | QString m_to; | ||
85 | QString m_cc; | ||
86 | QString m_bcc; | ||
87 | QString m_subject; | ||
88 | QString m_body; | ||
89 | QStringList m_identityModel; | ||
90 | int m_fromIndex; | ||
91 | QVariant m_originalMessage; | ||
92 | QVariant m_msg; | ||
93 | }; | ||
diff --git a/framework/domain/csshelper.cpp b/framework/domain/csshelper.cpp new file mode 100644 index 00000000..a6355c57 --- /dev/null +++ b/framework/domain/csshelper.cpp | |||
@@ -0,0 +1,64 @@ | |||
1 | /* | ||
2 | csshelper.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 "csshelper.h" | ||
33 | |||
34 | #include <QColor> | ||
35 | #include <QDebug> | ||
36 | #include <QFile> | ||
37 | #include <QFont> | ||
38 | #include <QFont> | ||
39 | #include <QPalette> | ||
40 | |||
41 | CSSHelper::CSSHelper(const QPaintDevice *pd) : | ||
42 | MessageViewer::CSSHelperBase(pd) | ||
43 | { | ||
44 | |||
45 | } | ||
46 | |||
47 | QString cssDefinitions() | ||
48 | { | ||
49 | QFile file(QLatin1String(MAIL_DATA_DIR) + QLatin1Char('/') + "mail.css"); | ||
50 | if (file.open(QFile::ReadOnly)) { | ||
51 | return file.readAll(); | ||
52 | } | ||
53 | return QString(); | ||
54 | } | ||
55 | |||
56 | QString CSSHelper::htmlHead(bool fixed) const | ||
57 | { | ||
58 | return | ||
59 | QLatin1String("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n" | ||
60 | "<html><head><title></title><style>\n") | ||
61 | + ::cssDefinitions() + | ||
62 | QLatin1String("</style></head>\n" | ||
63 | "<body>\n"); | ||
64 | } \ No newline at end of file | ||
diff --git a/framework/domain/csshelper.h b/framework/domain/csshelper.h new file mode 100644 index 00000000..775014e3 --- /dev/null +++ b/framework/domain/csshelper.h | |||
@@ -0,0 +1,44 @@ | |||
1 | /* -*- c++ -*- | ||
2 | csshelper.h | ||
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 | #pragma once | ||
33 | |||
34 | #include <MessageViewer/CSSHelperBase> | ||
35 | |||
36 | class CSSHelper : public MessageViewer::CSSHelperBase | ||
37 | { | ||
38 | public: | ||
39 | explicit CSSHelper(const QPaintDevice *pd); | ||
40 | |||
41 | /** @return HTML head including style sheet definitions and the | ||
42 | >body< tag */ | ||
43 | QString htmlHead(bool fixedFont = false) const Q_DECL_OVERRIDE; | ||
44 | }; \ No newline at end of file | ||
diff --git a/framework/domain/data/mail.css b/framework/domain/data/mail.css new file mode 100644 index 00000000..b77e36ee --- /dev/null +++ b/framework/domain/data/mail.css | |||
@@ -0,0 +1,298 @@ | |||
1 | div.header { | ||
2 | margin-bottom: 10pt ! important; | ||
3 | } | ||
4 | |||
5 | table.textAtm { | ||
6 | margin-top: 10pt ! important; | ||
7 | margin-bottom: 10pt ! important; | ||
8 | } | ||
9 | |||
10 | tr.textAtmH, | ||
11 | tr.textAtmB, | ||
12 | tr.rfc822B { | ||
13 | font-weight: normal ! important; | ||
14 | } | ||
15 | |||
16 | tr.signInProgressH, | ||
17 | tr.rfc822H, | ||
18 | tr.encrH, | ||
19 | tr.signOkKeyOkH, | ||
20 | tr.signOkKeyBadH, | ||
21 | tr.signWarnH, | ||
22 | tr.sign | ||
23 | ErrH { | ||
24 | font-weight: bold ! important; | ||
25 | } | ||
26 | |||
27 | tr.textAtmH td, | ||
28 | tr.textAtmB td { | ||
29 | padding: 3px ! important; | ||
30 | } | ||
31 | |||
32 | table.rfc822 { | ||
33 | width: 100% ! important; | ||
34 | border: solid 1px black ! important; | ||
35 | margin-top: 10pt ! important; | ||
36 | margin-bottom: 10pt ! important; | ||
37 | } | ||
38 | |||
39 | table.textAtm, | ||
40 | table.encr, | ||
41 | table.signWarn, | ||
42 | table.signErr, | ||
43 | table.signOkKeyBad, | ||
44 | table.signOkKeyOk, | ||
45 | table.signInProgress, | ||
46 | div.fancy.header table { | ||
47 | width: 100% ! important; | ||
48 | border-width: 0px ! important; | ||
49 | line-height: normal; | ||
50 | } | ||
51 | |||
52 | div.htmlWarn { | ||
53 | margin: 0px 5% ! important; | ||
54 | padding: 10px ! important; | ||
55 | text-align: left ! important; | ||
56 | line-height: normal; | ||
57 | } | ||
58 | |||
59 | div.fancy.header > div { | ||
60 | font-weight: bold ! important; | ||
61 | padding: 4px ! important; | ||
62 | line-height: normal; | ||
63 | } | ||
64 | |||
65 | div.fancy.header table { | ||
66 | padding: 2px ! important; | ||
67 | text-align: left ! important; | ||
68 | border-collapse: separate ! important; | ||
69 | } | ||
70 | |||
71 | div.fancy.header table th { | ||
72 | font-family: "Helvetica" ! important; | ||
73 | font-size: 12pt; | ||
74 | padding: 0px ! important; | ||
75 | white-space: nowrap ! important; | ||
76 | border-spacing: 0px ! important; | ||
77 | text-align: left ! important; | ||
78 | vertical-align: top ! important; | ||
79 | background-color: #efebe7 ! important; | ||
80 | color: #000000 ! important; | ||
81 | border: 1px ! important; | ||
82 | } | ||
83 | |||
84 | div.fancy.header table td { | ||
85 | font-family: "Helvetica" ! important; | ||
86 | font-size: 12pt; | ||
87 | padding: 0px ! important; | ||
88 | border-spacing: 0px ! important; | ||
89 | text-align: left ! important; | ||
90 | vertical-align: top ! important; | ||
91 | width: 100% ! important; | ||
92 | background-color: #efebe7 ! important; | ||
93 | color: #000000 ! important; | ||
94 | border: 1px ! important; | ||
95 | } | ||
96 | |||
97 | div.fancy.header table a:hover { | ||
98 | background-color: transparent ! important; | ||
99 | } | ||
100 | |||
101 | span.pimsmileytext { | ||
102 | position: absolute; | ||
103 | top: 0px; | ||
104 | left: 0px; | ||
105 | visibility: hidden; | ||
106 | } | ||
107 | |||
108 | img.pimsmileyimg { | ||
109 | } | ||
110 | |||
111 | div.quotelevelmark { | ||
112 | position: absolute; | ||
113 | margin-left:-10px; | ||
114 | } | ||
115 | |||
116 | body { | ||
117 | font-family: "Helvetica" ! important; | ||
118 | font-size: 12pt; | ||
119 | color: #000000 ! important; | ||
120 | background-color: #ffffff ! important; | ||
121 | } | ||
122 | |||
123 | a { | ||
124 | color: #0000cc ! important; | ||
125 | text-decoration: none ! important; | ||
126 | } | ||
127 | |||
128 | a.white { | ||
129 | color: white ! important; | ||
130 | } | ||
131 | |||
132 | a.black { | ||
133 | color: black ! important; | ||
134 | } | ||
135 | |||
136 | table.textAtm { background-color: #000000 ! important; } | ||
137 | |||
138 | tr.textAtmH { | ||
139 | background-color: #ffffff ! important; | ||
140 | font-family: "Helvetica" ! important; | ||
141 | font-size: 12pt; | ||
142 | } | ||
143 | |||
144 | tr.textAtmB { | ||
145 | background-color: #ffffff ! important; | ||
146 | } | ||
147 | |||
148 | table.signInProgress, | ||
149 | table.rfc822 { | ||
150 | background-color: #ffffff ! important | ||
151 | ; | ||
152 | } | ||
153 | |||
154 | tr.signInProgressH, | ||
155 | tr.rfc822H { | ||
156 | font-family: "Helvetica" ! important; | ||
157 | font-size: 12pt; | ||
158 | } | ||
159 | |||
160 | table.encr { | ||
161 | background-color: #0010cc ! important; | ||
162 | } | ||
163 | |||
164 | tr.encrH { | ||
165 | background-color: #1010ee ! important; | ||
166 | color: #aaaaaa ! important; | ||
167 | font-family: "Helvetica" ! important; | ||
168 | font-size: 12pt; | ||
169 | } | ||
170 | |||
171 | tr.encrB { background-color: #ffe0e0 ! important; } | ||
172 | |||
173 | table.signOkKeyOk { | ||
174 | background-color: #00cc00 ! important; | ||
175 | } | ||
176 | |||
177 | tr.signOkKeyOkH { | ||
178 | background-color: #00ff00 ! important; | ||
179 | color: #000000 ! important; | ||
180 | font-family: "Helvetica" ! important; | ||
181 | font-size: 12pt; | ||
182 | } | ||
183 | |||
184 | tr.signOkKeyOkB { background-color: #e0ffe0 ! important; } | ||
185 | |||
186 | table.signOkKeyBad { | ||
187 | background-color: #00cc00 ! important; | ||
188 | } | ||
189 | |||
190 | tr.signOkKeyBadH { | ||
191 | background-color: #00ff00 ! important; | ||
192 | color: #000000 ! important; | ||
193 | font-family: "Helvetica" ! important; | ||
194 | font-size: 12pt; | ||
195 | } | ||
196 | |||
197 | tr.signOkKeyBadB { background-color: #e0ffe0 ! important; } | ||
198 | |||
199 | table.signWarn { | ||
200 | background-color: #cc0 ! important; | ||
201 | } | ||
202 | |||
203 | tr.signWarnH { | ||
204 | background-color: #fc0 ! important; | ||
205 | color: #000000 ! important; | ||
206 | font-family: "Helvetica" ! imp | ||
207 | ortant; | ||
208 | font-size: 12pt; | ||
209 | } | ||
210 | |||
211 | tr.signWarnB { background-color: #e0e0ff ! important; } | ||
212 | |||
213 | table.signErr { | ||
214 | background-color: #c00 ! important; | ||
215 | } | ||
216 | |||
217 | tr.signErrH { | ||
218 | background-color: #0f00 ! important; | ||
219 | color: #0000 | ||
220 | 00 ! important; | ||
221 | font-family: "Helvetica" ! important; | ||
222 | font-size: 12pt; | ||
223 | } | ||
224 | |||
225 | tr.signErrB { background-color: #d3d3f0 ! important; } | ||
226 | |||
227 | div.htmlWarn { | ||
228 | border: 2px solid #00001a ! important; | ||
229 | line-height: normal; | ||
230 | } | ||
231 | |||
232 | div.header { | ||
233 | font-family: "Helvetica" ! important; | ||
234 | font-size: 12pt; | ||
235 | } | ||
236 | |||
237 | div.fancy.header > div { | ||
238 | background-color: #308cc6 ! important; | ||
239 | color: #ffffff ! important; | ||
240 | border: solid #000000 1px ! important; | ||
241 | line-height: normal; | ||
242 | } | ||
243 | |||
244 | div.fancy.header > div a[href] { color: #ffffff ! important; } | ||
245 | |||
246 | div.fancy.header > div a[href]:hover { text-decoration: underline ! important; } | ||
247 | |||
248 | div.fancy.header > div.spamheader { | ||
249 | background-color: #cdcdcd ! important; | ||
250 | border-top: 0px ! important; | ||
251 | padding: 3px ! important; | ||
252 | color: black ! important; | ||
253 | font-weight: bold ! important; | ||
254 | font-size: 12pt; | ||
255 | } | ||
256 | |||
257 | div.fancy.header > table.outer { | ||
258 | background-color: #efebe7 ! important; | ||
259 | color: #000000 ! important; | ||
260 | border-bottom: solid #000000 1px ! important; | ||
261 | border-left: solid #000000 1px ! important; | ||
262 | border-right: solid #000000 1px ! important; | ||
263 | } | ||
264 | |||
265 | div.senderpic{ | ||
266 | padding: 0px ! important; | ||
267 | font-size:0.8em ! important; | ||
268 | border:1px solid #b8b5b2 ! important; | ||
269 | background-color:#efebe7 ! important; | ||
270 | } | ||
271 | |||
272 | div.senderstatus{ | ||
273 | text-align:center ! important; | ||
274 | } | ||
275 | |||
276 | div.quotelevel1 { | ||
277 | color: #100000 ! important; | ||
278 | } | ||
279 | |||
280 | div.quotelevel2 { | ||
281 | color: #200000 ! important; | ||
282 | } | ||
283 | |||
284 | div.quotelevel3 { | ||
285 | color: #300000 ! important; | ||
286 | } | ||
287 | |||
288 | div.deepquotelevel1 { | ||
289 | color: #100000 ! important; | ||
290 | } | ||
291 | |||
292 | div.deepquotelevel2 { | ||
293 | color: #200000 ! important; | ||
294 | } | ||
295 | |||
296 | div.deepquotelevel3 { | ||
297 | color: #300000 ! important; | ||
298 | } | ||
diff --git a/framework/domain/folderlistcontroller.cpp b/framework/domain/folderlistcontroller.cpp new file mode 100644 index 00000000..46a6f648 --- /dev/null +++ b/framework/domain/folderlistcontroller.cpp | |||
@@ -0,0 +1,69 @@ | |||
1 | /* | ||
2 | Copyright (c) 2016 Michael Bohlender <michael.bohlender@kdemail.net> | ||
3 | Copyright (c) 2016 Christian Mollekopf <mollekopf@kolabsys.com> | ||
4 | |||
5 | This library is free software; you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Library General Public License as published by | ||
7 | the Free Software Foundation; either version 2 of the License, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, but WITHOUT | ||
11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public | ||
13 | License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Library General Public License | ||
16 | along with this library; see the file COPYING.LIB. If not, write to the | ||
17 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | #include "folderlistcontroller.h" | ||
22 | |||
23 | #include "folderlistmodel.h" | ||
24 | |||
25 | #include <QDebug> | ||
26 | |||
27 | FolderListController::FolderListController(QObject *parent) : QObject(parent), m_model(new FolderListModel) | ||
28 | { | ||
29 | |||
30 | } | ||
31 | |||
32 | QString FolderListController::accountId() const | ||
33 | { | ||
34 | return m_accountId; | ||
35 | } | ||
36 | |||
37 | void FolderListController::setAccountId(const QString &id) | ||
38 | { | ||
39 | if(m_accountId != id) { | ||
40 | m_accountId = id; | ||
41 | |||
42 | loadFolders(id); | ||
43 | |||
44 | emit accountIdChanged(); | ||
45 | } | ||
46 | } | ||
47 | |||
48 | FolderListModel* FolderListController::model() const | ||
49 | { | ||
50 | return m_model.data(); | ||
51 | } | ||
52 | |||
53 | void FolderListController::loadFolders(const QString &id) | ||
54 | { | ||
55 | //load foldermodel from sink | ||
56 | |||
57 | } | ||
58 | |||
59 | |||
60 | void FolderListController::addFolder(const QString &name) | ||
61 | { | ||
62 | qDebug() << "User Action: add folder " << name; | ||
63 | } | ||
64 | |||
65 | void FolderListController::deleteFolder(const QString &id) | ||
66 | { | ||
67 | qDebug() << "User Action: delete folder " << id; | ||
68 | } | ||
69 | |||
diff --git a/framework/domain/folderlistcontroller.h b/framework/domain/folderlistcontroller.h new file mode 100644 index 00000000..11057f21 --- /dev/null +++ b/framework/domain/folderlistcontroller.h | |||
@@ -0,0 +1,56 @@ | |||
1 | /* | ||
2 | Copyright (c) 2016 Michael Bohlender <michael.bohlender@kdemail.net> | ||
3 | Copyright (c) 2016 Christian Mollekopf <mollekopf@kolabsys.com> | ||
4 | |||
5 | This library is free software; you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Library General Public License as published by | ||
7 | the Free Software Foundation; either version 2 of the License, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, but WITHOUT | ||
11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public | ||
13 | License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Library General Public License | ||
16 | along with this library; see the file COPYING.LIB. If not, write to the | ||
17 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | #pragma once | ||
22 | |||
23 | #include "folderlistmodel.h" | ||
24 | |||
25 | #include <QObject> | ||
26 | #include <QScopedPointer> | ||
27 | #include <QString> | ||
28 | |||
29 | class FolderListController : public QObject | ||
30 | { | ||
31 | Q_OBJECT | ||
32 | Q_PROPERTY (QString accountId READ accountId WRITE setAccountId NOTIFY accountIdChanged) | ||
33 | Q_PROPERTY (FolderListModel *model READ model CONSTANT) | ||
34 | |||
35 | public: | ||
36 | explicit FolderListController(QObject *parent = Q_NULLPTR); | ||
37 | |||
38 | QString accountId() const; | ||
39 | void setAccountId(const QString &id); | ||
40 | |||
41 | FolderListModel *model() const; | ||
42 | |||
43 | void loadFolders(const QString &id); | ||
44 | |||
45 | signals: | ||
46 | void accountIdChanged(); | ||
47 | |||
48 | public slots: | ||
49 | void deleteFolder(const QString &id); | ||
50 | void addFolder(const QString &name); | ||
51 | |||
52 | |||
53 | private: | ||
54 | QString m_accountId; | ||
55 | QScopedPointer<FolderListModel> m_model; | ||
56 | }; | ||
diff --git a/framework/domain/folderlistmodel.cpp b/framework/domain/folderlistmodel.cpp new file mode 100644 index 00000000..ce6fb4fd --- /dev/null +++ b/framework/domain/folderlistmodel.cpp | |||
@@ -0,0 +1,65 @@ | |||
1 | /* | ||
2 | Copyright (c) 2016 Michael Bohlender <michael.bohlender@kdemail.net> | ||
3 | Copyright (c) 2016 Christian Mollekopf <mollekopf@kolabsys.com> | ||
4 | |||
5 | This library is free software; you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Library General Public License as published by | ||
7 | the Free Software Foundation; either version 2 of the License, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, but WITHOUT | ||
11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public | ||
13 | License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Library General Public License | ||
16 | along with this library; see the file COPYING.LIB. If not, write to the | ||
17 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | #include "folderlistmodel.h" | ||
22 | #include <sink/store.h> | ||
23 | |||
24 | FolderListModel::FolderListModel(QObject *parent) : QIdentityProxyModel() | ||
25 | { | ||
26 | Sink::Query query; | ||
27 | query.liveQuery = true; | ||
28 | query.requestedProperties << "name" << "icon" << "parent"; | ||
29 | query.parentProperty = "parent"; | ||
30 | mModel = Sink::Store::loadModel<Sink::ApplicationDomain::Folder>(query); | ||
31 | setSourceModel(mModel.data()); | ||
32 | } | ||
33 | |||
34 | FolderListModel::~FolderListModel() | ||
35 | { | ||
36 | |||
37 | } | ||
38 | |||
39 | QHash< int, QByteArray > FolderListModel::roleNames() const | ||
40 | { | ||
41 | QHash<int, QByteArray> roles; | ||
42 | |||
43 | roles[Name] = "name"; | ||
44 | roles[Icon] = "icon"; | ||
45 | roles[Id] = "id"; | ||
46 | roles[DomainObject] = "domainObject"; | ||
47 | |||
48 | return roles; | ||
49 | } | ||
50 | |||
51 | QVariant FolderListModel::data(const QModelIndex &idx, int role) const | ||
52 | { | ||
53 | auto srcIdx = mapToSource(idx); | ||
54 | switch (role) { | ||
55 | case Name: | ||
56 | return srcIdx.sibling(srcIdx.row(), 0).data(Qt::DisplayRole).toString(); | ||
57 | case Icon: | ||
58 | return srcIdx.sibling(srcIdx.row(), 1).data(Qt::DisplayRole).toString(); | ||
59 | case Id: | ||
60 | return srcIdx.data(Sink::Store::DomainObjectBaseRole).value<Sink::ApplicationDomain::ApplicationDomainType::Ptr>()->identifier(); | ||
61 | case DomainObject: | ||
62 | return srcIdx.data(Sink::Store::DomainObjectRole); | ||
63 | } | ||
64 | return QIdentityProxyModel::data(idx, role); | ||
65 | } | ||
diff --git a/framework/domain/folderlistmodel.h b/framework/domain/folderlistmodel.h new file mode 100644 index 00000000..7844e59a --- /dev/null +++ b/framework/domain/folderlistmodel.h | |||
@@ -0,0 +1,50 @@ | |||
1 | /* | ||
2 | Copyright (c) 2016 Michael Bohlender <michael.bohlender@kdemail.net> | ||
3 | Copyright (c) 2016 Christian Mollekopf <mollekopf@kolabsys.com> | ||
4 | |||
5 | This library is free software; you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Library General Public License as published by | ||
7 | the Free Software Foundation; either version 2 of the License, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, but WITHOUT | ||
11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public | ||
13 | License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Library General Public License | ||
16 | along with this library; see the file COPYING.LIB. If not, write to the | ||
17 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | #pragma once | ||
22 | |||
23 | #include <QObject> | ||
24 | #include <QIdentityProxyModel> | ||
25 | #include <QSharedPointer> | ||
26 | #include <QStringList> | ||
27 | |||
28 | class FolderListModel : public QIdentityProxyModel | ||
29 | { | ||
30 | Q_OBJECT | ||
31 | |||
32 | public: | ||
33 | FolderListModel(QObject *parent = Q_NULLPTR); | ||
34 | ~FolderListModel(); | ||
35 | |||
36 | QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; | ||
37 | |||
38 | enum Roles { | ||
39 | Name = Qt::UserRole + 1, | ||
40 | Icon, | ||
41 | Id, | ||
42 | DomainObject | ||
43 | }; | ||
44 | Q_ENUMS(Roles) | ||
45 | |||
46 | QHash<int, QByteArray> roleNames() const; | ||
47 | |||
48 | private: | ||
49 | QSharedPointer<QAbstractItemModel> mModel; | ||
50 | }; | ||
diff --git a/framework/domain/maillistcontroller.cpp b/framework/domain/maillistcontroller.cpp new file mode 100644 index 00000000..a4bd6436 --- /dev/null +++ b/framework/domain/maillistcontroller.cpp | |||
@@ -0,0 +1,101 @@ | |||
1 | /* | ||
2 | Copyright (c) 2016 Michael Bohlender <michael.bohlender@kdemail.net> | ||
3 | Copyright (c) 2016 Christian Mollekopf <mollekopf@kolabsys.com> | ||
4 | |||
5 | This library is free software; you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Library General Public License as published by | ||
7 | the Free Software Foundation; either version 2 of the License, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, but WITHOUT | ||
11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public | ||
13 | License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Library General Public License | ||
16 | along with this library; see the file COPYING.LIB. If not, write to the | ||
17 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | #include "maillistcontroller.h" | ||
22 | |||
23 | #include <QStringList> | ||
24 | |||
25 | #include <sink/store.h> | ||
26 | |||
27 | #include "maillistmodel.h" | ||
28 | |||
29 | MailListController::MailListController(QObject *parent) : QObject(parent), m_model(new MailListModel) | ||
30 | { | ||
31 | } | ||
32 | |||
33 | MailListModel *MailListController::model() const | ||
34 | { | ||
35 | return m_model.data(); | ||
36 | |||
37 | } | ||
38 | |||
39 | void MailListController::loadAllMail() | ||
40 | { | ||
41 | Sink::Query query; | ||
42 | query.liveQuery = true; | ||
43 | query.requestedProperties << "subject" << "sender" << "senderName" << "date" << "unread" << "important"; | ||
44 | m_model->runQuery(query); | ||
45 | } | ||
46 | |||
47 | void MailListController::loadMailFolder(const QString &folderId) | ||
48 | { | ||
49 | Sink::Query query; | ||
50 | query.liveQuery = true; | ||
51 | query.requestedProperties << "subject" << "sender" << "senderName" << "date" << "unread" << "important" << "folder"; | ||
52 | query.propertyFilter.insert("folder", folderId.toLatin1()); | ||
53 | m_model->runQuery(query); | ||
54 | } | ||
55 | |||
56 | void MailListController::loadUnreadMail() | ||
57 | { | ||
58 | Sink::Query query; | ||
59 | query.liveQuery = true; | ||
60 | query.requestedProperties << "subject" << "sender" << "senderName" << "date" << "unread" << "important"; | ||
61 | query.propertyFilter.insert("unread", true); | ||
62 | m_model->runQuery(query); | ||
63 | } | ||
64 | |||
65 | void MailListController::loadImportantMail() | ||
66 | { | ||
67 | Sink::Query query; | ||
68 | query.liveQuery = true; | ||
69 | query.requestedProperties << "subject" << "sender" << "senderName" << "date" << "unread" << "important"; | ||
70 | query.propertyFilter.insert("important", true); | ||
71 | m_model->runQuery(query); | ||
72 | } | ||
73 | |||
74 | QString MailListController::selectedMail() const | ||
75 | { | ||
76 | return m_selectedMail; | ||
77 | } | ||
78 | |||
79 | void MailListController::setSelectedMail(const QString& id) | ||
80 | { | ||
81 | if (m_selectedMail != id) { | ||
82 | m_selectedMail = id; | ||
83 | emit selectedMailChanged(); | ||
84 | } | ||
85 | } | ||
86 | |||
87 | void MailListController::markMailImportant(bool important) | ||
88 | { | ||
89 | qDebug() << "user action: mark mail important "; | ||
90 | } | ||
91 | |||
92 | void MailListController::markMailUnread(bool unread) | ||
93 | { | ||
94 | qDebug() << "user action: mark mail unread "; | ||
95 | } | ||
96 | |||
97 | void MailListController::deleteMail() | ||
98 | { | ||
99 | qDebug() << "user action: delete mail"; | ||
100 | } | ||
101 | |||
diff --git a/framework/domain/maillistcontroller.h b/framework/domain/maillistcontroller.h new file mode 100644 index 00000000..959c63a3 --- /dev/null +++ b/framework/domain/maillistcontroller.h | |||
@@ -0,0 +1,61 @@ | |||
1 | /* | ||
2 | Copyright (c) 2016 Michael Bohlender <michael.bohlender@kdemail.net> | ||
3 | Copyright (c) 2016 Christian Mollekopf <mollekopf@kolabsys.com> | ||
4 | |||
5 | This library is free software; you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Library General Public License as published by | ||
7 | the Free Software Foundation; either version 2 of the License, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, but WITHOUT | ||
11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public | ||
13 | License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Library General Public License | ||
16 | along with this library; see the file COPYING.LIB. If not, write to the | ||
17 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | #pragma once | ||
22 | |||
23 | #include "maillistmodel.h" | ||
24 | |||
25 | #include <QObject> | ||
26 | #include <QScopedPointer> | ||
27 | #include <QString> | ||
28 | #include <QAbstractItemModel> | ||
29 | |||
30 | class MailListController : public QObject | ||
31 | { | ||
32 | Q_OBJECT | ||
33 | Q_PROPERTY (MailListModel *model READ model CONSTANT) | ||
34 | Q_PROPERTY (QString selectedMail READ selectedMail WRITE setSelectedMail NOTIFY selectedMailChanged) | ||
35 | |||
36 | public: | ||
37 | explicit MailListController(QObject *parent = Q_NULLPTR); | ||
38 | |||
39 | MailListModel *model() const; | ||
40 | |||
41 | QString selectedMail() const; | ||
42 | void setSelectedMail(const QString &id); | ||
43 | |||
44 | signals: | ||
45 | void selectedMailChanged(); | ||
46 | |||
47 | public slots: | ||
48 | void loadAllMail(); | ||
49 | void loadUnreadMail(); | ||
50 | void loadImportantMail(); | ||
51 | void loadMailFolder(const QString &folderId); | ||
52 | |||
53 | void markMailImportant(bool important); | ||
54 | void markMailUnread(bool unread); | ||
55 | void deleteMail(); | ||
56 | |||
57 | private: | ||
58 | QScopedPointer<MailListModel> m_model; | ||
59 | |||
60 | QString m_selectedMail; | ||
61 | }; | ||
diff --git a/framework/domain/maillistmodel.cpp b/framework/domain/maillistmodel.cpp new file mode 100644 index 00000000..b46fabf8 --- /dev/null +++ b/framework/domain/maillistmodel.cpp | |||
@@ -0,0 +1,149 @@ | |||
1 | /* | ||
2 | Copyright (c) 2016 Michael Bohlender <michael.bohlender@kdemail.net> | ||
3 | Copyright (c) 2016 Christian Mollekopf <mollekopf@kolabsys.com> | ||
4 | |||
5 | This library is free software; you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Library General Public License as published by | ||
7 | the Free Software Foundation; either version 2 of the License, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, but WITHOUT | ||
11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public | ||
13 | License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Library General Public License | ||
16 | along with this library; see the file COPYING.LIB. If not, write to the | ||
17 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | #include "maillistmodel.h" | ||
22 | |||
23 | #include <QFile> | ||
24 | #include <QDateTime> | ||
25 | |||
26 | |||
27 | MailListModel::MailListModel(QObject *parent) | ||
28 | : QSortFilterProxyModel() | ||
29 | { | ||
30 | setDynamicSortFilter(true); | ||
31 | sort(0, Qt::DescendingOrder); | ||
32 | } | ||
33 | |||
34 | MailListModel::~MailListModel() | ||
35 | { | ||
36 | |||
37 | } | ||
38 | |||
39 | QHash< int, QByteArray > MailListModel::roleNames() const | ||
40 | { | ||
41 | QHash<int, QByteArray> roles; | ||
42 | |||
43 | roles[Subject] = "subject"; | ||
44 | roles[Sender] = "sender"; | ||
45 | roles[SenderName] = "senderName"; | ||
46 | roles[Date] = "date"; | ||
47 | roles[Unread] = "unread"; | ||
48 | roles[Important] = "important"; | ||
49 | roles[Id] = "id"; | ||
50 | roles[MimeMessage] = "mimeMessage"; | ||
51 | roles[DomainObject] = "domainObject"; | ||
52 | |||
53 | return roles; | ||
54 | } | ||
55 | |||
56 | QVariant MailListModel::data(const QModelIndex &idx, int role) const | ||
57 | { | ||
58 | auto srcIdx = mapToSource(idx); | ||
59 | switch (role) { | ||
60 | case Subject: | ||
61 | return srcIdx.sibling(srcIdx.row(), 0).data(Qt::DisplayRole).toString(); | ||
62 | case Sender: | ||
63 | return srcIdx.sibling(srcIdx.row(), 1).data(Qt::DisplayRole).toString(); | ||
64 | case SenderName: | ||
65 | return srcIdx.sibling(srcIdx.row(), 2).data(Qt::DisplayRole).toString(); | ||
66 | case Date: | ||
67 | return srcIdx.sibling(srcIdx.row(), 3).data(Qt::DisplayRole).toString(); | ||
68 | case Unread: | ||
69 | return srcIdx.sibling(srcIdx.row(), 4).data(Qt::DisplayRole).toBool(); | ||
70 | case Important: | ||
71 | return srcIdx.sibling(srcIdx.row(), 5).data(Qt::DisplayRole).toBool(); | ||
72 | case Id: | ||
73 | return srcIdx.data(Sink::Store::DomainObjectBaseRole).value<Sink::ApplicationDomain::ApplicationDomainType::Ptr>()->identifier(); | ||
74 | case DomainObject: | ||
75 | return srcIdx.data(Sink::Store::DomainObjectRole); | ||
76 | case MimeMessage: { | ||
77 | auto filename = srcIdx.sibling(srcIdx.row(), 6).data(Qt::DisplayRole).toString(); | ||
78 | QFile file(filename); | ||
79 | if (file.open(QFile::ReadOnly)) { | ||
80 | auto content = file.readAll(); | ||
81 | qWarning() << filename << content; | ||
82 | return content; | ||
83 | } else { | ||
84 | qWarning() << "Failed to open the file"; | ||
85 | } | ||
86 | return "Failed to read mail."; | ||
87 | } | ||
88 | } | ||
89 | return QSortFilterProxyModel::data(idx, role); | ||
90 | } | ||
91 | |||
92 | bool MailListModel::lessThan(const QModelIndex &left, const QModelIndex &right) const | ||
93 | { | ||
94 | const QVariant leftData = left.sibling(left.row(), 3).data(Qt::DisplayRole); | ||
95 | const QVariant rightData = right.sibling(right.row(), 3).data(Qt::DisplayRole); | ||
96 | return leftData.toDateTime() < rightData.toDateTime(); | ||
97 | } | ||
98 | |||
99 | void MailListModel::runQuery(const Sink::Query &query) | ||
100 | { | ||
101 | m_model = Sink::Store::loadModel<Sink::ApplicationDomain::Mail>(query); | ||
102 | setSourceModel(m_model.data()); | ||
103 | } | ||
104 | |||
105 | void MailListModel::setParentFolder(const QVariant &parentFolder) | ||
106 | { | ||
107 | auto folder = parentFolder.value<Sink::ApplicationDomain::Folder::Ptr>(); | ||
108 | if (!folder) { | ||
109 | qWarning() << "No folder: " << parentFolder; | ||
110 | return; | ||
111 | } | ||
112 | Sink::Query query; | ||
113 | query.liveQuery = true; | ||
114 | query.requestedProperties << "subject" << "sender" << "senderName" << "date" << "unread" << "important" << "folder"; | ||
115 | query.propertyFilter.insert("folder", folder->identifier()); | ||
116 | query.resources << folder->resourceInstanceIdentifier(); | ||
117 | query.sortProperty = "date"; | ||
118 | query.limit = 100; | ||
119 | qWarning() << "Running folder query: " << folder->resourceInstanceIdentifier() << folder->identifier(); | ||
120 | runQuery(query); | ||
121 | } | ||
122 | |||
123 | QVariant MailListModel::parentFolder() const | ||
124 | { | ||
125 | return QVariant(); | ||
126 | } | ||
127 | |||
128 | void MailListModel::setMail(const QVariant &variant) | ||
129 | { | ||
130 | auto mail = variant.value<Sink::ApplicationDomain::Mail::Ptr>(); | ||
131 | if (!mail) { | ||
132 | qWarning() << "No mail: " << mail; | ||
133 | return; | ||
134 | } | ||
135 | Sink::Query query; | ||
136 | query.liveQuery = false; | ||
137 | query.requestedProperties << "subject" << "sender" << "senderName" << "date" << "unread" << "important" << "mimeMessage"; | ||
138 | query.ids << mail->identifier(); | ||
139 | query.resources << mail->resourceInstanceIdentifier(); | ||
140 | qWarning() << "Running mail query: " << mail->resourceInstanceIdentifier() << mail->identifier(); | ||
141 | runQuery(query); | ||
142 | } | ||
143 | |||
144 | QVariant MailListModel::mail() const | ||
145 | { | ||
146 | return QVariant(); | ||
147 | } | ||
148 | |||
149 | |||
diff --git a/framework/domain/maillistmodel.h b/framework/domain/maillistmodel.h new file mode 100644 index 00000000..47a2a091 --- /dev/null +++ b/framework/domain/maillistmodel.h | |||
@@ -0,0 +1,66 @@ | |||
1 | /* | ||
2 | Copyright (c) 2016 Michael Bohlender <michael.bohlender@kdemail.net> | ||
3 | Copyright (c) 2016 Christian Mollekopf <mollekopf@kolabsys.com> | ||
4 | |||
5 | This library is free software; you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Library General Public License as published by | ||
7 | the Free Software Foundation; either version 2 of the License, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, but WITHOUT | ||
11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public | ||
13 | License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Library General Public License | ||
16 | along with this library; see the file COPYING.LIB. If not, write to the | ||
17 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | #pragma once | ||
22 | |||
23 | #include <sink/store.h> | ||
24 | |||
25 | #include <QSortFilterProxyModel> | ||
26 | #include <QSharedPointer> | ||
27 | #include <QStringList> | ||
28 | |||
29 | class MailListModel : public QSortFilterProxyModel | ||
30 | { | ||
31 | Q_OBJECT | ||
32 | Q_PROPERTY (QVariant parentFolder READ parentFolder WRITE setParentFolder) | ||
33 | Q_PROPERTY (QVariant mail READ mail WRITE setMail) | ||
34 | |||
35 | public: | ||
36 | MailListModel(QObject *parent = Q_NULLPTR); | ||
37 | ~MailListModel(); | ||
38 | |||
39 | QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; | ||
40 | |||
41 | bool lessThan(const QModelIndex &left, const QModelIndex &right) const Q_DECL_OVERRIDE; | ||
42 | |||
43 | enum Roles { | ||
44 | Subject = Qt::UserRole + 1, | ||
45 | Sender, | ||
46 | SenderName, | ||
47 | Date, | ||
48 | Unread, | ||
49 | Important, | ||
50 | Id, | ||
51 | MimeMessage, | ||
52 | DomainObject | ||
53 | }; | ||
54 | |||
55 | QHash<int, QByteArray> roleNames() const; | ||
56 | |||
57 | void runQuery(const Sink::Query &query); | ||
58 | |||
59 | void setParentFolder(const QVariant &parentFolder); | ||
60 | QVariant parentFolder() const; | ||
61 | |||
62 | void setMail(const QVariant &mail); | ||
63 | QVariant mail() const; | ||
64 | private: | ||
65 | QSharedPointer<QAbstractItemModel> m_model; | ||
66 | }; | ||
diff --git a/framework/domain/mailplugin.cpp b/framework/domain/mailplugin.cpp new file mode 100644 index 00000000..2d19a437 --- /dev/null +++ b/framework/domain/mailplugin.cpp | |||
@@ -0,0 +1,40 @@ | |||
1 | /* | ||
2 | Copyright (c) 2016 Michael Bohlender <michael.bohlender@kdemail.net> | ||
3 | Copyright (c) 2016 Christian Mollekopf <mollekopf@kolabsys.com> | ||
4 | |||
5 | This library is free software; you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Library General Public License as published by | ||
7 | the Free Software Foundation; either version 2 of the License, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, but WITHOUT | ||
11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public | ||
13 | License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Library General Public License | ||
16 | along with this library; see the file COPYING.LIB. If not, write to the | ||
17 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | #include "mailplugin.h" | ||
22 | |||
23 | #include "maillistmodel.h" | ||
24 | #include "folderlistmodel.h" | ||
25 | #include "composer.h" | ||
26 | #include "messageparser.h" | ||
27 | #include "retriever.h" | ||
28 | |||
29 | #include <QtQml> | ||
30 | |||
31 | void MailPlugin::registerTypes (const char *uri) | ||
32 | { | ||
33 | Q_ASSERT(uri == QLatin1String("org.kde.kube.mail")); | ||
34 | |||
35 | qmlRegisterType<FolderListModel>(uri, 1, 0, "FolderListModel"); | ||
36 | qmlRegisterType<MailListModel>(uri, 1, 0, "MailListModel"); | ||
37 | qmlRegisterType<Composer>(uri, 1, 0, "Composer"); | ||
38 | qmlRegisterType<MessageParser>(uri, 1, 0, "MessageParser"); | ||
39 | qmlRegisterType<Retriever>(uri, 1, 0, "Retriever"); | ||
40 | } | ||
diff --git a/framework/domain/mailplugin.h b/framework/domain/mailplugin.h new file mode 100644 index 00000000..ebd091ee --- /dev/null +++ b/framework/domain/mailplugin.h | |||
@@ -0,0 +1,33 @@ | |||
1 | /* | ||
2 | Copyright (c) 2016 Michael Bohlender <michael.bohlender@kdemail.net> | ||
3 | Copyright (c) 2016 Christian Mollekopf <mollekopf@kolabsys.com> | ||
4 | |||
5 | This library is free software; you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Library General Public License as published by | ||
7 | the Free Software Foundation; either version 2 of the License, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, but WITHOUT | ||
11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public | ||
13 | License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Library General Public License | ||
16 | along with this library; see the file COPYING.LIB. If not, write to the | ||
17 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | #pragma once | ||
22 | |||
23 | #include <QQmlEngine> | ||
24 | #include <QQmlExtensionPlugin> | ||
25 | |||
26 | class MailPlugin : public QQmlExtensionPlugin | ||
27 | { | ||
28 | Q_OBJECT | ||
29 | Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") | ||
30 | |||
31 | public: | ||
32 | virtual void registerTypes(const char *uri); | ||
33 | }; \ No newline at end of file | ||
diff --git a/framework/domain/mailtemplates.cpp b/framework/domain/mailtemplates.cpp new file mode 100644 index 00000000..e5ee8533 --- /dev/null +++ b/framework/domain/mailtemplates.cpp | |||
@@ -0,0 +1,804 @@ | |||
1 | /* | ||
2 | Copyright (C) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com | ||
3 | Copyright (c) 2010 Leo Franchi <lfranchi@kde.org> | ||
4 | Copyright (c) 2016 Christian Mollekopf <mollekopf@kolabsys.com> | ||
5 | |||
6 | This library is free software; you can redistribute it and/or modify it | ||
7 | under the terms of the GNU Library General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or (at your | ||
9 | option) any later version. | ||
10 | |||
11 | This library is distributed in the hope that it will be useful, but WITHOUT | ||
12 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
13 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public | ||
14 | License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU Library General Public License | ||
17 | along with this library; see the file COPYING.LIB. If not, write to the | ||
18 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
19 | 02110-1301, USA. | ||
20 | */ | ||
21 | #include "mailtemplates.h" | ||
22 | |||
23 | #include <QByteArray> | ||
24 | #include <QList> | ||
25 | #include <QDebug> | ||
26 | #include <QImage> | ||
27 | #include <QWebPage> | ||
28 | #include <QWebFrame> | ||
29 | #include <QSysInfo> | ||
30 | #include <QTextCodec> | ||
31 | #include <QApplication> | ||
32 | |||
33 | #include <KCodecs/KCharsets> | ||
34 | #include <KMime/Types> | ||
35 | |||
36 | #include "stringhtmlwriter.h" | ||
37 | #include "objecttreesource.h" | ||
38 | #include "csshelper.h" | ||
39 | |||
40 | #include <MessageViewer/ObjectTreeParser> | ||
41 | |||
42 | namespace KMime { | ||
43 | namespace Types { | ||
44 | static bool operator==(const KMime::Types::AddrSpec &left, const KMime::Types::AddrSpec &right) | ||
45 | { | ||
46 | return (left.asString() == right.asString()); | ||
47 | } | ||
48 | |||
49 | static bool operator==(const KMime::Types::Mailbox &left, const KMime::Types::Mailbox &right) | ||
50 | { | ||
51 | return (left.addrSpec().asString() == right.addrSpec().asString()); | ||
52 | } | ||
53 | } | ||
54 | } | ||
55 | |||
56 | static KMime::Types::Mailbox::List stripMyAddressesFromAddressList(const KMime::Types::Mailbox::List &list, const KMime::Types::AddrSpecList me) | ||
57 | { | ||
58 | KMime::Types::Mailbox::List addresses(list); | ||
59 | for (KMime::Types::Mailbox::List::Iterator it = addresses.begin(); it != addresses.end();) { | ||
60 | if (me.contains(it->addrSpec())) { | ||
61 | it = addresses.erase(it); | ||
62 | } else { | ||
63 | ++it; | ||
64 | } | ||
65 | } | ||
66 | |||
67 | return addresses; | ||
68 | } | ||
69 | |||
70 | void initHeader(const KMime::Message::Ptr &message) | ||
71 | { | ||
72 | message->removeHeader<KMime::Headers::To>(); | ||
73 | message->removeHeader<KMime::Headers::Subject>(); | ||
74 | message->date()->setDateTime(QDateTime::currentDateTime()); | ||
75 | |||
76 | const QStringList extraInfo = QStringList() << QSysInfo::prettyProductName(); | ||
77 | message->userAgent()->fromUnicodeString(QString("%1/%2(%3)").arg(QString::fromLocal8Bit("Kube")).arg("0.1").arg(extraInfo.join(",")), "utf-8"); | ||
78 | // This will allow to change Content-Type: | ||
79 | message->contentType()->setMimeType("text/plain"); | ||
80 | } | ||
81 | |||
82 | QString replacePrefixes(const QString &str, const QStringList &prefixRegExps, | ||
83 | bool replace, const QString &newPrefix) | ||
84 | { | ||
85 | bool recognized = false; | ||
86 | // construct a big regexp that | ||
87 | // 1. is anchored to the beginning of str (sans whitespace) | ||
88 | // 2. matches at least one of the part regexps in prefixRegExps | ||
89 | QString bigRegExp = QStringLiteral("^(?:\\s+|(?:%1))+\\s*").arg(prefixRegExps.join(QStringLiteral(")|(?:"))); | ||
90 | QRegExp rx(bigRegExp, Qt::CaseInsensitive); | ||
91 | if (rx.isValid()) { | ||
92 | QString tmp = str; | ||
93 | if (rx.indexIn(tmp) == 0) { | ||
94 | recognized = true; | ||
95 | if (replace) { | ||
96 | return tmp.replace(0, rx.matchedLength(), newPrefix + QLatin1String(" ")); | ||
97 | } | ||
98 | } | ||
99 | } else { | ||
100 | qWarning() << "bigRegExp = \"" | ||
101 | << bigRegExp << "\"\n" | ||
102 | << "prefix regexp is invalid!"; | ||
103 | // try good ole Re/Fwd: | ||
104 | recognized = str.startsWith(newPrefix); | ||
105 | } | ||
106 | |||
107 | if (!recognized) { | ||
108 | return newPrefix + QLatin1String(" ") + str; | ||
109 | } else { | ||
110 | return str; | ||
111 | } | ||
112 | } | ||
113 | |||
114 | QString cleanSubject(const KMime::Message::Ptr &msg, const QStringList &prefixRegExps, bool replace, const QString &newPrefix) | ||
115 | { | ||
116 | return replacePrefixes(msg->subject()->asUnicodeString(), prefixRegExps, replace, newPrefix); | ||
117 | } | ||
118 | |||
119 | QString forwardSubject(const KMime::Message::Ptr &msg) | ||
120 | { | ||
121 | bool replaceForwardPrefix = true; | ||
122 | QStringList forwardPrefixes; | ||
123 | forwardPrefixes << "Fwd:"; | ||
124 | forwardPrefixes << "FW:"; | ||
125 | return cleanSubject(msg, forwardPrefixes, replaceForwardPrefix, QStringLiteral("Fwd:")); | ||
126 | } | ||
127 | |||
128 | QString replySubject(const KMime::Message::Ptr &msg) | ||
129 | { | ||
130 | bool replaceReplyPrefix = true; | ||
131 | QStringList replyPrefixes; | ||
132 | //We're escaping the regex escape sequences. awesome | ||
133 | replyPrefixes << "Re\\\\s*:"; | ||
134 | replyPrefixes << "Re[\\\\d+\\\\]:"; | ||
135 | replyPrefixes << "Re\\\\d+:"; | ||
136 | return cleanSubject(msg, replyPrefixes, replaceReplyPrefix, QStringLiteral("Re:")); | ||
137 | } | ||
138 | |||
139 | QByteArray getRefStr(const KMime::Message::Ptr &msg) | ||
140 | { | ||
141 | QByteArray firstRef, lastRef, refStr, retRefStr; | ||
142 | int i, j; | ||
143 | |||
144 | if (auto hdr = msg->references(false)) { | ||
145 | refStr = hdr->as7BitString(false).trimmed(); | ||
146 | } | ||
147 | |||
148 | if (refStr.isEmpty()) { | ||
149 | return msg->messageID()->as7BitString(false); | ||
150 | } | ||
151 | |||
152 | i = refStr.indexOf('<'); | ||
153 | j = refStr.indexOf('>'); | ||
154 | firstRef = refStr.mid(i, j - i + 1); | ||
155 | if (!firstRef.isEmpty()) { | ||
156 | retRefStr = firstRef + ' '; | ||
157 | } | ||
158 | |||
159 | i = refStr.lastIndexOf('<'); | ||
160 | j = refStr.lastIndexOf('>'); | ||
161 | |||
162 | lastRef = refStr.mid(i, j - i + 1); | ||
163 | if (!lastRef.isEmpty() && lastRef != firstRef) { | ||
164 | retRefStr += lastRef + ' '; | ||
165 | } | ||
166 | |||
167 | retRefStr += msg->messageID()->as7BitString(false); | ||
168 | return retRefStr; | ||
169 | } | ||
170 | |||
171 | KMime::Content *createPlainPartContent(const KMime::Message::Ptr &msg, const QString &plainBody) | ||
172 | { | ||
173 | KMime::Content *textPart = new KMime::Content(msg.data()); | ||
174 | textPart->contentType()->setMimeType("text/plain"); | ||
175 | //FIXME This is supposed to select a charset out of the available charsets that contains all necessary characters to render the text | ||
176 | // QTextCodec *charset = selectCharset(m_charsets, plainBody); | ||
177 | // textPart->contentType()->setCharset(charset->name()); | ||
178 | textPart->contentType()->setCharset("utf-8"); | ||
179 | textPart->contentTransferEncoding()->setEncoding(KMime::Headers::CE8Bit); | ||
180 | textPart->fromUnicodeString(plainBody); | ||
181 | return textPart; | ||
182 | } | ||
183 | |||
184 | KMime::Content *createMultipartAlternativeContent(const KMime::Message::Ptr &msg, const QString &plainBody, const QString &htmlBody) | ||
185 | { | ||
186 | KMime::Content *multipartAlternative = new KMime::Content(msg.data()); | ||
187 | multipartAlternative->contentType()->setMimeType("multipart/alternative"); | ||
188 | const QByteArray boundary = KMime::multiPartBoundary(); | ||
189 | multipartAlternative->contentType()->setBoundary(boundary); | ||
190 | |||
191 | KMime::Content *textPart = createPlainPartContent(msg, plainBody); | ||
192 | multipartAlternative->addContent(textPart); | ||
193 | |||
194 | KMime::Content *htmlPart = new KMime::Content(msg.data()); | ||
195 | htmlPart->contentType()->setMimeType("text/html"); | ||
196 | //FIXME This is supposed to select a charset out of the available charsets that contains all necessary characters to render the text | ||
197 | // QTextCodec *charset = selectCharset(m_charsets, htmlBody); | ||
198 | // htmlPart->contentType()->setCharset(charset->name()); | ||
199 | textPart->contentType()->setCharset("utf-8"); | ||
200 | htmlPart->contentTransferEncoding()->setEncoding(KMime::Headers::CE8Bit); | ||
201 | htmlPart->fromUnicodeString(htmlBody); | ||
202 | multipartAlternative->addContent(htmlPart); | ||
203 | |||
204 | return multipartAlternative; | ||
205 | } | ||
206 | |||
207 | void addProcessedBodyToMessage(const KMime::Message::Ptr &msg, const QString &plainBody, const QString &htmlBody, bool forward) | ||
208 | { | ||
209 | //FIXME | ||
210 | // MessageCore::ImageCollector ic; | ||
211 | // ic.collectImagesFrom(mOrigMsg.data()); | ||
212 | |||
213 | // Now, delete the old content and set the new content, which | ||
214 | // is either only the new text or the new text with some attachments. | ||
215 | auto parts = msg->contents(); | ||
216 | foreach (KMime::Content *content, parts) { | ||
217 | msg->removeContent(content, true/*delete*/); | ||
218 | } | ||
219 | |||
220 | msg->contentType()->clear(); // to get rid of old boundary | ||
221 | |||
222 | const QByteArray boundary = KMime::multiPartBoundary(); | ||
223 | KMime::Content *const mainTextPart = | ||
224 | htmlBody.isEmpty() ? | ||
225 | createPlainPartContent(msg, plainBody) : | ||
226 | createMultipartAlternativeContent(msg, plainBody, htmlBody); | ||
227 | mainTextPart->assemble(); | ||
228 | |||
229 | KMime::Content *textPart = mainTextPart; | ||
230 | // if (!ic.images().empty()) { | ||
231 | // textPart = createMultipartRelated(ic, mainTextPart); | ||
232 | // textPart->assemble(); | ||
233 | // } | ||
234 | |||
235 | // If we have some attachments, create a multipart/mixed mail and | ||
236 | // add the normal body as well as the attachments | ||
237 | KMime::Content *mainPart = textPart; | ||
238 | //FIXME | ||
239 | // if (forward) { | ||
240 | // auto attachments = mOrigMsg->attachments(); | ||
241 | // attachments += mOtp->nodeHelper()->attachmentsOfExtraContents(); | ||
242 | // if (!attachments.isEmpty()) { | ||
243 | // mainPart = createMultipartMixed(attachments, textPart); | ||
244 | // mainPart->assemble(); | ||
245 | // } | ||
246 | // } | ||
247 | |||
248 | msg->setBody(mainPart->encodedBody()); | ||
249 | msg->setHeader(mainPart->contentType()); | ||
250 | msg->setHeader(mainPart->contentTransferEncoding()); | ||
251 | msg->assemble(); | ||
252 | msg->parse(); | ||
253 | } | ||
254 | |||
255 | QString plainToHtml(const QString &body) | ||
256 | { | ||
257 | QString str = body; | ||
258 | str = str.toHtmlEscaped(); | ||
259 | str.replace(QStringLiteral("\n"), QStringLiteral("<br />\n")); | ||
260 | return str; | ||
261 | } | ||
262 | |||
263 | //TODO implement this function using a DOM tree parser | ||
264 | void makeValidHtml(QString &body, const QString &headElement) | ||
265 | { | ||
266 | QRegExp regEx; | ||
267 | regEx.setMinimal(true); | ||
268 | regEx.setPattern(QStringLiteral("<html.*>")); | ||
269 | |||
270 | if (!body.isEmpty() && !body.contains(regEx)) { | ||
271 | regEx.setPattern(QStringLiteral("<body.*>")); | ||
272 | if (!body.contains(regEx)) { | ||
273 | body = QLatin1String("<body>") + body + QLatin1String("<br/></body>"); | ||
274 | } | ||
275 | regEx.setPattern(QStringLiteral("<head.*>")); | ||
276 | if (!body.contains(regEx)) { | ||
277 | body = QLatin1String("<head>") + headElement + QLatin1String("</head>") + body; | ||
278 | } | ||
279 | body = QLatin1String("<html>") + body + QLatin1String("</html>"); | ||
280 | } | ||
281 | } | ||
282 | |||
283 | QString stripSignature(const QString &msg) | ||
284 | { | ||
285 | // Following RFC 3676, only > before -- | ||
286 | // I prefer to not delete a SB instead of delete good mail content. | ||
287 | const QRegExp sbDelimiterSearch = QRegExp(QLatin1String("(^|\n)[> ]*-- \n")); | ||
288 | // The regular expression to look for prefix change | ||
289 | const QRegExp commonReplySearch = QRegExp(QLatin1String("^[ ]*>")); | ||
290 | |||
291 | QString res = msg; | ||
292 | int posDeletingStart = 1; // to start looking at 0 | ||
293 | |||
294 | // While there are SB delimiters (start looking just before the deleted SB) | ||
295 | while ((posDeletingStart = res.indexOf(sbDelimiterSearch, posDeletingStart - 1)) >= 0) { | ||
296 | QString prefix; // the current prefix | ||
297 | QString line; // the line to check if is part of the SB | ||
298 | int posNewLine = -1; | ||
299 | |||
300 | // Look for the SB beginning | ||
301 | int posSignatureBlock = res.indexOf(QLatin1Char('-'), posDeletingStart); | ||
302 | // The prefix before "-- "$ | ||
303 | if (res.at(posDeletingStart) == QLatin1Char('\n')) { | ||
304 | ++posDeletingStart; | ||
305 | } | ||
306 | |||
307 | prefix = res.mid(posDeletingStart, posSignatureBlock - posDeletingStart); | ||
308 | posNewLine = res.indexOf(QLatin1Char('\n'), posSignatureBlock) + 1; | ||
309 | |||
310 | // now go to the end of the SB | ||
311 | while (posNewLine < res.size() && posNewLine > 0) { | ||
312 | // handle the undefined case for mid ( x , -n ) where n>1 | ||
313 | int nextPosNewLine = res.indexOf(QLatin1Char('\n'), posNewLine); | ||
314 | |||
315 | if (nextPosNewLine < 0) { | ||
316 | nextPosNewLine = posNewLine - 1; | ||
317 | } | ||
318 | |||
319 | line = res.mid(posNewLine, nextPosNewLine - posNewLine); | ||
320 | |||
321 | // check when the SB ends: | ||
322 | // * does not starts with prefix or | ||
323 | // * starts with prefix+(any substring of prefix) | ||
324 | if ((prefix.isEmpty() && line.indexOf(commonReplySearch) < 0) || | ||
325 | (!prefix.isEmpty() && line.startsWith(prefix) && | ||
326 | line.mid(prefix.size()).indexOf(commonReplySearch) < 0)) { | ||
327 | posNewLine = res.indexOf(QLatin1Char('\n'), posNewLine) + 1; | ||
328 | } else { | ||
329 | break; // end of the SB | ||
330 | } | ||
331 | } | ||
332 | |||
333 | // remove the SB or truncate when is the last SB | ||
334 | if (posNewLine > 0) { | ||
335 | res.remove(posDeletingStart, posNewLine - posDeletingStart); | ||
336 | } else { | ||
337 | res.truncate(posDeletingStart); | ||
338 | } | ||
339 | } | ||
340 | |||
341 | return res; | ||
342 | } | ||
343 | |||
344 | QString plainMessageText(MessageViewer::ObjectTreeParser &otp, bool aStripSignature) | ||
345 | { | ||
346 | QString result = otp.plainTextContent(); | ||
347 | if (result.isEmpty()) { //HTML-only mails | ||
348 | QWebPage doc; | ||
349 | doc.mainFrame()->setHtml(otp.htmlContent()); | ||
350 | result = doc.mainFrame()->toPlainText(); | ||
351 | } | ||
352 | |||
353 | if (aStripSignature) { | ||
354 | result = stripSignature(result); | ||
355 | } | ||
356 | |||
357 | return result; | ||
358 | } | ||
359 | |||
360 | QString htmlMessageText(MessageViewer::ObjectTreeParser &otp, bool aStripSignature, QString &headElement) | ||
361 | { | ||
362 | QString htmlElement = otp.htmlContent(); | ||
363 | |||
364 | if (htmlElement.isEmpty()) { //plain mails only | ||
365 | QString htmlReplace = otp.plainTextContent().toHtmlEscaped(); | ||
366 | htmlReplace = htmlReplace.replace(QStringLiteral("\n"), QStringLiteral("<br />")); | ||
367 | htmlElement = QStringLiteral("<html><head></head><body>%1</body></html>\n").arg(htmlReplace); | ||
368 | } | ||
369 | |||
370 | //QWebPage relies on this | ||
371 | Q_ASSERT(QApplication::style()); | ||
372 | QWebPage page; | ||
373 | page.settings()->setAttribute(QWebSettings::JavascriptEnabled, false); | ||
374 | page.settings()->setAttribute(QWebSettings::JavaEnabled, false); | ||
375 | page.settings()->setAttribute(QWebSettings::PluginsEnabled, false); | ||
376 | page.settings()->setAttribute(QWebSettings::AutoLoadImages, false); | ||
377 | |||
378 | page.currentFrame()->setHtml(htmlElement); | ||
379 | |||
380 | //TODO to be tested/verified if this is not an issue | ||
381 | page.settings()->setAttribute(QWebSettings::JavascriptEnabled, true); | ||
382 | const QString bodyElement = page.currentFrame()->evaluateJavaScript( | ||
383 | QStringLiteral("document.getElementsByTagName('body')[0].innerHTML")).toString(); | ||
384 | |||
385 | headElement = page.currentFrame()->evaluateJavaScript( | ||
386 | QStringLiteral("document.getElementsByTagName('head')[0].innerHTML")).toString(); | ||
387 | |||
388 | page.settings()->setAttribute(QWebSettings::JavascriptEnabled, false); | ||
389 | |||
390 | if (!bodyElement.isEmpty()) { | ||
391 | if (aStripSignature) { | ||
392 | //FIXME strip signature works partially for HTML mails | ||
393 | return stripSignature(bodyElement); | ||
394 | } | ||
395 | return bodyElement; | ||
396 | } | ||
397 | |||
398 | if (aStripSignature) { | ||
399 | //FIXME strip signature works partially for HTML mails | ||
400 | return stripSignature(htmlElement); | ||
401 | } | ||
402 | return htmlElement; | ||
403 | } | ||
404 | |||
405 | QString formatQuotePrefix(const QString &wildString, const QString &fromDisplayString) | ||
406 | { | ||
407 | QString result; | ||
408 | |||
409 | if (wildString.isEmpty()) { | ||
410 | return wildString; | ||
411 | } | ||
412 | |||
413 | unsigned int strLength(wildString.length()); | ||
414 | for (uint i = 0; i < strLength;) { | ||
415 | QChar ch = wildString[i++]; | ||
416 | if (ch == QLatin1Char('%') && i < strLength) { | ||
417 | ch = wildString[i++]; | ||
418 | switch (ch.toLatin1()) { | ||
419 | case 'f': { // sender's initals | ||
420 | if (fromDisplayString.isEmpty()) { | ||
421 | break; | ||
422 | } | ||
423 | |||
424 | uint j = 0; | ||
425 | const unsigned int strLength(fromDisplayString.length()); | ||
426 | for (; j < strLength && fromDisplayString[j] > QLatin1Char(' '); ++j) | ||
427 | ; | ||
428 | for (; j < strLength && fromDisplayString[j] <= QLatin1Char(' '); ++j) | ||
429 | ; | ||
430 | result += fromDisplayString[0]; | ||
431 | if (j < strLength && fromDisplayString[j] > QLatin1Char(' ')) { | ||
432 | result += fromDisplayString[j]; | ||
433 | } else if (strLength > 1) { | ||
434 | if (fromDisplayString[1] > QLatin1Char(' ')) { | ||
435 | result += fromDisplayString[1]; | ||
436 | } | ||
437 | } | ||
438 | } | ||
439 | break; | ||
440 | case '_': | ||
441 | result += QLatin1Char(' '); | ||
442 | break; | ||
443 | case '%': | ||
444 | result += QLatin1Char('%'); | ||
445 | break; | ||
446 | default: | ||
447 | result += QLatin1Char('%'); | ||
448 | result += ch; | ||
449 | break; | ||
450 | } | ||
451 | } else { | ||
452 | result += ch; | ||
453 | } | ||
454 | } | ||
455 | return result; | ||
456 | } | ||
457 | |||
458 | QString quotedPlainText(const QString &selection, const QString &fromDisplayString) | ||
459 | { | ||
460 | QString content = selection; | ||
461 | // Remove blank lines at the beginning: | ||
462 | const int firstNonWS = content.indexOf(QRegExp(QLatin1String("\\S"))); | ||
463 | const int lineStart = content.lastIndexOf(QLatin1Char('\n'), firstNonWS); | ||
464 | if (lineStart >= 0) { | ||
465 | content.remove(0, static_cast<unsigned int>(lineStart)); | ||
466 | } | ||
467 | |||
468 | const auto quoteString = QStringLiteral("> "); | ||
469 | const QString indentStr = formatQuotePrefix(quoteString, fromDisplayString); | ||
470 | //FIXME | ||
471 | // if (TemplateParserSettings::self()->smartQuote() && mWrap) { | ||
472 | // content = MessageCore::StringUtil::smartQuote(content, mColWrap - indentStr.length()); | ||
473 | // } | ||
474 | content.replace(QLatin1Char('\n'), QLatin1Char('\n') + indentStr); | ||
475 | content.prepend(indentStr); | ||
476 | content += QLatin1Char('\n'); | ||
477 | |||
478 | return content; | ||
479 | } | ||
480 | |||
481 | QString quotedHtmlText(const QString &selection) | ||
482 | { | ||
483 | QString content = selection; | ||
484 | //TODO 1) look for all the variations of <br> and remove the blank lines | ||
485 | //2) implement vertical bar for quoted HTML mail. | ||
486 | //3) After vertical bar is implemented, If a user wants to edit quoted message, | ||
487 | // then the <blockquote> tags below should open and close as when required. | ||
488 | |||
489 | //Add blockquote tag, so that quoted message can be differentiated from normal message | ||
490 | content = QLatin1String("<blockquote>") + content + QLatin1String("</blockquote>"); | ||
491 | return content; | ||
492 | } | ||
493 | |||
494 | void applyCharset(const KMime::Message::Ptr msg, const KMime::Message::Ptr &origMsg) | ||
495 | { | ||
496 | // first convert the body from its current encoding to unicode representation | ||
497 | QTextCodec *bodyCodec = KCharsets::charsets()->codecForName(QString::fromLatin1(msg->contentType()->charset())); | ||
498 | if (!bodyCodec) { | ||
499 | bodyCodec = KCharsets::charsets()->codecForName(QStringLiteral("UTF-8")); | ||
500 | } | ||
501 | |||
502 | const QString body = bodyCodec->toUnicode(msg->body()); | ||
503 | |||
504 | // then apply the encoding of the original message | ||
505 | msg->contentType()->setCharset(origMsg->contentType()->charset()); | ||
506 | |||
507 | QTextCodec *codec = KCharsets::charsets()->codecForName(QString::fromLatin1(msg->contentType()->charset())); | ||
508 | if (!codec) { | ||
509 | qCritical() << "Could not get text codec for charset" << msg->contentType()->charset(); | ||
510 | } else if (!codec->canEncode(body)) { // charset can't encode body, fall back to preferred | ||
511 | const QStringList charsets /*= preferredCharsets() */; | ||
512 | |||
513 | QList<QByteArray> chars; | ||
514 | chars.reserve(charsets.count()); | ||
515 | foreach (const QString &charset, charsets) { | ||
516 | chars << charset.toLatin1(); | ||
517 | } | ||
518 | |||
519 | //FIXME | ||
520 | QByteArray fallbackCharset/* = selectCharset(chars, body)*/; | ||
521 | if (fallbackCharset.isEmpty()) { // UTF-8 as fall-through | ||
522 | fallbackCharset = "UTF-8"; | ||
523 | } | ||
524 | |||
525 | codec = KCharsets::charsets()->codecForName(QString::fromLatin1(fallbackCharset)); | ||
526 | msg->setBody(codec->fromUnicode(body)); | ||
527 | } else { | ||
528 | msg->setBody(codec->fromUnicode(body)); | ||
529 | } | ||
530 | } | ||
531 | |||
532 | enum ReplyStrategy { | ||
533 | ReplyList, | ||
534 | ReplySmart, | ||
535 | ReplyAll, | ||
536 | ReplyAuthor, | ||
537 | ReplyNone | ||
538 | }; | ||
539 | |||
540 | KMime::Message::Ptr MailTemplates::reply(const KMime::Message::Ptr &origMsg) | ||
541 | { | ||
542 | //FIXME | ||
543 | const bool alwaysPlain = true; | ||
544 | //FIXME | ||
545 | const ReplyStrategy replyStrategy = ReplySmart; | ||
546 | KMime::Message::Ptr msg(new KMime::Message); | ||
547 | //FIXME | ||
548 | //Personal email addresses | ||
549 | KMime::Types::AddrSpecList me; | ||
550 | KMime::Types::Mailbox::List toList; | ||
551 | KMime::Types::Mailbox::List replyToList; | ||
552 | KMime::Types::Mailbox::List mailingListAddresses; | ||
553 | |||
554 | // const uint originalIdentity = identityUoid(origMsg); | ||
555 | initHeader(msg); | ||
556 | replyToList = origMsg->replyTo()->mailboxes(); | ||
557 | |||
558 | msg->contentType()->setCharset("utf-8"); | ||
559 | |||
560 | if (origMsg->headerByType("List-Post") && | ||
561 | origMsg->headerByType("List-Post")->asUnicodeString().contains(QStringLiteral("mailto:"), Qt::CaseInsensitive)) { | ||
562 | |||
563 | const QString listPost = origMsg->headerByType("List-Post")->asUnicodeString(); | ||
564 | QRegExp rx(QStringLiteral("<mailto:([^@>]+)@([^>]+)>"), Qt::CaseInsensitive); | ||
565 | if (rx.indexIn(listPost, 0) != -1) { // matched | ||
566 | KMime::Types::Mailbox mailbox; | ||
567 | mailbox.fromUnicodeString(rx.cap(1) + QLatin1Char('@') + rx.cap(2)); | ||
568 | mailingListAddresses << mailbox; | ||
569 | } | ||
570 | } | ||
571 | |||
572 | switch (replyStrategy) { | ||
573 | case ReplySmart: { | ||
574 | if (auto hdr = origMsg->headerByType("Mail-Followup-To")) { | ||
575 | toList << KMime::Types::Mailbox::listFrom7BitString(hdr->as7BitString(false)); | ||
576 | } else if (!replyToList.isEmpty()) { | ||
577 | toList = replyToList; | ||
578 | } else if (!mailingListAddresses.isEmpty()) { | ||
579 | toList = (KMime::Types::Mailbox::List() << mailingListAddresses.at(0)); | ||
580 | } else { | ||
581 | // doesn't seem to be a mailing list, reply to From: address | ||
582 | toList = origMsg->from()->mailboxes(); | ||
583 | |||
584 | bool listContainsMe = false; | ||
585 | for (const auto &m : me) { | ||
586 | KMime::Types::Mailbox mailbox; | ||
587 | mailbox.setAddress(m); | ||
588 | if (toList.contains(mailbox)) { | ||
589 | listContainsMe = true; | ||
590 | } | ||
591 | } | ||
592 | if (listContainsMe) { | ||
593 | // sender seems to be one of our own identities, so we assume that this | ||
594 | // is a reply to a "sent" mail where the users wants to add additional | ||
595 | // information for the recipient. | ||
596 | toList = origMsg->to()->mailboxes(); | ||
597 | } | ||
598 | } | ||
599 | // strip all my addresses from the list of recipients | ||
600 | const KMime::Types::Mailbox::List recipients = toList; | ||
601 | |||
602 | toList = stripMyAddressesFromAddressList(recipients, me); | ||
603 | |||
604 | // ... unless the list contains only my addresses (reply to self) | ||
605 | if (toList.isEmpty() && !recipients.isEmpty()) { | ||
606 | toList << recipients.first(); | ||
607 | } | ||
608 | } | ||
609 | break; | ||
610 | case ReplyList: { | ||
611 | if (auto hdr = origMsg->headerByType("Mail-Followup-To")) { | ||
612 | KMime::Types::Mailbox mailbox; | ||
613 | mailbox.from7BitString(hdr->as7BitString(false)); | ||
614 | toList << mailbox; | ||
615 | } else if (!mailingListAddresses.isEmpty()) { | ||
616 | toList << mailingListAddresses[ 0 ]; | ||
617 | } else if (!replyToList.isEmpty()) { | ||
618 | // assume a Reply-To header mangling mailing list | ||
619 | toList = replyToList; | ||
620 | } | ||
621 | |||
622 | //FIXME | ||
623 | // strip all my addresses from the list of recipients | ||
624 | const KMime::Types::Mailbox::List recipients = toList; | ||
625 | toList = stripMyAddressesFromAddressList(recipients, me); | ||
626 | } | ||
627 | break; | ||
628 | case ReplyAll: { | ||
629 | KMime::Types::Mailbox::List recipients; | ||
630 | KMime::Types::Mailbox::List ccRecipients; | ||
631 | |||
632 | // add addresses from the Reply-To header to the list of recipients | ||
633 | if (!replyToList.isEmpty()) { | ||
634 | recipients = replyToList; | ||
635 | |||
636 | // strip all possible mailing list addresses from the list of Reply-To addresses | ||
637 | foreach (const KMime::Types::Mailbox &mailbox, mailingListAddresses) { | ||
638 | foreach (const KMime::Types::Mailbox &recipient, recipients) { | ||
639 | if (mailbox == recipient) { | ||
640 | recipients.removeAll(recipient); | ||
641 | } | ||
642 | } | ||
643 | } | ||
644 | } | ||
645 | |||
646 | if (!mailingListAddresses.isEmpty()) { | ||
647 | // this is a mailing list message | ||
648 | if (recipients.isEmpty() && !origMsg->from()->asUnicodeString().isEmpty()) { | ||
649 | // The sender didn't set a Reply-to address, so we add the From | ||
650 | // address to the list of CC recipients. | ||
651 | ccRecipients += origMsg->from()->mailboxes(); | ||
652 | qDebug() << "Added" << origMsg->from()->asUnicodeString() << "to the list of CC recipients"; | ||
653 | } | ||
654 | |||
655 | // if it is a mailing list, add the posting address | ||
656 | recipients.prepend(mailingListAddresses[ 0 ]); | ||
657 | } else { | ||
658 | // this is a normal message | ||
659 | if (recipients.isEmpty() && !origMsg->from()->asUnicodeString().isEmpty()) { | ||
660 | // in case of replying to a normal message only then add the From | ||
661 | // address to the list of recipients if there was no Reply-to address | ||
662 | recipients += origMsg->from()->mailboxes(); | ||
663 | qDebug() << "Added" << origMsg->from()->asUnicodeString() << "to the list of recipients"; | ||
664 | } | ||
665 | } | ||
666 | |||
667 | // strip all my addresses from the list of recipients | ||
668 | toList = stripMyAddressesFromAddressList(recipients, me); | ||
669 | |||
670 | // merge To header and CC header into a list of CC recipients | ||
671 | if (!origMsg->cc()->asUnicodeString().isEmpty() || !origMsg->to()->asUnicodeString().isEmpty()) { | ||
672 | KMime::Types::Mailbox::List list; | ||
673 | if (!origMsg->to()->asUnicodeString().isEmpty()) { | ||
674 | list += origMsg->to()->mailboxes(); | ||
675 | } | ||
676 | if (!origMsg->cc()->asUnicodeString().isEmpty()) { | ||
677 | list += origMsg->cc()->mailboxes(); | ||
678 | } | ||
679 | |||
680 | foreach (const KMime::Types::Mailbox &mailbox, list) { | ||
681 | if (!recipients.contains(mailbox) && | ||
682 | !ccRecipients.contains(mailbox)) { | ||
683 | ccRecipients += mailbox; | ||
684 | qDebug() << "Added" << mailbox.prettyAddress() << "to the list of CC recipients"; | ||
685 | } | ||
686 | } | ||
687 | } | ||
688 | |||
689 | if (!ccRecipients.isEmpty()) { | ||
690 | // strip all my addresses from the list of CC recipients | ||
691 | ccRecipients = stripMyAddressesFromAddressList(ccRecipients, me); | ||
692 | |||
693 | // in case of a reply to self, toList might be empty. if that's the case | ||
694 | // then propagate a cc recipient to To: (if there is any). | ||
695 | if (toList.isEmpty() && !ccRecipients.isEmpty()) { | ||
696 | toList << ccRecipients.at(0); | ||
697 | ccRecipients.pop_front(); | ||
698 | } | ||
699 | |||
700 | foreach (const KMime::Types::Mailbox &mailbox, ccRecipients) { | ||
701 | msg->cc()->addAddress(mailbox); | ||
702 | } | ||
703 | } | ||
704 | |||
705 | if (toList.isEmpty() && !recipients.isEmpty()) { | ||
706 | // reply to self without other recipients | ||
707 | toList << recipients.at(0); | ||
708 | } | ||
709 | } | ||
710 | break; | ||
711 | case ReplyAuthor: { | ||
712 | if (!replyToList.isEmpty()) { | ||
713 | KMime::Types::Mailbox::List recipients = replyToList; | ||
714 | |||
715 | // strip the mailing list post address from the list of Reply-To | ||
716 | // addresses since we want to reply in private | ||
717 | foreach (const KMime::Types::Mailbox &mailbox, mailingListAddresses) { | ||
718 | foreach (const KMime::Types::Mailbox &recipient, recipients) { | ||
719 | if (mailbox == recipient) { | ||
720 | recipients.removeAll(recipient); | ||
721 | } | ||
722 | } | ||
723 | } | ||
724 | |||
725 | if (!recipients.isEmpty()) { | ||
726 | toList = recipients; | ||
727 | } else { | ||
728 | // there was only the mailing list post address in the Reply-To header, | ||
729 | // so use the From address instead | ||
730 | toList = origMsg->from()->mailboxes(); | ||
731 | } | ||
732 | } else if (!origMsg->from()->asUnicodeString().isEmpty()) { | ||
733 | toList = origMsg->from()->mailboxes(); | ||
734 | } | ||
735 | } | ||
736 | break; | ||
737 | case ReplyNone: | ||
738 | // the addressees will be set by the caller | ||
739 | break; | ||
740 | } | ||
741 | |||
742 | foreach (const KMime::Types::Mailbox &mailbox, toList) { | ||
743 | msg->to()->addAddress(mailbox); | ||
744 | } | ||
745 | |||
746 | const QByteArray refStr = getRefStr(origMsg); | ||
747 | if (!refStr.isEmpty()) { | ||
748 | msg->references()->fromUnicodeString(QString::fromLocal8Bit(refStr), "utf-8"); | ||
749 | } | ||
750 | |||
751 | //In-Reply-To = original msg-id | ||
752 | msg->inReplyTo()->from7BitString(origMsg->messageID()->as7BitString(false)); | ||
753 | |||
754 | msg->subject()->fromUnicodeString(replySubject(origMsg), "utf-8"); | ||
755 | |||
756 | auto definedLocale = QLocale::system(); | ||
757 | |||
758 | //TODO set empty source instead | ||
759 | StringHtmlWriter htmlWriter; | ||
760 | QImage paintDevice; | ||
761 | CSSHelper cssHelper(&paintDevice); | ||
762 | MessageViewer::NodeHelper nodeHelper; | ||
763 | ObjectTreeSource source(&htmlWriter, &cssHelper); | ||
764 | MessageViewer::ObjectTreeParser otp(&source, &nodeHelper); | ||
765 | otp.setAllowAsync(false); | ||
766 | otp.parseObjectTree(origMsg.data()); | ||
767 | |||
768 | //Add quoted body | ||
769 | QString plainBody; | ||
770 | QString htmlBody; | ||
771 | |||
772 | //On $datetime you wrote: | ||
773 | const QDateTime date = origMsg->date()->dateTime(); | ||
774 | const auto dateTimeString = QString("%1 %2").arg(definedLocale.toString(date.date(), QLocale::LongFormat)).arg(definedLocale.toString(date.time(), QLocale::LongFormat)); | ||
775 | const auto onDateYouWroteLine = QString("On %1 you wrote:").arg(dateTimeString); | ||
776 | plainBody.append(onDateYouWroteLine); | ||
777 | htmlBody.append(plainToHtml(onDateYouWroteLine)); | ||
778 | |||
779 | //Strip signature for replies | ||
780 | const bool stripSignature = true; | ||
781 | |||
782 | //Quoted body | ||
783 | QString plainQuote = quotedPlainText(plainMessageText(otp, stripSignature), origMsg->from()->displayString()); | ||
784 | if (plainQuote.endsWith(QLatin1Char('\n'))) { | ||
785 | plainQuote.chop(1); | ||
786 | } | ||
787 | plainBody.append(plainQuote); | ||
788 | QString headElement; | ||
789 | htmlBody.append(quotedHtmlText(htmlMessageText(otp, stripSignature, headElement))); | ||
790 | |||
791 | if (alwaysPlain) { | ||
792 | htmlBody.clear(); | ||
793 | } else { | ||
794 | makeValidHtml(htmlBody, headElement); | ||
795 | } | ||
796 | |||
797 | addProcessedBodyToMessage(msg, plainBody, htmlBody, false); | ||
798 | |||
799 | applyCharset(msg, origMsg); | ||
800 | |||
801 | msg->assemble(); | ||
802 | |||
803 | return msg; | ||
804 | } | ||
diff --git a/framework/domain/mailtemplates.h b/framework/domain/mailtemplates.h new file mode 100644 index 00000000..6519122a --- /dev/null +++ b/framework/domain/mailtemplates.h | |||
@@ -0,0 +1,28 @@ | |||
1 | /* | ||
2 | Copyright (c) 2016 Christian Mollekopf <mollekopf@kolabsys.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 <QByteArray> | ||
23 | #include <KMime/Message> | ||
24 | |||
25 | namespace MailTemplates | ||
26 | { | ||
27 | KMime::Message::Ptr reply(const KMime::Message::Ptr &message); | ||
28 | }; | ||
diff --git a/framework/domain/mailtransport.cpp b/framework/domain/mailtransport.cpp new file mode 100644 index 00000000..49d858e1 --- /dev/null +++ b/framework/domain/mailtransport.cpp | |||
@@ -0,0 +1,160 @@ | |||
1 | /* | ||
2 | Copyright (c) 2016 Christian Mollekopf <mollekopf@kolabsys.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 | #include "mailtransport.h" | ||
20 | |||
21 | #include <QByteArray> | ||
22 | #include <QList> | ||
23 | #include <QDebug> | ||
24 | |||
25 | extern "C" { | ||
26 | |||
27 | #include <stdio.h> | ||
28 | #include <string.h> | ||
29 | #include <curl/curl.h> | ||
30 | |||
31 | struct upload_status { | ||
32 | int offset; | ||
33 | const char *data; | ||
34 | }; | ||
35 | |||
36 | static size_t payload_source(void *ptr, size_t size, size_t nmemb, void *userp) | ||
37 | { | ||
38 | struct upload_status *upload_ctx = (struct upload_status *)userp; | ||
39 | const char *data; | ||
40 | |||
41 | if((size == 0) || (nmemb == 0) || ((size*nmemb) < 1)) { | ||
42 | return 0; | ||
43 | } | ||
44 | |||
45 | data = &upload_ctx->data[upload_ctx->offset]; | ||
46 | if(data) { | ||
47 | size_t len = strlen(data); | ||
48 | if (len > size * nmemb) { | ||
49 | len = size * nmemb; | ||
50 | } | ||
51 | fprintf(stderr, "read n bytes: %d\n",len); | ||
52 | memcpy(ptr, data, len); | ||
53 | upload_ctx->offset += len; | ||
54 | return len; | ||
55 | } | ||
56 | |||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | |||
61 | void sendMessageCurl(const char *to[], int numTos, const char *cc[], int numCcs, const char *msg, bool useTls, const char* from, const char *username, const char *password, const char *server, bool verifyPeer) | ||
62 | { | ||
63 | //For ssl use "smtps://mainserver.example.net | ||
64 | const char* cacert = 0; // = "/path/to/certificate.pem"; | ||
65 | |||
66 | CURL *curl; | ||
67 | CURLcode res = CURLE_OK; | ||
68 | struct curl_slist *recipients = NULL; | ||
69 | struct upload_status upload_ctx; | ||
70 | |||
71 | upload_ctx.offset = 0; | ||
72 | upload_ctx.data = msg; | ||
73 | |||
74 | curl = curl_easy_init(); | ||
75 | if(curl) { | ||
76 | curl_easy_setopt(curl, CURLOPT_USERNAME, username); | ||
77 | curl_easy_setopt(curl, CURLOPT_PASSWORD, password); | ||
78 | |||
79 | curl_easy_setopt(curl, CURLOPT_URL, server); | ||
80 | |||
81 | if (useTls) { | ||
82 | curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_TRY); | ||
83 | } | ||
84 | |||
85 | if (!verifyPeer) { | ||
86 | curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); | ||
87 | curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); | ||
88 | } | ||
89 | if (cacert) { | ||
90 | curl_easy_setopt(curl, CURLOPT_CAINFO, cacert); | ||
91 | } | ||
92 | |||
93 | if (from) { | ||
94 | curl_easy_setopt(curl, CURLOPT_MAIL_FROM, from); | ||
95 | } | ||
96 | |||
97 | for (int i = 0; i < numTos; i++) { | ||
98 | recipients = curl_slist_append(recipients, to[i]); | ||
99 | } | ||
100 | for (int i = 0; i < numCcs; i++) { | ||
101 | recipients = curl_slist_append(recipients, cc[i]); | ||
102 | } | ||
103 | curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients); | ||
104 | |||
105 | /* We're using a callback function to specify the payload (the headers and | ||
106 | * body of the message). You could just use the CURLOPT_READDATA option to | ||
107 | * specify a FILE pointer to read from. */ | ||
108 | curl_easy_setopt(curl, CURLOPT_READFUNCTION, payload_source); | ||
109 | curl_easy_setopt(curl, CURLOPT_READDATA, &upload_ctx); | ||
110 | curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); | ||
111 | |||
112 | /* Since the traffic will be encrypted, it is very useful to turn on debug | ||
113 | * information within libcurl to see what is happening during the transfer. | ||
114 | */ | ||
115 | curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); | ||
116 | |||
117 | res = curl_easy_perform(curl); | ||
118 | if(res != CURLE_OK) { | ||
119 | fprintf(stderr, "curl_easy_perform() failed: %s\n", | ||
120 | curl_easy_strerror(res)); | ||
121 | } | ||
122 | curl_slist_free_all(recipients); | ||
123 | curl_easy_cleanup(curl); | ||
124 | } | ||
125 | } | ||
126 | |||
127 | }; | ||
128 | |||
129 | void MailTransport::sendMessage(const KMime::Message::Ptr &message, const QByteArray &server, const QByteArray &username, const QByteArray &password, const QByteArray &cacert) | ||
130 | { | ||
131 | QByteArray msg = message->encodedContent(); | ||
132 | qWarning() << "Sending message " << msg; | ||
133 | |||
134 | QByteArray from(message->from(true)->mailboxes().isEmpty() ? QByteArray() : message->from(true)->mailboxes().first().address()); | ||
135 | QList<QByteArray> toList; | ||
136 | for (const auto &mb : message->to(true)->mailboxes()) { | ||
137 | toList << mb.address(); | ||
138 | } | ||
139 | QList<QByteArray> ccList; | ||
140 | for (const auto &mb : message->cc(true)->mailboxes()) { | ||
141 | ccList << mb.address(); | ||
142 | } | ||
143 | bool useTls = true; | ||
144 | bool verifyPeer = false; | ||
145 | |||
146 | const int numTos = toList.size(); | ||
147 | const char* to[numTos]; | ||
148 | for (int i = 0; i < numTos; i++) { | ||
149 | to[i] = toList.at(i); | ||
150 | } | ||
151 | |||
152 | const int numCcs = ccList.size(); | ||
153 | const char* cc[numCcs]; | ||
154 | for (int i = 0; i < numCcs; i++) { | ||
155 | cc[i] = ccList.at(i); | ||
156 | } | ||
157 | |||
158 | sendMessageCurl(to, numTos, cc, numCcs, msg, useTls, from.isEmpty() ? nullptr : from, username, password, server, verifyPeer); | ||
159 | qWarning() << "Message sent"; | ||
160 | } | ||
diff --git a/framework/domain/mailtransport.h b/framework/domain/mailtransport.h new file mode 100644 index 00000000..2eb30a03 --- /dev/null +++ b/framework/domain/mailtransport.h | |||
@@ -0,0 +1,28 @@ | |||
1 | /* | ||
2 | Copyright (c) 2016 Christian Mollekopf <mollekopf@kolabsys.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 <QByteArray> | ||
23 | #include <KMime/Message> | ||
24 | |||
25 | namespace MailTransport | ||
26 | { | ||
27 | void sendMessage(const KMime::Message::Ptr &message, const QByteArray &server, const QByteArray &username, const QByteArray &password, const QByteArray &cacert); | ||
28 | }; | ||
diff --git a/framework/domain/messageparser.cpp b/framework/domain/messageparser.cpp new file mode 100644 index 00000000..89f67f38 --- /dev/null +++ b/framework/domain/messageparser.cpp | |||
@@ -0,0 +1,76 @@ | |||
1 | /* | ||
2 | Copyright (c) 2016 Christian Mollekopf <mollekopf@kolabsys.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 | #include "messageparser.h" | ||
20 | |||
21 | #include "stringhtmlwriter.h" | ||
22 | #include "objecttreesource.h" | ||
23 | #include "csshelper.h" | ||
24 | |||
25 | #include <QFile> | ||
26 | #include <QImage> | ||
27 | #include <QDebug> | ||
28 | #include <QTime> | ||
29 | #include <MessageViewer/ObjectTreeParser> | ||
30 | |||
31 | MessageParser::MessageParser(QObject *parent) | ||
32 | : QObject(parent) | ||
33 | { | ||
34 | |||
35 | } | ||
36 | |||
37 | QString MessageParser::html() const | ||
38 | { | ||
39 | return mHtml; | ||
40 | } | ||
41 | |||
42 | QVariant MessageParser::message() const | ||
43 | { | ||
44 | return QVariant(); | ||
45 | } | ||
46 | |||
47 | void MessageParser::setMessage(const QVariant &message) | ||
48 | { | ||
49 | QTime time; | ||
50 | time.start(); | ||
51 | const auto mailData = KMime::CRLFtoLF(message.toByteArray()); | ||
52 | KMime::Message::Ptr msg(new KMime::Message); | ||
53 | msg->setContent(mailData); | ||
54 | msg->parse(); | ||
55 | qWarning() << "parsed: " << time.elapsed(); | ||
56 | |||
57 | // render the mail | ||
58 | StringHtmlWriter htmlWriter; | ||
59 | QImage paintDevice; | ||
60 | CSSHelper cssHelper(&paintDevice); | ||
61 | //temporary files only have the lifetime of the nodehelper, so we keep it around until the mail changes. | ||
62 | mNodeHelper = std::make_shared<MessageViewer::NodeHelper>(); | ||
63 | ObjectTreeSource source(&htmlWriter, &cssHelper); | ||
64 | MessageViewer::ObjectTreeParser otp(&source, mNodeHelper.get()); | ||
65 | |||
66 | htmlWriter.begin(QString()); | ||
67 | htmlWriter.queue(cssHelper.htmlHead(false)); | ||
68 | |||
69 | otp.parseObjectTree(msg.data()); | ||
70 | |||
71 | htmlWriter.queue(QStringLiteral("</body></html>")); | ||
72 | htmlWriter.end(); | ||
73 | |||
74 | mHtml = htmlWriter.html(); | ||
75 | emit htmlChanged(); | ||
76 | } | ||
diff --git a/framework/domain/messageparser.h b/framework/domain/messageparser.h new file mode 100644 index 00000000..ba08a5ec --- /dev/null +++ b/framework/domain/messageparser.h | |||
@@ -0,0 +1,51 @@ | |||
1 | /* | ||
2 | Copyright (c) 2016 Christian Mollekopf <mollekopf@kolabsys.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 <QObject> | ||
23 | #include <QString> | ||
24 | #include <QStringList> | ||
25 | #include <memory> | ||
26 | |||
27 | namespace MessageViewer { | ||
28 | class NodeHelper; | ||
29 | }; | ||
30 | |||
31 | class MessageParser : public QObject | ||
32 | { | ||
33 | Q_OBJECT | ||
34 | Q_PROPERTY (QVariant message READ message WRITE setMessage) | ||
35 | Q_PROPERTY (QString html READ html NOTIFY htmlChanged) | ||
36 | |||
37 | public: | ||
38 | explicit MessageParser(QObject *parent = Q_NULLPTR); | ||
39 | |||
40 | QString html() const; | ||
41 | |||
42 | QVariant message() const; | ||
43 | void setMessage(const QVariant &to); | ||
44 | |||
45 | signals: | ||
46 | void htmlChanged(); | ||
47 | |||
48 | private: | ||
49 | QString mHtml; | ||
50 | std::shared_ptr<MessageViewer::NodeHelper> mNodeHelper; | ||
51 | }; | ||
diff --git a/framework/domain/objecttreesource.cpp b/framework/domain/objecttreesource.cpp new file mode 100644 index 00000000..d14b7b9b --- /dev/null +++ b/framework/domain/objecttreesource.cpp | |||
@@ -0,0 +1,144 @@ | |||
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 <MessageViewer/AttachmentStrategy> | ||
23 | |||
24 | class ObjectSourcePrivate | ||
25 | { | ||
26 | public: | ||
27 | ObjectSourcePrivate() | ||
28 | : mWriter(0) | ||
29 | , mCSSHelper(0) | ||
30 | , mAllowDecryption(true) | ||
31 | , mHtmlLoadExternal(true) | ||
32 | , mHtmlMail(true) | ||
33 | { | ||
34 | |||
35 | } | ||
36 | MessageViewer::HtmlWriter *mWriter; | ||
37 | MessageViewer::CSSHelperBase *mCSSHelper; | ||
38 | bool mAllowDecryption; | ||
39 | bool mHtmlLoadExternal; | ||
40 | bool mHtmlMail; | ||
41 | }; | ||
42 | |||
43 | ObjectTreeSource::ObjectTreeSource(MessageViewer::HtmlWriter *writer, | ||
44 | MessageViewer::CSSHelperBase *cssHelper) | ||
45 | : MessageViewer::ObjectTreeSourceIf() | ||
46 | , d(new ObjectSourcePrivate) | ||
47 | { | ||
48 | d->mWriter = writer; | ||
49 | d->mCSSHelper = cssHelper; | ||
50 | } | ||
51 | |||
52 | ObjectTreeSource::~ObjectTreeSource() | ||
53 | { | ||
54 | delete d; | ||
55 | } | ||
56 | |||
57 | void ObjectTreeSource::setAllowDecryption(bool allowDecryption) | ||
58 | { | ||
59 | d->mAllowDecryption = allowDecryption; | ||
60 | } | ||
61 | |||
62 | MessageViewer::HtmlWriter *ObjectTreeSource::htmlWriter() | ||
63 | { | ||
64 | return d->mWriter; | ||
65 | } | ||
66 | MessageViewer::CSSHelperBase *ObjectTreeSource::cssHelper() | ||
67 | { | ||
68 | return d->mCSSHelper; | ||
69 | } | ||
70 | |||
71 | bool ObjectTreeSource::htmlLoadExternal() const | ||
72 | { | ||
73 | return d->mHtmlLoadExternal; | ||
74 | } | ||
75 | |||
76 | void ObjectTreeSource::setHtmlLoadExternal(bool loadExternal) | ||
77 | { | ||
78 | d->mHtmlLoadExternal = loadExternal; | ||
79 | } | ||
80 | |||
81 | bool ObjectTreeSource::htmlMail() const | ||
82 | { | ||
83 | return d->mHtmlMail; | ||
84 | } | ||
85 | |||
86 | void ObjectTreeSource::setHtmlMail(bool htmlMail) | ||
87 | { | ||
88 | d->mHtmlMail = htmlMail; | ||
89 | } | ||
90 | |||
91 | bool ObjectTreeSource::decryptMessage() const | ||
92 | { | ||
93 | return d->mAllowDecryption; | ||
94 | } | ||
95 | |||
96 | bool ObjectTreeSource::showSignatureDetails() const | ||
97 | { | ||
98 | return true; | ||
99 | } | ||
100 | |||
101 | int ObjectTreeSource::levelQuote() const | ||
102 | { | ||
103 | return 1; | ||
104 | } | ||
105 | |||
106 | const QTextCodec *ObjectTreeSource::overrideCodec() | ||
107 | { | ||
108 | return Q_NULLPTR; | ||
109 | } | ||
110 | |||
111 | QString ObjectTreeSource::createMessageHeader(KMime::Message *message) | ||
112 | { | ||
113 | return QString(); | ||
114 | } | ||
115 | |||
116 | const MessageViewer::AttachmentStrategy *ObjectTreeSource::attachmentStrategy() | ||
117 | { | ||
118 | return MessageViewer::AttachmentStrategy::smart(); | ||
119 | } | ||
120 | |||
121 | QObject *ObjectTreeSource::sourceObject() | ||
122 | { | ||
123 | return Q_NULLPTR; | ||
124 | } | ||
125 | |||
126 | void ObjectTreeSource::setHtmlMode(MessageViewer::Util::HtmlMode mode) | ||
127 | { | ||
128 | Q_UNUSED(mode); | ||
129 | } | ||
130 | |||
131 | bool ObjectTreeSource::autoImportKeys() const | ||
132 | { | ||
133 | return false; | ||
134 | } | ||
135 | |||
136 | bool ObjectTreeSource::showEmoticons() const | ||
137 | { | ||
138 | return false; | ||
139 | } | ||
140 | |||
141 | bool ObjectTreeSource::showExpandQuotesMark() const | ||
142 | { | ||
143 | return false; | ||
144 | } | ||
diff --git a/framework/domain/objecttreesource.h b/framework/domain/objecttreesource.h new file mode 100644 index 00000000..db14e3ff --- /dev/null +++ b/framework/domain/objecttreesource.h | |||
@@ -0,0 +1,57 @@ | |||
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 <MessageViewer/ObjectTreeSourceIf> | ||
24 | |||
25 | class QString; | ||
26 | |||
27 | class ObjectSourcePrivate; | ||
28 | class ObjectTreeSource : public MessageViewer::ObjectTreeSourceIf | ||
29 | { | ||
30 | public: | ||
31 | ObjectTreeSource(MessageViewer::HtmlWriter *writer, | ||
32 | MessageViewer::CSSHelperBase *cssHelper); | ||
33 | virtual ~ObjectTreeSource(); | ||
34 | void setHtmlLoadExternal(bool loadExternal); | ||
35 | void setHtmlMail(bool htmlMail); | ||
36 | bool htmlMail() const Q_DECL_OVERRIDE; | ||
37 | bool decryptMessage() const Q_DECL_OVERRIDE; | ||
38 | bool htmlLoadExternal() const Q_DECL_OVERRIDE; | ||
39 | bool showSignatureDetails() const Q_DECL_OVERRIDE; | ||
40 | void setHtmlMode(MessageViewer::Util::HtmlMode mode) Q_DECL_OVERRIDE; | ||
41 | void setAllowDecryption(bool allowDecryption); | ||
42 | int levelQuote() const Q_DECL_OVERRIDE; | ||
43 | const QTextCodec *overrideCodec() Q_DECL_OVERRIDE; | ||
44 | QString createMessageHeader(KMime::Message *message) Q_DECL_OVERRIDE; | ||
45 | const MessageViewer::AttachmentStrategy *attachmentStrategy() Q_DECL_OVERRIDE; | ||
46 | MessageViewer::HtmlWriter *htmlWriter() Q_DECL_OVERRIDE; | ||
47 | MessageViewer::CSSHelperBase *cssHelper() Q_DECL_OVERRIDE; | ||
48 | QObject *sourceObject() Q_DECL_OVERRIDE; | ||
49 | bool autoImportKeys() const Q_DECL_OVERRIDE; | ||
50 | bool showEmoticons() const Q_DECL_OVERRIDE; | ||
51 | bool showExpandQuotesMark() const Q_DECL_OVERRIDE; | ||
52 | private: | ||
53 | ObjectSourcePrivate *const d; | ||
54 | }; | ||
55 | |||
56 | #endif | ||
57 | |||
diff --git a/framework/domain/qmldir b/framework/domain/qmldir new file mode 100644 index 00000000..fd54e5ee --- /dev/null +++ b/framework/domain/qmldir | |||
@@ -0,0 +1,3 @@ | |||
1 | module org.kde.kube.mail | ||
2 | |||
3 | plugin mailplugin | ||
diff --git a/framework/domain/retriever.cpp b/framework/domain/retriever.cpp new file mode 100644 index 00000000..b8e29523 --- /dev/null +++ b/framework/domain/retriever.cpp | |||
@@ -0,0 +1,55 @@ | |||
1 | /* | ||
2 | Copyright (c) 2016 Christian Mollekopf <mollekopf@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 | |||
21 | #include "retriever.h" | ||
22 | |||
23 | Retriever::Retriever(QObject *parent) : QObject(parent) | ||
24 | { | ||
25 | } | ||
26 | |||
27 | QAbstractItemModel* Retriever::model() const | ||
28 | { | ||
29 | return mModel; | ||
30 | } | ||
31 | |||
32 | void Retriever::setModel(QAbstractItemModel* model) | ||
33 | { | ||
34 | mValue = QVariant(); | ||
35 | mModel = model; | ||
36 | connect(model, &QAbstractItemModel::rowsInserted, this, &Retriever::onRowsInserted); | ||
37 | connect(model, &QAbstractItemModel::modelReset, this, &Retriever::onModelReset); | ||
38 | if (model->rowCount(QModelIndex())) { | ||
39 | mValue = model->index(0, 0, QModelIndex()).data(mModel->roleNames().key(mPropertyName.toLatin1())); | ||
40 | emit valueChanged(); | ||
41 | } | ||
42 | } | ||
43 | |||
44 | void Retriever::onRowsInserted(const QModelIndex &parent, int first, int last) | ||
45 | { | ||
46 | if (!mValue.isValid()) { | ||
47 | mValue = mModel->index(0, 0, QModelIndex()).data(mModel->roleNames().key(mPropertyName.toLatin1())); | ||
48 | emit valueChanged(); | ||
49 | } | ||
50 | } | ||
51 | |||
52 | void Retriever::onModelReset() | ||
53 | { | ||
54 | mValue = QVariant(); | ||
55 | } | ||
diff --git a/framework/domain/retriever.h b/framework/domain/retriever.h new file mode 100644 index 00000000..e454532d --- /dev/null +++ b/framework/domain/retriever.h | |||
@@ -0,0 +1,55 @@ | |||
1 | /* | ||
2 | Copyright (c) 2016 Christian Mollekopf <mollekopf@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 <QObject> | ||
23 | #include <QAbstractItemModel> | ||
24 | #include <QVariant> | ||
25 | |||
26 | /** | ||
27 | * A wrapper for a QAbstractItemModel to retrieve a value from a single index via property binding | ||
28 | * | ||
29 | * Assign a model that retrieves the index, set the property your interested in, and propery-bind "value". | ||
30 | */ | ||
31 | class Retriever : public QObject | ||
32 | { | ||
33 | Q_OBJECT | ||
34 | Q_PROPERTY(QAbstractItemModel* model READ model WRITE setModel) | ||
35 | Q_PROPERTY(QString propertyName MEMBER mPropertyName) | ||
36 | Q_PROPERTY(QVariant value MEMBER mValue NOTIFY valueChanged) | ||
37 | |||
38 | public: | ||
39 | explicit Retriever(QObject *parent = Q_NULLPTR); | ||
40 | |||
41 | QAbstractItemModel* model() const; | ||
42 | void setModel(QAbstractItemModel* model); | ||
43 | |||
44 | signals: | ||
45 | void valueChanged(); | ||
46 | |||
47 | private slots: | ||
48 | void onRowsInserted(const QModelIndex &parent, int first, int last); | ||
49 | void onModelReset(); | ||
50 | |||
51 | private: | ||
52 | QString mPropertyName; | ||
53 | QVariant mValue; | ||
54 | QAbstractItemModel *mModel; | ||
55 | }; | ||
diff --git a/framework/domain/singlemailcontroller.cpp b/framework/domain/singlemailcontroller.cpp new file mode 100644 index 00000000..8ee4acbb --- /dev/null +++ b/framework/domain/singlemailcontroller.cpp | |||
@@ -0,0 +1,46 @@ | |||
1 | /* | ||
2 | Copyright (c) 2016 Michael Bohlender <michael.bohlender@kdemail.net> | ||
3 | Copyright (c) 2016 Christian Mollekopf <mollekopf@kolabsys.com> | ||
4 | |||
5 | This library is free software; you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Library General Public License as published by | ||
7 | the Free Software Foundation; either version 2 of the License, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, but WITHOUT | ||
11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public | ||
13 | License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Library General Public License | ||
16 | along with this library; see the file COPYING.LIB. If not, write to the | ||
17 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | #include "singlemailcontroller.h" | ||
22 | |||
23 | SingleMailController::SingleMailController(QObject *parent) : QObject(parent), m_model(new MailListModel) | ||
24 | { | ||
25 | |||
26 | } | ||
27 | |||
28 | SingleMailController::~SingleMailController() | ||
29 | { | ||
30 | |||
31 | } | ||
32 | |||
33 | MailListModel* SingleMailController::model() const | ||
34 | { | ||
35 | return m_model.data(); | ||
36 | } | ||
37 | |||
38 | |||
39 | void SingleMailController::loadMail(const QString &id) | ||
40 | { | ||
41 | Sink::Query query; | ||
42 | query.liveQuery = false; | ||
43 | query.requestedProperties << "subject" << "sender" << "senderName" << "date" << "unread" << "important" << "mimeMessage"; | ||
44 | query.ids << id.toLatin1(); | ||
45 | m_model->runQuery(query); | ||
46 | } \ No newline at end of file | ||
diff --git a/framework/domain/singlemailcontroller.h b/framework/domain/singlemailcontroller.h new file mode 100644 index 00000000..283b03c4 --- /dev/null +++ b/framework/domain/singlemailcontroller.h | |||
@@ -0,0 +1,49 @@ | |||
1 | /* | ||
2 | Copyright (c) 2016 Michael Bohlender <michael.bohlender@kdemail.net> | ||
3 | Copyright (c) 2016 Christian Mollekopf <mollekopf@kolabsys.com> | ||
4 | |||
5 | This library is free software; you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Library General Public License as published by | ||
7 | the Free Software Foundation; either version 2 of the License, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, but WITHOUT | ||
11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public | ||
13 | License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Library General Public License | ||
16 | along with this library; see the file COPYING.LIB. If not, write to the | ||
17 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | #pragma once | ||
22 | |||
23 | #include "maillistmodel.h" | ||
24 | |||
25 | #include <QObject> | ||
26 | #include <QString> | ||
27 | #include <QDateTime> | ||
28 | #include <QScopedPointer> | ||
29 | |||
30 | class SingleMailController : public QObject | ||
31 | { | ||
32 | Q_OBJECT | ||
33 | Q_PROPERTY (MailListModel *model READ model CONSTANT) | ||
34 | |||
35 | public: | ||
36 | explicit SingleMailController(QObject *parent = Q_NULLPTR); | ||
37 | ~SingleMailController(); | ||
38 | |||
39 | MailListModel *model() const; | ||
40 | |||
41 | Q_SIGNALS: | ||
42 | void messageChanged(); | ||
43 | |||
44 | public slots: | ||
45 | void loadMail(const QString &id); | ||
46 | |||
47 | private: | ||
48 | QScopedPointer<MailListModel> m_model; | ||
49 | }; | ||
diff --git a/framework/domain/stringhtmlwriter.cpp b/framework/domain/stringhtmlwriter.cpp new file mode 100644 index 00000000..df108946 --- /dev/null +++ b/framework/domain/stringhtmlwriter.cpp | |||
@@ -0,0 +1,145 @@ | |||
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 | |||
38 | StringHtmlWriter::StringHtmlWriter() | ||
39 | : MessageViewer::HtmlWriter() | ||
40 | , mState(Ended) | ||
41 | { | ||
42 | } | ||
43 | |||
44 | StringHtmlWriter::~StringHtmlWriter() | ||
45 | { | ||
46 | } | ||
47 | |||
48 | void 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 | |||
64 | void 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 | |||
78 | void 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 | |||
89 | void 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 | |||
97 | void StringHtmlWriter::queue(const QString &str) | ||
98 | { | ||
99 | write(str); | ||
100 | } | ||
101 | |||
102 | void StringHtmlWriter::flush() | ||
103 | { | ||
104 | mState = Begun; // don't run into end()'s warning | ||
105 | end(); | ||
106 | } | ||
107 | |||
108 | void StringHtmlWriter::embedPart(const QByteArray &contentId, const QString &url) | ||
109 | { | ||
110 | write("<!-- embedPart(contentID=" + contentId + ", url=" + url + ") -->\n"); | ||
111 | mEmbeddedPartMap.insert(contentId, url); | ||
112 | } | ||
113 | |||
114 | void 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 | |||
121 | void 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 | |||
130 | void 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 | |||
139 | QString StringHtmlWriter::html() const | ||
140 | { | ||
141 | if (mState != Ended) { | ||
142 | qWarning() << "Called on non-ended session!"; | ||
143 | } | ||
144 | return mHtml; | ||
145 | } | ||
diff --git a/framework/domain/stringhtmlwriter.h b/framework/domain/stringhtmlwriter.h new file mode 100644 index 00000000..fa0a7aa5 --- /dev/null +++ b/framework/domain/stringhtmlwriter.h | |||
@@ -0,0 +1,70 @@ | |||
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 <MessageViewer/HtmlWriter> | ||
34 | |||
35 | #include <QFile> | ||
36 | #include <QTextStream> | ||
37 | |||
38 | class QString; | ||
39 | |||
40 | class StringHtmlWriter : public MessageViewer::HtmlWriter | ||
41 | { | ||
42 | public: | ||
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 | private: | ||
57 | void insertExtraHead(); | ||
58 | void resolveCidUrls(); | ||
59 | |||
60 | QString mHtml; | ||
61 | QString mExtraHead; | ||
62 | enum State { | ||
63 | Begun, | ||
64 | Queued, | ||
65 | Ended | ||
66 | } mState; | ||
67 | QMap<QByteArray, QUrl> mEmbeddedPartMap; | ||
68 | }; | ||
69 | |||
70 | #endif // __MESSAGEVIEWER_FILEHTMLWRITER_H__ | ||