#!/bin/bash
# iRetinizeBoot 1.0
# Original idea: Ardu
# Mod iSmoothProject


clearline() {
        echo -en \r
        printf "%$(($(tput cols)-1))s"
}
cleanup() {
        cd "$ORIG_DIR"
        if [ "$tmpdir" ] && [ -d "$tmpdir" ]; then
                rm -rf "$tmpdir"
        fi
        
        # Print prompt on a new line if unfinished
        printf "%$(($(tput cols)-1))s\r"
}
debugPause() {
        echo "DEBUG PAUSE"
        read -s -n 1 dummy
}
prompt() {
        local answer=""
        local allowed="YN"
        [ $# == 0 ] && return
        while [ $# -gt 0 ]; do
                case "$1" in
                        -a | --allowed-answers )        local allowed="$(echo "$2" | tr [:lower:] [:upper:])"; shift;;
                        -p | --prompt )                         local prompt="$2"; shift;;
                esac
                shift
        done

        if [ "$prompt" == "$(echo "$prompt" | tr -d [])" ]; then
                local i=0
                local padd="["
                for ((i=0; i<${#allowed}; i++)); do
                        [ $i != 0 ] && [ $i != "${#allowed}" ] && local padd+="/"
                        local padd+="${allowed:$i:1}"
                done
                local padd+="]"
                prompt+=" $padd: "
        fi
        
        # Dirty and nasty GUI mode support assumes yes to all queries
        if [ "$GUI" == 1 ]; then
                ret="Y"
                return 0
        fi
        
        while [ ! $answer ]; do
                read -n 1 -p "$prompt" answer; echo
                answer="$(echo "$answer" | tr [:lower:] [:upper:] | tr -dc "$allowed")"
                
                local i=0
                for ((i=0; i<${#allowed}; i++)); do
                        local char="${allowed:$i:1}"
                        if [ "$answer" == "$char" ]; then
                                ret="$answer"
                                return $i
                        fi
                done
                echo "Invalid response"
                answer=""
        done
}

# Functions specific to iRetiner.sh
artworkToIcon() {
        local target="$1"
        local iTunesArtwork="$2"
        [ ! -f "$iTunesArtwork" ] && continue
        
        local tmpicon="$(mktemp -u "$tmpdir/Icon-XXXXXXXX").jpg"
        djpeg -outfile "$tmpicon" "$iTunesArtwork"
        rm -rf "$target"
        convert "$tmpicon" -resize "$RETINA_SIZE" "$tmpicon.png"
        pincrush "$tmpicon.png" "$target" 2>/dev/null
        rm -rf "$tmpicon" "$tmpicon.png"
}
backup() {
        local file="$1"
        if [ -f "$file" ] && [ ! -f "$file.orig" ]; then
                local timestamp="$(mktemp "$tmpdir/timestamp-XXXXXXXX")"
                touch --reference="$file" "$timestamp"
                cp -p "$file" "$file.orig"
                touch --no-create --reference "$timestamp" "$file"
                touch --no-create --reference "$timestamp" "$file.orig"
                rm -rf "$timestamp"
        fi
}               
findCFBundleIconFile() {
        local fullpath="$1"
        local CFBundleIconFile="$(plutil -key CFBundleIconFile "$fullpath/Info.plist" 2>/dev/null)"
        if [ ! -f "$fullpath/$CFBundleIconFile" ]; then
                for CFBundleIconFile in "Icon.png" "icon.png" "Icon.PNG" "icon.PNG" "ICON.png" "ICON.PNG"; do
                        [ -f "$fullpath/$CFBundleIconFile" ] && break
                done
        fi
        echo "$CFBundleIconFile"
}
ignoreicon() { # Returns 0 for continue, 1 for ignore
        local fullpath="$1"
        local CFBundleIconFile="$2"
        
        local test="$(echo -En "$CFBundleIconFile" | sed 's/\(.*\)\..*/\1/')"
        if [ ! -f "$fullpath/$CFBundleIconFile" ] || [ -f "$fullpath/$CFBundleIconFile.orig" ] || \
                [ -f "$fullpath/$test@2x.png" ] || [ -f "$fullpath/$test@2x.PNG" ] || \
                [ -f "$fullpath/$test@2X.png" ] || [ -f "$fullpath/$test@2X.PNG" ]; then
                ret=1
        else
                ret=0
        fi
        return "$ret"
}
setupvars() {
        local sandpath="$1"
        baseapp="$(basename "$sandpath/"*.app 2>/dev/null)"
        iTunesArtwork="$sandpath/iTunesArtwork"
        Info="$sandpath/$baseapp/Info.plist"
        fullpath="$sandpath/$baseapp"
}

# bashtrackr, apptrackr API bash library (by ttwj)
# http://hackulo.us/forums/index.php?/topic/98106-release-bashtrackr-apptrackr-api-library-in-bash/
# apptrackr API info as of Nov 2010
# Version 0.1, by ttwj
# Thanks to
# MadHouse - For JSON parsing methods and help with apptrackr API
# ajm2k - For JSON parsing methods
# People on #bash on freenode for helping
data_parse() {
        # data.fetch <string>
        # fetch the code
        code=$(echo "$1" | tr '{', '\n' | sed -n "2p" | sed -e 's/:/ /' | awk '{print $2}')
        if [ "${code:0:1}" != "2" ]; then
                # :(
                # echo "Error: response code $code was returned, please check http://hackulo.us/fo...-apptrackr-api/ for list of response codes"
                false
        else
                string=$(echo "$1" | tr '{', '\n' | sed -e '/"signature":\(.*\)/d;/"data":\(.*\)/d;/"signature":\(.*\)/d;/"code":\(.*\)/d' |sed -e 's/\\"//g;s/\\\\\\\//\//g;s/\\//g' | tr '}', '\n' | sed -e 's/"//' | sed '/^$/d')
                echo "$string"
        fi
}
request_send() {
        # array.send <string> <API Location (optional)>
        # quote string
        string=$(echo "$1" | sed -e 's/"/\\"/g')
        string='{"request":"'"$string"'"}'
        if [ "$2" ]; then
                api="$2"
        else
                api="http://api.apptrackr.org"
        fi
        output=$(curl -s -d "request=$string" "$api")
        echo "$output"
}
app_checkUpdates() {
        #app.checkUpdates <app ids>
        for i in ${@}; do
                appids=$((appids+1))
                if [ "$appids" -gt "100" ]; then
                        echo "Error, cannot check for more than 100 updates."
                        break
                        return 0
                fi
                if [ "$appids" -gt "1" ]; then
                        string="$string, $i"
                else
                        string="$i"
                fi
        done    
        json='{"object":"App","action":"checkUpdates","args":{"appids":['"$string"']}}'
        echo "$json"
}
app_getDetails() {
        # app_getDetails <app id> <fields>
        supported_list="appid scrapeid add_date last_modification itunesurl name seller category storeid size latest_version release_date copyright price rating icon57 icon75 icon100 icon175 description whatsnew requirements languages universal"
        for i in ${@:2}; do
                if [ "$(echo "$supported_list" | grep -w "$i")" ]; then
                                if [ ! "$field" ]; then
                                        field="\"$i\""
                                else
                                        field="$field, \"$i\""
                                fi
                        else
                                #echo "Error: unknown field requested, please check http://hackulo.us/fo...-apptrackr-api/ for a list of supported fields"
                                return 0
                fi
        done
        json='{"object":"App","action":"getDetails","args":{"app_id":'$1',"fields":['$field']}}'
        echo "$json"
}
app_getList() {
        #app.getList <appsPerPage> <sort> <page> <search (optional)> <category (optional)> <showPageCount (optional)> <deviceid (optional)>
        #do some checks..
        if [ ! "$1" ]; then echo "Error: Missing appsPerPage"; return 0; fi
        if [ ! "$2" ]; then echo "Error: Missing sort"; return 0; fi
        if [ ! "$3" ]; then echo "Error: Missing page"; return 0; fi
        if [ ! "$(echo '15 30 60 null' | grep -w "$1")" ]; then echo "Error: appsPerPage can only be 15, 30 or 60, please check the apptrackr API documentation for more info"; return 0; fi
        if [ ! "$(echo '0 1 2 null' | grep -w "$8")" ]; then echo "Error: deviceid can only be 0 (All), 1 (iPhone/iPod Touch) and 2 (iPad)."; return 0; fi
        if [ ! "$4" = "null" ]; then 
                string=", \"search\":\"$4\""
        else
                string=""
        fi
        if [ ! "$5" = "null" ]; then
                string="$string, \"category\":$5"
        fi
        if [ ! "$6" = "null" ]; then
                string="$string, \"showPageCount\":$6"
        fi
        if [ ! "$7" = "null" ]; then
                string="$string, \"deviceid\":$7"
        fi
        json='{"object": "App","action":"getList","args":{"appsPerPage":'$1',"sort":'$2',"page":'$3''$string'}}'
        echo "$json"
}
app_scrape() {
        #this part was the easiest to do :3
        #app.scrape <itunes url>
        if [[ ! "$1" = *http*://*itunes*.*apple*.*com* ]]; then
                echo "Error: Not a valid iTunes URL"
                return 0
        fi
        json='{"object":"App","action":"scrape","args":{"itunes_url":"'$1'"}}'
        echo "$json"
}
bundle_getItunesIDs() {
        # getItunesIDs <app ids>
        [ "${#@}" -le 0 ] && return 1

        local string="\"$1\""
        shift
        local appid=""
        for appid in ${@}; do
                string="$string, \"$appid\""
                shift
        done

        json="{\"object\":\"Bundle\",\"action\":\"getItunesIDs\",\"args\":{\"bundleList\":[$string]}}"
        echo "$json"
}
category_getList() {
        json='{"object": "Category","action": "getList"}'
        echo "$json"
}
link_get() {
        #link.get <appid>
        if [ ! "$1" ]; then echo "Error: Please input an appid"; return 0; fi
        json='{"object": "Link","action": "get","args": {"app_id": '$1'}}'
        echo "$json"
}
screenshot_get() {
        #screenshot.get <appid>
        if [ ! "$1" ]; then echo "Error: Please input an appid"; return 0; fi
        json='{"object": "Screenshot","action": "get","args": {"app_id": '$1'}}'
        echo "$json"
}
user_checkAuth() {
        #user.checkAuth <username> <passhash>
        if [ ! "$1" ]; then echo "Error: Please input a username"; return 0; fi
        if [ ! "$2" ]; then echo "Error: Please input a passhash"; return 0; fi
        json='{"object": "User","action": "checkAuth","auth": {"username": "'$1'","passhash": "'$2'"}}'
        echo "$json"
}
# end bashtrackr code

# Constants
ICONCACHE_DIR="/var/mobile/Library/Caches/com.apple.IconsCache"
LIST_SPLIT_LIMIT="20"
ORIG_DIR="$PWD"
RETINA_SIZE="114x114"
SANDBOX_ROOTS="/var/mobile/Applications"
SCRIPT_NAME="iRetiner.sh"
SCRIPT_VERSION="0.51"

GUI=0

trap "cleanup; exit" ABRT EXIT HUP INT TERM QUIT
ret=0
menuOptions=("Adapt all icons using iTunesArtwork " "Download and adapt specific icons from iTunes" \
        "Revert adapted Retina icons to original icons" \
        "Help/About" "Exit")

# ----====== Interface begins here ======----
clear
echo "$SCRIPT_NAME ($SCRIPT_VERSION)"
printf "%$(tput cols)s" | tr " " "="

# Dependency checking
for dependency in com.ericasadun.utilities \
        coreutils curl gawk grep imagemagick \
        jpeg pincrush sed shell-cmds wget; do
        if [ ! -f "/var/lib/dpkg/info/$dependency.list" ]; then
                [ ! "$missing" ] && missing="$dependency"
                [ "$missing" ] && missing+=" $dependency"
        fi
done
if [ "$missing" ]; then
        echo "$SCRIPT_NAME depends on the missing package(s) $missing" >&2
        if [ ! -f "/usr/bin/apt-get" ]; then
                echo "Install from Cydia to fix" >&2
                exit 1
        elif [ -f "/usr/bin/apt-get" ]; then
                prompt -p "Install now"
                if [ "$ret" == "Y" ]; then
                        apt-get --force-yes install $missing
                elif [ "$ret" == "N" ]; then
                        echo "Aborting" >&2
                        exit 1
                fi
        fi
fi

[ "$(deviceinfo -c | grep -i -e M68AP -e N82AP -e N88AP -e N45AP -e N72AP -e N18AP)" ] && RETINA_SIZE="57x57"

tmpdir="$(mktemp -d /tmp/$(basename "$0" .sh)-XXXXXXXX)"

while [ "$#" -gt 0 ]; do
        case "$1" in
                -a | -adapt )   # Retina display adaption using local iTunesArtwork
                menuSelectionNumber=1
                GUI=1
                ;;
                
                -r | -revert )  # Revert icons
                menuSelectionNumber=3
                GUI=1
                ;;
        esac
        shift
done

if [ "$GUI" == 0 ]; then
menuSelectionNumber="1"
         
                break
fi


case $menuSelectionNumber in
        ${#menuOptions[@]} ) # Exit
        exit 0
        ;;
                
        $((${#menuOptions[@]} - 1)) ) # Help screen
        echo -e "Usage: $(basename "$0")"
        echo -e "Coded by dxs"
        echo -e "Original idea by Ardu"
        echo -e "Thanks to ttwj for the bashtrackr library, used in the download method"
        echo
        echo -e "Report bugs to dxs444@gmail.com"
        echo -e "Adds Retina Display icons to AppStore apps"
        echo -e "As usual, use at your own risk."
        echo
        echo -e "Neither the iTunesArtwork method or the download method is superior to one another, only the source of the image differs"
        echo
        echo -e "If you have used version 0.3 of $SCRIPT_NAME, you may have noticed the speed at which apps are processed is slower"
        echo -e "This is because the new icons are now being converted and resized, so to improve operating system performance"
        echo -e
        echo -e "Command line usage:"
        echo -e "-a | -adapt"
        echo -e "Adapt all icons to Retina Display using local iTunesArtwork"
        echo -e
        echo -e "-r | -revert"
        echo -e "Revert all icons to original states"
        exit 0
        ;;
        
        * ) #Confirm action
        echo
        echo "Operation: $menuSelectionText"
       
        ;;& # Special ";;&" allows case to keep on checking following conditions
        
        1 ) # iTunesArtwork method
        progress_current=0
        progress_full="$(ls -x -1 "$SANDBOX_ROOTS" | wc -l)"
        ls -x -1 "$SANDBOX_ROOTS" | while read sandbox; do      
                ((progress_current++))
                progress_percent=$(($progress_current*100 / $progress_full))
                echo -en "\rAdding Retina Display icons $progress_percent% ($progress_current/$progress_full)"
                
                setupvars "$SANDBOX_ROOTS/$sandbox"
                [ ! -f "$Info" ] && continue
                [ ! -f "$iTunesArtwork" ] && continue
                
                CFBundleIconFile="$(findCFBundleIconFile "$fullpath")"
                [ ! -f "$fullpath/$CFBundleIconFile" ] && continue
                
                ignoreicon "$fullpath" "$CFBundleIconFile"
                [ "$ret" == 1 ] && continue
                        
                target="$fullpath/$CFBundleIconFile"
                touch --reference="$target" "$tmpdir/timestamp.tmp"
                backup "$target"
                artworkToIcon "$target" "$iTunesArtwork"
                touch --no-create --reference="$tmpdir/timestamp.tmp" "$target"
        done; echo # This last "echo" ends the progress indicator
        ;;
        
        2 ) # AppTrackr API method
        # Database is built as AppList.txt
        # Format of AppList.txt:
        # (Sandbox Path + Basename) (CFBundleIdentifier) (CFBundleIconFile) (iTunes ID) (iTunes URL) (Icon175 Link)
        echo -e "Listing apps"
        rm -rf "$tmpdir/"*.tmp
        i="$(($(echo -En "$SANDBOX_ROOTS/00000000-0000-0000-0000-000000000000/Dummy.app" | tr -dc / | wc -c) + 1))"
        ls -x -1 -d "$SANDBOX_ROOTS"/*/*.app 2>/dev/null | sed -e 's,\(.\)/$,\1,' | sort -d -f -k "$i" -t'/' > "$tmpdir/AppList.tmp"
        if [ ! -f "$tmpdir/AppList.tmp" ]; then
                echo "No apps are installed"
                exit 3
        fi
        
        oldIFS="$IFS"; IFS=$'\n'
        numApps="$(cat "$tmpdir/AppList.tmp" | wc -l 2>/dev/null)"
        numField="$(($(echo -En "$SANDBOX_ROOTS" | tr -dc "/" | wc -m) + 2))"
        PS3="Select app(s), seperated by space(s): "
        select baseapp in $(cat "$tmpdir/AppList.tmp" | awk -F / '{print $NF}' | sed 's/\.app$//g'); do
                i="$(echo -En "$REPLY" | tr -dc "0-9 ")"
                if [ "$i" == 0 ] || [ "$REPLY" == "TERMINATE" ]; then
                        echo "Terminated"
                        exit 4
                else
                        break
                fi
        done
        IFS="$oldIFS"
        for selection in $i; do
                if [ ! "$selection" ] || [ "$selection" -lt 1 ] || [ "$selection" -gt "$numApps" ]; then
                        echo "Invalid selection \"$selection\""
                        continue
                else
                        awk "NR == $selection {print; exit}" "$tmpdir/AppList.tmp" | cut -d "/" -f "$numField" >> "$tmpdir/Queue.tmp"
                        # echo -En "Queued :"
                        # awk "NR == $selection {print; exit}" "$tmpdir/AppList.tmp" | cut -d "/" -f "$numField"
                fi
        done

        if [ ! -f "$tmpdir/Queue.tmp" ]; then
                echo "No apps selected"
                exit 2
        fi
        # Listing apps
        progress_current=0
        progress_full="$(ls -x -1 "$SANDBOX_ROOTS" | wc -l)"
        cat "$tmpdir/Queue.tmp" | while read sandbox; do
                ((progress_current++))
                progress_percent=$(($progress_current*100 / $progress_full))
                echo -en "\rListing apps $progress_percent% ($progress_current/$progress_full)"

                setupvars "$SANDBOX_ROOTS/$sandbox"
                
                # Finding CFBundleIdentifier
                CFBundleIdentifier="$(plutil -key CFBundleIdentifier "$fullpath/Info.plist" 2>/dev/null)"
                [ ! "$CFBundleIdentifier" ] && continue
        
                CFBundleIconFile="$(findCFBundleIconFile "$fullpath")"
                
                ignoreicon "$fullpath" "$CFBundleIconFile"
                [ "$ret" == 1 ] && continue
        
                # Self-explanatory
                echo -En "$fullpath" >> "$tmpdir/AppList.txt"
                echo -en $'\t' >> "$tmpdir/AppList.txt"
                echo -En "$CFBundleIdentifier" >> "$tmpdir/AppList.txt"
                echo -en $'\t' >> "$tmpdir/AppList.txt"
                echo -E "$CFBundleIconFile" >> "$tmpdir/AppList.txt"
        done; echo
        rm -rf "$tmpdir/"*.tmp
        
        # Getting iTunesIDs
        progress_current=0
        progress_full="$(cat "$tmpdir/AppList.txt" | wc -l)"
        i=0; cat "$tmpdir/AppList.txt" | while read line; do
                ((progress_current++))
                progress_percent=$(($progress_current*100 / $progress_full))
                echo -en "\rReading iTunesMetadata.plist $progress_percent% ($progress_current/$progress_full)"
                
                sandboxPath="$(echo -En "$line" | cut -d $'\t' -f 1)"
                CFBundleIdentifier="$(echo -En "$line" | cut -d $'\t' -f 2)"
                iTunesMetadata="$(dirname "$sandboxPath" 2>/dev/null)/iTunesMetadata.plist"
                
                while [ 1 ]; do
                        if [ -f "$iTunesMetadata" ]; then
                                iTunesID="$(plutil -key itemId "$iTunesMetadata" 2>/dev/null)"
                                if [ "$iTunesID" ]; then
                                        echo -En "$line" >> "$tmpdir/AppListNew.tmp"
                                        echo -en $'\t' >> "$tmpdir/AppListNew.tmp"
                                        echo -E "$iTunesID" >> "$tmpdir/AppListNew.tmp"
                                        break
                                fi
                        fi
                        pi="$(($i / $LIST_SPLIT_LIMIT))"
                        echo -E "$line" >> "$tmpdir/RequestID[$pi].tmp"
                        ((i++))
                        break
                done
        done; echo
        
        progress_current=0
        progress_full="$(ls "$tmpdir/RequestID"*".tmp" | wc -l)"
        oldIFS="$IFS"; IFS=" "
        pi=0; while [ -f "$tmpdir/RequestID[$pi].tmp" ]; do
                ((progress_current++))
                progress_percent=$(($progress_current*100 / $progress_full))
                echo -en "\rRequesting iTunesIDs $progress_percent% (batch $progress_current/$progress_full)"
                
                list_CFBundleIdentifier="$(cat "$tmpdir/RequestID[$pi].tmp" | cut -d $'\t' -f 2 | tr $'\n' ' ')"
                data_parse "$(request_send "$(bundle_getItunesIDs $list_CFBundleIdentifier)")" | cut -d ":" -f 2 > "$tmpdir/iTunesID.tmp"
                
                i=1; cat "$tmpdir/iTunesID.tmp" | while read line; do
                        # Fancy abracadabra with awk gets line number "$i" from RequestID[$pi].tmp
                        awk "NR == $i {print; exit}" "$tmpdir/RequestID[$pi].tmp" | tr -d $'\n' >> "$tmpdir/AppListNew.tmp"
                        echo -en $'\t' >> "$tmpdir/AppListNew.tmp"
                        echo -E "$line" >> "$tmpdir/AppListNew.tmp"
                        ((i++))
                done
                ((pi++))
        done; echo
        IFS="$oldIFS"
        mv "$tmpdir/AppListNew.tmp" "$tmpdir/AppList.txt"
        rm -rf "$tmpdir/"*.tmp
        
        # Requesting iTunes URLs
        progress_current=0
        progress_full="$(cat "$tmpdir/AppList.txt" | wc -l)"
        cat "$tmpdir/AppList.txt" | while read line; do
                ((progress_current++))
                progress_percent=$(($progress_current*100 / $progress_full))
                echo -en "\rRequesting iTunes URLs $progress_percent% ($progress_current/$progress_full)"
                
                iTunesID="$(echo -En "$line" | cut -d $'\t' -f 4)"
                echo -En "$line" >> "$tmpdir/AppListNew.tmp"
                echo -en $'\t' >> "$tmpdir/AppListNew.tmp"
                
                data_parse "$(request_send "$(app_getDetails $iTunesID itunesurl)")" | tr -d $'\n'| sed 's/^.*http/http/' >> "$tmpdir/AppListNew.tmp"
                echo -e >> "$tmpdir/AppListNew.tmp"
                ((i++))
        done; echo
        mv "$tmpdir/AppListNew.tmp" "$tmpdir/AppList.txt"

        # Requesting icon links
        progress_current=0
        progress_full="$(cat "$tmpdir/AppList.txt" | wc -l)"
        cat "$tmpdir/AppList.txt" | while read line; do
                ((progress_current++))
                progress_percent=$(($progress_current*100 / $progress_full))
                echo -en "\rRequesting image links $progress_percent% ($progress_current/$progress_full)"
                
                iTunesURL="$(echo -En "$line" | cut -d $'\t' -f 5)"
                echo -En "$line" >> "$tmpdir/AppListNew.tmp"
                echo -en $'\t' >> "$tmpdir/AppListNew.tmp"
                data_parse "$(request_send "$(app_scrape $iTunesURL)")" | grep "icon-175:" | tr -d $'\n'| sed 's/^.*http/http/' >> "$tmpdir/AppListNew.tmp"
                echo -e >> "$tmpdir/AppListNew.tmp"
                ((i++))
        done; echo
        mv "$tmpdir/AppListNew.tmp" "$tmpdir/AppList.txt"
        
        # Downloading and writing files
        progress_current=0
        progress_full="$(cat "$tmpdir/AppList.txt" | wc -l)"
        cat "$tmpdir/AppList.txt" | while read line; do
                ((progress_current++))
                progress_full="$(cat "$tmpdir/AppList.txt" | wc -l)"
                echo -en "\rDownloading and writing new icon files $progress_percent% ($progress_current/$progress_full)"
                
                fullpath="$(echo -En "$line" | cut -d $'\t' -f 1)"
                CFBundleIconFile="$(echo -En "$line" | cut -d $'\t' -f 3)"
                link="$(echo -En "$line" | cut -d $'\t' -f 6)"
                
                target="$fullpath/$CFBundleIconFile"
                touch -r "$target" "$tmpdir/timestamp.tmp"
                
                backup "$target"
                rm -rf "$tmpdir/Icon.jpg"
                wget -q --output-document="$tmpdir/Icon.jpg" "$link"
                artworkToIcon "$target" "$tmpdir/Icon.jpg"
                rm -rf "$tmpdir/Icon.jpg"
                
                [ ! -f "$target" ] && cp -p "$target.orig" "$target" # Failed
                touch --no-create -r "$tmpdir/timestamp.tmp" "$target"
        done; echo
        ;;
        
        3 ) # Revert to original icons
        progress_current=0
        progress_full="$(ls -x -1 "$SANDBOX_ROOTS" | wc -l)"
        ls -x -1 "$SANDBOX_ROOTS" | while read sandbox; do      
                ((progress_current++))
                progress_percent=$(($progress_current*100 / $progress_full))
                echo -en "\rReverting to original icons $progress_percent% ($progress_current/$progress_full)"

                setupvars "$SANDBOX_ROOTS/$sandbox"
                [ ! -f "$Info" ] && continue
                
                CFBundleIconFile="$(findCFBundleIconFile "$fullpath")"
                target="$fullpath/$CFBundleIconFile"
                [ ! -f "$target.orig" ] && continue
                
                touch --reference="$target.orig" "$tmpdir/timestamp.tmp"
                mv "$target.orig" "$target"
                touch --no-create --reference="$tmpdir/timestamp.tmp" "$target"
        done; echo
        ;;
esac

echo "Clearing the icon cache"
rm -rf "$ICONCACHE_DIR"/*


# Amen.
exit 0
