--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/protocols/demo/purpledemocontacts.c Mon Mar 25 21:43:28 2024 -0500 @@ -0,0 +1,357 @@ +/* + * 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 <json-glib/json-glib.h> + +#include "purpledemocontacts.h" + +#include "purpledemoresource.h" + +/****************************************************************************** + * Helpers + *****************************************************************************/ +static void +purple_demo_contacts_load_contact_icon(PurpleContactInfo *info, + const char *name) +{ + PurpleAvatar *avatar = NULL; + GError *error = NULL; + char *path = NULL; + + path = g_strdup_printf("/im/pidgin/purple/demo/buddy_icons/%s.png", name); + avatar = purple_avatar_new_from_resource(path, &error); + + if(error != NULL) { + g_message("Failed to load find an icon for %s: %s", path, + error->message); + + g_free(path); + g_clear_error(&error); + + return; + } + + g_free(path); + + if(PURPLE_IS_AVATAR(avatar)) { + purple_contact_info_set_avatar(info, avatar); + + g_clear_object(&avatar); + } +} + +static void +purple_demo_contacts_load_contact_person(JsonObject *person_object, + PurpleContactInfo *info) +{ + PurplePerson *person = NULL; + gboolean new_person = FALSE; + const char *value = NULL; + + /* If the person has an id, grab it so we can use it when constructing the + * person object. + */ + if(json_object_has_member(person_object, "id")) { + value = json_object_get_string_member(person_object, "id"); + } + + /* See if the contact has an existing person. */ + person = purple_contact_info_get_person(info); + if(PURPLE_IS_PERSON(person)) { + const char *existing_id = NULL; + + /* If the existing person's id doesn't match the new one, NULL out + * person so it'll be recreated with the new id. + */ + existing_id = purple_person_get_id(person); + if(!purple_strequal(existing_id, value)) { + person = NULL; + } + } + + /* If the person didn't exist or it had a different id, create a new person + * with the id. + */ + if(!PURPLE_IS_PERSON(person)) { + person = g_object_new(PURPLE_TYPE_PERSON, "id", value, NULL); + new_person = TRUE; + } + + /* Alias */ + if(json_object_has_member(person_object, "alias")) { + value = json_object_get_string_member(person_object, "alias"); + if(!purple_strempty(value)) { + purple_person_set_alias(person, value); + } + } + + /* Create the link between the person and the contact info. */ + if(new_person) { + purple_person_add_contact_info(person, info); + purple_contact_info_set_person(info, person); + + g_clear_object(&person); + } +} + +static void +purple_demo_contacts_load_contact_presence(JsonObject *presence_object, + PurpleContactInfo *info) +{ + PurplePresence *presence = NULL; + const gchar *value = NULL; + + presence = purple_contact_info_get_presence(info); + + /* Emoji */ + if(json_object_has_member(presence_object, "emoji")) { + value = json_object_get_string_member(presence_object, "emoji"); + if(!purple_strempty(value)) { + purple_presence_set_emoji(presence, value); + } + } + + /* Idle Time */ + if(json_object_has_member(presence_object, "idle")) { + GDateTime *now = NULL; + GDateTime *idle_since = NULL; + gint64 ivalue = 0; + + ivalue = json_object_get_int_member(presence_object, "idle"); + + now = g_date_time_new_now_local(); + idle_since = g_date_time_add_minutes(now, -1 * ivalue); + + purple_presence_set_idle(presence, TRUE, idle_since); + + g_date_time_unref(idle_since); + g_date_time_unref(now); + } + + /* Message */ + if(json_object_has_member(presence_object, "message")) { + value = json_object_get_string_member(presence_object, "message"); + if(!purple_strempty(value)) { + purple_presence_set_message(presence, value); + } + } + + /* Mobile */ + if(json_object_has_member(presence_object, "mobile")) { + gboolean bvalue = FALSE; + bvalue = json_object_get_boolean_member(presence_object, "mobile"); + purple_presence_set_mobile(presence, bvalue); + } + + /* Primitive */ + if(json_object_has_member(presence_object, "primitive")) { + PurplePresencePrimitive primitive = PURPLE_PRESENCE_PRIMITIVE_OFFLINE; + + value = json_object_get_string_member(presence_object, "primitive"); + if(!purple_strempty(value)) { + GEnumClass *enum_class = NULL; + GEnumValue *enum_value = NULL; + + enum_class = g_type_class_ref(PURPLE_TYPE_PRESENCE_PRIMITIVE); + enum_value = g_enum_get_value_by_nick(enum_class, value); + + if(enum_value != NULL) { + primitive = enum_value->value; + } + + g_type_class_unref(enum_class); + } + + purple_presence_set_primitive(presence, primitive); + } +} + +static void +purple_demo_contacts_load_contact(PurpleContactManager *manager, + PurpleAccount *account, + JsonObject *contact_object) +{ + PurpleContact *contact = NULL; + PurpleContactInfo *info = NULL; + gboolean new_contact = FALSE; + const char *id = NULL; + const char *value = NULL; + + /* If we have an id, grab so we can create the contact with it. */ + if(json_object_has_member(contact_object, "id")) { + id = json_object_get_string_member(contact_object, "id"); + } + + /* Look for an existing contact before creating a new one. This stops us + * from getting multiples when we trigger connection errors. + */ + if(!purple_strempty(id)) { + contact = purple_contact_manager_find_with_id(manager, account, id); + } + + /* If we didn't find an existing contact, create it now with the provided + * id. + */ + if(!PURPLE_IS_CONTACT(contact)) { + contact = purple_contact_new(account, id); + new_contact = TRUE; + } + + info = PURPLE_CONTACT_INFO(contact); + + /* Alias */ + if(json_object_has_member(contact_object, "alias")) { + value = json_object_get_string_member(contact_object, "alias"); + if(!purple_strempty(value)) { + purple_contact_info_set_alias(info, value); + } + } + + /* Color */ + if(json_object_has_member(contact_object, "color")) { + value = json_object_get_string_member(contact_object, "color"); + if(!purple_strempty(value)) { + purple_contact_info_set_color(info, value); + } + } + + /* Display Name */ + if(json_object_has_member(contact_object, "display_name")) { + value = json_object_get_string_member(contact_object, "display_name"); + if(!purple_strempty(value)) { + purple_contact_info_set_display_name(info, value); + } + } + + /* Username */ + if(json_object_has_member(contact_object, "username")) { + value = json_object_get_string_member(contact_object, "username"); + if(!purple_strempty(value)) { + purple_contact_info_set_username(info, value); + + purple_demo_contacts_load_contact_icon(info, value); + } + } + + /* Load the profile if it exists. */ + if(json_object_has_member(contact_object, "profile")) { + value = json_object_get_string_member(contact_object, "profile"); + if(!purple_strempty(value)) { + g_object_set_data_full(G_OBJECT(info), "demo-profile", + g_strdup(value), g_free); + } + } + + /* Load the tags. */ + if(json_object_has_member(contact_object, "tags")) { + PurpleTags *tags = purple_contact_info_get_tags(info); + JsonArray *array = NULL; + GList *elements = NULL; + + array = json_object_get_array_member(contact_object, "tags"); + elements = json_array_get_elements(array); + while(elements != NULL) { + JsonNode *tag_node = elements->data; + const char *tag = json_node_get_string(tag_node); + + purple_tags_add(tags, tag); + + elements = g_list_delete_link(elements, elements); + } + } + + /* Load the person. */ + if(json_object_has_member(contact_object, "person")) { + JsonObject *person_object = NULL; + + person_object = json_object_get_object_member(contact_object, + "person"); + + purple_demo_contacts_load_contact_person(person_object, info); + } + + /* Load the presence. */ + if(json_object_has_member(contact_object, "presence")) { + JsonObject *presence_object = NULL; + + presence_object = json_object_get_object_member(contact_object, + "presence"); + + purple_demo_contacts_load_contact_presence(presence_object, info); + } + + /* Finally add the contact to the contact manager if it's new. */ + if(new_contact) { + purple_contact_manager_add(manager, contact); + } + + g_clear_object(&contact); +} + +/****************************************************************************** + * Local Exports + *****************************************************************************/ +void +purple_demo_contacts_load(PurpleAccount *account) { + PurpleContactManager *manager = NULL; + GError *error = NULL; + GInputStream *istream = NULL; + GList *contacts = NULL; + JsonArray *contacts_array = NULL; + JsonNode *root_node = NULL; + JsonParser *parser = NULL; + + /* get a stream to the contacts.json resource */ + istream = g_resource_open_stream(purple_demo_get_resource(), + "/im/pidgin/purple/demo/contacts.json", + G_RESOURCE_LOOKUP_FLAGS_NONE, NULL); + + /* create our parser */ + parser = json_parser_new(); + + if(!json_parser_load_from_stream(parser, istream, NULL, &error)) { + g_critical("%s", error->message); + g_clear_error(&error); + return; + } + + root_node = json_parser_get_root(parser); + + manager = purple_contact_manager_get_default(); + + /* Load the contacts! */ + contacts_array = json_node_get_array(root_node); + contacts = json_array_get_elements(contacts_array); + while(contacts != NULL) { + JsonNode *contact_node = NULL; + JsonObject *contact_object = NULL; + + contact_node = contacts->data; + contact_object = json_node_get_object(contact_node); + + purple_demo_contacts_load_contact(manager, account, contact_object); + + contacts = g_list_delete_link(contacts, contacts); + } + + /* Clean up everything else... */ + g_clear_object(&parser); + + g_input_stream_close(istream, NULL, NULL); + g_object_unref(istream); +}