482 lines
24 KiB
PHP
482 lines
24 KiB
PHP
<?php
|
||
// vim: set ai ts=4 sw=4 ft=php:
|
||
// Version for SCCP Manager 13.0.X
|
||
//
|
||
/* This is the driver for Sccp_manager in FreePBX.
|
||
It is loaded via an include, written by the installer, at
|
||
modules/core/functions.inc/drivers
|
||
and provides the following required methods. it provides the interface between
|
||
FreePBX extensions and sccp_manager lines
|
||
*
|
||
* getInfo
|
||
* addDevice
|
||
* delDevice
|
||
* getDevice - Called by core to read sccpline returning fields in data_fld
|
||
* getDefaultDeviceSettings -
|
||
* getDeviceDisplay - Called by functionsInc to load sccp tab using values from Device and getDevice.
|
||
*
|
||
*/
|
||
//
|
||
namespace FreePBX\modules\Core\Drivers;
|
||
class Sccp extends \FreePBX\modules\Core\Driver {
|
||
// This is a map between sccpline fields and FreePBX fields.
|
||
// TODO: List needs to be extended. Missing fields, not necessarily all required
|
||
/* adhocNumber
|
||
meetme
|
||
meetmenum
|
||
meetmeopts
|
||
regexten
|
||
directed_pickup
|
||
directed_pickup_context
|
||
pickup_modeanswer
|
||
amaflags
|
||
setvar
|
||
phonecodepage
|
||
trnsfvm
|
||
vmnum
|
||
*/
|
||
private $data_fld = array("pin"=>'pin', "label" => 'label', "accountcode" => 'account',
|
||
"context" =>'context',"incominglimit"=>'incominglimit',
|
||
"callgroup"=>'callgroup',"pickupgroup"=>'pickupgroup',
|
||
"transfer" => 'transfer', "echocancel" => 'echocancel',
|
||
"language" => 'language', "description" => 'callerid',
|
||
"cid_num" => 'cid_num', "cid_name" => 'label', "mailbox" => 'mailbox',
|
||
"musicclass" => 'musicclass', "allow" => 'allow',"disallow" => 'disallow',
|
||
"videomode" => 'videomode', 'pickup_modeanswer' => 'pickup_modeanswer',
|
||
"dnd" => 'dnd', "silencesuppression" => 'silencesuppression',
|
||
"secondary_dialtone_digits" => 'secondary_dialtone_digits',
|
||
"secondary_dialtone_tone" => 'secondary_dialtone_tone',
|
||
'namedcallgroup'=>'namedcallgroup', 'namedpickupgroup' => 'namedpickupgroup',
|
||
'directed_pickup' => 'directed_pickup'
|
||
);
|
||
// These are gui defaults used by freePBX for the elements in the SCCP tab in add/edit phone.
|
||
private $guiDefaults =array(
|
||
'gui_checkset' => array( "elemname" => "",
|
||
"prompttext" => "", //ok
|
||
"helptext" => "",
|
||
"currentvalue" => "",
|
||
"valarray" => array(),
|
||
"jsonclick" => '',
|
||
"jsvalidation" => "", //ok
|
||
"failvalidationmsg" => "", //ok
|
||
"canbeempty" => true,
|
||
"maxchars" => 0,
|
||
"disable" => false, //ok
|
||
"inputgroup" => false,
|
||
"class" => "",
|
||
"cblabel" => 'Enable',
|
||
"disabled_value" => 'DEFAULT',
|
||
"check_enables" => 'true',
|
||
"cbdisable" => false,
|
||
"cbclass" => '')
|
||
);
|
||
|
||
private $line_defaults = array();
|
||
|
||
public function __construct($parent_class = null) {
|
||
|
||
$this->freepbx = $parent_class;
|
||
$this->database = $parent_class->Database();
|
||
// Get system defaults [systemdefault] and sitedefaults [data] from sccpsettings.
|
||
$stmt = $this->database->prepare("SELECT * FROM sccpsettings WHERE systemdefault !=''");
|
||
$stmt->execute();
|
||
$raw_settings = $stmt->fetchAll(\PDO::FETCH_ASSOC);
|
||
foreach ($raw_settings as $key => $valueArray) {
|
||
$sccpDefaults[$valueArray['keyword']] = $valueArray['systemdefault'];
|
||
$siteDefaults[$valueArray['keyword']] = $valueArray['data'];
|
||
}
|
||
// This will produce an array where site defaults take precedence over system defaults
|
||
$this->line_defaults = array_intersect_key($siteDefaults,$sccpDefaults);
|
||
// If have no site codecs, use system defaults - must have a codec!
|
||
if (empty($this->line_defaults['allow'])) {
|
||
$this->line_defaults['allow'] = $sccpDefaults['allow'];
|
||
}
|
||
if (empty($this->line_defaults['disallow'])) {
|
||
$this->line_defaults['disallow'] = $sccpDefaults['disallow'];
|
||
}
|
||
unset($raw_settings, $siteDefaults, $sccpDefaults);
|
||
}
|
||
|
||
public function getInfo() {
|
||
return array(
|
||
"rawName" => "sccp",
|
||
"hardware" => "sccp_custom",
|
||
"prettyName" => _("Sccp Custom Driver"),
|
||
"shortName" => "SCCP",
|
||
"description" => _("Sccp Device"),
|
||
"Version" => "11.5",
|
||
"about" => "Sccp class Base ver: 11.5, Sccp ver: default"
|
||
);
|
||
}
|
||
|
||
public function addDevice($id, $settings) {
|
||
// This is actually save line and is used by add and edit.
|
||
$add_fld = array ("name"=>'label',"outboundcid"=>'cid_num',"langcode"=>'language',"extdisplay"=>'description','devinfo_mailbox'=>'mailbox');
|
||
$settings['cid_num']['value'] = '';
|
||
$settings['cid_name']['value'] = '';
|
||
$settings['mailbox']['value']= '';
|
||
|
||
// Add $_REQUEST values to settings
|
||
if (isset($_REQUEST)){
|
||
foreach($add_fld as $key => $val) {
|
||
if (!empty($_REQUEST[$key])){
|
||
$settings[$val]['value'] = $_REQUEST[$key];
|
||
}
|
||
}
|
||
}
|
||
$allow_codec = array();
|
||
foreach($settings as $key => $val) {
|
||
if (strncmp($key,'codec_',6) === 0 ) {
|
||
$allow_codec[] = str_replace('codec_','',$key);
|
||
}
|
||
}
|
||
$settings['allow']['value'] = implode(";", $allow_codec);
|
||
// Reset to line defaults if no value selected
|
||
if (empty($settings['allow']['value'])) {
|
||
$settings['allow']['value'] = $this->line_defaults['allow'];
|
||
}
|
||
|
||
// If set, parse outboundcid content into cid_num and cid_name sccpline fields
|
||
if (!empty($settings['cid_num']['value'])) {
|
||
$outboundcid = $settings['cid_num']['value'];
|
||
if (preg_match('/"(.*)"\s?<(.*)>/', $outboundcid, $matches)) {
|
||
$settings['cid_num']['value'] = $matches[2];
|
||
$settings['cid_name']['value'] = $matches[1];
|
||
} else if (is_integer($outboundcid)) {
|
||
$settings['cid_num']['value'] = $outboundcid;
|
||
}
|
||
}
|
||
|
||
if ($this->line_defaults['dndFeature'] == 'off') {
|
||
$settings['dnd']['value'] = 'off';
|
||
}
|
||
|
||
if (!empty($_REQUEST['vm']) && ($_REQUEST['vm'] =='enabled')){ // mailbox
|
||
if (empty($settings['mailbox']['value'])) {
|
||
$settings['mailbox']['value']= $id;
|
||
}
|
||
}
|
||
|
||
// only store values that have been set; if need to display a default, must show in page.
|
||
$sqlSet = "name='{$id}'";
|
||
foreach($this->data_fld as $key => $val) {
|
||
if (!empty($settings[$val]['value'])) {
|
||
$sqlSet .= ", {$key}='{$settings[$val]['value']}'";
|
||
}
|
||
}
|
||
|
||
$stmt = "INSERT INTO sccpline SET {$sqlSet} ON DUPLICATE KEY UPDATE {$sqlSet}";
|
||
$sth = $this->database->prepare($stmt);
|
||
$sth->execute();
|
||
/*
|
||
If called from SCCP Phone, redirect to SCCP Phone page on submit.
|
||
This was last function in add so should be safe.
|
||
Prefer to add in Hooks, but is not followed even if set for $currentComponent
|
||
Do nothing if called from QuickCreateExtension when display is not set
|
||
*/
|
||
if (isset($_REQUEST['display'])) {
|
||
redirect("config.php?display=sccp_phone", false);
|
||
}
|
||
// Have changed something so need to reload the device
|
||
// TODO: are we reloading the device or reloading Asterisk
|
||
$this->reload_line($id);
|
||
return true;
|
||
}
|
||
|
||
public function delDevice($id) {
|
||
//Required by FreePBX.
|
||
// Delete associated default line buttons or will leave orphans
|
||
foreach (array($id) as $openId) {
|
||
$sth = $this->database->prepare("DELETE FROM sccpbuttonconfig WHERE name LIKE :openID AND buttontype = 'line'");
|
||
$openId = "{$openId}%";
|
||
$sth->bindParam(':openID', $openId);
|
||
$sth->execute();
|
||
}
|
||
|
||
$sth = $this->database->prepare("DELETE FROM sccpline WHERE name = ?");
|
||
$sth->execute(array($id));
|
||
return true;
|
||
}
|
||
|
||
public function getDevice($id) {
|
||
// FreePBX required method
|
||
$sql = "SELECT name AS id, name AS name ";
|
||
foreach($this->data_fld as $key => $val) {
|
||
$sql .= ", {$key} AS {$val}";
|
||
}
|
||
$sql .= " FROM sccpline WHERE name = '{$id}'";
|
||
$sth = $this->database->prepare($sql);
|
||
$tech = array();
|
||
try {
|
||
$sth->execute(array($id));
|
||
$tech = $sth->fetch(\PDO::FETCH_ASSOC);
|
||
$tech['dial']="SCCP/{$id}";
|
||
} catch(\Exception $e) {}
|
||
return $tech;
|
||
}
|
||
|
||
public function getDefaultDeviceSettings($id, $displayname, &$flag) {
|
||
// FreePBX required method
|
||
$settingsFields = array('mailbox', 'incominglimit', 'context', 'directed_pickup_context', 'callgroup', 'pickupgroup', 'namedcallgroup',
|
||
'namedpickupgroup', 'adhocNumber', 'secondary_dialtone_digits', 'secondary_dialtone_tone', 'directed_pickup', 'pickup_modeanswer',
|
||
'transfer', 'echocancel', 'dnd', 'silencesuppression', 'musicclass', 'pin', 'allow', 'disallow');
|
||
foreach ($settingsFields as $key) {
|
||
$settings[$key] = array('value' => $this->line_defaults[$key], 'flag' => $flag++);
|
||
}
|
||
return array('dial' => 'SCCP', 'settings' => $settings);
|
||
}
|
||
|
||
public function getDeviceDisplay($display, $deviceInfo, $currentComponent, $primarySection) {
|
||
global $amp_conf;
|
||
$activeCodecs = array();
|
||
// load xml data to get help from same source as rest of module
|
||
$xml_vars = $amp_conf['AMPWEBROOT'] . '/admin/modules/sccp_manager/conf/sccpgeneral.xml.v433';
|
||
$this->xml_data = simplexml_load_file($xml_vars);
|
||
// load metainfo from chan-sccp - help information if not in xml. Only load first time as static data.
|
||
if (empty($this->sccpHelpInfo)) {
|
||
$sysConfiguration = \FreePbx::sccp_manager()->aminterface->getSCCPConfigMetaData('general');
|
||
foreach ($sysConfiguration['Options'] as $key => $valueArray) {
|
||
foreach ($valueArray['Description'] as $descKey => $descValue) {
|
||
$this->sccpHelpInfo[$valueArray['Name']] .= $descValue . '<br>';
|
||
}
|
||
}
|
||
unset($sysConfiguration);
|
||
}
|
||
|
||
$section = _("SCCP Extension Details");
|
||
$section_с = _("SCCP Codec Details");
|
||
$gn_category = "sccp";
|
||
//add sccp category
|
||
$currentComponent->addTabTranslation('sccp',_('SCCP'));
|
||
|
||
// get site and system defaults
|
||
$systemCodecs = array_fill_keys(explode(';',$this->line_defaults['allow']),true);
|
||
$siteAudioCodecs = array_intersect_key($systemCodecs, $this->freepbx->Codecs->getAudio());
|
||
$siteVideoCodecs = array_intersect_key($systemCodecs, $this->freepbx->Codecs->getVideo());
|
||
|
||
if (empty($deviceInfo['allow'])) {
|
||
// No allowed codecs so reset to site defaults
|
||
foreach ($systemCodecs as $lineCodec => $dummyVal) {
|
||
$activeCodecs[] = "devinfo_codec_{$lineCodec}";
|
||
}
|
||
} else {
|
||
// have allowed codecs for this line
|
||
foreach (explode(';',$deviceInfo['allow']) as $lineCodec) {
|
||
$activeCodecs[] = "devinfo_codec_{$lineCodec}";
|
||
}
|
||
}
|
||
|
||
// Fill Audio codecs information
|
||
foreach ($siteAudioCodecs as $key => $value) {
|
||
$audioCodecButtons[] = array('value' => "devinfo_codec_{$key}", 'text' => $key);
|
||
}
|
||
// Fill Video codecs information
|
||
foreach ($siteVideoCodecs as $key => $value) {
|
||
$videoCodecButtons[] = array('value' => "devinfo_codec_{$key}", 'text' => $key);
|
||
}
|
||
|
||
$tmparr['disallow'] = array('prompttext' => _('Disallowed Codecs'),
|
||
'value' => $this->line_defaults['disallow'],
|
||
'tt' => 'Codecs that are disallowed. Default and recommended value is all',
|
||
'level' => 1,
|
||
'section' => $section_с,
|
||
'category' => $gn_category
|
||
);
|
||
|
||
$el = array(
|
||
"elemname" => "devinfo_sccp_codec",
|
||
"prompttext" => _('Line Audio Codec:'),
|
||
"helptext" => _("Line Audio Codec. Uncheck all Audio and Video codecs to return to site defaults"),
|
||
"currentvalue" => $activeCodecs,
|
||
"valarray" => $audioCodecButtons,
|
||
"class" => $section_с,
|
||
"disable" => 0
|
||
);
|
||
// Override defaults with $el
|
||
$currentComponent->addguielem($section_с, new \gui_checkset(array_merge($this->guiDefaults['gui_checkset'],$el)), $gn_category);
|
||
unset($el);
|
||
|
||
$el = array(
|
||
"elemname" => "devinfo_sccp_vcodec",
|
||
"prompttext" => _('Line Video Codec:'),
|
||
"helptext" => _("Line Video Codec"),
|
||
"currentvalue" => $activeCodecs,
|
||
"valarray" => $videoCodecButtons,
|
||
"class" => $section_с,
|
||
"disable" => 0
|
||
);
|
||
$currentComponent->addguielem($section_с, new \gui_checkset(array_merge($this->guiDefaults['gui_checkset'],$el)), $gn_category);
|
||
|
||
$pageGroup = $this->xml_data->xpath('//page_group[@name="sccp_extension_config"]');
|
||
$elements = $pageGroup[0]->children();
|
||
|
||
foreach ($elements as $child) {
|
||
if (empty($child->help)) {
|
||
$child->help = 'Help is not available.';
|
||
$child->meta_help = '1';
|
||
}
|
||
switch ($child['type']) {
|
||
case 'IE':
|
||
$elementID = (string)$child->input[0]->name;
|
||
if (!empty($metainfo[$elementID])) {
|
||
if ($child->meta_help == '1' || $child->help == 'Help!') {
|
||
$child->help = $metainfo[$shortId];
|
||
}
|
||
}
|
||
$tmparr[$elementID] = array('prompttext' => _((string)$child->label),
|
||
'value' => $this->line_defaults[$elementID],
|
||
'tt' => (string)$child->help,
|
||
'level' => 1,
|
||
'section' => $section,
|
||
'category' => $gn_category
|
||
);
|
||
break;
|
||
case 'IS':
|
||
$select = array();
|
||
foreach ($child->xpath('button') as $value) {
|
||
$select[] = array('value' => strtolower((string)$value[@value]), 'text' => (string)$value);
|
||
}
|
||
$hideButton = false;
|
||
if (($this->line_defaults['dndFeature'] == 'off') && ($child['id'] == 5)) {
|
||
$hideButton = true;
|
||
}
|
||
$tmparr[(string)$child->name] = array('prompttext' => _((string)$child->label),
|
||
'value' => $this->line_defaults[(string)$child->name],
|
||
'tt' => (string)$child->help,
|
||
'select' => $select,
|
||
'level' => 1,
|
||
'disable' => $hideButton,
|
||
'hidden' => $hideButton,
|
||
'type' => 'radio',
|
||
'section' => $section,
|
||
'category' => $gn_category
|
||
);
|
||
unset($select);
|
||
break;
|
||
case 'SLD':
|
||
$select = array(
|
||
array( 'value' => '0x21', 'text' => 'Inside Dial Tone'),
|
||
array( 'value' => '0x22', 'text' => 'Outside Dial Tone'),
|
||
array( 'value' => '0x23', 'text' => 'Line Busy Tone'),
|
||
array( 'value' => '0x24', 'text' => 'Alerting Tone'),
|
||
array( 'value' => '0x25', 'text' => 'Reorder Tone'),
|
||
array( 'value' => '0x26', 'text' => 'Recorder Warning Tone'),
|
||
array( 'value' => '0x27', 'text' => 'Recorder Detected Tone'),
|
||
array( 'value' => '0x28', 'text' => 'Reverting Tone'),
|
||
array( 'value' => '0x29', 'text' => 'Receiver OffHook Tone'),
|
||
array( 'value' => '0x2A', 'text' => 'Partial Dial Tone'),
|
||
array( 'value' => '0x2B', 'text' => 'No Such Number Tone'),
|
||
array( 'value' => '0x2C', 'text' => 'Busy Verification Tone'),
|
||
array( 'value' => '0x2D', 'text' => 'Call Waiting Tone'),
|
||
array( 'value' => '0x2E', 'text' => 'Confirmation Tone'),
|
||
array( 'value' => '0x2F', 'text' => 'Camp On Indication Tone'),
|
||
array( 'value' => '0x30', 'text' => 'Recall Dial Tone'),
|
||
array( 'value' => '0x31', 'text' => 'Zip Zip'),
|
||
array( 'value' => '0x32', 'text' => 'Zip'),
|
||
array( 'value' => '0x33', 'text' => 'Beep Bonk'),
|
||
array( 'value' => '0x34', 'text' => 'Music Tone'),
|
||
array( 'value' => '0x35', 'text' => 'Hold Tone'),
|
||
array( 'value' => '0x36', 'text' => 'Test Tone'),
|
||
array( 'value' => '0x37', 'text' => 'DT Monitor Warning Tone'),
|
||
array( 'value' => '0x40', 'text' => 'Add Call Waiting'),
|
||
array( 'value' => '0x41', 'text' => 'Priority Call Wait'),
|
||
array( 'value' => '0x42', 'text' => 'Recall Dial'),
|
||
array( 'value' => '0x43', 'text' => 'Barg In'),
|
||
array( 'value' => '0x44', 'text' => 'Distinct Alert'),
|
||
array( 'value' => '0x45', 'text' => 'Priority Alert'),
|
||
array( 'value' => '0x46', 'text' => 'Reminder Ring'),
|
||
array( 'value' => '0x47', 'text' => 'Precedence RingBank'),
|
||
array( 'value' => '0x48', 'text' => 'Pre-EmptionTone'),
|
||
array( 'value' => '0x67', 'text' => '2105 HZ'),
|
||
array( 'value' => '0x68', 'text' => '2600 HZ'),
|
||
array( 'value' => '0x69', 'text' => '440 HZ'),
|
||
array( 'value' => '0x6A', 'text' => '300 HZ'),
|
||
array( 'value' => '0x77', 'text' => 'MLPP Pala'),
|
||
array( 'value' => '0x78', 'text' => 'MLPP Ica'),
|
||
array( 'value' => '0x79', 'text' => 'MLPP Vca'),
|
||
array( 'value' => '0x7A', 'text' => 'MLPP Bpa'),
|
||
array( 'value' => '0x7B', 'text' => 'MLPP Bnea'),
|
||
array( 'value' => '0x7C', 'text' => 'MLPP Upa')
|
||
);
|
||
|
||
|
||
$tmparr[(string)$child->name] = array('prompttext' => _((string)$child->label),
|
||
'value' => $this->line_defaults[(string)$child->name],
|
||
'tt' => (string)$child->help,
|
||
'select' => $select,
|
||
'level' => 1,
|
||
'type' => 'select',
|
||
'section' => $section,
|
||
'category' => $gn_category
|
||
);
|
||
unset($select);
|
||
break;
|
||
case 'SLG':
|
||
$elementID = (string)$child->name;
|
||
$named_group = \FreePbx::sccp_manager()->dbinterface->getNamedGroup($elementID);
|
||
if (!empty($named_group[$elementID])) {
|
||
foreach ($named_group[$elementID] as $val) {
|
||
$select[] = array('value' => $val, 'text' => $val);
|
||
}
|
||
}
|
||
// Disable and hide list elements if there are no valid values
|
||
$tmparr[(string)$child->name] = array('prompttext' => _((string)$child->label),
|
||
'value' => $this->line_defaults[(string)$child->name],
|
||
'tt' => (string)$child->help,
|
||
'select' => $select,
|
||
'level' => 1,
|
||
'disable' => empty($named_group[$elementID][0]),
|
||
'hidden' => empty($named_group[$elementID][0]),
|
||
'section' => $section,
|
||
'category' => $gn_category
|
||
);
|
||
unset($select);
|
||
break;
|
||
case 'SLM':
|
||
if (function_exists('music_list')){
|
||
foreach (music_list() as $value) {
|
||
$select[] = array('value' => $value, 'text' => _($value));
|
||
}
|
||
} else {
|
||
$select[] = array('value' => 'default', 'text' => _('default'));
|
||
}
|
||
$tmparr[(string)$child->name] = array('prompttext' => _((string)$child->label),
|
||
'value' => $this->line_defaults[(string)$child->name],
|
||
'tt' => (string)$child->help,
|
||
'select' => $select,
|
||
'level' => 1,
|
||
'type' => 'select',
|
||
'section' => $section,
|
||
'category' => $gn_category
|
||
);
|
||
unset($select);
|
||
break;
|
||
}
|
||
}
|
||
|
||
$select[] = array('value' => 'off', 'text' => 'Off');
|
||
$select[] = array('value' => 'user', 'text' => 'User');
|
||
$select[] = array('value' => 'auto', 'text' => 'Auto');
|
||
$tt = _("Automatic or Manual video mode. Valid values are 'auto', 'user' or 'off'. When set to 'auto', video will automatically start if both parties have a compatible code enabled. In 'user' mode the user needs to press the vidmode softkey before video will be tried. Default:'auto'");
|
||
$tmparr['videomode'] = array('prompttext' => _('Video Mode '), 'value' => 'auto', 'tt' => $tt, 'select' => $select, 'level' => 1, 'type' => 'radio', 'section' => $section_с, 'category' => $gn_category);
|
||
unset($select);
|
||
|
||
return $tmparr;
|
||
}
|
||
|
||
public function reload_line($id) {
|
||
global $astman;
|
||
// TODO: Change to use amInterfaceClasses
|
||
$result = $astman->Command('sccp reload line ' . $id);
|
||
return $result;
|
||
}
|
||
|
||
|
||
|
||
public function getDeviceHeaders() {
|
||
return array(
|
||
'secret' => array('identifier' => _('Secret'), 'description' => sprintf(_('Secret [Enter "%s" to regenerate]'),"REGEN")),
|
||
);
|
||
}
|
||
}
|