<?
/**
 * Voiceone Frontend functions
 * @package voiceone
 * @subpackage lib_functions
 */
 

  // This function retrieve the already done groups and return the html for displaing it.
  // $type: the group type
  // $js: a return variable that contains the javascript for the ajax function
  // RETURN: this function return the html for display the groups
  
  function lastVersion(&$js) {
    global $asterisk,$relBasePath,$cwlang,$cw_version,$cw_plugin_version;

    $html="You current VoiceOne version is <strong>v. $cw_version</strong> using plugin subsystem <strong>v. $cw_plugin_version</strong>";    
    
    //------------------------------   CLIENT SIDE    --------------------------
    
    //html code
    ob_start()
    ?>
    	<h2><?=$cwlang["group"][""]?>VoiceOne Version</h2>
      <p class="blockintro">
        <?=$cwlang["group"][""]?>
        <a href="#" onclick="return do_getLastVersion(1);" class="admin" ><?=$cwlang["group"][""]?>Check for newer version</a> (you'll send ONLY your current version information to our server)        
      </p>
      <div class="block">
        <div id="versionTable"><?=$html?></div><div id="versionStatus"></div>
        <div style="clear: both"></div> 
      </div>
    <?
    $contents=ob_get_contents();
    ob_end_clean();


    //javascript code
  	ob_start();
      ?>
    	function do_getLastVersion_cb(txt) {
        document.getElementById("versionStatus").innerHTML="";
        document.getElementById("versionTable").innerHTML=txt;
    	}
    	
    	function do_getLastVersion(txt) {
        document.getElementById("versionStatus").innerHTML="<img src='<?=$relBasePath?>/public/img/ico-progress.gif' > <?=$cwlang["generic"][""]?>Checking in progress...";
        x_getLastVersion(do_getLastVersion_cb);   
        return false;	
    	}
      <?

    $js.=ob_get_contents();
    ob_end_clean();

    //------------------------------   SERVER SIDE    --------------------------
  	function getLastVersion() {
      global $relBasePath,$asterisk,$cw_version;
      $lastVersion=$asterisk->versionCheck();
      if ($err=$asterisk->getError()) return ("Error: $err");
      if (is_array($lastVersion))
      foreach ($lastVersion as $v) $arr[$v["key"]]=$v["value"];
  
      if ($arr["last_version"]==$arr["current_version"]) 
        $ret="You current VoiceOne version is the <strong>most updated one</strong>. No newer versions available.";
      else
        $ret="Your current VoiceOne version is the <strong>".$arr["current_version"]."</strong>. On the <a href=\"http://www.voiceone.it\" target=\"_blank\">www.voiceone.it</a> you can find the latest <strong>".$arr["last_version"]."</strong> VoiceOne version.";

      return $ret;
  	}

  	sajax_export("getLastVersion");
    return $contents;
  }
  
  // This function retrieve the already done groups and return the html for displaing it.
  // $type: the group type
  // $js: a return variable that contains the javascript for the ajax function
  // RETURN: this function return the html for display the groups
  
  function listGroup($type,&$js,$groups=null) {
    global $asterisk,$relBasePath,$cwlang;
    $ret=$asterisk->getGroup(0,$type);
    if ($err=$asterisk->getError()) die("Error: $err");
    $count=0;
    
    if (is_array($ret))
    foreach($ret as $v) {
      $id=$v["id"];
      $name=$v["name"];
      $type=$v["type"];
      $metagroup=$v["metagroup"];
      if ($metagroup==1) continue;
      if ($type==GROUP_OF_EXTENSION)     $prot="<img src=\"$relBasePath/public/img/client.gif\" alt=\"client\" />";
      if ($type==GROUP_OF_OFFICE) $prot="<img src=\"$relBasePath/public/img/dep.gif\" alt=\"department\" />";
      if ($type==GROUP_OF_RESOURCE)   $prot="<img src=\"$relBasePath/public/img/res.gif\" alt=\"resource\" />";
      if ($type==GROUP_OF_PHONENUMBER)$prot="<img src=\"$relBasePath/public/img/number.gif\" alt=\"Phone Number\" />";
      if (is_array($groups)) {
        if (in_array($id, $groups ) ) $checked=" checked=\"checked\"";
        else $checked="";
      } else $checked="";
      $html.="<div class=\"groupItem\"> <input type=\"checkbox\" name=\"group[]\" value=\"$id\" $checked/>$prot $name </div>\n";
      if ((++$count)%2==0) $html.="</tr><tr>\n";
    }
    
    //------------------------------   CLIENT SIDE    --------------------------
    
    //html code
    ob_start()
    ?>
    	<h2><?=$cwlang["group"]["title"]?></h2>
      <p class="blockintro">
        <?=$cwlang["group"]["chooseGroup"]?>
        (<a href="<?=$PHP_SELF?>" onclick="if (groupName=prompt('Name','group'+Math.round(Math.random()*1000))) {do_addGroup(groupName,<?=$type?>); return false;}" class="admin" ><?=$cwlang["group"]["newGroup"]?></a>)
      </p>
      <div class="block">
        <div id="groupTable"><?=$html?></div><div id="groupStatus"></div>
        <div style="clear: both"></div> 
      </div>
    <?
    $contents=ob_get_contents();
    ob_end_clean();

    //javascript code
  	ob_start();
      ?>
    	function do_addGroup_cb(groupArray) {
        
        var groupName=groupArray["name"];
        var groupId=groupArray["id"];
        var groupIcon=groupArray["icon"];

        document.getElementById("groupStatus").innerHTML="";
        
        var groupList=document.getElementById("groupTable");
        var oNewNode = document.createElement("DIV");
        oNewNode.className="groupItem";
        oNewNode.innerHTML="<input type=\"checkbox\" name=\"group[]\" checked=\"checked\" value=\"" + groupId + "\"/> " + groupIcon + " " + groupName ;
        groupList.appendChild(oNewNode);
        
    	}
    	
    	function do_addGroup(groupName,type) {
        document.getElementById("groupStatus").innerHTML="<img src='<?=$relBasePath?>/public/img/ico-progress.gif' > <?=$cwlang["generic"]["working"]?>";
        x_addGroup(groupName, type, do_addGroup_cb);    		
    	}
      <?

    $js.=ob_get_contents();
    ob_end_clean();


    //------------------------------   SERVER SIDE    --------------------------
  	function addGroup($groupName,$type) {
      global $relBasePath,$asterisk;
      if ($type==GROUP_OF_EXTENSION)     $prot="<img src=\"$relBasePath/public/img/client.gif\" alt=\"client\" />";
      if ($type==GROUP_OF_OFFICE) $prot="<img src=\"$relBasePath/public/img/dep.gif\" alt=\"department\" />";
      if ($type==GROUP_OF_RESOURCE)   $prot="<img src=\"$relBasePath/public/img/res.gif\" alt=\"resource\" />";
      if ($type==GROUP_OF_PHONENUMBER)$prot="<img src=\"$relBasePath/public/img/number.gif\" alt=\"Phone Number\" />";

      $entry=Array("type" => $type, "name" => $groupName );
      $result=$asterisk->putGroup($entry);
      if ($result>0) {
        $ret["id"]=$result;
        $ret["name"]=$groupName;
        $ret["icon"]=$prot;
      } else {
        $ret["id"]=0;
      }

      return $ret;
  	}

  	sajax_export("addGroup");
    return $contents;
  }
  

  // This function creates the audiopanel and returns the html for displaing it.
  // $fieldName: name and id-suffix  for the html combobox element 
  // $selFileName: Filename selected from combobox
  // $js: a return variable that contains the javascript for the ajax function
  // RETURN: this function return the html for display the groups

  // THIS FUNCTION WAS MODIFIED AND IMPROVED BY Wolfgang (www.altrust.de)
  
  function getAudioPanel($fieldName,$selFileName,&$js) {
    global $asterisk,$relBasePath,$cwlang;
    $ret=$asterisk->getAudioFile();
    if ($err=$asterisk->getError()) die("Error: $err");
    if (is_array($ret))
    foreach($ret as $v) {
      $id=$v["id"];
      $name=$v["name"];
      $filename=$v["filename"];
      if ($filename==$selFileName) $sel=" selected='selected' "; else $sel="";
      $option.="<option value=\"$filename\" $sel>$name</option>";
    }
    $audioList="<select name=\"$fieldName\" id=\"audio_$fieldName\"><option></option>$option</select> ";

    $option="";
    $ret=$asterisk->getClient(0,0);
    if ($err=$asterisk->getError()) die("Error: $err");
    if (is_array($ret))
    foreach($ret as $v) {
      $id=$v["id"];
      $name=$v["name"];
      $surname=$v["surname"];
      $extension=$v["extension"];
      $option.="<option value=\"$id\">$name $surname &lt;$extension&gt;</option>";
    }
    $clientList="<select name=\"clientToCall_$fieldName\" id=\"clientToCall_$fieldName\">$option</select>";

    //------------------------------   CLIENT SIDE    --------------------------
    
    //html code
    ob_start()
    ?>
      <table cellpadding="0" cellspacing="0">
<!--
        <tr>
          <td>Upload a new file </td><td><input type="file" size="25" maxlength="50" id="node[audio]" name="node[audio]" value="<?=$audio?>" /></td>        
        </tr>
-->
        <tr>
          <td><?=$cwlang["audiorecorder"]["selectAudiofile"]?></td>
          <td>
            <?=$audioList?>
          </td>
          <td>
            <!-- rename an existing audiofile -->    
            <a href="<?=$PHP_SELF?>" onclick="if (newFilename=prompt('<?=$cwlang["audiorecorder"]["promptFilename"]?>','audio'+Math.round(Math.random()*1000))) {return do_renameAudio('<?=$fieldName?>',newFilename);}" >
              <img src="<?=$relBasePath?>/public/img/icon_edit.gif" alt="rename audio file" /></a>
            <!-- delete an existing audiofile -->      
            <a href="<?=$PHP_SELF?>" onclick="return do_deleteAudio('<?=$fieldName?>');" >
              <img src="<?=$relBasePath?>/public/img/icon_remove.gif" alt="delete audio file" /></a>
          </td>
        </tr>
        <tr>
          <td>
            <?=$cwlang["audiorecorder"]["recordAudiofile"]?>
          </td>
          <td>
            <?=$clientList?>   
            </td>
            <td>
            <!-- play an existing audiofile -->  
            <a href="<?=$PHP_SELF?>" onclick="return do_playAudio('<?=$fieldName?>');" >
              <img src="<?=$relBasePath?>/public/img/play.gif" alt="play audio file" /></a>
            <!-- record a new audiofile -->
            <a href="<?=$PHP_SELF?>" onclick="if (filename=prompt('<?=$cwlang["audiorecorder"]["promptFilename"]?>','audio'+Math.round(Math.random()*1000))) {return do_recordAudio('<?=$fieldName?>',filename);}" >
              <img src="<?=$relBasePath?>/public/img/record.gif" alt="record audio file" /></a>
            <!-- show status message -->      
            <span id="audioStatus_<?=$fieldName?>"></span>
          </td>
        </tr>
      </table>
    <?
    $contents=ob_get_contents();
    ob_end_clean();

    //javascript code
  	ob_start();
    ?>

        <!-- record audiofile --> 	
		function do_recordAudio(fieldName,filename) {
      document.getElementById("audioStatus_"+fieldName).innerHTML="<img src='<?=$relBasePath?>/public/img/ico-progress.gif' > <?=$cwlang["generic"]["working"]?>";
      clientToCall=document.getElementById("clientToCall_"+fieldName).value;
      x_recordAudio(filename, clientToCall, fieldName, do_recordAudio_cb);    	
      return false;	
    }	
		
		function do_recordAudio_cb(ret) {
      var result=ret["result"];
      var name=ret["filename"];
      var filename=ret["filename"]+".gsm";
      var fieldName=ret["fieldname"];
      if (result==1) {
        document.getElementById("audioStatus_"+fieldName).innerHTML="";
        var selectObj=document.getElementById("audio_"+fieldName);
        var i = selectObj.options.length;
        selectObj.options.length = i + 1;
        selectObj.options[i].value = (filename != '' && filename != ' ') ? filename : ' ';
        selectObj.options[i].text = (name != '' && name != ' ') ? name : '[empty]';
        selectObj.options[i].selected = 1;
      } else alert("<?=$cwlang["audiorecorder"]["genericError"]?>");
    }
    	 	
    <!-- play audiofile --> 
  	function do_playAudio(fieldName) {
      document.getElementById("audioStatus_"+fieldName).innerHTML="<img src='<?=$relBasePath?>/public/img/ico-progress.gif' > <?=$cwlang["generic"]["working"]?>";
      clientToCall=document.getElementById("clientToCall_"+fieldName).value;
      filename=document.getElementById("audio_"+fieldName).value;
      x_playAudio(filename, clientToCall, fieldName, do_playAudio_cb);    	
      return false;	
    }

    function do_playAudio_cb(ret) {
      var fieldName=ret["fieldname"];
      document.getElementById("audioStatus_"+fieldName).innerHTML="";
    }
		
		<!-- delete audiofile -->
		function do_deleteAudio(fieldName) {
      document.getElementById("audioStatus_"+fieldName).innerHTML="<img src='<?=$relBasePath?>/public/img/ico-progress.gif' > <?=$cwlang["generic"]["working"]?>";
      filename=document.getElementById("audio_"+fieldName).value;
      x_deleteAudio(filename, fieldName, do_deleteAudio_cb);    	
      return false;	
    }
		
		function do_deleteAudio_cb(ret) {
      var result=ret["result"];
      var name=ret["filename"]; name = name.substring(0, name.length - 4); 
      var filename=ret["filename"]; 
      var fieldName=ret["fieldname"];
      if (result==1) {
        document.getElementById("audioStatus_"+fieldName).innerHTML="";
        var selectObj=document.getElementById("audio_"+fieldName);
        var i = selectObj.options.length;
        for (var x = 0; x < i; x++) {
          if (selectObj.options[x].value == filename) {
            selectObj.remove(x);
            alert ("Recording:"+name+" was removed.");
          }
        }
      } else {
        document.getElementById("audioStatus_"+fieldName).innerHTML="";
        alert("<?=$cwlang["audiorecorder"]["cannotDeleteAudiofile"]?>. <?=$cwlang["audiorecorder"]["audiofileUsedInIVR"]?>.");
      }
    }
		
		<!-- rename audiofile -->
		function do_renameAudio(fieldName, newFilename) {
      document.getElementById("audioStatus_"+fieldName).innerHTML="<img src='<?=$relBasePath?>/public/img/ico-progress.gif' > <?=$cwlang["generic"]["working"]?>";
      filename=document.getElementById("audio_"+fieldName).value;
      x_renameAudio(filename, newFilename, fieldName, do_renameAudio_cb);    	
      return false;	
    }
		
		function do_renameAudio_cb(ret) {
      var result=ret["result"];
      var name=ret["filename"]; name = name.substring(0, name.length - 4); 
      var filename=ret["filename"];
      var newName=ret["newFilename"]; newName = newName.substring(0, newName.length - 4); 
      var newFilename=ret["newFilename"]; 
      var fieldName=ret["fieldname"];
      if (result==1) {
        document.getElementById("audioStatus_"+fieldName).innerHTML="";
        var selectObj=document.getElementById("audio_"+fieldName);
        var i = selectObj.options.length;
        for (var x = 0; x < i; x++) {
          if (selectObj.options[x].value == filename) {
            selectObj.remove(x);
          }
        }
        var i = selectObj.options.length;
        selectObj.options.length = i + 1;
        selectObj.options[i].value = newFilename;
        selectObj.options[i].text = newName;
        selectObj.options[i].selected = 1;
      } else alert("<?=$cwlang["audiorecorder"]["genericError"]?>");
    }
		
    <?
	if (!function_exists("recordAudio")) $js.=ob_get_contents();
	ob_end_clean();

  //------------------------------   SERVER SIDE    --------------------------
  if (!function_exists("recordAudio")) {
  	function recordAudio($filename,$clientToCall,$fieldName) {
      global $relBasePath,$asterisk;
      error_log("RECORD filename: $filename - client2call: $clientToCall");
      $result=$asterisk->recordAudioFile($filename,$clientToCall);
      if ($result>0) {
        $ret["result"]=1;
        $ret["filename"]=$filename;
        $ret["fieldname"]=$fieldName;
        //save the file to V1 table
        $asterisk->putAudioFile($filename,$filename.".gsm");
      } else {
        $ret["result"]=0;
      }
      return $ret;
  	}
  	sajax_export("recordAudio");
  }

  if (!function_exists("playAudio")) {
  	function playAudio($filename,$clientToCall,$fieldName) {
      global $relBasePath,$asterisk;
      error_log("PLAY filename: $filename - client2call: $clientToCall");
      $result=$asterisk->recordAudioFile($filename,$clientToCall);	
      if ($result>0) {
        $ret["result"]=1;
      } else {
        $ret["result"]=0;
      }
      $ret["fieldname"]=$fieldName;
      return $ret;
  	}
  	sajax_export("playAudio");
  }

  if (!function_exists("deleteAudio")) {
    function deleteAudio($filename, $fieldName) {
      global $asterisk;
      error_log("DELETE Audiofile filename: $filename");
      $result=$asterisk->deleteAudioFile($filename);       
  	  if ($result>0) {
        $ret["result"]=1;
        $ret["filename"]=$filename;
      } else {
        $ret["result"]=0;
    		$ret["filename"]=$filename;
      }
        
      $ret["fieldname"]=$fieldName;
      return $ret;
    }
    sajax_export("deleteAudio");
  }
	
	if (!function_exists("renameAudio")) {
	  function renameAudio($filename, $newFilename, $fieldName) {
      global $relBasePath,$asterisk;
      error_log("RENAME Audiofile old filename: $filename - new filename: $newFilename");
      // note: take care of wether filename does or does not include an extension! See frontend code. 
  		$result=$asterisk->renameAudioFile($filename, $newFilename.".gsm", $newFilename);
  		if ($result>0) {
  		  $ret["result"]=1;       
  		  $ret["filename"]=$filename;
  		  $ret["newFilename"]=$newFilename.".gsm";
      } else {
        $ret["result"]=0;
      }
      $ret["fieldname"]=$fieldName;
      return $ret;
    }
    sajax_export("renameAudio");
  }
	
  return $contents;
}
  

  
  //----------------------------------------------------------------------------
  
  // This function retrieve the already done rules and return the html for displaing it.
  // $js: a return variable that contains the javascript for the ajax function
  // $rule: an input parameter for the already selected rule
  // RETURN: this function return the html for display the rule
  
  function listRule(&$js,$rule=null,$type=RULE_OUTGOING) {
    global $asterisk,$relBasePath,$cwlang;
    $ret=$asterisk->getRule(0,$type);
    if ($err=$asterisk->getError()) die("Error: $err");
    $count=0;

    if (is_array($ret))
    foreach($ret as $v) {
      $id=$v["id"];
      $name=$v["name"];
      if ($id==$rule or ($rule==null and $count=="0")) 
        $html.="<div class=\"groupItem\"> <input type=\"radio\" name=\"rule\" value=\"$id\" checked=\"checked\"/> <strong>$name</strong> </div>\n";
      else 
        $html.="<div class=\"groupItem\"> <input type=\"radio\" name=\"rule\" value=\"$id\" /> $name </div>\n";
      if ((++$count)%2==0) $html.="</tr><tr>\n";
    }
    
    //------------------------------   CLIENT SIDE    --------------------------
    
    //html code
    ob_start()
    ?>
    	<h2><?=$cwlang["right"][""]?>Rule</h2>
      <p class="blockintro">
        <?=$cwlang["right"][""]?>Choose the rule that will be applied to this entity
        (<a href="<?=$PHP_SELF?>" onclick="if (ruleName=prompt('Name','rule'+Math.round(Math.random()*1000))) {do_addRule(ruleName,<?=$type?>); return false;}" class="admin" ><?=$cwlang["right"][""]?>New Rule</a>)
      </p>
      <div class="block">
        <div id="ruleTable"><?=$html?></div><div id="ruleStatus"></div>
        <div style="clear: both"></div> 
      </div>
    <?
    $contents=ob_get_contents();
    ob_end_clean();

    //javascript code
  	ob_start();
      ?>
    	function do_addRule_cb(ruleArray) {
        var ruleName=ruleArray["name"];
        var ruleId=ruleArray["id"];

        document.getElementById("ruleStatus").innerHTML="";
        
        var ruleList=document.getElementById("ruleTable");
        var oNewNode = document.createElement("DIV");
        oNewNode.className="groupItem";
        oNewNode.innerHTML="<input type=\"radio\" id=\"rule" + ruleId + "\" name=\"rule\" value=\"" + ruleId + "\"  /> " + ruleName ;
        ruleList.appendChild(oNewNode);
        document.getElementById("rule"+ruleId).checked=true;
    	}
    	
    	function do_addRule(ruleName,type) {
        document.getElementById("ruleStatus").innerHTML="<img src='<?=$relBasePath?>/public/img/ico-progress.gif' > <?=$cwlang["generic"]["working"]?>";
        x_addRule(ruleName, type, do_addRule_cb);    		
    	}
      <?

    $js.=ob_get_contents();
    ob_end_clean();


    //------------------------------   SERVER SIDE    --------------------------
  	function addRule($ruleName,$type) {
      global $relBasePath,$asterisk;

      $entry=Array("name" => $ruleName,"type" => $type);
      $result=$asterisk->putRule($entry);

      if ($result>0) {
        $ret["id"]=$result;
        $ret["name"]=$ruleName;
      } else {
        $ret["id"]=0;
      }
      return $ret;
  	}

  	sajax_export("addRule");
    
    return $contents;
  }  
  


  
  
  
  // This function retrieve the already done groups and return the html for displaing it.
  // $type: the group type
  // $js: a return variable that contains the javascript for the ajax function
  // RETURN: this function return the html for display the groups
  
  function listMacro(&$js,$macro=null,$parameter=null,$htmlHeader=true) {
    global $asterisk,$relBasePath,$cwlang;
    $ret=$asterisk->getMacro(0);
    if ($err=$asterisk->getError()) die("Error: $err");
    $html.="<option value=\"\">[None]</option>";

    if ($macro=="0") $macro=="";
    if (is_array($ret))
    foreach($ret as $v) {
      $id=$v["id"];
      $name=$v["name"];
      $label=$v["label"];
      $description=$v["description"];
      if ($macro==$id) $selected=" selected=\"selected\""; else $selected="";
      $html.="<option value=\"$id\" $selected/>$label</div>\n";
    }
    
    //------------------------------   CLIENT SIDE    --------------------------
    
    //html code
    ob_start();
    ?>
    	<h2><?=$cwlang["group"][""]?>Macro</h2>
      <p class="blockintro">
        <?=$cwlang["group"][""]?>Choose a macro to execute
      </p>
      <div class="block">
        Execute the macro <select name="macro" onchange="do_changeMacro(this.value,'<?=$macro?>','<?=$parameter?>')"><?=$html?></select>
        <div id="macroPanel"></div>
      </div>
    <?
    $contents=ob_get_contents();
    ob_end_clean();

    //if htmlHeader is false, don't display title, description and container
    if ($htmlHeader===false) $contents="<div id=\"macroPanel\"></div>";

    //set the already selected parameter
    if ($macro!="") $contents.="<script>do_changeMacro($macro,'$macro','$parameter')</script>";
    
    //javascript code
  	ob_start();
      ?>
    	function do_changeMacro_cb(html) {
        var dest=document.getElementById("macroPanel");
        dest.innerHTML=html;
    	}
    	
    	function do_changeMacro(macroId,selMacro,params) {
        document.getElementById("macroPanel").innerHTML="<img src='<?=$relBasePath?>/public/img/ico-progress.gif' > <?=$cwlang["generic"]["working"]?>";
        x_changeMacro(macroId, selMacro, params, do_changeMacro_cb);    		
    	}
      <?

    $js.=ob_get_contents();
    ob_end_clean();


    //------------------------------   SERVER SIDE    --------------------------
  	function changeMacro($macroId,$selMacro,$selParams) {
      global $asterisk, $relBasePath,$asterisk;

      if ($macroId=="") return ""; 
      
      $arr=$asterisk->getMacro($macroId);
      $label=$arr[0]["label"];
      $description=$arr[0]["description"];
      $parameter=$arr[0]["parameter"]; 
      $params=xml2array($parameter);
      
      if ($macroId==$selMacro) {
        $pArr=split("\|",$selParams);
        if (is_array($pArr))
        foreach ($pArr as $v) {
          $keyvalue=split("=",$v);
          $selParamsArr[$keyvalue[0]]=$keyvalue[1];
        } 
      }
      
      if (is_array($params))
      foreach($params as $p) {
        if ($p["name"]!="param") continue;
        $pName=$p["attributes"]["name"];
        $pLabel=$p["attributes"]["label"];
        $pType=$p["attributes"]["type"];
        $pDescription=$p["attributes"]["description"];
        $ret.="<tr>\n";
        $ret.="<td class=\"required\">$pLabel:</td>";
        switch ($pType) {
          case "QUEUE":
            $option="";
            $arr=$asterisk->getQueue(0);
            if (is_array($arr)) foreach($arr as $v) {
              if ($selParamsArr[$pName]==$v["id"]) $sel=" selected=\"selected\""; else $sel="";
              $option.="<option $sel value=\"".$v["id"]."\">".$v["name"]."</option>\n";
            } else $option.="<option value=\"\">[none]</option>\n";
            $ret.="<td><select id=\"macro_param[$pName]\" name=\"macro_param[$pName]\" >$option</select> <span class=\"help\">$pDescription</span></td>";
          break;
          case "GROUP":
            $option="";
            $arr=$asterisk->getGroup(0,0);
            if (is_array($arr)) foreach($arr as $v) {
              if ($selParamsArr[$pName]==$v["id"]) $sel=" selected=\"selected\""; else $sel="";
              $option.="<option $sel value=\"".$v["id"]."\">".$v["name"]."</option>\n";
            } else $option.="<option value=\"\">[none]</option>\n";
            $ret.="<td><select id=\"macro_param[$pName]\" name=\"macro_param[$pName]\" >$option</select> <span class=\"help\">$pDescription</span></td>";
          break;
          case "EXTENSION":
            $option="";
            $arr=$asterisk->getClient(0,0);
            if (is_array($arr)) foreach($arr as $v) {
              if ($selParamsArr[$pName]==$v["id"]) $sel=" selected=\"selected\""; else $sel="";
              $option.="<option $sel value=\"".$v["id"]."\">".$v["name"]." ".$v["surname"]." &lt;".$v["extension"]."&gt;</option>\n";
            } else $option.="<option value=\"\">[none]</option>\n";
            $ret.="<td><select id=\"macro_param[$pName]\" name=\"macro_param[$pName]\" >$option</select> <span class=\"help\">$pDescription</span></td>";
          break;
          case "IVR":
            $option="";
            $arr=$asterisk->getIvr(0);
            if (is_array($arr)) foreach($arr as $v) {
              if ($selParamsArr[$pName]==$v["id"]) $sel=" selected=\"selected\""; else $sel="";
              $option.="<option $sel value=\"".$v["id"]."\">".$v["name"]."</option>\n";
            } else $option.="<option value=\"\">[none]</option>\n";
            $ret.="<td><select id=\"macro_param[$pName]\" name=\"macro_param[$pName]\" >$option</select> <span class=\"help\">$pDescription</span></td>";
          break;
          case "EMAIL_EXTENSION":
            $option="";
            $arr=$asterisk->getClient(0,0);
            if (is_array($arr)) foreach($arr as $v) {
              $value=$v["voicemail"]["email"];
              if ($selParamsArr[$pName]==$value) $sel=" selected=\"selected\""; else $sel="";
              $option.="<option $sel value=\"$value\">".$v["name"]."</option>\n";
            } else $option.="<option value=\"\">[none]</option>\n";
            $ret.="<td><select id=\"macro_param[$pName]\" name=\"macro_param[$pName]\" >$option</select> <span class=\"help\">$pDescription</span></td>";
          break;
          case "OUTGOING_RULE":
            $option="";
            $arr=$asterisk->getRule(0,RULE_OUTGOING);
            if (is_array($arr)) foreach($arr as $v) {
              if ($selParamsArr[$pName]==$v["id"]) $sel=" selected=\"selected\""; else $sel="";
              $option.="<option $sel value=\"".$v["name"]."\">".$v["name"]."</option>\n";
            } else $option.="<option value=\"\">[none]</option>\n";
            $ret.="<td><select id=\"macro_param[$pName]\" name=\"macro_param[$pName]\" >$option</select> <span class=\"help\">$pDescription</span></td>";
          break;
          case "TEXTFIELD":
            $value=$selParamsArr[$pName];
            $ret.="<td><input type=\"textfield\" id=\"macro_param[$pName]\" name=\"macro_param[$pName]\" value=\"$value\"/> <span class=\"help\">$pDescription</span></td>";
          break;
        }
        $ret.="</tr>\n";        
      }
      if ($ret!="") $ret="<table class=\"todolist\">\n<tr><td colspan=\"2\"><br/>$description&nbsp;</td></tr>$ret</table>\n";
      return "<div>$ret</div>";
  	}

  	sajax_export("changeMacro");
    return $contents;
  }
  
  

  
  // This function retrieve the already done groups and return the html for displaing it.
  // $type: the group type
  // $js: a return variable that contains the javascript for the ajax function
  // RETURN: this function return the html for display the groups
  
  function listOption(&$js,$technology=null,$optionArr=null,$showGeneralOptions=false,$canChangeTech=true,$ruleType=0,$extra=false,$onlyVoipTechnologies=false) {
    global $asterisk,$relBasePath,$cwlang;

    //create the technology list
    $tech=$asterisk->getTechnology(0);
    foreach($tech as $t) {
      $tId=$t["id"];
      $tName=$t["name"];
      $tVoip=$t["voip"];
      if ($onlyVoipTechnologies==true and $tVoip==0) continue;
      if ($tId==$technology) {$s=" selected=\"selected\" "; $techName=$tName;} else $s="";
      $html.="<option value=\"$tId\" $s>$tName</option>\n";
    }
    if ($canChangeTech===true) $html="Choose the technology: <select id=\"techSelect\" name=\"technology\" onchange=\"do_changeTech(this.value,'$technology','$options','$showGeneralOptions',$ruleType,'$extra')\">$html</select>\n";
    else $html="Edit the options of $techName technology <input type=\"hidden\"  id=\"techSelect\" name=\"techSelect\" value=\"$technology\" /> ";
    
    //implode the array in a string to be passed via javascript
    if (is_array($optionArr)) 
    foreach ($optionArr as $o) $options.=$o["key"]."=".$o["value"]."|";
    $options=substr($options,0,-1);
    
    //transform the boolean $showGeneralOptions in a int variable
    $showGeneralOptions=intval($showGeneralOptions);
    
    //------------------------------   CLIENT SIDE    --------------------------
    
    //html code
    ob_start();
    ?>
    	<h2><?=$cwlang["group"][""]?>Technology</h2>
      <p class="blockintro">
        <?=$cwlang["group"][""]?>
        <?=$html?>
      </p>
      <div class="block">
        <div id="techPanel"></div>
      </div>
    <?
    $contents=ob_get_contents();
    ob_end_clean();

    //set the already selected parameter
    $contents.="<script>do_changeTech(document.getElementById('techSelect').value,'$technology','$options','$showGeneralOptions',$ruleType,'$extra')</script>";
    
    //javascript code
  	ob_start();
      ?>
    	function do_changeTech_cb(html) {
        var dest=document.getElementById("techPanel");
        dest.innerHTML=html;
    	}
    	
    	function do_changeTech(techId,selTech,selOptions,selGeneral,ruleType,extra) {
        document.getElementById("techPanel").innerHTML="<img src='<?=$relBasePath?>/public/img/ico-progress.gif' > <?=$cwlang["generic"]["working"]?>";
        x_changeTech(techId, selTech, selOptions, selGeneral, ruleType, extra,do_changeTech_cb);    		
    	}
      <?

    $js.=ob_get_contents();
    ob_end_clean();


    //------------------------------   SERVER SIDE    --------------------------
  	function changeTech($techId,$selTech,$selOptions,$showGeneralOptions,$ruleType,$extra) {
      global $asterisk, $relBasePath,$asterisk;

    
      //convert 
      ($showGeneralOptions==1)?$showGeneralOptions=true:$showGeneralOptions=false;
      ($extra==1)?$extra=true:$extra=false;

      //a control
      if ($techId=="") return ""; 

      //get the technology name
      $techArr=$asterisk->getTechnology($techId);
      $techName=$techArr[0]["name"];

      //get the configuration option
      $optionArr=$asterisk->getConfOption(0,$techName);
      
      //extract the options
      if ($techId==$selTech) {
        $oArr=split("\|",$selOptions);
        if (is_array($oArr))
        foreach ($oArr as $v) {
          $keyvalueArr=split("=",$v);
          $selOptionsArr[$keyvalueArr[0]]=$keyvalueArr[1];
        } 
      }
      
/*
      //get the template
      if ($showGeneralOptions===false) {
        $html= "      <tr >\n" ;
        $html.= "        <td class=\"colOption\"><label class=\"required\">Template:</label></td>\n" ; 
        $html.= "        <td> <select><option>[custom]</option></select></td>\n" ;
        $html.= "     </tr>\n" ;
      }
*/        

      //create the HTML options
      $html.=getOption($optionArr,$selOptionsArr,$showGeneralOptions,$ruleType,$extra);

      return "<table>".$html."</table>";
  	}

  	sajax_export("changeTech");
    return $contents;
  }
  
  

  



  
  
  
  
  // This function retrieve the already done groups and return the html for displaing it.
  // $type: the group type
  // $js: a return variable that contains the javascript for the ajax function
  // RETURN: this function return the html for display the groups
  
  function listGroupEntity(&$js,$group=null,$entity=null) {
    global $asterisk,$relBasePath,$cwlang;

    if ($entity!="" and $entity!="0") {
      $entityArr=$asterisk->getEntity($entity);
      $entityType=$entityArr[0]["type"];
      switch ($entityType) {
        case EXTENSION:
        case EXTENSION:
          $kind=GROUP_OF_EXTENSION;
        break;
        case VOIP_PROVIDER:
        case TELCO_PROVIDER:
        case MISDN_GROUP:
        case CHANNEL:
          $kind=GROUP_OF_RESOURCE;
        break;
        case OFFICE:
          $kind=GROUP_OF_OFFICE;
        break;
        case PHONENUMBER:
          $kind=GROUP_OF_PHONENUMBER;
        break;
        case APPLICATION:
          $kind=GROUP_OF_APPLICATION;
        break;
      }

    } else if ($group!="" and $group!="0") {
      $groupArr=$asterisk->getGroup($group,0);
      $kind=$groupArr[0]["type"];
    }
          
    if ($kind==GROUP_OF_ALL or $kind=="") $sel="selected='selected'"; else $sel="";
    $html = "    <option value=\"".GROUP_OF_ALL."\" $sel >[all]</option>\n";
    if ($kind==GROUP_OF_EXTENSION) $sel="selected='selected'"; else $sel="";
    $html.= "    <option value=\"".GROUP_OF_EXTENSION."\" $sel >Extensions</option>\n" ;
    if ($kind==GROUP_OF_OFFICE) $sel="selected='selected'"; else $sel="";
    $html.= "    <option value=\"".GROUP_OF_OFFICE."\" $sel >Offices</option>\n" ;
    if ($kind==GROUP_OF_PHONENUMBER) $sel="selected='selected'"; else $sel="";
    $html.= "    <option value=\"".GROUP_OF_PHONENUMBER."\" $sel >Phone Numbers</option>\n";
    if ($kind==GROUP_OF_APPLICATION) $sel="selected='selected'"; else $sel="";
    $html.= "    <option value=\"".GROUP_OF_APPLICATION."\" $sel >Application</option>\n";
    
    //------------------------------   CLIENT SIDE    --------------------------

    //html code
    ob_start();
    ?>
    	<h2><?=$cwlang["group"][""]?>2) What</h2>
      <p class="blockintro">
        <?=$cwlang["group"][""]?>Choose your dialed destination
      </p>
      <div class="block">
        <div>What destination do you want to dial with: <select name="kind"  onchange="do_changeKind(this.value,<?=intval($kind)?>,<?=intval($group)?>,<?=intval($entity)?>); "><?=$html?></select></div>
        <span id="choosePanel"></span>
        <div style="clear:both"></div>
      </div>
    <?
    if ($kind!="") echo "<script>do_changeKind($kind,$kind,$group,$entity); </script>";
    else echo "<script>do_changeKind(".GROUP_OF_ALL.",".GROUP_OF_ALL.",".intval($group).",".intval($entity).");</script>";
    $contents=ob_get_contents();
    ob_end_clean();

    //javascript code
  	ob_start();
      ?>
      var kindGlobal;
      
    	function do_changeKind_cb(html) {
        var dest=document.getElementById("choosePanel");
        dest.innerHTML=html;
        managePanel(kindGlobal);
    	}
    	
    	function do_changeKind(kindValue,kind,group,entity) {
        kindGlobal=kindValue;
        document.getElementById("choosePanel").innerHTML="<img src='<?=$relBasePath?>/public/img/ico-progress.gif' > <?=$cwlang["generic"]["working"]?>";
        x_changeKind(kindValue, kind, group, entity, do_changeKind_cb);    		
    	}

      function managePanel(kind) {
        if (kind==<?=GROUP_OF_ALL?>) value="block"; 
        if (kind==<?=GROUP_OF_EXTENSION?>) value="none"; 
        if (kind==<?=GROUP_OF_OFFICE?>) value="none"; 
        if (kind==<?=GROUP_OF_PHONENUMBER?>) value="block"; 
        if (kind==<?=GROUP_OF_APPLICATION?>) value="none"; 
        obj=document.getElementById("trunkDiv");
        if (obj!=null) obj.style.display=value;
      }

      
      <?
    $js.=ob_get_contents();
    ob_end_clean();


    //------------------------------   SERVER SIDE    --------------------------
  	function changeKind($kindValue,$kind,$group,$entity) {
      global $asterisk, $relBasePath,$asterisk;
      if ($kindValue=="") return ""; 

      //get the groups
      $grp=$asterisk->getGroup(0,$kindValue);
      if (is_array($grp))
      foreach ($grp as $g) {
        $grpid=$g["id"];
        $grpMetaGroup=$g["metagroup"];
        $grpname=str_replace("-"," ",str_replace("_","",$g["name"]));
        if ($grpMetaGroup) $grpname="[".strtoupper($grpname)."]";
        if ($grpid==$group or $grpid==GROUP_OF_ALL ) $checked=" checked=\"checked\" "; else $checked="";
        $html_group=" <input type=\"radio\" name=\"group\" value=\"g_$grpid\" $checked/> $grpname ".$html_group;
      }      

      switch ($kindValue) {
        case GROUP_OF_EXTENSION: //retrieve the extensions information
          $ret=$asterisk->getClient(0,0);
          if ($err=$asterisk->getError()) die("Error: $err");
          $count=0;
          if (is_array($ret))
          foreach($ret as $v) {
            $id=$v["id"];
            $callerid=$v["name"]." ".$v["surname"]." &lt;".$v["extension"]."&gt;";
            $icon=getIcon($v["technology"]);
            if ($id==$entity) $checked=" checked=\"checked\" "; else $checked="";
            $html_entity.="<input type=\"radio\" name=\"group\" value=\"$id\" $checked/> $icon $callerid ";
          }
        break;
        case GROUP_OF_OFFICE: //retrieve the offices information
          $ret=$asterisk->getOffice(0);
          if ($err=$asterisk->getError()) die("Error: $err");
          $count=0;
          if (is_array($ret))
          foreach($ret as $v) {
            $id=$v["id"];
            $name=$v["name"];
            $icon=getIcon(IAX2);
            if ($id==$entity) $checked=" checked=\"checked\" "; else $checked="";
            $html_entity.="<input type=\"radio\" name=\"group\" value=\"$id\" $checked/> $icon $name ";
          }
        break;
        case GROUP_OF_PHONENUMBER:
          //retrieve the phonenumber information
          $ret=$asterisk->getPhoneNumber(0);
          if ($err=$asterisk->getError()) die("Error: $err");
          $count=0;
          if (is_array($ret))
          foreach($ret as $v) {
            $id=$v["id"];
            $name=$v["name"];
            if ($id==$entity) $checked=" checked=\"checked\" "; else $checked="";
            $html_entity.=" <input type=\"radio\" name=\"group\" value=\"$id\" $checked/> $imgNum $name ";
          }
        break;
        case GROUP_OF_APPLICATION:
          //retrieve the application information
          $ret=$asterisk->getApplication(0);
          if ($err=$asterisk->getError()) die("Error: $err");
          $count=0;
          if (is_array($ret))
          foreach($ret as $v) {
            $id=$v["id"];
            $name=$v["name"];
            $desc=$v["description"];
            $ext=str_replace(".","",str_replace("_","",$v["extension"]));
            if ($id==$entity) $checked=" checked=\"checked\" "; else $checked="";
            $html_entity.=" <input type=\"radio\" name=\"group\" value=\"$id\" $checked/> $imgNum <a title=\"$desc\">$name</a> ($ext)";
          }
        break;
      }
      $html ="<dl>";
      $html.="<dt><strong>Groups:</strong> </dt><dd>".$html_group."</dd>";
      if ($html_entity!="") $html.="<dt><strong>Entities:</strong> </dt><dd> ".$html_entity."</dd>";
      $html.="</dl>\n";
      return $html;
  	}

  	sajax_export("changeKind");
    return $contents;
  }
  
  
  // This function retrieve the already done groups and return the html for displaing it.
  // $type: the group type
  // $js: a return variable that contains the javascript for the ajax function
  // RETURN: this function return the html for display the groups
  
  function listTrunk(&$js,$trunk=null,$number=null) {
    global $asterisk,$relBasePath,$cwlang;
    $ret=$asterisk->getTrunk(0,0);
    if ($err=$asterisk->getError()) die("Error: $err");
    $html.="<option value=\"\">[Any]</option>";
    
    if (is_array($ret))
    foreach($ret as $v) {
      $id=$v["id"];
      $name=$v["name"];
      if ($trunk==$id) $selected=" selected=\"selected\""; else $selected="";
      $html.="<option value=\"$id\" $selected/>$name</div>\n";
    }
    
    //------------------------------   CLIENT SIDE    --------------------------
    
    //html code
    ob_start();
    ?>
    	<h2><?=$cwlang["group"][""]?>Trunk</h2>
      <p class="blockintro">
        <?=$cwlang["group"][""]?>Choose the trunk you want to dial with
      </p>
      <div class="block">
        <div style="float: left">Trunk: <select name="trunk"  onchange="do_changeTrunk(this.value,'<?=$trunk?>','<?=$number?>')"><?=$html?></select></div>
        <span id="trunkPanel"></span>
        <div style="clear:both"></div>
      </div>
    <?
    echo "<script>do_changeTrunk(".intval($trunk).",'$trunk','$number')</script>";
    $contents=ob_get_contents();
    ob_end_clean();

    //javascript code
  	ob_start();
      ?>
    	function do_changeTrunk_cb(html) {
        var dest=document.getElementById("trunkPanel");
        dest.innerHTML=html;
    	}
    	
    	function do_changeTrunk(trunkId,selTrunk,number) {
        document.getElementById("trunkPanel").innerHTML="<img src='<?=$relBasePath?>/public/img/ico-progress.gif' > <?=$cwlang["generic"]["working"]?>";
        x_changeTrunk(trunkId, selTrunk, number, do_changeTrunk_cb);    		
    	}
      <?

    $js.=ob_get_contents();
    ob_end_clean();


    //------------------------------   SERVER SIDE    --------------------------
  	function changeTrunk($trunkId,$selTrunk,$selNumber) {
      global $asterisk, $relBasePath,$asterisk;
      //if ($trunkId=="") return ""; 

      $numberArr=split("\|",$selNumber);
      
      //add extension [s] and [all extension]
      if ($selNumber=="") $sel=" selected=\"selected\" "; else $sel="";
      $option.="<option value=\"\" $sel>*</option>";
      if (in_array("s",$numberArr)) $sel=" selected=\"selected\" "; else $sel="";
      $option.="<option value=\"s\" $sel>s</option>";

      //get the phone numbers
      if ($trunkId!="") { 
        $arr=$asterisk->getTrunk($trunkId,0);
        $name=$arr[0]["name"];
        $technology=$arr[0]["technology"];
        $key=$arr[0]["key"]; 
        $msns=$arr[0]["msns"]; 
        
        // extract the phone numbers
        if (is_array($msns))
        foreach ($msns as $m) {
          if (in_array($m,$numberArr)) $sel=" selected=\"selected\" "; else $sel="";
          $option.="<option value=\"$m\" $sel>$m</option>";
        }
      }
      
      if (count($msns)>1) {
        if (count($msns)>5) $size=5; 
        else $size=count($msns);
        $multiple=" size=\"$size\"  multiple=\"multiple\" ";
        $help="<div class=\"help\">Select the numbers you want to manage (hold CTRL + click for multiple numbers)</div>";
      } else $multiple="";
      //if (count($msns)>0) 
      $ret=" <select name=\"number[]\" $multiple>$option</select> $help";
      
      return "<div>$ret</div>";
  	}

  	sajax_export("changeTrunk");
    return $contents;
  }
  
  
  
  
  //----------------------------------------------------------------------------
  
  // This function retrieve the already done rights and return the html for displaing it.
  // $js: a return variable that contains the javascript for the ajax function
  // $rights: an input parameter for the already selected rights
  // RETURN: this function return the html for display the rights
  
  function manageNode(&$js) {
    global $asterisk,$relBasePath,$cwlang;

    if (!isset($_REQUEST["choosedIvr"])) return;
    
    $ivr=$asterisk->getIvr($_REQUEST["choosedIvr"]);
    $ivr_id=$ivr[0]["id"];    
    $rootNode=$ivr[0]["rootnode"];
    $rootName=$ivr[0]["name"];
    if ($ivr_id=="") return;
    //$nodeArray=$asterisk->getIvrNode($rootNode,true);
    $nodeArray=$asterisk->getIvrNode(0,$_REQUEST["choosedIvr"]);
    $html=writeTree($nodeArray,$rootNode);
    $firstNodeName=$nodeArray[0]["name"];
    
    //get selected node
    if (isset($_GET["nodeId"])) $selectedNode=$_GET["nodeId"];
    else if (isset($_GET["parentId"])) $selectedNode=$_GET["parentId"];
    else $selectedNode=$rootNode;
    
    //------------------------------   CLIENT SIDE    --------------------------
    
    //html code
    ob_start()
    ?>
          <h1><?=$cwlang["ivr"]["title"]?> <?=$rootName?></h1>
          <div id="tree"></div>        
          <script>
            if (document.getElementById) {
              var selected=null;
              var name= "<?=$firstNodeName?></a>" +   
                " <a href=\"edit.php?parentId=<?=$rootNode?>&choosedIvr=<?=$ivr_id?>\"><img src=\"../../admin/public/img/add.gif\" alt=\"Add a new node\"/></a>" +
                " <a href=\"javascript: if (confirm('Are you sure to delete?')) location.href='index.php?cmd=delNode&id=<?=$rootNode?>&choosedIvr=<?=$ivr_id?>'; \"><img src=\"../../admin/public/img/trash.gif\" alt=\"Delete this node\"/></a> ";
            	var node_<?=$rootNode?> = new WebFXTree(name,'edit.php?nodeId=<?=$rootNode?>&choosedIvr=<?=$ivr_id?>');
              node_<?=$rootNode?>.nodeId=<?=$rootNode?>;
              node_<?=$rootNode?>.ivrId=<?=$ivr_id?>;
            	node_<?=$rootNode?>.setBehavior('classic');
              <?=$html?>
              
              document.getElementById("tree").innerHTML=node_<?=$rootNode?>.toString();
              node_<?=$rootNode?>.expandAll();
              if (selected!=null) selected.focus();
              else node_<?=$selectedNode?>.focus();
              //if (node_<?=$rootNode?>.getSelected()==node_<?=$rootNode?>) {do_addButton(<?=$rootNode?>);}
            }
          </script>
    
          <br />
          <input type="button" onclick="do_buildIvr();"   style="width: 166px;" value="<?=$cwlang["ivr"]["apply"]?>" /><br />
          
    <?
    $contents=ob_get_contents();
    ob_end_clean();

    //javascript code
  	ob_start();
      ?>
      function do_buildIvr_cb() {
        if (document.getElementById("alert")) document.getElementById("alert").style.display="none";
        document.getElementById("editPane").innerHTML="<strong><?=$cwlang["ivr"]["created"]?></strong>";
        Fat.fade_element("editPane", 30, 300, "#FFFF33", "#FFFFFF");
      }
      function do_buildIvr() {
        document.getElementById("editPane").innerHTML="<img src='<?=$relBasePath?>/public/img/ico-progress.gif' > <?=$cwlang["ivr"]["creating"]?>";
        x_buildIvr(<?=$ivr_id?>,do_buildIvr_cb);
      }
      <?

    $js.=ob_get_contents();
    ob_end_clean();


    //------------------------------   SERVER SIDE    --------------------------

    function buildIvr($ivr_id) {
      global $asterisk;
      $ret=$asterisk->compileIvr($ivr_id);
      return 1;
    }

  	sajax_export("buildIvr");
    return $contents;
  }  
  
  function writeTree($nodeArray,$id=1,$ret="") {
    $return="";
    $ivr_id=$_REQUEST["choosedIvr"];
    $postdata=$_POST["node"];
    $selected=$postdata["id"];
    foreach ($nodeArray as $n) {
      if ($n["parent"]==$id) {
        $nodeParent=$n["parent"];
        $nodeId=$n["id"];
        $nodeName=$n["name"];
        $nodeKey=$n["key"];
        if ($nodeKey!="") $key="$nodeKey - "; else $key="";
        $tmpVar="node_".$nodeId;
        $parentName="node_".$id;
        $return.= "     var $tmpVar = new WebFXTreeItem(\"$key$nodeName \",\"edit.php?nodeId=$nodeId&choosedIvr=".$_REQUEST["choosedIvr"]."\");\n" ;
        $return.= "     $tmpVar.nodeId=$nodeId;\n" ;
        $return.= "     $tmpVar.ivrId=$ivr_id;\n" ;
        $return.= "    	$parentName.add($tmpVar);\n" ;
        if ($n["id"]==$selected) $return.= "    	selected=".$tmpVar."; \n" ;
        $return.= writeTree($nodeArray,$nodeId,$ret);
      }
    }
    return $ret.$return;
  }

    
  //----------------------------  getOption  -----------------------------------
  //-------------- return the html formatted technology option. ----------------
  
  function getOption($optionArr, $userValue=null ,$viewGeneral=true,$ruleType=0,$extra=false) {
    global $asterisk,$relBasePath;

    if ($err=$asterisk->getError()) die("Error: $err");
    if (is_array($optionArr)) {
      foreach($optionArr as $v) {
        $element="";
        $id=$v["id"];
        $name=$v["name"];
        $label=$v["label"];
        $value=$v["value"];
        $valuelist=$v["valuelist"];
        $default=$v["default"];
        $type=$v["type"];
        $comment=nl2br($v["comment"]);
        $commented=$v["commented"];
        $general_section=$v["general_section"];
        $default_section=$v["default_section"];
        $advanced_option=$v["advanced_option"];
  
        //calculate the real value
        if ($value=="") $v=$default; else $v=$value;
        if (is_array($userValue)) foreach($userValue as $uk=>$uv) if ($uk==$id) $v=$uv;

        //if client specific options, show only already uncommented options
        if ($viewGeneral===false) {
          //$label=$label." - g".$general_section."d".$default_section."c".$commented;
          if ($advanced_option!=1) $commented=0;
          else if (@array_key_exists($id,$userValue)) $commented=0;
          else if ($default_section==0 and $default_section==1) $commented=$commented;
          else $commented=1;
        }
        
        //evaluate the different input type field
        switch ($type) {
          case "textfield":
          case "codeclist":
            $element.="<input type=\"text\" size=\"25\" maxlength=\"30\" id=\"$name\" name=\"option_$id\" value=\"$v\" $disabled />";
          break;
          case "check":
            $arr=split(",",$valuelist);
            foreach($arr as $item) {
              $item=trim($item);
              if ($item==$v) $checked=" checked=\"checked\" "; else $checked="";
              if ($item==$default) $d=" (default) "; else $d=""; 
              $element.="<input type=\"checkbox\" id=\"$name\" name=\"option_$id\" value=\"$item\" $checked  $disabled/> $item $d";
            }
          break;
          case "radio":
            $arr=split(",",$valuelist);
            foreach($arr as $item) {
              $item=trim($item);
              if ($item==$v) $checked=" checked=\"checked\" "; else $checked="";
              if ($item==$default) $d=" (default) "; else $d=""; 
              $element.="<input type=\"radio\" id=\"$name\" name=\"option_$id\" value=\"$item\" $checked  $disabled/> $item $d";
            }
          break;
          case "select":
            $arr=split(",",$valuelist);
            $element="<select name=\"option_$id\" id=\"$name\"  $disabled >";
            foreach($arr as $item) {
              $item=trim($item);
              if ($item==$v) $checked=" selected=\"selected\" "; else $checked="";
              if ($item==$default) $d=" (default) "; else $d=""; 
              $element.="<option value=\"".trim($item)."\" $checked/> $item $d</option>";
            }
            $element.="</select>";
          break;
          case "trunklist":
            $technology=$valuelist;
            $arr=$asterisk->getTrunk(0,$technology);
            $element="<select name=\"option_$id\" id=\"$name\"  $disabled >";
            foreach($arr as $item) {
              $itemId=$item["id"];
              $itemName=$item["name"];
              if ($itemId==$v) $checked=" selected=\"selected\" "; else $checked="";
              if ($itemId==$default) $d=" (default) "; else $d=""; 
              $element.="<option value=\"$itemName\" $checked/> $itemName $d</option>";
              //$element.="<option value=\"$itemId\" $checked/> $itemName $d</option>";
            }
            $element.="</select>";
          break;
          case "rulelist":
            $arr=$asterisk->getRule(0,intval($ruleType));
            $element="<select name=\"option_$id\" id=\"$name\"  $disabled >";
            foreach($arr as $item) {
              $itemId=$item["id"];
              $itemName=$item["name"];
              if ($itemName==$v) $checked=" selected=\"selected\" "; else $checked="";
              if ($itemName==$default) $d=" (default) "; else $d=""; 
              $element.="<option value=\"$itemName\" $checked/> $itemName $d</option>";
            }
            $element.="</select>";
          break;
          case "isdn_nt_port":
            $isdnPortArr=$asterisk->getIsdnPort(0);
            $count=1;
            errArr($isdnPortArr);
            foreach($isdnPortArr as $port) {
              if ($port["available"]=="0" and $count<>$v) {$count++; continue;}
              if ($port["layermask"]!="0x3") {$count++; continue;}
              if ($count==$v) $checked=" checked=\"checked\" "; else $checked="";
              if ($port["id"]==$default) $d=" (default) "; else $d=""; 
              $element.="<input type=\"radio\" id=\"$name\" name=\"option_$id\" value=\"$count\" $checked  $disabled/> Port: ".$port["port"]." (card ".$port["card_id"].") $d";
              if (++$count%2==1) $element.="<br>";
            }
        }
    

        if ($commented=="1") { $on="0"; $status=" class='ON' "; $classOn=" class=\"hide\" "; $classOff=" class=\"show\" "; $buttonLabel="<img src=\"".$relBasePath."/public/img/checkbox.gif\" alt=\"\" />"; $classLabel=" class=\"commented\" ";}
        else  { $on="1"; $status=" class='OFF' ";  $classOn=" class=\"show\" "; $classOff=" class=\"hide\" "; $buttonLabel="<img src=\"".$relBasePath."/public/img/checkbox_ok.gif\" alt=\"\" />"; $classLabel=" class=\"required\" ";}
        
        $on_element   = "<div id=\"on_$name\" $classOn >$element</div>";
        $off_element  = "<div id=\"off_$name\" $classOff >$v</div>";
        $status_element="<input type=\"hidden\" name=\"status_$id\" id=\"status_$id\" value=\"$on\" />";
        $button       = "<a $status onclick=\"switchOnOff(this,'$name',$id,'".$relBasePath."');\">$buttonLabel</a>";
        $help         = "      <tr><td class=\"help\"><div id=\"help_$name\" $classOn>$comment</div></td><td></td></tr>\n" ;
        if ($label!="") $htmlName = $label;
        else $htmlName= UCfirst(str_replace("_"," ",$name));
        $label        = "<label id=\"label_$name\" $classLabel>$htmlName:</label>";

        if ($advanced_option==0) $button="";
        
        $html  = "      <tr >\n" ;
        $html .= "        <td class=\"colOption\">$button $label</td>\n" ; 
        $html .= "        <td> $on_element $off_element $status_element </td>\n" ;
        $html .= "     </tr>\n" ;
        $html .= $help;

        if ($viewGeneral === true and $general_section == 1) $ret .= $html;
        if ($viewGeneral === false and $default_section == 1) {
          if ($advanced_option == 0) $html_not_adv .= $html; else $html_adv .= $html;
        }
        if ($extra === true AND $default_section == 0 AND $general_section == 0) 
          $html_not_adv .= $html; 
      }  //end of foreach
    } //end of if is_array  

    if ($viewGeneral===false) {
      $ret=$html_not_adv;
      $ret.="<tr><td colspan=\"2\">";
      //$ret.="<input type=\"checkbox\" id=\"chkadvanced\" value=\"1\" onclick=\"this.checked?show('advanced_options'):hide('advanced_options');\" />\n";
      $ret.="<a class=\"admin\" href=\"#\" onclick=\"return showHide('advanced_options');\">Show advanced option</a></td></tr>\n";
      $ret.="</table><table id=\"advanced_options\">\n";
      $ret.=$html_adv;
    }
    
    return $ret;
  }    
  
  
  
/*******************************************************************************
****************      Show DID        *****************************************/
  function showDid($did) {
    global $asterisk;
/*
    $option="<option value=\"0\">-- No DID enabled --</option>\n";
    //get the rules
    $ret=$asterisk->getRule(0,RULE_OUTGOING);
    if ($err=$asterisk->getError()) die("Error: $err");
    if (is_array($ret)) 
    foreach($ret as $v) {
      $id=$v["id"];
      $name=$v["name"];
      if ($id==$did) $sel=" selected=\"selected\" "; else $sel="";
      $option.="<option value=\"$id\" $sel>$name</option>\n";
    }
    $ret="<select name=\"did\">$option</select>";
*/
    if ($did=="0" or $did=="") $chk=" checked=\"checked\" "; else $chk="";
    $ret="<input type=\"radio\" name=\"did\" value=\"0\" $chk> OFF &nbsp;&nbsp;";
    if ($did=="1") $chk=" checked=\"checked\" "; else $chk="";
    $ret.="<input type=\"radio\" name=\"did\" value=\"1\" $chk> ON";
    return $ret;
  }
  
/*******************************************************************************
****************      Go To Main Page *****************************************/
  function goToMainPage($alert,$page="") {
    session_start();
    $_SESSION['alert']=$alert;
    if ($page=="") header("location: ../");
    else header("location: $page");
    die;
    return;
  }

  function getAlert() {
    session_start();
    $alert=$_SESSION['alert'];
    unset($_SESSION['alert']);
    return $alert;
  }
  
  
/*******************************************************************************
****************      User informations *****************************************/

  function checkUserAccount($username, $password) {
    global $asterisk;
    $result=$asterisk->checkUser($username,md5($password));
    return $result;
	}
  
  function getAvailLang() {
    global $absBasePath;
    if ($handle = opendir($absBasePath."public/lang")) {
       while (false !== ($file = readdir($handle))) { 
           if ($file != "." && $file != ".." and substr($file,-4,4)==".php") { 
               $ret[]=substr($file,0,strlen($file)-4); 
           } 
       }
       closedir($handle); 
    }
    return $ret;
	}
  

/*******************************************************************************
*****************     VARIOUS                          ************************/

  function getIcon($tech) {
    global $relBasePath,$absBasePath;
    $icon="/public/img/tech/$tech.gif";
    if (file_exists($absBasePath.$icon)) 
      $ret=$relBasePath.$icon;
    else $ret=$relBasePath."public/img/tech/unknown.gif";
    $ret="<img src=\"$ret\" />";
    return $ret;
  }

/*******************************************************************************
*****************     Create an Html Version of Action ************************/
  

  function getHtmlAction($nid,$action,$action_option) {//,$act,$grp,$que,$ivr) {
    global $asterisk,$cwlang;
  
    //select the available action
    $act=$asterisk->getAction(0);
    if ($err=$asterisk->getError()) die("Error: $err");
  
    //select the available extension group
    $grp=$asterisk->getGroup(0,GROUP_OF_EXTENSION);
    if ($err=$asterisk->getError()) die("Error: $err");
    
    //select the available queue
    $que=$asterisk->getQueue(0);
    if ($err=$asterisk->getError()) die("Error: $err");
  
    //select the available ivr
    $ivr=$asterisk->getIvr(0);
    if ($err=$asterisk->getError()) die("Error: $err");
  
    if (is_array($grp)) foreach($grp as $a) {
      if ($a["id"]==$action_option and $action==ACTION_GROUP) $selected=" selected=\"selected\" "; else $selected="";
      $option[ACTION_GROUP].="<option value=\"".$a["id"]."\" $selected>".$a["name"]."</option>";
    }
    $option[ACTION_GROUP]="<select $display name=\"action_option[$nid][".ACTION_GROUP."]\" id=\"opt".$nid."-".ACTION_GROUP."\" ><option></option>".$option[ACTION_GROUP]."</select>";
    
    if (is_array($que)) foreach($que as $a) {
      if ($a["id"]==$action_option and $action==ACTION_QUEUE) $selected=" selected=\"selected\" "; else $selected="";
      $option[ACTION_QUEUE].="<option value=\"".$a["id"]."\" $selected>".$a["name"]."</option>";
    }
    $option[ACTION_QUEUE]="<select $display name=\"action_option[$nid][".ACTION_QUEUE."]\" id=\"opt".$nid."-".ACTION_QUEUE."\"><option></option>".$option[ACTION_QUEUE]."</select>";

    if (is_array($ivr)) foreach($ivr as $a) {
      if ($a["id"]==$action_option and $action==ACTION_IVR) $selected=" selected=\"selected\" "; else $selected="";
      $option[ACTION_IVR].="<option value=\"".$a["id"]."\" $selected>".$a["name"]."</option>";
    }
    $option[ACTION_IVR]="<select $display name=\"action_option[$nid][".ACTION_IVR."]\"  id=\"opt".$nid."-".ACTION_IVR."\"><option></option>".$option[ACTION_IVR]."</select>";

    
    //no choose
    $actionAvailable.="<tr><td class=\"actionTableLabel\">\n";
    if ($action==0) $checked=" checked=\"checked\" "; else $checked="";
    $actionAvailable.="<input type=\"radio\" name=\"action[".$nid."]\" value=\"0\" $checked> No Action \n";
    $actionAvailable.="</td></tr> \n";

    if (is_array($act)) 
    foreach($act as $a) {
      $actionAvailable.="<tr><td class=\"actionTableLabel\">\n";
      if ($a["id"]==$action) $checked=" checked=\"checked\" "; else $checked="";
      $actionAvailable.="<input type=\"radio\" name=\"action[".$nid."]\" value=\"".$a["id"]."\" $checked>".$a["name"]." \n";
      
      $actionAvailable.="</td><td class=\"actionTableValue\">\n";
      if (isset($option[$a["id"]])) $actionAvailable.=$option[$a["id"]]."\n";
      //else $actionAvailable.="<input type=\"text\"  name=\"action_option[$nid][".$a["id"]."]\"  id=\"opt$group-".$a["id"]."\"/>\n";
      $actionAvailable.="</td></tr>\n";
    }

    //$html=" <span style='margin-left: 30px;' > \n";
    $html.=" <table class=\"actionTable\">$actionAvailable</table>";
    //$html.=" </span> \n";
    return $html;    
  } //end of function



/**
 * Convert an XML data structure that is *read from file* into an array.
 * 
 * Array stucture: Node:[0]['name]=TAG opened; [0]['text']=Value [0]['closetag']=TAG closed; [0]['elements']=Array of subnode
 * @param string $xml filename with xml data to read and convert. 
 * @return array $xmlary reflecting structure
 * @todo separate file_get_contents from the function. This function should not read the file but take only the the xml string!
 */  
  if (!function_exists("xml2array")) {
    function xml2array ($xml)
    {
       $xmlary = array();
    
       // TODO: should not be done here!
       if ((strlen ($xml) < 256) && is_file ($xml)) {
         $xml = file_get_contents ($xml);
       }
      
       $ReElements = '/<(\w+)\s*([^\/>]*)\s*(?:\/>|>(.*?)<(\/\s*\1\s*)>)/s';
       $ReAttributes = '/(\w+)=(?:"|\')([^"\']*)(:?"|\')/';
       preg_match_all ($ReElements, $xml, $elements);

       foreach ($elements[1] as $ie => $xx) {
       
         $xmlary[$ie]["name"] = $elements[1][$ie];
         
         if ($attributes = trim($elements[2][$ie])) {
           preg_match_all ($ReAttributes, $attributes, $att);
           foreach ($att[1] as $ia => $xx) {
             // all the attributes for current element are added here
             $xmlary[$ie]["attributes"][$att[1][$ia]] = $att[2][$ia];
           }
         } // if $attributes
         
         // get text if it's combined with sub elements
         $cdend = strpos($elements[3][$ie],"<");
         
         if ($cdend > 0) {
           $xmlary[$ie]["text"] = substr($elements[3][$ie],0,$cdend -1);
         } // if cdend
           
         if (preg_match ($ReElements, $elements[3][$ie])) {
           $xmlary[$ie]["elements"] = xml2array ($elements[3][$ie]);
         } else if (isset($elements[3][$ie])) {
           $xmlary[$ie]["text"] = $elements[3][$ie];
         }
         
         $xmlary[$ie]["closetag"] = $elements[4][$ie];
         
       }//foreach elements[1]
       
       return $xmlary;
    } 
  }


  
/**
 * Convert an xmlarray data structure build with xml2array to a simple hash with UNIQUE keys of one level
 *
 * Subnodes are kept in their orginal data stucture. This allows recusive use of this function
 * Note: Works only if nodes have unique TAG-Names per level. 
 * Array stucture: Node:[0]['name]=TAG opened; [0]['text']=Value [0]['closetag']=TAG closed; [0]['elements']=Array of subnode
 * @param array $xmlArr reflecting structure
 * @return array $xmlHash with unique key-value pairs
 * @see xlm2array
 */  
  if (!function_exists("xmlArray2Hash")) {
    function xmlArray2Hash ($xmlArr) {
    
      $xmlHash = "";
      foreach ($xmlArr as $node) {
      
      if (!is_array($node['elements'])) {
        // final node without subnodes
        $xmlHash[$node['name']] = $node['text'];
      } else {
        // node has subnodes. keep them as they are
        $xmlHash[$node['name']] = $node['elements'];
      }
      
    } // foreach
    
    return $xmlHash;
      
    }
  }
  
  if (!function_exists("errArr")) {
    function errArr($arr) {
      if (count($arr)==0) { error_log("ok!"); }
      else {
        ob_start();
        print_r($arr);
        $contents=ob_get_contents();
        ob_end_clean();
        error_log($contents);     
      }
      unset($arr);
      return;
    }
  }  


/**
 * Get content from file.
 *
 * @param string $filename File to read  data from
 * @param integer $use_include_path Set to 1 if the include path should be used
 * @return string $data  read from file or "" if nothing to read or read failed
 */
  if (!function_exists("file_get_contents")) {
    function file_get_contents($filename, $use_include_path = 0) {
      $data = ""; // just to be safe. Dunno, if this is really needed
      $file = @fopen($filename, "rb", $use_include_path);
      if ($file) {
        while (!feof($file)) $data .= fread($file, 1024);
        fclose($file);
      }
      return $data;
    }
  }




/**
 * Put content to file.
 *
 * @param string $filename File to write  data to. If the file does exist, it will be deleteted!
 * @param string $data data to write to file
 * @param integer $use_include_path Set to 1 if the include path should be used
 * @return integer 1=ok 0=failure
 */  
  if (!function_exists("file_put_contents")) {
    function file_put_contents($filename, $data, $use_include_path = 0) {
      $file = @fopen($filename, "wb", $use_include_path);
      if ($file) {
        fwrite($file, $data);
        fclose($file);
        return 1;
      } else {
        return 0;
      }
    }
  }
   
/**
 * Convert an array into an XML data structure
 *
 * @param array $array data to convert
 * @param integer $deep. Helper for recursion when indent is active. Matches deeps of structure.
 * @return string $result XML structure
 * @todo add a parameter to enable/disable/modify indent 
*/  
  if (!function_exists("array2xml")) {
    function array2xml($array, $deep = 1) {
      
      //$indent = str_repeat("\t", $deep);
        $indent = str_repeat("  ", $deep);
        
      foreach ($array as $key => $value) {        
        if (!is_array($value)) {
          $xmlstr .= $indent . "<". $key .">";
          //$xmlstr .= $indent . "\t<![CDATA[". $value ."]]>\n";
          $xmlstr .= "". $value ."";
          $xmlstr .= "</". $key .">\n";
        } else {
          $currentkey = $key;
          $xmlstr .= $indent . "<". $currentkey .">\n";
          $xmlstr .= array2xml($value, ++$deep);
          $xmlstr .= $indent . "</". $currentkey .">\n";
        }
      }
      return $xmlstr;
    }
  }
  
  
/* =========== Client plugin section =========== 
Plugin system overview:
Author: Wolfgang Alper

Design
==================
The design of the plugin system allows to add nearly any types of vo-objects (also those that are not having a unique id). 
The core of the pluginsystem is the "plugin-cache". It resides on the voiceone client sandbox directory.
There plugins can coexist in different versions. The system ensures, that only one version of plugin can be activated at a time.
The plugin-cache must exist for each plugin, regardless of it's state (activated, deactivated).
The system recreates the plugin-cache for each plugin installed.
The same applies to the plugin-archive. I.e. the system ensures that an archive exists for every plugin-cache.
The reason for this is: User should be able to export (download) plugins and get information about plugins, independant from their states.
If these informaton would only be read from the database for activated plugin, then this would not be possible.

==activation process==
When a plugin is activated, the plugindata is passed via WDSL functions to the voiceone_webservices and added to the database.
The system checks wether objects, that are installed as part of *other* plugins, already exist. (use a compare by name not by id, because id's can be different from system to system!)
If yes than these objects are overridden but keep their existing id, otherwise these objects are created with a new id.
The activation itself is a two step process:
-1st get new id's if required
-2nd fix id references if necessary (like in an application that references a macro)
In other words, if the plugin contains a macro called "mymacro" and an application "myapplication", then the plugin system ensures that "myapplication" refrences "mymacro" even if new id's have been created.
This is different from the orginal concept, where id's were created as specified in data.xml, and therefore protects the system from overriding existing but different entities.

==deactivation process==
When a plugin is deactivated, the voiceone_webservice is asked to remove the plugin and its related objects from the database.
However if an object (like a macro) is still being used by other plugins, then this object is not removed.
This ensures, that deactivating a plugin does not break the system.
Example: If a user creates a plugin and uses a macro that is part of the system plugins like "incoming-call-to-group", then the system will keep that macro, because it is part of the system plugins.

==deletion process==
The process of deleting a plugin contains the following steps:
-deactivate the plugin. (check wich objects can be removed and which must be kept)
-delete the plugin cache.
-delete the plugin archive.
So the difference to deactivate is the removal of the cache and archive of that plugin in that version.

Internals
==================
The pluginsystem introduces some new WDSL backend functions to make access via the frontend easier. (See interfaces.php)
Also the frontend provides some new helper (see functions.php)

==plugin system version==
The idea of the plugin_system_version: If the voiceone_version change, the pluginsystem might not change. So the versioning for plugins and the plugin system must be different from voiceone versioning. This ensure consistency between a plugin and the plugin-system.
If the plugin-system changes (if it effects existing plugins), we use the voiceone_version that introduces the updated pluginsystem, as the version for that pluginsystem. So far, this release does not check the new global var $cw_plugin_version, because the corresponding $cw_version was not clear and $cw_plugin_version should be plain numeric. The next release will do this.

==plugininfo.xml==
This is the plugin description file. Next to a couple of informations, it contains: the voiceone_version and plugin_system_version used to build the plugin, the plugin_version and a reference to the plugin content via plugindata.xml. Each content type has its own md5sum for verification purpose.
To be more xml compliant, it uses one root node <plugininfo>

==plugindata.xml==
This is the plugin data file with content that can be stored in xml or with refrences to other external resources.
To be more xml compliant, it uses one root node <plugindata> 

==plugin database handling==
The new system adds a new table to store all objects that belong to a plugin and changes the existing table.
The new table:
-Ensures that objects are not deleted while in use by other plugins.
-Allows to add non-entities (Vo-Objects that have no unique id and no unique group identifier like group of extensions etc.)

Terms
==================
-pluginVersion = <pluginVersion>. Example: 1.0.1. Must not contain whitespaces, ".." or "/"!
-pluginName = <pluginName>. Example: wake_up-call. Must not contain whitespaces!
-plugin = alias for the <pluginName>.<pluginVersion>. Example: "wake_up-call.1.0.1"
-pluginArchive = <pluginName>.<pluginVersion>.zip. Example: wake_up-call.1.0.1.zip
-pluginCache = Use <plugin> as directory name. Example: wake_up-call.1.0.1
*/

  
/**
 * Create a pluginCache based on a collection of VO-Objects and a plugin information description
 *
 * @param array $pli plugin information
 * @param array $pld xml description and content of plugin data
 * Format: array[type][id]. array['application'][id]
 * @return $plugin (=relative cache directory name) or "" if failure
 */
  if (!function_exists("createPluginCache")) {
    function createPluginCache($pli, $pld) {
      
      global $asterisk, $absPluginPath, $cwlang;
      
      // contains xml serialized data and description of objects that are part of the plugin
      $xmlPld = "";    
      // contains xml serialized data of plugin information to add to the plugin
      $xmlPli= "";
      // number of elements in plugin
      $ecount = 0;
      
      $indent = "  ";
      
      //
      // plugin data 
      //
      
      // create a valid xml. so we need a unique start tag
      $xmlPld = "<plugindata>\n";
      
      foreach ($pld as $mytype=>$myopt) { 
     
        foreach ($myopt as $mykey=>$myid) { 

          switch ($mytype) {
            case APPLICATION:
              $data = $asterisk->getApplication($myid);
              $xmlPld .= "<application>\n";
              $xmlPld .= array2xml($data[0]); 
              $xmlPld .= "</application>\n";
              $ecount += 1;
            break;
              
            case MACRO:
              $data = $asterisk->getMacro($myid);
              $xmlPld .= "<macro>\n";
              $xmlPld .= array2xml($data[0]);
              $xmlPld .= "</macro>\n";
              $ecount += 1;
            break;
              
            case QUEUE:
              $data = $asterisk->getQueue($myid);
              $xmlPld .= "<queue>\n";           
              $xmlPld .= array2xml($data[0]);
              $xmlPld .= "</queue>\n";
              $ecount += 1;
            break;
            
            // unsupported type
            default:
            break;
          } // switch
          
        } // foreach $myopt
        
      } // foreach $pld
      
      $xmlPld .= "</plugindata>\n";
      
   
      //
      // create the plugin package directory
      //
      
      // file and directory are build from name and version. so check for invalid entries like .. etc. 
      // replace whitespaces and '.' with '_'
      $pli['name'] = preg_replace('/ /', '_', $pli['label']);
      $pli['name'] = preg_replace('/\./', '_', $pli['name']);
  
      // replace whitespaces and '.' with '_'
      $pli['version'] = preg_replace('/\.\.+/', '', $pli['version']);
      $pli['version'] = preg_replace('/\/+/', '', $pli['version']);
      
      // because so often needed, we add the packageName as field. 
      $pli['packageName'] = $pli['name'] . "." . $pli['version'];
      
      // number of elements in plugin - also quite useful 
      $pli['elementCount'] = $ecount;
                 
      //
      // create the plugin package directory
      //
      
      // directory name without / for new plugin
      $plugin = $pli['name'] . "." . $pli['version'];
       // absolute path to new plugin directory
      $absPluginDir = $absPluginPath . $plugin . "/";
  
      // make directories if they do not exist
      // should work, because ../sandbox must be read/writable per definition
      if (!is_dir($absPluginPath)) { mkdir($absPluginPath); }
      if (!is_dir($absPluginDir)) { mkdir($absPluginDir); }
  
      // write the data files. need to do this first, because we add the md5sum to the plugininfo
      file_put_contents($absPluginDir . "plugindata.xml", $xmlPld, 0);
      $md5PluginData = md5_file($absPluginDir . "plugindata.xml");
      
      
      //
      // plugin information section 
      //     
      
      $xmlPli = "<plugininfo>" . "\n";
      $xmlPli .= array2xml($pli);
      $xmlPli .= $indent . "<content>" . "\n";
      $xmlPli .= $indent . $indent . "<file>" . "\n";
      $xmlPli .= $indent . $indent . $indent . "<filename>" . "plugindata.xml" . "</filename>" . "\n";
      $xmlPli .= $indent . $indent . $indent . "<md5>" . $md5PluginData . "</md5>" . "\n";
      $xmlPli .= $indent . $indent . "</file>" . "\n";
      $xmlPli .= $indent . "</content>" . "\n";
      $xmlPli .= "</plugininfo>" . "\n";
      
      // write the plugin information file
      file_put_contents($absPluginDir . "plugininfo.xml", $xmlPli, 0);

      // see if all went ok and return
      if (is_file($absPluginDir . "plugindata.xml")) {
        return $plugin;
      } else {
        return "";
      }
      
    }
  }

  
  
/**
 * Create a plugin cache directory based on an activated plugin in the database. 
 *
 * Used to ensure that a pluginCache exists for each activated plugin
 * If a cache directory or archive does not exist, it will be created automatically.
 * @param integer $id as used for plugin in database
 * @see createPluginCache
 * @see readPluginCache
 * @return $plugin (=relative cache directory name) if a cachedir were created or "" if plugin does not exist or nothing to do
 */
  if (!function_exists("createPluginCachefromDB")) {
    function createPluginCachefromDB($id) {
      
      global $asterisk, $absPluginPath, $cwlang, $cw_plugin_version, $cw_version;
      
      $installedPlugin = $asterisk->getPlugin($id);
      // exit if plugin with the given id does not exist
      If ($installedPlugin == "") return "";
            
      // $plugin contains full name like "Wake-Up_call.1.1.10"
      $plugin = $installedPlugin[0]['name'] . "." . $installedPlugin[0]['version'];
      $plCache = readPluginCache($plugin);
      // exit if plugincache exist
      if ($plCache != "") return "";
      
      //
      // plugin cache is missing. create it.
      // should never happen by design, but you never know...
      // maybe the user has delete the files in the plugin dir...
      //
      
      // build entity array grouped by type to allow use of createPluginCache
      $entArr = explode("|", $installedPlugin[0]['entity']);
      foreach ($entArr as $eNr=>$eId) {
        $entity = getEntity($eId);
        $pld[$entity[0]['type']][] = $eId;
      }
      
      // build information array. map database fields
      $pli['name'] = $installedPlugin[0]['name'];
      $pli['label'] = $installedPlugin[0]['label'];
      $pli['packageName'] = $installedPlugin[0]['package_name'];
      $pli['version'] = $installedPlugin[0]['version'];
      // we also add the current date, because plugin is recreated. (format 2006-06-21)
      $pli['date'] = date("Y-m-d");
      $pli['description'] = $installedPlugin[0]['description'];
      $pli['authorName'] = $installedPlugin[0]['author_name'];
      $pli['authorEmail'] = $installedPlugin[0]['author_email'];
      $pli['authorWebsite'] = $installedPlugin[0]['author_website'];      
      // Note we add the voVersion and voPlVersion from this system, 
      // because we recreate the cache dir and therefore the entire plugin
      $pli['voVersion'] = $cw_version;
      $pli['voPlVersion'] = $cw_plugin_version;
      
      
      // create pluginCache
      $ret = createPluginCache($pli, $pld);
      // create pluginArchive 
      if ($ret != "") { createPluginArchive($ret); }
      
      return $ret;
      
    }
  }

  
  
/**
 * Create a plugin zip compressed archive based on a plugin directory. 
 *
 * Plugin archives are used if a plugin should be uploaded / downloaded
 * @param string $plugin ( equals to relative directory name. I.e. Wake_UP-Call.1.1.10)
 * @return $md5sum of pluginArchive
 */
  if (!function_exists("createPluginArchive")) {
    function createPluginArchive($plugin) {

      global $absPluginPath;
      $pluginFiles = $absPluginPath . $plugin . "/*";
      $pluginArchive = $plugin . ".zip";
    
      // create package in $absPluginPath. Zip file contains no path information
      // "zip -j wakeup.zip Wake-Up_Call.1.1.10/*"
      $cmd = "zip -j  " . $absPluginPath . $pluginArchive . " " . $pluginFiles;
      $output=shell_exec("$cmd");
      
      // see if all went ok
      if (is_file($absPluginPath . $pluginArchive)) {
        $md5sum = md5_file($absPluginPath . $pluginArchive);
      } else {
        $md5sum = "";
      }
      return $md5sum;
    }
  }



/**
 * Check wether a specific plugin exists in the cache, or get a list of all plugins in the plugin cache directory
 *
 * Note: Creates a pluginArchive in case it does not exist.
 * @param string $plugin or "" for a list of all plugin packages.
 * @return array $pluginList containing [0]=$plugin, a list of all plugins, or "" if the plugin does not exist
 */
  if (!function_exists("readPluginCache")) {
    function readPluginCache($plugin) {
      
      global $absPluginPath;

      $ret = "";
      
      $dh = opendir($absPluginPath);
      while (false !== ($pldir = readdir($dh))) {
      //add only subdirs
        if ( is_dir($absPluginPath ."/" .$pldir) ) {
          //avoid to list just stuff
          if ( ($pldir != ".") and ($pldir != "..") ) {
            // found a valid directory. check wether to add to list
            if (($plugin == $pldir) or ($plugin == "")) {
              $ret[] = $pldir;
              // check if pluginArchive exists. if not create it
              if (!is_file($absPluginPath . $pldir . ".zip")) {
                createPluginArchive($pldir);
              }
            }
          }
        } 
      }// while
      closedir($dh); 
      
      // sort the result, so packages stay together, looks better in any type of list 
      if (is_array($ret)) { sort($ret); }
      
      return $ret;
    }
  }


  
/**
 * Read plugin information for a specific plugin from cache
 * 
 * @param string $plugin 
 * @return array $xmlPluginInfo or "" if failure
 */
  if (!function_exists("readPluginInfoAsXML")) {
    function readPluginInfoAsXML($pl) {
      global $absPluginPath;      
      return file_get_contents($absPluginPath . $pl . "/plugininfo.xml" );
    }
  }
  


/**
 * Read plugin data for a specific plugin from cache  and return xml string
 * 
 * @param string $plugin 
 * @return string $xmlPluginData or "" if failure
 */
  if (!function_exists("readPluginDataAsXML")) {
    function readPluginDataAsXML($pl) {
      global $absPluginPath;
      return file_get_contents($absPluginPath . $pl . "/plugindata.xml" );
    }
  }
  
  
  
/**
 * Read plugin information for a specific plugin from cache, or get info about all plugins
 * 
 * Creates the corresponding pluginCache and pluginArchive in case it does not exists.
 * Adds md5sum of pluginArchive to return array as arr[plugin]['md5']
 * @param string $plugin or "" for a list of all plugins
 * @return array $pluginList containing an array['plugin'] with content of plugininfo.xml for each entry or "" if no valid plugin exist
 */
  if (!function_exists("readPluginInfo")) {
    function readPluginInfo($plugin) {

      global $absPluginPath, $asterisk;
      
      $pli = "";

      // first make sure that we have a cache entry for each plugin in the database
      // by design that should not be necessary, but you never know...
      $installedPlugins = $asterisk->getPlugin("");
      foreach ($installedPlugins as $p=>$v) {
        // This is safe. createPluginCachefromDB checks wether the pluginCache exists automatically
        $ret = createPluginCachefromDB($v['id']);
      }
      
      $plList=readPluginCache($plugin);
      
      // walk through the list
      foreach ($plList as $pl) {
                               
        // check wether this is a valid plugin cache. i.e skip scratch and the like
       if (is_file($absPluginPath . $pl . "/plugininfo.xml")) {
          $ret = file_get_contents($absPluginPath . $pl . "/plugininfo.xml" );
         
          $pli[$pl] = xml2array($ret);
          
          // add node for md5sum of archive . archive must exists because readPluginCache() would have created it if necessary
          $newNode['name'] = 'md5'; $newNode['closetag'] = '/md5';
          $newNode['text'] = md5_file($absPluginPath . $pl . ".zip");
          $pli[$pl][0]['elements'][] = $newNode;
          
          // add a node to indicate wether the plugin is installed
          $newNode['name'] = 'state'; $newNode['closetag'] = '/state';
          $installed = $asterisk->getPluginByPackageName($pl);
          if ($installed != "") {
            $newNode['text'] = STATE_SELECTED;  
          } else {
            $newNode['text'] = STATE_AVAILABLE;  
          }  
          $pli[$pl][0]['elements'][] = $newNode;       
         
        } // if
        
      } // foreach plList

      return $pli;
    }
  }



/**
 * Read plugin data for a specific plugin from cache, or get info about all plugins
 * 
 * Creates the corresponding pluginCache and pluginArchive in case it does not exists.  
 * @param string $plugin or "" for a list of all plugins
 * @return array $pluginList containing an array['plugin'] with content of plugininfo.xml for each entry or "" if no valid plugin exist
 */
  if (!function_exists("readPluginData")) {
    function readPluginData($plugin) {

      global $absPluginPath, $asterisk;
      
      $plc = "";

      // first make sure that we have a cache entry for each plugin in the database
      // by design that should not be necessary, but you never know...
      $installedPlugins = $asterisk->getPlugin("");     
      foreach ($installedPlugins as $p=>$v) {
        // This is safe. createPluginCachefromDB checks wether the pluginCache exists automatically
        $ret = createPluginCachefromDB($v['id']);
      }
      
      $plList=readPluginCache($plugin);
      // walk through the list

      foreach ($plList as $pl) {                               
        // check wether this is a valid plugin cache. i.e skip scratch and the like
        if (is_file($absPluginPath . $pl . "/plugindata.xml")) {
          $ret = file_get_contents($absPluginPath . $pl . "/plugindata.xml" );          
          $plc[$pl] = xml2array($ret);                    
        }         
      } // foreach plList

      return $plc;
    }
  }
  
  
  
  
/**
 * Get URL link to pluginArchive for download, or get URL links for all pluginArchives
 * 
 * @param string $plugin or "" for links of all pluginArchives
 * @return array $pluginArchiveURL containing an array with links for each entry or an array with [0]="" if failure
 * @todo replace hardcoded part of url with a global var or a function
 */
  if (!function_exists("readPluginArchiveURL")) {
    function readPluginArchiveURL($plugin) {

      global $absPluginPath;

      $plList=readPluginCache($plugin);
      // walk through the list
      foreach ($plList as $plInfo) {
        // first check if plugin exists. if not create it
        if (!is_file($absPluginPath . $plInfo . "zip")) {
          // TODO: ugly hack to get URL. 
          $plLink[$plInfo] = "../../../sandbox/plugins/" . $plInfo . ".zip";
        }
      } // foreach plList

      return $plLink;
    }
  }
  
  
/**
 * Create a pluginCache from uploaded pluginArchive that is zip compressed
 * 
 * Validate archive, create pluginCache directory with content, rename the directory and archive to match the name and version of the plugin
 * Note: This function does not activate the plugin.
 * @param string $pluginArchive (I.e. Wake_UP-Call.1.1.10.zip)
 * @return array $ret arr['state'] = true | false, arr['msg'] = statusmsg;
 * @todo do more validation for plugin. check version number
 */
  if (!function_exists("createPluginCachefromArchive")) {
    function createPluginCachefromArchive($pluginArchive) {
    
      global $absPluginPath, $cwlang;
      
      // use scratch dir as a temporary directory to allow to validate the content
      $scratch = "scratch";
      $scratchDir = $scratch . "/";
      $ret = array();
      
      // make directory if it does not exist
      // should work, because ../sandbox must be read/writable per definition
      if (!is_dir($absPluginPath.$scratchDir)) { mkdir($absPluginPath.$scratchDir); }
      // remove any possible previous files
      $cmd = "rm " . $absPluginPath . $scratchDir . "*";
      shell_exec("$cmd");
      
      // unzip package in $absPluginPath. Zip file contains no path information
      $cmd = "unzip " . $absPluginPath . $pluginArchive . " -d " . $absPluginPath.$scratchDir;
      shell_exec("$cmd");
      
      
      // check if valid plugin content - must at least contain plugininfo.xml
      if (!is_file($absPluginPath . $scratchDir . "plugininfo.xml")) {
        $state = false;
        $msg = $cwlang["plugins"]["pluginNotUploaded"];
        $msg .= "No valid Plugin Archive.";
        // remove uploaded file and its content
        $cmd = "rm " . $absPluginPath . $pluginArchive;
        shell_exec("$cmd");
        $cmd = "rm " . $absPluginPath . $scratchDir . "*";
        shell_exec("$cmd");
        $cmd = "rm -R " . $absPluginPath . $scratchDir;
        shell_exec("$cmd");
        
        $ret['state'] = $state;
        $ret['msg'] = $msg;
        return $ret;
      }
      
      
      // seems to be plugin. read the content of plugininfo.xml
      $newPlInfo = array(); // array for new uploaded plugin
      $curPlInfo = array(); // array for a potential existing plugin with the same name and version
      $ret = readPluginInfo($scratch);
      $newPlInfo = xmlArray2Hash($ret[$scratch][0]['elements']);  
      $newPackageName = $newPlInfo['packageName'];
      $newPackageMD5 = md5_file($absPluginPath . $pluginArchive);
      
      // readPluginInfo created "$scratch.zip" -  need to remove this file
      $cmd = "rm " . $absPluginPath . $scratch . ".zip";
      shell_exec("$cmd");                  
      
      if ($newPackageName != "") {
        // check wether we already have a plugin with the same name and version 
        $ret = readPluginInfo($newPackageName);
        $curPlInfo = xmlArray2Hash($ret[$newPackageName][0]['elements']);          
        
        if ($curPlInfo['packageName'] != "") { 
          // we already have a plugin with the same name and version. Do nothing and inform the user
          $state = false;
          $msg = $cwlang["plugins"]["pluginNotUploaded"] . "<br />";
          $msg .= "This plugin already exists in the same version." . "<br />" . "<br />";
          $msg .= "Plugin Package: " . $newPackageName . "<br />";
          $msg .= "Existing plugin MD5: " . $curPlInfo['md5'] . "<br />";
          $msg .= "Uploaded plugin MD5: " . $newPackageMD5 . "<br /><br />";
          $msg .= "If you want to use the uploaded plugin, delete the existing plugin first and try again." . "<br />";
          
          // remove uploaded file and its content
          $cmd = "rm " . $absPluginPath . $pluginArchive;
          shell_exec("$cmd");
          $cmd = "rm " . $absPluginPath . $scratchDir . "*";
          shell_exec("$cmd");
          $cmd = "rm -R " . $absPluginPath . $scratchDir;
          shell_exec("$cmd");
          
          $ret['state'] = $state;
          $ret['msg'] = $msg;
          return $ret;
        } //if we have already that package
      }
      
      // ok it seems that we can go ahead. we still have the data of the plugin in our array
      // rename the scratch dir to the packageName
      $cmd = "mv " . $absPluginPath . $scratchDir . "  " . $absPluginPath . $newPackageName . "/";
      shell_exec("$cmd");
      // rename the archive back to the packageName
      $cmd = "mv " . $absPluginPath . $pluginArchive . "  " . $absPluginPath . $newPackageName . ".zip";
      shell_exec("$cmd");


      // This should not be necessary - but it is safe
      // remove the scratch Dir 
      $cmd = "rm -R " . $absPluginPath . $scratchDir;
      shell_exec("$cmd");
      
      // build the ok message
      $state = true;
      $msg = "<strong>" . $cwlang["plugins"]["pluginUploaded"] . "</strong>" . "<br />";
      $msg .= "<strong>" . "Plugin Package name: " . "</strong>" . $newPackageName . "<br />";
      $msg .= "<strong>" . "Plugin MD5: " . "</strong>" . $newPackageMD5 . "<br />";
      
      $ret['state'] = $state; 
      $ret['msg'] = $msg;
      
      return $ret;
    }
  }

  
/**
 * Delete a plugin with its archive and cache directory
 * 
 * @param string $plugin (I.e. Wake_UP-Call.1.1.10)
 * @return integer $ret 1=ok 0=err
 * @todo check wether the plugin is active and handle the database together with vo-objects that are part of the plugin
 */
  if (!function_exists("deletePluginCache")) {
    function deletePluginCache($plugin) {
    
      global $absPluginPath, $cwlang;
      
      // does the cache exists
      if (!is_dir($absPluginPath . $plugin . "/")) {
        $ret = 0;
        return $ret;
      }
      
      // remove the cache Dir 
      $cmd = "rm -R " . $absPluginPath . $plugin . "/";
      shell_exec("$cmd");
      
      // remove the archive
      $cmd = "rm " . $absPluginPath . $plugin . ".zip";
      shell_exec("$cmd");
      
      $ret = 1;
      
      return $ret;
  
    }
  }

  
?>