<?php
class workstartup extends plugin
{
  /* Ldap server list */
  var $gotoLdapServers    = array();
  var $gotoLdapServerList = array();
  var $gotoLdap_inherit   = FALSE;

  /* Generic terminal attributes */
	# This is disabled as long there is no possiblilty to set these parameters
  #var $bootmode             = "G";
  var $bootmode             = "";
  var $gotoBootKernel       = "default-inherited";
  var $gotoKernelParameters = "";
  var $gotoLdapServer       = "default-inherited";
  var $gotoModules          = array();
  var $gotoAutoFs           = array();
  var $gotoFilesystem       = array();
  var $gotoTerminalPath     = "";
  var $gotoBootKernels      = array();

  /* attribute list for save action */
  var $attributes           = array("gotoLdapServer", "gotoBootKernel", "gotoKernelParameters", 
                                    "FAIclass", "FAIstatus", "gotoShare","FAIdebianMirror", "FAIrelease");
  var $objectclasses        = array("GOhard", "FAIobject");

  /* Share */
  var $gotoShares         = array();// Currently Share Option
  var $gotoShare          = "";     // currently selected Share Option
  var $gotoShareSelections= array();// Available Shares for this account in Listbox format
  var $gotoAvailableShares= array();// Available Shares for this account

  /* Helper */
  var $orig_dn            = "";
  var $ignore_account     = TRUE;
 
  /* FAI class selection */ 
  var $FAIclass           = array();  // The currently selected classes 
  var $FAIrelease           = "";
  var $FAIdebianMirror      = "auto";
  var $si_active            = FALSE;
  var $si_fai_action_failed = FALSE;

  var $cache              = array(); // Used as cache in fai mehtods

  var $FAIstatus          = "";
  var $FAIclasses         = array();

  var $view_logged        = FALSE;
  
  /* FAI class selection */
  var $InheritedFAIclass       = array();
  var $InheritedFAIrelease     = "";
  var $InheritedFAIdebianMirror= "auto";

  var $CopyPasteVars    = array("gotoModules","gotoShares");
  var $fai_activated    = FALSE;
  var $o_group_dn       = "";
  var $member_of_ogroup = FALSE;

  function workstartup (&$config, $dn= NULL, $parent= NULL)
  {
    /* Check if FAI is active */
    $tmp= $config->search("faiManagement", "CLASS",array('menu','tabs'));
    if(!empty($tmp) && class_available("faiManagement")){
      $this->fai_activated = TRUE;
    }else{
      $this->attributes = array("gotoLdapServer", "gotoBootKernel", "gotoKernelParameters", "gotoShare");
      $this->objectclasses  = array("GOhard");
    }

    plugin::plugin ($config, $dn, $parent);

    /* Check for si daemon */
    $this->si_active = $this->config->get_cfg_value("gosaSupportURI") != "";

    /* Check object group membership */
    if(!isset($this->parent->by_object['ogroup'])){
      $ldap = $this->config->get_ldap_link();
      $ldap->cd ($this->config->current['BASE']);
      $ldap->search("(&(objectClass=gotoWorkstationTemplate)(member=".LDAP::prepare4filter($this->dn)."))",array("cn","dn"));
      if($ldap->count()){
        $this->member_of_ogroup = TRUE;
        $attrs = $ldap->fetch();
        $this->o_group_dn = $attrs['dn'];
      }
    }

    /* Creating a list of valid Mirrors 
     * none will not be saved to ldap.
     */
    $ldap   = $this->config->get_ldap_link();
    $ldap->cd($this->config->current['BASE']);
    $ui = get_userinfo();
    foreach($this->config->data['SERVERS']['LDAP'] as $dn => $data){
      if($ui->get_category_permissions($data['dn'],"server",TRUE)){
        for($i = 0; $i < $data['goLdapBase']['count']; $i ++){
          $name = $data["cn"][0].":".$data["goLdapBase"][$i];
          $this->gotoLdapServerList[]= $name; 
        }
      }
    }

    /* Get list of assigned ldap servers 
     */ 
    if(isset($this->attrs['gotoLdapServer'])){
      unset($this->attrs['gotoLdapServer']['count']);
      sort($this->attrs['gotoLdapServer']);
      foreach($this->attrs['gotoLdapServer'] as $value){
        $this->gotoLdapServers[] = preg_replace("/^[0-9]*:/","",$value);
      }
    } 
    natcasesort($this->gotoLdapServerList);

    if(!count($this->gotoLdapServers) && $this->member_of_ogroup){ 
      $this->gotoLdap_inherit = TRUE;
    }

    /* FAI Initialization
       Skip this if FAI is not activated 
     */
    if($this->fai_activated) {

      /* Parse used FAIclasses (stored as string).
       * The single classes are seperated by ' '.
       * There is also the release type given, after first
       *  occurrence of ':'.
       */
      $this->FAIclass =array();
      if(isset($this->attrs['FAIclass'][0])){
        $tmp = explode(" ",$this->attrs['FAIclass'][0]);
        $tmp2 =array();  

        foreach($tmp as $class){
          if( ":" == $class[0] ) {
            $this->FAIrelease = trim(substr($class, 1));
          }else{
            $tmp2[$class] = $class;
          }
        }
        $this->FAIclass = $tmp2;
      }
    }

    /* Get arrays */
    foreach (array("gotoModules", "gotoAutoFs", "gotoFilesystem") as $val){
      if (isset($this->attrs["$val"]["count"])){
        for ($i= 0; $i<$this->attrs["count"]; $i++){
          if (isset($this->attrs["$val"][$i])){
            array_push($this->$val, $this->attrs["$val"][$i]);
          }
        }
      }
      sort ($this->$val);
      $this->$val= array_unique($this->$val);
    }

    /* Prepare Shares */
    if((isset($this->attrs['gotoShare']))&&(is_array($this->attrs['gotoShare']))){
      unset($this->attrs['gotoShare']['count']);
      foreach($this->attrs['gotoShare'] as $share){
        $tmp = $tmp2 = array();
        $tmp = explode("|",$share);
        $tmp2['server']      =$tmp[0];
        $tmp2['name']        =$tmp[1];
        $tmp2['mountPoint']  =$tmp[2];
        $this->gotoShares[$tmp[1]."|".$tmp[0]]=$tmp2;
      }
    }

    $this->gotoShareSelections= $config->getShareList(true);
    $this->gotoAvailableShares= $config->getShareList(false);
    $tmp2 = array();
  

    $this->orig_dn= $this->dn;

    /* Handle inheritance value "default" */
    if ($this->member_of_ogroup){
      $this->gotoBootKernels= array("default-inherited" => '['._("inherited").']'); 
    }

    /* If we are member in an object group,
     *  we have to handle inherited values.
     * So you can see what is inherited.
     */
    if ($this->member_of_ogroup){

      if(count($this->FAIclass)==0 && $this->FAIrelease == ""){
        $this->FAIdebianMirror = "inherited";
      }

      if($this->fai_activated){
        $map= array("gotoBootKernel","FAIclass","FAIdebianMirror");
      }else{
        $map= array("gotoBootKernel");
      }

      $ldap = $this->config->get_ldap_link();
      $ldap->cat($this->o_group_dn);
      $attrs= $ldap->fetch();

      foreach ($map as $name){
        if (!isset($attrs[$name][0])){
          continue;
        }

        switch ($name){
          case 'gotoBootKernel':
            $this->gotoBootKernels['default-inherited']=  _("inherited").' ['.$attrs[$name][0].']' ;
            break;

          case 'FAIclass':
            $str = explode(":",$attrs[$name][0]);
            $this->InheritedFAIclass    = explode(" ",trim($str[0]));
            $this->InheritedFAIrelease  = trim($str[1]);
            break;

          case 'FAIdebianMirror':
            $this->InheritedFAIdebianMirror = $attrs[$name][0];
            break;
        }
      }
    }

    $this->update_fai_cache();

    if($this->fai_activated && !$this->si_fai_action_failed && $this->si_active){

      /* Check if the current mirror is available 
       */
      if(!isset($this->cache['SERVERS'][$this->FAIdebianMirror])){
        if(count($this->FAIclass)){
          msg_dialog::display(_("Error"), sprintf(_("FAI mirror '%s' is not available - setting to mirror 'auto'!"), $this->FAIdebianMirror), ERROR_DIALOG);
        }
        $this->FAIdebianMirror = "auto";
        $this->FAIrelease = key($this->cache['SERVERS'][$this->FAIdebianMirror]);
        $this->cache['CLASSES'] = array();
        $this->update_fai_cache();
      }
  
      /* Check if the current mirror is available 
       */
      if(!isset($this->cache['SERVERS'][$this->FAIdebianMirror][$this->FAIrelease])){
        $new_release = key($this->cache['SERVERS'][$this->FAIdebianMirror]); 
        if(count($this->FAIclass)){
          msg_dialog::display(_("Error"), sprintf(_("FAI release '%s' is not available on mirror '%s' - setting to release '%s'!"), $this->FAIrelease, $this->FAIdebianMirror,$new_release), ERROR_DIALOG);
        }
        $this->FAIrelease = $new_release;
        $this->cache['CLASSES'] = array();
        $this->update_fai_cache();
      }
    }
  }

  
  function check()
  {
    $messages = array();
    
    /* Call common method to give check the hook */
    $messages= plugin::check();

    /* If there are packages selected, but no mirror show error */   
    if(($this->FAIdebianMirror == "none")&&(count($this->FAIclass)>0)){
      $messages[]=_("Please select a 'FAI server' or remove the 'FAI classes'.");
    }

    return($messages);
  }

  function execute()
  {
  	/* Call parent execute */
  	plugin::execute();

    if($this->is_account && !$this->view_logged){
      $this->view_logged = TRUE;
      new log("view","workstation/".get_class($this),$this->dn);
    }

    /* Do we represent a valid terminal? */
    if (!$this->is_account && $this->parent === NULL){
      $display= "<img alt=\"\" src=\"images/small-error.png\" align=middle>&nbsp;<b>".
        msgPool::noValidExtension(_("workstation"))."</b>";
      return ($display);
    }

    /* Add module */
    if (isset ($_POST['add_module'])){
      if ($_POST['module'] != "" && $this->acl_is_writeable("gotoModules")){
        $this->add_list ($this->gotoModules, $_POST['module']);
      }
    }

    /* Delete module */
    if (isset ($_POST['delete_module'])){
      if (count($_POST['modules_list']) && $this->acl_is_writeable("gotoModules")){
        $this->del_list ($this->gotoModules, $_POST['modules_list']);
      }
    }

    /* FAI class management */
    if($this->fai_activated){
      if(((isset($_POST['AddClass']))&&(isset($_POST['FAIclassesSel']))) && ($this->acl_is_writeable("FAIclass"))){
        $found = 0 ; 

        /* If this new class/profile will attach a second partition table
         * to our list of classes, abort and show a message.
         */
        foreach($this->FAIclass as $name){
          if(isset($this->FAIclassInfo[$name])){
            foreach($this->FAIclassInfo[$name] as $atr){
              if(isset($atr['obj'])){
                if($atr['obj'] == "FAIpartitionTable"){
                  $found ++ ; 
                }
              }
            }
          }
        }

        if((isset($this->FAIclassInfo[$_POST['FAIclassesSel']]['FAIpartitionTable']))&&($found>0)){
          msg_dialog::display(_("Error"), _("There is already a profile containing a partition table in your configuration!") , ERROR_DIALOG);
        }else{
          $this->FAIclass[$_POST['FAIclassesSel']]=$_POST['FAIclassesSel'];
        }
      }

      $sort = false;

      /* Move one used class class one position up or down */
      if($this->acl_is_writeable("FAIclass")){
        foreach($_POST as $name => $val){

          $sort_type = false;
          if((preg_match("/sort_up/",$name))&&(!$sort)){
            $sort_type = "sort_up_";
          }
          if((preg_match("/sort_down/",$name))&&(!$sort)){
            $sort_type = "sort_down_";
          }

          if(($sort_type)&&(!$sort)){
            $value = base64_decode(preg_replace("/_.*$/i","",preg_replace("/".$sort_type."/i","",$name)));
            $sort = true;

            $last = -1;
            $change_down  = -1;

            /* Create array with numeric index */ 
            $tmp = array();
            foreach($this->FAIclass as $class){
              $tmp [] = $class;
            }

            /* Walk trough array */
            foreach($tmp as $key => $faiName){
              if($faiName == $value){
                if($sort_type == "sort_up_"){
                  if($last != -1){
                    $change_down= $last;
                  }
                }else{
                  if(isset($tmp[$key+1])){
                    $change_down = $key;
                  }
                }
              }
              $last = $key;
            }

            $tmp2 = array();
            $skip = false;    

            foreach($tmp as $ky => $vl){

              if($ky == $change_down){
                $skip = $vl;
              }else{
                $tmp2[$vl] = $vl;
              }
              if(($skip != false)&&($ky != $change_down)){
                $tmp2[$skip]  = $skip;
                $skip =false;
              }
            }   
            $this->FAIclass = $tmp2; 
          }

          if(preg_match("/fai_remove/i",$name)){
            $value = base64_decode(preg_replace("/_.*$/i","",preg_replace("/fai_remove_/i","",$name)));
            unset($this->FAIclass[$value]);
          }
        }
      }

      /* Delete selected class from our list */
      if($this->acl_is_writeable("FAIclass")){
        if((isset($_POST['DelClass']))&&(isset($_POST['FAIclassSel']))){
          if(isset($this->FAIclass[$_POST['FAIclassSel']])){
            unset($this->FAIclass[$_POST['FAIclassSel']]);
          }
        }
      }
    }// END fai handling

    /* Show main page */
    $smarty= get_smarty();

    /* Assign ACLs to smarty */
    $tmp = $this->plInfo();
    foreach($tmp['plProvidedAcls'] as $name => $translation){
      $smarty->assign($name."ACL",$this->getacl($name));
    } 

    $smarty->assign("member_of_ogroup",$this->member_of_ogroup);

    /* In this section server shares will be defined
     * A user can select one of the given shares and a mount point
     *  and attach this combination to his setup.
     */
    $smarty->assign("gotoShareSelections",    $this->gotoShareSelections);
    $smarty->assign("gotoShareSelectionKeys", array_flip($this->gotoShareSelections));

    /* if $_POST['gotoShareAdd'] is set, we will try to add a new entry
     * This entry will be, a combination of mountPoint and sharedefinitions
     */
    if((isset($_POST['gotoShareAdd'])) && isset($_POST['gotoShareSelection']) && ($this->acl_is_writeable("gotoShare"))) {
      /* We assign a share to this user, if we don't know where to mount the share */
      if((!isset($_POST['gotoShareMountPoint']))||(empty($_POST['gotoShareMountPoint']))||(preg_match("/[\|]/i",$_POST['gotoShareMountPoint']))){
        msg_dialog::display(_("Error"), msgPool::required(_("Mount point")), ERROR_DIALOG);
      }else{
    
        if(isset($this->gotoAvailableShares[$_POST['gotoShareSelection']])){
          $a_share = $this->gotoAvailableShares[$_POST['gotoShareSelection']];
          $s_mount = $_POST['gotoShareMountPoint'];
          /* Preparing the new assignment */
          $this->gotoShares[$a_share['name']."|".$a_share['server']]=$a_share;
          $this->gotoShares[$a_share['name']."|".$a_share['server']]['mountPoint']=$s_mount;
        }
      }
    }

    /* if the Post  gotoShareDel is set, someone asked GOsa to delete the selected entry (if there is one selected)
     * If there is no defined share selected, we will abort the deletion without any message
     */
    if(($this->acl_is_writeable("gotoShare"))&& (isset($_POST['gotoShareDel']))&&(isset($_POST['gotoShare']))){
      unset($this->gotoShares[$_POST['gotoShare']]);
    }

    $smarty->assign("gotoShares",$this->printOutAssignedShares());
    $smarty->assign("gotoSharesCount",count($this->printOutAssignedShares()));
    $smarty->assign("gotoShareKeys",array_flip($this->printOutAssignedShares()));
    $smarty->assign("gotoBootKernels",$this->gotoBootKernels);

    /* Create divSelectBox for ldap server selection
     */
    $SelectBoxLdapServer = new divSelectBox("LdapServer");
    $SelectBoxLdapServer->SetHeight(130);

    /* Add new ldap server to the list */
    if($this->acl_is_writeable("gotoLdapServer") && 
        !$this->gotoLdap_inherit && 
        isset($_POST['add_ldap_server']) && 
        isset($_POST['ldap_server_to_add'])){
      if(isset($this->gotoLdapServerList[$_POST['ldap_server_to_add']])){
        $to_add = $this->gotoLdapServerList[$_POST['ldap_server_to_add']];
        if(!in_array($to_add,$this->gotoLdapServers)){
          $this->gotoLdapServers[] = $to_add;
        }
      }
    }
    
    /* Move ldap servers up and down */
    if(!$this->gotoLdap_inherit && $this->acl_is_writeable("gotoLdapServer")){
      foreach($_POST as $name => $value){
        if(preg_match("/sort_ldap_up_/",$name)){
          $id = preg_replace("/^sort_ldap_up_([0-9]*)_(x|y)$/","\\1",$name);
          $from =  $id;  
          $to   =  $id -1;
          $tmp = $this->array_switch_item($this->gotoLdapServers,$from,$to);
          if($tmp){
            $this->gotoLdapServers = $tmp;
          }
          break;
        }
        if(preg_match("/sort_ldap_down_/",$name)){
          $id = preg_replace("/^sort_ldap_down_([0-9]*)_(x|y)$/","\\1",$name);
          $from =  $id;  
          $to   =  $id +1;
          $tmp = $this->array_switch_item($this->gotoLdapServers,$from,$to);
          if($tmp){
            $this->gotoLdapServers = $tmp;
          }
          break;
        }
        if(preg_match("/gotoLdapRemove_/",$name)){
          $id = preg_replace("/^gotoLdapRemove_([0-9]*)_(x|y)$/","\\1",$name);
          $value = $this->gotoLdapServers[$id];
          $this->gotoLdapServers = array_remove_entries(array($value),$this->gotoLdapServers);
          break;
        }
      } 
    }
  
    /* Add Entries */
    if($this->acl_is_readable("gotoLdapServer")){

      foreach($this->gotoLdapServers as $key => $server){

        /* Announce missing entries */
        if(!in_array($server,$this->gotoLdapServerList)){
          $server = $server."&nbsp;<font style='color:red'>(missing)</font>";
        }

        /* Convert old style entry */
        if (!preg_match('%:ldaps?://%', $server)){
          $server= "ldap://".preg_replace('/^([^:]+):/', '\1/', $server);

        /* Beautify new style entries */
      } else {
        $server= preg_replace("/^[^:]+:/", "", $server);
      }

      $SelectBoxLdapServer->AddEntry(
          array(array("string" => $server),
            array("string" => 
              "<input class='center' type='image' src='images/lists/sort-up.png' name='sort_ldap_up_".$key."'>&nbsp;".
              "<input class='center' type='image' src='images/lists/sort-down.png' name='sort_ldap_down_".$key."'>&nbsp;".
              "<input class='center' type='image' src='images/lists/trash.png' name='gotoLdapRemove_".$key."'>",
              "attach" => "style='text-align:right;width:40px;border-right:0px;'")));
      }    
    }    

    if($this->gotoLdap_inherit){
      $smarty->assign("gotoLdapServerACL_inherit", preg_replace("/w/","",$this->getacl("gotoLdapServer")));;
    }else{
      $smarty->assign("gotoLdapServerACL_inherit", $this->getacl("gotoLdapServer"));
    }
    
    $list = array();
    foreach($this->gotoLdapServerList as $key => $entry){
      if(!in_array($entry,$this->gotoLdapServers)){

        /* Convert old style entry */
        if (!preg_match('%:ldap[s]*://%', $entry)){
          $entry= "ldap://".preg_replace('/^([^:]+):/', '\1/', $entry);

        /* Beautify new style entries */
        } else {
          $entry= preg_replace("/^[^:]+:/", "", $entry);
        }

        $list[$key] = $entry;
      }
    }
    $smarty->assign("gotoLdapServers",    $SelectBoxLdapServer->DrawList());
    $smarty->assign("gotoLdapServerList", $list);
    $smarty->assign("gotoLdap_inherit",   $this->gotoLdap_inherit);
    $smarty->assign("JS",  session::get('js'));

    foreach (array("gotoModules", "gotoAutoFs", "gotoFilesystem") as $val){
      $smarty->assign("$val", $this->$val);
    }

    /* Values */
    foreach(array("gotoBootKernel","gotoShare","FAIclasses","FAIclass","FAIdebianMirror","FAIrelease") as $val){
      $smarty->assign($val, $this->$val);
    }

    $smarty->assign("fai_activated",$this->fai_activated);

    /* Create FAI output */
    $this->update_fai_cache();
    $smarty->assign("si_fai_action_failed",$this->si_fai_action_failed);
    $smarty->assign("si_active",$this->si_active);

    $div = new divSelectBox("WSFAIscriptClasses");
    $div -> SetHeight("110");
  
    if(!$this->si_fai_action_failed && $this->si_active && $this->fai_activated){

      $smarty->assign("FAIservers"  , $this->cache['SERVERS']);
      $smarty->assign("FAIdebianMirror",$this->FAIdebianMirror);
      $smarty->assign("FAIrelease"  , $this->FAIrelease);
      $smarty->assign("FAIclasses"  , $this->selectable_classes());

      /* Get classes for release from cache.
       * Or build cache
       */
      if($this->FAIdebianMirror == "inherited"){
        $release = $this->InheritedFAIrelease;
      }else{
        $release = $this->FAIrelease;
      }

      $smarty->assign("gotoBootKernels",$this->cache['KERNELS'][$release]);
      $smarty->assign("InheritedFAIrelease",$this->InheritedFAIrelease);

      $str_empty  = " &nbsp;<img src='images/empty.png' alt=\"\" width='7'>"; 
      if($this->acl_is_writeable("FAIclass")){
        $str_up     = " &nbsp;<input type='image' src='images/lists/sort-up.png'    name='sort_up_%s'    value='%s'>";
        $str_down   = " &nbsp;<input type='image' src='images/lists/sort-down.png'  name='sort_down_%s'  value='%s'>";
        $str_remove = " &nbsp;<input type='image' src='images/lists/trash.png'  name='fai_remove_%s' value='%s'>";
      }else{
        $str_up=$str_down=$str_remove=$str_empty;
      }

      /* Get classes */
      if($this->FAIdebianMirror == "inherited"){
        $tmp = $this->InheritedFAIclass;
      }else{
        $tmp = $this->FAIclass;
      }

      /* Get invalid classes */
      $invalid = $this->get_invalid_classes($tmp);

      /* Draw every single entry */
      $i = 1;
      if($this->acl_is_readable("FAIclass")){
        foreach($tmp as $class){

          /* Mark invalid classes. (Not in selected release)
           */
          $marker = "";
          if(in_array_ics($class,$invalid)){
            $marker = "&nbsp;<font color='red'>("._("Not available in current setup").")</font>";
          }

          /* Create up/down priority icons  
           * Skip this, if we have inherited the FAI classes.
           */
          if($this->FAIdebianMirror == "inherited"){
            $str = "";
          }else{
            if($i==1){
              $str = $str_empty.$str_down.$str_remove;
            }elseif($i == count($this->FAIclass)){
              $str = $str_up.$str_empty.$str_remove;
            }else{
              $str = $str_up.$str_down.$str_remove;
            }
          }
          $i ++ ; 

          /* Get Description tag 
           *  There may be several FAI objects with the same class name, 
           *   use the description from FAIprofile, if possible.
           */  
          $desc = ""; 

          $objects = array(
              "Pl"  => array("IMG"=> "plugins/fai/images/fai_partitionTable.png"),
              "Pt"     => array("IMG"=> "plugins/fai/images/fai_packages.png"),
              "S"          => array("IMG"=> "plugins/fai/images/fai_script.png"),
              "V"        => array("IMG"=> "plugins/fai/images/fai_variable.png"),
              "H"            => array("IMG"=> "plugins/fai/images/fai_hook.png"),
              "P"         => array("IMG"=> "plugins/fai/images/fai_profile.png"),
              "T"        => array("IMG"=> "plugins/fai/images/fai_template.png"));

          if(isset($this->cache['CLASSES'][$this->FAIrelease][$class])){
            $desc ="";
            foreach($this->cache['CLASSES'][$this->FAIrelease][$class] as $types ){
              if(isset($types['Abbr'])){
                $desc.= "<img src='".$objects[$types['Abbr']]['IMG']."' class='center'> ";
                if($types['Type'] == "FAIprofile"){
                  break;
                }
              }
            }
          }
          if(!empty($desc)){
            $desc = "&nbsp;".trim($desc)."";
          }        

          $div->AddEntry(array(
                array("string"=>$class.$marker),
                array("string"=>$desc),
                array("string"=>preg_replace("/\%s/",base64_encode($class),$str),"attach"=>"style='width:50px;border-right:none;'")
                ));
        }  
      }// END FAI output generation 
    }// END FAI output generation 
    $smarty->assign("FAIScriptlist",$div->DrawList()); 

    /* Radio button group */
    if (preg_match("/G/", $this->bootmode)) {
      $smarty->assign("graphicalbootup", "checked");
    } else {
      $smarty->assign("graphicalbootup", "");
    }
    if (preg_match("/T/", $this->bootmode)) {
      $smarty->assign("textbootup", "checked");
    } else {
      $smarty->assign("textbootup", "");
    }
    if (preg_match("/D/", $this->bootmode)) {
      $smarty->assign("debugbootup", "checked");
    } else {
      $smarty->assign("debugbootup", "");
    }

    /* Show main page */
    $smarty->assign("gotoKernelParameters",$this->gotoKernelParameters);
    return($smarty->fetch (get_template_path('workstationStartup.tpl', TRUE,dirname(__FILE__))));
  }


  function remove_from_parent()
  {
    $this->handle_post_events("remove");
    new log("remove","workstation/".get_class($this),$this->dn);
  }


  /* Save data to object */
  function save_object()
  {
    $old_mirror  = $this->FAIdebianMirror;
    plugin::save_object();

    /* Update release */
    if($old_mirror != $this->FAIdebianMirror){
      if(!isset($this->cache['SERVERS'][$this->FAIdebianMirror][$this->FAIrelease])){
        $this->FAIrelease      = key($this->cache['SERVERS'][$this->FAIdebianMirror]);
      }
    }

    if(isset($_POST['WorkstationStarttabPosted'])){
      if(isset($_POST['gotoLdap_inherit'])){
        $this->gotoLdap_inherit = TRUE;
      }else{
        $this->gotoLdap_inherit = FALSE;
      }

      /* Save group radio buttons */
      if ($this->acl_is_writeable("bootmode") && isset($_POST["bootmode"])){
        $this->bootmode= $_POST["bootmode"];
      }
    }
  }


  /* Save to LDAP */
  function save()
  {

    /* Depending on the baseobject (Ogroup / WS) we
     *  use another set of objectClasses
     * In case of WS itself, we use  "array("GOhard", "FAIobject");"
     * if we are currently editing from ogroup menu we use (array("gotWorkstationTemplate","GOhard", "FAIobject"))
     */
    if(isset($this->parent->by_object['ogroup'])){
      $this->objectclasses = array("gotoWorkstationTemplate");
    }elseif(isset($this->parent->by_object['workgeneric'])){
      $this->objectclasses = array("GOhard");
    }elseif(isset($this->parent->by_object['servgeneric'])){
      $this->objectclasses = array("GOhard","gotoWorkstationTemplate");
    }else{
      msg_dialog::display(_("Fatal error"),
          "Object Type Configuration is unknown. Please contact the GOsa developers.",
          FATAL_ERROR_DIALOG);
      exit();
    }

    /* Append FAI class */
    if($this->fai_activated){
      $this->objectclasses[]  = "FAIobject";
    }

    /* Find proper terminal path for tftp configuration
       FIXME: This is suboptimal when the default has changed to
       another location! */
    if (($this->gotoTerminalPath == "default")){
      $ldap= $this->config->get_ldap_link();

      /* Strip relevant part from dn, keep trailing ',' */
      $tmp= preg_replace("/^cn=[^,]+,".preg_quote(get_ou('terminalRDN'), '/')."/i", "", $this->dn);
      $tmp= preg_replace("/".$this->config->current['BASE']."$/i", "", $tmp);

      /* Walk from top to base and try to load default values for
         'gotoTerminalPath'. Abort when an entry is found. */
      while (TRUE){
        $tmp= preg_replace ("/^[^,]+,/", "", $tmp);

        $ldap->cat("cn=default,".get_ou('terminalRDN').$tmp.
            $this->config->current['BASE'], array('gotoTerminalPath'));
        $attrs= $ldap->fetch();
        if (isset($attrs['gotoTerminalPath'])){
          $this->gotoTerminalPath= $attrs['gotoTerminalPath'][0];
          break;
        }

        /* Nothing left? */
        if ($tmp == ""){
          break;
        }
      }
    }

    plugin::save();

    unset( $this->attrs['FAIrelease'] );
    $str = "";

    /* Skip FAI attribute handling if not necessary */
    if($this->fai_activated && !$this->si_fai_action_failed){
      if($this->FAIdebianMirror == "inherited"){
        $this->attrs['FAIclass'] = $this->attrs['FAIrelease'] =  $this->attrs['FAIdebianMirror'] = array();
      }else{
        foreach($this->FAIclass as $class){
          $str .= $class." ";
        }
        $str = trim($str);
        if(empty($this->attrs['FAIclass'])){
          $this->attrs['FAIclass'] = array();
        }else{
          $this->attrs['FAIclass']= $str." :".$this->FAIrelease;
        }
      }
    }

    /* Add missing arrays */
    foreach (array("gotoFilesystem", "gotoAutoFs", "gotoModules") as $val){
      if (isset ($this->$val) && count ($this->$val) != 0){
    
        $this->attrs["$val"]= array_unique($this->$val);
      }
      if(!isset($this->attrs["$val"])) $this->attrs["$val"]=array();
    }

    /* Prepare list of ldap servers */
    $this->attrs['gotoLdapServer'] = array();
    if(!$this->gotoLdap_inherit){
      $i = 0;
      foreach($this->gotoLdapServers as $server){
        $i ++;
        $this->attrs['gotoLdapServer'][] = $i.":".$server;
      }
    }

    if ($this->attrs['gotoBootKernel'] == "default-inherited"){
      $this->attrs['gotoBootKernel']= array();
    }

    /* if mirror == none stop saving this attribute */
    if($this->FAIdebianMirror == "none"){
      $this->FAIdebianMirror = "";
    }
   
    /* Get FAIstate from object, the generic tab could have changed it during execute */
    $ldap= $this->config->get_ldap_link();
    $ldap->cd($this->dn);


    /* Skip FAI attribute handling if not necessary */
    if($this->fai_activated && !$this->si_fai_action_failed && $this->si_active){
      $ldap->cat($this->dn,array("FAIstate"));
      $checkFAIstate = $ldap->fetch();

      /* Remove FAI objects if no FAI class is selected */ 
      if((count($this->FAIclass)==0) && (!isset($checkFAIstate['FAIstate']))){
        $this->attrs['FAIclass']        = array();
        $this->attrs['FAIdebianMirror'] = array();
      }
    }else{

      /* Don't touch FAI objects if something went wrong with the si daemon.
       */
      if(isset($this->attrs['FAIclass'])) unset($this->attrs['FAIclass']);
      if(isset($this->attrs['FAIdebianMirror'])) unset($this->attrs['FAIdebianMirror']);
    }

    /* prepare share settings */
    $tmp = array();
    foreach($this->gotoShares as $name => $settings){
      $tmp2= explode("|",$name);
      $name = $tmp2[0];
      $tmp[] = $settings['server']."|".$name."|".$settings['mountPoint'];
    }
    $this->attrs['gotoShare']=$tmp;
    $this->cleanup();
    $ldap->modify ($this->attrs); 
    new log("modify","workstation/".get_class($this),$this->dn,array_keys($this->attrs),$ldap->get_error());

    if (!$ldap->success()){
      msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $this->dn, LDAP_MOD, get_class()));
    }
    $this->handle_post_events("modify");

    /* Check if LDAP server has changed */
    if ((isset($this->attrs['gotoLdapServer']) && class_available("DaemonEvent")) || $this->gotoLdap_inherit){
      $events = DaemonEvent::get_event_types(SYSTEM_EVENT | HIDDEN_EVENT);
      $o_queue = new gosaSupportDaemon();
      if(isset($events['TRIGGERED']['DaemonEvent_reload_ldap_config'])){
        $evt = $events['TRIGGERED']['DaemonEvent_reload_ldap_config'];
        $macs = array();
    
        /* Get list of macAddresses 
         */
        if(isset($this->parent->by_object['ogroup'])){
        
          /* If we are an object group, add all member macs 
           */
          $p = $this->parent->by_object['ogroup'];
          foreach($p->memberList as $dn => $obj){
            if(isset($p->objcache[$dn]['macAddress']) && !empty($p->objcache[$dn]['macAddress'])){
              $macs[] = $p->objcache[$dn]['macAddress'];
            }
          }
        }elseif(isset($this->parent->by_object['workgeneric']->netConfigDNS->macAddress)){

          /* We are a workstation. Add current mac.
           */
          $mac = $this->parent->by_object['workgeneric']->netConfigDNS->macAddress;
          if(!empty($mac)){
            $macs[] = $mac;
          }          
        }elseif(isset($this->parent->by_object['servgeneric']->netConfigDNS->macAddress)){

          /* We are a server. Add current mac.
           */
          $mac = $this->parent->by_object['servgeneric']->netConfigDNS->macAddress;
          if(!empty($mac)){
            $macs[] = $mac;
          }          
        }

        /* Trigger event for all member objects 
         */
        foreach($macs as $mac){
          $tmp = new $evt['CLASS_NAME']($this->config);
          $tmp->set_type(TRIGGERED_EVENT);
          $tmp->add_targets(array($mac));
          if(!$o_queue->append($tmp)){
            msg_dialog::display(_("Service infrastructure"),msgPool::siError($o_queue->get_error()),ERROR_DIALOG);
          }
        }
      }
    }
  }


  /* Add value to array, check if unique */
  function add_list (&$array, $value)
  {
    if ($value != ""){
      $array[]= $value;
      sort($array);
      array_unique ($array);
    }
  }


  /* Delete value to array, check if unique */
  function del_list (&$array, $list)
  {
    $tmp= array();
    foreach ($array as $mod){
      if (!in_array($mod, $list)){
        $tmp[]= $mod;
      }
    }
    $array= $tmp;
  }

  /* Generate ListBox frindly output for the defined shares
   * Possibly Add or remove an attribute here,
   */
  function printOutAssignedShares()
  {
    $a_return = array();
    if(is_array($this->gotoShares)){
      foreach($this->gotoShares as $share){
        $a_return[$share['name']."|".$share['server']]= $share['name']." [".$share['server']."]";
      }
    }
    return($a_return);
  }



  function PrepareForCopyPaste($source)
  {
    plugin::PrepareForCopyPaste($source);    
    $source_o = new workstartup ($this->config, $source['dn']);
    foreach(array("FAIclass","gotoModules", "gotoAutoFs", "gotoFilesystem",
          "gotoKernelParameters","gotoShares","gotoLdapServers","gotoLdapServerList",
          "gotoLdap_inherit") as $attr){
      $this->$attr = $source_o->$attr;
    }
  }

  
  function array_switch_item($ar,$from,$to)
  {
    if(!is_array($ar)){
      return(false);
    }
    if(!isset($ar[$from])){
      return(false);
    }
    if(!isset($ar[$to])){
      return(false);
    }

    $tmp = $ar[$from];
    $ar[$from] = $ar[$to];    
    $ar[$to] = $tmp;    
    return($ar);
  }


  /* Return plugin informations for acl handling */ 
  static function plInfo()
  {
    return (array( 
          "plShortName"   => _("Startup"),
          "plDescription" => _("System startup"),
          "plSelfModify"  => FALSE,
          "plDepends"     => array(),
          "plPriority"    => 9,
          "plSection"     => array("administration"),           
          "plCategory"    => array("workstation","server","ogroups"),

          "plProvidedAcls"=> array(
            "gotoLdapServer"        => _("Ldap server"),
            "gotoBootKernel"        => _("Boot kernel"),
            "gotoKernelParameters"  => _("Kernel parameter"),

            "gotoModules"           => _("Kernel modules"),
            "gotoShare"             => _("Shares"),

            "FAIclass"              => _("FAI classes"),
            "FAIdebianMirror"       => _("Debian mirror"),
            "FAIrelease"            => _("Debian release"),

            "FAIstatus"             => _("FAI status flag")) // #FIXME is this acl realy necessary ?
          ));
  }


  /* Updates release dns 
   *  and reads all classes for the current release, 
   *  if not already done ($this->cache).
   */
  function update_fai_cache($first_call = FALSE)
  {
    $force = FALSE;
    if(!$this->si_active) return; 
    $start = microtime(TRUE);  

    if($this->si_fai_action_failed && !isset($_POST['fai_si_retry'])) return;

    $this->si_fai_action_failed = FALSE;

    /* Get the list of available servers and their releases. 
     */
    if($force || !isset($this->cache['SERVERS'])){

      $o_queue = new gosaSupportDaemon();
      $tmp = $o_queue->FAI_get_server();
      if($o_queue->is_error()){
        msg_dialog::display(_("Service infrastructure"),msgPool::siError($o_queue->get_error()),ERROR_DIALOG);
        $this->si_fai_action_failed = TRUE;
        $this->cache = array();
        return;
      }else{

        foreach($tmp as $entry){
          $rel = $entry['FAI_RELEASE'];
          $this->cache['SERVERS']['auto'][$rel] = $rel;
          $this->cache['SERVERS'][$entry['SERVER']][$rel] = $rel;
          uksort($this->cache['SERVERS']['auto'], 'strnatcasecmp');
          uksort($this->cache['SERVERS'][$entry['SERVER']], 'strnatcasecmp');
        }
      }
    }

    /* Ensure that our selection is valid, else we get several PHP warnings 
        if there is no FAI configuration at all.
     */
    if(!isset($this->cache['SERVERS'][$this->FAIdebianMirror])){
      $this->cache['SERVERS'][$this->FAIdebianMirror][''] ='';
    }

    /* Build up arrays, without checks */
    if(!$first_call){

      /* Check if the selected mirror is available */
      if(!isset($this->cache['SERVERS'][$this->FAIdebianMirror])){
        $this->FAIdebianMirror = "auto";
        $this->FAIrelease      = key($this->cache['SERVERS'][$this->FAIdebianMirror]);
        trigger_error("There was a problem with the selected FAIdebianMirror. This mirror ('".$this->FAIdebianMirror."') is not available");
      }

      /* Check if the selected release is available */
      if($this->FAIdebianMirror != "inherited" && !isset($this->cache['SERVERS'][$this->FAIdebianMirror][$this->FAIrelease])){

        if($this->FAIrelease != ""){
          trigger_error("There was a problem with the selected FAIrelease. This release ('".$this->FAIrelease."') is not available");
        }
        $this->FAIrelease = key($this->cache['SERVERS'][$this->FAIdebianMirror]);
      }
    }

    /* Get classes for release from cache. 
     * Or build cache
     */
    if($this->FAIdebianMirror == "inherited"){
      $release = $this->InheritedFAIrelease;
    }else{
      $release = $this->FAIrelease;
    }

    if($force || !isset($this->cache['CLASSES'][$release]) && $release != ""){

      /* Get the list of available servers and their releases.
       */
      $o_queue = new gosaSupportDaemon();
      $tmp = $o_queue->FAI_get_classes($release);

      $this->cache['CLASSES'][$release] = array();
      if($o_queue->is_error()){
        msg_dialog::display(_("Service infrastructure"),msgPool::siError($o_queue->get_error()),ERROR_DIALOG);
        $this->si_fai_action_failed = TRUE;
        $this->cache=array();
        return;
      }else{
        foreach($tmp as $entry){
          $class = $entry['CLASS'];
          $this->cache['CLASSES'][$release][$class][] = $this->analyse_fai_object($entry); 
        }
      }

      /* Add object caught from external hook
       */
      $lines= $this->GetHookElements();
      foreach ($lines as $hline){
        $entries= explode(";", $hline);
        $server = $entries['0'];
        $url    = $entries['1'];
        if (!empty($url)){

          /* Split releases */
          if (isset($entries[2])){
            $releases= explode(",", $entries[2]);

            foreach ($releases as $release_data){
              $release_c  = preg_replace('/:.*$/', '', $release_data);
              $sections_c = explode(':', preg_replace('/^[^:]+:([^|]+)|.*$/', '\1', $release_data));
              $classes_c  = explode('|', preg_replace('/^[^|]+\|(.*)$/', '\1', $release_data));

              if($release_c == $release){
                $this->cache['SERVERS'][$url][$release_c]=$release_c;
                $this->cache['SERVERS']['auto'][$release_c]=$release_c; 
                foreach ($classes_c as $class){
                  if ($class != ""){
                    $this->cache['CLASSES'][$release_c][$class]= array();
                  }
                }
              }
            }
          }
        }
      }
      uksort($this->cache['SERVERS'], 'strnatcasecmp');

      /* Only add inherit option, if we are part in an object group
       */
      if($this->member_of_ogroup){
        $this->cache['SERVERS'] = array_merge(array('inherited' => array()),$this->cache['SERVERS']);
      }
    }

    /* Get list of available kernel for this release 
     */
    if(!isset($this->cache['KERNELS'])) $this->cache['KERNELS'] = array();

    if($force || !isset($this->cache['KERNELS'][$release])){
      $o_queue = new gosaSupportDaemon();
      $tmp = $o_queue->FAI_get_kernels($release);
      $this->cache['KERNELS'][$release] = array();
      foreach($this->gotoBootKernels as $name => $default){
        $this->cache['KERNELS'][$release][$name] = $default;
      }
      foreach($tmp as $kernel){
        if(empty($kernel)) continue;
        $this->cache['KERNELS'][$release][$kernel]=$kernel;
      }
      ksort($this->cache['KERNELS'][$release]);
    }
  }


  /* This function return an array containing all 
   *  invalid classes for the selected server/release
   */
  function get_invalid_classes($classes)
  {
    $this->update_fai_cache();
    if($this->FAIdebianMirror == "inherited" && isset($this->cache['CLASSES'][$this->InheritedFAIrelease])){
      $release_classes = $this->cache['CLASSES'][$this->InheritedFAIrelease];
    }elseif(isset($this->cache['CLASSES'][$this->FAIrelease])){
      $release_classes = $this->cache['CLASSES'][$this->FAIrelease];
    }else{
      $release_classes = array();
    }


    /* Detect all classes that are not valid 
     *  for the selected release 
     */
    $NA = array();
    foreach($classes as $class){
      if(!isset($release_classes[$class])){
        $NA[] = $class;
      }
    }
    return($NA);
  }  

  
  /* Get all selectable classes for the ui select box
   */
  function selectable_classes()
  {
    $this->update_fai_cache();

    if($this->FAIdebianMirror == "inherited" && isset($this->cache['CLASSES'][$this->InheritedFAIrelease])){
      $classes = $this->cache['CLASSES'][$this->InheritedFAIrelease];
    }elseif(isset($this->cache['CLASSES'][$this->FAIrelease])){
      $classes = $this->cache['CLASSES'][$this->FAIrelease];
    }else{
      $classes = array();
    }

    $Abbr ="";
    $ret= array();
    foreach($classes as $class_name => $class_types){
      if(!in_array($class_name,$this->FAIclass)){
        $Abbr = "";
        foreach($class_types as $type){
          if(!preg_match("/".$type['Abbr']."/",$Abbr)){
            $Abbr .= $type['Abbr']." ";
          }
        }
        $ret[$class_name] = trim($Abbr);
      }
    }
    uksort($ret, 'strnatcasecmp');
    return($ret);
  }


  /* Analyse FAI object and return an array with usefull informations like 
   *  FAIobject type.
   */
  function analyse_fai_object($attr)
  {
    $tmp = array();
    switch($attr['TYPE']){

      case 'FAIpackageList':
        $tmp["Type"]= 'FAIpackageList';
        $tmp["Abbr"]= 'Pl';
        break;
      case 'FAItemplate': 
        $tmp["Type"]= 'FAItemplate'; 
        $tmp["Abbr"]= 'T'; 
        break;
      case 'FAIvariable':
        $tmp["Type"]= 'FAIvariable'; 
        $tmp["Abbr"]= 'V'; 
        break;
      case 'FAIscript':
        $tmp["Type"]= 'FAIscript'; 
        $tmp["Abbr"]= 'S'; 
        break;
      case 'FAIhook':
        $tmp["Type"]= 'FAIhook'; 
        $tmp["Abbr"]= 'H'; 
        break;
      case 'FAIpartitionTable':
        $tmp["Type"]= 'FAIpartitionTable'; 
        $tmp["Abbr"]= 'Pt'; 
        break;
      case 'FAIprofile':
        $tmp["Type"]= 'FAIprofile'; 
        $tmp["Abbr"]= 'P'; 
        break;
      default: trigger_error("Unknown FAI object type!");;
    }
    return($tmp);
  }


  /* Return repository hook output, if possible.
   */
  function GetHookElements()
  {
    $ret = array();
    $cmd= $this->config->search("servrepository", "repositoryBranchHook",array('tabs'));
    if(!empty($cmd)){
      $res = shell_exec($cmd);
      $res2 = trim($res);
      if((!$res)){
        msg_dialog::display(_("Configuration error"), msgPool::cmdexecfailed("repositoryBranchHook", $cmd), ERROR_DIALOG);
      }elseif(empty($res2)){
        msg_dialog::display(_("Configuration error"), _("'repositoryBranchHook' returned no result!"), ERROR_DIALOG);
      }else{
        $tmp = preg_split("/\n/",$res);
        foreach($tmp as $line){
          if(empty($line)) continue;
          $ret[]= $line;
        }
      }
    }
    return($ret);
  }


  /* This function creates the release name out of a dn 
   *  e.g. "ou=1.0rc2,ou=siga,ou=fai,..." => "siga/1.0rc2"
   */
  function dn_to_release_name($dn)
  {
    $relevant = preg_replace("/,".preg_quote(get_ou("faiBaseRDN"), '/').".*$/i","",$dn);
    $parts    = array_reverse(explode(",",$relevant));
    $str ="";
    foreach($parts as $part){
      $str .= preg_replace("/^ou=/","",$part)."/";
    }
    return(preg_replace("/\/$/","",$str)); 
  }
}

// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
?>
