diff --git a/Sccp_manager.inc/aminterface/Event.class.php b/Sccp_manager.inc/aminterface/Event.class.php index 640ffd5..a08c50f 100644 --- a/Sccp_manager.inc/aminterface/Event.class.php +++ b/Sccp_manager.inc/aminterface/Event.class.php @@ -26,8 +26,7 @@ abstract class Event extends IncomingMessage { parent::__construct($rawContent); $this->_events = array(); - $this->_eventsCount = 0; -// $this->_completed = !$this->isList(); + $this->_completed = false; } } @@ -35,8 +34,6 @@ class UnknownEvent extends Event { public function __construct($rawContent = '') { -// print_r($rawContent); -// die(); } } @@ -60,28 +57,13 @@ class TableEnd_Event extends Event class SCCPSoftKeySetEntry_Event extends Event { - + // This is a list of tables, each table is an entry protected $_data; - - public function __construct($rawContent) - { - parent::__construct($rawContent); - return null; - } -} - -class SCCPShowSoftKeySetsComplete_Event extends Event -{ - - public function getListItems() - { - return intval($this->getKey('ListItems')); - } } class ExtensionStatus_Event extends Event { - + // this is a list of tables, each table is an entry public function getPrivilege() { return $this->getKey('Privilege'); @@ -110,27 +92,12 @@ class ExtensionStatus_Event extends Event class SCCPDeviceEntry_Event extends Event { - -} - -class SCCPShowDeviceComplete_Event extends Event -{ - - public function getListItems() - { - return intval($this->getKey('ListItems')); - } - public function __construct($rawContent) - { - parent::__construct($rawContent); - $this->_completed = $this->getKey('EventList'); -// return null; - } + // This is a list of tables, each table is an entry } class SCCPShowDevice_Event extends Event { - + // This is a list of tables public function getCapabilities() { $ret = array(); @@ -153,15 +120,6 @@ class SCCPShowDevice_Event extends Event return $ret; } } - -class SCCPShowDevicesComplete_Event extends Event -{ - - public function getListItems() - { - return intval($this->getKey('ListItems')); - } -} class SCCPDeviceButtonEntry_Event extends Event { } @@ -182,7 +140,67 @@ class SCCPDeviceStatisticsEntry_Event extends Event class SCCPDeviceSpeeddialEntry_Event extends Event { } -class ExtensionStateListComplete_Event extends Event +abstract class ClosingEvent extends Event { + public function __construct($message) { + parent::__construct($message); + $this->_completed = true; + } + public function getListItems() { + return intval($this->getKey('ListItems')); + } } +class ResponseComplete_Event extends ClosingEvent +{ + // dummy event to avoid unnecessary testing + public function listCorrectlyReceived($_message, $_eventCount){ + return true; + } +} + +class SCCPShowDeviceComplete_Event extends ClosingEvent +{ + public function listCorrectlyReceived($_message, $_eventCount){ + // Have end of list event. Check with number of lines received and send true if match. + // Remove 9 for the start and end events, and then 4. + if ($this->getKey('listitems') === substr_count( $_message, "\n") -13) { + return true; + } + return false; + } +} +class SCCPShowDevicesComplete_Event extends ClosingEvent +{ + public function listCorrectlyReceived($_message, $_eventCount) { + // Have end of list event. Check with number of events received and send true if match. + // Remove 9 for the lines in the list start and end, and the 2 blank lines. + if ($this->getKey('listitems') === substr_count( $_message, "\n") -11) { + return true; + } + return false; + } +} +class ExtensionStateListComplete_Event extends ClosingEvent +{ + public function listCorrectlyReceived($_message, $_eventCount){ + // Have end of list event. Check with number of events received and send true if match. + // Remove 1 as the closing event is included in the count. + if ($this->getKey('listitems') === $_eventCount -1) { + return true; + } + return false; + } +} + +class SCCPShowSoftKeySetsComplete_Event extends ClosingEvent +{ + public function listCorrectlyReceived($_message, $_eventCount){ + // Have the end of list event. Check the number of lines received and + // return true if match. Remove 8 for the complete event. + if ($this->getKey('listitems') === substr_count( $_message, "\n") -11) { + return true; + } + return false; + } +} diff --git a/Sccp_manager.inc/aminterface/Message.class.php b/Sccp_manager.inc/aminterface/Message.class.php index b109512..d7193c4 100644 --- a/Sccp_manager.inc/aminterface/Message.class.php +++ b/Sccp_manager.inc/aminterface/Message.class.php @@ -176,7 +176,7 @@ abstract class Message return (double) $value; } default: - throw new PAMIException("Don't know how to convert: '" . $value . "'\n"); + throw new AMIException("Don't know how to convert: '" . $value . "'\n"); break; } } @@ -242,6 +242,11 @@ abstract class IncomingMessage extends Message return $this->rawContent; } + public function isComplete() + { + return $this->_completed; + } + public function __sleep() { $ret = parent::__sleep(); @@ -418,6 +423,6 @@ class SCCPConfigMetaDataAction extends ActionMessage if ($segment != false) { $this->setKey('Segment', $segment); } - $this->setResponseHandler("SCCPGeneric"); + $this->setResponseHandler("SCCPJSON"); } } diff --git a/Sccp_manager.inc/aminterface/Response.class.php b/Sccp_manager.inc/aminterface/Response.class.php index 1a00df0..f7e30ed 100644 --- a/Sccp_manager.inc/aminterface/Response.class.php +++ b/Sccp_manager.inc/aminterface/Response.class.php @@ -1,12 +1,10 @@ _events = array(); $this->_eventsCount = 0; - $this->_completed = !$this->isList(); - } - - public function isComplete() - { - return $this->_completed; + $this->_completed = $this->isSuccess(); } public function __sleep() @@ -42,20 +35,19 @@ abstract class Response extends IncomingMessage return $ret; } - public function addEvent($event) - { - $this->_events[] = $event; - if (stristr($event->getEventList(), 'complete') !== false - || stristr($event->getName(), 'complete') !== false - || stristr($event->getName(), 'DBGetResponse') !== false - ) { - $this->_completed = true; - } - } public function getEvents() { return $this->_events; } + public function getClosingEvent() { + return $this->_events['ClosingEvent']; + } + public function removeClosingEvent() { + unset($this->_events['ClosingEvent']); + } + public function getCountOfEvents() { + return count($this->_events); + } public function isSuccess() { @@ -65,10 +57,9 @@ abstract class Response extends IncomingMessage public function isList() { - return - stristr($this->getKey('EventList'), 'start') !== false - || stristr($this->getMessage(), 'follow') !== false - ; + if ($this->getKey('EventList') === 'start' ) { + return true; + } } public function getMessage() @@ -94,36 +85,37 @@ abstract class Response extends IncomingMessage } } } +class GenericResponse extends Response +{ +} + //**************************************************************************** +// There are two types of Response messages returned by AMI +// Self contained responses which include any data requested; +// List Responses which contain the data in event messages that follow +// the response message.Response and Event +// Following are the self contained Response classes. +//**************************************************************************** + class Generic_Response extends Response { - public function __construct($rawContent) { parent::__construct($rawContent); -// print_r('
---- r --
'); -// print_r($rawContent); + // add dummy closing event + $this->_events['ClosingEvent'] = new ResponseComplete_Event($rawContent); } } -class Login_Response extends Response +class Login_Response extends Generic_Response { - - public function __construct($rawContent) - { - parent::__construct($rawContent); - return $this->isSuccess(); - } } -class Command_Response extends Response +class Command_Response extends Generic_Response { private $_temptable; public function __construct($rawContent) { -// print_r('
---- r --
'); -// print_r($rawContent); -// print_r('
---- re --
'); $this->_temptable = array(); parent::__construct($rawContent); $lines = explode(Message::EOL, $rawContent); @@ -150,26 +142,35 @@ class Command_Response extends Response } } } -/* Not required $_temptable cannot be empty as has at least an actionID - see also getResult - if (!empty($this->_temptable)) { - $this->setKey('output', 'array'); - } -*/ - $this->_completed = $this->isSuccess(); -// return $this->isSuccess(); } public function getResult() { -/* Below test no longer valid as key no longer set - if (stristr($this->getKey('output'), 'array') !== false) { - $result = $this->_temptable; - } else { - $result = $this->getMessage(); - } -*/ return $this->_temptable; + return $this->_temptable; } } +class SCCPJSON_Response extends Generic_Response +{ + public function __construct($rawContent) + { + parent::__construct($rawContent); + $this->getVariable($rawContent, array("DataType" => "DataType:", "JSONRAW" => "JSON:")); + if (null !== $this->getKey('JSONRAW')) { + $this->setKey('Response', 'Success'); + } + } + public function getResult() + { + if (($json = json_decode($this->getKey('JSON'), true)) != false) { + return $json; + } + } +} + +//***************************************************************************// +// Following are the Response classes where the data is contained in a series. +// of event messages. + class SCCPGeneric_Response extends Response { protected $_tables; @@ -178,18 +179,15 @@ class SCCPGeneric_Response extends Response public function __construct($rawContent) { parent::__construct($rawContent); - $_fields = array("EventList" => "EventList:", "Message" => "Message:"); + // Confirm that there is a list following. This overrides any setting + // made in one of the parent constructs. $this->_completed = !$this->isList(); } public function addEvent($event) { - if ($event->getEventList() === 'start') { - // Have started a list of events; this may include tables - // Nothing to do with this event, only need to handle - // the events that follow - return; - } + // Start of list is handled by the isList function in the Constructor + // which also defines the list end event if ( empty($thisSetEventEntryType)) { // This is empty as soon as we have received a TableStart. @@ -201,8 +199,9 @@ class SCCPGeneric_Response extends Response $thisSetEventEntryType = 'undefinedAsThisIsNotASet'; } } - $unknownevent = "FreePBX\\modules\\Sccp_manager\\aminterface\\UnknownEvent"; - if ($event instanceof $unknownevent) { + // Unknown events will cause an exception. + // All event classes must be defined within Event.class. + if (get_class($event) === 'FreePBX\modules\Sccp_manager\aminterface\UnknownEvent') { $this->_events[] = $event; return; } @@ -230,18 +229,20 @@ class SCCPGeneric_Response extends Response // If counts do not match return false and table will not be //loaded if ($event->getKey('TableEntries') != count($this->_tables[$event->getTableName()]['Entries'])) { - return $this->_completed = false; + return false; } break; + //case $eventListEndEvent; + case $this->getKey('eventListEndEvent'); + // Have the list end event. The correct number of entries is verified in the event constructor + $this->_events['ClosingEvent'] = $event; + $this->eventListEndEvent = null; + //return $this->_completed = true; + break; default: // add regular list event $this->_events[] = $event; } - - if ($event->getEventList() === 'Complete') { - // Received a complete eventList. - return $this->_completed = true; - } } protected function ConvertTableData(String $_tablename, Array $_fkey, Array $_fields) @@ -305,19 +306,6 @@ class SCCPGeneric_Response extends Response return $result; } -/* public function hasTable() - { - if (is_array($this->_tables)) { - return true; - } - return false; - } - - public function getTableNames() - { - return (is_array($this->_tables)) ? array_keys($this->_tables) : null; - } -*/ public function Table2Array( String $tablename ) { $result =array(); @@ -330,79 +318,28 @@ class SCCPGeneric_Response extends Response return $result; } -/* public function Events2Array() - { - $result =array(); - foreach ($this->_events as $trow) { - // $tmp_result = $trow->getKeys(); - // if (is_array($tmp_result)) { - $result = array_merge($result, $trow->getKeys()); - //} else { - // $result [] = $tmp_result; - // } - } - return $result; - } - - public function getTable($tablename) - { - if (is_array($this->_tables) && array_key_exists($tablename, $this->_tables)) { - return $this->_tables[$tablename]; - } - throw new PAMIException("No such table."); - } - - public function getJSON() - { - if (strlen($this->getKey('JSON')) > 0) { - if (($json = json_decode($this->getKey('JSON'), true)) != false) { - return $json; - } - } - throw new AMIException("No JSON Key found to return."); - } -*/ public function getResult() { - if ($this->getKey('JSON') !== null && !empty($this->getKey('JSON'))) { - if (($json = json_decode($this->getKey('JSON'), true)) != false) { - return $json; - } - } else { return $this->getMessage(); - } } } -class SCCPJSON_Response extends Response -{ - public function __construct($rawContent) - { - parent::__construct($rawContent); - $this->getVariable($rawContent, array("DataType" => "DataType:", "JSONRAW" => "JSON:")); - if (null !== $this->getKey('JSONRAW')) { - $this->setKey('Response', 'Success'); - } - return $this->isSuccess(); - } -} class SCCPShowSoftkeySets_Response extends SCCPGeneric_Response { public function __construct($rawContent) { parent::__construct($rawContent); + $this->setKey('eventlistendevent', 'SCCPShowSoftKeySetsComplete'); } public function getResult() { - // $_fields = array('description'=>'description','label'=>'label','lblid'=>'lblid'); return $this->ConvertTableData( 'SoftKeySets', array('set','mode'), array('description'=>'description','label'=>'label','lblid'=>'lblid') ); - // return $result; } } @@ -411,18 +348,16 @@ class SCCPShowDevices_Response extends SCCPGeneric_Response public function __construct($rawContent) { parent::__construct($rawContent); + $this->setKey('eventlistendevent', 'SCCPShowDevicesComplete'); } public function getResult() { -// $_fields = array('mac'=>'mac','address'=>'address','descr'=>'descr','regstate'=>'status', -// 'token'=>'token','act'=>'act', 'lines'=>'lines','nat'=>'nat','regtime'=>'regtime'); return $this->ConvertTableData( 'Devices', array('mac'), array('mac'=>'name','address'=>'address','descr'=>'descr','regstate'=>'status', 'token'=>'token','act'=>'act', 'lines'=>'lines','nat'=>'nat','regtime'=>'regtime') ); -// return $result; } } @@ -431,6 +366,7 @@ class SCCPShowDevice_Response extends SCCPGeneric_Response public function __construct($rawContent) { parent::__construct($rawContent); + $this->setKey('eventlistendevent', 'SCCPShowDeviceComplete'); } public function getResult() { @@ -440,6 +376,7 @@ class SCCPShowDevice_Response extends SCCPGeneric_Response foreach ($this->_events as $trow) { $result = array_merge($result, $trow->getKeys()); } + // Now handle label changes so that keys from AMI correspond to db keys in _tables $result['Buttons'] = $this->ConvertTableData( 'Buttons', array('id'), @@ -479,6 +416,7 @@ class ExtensionStateList_Response extends SCCPGeneric_Response public function __construct($rawContent) { parent::__construct($rawContent); + $this->setKey('eventlistendevent', 'ExtensionStateListComplete'); } public function getResult() { diff --git a/Sccp_manager.inc/aminterface/aminterface.class.php b/Sccp_manager.inc/aminterface/aminterface.class.php index 428717f..008bf30 100644 --- a/Sccp_manager.inc/aminterface/aminterface.class.php +++ b/Sccp_manager.inc/aminterface/aminterface.class.php @@ -6,7 +6,6 @@ * * 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; @@ -17,17 +16,15 @@ class aminterface var $_error; var $_config; var $_test; - var $_countE; private $_connect_state; -// var $ProcessingMessage; private $_lastActionClass; private $_lastActionId; private $_lastRequestedResponseHandler; private $_ProcessingMessage; private $_DumpMessage; - private $_eventFactory; - private $_responseFactory; private $debug_level = 1; + private $_incomingRawMessage; + private $eventListEndEvent; public function load_subspace($parent_class = null) { @@ -56,10 +53,10 @@ class aminterface $this->_error = array(); $this->_config = array('host' => 'localhost', 'user' => '', 'pass' => '', 'port' => '5038', 'tsoket' => 'tcp://', 'timeout' => 30, 'enabled' => true); $this->_eventListeners = array(); -// $this->_eventFactory = new EventFactoryImpl(\Logger::getLogger('EventFactory')); -// $this->_responseFactory = new ResponseFactoryImpl(\Logger::getLogger('ResponseFactory')); - $this->_incomingQueue = array(); + $this->_incomingMsgObjectList = array(); $this->_lastActionId = false; + $this->_incomingRawMessage = array(); + $this->eventListEndEvent = ''; $fld_conf = array('user' => 'AMPMGRUSER', 'pass' => 'AMPMGRPASS'); if (isset($amp_conf['AMPMGRUSER'])) { @@ -86,7 +83,7 @@ class aminterface public function info() { $Ver = '13.0.4'; - if ($this->_config['enabled']) { + if ($this->_config['enabled']){ return array('Version' => $Ver, 'about' => 'AMI data ver: ' . $Ver, 'test' => get_declared_classes()); } else { @@ -95,9 +92,8 @@ class aminterface } } - /** - * Opens a tcp connection to ami. - * + /* + * Opens a socket connection to ami. */ public function open() { @@ -134,7 +130,7 @@ class aminterface return true; } - /** + /* * Closes the connection to ami. */ public function close() @@ -143,80 +139,86 @@ class aminterface $this->_ProcessingMessage = ''; @stream_socket_shutdown($this->_socket, STREAM_SHUT_RDWR); } - + /* + * Send action message to ami, and wait for Response + */ public function send($message) { + $_incomingRawMessage = array(); $messageToSend = $message->serialize(); $length = strlen($messageToSend); - $this->_countE = 0; $this->_DumpMessage = ''; - $this->_lastActionId = $message->getActionId(); + $this->_lastActionId = $message->getActionID(); $this->_lastRequestedResponseHandler = $message->getResponseHandler(); $this->_lastActionClass = $message; + $this->_incomingRawMessage[$this->_lastActionId] = ''; + $this->eventListIsCompleted = array(); if (@fwrite($this->_socket, $messageToSend) < $length) { $this->_errorException('Could not send message'); return false; } - $time_connect = microtime_float(); - $this->_msgToDebug(90, 'Time: '. ($time_connect)); - while (1) { + // Have sent a message and now have to wait for and read the reply + // The below infinite loop waits for $this->completed to be true. + // The loop calls readBuffer, which calls GetMessages, which calls Process + // This loop then continues until we have _thisComplete as an object variable + $this->eventListIsCompleted[$this->_lastActionId] = false; + while (true) { stream_set_timeout($this->_socket, 1); -// stream_set_timeout($this->_socket, (isset($this->socket_param['timeout']) ? $this->socket_param['timeout'] : 1)); - $this->process(); - $time_co = microtime_float(); - $this->_msgToDebug(90, 'Time: '. ($time_co-$time_connect)); + $this->readBuffer(); $info = stream_get_meta_data($this->_socket); - if ($info['timed_out'] == false) { - $response = $this->getRelated($message); - if ($response != false) { - $this->_lastActionId = false; - $this->_msgToDebug(98, '---- Dump MSG -------'); - $this->_msgToDebug(98, $this->_DumpMessage); + if ($info['timed_out'] == true) { + $this->_errorException("Read waittime: " . ($this->socket_param['timeout']) . " exceeded (timeout).\n"); + return false; + } + if ($this->eventListIsCompleted[$this->_lastActionId]) { + $response = $this->_incomingMsgObjectList[$this->_lastActionId]; + // need to test that the list was successfully completed here + $allReceived = $response->getClosingEvent() + ->listCorrectlyReceived($this->_incomingRawMessage[$this->_lastActionId], + $response->getCountOfEvents()); + // now tidy up removing any temp variables or objects + $response->removeClosingEvent(); + unset($_incomingRawMessage[$this->_lastActionId]); + unset($this->_incomingMsgObjectList[$this->_lastActionId]); + unset($this->_lastActionId); + if ($allReceived) { return $response; } - } else { - break; + // Something is missing from the events list received via AMI, or + // the control parameter at the end of the list has changed. + // This will cause an exception as returning a boolean instead of a Response + // Maybe should handle better, but + // need to break out of the loop as nothing more coming. + try { + throw new \invalidArgumentException("Counts do not match on returned AMI Result"); + } catch ( \invalidArgumentException $e) { + echo substr(strrchr(get_class($response), '\\'), 1), " ", $e->getMessage(), "\n"; + } + return $response; } } - $this->_errorException("Read waittime: " . ($this->socket_param['timeout']) . " exceeded (timeout).\n"); } - protected function getRelated($message) + protected function readBuffer () { - $ret = false; - $id = 0; - $id = $message->getActionID('ActionID'); - if (isset($this->_incomingQueue[$id])) { - $response = $this->_incomingQueue[$id]; - if ($response->isComplete()) { - unset($this->_incomingQueue[$id]); - $ret = $response; - } + $read = @fread($this->_socket, 65535); + // AMI never returns EOF + if ($read === false ) { + $this->_errorException('Error reading'); } - return $ret; - } - - private function _messageToEvent($msg) - { - return $this->_eventFromRaw($msg); + // Do not return empty Messages + while ($read == "" ) { + $read = @fread($this->_socket, 65535); + } + // Add read to the rest of buffer from previous read + $this->_ProcessingMessage .= $read; + $this->getMessages(); } protected function getMessages() { $msgs = array(); - // Read something. - $read = @fread($this->_socket, 65535); - if ($read === false || @feof($this->_socket)) { - $this->_errorException('Error reading'); - } - - if ($read == "") { - usleep(100); - } else { - $this->_msgToDebug(98, '--- Not Empy AMI MSG --- '); - } - $this->_ProcessingMessage .= $read; - $this->_DumpMessage .= $read; + // Extract any complete messages and leave remainder for next read while (($marker = strpos($this->_ProcessingMessage, aminterface\Message::EOM))) { $msg = substr($this->_ProcessingMessage, 0, $marker); $this->_ProcessingMessage = substr( @@ -225,56 +227,39 @@ class aminterface ); $msgs[] = $msg; } - return $msgs; + $this->process($msgs); } - public function process() + public function process(array $msgs) { - $msgs = $this->getMessages(); - $this->_msgToDebug(90, $msgs); - $this->_countE++; - if ($this->_countE > 10000) { - $this->_msgToDebug(9, '--- Procecc Die, Dump --- '); - $this->_msgToDebug(9, $this->_DumpMessage); - $this->_msgToDebug(9, '--- END Procecc Die, Dump --- '); - die(); - } foreach ($msgs as $aMsg) { - $resPos = strpos($aMsg, 'Response:'); - $evePos = strpos($aMsg, 'Event:'); + // 2 types of message; Response or Event. Response only incudes data + // for JSON response and Command response. All other responses expect + // data in an event list - these events need to be attached to the response. + $resPos = strpos($aMsg, 'Response: '); // Have a Response message. This may not be 0. + $evePos = strpos($aMsg, 'Event: '); // Have an Event Message. This should always be 0. + // Add the incoming message to a string that can be checked + // against the completed message event when it is received. + $this->_incomingRawMessage[$this->_lastActionId] .= "\r\n\r\n" . $aMsg; if (($resPos !== false) && (($resPos < $evePos) || $evePos === false)) { - $response = $this->_msgToResponse($aMsg); // resp Ok - $this->_incomingQueue[$this->_lastActionId] = $response; - } elseif ($evePos !== false) { - $event = $this->_messageToEvent($aMsg); // Event Ok - - $this->_msgToDebug(99, '--- Response Type 2 --- '); - $this->_msgToDebug(99, $aMsg); - $this->_msgToDebug(99, '--- Event Response Type 2 --- '); - $this->_msgToDebug(99, $event); - - if ($event != null) { - $response = $this->findResponse($event); -// print_r($response); -// print_r('
--- E2 Response Type 2 ----------
'); - if ($response === false || $response->isComplete()) { - $this->dispatch($event); // не работает - } else { - $response->addEvent($event); - } - } + $response = $this->_responseObjFromMsg($aMsg); // resp Ok + $this->eventListEndEvent = $response->getKey('eventlistendevent'); + $this->_incomingMsgObjectList[$this->_lastActionId] = $response; + $this->eventListIsCompleted[$this->_lastActionId] = $response->isComplete(); + } elseif ($evePos === 0) { // Event must be at the start of the msg. + $event = $this->_eventObjFromMsg($aMsg); // Event Ok + $this->eventListIsCompleted[$this->_lastActionId] = $event->isComplete(); + $this->_incomingMsgObjectList[$this->_lastActionId]->addEvent($event); } else { // broken ami most probably through changes in chan_sccp_b. - //sending a response with events without Event and ActionId + // AMI is sending a message which is neither a response nor an event. $this->_msgToDebug(1, 'resp broken ami'); $bMsg = 'Event: ResponseEvent' . "\r\n"; $bMsg .= 'ActionId: ' . $this->_lastActionId . "\r\n" . $aMsg; - $event = $this->_messageToEvent($bMsg); - $response = $this->findResponse($event); - $response->addEvent($event); + $event = $this->_eventObjFromMsg($bMsg); + $this->_incomingMsgObjectList[$this->_lastActionId]->addEvent($event); } } -// print_r('
--- EProcecc ----------
'); } private function _msgToDebug($level, $msg) @@ -287,74 +272,32 @@ class aminterface print_r('
'); } - private function _msgToResponse($msg) + private function _responseObjFromMsg($message) { - // print_r("
------------hmsg----------
"); - // print_r($this->_lastActionClass); -// print_r($this->_lastRequestedResponseHandler); -// print_r("
------------emsg----------
"); -// print_r($msg); - $response = $this->_msgFromRaw($msg, $this->_lastActionClass, $this->_lastRequestedResponseHandler); -// print_r("
------------rmsg----------
"); - // print_r($response); -// print_r("
------------ermsg----------
"); - - $actionId = $response->getActionId(); - if ($actionId === null) { - $actionId = $this->_lastActionId; - $response->setActionId($this->_lastActionId); - } - return $response; - } - - /* - * - * - */ - - public function _msgFromRaw($message, $requestingaction = false, $responseHandler = false) - { - $_className = false; - $responseclass = '\\FreePBX\\modules\\Sccp_manager\\aminterface\\Generic_Response'; - if ($responseHandler != false) { - $_className = '\\FreePBX\\modules\\Sccp_manager\\aminterface\\' . $responseHandler . '_Response'; - } elseif ($requestingaction != false) { - $_className = '\\FreePBX\\modules\\Sccp_manager\\' . substr(get_class($requestingaction), 20, -6) . '_Response'; + $responseClass = '\\FreePBX\\modules\\Sccp_manager\\aminterface\\Generic_Response'; + if ($this->_lastRequestedResponseHandler != false) { + $_className = '\\FreePBX\\modules\\Sccp_manager\\aminterface\\' . $this->_lastRequestedResponseHandler . '_Response'; } if ($_className) { if (class_exists($_className, true)) { - $responseclass = $_className; + $responseClass = $_className; } elseif ($responseHandler != false) { $this->_errorException('Response Class ' . $_className . ' requested via responseHandler, could not be found'); } } - return new $responseclass($message); - } - - protected function _errorException($msg) - { - $this->_error[] = $msg; - } - - /* - * Replace or dublicate to AMI interface - */ - - public function _eventFromRaw($message) - { - $eventStart = strpos($message, 'Event: ') + 7; - - if ($eventStart > strlen($message)) { - return new aminterface\UnknownEvent($message); + $response = new $responseClass($message); + $actionId = $response->getActionID(); + if ($actionId === null) { + $response->setActionId($this->_lastActionId); } - - $eventEnd = strpos($message, aminterface\Message::EOL, $eventStart); - if ($eventEnd === false) { - $eventEnd = strlen($message); - } - $name = substr($message, $eventStart, $eventEnd - $eventStart); + return $response; + } + public function _eventObjFromMsg($message) + { + $eventType = explode(aminterface\Message::EOL,$message,2); + $name = trim(explode(':',$eventType[0],2)[1]); $className = '\\FreePBX\\modules\\Sccp_manager\\aminterface\\' . $name . '_Event'; if (class_exists($className, true) === false) { $className = '\\FreePBX\\modules\\Sccp_manager\\aminterface\\UnknownEvent'; @@ -362,40 +305,6 @@ class aminterface return new $className($message); } - public function _respnceFromRaw($message, $requestingaction = false, $responseHandler = false) - { - - $responseclass = '\\FreePBX\\modules\\Sccp_manager\\aminterface\\Response'; - - $_className = false; - if ($responseHandler != false) { - $_className = '\\FreePBX\\modules\\Sccp_manager\\aminterface\\' . $responseHandler . '_Response'; - } elseif ($requestingaction != false) { - $_className = '\\FreePBX\\modules\\Sccp_manager\\aminterface\\' . substr(get_class($requestingaction), 20, -6) . '_Response'; - } - if ($_className) { - if (class_exists($_className, true)) { - $responseclass = $_className; - } elseif ($responseHandler != false) { - throw new AMIException('Response Class ' . $_className . ' requested via responseHandler, could not be found'); - } - } -// if ($this->_logger->isDebugEnabled()) $this->_logger->debug('Created: ' . $responseclass . "\n"); - print_r($responseclass); - die(); - return new $responseclass($message); - } - -// protected function findResponse(IncomingMessage $message) { - protected function findResponse($message) - { - $actionId = $message->getActionId(); - if (isset($this->_incomingQueue[$actionId])) { - return $this->_incomingQueue[$actionId]; - } - return false; - } - protected function dispatch($message) { print_r("
------------dispatch----------
"); @@ -451,8 +360,7 @@ class aminterface $result = array(); if ($this->_connect_state) { $_action = new \FreePBX\modules\Sccp_manager\aminterface\ExtensionStateListAction(); - $_response = $this->send($_action); - $_res = $_response->getResult(); + $_res = $this->send($_action)->getResult(); foreach ($_res as $key => $value) { foreach ($value as $key2 => $value2) { $result[$key.'@'.$key2] = $key.'@'.$key2; @@ -467,8 +375,7 @@ class aminterface $result = array(); if ($this->_connect_state) { $_action = new \FreePBX\modules\Sccp_manager\aminterface\SCCPShowSoftkeySetsAction(); - $_response = $this->send($_action); - $_res = $_response->getResult(); + $_res = $this->send($_action)->getResult(); foreach ($_res as $key => $value) { $result[$key] = $key; } @@ -480,9 +387,8 @@ class aminterface $result = array(); if ($this->_connect_state) { $_action = new \FreePBX\modules\Sccp_manager\aminterface\SCCPShowDevicesAction(); - $_response = $this->send($_action); - $result = $_response->getResult(); - foreach ($result as $key => $value) { + $_res = $this->send($_action)->getResult(); + foreach ($_res as $key => $value) { $result[$key]['name'] = $key; } } @@ -493,8 +399,7 @@ class aminterface $result = array(); if ($this->_connect_state) { $_action = new \FreePBX\modules\Sccp_manager\aminterface\SCCPShowDeviceAction($devicename); - $_response = $this->send($_action); - $result = $_response->getResult(); + $result = $this->send($_action)->getResult(); $result['MAC_Address'] = $result['macaddress']; } return $result; @@ -510,7 +415,6 @@ class aminterface $_response = $this->send($_action); $result['data'] = 'Device :'.$devicename.' Result: '.$_response->getMessage(); $result['Response']=$_response->getKey('Response'); - // $result = $_response->getResult(); } return $result; } @@ -533,55 +437,55 @@ class aminterface $metadata = $this->send($_action)->getResult(); } //return $result; - if ($metadata && array_key_exists("Version", $metadata)) { - $result["Version"] = $metadata["Version"]; - $version_parts = explode(".", $metadata["Version"]); - $result["vCode"] = 0; - if ($version_parts[0] == "4") { + if (isset($metadata['Version'])) { + $result['Version'] = $metadata['Version']; + $version_parts = explode('.', $metadata['Version']); + $result['vCode'] = 0; + if ($version_parts[0] === 4) { switch ($version_parts[1]) { - case "1": - $result["vCode"] = 410; + case 1: + $result['vCode'] = 410; break; - case "2": - $result["vCode"] = 420; + case 2: + $result['vCode'] = 420; break; case 3. . .5: - if($version_parts[2] == "3"){ - $result["vCode"] = 433; + if($version_parts[2] == 3){ + $result['vCode'] = 433; } else { - $result["vCode"] = 430; + $result['vCode'] = 430; } break; default: - $result["vCode"] = 400; + $result['vCode'] = 400; break; } } /* Revision got replaced by RevisionHash in 10404 (using the hash does not work) */ if (array_key_exists("Revision", $metadata)) { if (base_convert($metadata["Revision"], 16, 10) == base_convert('702487a', 16, 10)) { - $result["vCode"] = 431; + $result['vCode'] = 431; } if (base_convert($metadata["Revision"], 16, 10) >= "10403") { - $result["vCode"] = 431; + $result['vCode'] = 431; } } if (array_key_exists("RevisionHash", $metadata)) { - $result["RevisionHash"] = $metadata["RevisionHash"]; + $result['RevisionHash'] = $metadata["RevisionHash"]; } else { - $result["RevisionHash"] = ''; + $result['RevisionHash'] = ''; } - if (array_key_exists("RevisionNum", $metadata)) { - $result["RevisionNum"] = $metadata["RevisionNum"]; - if ($metadata["RevisionNum"] >= "10403") { // new method, RevisionNum is incremental - $result["vCode"] = 432; + if (isset($metadata['RevisionNum'])) { + $result['RevisionNum'] = $metadata['RevisionNum']; + if ($metadata['RevisionNum'] >= 10403) { // new method, RevisionNum is incremental + $result['vCode'] = 432; } - if ($metadata["RevisionNum"] >= "10491") { // new method, RevisionNum is incremental - $result["vCode"] = 433; + if ($metadata['RevisionNum'] >= 10491) { // new method, RevisionNum is incremental + $result['vCode'] = 433; } } - if (array_key_exists("ConfigureEnabled", $metadata)) { - $result["futures"] = implode(';', $metadata["ConfigureEnabled"]); + if (isset($metadata['ConfigureEnabled'])) { + $result['futures'] = implode(';', $metadata['ConfigureEnabled']); } } return $result; diff --git a/Sccp_manager.inc/srvinterface.class.php b/Sccp_manager.inc/srvinterface.class.php index 0321aa2..84302ee 100644 --- a/Sccp_manager.inc/srvinterface.class.php +++ b/Sccp_manager.inc/srvinterface.class.php @@ -14,7 +14,8 @@ class srvinterface { var $error; var $_info; - var $ami_mode; + var $ami_mode = false; + var $useAmiInterface = true; public function __construct($parent_class = null) { $this->paren_class = $parent_class; @@ -51,9 +52,13 @@ class srvinterface { } } if ($this->aminterface->status()) { - $this->aminterface->open(); + // Ami is not hard disabled in Amiinterface __construct 54. + if ($this->aminterface->open()) { + // Can open a connection. Now check compatibility with chan-sccp. + // will return true if compatible. + $this->ami_mode = $this->get_compatible_sccp(true)[1]; + } } - $this->ami_mode = $this->aminterface->status(); } public function info() { @@ -198,24 +203,35 @@ class srvinterface { } } - public function get_compatible_sccp() { - + public function get_compatible_sccp($revNumComp=false) { + // only called with args from installer to get revision and compatibility $res = $this->getSCCPVersion(); if (empty($res)) { return 0; } switch ($res["vCode"]) { case 0: - return 0; + $retval = 0; + break; case 433: - return 433; - + $retval = 433; + break; case 432: + $retval = 430; + break; case 431: - return 431; + $retval = 431; + break; default: - return 430; + $retval = 430; } + if ($res['RevisionNum'] < 11063) { + $this->useAmiInterface = false; + } + if ($revNumComp) { + return array($retval, $this->useAmiInterface); + } + return $retval; } public function getSCCPVersion() { @@ -227,7 +243,6 @@ class srvinterface { } public function sccp_list_keysets() { - if ($this->ami_mode) { return $this->aminterface->sccp_list_keysets(); } else { diff --git a/assets/js/sccp_manager.js b/assets/js/sccp_manager.js index b8502ff..c1afed0 100644 --- a/assets/js/sccp_manager.js +++ b/assets/js/sccp_manager.js @@ -241,7 +241,7 @@ $(document).ready(function () { } e.preventDefault(); }); - + // Form.buttons - Form.adddevice $('.futuretype').change(function (e) { var kid = $(this).data('id'); @@ -256,7 +256,7 @@ $(document).ready(function () { } } }); - + }); $('.buttontype').change(function (e) { @@ -627,7 +627,7 @@ $(document).ready(function () { i++; }); } - + if (datas === '') { if (confirm(conf_msg)) { datas = 'name[0]=all'; @@ -1011,7 +1011,7 @@ function bs_page_reload() } function bs_alert(data, status, reload) { - + if (document.getElementById('hwalert') === null) { if (Array.isArray(data)) { data.forEach(function (entry) { @@ -1027,7 +1027,7 @@ function bs_alert(data, status, reload) if (status === true) { modal.find('.modal-title').text('Operation result'); } else { - modal.find('.modal-title').text('Erroe operation '); + modal.find('.modal-title').text('Error operation '); } } else { modal.find('.modal-title').text('Operation result'); @@ -1075,4 +1075,3 @@ function sleep(milliseconds) } } } - diff --git a/install.php b/install.php index b35772f..72e3f1d 100644 --- a/install.php +++ b/install.php @@ -18,6 +18,7 @@ global $version; global $srvinterface; global $mobile_hw; $mobile_hw = '0'; +global $useAmiInterface; $class = "\\FreePBX\\Modules\\Sccp_manager\\srvinterface"; if (!class_exists($class, false)) { @@ -378,6 +379,7 @@ $table_req = array('sccpdevice', 'sccpline'); $ss = FreePBX::create()->Sccp_manager; $astman = FreePBX::create()->astman; $sccp_compatible = 0; +$chanSCCPWarning = true; //$db_config = $db_config_v0; $db_config = ''; @@ -448,13 +450,13 @@ function CheckAsteriskVersion() function CheckChanSCCPCompatible() { + global $chanSCCPWarning; global $srvinterface, $astman; if (!$astman) { ie_freepbx('No asterisk manager connection provided!. Installation Failed'); } - $sccp_compatible = $srvinterface->get_compatible_sccp(); - outn("
  • " . _("Sccp model Compatible code : ") . $sccp_compatible . "
  • "); - return $sccp_compatible; + // calling with true returns array with compatibility and RevisionNumber + return $srvinterface->get_compatible_sccp(true); } function InstallDB_Buttons() @@ -967,7 +969,11 @@ function Setup_RealTime() CheckSCCPManagerDBTables($table_req); #CheckPermissions(); CheckAsteriskVersion(); -$sccp_compatible = CheckChanSCCPCompatible(); +$sccp_version = array(); +$sccp_version = CheckChanSCCPCompatible(); +$sccp_compatible = $sccp_version[0]; +$chanSCCPWarning = $sccp_version[1] ^= 1; +outn("
  • " . _("Sccp model Compatible code : ") . $resultReturned[0] . "
  • "); if ($sccp_compatible == 0) { // die_freepbx('Chan Sccp not Found. Install it before continuing'); outn("
    "); @@ -998,6 +1004,10 @@ if (!$sccp_db_ver) { InstallDB_createButtonConfigTrigger(); InstallDB_CreateSccpDeviceConfigView($sccp_compatible); InstallDB_updateDBVer($sccp_compatible); +if ($chanSCCPWarning) { + outn("
    "); + outn("Warning: Upgrade chan_sccp_b to use full ami functionality"); +} if (!$sccp_db_ver) { Setup_RealTime(); outn("
    "); diff --git a/views/server.info.php b/views/server.info.php index d69bd5f..3dfb207 100644 --- a/views/server.info.php +++ b/views/server.info.php @@ -36,6 +36,10 @@ $info['aminterface'] = $this->aminterface->info(); $info['XML'] = $this->xmlinterface->info(); $info['sccp_class'] = $driver['sccp']; $info['Core_sccp'] = array('Version' => $core['Version'], 'about' => 'Sccp ver.' . $core['Version'] . ' r' . $core['vCode'] . ' Revision :' . $core['RevisionNum'] . ' Hash :' . $core['RevisionHash']); +if (!$this->srvinterface->useAmiInterface) { + $info['aminterface']['about'] .= ' -- Disabled'; + $info['Core_sccp'] = array('Version' => $core['Version'], 'about' => 'Sccp ver.' . $core['Version'] . ' r' . $core['vCode'] . ' Revision :' . $core['RevisionNum'] . ' Hash :' . $core['RevisionHash'] . ' ----Warning: Upgrade chan_sccp to use full ami functionality'); +} $info['Asterisk'] = array('Version' => FreePBX::Config()->get('ASTVERSION'), 'about' => 'Asterisk.');