#!/usr/bin/env ruby # SpringRoll - SpringBoard beautifier # by Yanik Magnan - http://r-ch.net/sr # == Usage # # sr [OPTIONS] # # backup # backs up current interface # # theme [themename] # applies the specified theme # # restore # restores backed up interface # # smbconv [themename] # converts SummerBoard themes into SpringRoll themes # # -h, --help, help # shows this help message require 'rdoc/usage' require 'fileutils' # Determine whether or not the device is running 2.0 (darwin9) # or 1.1.x (darwin8) by seeing if AppStore exists. if Dir.entries("/Applications").include?("AppStore.app") then $ostype = "darwin9" else $ostype = "darwin8" end $user = ENV['USER'] $args = ARGV $ver = "r7" # Initialize constants SB = "/System/Library/CoreServices/SpringBoard.app" SR = "/var/root/SpringRoll" APPSTORE_SUPPORT = false case $ostype when "darwin8": SLIDER_PREFIX = "/System/Library/Frameworks/TelephonyUI.framework" when "darwin9": SLIDER_PREFIX = "/System/Library/PrivateFrameworks/TelephonyUI.framework" end # Warn users that AppStore support is now disabled if Dir.entries("/var/root").include?("SpringRoll") and ($ostype == "darwin9") then if Dir.entries(SR).include?(".r7firstrun") then else puts <<-doc * SPRINGROLL R7 Apparently, AppStore support is harder than I imagined, and testing all kinds of scenarios to keep things from breaking was getting troublesome. Rather than constantly breaking your apps, I've decided to disable AppStore support. This essentially means that r7 has the features of r4, except much faster. Crazy people who'd like to enable the broken AppStore support can by editing the APPSTORE_SUPPORT constant from false to true. Customize is apparently available for 2.0 now, so that's most likely going to support AppStore applications soon, and I suggest people switch to it if they want stability. Future SpringRoll updates will concentrate on user experience and bug fixes rather than AppStore support. I'm done wasting your time now! doc sleep 10 `touch #{SR}/.r7firstrun` end end # Exceptions hash table courtesy of fujin Exceptions = { "CurrencyConverterApp.app" => "CurrencyAppIcon.png", "SimpleFlashLight.app" => "flashlighticon.png", "Exposure.app" => "Exposure.png", "NYTimes.app" => "NYTApplicationIcon.png", "aSubnet.app" => "logo.png", "Reviews.app" => "IGN_57x57.png", "Twitterrific.app" => [ "Icon.png", "Icon_free.png"], "VNC.app" => [ "vnciconLITE.png", "vncicon.png", "vnciconDEMO.png"], "SudokuFree.app" => "SudokuFreeIcon.png", "AOL Radio.app" => "radio.png", "Flashlight.app" => "appicon.png", "MySpace.app" => "applicationIcon_prerendered.png", "WeatherBug.app" => "apple-touch-icon.png", "YelpIPhone_take5.app" => "yelpicon.png", "imaze.app" => "maze.png", "iMmo.app" => "Icon2.png", "Bubbles.app" => "BubblesIcon.png", "WritingPad.app" => "WritingPadlogo57X57.png", "Jott.app" => "jotttouch_icon.png", "iYardage.app" => "iyardage_icon_57x57_dc.png", "korebasi lite.app" => "korebasi_icon.png", "YPmobile.app" => "rubicon.png", "Mobile News.app" => "apple-touch-icon.png", "Rhythm.app" => "vSnax_Logo.png", "WordPress.app" => "application-icon.png", "RubyRepeat.app" => "rubyrepeat_icon.png", "Tanjas SOS.app" => "AppIcon.png", "Save Benjis.app" => "benji_face.png", "Barcode.app" => "Barcode.png", "Stanza.app" => "Icon57x57.png", "Eventful.app" => "eventful-icon.png", "eReader.app" => "app-icon.png", "SQLiteBooks.app" => "ToDo_57.png" } # TO BE REPLACED BY VASTLY SUPERIOR EXCEPTIONS HASH TABLE: # Array of AppStore applications that have special icon names. $special = ["CurrencyConverterApp.app", "SimpleFlashLight.app", "Exposure.app", "NYTimes.app", "aSubnet.app", "Reviews.app", "Twitterrific.app", "VNC.app", "SudokuFree.app", "AOL Radio.app", "Flashlight.app", "MySpace.app", "WeatherBug.app", "YelpIPhone_take5.app", "imaze.app", "iMmo.app", "Bubbles.app", "WritingPad.app", "Jott.app", "iYardage.app", "korebasi lite.app", "YPmobile.app", "Mobile News.app", "Rhythm.app", "WordPress.app", "RubyRepeat.app","Tanjas SOS.app","Save Benjis.app","Barcode.app","Stanza.app","Eventful.app","eReader.app","SQLiteBooks.app"] def new puts "NEW IN #{$ver}:" puts "- AppStore Support!" puts "- Available on Cydia thanks to the MMi repo!" end def bakcp(full,base) print "*** #{base} ... " FileUtils::cp(full,"#{SR}/Default/#{base}") print "DONE \n" end # NEW FROM SRA def t_specialcases(f,basename) theme_special(f,basename,"CurrencyConverterApp.app","CurrencyAppIcon.png") theme_special(f,basename,"SimpleFlashLight.app","flashlighticon.png") theme_special(f,basename,"Exposure.app","Exposure.png") theme_special(f,basename,"NYTimes.app","NYTApplicationIcon.png") theme_special(f,basename,"aSubnet.app","logo.png") theme_special(f,basename,"Reviews.app","IGN_57x57.png") theme_special(f,basename,"Twitterrific.app","Icon.png") theme_special(f,basename,"Twitterrific.app","Icon_free.png") theme_special(f,basename,"VNC.app","vnciconLITE.png") theme_special(f,basename,"VNC.app","vncicon.png") theme_special(f,basename,"VNC.app","vnciconDEMO.png") theme_special(f,basename,"SudokuFree.app","SudokuFreeIcon.png") theme_special(f,basename,"AOL Radio.app","radio.png") theme_special(f,basename,"Flashlight.app","appicon.png") theme_special(f,basename,"MySpace.app","applicationIcon_prerendered.png") theme_special(f,basename,"WeatherBug.app","apple-touch-icon.png") theme_special(f,basename,"YelpIPhone_take5.app","yelpicon.png") theme_special(f,basename,"imaze.app","maze.png") theme_special(f,basename,"iMmo.app","Icon2.png") theme_special(f,basename,"Bubbles.app","BubblesIcon.png") theme_special(f,basename,"WritingPad.app","WritingPadlogo57X57.png") theme_special(f,basename,"Jott.app","jotttouch_icon.png") theme_special(f,basename,"iYardage.app","iyardage_icon_57x57_dc.png") theme_special(f,basename,"korebasi lite.app","korebasi_icon.png") theme_special(f,basename,"YPmobile.app","rubicon.png") theme_special(f,basename,"Mobile News.app","apple-touch-icon.png") theme_special(f,basename,"Rhythm.app","vSnax_Logo.png") theme_special(f,basename,"WordPress.app","application-icon.png") theme_special(f,basename,"RubyRepeat.app","rubyrepeat_icon.png") theme_special(f,basename,"Tanjas SOS.app","AppIcon.png") theme_special(f,basename,"Save Benjis.app","benji_face.png") theme_special(f,basename,"Barcode.app","Barcode.png") theme_special(f,basename,"Stanza.app","Icon57x57.png") theme_special(f,basename,"Eventful.app","eventful-icon.png") theme_special(f,basename,"eReader.app","app-icon.png") theme_special(f,basename,"SQLiteBooks.app","ToDo_57.png") end # END NEW FROM SRA def backup # Back up icons, dock, badge, slider resources to the Default theme puts "* Backing up resources:" # Change directory to /var/root puts "** Changing directory to /var/root" Dir.chdir "/var/root" # prepare theme directories if nonexistant puts "** Verifying theme directory structure" if Dir.entries(Dir.pwd).include?("SpringRoll") == false then print "*** Creating SpringRoll directory ... " Dir.mkdir 'SpringRoll' print "DONE \n" end Dir.chdir SR if Dir.entries(Dir.pwd).include?("Default") == false then print "*** Creating Default directory ... " Dir.mkdir 'Default' print "DONE \n" end Dir.chdir "#{SR}/Default" if Dir.entries(Dir.pwd).include?("Icons") == false then print "*** Creating Icons directory ... " Dir.mkdir 'Icons' print "DONE \n" end # NON-ICON EXTRAS # DOCK puts "** Backing up Dock resources:" bakcp("#{SB}/SBDockBG.png","SBDockBG.png") bakcp("#{SB}/SBDockBG2.png","SBDockBG2.png") # BADGE puts "** Backing up Badge resources:" bakcp("#{SB}/SBBadgeBG.png","SBBadgeBG.png") # SLIDERS puts "** Backing up Slider resources:" slider_rsrc = { "#{SLIDER_PREFIX}/bottombarknobgray.png" => "bottombarknobgray.png", "#{SLIDER_PREFIX}/bottombarknobgreen.png" => "bottombarknobgreen.png", "#{SLIDER_PREFIX}/bottombarknobred.png" => "bottombarknobred.png", "#{SLIDER_PREFIX}/bottombarbkgndlock.png" => "bottombarbkgndlock.png", "#{SLIDER_PREFIX}/bottombarlocktextmask.png" => "bottombarlocktextmask.png", "#{SLIDER_PREFIX}/topbarbkgnd.png" => "topbarbkgnd.png" } slider_rsrc.each do |src,dest| bakcp(src,dest) end # BATTERY puts "** Backing up Battery resources:" (1..17).each do |i| bakcp("#{SB}/BatteryBG_#{i}.png","BatteryBG_#{i}.png") end # STATUSBAR puts "** Backing up StatusBar resources:" statusbar_rsrc = { "#{SB}/Default_BG.png" => "Default_BG.png", "#{SB}/FSO_BG.png" => "FSO_BG.png", "#{SB}/FST_BG.png" => "FST_BG.png" } statusbar_rsrc.each do |src,dest| bakcp(src,dest) end # ICONS puts "** Backing up application icons:" Dir.chdir '/Applications' $apps = Dir.entries('/Applications') $apps.delete('.') $apps.delete('..') while $apps.nitems > 0: if File.directory?("/Applications/#{$apps[0]}") then Dir.chdir("/Applications/#{$apps[0]}") def mobilemusicplayer bakcp('/Applications/MobileMusicPlayer.app/icon-AudioPlayer.png','Icons/MobileMusicPlayer-AudioPlayer.png') bakcp('/Applications/MobileMusicPlayer.app/icon-MediaPlayer.png','Icons/MobileMusicPlayer-MediaPlayer.png') bakcp('/Applications/MobileMusicPlayer.app/icon-VideoPlayer.png','Icons/MobileMusicPlayer-VideoPlayer.png') end def mobileslideshow bakcp('/Applications/MobileSlideShow.app/icon-Camera.png', 'Icons/MobileSlideShow-Camera.png') bakcp('/Applications/MobileSlideShow.app/icon-Photos.png', 'Icons/MobileSlideShow-Photos.png') end def normalicon print "*** #{$apps[0]} - icon.png ... " basename = $apps[0].gsub('.app','.png') case Dir.entries(Dir.pwd).include?('icon.png') when true FileUtils::cp("/Applications/#{$apps[0]}/icon.png","#{SR}/Default/Icons/#{basename}") puts "DONE" when false: puts "NOT FOUND!" end end case $apps[0] when 'MobileMusicPlayer.app': mobilemusicplayer when 'MobileSlideShow.app': mobileslideshow else normalicon end $apps.shift else $apps.shift end end # APP STORE APPLICATION ICONS if ($ostype == "darwin9") and (APPSTORE_SUPPORT == true) then puts "** Backing up purchased app icons:" Dir.chdir('/var/mobile/Applications') $apps = Dir.entries(Dir.pwd) $apps.delete('.') $apps.delete('..') while $apps.nitems > 0 do Dir.chdir("/var/mobile/Applications/#{$apps[0]}") Dir.entries(Dir.pwd).each do |f| if f.include? ".app" then Dir.chdir("/var/mobile/Applications/#{$apps[0]}/#{f}") basename = f.gsub('.app','.png') if Exceptions.has_key?(f) then icon = Exceptions.fetch(f) if icon.is_a?String # Process it once! if Dir.entries(Dir.pwd).include?(icon) then print "*** #{f} - #{icon} ... " FileUtils::cp("/var/mobile/Applications/#{$apps[0]}/#{f}/#{icon}", "#{SR}/Default/Icons/#{basename}") puts "DONE" end elsif icon.is_a?Array # Process each element! icon.each do |file| if Dir.entries(Dir.pwd).include?(file) then print "*** #{f} - #{file} ... " FileUtils::cp("/var/mobile/Applications/#{$apps[0]}/#{f}/#{file}", "#{SR}/Default/Icons/#{basename}") puts "DONE" end end end else if Dir.entries(Dir.pwd).include?("icon.png") then print "*** #{f} - icon.png ... " FileUtils::cp("/var/mobile/Applications/#{$apps[0]}/#{f}/icon.png","#{SR}/Default/Icons/#{basename}") print "DONE \n" elsif Dir.entries(Dir.pwd).include?("Icon.png") then print "*** #{f} - Icon.png ... " FileUtils::cp("/var/mobile/Applications/#{$apps[0]}/#{f}/Icon.png","#{SR}/Default/Icons/#{basename}") print "DONE \n" end end if Dir.entries(SR).include?("AppStoreSupport") then FileUtils::cp("/var/mobile/Applications/#{$apps[0]}/#{f}/Info.plist","#{SR}/AppStoreSupport/#{f}-Info.plist") else Dir.mkdir("#{SR}/AppStoreSupport") FileUtils::cp("/var/mobile/Applications/#{$apps[0]}/#{f}/Info.plist","#{SR}/AppStoreSupport/#{f}-Info.plist") end end end $apps.shift end end # APP STORE SECTION ENDS HERE # PLEASE PLEASE PLEASE DON'T BREAK! puts "* Backup complete." puts " To restore, use 'sr restore'." end def patch(iconfile,f) # SpringRoll Patcher # First -> Patch the CodeResources files_done = nil supp_passed = nil rsrc_file = open("CodeResources","r+") rsrc_count = 1 # State of the process. supp_passed = nil first_pass = nil files_done = nil # For each line in the CodeResources rsrc_file.each { |line| if first_pass == nil then if files_done == true then if supp_passed.nil? then if (line =~ /.supp/) and (line =~ /SC_Info/) then supp_passed = true end end if supp_passed == true then if line.match "\t\t" then rsrc_file.puts "\t\t#{iconfile}" rsrc_file.puts "\t\t" rsrc_file.puts "\t\t\tomit" rsrc_file.puts "\t\t\t" rsrc_file.puts "\t\t\tweight" rsrc_file.puts "\t\t\t10000" rsrc_file.puts "\t\t" rsrc_file.puts "\t" rsrc_file.puts "" rsrc_file.puts "" first_pass = true end end end if files_done.nil? then if line.match "\t\t#{iconfile}" then $icon_line = rsrc_count end end if line.match "\trules" then files_done = true end rsrc_count += 1 end } rsrc_file.close # First - 2nd pass rsrc2_file = open("CodeResources","r+") second_count = 1 rsrc2_file.each { |line| if (second_count == ($icon_line - 1)) then rsrc2_file.print " " iconfile.length.times do rsrc2_file.print " " end rsrc2_file.puts " " rsrc2_file.puts " " rsrc2_file.puts " " rsrc2_file.puts " " end second_count += 1 } rsrc2_file.close `plutil -c xml1 CodeResources` # First - Last : Keep a SHA1 of the patched CodeResources in SpringRoll/AppStoreSupport `touch "#{SR}/AppStoreSupport/#{f}-CodeResources"` rsrc_shafile = open("#{SR}/AppStoreSupport/#{f}-CodeResources","w") rsrc_sha1 = `openssl sha1 CodeResources` rsrc_sha1 = rsrc_sha1.chomp rsrc_sha1.gsub!("SHA1(CodeResources)= ","") rsrc_shafile.puts rsrc_sha1 rsrc_shafile.close # Second -> Patch the ResourceRules.plist supp2_passed = nil `plutil -c xml1 ResourceRules.plist` rule_complete = nil rule_file = open("ResourceRules.plist","r+") rule_file.each { |line| if (line =~ /SC_Info/) and (line =~ /.supp/) then supp2_passed = true end if (supp2_passed == true) then if line.match("\t\t") then rule_file.puts "\t\t#{iconfile}" rule_file.puts "\t\t" rule_file.puts "\t\t\tomit" rule_file.puts "\t\t\t" rule_file.puts "\t\t\tweight" rule_file.puts "\t\t\t10000" rule_file.puts "\t\t" rule_file.puts "\t" rule_file.puts "" rule_file.puts "" end end } rule_file.close `plutil -c binary1 ResourceRules.plist` `touch "#{SR}/AppStoreSupport/#{f}-ResourceRules.plist"` rule_shafile = open("#{SR}/AppStoreSupport/#{f}-ResourceRules.plist","w") rule_sha1 = `openssl sha1 ResourceRules.plist` rule_sha1 = rule_sha1.chomp rule_sha1 = rule_sha1.gsub!("SHA1(ResourceRules.plist)= ","") rule_shafile.puts rule_sha1 rule_shafile.close end def thcp(base, full) if Dir.entries(Dir.pwd).include?(base) then print "*** #{base} ... " FileUtils::cp("#{Dir.pwd}/#{base}","#{full}") print "DONE \n" else puts "*** #{base} ... NOT FOUND" end end def theme_special(f, basename, app, filename) @f = f @basename = basename @app = app @filename = filename if f == @app then if Dir.entries("#{SR}/#{ARGV[1]}/Icons").include?(@basename) then print "*** #{@f} - #{@filename} ... " shaverify(@filename,@f,@basename) print "DONE \n" end end end def theme # Keep people from screwing their iPhones badly by verifying if the theme is Default. raise StandardError, "DO NOT USE SPRINGROLL THEME DEFAULT! If you want to restore your backup, use sr restore." if ARGV[1] == "Default" puts "* Theming interface with theme: #{ARGV[1]}" # Verify to see if the theme in question exists! print "** Does the theme even exist to begin with? ... " Dir.chdir SR if Dir.entries(Dir.pwd).include?(ARGV[1]) == false then print "NO \n" raise StandardError, "The theme you have specified does not exist! Make sure your theme is one word only!" end print "YES \n" # Force the user to run a backup if he/she hasn't yet. if Dir.entries(Dir.pwd).include?("Default") == false then puts "** WARNING: I strongly recommend running" puts " 'sr backup' before doing this to keep" puts " backup of your UI just in case." raise StandardError, "Run sr backup to back things up for your own safety." end Dir.chdir("#{SR}/#{ARGV[1]}") # NON-ICON EXTRAS # DOCK puts "** Copying dock resources:" dock_rsrc = { "Dock.png" => [ "#{SB}/SBDockBG.png", "#{SB}/SBDockBG2.png" ] } dock_rsrc.each do |src,dest| if dest.is_a?Array dest.each do |realdest| thcp(src,realdest) end end end # BADGE puts "** Copying badge resources:" thcp("Badge.png","#{SB}/SBBadgeBG.png") # SLIDERS puts "** Copying slider resources:" slider_rsrc = { "Slider-Gray.png" => "#{SLIDER_PREFIX}/bottombarknobgray.png", "Slider-Green.png" => "#{SLIDER_PREFIX}/bottombarknobgreen.png", "Slider-Red.png" => "#{SLIDER_PREFIX}/bottombarknobred.png", "Slider-bkgndlock.png" => "#{SLIDER_PREFIX}/bottombarbkgndlock.png", "Slider-textmask.png" => "#{SLIDER_PREFIX}/bottombarlocktextmask.png", "Slider-topbarbkgnd.png" => "#{SLIDER_PREFIX}/topbarbkgnd.png" } slider_rsrc.each do |src,dest| thcp(src,dest) end # BATTERY puts "** Copying battery resources:" if Dir.entries(Dir.pwd).include?("Battery") then Dir.chdir("Battery") (1..17).each do |i| thcp("BatteryBG_#{i}.png","#{SB}/BatteryBG_#{i}.png") end Dir.chdir("..") else puts "*** No battery subfolder found." end # STATUS BAR puts "** Copying status bar resources:" statusbar_rsrc = { "StatusBar-Default.png" => "#{SB}/Default_BG.png", "StatusBar-FSO.png" => "#{SB}/FSO_BG.png", "StatusBar-FST.png" => "#{SB}/FST_BG.png" } statusbar_rsrc.each do |src,dest| thcp(src,dest) end # ICONS if Dir.entries("/var/root/SpringRoll/#{ARGV[1]}").include?('Icons') then puts "** Copying icons..." Dir.chdir('/Applications') $apps = Dir.entries('/Applications') $apps.delete('.') $apps.delete('..') while $apps.nitems > 0: if File.directory?("/Applications/#{$apps[0]}") then Dir.chdir("/Applications/#{$apps[0]}") def tmobilemusicplayer if Dir.entries("#{SR}/#{ARGV[1]}/Icons").include?('MobileMusicPlayer-AudioPlayer.png') then print "*** MobileMusicPlayer-AudioPlayer.png ... " FileUtils::cp("#{SR}/#{ARGV[1]}/Icons/MobileMusicPlayer-AudioPlayer.png","/Applications/MobileMusicPlayer.app/icon-AudioPlayer.png") print "DONE \n" else puts "*** MobileMusicPlayer-AudioPlayer.png ... " end if Dir.entries("#{SR}/#{ARGV[1]}/Icons").include?('MobileMusicPlayer-MediaPlayer.png') then print "*** MobileMusicPlayer-MediaPlayer.png ... " FileUtils::cp("#{SR}/#{ARGV[1]}/Icons/MobileMusicPlayer-MediaPlayer.png","/Applications/MobileMusicPlayer.app/icon-MediaPlayer.png") print "DONE \n" else puts "*** MobileMusicPlayer-MediaPlayer.png ... NOT FOUND" end if Dir.entries("#{SR}/#{ARGV[1]}/Icons").include?('MobileMusicPlayer-VideoPlayer.png') then print "*** MobileMusicPlayer-VideoPlayer.png ... " FileUtils::cp("#{SR}/#{ARGV[1]}/Icons/MobileMusicPlayer-VideoPlayer.png","/Applications/MobileMusicPlayer.app/icon-VideoPlayer.png") print "DONE \n" else puts "*** MobileMusicPlayer-VideoPlayer.png ... NOT FOUND!" end end def tmobileslideshow if Dir.entries("#{SR}/#{ARGV[1]}/Icons").include?('MobileSlideShow-Camera.png') then print "*** MobileSlideShow-Camera.png ... " FileUtils::cp("#{SR}/#{ARGV[1]}/Icons/MobileSlideShow-Camera.png","/Applications/MobileSlideShow.app/icon-Camera.png") print "DONE \n" else puts "*** MobileSlideShow-Camera.png ... NOT FOUND" end if Dir.entries("#{SR}/#{ARGV[1]}/Icons").include?('MobileSlideShow-Photos.png') then print "*** MobileSlideShow-Photos.png ... " FileUtils::cp("#{SR}/#{ARGV[1]}/Icons/MobileSlideShow-Photos.png","/Applications/MobileSlideShow.app/icon-Photos.png") print "DONE \n" else puts "*** MobileSlideShow-Photos.png ... NOT FOUND" end end def tnormalicon print "*** #{$apps[0]} - icon.png ... " basename = $apps[0].gsub('.app','.png') if Dir.entries("#{SR}/#{ARGV[1]}/Icons").include?(basename) then FileUtils::cp("#{SR}/#{ARGV[1]}/Icons/#{basename}","/Applications/#{$apps[0]}/icon.png") puts "DONE" else puts "NOT FOUND!" end end case $apps[0] when 'MobileMusicPlayer.app': tmobilemusicplayer when 'MobileSlideShow.app': tmobileslideshow else tnormalicon end $apps.shift else $apps.shift end end else puts "** No Icons folder detected. Skipping icons." end # APP STORE SUPPORT BEGINS HERE! if ($ostype == "darwin9") and (APPSTORE_SUPPORT == true) and (Dir.entries("#{SR}/#{ARGV[1]}").include?('Icons')) then puts "** Copying purchased app icons:" # Change directory to /var/mobile/Applications Dir.chdir("/var/mobile/Applications") $apps = Dir.entries("/var/mobile/Applications") # Remove the self-referential/back entries $apps.delete "." $apps.delete ".." # While there are still apps to process: while $apps.nitems > 0: # And if the app is really an app (directory) if File.directory?("/var/mobile/Applications/#{$apps[0]}") then # Change to its directory Dir.chdir("/var/mobile/Applications/#{$apps[0]}") # For each file... Dir.entries(Dir.pwd).each do |f| # If one is an app... if f.include? ".app" then # Enter it. Dir.chdir("/var/mobile/Applications/#{$apps[0]}/#{f}") # Set a basename. basename = f.gsub('.app','.png') # If the theme has an icon for this app then: if Dir.entries("/var/root/SpringRoll/#{ARGV[1]}/Icons").include?(basename) then # If it's an exception, run t_specialcases if $special.include?(f) then t_specialcases(f,basename) else # If it's normal, process its icon.png or Icon.png if Dir.entries(Dir.pwd).include?("icon.png") then print "*** #{f} - icon.png ... " shaverify("icon.png",f,basename) print "DONE \n" end if Dir.entries(Dir.pwd).include?("Icon.png") then print "*** #{f} - Icon.png ... " shaverify("Icon.png",f,basename) print "DONE \n" end end # Change its gloss setting only if the app has an icon `plutil -c xml1 Info.plist` `plutil -1 UIPrerenderedIcon Info.plist` `plutil -c binary1 Info.plist` end end end # Move onto the next entry $apps.shift else # If it isn't an app... then go to the next entry $apps.shift end end end `killall SpringBoard` puts "* Theming complete." puts " To restore: use 'sr restore'" puts " Device will respring shortly." end def shaverify(iconname,f,basename) # Verify the patch state of CodeResources and ResourceRules.plist # Does CodeResources exist? if Dir.entries(Dir.pwd).include?("CodeResources") then @rsrc_exists = true else @rsrc_exists = false end # Does ResourceRules exist? if Dir.entries(Dir.pwd).include?("ResourceRules.plist") then @rule_exists = true else @rule_exists = false end # If both files exist, then... if (@rsrc_exists == true) and (@rule_exists == true) then # Do they both have SHA1 files? if Dir.entries("#{SR}/AppStoreSupport").include?("#{f}-CodeResources") then @rsrc_sha_exists = true else @rsrc_sha_exists = false end if Dir.entries("#{SR}/AppStoreSupport").include?("#{f}-ResourceRules.plist") then @rule_sha_exists = true else @rule_sha_exists = false end # If so... if (@rsrc_sha_exists == true) and (@rule_sha_exists == true) then # Do they match to the sha of the actual file? # Get the contents of the saved SHA # This is a cat call because it's faster to implement and essentially has the same result. @rsrc_saved_sha = `cat "#{SR}/AppStoreSupport/#{f}-CodeResources"` @rsrc_saved_sha = @rsrc_saved_sha.chomp @rule_saved_sha = `cat "#{SR}/AppStoreSupport/#{f}-ResourceRules.plist"` @rule_saved_sha = @rule_saved_sha.chomp # Get the real SHA @rsrc_real_sha = `openssl sha1 "CodeResources"` @rsrc_real_sha = @rsrc_real_sha.chomp @rsrc_real_sha.gsub!("SHA1(CodeResources)= ","") @rule_real_sha = `openssl sha1 "ResourceRules.plist"` @rule_real_sha = @rule_real_sha.chomp @rule_real_sha.gsub!("SHA1(ResourceRules.plist)= ","") # If they match: if (@rsrc_real_sha == @rsrc_saved_sha) and (@rule_real_sha == @rule_saved_sha) then # Simply copy the icon over, no questions asked. FileUtils::cp("#{SR}/#{ARGV[1]}/Icons/#{basename}","/var/mobile/Applications/#{$apps[0]}/#{f}/#{iconname}") else # And if they don't, refuse to do anything with that app and give a warning. puts "\n*** REGARDING #{f}:" puts " This application's CodeResources or ResourceRules.plist files" puts " have been modified by an outside source. Changing the icon" puts " could cause the application to stop functioning. Therefore," puts " SpringRoll recommends you reinstall the applications and" puts " delete its footprint files at the following path:" puts " /var/root/SpringRoll/AppStoreSupport/#{f}-CodeResources" puts " /var/root/SpringRoll/AppStoreSupport/#{f}-ResourceRules.plist" puts " -> This application remains untouched." end else # If the files don't exist, then the application is not patched! patch(iconname,f) FileUtils::cp("#{SR}/#{ARGV[1]}/Icons/#{basename}","/var/mobile/Applications/#{$apps[0]}/#{f}/#{iconname}") end end end def restcp(base, full) print "*** #{base} ... " FileUtils::cp("#{SR}/Default/#{base}","#{full}") print "DONE \n" end def restore # Set SpringBoard prefix. puts "* Restoring backup." # DOCK puts "** Restoring original Dock resources:" restcp("SBDockBG.png","#{SB}/SBDockBG.png") restcp("SBDockBG2.png","#{SB}/SBDockBG2.png") # BADGE puts "** Restoring original Badge resources:" restcp("SBBadgeBG.png","#{SB}/SBBadgeBG.png") # SLIDERS puts "** Restoring original Slider resources:" slider_rsrc = { "bottombarknobgray.png" => "#{SLIDER_PREFIX}/bottombarknobgray.png", "bottombarknobgreen.png" => "#{SLIDER_PREFIX}/bottombarknobgreen.png", "bottombarknobred.png" => "#{SLIDER_PREFIX}/bottombarknobred.png", "bottombarbkgndlock.png" => "#{SLIDER_PREFIX}/bottombarbkgndlock.png", "bottombarlocktextmask.png" => "#{SLIDER_PREFIX}/bottombartextmask.png", "topbarbkgnd.png" => "#{SLIDER_PREFIX}/topbarbkgnd.png" } slider_rsrc.each do |src,dest| restcp(src,dest) end # BATTERY puts "** Restoring original Battery resources:" (1..17).each do |i| restcp("BatteryBG_#{i}.png","#{SB}/BatteryBG_#{i}.png") end # STATUS BAR puts "** Restoring original StatusBar resources:" statusbar_rsrc = { "Default_BG.png" => "#{SB}/Default_BG.png", "FSO_BG.png" => "#{SB}/FSO_BG.png", "FST_BG.png" => "#{SB}/FST_BG.png" } statusbar_rsrc.each do |src,dest| restcp(src,dest) end # NORMAL APP ICONS puts '** Restoring application icons:' Dir.chdir('/Applications') $apps = Dir.entries('/Applications') $apps.delete('.') $apps.delete('..') while $apps.nitems > 0: if File.directory?("/Applications/#{$apps[0]}") then Dir.chdir("/Applications/#{$apps[0]}") def rmobilemusicplayer mmp_rsrc = { "Icons/MobileMusicPlayer-AudioPlayer.png" => "#{Dir.pwd}/icon-AudioPlayer.png", "Icons/MobileMusicPlayer-MediaPlayer.png" => "#{Dir.pwd}/icon-MediaPlayer.png", "Icons/MobileMusicPlayer-VideoPlayer.png" => "#{Dir.pwd}/icon-VideoPlayer.png" } mmp_rsrc.each do |src,dest| restcp(src,dest) end end def rmobileslideshow mss_rsrc = { "Icons/MobileSlideShow-Camera.png", "#{Dir.pwd}/icon-Camera.png", "Icons/MobileSlideShow-Photos.png", "#{Dir.pwd}/icon-Photos.png" } mss_rsrc.each do |src,dest| restcp(src,dest) end end def rnormalicon print "*** #{$apps[0]} - icon.png ... " basename = $apps[0].gsub('.app','.png') if Dir.entries("#{SR}/Default/Icons").include?(basename) then FileUtils::cp("#{SR}/Default/Icons/#{basename}","/Applications/#{$apps[0]}/icon.png") puts "DONE" else puts "NOT FOUND!" end end case $apps[0] when 'MobileMusicPlayer.app': rmobilemusicplayer when 'MobileSlideShow.app': rmobileslideshow else rnormalicon end $apps.shift else $apps.shift end end # APP STORE APPLICATION ICONS if ($ostype == "darwin9") and (APPSTORE_SUPPORT == true) then puts "** Restoring purchased app icons:" Dir.chdir("/var/mobile/Applications") $apps = Dir.entries("/var/mobile/Applications") $apps.delete "." $apps.delete ".." while $apps.nitems > 0: Dir.chdir("/var/mobile/Applications/#{$apps[0]}") Dir.entries(Dir.pwd).each do |f| if f.include? ".app" then Dir.chdir("/var/mobile/Applications/#{$apps[0]}/#{f}") basename = f.gsub('.app', '.png') if Dir.entries("#{SR}/Default/Icons").include?(basename) then if Exceptions.has_key?(f) icon = Exceptions.fetch(f) if icon.is_a?String # Process once print "*** #{f} - #{icon} ... " FileUtils::cp("#{SR}/Default/Icons/#{basename}", "/var/mobile/Applications/#{$apps[0]}/#{f}/#{icon}") puts "DONE" elsif icon.is_a?Array # Process each element individually icon.each do |file| print "*** #{f} - #{file} ... " FileUtils::cp("#{SR}/Default/Icons/#{basename}", "/var/mobile/Applications/#{$apps[0]}/#{f}/#{file}") puts "DONE" end end else if Dir.entries(Dir.pwd).include?("icon.png") print "*** #{f} - icon.png ... " FileUtils::cp("#{SR}/Default/Icons/#{basename}", "/var/mobile/Applications/#{$apps[0]}/#{f}/icon.png") puts "DONE" elsif Dir.entries(Dir.pwd).include?("Icon.png") print "*** #{f} - Icon.png ... " FileUtils::cp("#{SR}/Default/Icons/#{basename}", "/var/mobile/Applications/#{$apps[0]}/#{f}/Icon.png") puts "DONE" end end end if Dir.entries("#{SR}/AppStoreSupport").include?("#{f}-Info.plist") FileUtils::cp("#{SR}/AppStoreSupport/#{f}-Info.plist","/var/mobile/Applications/#{$apps[0]}/#{f}/Info.plist") end end end $apps.shift end end # END OF RESTORE `killall SpringBoard` puts "* Interface restored." puts " Device will respring shortly." end # SUMMERBOARD SUPPORT def smbmv(old,new) if Dir.entries(Dir.pwd).include?(old) then print "** #{old} -> #{new} ... " File.rename(old,new) print "DONE \n" end end def smbconv # Verify to see if the theme even exists! if Dir.entries(SR).include?(ARGV[1]) then Dir.chdir("#{SR}/#{ARGV[1]}") puts "* Renaming status bar:" smbmv("StatusBar.png","StatusBar-FSO.png") puts "* Renaming icons:" # Don't break if the user's theme doesn't have # an icons folder! if Dir.entries(Dir.pwd).include?("Icons") then Dir.chdir("#{SR}/#{ARGV[1]}/Icons") smbrenames = { "Calendar.png" => "MobileCal.png", "Camera.png" => "MobileSlideShow-Camera.png", "Clock.png" => "MobileTimer.png", "Contacts.png" => "MobileAddressBook.png", "Mail.png" => "MobileMail.png", "Music.png" => "MobileMusicPlayer-AudioPlayer.png", "Notes.png" => "MobileNotes.png", "Phone.png" => "MobilePhone.png", "Photos.png" => "MobileSlideShow-Photos.png", "Safari.png" => "MobileSafari.png", "Settings.png" => "Preferences.png", "Text.png" => "MobileSMS.png", "Videos.png" => "MobileMusicPlayer-VideoPlayer.png", "iPod.png" => "MobileMusicPlayer-MediaPlayer.png", "iTunes.png" => "MobileStore.png" } smbrenames.each do |old, new| smbmv(old,new) end else puts "* WARNING! No icon directory found!" end puts "* Conversion complete!" puts " Use 'sr theme #{ARGV[1]}' to" puts " apply this theme." else raise StandardError, "The theme you've specified doesn't exist." end end # MANUAL PREPARATION def manualprep Dir.chdir("/var/mobile/Applications") $apps = Dir.entries("/var/mobile/Applications") $apps.delete "." $apps.delete ".." while $apps.nitems > 0: Dir.chdir("/var/mobile/Applications/#{$apps[0]}") Dir.entries(Dir.pwd).each do |f| if f.include? ".app" then Dir.chdir("/var/mobile/Applications/#{$apps[0]}/#{f}") puts("* Preparing manually-edited CodeResources/ResourceRules.plist footprint files.") # CodeResources `touch "#{SR}/AppStoreSupport/#{f}-CodeResources"` rsrc_shafile = open("#{SR}/AppStoreSupport/#{f}-CodeResources","w") rsrc_sha1 = `openssl sha1 CodeResources` rsrc_sha1 = rsrc_sha1.chomp rsrc_sha1.gsub!("SHA1(CodeResources)= ","") rsrc_shafile.puts rsrc_sha1 rsrc_shafile.close # ResourceRules.plist `plutil -c binary1 ResourceRules.plist` `touch "#{SR}/AppStoreSupport/#{f}-ResourceRules.plist"` rule_shafile = open("#{SR}/AppStoreSupport/#{f}-ResourceRules.plist","w") rule_sha1 = `openssl sha1 ResourceRules.plist` rule_sha1 = rule_sha1.chomp rule_sha1 = rule_sha1.gsub!("SHA1(ResourceRules.plist)= ","") rule_shafile.puts rule_sha1 rule_shafile.close end end $apps.shift end end # ARGUMENT PROCESSING # To be phased out with GetoptLong in the future. def proceed(action) # Verify to see if user is root. if $user != 'root' then raise StandardError, "You must run this as root!" end # Dispatch orders. case action when 'backup': backup # WORKING! when 'theme': theme # WORKING! when 'restore': restore # WORKING! when 'smbconv': smbconv # WORKING! when 'manualprep': manualprep end end case ARGV[0] when nil: RDoc::usage when 'r': proceed(restore) when 't': proceed(theme) when 'b': proceed(backup) when 's': proceed(smbconv) when 'm': proceed(manualprep) when 'restore': proceed(restore) when 'backup': proceed(backup) when 'theme': proceed(theme) when 'smbconv': proceed(smbconv) when 'whatsnew': new when 'manualprep': manualprep else RDoc::usage end