#!/bin/bash # A script for Clover Theme Manager # Copyright (C) 2014-2019 Blackosx # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # Credits: # Thanks to SoThOr for helping with svn communications # Thanks to apianti for setting up the Clover git theme repository. # Thanks to apianti, dmazar & JrCs for their git know-how. # Thanks to alexq, asusfreak, chris1111, droplets, eMatoS, kyndder & oswaldini for testing. VERS="0.78.3" # ======================================================================================= # Helper Functions/Routines # ======================================================================================= # --------------------------------------------------------------------------------------- CreateSymbolicLinks() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}CreateSymbolicLinks()" local checkCount=0 # Create symbolic link to local images if [ ! -L "${WORKING_PATH}/${APP_DIR_NAME}/themes" ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Creating symbolic link to ${WORKING_PATH}/${APP_DIR_NAME}/themes" ln -s "${WORKING_PATH}/${APP_DIR_NAME}"/themes "$TEMPDIR" ((checkCount++)) else [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Symbolic link to ${WORKING_PATH}/${APP_DIR_NAME}/themes exists" ((checkCount++)) fi # Create symbolic link to local help page if [ ! -L "${WORKING_PATH}/${APP_DIR_NAME}/CloverThemeManagerApp/help/add_theme.html" ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Creating symbolic link to ${WORKING_PATH}/${APP_DIR_NAME}/CloverThemeManagerApp/help/add_theme.html" ln -s "${WORKING_PATH}/${APP_DIR_NAME}"/CloverThemeManagerApp/help/add_theme.html "$TEMPDIR" ((checkCount++)) else [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Symbolic link to ${WORKING_PATH}/${APP_DIR_NAME}/CloverThemeManagerApp/help/add_theme.html exists" ((checkCount++)) fi # Create symbolic links for scripts dir files, except cloverthememanager.js which is copied to tmp earlier on local filecount=0 for f in "$JSSCRIPTS_DIR"/* do if [ "${f##*/}" != "cloverthememanager.js" ]; then if [ ! -L "$f" ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Creating symbolic link to $f" ln -s "$f" "$TEMPDIR"/scripts ((checkCount++)) else [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Symbolic link to $f exists" fi ((filecount++)) fi done # Create symbolic links for styles dir if [ ! -L "${PUBLIC_DIR}/styles" ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Creating symbolic link to ${PUBLIC_DIR}/styles" ln -s "${PUBLIC_DIR}/styles" "$TEMPDIR" ((checkCount++)) else [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Symbolic link to ${PUBLIC_DIR}/styles exists" ((checkCount++)) fi # Create symbolic links for assets dir if [ ! -L "${PUBLIC_DIR}/assets" ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Creating symbolic link to ${PUBLIC_DIR}/assets" ln -s "${PUBLIC_DIR}/assets" "$TEMPDIR" ((checkCount++)) else [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Symbolic link to ${PUBLIC_DIR}/assets exists" ((checkCount++)) fi # Add messages in to log for initialise.js to detect. local countToMatch=$(( 4 + filecount )) if [ $checkCount -eq $countToMatch ]; then WriteToLog "CTM_SymbolicLinksOK" else WriteToLog "CTM_SymbolicLinksFail" fi } # --------------------------------------------------------------------------------------- SendToUIUVersionedDir() { echo "${1}" >> "$logBashToJsVersionedDir" } # --------------------------------------------------------------------------------------- FindStringInPlist() { # Check if file contains carriage returns (CR) as opposed to Line Feed (LF) checkForCR=$( tr -cd '\r' < "$2" | wc -c ) if [ $checkForCR -gt 0 ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}${2##*/} contains carriage returns (CR)" local a=$( cat -v "$2" ) local b="${a##*${1}}" local c="${b%%*}" local string="${c##*}" else local string=$( grep -A 1 "${1}" "${2}" | head -n 2 | tail -2 | sed 1d | sed -e 's/<\/string>//g' ) fi string=${string#*} echo "$string" } # --------------------------------------------------------------------------------------- FindStringInPlistVariable() { local string=$( echo "${2}" | grep -A 1 "${1}" | head -n 2 | tail -2 | sed 1d | sed -e 's/<\/string>//g' ) string=${string#*} echo "$string" } # --------------------------------------------------------------------------------------- RemoveFile() { if [ -f "$1" ]; then rm "$1" fi } # --------------------------------------------------------------------------------------- CalculateMd5() { local hash=$( md5 "$1" ) echo "${hash##*= }" } # --------------------------------------------------------------------------------------- ResetNewlyInstalledThemeVars() { # Reset vars for newly installed theme gNewInstalledThemeName="" gNewInstalledThemePath="" gNewInstalledThemePathDevice="" gNewinstalledThemePartitionGUID="" } # --------------------------------------------------------------------------------------- ResetUnInstalledThemeVars() { # Reset vars for newly installed theme gUnInstalledThemeName="" gUnInstalledThemePath="" gUnInstalledThemePathDevice="" gUninstalledThemePartitionGUID="" } # --------------------------------------------------------------------------------------- ResetInternalThemeArrays() { # Reset arrays for newly installed theme unset installedThemeName unset installedThemePath unset installedThemePathDevice unset installedThemePartitionGUID } # --------------------------------------------------------------------------------------- ResetInternalDiskArrays() { # Reset arrays for newly installed theme unset duIdentifier unset duVolumeName unset duVolumeMountPoint unset duContent unset duPartitionGuid unset themeDirPaths } # --------------------------------------------------------------------------------------- RenameInternalESPMountPointToEFI() { #[[ DEBUG -eq 1 ]] && WriteLinesToLog #[[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}RenameInternalESPMountPointToEFI()" # Rename internal ESP internal mountpoint in supplied path to EFI if [[ "$1" == *"$gESPMountPrefix"* ]]; then local tmpVolume="${1%/EFI*}" local tmpPath="${1##*$tmpVolume}" local finalPath="/Volumes/EFI${tmpPath}" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Renaming for UI $1 to $finalPath" else finalPath="$1" fi echo "$finalPath" } # --------------------------------------------------------------------------------------- MaintainInstalledThemeListInPrefs() { # This routine creates the InstalledThemes array which is # then written to the user's preferences file. # The InstalledThemes array keeps track of the current state # of all theme installations done by this application. # It also records the update state of each installed theme. # When themes are UnInstalled/deleted by the user, the pref # entry is also removed. [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}MaintainInstalledThemeListInPrefs()" chmod 755 "$gUserPrefsFile".plist openArray="" closeArray="" openDict="" closeDict="" local themeToAppend=0 InsertDictionaryIntoArray() { local passedPath="$1" local passedDevice="$2" local passedUuid="$3" local passedUpdate="$4" # Rename any ESP internal mountpoint to EFI passedPath=$( RenameInternalESPMountPointToEFI "$passedPath" ) # open dictionary arrayString="${arrayString}$openDict" # Add theme entries arrayString="${arrayString}ThemePath" arrayString="${arrayString}$passedPath" arrayString="${arrayString}ThemePathDevice" arrayString="${arrayString}$passedDevice" arrayString="${arrayString}VolumeUUID" arrayString="${arrayString}$passedUuid" #arrayString="${arrayString}UpdateAvailable" #arrayString="${arrayString}$passedUpdate" # close dictionary arrayString="${arrayString}$closeDict" } # Is there a newly installed theme to add? # And on a partition with a unique partition GUID? if [ "$gNewInstalledThemeName" != "" ] && [ "$gNewinstalledThemePartitionGUID" != "$zeroUUID" ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Newly installed theme to be added to prefs: $gNewInstalledThemeName" # Is this new theme already installed elsewhere? for ((n=0; n<${#installedThemeName[@]}; n++ )); do if [ "$gNewInstalledThemeName" == "${installedThemeName[$n]}" ]; then themeToAppend=1 [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}$gNewInstalledThemeName is already in prefs - will append to entry" break fi done fi # Is there an UnInstalled theme to remove? local dontReAddThemeId=9999 if [ "$gUnInstalledThemeName" != "" ] && [ "$gNewinstalledThemePartitionGUID" != "$zeroUUID" ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}UnInstalled theme to be removed: $gUnInstalledThemeName" # Check for ESP mountpoint local pathToCheck if [[ "$gUnInstalledThemePath" == *$gESPMountPrefix* ]]; then local tmpStrip="${themeDirPaths[$entry]#*/}" tmpStrip="${tmpStrip#*/}" tmpStrip="${tmpStrip#*/}" pathToCheck="/Volumes/EFI/${tmpStrip}" else pathToCheck="$gUnInstalledThemePath" fi # Loop though array of installed themes to find ID of theme to remove. for ((n=0; n<${#installedThemeName[@]}; n++ )); do if [ "${installedThemeName[$n]}" == "$gUnInstalledThemeName" ] && [ "${installedThemePath[$n]}" == "$pathToCheck" ] && \ [ "${installedThemePartitionGUID[$n]}" == "$gUninstalledThemePartitionGUID" ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Will remove ${installedThemeName[$n]},${installedThemePath[$n]},${installedThemePartitionGUID[$n]}" dontReAddThemeId=$n ResetUnInstalledThemeVars break fi done fi # Construct InstalledThemes array arrayString="" lastAddedThemeName="" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Updating InstalledThemes prefs" for ((n=0; n<${#installedThemeName[@]}; n++ )); do # Don't write back a theme if marked to be removed if [ $n -ne $dontReAddThemeId ]; then # Housekeeping can change a theme name to a dash. # This indicates the theme entry in no longer required. if [ "${installedThemeName[$n]}" != "-" ]; then # Add theme key if [ "${installedThemeName[$n]}" != "$lastAddedThemeName" ]; then # Check if there's a newly installed theme to append to this current array if [ $themeToAppend -eq 1 ] && [ "$lastAddedThemeName" == "$gNewInstalledThemeName" ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Appending $gNewInstalledThemeName dictionary to existing array." InsertDictionaryIntoArray "$gNewInstalledThemePath" "$gNewInstalledThemePathDevice" "$gNewinstalledThemePartitionGUID" "" themeToAppend=0 ResetNewlyInstalledThemeVars fi # close any previous arrays if [ "$lastAddedThemeName" != "" ]; then arrayString="${arrayString}$closeArray" fi # Write new theme key arrayString="${arrayString}${installedThemeName[$n]}" # open array arrayString="${arrayString}$openArray" lastAddedThemeName="${installedThemeName[$n]}" fi InsertDictionaryIntoArray "${installedThemePath[$n]}" "${installedThemePathDevice[$n]}" "${installedThemePartitionGUID[$n]}" fi fi done # Did the loop finish before appending a newly installed theme to an existing them entry? # Check if there's a newly installed theme to append to this current array if [ $themeToAppend -eq 1 ] && [ "$lastAddedThemeName" == "$gNewInstalledThemeName" ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Append didn't happen. Attempting to appending $gNewInstalledThemeName now." InsertDictionaryIntoArray "$gNewInstalledThemePath" "$gNewInstalledThemePathDevice" "$gNewinstalledThemePartitionGUID" themeToAppend=0 ResetNewlyInstalledThemeVars fi # Was the above loop run? if [ "$lastAddedThemeName" != "" ]; then # close array arrayString="${arrayString}$closeArray" fi # Did the newly installed theme get appended? If not then it needs adding at end. if [ "$gNewInstalledThemeName" != "" ]; then # Write new theme key arrayString="${arrayString}${gNewInstalledThemeName}" # open array arrayString="${arrayString}$openArray" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Append still hasn't completed. Appending $gNewInstalledThemeName now." InsertDictionaryIntoArray "$gNewInstalledThemePath" "$gNewInstalledThemePathDevice" "$gNewinstalledThemePartitionGUID" # close array arrayString="${arrayString}$closeArray" lastAddedThemeName="$gNewInstalledThemeName" ResetNewlyInstalledThemeVars fi # Delete existing and write new InstalledThemes prefs key [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Removing previous InstalledThemes array from prefs file" defaults delete "$gUserPrefsFile" "InstalledThemes" # Only add back if there's something to write. if [ "$lastAddedThemeName" != "" ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Inserting InstalledThemes array in to prefs file" defaults write "$gUserPrefsFile" InstalledThemes -array "$openDict$arrayString$closeDict" fi chmod 755 "$gUserPrefsFile".plist ReadPrefsFile } # --------------------------------------------------------------------------------------- UpdatePrefsKey() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}UpdatePrefsKey()" local passedKey="$1" local passedValue="$2" # Rename any ESP internal mountpoint to EFI if [ "$passedKey" == "LastSelectedPath" ]; then passedValue=$( RenameInternalESPMountPointToEFI "$passedValue" ) fi if [ -f "$gUserPrefsFile".plist ]; then defaults delete "$gUserPrefsFile" "$passedKey" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Writing prefs key $passedKey = $passedValue" defaults write "$gUserPrefsFile" "$passedKey" "$passedValue" else WriteToLog "Error! ${gUserPrefsFile}.plist not found." fi } # --------------------------------------------------------------------------------------- ClearTopOfMessageLog() { # removes the first line of the log file. local log=$(tail -n +2 "$1"); > "$1" && if [ "$log" != "" ]; then echo "$log" > "$1"; fi } # --------------------------------------------------------------------------------------- RunThemeAction() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}RunThemeAction()" local passedAction="$1" # Will be either Install, UnInstall or Update local themeTitleToActOn="$2" local successFlag=1 CheckPathIsWriteable "${TARGET_THEME_DIR}" local isPathWriteable=$? # 1 = not writeable / 0 = writeable case "$passedAction" in "Install") WriteToLog "Installing theme $themeTitleToActOn to ${TARGET_THEME_DIR}" local successFlag=1 # Only clone the theme from the Clover repo if not already installed # in which case the bare repo will already be in the local support dir. if [ ! -d "${WORKING_PATH}/${APP_DIR_NAME}"/"$themeTitleToActOn".git ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Creating a bare git clone of $themeTitleToActOn" local themeNameWithSpacesFixed=$( echo "$themeTitleToActOn" | sed 's/ /%20/g' ) cd "${WORKING_PATH}/${APP_DIR_NAME}" feedbackCheck=$("$gitCmd" clone --progress --depth=1 --bare "$remoteRepositoryUrl"/themes.git/themes/"${themeNameWithSpacesFixed}"/theme.git "$themeTitleToActOn".git 2>&1 ) [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Install git clone: $feedbackCheck" else WriteToLog "Bare git clone of $themeTitleToActOn already exists. Will checkout from that." fi if [ -d "${WORKING_PATH}/${APP_DIR_NAME}"/"$themeTitleToActOn".git ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Checking out bare git clone of ${themeTitleToActOn}." # Theme currently gets checked out as /path/to/EFI/Clover/Themes//themes// # Desired path is /path/to/EFI/Clover/Themes/ # So checkout to a directory for unpacking first. if [ -d "$UNPACKDIR" ]; then cd "${WORKING_PATH}/${APP_DIR_NAME}" feedbackCheck=$("$gitCmd" --git-dir="$themeTitleToActOn".git --work-tree="$UNPACKDIR" checkout . 2>&1 ) [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}checkout .: $feedbackCheck" feedbackCheck=$("$gitCmd" --git-dir="$themeTitleToActOn".git --work-tree="$UNPACKDIR" checkout HEAD -- 2>&1 ) && successFlag=0 [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}checkout HEAD --: $feedbackCheck" else [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Error. UnPack dir does not exist." fi # Read current hash from packed-refs file. local currentThemeHash=$( cat "${WORKING_PATH}/${APP_DIR_NAME}"/"$themeTitleToActOn".git/packed-refs | grep refs/heads/master ) currentThemeHash="${currentThemeHash% refs*}" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}hash=$currentThemeHash" fi if [ ${successFlag} -eq 0 ]; then # Write hash to file in to unpacked theme dir. local addFile=0 [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Writing hash to ${UNPACKDIR}/themes/${themeTitleToActOn}/.hash" echo $currentThemeHash > "$UNPACKDIR"/themes/"$themeTitleToActOn"/.hash && addFile=1 if [ $addFile -eq 1 ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Added hash successfully" chmod 755 "$UNPACKDIR"/themes/"$themeTitleToActOn"/.hash && [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Set hash file permissions" # Enable glob to match dot files. shopt -s dotglob fi # Delete theme.git dir from theme if [ -d "$UNPACKDIR"/themes/"$themeTitleToActOn"/theme.git ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Removing theme.git directory from ${UNPACKDIR}/themes/${themeTitleToActOn}" rm -rf "$UNPACKDIR"/themes/"$themeTitleToActOn"/theme.git fi # Create theme dir on target and move unpacked theme files to the target dir. targetThemeDir="${TARGET_THEME_DIR}"/"$themeTitleToActOn" if [ $isPathWriteable -eq 1 ]; then # Not Writeable if [ $(CheckOsVersion) -ge 13 ]; then successFlag=$( /usr/bin/osascript -e 'tell application "SecurityAgent" to activate'; \ /usr/bin/osascript -e "do shell script \"$uiSudoChanges \" & \"‡Move\" & \"‡$targetThemeDir\" & \"‡$UNPACKDIR\" & \"‡$themeTitleToActOn\" with administrator privileges" ) else successFlag=$( /usr/bin/osascript -e "do shell script \"$uiSudoChanges \" & \"‡Move\" & \"‡$targetThemeDir\" & \"‡$UNPACKDIR\" & \"‡$themeTitleToActOn\" with administrator privileges" ) fi else chckDir=0 mkdir "$targetThemeDir" && chckDir=1 if [ $chckDir -eq 1 ]; then # Move unpacked files to target theme path. cd "$UNPACKDIR"/themes if [ -d "$themeTitleToActOn" ]; then mv "$themeTitleToActOn"/* "$targetThemeDir" && WriteToLog "Installation was successful." && successFlag=0 fi fi fi # Remove the unpacked files. if [ -d "$UNPACKDIR"/themes ]; then rm -rf "$UNPACKDIR"/themes fi # Disable glob to match dot files. shopt -u dotglob fi ;; "UnInstall") WriteToLog "Deleting ${TARGET_THEME_DIR}/$themeTitleToActOn" # Check if theme needs elevated privileges to remove CheckPathIsWriteable "${TARGET_THEME_DIR}/$themeTitleToActOn" local isPathWriteable=$? # 1 = not writeable / 0 = writeable if [ $isPathWriteable -eq 1 ]; then # Not Writeable if [ $(CheckOsVersion) -ge 13 ]; then successFlag=$( /usr/bin/osascript -e 'tell application "SecurityAgent" to activate'; \ /usr/bin/osascript -e "do shell script \"$uiSudoChanges \" & \"‡UnInstall\" & \"‡${TARGET_THEME_DIR}\" & \"‡$themeTitleToActOn\" with administrator privileges" ) else successFlag=$( /usr/bin/osascript -e "do shell script \"$uiSudoChanges \" & \"‡UnInstall\" & \"‡${TARGET_THEME_DIR}\" & \"‡$themeTitleToActOn\" with administrator privileges" ) fi else cd "${TARGET_THEME_DIR}" if [ -d "$themeTitleToActOn" ]; then rm -rf "$themeTitleToActOn" && WriteToLog "Deletion was successful." && successFlag=0 fi fi ;; "Update") WriteToLog "Updating ${TARGET_THEME_DIR}/$themeTitleToActOn" # Save current path local currentPath=$( pwd ) # Check if bare git repo for this theme exists and delete if yes. if [ -d "${WORKING_PATH}/${APP_DIR_NAME}"/"$themeTitleToActOn".git ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}bare repo for $themeTitleToActOn exists. Deleting" cd "${WORKING_PATH}/${APP_DIR_NAME}" rm -rf "$themeTitleToActOn".git fi # Clone theme from repo. [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Creating a bare git clone of $themeTitleToActOn" local themeNameWithSpacesFixed=$( echo "$themeTitleToActOn" | sed 's/ /%20/g' ) cd "${WORKING_PATH}/${APP_DIR_NAME}" feedbackCheck=$("$gitCmd" clone --progress --depth=1 --bare "$remoteRepositoryUrl"/themes.git/themes/"${themeNameWithSpacesFixed}"/theme.git "$themeTitleToActOn".git 2>&1 ) [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Install git clone: $feedbackCheck" # Checkout the bare repo to the unpack dir then replace on target dir. if [ -d "${TARGET_THEME_DIR}"/"$themeTitleToActOn" ] && [ -d "${WORKING_PATH}/${APP_DIR_NAME}"/"$themeTitleToActOn".git ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Force checking out bare git clone of ${themeTitleToActOn}." cd "${WORKING_PATH}/${APP_DIR_NAME}" feedbackCheck=$("$gitCmd" --git-dir="$themeTitleToActOn".git --work-tree="$UNPACKDIR" checkout --force 2>&1) && successFlag=0 [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}checkout git clone: $feedbackCheck" if [ $successFlag -eq 0 ]; then # Read current hash from packed-refs file. local currentThemeHash=$( cat "${WORKING_PATH}/${APP_DIR_NAME}"/"$themeTitleToActOn".git/packed-refs | grep refs/heads/master ) currentThemeHash="${currentThemeHash:0:40}" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}hash=$currentThemeHash" # Write hash to file in to unpacked theme dir. local addFile=0 [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Writing hash to ${UNPACKDIR}/themes/${themeTitleToActOn}/.hash" echo $currentThemeHash > "$UNPACKDIR"/themes/"$themeTitleToActOn"/.hash && addFile=1 if [ $addFile -eq 1 ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Added hash successfully" chmod 755 "$UNPACKDIR"/themes/"$themeTitleToActOn"/.hash && [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Set hash file permissions" # Enable glob to match dot files. shopt -s dotglob fi # Delete theme.git dir from theme if [ -d "$UNPACKDIR"/themes/"$themeTitleToActOn"/theme.git ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Removing theme.git directory from ${UNPACKDIR}/themes/${themeTitleToActOn}" rm -rf "$UNPACKDIR"/themes/"$themeTitleToActOn"/theme.git fi targetThemeDir="${TARGET_THEME_DIR}"/"$themeTitleToActOn" if [ $isPathWriteable -eq 1 ]; then # Not Writeable if [ $(CheckOsVersion) -ge 13 ]; then successFlag=$( /usr/bin/osascript -e 'tell application "SecurityAgent" to activate'; \ /usr/bin/osascript -e "do shell script \"$uiSudoChanges \" & \"‡Update\" & \"‡$targetThemeDir\" & \"‡$UNPACKDIR\" & \"‡$themeTitleToActOn\" with administrator privileges" ) else successFlag=$( /usr/bin/osascript -e "do shell script \"$uiSudoChanges \" & \"‡Update\" & \"‡$targetThemeDir\" & \"‡$UNPACKDIR\" & \"‡$themeTitleToActOn\" with administrator privileges" ) fi else if [ -d "$targetThemeDir" ]; then chckDir=0 [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Removing existing $targetThemeDir files" rm -rf "$targetThemeDir"/* && chckDir=1 if [ $chckDir -eq 1 ]; then # Move unpacked files to target theme path. cd "$UNPACKDIR"/themes if [ -d "$themeTitleToActOn" ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Moving updated $themeTitleToActOn theme files to $targetThemeDir" mv "$themeTitleToActOn"/* "$targetThemeDir" && WriteToLog "Updating was successful." && successFlag=0 fi fi fi fi # Remove the unpacked files. if [ -d "$UNPACKDIR"/themes ]; then rm -rf "$UNPACKDIR"/themes fi # Disable glob to match dot files. shopt -u dotglob fi fi # change back to previous directory cd "$currentPath" ;; esac # Was operation a success? if [ $successFlag -eq 0 ]; then if [ $COMMANDLINE -eq 0 ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}$themeTitleToActOn : ${passedAction} : Success" #[[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Sending UI: Success@${passedAction}@$themeTitleToActOn" #SendToUI "Success@${passedAction}@$themeTitleToActOn" if [ "$passedAction" == "Install" ] && [ "$TARGET_THEME_PARTITIONGUID" != "$zeroUUID" ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Saving settings for newly installed theme." SendToUI "Success‡${passedAction}‡$themeTitleToActOn" # Save new theme details for adding to prefs file gNewInstalledThemeName="$themeTitleToActOn" gNewInstalledThemePath="$TARGET_THEME_DIR" gNewInstalledThemePathDevice="$TARGET_THEME_DIR_DEVICE" gNewinstalledThemePartitionGUID="$TARGET_THEME_PARTITIONGUID" fi if [ "$passedAction" == "UnInstall" ] && [ "$TARGET_THEME_PARTITIONGUID" != "$zeroUUID" ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Saving settings for UnInstalled theme." SendToUI "Success‡${passedAction}‡$themeTitleToActOn" # Save new theme details for adding to prefs file gUnInstalledThemeName="$themeTitleToActOn" gUnInstalledThemePath="$TARGET_THEME_DIR" gUnInstalledThemePathDevice="$TARGET_THEME_DIR_DEVICE" gUninstalledThemePartitionGUID="$TARGET_THEME_PARTITIONGUID" fi # Record what theme was installed where. MaintainInstalledThemeListInPrefs if [ "$passedAction" == "UnInstall" ]; then # Delete .git from local support directory if no longer needed CheckIfThemeNoLongerInstalledThenDeleteLocalTheme "$themeTitleToActOn" fi fi return 0 else if [ $COMMANDLINE -eq 0 ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}$themeTitleToActOn : ${passedAction} : Fail" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Sending UI: Fail@${passedAction}@$themeTitleToActOn" SendToUI "Fail‡${passedAction}‡$themeTitleToActOn" fi return 1 fi } # --------------------------------------------------------------------------------------- CreateThemeListHtml() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}CreateThemeListHtml()" # Build html for each theme. [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Creating html theme list." [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Number of theme titles=${#themeTitle[@]}" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Number of theme description=${#themeDescription[@]}" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Number of theme author=${#themeAuthor[@]}" local imageFormat="png" if [ ${#themeTitle[@]} -eq ${#themeDescription[@]} ] && [ ${#themeTitle[@]} -eq ${#themeAuthor[@]} ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Found ${#themeTitle[@]} Titles, Descriptions and Authors" for ((n=0; n<${#themeTitle[@]}; n++ )); do [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Creating html for ${themeTitle[$n]} theme" themeHtml="$themeHtml"$(printf "
\r") themeHtml="$themeHtml"$(printf "
\r") if [ -f "${TEMPDIR}/themes/${themeTitle[$n]}/Theme.svg" ]; then themeHtml="$themeHtml"$(printf "
\r") elif [ -f "${TEMPDIR}/themes/${themeTitle[$n]}/screenshot.$imageFormat" ]; then themeHtml="$themeHtml"$(printf "
\r") fi themeHtml="$themeHtml"$(printf "

${themeTitle[$n]}
${themeDescription[$n]}
${themeAuthor[$n]}

\r") themeHtml="$themeHtml"$(printf "
\r") themeHtml="$themeHtml"$(printf "
\r") themeHtml="$themeHtml"$(printf "
\r") themeHtml="$themeHtml"$(printf "
\r") if [ -f "${TEMPDIR}/themes/${themeTitle[$n]}/Theme.svg" ]; then themeHtml="$themeHtml"$(printf "
\r") elif [ -f "${TEMPDIR}/themes/${themeTitle[$n]}/screenshot.$imageFormat" ]; then themeHtml="$themeHtml"$(printf "
\r") fi themeHtml="$themeHtml"$(printf "\r") done WriteToLog "CTM_ThemeListOK" else [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Error: Title(${#themeTitle[@]}), Author(${#themeAuthor[@]}), Description(${#themeDescription[@]}) mismatch." for ((n=0; n<${#themeTitle[@]}; n++ )); do [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}$n : ${themeTitle[$n]} | ${themeDescription[$n]} | ${themeAuthor[$n]}" done WriteToLog "CTM_ThemeListFail" fi } # --------------------------------------------------------------------------------------- InsertThemeListHtmlInToManageThemes() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}InsertThemeListHtmlInToManageThemes()" local passedOptionalCommand="$1" local check=1 if [ "$passedOptionalCommand" == "file" ]; then # Read previously saved file themeHtml=$( cat "${WORKING_PATH}/${APP_DIR_NAME}"/theme.html ) # Escape all ampersands themeHtml=$( echo "$themeHtml" | sed 's/&/\\\&/g' ); else # Use internal string var # Escape forward slashes themeHtml=$( echo "$themeHtml" | sed 's/\//\\\//g' ) # Save html to file echo "$themeHtml" > "${WORKING_PATH}/${APP_DIR_NAME}"/theme.html fi # Insert Html in to placeholder [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Inserting HTML in to managethemes.html" LANG=C sed -ie "s//${themeHtml}/g" "${TEMPDIR}"/managethemes.html && check=0 # Clean up if [ -f "${TEMPDIR}"/managethemes.htmle ]; then rm "${TEMPDIR}"/managethemes.htmle fi # Add messages in to log for initialise.js to detect. if [ $check -eq 0 ]; then WriteToLog "CTM_InsertHtmlOK" else WriteToLog "CTM_InsertHtmlFail" fi } # --------------------------------------------------------------------------------------- SetControlOptionHtmlSections() { local disabledConfigPlist="" local nvramText="" local configPlistText="" if [ "$gNvramPlistFullPath" == "Native NVRAM" ]; then nvramText="Native" else if [ ! "$gNvramPlistFullPath" == "" ]; then # nvram.plist found in bootlog nvramText="using file nvram.plist" fi fi if [ -f "$gConfigPlistFullPath" ]; then configPlistText=$( RenameInternalESPMountPointToEFI "$gConfigPlistFullPath" ) else configPlistText="$gConfigPlistFullPath" disabledConfigPlist="disabled" fi # Escape paths nvramText=$( echo "$nvramText" | sed 's/\//\\\//g' ) configPlistText=$( echo "$configPlistText" | sed 's/\//\\\//g' ) # Set html sections ctOuterOpen=$(printf "
\r") ctOpen=$(printf "
\r") ctOpenTitle=$(printf "
\r") ctBandTitle=$(printf "
Set which theme to use next boot. (Note: Any NVRAM entry will take precedence over config.plist)<\/div>\r") # Build NVRAM band ctBandNvram=$(printf "
NVRAM:<\/div>\r") ctBandNvram="$ctBandNvram"$(printf "
${nvramText}<\/div>\r") # UEFI boot with Native NVRAM or Legacy boot AND Launch Daemon & rc scripts working if [[ "$gNvramPlistFullPath" == "Native NVRAM" ]] || [[ "$gBootType" == "Legacy" && $gNvramSave -eq 0 ]]; then ctBandNvram="$ctBandNvram"$(printf "
Selected Theme:<\/div>\r") ctBandNvram="$ctBandNvram"$(printf " \r") ctBandConfig="$ctBandConfig"$(printf " \r") ctBandConfig="$ctBandConfig"$(printf " <\/select>\r") # Build next boot band ctNextBootTheme=$(printf "
PREDICTION:<\/div>\r") ctNextBootTheme="$ctNextBootTheme"$(printf "
Theme to be used for next boot from device $TARGET_THEME_DIR_DEVICE<\/div>\r") ctNextBootTheme="$ctNextBootTheme"$(printf "
Entry:<\/div>\r") ctNextBootTheme="$ctNextBootTheme"$(printf "
\r") ctNextBootTheme="$ctNextBootTheme"$(printf " <\/span>\r") ctNextBootTheme="$ctNextBootTheme"$(printf " <\/div> \r") ctClose=$(printf " <\/div> \r") ctOuterClose=$(printf " <\/div> ") } # --------------------------------------------------------------------------------------- CreateControlOptionsHtmlAndInsert() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}CreateControlOptionsHtmlAndInsert()" local check=1 SetControlOptionHtmlSections local controlOptionsHtml="${ctOuterOpen}" # Add section title band controlOptionsHtml="${controlOptionsHtml}${ctOpenTitle}${ctBandTitle}${ctClose}" # Add nvram control band if UEFI boot with Native NVRAM or Legacy boot AND Launch Daemon & rc scripts working #if [[ "$gNvramPlistFullPath" == "Native NVRAM" ]] || [[ "$gBootType" == "Legacy" && $gNvramSave -eq 0 ]]; then # controlOptionsHtml="${controlOptionsHtml}${ctOpen}${ctBandNvram}${ctClose}" #fi # Add nvram.plist control band if not using Native NVRAM AND Launch Daemon & rc scripts are not working #if [ "$gNvramPlistFullPath" != "" ] && [ "$gNvramPlistFullPath" != "Native NVRAM" ] && [ $gNvramSave -eq 1 ]; then # controlOptionsHtml="${controlOptionsHtml}${ctOpen}${ctBandNvramP}${ctClose}" #fi controlOptionsHtml="${controlOptionsHtml}${ctOpen}${ctBandNvram}${ctClose}" # Add config.plist control band if [ "$gConfigPlistFullPath" != "" ]; then controlOptionsHtml="${controlOptionsHtml}${ctOpen}${ctBandConfig}${ctClose}" fi # Add next boot theme prediction band if [ "$gConfigPlistFullPath" != "" ]; then controlOptionsHtml="${controlOptionsHtml}${ctOpen}${ctNextBootTheme}${ctClose}" fi controlOptionsHtml="${controlOptionsHtml}${ctOuterClose}" # Insert control options band Html in to placeholder [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Inserting control options band HTML in to managethemes.html" LANG=C sed -ie "s//${controlOptionsHtml}/g" "${TEMPDIR}"/managethemes.html && check=0 # Clean up if [ -f "${TEMPDIR}"/managethemes.htmle ]; then rm "${TEMPDIR}"/managethemes.htmle fi # Add messages in to log for initialise.js to detect. if [ $check -eq 0 ]; then WriteToLog "CTM_ControlOptionsOK" else WriteToLog "CTM_ControlOptionsFail" fi } # --------------------------------------------------------------------------------------- InsertNotificationCodeInToJS() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}InsertNotificationCodeInToJS()" local check=1 codeToInsert="macgap.notice.notify({ title: 'Clover Theme Manager', content: messageBody, sound: true});" # Insert Html in to placeholder [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Inserting JS notification code in to cloverthememanager.js" LANG=C sed -ie "s/\/\/ INSERT_NOTIFICATION_CODE_HERE/${codeToInsert}/g" "${TEMPDIR}"/scripts/cloverthememanager.js && check=0 # Clean Up if [ -f "${TEMPDIR}"/scripts/cloverthememanager.jse ]; then rm "${TEMPDIR}"/scripts/cloverthememanager.jse fi # Add messages in to log for initialise.js to detect. if [ $check -eq 0 ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Inserting notification code was successful." else [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Inserting notification code failed." fi } # --------------------------------------------------------------------------------------- CheckOsVersion() { local osVer=$( uname -r ) echo ${osVer%%.*} } # ======================================================================================= # Routines for checking ownership and elevating privileges, if necessary # ======================================================================================= # --------------------------------------------------------------------------------------- ResolveVolumePathFromGUID() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}ResolveVolumePathFromGUID()" # Resolve volume path from GUID local volumePath="" # MBR partition scheme does not use GUID's so check if [ "$1" != "$zeroUUID" ]; then for (( u=0; u<${#themeDirPaths[@]}; u++ )) do [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Matching ${duPartitionGuid[$u]} : $1" if [[ "${duPartitionGuid[$u]}" == "$1" ]]; then volumePath="${themeDirPaths[$u]}" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Match: Volume Path=$volumePath" break fi done else volumePath="" fi echo "$volumePath" } # --------------------------------------------------------------------------------------- CheckPathIsWriteable() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}CheckPathIsWriteable()" local passedMountPoint="$1" local isWriteable=1 if [ "$passedMountPoint" != "" ]; then touch "$passedMountPoint"/.test 2>/dev/null && rm -f "$passedMountPoint"/.test || isWriteable=0 fi if [ $isWriteable -eq 0 ]; then return 1 else return 0 fi } # --------------------------------------------------------------------------------------- FindArrayIdFromTarget() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}FindArrayIdFromTarget()" local success=0 for ((a=0; a<${#duIdentifier[@]}; a++)) do [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Does ${duPartitionGuid[$a]}=${TARGET_THEME_PARTITIONGUID} && ${themeDirPaths[$a]}=${TARGET_THEME_DIR}" if [ "${duPartitionGuid[$a]}" == "${TARGET_THEME_PARTITIONGUID}" ] && [ "${themeDirPaths[$a]}" == "${TARGET_THEME_DIR}" ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Match found. Returning $a" echo $a success=1 break fi done [[ $success -eq 0 ]] && echo - } # ======================================================================================= # Initialisation Routines # ======================================================================================= # --------------------------------------------------------------------------------------- ReadRepoUrlList() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}ReadRepoUrlList()" WriteToLog "Looking for URL list" if [ -f "$gThemeRepoUrlFile" ]; then WriteToLog "Reading URL list" oIFS="$IFS"; IFS=$'\n' while read -r line do if [ ! "${line:0:1}" == "#" ]; then WriteToLog "Found URL $line" repositoryUrls+=( "${line##*#}" ) fi done < "$gThemeRepoUrlFile" IFS="$oIFS" WriteToLog "Number of repositories found: ${#repositoryUrls[@]}" else WriteToLog "$gThemeRepoUrlFile not found." fi } # --------------------------------------------------------------------------------------- RefreshHtmlTemplates() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}RefreshHtmlTemplates()" passedTemplate="$1" local check=1 # For now remove previous managethemes.html and copy template if [ -f "${PUBLIC_DIR}"/$passedTemplate ]; then if [ -f "${PUBLIC_DIR}"/$passedTemplate.template ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Setting $passedTemplate to default." rm "${PUBLIC_DIR}"/$passedTemplate #cp "${PUBLIC_DIR}"/$passedTemplate.template "${PUBLIC_DIR}"/$passedTemplate && check=0 cp "${PUBLIC_DIR}"/$passedTemplate.template "${TEMPDIR}"/$passedTemplate && check=0 else [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Error: missing ${PUBLIC_DIR}/$passedTemplate.template" fi else [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Creating: $passedTemplate" #cp "${PUBLIC_DIR}"/$passedTemplate.template "${PUBLIC_DIR}"/$passedTemplate && check=0 cp "${PUBLIC_DIR}"/$passedTemplate.template "${TEMPDIR}"/$passedTemplate && check=0 fi # Add message in to log for initialise.js to detect. if [ $check -eq 0 ]; then WriteToLog "CTM_HTMLTemplateOK" else WriteToLog "CTM_HTMLTemplateFail" fi } # --------------------------------------------------------------------------------------- IsRepositoryLive() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}IsRepositoryLive()" local noConnection=1 #local gitRepositoryUrl=$( echo ${remoteRepositoryUrl}/ | sed 's/http:/git:/' ) local gitRepositoryUrl=$remoteRepositoryUrl WriteToLog "CTM_RepositoryCheckNetwork" WriteToLog "CTM_RepositoryChecking" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Connecting to ${gitRepositoryUrl}/themes" local testConnection=$( "$gitCmd" ls-remote ${gitRepositoryUrl}/themes ) [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}$testConnection" if [ "$testConnection" ]; then WriteToLog "CTM_RepositorySuccess" else WriteToLog "${debugIndentTwo}git ls-remote failed: $testConnection" noConnection=0 fi if [ $noConnection -eq 0 ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Cannot contact the Repository ${gitRepositoryUrl}/themes" WriteToLog "CTM_RepositoryError" # initialise.js should pick this up, notify the user, then quit. exit 1 fi } # --------------------------------------------------------------------------------------- EnsureLocalSupportDir() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}EnsureLocalSupportDir()" # Check for local support directory local pathToCreate="${WORKING_PATH}/${APP_DIR_NAME}" if [ ! -d "$pathToCreate" ]; then WriteToLog "Creating $pathToCreate" mkdir -p "$pathToCreate" fi # Create unpacking directory for checking out cloned bare theme repo's # from clover repo. This is because the themes checkout as: # /path/to/EFI/Clover/Themes//themes// if [ ! -d "$UNPACKDIR" ]; then mkdir "$UNPACKDIR" fi # Add message in to log for initialise.js to detect. if [ -d "$pathToCreate" ] && [ -d "$UNPACKDIR" ]; then WriteToLog "CTM_SupportDirOK" else WriteToLog "CTM_SupportDirFail" fi } # --------------------------------------------------------------------------------------- EnsureSymlinks() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}EnsureSymlinks()" # Rather than check if a valid one exists, it's quicker to simply re-create it. if [ -h "$ASSETS_DIR"/themes ] || [ -L "$ASSETS_DIR"/themes ]; then rm "$ASSETS_DIR"/themes fi if [ -h "$PUBLIC_DIR"/add_theme.html ] || [ -L "$PUBLIC_DIR"/add_theme.html ]; then rm "$PUBLIC_DIR"/add_theme.html fi CreateSymbolicLinks } # --------------------------------------------------------------------------------------- DownloadPublicDirFromServer() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}DownloadPublicDirFromServer()" # Remove app files from a previous run if [ -d "${WORKING_PATH}/${APP_DIR_NAME}"/CloverThemeManagerApp ]; then WriteToLog "Removing previous CloverThemeManagerApp directory" rm -rf "${WORKING_PATH}/${APP_DIR_NAME}"/CloverThemeManagerApp fi # Download public dir local success=0 local filePath="CloverThemeManagerApp/CloverThemeManager/public" local pathToWorkingPublicDir="${WORKING_PATH}/${APP_DIR_NAME}"/CloverThemeManagerApp/CloverThemeManager/public #local gitRepositoryUrl=$( echo ${remoteRepositoryUrl}/ | sed 's/http:/git:/' ) local gitRepositoryUrl=$remoteRepositoryUrl cd "${WORKING_PATH}/${APP_DIR_NAME}" "$gitCmd" archive --remote="${gitRepositoryUrl}/themes" HEAD "$filePath" | tar -x && success=1 if [ $success -eq 1 ]; then WriteToLog "Downloading app files from the repo was successful." return 0 else WriteToLog "Error. Downloading app files from the repo failed." return 1 fi } # --------------------------------------------------------------------------------------- GetLatestIndexAndEnsureThemeHtml() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}GetLatestIndexAndEnsureThemeHtml()" BuildThemeTextInformation() { # Read local theme.plists and parse author and description info. # Create array of directory list alphabetically oIFS="$IFS"; IFS=$'\r\n' themeList=( $( ls -d "${WORKING_PATH}/${APP_DIR_NAME}"/themes/* | sort -f )) [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Reading theme plists." # Read each themes' Author & Description. for ((n=0; n<${#themeList[@]}; n++ )); do tmpTitle="${themeList[$n]##*/}" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Reading theme plists for $tmpTitle" themeTitle+=("$tmpTitle") if [ -f "${WORKING_PATH}/${APP_DIR_NAME}/themes/${tmpTitle}/theme.plist" ]; then # Read theme.plist to extract Author & Description. themeAuthor+=( $(FindStringInPlist "Author" "${WORKING_PATH}/${APP_DIR_NAME}/themes/${tmpTitle}/theme.plist")) themeDescription+=( $(FindStringInPlist "Description" "${WORKING_PATH}/${APP_DIR_NAME}/themes/${tmpTitle}/theme.plist")) elif [ -f "${WORKING_PATH}/${APP_DIR_NAME}/themes/${tmpTitle}/theme.svg" ]; then # convert to unix line endings and extract Author & Description. tmpAuthor=$( tr '\r' '\n' < "${WORKING_PATH}/${APP_DIR_NAME}/themes/${tmpTitle}/theme.svg" | grep "Author=" ) tmpAuthor="${tmpAuthor#*=\"}" tmpAuthor="${tmpAuthor%*\"}" themeAuthor+=("$tmpAuthor") tmpDescription=$( tr '\r' '\n' < "${WORKING_PATH}/${APP_DIR_NAME}/themes/${tmpTitle}/theme.svg" | grep "Description=" ) tmpDescription="${tmpDescription#*=\"}" tmpDescription="${tmpDescription%*\"}" themeDescription+=("$tmpDescription") fi done IFS="$oIFS" } CloneAndCheckoutIndex() { local check=1 # Remove index.git from a previous run if [ -d "${WORKING_PATH}/${APP_DIR_NAME}"/index.git ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Removing previous index.git" rm -rf "${WORKING_PATH}/${APP_DIR_NAME}"/index.git fi # Remove any images from a previous run if [ -d "${WORKING_PATH}/${APP_DIR_NAME}"/images ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Removing previous index images directory" rm -rf "${WORKING_PATH}/${APP_DIR_NAME}"/images fi # Remove any theme.plists from a previous run if [ -d "${WORKING_PATH}/${APP_DIR_NAME}"/themes ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Removing previous index themes directory" rm -rf "${WORKING_PATH}/${APP_DIR_NAME}"/themes fi # Get new index.git from CloverRepo cd "${WORKING_PATH}/${APP_DIR_NAME}" WriteToLog "CTM_IndexCloneAndCheckout" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Cloning bare repo index.git" "$gitCmd" clone --depth=1 --bare "$remoteRepositoryUrl"/themes.git/index.git [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Checking out index.git" "$gitCmd" --git-dir="${WORKING_PATH}/${APP_DIR_NAME}"/index.git --work-tree="${WORKING_PATH}/${APP_DIR_NAME}" checkout --force && check=0 # Add message in to log for initialise.js to detect. if [ $check -eq 0 ]; then WriteToLog "CTM_IndexOK" else WriteToLog "CTM_IndexFail" fi } GetIndexAndProcessThemeList() { CloneAndCheckoutIndex BuildThemeTextInformation CreateThemeListHtml InsertThemeListHtmlInToManageThemes } if [ ! -d "${WORKING_PATH}/${APP_DIR_NAME}"/index.git ]; then GetIndexAndProcessThemeList else # Check existing index.git is not older than when repo was rebuilt # Clover Theme Repo was rebuilt on 14th December 2014. Any index.git # from before then will not fetch and needs to be deleted. # To be safe I am using 15th December 2104 as date to check. # epoch for that is calculated with: date -j -f "%d-%B-%y" 15-DEC-14 +%s # Giving epoch of: 1418667240 repoRebuildEpoch=1500708860 # Get epoch of existing index.git indexFileEpoch=$( stat -f "%m" "${WORKING_PATH}/${APP_DIR_NAME}"/index.git ) [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}indexFileEpoch=$indexFileEpoch" if [ $indexFileEpoch -lt $repoRebuildEpoch ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}index.git is from before repo was rebuilt" GetIndexAndProcessThemeList else # Check for updates to index.git [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Checking for update to index.git" cd "${WORKING_PATH}/${APP_DIR_NAME}"/index.git local updateCheck=$( "$gitCmd" fetch --progress origin master:master 2>&1 ) if [[ "$updateCheck" == *done.* ]]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}index.git has been updated. Re-downloading" GetIndexAndProcessThemeList else [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}No updates to index.git" WriteToLog "CTM_IndexOK" # Commented out the below condition for now to force rebuild of file. # This is because we now check themeList array in CheckForThemeUpdates() # to see if a theme still exists on the Repo. # Use previously saved theme.html #if [ -f "${WORKING_PATH}/${APP_DIR_NAME}"/theme.html ]; then # WriteToLog "CTM_ThemeListOK" # InsertThemeListHtmlInToManageThemes "file" #else [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Error!. ${WORKING_PATH}/${APP_DIR_NAME}/theme.html not found" BuildThemeTextInformation CreateThemeListHtml InsertThemeListHtmlInToManageThemes #fi fi fi # Check for help directory and add_theme.html file. addThemeHelpFile=$( find "${WORKING_PATH}/${APP_DIR_NAME}"/ -type f -name "add_theme.html" 2>/dev/null ) if [ ! "$addThemeHelpFile" ]; then "$gitCmd" --git-dir="${WORKING_PATH}/${APP_DIR_NAME}"/index.git --work-tree="${WORKING_PATH}/${APP_DIR_NAME}" checkout --force fi fi } # --------------------------------------------------------------------------------------- GetFreeSpaceOfTargetDeviceAndSendToUI() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}GetFreeSpaceOfTargetDeviceAndSendToUI()" # Read available space on volume and send to the UI. [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Getting free space on target device $TARGET_THEME_DIR_DEVICE" oIFS="$IFS"; IFS=$'\r\n' deviceResult=( $( df -laH | grep "$TARGET_THEME_DIR_DEVICE" | awk '{print $1}' )) [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}deviceResult=$deviceResult" IFS="$oIFS" local found=99 for (( d=0; d<${#deviceResult[@]}; d++ )) do if [ "${deviceResult[$d]##*/}" == "$TARGET_THEME_DIR_DEVICE" ]; then found=$d [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}found=$found" fi done if [ $found -lt 99 ]; then local freeSpace=$(df -laH | grep "$TARGET_THEME_DIR_DEVICE" | awk '{print $4}' | head -n$(( found + 1 )) | tail -n1) else local freeSpace="0M" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}*Couldn't get free space." fi WriteToLog "Freespace on target: $freeSpace" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Sending UI: FreeSpace:$freeSpace" SendToUI "FreeSpace‡${freeSpace}‡" } # --------------------------------------------------------------------------------------- ReadThemeDirList() { # Read /tmp/CloverThemeManager/themeDirInfo.txt file and populate # arrays for theme directory information. # themeDirInfo.txt is created by findThemeDirs.sh script. [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}ReadThemeDirList()" ResetInternalDiskArrays if [ -f "$themeDirInfo" ]; then oIFS="$IFS"; IFS=$'\r\n' while read -r line do duIdentifier+=( $( cut -d@ -f1 <<<"${line}" )) duVolumeName+=( $( cut -d@ -f2 <<<"${line}" )) duVolumeMountPoint+=( $( cut -d@ -f3 <<<"${line}" )) duContent+=( $( cut -d@ -f4 <<<"${line}" )) duPartitionGuid+=( $( cut -d@ -f5 <<<"${line}" )) themeDirPaths+=( $( cut -d@ -f6 <<<"${line}" )) done < "$themeDirInfo" IFS="$oIFS" # Check array contents match and send message to UI via log local total=${#duIdentifier[@]} if [ ${#duVolumeName[@]} -ne $total ] || [ ${#duVolumeMountPoint[@]} -ne $total ] || \ [ ${#duContent[@]} -ne $total ] || [ ${#duPartitionGuid[@]} -ne $total ] || [ ${#themeDirPaths[@]} -ne $total ]; then [[ $gInitialising -eq 0 ]] && WriteToLog "CTM_ThemeDirsFail" # Print results for (( s=0; s<${#duIdentifier[@]}; s++ )) do WriteToLog "${duIdentifier[$s]} | ${duVolumeName[$s]} | ${duVolumeMountPoint[$s]} | ${duContent[$s]} | ${duPartitionGuid[$s]} | ${themeDirPaths[$s]}" done exit 1 else [[ $gInitialising -eq 0 ]] && WriteToLog "CTM_ThemeDirsOK" fi else WriteToLog "Missing $themeDirInfo file. No mounted volumes contain /EFI/Clover/Themes directory." WriteToLog "CTM_ThemeDirsOKFail" fi } # --------------------------------------------------------------------------------------- SetTargetAndMountpoint() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}SetTargetAndMountpoint()" if [ "$gBootDeviceIdentifier" != "" ] && [ "$gBootDeviceIdentifier" != "Failed" ]; then for (( t=0; t<${#duIdentifier[@]}; t++ )) do if [ "${duIdentifier[$t]}" == "$gBootDeviceIdentifier" ]; then TARGET_THEME_DIR="${themeDirPaths[$t]}" TARGET_THEME_DIR_DEVICE="${duIdentifier[$t]}" TARGET_THEME_PARTITIONGUID="${duPartitionGuid[$t]}" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Set target volume to boot device: $gBootDeviceIdentifier" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}TARGET_THEME_DIR=$TARGET_THEME_DIR" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}TARGET_THEME_DIR_DEVICE=$TARGET_THEME_DIR_DEVICE" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}TARGET_THEME_PARTITIONGUID=$TARGET_THEME_PARTITIONGUID" gBootDeviceMountPoint="${TARGET_THEME_DIR%/EFI*}" # Send result to UI [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Sending UI message: BootDevice@Mounted@${gBootDeviceIdentifier}@${gBootDeviceMountPoint}" SendToUI "BootDevice‡Mounted‡${gBootDeviceIdentifier}‡${gBootDeviceMountPoint}" break fi done else # Send message to UI if identifier is set to 'Failed'. Otherwise a blank identifier could mean bootlog did not exist. if [ "$gBootDeviceIdentifier" == "Failed" ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Sending UI message: BootDevice@Failed@@" SendToUI "BootDevice‡Failed‡‡" fi fi } # --------------------------------------------------------------------------------------- GetBootlog() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}GetBootlog()" local bootLog=$( ioreg -lw0 -pIODeviceTree | grep boot-log ) #bootLog=${bootLog#*'<'} #bootLog=${bootLog%%'>'*} # Use cut instead of above as a large bootlog a couple of minutes removing > from end. bootLog=$(cut -d '<' -f2 <<< "$bootLog") bootLog=$(cut -d '>' -f1 <<< "$bootLog") if [ "$bootLog" != "" ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Found a bootlog in ioreg. Writing bootlog to disk" echo "$bootLog" > "${TEMPDIR}"/bootLogtmp xxd -r -p "${TEMPDIR}"/bootLogtmp > "${bootLogFile}_tmp" && rm "${TEMPDIR}"/bootLogtmp # Convert to Unix Line Feed endings tr -d '\r' < "${bootLogFile}_tmp" > "${bootLogFile}" && rm "${bootLogFile}_tmp" # Remove bootlog if not from Clover local checkLog=$( grep "Starting Clover" $bootLogFile ) if [ "$checkLog" == "" ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}bootlog is not from Clover. Deleting" rm $bootLogFile fi else [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}bootlog from ioreg is blank" fi } # --------------------------------------------------------------------------------------- ReadBootLogAndSetPaths() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}ReadBootLogAndSetPaths()" local runInfo="$1" # Will be either 'Init' or 'Rescan' # Run bootlog script to read bootlog for theme info. # This script builds the bootlog html and injects it into the managethemes template. "$bootlogScript" "$runInfo" "$gBootDeviceIdentifier" "$gBootDeviceMountPoint" # The bootlog script writes some paths (or text 'Native NVRAM') to file. Read them in. if [ -f "$bootlogScriptOutfile" ]; then gNvramPlistFullPath=$( grep "nvram‡" "$bootlogScriptOutfile" ) && gNvramPlistFullPath="${gNvramPlistFullPath##*‡}" gNvramPlistThemeEntry=$( grep "nvramThemeEntry‡" "$bootlogScriptOutfile" ) && gNvramPlistThemeEntry="${gNvramPlistThemeEntry##*‡}" gConfigPlistFullPath=$( grep "config‡" "$bootlogScriptOutfile" ) && gConfigPlistFullPath="${gConfigPlistFullPath##*‡}" gBootType=$( grep "bootType‡" "$bootlogScriptOutfile" ) && gBootType="${gBootType##*‡}" gNvramSave=$( grep "nvramSave‡" "$bootlogScriptOutfile" ) && gNvramSave="${gNvramSave##*‡}" # Honour the users choice to have the bootlog closed or expanded if [ "$gBootlogState" == "Close" ]; then gBootlogState="ShowClosed" else gBootlogState="Show" fi fi [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Returned back from bootlog script: gNvramPlistFullPath=$gNvramPlistFullPath | gConfigPlistFullPath=$gConfigPlistFullPath" } # --------------------------------------------------------------------------------------- GetSelfDevicePath() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}GetSelfDevicePath()" if [ -f "$bootLogFile" ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Reading bootlog" local selfDevicePath=$( grep -a SelfDevicePath "$bootLogFile" ) if [[ "$selfDevicePath" ]]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Found selfDevicePath" # Will look something like these examples #0:999 0:000 SelfDevicePath=PcieRoot(0x0)\Pci(0x1F,0x2)\USB(0x0,0x0)\HD(1,MBR,0x00000000,0x2,0x3BB7BE) @1DBDFE98 #0:100 0:000 SelfDevicePath=PciRoot(0x0)\Pci(0x1F,0x2)\Sata(0x0,0xFFFF,0x0)\HD(1,GPT,BC1B343C-2D6B-4C0C-8B88-71C2AFCF6E65,0x28,0x64000) @C7AA598 #0:100 0:000 SelfDevicePath=PciRoot(0x0)\Pci(0x1F,0x2)\VenHw(CF31FAC5-C24E-11D2-85F3-00A0C93EC93B,02)\HD(1,GPT,AA434287-E363-4254-AC5A-27189F7BDCC0,0x28,0x64000) @97548018 # Get device path and split in to parts devicePath="${selfDevicePath#*=}" declare -a devicePathArr IFS=$'\\' devicePathArr=($devicePath) IFS="$oIFS" #local deviceType="-" #deviceType="${devicePathArr[2]%(*}" if [ $DEBUG -eq 1 ]; then for ((i=0; i<${#devicePathArr[@]}; i++)) do WriteToLog "${debugIndentTwo}devicePathArr[$i]=${devicePathArr[$i]}" done fi idx=${#devicePathArr[@]} while [[ "${devicePathArr[$idx]}" != "HD("* ]] do ((idx--)) done # Split HD in to parts devicePathHD="${devicePathArr[$idx]%)*}" devicePathHD="${devicePathHD#*(}" # Should be something like these examples: #1,MBR,0x2A482A48,0x2,0x4EFC1B80 #2,GPT,F55D9AC4-08A8-4269-9A8E-396DBE7C7943,0x64028,0x1C0000 declare -a hdArr IFS=$',' hdArr=($devicePathHD) IFS="$oIFS" local bootDevicePartition="${hdArr[0]}" local bootDevicePartType="${hdArr[1]}" local bootDevicePartSignature="${hdArr[2]}" local bootDevicePartStart="${hdArr[3]}" local bootDevicePartSize="${hdArr[4]}" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}PartType=$bootDevicePartType" if [ "$bootDevicePartType" == "GPT" ]; then local identifier=$( "$partutil" --search-uuid $bootDevicePartSignature ) [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}identifier=$identifier" # is this an unmounted ESP? if [ -f "$espList" ] && [ "$identifier" != "" ]; then checkESP=$( grep "$identifier" "$espList" ) if [ "$checkESP" != "" ] && [[ "$checkESP" == *@U ]]; then # Instruct UI to tell user that it needs password to mount ESP WriteToLog "CTM_BootDeviceGPT" identifier=$(MountESPAndSearchThemesPath "$identifier") fi fi [[ "$identifier" == "" ]] && identifier="Failed" elif [ "$bootDevicePartType" == "MBR" ]; then # Convert device hex values to human readable local bootDevicePartStartDec=$(echo "ibase=16; ${bootDevicePartStart#*x}" | bc) local bootDevicePartSizeDec=$(echo "ibase=16; ${bootDevicePartSize#*x}" | bc) # Save boot device details to file echo "${bootDevicePartition}‡${bootDevicePartType}‡${bootDevicePartSignature}‡${bootDevicePartStartDec}‡${bootDevicePartSizeDec}" > "$bootDeviceInfo" # Instruct UI to tell user that it needs password for identifying MBR device WriteToLog "CTM_BootDeviceMBR" local identifier=$(DetectMBRDevice) fi [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Boot device part type=${bootDevicePartType} | identifier=${identifier}" echo "$identifier" else echo "" fi else [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}$bootLog not found" fi WriteToLog "CTM_BootDeviceCloseWindow" } # --------------------------------------------------------------------------------------- CreateAndSendVolumeDropDownMenu() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}CreateAndSendVolumeDropDownMenu()" # Send new dropdown list for UI for (( p=0; p<${#themeDirPaths[@]}; p++ )) do # Check if mountpoint is temporary for ESP partition. # If yes then make it human readable by changing to EFI. if [[ "${themeDirPaths[$p]}" == *$gESPMountPrefix* ]]; then local tmpStrip="${themeDirPaths[$p]#*/}" tmpStrip="${tmpStrip#*/}" tmpStrip="${tmpStrip#*/}" pathToPrint="/Volumes/EFI/${tmpStrip}" espID=$p else pathToPrint="${themeDirPaths[$p]}" fi if [ "${duIdentifier[$p]}" == "$gBootDeviceIdentifier" ]; then pathToPrint="BOOT DEVICE | $pathToPrint" fi local newPathList="${newPathList}","${p};${pathToPrint} [${duIdentifier[$p]}] [${duPartitionGuid[$p]}]" done if [ "$newPathList" != "" ]; then # Remove leading comma from string newPathList="${newPathList#?}" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Sending UI message: NewVolumeDropDown@${newPathList}@" SendToUI "NewVolumeDropDown‡${newPathList}‡" return 0 else # Still send UI DropDown message, even though there are no entries. SendToUI "NewVolumeDropDown‡‡" return 1 fi } # --------------------------------------------------------------------------------------- MountESPAndSearchThemesPath() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}MountESPAndSearchThemesPath()" local espMountedCount=0 local identifier="$1" if [ $(CheckOsVersion) -ge 13 ]; then espMountedCount=$( /usr/bin/osascript -e 'tell application "SecurityAgent" to activate'; \ /usr/bin/osascript -e "do shell script \"$uiSudoChanges \" & \"‡ManageESP\" with administrator privileges" ) else espMountedCount=$( /usr/bin/osascript -e "do shell script \"$uiSudoChanges \" & \"‡ManageESP\" with administrator privileges" ) fi if [ $espMountedCount -gt 0 ]; then WriteToLog "Checked and found $espMountedCount ESP with /EFI/Clover/Themes dir." "$findThemeDirs" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Sending UI message: MessageESP@Mounted@${espMountedCount}" SendToUI "MessageESP‡Mounted‡${espMountedCount}" echo "$identifier" elif [ -z $espMountedCount ]; then WriteToLog "User cancelled password dialog" # Send UI message so the message box shows close box button. [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Sending UI message: MessageESP@Cancelled@0" SendToUI "MessageESP‡Cancelled‡0" echo "Failed" else WriteToLog "Checked and found no unmounted ESP(s) with /EFI/Clover/Themes dir." # Send UI message that no ESP's were mounted. This changes message box content and shows close box button. [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Sending UI message: MessageESP@Mounted@0" SendToUI "MessageESP‡Mounted‡0" echo "Failed" fi } # --------------------------------------------------------------------------------------- DetectMBRDevice() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}DetectMBRDevice()" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}User selected to detect MBR device." local device="" if [ $(CheckOsVersion) -ge 13 ]; then device=$( /usr/bin/osascript -e "do shell script \"$uiSudoChanges \" & \"‡FindMBrBootDevice\" with administrator privileges" ) else device=$( /usr/bin/osascript -e "do shell script \"$uiSudoChanges \" & \"‡FindMBrBootDevice\" with administrator privileges" ) fi if [ "$device" != "" ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Found boot device. $deviceFound" echo "$device" elif [ -z $device ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}User cancelled password dialog" echo "Failed" else [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Failed to match a mounted boot device." echo "Failed" fi } # --------------------------------------------------------------------------------------- ReadPrefsFile() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}ReadPrefsFile()" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Read user preferences file" # Check for preferences file if [ -f "$gUserPrefsFile".plist ]; then gLastSelectedPath=$( defaults read "$gUserPrefsFile" LastSelectedPath ) [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}gLastSelectedPath=$gLastSelectedPath" gLastSelectedPathDevice=$( defaults read "$gUserPrefsFile" LastSelectedPathDevice ) [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}gLastSelectedPathDevice=$gLastSelectedPathDevice" gLastSelectedPartitionGUID=$( defaults read "$gUserPrefsFile" LastSelectedPartitionGUID ) [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}gLastSelectedPartitionGUID=$gLastSelectedPartitionGUID" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Resetting internal theme arrays" ResetInternalThemeArrays gBootlogState=$( defaults read "$gUserPrefsFile" ShowHideBootlog ) [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}gBootlogState=${gBootlogState}" local tmp=$( defaults read "$gUserPrefsFile" Thumbnail ) if [ "$tmp" != "" ]; then gThumbSizeX="${tmp% *}" gThumbSizeY="${tmp#* }" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}ThumbnailSize=${gThumbSizeX}x${gThumbSizeY}" fi gUISettingViewUnInstalled=$( defaults read "$gUserPrefsFile" UnInstalledButton ) [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}gUISettingViewUnInstalled=${gUISettingViewUnInstalled}" gUISettingViewThumbnails=$( defaults read "$gUserPrefsFile" ViewThumbnails ) [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}gUISettingViewThumbnails=${gUISettingViewThumbnails}" gUISettingViewPreviews=$( defaults read "$gUserPrefsFile" ShowPreviewsButton ) [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}gUISettingViewPreviews=${gUISettingViewPreviews}" # Find installed themes oIFS="$IFS"; IFS=$'\n' local readVar=( $( defaults read "$gUserPrefsFile" InstalledThemes | grep = ) ) IFS="$oIFS" # get total count of lines, less one for zero based index. local count=(${#readVar[@]}-1) foundThemeName=0 for (( x=0; x<=$count; x++ )) do if [ $foundThemeName -eq 1 ] || [[ "${readVar[$x]}" == *ThemePath* ]]; then local tmpOption="${readVar[$x]%=*}" tmpOption="${tmpOption//[[:space:]]}" # Remove whitespace local tmpValue="${readVar[$x]#*=}" tmpValue=$( echo "$tmpValue" | sed 's/^ *//') # Remove leading whitespace tmpValue=$( echo "$tmpValue" | tr -d '";' ) # Remove quotes and semicolon from the string case "$tmpOption" in "ThemePath" ) installedThemeName+=( "$themeName" ) installedThemePath+=("$tmpValue") ;; "ThemePathDevice" ) installedThemePathDevice+=("$tmpValue") ;; "VolumeUUID" ) installedThemePartitionGUID+=("$tmpValue") ;; esac fi # Look for an open parenthesis to indicate start of array entry if [[ "${readVar[$x]}" == *\(* ]]; then themeName="${readVar[$x]% =*}" # Remove all after ' =' themeName=$( echo "$themeName" | sed 's/^ *//') # Remove leading whitespace themeName=$( echo "$themeName" | sed 's/\"//g' ) # Remove any quotes foundThemeName=1 fi done # Add message in to log for initialise.js to detect. #[[ $gInitialising -eq 0 ]] && WriteToLog "CTM_ReadPrefsOK" else [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Preferences file not found." [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Creating initial prefs file: $gUserPrefsFile" defaults write "$gUserPrefsFile" "LastSelectedPath" "-" defaults write "$gUserPrefsFile" "LastSelectedPathDevice" "-" defaults write "$gUserPrefsFile" "LastSelectedPartitionGUID" "-" TARGET_THEME_DIR="-" TARGET_THEME_DIR_DEVICE="-" TARGET_THEME_PARTITIONGUID="-" # Add message in to log for initialise.js to detect. WriteToLog "CTM_ReadPrefsCreate" fi if [ "$gBootlogState" == "" ]; then gBootlogState="Open" fi [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}TARGET_THEME_DIR=$TARGET_THEME_DIR" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}TARGET_THEME_DIR_DEVICE=$TARGET_THEME_DIR_DEVICE" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}TARGET_THEME_PARTITIONGUID=$TARGET_THEME_PARTITIONGUID" [[ DEBUG -eq 1 ]] && SendInternalThemeArraysToLogFile } # --------------------------------------------------------------------------------------- MapLastSelectedPathToGUID() { # Map $gLastSelectedPath against $gLastSelectedPartitionGUID to catch differences # which will occur when using ESP. Internal random mountpoint gets written to # prefs as /Volumes/EFI because random mountpoint will not happen again. [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}MapLastSelectedPathToGUID()" if [ "$gLastSelectedPartitionGUID" != "-" ] && [ "$gLastSelectedPath" != "-" ] && [ "$gLastSelectedPathDevice" != "-" ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Mapping last selected partition GUID against mounted partition GUIDs" local checkPath="" for (( u=0; u<${#themeDirPaths[@]}; u++ )) do # Note: Two MBR partitioned, FAT32 formatted USB sticks will both have zero UUID. if [ "${gLastSelectedPartitionGUID}" == "${zeroUUID}" ]; then if [ "${duPartitionGuid[$u]}" == "$zeroUUID" ]; then # Attempt to match theme path if [ "${themeDirPaths[$u]}" == "$TARGET_THEME_DIR" ]; then checkPath="${themeDirPaths[$u]}" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Match found:checkPath=$checkPath" break fi fi else [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Checking ${duPartitionGuid[$u]} = $gLastSelectedPartitionGUID" if [ "${duPartitionGuid[$u]}" == "$gLastSelectedPartitionGUID" ]; then checkPath="${themeDirPaths[$u]}" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Match found:checkPath=$checkPath" fi fi done if [ "$checkPath" != "" ]; then TARGET_THEME_DIR="$checkPath" else TARGET_THEME_DIR="$gLastSelectedPath" fi TARGET_THEME_DIR_DEVICE="$gLastSelectedPathDevice" TARGET_THEME_PARTITIONGUID="$gLastSelectedPartitionGUID" else [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}No last selected partition is set." TARGET_THEME_DIR="-" TARGET_THEME_DIR_DEVICE="-" TARGET_THEME_PARTITIONGUID="-" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}TARGET_THEME_DIR=$TARGET_THEME_DIR" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}TARGET_THEME_DIR_DEVICE=$TARGET_THEME_DIR_DEVICE" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}TARGET_THEME_PARTITIONGUID=$TARGET_THEME_PARTITIONGUID" fi } # --------------------------------------------------------------------------------------- SendInternalThemeArraysToLogFile() { # This is only called if DEBUG is set to 1 # It will loop through the internal arrays for installed themes and # print them to the log file. # They arrays are saved to prefs in MaintainInstalledThemeListInPrefs() [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}SendInternalThemeArraysToLogFile()" WriteLinesToLog local totalPath="${#installedThemePath[@]}" local totalPathDevice="${#installedThemePathDevice[@]}" local totalVolUuid="${#installedThemePartitionGUID[@]}" if [ $totalPath -ne $totalPathDevice ] && [ $totalPath -ne $totalVolUuid ]; then WriteToLog "${debugIndentTwo}Error. Preferences are corrupt" exit 1 else WriteToLog "${debugIndentTwo}Prefs shows total number of installed themes=${#installedThemeName[@]}" for ((n=0; n<${#installedThemeName[@]}; n++ )); do WriteToLog "${debugIndentTwo}$n: ${installedThemeName[$n]}, ${installedThemePath[$n]}, ${installedThemePathDevice[$n]}, ${installedThemePartitionGUID[$n]}" done fi } # --------------------------------------------------------------------------------------- SendTargetToUiRunChecks() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}SendTargetToUiRunChecks()" if [ ! "$TARGET_THEME_DIR" == "" ] && [ ! "$TARGET_THEME_DIR" == "-" ] ; then local entry=$( FindArrayIdFromTarget ) [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}entry=$entry" CheckThemePathIsStillValid retVal=$? # returns 1 if invalid / 0 if valid if [ $retVal -eq 0 ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Sending UI: Target@$entry" SendToUI "Target‡$entry" GetListOfInstalledThemesAndSendToUI GetFreeSpaceOfTargetDeviceAndSendToUI # Run this regardless of path chosen as JS is waiting to hear it. CheckAndRecordUnManagedThemesAndSendToUI fi fi } # --------------------------------------------------------------------------------------- SendUIInitData() { # This is called once after much of the initialisation routines have run. [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}SendUIInitData()" # Send UI setting for BootlogView and adjust footer height [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Sending UI: BootlogView@${gBootlogState}@" SendToUI "BootlogView‡${gBootlogState}‡" SendTargetToUiRunChecks if [ "$TARGET_THEME_DIR" == "" ] || [ "$TARGET_THEME_DIR" == "-" ] ; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Sending UI: NoPathSelected@@" SendToUI "NoPathSelected‡‡" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Sending UI: Target@-@" SendToUI "Target‡-‡" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Sending UI: InstalledThemes@-@" SendToUI "InstalledThemes‡-‡" fi # Send thumbnail size if [ $gThumbSizeX -gt 0 ] && [ $gThumbSizeY -gt 0 ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Sending UI: ThumbnailSize@${gThumbSizeX}@${gThumbSizeY}" SendToUI "ThumbnailSize‡${gThumbSizeX}‡${gThumbSizeY}" fi # Send UI view choice for UnInstalled themes [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Sending UI: UnInstalledView@${gUISettingViewUnInstalled}@" SendToUI "UnInstalledView‡${gUISettingViewUnInstalled}‡" # Send UI view choice for Thumbnails [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Sending UI: ThumbnailView@${gUISettingViewThumbnails}@" SendToUI "ThumbnailView‡${gUISettingViewThumbnails}‡" # Send UI view choice for Previews [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Sending UI: PreviewView@${gUISettingViewPreviews}@" SendToUI "PreviewView‡${gUISettingViewPreviews}‡" # Add message in to log for initialise.js to detect. WriteToLog "CTM_InitInterface" } # --------------------------------------------------------------------------------------- ReadThemeEntriesAndSendToUI() { if [ "$TARGET_THEME_DIR" != "-" ] && [ "$TARGET_THEME_DIR_DEVICE" != "-" ] && [ "$TARGET_THEME_PARTITIONGUID" != "-" ]; then # Check if selected device is boot device if [ "$TARGET_THEME_DIR_DEVICE" == "$gBootDeviceIdentifier" ]; then # Read current Clover.Theme Nvram variable and send to UI. ReadAndSendCurrentNvramTheme # Read current nvram.plist theme var and send to UI ReadAndSendCurrentNvramPlistTheme # Read current config.plist theme entry and send to UI ReadAndSendCurrentConfigPlistTheme fi fi } # ======================================================================================= # After Initialisation Routines # ======================================================================================= # --------------------------------------------------------------------------------------- RespondToUserDeviceSelection() { # Called from the Main Message Loop when a user has changed the # themes file path from the drop down menu in the UI. # # This routine takes the message, and splits it to find the device # and volume name. Then providing the user has not chosen 'Please Choose' # from the menu (indicated by a - for each device and volumeName), the # path is double checked before writing the choice to the user prefs file. # # Routines are then called to perform the following: # 1 - Get a list of theme directories at selected file path. # 2 - Get available free space on target volume. # 3 - Housekeep locally installed bare git clones. # 4 - Check for any theme updates on target volume. # 5 - Decide to show or hide control options. # 6 - Send list of installed themes to the UI. [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}RespondToUserDeviceSelection()" local messageFromUi="$1" # parse message # remove everything up until, and including, the first ‡ local messageFromUi="${messageFromUi#*‡}" local pathOption="${messageFromUi##*‡}" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}RespondToUserDeviceSelection() messageFromUi=$messageFromUi | pathOption=$pathOption" # Check user did actually change from default if [ ! "$pathOption" == "-" ]; then WriteLinesToLog WriteToLog "Target path changed: ${themeDirPaths[$pathOption]} on device ${duIdentifier[$pathOption]} with GUID ${duPartitionGuid[$pathOption]}" local volumePath=$( ResolveVolumePathFromGUID "${duPartitionGuid[$pathOption]}" ) if [ "$volumePath" != "" ]; then TARGET_THEME_DIR="$volumePath" else TARGET_THEME_DIR="${themeDirPaths[$pathOption]}" fi TARGET_THEME_DIR_DEVICE="${duIdentifier[$pathOption]}" TARGET_THEME_PARTITIONGUID="${duPartitionGuid[$pathOption]}" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}TARGET_THEME_DIR=$TARGET_THEME_DIR" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}TARGET_THEME_DIR_DEVICE=$TARGET_THEME_DIR_DEVICE" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}TARGET_THEME_PARTITIONGUID=$TARGET_THEME_PARTITIONGUID" CheckThemePathIsStillValid retVal=$? # returns 1 if invalid / 0 if valid if [ $retVal -eq 0 ]; then UpdatePrefsKey "LastSelectedPath" "$TARGET_THEME_DIR" UpdatePrefsKey "LastSelectedPathDevice" "$TARGET_THEME_DIR_DEVICE" UpdatePrefsKey "LastSelectedPartitionGUID" "$TARGET_THEME_PARTITIONGUID" GetListOfInstalledThemesAndSendToUI GetFreeSpaceOfTargetDeviceAndSendToUI CheckAndRecordUnManagedThemesAndSendToUI CheckForAndRemoveThemeGitDirs CheckAndRemoveBareClonesNoLongerNeeded CheckForThemeUpdates & ShowHideUIControlOptions ReadThemeEntriesAndSendToUI else # Run these regardless of path chosen as JS is waiting to hear it. CheckAndRecordUnManagedThemesAndSendToUI fi else [[ DEBUG -eq 1 ]] && WriteToLog "User de-selected Volume path and chose menu title. Do Nothing." TARGET_THEME_DIR="-" TARGET_THEME_DIR_DEVICE="-" TARGET_THEME_PARTITIONGUID="-" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Setting prefs for default dir,path & GUID to -" UpdatePrefsKey "LastSelectedPath" "$TARGET_THEME_DIR" UpdatePrefsKey "LastSelectedPathDevice" "$TARGET_THEME_DIR_DEVICE" UpdatePrefsKey "LastSelectedPartitionGUID" "$TARGET_THEME_PARTITIONGUID" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Sending UI: InstalledThemes@-@" SendToUI "InstalledThemes‡-‡" fi [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Sending UI: EnableInterface@@" SendToUI "EnableInterface‡‡" } # --------------------------------------------------------------------------------------- ShowHideUIControlOptions() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}ShowHideUIControlOptions()" # Check if this selected device is boot device or not if [ "$TARGET_THEME_DIR_DEVICE" != "$gBootDeviceIdentifier" ]; then # Hide theme control options WriteToLog "$TARGET_THEME_DIR_DEVICE is not boot device. Hiding control options." [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Sending UI: ShowHideControlOptions@Hide@" SendToUI "ShowHideControlOptions‡Hide‡" else # Show theme control options WriteToLog "$TARGET_THEME_DIR_DEVICE is boot device. Show control options." [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Sending UI: ShowHideControlOptions@Show@" SendToUI "ShowHideControlOptions‡Show‡" fi } # --------------------------------------------------------------------------------------- RespondToUserThemeAction() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}RespondToUserThemeAction()" local messageFromUi="$1" # remove everything up until, and including, the first ‡ messageFromUi="${messageFromUi#*‡}" chosenTheme="${messageFromUi%%‡*}" desiredAction="${messageFromUi##*‡}" # further strip theme name and action chosenTheme="${chosenTheme##*button_}" desiredAction="${desiredAction##*button}" # Note - desiredAction will be either: Install, UnInstall or Update if [ ! "$chosenTheme" == "" ] && [ ! "$desiredAction" == "" ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}User chose to $desiredAction theme $chosenTheme" CheckThemePathIsStillValid retVal=$? # returns 1 if invalid / 0 if valid if [ $retVal -eq 0 ]; then RunThemeAction "$desiredAction" "$chosenTheme" # Add 'Update success' notification to UI here so to not conflict with the 'Update All' functionality local checkSuccess=$? if [ "$desiredAction" == "Update" ] && [ $checkSuccess -eq 0 ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Sending UI: Success@${desiredAction}@$chosenTheme" SendToUI "Success‡${desiredAction}‡$chosenTheme" fi return $checkSuccess else return 1 fi fi } # --------------------------------------------------------------------------------------- CheckThemePathIsStillValid() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}CheckThemePathIsStillValid()" local findDevice="" local stillMounted=0 # Find device by previously used UUID. if [ "$TARGET_THEME_PARTITIONGUID" != "$zeroUUID" ] && [ "$TARGET_THEME_PARTITIONGUID" != "-" ]; then findDevice=$( "$partutil" --search-uuid $TARGET_THEME_PARTITIONGUID ) else findDevice="$TARGET_THEME_DIR_DEVICE" fi # Match device to current list of mounted partitions with valid theme paths. if [ "$findDevice" != "" ]; then for ((i=0; i<${#duIdentifier[@]}; i++)) do if [ $findDevice == ${duIdentifier[$i]} ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Device $TARGET_THEME_PARTITIONGUID is ${duIdentifier[$i]}" # Check path actually exists if [ -d "$TARGET_THEME_DIR" ]; then stillMounted=1 # Ensure current TARGET_THEME_DIR_DEVICE matches device TARGET_THEME_DIR_DEVICE=${duIdentifier[$i]} fi fi done fi if [ $stillMounted -eq 0 ] && [ "$TARGET_THEME_DIR" != "-" ]; then WriteToLog "Theme directory $TARGET_THEME_DIR on $TARGET_THEME_PARTITIONGUID does not exist! Setting to -" local entry=$( FindArrayIdFromTarget ) [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}entry=$entry" local pathToPrint="$TARGET_THEME_DIR" if [ "$entry" != "-" ]; then if [[ "${themeDirPaths[$entry]}" == *$gESPMountPrefix* ]]; then local tmpStrip="${themeDirPaths[$entry]#*/}" tmpStrip="${tmpStrip#*/}" tmpStrip="${tmpStrip#*/}" pathToPrint="/Volumes/EFI/${tmpStrip}" fi fi [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Sending UI: NotExist@${TARGET_THEME_PARTITIONGUID}@${pathToPrint}@$entry" SendToUI "NotExist‡${TARGET_THEME_PARTITIONGUID}‡${pathToPrint}‡$entry" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}NoPathSelected" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Sending UI: NoPathSelected@@" SendToUI "NoPathSelected‡‡" # Re-build theme directory list "$findThemeDirs" ReadThemeDirList CreateAndSendVolumeDropDownMenu [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Sending UI: Target@-" SendToUI "Target‡-‡" RespondToUserDeviceSelection "‡-" return 1 else [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Theme directory $TARGET_THEME_DIR exists." return 0 fi } # --------------------------------------------------------------------------------------- GetListOfInstalledThemesAndSendToUI() { # Scan the selected EFI/Clover/Themes directory for a list of installed themes. # The user could add themes without using the app so we need to keep to track of # what's there. # Send the list of installed themes to the UI. [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}GetListOfInstalledThemesAndSendToUI()" installedThemeStr="" unset installedThemesFoundAfterSearch unset installedThemesOnCurrentVolume if [ "$TARGET_THEME_DIR" != "" ] && [ "$TARGET_THEME_DIR" != "-" ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Looking for installed themes at $TARGET_THEME_DIR on $TARGET_THEME_DIR_DEVICE" oIFS="$IFS"; IFS=$'\r\n' installedThemesFoundAfterSearch=( $( find "$TARGET_THEME_DIR"/* -type d -depth 0 )) for ((i=0; i<${#installedThemesFoundAfterSearch[@]}; i++)) do installedThemesOnCurrentVolume[$i]="${installedThemesFoundAfterSearch[$i]##*/}" # Create comma separated string for sending to the UI installedThemeStr="${installedThemeStr},${installedThemesOnCurrentVolume[$i]}" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Found installed theme: ${installedThemesOnCurrentVolume[$i]}" done IFS="$oIFS" # Remove leading comma from string installedThemeStr="${installedThemeStr#?}" else [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Can't check for installed themes at $TARGET_THEME_DIR" fi # Sort comma separated list. # This is necessary only for applying different fills (shadows/without shadows) in JS ChangeButtonAndBandToUnInstall() installedThemeStr=$( LC_ALL=C; echo "$installedThemeStr" | tr , "\n" | sort -f | tr "\n" , ) # Remove trailing comma from string if [ "${installedThemeStr: -1}" == "," ]; then installedThemeStr="${installedThemeStr%?}" fi WriteToLog "Installed Themes:${installedThemeStr}" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Sending UI: InstalledThemes@${installedThemeStr}@" SendToUI "InstalledThemes‡${installedThemeStr}‡" } # --------------------------------------------------------------------------------------- CheckThemeIsInPrefs() { # Check for any inconsistency where a theme entry in user prefs may be missing when # it's clearly installed in the users EFI/Clover/Themes directory AND has a parent # bare clone in the support directory. # If found - Add this theme in to prefs. [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}CheckThemeIsInPrefs()" local themeToFind="$1" local inPrefs=0 for ((n=0; n<${#installedThemeName[@]}; n++ )) do if [ "${installedThemeName[$n]}" == "$themeToFind" ] && [ "${installedThemePartitionGUID[$n]}" == "$TARGET_THEME_PARTITIONGUID" ]; then inPrefs=1 fi done if [ $inPrefs -eq 0 ]; then # Should add in to prefs [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}* $themeToFind is in ${TARGET_THEME_DIR} and bare clone exists but not in prefs! Adding now." # Add the details for this theme for adding to prefs file gNewInstalledThemeName="$themeToFind" gNewInstalledThemePath="$TARGET_THEME_DIR" gNewInstalledThemePathDevice="$TARGET_THEME_DIR_DEVICE" gNewinstalledThemePartitionGUID="$TARGET_THEME_PARTITIONGUID" # Run routine to update prefs file. MaintainInstalledThemeListInPrefs fi } # --------------------------------------------------------------------------------------- CheckAndRecordUnManagedThemesAndSendToUI() { # Note: installedThemesOnCurrentVolume[] contains list of themes installed on the current theme path. # Plan: loop through this array and check for existence of .hash file # Create list of any installed themes missing a .hash file in $unversionedThemeStr # Send the list to the UI so a cross is drawn to the right of the 'UnInstall' button. [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}CheckAndRecordUnManagedThemesAndSendToUI()" if [ ! "$TARGET_THEME_DIR" == "-" ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Checking $TARGET_THEME_DIR for any unmanaged themes (without a .hash)." unversionedThemeStr="" local prefsNeedUpdating=0 for ((t=0; t<${#installedThemesOnCurrentVolume[@]}; t++)) do #if [ ! -d "${WORKING_PATH}/${APP_DIR_NAME}"/"${installedThemesOnCurrentVolume[$t]}.git" ]; then #WriteToLog "${TARGET_THEME_DIR}/${installedThemesOnCurrentVolume[$t]} is missing parent bare clone from support dir!" # Check for .hash inside installed theme dir if [ ! -f "$TARGET_THEME_DIR"/"${installedThemesOnCurrentVolume[$t]}"/.hash ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}${TARGET_THEME_DIR}/${installedThemesOnCurrentVolume[$t]} has no hash" # Append to list of themes that cannot be checked for updates unversionedThemeStr="${unversionedThemeStr},${installedThemesOnCurrentVolume[$t]}" # Remove any pref entry for this theme for ((d=0; d<${#installedThemeName[@]}; d++)) do if [ "${installedThemeName[$d]}" == "${installedThemesOnCurrentVolume[$t]}" ] && \ [ "${installedThemePartitionGUID[$d]}" == "${TARGET_THEME_PARTITIONGUID}" ] && \ [ "$TARGET_THEME_PARTITIONGUID" != "$zeroUUID" ]; then # Doing this will effectively delete the theme from prefs as it # will be skipped in the loop in MaintainInstalledThemeListInPrefs() [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Housekeeping: Will remove prefs entry for ${installedThemeName[$d]} on $TARGET_THEME_PARTITIONGUID" prefsNeedUpdating=1 installedThemeName[$d]="-" fi done else [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}${TARGET_THEME_DIR}/${installedThemesOnCurrentVolume[$t]} has parent bare clone in support dir" # Match - theme dir in users theme path that also has a parent bare clone in app support dir. # Double check this is also in user prefs file. if [ "$TARGET_THEME_PARTITIONGUID" != "$zeroUUID" ]; then CheckThemeIsInPrefs "${installedThemesOnCurrentVolume[$t]}" fi fi done # Run routine to update prefs file. if [ $prefsNeedUpdating -eq 1 ]; then MaintainInstalledThemeListInPrefs fi # Remove leading comma from string unversionedThemeStr="${unversionedThemeStr#?}" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Sending UI list of themes not installed by this app: UnversionedThemes@${unversionedThemeStr}@" SendToUI "UnversionedThemes‡${unversionedThemeStr}‡" fi } # --------------------------------------------------------------------------------------- CheckForAndRemoveThemeGitDirs() { # Note: installedThemesOnCurrentVolume[] contains list of themes installed on the current theme path. # Plan: loop through this array and check for existence of theme.git directories. # Remove any, if found [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}CheckForAndRemoveThemeGitDirs()" if [ ! "$TARGET_THEME_DIR" == "-" ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Checking $TARGET_THEME_DIR for any theme.git dirs." local dirToCheck="" for ((t=0; t<${#installedThemesOnCurrentVolume[@]}; t++)) do # Check for theme.git dir inside installed theme dir dirToCheck="$TARGET_THEME_DIR"/"${installedThemesOnCurrentVolume[$t]}"/theme.git [[ -d "$dirToCheck" ]] && rm -rf "$dirToCheck" && [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Found and deleted $dirToCheck." done fi } # --------------------------------------------------------------------------------------- IsThemeInstalled() { local passedTheme="$1" local found=1 for ((t=0; t<${#installedThemesOnCurrentVolume[@]}; t++ )); do if [ "$passedTheme" == "${installedThemesOnCurrentVolume[$t]}" ]; then found=0 break fi done echo $found } # --------------------------------------------------------------------------------------- ReadConfigPList() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}ReadConfigPList()" # Set default vars gConfigTextOnly=1 # Set to 0 if config plist file has TextOnly set to true gConfigFastBoot=1 # Set to 0 if config plist file has Fast Boot set to true # check for TextOnly and Fast boot options set by user if [ "$gConfigPlistFullPath" != "" ] && [ -f "$gConfigPlistFullPath" ]; then local checkTextOnly=$( grep -A1 "TextOnly" "$gConfigPlistFullPath" ) if [[ "$checkTextOnly" == *true* ]]; then gConfigTextOnly=0 [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}Text Only boot option is enabled" fi local checkFast=$( grep -A1 "Fast" "$gConfigPlistFullPath" ) if [[ "$checkFast" == *true* ]]; then gConfigFastBoot=0 [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}Fast boot option is enabled" fi fi } # --------------------------------------------------------------------------------------- PredictNextTheme() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}PredictNextTheme()" local themeToSend="" if [ "$gBootType" == "UEFI" ]; then if [ "$CURRENT_THEME_ENTRY_NVRAM" != "" ]; then local checkTheme=$( IsThemeInstalled "$CURRENT_THEME_ENTRY_NVRAM" ) if [ $checkTheme -eq 0 ] || [ "$CURRENT_THEME_ENTRY_NVRAM" == "embedded" ]; then themeToSend="$CURRENT_THEME_ENTRY_NVRAM" fi elif [ "$CURRENT_THEME_ENTRY_CONFIG_PLIST" != "" ]; then local checkTheme=$( IsThemeInstalled "$CURRENT_THEME_ENTRY_CONFIG_PLIST" ) if [ $checkTheme -eq 0 ] || [ "$CURRENT_THEME_ENTRY_CONFIG_PLIST" == "embedded" ]; then themeToSend="$CURRENT_THEME_ENTRY_CONFIG_PLIST" fi fi elif [ "$gBootType" == "Legacy" ]; then if [ "$CURRENT_THEME_ENTRY_NVRAM" != "" ] && [ $gNvramSave -eq 0 ]; then local checkTheme=$( IsThemeInstalled "$CURRENT_THEME_ENTRY_NVRAM" ) if [ $checkTheme -eq 0 ] || [ "$CURRENT_THEME_ENTRY_NVRAM" == "embedded" ]; then themeToSend="$CURRENT_THEME_ENTRY_NVRAM" fi elif [ "$CURRENT_THEME_ENTRY_NVRAM_PLIST" != "" ] && [ $gNvramSave -eq 1 ]; then local checkTheme=$( IsThemeInstalled "$CURRENT_THEME_ENTRY_NVRAM_PLIST" ) if [ $checkTheme -eq 0 ] || [ "$CURRENT_THEME_ENTRY_NVRAM_PLIST" == "embedded" ]; then themeToSend="$CURRENT_THEME_ENTRY_NVRAM_PLIST" fi elif [ "$CURRENT_THEME_ENTRY_CONFIG_PLIST" != "" ]; then local checkTheme=$( IsThemeInstalled "$CURRENT_THEME_ENTRY_CONFIG_PLIST" ) if [ $checkTheme -eq 0 ] || [ "$CURRENT_THEME_ENTRY_CONFIG_PLIST" == "embedded" ]; then themeToSend="$CURRENT_THEME_ENTRY_CONFIG_PLIST" fi fi fi if [ "$themeToSend" == "" ]; then if [ ${#installedThemesOnCurrentVolume[@]} -gt 0 ]; then themeToSend="random" else themeToSend="embedded" fi fi # Check for special themes (using /rEFIt_UEFI/Platform/Settings.c for ref) local month=$( date +"%m" ) local day=$( date +"%d" ) if [[ $month -eq 12 ]] && [[ $day -ge 25 && $day -le 31 ]]; then local checkTheme=$( IsThemeInstalled "christmas" ) [[ checkTheme -eq 0 ]] && themeToSend="christmas" elif [[ $month -eq 1 ]] && [[ $day -ge 1 && $day -le 7 ]]; then local checkTheme=$( IsThemeInstalled "newyear" ) [[ checkTheme -eq 0 ]] && themeToSend="newyear" fi # Check for Fast boot or Text Only boot options enabled in config.plist ReadConfigPList if [ $gConfigTextOnly -eq 0 ]; then themeToSend="None (Text Only is enabled)" fi if [ $gConfigFastBoot -eq 0 ]; then themeToSend="None (Fast boot is enabled)" fi WriteToLog "Prediction: Next boot from this device will load theme: $themeToSend" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Sending UI: SetPrediction@${themeToSend}@" SendToUI "SetPrediction‡${themeToSend}‡" } # --------------------------------------------------------------------------------------- RespondToDropDownMenuChange() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}RespondToDropDownMenuChange()" local messageFromUi="$1" local wantToChange="${messageFromUi%‡*}" local themeToSet="${messageFromUi#*‡}" local lastChar=$( echo -n "$wantToChange" | tail -c -1 ) if [ "$lastChar" == "N" ]; then if [ "$themeToSet" != "!Remove!" ]; then WriteToLog "User chose to set nvram var to $themeToSet" SetNvramTheme "$themeToSet" else WriteToLog "User chose to delete clover.Theme nvram var" DeleteNvramThemeVar fi elif [ "$lastChar" == "P" ]; then if [ "$themeToSet" != "!Remove!" ]; then WriteToLog "User chose to set nvram plist to $themeToSet" SetNvramFile "$themeToSet" else WriteToLog "User chose to remove nvram.plist theme entry" DeleteNvramPlistThemeEntry fi elif [ "$lastChar" == "C" ]; then if [ "$themeToSet" != "!Remove!" ]; then WriteToLog "User chose to set config.plist to $themeToSet" SetConfigFile "$themeToSet" else WriteToLog "User chose to remove config.plist theme entry" DeleteConfigPlistThemeEntry fi fi } # --------------------------------------------------------------------------------------- RespondToUpdateAll() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}RespondToUpdateAll()" local messageFromUi="$1" local updateThemeList="${messageFromUi#*‡}" local updateFail=0 WriteToLog "User chose to update all themes" oIFS="$IFS"; IFS=$',' read -a arr <<< "$updateThemeList" IFS="$oIFS" for (( u=0; u<${#arr[@]}; u++ )); do CheckThemePathIsStillValid retVal=$? # returns 1 if invalid / 0 if valid if [ $retVal -eq 0 ]; then WriteToLog "Calling update for theme: ${arr[$u]}" RunThemeAction "Update" "${arr[$u]}" updateFail=$? # returns 1 if process failed / 0 if success if [ $updateFail -eq 0 ]; then SendToUI "UpdateAll‡Theme‡${arr[$u]}" fi else updateFail=1 fi done if [ $updateFail -eq 0 ]; then # Operation was successful SendToUI "UpdateAll‡Complete‡-" GetListOfInstalledThemesAndSendToUI GetFreeSpaceOfTargetDeviceAndSendToUI CheckAndRecordUnManagedThemesAndSendToUI ReadThemeEntriesAndSendToUI fi } # --------------------------------------------------------------------------------------- ReadAndSendCurrentNvramTheme() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}ReadAndSendCurrentNvramTheme()" local readNvramVar=$( nvram -p | grep Clover.Theme | tr -d '\011' ) # Extract theme name local themeName="${readNvramVar##*Clover.Theme}" if [ ! -z "$readNvramVar" ]; then WriteToLog "Clover.Theme NVRAM variable is set to $themeName" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Sending UI: Nvram@${themeName}@" SendToUI "Nvram‡${themeName}‡" # Add message in to log for initialise.js to detect. [[ $gInitialising -eq 0 ]] && WriteToLog "CTM_NvramFound" CURRENT_THEME_ENTRY_NVRAM="$themeName" PredictNextTheme else # Sending '-' to the UI here causes the drop down menu to be populated to the value '-' # which currently defaults to menu option ' ' WriteToLog "Clover.Theme NVRAM variable is not set" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Sending UI: Nvram@-@" SendToUI "Nvram‡-‡" # Add message in to log for initialise.js to detect. [[ $gInitialising -eq 0 ]] && WriteToLog "CTM_NvramNotFound" PredictNextTheme fi } # --------------------------------------------------------------------------------------- ReadAndSendCurrentNvramPlistTheme() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}ReadAndSendCurrentNvramPlistTheme()" if [ -f "$gNvramPlistFullPath" ]; then # Extract theme name local themeName=$( /usr/libexec/PlistBuddy -c "Print:Clover.Theme" "$gNvramPlistFullPath" 2>/dev/null ) if [ "$themeName" != "" ]; then WriteToLog "$gNvramPlistFullPath contains theme entry $themeName" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Sending UI: NvramP@${themeName}@" #SendToUI "NvramP@${themeName}@" SendToUI "Nvram‡${themeName}‡" CURRENT_THEME_ENTRY_NVRAM_PLIST="$themeName" PredictNextTheme else # Sending '-' to the UI here causes the drop down menu to be populated to the value '-' # which currently defaults to menu option ' ' WriteToLog "$gNvramPlistFullPath does not contain a theme entry" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Sending UI: NvramP@-@" #SendToUI "NvramP@-@" SendToUI "Nvram‡-‡" PredictNextTheme fi else [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}$gNvramPlistFullPath does not exist." # Is there a theme entry from nvram.plist from bootlog? if [ "$gNvramPlistThemeEntry" != "" ]; then WriteToLog "$gNvramPlistFullPath contained the following theme at boot time: $gNvramPlistThemeEntry" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Sending UI: NvramP@${gNvramPlistThemeEntry}@" #SendToUI "NvramP@${gNvramPlistThemeEntry}@" SendToUI "Nvram‡${gNvramPlistThemeEntry}‡" CURRENT_THEME_ENTRY_NVRAM_PLIST="$gNvramPlistThemeEntry" PredictNextTheme fi fi } # --------------------------------------------------------------------------------------- ReadAndSendCurrentConfigPlistTheme() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}ReadAndSendCurrentConfigPlistTheme()" if [ -f "$gConfigPlistFullPath" ]; then # Extract theme name local themeName=$( /usr/libexec/PlistBuddy -c "Print:GUI:Theme" "$gConfigPlistFullPath" 2>/dev/null ) if [ "$themeName" != "" ]; then WriteToLog "$gConfigPlistFullPath contains theme entry $themeName" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Sending UI: ConfigP@${themeName}@" SendToUI "ConfigP‡${themeName}‡" CURRENT_THEME_ENTRY_CONFIG_PLIST="$themeName" PredictNextTheme else # Sending '-' to the UI here causes the drop down menu to be populated to the value '-' # which currently defaults to menu option ' ' WriteToLog "$gConfigPlistFullPath does not contain a theme entry" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Sending UI: ConfigP@-@" SendToUI "ConfigP‡-‡" PredictNextTheme fi else [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}$gConfigPlistFullPath does not exist." fi } # --------------------------------------------------------------------------------------- SetNvramTheme() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}SetNvramTheme()" local chosenTheme="$1" local successFlag=1 if [ $(CheckOsVersion) -ge 13 ]; then # com.apple.security.agentStub on Mavericks? successFlag=$( /usr/bin/osascript -e 'tell application "SecurityAgent" to activate'; \ /usr/bin/osascript -e "do shell script \"$uiSudoChanges \" & \"‡SetNVRAMVar\" & \"‡${chosenTheme}\" with administrator privileges" ) else successFlag=$( /usr/bin/osascript -e "do shell script \"$uiSudoChanges \" & \"‡SetNVRAMVar\" & \"‡${chosenTheme}\" with administrator privileges" ) fi # Was operation a success? if [ $successFlag -eq 0 ]; then WriteToLog "Setting NVRAM Variable was successful." else WriteToLog "Setting NVRAM Variable failed." fi # Read current Clover.Theme Nvram variable and send to UI. ReadAndSendCurrentNvramTheme } # --------------------------------------------------------------------------------------- DeleteNvramThemeVar() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}DeleteNvramThemeVar()" local successFlag=1 if [ $(CheckOsVersion) -ge 13 ]; then # com.apple.security.agentStub on Mavericks? successFlag=$( /usr/bin/osascript -e 'tell application "SecurityAgent" to activate'; \ /usr/bin/osascript -e "do shell script \"$uiSudoChanges \" & \"‡DeleteNVRAMVar\" with administrator privileges" ) else successFlag=$( /usr/bin/osascript -e "do shell script \"$uiSudoChanges \" & \"‡DeleteNVRAMVar\" with administrator privileges" ) fi # Was operation a success? if [ $successFlag -eq 0 ]; then WriteToLog "Deleting NVRAM Variable was successful." CURRENT_THEME_ENTRY_NVRAM="" else WriteToLog "Deleting NVRAM Variable failed." fi # Read current Clover.Theme Nvram variable and send to UI. ReadAndSendCurrentNvramTheme } # --------------------------------------------------------------------------------------- SetNvramFile() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}SetNvramFile()" local chosenTheme="$1" local successFlag=1 if [ -f "$gNvramPlistFullPath" ]; then if [ $(CheckOsVersion) -ge 13 ]; then # com.apple.security.agentStub on Mavericks? successFlag=$( /usr/bin/osascript -e 'tell application "SecurityAgent" to activate'; \ /usr/bin/osascript -e "do shell script \"$uiSudoChanges \" & \"‡SetNVRAMFile\" & \"‡${chosenTheme}\" & \"‡${gNvramPlistFullPath}\" with administrator privileges" ) else successFlag=$( /usr/bin/osascript -e "do shell script \"$uiSudoChanges \" & \"‡SetNVRAMFile\" & \"‡${chosenTheme}\" & \"‡${gNvramPlistFullPath}\" with administrator privileges" ) fi fi # Was operation a success? if [ $successFlag -eq 0 ]; then WriteToLog "Setting NVRAM Variable in $gNvramPlistFullPath was successful." else WriteToLog "Setting NVRAM Variable in $gNvramPlistFullPath failed." fi # Read current nvram.plist theme var and send to UI ReadAndSendCurrentNvramPlistTheme } # --------------------------------------------------------------------------------------- DeleteNvramPlistThemeEntry() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}DeleteNvramPlistThemeEntry()" local successFlag=1 if [ -f "$gNvramPlistFullPath" ]; then if [ $(CheckOsVersion) -ge 13 ]; then # com.apple.security.agentStub on Mavericks? successFlag=$( /usr/bin/osascript -e 'tell application "SecurityAgent" to activate'; \ /usr/bin/osascript -e "do shell script \"$uiSudoChanges \" & \"‡DeleteThemePlistEntry\" & \"‡${gNvramPlistFullPath}\" with administrator privileges" ) else successFlag=$( /usr/bin/osascript -e "do shell script \"$uiSudoChanges \" & \"‡DeleteThemePlistEntry\" & \"‡${gNvramPlistFullPath}\" with administrator privileges" ) fi fi # Was operation a success? if [ $successFlag -eq 0 ]; then WriteToLog "Deleting theme entry from $gNvramPlistFullPath was successful." CURRENT_THEME_ENTRY_NVRAM_PLIST="" else WriteToLog "Deleting theme entry from $gNvramPlistFullPath failed." fi # Read current nvram.plist theme var and send to UI ReadAndSendCurrentNvramPlistTheme } # --------------------------------------------------------------------------------------- SetConfigFile() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}SetConfigFile()" local chosenTheme="$1" local successFlag=1 if [ -f "$gConfigPlistFullPath" ]; then if [ $(CheckOsVersion) -ge 13 ]; then # com.apple.security.agentStub on Mavericks? successFlag=$( /usr/bin/osascript -e 'tell application "SecurityAgent" to activate'; \ /usr/bin/osascript -e "do shell script \"$uiSudoChanges \" & \"‡SetNVRAMFile\" & \"‡${chosenTheme}\" & \"‡${gConfigPlistFullPath}\" with administrator privileges" ) else successFlag=$( /usr/bin/osascript -e "do shell script \"$uiSudoChanges \" & \"‡SetNVRAMFile\" & \"‡${chosenTheme}\" & \"‡${gConfigPlistFullPath}\" with administrator privileges" ) fi fi # Was operation a success? if [ $successFlag -eq 0 ]; then WriteToLog "Setting theme in $gConfigPlistFullPath was successful." else [WriteToLog "Setting theme in $gConfigPlistFullPath failed." fi # Read current config.plist theme entry and send to UI ReadAndSendCurrentConfigPlistTheme } # --------------------------------------------------------------------------------------- DeleteConfigPlistThemeEntry() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}DeleteConfigPlistThemeEntry()" local successFlag=1 if [ -f "$gConfigPlistFullPath" ]; then if [ $(CheckOsVersion) -ge 13 ]; then # com.apple.security.agentStub on Mavericks? successFlag=$( /usr/bin/osascript -e 'tell application "SecurityAgent" to activate'; \ /usr/bin/osascript -e "do shell script \"$uiSudoChanges \" & \"‡DeleteThemePlistEntry\" & \"‡${gConfigPlistFullPath}\" with administrator privileges" ) else successFlag=$( /usr/bin/osascript -e "do shell script \"$uiSudoChanges \" & \"‡DeleteThemePlistEntry\" & \"‡${gConfigPlistFullPath}\" with administrator privileges" ) fi fi # Was operation a success? if [ $successFlag -eq 0 ]; then WriteToLog "Deleting theme entry from $gConfigPlistFullPath was successful." CURRENT_THEME_ENTRY_CONFIG_PLIST="" else WriteToLog "Deleting theme entry from $gConfigPlistFullPath failed." fi # Read current nvram.plist theme var and send to UI ReadAndSendCurrentConfigPlistTheme } # --------------------------------------------------------------------------------------- CheckIfThemeNoLongerInstalledThenDeleteLocalTheme() { # If all instances of a local bare repo theme.git have been uninstalled # then delete the local bare repo. [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}CheckIfThemeNoLongerInstalledThenDeleteLocalTheme()" local passedThemeName="$1" local foundTheme=0 for ((n=0; n<${#installedThemeName[@]}; n++ )); do if [ "${installedThemeName[$n]}" == "$passedThemeName" ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Keeping ${passedThemeName}.git local bare repo as it's still in use." foundTheme=1 break fi done if [ $foundTheme -eq 0 ]; then if [ -d "${WORKING_PATH}/${APP_DIR_NAME}/${passedThemeName}".git ]; then #WriteToLog "Local bare repo ${passedThemeName}.git is no longer in use. Deleting." [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Local bare repo ${passedThemeName}.git is now being deleted." rm -rf "${WORKING_PATH}/${APP_DIR_NAME}/${passedThemeName}".git fi fi } # --------------------------------------------------------------------------------------- CheckForThemeUpdates() { # Note: installedThemesOnCurrentVolume[] contains list of themes installed on the current theme path. # Plan: loop through this array and check for commit hash saved in .hash file at root of local theme dir. # If found, get current commit hash from server and compare. Any change indicates an update. [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}CheckForThemeUpdates()" [[ DEBUG -eq 1 ]] && WriteToLog "Num Themes in themeList=${#themeList[@]}" local updateAvailThemeStr="" local themeHashLocal="" local themeHashRepo="" local themeStillExistsInRepo=0 if [ "$TARGET_THEME_DIR" != "-" ]; then WriteToLog "Checking $TARGET_THEME_DIR for any theme updates." [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Sending UI: CheckingThemeUpdates@@" SendToUI "CheckingThemeUpdates‡‡" for ((t=0; t<${#installedThemesOnCurrentVolume[@]}; t++)) do themeStillExistsInRepo=0 # Check theme still exists in the repo for ((e=0; e<${#themeList[@]}; e++)) do if [ "${installedThemesOnCurrentVolume[$t]}" == "${themeList[$e]##*/}" ]; then themeStillExistsInRepo=1 break fi done # read hash from currently installed theme if [ -f "$TARGET_THEME_DIR"/"${installedThemesOnCurrentVolume[$t]}"/.hash ] && [ $themeStillExistsInRepo -eq 1 ]; then themeHashLocal=$( cat "$TARGET_THEME_DIR"/"${installedThemesOnCurrentVolume[$t]}"/.hash ) [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}themeHashLocal=$themeHashLocal" # get hash of theme in the repo themeHashRepo=$( "$gitCmd" ls-remote ${remoteRepositoryUrl}/themes.git/themes/"${installedThemesOnCurrentVolume[$t]}"/theme | grep refs/heads/master) WriteToLog "$themeHashRepo" themeHashRepo="${themeHashRepo:0:40}" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}themeHashRepo=$themeHashRepo" if [ "$themeHashRepo" != "" ]; then if [ "$themeHashLocal" != "$themeHashRepo" ]; then # Theme has been updated. WriteToLog "${installedThemesOnCurrentVolume[$t]} has an update available." [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}hash diff: $themeHashLocal | $themeHashRepo" updateAvailThemeStr="${updateAvailThemeStr},${installedThemesOnCurrentVolume[$t]}" else [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}hash matches. No update for ${installedThemesOnCurrentVolume[$t]}" fi else [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Failed to read hash for ${installedThemesOnCurrentVolume[$t]} from repository." fi else [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Theme ${installedThemesOnCurrentVolume[$t]} either has no hash, or theme no longer exists in the repository." fi done if [ "$updateAvailThemeStr" != "" ] && [ "${updateAvailThemeStr:0:1}" == "," ]; then # Sort comma separated list. # This is necessary only for applying different fills (shadows/without shadows) in JS ChangeButtonAndBandToUpdate() updateAvailThemeStr=$( LC_ALL=C; echo "$updateAvailThemeStr" | tr , "\n" | sort -f | tr "\n" , ) # Remove leading comma from string updateAvailThemeStr="${updateAvailThemeStr#?}" else WriteToLog "No theme updates found." fi [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Sending UI: UpdateAvailThemes‡${updateAvailThemeStr}‡" SendToUI "UpdateAvailThemes‡${updateAvailThemeStr}‡" fi } # --------------------------------------------------------------------------------------- CheckAndRemoveBareClonesNoLongerNeeded() { # Check each installed theme entry in prefs against themes installed in current # /EFI/Clover/Themes dir selected by user. # If prefs says a theme should be on selected volume but it's not (maybe user # manually removed it?), then remove entry from prefs. # Also check to see if the bare clone in support dir can be deleted. [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}CheckAndRemoveBareClonesNoLongerNeeded()" if [ ! "$TARGET_THEME_DIR" == "-" ]; then foundCloneToDelete=0 prefsNeedUpdating=0 # Loop through themes installed in prefs file for ((n=0; n<${#installedThemeName[@]}; n++ )); do # Check current partition GUID in prefs matches current partition GUID if [ "${installedThemePartitionGUID[$n]}" == "$TARGET_THEME_PARTITIONGUID" ]; then # Is theme installed in current theme dir? local themeIsInDir=0 for ((t=0; t<${#installedThemesOnCurrentVolume[@]}; t++)) do if [ "${installedThemeName[$n]}" == "${installedThemesOnCurrentVolume[$t]}" ]; then themeIsInDir=1 break fi done if [ $themeIsInDir -eq 0 ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Housekeeping: ${installedThemeName[$n]} exists in prefs for $TARGET_THEME_DIR but it's not installed!" foundCloneToDelete=1 # if bare clone exists in support dir then there's a chance it could be deleted. if [ -d "${WORKING_PATH}/${APP_DIR_NAME}/${installedThemeName[$n]}".git ]; then # Need to check the bare clone is not needed for a different volume though.. for ((x=0; x<${#installedThemeName[@]}; x++ )); do if [ "${installedThemeName[$n]}" == "${installedThemeName[$x]}" ]; then if [ "${installedThemePath[$n]}" != "${installedThemePath[$x]}" ]; then foundCloneToDelete=0 fi fi done if [ $foundCloneToDelete -eq 1 ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Housekeeping: Deleting bare clone ${installedThemeName[$n]}.git" cd "${WORKING_PATH}/${APP_DIR_NAME}" rm -rf "${installedThemeName[$n]}".git else WriteToLog "Housekeeping: Keeping bare clone ${installedThemeName[$n]}.git as it's used on another volume." fi fi # Set theme name to - # Doing this will effectively delete the theme from prefs as it # will be skipped in the loop in MaintainInstalledThemeListInPrefs() [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Housekeeping: Will remove prefs entry for ${installedThemeName[$n]} in $TARGET_THEME_DIR" prefsNeedUpdating=1 installedThemeName[$n]="-" fi fi done # Run routine to update prefs file. if [ $foundCloneToDelete -eq 1 ] || [ $prefsNeedUpdating -eq 1 ]; then MaintainInstalledThemeListInPrefs fi fi } # --------------------------------------------------------------------------------------- CleanInstalledThemesPrefEntries() { # Check for and remove any duplicate installed theme entries from prefs. # This should not happen in the first place but I have found some examples # during my local testing here. Could be a bug that needs finding! [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}CleanInstalledThemesPrefEntries()" foundEntryToDelete=0 for ((n=0; n<${#installedThemeName[@]}; n++ )); do for ((m=0; m<${#installedThemeName[@]}; m++ )); do if [ $m -ne $n ] && [ "${installedThemeName[$n]}" == "${installedThemeName[$m]}" ]; then # Found another theme entry by same name # Is this installed elsewhere or a duplicate entry? if [ "${installedThemePath[$n]}" == "${installedThemePath[$m]}" ] && \ [ "${installedThemePathDevice[$n]}" == "${installedThemePathDevice[$m]}" ] && \ [ "${installedThemePartitionGUID[$n]}" == "${installedThemePartitionGUID[$m]}" ]; then # Duplicate entry. Remove foundEntryToDelete=1 [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Housekeeping: Removing duplicate prefs entry for ${installedThemeName[$n]} at ${installedThemePath[$n]}." installedThemeName[$n]="-" fi fi done done # Run routine to update prefs file. if [ $foundEntryToDelete -eq 1 ]; then MaintainInstalledThemeListInPrefs fi } # --------------------------------------------------------------------------------------- IsGitInstalled() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}IsGitInstalled()" local tmp=$( which -a git ) local num=$( which -a git | wc -l ) [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Number of git installations: ${num##* }" [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}git installations: $tmp" if [ $( which -s git) ]; then # Alert user in UI WriteToLog "CTM_GitFail" else # a git file exists which is a start. gitCmd=$( which git ) # However.... # File /usr/bin/git exists by default from virgin OS X install. # But this is not the actual git executable that's installed # with Xcode command line tools. # /usr/bin/xcrun can find and return true location. # $ /usr/bin/xcrun --find git # Applications/Xcode.app/Contents/Developer/usr/bin/git # But.... # If user has not installed the Xcode command line developer tools # then trying to run /usr/bin/git or /usr/bin/xcrun will result in a # dialog in the Finder and also the following command line message: # xcode-select: note: no developer tools were found at # '/Applications/Xcode.app', requesting install. Choose an option # in the dialog to download the command line developer tools. # Thing is, we don't want to see a dialog box pop up in the Finder, # well not yet anyway. # Also, user may not want to install full Xcode command line tools. # They have the option to just install git from http://git-scm.com # If they install only git then we can use that. # Note: git installer creates: # directory /usr/local/git contain git files. # file /etc/paths.d/git containing /usr/local/git/bin # file /etc/manpaths.d/git containing /usr/local/git/bin/share/man # The paths.d entry appends /usr/local/git/bin to the end of $PATH # So we can't call git using just 'git' or /usr/bin/git gets called. # Also.... # We can't prepend /usr/local/git/bin to $PATH because # the users local command line returns different results to # what's returned from the command line when launched from a GUI app. # This could be a Yosemite? bug but any adjusted $PATH from say # a users ~/.bash_profile does not get presented to script from GUI. # For example from the users local command line: # $ which -a git # /usr/local/git/bin/git <-- $PATH entry added in ~/.bash_profile # /usr/bin/git # But from script launched from app # $ which -a git # /usr/bin/git <-- $PATH entry (above) is missing # So let's check for the full path and use that (if present). # Check for installed git from http://git-scm.com if [ -f /usr/local/git/bin/git ]; then gitCmd="/usr/local/git/bin/git" else # Nope.. # Time to actually run /usr/bin/git and see if Xcode developer # tools have been installed. If not a dialog will show in Finder. if [ "$gitCmd" == "/usr/bin/git" ]; then local catchReturn=$( /usr/bin/git 2>&1) if [[ "$catchReturn" == *"no developer tools were found"* ]]; then WriteToLog "CTM_GitFail" gitCmd="" else gitCmd="/usr/bin/git" fi fi fi if [ "$gitCmd" != "" ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}using git at :$gitCmd" # Check version local gitVersion=$( $gitCmd --version ) [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}$( $gitCmd --version )" if [ "$gitVersion" != "" ]; then [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}git version detection passed." WriteToLog "CTM_GitOK" else # Basic check for Xcode licence agreement local gitCheck=$( $gitCmd 2>&1 ) if [[ "$gitCheck" == *Xcode* ]]; then WriteToLog "Xcode licence has not yet been agreed to." WriteToLog "CTM_GitLicence" else [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}git version detection failed." WriteToLog "CTM_GitVersionFail" fi exit 1 fi fi fi } # --------------------------------------------------------------------------------------- CleanUp() { [[ DEBUG -eq 1 ]] && WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}CleanUp()" RemoveFile "$logJsToBash" RemoveFile "$logFile" RemoveFile "$themeDirInfo" RemoveFile "$logBashToJs" RemoveFile "$updateScript" RemoveFile "$espList" RemoveFile "$mbrList" RemoveFile "$bootLogFile" RemoveFile "$bootlogScriptOutfile" RemoveFile "$bootDeviceInfo" RemoveFile "${TEMPDIR}/add_theme.html" RemoveFile "${TEMPDIR}/managethemes.html" # Remove symbolic link for the themes dir if [ -h "${TEMPDIR}"/themes ]; then rm "${TEMPDIR}"/themes fi # Remove symbolic link for the scripts files if [ -h "${TEMPDIR}"/scripts/initialise.js ]; then rm "${TEMPDIR}"/scripts/initialise.js fi if [ -h "${TEMPDIR}"/scripts/jquery-2.1.3.min.js ]; then rm "${TEMPDIR}"/scripts/jquery-2.1.3.min.js fi # Remove symbolic link for the styles dir if [ -h "${TEMPDIR}"/styles ]; then rm "${TEMPDIR}"/styles fi # Remove symbolic link for the assets dir if [ -h "${TEMPDIR}"/assets ]; then rm "${TEMPDIR}"/assets fi #if [ -d "$tmp_dir" ]; then # rm -rf "$tmp_dir" #fi # Remove the copy of cloverthememanager.js if [ -f "${TEMPDIR}"/scripts/cloverthememanager.js ]; then rm "${TEMPDIR}"/scripts/cloverthememanager.js fi # Remove the temporary scripts dir if [ -d "${TEMPDIR}"/scripts ]; then rmdir "${TEMPDIR}"/scripts fi # Remove the temporary dir if [ -d "${TEMPDIR}" ]; then rmdir "${TEMPDIR}" fi # Check again and force if not removed if [ -d "${TEMPDIR}" ]; then rm -rf "${TEMPDIR}" fi } #=============================================================== # Main #=============================================================== # Make sure this script exits when parent app is closed. # Get process ID of this script scriptPid=$( echo "$$" ) # Get process ID of parent appPid=$( ps -p ${pid:-$$} -o ppid= ) # Resolve path SELF_PATH=$(cd -P -- "$(dirname -- "$0")" && pwd -P) && SELF_PATH=$SELF_PATH/$(basename -- "$0") source "${SELF_PATH%/*}"/shared.sh # Globals #gThemeRepoUrlFile="$PUBLIC_DIR"/theme_repo_url_list.txt gUserPrefsFileName="org.black.CloverThemeManager" gUserPrefsFile="$HOME/Library/Preferences/$gUserPrefsFileName" gThumbSizeX=0 gThumbSizeY=0 gUISettingViewUnInstalled="Show" gUISettingViewThumbnails="Show" gUISettingViewPreviews="Hide" gInitialising=0 # Send init messages to log file for initialise.js to read. gitCmd="" # Will be set to path to installed git binary to use gBootlogState="Open" # Default state for bootlog in UI. This is overridden by user prefs gNvramPlistFullPath="" # Will become full path if theme entry exists in nvram.plist gNvramPlistThemeEntry="" # Will become theme entry in nvram.plist gConfigPlistFullPath="" # Will become full path if theme entry exists in config.plist gBootType="" # Will become either UEFI or Legacy gNvramSave=1 # Set to 0 if writing to NVRAM is saved for next boot gBootDeviceIdentifier="" # Will become identifier of boot device gBootDeviceMountPoint="" # Will become mountpoint of boot device gConfigTextOnly=1 # Set to 0 if config plist contains textOnly gConfigFastBoot=1 # Set to 0 if config plist contains textOnly CURRENT_THEME_ENTRY_NVRAM="" CURRENT_THEME_ENTRY_NVRAM_PLIST="" CURRENT_THEME_ENTRY_CONFIG_PLIST="" TARGET_THEME_DIR="" TARGET_THEME_DIR_DEVICE="" TARGET_THEME_PARTITIONGUID="" # Find version of main app. mainAppInfoFilePath="${SELF_PATH%Resources*}" mainAppVersion=$( /usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString" "$mainAppInfoFilePath"/Info.plist ) # Begin log file RemoveFile "$logFile" WriteToLog "CTM_Version ${mainAppVersion}" WriteToLog "Started Clover Theme Manager script" getDate=$(date); WriteToLog "$getDate" WriteLinesToLog WriteToLog "scriptPid=$scriptPid | appPid=$appPid" WriteLinesToLog [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}PATH=$PATH" # Ensure permissions of findThemeDirs script if [ -f "$findThemeDirs" ]; then chmod 755 "$findThemeDirs" && [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}Set permissions of findThemeDirs script" fi # Ensure permissions of findThemeDirs script if [ -f "$bootlogScript" ]; then chmod 755 "$bootlogScript" && [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndent}Set permissions of bootlog script" fi WriteToLog "==== Initialisation Start ====" IsGitInstalled # Only continue if git is installed if [ "$gitCmd" != "" ]; then # Was this script called from a script or the command line identityCallerCheck=`ps -o stat= -p $$` if [ "${identityCallerCheck:1:1}" == "+" ]; then # Called from command line so interpret arguments. # Will expect 2 arguments # 1 - The install path # 2 - The theme name if [ "$#" -eq 2 ]; then TARGET_THEME_DIR="$1" themeToInstall="$2" else echo "Error - wrong number of arguments passed." echo "Expects 1st as full target path. 2nd Theme name" exit 1 fi # Redirect all log file output to stdout COMMANDLINE=1 # Should we be checking the theme exists on the repo? # Currently this does not happen. # Does theme path exist? if [ -d "$TARGET_THEME_DIR" ]; then RunThemeAction "Install" "$themeToInstall" returnValue=$? if [ ${returnValue} -eq 0 ]; then # Operation was successful echo "Theme $themeToInstall was successfully installed to $TARGET_THEME_DIR" exit 0 else echo "Error - Theme $themeToInstall failed to be installed to $TARGET_THEME_DIR" exit 1 fi else echo "Error - Target path $TARGET_THEME_DIR does not exist." exit 1 fi else # Called from Clover Theme Manager.app # Arrays for theme.plists declare -a themeList # holds the name of each theme declare -a themeTitle # holds the title of each theme declare -a themeAuthor # holds the author of each theme declare -a themeDescription # holds the description of each theme # Arrays for saving volume info declare -a duIdentifier # holds the Disk Util identifier of available volume paths declare -a duVolumeName # holds the Disk Util volume name of available volume paths declare -a duVolumeMountPoint # holds the Disk Util mountpoint of available volume paths declare -a duContent # holds the Disk Util content of available volume paths declare -a duPartitionGuid # holds the Disk Util UUID of available volume paths # Arrays for theme declare -a themeDirPaths # holds full path of theme directory on each volume declare -a installedThemesOnCurrentVolume # holds list of themes on currently selected volume declare -a installedThemesFoundAfterSearch # holds list of themes found on the selected volume # Arrays for list of what themes are installed where. declare -a installedThemeName # holds installed theme names read from prefs declare -a installedThemePath # holds theme paths for installed themes read from prefs declare -a installedThemePathDevice # holds theme device identifiers for installed themes read from prefs declare -a installedThemePartitionGUID # holds theme device UUID's for installed themes read from prefs # Globals for newly installed theme before adding to prefs ResetNewlyInstalledThemeVars ResetUnInstalledThemeVars # For using additional theme repositories. # Not working in this version #declare -a repositoryUrls #declare -a repositoryThemes #tmp_dir=$(mktemp -d -t theme_manager) #ReadRepoUrlList # Run child script to gather information of volumes with /EFI/Clover/Themes directories "$findThemeDirs" & RefreshHtmlTemplates "managethemes.html" IsRepositoryLive EnsureLocalSupportDir # Clean any old files from support dir from previous app versions if [ -f "${WORKING_PATH}/${APP_DIR_NAME}"/*.plist ]; then rm "${WORKING_PATH}/${APP_DIR_NAME}"/*.plist fi if [ -f "${WORKING_PATH}/${APP_DIR_NAME}"/dropdown_html ]; then rm "${WORKING_PATH}/${APP_DIR_NAME}"/dropdown_html fi if [ -f "${WORKING_PATH}/${APP_DIR_NAME}"/theme_html ]; then rm "${WORKING_PATH}/${APP_DIR_NAME}"/theme_html fi # Copy cloverthememanager.js to temp dir mkdir "$TEMPDIR"/scripts cp "$JSSCRIPTS_DIR"/cloverthememanager.js "$TEMPDIR"/scripts EnsureSymlinks GetLatestIndexAndEnsureThemeHtml WriteToLog "CTM_ThemeDirsScan" wait # Check for preferences file and add message in to log for initialise.js to detect. if [ -f "$gUserPrefsFile".plist ]; then [[ $gInitialising -eq 0 ]] && WriteToLog "CTM_ReadPrefsOK" fi ReadPrefsFile CleanInstalledThemesPrefEntries # Search ioreg for bootlog and write to file. GetBootlog # Identify boot device from bootlog and try to have it available. # If MBR, try to find it among currently mounted devices. # If GPT, match GUID from devicepath. If unmounted ESP, then mount. # Returns identifier. For example, disk0s1 gBootDeviceIdentifier=$( GetSelfDevicePath ) # Calls MountESPAndSearchThemesPath (if GPT and ESP is not mounted) # Build internal theme list ReadThemeDirList # Set internal target and mountpoint then notify UI SetTargetAndMountpoint # Send list of volumes with /EFI/Clover/Themes directories to UI CreateAndSendVolumeDropDownMenu if [ $? -eq 0 ]; then WriteToLog "CTM_DropDownListOK" else WriteToLog "CTM_DropDownListNone" fi # Run bootlog script to read bootlog for theme info and populate theme control paths ReadBootLogAndSetPaths "Init" # Set last used volumes (as read from prefs), if boot device was not found. if [ "$TARGET_THEME_DIR" == "" ] || [ "$TARGET_THEME_DIR" == "-" ]; then MapLastSelectedPathToGUID fi # Inject this as it will be hidden if boot device has not been identified. # This way the html will exist so if the user decides to rescan boot device, the # paths can be updated in cloverthememanager.js CreateControlOptionsHtmlAndInsert WriteToLog "Using target $TARGET_THEME_DIR on device $TARGET_THEME_DIR_DEVICE with GUID $TARGET_THEME_PARTITIONGUID" # Send UI target theme entry to display, and other data to set default / restore state of main UI page SendUIInitData # Read each available place where theme entry could be ReadThemeEntriesAndSendToUI # Show theme setting control options depending on currently selected device ShowHideUIControlOptions # If OS is newer than Lion then enable notifications if [ $(CheckOsVersion) -gt 11 ]; then InsertNotificationCodeInToJS fi # Write string to mark the end of init. # initialise.js looks for this to signify initialisation is complete. # At which point it then redirects to the main UI page. WriteToLog "Complete!" WriteToLog "==== Initialisation End ====" # Feedback for command line echo "Initialisation complete. Entering loop." # Set initialising var to 1 to disable some init messages no longer needed in the log file. gInitialising=1 # Remember parent process id parentId=$appPid CheckAndRemoveBareClonesNoLongerNeeded CheckForAndRemoveThemeGitDirs CheckForThemeUpdates & [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Sending UI: EnableInterface@@" SendToUI "EnableInterface‡‡" # The messaging system is event driven and quite simple. # Run a loop for as long as the parent process ID still exists while [ "$appPid" == "$parentId" ]; do sleep 0.25 # Check every 1/4 second. #=============================================================== # Main Message Loop for responding to UI feedback #=============================================================== # Read first line of log file logLine=$(head -n 1 "$logJsToBash") # Has user selected partition for an /EFI/Clover/themes directory? if [[ "$logLine" == *CTM_selectedPartition* ]]; then ClearTopOfMessageLog "$logJsToBash" # js sends "CTM_selectedPartition@" + selectedPartition # where selectedPartition is the array element id of RespondToUserDeviceSelection "$logLine" # Has the user clicked the Rescan Boot Device button? elif [[ "$logLine" == *RescanBootDevice* ]]; then ClearTopOfMessageLog "$logJsToBash" WriteToLog "User selected to Rescan boot device" gBootDeviceIdentifier=$( GetSelfDevicePath ) ReadThemeDirList SetTargetAndMountpoint CreateAndSendVolumeDropDownMenu ReadBootLogAndSetPaths "Rescan" SendTargetToUiRunChecks CheckForThemeUpdates & ReadThemeEntriesAndSendToUI nvramPath="" configPath="" mountpoint="" if [ -f "$gNvramPlistFullPath" ]; then nvramPath="$gNvramPlistFullPath" fi if [ -f "$gConfigPlistFullPath" ]; then configPath="$gConfigPlistFullPath" configPath=$( RenameInternalESPMountPointToEFI "$configPath" ) fi if [ "$gBootDeviceMountPoint" != "" ]; then mountpoint="$gBootDeviceMountPoint" fi [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Sending UI: UpdateThemePaths@${nvramPath}@${configPath}@${mountpoint}" SendToUI "UpdateThemePaths‡${nvramPath}‡${configPath}‡${mountpoint}" ShowHideUIControlOptions # Has the user clicked the OpenPath button? elif [[ "$logLine" == *OpenPath* ]]; then ClearTopOfMessageLog "$logJsToBash" CheckThemePathIsStillValid retVal=$? # returns 1 if invalid / 0 if valid if [ $retVal -eq 0 ]; then [[ ! "$TARGET_THEME_DIR" == "-" ]] && Open "$TARGET_THEME_DIR" fi WriteToLog "User selected to open $TARGET_THEME_DIR" # Has the user clicked the MountESP button? elif [[ "$logLine" == *MountESP* ]]; then ClearTopOfMessageLog "$logJsToBash" WriteToLog "User selected to Mount ESP. Looking for EFI/Clover/Themes directory." checkAction=$(MountESPAndSearchThemesPath "$gBootDeviceIdentifier") if [ "$checkAction" != "Failed" ]; then ReadThemeDirList CreateAndSendVolumeDropDownMenu [[ DEBUG -eq 1 ]] && WriteToLog "${debugIndentTwo}Sending UI: Target@$espID" SendToUI "Target‡$espID" RespondToUserDeviceSelection "‡$espID" fi # Has the user pressed a theme button to install, uninstall or update? elif [[ "$logLine" == *CTM_ThemeAction* ]]; then ClearTopOfMessageLog "$logJsToBash" RespondToUserThemeAction "$logLine" returnValue=$? if [ ${returnValue} -eq 0 ]; then # Operation was successful GetListOfInstalledThemesAndSendToUI GetFreeSpaceOfTargetDeviceAndSendToUI CheckAndRecordUnManagedThemesAndSendToUI ReadThemeEntriesAndSendToUI fi # Has the user pressed the Update All button? elif [[ "$logLine" == *CTM_UpdateAll* ]]; then ClearTopOfMessageLog "$logJsToBash" RespondToUpdateAll "$logLine" # Has user selected a theme control option? elif [[ "$logLine" == *CTM_changeTheme* ]]; then ClearTopOfMessageLog "$logJsToBash" RespondToDropDownMenuChange "$logLine" # Has user changed the thumbnail size? elif [[ "$logLine" == *CTM_thumbSize* ]]; then ClearTopOfMessageLog "$logJsToBash" # parse message # remove everything up until, and including, the first ‡ thumbSize="${logLine#*‡}" UpdatePrefsKey "Thumbnail" "$thumbSize" WriteToLog "User changed thumbnail size to $thumbSize" # Has user chosen to show uninstalled themes? elif [[ "$logLine" == *CTM_showUninstalled* ]]; then ClearTopOfMessageLog "$logJsToBash" UpdatePrefsKey "UnInstalledButton" "Show" WriteToLog "User chose to show all themes" # Has user chosen to hide uninstalled themes? elif [[ "$logLine" == *CTM_hideUninstalled* ]]; then ClearTopOfMessageLog "$logJsToBash" UpdatePrefsKey "UnInstalledButton" "Hide" WriteToLog "User chose to hide uninstalled themes" # Has user chosen to show thumbnails? elif [[ "$logLine" == *CTM_hideThumbails* ]]; then ClearTopOfMessageLog "$logJsToBash" UpdatePrefsKey "ViewThumbnails" "Show" WriteToLog "User chose to show thumbnails" # Has user chosen to hide thumbnails? elif [[ "$logLine" == *CTM_showThumbails* ]]; then ClearTopOfMessageLog "$logJsToBash" UpdatePrefsKey "ViewThumbnails" "Hide" WriteToLog "User chose to hide thumbnails" # Has user chosen to hide previews? elif [[ "$logLine" == *CTM_hidePreviews* ]]; then ClearTopOfMessageLog "$logJsToBash" UpdatePrefsKey "ShowPreviewsButton" "Hide" WriteToLog "User chose to hide previews" # Has user chosen to show preview? elif [[ "$logLine" == *CTM_showPreviews* ]]; then ClearTopOfMessageLog "$logJsToBash" UpdatePrefsKey "ShowPreviewsButton" "Show" WriteToLog "User chose to show previews" elif [[ "$logLine" == *started* ]]; then ClearTopOfMessageLog "$logJsToBash" # Has user chosen to show/hide bootlog info? elif [[ "$logLine" == *CTM_bootlog* ]]; then ClearTopOfMessageLog "$logJsToBash" # remove everything up until, and including, the first ‡ gBootlogState="${logLine#*‡}" UpdatePrefsKey "ShowHideBootlog" "$gBootlogState" # Clear and Relaunch messages? elif [[ "$logLine" == *Relaunch* ]]; then ClearTopOfMessageLog "$logJsToBash" # Look out for App Transport Security message and clear elif [[ "$logLine" == *Transport* ]]; then ClearTopOfMessageLog "$logJsToBash" # App temporary work around for *** WARNING: Method convertPointToBase: elif [[ "$logLine" == *convertPointToBase* ]]; then ClearTopOfMessageLog "$logJsToBash" fi # Get process ID of parent appPid=$( ps -p ${pid:-$$} -o ppid= ) done # CleanUp # /tmp/CloverThemeManager Dir is now deleted by main app on exit. exit 0 fi else WriteToLog "CTM_GitFail" exit 1 fi