<?php

/*
 * Copyright 2005 - 2025 Centreon (https://www.centreon.com/)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * For more information : contact@centreon.com
 *
 */

require_once _CENTREON_PATH_ . '/www/class/centreonDB.class.php';
require_once _CENTREON_PATH_ . '/www/class/centreonExternalCommand.class.php';
require_once __DIR__ . '/centreon_configuration_objects.class.php';

/**
 * Class
 *
 * @class CentreonMonitoringExternalcmd
 */
class CentreonMonitoringExternalcmd extends CentreonConfigurationObjects
{
    /** @var CentreonDB */
    protected $pearDBMonitoring;

    /** @var string */
    protected $centcore_file;

    /**
     * CentreonMonitoringExternalcmd constructor
     */
    public function __construct()
    {
        parent::__construct();
        $this->pearDBMonitoring = new CentreonDB('centstorage');
        if (is_dir(_CENTREON_VARLIB_ . '/centcore')) {
            $this->centcore_file = _CENTREON_VARLIB_ . '/centcore/' . microtime(true) . '-externalcommand.cmd';
        } else {
            $this->centcore_file = _CENTREON_VARLIB_ . '/centcore.cmd';
        }
    }

    /**
     * @throws PDOException
     * @throws RestBadRequestException
     * @throws RestException
     * @throws RestUnauthorizedException
     * @return array
     */
    public function postSend()
    {
        global $centreon;

        if (
            isset($this->arguments['commands'])
            && is_array($this->arguments['commands'])
            && count($this->arguments['commands'])
        ) {
            // Get poller Listing
            $query = 'SELECT id '
                . 'FROM nagios_server '
                . 'WHERE ns_activate = "1"';

            $dbResult = $this->pearDB->query($query);
            $pollers = [];

            while ($row = $dbResult->fetch(PDO::FETCH_ASSOC)) {
                $pollers[$row['id']] = 1;
            }

            $externalCommand = new CentreonExternalCommand();
            $availableCommands = [];

            /**
             * We need to make the concordance between the data saved in the database
             * and the action provided by the user.
             */
            foreach ($externalCommand->getExternalCommandList() as $key => $cmd) {
                foreach ($cmd as $c) {
                    $availableCommands[$c] = $key;
                }
            }

            $isAdmin = $centreon->user->admin;

            /**
             * If user is not admin we need to retrieve its ACL
             */
            if (! $isAdmin) {
                $userAcl = new CentreonACL($centreon->user->user_id, $isAdmin);
            }

            if ($fh = @fopen($this->centcore_file, 'a+')) {
                foreach ($this->arguments['commands'] as $command) {
                    $commandSplitted = explode(';', $command['command']);
                    $action = $commandSplitted[0];
                    if (! $isAdmin) {
                        if (preg_match('/HOST(_SVC)?/', $action, $matches)) {
                            if (! isset($commandSplitted[1])) {
                                throw new RestBadRequestException(_('Host not found'));
                            }
                            $query = 'SELECT acl.host_id
                                FROM centreon_acl acl, hosts h
                                WHERE acl.host_id = h.host_id
                                AND acl.service_id IS NULL
                                AND h.name = ?
                                AND acl.group_id IN (' . $userAcl->getAccessGroupsString() . ')';
                            $result = $this->pearDBMonitoring->prepare($query);
                            $result->execute([$commandSplitted[1]]);
                            if ($result->fetch() === false) {
                                throw new RestBadRequestException(_('Host not found'));
                            }
                        } elseif (preg_match('/(?!HOST_)SVC/', $action, $matches)) {
                            if (! isset($commandSplitted[1]) || ! isset($commandSplitted[2])) {
                                throw new RestBadRequestException(_('Service not found'));
                            }
                            $query = 'SELECT acl.service_id
                                FROM centreon_acl acl, hosts h, services s
                                WHERE h.host_id = s.host_id
                                AND acl.host_id = s.host_id
                                AND acl.service_id = s.service_id
                                AND h.name = :hostName
                                AND s.description = :serviceDescription
                                AND acl.group_id IN (' . $userAcl->getAccessGroupsString() . ')';

                            $statement = $this->pearDBMonitoring->prepare($query);
                            $statement->bindValue(':hostName', $commandSplitted[1], PDO::PARAM_STR);
                            $statement->bindValue(':serviceDescription', $commandSplitted[2], PDO::PARAM_STR);
                            $statement->execute();
                            if ($statement->fetch() === false) {
                                throw new RestBadRequestException(_('Service not found'));
                            }
                        }
                    }

                    // checking that action provided exists
                    if (! array_key_exists($action, $availableCommands)) {
                        throw new RestBadRequestException('Action ' . $action . ' not supported');
                    }

                    if (! $isAdmin) {
                        // Checking that the user has rights to do the action provided
                        if ($userAcl->checkAction($availableCommands[$action]) === 0) {
                            throw new RestUnauthorizedException(
                                'User is not allowed to execute ' . $action . ' action'
                            );
                        }
                    }

                    if (isset($pollers[$command['poller_id']])) {
                        fwrite(
                            $fh,
                            'EXTERNALCMD:' . $command['poller_id'] . ':['
                            . $command['timestamp'] . '] ' . $command['command'] . "\n"
                        );
                    }
                }
                fclose($fh);

                return ['success' => true];
            }

            throw new RestException('Cannot open Centcore file');
        } else {
            throw new RestBadRequestException('Bad arguments - Cannot find command list');
        }
    }
}
