Mon, 30 Jun 2025 14:22:13 -0500
Update the flatpak to gnome 48 and to the matching birb version
The birb version was missed here when it was updated.
Testing Done:
Built the flatpak with the instructions in the readme.
Reviewed at https://reviews.imfreedom.org/r/4038/
/* * 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 "purpletags.h" #include "util.h" enum { SIG_ADDED, SIG_REMOVED, N_SIGNALS, }; static guint signals[N_SIGNALS] = {0, }; struct _PurpleTags { GObject parent; GList *tags; }; G_DEFINE_FINAL_TYPE(PurpleTags, purple_tags, G_TYPE_OBJECT) /****************************************************************************** * Helpers *****************************************************************************/ static void purple_tags_real_add(PurpleTags *tags, const char *tag, const char *name, const char *value) { /* If this tag exists, remove it. */ purple_tags_remove(tags, tag); /* Add the new tag. */ tags->tags = g_list_append(tags->tags, g_strdup(tag)); /* Finally emit the signal. */ g_signal_emit(tags, signals[SIG_ADDED], 0, tag, name, value); } static gboolean purple_tags_real_remove(PurpleTags *tags, const char *tag, const char *name, const char *value) { /* Walk through the tags looking for the one that was passed in. */ for(GList *l = tags->tags; l != NULL; l = l->next) { gchar *etag = l->data; /* If we found it, remove it and exit early. */ if(purple_strequal(etag, tag)) { g_free(etag); tags->tags = g_list_delete_link(tags->tags, l); g_signal_emit(tags, signals[SIG_REMOVED], 0, tag, name, value); return TRUE; } } return FALSE; } /****************************************************************************** * GObject Implementation *****************************************************************************/ static void purple_tags_dispose(GObject *obj) { PurpleTags *tags = PURPLE_TAGS(obj); g_clear_list(&tags->tags, g_free); G_OBJECT_CLASS(purple_tags_parent_class)->dispose(obj); } static void purple_tags_init(G_GNUC_UNUSED PurpleTags *tags) { } static void purple_tags_class_init(PurpleTagsClass *klass) { GObjectClass *obj_class = G_OBJECT_CLASS(klass); obj_class->dispose = purple_tags_dispose; /** * PurpleTags::added: * @tags: The instance. * @tag: The tag value. * @name: The name of the tag. * @value: The value of the tag. * * Emitted when a tag is added. The tag as well as its name and value are * provided to be as flexible as possible. * * > NOTE: When a duplicate tag is added, the original one will be removed * > which will emit the [signal@Tags::removed] signal and then the new tag * > will be added which will emit [signal@Tags::added]. * * Since: 3.0 */ signals[SIG_ADDED] = g_signal_new_class_handler( "added", G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_LAST, NULL, NULL, NULL, NULL, G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); /** * PurpleTags::removed: * @tags: The instance. * @tag: The tag value. * @name: The name of the tag. * @value: The value of the tag. * * Emitted when a tag is removed. The tag as well as its name and value are * provided to be as flexible as possible. * * > NOTE: When a duplicate tag is added, the original one will be removed * > which will emit the [signal@Tags::removed] signal and then the new tag * > will be added which will emit [signal@Tags::added]. * * Since: 3.0 */ signals[SIG_REMOVED] = g_signal_new_class_handler( "removed", G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_LAST, NULL, NULL, NULL, NULL, G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); } /****************************************************************************** * Public API *****************************************************************************/ PurpleTags * purple_tags_new(void) { return g_object_new(PURPLE_TYPE_TAGS, NULL); } gboolean purple_tags_exists(PurpleTags *tags, const char *tag) { g_return_val_if_fail(PURPLE_IS_TAGS(tags), FALSE); g_return_val_if_fail(!purple_strempty(tag), FALSE); for(GList *l = tags->tags; l != NULL; l = l->next) { const char *existing = l->data; if(purple_strequal(existing, tag)) { return TRUE; } } return FALSE; } const gchar * purple_tags_lookup(PurpleTags *tags, const gchar *name, gboolean *found) { size_t name_len = 0; g_return_val_if_fail(PURPLE_IS_TAGS(tags), FALSE); g_return_val_if_fail(name != NULL, FALSE); /* Assume we're going to find the tag, if we don't we set found to false * before we return. This sounds silly, but it saves some additional logic * below. */ if(found) { *found = TRUE; } name_len = strlen(name); for(GList *l = tags->tags; l != NULL; l = l->next) { const gchar *tag = l->data; if(g_str_has_prefix(tag, name)) { const gchar *value = tag + name_len; if(*value == '\0') { return NULL; } else if(*value == ':') { return value+1; } } } /* We didn't find the tag, so set found to false if necessary. */ if(found) { *found = FALSE; } return NULL; } const gchar * purple_tags_get(PurpleTags *tags, const gchar *name) { g_return_val_if_fail(PURPLE_IS_TAGS(tags), NULL); g_return_val_if_fail(name != NULL, NULL); return purple_tags_lookup(tags, name, NULL); } void purple_tags_add(PurpleTags *tags, const gchar *tag) { char *name = NULL; char *value = NULL; g_return_if_fail(PURPLE_IS_TAGS(tags)); g_return_if_fail(tag != NULL); purple_tag_split(tag, &name, &value); purple_tags_real_add(tags, tag, name, value); g_clear_pointer(&name, g_free); g_clear_pointer(&value, g_free); } void purple_tags_add_with_value(PurpleTags *tags, const char *name, const char *value) { char *tag = NULL; g_return_if_fail(PURPLE_IS_TAGS(tags)); g_return_if_fail(name != NULL); if(value != NULL) { tag = g_strdup_printf("%s:%s", name, value); } else { tag = g_strdup(name); } purple_tags_real_add(tags, tag, name, value); g_free(tag); } gboolean purple_tags_remove(PurpleTags *tags, const gchar *tag) { gchar *name = NULL; gchar *value = NULL; gboolean ret = FALSE; g_return_val_if_fail(PURPLE_IS_TAGS(tags), FALSE); g_return_val_if_fail(tag != NULL, FALSE); purple_tag_split(tag, &name, &value); ret = purple_tags_real_remove(tags, tag, name, value); g_clear_pointer(&name, g_free); g_clear_pointer(&value, g_free); return ret; } gboolean purple_tags_remove_with_value(PurpleTags *tags, const char *name, const char *value) { char *tag = NULL; gboolean ret = FALSE; g_return_val_if_fail(PURPLE_IS_TAGS(tags), FALSE); g_return_val_if_fail(name != NULL, FALSE); /* If there's no value, the tag and name are the same so we can avoid an * unnecessary allocation. */ if(value == NULL) { return purple_tags_real_remove(tags, name, name, NULL); } tag = g_strdup_printf("%s:%s", name, value); ret = purple_tags_real_remove(tags, tag, name, value); g_free(tag); return ret; } void purple_tags_remove_all(PurpleTags *tags) { g_return_if_fail(PURPLE_IS_TAGS(tags)); g_clear_list(&tags->tags, g_free); } guint purple_tags_get_count(PurpleTags *tags) { g_return_val_if_fail(PURPLE_IS_TAGS(tags), 0); return g_list_length(tags->tags); } GList * purple_tags_get_all(PurpleTags *tags) { g_return_val_if_fail(PURPLE_IS_TAGS(tags), NULL); return tags->tags; } GList * purple_tags_get_all_with_name(PurpleTags *tags, const char *name) { GList *ret = NULL; size_t name_len = 0; g_return_val_if_fail(PURPLE_IS_TAGS(tags), NULL); g_return_val_if_fail(!purple_strempty(name), NULL); name_len = strlen(name); for(GList *l = tags->tags; l != NULL; l = l->next) { char *tag = l->data; if(g_str_has_prefix(tag, name)) { const char *value = tag + name_len; /* Make sure this is a tag with no value and that we didn't get a * partial match on the name. */ if(*value == '\0' || *value == ':') { ret = g_list_prepend(ret, tag); } } } return g_list_reverse(ret); } gchar * purple_tags_to_string(PurpleTags *tags, const gchar *separator) { GString *value = NULL; g_return_val_if_fail(PURPLE_IS_TAGS(tags), NULL); value = g_string_new(""); for(GList *l = tags->tags; l != NULL; l = l->next) { const gchar *tag = l->data; g_string_append(value, tag); if(separator != NULL && l->next != NULL) { g_string_append(value, separator); } } return g_string_free_and_steal(value); } void purple_tag_split(const char *tag, char **name, char **value) { const char *colon = NULL; g_return_if_fail(tag != NULL); colon = g_strstr_len(tag, -1, ":"); if(colon == NULL) { if(name != NULL) { *name = g_strdup(tag); } if(value != NULL) { *value = NULL; } } else { if(name != NULL) { *name = g_strndup(tag, colon - tag); } if(value != NULL) { *value = g_strdup(colon + 1); } } } gboolean purple_tags_contains(PurpleTags *tags, PurpleTags *needle) { g_return_val_if_fail(PURPLE_IS_TAGS(tags), FALSE); g_return_val_if_fail(PURPLE_IS_TAGS(needle), FALSE); for(GList *tag = needle->tags; tag != NULL; tag = tag->next) { const char *needle_tag = tag->data; if(!purple_tags_exists(tags, needle_tag)) { return FALSE; } } return TRUE; }