From cb890aa264cc3e6155b85bc92e64c3f9294f0109 Mon Sep 17 00:00:00 2001
From: steve-lad <72376554+steve-lad@users.noreply.github.com>
Date: Tue, 22 Jun 2021 17:18:01 +0200
Subject: [PATCH] Update installer to check TFTP server is running and usable
Use dummy put to test and locate the TFTP server
Move all TFTP tests from extconfigs to install (reduces module constructor)
---
Sccp_manager.class.php | 3 +-
install.php | 184 +++++++++++++++++++++++++---
module.xml | 2 +-
sccpManClasses/extconfigs.class.php | 135 +-------------------
4 files changed, 174 insertions(+), 150 deletions(-)
diff --git a/Sccp_manager.class.php b/Sccp_manager.class.php
index 4c0d8dc..a18eade 100644
--- a/Sccp_manager.class.php
+++ b/Sccp_manager.class.php
@@ -956,7 +956,6 @@ class Sccp_manager extends \FreePBX_Helpers implements \BMO {
* Check file paths and permissions
*/
- // !TODO!: -TODO-: This function is getting a little big. Might be possible to sperate tftp work into it's own file/class. Initially, you need to remove the not working section and commented out section
function initializeSccpPath() {
global $db;
global $amp_conf;
@@ -978,7 +977,7 @@ class Sccp_manager extends \FreePBX_Helpers implements \BMO {
$driver = $this->FreePBX->Core->getAllDriversInfo();
$this->sccpvalues['sccp_compatible'] = array('keyword' => 'sccp_compatible', 'data' => $ver_id, 'type' => '1', 'seq' => '99');
- $this->sccppath = $this->extconfigs->validate_init_path($confDir, $this->sccpvalues);
+ //$this->sccppath = $this->extconfigs->validate_init_path($confDir, $this->sccpvalues);
$driver = $this->FreePBX->Core->getAllDriversInfo(); // Check that Sccp Driver has been updated by above
$read_config = $this->cnf_read->getConfig('sccp.conf');
diff --git a/install.php b/install.php
index d485969..305871a 100644
--- a/install.php
+++ b/install.php
@@ -10,6 +10,8 @@ global $version;
global $aminterface;
global $mobile_hw;
global $useAmiForSoftKeys;
+global $settingsFromDb;
+global $cnf_int;
$mobile_hw = '0';
$autoincrement = (($amp_conf["AMPDBENGINE"] == "sqlite") || ($amp_conf["AMPDBENGINE"] == "sqlite3")) ? "AUTOINCREMENT" : "AUTO_INCREMENT";
$table_req = array('sccpdevice', 'sccpline', 'sccpsettings');
@@ -17,8 +19,14 @@ $sccp_compatible = 0;
$chanSCCPWarning = true;
$db_config = '';
$sccp_version = array();
+$cnf_int = \FreePBX::Config();
CheckSCCPManagerDBTables($table_req);
+
+$stmt = $db->prepare("SELECT * FROM sccpsettings");
+$stmt->execute();
+$settingsFromDb = $stmt->fetchAll(\PDO::FETCH_ASSOC);
+
CheckAsteriskVersion();
// Have essential tables so can create Sccp_manager object and verify have aminterface
@@ -66,6 +74,7 @@ if ($chanSCCPWarning) {
}
Setup_RealTime();
addDriver($sccp_compatible);
+checkTftpServer();
outn("
");
outn("Install Complete !");
outn("
");
@@ -283,7 +292,6 @@ function Get_DB_config($sccp_compatible)
function CheckSCCPManagerDBTables($table_req)
{
// These tables should already exist having been created by FreePBX through module.xml
- global $amp_conf;
global $db;
outn("
" . _("Checking for required Sccp_manager database tables..") . "");
foreach ($table_req as $value) {
@@ -300,17 +308,13 @@ function CheckSCCPManagerDBVersion()
{
global $db;
outn("" . _("Checking for previous version of Sccp_manager.") . "");
- $check = $db->getRow("SELECT data FROM `sccpsettings` where keyword ='sccp_compatible'", DB_FETCHMODE_ASSOC);
- if (DB::IsError($check)) {
+
+ if (!isset($settingsFromDb['sccp_compatible']['data'])) {
outn(_("No previous version found "));
return false;
}
- if (!empty($check['data'])) {
- outn(_("Found DB Schema : " . $check['data']));
- return $check['data'];
- } else {
- return false;
- }
+ outn(_("Found DB Schema : {$settingsFromDb['sccp_compatible']['data']}"));
+ return $settingsFromDb['sccp_compatible']['data'];
}
/* notused */
@@ -707,8 +711,8 @@ function InstallDB_CreateSccpDeviceConfigView($sccp_compatible)
function createBackUpConfig()
{
global $amp_conf;
+ global $cnf_int;
outn("" . _("Creating Config BackUp") . "");
- $cnf_int = \FreePBX::Config();
$backup_files = array('extensions','extconfig','res_mysql', 'res_config_mysql','sccp','sccp_hardware','sccp_extensions');
$backup_ext = array('_custom.conf', '_additional.conf','.conf');
$dir = $cnf_int->get('ASTETCDIR');
@@ -745,9 +749,8 @@ function createBackUpConfig()
function RenameConfig()
{
- global $amp_conf;
outn("" . _("Move Old Config") . "");
- $cnf_int = \FreePBX::Config();
+ global $cnf_int;
$rename_files = array('sccp_hardware','sccp_extensions');
$rename_ext = array('_custom.conf', '_additional.conf','.conf');
$dir = $cnf_int->get('ASTETCDIR');
@@ -764,7 +767,7 @@ function Setup_RealTime()
{
outn("" . _("Checking realtime configuration ...") . "");
global $amp_conf;
- $cnf_int = \FreePBX::Config();
+ global $cnf_int;
$cnf_wr = \FreePBX::WriteConfig();
$cnf_read = \FreePBX::LoadConfig();
@@ -858,7 +861,7 @@ function addDriver($sccp_compatible) {
$contents = "";
file_put_contents($file, $contents);
- $cnf_int = \FreePBX::Config();
+ global $cnf_int;
$dir = $cnf_int->get('ASTETCDIR');
if (!file_exists("{$dir}/sccp.conf")) { // System re Config
outn("" . _("Adding default configuration file ...") . "");
@@ -866,5 +869,158 @@ function addDriver($sccp_compatible) {
file_put_contents("{$dir}/sccp.conf", $sccpfile);
}
}
+function checkTftpServer() {
+ global $db;
+ global $cnf_int;
+ $confDir = $cnf_int->get('ASTETCDIR');
+ // TODO: add option to use external server
+ $remoteFile = "TestFileXXX111.txt"; // should not exist
+ tftp_put_test_file();
+
+ $possibleFtpDirs = array('/srv', '/srv/tftp','/var/lib/tftp', '/tftpboot');
+ foreach ($possibleFtpDirs as $dirToTest) {
+ if (file_exists("{$dirToTest}/{$remoteFile}")) {
+ $tftpRootPath = $dirToTest;
+ unlink("{$dirToTest}/{$remoteFile}");
+ outn("" . _("Found ftp root dir at {$dirToTest}") . "");
+
+ $sql = "REPLACE INTO sccpsettings (keyword, data, seq, type) VALUES ('tftp_path', '{$tftpRootPath}','0','0');";
+ $results = $db->query($sql);
+ if (DB::IsError($results)) {
+ die_freepbx(sprintf(_("Error updating tftp_path in sccpsettings. Command was: %s; error was: %s "), $sql, $results->getMessage()));
+ }
+ break;
+ }
+ }
+
+ if (empty($tftpRootPath)) {
+ die_freepbx(_("Either tftp server is down or TFTP root is non standard. Please fix, refresh, and try again"));
+ }
+ if (!is_writeable($tftpRootPath)) {
+ die_freepbx(_("{$tftpRootPath} is not writable by user asterisk. Please fix, refresh and try again"));
+ }
+
+ $adv_config = array('tftproot' => '',
+ 'firmware' => 'firmware',
+ 'settings' => 'settings',
+ 'locales' => 'locales',
+ 'languages' => 'languages',
+ 'templates' => 'templates',
+ 'dialplan' => 'dialplan',
+ 'softkey' => 'softkey'
+ );
+
+ $adv_tree['pro'] = array('templates' => 'tftproot',
+ 'settings' => 'tftproot',
+ 'locales' => 'tftproot',
+ 'firmware' => 'tftproot',
+ 'languages' => 'locales',
+ 'dialplan' => 'tftproot',
+ 'softkey' => 'tftproot'
+ );
+
+ $adv_tree['def'] = array('templates' => 'tftproot',
+ 'settings' => '',
+ 'locales' => '',
+ 'firmware' => '',
+ 'languages' => 'tftproot',
+ 'dialplan' => '',
+ 'softkey' => ''
+ );
+
+ $base_tree = array('tftp_templates' => 'templates',
+ 'tftp_path_store' => 'settings',
+ 'tftp_lang_path' => 'languages',
+ 'tftp_firmware_path' => 'firmware',
+ 'tftp_dialplan' => 'dialplan',
+ 'tftp_softkey' => 'softkey'
+ );
+
+ $base_config = array('asterisk' => $confDir,
+ 'sccp_conf' => "$confDir/sccp.conf",
+ 'tftp_path' => $tftpRootPath);
+
+ if (!empty($db_vars['tftp_rewrite_path'])) {
+ $adv_ini = $db_vars['tftp_rewrite_path']["data"];
+ }
+
+ $adv_tree_mode = 'def';
+ if (empty($db_vars["tftp_rewrite"])) {
+ $db_vars["tftp_rewrite"]["data"] = "off";
+ }
+
+ $adv_config['tftproot'] = $base_config["tftp_path"];
+ if ($settingsFromDb["tftp_rewrite"]["data"] == 'pro') {
+ $adv_tree_mode = 'pro';
+ if (!empty($adv_ini)) { // something found in external conflicts
+ $adv_ini .= '/index.cnf';
+ if (file_exists($adv_ini)) {
+ $adv_ini_array = parse_ini_file($adv_ini);
+ $adv_config = array_merge($adv_config, $adv_ini_array);
+ }
+ }
+ }
+ if ($settingsFromDb["tftp_rewrite"]["data"] == 'on') {
+ $adv_tree_mode = 'def';
+ }
+ foreach ($adv_tree[$adv_tree_mode] as $key => $value) {
+ if (!empty($adv_config[$key])) {
+ if (!empty($value)) {
+ if (substr($adv_config[$key], 0, 1) != "/") {
+ $adv_config[$key] = $adv_config[$value] . '/' . $adv_config[$key];
+ }
+ } else {
+ $adv_config[$key] = $adv_config['tftproot'];
+ }
+ }
+ }
+ foreach ($base_tree as $key => $value) {
+ $base_config[$key] = $adv_config[$value];
+ if (!file_exists($base_config[$key])) {
+ if (!mkdir($base_config[$key], 0777, true)) {
+ die('Error creating dir : ' . $base_config[$key]);
+ }
+ }
+ }
+
+ if (!file_exists($base_config["tftp_templates"] . '/XMLDefault.cnf.xml_template')) {
+ $src_path = $_SERVER['DOCUMENT_ROOT'] . '/admin/modules/sccp_manager/conf/';
+ $dst_path = $base_config["tftp_templates"] . '/';
+ foreach (glob($src_path . '*.*_template') as $filename) {
+ copy($filename, $dst_path . basename($filename));
+ }
+ }
+ return $base_config;
+}
+
+function tftp_put_test_file()
+{
+ // https://datatracker.ietf.org/doc/html/rfc1350
+ $socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
+ $host = "127.0.0.1"; // TODO: Should consider remote TFT Servers in future
+
+ // create the WRQ request packet
+ $packet = chr(0) . chr(2) . "TestFileXXX111.txt" . chr(0) . 'netascii' . chr(0);
+ // UDP is connectionless, so we just send it.
+ socket_sendto($socket, $packet, strlen($packet), MSG_EOR, $host, 69);
+
+ $buffer = '';
+ $port = '';
+ $ret = '';
+
+ // Should now receive an ack packet
+ socket_recvfrom($socket, $buffer, 4, MSG_PEEK, $host, $port);
+
+ // Then should send our data packet
+ $packet = chr(0) . chr(3) . chr(0) . chr(1) . 'This is a test file';
+ socket_sendto($socket, $packet, strlen($packet), MSG_EOR, $host, $port);
+
+ // finally will recieve an ack packet
+ socket_recvfrom($socket, $buffer, 4, MSG_PEEK, $host, $port);
+
+ socket_close($socket);
+
+ return;
+}
?>
diff --git a/module.xml b/module.xml
index 57723fe..cd5c29f 100644
--- a/module.xml
+++ b/module.xml
@@ -1,7 +1,7 @@
sccp_manager
SCCP Manager
- 14.3.0.1
+ 14.3.0.0
setup
SCCP Connectivity
Steve Lad, Alex GP
diff --git a/sccpManClasses/extconfigs.class.php b/sccpManClasses/extconfigs.class.php
index 75cdd6d..e73df46 100644
--- a/sccpManClasses/extconfigs.class.php
+++ b/sccpManClasses/extconfigs.class.php
@@ -113,8 +113,7 @@ class extconfigs
"hotline_extension" => '*60', # !TODO!: Is this a good default extension to dial for hotline ?
"hotline_label" => 'hotline',
"devicetable" => 'sccpdevice',
- "linetable" => 'sccpline',
- "tftp_path" => '/tftpboot'
+ "linetable" => 'sccpline'
);
private $keysetdefault = array('onhook' => 'redial,newcall,cfwdall,cfwdbusy,cfwdnoanswer,pickup,gpickup,dnd,private',
'connected' => 'hold,endcall,park,vidmode,select,cfwdall,cfwdbusy,idivert,monitor',
@@ -221,137 +220,7 @@ class extconfigs
'New Zealand' => array('offset' => '720', 'daylight' => true)
);
- public function validate_init_path($confDir = '', $db_vars) {
- $adv_config = array('tftproot' => '',
- 'firmware' => 'firmware',
- 'settings' => 'settings',
- 'locales' => 'locales',
- 'languages' => 'languages',
- 'templates' => 'templates',
- 'dialplan' => 'dialplan',
- 'softkey' => 'softkey'
- );
-
- $adv_tree['pro'] = array('templates' => 'tftproot',
- 'settings' => 'tftproot',
- 'locales' => 'tftproot',
- 'firmware' => 'tftproot',
- 'languages' => 'locales',
- 'dialplan' => 'tftproot',
- 'softkey' => 'tftproot'
- );
-
- $adv_tree['def'] = array('templates' => 'tftproot',
- 'settings' => '',
- 'locales' => '',
- 'firmware' => '',
- 'languages' => 'tftproot',
- 'dialplan' => '',
- 'softkey' => ''
- );
-
- $base_tree = array('tftp_templates' => 'templates',
- 'tftp_path_store' => 'settings',
- 'tftp_lang_path' => 'languages',
- 'tftp_firmware_path' => 'firmware',
- 'tftp_dialplan' => 'dialplan',
- 'tftp_softkey' => 'softkey'
- );
-
- if (empty($confDir)) {
- return array('error' => 'empty СonfDir');
- }
-
- $base_config = array('asterisk' => $confDir,
- 'sccp_conf' => "$confDir/sccp.conf",
- 'tftp_path' => '');
-
-// Test Base dir (/tftproot)
- if (!empty($db_vars["tftp_path"])) {
- if (file_exists($db_vars["tftp_path"]["data"])) {
- $base_config["tftp_path"] = $db_vars["tftp_path"]["data"];
- }
- }
- if (empty($base_config["tftp_path"])) {
- if (file_exists($this->getExtConfig('sccpDefaults', "tftp_path"))) {
- $base_config["tftp_path"] = $this->getExtConfig('sccpDefaults', "tftp_path");
- }
- }
- if (empty($base_config["tftp_path"])) {
- if (!empty($this->paren_class)) {
- $this->paren_class->class_error['tftp_path'] = 'Tftp path not exist or not defined';
- }
- return array('error' => 'empty tftp_path');
- }
- if (!is_writeable($base_config["tftp_path"])) {
- if (!empty($this->paren_class)) {
- $this->paren_class->class_error['tftp_path'] = 'No write permission on tftp DIR';
- }
- return array('error' => 'No write permission on tftp DIR');
- }
-// END Test Base dir (/tftproot)
-
- if (!empty($db_vars['tftp_rewrite_path'])) {
- $adv_ini = $db_vars['tftp_rewrite_path']["data"];
- }
-
- $adv_tree_mode = 'def';
- if (empty($db_vars["tftp_rewrite"])) {
- $db_vars["tftp_rewrite"]["data"] = "off";
- }
-
- $adv_config['tftproot'] = $base_config["tftp_path"];
- if ($db_vars["tftp_rewrite"]["data"] == 'pro') {
- $adv_tree_mode = 'pro';
- if (!empty($adv_ini)) { // something found in external conflicts
- $adv_ini .= '/index.cnf';
- if (file_exists($adv_ini)) {
- $adv_ini_array = parse_ini_file($adv_ini);
- $adv_config = array_merge($adv_config, $adv_ini_array);
- }
- }
- }
- if ($db_vars["tftp_rewrite"]["data"] == 'on') {
- $adv_tree_mode = 'def';
- }
- foreach ($adv_tree[$adv_tree_mode] as $key => $value) {
- if (!empty($adv_config[$key])) {
- if (!empty($value)) {
- if (substr($adv_config[$key], 0, 1) != "/") {
- $adv_config[$key] = $adv_config[$value] . '/' . $adv_config[$key];
- }
- } else {
- $adv_config[$key] = $adv_config['tftproot'];
- }
- }
- }
- foreach ($base_tree as $key => $value) {
- $base_config[$key] = $adv_config[$value];
- if (!file_exists($base_config[$key])) {
- if (!mkdir($base_config[$key], 0777, true)) {
- die('Error creating dir : ' . $base_config[$key]);
- }
- }
- }
-
- // TFTP -REWrite double model
- if (empty($_SERVER['DOCUMENT_ROOT'])) {
- if (!empty($this->paren_class)) {
- $this->paren_class->class_error['DOCUMENT_ROOT'] = 'Empty DOCUMENT_ROOT';
- }
- $base_config['error'] = 'Empty DOCUMENT_ROOT';
- return $base_config;
- }
-
- if (!file_exists($base_config["tftp_templates"] . '/XMLDefault.cnf.xml_template')) {
- $src_path = $_SERVER['DOCUMENT_ROOT'] . '/admin/modules/sccp_manager/conf/';
- $dst_path = $base_config["tftp_templates"] . '/';
- foreach (glob($src_path . '*.*_template') as $filename) {
- copy($filename, $dst_path . basename($filename));
- }
- }
- return $base_config;
- }
+
public function validate_RealTime( $connector )
{