]> gitweb.stoutner.com Git - PrivacyBrowserPC.git/commitdiff
Add durable cookie support.
authorSoren Stoutner <soren@stoutner.com>
Thu, 26 May 2022 23:33:20 +0000 (16:33 -0700)
committerSoren Stoutner <soren@stoutner.com>
Thu, 26 May 2022 23:33:20 +0000 (16:33 -0700)
19 files changed:
src/CMakeLists.txt
src/databases/CMakeLists.txt [new file with mode: 0644]
src/databases/CookiesDatabase.cpp [new file with mode: 0644]
src/databases/CookiesDatabase.h [new file with mode: 0644]
src/databases/DomainsDatabase.cpp [new file with mode: 0644]
src/databases/DomainsDatabase.h [new file with mode: 0644]
src/dialogs/AddOrEditCookieDialog.cpp
src/dialogs/AddOrEditCookieDialog.h
src/dialogs/CookiesDialog.cpp
src/dialogs/CookiesDialog.h
src/dialogs/DomainSettingsDialog.cpp
src/helpers/CMakeLists.txt
src/helpers/DomainsDatabaseHelper.cpp [deleted file]
src/helpers/DomainsDatabaseHelper.h [deleted file]
src/main.cpp
src/uis/AddOrEditCookieDialog.ui
src/views/BrowserView.cpp
src/views/BrowserView.h
src/windows/BrowserWindow.cpp

index fb702314c31b9b49bd0efa8c8bb54197c18679d0..fd274cef043d381d981fa04f0a3966d8599a2235 100644 (file)
@@ -62,6 +62,7 @@ target_link_libraries(privacy-browser
 )
 
 # Add the subdirectories.
+add_subdirectory(databases)
 add_subdirectory(dialogs)
 add_subdirectory(filters)
 add_subdirectory(helpers)
diff --git a/src/databases/CMakeLists.txt b/src/databases/CMakeLists.txt
new file mode 100644 (file)
index 0000000..0abb936
--- /dev/null
@@ -0,0 +1,23 @@
+# Copyright © 2022 Soren Stoutner <soren@stoutner.com>.
+#
+# This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc>.
+#
+# Privacy Browser PC is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Privacy Browser PC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Privacy Browser PC.  If not, see <http://www.gnu.org/licenses/>.
+
+
+# List the sources to include in the executable.
+target_sources(privacy-browser PRIVATE
+    CookiesDatabase.cpp
+    DomainsDatabase.cpp
+)
diff --git a/src/databases/CookiesDatabase.cpp b/src/databases/CookiesDatabase.cpp
new file mode 100644 (file)
index 0000000..adc4f1b
--- /dev/null
@@ -0,0 +1,377 @@
+/*
+ * Copyright © 2022 Soren Stoutner <soren@stoutner.com>.
+ *
+ * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc>.
+ *
+ * Privacy Browser PC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Privacy Browser PC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Privacy Browser PC.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+// Application headers.
+#include "CookiesDatabase.h"
+
+// Define the private static schema constants.
+const int CookiesDatabase::SCHEMA_VERSION = 0;
+
+// Define the public static database constants.
+const QString CookiesDatabase::CONNECTION_NAME = "cookies_database";
+const QString CookiesDatabase::COOKIES_TABLE = "cookies";
+
+// Define the public static database field names.
+const QString CookiesDatabase::_ID = "_id";
+const QString CookiesDatabase::DOMAIN = "domain";
+const QString CookiesDatabase::NAME = "name";
+const QString CookiesDatabase::PATH = "path";
+const QString CookiesDatabase::EXPIRATION_DATE = "expiration_date";
+const QString CookiesDatabase::HTTP_ONLY = "http_only";
+const QString CookiesDatabase::SECURE = "secure";
+const QString CookiesDatabase::VALUE = "value";
+
+// Construct the class.
+CookiesDatabase::CookiesDatabase() {}
+
+void CookiesDatabase::addDatabase()
+{
+    // Add the cookies database.
+    QSqlDatabase cookiesDatabase = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"), CONNECTION_NAME);
+
+    // Set the database name.
+    cookiesDatabase.setDatabaseName(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/cookies.db");
+
+    // Open the database.
+    if (cookiesDatabase.open())  // Opening the database succeeded.
+    {
+        // Check to see if the cookies table already exists.
+        if (cookiesDatabase.tables().contains(COOKIES_TABLE))  // The cookies table exists.
+        {
+            // Query the database schema version.
+            QSqlQuery schemaVersionQuery = cookiesDatabase.exec(QStringLiteral("PRAGMA user_version"));
+
+            // Move to the first record.
+            schemaVersionQuery.first();
+
+            // Get the current schema versin.
+            int currentSchemaVersion = schemaVersionQuery.value(0).toInt();
+
+            // Check to see if the schema has been updated.
+            if (currentSchemaVersion < SCHEMA_VERSION)
+            {
+                // Run the schema update code.
+                switch (currentSchemaVersion)
+                {
+                    // Upgrade code here.
+                }
+
+                // Update the schema version.
+                cookiesDatabase.exec("PRAGMA user_version = " + QString::number(SCHEMA_VERSION));
+            }
+        }
+        else  // The cookies table does not exist.
+        {
+            // Instantiate a create table query.
+            QSqlQuery createTableQuery(cookiesDatabase);
+
+            // Prepare the create table query.
+            createTableQuery.prepare("CREATE TABLE " + COOKIES_TABLE + "(" +
+                _ID + " INTEGER PRIMARY KEY, " +
+                DOMAIN + " TEXT NOT NULL, " +
+                NAME + " TEXT NOT NULL, " +
+                PATH + " TEXT NOT NULL, " +
+                EXPIRATION_DATE + " TEXT, " +
+                HTTP_ONLY + " INTEGER NOT NULL DEFAULT 0, " +
+                SECURE + " INTEGER NOT NULL DEFAULT 0, " +
+                VALUE + " TEXT NOT NULL)"
+            );
+
+            // Execute the query.
+            if (!createTableQuery.exec())
+            {
+                // Log any errors.
+                qDebug().noquote().nospace() << "Error creating table:  " << cookiesDatabase.lastError();
+            }
+
+            // Set the schema version.
+            cookiesDatabase.exec("PRAGMA user_version = " + QString::number(SCHEMA_VERSION));
+        }
+    }
+    else  // Opening the database failed.
+    {
+        // Write the last database error message to the debug output.
+        qDebug().noquote().nospace() << "Error opening database:  " << cookiesDatabase.lastError();
+    }
+}
+
+void CookiesDatabase::addCookie(const QNetworkCookie &cookie)
+{
+    // Get a handle for the cookies database.
+    QSqlDatabase cookiesDatabase = QSqlDatabase::database(CONNECTION_NAME);
+
+    // Check to see if the cookie already exists in the database.
+    if (isDurable(cookie))  // The cookie already exists.
+    {
+        // Update the existing cookie.
+        updateCookie(cookie);
+    }
+    else  // The cookie doesn't already exist.
+    {
+        // Instantiate an add cookie query.
+        QSqlQuery addCookieQuery(cookiesDatabase);
+
+        // Prepare the add cookie query.
+        addCookieQuery.prepare("INSERT INTO " + COOKIES_TABLE + " (" + DOMAIN + ", " + NAME + ", " + PATH + ", " + EXPIRATION_DATE + ", " + HTTP_ONLY + ", " + SECURE + ", " + VALUE + ") "
+                            "VALUES (:domain, :name, :path, :expiration_date, :http_only, :secure, :value)"
+        );
+
+        // Bind the values.
+        addCookieQuery.bindValue(":domain", cookie.domain());
+        addCookieQuery.bindValue(":name", QString(cookie.name()));
+        addCookieQuery.bindValue(":path", cookie.path());
+        addCookieQuery.bindValue(":expiration_date", cookie.expirationDate());
+        addCookieQuery.bindValue(":http_only", cookie.isHttpOnly());
+        addCookieQuery.bindValue(":secure", cookie.isSecure());
+        addCookieQuery.bindValue(":value", QString(cookie.value()));
+
+        // Execute the query.
+        addCookieQuery.exec();
+    }
+}
+
+void CookiesDatabase::deleteAllCookies()
+{
+    // Get a handle for the cookies database.
+    QSqlDatabase cookiesDatabase = QSqlDatabase::database(CONNECTION_NAME);
+
+    // Instantiate a delete all cookies query.
+    QSqlQuery deleteAllCookiesQuery(cookiesDatabase);
+
+    // Prepare the delete all cookies query.
+    deleteAllCookiesQuery.prepare("DELETE FROM " + COOKIES_TABLE);
+
+    // Execute the query.
+    deleteAllCookiesQuery.exec();
+}
+
+void CookiesDatabase::deleteCookie(const QNetworkCookie &cookie)
+{
+    // Get a handle for the cookies database.
+    QSqlDatabase cookiesDatabase = QSqlDatabase::database(CONNECTION_NAME);
+
+    // Instantiate a delete cookie query.
+    QSqlQuery deleteCookieQuery(cookiesDatabase);
+
+    // Prepare the delete cookie query.
+    deleteCookieQuery.prepare("DELETE FROM " + COOKIES_TABLE + " WHERE " + DOMAIN + " = :domain AND " + NAME + " = :name AND " + PATH + " = :path");
+
+    // Bind the values.
+    deleteCookieQuery.bindValue(":domain", cookie.domain());
+    deleteCookieQuery.bindValue(":name", QString(cookie.name()));
+    deleteCookieQuery.bindValue(":path", cookie.path());
+
+    // Execute the query.
+    deleteCookieQuery.exec();
+}
+
+QList<QNetworkCookie*>* CookiesDatabase::getCookies()
+{
+    // Get a handle for the cookies database.
+    QSqlDatabase cookiesDatabase = QSqlDatabase::database(CONNECTION_NAME);
+
+    // Instantiate a cookies query.
+    QSqlQuery cookiesQuery(cookiesDatabase);
+
+    // Set the query to be forward only.
+    cookiesQuery.setForwardOnly(true);
+
+    // Prepare the cookies query.
+    cookiesQuery.prepare("SELECT * FROM " + COOKIES_TABLE);
+
+    // Execute the query.
+    cookiesQuery.exec();
+
+    // Create a cookie list.
+    QList<QNetworkCookie*> *cookieListPointer = new QList<QNetworkCookie*>;
+
+    // Populate the cookie list.
+    while (cookiesQuery.next())
+    {
+        // Create a cookie.
+        QNetworkCookie *cookiePointer = new QNetworkCookie();
+
+        // Populate the cookie.
+        cookiePointer->setDomain(cookiesQuery.value(DOMAIN).toString());
+        cookiePointer->setName(cookiesQuery.value(NAME).toString().toUtf8());
+        cookiePointer->setPath(cookiesQuery.value(PATH).toString());
+        cookiePointer->setExpirationDate(QDateTime::fromString(cookiesQuery.value(EXPIRATION_DATE).toString(), Qt::ISODate));
+        cookiePointer->setHttpOnly(cookiesQuery.value(HTTP_ONLY).toBool());
+        cookiePointer->setSecure(cookiesQuery.value(SECURE).toBool());
+        cookiePointer->setValue(cookiesQuery.value(VALUE).toString().toUtf8());
+
+        // Add the cookie to the list.
+        cookieListPointer->append(cookiePointer);
+    }
+
+    // Return the cookie list.
+    return cookieListPointer;
+}
+
+bool CookiesDatabase::isDurable(const QNetworkCookie &cookie)
+{
+    // Get a handle for the cookies database.
+    QSqlDatabase cookiesDatabase = QSqlDatabase::database(CONNECTION_NAME);
+
+    // Instantiate an is durable query.
+    QSqlQuery isDurableQuery(cookiesDatabase);
+
+    // Set the query to be forward only.
+    isDurableQuery.setForwardOnly(true);
+
+    // Prepare the is durable query.
+    isDurableQuery.prepare("SELECT " + _ID + " FROM " + COOKIES_TABLE + " WHERE " + DOMAIN + " = :domain AND " + NAME + " = :name AND " + PATH + " = :path");
+
+    // Bind the values.
+    isDurableQuery.bindValue(":domain", cookie.domain());
+    isDurableQuery.bindValue(":name", QString(cookie.name()));
+    isDurableQuery.bindValue(":path", cookie.path());
+
+    // Execute the query.
+    isDurableQuery.exec();
+
+    // Move to the first entry.
+    isDurableQuery.first();
+
+    // Return the status of the cookie in the database.
+    return (isDurableQuery.isValid());
+}
+
+bool CookiesDatabase::isUpdate(const QNetworkCookie &cookie)
+{
+    // Get a handle for the cookies database.
+    QSqlDatabase cookiesDatabase = QSqlDatabase::database(CONNECTION_NAME);
+
+    // Instantiate an is update query.
+    QSqlQuery isUpdateQuery(cookiesDatabase);
+
+    // Prepare the is update query.
+    isUpdateQuery.prepare("SELECT " + EXPIRATION_DATE + " , " + HTTP_ONLY + " , " + SECURE + " , " + VALUE + " FROM " + COOKIES_TABLE + " WHERE " + DOMAIN + " = :domain AND " +
+                          NAME + " = :name AND " + PATH + " = :path");
+
+    // Bind the values.
+    isUpdateQuery.bindValue(":domain", cookie.domain());
+    isUpdateQuery.bindValue(":name", QString(cookie.name()));
+    isUpdateQuery.bindValue(":path", cookie.path());
+
+    // Execute the query.
+    isUpdateQuery.exec();
+
+    // Move to the first entry.
+    isUpdateQuery.first();
+
+    // Check to see if the cookie exists.
+    if (isUpdateQuery.isValid())  // The cookie exists in the database.
+    {
+        // Check to see if the cookie data has changed.
+        if ((QDateTime::fromString(isUpdateQuery.value(0).toString(), Qt::ISODate) != cookie.expirationDate()) ||
+            (isUpdateQuery.value(1).toBool() != cookie.isHttpOnly()) ||
+            (isUpdateQuery.value(2).toBool() != cookie.isSecure()) ||
+            (isUpdateQuery.value(3).toString().toUtf8() != cookie.value()))  // The cookies data has changed.
+        {
+            qDebug() << "The durable cookie data has changed.";
+
+            // Return true.
+            return true;
+        }
+        else  // The cookie data has not changed.
+        {
+            qDebug() << "The durable cookie data is unchanged.";
+
+            // Return false.
+            return false;
+        }
+    }
+    else  // The cookie does not exist in the database.
+    {
+        // Return false.
+        return false;
+    }
+}
+
+void CookiesDatabase::updateCookie(const QNetworkCookie &cookie)
+{
+    // Get a handle for the cookies database.
+    QSqlDatabase cookiesDatabase = QSqlDatabase::database(CONNECTION_NAME);
+
+    // Create the update cookie query.
+    QSqlQuery updateCookieQuery(cookiesDatabase);
+
+    // Prepare the edit cookie query.
+    updateCookieQuery.prepare("UPDATE " + COOKIES_TABLE + " SET " + EXPIRATION_DATE + " = :expiration_date , " + HTTP_ONLY + " = :http_only , " + SECURE + " = :secure , " +
+                              VALUE + " = :value WHERE " + DOMAIN + " = :domain AND " + NAME + " = :name AND " + PATH + " = :path");
+
+    // Bind the values.
+    updateCookieQuery.bindValue(":domain", cookie.domain());
+    updateCookieQuery.bindValue(":name", QString(cookie.name()));
+    updateCookieQuery.bindValue(":path", cookie.path());
+    updateCookieQuery.bindValue(":expiration_date", cookie.expirationDate());
+    updateCookieQuery.bindValue(":http_only", cookie.isHttpOnly());
+    updateCookieQuery.bindValue(":secure", cookie.isSecure());
+    updateCookieQuery.bindValue(":value", QString(cookie.value()));
+
+    // Execute the query.
+    updateCookieQuery.exec();
+}
+
+void CookiesDatabase::updateCookie(const QNetworkCookie &oldCookie, const QNetworkCookie &newCookie)
+{
+    // Get a handle for the cookies database.
+    QSqlDatabase cookiesDatabase = QSqlDatabase::database(CONNECTION_NAME);
+
+    // Create the old cookie query.
+    QSqlQuery oldCookieQuery(cookiesDatabase);
+
+    // Set the query to be forward only.
+    oldCookieQuery.setForwardOnly(true);
+
+    // Prepare the old cookie query.
+    oldCookieQuery.prepare("SELECT " + _ID + " FROM " + COOKIES_TABLE + " WHERE " + DOMAIN + " = :domain AND " + NAME + " = :name AND " + PATH + " = :path");
+
+    // Bind the values.
+    oldCookieQuery.bindValue(":domain", oldCookie.domain());
+    oldCookieQuery.bindValue(":name", QString(oldCookie.name()));
+    oldCookieQuery.bindValue(":path", oldCookie.path());
+
+    // Execute the query.
+    oldCookieQuery.exec();
+
+    // Move to the first entry.
+    oldCookieQuery.first();
+
+    // Create the update cookie query.
+    QSqlQuery updateCookieQuery(cookiesDatabase);
+
+    // Prepare the update cookie query.
+    updateCookieQuery.prepare("UPDATE " + COOKIES_TABLE + " SET " + DOMAIN + " = :domain , " + NAME + " = :name , " + PATH + " = :path , " + EXPIRATION_DATE + " = :expiration_date , " +
+                              HTTP_ONLY + " = :http_only , " + SECURE + " = :secure , " + VALUE + " = :value WHERE " + _ID + " = :id");
+
+    // Bind the values.
+    updateCookieQuery.bindValue(":id", oldCookieQuery.value(0).toLongLong());
+    updateCookieQuery.bindValue(":domain", newCookie.domain());
+    updateCookieQuery.bindValue(":name", QString(newCookie.name()));
+    updateCookieQuery.bindValue(":path", newCookie.path());
+    updateCookieQuery.bindValue(":expiration_date", newCookie.expirationDate());
+    updateCookieQuery.bindValue(":http_only", newCookie.isHttpOnly());
+    updateCookieQuery.bindValue(":secure", newCookie.isSecure());
+    updateCookieQuery.bindValue(":value", QString(newCookie.value()));
+
+    // Execute the query.
+    updateCookieQuery.exec();
+}
diff --git a/src/databases/CookiesDatabase.h b/src/databases/CookiesDatabase.h
new file mode 100644 (file)
index 0000000..6fcae89
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright © 2022 Soren Stoutner <soren@stoutner.com>.
+ *
+ * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc>.
+ *
+ * Privacy Browser PC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Privacy Browser PC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Privacy Browser PC.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef COOKIESDATABASE_H
+#define COOKIESDATABASE_H
+
+// Qt framework headers.
+#include <QNetworkCookie>
+#include <QtSql>
+
+class CookiesDatabase
+{
+public:
+    // The default constructor.
+    CookiesDatabase();
+
+    // The public functions.
+    static void addDatabase();
+    static void addCookie(const QNetworkCookie &cookie);
+    static void deleteAllCookies();
+    static void deleteCookie(const QNetworkCookie &cookie);
+    static QList<QNetworkCookie*>* getCookies();
+    static bool isDurable(const QNetworkCookie &cookie);
+    static bool isUpdate(const QNetworkCookie &cookie);
+    static void updateCookie(const QNetworkCookie &cookie);
+    static void updateCookie(const QNetworkCookie &oldCookie, const QNetworkCookie &newCookie);
+
+    // The public constants.
+    static const QString _ID;
+    static const QString CONNECTION_NAME;
+    static const QString COOKIES_TABLE;
+    static const QString DOMAIN;
+    static const QString EXPIRATION_DATE;
+    static const QString HTTP_ONLY;
+    static const QString NAME;
+    static const QString PATH;
+    static const QString SECURE;
+    static const QString VALUE;
+
+private:
+    // The private static constants.
+    static const int SCHEMA_VERSION;
+};
+#endif
diff --git a/src/databases/DomainsDatabase.cpp b/src/databases/DomainsDatabase.cpp
new file mode 100644 (file)
index 0000000..6dfc1bd
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ * Copyright © 2022 Soren Stoutner <soren@stoutner.com>.
+ *
+ * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc>.
+ *
+ * Privacy Browser PC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Privacy Browser PC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Privacy Browser PC.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+// Application headers.
+#include "DomainsDatabase.h"
+#include "helpers/UserAgentHelper.h"
+
+// Define the private static schema constants.
+const int DomainsDatabase::SCHEMA_VERSION = 5;
+
+// Define the public static database constants.
+const QString DomainsDatabase::CONNECTION_NAME = "domains_database";
+const QString DomainsDatabase::DOMAINS_TABLE = "domains";
+
+// Define the public static database field names.
+const QString DomainsDatabase::_ID = "_id";
+const QString DomainsDatabase::DOMAIN_NAME = "domain_name";
+const QString DomainsDatabase::JAVASCRIPT = "javascript";
+const QString DomainsDatabase::LOCAL_STORAGE = "local_storage";
+const QString DomainsDatabase::DOM_STORAGE = "dom_storage";
+const QString DomainsDatabase::USER_AGENT = "user_agent";
+const QString DomainsDatabase::ZOOM_FACTOR = "zoom_factor";
+const QString DomainsDatabase::CUSTOM_ZOOM_FACTOR = "custom_zoom_factor";
+
+// Construct the class.
+DomainsDatabase::DomainsDatabase() {}
+
+void DomainsDatabase::addDatabase()
+{
+    // Add the domain settings database.
+    QSqlDatabase domainsDatabase = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"), CONNECTION_NAME);
+
+    // Set the database name.
+    domainsDatabase.setDatabaseName(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/domains.db");
+
+    // Open the database.
+    if (domainsDatabase.open())  // Opening the database succeeded.
+    {
+        // Check to see if the domains table already exists.
+        if (domainsDatabase.tables().contains(DOMAINS_TABLE))  // The domains table already exists.
+        {
+            // Query the database schema version.
+            QSqlQuery schemaVersionQuery = domainsDatabase.exec(QStringLiteral("PRAGMA user_version"));
+
+            // Move to the first record.
+            schemaVersionQuery.first();
+
+            // Get the current schema version.
+            int currentSchemaVersion = schemaVersionQuery.value(0).toInt();
+
+            // Check to see if the schema has been updated.
+            if (currentSchemaVersion < SCHEMA_VERSION)
+            {
+                // Run the schema update code.
+                switch (currentSchemaVersion)
+                {
+                    // Upgrade from schema version 0 to schema version 1.
+                    case 0:
+                    {
+                        // Add the JavaScript column.
+                        domainsDatabase.exec("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + JAVASCRIPT + " INTEGER DEFAULT 0");
+
+                        // Fallthrough to the next case.
+                        [[fallthrough]];
+                    }
+
+                    // Upgrade from schema version 1 to schema version 2.
+                    case 1:
+                    {
+                        // Add the User Agent column.
+                        domainsDatabase.exec("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + USER_AGENT + " TEXT DEFAULT '" + UserAgentHelper::SYSTEM_DEFAULT_DATABASE + "'");
+
+                        // Fallthrough to the next case.
+                        [[fallthrough]];
+                    }
+
+                    // Upgrade from schema version 2 to schema version 3.
+                    case 2:
+                    {
+                        // Add the Zoom Factor columns.
+                        domainsDatabase.exec("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + ZOOM_FACTOR + " INTEGER DEFAULT 0");
+                        domainsDatabase.exec("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + CUSTOM_ZOOM_FACTOR + " REAL DEFAULT 1.0");
+
+                        // Fallthrough to the next case.
+                        [[fallthrough]];
+                    }
+
+                    // Upgrade from schema version 3 to schema version 4.
+                    case 3:
+                    {
+                        // Add the DOM Storage column.
+                        domainsDatabase.exec("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + DOM_STORAGE + " INTEGER DEFAULT 0");
+
+                        // Fallthrough to the next case.
+                        [[fallthrough]];
+                    }
+
+                    // Upgrade from schema version 4 to schema version 5.
+                    case 4:
+                    {
+                        // Add the Local Storage column.
+                        domainsDatabase.exec("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + LOCAL_STORAGE + " INTEGER DEFAULT 0");
+
+                        // Fallthrough to the next case.
+                        // [[fallthrough]];
+                    }
+                }
+
+                // Update the schema version.
+                domainsDatabase.exec("PRAGMA user_version = " + QString::number(SCHEMA_VERSION));
+            }
+        }
+        else  // The domains table does not exist.
+        {
+            // Instantiate a create table query.
+            QSqlQuery createTableQuery(domainsDatabase);
+
+            // Prepare the create table query.
+            createTableQuery.prepare("CREATE TABLE " + DOMAINS_TABLE + "(" +
+                _ID + " INTEGER PRIMARY KEY, " +
+                DOMAIN_NAME + " TEXT, " +
+                JAVASCRIPT + " INTEGER DEFAULT 0, " +
+                LOCAL_STORAGE + " INTEGER DEFAULT 0, " +
+                DOM_STORAGE + " INTEGER DEFAULT 0, " +
+                USER_AGENT + " TEXT DEFAULT '" + UserAgentHelper::SYSTEM_DEFAULT_DATABASE + "', " +
+                ZOOM_FACTOR + " INTEGER DEFAULT 0, " +
+                CUSTOM_ZOOM_FACTOR + " REAL DEFAULT 1.0)"
+            );
+
+            // Execute the query.
+            if (!createTableQuery.exec())
+            {
+                // Log any errors.
+                qDebug().noquote().nospace() << "Error creating table:  " << domainsDatabase.lastError();
+            }
+
+            // Set the schema version.
+            domainsDatabase.exec("PRAGMA user_version = " + QString::number(SCHEMA_VERSION));
+        }
+    }
+    else  // Opening the database failed.
+    {
+        // Write the last database error message to the debug output.
+        qDebug().noquote().nospace() << "Error opening database:  " << domainsDatabase.lastError();
+    }
+};
+
+QSqlQuery DomainsDatabase::getDomainQuery(const QString &hostname)
+{
+    // Get a handle for the domains database.
+    QSqlDatabase domainsDatabase = QSqlDatabase::database(CONNECTION_NAME);
+
+    // Instantiate the all domain names query.
+    QSqlQuery allDomainNamesQuery(domainsDatabase);
+
+    // Set the query to be forward only (increases performance while iterating over the query).
+    allDomainNamesQuery.setForwardOnly(true);
+
+    // Prepare the query.
+    allDomainNamesQuery.prepare("SELECT " + _ID + "," + DOMAIN_NAME + " FROM " + DOMAINS_TABLE);
+
+    // Execute the query.
+    allDomainNamesQuery.exec();
+
+    // Create a domains settings map.
+    QMap<QString, int> domainSettingsMap;
+
+    // Populate the domain settings map.
+    while (allDomainNamesQuery.next())
+    {
+        // Add the domain name and database ID to the map.
+        domainSettingsMap.insert(allDomainNamesQuery.record().field(DOMAIN_NAME).value().toString(), allDomainNamesQuery.record().field(_ID).value().toInt());
+    }
+
+    // Initialize the database ID tracker.
+    int databaseId = -1;
+
+    // Get the database ID if the hostname is found in the domain settings set.
+    if (domainSettingsMap.contains(hostname))
+    {
+        databaseId = domainSettingsMap.value(hostname);
+    }
+
+    // Create a subdomain string.
+    QString subdomain = hostname;
+
+    // Check all the subdomains of the hostname.
+    while ((databaseId == -1) && subdomain.contains("."))  // Stop checking when a match is found or there are no more `.` in the hostname.
+    {
+        // Check to see if the domain settings map contains the subdomain with a `*.` prepended.
+        if (domainSettingsMap.contains("*." + subdomain))
+        {
+            // Get the database ID.
+            databaseId = domainSettingsMap.value("*." + subdomain);
+        }
+
+        // Strip out the first subdomain.
+        subdomain = subdomain.section('.', 1);
+    }
+
+    // Instantiate the domain lookup query.
+    QSqlQuery domainLookupQuery(domainsDatabase);
+
+    // Prepare the domain lookup query.
+    domainLookupQuery.prepare("SELECT * FROM " + DOMAINS_TABLE + " WHERE " + _ID + " = " + QString::number(databaseId));
+
+    // Execute the query.
+    domainLookupQuery.exec();
+
+    // Move to the first entry.
+    domainLookupQuery.first();
+
+    // Return the query.
+    return domainLookupQuery;
+}
diff --git a/src/databases/DomainsDatabase.h b/src/databases/DomainsDatabase.h
new file mode 100644 (file)
index 0000000..a75b831
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright © 2022 Soren Stoutner <soren@stoutner.com>.
+ *
+ * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc>.
+ *
+ * Privacy Browser PC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Privacy Browser PC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Privacy Browser PC.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef DOMAINSDATABASE_H
+#define DOMAINSDATABASE_H
+
+// Qt framework headers.
+#include <QtSql>
+
+class DomainsDatabase
+{
+public:
+    // The default constructor.
+    DomainsDatabase();
+
+    // The public functions.
+    static void addDatabase();
+    static QSqlQuery getDomainQuery(const QString &hostname);
+
+    // The public int constants.
+    static const int SYSTEM_DEFAULT = 0;
+    static const int DISABLED = 1;
+    static const int ENABLED = 2;
+    static const int CUSTOM = 1;
+
+    // The public constants.
+    static const QString _ID;
+    static const QString CONNECTION_NAME;
+    static const QString CUSTOM_ZOOM_FACTOR;
+    static const QString DOM_STORAGE;
+    static const QString DOMAIN_NAME;
+    static const QString DOMAINS_TABLE;
+    static const QString JAVASCRIPT;
+    static const QString LOCAL_STORAGE;
+    static const QString USER_AGENT;
+    static const QString ZOOM_FACTOR;
+
+private:
+    // The private static constants.
+    static const int SCHEMA_VERSION;
+};
+#endif
index 78234a68b1119e29908cb8f6b48e41ff774b46d8..e39303e8e7094230d63cf6db49615fcb0686e8d5 100644 (file)
@@ -20,6 +20,7 @@
 // Application headers.
 #include "AddOrEditCookieDialog.h"
 #include "ui_AddOrEditCookieDialog.h"
+#include "databases/CookiesDatabase.h"
 
 // KDE Framework headers.
 #include <KLocalizedString>
@@ -33,7 +34,7 @@ const int AddOrEditCookieDialog::AddCookie = 0;
 const int AddOrEditCookieDialog::EditCookie = 1;
 
 // Construct the class.
-AddOrEditCookieDialog::AddOrEditCookieDialog(const int &dialogType, const QNetworkCookie *cookiePointer) : QDialog(nullptr)
+AddOrEditCookieDialog::AddOrEditCookieDialog(const int &dialogType, const QNetworkCookie *cookiePointer, const bool &isDurable) : QDialog(nullptr)
 {
     // Set the dialog window title according to the dialog type.
     if (dialogType == AddCookie)
@@ -41,8 +42,9 @@ AddOrEditCookieDialog::AddOrEditCookieDialog(const int &dialogType, const QNetwo
     else
         setWindowTitle(i18nc("The edit cookie dialog window title.", "Edit Cookie"));
 
-    // Populate the is edit dialog boolean.
+    // Populate the class variables.
     isEditDialog = (dialogType == EditCookie);
+    originalIsDurable = isDurable;
 
     // Set the window modality.
     setWindowModality(Qt::WindowModality::ApplicationModal);
@@ -56,6 +58,7 @@ AddOrEditCookieDialog::AddOrEditCookieDialog(const int &dialogType, const QNetwo
     // Get handles for the widgets.
     domainLineEditPointer = addOrEditCookieDialogUi.domainLineEdit;
     nameLineEditPointer = addOrEditCookieDialogUi.nameLineEdit;
+    durableCheckBoxPointer = addOrEditCookieDialogUi.durableCheckBox;
     expirationCheckBoxPointer = addOrEditCookieDialogUi.expirationCheckBox;
     expirationDateTimeEditPointer = addOrEditCookieDialogUi.expirationDateTimeEdit;
     pathLineEditPointer = addOrEditCookieDialogUi.pathLineEdit;
@@ -69,18 +72,19 @@ AddOrEditCookieDialog::AddOrEditCookieDialog(const int &dialogType, const QNetwo
     if (isEditDialog)
     {
         // Store the old cookie.
-        oldCookie = *cookiePointer;
+        originalCookie = *cookiePointer;
 
         // Populate the widgets.
-        domainLineEditPointer->setText(oldCookie.domain());
-        nameLineEditPointer->setText(oldCookie.name());
-        pathLineEditPointer->setText(oldCookie.path());
-        httpOnlyCheckBoxPointer->setChecked(oldCookie.isHttpOnly());
-        secureCheckBoxPointer->setChecked(oldCookie.isSecure());
-        valueLineEditPointer->setText(oldCookie.value());
+        domainLineEditPointer->setText(originalCookie.domain());
+        durableCheckBoxPointer->setChecked(originalIsDurable);
+        nameLineEditPointer->setText(originalCookie.name());
+        pathLineEditPointer->setText(originalCookie.path());
+        httpOnlyCheckBoxPointer->setChecked(originalCookie.isHttpOnly());
+        secureCheckBoxPointer->setChecked(originalCookie.isSecure());
+        valueLineEditPointer->setText(originalCookie.value());
 
         // Populate the expiration date if it exists.
-        if (!oldCookie.isSessionCookie())
+        if (!originalCookie.isSessionCookie())
         {
             // Check the expiration box.
             expirationCheckBoxPointer->setChecked(true);
@@ -89,7 +93,7 @@ AddOrEditCookieDialog::AddOrEditCookieDialog(const int &dialogType, const QNetwo
             expirationDateTimeEditPointer->setEnabled(true);
 
             // Set the expiration date.
-            expirationDateTimeEditPointer->setDateTime(oldCookie.expirationDate());
+            expirationDateTimeEditPointer->setDateTime(originalCookie.expirationDate());
         }
     }
 
@@ -114,13 +118,13 @@ void AddOrEditCookieDialog::saveCookie()
 {
     // Delete the old cookie if this is an edit dialog.
     if (isEditDialog)
-        emit deleteCookie(oldCookie);
+        emit deleteCookie(originalCookie);
 
     // Create the variables.
     QNetworkCookie cookie;
 
     // Populate the cookie.
-    cookie.setDomain(domainLineEditPointer->text());
+    cookie.setDomain(domainLineEditPointer->text().toLower());
     cookie.setName(nameLineEditPointer->text().toUtf8());
     cookie.setPath(pathLineEditPointer->text());
     cookie.setHttpOnly(httpOnlyCheckBoxPointer->isChecked());
@@ -130,8 +134,37 @@ void AddOrEditCookieDialog::saveCookie()
     // Populate the expiration date if it is specified.
     if (expirationCheckBoxPointer->isChecked()) cookie.setExpirationDate(expirationDateTimeEditPointer->dateTime());
 
-    // Add the cookie.
-    emit addCookie(cookie);
+    // Get the durable status.
+    const bool isDurable = durableCheckBoxPointer->isChecked();
+
+    // Update the durable cookies database.
+    if (originalIsDurable)  // The cookie is currently in the durable cookies database.
+    {
+        if (isDurable)  // Update the cookie in the database.
+        {
+            qDebug() << "Updating a durable cookie.";
+
+            // Update the cookie in the durable cookies database.
+            CookiesDatabase::updateCookie(originalCookie, cookie);
+        }
+        else  // Delete the cookie from the database.
+        {
+            qDebug() << "Deleting a durable cookie.";
+
+            // Delete the cookie from the durable cookies database.
+            CookiesDatabase::deleteCookie(originalCookie);
+        }
+    }
+    else if (isDurable)  // The cookie is being added to the durable cookies database.
+    {
+        qDebug() << "Adding a durable cookie.";
+
+        // Add the cookie to the durable cookies database.
+        CookiesDatabase::addCookie(cookie);
+    }
+
+    // Add the cookie to the store, the list, and the tree.
+    emit addCookie(cookie, isDurable);
 
     // Close the dialog.
     reject();
index 5bc763f6e5a2b6dc9f87bf28ec47a2388954185d..d00e3f7596d06169420df8240a1baacb18f190fc 100644 (file)
@@ -33,7 +33,7 @@ class AddOrEditCookieDialog : public QDialog
 
 public:
     // The primary constructor.
-    explicit AddOrEditCookieDialog(const int &dialogType, const QNetworkCookie *cookiePointer = nullptr);
+    explicit AddOrEditCookieDialog(const int &dialogType, const QNetworkCookie *cookiePointer = nullptr, const bool &isDurable = false);
 
     // The public static constants.
     static const int AddCookie;
@@ -41,7 +41,7 @@ public:
 
 signals:
     // The signals.
-    void addCookie(const QNetworkCookie &cookie) const;
+    void addCookie(const QNetworkCookie &cookie, const bool &isDurable) const;
     void deleteCookie(const QNetworkCookie &cookie) const;
 
 private Q_SLOTS:
@@ -53,6 +53,7 @@ private Q_SLOTS:
 private:
     // The private widgets.
     QLineEdit *domainLineEditPointer;
+    QCheckBox *durableCheckBoxPointer;
     QCheckBox *expirationCheckBoxPointer;
     QDateTimeEdit *expirationDateTimeEditPointer;
     QCheckBox *httpOnlyCheckBoxPointer;
@@ -63,7 +64,8 @@ private:
     QLineEdit *valueLineEditPointer;
 
     // The private variables.
-    QNetworkCookie oldCookie;
     bool isEditDialog;
+    QNetworkCookie originalCookie;
+    bool originalIsDurable;
 };
 #endif
index b200891566a8ef8def175108394de306e1cda854..fa9679c457a4b4e58e906457cd367ca2ed577c30 100644 (file)
@@ -21,6 +21,7 @@
 #include "AddOrEditCookieDialog.h"
 #include "CookiesDialog.h"
 #include "ui_CookiesDialog.h"
+#include "databases/CookiesDatabase.h"
 
 // KDE Frameworks headers.
 #include <KLocalizedString>
@@ -117,30 +118,33 @@ CookiesDialog::CookiesDialog(std::list<QNetworkCookie> *originalCookieListPointe
     // Get a handle for the tree view.
     treeViewPointer = cookiesDialogUi.treeView;
 
-    // Initialize the standard item model.
-    standardItemModelPointer = new QStandardItemModel();
+    // Initialize the tree model.
+    treeModelPointer = new QStandardItemModel();
 
     // Set the column count.
-    standardItemModelPointer->setColumnCount(6);
-
-    // Set the header data.
-    standardItemModelPointer->setHeaderData(0, Qt::Horizontal, i18nc("The cookie Name header.", "Name"));
-    standardItemModelPointer->setHeaderData(1, Qt::Horizontal, i18nc("The cookie Path header.", "Path"));
-    standardItemModelPointer->setHeaderData(2, Qt::Horizontal, i18nc("The cookie Expiration Date header.", "Expiration Date"));
-    standardItemModelPointer->setHeaderData(3, Qt::Horizontal, i18nc("The cookie HTTP Only header.", "HTTP Only"));
-    standardItemModelPointer->setHeaderData(4, Qt::Horizontal, i18nc("The cookie Secure header.", "Secure"));
-    standardItemModelPointer->setHeaderData(5, Qt::Horizontal, i18nc("The cookie Value header.", "Value"));
-
-    // Set the header tool tips.
-    standardItemModelPointer->horizontalHeaderItem(0)->setToolTip(i18nc("The cookie Name tool tip.",
+    treeModelPointer->setColumnCount(7);
+
+    // Set the tree header data.
+    treeModelPointer->setHeaderData(0, Qt::Horizontal, i18nc("The cookie Name header.", "Name"));
+    treeModelPointer->setHeaderData(1, Qt::Horizontal, i18nc("The cookie Durable header.", "Durable"));
+    treeModelPointer->setHeaderData(2, Qt::Horizontal, i18nc("The cookie Path header.", "Path"));
+    treeModelPointer->setHeaderData(3, Qt::Horizontal, i18nc("The cookie Expiration Date header.", "Expiration Date"));
+    treeModelPointer->setHeaderData(4, Qt::Horizontal, i18nc("The cookie HTTP Only header.", "HTTP Only"));
+    treeModelPointer->setHeaderData(5, Qt::Horizontal, i18nc("The cookie Secure header.", "Secure"));
+    treeModelPointer->setHeaderData(6, Qt::Horizontal, i18nc("The cookie Value header.", "Value"));
+
+    // Set the tree header tool tips.
+    treeModelPointer->horizontalHeaderItem(0)->setToolTip(i18nc("The cookie Name tool tip.",
                                                                         "The name identifies the cookie.  Each cookie has a unique combination of domain, name, and path."));
-    standardItemModelPointer->horizontalHeaderItem(1)->setToolTip(i18nc("The cookie Path tool tip.", "Websites can restrict cookie access to subpath of their URL."));
-    standardItemModelPointer->horizontalHeaderItem(2)->setToolTip(i18nc("The cookie Expiration Date tool tip.",
+    treeModelPointer->horizontalHeaderItem(1)->setToolTip(i18nc("The cookie Durable tool tip",
+                                                                        "Durable cookies pursist across restarts, irrespective of the expiration date. All other cookies are deleted when Privacy Browser closes, irrespective of the expiration date."));
+    treeModelPointer->horizontalHeaderItem(2)->setToolTip(i18nc("The cookie Path tool tip.", "Websites can restrict cookie access to subpath of their URL."));
+    treeModelPointer->horizontalHeaderItem(3)->setToolTip(i18nc("The cookie Expiration Date tool tip.",
                                                                         "Cookies without an expiration date are known as session cookies and are expected to be deleted every time the browser closes."));
-    standardItemModelPointer->horizontalHeaderItem(3)->setToolTip(i18nc("The cookie HTTP Only tool tip.",
+    treeModelPointer->horizontalHeaderItem(4)->setToolTip(i18nc("The cookie HTTP Only tool tip.",
                                                                         "Restrict cookie access to HTTP (and HTTPS). This prevents JavaScript from accessing the cookie, which hardens it against cross-site scripting attacks."));
-    standardItemModelPointer->horizontalHeaderItem(4)->setToolTip(i18nc("The cookie Secure tool tip.", "Only allow the cookie to be transferred across HTTPS (as opposed to HTTP)."));
-    standardItemModelPointer->horizontalHeaderItem(5)->setToolTip(i18nc("The cookie Value tool tip.", "The value contains the cookie data."));
+    treeModelPointer->horizontalHeaderItem(5)->setToolTip(i18nc("The cookie Secure tool tip.", "Only allow the cookie to be transferred across HTTPS (as opposed to HTTP)."));
+    treeModelPointer->horizontalHeaderItem(6)->setToolTip(i18nc("The cookie Value tool tip.", "The value contains the cookie data."));
 
     // Sort the cookie list.
     cookieListPointer->sort(cookieSortPredicate);
@@ -148,10 +152,10 @@ CookiesDialog::CookiesDialog(std::list<QNetworkCookie> *originalCookieListPointe
     // Create the current domain string.
     QString currentDomainString = "";
 
-    // Create the current domain standard item pointer.
-    QStandardItem *currentDomainStandardItemPointer;
+    // Create the current domain item pointer.
+    QStandardItem *currentDomainItemPointer;
 
-    // Populate the VBoxLayout.
+    // Populate the cookie tree view.
     for (QNetworkCookie cookie : *cookieListPointer)
     {
         // Get the cookie domain.
@@ -160,72 +164,45 @@ CookiesDialog::CookiesDialog(std::list<QNetworkCookie> *originalCookieListPointe
         // Check to see if the cookie is a member of the current domain.
         if (cookieDomain != currentDomainString)  // Create a new domain in the tree.
         {
-            // Create a list for the domain standard items.
-            QList<QStandardItem*> domainStandardItemList;
-
-            // Create the new domain standard items.
-            QStandardItem *domainStandardItemPointer = new QStandardItem(cookieDomain);
-            QStandardItem *pathStandardItemPointer = new QStandardItem(QStringLiteral(""));
-            QStandardItem *expirationDateStandardItemPointer = new QStandardItem(QStringLiteral(""));
-            QStandardItem *isHttpOnlyStandardItemPointer = new QStandardItem(QStringLiteral(""));
-            QStandardItem *isSecureStandardItemPointer = new QStandardItem(QStringLiteral(""));
-            QStandardItem *valueStandardItemPointer = new QStandardItem(QStringLiteral(""));
-
-            // Disable editing of the domain.
-            domainStandardItemPointer->setEditable(false);
-            pathStandardItemPointer->setEditable(false);
-            expirationDateStandardItemPointer->setEditable(false);
-            isHttpOnlyStandardItemPointer->setEditable(false);
-            isSecureStandardItemPointer->setEditable(false);
-            valueStandardItemPointer->setEditable(false);
-
-            // Populate the domain standard item list.
-            domainStandardItemList.append(domainStandardItemPointer);
-            domainStandardItemList.append(pathStandardItemPointer);
-            domainStandardItemList.append(expirationDateStandardItemPointer);
-            domainStandardItemList.append(isHttpOnlyStandardItemPointer);
-            domainStandardItemList.append(isSecureStandardItemPointer);
-            domainStandardItemList.append(valueStandardItemPointer);
+            // Create the domain name item.
+            QStandardItem *domainNameItemPointer = new QStandardItem(cookieDomain);
 
             // Add the domain to the tree.
-            standardItemModelPointer->invisibleRootItem()->appendRow(domainStandardItemList);
+            treeModelPointer->invisibleRootItem()->appendRow(domainNameItemPointer);
 
             // Update the current domain string.
             currentDomainString = cookieDomain;
 
-            // Update the current domain standard item pointer.
-            currentDomainStandardItemPointer = domainStandardItemPointer;
+            // Update the current domain item pointer.
+            currentDomainItemPointer = domainNameItemPointer;
         }
 
-        // Create a list for the cookie standard items.
-        QList<QStandardItem*> cookieStandardItemList;
-
-        // Create the cookie standard items.
-        QStandardItem *nameStandardItemPointer = new QStandardItem(QString(cookie.name()));
-        QStandardItem *pathStandardItemPointer = new QStandardItem(QString(cookie.path()));
-        QStandardItem *expirationDateStandardItemPointer = new QStandardItem(QString(cookie.expirationDate().toString()));
-        QStandardItem *isHttpOnlyStandardItemPointer = new QStandardItem(QString(cookie.isHttpOnly() ? i18n("yes") : i18n("no")));
-        QStandardItem *isSecureStandardItemPointer = new QStandardItem(QString(cookie.isSecure() ? i18n("yes") : i18n("no")));
-        QStandardItem *valueStandardItemPointer = new QStandardItem(QString(cookie.value()));
-
-        // Disable editing of the cookie standard items.
-        nameStandardItemPointer->setEditable(false);
-        pathStandardItemPointer->setEditable(false);
-        expirationDateStandardItemPointer->setEditable(false);
-        isHttpOnlyStandardItemPointer->setEditable(false);
-        isSecureStandardItemPointer->setEditable(false);
-        valueStandardItemPointer->setEditable(false);
+        // Check to see if the cookie is durable.
+        bool isDurable = CookiesDatabase::isDurable(cookie);
+
+        // Create a list for the cookie items.
+        QList<QStandardItem*> cookieItemList;
+
+        // Create the cookie items.
+        QStandardItem *nameItemPointer = new QStandardItem(QString(cookie.name()));
+        QStandardItem *durableItemPointer = new QStandardItem(QString(isDurable ? i18n("yes") : i18n("no")));
+        QStandardItem *pathItemPointer = new QStandardItem(QString(cookie.path()));
+        QStandardItem *expirationDateItemPointer = new QStandardItem(QString(cookie.expirationDate().toString()));
+        QStandardItem *isHttpOnlyItemPointer = new QStandardItem(QString(cookie.isHttpOnly() ? i18n("yes") : i18n("no")));
+        QStandardItem *isSecureItemPointer = new QStandardItem(QString(cookie.isSecure() ? i18n("yes") : i18n("no")));
+        QStandardItem *valueItemPointer = new QStandardItem(QString(cookie.value()));
 
         // Populate the cookie standard item list.
-        cookieStandardItemList.append(nameStandardItemPointer);
-        cookieStandardItemList.append(pathStandardItemPointer);
-        cookieStandardItemList.append(expirationDateStandardItemPointer);
-        cookieStandardItemList.append(isHttpOnlyStandardItemPointer);
-        cookieStandardItemList.append(isSecureStandardItemPointer);
-        cookieStandardItemList.append(valueStandardItemPointer);
+        cookieItemList.append(nameItemPointer);
+        cookieItemList.append(durableItemPointer);
+        cookieItemList.append(pathItemPointer);
+        cookieItemList.append(expirationDateItemPointer);
+        cookieItemList.append(isHttpOnlyItemPointer);
+        cookieItemList.append(isSecureItemPointer);
+        cookieItemList.append(valueItemPointer);
 
         // Add the cookie to the tree.
-        currentDomainStandardItemPointer->appendRow(cookieStandardItemList);
+        currentDomainItemPointer->appendRow(cookieItemList);
     }
 
     // Auto resize the headers.
@@ -240,14 +217,17 @@ CookiesDialog::CookiesDialog(std::list<QNetworkCookie> *originalCookieListPointe
     // Indicate that all the rows are the same height, wich improves performance.
     treeViewPointer->setUniformRowHeights(true);
 
-    // Set the tree view model.
-    treeViewPointer->setModel(standardItemModelPointer);
+    // Disable editing.
+    treeViewPointer->setEditTriggers(QAbstractItemView::NoEditTriggers);
+
+    // Set the tree model.
+    treeViewPointer->setModel(treeModelPointer);
 
-    // Get a handle for the tree view selection model.
-    treeViewSelectionModelPointer = treeViewPointer->selectionModel();
+    // Get a handle for the tree selection model.
+    treeSelectionModelPointer = treeViewPointer->selectionModel();
 
     // Listen for selection changes.
-    connect(treeViewSelectionModelPointer, SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(updateUi()));
+    connect(treeSelectionModelPointer, SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(updateUi()));
 
     // Get handles for the buttons.
     addCookieButtonPointer = cookiesDialogUi.addCookieButton;
@@ -297,7 +277,7 @@ CookiesDialog::CookiesDialog(std::list<QNetworkCookie> *originalCookieListPointe
     updateUi();
 };
 
-void CookiesDialog::addCookieFromDialog(const QNetworkCookie &cookie) const
+void CookiesDialog::addCookieFromDialog(const QNetworkCookie &cookie, const bool &isDurable) const
 {
     // Add the cookie to the cookie list and the cookie store.
     emit addCookie(cookie);
@@ -306,46 +286,22 @@ void CookiesDialog::addCookieFromDialog(const QNetworkCookie &cookie) const
     QString newDomain = cookie.domain();
 
     // Check to see if the domain already exists in the model.
-    QList<QStandardItem*> currentDomainStandardItemList = standardItemModelPointer->findItems(newDomain);
+    QList<QStandardItem*> currentDomainItemList = treeModelPointer->findItems(newDomain);
 
-    // Create a domain standard item pointer.
-    QStandardItem *domainStandardItemPointer;
+    // Create a domain item pointer.
+    QStandardItem *domainNameItemPointer;
 
-    // Prepare the domain standard item pointer.
-    if (currentDomainStandardItemList.isEmpty())  // The domain doesn't currently exist in the tree.
+    // Prepare the domain item pointer.
+    if (currentDomainItemList.isEmpty())  // The domain doesn't currently exist in the tree.
     {
-        // Create a list for the domain standard items.
-        QList<QStandardItem*> domainStandardItemList;
-
-        // Create the new domain standard items.
-        domainStandardItemPointer = new QStandardItem(newDomain);
-        QStandardItem *pathStandardItemPointer = new QStandardItem(QStringLiteral(""));
-        QStandardItem *expirationDateStandardItemPointer = new QStandardItem(QStringLiteral(""));
-        QStandardItem *isHttpOnlyStandardItemPointer = new QStandardItem(QStringLiteral(""));
-        QStandardItem *isSecureStandardItemPointer = new QStandardItem(QStringLiteral(""));
-        QStandardItem *valueStandardItemPointer = new QStandardItem(QStringLiteral(""));
-
-        // Disable editing of the domain.
-        domainStandardItemPointer->setEditable(false);
-        pathStandardItemPointer->setEditable(false);
-        expirationDateStandardItemPointer->setEditable(false);
-        isHttpOnlyStandardItemPointer->setEditable(false);
-        isSecureStandardItemPointer->setEditable(false);
-        valueStandardItemPointer->setEditable(false);
-
-        // Populate the domain standard item list.
-        domainStandardItemList.append(domainStandardItemPointer);
-        domainStandardItemList.append(pathStandardItemPointer);
-        domainStandardItemList.append(expirationDateStandardItemPointer);
-        domainStandardItemList.append(isHttpOnlyStandardItemPointer);
-        domainStandardItemList.append(isSecureStandardItemPointer);
-        domainStandardItemList.append(valueStandardItemPointer);
+        // Create the domain name item.
+        domainNameItemPointer = new QStandardItem(newDomain);
 
         // Create the insert domain row number.
         int insertDomainRowNumber = 0;
 
         // Get the number of domains in the tree.
-        int numberOfDomains = standardItemModelPointer->invisibleRootItem()->rowCount();
+        int numberOfDomains = treeModelPointer->invisibleRootItem()->rowCount();
 
         // Get the new domain strings.
         QString newDomainTopLevelDomain = newDomain.section('.', -1);
@@ -356,7 +312,7 @@ void CookiesDialog::addCookieFromDialog(const QNetworkCookie &cookie) const
         for (int i = 0; i < numberOfDomains; ++i)
         {
             // Get the current domain strings.
-            QString currentDomain = standardItemModelPointer->invisibleRootItem()->child(i, 0)->index().data().toString();
+            QString currentDomain = treeModelPointer->invisibleRootItem()->child(i, 0)->index().data().toString();
             QString currentDomainTopLevelDomain = currentDomain.section('.', -1);
             QString currentDomainSecondLevelDomain = currentDomain.section('.', -2);
             QString currentDomainThirdLevelDomain = currentDomain.section('.', -3);
@@ -385,76 +341,85 @@ void CookiesDialog::addCookieFromDialog(const QNetworkCookie &cookie) const
         }
 
         // Add the domain to the tree.
-        standardItemModelPointer->invisibleRootItem()->insertRow(insertDomainRowNumber, domainStandardItemList);
+        treeModelPointer->invisibleRootItem()->insertRow(insertDomainRowNumber, domainNameItemPointer);
     }
     else  // The domain already exists in the tree.
     {
         // Use the current domain standard item.
-        domainStandardItemPointer = currentDomainStandardItemList[0];
+        domainNameItemPointer = currentDomainItemList[0];
     }
 
     // Get strings for the new cookie name and path (used later in the placement of the row).
     QString newCookieName = QString(cookie.name());
     QString newCookiePath = QString(cookie.path());
 
-    // Create a list for the cookie standard items.
-    QList<QStandardItem*> cookieStandardItemList;
-
-    // Create the cookie standard items.
-    QStandardItem *nameStandardItemPointer = new QStandardItem(newCookieName);
-    QStandardItem *pathStandardItemPointer = new QStandardItem(newCookiePath);
-    QStandardItem *expirationDateStandardItemPointer = new QStandardItem(QString(cookie.expirationDate().toString()));
-    QStandardItem *isHttpOnlyStandardItemPointer = new QStandardItem(QString(cookie.isHttpOnly() ? i18n("yes") : i18n("no")));
-    QStandardItem *isSecureStandardItemPointer = new QStandardItem(QString(cookie.isSecure() ? i18n("yes") : i18n("no")));
-    QStandardItem *valueStandardItemPointer = new QStandardItem(QString(cookie.value()));
-
-    // Disable editing of the cookie standard items.
-    nameStandardItemPointer->setEditable(false);
-    pathStandardItemPointer->setEditable(false);
-    expirationDateStandardItemPointer->setEditable(false);
-    isHttpOnlyStandardItemPointer->setEditable(false);
-    isSecureStandardItemPointer->setEditable(false);
-    valueStandardItemPointer->setEditable(false);
-
-    // Populate the cookie standard item list.
-    cookieStandardItemList.append(nameStandardItemPointer);
-    cookieStandardItemList.append(pathStandardItemPointer);
-    cookieStandardItemList.append(expirationDateStandardItemPointer);
-    cookieStandardItemList.append(isHttpOnlyStandardItemPointer);
-    cookieStandardItemList.append(isSecureStandardItemPointer);
-    cookieStandardItemList.append(valueStandardItemPointer);
+    // Create a cookie item list.
+    QList<QStandardItem*> cookieItemList;
+
+    // Create the cookie items.
+    QStandardItem *nameItemPointer = new QStandardItem(newCookieName);
+    QStandardItem *durableItemPointer = new QStandardItem(QString(isDurable ? i18n("yes") : i18n("no")));
+    QStandardItem *pathItemPointer = new QStandardItem(newCookiePath);
+    QStandardItem *expirationDateItemPointer = new QStandardItem(QString(cookie.expirationDate().toString()));
+    QStandardItem *isHttpOnlyItemPointer = new QStandardItem(QString(cookie.isHttpOnly() ? i18n("yes") : i18n("no")));
+    QStandardItem *isSecureItemPointer = new QStandardItem(QString(cookie.isSecure() ? i18n("yes") : i18n("no")));
+    QStandardItem *valueItemPointer = new QStandardItem(QString(cookie.value()));
+
+    // Populate the cookie item list.
+    cookieItemList.append(nameItemPointer);
+    cookieItemList.append(durableItemPointer);
+    cookieItemList.append(pathItemPointer);
+    cookieItemList.append(expirationDateItemPointer);
+    cookieItemList.append(isHttpOnlyItemPointer);
+    cookieItemList.append(isSecureItemPointer);
+    cookieItemList.append(valueItemPointer);
 
     // Create the insert cookie row number.
     int insertCookieRowNumber = 0;
 
+    // Create the remove existing row tracker.
+    bool removeExistingRow = false;
+
     // Get the number of cookies in the domain.
-    int numberOfCookies = domainStandardItemPointer->rowCount();
+    int numberOfCookies = domainNameItemPointer->rowCount();
 
     // Iterate through the cookies for this domain.
     for (int i = 0; i < numberOfCookies; ++i)
     {
         // Get the current cookie name and path at the indicated row.
-        QString currentCookieName = domainStandardItemPointer->child(i, 0)->index().data().toString();
-        QString currentCookiePath = domainStandardItemPointer->child(i, 1)->index().data().toString();
+        QString currentCookieName = domainNameItemPointer->child(i, 0)->index().data().toString();
+        QString currentCookiePath = domainNameItemPointer->child(i, 2)->index().data().toString();
 
         // Check to see if the new cookie should be inserted after the current cookie.
-        if (newCookieName > currentCookieName)
+        if (newCookieName > currentCookieName)  // The new cookie name comes after the current cookie name.
         {
             // Insert the new cookie after the current cookie.
             insertCookieRowNumber = i + 1;
         }
-        else if ((newCookieName == currentCookieName) && (newCookiePath > currentCookiePath))
+        else if ((newCookieName == currentCookieName) && (newCookiePath > currentCookiePath))  // The names are the same, but the new cookie path comes after the current cookie path.
         {
             // Insert the new cookie after the current cookie.
             insertCookieRowNumber = i + 1;
         }
+        else if ((newCookieName == currentCookieName) && (newCookiePath == currentCookiePath))  // The cookies are the same.
+        {
+            // Remove the existing cookie in this row.
+            removeExistingRow = true;
+
+            // Insert the cookie in it's place.
+            insertCookieRowNumber = i;
+        }
     }
 
-    // Add the cookie to the tree.
-    domainStandardItemPointer->insertRow(insertCookieRowNumber, cookieStandardItemList);
+    // Remove the existing row if it is being edited.
+    if (removeExistingRow)
+        domainNameItemPointer->removeRow(insertCookieRowNumber);
+
+    // Add the cookie to the tree model.
+    domainNameItemPointer->insertRow(insertCookieRowNumber, cookieItemList);
 
     // Get the new cookie model index.
-    QModelIndex newCookieIndex = nameStandardItemPointer->index();
+    QModelIndex newCookieIndex = nameItemPointer->index();
 
     // Set the new cookie to be the current index.
     treeViewPointer->setCurrentIndex(newCookieIndex);
@@ -463,7 +428,7 @@ void CookiesDialog::addCookieFromDialog(const QNetworkCookie &cookie) const
     treeViewPointer->expand(newCookieIndex.parent());
 }
 
-void CookiesDialog::deleteCookie(const QModelIndex &modelIndex) const
+void CookiesDialog::deleteCookie(const QModelIndex &modelIndex, const bool &deleteDurableCookies) const
 {
     // Create a partial cookie.
     QNetworkCookie partialCookie;
@@ -471,40 +436,69 @@ void CookiesDialog::deleteCookie(const QModelIndex &modelIndex) const
     // Populate the partial cookie from the current model index.
     partialCookie.setDomain(modelIndex.parent().siblingAtColumn(0).data().toString());
     partialCookie.setName(modelIndex.siblingAtColumn(0).data().toString().toUtf8());
-    partialCookie.setPath(modelIndex.siblingAtColumn(1).data().toString());
+    partialCookie.setPath(modelIndex.siblingAtColumn(2).data().toString());
 
     // Create a cookie to delete.
     QNetworkCookie cookieToDelete;
 
-    // Search for the partial cookie in the cookie list.
-    for (QNetworkCookie cookie : *cookieListPointer)
+    // Check if the cookie is durable.
+    bool isDurable = CookiesDatabase::isDurable(partialCookie);
+
+    // Only delete durable cookies if directed.
+    if (deleteDurableCookies || !isDurable)
     {
-        // Store the cookie to delete if it has the same identifier as the partial cookie.
-        if (cookie.hasSameIdentifier(partialCookie))
-            cookieToDelete = cookie;
+        // Search for the partial cookie in the cookie list.
+        for (QNetworkCookie cookie : *cookieListPointer)
+        {
+            // Store the cookie to delete if it has the same identifier as the partial cookie.
+            if (cookie.hasSameIdentifier(partialCookie))
+                cookieToDelete = cookie;
+        }
+
+        // Remove the cookie from the tree model.
+        treeModelPointer->removeRow(modelIndex.row(), modelIndex.parent());
+
+        // Delete the cookie from the cookie list and cookie store.
+        emit deleteCookie(cookieToDelete);
+
+        // Delete the cookie from the durable cookies database.
+        if (isDurable)
+            CookiesDatabase::deleteCookie(cookieToDelete);
     }
+}
 
-    // Remove the cookie from the tree view.
-    standardItemModelPointer->removeRow(modelIndex.row(), modelIndex.parent());
+void CookiesDialog::deleteDomain(const QModelIndex &modelIndex, const bool &deleteDurableCookies) const
+{
+    // Get the parent index.
+    QModelIndex parentIndex = modelIndex.parent();
 
-    // Delete the cookie from the cookie list and cookie store.
-    emit deleteCookie(cookieToDelete);
+    // Get the number of cookies in the domain.
+    int numberOfCookies = treeModelPointer->rowCount(modelIndex);
+
+    // Delete each child cookie, starting from the bottom.
+    for (int i = numberOfCookies; i > 0; --i)
+        deleteCookie(treeModelPointer->index(i-1, 0, modelIndex), deleteDurableCookies);
+
+    // Remove the domain if all the cookies have been deleted.
+    if (treeModelPointer->rowCount(modelIndex) == 0)
+        treeModelPointer->removeRow(modelIndex.row(), parentIndex);
 }
 
+
 void CookiesDialog::deleteCookieFromDialog(const QNetworkCookie &cookie) const
 {
     // Get the current model index.
-    QModelIndex currentIndex = treeViewSelectionModelPointer->currentIndex();
+    QModelIndex currentIndex = treeSelectionModelPointer->currentIndex();
 
     // Get the parent index.
     QModelIndex parentIndex = currentIndex.parent();
 
-    // Remove the cookie from the tree view.
-    standardItemModelPointer->removeRow(currentIndex.row(), parentIndex);
+    // Remove the cookie from the tree model.
+    treeModelPointer->removeRow(currentIndex.row(), parentIndex);
 
-    // Remove the domain from the tree view if its only cookie has been deleted.
-    if (standardItemModelPointer->rowCount(parentIndex) == 0)
-        standardItemModelPointer->removeRow(parentIndex.row(), parentIndex.parent());
+    // Remove the domain from the tree model if its only cookie has been deleted.
+    if (treeModelPointer->rowCount(parentIndex) == 0)
+        treeModelPointer->removeRow(parentIndex.row(), parentIndex.parent());
 
     // Delete the cookie from the cookie list and cookie store.
     emit deleteCookie(cookie);
@@ -519,7 +513,7 @@ void CookiesDialog::showAddCookieDialog() const
     addCookieDialogPointer->show();
 
     // Add the cookie if directed.
-    connect(addCookieDialogPointer, SIGNAL(addCookie(QNetworkCookie)), this, SLOT(addCookieFromDialog(QNetworkCookie)));
+    connect(addCookieDialogPointer, SIGNAL(addCookie(QNetworkCookie, bool)), this, SLOT(addCookieFromDialog(QNetworkCookie, bool)));
 }
 
 void CookiesDialog::showDeleteAllMessageBox() const
@@ -536,6 +530,12 @@ void CookiesDialog::showDeleteAllMessageBox() const
     // Set the text.
     deleteAllCookiesMessageBox.setText(i18nc("Delete all cookies dialog text", "Delete all cookies?"));
 
+    // Create a delete durable cookies check box.
+    QCheckBox deleteDurableCookiesCheckBox(i18nc("Delete durable cookies check box", "Delete even if durable"));
+
+    // Add the check box to the dialog.
+    deleteAllCookiesMessageBox.setCheckBox(&deleteDurableCookiesCheckBox);
+
     // Set the standard buttons.
     deleteAllCookiesMessageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
 
@@ -548,27 +548,43 @@ void CookiesDialog::showDeleteAllMessageBox() const
     // Delete all cookies if instructed.
     if (returnValue == QMessageBox::Yes)
     {
-        // Delete all the cookies.
-        emit deleteAllCookies();
+        // Only delete durable cookies if requested.
+        if (deleteDurableCookiesCheckBox.isChecked())  // Delete everything.
+        {
+            // Delete all the cookies.
+            emit deleteAllCookies();
+
+            // Clear the tree model.
+            treeModelPointer->clear();
+
+            // Delete the durable cookies from the database.
+            CookiesDatabase::deleteAllCookies();
+
+            // Update the UI.
+            updateUi();
+        }
+        else  // Only delete cookies that are not durable.
+        {
+            // Get the root model index.
+            QModelIndex rootIndex = treeModelPointer->invisibleRootItem()->index();
 
-        // Clear the standard item model.
-        standardItemModelPointer->clear();
+            // Get the number of domains.
+            int numberOfDomains = treeModelPointer->rowCount(rootIndex);
 
-        // Update the UI.
-        updateUi();
+            // Delete each domain, starting from the bottom.
+            for (int i = numberOfDomains; i > 0; --i)
+                deleteDomain(treeModelPointer->index(i - 1, 0, rootIndex), deleteDurableCookiesCheckBox.isChecked());
+        }
     }
 }
 
 void CookiesDialog::showDeleteCookieMessageBox() const
 {
     // Get the current model index.
-    QModelIndex currentIndex = treeViewSelectionModelPointer->currentIndex();
-
-    // Get the parent model index.
-    QModelIndex parentIndex = currentIndex.parent();
+    QModelIndex currentIndex = treeSelectionModelPointer->currentIndex();
 
     // Determine if a domain is selected.
-    bool isDomain = standardItemModelPointer->hasChildren(currentIndex);
+    bool isDomain = treeModelPointer->hasChildren(currentIndex);
 
     // Instantiate a delete cookie message box.
     QMessageBox deleteCookieMessageBox;
@@ -576,26 +592,35 @@ void CookiesDialog::showDeleteCookieMessageBox() const
     // Set the icon.
     deleteCookieMessageBox.setIcon(QMessageBox::Warning);
 
-    if (isDomain)
+    // Create a delete durable cookies check box.
+    QCheckBox deleteDurableCookiesCheckBox(i18nc("Delete durable cookies check box", "Delete even if durable"));
+
+    if (isDomain)  // A domain is selected.
     {
         // Get the number of cookies.
-        int numberOfCookiesToDelete = standardItemModelPointer->rowCount(currentIndex);
+        int numberOfCookiesToDelete = treeModelPointer->rowCount(currentIndex);
 
         // Set the window title.
-        deleteCookieMessageBox.setWindowTitle(i18nc("Delete cookies dialog title", "Delete %1 Cookies", numberOfCookiesToDelete));
+        deleteCookieMessageBox.setWindowTitle(i18ncp("Delete cookies dialog title", "Delete %1 Cookie", "Delete 1% Cookies", numberOfCookiesToDelete));
 
         // Set the text.
-        deleteCookieMessageBox.setText(i18nc("Delete cookies dialog text", "Delete %1 cookies?", numberOfCookiesToDelete));
+        deleteCookieMessageBox.setText(i18ncp("Delete cookies dialog text", "Delete %1 cookie?", "Delete %1 cookies?", numberOfCookiesToDelete));
     }
-    else
+    else  // A single cookie is selected.
     {
         // Set the window title.
         deleteCookieMessageBox.setWindowTitle(i18nc("Delete cookie dialog title", "Delete 1 Cookie"));
 
         // Set the text.
         deleteCookieMessageBox.setText(i18nc("Delete cookie dialog text", "Delete 1 cookie?"));
+
+        // Check the box.
+        deleteDurableCookiesCheckBox.setChecked(true);
     }
 
+    // Add the check box to the dialog.
+    deleteCookieMessageBox.setCheckBox(&deleteDurableCookiesCheckBox);
+
     // Set the standard buttons.
     deleteCookieMessageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
 
@@ -611,27 +636,20 @@ void CookiesDialog::showDeleteCookieMessageBox() const
         // Delete the cookies according to the selection.
         if (isDomain)  // A domain is selected.
         {
-            // Get the number of cookies.
-            int numberOfCookies = standardItemModelPointer->rowCount(currentIndex);
-
-            // Delete each child cookie.
-            for (int i = 0; i < numberOfCookies; ++i)
-            {
-                // Delete the cookie for the first child.  Once this is deleted, the second child will become the first child.
-                deleteCookie(standardItemModelPointer->index(0, 0, currentIndex));
-            }
-
-            // Delete the domain from the tree view.
-            standardItemModelPointer->removeRow(currentIndex.row(), parentIndex);
+            // Delete the domain.
+            deleteDomain(currentIndex, deleteDurableCookiesCheckBox.isChecked());
         }
         else  // A single cookie is selected.
         {
+            // Get the parent model index.
+            QModelIndex parentIndex = currentIndex.parent();
+
             // Delete the cookie.
-            deleteCookie(currentIndex);
+            deleteCookie(currentIndex, deleteDurableCookiesCheckBox.isChecked());
 
             // Remove the domain row if its only cookie has been deleted.
-            if (standardItemModelPointer->rowCount(parentIndex) == 0)
-                standardItemModelPointer->removeRow(parentIndex.row(), parentIndex.parent());
+            if (treeModelPointer->rowCount(parentIndex) == 0)
+                treeModelPointer->removeRow(parentIndex.row(), parentIndex.parent());
         }
     }
 }
@@ -639,7 +657,7 @@ void CookiesDialog::showDeleteCookieMessageBox() const
 void CookiesDialog::showEditCookieDialog() const
 {
     // Get the current model index.
-    QModelIndex currentIndex = treeViewSelectionModelPointer->currentIndex();
+    QModelIndex currentIndex = treeSelectionModelPointer->currentIndex();
 
     // Create a partial cookie.
     QNetworkCookie partialCookie;
@@ -647,7 +665,7 @@ void CookiesDialog::showEditCookieDialog() const
     // Populate the partial cookie from the current model index.
     partialCookie.setDomain(currentIndex.parent().siblingAtColumn(0).data().toString());
     partialCookie.setName(currentIndex.siblingAtColumn(0).data().toString().toUtf8());
-    partialCookie.setPath(currentIndex.siblingAtColumn(1).data().toString());
+    partialCookie.setPath(currentIndex.siblingAtColumn(2).data().toString());
 
     // Create a cookie to edit.
     QNetworkCookie cookieToEdit;
@@ -661,33 +679,33 @@ void CookiesDialog::showEditCookieDialog() const
     }
 
     // Instantiate an edit cookie dialog.
-    QDialog *editCookieDialogPointer = new AddOrEditCookieDialog(AddOrEditCookieDialog::EditCookie, &cookieToEdit);
+    QDialog *editCookieDialogPointer = new AddOrEditCookieDialog(AddOrEditCookieDialog::EditCookie, &cookieToEdit, currentIndex.siblingAtColumn(1).data().toString() == i18n("yes"));
 
     // Show the dialog.
     editCookieDialogPointer->show();
 
     // Process cookie events.
-    connect(editCookieDialogPointer, SIGNAL(addCookie(QNetworkCookie)), this, SLOT(addCookieFromDialog(QNetworkCookie)));
+    connect(editCookieDialogPointer, SIGNAL(addCookie(QNetworkCookie, bool)), this, SLOT(addCookieFromDialog(QNetworkCookie, bool)));
     connect(editCookieDialogPointer, SIGNAL(deleteCookie(QNetworkCookie)), this, SLOT(deleteCookieFromDialog(QNetworkCookie)));
 }
 
 void CookiesDialog::updateUi() const
 {
     // Get the current index of the first column.
-    QModelIndex currentIndex = treeViewSelectionModelPointer->currentIndex().siblingAtColumn(0);
+    QModelIndex currentIndex = treeSelectionModelPointer->currentIndex().siblingAtColumn(0);
 
     // Set the status of the buttons.
-    editCookieButtonPointer->setEnabled(treeViewSelectionModelPointer->hasSelection() && !standardItemModelPointer->hasChildren(currentIndex));
-    deleteCookieButtonPointer->setEnabled(treeViewSelectionModelPointer->hasSelection());;
-    deleteAllButtonPointer->setEnabled(standardItemModelPointer->hasChildren(standardItemModelPointer->invisibleRootItem()->index()));
+    editCookieButtonPointer->setEnabled(treeSelectionModelPointer->hasSelection() && !treeModelPointer->hasChildren(currentIndex));
+    deleteCookieButtonPointer->setEnabled(treeSelectionModelPointer->hasSelection());;
+    deleteAllButtonPointer->setEnabled(treeModelPointer->hasChildren(treeModelPointer->invisibleRootItem()->index()));
 
     // Update the delete cookie button text.
     if (deleteCookieButtonPointer->isEnabled())  // The button is enabled.
     {
-        if (standardItemModelPointer->hasChildren(currentIndex))  // A domain is selected.
+        if (treeModelPointer->hasChildren(currentIndex))  // A domain is selected.
         {
             // Update the button text.
-            deleteCookieButtonPointer->setText(i18nc("Delete cookies button.", "&Delete %1 cookies", standardItemModelPointer->rowCount(currentIndex)));
+            deleteCookieButtonPointer->setText(i18ncp("Delete cookies button.", "&Delete %1 cookie", "&Delete %1 cookies", treeModelPointer->rowCount(currentIndex)));
         }
         else  // A single cookie is selected.
         {
index f34beca66ad7b95153b93030472a7649f6069e69..89c2be4e1998432c40faf8536960cf99d032c50b 100644 (file)
@@ -47,7 +47,7 @@ signals:
 
 private Q_SLOTS:
     // The private slots.
-    void addCookieFromDialog(const QNetworkCookie &cookie) const;
+    void addCookieFromDialog(const QNetworkCookie &cookie, const bool &isDurable) const;
     void deleteCookieFromDialog(const QNetworkCookie &cookie) const;
     void showAddCookieDialog() const;
     void showDeleteAllMessageBox() const;
@@ -57,16 +57,17 @@ private Q_SLOTS:
 
 private:
     // The private variables.
-    QItemSelectionModel *treeViewSelectionModelPointer;
     QPushButton *addCookieButtonPointer;
     std::list<QNetworkCookie> *cookieListPointer;
     QPushButton *deleteAllButtonPointer;
     QPushButton *deleteCookieButtonPointer;
     QPushButton *editCookieButtonPointer;
-    QStandardItemModel *standardItemModelPointer;
+    QStandardItemModel *treeModelPointer;
+    QItemSelectionModel *treeSelectionModelPointer;
     QTreeView *treeViewPointer;
 
     // The private functions.
-    void deleteCookie(const QModelIndex &modelIndex) const;
+    void deleteCookie(const QModelIndex &modelIndex, const bool &deleteDurableCookies) const;
+    void deleteDomain(const QModelIndex &modelIndex, const bool &deleteDurableCookies) const;
 };
 #endif
index 151a0b4926be9930962306e38fc1beeebfcd3e52..76477ecf8ccceab21f23aad2005282f5d064ada2 100644 (file)
@@ -21,7 +21,7 @@
 #include "DomainSettingsDialog.h"
 #include "Settings.h"
 #include "ui_DomainSettingsDialog.h"
-#include "helpers/DomainsDatabaseHelper.h"
+#include "databases/DomainsDatabase.h"
 #include "helpers/UserAgentHelper.h"
 
 // Qt toolkit headers.
@@ -70,10 +70,10 @@ DomainSettingsDialog::DomainSettingsDialog(const int &startType, const QString &
     resetButtonPointer = dialogButtonBoxPointer->button(QDialogButtonBox::StandardButton::Reset);
 
     // Create a table model.
-    domainsTableModelPointer = new QSqlTableModel(nullptr, QSqlDatabase::database(DomainsDatabaseHelper::CONNECTION_NAME));
+    domainsTableModelPointer = new QSqlTableModel(nullptr, QSqlDatabase::database(DomainsDatabase::CONNECTION_NAME));
 
     // Set the table for the model.
-    domainsTableModelPointer->setTable(DomainsDatabaseHelper::DOMAINS_TABLE);
+    domainsTableModelPointer->setTable(DomainsDatabase::DOMAINS_TABLE);
 
     // Set the edit strategy to be manual.
     domainsTableModelPointer->setEditStrategy(QSqlTableModel::EditStrategy::OnManualSubmit);
@@ -102,7 +102,7 @@ DomainSettingsDialog::DomainSettingsDialog(const int &startType, const QString &
         case SHOW_ALL_DOMAINS:
         {
             // Select the first entry in the list view.
-            domainsListViewPointer->setCurrentIndex(domainsTableModelPointer->index(0, domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::DOMAIN_NAME)));
+            domainsListViewPointer->setCurrentIndex(domainsTableModelPointer->index(0, domainsTableModelPointer->fieldIndex(DomainsDatabase::DOMAIN_NAME)));
 
             // Populate the domain settings.
             domainSelected(domainsSelectionModelPointer->currentIndex());
@@ -121,8 +121,8 @@ DomainSettingsDialog::DomainSettingsDialog(const int &startType, const QString &
         case EDIT_DOMAIN:
         {
             // Find the index for the new domain.  `1` returns the first match.
-            QModelIndexList newDomainIndex = domainsTableModelPointer->match(domainsTableModelPointer->index(0, domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::DOMAIN_NAME)),
-                                                                        Qt::DisplayRole, domainName, 1, Qt::MatchWrap);
+            QModelIndexList newDomainIndex = domainsTableModelPointer->match(domainsTableModelPointer->index(0, domainsTableModelPointer->fieldIndex(DomainsDatabase::DOMAIN_NAME)),
+                                                                             Qt::DisplayRole, domainName, 1, Qt::MatchWrap);
 
             // Move to the new domain.
             domainsListViewPointer->setCurrentIndex(newDomainIndex[0]);
@@ -161,15 +161,15 @@ DomainSettingsDialog::DomainSettingsDialog(const int &startType, const QString &
 void DomainSettingsDialog::addDomain(const QString &domainName) const
 {
     // Create a new domain record.
-    QSqlRecord newDomainRecord = QSqlDatabase::database(DomainsDatabaseHelper::CONNECTION_NAME).record(DomainsDatabaseHelper::DOMAINS_TABLE);
+    QSqlRecord newDomainRecord = QSqlDatabase::database(DomainsDatabase::CONNECTION_NAME).record(DomainsDatabase::DOMAINS_TABLE);
 
     // Set the values for the new domain.
-    newDomainRecord.setValue(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::DOMAIN_NAME), domainName);
-    newDomainRecord.setValue(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::JAVASCRIPT), DomainsDatabaseHelper::SYSTEM_DEFAULT);
-    newDomainRecord.setValue(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::DOM_STORAGE), DomainsDatabaseHelper::SYSTEM_DEFAULT);
-    newDomainRecord.setValue(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::USER_AGENT), UserAgentHelper::SYSTEM_DEFAULT_DATABASE);
-    newDomainRecord.setValue(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::ZOOM_FACTOR), DomainsDatabaseHelper::SYSTEM_DEFAULT);
-    newDomainRecord.setValue(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::CUSTOM_ZOOM_FACTOR), 1.0);
+    newDomainRecord.setValue(domainsTableModelPointer->fieldIndex(DomainsDatabase::DOMAIN_NAME), domainName);
+    newDomainRecord.setValue(domainsTableModelPointer->fieldIndex(DomainsDatabase::JAVASCRIPT), DomainsDatabase::SYSTEM_DEFAULT);
+    newDomainRecord.setValue(domainsTableModelPointer->fieldIndex(DomainsDatabase::DOM_STORAGE), DomainsDatabase::SYSTEM_DEFAULT);
+    newDomainRecord.setValue(domainsTableModelPointer->fieldIndex(DomainsDatabase::USER_AGENT), UserAgentHelper::SYSTEM_DEFAULT_DATABASE);
+    newDomainRecord.setValue(domainsTableModelPointer->fieldIndex(DomainsDatabase::ZOOM_FACTOR), DomainsDatabase::SYSTEM_DEFAULT);
+    newDomainRecord.setValue(domainsTableModelPointer->fieldIndex(DomainsDatabase::CUSTOM_ZOOM_FACTOR), 1.0);
 
     // Insert the new domain.  `-1` appends it to the end.
     domainsTableModelPointer->insertRecord(-1, newDomainRecord);
@@ -178,8 +178,8 @@ void DomainSettingsDialog::addDomain(const QString &domainName) const
     domainsTableModelPointer->submitAll();
 
     // Find the index for the new domain.  `-1` allows for multiple entries to be returned.
-    QModelIndexList newDomainIndex = domainsTableModelPointer->match(domainsTableModelPointer->index(0, domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::DOMAIN_NAME)),
-                                                                        Qt::DisplayRole, domainName, -1, Qt::MatchWrap);
+    QModelIndexList newDomainIndex = domainsTableModelPointer->match(domainsTableModelPointer->index(0, domainsTableModelPointer->fieldIndex(DomainsDatabase::DOMAIN_NAME)),
+                                                                     Qt::DisplayRole, domainName, -1, Qt::MatchWrap);
 
     // Move to the new domain.  If there are multiple domains with the same name, the new one should be the last in the list.
     domainsListViewPointer->setCurrentIndex(newDomainIndex[newDomainIndex.size() - 1]);
@@ -197,17 +197,17 @@ void DomainSettingsDialog::apply() const
     QModelIndex currentIndex = domainsListViewPointer->currentIndex();
 
     // Get the ID of the current index row.
-    QVariant currentId = currentIndex.siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::_ID)).data();
+    QVariant currentId = currentIndex.siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabase::_ID)).data();
 
     // Submit all pending changes.
     domainsTableModelPointer->submitAll();
 
     // Find the new index for the selected id.  The `1` keeps searching after the first match.
-    QModelIndexList newIndexList = domainsTableModelPointer->match(currentIndex.siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::_ID)), Qt::DisplayRole, currentId,
+    QModelIndexList newIndexList = domainsTableModelPointer->match(currentIndex.siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabase::_ID)), Qt::DisplayRole, currentId,
                                                                    1, Qt::MatchWrap);
 
     // Select the new index.
-    domainsListViewPointer->setCurrentIndex(newIndexList[0].siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::DOMAIN_NAME)));
+    domainsListViewPointer->setCurrentIndex(newIndexList[0].siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabase::DOMAIN_NAME)));
 
     // Update the UI.
     updateUi();
@@ -228,7 +228,7 @@ void DomainSettingsDialog::cancel()
 void DomainSettingsDialog::customZoomFactorChanged(const double &newValue) const
 {
     // Update the domains table model.
-    domainsTableModelPointer->setData(domainsSelectionModelPointer->currentIndex().siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::CUSTOM_ZOOM_FACTOR)), newValue);
+    domainsTableModelPointer->setData(domainsSelectionModelPointer->currentIndex().siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabase::CUSTOM_ZOOM_FACTOR)), newValue);
 
     // Update the UI.
     updateUi();
@@ -237,7 +237,7 @@ void DomainSettingsDialog::customZoomFactorChanged(const double &newValue) const
 void DomainSettingsDialog::domStorageChanged(const int &newIndex) const
 {
     // Update the domains table model.
-    domainsTableModelPointer->setData(domainsSelectionModelPointer->currentIndex().siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::DOM_STORAGE)), newIndex);
+    domainsTableModelPointer->setData(domainsSelectionModelPointer->currentIndex().siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabase::DOM_STORAGE)), newIndex);
 
     // Populate the DOM storage label.
     populateDomStorageLabel();
@@ -261,16 +261,16 @@ void DomainSettingsDialog::domainSelected(const QModelIndex &modelIndex) const
     domainNameLineEditPointer->setText(modelIndex.data().toString());
 
     // Populate the JavaScript combo box.
-    javaScriptComboBoxPointer->setCurrentIndex(modelIndex.siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::JAVASCRIPT)).data().toInt());
+    javaScriptComboBoxPointer->setCurrentIndex(modelIndex.siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabase::JAVASCRIPT)).data().toInt());
 
     // Populate the local storage combo box.
-    localStorageComboBoxPointer->setCurrentIndex(modelIndex.siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::LOCAL_STORAGE)).data().toInt());
+    localStorageComboBoxPointer->setCurrentIndex(modelIndex.siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabase::LOCAL_STORAGE)).data().toInt());
 
     // Populate the DOM storage combo box.
-    domStorageComboBoxPointer->setCurrentIndex(modelIndex.siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::DOM_STORAGE)).data().toInt());
+    domStorageComboBoxPointer->setCurrentIndex(modelIndex.siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabase::DOM_STORAGE)).data().toInt());
 
     // Get the user agent string.
-    QString userAgent = modelIndex.siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::USER_AGENT)).data().toString();
+    QString userAgent = modelIndex.siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabase::USER_AGENT)).data().toString();
 
     // Get the user agent index.
     int userAgentIndex = UserAgentHelper::getDomainSettingsUserAgentIndex(userAgent);
@@ -282,7 +282,7 @@ void DomainSettingsDialog::domainSelected(const QModelIndex &modelIndex) const
     if (userAgentIndex == -1) userAgentComboBoxPointer->setCurrentText(userAgent);
 
     // Get the zoom factor combo box index.
-    int zoomFactorComboBoxIndex = modelIndex.siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::ZOOM_FACTOR)).data().toInt();
+    int zoomFactorComboBoxIndex = modelIndex.siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabase::ZOOM_FACTOR)).data().toInt();
 
     // Populate the zoom factor combo box.
     zoomFactorComboBoxPointer->setCurrentIndex(zoomFactorComboBoxIndex);
@@ -296,7 +296,7 @@ void DomainSettingsDialog::domainSelected(const QModelIndex &modelIndex) const
     else  // Custom zoom factor is selected.
     {
         // Display the custom zoom factor from the domain settings.
-        customZoomFactorSpinBoxPointer->setValue(modelIndex.siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::CUSTOM_ZOOM_FACTOR)).data().toDouble());
+        customZoomFactorSpinBoxPointer->setValue(modelIndex.siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabase::CUSTOM_ZOOM_FACTOR)).data().toDouble());
     }
 
     // Set the initial status of the custom zoom factor spin box.
@@ -315,7 +315,7 @@ void DomainSettingsDialog::domainSelected(const QModelIndex &modelIndex) const
 void DomainSettingsDialog::javaScriptChanged(const int &newIndex) const
 {
     // Update the domains table model.
-    domainsTableModelPointer->setData(domainsSelectionModelPointer->currentIndex().siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::JAVASCRIPT)), newIndex);
+    domainsTableModelPointer->setData(domainsSelectionModelPointer->currentIndex().siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabase::JAVASCRIPT)), newIndex);
 
     // Populate the JavaScript label.
     populateJavaScriptLabel();
@@ -327,7 +327,7 @@ void DomainSettingsDialog::javaScriptChanged(const int &newIndex) const
 void DomainSettingsDialog::localStorageChanged(const int &newIndex) const
 {
     // Update the domains table model.
-    domainsTableModelPointer->setData(domainsSelectionModelPointer->currentIndex().siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::LOCAL_STORAGE)), newIndex);
+    domainsTableModelPointer->setData(domainsSelectionModelPointer->currentIndex().siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabase::LOCAL_STORAGE)), newIndex);
 
     // Poplate the local storage label.
     populateLocalStorageLabel();
@@ -354,7 +354,7 @@ void DomainSettingsDialog::populateDomStorageLabel() const
     switch (domStorageComboBoxPointer->currentIndex())
     {
         // Set the text according to the system default.
-        case (DomainsDatabaseHelper::SYSTEM_DEFAULT):
+        case (DomainsDatabase::SYSTEM_DEFAULT):
         {
             if (Settings::domStorageEnabled())
                 domStorageLabelPointer->setText(i18nc("Domain settings DOM storage label.", "DOM storage enabled"));
@@ -365,7 +365,7 @@ void DomainSettingsDialog::populateDomStorageLabel() const
         }
 
         // Set the disabled text in bold.
-        case (DomainsDatabaseHelper::DISABLED):
+        case (DomainsDatabase::DISABLED):
         {
             domStorageLabelPointer->setText(i18nc("Domain settings DOM storage label.  The <b> tags should be retained.", "<b>DOM storage disabled</b>"));
 
@@ -373,7 +373,7 @@ void DomainSettingsDialog::populateDomStorageLabel() const
         }
 
         // Set the enabled text in bold.
-        case (DomainsDatabaseHelper::ENABLED):
+        case (DomainsDatabase::ENABLED):
         {
             domStorageLabelPointer->setText(i18nc("Domain settings DOM storage label.  The <b> tags should be retained.", "<b>DOM storage enabled</b>"));
 
@@ -388,7 +388,7 @@ void DomainSettingsDialog::populateJavaScriptLabel() const
     switch (javaScriptComboBoxPointer->currentIndex())
     {
         // Set the text according to the system default.
-        case (DomainsDatabaseHelper::SYSTEM_DEFAULT):
+        case (DomainsDatabase::SYSTEM_DEFAULT):
         {
             if (Settings::javaScriptEnabled())
                 javaScriptLabelPointer->setText(i18nc("Domain settings JavaScript label.", "JavaScript enabled"));
@@ -399,7 +399,7 @@ void DomainSettingsDialog::populateJavaScriptLabel() const
         }
 
         // Set the disabled text in bold.
-        case (DomainsDatabaseHelper::DISABLED):
+        case (DomainsDatabase::DISABLED):
         {
             javaScriptLabelPointer->setText(i18nc("Domain settings JavaScript label.  The <b> tags should be retained.", "<b>JavaScript disabled</b>"));
 
@@ -407,7 +407,7 @@ void DomainSettingsDialog::populateJavaScriptLabel() const
         }
 
         // Set the enabled text in bold.
-        case (DomainsDatabaseHelper::ENABLED):
+        case (DomainsDatabase::ENABLED):
         {
             javaScriptLabelPointer->setText(i18nc("Domain settings JavaScript label.  The <b> tags should be retained.", "<b>JavaScript enabled</b>"));
 
@@ -422,7 +422,7 @@ void DomainSettingsDialog::populateLocalStorageLabel() const
     switch (localStorageComboBoxPointer->currentIndex())
     {
         // Set the text according to the system default.
-        case (DomainsDatabaseHelper::SYSTEM_DEFAULT):
+        case (DomainsDatabase::SYSTEM_DEFAULT):
         {
             if (Settings::localStorageEnabled())
                 localStorageLabelPointer->setText(i18nc("Domain settings local storage label.", "Local storage enabled"));
@@ -433,7 +433,7 @@ void DomainSettingsDialog::populateLocalStorageLabel() const
         }
 
         // Set the disabled text in bold.
-        case (DomainsDatabaseHelper::DISABLED):
+        case (DomainsDatabase::DISABLED):
         {
             localStorageLabelPointer->setText(i18nc("Domain settings local storage label.  The <b> tags should be retained.", "<b>Local storage disabled</b>"));
 
@@ -441,7 +441,7 @@ void DomainSettingsDialog::populateLocalStorageLabel() const
         }
 
         // Set the enabled text in bold.
-        case (DomainsDatabaseHelper::ENABLED):
+        case (DomainsDatabase::ENABLED):
         {
             localStorageLabelPointer->setText(i18nc("Domain settings local storage label.  The <b> tabs should be retained.", "<b>Local storage enabled</b>"));
 
@@ -574,7 +574,7 @@ void DomainSettingsDialog::updateUi() const
 void DomainSettingsDialog::userAgentChanged(const QString &updatedUserAgent) const
 {
     // Update the domains table model.
-    domainsTableModelPointer->setData(domainsSelectionModelPointer->currentIndex().siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::USER_AGENT)),
+    domainsTableModelPointer->setData(domainsSelectionModelPointer->currentIndex().siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabase::USER_AGENT)),
                                       UserAgentHelper::getDatabaseUserAgentNameFromTranslatedName(updatedUserAgent));
 
     // Populate the user agent label.
@@ -590,7 +590,7 @@ void DomainSettingsDialog::zoomFactorComboBoxChanged(const int &newIndex) const
     QModelIndex modelIndex = domainsSelectionModelPointer->currentIndex();
 
     // Update the domains table model.
-    domainsTableModelPointer->setData(modelIndex.siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::ZOOM_FACTOR)), newIndex);
+    domainsTableModelPointer->setData(modelIndex.siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabase::ZOOM_FACTOR)), newIndex);
 
     // Populate the custom zoom factor spin box according to the zoom factor combo box.
     if (newIndex == 0)  // System default zoom factor is selected.
@@ -601,7 +601,7 @@ void DomainSettingsDialog::zoomFactorComboBoxChanged(const int &newIndex) const
     else  // Custom zoom factor is selected.
     {
         // Display the custom zoom factor from the domain settings.
-        customZoomFactorSpinBoxPointer->setValue(modelIndex.siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::CUSTOM_ZOOM_FACTOR)).data().toDouble());
+        customZoomFactorSpinBoxPointer->setValue(modelIndex.siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabase::CUSTOM_ZOOM_FACTOR)).data().toDouble());
     }
 
     // Update the status of the custom zoom factor spin box.
index df368ac244636de0a8f1b08ad7cb9d27d8e1c39f..042c5c37e0179a475c3175a80f49173c0c9ef336 100644 (file)
@@ -18,7 +18,6 @@
 
 # List the sources to include in the executable.
 target_sources(privacy-browser PRIVATE
-    DomainsDatabaseHelper.cpp
     SearchEngineHelper.cpp
     UserAgentHelper.cpp
 )
diff --git a/src/helpers/DomainsDatabaseHelper.cpp b/src/helpers/DomainsDatabaseHelper.cpp
deleted file mode 100644 (file)
index d1f8b22..0000000
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * Copyright © 2022 Soren Stoutner <soren@stoutner.com>.
- *
- * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc>.
- *
- * Privacy Browser PC is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Privacy Browser PC is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Privacy Browser PC.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-// Application headers.
-#include "DomainsDatabaseHelper.h"
-#include "UserAgentHelper.h"
-
-// Define the public static domain constants.
-const QString DomainsDatabaseHelper::CONNECTION_NAME = "domains_database";
-const QString DomainsDatabaseHelper::DOMAINS_TABLE = "domains";
-
-// Define the private static schema constants.
-const int DomainsDatabaseHelper::SCHEMA_VERSION = 5;
-
-// Define the public static database field names.
-const QString DomainsDatabaseHelper::_ID = "_id";
-const QString DomainsDatabaseHelper::DOMAIN_NAME = "domain_name";
-const QString DomainsDatabaseHelper::JAVASCRIPT = "javascript";
-const QString DomainsDatabaseHelper::LOCAL_STORAGE = "local_storage";
-const QString DomainsDatabaseHelper::DOM_STORAGE = "dom_storage";
-const QString DomainsDatabaseHelper::USER_AGENT = "user_agent";
-const QString DomainsDatabaseHelper::ZOOM_FACTOR = "zoom_factor";
-const QString DomainsDatabaseHelper::CUSTOM_ZOOM_FACTOR = "custom_zoom_factor";
-
-// Construct the class.
-DomainsDatabaseHelper::DomainsDatabaseHelper() {}
-
-void DomainsDatabaseHelper::addDatabase()
-{
-    // Add the domain settings database.
-    QSqlDatabase domainsDatabase = QSqlDatabase::addDatabase("QSQLITE", CONNECTION_NAME);
-
-    // Set the database name.
-    domainsDatabase.setDatabaseName(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/domains.db");
-
-    // Open the database.
-    if (domainsDatabase.open())  // Opening the database succeeded.
-    {
-        // Check to see if the domains table already exists.
-        if (domainsDatabase.tables().contains(DOMAINS_TABLE))
-        {
-            // Query the database schema version.
-            QSqlQuery getSchemaVersionQuery = domainsDatabase.exec("PRAGMA user_version");
-
-            // Move to the first record.
-            getSchemaVersionQuery.first();
-
-            // Get the current schema version.
-            int currentSchemaVersion = getSchemaVersionQuery.value(0).toInt();
-
-            // Check to see if the schama has been updated.
-            if (SCHEMA_VERSION > currentSchemaVersion)
-            {
-                // Run schema update code.
-                switch (currentSchemaVersion)
-                {
-                    // Upgrade from schema version 0 to schema version 1.
-                    case 0:
-                    {
-                        // Add the JavaScript column.
-                        domainsDatabase.exec("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + JAVASCRIPT + " INTEGER DEFAULT 0");
-
-                        // Fallthrough to the next case.
-                        [[fallthrough]];
-                    }
-
-                    // Upgrade from schema version 1 to schema version 2.
-                    case 1:
-                    {
-                        // Add the User Agent column.
-                        domainsDatabase.exec("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + USER_AGENT + " TEXT DEFAULT '" + UserAgentHelper::SYSTEM_DEFAULT_DATABASE + "'");
-
-                        // Fallthrough to the next case.
-                        [[fallthrough]];
-                    }
-
-                    // Upgrade from schema version 2 to schema version 3.
-                    case 2:
-                    {
-                        // Add the Zoom Factor columns.
-                        domainsDatabase.exec("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + ZOOM_FACTOR + " INTEGER DEFAULT 0");
-                        domainsDatabase.exec("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + CUSTOM_ZOOM_FACTOR + " REAL DEFAULT 1.0");
-
-                        // Fallthrough to the next case.
-                        [[fallthrough]];
-                    }
-
-                    // Upgrade from schema version 3 to schema version 4.
-                    case 3:
-                    {
-                        // Add the DOM Storage column.
-                        domainsDatabase.exec("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + DOM_STORAGE + " INTEGER DEFAULT 0");
-
-                        // Fallthrough to the next case.
-                        [[fallthrough]];
-                    }
-
-                    case 4:
-                    {
-                        // Add the Local Storage column.
-                        domainsDatabase.exec("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + LOCAL_STORAGE + " INTEGER DEFAULT 0");
-
-                        // Fallthrough to the next case.
-                        // [[fallthrough]];
-                    }
-                }
-
-                // Update the schema version.
-                domainsDatabase.exec("PRAGMA user_version = " + QString::number(SCHEMA_VERSION));
-            }
-        }
-        else
-        {
-            // Instantiate a create table query.
-            QSqlQuery createTableQuery(domainsDatabase);
-
-            // Prepare the create table query.
-            createTableQuery.prepare("CREATE TABLE " + DOMAINS_TABLE + "(" +
-                _ID + " INTEGER PRIMARY KEY, " +
-                DOMAIN_NAME + " TEXT, " +
-                JAVASCRIPT + " INTEGER DEFAULT 0, " +
-                LOCAL_STORAGE + " INTEGER DEFAULT 0, " +
-                DOM_STORAGE + " INTEGER DEFAULT 0, " +
-                USER_AGENT + " TEXT DEFAULT '" + UserAgentHelper::SYSTEM_DEFAULT_DATABASE + "', " +
-                ZOOM_FACTOR + " INTEGER DEFAULT 0, " +
-                CUSTOM_ZOOM_FACTOR + " REAL DEFAULT 1.0)"
-            );
-
-            // Execute the query.
-            if (!createTableQuery.exec())
-            {
-                // Log any errors.
-                qDebug().noquote().nospace() << "Error creating table:  " << domainsDatabase.lastError();
-            }
-
-            // Set the schema version.
-            domainsDatabase.exec("PRAGMA user_version = " + QString::number(SCHEMA_VERSION));
-        }
-    }
-    else  // Opening the database failed.
-    {
-        // Write the last database error message to the debug output.
-        qDebug().noquote().nospace() << "Error opening database:  " << domainsDatabase.lastError();
-    }
-};
-
-QSqlQuery DomainsDatabaseHelper::getDomainQuery(const QString &hostname)
-{
-    // Get a handle for the domains database.
-    QSqlDatabase domainsDatabase = QSqlDatabase::database(CONNECTION_NAME);
-
-    // Instantiate the all domain names query.
-    QSqlQuery allDomainNamesQuery(domainsDatabase);
-
-    // Set the query to be forward only (increases performance while iterating over the query).
-    allDomainNamesQuery.setForwardOnly(true);
-
-    // Prepare the query.
-    allDomainNamesQuery.prepare("SELECT " + _ID + "," + DOMAIN_NAME + " FROM " + DOMAINS_TABLE);
-
-    // Execute the query.
-    allDomainNamesQuery.exec();
-
-    // Create a domains settings map.
-    QMap<QString, int> domainSettingsMap;
-
-    // Populate the domain settings map.
-    while (allDomainNamesQuery.next())
-    {
-        // Add the domain name and database ID to the map.
-        domainSettingsMap.insert(allDomainNamesQuery.record().field(DomainsDatabaseHelper::DOMAIN_NAME).value().toString(),
-                                 allDomainNamesQuery.record().field(DomainsDatabaseHelper::_ID).value().toInt());
-    }
-
-    // Initialize the database ID tracker.
-    int databaseId = -1;
-
-    // Get the database ID if the hostname is found in the domain settings set.
-    if (domainSettingsMap.contains(hostname))
-    {
-        databaseId = domainSettingsMap.value(hostname);
-    }
-
-    // Create a subdomain string.
-    QString subdomain = hostname;
-
-    // Check all the subdomains of the hostname.
-    while ((databaseId == -1) && subdomain.contains("."))  // Stop checking when a match is found or there are no more `.` in the hostname.
-    {
-        // Check to see if the domain settings map contains the subdomain with a `*.` prepended.
-        if (domainSettingsMap.contains("*." + subdomain))
-        {
-            // Get the database ID.
-            databaseId = domainSettingsMap.value("*." + subdomain);
-        }
-
-        // Strip out the first subdomain.
-        subdomain = subdomain.section('.', 1);
-    }
-
-    // Instantiate the domain lookup query.
-    QSqlQuery domainLookupQuery(domainsDatabase);
-
-    // Prepare the domain lookup query.
-    domainLookupQuery.prepare("SELECT * FROM " + DOMAINS_TABLE + " WHERE " + _ID + " = " + QString::number(databaseId));
-
-    // Execute the query.
-    domainLookupQuery.exec();
-
-    // Move to the first entry.
-    domainLookupQuery.first();
-
-    // Return the query.
-    return domainLookupQuery;
-}
diff --git a/src/helpers/DomainsDatabaseHelper.h b/src/helpers/DomainsDatabaseHelper.h
deleted file mode 100644 (file)
index 50058db..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright © 2022 Soren Stoutner <soren@stoutner.com>.
- *
- * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc>.
- *
- * Privacy Browser PC is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Privacy Browser PC is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Privacy Browser PC.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef DOMAINSDATABASEHELPER_H
-#define DOMAINSDATABASEHELPER_H
-
-// Qt framework headers.
-#include <QtSql>
-
-class DomainsDatabaseHelper
-{
-public:
-    // The default constructor.
-    DomainsDatabaseHelper();
-
-    // The public functions.
-    static void addDatabase();
-    static QSqlQuery getDomainQuery(const QString &hostname);
-
-    // The public int constants.
-    static const int SYSTEM_DEFAULT = 0;
-    static const int DISABLED = 1;
-    static const int ENABLED = 2;
-    static const int CUSTOM = 1;
-
-    // The public constants.
-    static const QString _ID;
-    static const QString CONNECTION_NAME;
-    static const QString CUSTOM_ZOOM_FACTOR;
-    static const QString DOM_STORAGE;
-    static const QString DOMAIN_NAME;
-    static const QString DOMAINS_TABLE;
-    static const QString JAVASCRIPT;
-    static const QString LOCAL_STORAGE;
-    static const QString USER_AGENT;
-    static const QString ZOOM_FACTOR;
-
-private:
-    // The private static constants.
-    static const int SCHEMA_VERSION;
-};
-#endif
index 6aa5c51a28c3eaf9c5aa443cd92667a5aa31a17c..10ce579ca39829f90c6046fcc0ca560483aaa087 100644 (file)
@@ -18,7 +18,8 @@
  */
 
 // Application headers.
-#include "helpers/DomainsDatabaseHelper.h"
+#include "databases/CookiesDatabase.h"
+#include "databases/DomainsDatabase.h"
 #include "windows/BrowserWindow.h"
 
 // KDE Frameworks headers.
@@ -80,8 +81,9 @@ int main(int argc, char *argv[])
     // Register with D-Bus, allowing multiple instances and allowing the program to run if for some reason the registration fails.
     KDBusService appDBusService(KDBusService::Multiple | KDBusService::NoExitOnFailure);
 
-    // Add the domains database.
-    DomainsDatabaseHelper::addDatabase();
+    // Add the databases.
+    DomainsDatabase::addDatabase();
+    CookiesDatabase::addDatabase();
 
     // Create the main window.
     BrowserWindow *browserWindowPointer = new BrowserWindow();
index adeaa4ee8887cbd9cbc7b5d6135984be74c79928..3595e741af800902ad792101fba358d7a51f7ca5 100644 (file)
                         <enum>Qt::AlignLeft</enum>
                     </property>
 
+                    <!-- Durable. -->
+                    <item>
+                        <widget class="QCheckBox" name="durableCheckBox">
+                            <property name="toolTip">
+                                <string>Durable cookies pursist across restarts, irrespective of the expiration date. All other cookies are deleted when Privacy Browser closes, irrespective of the expiration date.</string>
+                            </property>
+                        </widget>
+                    </item>
+
+                    <item>
+                        <widget class="QLabel">
+                            <property name="text">
+                                <string>Durable</string>
+                            </property>
+
+                            <property name="toolTip">
+                                <string>Durable cookies pursist across restarts, irrespective of the expiration date. All other cookies are deleted when Privacy Browser closes, irrespective of the expiration date.</string>
+                            </property>
+                        </widget>
+                    </item>
+
+                    <item>
+                        <widget class="QLabel">
+                            <property name="textFormat">
+                                <enum>Qt::RichText</enum>
+                            </property>
+
+                            <!-- Spacer label. -->
+                            <property name="text">
+                                <string>&amp;nbsp;&amp;nbsp;&amp;nbsp;</string>
+                            </property>
+                        </widget>
+                    </item>
+
                     <!-- Path. -->
                     <item>
                         <widget class="QLabel">
 
                     <item>
                         <widget class="QLabel">
-                            <property name="toolTip">
-                                <string>Cookies without an expiration date are known as session cookies and are expected to be deleted every time the browser closes.</string>
-                            </property>
-
                             <property name="text">
                                 <string>Expiration date</string>
                             </property>
+
+                            <property name="toolTip">
+                                <string>Cookies without an expiration date are known as session cookies and are expected to be deleted every time the browser closes.</string>
+                            </property>
                         </widget>
                     </item>
 
 
                     <item>
                         <widget class="QLabel">
-                            <property name="toolTip">
-                                <string>Restrict cookie access to HTTP (and HTTPS). This prevents JavaScript from accessing the cookie, which hardens it against cross-site scripting attacks.</string>
-                            </property>
-
                             <property name="text">
                                 <string>HTTP only</string>
                             </property>
+
+                            <property name="toolTip">
+                                <string>Restrict cookie access to HTTP (and HTTPS). This prevents JavaScript from accessing the cookie, which hardens it against cross-site scripting attacks.</string>
+                            </property>
                         </widget>
                     </item>
 
 
                     <item>
                         <widget class="QLabel">
-                            <property name="toolTip">
-                                <string>Only allow the cookie to be transferred across HTTPS (as opposed to HTTP).</string>
-                            </property>
-
                             <property name="text">
                                 <string>Secure</string>
                             </property>
+
+                            <property name="toolTip">
+                                <string>Only allow the cookie to be transferred across HTTPS (as opposed to HTTP).</string>
+                            </property>
                         </widget>
                     </item>
                 </layout>
index 440c694ab02a7ca130bfc58dbeb85ba9fa2a1b8b..591e16aa3ae44361e6f43c70d40b20d51af406fe 100644 (file)
@@ -21,8 +21,9 @@
 #include "BrowserView.h"
 #include "Settings.h"
 #include "ui_BrowserView.h"
+#include "databases/CookiesDatabase.h"
+#include "databases/DomainsDatabase.h"
 #include "filters/MouseEventFilter.h"
-#include "helpers/DomainsDatabaseHelper.h"
 #include "helpers/SearchEngineHelper.h"
 #include "helpers/UserAgentHelper.h"
 #include "interceptors/UrlRequestInterceptor.h"
@@ -94,6 +95,13 @@ BrowserView::BrowserView(QWidget *parent) : QWidget(parent)
     connect(webEngineCookieStorePointer, SIGNAL(cookieAdded(QNetworkCookie)), this, SLOT(cookieAdded(QNetworkCookie)));
     connect(webEngineCookieStorePointer, SIGNAL(cookieRemoved(QNetworkCookie)), this, SLOT(cookieRemoved(QNetworkCookie)));
 
+    // Get a list of durable cookies.
+    QList<QNetworkCookie*> *durableCookiesListPointer = CookiesDatabase::getCookies();
+
+    // Add the durable cookies to the store.
+    for (QNetworkCookie *cookiePointer : *durableCookiesListPointer)
+        addCookieToStore(*cookiePointer);
+
     // Store a copy of the WebEngine default user agent.
     webEngineDefaultUserAgent = webEngineProfilePointer->httpUserAgent();
 
@@ -152,7 +160,8 @@ BrowserView::~BrowserView()
     webEnginePagePointer->deleteLater();
 }
 
-void BrowserView::addCookieToStore(QNetworkCookie &cookie) const
+// The cookie is copied instead of referenced so that changes made to the cookie do not create a race condition with the display of the cookie in the dialog.
+void BrowserView::addCookieToStore(QNetworkCookie cookie) const
 {
     // Create a url.
     QUrl url;
@@ -201,7 +210,7 @@ void BrowserView::applyDomainSettingsWithoutReloading(const QString &hostname)
 void BrowserView::applyDomainSettings(const QString &hostname, const bool reloadWebsite)
 {
     // Get the record for the hostname.
-    QSqlQuery domainQuery = DomainsDatabaseHelper::getDomainQuery(hostname);
+    QSqlQuery domainQuery = DomainsDatabase::getDomainQuery(hostname);
 
     // Check if the hostname has domain settings.
     if (domainQuery.isValid())  // The hostname has domain settings.
@@ -210,10 +219,10 @@ void BrowserView::applyDomainSettings(const QString &hostname, const bool reload
         QSqlRecord domainRecord = domainQuery.record();
 
         // Set the JavaScript status.
-        switch (domainRecord.field(DomainsDatabaseHelper::JAVASCRIPT).value().toInt())
+        switch (domainRecord.field(DomainsDatabase::JAVASCRIPT).value().toInt())
         {
             // Set the default JavaScript status.
-            case (DomainsDatabaseHelper::SYSTEM_DEFAULT):
+            case (DomainsDatabase::SYSTEM_DEFAULT):
             {
                 webEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, Settings::javaScriptEnabled());
 
@@ -221,7 +230,7 @@ void BrowserView::applyDomainSettings(const QString &hostname, const bool reload
             }
 
             // Disable JavaScript.
-            case (DomainsDatabaseHelper::DISABLED):
+            case (DomainsDatabase::DISABLED):
             {
                 webEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, false);
 
@@ -229,7 +238,7 @@ void BrowserView::applyDomainSettings(const QString &hostname, const bool reload
             }
 
             // Enable JavaScript.
-            case (DomainsDatabaseHelper::ENABLED):
+            case (DomainsDatabase::ENABLED):
             {
                 webEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, true);
 
@@ -238,10 +247,10 @@ void BrowserView::applyDomainSettings(const QString &hostname, const bool reload
         }
 
         // Set the local storage status.
-        switch (domainRecord.field(DomainsDatabaseHelper::LOCAL_STORAGE).value().toInt())
+        switch (domainRecord.field(DomainsDatabase::LOCAL_STORAGE).value().toInt())
         {
             // Set the default local storage status.
-            case (DomainsDatabaseHelper::SYSTEM_DEFAULT):
+            case (DomainsDatabase::SYSTEM_DEFAULT):
             {
                 currentPrivacyWebEnginePointer->localStorageEnabled = Settings::localStorageEnabled();
 
@@ -249,7 +258,7 @@ void BrowserView::applyDomainSettings(const QString &hostname, const bool reload
             }
 
             // Disable local storage.
-            case (DomainsDatabaseHelper::DISABLED):
+            case (DomainsDatabase::DISABLED):
             {
                 currentPrivacyWebEnginePointer->localStorageEnabled = false;
 
@@ -257,7 +266,7 @@ void BrowserView::applyDomainSettings(const QString &hostname, const bool reload
             }
 
             // Enable local storage.
-            case (DomainsDatabaseHelper::ENABLED):
+            case (DomainsDatabase::ENABLED):
             {
                 currentPrivacyWebEnginePointer->localStorageEnabled = true;
 
@@ -266,10 +275,10 @@ void BrowserView::applyDomainSettings(const QString &hostname, const bool reload
         }
 
         // Set the DOM storage status.
-        switch (domainRecord.field(DomainsDatabaseHelper::DOM_STORAGE).value().toInt())
+        switch (domainRecord.field(DomainsDatabase::DOM_STORAGE).value().toInt())
         {
             // Set the default DOM storage status.
-            case (DomainsDatabaseHelper::SYSTEM_DEFAULT):
+            case (DomainsDatabase::SYSTEM_DEFAULT):
             {
                 webEngineSettingsPointer->setAttribute(QWebEngineSettings::LocalStorageEnabled, Settings::domStorageEnabled());
 
@@ -277,7 +286,7 @@ void BrowserView::applyDomainSettings(const QString &hostname, const bool reload
             }
 
             // Disable DOM storage.
-            case (DomainsDatabaseHelper::DISABLED):
+            case (DomainsDatabase::DISABLED):
             {
                 webEngineSettingsPointer->setAttribute(QWebEngineSettings::LocalStorageEnabled, false);
 
@@ -285,7 +294,7 @@ void BrowserView::applyDomainSettings(const QString &hostname, const bool reload
             }
 
             // Enable DOM storage.
-            case (DomainsDatabaseHelper::ENABLED):
+            case (DomainsDatabase::ENABLED):
             {
                 webEngineSettingsPointer->setAttribute(QWebEngineSettings::LocalStorageEnabled, true);
 
@@ -294,13 +303,13 @@ void BrowserView::applyDomainSettings(const QString &hostname, const bool reload
         }
 
         // Set the user agent.
-        webEngineProfilePointer->setHttpUserAgent(UserAgentHelper::getResultingDomainSettingsUserAgent(domainRecord.field(DomainsDatabaseHelper::USER_AGENT).value().toString()));
+        webEngineProfilePointer->setHttpUserAgent(UserAgentHelper::getResultingDomainSettingsUserAgent(domainRecord.field(DomainsDatabase::USER_AGENT).value().toString()));
 
         // Check if a custom zoom factor is set.
-        if (domainRecord.field(DomainsDatabaseHelper::ZOOM_FACTOR).value().toInt())
+        if (domainRecord.field(DomainsDatabase::ZOOM_FACTOR).value().toInt())
         {
             // Store the current zoom factor.
-            currentZoomFactor = domainRecord.field(DomainsDatabaseHelper::CUSTOM_ZOOM_FACTOR).value().toDouble();
+            currentZoomFactor = domainRecord.field(DomainsDatabase::CUSTOM_ZOOM_FACTOR).value().toDouble();
         }
         else
         {
@@ -312,7 +321,7 @@ void BrowserView::applyDomainSettings(const QString &hostname, const bool reload
         webEngineViewPointer->setZoomFactor(currentZoomFactor);
 
         // Apply the domain settings palette to the URL line edit.
-        emit updateDomainSettingsIndicator(true, domainRecord.field(DomainsDatabaseHelper::DOMAIN_NAME).value().toString());
+        emit updateDomainSettingsIndicator(true, domainRecord.field(DomainsDatabase::DOMAIN_NAME).value().toString());
     }
     else  // The hostname does not have domain settings.
     {
index 859a93f2ee27c6c0d72e69497461d16236a39e49..93966321440c51e40c993f2b38305581c118603e 100644 (file)
@@ -76,7 +76,7 @@ signals:
 
 public Q_SLOTS:
     // The public slots.
-    void addCookieToStore(QNetworkCookie &cookie) const;
+    void addCookieToStore(QNetworkCookie cookie) const;
     void applyApplicationSettings();
     void applyDomainSettingsAndReload();
     void applyDomainSettingsWithoutReloading(const QString &hostname);
index 60ddaa4d6e2f31ca8fe62a1ad3778c76537e31b3..4a61438f1f8a9402d567a83beed3330a27199a90 100644 (file)
@@ -22,6 +22,7 @@
 #include "Settings.h"
 #include "ui_SettingsPrivacy.h"
 #include "ui_SettingsGeneral.h"
+#include "databases/CookiesDatabase.h"
 #include "dialogs/CookiesDialog.h"
 #include "dialogs/DomainSettingsDialog.h"
 #include "helpers/SearchEngineHelper.h"
@@ -268,6 +269,10 @@ void BrowserWindow::addCookieToList(const QNetworkCookie &newCookie) const
 
     // Update the action text.
     cookiesActionPointer->setText(i18nc("The Cookies action, which also displays the number of cookies", "Cookies - %1", cookieListPointer->size()));
+
+    // Update the cookie if it is durable and has new data.
+    if (CookiesDatabase::isUpdate(newCookie))
+        CookiesDatabase::updateCookie(newCookie);
 }
 
 void BrowserWindow::addOrEditDomainSettings() const