LSsession :
[ldapsaisie.git] / trunk / includes / class / class.LSsession.php
1 <?php
2 /*******************************************************************************
3  * Copyright (C) 2007 Easter-eggs
4  * http://ldapsaisie.labs.libre-entreprise.org
5  *
6  * Author: See AUTHORS file in top-level directory.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License version 2
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20
21 ******************************************************************************/
22
23 /**
24  * Gestion des sessions
25  *
26  * Cette classe gère les sessions d'utilisateurs.
27  *
28  * @author Benjamin Renard <brenard@easter-eggs.com>
29  */
30 class LSsession {
31
32   // La configuration du serveur Ldap utilisé
33   public static $ldapServer = NULL;
34   
35   // L'id du serveur Ldap utilisé
36   private static $ldapServerId = NULL;
37   
38   // Le topDn courant
39   private static $topDn = NULL;
40   
41   // Le DN de l'utilisateur connecté
42   private static $dn = NULL;
43   
44   // Le RDN de l'utilisateur connecté (son identifiant)
45   private static $rdn = NULL;
46   
47   // Les LSprofiles de l'utilisateur
48   private static $LSprofiles = array();
49   
50   // Les droits d'accès de l'utilisateur
51   private static $LSaccess = array();
52   
53   // Les fichiers temporaires
54   private static $tmp_file = array();
55   
56   // Langue et encodage actuel
57   private static $lang = NULL;
58   private static $encoding = NULL;
59   
60   /*
61    * Constante de classe non stockée en session
62    */
63   // Le template à afficher
64   private static $template = NULL;
65   
66   // Les subDn des serveurs Ldap
67   private static $_subDnLdapServer = array();
68   
69   // Affichage Ajax
70   private static $ajaxDisplay = false;
71
72   // Les fichiers JS à charger dans la page
73   private static $JSscripts = array();
74   
75   // Les paramètres JS à communiquer dans la page
76   private static $_JSconfigParams = array();
77   
78   // Les fichiers CSS à charger dans la page
79   private static $CssFiles = array();
80
81   // L'objet de l'utilisateur connecté
82   private static $LSuserObject = NULL;
83
84  /**
85   * Include un fichier PHP
86   *
87   * @author Benjamin Renard <brenard@easter-eggs.com>
88   *
89   * @retval true si tout c'est bien passé, false sinon
90   */
91   public static function includeFile($file) {
92     if (!file_exists($file)) {
93       return;
94     }
95     if (LSdebug) {
96       return include_once($file);
97     }
98     else {
99       return @include_once($file);
100     }
101     return;
102   }
103
104  /**
105   * Lancement de LSconfig
106   *
107   * @author Benjamin Renard <brenard@easter-eggs.com>
108   *
109   * @retval true si tout c'est bien passé, false sinon
110   */
111   private static function startLSconfig() {
112     if (self :: loadLSclass('LSconfig')) {
113       if (LSconfig :: start()) {
114         return true;
115       }
116     }
117     die("ERROR : Can't load configuration files.");
118     return;
119   }
120
121  /**
122   * Lancement et initialisation de Smarty
123   *
124   * @author Benjamin Renard <brenard@easter-eggs.com>
125   *
126   * @retval true si tout c'est bien passé, false sinon
127   */  
128   private static function startLStemplate() {
129     if ( self :: includeFile(LSconfig :: get('Smarty')) ) {
130       $GLOBALS['Smarty'] = new Smarty();
131       $GLOBALS['Smarty'] -> template_dir = LS_TEMPLATES_DIR;
132       $GLOBALS['Smarty'] -> compile_dir = LS_TMP_DIR;
133       
134       if (LSdebug) {
135         $GLOBALS['Smarty'] -> caching = 0;
136         // cache files are always regenerated
137         $GLOBALS['Smarty'] -> force_compile = TRUE;
138         // recompile template if it is changed
139         $GLOBALS['Smarty'] -> compile_check = TRUE;
140         if (isset($_REQUEST['debug_smarty'])) {
141           // debug smarty
142           $GLOBALS['Smarty'] -> debugging = true; 
143         }
144       }
145       
146       $GLOBALS['Smarty'] -> assign('LS_CSS_DIR',LS_CSS_DIR);
147       $GLOBALS['Smarty'] -> assign('LS_IMAGES_DIR',LS_IMAGES_DIR);
148       
149       self :: addJSconfigParam('LS_IMAGES_DIR',LS_IMAGES_DIR);
150       return true;
151     }
152     die("ERROR : Can't load Smarty.");
153     return;
154   }
155   
156  /**
157   * Retourne le topDn de la session
158   *
159   * @author Benjamin Renard <brenard@easter-eggs.com>
160   *
161   * @retval string le topDn de la session
162   */
163   public static function getTopDn() {
164     return self :: $topDn;
165   }
166
167  /**
168   * Initialisation de la gestion des erreurs
169   *
170   * Création de l'objet LSerror
171   *
172   * @author Benjamin Renard <brenard@easter-eggs.com
173   *
174   * @retval boolean true si l'initialisation a réussi, false sinon.
175   */
176   private static function startLSerror() {
177     if(!self :: loadLSclass('LSerror')) {
178       return;
179     }
180     self :: defineLSerrors();
181     return true;
182   }
183
184  /**
185   * Chargement d'une classe d'LdapSaisie
186   *
187   * @param[in] $class Nom de la classe Ã  charger (Exemple : LSpeople)
188   * @param[in] $type (Optionnel) Type de classe Ã  charger (Exemple : LSobjects)
189   *
190   * @author Benjamin Renard <brenard@easter-eggs.com
191   * 
192   * @retval boolean true si le chargement a réussi, false sinon.
193   */
194   public static function loadLSclass($class,$type='') {
195     if (class_exists($class))
196       return true;
197     if($type!='')
198       $type=$type.'.';
199     return self :: includeFile(LS_CLASS_DIR .'class.'.$type.$class.'.php');
200   }
201
202  /**
203   * Chargement d'un object LdapSaisie
204   *
205   * @param[in] $object Nom de l'objet Ã  charger
206   *
207   * @retval boolean true si le chargement a réussi, false sinon.
208   */
209   public static function loadLSobject($object) {
210     if(class_exists($object)) {
211       return true;
212     }
213     $error = 0;
214     self :: loadLSclass('LSldapObject');
215     if (!self :: loadLSclass($object,'LSobjects')) {
216       $error = 1;
217     }
218     if (!self :: includeFile( LS_OBJECTS_DIR . 'config.LSobjects.'.$object.'.php' )) {
219       $error = 1;
220     }
221     else {
222       if (!LSconfig :: set("LSobjects.$object",$GLOBALS['LSobjects'][$object])) {
223         $error = 1;
224       }
225     }
226     if ($error) {
227       LSerror :: addErrorCode('LSsession_04',$object);
228       return;
229     }
230     return true;
231   }
232
233  /**
234   * Chargement d'un addons d'LdapSaisie
235   *
236   * @param[in] $addon Nom de l'addon Ã  charger (Exemple : samba)
237   *
238   * @author Benjamin Renard <brenard@easter-eggs.com
239   * 
240   * @retval boolean true si le chargement a réussi, false sinon.
241   */
242   public static function loadLSaddon($addon) {
243     if(self :: includeFile(LS_ADDONS_DIR .'LSaddons.'.$addon.'.php')) {
244       self :: includeFile(LS_CONF_DIR."LSaddons/config.LSaddons.".$addon.".php");
245       if (!call_user_func('LSaddon_'. $addon .'_support')) {
246         LSerror :: addErrorCode('LSsession_02',$addon);
247         return;
248       }
249       return true;
250     }
251     return;
252   }
253
254  /**
255   * Chargement des addons LdapSaisie
256   *
257   * Chargement des LSaddons contenue dans la variable
258   * $GLOBALS['LSaddons']['loads']
259   *
260   * @retval boolean true si le chargement a réussi, false sinon.
261   */
262   public static function loadLSaddons() {
263     $conf=LSconfig :: get('LSaddons.loads');
264     if(!is_array($conf)) {
265       LSerror :: addErrorCode('LSsession_01',"LSaddons['loads']");
266       return;
267     }
268
269     foreach ($conf as $addon) {
270       self :: loadLSaddon($addon);
271     }
272     return true;
273   }
274
275  /**
276   * Défini la locale
277   * 
278   * @retval void
279   */
280   public static function setLocale() {
281     if (isset($_REQUEST['lang'])) {
282       $lang = $_REQUEST['lang'];
283     }
284     elseif (isset($_SESSION['LSlang'])) {
285       $lang = $_SESSION['LSlang'];
286     }
287     elseif (isset(self :: $ldapServer['lang'])) {
288       $lang = self :: $ldapServer['lang'];
289     }
290     else {
291       $lang = LSconfig :: get('lang');
292     }
293     
294     if (isset($_REQUEST['encoding'])) {
295       $encoding = $_REQUEST['encoding'];
296     }
297     elseif (isset($_SESSION['LSencoding'])) {
298       $encoding = $_SESSION['LSencoding'];
299     }
300     elseif (isset(self :: $ldapServer['encoding'])) {
301       $encoding = self :: $ldapServer['encoding'];
302     }
303     else {
304       $encoding = LSconfig :: get('encoding');
305     }
306     
307     $_SESSION['LSlang']=$lang;
308     self :: $lang=$lang;
309     $_SESSION['LSencoding']=$encoding;
310     self :: $encoding=$encoding;
311     
312
313     if (self :: localeExist($lang,$encoding)) {
314       if ($encoding) {
315         $lang.='.'.$encoding;
316       }
317       setlocale(LC_ALL, $lang);
318       bindtextdomain(LS_TEXT_DOMAIN, LS_I18N_DIR);
319       textdomain(LS_TEXT_DOMAIN);
320       
321       if (is_file(LS_I18N_DIR.'/'.$lang.'/lang.php')) {
322         include(LS_I18N_DIR.'/'.$lang.'/lang.php');
323       }
324     }
325     else {
326       if ($encoding && $lang) {
327         $lang.='.'.$encoding;
328       }
329       LSdebug('La locale "'.$lang.'" n\'existe pas, utilisation de la locale par défaut.');
330     }
331   }
332   
333  /**
334   * Retourne la liste des langues disponibles
335   * 
336   * @retval array Tableau/Liste des langues disponibles
337   **/ 
338   public static function getLangList() {
339     $list=array('en_US');
340     if (self :: $encoding) {
341       $regex = '^([a-zA-Z_]*)\.'.self :: $encoding.'$';
342     }
343     else {
344       $regex = '^([a-zA-Z_]*)$';
345     }
346     if ($handle = opendir(LS_I18N_DIR)) {
347       while (false !== ($file = readdir($handle))) {
348         if(is_dir(LS_I18N_DIR.'/'.$file)) {
349           if (ereg($regex,$file,$regs)) {
350             if (!in_array($regs[1],$list)) {
351               $list[]=$regs[1];
352             }
353           }
354         }
355       }
356     }
357     return $list;
358   }
359
360  /**
361   * Retourne la langue courante de la session
362   * 
363   * @param[in] boolean Si true, le code langue retourné sera court
364   * 
365   * @retval string La langue de la session
366   **/
367   public static function getLang($short=false) {
368     if ($short) {
369       return strtolower(self :: $lang[0].self :: $lang[1]);
370     }
371     return self :: $lang;
372   }
373   
374  /**
375   * Vérifie si une locale est disponible
376   * 
377   * @param[in] $lang string La langue (Ex : fr_FR)
378   * @param[in] $encoding string L'encodage de caractère (Ex : UTF8)
379   * 
380   * @retval boolean True si la locale est disponible, False sinon
381   **/
382   public static function localeExist($lang,$encoding) {
383     if ( !$lang && !$encoding ) {
384       return;
385     }
386     $locale=$lang.(($encoding)?'.'.$encoding:'');
387     if ($locale=='en_US.UTF8') {
388       return true;
389     }
390     return (is_dir(LS_I18N_DIR.'/'.$locale));
391   }
392
393  /**
394   * Initialisation LdapSaisie
395   *
396   * @retval boolean True si l'initialisation à réussi, false sinon.
397   */
398   public static function initialize() {
399     if (!self :: startLSconfig()) {
400       return;
401     }
402     
403     self :: startLStemplate();
404     
405     session_start();
406     
407     self :: setLocale();
408     
409     self :: startLSerror();
410     self :: loadLSaddons();
411     return true;
412   }
413
414  /**
415   * Initialisation de la session LdapSaisie
416   *
417   * Initialisation d'une LSsession :
418   * - Authentification et activation du mécanisme de session de LdapSaisie
419   * - ou Chargement des paramètres de la session Ã  partir de la variable 
420   *   $_SESSION['LSsession'].
421   * - ou Destruction de la session en cas de $_GET['LSsession_logout'].
422   *
423   * @retval boolean True si l'initialisation Ã  réussi (utilisateur authentifié), false sinon.
424   */
425   public static function startLSsession() {
426     if (!self :: initialize()) {
427       return;
428     }   
429
430     // Déconnexion
431     if (isset($_GET['LSsession_logout'])||isset($_GET['LSsession_recoverPassword'])) {
432       session_destroy();
433       
434       if (is_array($_SESSION['LSsession']['tmp_file'])) {
435         self :: $tmp_file = $_SESSION['LSsession']['tmp_file'];
436       }
437       self :: deleteTmpFile();
438       unset($_SESSION['LSsession']);
439     }
440     
441     // Récupération de mot de passe
442     if (isset($_GET['recoveryHash'])) {
443       $_POST['LSsession_user'] = 'a determiner plus tard';
444     }
445     
446     if(isset($_SESSION['LSsession']['dn'])) {
447       // Session existante
448       self :: $topDn        = $_SESSION['LSsession']['topDn'];
449       self :: $dn           = $_SESSION['LSsession']['dn'];
450       self :: $rdn          = $_SESSION['LSsession']['rdn'];
451       self :: $ldapServerId = $_SESSION['LSsession']['ldapServerId'];
452       self :: $tmp_file     = $_SESSION['LSsession']['tmp_file'];
453       
454       if ( self :: cacheLSprofiles() && !isset($_REQUEST['LSsession_refresh']) ) {
455         self :: setLdapServer(self :: $ldapServerId);
456         self :: $LSprofiles   = $_SESSION['LSsession']['LSprofiles'];
457         self :: $LSaccess   = $_SESSION['LSsession']['LSaccess'];
458         if (!self :: LSldapConnect())
459           return;
460       }
461       else {
462         self :: setLdapServer(self :: $ldapServerId);
463         if (!self :: LSldapConnect())
464           return;
465         self :: loadLSprofiles();
466       }
467       
468       if ( self :: cacheSudDn() && (!isset($_REQUEST['LSsession_refresh'])) ) {
469         self :: $_subDnLdapServer = $_SESSION['LSsession_subDnLdapServer'];
470       }
471       
472       if (!self :: loadLSobject(self :: $ldapServer['authObjectType'])) {
473         return;
474       }
475       
476       self :: getLSuserObject();
477       
478       if ( !self :: cacheLSprofiles() || isset($_REQUEST['LSsession_refresh']) ) {
479         self :: loadLSaccess();
480       }
481       
482       $GLOBALS['Smarty'] -> assign('LSsession_username',self :: getLSuserObject() -> getDisplayName());
483       
484       if ($_POST['LSsession_topDn']) {
485         if (self :: validSubDnLdapServer($_POST['LSsession_topDn'])) {
486           self :: $topDn = $_POST['LSsession_topDn'];
487           $_SESSION['LSsession']['topDn'] = $_POST['LSsession_topDn'];
488         } // end if
489       } // end if
490       
491       return true;
492       
493     }
494     else {
495       // Session inexistante
496       $recoveryPasswordInfos=array();
497
498       if (isset($_POST['LSsession_user'])) {
499         if (isset($_POST['LSsession_ldapserver'])) {
500           self :: setLdapServer($_POST['LSsession_ldapserver']);
501         }
502         else {
503           self :: setLdapServer(0);
504         }
505         
506         // Connexion au serveur LDAP
507         if (self :: LSldapConnect()) {
508
509           // topDn
510           if ( $_POST['LSsession_topDn'] != '' ){
511             self :: $topDn = $_POST['LSsession_topDn'];
512           }
513           else {
514             self :: $topDn = self :: $ldapServer['ldap_config']['basedn'];
515           }
516           $_SESSION['LSsession_topDn']=self :: $topDn;
517
518           if ( self :: loadLSobject(self :: $ldapServer['authObjectType']) ) {
519             $authobject = new self :: $ldapServer['authObjectType']();
520             $find=true;
521             if (isset($_GET['recoveryHash'])) {
522               $filter=self :: $ldapServer['recoverPassword']['recoveryHashAttr']."=".$_GET['recoveryHash'];
523               $result = $authobject -> listObjects($filter,self :: $topDn);
524               $nbresult=count($result);
525               if ($nbresult==1) {
526                 $rdn = $result[0] -> getValue('rdn');
527                 $rdn = $rdn[0];
528                 $_POST['LSsession_user'] = $rdn;
529                 $find=false;
530               }
531             }
532             if ($find) {
533               $result = $authobject -> searchObject($_POST['LSsession_user'],self :: $topDn,self :: $ldapServer['authObjectFilter']);
534               $nbresult=count($result);
535             }
536             if ($nbresult==0) {
537               // identifiant incorrect
538               LSdebug('identifiant incorrect');
539               LSerror :: addErrorCode('LSsession_06');
540             }
541             else if ($nbresult>1) {
542               // duplication d'authentité
543               LSerror :: addErrorCode('LSsession_07');
544             }
545             else {
546               if (isset($_GET['LSsession_recoverPassword'])) {
547                 LSdebug('Recover : Id trouvé');
548                 if (self :: $ldapServer['recoverPassword']) {
549                   if (self :: loadLSaddon('mail')) {
550                     LSdebug('Récupération active');
551                     $user=$result[0];
552                     $emailAddress = $user -> getValue(self :: $ldapServer['recoverPassword']['mailAttr']);
553                     $emailAddress = $emailAddress[0];
554                     
555                     // Header des mails
556                     $sendParams=array();
557                     if (self :: $ldapServer['recoverPassword']['recoveryEmailSender']) {
558                       $sendParams['From']=self :: $ldapServer['recoverPassword']['recoveryEmailSender'];
559                     }
560                     
561                     if (checkEmail($emailAddress)) {
562                       LSdebug('Email : '.$emailAddress);
563                       self :: $dn = $user -> getDn();
564                       // 1ère étape : envoie du recoveryHash
565                       if (!isset($_GET['recoveryHash'])) {
566                         // Generer un hash
567                         $rdn=$user -> getValue('rdn');
568                         $rdn = $rdn[0];
569                         $recovery_hash = md5($rdn . strval(time()) . strval(rand()));
570                         
571                         $lostPasswdForm = $user -> getForm('lostPassword');
572                         $lostPasswdForm -> setPostData(
573                           array(
574                             self :: $ldapServer['recoverPassword']['recoveryHashAttr'] => $recovery_hash
575                           )
576                           ,true
577                         );
578                         
579                         if($lostPasswdForm -> validate()) {
580                           if ($user -> updateData('lostPassword')) {
581                             // recoveryHash de l'utilisateur mis à jour
582                             if ($_SERVER['HTTPS']=='on') {
583                               $recovery_url='https://';
584                             }
585                             else {
586                               $recovery_url='http://';
587                             }
588                             $recovery_url .= $_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'].'&recoveryHash='.$recovery_hash;
589
590                             if (
591                               sendMail(
592                                 $emailAddress,
593                                 self :: $ldapServer['recoverPassword']['recoveryHashMail']['subject'],
594                                 getFData(self :: $ldapServer['recoverPassword']['recoveryHashMail']['msg'],$recovery_url),
595                                 $sendParams
596                               )
597                             ){
598                               // Mail a bien été envoyé
599                               $recoveryPasswordInfos['recoveryHashMail']=$emailAddress;
600                             }
601                             else {
602                               // Problème durant l'envoie du mail
603                               LSdebug("Problème durant l'envoie du mail");
604                               LSerror :: addErrorCode('LSsession_20',7);
605                             }
606                           }
607                           else {
608                             // Erreur durant la mise à jour de l'objet
609                             LSdebug("Erreur durant la mise à jour de l'objet");
610                             LSerror :: addErrorCode('LSsession_20',6);
611                           }
612                         }
613                         else {
614                           // Erreur durant la validation du formulaire de modification de perte de password
615                           LSdebug("Erreur durant la validation du formulaire de modification de perte de password");
616                           LSerror :: addErrorCode('LSsession_20',5);
617                         }
618                       }
619                       // 2nd étape : génération du mot de passe + envoie par mail
620                       else {
621                         $attr=$user -> attrs[self :: $ldapServer['authObjectTypeAttrPwd']];
622                         if ($attr instanceof LSattribute) {
623                           $mdp = generatePassword($attr -> config['html_options']['chars'],$attr -> config['html_options']['lenght']);
624                           LSdebug('Nvx mpd : '.$mdp);
625                           $lostPasswdForm = $user -> getForm('lostPassword');
626                           $lostPasswdForm -> setPostData(
627                             array(
628                               self :: $ldapServer['recoverPassword']['recoveryHashAttr'] => array(''),
629                               self :: $ldapServer['authObjectTypeAttrPwd'] => array($mdp)
630                             )
631                             ,true
632                           );
633                           if($lostPasswdForm -> validate()) {
634                             if ($user -> updateData('lostPassword')) {
635                               if (
636                                 sendMail(
637                                   $emailAddress,
638                                   self :: $ldapServer['recoverPassword']['newPasswordMail']['subject'],
639                                   getFData(self :: $ldapServer['recoverPassword']['newPasswordMail']['msg'],$mdp),
640                                   $sendParams
641                                 )
642                               ){
643                                 // Mail a bien été envoyé
644                                 $recoveryPasswordInfos['newPasswordMail']=$emailAddress;
645                               }
646                               else {
647                                 // Problème durant l'envoie du mail
648                                 LSdebug("Problème durant l'envoie du mail");
649                                 LSerror :: addErrorCode('LSsession_20',4);
650                               }
651                             }
652                             else {
653                               // Erreur durant la mise à jour de l'objet
654                               LSdebug("Erreur durant la mise à jour de l'objet");
655                               LSerror :: addErrorCode('LSsession_20',3);
656                             }
657                           }
658                           else {
659                             // Erreur durant la validation du formulaire de modification de perte de password
660                             LSdebug("Erreur durant la validation du formulaire de modification de perte de password");
661                             LSerror :: addErrorCode('LSsession_20',2);
662                           }
663                         }
664                         else {
665                           // l'attribut password n'existe pas
666                           LSdebug("L'attribut password n'existe pas");
667                           LSerror :: addErrorCode('LSsession_20',1);
668                         }
669                       }
670                     }
671                     else {
672                       LSerror :: addErrorCode('LSsession_19');
673                     }
674                   }
675                 }
676                 else {
677                   LSerror :: addErrorCode('LSsession_18');
678                 }
679               }
680               else {
681                 if ( self :: checkUserPwd($result[0],$_POST['LSsession_pwd']) ) {
682                   // Authentification réussi
683                   self :: $LSuserObject = $result[0];
684                   self :: $dn = $result[0]->getValue('dn');
685                   self :: $rdn = $result[0]->getValue('rdn');
686                   self :: loadLSprofiles();
687                   self :: loadLSaccess();
688                   $GLOBALS['Smarty'] -> assign('LSsession_username',self :: getLSuserObject() -> getDisplayName());
689                   $_SESSION['LSsession']=self :: getContextInfos();
690                   return true;
691                 }
692                 else {
693                   LSerror :: addErrorCode('LSsession_06');
694                   LSdebug('mdp incorrect');
695                 }
696               }
697             }
698           }
699           else {
700             LSerror :: addErrorCode('LSsession_10');
701           }
702         }
703         else {
704           LSerror :: addErrorCode('LSsession_09');
705         }
706       }
707       if (self :: $ldapServerId) {
708         $GLOBALS['Smarty'] -> assign('ldapServerId',self :: $ldapServerId);
709       }
710       $GLOBALS['Smarty'] -> assign('topDn',self :: $topDn);
711       if (isset($_GET['LSsession_recoverPassword'])) {
712         self :: displayRecoverPasswordForm($recoveryPasswordInfos);
713       }
714       else {
715         self :: displayLoginForm();
716       }
717       return;
718     }
719   }
720   
721  /**
722   * Retourne les informations du contexte
723   *
724   * @author Benjamin Renard <brenard@easter-eggs.com
725   * 
726   * @retval array Tableau associatif des informations du contexte
727   */
728   private static function getContextInfos() {
729     return array(
730       'tmp_file' => self :: $tmp_file,
731       'topDn' => self :: $topDn,
732       'dn' => self :: $dn,
733       'rdn' => self :: $rdn,
734       'ldapServerId' => self :: $ldapServerId,
735       'ldapServer' => self :: $ldapServer,
736       'LSprofiles' => self :: $LSprofiles,
737       'LSaccess' => self :: $LSaccess
738     );
739   }
740   
741   /**
742   * Retourne l'objet de l'utilisateur connecté
743   *
744   * @author Benjamin Renard <brenard@easter-eggs.com
745   * 
746   * @retval mixed L'objet de l'utilisateur connecté ou false si il n'a pas put
747   *               être créé
748   */
749   public static function getLSuserObject($dn=null) {
750     if ($dn) {
751       self :: $dn = $dn;
752     }
753     if (!self :: $LSuserObject) {
754       if (self :: loadLSobject(self :: $ldapServer['authObjectType'])) {
755         self :: $LSuserObject = new self :: $ldapServer['authObjectType']();
756         self :: $LSuserObject -> loadData(self :: $dn);
757       }
758       else {
759         return;
760       }
761     }
762     return self :: $LSuserObject;
763   }
764   
765  /**
766   * Retourne le DN de l'utilisateur connecté
767   *
768   * @author Benjamin Renard <brenard@easter-eggs.com
769   * 
770   * @retval string Le DN de l'utilisateur connecté
771   */
772   public static function getLSuserObjectDn() {
773     return self :: $dn;
774   }
775
776  /**
777   * Modifie l'utilisateur connecté à la volé
778   * 
779   * @param[in] $object Mixed  L'objet Ldap du nouvel utilisateur
780   *                           le type doit correspondre à
781   *                           self :: $ldapServer['authObjectType']
782   * 
783   * @retval boolean True en cas de succès, false sinon
784   */
785  public static function changeAuthUser($object) {
786   if ($object instanceof self :: $ldapServer['authObjectType']) {
787     self :: $dn = $object -> getDn();
788     $rdn = $object -> getValue('rdn');
789     if(is_array($rdn)) {
790       $rdn = $rdn[0];
791     }
792     self :: $rdn = $rdn;
793     self :: $LSuserObject = $object;
794     
795     if(self :: loadLSprofiles()) {
796       self :: loadLSaccess();
797       $_SESSION['LSsession']=self :: getContextInfos();
798       return true;
799     }
800   }
801   return;
802  }
803
804  /**
805   * Définition du serveur Ldap de la session
806   *
807   * Définition du serveur Ldap de la session Ã  partir de son ID dans 
808   * le tableau LSconfig :: get('ldap_servers').
809   *
810   * @param[in] integer Index du serveur Ldap
811   *
812   * @retval boolean True sinon false.
813   */
814   public static function setLdapServer($id) {
815     $conf = LSconfig :: get("ldap_servers.$id");
816     if ( is_array($conf) ) {
817       self :: $ldapServerId = $id;
818       self :: $ldapServer = $conf;
819       self :: setLocale();
820       return true;
821     }
822     else {
823       return;
824     }
825   }
826
827  /**
828   * Connexion au serveur Ldap
829   *
830   * @retval boolean True sinon false.
831   */
832   public static function LSldapConnect() {
833     if (self :: $ldapServer) {
834       self :: includeFile(LSconfig :: get('NetLDAP2'));
835       if (!self :: loadLSclass('LSldap')) {
836         return;
837       }
838       LSldap :: connect(self :: $ldapServer['ldap_config']);
839       if (LSldap :: isConnected()) {
840         return true;
841       }
842       else {
843         return;
844       }
845     }
846     else {
847       LSerror :: addErrorCode('LSsession_03');
848       return;
849     }
850   }
851
852   /**
853    * Use this function to know if subDn is enabled for the curent LdapServer
854    * 
855    * @retval boolean
856    **/
857   public static function subDnIsEnabled() {
858     if (!isset(self :: $ldapServer['subDn'])) {
859       return;
860     }
861     if ( !is_array(self :: $ldapServer['subDn']) ) {
862       return;
863     }
864     return true;
865   }
866
867  /**
868   * Retourne les sous-dns du serveur Ldap courant
869   *
870   * @retval mixed Tableau des subDn, false si une erreur est survenue.
871   */
872   public static function getSubDnLdapServer() {
873     if (self :: cacheSudDn() && isset(self :: $_subDnLdapServer[self :: $ldapServerId])) {
874       return self :: $_subDnLdapServer[self :: $ldapServerId];
875     }
876     if (!self::subDnIsEnabled()) {
877       return;
878     }
879     $return=array();
880     foreach(self :: $ldapServer['subDn'] as $subDn_name => $subDn_config) {
881       if ($subDn_name == 'LSobject') {
882         if (is_array($subDn_config)) {
883           foreach($subDn_config as $LSobject_name => $LSoject_config) {
884             if ($LSoject_config['basedn']) {
885               $basedn = $LSoject_config['basedn'];
886             }
887             else {
888               $basedn = NULL;
889             }
890             if ($LSoject_config['displayName']) {
891               $displayName = $LSoject_config['displayName'];
892             }
893             else {
894               $displayName = NULL;
895             }
896             if( self :: loadLSobject($LSobject_name) ) {
897               if ($subdnobject = new $LSobject_name()) {
898                 $tbl_return = $subdnobject -> getSelectArray(NULL,$basedn,$displayName);
899                 if (is_array($tbl_return)) {
900                   $return=array_merge($return,$tbl_return);
901                 }
902                 else {
903                   LSerror :: addErrorCode('LSsession_17',3);
904                 }
905               }
906               else {
907                 LSerror :: addErrorCode('LSsession_17',2);
908               }
909             }
910           }
911         }
912         else {
913           LSerror :: addErrorCode('LSsession_17',1);
914         }
915       }
916       else {
917         if ((isCompatibleDNs($subDn_config['dn'],self :: $ldapServer['ldap_config']['basedn']))&&($subDn_config['dn']!="")) {
918           $return[$subDn_config['dn']] = __($subDn_name);
919         }
920       }
921     }
922     if (self :: cacheSudDn()) {
923       self :: $_subDnLdapServer[self :: $ldapServerId]=$return;
924       $_SESSION['LSsession_subDnLdapServer'] = self :: $_subDnLdapServer;
925     }
926     return $return;
927   }
928   
929   /**
930    * Retourne la liste de subDn du serveur Ldap utilise
931    * trié par la profondeur dans l'arboressence (ordre décroissant)
932    * 
933    * @return array() Tableau des subDn trié
934    */  
935   public static function getSortSubDnLdapServer() {
936     $subDnLdapServer = self :: getSubDnLdapServer();
937     if (!$subDnLdapServer) {
938       return array();
939     }
940     uksort($subDnLdapServer,"compareDn");
941     return $subDnLdapServer;
942   }
943
944  /**
945   * Retourne les options d'une liste déroulante pour le choix du topDn
946   * de connexion au serveur Ldap
947   *
948   * Liste les subdn (self :: $ldapServer['subDn'])
949   *
950   * @retval string Les options (<option>) pour la sélection du topDn.
951   */
952   public static function getSubDnLdapServerOptions($selected=NULL) {
953     $list = self :: getSubDnLdapServer();
954     if ($list) {
955       asort($list);
956       $display='';
957       foreach($list as $dn => $txt) {
958         if ($selected && ($selected==$dn)) {
959           $selected_txt = ' selected';
960         }
961         else {
962           $selected_txt = '';
963         }
964         $display.="<option value=\"".$dn."\"$selected_txt>".$txt."</option>\n"; 
965       }
966       return $display;
967     }
968     return;
969   }
970
971  /**
972   * Vérifie qu'un subDn est déclaré
973   *
974   * @param[in] string Un subDn
975   * 
976   * @retval boolean True si le subDn existe, False sinon
977   */
978   public static function validSubDnLdapServer($subDn) {
979     $listTopDn = self :: getSubDnLdapServer();
980     if(is_array($listTopDn)) {
981       foreach($listTopDn as $dn => $txt) {
982         if ($subDn==$dn) {
983           return true;
984         } // end if
985       } // end foreach
986     } // end if
987     return;
988   }
989
990  /**
991   * Test un couple LSobject/pwd
992   *
993   * Test un bind sur le serveur avec le dn de l'objet et le mot de passe fourni.
994   *
995   * @param[in] LSobject L'object "user" pour l'authentification
996   * @param[in] string Le mot de passe Ã  tester
997   *
998   * @retval boolean True si l'authentification Ã  réussi, false sinon.
999   */
1000   public static function checkUserPwd($object,$pwd) {
1001     return LSldap :: checkBind($object -> getValue('dn'),$pwd);
1002   }
1003
1004  /**
1005   * Affiche le formulaire de login
1006   *
1007   * Défini les informations pour le template Smarty du formulaire de login.
1008   *
1009   * @retval void
1010   */
1011   public static function displayLoginForm() {
1012     $GLOBALS['Smarty'] -> assign('pagetitle',_('Connection'));
1013     if (isset($_GET['LSsession_logout'])) {
1014       $GLOBALS['Smarty'] -> assign('loginform_action','index.php');
1015     }
1016     else {
1017       $GLOBALS['Smarty'] -> assign('loginform_action',$_SERVER['REQUEST_URI']);
1018     }
1019     if (count(LSconfig :: get('ldap_servers'))==1) {
1020       $GLOBALS['Smarty'] -> assign('loginform_ldapserver_style','style="display: none"');
1021     }
1022     $GLOBALS['Smarty'] -> assign('loginform_label_ldapserver',_('LDAP server'));
1023     $ldapservers_name=array();
1024     $ldapservers_index=array();
1025     foreach(LSconfig :: get('ldap_servers') as $id => $infos) {
1026       $ldapservers_index[]=$id;
1027       $ldapservers_name[]=__($infos['name']);
1028     }
1029     $GLOBALS['Smarty'] -> assign('loginform_ldapservers_name',$ldapservers_name);
1030     $GLOBALS['Smarty'] -> assign('loginform_ldapservers_index',$ldapservers_index);
1031
1032     $GLOBALS['Smarty'] -> assign('loginform_label_level',_('Level'));
1033     $GLOBALS['Smarty'] -> assign('loginform_label_user',_('Identifier'));
1034     $GLOBALS['Smarty'] -> assign('loginform_label_pwd',_('Password'));
1035     $GLOBALS['Smarty'] -> assign('loginform_label_submit',_('Connect'));
1036     $GLOBALS['Smarty'] -> assign('loginform_label_recoverPassword',_('Forgot your password ?'));
1037     
1038     self :: setTemplate('login.tpl');
1039     self :: addJSscript('LSsession_login.js');
1040   }
1041
1042  /**
1043   * Affiche le formulaire de récupération de mot de passe
1044   *
1045   * Défini les informations pour le template Smarty du formulaire de 
1046   * récupération de mot de passe
1047   * 
1048   * @param[in] $infos array() Information sur le status du processus de 
1049   *                           recouvrement de mot de passe
1050   *
1051   * @retval void
1052   */
1053   public static function displayRecoverPasswordForm($recoveryPasswordInfos) {
1054     $GLOBALS['Smarty'] -> assign('pagetitle',_('Recovery of your credentials'));
1055     $GLOBALS['Smarty'] -> assign('recoverpasswordform_action','index.php?LSsession_recoverPassword');
1056     
1057     if (count(LSconfig :: get('ldap_servers'))==1) {
1058       $GLOBALS['Smarty'] -> assign('recoverpasswordform_ldapserver_style','style="display: none"');
1059     }
1060     
1061     $GLOBALS['Smarty'] -> assign('recoverpasswordform_label_ldapserver',_('LDAP server'));
1062     $ldapservers_name=array();
1063     $ldapservers_index=array();
1064     foreach(LSconfig :: get('ldap_servers') as $id => $infos) {
1065       $ldapservers_index[]=$id;
1066       $ldapservers_name[]=$infos['name'];
1067     }
1068     $GLOBALS['Smarty'] -> assign('recoverpasswordform_ldapservers_name',$ldapservers_name);
1069     $GLOBALS['Smarty'] -> assign('recoverpasswordform_ldapservers_index',$ldapservers_index);
1070
1071     $GLOBALS['Smarty'] -> assign('recoverpasswordform_label_user',_('Identifier'));
1072     $GLOBALS['Smarty'] -> assign('recoverpasswordform_label_submit',_('Validate'));
1073     $GLOBALS['Smarty'] -> assign('recoverpasswordform_label_back',_('Back'));
1074     
1075     $recoverpassword_msg = _('Please fill the identifier field to proceed recovery procedure');
1076     
1077     if (isset($recoveryPasswordInfos['recoveryHashMail'])) {
1078       $recoverpassword_msg = getFData(
1079         _("An email has been sent to  %{mail}. " .
1080         "Please follow the instructions on it."),
1081         $recoveryPasswordInfos['recoveryHashMail']
1082       );
1083     }
1084     
1085     if (isset($recoveryPasswordInfos['newPasswordMail'])) {
1086       $recoverpassword_msg = getFData(
1087         _("Your new password has been sent to %{mail}. "),
1088         $recoveryPasswordInfos['newPasswordMail']
1089       );
1090     }
1091     
1092     $GLOBALS['Smarty'] -> assign('recoverpassword_msg',$recoverpassword_msg);
1093     
1094     self :: setTemplate('recoverpassword.tpl');
1095     self :: addJSscript('LSsession_recoverPassword.js');
1096   }
1097
1098  /**
1099   * Défini le template Smarty Ã  utiliser
1100   *
1101   * Remarque : les fichiers de templates doivent se trouver dans le dossier 
1102   * templates/.
1103   *
1104   * @param[in] string Le nom du fichier de template
1105   *
1106   * @retval void
1107   */
1108   public static function setTemplate($template) {
1109     self :: $template = $template;
1110   }
1111
1112  /**
1113   * Ajoute un script JS au chargement de la page
1114   *
1115   * Remarque : les scripts doivents Ãªtre dans le dossier LS_JS_DIR.
1116   *
1117   * @param[in] $script Le nom du fichier de script Ã  charger.
1118   *
1119   * @retval void
1120   */
1121   public static function addJSscript($file,$path=NULL) {
1122     $script=array(
1123       'file' => $file,
1124       'path' => $path
1125     );
1126     self :: $JSscripts[$path.$file]=$script;
1127   }
1128
1129  /**
1130   * Ajouter un paramètre de configuration Javascript
1131   * 
1132   * @param[in] $name string Nom de la variable de configuration
1133   * @param[in] $val mixed Valeur de la variable de configuration
1134   *
1135   * @retval void
1136   */
1137   public static function addJSconfigParam($name,$val) {
1138     self :: $_JSconfigParams[$name]=$val;
1139   }
1140
1141  /**
1142   * Ajoute une feuille de style au chargement de la page
1143   *
1144   * Remarque : les scripts doivents Ãªtre dans le dossier LS_CSS_DIR.
1145   *
1146   * @param[in] $script Le nom du fichier css Ã  charger.
1147   *
1148   * @retval void
1149   */
1150   public static function addCssFile($file,$path=NULL) {
1151     $cssFile=array(
1152       'file' => $file,
1153       'path' => $path
1154     );
1155     self :: $CssFiles[$path.$file]=$cssFile;
1156   }
1157
1158  /**
1159   * Affiche le template Smarty
1160   *
1161   * Charge les dépendances et affiche le template Smarty
1162   *
1163   * @retval void
1164   */
1165   public static function displayTemplate() {
1166     // JS
1167     $JSscript_txt='';
1168     foreach ($GLOBALS['defaultJSscipts'] as $script) {
1169       $JSscript_txt.="<script src='".LS_JS_DIR.$script."' type='text/javascript'></script>\n";
1170     }
1171
1172     foreach (self :: $JSscripts as $script) {
1173       if (!$script['path']) {
1174         $script['path']=LS_JS_DIR;
1175       }
1176       else {
1177         $script['path'].='/';
1178       }
1179       $JSscript_txt.="<script src='".$script['path'].$script['file']."' type='text/javascript'></script>\n";
1180     }
1181
1182     $KAconf = LSconfig :: get('keepLSsessionActive');
1183     if ( 
1184           (
1185             (!isset(self :: $ldapServer['keepLSsessionActive']))
1186             &&
1187             (!($KAconf === false))
1188           )
1189           ||
1190           (self :: $ldapServer['keepLSsessionActive'])
1191         ) {
1192       self :: addJSconfigParam('keepLSsessionActive',ini_get('session.gc_maxlifetime'));
1193     }
1194
1195     $GLOBALS['Smarty'] -> assign('LSjsConfig',json_encode(self :: $_JSconfigParams));
1196     
1197     if (LSdebug) {
1198       $JSscript_txt.="<script type='text/javascript'>LSdebug_active = 1;</script>\n";
1199     }
1200     else {
1201       $JSscript_txt.="<script type='text/javascript'>LSdebug_active = 0;</script>\n";
1202     }
1203     
1204     $GLOBALS['Smarty'] -> assign('LSsession_js',$JSscript_txt);
1205
1206     // Css
1207     self :: addCssFile("LSdefault.css");
1208     $Css_txt='';
1209     foreach (self :: $CssFiles as $file) {
1210       if (!$file['path']) {
1211         $file['path']=LS_CSS_DIR.'/';
1212       }
1213       $Css_txt.="<link rel='stylesheet' type='text/css' href='".$file['path'].$file['file']."' />\n";
1214     }
1215     $GLOBALS['Smarty'] -> assign('LSsession_css',$Css_txt);
1216   
1217     if (isset(self :: $LSaccess[self :: $topDn])) {
1218       $GLOBALS['Smarty'] -> assign('LSaccess',self :: $LSaccess[self :: $topDn]);
1219     }
1220     
1221     // Niveau
1222     $listTopDn = self :: getSubDnLdapServer();
1223     if (is_array($listTopDn)) {
1224       asort($listTopDn);
1225       $GLOBALS['Smarty'] -> assign('label_level',self :: getSubDnLabel());
1226       $GLOBALS['Smarty'] -> assign('_refresh',_('Refresh'));
1227       $LSsession_topDn_index = array();
1228       $LSsession_topDn_name = array();
1229       foreach($listTopDn as $index => $name) {
1230         $LSsession_topDn_index[]  = $index;
1231         $LSsession_topDn_name[]   = $name;
1232       }
1233       $GLOBALS['Smarty'] -> assign('LSsession_subDn_indexes',$LSsession_topDn_index);
1234       $GLOBALS['Smarty'] -> assign('LSsession_subDn_names',$LSsession_topDn_name);
1235       $GLOBALS['Smarty'] -> assign('LSsession_subDn',self :: $topDn);
1236       $GLOBALS['Smarty'] -> assign('LSsession_subDnName',self :: getSubDnName());
1237     }
1238     
1239     $GLOBALS['Smarty'] -> assign('LSlanguages',self :: getLangList());
1240     $GLOBALS['Smarty'] -> assign('LSlang',self :: $lang);
1241     $GLOBALS['Smarty'] -> assign('LSencoding',self :: $encoding);
1242     $GLOBALS['Smarty'] -> assign('lang_label',_('Language'));
1243
1244     // Infos
1245     if((!empty($_SESSION['LSsession_infos']))&&(is_array($_SESSION['LSsession_infos']))) {
1246       $txt_infos="<ul>\n";
1247       foreach($_SESSION['LSsession_infos'] as $info) {
1248         $txt_infos.="<li>$info</li>\n";
1249       }
1250       $txt_infos.="</ul>\n";
1251       $GLOBALS['Smarty'] -> assign('LSinfos',$txt_infos);
1252       $_SESSION['LSsession_infos']=array();
1253     }
1254     
1255     if (self :: $ajaxDisplay) {
1256       $GLOBALS['Smarty'] -> assign('LSerror_txt',LSerror :: getErrors());
1257       $GLOBALS['Smarty'] -> assign('LSdebug_txt',LSdebug_print(true));
1258     }
1259     else {
1260       LSerror :: display();
1261       LSdebug_print();
1262     }
1263     if (!self :: $template)
1264       self :: setTemplate('empty.tpl');
1265       
1266     $GLOBALS['Smarty'] -> assign('connected_as',_("Connected as"));
1267     
1268     $GLOBALS['Smarty'] -> display(self :: $template);
1269   }
1270   
1271  /**
1272   * Défini que l'affichage se fera ou non via un retour Ajax
1273   * 
1274   * @param[in] $val boolean True pour que l'affichage se fasse par un retour
1275   *                         Ajax, false sinon
1276   * @retval void
1277   */
1278   public static function setAjaxDisplay($val=true) {
1279     self :: $ajaxDisplay = (boolean)$val;
1280   }
1281   
1282  /**
1283   * Affiche un retour Ajax
1284   *
1285   * @retval void
1286   */
1287   public static function displayAjaxReturn($data=array()) {
1288     if (isset($data['LSredirect']) && (!LSdebugDefined()) ) {
1289       echo json_encode($data);
1290       return;
1291     }
1292     
1293     $data['LSjsConfig'] = self :: $_JSconfigParams;
1294     
1295     // Infos
1296     if((!empty($_SESSION['LSsession_infos']))&&(is_array($_SESSION['LSsession_infos']))) {
1297       $txt_infos="<ul>\n";
1298       foreach($_SESSION['LSsession_infos'] as $info) {
1299         $txt_infos.="<li>$info</li>\n";
1300       }
1301       $txt_infos.="</ul>\n";
1302       $data['LSinfos'] = $txt_infos;
1303       $_SESSION['LSsession_infos']=array();
1304     }
1305     
1306     if (LSerror :: errorsDefined()) {
1307       $data['LSerror'] = LSerror :: getErrors();
1308     }
1309
1310     if (isset($_REQUEST['imgload'])) {
1311       $data['imgload'] = $_REQUEST['imgload'];
1312     }
1313
1314     if (LSdebugDefined()) {
1315       $data['LSdebug'] = LSdebug_print(true);
1316     }
1317
1318     echo json_encode($data);  
1319   }
1320  
1321  /**
1322   * Retournne un template Smarty compilé
1323   *
1324   * @param[in] string $template Le template à retourner
1325   * @param[in] array $variables Variables Smarty à assigner avant l'affichage
1326   * 
1327   * @retval string Le HTML compilé du template
1328   */
1329   public static function fetchTemplate($template,$variables=array()) {
1330     foreach($variables as $name => $val) {
1331       $GLOBALS['Smarty'] -> assign($name,$val);
1332     }
1333     return $GLOBALS['Smarty'] -> fetch($template);
1334   }
1335   
1336   /**
1337    * Charge les droits LS de l'utilisateur
1338    * 
1339    * @retval boolean True si le chargement Ã  réussi, false sinon.
1340    **/
1341   private static function loadLSprofiles() {
1342     if (is_array(self :: $ldapServer['LSprofiles'])) {
1343       foreach (self :: $ldapServer['LSprofiles'] as $profile => $profileInfos) {
1344         if (is_array($profileInfos)) {
1345           foreach ($profileInfos as $topDn => $rightsInfos) {
1346             /*
1347              * If $topDn == 'LSobject', we search for each LSobject type to find
1348              * all items on witch the user will have powers.
1349              */
1350             if ($topDn == 'LSobjects') {
1351               if (is_array($rightsInfos)) {
1352                 foreach ($rightsInfos as $LSobject => $listInfos) {
1353                   if (self :: loadLSobject($LSobject)) {
1354                     if ($object = new $LSobject()) {
1355                       if ($listInfos['filter']) {
1356                         $filter = self :: getLSuserObject() -> getFData($listInfos['filter']);
1357                       }
1358                       else {
1359                         $filter = $listInfos['attr'].'='.self :: getLSuserObject() -> getFData($listInfos['attr_value']);
1360                       }
1361                       $list = $object -> search($filter,$listInfos['basedn'],$listInfos['params']);
1362                       foreach($list as $obj) {
1363                         self :: $LSprofiles[$profile][] = $obj['dn'];
1364                       }
1365                     }
1366                     else {
1367                       LSdebug('Impossible de créer l\'objet de type : '.$LSobject);
1368                     }
1369                   }
1370                 }
1371               }
1372               else {
1373                 LSdebug('LSobjects => [] doit etre un tableau');
1374               }
1375             }
1376             else {
1377               if (is_array($rightsInfos)) {
1378                 foreach($rightsInfos as $dn => $conf) {
1379                   if ((isset($conf['attr'])) && (isset($conf['LSobject']))) {
1380                     if( self :: loadLSobject($conf['LSobject']) ) {
1381                       if ($object = new $conf['LSobject']()) {
1382                         if ($object -> loadData($dn)) {
1383                           $listDns=$object -> getValue($conf['attr']);
1384                           $valKey = (isset($conf['attr_value']))?$conf['attr_value']:'%{dn}';
1385                           $val = self :: getLSuserObject() -> getFData($valKey);
1386                           if (is_array($listDns)) {
1387                             if (in_array($val,$listDns)) {
1388                               self :: $LSprofiles[$profile][] = $topDn;
1389                             }
1390                           }
1391                         }
1392                         else {
1393                           LSdebug('Impossible de chargé le dn : '.$dn);
1394                         }
1395                       }
1396                       else {
1397                         LSdebug('Impossible de créer l\'objet de type : '.$conf['LSobject']);
1398                       }
1399                     }
1400                   }
1401                   else {
1402                     if (self :: $dn == $dn) {
1403                       self :: $LSprofiles[$profile][] = $topDn;
1404                     }
1405                   }
1406                 }
1407               }
1408               else {
1409                 if ( self :: $dn == $rightsInfos ) {
1410                   self :: $LSprofiles[$profile][] = $topDn;
1411                 }
1412               }
1413             } // fin else ($topDn == 'LSobjects')
1414           } // fin foreach($profileInfos)
1415         } // fin is_array($profileInfos)
1416       } // fin foreach LSprofiles
1417       LSdebug(self :: $LSprofiles);
1418       return true;
1419     }
1420     else {
1421       return;
1422     }
1423   }
1424   
1425   /**
1426    * Charge les droits d'accès de l'utilisateur pour construire le menu de l'interface
1427    *
1428    * @retval void
1429    */
1430   private static function loadLSaccess() {
1431     $LSaccess=array();
1432     if (is_array(self :: $ldapServer['subDn'])) {
1433       foreach(self :: $ldapServer['subDn'] as $name => $config) {
1434         if ($name=='LSobject') {
1435           if (is_array($config)) {
1436
1437             // Définition des subDns 
1438             foreach($config as $objectType => $objectConf) {
1439               if (self :: loadLSobject($objectType)) {
1440                 if ($subdnobject = new $objectType()) {
1441                   $tbl = $subdnobject -> getSelectArray();
1442                   if (is_array($tbl)) {
1443                     // Définition des accès
1444                     $access=array();
1445                     if (is_array($objectConf['LSobjects'])) {
1446                       foreach($objectConf['LSobjects'] as $type) {
1447                         if (self :: loadLSobject($type)) {
1448                           if (self :: canAccess($type)) {
1449                             $access[$type] = LSconfig :: get('LSobjects.'.$type.'.label');
1450                           }
1451                         }
1452                       }
1453                     }
1454                     foreach($tbl as $dn => $dn_name) {
1455                       $LSaccess[$dn]=$access;
1456                     }
1457                   }
1458                 }
1459               }
1460             }
1461           }
1462         }
1463         else {
1464           if ((isCompatibleDNs(self :: $ldapServer['ldap_config']['basedn'],$config['dn']))&&($config['dn']!='')) {
1465             $access=array();
1466             if (is_array($config['LSobjects'])) {
1467               foreach($config['LSobjects'] as $objectType) {
1468                 if (self :: loadLSobject($objectType)) {
1469                   if (self :: canAccess($objectType)) {
1470                     $access[$objectType] = LSconfig :: get('LSobjects.'.$objectType.'.label');
1471                   }
1472                 }
1473               }
1474             }
1475             $LSaccess[$config['dn']]=$access;
1476           }
1477         }
1478       }
1479     }
1480     else {
1481       if(is_array(self :: $ldapServer['LSaccess'])) {
1482         $access=array();
1483         foreach(self :: $ldapServer['LSaccess'] as $objectType) {
1484           if (self :: loadLSobject($objectType)) {
1485             if (self :: canAccess($objectType)) {
1486                 $access[$objectType] = LSconfig :: get('LSobjects.'.$objectType.'.label');
1487             }
1488           }
1489         }
1490         $LSaccess[self :: $topDn] = $access;
1491       }
1492     }
1493     foreach($LSaccess as $dn => $access) {
1494       $LSaccess[$dn] = array_merge(
1495         array(
1496           'SELF' => 'My account'
1497         ),
1498         $access
1499       );
1500     }
1501     
1502     self :: $LSaccess = $LSaccess;
1503     $_SESSION['LSsession']['LSaccess'] = $LSaccess;
1504   }
1505   
1506   /**
1507    * Dit si l'utilisateur est du profil pour le DN spécifié
1508    *
1509    * @param[in] string $profile de l'objet
1510    * @param[in] string $dn DN de l'objet
1511    * 
1512    * @retval boolean True si l'utilisateur est du profil sur l'objet, false sinon.
1513    */
1514   public static function isLSprofile($dn,$profile) {
1515     if (is_array(self :: $LSprofiles[$profile])) {
1516       foreach(self :: $LSprofiles[$profile] as $topDn) {
1517         if($dn == $topDn) {
1518           return true;
1519         }
1520         else if ( isCompatibleDNs($dn,$topDn) ) {
1521           return true;
1522         }
1523       }
1524     }
1525     return;
1526   }
1527   
1528   /**
1529    * Retourne qui est l'utilisateur par rapport Ã  l'object
1530    *
1531    * @param[in] string Le DN de l'objet
1532    * 
1533    * @retval string 'admin'/'self'/'user' pour Admin , l'utilisateur lui même ou un simple utilisateur
1534    */
1535   public static function whoami($dn) {
1536     $retval = array('user');
1537     
1538     foreach(self :: $LSprofiles as $profile => $infos) {
1539       if(self :: isLSprofile($dn,$profile)) {
1540        $retval[]=$profile;
1541       }
1542     }
1543     
1544     if (self :: $dn == $dn) {
1545       $retval[]='self';
1546     }
1547     
1548     return $retval;
1549   }
1550   
1551   /**
1552    * Retourne le droit de l'utilisateur Ã  accèder Ã  un objet
1553    * 
1554    * @param[in] string $LSobject Le type de l'objet
1555    * @param[in] string $dn Le DN de l'objet (le container_dn du type de l'objet par défaut)
1556    * @param[in] string $right Le type de droit d'accès Ã  tester ('r'/'w')
1557    * @param[in] string $attr Le nom de l'attribut auquel on test l'accès
1558    *
1559    * @retval boolean True si l'utilisateur a accès, false sinon
1560    */
1561   public static function canAccess($LSobject,$dn=NULL,$right=NULL,$attr=NULL) {
1562     if (!self :: loadLSobject($LSobject)) {
1563       return;
1564     }
1565     if ($dn) {
1566       $whoami = self :: whoami($dn);
1567       if ($dn==self :: getLSuserObject() -> getValue('dn')) {
1568         if (!self :: in_menu('SELF')) {
1569           return;
1570         }
1571       }
1572       else {
1573         $obj = new $LSobject();
1574         $obj -> dn = $dn;
1575         if (!self :: in_menu($LSobject,$obj -> getSubDnValue())) {
1576           return;
1577         }
1578       }
1579     }
1580     else {
1581       $objectdn=LSconfig :: get('LSobjects.'.$LSobject.'.container_dn').','.self :: $topDn;
1582       $whoami = self :: whoami($objectdn);
1583     }
1584     
1585     // Pour un attribut particulier
1586     if ($attr) {
1587       if ($attr=='rdn') {
1588         $attr=LSconfig :: get('LSobjects.'.$LSobject.'.rdn');
1589       }
1590       if (!is_array(LSconfig :: get('LSobjects.'.$LSobject.'.attrs.'.$attr))) {
1591         return;
1592       }
1593
1594       $r = 'n';
1595       foreach($whoami as $who) {
1596         $nr = LSconfig :: get('LSobjects.'.$LSobject.'.attrs.'.$attr.'.rights.'.$who);
1597         if($nr == 'w') {
1598           $r = 'w';
1599         }
1600         else if($nr == 'r') {
1601           if ($r=='n') {
1602             $r='r';
1603           }
1604         }
1605       }
1606       
1607       if (($right=='r')||($right=='w')) {
1608         if ($r==$right) {
1609           return true;
1610         }
1611         return;
1612       }
1613       else {
1614         if ( ($r=='r') || ($r=='w') ) {
1615           return true;
1616         }
1617         return;
1618       }
1619     }
1620     
1621     // Pour un attribut quelconque
1622     $attrs_conf=LSconfig :: get('LSobjects.'.$LSobject.'.attrs');
1623     if (is_array($attrs_conf)) {
1624       if (($right=='r')||($right=='w')) {
1625         foreach($whoami as $who) {
1626           foreach ($attrs_conf as $attr_name => $attr_config) {
1627             if ($attr_config['rights'][$who]==$right) {
1628               return true;
1629             }
1630           }
1631         }
1632       }
1633       else {
1634         foreach($whoami as $who) {
1635           foreach ($attrs_conf as $attr_name => $attr_config) {
1636             if ( ($attr_config['rights'][$who]=='r') || ($attr_config['rights'][$who]=='w') ) {
1637               return true;
1638             }
1639           }
1640         }
1641       }
1642     }
1643     return;
1644   }
1645   
1646   /**
1647    * Retourne le droit de l'utilisateur Ã  editer Ã  un objet
1648    * 
1649    * @param[in] string $LSobject Le type de l'objet
1650    * @param[in] string $dn Le DN de l'objet (le container_dn du type de l'objet par défaut)
1651    * @param[in] string $attr Le nom de l'attribut auquel on test l'accès
1652    *
1653    * @retval boolean True si l'utilisateur a accès, false sinon
1654    */
1655   public static function canEdit($LSobject,$dn=NULL,$attr=NULL) {
1656     return self :: canAccess($LSobject,$dn,'w',$attr);
1657   }
1658
1659   /**
1660    * Retourne le droit de l'utilisateur Ã  supprimer un objet
1661    * 
1662    * @param[in] string $LSobject Le type de l'objet
1663    * @param[in] string $dn Le DN de l'objet (le container_dn du type de l'objet par défaut)
1664    *
1665    * @retval boolean True si l'utilisateur a accès, false sinon
1666    */  
1667   public static function canRemove($LSobject,$dn) {
1668     return self :: canAccess($LSobject,$dn,'w','rdn');
1669   }
1670   
1671   /**
1672    * Retourne le droit de l'utilisateur Ã  créer un objet
1673    * 
1674    * @param[in] string $LSobject Le type de l'objet
1675    *
1676    * @retval boolean True si l'utilisateur a accès, false sinon
1677    */    
1678   public static function canCreate($LSobject) {
1679     return self :: canAccess($LSobject,NULL,'w','rdn');
1680   }
1681   
1682   /**
1683    * Retourne le droit de l'utilisateur Ã  gérer la relation d'objet
1684    * 
1685    * @param[in] string $dn Le DN de l'objet (le container_dn du type de l'objet par défaut)
1686    * @param[in] string $LSobject Le type de l'objet
1687    * @param[in] string $relationName Le nom de la relation avec l'objet
1688    * @param[in] string $right Le type de droit a vérifier ('r' ou 'w')
1689    *
1690    * @retval boolean True si l'utilisateur a accès, false sinon
1691    */
1692   public static function relationCanAccess($dn,$LSobject,$relationName,$right=NULL) {
1693     $relConf=LSconfig :: get('LSobjects.'.$LSobject.'.LSrelation.'.$relationName);
1694     if (!is_array($relConf))
1695       return;
1696     $whoami = self :: whoami($dn);
1697
1698     if (($right=='w') || ($right=='r')) {
1699       $r = 'n';
1700       foreach($whoami as $who) {
1701         $nr = $relConf['rights'][$who];
1702         if($nr == 'w') {
1703           $r = 'w';
1704         }
1705         else if($nr == 'r') {
1706           if ($r=='n') {
1707             $r='r';
1708           }
1709         }
1710       }
1711       
1712       if ($r == $right) {
1713         return true;
1714       }
1715     }
1716     else {
1717       foreach($whoami as $who) {
1718         if (($relConf['rights'][$who] == 'w') || ($relConf['rights'][$who] == 'r')) {
1719           return true;
1720         }
1721       }
1722     }
1723     return;
1724   }
1725
1726   /**
1727    * Retourne le droit de l'utilisateur Ã  modifier la relation d'objet
1728    * 
1729    * @param[in] string $dn Le DN de l'objet (le container_dn du type de l'objet par défaut)
1730    * @param[in] string $LSobject Le type de l'objet
1731    * @param[in] string $relationName Le nom de la relation avec l'objet
1732    *
1733    * @retval boolean True si l'utilisateur a accès, false sinon
1734    */  
1735   public static function relationCanEdit($dn,$LSobject,$relationName) {
1736     return self :: relationCanAccess($dn,$LSobject,$relationName,'w');
1737   }
1738
1739   /**
1740    * Ajoute un fichier temporaire
1741    * 
1742    * @author Benjamin Renard <brenard@easter-eggs.com>
1743    * 
1744    * @retval void
1745    **/
1746   public static function addTmpFile($value,$filePath) {
1747     $hash = mhash(MHASH_MD5,$value);
1748     self :: $tmp_file[$filePath] = $hash;
1749     $_SESSION['LSsession']['tmp_file'][$filePath] = $hash;
1750   }
1751   
1752   /**
1753    * Retourne le chemin du fichier temporaire si l'existe
1754    * 
1755    * @author Benjamin Renard <brenard@easter-eggs.com>
1756    * 
1757    * @param[in] $value La valeur du fichier
1758    * 
1759    * @retval mixed 
1760    **/
1761   public static function tmpFileExist($value) {
1762     $hash = mhash(MHASH_MD5,$value);
1763     foreach(self :: $tmp_file as $filePath => $contentHash) {
1764       if ($hash == $contentHash) {
1765         return $filePath;
1766       }
1767     }
1768     return false;
1769   }
1770   
1771   /**
1772    * Retourne le chemin du fichier temporaire
1773    * 
1774    * Retourne le chemin du fichier temporaire qu'il créera Ã  partir de la valeur
1775    * s'il n'existe pas déjà.
1776    * 
1777    * @author Benjamin Renard <brenard@easter-eggs.com>
1778    * 
1779    * @param[in] $value La valeur du fichier
1780    * 
1781    * @retval mixed 
1782    **/
1783   public static function getTmpFile($value) {
1784     $exist = self :: tmpFileExist($value);
1785     if (!$exist) {
1786       $img_path = LS_TMP_DIR .rand().'.tmp';
1787       $fp = fopen($img_path, "w");
1788       fwrite($fp, $value);
1789       fclose($fp);
1790       self :: addTmpFile($value,$img_path);
1791       return $img_path;
1792     }
1793     else {
1794       return $exist;
1795     }
1796   }
1797   
1798   /**
1799    * Supprime les fichiers temporaires
1800    * 
1801    * @author Benjamin Renard <brenard@easter-eggs.com>
1802    * 
1803    * @retval void
1804    **/
1805   public static function deleteTmpFile($filePath=NULL) {
1806     if ($filePath) {
1807         @unlink($filePath);
1808         unset(self :: $tmp_file[$filePath]);
1809         unset($_SESSION['LSsession']['tmp_file'][$filePath]);
1810     }
1811     else {
1812       foreach(self :: $tmp_file as $file => $content) {
1813         @unlink($file);
1814       }
1815       self :: $tmp_file = array();
1816       $_SESSION['LSsession']['tmp_file'] = array();
1817     }
1818   }
1819
1820   /**
1821    * Retourne true si le cache des droits est activé
1822    *
1823    * @author Benjamin Renard <brenard@easter-eggs.com>
1824    * 
1825    * @retval boolean True si le cache des droits est activé, false sinon.
1826    */
1827   public static function cacheLSprofiles() {
1828     return ( (LSconfig :: get('cacheLSprofiles')) || (self :: $ldapServer['cacheLSprofiles']) );
1829   }
1830
1831   /**
1832    * Retourne true si le cache des subDn est activé
1833    *
1834    * @author Benjamin Renard <brenard@easter-eggs.com>
1835    * 
1836    * @retval boolean True si le cache des subDn est activé, false sinon.
1837    */
1838   public static function cacheSudDn() {
1839     return ( (LSconfig :: get('cacheSubDn')) || (self :: $ldapServer['cacheSubDn']));
1840   }
1841   
1842   /**
1843    * Retourne true si le cache des recherches est activé
1844    *
1845    * @author Benjamin Renard <brenard@easter-eggs.com>
1846    * 
1847    * @retval boolean True si le cache des recherches est activé, false sinon.
1848    */
1849   public static function cacheSearch() {
1850     return ( (LSconfig :: get('cacheSearch')) || (self :: $ldapServer['cacheSearch']));
1851   }
1852   
1853   /**
1854    * Retourne le label des niveaux pour le serveur ldap courant
1855    * 
1856    * @author Benjamin Renard <brenard@easter-eggs.com>
1857    * 
1858    * @retval string Le label des niveaux pour le serveur ldap dourant
1859    */
1860   public static function getSubDnLabel() {
1861     return (self :: $ldapServer['subDnLabel']!='')?__(self :: $ldapServer['subDnLabel']):_('Level');
1862   }
1863   
1864   /**
1865    * Retourne le nom du subDn
1866    * 
1867    * @param[in] $subDn string subDn
1868    * 
1869    * @retval string Le nom du subDn ou '' sinon
1870    */
1871   public static function getSubDnName($subDn=false) {
1872     if (!$subDn) {
1873       $subDn = self :: $topDn;
1874     }
1875     if (self :: getSubDnLdapServer()) {
1876       if (isset(self :: $_subDnLdapServer[self :: $ldapServerId][$subDn])) {
1877         return self :: $_subDnLdapServer[self :: $ldapServerId][$subDn];
1878       }
1879     }
1880     return '';
1881   }
1882
1883   /**
1884    * L'objet est t-il utilisé pour listé les subDnS
1885    * 
1886    * @param[in] $type string Le type d'objet
1887    * 
1888    * @retval boolean true si le type d'objet est un subDnObject, false sinon
1889    */
1890   public static function isSubDnLSobject($type) {
1891     $result = false;
1892     if (is_array(self :: $ldapServer['subDn']['LSobject'])) {
1893       foreach(self :: $ldapServer['subDn']['LSobject'] as $key => $value) {
1894         if ($key==$type) {
1895           $result=true;
1896         }
1897       }
1898     }
1899     return $result;
1900   }
1901   
1902   /**
1903    * Indique si un type d'objet est dans le menu courant
1904    * 
1905    * @retval boolean true si le type d'objet est dans le menu, false sinon
1906    */
1907   public static function in_menu($LSobject,$topDn=NULL) {
1908     if (!$topDn) {
1909       $topDn=self :: $topDn;
1910     }
1911     return isset(self :: $LSaccess[$topDn][$LSobject]);
1912   }
1913   
1914   /**
1915    * Indique si le serveur LDAP courant a des subDn
1916    * 
1917    * @retval boolean true si le serveur LDAP courant a des subDn, false sinon
1918    */
1919   public static function haveSubDn() {
1920     return (is_array(self :: $ldapServer['subDn']));
1921   }
1922
1923   /**
1924    * Ajoute une information à afficher
1925    * 
1926    * @param[in] $msg string Le message à afficher
1927    * 
1928    * @retval void
1929    */
1930   public static function addInfo($msg) {
1931     $_SESSION['LSsession_infos'][]=$msg;
1932   }
1933   
1934   /**
1935    * Redirection de l'utilisateur vers une autre URL
1936    * 
1937    * @param[in] $url string L'URL
1938    * @param[in] $exit boolean Si true, l'execution script s'arrête après la redirection
1939    * 
1940    * @retval void
1941    */  
1942   public static function redirect($url,$exit=true) {
1943     $GLOBALS['Smarty'] -> assign('url',$url);
1944     $GLOBALS['Smarty'] -> display('redirect.tpl');
1945     if ($exit) {
1946       exit();
1947     }
1948   }
1949   
1950   /**
1951    * Retourne l'adresse mail d'emission configurée pour le serveur courant
1952    * 
1953    * @retval string Adresse mail d'emission
1954    */
1955   public static function getEmailSender() {
1956     return self :: $ldapServer['emailSender'];  
1957   }
1958   
1959   /**
1960    * Ajout d'une information d'aide
1961    * 
1962    * @param[in] $group string Le nom du groupe d'infos dans lequels ajouter
1963    *                          celle-ci
1964    * @param[in] $infos array  Tableau array(name => value) des infos
1965    * 
1966    * @retval void
1967    */
1968   public static function addHelpInfos($group,$infos) {
1969     if (is_array($infos)) {
1970       if (is_array(self :: $_JSconfigParams['helpInfos'][$group])) {
1971         self :: $_JSconfigParams['helpInfos'][$group] = array_merge(self :: $_JSconfigParams['helpInfos'][$group],$infos);
1972       }
1973       else {
1974         self :: $_JSconfigParams['helpInfos'][$group] = $infos;
1975       }
1976     }
1977   }
1978   
1979  /**
1980   * Défini les codes erreur relative à la classe LSsession
1981   * 
1982   * @retval void
1983   */  
1984   private static function defineLSerrors() {
1985     /*
1986      * Error Codes
1987      */
1988     LSerror :: defineError('LSsession_01',
1989     _("LSsession : The constant %{const} is not defined.")
1990     );
1991     LSerror :: defineError('LSsession_02',
1992     _("LSsession : The %{addon} support is uncertain. Verify system compatibility and the add-on configuration.")
1993     );
1994     LSerror :: defineError('LSsession_03',
1995     _("LSsession : LDAP server's configuration data are invalid. Can't connect.")
1996     );
1997     LSerror :: defineError('LSsession_04',
1998     _("LSsession : Failed to load LSobject type %{type} : unknon type.")
1999     );
2000     LSerror :: defineError('LSsession_05',
2001     _("LSsession : Failed to load LSclass %{class}.")
2002     );
2003     LSerror :: defineError('LSsession_06',
2004     _("LSsession : Login or password incorrect.")
2005     );
2006     LSerror :: defineError('LSsession_07',
2007     _("LSsession : Impossible to identify you : Duplication of identities.")
2008     );
2009     LSerror :: defineError('LSsession_08',
2010     _("LSsession : Can't load Smarty template engine.")
2011     );
2012     LSerror :: defineError('LSsession_09',
2013     _("LSsession : Can't connect to LDAP server.")
2014     );
2015     LSerror :: defineError('LSsession_10',
2016     _("LSsession : Could not load type of identifiable objects.")
2017     );
2018     LSerror :: defineError('LSsession_11',
2019     _("LSsession : Your are not authorized to do this action.")
2020     );
2021     LSerror :: defineError('LSsession_12',
2022     _("LSsession : Some informations are missing to display this page.")
2023     );
2024     // 13 -> 16 : not yet used
2025     LSerror :: defineError('LSsession_17',
2026     _("LSsession : Error during creation of list of levels. Contact administrators. (Code : %{code})")
2027     );
2028     LSerror :: defineError('LSsession_18',
2029     _("LSsession : The password recovery is disabled for this LDAP server.")
2030     );
2031     LSerror :: defineError('LSsession_19',
2032     _("LSsession : Some informations are missing to recover your password. Contact administrators.")
2033     );
2034     LSerror :: defineError('LSsession_20',
2035     _("LSsession : Error during password recovery. Contact administrators.(Step : %{step})")
2036     );
2037     // 21 : not yet used
2038     LSerror :: defineError('LSsession_22',
2039     _("LSsession : problem during initialisation.")
2040     );
2041
2042
2043     // LSrelations
2044     LSerror :: defineError('LSrelations_01',
2045     _("LSrelation : The listing function for the relation %{relation} is unknow.")
2046     );
2047     LSerror :: defineError('LSrelations_02',
2048     _("LSrelation : The update function of the relation %{relation} is unknow.")
2049     );
2050     LSerror :: defineError('LSrelations_03',
2051     _("LSrelation : Error during relation update of the relation %{relation}.")
2052     );
2053     LSerror :: defineError('LSrelations_04',
2054     _("LSrelation : Object type %{LSobject} unknow (Relation : %{relation}).")
2055     );
2056     LSerror :: defineError('LSrelations_05',
2057     _("LSrelation : Some parameters are missing in the call of methods to handle standard relations (Method : %{meth}).")
2058     );
2059   }
2060
2061   public static function ajax_onLdapServerChangedLogin(&$data) {  
2062     if ( isset($_REQUEST['server']) ) {
2063       self :: setLdapServer($_REQUEST['server']);
2064       $data = array();
2065       if ( self :: LSldapConnect() ) {
2066         session_start();
2067         if (isset($_SESSION['LSsession_topDn'])) {
2068           $sel = $_SESSION['LSsession_topDn'];
2069         }
2070         else {
2071           $sel = NULL;
2072         }
2073         $list = self :: getSubDnLdapServerOptions($sel);
2074         if (is_string($list)) {
2075           $data['list_topDn'] = "<select name='LSsession_topDn' id='LSsession_topDn'>".$list."</select>";
2076           $data['subDnLabel'] = self :: getSubDnLabel();
2077         }
2078       }
2079       $data['recoverPassword'] = isset(self :: $ldapServer['recoverPassword']);
2080     }
2081   }
2082   
2083   public static function ajax_onLdapServerChangedRecoverPassword(&$data) {  
2084     if ( isset($_REQUEST['server']) ) {
2085       self :: setLdapServer($_REQUEST['server']);
2086       $data=array('recoverPassword' => isset(self :: $ldapServer['recoverPassword']));
2087     }
2088   }
2089 }
2090
2091 ?>