[pim/trojita] src: Check that QFiles are open and dirs created

Espen Sandøy Hustad <[email protected]>
Newsgroups gmane.comp.kde.cvs
Message-ID <[email protected]>
Git commit a1f30f6ea9e93f506cfb3ee4a1f6bee73f8b8d8c by Espen Sandøy Hustad.
Committed on 03/08/2026 at 18:42.
Pushed by ehustad into branch 'master'.

Check that QFiles are open and dirs created

Add a new signal to PluginManager that signals if an error
occured during the creation of a plugin, and show a new warning
dialog box if this signal is emitted.

This allows throwing a std::runtime_exception when an error occurs on
Plugin::create, for example not being able to read a file or create a
directory.

Use this functionality to do proper error handling in the
abookaddressbook plugin, and fix the build warnings:

src/Plugins/AbookAddressbook/AbookAddressbook.cpp:194:9:
warning: ignoring return value of function declared with
'nodiscard' attribute [-Wunused-result]

src/Plugins/AbookAddressbook/AbookAddressbook.cpp:205:9:
warning: ignoring return value of function declared with
'nodiscard' attribute [-Wunused-result]

M  +11   -0    src/Gui/Window.cpp
M  +28   -5    src/Plugins/AbookAddressbook/AbookAddressbook.cpp
M  +20   -3    src/Plugins/PluginManager.cpp
M  +1    -0    src/Plugins/PluginManager.h

https://invent.kde.org/pim/trojita/-/commit/a1f30f6ea9e93f506cfb3ee4a1f6bee73f8b8d8c

diff --git a/src/Gui/Window.cpp b/src/Gui/Window.cpp
index 9a028f8c2..f0d14438a 100644
--- a/src/Gui/Window.cpp
+++ b/src/Gui/Window.cpp
@@ -137,6 +137,17 @@ MainWindow::MainWindow(QSettings *settings): QMainWindow(), m_imapAccess(nullptr
                                             "You might want to update your system or report a bug to your vendor."
                                             "\n\n%1").arg(errorMessage));
     });
+
+    connect(m_pluginManager, &Plugins::PluginManager::pluginCreateError, this, [this](const QString &name, const QString &description, const QString &errorMessage) {
+        Gui::Util::messageBoxWarning(this, tr("Plugin Error"),
+                                     //: The %1 placeholder is the name of the plugin.
+                                     //: The %2 placeholder is the human readable description of the plugin.
+                                     //: The %3 placeholder is the detailed error message, ready for human consumption.
+                                     tr("The plugin \"%1 (%2)\" failed to load, therefore some functionality might be lost. "
+                                            "\n\n%3").arg(name, description, errorMessage));
+
+    });
+
 #ifdef TROJITA_HAVE_CRYPTO_MESSAGES
     Plugins::PluginManager::MimePartReplacers replacers;
 #ifdef TROJITA_HAVE_GPGMEPP
diff --git a/src/Plugins/AbookAddressbook/AbookAddressbook.cpp b/src/Plugins/AbookAddressbook/AbookAddressbook.cpp
index d3635fccf..1ae5251c0 100644
--- a/src/Plugins/AbookAddressbook/AbookAddressbook.cpp
+++ b/src/Plugins/AbookAddressbook/AbookAddressbook.cpp
@@ -194,7 +194,11 @@ void AbookAddressbook::createAbookDir()
         return;
     }
 
-    dir.mkpath(dir.absolutePath());
+    if (!dir.mkpath(dir.absolutePath())) {
+        //: Translators: %1 is the filename of the abook dot directory
+        throw std::runtime_error(tr("Failed to create abook directory \"%1\": Do you have sufficient permissions?")
+                                    .arg(dir.absolutePath()).toStdString());
+    }
 }
 
 void AbookAddressbook::updateConfigFile() const
@@ -204,7 +208,13 @@ void AbookAddressbook::updateConfigFile() const
     if (!file.exists()) {
         abookrc << QStringLiteral("field photo = Photo") << QStringLiteral("set preserve_fields=all");
     } else {
-        file.open(QIODevice::ReadOnly|QIODevice::Text);
+        if (!file.open(QIODevice::ReadOnly|QIODevice::Text)) {
+            //: Translators: %1 is the filename of the abook config file
+            //: %2 is the detailed error description from Qt, ready for human consumption
+            throw std::runtime_error(tr("Failed to open abook configfile \"%1\" for reading: %2")
+                                        .arg(file.fileName(), file.errorString()).toStdString());
+        }
+
         abookrc = QString::fromLocal8Bit(file.readAll()).split(QStringLiteral("\n"));
 
         bool havePhoto = false;
@@ -222,15 +232,28 @@ void AbookAddressbook::updateConfigFile() const
         file.close();
     }
 
-    file.open(QIODevice::WriteOnly|QIODevice::Truncate);
+    if (!file.open(QIODevice::WriteOnly|QIODevice::Truncate)) {
+        //: Translators: %1 is the filename of the abook config file
+        //: %2 is the detailed error description from Qt, ready for human consumption
+        throw std::runtime_error(tr("Failed to open abook configfile \"%1\" for writing: %2")
+                                    .arg(file.fileName(), file.errorString()).toStdString());
+    }
     file.write(abookrc.join(QStringLiteral("\n")).toLocal8Bit());
 }
 
 void AbookAddressbook::createAbookDBFile() const
 {
     QFile abookFile(dbFileName());
-    if (!abookFile.exists()) {
-        abookFile.open(QIODevice::WriteOnly);
+    if (abookFile.exists()) {
+        return;
+    }
+
+    if (!abookFile.open(QIODevice::WriteOnly)) {
+        //: Translators: %1 is the filename of the abook database file
+        //: %2 is the detailed error description from Qt, ready for human consumption
+        throw std::runtime_error(tr("Failed to create abook database \"%1\": %2")
+                                    .arg(abookFile.fileName(), abookFile.errorString()).toStdString());
+
     }
 }
 
diff --git a/src/Plugins/PluginManager.cpp b/src/Plugins/PluginManager.cpp
index 38d2f9376..4cc8acbe0 100644
--- a/src/Plugins/PluginManager.cpp
+++ b/src/Plugins/PluginManager.cpp
@@ -227,7 +227,13 @@ void PluginManager::setAddressbookPlugin(const QString &name)
 #ifdef PLUGIN_DEBUG
         qDebug() << "Setting new address book plugin:" << (*plugin)->name();
 #endif
-        m_addressbook = (*plugin)->create(this, m_settings);
+        const QString description = (*plugin)->description();
+
+        try {
+            m_addressbook = (*plugin)->create(this, m_settings);
+        } catch (std::runtime_error &err) {
+            emit pluginCreateError(name, description, QString::fromStdString(err.what()));
+        }
     }
 
     emit pluginsChanged();
@@ -245,7 +251,13 @@ void PluginManager::setPasswordPlugin(const QString &name)
 #ifdef PLUGIN_DEBUG
         qDebug() << "Setting new password plugin:" << (*plugin)->name();
 #endif
-        m_password = (*plugin)->create(this, m_settings);
+        const QString description = (*plugin)->description();
+
+        try {
+            m_password = (*plugin)->create(this, m_settings);
+        } catch (std::runtime_error &err) {
+            emit pluginCreateError(name, description, QString::fromStdString(err.what()));
+        }
     }
 
     emit pluginsChanged();
@@ -263,7 +275,12 @@ void PluginManager::setSpellcheckerPlugin(const QString &name)
 #ifdef PLUGIN_DEBUG
         qDebug() << "Setting new spellchecker plugin:" << (*plugin)->name();
 #endif
-        m_spellchecker = (*plugin)->create(this, m_settings);
+        const QString description = (*plugin)->description();
+        try {
+            m_spellchecker = (*plugin)->create(this, m_settings);
+        } catch (std::runtime_error &err) {
+            emit pluginCreateError(name, description, QString::fromStdString(err.what()));
+        }
     }
 
     emit pluginsChanged();
diff --git a/src/Plugins/PluginManager.h b/src/Plugins/PluginManager.h
index c0a00a70d..705c92a4c 100644
--- a/src/Plugins/PluginManager.h
+++ b/src/Plugins/PluginManager.h
@@ -99,6 +99,7 @@ public:
 signals:
     void pluginsChanged();
     void pluginError(const QString &errorMessage);
+    void pluginCreateError(const QString &name, const QString &description, const QString &errorMessage);
 
 private slots:
     void loadPlugins();
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.