Using mod_rest to update the roster

I have tried using mod_rest to update the roster but am having difficulty.

I issue two iq requests to add the users into each others rosters which works perfectly, but when I send the presence requests with a type of "subscribe" for each of the users, the roster only updates the ask field of one of the users to "I" but doesn't update the ask field for the other user. Similarly when I send the presence requests with a type of "subscribed" nothing happens for either of the two users.

I would like to be able to add the two users into each others rosters and automatically subscribe to each others presence.

Am I doing something wrong or is there perhaps another way that this can be achieved?

Try mod_admin_extra add_rosteritem

You can tell ejabberd to add the roster items to the local account rosters directly, bypassing the XMPP subscription stuff.

Install mod_admin_extra, which provides a new ejabberd command "add_rosteritem". You can test it in the shell using ejabberdctl:

$ ejabberdctl help add_rosteritem

  Command Name: add_rosteritem

  Arguments: localuser::string
             localserver::string
             user::string
             server::string
             nick::string
             group::string
             subs::string

  Returns: res::rescode

  Tags: roster

  Description: Add an item to a user's roster

$ ejabberdctl add_rosteritem badlop localhost otheruser localhost OtherUser Friends both
$ ejabberdctl add_rosteritem otheruser localhost badlop localhost Badlop OldFriends both

When you are familiar with the command, you can try to execute it by sending a request to mod_rest. For that, see the example call in Python at the end of mod_rest's README.txt

I have already tried mod_admin_extra but prefer to use mod_rest

Thanks for your suggestion.

I have already tried using mod_admin_extra, but prefer using mod_rest since mod_admin_extra only appears to support the native mnesia database and not a roster stored in a MySQL database.

Our server configuration relies on several servers being able to add the entries to the roster, not just a single server, so I was thinking that mod_rest might be a better approach than mod_admin_extra.

The Python example in the README.text for mod_rest only provides a simple example on how to send a message.

Sending a message works fine, and even adding the users into each others rosters via mod_rest works fine, but the value of 'subscription' for each user is 'N' (none) so they appear offline to each other.

I want to be able to change 'subscription' from 'N' (none) to 'B' (both) so that they can appear online to each other.

I tried sending the following XML the mod_rest web service for each user but its not working:

<presence from="garth@localhost" to="ashley@localhost" type="subscribe"/>
<presence from="ashley@localhost" to="garth@localost" type="subscribe"/>

AND

<presence from="ashley@localhost" to="garth@localost" type="subscribed"/>
<presence from="garth@localhost" to="ashley@localhost" type="subscribed"/>

What happens is that the 'ask' field for ashley@localhost gets set from 'N' (none) to 'I' (in), but thats the only thing that gets updated as a result of all 4 requests.

presence subscribe requests work but subscribed requests don't

Sorry, one of my users wasn't registered. Now that they are registered, the ask field for both users gets set to 'I' (in), so the 'subscribe' requests are working, but the ones to accept the subscription requests and set the subscription status are not working, ie.

<presence from="ashley@localhost" to="garth@localost" type="subscribed"/>
<presence from="garth@localhost" to="ashley@localhost" type="subscribed"/>

add_rosteritem not working from external script

i installed mod_admin_extra, and am trying to add 2 users to each other user , when i try from shell its working perfectly, but when i try to call it from an external php script its not working, same happens using TCL script, here is what i get in my error log:

=INFO REPORT==== 2011-01-02 10:02:27 ===
I(<0.356.0>:ejabberd_listener:232) : (#Port<0.1687>) Accepted connection {{my,ip,address,here},37081} -> {{ejabberd,ip,address,here},5280}

=INFO REPORT==== 2011-01-02 10:02:27 ===
D(<0.1108.0>:ejabberd_http:135) : S: [{["rest"],mod_rest},
                                      {["admin"],ejabberd_web_admin},
                                      {["http-bind"],mod_http_bind},
                                      {["http-poll"],ejabberd_http_poll}]

=INFO REPORT==== 2011-01-02 10:02:27 ===
I(<0.1108.0>:ejabberd_http:137) : started: {gen_tcp,#Port<0.1687>}

=INFO REPORT==== 2011-01-02 10:02:27 ===
D(<0.1108.0>:ejabberd_http:254) : (#Port<0.1687>) http query: 'POST' /rest/

=INFO REPORT==== 2011-01-02 10:02:27 ===
D(<0.1108.0>:ejabberd_http:420) : client data: "add_rosteritem anna im.mysite.com karen im.mysite.com someOne Friends both"

=INFO REPORT==== 2011-01-02 10:02:27 ===
D(<0.1108.0>:ejabberd_http:323) : ["rest"] matches ["rest"]

=INFO REPORT==== 2011-01-02 10:02:27 ===
I(<0.1108.0>:mod_rest:92) : Data: "add_rosteritem anna im.mysite.com karen im.mysite.com someOne Friends both"

=INFO REPORT==== 2011-01-02 10:02:27 ===
D(<0.1108.0>:mod_rest:58) : Error when processing REST request:
Data: "add_rosteritem anna im.mysite.com karen im.mysite.com someOne Friends both"
Error: {badmatch,false}

here is the php script i tried:

<?php
$param
=array("user"=>"admin", "host"=>"ejabberd.ip.address.here");
$request = "add_rosteritem anna im.mysite.com karen im.mysite.com someOne Friends both";
$context = stream_context_create(array('http' => array(
  
'method' => "POST",
  
'header' => "Content-Type: text/xml\r\n" .
              
"Content-Length: ".strlen($request),
  
'content' => $request
)));

$file = file_get_contents("http://ejabberd.ip.address.here:5280/rest/", false, $context);

echo

$file;

/*$response = xmlrpc_decode($file);

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

?>

What am i doing wrong? can anyone advise me?

XMPP Domain

nouralk wrote:

$file = file_get_contents("http://ejabberd.ip.address.here:5280/rest/", false, $context);

Instead of IP address, put the XMPP domain (im.mysite.com). If that still fails, then describe what ejabberd and mod_rest versions you use.

Problem Solved

I was trying to over-complicate the process... now I understand what badlop was saying.

The easiest way of handling this is to simply include the ejabberdctl commands in the rest request instead of trying to use XML.

add_rosteritem ashley ashley garth ashley garth Buddies both

works like a charm.

In PHP this can be done as follows:

function sendRESTRequest ($url, $xml) {
    $context = stream_context_create(
         array('http' =>
                        array(
                                'method' => "POST",
                                'header' => "Content-Length: ".strlen($xml),
                                'content' => $xml
                        )
            )
    );
    $file = file_get_contents($url, false, $context);
    echo "file:[$file]\n";
}
$request = "add_rosteritem ashley ashley garth ashley garth Buddies both";
sendRESTRequest($url, $request);

Example PHP code for the README

I'd like to include a PHP example code like yours in mod_rest README. I tried to write a file with this content:

<?
function sendRESTRequest ($url, $xml) {
    $context = stream_context_create(
         array('http' =>
                        array(
                                'method' => "POST",
                                'header' => "Content-Length: ".strlen($xml),
                                'content' => $xml
                        )
            )
    );
    $file = file_get_contents($url, false, $context);
    echo "file:[$file]\n";
}
$url = "http://127.0.0.1:5280/rest";
$request = "register user123 localhost somepass";
sendRESTRequest($url, $request);
?>

But calling it failed:

$ php5-cgi rest.php

PHP Notice:  file_get_contents(): Content-type not specified assuming 
application/x-www-form-urlencoded 
in /f/jabber/p1/modules/mod_rest/trunk/aa.php on line 13

PHP Warning:  file_get_contents(http://127.0.0.1:5280/rest): 
failed to open stream: HTTP request failed! HTTP/1.0 406 Not Acceptable
 in /f/jabber/p1/modules/mod_rest/trunk/aa.php on line 13

X-Powered-By: PHP/5.3.2-1
Content-type: text/html

file:[]

Do you know what's the problem, or how to fix, or provide another example in PHP?

You need to specify the allowed_ips in the module configuration

The error you received happens when the host you are attempting to send the rest request from is not authorised to send rest requests in ejabberd.cfg

You need to add something like the following to ejabberd.cfg:

  {mod_rest,  [
              {allowed_ips, [ {127,0,0,1}, {192,168,1,100} ]}
              ]}

The content you provided doesn't actually declare the $url variable so it would be good to do something like the following:

<?
function sendRESTRequest ($url, $xml) {
    $context = stream_context_create(
         array('http' =>
                        array(
                                'method' => "POST",
                                'header' => "Content-Length: ".strlen($xml),
                                'content' => $xml
                        )
            )
    );
    $file = file_get_contents($url, false, $context);
    echo "file:[$file]\n";
}

$url = "http://127.0.0.1:5280/rest";

$request = "register user123 localhost somepass";
sendRESTRequest($url, $request);
$request = "status";

sendRESTRequest($url, $request);
?>

More changes in PHP, and last problem

Ok, I made some progress. In fact I don't need the allowed_ips option. Then, in the PHP code I changed the array code to indicate explicitely the Host header:

array(
  'method' => "POST",
  'header' => "Host: localhost:5280\nContent-Type: text/html; charset=utf-8",
  'content' => $xml
)

Now I can call:

$ php aa.php
file:[User user12@localhost succesfully registered]

The only problem is that, when there is some error returned, the PHP code doesn't show the exact error reason:

$ php aa.php
PHP Warning:  file_get_contents(http://127.0.0.1:5280/rest):
failed to open stream:
HTTP request failed!
HTTP/1.0 500 Internal Server Error
 in /modules/mod_rest/trunk/aa.php on line 12

file:[]

It's only seen in the network traffic:

HTTP/1.0 500 Internal Server Error
Connection: close
Content-Type: text/html; charset=utf-8
Content-Length: 65

User user12@localhost already registered at node ejabberd@galleta

This is problem with mod_rest not PHP

This is problem is generic to mod_rest and not a problem with PHP.

If you execute the same command in Python, you get the same result:

$ python rest.py 
Traceback (most recent call last):
  File "rest.py", line 16, in 
    resp = urllib2.urlopen(server_url, call)
  File "/usr/lib/python2.6/urllib2.py", line 124, in urlopen
    return _opener.open(url, data, timeout)
  File "/usr/lib/python2.6/urllib2.py", line 395, in open
    response = meth(req, response)
  File "/usr/lib/python2.6/urllib2.py", line 508, in http_response
    'http', request, response, code, msg, hdrs)
  File "/usr/lib/python2.6/urllib2.py", line 433, in error
    return self._call_chain(*args)
  File "/usr/lib/python2.6/urllib2.py", line 367, in _call_chain
    result = func(*args)
  File "/usr/lib/python2.6/urllib2.py", line 516, in http_error_default
    raise HTTPError(req.get_full_url(), code, msg, hdrs, fp)
urllib2.HTTPError: HTTP Error 500: Internal Server Error

Update the HTTP status code in mod_rest.erl from 500 to 200

If you update the HTTP status code on line 93 of mod_rest.erl from 500 (Internal Server Error) to 200 (OK), then the correct message will be displayed in Python as well as PHP.

Oh, but in that case it's

Oh, but in that case it's necessary to parse the response to know if there was any error. I'll keep the code as it is now.

I've added your example PHP code to mod_rest README.txt

example for mod_rest only works in PHP 5 - example in PHP 4

Thanks for adding the example PHP code to the mod_rest README.txt.

Unfortunately the example PHP code only works in PHP 5 but does not work in PHP 4.

It would be better to change the sendRESTRequest function as follows in order for the example code to work in both PHP 4 and PHP 5.

function sendRESTRequest ($url, $xml) {
    $context = stream_context_create(
         array('http' =>
                        array(
                                'method' => "POST",
                                'header' => "Content-Length: ".strlen($xml),
                                'content' => $xml
                        )
            )
    );
    $fp = fopen($url, 'r', false, $context);
    $response = '';
    while(!feof($fp)) {
        $response .= fread($fp, 4096);
    }
    fclose($fp);
    echo "Response: $response\n";
    return $response;
}

Streamlined sendRESTRequest function for PHP4 as well as PHP5

I have streamlined the sendRESTRequest function so that it can support PHP5 using file_get_contents and implement the alternative solution for PHP4:

function sendRESTRequest ($url, $request) {
    // Create a stream context so that we can POST the REST request to $url
    $context = stream_context_create (array ('http' => array ('method' => 'POST'
                                            ,'header' => "Content-Length: ".strlen($request)
                                            ,'content' => $request)));

    // Use file_get_contents for PHP 5+ otherwise use fopen, fread, fclose
    if (version_compare(PHP_VERSION, '5.0.0', '>=')) {
        $result = file_get_contents($url, false, $context);
    } else {
        // This is the PHP4 workaround which is slightly less elegant
        // Supress fopen warnings, otherwise they interfere with the page headers
        $fp = @fopen($url, 'r', false, $context);
        $result = '';

        // Only proceed if we have a file handle, otherwise we enter an infinite loop
        if ($fp) {
            while(!feof($fp)) {
                $result .= fread($fp, 4096);
            }
            fclose($fp);
        }
    }

    return $result;
}

Ok, I've update the code in

Ok, I've update the code in the README.

Return codes

I'm having issues with the way ejabberdctl returns error codes.

If I run a command like

ejabberdctl check_account garth localhost

and the account exists, nothing is returned. To actually check the error code, I have to do

echo $?

If the account exists, it returns a 0, if it doesn't exist, it reutrns a 1. Nevermind the fact that the error codes seem the wrong way around, I have no way of checking these codes when doing a POST to the server in php, using a function as outlined above.

It seems to me, if using the check account exmaple, that if I do a post and the account doesn't exist, then the fopen fails, if it does exist, then the fopen succeeds, but no content is returned.

The problem with this is, I have no way of knowing the difference between the actual post failing or the account simply not existing.

Is there another way I can communicate with the server and actually get the return codes back?

Return at least the code

With this change, when the response contains no text, at least the status code number is returned, and doesn't return 500 in case of response==false:

--- src/mod_rest.erl    (revision: 1099)
+++ src/mod_rest.erl    (copia de trabajo)
@@ -93,10 +93,14 @@
     Args = split_line(Data),
     AccessCommands = get_option_access(Host),
     case ejabberd_ctl:process2(Args, AccessCommands) of
+       {"", ?STATUS_SUCCESS} ->
+           {200, [], integer_to_list(?STATUS_SUCCESS)};
        {String, ?STATUS_SUCCESS} ->
            {200, [], String};
+       {"", Code} ->
+           {200, [], integer_to_list(Code)};
        {String, _Code} ->
-           {500, [], String}
+           {200, [], String}
     end.

 %% This function throws an error if the module is not started in that VHost.

Try it and tell me if that solves the problem, and it's worth including in SVN.

able to add_rosteritem using ejabberdctl but not with mod_rest.

Hi,

I have configured mod_rest and mod_admin_extra.
I am able to do following command using shell:
ejabberdctl add_rosteritem ashley ashley garth ashley garth Buddies both

but when I tried through PHP client, I'm getting the following error.

Resolving mydomain.net... xxx.xxx.xxx.xxx
Connecting to mydomain.net|xxx.xxx.xxx.xxx|:5280... connected.
HTTP request sent, awaiting response...
HTTP/1.0 406 Not Acceptable
Connection: keep-alive
Content-Type: text/html; charset=utf-8
Content-Length: 43
2010-08-02 18:38:00 ERROR 406: Not Acceptable.

Could you please point out what else I need to configure?

Best Regards,
Sa Lin

Try recent SVN and look at logs

salin wrote:

when I tried through PHP client, I'm getting the following error.

2010-08-02 18:38:00 ERROR 406: Not Acceptable.

The problem happens when processing your request, maybe it lacks some argument, or the arguments are wrongly formatted, or escaped.

I've added some debug lines to mod_rest in SVN. You can download it, recompile, install, configure {loglevel, 5} in ejabberd.cfg, start ejabberd, make your request, and then search in the log files for the word "REST".

Hi please can you help how to

Hi please can you help how to configured mod_rest and mod_admin_extra in my ubuntu machine

Hi i want to make friend on

Hi i want to make friend on ejabberd using php code & for this i use this command Install mod_admin_extra to install roster on my ubuntu machine it shows command not found,please help me,Thanks in Advance.

Syndicate content