Ganteng Doang Upload Shell Gak Bisa


Linux server.jmdstrack.com 3.10.0-1160.119.1.el7.tuxcare.els10.x86_64 #1 SMP Fri Oct 11 21:40:41 UTC 2024 x86_64
/ home/ jmdstrac/ public_html/ devices/ src/

/home/jmdstrac/public_html/devices/src/CronTask.php

<?php

/**
 * ---------------------------------------------------------------------
 *
 * GLPI - Gestionnaire Libre de Parc Informatique
 *
 * http://glpi-project.org
 *
 * @copyright 2015-2023 Teclib' and contributors.
 * @copyright 2003-2014 by the INDEPNET Development Team.
 * @licence   https://www.gnu.org/licenses/gpl-3.0.html
 *
 * ---------------------------------------------------------------------
 *
 * LICENSE
 *
 * This file is part of GLPI.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 * ---------------------------------------------------------------------
 */

// Needed for signal handler
declare(ticks=1);

use Glpi\Event;

/**
 * CronTask class
 */
class CronTask extends CommonDBTM
{
   // From CommonDBTM
    public $dohistory                   = true;

   // Specific ones
    private static $lockname = '';
    private $timer           = 0.0;
    private $startlog        = 0;
    private $volume          = 0;
    public static $rightname        = 'config';

   // Class constant
    const STATE_DISABLE = 0;
    const STATE_WAITING = 1;
    const STATE_RUNNING = 2;

    const MODE_INTERNAL = 1;
    const MODE_EXTERNAL = 2;


    public static function getForbiddenActionsForMenu()
    {
        return ['add'];
    }


    public function getForbiddenStandardMassiveAction()
    {

        $forbidden   = parent::getForbiddenStandardMassiveAction();
        $forbidden[] = 'delete';
        $forbidden[] = 'purge';
        $forbidden[] = 'restore';
        return $forbidden;
    }


    public static function getTypeName($nb = 0)
    {
        return _n('Automatic action', 'Automatic actions', $nb);
    }


    public function defineTabs($options = [])
    {

        $ong = [];
        $this->addDefaultFormTab($ong);
        $this->addImpactTab($ong, $options);
        $this->addStandardTab('CronTaskLog', $ong, $options);
        $this->addStandardTab('Log', $ong, $options);

        return $ong;
    }


    public static function canDelete()
    {
        return false;
    }


    public function cleanDBonPurge()
    {

       // CronTaskLog does not extends CommonDBConnexity
        $ctl = new CronTaskLog();
        $ctl->deleteByCriteria(['crontasks_id' => $this->fields['id']]);
    }


    /**
     * Read a CronTask by its name
     *
     * Used by plugins to load its crontasks
     *
     * @param string $itemtype  itemtype of the crontask
     * @param string $name      name of the task
     *
     * @return boolean true if succeed else false
     **/
    public function getFromDBbyName($itemtype, $name)
    {

        return $this->getFromDBByCrit([
            $this->getTable() . '.name'      => (string)$name,
            $this->getTable() . '.itemtype'  => (string)$itemtype
        ]);
    }


    /**
     * Give a task state
     *
     * @return integer 0 : task is enabled
     *    if disable : 1: by config, 2: by system lock, 3: by plugin
     **/
    public function isDisabled()
    {

        if ($this->fields['state'] == self::STATE_DISABLE) {
            return 1;
        }

        if (
            is_file(GLPI_CRON_DIR . '/all.lock')
            || is_file(GLPI_CRON_DIR . '/' . $this->fields['name'] . '.lock')
        ) {
           // Global lock
            return 2;
        }

        if (!($tab = isPluginItemType($this->fields['itemtype']))) {
            return 0;
        }

       // Plugin case
        $plug = new Plugin();
        if (!$plug->isActivated($tab["plugin"])) {
            return 3;
        }
        return 0;
    }

    /**
     * Get all itemtypes used
     *
     * @return string[]
     **/
    public static function getUsedItemtypes()
    {
        global $DB;

        $types = [];
        $iterator = $DB->request([
            'SELECT'          => 'itemtype',
            'DISTINCT'        => true,
            'FROM'            => 'glpi_crontasks'
        ]);
        foreach ($iterator as $data) {
            $types[] = $data['itemtype'];
        }
        return $types;
    }

    /**
     * Signal handler callback
     *
     * @param integer $signo Signal number
     * @since 9.1
     */
    public function signal($signo)
    {
        if ($signo == SIGTERM) {
            pcntl_signal(SIGTERM, SIG_DFL);

           // End of this task
            $this->end(null);

           // End of this cron
            $_SESSION["glpicronuserrunning"] = '';
            self::release_lock();
            Toolbox::logInFile('cron', __('Action aborted') . "\n");
            exit;
        }
    }

    /**
     * Start a task, timer, stat, log, ...
     *
     * @return bool : true if ok (not start by another)
     **/
    public function start()
    {
        global $DB;

        if (!isset($this->fields['id']) || ($DB->isSlave())) {
            return false;
        }

        if (isCommandLine() && function_exists('pcntl_signal')) {
            pcntl_signal(SIGTERM, [$this, 'signal']);
        }

        $result = $DB->update(
            $this->getTable(),
            [
                'state'  => self::STATE_RUNNING,
                'lastrun'   => new \QueryExpression('DATE_FORMAT(NOW(),\'%Y-%m-%d %H:%i:00\')')
            ],
            [
                'id'  => $this->fields['id'],
                'NOT' => ['state' => self::STATE_RUNNING]
            ]
        );

        if ($DB->affectedRows($result) > 0) {
            $this->timer  = microtime(true);
            $this->volume = 0;
            $log = new CronTaskLog();
            // No gettext for log
            $txt = sprintf(
                '%1$s: %2$s',
                'Run mode',
                $this->getModeName(isCommandLine() ? self::MODE_EXTERNAL
                : self::MODE_INTERNAL)
            );

            $this->startlog = $log->add(['crontasks_id'    => $this->fields['id'],
                'date'            => $_SESSION['glpi_currenttime'],
                'content'         => addslashes($txt),
                'crontasklogs_id' => 0,
                'state'           => CronTaskLog::STATE_START,
                'volume'          => 0,
                'elapsed'         => 0
            ]);
            return true;
        }
        return false;
    }


    /**
     * Set the currently proccessed volume of a running task
     *
     * @param $volume
     **/
    public function setVolume($volume)
    {
        $this->volume = $volume;
    }


    /**
     * Increase the currently proccessed volume of a running task
     *
     * @param $volume
     **/
    public function addVolume($volume)
    {
        $this->volume += $volume;
    }


    /**
     * End a task, timer, stat, log, ...
     *
     * @param int|null $retcode
     *    <0: need to run again
     *    0 : nothing to do
     *    >0: ok
     * @param int $log_state
     *
     * @return bool : true if ok (not start by another)
     *
     * @since 9.5.5 Added parameter $log_state.
     **/
    public function end($retcode, int $log_state = CronTaskLog::STATE_STOP)
    {
        global $DB;

        if (!isset($this->fields['id'])) {
            return false;
        }

        $result = $DB->update(
            $this->getTable(),
            [
                'state'  => $this->fields['state']
            ],
            [
                'id'     => $this->fields['id'],
                'state'  => self::STATE_RUNNING
            ]
        );

        if ($DB->affectedRows($result) > 0) {
           // No gettext for log but add gettext line to be parsed for pot generation
           // order is important for insertion in english in the database
            if ($log_state === CronTaskLog::STATE_ERROR) {
                $content = __('Execution error');
                $content = 'Execution error';
            } else if (is_null($retcode)) {
                $content = __('Action aborted');
                $content = 'Action aborted';
            } else if ($retcode < 0) {
                $content = __('Action completed, partially processed');
                $content = 'Action completed, partially processed';
            } else if ($retcode > 0) {
                $content = __('Action completed, fully processed');
                $content = 'Action completed, fully processed';
            } else {
                $content = __('Action completed, no processing required');
                $content = 'Action completed, no processing required';
            }

            $log = new CronTaskLog();
            $log->add(['crontasks_id'    => $this->fields['id'],
                'date'            => $_SESSION['glpi_currenttime'],
                'content'         => $content,
                'crontasklogs_id' => $this->startlog,
                'state'           => $log_state,
                'volume'          => $this->volume,
                'elapsed'         => (microtime(true) - $this->timer)
            ]);
            return true;
        }
        return false;
    }


    /**
     * Add a log message for a running task
     *
     * @param string $content
     **/
    public function log($content)
    {

        if (!isset($this->fields['id'])) {
            return false;
        }
        $log     = new CronTaskLog();
        $content = Toolbox::substr($content, 0, 200);
        return $log->add(['crontasks_id'    => $this->fields['id'],
            'date'            => $_SESSION['glpi_currenttime'],
            'content'         => addslashes($content),
            'crontasklogs_id' => $this->startlog,
            'state'           => CronTaskLog::STATE_RUN,
            'volume'          => $this->volume,
            'elapsed'         => (microtime(true) - $this->timer)
        ]);
    }


    /**
     * read the first task which need to be run by cron
     *
     * @param integer $mode >0 retrieve task configured for this mode
     *                      <0 retrieve task allowed for this mode (force, no time check)
     * @param string $name  one specify action
     *
     * @return boolean false if no task to run
     **/
    public function getNeedToRun($mode = 0, $name = '')
    {
        global $DB;

        $hour_criteria = new QueryExpression('hour(curtime())');

        $itemtype_orwhere = [
         // Core crontasks
            [
                ['NOT' => ['itemtype' => ['LIKE', 'Plugin%']]],
                ['NOT' => ['itemtype' => ['LIKE', addslashes('GlpiPlugin\\\\') . '%']]]
            ]
        ];
        foreach (Plugin::getPlugins() as $plug) {
           // Activated plugin tasks
            $itemtype_orwhere[] = [
                'OR' => [
                    ['itemtype' => ['LIKE', sprintf('Plugin%s', $plug) . '%']],
                    ['itemtype' => ['LIKE', addslashes(sprintf('GlpiPlugin\\\\%s\\\\', $plug)) . '%']]
                ]
            ];
        }

        $WHERE = [
            ['OR' => $itemtype_orwhere]
        ];

        if ($name) {
            $WHERE['name'] = addslashes($name);
        }

       // In force mode
        if ($mode < 0) {
            $WHERE['state'] = ['!=', self::STATE_RUNNING];
            $WHERE['allowmode'] = ['&', (int)$mode * -1];
        } else {
            $WHERE['state'] = self::STATE_WAITING;
            if ($mode > 0) {
                $WHERE['mode'] = $mode;
            }

           // Get system lock
            if (is_file(GLPI_CRON_DIR . '/all.lock')) {
               // Global lock
                return false;
            }
            $locks = [];
            foreach (glob(GLPI_CRON_DIR . '/*.lock') as $lock) {
                $reg = [];
                if (preg_match('!.*/(.*).lock$!', $lock, $reg)) {
                    $locks[] = $reg[1];
                }
            }
            if (count($locks)) {
                $WHERE[] = ['NOT' => ['name' => $locks]];
            }

           // Build query for frequency and allowed hour
            $WHERE[] = ['OR' => [
                ['AND' => [
                    ['hourmin'   => ['<', new QueryExpression($DB->quoteName('hourmax'))]],
                    'hourmin'   => ['<=', $hour_criteria],
                    'hourmax'   => ['>', $hour_criteria]
                ]
                ],
                ['AND' => [
                    'hourmin'   => ['>', new QueryExpression($DB->quoteName('hourmax'))],
                    'OR'        => [
                        'hourmin'   => ['<=', $hour_criteria],
                        'hourmax'   => ['>', $hour_criteria]
                    ]
                ]
                ]
            ]
            ];
            $WHERE[] = ['OR' => [
                'lastrun'   => null,
                new \QueryExpression('unix_timestamp(' . $DB->quoteName('lastrun') . ') + ' . $DB->quoteName('frequency') . ' <= unix_timestamp(now())')
            ]
            ];
        }

        $iterator = $DB->request([
            'SELECT' => [
                '*',
                new \QueryExpression("LOCATE('Plugin', " . $DB->quoteName('itemtype') . ") AS ISPLUGIN")
            ],
            'FROM'   => $this->getTable(),
            'WHERE'  => $WHERE,
         // Core task before plugins
            'ORDER'  => [
                'ISPLUGIN',
                new \QueryExpression('unix_timestamp(' . $DB->quoteName('lastrun') . ')+' . $DB->quoteName('frequency') . '')
            ]
        ]);

        if (count($iterator)) {
            $this->fields = $iterator->current();
            return true;
        }
        return false;
    }

    /**
     * Send a notification on task error.
     */
    private function sendNotificationOnError(): void
    {
        global $DB;

        $alert_iterator = $DB->request(
            [
                'FROM'      => 'glpi_alerts',
                'WHERE'     => [
                    'items_id' => $this->fields['id'],
                    'itemtype' => 'CronTask',
                    'date'     => ['>', new QueryExpression('CURRENT_TIMESTAMP() - INTERVAL 1 day')],
                ],
            ]
        );
        if ($alert_iterator->count() > 0) {
           // An alert has been sent within last day, so do not send a new one to not bother administrator
            return;
        }

       // Check if errors threshold is exceeded, and send a notification in this case.
       //
       // We check on last "$threshold * 2" runs as a task that works only half of the time
       // is not a normal behaviour.
       // For instance, if threshold is 5, then a task that fails 5 times on last 10 executions
       // will trigger a notification.
        $threshold = 5;

        $iterator = $DB->request(
            [
                'FROM'   => 'glpi_crontasklogs',
                'WHERE'  => [
                    'crontasks_id' => $this->fields['id'],
                    'state'        => [CronTaskLog::STATE_STOP, CronTaskLog::STATE_ERROR],
                ],
                'ORDER'  => 'id DESC',
                'LIMIT'  => $threshold * 2
            ]
        );

        $error_count = 0;
        foreach ($iterator as $row) {
            if ($row['state'] === CronTaskLog::STATE_ERROR) {
                $error_count++;
            }
        }

        if ($error_count >= $threshold) {
           // No alert has been sent within last day, so we can send one without bothering administrator
            NotificationEvent::raiseEvent('alert', $this, ['items' => [$this->fields['id'] => $this->fields]]);
            QueuedNotification::forceSendFor($this->getType(), $this->fields['id']);

           // Delete existing outdated alerts
            $alert = new Alert();
            $alert->deleteByCriteria(['itemtype' => 'CronTask', 'items_id' => $this->fields['id']], 1);

           // Create a new alert
            $alert->add(
                [
                    'type'     => Alert::THRESHOLD,
                    'itemtype' => 'CronTask',
                    'items_id' => $this->fields['id'],
                ]
            );
        }
    }


    /**
     * Print the contact form
     *
     * @param integer $ID
     * @param array   $options
     *     - target filename : where to go when done.
     *     - withtemplate boolean : template or basic item
     *
     * @return boolean
     **/
    public function showForm($ID, array $options = [])
    {
        global $CFG_GLPI;

        if (!Config::canView() || !$this->getFromDB($ID)) {
            return false;
        }
        $options['candel'] = false;
        $this->showFormHeader($options);

        echo "<tr class='tab_bg_1'>";
        echo "<td>" . __('Name') . "</td>";
        echo "<td class ='b'>";
        $name = $this->fields["name"];
        if ($isplug = isPluginItemType($this->fields["itemtype"])) {
            $name = sprintf(__('%1$s - %2$s'), $isplug["plugin"], $name);
        }
        echo $name . "</td>";
        echo "<td rowspan='6' class='middle right'>" . __('Comments') . "</td>";
        echo "<td class='center middle' rowspan='6'>";
        echo "<textarea class='form-control' name='comment' >" . $this->fields["comment"] . "</textarea>";
        echo "</td></tr>";

        echo "<tr class='tab_bg_1'><td>" . __('Description') . "</td><td>";
        echo $this->getDescription($ID);
        echo "</td></tr>";

        echo "<tr class='tab_bg_1'><td>" . __('Run frequency') . "</td><td>";
        Dropdown::showFrequency('frequency', $this->fields["frequency"]);
        echo "</td></tr>";

        $tmpstate = $this->fields["state"];
        echo "<tr class='tab_bg_1'><td>" . __('Status') . "</td><td>";
        if (
            is_file(GLPI_CRON_DIR . '/' . $this->fields["name"] . '.lock')
            || is_file(GLPI_CRON_DIR . '/all.lock')
        ) {
            echo "<span class='b'>" . __('System lock') . "</span><br>";
            $tmpstate = self::STATE_DISABLE;
        }

        if ($isplug) {
            $plug = new Plugin();
            if (!$plug->isActivated($isplug["plugin"])) {
                echo "<span class='b'>" . __('Disabled plugin') . "</span><br>";
                $tmpstate = self::STATE_DISABLE;
            }
        }

        if ($this->fields["state"] == self::STATE_RUNNING) {
            echo "<span class='b'>" . $this->getStateName(self::STATE_RUNNING) . "</span>";
        } else {
            self::dropdownState('state', $this->fields["state"]);
        }
        echo "</td></tr>";

        echo "<tr class='tab_bg_1'><td>" . __('Run mode') . "</td><td>";
        $modes = [];
        if ($this->fields['allowmode'] & self::MODE_INTERNAL) {
            $modes[self::MODE_INTERNAL] = self::getModeName(self::MODE_INTERNAL);
        }
        if ($this->fields['allowmode'] & self::MODE_EXTERNAL) {
            $modes[self::MODE_EXTERNAL] = self::getModeName(self::MODE_EXTERNAL);
        }
        Dropdown::showFromArray('mode', $modes, ['value' => $this->fields['mode']]);
        echo "</td></tr>";

        echo "<tr class='tab_bg_1'><td>" . __('Run period') . "</td><td>";
        Dropdown::showNumber('hourmin', ['value' => $this->fields['hourmin'],
            'min'   => 0,
            'max'   => 24
        ]);
        echo "&nbsp;->&nbsp;";
        Dropdown::showNumber('hourmax', ['value' => $this->fields['hourmax'],
            'min'   => 0,
            'max'   => 24
        ]);
        echo "</td></tr>";

        echo "<tr class='tab_bg_1'><td>" . __('Number of days this action logs are stored') . "</td><td>";
        Dropdown::showNumber('logs_lifetime', ['value' => $this->fields['logs_lifetime'],
            'min'   => 10,
            'max'   => 360,
            'step'  => 10,
            'toadd' => [0 => __('Infinite')]
        ]);
        echo "</td><td>" . __('Last run') . "</td><td>";

        if (empty($this->fields['lastrun'])) {
            echo __('Never');
        } else {
            echo Html::convDateTime($this->fields['lastrun']);
            echo "&nbsp;";
            Html::showSimpleForm(
                static::getFormURL(),
                'resetdate',
                __('Blank'),
                ['id' => $ID],
                'fa-times-circle'
            );
        }
        echo "</td></tr>";

        $label = $this->getParameterDescription();
        echo "<tr class='tab_bg_1'><td>";
        if (empty($label)) {
            echo "&nbsp;</td><td>&nbsp;";
        } else {
            echo $label . "&nbsp;</td><td>";
            Dropdown::showNumber('param', ['value' => $this->fields['param'],
                'min'   => 0,
                'max'   => 10000
            ]);
        }
        echo "</td><td>" . __('Next run') . "</td><td>";

        if ($tmpstate == self::STATE_RUNNING) {
            $launch = false;
        } else {
            $launch = $this->fields['allowmode'] & self::MODE_INTERNAL;
        }

        if ($tmpstate != self::STATE_WAITING) {
            echo $this->getStateName($tmpstate);
        } else if (empty($this->fields['lastrun'])) {
            echo __('As soon as possible');
        } else {
            $next = strtotime($this->fields['lastrun']) + $this->fields['frequency'];
            $h    = date('H', $next);
            $deb  = ($this->fields['hourmin'] < 10 ? "0" . $this->fields['hourmin']
                                                : $this->fields['hourmin']);
            $fin  = ($this->fields['hourmax'] < 10 ? "0" . $this->fields['hourmax']
                                                : $this->fields['hourmax']);

            if (
                ($deb < $fin)
                && ($h < $deb)
            ) {
                $disp = date('Y-m-d', $next) . " $deb:00:00";
                $next = strtotime($disp);
            } else if (
                ($deb < $fin)
                    && ($h >= $this->fields['hourmax'])
            ) {
                $disp = date('Y-m-d', $next + DAY_TIMESTAMP) . " $deb:00:00";
                $next = strtotime($disp);
            }

            if (
                ($deb > $fin)
                && ($h < $deb)
                && ($h >= $fin)
            ) {
                $disp = date('Y-m-d', $next) . " $deb:00:00";
                $next = strtotime($disp);
            } else {
                $disp = date("Y-m-d H:i:s", $next);
            }

            if ($next < time()) {
                echo __('As soon as possible') . '<br>(' . Html::convDateTime($disp) . ') ';
            } else {
                echo Html::convDateTime($disp);
            }
        }

        if (isset($CFG_GLPI['maintenance_mode']) && $CFG_GLPI['maintenance_mode']) {
            echo "<div class='warning'>" .
              __('Maintenance mode enabled, running tasks is disabled') .
              "</div>";
        } else if ($launch) {
            echo "&nbsp;";
            Html::showSimpleForm(
                static::getFormURL(),
                ['execute' => $this->fields['name']],
                __('Execute')
            );
        }
        if ($tmpstate == self::STATE_RUNNING) {
            Html::showSimpleForm(
                static::getFormURL(),
                'resetstate',
                __('Blank'),
                ['id' => $ID],
                'fa-times-circle'
            );
        }
        echo "</td></tr>";

        $this->showFormButtons($options);

        return true;
    }


    /**
     * reset the next launch date => for a launch as soon as possible
     **/
    public function resetDate()
    {

        if (!isset($this->fields['id'])) {
            return false;
        }
        return $this->update(['id'      => $this->fields['id'],
            'lastrun' => 'NULL'
        ]);
    }


    /**
     * reset the current state
     **/
    public function resetState()
    {

        if (!isset($this->fields['id'])) {
            return false;
        }
        return $this->update(['id'    => $this->fields['id'],
            'state' => self::STATE_WAITING
        ]);
    }


    /**
     * Translate task description
     *
     * @param $id integer ID of the crontask
     *
     * @return string
     **/
    public function getDescription($id)
    {

        if (!isset($this->fields['id']) || ($this->fields['id'] != $id)) {
            $this->getFromDB($id);
        }

        $hook = [$this->fields['itemtype'], 'cronInfo'];
        if (is_callable($hook)) {
            $info = call_user_func($hook, $this->fields['name']);
        } else {
            $info = false;
        }

        if (isset($info['description'])) {
            return $info['description'];
        }

        return $this->fields['name'];
    }


    /**
     * Translate task parameter description
     *
     * @return string
     **/
    public function getParameterDescription()
    {

        $hook = [$this->fields['itemtype'], 'cronInfo'];

        if (is_callable($hook)) {
            $info = call_user_func($hook, $this->fields['name']);
        } else {
            $info = false;
        }

        if (isset($info['parameter'])) {
            return $info['parameter'];
        }

        return '';
    }


    /**
     * Translate state to string
     *
     * @param $state integer
     *
     * @return string
     **/
    public static function getStateName($state)
    {

        switch ($state) {
            case self::STATE_RUNNING:
                return __('Running');

            case self::STATE_WAITING:
                return __('Scheduled');

            case self::STATE_DISABLE:
                return __('Disabled');
        }

        return '???';
    }


    /**
     * Dropdown of state
     *
     * @param string  $name     select name
     * @param integer $value    default value
     * @param boolean $display  display or get string
     *
     * @return string|integer HTML output, or random part of dropdown ID.
     **/
    public static function dropdownState($name, $value = 0, $display = true)
    {

        return Dropdown::showFromArray(
            $name,
            [self::STATE_DISABLE => __('Disabled'),
                self::STATE_WAITING => __('Scheduled')
            ],
            ['value'   => $value,
                'display' => $display
            ]
        );
    }


    /**
     * Translate Mode to string
     *
     * @param $mode integer
     *
     * @return string
     **/
    public static function getModeName($mode)
    {

        switch ($mode) {
            case self::MODE_INTERNAL:
                return __('GLPI');

            case self::MODE_EXTERNAL:
                return __('CLI');
        }

        return '???';
    }


    /**
     * Get a global database lock for cron
     *
     * @return Boolean
     **/
    private static function get_lock()
    {
        global $DB;

       // Changer de nom toutes les heures en cas de blocage MySQL (ca arrive)
        $nom = "glpicron." . intval(time() / HOUR_TIMESTAMP - 340000);

        if ($DB->getLock($nom)) {
            self::$lockname = $nom;
            return true;
        }

        return false;
    }


    /**
     * Release the global database lock
     **/
    private static function release_lock()
    {
        global $DB;

        if (self::$lockname) {
            $DB->releaseLock(self::$lockname);
            self::$lockname = '';
        }
    }


    /**
     * Launch the need cron tasks
     *
     * @param integer $mode   (internal/external, <0 to force)
     * @param integer $max    number of task to launch
     * @param string  $name   name of task to run
     *
     * @return string|boolean the name of last task launched, or false if execution not available
     **/
    public static function launch($mode, $max = 1, $name = '')
    {
        global $CFG_GLPI;

       // No cron in maintenance mode
        if (isset($CFG_GLPI['maintenance_mode']) && $CFG_GLPI['maintenance_mode']) {
            Toolbox::logInFile('cron', __('Maintenance mode enabled, running tasks is disabled') . "\n");
            return false;
        }

        $crontask = new self();
        $taskname = '';
        if (abs($mode) == self::MODE_EXTERNAL) {
           // If cron is launched in command line, and if memory is insufficient,
           // display a warning in the logs
            if (Toolbox::checkMemoryLimit() == 2) {
                Toolbox::logInFile('cron', __('A minimum of 64 Mio is commonly required for GLPI.') . "\n");
            }
           // If no task in CLI mode, call cron.php from command line is not really usefull ;)
            if (!countElementsInTable($crontask->getTable(), ['mode' => abs($mode)])) {
                Toolbox::logInFile(
                    'cron',
                    __('No task with Run mode = CLI, fix your tasks configuration') . "\n"
                );
            }
        }

        if (self::get_lock()) {
            for ($i = 1; $i <= $max; $i++) {
                $msgprefix = sprintf(
                //TRANS: %1$s is mode (external or internal), %2$s is an order number,
                    __('%1$s #%2$s'),
                    abs($mode) == self::MODE_EXTERNAL ? __('External') : __('Internal'),
                    $i
                );
                if ($crontask->getNeedToRun($mode, $name)) {
                     $_SESSION["glpicronuserrunning"] = "cron_" . $crontask->fields['name'];

                     $function = sprintf('%s::cron%s', $crontask->fields['itemtype'], $crontask->fields['name']);

                    if (is_callable($function)) {
                        if ($crontask->start()) { // Lock in DB + log start
                            $taskname = $crontask->fields['name'];

                            Toolbox::logInFile(
                                'cron',
                                sprintf(
                                    __('%1$s: %2$s'),
                                    $msgprefix,
                                    sprintf(__('%1$s %2$s') . "\n", __('Launch'), $crontask->fields['name'])
                                )
                            );
                            try {
                                  $retcode = call_user_func($function, $crontask);
                            } catch (\Throwable $e) {
                                global $GLPI;
                                $GLPI->getErrorHandler()->handleException($e);
                                Toolbox::logInFile(
                                    'cron',
                                    sprintf(
                                        __('%1$s: %2$s'),
                                        $msgprefix,
                                        sprintf(
                                            __('Error during %s execution. Check in "%s" for more details.') . "\n",
                                            $crontask->fields['name'],
                                            GLPI_LOG_DIR . '/php-errors.log'
                                        )
                                    )
                                );
                                $retcode = null;
                                $crontask->end(null, CronTaskLog::STATE_ERROR);
                                $crontask->sendNotificationOnError();
                                continue;
                            }
                             $crontask->end($retcode); // Unlock in DB + log end
                        } else {
                            Toolbox::logInFile(
                                'cron',
                                sprintf(
                                    __('%1$s: %2$s'),
                                    $msgprefix,
                                    sprintf(__('%1$s %2$s') . "\n", __("Can't start"), $crontask->fields['name'])
                                )
                            );
                        }
                    } else {
                        $undefined_msg = sprintf(__('Undefined function %s (for cron)') . "\n", $function);
                        Toolbox::logInFile('php-errors', $undefined_msg);
                        Toolbox::logInFile(
                            'cron',
                            sprintf(
                                __('%1$s: %2$s'),
                                $msgprefix,
                                sprintf(__('%1$s %2$s') . "\n", __("Can't start"), $crontask->fields['name'])
                            ) . "\n" . $undefined_msg
                        );
                    }
                } else if ($i == 1) {
                    $msgcron = sprintf(__('%1$s: %2$s'), $msgprefix, __('Nothing to launch'));
                    Toolbox::logInFile('cron', $msgcron . "\n");
                }
            }
            $_SESSION["glpicronuserrunning"] = '';
            self::release_lock();
        } else {
            Toolbox::logInFile('cron', __("Can't get DB lock") . "\n");
        }

        return $taskname;
    }


    /**
     * Register new task for plugin (called by plugin during install)
     *
     * @param string  $itemtype  itemtype of the plugin object
     * @param string  $name      task name
     * @param integer $frequency execution frequency
     * @param array   $options   optional options
     *       (state, mode, allowmode, hourmin, hourmax, logs_lifetime, param, comment)
     *
     * @return boolean
     **/
    public static function register($itemtype, $name, $frequency, $options = [])
    {

       // Check that hook exists
        if (!isPluginItemType($itemtype) && !class_exists($itemtype)) {
            return false;
        }

       // manage NS class
        $itemtype = addslashes($itemtype);

        $temp = new self();
       // Avoid duplicate entry
        if ($temp->getFromDBbyName($itemtype, $name)) {
            return false;
        }
        $input = [
            'itemtype'  => $itemtype,
            'name'      => $name,
            'allowmode' => self::MODE_INTERNAL | self::MODE_EXTERNAL,
            'frequency' => $frequency
        ];

        foreach (
            ['allowmode', 'comment', 'hourmax', 'hourmin', 'logs_lifetime', 'mode',
                'param', 'state'
            ] as $key
        ) {
            if (isset($options[$key])) {
                $input[$key] = $options[$key];
            }
        }
        if (
            defined('GLPI_SYSTEM_CRON')
            && ($input['allowmode'] & self::MODE_EXTERNAL)
            && !isset($input['mode'])
        ) {
           // Downstream packages may provide a good system cron
            $input['mode'] = self::MODE_EXTERNAL;
        }
        return $temp->add($input);
    }


    /**
     * Unregister tasks for a plugin (call by glpi after uninstall)
     *
     * @param $plugin : name of the plugin
     *
     * @return bool for success
     **/
    public static function unregister($plugin)
    {
        global $DB;

        if (empty($plugin)) {
            return false;
        }
        $temp = new CronTask();
        $ret  = true;

        $iterator = $DB->request([
            'FROM'   => self::getTable(),
            'WHERE'  => [
                'OR' => [
                    ['itemtype' => ['LIKE', sprintf('Plugin%s', $plugin) . '%']],
                    ['itemtype' => ['LIKE', addslashes(sprintf('GlpiPlugin\\\\%s\\\\', $plugin)) . '%']]
                ]
            ]
        ]);

        foreach ($iterator as $data) {
            if (!$temp->delete($data)) {
                $ret = false;
            }
        }

        return $ret;
    }


    /**
     * Display statistics of a task
     *
     * @return void
     **/
    public function showStatistics()
    {
        global $DB;

        echo "<br><div class='center'>";
        echo "<table class='tab_cadre'>";
        echo "<tr><th colspan='2'>&nbsp;" . __('Statistics') . "</th></tr>\n";

        $nbstart = countElementsInTable(
            'glpi_crontasklogs',
            ['crontasks_id' => $this->fields['id'],
                'state'        => CronTaskLog::STATE_START
            ]
        );
        $nbstop  = countElementsInTable(
            'glpi_crontasklogs',
            ['crontasks_id' => $this->fields['id'],
                'state'        => CronTaskLog::STATE_STOP
            ]
        );
        $nberror = countElementsInTable(
            'glpi_crontasklogs',
            ['crontasks_id' => $this->fields['id'],
                'state'        => CronTaskLog::STATE_ERROR
            ]
        );

        echo "<tr class='tab_bg_2'><td>" . __('Run count') . "</td><td class='right'>";
        if ($nbstart == $nbstop) {
            echo $nbstart;
        } else {
           // This should not appen => task crash ?
           //TRANS: %s is the number of starts
            printf(_n('%s start', '%s starts', $nbstart), $nbstart);
            echo "<br>";
           //TRANS: %s is the number of stops
            printf(_n('%s stop', '%s stops', $nbstop), $nbstop);
            echo "<br>";
           //TRANS: %s is the number of errors
            printf(_n('%s error', '%s errors', $nberror), $nberror);
        }
        echo "</td></tr>";

        if ($nbstop) {
            $data = $DB->request([
                'SELECT' => [
                    'MIN' => [
                        'date AS datemin',
                        'elapsed AS elapsedmin',
                        'volume AS volmin'
                    ],
                    'MAX' => [
                        'elapsed AS elapsedmax',
                        'volume AS volmax'
                    ],
                    'SUM' => [
                        'elapsed AS elapsedtot',
                        'volume AS voltot'
                    ],
                    'AVG' => [
                        'elapsed AS elapsedavg',
                        'volume AS volavg'
                    ]
                ],
                'FROM'   => CronTaskLog::getTable(),
                'WHERE'  => [
                    'crontasks_id' => $this->fields['id'],
                    'state'        => CronTaskLog::STATE_STOP
                ]
            ])->current();

            echo "<tr class='tab_bg_1'><td>" . __('Start date') . "</td>";
            echo "<td class='right'>" . Html::convDateTime($data['datemin']) . "</td></tr>";

            echo "<tr class='tab_bg_2'><td>" . __('Minimal time') . "</td>";
            echo "<td class='right'>" . sprintf(
                _n('%s second', '%s seconds', $data['elapsedmin']),
                number_format($data['elapsedmin'], 2)
            );
            echo "</td></tr>";

            echo "<tr class='tab_bg_1'><td>" . __('Maximal time') . "</td>";
            echo "<td class='right'>" . sprintf(
                _n('%s second', '%s seconds', $data['elapsedmax']),
                number_format($data['elapsedmax'], 2)
            );
            echo "</td></tr>";

            echo "<tr class='tab_bg_2'><td>" . __('Average time') . "</td>";
            echo "<td class='right b'>" . sprintf(
                _n('%s second', '%s seconds', $data['elapsedavg']),
                number_format($data['elapsedavg'], 2)
            );
            echo "</td></tr>";

            echo "<tr class='tab_bg_1'><td>" . __('Total duration') . "</td>";
            echo "<td class='right'>" . sprintf(
                _n('%s second', '%s seconds', $data['elapsedtot']),
                number_format($data['elapsedtot'], 2)
            );
            echo "</td></tr>";

            if ($data['voltot'] > 0) {
                echo "<tr class='tab_bg_2'><td>" . __('Minimal count') . "</td>";
                echo "<td class='right'>" . sprintf(
                    _n('%s item', '%s items', $data['volmin']),
                    $data['volmin']
                ) . "</td></tr>";

                 echo "<tr class='tab_bg_1'><td>" . __('Maximal count') . "</td>";
                 echo "<td class='right'>" . sprintf(
                     _n('%s item', '%s items', $data['volmax']),
                     $data['volmax']
                 ) . "</td></tr>";

                 echo "<tr class='tab_bg_2'><td>" . __('Average count') . "</td>";
                 echo "<td class='right b'>" . sprintf(
                     _n('%s item', '%s items', $data['volavg']),
                     number_format($data['volavg'], 2)
                 ) .
                   "</td></tr>";

                 echo "<tr class='tab_bg_1'><td>" . __('Total count') . "</td>";
                 echo "<td class='right'>" . sprintf(
                     _n('%s item', '%s items', $data['voltot']),
                     $data['voltot']
                 ) . "</td></tr>";

                 echo "<tr class='tab_bg_2'><td>" . __('Average speed') . "</td>";
                 echo "<td class='left'>" . sprintf(
                     __('%s items/sec'),
                     number_format($data['voltot'] / $data['elapsedtot'], 2)
                 );
                 echo "</td></tr>";
            }
        }
        echo "</table></div>";
    }


    /**
     * Display list of a runned tasks
     *
     * @return void
     **/
    public function showHistory()
    {
        global $DB;

        if (isset($_GET["crontasklogs_id"]) && $_GET["crontasklogs_id"]) {
            $this->showHistoryDetail($_GET["crontasklogs_id"]);
            return;
        }

        if (isset($_GET["start"])) {
            $start = $_GET["start"];
        } else {
            $start = 0;
        }

       // Total Number of events
        $number = countElementsInTable(
            'glpi_crontasklogs',
            [
                'crontasks_id' => $this->fields['id'],
                'state'        => [CronTaskLog::STATE_STOP, CronTaskLog::STATE_ERROR],
            ]
        );

        echo "<br><div class='center'>";
        if ($number < 1) {
            echo "<table class='tab_cadre_fixe'>";
            echo "<tr><th>" . __('No item found') . "</th></tr>";
            echo "</table>";
            echo "</div>";
            return;
        }

       // Display the pager
        Html::printAjaxPager(__('Last run list'), $start, $number);

        $iterator = $DB->request([
            'FROM'   => 'glpi_crontasklogs',
            'WHERE'  => [
                'crontasks_id' => $this->fields['id'],
                'state'        => [CronTaskLog::STATE_STOP, CronTaskLog::STATE_ERROR],
            ],
            'ORDER'  => 'id DESC',
            'START'  => (int)$start,
            'LIMIT'  => (int)$_SESSION['glpilist_limit']
        ]);

        if (count($iterator)) {
            echo "<table class='tab_cadrehov'>";
            $header = "<tr>";
            $header .= "<th>" . _n('Date', 'Dates', 1) . "</th>";
            $header .= "<th>" . __('Total duration') . "</th>";
            $header .= "<th>" . _x('quantity', 'Number') . "</th>";
            $header .= "<th>" . __('Description') . "</th>";
            $header .= "</tr>\n";
            echo $header;

            foreach ($iterator as $data) {
                echo "<tr class='tab_bg_2'>";
                echo "<td><a href='javascript:reloadTab(\"crontasklogs_id=" .
                        $data['crontasklogs_id'] . "\");'>" . Html::convDateTime($data['date']) .
                  "</a></td>";
                echo "<td class='right'>" . sprintf(
                    _n(
                        '%s second',
                        '%s seconds',
                        intval($data['elapsed'])
                    ),
                    number_format($data['elapsed'], 3)
                ) .
                    "&nbsp;&nbsp;&nbsp;</td>";
                echo "<td class='numeric'>" . $data['volume'] . "</td>";
               // Use gettext to display
                echo "<td>" . __($data['content']) . "</td>";
                echo "</tr>\n";
            }
            echo $header;
            echo "</table>";
        } else { // Not found
            echo __('No item found');
        }
        Html::printAjaxPager(__('Last run list'), $start, $number);

        echo "</div>";
    }


    /**
     * Display detail of a runned task
     *
     * @param $logid : crontasklogs_id
     *
     * @return void
     **/
    public function showHistoryDetail($logid)
    {
        global $DB;

        echo "<br><div class='center'>";
        echo "<p><a href='javascript:reloadTab(\"crontasklogs_id=0\");'>" . __('Last run list') . "</a>" .
           "</p>";

        $iterator = $DB->request([
            'FROM'   => 'glpi_crontasklogs',
            'WHERE'  => [
                'OR' => [
                    'id'              => $logid,
                    'crontasklogs_id' => $logid
                ]
            ],
            'ORDER'  => 'id ASC'
        ]);

        if (count($iterator)) {
            echo "<table class='tab_cadrehov'><tr>";
            echo "<th>" . _n('Date', 'Dates', 1) . "</th>";
            echo "<th>" . __('Status') . "</th>";
            echo "<th>" . __('Duration') . "</th>";
            echo "<th>" . _x('quantity', 'Number') . "</th>";
            echo "<th>" . __('Description') . "</th>";
            echo "</tr>\n";

            $first = true;
            foreach ($iterator as $data) {
                echo "<tr class='tab_bg_2'>";
                echo "<td class='center'>" . ($first ? Html::convDateTime($data['date'])
                                                : "&nbsp;") . "</a></td>";
                $content = $data['content'];
                switch ($data['state']) {
                    case CronTaskLog::STATE_START:
                        echo "<td>" . __('Start') . "</td>";
                     // Pass content to gettext
                     // implode (Run mode: XXX)
                        $list = explode(':', $data['content']);
                        if (count($list) == 2) {
                               $content = sprintf('%1$s: %2$s', __($list[0]), $list[1]);
                        }
                        break;

                    case CronTaskLog::STATE_STOP:
                        echo "<td>" . __('End') . "</td>";
                   // Pass content to gettext
                        $content = __($data['content']);
                        break;

                    case CronTaskLog::STATE_ERROR:
                        echo "<td>" . __('Error') . "</td>";
                        // Pass content to gettext
                        $content = __($data['content']);
                        break;

                    default:
                         echo "<td>" . __('Running') . "</td>";
                         // Pass content to gettext
                         $content = __($data['content']);
                }

                echo "<td class='right'>" . sprintf(
                    _n(
                        '%s second',
                        '%s seconds',
                        intval($data['elapsed'])
                    ),
                    number_format($data['elapsed'], 3)
                ) .
                    "&nbsp;&nbsp;</td>";
                echo "<td class='numeric'>" . $data['volume'] . "</td>";

                echo "<td>" . $content . "</td>";
                echo "</tr>\n";
                $first = false;
            };

            echo "</table>";
        } else { // Not found
            echo __('No item found');
        }

        echo "</div>";
    }


    /**
     * @since 0.84
     *
     * @param $field
     * @param $name               (default '')
     * @param $values             (default '')
     * @param $options      array
     **/
    public static function getSpecificValueToSelect($field, $name = '', $values = '', array $options = [])
    {

        if (!is_array($values)) {
            $values = [$field => $values];
        }
        $options['display'] = 0;
        switch ($field) {
            case 'mode':
                $options['value']         = $values[$field];
                $tab = [
                    self::MODE_INTERNAL => self::getModeName(self::MODE_INTERNAL),
                    self::MODE_EXTERNAL => self::getModeName(self::MODE_EXTERNAL),
                ];
                return Dropdown::showFromArray($name, $tab, $options);

            case 'state':
                return CronTask::dropdownState($name, $values[$field], false);
        }

        return parent::getSpecificValueToSelect($field, $name, $values, $options);
    }


    public static function getSpecificValueToDisplay($field, $values, array $options = [])
    {

        if (!is_array($values)) {
            $values = [$field => $values];
        }
        switch ($field) {
            case 'mode':
                return self::getModeName($values[$field]);

            case 'state':
                return self::getStateName($values[$field]);
        }
        return parent::getSpecificValueToDisplay($field, $values, $options);
    }


    public function getSpecificMassiveActions($checkitem = null)
    {

        $isadmin = static::canUpdate();
        $actions = parent::getSpecificMassiveActions($checkitem);

        if ($isadmin) {
            $actions[__CLASS__ . MassiveAction::CLASS_ACTION_SEPARATOR . 'reset'] = __('Reset last run');
        }
        return $actions;
    }


    public static function processMassiveActionsForOneItemtype(
        MassiveAction $ma,
        CommonDBTM $item,
        array $ids
    ) {

        switch ($ma->getAction()) {
            case 'reset':
                foreach ($ids as $key) {
                    if (Config::canUpdate()) {
                        if ($item->getFromDB($key)) {
                            if ($item->resetDate()) {
                                 $ma->itemDone($item->getType(), $key, MassiveAction::ACTION_OK);
                            } else {
                                $ma->itemDone($item->getType(), $key, MassiveAction::ACTION_KO);
                                $ma->addMessage($item->getErrorMessage(ERROR_ON_ACTION));
                            }
                        } else {
                            $ma->itemDone($item->getType(), $key, MassiveAction::ACTION_KO);
                            $ma->addMessage($item->getErrorMessage(ERROR_NOT_FOUND));
                        }
                    } else {
                        $ma->itemDone($item->getType(), $key, MassiveAction::ACTION_NORIGHT);
                        $ma->addMessage($item->getErrorMessage(ERROR_RIGHT));
                    }
                }
                return;
        }
        parent::processMassiveActionsForOneItemtype($ma, $item, $ids);
    }


    public function rawSearchOptions()
    {
        global $DB;

        $tab = [];

        $tab[] = [
            'id'                 => 'common',
            'name'               => __('Characteristics')
        ];

        $tab[] = [
            'id'                 => '1',
            'table'              => $this->getTable(),
            'field'              => 'name',
            'name'               => __('Name'),
            'datatype'           => 'itemlink',
            'massiveaction'      => false
        ];

        $tab[] = [
            'id'                 => '2',
            'table'              => $this->getTable(),
            'field'              => 'id',
            'name'               => __('ID'),
            'massiveaction'      => false,
            'datatype'           => 'number'
        ];

        $tab[] = [
            'id'                 => '3',
            'table'              => $this->getTable(),
            'field'              => 'description',
            'name'               => __('Description'),
            'nosearch'           => true,
            'nosort'             => true,
            'massiveaction'      => false,
            'datatype'           => 'text',
            'computation'        => $DB->quoteName('TABLE.id') // Virtual data
        ];

        $tab[] = [
            'id'                 => '4',
            'table'              => $this->getTable(),
            'field'              => 'state',
            'name'               => __('Status'),
            'searchtype'         => ['equals', 'notequals'],
            'datatype'           => 'specific'
        ];

        $tab[] = [
            'id'                 => '5',
            'table'              => $this->getTable(),
            'field'              => 'mode',
            'name'               => __('Run mode'),
            'datatype'           => 'specific',
            'searchtype'         => ['equals', 'notequals']
        ];

        $tab[] = [
            'id'                 => '6',
            'table'              => $this->getTable(),
            'field'              => 'frequency',
            'name'               => __('Run frequency'),
            'datatype'           => 'timestamp',
            'massiveaction'      => false
        ];

        $tab[] = [
            'id'                 => '7',
            'table'              => $this->getTable(),
            'field'              => 'lastrun',
            'name'               => __('Last run'),
            'datatype'           => 'datetime',
            'massiveaction'      => false
        ];

        $tab[] = [
            'id'                 => '8',
            'table'              => $this->getTable(),
            'field'              => 'itemtype',
            'name'               => __('Item type'),
            'massiveaction'      => false,
            'datatype'           => 'itemtypename',
            'types'              => self::getUsedItemtypes()
        ];

        $tab[] = [
            'id'                 => '16',
            'table'              => $this->getTable(),
            'field'              => 'comment',
            'name'               => __('Comments'),
            'datatype'           => 'text'
        ];

        $tab[] = [
            'id'                 => '17',
            'table'              => $this->getTable(),
            'field'              => 'hourmin',
            'name'               => __('Begin hour of run period'),
            'datatype'           => 'integer',
            'min'                => 0,
            'max'                => 24
        ];

        $tab[] = [
            'id'                 => '18',
            'table'              => $this->getTable(),
            'field'              => 'hourmax',
            'name'               => __('End hour of run period'),
            'datatype'           => 'integer',
            'min'                => 0,
            'max'                => 24
        ];

        $tab[] = [
            'id'                 => '19',
            'table'              => $this->getTable(),
            'field'              => 'logs_lifetime',
            'name'               => __('Number of days this action logs are stored'),
            'datatype'           => 'integer',
            'min'                => 10,
            'max'                => 360,
            'step'               => 10,
            'toadd'              => [
                '0'                  => 'Infinite'
            ]
        ];

        $tab[] = [
            'id'                 => '20',
            'table'              => $this->getTable(),
            'field'              => 'date_mod',
            'name'               => __('Last update'),
            'datatype'           => 'datetime',
            'massiveaction'      => false
        ];

        $tab[] = [
            'id'                 => '121',
            'table'              => $this->getTable(),
            'field'              => 'date_creation',
            'name'               => __('Creation date'),
            'datatype'           => 'datetime',
            'massiveaction'      => false
        ];

        return $tab;
    }


    /**
     * Garbage collector for expired file session
     *
     * @param CronTask $task for log
     *
     * @return integer
     **/
    public static function cronSession(CronTask $task)
    {

       // max time to keep the file session
        $maxlifetime = ini_get('session.gc_maxlifetime');
        if ($maxlifetime == 0) {
            $maxlifetime = WEEK_TIMESTAMP;
        }
        $nb = 0;
        foreach (glob(GLPI_SESSION_DIR . "/sess_*") as $filename) {
            if ((filemtime($filename) + $maxlifetime) < time()) {
               // Delete session file if not delete before
                if (@unlink($filename)) {
                    $nb++;
                }
            }
        }

        $task->setVolume($nb);
        if ($nb) {
           //TRANS: % %1$d is a number, %2$s is a number of seconds
            $task->log(sprintf(
                _n(
                    'Clean %1$d session file created since more than %2$s seconds',
                    'Clean %1$d session files created since more than %2$s seconds',
                    $nb
                ) . "\n",
                $nb,
                $maxlifetime
            ));
            return 1;
        }

        return 0;
    }


    /**
     * Circular logs
     *
     * @since 0.85
     *
     * @param CronTask $task for log
     *
     * @return integer
     **/
    public static function cronCircularlogs(CronTask $task)
    {

        $actionCode = 0; // by default
        $error      = false;
        $task->setVolume(0); // start with zero

       // compute date in the past for the archived log to be deleted
        $firstdate = date("Ymd", time() - ($task->fields['param'] * DAY_TIMESTAMP)); // compute current date - param as days and format it like YYYYMMDD

       // first look for bak to delete
        $dir       = GLPI_LOG_DIR . "/*.bak";
        $findfiles = glob($dir);
        foreach ($findfiles as $file) {
            $shortfile = str_replace(GLPI_LOG_DIR . '/', '', $file);
           // now depending on the format of the name we delete the file (for aging archives) or rename it (will add Ymd.log to the end of the file)
            $match = null;
            if (preg_match('/.+[.]log[.](\\d{8})[.]bak$/', $file, $match) > 0) {
                if ($match[1] < $firstdate) {
                    $task->addVolume(1);
                    if (unlink($file)) {
                        $task->log(sprintf(__('Deletion of archived log file: %s'), $shortfile));
                        $actionCode = 1;
                    } else {
                        $task->log(sprintf(__('Unable to delete archived log file: %s'), $shortfile));
                        $error = true;
                    }
                }
            }
        }

       // second look for log to archive
        $dir       = GLPI_LOG_DIR . "/*.log";
        $findfiles = glob($dir);
        foreach ($findfiles as $file) {
            $shortfile    = str_replace(GLPI_LOG_DIR . '/', '', $file);
           // rename the file
            $newfilename  = $file . "." . date("Ymd", time()) . ".bak"; // will add to filename a string with format YYYYMMDD (= current date)
            $shortnewfile = str_replace(GLPI_LOG_DIR . '/', '', $newfilename);

            $task->addVolume(1);
            if (!file_exists($newfilename) && rename($file, $newfilename)) {
                $task->log(sprintf(__('Archiving log file: %1$s to %2$s'), $shortfile, $shortnewfile));
                $actionCode = 1;
            } else {
                $task->log(sprintf(
                    __('Unable to archive log file: %1$s. %2$s already exists. Wait till next day.'),
                    $shortfile,
                    $shortnewfile
                ));
                $error = true;
            }
        }

        if ($error) {
            return -1;
        }
        return $actionCode;
    }


    /**
     * Garbage collector for cleaning graph files
     *
     * @param CronTask $task for log
     *
     * @return integer
     **/
    public static function cronGraph(CronTask $task)
    {

       // max time to keep the file session
        $maxlifetime = HOUR_TIMESTAMP;
        $nb          = 0;
        foreach (glob(GLPI_GRAPH_DIR . "/*") as $filename) {
            if (basename($filename) == "remove.txt" && is_dir(GLPI_ROOT . '/.git')) {
                continue;
            }
            if ((filemtime($filename) + $maxlifetime) < time()) {
                if (@unlink($filename)) {
                    $nb++;
                }
            }
        }

        $task->setVolume($nb);
        if ($nb) {
            $task->log(sprintf(
                _n(
                    'Clean %1$d graph file created since more than %2$s seconds',
                    'Clean %1$d graph files created since more than %2$s seconds',
                    $nb
                ) . "\n",
                $nb,
                $maxlifetime
            ));
            return 1;
        }

        return 0;
    }

    /**
     * Garbage collector for cleaning tmp files
     *
     * @param CronTask $task for log
     *
     * @return integer
     **/
    public static function cronTemp(CronTask $task)
    {

       // max time to keep the file session
        $maxlifetime = HOUR_TIMESTAMP;
        $nb          = 0;

        $dir = new RecursiveDirectoryIterator(GLPI_TMP_DIR, RecursiveDirectoryIterator::SKIP_DOTS);
        $files = new RecursiveIteratorIterator(
            $dir,
            RecursiveIteratorIterator::CHILD_FIRST
        );

       //first step unlike only file if needed
        foreach ($files as $filename) {
            if (basename($filename) == ".gitkeep") {
                continue;
            }

            if (
                is_file($filename) && is_writable($filename)
                && (filemtime($filename) + $maxlifetime) < time()
            ) {
                if (@unlink($filename)) {
                    $nb++;
                }
            }

            if (
                is_dir($filename) && is_readable($filename)
                //be sure that the directory is empty
                && count(scandir($filename)) == 2
            ) {
                if (@rmdir($filename)) {
                    $nb++;
                }
            }
        }

        $task->setVolume($nb);
        if ($nb) {
            $task->log(sprintf(
                _n(
                    'Clean %1$d temporary file created since more than %2$s seconds',
                    'Clean %1$d temporary files created since more than %2$s seconds',
                    $nb
                ) . "\n",
                $nb,
                $maxlifetime
            ));
            return 1;
        }

        return 0;
    }

    /**
     * Clean log cron function
     *
     * @param CronTask $task
     *
     * @return integer
     **/
    public static function cronLogs($task)
    {
        global $DB;

        $vol = 0;

       // Expire Event Log
        if ($task->fields['param'] > 0) {
            $vol += Event::cleanOld($task->fields['param']);
        }

        foreach ($DB->request('glpi_crontasks') as $data) {
            if ($data['logs_lifetime'] > 0) {
                $vol += CronTaskLog::cleanOld($data['id'], $data['logs_lifetime']);
            }
        }
        $task->setVolume($vol);
        return ($vol > 0 ? 1 : 0);
    }


    /**
     * Cron job to check if a new version is available
     *
     * @param CronTask $task for log
     *
     * @return integer
     **/
    public static function cronCheckUpdate($task)
    {

        $result = Toolbox::checkNewVersionAvailable();
        $task->log($result);

        return 1;
    }


    /**
     * Check zombie crontask
     *
     * @param CronTask $task for log
     *
     * @return integer
     **/
    public static function cronWatcher($task)
    {
        global $DB;

       // CronTasks running for more than 1 hour or 2 frequency
        $iterator = $DB->request([
            'FROM'   => self::getTable(),
            'WHERE'  => [
                'state'  => self::STATE_RUNNING,
                'OR'     => [
                    new \QueryExpression('unix_timestamp(' . $DB->quoteName('lastrun') . ') + 2 * ' . $DB->quoteName('frequency') . ' < unix_timestamp(now())'),
                    new \QueryExpression('unix_timestamp(' . $DB->quoteName('lastrun') . ') + 2 * ' . HOUR_TIMESTAMP . ' < unix_timestamp(now())')
                ]
            ]
        ]);
        $crontasks = [];
        foreach ($iterator as $data) {
            $crontasks[$data['id']] = $data;
        }

        if (count($crontasks)) {
            $task = new self();
            $task->getFromDBByCrit(['itemtype' => 'CronTask', 'name' => 'watcher']);
            if (NotificationEvent::raiseEvent("alert", $task, ['items' => $crontasks])) {
                $task->addVolume(1);
            }
            QueuedNotification::forceSendFor($task->getType(), $task->fields['id']);
        }

        return 1;
    }


    /**
     * get Cron description parameter for this class
     *
     * @param $name string name of the task
     *
     * @return array of string
     **/
    public static function cronInfo($name)
    {

        switch ($name) {
            case 'checkupdate':
                return ['description' => __('Check for new updates')];

            case 'logs':
                return ['description' => __('Clean old logs'),
                    'parameter'
                           => __('System logs retention period (in days, 0 for infinite)')
                ];

            case 'session':
                return ['description' => __('Clean expired sessions')];

            case 'graph':
                return ['description' => __('Clean generated graphics')];

            case 'temp':
                return ['description' => __('Clean temporary files')];

            case 'watcher':
                return ['description' => __('Monitoring of automatic actions')];

            case 'circularlogs':
                return ['description' => __("Archives log files and deletes aging ones"),
                    'parameter'   => __("Number of days to keep archived logs")
                ];
        }

        return [];
    }


    /**
     * Call cron without time check
     *
     * @return boolean : true if launched
     **/
    public static function callCronForce()
    {
        global $CFG_GLPI;

        $path = $CFG_GLPI['root_doc'] . "/front/cron.php";

        echo "<div style=\"background-image: url('$path');\"></div>";
        return true;
    }


    /**
     * Call cron if time since last launch elapsed
     *
     * @return void
     **/
    public static function callCron()
    {

        if (isset($_SESSION["glpicrontimer"])) {
           // call static function callcron() every 5min
            if ((time() - $_SESSION["glpicrontimer"]) > 300) {
                if (self::callCronForce()) {
                   // Restart timer
                    $_SESSION["glpicrontimer"] = time();
                }
            }
        } else {
           // Start timer
            $_SESSION["glpicrontimer"] = time();
        }
    }


    public static function getIcon()
    {
        return "ti ti-settings-automation";
    }
}
			
			


Thanks For 0xGh05T - DSRF14 - Mr.Dan07 - Leri01 - FxshX7 - AlkaExploiter - xLoveSyndrome'z - Acep Gans'z

JMDS TRACK – Just Another Diagnostics Lab Site

Home

JMDS TRACK Cameroon

Boost the productivity of your mobile ressources


Make An Appointment


Fleet management

  1. Reduce the operting cost and the unavailability of your vehicles
  2. reduce the fuel consumption of your fleet
  3. Improve the driving dehavior and safety of your drivers
  4. optimize the utilization rate of your equipment 
  5. protect your vehicle against theft
  6. Improve the quality of your customer service


Find out more

Assets management

  1. Track the roaming of your equipment
  2. Optimise the management of your assets on site and during transport
  3. Secure the transport of your goods
  4. Make your team responsible for preventing the loss of tools, equipment
  5. Take a real-time inventory of your equipment on site
  6. Easily find your mobile objects or equipment



Find out more



Find out more

Antitheft solutions

  1. Secure your vehicles and machinery and increase your chances of recovering them in the event of theft
  2. Protect your assets and reduce the costs associated with their loss
  3. Combine immobiliser and driver identification and limit the risk of theft
  4. Identify fuel theft and reduce costs
  5. Protect your goods and take no more risks
  6. Be alerted to abnormal events

Our Location

 Douala BP cité 

     and

Yaoundé Total Essos


Make An Appointment


Get Directions

682230363/ 677481892

What makes us different from others

  • young and dynamic team
  • call center 24/24 7/7
  • roaming throughout Africa
  • team of developers who can develop customer-specific solutions
  • diversity of services
  • reactive and prompt after-sales service when soliciting a customer or a malfunction
  • Free Maintenance and installation in the cities of Douala and Yaounde

https://youtu.be/xI1cz_Jh2x8

15+
years of experience in GPS system development, production and deployment.

15 Collaborators

More than 15 employees dedicated to the research and development of new applications and to customer care

5 000 Vehicles and mobile assets

5 000 vehicles and mobile assets under management, in Africa

Our Partners










Latest Case Studies

Our current projects 

5/5
Bon SAV , SATISFAIT DU TRAITEMENT DES REQUETES

M DIPITA CHRISTIAN
Logistic Safety Manager Road Safety Manager
5/5
La réactivité de JMDS est excellente
Nous restons satisfait dans l’ensemble des prestations relatives a la couverture de notre parc automobile

Hervé Frédéric NDENGUE
Chef Service Adjoint de la Sécurité Générale (CNPS)
5/5
L’APPLICATION EMIXIS est convivial A L’utilisation
BEIG-3 SARL
DIRECTOR GENERAL
5/5
Nevertheless I am delighted with the service
MR. BISSE BENJAMIN
CUSTOMER

Subsribe To Our Newsletter

Stay in touch with us to get latest news and special offers.



Address JMDS TRACK

Douala bp cité



and

YAOUNDE Total Essos

Call Us

+237682230363



Email Us


info@jmdstrack.cm