#! /usr/bin/php
<?php

define( "VERSION", 0.01 );


// Don't mess up the output with warnings/errors
ini_set( 'display_errors', false );

define( "STATUS_OK",       0 );
define( "STATUS_WARNING",  1 );
define( "STATUS_CRITICAL", 2 );
define( "STATUS_UNKNOWN",  3 );


////////////////////////////////////////
// PARSE COMMAND LINE ARGUMENTS
////////////////////////////////////////

$i = 1;

$valid_commands = array(
    "core show channels",
    "pri show spans",
    "sip show channels",
    "sip show peers",
    "dahdi show status"
);

if( $argc == 1 ) {
    printHelp();
    exit( STATUS_UNKNOWN );
}

// defaults
$warning  = 2;
$critical = 1;
$num_pris = 0;
$port = 5038;
$username = '';
$password = '';
$host = '';
$timeout = 10;
$verbose = false;
$command = false;

$required_params = 3;
$required_params_got = 0;


while( $i < $argc ) {

    if( $argv[$i][0] != '-' ) {
        $i++;
        continue;
    }

    switch( $argv[$i][1] ) {

        case 'h':
        case '?':
            printHelp();
            exit( STATUS_OK );
            break;
            
        case 'V':
            printVersion();
            exit( STATUS_OK );
            break;
            
        case 'v':
            $verbose = true;
            $i++;
            break;
            
        case 'U':
            $username = $argv[$i+1];
            $i++;
            $required_params_got++;
            break;

        case 'P':
            $password = $argv[$i+1];
            $i++;
            $required_params_got++;
            break;

        case 'c':
            $critical = $argv[$i+1];
            $i++;
            break;
            
        case 'w':
            $warning = $argv[$i+1];
            $i++;
            break;
            
        case 't':
            $timeout = $argv[$i+1];
            $i++;
            break;
            
        case 'H':
            $host = $argv[$i+1];
            $i++;
            $required_params_got++;
            break;
            
        case '-':
        case 'h':
        case '?':
            printHelp();
            exit( STATUS_OK );
            break;
            
        case 'C':
            $command = $argv[$i+1];
            $i++;
            break;

        default:
            $i++;
    }

}

// Make sure we don't run indefinitly
ini_set( 'max_execution_time', $timeout+5 );

if (array_search($command,$valid_commands) === false) {
   print "You must provide a valid command with -C argument, please view below.\n";
   printHelp();
   exit( STATUS_UNKNOWN );
}

if( $required_params != $required_params_got ) {
    echo "Host, Username and Password are required.\n";
    printHelp();
    exit( STATUS_CRITICAL );
}


if ($verbose) echo "Input data validation suceeded, let's run the command\n";
$ret = connectAndRun();

$funcName = str_replace(" ","_",$command);
if ($verbose) echo "Running function $funcName\n";

if (!function_exists($funcName)) {
	echo "Ops, an unexpected error occurred. Please contact OpServices\n";
	exit( STATUS_UNKNOWN );
}

exit( $funcName($ret) );


function dahdi_show_status($arr) {

	$aDahdi = array();

	//Description                              Alarms  IRQ    bpviol CRC4   Fra Codi Options  LBO
	//AP404 Card 1 Span 1                      OK      0      1      122    CCS HDB3 CRC4     0 db (CSU)/0-133 feet (DSX-1)
	foreach($arr as $line) {
		if (preg_match("/^(.+) {7,}([^ ]+) +([^ ]+) +([^ ]+) +([^ ]+) +([^ ]+) +([^ ]+) +([^ ]+) +([^ ]+) +(.+)$/",$line,$matches)) {

			$a = new StdClass();
			$a->description = preg_replace("/ {2,}/"," ",$matches[1]);
			$a->alarms = $matches[2];
			$a->irq = $matches[3];
			$a->bpviol = $matches[4];
			$a->crc4 = $matches[5];
			$a->fra = $matches[6];
			$a->codi = $matches[7];
			$a->options = $matches[8];
			$a->lbo = $matches[9];

			$aDahdi[] = $a;
		}
	}


	$count = count($aDahdi);
	$retCode = STATUS_OK;
	$alarms = "Alarms: ";
	foreach($aDahdi as $d) {
		if ($d->alarms != "OK") {
			$alarms .= " {$d->description}({$d->alarms})";
			$retCode = STATUS_CRITICAL;
		}
	}

	if ($retCode == STATUS_OK)
		print "OK - No alarms among $count dahdi\n";
	else
		print "CRITICAL - $alarms\n";

	return $retCode;
}


function sip_show_channels($arr) {

	global $warning;
	global $critical;

	// Peer             User/ANR    Call ID          Format           Hold     Last Message
	//  201.33.209.194   3904383132  1393637-3478951  0x100 (g729)     No       Rx: ACK
	$channels = array();
	foreach($arr as $line) {
		if (preg_match("/^([^ ]+) +([^ ]+) +([^ ]+) +([^ ]+) +([^ ]+) +([^ ]+) +([^ ]+) +([^ ]+) *$/", $line, $matches)) {
			
			$c = new StdClass();
			$c->peer = $matches[1];
			$c->useranr = $matches[2];
			$c->callid = $matches[3];
			$c->format = $matches[4]." ".$matches[5];
			$c->hold = $matches[6];
			$c->lastMessage = $matches[7]." ".$matches[8];

			$channels[]  = $c;
		}
	}

	$count = count($channels);
	if ($count >= $critical) {
		print "CRITICAL - $count sip channels | channels=$count;$warning;$critical;0;\n";
		return STATUS_CRITICAL;
	} elseif ($count >= $warning) {
		print "WARNING - $count sip channels | channels=$count;$warning;$critical;0;\n";
		return STATUS_WARNING;
	}

	print "OK - $count sip channels | channels=$count;$warning;$critical;0;\n";
	return STATUS_OK;

}

function pri_show_spans($arr) {

	$spans = array();
	foreach($arr as $line) {
		if (preg_match("/^(PRI .+):(.+)$/", $line, $matches)) {
			$s = new StdClass();
			$s->id = $matches[1];
			$s->state = $matches[2];
			$spans[] = $s;
		}
	}

	$count = count($spans);
	if ($count == 0) {
		print "CRITICAL - Unable to find spans\n";
		return STATUS_CRITICAL;
	}

	$retCode = STATUS_OK;
	$outStr = "Spans with problem: ";
	foreach($spans as $s) {

		if (strstr($s->state,"Down") !== false || strstr($s->state,"Alarm")) {
			$retCode = STATUS_CRITICAL;
			$outStr .= " $s->id($s->state)";
		}
	}

	if ($retCode == STATUS_OK) {
		print "OK - All $count spans verified sucessfully\n";
	} else {
		print $outStr."\n";
	}

	return $retCode;
}


function core_show_channels($arr) {

	$channels = array();
	$first = true;
	foreach($arr as $line) {

		if (preg_match("/^([^ ]+) +([^ ]+) +([^ ]+) +([^ ]+) +$/",$line,$matches)) {

			if ($first) {
				$first = false;
				continue;
			}

			$c = new StdClass();
			$c->channel = $matches[1];
			$c->location = $matches[2];
			$c->state = $matches[3];
			$c->application = $matches[4];

			$channels[] = $c;
		}

	}

	$count = count($channels);
	if ($count == 0) {
		print "CRITICAL - Unable to find channels\n";
		return STATUS_CRITICAL;
	}

	$retCode = STATUS_OK;
	$outStr = "Channels with problem: ";


	foreach($channels as $c) {

		if ($c->state !=  "Up" && $c->state != "Ring") {
			$retCode = STATUS_CRITICAL;
			$outStr .= " ".$c->channel;
		}
	}

	if ($retCode == STATUS_OK) {
		print "OK - All $count channels in Up or Ring state\n";
	} else {
		print $outStr."\n";
	}

	return $retCode;

}

function printVersion() {
	global $argv;
	printf( "{$argv[0]} (Nagios Plugin) %0.2f\n", VERSION );
}

function connectAndRun() {

	global $host;
	global $port;
	global $errno;
	global $errstr;
	global $timeout;
	global $command;
	global $verbose;
	global $username;
	global $password;
	$asttext = "";

	if ($verbose) echo "Connect and run - $command\n";

	if (!$command) {
		print "You must provide a valid command with -C argument, please view below.\n";
		printHelp();
		exit( STATUS_UNKNOWN );
	}

	if( ( $astsock = @fsockopen( $host, $port, $errno, $errstr, $timeout ) ) === false ) {
		echo "Could not connect to Asterisk manager: $errstr\n";
		exit( STATUS_CRITICAL );
	}

	fputs( $astsock, "Action: Login\r\n");
	fputs( $astsock, "UserName: $username\r\n");
	fputs( $astsock, "Secret: $password\r\n\r\n");
	fputs( $astsock, "Action: Command\r\n");
	fputs( $astsock, "Command: $command\r\n\r\n");
	fputs( $astsock, "Action: Logoff\r\n\r\n");

	while( !feof( $astsock ) ) {
		$asttext .= fread( $astsock, 8192 );
	}

	fclose( $astsock );

	if( strpos( $asttext, "Authentication failed" ) !== false ) {
		echo "Asterisk manager authentication failed.\n";
		exit( STATUS_CRITICAL );
	}

	if( strpos( $asttext, "Permission denied" ) !== false ) {
		echo "Asterisk manager permission denied for Command.\n";
		exit( STATUS_CRITICAL );
	}


	$aRet = array();
	$aRet = explode("\n",$asttext);
	
	return $aRet;

}



function printHelp()
{
    global $argv, $timeout, $port, $valid_commands;
    
    echo <<<END_USAGE

check_asterisk - Nagios plugin to check Asterisk Manager state
Copyright (c) 2007 Open Source Solutions Ltd - http://www.opensolutions.ie/

This plugin will query the Asterisk service via the manager interface for the
status and interpret the output.

{$argv[0]} -H host -U username -P password -C command [-p port] [-w warn] [-c crit] 
        [-t timeout] [-v] [-h] [-?] [--help]

Options:

 -h,-?,--help 
    Print detailed help screen
 -V
    Print version information
 -H
    IP address of the Asterisk host
 -U
    Asterisk manager username
 -P 
    Password for the Asterisk manager user
 -C
    Command to be checked(see below)
 -p
    Asterisk manager port (default $port)
 -c
    When the number of provisioned and up PRIs reach this, a critical warning will be generated
 -w
    When the number of provisioned and up PRIs reach this, a warning will be generated
 -t 
    How many seconds to wait before timing out when connecting to the Asterisk manager
    (default $timeout)
 -v
    Verbose; print the Asterisk manager session
    

END_USAGE;

print " Commands:\n";
foreach($valid_commands as $vc) {
	print "   $vc\n";
}


}

?>
