<?php

require_once 'common/mailfunctions.php';
require_once 'common/xmlFunctions.php';

function plugin_serverstatus_variables()
{
    $variables = array(
        'Plugin Name'   => array(
            'type'          => 'hidden',
            'description'   => '',
            'value'         => 'Server Status',
        ),
        'Enabled'       => array(
            'type'          => 'yesno',
            'description'   => 'When enabled and server plugin has server stats script URL, ClientExec will notify you if the server is not responding or when certain thresholds are met.',
            'value'         => '0',
        ),
        'Admin E-mail'     => array(
            'type'          => 'text',
            'description'   => 'E-mails that will be E-mailed when thresholds are passed. Separate multiple E-mails with commas.<br/>Ex: e-mail1@domain.com, e-mail2@domain.com',
            'value'         => '',
        ),
        '1 Min. Load Average'     => array(
            'type'          => 'text',
            'description'   => 'Add 1 Minute server load average threshold you want this service to E-mail if passed.<br/>Ex: 1.5, will E-mail when load goes over 1.5',
            'value'         => '',
        ),
        '5 Min. Load Average'     => array(
            'type'          => 'text',
            'description'   => 'Add 5 Minute server load average threshold you want this service to E-mail if passed.<br/>Ex: 1.5, will E-mail when load goes over 1.5',
            'value'         => '',
        ),
        'Used Physical Memory'     => array(
            'type'          => 'text',
            'description'   => 'Add used physical memory threshold in megabytes (MB) you want this service to E-mail if passed. Current cache use will be subtracted from the Used Physical Memory on the server.<br/>Ex: 512, will E-mail when memory goes over 512 MB',
            'value'         => '',
        ),
        'Server Restarted'  => array(
            'type'          => 'yesno',
            'description'   => 'Notify if the server was restarted since the last check.',
            'value'         => '0',
        ),
        'Mount Space Available'     => array(
            'type'          => 'text',
            'description'   => 'Add mount and percentage threshold that you want this service to E-mail you on. Use ; as separator if you want to monitor more than one mount.<br/>Ex: /home,75;/tmp,50',
            'value'         => '',
        ),
        'Run schedule - Minute'  => array(
            'type'          => 'text',
            'description'   => 'Enter number, range, list or steps',
            'value'         => '*',
            'helpid'        => '8',
        ),
        'Run schedule - Hour'  => array(
            'type'          => 'text',
            'description'   => 'Enter number, range, list or steps',
            'value'         => '*',
        ),
        'Run schedule - Day'  => array(
            'type'          => 'text',
            'description'   => 'Enter number, range, list or steps',
            'value'         => '*',
        ),
        'Run schedule - Month'  => array(
            'type'          => 'text',
            'description'   => 'Enter number, range, list or steps',
            'value'         => '*',
        ),
        'Run schedule - Day of the week'  => array(
            'type'          => 'text',
            'description'   => 'Enter number in range 0-7 (0 is Sunday) or a 3 letter shortcut (e.g. sun)',
            'value'         => '*',
        ),
    );

    return $variables;
}

function plugin_serverstatus_execute()
{
    // NOTE: We must return error objects only when there are fatal errors that prevent the plugin from working appropiately,
    // and handle inside this plugin the e-mailing corresponding to events.

    global $gSettingsArray;

    if (defined('INCLUDE_STEPS') && (INCLUDE_STEPS == 'service')) {
        $arrEmails = explode(',', $gSettingsArray['plugin_serverstatus_Admin E-mail']);
    } else {
        $arrEmails = false;
    }

    $messages = array();

    // Get list of servers
    $sql = "SELECT id, name, statsurl FROM server WHERE statsurl != ''";
    $result = $GLOBALS['db']->query($sql);

    $str1minLoad = $gSettingsArray['plugin_serverstatus_1 Min. Load Average'];
    $str5minLoad = $gSettingsArray['plugin_serverstatus_5 Min. Load Average'];
    $strMemory = $gSettingsArray['plugin_serverstatus_Used Physical Memory'];
    $arrSpace = explode(';', $gSettingsArray['plugin_serverstatus_Mount Space Available']);
    if ( ($str1minLoad == "") && ($str5minLoad == "") && ($arrSpace[0] == "") ) {
        return;
    }

    while (list($serverid, $servername, $statsurl) = $result->fetch())
    {
        if (is_error($xmldata = _plugin_serverstatus_getXMLData($statsurl, $serverid, $servername, $arrEmails))) {
            $messages[] = $xmldata;
            continue;
        }

        //need to validate XML before we do anything so that we do not
        //get unexpected errors when using this xmlize function
        $xml = xmlize($xmldata,1);

        $uptimeTimeStamp = $xml["phpsysinfo"]["#"]["Vitals"][0]["#"]["Uptime"][0]["#"];
        if ($gSettingsArray['plugin_serverstatus_Server Restarted']
            && $uptimeStatus = _plugin_serverstatus_updateUptimeStatus($uptimeTimeStamp, $serverid, $servername, $arrEmails))
        {
            $messages[] = $uptimeStatus;
        }

        //Check 1 Min. Load Threshold
        if ($str1minLoad != '' && ($load1minStatus = _checkLoad($xml,$serverid, $servername, $arrEmails, '1'))) {
            $messages[] = $load1minStatus;
        }
        //Check 5 Min. Load Threshold
        if ($str5minLoad != '' && ($load5minStatus = _checkLoad($xml,$serverid, $servername, $arrEmails, '5'))) {
            $messages[] = $load5minStatus;
        }
        //Check Used Physical Memory Threshold
        if ($strMemory != '' && ($memoryStatus = _plugin_serverstatus_checkmemory($xml,$serverid, $servername, $arrEmails))) {
            $messages[] = $memoryStatus;
        }

        //Check Disk Mount Space
        if($arrSpace[0] != ""){
            $mountsStatus = _plugin_serverstatus_checkdiskspace($xml, $serverid, $servername, $arrEmails);
            if (is_array($mountsStatus) && $mountsStatus) {
                foreach ($mountsStatus as $status) {
                    if ($status) {
                        $messages[] = $status;
                    }
                }
            }
        }

    }

    if (!$messages) {
        return array('Server Status Is Ok');
    }

    return $messages;
}

function plugin_serverstatus_output()
{
    global $tpl;
    global $gSettingsArray;

}

function plugin_serverstatus_dashboard()
{
    global $gSettingsArray;
}

function isMountExists($xml,$matchmount){

    $mounts = $xml["phpsysinfo"]["#"]["FileSystem"][0]["#"]["Mount"];
    $found=false;

    for($i = 0; $i < sizeof($mounts); $i++) {
        $mount = $mounts[$i];
        $mountpoint = $mount["#"]["MountPoint"][0]["#"];
        $mountpercent = $mount["#"]["Percent"][0]["#"];
        if($matchmount==$mountpoint) $found = true;
    }

    return $found;
}

function checkIfMountOverThreshold($xml, $matchmount, $threshold, $serverId, $servername, $arrEmails){

    $mounts = $xml["phpsysinfo"]["#"]["FileSystem"][0]["#"]["Mount"];
    $strErrorMessage = "";

    for($i = 0; $i < sizeof($mounts); $i++) {
        $mount = $mounts[$i];
        $mountpoint = $mount["#"]["MountPoint"][0]["#"];
        $mountpercent = $mount["#"]["Percent"][0]["#"];
        if($matchmount==$mountpoint){
            $status = "Mount over threshold-> server: $serverId mount: $matchmount";
            $result = $GLOBALS['db']->query("SELECT id, status FROM services_log "
                                           ."WHERE status = ?", $status);
            if ($row = $result->fetch()) {
                $notified = true;
            } else {
                $notified = false;
            }
            if( intval($threshold) < intval($mountpercent) ){
                if (!$notified) {
                    $strErrorMessage =  "Server ".$servername." Mount Threshold Error: ".$matchmount." (".$mountpercent."% used) has exceeded threshold set for this mount of ".$threshold."%";
                    if ($arrEmails) {
                        _plugin_serverstatus_email($arrEmails, false, $strErrorMessage);
                    }
                    $GLOBALS['db']->query("INSERT INTO services_log values(NULL, 'serverstatus', ?, 0, '', '', ?)", date('Y-m-d H:i:s'), $status);
                }
            } elseif ($notified) {
                if ($arrEmails) {
                    _plugin_serverstatus_email($arrEmails,
                                               false,
                                               "Server $servername Mount $matchmount  has returned to a level ($mountpercent%) below the set threshold ($threshold%).");
                }
                $GLOBALS['db']->query("DELETE FROM services_log WHERE status = ?", $status);
            }
        }
    }

    return $strErrorMessage;
}

function _plugin_serverstatus_checkdiskspace($xml, $serverId, $servername, $arrEmails){
    global $gSettingsArray;

    $status = array();
    $arrSpaces = explode(';', $gSettingsArray['plugin_serverstatus_Mount Space Available']);

    //need to look for mounts
    for($x=0;$x<=sizeof($arrSpaces);$x++){

        $bolServerMatched = false;

        $arrMount = explode(',',$arrSpaces[$x]);

        $tMount = $arrMount[0];
        $tMountThreshold = $arrMount[1];
        $tMountServer = $arrMount[2];

        if(strtoupper($tMountServer) == strtoupper($servername)){
            $bolServerMatched = true;
        }

        if(($tMount!="") && ($bolServerMatched || ($tMountServer=="") ) ){

            if(isMountExists($xml,$tMount)){
                $strError = checkIfMountOverThreshold($xml, $tMount, $tMountThreshold, $serverId, $servername, $arrEmails);
                if($strError!=""){
                    $status[] = $strError;
                }
            }else{
                    $status[] = new Error_CE(8838, "Server ".$servername." Mount Threshold Error: ".$tMount. " does not exist on server ".$servername);
            }
        }
    }
    return $status;
}

function _checkLoad($xml,$serverId, $servername, $arrEmails, $loadTime)
{
    global $gSettingsArray;

    $loadaverages = $xml["phpsysinfo"]["#"]["Vitals"][0]["#"]["LoadAvg"][0]["#"];

    //Get the load threshold placed in admin->plugins->
    switch($loadTime) {
        case 1:
            $strLoad = $gSettingsArray['plugin_serverstatus_1 Min. Load Average'];
            $status = "1 Min. Load over threshold-> server: $serverId";
            $loadIndex = 0;
            $thresholdExceededMessage = 'Server %s 1 Min. Load Average Threshold Error (%s): Your threshold of %s was exceeded';
            $belowThresholdMessage = 'Server %s 1 Min. Load Average (%s) has returned to a level below the set threshold (%s).';
            break;
        case 5:
            $strLoad = $gSettingsArray['plugin_serverstatus_5 Min. Load Average'];
            $status = "5 Min. Load over threshold-> server: $serverId";
            $loadIndex = 1;
            $thresholdExceededMessage = 'Server %s 5 Min. Load Average Threshold Error (%s): Your threshold of %s was exceeded';
            $belowThresholdMessage = 'Server %s 5 Min. Load Average (%s) has returned to a level below the set threshold (%s).';
            break;
    }

    $result = $GLOBALS['db']->query("SELECT id, status FROM services_log "
                                   ."WHERE status = ? ORDER BY time DESC", $status);
    if ($row = $result->fetch()) {
        $notified = true;
    } else {
        $notified = false;
    }

    if($loadaverages!=""){
        $loads = explode(" ",$loadaverages);
        $load = $loads[$loadIndex];
        if(floatval($strLoad) < floatval($load) ) {
            if (!$notified) {
                $GLOBALS['db']->query("INSERT INTO services_log values(NULL, 'serverstatus', ?, 0, '', '', ?)", date('Y-m-d H:i:s'), $status);
                if ($arrEmails) {
                    _plugin_serverstatus_email($arrEmails,
                                               false,
                                               sprintf($thresholdExceededMessage, $servername, $loadaveraged, $strLoad));
                }
                return sprintf($thresholdExceededMessage, $servername, $loadaveraged, $strLoad);
            }
        } elseif ($notified) {
            // send the e-mail here because it's not an error message like the others
            $GLOBALS['db']->query("DELETE FROM services_log WHERE status = ?", $status);
            if ($arrEmails) {
                _plugin_serverstatus_email($arrEmails,
                                           false,
                                           sprintf($belowThresholdMessage, $servername, $loadaverages, $strLoad));
            }
            return sprintf($belowThresholdMessage, $servername, $loadaverages, $strLoad);
        }
        return;
    }
    return new Error_CE(3478, lang('Load average was not present in server status output'));
}

function _plugin_serverstatus_checkmemory($xml,$serverId, $servername, $arrEmails){
    global $gSettingsArray;

    $memory = $xml["phpsysinfo"]["#"]["Memory"][0]["#"]["Used"][0]["#"];
    $cachedmemory = $xml["phpsysinfo"]["#"]["Memory"][0]["#"]["Cached"][0]["#"];

    if ($cachedmemory == '') {
		$cachedmemory = 0;
    }

    //Get the memory threshold placed in admin->plugins->
    $strMemory = $gSettingsArray['plugin_serverstatus_Used Physical Memory'];
    $status = "Used Memory over threshold-> server: $serverId";

    $result = $GLOBALS['db']->query("SELECT id, status FROM services_log "
                                   ."WHERE status = ? ORDER BY time DESC", $status);
    if ($row = $result->fetch()) {
        $notified = true;
    } else {
        $notified = false;
    }

    if($memory!=""){
        $mbmemory = round(($memory-$cachedmemory)/1024);
        if(floatval($strMemory) < floatval($mbmemory) ) {
            if (!$notified) {
                $GLOBALS['db']->query("INSERT INTO services_log values(NULL, 'serverstatus', ?, 0, '', '', ?)", date('Y-m-d H:i:s'), $status);
                if ($arrEmails) {
                    _plugin_serverstatus_email($arrEmails,
                                               false,
                                               "Server ".$servername." Used Physical Memory Threshold Error (".$mbmemory." MB): Your threshold of ".$strMemory." MB was exceeded");
                }
                return "Server ".$servername." Used Physical Memory Threshold Error (".$mbmemory." MB): Your threshold of ".$strMemory." MB was exceeded";
            }
        } elseif ($notified) {
            // send the e-mail here because it's not an error message like the others
            $GLOBALS['db']->query("DELETE FROM services_log WHERE status = ?", $status);
            if ($arrEmails) {
                _plugin_serverstatus_email($arrEmails,
                                           false,
                                           "Server $servername Used Physical Memory ($mbmemory MB) has returned to a level below the set threshold ($strMemory MB).");
            }
            return "Server $servername Used Physical Memory($mbmemory MB) has returned to a level below the set threshold ($strMemory MB).";
        }
        return;
    }
    return new Error_CE(3478, lang('Used Physical Memory was not present in server status output'));
}


function _plugin_serverstatus_email($arrEmails, $arrFailedMessage, $strBody = false) {

    global $gSettingsArray;

    $strSubject = "Server Status Report";
    $strErrors = "";
    
    if (arrFailedMessage) {
        for($x=0;$x<=sizeof($arrFailedMessage);$x++){
            if($arrFailedMessage[$x]!="")   $strErrors .= $arrFailedMessage[$x]."\n";
        }
    }

    if (!$strBody) {
        $strBody = "Server Status Error:\n ".$strErrors." \n\n\n\nThis email is sent to you by ClientExec";
    }

    for($x=0;$x<=sizeof($arrEmails);$x++){
        if ($arrEmails[$x]!=""){
            $strFromEmail = $gSettingsArray['Support E-mail'];
            $strFromName = $gSettingsArray['Support E-mail'];
            $strTo = $arrEmails[$x];
            MailMessageEmail($strBody,$strFromEmail,$strFromName,$strTo,'',$strSubject,3,false);
        }
    }

}

function _plugin_serverstatus_parseUptime($tuptime) {
     $uptimeString = "";
     $secs = round($tuptime % 60);
     $mins = round($tuptime / 60 % 60);
     $hours = round($tuptime / 3600 % 24);
     $days = round($tuptime / 86400);

     if ($days > 0) {
       $uptimeString .= $days;
       $uptimeString .= ($days == 1) ? " day " : " days ";
     }

     if ($hours > 0) {
       $uptimeString .= $hours;
       $uptimeString .= ($hours == 1) ? " hour " : " hours ";
     }

     if ($mins > 0) {
       $uptimeString .= $mins;
       $uptimeString .= ($mins == 1) ? " minute " : " minutes ";
     }

     $uptimeString .= $secs;
     $uptimeString .= ($secs == 1) ? " second " : " seconds ";

     return $uptimeString;
}

function _plugin_serverstatus_updateUptimeStatus($uptime, $serverId, $serverName, $arrEmails) {
    $newStatus = "Uptime-> server: $serverId uptime: $uptime";
    $result = $GLOBALS['db']->query("SELECT id, time, status FROM services_log "
                                   ."WHERE status LIKE ? ORDER BY time DESC", "Uptime-> server: $serverId%");
    if (($row = $result->fetch()) && ($id = $row['id']) && ($status = $row['status']) && ($time = $row['time'])) {
        $GLOBALS['db']->query("UPDATE services_log "
                             ."SET time = ?, status = ? "
                             ."WHERE id = ?", date('Y-m-d H:i:s'), $newStatus, $id);
        $lastChecked = strtotime($time);
        preg_match('/uptime: (\d+)/', $status, $matches);
        $lastUptime = $matches[1];
        list($year, $month, $day, $hour, $minute, $second) = sscanf($time, '%d-%d-%d %d:%d:%d');
        $lastChecked = mktime($hour, $minute, $second, $month, $day, $year);
        // +10 to avoid false alarms caused by latencies in the uptime extraction from the server
        if ($uptime - $lastUptime + 10 < time() - $lastChecked) {
            if ($arrEmails) {
                _plugin_serverstatus_email($arrEmails, false, lang('Server %s has been restarted since the last check.', $serverName));
            }
            return lang('Server %s has been restarted since the last check.', $serverName);
        }
    } else {
        $GLOBALS['db']->query("INSERT INTO services_log VALUES(NULL, 'serverstatus', ?, 0, '', '', ?)", date('Y-m-d H:i:s'), $newStatus);
    }
}

function _plugin_serverstatus_getXMLData($statsurl, $serverId, $serverName, $arrEmails) {
    $strErrorMessage = "";
    $xmldata = curlRequest($statsurl, false, false, true, true);
    $status = "Server not responding-> server: $serverId";
    $result = $GLOBALS['db']->query("SELECT id, status FROM services_log "
                                   ."WHERE status = ?", $status);
    if ($row = $result->fetch()) {
        $notified = true;
    } else {
        $notified = false;
    }

    if (is_error($xmldata)) {
        if (!$notified) {
            $GLOBALS['db']->query("INSERT INTO services_log VALUES(NULL, 'serverstatus', ?, 0, '', '', ?)", date('Y-m-d H:i:s'), $status);
            if ($arrEmails) {
                _plugin_serverstatus_email($arrEmails, false, lang('Server %s is not responding.', $serverName));
            }
        }
        return lang('Server %s is not responding.', $serverName);
    } elseif ($notified) {
        if ($arrEmails) {
            _plugin_serverstatus_email($arrEmails,
                                       false,
                                       "Server $serverName is now responding.");
        }
        $GLOBALS['db']->query("DELETE FROM services_log WHERE status = ?", $status);
    }

    return $xmldata;
}

?>
