/*
 * The Cryptonit security software suite is developped by IDEALX
 * Cryptonit Team (http://IDEALX.org/ and http://cryptonit.org).
 *
 * Copyright 2003-2006 IDEALX
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License version
 * 2 as published by the Free Software Foundation.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301, USA. 
 *
 * In addition, as two special exceptions:
 *
 * 1) IDEALX S.A.S gives permission to:
 *  * link the code of portions of his program with the OpenSSL library under
 *    certain conditions described in each source file
 *  * distribute linked combinations including the two, with respect to the
 *    OpenSSL license and with the GPL
 *
 * You must obey the GNU General Public License in all respects for all of the
 * code used other than OpenSSL. If you modify file(s) with this exception,
 * you may extend this exception to your version of the file(s), but you are
 * not obligated to do so. If you do not wish to do so, delete this exception
 * statement from your version, in all files (this very one along with all
 * source files).

 * 2) IDEALX S.A.S acknowledges that portions of his sourcecode uses (by the
 * way of headers inclusion) some work published by 'RSA Security Inc.'. Those
 * portions are "derived from the RSA Security Inc. PKCS #11Cryptographic
 * Token Interface (Cryptoki)" as described in each individual source file.
 */

#ifndef LDAPCache_hh
#define LDAPCache_hh

#include "DirectoryService.hh"

#define LDAP_DEPRECATED 1

#include <ldap.h>

#ifndef LDAP_DEFAULT_PORT
#define LDAP_DEFAULT_PORT 389
#endif

namespace Cryptonit
{

    /** LDAP caching backend.
     *  This backend reads the contents of a LDAP directory, with
     *  an optionnal filter, and stores all entries in memory for
     *  "offline" access.
     */
    class LDAPCache: public DirectoryService
    {
    private:

	/** Pointer on the current LDAP session.
	 *  This backend can handle only one connection
	 *  in the same time.
	 */
	LDAP* ldap_session;


	/** Timeout in seconds for asynchronous search.
	 */
	unsigned int timeout;


	/** Hostname of the current session.
	 */
	std::string current_host;


	/** Port number of the current session.
	 */
	unsigned int current_port;

        /** Retain LDAPv2 compatibility ?
        */
        int v2compatibility;

	/** Base of the current session.
	 */
	std::string current_base;


	/** Search filter of the current session.
	 */
	std::string current_filter;


	/** Requested attributes for this session.
	 * Mainly used with the URI constructor.
	 */
	std::vector<std::string> current_attributes;


	/** Scope type of the current session.
	 *  Values could be LDAP_SCOPE_BASE, LDAP_SCOPE_ONELEVEL
	 *  or LDAP_SCOPE_SUBTREE. For a description on the scope,
	 *  see the LDAP documentation.
	 */
	int current_scope;


	/** Current login used for connecting to the LDAP
	 */
	std::string current_login;


	/** Current password used for connecting to the LDAP
	 */
	std::string current_password;

      /**
       * Current value for LDAPv2 compatibility
       */
      bool current_v2compatibility;


	/** Initializes a new LDAP connection if 'ldap_session' is NULL
	 *  'ldap_session != NULL' is interpreted like an already in use connection
	 *  Returns a new LDAP connection or NULL if it was failed.
	 *
	 *  @param host : LDAP server hostname
	 *  @param port : LDAP server port number
	 *  @param v2compatibility : LDAP v2 compatibility
	 *  @param login : LDAP login
	 *  @param passwd : LDAP password
	 */
      LDAP* initLdapSession( const std::string host, int port, int v2compatibility, 
			       std::string login, std::string passwd );


	/** Adds all attributes of a specifief entry with their values into the hash table.
	 *
	 *  @param lp : pointer on a LDAP session
	 *  @param entry : the entry to be added
	 */
	bool addEntry( LDAP* ld, LDAPMessage *entry );

	
	/** Parses a given URI, in the format described in RFC2255.
	 *  @Notes: The parsing code is rudimentary.
	 *
	 *  @param uri : the URI to parse.
	 *  @param server : receives the server name
	 *  @param port : receives the port number
	 *  @param dn : receives the DN
	 *  @param scope : receives the scope search
	 *  @param filter : receives the filter search
	 *  @param port : receives the attribute list
	 */
	bool parseURI( const std::string uri, 
		       std::string& server, std::string& port,
		       std::string& dn, std::string& scope, std::string& filter, 
		       std::vector<std::string>& attributes );



    public:

	/** Instantiates a new LDAPCache backend, setting defaults values, like
	 *  the timeout to 20 seconds and the scope to LDAP_SCOPE_SUBTREE.
	 *  You need to establish the connection with the read() method.
	 */
	LDAPCache();


	/** Instantiates a new LDAPCache backend like the LDAPCache()
	 *  constructor, but with a given URI. The "ldapcache://" part is ignored if
	 *  presents.
	 *  For the LDAP URL reference, see RFC 2255.
	 *  @Notes: The parsing code is rudimentary.
	 *
	 *  @param uri : URI
	 */
	LDAPCache( const std::string uri );


	/** Reads the contents of a LDAP directory, and copy all
	 *  of its data into memory.
	 *
	 *  @param params[0] : LDAP server host name
	 *  @param params[1] : LDAP server port
	 *  @param params[2] : base for search (ex: "O=COMPANY,C=FR")
	 *  @param params[3] : search filter (ex: "cn=*")
	 *  @param params[4] : scope type, could be "LDAP_SCOPE_BASE", "LDAP_SCOPE_ONELEVEL"
	 *                     or "LDAP_SCOPE_SUBTREE", default is "LDAP_SCOPE_SUBTREE"
	 *  @param params[5..n] : optionnal attribute list for restricting storage
	 *  @param params[END] : the last unused argument must be set to the empty string: ""
	 *
	 * @Notes: the attribute restriction is not yet implemented.
	 */
	bool read( const std::string params[] );

    
	/** Returns the value of the current timeout in seconds.
	 */
	unsigned int getTimeout();


	/** Sets the value of the current timeout in seconds.
	 */
	void setTimeout( unsigned int t );


	/** Returns the current scope.
	 */
	int getScope();


	/** Sets the scope. For a description on the scope, see the LDAP documentation.
	 *  This constants are defined in the LDAP headers.
	 *  If an illegal value is passed, the current scope will be set to LDAP_SCOPE_SUBTREE.
	 *
	 *  @param s : the values could be LDAP_SCOPE_BASE, LDAP_SCOPE_ONELEVEL
	 *             or LDAP_SCOPE_SUBTREE
	 */
	void setScope( int s );


	/** Sets the scope. For a description on the scope, see the LDAP documentation.
	 *  If an illegal value is passed, the current scope will be set to LDAP_SCOPE_SUBTREE.
	 *
	 *  @param s : the values could one of these character string "LDAP_SCOPE_BASE",
	 *             "LDAP_SCOPE_ONELEVEL",  "LDAP_SCOPE_SUBTREE", "base", "one" or "sub"
	 */
	void setScope( const std::string s );

	
	/** Set the current login to login.
	 *  You need to call this method before read(), if you must
	 *  provide a login for connecting to the LDAP server.
	 */
	bool setLogin( const std::string login );


	/** Set the current password to passwd.
	 *  You need to call this method before read(), if you must
	 *  provide a password for connecting to the LDAP server.
	 */
	bool setPassword( const std::string passwd );

        bool retainV2(const int v2compatibility);

    };

} // Namespace
#endif
