diff --git a/cas_auth/Copy of start.php b/cas_auth/Copy of start.php
new file mode 100644
index 0000000000000000000000000000000000000000..61c7d68ca82604161f49c61cd66dac966b4ca1da
--- /dev/null
+++ b/cas_auth/Copy of start.php	
@@ -0,0 +1,368 @@
+<?php
+	/**
+	 * Elgg CAS authentication
+	 * 
+	 * @package cas_auth
+	 * @license http://www.gnu.org/licenses/gpl.html
+	 * @author Xavier Roussel <xavier.roussel@uvsq.fr>
+	 * @copyright UVSQ 2008
+	 * @link http://www.uvsq.fr
+	 */
+
+	// Include main cas lib
+	include_once 'cas/CAS.php';
+	$casInitialized = false;
+	
+	/**
+	 * CAS Authentication init
+	 * 
+	 */
+	function cas_auth_init()
+	{
+		// global config
+		global $CONFIG;
+		// plugin config
+		$config = find_plugin_settings('cas_auth');
+		// todo : send message to user
+		if (!$config) return false;
+
+		// CAS auth required
+		if ( $_REQUEST['loginwith'] == 'UNLlogin' && !isset($_REQUEST['ticket']) )
+		{	
+			createCas();
+		}
+		// CAS auth done
+		if ( $_REQUEST['loginwith'] == 'UNLlogin' && isset($_REQUEST['ticket']) )
+		{
+			// Check CAS auth the CAS way just in case
+			if ( checkCas() ) {
+				$_SESSION['loggedWithCAS'] = true;
+				$uname = getUserCas();
+				var_dump($uname);
+				if(ldapAuthenticate( getUserCas() )) {
+					system_message(elgg_echo('loginok'));
+				}
+				else register_error(elgg_echo('loginerror'));
+			}
+		}
+		// The CAS ticket is lost, log out
+		if ( $_SESSION['loggedWithCAS'] && !checkCas() ) {
+			$_SESSION['loggedWithCAS'] = false;
+			forward($CONFIG->url.'/action/logout');
+		}
+	}
+	
+	// Register the initialisation function
+	register_elgg_event_handler('init','system','cas_auth_init');
+	// Register CAS logout to main logout only if user logged with CAS
+	if ( $_SESSION['loggedWithCAS'] ) {
+		register_elgg_event_handler('logout', 'user', 'logoutCas');
+	}
+
+	/**
+	 * CAS client initialization
+	 * 
+	 */
+	function initCas() {
+		if (!$GLOBALS[casInitialized]) {
+			$config = find_plugin_settings('cas_auth');
+			phpCAS::client(CAS_VERSION_2_0, $config->casurl, (int) $config->casport , $config->casuri );
+			$GLOBALS[casInitialized] = true;
+		}	
+	}
+
+	/**
+	 * Force authentication
+	 * 
+	 */
+	function createCas() {
+		initCas();
+		phpCAS::forceAuthentication();
+	}
+
+	/**
+	 * Check auth
+	 * 
+	 * @return boolean
+	 */
+	function checkCas() {		
+		initCas();
+		if (phpCAS::checkAuthentication()) {
+			return true;
+		}
+		else return false;
+	}
+
+	/**
+	 * Get CAS user
+	 * 
+	 * @return string name of the user
+	 */
+	function getUserCas() {
+		return phpCAS::getUser();
+	}
+
+	/**
+	 * CAS logout
+	 * 
+	 */
+	function logoutCas() {
+		global $CONFIG;
+		initCas();
+		phpCAS::logout($CONFIG->url.'/action/logout');	
+	}
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	/**
+   * LDAP authentication
+   * 
+   * @param string $username Go around PAM handler credentials (CAS can't return a password)
+   * @return boolean
+   */
+	function ldapAuthenticate($username)
+	{
+		// Nothing to do if LDAP module not installed
+		if (!function_exists('ldap_connect')) {
+			return false;
+		}
+
+		// Get configuration settings
+		$config = find_plugin_settings('ldap_auth');
+
+		// Nothing to do if not configured
+		if (!$config)
+		{
+			return false;
+		}
+
+		if (empty($username)) {
+			return false;
+		}
+
+		// Perform the authentication
+		return ldapCheck($config, $username);
+	}
+   
+  /**
+   * Perform an LDAP authentication check
+   *
+   * @param ElggPlugin $config
+   * @param string $username
+   * @return boolean
+   */
+	function ldapCheck($config, $username)
+	{
+		$host = $config->hostname;
+
+		// No point continuing
+		if(empty($host))
+		{
+			error_log("LDAP error: no host configured.");
+			return;
+		}
+		$port        = $config->port;
+		$version     = $config->version;
+		$basedn      = $config->basedn;
+		$filter_attr = $config->filter_attr;
+		$search_attr = $config->search_attr;
+		$bind_dn     = $config->ldap_bind_dn;
+		$bind_pwd    = $config->ldap_bind_pwd;
+		$user_create = $config->user_create;
+		$start_tls   = $config->start_tls;
+
+		($user_create == 'on') ? $user_create = true : $user_create = false;
+		($start_tls == 'on') ? $start_tls = true : $start_tls = false;
+
+		$port        ? $port        : $port = 389;
+		$version     ? $version     : $version = 3;
+		$filter_attr ? $filter_attr : $filter_attr = 'uid';
+		$basedn      ? $basedn = array_map('trim', explode(':', $basedn)) : $basedn = array();
+
+		if (!empty($search_attr))
+		{
+			// $search_attr as in "email:email_address, name:name_name";
+
+			$pairs = array_map('trim',explode(',', $search_attr));
+
+			$values = array();
+
+			foreach ($pairs as $pair)
+			{
+				$parts = array_map('trim', explode(':', $pair));
+
+				$values[$parts[0]] = $parts[1];
+			}
+
+			$search_attr = $values;
+		}
+		else
+		{
+			$search_attr = array('dn' => 'dn');
+		}
+
+		// Create a connection
+		if ($ds = ldapConnect($host, $port, $version, $bind_dn, $bind_pwd))
+		{
+			if ($start_tls and !ldap_start_tls($ds)) return false;
+
+			// Perform a search
+			foreach ($basedn as $this_ldap_basedn)
+			{
+				$ldap_user_info = ldapDoAuth($ds, $this_ldap_basedn, $username, $filter_attr, $search_attr);
+
+				if($ldap_user_info)
+				{
+					// LDAP login successful
+					if ($user = get_user_by_username($username))
+					{
+						// User exists, login            	        
+						return login($user);
+					}
+					else
+					{
+						// Valid login but user doesn't exist
+						if ($user_create)
+						{
+							$name  = $ldap_user_info['firstname'];
+
+							if (isset($ldap_user_info['lastname']))
+							{
+								$name  = $name . " " . $ldap_user_info['lastname'];
+							}
+
+							($ldap_user_info['mail']) ? $email = $ldap_user_info['mail'] : $email = null;
+
+							if ($user_guid = register_user($username, 'generic', $name, $email))
+							{
+								// Success, credentials valid and account has been created                                
+								return login(get_user($user_guid));
+							}
+							else
+							{
+								register_error(elgg_echo('ldap_auth:no_register'));
+								return false;
+							}
+						}
+						else
+						{
+							register_error(elgg_echo("ldap_auth:no_account"));
+							return false;
+						}
+					}
+				}
+			}
+			// Close the connection
+			ldap_close($ds);
+			return false;
+		}
+		else
+		{
+			return false;
+		}
+	}
+    
+	/**
+	 * Create an LDAP connection
+	 *
+	 * @param string $host
+	 * @param int $port
+	 * @param int $version
+	 * @param string $bind_dn
+	 * @param string $bind_pwd
+	 * @return mixed LDAP link identifier on success, or false on error
+	 */
+	function ldapConnect($host, $port, $version, $bind_dn, $bind_pwd)
+	{
+		$ds = @ldap_connect($host, $port);
+
+		@ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, $version);
+		// Start the LDAP bind process
+		$ldapbind = null;
+
+		if ($ds)
+		{
+			if ($bind_dn != '')
+			{
+				$ldapbind = @ldap_bind($ds, $bind_dn, $bind_pwd);
+			}
+			else
+			{
+				// Anonymous bind
+				$ldapbind = @ldap_bind($ds);
+			}
+		}
+		else
+		{
+			// Unable to connect
+			error_log('Unable to connect to the LDAP server: '.ldap_error($ds));
+			return false;
+		}
+
+		if (!$ldapbind)
+		{
+			error_log('Unable to bind to the LDAP server with provided credentials: '.ldap_error($ds));
+			ldap_close($ds);
+			return false;
+		}
+		return $ds;
+	}
+
+	/**
+	 * Performs actual LDAP authentication
+	 *
+	 * @param object $ds LDAP link identifier
+	 * @param string $basedn
+	 * @param string $username
+	 * @param string $filter_attr
+	 * @param string $search_attr
+	 * @return mixed array with search attributes or false on error
+	 */
+	function ldapDoAuth($ds, $basedn, $username, $filter_attr, $search_attr)
+	{
+		$sr = @ldap_search($ds, $basedn, $filter_attr ."=". $username, array_values($search_attr));
+		if(!$sr)
+		{
+			error_log('Unable to perform LDAP search: '.ldap_error($ds));
+			return false;
+		}
+
+		$entry = ldap_get_entries($ds, $sr);
+		if(!$entry or !$entry[0])
+		{
+			return false; // didn't find username
+		}
+
+		// We have a bind, a valid login
+		foreach (array_keys($search_attr) as $attr)
+		{
+			$ldap_user_info[$attr] = $entry[0][$search_attr[$attr]][0];
+		}
+		return $ldap_user_info;
+	}
+?>
\ No newline at end of file
diff --git a/cas_auth/README.txt b/cas_auth/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..fbb1881b5cc28acedc01d056ce46a937969a9219
--- /dev/null
+++ b/cas_auth/README.txt
@@ -0,0 +1,20 @@
+Elgg is an open source social networking platform.
+
+CAS (Central Authentification Service) is an SSO.
+
+This project tries to allow CAS authentification in Elgg. The idea is to authenticate with CAS, then look up the user info in LDAP
+and authenticate the user in Elgg.
+
+This plugin has been widely built on the ldap_auth plugin from Misja Hoebe and is inspired from the CAS authentification used in 
+Claroline : www.claroline.net
+
+You can edit the config in the Tool administration section by providing CAS host, port and URI.
+
+--
+
+Xavier Roussel
+Responsable technique - TICE
+Direction des Systèmes d'Information - UVSQ
+xavier.roussel@uvsq.fr
+www.uvsq.fr
+www.tice.uvsq.fr
\ No newline at end of file
diff --git a/cas_auth/cas/CAS.php b/cas_auth/cas/CAS.php
new file mode 100644
index 0000000000000000000000000000000000000000..77457f95fbaba263ea41a184bb226b5e457476ea
--- /dev/null
+++ b/cas_auth/cas/CAS.php
@@ -0,0 +1,1225 @@
+<?php // $Id: CAS.php 9707 2007-12-12 13:46:31Z mlaurent $
+if ( count( get_included_files() ) == 1 ) die( '---' );
+
+error_reporting(E_ALL ^ E_NOTICE);
+
+//
+// hack by Vangelis Haniotakis to handle the absence of $_SERVER['REQUEST_URI'] in IIS
+//
+if (!$_SERVER['REQUEST_URI']) {
+     $_SERVER['REQUEST_URI'] = $_SERVER['SCRIPT_NAME'].'?'.$_SERVER['QUERY_STRING'];
+}
+
+//
+// another one by Vangelis Haniotakis also to make phpCAS work with PHP5
+//
+if (version_compare(PHP_VERSION,'5','>=')) {
+    require_once(dirname(__FILE__).'/domxml-php4-php5.php');
+}
+
+/**
+ * @file CAS/CAS.php
+ * Interface class of the phpCAS library
+ *
+ * @ingroup public
+ */
+
+// ########################################################################
+//  CONSTANTS
+// ########################################################################
+
+// ------------------------------------------------------------------------
+//  CAS VERSIONS
+// ------------------------------------------------------------------------
+
+/**
+ * phpCAS version. accessible for the user by phpCAS::getVersion().
+ */
+define('PHPCAS_VERSION','0.4.21-1');
+
+// ------------------------------------------------------------------------
+//  CAS VERSIONS
+// ------------------------------------------------------------------------
+/**
+ * @addtogroup public
+ * @{
+ */
+
+/**
+ * CAS version 1.0
+ */
+define("CAS_VERSION_1_0",'1.0');
+/*!
+ * CAS version 2.0
+ */
+define("CAS_VERSION_2_0",'2.0');
+
+/** @} */
+/**
+ * @addtogroup publicPGTStorage
+ * @{
+ */
+// ------------------------------------------------------------------------
+//  FILE PGT STORAGE
+// ------------------------------------------------------------------------
+/**
+ * Default path used when storing PGT's to file
+ */
+define("CAS_PGT_STORAGE_FILE_DEFAULT_PATH",'/tmp');
+/**
+ * phpCAS::setPGTStorageFile()'s 2nd parameter to write plain text files
+ */
+define("CAS_PGT_STORAGE_FILE_FORMAT_PLAIN",'plain');
+/**
+ * phpCAS::setPGTStorageFile()'s 2nd parameter to write xml files
+ */
+define("CAS_PGT_STORAGE_FILE_FORMAT_XML",'xml');
+/**
+ * Default format used when storing PGT's to file
+ */
+define("CAS_PGT_STORAGE_FILE_DEFAULT_FORMAT",CAS_PGT_STORAGE_FILE_FORMAT_PLAIN);
+// ------------------------------------------------------------------------
+//  DATABASE PGT STORAGE
+// ------------------------------------------------------------------------
+/**
+ * default database type when storing PGT's to database
+ */
+define("CAS_PGT_STORAGE_DB_DEFAULT_DATABASE_TYPE",'mysql');
+/**
+ * default host when storing PGT's to database
+ */
+define("CAS_PGT_STORAGE_DB_DEFAULT_HOSTNAME",'localhost');
+/**
+ * default port when storing PGT's to database
+ */
+define("CAS_PGT_STORAGE_DB_DEFAULT_PORT",'');
+/**
+ * default database when storing PGT's to database
+ */
+define("CAS_PGT_STORAGE_DB_DEFAULT_DATABASE",'phpCAS');
+/**
+ * default table when storing PGT's to database
+ */
+define("CAS_PGT_STORAGE_DB_DEFAULT_TABLE",'pgt');
+
+/** @} */
+// ------------------------------------------------------------------------
+// SERVICE ACCESS ERRORS
+// ------------------------------------------------------------------------
+/**
+ * @addtogroup publicServices
+ * @{
+ */
+
+/**
+ * phpCAS::service() error code on success
+ */
+define("PHPCAS_SERVICE_OK",0);
+/**
+ * phpCAS::service() error code when the PT could not retrieve because
+ * the CAS server did not respond.
+ */
+define("PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE",1);
+/**
+ * phpCAS::service() error code when the PT could not retrieve because
+ * the response of the CAS server was ill-formed.
+ */
+define("PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE",2);
+/**
+ * phpCAS::service() error code when the PT could not retrieve because
+ * the CAS server did not want to.
+ */
+define("PHPCAS_SERVICE_PT_FAILURE",3);
+/**
+ * phpCAS::service() error code when the service was not available.
+ */
+define("PHPCAS_SERVICE_NOT AVAILABLE",4);
+
+/** @} */
+// ------------------------------------------------------------------------
+//  LANGUAGES
+// ------------------------------------------------------------------------
+/**
+ * @addtogroup publicLang
+ * @{
+ */
+
+define("PHPCAS_LANG_ENGLISH",    'english');
+define("PHPCAS_LANG_FRENCH",     'french');
+define("PHPCAS_LANG_GREEK",      'greek');
+
+/** @} */
+
+/**
+ * @addtogroup internalLang
+ * @{
+ */
+
+/**
+ * phpCAS default language (when phpCAS::setLang() is not used)
+ */
+define("PHPCAS_LANG_DEFAULT", PHPCAS_LANG_ENGLISH);
+
+/** @} */
+// ------------------------------------------------------------------------
+//  MISC
+// ------------------------------------------------------------------------
+/**
+ * @addtogroup internalMisc
+ * @{
+ */
+
+/**
+ * This global variable is used by the interface class phpCAS.
+ *
+ * @hideinitializer
+ */
+$PHPCAS_CLIENT  = null;
+
+/**
+ * This global variable is used to store where the initializer is called from 
+ * (to print a comprehensive error in case of multiple calls).
+ *
+ * @hideinitializer
+ */
+$PHPCAS_INIT_CALL = array('done' => FALSE,
+			  'file' => '?',
+			  'line' => -1,
+			  'method' => '?');
+
+/**
+ * This global variable is used to store where the method checking
+ * the authentication is called from (to print comprehensive errors)
+ *
+ * @hideinitializer
+ */
+$PHPCAS_AUTH_CHECK_CALL = array('done' => FALSE,
+				'file' => '?',
+				'line' => -1,
+				'method' => '?',
+				'result' => FALSE);
+
+/**
+ * This global variable is used to store phpCAS debug mode.
+ *
+ * @hideinitializer
+ */
+$PHPCAS_DEBUG  = array('filename' => FALSE,
+		       'indent' => 0,
+		       'unique_id' => '');
+
+/** @} */
+
+// ########################################################################
+//  CLIENT CLASS
+// ########################################################################
+
+// include client class
+include_once(dirname(__FILE__).'/client.php');
+
+// ########################################################################
+//  INTERFACE CLASS
+// ########################################################################
+
+/**
+ * @class phpCAS
+ * The phpCAS class is a simple container for the phpCAS library. It provides CAS
+ * authentication for web applications written in PHP.
+ *
+ * @ingroup public
+ * @author Pascal Aubry <pascal.aubry at univ-rennes1.fr>
+ *
+ * \internal All its methods access the same object ($PHPCAS_CLIENT, declared 
+ * at the end of CAS/client.php).
+ */
+
+
+
+class phpCAS
+{
+
+  // ########################################################################
+  //  INITIALIZATION
+  // ########################################################################
+
+  /**
+   * @addtogroup publicInit
+   * @{
+   */
+
+  /**
+   * phpCAS client initializer.
+   * @note Only one of the phpCAS::client() and phpCAS::proxy functions should be
+   * called, only once, and before all other methods (except phpCAS::getVersion()
+   * and phpCAS::setDebug()).
+   *
+   * @param $server_version the version of the CAS server
+   * @param $server_hostname the hostname of the CAS server
+   * @param $server_port the port the CAS server is running on
+   * @param $server_uri the URI the CAS server is responding on
+   * @param $start_session Have phpCAS start PHP sessions (default true)
+   *
+   * @return a newly created CASClient object
+   */
+  function client($server_version,
+		  $server_hostname,
+		  $server_port,
+		  $server_uri,
+ 		  $start_session = true)
+    {
+      global $PHPCAS_CLIENT, $PHPCAS_INIT_CALL;
+
+      phpCAS::traceBegin();
+      if ( is_object($PHPCAS_CLIENT) ) {
+	phpCAS::error($PHPCAS_INIT_CALL['method'].'() has already been called (at '.$PHPCAS_INIT_CALL['file'].':'.$PHPCAS_INIT_CALL['line'].')');
+      }
+      if ( gettype($server_version) != 'string' ) {
+	phpCAS::error('type mismatched for parameter $server_version (should be `string\')');
+      }
+      if ( gettype($server_hostname) != 'string' ) {
+	phpCAS::error('type mismatched for parameter $server_hostname (should be `string\')');
+      }
+      if ( gettype($server_port) != 'integer' ) {
+	phpCAS::error('type mismatched for parameter $server_port (should be `integer\')');
+      }
+      if ( gettype($server_uri) != 'string' ) {
+	phpCAS::error('type mismatched for parameter $server_uri (should be `string\')');
+      }
+
+      // store where the initialzer is called from
+      $dbg = phpCAS::backtrace();
+      $PHPCAS_INIT_CALL = array('done' => TRUE,
+				'file' => $dbg[0]['file'],
+				'line' => $dbg[0]['line'],
+				'method' => __CLASS__.'::'.__FUNCTION__);
+
+      // initialize the global object $PHPCAS_CLIENT
+      $PHPCAS_CLIENT = new CASClient($server_version,FALSE/*proxy*/,$server_hostname,$server_port,$server_uri,$start_session);
+      phpCAS::traceEnd();
+    }
+
+  /**
+   * phpCAS proxy initializer.
+   * @note Only one of the phpCAS::client() and phpCAS::proxy functions should be
+   * called, only once, and before all other methods (except phpCAS::getVersion()
+   * and phpCAS::setDebug()).
+   *
+   * @param $server_version the version of the CAS server
+   * @param $server_hostname the hostname of the CAS server
+   * @param $server_port the port the CAS server is running on
+   * @param $server_uri the URI the CAS server is responding on
+   * @param $start_session Have phpCAS start PHP sessions (default true)
+   *
+   * @return a newly created CASClient object
+   */
+  function proxy($server_version,
+		 $server_hostname,
+		 $server_port,
+		 $server_uri,
+ 		 $start_session = true)
+    {
+      global $PHPCAS_CLIENT, $PHPCAS_INIT_CALL;
+
+      phpCAS::traceBegin();
+      if ( is_object($PHPCAS_CLIENT) ) {
+	phpCAS::error($PHPCAS_INIT_CALL['method'].'() has already been called (at '.$PHPCAS_INIT_CALL['file'].':'.$PHPCAS_INIT_CALL['line'].')');
+      }
+      if ( gettype($server_version) != 'string' ) {
+	phpCAS::error('type mismatched for parameter $server_version (should be `string\')');
+      }
+      if ( gettype($server_hostname) != 'string' ) {
+	phpCAS::error('type mismatched for parameter $server_hostname (should be `string\')');
+      }
+      if ( gettype($server_port) != 'integer' ) {
+	phpCAS::error('type mismatched for parameter $server_port (should be `integer\')');
+      }
+      if ( gettype($server_uri) != 'string' ) {
+	phpCAS::error('type mismatched for parameter $server_uri (should be `string\')');
+      }
+
+      // store where the initialzer is called from
+      $dbg = phpCAS::backtrace();
+      $PHPCAS_INIT_CALL = array('done' => TRUE,
+				'file' => $dbg[0]['file'],
+				'line' => $dbg[0]['line'],
+				'method' => __CLASS__.'::'.__FUNCTION__);
+
+      // initialize the global object $PHPCAS_CLIENT
+      $PHPCAS_CLIENT = new CASClient($server_version,TRUE/*proxy*/,$server_hostname,$server_port,$server_uri,$start_session);
+      phpCAS::traceEnd();
+    }
+
+  /** @} */
+  // ########################################################################
+  //  DEBUGGING
+  // ########################################################################
+
+  /**
+   * @addtogroup publicDebug
+   * @{
+   */
+
+  /**
+   * Set/unset debug mode
+   *
+   * @param $filename the name of the file used for logging, or FALSE to stop debugging.
+   */
+  function setDebug($filename='')
+    {
+      global $PHPCAS_DEBUG;
+
+      if ( $filename != FALSE && gettype($filename) != 'string' ) {
+	phpCAS::error('type mismatched for parameter $dbg (should be FALSE or the name of the log file)');
+      }
+
+      if ( empty($filename) ) {
+      	if ( preg_match('/^Win.*/',getenv('OS')) ) {
+      	  if ( isset($_ENV['TMP']) ) {
+      	    $debugDir = $_ENV['TMP'].'/';
+      	  } else if ( isset($_ENV['TEMP']) ) {
+      	    $debugDir = $_ENV['TEMP'].'/';
+      	  } else {
+      	    $debugDir = '';
+      	  }
+      	} else {
+      	  $debugDir = '/tmp/';
+      	}
+      	$filename = $debugDir . 'phpCAS.log';
+      }
+
+      if ( empty($PHPCAS_DEBUG['unique_id']) ) {
+	$PHPCAS_DEBUG['unique_id'] = substr(strtoupper(md5(uniqid(''))),0,4);
+      }
+
+      $PHPCAS_DEBUG['filename'] = $filename;
+
+      phpCAS::trace('START ******************');
+    }
+  
+  /** @} */
+  /**
+   * @addtogroup internalDebug
+   * @{
+   */
+
+  /**
+   * This method is a wrapper for debug_backtrace() that is not available 
+   * in all PHP versions (>= 4.3.0 only)
+   */
+  function backtrace()
+    {
+      if ( function_exists('debug_backtrace') ) {
+        return debug_backtrace();
+      } else {
+        // poor man's hack ... but it does work ...
+        return array();
+      }
+    }
+
+  /**
+   * Logs a string in debug mode.
+   *
+   * @param $str the string to write
+   *
+   * @private
+   */
+  function log($str)
+    {
+      $indent_str = ".";
+      global $PHPCAS_DEBUG;
+
+      if ( $PHPCAS_DEBUG['filename'] ) {
+	for ($i=0;$i<$PHPCAS_DEBUG['indent'];$i++) {
+	  $indent_str .= '|    ';
+	}
+	error_log($PHPCAS_DEBUG['unique_id'].' '.$indent_str.$str."\n",3,$PHPCAS_DEBUG['filename']);
+      }
+
+    }
+  
+  /**
+   * This method is used by interface methods to print an error and where the function
+   * was originally called from.
+   *
+   * @param $msg the message to print
+   *
+   * @private
+   */
+  function error($msg)
+    {
+      $dbg = phpCAS::backtrace();
+      $function = '?';
+      $file = '?';
+      $line = '?';
+      if ( is_array($dbg) ) {
+	for ( $i=1; $i<sizeof($dbg); $i++) {
+	  if ( is_array($dbg[$i]) ) {
+	    if ( $dbg[$i]['class'] == __CLASS__ ) {
+	      $function = $dbg[$i]['function'];
+	      $file = $dbg[$i]['file'];
+	      $line = $dbg[$i]['line'];
+	    }
+	  }
+	}
+      }
+      echo "<br />\n<b>phpCAS error</b>: <font color=\"FF0000\"><b>".__CLASS__."::".$function.'(): '.htmlentities($msg)."</b></font> in <b>".$file."</b> on line <b>".$line."</b><br />\n";
+      phpCAS::trace($msg);
+      phpCAS::traceExit();
+      exit();
+    }
+
+  /**
+   * This method is used to log something in debug mode.
+   */
+  function trace($str)
+    {
+      $dbg = phpCAS::backtrace();
+      phpCAS::log($str.' ['.basename($dbg[1]['file']).':'.$dbg[1]['line'].']');
+    }
+
+  /**
+   * This method is used to indicate the start of the execution of a function in debug mode.
+   */
+  function traceBegin()
+    {
+      global $PHPCAS_DEBUG;
+
+      $dbg = phpCAS::backtrace();
+      $str = '=> ';
+      if ( !empty($dbg[2]['class']) ) {
+	$str .= $dbg[2]['class'].'::';
+      }
+      $str .= $dbg[2]['function'].'(';      
+      if ( is_array($dbg[2]['args']) ) {
+	foreach ($dbg[2]['args'] as $index => $arg) {
+	  if ( $index != 0 ) {
+	    $str .= ', ';
+	  }
+	  $str .= str_replace("\n","",var_export($arg,TRUE));
+	}
+      }
+      $str .= ') ['.basename($dbg[2]['file']).':'.$dbg[2]['line'].']';
+      phpCAS::log($str);
+      $PHPCAS_DEBUG['indent'] ++;
+    }
+
+  /**
+   * This method is used to indicate the end of the execution of a function in debug mode.
+   *
+   * @param $res the result of the function
+   */
+  function traceEnd($res='')
+    {
+      global $PHPCAS_DEBUG;
+
+      $PHPCAS_DEBUG['indent'] --;
+      $dbg = phpCAS::backtrace();
+      $str = '';
+      $str .= '<= '.str_replace("\n","",var_export($res,TRUE));
+      phpCAS::log($str);
+    }
+
+  /**
+   * This method is used to indicate the end of the execution of the program
+   */
+  function traceExit()
+    {
+      global $PHPCAS_DEBUG;
+
+      phpCAS::log('exit()');
+      while ( $PHPCAS_DEBUG['indent'] > 0 ) {
+	phpCAS::log('-');
+	$PHPCAS_DEBUG['indent'] --;
+      }
+    }
+
+  /** @} */
+  // ########################################################################
+  //  INTERNATIONALIZATION
+  // ########################################################################
+  /**
+   * @addtogroup publicLang
+   * @{
+   */
+
+  /**
+   * This method is used to set the language used by phpCAS. 
+   * @note Can be called only once.
+   *
+   * @param $lang a string representing the language.
+   *
+   * @sa PHPCAS_LANG_FRENCH, PHPCAS_LANG_ENGLISH
+   */
+  function setLang($lang)
+    {
+      global $PHPCAS_CLIENT;
+      if ( !is_object($PHPCAS_CLIENT) ) {
+	phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()');
+      }
+      if ( gettype($lang) != 'string' ) {
+	phpCAS::error('type mismatched for parameter $lang (should be `string\')');
+      }
+      $PHPCAS_CLIENT->setLang($lang);
+    }
+
+  /** @} */
+  // ########################################################################
+  //  VERSION
+  // ########################################################################
+  /**
+   * @addtogroup public
+   * @{
+   */
+
+  /**
+   * This method returns the phpCAS version.
+   *
+   * @return the phpCAS version.
+   */
+  function getVersion()
+    {
+      return PHPCAS_VERSION;
+    }
+  
+  /** @} */
+  // ########################################################################
+  //  HTML OUTPUT
+  // ########################################################################
+  /**
+   * @addtogroup publicOutput
+   * @{
+   */
+
+  /**
+   * This method sets the HTML header used for all outputs.
+   *
+   * @param $header the HTML header.
+   */
+  function setHTMLHeader($header)
+    {
+      global $PHPCAS_CLIENT;
+      if ( !is_object($PHPCAS_CLIENT) ) {
+	phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()');
+      }
+      if ( gettype($header) != 'string' ) {
+	phpCAS::error('type mismatched for parameter $header (should be `string\')');
+      }
+      $PHPCAS_CLIENT->setHTMLHeader($header);
+    }
+
+  /**
+   * This method sets the HTML footer used for all outputs.
+   *
+   * @param $footer the HTML footer.
+   */
+  function setHTMLFooter($footer)
+    {
+      global $PHPCAS_CLIENT;
+      if ( !is_object($PHPCAS_CLIENT) ) {
+	phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()');
+      }
+      if ( gettype($footer) != 'string' ) {
+	phpCAS::error('type mismatched for parameter $footer (should be `string\')');
+      }
+      $PHPCAS_CLIENT->setHTMLHeader($header);
+    }
+
+  /** @} */
+  // ########################################################################
+  //  PGT STORAGE
+  // ########################################################################
+  /**
+   * @addtogroup publicPGTStorage
+   * @{
+   */
+
+  /**
+   * This method is used to tell phpCAS to store the response of the
+   * CAS server to PGT requests onto the filesystem. 
+   *
+   * @param $format the format used to store the PGT's (`plain' and `xml' allowed)
+   * @param $path the path where the PGT's should be stored
+   */
+  function setPGTStorageFile($format='',
+			     $path='')
+    {
+      global $PHPCAS_CLIENT,$PHPCAS_AUTH_CHECK_CALL;
+
+      phpCAS::traceBegin();
+      if ( !is_object($PHPCAS_CLIENT) ) {
+	phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()');
+      }
+      if ( !$PHPCAS_CLIENT->isProxy() ) {
+	phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()');
+      }
+      if ( $PHPCAS_AUTH_CHECK_CALL['done'] ) {
+	phpCAS::error('this method should only be called before '.$PHPCAS_AUTH_CHECK_CALL['method'].'() (called at '.$PHPCAS_AUTH_CHECK_CALL['file'].':'.$PHPCAS_AUTH_CHECK_CALL['line'].')');
+      }
+      if ( gettype($format) != 'string' ) {
+	phpCAS::error('type mismatched for parameter $format (should be `string\')');
+      }
+      if ( gettype($path) != 'string' ) {
+	phpCAS::error('type mismatched for parameter $format (should be `string\')');
+      }
+      $PHPCAS_CLIENT->setPGTStorageFile($format,$path);
+      phpCAS::traceEnd();
+    }
+  
+  /**
+   * This method is used to tell phpCAS to store the response of the
+   * CAS server to PGT requests into a database. 
+   * @note The connection to the database is done only when needed. 
+   * As a consequence, bad parameters are detected only when 
+   * initializing PGT storage, except in debug mode.
+   *
+   * @param $user the user to access the data with
+   * @param $password the user's password
+   * @param $database_type the type of the database hosting the data
+   * @param $hostname the server hosting the database
+   * @param $port the port the server is listening on
+   * @param $database the name of the database
+   * @param $table the name of the table storing the data
+   */
+  function setPGTStorageDB($user,
+			   $password,
+			   $database_type='',
+			   $hostname='',
+			   $port=0,
+			   $database='',
+			   $table='')
+    {
+      global $PHPCAS_CLIENT,$PHPCAS_AUTH_CHECK_CALL;
+
+      phpCAS::traceBegin();
+      if ( !is_object($PHPCAS_CLIENT) ) {
+	phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()');
+      }
+      if ( !$PHPCAS_CLIENT->isProxy() ) {
+	phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()');
+      }
+      if ( $PHPCAS_AUTH_CHECK_CALL['done'] ) {
+	phpCAS::error('this method should only be called before '.$PHPCAS_AUTH_CHECK_CALL['method'].'() (called at '.$PHPCAS_AUTH_CHECK_CALL['file'].':'.$PHPCAS_AUTH_CHECK_CALL['line'].')');
+      }
+      if ( gettype($user) != 'string' ) {
+	phpCAS::error('type mismatched for parameter $user (should be `string\')');
+      }
+      if ( gettype($password) != 'string' ) {
+	phpCAS::error('type mismatched for parameter $password (should be `string\')');
+      }
+      if ( gettype($database_type) != 'string' ) {
+	phpCAS::error('type mismatched for parameter $database_type (should be `string\')');
+      }
+      if ( gettype($hostname) != 'string' ) {
+	phpCAS::error('type mismatched for parameter $hostname (should be `string\')');
+      }
+      if ( gettype($port) != 'integer' ) {
+	phpCAS::error('type mismatched for parameter $port (should be `integer\')');
+      }
+      if ( gettype($database) != 'string' ) {
+	phpCAS::error('type mismatched for parameter $database (should be `string\')');
+      }
+      if ( gettype($table) != 'string' ) {
+	phpCAS::error('type mismatched for parameter $table (should be `string\')');
+      }
+      $PHPCAS_CLIENT->setPGTStorageDB($this,$user,$password,$hostname,$port,$database,$table);
+      phpCAS::traceEnd();
+    }
+  
+  /** @} */
+  // ########################################################################
+  // ACCESS TO EXTERNAL SERVICES
+  // ########################################################################
+  /**
+   * @addtogroup publicServices
+   * @{
+   */
+
+  /**
+   * This method is used to access an HTTP[S] service.
+   * 
+   * @param $url the service to access.
+   * @param $err_code an error code Possible values are PHPCAS_SERVICE_OK (on
+   * success), PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE, PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE,
+   * PHPCAS_SERVICE_PT_FAILURE, PHPCAS_SERVICE_NOT AVAILABLE.
+   * @param $output the output of the service (also used to give an error
+   * message on failure).
+   *
+   * @return TRUE on success, FALSE otherwise (in this later case, $err_code
+   * gives the reason why it failed and $output contains an error message).
+   */
+  function serviceWeb($url,&$err_code,&$output)
+    {
+      global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL;
+
+      phpCAS::traceBegin();
+      if ( !is_object($PHPCAS_CLIENT) ) {
+	phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()');
+      }
+      if ( !$PHPCAS_CLIENT->isProxy() ) {
+	phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()');
+      }
+      if ( !$PHPCAS_AUTH_CHECK_CALL['done'] ) {
+	phpCAS::error('this method should only be called after the programmer is sure the user has been authenticated (by calling '.__CLASS__.'::checkAuthentication() or '.__CLASS__.'::forceAuthentication()');
+      }
+      if ( !$PHPCAS_AUTH_CHECK_CALL['result'] ) {
+	phpCAS::error('authentication was checked (by '.$PHPCAS_AUTH_CHECK_CALL['method'].'() at '.$PHPCAS_AUTH_CHECK_CALL['file'].':'.$PHPCAS_AUTH_CHECK_CALL['line'].') but the method returned FALSE');
+      }
+      if ( gettype($url) != 'string' ) {
+	phpCAS::error('type mismatched for parameter $url (should be `string\')');
+      }
+      
+      $res = $PHPCAS_CLIENT->serviceWeb($url,$err_code,$output);
+
+      phpCAS::traceEnd($res);
+      return $res;
+    }
+
+  /**
+   * This method is used to access an IMAP/POP3/NNTP service.
+   * 
+   * @param $url a string giving the URL of the service, including the mailing box
+   * for IMAP URLs, as accepted by imap_open().
+   * @param $flags options given to imap_open().
+   * @param $err_code an error code Possible values are PHPCAS_SERVICE_OK (on
+   * success), PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE, PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE,
+   * PHPCAS_SERVICE_PT_FAILURE, PHPCAS_SERVICE_NOT AVAILABLE.
+   * @param $err_msg an error message on failure
+   * @param $pt the Proxy Ticket (PT) retrieved from the CAS server to access the URL
+   * on success, FALSE on error).
+   *
+   * @return an IMAP stream on success, FALSE otherwise (in this later case, $err_code
+   * gives the reason why it failed and $err_msg contains an error message).
+   */
+  function serviceMail($url,$flags,&$err_code,&$err_msg,&$pt)
+    {
+      global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL;
+
+      phpCAS::traceBegin();
+      if ( !is_object($PHPCAS_CLIENT) ) {
+	phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()');
+      }
+      if ( !$PHPCAS_CLIENT->isProxy() ) {
+	phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()');
+      }
+      if ( !$PHPCAS_AUTH_CHECK_CALL['done'] ) {
+	phpCAS::error('this method should only be called after the programmer is sure the user has been authenticated (by calling '.__CLASS__.'::checkAuthentication() or '.__CLASS__.'::forceAuthentication()');
+      }
+      if ( !$PHPCAS_AUTH_CHECK_CALL['result'] ) {
+	phpCAS::error('authentication was checked (by '.$PHPCAS_AUTH_CHECK_CALL['method'].'() at '.$PHPCAS_AUTH_CHECK_CALL['file'].':'.$PHPCAS_AUTH_CHECK_CALL['line'].') but the method returned FALSE');
+      }
+      if ( gettype($url) != 'string' ) {
+	phpCAS::error('type mismatched for parameter $url (should be `string\')');
+      }
+      
+      if ( gettype($flags) != 'integer' ) {
+	phpCAS::error('type mismatched for parameter $flags (should be `integer\')');
+      }
+      
+      $res = $PHPCAS_CLIENT->serviceMail($url,$flags,$err_code,$err_msg,$pt);
+
+      phpCAS::traceEnd($res);
+      return $res;
+    }
+
+  /** @} */
+  // ########################################################################
+  //  AUTHENTICATION
+  // ########################################################################
+  /**
+   * @addtogroup publicAuth
+   * @{
+   */
+
+  /**
+   * This method is called to check if the user is authenticated (use the gateway feature).
+   * @return TRUE when the user is authenticated; otherwise FALSE.
+   */
+  function checkAuthentication()
+    {
+      global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL;
+
+      phpCAS::traceBegin();
+      if ( !is_object($PHPCAS_CLIENT) ) {
+        phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()');
+      }
+
+      $auth = $PHPCAS_CLIENT->checkAuthentication();
+
+      // store where the authentication has been checked and the result
+      $dbg = phpCAS::backtrace();
+      $PHPCAS_AUTH_CHECK_CALL = array('done' => TRUE,
+				      'file' => $dbg[0]['file'],
+				      'line' => $dbg[0]['line'],
+				      'method' => __CLASS__.'::'.__FUNCTION__,
+				      'result' => $auth );
+      phpCAS::traceEnd($auth);
+      return $auth; 
+    }
+  
+  /**
+   * This method is called to force authentication if the user was not already 
+   * authenticated. If the user is not authenticated, halt by redirecting to 
+   * the CAS server.
+   */
+  function forceAuthentication()
+    {
+      global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL;
+
+      phpCAS::traceBegin();
+      if ( !is_object($PHPCAS_CLIENT) ) {
+        phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()');
+      }
+      
+      $auth = $PHPCAS_CLIENT->forceAuthentication();
+
+      // store where the authentication has been checked and the result
+      $dbg = phpCAS::backtrace();
+      $PHPCAS_AUTH_CHECK_CALL = array('done' => TRUE,
+				      'file' => $dbg[0]['file'],
+				      'line' => $dbg[0]['line'],
+				      'method' => __CLASS__.'::'.__FUNCTION__,
+				      'result' => $auth );
+
+      if ( !$auth ) {
+        phpCAS::trace('user is not authenticated, redirecting to the CAS server');
+        $PHPCAS_CLIENT->forceAuthentication();
+      } else {
+        phpCAS::trace('no need to authenticate (user `'.phpCAS::getUser().'\' is already authenticated)');
+      }
+
+      phpCAS::traceEnd();
+    }
+  
+  /**
+   * This method has been left from version 0.4.1 for compatibility reasons.
+   */
+  function authenticate()
+    {
+      phpCAS::error('this method is deprecated. You should use '.__CLASS__.'::forceAuthentication() instead');
+    }
+  
+  /**
+   * This method has been left from version 0.4.19 for compatibility reasons.
+   */
+  function isAuthenticated()
+    {
+      phpCAS::error('this method is deprecated. You should use '.__CLASS__.'::forceAuthentication() instead');
+    }
+  
+  /**
+   * This method returns the CAS user's login name.
+   * @warning should not be called only after phpCAS::forceAuthentication()
+   * or phpCAS::checkAuthentication().
+   *
+   * @return the login name of the authenticated user
+   */
+  function getUser()
+    {
+      global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL;
+      if ( !is_object($PHPCAS_CLIENT) ) {
+	phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()');
+      }
+      if ( !$PHPCAS_AUTH_CHECK_CALL['done'] ) {
+	phpCAS::error('this method should only be called after '.__CLASS__.'::forceAuthentication() or '.__CLASS__.'::isAuthenticated()');
+      }
+      if ( !$PHPCAS_AUTH_CHECK_CALL['result'] ) {
+	phpCAS::error('authentication was checked (by '.$PHPCAS_AUTH_CHECK_CALL['method'].'() at '.$PHPCAS_AUTH_CHECK_CALL['file'].':'.$PHPCAS_AUTH_CHECK_CALL['line'].') but the method returned FALSE');
+      }
+      return $PHPCAS_CLIENT->getUser();
+    }
+
+  /**
+   * This method returns the URL to be used to login.
+   * or phpCAS::isAuthenticated().
+   *
+   * @return the login name of the authenticated user
+   */
+  function getServerLoginURL()
+    {
+      global $PHPCAS_CLIENT;
+      if ( !is_object($PHPCAS_CLIENT) ) {
+	phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()');
+      }
+      return $PHPCAS_CLIENT->getServerLoginURL();
+    }
+
+  /**
+   * Set the login URL of the CAS server.
+   * @param $url the login URL
+   * @since 0.4.21 by Wyman Chan
+   */
+  function setServerLoginURL($url='')
+   {
+     global $PHPCAS_CLIENT;
+     phpCAS::traceBegin();
+     if ( !is_object($PHPCAS_CLIENT) ) {
+        phpCAS::error('this method should only be called after
+'.__CLASS__.'::client()');
+     }
+     if ( gettype($url) != 'string' ) {
+        phpCAS::error('type mismatched for parameter $url (should be
+`string\')');
+     }
+     $PHPCAS_CLIENT->setServerLoginURL($url);
+     phpCAS::traceEnd();
+   }
+
+  /**
+   * This method returns the URL to be used to login.
+   * or phpCAS::isAuthenticated().
+   *
+   * @return the login name of the authenticated user
+   */
+  function getServerLogoutURL()
+    {
+      global $PHPCAS_CLIENT;
+      if ( !is_object($PHPCAS_CLIENT) ) {
+	phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()');
+      }
+      return $PHPCAS_CLIENT->getServerLogoutURL();
+    }
+
+  /**
+   * Set the logout URL of the CAS server.
+   * @param $url the logout URL
+   * @since 0.4.21 by Wyman Chan
+   */
+  function setServerLogoutURL($url='')
+   {
+     global $PHPCAS_CLIENT;
+     phpCAS::traceBegin();
+     if ( !is_object($PHPCAS_CLIENT) ) {
+        phpCAS::error('this method should only be called after
+'.__CLASS__.'::client()');
+     }
+     if ( gettype($url) != 'string' ) {
+        phpCAS::error('type mismatched for parameter $url (should be
+`string\')');
+     }
+     $PHPCAS_CLIENT->setServerLogoutURL($url);
+     phpCAS::traceEnd();
+   }
+
+  /**
+   * This method is used to logout from CAS. Halts by redirecting to the CAS server.
+   * @param $url a URL that will be transmitted to the CAS server (to come back to when logged out)
+   */
+  function logout($url = "")
+    {
+      global $PHPCAS_CLIENT;
+
+      phpCAS::traceBegin();
+      if ( !is_object($PHPCAS_CLIENT) ) {
+	phpCAS::error('this method should only be called after '.__CLASS__.'::client() or'.__CLASS__.'::proxy()');
+      }
+      $PHPCAS_CLIENT->logout($url);
+      // never reached
+      phpCAS::traceEnd();
+    }
+
+  /**
+   * Set the fixed URL that will be used by the CAS server to transmit the PGT.
+   * When this method is not called, a phpCAS script uses its own URL for the callback.
+   *
+   * @param $url the URL
+   */
+  function setFixedCallbackURL($url='')
+   {
+     global $PHPCAS_CLIENT;
+     phpCAS::traceBegin();
+     if ( !is_object($PHPCAS_CLIENT) ) {
+        phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()');
+     }
+     if ( !$PHPCAS_CLIENT->isProxy() ) {
+        phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()');
+     }
+     if ( gettype($url) != 'string' ) {
+        phpCAS::error('type mismatched for parameter $url (should be `string\')');
+     }
+     $PHPCAS_CLIENT->setCallbackURL($url);
+     phpCAS::traceEnd();
+   }
+   
+  /**
+   * Set the fixed URL that will be set as the CAS service parameter. When this
+   * method is not called, a phpCAS script uses its own URL.
+   *
+   * @param $url the URL
+   */
+   function setFixedServiceURL($url)
+   {
+     global $PHPCAS_CLIENT;
+     phpCAS::traceBegin();
+     if ( !is_object($PHPCAS_CLIENT) ) {
+         phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()');
+     }  
+     if ( gettype($url) != 'string' ) {
+        phpCAS::error('type mismatched for parameter $url (should be `string\')');
+     }
+     $PHPCAS_CLIENT->setURL($url);
+     phpCAS::traceEnd();
+   }
+
+  /**
+   * Get the URL that is set as the CAS service parameter.
+   */
+   function getServiceURL()
+   {
+     global $PHPCAS_CLIENT;
+     if ( !is_object($PHPCAS_CLIENT) ) {
+        phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()');
+     }  
+     return($PHPCAS_CLIENT->getURL());
+   }
+
+  /**
+   * Retrieve a Proxy Ticket from the CAS server.
+   */
+   function retrievePT($target_service,&$err_code,&$err_msg)
+   {
+     global $PHPCAS_CLIENT;
+     if ( !is_object($PHPCAS_CLIENT) ) {
+        phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()');
+     }  
+     if ( gettype($target_service) != 'string' ) {
+        phpCAS::error('type mismatched for parameter $target_service(should be `string\')');
+     }
+     return($PHPCAS_CLIENT->retrievePT($target_service,$err_code,$err_msg));
+   }
+  /** @} */
+
+}
+
+// ########################################################################
+// DOCUMENTATION
+// ########################################################################
+
+// ########################################################################
+//  MAIN PAGE
+
+/**
+ * @mainpage
+ *
+ * The following pages only show the source documentation.
+ *
+ * For more information on phpCAS, please refer to http://esup-phpcas.sourceforge.net
+ *
+ */
+
+// ########################################################################
+//  MODULES DEFINITION
+
+/** @defgroup public User interface */
+
+/** @defgroup publicInit Initialization
+ *  @ingroup public */
+
+/** @defgroup publicAuth Authentication
+ *  @ingroup public */
+
+/** @defgroup publicServices Access to external services
+ *  @ingroup public */
+
+/** @defgroup publicConfig Configuration
+ *  @ingroup public */
+
+/** @defgroup publicLang Internationalization
+ *  @ingroup publicConfig */
+
+/** @defgroup publicOutput HTML output
+ *  @ingroup publicConfig */
+
+/** @defgroup publicPGTStorage PGT storage
+ *  @ingroup publicConfig */
+
+/** @defgroup publicDebug Debugging
+ *  @ingroup public */
+
+
+/** @defgroup internal Implementation */
+
+/** @defgroup internalAuthentication Authentication
+ *  @ingroup internal */
+
+/** @defgroup internalBasic CAS Basic client features (CAS 1.0, Service Tickets)
+ *  @ingroup internal */
+
+/** @defgroup internalProxy CAS Proxy features (CAS 2.0, Proxy Granting Tickets)
+ *  @ingroup internal */
+
+/** @defgroup internalPGTStorage PGT storage
+ *  @ingroup internalProxy */
+
+/** @defgroup internalPGTStorageDB PGT storage in a database
+ *  @ingroup internalPGTStorage */
+
+/** @defgroup internalPGTStorageFile PGT storage on the filesystem
+ *  @ingroup internalPGTStorage */
+
+/** @defgroup internalCallback Callback from the CAS server
+ *  @ingroup internalProxy */
+
+/** @defgroup internalProxied CAS proxied client features (CAS 2.0, Proxy Tickets)
+ *  @ingroup internal */
+
+/** @defgroup internalConfig Configuration
+ *  @ingroup internal */
+
+/** @defgroup internalOutput HTML output
+ *  @ingroup internalConfig */
+
+/** @defgroup internalLang Internationalization
+ *  @ingroup internalConfig
+ *
+ * To add a new language:
+ * - 1. define a new constant PHPCAS_LANG_XXXXXX in CAS/CAS.php
+ * - 2. copy any file from CAS/languages to CAS/languages/XXXXXX.php
+ * - 3. Make the translations
+ */
+
+/** @defgroup internalDebug Debugging
+ *  @ingroup internal */
+
+/** @defgroup internalMisc Miscellaneous
+ *  @ingroup internal */
+
+// ########################################################################
+//  EXAMPLES
+
+/**
+ * @example example_simple.php
+ */
+/**
+ * @example example_proxy.php
+ */
+/**
+ * @example example_proxy2.php
+ */
+/**
+ * @example example_lang.php
+ */
+/**
+ * @example example_html.php
+ */
+/**
+ * @example example_file.php
+ */
+/**
+ * @example example_db.php
+ */
+/**
+ * @example example_service.php
+ */
+/**
+ * @example example_session_proxy.php
+ */
+/**
+ * @example example_session_service.php
+ */
+/**
+ * @example example_gateway.php
+ */
+
+
+
+?>
\ No newline at end of file
diff --git a/cas_auth/cas/PGTStorage/pgt-db.php b/cas_auth/cas/PGTStorage/pgt-db.php
new file mode 100644
index 0000000000000000000000000000000000000000..6ce6855796d774725eddb4edfd8bd96476c0c8e2
--- /dev/null
+++ b/cas_auth/cas/PGTStorage/pgt-db.php
@@ -0,0 +1,191 @@
+<?php // $Id: pgt-db.php 9707 2007-12-12 13:46:31Z mlaurent $
+if ( count( get_included_files() ) == 1 ) die( '---' );
+
+/**
+ * @file CAS/PGTStorage/pgt-db.php
+ * Basic class for PGT database storage
+ */
+
+// include phpDB library (the test was introduced in release 0.4.8 for
+// the integration into Tikiwiki).
+if (!class_exists('DB')) {
+  include_once('DB.php');
+}
+
+/**
+ * @class PGTStorageDB
+ * The PGTStorageDB class is a class for PGT database storage. An instance of
+ * this class is returned by CASClient::SetPGTStorageDB().
+ *
+ * @author Pascal Aubry <pascal.aubry at univ-rennes1.fr>
+ *
+ * @ingroup internalPGTStorageDB
+ */
+
+class PGTStorageDB extends PGTStorage
+{
+  /**
+   * @addtogroup internalPGTStorageDB
+   * @{
+   */
+
+  /**
+   * a string representing a PEAR DB URL to connect to the database. Written by
+   * PGTStorageDB::PGTStorageDB(), read by getURL().
+   *
+   * @hideinitializer
+   * @private
+   */
+  var $_url='';
+
+  /**
+   * This method returns the PEAR DB URL to use to connect to the database.
+   *
+   * @return a PEAR DB URL
+   *
+   * @private
+   */
+  function getURL()
+    {
+      return $this->_url;
+    }
+
+  /**
+   * The handle of the connection to the database where PGT's are stored. Written by
+   * PGTStorageDB::init(), read by getLink().
+   *
+   * @hideinitializer
+   * @private
+   */
+  var $_link = null;
+
+  /**
+   * This method returns the handle of the connection to the database where PGT's are
+   * stored.
+   *
+   * @return a handle of connection.
+   *
+   * @private
+   */
+  function getLink()
+    {
+      return $this->_link;
+    }
+
+  /**
+   * The name of the table where PGT's are stored. Written by
+   * PGTStorageDB::PGTStorageDB(), read by getTable().
+   *
+   * @hideinitializer
+   * @private
+   */
+  var $_table = '';
+
+  /**
+   * This method returns the name of the table where PGT's are stored.
+   *
+   * @return the name of a table.
+   *
+   * @private
+   */
+  function getTable()
+    {
+      return $this->_table;
+    }
+
+  // ########################################################################
+  //  DEBUGGING
+  // ########################################################################
+
+  /**
+   * This method returns an informational string giving the type of storage
+   * used by the object (used for debugging purposes).
+   *
+   * @return an informational string.
+   * @public
+   */
+  function getStorageType()
+    {
+      return "database";
+    }
+
+  /**
+   * This method returns an informational string giving informations on the
+   * parameters of the storage.(used for debugging purposes).
+   *
+   * @public
+   */
+  function getStorageInfo()
+    {
+      return 'url=`'.$this->getURL().'\', table=`'.$this->getTable().'\'';
+    }
+
+  // ########################################################################
+  //  CONSTRUCTOR
+  // ########################################################################
+
+  /**
+   * The class constructor, called by CASClient::SetPGTStorageDB().
+   *
+   * @param $cas_parent the CASClient instance that creates the object.
+   * @param $user the user to access the data with
+   * @param $password the user's password
+   * @param $database_type the type of the database hosting the data
+   * @param $hostname the server hosting the database
+   * @param $port the port the server is listening on
+   * @param $database the name of the database
+   * @param $table the name of the table storing the data
+   *
+   * @public
+   */
+  function PGTStorageDB($cas_parent,$user,$password,$database_type,$hostname,$port,$database,$table)
+    {
+      phpCAS::traceBegin();
+
+      // call the ancestor's constructor
+      $this->PGTStorage($cas_parent);
+
+      if ( empty($database_type) ) $database_type = CAS_PGT_STORAGE_DB_DEFAULT_DATABASE_TYPE;
+      if ( empty($hostname) ) $hostname = CAS_PGT_STORAGE_DB_DEFAULT_HOSTNAME;
+      if ( $port==0 ) $port = CAS_PGT_STORAGE_DB_DEFAULT_PORT;
+      if ( empty($database) ) $database = CAS_PGT_STORAGE_DB_DEFAULT_DATABASE;
+      if ( empty($table) ) $table = CAS_PGT_STORAGE_DB_DEFAULT_TABLE;
+
+      // build and store the PEAR DB URL
+      $this->_url = $database_type.':'.'//'.$user.':'.$password.'@'.$server.':'.$port.'/'.$database;
+
+      // XXX should use setURL and setTable
+      phpCAS::traceEnd();
+    }
+
+  // ########################################################################
+  //  INITIALIZATION
+  // ########################################################################
+
+  /**
+   * This method is used to initialize the storage. Halts on error.
+   *
+   * @public
+   */
+  function init()
+    {
+      phpCAS::traceBegin();
+      // if the storage has already been initialized, return immediatly
+      if ( $this->isInitialized() )
+	return;
+      // call the ancestor's method (mark as initialized)
+      parent::init();
+
+      // try to connect to the database
+      $this->_link = DB::connect($this->getURL());
+      if ( DB::isError($this->_link) ) {
+	phpCAS::error('could not connect to database ('.DB::errorMessage($this->_link).')');
+      }
+      var_dump($this->_link);
+      phpCAS::traceBEnd();
+    }
+
+  /** @} */
+}
+
+?>
\ No newline at end of file
diff --git a/cas_auth/cas/PGTStorage/pgt-file.php b/cas_auth/cas/PGTStorage/pgt-file.php
new file mode 100644
index 0000000000000000000000000000000000000000..b2d8b3452db6f8222b9e95fb338a404b7d309cc1
--- /dev/null
+++ b/cas_auth/cas/PGTStorage/pgt-file.php
@@ -0,0 +1,238 @@
+<?php // $Id: pgt-file.php 9707 2007-12-12 13:46:31Z mlaurent $
+if ( count( get_included_files() ) == 1 ) die( '---' );
+
+/**
+ * @file CAS/PGTStorage/pgt-file.php
+ * Basic class for PGT file storage
+ */
+
+/**
+ * @class PGTStorageFile
+ * The PGTStorageFile class is a class for PGT file storage. An instance of
+ * this class is returned by CASClient::SetPGTStorageFile().
+ *
+ * @author Pascal Aubry <pascal.aubry at univ-rennes1.fr>
+ *
+ * @ingroup internalPGTStorageFile
+ */
+
+class PGTStorageFile extends PGTStorage
+{
+  /**
+   * @addtogroup internalPGTStorageFile
+   * @{
+   */
+
+  /**
+   * a string telling where PGT's should be stored on the filesystem. Written by
+   * PGTStorageFile::PGTStorageFile(), read by getPath().
+   *
+   * @private
+   */
+  var $_path;
+
+  /**
+   * This method returns the name of the directory where PGT's should be stored
+   * on the filesystem.
+   *
+   * @return the name of a directory (with leading and trailing '/')
+   *
+   * @private
+   */
+  function getPath()
+    {
+      return $this->_path;
+    }
+
+  /**
+   * a string telling the format to use to store PGT's (plain or xml). Written by
+   * PGTStorageFile::PGTStorageFile(), read by getFormat().
+   *
+   * @private
+   */
+  var $_format;
+
+  /**
+   * This method returns the format to use when storing PGT's on the filesystem.
+   *
+   * @return a string corresponding to the format used (plain or xml).
+   *
+   * @private
+   */
+  function getFormat()
+    {
+      return $this->_format;
+    }
+
+  // ########################################################################
+  //  DEBUGGING
+  // ########################################################################
+
+  /**
+   * This method returns an informational string giving the type of storage
+   * used by the object (used for debugging purposes).
+   *
+   * @return an informational string.
+   * @public
+   */
+  function getStorageType()
+    {
+      return "file";
+    }
+
+  /**
+   * This method returns an informational string giving informations on the
+   * parameters of the storage.(used for debugging purposes).
+   *
+   * @return an informational string.
+   * @public
+   */
+  function getStorageInfo()
+    {
+      return 'path=`'.$this->getPath().'\', format=`'.$this->getFormat().'\'';
+    }
+
+  // ########################################################################
+  //  CONSTRUCTOR
+  // ########################################################################
+
+  /**
+   * The class constructor, called by CASClient::SetPGTStorageFile().
+   *
+   * @param $cas_parent the CASClient instance that creates the object.
+   * @param $format the format used to store the PGT's (`plain' and `xml' allowed).
+   * @param $path the path where the PGT's should be stored
+   *
+   * @public
+   */
+  function PGTStorageFile($cas_parent,$format,$path)
+    {
+      phpCAS::traceBegin();
+      // call the ancestor's constructor
+      $this->PGTStorage($cas_parent);
+
+      if (empty($format) ) $format = CAS_PGT_STORAGE_FILE_DEFAULT_FORMAT;
+      if (empty($path) ) $path = CAS_PGT_STORAGE_FILE_DEFAULT_PATH;
+
+      // check that the path is an absolute path
+      if ( $path[0] != '/' ) {
+	phpCAS::error('an absolute path is needed for PGT storage to file');
+      }
+
+      // store the path (with a leading and trailing '/')
+      $path = preg_replace('|[/]*$|','/',$path);
+      $path = preg_replace('|^[/]*|','/',$path);
+      $this->_path = $path;
+
+      // check the format and store it
+      switch ($format) {
+      case CAS_PGT_STORAGE_FILE_FORMAT_PLAIN:
+      case CAS_PGT_STORAGE_FILE_FORMAT_XML:
+	$this->_format = $format;
+	break;
+      default:
+	phpCAS::error('unknown PGT file storage format (`'.CAS_PGT_STORAGE_FILE_FORMAT_PLAIN.'\' and `'.CAS_PGT_STORAGE_FILE_FORMAT_XML.'\' allowed)');
+      }
+      phpCAS::traceEnd();
+    }
+
+  // ########################################################################
+  //  INITIALIZATION
+  // ########################################################################
+
+  /**
+   * This method is used to initialize the storage. Halts on error.
+   *
+   * @public
+   */
+  function init()
+    {
+      phpCAS::traceBegin();
+      // if the storage has already been initialized, return immediatly
+      if ( $this->isInitialized() )
+	return;
+      // call the ancestor's method (mark as initialized)
+      parent::init();
+      phpCAS::traceEnd();
+    }
+
+  // ########################################################################
+  //  PGT I/O
+  // ########################################################################
+
+  /**
+   * This method returns the filename corresponding to a PGT Iou.
+   *
+   * @param $pgt_iou the PGT iou.
+   *
+   * @return a filename
+   * @private
+   */
+  function getPGTIouFilename($pgt_iou)
+    {
+      phpCAS::traceBegin();
+      return $this->getPath().$pgt_iou.'.'.$this->getFormat();
+      phpCAS::traceEnd();
+    }
+
+  /**
+   * This method stores a PGT and its corresponding PGT Iou into a file. Echoes a
+   * warning on error.
+   *
+   * @param $pgt the PGT
+   * @param $pgt_iou the PGT iou
+   *
+   * @public
+   */
+  function write($pgt,$pgt_iou)
+    {
+      phpCAS::traceBegin();
+      $fname = $this->getPGTIouFilename($pgt_iou);
+      if ( $f=fopen($fname,"w") ) {
+	if ( fputs($f,$pgt) === FALSE ) {
+	  phpCAS::error('could not write PGT to `'.$fname.'\'');
+	}
+	fclose($f);
+      } else {
+	phpCAS::error('could not open `'.$fname.'\'');
+      }
+      phpCAS::traceEnd();
+    }
+
+  /**
+   * This method reads a PGT corresponding to a PGT Iou and deletes the
+   * corresponding file.
+   *
+   * @param $pgt_iou the PGT iou
+   *
+   * @return the corresponding PGT, or FALSE on error
+   *
+   * @public
+   */
+  function read($pgt_iou)
+    {
+      phpCAS::traceBegin();
+      $pgt = FALSE;
+      $fname = $this->getPGTIouFilename($pgt_iou);
+      if ( !($f=fopen($fname,"r")) ) {
+	phpCAS::trace('could not open `'.$fname.'\'');
+      } else {
+	if ( ($pgt=fgets($f)) === FALSE ) {
+	  phpCAS::trace('could not read PGT from `'.$fname.'\'');
+	}
+	fclose($f);
+      }
+
+      // delete the PGT file
+      @unlink($fname);
+
+      phpCAS::traceEnd($pgt);
+      return $pgt;
+    }
+
+  /** @} */
+
+}
+
+
+?>
\ No newline at end of file
diff --git a/cas_auth/cas/PGTStorage/pgt-main.php b/cas_auth/cas/PGTStorage/pgt-main.php
new file mode 100644
index 0000000000000000000000000000000000000000..7036ca1d3b2cf9c4195656e5ef4d88ae44374693
--- /dev/null
+++ b/cas_auth/cas/PGTStorage/pgt-main.php
@@ -0,0 +1,189 @@
+<?php // $Id: pgt-main.php 9707 2007-12-12 13:46:31Z mlaurent $
+if ( count( get_included_files() ) == 1 ) die( '---' );
+
+/**
+ * @file CAS/PGTStorage/pgt-main.php
+ * Basic class for PGT storage
+ */
+
+/**
+ * @class PGTStorage
+ * The PGTStorage class is a generic class for PGT storage. This class should
+ * not be instanciated itself but inherited by specific PGT storage classes.
+ *
+ * @author   Pascal Aubry <pascal.aubry at univ-rennes1.fr>
+ *
+ * @ingroup internalPGTStorage
+ */
+
+class PGTStorage
+{
+  /**
+   * @addtogroup internalPGTStorage
+   * @{
+   */
+
+  // ########################################################################
+  //  CONSTRUCTOR
+  // ########################################################################
+
+  /**
+   * The constructor of the class, should be called only by inherited classes.
+   *
+   * @param $cas_parent the CASclient instance that creates the current object.
+   *
+   * @protected
+   */
+  function PGTStorage($cas_parent)
+    {
+      phpCAS::traceBegin();
+      if ( !$cas_parent->isProxy() ) {
+	phpCAS::error('defining PGT storage makes no sense when not using a CAS proxy');
+      }
+      phpCAS::traceEnd();
+    }
+
+  // ########################################################################
+  //  DEBUGGING
+  // ########################################################################
+
+  /**
+   * This virtual method returns an informational string giving the type of storage
+   * used by the object (used for debugging purposes).
+   *
+   * @public
+   */
+  function getStorageType()
+    {
+      phpCAS::error(__CLASS__.'::'.__FUNCTION__.'() should never be called');
+    }
+
+  /**
+   * This virtual method returns an informational string giving informations on the
+   * parameters of the storage.(used for debugging purposes).
+   *
+   * @public
+   */
+  function getStorageInfo()
+    {
+      phpCAS::error(__CLASS__.'::'.__FUNCTION__.'() should never be called');
+    }
+
+  // ########################################################################
+  //  ERROR HANDLING
+  // ########################################################################
+
+  /**
+   * string used to store an error message. Written by PGTStorage::setErrorMessage(),
+   * read by PGTStorage::getErrorMessage().
+   *
+   * @hideinitializer
+   * @private
+   * @deprecated not used.
+   */
+  var $_error_message=FALSE;
+
+  /**
+   * This method sets en error message, which can be read later by
+   * PGTStorage::getErrorMessage().
+   *
+   * @param $error_message an error message
+   *
+   * @protected
+   * @deprecated not used.
+   */
+  function setErrorMessage($error_message)
+    {
+      $this->_error_message = $error_message;
+    }
+
+  /**
+   * This method returns an error message set by PGTStorage::setErrorMessage().
+   *
+   * @return an error message when set by PGTStorage::setErrorMessage(), FALSE
+   * otherwise.
+   *
+   * @public
+   * @deprecated not used.
+   */
+  function getErrorMessage()
+    {
+      return $this->_error_message;
+    }
+
+  // ########################################################################
+  //  INITIALIZATION
+  // ########################################################################
+
+  /**
+   * a boolean telling if the storage has already been initialized. Written by
+   * PGTStorage::init(), read by PGTStorage::isInitialized().
+   *
+   * @hideinitializer
+   * @private
+   */
+  var $_initialized = FALSE;
+
+  /**
+   * This method tells if the storage has already been intialized.
+   *
+   * @return a boolean
+   *
+   * @protected
+   */
+  function isInitialized()
+    {
+      return $this->_initialized;
+    }
+
+  /**
+   * This virtual method initializes the object.
+   *
+   * @protected
+   */
+  function init()
+    {
+      $this->_initialized = TRUE;
+    }
+
+  // ########################################################################
+  //  PGT I/O
+  // ########################################################################
+
+  /**
+   * This virtual method stores a PGT and its corresponding PGT Iuo.
+   * @note Should never be called.
+   *
+   * @param $pgt the PGT
+   * @param $pgt_iou the PGT iou
+   *
+   * @protected
+   */
+  function write($pgt,$pgt_iou)
+    {
+      phpCAS::error(__CLASS__.'::'.__FUNCTION__.'() should never be called');
+    }
+
+  /**
+   * This virtual method reads a PGT corresponding to a PGT Iou and deletes
+   * the corresponding storage entry.
+   * @note Should never be called.
+   *
+   * @param $pgt_iou the PGT iou
+   *
+   * @protected
+   */
+  function read($pgt_iou)
+    {
+      phpCAS::error(__CLASS__.'::'.__FUNCTION__.'() should never be called');
+    }
+
+  /** @} */
+
+}
+
+// include specific PGT storage classes
+include_once(dirname(__FILE__).'/pgt-file.php');
+include_once(dirname(__FILE__).'/pgt-db.php');
+
+?>
\ No newline at end of file
diff --git a/cas_auth/cas/client.php b/cas_auth/cas/client.php
new file mode 100644
index 0000000000000000000000000000000000000000..964a5eca6f405df2319bc003ee3affcde3e65168
--- /dev/null
+++ b/cas_auth/cas/client.php
@@ -0,0 +1,1975 @@
+<?php // $Id: client.php 9707 2007-12-12 13:46:31Z mlaurent $
+if ( count( get_included_files() ) == 1 ) die( '---' );
+
+/**
+ * @file CAS/client.php
+ * Main class of the phpCAS library
+ */
+
+// include internationalization stuff
+include_once(dirname(__FILE__).'/languages/languages.php');
+
+// include PGT storage classes
+include_once(dirname(__FILE__).'/PGTStorage/pgt-main.php');
+
+/**
+ * @class CASClient
+ * The CASClient class is a client interface that provides CAS authentication
+ * to PHP applications.
+ *
+ * @author Pascal Aubry <pascal.aubry at univ-rennes1.fr>
+ */
+
+class CASClient
+{
+
+  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+  // XX                                                                    XX
+  // XX                          CONFIGURATION                             XX
+  // XX                                                                    XX
+  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+  // ########################################################################
+  //  HTML OUTPUT
+  // ########################################################################
+  /**
+   * @addtogroup internalOutput
+   * @{
+   */  
+  
+  /**
+   * This method filters a string by replacing special tokens by appropriate values
+   * and prints it. The corresponding tokens are taken into account:
+   * - __CAS_VERSION__
+   * - __PHPCAS_VERSION__
+   * - __SERVER_BASE_URL__
+   *
+   * Used by CASClient::PrintHTMLHeader() and CASClient::printHTMLFooter().
+   *
+   * @param $str the string to filter and output
+   *
+   * @private
+   */
+  function HTMLFilterOutput($str)
+    {
+      $str = str_replace('__CAS_VERSION__',$this->getServerVersion(),$str);
+      $str = str_replace('__PHPCAS_VERSION__',phpCAS::getVersion(),$str);
+      $str = str_replace('__SERVER_BASE_URL__',$this->getServerBaseURL(),$str);
+      echo $str;
+    }
+
+  /**
+   * A string used to print the header of HTML pages. Written by CASClient::setHTMLHeader(),
+   * read by CASClient::printHTMLHeader().
+   *
+   * @hideinitializer
+   * @private
+   * @see CASClient::setHTMLHeader, CASClient::printHTMLHeader()
+   */
+  var $_output_header = '';
+  
+  /**
+   * This method prints the header of the HTML output (after filtering). If
+   * CASClient::setHTMLHeader() was not used, a default header is output.
+   *
+   * @param $title the title of the page
+   *
+   * @see HTMLFilterOutput()
+   * @private
+   */
+  function printHTMLHeader($title)
+    {
+      $this->HTMLFilterOutput(str_replace('__TITLE__',
+					  $title,
+					  (empty($this->_output_header)
+					   ? '<html><head><title>__TITLE__</title></head><body><h1>__TITLE__</h1>'
+					   : $this->output_header)
+					  )
+			      );
+    }
+
+  /**
+   * A string used to print the footer of HTML pages. Written by CASClient::setHTMLFooter(),
+   * read by printHTMLFooter().
+   *
+   * @hideinitializer
+   * @private
+   * @see CASClient::setHTMLFooter, CASClient::printHTMLFooter()
+   */
+  var $_output_footer = '';
+  
+  /**
+   * This method prints the footer of the HTML output (after filtering). If
+   * CASClient::setHTMLFooter() was not used, a default footer is output.
+   *
+   * @see HTMLFilterOutput()
+   * @private
+   */
+  function printHTMLFooter()
+    {
+      $this->HTMLFilterOutput(empty($this->_output_footer)
+			      ?('<hr><address>phpCAS __PHPCAS_VERSION__ '.$this->getString(CAS_STR_USING_SERVER).' <a href="__SERVER_BASE_URL__">__SERVER_BASE_URL__</a> (CAS __CAS_VERSION__)</a></address></body></html>')
+			      :$this->_output_footer);
+    }
+
+  /**
+   * This method set the HTML header used for all outputs.
+   *
+   * @param $header the HTML header.
+   *
+   * @public
+   */
+  function setHTMLHeader($header)
+    {
+      $this->_output_header = $header;
+    }
+
+  /**
+   * This method set the HTML footer used for all outputs.
+   *
+   * @param $footer the HTML footer.
+   *
+   * @public
+   */
+  function setHTMLFooter($footer)
+    {
+      $this->_output_footer = $footer;
+    }
+
+  /** @} */
+  // ########################################################################
+  //  INTERNATIONALIZATION
+  // ########################################################################
+  /**
+   * @addtogroup internalLang
+   * @{
+   */  
+  /**
+   * A string corresponding to the language used by phpCAS. Written by 
+   * CASClient::setLang(), read by CASClient::getLang().
+
+   * @note debugging information is always in english (debug purposes only).
+   *
+   * @hideinitializer
+   * @private
+   * @sa CASClient::_strings, CASClient::getString()
+   */
+  var $_lang = '';
+  
+  /**
+   * This method returns the language used by phpCAS.
+   *
+   * @return a string representing the language
+   *
+   * @private
+   */
+  function getLang()
+    {
+      if ( empty($this->_lang) )
+	$this->setLang(PHPCAS_LANG_DEFAULT);
+      return $this->_lang;
+    }
+
+  /**
+   * array containing the strings used by phpCAS. Written by CASClient::setLang(), read by 
+   * CASClient::getString() and used by CASClient::setLang().
+   *
+   * @note This array is filled by instructions in CAS/languages/<$this->_lang>.php
+   *
+   * @private
+   * @see CASClient::_lang, CASClient::getString(), CASClient::setLang(), CASClient::getLang()
+   */
+  var $_strings;
+
+  /**
+   * This method returns a string depending on the language.
+   *
+   * @param $str the index of the string in $_string.
+   *
+   * @return the string corresponding to $index in $string.
+   *
+   * @private
+   */
+  function getString($str)
+    {
+      // call CASclient::getLang() to be sure the language is initialized
+      $this->getLang();
+      
+      if ( !isset($this->_strings[$str]) ) {
+	trigger_error('string `'.$str.'\' not defined for language `'.$this->getLang().'\'',E_USER_ERROR);
+      }
+      return $this->_strings[$str];
+    }
+
+  /**
+   * This method is used to set the language used by phpCAS. 
+   * @note Can be called only once.
+   *
+   * @param $lang a string representing the language.
+   *
+   * @public
+   * @sa CAS_LANG_FRENCH, CAS_LANG_ENGLISH
+   */
+  function setLang($lang)
+    {
+      // include the corresponding language file
+      include_once(dirname(__FILE__).'/languages/'.$lang.'.php');
+
+      if ( !is_array($this->_strings) ) {
+	trigger_error('language `'.$lang.'\' is not implemented',E_USER_ERROR);
+      }
+      $this->_lang = $lang;
+    }
+
+  /** @} */
+  // ########################################################################
+  //  CAS SERVER CONFIG
+  // ########################################################################
+  /**
+   * @addtogroup internalConfig
+   * @{
+   */  
+  
+  /**
+   * a record to store information about the CAS server.
+   * - $_server["version"]: the version of the CAS server
+   * - $_server["hostname"]: the hostname of the CAS server
+   * - $_server["port"]: the port the CAS server is running on
+   * - $_server["uri"]: the base URI the CAS server is responding on
+   * - $_server["base_url"]: the base URL of the CAS server
+   * - $_server["login_url"]: the login URL of the CAS server
+   * - $_server["service_validate_url"]: the service validating URL of the CAS server
+   * - $_server["proxy_url"]: the proxy URL of the CAS server
+   * - $_server["proxy_validate_url"]: the proxy validating URL of the CAS server
+   * - $_server["logout_url"]: the logout URL of the CAS server
+   *
+   * $_server["version"], $_server["hostname"], $_server["port"] and $_server["uri"]
+   * are written by CASClient::CASClient(), read by CASClient::getServerVersion(), 
+   * CASClient::getServerHostname(), CASClient::getServerPort() and CASClient::getServerURI().
+   *
+   * The other fields are written and read by CASClient::getServerBaseURL(), 
+   * CASClient::getServerLoginURL(), CASClient::getServerServiceValidateURL(), 
+   * CASClient::getServerProxyValidateURL() and CASClient::getServerLogoutURL().
+   *
+   * @hideinitializer
+   * @private
+   */
+  var $_server = array(
+		       'version' => -1,
+		       'hostname' => 'none',
+		       'port' => -1,
+		       'uri' => 'none'
+		       );
+  
+  /**
+   * This method is used to retrieve the version of the CAS server.
+   * @return the version of the CAS server.
+   * @private
+   */
+  function getServerVersion()
+    { 
+      return $this->_server['version']; 
+    }
+
+  /**
+   * This method is used to retrieve the hostname of the CAS server.
+   * @return the hostname of the CAS server.
+   * @private
+   */
+  function getServerHostname()
+    { return $this->_server['hostname']; }
+
+  /**
+   * This method is used to retrieve the port of the CAS server.
+   * @return the port of the CAS server.
+   * @private
+   */
+  function getServerPort()
+    { return $this->_server['port']; }
+
+  /**
+   * This method is used to retrieve the URI of the CAS server.
+   * @return a URI.
+   * @private
+   */
+  function getServerURI()
+    { return $this->_server['uri']; }
+
+  /**
+   * This method is used to retrieve the base URL of the CAS server.
+   * @return a URL.
+   * @private
+   */
+  function getServerBaseURL()
+    { 
+      // the URL is build only when needed
+      if ( empty($this->_server['base_url']) ) {
+	$this->_server['base_url'] = 'https://'
+	  .$this->getServerHostname()
+	  .':'
+	  .$this->getServerPort()
+	  .$this->getServerURI();
+      }
+      return $this->_server['base_url']; 
+    }
+
+  /**
+   * This method is used to retrieve the login URL of the CAS server.
+   * @param $gateway true to check authentication, false to force it
+   * @return a URL.
+   * @private
+   */
+  function getServerLoginURL($gateway)
+    { 
+      phpCAS::traceBegin();
+      // the URL is build only when needed
+      if ( empty($this->_server['login_url']) ) {
+        $this->_server['login_url'] = $this->getServerBaseURL();
+        $this->_server['login_url'] .= 'login?service=';
+        $this->_server['login_url'] .= preg_replace('/&/','%26',$this->getURL());
+        if ($gateway) {
+          $this->_server['login_url'] .= '&gateway=true';
+        }
+      }
+      phpCAS::traceEnd($this->_server['login_url']);
+      return $this->_server['login_url']; 
+    }
+
+  /**
+   * This method sets the login URL of the CAS server.
+   * @param $url the login URL
+   * @private
+   * @since 0.4.21 by Wyman Chan
+   */
+  function setServerLoginURL($url)
+    {
+      return $this->_server['login_url'] = $url;
+    }
+
+  /**
+   * This method is used to retrieve the service validating URL of the CAS server.
+   * @return a URL.
+   * @private
+   */
+  function getServerServiceValidateURL()
+    { 
+      // the URL is build only when needed
+      if ( empty($this->_server['service_validate_url']) ) {
+	switch ($this->getServerVersion()) {
+	case CAS_VERSION_1_0:
+	  $this->_server['service_validate_url'] = $this->getServerBaseURL().'validate';
+	  break;
+	case CAS_VERSION_2_0:
+	  $this->_server['service_validate_url'] = $this->getServerBaseURL().'serviceValidate';
+	  break;
+	}
+      }
+      return $this->_server['service_validate_url'].'?service='.preg_replace('/&/','%26',$this->getURL()); 
+    }
+
+  /**
+   * This method is used to retrieve the proxy validating URL of the CAS server.
+   * @return a URL.
+   * @private
+   */
+  function getServerProxyValidateURL()
+    { 
+      // the URL is build only when needed
+      if ( empty($this->_server['proxy_validate_url']) ) {
+	switch ($this->getServerVersion()) {
+	case CAS_VERSION_1_0:
+	  $this->_server['proxy_validate_url'] = '';
+	  break;
+	case CAS_VERSION_2_0:
+	  $this->_server['proxy_validate_url'] = $this->getServerBaseURL().'proxyValidate';
+	  break;
+	}
+      }
+      return $this->_server['proxy_validate_url'].'?service='.preg_replace('/&/','%26',$this->getURL()); 
+    }
+
+  /**
+   * This method is used to retrieve the proxy URL of the CAS server.
+   * @return a URL.
+   * @private
+   */
+  function getServerProxyURL()
+    { 
+      // the URL is build only when needed
+      if ( empty($this->_server['proxy_url']) ) {
+	switch ($this->getServerVersion()) {
+	case CAS_VERSION_1_0:
+	  $this->_server['proxy_url'] = '';
+	  break;
+	case CAS_VERSION_2_0:
+	  $this->_server['proxy_url'] = $this->getServerBaseURL().'proxy';
+	  break;
+	}
+      }
+      return $this->_server['proxy_url']; 
+    }
+
+  /**
+   * This method is used to retrieve the logout URL of the CAS server.
+   * @return a URL.
+   * @private
+   */
+  function getServerLogoutURL()
+    { 
+      // the URL is build only when needed
+      if ( empty($this->_server['logout_url']) ) {
+	$this->_server['logout_url'] = $this->getServerBaseURL().'logout';
+      }
+      return $this->_server['logout_url']; 
+    }
+
+  /**
+   * This method sets the logout URL of the CAS server.
+   * @param $url the logout URL
+   * @private
+   * @since 0.4.21 by Wyman Chan
+   */
+  function setServerLogoutURL($url)
+    {
+      return $this->_server['logout_url'] = $url;
+    }
+
+  // ########################################################################
+  //  CONSTRUCTOR
+  // ########################################################################
+  /**
+   * CASClient constructor.
+   *
+   * @param $server_version the version of the CAS server
+   * @param $proxy TRUE if the CAS client is a CAS proxy, FALSE otherwise
+   * @param $server_hostname the hostname of the CAS server
+   * @param $server_port the port the CAS server is running on
+   * @param $server_uri the URI the CAS server is responding on
+   * @param $start_session Have phpCAS start PHP sessions (default true)
+   *
+   * @return a newly created CASClient object
+   *
+   * @public
+   */
+  function CASClient($server_version,
+		     $proxy,
+		     $server_hostname,
+		     $server_port,
+		     $server_uri,
+		     $start_session = true)
+    {
+      phpCAS::traceBegin();
+
+      // activate session mechanism if desired
+      if ($start_session) {
+           session_start();
+      }
+
+      $this->_proxy = $proxy;
+
+      // check version
+      switch ($server_version) {
+      case CAS_VERSION_1_0:
+	if ( $this->isProxy() )
+	  phpCAS::error('CAS proxies are not supported in CAS '
+			.$server_version);
+	break;
+      case CAS_VERSION_2_0:
+	break;
+      default:
+	phpCAS::error('this version of CAS (`'
+		      .$server_version
+		      .'\') is not supported by phpCAS '
+			.phpCAS::getVersion());
+      }
+      $this->_server['version'] = $server_version;
+
+      // check hostname
+      if ( empty($server_hostname) 
+	   || !preg_match('/[\.\d\-abcdefghijklmnopqrstuvwxyz]*/',$server_hostname) ) {
+	phpCAS::error('bad CAS server hostname (`'.$server_hostname.'\')');
+      }
+      $this->_server['hostname'] = $server_hostname;
+
+      // check port
+      if ( $server_port == 0 
+	   || !is_int($server_port) ) {
+	phpCAS::error('bad CAS server port (`'.$server_hostname.'\')');
+      }
+      $this->_server['port'] = $server_port;
+
+      // check URI
+      if ( !preg_match('/[\.\d\-_abcdefghijklmnopqrstuvwxyz\/]*/',$server_uri) ) {
+	phpCAS::error('bad CAS server URI (`'.$server_uri.'\')');
+      }
+      // add leading and trailing `/' and remove doubles      
+      $server_uri = preg_replace('/\/\//','/','/'.$server_uri.'/');
+      $this->_server['uri'] = $server_uri;
+
+      // set to callback mode if PgtIou and PgtId CGI GET parameters are provided 
+      if ( $this->isProxy() ) {
+	$this->setCallbackMode(!empty($_GET['pgtIou'])&&!empty($_GET['pgtId']));
+      }
+
+      if ( $this->isCallbackMode() ) {
+	// callback mode: check that phpCAS is secured
+	if ( $_SERVER['HTTPS'] != 'on' ) {
+	  phpCAS::error('CAS proxies must be secured to use phpCAS; PGT\'s will not be received from the CAS server');
+	}
+      } else {
+	// normal mode: get ticket and remove it from CGI parameters for developpers
+	$ticket = $_GET['ticket'];
+	// at first check for a Service Ticket
+	if( preg_match('/^ST-/',$ticket)) {
+	  phpCAS::trace('ST \''.$ticket.'\' found');
+	  // ST present
+	  $this->setST($ticket);
+	} 
+	// in a second time check for a Proxy Ticket (CAS >= 2.0)
+	else if( ($this->getServerVersion()!=CAS_VERSION_1_0) && preg_match('/^PT-/',$ticket) ) {
+	  phpCAS::trace('PT \''.$ticket.'\' found');
+	  $this->setPT($ticket);
+	} 
+	// ill-formed ticket, halt
+	else if ( !empty($ticket) ) {
+	  phpCAS::error('ill-formed ticket found in the URL (ticket=`'.htmlentities($ticket).'\')');
+	}
+	// ticket has been taken into account, unset it to hide it to applications
+	unset($_GET['ticket']);
+      }
+      phpCAS::traceEnd();
+    }
+
+  /** @} */
+
+  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+  // XX                                                                    XX
+  // XX                           AUTHENTICATION                           XX
+  // XX                                                                    XX
+  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+  /**
+   * @addtogroup internalAuthentication
+   * @{
+   */  
+  
+  /**
+   * The Authenticated user. Written by CASClient::setUser(), read by CASClient::getUser().
+   * @attention client applications should use phpCAS::getUser().
+   *
+   * @hideinitializer
+   * @private
+   */
+  var $_user = '';
+  
+  /**
+   * This method sets the CAS user's login name.
+   *
+   * @param $user the login name of the authenticated user.
+   *
+   * @private
+   */
+  function setUser($user)
+    {
+      $this->_user = $user;
+    }
+
+  /**
+   * This method returns the CAS user's login name.
+   * @warning should be called only after CASClient::forceAuthentication() or 
+   * CASClient::isAuthenticated(), otherwise halt with an error.
+   *
+   * @return the login name of the authenticated user
+   */
+  function getUser()
+    {
+      if ( empty($this->_user) ) {
+	phpCAS::error('this method should be used only after '.__CLASS__.'::forceAuthentication() or '.__CLASS__.'::isAuthenticated()');
+      }
+      return $this->_user;
+    }
+
+  /**
+   * This method is called to be sure that the user is authenticated. When not 
+   * authenticated, halt by redirecting to the CAS server; otherwise return TRUE.
+   * @return TRUE when the user is authenticated; otherwise halt.
+   * @public
+   */
+  function forceAuthentication()
+    {
+      phpCAS::traceBegin();
+
+      if ( $this->isAuthenticated() ) {
+        // the user is authenticated, nothing to be done.
+	    phpCAS::trace('no need to authenticate');
+	    $res = TRUE;
+      } else {
+	    // the user is not authenticated, redirect to the CAS server
+        unset($_SESSION['phpCAS']['auth_checked']);
+	    $this->redirectToCas(FALSE/* no gateway */);	
+	    // never reached
+	    $res = FALSE;
+      }
+      phpCAS::traceEnd($res);
+      return $res;
+    }
+  
+  /**
+   * This method is called to check whether the ser is authenticated or not.
+   * @return TRUE when the user is authenticated, FALSE otherwise.
+   * @public
+   */
+  function checkAuthentication()
+    {
+      phpCAS::traceBegin();
+
+      if ( $this->isAuthenticated() ) {
+	    phpCAS::trace('user is authenticated');
+	    $res = TRUE;
+      } else if (isset($_SESSION['phpCAS']['auth_checked'])) {
+        // the previous request has redirected the client to the CAS server with gateway=true
+        unset($_SESSION['phpCAS']['auth_checked']);
+        $res = FALSE;
+      } else {
+        $_SESSION['phpCAS']['auth_checked'] = true;
+	    $this->redirectToCas(TRUE/* gateway */);	
+	    // never reached
+	    $res = FALSE;
+      }
+      phpCAS::traceEnd($res);
+      return $res;
+    }
+  
+  /**
+   * This method is called to check if the user is authenticated (previously or by
+   * tickets given in the URL
+   *
+   * @return TRUE when the user is authenticated; otherwise halt.
+   *
+   * @public
+   */
+  function isAuthenticated()
+    {
+      phpCAS::traceBegin();
+      $res = FALSE;
+      $validate_url = '';
+
+      if ( $this->wasPreviouslyAuthenticated() ) {
+	// the user has already (previously during the session) been 
+	// authenticated, nothing to be done.
+	phpCAS::trace('user was already authenticated, no need to look for tickets');
+	$res = TRUE;
+      } elseif ( $this->hasST() ) {
+	// if a Service Ticket was given, validate it
+	phpCAS::trace('ST `'.$this->getST().'\' is present');
+	$this->validateST($validate_url,$text_response,$tree_response); // if it fails, it halts
+	phpCAS::trace('ST `'.$this->getST().'\' was validated');
+	if ( $this->isProxy() ) {
+	  $this->validatePGT($validate_url,$text_response,$tree_response); // idem
+	  phpCAS::trace('PGT `'.$this->getPGT().'\' was validated');
+	  $_SESSION['phpCAS']['pgt'] = $this->getPGT();
+	}
+	$_SESSION['phpCAS']['user'] = $this->getUser();
+	$res = TRUE;
+      } elseif ( $this->hasPT() ) {
+	// if a Proxy Ticket was given, validate it
+	phpCAS::trace('PT `'.$this->getPT().'\' is present');
+	$this->validatePT($validate_url,$text_response,$tree_response); // note: if it fails, it halts
+	phpCAS::trace('PT `'.$this->getPT().'\' was validated');
+	if ( $this->isProxy() ) {
+	  $this->validatePGT($validate_url,$text_response,$tree_response); // idem
+	  phpCAS::trace('PGT `'.$this->getPGT().'\' was validated');
+	  $_SESSION['phpCAS']['pgt'] = $this->getPGT();
+	}
+	$_SESSION['phpCAS']['user'] = $this->getUser();
+	$res = TRUE;
+      } else {
+	// no ticket given, not authenticated
+	phpCAS::trace('no ticket found');
+      }
+
+      phpCAS::traceEnd($res);
+      return $res;
+    }
+  
+  /**
+   * This method tells if the user has already been (previously) authenticated
+   * by looking into the session variables.
+   *
+   * @note This function switches to callback mode when needed.
+   *
+   * @return TRUE when the user has already been authenticated; FALSE otherwise.
+   *
+   * @private
+   */
+  function wasPreviouslyAuthenticated()
+    {
+      phpCAS::traceBegin();
+
+      if ( $this->isCallbackMode() ) {
+	$this->callback();
+      }
+
+      $auth = FALSE;
+
+      if ( $this->isProxy() ) {
+	// CAS proxy: username and PGT must be present
+	if ( !empty($_SESSION['phpCAS']['user']) && !empty($_SESSION['phpCAS']['pgt']) ) {
+	  // authentication already done
+	  $this->setUser($_SESSION['phpCAS']['user']);
+	  $this->setPGT($_SESSION['phpCAS']['pgt']);
+	  phpCAS::trace('user = `'.$_SESSION['phpCAS']['user'].'\', PGT = `'.$_SESSION['phpCAS']['pgt'].'\''); 
+	  $auth = TRUE;
+	} elseif ( !empty($_SESSION['phpCAS']['user']) && empty($_SESSION['phpCAS']['pgt']) ) {
+	  // these two variables should be empty or not empty at the same time
+	  phpCAS::trace('username found (`'.$_SESSION['phpCAS']['user'].'\') but PGT is empty');
+	  // unset all tickets to enforce authentication
+	  unset($_SESSION['phpCAS']);
+	  $this->setST('');
+	  $this->setPT('');
+	} elseif ( empty($_SESSION['phpCAS']['user']) && !empty($_SESSION['phpCAS']['pgt']) ) {
+	  // these two variables should be empty or not empty at the same time
+	  phpCAS::trace('PGT found (`'.$_SESSION['phpCAS']['pgt'].'\') but username is empty'); 
+	  // unset all tickets to enforce authentication
+	  unset($_SESSION['phpCAS']);
+	  $this->setST('');
+	  $this->setPT('');
+	} else {
+	  phpCAS::trace('neither user not PGT found'); 
+	}
+      } else {
+	// `simple' CAS client (not a proxy): username must be present
+	if ( !empty($_SESSION['phpCAS']['user']) ) {
+	  // authentication already done
+	  $this->setUser($_SESSION['phpCAS']['user']);
+	  phpCAS::trace('user = `'.$_SESSION['phpCAS']['user'].'\''); 
+	  $auth = TRUE;
+	} else {
+	  phpCAS::trace('no user found');
+	}
+      }
+      
+      phpCAS::traceEnd($auth);
+      return $auth;
+    }
+  
+  /**
+   * This method is used to redirect the client to the CAS server.
+   * It is used by CASClient::forceAuthentication() and CASClient::checkAuthentication().
+   * @param $gateway true to check authentication, false to force it
+   * @public
+   */
+  function redirectToCas($gateway)
+    {
+      phpCAS::traceBegin();
+      $cas_url = $this->getServerLoginURL($gateway);
+      header('Location: '.$cas_url);
+      $this->printHTMLHeader($this->getString(CAS_STR_AUTHENTICATION_WANTED));
+      printf('<p>'.$this->getString(CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED).'</p>',$cas_url);
+      $this->printHTMLFooter();
+      phpCAS::traceExit();
+      exit();
+    }
+  
+  /**
+   * This method is used to logout from CAS.
+   * @param $url a URL that will be transmitted to the CAS server (to come back to when logged out)
+   * @public
+   */
+  function logout($url = "")
+    {
+      phpCAS::traceBegin();
+      $cas_url = $this->getServerLogoutURL();
+      // v0.4.14 sebastien.gougeon at univ-rennes1.fr
+      // header('Location: '.$cas_url);
+      if ( $url != "" ) {
+        $url = '?service=' . $url;
+      }
+      header('Location: '.$cas_url . $url);
+      session_unset();
+      session_destroy();
+      $this->printHTMLHeader($this->getString(CAS_STR_LOGOUT));
+      printf('<p>'.$this->getString(CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED).'</p>',$cas_url);
+      $this->printHTMLFooter();
+      phpCAS::traceExit();
+      exit();
+    }
+  
+  /** @} */
+
+  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+  // XX                                                                    XX
+  // XX                  BASIC CLIENT FEATURES (CAS 1.0)                   XX
+  // XX                                                                    XX
+  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+  // ########################################################################
+  //  ST
+  // ########################################################################
+  /**
+   * @addtogroup internalBasic
+   * @{
+   */  
+  
+  /**
+   * the Service Ticket provided in the URL of the request if present
+   * (empty otherwise). Written by CASClient::CASClient(), read by 
+   * CASClient::getST() and CASClient::hasPGT().
+   *
+   * @hideinitializer
+   * @private
+   */
+  var $_st = '';
+  
+  /**
+   * This method returns the Service Ticket provided in the URL of the request.
+   * @return The service ticket.
+   * @private
+   */
+  function getST()
+    { return $this->_st; }
+
+  /**
+   * This method stores the Service Ticket.
+   * @param $st The Service Ticket.
+   * @private
+   */
+  function setST($st)
+    { $this->_st = $st; }
+
+  /**
+   * This method tells if a Service Ticket was stored.
+   * @return TRUE if a Service Ticket has been stored.
+   * @private
+   */
+  function hasST()
+    { return !empty($this->_st); }
+
+  /** @} */
+
+  // ########################################################################
+  //  ST VALIDATION
+  // ########################################################################
+  /**
+   * @addtogroup internalBasic
+   * @{
+   */  
+
+  /**
+   * This method is used to validate a ST; halt on failure, and sets $validate_url,
+   * $text_reponse and $tree_response on success. These parameters are used later
+   * by CASClient::validatePGT() for CAS proxies.
+   * 
+   * @param $validate_url the URL of the request to the CAS server.
+   * @param $text_response the response of the CAS server, as is (XML text).
+   * @param $tree_response the response of the CAS server, as a DOM XML tree.
+   *
+   * @return bool TRUE when successfull, halt otherwise by calling CASClient::authError().
+   *
+   * @private
+   */
+  function validateST($validate_url,&$text_response,&$tree_response)
+    {
+      phpCAS::traceBegin();
+      // build the URL to validate the ticket
+      $validate_url = $this->getServerServiceValidateURL().'&ticket='.$this->getST();
+      if ( $this->isProxy() ) {
+	// pass the callback url for CAS proxies
+	$validate_url .= '&pgtUrl='.$this->getCallbackURL();
+      }
+
+      // open and read the URL
+      if ( !$this->readURL($validate_url,''/*cookies*/,$headers,$text_response,$err_msg) ) {
+	phpCAS::trace('could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')');
+	$this->authError('ST not validated',
+			 $validate_url,
+			 TRUE/*$no_response*/);
+      }
+
+      // analyze the result depending on the version
+      switch ($this->getServerVersion()) {
+      case CAS_VERSION_1_0:
+	if (preg_match('/^no\n/',$text_response)) {
+	  phpCAS::trace('ST has not been validated');
+	  $this->authError('ST not validated',
+		       $validate_url,
+		       FALSE/*$no_response*/,
+		       FALSE/*$bad_response*/,
+		       $text_response);
+	}
+	if (!preg_match('/^yes\n/',$text_response)) {
+	  phpCAS::trace('ill-formed response');
+	  $this->authError('ST not validated',
+		       $validate_url,
+		       FALSE/*$no_response*/,
+		       TRUE/*$bad_response*/,
+		       $text_response);
+	}
+	// ST has been validated, extract the user name
+	$arr = preg_split('/\n/',$text_response);
+	$this->setUser(trim($arr[1]));
+	break;
+      case CAS_VERSION_2_0:
+	// read the response of the CAS server into a DOM object
+	if ( !($dom = domxml_open_mem($text_response))) {
+	  phpCAS::trace('domxml_open_mem() failed');
+	  $this->authError('ST not validated',
+		       $validate_url,
+		       FALSE/*$no_response*/,
+		       TRUE/*$bad_response*/,
+		       $text_response);
+	}
+	// read the root node of the XML tree
+	if ( !($tree_response = $dom->document_element()) ) {
+	  phpCAS::trace('document_element() failed');
+	  $this->authError('ST not validated',
+		       $validate_url,
+		       FALSE/*$no_response*/,
+		       TRUE/*$bad_response*/,
+		       $text_response);
+	}
+	// insure that tag name is 'serviceResponse'
+	if ( $tree_response->node_name() != 'serviceResponse' ) {
+	  phpCAS::trace('bad XML root node (should be `serviceResponse\' instead of `'.$tree_response->node_name().'\'');
+	  $this->authError('ST not validated',
+		       $validate_url,
+		       FALSE/*$no_response*/,
+		       TRUE/*$bad_response*/,
+		       $text_response);
+	}
+	if ( sizeof($success_elements = $tree_response->get_elements_by_tagname("authenticationSuccess")) != 0) {
+	  // authentication succeded, extract the user name
+	  if ( sizeof($user_elements = $success_elements[0]->get_elements_by_tagname("user")) == 0) {
+	    phpCAS::trace('<authenticationSuccess> found, but no <user>');
+	    $this->authError('ST not validated',
+			 $validate_url,
+			 FALSE/*$no_response*/,
+			 TRUE/*$bad_response*/,
+			 $text_response);
+	  }
+	  $user = trim($user_elements[0]->get_content());
+	  phpCAS::trace('user = `'.$user);
+	  $this->setUser($user);
+	  
+	} else if ( sizeof($failure_elements = $tree_response->get_elements_by_tagname("authenticationFailure")) != 0) {
+	  phpCAS::trace('<authenticationFailure> found');
+	  // authentication failed, extract the error code and message
+	  $this->authError('ST not validated',
+		       $validate_url,
+		       FALSE/*$no_response*/,
+		       FALSE/*$bad_response*/,
+		       $text_response,
+		       $failure_elements[0]->get_attribute('code')/*$err_code*/,
+		       trim($failure_elements[0]->get_content())/*$err_msg*/);
+	} else {
+	  phpCAS::trace('neither <authenticationSuccess> nor <authenticationFailure> found');
+	  $this->authError('ST not validated',
+		       $validate_url,
+		       FALSE/*$no_response*/,
+		       TRUE/*$bad_response*/,
+		       $text_response);
+	}
+	break;
+      }
+      
+      // at this step, ST has been validated and $this->_user has been set,
+      phpCAS::traceEnd(TRUE);
+      return TRUE;
+    }
+
+  /** @} */
+
+  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+  // XX                                                                    XX
+  // XX                     PROXY FEATURES (CAS 2.0)                       XX
+  // XX                                                                    XX
+  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+  // ########################################################################
+  //  PROXYING
+  // ########################################################################
+  /**
+   * @addtogroup internalProxy
+   * @{
+   */
+
+  /**
+   * A boolean telling if the client is a CAS proxy or not. Written by CASClient::CASClient(), 
+   * read by CASClient::isProxy().
+   *
+   * @private
+   */
+  var $_proxy;
+  
+  /**
+   * Tells if a CAS client is a CAS proxy or not
+   *
+   * @return TRUE when the CAS client is a CAs proxy, FALSE otherwise
+   *
+   * @private
+   */
+  function isProxy()
+    {
+      return $this->_proxy;
+    }
+
+  /** @} */
+  // ########################################################################
+  //  PGT
+  // ########################################################################
+  /**
+   * @addtogroup internalProxy
+   * @{
+   */  
+  
+  /**
+   * the Proxy Grnting Ticket given by the CAS server (empty otherwise). 
+   * Written by CASClient::setPGT(), read by CASClient::getPGT() and CASClient::hasPGT().
+   *
+   * @hideinitializer
+   * @private
+   */
+  var $_pgt = '';
+  
+  /**
+   * This method returns the Proxy Granting Ticket given by the CAS server.
+   * @return The Proxy Granting Ticket.
+   * @private
+   */
+  function getPGT()
+    { return $this->_pgt; }
+
+  /**
+   * This method stores the Proxy Granting Ticket.
+   * @param $pgt The Proxy Granting Ticket.
+   * @private
+   */
+  function setPGT($pgt)
+    { $this->_pgt = $pgt; }
+
+  /**
+   * This method tells if a Proxy Granting Ticket was stored.
+   * @return TRUE if a Proxy Granting Ticket has been stored.
+   * @private
+   */
+  function hasPGT()
+    { return !empty($this->_pgt); }
+
+  /** @} */
+
+  // ########################################################################
+  //  CALLBACK MODE
+  // ########################################################################
+  /**
+   * @addtogroup internalCallback
+   * @{
+   */  
+  /**
+   * each PHP script using phpCAS in proxy mode is its own callback to get the
+   * PGT back from the CAS server. callback_mode is detected by the constructor
+   * thanks to the GET parameters.
+   */
+
+  /**
+   * a boolean to know if the CAS client is running in callback mode. Written by
+   * CASClient::setCallBackMode(), read by CASClient::isCallbackMode().
+   *
+   * @hideinitializer
+   * @private
+   */
+  var $_callback_mode = FALSE;
+  
+  /**
+   * This method sets/unsets callback mode.
+   *
+   * @param $callback_mode TRUE to set callback mode, FALSE otherwise.
+   *
+   * @private
+   */
+  function setCallbackMode($callback_mode)
+    {
+      $this->_callback_mode = $callback_mode;
+    }
+
+  /**
+   * This method returns TRUE when the CAs client is running i callback mode, 
+   * FALSE otherwise.
+   *
+   * @return A boolean.
+   *
+   * @private
+   */
+  function isCallbackMode()
+    {
+      return $this->_callback_mode;
+    }
+
+  /**
+   * the URL that should be used for the PGT callback (in fact the URL of the 
+   * current request without any CGI parameter). Written and read by 
+   * CASClient::getCallbackURL().
+   *
+   * @hideinitializer
+   * @private
+   */
+  var $_callback_url = '';
+
+  /**
+   * This method returns the URL that should be used for the PGT callback (in
+   * fact the URL of the current request without any CGI parameter, except if
+   * phpCAS::setFixedCallbackURL() was used).
+   *
+   * @return The callback URL
+   *
+   * @private
+   */
+  function getCallbackURL()
+    {
+      // the URL is built when needed only
+      if ( empty($this->_callback_url) ) {
+        $final_uri = '';
+	    // remove the ticket if present in the URL
+	    $final_uri = 'https://';
+	    /* replaced by Julien Marchal - v0.4.6
+	     * $this->uri .= $_SERVER['SERVER_NAME'];
+	     */
+        if(empty($_SERVER['HTTP_X_FORWARDED_SERVER'])){
+          /* replaced by teedog - v0.4.12
+           * $final_uri .= $_SERVER['SERVER_NAME'];
+           */
+          if (empty($_SERVER['SERVER_NAME'])) {
+            $final_uri .= $_SERVER['HTTP_HOST'];
+          } else {
+            $final_uri .= $_SERVER['SERVER_NAME'];
+          }
+        } else {
+          $final_uri .= $_SERVER['HTTP_X_FORWARDED_SERVER'];
+        }
+	    if ( ($_SERVER['HTTPS']=='on' && $_SERVER['SERVER_PORT']!=443)
+	       || ($_SERVER['HTTPS']!='on' && $_SERVER['SERVER_PORT']!=80) ) {
+	      $final_uri .= ':';
+	      $final_uri .= $_SERVER['SERVER_PORT'];
+	    }
+	    $request_uri = $_SERVER['REQUEST_URI'];
+	    $request_uri = preg_replace('/\?.*$/','',$request_uri);
+	    $final_uri .= $request_uri;
+	    $this->setCallbackURL($final_uri);
+      }
+      return $this->_callback_url;
+    }
+
+  /**
+   * This method sets the callback url.
+   *
+   * @param $callback_url url to set callback 
+   *
+   * @private
+   */
+  function setCallbackURL($url)
+    {
+      return $this->_callback_url = $url;
+    }
+
+  /**
+   * This method is called by CASClient::CASClient() when running in callback
+   * mode. It stores the PGT and its PGT Iou, prints its output and halts.
+   *
+   * @private
+   */
+  function callback()
+    {
+      phpCAS::traceBegin();
+      $this->printHTMLHeader('phpCAS callback');
+      $pgt_iou = $_GET['pgtIou'];
+      $pgt = $_GET['pgtId'];
+      phpCAS::trace('Storing PGT `'.$pgt.'\' (id=`'.$pgt_iou.'\')');
+      echo '<p>Storing PGT `'.$pgt.'\' (id=`'.$pgt_iou.'\').</p>';
+      $this->storePGT($pgt,$pgt_iou);
+      $this->printHTMLFooter();
+      phpCAS::traceExit();
+    }
+
+  /** @} */
+
+  // ########################################################################
+  //  PGT STORAGE
+  // ########################################################################
+  /**
+   * @addtogroup internalPGTStorage
+   * @{
+   */  
+    
+  /**
+   * an instance of a class inheriting of PGTStorage, used to deal with PGT
+   * storage. Created by CASClient::setPGTStorageFile() or CASClient::setPGTStorageDB(), used 
+   * by CASClient::setPGTStorageFile(), CASClient::setPGTStorageDB() and CASClient::initPGTStorage().
+   *
+   * @hideinitializer
+   * @private
+   */
+  var $_pgt_storage = null;
+
+  /**
+   * This method is used to initialize the storage of PGT's.
+   * Halts on error.
+   *
+   * @private
+   */
+  function initPGTStorage()
+    {
+      // if no SetPGTStorageXxx() has been used, default to file
+      if ( !is_object($this->_pgt_storage) ) {
+	$this->setPGTStorageFile();
+      }
+
+      // initializes the storage
+      $this->_pgt_storage->init();
+    }
+  
+  /**
+   * This method stores a PGT. Halts on error.
+   *
+   * @param $pgt the PGT to store
+   * @param $pgt_iou its corresponding Iou
+   *
+   * @private
+   */
+  function storePGT($pgt,$pgt_iou)
+    {
+      // ensure that storage is initialized
+      $this->initPGTStorage();
+      // writes the PGT
+      $this->_pgt_storage->write($pgt,$pgt_iou);
+    }
+  
+  /**
+   * This method reads a PGT from its Iou and deletes the corresponding storage entry.
+   *
+   * @param $pgt_iou the PGT Iou
+   *
+   * @return The PGT corresponding to the Iou, FALSE when not found.
+   *
+   * @private
+   */
+  function loadPGT($pgt_iou)
+    {
+      // ensure that storage is initialized
+      $this->initPGTStorage();
+      // read the PGT
+      return $this->_pgt_storage->read($pgt_iou);
+    }
+  
+  /**
+   * This method is used to tell phpCAS to store the response of the
+   * CAS server to PGT requests onto the filesystem. 
+   *
+   * @param $format the format used to store the PGT's (`plain' and `xml' allowed)
+   * @param $path the path where the PGT's should be stored
+   *
+   * @public
+   */
+  function setPGTStorageFile($format='',
+			     $path='')
+    {
+      // check that the storage has not already been set
+      if ( is_object($this->_pgt_storage) ) {
+	phpCAS::error('PGT storage already defined');
+      }
+
+      // create the storage object
+      $this->_pgt_storage = &new PGTStorageFile($this,$format,$path);
+    }
+  
+  /**
+   * This method is used to tell phpCAS to store the response of the
+   * CAS server to PGT requests into a database. 
+   * @note The connection to the database is done only when needed. 
+   * As a consequence, bad parameters are detected only when 
+   * initializing PGT storage.
+   *
+   * @param $user the user to access the data with
+   * @param $password the user's password
+   * @param $database_type the type of the database hosting the data
+   * @param $hostname the server hosting the database
+   * @param $port the port the server is listening on
+   * @param $database the name of the database
+   * @param $table the name of the table storing the data
+   *
+   * @public
+   */
+  function setPGTStorageDB($user,
+			   $password,
+			   $database_type,
+			   $hostname,
+			   $port,
+			   $database,
+			   $table)
+    {
+      // check that the storage has not already been set
+      if ( is_object($this->_pgt_storage) ) {
+	phpCAS::error('PGT storage already defined');
+      }
+
+      // warn the user that he should use file storage...
+      trigger_error('PGT storage into database is an experimental feature, use at your own risk',E_USER_WARNING);
+
+      // create the storage object
+      $this->_pgt_storage = & new PGTStorageDB($this,$user,$password,$database_type,$hostname,$port,$database,$table);
+    }
+  
+  // ########################################################################
+  //  PGT VALIDATION
+  // ########################################################################
+  /**
+   * This method is used to validate a PGT; halt on failure.
+   * 
+   * @param $validate_url the URL of the request to the CAS server.
+   * @param $text_response the response of the CAS server, as is (XML text); result
+   * of CASClient::validateST() or CASClient::validatePT().
+   * @param $tree_response the response of the CAS server, as a DOM XML tree; result
+   * of CASClient::validateST() or CASClient::validatePT().
+   *
+   * @return bool TRUE when successfull, halt otherwise by calling CASClient::authError().
+   *
+   * @private
+   */
+  function validatePGT(&$validate_url,$text_response,$tree_response)
+    {
+      phpCAS::traceBegin();
+      if ( sizeof($arr = $tree_response->get_elements_by_tagname("proxyGrantingTicket")) == 0) {
+	phpCAS::trace('<proxyGrantingTicket> not found');
+	// authentication succeded, but no PGT Iou was transmitted
+	$this->authError('Ticket validated but no PGT Iou transmitted',
+		     $validate_url,
+		     FALSE/*$no_response*/,
+		     FALSE/*$bad_response*/,
+		     $text_response);
+      } else {
+	// PGT Iou transmitted, extract it
+	$pgt_iou = trim($arr[0]->get_content());
+	$pgt = $this->loadPGT($pgt_iou);
+	if ( $pgt == FALSE ) {
+	  phpCAS::trace('could not load PGT');
+	  $this->authError('PGT Iou was transmitted but PGT could not be retrieved',
+		       $validate_url,
+		       FALSE/*$no_response*/,
+		       FALSE/*$bad_response*/,
+		       $text_response);
+	}
+	$this->setPGT($pgt);
+      }
+      phpCAS::traceEnd(TRUE);
+      return TRUE;
+    }
+
+  // ########################################################################
+  //  PGT VALIDATION
+  // ########################################################################
+
+  /**
+   * This method is used to retrieve PT's from the CAS server thanks to a PGT.
+   * 
+   * @param $target_service the service to ask for with the PT.
+   * @param $err_code an error code (PHPCAS_SERVICE_OK on success).
+   * @param $err_msg an error message (empty on success).
+   *
+   * @return a Proxy Ticket, or FALSE on error.
+   *
+   * @private
+   */
+  function retrievePT($target_service,&$err_code,&$err_msg)
+    {
+      phpCAS::traceBegin();
+
+      // by default, $err_msg is set empty and $pt to TRUE. On error, $pt is
+      // set to false and $err_msg to an error message. At the end, if $pt is FALSE 
+      // and $error_msg is still empty, it is set to 'invalid response' (the most
+      // commonly encountered error).
+      $err_msg = '';
+
+      // build the URL to retrieve the PT
+      $cas_url = $this->getServerProxyURL().'?targetService='.preg_replace('/&/','%26',$target_service).'&pgt='.$this->getPGT();
+
+      // open and read the URL
+      if ( !$this->readURL($cas_url,''/*cookies*/,$headers,$cas_response,$err_msg) ) {
+	phpCAS::trace('could not open URL \''.$cas_url.'\' to validate ('.$err_msg.')');
+	$err_code = PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE;
+	$err_msg = 'could not retrieve PT (no response from the CAS server)';
+	phpCAS::traceEnd(FALSE);
+	return FALSE;
+      }
+
+      $bad_response = FALSE;
+
+      if ( !$bad_response ) {
+	// read the response of the CAS server into a DOM object
+	if ( !($dom = @domxml_open_mem($cas_response))) {
+	  phpCAS::trace('domxml_open_mem() failed');
+	  // read failed
+	  $bad_response = TRUE;
+	} 
+      }
+
+      if ( !$bad_response ) {
+	// read the root node of the XML tree
+	if ( !($root = $dom->document_element()) ) {
+	  phpCAS::trace('document_element() failed');
+	  // read failed
+	  $bad_response = TRUE;
+	} 
+      }
+
+      if ( !$bad_response ) {
+	// insure that tag name is 'serviceResponse'
+	if ( $root->node_name() != 'serviceResponse' ) {
+	  phpCAS::trace('node_name() failed');
+	  // bad root node
+	  $bad_response = TRUE;
+	} 
+      }
+
+      if ( !$bad_response ) {
+	// look for a proxySuccess tag
+	if ( sizeof($arr = $root->get_elements_by_tagname("proxySuccess")) != 0) {
+	  // authentication succeded, look for a proxyTicket tag
+	  if ( sizeof($arr = $root->get_elements_by_tagname("proxyTicket")) != 0) {
+	    $err_code = PHPCAS_SERVICE_OK;
+	    $err_msg = '';
+	    $pt = trim($arr[0]->get_content());
+	    phpCAS::traceEnd($pt);
+	    return $pt;
+	  } else {
+	    phpCAS::trace('<proxySuccess> was found, but not <proxyTicket>');
+	  }
+	} 
+	// look for a proxyFailure tag
+	else if ( sizeof($arr = $root->get_elements_by_tagname("proxyFailure")) != 0) {
+	  // authentication failed, extract the error
+	  $err_code = PHPCAS_SERVICE_PT_FAILURE;
+	  $err_msg = 'PT retrieving failed (code=`'
+	    .$arr[0]->get_attribute('code')
+	    .'\', message=`'
+	    .trim($arr[0]->get_content())
+	    .'\')';
+	  phpCAS::traceEnd(FALSE);
+	  return FALSE;
+	} else {
+	  phpCAS::trace('neither <proxySuccess> nor <proxyFailure> found');
+	}
+      }
+
+      // at this step, we are sure that the response of the CAS server was ill-formed
+      $err_code = PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE;
+      $err_msg = 'Invalid response from the CAS server (response=`'.$cas_response.'\')';
+
+      phpCAS::traceEnd(FALSE);
+      return FALSE;
+    }
+
+  // ########################################################################
+  // ACCESS TO EXTERNAL SERVICES
+  // ########################################################################
+
+  /**
+   * This method is used to acces a remote URL.
+   *
+   * @param $url the URL to access.
+   * @param $cookies an array containing cookies strings such as 'name=val'
+   * @param $headers an array containing the HTTP header lines of the response
+   * (an empty array on failure).
+   * @param $body the body of the response, as a string (empty on failure).
+   * @param $err_msg an error message, filled on failure.
+   *
+   * @return TRUE on success, FALSE otherwise (in this later case, $err_msg
+   * contains an error message).
+   *
+   * @private
+   */
+  function readURL($url,$cookies,&$headers,&$body,&$err_msg)
+    {
+      phpCAS::traceBegin();
+      $headers = '';
+      $body = '';
+      $err_msg = '';
+
+      $res = TRUE;
+
+      // initialize the CURL session
+      $ch = curl_init($url);
+	
+	  // verify the the server's certificate corresponds to its name
+	  curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1);
+	  // but do not verify the certificate itself
+	  curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
+
+      // return the CURL output into a variable
+      curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+      // include the HTTP header with the body
+      curl_setopt($ch, CURLOPT_HEADER, 1);
+      // add cookies headers
+      if ( is_array($cookies) ) {
+	curl_setopt($ch,CURLOPT_COOKIE,implode(';',$cookies));
+      }
+      // perform the query
+      $buf = curl_exec ($ch);
+      if ( $buf === FALSE ) {
+	phpCAS::trace('cur_exec() failed');
+	$err_msg = 'CURL error #'.curl_errno($ch).': '.curl_error($ch);
+	// close the CURL session
+	curl_close ($ch);
+	$res = FALSE;
+      } else {
+	// close the CURL session
+	curl_close ($ch);
+	
+	// find the end of the headers
+	// note: strpos($str,"\n\r\n\r") does not work (?)
+	$pos = FALSE;
+	for ($i=0; $i<strlen($buf); $i++) {
+	  if ( $buf[$i] == chr(13) ) 
+	    if ( $buf[$i+1] == chr(10) ) 
+	      if ( $buf[$i+2] == chr(13) ) 
+		if ( $buf[$i+3] == chr(10) ) {
+		  // header found
+		  $pos = $i;
+		  break;
+		}
+	}
+	
+	if ( $pos === FALSE ) {
+	  // end of header not found
+	  $err_msg = 'no header found';
+	  phpCAS::trace($err_msg);
+	  $res = FALSE;
+	} else { 
+	  // extract headers into an array
+	  $headers = preg_split ("/[\n\r]+/",substr($buf,0,$pos));	  
+	  // extract body into a string
+	  $body = substr($buf,$pos+4);
+	}
+      }
+
+      phpCAS::traceEnd($res);
+      return $res;
+    }
+
+  /**
+   * This method is used to access an HTTP[S] service.
+   * 
+   * @param $url the service to access.
+   * @param $err_code an error code Possible values are PHPCAS_SERVICE_OK (on
+   * success), PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE, PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE,
+   * PHPCAS_SERVICE_PT_FAILURE, PHPCAS_SERVICE_NOT AVAILABLE.
+   * @param $output the output of the service (also used to give an error
+   * message on failure).
+   *
+   * @return TRUE on success, FALSE otherwise (in this later case, $err_code
+   * gives the reason why it failed and $output contains an error message).
+   *
+   * @public
+   */
+  function serviceWeb($url,&$err_code,&$output)
+    {
+      phpCAS::traceBegin();
+      // at first retrieve a PT
+      $pt = $this->retrievePT($url,$err_code,$output);
+
+      $res = TRUE;
+      
+      // test if PT was retrieved correctly
+      if ( !$pt ) {
+	// note: $err_code and $err_msg are filled by CASClient::retrievePT()
+	phpCAS::trace('PT was not retrieved correctly');
+	$res = FALSE;
+      } else {
+	// add cookies if necessary
+	if ( is_array($_SESSION['phpCAS']['services'][$url]['cookies']) ) {
+	  foreach ( $_SESSION['phpCAS']['services'][$url]['cookies'] as $name => $val ) { 
+	    $cookies[] = $name.'='.$val;
+	  }
+	}
+	
+	// build the URL including the PT
+	if ( strstr($url,'?') === FALSE ) {
+	  $service_url = $url.'?ticket='.$pt;
+	} else {
+	  $service_url = $url.'&ticket='.$pt;
+	}
+	
+	phpCAS::trace('reading URL`'.$service_url.'\'');
+	if ( !$this->readURL($service_url,$cookies,$headers,$output,$err_msg) ) {
+	  phpCAS::trace('could not read URL`'.$service_url.'\'');
+	  $err_code = PHPCAS_SERVICE_NOT_AVAILABLE;
+	  // give an error message
+	  $output = sprintf($this->getString(CAS_STR_SERVICE_UNAVAILABLE),
+			    $service_url,
+			    $err_msg);
+	  $res = FALSE;
+	} else {
+	  // URL has been fetched, extract the cookies
+	  phpCAS::trace('URL`'.$service_url.'\' has been read, storing cookies:');
+	  foreach ( $headers as $header ) {
+	    // test if the header is a cookie
+	    if ( preg_match('/^Set-Cookie:/',$header) ) {
+	      // the header is a cookie, remove the beginning
+	      $header_val = preg_replace('/^Set-Cookie: */','',$header);
+	      // extract interesting information
+	      $name_val = strtok($header_val,'; ');
+	      // extract the name and the value of the cookie
+	      $cookie_name = strtok($name_val,'=');
+	      $cookie_val = strtok('=');
+	      // store the cookie 
+	      $_SESSION['phpCAS']['services'][$url]['cookies'][$cookie_name] = $cookie_val;
+	      phpCAS::trace($cookie_name.' -> '.$cookie_val);
+	    }
+	  }
+	}
+      }
+
+      phpCAS::traceEnd($res);
+      return $res;
+  }
+
+  /**
+   * This method is used to access an IMAP/POP3/NNTP service.
+   * 
+   * @param $url a string giving the URL of the service, including the mailing box
+   * for IMAP URLs, as accepted by imap_open().
+   * @param $flags options given to imap_open().
+   * @param $err_code an error code Possible values are PHPCAS_SERVICE_OK (on
+   * success), PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE, PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE,
+   * PHPCAS_SERVICE_PT_FAILURE, PHPCAS_SERVICE_NOT AVAILABLE.
+   * @param $err_msg an error message on failure
+   * @param $pt the Proxy Ticket (PT) retrieved from the CAS server to access the URL
+   * on success, FALSE on error).
+   *
+   * @return an IMAP stream on success, FALSE otherwise (in this later case, $err_code
+   * gives the reason why it failed and $err_msg contains an error message).
+   *
+   * @public
+   */
+  function serviceMail($url,$flags,&$err_code,&$err_msg,&$pt)
+    {
+      phpCAS::traceBegin();
+      // at first retrieve a PT
+      $pt = $this->retrievePT($target_service,$err_code,$output);
+
+      $stream = FALSE;
+      
+      // test if PT was retrieved correctly
+      if ( !$pt ) {
+	// note: $err_code and $err_msg are filled by CASClient::retrievePT()
+	phpCAS::trace('PT was not retrieved correctly');
+      } else {
+	phpCAS::trace('opening IMAP URL `'.$url.'\'...');
+	$stream = @imap_open($url,$this->getUser(),$pt,$flags);
+	if ( !$stream ) {
+	  phpCAS::trace('could not open URL');
+	  $err_code = PHPCAS_SERVICE_NOT_AVAILABLE;
+	  // give an error message
+	  $err_msg = sprintf($this->getString(CAS_STR_SERVICE_UNAVAILABLE),
+			     $service_url,
+			     var_export(imap_errors(),TRUE));
+	  $pt = FALSE;
+	  $stream = FALSE;
+	} else {
+	  phpCAS::trace('ok');
+	}
+      }
+
+      phpCAS::traceEnd($stream);
+      return $stream;
+  }
+
+  /** @} */
+
+  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+  // XX                                                                    XX
+  // XX                  PROXIED CLIENT FEATURES (CAS 2.0)                 XX
+  // XX                                                                    XX
+  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+  // ########################################################################
+  //  PT
+  // ########################################################################
+  /**
+   * @addtogroup internalProxied
+   * @{
+   */  
+  
+  /**
+   * the Proxy Ticket provided in the URL of the request if present
+   * (empty otherwise). Written by CASClient::CASClient(), read by 
+   * CASClient::getPT() and CASClient::hasPGT().
+   *
+   * @hideinitializer
+   * @private
+   */
+  var $_pt = '';
+  
+  /**
+   * This method returns the Proxy Ticket provided in the URL of the request.
+   * @return The proxy ticket.
+   * @private
+   */
+  function getPT()
+    { return $this->_pt; }
+
+  /**
+   * This method stores the Proxy Ticket.
+   * @param $pt The Proxy Ticket.
+   * @private
+   */
+  function setPT($pt)
+    { $this->_pt = $pt; }
+
+  /**
+   * This method tells if a Proxy Ticket was stored.
+   * @return TRUE if a Proxy Ticket has been stored.
+   * @private
+   */
+  function hasPT()
+    { return !empty($this->_pt); }
+
+  /** @} */
+  // ########################################################################
+  //  PT VALIDATION
+  // ########################################################################
+  /**
+   * @addtogroup internalProxied
+   * @{
+   */  
+
+  /**
+   * This method is used to validate a PT; halt on failure
+   * 
+   * @return bool TRUE when successfull, halt otherwise by calling CASClient::authError().
+   *
+   * @private
+   */
+  function validatePT(&$validate_url,&$text_response,&$tree_response)
+    {
+      phpCAS::traceBegin();
+      // build the URL to validate the ticket
+      $validate_url = $this->getServerProxyValidateURL().'&ticket='.$this->getPT();
+
+      if ( $this->isProxy() ) {
+      // pass the callback url for CAS proxies
+	$validate_url .= '&pgtUrl='.$this->getCallbackURL();
+      }
+
+      // open and read the URL
+      if ( !$this->readURL($validate_url,''/*cookies*/,$headers,$text_response,$err_msg) ) {
+	phpCAS::trace('could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')');
+	$this->authError('PT not validated',
+			 $validate_url,
+			 TRUE/*$no_response*/);
+      }
+
+      // read the response of the CAS server into a DOM object
+      if ( !($dom = domxml_open_mem($text_response))) {
+	// read failed
+	$this->authError('PT not validated',
+		     $validate_url,
+		     FALSE/*$no_response*/,
+		     TRUE/*$bad_response*/,
+		     $text_response);
+      }
+      // read the root node of the XML tree
+      if ( !($tree_response = $dom->document_element()) ) {
+	// read failed
+	$this->authError('PT not validated',
+		     $validate_url,
+		     FALSE/*$no_response*/,
+		     TRUE/*$bad_response*/,
+		     $text_response);
+      }
+      // insure that tag name is 'serviceResponse'
+      if ( $tree_response->node_name() != 'serviceResponse' ) {
+	// bad root node
+	$this->authError('PT not validated',
+		     $validate_url,
+		     FALSE/*$no_response*/,
+		     TRUE/*$bad_response*/,
+		     $text_response);
+      }
+      if ( sizeof($arr = $tree_response->get_elements_by_tagname("authenticationSuccess")) != 0) {
+	// authentication succeded, extract the user name
+	if ( sizeof($arr = $tree_response->get_elements_by_tagname("user")) == 0) {
+	  // no user specified => error
+	  $this->authError('PT not validated',
+		       $validate_url,
+		       FALSE/*$no_response*/,
+		       TRUE/*$bad_response*/,
+		       $text_response);
+	}
+	$this->setUser(trim($arr[0]->get_content()));
+	
+      } else if ( sizeof($arr = $tree_response->get_elements_by_tagname("authenticationFailure")) != 0) {
+	// authentication succeded, extract the error code and message
+	$this->authError('PT not validated',
+		     $validate_url,
+		     FALSE/*$no_response*/,
+		     FALSE/*$bad_response*/,
+		     $text_response,
+		     $arr[0]->get_attribute('code')/*$err_code*/,
+		     trim($arr[0]->get_content())/*$err_msg*/);
+      } else {
+	$this->authError('PT not validated',
+		     $validate_url,	
+		     FALSE/*$no_response*/,
+		     TRUE/*$bad_response*/,
+		     $text_response);
+      }
+      
+      // at this step, PT has been validated and $this->_user has been set,
+
+      phpCAS::traceEnd(TRUE);
+      return TRUE;
+    }
+
+  /** @} */
+
+  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+  // XX                                                                    XX
+  // XX                               MISC                                 XX
+  // XX                                                                    XX
+  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+  /**
+   * @addtogroup internalMisc
+   * @{
+   */  
+  
+  // ########################################################################
+  //  URL
+  // ########################################################################
+  /**
+   * the URL of the current request (without any ticket CGI parameter). Written 
+   * and read by CASClient::getURL().
+   *
+   * @hideinitializer
+   * @private
+   */
+  var $_url = '';
+
+  /**
+   * This method returns the URL of the current request (without any ticket
+   * CGI parameter).
+   *
+   * @return The URL
+   *
+   * @private
+   */
+  function getURL()
+    {
+      phpCAS::traceBegin();
+      // the URL is built when needed only
+      if ( empty($this->_url) ) {
+	    $final_uri = '';
+	    // remove the ticket if present in the URL
+	    $final_uri = ($_SERVER['HTTPS'] == 'on') ? 'https' : 'http';
+	    $final_uri .= '://';
+	    /* replaced by Julien Marchal - v0.4.6
+	     * $this->_url .= $_SERVER['SERVER_NAME'];
+	     */
+        if(empty($_SERVER['HTTP_X_FORWARDED_SERVER'])){
+          /* replaced by teedog - v0.4.12
+           * $this->_url .= $_SERVER['SERVER_NAME'];
+           */
+          if (empty($_SERVER['SERVER_NAME'])) {
+            $final_uri .= $_SERVER['HTTP_HOST'];
+          } else {
+            $final_uri .= $_SERVER['SERVER_NAME'];
+          }
+        } else {
+          $final_uri .= $_SERVER['HTTP_X_FORWARDED_SERVER'];
+        }
+	  if ( ($_SERVER['HTTPS']=='on' && $_SERVER['SERVER_PORT']!=443)
+	     || ($_SERVER['HTTPS']!='on' && $_SERVER['SERVER_PORT']!=80) ) {
+	    $final_uri .= ':';
+	    $final_uri .= $_SERVER['SERVER_PORT'];
+	  }
+
+	  $final_uri .= strtok($_SERVER['REQUEST_URI'],"?");
+	  $cgi_params = '?'.strtok("?");
+	  // remove the ticket if present in the CGI parameters
+	  $cgi_params = preg_replace('/&ticket=[^&]*/','',$cgi_params);
+	  $cgi_params = preg_replace('/\?ticket=[^&;]*/','?',$cgi_params);
+	  $cgi_params = preg_replace('/\?%26/','?',$cgi_params);
+	  $cgi_params = preg_replace('/\?&/','?',$cgi_params);
+	  $cgi_params = preg_replace('/\?$/','',$cgi_params);
+	  $final_uri .= $cgi_params;
+	  $this->setURL($final_uri);
+    }
+    phpCAS::traceEnd($this->_url);
+    return $this->_url;
+  }
+
+  /**
+   * This method sets the URL of the current request 
+   *
+   * @param $url url to set for service
+   *
+   * @private
+   */
+  function setURL($url)
+    {
+      $this->_url = $url;
+    }
+  
+  // ########################################################################
+  //  AUTHENTICATION ERROR HANDLING
+  // ########################################################################
+  /**
+   * This method is used to print the HTML output when the user was not authenticated.
+   *
+   * @param $failure the failure that occured
+   * @param $cas_url the URL the CAS server was asked for
+   * @param $no_response the response from the CAS server (other 
+   * parameters are ignored if TRUE)
+   * @param $bad_response bad response from the CAS server ($err_code
+   * and $err_msg ignored if TRUE)
+   * @param $cas_response the response of the CAS server
+   * @param $err_code the error code given by the CAS server
+   * @param $err_msg the error message given by the CAS server
+   *
+   * @private
+   */
+  function authError($failure,$cas_url,$no_response,$bad_response='',$cas_response='',$err_code='',$err_msg='')
+    {
+      phpCAS::traceBegin();
+
+      $this->printHTMLHeader($this->getString(CAS_STR_AUTHENTICATION_FAILED));
+      printf($this->getString(CAS_STR_YOU_WERE_NOT_AUTHENTICATED),$this->getURL(),$_SERVER['SERVER_ADMIN']);
+      phpCAS::trace('CAS URL: '.$cas_url);
+      phpCAS::trace('Authentication failure: '.$failure);
+      if ( $no_response ) {
+	phpCAS::trace('Reason: no response from the CAS server');
+      } else {
+	if ( $bad_response ) {
+	    phpCAS::trace('Reason: bad response from the CAS server');
+	} else {
+	  switch ($this->getServerVersion()) {
+	  case CAS_VERSION_1_0:
+	    phpCAS::trace('Reason: CAS error');
+	    break;
+	  case CAS_VERSION_2_0:
+	    if ( empty($err_code) )
+	      phpCAS::trace('Reason: no CAS error');
+	    else
+	      phpCAS::trace('Reason: ['.$err_code.'] CAS error: '.$err_msg);
+	    break;
+	  }
+	}
+	phpCAS::trace('CAS response: '.$cas_response);
+      }
+      $this->printHTMLFooter();
+      phpCAS::traceExit();
+      exit();
+    }
+
+  /** @} */
+}
+
+?>
\ No newline at end of file
diff --git a/cas_auth/cas/domxml-php4-php5.php b/cas_auth/cas/domxml-php4-php5.php
new file mode 100644
index 0000000000000000000000000000000000000000..be4b65937de8913aadcd5f03fcb81ad3def9f3a9
--- /dev/null
+++ b/cas_auth/cas/domxml-php4-php5.php
@@ -0,0 +1,279 @@
+<?php // $Id: domxml-php4-php5.php 9707 2007-12-12 13:46:31Z mlaurent $
+if ( count( get_included_files() ) == 1 ) die( '---' );
+
+/**
+ * @file domxml-php4-php5.php
+ * Require PHP5, uses built-in DOM extension.
+ * To be used in PHP4 scripts using DOMXML extension.
+ * Allows PHP4/DOMXML scripts to run on PHP5/DOM.
+ * (Requires PHP5/XSL extension for domxml_xslt functions)
+ *
+ * Typical use:
+ * <pre>
+ * {
+ *  if (version_compare(PHP_VERSION,'5','>='))
+ *   require_once('domxml-php4-to-php5.php');
+ * }
+ * </pre>
+ *
+ * Version 1.5.5, 2005-01-18, http://alexandre.alapetite.net/doc-alex/domxml-php4-php5/
+ *
+ * ------------------------------------------------------------------<br>
+ * Written by Alexandre Alapetite, http://alexandre.alapetite.net/cv/
+ *
+ * Copyright 2004, Licence: Creative Commons "Attribution-ShareAlike 2.0 France" BY-SA (FR),
+ * http://creativecommons.org/licenses/by-sa/2.0/fr/
+ * http://alexandre.alapetite.net/divers/apropos/#by-sa
+ * - Attribution. You must give the original author credit
+ * - Share Alike. If you alter, transform, or build upon this work,
+ *   you may distribute the resulting work only under a license identical to this one
+ * - The French law is authoritative
+ * - Any of these conditions can be waived if you get permission from Alexandre Alapetite
+ * - Please send to Alexandre Alapetite the modifications you make,
+ *   in order to improve this file for the benefit of everybody
+ *
+ * If you want to distribute this code, please do it as a link to:
+ * http://alexandre.alapetite.net/doc-alex/domxml-php4-php5/
+ */
+
+function domxml_new_doc($version) {return new php4DOMDocument('');}
+function domxml_open_file($filename) {return new php4DOMDocument($filename);}
+function domxml_open_mem($str)
+{
+ $dom=new php4DOMDocument('');
+ $dom->myDOMNode->loadXML($str);
+ return $dom;
+}
+function xpath_eval($xpath_context,$eval_str,$contextnode=null) {return $xpath_context->query($eval_str,$contextnode);}
+function xpath_new_context($dom_document) {return new php4DOMXPath($dom_document);}
+
+class php4DOMAttr extends php4DOMNode
+{
+ function php4DOMAttr($aDOMAttr) {$this->myDOMNode=$aDOMAttr;}
+ function Name() {return $this->myDOMNode->name;}
+ function Specified() {return $this->myDOMNode->specified;}
+ function Value() {return $this->myDOMNode->value;}
+}
+
+class php4DOMDocument extends php4DOMNode
+{
+ function php4DOMDocument($filename='')
+ {
+  $this->myDOMNode=new DOMDocument();
+  if ($filename!='') $this->myDOMNode->load($filename);
+ }
+ function create_attribute($name,$value)
+ {
+  $myAttr=$this->myDOMNode->createAttribute($name);
+  $myAttr->value=$value;
+  return new php4DOMAttr($myAttr,$this);
+ }
+ function create_cdata_section($content) {return new php4DOMNode($this->myDOMNode->createCDATASection($content),$this);}
+ function create_comment($data) {return new php4DOMNode($this->myDOMNode->createComment($data),$this);}
+ function create_element($name) {return new php4DOMElement($this->myDOMNode->createElement($name),$this);}
+ function create_text_node($content) {return new php4DOMNode($this->myDOMNode->createTextNode($content),$this);}
+ function document_element() {return new php4DOMElement($this->myDOMNode->documentElement,$this);}
+ function dump_file($filename,$compressionmode=false,$format=false) {return $this->myDOMNode->save($filename);}
+ function dump_mem($format=false,$encoding=false) {return $this->myDOMNode->saveXML();}
+ function get_element_by_id($id) {return new php4DOMElement($this->myDOMNode->getElementById($id),$this);}
+ function get_elements_by_tagname($name)
+ {
+  $myDOMNodeList=$this->myDOMNode->getElementsByTagName($name);
+  $nodeSet=array();
+  $i=0;
+  if (isset($myDOMNodeList))
+   while ($node=$myDOMNodeList->item($i))
+   {
+    $nodeSet[]=new php4DOMElement($node,$this);
+    $i++;
+   }
+  return $nodeSet;
+ }
+ function html_dump_mem() {return $this->myDOMNode->saveHTML();}
+ function root() {return new php4DOMElement($this->myDOMNode->documentElement,$this);}
+}
+
+class php4DOMElement extends php4DOMNode
+{
+ function get_attribute($name) {return $this->myDOMNode->getAttribute($name);}
+ function get_elements_by_tagname($name)
+ {
+  $myDOMNodeList=$this->myDOMNode->getElementsByTagName($name);
+  $nodeSet=array();
+  $i=0;
+  if (isset($myDOMNodeList))
+   while ($node=$myDOMNodeList->item($i))
+   {
+    $nodeSet[]=new php4DOMElement($node,$this->myOwnerDocument);
+    $i++;
+   }
+  return $nodeSet;
+ }
+ function has_attribute($name) {return $this->myDOMNode->hasAttribute($name);}
+ function remove_attribute($name) {return $this->myDOMNode->removeAttribute($name);}
+ function set_attribute($name,$value) {return $this->myDOMNode->setAttribute($name,$value);}
+ function tagname() {return $this->myDOMNode->tagName;}
+}
+
+class php4DOMNode
+{
+ var $myDOMNode;
+ var $myOwnerDocument;
+ function php4DOMNode($aDomNode,$aOwnerDocument)
+ {
+  $this->myDOMNode=$aDomNode;
+  $this->myOwnerDocument=$aOwnerDocument;
+ }
+ function __get($name)
+ {
+  if ($name=='type') return $this->myDOMNode->nodeType;
+  elseif ($name=='tagname') return $this->myDOMNode->tagName;
+  elseif ($name=='content') return $this->myDOMNode->textContent;
+  else
+  {
+   $myErrors=debug_backtrace();
+   trigger_error('Undefined property: '.get_class($this).'::$'.$name.' ['.$myErrors[0]['file'].':'.$myErrors[0]['line'].']',E_USER_NOTICE);
+   return false;
+  }
+ }
+ function append_child($newnode) {return new php4DOMElement($this->myDOMNode->appendChild($newnode->myDOMNode),$this->myOwnerDocument);}
+ function append_sibling($newnode) {return new php4DOMElement($this->myDOMNode->parentNode->appendChild($newnode->myDOMNode),$this->myOwnerDocument);}
+ function attributes()
+ {
+  $myDOMNodeList=$this->myDOMNode->attributes;
+  $nodeSet=array();
+  $i=0;
+  if (isset($myDOMNodeList))
+   while ($node=$myDOMNodeList->item($i))
+   {
+    $nodeSet[]=new php4DOMAttr($node,$this->myOwnerDocument);
+    $i++;
+   }
+  return $nodeSet;
+ }
+ function child_nodes()
+ {
+  $myDOMNodeList=$this->myDOMNode->childNodes;
+  $nodeSet=array();
+  $i=0;
+  if (isset($myDOMNodeList))
+   while ($node=$myDOMNodeList->item($i))
+   {
+    $nodeSet[]=new php4DOMElement($node,$this->myOwnerDocument);
+    $i++;
+   }
+  return $nodeSet;
+ }
+ function children() {return $this->child_nodes();}
+ function clone_node($deep=false) {return new php4DOMElement($this->myDOMNode->cloneNode($deep),$this->myOwnerDocument);}
+ function first_child() {return new php4DOMElement($this->myDOMNode->firstChild,$this->myOwnerDocument);}
+ function get_content() {return $this->myDOMNode->textContent;}
+ function has_attributes() {return $this->myDOMNode->hasAttributes();}
+ function has_child_nodes() {return $this->myDOMNode->hasChildNodes();}
+ function insert_before($newnode,$refnode) {return new php4DOMElement($this->myDOMNode->insertBefore($newnode->myDOMNode,$refnode->myDOMNode),$this->myOwnerDocument);}
+ function is_blank_node()
+ {
+  $myDOMNodeList=$this->myDOMNode->childNodes;
+  $i=0;
+  if (isset($myDOMNodeList))
+   while ($node=$myDOMNodeList->item($i))
+   {
+    if (($node->nodeType==XML_ELEMENT_NODE)||
+        (($node->nodeType==XML_TEXT_NODE)&&!ereg('^([[:cntrl:]]|[[:space:]])*$',$node->nodeValue)))
+     return false;
+    $i++;
+   }
+  return true;
+ }
+ function last_child() {return new php4DOMElement($this->myDOMNode->lastChild,$this->myOwnerDocument);}
+ function new_child($name,$content)
+ {
+  $mySubNode=$this->myDOMNode->ownerDocument->createElement($name);
+  $mySubNode->appendChild($this->myDOMNode->ownerDocument->createTextNode($content));
+  $this->myDOMNode->appendChild($mySubNode);
+  return new php4DOMElement($mySubNode,$this->myOwnerDocument);
+ }
+ function next_sibling() {return new php4DOMElement($this->myDOMNode->nextSibling,$this->myOwnerDocument);}
+ function node_name() {return $this->myDOMNode->localName;}
+ function node_type() {return $this->myDOMNode->nodeType;}
+ function node_value() {return $this->myDOMNode->nodeValue;}
+ function owner_document() {return $this->myOwnerDocument;}
+ function parent_node() {return new php4DOMElement($this->myDOMNode->parentNode,$this->myOwnerDocument);}
+ function prefix() {return $this->myDOMNode->prefix;}
+ function previous_sibling() {return new php4DOMElement($this->myDOMNode->previousSibling,$this->myOwnerDocument);}
+ function remove_child($oldchild) {return new php4DOMElement($this->myDOMNode->removeChild($oldchild->myDOMNode),$this->myOwnerDocument);}
+ function replace_child($oldnode,$newnode) {return new php4DOMElement($this->myDOMNode->replaceChild($oldnode->myDOMNode,$newnode->myDOMNode),$this->myOwnerDocument);}
+ function set_content($text)
+ {
+  if (($this->myDOMNode->hasChildNodes())&&($this->myDOMNode->firstChild->nodeType==XML_TEXT_NODE))
+   $this->myDOMNode->removeChild($this->myDOMNode->firstChild);
+  return $this->myDOMNode->appendChild($this->myDOMNode->ownerDocument->createTextNode($text));
+ }
+}
+
+class php4DOMNodelist
+{
+ var $myDOMNodelist;
+ var $nodeset;
+ function php4DOMNodelist($aDOMNodelist,$aOwnerDocument)
+ {
+  $this->myDOMNodelist=$aDOMNodelist;
+  $this->nodeset=array();
+  $i=0;
+  if (isset($this->myDOMNodelist))
+   while ($node=$this->myDOMNodelist->item($i))
+   {
+    $this->nodeset[]=new php4DOMElement($node,$aOwnerDocument);
+    $i++;
+   }
+ }
+}
+
+class php4DOMXPath
+{
+ var $myDOMXPath;
+ var $myOwnerDocument;
+ function php4DOMXPath($dom_document)
+ {
+  $this->myOwnerDocument=$dom_document;
+  $this->myDOMXPath=new DOMXPath($dom_document->myDOMNode);
+ }
+ function query($eval_str,$contextnode)
+ {
+  if (isset($contextnode)) return new php4DOMNodelist($this->myDOMXPath->query($eval_str,$contextnode->myDOMNode),$this->myOwnerDocument);
+  else return new php4DOMNodelist($this->myDOMXPath->query($eval_str),$this->myOwnerDocument);
+ }
+ function xpath_register_ns($prefix,$namespaceURI) {return $this->myDOMXPath->registerNamespace($prefix,$namespaceURI);}
+}
+
+if (extension_loaded('xsl'))
+{//See also: http://alexandre.alapetite.net/doc-alex/xslt-php4-php5/
+ function domxml_xslt_stylesheet($xslstring) {return new php4DomXsltStylesheet(DOMDocument::loadXML($xslstring));}
+ function domxml_xslt_stylesheet_doc($dom_document) {return new php4DomXsltStylesheet($dom_document);}
+ function domxml_xslt_stylesheet_file($xslfile) {return new php4DomXsltStylesheet(DOMDocument::load($xslfile));}
+ class php4DomXsltStylesheet
+ {
+  var $myxsltProcessor;
+  function php4DomXsltStylesheet($dom_document)
+  {
+   $this->myxsltProcessor=new xsltProcessor();
+   $this->myxsltProcessor->importStyleSheet($dom_document);
+  }
+  function process($dom_document,$xslt_parameters=array(),$param_is_xpath=false)
+  {
+   foreach ($xslt_parameters as $param=>$value)
+    $this->myxsltProcessor->setParameter('',$param,$value);
+   $myphp4DOMDocument=new php4DOMDocument();
+   $myphp4DOMDocument->myDOMNode=$this->myxsltProcessor->transformToDoc($dom_document->myDOMNode);
+   return $myphp4DOMDocument;
+  }
+  function result_dump_file($dom_document,$filename)
+  {
+   $html=$dom_document->myDOMNode->saveHTML();
+   file_put_contents($filename,$html);
+   return $html;
+  }
+  function result_dump_mem($dom_document) {return $dom_document->myDOMNode->saveHTML();}
+ }
+}
+?>
\ No newline at end of file
diff --git a/cas_auth/cas/languages/english.php b/cas_auth/cas/languages/english.php
new file mode 100644
index 0000000000000000000000000000000000000000..8a191986a54a682eb5a9ae610591595aa1dab064
--- /dev/null
+++ b/cas_auth/cas/languages/english.php
@@ -0,0 +1,28 @@
+<?php // $Id: english.php 9707 2007-12-12 13:46:31Z mlaurent $
+if ( count( get_included_files() ) == 1 ) die( '---' );
+
+/**
+ * @file languages/english.php
+ * @author Pascal Aubry <pascal.aubry at univ-rennes1.fr>
+ * @sa @link internalLang Internationalization @endlink
+ * @ingroup internalLang
+ */
+
+$this->_strings = array(
+ CAS_STR_USING_SERVER
+ => 'using server',
+ CAS_STR_AUTHENTICATION_WANTED
+ => 'CAS Authentication wanted!',
+ CAS_STR_LOGOUT
+ => 'CAS logout wanted!',
+ CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED
+ => 'You should already have been redirected to the CAS server. Click <a href="%s">here</a> to continue.',
+ CAS_STR_AUTHENTICATION_FAILED
+ => 'CAS Authentication failed!',
+ CAS_STR_YOU_WERE_NOT_AUTHENTICATED
+ => '<p>You were not authenticated.</p><p>You may submit your request again by clicking <a href="%s">here</a>.</p><p>If the problem persists, you may contact <a href="mailto:%s">the administrator of this site</a>.</p>',
+ CAS_STR_SERVICE_UNAVAILABLE
+ => 'The service `<b>%s</b>\' is not available (<b>%s</b>).'
+);
+
+?>
\ No newline at end of file
diff --git a/cas_auth/cas/languages/french.php b/cas_auth/cas/languages/french.php
new file mode 100644
index 0000000000000000000000000000000000000000..d6b7d0c9e65a7987bd84be8ed8ea20372e51e462
--- /dev/null
+++ b/cas_auth/cas/languages/french.php
@@ -0,0 +1,29 @@
+<?php // $Id: french.php 9707 2007-12-12 13:46:31Z mlaurent $
+if ( count( get_included_files() ) == 1 ) die( '---' );
+
+/**
+ * @file languages/english.php
+ * @author Pascal Aubry <pascal.aubry at univ-rennes1.fr>
+ * @sa @link internalLang Internationalization @endlink
+ * @ingroup internalLang
+ */
+
+$this->_strings = array(
+ CAS_STR_USING_SERVER
+ => 'utilisant le serveur',
+ CAS_STR_AUTHENTICATION_WANTED
+ => 'Authentication CAS n�cessaire&nbsp;!',
+ CAS_STR_LOGOUT
+ => 'D�connexion demand�e&nbsp;!',
+ CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED
+ => 'Vous auriez du etre redirig�(e) vers le serveur CAS. Cliquez <a href="%s">ici</a> pour continuer.',
+ CAS_STR_AUTHENTICATION_FAILED
+ => 'Authentification CAS infructueuse&nbsp;!',
+ CAS_STR_YOU_WERE_NOT_AUTHENTICATED
+ => '<p>Vous n\'avez pas �t� authentifi�(e).</p><p>Vous pouvez soumettre votre requete � nouveau en cliquant <a href="%s">ici</a>.</p><p>Si le probl�me persiste, vous pouvez contacter <a href="mailto:%s">l\'administrateur de ce site</a>.</p>',
+ CAS_STR_SERVICE_UNAVAILABLE
+ => 'Le service `<b>%s</b>\' est indisponible (<b>%s</b>)'
+
+);
+
+?>
\ No newline at end of file
diff --git a/cas_auth/cas/languages/greek.php b/cas_auth/cas/languages/greek.php
new file mode 100644
index 0000000000000000000000000000000000000000..f5021c2160930d89e2662e1e90dd930034e14d9a
--- /dev/null
+++ b/cas_auth/cas/languages/greek.php
@@ -0,0 +1,28 @@
+<?php // $Id: greek.php 9707 2007-12-12 13:46:31Z mlaurent $
+if ( count( get_included_files() ) == 1 ) die( '---' );
+
+/**
+ * @file languages/greek.php
+ * @author Vangelis Haniotakis <haniotak at ucnet.uoc.gr>
+ * @sa @link internalLang Internationalization @endlink
+ * @ingroup internalLang
+ */
+
+$this->_strings = array(
+ CAS_STR_USING_SERVER
+ => '��������������� � ������������',
+ CAS_STR_AUTHENTICATION_WANTED
+ => '���������� � ����������� CAS!',
+ CAS_STR_LOGOUT
+ => '���������� � ���������� ��� CAS!',
+ CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED
+ => '�� ������ �� ������ �������������� ���� ����������� CAS. ����� ���� <a href="%s">���</a> ��� �� ����������.',
+ CAS_STR_AUTHENTICATION_FAILED
+ => '� ����������� CAS �������!',
+ CAS_STR_YOU_WERE_NOT_AUTHENTICATED
+ => '<p>��� ���������������.</p><p>�������� �� ����������������, �������� ���� <a href="%s">���</a>.</p><p>��� �� �������� ���������, ����� �� ����� �� ��� <a href="mailto:%s">�����������</a>.</p>',
+ CAS_STR_SERVICE_UNAVAILABLE
+ => '� �������� `<b>%s</b>\' ��� ����� ��������� (<b>%s</b>).'
+);
+
+?>
\ No newline at end of file
diff --git a/cas_auth/cas/languages/languages.php b/cas_auth/cas/languages/languages.php
new file mode 100644
index 0000000000000000000000000000000000000000..e46897a18945a180fccf6d08447793aafc17ff6f
--- /dev/null
+++ b/cas_auth/cas/languages/languages.php
@@ -0,0 +1,25 @@
+<?php // $Id: languages.php 9707 2007-12-12 13:46:31Z mlaurent $
+if ( count( get_included_files() ) == 1 ) die( '---' );
+
+/**
+ * @file languages/languages.php
+ * Internationalization constants
+ * @author Pascal Aubry <pascal.aubry at univ-rennes1.fr>
+ * @sa @link internalLang Internationalization @endlink
+ * @ingroup internalLang
+ */
+
+//@{
+/**
+ * a phpCAS string index
+ */
+define("CAS_STR_USING_SERVER",                1);
+define("CAS_STR_AUTHENTICATION_WANTED",       2);
+define("CAS_STR_LOGOUT",                      3);
+define("CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED", 4);
+define("CAS_STR_AUTHENTICATION_FAILED",       5);
+define("CAS_STR_YOU_WERE_NOT_AUTHENTICATED",  6);
+define("CAS_STR_SERVICE_UNAVAILABLE",         7);
+//@}
+
+?>
\ No newline at end of file
diff --git a/cas_auth/images/connex_cas.gif b/cas_auth/images/connex_cas.gif
new file mode 100644
index 0000000000000000000000000000000000000000..fff52b267a316c07497aa130a223d16274b5c9d5
Binary files /dev/null and b/cas_auth/images/connex_cas.gif differ
diff --git a/cas_auth/start.php b/cas_auth/start.php
new file mode 100644
index 0000000000000000000000000000000000000000..cacbc815e19a4002e2c3d46512da1652ab40d582
--- /dev/null
+++ b/cas_auth/start.php
@@ -0,0 +1,466 @@
+<?php
+	/**
+	 * Elgg CAS authentication
+	 * 
+	 * @package cas_auth
+	 * @license http://www.gnu.org/licenses/gpl.html
+	 * @author Xavier Roussel <xavier.roussel@uvsq.fr>
+	 * @copyright UVSQ 2008
+	 * @link http://www.uvsq.fr
+	 */
+
+	require_once 'UNL/Services/Peoplefinder.php';
+	
+	//In order to avoid a "__PHP_Incomplete_Class" problem when we unserialize the Peoplefinder data we need to set up the class here
+	//http://us2.php.net/manual/en/function.unserialize.php
+	class UNL_Peoplefinder_Record {
+	 public $cn;
+	 public $ou;	 
+	 public $eduPersonNickname;
+	 public $eduPersonPrimaryAffiliation;
+	 public $givenName;
+	 public $displayName;
+	 public $mail;
+	 public $postalAddress;
+	 public $sn;
+	 public $telephoneNumber;
+	 public $title;
+	 public $uid;
+	 public $unlHRPrimaryDepartment;
+	 public $unlHRAddress;
+	 public $unlSISClassLevel;
+	 public $unlSISCollege;
+	 public $unlSISLocalAddr1;
+	 public $unlSISLocalAddr2;
+	 public $unlSISLocalCity;
+	 public $unlSISLocalPhone;
+	 public $unlSISLocalState;
+	 public $unlSISLocalZip;
+	 public $unlSISPermAddr1;
+	 public $unlSISPermAddr2;
+	 public $unlSISPermCity;
+	 public $unlSISPermState;
+	 public $unlSISPermZip;
+	 public $unlSISMajor;
+	 public $unlEmailAlias;	 	
+	}
+			
+
+	// Include main cas lib
+	include_once 'cas/CAS.php';
+	$casInitialized = false;
+
+	/**
+	 * CAS Authentication init
+	 * 
+	 */
+	function cas_auth_init()
+	{
+		// global config
+		global $CONFIG;
+		// plugin config
+		$config = find_plugin_settings('cas_auth');
+		// todo : send message to user
+		if (!$config) return false;
+
+		// CAS auth required
+		if ( $_REQUEST['loginwith'] == 'UNLlogin' && !isset($_REQUEST['ticket']) )
+		{	
+			createCas();
+		}
+		// CAS auth done
+		if ( $_REQUEST['loginwith'] == 'UNLlogin' && (isset($_REQUEST['ticket']) || isset($_REQUEST['email'])) )
+		{
+			// Check CAS auth the CAS way just in case
+			if ( checkCas() ) {
+				$_SESSION['loggedWithCAS'] = true;			
+				
+				$cas_user = getUserCas();
+				if(ldapAuthenticate( $cas_user )) {
+					system_message(elgg_echo('loginok'));
+					forward("pg/profile/unl_" . $cas_user);
+				}
+				else register_error(elgg_echo('loginerror'));
+			}
+			else register_error(elgg_echo('loginerror'));
+		}
+		// The CAS ticket is lost, log out
+		if ( $_SESSION['loggedWithCAS'] && !checkCas() ) {
+			$_SESSION['loggedWithCAS'] = false;
+			forward($CONFIG->url.'/action/logout');
+		}
+		
+	
+		
+	}
+	
+
+	global $CONFIG;
+	register_action("cas_auth/getemail",true,$CONFIG->pluginspath . "cas_auth/views/default/actions/getemail.php");
+	// Register the initialisation function
+	register_elgg_event_handler('init','system','cas_auth_init');
+	// Register CAS logout to main logout only if user logged with CAS
+	if ( $_SESSION['loggedWithCAS'] ) {
+		register_elgg_event_handler('logout', 'user', 'logoutCas');
+	}
+
+	/**
+	 * CAS client initialization
+	 * 
+	 */
+	function initCas() {
+		if (!$GLOBALS[casInitialized]) {
+			$config = find_plugin_settings('cas_auth');
+			phpCAS::client(CAS_VERSION_2_0, $config->casurl, (int) $config->casport , $config->casuri );
+			$GLOBALS[casInitialized] = true;
+		}	
+	}
+
+	/**
+	 * Force authentication
+	 * 
+	 */
+	function createCas() {
+		initCas();
+		phpCAS::forceAuthentication();
+	}
+
+	/**
+	 * Check auth
+	 * 
+	 * @return boolean
+	 */
+	function checkCas() {		
+		initCas();
+		if (phpCAS::checkAuthentication()) {
+			return true;
+		}
+		else return false;
+	}
+
+	/**
+	 * Get CAS user
+	 * 
+	 * @return string name of the user
+	 */
+	function getUserCas() {
+		return phpCAS::getUser();
+	}
+
+	/**
+	 * CAS logout
+	 * 
+	 */
+	function logoutCas() {
+		global $CONFIG;
+		initCas();
+		phpCAS::logout($CONFIG->url.'/action/logout');	
+	}
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	/**
+   * LDAP authentication
+   * 
+   * @param string $username Go around PAM handler credentials (CAS can't return a password)
+   * @return boolean
+   */
+	function ldapAuthenticate($username)
+	{
+		// Nothing to do if LDAP module not installed
+//		if (!function_exists('ldap_connect')) {
+//			return false;
+//		}
+
+		// Get configuration settings
+//		$config = find_plugin_settings('ldap_auth');
+
+		// Nothing to do if not configured
+//		if (!$config)
+//		{
+//			return false;
+//		}
+
+		if (empty($username)) {
+			return false;
+		}
+
+		// Perform the authentication
+		return ldapCheck(/*$config, */$username);
+	}
+   
+  /**
+   * Perform an LDAP authentication check
+   *
+   * @param ElggPlugin $config
+   * @param string $username
+   * @return boolean
+   */
+	function ldapCheck(/*$config, */$username)
+	{
+/*		$host = $config->hostname;
+
+		// No point continuing
+		if(empty($host))
+		{
+			error_log("LDAP error: no host configured.");
+			return;
+		}
+		$port        = $config->port;
+		$version     = $config->version;
+		$basedn      = $config->basedn;
+		$filter_attr = $config->filter_attr;
+		$search_attr = $config->search_attr;
+		$bind_dn     = $config->ldap_bind_dn;
+		$bind_pwd    = $config->ldap_bind_pwd;
+		$user_create = $config->user_create;
+		$start_tls   = $config->start_tls;
+
+		($user_create == 'on') ? $user_create = true : $user_create = false;
+		($start_tls == 'on') ? $start_tls = true : $start_tls = false;
+
+		$port        ? $port        : $port = 389;
+		$version     ? $version     : $version = 3;
+		$filter_attr ? $filter_attr : $filter_attr = 'uid';
+		$basedn      ? $basedn = array_map('trim', explode(':', $basedn)) : $basedn = array();
+
+		if (!empty($search_attr))
+		{
+			// $search_attr as in "email:email_address, name:name_name";
+
+			$pairs = array_map('trim',explode(',', $search_attr));
+
+			$values = array();
+
+			foreach ($pairs as $pair)
+			{
+				$parts = array_map('trim', explode(':', $pair));
+
+				$values[$parts[0]] = $parts[1];
+			}
+
+			$search_attr = $values;
+		}
+		else
+		{
+			$search_attr = array('dn' => 'dn');
+		}
+*/
+/*		// Create a connection
+		if ($ds = ldapConnect($host, $port, $version, $bind_dn, $bind_pwd))
+		{
+			if ($start_tls and !ldap_start_tls($ds)) return false;
+
+			// Perform a search
+			foreach ($basedn as $this_ldap_basedn)
+			{
+				$ldap_user_info = ldapDoAuth($ds, $this_ldap_basedn, $username, $filter_attr, $search_attr);
+
+				if($ldap_user_info)
+				{
+*/					
+		
+					$pf_user_info = peoplefinderServices($username);
+					
+					//We're going to make every UNL SSO user have an elgg profile name as such: unl_erasmussen2
+					//and not allow friends of unl who register via elgg to pick names that begin with "unl_"
+					//This way, we won't have to deal with the case where someone registers erasmussen2 on elgg, then
+					//the real erasmussen2 signs in for the first time with UNL SSO and is logged in as the elgg user erasmussen2
+					//rather then having a new account created.									
+					$username = 'unl_' . $username;
+					//Replace the hyphen in a student's name with an underscore
+					$username = str_replace('-','_',$username);
+			
+					
+					if ($user = get_user_by_username($username))
+					{
+						// User exists, login            	        
+						return login($user);
+					}
+					else
+					{
+						// Valid login but user doesn't exist
+						//if ($user_create)
+						//{
+						//	$name  = $ldap_user_info['firstname'];
+							$name  = $pf_user_info->displayName;
+
+						//	if (isset($ldap_user_info['lastname']))
+						//	{
+						//		$name  = $name . " " . $ldap_user_info['lastname'];
+						//	}
+							
+							//
+				/*			if(!empty($pf_user_info->mail))
+							{
+								($pf_user_info->mail) ? $email = $pf_user_info->mail : $email = null;
+							}
+							else*/ if( isset($_REQUEST['email']) ){
+								$email = $_REQUEST['email'];
+							}
+							else
+							{								
+								forward($CONFIG->url . 'mod/cas_auth/views/default/account/getemail.php');
+							}
+								
+				/*			if ($user_guid = register_user($username, 'generic', $name, $email, false, 0, '', true))
+							{
+								// Success, credentials valid and account has been created                                
+								return login(get_user($user_guid));
+							}
+							else
+							{
+								register_error(elgg_echo("registerbad"));
+								return false;
+							}
+				*/			
+							
+							
+							try {
+								if ($user_guid = register_user($username, 'generic', $name, $email, false, 0, '', true))
+								 {
+									
+									// Success, credentials valid and account has been created                                
+									return login(get_user($user_guid));
+								} else {
+									register_error(elgg_echo("registerbad"));
+								}
+							} catch (RegistrationException $r) {
+								register_error($r->getMessage());
+							}
+						//}
+						//else
+						//{
+						//	register_error(elgg_echo("ldap_auth:no_account"));
+						//	return false;
+						//}
+					}
+/*				}
+			}
+			// Close the connection
+			ldap_close($ds);
+			return false;
+		}
+		else
+		{
+			return false;
+		}
+*/	}
+   
+	/**
+	 * Create an LDAP connection
+	 *
+	 * @param string $host
+	 * @param int $port
+	 * @param int $version
+	 * @param string $bind_dn
+	 * @param string $bind_pwd
+	 * @return mixed LDAP link identifier on success, or false on error
+	 */
+/*	function ldapConnect($host, $port, $version, $bind_dn, $bind_pwd)
+	{
+		$ds = @ldap_connect($host, $port);
+
+		@ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, $version);
+		// Start the LDAP bind process
+		$ldapbind = null;
+
+		if ($ds)
+		{
+			if ($bind_dn != '')
+			{
+				$ldapbind = @ldap_bind($ds, $bind_dn, $bind_pwd);
+			}
+			else
+			{
+				// Anonymous bind
+				$ldapbind = @ldap_bind($ds);
+			}
+		}
+		else
+		{
+			// Unable to connect
+			error_log('Unable to connect to the LDAP server: '.ldap_error($ds));
+			return false;
+		}
+
+		if (!$ldapbind)
+		{
+			error_log('Unable to bind to the LDAP server with provided credentials: '.ldap_error($ds));
+			ldap_close($ds);
+			return false;
+		}
+		return $ds;
+	}
+*/
+	/**
+	 * Performs actual LDAP authentication
+	 *
+	 * @param object $ds LDAP link identifier
+	 * @param string $basedn
+	 * @param string $username
+	 * @param string $filter_attr
+	 * @param string $search_attr
+	 * @return mixed array with search attributes or false on error
+	 */
+/*	function ldapDoAuth($ds, $basedn, $username, $filter_attr, $search_attr)
+	{
+		$sr = @ldap_search($ds, $basedn, $filter_attr ."=". $username, array_values($search_attr));
+		if(!$sr)
+		{
+			error_log('Unable to perform LDAP search: '.ldap_error($ds));
+			return false;
+		}
+
+		$entry = ldap_get_entries($ds, $sr);
+		if(!$entry or !$entry[0])
+		{
+			return false; // didn't find username
+		}
+
+		// We have a bind, a valid login
+		foreach (array_keys($search_attr) as $attr)
+		{
+			$ldap_user_info[$attr] = $entry[0][$search_attr[$attr]][0];
+		}
+		return $ldap_user_info;
+	}
+*/	
+	/**
+	 * Gets a UNL SSO user's info from Peoplefinder Services
+	 * 
+	 * @param string $username
+	 * @return array of information from PF Services
+	 */
+	function peoplefinderServices($username)
+	{
+		$pfrecord = unserialize(file_get_contents('http://peoplefinder.unl.edu/service.php?uid=' . $username . '&format=php'));
+		
+		return $pfrecord;
+	}
+?>
\ No newline at end of file
diff --git a/cas_auth/views/default/account/forms/getemail.php b/cas_auth/views/default/account/forms/getemail.php
new file mode 100644
index 0000000000000000000000000000000000000000..a747b4b54a5b112601e32c96b8c1adabc6e402d3
--- /dev/null
+++ b/cas_auth/views/default/account/forms/getemail.php
@@ -0,0 +1,29 @@
+<?php
+
+     /**
+	 * Elgg Get Email Only SSO register form
+	 * 
+	 * @package Elgg
+	 * @subpackage Core
+	 * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html GNU Public License version 2
+	 * @author Curverider Ltd
+	 * @copyright Curverider Ltd 2008-2009
+	 * @link http://elgg.org/
+	 */
+	 
+	// if we're returning from a failed email validation, we'll put the failed email in the email form field
+	if( isset($_REQUEST['e']) )
+	{
+		$vars['unl_email'] = $_REQUEST['e'];
+	}
+
+	$form_body .= "<p><label>" . elgg_echo('email') . "<br />" . elgg_view('input/text' , array('internalname' => 'email', 'class' => "general-textarea", 'value' => $vars['unl_email'])) . "</label><br />";
+
+	$form_body .= elgg_view('input/submit', array('internalname' => 'submit', 'value' => 'Complete Registration and Login!')) . "</p>";
+?>
+
+	
+	<div id="register-box">
+	<h2>We just want to make sure we have your correct e-mail and then we'll log you in</h2>
+	<?php echo elgg_view('input/form', array('action' => "{$vars['url']}action/cas_auth/getemail", 'body' => $form_body)) ?>
+	</div>
\ No newline at end of file
diff --git a/cas_auth/views/default/account/forms/login.php b/cas_auth/views/default/account/forms/login.php
new file mode 100644
index 0000000000000000000000000000000000000000..99d361d88f717f8d9080ae8b602510ba1fc8e9d8
--- /dev/null
+++ b/cas_auth/views/default/account/forms/login.php
@@ -0,0 +1,31 @@
+<?php
+
+     /**
+	 * Elgg login form adapted for CAS Auth
+	 * 
+	 * @package cas_auth
+	 * @license http://www.gnu.org/licenses/gpl.html
+	 * @author Xavier Roussel
+	 * @copyright UVSQ 2008
+	 * @link http://www.uvsq.fr
+	 */
+	 
+	global $CONFIG;
+	
+	$form_body = "<p class=\"login-box\"><label>" . elgg_echo('username') . "<br />" . elgg_view('input/text', array('internalname' => 'username', 'class' => 'login-textarea')) . "</label>";
+	$form_body .= "<br />";
+	$form_body .= "<label>" . elgg_echo('password') . "<br />" . elgg_view('input/password', array('internalname' => 'password', 'class' => 'login-textarea')) . "</label><br />";
+	$form_body .= elgg_view('input/submit', array('value' => elgg_echo('login'))) . " <div id=\"persistent_login\"><label><input type=\"checkbox\" name=\"persistent\" value=\"true\" />".elgg_echo('user:persistent')."</label></div></p>";
+	$form_body .= "<p class=\"loginbox\">";
+	$form_body .= (!isset($CONFIG->disable_registration) || !($CONFIG->disable_registration)) ? "<a href=\"{$vars['url']}account/register.php\">" . elgg_echo('register') . "</a> | " : "";
+	$form_body .= "<a href=\"{$vars['url']}account/forgotten_password.php\">" . elgg_echo('user:password:lost') . "</a></p>";  
+	
+	//<input name=\"username\" type=\"text\" class="general-textarea" /></label>
+?>
+	
+	<div id="login-box">
+	<h2><?php echo elgg_echo('login'); ?></h2>
+		<!-- Comment the line below to allow only CAS authentification -->
+		<?php  echo elgg_view('input/form', array('body' => $form_body, 'action' => "{$vars['url']}action/login")); ?>
+		<a href="?loginwith=UNLlogin" alt="Login using your my.UNL credentials"><img src="<?php echo $CONFIG->wwwroot; ?>mod/cas_auth/images/connex_cas.gif" title="Login using your my.UNL credentials""></a>
+	</div>
diff --git a/cas_auth/views/default/account/getemail.php b/cas_auth/views/default/account/getemail.php
new file mode 100644
index 0000000000000000000000000000000000000000..231b31eeeb0b2405627489da430d0ef64cb1907a
--- /dev/null
+++ b/cas_auth/views/default/account/getemail.php
@@ -0,0 +1,22 @@
+<?php
+
+	/**
+	 * Get a UNL SSO user's email when they login the first time
+	 * 
+	 * @package cas_auth
+	 * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html GNU Public License version 2
+	 * @author Eric Rasmussen
+	 * @copyright University of Nebraska-Lincoln 2009
+	 * @link http://www.unl.edu/
+	 */
+
+	/**
+	 * Start the Elgg engine
+	 */
+		require_once(dirname(dirname(dirname(dirname(dirname(dirname(__FILE__)))))) . "/engine/start.php");
+
+	
+	page_draw(elgg_echo('register'), elgg_view("account/forms/getemail"));
+
+		
+?>
\ No newline at end of file
diff --git a/cas_auth/views/default/actions/getemail.php b/cas_auth/views/default/actions/getemail.php
new file mode 100644
index 0000000000000000000000000000000000000000..8847eefccd53736b519d19ab68eefa940c8b2560
--- /dev/null
+++ b/cas_auth/views/default/actions/getemail.php
@@ -0,0 +1,53 @@
+<?php
+
+	/**
+	 * Elgg UNL SSO get email registration action
+	 * 
+	 * @package Elgg
+	 * @subpackage Core
+	 * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html GNU Public License version 2
+	 * @author Curverider Ltd
+	 * @copyright Curverider Ltd 2008-2009
+	 * @link http://elgg.org/
+	 */
+
+//	require_once(dirname(dirname(__FILE__)) . "/engine/start.php");
+	global $CONFIG;
+	
+//	action_gatekeeper();
+
+
+	// Get variables
+
+		$email = get_input('email');
+	//	var_dump($email);
+	
+		$email = sanitise_string($email);
+	//	var_dump($email);
+
+		if (is_email_address($email))
+		{
+			if (!get_user_by_email($email))
+			{
+				forward('?loginwith=UNLlogin&email=' . $email);
+			}
+			else
+			{
+				register_error(elgg_echo("Sorry, that email has already been registered.  Please try again."));
+			}
+		}
+		else
+		{
+			register_error(elgg_echo("Sorry, that is not a complete email address.  Please try again."));
+		}
+	
+		
+		
+			
+		$qs = explode('?',$_SERVER['HTTP_REFERER']);
+		$qs = $qs[0];
+		$qs .= "?e=" . urlencode($email);
+		
+		forward($CONFIG->url . 'mod/cas_auth/views/default/account/getemail.php?e=' . urlencode($email));
+
+?>
\ No newline at end of file
diff --git a/cas_auth/views/default/settings/cas_auth/edit.php b/cas_auth/views/default/settings/cas_auth/edit.php
new file mode 100644
index 0000000000000000000000000000000000000000..65f86877e2c3a9676eb8a084e86f1b30e6d7e97f
--- /dev/null
+++ b/cas_auth/views/default/settings/cas_auth/edit.php
@@ -0,0 +1,25 @@
+<?php
+ /**
+* Elgg CAS authentication
+* 
+* @package cas_auth
+* @license http://www.gnu.org/licenses/gpl.html
+* @author Xavier Roussel <xavier.roussel@uvsq.fr>
+* @copyright UVSQ 2008
+* @link http://www.uvsq.fr
+*/
+?>
+<p>
+    <fieldset style="border: 1px solid; padding: 15px; margin: 0 10px 0 10px">
+        <legend><?php echo elgg_echo('CAS');?></legend>
+        
+        <label for="params[casurl]"><?php echo elgg_echo('CAS URL');?></label><br/>
+        <input type="text" name="params[casurl]" value="<?php echo $vars['entity']->casurl;?>" /><br/>
+        
+				<label for="params[casport]"><?php echo elgg_echo('CAS PORT');?></label><br/>
+        <input type="text" name="params[casport]" value="<?php echo $vars['entity']->casport;?>" /><br/>
+
+				<label for="params[casuri]"><?php echo elgg_echo('CAS URI');?></label><br/>
+        <input type="text" name="params[casuri]" value="<?php echo $vars['entity']->casuri;?>" /><br/>
+    </fieldset>
+</p>
\ No newline at end of file