From 0e00a228d67d77fadc80eee2df04c2cec25b8db8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 30 May 2025 21:25:20 +0200 Subject: [PATCH 01/27] global-functions: $WaitForFile: use :retry for simplification, ... ... and to work around restrictions in new file handling. --- global-functions.rsc | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 3a62169..fa5d2be 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1746,16 +1746,14 @@ :global MAX; :set FileName [ $CleanFilePath $FileName ]; - :local I 1; :local Delay ([ $MAX [ $EitherOr $WaitTime 2s ] 100ms ] / 10); - :while ([ :len [ /file/find where name=$FileName ] ] = 0) do={ - :if ($I >= 10) do={ - :return false; - } - :delay $Delay; - :set I ($I + 1); - } + :do { + :retry { + /file/get $FileName; + :return true; + } delay=$Delay max=10; + } on-error={ } :return false; } From cb984a5e527a12aaa2336cfd66f180302755f066 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 30 May 2025 20:34:07 +0200 Subject: [PATCH 02/27] global-functions: introduce $FileExists --- global-functions.rsc | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index fa5d2be..ddddc40 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -38,6 +38,7 @@ :global ExitError; :global FetchHuge; :global FetchUserAgentStr; +:global FileExists; :global FileGet; :global FormatLine; :global FormatMultiLines; @@ -530,6 +531,29 @@ $Resource->"architecture-name" . " " . $Caller . "/Fetch (https://rsc.eworm.de/)"); } +# check for existence of file, optionally with type +:set FileExists do={ + :local FileName [ :tostr $1 ]; + :local Type [ :tostr $2 ]; + + :global FileGet; + + :local FileVal [ $FileGet $FileName ]; + :if ($FileVal = false) do={ + :return false; + } + + :if ([ :len ($FileVal->"size") ] = 0) do={ + :return false; + } + + :if ([ :len $Type ] = 0 || $FileVal->"type" = $Type) do={ + :return true; + } + + :return false; +} + # get file properties in array, or false on error :set FileGet do={ :local FileName [ :tostr $1 ]; From 8353a8547f45a18e167b8ffd3779d8bd469dd1c7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 30 May 2025 20:44:49 +0200 Subject: [PATCH 03/27] global-functions: $DownloadPackage: use $FileExists ... ... to work around restrictions in new file handling. --- global-functions.rsc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index ddddc40..50426b6 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -365,6 +365,7 @@ :global CertificateAvailable; :global CleanFilePath; + :global FileExists; :global LogPrint; :global MkDir; :global RmFile; @@ -385,7 +386,7 @@ :return false; } - :if ([ :len [ /file/find where name=$PkgDest type="package" ] ] > 0) do={ + :if ([ $FileExists $PkgDest "package" ] = true) do={ $LogPrint info $0 ("Package file " . $PkgName . " already exists."); :return true; } @@ -407,7 +408,7 @@ :return false; } - :if ([ /file/get [ find where name=$PkgDest ] type ] != "package") do={ + :if ([ $FileExists $PkgDest "package" ] = false) do={ $LogPrint warning $0 ("Downloaded file is not a package, removing."); $RmFile $PkgDest; :return false; From a2f837be591e4e64f2634e1d2e57352989326e98 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 30 May 2025 22:39:18 +0200 Subject: [PATCH 04/27] backup-email: use :retry and $FileExists ... ... to work around restrictions in new file handling. --- backup-email.rsc | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/backup-email.rsc b/backup-email.rsc index 632d2e6..cff6fd8 100644 --- a/backup-email.rsc +++ b/backup-email.rsc @@ -27,6 +27,7 @@ :global CleanName; :global DeviceInfo; + :global FileExists; :global FormatLine; :global LogPrint; :global MkDir; @@ -124,16 +125,16 @@ attach=$Attach; remove-attach=true }); # wait for the mail to be sent - :local I 0; - :while ([ :len [ /file/find where name ~ ($FilePath . "\\.(backup|rsc)\$") ] ] > 0) do={ - :if ($I >= 120) do={ - $LogPrint warning $ScriptName ("Files are still available, sending e-mail failed."); - :set PackagesUpdateBackupFailure true; - :set ExitOK true; - :error false; - } - :delay 1s; - :set I ($I + 1); + :do { + :retry { + :if ([ $FileExists ($FilePath . ".backup") "backup" ] = true || \ + [ $FileExists ($FilePath . ".rsc") "script" ] = true) do={ + :error "Files are still available."; + } + } delay=1s max=120; + } on-error={ + $LogPrint warning $ScriptName ("Files are still available, sending e-mail failed."); + :set PackagesUpdateBackupFailure true; } } do={ :global ExitError; $ExitError $ExitOK [ :jobname ] $Err; From 43bac7c33c50e164ff7ac56029519d510bc08973 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 2 Jun 2025 23:52:29 +0200 Subject: [PATCH 05/27] backup-email: check for .conf file --- backup-email.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backup-email.rsc b/backup-email.rsc index cff6fd8..cc62105 100644 --- a/backup-email.rsc +++ b/backup-email.rsc @@ -127,7 +127,8 @@ # wait for the mail to be sent :do { :retry { - :if ([ $FileExists ($FilePath . ".backup") "backup" ] = true || \ + :if ([ $FileExists ($FilePath . ".conf") ".conf file" ] = true || \ + [ $FileExists ($FilePath . ".backup") "backup" ] = true || \ [ $FileExists ($FilePath . ".rsc") "script" ] = true) do={ :error "Files are still available."; } From daee05dbd7c03aa7ce977ba7856234026185c4a1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 2 Jun 2025 23:49:50 +0200 Subject: [PATCH 06/27] backup-email: add a comment why files are not removed --- backup-email.rsc | 1 + 1 file changed, 1 insertion(+) diff --git a/backup-email.rsc b/backup-email.rsc index cc62105..8015bea 100644 --- a/backup-email.rsc +++ b/backup-email.rsc @@ -137,6 +137,7 @@ $LogPrint warning $ScriptName ("Files are still available, sending e-mail failed."); :set PackagesUpdateBackupFailure true; } + # do not remove the files here, as the mail is still queued! } do={ :global ExitError; $ExitError $ExitOK [ :jobname ] $Err; } From e3284ca77081642d2105d6a6773fa6767188dbec Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 30 May 2025 22:46:03 +0200 Subject: [PATCH 07/27] mod/notification-email: use $FileExists ... ... to work around restrictions in new file handling. --- mod/notification-email.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mod/notification-email.rsc b/mod/notification-email.rsc index 5293766..75e11b9 100644 --- a/mod/notification-email.rsc +++ b/mod/notification-email.rsc @@ -40,6 +40,7 @@ :global EitherOr; :global EMailGenerateFrom; + :global FileExists; :global IsDNSResolving; :global IsTimeSync; :global LogPrint; @@ -93,7 +94,7 @@ :onerror Err { :local Attach ({}); :foreach File in=[ :toarray [ $EitherOr ($Message->"attach") "" ] ] do={ - :if ([ :len [ /file/find where name=$File ] ] = 1) do={ + :if ([ $FileExists $File ] = true) do={ :set Attach ($Attach, $File); } else={ $LogPrint warning $0 ("File '" . $File . "' does not exist, can not attach."); From 2d81984aed8894200e4f8c6c72596b8b05bdbb93 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 30 May 2025 22:46:16 +0200 Subject: [PATCH 08/27] mod/notification-email: use $RmFile --- mod/notification-email.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mod/notification-email.rsc b/mod/notification-email.rsc index 75e11b9..ad9762a 100644 --- a/mod/notification-email.rsc +++ b/mod/notification-email.rsc @@ -44,6 +44,7 @@ :global IsDNSResolving; :global IsTimeSync; :global LogPrint; + :global RmFile; :local AllDone true; :local QueueLen [ :len $EmailQueue ]; @@ -111,7 +112,7 @@ :set Wait false; :if (($Message->"remove-attach") = true) do={ :foreach File in=$Attach do={ - /file/remove $File; + $RmFile $File; } } } From 80aed200fd7400e4a4958ba314912488780be635 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 30 May 2025 22:48:57 +0200 Subject: [PATCH 09/27] mod/ssh-keys-import: use $FileExists ... ... to work around restrictions in new file handling. --- mod/ssh-keys-import.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mod/ssh-keys-import.rsc b/mod/ssh-keys-import.rsc index 9467525..7bdc95d 100644 --- a/mod/ssh-keys-import.rsc +++ b/mod/ssh-keys-import.rsc @@ -75,6 +75,7 @@ :local User [ :tostr $2 ]; :global EitherOr; + :global FileExists; :global LogPrint; :global ParseKeyValueStore; :global SSHKeysImport; @@ -84,8 +85,7 @@ :return false; } - :local File [ /file/find where name=$FileName ]; - :if ([ :len $File ] = 0) do={ + :if ([ $FileExists $FileName ] = true) do={ $LogPrint warning $0 ("File '" . $FileName . "' does not exist."); :return false; } From 30b80e903dbf80510fbb05f21c598ecf6c1834d7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 30 May 2025 22:41:03 +0200 Subject: [PATCH 10/27] telegram-chat: use $FileExists ... ... to work around restrictions in new file handling. --- telegram-chat.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/telegram-chat.rsc b/telegram-chat.rsc index fdd0883..7f7b7a7 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -30,6 +30,7 @@ :global CertificateAvailable; :global EitherOr; :global EscapeForRegEx; + :global FileExists; :global GetRandom20CharAlNum; :global IfThenElse; :global LogPrint; @@ -154,7 +155,7 @@ :if ([ $WaitForFile ($File . ".done") [ $EitherOr $TelegramChatRunTime 20s ] ] = false) do={ :set State ([ $SymbolForNotification "warning-sign" ] . "The command did not finish, still running in background.\n\n"); } - :if ([ :len [ /file/find where name=($File . ".failed") ] ] > 0) do={ + :if ([ $FileExists ($File . ".failed") ] = true) do={ :set State ([ $SymbolForNotification "cross-mark" ] . "The command failed with an error!\n\n"); } :local Content ([ /file/read chunk-size=32768 file=$File as-value ]->"data"); From 5b15c82bb11f9da1b6858504dc1e0de401e91c8f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 2 Jun 2025 22:16:43 +0200 Subject: [PATCH 11/27] capsman-download-packages: use $FileGet ... ... to work around restrictions in new file handling. --- capsman-download-packages.capsman.rsc | 3 ++- capsman-download-packages.template.rsc | 3 ++- capsman-download-packages.wifi.rsc | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/capsman-download-packages.capsman.rsc b/capsman-download-packages.capsman.rsc index cab1e4c..e296e15 100644 --- a/capsman-download-packages.capsman.rsc +++ b/capsman-download-packages.capsman.rsc @@ -20,6 +20,7 @@ :global CleanFilePath; :global DownloadPackage; + :global FileGet; :global LogPrint; :global MkDir; :global RmFile; @@ -42,7 +43,7 @@ :error false; } - :if ([ :len [ /file/find where name=$PackagePath type="directory" ] ] = 0) do={ + :if ([ $FileGet $PackagePath ] = false) do={ :if ([ $MkDir $PackagePath ] = false) do={ $LogPrint warning $ScriptName ("Creating directory at CAPsMAN package path (" . \ $PackagePath . ") failed!"); diff --git a/capsman-download-packages.template.rsc b/capsman-download-packages.template.rsc index ea41120..4040d4d 100644 --- a/capsman-download-packages.template.rsc +++ b/capsman-download-packages.template.rsc @@ -21,6 +21,7 @@ :global CleanFilePath; :global DownloadPackage; + :global FileGet; :global LogPrint; :global MkDir; :global RmFile; @@ -44,7 +45,7 @@ :error false; } - :if ([ :len [ /file/find where name=$PackagePath type="directory" ] ] = 0) do={ + :if ([ $FileGet $PackagePath ] = false) do={ :if ([ $MkDir $PackagePath ] = false) do={ $LogPrint warning $ScriptName ("Creating directory at CAPsMAN package path (" . \ $PackagePath . ") failed!"); diff --git a/capsman-download-packages.wifi.rsc b/capsman-download-packages.wifi.rsc index a810356..809fe8e 100644 --- a/capsman-download-packages.wifi.rsc +++ b/capsman-download-packages.wifi.rsc @@ -20,6 +20,7 @@ :global CleanFilePath; :global DownloadPackage; + :global FileGet; :global LogPrint; :global MkDir; :global RmFile; @@ -42,7 +43,7 @@ :error false; } - :if ([ :len [ /file/find where name=$PackagePath type="directory" ] ] = 0) do={ + :if ([ $FileGet $PackagePath ] = false) do={ :if ([ $MkDir $PackagePath ] = false) do={ $LogPrint warning $ScriptName ("Creating directory at CAPsMAN package path (" . \ $PackagePath . ") failed!"); From 15fd522d3db507cc7c22af9cd59ff85d41a5be6f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 30 May 2025 23:22:59 +0200 Subject: [PATCH 12/27] capsman-download-packages: adopt new functionality from file menu --- capsman-download-packages.capsman.rsc | 8 ++++---- capsman-download-packages.template.rsc | 8 ++++---- capsman-download-packages.wifi.rsc | 8 ++++---- doc/capsman-download-packages.md | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/capsman-download-packages.capsman.rsc b/capsman-download-packages.capsman.rsc index e296e15..aaebf5c 100644 --- a/capsman-download-packages.capsman.rsc +++ b/capsman-download-packages.capsman.rsc @@ -4,7 +4,7 @@ # Michael Gisbers # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.15 +# requires RouterOS, version=7.18 # # download and cleanup packages for CAP installation from CAPsMAN # https://rsc.eworm.de/doc/capsman-download-packages.md @@ -54,8 +54,8 @@ "). Please place your packages!"); } - :foreach Package in=[ /file/find where type=package \ - package-version!=$InstalledVersion name~("^" . $PackagePath) ] do={ + :foreach Package in=[ /file/find recursive where path=$PackagePath \ + type="package" package-version!=$InstalledVersion ] do={ :local File [ /file/get $Package ]; :if ($File->"package-architecture" = "mips") do={ :set ($File->"package-architecture") "mipsbe"; @@ -67,7 +67,7 @@ } } - :if ([ :len [ /file/find where type=package name~("^" . $PackagePath) ] ] = 0) do={ + :if ([ :len [ /file/find recursive where path=$PackagePath type="package" ] ] = 0) do={ $LogPrint info $ScriptName ("No packages available, downloading default set."); :foreach Arch in={ "arm"; "mipsbe" } do={ :foreach Package in={ "routeros"; "wireless" } do={ diff --git a/capsman-download-packages.template.rsc b/capsman-download-packages.template.rsc index 4040d4d..ebbba70 100644 --- a/capsman-download-packages.template.rsc +++ b/capsman-download-packages.template.rsc @@ -4,7 +4,7 @@ # Michael Gisbers # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.15 +# requires RouterOS, version=7.18 # # download and cleanup packages for CAP installation from CAPsMAN # https://rsc.eworm.de/doc/capsman-download-packages.md @@ -56,8 +56,8 @@ "). Please place your packages!"); } - :foreach Package in=[ /file/find where type=package \ - package-version!=$InstalledVersion name~("^" . $PackagePath) ] do={ + :foreach Package in=[ /file/find recursive where path=$PackagePath \ + type="package" package-version!=$InstalledVersion ] do={ :local File [ /file/get $Package ]; :if ($File->"package-architecture" = "mips") do={ :set ($File->"package-architecture") "mipsbe"; @@ -69,7 +69,7 @@ } } - :if ([ :len [ /file/find where type=package name~("^" . $PackagePath) ] ] = 0) do={ + :if ([ :len [ /file/find recursive where path=$PackagePath type="package" ] ] = 0) do={ $LogPrint info $ScriptName ("No packages available, downloading default set."); # NOT /interface/wifi/ # :foreach Arch in={ "arm"; "mipsbe" } do={ diff --git a/capsman-download-packages.wifi.rsc b/capsman-download-packages.wifi.rsc index 809fe8e..7de0431 100644 --- a/capsman-download-packages.wifi.rsc +++ b/capsman-download-packages.wifi.rsc @@ -4,7 +4,7 @@ # Michael Gisbers # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.15 +# requires RouterOS, version=7.18 # # download and cleanup packages for CAP installation from CAPsMAN # https://rsc.eworm.de/doc/capsman-download-packages.md @@ -54,8 +54,8 @@ "). Please place your packages!"); } - :foreach Package in=[ /file/find where type=package \ - package-version!=$InstalledVersion name~("^" . $PackagePath) ] do={ + :foreach Package in=[ /file/find recursive where path=$PackagePath \ + type="package" package-version!=$InstalledVersion ] do={ :local File [ /file/get $Package ]; :if ($File->"package-architecture" = "mips") do={ :set ($File->"package-architecture") "mipsbe"; @@ -67,7 +67,7 @@ } } - :if ([ :len [ /file/find where type=package name~("^" . $PackagePath) ] ] = 0) do={ + :if ([ :len [ /file/find recursive where path=$PackagePath type="package" ] ] = 0) do={ $LogPrint info $ScriptName ("No packages available, downloading default set."); :foreach Arch in={ "arm"; "arm64" } do={ :local Packages { "arm"={ "routeros"; "wifi-qcom"; "wifi-qcom-ac" }; diff --git a/doc/capsman-download-packages.md b/doc/capsman-download-packages.md index 5722227..4daad49 100644 --- a/doc/capsman-download-packages.md +++ b/doc/capsman-download-packages.md @@ -4,7 +4,7 @@ Download packages for CAP upgrade from CAPsMAN [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.18-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) From c3d3d61f92d4d3e219373045dbd3b982af18a824 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 2 Jun 2025 15:58:00 +0200 Subject: [PATCH 13/27] packages-update: support deferred reboot with longer interval --- doc/packages-update.md | 4 ++-- packages-update.rsc | 11 ++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/doc/packages-update.md b/doc/packages-update.md index 75225fe..a0a1795 100644 --- a/doc/packages-update.md +++ b/doc/packages-update.md @@ -46,8 +46,8 @@ Configuration The configuration goes to `global-config-overlay`, this is the only parameter: -* `PackagesUpdateDeferReboot`: defer the reboot for night (between 3 AM - and 5 AM) +* `PackagesUpdateDeferReboot`: defer the reboot for night (between 3 AM and + 5 AM), use a numerical value in days suffixed with a `d` to defer further By modifying the scheduler's `start-time` you can force the reboot at different time. diff --git a/packages-update.rsc b/packages-update.rsc index 4fde131..43f6749 100644 --- a/packages-update.rsc +++ b/packages-update.rsc @@ -31,19 +31,24 @@ :local Schedule do={ :local ScriptName [ :tostr $1 ]; + :global PackagesUpdateDeferReboot; + :global GetRandomNumber; + :global IfThenElse; :global LogPrint; :global RebootForUpdate do={ /system/reboot; } + :local Interval [ $IfThenElse ($PackagesUpdateDeferReboot >= 1d) $PackagesUpdateDeferReboot 1d ]; :local StartTime [ :tostr [ :totime (10800 + [ $GetRandomNumber 7200 ]) ] ]; - /system/scheduler/add name="_RebootForUpdate" start-time=$StartTime interval=1d \ + /system/scheduler/add name="_RebootForUpdate" start-time=$StartTime interval=$Interval \ on-event=("/system/scheduler/remove \"_RebootForUpdate\"; " . \ ":global RebootForUpdate; \$RebootForUpdate;"); $LogPrint info $ScriptName ("Scheduled reboot for update at " . $StartTime . \ - " local time (" . [ /system/clock/get time-zone-name ] . ")."); + " local time (" . [ /system/clock/get time-zone-name ] . ")" . \ + [ $IfThenElse ($Interval > 1d) (" deferred by " . $Interval) ] . "."); :return true; } @@ -153,7 +158,7 @@ :error true; } } else={ - :if ($PackagesUpdateDeferReboot = true) do={ + :if ($PackagesUpdateDeferReboot = true || $PackagesUpdateDeferReboot >= 1d) do={ $Schedule $ScriptName; :set ExitOK true; :error true; From 1f4bf9ee63c57a711652954d6d408b221a6503e5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 2 Jun 2025 16:12:28 +0200 Subject: [PATCH 14/27] check-routeros-update: remove a stale scheduler --- check-routeros-update.rsc | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/check-routeros-update.rsc b/check-routeros-update.rsc index e28a019..8b80dde 100644 --- a/check-routeros-update.rsc +++ b/check-routeros-update.rsc @@ -28,6 +28,7 @@ :global EscapeForRegEx; :global FetchUserAgentStr; :global LogPrint; + :global RebootForUpdate; :global ScriptFromTerminal; :global ScriptLock; :global SendNotification2; @@ -62,9 +63,14 @@ $WaitFullyConnected; :if ([ :len [ /system/scheduler/find where name="_RebootForUpdate" ] ] > 0) do={ - $LogPrint info $ScriptName ("A reboot for update is already scheduled."); - :set ExitOK true; - :error false; + :if ([ :typeof $RebootForUpdate ] = "nothing") do={ + $LogPrint info $ScriptName ("Found a stale scheduler for reboot, removing."); + /system/scheduler/remove "_RebootForUpdate"; + } else={ + $LogPrint info $ScriptName ("A reboot for update is already scheduled."); + :set ExitOK true; + :error false; + } } $LogPrint debug $ScriptName ("Checking for updates..."); From 0de6d006ae1773b38bef60845c6c343bc20f5da6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 2 Jun 2025 21:37:59 +0200 Subject: [PATCH 15/27] update list of contributors --- CONTRIBUTIONS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index 5bf5d08..00861c1 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -35,6 +35,7 @@ Add yourself to the list, [donate with PayPal ↗️](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J)! * Abdul Mannan Abbasi +* Alex Maier * Andrea Ruffini Perico * Andrew Cox * Christoph Boss (@Kampfwurst) From 595b4aea9d43f6eef3aa3dad7a198431a7e3cf9a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 Jun 2025 22:54:40 +0200 Subject: [PATCH 16/27] capsman-download-packages: revert changes for "new functionality" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (Though we keep the quoting for type.) Well, turned out this functionality is for `/file/print` only, but does not work with `/file/find`. 🫣🥴 This reverts commit 15fd522d3db507cc7c22af9cd59ff85d41a5be6f. --- capsman-download-packages.capsman.rsc | 8 ++++---- capsman-download-packages.template.rsc | 8 ++++---- capsman-download-packages.wifi.rsc | 8 ++++---- doc/capsman-download-packages.md | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/capsman-download-packages.capsman.rsc b/capsman-download-packages.capsman.rsc index aaebf5c..2ea1667 100644 --- a/capsman-download-packages.capsman.rsc +++ b/capsman-download-packages.capsman.rsc @@ -4,7 +4,7 @@ # Michael Gisbers # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.18 +# requires RouterOS, version=7.15 # # download and cleanup packages for CAP installation from CAPsMAN # https://rsc.eworm.de/doc/capsman-download-packages.md @@ -54,8 +54,8 @@ "). Please place your packages!"); } - :foreach Package in=[ /file/find recursive where path=$PackagePath \ - type="package" package-version!=$InstalledVersion ] do={ + :foreach Package in=[ /file/find where type="package" \ + package-version!=$InstalledVersion name~("^" . $PackagePath) ] do={ :local File [ /file/get $Package ]; :if ($File->"package-architecture" = "mips") do={ :set ($File->"package-architecture") "mipsbe"; @@ -67,7 +67,7 @@ } } - :if ([ :len [ /file/find recursive where path=$PackagePath type="package" ] ] = 0) do={ + :if ([ :len [ /file/find where type="package" name~("^" . $PackagePath) ] ] = 0) do={ $LogPrint info $ScriptName ("No packages available, downloading default set."); :foreach Arch in={ "arm"; "mipsbe" } do={ :foreach Package in={ "routeros"; "wireless" } do={ diff --git a/capsman-download-packages.template.rsc b/capsman-download-packages.template.rsc index ebbba70..f95212a 100644 --- a/capsman-download-packages.template.rsc +++ b/capsman-download-packages.template.rsc @@ -4,7 +4,7 @@ # Michael Gisbers # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.18 +# requires RouterOS, version=7.15 # # download and cleanup packages for CAP installation from CAPsMAN # https://rsc.eworm.de/doc/capsman-download-packages.md @@ -56,8 +56,8 @@ "). Please place your packages!"); } - :foreach Package in=[ /file/find recursive where path=$PackagePath \ - type="package" package-version!=$InstalledVersion ] do={ + :foreach Package in=[ /file/find where type="package" \ + package-version!=$InstalledVersion name~("^" . $PackagePath) ] do={ :local File [ /file/get $Package ]; :if ($File->"package-architecture" = "mips") do={ :set ($File->"package-architecture") "mipsbe"; @@ -69,7 +69,7 @@ } } - :if ([ :len [ /file/find recursive where path=$PackagePath type="package" ] ] = 0) do={ + :if ([ :len [ /file/find where type="package" name~("^" . $PackagePath) ] ] = 0) do={ $LogPrint info $ScriptName ("No packages available, downloading default set."); # NOT /interface/wifi/ # :foreach Arch in={ "arm"; "mipsbe" } do={ diff --git a/capsman-download-packages.wifi.rsc b/capsman-download-packages.wifi.rsc index 7de0431..03fd9e7 100644 --- a/capsman-download-packages.wifi.rsc +++ b/capsman-download-packages.wifi.rsc @@ -4,7 +4,7 @@ # Michael Gisbers # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.18 +# requires RouterOS, version=7.15 # # download and cleanup packages for CAP installation from CAPsMAN # https://rsc.eworm.de/doc/capsman-download-packages.md @@ -54,8 +54,8 @@ "). Please place your packages!"); } - :foreach Package in=[ /file/find recursive where path=$PackagePath \ - type="package" package-version!=$InstalledVersion ] do={ + :foreach Package in=[ /file/find where type="package" \ + package-version!=$InstalledVersion name~("^" . $PackagePath) ] do={ :local File [ /file/get $Package ]; :if ($File->"package-architecture" = "mips") do={ :set ($File->"package-architecture") "mipsbe"; @@ -67,7 +67,7 @@ } } - :if ([ :len [ /file/find recursive where path=$PackagePath type="package" ] ] = 0) do={ + :if ([ :len [ /file/find where type="package" name~("^" . $PackagePath) ] ] = 0) do={ $LogPrint info $ScriptName ("No packages available, downloading default set."); :foreach Arch in={ "arm"; "arm64" } do={ :local Packages { "arm"={ "routeros"; "wifi-qcom"; "wifi-qcom-ac" }; diff --git a/doc/capsman-download-packages.md b/doc/capsman-download-packages.md index 4daad49..5722227 100644 --- a/doc/capsman-download-packages.md +++ b/doc/capsman-download-packages.md @@ -4,7 +4,7 @@ Download packages for CAP upgrade from CAPsMAN [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.18-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) From e2d3f0f073f1cd923892f4ac9af0d20dfb5902ff Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 Jun 2025 12:26:49 +0200 Subject: [PATCH 17/27] fw-addr-lists: delay on possible scripting subsystem crash This happens in :convert when a list is way too large. Let's use $LogPrintOnce here. If the scripting subsystem really crashes the message will be purged from $LogPrintOnceMessages anyway (as all global variables are lost). --- fw-addr-lists.rsc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index efd37db..0c45f7e 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -48,6 +48,12 @@ } $WaitFullyConnected; + :if ([ :len [ /log/find where topics=({"script"; "warning"}) \ + message=("\$LogPrintOnce: The message is already in log, scripting subsystem may have crashed before!") ] ] > 0) do={ + $LogPrintOnce warning $ScriptName ("Scripting subsystem may have crashed, possibly caused by us. Delaying!"); + :delay 5m; + } + :local ListComment ("managed by " . $ScriptName); :foreach FwListName,FwList in=$FwAddrLists do={ From de2a90d8413b832d3bb01337ef14d1866d23d981 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 Jun 2025 15:51:16 +0200 Subject: [PATCH 18/27] doc/fw-addr-lists: add a warning on possible subsystem crash --- doc/fw-addr-lists.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/fw-addr-lists.md b/doc/fw-addr-lists.md index d09383b..46b80c2 100644 --- a/doc/fw-addr-lists.md +++ b/doc/fw-addr-lists.md @@ -32,7 +32,10 @@ certificate is checked. > ⚠️ **Warning**: The script does not limit the size of a list, but keep in > mind that huge lists can exhaust your device's resources (RAM and CPU), -> and may take a long time to process. +> and may take a long time to process. +> Even crashes for the complete scripting (and CLI) subsystem are possible. +> This should be logged accordingly with warnings when global functions are +> reloaded from scheduler. Requirements and installation ----------------------------- From 95f8af6234ab56c9a831d0f37f338d7b8b3e0cbe Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 20 Jun 2025 23:47:47 +0200 Subject: [PATCH 19/27] packages-update: convert to time before comparing... ... to avoid: packages-update: Script 'packages-update' exited with error: Script Error: cannot compare if truth value is more than or equal to ip address --- packages-update.rsc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages-update.rsc b/packages-update.rsc index 43f6749..d3140f2 100644 --- a/packages-update.rsc +++ b/packages-update.rsc @@ -41,7 +41,8 @@ /system/reboot; } - :local Interval [ $IfThenElse ($PackagesUpdateDeferReboot >= 1d) $PackagesUpdateDeferReboot 1d ]; + :local Interval [ $IfThenElse ([ :totime $PackagesUpdateDeferReboot ] >= 1d) \ + $PackagesUpdateDeferReboot 1d ]; :local StartTime [ :tostr [ :totime (10800 + [ $GetRandomNumber 7200 ]) ] ]; /system/scheduler/add name="_RebootForUpdate" start-time=$StartTime interval=$Interval \ on-event=("/system/scheduler/remove \"_RebootForUpdate\"; " . \ @@ -158,7 +159,7 @@ :error true; } } else={ - :if ($PackagesUpdateDeferReboot = true || $PackagesUpdateDeferReboot >= 1d) do={ + :if ($PackagesUpdateDeferReboot = true || [ :totime $PackagesUpdateDeferReboot ] >= 1d) do={ $Schedule $ScriptName; :set ExitOK true; :error true; From 64158498504635d98adac896f480d71d9bf8a2a9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sat, 21 Jun 2025 23:09:24 +0200 Subject: [PATCH 20/27] global-functions: $WaitForFile: (mostly) revert changes This (mostly) reverts commits 0e00a228d67d77fadc80eee2df04c2cec25b8db8 and e08bb2192dfd22b25652553f28304818a3602331. This is required for RouterOS 7.20beta4. That fixed recursive find for files, and (again, or still?) suffers timing (and thus racing) issues getting file properties. This breaks RouterOS 7.20beta2 again, so that specific version is not supported. Just update... --- global-functions.rsc | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 50426b6..fd89f0f 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1771,14 +1771,26 @@ :global MAX; :set FileName [ $CleanFilePath $FileName ]; - :local Delay ([ $MAX [ $EitherOr $WaitTime 2s ] 100ms ] / 10); + :local Delay ([ $MAX [ $EitherOr $WaitTime 2s ] 100ms ] / 9); :do { - :retry { + :retry { + :if ([ :len [ /file/find where name=$FileName ] ] = 0) do={ + :error false; + } + } delay=$Delay max=10; + } on-error={ + :return false; + } + + :while ([ :len [ /file/find where name=$FileName ] ] > 0) do={ + :do { /file/get $FileName; :return true; - } delay=$Delay max=10; - } on-error={ } + } on-error={ } + :delay $Delay; + :set Delay ($Delay * 3 / 2); + } :return false; } From 1307b8587e57deaf95146820b7f32bb9a713892d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 22 Jun 2025 00:15:17 +0200 Subject: [PATCH 21/27] global-functions: $FileGet: mitigate race with file properties RouterOS is suffering a race condition, where a file exists, but its properties are not (yet) available. This is handled in $WaitForFile. This passes an interval of zero to $WaitForFile, as does not wait for the file to exist, but wants to avoid the race only. --- global-functions.rsc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index fd89f0f..829cbf2 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -559,6 +559,12 @@ :set FileGet do={ :local FileName [ :tostr $1 ]; + :global WaitForFile; + + :if ([ $WaitForFile $FileName 0s ] = false) do={ + :return false; + } + :local FileVal false; :do { :set FileVal [ /file/get $FileName ]; From d46574b4fe5ea3f72ce804bd5fb38a5408f9cd94 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 25 Jun 2025 10:30:26 +0200 Subject: [PATCH 22/27] netwatch-dns: retry doh server... ... for more resilience on bad connectivity or saturated link. --- netwatch-dns.rsc | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/netwatch-dns.rsc b/netwatch-dns.rsc index 4fa076a..2df26b0 100644 --- a/netwatch-dns.rsc +++ b/netwatch-dns.rsc @@ -119,11 +119,13 @@ :local Data false; :onerror Err { - :set Data ([ /tool/fetch check-certificate=yes-without-crl output=user \ - http-header-field=({ "accept: application/dns-message" }) \ - url=(($DohServer->"doh-url") . "?dns=" . [ :convert to=base64 ([ :rndstr length=2 ] . \ - "\01\00" . "\00\01" . "\00\00" . "\00\00" . "\00\00" . "\09doh-check\05eworm\02de\00" . \ - "\00\10" . "\00\01") ]) as-value ]->"data"); + :retry { + :set Data ([ /tool/fetch check-certificate=yes-without-crl output=user \ + http-header-field=({ "accept: application/dns-message" }) \ + url=(($DohServer->"doh-url") . "?dns=" . [ :convert to=base64 ([ :rndstr length=2 ] . \ + "\01\00" . "\00\01" . "\00\00" . "\00\00" . "\00\00" . "\09doh-check\05eworm\02de\00" . \ + "\00\10" . "\00\01") ]) as-value ]->"data"); + } delay=1s max=3; } do={ $LogPrint warning $ScriptName ("Request to DoH server " . ($DohServer->"doh-url") . \ " failed: " . $Err); From b068f86995c63278c91f9e92831f075fab5af2f1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 25 Jun 2025 10:47:12 +0200 Subject: [PATCH 23/27] netwatch-dns: fix indention --- netwatch-dns.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netwatch-dns.rsc b/netwatch-dns.rsc index 2df26b0..9e2f9bc 100644 --- a/netwatch-dns.rsc +++ b/netwatch-dns.rsc @@ -125,7 +125,7 @@ url=(($DohServer->"doh-url") . "?dns=" . [ :convert to=base64 ([ :rndstr length=2 ] . \ "\01\00" . "\00\01" . "\00\00" . "\00\00" . "\00\00" . "\09doh-check\05eworm\02de\00" . \ "\00\10" . "\00\01") ]) as-value ]->"data"); - } delay=1s max=3; + } delay=1s max=3; } do={ $LogPrint warning $ScriptName ("Request to DoH server " . ($DohServer->"doh-url") . \ " failed: " . $Err); From 89175e511fc965721fc19d88819c0fef13e383dc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 7 Jul 2025 18:38:21 +0200 Subject: [PATCH 24/27] accesslist-duplicates: print without paging --- accesslist-duplicates.capsman.rsc | 2 +- accesslist-duplicates.local.rsc | 2 +- accesslist-duplicates.template.rsc | 6 +++--- accesslist-duplicates.wifi.rsc | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/accesslist-duplicates.capsman.rsc b/accesslist-duplicates.capsman.rsc index 5e6cf0a..1da0366 100644 --- a/accesslist-duplicates.capsman.rsc +++ b/accesslist-duplicates.capsman.rsc @@ -22,7 +22,7 @@ :foreach AccList in=[ /caps-man/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ :local Mac [ /caps-man/access-list/get $AccList mac-address ]; :if ($Seen->$Mac = 1) do={ - /caps-man/access-list/print where mac-address=$Mac; + /caps-man/access-list/print without-paging where mac-address=$Mac; :local Remove [ :tonum [ /terminal/ask prompt="\nNumeric id to remove, any key to skip!" ] ]; :if ([ :typeof $Remove ] = "num") do={ diff --git a/accesslist-duplicates.local.rsc b/accesslist-duplicates.local.rsc index a6b4f41..03a9724 100644 --- a/accesslist-duplicates.local.rsc +++ b/accesslist-duplicates.local.rsc @@ -22,7 +22,7 @@ :foreach AccList in=[ /interface/wireless/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ :local Mac [ /interface/wireless/access-list/get $AccList mac-address ]; :if ($Seen->$Mac = 1) do={ - /interface/wireless/access-list/print where mac-address=$Mac; + /interface/wireless/access-list/print without-paging where mac-address=$Mac; :local Remove [ :tonum [ /terminal/ask prompt="\nNumeric id to remove, any key to skip!" ] ]; :if ([ :typeof $Remove ] = "num") do={ diff --git a/accesslist-duplicates.template.rsc b/accesslist-duplicates.template.rsc index e51198d..bf23147 100644 --- a/accesslist-duplicates.template.rsc +++ b/accesslist-duplicates.template.rsc @@ -27,9 +27,9 @@ :local Mac [ /interface/wifi/access-list/get $AccList mac-address ]; :local Mac [ /interface/wireless/access-list/get $AccList mac-address ]; :if ($Seen->$Mac = 1) do={ - /caps-man/access-list/print where mac-address=$Mac; - /interface/wifi/access-list/print where mac-address=$Mac; - /interface/wireless/access-list/print where mac-address=$Mac; + /caps-man/access-list/print without-paging where mac-address=$Mac; + /interface/wifi/access-list/print without-paging where mac-address=$Mac; + /interface/wireless/access-list/print without-paging where mac-address=$Mac; :local Remove [ :tonum [ /terminal/ask prompt="\nNumeric id to remove, any key to skip!" ] ]; :if ([ :typeof $Remove ] = "num") do={ diff --git a/accesslist-duplicates.wifi.rsc b/accesslist-duplicates.wifi.rsc index cadacb6..528a73c 100644 --- a/accesslist-duplicates.wifi.rsc +++ b/accesslist-duplicates.wifi.rsc @@ -22,7 +22,7 @@ :foreach AccList in=[ /interface/wifi/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ :local Mac [ /interface/wifi/access-list/get $AccList mac-address ]; :if ($Seen->$Mac = 1) do={ - /interface/wifi/access-list/print where mac-address=$Mac; + /interface/wifi/access-list/print without-paging where mac-address=$Mac; :local Remove [ :tonum [ /terminal/ask prompt="\nNumeric id to remove, any key to skip!" ] ]; :if ([ :typeof $Remove ] = "num") do={ From 4c2c7e817a03202d8202bc4902f12990b0b06028 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 21 Jul 2025 10:47:19 +0200 Subject: [PATCH 25/27] netwatch-notify: give the number of failures... ... to indicated this happened several times. --- netwatch-notify.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc index 00f03cd..12f2721 100644 --- a/netwatch-notify.rsc +++ b/netwatch-notify.rsc @@ -127,7 +127,7 @@ $LogPrint [ $IfThenElse ($HostInfo->"no-resolve-fail" != true) warning debug ] \ $ScriptName ("Resolving name '" . $HostInfo->"resolve" . [ $IfThenElse \ ($HostInfo->"resolve" != $HostInfo->"name") ("' for " . $Type . " '" . \ - $HostInfo->"name") "" ] . "' failed: " . $Err); + $HostInfo->"name") "" ] . "' failed third time: " . $Err); } } } From 721e786f68cccfa789874545889169212b37bf11 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 21 Jul 2025 10:52:22 +0200 Subject: [PATCH 26/27] netwatch-notify: increase the address-list timeout even further --- netwatch-notify.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc index 12f2721..1fcc203 100644 --- a/netwatch-notify.rsc +++ b/netwatch-notify.rsc @@ -62,14 +62,14 @@ :local FwAddrList ($ScriptName . "-" . [ $GetRandom20CharAlNum ]); :if ([ :typeof [ :toip $Expected ] ] = "ip") do={ - /ip/firewall/address-list/add address=$Name list=$FwAddrList dynamic=yes timeout=10s; + /ip/firewall/address-list/add address=$Name list=$FwAddrList dynamic=yes timeout=30s; :delay 20ms; :if ([ :len [ /ip/firewall/address-list/find where list=$FwAddrList address=$Expected ] ] > 0) do={ :return true; } } :if ([ :typeof [ :toip6 $Expected ] ] = "ip6") do={ - /ipv6/firewall/address-list/add address=$Name list=$FwAddrList dynamic=yes timeout=10s; + /ipv6/firewall/address-list/add address=$Name list=$FwAddrList dynamic=yes timeout=30s; :delay 20ms; :if ([ :len [ /ipv6/firewall/address-list/find where list=$FwAddrList address=$Expected ] ] > 0) do={ :return true; From a856d309df956db8bd93647a1998c95afe38da02 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 28 Jul 2025 16:47:27 +0200 Subject: [PATCH 27/27] global-functions: $SymbolByUnicodeName: allow to add more symbols... ... for example from a module. Add a script `mod/symbols-extra` with something like: :global SymbolsExtra; :set ($SymbolsExtra->"rocket") "\F0\9F\9A\80"; --- global-functions.rsc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 829cbf2..40c3817 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1608,7 +1608,9 @@ :global LogPrintOnce; - :local Symbols { + :global SymbolsExtra; + + :local Symbols ({ "abacus"="\F0\9F\A7\AE"; "alarm-clock"="\E2\8F\B0"; "arrow-down"="\E2\AC\87"; @@ -1643,7 +1645,7 @@ "star"="\E2\AD\90"; "warning-sign"="\E2\9A\A0"; "white-heavy-check-mark"="\E2\9C\85" - } + }, $SymbolsExtra); :if ([ :len ($Symbols->$Name) ] = 0) do={ $LogPrintOnce warning $0 ("No symbol available for name '" . $Name . "'!");