#!/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