Wed, 15 Jun 2016 21:59:51 -0500
Merged in dequisdequis/pidgin/release-2.x.y (pull request #51)
Add PurpleCommandsUiOps API from instantbird
--- a/ChangeLog.API Tue Jun 07 00:44:16 2016 -0500 +++ b/ChangeLog.API Wed Jun 15 21:59:51 2016 -0500 @@ -5,6 +5,8 @@ Added: * account-status-changing signal (account signals) * buddy-removed-from-group signal (blist signals) + * PurpleCommandsUiOps, to allow the UI to override the + built-in handling of commands. version 2.10.12: * No changes
--- a/libpurple/cmds.c Tue Jun 07 00:44:16 2016 -0500 +++ b/libpurple/cmds.c Wed Jun 15 21:59:51 2016 -0500 @@ -27,10 +27,11 @@ #include "util.h" #include "cmds.h" +static PurpleCommandsUiOps *cmds_ui_ops = NULL; static GList *cmds = NULL; static guint next_id = 1; -typedef struct _PurpleCmd { +struct _PurpleCmd { PurpleCmdId id; gchar *cmd; gchar *args; @@ -40,7 +41,7 @@ PurpleCmdFunc func; gchar *help; void *data; -} PurpleCmd; +}; static gint cmds_compare_func(const PurpleCmd *a, const PurpleCmd *b) @@ -59,6 +60,7 @@ { PurpleCmdId id; PurpleCmd *c; + PurpleCommandsUiOps *ops; g_return_val_if_fail(cmd != NULL && *cmd != '\0', 0); g_return_val_if_fail(args != NULL, 0); @@ -79,6 +81,10 @@ cmds = g_list_insert_sorted(cmds, c, (GCompareFunc)cmds_compare_func); + ops = purple_cmds_get_ui_ops(); + if (ops && ops->register_command) + ops->register_command(cmd, p, f, prpl_id, helpstr, c); + purple_signal_emit(purple_cmds_get_handle(), "cmd-added", cmd, p, f); return id; @@ -102,6 +108,10 @@ c = l->data; if (c->id == id) { + PurpleCommandsUiOps *ops = purple_cmds_get_ui_ops(); + if (ops && ops->unregister_command) + ops->unregister_command(c->cmd, c->prpl_id); + cmds = g_list_remove(cmds, c); purple_signal_emit(purple_cmds_get_handle(), "cmd-removed", c->cmd); purple_cmd_free(c); @@ -301,6 +311,39 @@ } +gboolean purple_cmd_execute(PurpleCmd *c, PurpleConversation *conv, + const gchar *cmdline) +{ + gchar *err = NULL; + gchar **args = NULL; + PurpleCmdRet ret = PURPLE_CMD_RET_CONTINUE; + + if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) { + if (!(c->flags & PURPLE_CMD_FLAG_IM)) + return FALSE; + } + else if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) { + if (!(c->flags & PURPLE_CMD_FLAG_CHAT)) + return FALSE; + } + else + return FALSE; + + /* XXX: Don't worry much about the markup version of the command + line, there's not a single use case... */ + /* this checks the allow bad args flag for us */ + if (!purple_cmd_parse_args(c, cmdline, cmdline, &args)) { + g_strfreev(args); + return FALSE; + } + + ret = c->func(conv, c->cmd, args, &err, c->data); + + g_free(err); + g_strfreev(args); + + return ret == PURPLE_CMD_RET_OK; +} GList *purple_cmd_list(PurpleConversation *conv) { @@ -368,6 +411,21 @@ return &handle; } +void +purple_cmds_set_ui_ops(PurpleCommandsUiOps *ops) +{ + cmds_ui_ops = ops; +} + +PurpleCommandsUiOps * +purple_cmds_get_ui_ops(void) +{ + /* It is perfectly acceptable for cmds_ui_ops to be NULL; this just + * means that the default libpurple implementation will be used. + */ + return cmds_ui_ops; +} + void purple_cmds_init(void) { gpointer handle = purple_cmds_get_handle();
--- a/libpurple/cmds.h Tue Jun 07 00:44:16 2016 -0500 +++ b/libpurple/cmds.h Wed Jun 15 21:59:51 2016 -0500 @@ -31,6 +31,8 @@ /**************************************************************************/ /*@{*/ +typedef struct _PurpleCmd PurpleCmd; + /** The possible results of running a command with purple_cmd_do_command(). */ typedef enum _PurpleCmdStatus { PURPLE_CMD_STATUS_OK, @@ -96,6 +98,31 @@ PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS = 0x08 } PurpleCmdFlag; +/** + * Command UI operations; UIs should implement this if they want to handle + * commands themselves, rather than relying on the core. + * + * @see @ref ui-ops + */ +typedef struct +{ + /** If implemented, the UI is responsible for handling commands. */ + /* @see purple_cmd_register for the argument values. */ + void (*register_command)(const gchar *name, PurpleCmdPriority priority, + PurpleCmdFlag flags, const gchar *prpl_id, + const gchar *help, PurpleCmd *cmd); + + /** Should be implemented if register_command is implemented. + * name and prpl_id will have the same value that were used + * for the register_command call. + */ + void (*unregister_command)(const gchar *name, const gchar *prpl_id); + + void (*_purple_reserved1)(void); + void (*_purple_reserved2)(void); + void (*_purple_reserved3)(void); + void (*_purple_reserved4)(void); +} PurpleCommandsUiOps; /*@}*/ @@ -182,9 +209,9 @@ * @param cmdline The command the user typed (including all arguments) as a single string. * The caller doesn't have to do any parsing, except removing the command * prefix, which the core has no knowledge of. cmd should not contain any - * formatting, and should be in plain text (no html entities). + * formatting, and should be in plain text (no HTML entities). * @param markup This is the same as cmd, but is the formatted version. It should be in - * HTML, with < > and &, at least, escaped to html entities, and should + * HTML, with < > and &, at least, escaped to HTML entities, and should * include both the default formatting and any extra manual formatting. * @param errormsg If the command failed errormsg is filled in with the appropriate error * message. It must be freed by the caller with g_free(). @@ -194,6 +221,23 @@ const gchar *markup, gchar **errormsg); /** + * Execute a specific command. + * + * The UI calls this to execute a command, after parsing the + * command name. + * + * @param c The command to execute. + * @param conv The conversation the command was typed in. + * @param cmdline The command the user typed (only the arguments). + * The caller should remove the prefix and the command name. + * It should not contain any formatting, and should be + * in plain text (no HTML entities). + * @return TRUE if the command handled the @a cmdline, FALSE otherwise. + */ +gboolean purple_cmd_execute(PurpleCmd *c, PurpleConversation *conv, + const gchar *cmdline); + +/** * List registered commands. * * Returns a <tt>GList</tt> (which must be freed by the caller) of all commands @@ -230,6 +274,23 @@ gpointer purple_cmds_get_handle(void); /** + * Sets the UI operations structure to be used when registering and + * unregistering commands. The UI operations need only be set if the + * UI wants to handle the commands itself; otherwise, leave it as NULL. + * + * @param ops The UI operations structure. + */ +void purple_cmds_set_ui_ops(PurpleCommandsUiOps *ops); + +/** + * Returns the UI operations structure to be used when registering and + * unregistering commands. + * + * @return The UI operations structure. + */ +PurpleCommandsUiOps *purple_cmds_get_ui_ops(void); + +/** * Initialize the commands subsystem. * @since 2.5.0 */