pidgin/pidgin

f2abd04191b7
Parents 19e53c9cab73
Children 8c352ec12439
Split PurplePluginInfo out to its own file

Testing Done:
Verified that plugins continued working.

Reviewed at https://reviews.imfreedom.org/r/684/
--- a/doc/reference/libpurple/libpurple-docs.xml Thu Jun 17 23:43:50 2021 -0500
+++ b/doc/reference/libpurple/libpurple-docs.xml Fri Jun 18 00:00:00 2021 -0500
@@ -82,6 +82,7 @@
<xi:include href="xml/purplemarkup.xml" />
<xi:include href="xml/purplenoopcredentialprovider.xml" />
<xi:include href="xml/purpleoptions.xml" />
+ <xi:include href="xml/purpleplugininfo.xml" />
<xi:include href="xml/purplepresence.xml" />
<xi:include href="xml/purpleprotocolattention.xml" />
<xi:include href="xml/purpleprotocolchat.xml" />
--- a/libpurple/meson.build Thu Jun 17 23:43:50 2021 -0500
+++ b/libpurple/meson.build Fri Jun 18 00:00:00 2021 -0500
@@ -59,6 +59,7 @@
'purplemessage.c',
'purplenoopcredentialprovider.c',
'purpleoptions.c',
+ 'purpleplugininfo.c',
'purplepresence.c',
'purpleprotocolattention.c',
'purpleprotocolchat.c',
@@ -153,6 +154,7 @@
'purplemessage.h',
'purplenoopcredentialprovider.h',
'purpleoptions.h',
+ 'purpleplugininfo.h',
'purplepresence.h',
'purpleprotocolattention.h',
'purpleprotocolchat.h',
@@ -236,6 +238,7 @@
'purpleconversation.h',
'purpleimconversation.h',
'purplemessage.h',
+ 'purpleplugininfo.h',
'roomlist.h',
'status.h',
'xfer.h',
--- a/libpurple/plugins.c Thu Jun 17 23:43:50 2021 -0500
+++ b/libpurple/plugins.c Fri Jun 18 00:00:00 2021 -0500
@@ -31,49 +31,6 @@
#include "signals.h"
#include "util.h"
-typedef struct _PurplePluginInfoPrivate PurplePluginInfoPrivate;
-
-/**************************************************************************
- * Plugin info private data
- **************************************************************************/
-struct _PurplePluginInfoPrivate {
- char *ui_requirement; /* ID of UI that is required to load the plugin */
- char *error; /* Why a plugin is not loadable */
-
- PurplePluginInfoFlags flags; /* Flags for the plugin */
-
- /* Callback that returns a list of actions the plugin can perform */
- PurplePluginActionsCb actions_cb;
-
- /* Callback that returns extra information about a plugin */
- PurplePluginExtraCb extra_cb;
-
- /* Callback that returns a preferences frame for a plugin */
- PurplePluginPrefFrameCb pref_frame_cb;
-
- /* Callback that returns a preferences request handle for a plugin */
- PurplePluginPrefRequestCb pref_request_cb;
-
- /* TRUE if a plugin has been unloaded at least once. Auto-load
- * plugins that have been unloaded once will not be auto-loaded again. */
- gboolean unloaded;
-};
-
-enum
-{
- PROP_0,
- PROP_UI_REQUIREMENT,
- PROP_ACTIONS_CB,
- PROP_EXTRA_CB,
- PROP_PREF_FRAME_CB,
- PROP_PREF_REQUEST_CB,
- PROP_FLAGS,
- PROP_LAST
-};
-
-G_DEFINE_TYPE_WITH_PRIVATE(PurplePluginInfo, purple_plugin_info,
- GPLUGIN_TYPE_PLUGIN_INFO);
-
/**************************************************************************
* Globals
**************************************************************************/
@@ -88,7 +45,7 @@
gpointer data)
{
PurplePluginInfo *info;
- PurplePluginInfoPrivate *priv;
+ const gchar *info_error = NULL;
g_return_val_if_fail(PURPLE_IS_PLUGIN(plugin), FALSE);
@@ -96,16 +53,15 @@
if (!info)
return TRUE; /* a GPlugin internal plugin */
- priv = purple_plugin_info_get_instance_private(info);
-
- if (priv->error) {
+ info_error = purple_plugin_info_get_error(info);
+ if(info_error != NULL) {
gchar *filename = gplugin_plugin_get_filename(plugin);
purple_debug_error("plugins", "Failed to load plugin %s: %s",
filename,
- priv->error);
+ info_error);
g_set_error(error, PURPLE_PLUGINS_DOMAIN, 0,
- "Plugin is not loadable: %s", priv->error);
+ "Plugin is not loadable: %s", info_error);
g_free(filename);
return FALSE;
@@ -158,7 +114,6 @@
plugin_unloaded_cb(GObject *manager, PurplePlugin *plugin)
{
PurplePluginInfo *info;
- PurplePluginInfoPrivate *priv;
g_return_if_fail(PURPLE_IS_PLUGIN(plugin));
@@ -166,8 +121,6 @@
if (!info)
return; /* a GPlugin internal plugin */
- priv = purple_plugin_info_get_instance_private(info);
-
/* cancel any pending dialogs the plugin has */
purple_request_close_with_handle(plugin);
purple_notify_close_with_handle(plugin);
@@ -175,7 +128,7 @@
purple_signals_disconnect_by_handle(plugin);
purple_signals_unregister_by_instance(plugin);
- priv->unloaded = TRUE;
+ purple_plugin_info_set_unloaded(info, TRUE);
loaded_plugins = g_list_remove(loaded_plugins, plugin);
plugins_to_disable = g_list_remove(plugins_to_disable, plugin);
@@ -299,277 +252,6 @@
}
/**************************************************************************
- * GObject code for PurplePluginInfo
- **************************************************************************/
-/* GObject initialization function */
-static void
-purple_plugin_info_init(PurplePluginInfo *info)
-{
-}
-
-/* Set method for GObject properties */
-static void
-purple_plugin_info_set_property(GObject *obj, guint param_id, const GValue *value,
- GParamSpec *pspec)
-{
- PurplePluginInfo *info = PURPLE_PLUGIN_INFO(obj);
- PurplePluginInfoPrivate *priv =
- purple_plugin_info_get_instance_private(info);
-
- switch (param_id) {
- case PROP_UI_REQUIREMENT:
- priv->ui_requirement = g_value_dup_string(value);
- break;
- case PROP_ACTIONS_CB:
- priv->actions_cb = g_value_get_pointer(value);
- break;
- case PROP_EXTRA_CB:
- priv->extra_cb = g_value_get_pointer(value);
- break;
- case PROP_PREF_FRAME_CB:
- priv->pref_frame_cb = g_value_get_pointer(value);
- break;
- case PROP_PREF_REQUEST_CB:
- priv->pref_request_cb = g_value_get_pointer(value);
- break;
- case PROP_FLAGS:
- priv->flags = g_value_get_flags(value);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
- break;
- }
-}
-
-/* Get method for GObject properties */
-static void
-purple_plugin_info_get_property(GObject *obj, guint param_id, GValue *value,
- GParamSpec *pspec)
-{
- PurplePluginInfo *info = PURPLE_PLUGIN_INFO(obj);
-
- switch (param_id) {
- case PROP_ACTIONS_CB:
- g_value_set_pointer(value,
- purple_plugin_info_get_actions_cb(info));
- break;
- case PROP_EXTRA_CB:
- g_value_set_pointer(value,
- purple_plugin_info_get_extra_cb(info));
- break;
- case PROP_PREF_FRAME_CB:
- g_value_set_pointer(value,
- purple_plugin_info_get_pref_frame_cb(info));
- break;
- case PROP_PREF_REQUEST_CB:
- g_value_set_pointer(value,
- purple_plugin_info_get_pref_request_cb(info));
- break;
- case PROP_FLAGS:
- g_value_set_flags(value, purple_plugin_info_get_flags(info));
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
- break;
- }
-}
-
-/* Called when done constructing */
-static void
-purple_plugin_info_constructed(GObject *object)
-{
- PurplePluginInfo *info = PURPLE_PLUGIN_INFO(object);
- GPluginPluginInfo *ginfo = GPLUGIN_PLUGIN_INFO(info);
- PurplePluginInfoPrivate *priv =
- purple_plugin_info_get_instance_private(info);
- const char *id = gplugin_plugin_info_get_id(ginfo);
- guint32 version;
-
- G_OBJECT_CLASS(purple_plugin_info_parent_class)->constructed(object);
-
- if (id == NULL || *id == '\0')
- priv->error = g_strdup(_("This plugin has not defined an ID."));
-
- if (priv->ui_requirement && !purple_strequal(priv->ui_requirement, purple_core_get_ui()))
- {
- priv->error = g_strdup_printf(_("You are using %s, but this plugin requires %s."),
- purple_core_get_ui(), priv->ui_requirement);
- purple_debug_error("plugins", "%s is not loadable: The UI requirement is not met. (%s)\n",
- id, priv->error);
- }
-
- version = gplugin_plugin_info_get_abi_version(ginfo);
- if (PURPLE_PLUGIN_ABI_MAJOR_VERSION(version) != PURPLE_MAJOR_VERSION ||
- PURPLE_PLUGIN_ABI_MINOR_VERSION(version) > PURPLE_MINOR_VERSION)
- {
- priv->error = g_strdup_printf(_("Your libpurple version is %d.%d.x (need %d.%d.x)"),
- PURPLE_MAJOR_VERSION, PURPLE_MINOR_VERSION,
- PURPLE_PLUGIN_ABI_MAJOR_VERSION(version),
- PURPLE_PLUGIN_ABI_MINOR_VERSION(version));
- purple_debug_error("plugins", "%s is not loadable: libpurple version is %d.%d.x (need %d.%d.x)\n",
- id, PURPLE_MAJOR_VERSION, PURPLE_MINOR_VERSION,
- PURPLE_PLUGIN_ABI_MAJOR_VERSION(version),
- PURPLE_PLUGIN_ABI_MINOR_VERSION(version));
- }
-}
-
-/* GObject finalize function */
-static void
-purple_plugin_info_finalize(GObject *object)
-{
- PurplePluginInfoPrivate *priv =
- purple_plugin_info_get_instance_private(
- PURPLE_PLUGIN_INFO(object));
-
- g_free(priv->ui_requirement);
- g_free(priv->error);
-
- G_OBJECT_CLASS(purple_plugin_info_parent_class)->finalize(object);
-}
-
-/* Class initializer function */
-static void purple_plugin_info_class_init(PurplePluginInfoClass *klass)
-{
- GObjectClass *obj_class = G_OBJECT_CLASS(klass);
-
- obj_class->constructed = purple_plugin_info_constructed;
- obj_class->finalize = purple_plugin_info_finalize;
-
- /* Setup properties */
- obj_class->get_property = purple_plugin_info_get_property;
- obj_class->set_property = purple_plugin_info_set_property;
-
- g_object_class_install_property(obj_class, PROP_UI_REQUIREMENT,
- g_param_spec_string("ui-requirement",
- "UI Requirement",
- "ID of UI that is required by this plugin", NULL,
- G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_property(obj_class, PROP_ACTIONS_CB,
- g_param_spec_pointer("actions-cb",
- "Plugin actions",
- "Callback that returns list of plugin's actions",
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_property(obj_class, PROP_EXTRA_CB,
- g_param_spec_pointer("extra-cb",
- "Extra info callback",
- "Callback that returns extra info about the plugin",
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_property(obj_class, PROP_PREF_FRAME_CB,
- g_param_spec_pointer("pref-frame-cb",
- "Preferences frame callback",
- "The callback that returns the preferences frame",
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_property(obj_class, PROP_PREF_REQUEST_CB,
- g_param_spec_pointer("pref-request-cb",
- "Preferences request callback",
- "Callback that returns preferences request handle",
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_property(obj_class, PROP_FLAGS,
- g_param_spec_flags("flags",
- "Plugin flags",
- "The flags for the plugin",
- PURPLE_TYPE_PLUGIN_INFO_FLAGS, 0,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_STRINGS));
-}
-
-/**************************************************************************
- * PluginInfo API
- **************************************************************************/
-GPluginPluginInfo *
-purple_plugin_info_new(const char *first_property, ...)
-{
- GObject *info;
- va_list var_args;
-
- /* at least ID is required */
- if (!first_property)
- return NULL;
-
- va_start(var_args, first_property);
- info = g_object_new_valist(PURPLE_TYPE_PLUGIN_INFO, first_property,
- var_args);
- va_end(var_args);
-
- return GPLUGIN_PLUGIN_INFO(info);
-}
-
-PurplePluginActionsCb
-purple_plugin_info_get_actions_cb(PurplePluginInfo *info)
-{
- PurplePluginInfoPrivate *priv = NULL;
-
- g_return_val_if_fail(PURPLE_IS_PLUGIN_INFO(info), NULL);
-
- priv = purple_plugin_info_get_instance_private(info);
- return priv->actions_cb;
-}
-
-PurplePluginExtraCb
-purple_plugin_info_get_extra_cb(PurplePluginInfo *info)
-{
- PurplePluginInfoPrivate *priv = NULL;
-
- g_return_val_if_fail(PURPLE_IS_PLUGIN_INFO(info), NULL);
-
- priv = purple_plugin_info_get_instance_private(info);
- return priv->extra_cb;
-}
-
-PurplePluginPrefFrameCb
-purple_plugin_info_get_pref_frame_cb(PurplePluginInfo *info)
-{
- PurplePluginInfoPrivate *priv = NULL;
-
- g_return_val_if_fail(PURPLE_IS_PLUGIN_INFO(info), NULL);
-
- priv = purple_plugin_info_get_instance_private(info);
- return priv->pref_frame_cb;
-}
-
-PurplePluginPrefRequestCb
-purple_plugin_info_get_pref_request_cb(PurplePluginInfo *info)
-{
- PurplePluginInfoPrivate *priv = NULL;
-
- g_return_val_if_fail(PURPLE_IS_PLUGIN_INFO(info), NULL);
-
- priv = purple_plugin_info_get_instance_private(info);
- return priv->pref_request_cb;
-}
-
-PurplePluginInfoFlags
-purple_plugin_info_get_flags(PurplePluginInfo *info)
-{
- PurplePluginInfoPrivate *priv = NULL;
-
- g_return_val_if_fail(PURPLE_IS_PLUGIN_INFO(info), 0);
-
- priv = purple_plugin_info_get_instance_private(info);
- return priv->flags;
-}
-
-const gchar *
-purple_plugin_info_get_error(PurplePluginInfo *info)
-{
- PurplePluginInfoPrivate *priv = NULL;
-
- g_return_val_if_fail(PURPLE_IS_PLUGIN_INFO(info), NULL);
-
- priv = purple_plugin_info_get_instance_private(info);
- return priv->error;
-}
-
-/**************************************************************************
* PluginAction API
**************************************************************************/
PurplePluginAction *
@@ -657,16 +339,17 @@
for (l = plugins; l != NULL; l = l->next) {
PurplePlugin *plugin = PURPLE_PLUGIN(l->data);
PurplePluginInfo *info;
- PurplePluginInfoPrivate *priv;
+ PurplePluginInfoFlags flags;
+ gboolean unloaded;
if (purple_plugin_is_loaded(plugin))
continue;
info = purple_plugin_get_info(plugin);
- priv = purple_plugin_info_get_instance_private(info);
- if (!priv->unloaded && purple_plugin_info_get_flags(info) &
- PURPLE_PLUGIN_INFO_FLAGS_AUTO_LOAD) {
+ unloaded = purple_plugin_info_get_unloaded(info);
+ flags = purple_plugin_info_get_flags(info);
+ if (!unloaded && flags & PURPLE_PLUGIN_INFO_FLAGS_AUTO_LOAD) {
gchar *filename = gplugin_plugin_get_filename(plugin);
purple_debug_info("plugins", "Auto-loading plugin %s\n",
filename);
--- a/libpurple/plugins.h Thu Jun 17 23:43:50 2021 -0500
+++ b/libpurple/plugins.h Fri Jun 18 00:00:00 2021 -0500
@@ -57,13 +57,7 @@
typedef GPluginPluginInterface PurplePluginInterface;
-/**
- * PURPLE_TYPE_PLUGIN_INFO:
- *
- * The standard _get_type macro for #PurplePluginInfo.
- */
-#define PURPLE_TYPE_PLUGIN_INFO (purple_plugin_info_get_type())
-typedef struct _PurplePluginInfo PurplePluginInfo;
+#include "purpleplugininfo.h"
/**
* PURPLE_TYPE_PLUGIN_ACTION:
@@ -73,8 +67,6 @@
#define PURPLE_TYPE_PLUGIN_ACTION (purple_plugin_action_get_type())
typedef struct _PurplePluginAction PurplePluginAction;
-#include "pluginpref.h"
-
/**
* PurplePluginActionCb:
* @action: the action information.
@@ -84,69 +76,6 @@
typedef void (*PurplePluginActionCb)(PurplePluginAction *action);
/**
- * PurplePluginActionsCb:
- * @plugin: the plugin associated with this callback.
- *
- * Returns a list of actions the plugin can perform.
- *
- * Returns: (transfer none): A list of actions the plugin can perform.
- */
-typedef GList *(*PurplePluginActionsCb)(PurplePlugin *plugin);
-
-/**
- * PurplePluginExtraCb:
- * @plugin: the plugin associated with this callback.
- *
- * Gives extra information about the plguin.
- *
- * Returns: a newly allocated string denoting extra information
- * about a plugin.
- */
-typedef gchar *(*PurplePluginExtraCb)(PurplePlugin *plugin);
-
-/**
- * PurplePluginPrefFrameCb:
- * @plugin: the plugin associated with this callback.
- *
- * Returns the preferences frame for the plugin.
- *
- * Returns: Preference frame.
- */
-typedef PurplePluginPrefFrame *(*PurplePluginPrefFrameCb)(PurplePlugin *plugin);
-
-/**
- * PurplePrefRequestCb:
- *
- * Returns the preferences request handle for a plugin.
- *
- * Returns: Preferences request handle.
- */
-typedef gpointer (*PurplePluginPrefRequestCb)(PurplePlugin *plugin);
-
-/**
- * PurplePluginInfoFlags:
- * @PURPLE_PLUGIN_INFO_FLAGS_INTERNAL: Plugin is not shown in UI lists
- * @PURPLE_PLUGIN_INFO_FLAGS_AUTO_LOAD: Auto-load the plugin
- *
- * Flags that can be used to treat plugins differently.
- */
-typedef enum /*< flags >*/
-{
- PURPLE_PLUGIN_INFO_FLAGS_INTERNAL = 1 << 1,
- PURPLE_PLUGIN_INFO_FLAGS_AUTO_LOAD = 1 << 2,
-
-} PurplePluginInfoFlags;
-
-/**
- * PurplePluginInfo:
- *
- * Holds information about a plugin.
- */
-struct _PurplePluginInfo {
- GPluginPluginInfo parent;
-};
-
-/**
* PurplePluginAction:
* @label: The label to display in the user interface.
* @callback: The function to call when the user wants to perform this action.
@@ -163,41 +92,6 @@
gpointer user_data;
};
-/**
- * PURPLE_PLUGIN_ABI_VERSION:
- *
- * Note: The lower six nibbles represent the ABI version for libpurple, the
- * rest are required by GPlugin.
- *
- * Returns: An ABI version to set in plugins using major and minor versions.
- */
-#define PURPLE_PLUGIN_ABI_VERSION(major,minor) \
- (0x01000000 | ((major) << 16) | (minor))
-
-/**
- * PURPLE_PLUGIN_ABI_MAJOR_VERSION:
- *
- * Returns: The major version from an ABI version
- */
-#define PURPLE_PLUGIN_ABI_MAJOR_VERSION(abi) \
- ((abi >> 16) & 0xff)
-
-/**
- * PURPLE_PLUGIN_ABI_MINOR_VERSION:
- *
- * Returns: The minor version from an ABI version
- */
-#define PURPLE_PLUGIN_ABI_MINOR_VERSION(abi) \
- (abi & 0xffff)
-
-/**
- * PURPLE_ABI_VERSION:
- *
- * A convenience‎ macro that returns an ABI version using PURPLE_MAJOR_VERSION
- * and PURPLE_MINOR_VERSION
- */
-#define PURPLE_ABI_VERSION PURPLE_PLUGIN_ABI_VERSION(PURPLE_MAJOR_VERSION, PURPLE_MINOR_VERSION)
-
G_BEGIN_DECLS
/**************************************************************************/
@@ -293,182 +187,6 @@
GSList *purple_plugin_get_dependent_plugins(PurplePlugin *plugin);
/**************************************************************************/
-/* PluginInfo API */
-/**************************************************************************/
-
-/**
- * purple_plugin_info_get_type:
- *
- * Returns: The #GType for the #PurplePluginInfo object.
- */
-G_DECLARE_FINAL_TYPE(PurplePluginInfo, purple_plugin_info, PURPLE, PLUGIN_INFO,
- GPluginPluginInfo)
-
-/**
- * purple_plugin_info_new:
- * @first_property: The first property name
- * @...: The value of the first property, followed optionally by more
- * name/value pairs, followed by %NULL
- *
- * Creates a new #PurplePluginInfo instance to be returned from
- * #plugin_query of a plugin, using the provided name/value pairs.
- *
- * All properties except <literal>"id"</literal> and
- * <literal>"purple-abi"</literal> are optional.
- *
- * Valid property names are:
- * <informaltable frame='none'>
- * <tgroup cols='2'><tbody>
- * <row><entry><literal>"id"</literal></entry>
- * <entry>(string) The ID of the plugin.</entry>
- * </row>
- * <row><entry><literal>"abi-version"</literal></entry>
- * <entry>(<type>guint32</type>) The ABI version required by the
- * plugin.</entry>
- * </row>
- * <row><entry><literal>"name"</literal></entry>
- * <entry>(string) The translated name of the plugin.</entry>
- * </row>
- * <row><entry><literal>"version"</literal></entry>
- * <entry>(string) Version of the plugin.</entry>
- * </row>
- * <row><entry><literal>"category"</literal></entry>
- * <entry>(string) Primary category of the plugin.</entry>
- * </row>
- * <row><entry><literal>"summary"</literal></entry>
- * <entry>(string) Brief summary of the plugin.</entry>
- * </row>
- * <row><entry><literal>"description"</literal></entry>
- * <entry>(string) Full description of the plugin.</entry>
- * </row>
- * <row><entry><literal>"authors"</literal></entry>
- * <entry>(<type>const gchar * const *</type>) A %NULL-terminated list of
- * plugin authors. format: First Last &lt;user\@domain.com&gt;</entry>
- * </row>
- * <row><entry><literal>"website"</literal></entry>
- * <entry>(string) Website of the plugin.</entry>
- * </row>
- * <row><entry><literal>"icon"</literal></entry>
- * <entry>(string) Path to a plugin's icon.</entry>
- * </row>
- * <row><entry><literal>"license-id"</literal></entry>
- * <entry>(string) Short name of the plugin's license. This should
- * either be an identifier of the license from
- * <ulink url="http://dep.debian.net/deps/dep5/#license-specification">
- * DEP5</ulink> or "Other" for custom licenses.</entry>
- * </row>
- * <row><entry><literal>"license-text"</literal></entry>
- * <entry>(string) The text of the plugin's license, if unlisted on
- * DEP5.</entry>
- * </row>
- * <row><entry><literal>"license-url"</literal></entry>
- * <entry>(string) The plugin's license URL, if unlisted on DEP5.</entry>
- * </row>
- * <row><entry><literal>"dependencies"</literal></entry>
- * <entry>(<type>const gchar * const *</type>) A %NULL-terminated list of
- * plugin IDs required by the plugin.</entry>
- * </row>
- * <row><entry><literal>"actions-cb"</literal></entry>
- * <entry>(#PurplePluginActionsCb) Callback that returns a list of
- * actions the plugin can perform.</entry>
- * </row>
- * <row><entry><literal>"extra-cb"</literal></entry>
- * <entry>(#PurplePluginExtraCb) Callback that returns a newly
- * allocated string denoting extra information about a plugin.</entry>
- * </row>
- * <row><entry><literal>"pref-frame-cb"</literal></entry>
- * <entry>(#PurplePluginPrefFrameCb) Callback that returns a
- * preferences frame for the plugin.</entry>
- * </row>
- * <row><entry><literal>"pref-request-cb"</literal></entry>
- * <entry>(#PurplePluginPrefRequestCb) Callback that returns a
- * preferences request handle for the plugin.</entry>
- * </row>
- * <row><entry><literal>"flags"</literal></entry>
- * <entry>(#PurplePluginInfoFlags) The flags for a plugin.</entry>
- * </row>
- * </tbody></tgroup>
- * </informaltable>
- *
- * See #PURPLE_PLUGIN_ABI_VERSION,
- * <link linkend="chapter-plugin-ids">Plugin IDs</link>.
- *
- * Returns: A new #PurplePluginInfo instance.
- */
-GPluginPluginInfo *purple_plugin_info_new(const char *first_property, ...) G_GNUC_NULL_TERMINATED;
-
-/**
- * purple_plugin_info_get_actions_cb:
- * @info: The plugin info to get the callback from.
- *
- * Returns the callback that retrieves the list of actions a plugin can perform
- * at that moment.
- *
- * Returns: The callback that returns a list of #PurplePluginAction
- * instances corresponding to the actions a plugin can perform.
- */
-PurplePluginActionsCb
-purple_plugin_info_get_actions_cb(PurplePluginInfo *info);
-
-/**
- * purple_plugin_info_get_extra_cb:
- * @info: The plugin info to get extra information from.
- *
- * Returns a callback that gives extra information about a plugin. You must
- * free the string returned by this callback.
- *
- * Returns: (transfer none): The callback that returns extra information about a plugin.
- */
-PurplePluginExtraCb
-purple_plugin_info_get_extra_cb(PurplePluginInfo *info);
-
-/**
- * purple_plugin_info_get_pref_frame_cb:
- * @info: The plugin info to get the callback from.
- *
- * Returns the callback that retrieves the preferences frame for a plugin, set
- * via the "pref-frame-cb" property of the plugin info.
- *
- * Returns: The callback that returns the preferences frame.
- */
-PurplePluginPrefFrameCb
-purple_plugin_info_get_pref_frame_cb(PurplePluginInfo *info);
-
-/**
- * purple_plugin_info_get_pref_request_cb:
- * @info: The plugin info to get the callback from.
- *
- * Returns the callback that retrieves the preferences request handle for a
- * plugin, set via the "pref-request-cb" property of the plugin info.
- *
- * Returns: (transfer none): The callback that returns the preferences request handle.
- */
-PurplePluginPrefRequestCb
-purple_plugin_info_get_pref_request_cb(PurplePluginInfo *info);
-
-/**
- * purple_plugin_info_get_flags:
- * @info: The plugin's info instance.
- *
- * Returns the plugin's flags.
- *
- * Returns: The flags of the plugin.
- */
-PurplePluginInfoFlags
-purple_plugin_info_get_flags(PurplePluginInfo *info);
-
-/**
- * purple_plugin_info_get_error:
- * @info: The plugin info.
- *
- * Returns an error in the plugin info that would prevent the plugin from being
- * loaded.
- *
- * Returns: The plugin info error, or %NULL.
- */
-const gchar *purple_plugin_info_get_error(PurplePluginInfo *info);
-
-/**************************************************************************/
/* PluginAction API */
/**************************************************************************/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/purpleplugininfo.c Fri Jun 18 00:00:00 2021 -0500
@@ -0,0 +1,353 @@
+/*
+ * 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/gi18n-lib.h>
+
+#include "internal.h"
+
+#include "core.h"
+#include "debug.h"
+#include "enums.h"
+#include "util.h"
+
+#include "purpleplugininfo.h"
+
+typedef struct {
+ gchar *ui_requirement; /* ID of UI that is required to load the plugin */
+ gchar *error; /* Why a plugin is not loadable */
+
+ PurplePluginInfoFlags flags; /* Flags for the plugin */
+
+ /* Callback that returns a list of actions the plugin can perform */
+ PurplePluginActionsCb actions_cb;
+
+ /* Callback that returns extra information about a plugin */
+ PurplePluginExtraCb extra_cb;
+
+ /* Callback that returns a preferences frame for a plugin */
+ PurplePluginPrefFrameCb pref_frame_cb;
+
+ /* Callback that returns a preferences request handle for a plugin */
+ PurplePluginPrefRequestCb pref_request_cb;
+
+ /* TRUE if a plugin has been unloaded at least once. Auto-load
+ * plugins that have been unloaded once will not be auto-loaded again. */
+ gboolean unloaded;
+} PurplePluginInfoPrivate;
+
+enum {
+ PROP_0,
+ PROP_UI_REQUIREMENT,
+ PROP_ACTIONS_CB,
+ PROP_EXTRA_CB,
+ PROP_PREF_FRAME_CB,
+ PROP_PREF_REQUEST_CB,
+ PROP_FLAGS,
+ N_PROPERTIES,
+};
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+
+G_DEFINE_TYPE_WITH_PRIVATE(PurplePluginInfo, purple_plugin_info,
+ GPLUGIN_TYPE_PLUGIN_INFO);
+
+/**************************************************************************
+ * GObject Implementation
+ **************************************************************************/
+static void
+purple_plugin_info_init(PurplePluginInfo *info) {
+}
+
+static void
+purple_plugin_info_set_property(GObject *obj, guint param_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ PurplePluginInfo *info = PURPLE_PLUGIN_INFO(obj);
+ PurplePluginInfoPrivate *priv = NULL;
+
+ priv = purple_plugin_info_get_instance_private(info);
+
+ switch (param_id) {
+ case PROP_UI_REQUIREMENT:
+ priv->ui_requirement = g_value_dup_string(value);
+ break;
+ case PROP_ACTIONS_CB:
+ priv->actions_cb = g_value_get_pointer(value);
+ break;
+ case PROP_EXTRA_CB:
+ priv->extra_cb = g_value_get_pointer(value);
+ break;
+ case PROP_PREF_FRAME_CB:
+ priv->pref_frame_cb = g_value_get_pointer(value);
+ break;
+ case PROP_PREF_REQUEST_CB:
+ priv->pref_request_cb = g_value_get_pointer(value);
+ break;
+ case PROP_FLAGS:
+ priv->flags = g_value_get_flags(value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+ break;
+ }
+}
+
+static void
+purple_plugin_info_get_property(GObject *obj, guint param_id, GValue *value,
+ GParamSpec *pspec)
+{
+ PurplePluginInfo *info = PURPLE_PLUGIN_INFO(obj);
+
+ switch (param_id) {
+ case PROP_ACTIONS_CB:
+ g_value_set_pointer(value,
+ purple_plugin_info_get_actions_cb(info));
+ break;
+ case PROP_EXTRA_CB:
+ g_value_set_pointer(value,
+ purple_plugin_info_get_extra_cb(info));
+ break;
+ case PROP_PREF_FRAME_CB:
+ g_value_set_pointer(value,
+ purple_plugin_info_get_pref_frame_cb(info));
+ break;
+ case PROP_PREF_REQUEST_CB:
+ g_value_set_pointer(value,
+ purple_plugin_info_get_pref_request_cb(info));
+ break;
+ case PROP_FLAGS:
+ g_value_set_flags(value, purple_plugin_info_get_flags(info));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+ break;
+ }
+}
+
+static void
+purple_plugin_info_constructed(GObject *object) {
+ PurplePluginInfo *info = PURPLE_PLUGIN_INFO(object);
+ GPluginPluginInfo *ginfo = GPLUGIN_PLUGIN_INFO(info);
+ PurplePluginInfoPrivate *priv = NULL;
+ const gchar *id = gplugin_plugin_info_get_id(ginfo);
+ guint32 version;
+
+ priv = purple_plugin_info_get_instance_private(info);
+
+ G_OBJECT_CLASS(purple_plugin_info_parent_class)->constructed(object);
+
+ if(id == NULL || *id == '\0') {
+ priv->error = g_strdup(_("This plugin has not defined an ID."));
+ }
+
+ if(priv->ui_requirement != NULL) {
+ if(!purple_strequal(priv->ui_requirement, purple_core_get_ui())) {
+ priv->error = g_strdup_printf(_("You are using %s, but this plugin "
+ "requires %s."),
+ purple_core_get_ui(),
+ priv->ui_requirement);
+ purple_debug_error("plugins",
+ "%s is not loadable: The UI requirement is not "
+ "met. (%s)\n",
+ id, priv->error);
+ }
+ }
+
+ version = gplugin_plugin_info_get_abi_version(ginfo);
+ if (PURPLE_PLUGIN_ABI_MAJOR_VERSION(version) != PURPLE_MAJOR_VERSION ||
+ PURPLE_PLUGIN_ABI_MINOR_VERSION(version) > PURPLE_MINOR_VERSION)
+ {
+ priv->error = g_strdup_printf(_("Your libpurple version is %d.%d.x "
+ "(need %d.%d.x)"),
+ PURPLE_MAJOR_VERSION,
+ PURPLE_MINOR_VERSION,
+ PURPLE_PLUGIN_ABI_MAJOR_VERSION(version),
+ PURPLE_PLUGIN_ABI_MINOR_VERSION(version));
+ purple_debug_error("plugins",
+ "%s is not loadable: libpurple version is %d.%d.x "
+ "(need %d.%d.x)\n",
+ id, PURPLE_MAJOR_VERSION, PURPLE_MINOR_VERSION,
+ PURPLE_PLUGIN_ABI_MAJOR_VERSION(version),
+ PURPLE_PLUGIN_ABI_MINOR_VERSION(version));
+ }
+}
+
+static void
+purple_plugin_info_finalize(GObject *object) {
+ PurplePluginInfoPrivate *priv = NULL;
+
+ priv = purple_plugin_info_get_instance_private(PURPLE_PLUGIN_INFO(object));
+
+ g_free(priv->ui_requirement);
+ g_free(priv->error);
+
+ G_OBJECT_CLASS(purple_plugin_info_parent_class)->finalize(object);
+}
+
+static void
+purple_plugin_info_class_init(PurplePluginInfoClass *klass) {
+ GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+
+ obj_class->constructed = purple_plugin_info_constructed;
+ obj_class->finalize = purple_plugin_info_finalize;
+
+ obj_class->get_property = purple_plugin_info_get_property;
+ obj_class->set_property = purple_plugin_info_set_property;
+
+ properties[PROP_UI_REQUIREMENT] = g_param_spec_string(
+ "ui-requirement", "UI Requirement",
+ "ID of UI that is required by this plugin",
+ NULL,
+ G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_ACTIONS_CB] = g_param_spec_pointer(
+ "actions-cb", "Plugin actions",
+ "Callback that returns list of plugin's actions",
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_EXTRA_CB] = g_param_spec_pointer(
+ "extra-cb", "Extra info callback",
+ "Callback that returns extra info about the plugin",
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_PREF_FRAME_CB] = g_param_spec_pointer(
+ "pref-frame-cb", "Preferences frame callback",
+ "The callback that returns the preferences frame",
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_PREF_REQUEST_CB] = g_param_spec_pointer(
+ "pref-request-cb", "Preferences request callback",
+ "Callback that returns preferences request handle",
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_FLAGS] = g_param_spec_flags(
+ "flags", "Plugin flags",
+ "The flags for the plugin",
+ PURPLE_TYPE_PLUGIN_INFO_FLAGS,
+ 0,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties(obj_class, N_PROPERTIES, properties);
+}
+
+/**************************************************************************
+ * Public API
+ **************************************************************************/
+GPluginPluginInfo *
+purple_plugin_info_new(const char *first_property, ...) {
+ GObject *info;
+ va_list var_args;
+
+ /* at least ID is required */
+ if (!first_property) {
+ return NULL;
+ }
+
+ va_start(var_args, first_property);
+ info = g_object_new_valist(PURPLE_TYPE_PLUGIN_INFO, first_property,
+ var_args);
+ va_end(var_args);
+
+ return GPLUGIN_PLUGIN_INFO(info);
+}
+
+PurplePluginActionsCb
+purple_plugin_info_get_actions_cb(PurplePluginInfo *info) {
+ PurplePluginInfoPrivate *priv = NULL;
+
+ g_return_val_if_fail(PURPLE_IS_PLUGIN_INFO(info), NULL);
+
+ priv = purple_plugin_info_get_instance_private(info);
+
+ return priv->actions_cb;
+}
+
+PurplePluginExtraCb
+purple_plugin_info_get_extra_cb(PurplePluginInfo *info) {
+ PurplePluginInfoPrivate *priv = NULL;
+
+ g_return_val_if_fail(PURPLE_IS_PLUGIN_INFO(info), NULL);
+
+ priv = purple_plugin_info_get_instance_private(info);
+
+ return priv->extra_cb;
+}
+
+PurplePluginPrefFrameCb
+purple_plugin_info_get_pref_frame_cb(PurplePluginInfo *info) {
+ PurplePluginInfoPrivate *priv = NULL;
+
+ g_return_val_if_fail(PURPLE_IS_PLUGIN_INFO(info), NULL);
+
+ priv = purple_plugin_info_get_instance_private(info);
+
+ return priv->pref_frame_cb;
+}
+
+PurplePluginPrefRequestCb
+purple_plugin_info_get_pref_request_cb(PurplePluginInfo *info) {
+ PurplePluginInfoPrivate *priv = NULL;
+
+ g_return_val_if_fail(PURPLE_IS_PLUGIN_INFO(info), NULL);
+
+ priv = purple_plugin_info_get_instance_private(info);
+
+ return priv->pref_request_cb;
+}
+
+PurplePluginInfoFlags
+purple_plugin_info_get_flags(PurplePluginInfo *info) {
+ PurplePluginInfoPrivate *priv = NULL;
+
+ g_return_val_if_fail(PURPLE_IS_PLUGIN_INFO(info), 0);
+
+ priv = purple_plugin_info_get_instance_private(info);
+
+ return priv->flags;
+}
+
+const gchar *
+purple_plugin_info_get_error(PurplePluginInfo *info) {
+ PurplePluginInfoPrivate *priv = NULL;
+
+ g_return_val_if_fail(PURPLE_IS_PLUGIN_INFO(info), NULL);
+
+ priv = purple_plugin_info_get_instance_private(info);
+
+ return priv->error;
+}
+
+gboolean
+purple_plugin_info_get_unloaded(PurplePluginInfo *info) {
+ PurplePluginInfoPrivate *priv = NULL;
+
+ g_return_val_if_fail(PURPLE_IS_PLUGIN_INFO(info), FALSE);
+
+ priv = purple_plugin_info_get_instance_private(info);
+
+ return priv->unloaded;
+}
+
+void
+purple_plugin_info_set_unloaded(PurplePluginInfo *info, gboolean unloaded) {
+ PurplePluginInfoPrivate *priv = NULL;
+
+ g_return_if_fail(PURPLE_IS_PLUGIN_INFO(info));
+
+ priv = purple_plugin_info_get_instance_private(info);
+
+ priv->unloaded = unloaded;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/purpleplugininfo.h Fri Jun 18 00:00:00 2021 -0500
@@ -0,0 +1,364 @@
+/*
+ * 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/>.
+ */
+
+#if !defined(PURPLE_GLOBAL_HEADER_INSIDE) && !defined(PURPLE_COMPILATION)
+# error "only <purple.h> may be included directly"
+#endif
+
+#ifndef PURPLE_PLUGIN_INFO_H
+#define PURPLE_PLUGIN_INFO_H
+
+/**
+ * SECTION:purpleplugininfo
+ * @section_id: libpurple-purpleplugininfo
+ * @title: PurplePluginInfo Object
+ * @see_also: <link linkend="chapter-signals-plugin">Plugin signals</link>,
+ * <link linkend="chapter-plugin-ids">Plugin IDs</link>,
+ * <link linkend="chapter-plugin-i18n">Third Party Plugin Translation</link>
+ */
+
+#include <glib.h>
+
+#include <gplugin.h>
+#include <gplugin-native.h>
+
+#include "pluginpref.h"
+
+/**
+ * PURPLE_TYPE_PLUGIN_INFO:
+ *
+ * The standard _get_type macro for #PurplePluginInfo.
+ */
+#define PURPLE_TYPE_PLUGIN_INFO (purple_plugin_info_get_type())
+
+/**
+ * purple_plugin_info_get_type:
+ *
+ * Returns: The #GType for the #PurplePluginInfo object.
+ */
+G_DECLARE_DERIVABLE_TYPE(PurplePluginInfo, purple_plugin_info, PURPLE, PLUGIN_INFO,
+ GPluginPluginInfo)
+
+#include "plugins.h"
+
+struct _PurplePluginInfoClass {
+ /*< private >*/
+ GPluginPluginInfoClass parent;
+
+ gpointer reserved[4];
+};
+
+/**
+ * PurplePluginActionsCb:
+ * @plugin: the plugin associated with this callback.
+ *
+ * Returns a list of actions the plugin can perform.
+ *
+ * Returns: (transfer none): A list of actions the plugin can perform.
+ */
+typedef GList *(*PurplePluginActionsCb)(PurplePlugin *plugin);
+
+/**
+ * PurplePluginExtraCb:
+ * @plugin: the plugin associated with this callback.
+ *
+ * Gives extra information about the plguin.
+ *
+ * Returns: a newly allocated string denoting extra information
+ * about a plugin.
+ */
+typedef gchar *(*PurplePluginExtraCb)(PurplePlugin *plugin);
+
+/**
+ * PurplePluginPrefFrameCb:
+ * @plugin: the plugin associated with this callback.
+ *
+ * Returns the preferences frame for the plugin.
+ *
+ * Returns: Preference frame.
+ */
+typedef PurplePluginPrefFrame *(*PurplePluginPrefFrameCb)(PurplePlugin *plugin);
+
+/**
+ * PurplePrefRequestCb:
+ *
+ * Returns the preferences request handle for a plugin.
+ *
+ * Returns: Preferences request handle.
+ */
+typedef gpointer (*PurplePluginPrefRequestCb)(PurplePlugin *plugin);
+
+/**
+ * PurplePluginInfoFlags:
+ * @PURPLE_PLUGIN_INFO_FLAGS_INTERNAL: Plugin is not shown in UI lists
+ * @PURPLE_PLUGIN_INFO_FLAGS_AUTO_LOAD: Auto-load the plugin
+ *
+ * Flags that can be used to treat plugins differently.
+ */
+typedef enum /*< flags >*/
+{
+ PURPLE_PLUGIN_INFO_FLAGS_INTERNAL = 1 << 1,
+ PURPLE_PLUGIN_INFO_FLAGS_AUTO_LOAD = 1 << 2,
+
+} PurplePluginInfoFlags;
+
+/**
+ * PurplePluginInfo:
+ *
+ * Holds information about a plugin.
+ *
+ * Since: 3.0.0
+ */
+
+/**
+ * PURPLE_PLUGIN_ABI_VERSION:
+ *
+ * Note: The lower six nibbles represent the ABI version for libpurple, the
+ * rest are required by GPlugin.
+ *
+ * Returns: An ABI version to set in plugins using major and minor versions.
+ */
+#define PURPLE_PLUGIN_ABI_VERSION(major,minor) \
+ (0x01000000 | ((major) << 16) | (minor))
+
+/**
+ * PURPLE_PLUGIN_ABI_MAJOR_VERSION:
+ *
+ * Returns: The major version from an ABI version
+ */
+#define PURPLE_PLUGIN_ABI_MAJOR_VERSION(abi) \
+ ((abi >> 16) & 0xff)
+
+/**
+ * PURPLE_PLUGIN_ABI_MINOR_VERSION:
+ *
+ * Returns: The minor version from an ABI version
+ */
+#define PURPLE_PLUGIN_ABI_MINOR_VERSION(abi) \
+ (abi & 0xffff)
+
+/**
+ * PURPLE_ABI_VERSION:
+ *
+ * A convenience macro that returns an ABI version using PURPLE_MAJOR_VERSION
+ * and PURPLE_MINOR_VERSION
+ */
+#define PURPLE_ABI_VERSION PURPLE_PLUGIN_ABI_VERSION(PURPLE_MAJOR_VERSION, PURPLE_MINOR_VERSION)
+
+G_BEGIN_DECLS
+
+/**
+ * purple_plugin_info_new:
+ * @first_property: The first property name
+ * @...: The value of the first property, followed optionally by more
+ * name/value pairs, followed by %NULL
+ *
+ * Creates a new #PurplePluginInfo instance to be returned from
+ * #plugin_query of a plugin, using the provided name/value pairs.
+ *
+ * All properties except <literal>"id"</literal> and
+ * <literal>"purple-abi"</literal> are optional.
+ *
+ * Valid property names are:
+ * <informaltable frame='none'>
+ * <tgroup cols='2'><tbody>
+ * <row><entry><literal>"id"</literal></entry>
+ * <entry>(string) The ID of the plugin.</entry>
+ * </row>
+ * <row><entry><literal>"abi-version"</literal></entry>
+ * <entry>(<type>guint32</type>) The ABI version required by the
+ * plugin.</entry>
+ * </row>
+ * <row><entry><literal>"name"</literal></entry>
+ * <entry>(string) The translated name of the plugin.</entry>
+ * </row>
+ * <row><entry><literal>"version"</literal></entry>
+ * <entry>(string) Version of the plugin.</entry>
+ * </row>
+ * <row><entry><literal>"category"</literal></entry>
+ * <entry>(string) Primary category of the plugin.</entry>
+ * </row>
+ * <row><entry><literal>"summary"</literal></entry>
+ * <entry>(string) Brief summary of the plugin.</entry>
+ * </row>
+ * <row><entry><literal>"description"</literal></entry>
+ * <entry>(string) Full description of the plugin.</entry>
+ * </row>
+ * <row><entry><literal>"authors"</literal></entry>
+ * <entry>(<type>const gchar * const *</type>) A %NULL-terminated list of
+ * plugin authors. format: First Last &lt;user\@domain.com&gt;</entry>
+ * </row>
+ * <row><entry><literal>"website"</literal></entry>
+ * <entry>(string) Website of the plugin.</entry>
+ * </row>
+ * <row><entry><literal>"icon"</literal></entry>
+ * <entry>(string) Path to a plugin's icon.</entry>
+ * </row>
+ * <row><entry><literal>"license-id"</literal></entry>
+ * <entry>(string) Short name of the plugin's license. This should
+ * either be an identifier of the license from
+ * <ulink url="http://dep.debian.net/deps/dep5/#license-specification">
+ * DEP5</ulink> or "Other" for custom licenses.</entry>
+ * </row>
+ * <row><entry><literal>"license-text"</literal></entry>
+ * <entry>(string) The text of the plugin's license, if unlisted on
+ * DEP5.</entry>
+ * </row>
+ * <row><entry><literal>"license-url"</literal></entry>
+ * <entry>(string) The plugin's license URL, if unlisted on DEP5.</entry>
+ * </row>
+ * <row><entry><literal>"dependencies"</literal></entry>
+ * <entry>(<type>const gchar * const *</type>) A %NULL-terminated list of
+ * plugin IDs required by the plugin.</entry>
+ * </row>
+ * <row><entry><literal>"actions-cb"</literal></entry>
+ * <entry>(#PurplePluginActionsCb) Callback that returns a list of
+ * actions the plugin can perform.</entry>
+ * </row>
+ * <row><entry><literal>"extra-cb"</literal></entry>
+ * <entry>(#PurplePluginExtraCb) Callback that returns a newly
+ * allocated string denoting extra information about a plugin.</entry>
+ * </row>
+ * <row><entry><literal>"pref-frame-cb"</literal></entry>
+ * <entry>(#PurplePluginPrefFrameCb) Callback that returns a
+ * preferences frame for the plugin.</entry>
+ * </row>
+ * <row><entry><literal>"pref-request-cb"</literal></entry>
+ * <entry>(#PurplePluginPrefRequestCb) Callback that returns a
+ * preferences request handle for the plugin.</entry>
+ * </row>
+ * <row><entry><literal>"flags"</literal></entry>
+ * <entry>(#PurplePluginInfoFlags) The flags for a plugin.</entry>
+ * </row>
+ * </tbody></tgroup>
+ * </informaltable>
+ *
+ * See #PURPLE_PLUGIN_ABI_VERSION,
+ * <link linkend="chapter-plugin-ids">Plugin IDs</link>.
+ *
+ * Returns: A new #PurplePluginInfo instance.
+ *
+ * Since: 3.0.0
+ */
+GPluginPluginInfo *purple_plugin_info_new(const char *first_property, ...) G_GNUC_NULL_TERMINATED;
+
+/**
+ * purple_plugin_info_get_actions_cb:
+ * @info: The plugin info to get the callback from.
+ *
+ * Returns the callback that retrieves the list of actions a plugin can perform
+ * at that moment.
+ *
+ * Returns: The callback that returns a list of #PurplePluginAction
+ * instances corresponding to the actions a plugin can perform.
+ *
+ * Since: 3.0.0
+ */
+PurplePluginActionsCb purple_plugin_info_get_actions_cb(PurplePluginInfo *info);
+
+/**
+ * purple_plugin_info_get_extra_cb:
+ * @info: The plugin info to get extra information from.
+ *
+ * Returns a callback that gives extra information about a plugin. You must
+ * free the string returned by this callback.
+ *
+ * Returns: (transfer none): The callback that returns extra information about a plugin.
+ *
+ * Since: 3.0.0
+ */
+PurplePluginExtraCb purple_plugin_info_get_extra_cb(PurplePluginInfo *info);
+
+/**
+ * purple_plugin_info_get_pref_frame_cb:
+ * @info: The plugin info to get the callback from.
+ *
+ * Returns the callback that retrieves the preferences frame for a plugin, set
+ * via the "pref-frame-cb" property of the plugin info.
+ *
+ * Returns: The callback that returns the preferences frame.
+ *
+ * Since: 3.0.0
+ */
+PurplePluginPrefFrameCb purple_plugin_info_get_pref_frame_cb(PurplePluginInfo *info);
+
+/**
+ * purple_plugin_info_get_pref_request_cb:
+ * @info: The plugin info to get the callback from.
+ *
+ * Returns the callback that retrieves the preferences request handle for a
+ * plugin, set via the "pref-request-cb" property of the plugin info.
+ *
+ * Returns: (transfer none): The callback that returns the preferences request handle.
+ *
+ * Since: 3.0.0
+ */
+PurplePluginPrefRequestCb purple_plugin_info_get_pref_request_cb(PurplePluginInfo *info);
+
+/**
+ * purple_plugin_info_get_flags:
+ * @info: The plugin's info instance.
+ *
+ * Returns the plugin's flags.
+ *
+ * Returns: The flags of the plugin.
+ *
+ * Since: 3.0.0
+ */
+PurplePluginInfoFlags purple_plugin_info_get_flags(PurplePluginInfo *info);
+
+/**
+ * purple_plugin_info_get_error:
+ * @info: The plugin info.
+ *
+ * Returns an error in the plugin info that would prevent the plugin from being
+ * loaded.
+ *
+ * Returns: The plugin info error, or %NULL.
+ *
+ * Since: 3.0.0
+ */
+const gchar *purple_plugin_info_get_error(PurplePluginInfo *info);
+
+/**
+ * purple_plugin_info_get_unloaded:
+ * @info: The #PurplePluginInfo instance.
+ *
+ * Gets whether or not the plugin has been unloaded.
+ *
+ * Returns: %TRUE if the plugin has been unloaded previously, or %FALSE if not.
+ *
+ * Since: 3.0.0
+ */
+gboolean purple_plugin_info_get_unloaded(PurplePluginInfo *info);
+
+/**
+ * purple_plugin_info_set_unloaded:
+ * @info: The #PurplePluginInfo instance.
+ * @unloaded: %TRUE to say the plugin has been unloaded.
+ *
+ * Sets the unloaded state of @info to @unloaded.
+ *
+ * Since: 3.0.0
+ */
+void purple_plugin_info_set_unloaded(PurplePluginInfo *info, gboolean unloaded);
+
+G_END_DECLS
+
+#endif /* PURPLE_PLUGIN_INFO_H */
+
--- a/po/POTFILES.in Thu Jun 17 23:43:50 2021 -0500
+++ b/po/POTFILES.in Fri Jun 18 00:00:00 2021 -0500
@@ -255,6 +255,7 @@
libpurple/purplenoopcredentialprovider.c
libpurple/purpleoptions.c
libpurple/purplepresence.c
+libpurple/purpleplugininfo.c
libpurple/purpleprotocolattention.c
libpurple/purpleprotocolchat.c
libpurple/purpleprotocolclient.c