<?php
//
//  Nagios Core Config Manager
//  Copyright (c) 2010-2019 Nagios Enterprises, LLC
//  Copyright (c) 2008, 2009 Martin Willisegger (nagconfig class)
//
//  File: config.class.php
//  Desc: Writes out configuration data to the filesystem
//


/**
 * Template builder class (replacing HTML_Template_IT)
 */
class Template {

    var $type = "";
    var $object = array();
    var $space = 4; // Number of spaces (as a tab) between opts
    var $lopt = 0; // The number of chars of the longest opt

    // List of configuration objects
    var $objects = array();

    // Default template header/footers
    var $header = "###############################################################################
#
# {TYPE} configuration file
#
# Created by: Nagios CCM {CCM_VERSION}
# Date:       {DATE}
# Version:    Nagios Core 4.x
#
# --- DO NOT EDIT THIS FILE BY HAND --- 
# Nagios CCM will overwrite all manual settings during the next update if you 
# would like to edit files manually, place them in the 'static' directory or 
# import your configs into the CCM by placing them in the 'import' directory.
#
###############################################################################";
    var $footer = "###############################################################################
#
# {TYPE} configuration file
#
# END OF FILE
#
###############################################################################";

    /**
     * Do basic replacements to prepare header/footer
     */
    function __construct($type) {
        $this->objtype = $this->get_object_type($type);
        $find = array("{TYPE}", "{CCM_VERSION}", "{DATE}");
        $replace = array(ucfirst($type), CCMVERSION, date("Y-m-d H:i:s", time()));
        $this->header = str_replace($find, $replace, $this->header);
        $this->footer = str_replace($find, $replace, $this->footer);
    }

    /**
     * Set the object types based on the $type which is typically plural
     * and used elsewhere in the CCM
     * (TODO: Clean this up someday so we don't need to do this switch statement)
     *
     * @param   string  $type   Type of object 
     * @return  string          Type of config object for Core
     */
    function get_object_type($type) {
        switch ($type) {
            case 'commands':
                return "command";
                break;
            case 'contactgroups':
                return "contactgroup";
                break;
            case 'contacts':
            case 'contacttemplates':
                return "contact";
                break;
            case 'hosts':
            case 'hosttemplates':
                return "host";
                break;
            case 'hostgroups':
                return "hostgroup";
                break;
            case 'hostdependencies':
                return "hostdependency";
                break;
            case 'hostescalations':
                return "hostescalation";
                break;
            case 'hostextinfo':
                return "hostextinfo";
                break;
            case 'services':
            case 'servicetemplates':
                return "service";
                break;
            case 'servicegroups':
                return "servicegroup";
                break;
            case 'servicedependencies':
                return "servicedependency";
                break;
            case 'serviceescalations':
                return "serviceescalation";
                break;
            case 'serviceextinfo':
                return "serviceextinfo";
                break;
            case 'timeperiods':
                return "timeperiod";
                break;
        }
    }

    /**
     * Create a new object definition section
     */
    function add_object() {
        if (!empty($this->object)) {
            $this->objects[] = $this->object;
        }
        $this->object = array();
    }

    /**
     * Add an option to the current object
     *
     * @param   string  $opt        Option name
     * @param   string  $val        Option value
     * @param   string  $comment    Comment on line
     */
    function add_option($opt, $val, $comment="") {
        if (!empty($opt)) {
            if (strlen($opt) > $this->lopt) {
                $this->lopt = strlen($opt);
            }
            $this->object[] = array('option' => $opt, 'value' => $val, 'comment' => $comment);
        }
    }

    /**
     * Parses the objects and creates a configuration file
     *
     * @return  string  Configuration file
     */
    function parse() {
        $cfg = "";
        $cfg .= $this->header."\n\n";

        // Make sure all objects have been added
        $this->add_object();

        // Create each object of the CFG
        foreach ($this->objects as $object) {
            $tmp = "";
            if (!empty($object)) {
                $tmp = "define {$this->objtype} {\n";
                foreach ($object as $i => $opt) {
                    $option = str_pad($opt['option'], $this->lopt);
                    $option = str_pad($option, strlen($option) + ($this->space * 2), " ", STR_PAD_BOTH);
                    $tmp .= $option.$opt['value'];
                    if (!empty($opt['comment'])) {
                        $tmp .= $blank."# ".$opt['comment'];
                    }
                    $tmp .= "\n";
                }
                $tmp .= "}\n\n";
            }
            $cfg .= $tmp;
        }

        $cfg .= $this->footer."\n";
        return $cfg;
    }

}


class Config
{
    // Class variable declaration
    var $intDomainId = 0;   // Is filled in the class
    var $strDBMessage = ""; // Used internally

    
    /**
     * Constructor for the config class. You can pass a configuration
     * array or the config array will be pulled from the session.
     * (Can someone explain why $CFG is passed as a session value... and named SETS?)
     *
     * @param   int     $domain     For multiple domain configs (optional - not used)
     */
    function __construct($config=null, $domain=1)
    {
        // Set domain (not currently used for anything)
        $this->intDomainId = $domain;
        if (isset($_SESSION['domain'])) {
            $this->intDomainId = $_SESSION['domain'];
        }
    }
  
    ///////////////////////////////////////////////////////////////////////////////////////////
    //  Function: Last table change and final configuration file change
    ///////////////////////////////////////////////////////////////////////////////////////////
    //
    //  Determines the timing of the last data table and change the last modification 
    //  to the configuration file
    //
    //  Transfer parameters: $strTableName - Data table name
    //
    //  Return value: 0 on success at / 1 failure
    //
    //  Return Values: $strTimeTable - The last data table change
    //                 $strTimeFile - The last configuration file change
    //                 $strCheckConfig - Information string if file is older than table
    //
    ///////////////////////////////////////////////////////////////////////////////////////////
    /**
     * @param $strTableName
     * @param $strTimeTable
     * @param $strTimeFile
     * @param $strCheckConfig
     *
     * @return int
     */
    function lastModified($strTableName, &$strTimeTable, &$strTimeFile, &$strCheckConfig)
    {
        global $ccm;

        // Configuration file name set in accordance with the table name
        switch($strTableName) {
            case "tbl_timeperiod": $strFile = "timeperiods.cfg"; break;
            case "tbl_command": $strFile = "commands.cfg"; break;
            case "tbl_contact": $strFile = "contacts.cfg"; break;
            case "tbl_contacttemplate": $strFile = "contacttemplates.cfg"; break;
            case "tbl_contactgroup": $strFile = "contactgroups.cfg"; break;
            case "tbl_hosttemplate": $strFile = "hosttemplates.cfg"; break;
            case "tbl_servicetemplate": $strFile = "servicetemplates.cfg"; break;
            case "tbl_hostgroup": $strFile = "hostgroups.cfg"; break;
            case "tbl_servicegroup": $strFile = "servicegroups.cfg"; break;
            case "tbl_servicedependency": $strFile = "servicedependencies.cfg"; break;
            case "tbl_hostdependency": $strFile = "hostdependencies.cfg"; break;
            case "tbl_serviceescalation": $strFile = "serviceescalations.cfg"; break;
            case "tbl_hostescalation": $strFile = "hostescalations.cfg"; break;
            case "tbl_hostextinfo": $strFile = "hostextinfo.cfg"; break;
            case "tbl_serviceextinfo": $strFile = "serviceextinfo.cfg"; break;
        }
    
        // Define variables 
        $strCheckConfig = "";
        $strTimeTable = "unknown";
        $strTimeFile = "unknown";

        // Status Delete Cache read and Domain Id new
        clearstatcache();
        if (isset($_SESSION['domain'])) { $this->intDomainId = $_SESSION['domain']; }
    
        // Last change to read the data table
        $strSQL = "SELECT `last_modified` FROM `".$strTableName."` WHERE `config_id`=".$this->intDomainId." ORDER BY `last_modified` DESC LIMIT 1";
        $booReturn = $ccm->db->getSingleDataset($strSQL, $arrDataset);
        if (($booReturn == true) && isset($arrDataset['last_modified'])) {
            $strTimeTable = $arrDataset['last_modified'];
        
            // Configuration data fetch
            $booReturn = $this->getConfigData("basedir", $strBaseDir);
            $booReturn = $this->getConfigData("method", $strMethod);
      
            // If file return older, the corresponding string
            if (($strMethod == 1) && (file_exists($strBaseDir."/".$strFile))) {
                $intFileStamp = filemtime($strBaseDir."/".$strFile);
                $strTimeFile = date("Y-m-d H:i:s", $intFileStamp);
                
                // If file return older, the corresponding string
                if (strtotime($strTimeTable) > $intFileStamp) {
                    $strCheckConfig = _("<span class='urgent'><span class='material-symbols-outlined'>warning</span> Changes detected! <strong><a href='" . get_component_url_base('nagioscorecfg') . "/applyconfig.php?cmd=confirm'>" . _("Apply Configuration") . "</a></strong> for new changes to take effect.</span>");
                }

                return(0);
            } 
        }
        return(1);
    }

    ///////////////////////////////////////////////////////////////////////////////////////////
    // Function: Last record update and final configuration file change 
    //////////////////////////////////////////////////////////////////////////////////////////
    //
    //  Determines the dates of the last record of the last amendment and modification
    //  the configuration file
    //
    //  Transfer parameters: $strConfigname - Name of the configuration
    //                       $strId - Record ID
    //                       $strType - Data type ("host" or "service")
    //
    //  Return value: 0 on success at / 1 failure
    //  Return Values: $strTime - Date of last record update
    //                 $strTimeFile - The last configuration file change
    //                 $intOlder - 0 if file is older / 1, if current
    //
    ///////////////////////////////////////////////////////////////////////////////////////////
    /**
     * @param $strConfigname
     * @param $strId
     * @param $strType
     * @param $strTime
     * @param $strTimeFile
     * @param $intOlder
     *
     * @return int
     */
    function lastModifiedDir($strConfigname, $strId, $strType, &$strTime, &$strTimeFile, &$intOlder, $useConfigname=false)
    {
        global $ccm;

        // File Name compile
        $strFile = $this->sanatize_filename($strConfigname).".cfg";
        $intCheck = 0;
    
        // Cache Status
        clearstatcache();

        // Last updated readout of the data table 
        if ($strType == "host") {
            $strTime = $ccm->db->getFieldData("SELECT DATE_FORMAT(`last_modified`,'%Y-%m-%d %H:%i:%s')
                                                       FROM `tbl_host` WHERE `id`=".$strId);
            $booReturn = $this->getConfigData("hostconfig", $strBaseDir);
            if ($strTime != false) { $intCheck++; }
        } elseif ($strType == "service") {
            if ($useConfigname) {
                $strSql = "SELECT DATE_FORMAT(`last_modified`,'%Y-%m-%d %H:%i:%s') FROM `tbl_service` WHERE `config_name` = '".$strConfigname."' ORDER BY `last_modified` DESC LIMIT 1";
            } else {
                $strSql = "SELECT DATE_FORMAT(`last_modified`,'%Y-%m-%d %H:%i:%s') FROM `tbl_service` WHERE `id`=".$strId;
            }
            $strTime = $ccm->db->getFieldData($strSql);
            $booReturn = $this->getConfigData("serviceconfig", $strBaseDir);
            if ($strTime != false) { $intCheck++; }
        } else {
            $strTime = "undefined";
            $intOlder = 1;
        }

        // Last change to read the configuration file
        $booReturn = $this->getConfigData("method", $strMethod);

        // Last change to read the configuration file
        if (($strMethod == 1) && (file_exists($strBaseDir."/".$strFile))) {
            $intFileStamp = filemtime($strBaseDir."/".$strFile);
            $strTimeFile = date("Y-m-d H:i:s", $intFileStamp);
            $intCheck++;
        } else {
            $strTimeFile = "undefined";
            $intOlder = 1;
        }

        // If both values are valid to compare
        if ($intCheck == 2) {
            if (strtotime($strTime) > $intFileStamp) { $intOlder = 1; } else { $intOlder = 0; }
            return(0);
        }

        return(1);
    }

    ///////////////////////////////////////////////////////////////////////////////////////////
    //  Function: Get configuration data
    ///////////////////////////////////////////////////////////////////////////////////////////
    //
    //  Determines the configuration settings using the domain, and the settings
    //  stored in the database since version 3.0. 
    //
    //  Transfer parameters: $strConfigItem - Configuration Item (DB column name)
    //
    //  Return value: 0 on success at / 1 failure
    //
    //  Return values: $strValue - Configuration value
    //
    ///////////////////////////////////////////////////////////////////////////////////////////
    /**
     * @param $strConfigItem
     * @param $strValue
     *
     * @return int
     */
    function getConfigData($strConfigItem, &$strValue)
    {
        global $ccm;

        $strSQL = "SELECT `".$strConfigItem."` FROM `tbl_domain` WHERE `id` = ".$this->intDomainId;
        $strValue = $ccm->db->getFieldData($strSQL);
        if ($strValue != "" ) { return(0); }
        return(1);
    }

    ///////////////////////////////////////////////////////////////////////////////////////////
    //  Function: Checks special template settings
    ///////////////////////////////////////////////////////////////////////////////////////////
    //
    //  Determined based on the template settings for additional options needed
    //  configuration value
    //
    //  Transfer parameters: $strValue - Unchanged configuration value
    //                       $strKeyField - Key field name that contains the options
    //                       $strTable - table name 
    //                       $intId - Record ID
    //
    //  Return value: $intSkip - Skip value
    //
    ///////////////////////////////////////////////////////////////////////////////////////////
    /**
     * @param $strValue
     * @param $strKeyField
     * @param $strTable
     * @param $intId
     * @param $intSkip
     *
     * @return string
     */
    function checkTpl($strValue, $strKeyField, $strTable, $intId, &$intSkip, $intMode = 0)
    {
        global $ccm;

        $strSQL = "SELECT `".$strKeyField."` FROM `".$strTable."` WHERE `id` = $intId";
        $intValue = $ccm->db->getFieldData($strSQL);
        if ($intValue == 0) { 
            if ($intMode == 2 && is_array($strValue)) {
                array_unshift($strValue, "+");
                return $strValue;
            } else {
                return("+".$strValue);
            }
        }
        if ($intValue == 1) {
            $intSkip = 0;
            return("null");
        }
        return($strValue);
    }

    ///////////////////////////////////////////////////////////////////////////////////////////
    //  Function: Moving a configuration file to the backup directory
    ///////////////////////////////////////////////////////////////////////////////////////////
    //
    // Moves an existing configuration file in the backup directory and deletes
    // the original file
    // 
    //  Transfer parameters: $strType - Type of configuration file 
    //                       $strName - Name of the configuration file
    //
    //  Returns: 0 on success at / 1 failure
    //
    ///////////////////////////////////////////////////////////////////////////////////////////
    /**
     * @param $strType
     * @param $strName
     *
     * @return int
     */
    function moveFile($strType, $strName) {
        
        // Sanatize file name
        $strName = $this->sanatize_filename($strName);

        // Directories determine
        switch ($strType) {

            case "host": 
                $this->getConfigData("hostconfig", $strConfigDir);
                $this->getConfigData("hostbackup", $strBackupDir);
                break;

            case "service":
                $this->getConfigData("serviceconfig", $strConfigDir);
                $this->getConfigData("servicebackup", $strBackupDir);
                break;

            case "basic":
                $this->getConfigData("basedir", $strConfigDir);
                $this->getConfigData("backupdir", $strBackupDir);
                break;

            case "nagiosbasic":
                $this->getConfigData("nagiosbasedir", $strConfigDir);
                $this->getConfigData("backupdir", $strBackupDir);
                break;

            default:
                return 1;
        }

        // Remove the file permanently instead of backing it up
        if (file_exists($strConfigDir."/".$strName)) {
            if (!unlink($strConfigDir."/".$strName)) {
                $this->strDBMessage = _('Config file: '.$strConfigDir."/".$strName.' failed to delete, check permissions and delete file manually!');
                return 1;
            } 
        } else {
            // Something went wrong  
            if (file_exists($strConfigDir."/".$strName)) {
                $this->strDBMessage = _('Config file: '.$strConfigDir."/".$strName.' failed to delete, check permissions and delete file manually!');
                return 1;
            } else {
                return 0; // File is already removed, shouldn't matter from here 
            }
        }

        return 0;
    }

    ///////////////////////////////////////////////////////////////////////////////////////////
    //  Function: Deletes a configuration file
    ///////////////////////////////////////////////////////////////////////////////////////////
    //
    //  Deletes a configuration file (does not create a backup)
    //
    //  Transfer parameter: $strType - Type of configuration file
    //                      $strName - Name of the configuration file
    //
    //  Returns: 0 on success at / 1 failure
    //
    ///////////////////////////////////////////////////////////////////////////////////////////
    /**
     * @param $strName
     *
     * @return int
     */
    function removeFile($strName) {

        // Check file exists and has permissions
        if (file_exists($strName)) {
            if (!unlink($strName)) {
                // Added check to see if the file is actually deleted 
                $this->strDBMessage = _('Cannot delete the file (check the permissions)!');
                return(1);
            }
        } else {
            $this->strDBMessage = _('Cannot delete the file (check the permissions)!');
            return(1);
        }
        return(0);
    }

    ///////////////////////////////////////////////////////////////////////////////////////////
    //  Function: write a complete configuration file
    ///////////////////////////////////////////////////////////////////////////////////////////
    //
    //  Writes a single configuration file with all records from a table or
    //  returns the output from a text file to download.
    //
    //  Transfer parameter: $strTableName - Table name
    //                      $intMode - 0 = Write file, 1 = output for Download
    //
    //  Returns: 0 on success at / 1 failure
    //
    //  RETURN VALUE: Success - error message using class variable strDBMessage
    //
    ///////////////////////////////////////////////////////////////////////////////////////////
    /**
     * @param   string  $strTableName
     * @param   int     $intMode
     * @param   string  $searchable
     * @return  int
     */
    function createConfig($strTableName, $intMode=0, $searchable = '')
    {
        global $ccm;

        if ($strTableName == "tbl_mrtgfile") { return; } // We don't want to create configuration for MRTG files -swolf 2024-06-17

        // Variables defined according to the Table names
        switch ($strTableName) {

            case "tbl_timeperiod":
                $strFileString = "timeperiods";
                $strOrderField = "timeperiod_name";
                break;

            case "tbl_command":
                $strFileString = "commands";
                $strOrderField = "command_name";
                break;

            case "tbl_contact":
                $strFileString = "contacts";
                $strOrderField = "contact_name";
                break;

            case "tbl_contacttemplate":
                $strFileString = "contacttemplates";
                $strOrderField = "template_name";
                break;

            case "tbl_contactgroup":
                $strFileString = "contactgroups";
                $strOrderField = "contactgroup_name";
                break;

            case "tbl_hosttemplate":
                $strFileString = "hosttemplates";
                $strOrderField = "template_name";
                break;

            case "tbl_hostgroup":
                $strFileString = "hostgroups";
                $strOrderField = "hostgroup_name";
                break;

            case "tbl_servicetemplate":
                $strFileString = "servicetemplates";
                $strOrderField = "template_name";
                break;
            
            case "tbl_servicegroup":
                $strFileString = "servicegroups";
                $strOrderField = "servicegroup_name";
                break;
            
            case "tbl_hostdependency":
                $strFileString = "hostdependencies";
                $strOrderField = "dependent_host_name";
                break;
            
            case "tbl_hostescalation":
                $strFileString = "hostescalations";
                $strOrderField = "host_name`,`hostgroup_name";
                break;
            
            case "tbl_hostextinfo":
                $strFileString = "hostextinfo";
                $strOrderField = "host_name";
                break;
            
            case "tbl_servicedependency":
                $strFileString = "servicedependencies";
                $strOrderField = "dependent_host_name";
                break;
            
            case "tbl_serviceescalation":
                $strFileString = "serviceescalations";
                $strOrderField = "host_name`,`service_description";
                break;
            
            case "tbl_serviceextinfo":
                $strFileString = "serviceextinfo";
                $strOrderField = "host_name";
                break;

            default:
                return(1);
        }

        $search_query = "";
        if (!empty($searchable)) {
            $search_query = " " . $strOrderField . " = '" . $ccm->db->escape_string($searchable) . "' AND ";
        }

        // SQL Query set and define file name 
        $strSQL = "SELECT * FROM `".$strTableName."`
                   WHERE `active`='1' AND".$search_query." `config_id`=".$this->intDomainId." ORDER BY `".$strOrderField."`";
        $strFile = $strFileString.".cfg";
        
        // Relations take
        $ccm->data->tableRelations($strTableName, $arrRelations);

        // Write configuration?
        if ($intMode == 0) {
            // Configuration data fetch
            $booReturn = $this->getConfigData("basedir", $strBaseDir);
            $booReturn = $this->getConfigData("backupdir", $strBackupDir);
            $booReturn = $this->getConfigData("method", $strMethod);
            if ($strMethod == 1) {
                // Configuration file open
                if (is_writable($strBaseDir."/".$strFile) || (!file_exists($strBaseDir."/".$strFile))) {
                    $CONFIGFILE = fopen($strBaseDir."/".$strFile, "w");
                    @chmod($strBaseDir."/".$strFile, 0664); // Try to chmod, not a big deal if it can't
                } else {
                    $ccm->data->writeLog("<span class=\"verify-critical\">"._('Configuration write failed:')."</span>"." ".$strFile);
                    $this->strDBMessage = "<span class=\"verify-critical\">"._('Cannot open/overwrite the configuration file (check the permissions)!')."</span>";
                    return(1);
                }
            } 
        }

        // Start building template
        $this->getConfigData("version", $strVersionValue);
        $tpl = new Template($strFileString);
    
        // Database query and result processing
        $booReturn = $ccm->db->getDataArray($strSQL, $arrData, $intDataCount);

        if ($booReturn == false) {
            $this->strDBMessage = "<span class=\"verify-critical\">"._('Error while selecting data from database:')."</span>"."<br>".$ccm->db->strDBError."<br>";
        } else if ($intDataCount != 0) {
            // Each record processed
            for ($i=0; $i < $intDataCount; $i++) {

                // Write out the config name at the top of the file if we are using something that
                // has a config name - so that we can update them better on import
                if (($strTableName == "tbl_serviceescalation") || ($strTableName == "tbl_hostescalation") || ($strTableName == "tbl_servicedependency") || ($strTableName == "tbl_hostdependency")) {
                    $tpl->add_option("# config_name", $arrData[$i]["config_name"]);
                }

                foreach($arrData[$i] AS $key => $value) {
                    $intSkip = 0;
                    if ($key == "id") $intDataId = $value;
          
                    // Special fields data skip
                    $strSpecial = "id,config_name,active,last_modified,access_rights,config_id,template,nodelete,command_type";
                    if ($strTableName == "tbl_hosttemplate") $strSpecial .= ",parents_tploptions,hostgroups_tploptions,contacts_tploptions,contact_groups_tploptions,use_template_tploptions";
                    if ($strTableName == "tbl_servicetemplate") $strSpecial .= ",host_name_tploptions,hostgroup_name_tploptions,servicegroups_tploptions,contacts_tploptions,contact_groups_tploptions,use_template_tploptions";
                    if ($strTableName == "tbl_contact") $strSpecial .= ",use_template_tploptions,contactgroups_tploptions,host_notification_commands_tploptions,service_notification_commands_tploptions";
                    if ($strTableName == "tbl_contacttemplate") $strSpecial .= ",use_template_tploptions,contactgroups_tploptions,host_notification_commands_tploptions,service_notification_commands_tploptions";

                    // Depending on the version skip other fields
                    if ($strVersionValue != 3) {
                        // Timeperiod
                        if ($strTableName == "tbl_timeperiod") $strSpecial .= ",exclude,name";
                        // Contact
                        if ($strTableName == "tbl_contact") $strSpecial .= ",host_notifications_enabled,service_notifications_enabled,can_submit_commands,retain_status_information,retain_nonstatus_information";
                        // Contacttemplate
                        if ($strTableName == "tbl_contacttemplate") $strSpecial .= ",host_notifications_enabled,service_notifications_enabled,can_submit_commands,retain_status_information,retain_nonstatus_information";
                        // Contactgroup
                        if ($strTableName == "tbl_contactgroup") $strSpecial .= ",contactgroup_members";
                        // Hostgroup
                        if ($strTableName == "tbl_hostgroup") $strSpecial .= ",hostgroup_members,notes,notes_url,action_url";
                        // Servicegroup
                        if ($strTableName == "tbl_sevicegroup") $strSpecial .= ",servicegroup_members,notes,notes_url,action_url";
                        // Hostdependencies
                        if ($strTableName == "tbl_hostdependency") $strSpecial .= ",dependent_hostgroup_name,hostgroup_name,dependency_period";
                    }

                    if ($strVersionValue == 3) {
                        // Servicetemplate
                        if ($strTableName == "tbl_servicetemplate") $strSpecial .= ",parallelize_check ";
                    }

                    if ($strVersionValue == 1) {
                        $strSpecial .= "";
                    }

                    $arrSpecial = explode(",", $strSpecial);
                    if (($value == "") || (in_array($key, $arrSpecial))) {
                        continue;
                    }

                    // Not all configuration data write
                    $strNoTwo  = "active_checks_enabled,passive_checks_enabled,obsess_over_host,check_freshness,event_handler_enabled,flap_detection_enabled,";
                    $strNoTwo .= "process_perf_data,retain_status_information,retain_nonstatus_information,notifications_enabled,parallelize_check,is_volatile,";
                    $strNoTwo .= "host_notifications_enabled,service_notifications_enabled,can_submit_commands,obsess_over_service";
                    $booTest = 0;
                    foreach(explode(",",$strNoTwo) AS $elem){
                        if (($key == $elem) && ($value == "2")) { $booTest = 1; }
                    }
                    if ($booTest == 1) { continue; }

                    // Is the data field associated with a relationship with another data field?
                    // TODO: Realtions ?
                    if (is_array($arrRelations)) {
                        foreach($arrRelations AS $elem) {
                            if ($elem['fieldName'] == $key) {

                                // Is this a normal 1: n relation
                                if (($elem['type'] == 2) && ($value == 1)) {

                                    $exclude = '';
                                    if (in_array($strTableName, array('tbl_servicetemplate', 'tbl_hostgroup', 'tbl_serviceescalation', 'tbl_hostescalation'))) {
                                        if ($elem['target'] == 'host_name' || $elem['target'] == "hostgroup_name" || $elem['target'] == "service_description") {
                                            $exclude = ', `exclude`';
                                        }
                                    }

                                    $strSQLRel = "SELECT `".$elem['tableName']."`.`".$elem['target']."`".$exclude." FROM `".$elem['linktable']."`
                                                  LEFT JOIN `".$elem['tableName']."` ON `".$elem['linktable']."`.`idSlave` = `".$elem['tableName']."`.`id`
                                                  WHERE `idMaster`=".$arrData[$i]['id']." AND `active`='1'
                                                  ORDER BY `".$elem['tableName']."`.`".$elem['target']."`";

                                    $booReturn = $ccm->db->getDataArray($strSQLRel, $arrDataRel, $intDataCountRel);

                                    // Records were found?
                                    if ($intDataCountRel != 0) {

                                        // Data field values of records found register
                                        $value = array();
                                        foreach ($arrDataRel AS $data) {
                                            
                                            $tmp = trim($data[$elem['target']]);
                                            if ($elem['target'] == 'host_name' || $elem['target'] == "hostgroup_name" || $elem['target'] == "service_description") {
                                                if (!empty($data['exclude'])) {
                                                    $tmp = '!'.$tmp;
                                                }
                                            }

                                            $value[] = $tmp;
                                        }

                                        if ($intMode != 2) {
                                            $value = implode(',', $value);
                                        }

                                    } else {
                                        $intSkip = 1;
                                    }

                                // Is this a normal 1:1 ratio?
                                } else if ($elem['type'] == 1) {
                                    if ($elem['tableName'] == "tbl_command") {
                                        $arrField = explode("!", $arrData[$i][$elem['fieldName']]);
                                        $strCommand = strchr($arrData[$i][$elem['fieldName']],"!");
                                        $strSQLRel = "SELECT `".$elem['target']."` FROM `".$elem['tableName']."` WHERE `id`=".$arrField[0]." AND `active`='1'";
                                    } else {
                                        $strSQLRel  = "SELECT `".$elem['target']."` FROM `".$elem['tableName']."` WHERE `id`=".$arrData[$i][$elem['fieldName']]." AND `active`='1'";
                                    }
                                    $booReturn = $ccm->db->getDataArray($strSQLRel, $arrDataRel, $intDataCountRel);
                  
                                    // Records were found?
                                    if ($booReturn && ($intDataCountRel != 0)) {
                                        // Value data field of the found record entry
                                        if ($elem['tableName'] == "tbl_command") {
                                            $value = $arrDataRel[0][$elem['target']].$strCommand;
                                        } else {
                                            $value = $arrDataRel[0][$elem['target']];
                                        }
                                    } else {
                                        $intSkip = 1;
                                    }
                
                                // If it is a normal 1: n relation with special table?
                                } else if (($elem['type'] == 3) && ($value == 1)) {
                                    $strSQLMaster = "SELECT * FROM `".$elem['linktable']."` WHERE `idMaster` = ".$arrData[$i]['id']." ORDER BY `idSort`";
                                    $booReturn = $ccm->db->getDataArray($strSQLMaster, $arrDataMaster, $intDataCountMaster);
                                    
                                    // Records were found?
                                    if ($intDataCountMaster != 0) {

                                        // Is this a normal 1: n relation with special table?
                                        $value = array();
                                        foreach ($arrDataMaster AS $data) {
                                            if ($data['idTable'] == 1) {
                                                $strSQLName = "SELECT `".$elem['target1']."` FROM `".$elem['tableName1']."` WHERE `id` = ".$data['idSlave']." AND `active`='1'";
                                            } else {
                                                $strSQLName = "SELECT `".$elem['target2']."` FROM `".$elem['tableName2']."` WHERE `id` = ".$data['idSlave']." AND `active`='1'";
                                            }
                                            $value[] = $ccm->db->getFieldData($strSQLName);
                                        }
                                        
                                        if ($intMode != 2) {
                                            $value = implode(',', $value);
                                        }

                                    } else {
                                        $intSkip = 1;
                                    }

                                // If it is a special relation to free variables?
                                } else if (($elem['type'] == 4) && ($value == 1)) {
                                    $strSQLVar = "SELECT * FROM `tbl_variabledefinition` LEFT JOIN `".$elem['linktable']."` ON `id` = `idSlave` WHERE `idMaster`=".$arrData[$i]['id']." ORDER BY `name`";
                                    $booReturn = $ccm->db->getDataArray($strSQLVar, $arrDSVar, $intDCVar);
                                    if ($intDCVar != 0) {
                                        foreach ($arrDSVar AS $vardata) {
                                            $tpl->add_option($vardata['name'], $vardata['value']);
                                        }
                                    }
                                    $intSkip = 1;
                                
                                // If it is a special relation to service groups?
                                } else if (($elem['type'] == 5) && ($value == 1)) {
                                    $strSQLMaster = "SELECT * FROM `".$elem['linktable']."` WHERE `idMaster` = ".$arrData[$i]['id'];
                                    $booReturn = $ccm->db->getDataArray($strSQLMaster, $arrDataMaster, $intDataCountMaster);
                  
                                    // Records were found?
                                    if ($intDataCountMaster != 0) {
                                        // Is this a normal 1: n relation with special table?
                                        $arrServices = array();
                                        foreach ($arrDataMaster AS $data) {
                                            if ($data['idSlaveHG'] != 0) {
                                                $strService = $ccm->db->getFieldData("SELECT `".$elem['target2']."` FROM `".$elem['tableName2']."` WHERE `id` = ".$data['idSlaveS']." AND `active`='1'");
                                                $strSQLHG1  = "SELECT `host_name` FROM `tbl_host` LEFT JOIN `tbl_lnkHostgroupToHost` ON `id`=`idSlave` WHERE `idMaster`=".$data['idSlaveHG']." AND `active`='1'";;
                                                $booReturn  = $ccm->db->getDataArray($strSQLHG1, $arrHG1, $intHG1);
                                                if ($intHG1 != 0) {
                                                    foreach ($arrHG1 AS $elemHG1) {
                                                        if (!in_array($elemHG1['host_name'].",".$strService, $arrServices)) {
                                                            $arrServices[] = $elemHG1['host_name'].",".$strService;
                                                        }
                                                    }
                                                }

                                                $strSQLHG2  = "SELECT `host_name` FROM `tbl_host` LEFT JOIN `tbl_lnkHostToHostgroup` ON `id`=`idMaster` WHERE `idSlave`=".$data['idSlaveHG']." AND `active`='1'";;
                                                $booReturn  = $ccm->db->getDataArray($strSQLHG2, $arrHG2, $intHG2);
                                                if ($intHG2 != 0) {
                                                    foreach ($arrHG2 AS $elemHG2) {
                                                        if (!in_array($elemHG2['host_name'].",".$strService, $arrServices)) {
                                                            $arrServices[] = $elemHG2['host_name'].",".$strService;
                                                        }
                                                    }
                                                }
                                            } else {
                                                $strHost   = $ccm->db->getFieldData("SELECT `".$elem['target1']."` FROM `".$elem['tableName1']."` WHERE `id` = ".$data['idSlaveH']." AND `active`='1'");
                                                $strService  = $ccm->db->getFieldData("SELECT `".$elem['target2']."` FROM `".$elem['tableName2']."` WHERE `id` = ".$data['idSlaveS']." AND `active`='1'");
                                                if (($strHost != "") && ($strService != "")) {
                                                    if (!in_array($strHost.",".$strService, $arrServices)) {
                                                        $arrServices[] = $strHost.",".$strService;
                                                    }
                                                }
                                            }
                                        }
                                        if ($intMode != 2) {
                                            $value = implode(',', $arrServices);
                                        } else {
                                            $value = $arrServices;
                                        }
                                    } else {
                                        $intSkip = 1;
                                    }

                                // If it is the exceptional value "*"?
                                } else if ($value == 2) {
                                    $value = "*";

                                    // Special for service escalations and service dependencies to ensure we add the objects that are excluded
                                    if (($strTableName == 'tbl_serviceescalation' && ($elem['target'] == 'host_name' || $elem['target'] == "hostgroup_name" || $elem['target'] == "service_description")) || 
                                        ($strTableName == 'tbl_servicedependency' && $elem['fieldName'] == 'dependent_service_description')) {

                                        $strSQLRel = "SELECT `".$elem['tableName']."`.`".$elem['target']."` FROM `".$elem['linktable']."`
                                                      LEFT JOIN `".$elem['tableName']."` ON `".$elem['linktable']."`.`idSlave` = `".$elem['tableName']."`.`id`
                                                      WHERE `idMaster`=".$arrData[$i]['id']." AND exclude = 1
                                                      ORDER BY `".$elem['tableName']."`.`".$elem['target']."`";
                                        $booReturn = $ccm->db->getDataArray($strSQLRel, $arrDataRel, $intDataCountRel);

                                        if ($intDataCountRel != 0) {
                                            $objs = array();
                                            foreach ($arrDataRel AS $data) {
                                                $objs[] = '!'.$data[$elem['target']];
                                            }
                                            $value .= ','.implode(',', $objs);
                                        }

                                    }

                                } else {
                                    $intSkip = 1;
                                }
                            }
                        }
                    }
          
                    // Rename fields
                    if ($strTableName == "tbl_hosttemplate") {
                        if ($key == "template_name") $key = "name";
                        if ($key == "use_template") $key = "use";
                        $strVIValues  = "active_checks_enabled,passive_checks_enabled,check_freshness,obsess_over_host,event_handler_enabled,";
                        $strVIValues .= "flap_detection_enabled,process_perf_data,retain_status_information,retain_nonstatus_information,";
                        $strVIValues .= "notifications_enabled";
                        if (in_array($key, explode(",", $strVIValues))) {
                            if ($value == -1) $value = "null";
                            if ($value == 3) $value = "null";
                        }
                        if ($key == "parents") $value = $this->checkTpl($value, "parents_tploptions", "tbl_hosttemplate", $intDataId, $intSkip);
                        if ($key == "hostgroups") $value = $this->checkTpl($value, "hostgroups_tploptions", "tbl_hosttemplate", $intDataId, $intSkip);
                        if ($key == "contacts") $value = $this->checkTpl($value, "contacts_tploptions", "tbl_hosttemplate", $intDataId, $intSkip);
                        if ($key == "contact_groups") $value = $this->checkTpl($value, "contact_groups_tploptions", "tbl_hosttemplate", $intDataId, $intSkip);
                        if ($key == "use") $value = $this->checkTpl($value, "use_template_tploptions", "tbl_hosttemplate", $intDataId, $intSkip);
                    }

                    if ($strTableName == "tbl_servicetemplate") {
                        if ($key == "template_name") $key = "name";
                        if ($key == "use_template") $key = "use";
                        if (($strVersionValue != 3) && ($strVersionValue != 2)) {
                            if ($key == "check_interval") $key = "normal_check_interval";
                            if ($key == "retry_interval") $key = "retry_check_interval";
                        }
                        $strVIValues  = "is_volatile,active_checks_enabled,passive_checks_enabled,parallelize_check,obsess_over_service,";
                        $strVIValues .= "check_freshness,event_handler_enabled,flap_detection_enabled,process_perf_data,retain_status_information,";
                        $strVIValues .= "retain_nonstatus_information,notifications_enabled";
                        if (in_array($key, explode(",", $strVIValues))) {
                            if ($value == -1) $value = "null";
                            if ($value == 3) $value = "null";
                        }
                        if ($key == "host_name") $value = $this->checkTpl($value, "host_name_tploptions", "tbl_servicetemplate", $intDataId, $intSkip);
                        if ($key == "hostgroup_name") $value = $this->checkTpl($value, "hostgroup_name_tploptions", "tbl_servicetemplate", $intDataId, $intSkip);
                        if ($key == "servicegroups") $value = $this->checkTpl($value, "servicegroups_tploptions", "tbl_servicetemplate", $intDataId, $intSkip);
                        if ($key == "contacts") $value = $this->checkTpl($value, "contacts_tploptions", "tbl_servicetemplate", $intDataId, $intSkip);
                        if ($key == "contact_groups") $value = $this->checkTpl($value, "contact_groups_tploptions", "tbl_servicetemplate", $intDataId, $intSkip);
                        if ($key == "use") $value = $this->checkTpl($value, "use_template_tploptions", "tbl_servicetemplate", $intDataId, $intSkip);
                    }

                    if ($strTableName == "tbl_contact") {
                        if ($key == "use_template") $key = "use";
                        $strVIValues = "host_notifications_enabled,service_notifications_enabled,can_submit_commands,retain_status_information,";
                        $strVIValues .= "retain_nonstatus_information";
                        if (in_array($key, explode(",", $strVIValues))) {
                            if ($value == -1) $value = "null";
                            if ($value == 3) $value = "null";
                        }
                        if ($key == "contactgroups") $value = $this->checkTpl($value, "contactgroups_tploptions", "tbl_contact", $intDataId, $intSkip);
                        if ($key == "host_notification_commands") $value = $this->checkTpl($value, "host_notification_commands_tploptions", "tbl_contact", $intDataId, $intSkip);
                        if ($key == "service_notification_commands") $value = $this->checkTpl($value, "service_notification_commands_tploptions", "tbl_contact", $intDataId, $intSkip);
                        if ($key == "use") $value = $this->checkTpl($value, "use_template_tploptions", "tbl_contact", $intDataId, $intSkip);
                    }

                    if ($strTableName == "tbl_contacttemplate") {
                        if ($key == "template_name") $key = "name";
                        if ($key == "use_template") $key = "use";
                        $strVIValues = "host_notifications_enabled,service_notifications_enabled,can_submit_commands,retain_status_information,";
                        $strVIValues .= "retain_nonstatus_information";
                        if (in_array($key, explode(",", $strVIValues))) {
                            if ($value == -1) $value = "null";
                            if ($value == 3) $value = "null";
                        }
                        if ($key == "contactgroups") $value = $this->checkTpl($value, "contactgroups_tploptions", "tbl_contacttemplate", $intDataId, $intSkip);
                        if ($key == "host_notification_commands") $value = $this->checkTpl($value, "host_notification_commands_tploptions", "tbl_contacttemplate", $intDataId, $intSkip);
                        if ($key == "service_notification_commands") $value = $this->checkTpl($value, "service_notification_commands_tploptions", "tbl_contacttemplate", $intDataId, $intSkip);
                        if ($key == "use") $value = $this->checkTpl($value, "use_template_tploptions", "tbl_contacttemplate", $intDataId, $intSkip);
                    }

                    // If the data field should not be skipped
                    if ($intSkip != 1) {
                        // Remove ; replacing with valid encoded char values
                        $value = str_replace(array('\;', ';'), array(';', '\;'), $value);

                        // Key and value to write to template and call next line
                        $tpl->add_option($key, $value);
                    }
                }
                // End of "foreach rule"

                // Special rule for periods of time
                if ($strTableName == "tbl_timeperiod") {
                    $strSQLTime = "SELECT `definition`, `range` FROM `tbl_timedefinition` WHERE `tipId` = ".$arrData[$i]['id'];
                    $booReturn = $ccm->db->getDataArray($strSQLTime, $arrDataTime, $intDataCountTime);
        
                    // Records were found?
                    if ($intDataCountTime != 0) {
                        // Is this a normal 1: n relation with special table?
                        foreach ($arrDataTime AS $data) {
                            // Key and value to write to template and call next line
                            $tpl->add_option(stripslashes($data['definition']), stripslashes($data['range']));
                        }
                    }
                }

                if (($strTableName == "tbl_hosttemplate") || ($strTableName == "tbl_servicetemplate") || ($strTableName == "tbl_contacttemplate")) {
                    $tpl->add_option("register", "0");
                }

                // Add config object to template
                $tpl->add_object();
            }
        }

        // Return a special version that is only an array
        if ($intMode == 2) {
            $tpl->add_object();

            $objs = array();
            foreach ($tpl->objects as $object) {
                $tmp = array();
                foreach ($object as $o) {
                    $tmp[$o['option']] = $o['value'];
                }
                $objs[] = $tmp;
            }

            return $objs;
        }

        $cfg_file = $tpl->parse();
    
        // According to the write mode, the output in the configuration file or directly print
        if ($intMode == 0) {
            fwrite($CONFIGFILE, $cfg_file);
            fclose($CONFIGFILE);
            $this->strDBMessage = _("<span class='successMessage'>"._('Configuration file').": <strong>$strFile</strong> "._('successfully written!')."</span>");
            return(0);
        } else if ($intMode == 1) {
            print $cfg_file;
            return(0);
        }
        return(1);
    }


    /**
     * Writes a configuration file for a host or set of services based on the config
     * name passed to it.
     *
     * @param   string  $strTableName   Table name
     * @param   string  $cfgName        Config name
     * @param   int     $intMode        0 = write file, 1 = output
     * @param   string  $service        A service_description if we are trying to get just a single service
     * @return  int                     1 for success and 0 for failure
     */
    function createConfigSingle($strTableName, $cfgName = '', $intMode = 0, $service = '', $filter = 'active')
    {
        global $ccm;
        $return = 0;

        if ($strTableName == "tbl_mrtgfile") { return; } // We don't want to create configuration for MRTG files -swolf 2024-06-17
        // Variables defined according to the Table names
        switch ($strTableName) {
            
            case "tbl_host":
                $setTemplate = "hosts";
                $this->getConfigData("hostconfig", $strBaseDir);
                $this->getConfigData("hostbackup", $strBackupDir);
                $strSQLData = "SELECT * FROM `".$strTableName."` WHERE `host_name`='" . $ccm->db->escape_string($cfgName) . "' AND `config_id`=".intval($this->intDomainId);
                break;

            case "tbl_service":
                $setTemplate = "services";
                $this->getConfigData("serviceconfig", $strBaseDir);
                $this->getConfigData("servicebackup", $strBackupDir);

                // Add special where statement if we have a service we are looking for
                $service_query = "";
                if (!empty($service)) {
                    $service_query = " service_description = '" . $ccm->db->escape_string($service) . "' AND ";
                }

                $strSQLData = "SELECT * FROM `".$strTableName."` WHERE `config_name`='".$cfgName."' AND" . $service_query . " `config_id`=".intval($this->intDomainId)." ORDER BY `service_description`";
                break;
        }
        $strFile = $this->sanatize_filename($cfgName).".cfg";

        // If a database error has occurred break here
        if ($ccm->db->strDBError != "") {
            $this->strDBMessage = _('Cannot open/overwrite the configuration file (check the permissions)!');
            return(1);
        }

        // Relations take
        $ccm->data->tableRelations($strTableName, $arrRelations);

        // Backup Configuration
        if ($intMode == 0) {
            
            // Configuration data fetch
            $booReturn = $this->getConfigData("method",$strMethod);
            if ($strMethod == 1) {              
                // Configuration file open
                if (is_writable($strBaseDir."/".$strFile) || (!file_exists($strBaseDir."/".$strFile))) {
                    $CONFIGFILE = fopen($strBaseDir."/".$strFile, "w");
                    @chmod($strBaseDir."/".$strFile, 0664); // Try to chmod (not a big deal if it can't)
                } else {
                    $ccm->data->writeLog(_('Configuration write failed:')." ".$strFile);
                    $this->strDBMessage = _('Cannot open/overwrite the configuration file (check the permissions)!');
                    return(1);
                }
            } 
        }

        // See all matching records to fetch
        $booReturn = $ccm->db->getDataArray($strSQLData, $arrDataConfig, $intDataCountConfig);

        $this->getConfigData("version", $strVersionValue);
        $tpl = new Template($setTemplate);

        // If the record was not found...
        if ($booReturn == false) {
            $this->strDBMessage = _('Error while selecting data from database:')."<br>".$ccm->db->strDBError."<br>";
        }
        // If the record has been found
        else if ($intDataCountConfig != 0) {

            // Process each record...
            for ($y=0; $y < $intDataCountConfig; $y++) {

                // Add config_name value for array-version of the output
                if ($intMode == 2 && $strTableName == 'tbl_service') {
                    $tpl->add_option('config_name', $cfgName);
                }

                // Default: active records.
                switch ($filter) {
                    case 'all':
                        // Nothing to do.
                        break;

                    case 'inactive':
                        if ($arrDataConfig[$y]['active'] == "1") { continue 2; }
                        break;

                    // Not strictly necessary, but makes sure the classic "default" is honored.
                    case 'active':
                    default:
                        if ($arrDataConfig[$y]['active'] == "0") { continue 2; }
                        break;
                }

                // XI Mod - Move template to first variable to print
                $x = 0;
                foreach($arrDataConfig as $configdata) {
                    $tmparr = array();
                    if (array_key_exists("id", $configdata))
                        $tmparr["id"] = $configdata["id"];
                    if (array_key_exists("host_name", $configdata))
                        $tmparr["host_name"] = $configdata["host_name"];
                    if (array_key_exists("service_description", $configdata))
                        $tmparr["service_description"] = $configdata["service_description"];
                    if (array_key_exists("use_template", $configdata))
                        $tmparr["use_template"] = $configdata["use_template"];
                    if (array_key_exists("use_template_tploptions", $configdata))
                        $tmparr["use_template_tploptions"] = $configdata["use_template_tploptions"];
                    foreach ($configdata as $var => $val) {
                        if ($var=="id" || $var=="host_name" || $var=="service_description" || $var=="use_template" || $var=="use_template_tploptions")
                            continue;
                        $tmparr[$var] = $val;
                    }
                    $arrDataConfig[$x] = $tmparr;
                    $x++;
                }

                foreach ($arrDataConfig[$y] AS $key => $value) {
                    $intSkip = 0;
                    if ($key == "id") $intDataId = $value;
                    
                    // Special fields data skip
                    $strSpecial = "id,config_name,active,last_modified,access_rights,config_id,template,nodelete,command_type";
                    if ($strTableName == "tbl_host") $strSpecial .= ",parents_tploptions,hostgroups_tploptions,contacts_tploptions,contact_groups_tploptions,use_template_tploptions";
                    if ($strTableName == "tbl_service") $strSpecial .= ",host_name_tploptions,hostgroup_name_tploptions,servicegroups_tploptions,contacts_tploptions,contact_groups_tploptions,use_template_tploptions";

                    // Depending on the version skip other fields
                    if ($strVersionValue == 3) {
                        if ($strTableName == "tbl_service") $strSpecial .= ",parallelize_check";
                    }
                    if ($strVersionValue == 1) {
                        $strSpecial .= "";
                    }
                    $arrSpecial = explode(",", $strSpecial);
                    if (($value == "") || (in_array($key, $arrSpecial))) {
                        continue;
                    }

                    // Not all configuration data to write
                    $strNoTwo = "active_checks_enabled,passive_checks_enabled,obsess_over_host,check_freshness,event_handler_enabled,flap_detection_enabled,process_perf_data,retain_status_information,retain_nonstatus_information,notifications_enabled,is_volatile,parallelize_check,obsess_over_service";
                    $booTest = 0;
                    foreach(explode(",", $strNoTwo) AS $elem){
                        if (($key == $elem) && ($value == "2")) $booTest = 1;
                    }

                    if ($booTest == 1) continue;
                    
                    // Is the data field is connected via a relationship with another data field? 
                    if (is_array($arrRelations)) {
                        foreach ($arrRelations AS $elem) {
                            if ($elem['fieldName'] == $key) {

                                // Is this a normal relation 1: n
                                if (($elem['type'] == 2) && ($value == 1)) {

                                    $exclude = '';
                                    if ($strTableName == 'tbl_service') {
                                        if ($elem['target'] == 'host_name' || $elem['target'] == "hostgroup_name") {
                                            $exclude = ', `exclude`';
                                        }
                                    }

                                    $strSQLRel = "SELECT `".$elem['tableName']."`.`".$elem['target']."`".$exclude." FROM `".$elem['linktable']."`
                                                  LEFT JOIN `".$elem['tableName']."` ON `".$elem['linktable']."`.`idSlave` = `".$elem['tableName']."`.`id`
                                                  WHERE `idMaster`=".$arrDataConfig[$y]['id']."
                                                  ORDER BY `".$elem['tableName']."`.`".$elem['target']."`";
                                    $booReturn = $ccm->db->getDataArray($strSQLRel, $arrDataRel, $intDataCountRel);

                                    // Records were found?
                                    if ($intDataCountRel != 0) {
                                        // Is this a normal 1: n relation with special table?
                                        $value = array();
                                        foreach ($arrDataRel AS $data) {

                                            $tmp = trim($data[$elem['target']]);
                                            if ($elem['target'] == 'host_name' || $elem['target'] == "hostgroup_name") {
                                                if (!empty($data['exclude'])) {
                                                    $tmp = '!'.$tmp;
                                                }
                                            }

                                            $value[] = $tmp;
                                        }
                                        if ($intMode != 2) {
                                            $value = implode(',', $value);
                                        }
                                    } else {
                                        $intSkip = 1;
                                    }
                                }
                                // Is this a normal 1:1 ratio?
                                else if ($elem['type'] == 1) {
                                    if ($elem['tableName'] == "tbl_command") {
                                        $arrField = explode("!", $arrDataConfig[$y][$elem['fieldName']]);
                                        $strCommand = strchr($arrDataConfig[$y][$elem['fieldName']], "!");
                                        $strSQLRel  = "SELECT `".$elem['target']."` FROM `".$elem['tableName']."` WHERE `id`=".$arrField[0];
                                    } else {
                                        $strSQLRel  = "SELECT `".$elem['target']."` FROM `".$elem['tableName']."` WHERE `id`=".$arrDataConfig[$y][$elem['fieldName']];
                                    }
                                    $booReturn = $ccm->db->getDataArray($strSQLRel, $arrDataRel, $intDataCountRel);

                                    // Found records?
                                    if ($booReturn && ($intDataCountRel != 0)) {
                                        // Value data field of the found record entry
                                        if ($elem['tableName'] == "tbl_command") {
                                            $value = $arrDataRel[0][$elem['target']].$strCommand;
                                        } else {
                                            $value = $arrDataRel[0][$elem['target']];
                                        }
                                    } else {
                                        $intSkip = 1;
                                    }
                                } 
                                // Is this a normal 1: n relationship with a special table?
                                else if (($elem['type'] == 3) && ($value == 1)) {
                                    $strSQLMaster = "SELECT * FROM `".$elem['linktable']."` WHERE `idMaster` = ".$arrDataConfig[$y]['id']." ORDER BY `idSort`";
                                    $booReturn = $ccm->db->getDataArray($strSQLMaster, $arrDataMaster, $intDataCountMaster);

                                    // Found records?
                                    if ($intDataCountMaster != 0) {
                                        // Is this a normal 1: n relation with special table?
                                        $value = array();
                                        foreach ($arrDataMaster AS $data) {
                                            if ($data['idTable'] == 1) {
                                                $strSQLName = "SELECT `".$elem['target1']."` FROM `".$elem['tableName1']."` WHERE `id` = ".$data['idSlave'];
                                            } else {
                                                $strSQLName = "SELECT `".$elem['target2']."` FROM `".$elem['tableName2']."` WHERE `id` = ".$data['idSlave'];
                                            }
                                            $value[] = $ccm->db->getFieldData($strSQLName);
                                        }
                                        if ($intMode != 2) {
                                            $value = implode(',', $value);
                                        }
                                    } else {
                                        $intSkip = 1;
                                    }
                                }
                                // If it is a special relation to free variables?
                                else if (($elem['type'] == 4) && ($value == 1)) {
                                    $strSQLVar = "SELECT * FROM `tbl_variabledefinition` LEFT JOIN `".$elem['linktable']."` ON `id` = `idSlave` WHERE `idMaster`=".$arrDataConfig[$y]['id']." ORDER BY `name`";
                                    $booReturn = $ccm->db->getDataArray($strSQLVar, $arrDSVar, $intDCVar);
                                    if ($intDCVar != 0) {
                                        foreach ($arrDSVar AS $vardata) {
                                            $tpl->add_option($vardata['name'], $vardata['value']);
                                        }
                                    }
                                    $intSkip = 1;
                                }
                                // If it is the exceptional value "*"?
                                else if ($value == 2) {

                                    $value = "*";

                                    // If it's a service, and it is hostgroups, check for excludes
                                    if ($strTableName == 'tbl_service') {
                                        if ($elem['target'] == 'host_name' || $elem['target'] == "hostgroup_name") {

                                            $strSQLRel = "SELECT `".$elem['tableName']."`.`".$elem['target']."` FROM `".$elem['linktable']."`
                                                          LEFT JOIN `".$elem['tableName']."` ON `".$elem['linktable']."`.`idSlave` = `".$elem['tableName']."`.`id`
                                                          WHERE `idMaster`=".$arrDataConfig[$y]['id']." AND exclude = 1
                                                          ORDER BY `".$elem['tableName']."`.`".$elem['target']."`";
                                            $booReturn = $ccm->db->getDataArray($strSQLRel, $arrDataRel, $intDataCountRel);

                                            if ($intDataCountRel != 0) {
                                                $objs = array();
                                                foreach ($arrDataRel AS $data) {
                                                    $objs[] = '!'.$data[$elem['target']];
                                                }
                                                $value .= ','.implode(',', $objs);
                                            }
                                        }
                                    }

                                } else {
                                    $intSkip = 1;
                                }
                            }
                        }
                    }

                    // Rename host fields
                    if ($strTableName == "tbl_host") {
                        if ($key == "use_template") $key = "use";
                        $strVIValues = "active_checks_enabled,passive_checks_enabled,check_freshness,obsess_over_host,event_handler_enabled,";
                        $strVIValues .= "flap_detection_enabled,process_perf_data,retain_status_information,retain_nonstatus_information,";
                        $strVIValues .= "notifications_enabled";
                        if (in_array($key, explode(",", $strVIValues))) {
                            if ($value == -1) $value = "null";
                            if ($value == 3) $value = "null";
                        }
                        if ($key == "parents") $value = $this->checkTpl($value, "parents_tploptions", "tbl_host", $intDataId, $intSkip, $intMode);
                        if ($key == "hostgroups") $value = $this->checkTpl($value, "hostgroups_tploptions", "tbl_host", $intDataId, $intSkip, $intMode);
                        if ($key == "contacts") $value = $this->checkTpl($value, "contacts_tploptions", "tbl_host", $intDataId, $intSkip, $intMode);
                        if ($key == "contact_groups") $value = $this->checkTpl($value, "contact_groups_tploptions", "tbl_host", $intDataId, $intSkip, $intMode);
                        if ($key == "use") $value = $this->checkTpl($value, "use_template_tploptions", "tbl_host", $intDataId, $intSkip, $intMode);
                    }

                    // Rename service fields
                    if ($strTableName == "tbl_service") {
                        if ($key == "use_template") $key = "use";
                        if (($strVersionValue != 3) && ($strVersionValue != 2)) {
                            if ($key == "check_interval") $key = "normal_check_interval";
                            if ($key == "retry_interval") $key = "retry_check_interval";
                        }
                        $strVIValues = "is_volatile,active_checks_enabled,passive_checks_enabled,parallelize_check,obsess_over_service,";
                        $strVIValues .= "check_freshness,event_handler_enabled,flap_detection_enabled,process_perf_data,retain_status_information,";
                        $strVIValues .= "retain_nonstatus_information,notifications_enabled";
                        if (in_array($key, explode(",", $strVIValues))) {
                            if ($value == -1) $value = "null";
                            if ($value == 3) $value = "null";
                        }
                        if ($key == "host_name") $value = $this->checkTpl($value, "host_name_tploptions", "tbl_service", $intDataId, $intSkip, $intMode);
                        if ($key == "hostgroup_name") $value = $this->checkTpl($value, "hostgroup_name_tploptions", "tbl_service", $intDataId, $intSkip, $intMode);
                        if ($key == "servicegroups") $value = $this->checkTpl($value, "servicegroups_tploptions", "tbl_service", $intDataId, $intSkip, $intMode);
                        if ($key == "contacts") $value = $this->checkTpl($value, "contacts_tploptions", "tbl_service", $intDataId, $intSkip, $intMode);
                        if ($key == "contact_groups") $value = $this->checkTpl($value, "contact_groups_tploptions", "tbl_service", $intDataId, $intSkip, $intMode);
                        if ($key == "use") $value = $this->checkTpl($value, "use_template_tploptions", "tbl_service", $intDataId, $intSkip, $intMode);
                    }

                    // If the data field should not be skipped
                    if ($intSkip != 1) {
                        // Remove ; replacing with valid encoded char values
                        $value = str_replace(array('\;', ';'), array(';', '\;'), $value);

                        // Key and value to write to template and call next line
                        $tpl->add_option($key, $value);
                    }
                }

                // Is the configuration active?
                $tpl->add_option("register", $arrDataConfig[$y]["active"]);
                $tpl->add_object();
            }
        }

        // Return a special version that is only an array
        if ($intMode == 2) {
            $tpl->add_object();

            $objs = array();
            foreach ($tpl->objects as $object) {
                $tmp = array();
                foreach ($object as $o) {
                    $tmp[$o['option']] = $o['value'];
                }
                $objs[] = $tmp;
            }

            return $objs;
        }

        $cfg_file = $tpl->parse();

        // According to the write mode, the output in the configuration file or directly print
        if ($intMode == 0) {
            fwrite($CONFIGFILE, $cfg_file);
            fclose($CONFIGFILE);
            $this->strDBMessage = _('Configuration file successfully written!');
            $return = 0;
        } else if ($intMode == 1) {
            print $cfg_file;
            $return = 0;
        }
        
        return $return;
    }

    // Sanatizes filename so that / can be used
    /**
     * @param $filename
     *
     * @return mixed
     */
    public function sanatize_filename($filename) {
        $search = array("/");
        return str_replace($search, "_", $filename);
    }
}