ejabberd-contrib/ejabberd_xmlrpc
Badlop 2e5bc8d269 Add ebin/ dirs with .keepme file to ensure Git tracks them 2013-04-25 12:55:59 +02:00
..
ebin Add ebin/ dirs with .keepme file to ensure Git tracks them 2013-04-25 12:55:59 +02:00
src Initial import from ejabberd-modules SVN 2013-04-15 12:03:14 +02:00
COPYING Initial import from ejabberd-modules SVN 2013-04-15 12:03:14 +02:00
ChangeLog Initial import from ejabberd-modules SVN 2013-04-15 12:03:14 +02:00
Emakefile Initial import from ejabberd-modules SVN 2013-04-15 12:03:14 +02:00
README.txt Initial import from ejabberd-modules SVN 2013-04-15 12:03:14 +02:00
build.bat Initial import from ejabberd-modules SVN 2013-04-15 12:03:14 +02:00
build.sh Initial import from ejabberd-modules SVN 2013-04-15 12:03:14 +02:00

README.txt

        ejabberd_xmlrpc - XML-RPC server

        Homepage: http://www.ejabberd.im/ejabberd_xmlrpc
        Author: Badlop


	DESCRIPTION
	-----------

ejabberd_xmlrpc is an ejabberd listener that starts a XML-RPC server
and waits for external calls.

ejabberd_xmlrpc implements some example calls that can be used to test
during the development of a new XML-RPC client.  But most
importantly, ejabberd_xmlrpc is also a frontend to execute ejabberd
commands.  This way a XML-RPC client can execute any ejabberd command.

This allows external programs written in any language like websites or
administrative tools to communicate with ejabberd to get information
or to make changes without the need to know ejabberd internals.  One
example usage is a corporate site in PHP that creates a Jabber user
every time a new user is created on the website.

Some benefits of interfacing with the Jabber server by XML-RPC instead
of modifying directly the database are:
 - external programs are more simple and easy to develop and debug
 - can communicate with a server in a different machine, and even on Internet


	REQUIREMENTS
	------------

    ejabberd 2.1.0 or higher
    XMLRPC-Erlang 1.13 with IP, Ruby and Xmerl 1.x patches
    Optional: mod_admin_extra implements many ejabberd commands for general server administration
    Optional: mod_muc_admin implements ejabberd commands for MUC administration


	CONFIGURE EJABBERD
	------------------

1. You need to get and install XMLRPC-Erlang.
You can download XMLRPC-Erlang binary files from
  http://www.ejabberd.im/ejabberd_xmlrpc
or compile it yourself:
  wget http://www.ejabberd.im/files/contributions/xmlrpc-1.13-ipr2.tgz
  tar -xzvf xmlrpc-1.13-ipr2.tgz
  cd xmlrpc-1.13/src
  make
  cd ../../
Then you can copy the *.beam files to ejabberd ebin directory,
or add an option like this to the ejabberd start script:
$ erl -pa '/home/jabber/xmlrpc-1.13/ebin' ...

2. Configure ejabberd to start this listener at startup:
edit ejabberd.cfg and add on the 'listen' section:
{listen, [
   {4560, ejabberd_xmlrpc, []},
    ...
 ]}.

3. Start ejabberd.

4. Verify that ejabberd is listening in that port:
$ netstat -n -l | grep 4560
tcp        0      0 0.0.0.0:4560            0.0.0.0:*               LISTEN

5. If there is any problem, check ejabberd.log and sasl.log files


	CONFIGURE
	---------

The listener allow several configurable options:

    {maxsessions, Integer}
    Number of concurrent connections allowed.
    Default: 10

    {timeout, Integer}
    Timeout of the connections, expressed in milliseconds.
    Default: 5000

    {access_commands, AccessCommands}
    This option allows to define a list of access restrictions.
    If this option is present, then XML-RPC calls must include as
    first argument a struct with a user, server and password of an
    account in ejabberd that has privileges in Access.
    If the option is not present, such struct must not be provided.
    The default value is to not define any restriction: []
    When one or several access restrictions are defined and the
    XML-RPC call provides authentication for an account, each
    restriction is verified until one matches completely:
    the account matches the Access rule,
    the command name is listed in CommandNames,
    and the provided arguments do not contradict Arguments.
    There is more information about AccessCommands in the ejabberd Guide.


Example configuration: XML-RPC calls can execute any command, with any
argument, and no authentication information must be provided:
{listen, [
  {4560, ejabberd_xmlrpc, [{maxsessions, 10}, {timeout, 5000}]},
  ...
 ]}.

In this case authentication information must be provided, but it is
enough that the account exists and the password is valid to execute
any command:
{listen, [
  {4560, ejabberd_xmlrpc, [{maxsessions, 10}, {timeout, 5000},
                           {access_commands, [{all, all, []}]}]},
  ...
 ]}.

In this example the local Jabber account xmlrpc-robot@jabber.example.org
can execute any command with no argument restriction:
{acl, xmlrpcbot, {user, "xmlrpc-robot", "jabber.example.org"}}.
{access, xmlrpcaccess, [{allow, xmlrpcbot}]}.
{listen, [
  {4560, ejabberd_xmlrpc, [{maxsessions, 10}, {timeout, 5000},
                           {access_commands, [{xmlrpcaccess, all, []}]}]},
  ...
 ]}.

Finally, in this complex example the listener only listens in port
4560 of IP address 127.0.0.1, and several access restrictions are
defined (the corresponding ACL and ACCESS are not shown):
{listen, [
  {{4560, "127.0.0.1"}, ejabberd_xmlrpc, [
    {access_commands, [
      %% This bot can execute any command:
      {xmlrpc_bot, all, []},
      %% This bot can execute any command,
      %% but if a 'host' argument is provided, it must be "example.org":
      {xmlrpc_bot_all_example, all, [{host, "example.org"}]},
      %% This bot can only execute the command 'dump'. No argument restriction:
      {xmlrpc_bot_backups, [dump], []}
      %% This bot can only execute the command 'register',
      %% and if argument 'host' is provided, it must be "example.org":
      {xmlrpc_bot_reg_example, [register], [{host, "example.org"}]},
      %% This bot can execute the commands 'register' and 'unregister',
      %% if argument host is provided, it must be "test.org":
      {xmlrpc_bot_reg_test, [register, unregister], [{host, "test.org"}]}
    ]}
  ]},
  ...
 ]}.



	USAGE
	-----

You can send calls to http://host:4560/

Call:           Arguments:                                             Returns:

 -- debug
echothis        String                                                   String
echothisnew     struct[{sentence, String}]           struct[{repeated, String}]
multhis         struct[{a, Integer}, {b, Integer}]                      Integer
multhisnew      struct[{a, Integer}, {b, Integer}]        struct[{mu, Integer}]

 -- statistics
tellme_title    String                                                   String
tellme_value    String                                                   String
tellme          String                 struct[{title, String}, {value. String}]


With ejabberd_xmlrpc you can execute any ejabberd command with a XML-RPC call.

1. Get a list of available ejabberd commands, for example:
$ ejabberdctl help
Available commands in this ejabberd node:
  connected_users              List all established sessions
  connected_users_number       Get the number of established sessions
  delete_expired_messages      Delete expired offline messages from database
  delete_old_messages days     Delete offline messages older than DAYS
  dump file                    Dump the database to text file
  register user host password  Register a user
  registered_users host        List all registered users in HOST
  reopen_log                   Reopen the log files
  restart                      Restart ejabberd
  restore file                 Restore the database from backup file
  status                       Get ejabberd status
  stop                         Stop ejabberd
  unregister user host         Unregister a user
  user_resources user host     List user's connected resources

2. When you found the command you want to call, get some additional
   help of the arguments and result:
$ ejabberdctl help user_resources
  Command Name: user_resources
  Arguments: user::string
             host::string
  Returns: resources::[ resource::string ]
  Tags: session
  Description: List user's connected resources

3. You can try to execute the command in the shell for the account testuser@localhost:
$ ejabberdctl user_resources testuser localhost
Home
Psi

4. Now implement the proper XML-RPC call in your XML-RPC client.
   This example will use the Erlang library:
$ erl
1> xmlrpc:call({127, 0, 0, 1}, 4560, "/", {call, user_resources, [{struct, [{user, "testuser"}, {host, "localhost"}]}]}).
{ok,{response,[{struct,[{resources,{array,[{struct,[{resource,"Home"}]},
                                           {struct,[{resource,"Psi"}]}]}}]}]}}

5. Note: if ejabberd_xmlrpc has the option 'access_commands'
   configured with some access restriction (see the example
   configurations provided above), the XML-RPC must include first an
   argument providing information of a valid account. For example:
1> xmlrpc:call({127, 0, 0, 1}, 4560, "/", {call, user_resources, [
   {struct, [{user, "adminuser"}, {server, "localhost"}, {password, "aeiou"}]},
   {struct, [{user, "testuser"}, {host, "localhost"}]} ]}).


Arguments in XML-RPC calls can be provided in any order;
This module will sort the arguments before calling the ejabberd command.

If auth is provided in the call when ejabberd_xmlrpc does not require it,
the call will return the error: -112 Unknown call



	EXAMPLE IN PHP
	--------------

This is an XML-RPC client in PHP, thanks to Zbyszek Żółkiewski and Calder.
It requires "allow_url_fopen = On" in your php.ini.

-------
<?
$param=array("user"=>"testuser", "host"=>"localhost");
$request = xmlrpc_encode_request('user_resources', $param, (array('encoding' => 'utf-8')));

$context = stream_context_create(array('http' => array(
    'method' => "POST",
    'header' => "User-Agent: XMLRPC::Client mod_xmlrpc\r\n" .
                "Content-Type: text/xml\r\n" .
                "Content-Length: ".strlen($request),
    'content' => $request
)));

$file = file_get_contents("http://127.0.0.1:4560/RPC2", false, $context);

$response = xmlrpc_decode($file);

if (xmlrpc_is_fault($response)) {
    trigger_error("xmlrpc: $response[faultString] ($response[faultCode])");
} else {
    print_r($response);
}

?>
-------

The response, following the example would be like this:
-------
$ php5 call.php
Array
(
    [resources] => Array
        (
            [0] => Array
                (
                    [resource] => Home
                )
            [1] => Array
                (
                    [resource] => Psi
                )
        )
)
-------

If you configured the option access_commands, you have to provide authentication
information by replacing the first lime with something like this:
-------
$param_auth=array("user"=>"analloweduser", "server"=>"localhost", "password"=>"MyPasS997");
$param_comm=array("user"=>"testuser", "host"=>"localhost");
$param=array($param_auth, $param_comm);
-------


 **** WARNING: all the remaining text was written for mod_xmlrpc and
      is NOT valid for ejabberd_xmlrpc ****


	TEST
	----

 - You can easily try the XML-RPC server starting a new Erlang Virtual Machine
   and making calls to ejabberd's XML-RPC:

1. Start Erlang with this option:
$ erl -pa '/home/jabber/xmlrpc-1.13/ebin'

2. Now on the Erlang console, write commands and check the results:

1> xmlrpc:call({127, 0, 0, 1}, 4560, "/", {call, echothis, [800]}).
{ok,{response,[800]}}

2> xmlrpc:call({127, 0, 0, 1}, 4560, "/", {call, echothis, ["blot cloc 557.889 kg"]}).
{ok,{response,["blot cloc 557.889 kg"]}}

3> xmlrpc:call({127, 0, 0, 1}, 4560, "/", {call, multhis, [{struct,[{a, 83}, {b, 689}]}]}).
{ok,{response,[57187]}}

4> xmlrpc:call({127, 0, 0, 1}, 4560, "/", {call, register,
[{struct, [{user, "ggeo"}, {host, "example.com"}, {password, "gogo11"}]}]}).
{ok,{response,[0]}}

5> xmlrpc:call({127, 0, 0, 1}, 4560, "/", {call, register,
[{struct, [{user, "ggeo"}, {host, "example.com"}, {password, "gogo11"}]}]}).
{ok,{response,[409]}}

6> xmlrpc:call({127, 0, 0, 1}, 4560, "/", {call, muc_room_change_option,
[{struct, [{name, "test"}, {service, "conference.localhost"},
 {option, "title"}, {value, "Test Room"}]}]}).

7> xmlrpc:call({127, 0, 0, 1}, 4560, "/", {call, muc_room_set_affiliation,
[{struct, [{name, "test"}, {service, "conference.example.com"},
{jid, "ex@example.com"}, {affiliation, "member"}]}]}).

8> xmlrpc:call({127, 0, 0, 1}, 4560, "/", {call, muc_room_set_affiliation,
[{struct, [{name, "test"}, {service, "conference.example.com"},
{jid, "ex@example.com"}, {affiliation, "none"}]}]}).


 - Some possible XML-RPC error messages:

   + Client: connection refused: wrong IP, wrong port, the server is not started...

2> xmlrpc:call({127, 0, 0, 1}, 44444, "/", {call, echothis, [800]}).
{error,econnrefused}

   + Client: bad value: a800 is a string, so it must be put into ""

7> xmlrpc:call({127, 0, 0, 1}, 4560, "/", {call, echothis, [a800]}).
{error,{bad_value,a800}}

   + Server: unknown call: you sent a call that the server does not implement

3> xmlrpc:call({127, 0, 0, 1}, 4560, "/", {call, bububu, [800]}).
{ok,{response,{fault,-1,"Unknown call: {call,bububu,[800]}"}}}


	EXAMPLE IN PYTHON
	-----------------

This is an example XML-RPC client in Python, thanks to Diddek:
-------
import xmlrpclib

server_url = 'http://127.0.0.1:4560';
server = xmlrpclib.Server(server_url);

params = {}
params["user"] = "ggeo"
params["host"] = "localhost"
params["password"] = "gogo11"

result = server.register(params)
print result
-------

This Python example shows how to provide authentication in the call, thanks to Muelli:
-------
import xmlrpclib

server_url = 'http://127.0.0.1:4560'
server = xmlrpclib.ServerProxy(server_url)

EJABBERD_XMLRPC_LOGIN = {'user': 'adminuser', 'server': 'localhost', 'password': 'aeiou'}

def ejabberdctl(command, data):
    fn = getattr(server, command)
    return fn(EJABBERD_XMLRPC_LOGIN, data)

result = ejabberdctl('register', {'user':'ggeo', 'host':'localhost', 'password':'gogo11'})
print result
-------


	EXAMPLE IN RUBY
	---------------

This is an example XML-RPC client in Ruby, thanks to Diddek:
-------
require 'xmlrpc/client'

host = "172.16.29.6:4560"
timeout = 3000000
client = XMLRPC::Client.new2("http://#{host}", "#{host}", timeout)
result = client.call("echothis", "800")
puts result
-------


	EXAMPLE IN JAVA
	---------------

This is an XML-RPC client in Java, thanks to Calder.
It requires Apache XML-RPC available at http://ws.apache.org/xmlrpc/

-------
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

import org.apache.xmlrpc.client.XmlRpcClient;
import org.apache.xmlrpc.client.XmlRpcClientConfigImpl;

public class Test {

	public static void main(String[] args) {
		try {
		    XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
		    config.setServerURL(new URL("http://127.0.0.1:4560/RPC2"));
		    XmlRpcClient client = new XmlRpcClient();
		    client.setConfig(config);

		    /* Command string */
		    String command = "check_password";

		    /* Parameters as struct */
		    Map struct = new HashMap();
		    struct.put("user", "test1");
		    struct.put("host", "localhost");
		    struct.put("password", "test");

		    Object[] params = new Object[]{struct};
		    Integer result = (Integer) client.execute(command, params);
		    System.out.println(result);
		} catch (Exception e) {
			System.out.println(e);
		}
	}

}
-------


	EXAMPLE IN C#
	-------------

This is an XML-RPC client in C#, thanks to Mitchel Constantin.

-------
// Copyright: 2010 Weavver, Inc. 
// Author: Mitchel Constantin <mythicalbox@weavver.com>
// License: Public Domain (Limited to this file)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CookComputing.XmlRpc;

namespace Weavver.Vendors.ProcessOne
{
     public struct send_message_chat
     {
          public string from;
          public string to;
          public string body;
     }
     public struct status {}
     public class ejabberdRPC
     {
          [XmlRpcUrl("http://205.134.225.18:4560/RPC2")]
          public interface IStateName : IXmlRpcProxy
          {
               [XmlRpcMethod("send_message_chat")]
               object SendMessageChat(send_message_chat message);
               [XmlRpcMethod("status")]
               object Status(status s);
          }
          public CookComputing.XmlRpc.XmlRpcStruct SendMessageChat(send_message_chat message)
          {
               IStateName proxy = XmlRpcProxyGen.Create<IStateName>();
               proxy.KeepAlive = false;
               return (CookComputing.XmlRpc.XmlRpcStruct) proxy.SendMessageChat(message);
          }
          public CookComputing.XmlRpc.XmlRpcStruct Status(status status)
          {
               IStateName proxy = XmlRpcProxyGen.Create<IStateName>();
               proxy.KeepAlive = false;
               return (CookComputing.XmlRpc.XmlRpcStruct) proxy.Status(status);
          }
     }
}
-------