1 /* Cydia Substrate - Meta-Library Insert for iPhoneOS
2 * Copyright (C) 2008-2009 Jay Freeman (saurik)
6 * Redistribution and use in source and binary
7 * forms, with or without modification, are permitted
8 * provided that the following conditions are met:
10 * 1. Redistributions of source code must retain the
11 * above copyright notice, this list of conditions
12 * and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the
14 * above copyright notice, this list of conditions
15 * and the following disclaimer in the documentation
16 * and/or other materials provided with the
18 * 3. The name of the author may not be used to endorse
19 * or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS''
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
24 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
33 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
35 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 #import <CoreFoundation/CoreFoundation.h>
39 #import <Foundation/Foundation.h>
40 #import <CoreGraphics/CGGeometry.h>
41 #import <UIKit/UIKit.h>
43 #import <SpringBoard/SBAlertItem.h>
44 #import <SpringBoard/SBAlertItemsController.h>
45 #import <SpringBoard/SBButtonBar.h>
46 #import <SpringBoard/SBStatusBarController.h>
47 #import <SpringBoard/SBStatusBarTimeView.h>
48 #import <SpringBoard/SBUIController.h>
50 #include <substrate.h>
52 Class $SafeModeAlertItem;
53 Class $SBAlertItemsController;
55 void SafeModeAlertItem$alertSheet$buttonClicked$(id self, SEL sel, id sheet, int button) {
65 [UIApp applicationOpenURL:[NSURL URLWithString:@"http://cydia.saurik.com/safemode/"]];
72 void SafeModeAlertItem$configure$requirePasscodeForActions$(id self, SEL sel, BOOL configure, BOOL require) {
73 UIModalView *sheet([self alertSheet]);
74 [sheet setDelegate:self];
75 [sheet setBodyText:@"We apologize for the inconvenience, but SpringBoard has just crashed.\n\nMobileSubstrate /did not/ cause this problem: it has protected you from it.\n\nYour device is now running in Safe Mode. All extensions that support this safety system are disabled.\n\nReboot (or restart SpringBoard) to return to the normal mode. To return to this dialog touch the status bar."];
76 [sheet addButtonWithTitle:@"OK"];
77 [sheet addButtonWithTitle:@"Restart"];
78 [sheet addButtonWithTitle:@"Help"];
79 [sheet setNumberOfRows:1];
82 void SafeModeAlertItem$performUnlockAction(id self, SEL sel) {
83 [[$SBAlertItemsController sharedInstance] activateAlertItem:self];
86 static void MSAlert() {
87 if ($SafeModeAlertItem == nil)
88 $SafeModeAlertItem = objc_lookUpClass("SafeModeAlertItem");
89 if ($SafeModeAlertItem == nil) {
90 $SafeModeAlertItem = objc_allocateClassPair(objc_getClass("SBAlertItem"), "SafeModeAlertItem", 0);
91 if ($SafeModeAlertItem == nil)
94 class_addMethod($SafeModeAlertItem, @selector(alertSheet:buttonClicked:), (IMP) &SafeModeAlertItem$alertSheet$buttonClicked$, "v@:@i");
95 class_addMethod($SafeModeAlertItem, @selector(configure:requirePasscodeForActions:), (IMP) &SafeModeAlertItem$configure$requirePasscodeForActions$, "v@:cc");
96 class_addMethod($SafeModeAlertItem, @selector(performUnlockAction), (IMP) SafeModeAlertItem$performUnlockAction, "v@:");
97 objc_registerClassPair($SafeModeAlertItem);
100 if ($SBAlertItemsController != nil)
101 [[$SBAlertItemsController sharedInstance] activateAlertItem:[[$SafeModeAlertItem alloc] init]];
104 MSHook(void, SBStatusBar$touchesEnded$withEvent$, SBStatusBar *self, SEL sel, id touches, id event) {
106 _SBStatusBar$touchesEnded$withEvent$(self, sel, touches, event);
109 MSHook(void, SBStatusBar$mouseDown$, SBStatusBar *self, SEL sel, GSEventRef event) {
111 _SBStatusBar$mouseDown$(self, sel, event);
114 static void SBIconController$showInfoAlertIfNeeded(id self, SEL sel) {
115 static bool loaded = false;
122 MSHook(int, SBButtonBar$maxIconColumns, SBButtonBar *self, SEL sel) {
125 max = _SBButtonBar$maxIconColumns(self, sel);
126 if (NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults])
127 if (NSDictionary *iconState = [defaults objectForKey:@"iconState"])
128 if (NSDictionary *buttonBar = [iconState objectForKey:@"buttonBar"])
129 if (NSArray *iconMatrix = [buttonBar objectForKey:@"iconMatrix"])
130 if ([iconMatrix count] != 0)
131 if (NSArray *row = [iconMatrix objectAtIndex:0]) {
132 int count([row count]);
139 MSHook(id, SBUIController$init, SBUIController *self, SEL sel) {
140 if ((self = _SBUIController$init(self, sel)) != nil) {
141 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
142 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
145 if (&_contentLayer != NULL)
146 layer = _contentLayer;
147 else if (&_contentView != NULL)
148 layer = _contentView;
153 [layer setBackgroundColor:[UIColor darkGrayColor]];
157 #define Paper_ "/Library/MobileSubstrate/MobilePaper.png"
159 MSHook(UIImage *, UIImage$defaultDesktopImage, UIImage *self, SEL sel) {
160 return [UIImage imageWithContentsOfFile:@Paper_];
163 MSHook(void, SBStatusBarTimeView$tile, SBStatusBarTimeView *self, SEL sel) {
164 NSString *&_time(MSHookIvar<NSString *>(self, "_time"));
165 CGRect &_textRect(MSHookIvar<CGRect>(self, "_textRect"));
168 _time = [@"Exit Safe Mode" retain];
169 GSFontRef font([self textFont]);
170 CGSize size([_time sizeWithFont:(id)font]);
171 CGRect frame([self frame]);
172 _textRect.size = size;
173 _textRect.origin.x = (frame.size.width - size.width) / 2;
174 _textRect.origin.y = (frame.size.height - size.height) / 2;
177 #define Dylib_ "/Library/MobileSubstrate/MobileSubstrate.dylib"
179 extern "C" void MSInitialize() {
180 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
182 NSLog(@"MS:Warning: Entering Safe Mode");
184 _SBButtonBar$maxIconColumns = MSHookMessage(objc_getClass("SBButtonBar"), @selector(maxIconColumns), &$SBButtonBar$maxIconColumns);
185 _SBUIController$init = MSHookMessage(objc_getClass("SBUIController"), @selector(init), &$SBUIController$init);
186 _SBStatusBar$touchesEnded$withEvent$ = MSHookMessage(objc_getClass("SBStatusBar"), @selector(touchesEnded:withEvent:), &$SBStatusBar$touchesEnded$withEvent$);
187 _SBStatusBar$mouseDown$ = MSHookMessage(objc_getClass("SBStatusBar"), @selector(mouseDown:), &$SBStatusBar$mouseDown$);
188 _SBStatusBarTimeView$tile = MSHookMessage(objc_getClass("SBStatusBarTimeView"), @selector(tile), &$SBStatusBarTimeView$tile);
190 _UIImage$defaultDesktopImage = MSHookMessage(object_getClass(objc_getClass("UIImage")), @selector(defaultDesktopImage), &$UIImage$defaultDesktopImage);
192 char *dil = getenv("DYLD_INSERT_LIBRARIES");
194 NSLog(@"MS:Error: DYLD_INSERT_LIBRARIES is unset?");
196 NSArray *dylibs([[NSString stringWithUTF8String:dil] componentsSeparatedByString:@":"]);
197 NSUInteger index([dylibs indexOfObject:@ Dylib_]);
198 if (index == NSNotFound)
199 NSLog(@"MS:Error: dylib not in DYLD_INSERT_LIBRARIES?");
200 else if ([dylibs count] == 1)
201 unsetenv("DYLD_INSERT_LIBRARIES");
203 NSMutableArray *value([[[NSMutableArray alloc] init] autorelease]);
204 [value setArray:dylibs];
205 [value removeObjectAtIndex:index];
206 setenv("DYLD_INSERT_LIBRARIES", [[value componentsJoinedByString:@":"] UTF8String], !0);
210 $SBAlertItemsController = objc_getClass("SBAlertItemsController");
212 if (Class _class = objc_getClass("SBIconController")) {
213 SEL sel(@selector(showInfoAlertIfNeeded));
214 if (Method method = class_getInstanceMethod(_class, sel))
215 method_setImplementation(method, (IMP) &SBIconController$showInfoAlertIfNeeded);