Files
webgui/emhttp/plugins/dynamix.plugin.manager/scripts/language

433 lines
12 KiB
PHP
Executable File

#!/usr/bin/php -q
<?PHP
// Copyright 2005-2023, Lime Technology
// License: GPLv2 only
//
// Program updates made by Bergware International (April 2020)
// Program updates made by Bergware International (June 2022)
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
require_once "$docroot/webGui/include/Wrappers.php";
require_once "$docroot/webGui/include/publish.php";
$logger = 'language-manager';
$usage = <<<EOF
Process language files.
Usage: language install LANGUAGE-FILE
install a language
Usage: language [attribute name] LANGUAGE-FILE
obtain an attribute value
Usage: language check LANGUAGE
check and output the latest version of the language
Usage: language update LANGUAGE
update the language
Usage: language remove LANGUAGE
remove the language
Usage: language checkall
check the latest version of all installed languages
Usage: language updateall
update all installed languages
EOF;
// Error code to description (wget)
// ref: https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html
//
function error_desc($code) {
switch($code) {
case 0: return 'No errors';
case -1: return 'Generic error';
case 1: return 'Generic error';
case 2: return 'Parse error';
case 3: return 'File I/O error';
case 4: return 'Network failure';
case 5: return 'SSL verification failure';
case 6: return 'Username/password authentication failure';
case 7: return 'Protocol errors';
case 8: return 'Invalid URL / Server error response';
default: return 'Error code '.$code;
}
}
// Signal DONE to caller
//
function done($code) {
global $nchan;
if ($nchan) write('_DONE_','');
exit($code);
}
// Function to write either to console (echo) or nchan (curl)
// Default output is console, use optional parameter "nchan" to write to nchan instead
//
function write(...$messages){
global $nchan;
if ($nchan) {
foreach ($messages as $message) {
publish('plugins', $message,1,false);
}
} else {
foreach ($messages as $message) echo $message;
}
}
// Run command and obtain output
//
function run($command) {
$run = popen($command,'r');
while (!feof($run)) write(fgets($run));
return pclose($run);
}
// Run hooked scripts before correct execution of "method"
// method = install, update, remove, check
// hook programs receives three parameters: type=language and method and language-name
//
function pre_hooks() {
global $method, $name;
$language = (pathinfo($name)['extension']??'')=='xml' ? $name : "lang-$name.xml";
$hooks = "/usr/local/emhttp/plugins/dynamix.plugin.manager/pre-hooks";
foreach (glob("$hooks/*") as $hook) if (is_executable($hook)) {
write("Executing hook script: ".basename($hook)."\n");
run("$hook language $method $language");
}
}
// Run hooked scripts after successful or failed completion of "method"
// method = install, update, remove, check
// hook programs receives four parameters: type=language and method and language-name and error (empty if none)
//
function post_hooks($error='') {
global $method, $name;
$language = (pathinfo($name)['extension']??'')=='xml' ? $name : "lang-$name.xml";
$hooks = "/usr/local/emhttp/plugins/dynamix.plugin.manager/post-hooks";
foreach (glob("$hooks/*") as $hook) if (is_executable($hook)) {
write("Executing hook script: ".basename($hook)."\n");
run("$hook language $method $language $error");
}
}
// Download a file from a URL.
// Returns TRUE if success else FALSE and fills in error.
//
function download($url, $name, &$error) {
$plg = basename($url);
if ($file = popen("wget --compression=auto --no-cache --progress=dot -O $name $url 2>&1", 'r')) {
write("language: downloading: $plg ...\r");
$level = -1;
while (!feof($file)) {
if (preg_match('/\d+%/', fgets($file), $matches)) {
$percentage = substr($matches[0],0,-1);
if ($percentage > $level) {
write("language: downloading: $plg ... $percentage%\r");
$level = $percentage;
}
}
}
if (($perror = pclose($file)) == 0) {
write("language: downloading: $plg ... done\n");
return true;
} else {
$error = "$plg download failure (".error_desc($perror).")";
return false;
}
} else {
$error = "$plg failed to open";
return false;
}
}
// Interpret a language file
// Returns TRUE if success, else FALSE and fills in error string.
//
function language($method, $xml_file, &$error) {
global $docroot, $boot, $plugins, $tmp;
// parse language XML file
$xml = file_exists($xml_file) ? @simplexml_load_file($xml_file,NULL,LIBXML_NOCDATA) : false;
if ($xml === false) {
$error = "XML file doesn't exist or xml parse error";
return false;
}
switch ($method) {
case 'install':
$url = $xml->LanguageURL;
$name = $xml->LanguagePack;
$save = "$boot/dynamix/lang-$name.zip";
if (!file_exists($save)) {
if ($url) {
if (!download($url, $save, $error)) {
@unlink($save);
return false;
}
} else {
$error = "missing URL";
return false;
}
}
$path = "$docroot/languages/$name";
exec("mkdir -p $path");
@unlink("$docroot/webGui/javascript/translate.$name.js");
foreach (glob("$path/*.dot",GLOB_NOSORT) as $dot_file) unlink($dot_file);
exec("unzip -qqLjo -d $path $save", $dummy, $err);
if ($err > 1) {
@unlink($save);
exec("rm -rf $path");
$error = "unzip failed. Error code $err";
return false;
}
return true;
case 'remove':
$name = $xml->LanguagePack;
if ($name) {
$path = "$docroot/languages/$name";
exec("rm -rf $path");
@unlink("$docroot/webGui/javascript/translate.$name.js");
@unlink("$boot/lang-$name.xml");
@unlink("$plugins/lang-$name.xml");
@unlink("$tmp/lang-$name.xml");
@unlink("$boot/dynamix/lang-$name.zip");
return true;
} else {
$error = "missing language pack";
return false;
}
case 'dump':
// dump file: debugging
write(print_r($xml,true));
return true;
default:
// return single attribute
$error = "$method attribute not present";
return $xml->$method ?: false;
}
}
$docroot = '/usr/local/emhttp';
$boot = '/boot/config/plugins';
$plugins = '/var/log/plugins';
$tmp = '/tmp/plugins';
$method = $argv[1];
$nchan = $argv[$argc-1] == 'nchan'; // console or nchan output
// MAIN - single argument
if ($argc < 2) {
write($usage);
done(1);
}
// language checkall
// check all installed languages
//
if ($method == 'checkall') {
write("language: checking all language packs\n");
foreach (glob("$plugins/lang-*.xml", GLOB_NOSORT) as $link) {
$lang_file = @readlink($link);
if ($lang_file === false) continue;
if (language('LanguageURL', $lang_file, $error) === false) continue;
$name = str_replace('lang-', '', basename($lang_file, '.xml'));
$lang = language('Language', $lang_file, $error) ?: $name;
write("language: checking $lang language pack ...\n");
exec(realpath($argv[0])." check $name >/dev/null");
}
write("language: checking finished.\n");
done(0);
}
// language updateall
// update all installed languages
//
if ($method == 'updateall') {
write("language: updating all language packs\n");
foreach (glob("$plugins/lang-*.xml", GLOB_NOSORT) as $link) {
$lang_file = @readlink($link);
if ($lang_file === false) continue;
if (language('LanguageURL', $lang_file, $error) === false) continue;
$version = language('Version', $lang_file, $error);
$name = str_replace('lang-', '', basename($lang_file, '.xml'));
$lang = language('Language', $lang_file, $error) ?: $name;
$latest = language('Version', "$tmp/lang-$name.xml", $error);
// update only when newer
if (strcmp($latest, $version) > 0) {
write("language: updating $lang language pack ...\n");
exec(realpath($argv[0])." update $name >/dev/null");
}
}
write("language: updating finished.\n");
done(0);
}
// MAIN - two arguments
if ($argc < 3) {
write($usage);
done(1);
}
// language install [language_file]
//
if ($method == 'install') {
$argv[2] = preg_replace('#[\x00-\x1F\x80-\xFF]#', '', $argv[2]);
$name = basename($argv[2]);
write("language: installing language pack\n");
// check for URL
if (preg_match('#^https?://#',$argv[2])) {
$langURL = $argv[2];
$xml_file = "$tmp/$name";
write("language: downloading: $name\n");
if (!download($langURL, $xml_file, $error)) {
write("language: $error\n");
@unlink($xml_file);
done(1);
}
} else {
$xml_file = realpath($argv[2]);
}
$link_file = "$plugins/$name";
$lang_file = "$boot/$name";
@unlink($link_file);
// run hook scripts for pre processing
pre_hooks();
if (language('install', $xml_file, $error) === false) {
write("language: $error\n");
// run hook scripts for post processing
post_hooks($error);
done(1);
}
$lang = language('Language', $xml_file, $error) ?: substr($name,0,-4);
copy($xml_file, $lang_file);
symlink($lang_file, $link_file);
write("language: $lang language pack installed\n");
my_logger("$lang language pack installed", $logger);
// run hook scripts for post processing
post_hooks();
done(0);
}
// language check [language]
//
if ($method == 'check') {
$name = $argv[2];
write("language: checking language pack\n");
$link_file = "$plugins/lang-$name.xml";
$lang_file = @readlink($link_file);
if ($lang_file === false) {
write("language: $name language pack not installed\n");
done(1);
}
$templateURL = language('TemplateURL', $lang_file, $error);
if ($templateURL === false) {
write("language: $error\n");
done(1);
}
$xml_file = "$tmp/lang-$name.xml";
if (!download($templateURL, $xml_file, $error)) {
write("language: $error\n");
@unlink($xml_file);
done(1);
}
// run hook scripts for pre processing
pre_hooks();
$version = language('Version', $xml_file, $error);
if ($version === false) {
write("language: $error\n");
// run hook scripts for post processing
post_hooks($error);
done(1);
}
write("$version\n");
// run hook scripts for post processing
post_hooks();
done(0);
}
// language update [language]
//
if ($method == 'update') {
$name = $argv[2];
write("language: updating language pack\n");
$link_file = "$plugins/lang-$name.xml";
$lang_file = @readlink($link_file);
if ($lang_file === false) {
write("language: $name language pack not installed\n");
done(1);
}
// verify previous check has been done
$xml_file = "$tmp/lang-$name.xml";
if (!file_exists($xml_file)) {
write("language: update does not exist, perform a check first\n");
exit (1);
}
$lang = language('Language', $xml_file, $error) ?: $name;
// check for a reinstall of same version
$old_version = language('Version', $lang_file, $error);
$new_version = language('Version', $xml_file, $error);
if ($new_version == $old_version) {
write("language: $lang language pack not reinstalling same version\n");
done(1);
}
// install the updated plugin
@unlink("$boot/dynamix/lang-$name.zip");
@unlink($link_file);
// run hook scripts for pre processing
pre_hooks();
if (language('install', $xml_file, $error) === false) {
write("language: $error\n");
// run hook scripts for post processing
post_hooks($error);
done(1);
}
copy($xml_file, $lang_file);
symlink($lang_file, $link_file);
write("language: $lang language pack updated\n");
my_logger("$lang language pack updated", $logger);
// run hook scripts for post processing
post_hooks();
done(0);
}
// language remove [language]
//
if ($method == 'remove') {
$name = $argv[2];
write("language: removing language pack: $name\n");
$link_file = "$plugins/lang-$name.xml";
$lang_file = @readlink($link_file);
if ($lang_file === false) {
write("language: $name language pack not installed\n");
done(1);
}
$lang = language('Language', $lang_file, $error) ?: $name;
// run hook scripts for pre processing
pre_hooks();
if (language('remove', $lang_file, $error) === false) {
write("language: $error\n");
// run hook scripts for post processing
post_hooks($error);
done(1);
}
write("language: $lang language pack removed\n");
my_logger("$lang language pack removed", $logger);
// run hook scripts for post processing
post_hooks();
done(0);
}
// return attribute
//
$xml_file = $argv[2];
$value = language($method, $xml_file, $error);
if ($value === false) {
write("language: $error\n");
done(1);
}
write("$value\n");
done(0);
?>