Fri, 07 Feb 2025 00:14:03 -0600
Replace the Purple.Sqlite3 API with Seagull
Seagull is our new SQLite3 utility library which will be expanded in the near
future.
Testing Done:
Ran in the devenv and built and ran the flatpak as well.
Reviewed at https://reviews.imfreedom.org/r/3821/
--- a/im.pidgin.Pidgin3.yml Thu Feb 06 20:29:19 2025 -0600 +++ b/im.pidgin.Pidgin3.yml Fri Feb 07 00:14:03 2025 -0600 @@ -95,6 +95,15 @@ archive-type: tar-xz url: https://sourceforge.net/projects/pidgin/files/gplugin/0.44.2/gplugin-0.44.2.tar.xz/download sha256: aea244e1add9628b50ec042c54cf93803f4577f8f142678f09b91fd4c0b20f72 + - name: seagull + buildsystem: meson + config-opts: + - "--wrap-mode=nofallback" + sources: + - type: archive + archive-type: tar-xz + url: https://sourceforge.net/projects/pidgin/files/seagull/0.1.1/seagull-0.1.1.tar.xz + sha256: 499fc45b6a8539bc2293b362fec1c847fe25697355a0572f07ace3f359a38873 - name: pidgin3 buildsystem: meson config-opts:
--- a/libpurple/meson.build Thu Feb 06 20:29:19 2025 -0600 +++ b/libpurple/meson.build Fri Feb 07 00:14:03 2025 -0600 @@ -70,7 +70,6 @@ 'purpleprotocolwhiteboard.c', 'purpleproxyinfo.c', 'purplesavedpresence.c', - 'purplesqlite3.c', 'purplesqlitehistoryadapter.c', 'purpletags.c', 'purpleui.c', @@ -166,7 +165,6 @@ 'purpleprotocolwhiteboard.h', 'purpleproxyinfo.h', 'purplesavedpresence.h', - 'purplesqlite3.h', 'purplesqlitehistoryadapter.h', 'purpletags.h', 'purpletyping.h', @@ -312,7 +310,7 @@ dependencies : # static_link_libs [dnsapi, ws2_32, glib, gio, gplugin_dep, libsoup, libxml, gdk_pixbuf, gstreamer, gstreamer_app, json, - sqlite3, math, birb_dep]) + seagull_dep, sqlite3, math, birb_dep]) install_headers(purple_coreheaders, subdir : purple_include_base)
--- a/libpurple/purplesqlite3.c Thu Feb 06 20:29:19 2025 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,211 +0,0 @@ -/* - * Purple - Internet Messaging Library - * Copyright (C) Pidgin Developers <devel@pidgin.im> - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This library 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 2 of the License, or (at your option) - * any later version. - * - * This library 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 - * this library; if not, see <https://www.gnu.org/licenses/>. - */ - -#include <gio/gio.h> - -#include <sqlite3.h> - -#include "purplesqlite3.h" - -/****************************************************************************** - * Helpers - *****************************************************************************/ -static gboolean -purple_sqlite3_run_migration(sqlite3 *db, int version, const char *migration, - GError **error) -{ - char *errmsg = NULL; - char *str = NULL; - gboolean success = TRUE; - - str = g_strdup_printf("BEGIN;%s;PRAGMA user_version=%d;COMMIT;", migration, - version); - - sqlite3_exec(db, str, NULL, NULL, &errmsg); - if(errmsg != NULL) { - g_set_error(error, PURPLE_SQLITE3_DOMAIN, 0, - "failed to run migration: %s", errmsg); - - sqlite3_free(errmsg); - - sqlite3_exec(db, "ROLLBACK", NULL, NULL, &errmsg); - if(errmsg != NULL) { - g_error("failed to rollback transaction: %s", errmsg); - - sqlite3_free(errmsg); - } - - success = FALSE; - } - - g_free(str); - - return success; -} - -/****************************************************************************** - * Public API - *****************************************************************************/ -int -purple_sqlite3_get_schema_version(sqlite3 *db, GError **error) { - sqlite3_stmt *stmt = NULL; - int version = -1; - - g_return_val_if_fail(db != NULL, -1); - - sqlite3_prepare_v2(db, "PRAGMA user_version", -1, &stmt, NULL); - - if(stmt == NULL) { - g_set_error(error, PURPLE_SQLITE3_DOMAIN, 0, - "error while creating prepared statement: %s", - sqlite3_errmsg(db)); - - return -1; - } - - if(sqlite3_step(stmt) == SQLITE_ROW) { - version = sqlite3_column_int(stmt, 0); - } else { - g_set_error_literal(error, PURPLE_SQLITE3_DOMAIN, 0, - "'PRAGMA user_version' didn't return a row"); - - sqlite3_finalize(stmt); - - return -1; - } - - sqlite3_finalize(stmt); - - return version; -} - -gboolean -purple_sqlite3_run_migrations_from_strings(sqlite3 *db, - const char *migrations[], - GError **error) -{ - int current_version = 0; - guint n_migrations = 0; - - g_return_val_if_fail(db != NULL, FALSE); - g_return_val_if_fail(migrations != NULL, FALSE); - - /* Get the current version or bail if it failed. */ - current_version = purple_sqlite3_get_schema_version(db, error); - if(current_version == -1) { - return FALSE; - } - - n_migrations = g_strv_length((char **)migrations); - if((guint)current_version > n_migrations) { - g_set_error(error, PURPLE_SQLITE3_DOMAIN, 0, - "schema version %u is higher than known migrations %u", - (guint)current_version, n_migrations); - - return FALSE; - } - - for(int i = current_version; migrations[i] != NULL; i++) { - int version = i + 1; - - if(!purple_sqlite3_run_migration(db, version, migrations[i], error)) { - return FALSE; - } - } - - return TRUE; -} - -gboolean -purple_sqlite3_run_migrations_from_resources(sqlite3 *db, const char *path, - const char *migrations[], - GError **error) -{ - GError *local_error = NULL; - int current_version = 0; - guint n_migrations = 0; - - g_return_val_if_fail(db != NULL, FALSE); - g_return_val_if_fail(path != NULL, FALSE); - g_return_val_if_fail(migrations != NULL, FALSE); - - /* Get the current version or bail if it failed. */ - current_version = purple_sqlite3_get_schema_version(db, error); - if(current_version == -1) { - return FALSE; - } - - n_migrations = g_strv_length((char **)migrations); - if((guint)current_version > n_migrations) { - g_set_error(error, PURPLE_SQLITE3_DOMAIN, 0, - "schema version %u is higher than known migrations %u", - (guint)current_version, n_migrations); - - return FALSE; - } - - /* `PRAGMA user_version` starts at 0, so write our version as i + 1. We - * start iterating the list of migrations at the current version of the - * database. If the database is already up to date, then current_version - * will point us at the null terminator in the list of migrations, which - * will short circuit the for loop. - */ - for(int i = current_version; migrations[i] != NULL; i++) { - GBytes *data = NULL; - char *full_path = NULL; - const gchar *migration = NULL; - int version = i + 1; - - /* Get the data from the resource */ - full_path = g_build_path("/", path, migrations[i], NULL); - - data = g_resources_lookup_data(full_path, G_RESOURCE_LOOKUP_FLAGS_NONE, - &local_error); - if(data == NULL || local_error != NULL) { - if(local_error == NULL) { - local_error = g_error_new(PURPLE_SQLITE3_DOMAIN, 0, - "failed to load resource %s", - full_path); - } - - g_propagate_error(error, local_error); - - g_clear_pointer(&data, g_bytes_unref); - g_free(full_path); - - return FALSE; - } - - g_free(full_path); - - migration = (const char *)g_bytes_get_data(data, NULL); - if(!purple_sqlite3_run_migration(db, version, migration, error)) { - g_bytes_unref(data); - - return FALSE; - } - - g_bytes_unref(data); - } - - return TRUE; -}
--- a/libpurple/purplesqlite3.h Thu Feb 06 20:29:19 2025 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,154 +0,0 @@ -/* - * Purple - Internet Messaging Library - * Copyright (C) Pidgin Developers <devel@pidgin.im> - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This library 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 2 of the License, or (at your option) - * any later version. - * - * This library 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 - * this library; if not, see <https://www.gnu.org/licenses/>. - */ - -#if !defined(PURPLE_GLOBAL_HEADER_INSIDE) && !defined(PURPLE_COMPILATION) -# error "only <purple.h> may be included directly" -#endif - -#ifndef PURPLE_SQLITE3_H -#define PURPLE_SQLITE3_H - -#include <glib.h> -#include <gio/gio.h> - -#include "purpleversion.h" - -G_BEGIN_DECLS - -/** - * PURPLE_SQLITE3_ERROR: - * - * An error domain for sqlite3 errors. - * - * Since: 3.0 - */ -#define PURPLE_SQLITE3_DOMAIN \ - g_quark_from_static_string("sqlite3") \ - PURPLE_AVAILABLE_MACRO_IN_3_0 - -/** - * PurpleSqlite3: - * - * A sqlite3 connection. - * - * This type alias exists to avoid requiring the sqlite3 header, but is no - * different from the `sqlite3` type. - * - * If that header is included first, this will be exactly equivalent, otherwise - * it will be a generic `gpointer`, which you should cast to a `sqlite3`. - * - * Since: 3.0 - */ -PURPLE_AVAILABLE_TYPE_IN_3_0 -#ifdef SQLITE_API -typedef sqlite3 PurpleSqlite3; -#else -typedef gpointer PurpleSqlite3; -#endif - -/** - * purple_sqlite3_get_schema_version: - * @db: The sqlite3 connection. - * @error: Return address for a #GError, or %NULL. - * - * Attempts to read the result of `PRAGMA user_version` which this API uses to - * store the schema version. - * - * Returns: %TRUE on success, or %FALSE on error with @error set. - * - * Since: 3.0 - */ -PURPLE_AVAILABLE_IN_3_0 -int purple_sqlite3_get_schema_version(PurpleSqlite3 *db, GError **error); - -/** - * purple_sqlite3_run_migrations_from_strings: - * @db: The sqlite3 connection. - * @migrations: (array zero-terminated=1): A list of SQL statements, each item - * being its own migration. - * @error: Return address for a #GError, or %NULL. - * - * Runs the given migrations in the order they are given. The index of each - * migration plus 1 is assumed is to be the version number of the migration, - * which means that you can not change the order of the migrations. The - * reasoning for the addition of 1 is because `PRAGMA user_version` defaults to - * 0. - * - * This expects each string in @migrations to be a complete migration. That is, - * each string in the array should contain all of the SQL for that migration. - * For example, if you're expecting to have 2 migrations, the initial creating - * two tables, and then adding a column to one of the existing tables, you - * would have something like the following code. - * - * ```c - * const char *migrations[] = { - * // Our initial migration that creates user and session tables. - * "CREATE TABLE user(id INTEGER PRIMARY KEY, name TEXT);" - * "CREATE TABLE session(user INTEGER, token TEXT) FOREIGN KEY(user) REFERENCES user(id);", - * // Begin our second migration that will add a display name to the user - * // table. Note the ',' at the end of the previous line. - * "ALTER TABLE user ADD COLUMN(display_name TEXT);", - * NULL - * }; - * ``` - * - * Also, this function will run each migration in its own transaction so you - * don't need to worry about them. This is done to make sure that the database - * stays at a known version and an incomplete migration will not be saved. - * - * Returns: %TRUE on success, or %FALSE on error potentially with @error set. - * - * Since: 3.0 - */ -PURPLE_AVAILABLE_IN_3_0 -gboolean purple_sqlite3_run_migrations_from_strings(PurpleSqlite3 *db, const char *migrations[], GError **error); - -/** - * purple_sqlite3_run_migrations_from_resources: - * @db: The sqlite3 connection. - * @path: The base path in @resource to use. - * @migrations: (array zero-terminated=1): The list of migrations in the order - * to run them. - * @error: Return address for a #GError, or %NULL. - * - * Runs the given migrations in the order they are given. The index of each - * migration plus 1 is assumed to be the version number of the migration, which - * means that you can not change the order of the migrations. The reasoning for - * the addition of 1 is because `PRAGMA user_version` defaults to 0. - * - * This will attempt to load the migrations via - * [func@Gio.resources_open_stream] by concatenating @path and the individual - * items of @migrations. Each migration will be ran in a transaction that - * includes updating the schema version, which is stored in - * `PRAGMA user_version`. This means you can't use `PRAGMA user_version` for - * other things. - * - * Returns: %TRUE on success, or %FALSE on error potentially with @error set. - * - * Since: 3.0 - */ -PURPLE_AVAILABLE_IN_3_0 -gboolean purple_sqlite3_run_migrations_from_resources(PurpleSqlite3 *db, const char *path, const char *migrations[], GError **error); - -G_END_DECLS - -#endif /* PURPLE_SQLITE3_H */
--- a/libpurple/purplesqlitehistoryadapter.c Thu Feb 06 20:29:19 2025 -0600 +++ b/libpurple/purplesqlitehistoryadapter.c Fri Feb 07 00:14:03 2025 -0600 @@ -23,6 +23,7 @@ #include <glib/gi18n-lib.h> #include <sqlite3.h> +#include <seagull.h> #include "purplesqlitehistoryadapter.h" @@ -31,7 +32,6 @@ #include "purpleconversationmanager.h" #include "purpleconversationmember.h" #include "purpleconversationmembers.h" -#include "purplesqlite3.h" struct _PurpleSqliteHistoryAdapter { PurpleHistoryAdapter parent; @@ -72,8 +72,8 @@ NULL }; - return purple_sqlite3_run_migrations_from_resources(adapter->db, path, - migrations, error); + return seagull_migrations_run_from_resources(adapter->db, path, migrations, + error); } static sqlite3_stmt *
--- a/libpurple/tests/meson.build Thu Feb 06 20:29:19 2025 -0600 +++ b/libpurple/tests/meson.build Fri Feb 07 00:14:03 2025 -0600 @@ -90,4 +90,3 @@ endforeach subdir('avatar') -subdir('sqlite3')
--- a/libpurple/tests/sqlite3/initial.sql Thu Feb 06 20:29:19 2025 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -CREATE TABLE foo(a TEXT); -CREATE TABLE bar(b TEXT); \ No newline at end of file
--- a/libpurple/tests/sqlite3/malformed.sql Thu Feb 06 20:29:19 2025 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -CREATE TABLE foo(a TEXT; \ No newline at end of file
--- a/libpurple/tests/sqlite3/meson.build Thu Feb 06 20:29:19 2025 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,16 +0,0 @@ -TEST_SQLITE3_SOURCES = [ - 'test_sqlite3.c' -] - -TEST_SQLITE3_RESOURCES = gnome.compile_resources('test_sqlite3_resources', - 'test_sqlite3.gresource.xml', - source_dir : '.', - c_name : 'test_sqlite3') -TEST_SQLITE3_SOURCES += TEST_SQLITE3_RESOURCES - -test_sqlite3 = executable( - 'test_sqlite3', - TEST_SQLITE3_SOURCES, - dependencies : [libpurple_dep, glib, sqlite3]) - -test('sqlite3', test_sqlite3)
--- a/libpurple/tests/sqlite3/secondary.sql Thu Feb 06 20:29:19 2025 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -CREATE TABLE baz(c TEXT); \ No newline at end of file
--- a/libpurple/tests/sqlite3/test_sqlite3.c Thu Feb 06 20:29:19 2025 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,477 +0,0 @@ -/* - * Purple - Internet Messaging Library - * Copyright (C) Pidgin Developers <devel@pidgin.im> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <https://www.gnu.org/licenses/>. - */ - -#include <glib.h> - -#include <sqlite3.h> - -#include <purple.h> - -/****************************************************************************** - * get schema version tests - *****************************************************************************/ -static void -test_sqlite3_get_schema_version_null(void) { - if(g_test_subprocess()) { - GError *error = NULL; - int version = 0; - - version = purple_sqlite3_get_schema_version(NULL, &error); - g_assert_error(error, PURPLE_SQLITE3_DOMAIN, 0); - g_clear_error(&error); - g_assert_cmpint(version, ==, -1); - } - - g_test_trap_subprocess(NULL, 0, 0); - g_test_trap_assert_failed(); - g_test_trap_assert_stderr("*assertion*!= NULL*"); -} - -static void -test_sqlite3_get_schema_version_new(void) { - GError *error = NULL; - sqlite3 *db = NULL; - int rc = 0; - int version = 0; - - rc = sqlite3_open(":memory:", &db); - g_assert_nonnull(db); - g_assert_cmpint(rc, ==, SQLITE_OK); - - version = purple_sqlite3_get_schema_version(db, &error); - g_assert_no_error(error); - g_assert_cmpint(version, ==, 0); - - rc = sqlite3_close(db); - g_assert_cmpint(rc, ==, SQLITE_OK); -} - -/****************************************************************************** - * string migration tests - *****************************************************************************/ -static void -test_sqlite3_string_migrations_null(void) { - if(g_test_subprocess()) { - GError *error = NULL; - sqlite3 *db = NULL; - gboolean res = FALSE; - int rc = 0; - - rc = sqlite3_open(":memory:", &db); - g_assert_nonnull(db); - g_assert_cmpint(rc, ==, SQLITE_OK); - - res = purple_sqlite3_run_migrations_from_strings(db, NULL, &error); - g_assert_no_error(error); - g_assert_false(res); - } - - g_test_trap_subprocess(NULL, 0, 0); - g_test_trap_assert_failed(); - g_test_trap_assert_stderr("*migrations != NULL*"); -} - -static void -test_sqlite3_string_migrations_null_terminator(void) { - GError *error = NULL; - sqlite3 *db = NULL; - gboolean res = FALSE; - int rc = 0; - int version = -1; - const char *migrations[] = {NULL}; - - rc = sqlite3_open(":memory:", &db); - g_assert_nonnull(db); - g_assert_cmpint(rc, ==, SQLITE_OK); - - res = purple_sqlite3_run_migrations_from_strings(db, migrations, &error); - g_assert_no_error(error); - g_assert_true(res); - - version = purple_sqlite3_get_schema_version(db, &error); - g_assert_no_error(error); - g_assert_cmpint(version, ==, 0); - - rc = sqlite3_close(db); - g_assert_cmpint(rc, ==, SQLITE_OK); -} - -static void -test_sqlite3_string_migrations_multiple(void) { - GError *error = NULL; - sqlite3 *db = NULL; - gboolean res = FALSE; - int rc = 0; - int version = -1; - const char *migrations[] = { - "CREATE TABLE foo(a TEXT); CREATE TABLE bar(b TEXT);", - "CREATE TABLE baz(c TEXT);", - NULL - }; - - rc = sqlite3_open(":memory:", &db); - g_assert_nonnull(db); - g_assert_cmpint(rc, ==, SQLITE_OK); - - res = purple_sqlite3_run_migrations_from_strings(db, migrations, &error); - g_assert_no_error(error); - g_assert_true(res); - - version = purple_sqlite3_get_schema_version(db, &error); - g_assert_no_error(error); - g_assert_cmpint(version, ==, 2); - - /* Run the migrations again and make sure we remain at schema version 2. */ - res = purple_sqlite3_run_migrations_from_strings(db, migrations, &error); - g_assert_no_error(error); - g_assert_true(res); - - version = purple_sqlite3_get_schema_version(db, &error); - g_assert_no_error(error); - g_assert_cmpint(version, ==, 2); - - rc = sqlite3_close(db); - g_assert_cmpint(rc, ==, SQLITE_OK); -} - -static void -test_sqlite3_string_migrations_syntax_error(void) { - GError *error = NULL; - sqlite3 *db = NULL; - gboolean res = FALSE; - int rc = 0; - int version = -1; - const char *migrations[] = { - "CREATE TABLE broke(a TEXT", - NULL - }; - - rc = sqlite3_open(":memory:", &db); - g_assert_nonnull(db); - g_assert_cmpint(rc, ==, SQLITE_OK); - - res = purple_sqlite3_run_migrations_from_strings(db, migrations, &error); - g_assert_error(error, PURPLE_SQLITE3_DOMAIN, 0); - g_clear_error(&error); - g_assert_false(res); - - version = purple_sqlite3_get_schema_version(db, &error); - g_assert_no_error(error); - g_assert_cmpint(version, ==, 0); - - rc = sqlite3_close(db); - g_assert_cmpint(rc, ==, SQLITE_OK); -} - -static void -test_sqlite3_string_migrations_older(void) { - GError *error = NULL; - sqlite3 *db = NULL; - gboolean res = FALSE; - int rc = 0; - int version = -1; - const char *migrations1[] = { - "CREATE TABLE foo(a TEXT); CREATE TABLE bar(b TEXT);", - "CREATE TABLE baz(c TEXT);", - NULL - }; - const char *migrations2[] = { - "CREATE TABLE foo(a TEXT); CREATE TABLE bar(b TEXT);", - NULL - }; - - rc = sqlite3_open(":memory:", &db); - g_assert_nonnull(db); - g_assert_cmpint(rc, ==, SQLITE_OK); - - res = purple_sqlite3_run_migrations_from_strings(db, migrations1, &error); - g_assert_no_error(error); - g_assert_true(res); - - version = purple_sqlite3_get_schema_version(db, &error); - g_assert_no_error(error); - g_assert_cmpint(version, ==, 2); - - /* Run the older migrations now and verify we get a failure. */ - res = purple_sqlite3_run_migrations_from_strings(db, migrations2, &error); - g_assert_error(error, PURPLE_SQLITE3_DOMAIN, 0); - g_clear_error(&error); - g_assert_false(res); - - version = purple_sqlite3_get_schema_version(db, &error); - g_assert_no_error(error); - g_assert_cmpint(version, ==, 2); - - rc = sqlite3_close(db); - g_assert_cmpint(rc, ==, SQLITE_OK); -} - -/****************************************************************************** - * resource migration tests - *****************************************************************************/ -static void -test_sqlite3_resource_migrations_null_path(void) { - if(g_test_subprocess()) { - GError *error = NULL; - sqlite3 *db = NULL; - gboolean res = FALSE; - int rc = 0; - - rc = sqlite3_open(":memory:", &db); - g_assert_nonnull(db); - g_assert_cmpint(rc, ==, SQLITE_OK); - - res = purple_sqlite3_run_migrations_from_resources(db, NULL, NULL, - &error); - g_assert_no_error(error); - g_assert_false(res); - - rc = sqlite3_close(db); - g_assert_cmpint(rc, ==, SQLITE_OK); - } - - g_test_trap_subprocess(NULL, 0, 0); - g_test_trap_assert_failed(); - g_test_trap_assert_stderr("*path != NULL*"); -} - -static void -test_sqlite3_resource_migrations_null_migrations(void) { - if(g_test_subprocess()) { - GError *error = NULL; - sqlite3 *db = NULL; - gboolean res = FALSE; - const char *path = "/im/libpidgin/purple/tests/sqlite3/"; - int rc = 0; - - rc = sqlite3_open(":memory:", &db); - g_assert_nonnull(db); - g_assert_cmpint(rc, ==, SQLITE_OK); - - res = purple_sqlite3_run_migrations_from_resources(db, path, NULL, - &error); - g_assert_no_error(error); - g_assert_false(res); - - rc = sqlite3_close(db); - g_assert_cmpint(rc, ==, SQLITE_OK); - } - - g_test_trap_subprocess(NULL, 0, 0); - g_test_trap_assert_failed(); - g_test_trap_assert_stderr("*migrations != NULL*"); -} - -static void -test_sqlite3_resource_migrations_null_terminator(void) { - GError *error = NULL; - sqlite3 *db = NULL; - gboolean res = FALSE; - int rc = 0; - int version = -1; - const char *migrations[] = {NULL}; - const char *path = "/im/pidgin/libpurple/tests/sqlite3/"; - - rc = sqlite3_open(":memory:", &db); - g_assert_nonnull(db); - g_assert_cmpint(rc, ==, SQLITE_OK); - - res = purple_sqlite3_run_migrations_from_resources(db, path, migrations, - &error); - g_assert_no_error(error); - g_assert_true(res); - - version = purple_sqlite3_get_schema_version(db, &error); - g_assert_no_error(error); - g_assert_cmpint(version, ==, 0); - - rc = sqlite3_close(db); - g_assert_cmpint(rc, ==, SQLITE_OK); -} - -static void -test_sqlite3_resource_migrations_multiple(void) { - GError *error = NULL; - sqlite3 *db = NULL; - gboolean res = FALSE; - int rc = 0; - int version = -1; - const char *migrations[] = {"initial.sql", "secondary.sql", NULL}; - const char *path = "/im/pidgin/libpurple/tests/sqlite3/"; - - rc = sqlite3_open(":memory:", &db); - g_assert_nonnull(db); - g_assert_cmpint(rc, ==, SQLITE_OK); - - res = purple_sqlite3_run_migrations_from_resources(db, path, migrations, - &error); - g_assert_no_error(error); - g_assert_true(res); - - version = purple_sqlite3_get_schema_version(db, &error); - g_assert_no_error(error); - g_assert_cmpint(version, ==, 2); - - /* Run the migrations again and make sure we remain at schema version 2. */ - res = purple_sqlite3_run_migrations_from_strings(db, migrations, &error); - g_assert_no_error(error); - g_assert_true(res); - - version = purple_sqlite3_get_schema_version(db, &error); - g_assert_no_error(error); - g_assert_cmpint(version, ==, 2); - - rc = sqlite3_close(db); - g_assert_cmpint(rc, ==, SQLITE_OK); -} - -static void -test_sqlite3_resource_migrations_missing(void) { - GError *error = NULL; - sqlite3 *db = NULL; - gboolean res = FALSE; - int rc = 0; - int version = -1; - const char *migrations[] = {"initial.sql", "imaginary.sql", NULL}; - const char *path = "/im/pidgin/libpurple/tests/sqlite3/"; - - rc = sqlite3_open(":memory:", &db); - g_assert_nonnull(db); - g_assert_cmpint(rc, ==, SQLITE_OK); - - res = purple_sqlite3_run_migrations_from_resources(db, path, migrations, - &error); - g_assert_error(error, G_RESOURCE_ERROR, 0); - g_clear_error(&error); - g_assert_false(res); - - version = purple_sqlite3_get_schema_version(db, &error); - g_assert_no_error(error); - g_assert_cmpint(version, ==, 1); - - rc = sqlite3_close(db); - g_assert_cmpint(rc, ==, SQLITE_OK); -} - -static void -test_sqlite3_resource_migrations_syntax_error(void) { - GError *error = NULL; - sqlite3 *db = NULL; - gboolean res = FALSE; - int rc = 0; - int version = -1; - const char *migrations[] = {"malformed.sql", NULL}; - const char *path = "/im/pidgin/libpurple/tests/sqlite3/"; - - rc = sqlite3_open(":memory:", &db); - g_assert_nonnull(db); - g_assert_cmpint(rc, ==, SQLITE_OK); - - res = purple_sqlite3_run_migrations_from_resources(db, path, migrations, - &error); - g_assert_error(error, PURPLE_SQLITE3_DOMAIN, 0); - g_clear_error(&error); - g_assert_false(res); - - version = purple_sqlite3_get_schema_version(db, &error); - g_assert_no_error(error); - g_assert_cmpint(version, ==, 0); - - rc = sqlite3_close(db); - g_assert_cmpint(rc, ==, SQLITE_OK); -} - -static void -test_sqlite3_resource_migrations_older(void) { - GError *error = NULL; - sqlite3 *db = NULL; - gboolean res = FALSE; - int rc = 0; - int version = -1; - const char *migrations1[] = {"initial.sql", "secondary.sql", NULL}; - const char *migrations2[] = {"initial.sql", NULL}; - const char *path = "/im/pidgin/libpurple/tests/sqlite3/"; - - rc = sqlite3_open(":memory:", &db); - g_assert_nonnull(db); - g_assert_cmpint(rc, ==, SQLITE_OK); - - res = purple_sqlite3_run_migrations_from_resources(db, path, migrations1, - &error); - g_assert_no_error(error); - g_assert_true(res); - - version = purple_sqlite3_get_schema_version(db, &error); - g_assert_no_error(error); - g_assert_cmpint(version, ==, 2); - - /* Run the older migrations now and verify we get a failure. */ - res = purple_sqlite3_run_migrations_from_resources(db, path, migrations2, - &error); - g_assert_error(error, PURPLE_SQLITE3_DOMAIN, 0); - g_clear_error(&error); - g_assert_false(res); - - version = purple_sqlite3_get_schema_version(db, &error); - g_assert_no_error(error); - g_assert_cmpint(version, ==, 2); - - rc = sqlite3_close(db); - g_assert_cmpint(rc, ==, SQLITE_OK); -} - -/****************************************************************************** - * Main - *****************************************************************************/ -int -main(int argc, char *argv[]) { - g_test_init(&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL); - - g_test_add_func("/sqlite3/schema_version/null", - test_sqlite3_get_schema_version_null); - g_test_add_func("/sqlite3/schema_version/new", - test_sqlite3_get_schema_version_new); - - g_test_add_func("/sqlite3/string_migrations/null", - test_sqlite3_string_migrations_null); - g_test_add_func("/sqlite3/string_migrations/null-terminator", - test_sqlite3_string_migrations_null_terminator); - g_test_add_func("/sqlite3/string_migrations/multiple", - test_sqlite3_string_migrations_multiple); - g_test_add_func("/sqlite3/string_migrations/syntax-error", - test_sqlite3_string_migrations_syntax_error); - g_test_add_func("/sqlite3/string_migrations/older", - test_sqlite3_string_migrations_older); - - g_test_add_func("/sqlite3/resource_migrations/null-path", - test_sqlite3_resource_migrations_null_path); - g_test_add_func("/sqlite3/resource_migrations/null-migrations", - test_sqlite3_resource_migrations_null_migrations); - g_test_add_func("/sqlite3/resource_migrations/null-terminator", - test_sqlite3_resource_migrations_null_terminator); - g_test_add_func("/sqlite3/resource_migrations/multiple", - test_sqlite3_resource_migrations_multiple); - g_test_add_func("/sqlite3/resource_migrations/missing", - test_sqlite3_resource_migrations_missing); - g_test_add_func("/sqlite3/resource_migrations/syntax-error", - test_sqlite3_resource_migrations_syntax_error); - g_test_add_func("/sqlite3/resource_migrations/older", - test_sqlite3_resource_migrations_older); - - return g_test_run(); -}
--- a/libpurple/tests/sqlite3/test_sqlite3.gresource.xml Thu Feb 06 20:29:19 2025 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<gresources> - <gresource prefix="/im/pidgin/libpurple/tests/sqlite3/"> - <file compressed="true">initial.sql</file> - <file compressed="true">secondary.sql</file> - <file compressed="true">malformed.sql</file> - </gresource> -</gresources>
--- a/meson.build Thu Feb 06 20:29:19 2025 -0600 +++ b/meson.build Fri Feb 07 00:14:03 2025 -0600 @@ -181,11 +181,6 @@ language : 'c',) ####################################################################### -# Check for gdk-pixbuf (required) -####################################################################### -gdk_pixbuf = dependency('gdk-pixbuf-2.0', version : '>= 2.26.0') - -####################################################################### # Check for GObject Introspection ####################################################################### if get_option('introspection') @@ -209,53 +204,27 @@ ENABLE_GTK = get_option('gtkui') ####################################################################### -# Check for LibXML2 (required) -####################################################################### -libxml = dependency('libxml-2.0', version : '>= 2.6.0') -if libxml.version().version_compare('<2.6.18') - message('Versions of libxml2 < 2.6.18 may contain bugs that could cause XMPP messages to be discarded.') -endif - +# Additional Dependencies ####################################################################### -# Check for JSON-GLib (required) -####################################################################### - +birb_dep = dependency('birb', version : '>=0.3.1') +gdk_pixbuf = dependency('gdk-pixbuf-2.0', version : '>= 2.26.0') +gstreamer = dependency('gstreamer-1.0', version : '>=1.14') +gstreamer_app = dependency('gstreamer-app-1.0') json = dependency('json-glib-1.0', version : '>= 0.14.0') -###################################################################### -# Check for libsoup (required) -####################################################################### - libsoup = dependency('libsoup-3.0', version : '>= 3') add_project_arguments( '-DSOUP_VERSION_MIN_REQUIRED=SOUP_VERSION_3_0', '-DSOUP_VERSION_MAX_ALLOWED=SOUP_VERSION_3_0', language : 'c') -####################################################################### -# Check for sqlite3 (required) -####################################################################### -sqlite3 = dependency('sqlite3', version : '>= 3.27.0') - -####################################################################### -# Check for GStreamer -####################################################################### - -gstreamer = dependency('gstreamer-1.0', version : '>=1.14') +libxml = dependency('libxml-2.0', version : '>= 2.6.0') +if libxml.version().version_compare('<2.6.18') + message('Versions of libxml2 < 2.6.18 may contain bugs that could cause XMPP messages to be discarded.') +endif -####################################################################### -# Check for Raw data streams support in Farstream -####################################################################### -gstreamer_app = dependency('gstreamer-app-1.0') - -####################################################################### -# Check for birb glib utility library -####################################################################### -birb_dep = dependency('birb', version : '>=0.3.1') - -####################################################################### -# Check for Xeme XMPP Library -####################################################################### +seagull_dep = dependency('seagull', version : '>= 0.1.1') +sqlite3 = dependency('sqlite3', version : '>= 3.27.0') xeme = dependency('xeme') dependency('shoes', required : false)
--- a/po/POTFILES.in Thu Feb 06 20:29:19 2025 -0600 +++ b/po/POTFILES.in Fri Feb 07 00:14:03 2025 -0600 @@ -91,7 +91,6 @@ libpurple/purpleprotocolwhiteboard.c libpurple/purpleproxyinfo.c libpurple/purplesavedpresence.c -libpurple/purplesqlite3.c libpurple/purplesqlitehistoryadapter.c libpurple/purpletags.c libpurple/purpleui.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/subprojects/seagull.wrap Fri Feb 07 00:14:03 2025 -0600 @@ -0,0 +1,5 @@ +[wrap-file] +directory = seagull-0.1.1 +source_url = https://sourceforge.net/projects/pidgin/files/seagull/0.1.1/seagull-0.1.1.tar.xz +source_filename = seagull-0.1.1.tar.xz +source_hash = 499fc45b6a8539bc2293b362fec1c847fe25697355a0572f07ace3f359a38873