Trac is being migrated to new services! Issues can be found in our new YouTrack instance and WIKI pages can be found on our website.

Version 5 (modified by hamiltont, 14 years ago) (diff)

added TOC, changed the command from /debug to /log to avoid builtin /debug command

Command API How-To

The command API is a method by which you can add commands to libpurple clients. Pidgin and Finch use the / character to denote a command, much like many IRC clients. This document will explain how to make your plugin add commands. Again we will assume that you have completed the Basic C Plugin Howto. We'll also continue to assume that you're using Pidgin 2.0.2 for these How-To documents as described there.

This document is incomplete. It has been saved to the wiki to ensure the current work is not lost. It should be finished soon.

About the Command API

The full command API documentation can be found at cmds.h. The API allows commands to specify priority, to allow proper handling of chained commands (aka, to create an order of operations). The API allows for flexible command arguments, from a single argument to multiple complex arguments.

Writing the Example Plugin

/*
 * Command Example Plugin
 *
 * Copyright (C) 2009, Hamilton Turner <hamiltont@gmail.com>
 *
 * 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.
 *
 */

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

/* Include glib.h for various types */
#include <glib.h>

/* This will prevent compiler errors in some instances and is better explained in the
 * how-to documents on the wiki */
#ifndef G_GNUC_NULL_TERMINATED
# if __GNUC__ >= 4
#  define G_GNUC_NULL_TERMINATED __attribute__((__sentinel__))
# else
#  define G_GNUC_NULL_TERMINATED
# endif
#endif

/* This is the required definition of PURPLE_PLUGINS as required for a plugin,
 * but we protect it with an #ifndef because config.h may define it for us
 * already and this would cause an unneeded compiler warning. */
#ifndef PURPLE_PLUGINS
# define PURPLE_PLUGINS
#endif

/* Here we're including the necessary libpurple headers for this plugin.  Note
 * that we're including them in alphabetical order.  This isn't necessary but
 * we do this throughout our source for consistency. */
#include "cmds.h"
#include "debug.h"
#include "plugin.h"
#include "notify.h"
#include "version.h"

/* It's more convenient to type PLUGIN_ID all the time than it is to type
 * "core-commandexample", so define this convenience macro. */
#define PLUGIN_ID "core-commandexample"

/* Common practice in third-party plugins is to define convenience macros for
 * many of the fields of the plugin info struct, so we'll do that for the
 * purposes of demonstration. */
#define PLUGIN_AUTHOR "Hamilton Turner <hamiltont@gmail.com>"

/* Initialized in the plugin_load() method, this allows us to keep a handle to 
 * ourself */ 
static PurplePlugin *command_example = NULL;


/* The callback function for our /log command. This function simply prints
 * whatever was entered as the argument to the debug command into the debug 
 * log. */
static PurpleCmdRet 
log_cb(PurpleConversation *conv, const gchar *cmd, gchar **args, gchar **error, void *data)
{
  purple_debug_misc(PLUGIN_ID, "log_cb called\n");
  purple_debug_misc(PLUGIN_ID, "message = %s\n", args[0]);

  return PURPLE_CMD_RET_OK;

}

/* The callback function for our /notify command. This function simply pops up
 * a notification with the word entered as the argument to the command */
static PurpleCmdRet 
notify_cb(PurpleConversation *conv, const gchar *cmd, gchar **args, gchar **error, void *data)
{

  purple_notify_info(command_example,
                     "Notify Notification Title",
                     "Notify Notification Primary Text",
                     args[0]);   /* Secondary text is the word entered */

  return PURPLE_CMD_RET_OK;

}




/* As we've covered before, libpurple calls this function, if present, when it
 * loads the plugin.  Here we're using it to show off the capabilities of the
 * debug API and just blindly returning TRUE to tell libpurple it's safe to
 * continue loading. */
static gboolean
plugin_load(PurplePlugin *plugin)
{
  /* Declare all vars up front. Avoids warnings on some compilers */
  gchar *log_help = NULL;
  gchar *notify_help = NULL;
  
  /* Save a handle to ourself for later */
  command_example = plugin;

  /* Help message for log command, in the correct format */
  log_help = "log &lt;log message here&gt;:  Prints a message to the debug log.";

  /* Register a command to allow a user to enter /log some message and have
   * that message stored to the log. This command runs with default priority,
   * can only be used in a standard chat message, not while in group chat
   * mode */ 
  purple_cmd_register 
    ("log",                         /* command name */ 
     "s",                           /* command arguments */
     PURPLE_CMD_P_DEFAULT,          /* command priority */  
     PURPLE_CMD_FLAG_IM,            /* flags saying where 
                                       command can be used */
     
     NULL,                          /* We do not need to pass
                                       plugin ID */
     
     log_cb,                        /* Name of the callback
                                       function */
     log_help,

     NULL                           /* We do not need any special
                                       user defined data here */
     );
        

  /* Help message for notify command, in the correct format */
  notify_help = "notify &lt;notify word here&gt;:  Pops up a notification with the word you enter.";


  /* Register a command to allow a user to enter /notify some word and have
   * that word notified back to them. This command runs with high priority,
   * can only be used both in group and standard chat messages */
  purple_cmd_register
    ("notify",                      /* command name */ 
     "w",                           /* command arguments */
     PURPLE_CMD_P_HIGH,             /* command priority */  
     PURPLE_CMD_FLAG_IM | 
       PURPLE_CMD_FLAG_CHAT,        /* flags saying where 
                                       command can be used */
     
     NULL,                          /* We do not need to pass
                                       plugin ID */
     
     notify_cb,                     /* Name of the callback
                                       function */
     notify_help,

     NULL                           /* We do not need any special
                                       user defined data here */
     );
 

  /* Just return true to tell libpurple to finish loading. */
  return TRUE;
}

static PurplePluginInfo info = {
        PURPLE_PLUGIN_MAGIC,        /* magic number */
        PURPLE_MAJOR_VERSION,       /* purple major */
        PURPLE_MINOR_VERSION,       /* purple minor */
        PURPLE_PLUGIN_STANDARD,     /* plugin type */
        NULL,                       /* UI requirement */
        0,                          /* flags */
        NULL,                       /* dependencies */
        PURPLE_PRIORITY_DEFAULT,    /* priority */

        PLUGIN_ID,                  /* id */
        "Command API Example",      /* name */
        DISPLAY_VERSION,            /* version */
        "Command API Example",      /* summary */
        "Command API Example",      /* description */
        PLUGIN_AUTHOR,              /* author */
        "http://pidgin.im",         /* homepage */

        plugin_load,                /* load */
        NULL,                       /* unload */
        NULL,                       /* destroy */

        NULL,                       /* ui info */
        NULL,                       /* extra info */
        NULL,                       /* prefs info */
        NULL,                       /* actions */
        NULL,                       /* reserved */
        NULL,                       /* reserved */
        NULL,                       /* reserved */
        NULL                        /* reserved */
};

static void
init_plugin(PurplePlugin *plugin)
{
}

PURPLE_INIT_PLUGIN(commandexample, init_plugin, info)

Compiling, Installing, and Testing the Plugin

As before, run make command_example.so (make -f Makefile.mingw command_example.dll for you Windows types) to build the plugin. Copy the resulting command_example.so to ~/.purple/plugins, or copy the resulting command_example.dll to %APPDATA%\.purple\plugins.

To test (we will assume you are using Pidgin), go to Tools->Plugins and enable the Command API Example plugin. Also, go to Help->Debug Window to show the Debug Window. Open an IM chat session, and type /log my log message here. Your message should show up in the Debug Window. Then type /notify Hello''. You should receive a notification box saying Hello! Also, be sure to try /notify Hello World'' and not that the command fails, because you input multiple arguments (2) when it was only expecting a single value.

Beyond the Command API

The command API provides a basic command framework for plugins, which can be an extremely valuable resource to plugin authors. The other areas we didn't cover here include much of the true power of the command API, but we will leave those as an area for your exploration at least for now. This document is done, but there are still others in the C Plugin How-To for you to explore!

Updates Needed to this page

  • Need to clean up the commands (purple_cmd_unregister) at unload.
All information, including names and email addresses, entered onto this website or sent to mailing lists affiliated with this website will be public. Do not post confidential information, especially passwords!