pidgin/pidgin

Create the new PurpleContact

18 months ago, Gary Kramlich
f589ceec0172
Parents 5ff19c662e31
Children d8fcd2907c3d
Create the new PurpleContact

Testing Done:
Ran the unit tests and `ninja pidgin-pot`

Bugs closed: PIDGIN-17663

Reviewed at https://reviews.imfreedom.org/r/1828/
--- a/libpurple/meson.build Fri Sep 23 03:44:40 2022 -0500
+++ b/libpurple/meson.build Fri Sep 23 03:47:08 2022 -0500
@@ -45,6 +45,7 @@
'purplechatconversation.c',
'purplechatuser.c',
'purpleconnectionerrorinfo.c',
+ 'purplecontact.c',
'purpleconversation.c',
'purpleconversationmanager.c',
'purpleconversationuiops.c',
@@ -147,6 +148,7 @@
'purplechatconversation.h',
'purplechatuser.h',
'purpleconnectionerrorinfo.h',
+ 'purplecontact.h',
'purpleconversation.h',
'purpleconversationmanager.h',
'purpleconversationuiops.h',
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/purplecontact.c Fri Sep 23 03:47:08 2022 -0500
@@ -0,0 +1,438 @@
+/*
+ * Purple - Internet Messaging Library
+ * Copyright (C) Pidgin Developers <devel@pidgin.im>
+ *
+ * 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 "purplecontact.h"
+
+struct _PurpleContact {
+ GObject parent;
+
+ gchar *id;
+ PurpleAccount *account;
+
+ gchar *username;
+ gchar *display_name;
+ gchar *alias;
+
+ GdkPixbuf *avatar;
+
+ PurplePresence *presence;
+
+ PurpleTags *tags;
+};
+
+enum {
+ PROP_0,
+ PROP_ID,
+ PROP_ACCOUNT,
+ PROP_USERNAME,
+ PROP_DISPLAY_NAME,
+ PROP_ALIAS,
+ PROP_AVATAR,
+ PROP_PRESENCE,
+ PROP_TAGS,
+ N_PROPERTIES
+};
+static GParamSpec *properties[N_PROPERTIES] = {NULL, };
+
+G_DEFINE_TYPE(PurpleContact, purple_contact, G_TYPE_OBJECT)
+
+/******************************************************************************
+ * Helpers
+ *****************************************************************************/
+static void
+purple_contact_set_account(PurpleContact *contact, PurpleAccount *account) {
+ g_return_if_fail(PURPLE_IS_CONTACT(contact));
+ g_return_if_fail(PURPLE_IS_ACCOUNT(account));
+
+ if(g_set_object(&contact->account, account)) {
+ g_object_notify_by_pspec(G_OBJECT(contact), properties[PROP_ACCOUNT]);
+ }
+}
+
+static void
+purple_contact_set_id(PurpleContact *contact, const gchar *id) {
+ g_return_if_fail(PURPLE_IS_CONTACT(contact));
+
+ g_free(contact->id);
+
+ if(id != NULL) {
+ contact->id = g_strdup(id);
+ } else {
+ contact->id = g_uuid_string_random();
+ }
+
+ g_object_notify_by_pspec(G_OBJECT(contact), properties[PROP_ID]);
+}
+
+/******************************************************************************
+ * GObject Implementation
+ *****************************************************************************/
+static void
+purple_contact_get_property(GObject *obj, guint param_id, GValue *value,
+ GParamSpec *pspec)
+{
+ PurpleContact *contact = PURPLE_CONTACT(obj);
+
+ switch(param_id) {
+ case PROP_ID:
+ g_value_set_string(value, purple_contact_get_id(contact));
+ break;
+ case PROP_ACCOUNT:
+ g_value_set_object(value, purple_contact_get_account(contact));
+ break;
+ case PROP_USERNAME:
+ g_value_set_string(value, purple_contact_get_username(contact));
+ break;
+ case PROP_DISPLAY_NAME:
+ g_value_set_string(value, purple_contact_get_display_name(contact));
+ break;
+ case PROP_ALIAS:
+ g_value_set_string(value, purple_contact_get_alias(contact));
+ break;
+ case PROP_AVATAR:
+ g_value_set_object(value, purple_contact_get_avatar(contact));
+ break;
+ case PROP_PRESENCE:
+ g_value_set_object(value, purple_contact_get_presence(contact));
+ break;
+ case PROP_TAGS:
+ g_value_set_object(value, purple_contact_get_tags(contact));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+ break;
+ }
+}
+
+static void
+purple_contact_set_property(GObject *obj, guint param_id, const GValue *value,
+ GParamSpec *pspec)
+{
+ PurpleContact *contact = PURPLE_CONTACT(obj);
+
+ switch(param_id) {
+ case PROP_ID:
+ purple_contact_set_id(contact, g_value_get_string(value));
+ break;
+ case PROP_ACCOUNT:
+ purple_contact_set_account(contact, g_value_get_object(value));
+ break;
+ case PROP_USERNAME:
+ purple_contact_set_username(contact, g_value_get_string(value));
+ break;
+ case PROP_DISPLAY_NAME:
+ purple_contact_set_display_name(contact, g_value_get_string(value));
+ break;
+ case PROP_ALIAS:
+ purple_contact_set_alias(contact, g_value_get_string(value));
+ break;
+ case PROP_AVATAR:
+ purple_contact_set_avatar(contact, g_value_get_object(value));
+ break;
+ case PROP_PRESENCE:
+ purple_contact_set_presence(contact, g_value_get_object(value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+ break;
+ }
+}
+
+static void
+purple_contact_dispose(GObject *obj) {
+ PurpleContact *contact = PURPLE_CONTACT(obj);
+
+ g_clear_object(&contact->account);
+ g_clear_object(&contact->avatar);
+ g_clear_object(&contact->presence);
+ g_clear_object(&contact->tags);
+
+ G_OBJECT_CLASS(purple_contact_parent_class)->dispose(obj);
+}
+
+static void
+purple_contact_finalize(GObject *obj) {
+ PurpleContact *contact = PURPLE_CONTACT(obj);
+
+ g_clear_pointer(&contact->id, g_free);
+ g_clear_pointer(&contact->username, g_free);
+ g_clear_pointer(&contact->display_name, g_free);
+ g_clear_pointer(&contact->alias, g_free);
+
+ G_OBJECT_CLASS(purple_contact_parent_class)->finalize(obj);
+}
+
+static void
+purple_contact_constructed(GObject *obj) {
+ PurpleContact *contact = NULL;
+
+ G_OBJECT_CLASS(purple_contact_parent_class)->constructed(obj);
+
+ contact = PURPLE_CONTACT(obj);
+ if(contact->id == NULL) {
+ purple_contact_set_id(contact, NULL);
+ }
+}
+
+static void
+purple_contact_init(PurpleContact *contact) {
+ contact->tags = purple_tags_new();
+}
+
+static void
+purple_contact_class_init(PurpleContactClass *klass) {
+ GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+
+ obj_class->get_property = purple_contact_get_property;
+ obj_class->set_property = purple_contact_set_property;
+ obj_class->constructed = purple_contact_constructed;
+ obj_class->dispose = purple_contact_dispose;
+ obj_class->finalize = purple_contact_finalize;
+
+ /**
+ * PurpleContact:id:
+ *
+ * The protocol specific id for the contact.
+ *
+ * Since: 3.0.0
+ */
+ properties[PROP_ID] = g_param_spec_string(
+ "id", "id",
+ "The id of the contact",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * PurpleContact:account:
+ *
+ * The account that this contact belongs to.
+ *
+ * Since: 3.0.0
+ */
+ properties[PROP_ACCOUNT] = g_param_spec_object(
+ "account", "account",
+ "The account this contact belongs to",
+ PURPLE_TYPE_ACCOUNT,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * PurpleContact:username:
+ *
+ * The username for this contact. In rare cases this can change, like when
+ * a user changes their "nick" on IRC which is their user name.
+ *
+ * Since: 3.0.0
+ */
+ properties[PROP_USERNAME] = g_param_spec_string(
+ "username", "username",
+ "The username of the contact",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * PurpleContact:display-name:
+ *
+ * The display name for this contact. This is generally set by the person
+ * the contact is representing and controlled via the protocol plugin.
+ *
+ * Since: 3.0.0
+ */
+ properties[PROP_DISPLAY_NAME] = g_param_spec_string(
+ "display-name", "display-name",
+ "The display name of the contact",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * PurpleContact:alias:
+ *
+ * The alias for this contact. This is controlled by the libpurple user and
+ * may be used by the protocol if it allows for aliasing.
+ *
+ * Since: 3.0.0
+ */
+ properties[PROP_ALIAS] = g_param_spec_string(
+ "alias", "alias",
+ "The alias of the contact.",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * PurpleContact:avatar:
+ *
+ * The avatar for this contact. This is typically controlled by the protocol
+ * and should only be read by others.
+ *
+ * Since: 3.0.0
+ */
+ properties[PROP_AVATAR] = g_param_spec_object(
+ "avatar", "avatar",
+ "The avatar of the contact",
+ GDK_TYPE_PIXBUF,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * PurpleContact:presence:
+ *
+ * The [class@Purple.Presence] for this contact. This is typically
+ * controlled by the protocol and should only be read by others.
+ *
+ * Since: 3.0.0
+ */
+ properties[PROP_PRESENCE] = g_param_spec_object(
+ "presence", "presence",
+ "The presence of the contact",
+ PURPLE_TYPE_PRESENCE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * PurpleContact:tags:
+ *
+ * The [class@Purple.Tags] for this contact.
+ *
+ * Since: 3.0.0
+ */
+ properties[PROP_TAGS] = g_param_spec_object(
+ "tags", "tags",
+ "The tags for the contact",
+ PURPLE_TYPE_TAGS,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties(obj_class, N_PROPERTIES, properties);
+}
+
+/******************************************************************************
+ * Public API
+ *****************************************************************************/
+PurpleContact *
+purple_contact_new(PurpleAccount *account, const gchar *username) {
+ g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
+ g_return_val_if_fail(username != NULL, NULL);
+
+ return g_object_new(PURPLE_TYPE_CONTACT,
+ "account", account,
+ "username", username,
+ NULL);
+}
+
+PurpleAccount *
+purple_contact_get_account(PurpleContact *contact) {
+ g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
+
+ return contact->account;
+}
+
+const gchar *
+purple_contact_get_id(PurpleContact *contact) {
+ g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
+
+ return contact->id;
+}
+
+const gchar *
+purple_contact_get_username(PurpleContact *contact) {
+ g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
+
+ return contact->username;
+}
+
+void
+purple_contact_set_username(PurpleContact *contact, const gchar *username) {
+ g_return_if_fail(PURPLE_IS_CONTACT(contact));
+ g_return_if_fail(username != NULL);
+
+ g_free(contact->username);
+ contact->username = g_strdup(username);
+
+ g_object_notify_by_pspec(G_OBJECT(contact), properties[PROP_USERNAME]);
+}
+
+const gchar *
+purple_contact_get_display_name(PurpleContact *contact) {
+ g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
+
+ return contact->display_name;
+}
+
+void
+purple_contact_set_display_name(PurpleContact *contact,
+ const gchar *display_name)
+{
+ g_return_if_fail(PURPLE_IS_CONTACT(contact));
+
+ g_free(contact->display_name);
+ contact->display_name = g_strdup(display_name);
+
+ g_object_notify_by_pspec(G_OBJECT(contact), properties[PROP_DISPLAY_NAME]);
+}
+
+const gchar *
+purple_contact_get_alias(PurpleContact *contact) {
+ g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
+
+ return contact->alias;
+}
+
+void
+purple_contact_set_alias(PurpleContact *contact, const gchar *alias) {
+ g_return_if_fail(PURPLE_IS_CONTACT(contact));
+
+ g_free(contact->alias);
+ contact->alias = g_strdup(alias);
+
+ g_object_notify_by_pspec(G_OBJECT(contact), properties[PROP_ALIAS]);
+}
+
+GdkPixbuf *
+purple_contact_get_avatar(PurpleContact *contact) {
+ g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
+
+ return contact->avatar;
+}
+
+void
+purple_contact_set_avatar(PurpleContact *contact, GdkPixbuf *avatar) {
+ g_return_if_fail(PURPLE_IS_CONTACT(contact));
+
+ if(g_set_object(&contact->avatar, avatar)) {
+ g_object_notify_by_pspec(G_OBJECT(contact), properties[PROP_AVATAR]);
+ }
+}
+
+PurplePresence *
+purple_contact_get_presence(PurpleContact *contact) {
+ g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
+
+ return contact->presence;
+}
+
+void
+purple_contact_set_presence(PurpleContact *contact, PurplePresence *presence) {
+ g_return_if_fail(PURPLE_IS_CONTACT(contact));
+
+ if(g_set_object(&contact->presence, presence)) {
+ g_object_notify_by_pspec(G_OBJECT(contact), properties[PROP_PRESENCE]);
+ }
+}
+
+PurpleTags *
+purple_contact_get_tags(PurpleContact *contact) {
+ g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
+
+ return contact->tags;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/purplecontact.h Fri Sep 23 03:47:08 2022 -0500
@@ -0,0 +1,229 @@
+/*
+ * Purple - Internet Messaging Library
+ * Copyright (C) Pidgin Developers <devel@pidgin.im>
+ *
+ * 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 <pidgin.h> may be included directly"
+#endif
+
+#ifndef PURPLE_CONTACT_H
+#define PURPLE_CONTACT_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#include <libpurple/account.h>
+#include <libpurple/purpletags.h>
+
+G_BEGIN_DECLS
+
+#define PURPLE_TYPE_CONTACT (purple_contact_get_type())
+G_DECLARE_FINAL_TYPE(PurpleContact, purple_contact, PURPLE, CONTACT, GObject)
+
+/**
+ * PurpleContact:
+ *
+ * A representation of a user. Contacts are used everywhere you need to refer to
+ * a user. Be it a chat, an direct message, a file transfer, etc.
+ */
+
+/**
+ * purple_contact_new:
+ * @account: The [class@Purple.Account] this contact is from.
+ * @username: The username of the contact.
+ *
+ * Creates a new [class@Purple.Contact].
+ */
+PurpleContact *purple_contact_new(PurpleAccount *account, const gchar *username);
+
+/**
+ * purple_contact_get_account:
+ * @contact: The instance.
+ *
+ * Gets the [class@Purple.Account] that @contact belongs to.
+ *
+ * Returns: (transfer none): The [class@Purple.Account] that @contact belongs
+ * to.
+ *
+ * Since: 3.0.0
+ */
+PurpleAccount *purple_contact_get_account(PurpleContact *contact);
+
+/**
+ * purple_contact_get_id:
+ * @contact: The instance.
+ *
+ * Gets the id of @contact.
+ *
+ * If a protocol would like to set this, it should call
+ * [ctor@GObject.Object.new] and pass in the id attribute manually.
+ *
+ * Returns: The id of the contact.
+ *
+ * Since: 3.0.0
+ */
+const gchar *purple_contact_get_id(PurpleContact *contact);
+
+/**
+ * purple_contact_get_username:
+ * @contact: The instance.
+ *
+ * Gets the username of @contact.
+ *
+ * Returns: The username of @contact.
+ *
+ * Since: 3.0.0
+ */
+const gchar *purple_contact_get_username(PurpleContact *contact);
+
+/**
+ * purple_contact_set_username:
+ * @contact: The instance.
+ * @username: The new username.
+ *
+ * Sets the username of @contact to @username.
+ *
+ * This is primarily used by protocol plugins like IRC when a user changes
+ * their "nick" which is their username.
+ *
+ * Since: 3.0.0
+ */
+void purple_contact_set_username(PurpleContact *contact, const gchar *username);
+
+/**
+ * purple_contact_get_display_name:
+ * @contact: The instance.
+ *
+ * Gets the display name for @contact. The display name is typically set by the
+ * contact and is handled by the protocol plugin.
+ *
+ * Returns: (nullable): The display name of @contact if one is set, otherwise
+ * %NULL will be returned.
+ *
+ * Since: 3.0.0
+ */
+const gchar *purple_contact_get_display_name(PurpleContact *contact);
+
+/**
+ * purple_contact_set_display_name:
+ * @contact: The instance.
+ * @display_name: (nullable): The new displayname.
+ *
+ * Sets the display name of @contact to @display_name.
+ *
+ * This should primarily only be used by protocol plugins and everyone else
+ * should be using [method@Purple.Contact.set_alias].
+ *
+ * Since: 3.0.0
+ */
+void purple_contact_set_display_name(PurpleContact *contact, const gchar *display_name);
+
+/**
+ * purple_contact_get_alias:
+ * @contact: The instance.
+ *
+ * Gets the alias for @contact.
+ *
+ * Returns: (nullable): The alias of @contact if one is set, otherwise %NULL.
+ *
+ * Since: 3.0.0
+ */
+const gchar *purple_contact_get_alias(PurpleContact *contact);
+
+/**
+ * purple_contact_set_alias:
+ * @contact: The instance.
+ * @alias: (nullable): The new alias.
+ *
+ * Sets the alias of @contact to @alias.
+ *
+ * Protocol plugins may use this value to synchronize across instances.
+ *
+ * Since: 3.0.0
+ */
+void purple_contact_set_alias(PurpleContact *contact, const gchar *alias);
+
+/**
+ * purple_contact_get_avatar:
+ * @contact: The instance.
+ *
+ * Gets the avatar for @contact if one is set.
+ *
+ * Returns: (transfer none): The avatar if set, otherwise %NULL.
+ *
+ * Since: 3.0.0
+ */
+GdkPixbuf *purple_contact_get_avatar(PurpleContact *contact);
+
+/**
+ * purple_contact_set_avatar:
+ * @contact: The instance.
+ * @avatar: (nullable): The new avatar to set.
+ *
+ * Sets the avatar for @contact to @avatar. If @avatar is %NULL an existing
+ * avatar will be removed.
+ *
+ * Typically this should only called by the protocol plugin.
+ *
+ * Since: 3.0.0
+ */
+void purple_contact_set_avatar(PurpleContact *contact, GdkPixbuf *avatar);
+
+/**
+ * purple_contact_get_presence:
+ * @contact: The instance.
+ *
+ * Gets the [class@Purple.Presence] for @contact.
+ *
+ * Returns: (nullable): The presence for @contact if one is set, otherwise
+ * %NULL.
+ *
+ * Since: 3.0.0
+ */
+PurplePresence *purple_contact_get_presence(PurpleContact *contact);
+
+/**
+ * purple_contact_set_presence:
+ * @contact: The instance.
+ * @presence: (nullable): The new [class@Purple.Presence] to set.
+ *
+ * Sets the presence for @contact to @presence. If @presence is %NULL, the
+ * existing presence will be cleared.
+ *
+ * Typically this should only be called by the protocol plugin.
+ *
+ * Since: 3.0.0
+ */
+void purple_contact_set_presence(PurpleContact *contact, PurplePresence *presence);
+
+/**
+ * purple_contact_get_tags:
+ * @contact: The instance.
+ *
+ * Gets the [class@Purple.Tags] instance for @contact.
+ *
+ * Returns: (transfer none): The tags for @contact.
+ *
+ * Since: 3.0.0
+ */
+PurpleTags *purple_contact_get_tags(PurpleContact *contact);
+
+G_END_DECLS
+
+#endif /* PURPLE_CONTACT_H */
--- a/libpurple/tests/meson.build Fri Sep 23 03:44:40 2022 -0500
+++ b/libpurple/tests/meson.build Fri Sep 23 03:47:08 2022 -0500
@@ -3,6 +3,7 @@
'account_manager',
'authorization_request',
'circular_buffer',
+ 'contact',
'credential_provider',
'history_adapter',
'history_manager',
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/tests/test_contact.c Fri Sep 23 03:47:08 2022 -0500
@@ -0,0 +1,129 @@
+/*
+ * 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 <purple.h>
+
+#include "test_ui.h"
+
+/******************************************************************************
+ * Tests
+ *****************************************************************************/
+static void
+test_purple_contact_new(void) {
+ PurpleAccount *account = NULL;
+ PurpleContact *contact = NULL;
+
+ account = purple_account_new("test", "test");
+ contact = purple_contact_new(account, "username");
+
+ g_assert_true(purple_contact_get_account(contact) == account);
+ g_assert_cmpstr(purple_contact_get_username(contact), ==, "username");
+
+ g_clear_object(&contact);
+ g_clear_object(&account);
+}
+
+static void
+test_purple_contact_properties(void) {
+ PurpleAccount *account = NULL;
+ PurpleAccount *account1 = NULL;
+ PurpleContact *contact = NULL;
+ PurplePresence *presence = NULL;
+ PurplePresence *presence1 = NULL;
+ PurpleTags *tags = NULL;
+ GdkPixbuf *avatar = NULL;
+ GdkPixbuf *avatar1 = NULL;
+ gchar *id = NULL;
+ gchar *username = NULL;
+ gchar *display_name = NULL;
+ gchar *alias = NULL;
+
+ account = purple_account_new("test", "test");
+ avatar = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, 1, 1);
+ presence = g_object_new(PURPLE_TYPE_PRESENCE, NULL);
+
+ /* 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
+ * code.
+ */
+ contact = g_object_new(
+ PURPLE_TYPE_CONTACT,
+ "account", account,
+ "username", "username",
+ "display-name", "display-name",
+ "alias", "alias",
+ "avatar", avatar,
+ "presence", presence,
+ NULL);
+
+ /* Now use g_object_get to read all of the properties. */
+ g_object_get(contact,
+ "id", &id,
+ "account", &account1,
+ "username", &username,
+ "display-name", &display_name,
+ "alias", &alias,
+ "avatar", &avatar1,
+ "presence", &presence1,
+ "tags", &tags,
+ NULL);
+
+ /* Compare all the things. */
+ g_assert_nonnull(id);
+ g_assert_true(account1 == account);
+ g_assert_cmpstr(username, ==, "username");
+ g_assert_cmpstr(display_name, ==, "display-name");
+ g_assert_cmpstr(alias, ==, "alias");
+ g_assert_true(avatar1 == avatar);
+ g_assert_true(presence1 == presence);
+ g_assert_nonnull(tags);
+
+ /* Free/unref all the things. */
+ g_clear_pointer(&id, g_free);
+ g_clear_object(&account1);
+ g_clear_pointer(&username, g_free);
+ g_clear_pointer(&display_name, g_free);
+ g_clear_pointer(&alias, g_free);
+ g_clear_object(&avatar1);
+ g_clear_object(&presence1);
+ g_clear_object(&tags);
+
+ g_clear_object(&presence);
+ g_clear_object(&avatar);
+ g_clear_object(&contact);
+ g_clear_object(&account);
+}
+
+/******************************************************************************
+ * Main
+ *****************************************************************************/
+gint
+main(gint argc, gchar *argv[]) {
+ g_test_init(&argc, &argv, NULL);
+
+ test_ui_purple_init();
+
+ g_test_add_func("/contact/new",
+ test_purple_contact_new);
+ g_test_add_func("/contact/properties",
+ test_purple_contact_properties);
+
+ return g_test_run();
+}
\ No newline at end of file
--- a/po/POTFILES.in Fri Sep 23 03:44:40 2022 -0500
+++ b/po/POTFILES.in Fri Sep 23 03:47:08 2022 -0500
@@ -239,6 +239,7 @@
libpurple/purplebuddypresence.c
libpurple/purplechatconversation.c
libpurple/purplechatuser.c
+libpurple/purplecontact.c
libpurple/purpleconversation.c
libpurple/purpleconversationmanager.c
libpurple/purpleconversationuiops.c
@@ -289,6 +290,7 @@
libpurple/tests/test_account_manager.c
libpurple/tests/test_account_option.c
libpurple/tests/test_circular_buffer.c
+libpurple/tests/test_contact.c
libpurple/tests/test_credential_manager.c
libpurple/tests/test_credential_provider.c
libpurple/tests/test_history_adapter.c