Code

Added saving and loading of postalCode / street. Closes #1138.
[gosa.git] / gosa-core / plugins / personal / generic / class_user.inc
index 1ad2c92648c6e8661346c29412f977183a6a4b70..f6de8cfad0f850a579116e6a91127c0270ed2d4f 100644 (file)
@@ -50,6 +50,8 @@ class user extends plugin
   var $o= "";
   var $ou= "";
   var $departmentNumber= "";
+  var $gosaLoginRestriction= array();
+  var $gosaLoginRestrictionWidget;
   var $employeeNumber= "";
   var $employeeType= "";
   var $roomNumber= "";
@@ -64,6 +66,7 @@ class user extends plugin
   var $use_dob= "0";
   var $gender="0";
   var $preferredLanguage="0";
+  var $baseSelector;
 
   var $jpegPhoto= "*removed*";
   var $photoData= "";
@@ -105,12 +108,16 @@ class user extends plugin
 
   var $view_logged = FALSE;
 
+  var $manager = "";
+  var $manager_name = "";
+
+
   /* attribute list for save action */
   var $attributes= array("sn", "givenName", "uid", "personalTitle", "academicTitle",
       "homePostalAddress", "homePhone", "labeledURI", "ou", "o", "dateOfBirth", "gender","preferredLanguage",
       "departmentNumber", "employeeNumber", "employeeType", "l", "st","jpegPhoto",
-      "roomNumber", "telephoneNumber", "mobile", "pager", "cn", "userPKCS12",
-      "postalAddress", "facsimileTelephoneNumber", "userSMIMECertificate");
+      "roomNumber", "telephoneNumber", "mobile", "pager", "cn", "userPKCS12", "street", "postalCode",
+      "postalAddress", "facsimileTelephoneNumber", "userSMIMECertificate", "gosaLoginRestriction", "manager");
 
   var $objectclasses= array("top", "person", "organizationalPerson", "inetOrgPerson",
       "gosaAccount");
@@ -124,13 +131,18 @@ class user extends plugin
 
   var $multiple_support = TRUE;
 
+  var $governmentmode = FALSE;
+
   /* constructor, if 'dn' is set, the node loads the given
      'dn' from LDAP */
   function user (&$config, $dn= NULL)
   {
+    global $lang;
+
     $this->config= $config;
     /* Configuration is fine, allways */
-    if ($this->config->current['GOVERNMENTMODE']){
+    if($this->config->get_cfg_value("honourIvbbAttributes") == "true"){
+      $this->governmentmode = TRUE;
       $this->attributes=array_merge($this->attributes,$this->govattrs);
     }
 
@@ -140,7 +152,7 @@ class user extends plugin
     $this->orig_dn  = $this->dn;
     $this->new_dn   = $dn;
 
-    if ($this->config->current['GOVERNMENTMODE']){
+    if ($this->governmentmode){
       /* Fix public visible attribute if unset */
       if (!isset($this->attrs['publicVisible'])){
         $this->publicVisible == "nein";
@@ -148,7 +160,7 @@ class user extends plugin
     }
 
     /* Load government mode attributes */
-    if ($this->config->current['GOVERNMENTMODE']){
+    if ($this->governmentmode){
       /* Copy all attributs */
       foreach ($this->govattrs as $val){
         if (isset($this->attrs["$val"][0])){
@@ -163,11 +175,7 @@ class user extends plugin
     }
 
     /* Make hash default to md5 if not set in config */
-    if (!isset($this->config->current['HASH'])){
-      $hash= "md5";
-    } else {
-      $hash= $this->config->current['HASH'];
-    }
+    $hash= $this->config->get_cfg_value("passwordDefaultHash", "crypt/md5");
 
     /* Load data from LDAP? */
     if ($dn !== NULL){
@@ -175,7 +183,7 @@ class user extends plugin
       /* Do base conversation */
       if ($this->dn == "new"){
         $ui= get_userinfo();
-        $this->base= dn2base($ui->dn);
+        $this->base= dn2base(session::global_is_set("CurrentMainBase")?"cn=dummy,".session::global_get("CurrentMainBase"):$ui->dn);
       } else {
         $this->base= dn2base($dn);
       }
@@ -186,7 +194,9 @@ class user extends plugin
        $matches= array();
         if (preg_match ("/^{[^}]+}/", $this->attrs['userPassword'][0])){
           $tmp= passwordMethod::get_method($this->attrs['userPassword'][0]);
-          $this->pw_storage= $tmp->get_hash(); 
+          if(is_object($tmp)){
+            $this->pw_storage= $tmp->get_hash(); 
+          }
 
         } else {
           if ($this->attrs['userPassword'][0] != ""){
@@ -218,23 +228,52 @@ class user extends plugin
     /* Generate dateOfBirth entry */
     if (isset ($this->attrs['dateOfBirth'])){
       /* This entry is ISO 8601 conform */
-      list($year, $month, $day)= split("-", $this->attrs['dateOfBirth'][0], 3);
+      list($year, $month, $day)= explode("-", $this->attrs['dateOfBirth'][0], 3);
     
-      $this->dateOfBirth=array( 'mon'=> $month,"mday"=> $day,"year"=> $year);
-      $this->use_dob= "1";
+      #TODO: use $lang to convert date
+      $this->dateOfBirth= "$day.$month.$year";
     } else {
-      $this->use_dob= "0";
+      $this->dateOfBirth= "";
     }
 
     /* Put gender attribute to upper case */
     if (isset ($this->attrs['gender'])){
       $this->gender= strtoupper($this->attrs['gender'][0]);
     }
+
+    // Get login restrictions
+    if(isset($this->attrs['gosaLoginRestriction'])){
+      $this->gosaLoginRestriction  =array();
+      for($i =0;$i < $this->attrs['gosaLoginRestriction']['count']; $i++){
+        $this->gosaLoginRestriction[] = $this->attrs['gosaLoginRestriction'][$i];
+      }
+    }
+    $this->gosaLoginRestrictionWidget= new sortableListing($this->gosaLoginRestriction);
+    $this->gosaLoginRestrictionWidget->setDeleteable(true);
+    $this->gosaLoginRestrictionWidget->setColspecs(array('*'));
+    $this->gosaLoginRestrictionWidget->setWidth("100%");
+    $this->gosaLoginRestrictionWidget->setHeight("70px");
  
     $this->orig_base = $this->base;
-  }
+    $this->baseSelector= new baseSelector($this->allowedBasesToMoveTo(), $this->base);
+    $this->baseSelector->setSubmitButton(false);
+    $this->baseSelector->setHeight(300);
+    $this->baseSelector->update(true);
 
 
+    // Detect the managers name
+    $this->manager_name = "";
+    $ldap = $this->config->get_ldap_link();
+    if(!empty($this->manager)){
+      $ldap->cat($this->manager, array('cn'));
+      if($ldap->count()){
+        $attrs = $ldap->fetch();
+        $this->manager_name = $attrs['cn'][0];
+      }else{
+        $this->manager_name = "("._("Unknown")."!): ".$this->manager;
+      }
+    }
+  }
 
 
   /* execute generates the html output for this node */
@@ -243,57 +282,59 @@ class user extends plugin
     /* Call parent execute */
     plugin::execute();
 
+    /* Set list ACL */
+    $this->gosaLoginRestrictionWidget->setAcl($this->getacl('gosaLoginRestriction', (!is_object($this->parent) && !session::is_set('edit'))));
+    $this->gosaLoginRestrictionWidget->update();
+
+    /* Handle add/delete for restriction mode */
+    if (isset($_POST['add_res']) && isset($_POST['res'])) {
+      $val= validate($_POST['res']);
+      if (preg_match('/^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/', $val) ||
+          preg_match('/^([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\/([0-9]+)$/', $val) ||
+          preg_match('/^([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\/([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)$/', $val)) {
+        $this->gosaLoginRestrictionWidget->addEntry($val);
+      } else {
+        msg_dialog::display(_("Error"), _("Please add a single IP address or a network/netmask combination!"), ERROR_DIALOG);
+      }
+    }
+
     /* Log view */
     if($this->is_account && !$this->view_logged){
       $this->view_logged = TRUE;
       new log("view","users/".get_class($this),$this->dn);
     }
 
-    $smarty= get_smarty();
-
-    /* Fill calendar */
-    if ($this->dateOfBirth == "0"){
-      $date= getdate();
-    } else {
-      if(is_array($this->dateOfBirth)){
-        $date = $this->dateOfBirth;
-  
-        // Trigger on dates like 1985-04-01, getdate only understands timestamps
-      } else if (!empty($this->dateOfBirth) && !is_numeric($this->dateOfBirth)){
-        $date= getdate(strtotime($this->dateOfBirth));
-
-      } else {
-        $date = getdate($this->dateOfBirth);
-      }
+    // Clear manager attribute if requested
+    if(preg_match("/ removeManager/i", " ".implode(array_keys($_POST),' ')." ")){
+      $this->manager = "";
+      $this->manager_name = "";
     }
 
-    $days= array();
-    for($d= 1; $d<32; $d++){
-      $days[$d]= $d;
+    // Allow to select a new inetOrgPersion:manager 
+    if(preg_match("/ editManager/i", " ".implode(array_keys($_POST),' ')." ")){
+      $this->dialog = new singleUserSelect($this->config, get_userinfo());
     }
-    $years= array();
+    if($this->dialog instanceOf singleUserSelect && count($this->dialog->detectPostActions())){
+      $users = $this->dialog->detectPostActions();
+      if(isset($users['targets']) && count($users['targets'])){
 
-    if(($date['year']-100)<1901){
-      $start = 1901;
-    }else{
-      $start = $date['year']-100;
+        $headpage = $this->dialog->getHeadpage();
+        $dn = $users['targets'][0];
+        $attrs = $headpage->getEntry($dn);
+        $this->manager = $dn;
+        $this->manager_name = $attrs['cn'][0];
+        $this->dialog = NULL;
+      }
     }
-
-    $end = $start +100;
-    
-    for($y= $start; $y<=$end; $y++){
-      $years[]= $y;
+    if(isset($_POST['add_users_cancel'])){
+      $this->dialog = NULL;
     }
-    $years['-']= "-&nbsp;";
-    $months= msgPool::months();
-    $months['-'] = '-&nbsp;';
+    if($this->dialog instanceOf singleUserSelect) return($this->dialog->execute()); 
+
 
-    $smarty->assign("day", $date["mday"]);
-    $smarty->assign("days", $days);
-    $smarty->assign("months", $months);
-    $smarty->assign("month", $date["mon"]-1);
-    $smarty->assign("years", $years);
-    $smarty->assign("year", $date["year"]);
+    $smarty= get_smarty();
+    $smarty->assign("usePrototype", "true");
+    $smarty->assign("gosaLoginRestrictionWidget", $this->gosaLoginRestrictionWidget->render());
 
     /* Assign sex */
     $sex= array(0 => "&nbsp;", "F" => _("female"), "M" => _("male"));
@@ -308,21 +349,11 @@ class user extends plugin
 
     /* Do we represent a valid gosaAccount? */
     if (!$this->is_account){
-      $str = "<img alt=\"\" src=\"images/stop.png\" align=\"middle\">&nbsp;<b>".
+      $str = "<img alt=\"\" src=\"images/small-error.png\" align=\"middle\">&nbsp;<b>".
         msgPool::noValidExtension("GOsa")."</b>";
       return($str);
     }
 
-    /* Base select dialog */
-    $once = true;
-    foreach($_POST as $name => $value){
-      if(preg_match("/^chooseBase/",$name) && $once){
-        $once = false;
-        $this->dialog = new baseSelectDialog($this->config,$this,$this->allowedBasesToMoveTo());
-        $this->dialog->setCurrentBase($this->base);
-      }
-    }
-
     /* Password configure dialog handling */
     if(is_object($this->pwObject) && $this->pwObject->display){
       $output= $this->pwObject->configure();
@@ -333,26 +364,6 @@ class user extends plugin
       $this->dialog= false;
     }
 
-    /* Dialog handling */
-    if(is_object($this->dialog)){
-      /* Must be called before save_object */
-      $this->dialog->save_object();
-   
-      if($this->dialog->isClosed()){
-        $this->dialog = false;
-      }elseif($this->dialog->isSelected()){
-
-        /* check if selected base is allowed to move to / create a new object */
-        $tmp = $this->get_allowed_bases();
-        if(isset($tmp[$this->dialog->isSelected()])){
-          $this->base = $this->dialog->isSelected();
-        }
-        $this->dialog= false;
-      }else{
-        return($this->dialog->execute());
-      }
-    }
-
     /* Want password method editing? */
     if ($this->acl_is_writeable("userPassword")){
       if (isset($_POST['edit_pw_method'])){
@@ -420,12 +431,6 @@ class user extends plugin
       $this->dialog= FALSE;
     }
 
-    /* Toggle dateOfBirth information */
-    if (isset($_POST['set_dob'])){
-      $this->use_dob= ($this->use_dob == "0")?"1":"0";
-    }
-
-
     /* Want certificate= */
     if ((isset($_POST['edit_cert'])) && $this->acl_is_readable("Certificate")){
 
@@ -563,19 +568,19 @@ class user extends plugin
           $smarty->assign($cert."_state","");
         }
       }
-      $this->config->current['GOVERNMENTMODE'] = "true";
-      if (isset($this->config->current['GOVERNMENTMODE']) &&
-          preg_match('/true/i', $this->config->current['GOVERNMENTMODE'])){
-        $smarty->assign("governmentmode", "true");
+  
+      if($this->governmentmode){
+        $smarty->assign("honourIvbbAttributes", "true");
       }else{
-        $smarty->assign("governmentmode", "false");
+        $smarty->assign("honourIvbbAttributes", "false");
       }
+      $smarty->assign("governmentmode", $this->governmentmode);
       return($smarty->fetch (get_template_path('generic_certs.tpl', TRUE, dirname(__FILE__))));
     }
 
     /* Prepare password hashes */
     if ($this->pw_storage == ""){
-      $this->pw_storage= $this->config->current['HASH'];
+      $this->pw_storage= $this->config->get_cfg_value("passwordDefaultHash");
     }
 
     $temp= passwordMethod::get_available_methods();
@@ -587,7 +592,18 @@ class user extends plugin
     }else{
       new msg_dialog(_("Password method"),_("The selected password method is no longer available."),WARNING_DIALOG);
     }
-    
+
+
+    /* Create password methods array */
+    $pwd_methods = array();
+    foreach($hashes as $id => $name){
+      if(!empty($temp['desc'][$id])){
+        $pwd_methods[$name] = $name." (".$temp['desc'][$id].")";
+      }else{
+        $pwd_methods[$name] = $name;
+      }
+    }
     /* Load attributes and acl's */
     $ui =get_userinfo();
     foreach($this->attributes as $val){
@@ -612,22 +628,30 @@ class user extends plugin
       $smarty->assign("$val"."ACL", $this->getacl($val,(!is_object($this->parent) && !session::is_set('edit'))));
     }
 
-    $smarty->assign("pwmode", $hashes);
+    // Special ACL for gosaLoginRestrictions - 
+    // In case of multiple edit, we need a readonly ACL for the list. 
+    $smarty->assign('gosaLoginRestriction_ONLY_R_ACL', 
+      preg_replace("/[^r]/i","", $this->getacl($val,(!is_object($this->parent) && !session::is_set('edit')))));
+
+    $smarty->assign("pwmode", $pwd_methods);
     $smarty->assign("pwmode_select", $this->pw_storage);
     $smarty->assign("pw_configurable", $is_configurable);
     $smarty->assign("passwordStorageACL", $this->getacl("userPassword",(!is_object($this->parent) && !session::is_set('edit'))));
-    $smarty->assign("base_select",      $this->base);
-    $smarty->assign("CertificatesACL",  $this->getacl("Certificate",(!is_object($this->parent) && !session::is_set('edit'))));
+
+    if(!session::is_set('edit')){
+      $smarty->assign("CertificatesACL","");
+    }else{
+      $smarty->assign("CertificatesACL",  $this->getacl("Certificate"));
+    }
+    
     $smarty->assign("userPictureACL",   $this->getacl("userPicture",(!is_object($this->parent) && !session::is_set('edit'))));
     $smarty->assign("userPicture_is_readable",   $this->acl_is_readable("userPicture",(!is_object($this->parent) && !session::is_set('edit'))));
 
     /* Create base acls */
-    $tmp = @$this->allowedBasesToMoveTo();
-    $smarty->assign("bases", $tmp);
+    $smarty->assign("base", $this->baseSelector->render());
 
     /* Save government mode attributes */
-    if (isset($this->config->current['GOVERNMENTMODE']) &&
-        preg_match('/true/i', $this->config->current['GOVERNMENTMODE'])){
+    if($this->governmentmode){
       $smarty->assign("governmentmode", "true");
       $ivbbmodes= array("nein", "ivbv", "testa", "ivbv,testa", "internet",
           "internet,ivbv", "internet,testa", "internet,ivbv,testa");
@@ -665,6 +689,7 @@ class user extends plugin
       $smarty->assign("has_phoneaccount", "false");
     }
     $smarty->assign("multiple_support" , $this->multiple_support_active);
+    $smarty->assign("manager_name",$this->manager_name);
     return($smarty->fetch (get_template_path('generic.tpl', TRUE, dirname(__FILE__))));
   }
 
@@ -672,10 +697,17 @@ class user extends plugin
   /* remove object from parent */
   function remove_from_parent()
   {
+    /* Only remove valid accounts */
+    if(!$this->initially_was_account) return;
+
     /* Remove password extension */
     $temp= passwordMethod::get_available_methods();
-    $this->pwObject= new $temp[$this->pw_storage]($this->config,$this->dn);
-    $this->pwObject->remove_from_parent();
+
+    /* Remove password method from user account */
+    if(isset($temp[$this->pw_storage]) && class_available($temp[$this->pw_storage])){
+      $this->pwObject= new $temp[$this->pw_storage]($this->config,$this->dn);
+      $this->pwObject->remove_from_parent();
+    }
 
     /* Remove user */
     $ldap= $this->config->get_ldap_link();
@@ -704,6 +736,36 @@ class user extends plugin
       $og->save ();
     }
 
+    // Update 'manager' attributes from gosaDepartment and inetOrgPerson
+    $filter = "(&(objectClass=inetOrgPerson)(manager=".LDAP::prepare4filter($this->dn)."))";
+    $ocs = $ldap->get_objectclasses();
+    if(isset($ocs['gosaDepartment']['MAY']) && in_array('manager', $ocs['gosaDepartment']['MAY'])){
+      $filter = "(|".$filter."(&(objectClass=gosaDepartment)(manager=".LDAP::prepare4filter($this->dn).")))";
+    }
+    $leaf_deps=  get_list($filter,array("all"),$this->config->current['BASE'],
+        array("manager","dn","objectClass"),GL_SUBSEARCH | GL_NO_ACL_CHECK);
+    foreach($leaf_deps as $entry){
+      $update = array('manager' => array());
+      $ldap->cd($entry['dn']);
+      $ldap->modify($update);
+      if(!$ldap->success()){
+        trigger_error(sprintf("Failed to update manager for '%s', error was '%s'", $entry['dn'], $ldap->get_error()));
+      }
+    }
+
+    /* Delete references to roles */
+    $ldap->cd ($this->config->current['BASE']);
+    $ldap->search ("(&(objectClass=organizationalRole)(roleOccupant=".LDAP::prepare4filter($this->dn)."))", array("cn"));
+    while ($ldap->fetch()){
+      $role= new roleGeneric($this->config, $ldap->getDN());
+      $key = array_search($this->dn,$role->roleOccupant);
+      if($key !== FALSE){
+        unset($role->roleOccupant[$key]);
+        $role->roleOccupant= array_values($role->roleOccupant);
+        $role->save ();
+      }
+    }
+
     /* If needed, let the password method do some cleanup */
     $tmp = new passwordMethod($this->config);
     $available = $tmp->get_available_methods();
@@ -715,8 +777,7 @@ class user extends plugin
     }
 
     /* Remove ACL dependencies too */
-    $tmp = new acl($this->config,$this->parent,$this->dn);
-    $tmp->remove_acl();
+    acl::remove_acl_for($this->dn);
 
     /* Optionally execute a command after we're done */
     $this->handle_post_events("remove",array("uid" => $this->uid));
@@ -734,8 +795,26 @@ class user extends plugin
       /* Parents save function */
       plugin::save_object ();
 
+      /* Refresh base */
+      if ($this->acl_is_moveable($this->base) || 
+            ($this->dn == "new" && $this->acl_is_createable($this->base))){
+        if (!$this->baseSelector->update()) {
+          msg_dialog::display(_("Error"), msgPool::permMove(), ERROR_DIALOG);
+        }
+        if ($this->base != $this->baseSelector->getBase()) {
+          $this->base= $this->baseSelector->getBase();
+          $this->is_modified= TRUE;
+        }
+      }
+      
+      /* Sync lists */
+      $this->gosaLoginRestrictionWidget->save_object();
+      if ($this->gosaLoginRestrictionWidget->isModified()) {
+        $this->gosaLoginRestriction= array_values($this->gosaLoginRestrictionWidget->getMaintainedData());
+      }
+
       /* Save government mode attributes */
-      if ($this->config->current['GOVERNMENTMODE']){
+      if ($this->governmentmode){
         foreach ($this->govattrs as $val){
           if ($this->acl_is_writeable($val,(!is_object($this->parent) && !session::is_set('edit'))) && isset($_POST["$val"])){
             $data= stripcslashes($_POST["$val"]);
@@ -753,23 +832,6 @@ class user extends plugin
         $this->givenName= $this->sn;
       }
 
-      /* Save base and pw_storage, since these are no LDAP attributes */
-      if (isset($_POST['base'])){
-
-        $tmp = $this->get_allowed_bases();
-        if(isset($tmp[$_POST['base']])){
-          $base= validate($_POST['base']);
-          if ($base != $this->base){
-            $this->is_modified= TRUE;
-          }
-          $this->base= $base;
-        }else{
-          $this->base = $base_tmp;
-          msg_dialog::display(_("Error"), msgPool::permMove(), ERROR_DIALOG);
-          $this->set_acl_base('dummy,'.$this->base);
-        }
-      }
-
       /* Get pw_storage mode */
       if (isset($_POST['pw_storage'])){
         foreach(array("pw_storage") as $val){
@@ -783,7 +845,23 @@ class user extends plugin
         }
       }
 
-      $this->set_acl_base('dummy,'.$this->base);
+      if($this->pw_storage != $this->last_pw_storage && isset($_POST['pw_storage'])){
+        if ($this->acl_is_writeable("userPassword")){
+          $temp= passwordMethod::get_available_methods();
+          if (!is_object($this->pwObject) || !($this->pwObject instanceOf $temp[$this->pw_storage])){
+            foreach($temp as $id => $data){
+              if(isset($data['name']) && $data['name'] == $this->pw_storage && $data['is_configurable']){
+                $this->pwObject= new $temp[$this->pw_storage]($this->config,$this->dn);
+                break;
+              }
+            }
+          }
+        }
+      }
+
+      /* Save current cn
+       */
+      $this->cn = $this->givenName." ".$this->sn;
     }
   }
 
@@ -805,19 +883,23 @@ class user extends plugin
   /* Save data to LDAP, depending on is_account we save or delete */
   function save()
   {
+    global $lang;
+
     /* Only force save of changes .... 
        If this attributes aren't changed, avoid saving.
      */
+  
     if($this->gender=="0") $this->gender ="";
     if($this->preferredLanguage=="0") $this->preferredLanguage ="";
 
     /* First use parents methods to do some basic fillup in $this->attrs */
     plugin::save ();
 
-    if ($this->use_dob == "1"){
-      /* If it is an array, the generic page has never been loaded - so there's no difference. Using an array would cause an error btw. */
+    if ($this->dateOfBirth != ""){
       if(!is_array($this->attrs['dateOfBirth'])) {
-        $this->attrs['dateOfBirth'] = date("Y-m-d", $this->dateOfBirth);
+        #TODO: use $lang to convert date
+        list($day, $month, $year)= explode(".", $this->dateOfBirth);
+        $this->attrs['dateOfBirth'] = sprintf("%04d-%02d-%02d", $year, $month, $day);
       }
     }
 
@@ -846,7 +928,7 @@ class user extends plugin
     }
 
     /* Hard coded government mode? */
-    if ($this->config->current['GOVERNMENTMODE'] != 'false'){
+    if ($this->governmentmode){
       $this->attrs['objectClass'][]= "ivbbentry";
 
       /* Copy standard attributes */
@@ -880,7 +962,7 @@ class user extends plugin
     }
 
     /* Special handling for dateOfBirth value */
-    if ($this->use_dob != "1"){
+    if ($this->dateOfBirth == ""){
       if ($this->is_new) {
         unset($this->attrs["dateOfBirth"]);
       } else {
@@ -905,72 +987,57 @@ class user extends plugin
     /* Special handling for attribute jpegPhote needed, scale image via
        image magick to 147x200 pixels and inject resulting data. */
     if ($this->jpegPhoto == "*removed*"){
-    
-      /* Reset attribute to avoid writing *removed* as value */    
-      $this->attrs["jpegPhoto"] = array();
-
-    } else {
-
-      /* Fallback if there's no image magick inside PHP */
-      if (!function_exists("imagick_blob2image")){
-        /* Get temporary file name for conversation */
-        $fname = tempnam ("/tmp", "GOsa");
-  
-        /* Open file and write out photoData */
-        $fp = fopen ($fname, "w");
-        fwrite ($fp, $this->photoData);
-        fclose ($fp);
-
-        /* Build conversation query. Filename is generated automatically, so
-           we do not need any special security checks. Exec command and save
-           output. For PHP safe mode, you'll need a configuration which respects
-           image magick as executable... */
-        $query= "convert -size 147x200 $fname -resize 147x200 +profile \"*\" -";
-        @DEBUG (DEBUG_SHELL, __LINE__, __FUNCTION__, __FILE__,
-            $query, "Execute");
-  
-        /* Read data written by convert */
-        $output= "";
-        $sh= popen($query, 'r');
-        while (!feof($sh)){
-          $output.= fread($sh, 4096);
-        }
-        pclose($sh);
-
-        unlink($fname);
 
-        /* Save attribute */
-        $this->attrs["jpegPhoto"] = $output;
-
-      } else {
+        /* Reset attribute to avoid writing *removed* as value */    
+        $this->attrs["jpegPhoto"] = array();
 
-        /* Load the new uploaded Photo */
-        if(!$handle  =  imagick_blob2image($this->photoData))  {
-          new log("debug","users/".get_class($this),$this->dn,array(),"Could not access uploaded image");
-        }
+    } else {
 
-        /* Resizing image to 147x200 and blur */
-        if(!imagick_resize($handle,147,200,IMAGICK_FILTER_GAUSSIAN,0)){
-          new log("debug","users/".get_class($this),$this->dn,array(),"Could not resize uploaded image");
-        }
+       if(class_exists('Imagick')){
+
+            $im = new Imagick();
+            $im->readImageBlob($this->photoData);
+            $im->setImageOpacity(1.0);
+            $im->resizeImage(147,200,Imagick::FILTER_UNDEFINED,0.5,TRUE);
+            $im->setCompressionQuality(90);
+            $im->setImageFormat('jpeg');
+            $this->attrs["jpegPhoto"] = $im->getImageBlob();
+
+        }elseif(exec('convert')){
+
+            /* Get temporary file name for conversation */
+            $fname = tempnam (TEMP_DIR, "GOsa");
+
+            /* Open file and write out photoData */
+            $fp = fopen ($fname, "w");
+            fwrite ($fp, $this->photoData);
+            fclose ($fp);
+
+            /* Build conversation query. Filename is generated automatically, so
+               we do not need any special security checks. Exec command and save
+               output. For PHP safe mode, you'll need a configuration which respects
+               image magick as executable... */
+            $query= "convert -size 147x200 $fname -resize 147x200 +profile \"*\" -";
+            @DEBUG (DEBUG_SHELL, __LINE__, __FUNCTION__, __FILE__,
+                    $query, "Execute");
+
+            /* Read data written by convert */
+            $output= "";
+            $sh= popen($query, 'r');
+            while (!feof($sh)){
+                $output.= fread($sh, 4096);
+            }
+            pclose($sh);
 
-        /* Converting image to JPEG */
-        if(!imagick_convert($handle,"JPEG")) {
-          new log("debug","users/".get_class($this),$this->dn,array(),"Could not convert uploaded image to jepg");
-        }
+            unlink($fname);
 
-        /* Creating binary Code for the Image */
-        if(!$dump = imagick_image2blob($handle)){
-          new log("debug","users/".get_class($this),$this->dn,array(),"Could not create new user image");
+            /* Save attribute */
+            $this->attrs["jpegPhoto"] = $output;
+        }else{
+            msg_dialog::display(_("Error"), 
+                    _("Cannot save user picture, GOsa requires the package 'imagemagick' or 'php5-imagick' to be installed!"), 
+                    ERROR_DIALOG);
         }
-
-        /* Sending Image */
-        $output=  $dump;
-
-        /* Save attribute */
-        $this->attrs["jpegPhoto"] = $output;
-      }
-
     }
 
     /* This only gets called when user is renaming himself */
@@ -1000,7 +1067,15 @@ class user extends plugin
 
     /* Set password to some junk stuff in case of templates */
     if ($this->is_template){
-      $this->attrs['userPassword']= '{crypt}N0T$3T4N0W';
+      $temp= passwordMethod::get_available_methods();
+      foreach($temp as $id => $data){
+        if(isset($data['name']) && $data['name'] == $this->pw_storage){
+          $tmp = new  $temp[$this->pw_storage]($this->config,$this->dn);
+          $tmp->set_hash($this->pw_storage);
+          $this->attrs['userPassword'] = $tmp->create_template_hash($this->attrs);
+          break;
+        }
+      }
     }
 
     @DEBUG (DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__,
@@ -1009,8 +1084,9 @@ class user extends plugin
     /* Finally write data with selected 'mode' */
     $this->cleanup();
 
-    if(isset($this->attrs['preferredLanguage'])){
-      $ui = session::get('ui');
+    /* Update current locale settings, if we have edited ourselves */
+    $ui = session::get('ui');
+    if(isset($this->attrs['preferredLanguage']) && $this->dn == $ui->dn){
       $ui->language = $this->preferredLanguage;
       session::set('ui',$ui);
       session::set('Last_init_lang',"update");
@@ -1049,11 +1125,11 @@ class user extends plugin
         die ("Could not connect to LDAP server");
       }
       ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
-      if (function_exists("ldap_set_rebind_proc") && isset($this->config->current['RECURSIVE']) && $this->config->current['RECURSIVE'] == "true") {
+      if (function_exists("ldap_set_rebind_proc") && $this->config->get_cfg_value("ldapFollowReferrals") == "true") {
         ldap_set_option($this->cid, LDAP_OPT_REFERRALS, 1);
         ldap_set_rebind_proc($ds, array(&$this, "rebind"));
       }
-      if(isset($config->current['TLS']) && $config->current['TLS'] == "true"){
+      if($this->config->get_cfg_value("ldapTLS") == "true"){
         ldap_start_tls($ds);
       }
       if (!($res = @ldap_bind($ds, $this->config->current['ADMIN'],
@@ -1092,27 +1168,89 @@ class user extends plugin
     return (0);
   }
 
+
+  function create_initial_rdn($pattern)
+  {
+    // Only generate single RDNs
+    if (preg_match('/\+/', $pattern)){
+      msg_dialog::display(_("Error"), _("Cannot build RDN: no + allowed to build sub RDN!"), ERROR_DIALOG);
+      return "";
+    }
+
+    // Extract attribute
+    $attribute= preg_replace('/=.*$/', '', $pattern);
+    if (!in_array_ics($attribute, $this->attributes)) {
+      msg_dialog::display(_("Error"), _("Cannot build RDN: attribute is not defined!"), ERROR_DIALOG);
+      return "";
+    }
+
+    // Sort attributes for length
+    $attrl= array();
+    foreach ($this->attributes as $attr) {
+      $attrl[$attr]= strlen($attr);
+    }
+    arsort($attrl);
+    
+    // Walk thru sorted attributes and replace them in pattern
+    foreach ($attrl as $attr => $dummy) {
+      if (!is_array($this->$attr)){
+        $pattern= preg_replace("/%$attr/", $this->$attr, $pattern);
+      } else {
+        // Array elements cannot be used for ID generation
+        if (preg_match("/%$attr/", $pattern)) {
+          msg_dialog::display(_("Error"), _("Cannot build RDN: invalid attribute parameters!"), ERROR_DIALOG);
+          break;
+        }
+      }
+    }
+
+    // Internally assign value
+    $this->$attribute= preg_replace('/^[^=]+=/', '', $pattern);
+
+    return $pattern;
+  }
+
   
   function update_new_dn()
   {
-    $pt= "";
-    if(isset($this->config->current['INCLUDE_PERSONAL_TITLE']) && preg_match("/true/i",$this->config->current['INCLUDE_PERSONAL_TITLE'])){
-      if(!empty($this->personalTitle)){
-        $pt = $this->personalTitle." ";
+    // Alternative way to handle DN
+    $pattern= $this->config->get_cfg_value("accountRDN");
+    if ($pattern != "") {
+      $rdn= $this->create_initial_rdn($pattern);
+      $attribute= preg_replace('/=.*$/', '', $rdn);
+      $value= preg_replace('/^[^=]+=$/', '', $rdn);
+
+      /* Don't touch dn, if $attribute hasn't changed */
+      if (isset($this->saved_attributes[$attribute]) && $this->saved_attributes[$attribute] == $this->$attribute &&
+            $this->orig_base == $this->base ){
+        $this->new_dn= $this->dn;
+      } else {
+        $this->new_dn= $this->create_unique_dn2($rdn, get_people_ou().$this->base);
       }
-    }
-    $this->cn= $pt.$this->givenName." ".$this->sn;
 
-    /* Permissions for that base? */
-    if (isset($this->config->current['DNMODE']) && $this->config->current['DNMODE'] == "uid"){
-      $this->new_dn= 'uid='.$this->uid.','.get_people_ou().$this->base;
+    // Original way to handle DN
     } else {
-      /* Don't touch dn, if cn hasn't changed */
-      if (isset($this->saved_attributes['cn']) && $this->saved_attributes['cn'] == $this->cn &&
-          $this->orig_base == $this->base ){
-        $this->new_dn= $this->dn;
+
+      $pt= "";
+      if($this->config->get_cfg_value("personalTitleInDN") == "true"){
+        if(!empty($this->personalTitle)){
+          $pt = $this->personalTitle." ";
+        }
+      }
+
+      $this->cn= $pt.$this->givenName." ".$this->sn;
+
+      /* Permissions for that base? */
+      if ($this->config->get_cfg_value("accountPrimaryAttribute") == "uid"){
+        $this->new_dn= 'uid='.$this->uid.','.get_people_ou().$this->base;
       } else {
-        $this->new_dn= $this->create_unique_dn('cn', get_people_ou().$this->base);
+        /* Don't touch dn, if cn hasn't changed */
+        if (isset($this->saved_attributes['cn']) && $this->saved_attributes['cn'] == $this->cn &&
+            $this->orig_base == $this->base ){
+          $this->new_dn= $this->dn;
+        } else {
+          $this->new_dn= $this->create_unique_dn('cn', get_people_ou().$this->base);
+        }
       }
     }
   }
@@ -1124,6 +1262,20 @@ class user extends plugin
     /* Call common method to give check the hook */
     $message= plugin::check();
 
+    /* Configurable password methods should be configured initially. 
+     */ 
+    if($this->last_pw_storage != $this->pw_storage){
+      $temp= passwordMethod::get_available_methods();
+      foreach($temp['name'] as $id => $name){
+        if($name == $this->pw_storage){
+          if($temp['is_configurable'][$id] && !$this->pwObject instanceof $temp[$name] ){
+            $message[] = _("The selected password method requires initial configuration!");
+          }
+          break;
+        }
+      }
+    }
+
     $this->update_new_dn();
 
     /* Set the new acl base */
@@ -1131,6 +1283,13 @@ class user extends plugin
       $this->set_acl_base($this->base);
     }
 
+    /* Check if we are allowed to create/move this user */
+    if($this->orig_dn == "new" && !$this->acl_is_createable($this->base)){
+      $message[]= msgPool::permCreate();
+    }elseif($this->orig_dn != "new" && $this->new_dn != $this->orig_dn && !$this->acl_is_moveable($this->base)){
+      $message[]= msgPool::permMove();
+    }
+
     /* UID already used? */
     $ldap= $this->config->get_ldap_link();
     $ldap->cd($this->config->current['BASE']);
@@ -1141,17 +1300,23 @@ class user extends plugin
     }
 
     /* In template mode, the uid and givenName are autogenerated... */
+    if ($this->sn == ""){
+      $message[]= msgPool::required(_("Name"));
+    }
+
+    // Check if a wrong base was supplied
+    if(!$this->baseSelector->checkLastBaseUpdate()){
+      $message[]= msgPool::check_base();;
+    }
+
     if (!$this->is_template){
-      if ($this->sn == ""){
-        $message[]= msgPool::required(_("Name"));
-      }
       if ($this->givenName == ""){
         $message[]= msgPool::required(_("Given name"));
       }
       if ($this->uid == ""){
         $message[]= msgPool::required(_("Login"));
       }
-      if (!(isset($this->config->current['DNMODE']) && $this->config->current['DNMODE'] == "uid")){
+      if ($this->config->get_cfg_value("accountPrimaryAttribute") != "uid"){
         $ldap->cat($this->new_dn);
         if ($ldap->count() != 0 && $this->dn != $this->new_dn && $this->dn == 'new'){
           $message[]= msgPool::duplicated(_("Name"));
@@ -1186,6 +1351,11 @@ class user extends plugin
       $message[]= msgPool::invalid(_("Pager"), $this->pager, "/[\/0-9 ()+*-]/");
     }
 
+    /* Check dates */
+    if (!tests::is_date($this->dateOfBirth)){
+      $message[]= msgPool::invalid(_("Date of birth"), $this->dateOfBirth,"" ,"23.02.2009");
+    }
+
     /* Check for reserved characers */
     if (preg_match ('/[,+"?\'()=<>;\\\\]/', $this->givenName)){
       $message[]= msgPool::invalid(_("Given name"), $this->givenName, '/[^,+"?\'()=<>;\\\\]/');
@@ -1201,10 +1371,15 @@ class user extends plugin
   /* Indicate whether a password change is needed or not */
   function password_change_needed()
   {
-    if(in_array("pw_storage",$this->multi_boxes)){
-      return(TRUE);
+    if($this->multiple_support_active){
+      return(FALSE);
+    }else{
+
+      if(in_array("pw_storage",$this->multi_boxes)){
+        return(TRUE);
+      }
+      return($this->pw_storage != $this->last_pw_storage && !$this->is_template);
     }
-    return($this->pw_storage != $this->last_pw_storage);
   }
 
 
@@ -1218,7 +1393,7 @@ class user extends plugin
     if((!$data) || ($data == "*removed*")){ 
 
       /* In case we don't get an entry, load a default picture */
-      $this->set_picture ();//"./images/default.jpg");
+      $this->set_picture ();
       $this->jpegPhoto= "*removed*";
     }else{
 
@@ -1236,13 +1411,11 @@ class user extends plugin
   {
     $ds= ldap_connect($this->config->current['SERVER']);
     ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
-    if (function_exists("ldap_set_rebind_proc") && isset($this->config->current['RECURSIVE']) && $this->config->current['RECURSIVE'] == "true") {
+    if (function_exists("ldap_set_rebind_proc") && $this->config->get_cfg_value("ldapFollowReferrals") == "true"){
       ldap_set_option($this->cid, LDAP_OPT_REFERRALS, 1);
       ldap_set_rebind_proc($ds, array(&$this, "rebind"));
     }
-    if(isset($this->config->current['TLS']) &&
-        $this->config->current['TLS'] == "true"){
-
+    if ($this->config->get_cfg_value("ldapTLS") == "true"){
       ldap_start_tls($ds);
     }
 
@@ -1271,7 +1444,7 @@ class user extends plugin
   function set_picture($filename ="")
   {
     if (!is_file($filename) || $filename =="" ){
-      $filename= "./images/default.jpg";
+      $filename= "./plugins/users/images/default.jpg";
       $this->jpegPhoto= "*removed*";
     }
 
@@ -1300,18 +1473,34 @@ class user extends plugin
   }
 
   /* Adapt from given 'dn' */
-  function adapt_from_template($dn)
+  function adapt_from_template($dn, $skip= array())
   {
-    plugin::adapt_from_template($dn);
+    plugin::adapt_from_template($dn, $skip);
+
+    /* Get password method from template 
+     */
+    $tmp= passwordMethod::get_method($this->attrs['userPassword'][0]);
+    if(is_object($tmp)){
+      if($tmp->is_configurable()){
+        $tmp->adapt_from_template($dn);
+        $this->pwObject = &$tmp;
+      }
+      $this->pw_storage= $tmp->get_hash();
+    }
 
     /* Get base */
-    $this->base= preg_replace('/^[^,]+,'.get_people_ou().'/i', '', $dn);
+    $this->base= preg_replace('/^[^,]+,'.preg_quote(get_people_ou(), '/').'/i', '', $dn);
+    $this->baseSelector->setBase($this->base);
 
-    if ($this->config->current['GOVERNMENTMODE']){
+    if($this->governmentmode){
 
       /* Walk through govattrs */
       foreach ($this->govattrs as $val){
 
+        if (in_array($val, $skip)){
+          continue;
+        }
+
         if (isset($this->attrs["$val"][0])){
 
           /* If attribute is set, replace dynamic parts: 
@@ -1329,12 +1518,25 @@ class user extends plugin
       }
     }
 
-    /* Get back uid/sn/givenName */
-    if ($this->parent !== NULL){
+    /* Get back uid/sn/givenName - only write if nothing's skipped */
+    if ($this->parent !== NULL && count($skip) == 0){
       $this->uid= $this->parent->uid;
       $this->sn= $this->parent->sn;
       $this->givenName= $this->parent->givenName;
     }
+
+
+    /* Generate dateOfBirth entry */
+    if (isset ($this->attrs['dateOfBirth'])){
+      /* This entry is ISO 8601 conform */
+      list($year, $month, $day)= explode("-", $this->attrs['dateOfBirth'][0], 3);
+
+      #TODO: use $lang to convert date
+      $this->dateOfBirth= "$day.$month.$year";
+    } else {
+      $this->dateOfBirth= "";
+    }
+
   }
 
  
@@ -1383,7 +1585,7 @@ class user extends plugin
   function saveCopyDialog()
   {
     /* Set_acl_base */
-    $this->set_acl_base("cn=dummy,".get_people_ou().$this->base);
+    $this->set_acl_base($this->base);
 
     if((isset($_FILES['picture_file']['tmp_name'])) && ($_FILES['picture_file']['size'] > 0)){
       $this->set_picture($_FILES['picture_file']['tmp_name']);
@@ -1392,7 +1594,7 @@ class user extends plugin
     /* Remove picture? */
     if (isset($_POST['picture_remove'])){
       $this->jpegPhoto= "*removed*";
-      $this->set_picture ("./images/default.jpg");
+      $this->set_picture ("./plugins/users/images/default.jpg");
       $this->is_modified= TRUE;
     }
 
@@ -1419,6 +1621,20 @@ class user extends plugin
     $this->old_userPKCS12= "";
     $this->old_userSMIMECertificate= "";
     $this->old_userCertificate= "";
+
+    /* Generate dateOfBirth entry */
+    if (isset ($source['dateOfBirth'])){
+        list($year, $month, $day)= explode("-", $source['dateOfBirth'][0], 3);
+        $this->dateOfBirth= "$day.$month.$year";
+    } else {
+        $this->dateOfBirth= "";
+    }
+
+    // Try to load the user picture
+    $tmp_dn = $this->dn;
+    $this->dn = $source['dn'];
+    $this->load_picture();
+    $this->dn = $tmp_dn;
   }
 
 
@@ -1451,40 +1667,50 @@ class user extends plugin
                                                   "objectClass" => "gosaAccount")),
 
         "plProvidedAcls" => array(
-          "base"              => _("Base"), 
-          "userPassword"      => _("User password"), 
-          "sn"                => _("Surename"),
+
+          "sn"                => _("Surname"),
           "givenName"         => _("Given name"),
           "uid"               => _("User identification"),
           "personalTitle"     => _("Personal title"),
           "academicTitle"     => _("Academic title"),
-          "homePostalAddress" => _("Home postal address"),
-          "homePhone"         => _("Home phone number"),
-          "labeledURI"        => _("Homepage"),
-          "o"                 => _("Organization"),
-          "ou"                => _("Department"),
+
           "dateOfBirth"       => _("Date of birth"),
-          "gender"            => _("Gender"),
+          "gender"            => _("Sex"),
           "preferredLanguage" => _("Preferred language"),
+          "base"              => _("Base"), 
+
+          "userPicture"       => _("User picture"),
+
+          "gosaLoginRestriction" => _("Login restrictions"),         
+
+          "o"                 => _("Organization"),
+          "ou"                => _("Department"),
           "departmentNumber"  => _("Department number"),
+          "manager"           => _("Manager"),
           "employeeNumber"    => _("Employee number"),
           "employeeType"      => _("Employee type"),
-          "l"                 => _("Location"),
-          "st"                => _("State"),
-          "userPicture"       => _("User picture"),
+
           "roomNumber"        => _("Room number"),
           "telephoneNumber"   => _("Telefon number"),
-          "mobile"            => _("Mobile number"),
           "pager"             => _("Pager number"),
-          "Certificate"        => _("User certificates"),
+          "mobile"            => _("Mobile number"),
+          "facsimileTelephoneNumber"     => _("Fax number"),
+
+          "st"                => _("State"),
+          "l"                 => _("Location"),
+          "postalAddress"     => _("Postal address"),
+
+          "homePostalAddress" => _("Home postal address"),
+          "homePhone"         => _("Home phone number"),
+          "labeledURI"        => _("Homepage"),
+          "userPassword"      => _("User password method"), 
+          "Certificate"       => _("User certificates"))
 
-          "postalAddress"                => _("Postal address"),
-          "facsimileTelephoneNumber"     => _("Fax number"))
         );
 
     /* Append government attributes if required */
-      global $config;
-    if (isset($config->current['GOVERNMENTMODE']) &&  preg_match('/true/i', $config->current['GOVERNMENTMODE'])){
+    global $config;
+    if($config->get_cfg_value("honourIvbbAttributes") == "true"){
       foreach($govattrs as $attr => $desc){
         $ret["plProvidedAcls"][$attr] = $desc;
       }
@@ -1515,12 +1741,19 @@ class user extends plugin
       $ret['orig_base']="Changed_by_Multi_Plug";
       $ret['base']=$this->base;
     }
+
+    $ret['gosaLoginRestriction'] = $this->gosaLoginRestriction;
+    $ret['gosaLoginRestriction_some'] = $this->gosaLoginRestriction_some;
+
     return($ret); 
   }
 
 
   function multiple_save_object()
   {
+
+    if(!isset($_POST['user_mulitple_edit'])) return;
+
     plugin::multiple_save_object();
 
     /* Get pw_storage mode */
@@ -1535,8 +1768,15 @@ class user extends plugin
         }
       }
     }
-    if(isset($_POST['base'])){
-      $this->base = get_post('base');
+  
+    /* Refresh base */
+    if ($this->acl_is_moveable($this->base)){
+      if (!$this->baseSelector->update()) {
+        msg_dialog::display(_("Error"), msgPool::permMove(), ERROR_DIALOG);
+      }
+      if ($this->base != $this->baseSelector->getBase()) {
+        $this->base= $this->baseSelector->getBase();
+      }
     }
 
     if(isset($_POST['user_mulitple_edit'])){
@@ -1546,6 +1786,12 @@ class user extends plugin
         }
       }
     }
+
+    /* Sync lists */
+    $this->gosaLoginRestrictionWidget->save_object();
+    if ($this->gosaLoginRestrictionWidget->isModified()) {
+      $this->gosaLoginRestriction= array_values($this->gosaLoginRestrictionWidget->getMaintainedData());
+    }
   }
 
   
@@ -1590,6 +1836,89 @@ class user extends plugin
   }
 
 
+  /*! \brief  Prepares the plugin to be used for multiple edit
+   *          Update plugin attributes with given array of attribtues.
+   *  \param  array   Array with attributes that must be updated.
+   */
+  function init_multiple_support($attrs,$all)
+  {
+    plugin::init_multiple_support($attrs,$all);
+
+    // Get login restrictions
+    if(isset($attrs['gosaLoginRestriction'])){
+      $this->gosaLoginRestriction  =array();
+      for($i =0;$i < $attrs['gosaLoginRestriction']['count']; $i++){
+        $this->gosaLoginRestriction[] = $attrs['gosaLoginRestriction'][$i];
+      }
+    }
+
+    // Detect the managers name
+    $this->manager_name = "";
+    $ldap = $this->config->get_ldap_link();
+    if(!empty($this->manager)){
+      $ldap->cat($this->manager, array('cn'));
+      if($ldap->count()){
+        $attrs = $ldap->fetch();
+        $this->manager_name = $attrs['cn'][0];
+      }else{
+        $this->manager_name = "("._("Unknown")."!): ".$this->manager;
+      }
+    }
+
+    // Detect login restriction not used in all user objects.
+    $this->gosaLoginRestriction_some = array();
+    if(isset($all['gosaLoginRestriction'])){
+      for($i=0;$i<$all['gosaLoginRestriction']['count'];$i++){
+        $this->gosaLoginRestriction_some[] = $all['gosaLoginRestriction'][$i];
+      }
+    }
+
+
+    // Reinit the login restriction list.
+    $data = $this->convertLoginRestriction();
+    if(count($data)){
+      $this->gosaLoginRestrictionWidget->setListData($data['data'], $data['displayData']);
+    }
+  }
+
+
+  function set_multi_edit_values($attrs)
+  {
+    $lR = array();
+
+    // Update loginRestrictions, keep my settings while ip is optional
+    foreach($attrs['gosaLoginRestriction_some'] as $ip){
+      if(in_array($ip, $this->gosaLoginRestriction) && in_array($ip, $attrs['gosaLoginRestriction'])){
+        $lR[] = $ip;
+      }
+    }
+
+    // Add enforced loginRestrictions 
+    foreach($attrs['gosaLoginRestriction'] as $ip){
+      $lR[] = $ip;
+    }
+
+    $lR = array_values(array_unique($lR));
+    $this->is_modified |=  array_differs($this->gosaLoginRestriction, $lR);
+    plugin::set_multi_edit_values($attrs);
+    $this->gosaLoginRestriction = $lR;
+  }
+
+
+  function convertLoginRestriction()
+  {
+    $all = array_unique(array_merge($this->gosaLoginRestriction,$this->gosaLoginRestriction_some));
+    $data = array();
+    foreach($all as $ip){
+      $data['data'][] = $ip;
+      if(!in_array($ip, $this->gosaLoginRestriction)){
+        $data['displayData'][] = array('mode' => LIST_MARKED , 'data' => array($ip.' ('._("Entries differ").')'));
+      }else{
+        $data['displayData'][] = array('mode' => 0 , 'data' => array($ip));
+      }
+    }   
+    return($data);
+  }
 }
 
 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: