Replace the ui info GHashTable with a gobject.

Fri, 20 Mar 2020 08:57:57 -0500

author
Gary Kramlich <grim@reaperworld.com>
date
Fri, 20 Mar 2020 08:57:57 -0500
changeset 40312
956745ff3ee8
parent 40311
b28beec32e25
child 40313
d0f01217e491

Replace the ui info GHashTable with a gobject.

doc/reference/libpurple/libpurple-docs.xml file | annotate | diff | comparison | revisions
finch/libfinch.c file | annotate | diff | comparison | revisions
libpurple/core.c file | annotate | diff | comparison | revisions
libpurple/core.h file | annotate | diff | comparison | revisions
libpurple/meson.build file | annotate | diff | comparison | revisions
libpurple/plugins/keyrings/kwallet/purplekwallet.cpp file | annotate | diff | comparison | revisions
libpurple/protocols/jabber/bosh.c file | annotate | diff | comparison | revisions
libpurple/protocols/jabber/iq.c file | annotate | diff | comparison | revisions
libpurple/protocols/jabber/jabber.c file | annotate | diff | comparison | revisions
libpurple/purpleuiinfo.c file | annotate | diff | comparison | revisions
libpurple/purpleuiinfo.h file | annotate | diff | comparison | revisions
pidgin/libpidgin.c file | annotate | diff | comparison | revisions
--- a/doc/reference/libpurple/libpurple-docs.xml	Fri Mar 13 22:11:34 2020 -0500
+++ b/doc/reference/libpurple/libpurple-docs.xml	Fri Mar 20 08:57:57 2020 -0500
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" 
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
                "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
 
 <!ENTITY % local.common.attrib "xmlns:xi  CDATA  #FIXED 'http://www.w3.org/2003/XInclude'">
@@ -66,6 +66,7 @@
       <xi:include href="xml/purple-gio.xml" />
       <xi:include href="xml/purpleaccountoption.xml" />
       <xi:include href="xml/purpleaccountusersplit.xml" />
+      <xi:include href="xml/purpleuiinfo.xml" />
       <xi:include href="xml/queuedoutputstream.xml" />
       <xi:include href="xml/signals.xml" />
       <xi:include href="xml/request.xml" />
@@ -93,7 +94,7 @@
   </part>
 
   <part id="Submodules">
-	  <title>Submodules</title>
+    <title>Submodules</title>
     <chapter id="messages">
       <title>Messaging</title>
 
--- a/finch/libfinch.c	Fri Mar 13 22:11:34 2020 -0500
+++ b/finch/libfinch.c	Fri Mar 20 08:57:57 2020 -0500
@@ -56,48 +56,13 @@
 	purple_debug_set_ui(PURPLE_DEBUG_UI(ui));
 }
 
-static GHashTable *ui_info = NULL;
-static GHashTable *finch_ui_get_info(void)
+static PurpleUiInfo *ui_info = NULL;
+static PurpleUiInfo *
+finch_ui_get_info(void)
 {
-	if (ui_info == NULL) {
-		ui_info = g_hash_table_new(g_str_hash, g_str_equal);
-
-		g_hash_table_insert(ui_info, "name", (char*)_("Finch"));
-		g_hash_table_insert(ui_info, "version", VERSION);
-		g_hash_table_insert(ui_info, "website", "https://pidgin.im");
-		g_hash_table_insert(ui_info, "dev_website", "https://developer.pidgin.im");
-		g_hash_table_insert(ui_info, "client_type", "console");
-
-		/*
-		 * This is the client key for "Finch." Please don't use this
-		 * key for other applications.  You can not specify a client
-		 * key, in which case the default "libpurple" key will be used
-		 */
-		g_hash_table_insert(ui_info, "prpl-aim-clientkey", "ma18nmEklXMR7Cj_");
-
-		/*
-		 * This is the client key for "Pidgin."  It is owned by the AIM
-		 * account "markdoliner."  Please don't use this key for other
-		 * applications.  You can either not specify a client key, in
-		 * which case the default "libpurple" key will be used, or you
-		 * can try to register your own at the AIM or ICQ web sites
-		 * (although this functionality was removed at some point, it's
-		 * possible it has been re-added).  AOL's old key management
-		 * page is http://developer.aim.com/manageKeys.jsp
-		 *
-		 * We used to have a Finch-specific devId/clientkey
-		 * (ma19sqWV9ymU6UYc), but it stopped working, so we switched
-		 * to this one.
-		 */
-		g_hash_table_insert(ui_info, "prpl-icq-clientkey", "ma1cSASNCKFtrdv9");
-
-		/*
-		 * This is the distid for Finch, given to us by AOL.  Please
-		 * don't use this for other applications.  You can just not
-		 * specify a distid and libpurple will use a default.
-		 */
-		g_hash_table_insert(ui_info, "prpl-aim-distid", GINT_TO_POINTER(1718));
-		g_hash_table_insert(ui_info, "prpl-icq-distid", GINT_TO_POINTER(1552));
+	if(!PURPLE_IS_UI_INFO(ui_info)) {
+		ui_info = purple_ui_info_new(_("Finch"), VERSION, "https://pidgin.im",
+		                             "https://developer.pidgin.im", "console");
 	}
 
 	return ui_info;
@@ -107,8 +72,7 @@
 finch_quit(void)
 {
 	finch_ui_uninit();
-	if (ui_info)
-		g_hash_table_destroy(ui_info);
+	g_clear_object(&ui_info);
 }
 
 static PurpleCoreUiOps core_ops =
@@ -118,12 +82,6 @@
 	finch_ui_init,
 	finch_quit,
 	finch_ui_get_info,
-
-	/* padding */
-	NULL,
-	NULL,
-	NULL,
-	NULL
 };
 
 static PurpleCoreUiOps *
--- a/libpurple/core.c	Fri Mar 13 22:11:34 2020 -0500
+++ b/libpurple/core.c	Fri Mar 20 08:57:57 2020 -0500
@@ -61,13 +61,13 @@
 static void
 purple_core_print_version(void)
 {
-	GHashTable *ui_info = purple_core_get_ui_info();
+	PurpleUiInfo *ui_info = purple_core_get_ui_info();
 	const gchar *ui_name;
 	const gchar *ui_version;
 	gchar *ui_full_name = NULL;
 
-	ui_name = ui_info ? g_hash_table_lookup(ui_info, "name") : NULL;
-	ui_version = ui_info ? g_hash_table_lookup(ui_info, "version") : NULL;
+	ui_name = ui_info ? purple_ui_info_get_name(ui_info) : NULL;
+	ui_version = ui_info ? purple_ui_info_get_version(ui_info) : NULL;
 
 	if (ui_name) {
 		if (ui_version) {
@@ -83,6 +83,7 @@
 		purple_core_get_version());
 
 	g_free(ui_full_name);
+	g_object_unref(G_OBJECT(ui_info));
 }
 
 gboolean
@@ -333,7 +334,7 @@
 	return _ops;
 }
 
-GHashTable* purple_core_get_ui_info() {
+PurpleUiInfo* purple_core_get_ui_info() {
 	PurpleCoreUiOps *ops = purple_core_get_ui_ops();
 
 	if(NULL == ops || NULL == ops->get_ui_info)
--- a/libpurple/core.h	Fri Mar 13 22:11:34 2020 -0500
+++ b/libpurple/core.h	Fri Mar 20 08:57:57 2020 -0500
@@ -32,6 +32,8 @@
 #include <glib.h>
 #include <glib-object.h>
 
+#include <libpurple/purpleuiinfo.h>
+
 #define PURPLE_TYPE_CORE_UI_OPS (purple_core_ui_ops_get_type())
 
 typedef struct PurpleCore PurpleCore;
@@ -66,13 +68,10 @@
 
 	void (*quit)(void);
 
-	GHashTable* (*get_ui_info)(void);
+	PurpleUiInfo *(*get_ui_info)(void);
 
 	/*< private >*/
-	void (*_purple_reserved1)(void);
-	void (*_purple_reserved2)(void);
-	void (*_purple_reserved3)(void);
-	void (*_purple_reserved4)(void);
+	gpointer reserved[4];
 };
 
 G_BEGIN_DECLS
@@ -175,52 +174,20 @@
 /**
  * purple_core_get_ui_info:
  *
- * Returns a hash table containing various information about the UI.  The
- * following well-known entries may be in the table (along with any others the
- * UI might choose to include):
+ * Returns a #PurpleUiInfo that contains information about the user interface.
  *
- * <informaltable frame='none'>
- *   <tgroup cols='2'><tbody>
- *   <row>
- *     <entry><literal>name</literal></entry>
- *     <entry>the user-readable name for the UI.</entry>
- *   </row>
- *   <row>
- *     <entry><literal>version</literal></entry>
- *     <entry>a user-readable description of the current version of the UI.</entry>
- *   </row>
- *   <row>
- *     <entry><literal>website</literal></entry>
- *     <entry>the UI's website, such as https://pidgin.im.</entry>
- *   </row>
- *   <row>
- *     <entry><literal>dev_website</literal></entry>
- *     <entry>the UI's development/support website, such as
- *       https://developer.pidgin.im.</entry>
- *   </row>
- *   <row>
- *     <entry><literal>client_type</literal></entry>
- *     <entry>the type of UI. Possible values include 'pc', 'console', 'phone',
- *       'handheld', 'web', and 'bot'. These values are compared
- *       programmatically and should not be localized.</entry>
- *   </row>
- *   </tbody></tgroup>
- * </informaltable>
- *
- * Returns: (transfer none): A GHashTable with strings for keys and values.
- *          This hash table should not be modified.
- *
+ * Returns: (transfer full): A #PurpleUiInfo instance.
  */
-GHashTable* purple_core_get_ui_info(void);
+PurpleUiInfo* purple_core_get_ui_info(void);
 
 /**
  * purple_core_migrate_to_xdg_base_dirs:
- * 
- * Migrates from legacy directory for libpurple to location following 
+ *
+ * Migrates from legacy directory for libpurple to location following
  * XDG base dir spec. https://developer.pidgin.im/ticket/10029
  * NOTE This is not finished yet. Need to decide where other profile files
  * should be moved. Search for usages of purple_user_dir().
- * 
+ *
  * Returns: TRUE if migrated successfully, FALSE otherwise. On failure,
  *         the application must display an error to the user and then exit.
  */
--- a/libpurple/meson.build	Fri Mar 13 22:11:34 2020 -0500
+++ b/libpurple/meson.build	Fri Mar 20 08:57:57 2020 -0500
@@ -48,6 +48,7 @@
 	'purple-gio.c',
 	'purpleaccountoption.c',
 	'purpleaccountusersplit.c',
+	'purpleuiinfo.c',
 	'queuedoutputstream.c',
 	'request.c',
 	'request-datasheet.c',
@@ -124,6 +125,7 @@
 	'purple-gio.h',
 	'purpleaccountoption.h',
 	'purpleaccountusersplit.h',
+	'purpleuiinfo.h',
 	'queuedoutputstream.h',
 	'request.h',
 	'request-datasheet.h',
--- a/libpurple/plugins/keyrings/kwallet/purplekwallet.cpp	Fri Mar 13 22:11:34 2020 -0500
+++ b/libpurple/plugins/keyrings/kwallet/purplekwallet.cpp	Fri Mar 20 08:57:57 2020 -0500
@@ -400,14 +400,18 @@
 
 static const char *kwallet_get_ui_name(void)
 {
-	GHashTable *ui_info;
+	PurpleUiInfo *ui_info = NULL;
 	const char *ui_name = NULL;
 
 	ui_info = purple_core_get_ui_info();
-	if (ui_info != NULL)
-		ui_name = (const char*)g_hash_table_lookup(ui_info, "name");
-	if (ui_name == NULL)
+	if(PURPLE_IS_UI_INFO(ui_info)) {
+		ui_name = purple_ui_info_get_name(ui_info);
+		g_object_unref(G_OBJECT(ui_info));
+	}
+
+	if(ui_name == NULL) {
 		ui_name = KWALLET_APP_NAME;
+	}
 
 	return ui_name;
 }
--- a/libpurple/protocols/jabber/bosh.c	Fri Mar 13 22:11:34 2020 -0500
+++ b/libpurple/protocols/jabber/bosh.c	Fri Mar 20 08:57:57 2020 -0500
@@ -64,21 +64,26 @@
 void
 jabber_bosh_init(void)
 {
-	GHashTable *ui_info = purple_core_get_ui_info();
+	PurpleUiInfo *ui_info = purple_core_get_ui_info();
 	const gchar *ui_name = NULL;
 	const gchar *ui_version = NULL;
 
-	if (ui_info) {
-		ui_name = g_hash_table_lookup(ui_info, "name");
-		ui_version = g_hash_table_lookup(ui_info, "version");
+	if(ui_info) {
+		ui_name = purple_ui_info_get_name(ui_info);
+		ui_version = purple_ui_info_get_version(ui_info);
 	}
 
-	if (ui_name) {
+	if(ui_name) {
 		jabber_bosh_useragent = g_strdup_printf(
 			"%s%s%s (libpurple " VERSION ")", ui_name,
 			ui_version ? " " : "", ui_version ? ui_version : "");
-	} else
+	} else {
 		jabber_bosh_useragent = g_strdup("libpurple " VERSION);
+	}
+
+	if(ui_info) {
+		g_object_unref(G_OBJECT(ui_info));
+	}
 }
 
 void jabber_bosh_uninit(void)
--- a/libpurple/protocols/jabber/iq.c	Fri Mar 13 22:11:34 2020 -0500
+++ b/libpurple/protocols/jabber/iq.c	Fri Mar 20 08:57:57 2020 -0500
@@ -228,7 +228,7 @@
 	PurpleXmlNode *query;
 
 	if(type == JABBER_IQ_GET) {
-		GHashTable *ui_info;
+		PurpleUiInfo *ui_info;
 		const char *ui_name = NULL, *ui_version = NULL;
 
 		iq = jabber_iq_new_query(js, JABBER_IQ_RESULT, "jabber:iq:version");
@@ -240,9 +240,9 @@
 
 		ui_info = purple_core_get_ui_info();
 
-		if(NULL != ui_info) {
-			ui_name = g_hash_table_lookup(ui_info, "name");
-			ui_version = g_hash_table_lookup(ui_info, "version");
+		if(PURPLE_IS_UI_INFO(ui_info)) {
+			ui_name = purple_ui_info_get_name(ui_info);
+			ui_version = purple_ui_info_get_version(ui_info);
 		}
 
 		if(NULL != ui_name && NULL != ui_version) {
@@ -256,6 +256,10 @@
 		}
 
 		jabber_iq_send(iq);
+
+		if(PURPLE_IS_UI_INFO(ui_info)) {
+			g_object_unref(G_OBJECT(ui_info));
+		}
 	}
 }
 
--- a/libpurple/protocols/jabber/jabber.c	Fri Mar 13 22:11:34 2020 -0500
+++ b/libpurple/protocols/jabber/jabber.c	Fri Mar 20 08:57:57 2020 -0500
@@ -3815,7 +3815,7 @@
 static void
 jabber_do_init(void)
 {
-	GHashTable *ui_info = purple_core_get_ui_info();
+	PurpleUiInfo *ui_info = purple_core_get_ui_info();
 	const gchar *ui_type;
 	const gchar *type = "pc"; /* default client type, if unknown or
 								unspecified */
@@ -3853,7 +3853,7 @@
 
 	jabber_cmds = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, cmds_free_func);
 
-	ui_type = ui_info ? g_hash_table_lookup(ui_info, "client_type") : NULL;
+	ui_type = ui_info ? purple_ui_info_get_client_type(ui_info) : NULL;
 	if (ui_type) {
 		if (purple_strequal(ui_type, "pc") ||
 			purple_strequal(ui_type, "console") ||
@@ -3866,7 +3866,7 @@
 	}
 
 	if (ui_info)
-		ui_name = g_hash_table_lookup(ui_info, "name");
+		ui_name = purple_ui_info_get_name(ui_info);
 	if (ui_name == NULL)
 		ui_name = PACKAGE;
 
@@ -3930,6 +3930,8 @@
 	jabber_si_init();
 
 	jabber_auth_init();
+
+	g_object_unref(G_OBJECT(ui_info));
 }
 
 static void
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/purpleuiinfo.c	Fri Mar 20 08:57:57 2020 -0500
@@ -0,0 +1,281 @@
+/*
+ * purple
+ *
+ * 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 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#include "purpleuiinfo.h"
+
+struct _PurpleUiInfo {
+	GObject parent;
+
+	gchar *name;
+	gchar *version;
+	gchar *website;
+	gchar *support_website;
+	gchar *client_type;
+};
+
+enum {
+	PROP_0,
+	PROP_NAME,
+	PROP_VERSION,
+	PROP_WEBSITE,
+	PROP_SUPPORT_WEBSITE,
+	PROP_CLIENT_TYPE,
+	N_PROPERTIES
+};
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+
+/******************************************************************************
+ * Helpers
+ *****************************************************************************/
+static void
+purple_ui_info_set_name(PurpleUiInfo *info, const gchar *name) {
+	g_free(info->name);
+	info->name = g_strdup(name);
+}
+
+static void
+purple_ui_info_set_version(PurpleUiInfo *info, const gchar *version) {
+	g_free(info->version);
+	info->version = g_strdup(version);
+}
+
+static void
+purple_ui_info_set_website(PurpleUiInfo *info, const gchar *website) {
+	g_free(info->website);
+	info->website = g_strdup(website);
+}
+
+static void
+purple_ui_info_set_support_website(PurpleUiInfo *info,
+                                   const gchar *support_website)
+{
+	g_free(info->support_website);
+	info->support_website = g_strdup(support_website);
+}
+
+static void
+purple_ui_info_set_client_type(PurpleUiInfo *info, const gchar *client_type) {
+	g_free(info->client_type);
+	info->client_type = g_strdup(client_type);
+}
+
+/******************************************************************************
+ * GObject Implementation
+ *****************************************************************************/
+G_DEFINE_TYPE(PurpleUiInfo, purple_ui_info, G_TYPE_OBJECT);
+
+static void
+purple_ui_info_get_property(GObject *obj, guint param_id, GValue *value,
+                            GParamSpec *pspec)
+{
+	PurpleUiInfo *info = PURPLE_UI_INFO(obj);
+
+	switch(param_id) {
+		case PROP_NAME:
+			g_value_set_string(value, purple_ui_info_get_name(info));
+			break;
+		case PROP_VERSION:
+			g_value_set_string(value, purple_ui_info_get_version(info));
+			break;
+		case PROP_WEBSITE:
+			g_value_set_string(value, purple_ui_info_get_website(info));
+			break;
+		case PROP_SUPPORT_WEBSITE:
+			g_value_set_string(value, purple_ui_info_get_support_website(info));
+			break;
+		case PROP_CLIENT_TYPE:
+			g_value_set_string(value, purple_ui_info_get_client_type(info));
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+			break;
+	}
+}
+
+static void
+purple_ui_info_set_property(GObject *obj, guint param_id, const GValue *value,
+                            GParamSpec *pspec)
+{
+	PurpleUiInfo *info = PURPLE_UI_INFO(obj);
+
+	switch(param_id) {
+		case PROP_NAME:
+			purple_ui_info_set_name(info, g_value_get_string(value));
+			break;
+		case PROP_VERSION:
+			purple_ui_info_set_version(info, g_value_get_string(value));
+			break;
+		case PROP_WEBSITE:
+			purple_ui_info_set_website(info, g_value_get_string(value));
+			break;
+		case PROP_SUPPORT_WEBSITE:
+			purple_ui_info_set_support_website(info,
+			                                   g_value_get_string(value));
+			break;
+		case PROP_CLIENT_TYPE:
+			purple_ui_info_set_client_type(info, g_value_get_string(value));
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+			break;
+	}
+}
+
+static void
+purple_ui_info_init(PurpleUiInfo *info) {
+}
+
+static void
+purple_ui_info_finalize(GObject *obj) {
+	PurpleUiInfo *info = PURPLE_UI_INFO(obj);
+
+	g_clear_pointer(&info->name, g_free);
+	g_clear_pointer(&info->version, g_free);
+	g_clear_pointer(&info->website, g_free);
+	g_clear_pointer(&info->support_website, g_free);
+	g_clear_pointer(&info->client_type, g_free);
+
+	G_OBJECT_CLASS(purple_ui_info_parent_class)->finalize(obj);
+}
+
+static void
+purple_ui_info_class_init(PurpleUiInfoClass *klass) {
+	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+
+	obj_class->get_property = purple_ui_info_get_property;
+	obj_class->set_property = purple_ui_info_set_property;
+	obj_class->finalize = purple_ui_info_finalize;
+
+	/**
+	 * PurpleUiInfo::name:
+	 *
+	 * The name of the user interface.
+	 */
+	properties[PROP_NAME] =
+		g_param_spec_string("name", "name", "The name of the user interface",
+		                    NULL,
+		                    G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+		                    G_PARAM_STATIC_STRINGS);
+
+	/**
+	 * PurpleUiInfo::version:
+	 *
+	 * The name of the user interface.
+	 */
+	properties[PROP_VERSION] =
+		g_param_spec_string("version", "version",
+		                    "The version of the user interface",
+		                    NULL,
+		                    G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+		                    G_PARAM_STATIC_STRINGS);
+
+	/**
+	 * PurpleUiInfo::website:
+	 *
+	 * The website of the user interface.
+	 */
+	properties[PROP_WEBSITE] =
+		g_param_spec_string("website", "website",
+		                    "The website of the user interface",
+		                    NULL,
+		                    G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+		                    G_PARAM_STATIC_STRINGS);
+
+	/**
+	 * PurpleUiInfo::support-website:
+	 *
+	 * The support website of the user interface.
+	 */
+	properties[PROP_SUPPORT_WEBSITE] =
+		g_param_spec_string("support-website", "support-website",
+		                    "The support website of the user interface",
+		                    NULL,
+		                    G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+		                    G_PARAM_STATIC_STRINGS);
+
+	/**
+	 * PurpleUiInfo::client-type:
+	 *
+	 * The client type of the user interface.
+	 */
+	properties[PROP_CLIENT_TYPE] =
+		g_param_spec_string("client-type", "client-type",
+		                    "The client type of the user interface",
+		                    NULL,
+		                    G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+		                    G_PARAM_STATIC_STRINGS);
+
+	g_object_class_install_properties(obj_class, N_PROPERTIES, properties);
+}
+
+/******************************************************************************
+ * Public API
+ *****************************************************************************/
+PurpleUiInfo *
+purple_ui_info_new(const gchar *name, const gchar *version,
+                   const gchar *website, const gchar *support_website,
+                   const gchar *client_type)
+{
+	return g_object_new(PURPLE_TYPE_UI_INFO,
+	                    "name", name,
+	                    "version", version,
+	                    "website", website,
+	                    "support-website", support_website,
+	                    "client-type", client_type,
+	                    NULL);
+}
+
+const gchar *
+purple_ui_info_get_name(PurpleUiInfo *info) {
+	g_return_val_if_fail(PURPLE_IS_UI_INFO(info), NULL);
+
+	return info->name;
+}
+
+const gchar *
+purple_ui_info_get_version(PurpleUiInfo *info) {
+	g_return_val_if_fail(PURPLE_IS_UI_INFO(info), NULL);
+
+	return info->version;
+}
+
+const gchar *
+purple_ui_info_get_website(PurpleUiInfo *info) {
+	g_return_val_if_fail(PURPLE_IS_UI_INFO(info), NULL);
+
+	return info->website;
+}
+
+const gchar *
+purple_ui_info_get_support_website(PurpleUiInfo *info) {
+	g_return_val_if_fail(PURPLE_IS_UI_INFO(info), NULL);
+
+	return info->support_website;
+}
+
+const gchar *
+purple_ui_info_get_client_type(PurpleUiInfo *info) {
+	g_return_val_if_fail(PURPLE_IS_UI_INFO(info), NULL);
+
+	return info->client_type;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/purpleuiinfo.h	Fri Mar 20 08:57:57 2020 -0500
@@ -0,0 +1,126 @@
+/*
+ * purple
+ *
+ * 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 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#ifndef PURPLE_UI_INFO_H
+#define PURPLE_UI_INFO_H
+
+/**
+ * SECTION:purpleuiinfo
+ * @section_id: libpurple-ui-info
+ * @short_description: <filename>purpleuiinfo.h</filename>
+ * @title: A simple class that contains information about a user interface.
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define PURPLE_TYPE_UI_INFO (purple_ui_info_get_type())
+G_DECLARE_FINAL_TYPE(PurpleUiInfo, purple_ui_info, PURPLE, UI_INFO, GObject)
+
+/**
+ * purple_ui_info_new:
+ * @name: The name.
+ * @version: The version.
+ * @website: The website.
+ * @support_website: The support website.
+ * @client_type: The client type.
+ *
+ * Creates a new #PurpleUiInfo with the given values.  If you only want to set
+ * a few of these, you should use g_object_new() directly.
+ *
+ * Returns: (transfer full): The newly created #PurpleUiInfo instance.
+ *
+ * Since: 3.0.0
+ */
+PurpleUiInfo *purple_ui_info_new(const gchar *name,
+                                 const gchar *version,
+                                 const gchar *website,
+                                 const gchar *support_website,
+                                 const gchar *client_type);
+
+/**
+ * purple_ui_info_get_name:
+ * @info: The #PurpleUiInfo instance.
+ *
+ * Gets the name from @info.
+ *
+ * Returns: The name from @info.
+ *
+ * Since: 3.0.0
+ */
+const gchar *purple_ui_info_get_name(PurpleUiInfo *info);
+
+/**
+ * purple_ui_info_get_version:
+ * @info: The #PurpleUiInfo instance.
+ *
+ * Gets the version from @info.
+ *
+ * Returns: The version from @info.
+ *
+ * Since: 3.0.0
+ */
+const gchar *purple_ui_info_get_version(PurpleUiInfo *info);
+
+/**
+ * purple_ui_info_get_website:
+ * @info: The #PurpleUiInfo instance.
+ *
+ * Gets the website from @info.
+ *
+ * Returns: The website for @info.
+ *
+ * Since: 3.0.0
+ */
+const gchar *purple_ui_info_get_website(PurpleUiInfo *info);
+
+/**
+ * purple_ui_info_get_support_website:
+ * @info: The #PurpleUiInfo instance.
+ *
+ * Gets the support website from @info.
+ *
+ * Returns: The support website from @info.
+ *
+ * Since: 3.0.0
+ */
+const gchar *purple_ui_info_get_support_website(PurpleUiInfo *info);
+
+/**
+ * purple_ui_info_get_client_type:
+ * @info: The #PurpleUiInfo instance.
+ *
+ * Gets the client type from @info.  For example: 'bot', 'console', 'mobile',
+ * 'pc', 'web', etc.
+ *
+ * Returns: The client type of @info.
+ *
+ * Since: 3.0.0
+ */
+const gchar *purple_ui_info_get_client_type(PurpleUiInfo *info);
+
+G_END_DECLS
+
+#endif /* PURPLE_UI_INFO_H */
+
--- a/pidgin/libpidgin.c	Fri Mar 13 22:11:34 2020 -0500
+++ b/pidgin/libpidgin.c	Fri Mar 20 08:57:57 2020 -0500
@@ -248,7 +248,7 @@
 	pidgin_notify_init();
 }
 
-static GHashTable *ui_info = NULL;
+static PurpleUiInfo *ui_info = NULL;
 
 static void
 pidgin_quit(void)
@@ -269,46 +269,17 @@
 	purple_debug_set_ui(NULL);
 	g_object_unref(ui);
 
-	if(NULL != ui_info)
-		g_hash_table_destroy(ui_info);
+	g_clear_object(&ui_info);
 
 	/* and end it all... */
 	g_application_quit(g_application_get_default());
 }
 
-static GHashTable *pidgin_ui_get_info(void)
+static PurpleUiInfo *pidgin_ui_get_info(void)
 {
 	if(NULL == ui_info) {
-		ui_info = g_hash_table_new(g_str_hash, g_str_equal);
-
-		g_hash_table_insert(ui_info, "name", (char*)PIDGIN_NAME);
-		g_hash_table_insert(ui_info, "version", VERSION);
-		g_hash_table_insert(ui_info, "website", "https://pidgin.im");
-		g_hash_table_insert(ui_info, "dev_website", "https://developer.pidgin.im");
-		g_hash_table_insert(ui_info, "client_type", "pc");
-
-		/*
-		 * prpl-aim-clientkey is a DevID (or "client key") for Pidgin, given to
-		 * us by AOL in September 2016.  prpl-icq-clientkey is also a client key
-		 * for Pidgin, owned by the AIM account "markdoliner."  Please don't use 
-		 * either for other applications.  Instead, you can either not specify a 
-		 * client key, in which case the default "libpurple" key will be used,
-		 * or you can try to register your own at the AIM or ICQ web sites
-		 * (although this functionality was removed at some point, it's possible 
-		 * it has been re-added).
-		 */
-		g_hash_table_insert(ui_info, "prpl-aim-clientkey", "do1UCeb5gNqxB1S1");
-		g_hash_table_insert(ui_info, "prpl-icq-clientkey", "ma1cSASNCKFtrdv9");
-
-		/*
-		 * prpl-aim-distid is a distID for Pidgin, given to us by AOL in
-		 * September 2016.  prpl-icq-distid is also a distID for Pidgin, given
-		 * to us by AOL.  Please don't use either for other applications.
-		 * Instead, you can just not specify a distID and libpurple will use a
-		 * default.
-		 */
-		g_hash_table_insert(ui_info, "prpl-aim-distid", GINT_TO_POINTER(1715));
-		g_hash_table_insert(ui_info, "prpl-icq-distid", GINT_TO_POINTER(1550));
+		ui_info = purple_ui_info_new(PIDGIN_NAME, VERSION, "https://pidgin.im",
+		                             "https://developer.pidgin.im", "pc");
 	}
 
 	return ui_info;
@@ -321,10 +292,6 @@
 	pidgin_ui_init,
 	pidgin_quit,
 	pidgin_ui_get_info,
-	NULL,
-	NULL,
-	NULL,
-	NULL
 };
 
 static PurpleCoreUiOps *

mercurial