Create PurpleSavedPresence for saving the users presences
Testing Done:
Ran the unit tests.
Bugs closed: PIDGIN-17795
Reviewed at https://reviews.imfreedom.org/r/2440/
--- a/libpurple/meson.build Tue Apr 18 22:44:01 2023 -0500
+++ b/libpurple/meson.build Tue Apr 25 00:46:17 2023 -0500
@@ -88,6 +88,7 @@
+ 'purplesavedpresence.c', 'purplesqlitehistoryadapter.c',
@@ -205,6 +206,7 @@
+ 'purplesavedpresence.h', 'purplesqlitehistoryadapter.h',
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/purplesavedpresence.c Tue Apr 25 00:46:17 2023 -0500
@@ -0,0 +1,376 @@
+ * 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 + * This program 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 program 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 program; if not, see <https://www.gnu.org/licenses/>. +#include <glib/gi18n-lib.h> +#include "purpleenums.h" +#include "purplesavedpresence.h" +struct _PurpleSavedPresence { + PurplePresencePrimitive primitive; +static GParamSpec *properties[N_PROPERTIES]; +G_DEFINE_TYPE(PurpleSavedPresence, purple_saved_presence, G_TYPE_OBJECT) +/****************************************************************************** + * GObject Implementation + *****************************************************************************/ +purple_saved_presence_set_property(GObject *obj, guint param_id, + const GValue *value, GParamSpec *pspec) + PurpleSavedPresence *presence = PURPLE_SAVED_PRESENCE(obj); + purple_saved_presence_set_last_used(presence, + g_value_get_boxed(value)); + purple_saved_presence_set_use_count(presence, + g_value_get_uint(value)); + purple_saved_presence_set_name(presence, + g_value_get_string(value)); + purple_saved_presence_set_primitive(presence, + g_value_get_enum(value)); + purple_saved_presence_set_message(presence, + g_value_get_string(value)); + purple_saved_presence_set_emoji(presence, + g_value_get_string(value)); + G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); +purple_saved_presence_get_property(GObject *obj, guint param_id, GValue *value, + PurpleSavedPresence *presence = PURPLE_SAVED_PRESENCE(obj); + g_value_set_boxed(value, + purple_saved_presence_get_last_used(presence)); + g_value_set_uint(value, + purple_saved_presence_get_use_count(presence)); + g_value_set_string(value, + purple_saved_presence_get_name(presence)); + g_value_set_enum(value, + purple_saved_presence_get_primitive(presence)); + g_value_set_string(value, + purple_saved_presence_get_message(presence)); + g_value_set_string(value, + purple_saved_presence_get_emoji(presence)); + G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); +purple_saved_presence_init(G_GNUC_UNUSED PurpleSavedPresence *presence) { +purple_saved_presence_finalize(GObject *obj) { + PurpleSavedPresence *presence = PURPLE_SAVED_PRESENCE(obj); + g_clear_pointer(&presence->last_used, g_date_time_unref); + g_clear_pointer(&presence->name, g_free); + g_clear_pointer(&presence->message, g_free); + g_clear_pointer(&presence->emoji, g_free); + G_OBJECT_CLASS(purple_saved_presence_parent_class)->finalize(obj); +purple_saved_presence_class_init(PurpleSavedPresenceClass *klass) { + GObjectClass *obj_class = G_OBJECT_CLASS(klass); + obj_class->get_property = purple_saved_presence_get_property; + obj_class->set_property = purple_saved_presence_set_property; + obj_class->finalize = purple_saved_presence_finalize; + * PurpleSavedPresence:last-used: + * The [struct@GLib.DateTime] when this saved presence was last used. + properties[PROP_LAST_USED] = g_param_spec_boxed( + "last-used", "last-used", + "The time this presence was last used.", + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + * PurpleSavedPresence:use-count: + * The number of times this saved presence has been used. + properties[PROP_USE_COUNT] = g_param_spec_uint( + "use-count", "use-count", + "The number of times this saved presence has been used.", + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + * PurpleSavedPresence:name: + * The name of the saved presence. + properties[PROP_NAME] = g_param_spec_string( + "The name of this saved presence.", + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + * PurpleSavedPresence:primitive: + * The [enum@Purple.StatusPrimitive] for this saved presence. + properties[PROP_PRIMITIVE] = g_param_spec_enum( + "primitive", "primitive", + "The primitive for this saved presence.", + PURPLE_TYPE_PRESENCE_PRIMITIVE, + PURPLE_PRESENCE_PRIMITIVE_OFFLINE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + * PurpleSavedPresence:message: + * The status message of this saved presence. + properties[PROP_MESSAGE] = g_param_spec_string( + "The status message of this saved presence.", + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + * PurpleSavedPresence:emoji: + * The emoji or mood of the presence. + properties[PROP_EMOJI] = g_param_spec_string( + "The emoji for this saved presence.", + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_class_install_properties(obj_class, N_PROPERTIES, properties); +/****************************************************************************** + *****************************************************************************/ +purple_saved_presence_new(void) { + return g_object_new(PURPLE_TYPE_SAVED_PRESENCE, NULL); +purple_saved_presence_get_last_used(PurpleSavedPresence *presence) { + g_return_val_if_fail(PURPLE_IS_SAVED_PRESENCE(presence), NULL); + return presence->last_used; +purple_saved_presence_set_last_used(PurpleSavedPresence *presence, + g_return_if_fail(PURPLE_IS_SAVED_PRESENCE(presence)); + if(presence->last_used != last_used) { + g_clear_pointer(&presence->last_used, g_date_time_unref); + if(last_used != NULL) { + presence->last_used = g_date_time_ref(last_used); + g_object_notify_by_pspec(G_OBJECT(presence), + properties[PROP_LAST_USED]); +purple_saved_presence_get_use_count(PurpleSavedPresence *presence) { + g_return_val_if_fail(PURPLE_IS_SAVED_PRESENCE(presence), 0); + return presence->use_count; +purple_saved_presence_set_use_count(PurpleSavedPresence *presence, + g_return_if_fail(PURPLE_IS_SAVED_PRESENCE(presence)); + if(presence->use_count != use_count) { + presence->use_count = use_count; + g_object_notify_by_pspec(G_OBJECT(presence), + properties[PROP_USE_COUNT]); +purple_saved_presence_get_name(PurpleSavedPresence *presence) { + g_return_val_if_fail(PURPLE_IS_SAVED_PRESENCE(presence), NULL); +purple_saved_presence_set_name(PurpleSavedPresence *presence, + g_return_if_fail(PURPLE_IS_SAVED_PRESENCE(presence)); + if(!purple_strequal(presence->name, name)) { + g_free(presence->name); + presence->name = g_strdup(name); + g_object_notify_by_pspec(G_OBJECT(presence), properties[PROP_NAME]); +purple_saved_presence_get_primitive(PurpleSavedPresence *presence) { + g_return_val_if_fail(PURPLE_IS_SAVED_PRESENCE(presence), + PURPLE_PRESENCE_PRIMITIVE_OFFLINE); + return presence->primitive; +purple_saved_presence_set_primitive(PurpleSavedPresence *presence, + PurplePresencePrimitive primitive) + g_return_if_fail(PURPLE_IS_SAVED_PRESENCE(presence)); + if(presence->primitive != primitive) { + presence->primitive = primitive; + g_object_notify_by_pspec(G_OBJECT(presence), + properties[PROP_PRIMITIVE]); +purple_saved_presence_get_message(PurpleSavedPresence *presence) { + g_return_val_if_fail(PURPLE_IS_SAVED_PRESENCE(presence), NULL); + return presence->message; +purple_saved_presence_set_message(PurpleSavedPresence *presence, + g_return_if_fail(PURPLE_IS_SAVED_PRESENCE(presence)); + if(!purple_strequal(presence->message, message)) { + g_free(presence->message); + presence->message = g_strdup(message); + g_object_notify_by_pspec(G_OBJECT(presence), properties[PROP_MESSAGE]); +purple_saved_presence_get_emoji(PurpleSavedPresence *presence) { + g_return_val_if_fail(PURPLE_IS_SAVED_PRESENCE(presence), NULL); + return presence->emoji; +purple_saved_presence_set_emoji(PurpleSavedPresence *presence, + g_return_if_fail(PURPLE_IS_SAVED_PRESENCE(presence)); + if(!purple_strequal(presence->emoji, emoji)) { + g_free(presence->emoji); + presence->emoji = g_strdup(emoji); + g_object_notify_by_pspec(G_OBJECT(presence), properties[PROP_EMOJI]); --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/purplesavedpresence.h Tue Apr 25 00:46:17 2023 -0500
@@ -0,0 +1,197 @@
+ * 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 + * This program 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 program 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 program; 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" +#ifndef PURPLE_SAVED_PRESENCE_H +#define PURPLE_SAVED_PRESENCE_H +#include <glib-object.h> +#include <libpurple/purplepresence.h> +#define PURPLE_TYPE_SAVED_PRESENCE purple_saved_presence_get_type() +G_DECLARE_FINAL_TYPE(PurpleSavedPresence, purple_saved_presence, PURPLE, + SAVED_PRESENCE, GObject) + * purple_saved_presence_new: + * Creates a new saved_presence instance. + * Returns: (transfer full): The new instance. +PurpleSavedPresence *purple_saved_presence_new(void); + * purple_saved_presence_get_last_used: + * @presence: The instance. + * Gets the [struct@GLib.DateTime] that @presence was last used. + * Returns: (transfer none) (nullable): The time @presence was last used or +GDateTime *purple_saved_presence_get_last_used(PurpleSavedPresence *presence); + * purple_saved_presence_set_last_used: + * @presence: The instance. + * @last_used: (nullable): The time this was last used. + * Sets the last time @presence was used to @last_used. If @last_used is %NULL, + * the time will be cleared. +void purple_saved_presence_set_last_used(PurpleSavedPresence *presence, GDateTime *last_used); + * purple_saved_presence_get_use_count: + * @presence: The instance. + * Gets the number of times @presence has been used. + * Returns: The number of times @presence has been used. +guint purple_saved_presence_get_use_count(PurpleSavedPresence *presence); + * purple_saved_presence_set_use_count: + * @presence: The instance. + * @use_count: The new use count. + * Sets the number of times @presence has been used to @use_count. +void purple_saved_presence_set_use_count(PurpleSavedPresence *presence, guint use_count); + * purple_saved_presence_get_name: + * @presence: The instance. + * Gets the name of @presence. + * Returns: (nullable): The name of @presence. +const char *purple_saved_presence_get_name(PurpleSavedPresence *presence); + * purple_saved_presence_set_name: + * @presence: The instance. + * @name: (nullable): The new name. + * Sets the name of @presence to @name. If @name is %NULL the name will be +void purple_saved_presence_set_name(PurpleSavedPresence *presence, const char *name); + * purple_saved_presence_get_primitive: + * @presence: The instance. + * Gets the [enum@PresencePrimitive] for @presence. + * Returns: The [enum@PresencePrimitive] for @presence. +PurplePresencePrimitive purple_saved_presence_get_primitive(PurpleSavedPresence *presence); + * purple_saved_presence_set_primitive: + * @presence: The instance. + * @primitive: The new primitive. + * Sets the [enum@PresencePrimitive] of @presence to @primitive. +void purple_saved_presence_set_primitive(PurpleSavedPresence *presence, PurplePresencePrimitive primitive); + * purple_saved_presence_get_message: + * @presence: The instance. + * Gets the message of @presence. + * Returns: (nullable): The message from @presence. +const char *purple_saved_presence_get_message(PurpleSavedPresence *presence); + * purple_saved_presence_set_message: + * @presence: The instance. + * @message: (nullable): The new message. + * Sets the message of @presence to @message. If @message is %NULL the message +void purple_saved_presence_set_message(PurpleSavedPresence *presence, const char *message); + * purple_saved_presence_get_emoji: + * @presence: The instance. + * Gets the emoji for @presence. + * Returns: (nullable): The emoji for @presence. +const char *purple_saved_presence_get_emoji(PurpleSavedPresence *presence); + * purple_saved_presence_set_emoji: + * @presence: The instance. + * @emoji: (nullable): The new emoji. + * Sets the emoji of @presence to @emoji. If @emoji is %NULL, the emoji will be +void purple_saved_presence_set_emoji(PurpleSavedPresence *presence, const char *emoji); +#endif /* PURPLE_SAVED_PRESENCE_H */ --- a/libpurple/tests/meson.build Tue Apr 18 22:44:01 2023 -0500
+++ b/libpurple/tests/meson.build Tue Apr 25 00:46:17 2023 -0500
@@ -29,6 +29,7 @@
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/tests/test_saved_presence.c Tue Apr 25 00:46:17 2023 -0500
@@ -0,0 +1,111 @@
+ * 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/>. +/****************************************************************************** + *****************************************************************************/ +test_purple_saved_presence_new(void) { + PurpleSavedPresence *presence = NULL; + presence = purple_saved_presence_new(); + g_assert_true(PURPLE_IS_SAVED_PRESENCE(presence)); + g_clear_object(&presence); +test_purple_saved_presence_properties(void) { + PurpleSavedPresence *presence = NULL; + PurplePresencePrimitive primitive; + GDateTime *last_used = NULL; + GDateTime *last_used1 = NULL; + last_used = g_date_time_new_now_local(); + /* Use g_object_new so we can test setting properties by name. All of them + * call the setter methods, so by doing it this way we exercise more of the + presence = g_object_new( + PURPLE_TYPE_SAVED_PRESENCE, + "last-used", last_used, + "name", "my saved status", + "primitive", PURPLE_PRESENCE_PRIMITIVE_STREAMING, + "message", "I'm live on twitch at https://twitch.tv/rw_grim/", + /* Now use g_object_get to read all of the properties. */ + "last-used", &last_used1, + "use-count", &use_count, + "primitive", &primitive, + /* Compare all the things. */ + g_assert_nonnull(last_used1); + g_assert_true(g_date_time_equal(last_used, last_used1)); + g_clear_pointer(&last_used1, g_date_time_unref); + g_assert_cmpuint(use_count, ==, 123); + g_assert_cmpstr(name, ==, "my saved status"); + g_clear_pointer(&name, g_free); + g_assert_cmpint(primitive, ==, PURPLE_PRESENCE_PRIMITIVE_STREAMING); + g_assert_cmpstr(message, ==, + "I'm live on twitch at https://twitch.tv/rw_grim/"); + g_clear_pointer(&message, g_free); + g_assert_cmpstr(emoji, ==, "💀"); + g_clear_pointer(&emoji, g_free); + g_clear_pointer(&last_used, g_date_time_unref); + g_clear_object(&presence); +/****************************************************************************** + *****************************************************************************/ +main(gint argc, gchar *argv[]) { + g_test_init(&argc, &argv, NULL); + g_test_add_func("/saved-presence/new", + test_purple_saved_presence_new); + g_test_add_func("/saved-presence/properties", + test_purple_saved_presence_properties);