Remove hint processing from __Construct and place in getbuttons, only place where used Return hint information in correct format from ami, to avoid second formatting Optimise db calls for hints to speed loading of add/edit device.
453 lines
12 KiB
PHP
453 lines
12 KiB
PHP
<?php
|
|
|
|
/**
|
|
*
|
|
* Core Comsnd Interface
|
|
*
|
|
* https://www.voip-info.org/asterisk-manager-example-php/
|
|
*/
|
|
/* !TODO!: Re-Indent this file. -TODO-: What do you mean? coreaccessinterface ?? */
|
|
|
|
namespace FreePBX\modules\Sccp_manager\aminterface;
|
|
|
|
class AMIException extends \Exception
|
|
{
|
|
|
|
}
|
|
|
|
abstract class Message
|
|
{
|
|
const EOL = "\r\n";
|
|
const EOM = "\r\n\r\n";
|
|
|
|
protected $lines;
|
|
protected $variables;
|
|
protected $keys;
|
|
protected $createdDate;
|
|
private $_responseHandler;
|
|
|
|
public function __construct()
|
|
{
|
|
$this->lines = array();
|
|
$this->variables = array();
|
|
$this->keys = array();
|
|
$this->createdDate = time();
|
|
}
|
|
|
|
public function _ToDebug($level, $msg)
|
|
{
|
|
}
|
|
|
|
public function getResponseHandler()
|
|
{
|
|
if (strlen($this->_responseHandler) > 0) {
|
|
// throw new AMIException('Hier:' . $this->_responseHandler);
|
|
return (string) $this->_responseHandler;
|
|
} else {
|
|
return "";
|
|
}
|
|
}
|
|
|
|
public function setResponseHandler($responseHandler)
|
|
{
|
|
if (0 == strlen($responseHandler)) {
|
|
return;
|
|
}
|
|
$className = '\\FreePBX\\modules\\Sccp_manager\\aminterface\\' . $responseHandler . '_Response';
|
|
if (class_exists($className, true)) {
|
|
$this->_responseHandler = $responseHandler;
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
|
|
public function setVariable($key, $value)
|
|
{
|
|
$key = strtolower($key);
|
|
$this->variables[$key] = $value;
|
|
/* print_r('<br>----Set Value -------<br>');
|
|
print_r($key);
|
|
print_r($value);
|
|
*/
|
|
}
|
|
/*
|
|
// Duplicate declaration - also declared in Response class where is used.
|
|
public function getVariable($key)
|
|
{
|
|
$key = strtolower($key);
|
|
|
|
if (!isset($this->variables[$key])) {
|
|
return null;
|
|
}
|
|
return $this->variables[$key];
|
|
}
|
|
*/
|
|
protected function setKey($key, $value)
|
|
{
|
|
$key = strtolower((string) $key);
|
|
$this->keys[$key] = (string) $value;
|
|
}
|
|
|
|
public function getKey($key)
|
|
{
|
|
$key = strtolower($key);
|
|
if (!isset($this->keys[$key])) {
|
|
return null;
|
|
}
|
|
//return (string)$this->keys[$key];
|
|
return $this->keys[$key];
|
|
}
|
|
|
|
public function getVariables()
|
|
{
|
|
return $this->variables;
|
|
}
|
|
/*
|
|
public function getActionID()
|
|
{
|
|
return $this->getKey('ActionID');
|
|
}
|
|
*/
|
|
public function getKeys()
|
|
{
|
|
return $this->keys;
|
|
}
|
|
|
|
private function serializeVariable($key, $value)
|
|
{
|
|
return "Variable: $key=$value";
|
|
}
|
|
|
|
protected function setSanitizedKey($key, $value)
|
|
{
|
|
// TODO: Need to handle JSON here rather than in getVariable as have
|
|
// already broken data into array.
|
|
$key = strtolower($key);
|
|
switch ($key) {
|
|
case 'json':
|
|
//$this->keys['JSONRAW'] = (string) $value;
|
|
$this->keys['json'] = (string) $value;
|
|
break;
|
|
case 'response':
|
|
case 'actionid':
|
|
case 'desc':
|
|
$this->keys[$key] = (string) $value;
|
|
break;
|
|
default:
|
|
$this->keys[$key] = $this->sanitizeInput($value);
|
|
break;
|
|
}
|
|
|
|
/*
|
|
$_string_key = array('actionid', 'descr');
|
|
if (array_search($key, $_string_key) !== false) {
|
|
$this->keys[$key] = (string) $this->sanitizeInput($value, 'string');
|
|
} else {
|
|
$this->keys[$key] = $this->sanitizeInput($value);
|
|
}
|
|
*/
|
|
}
|
|
|
|
protected function sanitizeInput($value, $prefered_type = '')
|
|
{
|
|
if ($prefered_type == '') {
|
|
// No longer send empty values
|
|
//if (!isset($value) || $value === null || strlen($value) == 0) {
|
|
//return null;
|
|
//} elseif (is_numeric($value)) {
|
|
if (is_numeric($value)) {
|
|
$prefered_type = 'numeric';
|
|
} elseif (is_string($value)) {
|
|
$prefered_type = 'string';
|
|
} else {
|
|
throw new AMIException("Don't know how to convert: '" . $value . "'\n");
|
|
}
|
|
}
|
|
//if ($prefered_type !== '') {
|
|
switch ($prefered_type) {
|
|
case 'string':
|
|
//if (!isset($value) || $value === null || strlen($value) == 0) {
|
|
//return '';
|
|
//}
|
|
if (filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE)) {
|
|
return (boolean) $value;
|
|
} elseif (filter_var($value, FILTER_SANITIZE_STRING, FILTER_NULL_ON_FAILURE)) {
|
|
return (string) $value;
|
|
} elseif (filter_var($value, FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_NULL_ON_FAILURE)) {
|
|
return (string) htmlspecialchars($value, ENT_QUOTES);
|
|
} else {
|
|
throw new AMIException("Incoming String is not sanitary. Skipping: '" . $value . "'\n");
|
|
}
|
|
break;
|
|
case 'numeric':
|
|
//if (!isset($value) || $value === null || strlen($value) == 0) {
|
|
//return 0;
|
|
//}
|
|
if (filter_var($value, FILTER_VALIDATE_INT, FILTER_FLAG_ALLOW_HEX | FILTER_FLAG_ALLOW_OCTAL)) {
|
|
return intval($value, 0);
|
|
} elseif (filter_var($value, FILTER_VALIDATE_FLOAT, FILTER_FLAG_ALLOW_FRACTION | FILTER_FLAG_ALLOW_THOUSAND | FILTER_FLAG_ALLOW_SCIENTIFIC)) {
|
|
return (float) $value;
|
|
} else {
|
|
return (double) $value;
|
|
}
|
|
default:
|
|
throw new AMIException("Don't know how to convert: '" . $value . "'\n");
|
|
break;
|
|
}
|
|
//}
|
|
}
|
|
|
|
protected function finishMessage($message)
|
|
{
|
|
return $message . self::EOL . self::EOL;
|
|
}
|
|
|
|
public function serialize()
|
|
{
|
|
$result = array();
|
|
foreach ($this->getKeys() as $k => $v) {
|
|
$result[] = $k . ': ' . $v;
|
|
}
|
|
foreach ($this->getVariables() as $k => $v) {
|
|
if (is_array($v)) {
|
|
foreach ($v as $singleValue) {
|
|
$result[] = $this->serializeVariable($k, $singleValue);
|
|
}
|
|
} else {
|
|
$result[] = $this->serializeVariable($k, $v);
|
|
}
|
|
}
|
|
$mStr = $this->finishMessage(implode(self::EOL, $result));
|
|
return $mStr;
|
|
}
|
|
|
|
public function setActionID($actionID)
|
|
{
|
|
if (0 == strlen($actionID)) {
|
|
throw new AMIException('ActionID cannot be empty.');
|
|
return;
|
|
}
|
|
|
|
if (strlen($actionID) > 69) {
|
|
throw new AMIException('ActionID can be at most 69 characters long.');
|
|
return;
|
|
}
|
|
|
|
$this->setKey('ActionID', $actionID);
|
|
}
|
|
|
|
public function __sleep()
|
|
{
|
|
return array('lines', 'variables', 'keys', 'createdDate');
|
|
}
|
|
}
|
|
|
|
abstract class IncomingMessage extends Message
|
|
{
|
|
|
|
protected $rawContent;
|
|
|
|
public function getEventList()
|
|
{
|
|
return $this->getKey('EventList');
|
|
}
|
|
|
|
public function getRawContent()
|
|
{
|
|
return $this->rawContent;
|
|
}
|
|
|
|
public function isComplete()
|
|
{
|
|
return $this->_completed;
|
|
}
|
|
|
|
public function __sleep()
|
|
{
|
|
$ret = parent::__sleep();
|
|
$ret[] = 'rawContent';
|
|
return $ret;
|
|
}
|
|
|
|
public function __construct($rawContent)
|
|
{
|
|
parent::__construct();
|
|
//dbug($rawContent);
|
|
$this->rawContent = $rawContent;
|
|
$lines = explode(Message::EOL, $rawContent);
|
|
foreach ($lines as $line) {
|
|
$content = explode(':', $line);
|
|
//$content = preg_split("/: /",$line);
|
|
//$name = strtolower(trim($content[0]));
|
|
// do strtolower in setSanitizedKey
|
|
$name = array_shift($content);
|
|
//unset($content[0]);
|
|
if (!isset($content[0])) {
|
|
continue;
|
|
}
|
|
//$value = isset($content[0]) ? trim(implode(':', $content)) : '';
|
|
try {
|
|
$this->setSanitizedKey($name, trim(implode(':', $content)));
|
|
} catch (AMIException $e) {
|
|
throw new AMIException("Error: '" . $e . "'\n Dump RawContent:\n" . $this->rawContent . "\n");
|
|
}
|
|
//dbug($this->keys);
|
|
}
|
|
//dbug($this->keys);
|
|
}
|
|
}
|
|
|
|
// namespace FreePBX\modules\Sccp_manager\aminterface\Message;
|
|
class LoginAction extends ActionMessage
|
|
{
|
|
|
|
/**
|
|
* Constructor.
|
|
*
|
|
* @param string $user AMI username.
|
|
* @param string $password AMI password.
|
|
*
|
|
* @return void
|
|
*/
|
|
public function __construct($user, $password)
|
|
{
|
|
parent::__construct('Login');
|
|
$this->setKey('Username', $user);
|
|
$this->setKey('Secret', $password);
|
|
$this->setKey('Events', 'off'); // &----
|
|
$this->setResponseHandler('Login');
|
|
}
|
|
}
|
|
|
|
abstract class ActionMessage extends Message
|
|
{
|
|
|
|
public function __construct($what)
|
|
{
|
|
parent::__construct();
|
|
$this->setKey('Action', $what);
|
|
$this->setKey('ActionID', microtime(true));
|
|
}
|
|
}
|
|
|
|
class CommandAction extends ActionMessage
|
|
{
|
|
public function __construct($command)
|
|
{
|
|
parent::__construct('Command');
|
|
$this->setKey('Command', $command);
|
|
$this->setResponseHandler("Command");
|
|
}
|
|
}
|
|
|
|
class ReloadAction extends ActionMessage
|
|
{
|
|
|
|
public function __construct($module = false)
|
|
{
|
|
parent::__construct('Reload');
|
|
if ($module !== false) {
|
|
$this->setKey('Module', $module);
|
|
$this->setResponseHandler("Generic");
|
|
}
|
|
}
|
|
}
|
|
|
|
class ExtensionStateListAction extends ActionMessage
|
|
{
|
|
|
|
public function __construct()
|
|
{
|
|
parent::__construct('ExtensionStateList');
|
|
//$this->setKey('Segment', 'general');
|
|
//$this->setKey('ResultFormat', 'command');
|
|
$this->setResponseHandler("ExtensionStateList");
|
|
}
|
|
}
|
|
class SCCPShowGlobalsAction extends ActionMessage
|
|
{
|
|
public function __construct()
|
|
{
|
|
parent::__construct('SCCPShowGlobals');
|
|
}
|
|
}
|
|
|
|
class SCCPShowSoftkeySetsAction extends ActionMessage
|
|
{
|
|
|
|
public function __construct()
|
|
{
|
|
parent::__construct('SCCPShowSoftkeySets');
|
|
//$this->setKey('Segment', 'general');
|
|
//$this->setKey('ResultFormat', 'command');
|
|
$this->setResponseHandler("SCCPShowSoftkeySets");
|
|
}
|
|
}
|
|
|
|
class SCCPShowDeviceAction extends ActionMessage
|
|
{
|
|
|
|
public function __construct($devicename)
|
|
{
|
|
parent::__construct('SCCPShowDevice');
|
|
//$this->setKey('Segment', 'general');
|
|
//$this->setKey('ResultFormat', 'command');
|
|
$this->setKey('DeviceName', $devicename);
|
|
$this->setResponseHandler("SCCPShowDevice");
|
|
}
|
|
}
|
|
|
|
class SCCPShowDevicesAction extends ActionMessage
|
|
{
|
|
|
|
public function __construct()
|
|
{
|
|
parent::__construct('SCCPShowDevices');
|
|
//$this->setKey('Segment', 'general');
|
|
//$this->setKey('ResultFormat', 'command');
|
|
$this->setResponseHandler("SCCPShowDevices");
|
|
}
|
|
}
|
|
|
|
class SCCPTokenAckAction extends ActionMessage
|
|
{
|
|
|
|
public function __construct($DeviceName)
|
|
{
|
|
parent::__construct('SCCPTokenAck');
|
|
$this->setKey('DeviceId', $DeviceName);
|
|
$this->setResponseHandler("Generic");
|
|
}
|
|
}
|
|
|
|
class SCCPDeviceRestartAction extends ActionMessage
|
|
{
|
|
|
|
public function __construct($DeviceName, $Type = "restart")
|
|
{
|
|
parent::__construct('SCCPDeviceRestart');
|
|
$this->setResponseHandler("Generic");
|
|
//if (empty($Type)) {
|
|
//$Type = "restart";
|
|
//}
|
|
$this->setKey('DeviceName', $DeviceName);
|
|
if (in_array(strtolower($Type), array('restart', 'full', 'reset'))) {
|
|
$this->setKey('Type', $Type);
|
|
} else {
|
|
throw new Exception('Param2 has to be one of \'restart\', \'full\', \'reset\'.');
|
|
}
|
|
}
|
|
}
|
|
|
|
class SCCPConfigMetaDataAction extends ActionMessage
|
|
{
|
|
public function __construct($segment = false)
|
|
{
|
|
parent::__construct('SCCPConfigMetaData');
|
|
if ($segment != false) {
|
|
$this->setKey('Segment', $segment);
|
|
}
|
|
$this->setResponseHandler("SCCPJSON");
|
|
}
|
|
}
|