<?php
/**
 * Requires PEAR
 */
require_once 'PEAR.php';

/**
 * Requires PEAR::XML_RPC
 */
require_once 'XML/RPC.php';

/**
 * VpopXmlrpcClient
 *
 * @author      Michael Wallner <mike@iworks.at>
 * @link        http://dev.iworks.at/vpop-xmlrpc/
 * @version     $Revision$
 */
class VpopXmlrpcClient
{
    var 
$client;
    var 
$defaultDomain;
    
    
/**
     * Constructor
     * 
     * @access  public
     * @param   string  $url
     * @param   string  $defaultDomain
     */
    
function VpopXmlrpcClient($url$defaultDomain null)
    {
        
$this->defaultDomain $defaultDomain;
        
$parts parse_url($url);
        
$this->client = &new XML_RPC_Client($parts['path'], $parts['host']);
        if (isset(
$parts['user'])) {
            
$this->client->setCredentials($parts['user'], $parts['pass']);
        }
    }
    
    
/**
     * Change Password
     * 
     * @access  public
     * @return  bool|PEAR_Error
     * @param   string  $user
     * @param   string  $password
     */
    
function passwd($user$password)
    {
        
$params = array('password' => $password);
        
$this->userDomain($params$user);
        return 
$this->rpcScalar('passwd'$params);
    }
    
    
/**
     * Auth
     * 
     * @access  public
     * @return  bool|PEAR_Error
     * @param   string  $user
     * @param   string  $password
     */
    
function auth($user$password)
    {
        
$params = array('password' => $password);
        
$this->userDomain($params$user);
        return 
$this->rpcScalar('auth'$params);
    }
    
    
/**
     * Add User
     * 
     * @access  public
     * @return  bool|PEAR_Error
     * @param   string  $user
     * @param   string  $password
     * @param   string  $fullname
     */
    
function addUser($user$password$fullname '')
    {
        
$params = array('password' => $password);
        
$this->userDomain($params$user);
        
        if (
$fullname) {
            
$params['fullname'] = $fullname;
        } else {
            
$params['fullname'] = $params['user'].'@'.$params['domain'];
        }
        
        return 
$this->rpcScalar('adduser'$params);
    }
    
    
/**
     * Delete User
     * 
     * @access  public
     * @return  bool|PEAR_Error
     * @param   string  $user
     */
    
function delUser($user)
    {
        
$this->userDomain($params$user);
        return 
$this->rpcScalar('deluser'$params);
    }
    
    
/**
     * Set Quota
     * 
     * @access  public
     * @return  bool|PEAR_Error
     * @param   string  $user
     * @param   string  $quota
     */
    
function setQuota($user$quota)
    {
        
$params = array('quota' => $quota);
        
$this->userDomain($params$user);
        return 
$this->rpcScalar('setquota'$params);
    }
    
    
/**
     * Add Domain
     * 
     * @access  public
     * @return  bool@PEAR_Error
     * @param   string  $domain
     * @param   string  $password
     */
    
function addDomain($domain$password)
    {
        return 
$this->rpcScalar('adddomain'
            array(
'domain' => $domain'password' => $password));
    }
    
    
/**
     * Delete Domain
     * 
     * @access  public
     * @return  bool|PEAR_Error
     * @param   string  $domain
     */
    
function delDomain($domain)
    {
        return 
$this->rpcScalar('deldomain', array('domain' => $domain));
    }
    
    
/**
     * List Users
     * 
     * @access  public
     * @return  mixed
     */
    
function listUsers($domain)
    {
        return 
$this->rpcStruct('listusers', array('domain' => $domain));
    }
    
    
/**
     * List Domains
     * 
     * @access  public
     * @return  mixed
     */
    
function listDomains()
    {
        return 
$this->rpcStruct('listdomains');
    }
    
    
/**
     * User Domain
     * 
     * @access  protected
     * @return  void
     * @param   array   &$params
     * @param   string  $user
     */
    
function userDomain(&$params$user)
    {
        if (
preg_match('/(.+)@(.+)/'$user$matches)) {
            
$params['user']     = $matches[1];
            
$params['domain']   = $matches[2];
        } else {
            
$params['user']     = $user;
            
$params['domain']   = $this->defaultDomain;
        }
    }
    
    
/**
     * RPC with scalar return value
     * 
     * @access  protected
     * @return  bool|PEAR_Error
     * @param   string  $action
     * @param   array   $params
     */
    
function rpcScalar($action$params = array())
    {
        
$result = &$this->_rpc($action$params);
        if (
PEAR::isError($result)) {
            return 
$result;
        }
        return 
$result->xv->scalarVal();
    }
    
    
/**
     * RPC with struct return value
     * 
     * @access  protected
     * @return  array|PEAR_Error
     * @param   string  $action
     * @param   string  $params
     */
    
function rpcStruct($action$params = array())
    {
        
$result = &$this->_rpc($action$params);
        if (
PEAR::isError($result)) {
            return 
$result;
        }
        return 
$this->flatten($result->xv->me['struct']);
    }
    
    
/**
     * RPC with array return value
     * 
     * @access  protected
     * @return  array|PEAR_Error
     * @param   string  $action
     * @param   string  $params
     */
    
function rpcArray($action$params = array())
    {
        
$result = &$this->_rpc($action$params);
        if (
PEAR::isError($result)) {
            return 
$result;
        }
        return 
$this->flatten($result->xv->me['array']);
    }
    
    
/**
     * @private
     */
    
function _rpc($action$params)
    {
        
$value null;
        if (
count($params)) {
            
$values = array();
            foreach ((array) 
$params as $name => $value) {
                
$values[$name] = &new XML_RPC_Value($value'string');
            }
            
$value = array(new XML_RPC_Value($values'struct'));
        }
        
$result $this->client->send(new XML_RPC_Message("vpop.$action"$value));
        if (
$result->faultCode()) {
            return 
PEAR::raiseError($result->faultString(), $result->faultCode());
        }
        return 
$result;
    }
    
    
/**
     * Flatten Structure
     * 
     * @access  protected
     * @return  array
     * @param   array   $struct
     */
    
function flatten(&$struct)
    {
        
$result = array();
        foreach ((array) 
$struct as $key => $val) {
            switch (
$type $val->kindOf())
            {
                case 
'array';
                case 
'struct':
                    
$result[$key] = $this->flatten($val->me[$type]);
                break;
                
                case 
'undef':
                    
$result[$key] = $$val->getVal();
                break;
                
                default:
                    
$result[$key] = $val->scalarVal();
            }
        }
        return 
$result;
    }
}

?>