Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(trunks): allow to enable/disable TOPOS for each trunk #341

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
88 changes: 88 additions & 0 deletions freepbx/initdb.d/migration.php
Original file line number Diff line number Diff line change
Expand Up @@ -236,3 +236,91 @@
$stmt = $db->prepare($sql);
$stmt->execute(['127.0.0.1:'.$_ENV['NETHVOICE_MARIADB_PORT']]);

# Create pjsip trunks custom flags table if not exist
# check if table exists
$sql = "SELECT * FROM information_schema.tables WHERE TABLE_SCHEMA = 'asterisk' AND TABLE_NAME = 'pjsip_trunks_custom_flags'";
$stmt = $db->prepare($sql);
$stmt->execute();
$res = $stmt->fetchAll(\PDO::FETCH_ASSOC);
if (count($res) == 0) {
// Create table and add default values
$db->query("CREATE TABLE `rest_pjsip_trunks_custom_flags` (
`provider_id` bigint(20) NOT NULL,
`keyword` varchar(30) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
`value` TINYINT(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`provider_id`,`keyword`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci" );
$db->query("INSERT INTO `rest_pjsip_trunks_custom_flags` (`provider_id`, `keyword`, `value`) VALUES
(1,'disable_topos_header',0),
(2,'disable_topos_header',0),
(3,'disable_topos_header',0),
(4,'disable_topos_header',0),
(5,'disable_topos_header',0),
(6,'disable_topos_header',0),
(7,'disable_topos_header',0),
(8,'disable_topos_header',0),
(9,'disable_topos_header',0),
(10,'disable_topos_header',0),
(11,'disable_topos_header',0),
(12,'disable_topos_header',0),
(13,'disable_topos_header',0),
(14,'disable_topos_header',0),
(15,'disable_topos_header',0),
(16,'disable_topos_header',0),
(17,'disable_topos_header',0),
(18,'disable_topos_header',0),
(19,'disable_topos_header',0),
(20,'disable_topos_header',0),
(21,'disable_topos_header',0),
(22,'disable_topos_header',0),
(23,'disable_topos_header',0),
(24,'disable_topos_header',0),
(25,'disable_topos_header',0),
(1,'disable_srtp_header',1),
(2,'disable_srtp_header',1),
(3,'disable_srtp_header',0),
(4,'disable_srtp_header',1),
(5,'disable_srtp_header',1),
(6,'disable_srtp_header',1),
(7,'disable_srtp_header',1),
(8,'disable_srtp_header',1),
(9,'disable_srtp_header',1),
(10,'disable_srtp_header',0),
(11,'disable_srtp_header',1),
(12,'disable_srtp_header',1),
(13,'disable_srtp_header',1),
(14,'disable_srtp_header',1),
(15,'disable_srtp_header',1),
(16,'disable_srtp_header',1),
(17,'disable_srtp_header',1),
(18,'disable_srtp_header',1),
(19,'disable_srtp_header',1),
(20,'disable_srtp_header',1),
(21,'disable_srtp_header',1),
(22,'disable_srtp_header',1),
(23,'disable_srtp_header',1),
(24,'disable_srtp_header',1);
");
}
// Add disable_srtp_header configuration for existing trunks that doesn't have media encription enabled and proxy configured
$sql = "SELECT DISTINCT id
FROM pjsip
WHERE id IN (
SELECT id
FROM pjsip
WHERE keyword = 'media_encryption' AND data = 'no'
)
AND id IN (
SELECT id
FROM pjsip
WHERE keyword = 'outbound_proxy' AND data IS NOT NULL AND data != ''
)";
$stmt = $db->prepare($sql);
$stmt->execute();
$res = $stmt->fetchAll(\PDO::FETCH_ASSOC);
$trunk_ids = array_column($res, 'id');
foreach ($trunk_ids as $trunk_id) {
$sql = "INSERT IGNORE INTO `kvstore_FreePBX_modules_Nethcti3` (`key`, `value`,`id`) VALUES ('disable_srtp_header`,'1',?)";
$stmt = $db->prepare($sql);
$stmt->execute([$trunk_id]);
}
145 changes: 142 additions & 3 deletions freepbx/var/www/html/freepbx/admin/modules/nethcti3/Nethcti3.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

namespace FreePBX\modules;

class Nethcti3 implements \BMO
class Nethcti3 extends \FreePBX_Helpers implements \BMO
{
public function __construct($freepbx = null) {
if ($freepbx == null)
Expand All @@ -39,8 +39,6 @@ public function backup() {
}
public function restore($backup) {
}
public function doConfigPageInit($page) {
}

/*Write a CTI configuration file in JSON format*/
public function writeCTIConfigurationFile($filename, $obj) {
Expand Down Expand Up @@ -243,4 +241,145 @@ public function genConfig() {
}
return $out;
}

// Add custom headers for trunks to trunks module
public static function myGuiHooks() {
return array("core", "INTERCEPT" => array("modules/core/page.trunks.php"));
}

public function doGuiHook($filename, &$output){}

public function doGuiIntercept($filename, &$output) {
# Show the custom field in the trunks module
if ($filename == "modules/core/page.trunks.php" && $_REQUEST['display'] == "trunks" && strtolower($_REQUEST['tech']) == "pjsip") {
$trunkid = str_replace("OUT_", "", $_REQUEST['extdisplay']);
$disable_topos_header = $this->getConfig('disable_topos_header', $trunkid);
$disable_srtp_header = $this->getConfig('disable_srtp_header', $trunkid);
$topos_section = '
<!--DISABLE TOPOS-->
<div class="element-container">
<div class="row">
<div class="col-md-12">
<div class="row">
<div class="form-group">
<div class="col-md-3">
<label class="control-label" for="disable_topos_header">'._("Disable TOPOS proxy header").'</label>
<i class="fa fa-question-circle fpbx-help-icon" data-for="disable_topos_header"></i>
</div>
<div class="col-md-9 radioset">
<input type="radio" name="disable_topos_header" id="disable_topos_headeryes" value="yes" '.($disable_topos_header == 1?"CHECKED":"").'>
<label for="disable_topos_headeryes">'. _("Yes") .'</label>
<input type="radio" name="disable_topos_header" id="disable_topos_headerno" value="no" '.($disable_topos_header == 0 || empty($disable_topos_header) ? "CHECKED" : "").'>
<label for="disable_topos_headerno">'._("No").'</label>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<span id="disable_topos_header-help" class="help-block fpbx-help-block">'. _("If yes, send topos=0 header to nethvoice-proxy to disable TOPOS for this trunk").'</span>
</div>
</div>
</div>
<!--END DISABLE TOPOS-->';
$disable_srtp_header_section = '
<!--DISABLE SRTP-->
<div class="element-container">
<div class="row">
<div class="col-md-12">
<div class="row">
<div class="form-group">
<div class="col-md-3">
<label class="control-label" for="disable_srtp_header">'._("Disable SRTP proxy header").'</label>
<i class="fa fa-question-circle fpbx-help-icon" data-for="disable_srtp_header"></i>
</div>
<div class="col-md-9 radioset">
<input type="radio" name="disable_srtp_header" id="disable_srtp_headeryes" value="yes" '.($disable_srtp_header == 1?"CHECKED":"").'>
<label for="disable_srtp_headeryes">'. _("Yes") .'</label>
<input type="radio" name="disable_srtp_header" id="disable_srtp_headerno" value="no" '.($disable_srtp_header == 0 || empty($disable_srtp_header) ? "CHECKED" : "").'>
<label for="disable_srtp_headerno">'._("No").'</label>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<span id="disable_srtp_header-help" class="help-block fpbx-help-block">'. _("If yes, send isTrunk=1 header to nethvoice-proxy to disable SRTP for this trunk").'</span>
</div>
</div>
</div>
<!--END DISABLE SRTP-->';
$output = str_replace('<!--END OUTBOUND PROXY-->','<!--END OUTBOUND PROXY-->'.$topos_section.$disable_srtp_header_section,$output);
}
}

public static function myConfigPageInits() {
return array("extensions", "recallonbusy", "trunks");

}

public function doConfigPageInit($display) {
global $astman;
if ($display == "extensions" && !empty($_REQUEST['recallonbusy'])) {
// Save Recall On Busy option for the extension
$astman->database_put("ROBconfig",$_REQUEST['extdisplay'],$_REQUEST['recallonbusy']);
} elseif ($display == "recallonbusy") {
if (!empty($_REQUEST['default'])) {
$this->setConfig('default',$_REQUEST['default']);
}
if (!empty($_REQUEST['digit'])) {
$this->setConfig('digit',$_REQUEST['digit']);
}
needreload();
} elseif ($display == "trunks") {
global $db;
if ($_REQUEST['action'] == "edittrunk" && !empty($_REQUEST['extdisplay'])) {
if (!empty($_REQUEST['disable_topos_header'])) {
// save topos configuratino for the trunk on trunk edit
$disable_topos_header = $_REQUEST['disable_topos_header'] == "yes" ? 1 : 0;
$trunkid = str_replace("OUT_", "", $_REQUEST['extdisplay']);
$this->setConfig('disable_topos_header', $disable_topos_header, $trunkid);
}
if (!empty($_REQUEST['disable_srtp_header'])) {
// save srtp configuration for the trunk on trunk edit
$disable_srtp_header = $_REQUEST['disable_srtp_header'] == "yes" ? 1 : 0;
$trunkid = str_replace("OUT_", "", $_REQUEST['extdisplay']);
$this->setConfig('disable_srtp_header', $disable_srtp_header, $trunkid);
}
} elseif ($_REQUEST['action'] == "addtrunk") {
// Get the future trunk id
$sql = 'SELECT trunkid FROM trunks';
$sth = $db->prepare($sql);
$sth->execute();
$trunkid = 1;
while ($res = $sth->fetchColumn()) {
if ($res > $trunkid) {
break;
}
$trunkid++;
}
if ($res == $trunkid) {
$trunkid++;
}
if (!empty($_REQUEST['disable_topos_header'])){
// save topos configuration for the trunk on trunk add
$disable_topos_header = $_REQUEST['disable_topos_header'] == "yes" ? 1 : 0;
$this->setConfig('disable_topos_header', $disable_topos_header, $trunkid);
}
if (!empty($_REQUEST['disable_srtp_header'])){
// save srtp configuration for the trunk on trunk add
$disable_srtp_header = $_REQUEST['disable_srtp_header'] == "yes" ? 1 : 0;
$this->setConfig('disable_srtp_header', $disable_srtp_header, $trunkid);
}
} elseif ($_REQUEST['action'] == "deltrunk") {
$trunkid = str_replace("OUT_", "", $_REQUEST['extdisplay']);
// delete topos configuration for the trunk
$this->delConfig('disable_topos_header', $trunkid);
// delete srtp configuration for the trunk
$this->delConfig('disable_srtp_header', $trunkid);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ function nethcti3_get_config($engine) {
if (isset($core_conf) && (method_exists($core_conf, 'addSipNotify'))) {
$core_conf->addSipNotify('generic-reload', array('Event' => 'check-sync\;reboot=false', 'Content-Length' => '0'));
}
/*Add contexts for gateway trunks identity*/
/*Add contexts for gateway trunks identity*/
$context = 'from-pstn-identity';
$ext->add($context, '_X!', '', new ext_noop('P-Preferred-Identity ${CUT(CUT(PJSIP_HEADER(read,P-Preferred-Identity),@,1),:,2)}'));
$ext->add($context, '_X!', '', new ext_noop('P-Asserted-Identity ${CUT(CUT(PJSIP_HEADER(read,P-Asserted-Identity),@,1),:,2)}'));
Expand All @@ -113,8 +113,8 @@ function nethcti3_get_config_late($engine) {
global $db;
switch($engine) {
case "asterisk":
/* Change CF for CTI voicemail status */
$ext->replace('macro-dial-one', 'cf', '2', new ext_execif('$["${DB(AMPUSER/${DB_RESULT}/cidnum)}" == "" && "${DB_RESULT:0:2}" != "vm"]', 'Set','__REALCALLERIDNUM=${DEXTEN}'));
/* Change CF for CTI voicemail status */
$ext->replace('macro-dial-one', 'cf', '2', new ext_execif('$["${DB(AMPUSER/${DB_RESULT}/cidnum)}" == "" && "${DB_RESULT:0:2}" != "vm"]', 'Set','__REALCALLERIDNUM=${DEXTEN}'));

/* Use main extension on login/logout/pause*/
if (!empty(\FreePBX::Queues()->listQueues())) {
Expand All @@ -138,31 +138,33 @@ function nethcti3_get_config_late($engine) {
$ext->splice('macro-dial-one','s','dial', new ext_execif('$["${DB(AMPUSER/${ARG3}/cidname)}" != "" && "${DB(AMPUSER/${CALLERID(num)}/cidname)}" = "" && "${ATTENDEDTRANSFER}" != "" && "${DB(AMPUSER/${FROMEXTEN}/cidname)}" != ""]', 'Set', 'CALLERID(num)=${DB(AMPUSER/${FROMEXTEN}/cidnum)}'),'',-1);
$ext->splice('macro-dial-one','s','dial', new ext_execif('$["${DB(AMPUSER/${CALLERID(num)}/cidname)}" != "" && "${ATTENDEDTRANSFER}" != ""]', 'Set', 'CALLERID(name)=${DB(AMPUSER/${CALLERID(num)}/cidname)}'),'',-1);
}
/*Add isTrunk = 1 header to VoIP trunks that doesn't require SRTP encryption*/
// Get all voip providers ip that doesn't need media encryption
$sql = "SELECT t1.data
FROM rest_pjsip_trunks_defaults AS t1
JOIN rest_pjsip_providers AS t2 ON t1.provider_id = t2.id
JOIN rest_pjsip_trunks_defaults AS t3 ON t2.id = t3.provider_id
WHERE t3.keyword = 'media_encryption' AND t3.data = 'no'
AND t1.keyword = 'sip_server'";
$stmt = $db->prepare($sql);
$stmt->execute();
$voip_providers = $stmt->fetchAll(PDO::FETCH_COLUMN);
// Get all trunks
$nethcti3 = \FreePBX::Nethcti3();
$trunks = FreePBX::Core()->listTrunks();
$voip_trunk_if = [];
foreach ($trunks as $trunk) {
$details = FreePBX::Core()->getTrunkDetails($trunk['trunkid']);
if (in_array($details['sip_server'], $voip_providers)) {
// Trunk needs needs media encryption disabled, set isTrunk header to 1
try {
$ext->splice('macro-dialout-trunk', 's', 'gocall', new ext_gosubif('$["${DIAL_TRUNK}" = "' . $trunk['trunkid'] . '"]', 'func-set-sipheader,s,1', false, 'isTrunk,1'));
} Catch(Exception $e) {
error_log('error adding isTrunk header setter to dialplan');
try {
/*Add isTrunk = 1 header to VoIP trunks that doesn't require SRTP encryption*/
$disable_srtp_header = $nethcti3->getConfig('disable_srtp_header', $trunk['trunkid']);
if ($disable_srtp_header==1) {
$ext->splice('macro-dialout-trunk', 's', 'gocall', new ext_gosubif('$["${DIAL_TRUNK}" = "' . $trunk['trunkid'] . '"]', 'func-set-sipheader,s,1', false, 'isTrunk,1'),'',6);
$add_unset_istrunk = true;
}
/*Add topos=0 header to voip trunks with disabled TOPOS for compatibility*/
$disable_topos_header = $nethcti3->getConfig('disable_topos_header', $trunk['trunkid']);
if ($disable_topos_header==1) {
$ext->splice('macro-dialout-trunk', 's', 'gocall', new ext_gosubif('$["${DIAL_TRUNK}" = "' . $trunk['trunkid'] . '"]', 'func-set-sipheader,s,1', false, 'topos,0'),'',6);
$add_unset_topos = true;
}
} catch (Exception $e) {
error_log('Error adding additional headers to trunk: '.$e->getMessage());
}
}
/* unset topos and isTrunk headers for calls to local extensions */
if ($add_unset_istrunk) {
$ext->splice('macro-dial-one', 's', 'setexttocall', new ext_gosub(1,'s','func-set-sipheader', 'isTrunk,unset'), '', 1);
}
if ($add_unset_topos) {
$ext->splice('macro-dial-one', 's', 'setexttocall', new ext_gosub(1,'s','func-set-sipheader', 'topos,unset'), '', 1);
}
/* Add inboundlookup agi for each inbound routes*/
$dids = FreePBX::Core()->getAllDIDs();
if (!empty($dids)) {
Expand Down Expand Up @@ -458,10 +460,10 @@ function nethcti3_get_config_late($engine) {
// Generate nethvoice report based on NethCTI configuration
nethvoice_report_config();

// Convert /etc/asterisk symlinks to file copied
if (file_exists('/var/lib/asterisk/bin/symlink2copies.sh')) {
system("/var/lib/asterisk/bin/symlink2copies.sh");
}
// Convert /etc/asterisk symlinks to file copied
if (file_exists('/var/lib/asterisk/bin/symlink2copies.sh')) {
system("/var/lib/asterisk/bin/symlink2copies.sh");
}

//Reload CTI
system("/var/www/html/freepbx/rest/lib/ctiReloadHelper.sh > /dev/null 2>&1 &");
Expand Down
Loading
Loading