*
* -------------------------------------------- *
* 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. *
\**************************************************************************/
/* $Id$ */
/* $Source$ */
// NOTE! This file is still in the experimental stages, use at your own risk!
// The only current documentation for it is the code and the comments
// A document explaining its usage should be done shortly
// PLEASE, do *NOT* make any changes to this file without talking to me
// directly first. Until I get it fully undercontrol.
// There might be possiable security holes in this, I haven't fully tested it
// (jengo)
$GLOBALS['phpgw_info'] = array();
$GLOBALS['phpgw_info']['flags'] = array(
'currentapp' => 'login',
'noheader' => True,
'disable_Template_class' => True
);
include('header.inc.php');
// If XML-RPC isn't enabled in PHP, return an XML-RPC response stating so
if (! function_exists('xmlrpc_server_create'))
{
echo "\n";
echo "\n";
echo "\n";
echo " \n";
echo " \n";
echo " \n";
echo " faultString\n";
echo " \n";
echo " XML-RPC support NOT enabled in PHP installation\n";
echo " \n";
echo " \n";
echo " \n";
echo " faultCode\n";
echo " \n";
echo " 1005\n";
echo " \n";
echo " \n";
echo " \n";
echo " \n";
echo "\n";
echo "\n";
exit;
}
// Return all PHP errors as faults
$GLOBALS['xmlrpc_server'] = xmlrpc_server_create();
error_reporting(E_ERROR | E_WARNING | E_PARSE);
set_error_handler('xmlrpc_custom_error');
$headers = getallheaders();
if (ereg('Basic',$headers['Authorization']))
{
$tmp = $headers['Authorization'];
$tmp = ereg_replace(' ','',$tmp);
$tmp = ereg_replace('Basic','',$tmp);
$auth = base64_decode(trim($tmp));
list($sessionid,$kp3) = split(':',$auth);
if ($GLOBALS['phpgw']->session->verify($sessionid,$kp3))
{
$GLOBALS['xmlrpc_server'] = xmlrpc_server_create();
$request_xml = $HTTP_RAW_POST_DATA;
// Find out what method they are calling
// This function is odd, you *NEED* to assign the results
// to a value, or $method is never returned. (jengo)
$null = xmlrpc_decode_request($request_xml, &$method);
$GLOBALS['phpgw']->session->xmlrpc_method_called = $method;
$GLOBALS['phpgw']->session->update_dla();
// Check permissions and load the class, register all methods
// for that class, and execute it
list($app,$class,$func) = explode('.',$method);
if ($method == 'system.logout' || $GLOBALS['phpgw_info']['user']['apps'][$app] || $app == 'phpgwapi')
{
$GLOBALS['obj'] = CreateObject($app . '.' . $class);
xmlrpc_server_register_method($xmlrpc_server,sprintf('%s.%s.%s',$app,$class,'listMethods'),'xmlrpc_list_methods');
xmlrpc_server_register_method($xmlrpc_server,sprintf('%s.%s.%s',$app,$class,'describeMethods'),xmlrpc_describe_methods);
xmlrpc_server_register_method($xmlrpc_server,'system.logout','xmlrpc_logout');
while (list(,$new_method) = @each($obj->xmlrpc_methods))
{
$full_method_name = sprintf('%s.%s.%s',$app,$class,$new_method['name']);
xmlrpc_server_register_method($xmlrpc_server,$full_method_name,'xmlrpc_call_wrapper');
// The following function is listed as being in the API, but doesn't actually exisit.
// This is more of a mental note to track down its exisitence
//xmlrpc_server_set_method_description($xmlrpc_server,$full_method_name,$new_method);
}
}
else if ($method != 'system.listMethods' && $method != 'system.describeMethods')
{
xmlrpc_error(1001,'Access not permitted');
}
echo xmlrpc_server_call_method($xmlrpc_server,$request_xml,'');
xmlrpc_server_destroy($xmlrpc_server);
}
else
{
// Session is invailed
xmlrpc_error(1001,'Session expired');
}
}
else
{
// First, create a single method being system.login
// If they don't request this, then just return a failed session error
$xmlrpc_server = xmlrpc_server_create();
$request_xml = $HTTP_RAW_POST_DATA;
// Find out what method they are calling
// This function is odd, you *NEED* to assign the results
// to a value, or $method is never returned. (jengo)
$null = xmlrpc_decode_request($request_xml, &$method);
if ($method == 'system.login')
{
xmlrpc_server_register_method($xmlrpc_server,'system.login','xmlrpc_login');
echo xmlrpc_server_call_method($xmlrpc_server,$request_xml,'');
xmlrpc_server_destroy($xmlrpc_server);
exit;
}
else
{
// They didn't request system.login and they didn't pass sessionid or
// kp3, this is an invailed session (The session could have also been killed or expired)
xmlrpc_error(1001,'Session expired');
}
}
// When PHP returns an error, return that error with a fault instead of
// HTML with will make most parsers fall apart
function xmlrpc_custom_error($error_number, $error_string, $filename, $line, $vars)
{
if (error_reporting() & $error_number)
{
$error_string .= sprintf("\nFilename: %s\nLine: %s",$filename,$line);
xmlrpc_error(1005,$error_string);
}
}
// This will create an XML-RPC error
// FIXME! This needs to be expanded to handle PHP errors themselfs
// it will make debugging easier
function xmlrpc_error($error_number, $error_string)
{
$values = array(
'faultString' => $error_string,
'faultCode' => $error_number
);
echo xmlrpc_encode_request(NULL,$values);
xmlrpc_server_destroy($GLOBALS['xmlrpc_server']);
exit;
}
// This will dynamicly create the avaiable methods for each class
function xmlrpc_list_methods($method)
{
list($app,$class,$func) = explode('.',$method);
$methods[] = 'system.login';
$methods[] = 'system.logout';
$methods[] = $method;
$methods[] = $app . '.' . $class . 'describeMethods';
for ($i=0; $ixmlrpc_methods); $i++)
{
$methods[] = $GLOBALS['obj']->xmlrpc_methods[$i]['name'];
}
return $methods;
}
function xmlrpc_describe_methods($method)
{
list($app,$class,$func) = explode('.',$method);
// FIXME! Add the missing pre-defined methods, example: system.login
for ($i=0; $ixmlrpc_methods); $i++)
{
$methods[] = $GLOBALS['obj']->xmlrpc_methods[$i];
}
return $methods;
}
// I know everyone hates wrappers, but this is the best way this can be done
// The XML-RPC functions pass method_name as the first parameter, which is
// unacceptable.
// Another reason for this, is it might be possiable to pass the sessionid
// and kp3 instead of using HTTP_AUTH features.
// Would be a nice workaround for librarys that don't support it, as its
// not in the XML-RPC spec.
function xmlrpc_call_wrapper($method_name, $parameters)
{
$a = explode('.',$method_name);
if (count($parameters) == 0)
{
$return = $GLOBALS['obj']->$a[2]();
}
else if (count($parameters) == 1)
{
$return = $GLOBALS['obj']->$a[2]($parameters[0]);
}
else
{
for ($i=0; $i$a[2](' . implode(',',$p) . ');');
}
// This needs to be expanded and more fully tested
if (gettype($return) == 'NULL')
{
return xmlrpc_error(1002,'No return value detected');
}
else
{
return $return;
}
}
// The following are common functions used ONLY by XML-RPC
function xmlrpc_login($method_name, $parameters)
{
$p = $parameters[0];
if ($p['domain'])
{
$username = $p['username'] . '@' . $p['domain'];
}
else
{
$username = $p['username'];
}
$sessionid = $GLOBALS['phpgw']->session->create($username,$p['password'],'text');
$kp3 = $GLOBALS['phpgw']->session->kp3;
$domain = $GLOBALS['phpgw']->session->account_domain;
if ($sessionid && $kp3)
{
return array(
'sessionid' => $sessionid,
'kp3' => $kp3,
'domain' => $domain
);
}
else
{
xmlrpc_error(1001,'Login failed');
}
}
function xmlrpc_logout($method, $parameters)
{
// We have already verified the session upon before this method is even created
// As long as nothing happens upon, its safe to destroy the session without
// fear of it being a hijacked session
$GLOBALS['phpgw']->session->destroy($GLOBALS['phpgw']->session->sessionid,$GLOBALS['phpgw']->session->kp3);
return True;
}