<?php
/**
 * $Horde: vacation/lib/Driver/ldap.php,v 1.1 2003/07/11 12:21:49 opal Exp $
 *
 * Copyright 2001-2003 Eric Rostetter <eric.rostetter@physics.utexas.edu>
 *
 * See the enclosed file LICENSE for license information (BSD). If you
 * did not receive this file, see http://www.horde.org/bsdl.php.
 *
 * Vacation_Driver_forwards:: implements the Vacation_Driver API for ftp driven
 * dot-forward compliant mail servers.
 *
 * @author  Eric Rostetter <eric.rostetter@physics.utexas.edu>
 * @version $Revision: 1.1 $
 * @package Vacation
 */

class Vacation_Driver_ldap extends Vacation_Driver {

    /** Pointer to the ldap connection. */
    var $_ds;

    /** Hash containing connection parameters. */
    var $_params;

    /** The error string returned to the user if an error occurs. */
    var $err_str;

/**
 * Constructs a new ftp dot-forward Vacation_Driber object.
 *
 * @param array  $params    A hash containing connection parameters.
 */
function Vacation_Driver_ldap($params = array())
{
    $this->_params = $params;
}

    /**
     * Do an ldap connect and bind as the guest user or as the optional userdn.
     *
     * @param    $userdn      The optional dn to use when binding non-anonymously.
     * @param    $oldpassword The optional password for $userdn.
     *
     * @return   boolean   True or False based on success of connect and bind.
     *
     */
    function _connect($userdn = null, $password = null, $realm = 'default') {
        $this->_ds = ldap_connect($this->_params[$realm]['host'], $this->_params[$realm]['port']);
        if (!$this->_ds) {
           return PEAR::raiseError(_("Could not connect to ldap server"));
        }

        if (!is_null($userdn)) {
            $result = @ldap_bind($this->_ds, $userdn, $password);
        } else {
            $result = @ldap_bind($this->_ds);
        }

        if (!$result) {
          return PEAR::raiseError(_("Could not bind to ldap server"));
        }

        return true;
    }

    /**
     * Close the ldap connection.
     */
    function _disconnect() {
        @ldap_close($this->_ds);
    }

/**
 * Check if the realm has a specific configuration.  If not, try to fall
 * back on the default configuration.  If still not a valid configuration
 * then exit with an error.
 *
 * @param string    $realm      The realm of the user, or "default" if none.
 *                              Note: passed by reference so we can change
 *                              it's value!
 *
 */

function check_config(&$realm) {

    // If no realm passed in, or no host config for the realm passed in,
    // then we fall back to the default realm

    if ( empty($realm) || empty($this->_params[$realm]['server']) ) {
       $realm = "default";
    }

    // If still no host/port, then we have a misconfigured module
    if (empty($this->_params[$realm]['host']) ||
        empty($this->_params[$realm]['port']) ) {
            $this->err_str = _("The module is not properly configured!");
            return false;
    }
    return true;
}

    /**
     * Lookup and return the user's dn.
     *
     * @param  $user     The username of the user.
     * @param  $realm    The realm (domain) name of the user.
     * @param  $basedn   The ldap basedn.
     * @param  $uid      The ldap uid.
     *
     * @return string    The ldap dn for the user.
     */
    function _lookupdn($user, $realm) {
        // bind as guest
        $this->_connect();

        // construct search
        $search = $this->_params[$realm]['uid'] . '=' . $user;
        if (!empty($this->_params[$realm]['realm'])) {
            $search .= '@' . $this->_params[$realm]['realm'];
        }

        // get userdn
        $result = ldap_search($this->_ds, $this->_params[$realm]['basedn'], $search);
        $entry = ldap_first_entry($this->_ds, $result);
        if ($entry === false) {
            $this->_disconnect();
            return PEAR::raiseError(_("User not found."));
        }
        $userdn = ldap_get_dn($this->_ds, $entry);

        // disconnect from ldap server
        $this->_disconnect();

        return $userdn;
    }

/**
 * Set the vacation notice up.
 * @param string    $user       The username to enable vacation for.
 * @param string    $realm      The realm of the user.
 * @param string    $target     The message to install.
 * @return boolean  Returns true on success, false on error.
 */

    function set_vacation($user, $realm, $pass, $message) {

        // Make sure the configuration file is correct
        if (!$this->check_config($realm)) {
            return false;
        }

        // get the user's dn
        if (array_key_exists('userdn', $this->_params[$realm])) {
            $userdn = $this->_params[$realm]['userdn'];
        } else {
            $userdn = $this->_lookupdn($user, $realm);
            if (PEAR::isError($userdn)) {
                return $userdn;
            }
        }

        // connect as the user
        $res = $this->_connect($userdn, $pass, $realm);
        if (PEAR::isError($res)) {
            $this->_disconnect();
            if ($res->getMessage() == _("Could not bind to ldap server")) {
                return PEAR::raiseError(_("Incorect Password"));
            }
            return $res;
        }

	// Prepare the message. \n->\n\n and UTF-8 encode.
	$message = ereg_replace("\r\n", "\\n", $message); 
	$message = mb_convert_encoding($message, "UTF-8", "ISO-8859-1");

	// change the user's vacation.
        $newDetails[$this->_params[$realm]['vacation']] = $message;
        $res = ldap_mod_replace($this->_ds, $userdn, $newDetails);
        $value = $this->_get_vacation($userdn, $this->_params[$realm]['vacation']);
        if (!$res) {
            $res = PEAR::raiseError(ldap_error($this->_ds));
        }

        // disconnect from ldap server
        $this->_disconnect();

        return true;
    }

  function get_vacation($realm = 'default', $user, $pass) {
        // Make sure the configuration file is correct
        if (!$this->check_config($realm)) {
            return false;
        }

        // get the user's dn
        if ( array_key_exists('userdn', $this->_params[$realm])) {
            $userdn = $this->_params[$realm]['userdn'];
        } else {
            $userdn = $this->_lookupdn($user, $realm);
            if (PEAR::isError($userdn)) {
                return $userdn;
            }
        }

        // connect as the user
        $res = $this->_connect($userdn, $pass, $realm);
        if (PEAR::isError($res)) {
            $this->_disconnect();
            if ($res->getMessage() == _("Could not bind to ldap server")) {
                return PEAR::raiseError(_("Incorect Password"));
            }
            return $res;
        }

	$vac = $this->_params[$realm]['vacation'];
	$msg = $this->_get_vacation($userdn, $vac);

        // disconnect from ldap server
        $this->_disconnect();

	// Prepare the message. \n->\n\n and UTF-8 encode.
	$msg = ereg_replace("\\\\n", "\r\n", $msg); 
	$msg = mb_convert_encoding($msg, "ISO-8859-1", "UTF-8");
	return $msg;
  }

  function _get_vacation($userdn, $vac) {
	$sr = ldap_search($this->_ds, $userdn, "$vac=*");
	$entry = ldap_first_entry($this->_ds, $sr);
	if (!$entry) {
	  return false;
        }
	$values = ldap_get_values($this->_ds, $entry, $vac);
	if ($values["count"] == 0) {
	   return false;
        }
	return $values[0];
  }

/**
 * Remove any existing vacation notices.
 *
 * @param string    $user       The user to disable vacation notices for.
 * @param string    $realm      The realm of the user.
 * @param string    $pass       The password of the user.
 *
 * @return boolean  Returns true on success, false on error.
 */

    function unset_vacation($user, $realm, $pass) {

        // Make sure the configuration file is correct
        if (!$this->check_config($realm)) {
            return false;
        }

        // get the user's dn
        if ( array_key_exists('userdn', $this->_params[$realm])) {
            $userdn = $this->_params[$realm]['userdn'];
        } else {
            $userdn = $this->_lookupdn($user, $realm);
            if (PEAR::isError($userdn)) {
                return $userdn;
            }
        }

        // connect as the user
        $res = $this->_connect($userdn, $pass, $realm);
        if (PEAR::isError($res)) {
            $this->_disconnect();
            if ($res->getMessage() == _("Could not bind to ldap server")) {
                return PEAR::raiseError(_("Incorect Password"));
            }
            return $res;
        }

	// del the user's vacation.
	$value = $this->_get_vacation($userdn,
				      $this->_params[$realm]['vacation']);
	$newDetails[$this->_params[$realm]['vacation']] = $value;
        $res = ldap_mod_del($this->_ds, $userdn, $newDetails);
        if (!$res) {
            $res = PEAR::raiseError(ldap_error($this->_ds));
        }

        // disconnect from ldap server
        $this->_disconnect();

        return true;
    }

}

?>
