diff --git a/MerlinAU.asp b/MerlinAU.asp new file mode 100644 index 00000000..80c5e75d --- /dev/null +++ b/MerlinAU.asp @@ -0,0 +1,2715 @@ + + + + + + + + + + + + +MerlinAU add-on for ASUSWRT-Merlin Firmware + + + + + + + + + + + + + + + +
+ + + +
+ + + + + + + +" /> +" /> + +" /> + +" /> +" /> +" /> +" /> +" /> +" /> + + + + + + + + +
  + + + + + + + +
+ + + +
+
 
+
MerlinAU
+
+
This is the MerlinAU add-on integrated into the router WebUI +[ + Wiki ] + +
+
 
+ + + + + + + + +
+ + + + + + + + + + + +
Firmware Status (click to expand/collapse)
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
F/W Product/Model ID:
F/W Variant Detected:Unknown
F/W Version Installed: + <% nvram_get("firmver"); %>.<% nvram_get("buildno"); %>.<% nvram_get("extendno"); %> +
F/W Update Available:NONE FOUND
Estimated Update Time:TBD
Last Notification Date:TBD
F/W Update Check:Disabled
+ + + + + + + + + + + +
Settings Status (click to expand/collapse)
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Changelog Approval:Disabled
Changelog Check:Disabled
Beta-to-Release Updates:Disabled
Tailscale VPN Access:Disabled
Automatic Backups:Disabled
Auto-Updates for MerlinAU:Disabled
Email Notifications:Disabled
+ +
 
+ + + + + + + + + +
Actions (click to expand/collapse)
+
+ ++ + + + + + + + + +
+ +
+ +
+
+ +
+ +
+ +
+
+
+ + ++ + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ + +
+ + + +
+ +
+ + +
+ Days: + + + + +
+ + + + + + + +
+
+
+ Hour: + +
+
+ Minutes: + +
+
+
+ +
+ +
+ +
 
+ + + + + + + + +
Advanced Options (click to expand/collapse)
+
+ ++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + +
+ +
+ +
+ +
+ + + + +
+ + + + +
+ + + + +
+ +
+ +
+
+ +
+
+
MerlinAU
+
+ + + diff --git a/MerlinAU.sh b/MerlinAU.sh index f8421d20..c1f5658a 100644 --- a/MerlinAU.sh +++ b/MerlinAU.sh @@ -4,12 +4,12 @@ # # Original Creation Date: 2023-Oct-01 by @ExtremeFiretop. # Official Co-Author: @Martinski W. - Date: 2023-Nov-01 -# Last Modified: 2025-Feb-17 +# Last Modified: 2025-Feb-25 ################################################################### set -u ## Set version for each Production Release ## -readonly SCRIPT_VERSION=1.3.10 +readonly SCRIPT_VERSION=1.4.0 readonly SCRIPT_NAME="MerlinAU" ## Set to "master" for Production Releases ## SCRIPT_BRANCH="dev" @@ -57,7 +57,7 @@ routerModelCheckFailed=false offlineUpdateTrigger=false ##----------------------------------------## -## Modified by Martinski W. [2025-Feb-15] ## +## Modified by Martinski W. [2025-Feb-18] ## ##----------------------------------------## readonly NOct="\e[0m" readonly BOLDct="\e[1m" @@ -66,26 +66,44 @@ readonly REDct="\e[1;31m" readonly GRNct="\e[1;32m" readonly YLWct="\e[1;33m" readonly BLUEct="\e[1;34m" -readonly MAGENTAct="\e[1;35m" +readonly MGNTct="\e[1;35m" #Magenta# readonly CYANct="\e[1;36m" readonly WHITEct="\e[1;37m" readonly CRITct="\e[1;41m" -readonly InvREDct="\e[1;41m" -readonly InvGRNct="\e[1;42m" +readonly InvREDct="\e[41m" +readonly InvGRNct="\e[42m" +readonly InvMGNct="\e[45m" +readonly InvBREDct="\e[30;101m" +readonly InvBGRNct="\e[30;102m" readonly InvBYLWct="\e[30;103m" +readonly InvBMGNct="\e[30;105m" readonly ScriptFileName="${0##*/}" readonly ScriptFNameTag="${ScriptFileName%%.*}" readonly ScriptDirNameD="${ScriptFNameTag}.d" ##----------------------------------------## -## Modified by Martinski W. [2024-Dec-01] ## +## Modified by Martinski W. [2025-Jan-15] ## ##----------------------------------------## readonly ADDONS_PATH="/jffs/addons" readonly SCRIPTS_PATH="/jffs/scripts" readonly SETTINGS_DIR="${ADDONS_PATH}/$ScriptDirNameD" -readonly SETTINGSFILE="${SETTINGS_DIR}/custom_settings.txt" -readonly SCRIPTVERPATH="${SETTINGS_DIR}/version.txt" +readonly CONFIG_FILE="${SETTINGS_DIR}/custom_settings.txt" +readonly SCRIPT_VERPATH="${SETTINGS_DIR}/version.txt" +readonly HELPER_JSFILE="${SETTINGS_DIR}/CheckHelper.js" +readonly SHARED_SETTINGS_FILE="${ADDONS_PATH}/custom_settings.txt" +readonly SHARED_WEB_DIR="$(readlink -f /www/user)" +readonly SCRIPT_WEB_DIR="${SHARED_WEB_DIR}/$SCRIPT_NAME" +readonly SCRIPT_WEB_ASP_FILE="${SCRIPT_NAME}.asp" +readonly SCRIPT_WEB_ASP_PATH="$SETTINGS_DIR/$SCRIPT_WEB_ASP_FILE" +readonly TEMP_MENU_TREE="/tmp/menuTree.js" +readonly ORIG_MENU_TREE="/www/require/modules/menuTree.js" +readonly WEBUI_LOCKFD=386 +readonly WEBUI_LOCKFILE="/tmp/addonwebui.lock" +readonly TEMPFILE="/tmp/MerlinAU_settings_$$.txt" +readonly webPageFileRegExp="user([1-9]|[1-2][0-9])[.]asp" +readonly webPageLineTabExp="\{url: \"$webPageFileRegExp\", tabName: " +readonly webPageLineRegExp="${webPageLineTabExp}\"$SCRIPT_NAME\"\}," # Give FIRST priority to built-in binaries over any other # export PATH="/bin:/usr/bin:/sbin:/usr/sbin:$PATH" @@ -120,14 +138,14 @@ then fi ##------------------------------------------## -## Modified by ExtremeFiretop [2024-Apr-02] ## +## Modified by ExtremeFiretop [2024-Dec-21] ## ##------------------------------------------## #-------------------------------------------------------# # We'll use the built-in AMTM email configuration file # to send email notifications *IF* enabled by the user. #-------------------------------------------------------# readonly FW_UpdateEMailFormatTypeDefault=HTML -readonly FW_UpdateEMailNotificationDefault=false +readonly FW_UpdateEMailNotificationDefault=DISABLED readonly amtmMailDirPath="/jffs/addons/amtm/mail" readonly amtmMailConfFile="${amtmMailDirPath}/email.conf" readonly amtmMailPswdFile="${amtmMailDirPath}/emailpw.enc" @@ -143,13 +161,15 @@ else cronListCmd="crontab -l" fi ##----------------------------------------## -## Modified by Martinski W. [2024-Nov-27] ## +## Modified by Martinski W. [2025-Jan-22] ## ##----------------------------------------## inMenuMode=true isInteractive=false FlashStarted=false MerlinChangeLogURL="" GnutonChangeLogURL="" +keepConfigFile=false +bypassPostponedDays=false # Main LAN Network Info # readonly myLAN_HostName="$(nvram get lan_hostname)" @@ -199,6 +219,7 @@ readonly SEPstr="----------------------------------------------------------" ## Added by Martinski W. [2024-Nov-24] ## ##-------------------------------------## # menu setup variables # +readonly padStr=" " readonly theExitStr="${GRNct}e${NOct}=Exit to Main Menu" readonly theMUExitStr="${GRNct}e${NOct}=Exit" readonly theADExitStr="${GRNct}e${NOct}=Exit to Advanced Options Menu" @@ -294,20 +315,31 @@ _WaitForEnterKey_() read -rs EnterKEY ; echo } -##----------------------------------## -## Added Martinski W. [2023-Nov-28] ## -##----------------------------------## +##-------------------------------------## +## Modified Martinski W. [2025-Feb-18] ## +##-------------------------------------## _WaitForYESorNO_() { - ! "$isInteractive" && return 0 - local promptStr + local defltCode=0 defltAnswer=NO promptStr - if [ $# -eq 0 ] || [ -z "$1" ] + if [ $# -eq 0 ] + then defltCode=0 ; defltAnswer=NO + elif [ "$1" = "NO" ] + then defltCode=1 ; defltAnswer=NO + elif [ "$1" = "YES" ] + then defltCode=0 ; defltAnswer=YES + fi + + ! "$isInteractive" && return "$defltCode" + + if [ $# -eq 0 ] || [ -z "$1" ] || \ + echo "$1" | grep -qE "^(YES|NO)$" then promptStr=" [yY|nN]? " else promptStr="$1 [yY|nN]? " fi printf "$promptStr" ; read -r YESorNO + [ -z "$YESorNO" ] && YESorNO="$defltAnswer" if echo "$YESorNO" | grep -qE "^([Yy](es)?|YES)$" then echo "OK" ; return 0 else echo "NO" ; return 1 @@ -315,76 +347,125 @@ _WaitForYESorNO_() } ##----------------------------------------## -## Modified by Martinski W. [2024-Nov-24] ## +## Modified by Martinski W. [2025-Jan-11] ## ##----------------------------------------## readonly LockFilePath="/tmp/var/${ScriptFNameTag}.LOCK" -LockFileMaxAgeSecs=600 #10-minutes# -LockWaitTimeoutSecs=120 +readonly LockTypeRegEx="(cliMenuLock|cliOptsLock|cliFileLock)" -_ReleaseLock_() { rm -f "$LockFilePath" ; } +_FindLockFileTypes_() +{ grep -woE "$LockTypeRegEx" "$LockFilePath" | tr '\n' ' ' | sed 's/[ ]*$//' ; } -if [ $# -eq 0 ] || [ -z "$1" ] || \ - [ "$1" = "resetLockFile" ] -then #Interactive Mode# - LockFileMaxAgeSecs=1200 - LockWaitTimeoutSecs=2 -elif [ "$1" = "addCronJob" ] -then #Special Case# - LockFileMaxAgeSecs=1200 - LockWaitTimeoutSecs=600 +_ReleaseLock_() +{ + local lockType + if [ $# -eq 0 ] || [ -z "$1" ] + then lockType="" + else lockType="$1" + fi + if [ -s "$LockFilePath" ] && \ + [ "$(wc -l < "$LockFilePath")" -gt 1 ] + then + if [ -z "$lockType" ] + then sed -i "/^$$|/d" "$LockFilePath" + else sed -i "/.*|${1}$/d" "$LockFilePath" + fi + [ -s "$LockFilePath" ] && return 0 + fi + rm -f "$LockFilePath" +} + +## Defaults ## +LockMaxTimeoutSecs=120 +LockFileMaxAgeSecs=600 #10-minutes# + +if [ $# -eq 0 ] || [ -z "$1" ] +then + #Interactive Mode# + LockMaxTimeoutSecs=3 + LockFileMaxAgeSecs=1200 +else + case "$1" in + run_now|resetLockFile) + LockMaxTimeoutSecs=3 + LockFileMaxAgeSecs=1200 + ;; + startup|addCronJob) + LockMaxTimeoutSecs=600 + LockFileMaxAgeSecs=900 + ;; + esac fi ##----------------------------------------## -## Modified by Martinski W. [2024-Nov-17] ## +## Modified by Martinski W. [2025-Jan-15] ## ##----------------------------------------## _AcquireLock_() { + local retCode waitTimeoutSecs + local lockFileSecs ageOfLockSecs oldPID + local lockTypeReq lockTypeFound + + if [ $# -gt 0 ] && [ -n "$1" ] + then lockTypeReq="$1" + else lockTypeReq="cliAnyLock" + fi + + _CreateLockFile_() + { echo "$$|$lockTypeReq" > "$LockFilePath" ; } + if [ ! -f "$LockFilePath" ] - then - echo "$$" > "$LockFilePath" - return 0 + then _CreateLockFile_ ; return 0 fi - local lockFileSecs ageOfLockSecs oldPID retCode waitTimeoutSecs retCode=1 + lockTypeFound="" waitTimeoutSecs=0 while true do - if [ -f "$LockFilePath" ] + if [ -s "$LockFilePath" ] then - oldPID="$(cat "$LockFilePath")" + oldPID="$(head -n1 "$LockFilePath" | awk -F '|' '{print $1}')" + if [ -n "$oldPID" ] && ! pidof "$ScriptFileName" | grep -qow "$oldPID" + then sed -i "/^${oldPID}|/d" "$LockFilePath" + fi lockFileSecs="$(date +%s -r "$LockFilePath")" + lockTypeFound="$(_FindLockFileTypes_)" + if [ "$lockTypeReq" != "cliAnyLock" ] && \ + ! echo "$lockTypeFound" | grep -qw "$lockTypeReq" + then # Specific "Lock Type" NOT found # + echo "$$|$lockTypeReq" >> "$LockFilePath" + retCode=0 ; break + fi + [ -z "$lockTypeFound" ] && lockTypeFound="noTypeLock" else - echo "$$" > "$LockFilePath" - retCode=0 - break + _CreateLockFile_ + retCode=0 ; break fi ageOfLockSecs="$(($(date +%s) - lockFileSecs))" if [ "$ageOfLockSecs" -gt "$LockFileMaxAgeSecs" ] then - Say "Stale Lock Found (older than $LockFileMaxAgeSecs secs.) Resetting lock file..." - if [ -n "$oldPID" ] && kill -EXIT "$oldPID" 2>/dev/null && \ - pidof "$ScriptFileName" | grep -qow "$oldPID" + Say "Stale Lock Found (older than $LockFileMaxAgeSecs secs). Resetting lock file..." + if [ -n "$oldPID" ] && \ + pidof "$ScriptFileName" | grep -qow "$oldPID" && \ + kill -EXIT "$oldPID" 2>/dev/null then kill -TERM "$oldPID" ; wait "$oldPID" fi - echo "$$" > "$LockFilePath" - retCode=0 - break - elif [ "$waitTimeoutSecs" -le "$LockWaitTimeoutSecs" ] + _CreateLockFile_ + retCode=0 ; break + elif [ "$waitTimeoutSecs" -le "$LockMaxTimeoutSecs" ] then if [ "$((waitTimeoutSecs % 10))" -eq 0 ] then - Say "Lock Found [Age: $ageOfLockSecs secs.] Waiting for script [PID=$oldPID] to exit [Timer: $waitTimeoutSecs secs.]" + Say "Lock Found [$lockTypeFound: $ageOfLockSecs secs]. Waiting for script [PID=$oldPID] to exit [Timer: $waitTimeoutSecs secs]" fi - sleep 2 - waitTimeoutSecs="$((waitTimeoutSecs + 2))" + sleep 5 + waitTimeoutSecs="$((waitTimeoutSecs + 5))" else - Say "${REDct}**ERROR**${NOct}: The shell script ${ScriptFileName} [PID=$oldPID] is already running [Lock Age: $ageOfLockSecs secs.]" - retCode=1 - break + Say "${REDct}**ERROR**${NOct}: The shell script ${ScriptFileName} [PID=$oldPID] is already running [$lockTypeFound: $ageOfLockSecs secs]" + retCode=1 ; break fi done return "$retCode" @@ -403,7 +484,8 @@ _DoExit_() ##------------------------------------------## ## Modified by ExtremeFiretop [2024-May-21] ## ##------------------------------------------## -logo() { +_ShowLogo_() +{ echo -e "${YLWct}" echo -e " __ __ _ _ _ _ " echo -e " | \/ | | (_) /\ | | | |" @@ -414,52 +496,64 @@ logo() { echo -e "${NOct}" } -##---------------------------------------## -## Added by ExtremeFiretop [2024-Jul-03] ## -##---------------------------------------## +##----------------------------------------## +## Modified by Martinski W. [2025-Feb-22] ## +##----------------------------------------## _ShowAbout_() { clear - logo + _ShowLogo_ cat </dev/null then - kill -TERM $Toggle_LEDs_PID - wait $Toggle_LEDs_PID + kill -TERM "$Toggle_LEDs_PID" + wait "$Toggle_LEDs_PID" # Set LEDs to their "initial state" # nvram set ${nvramLEDsVar}="$LEDsInitState" /sbin/service restart_leds >/dev/null 2>&1 @@ -770,24 +864,44 @@ readonly FW_SFURL_RELEASE="${FW_SFURL_BASE}/${PRODUCT_ID}/${FW_SFURL_RELEASE_SUF readonly isGNUtonFW="$(_GetFirmwareVariantFromRouter_)" ##----------------------------------------## -## Modified by Martinski W. [2024-Jul-03] ## +## Modified by Martinski W. [2025-Jan-05] ## +##----------------------------------------## +readonly FW_RouterProductID="${GRNct}${PRODUCT_ID}${NOct}" +# Some Model IDs have a lower case suffix of the same Product ID # +if [ "$PRODUCT_ID" = "$(echo "$MODEL_ID" | tr 'a-z' 'A-Z')" ] +then + readonly FW_RouterModelID="$PRODUCT_ID" + readonly FW_RouterModelIDstr="$FW_RouterProductID" +else + readonly FW_RouterModelID="${PRODUCT_ID}/$MODEL_ID" + readonly FW_RouterModelIDstr="${FW_RouterProductID}/${GRNct}${MODEL_ID}${NOct}" +fi + +##----------------------------------------## +## Modified by Martinski W. [2025-Jan-05] ## ##----------------------------------------## _ChangeToDev_() { + if ! _AcquireLock_ cliFileLock + then return 1 + fi SCRIPT_BRANCH="dev" SCRIPT_URL_REPO="${SCRIPT_URL_BASE}/$SCRIPT_BRANCH" - _SCRIPTUPDATE_ force + _SCRIPT_UPDATE_ force _DoExit_ 0 } ##----------------------------------------## -## Modified by Martinski W. [2024-Jul-03] ## +## Modified by Martinski W. [2025-Jan-05] ## ##----------------------------------------## _ChangeToStable_() { + if ! _AcquireLock_ cliFileLock + then return 1 + fi SCRIPT_BRANCH="master" SCRIPT_URL_REPO="${SCRIPT_URL_BASE}/$SCRIPT_BRANCH" - _SCRIPTUPDATE_ force + _SCRIPT_UPDATE_ force _DoExit_ 0 } @@ -855,20 +969,53 @@ else readonly FW_Update_LOG_BASE_DefaultDIR="$ADDONS_PATH" fi +##-------------------------------------## +## Added by Martinski W. [2025-Jan-15] ## +##-------------------------------------## +_SetUp_FW_UpdateZIP_DirectoryPaths_() +{ + local theDirPath="" + if [ $# -eq 1 ] && [ -n "$1" ] && [ -d "$1" ] + then + theDirPath="$1" + else + theDirPath="$(Get_Custom_Setting FW_New_Update_ZIP_Directory_Path)" + fi + FW_ZIP_BASE_DIR="$theDirPath" + FW_ZIP_DIR="${FW_ZIP_BASE_DIR}/$FW_ZIP_SUBDIR" + FW_ZIP_FPATH="${FW_ZIP_DIR}/${FW_FileName}.zip" +} + +##-------------------------------------## +## Added by Martinski W. [2025-Jan-15] ## +##-------------------------------------## +_SetUp_FW_UpdateLOG_DirectoryPaths_() +{ + local theDirPath="" + if [ $# -eq 1 ] && [ -n "$1" ] && [ -d "$1" ] + then + theDirPath="$1" + else + theDirPath="$(Get_Custom_Setting FW_New_Update_LOG_Directory_Path)" + fi + FW_LOG_BASE_DIR="$theDirPath" + FW_LOG_DIR="${FW_LOG_BASE_DIR}/$FW_LOG_SUBDIR" +} + ##----------------------------------------## -## Modified by Martinski W. [2024-Nov-27] ## +## Modified by Martinski W. [2025-Jan-05] ## ##----------------------------------------## -_Init_Custom_Settings_Config_() +_InitCustomSettingsConfig_() { [ ! -d "$SETTINGS_DIR" ] && mkdir -m 755 -p "$SETTINGS_DIR" - if [ ! -f "$SETTINGSFILE" ] + if [ ! -f "$CONFIG_FILE" ] then { echo "FW_New_Update_Notification_Date TBD" echo "FW_New_Update_Notification_Vers TBD" echo "FW_New_Update_Postponement_Days=$FW_UpdateDefaultPostponementDays" - echo "FW_New_Update_EMail_Notification=$FW_UpdateEMailNotificationDefault" + echo "FW_New_Update_EMail_Notification $FW_UpdateEMailNotificationDefault" echo "FW_New_Update_EMail_FormatType=\"${FW_UpdateEMailFormatTypeDefault}\"" echo "FW_New_Update_Cron_Job_Schedule=\"${FW_Update_CRON_DefaultSchedule}\"" echo "FW_New_Update_ZIP_Directory_Path=\"${FW_Update_ZIP_DefaultSetupDIR}\"" @@ -877,107 +1024,104 @@ _Init_Custom_Settings_Config_() echo "FW_New_Update_EMail_CC_Name=TBD" echo "FW_New_Update_EMail_CC_Address=TBD" echo "CheckChangeLog ENABLED" + echo "FW_Update_Check TBD" echo "Allow_Updates_OverVPN DISABLED" - echo "FW_New_Update_Changelog_Approval=TBD" echo "FW_Allow_Beta_Production_Up ENABLED" - echo "FW_Auto_Backupmon ENABLED" echo "Allow_Script_Auto_Update DISABLED" echo "Script_Update_Cron_Job_SchedDays=\"${SW_Update_CRON_DefaultSchedDays}\"" - } > "$SETTINGSFILE" - chmod 0664 "$SETTINGSFILE" + } > "$CONFIG_FILE" + chmod 664 "$CONFIG_FILE" return 1 fi local retCode=0 preferredPath - if ! grep -q "^FW_New_Update_Notification_Date " "$SETTINGSFILE" + # TEMPORARY Migration Function # + _Migrate_Settings_ + + if ! grep -q "^FW_New_Update_Notification_Date " "$CONFIG_FILE" then - sed -i "1 i FW_New_Update_Notification_Date TBD" "$SETTINGSFILE" + sed -i "1 i FW_New_Update_Notification_Date TBD" "$CONFIG_FILE" retCode=1 fi - if ! grep -q "^FW_New_Update_Notification_Vers " "$SETTINGSFILE" + if ! grep -q "^FW_New_Update_Notification_Vers " "$CONFIG_FILE" then - sed -i "2 i FW_New_Update_Notification_Vers TBD" "$SETTINGSFILE" + sed -i "2 i FW_New_Update_Notification_Vers TBD" "$CONFIG_FILE" retCode=1 fi - if ! grep -q "^FW_New_Update_Postponement_Days=" "$SETTINGSFILE" + if ! grep -q "^FW_New_Update_Postponement_Days=" "$CONFIG_FILE" then - sed -i "3 i FW_New_Update_Postponement_Days=$FW_UpdateDefaultPostponementDays" "$SETTINGSFILE" + sed -i "3 i FW_New_Update_Postponement_Days=$FW_UpdateDefaultPostponementDays" "$CONFIG_FILE" retCode=1 fi - if ! grep -q "^FW_New_Update_EMail_Notification=" "$SETTINGSFILE" + if ! grep -q "^FW_New_Update_EMail_Notification " "$CONFIG_FILE" then - sed -i "4 i FW_New_Update_EMail_Notification=$FW_UpdateEMailNotificationDefault" "$SETTINGSFILE" + sed -i "4 i FW_New_Update_EMail_Notification $FW_UpdateEMailNotificationDefault" "$CONFIG_FILE" retCode=1 fi - if ! grep -q "^FW_New_Update_EMail_FormatType=" "$SETTINGSFILE" + if ! grep -q "^FW_New_Update_EMail_FormatType=" "$CONFIG_FILE" then - sed -i "5 i FW_New_Update_EMail_FormatType=\"${FW_UpdateEMailFormatTypeDefault}\"" "$SETTINGSFILE" + sed -i "5 i FW_New_Update_EMail_FormatType=\"${FW_UpdateEMailFormatTypeDefault}\"" "$CONFIG_FILE" retCode=1 fi - if ! grep -q "^FW_New_Update_Cron_Job_Schedule=" "$SETTINGSFILE" + if ! grep -q "^FW_New_Update_Cron_Job_Schedule=" "$CONFIG_FILE" then - sed -i "6 i FW_New_Update_Cron_Job_Schedule=\"${FW_Update_CRON_DefaultSchedule}\"" "$SETTINGSFILE" + sed -i "6 i FW_New_Update_Cron_Job_Schedule=\"${FW_Update_CRON_DefaultSchedule}\"" "$CONFIG_FILE" retCode=1 fi - if ! grep -q "^FW_New_Update_ZIP_Directory_Path=" "$SETTINGSFILE" + if ! grep -q "^FW_New_Update_ZIP_Directory_Path=" "$CONFIG_FILE" then - sed -i "7 i FW_New_Update_ZIP_Directory_Path=\"${FW_Update_ZIP_DefaultSetupDIR}\"" "$SETTINGSFILE" + sed -i "7 i FW_New_Update_ZIP_Directory_Path=\"${FW_Update_ZIP_DefaultSetupDIR}\"" "$CONFIG_FILE" retCode=1 fi - if ! grep -q "^FW_New_Update_LOG_Directory_Path=" "$SETTINGSFILE" + if ! grep -q "^FW_New_Update_LOG_Directory_Path=" "$CONFIG_FILE" then - sed -i "8 i FW_New_Update_LOG_Directory_Path=\"${FW_Update_LOG_BASE_DefaultDIR}\"" "$SETTINGSFILE" + sed -i "8 i FW_New_Update_LOG_Directory_Path=\"${FW_Update_LOG_BASE_DefaultDIR}\"" "$CONFIG_FILE" retCode=1 fi - if ! grep -q "^FW_New_Update_LOG_Preferred_Path=" "$SETTINGSFILE" + if ! grep -q "^FW_New_Update_LOG_Preferred_Path=" "$CONFIG_FILE" then preferredPath="$(Get_Custom_Setting FW_New_Update_LOG_Directory_Path)" - sed -i "9 i FW_New_Update_LOG_Preferred_Path=\"${preferredPath}\"" "$SETTINGSFILE" - retCode=1 - fi - if ! grep -q "^CheckChangeLog " "$SETTINGSFILE" - then - sed -i "10 i CheckChangeLog ENABLED" "$SETTINGSFILE" + sed -i "9 i FW_New_Update_LOG_Preferred_Path=\"${preferredPath}\"" "$CONFIG_FILE" retCode=1 fi - if ! grep -q "^Allow_Updates_OverVPN " "$SETTINGSFILE" + if ! grep -q "^CheckChangeLog " "$CONFIG_FILE" then - sed -i "11 i Allow_Updates_OverVPN DISABLED" "$SETTINGSFILE" + sed -i "10 i CheckChangeLog ENABLED" "$CONFIG_FILE" retCode=1 fi - if ! grep -q "^FW_Allow_Beta_Production_Up " "$SETTINGSFILE" + if ! grep -q "^FW_Update_Check " "$CONFIG_FILE" then - sed -i "12 i FW_Allow_Beta_Production_Up ENABLED" "$SETTINGSFILE" + sed -i "11 i FW_Update_Check TBD" "$CONFIG_FILE" retCode=1 fi - if ! grep -q "^FW_Auto_Backupmon " "$SETTINGSFILE" + if ! grep -q "^Allow_Updates_OverVPN " "$CONFIG_FILE" then - sed -i "13 i FW_Auto_Backupmon ENABLED" "$SETTINGSFILE" + sed -i "12 i Allow_Updates_OverVPN DISABLED" "$CONFIG_FILE" retCode=1 fi - if ! grep -q "^Allow_Script_Auto_Update " "$SETTINGSFILE" + if ! grep -q "^FW_Allow_Beta_Production_Up " "$CONFIG_FILE" then - sed -i "14 i Allow_Script_Auto_Update DISABLED" "$SETTINGSFILE" + sed -i "13 i FW_Allow_Beta_Production_Up ENABLED" "$CONFIG_FILE" retCode=1 fi - if ! grep -q "^Script_Update_Cron_Job_SchedDays=" "$SETTINGSFILE" + if ! grep -q "^Allow_Script_Auto_Update " "$CONFIG_FILE" then - sed -i "15 i Script_Update_Cron_Job_SchedDays=\"${SW_Update_CRON_DefaultSchedDays}\"" "$SETTINGSFILE" + sed -i "14 i Allow_Script_Auto_Update DISABLED" "$CONFIG_FILE" retCode=1 fi - if ! grep -q "^FW_New_Update_Changelog_Approval=" "$SETTINGSFILE" + if ! grep -q "^Script_Update_Cron_Job_SchedDays=" "$CONFIG_FILE" then - sed -i "16 i FW_New_Update_Changelog_Approval=TBD" "$SETTINGSFILE" + sed -i "15 i Script_Update_Cron_Job_SchedDays=\"${SW_Update_CRON_DefaultSchedDays}\"" "$CONFIG_FILE" retCode=1 fi - dos2unix "$SETTINGSFILE" - chmod 0664 "$SETTINGSFILE" + dos2unix "$CONFIG_FILE" + chmod 664 "$CONFIG_FILE" return "$retCode" } ##----------------------------------------## -## Modified by Martinski W. [2024-Nov-27] ## +## Modified by Martinski W. [2025-Jan-05] ## ##----------------------------------------## Get_Custom_Setting() { @@ -987,18 +1131,21 @@ Get_Custom_Setting() local setting_value="" setting_type="$1" default_value="TBD" [ $# -gt 1 ] && default_value="$2" - if [ -f "$SETTINGSFILE" ]; then + if [ -f "$CONFIG_FILE" ] + then case "$setting_type" in "ROGBuild" | "TUFBuild" | \ "credentials_base64" | \ "CheckChangeLog" | \ + "FW_Update_Check" | \ "Allow_Updates_OverVPN" | \ "FW_Allow_Beta_Production_Up" | \ "FW_Auto_Backupmon" | \ "Allow_Script_Auto_Update" | \ + "FW_New_Update_EMail_Notification" | \ "FW_New_Update_Notification_Date" | \ "FW_New_Update_Notification_Vers") - setting_value="$(grep "^${setting_type} " "$SETTINGSFILE" | awk -F ' ' '{print $2}')" + setting_value="$(grep "^${setting_type} " "$CONFIG_FILE" | awk -F ' ' '{print $2}')" ;; "FW_New_Update_Postponement_Days" | \ "FW_New_Update_Changelog_Approval" | \ @@ -1008,52 +1155,27 @@ Get_Custom_Setting() "FW_New_Update_ZIP_Directory_Path" | \ "FW_New_Update_LOG_Directory_Path" | \ "FW_New_Update_LOG_Preferred_Path" | \ - "FW_New_Update_EMail_Notification" | \ "FW_New_Update_EMail_FormatType" | \ "FW_New_Update_EMail_CC_Name" | \ "FW_New_Update_EMail_CC_Address") - grep -q "^${setting_type}=" "$SETTINGSFILE" && \ - setting_value="$(grep "^${setting_type}=" "$SETTINGSFILE" | awk -F '=' '{print $2}' | sed "s/['\"]//g")" + grep -q "^${setting_type}=" "$CONFIG_FILE" && \ + setting_value="$(grep "^${setting_type}=" "$CONFIG_FILE" | awk -F '=' '{print $2}' | sed "s/['\"]//g")" ;; *) setting_value="**ERROR**" ;; esac - [ -z "$setting_value" ] && echo "$default_value" || echo "$setting_value" + if [ -z "$setting_value" ] + then echo "$default_value" + else echo "$setting_value" + fi else echo "$default_value" fi } ##----------------------------------------## -## Modified by Martinski W. [2024-Apr-30] ## -##----------------------------------------## -_GetAllNodeSettings_() -{ - if [ $# -lt 2 ] || [ -z "$1" ] || [ -z "$2" ] - then echo "**ERROR**" ; return 1; fi - - ## Node Setting KEY="Node_{MACaddress}_{keySuffix}" ## - local fullKeyName="Node_${1}_${2}" - local setting_value="TBD" matched_lines - - # Ensure the settings directory exists # - [ ! -d "$SETTINGS_DIR" ] && mkdir -m 755 -p "$SETTINGS_DIR" - - if [ -f "$SETTINGSFILE" ] - then - matched_lines="$(grep -E "^${fullKeyName}=.*" "$SETTINGSFILE")" - if [ -n "$matched_lines" ] - then - # Extract the value from the first matched line # - setting_value="$(echo "$matched_lines" | head -n 1 | awk -F '=' '{print $2}' | tr -d '"')" - fi - fi - echo "$setting_value" -} - -##----------------------------------------## -## Modified by Martinski W. [2024-Nov-27] ## +## Modified by Martinski W. [2025-Jan-20] ## ##----------------------------------------## Update_Custom_Settings() { @@ -1062,31 +1184,34 @@ Update_Custom_Settings() local fixedVal oldVal="" local setting_type="$1" setting_value="$2" - # Check if the directory exists, and if not, create it + # Check if the directory exists, and if not, create it # [ ! -d "$SETTINGS_DIR" ] && mkdir -m 755 -p "$SETTINGS_DIR" case "$setting_type" in "ROGBuild" | "TUFBuild" | \ "credentials_base64" | \ "CheckChangeLog" | \ + "FW_Update_Check" | \ "Allow_Updates_OverVPN" | \ "FW_Allow_Beta_Production_Up" | \ "FW_Auto_Backupmon" | \ "Allow_Script_Auto_Update" | \ + "FW_New_Update_EMail_Notification" | \ "FW_New_Update_Notification_Date" | \ "FW_New_Update_Notification_Vers") - if [ -f "$SETTINGSFILE" ] + if [ -f "$CONFIG_FILE" ] then - if [ "$(grep -c "$setting_type" "$SETTINGSFILE")" -gt 0 ] + if [ "$(grep -c "^$setting_type" "$CONFIG_FILE")" -gt 0 ] then - if [ "$setting_value" != "$(grep "^$setting_type" "$SETTINGSFILE" | cut -f2 -d' ')" ]; then - sed -i "s/$setting_type.*/$setting_type $setting_value/" "$SETTINGSFILE" + if [ "$setting_value" != "$(grep "^$setting_type" "$CONFIG_FILE" | cut -f2 -d' ')" ] + then + sed -i "s/^$setting_type.*/$setting_type $setting_value/" "$CONFIG_FILE" fi else - echo "$setting_type $setting_value" >> "$SETTINGSFILE" + echo "$setting_type $setting_value" >> "$CONFIG_FILE" fi else - echo "$setting_type $setting_value" > "$SETTINGSFILE" + echo "$setting_type $setting_value" > "$CONFIG_FILE" fi ;; "FW_New_Update_Postponement_Days" | \ @@ -1097,25 +1222,24 @@ Update_Custom_Settings() "FW_New_Update_ZIP_Directory_Path" | \ "FW_New_Update_LOG_Directory_Path" | \ "FW_New_Update_LOG_Preferred_Path" | \ - "FW_New_Update_EMail_Notification" | \ "FW_New_Update_EMail_FormatType" | \ "FW_New_Update_EMail_CC_Name" | \ "FW_New_Update_EMail_CC_Address") - if [ -f "$SETTINGSFILE" ] + if [ -f "$CONFIG_FILE" ] then - if grep -q "^${setting_type}=" "$SETTINGSFILE" + if grep -q "^${setting_type}=" "$CONFIG_FILE" then - oldVal="$(grep "^${setting_type}=" "$SETTINGSFILE" | awk -F '=' '{print $2}' | sed "s/['\"]//g")" + oldVal="$(grep "^${setting_type}=" "$CONFIG_FILE" | awk -F '=' '{print $2}' | sed "s/['\"]//g")" if [ -z "$oldVal" ] || [ "$oldVal" != "$setting_value" ] then fixedVal="$(echo "$setting_value" | sed 's/[\/.,*-]/\\&/g')" - sed -i "s/${setting_type}=.*/${setting_type}=\"${fixedVal}\"/" "$SETTINGSFILE" + sed -i "s/${setting_type}=.*/${setting_type}=\"${fixedVal}\"/" "$CONFIG_FILE" fi else - echo "$setting_type=\"${setting_value}\"" >> "$SETTINGSFILE" + echo "$setting_type=\"${setting_value}\"" >> "$CONFIG_FILE" fi else - echo "$setting_type=\"${setting_value}\"" > "$SETTINGSFILE" + echo "$setting_type=\"${setting_value}\"" > "$CONFIG_FILE" fi if [ "$setting_type" = "FW_New_Update_Postponement_Days" ] then @@ -1125,10 +1249,6 @@ Update_Custom_Settings() then FW_UpdateExpectedRunDate="$setting_value" # - elif [ "$setting_type" = "FW_New_Update_EMail_Notification" ] - then - sendEMailNotificationsFlag="$setting_value" - # elif [ "$setting_type" = "FW_New_Update_EMail_FormatType" ] then sendEMailFormaType="$setting_value" @@ -1146,38 +1266,39 @@ Update_Custom_Settings() elif [ "$setting_type" = "FW_New_Update_Cron_Job_Schedule" ] then FW_UpdateCronJobSchedule="$setting_value" + _WebUI_AutoScriptUpdateCronSchedule_ + _WebUI_AutoFWUpdateCheckCronSchedule_ # elif [ "$setting_type" = "Script_Update_Cron_Job_SchedDays" ] then ScriptUpdateCronSchedDays="$setting_value" + _WebUI_AutoScriptUpdateCronSchedule_ # elif [ "$setting_type" = "FW_New_Update_ZIP_Directory_Path" ] then - FW_ZIP_BASE_DIR="$setting_value" - FW_ZIP_DIR="${setting_value}/$FW_ZIP_SUBDIR" - FW_ZIP_FPATH="${FW_ZIP_DIR}/${FW_FileName}.zip" + _SetUp_FW_UpdateZIP_DirectoryPaths_ "$setting_value" # elif [ "$setting_type" = "FW_New_Update_LOG_Directory_Path" ] - then # Addition for handling log directory path - FW_LOG_BASE_DIR="$setting_value" - FW_LOG_DIR="${setting_value}/$FW_LOG_SUBDIR" + then + _SetUp_FW_UpdateLOG_DirectoryPaths_ "$setting_value" fi ;; *) # Generic handling for arbitrary settings # - if grep -q "^${setting_type}=" "$SETTINGSFILE" + if grep -q "^${setting_type}=" "$CONFIG_FILE" then - oldVal="$(grep "^${setting_type}=" "$SETTINGSFILE" | awk -F '=' '{print $2}' | sed "s/['\"]//g")" + oldVal="$(grep "^${setting_type}=" "$CONFIG_FILE" | awk -F '=' '{print $2}' | sed "s/['\"]//g")" if [ -z "$oldVal" ] || [ "$oldVal" != "$setting_value" ] then fixedVal="$(echo "$setting_value" | sed 's/[\/&]/\\&/g')" - sed -i "s/^${setting_type}=.*/${setting_type}=\"${fixedVal}\"/" "$SETTINGSFILE" + sed -i "s/^${setting_type}=.*/${setting_type}=\"${fixedVal}\"/" "$CONFIG_FILE" fi else - echo "${setting_type}=\"${setting_value}\"" >> "$SETTINGSFILE" + echo "${setting_type}=\"${setting_value}\"" >> "$CONFIG_FILE" fi ;; esac + return 0 } ##----------------------------------------## @@ -1185,29 +1306,221 @@ Update_Custom_Settings() ##----------------------------------------## Delete_Custom_Settings() { - if [ $# -lt 1 ] || [ -z "$1" ] || [ ! -f "$SETTINGSFILE" ] + if [ $# -lt 1 ] || [ -z "$1" ] || [ ! -f "$CONFIG_FILE" ] then return 1 ; fi local setting_type="$1" - sed -i "/^${setting_type}[ =]/d" "$SETTINGSFILE" + sed -i "/^${setting_type}[ =]/d" "$CONFIG_FILE" return $? } ##------------------------------------------## -## Modified by ExtremeFiretop [2024-Jan-24] ## +## Modified by ExtremeFiretop [2024-Dec-21] ## ##------------------------------------------## +_GetAllNodeSettings_() +{ + if [ $# -lt 2 ] || [ -z "$1" ] || [ -z "$2" ] + then echo "**ERROR**" ; return 1; fi + + ## Node Setting KEY="Node_{MACaddress}_{keySuffix}" ## + local fullKeyName="Node_${1}_${2}" + local setting_value="TBD" matched_lines + + # Ensure the settings directory exists # + [ ! -d "$SETTINGS_DIR" ] && mkdir -m 755 -p "$SETTINGS_DIR" + + if [ -f "$CONFIG_FILE" ] + then + matched_lines="$(grep -E "^${fullKeyName}=.*" "$CONFIG_FILE")" + if [ -n "$matched_lines" ] + then + # Extract the value from the first matched line # + setting_value="$(echo "$matched_lines" | head -n 1 | awk -F '=' '{print $2}' | tr -d '"')" + fi + fi + echo "$setting_value" +} + +##-------------------------------------## +## Added by Martinski W. [2025-Feb-23] ## +##-------------------------------------## +extCheckRETvarID=0x00 +extCheckZIPdirID=0x01 +extCheckLOGdirID=0x02 +extCheckALLvarID=0x0F +extCheckZIPdirOK=true +extCheckLOGdirOK=true +extCheckRETvarOK=true +extCheckZIPdirMG="OK" +extCheckLOGdirMG="OK" +extCheckRETvarMG="OK" + +##-------------------------------------## +## Added by Martinski W. [2025-Feb-25] ## +##-------------------------------------## +_WebUI_FW_UpdateZIPDirPathDefault_() +{ + local defltDirPath="/home/root" + if [ -n "$USBMountPoint" ] && \ + _ValidateUSBMountPoint_ "$FW_ZIP_BASE_DIR" + then defltDirPath="$FW_ZIP_BASE_DIR" ; fi + _WriteVarDefToHelperJSFile_ "defaultFWUpdateZIPdirPath" "$defltDirPath" +} + +##----------------------------------------## +## Modified by Martinski W. [2025-Feb-25] ## +##----------------------------------------## +_InitHelperJSFile_() +{ + ! "$inRouterSWmode" && return 0 + + [ ! -s "$HELPER_JSFILE" ] && \ + { + echo "var externalCheckID = 0x00;" + echo "var externalCheckOK = true;" + echo "var externalCheckMsg = '';" + } > "$HELPER_JSFILE" + + _WebUI_FW_UpdateZIPDirPathDefault_ + _WebUI_SetEmailConfigFileFromAMTM_ + _WebUI_AutoScriptUpdateCronSchedule_ + _WebUI_AutoFWUpdateCheckCronSchedule_ +} + +##----------------------------------------## +## Modified by Martinski W. [2025-Feb-25] ## +##----------------------------------------## +_UpdateHelperJSFile_() +{ + if [ $# -lt 2 ] || \ + [ -z "$1" ] || [ -z "$2" ] || \ + ! "$inRouterSWmode" + then return 1; fi + + local extCheckMsg="" + if [ $# -gt 2 ] && [ -n "$3" ] + then extCheckMsg="$3" ; fi + + if [ "$(($1 & extCheckZIPdirID))" -gt 0 ] + then + extCheckZIPdirOK="$2" + extCheckZIPdirMG="$extCheckMsg" + fi + if [ "$(($1 & extCheckLOGdirID))" -gt 0 ] + then + extCheckLOGdirOK="$2" + extCheckLOGdirMG="$extCheckMsg" + fi + + if [ "$1" = "$extCheckALLvarID" ] || \ + [ "$extCheckZIPdirOK" = "$extCheckLOGdirOK" ] + then + extCheckRETvarOK="$extCheckZIPdirOK" + extCheckRETvarID="$((extCheckZIPdirID | extCheckLOGdirID))" + if "$extCheckZIPdirOK" + then + extCheckRETvarMG="$extCheckZIPdirMG" + else + extCheckRETvarMG="${extCheckZIPdirMG}\n\n${extCheckLOGdirMG}" + fi + elif ! "$extCheckZIPdirOK" + then + extCheckRETvarOK="$extCheckZIPdirOK" + extCheckRETvarID="$extCheckZIPdirID" + extCheckRETvarMG="$extCheckZIPdirMG" + elif ! "$extCheckLOGdirOK" + then + extCheckRETvarOK="$extCheckLOGdirOK" + extCheckRETvarID="$extCheckLOGdirID" + extCheckRETvarMG="$extCheckLOGdirMG" + fi + + { + echo "var externalCheckID = ${extCheckRETvarID};" + echo "var externalCheckOK = ${extCheckRETvarOK};" + echo "var externalCheckMsg = '${extCheckRETvarMG}';" + } > "$HELPER_JSFILE" + + _WebUI_FW_UpdateZIPDirPathDefault_ + _WebUI_SetEmailConfigFileFromAMTM_ + _WebUI_AutoScriptUpdateCronSchedule_ + _WebUI_AutoFWUpdateCheckCronSchedule_ +} + +##----------------------------------------## +## Modified by Martinski W. [2025-Feb-23] ## +##----------------------------------------## +_Validate_FW_UpdateLOG_DirectoryPath_() +{ + if [ $# -eq 0 ] || [ -z "$1" ] ; then return 1 ; fi + + local updateHelperJS=false + if [ $# -eq 2 ] && [ "$2" = "true" ] + then updateHelperJS=true ; fi + + if [ ! -d "$1" ] + then + if "$updateHelperJS" + then + checkErrorMsg="The directory path for F/W update log files is NOT found:\n[$1]" + _UpdateHelperJSFile_ "$extCheckLOGdirID" "false" "$checkErrorMsg" + fi + Say "${REDct}**ERROR**${NOct}: Directory path [${REDct}${1}${NOct}] for F/W update log files is NOT found." + _WaitForEnterKey_ + return 1 + fi + + if [ "$1" = "$FW_LOG_DIR" ] || [ "$1" = "$FW_LOG_BASE_DIR" ] + then + _UpdateHelperJSFile_ "$extCheckLOGdirID" "true" + return 0 + fi + + local newFullDirPath="" newBaseDirPath="$1" + + if echo "$newBaseDirPath" | grep -qE "/${FW_LOG_SUBDIR}$" + then newFullDirPath="$newBaseDirPath" + else newFullDirPath="${newBaseDirPath}/$FW_LOG_SUBDIR" + fi + mkdir -p -m 755 "$newFullDirPath" 2>/dev/null + if [ ! -d "$newFullDirPath" ] + then + if "$updateHelperJS" + then + checkErrorMsg="The directory path for F/W update log files cannot be created:\n[$newFullDirPath]" + _UpdateHelperJSFile_ "$extCheckLOGdirID" "false" "$checkErrorMsg" + fi + Say "${REDct}**ERROR**${NOct}: Could NOT create directory path [${REDct}${newFullDirPath}${NOct}] for F/W update log files." + _WaitForEnterKey_ + return 1 + fi + # Move any existing log files to new directory # + mv -f "${FW_LOG_DIR}"/*.log "$newFullDirPath" 2>/dev/null + # Remove now the obsolete directory path # + rm -fr "${FW_LOG_DIR:?}" + # Update the log directory paths after validation # + Update_Custom_Settings FW_New_Update_LOG_Directory_Path "$newBaseDirPath" + Update_Custom_Settings FW_New_Update_LOG_Preferred_Path "$newBaseDirPath" + _UpdateHelperJSFile_ "$extCheckLOGdirID" "true" + return 0 +} + +##----------------------------------------## +## Modified by Martinski W. [2025-Feb-23] ## +##----------------------------------------## _Set_FW_UpdateLOG_DirectoryPath_() { - local newLogBaseDirPath="$FW_LOG_BASE_DIR" newLogFileDirPath="" + local newLOG_BaseDirPath="$FW_LOG_BASE_DIR" while true do - printf "\nEnter the directory path where the LOG subdirectory [${GRNct}${FW_LOG_SUBDIR}${NOct}] will be stored.\n" - printf "[${theADExitStr}] [CURRENT: ${GRNct}${FW_LOG_BASE_DIR}${NOct}]: " + printf "\nEnter the directory path where the subdirectory [${GRNct}${FW_LOG_SUBDIR}${NOct}] will be located.\n" + printf "[${theLGExitStr}]\n" + printf "[Current Base Path: ${GRNct}${FW_LOG_BASE_DIR}${NOct}]: " read -r userInput - if [ -z "$userInput" ] || echo "$userInput" | grep -qE "^(e|exit|Exit)$" - then break ; fi + if [ -z "$userInput" ] ; then break ; fi + if echo "$userInput" | grep -qE "^(e|exit|Exit)$" ; then return 1 ; fi if echo "$userInput" | grep -q '/$' then userInput="${userInput%/*}" ; fi @@ -1225,7 +1538,7 @@ _Set_FW_UpdateLOG_DirectoryPath_() fi if [ -d "$userInput" ] - then newLogBaseDirPath="$userInput" ; break ; fi + then newLOG_BaseDirPath="$userInput" ; break ; fi rootDir="${userInput%/*}" if [ ! -d "$rootDir" ] @@ -1244,67 +1557,100 @@ _Set_FW_UpdateLOG_DirectoryPath_() else mkdir -m 755 "$userInput" 2>/dev/null if [ -d "$userInput" ] - then newLogBaseDirPath="$userInput" ; break + then newLOG_BaseDirPath="$userInput" ; break else printf "\n${REDct}**ERROR**${NOct}: Could NOT create directory [${REDct}${userInput}${NOct}].\n\n" fi fi done - # Double-check current directory indeed exists after menu selection # - if [ "$newLogBaseDirPath" = "$FW_LOG_BASE_DIR" ] && [ ! -d "$FW_LOG_DIR" ] - then mkdir -p -m 755 "$FW_LOG_DIR" ; fi - - if [ "$newLogBaseDirPath" != "$FW_LOG_BASE_DIR" ] && [ -d "$newLogBaseDirPath" ] + if [ -d "$newLOG_BaseDirPath" ] then - if ! echo "$newLogBaseDirPath" | grep -qE "${FW_LOG_SUBDIR}$" - then newLogFileDirPath="${newLogBaseDirPath}/$FW_LOG_SUBDIR" ; fi - mkdir -p -m 755 "$newLogFileDirPath" 2>/dev/null - if [ ! -d "$newLogFileDirPath" ] - then - printf "\n${REDct}**ERROR**${NOct}: Could NOT create directory [${REDct}${newLogFileDirPath}${NOct}].\n" - _WaitForEnterKey_ - return 1 + if ! _Validate_FW_UpdateLOG_DirectoryPath_ "$newLOG_BaseDirPath" + then return 1 fi - # Move any existing log files to new directory # - mv -f "${FW_LOG_DIR}"/*.log "$newLogFileDirPath" 2>/dev/null - # Remove now the obsolete directory path # - rm -fr "${FW_LOG_DIR:?}" - # Update the log directory path after validation # - Update_Custom_Settings FW_New_Update_LOG_Directory_Path "$newLogBaseDirPath" - Update_Custom_Settings FW_New_Update_LOG_Preferred_Path "$newLogBaseDirPath" echo "The directory path for the log files was updated successfully." - _WaitForEnterKey_ "$advnMenuReturnPromptStr" + _WaitForEnterKey_ "$logsMenuReturnPromptStr" fi return 0 } ##----------------------------------------## -## Modified by Martinski W. [2024-Jul-31] ## +## Modified by Martinski W. [2025-Feb-23] ## ##----------------------------------------## -_Set_FW_UpdateZIP_DirectoryPath_() +_Validate_FW_UpdateZIP_DirectoryPath_() { - local newZIP_BaseDirPath="$FW_ZIP_BASE_DIR" newZIP_FileDirPath="" + if [ $# -eq 0 ] || [ -z "$1" ] ; then return 1 ; fi - while true - do - if "$isGNUtonFW" - then - printf "\nEnter the directory path where the update subdirectory [${GRNct}${FW_ZIP_SUBDIR}${NOct}] will be stored.\n" - else - printf "\nEnter the directory path where the ZIP subdirectory [${GRNct}${FW_ZIP_SUBDIR}${NOct}] will be stored.\n" - fi - if [ -n "$USBMountPoint" ] && _ValidateUSBMountPoint_ "$FW_ZIP_BASE_DIR" - then - printf "Default directory for USB-attached drive: [${GRNct}${FW_ZIP_BASE_DIR}${NOct}]\n" - else - printf "Default directory for 'Local' storage is: [${GRNct}/home/root${NOct}]\n" - fi - printf "\n[${theADExitStr}] [CURRENT: ${GRNct}${FW_ZIP_BASE_DIR}${NOct}]: " + local updateHelperJS=false + if [ $# -eq 2 ] && [ "$2" = "true" ] + then updateHelperJS=true ; fi - read -r userInput + if [ ! -d "$1" ] + then + if "$updateHelperJS" + then + checkErrorMsg="The directory path for F/W update files is NOT found:\n[$1]" + _UpdateHelperJSFile_ "$extCheckZIPdirID" "false" "$checkErrorMsg" + fi + Say "${REDct}**ERROR**${NOct}: Directory path [${REDct}${1}${NOct}] for F/W update files is NOT found." + _WaitForEnterKey_ + return 1 + fi - if [ -z "$userInput" ] ; then break ; fi - if echo "$userInput" | grep -qE "^(e|E|exit|Exit)$" ; then return 1 ; fi + if [ "$1" = "$FW_ZIP_DIR" ] || [ "$1" = "$FW_ZIP_BASE_DIR" ] + then + _UpdateHelperJSFile_ "$extCheckZIPdirID" "true" + return 0 + fi + + local newFullDirPath="" newBaseDirPath="$1" + + if echo "$newBaseDirPath" | grep -qE "/${FW_ZIP_SUBDIR}$" + then newFullDirPath="$newBaseDirPath" + else newFullDirPath="${newBaseDirPath}/$FW_ZIP_SUBDIR" + fi + mkdir -p -m 755 "$newFullDirPath" 2>/dev/null + if [ ! -d "$newFullDirPath" ] + then + if "$updateHelperJS" + then + checkErrorMsg="The directory path for F/W update files cannot be created:\n[$newFullDirPath]" + _UpdateHelperJSFile_ "$extCheckZIPdirID" "false" "$checkErrorMsg" + fi + Say "${REDct}**ERROR**${NOct}: Could NOT create directory path [${REDct}${newFullDirPath}${NOct}] for F/W update files." + _WaitForEnterKey_ + return 1 + fi + # Remove now the obsolete directory path # + rm -fr "${FW_ZIP_DIR:?}" + rm -f "${newFullDirPath}"/*.zip "${newFullDirPath}"/*.sha256 + Update_Custom_Settings FW_New_Update_ZIP_Directory_Path "$newBaseDirPath" + _UpdateHelperJSFile_ "$extCheckZIPdirID" "true" + return 0 +} + +##----------------------------------------## +## Modified by Martinski W. [2025-Feb-23] ## +##----------------------------------------## +_Set_FW_UpdateZIP_DirectoryPath_() +{ + local newZIP_BaseDirPath="$FW_ZIP_BASE_DIR" + + while true + do + printf "\nEnter the directory path where the update subdirectory [${GRNct}${FW_ZIP_SUBDIR}${NOct}] will be located.\n" + if [ -n "$USBMountPoint" ] && _ValidateUSBMountPoint_ "$FW_ZIP_BASE_DIR" + then + printf "Default directory for USB-attached drive: [${GRNct}${FW_ZIP_BASE_DIR}${NOct}]\n" + else + printf "Default directory for 'Local' storage is: [${GRNct}/home/root${NOct}]\n" + fi + printf "\n[${theADExitStr}]\n" + printf "[Current Base Path: ${GRNct}${FW_ZIP_BASE_DIR}${NOct}]: " + read -r userInput + + if [ -z "$userInput" ] ; then break ; fi + if echo "$userInput" | grep -qE "^(e|E|exit|Exit)$" ; then return 1 ; fi if echo "$userInput" | grep -q '/$' then userInput="${userInput%/*}" ; fi @@ -1347,21 +1693,11 @@ _Set_FW_UpdateZIP_DirectoryPath_() fi done - if [ "$newZIP_BaseDirPath" != "$FW_ZIP_BASE_DIR" ] && [ -d "$newZIP_BaseDirPath" ] + if [ -d "$newZIP_BaseDirPath" ] then - if ! echo "$newZIP_BaseDirPath" | grep -qE "${FW_ZIP_SUBDIR}$" - then newZIP_FileDirPath="${newZIP_BaseDirPath}/$FW_ZIP_SUBDIR" ; fi - mkdir -p -m 755 "$newZIP_FileDirPath" 2>/dev/null - if [ ! -d "$newZIP_FileDirPath" ] - then - printf "\n${REDct}**ERROR**${NOct}: Could NOT create directory [${REDct}${newZIP_FileDirPath}${NOct}].\n" - _WaitForEnterKey_ - return 1 + if ! _Validate_FW_UpdateZIP_DirectoryPath_ "$newZIP_BaseDirPath" + then return 1 fi - # Remove now the obsolete directory path # - rm -fr "${FW_ZIP_DIR:?}" - rm -f "${newZIP_FileDirPath}"/*.zip "${newZIP_FileDirPath}"/*.sha256 - Update_Custom_Settings FW_New_Update_ZIP_Directory_Path "$newZIP_BaseDirPath" if "$isGNUtonFW" then echo "The directory path for the F/W update file was updated successfully." @@ -1374,20 +1710,93 @@ _Set_FW_UpdateZIP_DirectoryPath_() return 0 } -_Init_Custom_Settings_Config_ +##----------------------------------------## +## Modified by Martinski W. [2025-Feb-15] ## +##----------------------------------------## +## Function to migrate specific settings from old values to new standardized values. +## This function is meant to be only TEMPORARY. +## We should be safe to remove it after 3 months, or 5 version releases, +## whichever comes first. Similar to the migration function removed in v1.0.9 +##-----------------------------------------------------------------------------------## +_Migrate_Settings_() +{ + [ ! -s "$CONFIG_FILE" ] && return 1 -##------------------------------------------## -## Modified by ExtremeFiretop [2024-Jun-03] ## -##------------------------------------------## -# NOTE: -# ROG upgrades to 3006 codebase should have -# the ROG option deleted. -#----------------------------------------------------------- -if ! "$isGNUtonFW" -then - if [ "$fwInstalledBaseVers" -ge 3006 ] && grep -q "^ROGBuild" "$SETTINGSFILE" - then Delete_Custom_Settings "ROGBuild" ; fi -fi + ## Migrate Setting from [y|Y|n|N] to [ENABLED|DISABLED] ## + ROGBuild_Value="$(Get_Custom_Setting ROGBuild)" + if [ "$ROGBuild_Value" != "TBD" ] + then + case "$ROGBuild_Value" in + y|Y) New_ROGBuild_Value="ENABLED" ;; + n|N) New_ROGBuild_Value="DISABLED" ;; + *) + New_ROGBuild_Value="" + ! echo "$ROGBuild_Value" | grep -qE "^(ENABLED|DISABLED)$" && \ + Say "ROGBuild has a unknown value: '$ROGBuild_Value'. Skipping migration for this setting." + ;; + esac + if [ -n "$New_ROGBuild_Value" ] + then + if Update_Custom_Settings ROGBuild "$New_ROGBuild_Value" + then + Say "ROGBuild setting was successfully migrated to '$New_ROGBuild_Value'." + else + Say "Error occurred while migrating ROGBuild setting to '$New_ROGBuild_Value'." + fi + fi + fi + + ## Migrate Setting from [y|Y|n|N] to [ENABLED|DISABLED] ## + TUFBuild_Value="$(Get_Custom_Setting TUFBuild)" + if [ "$TUFBuild_Value" != "TBD" ] + then + case "$TUFBuild_Value" in + y|Y) New_TUFBuild_Value="ENABLED" ;; + n|N) New_TUFBuild_Value="DISABLED" ;; + *) + New_TUFBuild_Value="" + ! echo "$TUFBuild_Value" | grep -qE "^(ENABLED|DISABLED)$" && \ + Say "TUFBuild has a unknown value: '$TUFBuild_Value'. Skipping migration for this setting." + ;; + esac + if [ -n "$New_TUFBuild_Value" ] + then + if Update_Custom_Settings TUFBuild "$New_TUFBuild_Value" + then + Say "TUFBuild setting was successfully migrated to '$New_TUFBuild_Value'." + else + Say "Error occurred while migrating TUFBuild setting to '$New_TUFBuild_Value'." + fi + fi + fi + + ## Migrate Setting from [true|false] to [ENABLED|DISABLED] ## + EMailNotif_Value="$(grep '^FW_New_Update_EMail_Notification=' "$CONFIG_FILE" | cut -d'=' -f2 | tr -d '"')" + if [ -n "$EMailNotif_Value" ] && [ "$EMailNotif_Value" != "TBD" ] + then + case "$EMailNotif_Value" in + true|TRUE|True) New_EMailNotif_Value="ENABLED" ;; + false|FALSE|False) New_EMailNotif_Value="DISABLED" ;; + *) + New_EMailNotif_Value="" + ! echo "$EMailNotif_Value" | grep -qE "^(ENABLED|DISABLED)$" && \ + Say "FW_New_Update_EMail_Notification has a unknown value: '$EMailNotif_Value'. Skipping migration for this setting." + ;; + esac + if [ -n "$New_EMailNotif_Value" ] + then + sed -i '/^FW_New_Update_EMail_Notification .*/d' "$CONFIG_FILE" + sed -i "s/^FW_New_Update_EMail_Notification=.*/FW_New_Update_EMail_Notification $New_EMailNotif_Value/" "$CONFIG_FILE" + if [ $? -eq 0 ] + then + sendEMailNotificationsFlag="$New_EMailNotif_Value" + Say "EMail_Notification setting was successfully migrated to $New_EMailNotif_Value." + else + Say "Error occurred while migrating EMail_Notification setting to $New_EMailNotif_Value." + fi + fi + fi +} ##------------------------------------------## ## Modified by ExtremeFiretop [2024-Jan-27] ## @@ -1398,22 +1807,22 @@ fi # storage for the ZIP file so that it can be downloaded # in a separate directory from the firmware bin file. #----------------------------------------------------------- -FW_BIN_BASE_DIR="/home/root" -FW_ZIP_BASE_DIR="$(Get_Custom_Setting FW_New_Update_ZIP_Directory_Path)" -FW_LOG_BASE_DIR="$(Get_Custom_Setting FW_New_Update_LOG_Directory_Path)" - readonly FW_LOG_SUBDIR="${ScriptDirNameD}/logs" readonly FW_BIN_SUBDIR="${ScriptDirNameD}/$FW_FileName" readonly FW_ZIP_SUBDIR="${ScriptDirNameD}/$FW_FileName" +FW_BIN_BASE_DIR="/home/root" FW_BIN_DIR="${FW_BIN_BASE_DIR}/$FW_BIN_SUBDIR" -FW_LOG_DIR="${FW_LOG_BASE_DIR}/$FW_LOG_SUBDIR" -FW_ZIP_DIR="${FW_ZIP_BASE_DIR}/$FW_ZIP_SUBDIR" -FW_ZIP_FPATH="${FW_ZIP_DIR}/${FW_FileName}.zip" -##----------------------------------------------## -## Added/Modified by Martinski W. [2023-Nov-24] ## -##----------------------------------------------## +##----------------------------------------## +## Modified by Martinski W. [2025-Jan-15] ## +##----------------------------------------## +_SetUp_FW_UpdateZIP_DirectoryPaths_ +_SetUp_FW_UpdateLOG_DirectoryPaths_ + +##----------------------------------------## +## Modified by Martinski W. [2023-Nov-24] ## +##----------------------------------------## # The built-in F/W hook script file to be used for # setting up persistent jobs to run after a reboot. readonly hookScriptFName="services-start" @@ -1434,8 +1843,10 @@ sendEMailFormaType="$(Get_Custom_Setting FW_New_Update_EMail_FormatType)" sendEMailNotificationsFlag="$(Get_Custom_Setting FW_New_Update_EMail_Notification)" sendEMail_CC_Name="$(Get_Custom_Setting FW_New_Update_EMail_CC_Name)" sendEMail_CC_Address="$(Get_Custom_Setting FW_New_Update_EMail_CC_Address)" -[ "$sendEMailFormaType" = "HTML" ] && \ -isEMailFormatHTML=true || isEMailFormatHTML=false +if [ "$sendEMailFormaType" = "HTML" ] +then isEMailFormatHTML=true +else isEMailFormatHTML=false +fi ##----------------------------------------## ## Modified by Martinski W. [2024-Nov-27] ## @@ -1503,6 +1914,518 @@ then Update_Custom_Settings FW_New_Update_LOG_Directory_Path "$UserPreferredLogPath" fi +##-------------------------------------## +## Added by Martinski W. [2025-Feb-12] ## +##-------------------------------------## +_Check_WebGUI_Page_Exists_() +{ + local webPageStr webPageFile theWebPage + + if [ ! -f "$TEMP_MENU_TREE" ] + then echo "NONE" ; return 1 ; fi + + theWebPage="NONE" + webPageStr="$(grep -E -m1 "^$webPageLineRegExp" "$TEMP_MENU_TREE")" + if [ -n "$webPageStr" ] + then + webPageFile="$(echo "$webPageStr" | grep -owE "$webPageFileRegExp" | head -n1)" + if [ -n "$webPageFile" ] && [ -s "${SHARED_WEB_DIR}/$webPageFile" ] + then theWebPage="$webPageFile" ; fi + fi + echo "$theWebPage" +} + +##----------------------------------------## +## Modified by Martinski W. [2025-Feb-12] ## +##----------------------------------------## +_GetWebUIPage_() +{ + local webPageFile webPagePath webPageTemp + + webPageFile="$(_Check_WebGUI_Page_Exists_)" + + for index in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 + do + webPageTemp="user${index}.asp" + webPagePath="${SHARED_WEB_DIR}/$webPageTemp" + + if [ -s "$webPagePath" ] && \ + [ "$(md5sum < "$1")" = "$(md5sum < "$webPagePath")" ] + then + webPageFile="$webPageTemp" + break + elif [ "$webPageFile" = "NONE" ] && [ ! -s "$webPagePath" ] + then + webPageFile="$webPageTemp" + fi + done + echo "$webPageFile" +} + +##----------------------------------------## +## Modified by Martinski W. [2025-Jan-11] ## +##----------------------------------------## +_Mount_WebUI_() +{ + if [ ! -f "$SCRIPT_WEB_ASP_PATH" ] + then + Say "${CRITct}**ERROR**${NOct}: The WebUI page file for $SCRIPT_NAME is NOT found." + return 1 + fi + local webPageFile + + Say "Mounting WebUI page for ${SCRIPT_NAME}..." + + eval exec "$WEBUI_LOCKFD>$WEBUI_LOCKFILE" + flock -x "$WEBUI_LOCKFD" + + webPageFile="$(_GetWebUIPage_ "$SCRIPT_WEB_ASP_PATH")" + if [ -z "$webPageFile" ] || [ "$webPageFile" = "NONE" ] + then + Say "${CRITct}**ERROR**${NOct}: Unable to mount the $SCRIPT_NAME WebUI page." + flock -u "$WEBUI_LOCKFD" + return 1 + fi + + cp -fp "$SCRIPT_WEB_ASP_PATH" "${SHARED_WEB_DIR}/$webPageFile" + echo "$SCRIPT_NAME" > "${SHARED_WEB_DIR}/$(echo "$webPageFile" | cut -f1 -d'.').title" + + if [ ! -f "$TEMP_MENU_TREE" ] + then cp -fp "$ORIG_MENU_TREE" "$TEMP_MENU_TREE" + fi + sed -i "/url: \"$webPageFile\", tabName: \"$SCRIPT_NAME\"/d" "$TEMP_MENU_TREE" + + # Insert new page tab in the 'Administration' menu # + sed -i "/url: \"Advanced_FirmwareUpgrade_Content.asp\", tabName:/a {url: \"$webPageFile\", tabName: \"$SCRIPT_NAME\"}," "$TEMP_MENU_TREE" + + umount "$ORIG_MENU_TREE" 2>/dev/null + mount -o bind "$TEMP_MENU_TREE" "$ORIG_MENU_TREE" + flock -u "$WEBUI_LOCKFD" + + Say "${GRNct}$SCRIPT_NAME WebUI page was mounted as $webPageFile successfully." + return 0 +} + +##-------------------------------------## +## Added by Martinski W. [2025-Feb-12] ## +##-------------------------------------## +_CheckFor_WebGUI_Page_() +{ + if "$inRouterSWmode" && \ + [ "$(_Check_WebGUI_Page_Exists_)" = "NONE" ] + then _Mount_WebUI_ ; fi +} + +##----------------------------------------## +## Modified by Martinski W. [2025-Jan-11] ## +##----------------------------------------## +_Unmount_WebUI_() +{ + if [ ! -f "$SCRIPT_WEB_ASP_PATH" ] + then + Say "${CRITct}**ERROR**${NOct}: The WebUI page file for $SCRIPT_NAME is NOT found." + return 1 + fi + local webPageFile + + Say "Unmounting WebUI page for $SCRIPT_NAME" + + eval exec "$WEBUI_LOCKFD>$WEBUI_LOCKFILE" + flock -x "$WEBUI_LOCKFD" + + webPageFile="$(_GetWebUIPage_ "$SCRIPT_WEB_ASP_PATH")" + if [ -z "$webPageFile" ] || [ "$webPageFile" = "NONE" ] + then + Say "WebUI page file for $SCRIPT_NAME is NOT found to uninstall." + flock -u "$WEBUI_LOCKFD" + return 1 + fi + + if [ -f "$TEMP_MENU_TREE" ] + then + sed -i "/url: \"$webPageFile\", tabName: \"$SCRIPT_NAME\"/d" "$TEMP_MENU_TREE" + fi + rm -f "${SHARED_WEB_DIR}/$webPageFile" + rm -f "${SHARED_WEB_DIR}/$(echo "$webPageFile" | cut -f1 -d'.').title" + + umount "$ORIG_MENU_TREE" 2>/dev/null + mount -o bind "$TEMP_MENU_TREE" "$ORIG_MENU_TREE" + flock -u "$WEBUI_LOCKFD" + + Say "${GRNct}$SCRIPT_NAME WebUI page unmounted successfully." + /sbin/service restart_httpd >/dev/null 2>&1 & + return 0 +} + +##----------------------------------------## +## Modified by Martinski W. [2025-Jan-12] ## +##----------------------------------------## +_AutoStartupHook_() +{ + local theScriptNameTag="#${SCRIPT_NAME}#" + local theHookScriptFile="${SCRIPTS_PATH}/services-start" + local theScriptFilePath="${SCRIPTS_PATH}/${SCRIPT_NAME}.sh" + + case "$1" in + create) + if [ -f "$theHookScriptFile" ] + then + theLineCount="$(grep -c "$theScriptNameTag" "$theHookScriptFile")" + theLineCountEx="$(grep -cx '\[ -x '"$theScriptFilePath"' \] && '"$theScriptFilePath"' startup "$@" & '"$theScriptNameTag" "$theHookScriptFile")" + + if [ "$theLineCount" -gt 1 ] || { [ "$theLineCountEx" -eq 0 ] && [ "$theLineCount" -gt 0 ] ; } + then + sed -i "/${theScriptNameTag}/d" "$theHookScriptFile" + fi + if [ "$theLineCountEx" -eq 0 ] + then + { + echo '[ -x '"$theScriptFilePath"' ] && '"$theScriptFilePath"' startup "$@" & '"$theScriptNameTag" + } >> "$theHookScriptFile" + fi + else + { + echo "#!/bin/sh" ; echo + echo '[ -x '"$theScriptFilePath"' ] && '"$theScriptFilePath"' startup "$@" & '"$theScriptNameTag" + echo + } > "$theHookScriptFile" + fi + chmod 755 "$theHookScriptFile" + ;; + delete) + if [ -f "$theHookScriptFile" ] && \ + { grep -q "$theScriptNameTag" "$theHookScriptFile" || \ + grep -q "$theScriptFilePath" "$theHookScriptFile" ; } + then + theFixedPath="$(echo "$theScriptFilePath" | sed 's/[\/.]/\\&/g')" + sed -i "/${theScriptNameTag}/d" "$theHookScriptFile" + sed -i "/$theFixedPath startup/d" "$theHookScriptFile" + fi + ;; + esac +} + +##----------------------------------------## +## Modified by Martinski W. [2025-Jan-12] ## +##----------------------------------------## +_AutoServiceEvent_() +{ + local theScriptNameTag="#${SCRIPT_NAME}#" + local theHookScriptFile="${SCRIPTS_PATH}/service-event" + local theScriptFilePath="${SCRIPTS_PATH}/${SCRIPT_NAME}.sh" + + case "$1" in + create) + if [ -f "$theHookScriptFile" ] + then + theLineCount="$(grep -c "$theScriptNameTag" "$theHookScriptFile")" + theLineCountEx="$(grep -cx 'if echo "$2" | /bin/grep -q "'"$SCRIPT_NAME"'" ; then { '"$theScriptFilePath"' service_event "$@" & }; fi '"$theScriptNameTag" "$theHookScriptFile")" + + if [ "$theLineCount" -gt 1 ] || { [ "$theLineCountEx" -eq 0 ] && [ "$theLineCount" -gt 0 ]; } + then + sed -i "/${theScriptNameTag}/d" "$theHookScriptFile" + fi + if [ "$theLineCountEx" -eq 0 ] + then + { + echo 'if echo "$2" | /bin/grep -q "'"$SCRIPT_NAME"'" ; then { '"$theScriptFilePath"' service_event "$@" & }; fi '"$theScriptNameTag" + } >> "$theHookScriptFile" + fi + else + { + echo "#!/bin/sh" ; echo + echo 'if echo "$2" | /bin/grep -q "'"$SCRIPT_NAME"'" ; then { '"$theScriptFilePath"' service_event "$@" & }; fi '"$theScriptNameTag" + echo + } > "$theHookScriptFile" + fi + chmod 755 "$theHookScriptFile" + ;; + delete) + if [ -f "$theHookScriptFile" ] && \ + { grep -q "$theScriptNameTag" "$theHookScriptFile" || \ + grep -q "$theScriptFilePath" "$theHookScriptFile" ; } + then + theFixedPath="$(echo "$theScriptFilePath" | sed 's/[\/.]/\\&/g')" + sed -i "/${theScriptNameTag}/d" "$theHookScriptFile" + sed -i "/$theFixedPath service_event/d" "$theHookScriptFile" + fi + ;; + esac +} + +##----------------------------------------## +## Modified by Martinski W. [2025-Jan-05] ## +##----------------------------------------## +_SetVersionSharedSettings_() +{ + if [ $# -eq 0 ] || [ -z "$1" ] || \ + ! echo "$1" | grep -qE "^(local|server|delete)$" + then return 1; fi + + if [ "$1" = "delete" ] + then + if [ -f "$SHARED_SETTINGS_FILE" ] + then + if grep -q "^MerlinAU_version_" "$SHARED_SETTINGS_FILE" + then + sed -i "/^MerlinAU_version_local/d" "$SHARED_SETTINGS_FILE" + sed -i "/^MerlinAU_version_server/d" "$SHARED_SETTINGS_FILE" + fi + fi + return 0 + fi + if [ $# -lt 2 ] || [ -z "$2" ] ; then return 1; fi + + local versionTypeStr="" + [ "$1" = "local" ] && versionTypeStr="MerlinAU_version_local" + [ "$1" = "server" ] && versionTypeStr="MerlinAU_version_server" + + if [ -f "$SHARED_SETTINGS_FILE" ] + then + if grep -q "^${versionTypeStr}.*" "$SHARED_SETTINGS_FILE" + then + if [ "$2" != "$(grep "^$versionTypeStr" "$SHARED_SETTINGS_FILE" | cut -f2 -d' ')" ] + then + sed -i "s/^${versionTypeStr}.*/$versionTypeStr $2/" "$SHARED_SETTINGS_FILE" + fi + else + echo "$versionTypeStr $2" >> "$SHARED_SETTINGS_FILE" + fi + else + echo "$versionTypeStr $2" > "$SHARED_SETTINGS_FILE" + fi + return 0 +} + +##----------------------------------------## +## Modified by Martinski W. [2025-Jan-20] ## +##----------------------------------------## +_CreateDirPaths_() +{ + if [ ! -d "$SETTINGS_DIR" ] + then + mkdir -p "$SETTINGS_DIR" + chmod 755 "$SETTINGS_DIR" + fi + ! "$inRouterSWmode" && return 0 + + if [ ! -d "$SCRIPT_WEB_DIR" ] + then + mkdir -p "$SCRIPT_WEB_DIR" + chmod 775 "$SCRIPT_WEB_DIR" + fi +} + +##----------------------------------------## +## Modified by Martinski W. [2025-Jan-20] ## +##----------------------------------------## +_CreateSymLinks_() +{ + if [ -d "$SCRIPT_WEB_DIR" ] + then + rm -rf "${SCRIPT_WEB_DIR:?}/"* 2>/dev/null + fi + ! "$inRouterSWmode" && return 0 + + ln -s "$CONFIG_FILE" "${SCRIPT_WEB_DIR}/config.htm" 2>/dev/null + ln -s "$HELPER_JSFILE" "${SCRIPT_WEB_DIR}/CheckHelper.js" 2>/dev/null +} + +##----------------------------------------## +## Modified by Martinski W. [2025-Feb-08] ## +##----------------------------------------## +_WriteVarDefToHelperJSFile_() +{ + if [ $# -lt 2 ] || [ -z "$1" ] || [ -z "$2" ] + then return 1; fi + + local varValue + if [ $# -eq 3 ] && [ "$3" = "true" ] + then varValue="$2" + else varValue="'${2}'" + fi + + if [ ! -s "$HELPER_JSFILE" ] + then + echo "var $1 = ${varValue};" > "$HELPER_JSFILE" + elif ! grep -q "^var $1 =.*" "$HELPER_JSFILE" + then + echo "var $1 = ${varValue};" >> "$HELPER_JSFILE" + elif ! grep -q "^var $1 = ${varValue};" "$HELPER_JSFILE" + then + sed -i "s/^var $1 =.*/var $1 = ${varValue};/" "$HELPER_JSFILE" + fi +} + +##-------------------------------------## +## Added by Martinski W. [2025-Jan-20] ## +##-------------------------------------## +_WebUI_AutoFWUpdateCheckCronSchedule_() +{ + ! "$inRouterSWmode" && return 0 + local fwUpdtCronScheduleRaw fwUpdtCronScheduleStr + fwUpdtCronScheduleRaw="$(Get_Custom_Setting FW_New_Update_Cron_Job_Schedule)" + fwUpdtCronScheduleStr="$(_TranslateCronSchedHR_ "$fwUpdtCronScheduleRaw")" + _WriteVarDefToHelperJSFile_ "fwAutoUpdateCheckCronSchedHR" "$fwUpdtCronScheduleStr" +} + +##-------------------------------------## +## Added by Martinski W. [2025-Jan-20] ## +##-------------------------------------## +_WebUI_AutoScriptUpdateCronSchedule_() +{ + ! "$inRouterSWmode" && return 0 + local scriptUpdtCronSchedRaw scriptUpdtCronSchedStr + scriptUpdtCronSchedRaw="$(_GetScriptAutoUpdateCronSchedule_)" + scriptUpdtCronSchedStr="$(_TranslateCronSchedHR_ "$scriptUpdtCronSchedRaw")" + _WriteVarDefToHelperJSFile_ "scriptAutoUpdateCronSchedHR" "$scriptUpdtCronSchedStr" +} + +##-------------------------------------## +## Added by Martinski W. [2025-Jan-27] ## +##-------------------------------------## +_WebUI_SetEmailConfigFileFromAMTM_() +{ + ! "$inRouterSWmode" && return 0 + _CheckEMailConfigFileFromAMTM_ 0 + _WriteVarDefToHelperJSFile_ "isEMailConfigEnabledInAMTM" "$isEMailConfigEnabledInAMTM" true +} + +##-------------------------------------## +## Added by Martinski W. [2025-Jan-15] ## +##-------------------------------------## +_ActionsAfterNewConfigSettings_() +{ + if [ ! -s "${CONFIG_FILE}.bak" ] || \ + diff -q "$CONFIG_FILE" "${CONFIG_FILE}.bak" >/dev/null 2>&1 + then return 1 ; fi + + _ConfigOptionChanged_() + { + if diff "$CONFIG_FILE" "${CONFIG_FILE}.bak" | grep -q "$1" + then return 0 + else return 1 + fi + } + local ccNewEmailAddr ccNewEmailName newScriptAUpdateVal + + if _ConfigOptionChanged_ "FW_New_Update_EMail_CC_Address=" + then + ccNewEmailAddr="$(Get_Custom_Setting FW_New_Update_EMail_CC_Address)" + ccNewEmailName="${ccNewEmailAddr%%@*}" + Update_Custom_Settings FW_New_Update_EMail_CC_Name "$ccNewEmailName" + fi + if _ConfigOptionChanged_ "FW_New_Update_Postponement_Days=" + then + _Calculate_NextRunTime_ + fi + if _ConfigOptionChanged_ "Allow_Script_Auto_Update" + then + ScriptAutoUpdateSetting="$(Get_Custom_Setting Allow_Script_Auto_Update)" + if [ "$ScriptAutoUpdateSetting" = "DISABLED" ] + then + _DelScriptAutoUpdateHook_ + _DelScriptAutoUpdateCronJob_ + elif [ "$ScriptAutoUpdateSetting" = "ENABLED" ] + then + scriptUpdateCronSched="$(_GetScriptAutoUpdateCronSchedule_)" + if _ValidateCronJobSchedule_ "$scriptUpdateCronSched" + then + _AddScriptAutoUpdateCronJob_ && _AddScriptAutoUpdateHook_ + fi + fi + fi + if _ConfigOptionChanged_ "CheckChangeLog" + then + currentChangelogValue="$(Get_Custom_Setting CheckChangeLog)" + if [ "$currentChangelogValue" = "DISABLED" ] + then + Delete_Custom_Settings "FW_New_Update_Changelog_Approval" + elif [ "$currentChangelogValue" = "ENABLED" ] + then + Update_Custom_Settings FW_New_Update_Changelog_Approval TBD + fi + fi +} + +##----------------------------------------## +## Modified by Martinski W. [2025-Jan-25] ## +##----------------------------------------## +_UpdateConfigFromWebUISettings_() +{ + [ ! -f "$SHARED_SETTINGS_FILE" ] && return 1 + + local settingsMergeOK=true logMsgTag="with errors." + + # Check for 'MerlinAU_' entries excluding 'version' # + if [ "$(grep "^MerlinAU_" "$SHARED_SETTINGS_FILE" | grep -vc "_version")" -gt 0 ] + then + Say "Updated settings from WebUI found, merging into $CONFIG_FILE" + cp -a "$CONFIG_FILE" "${CONFIG_FILE}.bak" + + # Extract 'MerlinAU_' entries excluding 'version' # + grep "^MerlinAU_" "$SHARED_SETTINGS_FILE" | grep -v "_version" > "$TEMPFILE" + sed -i 's/^MerlinAU_//g;s/ /=/g' "$TEMPFILE" + + while IFS='' read -r line || [ -n "$line" ] + do + keySettingName="$(echo "$line" | cut -f1 -d'=')" + keySettingValue="$(echo "$line" | cut -f2- -d'=')" + + if [ "$keySettingName" = "FW_New_Update_ZIP_Directory_Path" ] + then + if _Validate_FW_UpdateZIP_DirectoryPath_ "$keySettingValue" true + then + Say "Directory path [$keySettingValue] was updated successfully." + else + settingsMergeOK=false + Say "**ERROR**: Could NOT update directory path [$keySettingValue]" + fi + continue + elif [ "$keySettingName" = "FW_New_Update_LOG_Directory_Path" ] + then + if _Validate_FW_UpdateLOG_DirectoryPath_ "$keySettingValue" true + then + Say "Directory path [$keySettingValue] was updated successfully." + else + settingsMergeOK=false + Say "**ERROR**: Could NOT update directory path [$keySettingValue]" + fi + continue + fi + + if [ "$keySettingName" = "FW_New_Update_Cron_Job_Schedule" ] + then # Replace delimiter char placed by the WebGUI # + keySettingValue="$(echo "$keySettingValue" | sed 's/|/ /g')" + fi + Update_Custom_Settings "$keySettingName" "$keySettingValue" + done < "$TEMPFILE" + + # Extract 'MerlinAU_version_*' separately (if found) # + grep '^MerlinAU_version_.*' "$SHARED_SETTINGS_FILE" > "$TEMPFILE" + # Now remove all 'MerlinAU_*' entries # + sed -i "/^MerlinAU_.*/d" "$SHARED_SETTINGS_FILE" + + # Reconstruct the shared settings file # + mv -f "$SHARED_SETTINGS_FILE" "${SHARED_SETTINGS_FILE}.bak" + cat "${SHARED_SETTINGS_FILE}.bak" "$TEMPFILE" > "$SHARED_SETTINGS_FILE" + rm -f "$TEMPFILE" "${SHARED_SETTINGS_FILE}.bak" + + _ActionsAfterNewConfigSettings_ + + "$settingsMergeOK" && logMsgTag="successfully." + Say "Merge of updated settings from WebUI was completed ${logMsgTag}" + + if ! "$settingsMergeOK" + then ## Reset for Next Check ## + { sleep 15 ; _UpdateHelperJSFile_ "$extCheckALLvarID" "true" ; } & + fi + else + Say "No updated settings from WebUI found. No merge into $CONFIG_FILE necessary." + fi + return 0 +} + ##-------------------------------------## ## Added by Martinski W. [2024-Dec-31] ## ##-------------------------------------## @@ -1542,38 +2465,80 @@ _CurlFileDownload_() "$srceFilePathDL" -o "$tempFilePathDL" if [ $? -ne 0 ] || [ ! -s "$tempFilePathDL" ] || \ grep -iq "^404: Not Found" "$tempFilePathDL" - then rm -f "$tempFilePathDL" ; retCode=1 - else mv -f "$tempFilePathDL" "$2" ; retCode=0 + then + rm -f "$tempFilePathDL" + retCode=1 + else + if [ "$1" = "$SCRIPT_WEB_ASP_FILE" ] && \ + [ -f "$2" ] && [ -f "$TEMP_MENU_TREE" ] && \ + ! diff -q "$tempFilePathDL" "$2" >/dev/null 2>&1 + then updatedWebUIPage=true + else updatedWebUIPage=false + fi + mv -f "$tempFilePathDL" "$2" + retCode=0 fi + return "$retCode" } ##----------------------------------------## ## Modified by Martinski W. [2025-Feb-15] ## ##----------------------------------------## -_SCRIPTUPDATE_() +_DownloadScriptFiles_() { - local extraParam="" + local retCode isUpdateAction updatedWebUIPage theWebPage - _DownloadScriptFiles_() - { - local retCode - if _CurlFileDownload_ "version.txt" "$SCRIPTVERPATH" - then - retCode=0 ; chmod 664 "$SCRIPTVERPATH" - else - retCode=1 - Say "${REDct}**ERROR**${NOct}: Unable to download latest version file for $SCRIPT_NAME." - fi - if _CurlFileDownload_ "${SCRIPT_NAME}.sh" "$ScriptFilePath" - then - retCode=0 ; chmod 755 "$ScriptFilePath" - else - retCode=1 - Say "${REDct}**ERROR**${NOct}: Unable to download latest script file for $SCRIPT_NAME." - fi - return "$retCode" - } + if [ $# -gt 0 ] && [ "$1" = "update" ] + then isUpdateAction=true + else isUpdateAction=false + fi + updatedWebUIPage=false + + if _CurlFileDownload_ "version.txt" "$SCRIPT_VERPATH" + then + retCode=0 ; chmod 664 "$SCRIPT_VERPATH" + else + retCode=1 + Say "${REDct}**ERROR**${NOct}: Unable to download latest version file for $SCRIPT_NAME." + fi + if "$inRouterSWmode" && \ + _CurlFileDownload_ "$SCRIPT_WEB_ASP_FILE" "$SCRIPT_WEB_ASP_PATH" + then + chmod 664 "$SCRIPT_WEB_ASP_PATH" + if "$updatedWebUIPage" + then + theWebPage="$(_GetWebUIPage_ "$SCRIPT_WEB_ASP_PATH")" + if [ -n "$theWebPage" ] && [ "$theWebPage" != "NONE" ] + then + sed -i "/url: \"$theWebPage\", tabName: \"$SCRIPT_NAME\"/d" "$TEMP_MENU_TREE" + rm -f "${SHARED_WEB_DIR}/$theWebPage" + rm -f "${SHARED_WEB_DIR}/$(echo "$theWebPage" | cut -f1 -d'.').title" + fi + "$isUpdateAction" && _Mount_WebUI_ + fi + retCode=0 + elif "$inRouterSWmode" + then + retCode=1 + Say "${REDct}**ERROR**${NOct}: Unable to download latest WebUI ASP file for $SCRIPT_NAME." + fi + if _CurlFileDownload_ "${SCRIPT_NAME}.sh" "$ScriptFilePath" + then + retCode=0 ; chmod 755 "$ScriptFilePath" + else + retCode=1 + Say "${REDct}**ERROR**${NOct}: Unable to download latest script file for $SCRIPT_NAME." + fi + return "$retCode" +} + +##----------------------------------------## +## Modified by Martinski W. [2025-Feb-15] ## +##----------------------------------------## +_SCRIPT_UPDATE_() +{ + local extraParam="" if [ $# -gt 0 ] && [ "$1" = "force" ] then @@ -1587,9 +2552,14 @@ _SCRIPTUPDATE_() fi printf "${CYANct}Downloading latest version [$DLRepoVersion] of ${SCRIPT_NAME}${NOct}\n" - if _DownloadScriptFiles_ + if _DownloadScriptFiles_ update then - printf "${CYANct}$SCRIPT_NAME was successfully updated.${NOct}\n\n" + printf "${CYANct}$SCRIPT_NAME files were successfully updated.${NOct}\n\n" + if "$inRouterSWmode" + then + _SetVersionSharedSettings_ local "$DLRepoVersion" + _SetVersionSharedSettings_ server "$DLRepoVersion" + fi sleep 1 _ReleaseLock_ exec "$ScriptFilePath" $extraParam @@ -1601,11 +2571,15 @@ _SCRIPTUPDATE_() ! _CheckForNewScriptUpdates_ && return 1 clear - logo + _ShowLogo_ + printf "\n${YLWct}Script Update Utility${NOct}\n\n" printf "${CYANct}Version Currently Installed: ${YLWct}${SCRIPT_VERSION}${NOct}\n" printf "${CYANct}Update Version Available Now: ${YLWct}${DLRepoVersion}${NOct}\n\n" + if "$inRouterSWmode" + then _SetVersionSharedSettings_ server "$DLRepoVersion" ; fi + if [ "$SCRIPT_VERSION" = "$DLRepoVersion" ] then echo -e "${CYANct}You are on the latest version! Would you like to download anyways?${NOct}" @@ -1614,8 +2588,10 @@ _SCRIPTUPDATE_() then printf "\n\n${CYANct}Downloading $SCRIPT_NAME $DLRepoVersion version.${NOct}\n" - if _DownloadScriptFiles_ + if _DownloadScriptFiles_ update then + if "$inRouterSWmode" + then _SetVersionSharedSettings_ local "$DLRepoVersion" ; fi printf "\n${CYANct}Download successful!${NOct}\n" printf "$(date) - Successfully downloaded $SCRIPT_NAME v${DLRepoVersion}\n" fi @@ -1633,8 +2609,10 @@ _SCRIPTUPDATE_() then printf "\n\n${CYANct}Downloading $SCRIPT_NAME $DLRepoVersion version.${NOct}\n" - if _DownloadScriptFiles_ + if _DownloadScriptFiles_ update then + if "$inRouterSWmode" + then _SetVersionSharedSettings_ local "$DLRepoVersion" ; fi printf "\n$(date) - Successfully downloaded $SCRIPT_NAME v${DLRepoVersion}\n" printf "${CYANct}Update successful! Restarting script...${NOct}\n" sleep 1 @@ -1661,17 +2639,17 @@ _CheckForNewScriptUpdates_() { echo DLRepoVersion="$SCRIPT_VERSION" - [ -s "$SCRIPTVERPATH" ] && DLRepoVersion="$(cat "$SCRIPTVERPATH")" - rm -f "$SCRIPTVERPATH" + [ -s "$SCRIPT_VERPATH" ] && DLRepoVersion="$(cat "$SCRIPT_VERPATH")" + rm -f "$SCRIPT_VERPATH" - if ! _CurlFileDownload_ "version.txt" "$SCRIPTVERPATH" + if ! _CurlFileDownload_ "version.txt" "$SCRIPT_VERPATH" then Say "${REDct}**ERROR**${NOct}: Unable to download latest version file for $SCRIPT_NAME." scriptUpdateNotify=0 return 1 fi - DLRepoVersion="$(cat "$SCRIPTVERPATH")" + DLRepoVersion="$(cat "$SCRIPT_VERPATH")" if [ -z "$DLRepoVersion" ] then Say "${REDct}**ERROR**${NOct}: Variable for downloaded version is empty." @@ -1693,7 +2671,7 @@ ${REDct}v${SCRIPT_VERSION}${NOct} --> ${GRNct}v${DLRepoVersion}${NOct}" Say "$myLAN_HostName - A new script version update (v$DLRepoVersion) is available to download." if [ "$ScriptAutoUpdateSetting" = "ENABLED" ] then - _SCRIPTUPDATE_ force + _SCRIPT_UPDATE_ force fi else scriptUpdateNotify=0 @@ -1723,7 +2701,7 @@ _GetLatestFWUpdateVersionFromRouter_() } ##------------------------------------------## -## Modified by ExtremeFiretop [2024-Nov-26] ## +## Modified by ExtremeFiretop [2024-Dec-28] ## ##------------------------------------------## _CreateEMailContent_() { @@ -1799,7 +2777,7 @@ _CreateEMailContent_() ;; STOP_FW_UPDATE_APPROVAL) emailBodyTitle="WARNING" - if $isEMailFormatHTML + if "$isEMailFormatHTML" then # Highlight high-risk terms using HTML with a yellow background # highlighted_changelog_contents="$(echo "$changelog_contents" | sed -E "s/($high_risk_terms)/\1<\/span>/gi")" @@ -1984,7 +2962,7 @@ EOF } ##----------------------------------------## -## Modified by Martinski W. [2024-Feb-16] ## +## Modified by Martinski W. [2025-Jan-10] ## ##----------------------------------------## _CheckEMailConfigFileFromAMTM_() { @@ -2023,6 +3001,15 @@ _CheckEMailConfigFileFromAMTM_() return 1 fi + sendEMail_CC_Name="$(Get_Custom_Setting FW_New_Update_EMail_CC_Name)" + sendEMail_CC_Address="$(Get_Custom_Setting FW_New_Update_EMail_CC_Address)" + sendEMailNotificationsFlag="$(Get_Custom_Setting FW_New_Update_EMail_Notification)" + sendEMailFormaType="$(Get_Custom_Setting FW_New_Update_EMail_FormatType)" + if [ "$sendEMailFormaType" = "HTML" ] + then isEMailFormatHTML=true + else isEMailFormatHTML=false + fi + if [ -n "$sendEMail_CC_Name" ] && [ "$sendEMail_CC_Name" != "TBD" ] && \ [ -n "$sendEMail_CC_Address" ] && [ "$sendEMail_CC_Address" != "TBD" ] then @@ -2034,13 +3021,13 @@ _CheckEMailConfigFileFromAMTM_() return 0 } -##----------------------------------------## -## Modified by Martinski W. [2024-Jun-05] ## -##----------------------------------------## +##------------------------------------------## +## Modified by ExtremeFiretop [2024-Dec-21] ## +##------------------------------------------## _SendEMailNotification_() { if [ $# -eq 0 ] || [ -z "$1" ] || \ - ! "$sendEMailNotificationsFlag" || \ + [ "$sendEMailNotificationsFlag" != "ENABLED" ] || \ ! _CheckEMailConfigFileFromAMTM_ 1 then return 1 ; fi @@ -2507,9 +3494,9 @@ check_memory_and_prompt_reboot() } ##----------------------------------------## -## Modified by Martinski W. [2024-May-31] ## +## Modified by Martinski W. [2025-Jan-05] ## ##----------------------------------------## -check_version_support() +_CheckForMinimumVersionSupport_() { local numOfFields current_version numCurrentVers numMinimumVers current_version="$(_GetCurrentFWInstalledLongVersion_)" @@ -2518,25 +3505,28 @@ check_version_support() numCurrentVers="$(_FWVersionStrToNum_ "$current_version" "$numOfFields")" numMinimumVers="$(_FWVersionStrToNum_ "$MinSupportedFirmwareVers" "$numOfFields")" - # If the current firmware version is lower than the minimum supported firmware version, exit. + # Check if current F/W version is lower than the minimum supported version # if [ "$numCurrentVers" -lt "$numMinimumVers" ] then MinFirmwareVerCheckFailed=true ; fi + + "$MinFirmwareVerCheckFailed" && return 1 || return 0 } -##------------------------------------------## -## Modified by ExtremeFiretop [2024-Oct-19] ## -##------------------------------------------## -check_model_support() +##----------------------------------------## +## Modified by Martinski W. [2025-Jan-05] ## +##----------------------------------------## +_CheckForMinimumModelSupport_() { # List of unsupported models as a space-separated string local unsupported_models="RT-AC87U RT-AC56U RT-AC66U RT-AC3200 RT-AC88U RT-AC5300 RT-AC3100 RT-AC68U RT-AC66U_B1 RT-AC68UF RT-AC68P RT-AC1900P RT-AC1900 RT-N66U RT-N16 DSL-AC68U" - # Get the current model local current_model="$(_GetRouterProductID_)" - # Check if the current model is in the list of unsupported models # + # Check if current model is in the list of unsupported models # if echo "$unsupported_models" | grep -wq "$current_model" then routerModelCheckFailed=true ; fi + + "$routerModelCheckFailed" && return 1 || return 0 } ##----------------------------------------## @@ -2595,40 +3585,116 @@ _GetRawKeypress_() stty "$savedSettings" } +##-------------------------------------## +## Added by Martinski W. [2025-Jan-10] ## +##-------------------------------------## +_OfflineKeySeqHandler_() +{ + if [ $# -lt 3 ] || [ -z "$1" ] || \ + [ -z "$2" ] || [ -z "$3" ] + then return 1 ; fi + + local retCode=1 + local offlineKeySeqNum="27251624" offlineKeySeqCnt=4 + + case "$3" in + FOUNDOK) + if [ "$1" -eq "$offlineKeySeqCnt" ] && \ + [ "$2" -eq "$offlineKeySeqNum" ] + then retCode=0 + else retCode=1 + fi + ;; + NOTFOUND) + if [ "$1" -gt 4 ] || \ + { [ "$1" -eq "$offlineKeySeqCnt" ] && \ + [ "$2" -ne "$offlineKeySeqNum" ] ; } + then retCode=0 + else retCode=1 + fi + ;; + *) retCode=1 ;; + esac + + return "$retCode" +} + +##-------------------------------------## +## Added by Martinski W. [2025-Jan-10] ## +##-------------------------------------## +_SetReloadKeySeqHandler_() +{ + if [ $# -lt 3 ] || [ -z "$1" ] || \ + [ -z "$2" ] || [ -z "$3" ] + then return 1 ; fi + + local retCode=1 + local setReloadKeySeqNum="1812" setReloadKeySeqCnt=2 + + case "$3" in + FOUNDOK) + if [ "$1" -eq "$setReloadKeySeqCnt" ] && \ + [ "$2" -eq "$setReloadKeySeqNum" ] + then retCode=0 + else retCode=1 + fi + ;; + NOTFOUND) + if [ "$1" -gt 4 ] || \ + { [ "$1" -eq "$setReloadKeySeqCnt" ] && \ + [ "$2" -ne "$setReloadKeySeqNum" ] ; } + then retCode=0 + else retCode=1 + fi + ;; + *) retCode=1 ;; + esac + + return "$retCode" +} + ##----------------------------------------## -## Modified by Martinski W. [2024-Jul-31] ## +## Modified by Martinski W. [2025-Jan-10] ## ##----------------------------------------## _GetKeypressInput_() { local inputStrLenMAX=16 inputString promptStr local charNum inputStrLen keypressCount - local theKeySeqCnt maxKeySeqCnt=4 retCode - local theKeySeqNum maxKeySeqNum="27251624" - local offlineModeFlag=false + local theKeySeqCnt theKeySeqNum retCode + local offlineUpdKeyFlag execReloadKeyFlag + + if [ -n "${offlineUpdTrigger:+xSETx}" ] + then + offlineUpdKeyFlag=true + offlineUpdTrigger=false + else + offlineUpdKeyFlag=false + unset offlineUpdTrigger + fi - if [ -n "${offlineUpdateFlag:+xSETx}" ] - then offlineModeFlag=true ; fi + if [ -n "${execReloadTrigger:+xSETx}" ] + then + execReloadKeyFlag=true + execReloadTrigger=false + else + execReloadKeyFlag=false + unset execReloadTrigger + fi if [ $# -eq 0 ] || [ -z "$1" ] then printf "\n**ERROR**: NO prompt string was provided.\n" return 1 fi - promptStr="$1" _ShowInputString_() { printf "\r\033[0K${promptStr} %s" "$inputString" ; } _ClearKeySeqState_() - { - theKeySeqNum=0 ; theKeySeqCnt=0 - if "$offlineModeFlag" - then offlineUpdateFlag=false - else unset offlineUpdateFlag - fi - } + { theKeySeqNum=0 ; theKeySeqCnt=0 ; } charNum="" + promptStr="$1" inputString="" inputStrLen=0 keypressCount=0 @@ -2686,26 +3752,37 @@ _GetKeypressInput_() continue fi - # Non-Printable ASCII Codes ## - if "$offlineModeFlag" && [ "$charNum" -gt 0 ] && [ "$charNum" -lt 32 ] + ## Non-Printable ASCII Codes ## + if [ "$charNum" -gt 0 ] && [ "$charNum" -lt 32 ] && \ + { "$offlineUpdKeyFlag" || "$execReloadKeyFlag" ; } then - offlineUpdateFlag=false + "$offlineUpdKeyFlag" && offlineUpdTrigger=false + "$execReloadKeyFlag" && execReloadTrigger=false + theKeySeqCnt="$((theKeySeqCnt + 1))" if [ "$theKeySeqCnt" -eq 1 ] then theKeySeqNum="$charNum" else theKeySeqNum="${theKeySeqNum}${charNum}" fi - if [ "$theKeySeqCnt" -eq "$maxKeySeqCnt" ] && \ - [ "$theKeySeqNum" -eq "$maxKeySeqNum" ] + if "$offlineUpdKeyFlag" && \ + _OfflineKeySeqHandler_ "$theKeySeqCnt" "$theKeySeqNum" FOUNDOK then _ClearKeySeqState_ if [ "$inputString" = "offline" ] - then offlineUpdateFlag=true ; fi + then offlineUpdTrigger=true ; fi + continue + fi + if "$execReloadKeyFlag" && \ + _SetReloadKeySeqHandler_ "$theKeySeqCnt" "$theKeySeqNum" FOUNDOK + then + _ClearKeySeqState_ + execReloadTrigger=true continue fi - if [ "$theKeySeqCnt" -gt "$maxKeySeqCnt" ] || \ - { [ "$theKeySeqCnt" -eq "$maxKeySeqCnt" ] && \ - [ "$theKeySeqNum" -ne "$maxKeySeqNum" ] ; } + if { "$offlineUpdKeyFlag" && \ + _OfflineKeySeqHandler_ "$theKeySeqCnt" "$theKeySeqNum" NOTFOUND ; } && \ + { "$execReloadKeyFlag" && \ + _SetReloadKeySeqHandler_ "$theKeySeqCnt" "$theKeySeqNum" NOTFOUND ; } then _ClearKeySeqState_ ; fi else _ClearKeySeqState_ @@ -2714,7 +3791,7 @@ _GetKeypressInput_() IFS="$savedIFS" theUserInputStr="$inputString" - return "$retCode" + echo ; return "$retCode" } ##----------------------------------------## @@ -2722,7 +3799,7 @@ _GetKeypressInput_() ##----------------------------------------## _GetPasswordInput_() { - local PSWDstrLenMIN=1 PSWDstrLenMAX=64 + local PSWDstrLenMIN=5 PSWDstrLenMAX=64 local newPSWDstring newPSWDtmpStr PSWDprompt local retCode charNum newPSWDlength showPSWD # For more responsive TAB keypress debounce # @@ -2996,7 +4073,6 @@ _GetLoginCredentials_() # Encode the Username and Password in Base64 # loginCredsENC="$(echo -n "${userName}:${thePWSDstring}" | openssl base64 -A)" - # Save the credentials to the SETTINGSFILE # Update_Custom_Settings credentials_base64 "$loginCredsENC" if [ "$thePWSDstring" != "$oldPWSDstring" ] @@ -3693,7 +4769,7 @@ _toggle_change_log_check_() if _WaitForYESorNO_ "\nProceed to ${REDct}DISABLE${NOct}?" then Update_Custom_Settings "CheckChangeLog" "DISABLED" - Update_Custom_Settings "FW_New_Update_Changelog_Approval" "TBD" + Delete_Custom_Settings "FW_New_Update_Changelog_Approval" printf "Changelog verification check is now ${REDct}DISABLED.${NOct}\n" else printf "Changelog verification check remains ${GRNct}ENABLED.${NOct}\n" @@ -3703,6 +4779,7 @@ _toggle_change_log_check_() if _WaitForYESorNO_ "\nProceed to ${GRNct}ENABLE${NOct}?" then Update_Custom_Settings "CheckChangeLog" "ENABLED" + Update_Custom_Settings "FW_New_Update_Changelog_Approval" "TBD" printf "Changelog verification check is now ${GRNct}ENABLED.${NOct}\n" else printf "Changelog verification check remains ${REDct}DISABLED.${NOct}\n" @@ -3822,18 +4899,18 @@ _ChangeBuildType_TUF_() # Use Get_Custom_Setting to retrieve the previous choice previous_choice="$(Get_Custom_Setting "TUFBuild")" - # If the previous choice is not set, default to 'n' # + # If the previous choice is not set, default to 'DISABLED' # if [ "$previous_choice" = "TBD" ]; then - previous_choice="n" + previous_choice="DISABLED" fi # Convert previous choice to a descriptive text # - if [ "$previous_choice" = "y" ]; then + if [ "$previous_choice" = "ENABLED" ]; then display_choice="TUF Build" else display_choice="Pure Build" fi - printf "\n\nCurrent Build Type: ${GRNct}${display_choice}${NOct}.\n" + printf "\nCurrent Build Type: ${GRNct}${display_choice}${NOct}.\n" doReturnToMenu=false while true @@ -3841,7 +4918,7 @@ _ChangeBuildType_TUF_() printf "\n${SEPstr}" printf "\nChoose your preferred option for the build type to flash:\n" printf "\n ${GRNct}1${NOct}. Original ${REDct}TUF${NOct} themed user interface" - printf "\n ${REDct}(Applies only if TUF F/W is available; otherwise, defaults to Pure build)${NOct}\n" + printf "\n ${REDct}(Applies only if TUF F/W is available)${NOct}\n" printf "\n ${GRNct}2${NOct}. Pure ${GRNct}Non-TUF${NOct} themed user interface" printf "\n ${GRNct}(Recommended)${NOct}\n" printf "\n ${GRNct}e${NOct}. Exit to Advanced Menu\n" @@ -3853,13 +4930,13 @@ _ChangeBuildType_TUF_() then doReturnToMenu=true ; break ; fi case $choice in - 1) buildtypechoice="y" + 1) buildtypechoice="ENABLED" printf "\n${InvBYLWct} NOTE: ${NOct}\n" printf "${CYANct}The TUF build will apply only if a compatible TUF firmware image is available." - printf "\nOtherwise, the Pure ${GRNct}Non-TUF${NOct}${CYANct} build will be used instead.${NOct}\n" + printf " Otherwise, the Pure ${GRNct}Non-TUF${NOct}${CYANct} build will be used instead.${NOct}\n" break ;; - 2) buildtypechoice="n" ; break + 2) buildtypechoice="DISABLED" ; break ;; *) echo ; _InvalidMenuSelection_ ;; @@ -3884,18 +4961,18 @@ _ChangeBuildType_ROG_() # Use Get_Custom_Setting to retrieve the previous choice previous_choice="$(Get_Custom_Setting "ROGBuild")" - # If the previous choice is not set, default to 'n' # + # If the previous choice is not set, default to 'DISABLED' # if [ "$previous_choice" = "TBD" ]; then - previous_choice="n" + previous_choice="DISABLED" fi # Convert previous choice to a descriptive text # - if [ "$previous_choice" = "y" ]; then + if [ "$previous_choice" = "ENABLED" ]; then display_choice="ROG Build" else display_choice="Pure Build" fi - printf "\n\nCurrent Build Type: ${GRNct}${display_choice}${NOct}.\n" + printf "\nCurrent Build Type: ${GRNct}${display_choice}${NOct}.\n" doReturnToMenu=false while true @@ -3903,7 +4980,7 @@ _ChangeBuildType_ROG_() printf "\n${SEPstr}" printf "\nChoose your preferred option for the build type to flash:\n" printf "\n ${GRNct}1${NOct}. Original ${REDct}ROG${NOct} themed user interface" - printf "\n ${REDct}(Applies only if ROG F/W is available; otherwise, defaults to Pure build)${NOct}\n" + printf "\n ${REDct}(Applies only if ROG F/W is available)${NOct}\n" printf "\n ${GRNct}2${NOct}. Pure ${GRNct}Non-ROG${NOct} themed user interface" printf "\n ${GRNct}(Recommended)${NOct}\n" printf "\n ${GRNct}e${NOct}. Exit to Advanced Menu\n" @@ -3915,13 +4992,13 @@ _ChangeBuildType_ROG_() then doReturnToMenu=true ; break ; fi case $choice in - 1) buildtypechoice="y" + 1) buildtypechoice="ENABLED" printf "\n${InvBYLWct} NOTE: ${NOct}\n" printf "${CYANct}The ROG build will apply only if a compatible ROG firmware image is available." - printf "\nOtherwise, the Pure ${GRNct}Non-ROG${NOct}${CYANct} build will be used instead.${NOct}\n" + printf " Otherwise, the Pure ${GRNct}Non-ROG${NOct}${CYANct} build will be used instead.${NOct}\n" break ;; - 2) buildtypechoice="n" ; break + 2) buildtypechoice="DISABLED" ; break ;; *) echo ; _InvalidMenuSelection_ ;; @@ -4599,19 +5676,13 @@ _GetScriptAutoUpdateCronSchedule_() } ##----------------------------------------## -## Modified by Martinski W. [2024-Nov-24] ## +## Modified by Martinski W. [2025-Feb-21] ## ##----------------------------------------## _AddScriptAutoUpdateCronJob_() { - local newSchedule newSetting retCode=1 - if [ $# -gt 0 ] && [ -n "$1" ] - then - newSetting=true - newSchedule="$1" - else - newSetting=false - newSchedule="$(_GetScriptAutoUpdateCronSchedule_)" - fi + local newSchedule retCode=1 + + newSchedule="$(_GetScriptAutoUpdateCronSchedule_)" if [ -z "$newSchedule" ] || [ "$newSchedule" = "TBD" ] then newSchedule="$ScriptAU_CRON_DefaultSchedule" @@ -4711,9 +5782,9 @@ _Set_FW_UpdatePostponementDays_() return 0 } -##-------------------------------------## -## Added by Martinski W. [2024-Nov-24] ## -##-------------------------------------## +##----------------------------------------## +## Modified by Martinski W. [2025-Jan-22] ## +##----------------------------------------## _TranslateCronSchedHR_() { if [ $# -eq 0 ] || [ -z "$1" ] @@ -4760,30 +5831,30 @@ _TranslateCronSchedHR_() if [ "$theCronDAYW" = "*" ] && [ "$theCronDAYM" = "*" ] then - infoStrDAYS="every day, in every month" + infoStrDAYS="every day, every month" elif [ "$theCronDAYW" != "*" ] then if echo "$theCronDAYW" | grep -qE "^[*]/.*" then freqNumDAYW="$(echo "$theCronDAYW" | cut -f2 -d'/')" - infoStrDAYS="every $freqNumDAYW days of the week, in every month" + infoStrDAYS="every $freqNumDAYW days of the week, every month" elif echo "$theCronDAYW" | grep -qE "[,-]" then - infoStrDAYS="days ${theCronDAYW}, in every month" + infoStrDAYS="on ${theCronDAYW}, every month" else - infoStrDAYS="day ${theCronDAYW}, in every month" + infoStrDAYS="on ${theCronDAYW}, every month" fi elif [ "$theCronDAYM" != "*" ] then if echo "$theCronDAYM" | grep -qE "^[*]/.*" then freqNumDAYM="$(echo "$theCronDAYM" | cut -f2 -d'/')" - infoStrDAYS="every $freqNumDAYM days of the month, in every month" + infoStrDAYS="every $freqNumDAYM days of the month, every month" elif echo "$theCronDAYM" | grep -qE "[,-]" then - infoStrDAYS="days ${theCronDAYM} of the month, in every month" + infoStrDAYS="days ${theCronDAYM} of the month, every month" else - infoStrDAYS="day ${theCronDAYM} of the month, in every month" + infoStrDAYS="day ${theCronDAYM} of the month, every month" fi fi @@ -5176,7 +6247,7 @@ _CheckForReturnToBeginMenu_() _ShowCronMenuHeader_() { clear - logo + _ShowLogo_ printf "================ F/W Update Check Schedule ===============\n" printf "${SEPstr}\n" } @@ -5407,7 +6478,7 @@ _Set_FW_UpdateCronScheduleGuided_() cronSchedDAYM="$(echo "$currCronSched" | awk -F ' ' '{print $3}')" cronSchedDAYW="$(echo "$currCronSched" | awk -F ' ' '{print $5}')" - ## MONTH is FIXED to "every month" for F/W Update Purposes ## + ## MONTH is FIXED to "Every Month" for F/W Update Purposes ## cronSchedMNTH="*" ; nextSchedMNTH="*" _ClearCronSchedValues_() @@ -5607,7 +6678,7 @@ _Set_FW_AutoUpdateCronSchedule_() } ##----------------------------------------## -## Modified by Martinski W. [2024-Nov-26] ## +## Modified by Martinski W. [2025-Feb-18] ## ##----------------------------------------## _Toggle_ScriptAutoUpdate_Config_() { @@ -5618,25 +6689,26 @@ _Toggle_ScriptAutoUpdate_Config_() if [ "$currentSetting" = "DISABLED" ] then - printf "\n${REDct}*NOTICE*${NOct}\n" + printf "\n${InvMGNct} *NOTICE* ${NOct}\n" printf "Enabling this feature allows the MerlinAU script to self-update automatically\n" printf "without user action when a newer version becomes available. This means both the\n" printf "script and the firmware updates become fully automatic. Proceed with caution.\n" printf "The recommendation is to always read the changelogs on SNBForums or Github.\n" - if _WaitForYESorNO_ "\nProceed to ${MAGENTAct}ENABLE${NOct}?" + if _WaitForYESorNO_ "\nProceed to ${MGNTct}ENABLE${NOct}?" then scriptUpdateCronSched="$(_GetScriptAutoUpdateCronSchedule_)" cronSchedStrHR="$(_TranslateCronSchedHR_ "$scriptUpdateCronSched")" printf "\nCurrent Schedule: ${GRNct}${scriptUpdateCronSched}${NOct}\n" printf "[${GRNct}${cronSchedStrHR}${NOct}]\n" - if _WaitForYESorNO_ "\nConfirm the above schedule to check for automatic script updates?" + printf "\n${BOLDct}Confirm the above schedule to check for automatic script updates${NOct}" + if _WaitForYESorNO_ YES then if _ValidateCronJobSchedule_ "$scriptUpdateCronSched" then Update_Custom_Settings "Allow_Script_Auto_Update" "ENABLED" - printf "MerlinAU automatic script updates are now ${MAGENTAct}ENABLED${NOct}.\n" + printf "MerlinAU automatic script updates are now ${MGNTct}ENABLED${NOct}.\n" printf "Adding '${GRNct}${SCRIPT_UP_CRON_JOB_TAG}${NOct}' cron job for automatic script updates...\n" if _AddScriptAutoUpdateCronJob_ then @@ -5659,13 +6731,13 @@ _Toggle_ScriptAutoUpdate_Config_() retCode=1 ; keepOptionDisabled=true fi else - printf "\n${REDct}*NOTICE*${NOct}\n" + printf "\n${InvREDct} *NOTICE* ${NOct}\n" printf "Disabling this feature will require user action to update the MerlinAU script\n" printf "when a newer version becomes available. This is the default setting.\n" - if _WaitForYESorNO_ "\nProceed to ${GRNct}DISABLE${NOct}?" + if _WaitForYESorNO_ "\nProceed to ${MGNTct}DISABLE${NOct}?" then Update_Custom_Settings "Allow_Script_Auto_Update" "DISABLED" - printf "MerlinAU automatic script updates are now ${GRNct}DISABLED${NOct}.\n" + printf "MerlinAU automatic script updates are now ${MGNTct}DISABLED${NOct}.\n" printf "Removing '${GRNct}${SCRIPT_UP_CRON_JOB_TAG}${NOct}' cron job for automatic script updates...\n" _DelScriptAutoUpdateHook_ if _DelScriptAutoUpdateCronJob_ @@ -5677,13 +6749,13 @@ _Toggle_ScriptAutoUpdate_Config_() # Error message is printed within function call # fi else - printf "MerlinAU automatic script updates remain ${MAGENTAct}ENABLED${NOct}.\n" + printf "MerlinAU automatic script updates remain ${MGNTct}ENABLED${NOct}.\n" fi fi if "$keepOptionDisabled" then - printf "MerlinAU automatic script updates remain ${GRNct}DISABLED.${NOct}\n" + printf "MerlinAU automatic script updates remain ${MGNTct}DISABLED.${NOct}\n" fi _WaitForEnterKey_ return "$retCode" @@ -6197,7 +7269,7 @@ _CheckNodeFWUpdateNotification_() } ##----------------------------------------## -## Modified by Martinski W. [2024-May-18] ## +## Modified by Martinski W. [2025-Jan-22] ## ##----------------------------------------## _CheckTimeToUpdateFirmware_() { @@ -6236,25 +7308,24 @@ _CheckTimeToUpdateFirmware_() upfwDateTimeStrn="$(date -d @$upfwDateTimeSecs +"%A, %Y-%b-%d %I:%M %p")" Say "The firmware update is expected to occur on or after ${GRNct}${upfwDateTimeStrn}${NOct}, depending on when your cron job is scheduled to check again." return 1 + else + Say "The firmware update is expected to occur on ${GRNct}${nextCronTimeSecs}${NOct}." fi - Say "The firmware update is expected to occur on ${GRNct}${nextCronTimeSecs}${NOct}." - echo "" - "$isInteractive" && \ printf "\n${BOLDct}Would you like to proceed with the update now${NOct}" - if _WaitForYESorNO_ + if _WaitForYESorNO_ "$("$bypassPostponedDays" && echo YES || echo NO)" then return 0 else return 1 fi } -##-------------------------------------## -## Added by Martinski W. [2024-Feb-16] ## -##-------------------------------------## +##------------------------------------------## +## Modified by ExtremeFiretop [2024-Dec-21] ## +##------------------------------------------## _RunEMailNotificationTest_() { - ! "$sendEMailNotificationsFlag" && return 1 + [ "$sendEMailNotificationsFlag" != "ENABLED" ] && return 1 local retCode=1 if _WaitForYESorNO_ "\nWould you like to run a test of the email notification?" @@ -6265,19 +7336,19 @@ _RunEMailNotificationTest_() return "$retCode" } -##----------------------------------------## -## Modified by Martinski W. [2024-Feb-16] ## -##----------------------------------------## +##------------------------------------------## +## Modified by ExtremeFiretop [2024-Dec-21] ## +##------------------------------------------## _Toggle_FW_UpdateEmailNotifications_() { local emailNotificationEnabled emailNotificationNewStateStr - if "$sendEMailNotificationsFlag" + if [ "$sendEMailNotificationsFlag" = "ENABLED" ] then - emailNotificationEnabled=true + emailNotificationEnabled="ENABLED" emailNotificationNewStateStr="${REDct}DISABLE${NOct}" else - emailNotificationEnabled=false + emailNotificationEnabled="DISABLED" emailNotificationNewStateStr="${GRNct}ENABLE${NOct}" fi @@ -6287,12 +7358,12 @@ _Toggle_FW_UpdateEmailNotifications_() return 1 fi - if "$emailNotificationEnabled" + if [ "$emailNotificationEnabled" = "ENABLED" ]; then - sendEMailNotificationsFlag=false + sendEMailNotificationsFlag="DISABLED" emailNotificationNewStateStr="${REDct}DISABLED${NOct}" else - sendEMailNotificationsFlag=true + sendEMailNotificationsFlag="ENABLED" emailNotificationNewStateStr="${GRNct}ENABLED${NOct}" fi @@ -6303,9 +7374,9 @@ _Toggle_FW_UpdateEmailNotifications_() _WaitForEnterKey_ "$advnMenuReturnPromptStr" } -##------------------------------------------## -## Modified by ExtremeFiretop [2023-Nov-26] ## -##------------------------------------------## +##----------------------------------------## +## Modified by Martinski W. [2025-Jan-05] ## +##----------------------------------------## _Toggle_FW_UpdateCheckSetting_() { local fwUpdateCheckEnabled fwUpdateCheckNewStateStr @@ -6328,12 +7399,14 @@ _Toggle_FW_UpdateCheckSetting_() runfwUpdateCheck=false FW_UpdateCheckState=0 fwUpdateCheckNewStateStr="${REDct}DISABLED${NOct}" + Update_Custom_Settings "FW_Update_Check" "DISABLED" _DelFWAutoUpdateHook_ _DelFWAutoUpdateCronJob_ else [ -x "$FW_UpdateCheckScript" ] && runfwUpdateCheck=true FW_UpdateCheckState=1 fwUpdateCheckNewStateStr="${GRNct}ENABLED${NOct}" + Update_Custom_Settings "FW_Update_Check" "ENABLED" if _AddFWAutoUpdateCronJob_ then printf "Cron job '${GRNct}${CRON_JOB_TAG}${NOct}' was added successfully.\n" @@ -6350,13 +7423,13 @@ _Toggle_FW_UpdateCheckSetting_() if "$runfwUpdateCheck" then printf "\nChecking for new F/W Updates... Please wait.\n" - sh $FW_UpdateCheckScript 2>&1 + sh "$FW_UpdateCheckScript" 2>&1 fi _WaitForEnterKey_ "$mainMenuReturnPromptStr" } ##----------------------------------------## -## Modified by Martinski W. [2024-Oct-04] ## +## Modified by Martinski W. [2025-Feb-22] ## ##----------------------------------------## _RemoveCronJobsFromAddOns_() { @@ -6397,7 +7470,10 @@ _RemoveCronJobsFromAddOns_() Say "Cron jobs [$cronJobCount] from 3rd-party add-ons were found." Say "---------------------------------------------------------------" - sleep 5 + "$isInteractive" && \ + printf "\nPlease wait to allow already started cron jobs to complete execution..." + sleep 15 + "$isInteractive" && printf "\nDone.\n" return 0 } @@ -6535,7 +7611,7 @@ _GetOfflineFirmwareVersion_() if [ -z "$firmware_version" ] then - fwVersionFormat="${BLUEct}BASE${WHITEct}.${CYANct}MAJOR${WHITEct}.${MAGENTAct}MINOR${WHITEct}.${YLWct}PATCH${NOct}" + fwVersionFormat="${BLUEct}BASE${WHITEct}.${CYANct}MAJOR${WHITEct}.${MGNTct}MINOR${WHITEct}.${YLWct}PATCH${NOct}" # Prompt user for the firmware version if extraction fails # printf "\n${REDct}**WARNING**${NOct}\n" if "$isGNUtonFW" @@ -6683,7 +7759,7 @@ _SelectOfflineUpdateFile_() } ##------------------------------------------## -## Modified by ExtremeFiretop [2024-Apr-18] ## +## Modified by ExtremeFiretop [2024-Dec-21] ## ##------------------------------------------## _GnutonBuildSelection_() { @@ -6693,13 +7769,13 @@ _GnutonBuildSelection_() # Fetch the previous choice from the settings file local previous_choice="$(Get_Custom_Setting "TUFBuild")" - if [ "$previous_choice" = "y" ] + if [ "$previous_choice" = "ENABLED" ] then - echo "TUF Build selected for flashing" + Say "TUF build selected for flashing" firmware_choice="tuf" - elif [ "$previous_choice" = "n" ] + elif [ "$previous_choice" = "DISABLED" ] then - echo "Pure Build selected for flashing" + Say "Pure build selected for flashing" firmware_choice="pure" elif [ "$inMenuMode" = true ] then @@ -6709,31 +7785,31 @@ _GnutonBuildSelection_() read -r choice if [ "$choice" = "y" ] || [ "$choice" = "Y" ] then - echo "TUF Build selected for flashing" + Say "TUF build selected for flashing" firmware_choice="tuf" - Update_Custom_Settings "TUFBuild" "y" + Update_Custom_Settings "TUFBuild" "ENABLED" else - echo "Pure Build selected for flashing" + Say "Pure build selected for flashing" firmware_choice="pure" - Update_Custom_Settings "TUFBuild" "n" + Update_Custom_Settings "TUFBuild" "DISABLED" fi else - echo "Defaulting to Pure Build due to non-interactive mode." + Say "Defaulting to Pure build due to non-interactive mode." firmware_choice="pure" - Update_Custom_Settings "TUFBuild" "n" + Update_Custom_Settings "TUFBuild" "DISABLED" fi elif echo "$PRODUCT_ID" | grep -q "^GT-" then # Fetch the previous choice from the settings file local previous_choice="$(Get_Custom_Setting "ROGBuild")" - if [ "$previous_choice" = "y" ] + if [ "$previous_choice" = "ENABLED" ] then - echo "ROG Build selected for flashing" + Say "ROG build selected for flashing" firmware_choice="rog" - elif [ "$previous_choice" = "n" ] + elif [ "$previous_choice" = "DISABLED" ] then - echo "Pure Build selected for flashing" + Say "Pure build selected for flashing" firmware_choice="pure" elif [ "$inMenuMode" = true ] then @@ -6743,18 +7819,18 @@ _GnutonBuildSelection_() read -r choice if [ "$choice" = "y" ] || [ "$choice" = "Y" ] then - echo "ROG Build selected for flashing" + Say "ROG build selected for flashing" firmware_choice="rog" - Update_Custom_Settings "ROGBuild" "y" + Update_Custom_Settings "ROGBuild" "ENABLED" else - echo "Pure Build selected for flashing" + Say "Pure build selected for flashing" firmware_choice="pure" - Update_Custom_Settings "ROGBuild" "n" + Update_Custom_Settings "ROGBuild" "DISABLED" fi else - echo "Defaulting to Pure Build due to non-interactive mode." + Say "Defaulting to Pure build due to non-interactive mode." firmware_choice="pure" - Update_Custom_Settings "ROGBuild" "n" + Update_Custom_Settings "ROGBuild" "DISABLED" fi else # If not a TUF model, process as usual @@ -6772,6 +7848,14 @@ _RunBackupmon_() if [ -f "/jffs/scripts/backupmon.sh" ] then local current_backup_settings="$(Get_Custom_Setting "FW_Auto_Backupmon")" + + # Default to ENABLED if the setting is empty + if [ "$current_backup_settings" = "TBD" ] + then + Update_Custom_Settings "FW_Auto_Backupmon" "ENABLED" + current_backup_settings="ENABLED" + fi + if [ "$current_backup_settings" = "ENABLED" ] then # Extract version number from backupmon.sh @@ -6828,6 +7912,11 @@ _RunBackupmon_() echo "" fi else + local current_backup_settings="$(Get_Custom_Setting "FW_Auto_Backupmon")" + if [ "$current_backup_settings" != "TBD" ] + then + Delete_Custom_Settings "FW_Auto_Backupmon" + fi Say "Backup script (BACKUPMON) is not installed. Skipping backup." echo "" fi @@ -6904,7 +7993,7 @@ _RunOfflineUpdateNow_() return 1 fi clear - logo + _ShowLogo_ printf "\n---------------------------------------------------\n" offlineUpdateTrigger=true @@ -6953,7 +8042,11 @@ _RunOfflineUpdateNow_() [ "$1" != "**ERROR**" ] && [ "$2" != "**NO_URL**" ] then release_link="$2" - _RunFirmwareUpdateNow_ + if _AcquireLock_ cliFileLock + then + _RunFirmwareUpdateNow_ + _ReleaseLock_ cliFileLock + fi _ClearOfflineUpdateState_ else Say "${REDct}**ERROR**${NOct}: No firmware release URL was found for [$MODEL_ID] router model." @@ -6986,13 +8079,13 @@ _RunFirmwareUpdateNow_() # it has the minimum firmware version supported. if "$routerModelCheckFailed" then - Say "${REDct}WARNING:${NOct} The current router model is not supported by this script." + Say "${REDct}*WARNING*:${NOct} The current router model is not supported by this script." if "$inMenuMode" then printf "\nWould you like to uninstall the script now?" if _WaitForYESorNO_ then - _DoUninstall_ + _DoUnInstallation_ return 0 else Say "Uninstallation cancelled. Exiting script." @@ -7041,9 +8134,7 @@ Please manually update to version ${GRNct}${MinSupportedFirmwareVers}${NOct} or Say "Using temporary fallback directory: /home/root" "$inMenuMode" && { _WaitForYESorNO_ "Continue?" || return 1 ; } # Continue # - FW_ZIP_BASE_DIR="/home/root" - FW_ZIP_DIR="${FW_ZIP_BASE_DIR}/$FW_ZIP_SUBDIR" - FW_ZIP_FPATH="${FW_ZIP_DIR}/${FW_FileName}.zip" + _SetUp_FW_UpdateZIP_DirectoryPaths_ "/home/root" fi if ! node_online_status="$(_NodeActiveStatus_)" @@ -7267,76 +8358,52 @@ Please manually update to version ${GRNct}${MinSupportedFirmwareVers}${NOct} or Say "Required RAM: ${requiredRAM_kb} KB - RAM Free: ${freeRAM_kb} KB - RAM Available: ${availableRAM_kb} KB" check_memory_and_prompt_reboot "$requiredRAM_kb" "$availableRAM_kb" - ##----------------------------------------## - ## Modified by Martinski W. [2024-Jun-04] ## - ##----------------------------------------## + ##------------------------------------------## + ## Modified by ExtremeFiretop [2024-Dec-21] ## + ##------------------------------------------## pure_file="$(ls -1 | grep -iE '.*[.](w|pkgtb)$' | grep -iv 'rog')" + # Detect ROG firmware file # + rog_file="$(ls | grep -i '_rog_')" - if [ "$fwInstalledBaseVers" -le 3004 ] && [ "$fwUpdateBaseNum" -le 3004 ] + # Check if a ROG build is present # + if [ -n "$rog_file" ] then - # Handle upgrades from 3004 and lower # - - # Detect ROG firmware file # - rog_file="$(ls | grep -i '_rog_')" - # Fetch the previous choice from the settings file previous_choice="$(Get_Custom_Setting "ROGBuild")" - - # Check if a ROG build is present - if [ -n "$rog_file" ] + # Use the previous choice if it exists and valid, else prompt the user for their choice in interactive mode + if [ "$previous_choice" = "ENABLED" ] + then + Say "ROG build selected for flashing" + firmware_file="$rog_file" + elif [ "$previous_choice" = "DISABLED" ] then - # Use the previous choice if it exists and valid, else prompt the user for their choice in interactive mode - if [ "$previous_choice" = "y" ] + Say "Pure build selected for flashing" + firmware_file="$pure_file" + elif [ "$inMenuMode" = true ] + then + printf "${REDct}Found ROG build: $rog_file.${NOct}\n" + printf "${REDct}Would you like to use the ROG build?${NOct}\n" + printf "Enter your choice (y/n): " + read -r choice + if [ "$choice" = "y" ] || [ "$choice" = "Y" ] then - Say "ROG Build selected for flashing" + Say "ROG build selected for flashing" firmware_file="$rog_file" - elif [ "$previous_choice" = "n" ] - then - Say "Pure Build selected for flashing" - firmware_file="$pure_file" - elif [ "$inMenuMode" = true ] - then - printf "${REDct}Found ROG build: $rog_file.${NOct}\n" - printf "${REDct}Would you like to use the ROG build?${NOct}\n" - printf "Enter your choice (y/n): " - read -r choice - if [ "$choice" = "y" ] || [ "$choice" = "Y" ]; then - Say "ROG Build selected for flashing" - firmware_file="$rog_file" - Update_Custom_Settings "ROGBuild" "y" - else - Say "Pure Build selected for flashing" - firmware_file="$pure_file" - Update_Custom_Settings "ROGBuild" "n" - fi + Update_Custom_Settings "ROGBuild" "ENABLED" else - # Default to pure_file in non-interactive mode if no previous choice - Say "Pure Build selected for flashing" - Update_Custom_Settings "ROGBuild" "n" + Say "Pure build selected for flashing" firmware_file="$pure_file" + Update_Custom_Settings "ROGBuild" "DISABLED" fi else - # No ROG build found, use the pure build - Say "No ROG Build detected. Skipping." - firmware_file="$pure_file" - fi - elif [ "$fwInstalledBaseVers" -eq 3004 ] && [ "$fwUpdateBaseNum" -ge 3006 ] - then - # Handle upgrade from 3004 to 3006 - # Fetch the previous choice from the settings file - previous_choice="$(Get_Custom_Setting "ROGBuild")" - - # Handle upgrade from 3004 to 3006 if there is a ROG setting - if [ "$previous_choice" = "y" ] - then - Say "Upgrading from 3004 to 3006, ROG UI is no longer supported, auto-selecting Pure UI firmware." - firmware_file="$pure_file" - Update_Custom_Settings "ROGBuild" "n" - else + # Default to pure_file in non-interactive mode if no previous choice + Say "Defaulting to Pure build for flashing" + Update_Custom_Settings "ROGBuild" "DISABLED" firmware_file="$pure_file" fi else - # Handle upgrades from 3006 and higher # + # No ROG build found, use the pure build + Say "No ROG build found. Skipping." firmware_file="$pure_file" fi @@ -7490,6 +8557,7 @@ Please manually update to version ${GRNct}${MinSupportedFirmwareVers}${NOct} or echo # *WARNING*: NO MORE logging at this point & beyond # + sync ; sleep 2 ; echo 3 > /proc/sys/vm/drop_caches ; sleep 3 /sbin/ejusb -1 0 -u 1 2>/dev/null #----------------------------------------------------------------------------------# @@ -7575,7 +8643,11 @@ Please manually update to version ${GRNct}${MinSupportedFirmwareVers}${NOct} or _PostUpdateEmailNotification_() { _DelPostUpdateEmailNotifyScriptHook_ - Update_Custom_Settings FW_New_Update_Changelog_Approval TBD + currentChangelogValue="$(Get_Custom_Setting CheckChangeLog)" + if [ "$currentChangelogValue" = "ENABLED" ] + then + Update_Custom_Settings "FW_New_Update_Changelog_Approval" "TBD" + fi local theWaitDelaySecs=10 local maxWaitDelaySecs=600 #10 minutes# @@ -7613,7 +8685,7 @@ _PostUpdateEmailNotification_() } ##----------------------------------------## -## Modified by Martinski W. [2024-Nov-17] ## +## Modified by Martinski W. [2024-Jan-05] ## ##----------------------------------------## _PostRebootRunNow_() { @@ -7653,7 +8725,11 @@ _PostRebootRunNow_() Say "END of $logMsg [$$curWaitDelaySecs sec.]" sleep 30 ## Let's wait a bit & proceed ## - _RunFirmwareUpdateNow_ + if _AcquireLock_ cliFileLock + then + _RunFirmwareUpdateNow_ + _ReleaseLock_ cliFileLock + fi } ##----------------------------------------## @@ -7671,10 +8747,10 @@ _DelFWAutoUpdateHook_() sed -i -e '/\/'"$ScriptFileName"' addCronJob & '"$hookScriptTagStr"'/d' "$hookScriptFile" if [ $? -eq 0 ] then - Say "Cron job hook was deleted successfully from '$hookScriptFile' script." + Say "F/W Update cron job hook was deleted successfully from '$hookScriptFile' script." fi else - printf "Cron job hook does not exist in '$hookScriptFile' script.\n" + printf "F/W Update cron job hook does not exist in '$hookScriptFile' script.\n" fi } @@ -7755,29 +8831,148 @@ _DelScriptAutoUpdateHook_() sed -i -e '/\/'"$ScriptFileName"' scriptAUCronJob & '"$hookScriptTagStr"'/d' "$hookScriptFile" if [ $? -eq 0 ] then - Say "Cron job hook was deleted successfully from '$hookScriptFile' script." + Say "ScriptAU cron job hook was deleted successfully from '$hookScriptFile' script." fi else - printf "Cron job hook does not exist in '$hookScriptFile' script.\n" + printf "ScriptAU cron job hook does not exist in '$hookScriptFile' script.\n" + fi +} + +##-------------------------------------## +## Added by Martinski W. [2025-Jan-05] ## +##-------------------------------------## +_CheckForMinimumRequirements_() +{ + local requirementsCheckOK=true + + if [ "$(uname -o)" != "ASUSWRT-Merlin" ] + then + requirementsCheckOK=false + Say "\n${CRITct}*WARNING*:${NOct} The current firmware installed is NOT ASUSWRT-Merlin.\n" + fi + + if ! nvram get rc_support | grep -qwoF "am_addons" + then + requirementsCheckOK=false + Say "\n${CRITct}*WARNING*:${NOct} The current firmware installed does NOT support add-ons.\n" + fi + + if ! _CheckForMinimumModelSupport_ + then + requirementsCheckOK=false + Say "\n${CRITct}*WARNING*:${NOct} The current router model ${REDct}${FW_RouterModelID}${NOct} is NOT supported by this script.\n" + fi + + if ! _CheckForMinimumVersionSupport_ + then + requirementsCheckOK=false + Say "\n${CRITct}*WARNING*:${NOct} The current firmware version is below the minimum supported by this script." + printf "\nCurrent F/W version found: ${REDct}${FW_InstalledVersion}${NOct}" + printf "\nMinimum version required: ${GRNct}${MinSupportedFirmwareVers}${NOct}\n" + fi + + jffsScriptOK="$(nvram get jffs2_scripts)" + if [ -n "$jffsScriptOK" ] && [ "$jffsScriptOK" -ne 1 ] && "$requirementsCheckOK" + then + nvram set jffs2_scripts=1 + nvram commit + mkdir -p "$SCRIPTS_PATH" + chmod 755 "$SCRIPTS_PATH" + Say "\nThe NVRAM Custom JFFS Scripts option was ${GRNct}ENABLED${NOct}.\n" + fi + + "$requirementsCheckOK" && return 0 || return 1 +} + +##-------------------------------------## +## Added by Martinski W. [2025-Jan-15] ## +##-------------------------------------## +_DoStartupInit_() +{ + _CreateDirPaths_ + _InitCustomSettingsConfig_ + _CreateSymLinks_ + _InitHelperJSFile_ + _SetVersionSharedSettings_ local "$SCRIPT_VERSION" + + if "$inRouterSWmode" + then + _Mount_WebUI_ + _AutoStartupHook_ create 2>/dev/null + _AutoServiceEvent_ create 2>/dev/null fi } ##----------------------------------------## -## Modified by Martinski W. [2024-Nov-24] ## +## Modified by Martinski W. [2025-Jan-15] ## ##----------------------------------------## -_DoUninstall_() +_DoInstallation_() { - printf "Are you sure you want to uninstall $ScriptFileName script now" + local webguiOK=true + + if ! _AcquireLock_ cliFileLock ; then return 1 ; fi + + _CreateDirPaths_ + _InitCustomSettingsConfig_ + _CreateSymLinks_ + _InitHelperJSFile_ + _SetVersionSharedSettings_ local "$SCRIPT_VERSION" + _SetVersionSharedSettings_ server "$SCRIPT_VERSION" + _DownloadScriptFiles_ install + + if "$inRouterSWmode" + then + ! _Mount_WebUI_ && webguiOK=false + _AutoStartupHook_ create 2>/dev/null + _AutoServiceEvent_ create 2>/dev/null + fi + ! "$webguiOK" && _DoExit_ 1 + + _ReleaseLock_ cliFileLock + _ReleaseLock_ cliOptsLock + + if ! _AcquireLock_ cliMenuLock + then Say "Exiting..." ; exit 1 ; fi + _MainMenu_ +} + +##----------------------------------------## +## Modified by Martinski W. [2025-Jan-22] ## +##----------------------------------------## +_DoUnInstallation_() +{ + "$isInteractive" && \ + printf "\n${BOLDct}Are you sure you want to uninstall $ScriptFileName script now${NOct}" ! _WaitForYESorNO_ && return 0 + if ! _AcquireLock_ cliFileLock ; then return 1 ; fi + + local savedCFGPath="${SCRIPTS_PATH}/${SCRIPT_NAME}_CFG.SAVED.TXT" + + printf "\n${BOLDct}Do you want to keep/save the $SCRIPT_NAME configuration file${NOct}" + if _WaitForYESorNO_ "$("$keepConfigFile" && echo YES || echo NO)" + then + keepConfigFile=true + mv -f "$CONFIG_FILE" "$savedCFGPath" + fi + _DelFWAutoUpdateHook_ _DelFWAutoUpdateCronJob_ _DelScriptAutoUpdateHook_ _DelScriptAutoUpdateCronJob_ _DelPostRebootRunScriptHook_ _DelPostUpdateEmailNotifyScriptHook_ + _SetVersionSharedSettings_ delete + + if "$inRouterSWmode" + then + _Unmount_WebUI_ + _AutoStartupHook_ delete 2>/dev/null + _AutoServiceEvent_ delete 2>/dev/null + fi if rm -fr "${SETTINGS_DIR:?}" && \ + rm -fr "${SCRIPT_WEB_DIR:?}" && \ rm -fr "${FW_BIN_BASE_DIR:?}/$ScriptDirNameD" && \ rm -fr "${FW_LOG_BASE_DIR:?}/$ScriptDirNameD" && \ rm -fr "${FW_ZIP_BASE_DIR:?}/$ScriptDirNameD" && \ @@ -7785,7 +8980,16 @@ _DoUninstall_() then Say "${GRNct}Successfully Uninstalled.${NOct}" else - Say "${REDct}Error: Uninstallation failed.${NOct}" + Say "${CRITct}**ERROR**: Uninstallation failed.${NOct}" + fi + + if "$keepConfigFile" + then + if mkdir -p "$SETTINGS_DIR" + then + chmod 755 "$SETTINGS_DIR" + mv -f "$savedCFGPath" "$CONFIG_FILE" + fi fi _DoExit_ 0 } @@ -7850,9 +9054,9 @@ _SetEMailFormatType_() _WaitForEnterKey_ "$advnMenuReturnPromptStr" } -##-------------------------------------## -## Added by Martinski W. [2024-Feb-16] ## -##-------------------------------------## +##----------------------------------------## +## Modified by Martinski W. [2025-Jan-27] ## +##----------------------------------------## _SetSecondaryEMailAddress_() { local currCC_NameOpt currCC_AddrOpt @@ -7884,9 +9088,10 @@ _SetSecondaryEMailAddress_() do printf "\nEnter a secondary email address to receive email notifications.\n" if [ -z "$currCC_AddrOpt" ] - then printf "[${theADExitStr}] [${currCC_AddrStr}]: " - else printf "[${theADExitStr}] [${clearOptStr}] [${currCC_AddrStr}]: " + then printf "[${theADExitStr}]\n" + else printf "[${theADExitStr}] [${clearOptStr}]\n" fi + printf "[${currCC_AddrStr}]: " read -r userInput [ -z "$userInput" ] && break @@ -7952,7 +9157,7 @@ _SetSecondaryEMailAddress_() while true do printf "\nEnter a name or alias for the secondary email address.\n" - printf "[${theADExitStr}] [${currCC_NameStr}]: " + printf "[${theADExitStr}]\n[${currCC_NameStr}]: " read -r userInput if [ -z "$userInput" ] || echo "$userInput" | grep -qE "^(e|exit|Exit)$" @@ -8048,108 +9253,125 @@ keepWfile=0 trap '_DoCleanUp_ 0 "$keepZIPfile" "$keepWfile" ; _DoExit_ 0' HUP INT QUIT ABRT TERM ##----------------------------------------## -## Modified by Martinski W. [2024-Feb-28] ## +## Modified by Martinski W. [2025-Jan-05] ## ##----------------------------------------## -# Prevent running this script multiple times simultaneously # -if ! _AcquireLock_ +if [ $# -eq 1 ] && [ "$1" = "resetLockFile" ] then - if [ $# -eq 1 ] && [ "$1" = "resetLockFile" ] - then - _ReleaseLock_ - Say "Lock file has now been reset. Exiting..." - exit 0 - fi - Say "Exiting..." ; exit 1 + ! _AcquireLock_ && printf "\nReset Lock and Exit...\n" + _ReleaseLock_ ; exit 0 fi -# Check if the router model is supported OR if -# it has the minimum firmware version supported. -check_model_support -check_version_support - -##-------------------------------------## -## Added by Martinski W. [2024-Jan-24] ## -##-------------------------------------## -_CheckEMailConfigFileFromAMTM_ 0 +##---------------------------------------## +## Added by ExtremeFiretop [2025-Feb-08] ## +##---------------------------------------## +_CheckAndSetBackupOption_() +{ + local currentBackupOption + currentBackupOption="$(Get_Custom_Setting "FW_Auto_Backupmon")" + if [ -f "/jffs/scripts/backupmon.sh" ] + then + # If setting is empty, add it to the configuration file # + if [ "$currentBackupOption" = "TBD" ] + then Update_Custom_Settings FW_Auto_Backupmon "ENABLED" + fi + else + # If the configuration setting exists, delete it # + if [ "$currentBackupOption" != "TBD" ] + then Delete_Custom_Settings "FW_Auto_Backupmon" + fi + fi +} -##----------------------------------------## -## Modified by Martinski W. [2025-Feb-15] ## -##----------------------------------------## -if [ $# -gt 0 ] && [ -n "$1" ] -then - inMenuMode=false - case "$1" in - run_now) _RunFirmwareUpdateNow_ - ;; - processNodes) _ProcessMeshNodes_ 0 - ;; - addCronJob) _AddFWAutoUpdateCronJob_ - ;; - scriptAUCronJob) _AddScriptAutoUpdateCronJob_ - ;; - postRebootRun) _PostRebootRunNow_ - ;; - postUpdateEmail) _PostUpdateEmailNotification_ - ;; - about) _ShowAbout_ - ;; - help) _ShowHelp_ - ;; - checkupdates) _CheckForNewScriptUpdates_ - ;; - forceupdate) _SCRIPTUPDATE_ force - ;; - develop) _ChangeToDev_ - ;; - stable) _ChangeToStable_ - ;; - uninstall) _DoUninstall_ - ;; - *) printf "${REDct}INVALID Parameter.${NOct}\n" - ;; - esac - _DoExit_ 0 -fi +##---------------------------------------## +## Added by ExtremeFiretop [2025-Feb-08] ## +##---------------------------------------## +_SetDefaultBuildType_() +{ + if echo "$PRODUCT_ID" | grep -q "^TUF-" + then + if [ "$(Get_Custom_Setting "TUFBuild")" = "TBD" ] + then Update_Custom_Settings "TUFBuild" "DISABLED" + fi + elif echo "$PRODUCT_ID" | grep -q "^GT-" + then + if [ "$(Get_Custom_Setting "ROGBuild")" = "TBD" ] + then Update_Custom_Settings "ROGBuild" "DISABLED" + fi + fi +} + +##-------------------------------------## +## Added by Martinski W. [2025-Jan-05] ## +##-------------------------------------## +_DisableFWAutoUpdateChecks_() +{ + _DelFWAutoUpdateHook_ + _DelFWAutoUpdateCronJob_ + Update_Custom_Settings "FW_Update_Check" "DISABLED" -# Download the latest version file from the source repository # -# to check if there's a new version update to notify the user # -_CheckForNewScriptUpdates_ + runfwUpdateCheck=false + if [ "$FW_UpdateCheckState" -ne 0 ] + then + FW_UpdateCheckState=0 + nvram set firmware_check_enable="$FW_UpdateCheckState" + nvram commit + fi +} ##-------------------------------------## -## Added by Martinski W. [2024-Nov-24] ## +## Added by Martinski W. [2025-Jan-05] ## ##-------------------------------------## -if [ "$ScriptAutoUpdateSetting" = "ENABLED" ] -then - _AddScriptAutoUpdateCronJob_ -fi +_EnableFWAutoUpdateChecks_() +{ + _AddFWAutoUpdateHook_ + Update_Custom_Settings "FW_Update_Check" "ENABLED" -# Check if the PREVIOUS Cron Job ID already exists # -if eval $cronListCmd | grep -qE "$CRON_JOB_RUN #${CRON_JOB_TAG_OLD}#$" -then #If it exists, delete the OLD one & create a NEW one# - cru d "$CRON_JOB_TAG_OLD" ; sleep 1 ; _AddFWAutoUpdateCronJob_ -fi + runfwUpdateCheck=true + if [ "$FW_UpdateCheckState" -ne 1 ] + then + FW_UpdateCheckState=1 + nvram set firmware_check_enable="$FW_UpdateCheckState" + nvram commit + fi +} ##----------------------------------------## -## Modified by Martinski W. [2024-Nov-24] ## +## Modified by Martinski W. [2025-Jan-12] ## ##----------------------------------------## -FW_UpdateCheckState="$(nvram get firmware_check_enable)" -[ -z "$FW_UpdateCheckState" ] && FW_UpdateCheckState=0 -if [ "$FW_UpdateCheckState" -eq 1 ] -then - runfwUpdateCheck=true +_ConfirmCronJobForFWAutoUpdates_() +{ + if [ $# -gt 0 ] && [ -n "$1" ] && \ + echo "$1" | grep -qE "^(install|startup)$" + then return 1 ; fi + + # Check if the PREVIOUS Cron Job ID already exists # + if eval $cronListCmd | grep -qE "$CRON_JOB_RUN #${CRON_JOB_TAG_OLD}#$" + then #If it exists, delete the OLD one & create a NEW one# + cru d "$CRON_JOB_TAG_OLD" ; sleep 1 ; _AddFWAutoUpdateCronJob_ + fi + + # Retrieve custom setting for automatic F/W update checks # + # Expected values: "ENABLED", "TBD", "DISABLED" (or fallback) # + fwUpdateCheckState="$(Get_Custom_Setting "FW_Update_Check")" + + # Always start with a default of "false" (do not run checks by default) # + runfwUpdateCheck=false + + FW_UpdateCheckState="$(nvram get firmware_check_enable)" + [ -z "$FW_UpdateCheckState" ] && FW_UpdateCheckState=0 + + ##------------------------------------------------------------## + # Priority is given to custom '$fwUpdateCheckState' value. + # The NVRAM variable is updated only after we've decided + # what to do based on the custom setting. + ##------------------------------------------------------------## - # Check if the F/W Update CRON job already exists # - if ! eval $cronListCmd | grep -qE "$CRON_JOB_RUN #${CRON_JOB_TAG}#$" + # 1) "ENABLED": Automatically enable checks (no user prompt) # + if [ "$fwUpdateCheckState" = "ENABLED" ] then - logo - # If CRON job does not exist, ask user for permission to add # - printf "Do you want to enable automatic firmware update checks?\n" - printf "This will create a CRON job to check for updates regularly.\n" - printf "The CRON can be disabled at anytime via the main menu.\n" - if _WaitForYESorNO_ + if ! eval "$cronListCmd" | grep -qE "$CRON_JOB_RUN #${CRON_JOB_TAG}#$" then - # Add the cron job since it doesn't exist and user consented - printf "Adding '${GRNct}${CRON_JOB_TAG}${NOct}' cron job...\n" + printf "Auto-enabling cron job '${GRNct}${CRON_JOB_TAG}${NOct}'...\n" if _AddFWAutoUpdateCronJob_ then printf "Cron job '${GRNct}${CRON_JOB_TAG}${NOct}' was added successfully.\n" @@ -8158,39 +9380,75 @@ then else printf "${REDct}**ERROR**${NOct}: Failed to add the cron job [${CRON_JOB_TAG}].\n" fi - _AddFWAutoUpdateHook_ else - printf "Automatic firmware update checks will be ${REDct}DISABLED${NOct}.\n" - printf "You can enable this feature later via the main menu.\n" - FW_UpdateCheckState=0 - runfwUpdateCheck=false - nvram set firmware_check_enable="$FW_UpdateCheckState" - nvram commit + printf "Cron job '${GRNct}${CRON_JOB_TAG}${NOct}' already exists.\n" fi - else - printf "Cron job '${GRNct}${CRON_JOB_TAG}${NOct}' already exists.\n" - _AddFWAutoUpdateHook_ - fi + _EnableFWAutoUpdateChecks_ - # Check if there's a new F/W update available # - "$runfwUpdateCheck" && [ -x "$FW_UpdateCheckScript" ] && sh $FW_UpdateCheckScript 2>&1 & - _WaitForEnterKey_ -fi + # 2) "TBD": Prompt the user (original behavior) # + elif [ "$fwUpdateCheckState" = "TBD" ] + then + if ! eval $cronListCmd | grep -qE "$CRON_JOB_RUN #${CRON_JOB_TAG}#$" + then + _ShowLogo_ + printf "Do you want to enable automatic firmware update checks?\n" + printf "This will create a CRON job to check for updates regularly.\n" + printf "The CRON can be disabled at any time via the main menu.\n" -padStr=" " + if _WaitForYESorNO_ + then + # User said YES -> enable checks # + printf "Adding '${GRNct}${CRON_JOB_TAG}${NOct}' cron job...\n" + if ! eval "$cronListCmd" | grep -qE "$CRON_JOB_RUN #${CRON_JOB_TAG}#$" + then + if _AddFWAutoUpdateCronJob_ + then + printf "Cron job '${GRNct}${CRON_JOB_TAG}${NOct}' was added successfully.\n" + cronSchedStrHR="$(_TranslateCronSchedHR_ "$FW_UpdateCronJobSchedule")" + printf "Job Schedule: ${GRNct}${cronSchedStrHR}${NOct}\n" + else + printf "${REDct}**ERROR**${NOct}: Failed to add the cron job [${CRON_JOB_TAG}].\n" + fi + else + printf "Cron job '${GRNct}${CRON_JOB_TAG}${NOct}' already exists.\n" + fi + _EnableFWAutoUpdateChecks_ + else + # User said NO -> disable checks # + printf "Automatic firmware update checks will be ${REDct}DISABLED${NOct}.\n" + printf "You can enable this feature later via the main menu.\n" + _DisableFWAutoUpdateChecks_ + fi + _WaitForEnterKey_ + else + printf "Cron job '${GRNct}${CRON_JOB_TAG}${NOct}' already exists.\n" + Update_Custom_Settings "FW_Update_Check" "ENABLED" + _AddFWAutoUpdateHook_ + runfwUpdateCheck=true + fi -##----------------------------------------## -## Modified by Martinski W. [2024-Jun-05] ## -##----------------------------------------## -FW_RouterProductID="${GRNct}${PRODUCT_ID}${NOct}" -# Some Model IDs have a lower case suffix of the same Product ID # -if [ "$PRODUCT_ID" = "$(echo "$MODEL_ID" | tr 'a-z' 'A-Z')" ] -then FW_RouterModelID="${FW_RouterProductID}" -else FW_RouterModelID="${FW_RouterProductID}/${GRNct}${MODEL_ID}${NOct}" -fi + # 3) "DISABLED": Perform the disable steps (same as _Toggle_FW_UpdateCheckSetting_) # + elif [ "$fwUpdateCheckState" = "DISABLED" ] + then + printf "Firmware update checks have been ${REDct}DISABLED${NOct}.\n" + _DisableFWAutoUpdateChecks_ -FW_InstalledVersion="$(_GetCurrentFWInstalledLongVersion_)" -FW_InstalledVerStr="${GRNct}${FW_InstalledVersion}${NOct}" + # 4) Unknown/fallback -> treat as DISABLED # + else + printf "Unknown FW_Update_Check value: '%s'. Disabling firmware checks.\n" "$fwUpdateCheckState" + _DisableFWAutoUpdateChecks_ + fi + + ##------------------------------------------------------------## + # If 'runfwUpdateCheck' is true and built-in script is found + # run the built-in F/W Update check in the background. + ##------------------------------------------------------------## + if "$runfwUpdateCheck" && [ -x "$FW_UpdateCheckScript" ] + then + sh "$FW_UpdateCheckScript" 2>&1 + sleep 1 + fi +} ##-------------------------------------## ## Added by Martinski W. [2024-May-03] ## @@ -8224,16 +9482,17 @@ _GetFileSelectionIndex_() if [ $# -lt 2 ] || [ "$2" != "-MULTIOK" ] then multiIndexListOK=false - promptStr="Enter selection [${selectStr}] [${theLGExitStr}]?" + promptStr="Enter selection [${selectStr}]?" else multiIndexListOK=true - promptStr="Enter selection [${selectStr} | ${theAllStr}] [${theLGExitStr}]?" + promptStr="Enter selection [${selectStr} | ${theAllStr}]?" fi fileIndex=0 multiIndex=false numRegEx="([1-9]|[1-9][0-9])" while true do + printf "[${theLGExitStr}]\n" printf "${promptStr} " ; read -r userInput if [ -z "$userInput" ] || \ @@ -8488,7 +9747,7 @@ _InvalidMenuSelection_() ##----------------------------------------## ## Modified by Martinski W. [2025-Feb-15] ## ##----------------------------------------## -_ShowMainMenu_() +_ShowMainMenuOptions_() { local FW_NewUpdateVerStr FW_NewUpdateVersion @@ -8496,12 +9755,16 @@ _ShowMainMenu_() # Check if router reports a new F/W update is available. # If yes, modify the notification settings accordingly. #-----------------------------------------------------------# - FW_NewUpdateVersion="$(_GetLatestFWUpdateVersionFromRouter_)" && \ - [ -n "$FW_InstalledVersion" ] && [ -n "$FW_NewUpdateVersion" ] && \ - _CheckNewUpdateFirmwareNotification_ "$FW_InstalledVersion" "$FW_NewUpdateVersion" + if FW_NewUpdateVersion="$(_GetLatestFWUpdateVersionFromRouter_)" && \ + [ -n "$FW_NewUpdateVersion" ] && [ -n "$FW_InstalledVersion" ] && \ + [ "$FW_NewUpdateVersion" != "$FW_NewUpdateVerInit" ] + then + FW_NewUpdateVerInit="$FW_NewUpdateVersion" + _CheckNewUpdateFirmwareNotification_ "$FW_InstalledVersion" "$FW_NewUpdateVersion" + fi clear - logo + _ShowLogo_ printf "${YLWct}============ By ExtremeFiretop & Martinski W. ============${NOct}\n\n" # New Script Update Notification # @@ -8543,7 +9806,7 @@ _ShowMainMenu_() fi if "$isGNUtonFW" - then FirmwareFlavor="${MAGENTAct}GNUton${NOct}" + then FirmwareFlavor="${MGNTct}GNUton${NOct}" else FirmwareFlavor="${BLUEct}Merlin${NOct}" fi @@ -8552,16 +9815,16 @@ _ShowMainMenu_() then if ! FW_NewUpdateVerStr="$(_GetLatestFWUpdateVersionFromRouter_ 1)" then FW_NewUpdateVerStr=" ${REDct}NONE FOUND${NOct}" - else FW_NewUpdateVerStr="${InvGRNct} ${FW_NewUpdateVerStr} ${NOct}$arrowStr" + else FW_NewUpdateVerStr="${InvBGRNct} ${FW_NewUpdateVerStr} ${NOct}$arrowStr" fi - printf "\n Router's Product Name/Model ID: ${FW_RouterModelID}${padStr}(H)ide" + printf "\n Router's Product Name/Model ID: ${FW_RouterModelIDstr}${padStr}(H)ide" printf "\n USB-Attached Storage Connected: $USBConnected" printf "\n F/W Variant Configuration Found: $FirmwareFlavor" printf "\n F/W Version Currently Installed: $FW_InstalledVerStr" printf "\n F/W Update Version Available: $FW_NewUpdateVerStr" printf "\n F/W Update Estimated Run Date: $ExpectedFWUpdateRuntime" else - printf "\n Router's Product Name/Model ID: ${FW_RouterModelID}${padStr}(S)how" + printf "\n Router's Product Name/Model ID: ${FW_RouterModelIDstr}${padStr}(S)how" fi printf "\n${SEPstr}" @@ -8577,10 +9840,11 @@ _ShowMainMenu_() printf "\n${padStr}[Currently ${InvREDct} DISABLED ${NOct}]" else printf "\n ${GRNct}3${NOct}. Toggle Automatic F/W Update Checks" - printf "\n${padStr}[Currently ${InvGRNct} ENABLED ${NOct}]" + printf "\n${padStr}[Currently ${InvBGRNct} ENABLED ${NOct}]" fi printf "\n${padStr}[Last Notification Date: $notificationStr]\n" + FW_UpdatePostponementDays="$(Get_Custom_Setting FW_New_Update_Postponement_Days)" printf "\n ${GRNct}4${NOct}. Set F/W Update Postponement Days" printf "\n${padStr}[Current Days: ${GRNct}${FW_UpdatePostponementDays}${NOct}]\n" @@ -8597,19 +9861,19 @@ _ShowMainMenu_() ChangelogApproval="$(Get_Custom_Setting "FW_New_Update_Changelog_Approval")" if [ "$ChangelogApproval" = "BLOCKED" ] then - printf "\n ${GRNct}6${NOct}. Toggle F/W Update Changelog Approval" - printf "\n${padStr}[Currently ${REDct}${ChangelogApproval}${NOct}]\n" + printf "\n ${GRNct}6${NOct}. Toggle F/W Update Changelog Approval" + printf "\n${padStr}[Currently ${REDct}${ChangelogApproval}${NOct}]\n" elif [ "$ChangelogApproval" = "APPROVED" ] then - printf "\n ${GRNct}6${NOct}. Toggle F/W Update Changelog Approval" - printf "\n${padStr}[Currently ${GRNct}${ChangelogApproval}${NOct}]\n" + printf "\n ${GRNct}6${NOct}. Toggle F/W Update Changelog Approval" + printf "\n${padStr}[Currently ${GRNct}${ChangelogApproval}${NOct}]\n" fi # Check for new script updates # if [ "$scriptUpdateNotify" != "0" ] then printf "\n ${GRNct}up${NOct}. Update $SCRIPT_NAME Script" - printf "\n${padStr}[Version ${InvGRNct} ${DLRepoVersion} ${NOct} Available for Download]\n" + printf "\n${padStr}[Version ${InvBGRNct} ${DLRepoVersion} ${NOct} Available for Download]\n" else printf "\n ${GRNct}up${NOct}. Force Update $SCRIPT_NAME Script" printf "\n${padStr}[No Update Available]\n" @@ -8631,7 +9895,7 @@ _ShowMainMenu_() } ##----------------------------------------## -## Modified by Martinski W. [2025-Feb-16] ## +## Modified by Martinski W. [2025-Feb-18] ## ##----------------------------------------## _ShowAdvancedOptionsMenu_() { @@ -8639,13 +9903,15 @@ _ShowAdvancedOptionsMenu_() local scriptUpdateCronSched current_build_type clear - logo + _ShowLogo_ printf "================== Advanced Options Menu =================\n" printf "${SEPstr}\n" + _SetUp_FW_UpdateZIP_DirectoryPaths_ printf "\n ${GRNct}1${NOct}. Set Directory for F/W Update File" printf "\n${padStr}[Current Path: ${GRNct}${FW_ZIP_DIR}${NOct}]\n" + FW_UpdateCronJobSchedule="$(Get_Custom_Setting FW_New_Update_Cron_Job_Schedule)" printf "\n ${GRNct}2${NOct}. Set F/W Update Cron Schedule" printf "\n${padStr}[Current Schedule: ${GRNct}${FW_UpdateCronJobSchedule}${NOct}]" printf "\n${padStr}[${GRNct}%s${NOct}]\n" "$(_TranslateCronSchedHR_ "$FW_UpdateCronJobSchedule")" @@ -8668,11 +9934,13 @@ _ShowAdvancedOptionsMenu_() printf "\n${padStr}[Currently ${REDct}ENABLED${NOct}]\n" fi + # Check if the file BACKUPMON exists # if [ -f "/jffs/scripts/backupmon.sh" ] then # Retrieve the current backup setting # currentBackupOption="$(Get_Custom_Setting "FW_Auto_Backupmon")" + # Display the backup option toggle menu printf "\n ${GRNct}ab${NOct}. Toggle Automatic Backups" if [ "$currentBackupOption" = "DISABLED" ] then printf "\n${padStr}[Currently ${REDct}${currentBackupOption}${NOct}]\n" @@ -8684,104 +9952,85 @@ _ShowAdvancedOptionsMenu_() printf "\n ${GRNct}au${NOct}. Toggle Auto-Updates for MerlinAU Script" if [ "$ScriptAutoUpdateSetting" = "DISABLED" ] then - printf "\n${padStr}[Currently ${GRNct}DISABLED${NOct}]\n" + printf "\n${padStr}[Currently ${InvBMGNct} DISABLED ${NOct}]\n" else scriptUpdateCronSched="$(_GetScriptAutoUpdateCronSchedule_)" printf "\n${padStr}[Current Schedule: ${GRNct}${scriptUpdateCronSched}${NOct}]" printf "\n${padStr}[${GRNct}%s${NOct}]\n" "$(_TranslateCronSchedHR_ "$scriptUpdateCronSched")" fi - if "$isGNUtonFW" - then - if [ "$fwInstalledBaseVers" -le 3004 ] - then - current_build_type="$(Get_Custom_Setting "TUFBuild")" - - # Convert the setting to a descriptive text - if [ "$current_build_type" = "y" ]; then - current_build_type_menu="TUF Build" - elif [ "$current_build_type" = "n" ]; then - current_build_type_menu="Pure Build" - else - current_build_type_menu="NOT SET" - fi - - if echo "$PRODUCT_ID" | grep -q "^TUF-" - then - printf "\n ${GRNct}bt${NOct}. Toggle F/W Build Type Preference" - if [ "$current_build_type_menu" = "NOT SET" ] - then printf "\n${padStr}[Current Build Type: ${REDct}${current_build_type_menu}${NOct}]\n" - else printf "\n${padStr}[Current Build Type: ${GRNct}${current_build_type_menu}${NOct}]\n" - fi - fi - elif [ "$fwInstalledBaseVers" -ge 3006 ] - then - local current_build_typerog="$(Get_Custom_Setting "ROGBuild")" - - # Convert the setting to a descriptive text - if [ "$current_build_typerog" = "y" ]; then - current_build_type_menurog="ROG Build" - elif [ "$current_build_typerog" = "n" ]; then - current_build_type_menurog="Pure Build" - else - current_build_type_menurog="NOT SET" - fi - - if echo "$PRODUCT_ID" | grep -q "^GT-" - then - printf "\n ${GRNct}bt${NOct}. Toggle F/W Build Type Preference" - if [ "$current_build_type_menurog" = "NOT SET" ] - then printf "\n${padStr}[Current Build Type: ${REDct}${current_build_type_menurog}${NOct}]\n" - else printf "\n${padStr}[Current Build Type: ${GRNct}${current_build_type_menurog}${NOct}]\n" - fi - fi - - local current_build_typetuf="$(Get_Custom_Setting "TUFBuild")" - - # Convert the setting to a descriptive text - if [ "$current_build_typetuf" = "y" ]; then - current_build_type_menutuf="TUF Build" - elif [ "$current_build_typetuf" = "n" ]; then - current_build_type_menutuf="Pure Build" - else - current_build_type_menutuf="NOT SET" - fi + if "$isGNUtonFW" + then + if echo "$PRODUCT_ID" | grep -q "^TUF-" + then + local current_build_type="$(Get_Custom_Setting "TUFBuild")" - if echo "$PRODUCT_ID" | grep -q "^TUF-" - then - printf "\n ${GRNct}bt${NOct}. Toggle F/W Build Type Preference" - if [ "$current_build_type_menutuf" = "NOT SET" ] - then printf "\n${padStr}[Current Build Type: ${REDct}${current_build_type_menutuf}${NOct}]\n" - else printf "\n${padStr}[Current Build Type: ${GRNct}${current_build_type_menutuf}${NOct}]\n" - fi - fi - fi - else - if [ "$fwInstalledBaseVers" -le 3004 ] - then - current_build_type="$(Get_Custom_Setting "ROGBuild")" + # Convert the setting to a descriptive text + if [ "$current_build_type" = "ENABLED" ] + then + current_build_type_menu="TUF Build" + elif [ "$current_build_type" = "DISABLED" ] + then + current_build_type_menu="Pure Build" + else + current_build_type_menu="NOT SET" + fi + printf "\n ${GRNct}bt${NOct}. Toggle F/W Build Type Preference" + if [ "$current_build_type_menu" = "NOT SET" ] + then + printf "\n${padStr}[Current Build Type: ${REDct}${current_build_type_menu}${NOct}]\n" + else + printf "\n${padStr}[Current Build Type: ${GRNct}${current_build_type_menu}${NOct}]\n" + fi + elif echo "$PRODUCT_ID" | grep -q "^GT-" + then + local current_build_typerog="$(Get_Custom_Setting "ROGBuild")" - # Convert the setting to a descriptive text - if [ "$current_build_type" = "y" ]; then - current_build_type_menu="ROG Build" - elif [ "$current_build_type" = "n" ]; then - current_build_type_menu="Pure Build" - else - current_build_type_menu="NOT SET" - fi + # Convert the setting to a descriptive text + if [ "$current_build_typerog" = "ENABLED" ] + then + current_build_type_menurog="ROG Build" + elif [ "$current_build_typerog" = "DISABLED" ] + then + current_build_type_menurog="Pure Build" + else + current_build_type_menurog="NOT SET" + fi + printf "\n ${GRNct}bt${NOct}. Toggle F/W Build Type Preference" + if [ "$current_build_type_menurog" = "NOT SET" ] + then + printf "\n${padStr}[Current Build Type: ${REDct}${current_build_type_menurog}${NOct}]\n" + else + printf "\n${padStr}[Current Build Type: ${GRNct}${current_build_type_menurog}${NOct}]\n" + fi + fi + else + if echo "$PRODUCT_ID" | grep -q "^GT-" + then + local current_build_type="$(Get_Custom_Setting "ROGBuild")" - if echo "$PRODUCT_ID" | grep -q "^GT-" - then - printf "\n ${GRNct}bt${NOct}. Toggle F/W Build Type Preference" - if [ "$current_build_type_menu" = "NOT SET" ] - then printf "\n${padStr}[Current Build Type: ${REDct}${current_build_type_menu}${NOct}]\n" - else printf "\n${padStr}[Current Build Type: ${GRNct}${current_build_type_menu}${NOct}]\n" - fi - fi - fi - fi + # Convert the setting to a descriptive text + if [ "$current_build_type" = "ENABLED" ] + then + current_build_type_menu="ROG Build" + elif [ "$current_build_type" = "DISABLED" ] + then + current_build_type_menu="Pure Build" + else + current_build_type_menu="NOT SET" + fi + printf "\n ${GRNct}bt${NOct}. Toggle F/W Build Type Preference" + if [ "$current_build_type_menu" = "NOT SET" ] + then + printf "\n${padStr}[Current Build Type: ${REDct}${current_build_type_menu}${NOct}]\n" + else + printf "\n${padStr}[Current Build Type: ${GRNct}${current_build_type_menu}${NOct}]\n" + fi + fi + fi # Additional Email Notification Options # + _WebUI_SetEmailConfigFileFromAMTM_ if _CheckEMailConfigFileFromAMTM_ 0 then # F/W Update Email Notifications # @@ -8791,14 +10040,14 @@ _ShowAdvancedOptionsMenu_() else printf "\n ${GRNct}em${NOct}. Toggle F/W Email Notifications" fi - if "$sendEMailNotificationsFlag" + if [ "$sendEMailNotificationsFlag" = "ENABLED" ] then printf "\n${padStr}[Currently ${GRNct}ENABLED${NOct}]\n" else printf "\n${padStr}[Currently ${REDct}DISABLED${NOct}]\n" fi - if "$sendEMailNotificationsFlag" + if [ "$sendEMailNotificationsFlag" = "ENABLED" ] then # Format Types: "HTML" or "Plain Text" # printf "\n ${GRNct}ef${NOct}. Set Email Format Type" @@ -8827,7 +10076,7 @@ _ShowAdvancedOptionsMenu_() _ShowNodesMenu_() { clear - logo + _ShowLogo_ printf "================ AiMesh Node(s) Info Menu ================\n" printf "${SEPstr}\n" @@ -8871,7 +10120,7 @@ _ShowNodesMenuOptions_() _ShowLogOptionsMenu_() { clear - logo + _ShowLogo_ printf "==================== Log Options Menu ====================\n" printf "${SEPstr}\n" @@ -8890,17 +10139,20 @@ _ShowLogOptionsMenu_() } ##----------------------------------------## -## Modified by Martinski W. [2024-May-04] ## +## Modified by Martinski W. [2025-Jan-15] ## ##----------------------------------------## _AdvancedLogsOptions_() { + local menuChoice="" + _SetUp_FW_UpdateLOG_DirectoryPaths_ + while true do _ShowLogOptionsMenu_ printf "\nEnter selection: " - read -r nodesChoice + read -r menuChoice echo - case $nodesChoice in + case "$menuChoice" in 1) _Set_FW_UpdateLOG_DirectoryPath_ ;; lg) if _CheckForUpdateLogFiles_ @@ -8928,17 +10180,20 @@ _AdvancedLogsOptions_() } ##------------------------------------------## -## Modified by ExtremeFiretop [2024-Nov-18] ## +## Modified by ExtremeFiretop [2025-Jan-10] ## ##------------------------------------------## _AdvancedOptionsMenu_() { local theUserInputStr="" - local offlineUpdateFlag=false + local offlineUpdTrigger=false + local execReloadTrigger=false + while true do _ShowAdvancedOptionsMenu_ _GetKeypressInput_ "Enter selection:" echo + case "$theUserInputStr" in 1) _Set_FW_UpdateZIP_DirectoryPath_ ;; @@ -8957,11 +10212,7 @@ _AdvancedOptionsMenu_() ;; bt) if echo "$PRODUCT_ID" | grep -q "^TUF-" then _ChangeBuildType_TUF_ - elif [ "$fwInstalledBaseVers" -le 3004 ] && \ - echo "$PRODUCT_ID" | grep -q "^GT-" - then _ChangeBuildType_ROG_ - elif [ "$fwInstalledBaseVers" -ge 3006 ] && "$isGNUtonFW" && \ - echo "$PRODUCT_ID" | grep -q "^GT-" + elif echo "$PRODUCT_ID" | grep -q "^GT-" then _ChangeBuildType_ROG_ else _InvalidMenuSelection_ fi @@ -8972,25 +10223,33 @@ _AdvancedOptionsMenu_() fi ;; ef) if "$isEMailConfigEnabledInAMTM" && \ - "$sendEMailNotificationsFlag" + [ "$sendEMailNotificationsFlag" = "ENABLED" ] then _SetEMailFormatType_ else _InvalidMenuSelection_ fi ;; se) if "$isEMailConfigEnabledInAMTM" && \ - "$sendEMailNotificationsFlag" + [ "$sendEMailNotificationsFlag" = "ENABLED" ] then _SetSecondaryEMailAddress_ else _InvalidMenuSelection_ fi ;; - un) _DoUninstall_ && _WaitForEnterKey_ + un) _DoUnInstallation_ && _WaitForEnterKey_ ;; e|E|exit) break ;; - *) if [ -n "${offlineUpdateFlag:+OK}" ] && "$offlineUpdateFlag" + *) if "$offlineUpdTrigger" then _RunOfflineUpdateNow_ [ "$?" -eq 2 ] && _InvalidMenuSelection_ + ## + elif "$execReloadTrigger" + then + printf "Reloading configuration to refresh menu." + printf "\nPlease wait...\n" + _ReleaseLock_ + exec "$ScriptFilePath" reload advmenu + exit 0 else _InvalidMenuSelection_ fi @@ -8999,63 +10258,286 @@ _AdvancedOptionsMenu_() done } -##------------------------------------------## -## Modified by ExtremeFiretop [2024-May-25] ## -##------------------------------------------## -# Main Menu loop -inMenuMode=true -HIDE_ROUTER_SECTION=false -if ! node_list="$(_GetNodeIPv4List_)" -then node_list="" ; fi +##----------------------------------------## +## Modified by Martinski W. [2025-Jan-10] ## +##----------------------------------------## +_MainMenu_() +{ + local theUserInputStr="" jumpToAdvMenu + local execReloadTrigger=false -while true -do - # Check if the directory exists again before attempting to navigate to it - [ -d "$FW_BIN_DIR" ] && cd "$FW_BIN_DIR" + inMenuMode=true + HIDE_ROUTER_SECTION=false + if ! node_list="$(_GetNodeIPv4List_)" + then node_list="" ; fi - _ShowMainMenu_ - printf "Enter selection: " ; read -r userChoice - echo - case $userChoice in - s|S|h|H) - if [ "$userChoice" = "s" ] || [ "$userChoice" = "S" ]; then - HIDE_ROUTER_SECTION=false - elif [ "$userChoice" = "h" ] || [ "$userChoice" = "H" ]; then - HIDE_ROUTER_SECTION=true - fi - ;; - 1) _RunFirmwareUpdateNow_ - FlashStarted=false - ;; - 2) _GetLoginCredentials_ - ;; - 3) _Toggle_FW_UpdateCheckSetting_ - ;; - 4) _Set_FW_UpdatePostponementDays_ - ;; - 5) _toggle_change_log_check_ - ;; - 6) if [ "$ChangelogApproval" = "TBD" ] || [ -z "$ChangelogApproval" ] - then _InvalidMenuSelection_ - else _Approve_FW_Update_ - fi - ;; - up) _SCRIPTUPDATE_ - ;; - ad) _AdvancedOptionsMenu_ - ;; - mn) if "$inRouterSWmode" && [ -n "$node_list" ] - then _ShowNodesMenuOptions_ - else _InvalidMenuSelection_ - fi - ;; - lo) _AdvancedLogsOptions_ - ;; - e|E|exit) _DoExit_ 0 - ;; - *) _InvalidMenuSelection_ - ;; + if [ $# -gt 1 ] && \ + [ "$1" = "reload" ] && \ + [ "$2" = "advmenu" ] + then jumpToAdvMenu=true + else jumpToAdvMenu=false + fi + + while true + do + [ -d "$FW_BIN_DIR" ] && cd "$FW_BIN_DIR" + + if "$jumpToAdvMenu" + then + theUserInputStr=ad + jumpToAdvMenu=false + else + _ShowMainMenuOptions_ + _GetKeypressInput_ "Enter selection:" + echo + fi + + case "$theUserInputStr" in + s|S|h|H) + if [ "$theUserInputStr" = "s" ] || \ + [ "$theUserInputStr" = "S" ] + then + HIDE_ROUTER_SECTION=false + elif [ "$theUserInputStr" = "h" ] || \ + [ "$theUserInputStr" = "H" ] + then + HIDE_ROUTER_SECTION=true + fi + ;; + 1) if _AcquireLock_ cliFileLock + then + _RunFirmwareUpdateNow_ + _ReleaseLock_ cliFileLock + FlashStarted=false + fi + ;; + 2) _GetLoginCredentials_ + ;; + 3) _Toggle_FW_UpdateCheckSetting_ + ;; + 4) _Set_FW_UpdatePostponementDays_ + ;; + 5) _toggle_change_log_check_ + ;; + 6) if [ -z "$ChangelogApproval" ] || \ + [ "$ChangelogApproval" = "TBD" ] + then _InvalidMenuSelection_ + else _Approve_FW_Update_ + fi + ;; + up) if _AcquireLock_ cliFileLock + then + _SCRIPT_UPDATE_ + _ReleaseLock_ cliFileLock + fi + ;; + ad) _AdvancedOptionsMenu_ + ;; + mn) if "$inRouterSWmode" && [ -n "$node_list" ] + then _ShowNodesMenuOptions_ + else _InvalidMenuSelection_ + fi + ;; + lo) _AdvancedLogsOptions_ + ;; + e|E|exit) _DoExit_ 0 + ;; + *) if "$execReloadTrigger" + then + printf "Reloading configuration to refresh menu." + printf "\nPlease wait...\n" + _ReleaseLock_ + exec "$ScriptFilePath" reload topmenu + exit 0 + else + _InvalidMenuSelection_ + fi + ;; + esac + done +} + +##-------------------------------------## +## Added by Martinski W. [2025-Jan-15] ## +##-------------------------------------## +_DoInitializationStartup_() +{ + if ! _CheckForMinimumRequirements_ + then + printf "\n${CRITct}Minimum requirements for $SCRIPT_NAME were not met. See the reason(s) above.${NOct}\n" + _DoExit_ 1 + fi + + if [ $# -gt 0 ] && [ -n "$1" ] && \ + echo "$1" | grep -qE "^(install|startup)$" + then return 1 ; fi + + _CreateDirPaths_ + _InitCustomSettingsConfig_ + _CreateSymLinks_ + _InitHelperJSFile_ + _SetVersionSharedSettings_ local "$SCRIPT_VERSION" + + if "$inRouterSWmode" + then + _AutoStartupHook_ create 2>/dev/null + _AutoServiceEvent_ create 2>/dev/null + fi + + _CheckAndSetBackupOption_ + _SetDefaultBuildType_ +} + +FW_InstalledVersion="$(_GetCurrentFWInstalledLongVersion_)" +FW_InstalledVerStr="${GRNct}${FW_InstalledVersion}${NOct}" +FW_NewUpdateVerInit=TBD + +##----------------------------------------## +## Modified by Martinski W. [2025-Feb-12] ## +##----------------------------------------## +if [ $# -eq 0 ] || [ -z "$1" ] || \ + { [ $# -gt 1 ] && [ "$1" = "reload" ] ; } +then + if ! _AcquireLock_ cliMenuLock + then Say "Exiting..." ; exit 1 ; fi + + inMenuMode=true + _DoInitializationStartup_ + if _AcquireLock_ cliFileLock + then + _CheckForNewScriptUpdates_ + _ReleaseLock_ cliFileLock + fi + if [ "$ScriptAutoUpdateSetting" = "ENABLED" ] + then _AddScriptAutoUpdateCronJob_ ; fi + _ConfirmCronJobForFWAutoUpdates_ + _CheckFor_WebGUI_Page_ + + _MainMenu_ "$@" + _DoExit_ 0 +fi + +##----------------------------------------## +## Modified by Martinski W. [2025-Feb-15] ## +##----------------------------------------## +if [ $# -gt 0 ] +then + if ! _AcquireLock_ cliOptsLock + then Say "Exiting..." ; exit 1 ; fi + + inMenuMode=false + _DoInitializationStartup_ "$1" + _ConfirmCronJobForFWAutoUpdates_ "$1" + + case "$1" in + run_now) + if _AcquireLock_ cliFileLock + then + _RunFirmwareUpdateNow_ + _ReleaseLock_ cliFileLock + fi + ;; + processNodes) _ProcessMeshNodes_ 0 + ;; + addCronJob) _AddFWAutoUpdateCronJob_ + ;; + scriptAUCronJob) _AddScriptAutoUpdateCronJob_ + ;; + postRebootRun) _PostRebootRunNow_ + ;; + postUpdateEmail) _PostUpdateEmailNotification_ + ;; + about) _ShowAbout_ + ;; + help) _ShowHelp_ + ;; + checkupdates) + if _AcquireLock_ cliFileLock + then + _CheckForNewScriptUpdates_ + _ReleaseLock_ cliFileLock + fi + ;; + forceupdate) + if _AcquireLock_ cliFileLock + then + _SCRIPT_UPDATE_ force + _ReleaseLock_ cliFileLock + fi + ;; + develop) _ChangeToDev_ + ;; + stable) _ChangeToStable_ + ;; + startup) _DoStartupInit_ + ;; + install) _DoInstallation_ + ;; + uninstall) _DoUnInstallation_ + ;; + service_event) + if [ "$2" = "start" ] + then + case "$3" in + "${SCRIPT_NAME}uninstall" | \ + "${SCRIPT_NAME}uninstall_keepConfig") + if [ "$3" = "${SCRIPT_NAME}uninstall_keepConfig" ] + then keepConfigFile=true + else keepConfigFile=false + fi + _DoUnInstallation_ + sleep 1 + ;; + "${SCRIPT_NAME}approvechangelog") + currApprovalStatus="$(Get_Custom_Setting "FW_New_Update_Changelog_Approval")" + if [ "$currApprovalStatus" = "BLOCKED" ] + then + Update_Custom_Settings "FW_New_Update_Changelog_Approval" "APPROVED" + elif [ "$currApprovalStatus" = "APPROVED" ] + then + Update_Custom_Settings "FW_New_Update_Changelog_Approval" "BLOCKED" + fi + ;; + "${SCRIPT_NAME}blockchangelog") + currApprovalStatus="$(Get_Custom_Setting "FW_New_Update_Changelog_Approval")" + if [ "$currApprovalStatus" = "APPROVED" ] + then + Update_Custom_Settings "FW_New_Update_Changelog_Approval" "BLOCKED" + elif [ "$currApprovalStatus" = "BLOCKED" ] + then + Update_Custom_Settings "FW_New_Update_Changelog_Approval" "APPROVED" + fi + ;; + "${SCRIPT_NAME}checkupdate" | \ + "${SCRIPT_NAME}checkupdate_bypassDays") + if _AcquireLock_ cliFileLock + then + if [ "$3" = "${SCRIPT_NAME}checkupdate_bypassDays" ] + then bypassPostponedDays=true + else bypassPostponedDays=false + fi + _RunFirmwareUpdateNow_ + _ReleaseLock_ cliFileLock + fi + ;; + "${SCRIPT_NAME}config") + if _AcquireLock_ cliFileLock + then + _UpdateConfigFromWebUISettings_ + _ConfirmCronJobForFWAutoUpdates_ + _ReleaseLock_ cliFileLock + fi + ;; + *) + printf "${REDct}INVALID Parameters [$*].${NOct}\n" + ;; + esac + fi + ;; + *) printf "${REDct}INVALID Parameter [$*].${NOct}\n" + ;; esac -done + _DoExit_ 0 +fi #EOF# diff --git a/README.md b/README.md index c32fe0d0..37314254 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,13 @@ # MerlinAU - AsusWRT-Merlin Firmware Auto Updater -## v1.3.10 -## 2025-Feb-18 +## v1.4.0 +## 2025-Mar-01 -![image](https://github.com/user-attachments/assets/2eebe686-364a-4fb1-9493-e6b91c23b9fd) -![image](https://github.com/user-attachments/assets/5ca4587f-5b6e-45a6-9c2d-a889b91f8368) +## WebUI: +![image](https://github.com/user-attachments/assets/10d0971c-b3c6-477a-8904-d4bf013f72df) + +## Core Shell Script: +![image](https://github.com/user-attachments/assets/06db50c7-bff7-4d8b-8a29-a304235896a2) +![image](https://github.com/user-attachments/assets/404b7a03-580a-4248-802d-a406fe1fe819) ![image](https://github.com/user-attachments/assets/959d7bb6-20b4-4e97-ab3e-b7b90cc08744) ![image](https://github.com/user-attachments/assets/2e92af06-a6b1-4573-9a89-6986e739b514) diff --git a/version.txt b/version.txt index 0c00f610..88c5fb89 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.3.10 +1.4.0