Page MenuHome GnuPG

No OneTemporary

diff --git a/src/core/autotests/fileopenertest.cpp b/src/core/autotests/fileopenertest.cpp
index 4e1b315..0be9ab8 100644
--- a/src/core/autotests/fileopenertest.cpp
+++ b/src/core/autotests/fileopenertest.cpp
@@ -1,57 +1,58 @@
-// SPDX-FileCopyrightText: 2023 Carl Schwan <carl@carlschwan.eu>
+// SPDX-FileCopyrightText: 2023 g10 Code GmbH
+// SPDX-FileContributor: Carl Schwan <carl@carlschwan.eu>
// SPDX-License-Identifier: LGPL-2.0-or-later
#include <MimeTreeParserCore/FileOpener>
#include <QDebug>
#include <QTest>
using namespace MimeTreeParser::Core;
class FileOpenerTest : public QObject
{
Q_OBJECT
private Q_SLOTS:
void openSingleMboxTest()
{
const auto messages = FileOpener::openFile(QLatin1String(MAIL_DATA_DIR) + QLatin1Char('/') + QLatin1String("smime-opaque-enc+sign.mbox"));
QCOMPARE(messages.count(), 1);
}
void openSingleCombinedTest()
{
const auto messages = FileOpener::openFile(QLatin1String(MAIL_DATA_DIR) + QLatin1Char('/') + QLatin1String("combined.mbox"));
QCOMPARE(messages.count(), 3);
}
void openAscTest()
{
const auto messages = FileOpener::openFile(QLatin1String(MAIL_DATA_DIR) + QLatin1Char('/') + QLatin1String("msg.asc"));
QCOMPARE(messages.count(), 1);
auto message = messages[0];
QCOMPARE(message->contentType()->mimeType(), "multipart/encrypted");
QCOMPARE(message->contents().count(), 2);
auto pgpPart = message->contents()[0];
QCOMPARE(pgpPart->contentType()->mimeType(), "application/pgp-encrypted");
auto octetStreamPart = message->contents()[1];
QCOMPARE(octetStreamPart->contentType()->mimeType(), "application/octet-stream");
}
void openSmimeTest()
{
const auto messages = FileOpener::openFile(QLatin1String(MAIL_DATA_DIR) + QLatin1Char('/') + QLatin1String("smime.p7m"));
QCOMPARE(messages.count(), 1);
auto message = messages[0];
QCOMPARE(message->contentType()->mimeType(), "application/pkcs7-mime");
QCOMPARE(message->contentType()->parameter(QStringLiteral("smime-type")), QStringLiteral("enveloped-data"));
QCOMPARE(message->contentDisposition()->filename(), QStringLiteral("smime.p7m"));
}
};
QTEST_GUILESS_MAIN(FileOpenerTest)
#include "fileopenertest.moc"
diff --git a/src/core/fileopener.cpp b/src/core/fileopener.cpp
index 0ac8b26..574022c 100644
--- a/src/core/fileopener.cpp
+++ b/src/core/fileopener.cpp
@@ -1,128 +1,129 @@
-// SPDX-FileCopyrigthText: 2023 Carl Schwan <carl@carlschwan.eu>
+// SPDX-FileCopyrightText: 2023 g10 Code GmbH
+// SPDX-FileContributor: Carl Schwan <carl.schwan@gnupg.com>
// SPDX-License-Identifier: LGPL-2.0-or-later
#include "fileopener.h"
#include "mimetreeparser_core_debug.h"
#include <QFile>
#include <QMimeDatabase>
#include <QMimeType>
using namespace MimeTreeParser::Core;
QVector<KMime::Message::Ptr> FileOpener::openFile(const QString &fileName)
{
QMimeDatabase db;
QMimeType mime = db.mimeTypeForFile(fileName);
KMime::Message::Ptr message(new KMime::Message);
QFile file(fileName);
file.open(QIODevice::ReadOnly);
if (!file.isOpen()) {
qCWarning(MIMETREEPARSER_CORE_LOG) << "Could not open file";
return {};
}
const auto content = file.readAll();
if (content.length() == 0) {
qCWarning(MIMETREEPARSER_CORE_LOG) << "File is empty";
return {};
}
if (mime.inherits(QStringLiteral("application/pkcs7-mime")) || fileName.endsWith(QStringLiteral("smime.p7m"))) {
auto contentType = message->contentType();
contentType->setMimeType("application/pkcs7-mime");
contentType->setParameter(QStringLiteral("smime-type"), QStringLiteral("enveloped-data"));
auto contentDisposition = new KMime::Headers::ContentDisposition;
contentDisposition->setDisposition(KMime::Headers::CDattachment);
contentDisposition->setFilename(QStringLiteral("smime.p7m"));
message->appendHeader(contentDisposition);
auto cte = message->contentTransferEncoding();
cte->setEncoding(KMime::Headers::CE7Bit);
cte->setDecoded(true);
message->setBody(content);
message->assemble();
} else if (mime.inherits(QStringLiteral("application/pgp-encrypted")) || fileName.endsWith(QStringLiteral(".asc"))) {
auto contentType = message->contentType();
contentType->setMimeType("multipart/encrypted");
contentType->setBoundary(KMime::multiPartBoundary());
contentType->setParameter(QStringLiteral("protocol"), QStringLiteral("application/pgp-encrypted"));
contentType->setCategory(KMime::Headers::CCcontainer);
auto cte = message->contentTransferEncoding();
cte->setEncoding(KMime::Headers::CE7Bit);
cte->setDecoded(true);
auto pgpEncrypted = new KMime::Content;
pgpEncrypted->contentType()->setMimeType("application/pgp-encrypted");
auto contentDisposition = new KMime::Headers::ContentDisposition;
contentDisposition->setDisposition(KMime::Headers::CDattachment);
pgpEncrypted->appendHeader(contentDisposition);
pgpEncrypted->setBody("Version: 1");
message->addContent(pgpEncrypted);
auto encryptedContent = new KMime::Content;
encryptedContent->contentType()->setMimeType("application/octet-stream");
contentDisposition = new KMime::Headers::ContentDisposition;
contentDisposition->setDisposition(KMime::Headers::CDinline);
contentDisposition->setFilename(QStringLiteral("msg.asc"));
encryptedContent->appendHeader(contentDisposition);
encryptedContent->setBody(content);
message->addContent(encryptedContent);
message->assemble();
} else {
int startOfMessage = 0;
if (content.startsWith("From ")) {
startOfMessage = content.indexOf('\n');
if (startOfMessage == -1) {
return {};
}
startOfMessage += 1; // the message starts after the '\n'
}
QVector<KMime::Message::Ptr> listMessages;
// check for multiple messages in the file
int endOfMessage = content.indexOf("\nFrom ", startOfMessage);
while (endOfMessage != -1) {
if (content.indexOf("From ", startOfMessage) == startOfMessage) {
startOfMessage = content.indexOf('\n', startOfMessage) + 1;
}
auto msg = new KMime::Message;
msg->setContent(KMime::CRLFtoLF(content.mid(startOfMessage, endOfMessage - startOfMessage)));
msg->parse();
if (!msg->hasContent()) {
delete msg;
msg = nullptr;
return {};
}
KMime::Message::Ptr mMsg(msg);
listMessages << mMsg;
startOfMessage = endOfMessage + 1;
endOfMessage = content.indexOf("\nFrom ", startOfMessage);
}
if (endOfMessage == -1) {
if (content.indexOf("From ", startOfMessage) == startOfMessage) {
startOfMessage = content.indexOf('\n', startOfMessage) + 1;
}
endOfMessage = content.length();
auto msg = new KMime::Message;
msg->setContent(KMime::CRLFtoLF(content.mid(startOfMessage, endOfMessage - startOfMessage)));
msg->parse();
if (!msg->hasContent()) {
delete msg;
msg = nullptr;
return {};
}
KMime::Message::Ptr mMsg(msg);
listMessages << mMsg;
}
return listMessages;
}
return {message};
}
diff --git a/src/core/fileopener.h b/src/core/fileopener.h
index a222173..2972588 100644
--- a/src/core/fileopener.h
+++ b/src/core/fileopener.h
@@ -1,20 +1,21 @@
-// SPDX-FileCopyrigthText: 2023 Carl Schwan <carl@carlschwan.eu>
+// SPDX-FileCopyrightText: 2023 g10 Code GmbH
+// SPDX-FileContributor: Carl Schwan <carl.schwan@gnupg.com>
// SPDX-License-Identifier: LGPL-2.0-or-later
#pragma once
#include "mimetreeparser_core_export.h"
#include <KMime/Message>
namespace MimeTreeParser
{
namespace Core
{
namespace FileOpener
{
/// Open messages from file
QVector<KMime::Message::Ptr> MIMETREEPARSER_CORE_EXPORT openFile(const QString &fileName);
}
}
}
diff --git a/src/widgets/CMakeLists.txt b/src/widgets/CMakeLists.txt
index 1bbf460..2fb4974 100644
--- a/src/widgets/CMakeLists.txt
+++ b/src/widgets/CMakeLists.txt
@@ -1,155 +1,158 @@
-# SPDX-FileCopyrightText: 2023 Carl Schwan <carl.schwan@gnupg.com>
+# SPDX-FileCopyrightText: 2023 g10 Code GmbH
+# SPDX-FileContributor: Carl Schwan <carlschwan@kde.org>
# SPDX-License-Identifier: BSD-3-Clause
ecm_setup_version(PROJECT
VARIABLE_PREFIX MIMETREEPARSER_WIDGETS
VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/mimetreeparser_widgets_version.h"
PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KPim${KF_MAJOR_VERSION}MimeTreeParserWidgetsConfigVersion.cmake"
SOVERSION 5
)
add_library(KPim${KF_MAJOR_VERSION}MimeTreeParserWidgets)
add_library(KPim${KF_MAJOR_VERSION}::MimeTreeParserWidgets
ALIAS KPim${KF_MAJOR_VERSION}MimeTreeParserWidgets)
target_sources(KPim${KF_MAJOR_VERSION}MimeTreeParserWidgets PRIVATE
attachmentview_p.h
attachmentview.cpp
messagecontainerwidget_p.h
messagecontainerwidget.cpp
messageviewer.h
messageviewer.cpp
messageviewerdialog.h
messageviewerdialog.cpp
urlhandler_p.h
urlhandler.cpp
)
ecm_qt_declare_logging_category(KPim${KF_MAJOR_VERSION}MimeTreeParserWidgets
HEADER mimetreeparser_widgets_debug.h
IDENTIFIER MIMETREEPARSER_WIDGET_LOG
CATEGORY_NAME org.kde.pim.mimetreeparser.widgets
DESCRIPTION "mimetreeparser (pim lib)"
EXPORT MIMETREEPARSER
)
if (COMPILE_WITH_UNITY_CMAKE_SUPPORT)
set_target_properties(KPim${KF_MAJOR_VERSION}MimeTreeParserWidgets PROPERTIES UNITY_BUILD ON)
endif()
generate_export_header(KPim${KF_MAJOR_VERSION}MimeTreeParserWidgets BASE_NAME mimetreeparser_widgets)
target_include_directories(KPim${KF_MAJOR_VERSION}MimeTreeParserWidgets INTERFACE "$<INSTALL_INTERFACE:${KDE_INSTALL_INCLUDEDIR}/KPim${KF_MAJOR_VERSION}/MimeTreeParserWidgets>")
target_link_libraries(KPim${KF_MAJOR_VERSION}MimeTreeParserWidgets
PUBLIC
Qt${KF_MAJOR_VERSION}::Widgets
KPim${KF_MAJOR_VERSION}::MimeTreeParserCore
PRIVATE
Qt${KF_MAJOR_VERSION}::PrintSupport
KF${KF_MAJOR_VERSION}::Codecs
KF${KF_MAJOR_VERSION}::I18n
KF${KF_MAJOR_VERSION}::CalendarCore
KF${KF_MAJOR_VERSION}::WidgetsAddons
KPim${KF_MAJOR_VERSION}::Libkleo
Gpgme::Gpgme
)
set_target_properties(KPim${KF_MAJOR_VERSION}MimeTreeParserWidgets PROPERTIES
VERSION ${MIMETREEPARSERNG_VERSION}
SOVERSION ${MIMETREEPARSERNG_SOVERSION}
EXPORT_NAME MimeTreeParserWidgets
)
ecm_generate_pri_file(BASE_NAME MimeTreeParserWidgets
LIB_NAME KPim${KF_MAJOR_VERSION}MimeTreeParserWidgets
DEPS "MimeTreeParserWidgets"
FILENAME_VAR PRI_FILENAME
)
install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR})
install(TARGETS
KPim${KF_MAJOR_VERSION}MimeTreeParserWidgets
EXPORT KPim${KF_MAJOR_VERSION}MimeTreeParserWidgetsTargets ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}
)
ecm_generate_headers(MimeTreeParserWidgets_CamelCase_HEADERS
HEADER_NAMES
MessageViewer
MessageViewerDialog
REQUIRED_HEADERS MimeTreeParserWidgets_HEADERS
PREFIX MimeTreeParserWidgets
)
install(FILES
${MimeTreeParserWidgets_CamelCase_HEADERS}
DESTINATION ${KDE_INSTALL_INCLUDEDIR}/KPim${KF_MAJOR_VERSION}/MimeTreeParserWidgets/MimeTreeParserWidgets
COMPONENT Devel
)
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/mimetreeparser_widgets_export.h
${MimeTreeParserWidgets_HEADERS}
DESTINATION ${KDE_INSTALL_INCLUDEDIR}/KPim${KF_MAJOR_VERSION}/MimeTreeParserWidgets/mimetreeparserwidgets
COMPONENT Devel
)
if (BUILD_QCH)
ecm_add_qch(
KPim${KF_MAJOR_VERSION}MimeTreeParserWidgets_QCH
NAME MimeTreeParserWidgets
BASE_NAME KPim${KF_MAJOR_VERSION}MimeTreeParserWidgets
VERSION ${PIM_VERSION}
ORG_DOMAIN org.kde
# using only public headers, to cover only public API
SOURCES ${MimeTreeParserWidgets_HEADERS}
MD_MAINPAGE "${CMAKE_SOURCE_DIR}/README.md"
LINK_QCHS
Qt${QT_MAJOR_VERSION}Core_QCH
INCLUDE_DIRS
${CMAKE_CURRENT_BINARY_DIR}
BLANK_MACROS
MIMETREEPARSER_WIDGETS_EXPORT
TAGFILE_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR}
QCH_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR}
COMPONENT Devel
)
endif()
########### CMake Config Files ###########
set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/KPim${KF_MAJOR_VERSION}MimeTreeParserWidgets")
if (BUILD_QCH)
ecm_install_qch_export(
TARGETS KPim${KF_MAJOR_VERSION}MimeTreeParserWidgets_QCH
FILE KPim${KF_MAJOR_VERSION}MimeTreeParserWidgetsQchTargets.cmake
DESTINATION "${CMAKECONFIG_INSTALL_DIR}"
COMPONENT Devel
)
set(PACKAGE_INCLUDE_QCHTARGETS "include(\"\${CMAKE_CURRENT_LIST_DIR}/KPim${KF_MAJOR_VERSION}MimeTreeParserWidgetsQchTargets.cmake\")")
endif()
configure_package_config_file(
"${CMAKE_CURRENT_SOURCE_DIR}/KPimMimeTreeParserWidgetsConfig.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/KPim${KF_MAJOR_VERSION}MimeTreeParserWidgetsConfig.cmake"
INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR}
)
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/KPim${KF_MAJOR_VERSION}MimeTreeParserWidgetsConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/KPim${KF_MAJOR_VERSION}MimeTreeParserWidgetsConfigVersion.cmake"
DESTINATION "${CMAKECONFIG_INSTALL_DIR}"
COMPONENT Devel
)
install(EXPORT KPim${KF_MAJOR_VERSION}MimeTreeParserWidgetsTargets
DESTINATION "${CMAKECONFIG_INSTALL_DIR}"
FILE KPim${KF_MAJOR_VERSION}MimeTreeParserWidgetsTargets.cmake
NAMESPACE KPim${KF_MAJOR_VERSION}::
)
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/mimetreeparser_widgets_version.h
DESTINATION ${KDE_INSTALL_INCLUDEDIR}/KPim${KF_MAJOR_VERSION}/MimeTreeParserWidgets
COMPONENT Devel
)
+
+add_subdirectory(autotests)
diff --git a/src/widgets/autotests/CMakeLists.txt b/src/widgets/autotests/CMakeLists.txt
new file mode 100644
index 0000000..95d9c44
--- /dev/null
+++ b/src/widgets/autotests/CMakeLists.txt
@@ -0,0 +1,10 @@
+# SPDX-FileCopyrightText: 2023 g10 Code GmbH
+# SPDX-FileContributor: Carl Schwan <carlschwan@kde.org>
+# SPDX-License-Identifier: BSD-3-Clause
+
+add_definitions(-DMAIL_DATA_DIR="${CMAKE_CURRENT_SOURCE_DIR}/../../core/testdata")
+
+ecm_add_test(messageviewerdialogtest.cpp
+ LINK_LIBRARIES KPim${KF_MAJOR_VERSION}MimeTreeParserWidgets Qt::Test
+ NAME_PREFIX "widget-"
+)
diff --git a/src/widgets/autotests/messageviewerdialogtest.cpp b/src/widgets/autotests/messageviewerdialogtest.cpp
new file mode 100644
index 0000000..3202ff8
--- /dev/null
+++ b/src/widgets/autotests/messageviewerdialogtest.cpp
@@ -0,0 +1,41 @@
+// SPDX-FileCopyrightText: 2023 g10 Code GmbH
+// SPDX-FileContributor: Carl Schwan <carl@carlschwan.eu>
+// SPDX-License-Identifier: LGPL-2.0-or-later
+
+#include <MimeTreeParserWidgets/MessageViewerDialog>
+#include <QLayout>
+#include <QTest>
+
+using namespace MimeTreeParser::Widgets;
+
+class MessageViewerDialogTest : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void messageViewerDialogCreationMultipleTest()
+ {
+ MessageViewerDialog dialog(QLatin1String(MAIL_DATA_DIR) + QLatin1Char('/') + QLatin1String("combined.mbox"));
+ QCOMPARE(dialog.messages().count(), 3);
+
+ QCOMPARE(dialog.layout()->count(), 2);
+ QVERIFY(dialog.layout()->itemAt(1)->layout());
+ QCOMPARE(dialog.layout()->itemAt(1)->layout()->count(), 2);
+
+ const auto actions = dialog.layout()->menuBar()->actions();
+ QCOMPARE(actions.count(), 2);
+ }
+
+ void messageViewerDialogCreationTest()
+ {
+ MessageViewerDialog dialog(QLatin1String(MAIL_DATA_DIR) + QLatin1Char('/') + QLatin1String("plaintext.mbox"));
+ QCOMPARE(dialog.messages().count(), 1);
+
+ QCOMPARE(dialog.layout()->count(), 1); // no toolbar here
+ QVERIFY(dialog.layout()->itemAt(0)->layout());
+ QCOMPARE(dialog.layout()->itemAt(0)->layout()->count(), 2);
+ }
+};
+
+QTEST_MAIN(MessageViewerDialogTest)
+#include "messageviewerdialogtest.moc"
diff --git a/src/widgets/messageviewerdialog.cpp b/src/widgets/messageviewerdialog.cpp
index 3b2f509..12825cc 100644
--- a/src/widgets/messageviewerdialog.cpp
+++ b/src/widgets/messageviewerdialog.cpp
@@ -1,255 +1,260 @@
// SPDX-FileCopyrightText: 2023 g10 Code GmbH
// SPDX-FileContributor: Carl Schwan <carl.schwan@gnupg.com>
// SPDX-License-Identifier: GPL-2.0-or-later
#include "messageviewerdialog.h"
#include "messageviewer.h"
#include "mimetreeparser_widgets_debug.h"
#include <MimeTreeParserCore/CryptoHelper>
#include <MimeTreeParserCore/FileOpener>
#include <KLocalizedString>
#include <KMessageBox>
#include <KMessageWidget>
#include <KMime/Message>
#include <QDialogButtonBox>
#include <QFileDialog>
#include <QMenuBar>
#include <QPainter>
#include <QPrintDialog>
#include <QPrintPreviewDialog>
#include <QPrinter>
#include <QPushButton>
#include <QSaveFile>
#include <QStandardPaths>
#include <QStyle>
#include <QToolBar>
#include <QVBoxLayout>
#include <memory>
using namespace MimeTreeParser::Widgets;
class MessageViewerDialog::Private
{
public:
int currentIndex = 0;
QVector<KMime::Message::Ptr> messages;
MimeTreeParser::Widgets::MessageViewer *messageViewer = nullptr;
QAction *nextAction = nullptr;
QAction *previousAction = nullptr;
void setCurrentIndex(int currentIndex);
QMenuBar *createMenuBar(QWidget *parent);
private:
void save(QWidget *parent);
void saveDecrypted(QWidget *parent);
void print(QWidget *parent);
void printPreview(QWidget *parent);
void printInternal(QPrinter *printer);
};
void MessageViewerDialog::Private::setCurrentIndex(int index)
{
Q_ASSERT(index >= 0);
Q_ASSERT(index < messages.count());
currentIndex = index;
messageViewer->setMessage(messages[currentIndex]);
previousAction->setEnabled(currentIndex != 0);
nextAction->setEnabled(currentIndex != messages.count() - 1);
}
QMenuBar *MessageViewerDialog::Private::createMenuBar(QWidget *parent)
{
const auto menuBar = new QMenuBar(parent);
// File menu
const auto fileMenu = menuBar->addMenu(i18nc("@action:inmenu", "&File"));
const auto saveAction = new QAction(QIcon::fromTheme(QStringLiteral("document-save")), i18nc("@action:inmenu", "&Save"));
QObject::connect(saveAction, &QAction::triggered, parent, [parent, this] {
save(parent);
});
fileMenu->addAction(saveAction);
const auto saveDecryptedAction = new QAction(QIcon::fromTheme(QStringLiteral("document-save")), i18nc("@action:inmenu", "Save Decrypted"));
QObject::connect(saveDecryptedAction, &QAction::triggered, parent, [parent, this] {
saveDecrypted(parent);
});
fileMenu->addAction(saveDecryptedAction);
const auto printPreviewAction = new QAction(QIcon::fromTheme(QStringLiteral("document-print-preview")), i18nc("@action:inmenu", "Print Preview"));
QObject::connect(printPreviewAction, &QAction::triggered, parent, [parent, this] {
printPreview(parent);
});
fileMenu->addAction(printPreviewAction);
const auto printAction = new QAction(QIcon::fromTheme(QStringLiteral("document-print")), i18nc("@action:inmenu", "&Print"));
QObject::connect(printAction, &QAction::triggered, parent, [parent, this] {
print(parent);
});
fileMenu->addAction(printAction);
// Navigation menu
const auto navigationMenu = menuBar->addMenu(i18nc("@action:inmenu", "&Navigation"));
previousAction = new QAction(QIcon::fromTheme(QStringLiteral("go-previous")), i18nc("@action:button Previous email", "Previous Message"), parent);
previousAction->setEnabled(false);
navigationMenu->addAction(previousAction);
nextAction = new QAction(QIcon::fromTheme(QStringLiteral("go-next")), i18nc("@action:button Next email", "Next Message"), parent);
nextAction->setEnabled(false);
navigationMenu->addAction(nextAction);
return menuBar;
}
void MessageViewerDialog::Private::save(QWidget *parent)
{
const QString fileName = QFileDialog::getSaveFileName(parent,
i18nc("@title:window", "Save File"),
QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation),
i18nc("File dialog accepted files", "Email files (*.mbox)"));
QSaveFile file(fileName);
if (!file.open(QIODevice::WriteOnly)) {
KMessageBox::error(parent, i18n("File %1 could not be created.", fileName), i18n("Error saving message"));
return;
}
file.write(messages[currentIndex]->encodedContent());
file.commit();
}
void MessageViewerDialog::Private::saveDecrypted(QWidget *parent)
{
const QString fileName = QFileDialog::getSaveFileName(parent,
i18nc("@title:window", "Save Decrypted File"),
QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation),
i18nc("File dialog accepted files", "Email files (*.mbox)"));
QSaveFile file(fileName);
if (!file.open(QIODevice::WriteOnly)) {
KMessageBox::error(parent, i18nc("Error message", "File %1 could not be created.", fileName), i18n("Error saving message"));
return;
}
auto message = messages[currentIndex];
bool wasEncrypted = false;
auto decryptedMessage = CryptoUtils::decryptMessage(message, wasEncrypted);
if (!wasEncrypted) {
decryptedMessage = message;
}
file.write(decryptedMessage->encodedContent());
file.commit();
}
void MessageViewerDialog::Private::print(QWidget *parent)
{
QPrinter printer;
QPrintDialog dialog(&printer, parent);
dialog.setWindowTitle(i18nc("@title:window", "Print Document"));
if (dialog.exec() != QDialog::Accepted)
return;
printInternal(&printer);
}
void MessageViewerDialog::Private::printPreview(QWidget *parent)
{
auto dialog = new QPrintPreviewDialog(parent);
dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->resize(800, 750);
dialog->setWindowTitle(i18nc("@title:window", "Print Document"));
QObject::connect(dialog, &QPrintPreviewDialog::paintRequested, parent, [this](QPrinter *printer) {
printInternal(printer);
});
dialog->open();
}
void MessageViewerDialog::Private::printInternal(QPrinter *printer)
{
QPainter painter;
painter.begin(printer);
const auto pageLayout = printer->pageLayout();
const auto pageRect = pageLayout.paintRectPixels(printer->resolution());
const auto paperRect = pageLayout.fullRectPixels(printer->resolution());
const double xscale = pageRect.width() / double(messageViewer->width());
const double yscale = pageRect.height() / double(messageViewer->height());
const double scale = qMin(qMin(xscale, yscale), 1.);
painter.translate(pageRect.x(), pageRect.y());
painter.scale(scale, scale);
messageViewer->print(&painter, pageRect.width());
}
MessageViewerDialog::MessageViewerDialog(const QString &fileName, QWidget *parent)
: QDialog(parent)
, d(std::make_unique<Private>())
{
const auto mainLayout = new QVBoxLayout(this);
mainLayout->setContentsMargins({});
const auto layout = new QVBoxLayout;
layout->setContentsMargins(style()->pixelMetric(QStyle::PM_LayoutLeftMargin, nullptr, this),
style()->pixelMetric(QStyle::PM_LayoutTopMargin, nullptr, this),
style()->pixelMetric(QStyle::PM_LayoutRightMargin, nullptr, this),
style()->pixelMetric(QStyle::PM_LayoutBottomMargin, nullptr, this));
const auto menuBar = d->createMenuBar(this);
mainLayout->setMenuBar(menuBar);
d->messages += MimeTreeParser::Core::FileOpener::openFile(fileName);
if (d->messages.isEmpty()) {
auto errorMessage = new KMessageWidget(this);
errorMessage->setMessageType(KMessageWidget::Error);
errorMessage->setText(i18nc("@info", "Unable to read file"));
layout->addWidget(errorMessage);
return;
}
const bool multipleMessages = d->messages.length() > 1;
if (multipleMessages) {
const auto toolBar = new QToolBar(this);
#ifdef Q_OS_UNIX
toolBar->setToolButtonStyle(Qt::ToolButtonFollowStyle);
#else
// on other platforms the default is IconOnly which is bad for
// accessibility and can't be changed by the user.
toolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
#endif
toolBar->addAction(d->previousAction);
connect(d->previousAction, &QAction::triggered, this, [this](int index) {
d->setCurrentIndex(d->currentIndex - 1);
});
const auto spacer = new QWidget(this);
spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
toolBar->addWidget(spacer);
toolBar->addAction(d->nextAction);
connect(d->nextAction, &QAction::triggered, this, [this](int index) {
d->setCurrentIndex(d->currentIndex + 1);
});
d->nextAction->setEnabled(true);
mainLayout->addWidget(toolBar);
}
mainLayout->addLayout(layout);
d->messageViewer = new MimeTreeParser::Widgets::MessageViewer(this);
d->messageViewer->setMessage(d->messages[0]);
layout->addWidget(d->messageViewer);
auto buttonBox = new QDialogButtonBox(this);
auto closeButton = buttonBox->addButton(QDialogButtonBox::Close);
connect(closeButton, &QPushButton::pressed, this, &QDialog::accept);
layout->addWidget(buttonBox);
}
MessageViewerDialog::~MessageViewerDialog() = default;
+
+QVector<KMime::Message::Ptr> MessageViewerDialog::messages() const
+{
+ return d->messages;
+}
diff --git a/src/widgets/messageviewerdialog.h b/src/widgets/messageviewerdialog.h
index cfc2da5..b2d7075 100644
--- a/src/widgets/messageviewerdialog.h
+++ b/src/widgets/messageviewerdialog.h
@@ -1,36 +1,39 @@
// SPDX-FileCopyrightText: 2023 g10 Code GmbH
// SPDX-FileContributor: Carl Schwan <carl.schwan@gnupg.com>
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "mimetreeparser_widgets_export.h"
+#include <KMime/Message>
#include <QDialog>
#include <memory>
namespace MimeTreeParser
{
namespace Widgets
{
/// MessageViewerDialog that displays the given email stored in the
/// file.
///
/// \author Carl Schwan <carl.schwan@gnupg.com>
class MIMETREEPARSER_WIDGETS_EXPORT MessageViewerDialog : public QDialog
{
Q_OBJECT
public:
MessageViewerDialog(const QString &fileName, QWidget *parent = nullptr);
~MessageViewerDialog() override;
+ QVector<KMime::Message::Ptr> messages() const;
+
private:
class Private;
std::unique_ptr<Private> const d;
};
} // end namespace Widgets
} // end namespace MimeTreeParser

File Metadata

Mime Type
text/x-diff
Expires
Thu, Dec 4, 1:03 PM (1 d, 14 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
a8/d6/62b92cb153e57a634b562289f293

Event Timeline