1 /* Cydia Substrate - Meta-Library Insert for iPhoneOS
2 * Copyright (C) 2008-2010 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/SBStatusBarDataManager.h>
48 #import <SpringBoard/SBStatusBarTimeView.h>
49 #import <SpringBoard/SBUIController.h>
51 #include <substrate.h>
53 Class $SafeModeAlertItem;
54 Class $SBAlertItemsController;
56 void SafeModeAlertItem$alertSheet$buttonClicked$(id self, SEL sel, id sheet, int button) {
66 [UIApp applicationOpenURL:[NSURL URLWithString:@"http://cydia.saurik.com/safemode/"]];
73 void SafeModeAlertItem$configure$requirePasscodeForActions$(id self, SEL sel, BOOL configure, BOOL require) {
74 id sheet([self alertSheet]);
75 [sheet setDelegate:self];
76 [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."];
77 [sheet addButtonWithTitle:@"OK"];
78 [sheet addButtonWithTitle:@"Restart"];
79 [sheet addButtonWithTitle:@"Help"];
80 [sheet setNumberOfRows:1];
81 if ([sheet respondsToSelector:@selector(setForceHorizontalButtonsLayout:)])
82 [sheet setForceHorizontalButtonsLayout:YES];
85 void SafeModeAlertItem$performUnlockAction(id self, SEL sel) {
86 [[$SBAlertItemsController sharedInstance] activateAlertItem:self];
89 static void MSAlert() {
90 if ($SafeModeAlertItem == nil)
91 $SafeModeAlertItem = objc_lookUpClass("SafeModeAlertItem");
92 if ($SafeModeAlertItem == nil) {
93 $SafeModeAlertItem = objc_allocateClassPair(objc_getClass("SBAlertItem"), "SafeModeAlertItem", 0);
94 if ($SafeModeAlertItem == nil)
97 class_addMethod($SafeModeAlertItem, @selector(alertSheet:buttonClicked:), (IMP) &SafeModeAlertItem$alertSheet$buttonClicked$, "v@:@i");
98 class_addMethod($SafeModeAlertItem, @selector(configure:requirePasscodeForActions:), (IMP) &SafeModeAlertItem$configure$requirePasscodeForActions$, "v@:cc");
99 class_addMethod($SafeModeAlertItem, @selector(performUnlockAction), (IMP) SafeModeAlertItem$performUnlockAction, "v@:");
100 objc_registerClassPair($SafeModeAlertItem);
103 if ($SBAlertItemsController != nil)
104 [[$SBAlertItemsController sharedInstance] activateAlertItem:[[[$SafeModeAlertItem alloc] init] autorelease]];
107 MSHook(void, SBStatusBar$touchesEnded$withEvent$, SBStatusBar *self, SEL sel, id touches, id event) {
109 _SBStatusBar$touchesEnded$withEvent$(self, sel, touches, event);
112 MSHook(void, SBStatusBar$mouseDown$, SBStatusBar *self, SEL sel, GSEventRef event) {
114 _SBStatusBar$mouseDown$(self, sel, event);
117 MSHook(void, UIStatusBar$touchesBegan$withEvent$, id self, SEL sel, void *arg0, void *arg1) {
119 _UIStatusBar$touchesBegan$withEvent$(self, sel, arg0, arg1);
122 MSHook(void, SBStatusBarDataManager$_updateTimeString, id self, SEL sel) {
123 if (char *_data = &MSHookIvar<char>(self, "_data")) {
124 char *timeString(_data + 20);
125 strcpy(timeString, "Exit Safe Mode");
129 static void SBIconController$showInfoAlertIfNeeded(id self, SEL sel) {
130 static bool loaded = false;
137 MSHook(int, SBButtonBar$maxIconColumns, SBButtonBar *self, SEL sel) {
140 max = _SBButtonBar$maxIconColumns(self, sel);
141 if (NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults])
142 if (NSDictionary *iconState = [defaults objectForKey:@"iconState"])
143 if (NSDictionary *buttonBar = [iconState objectForKey:@"buttonBar"])
144 if (NSArray *iconMatrix = [buttonBar objectForKey:@"iconMatrix"])
145 if ([iconMatrix count] != 0)
146 if (NSArray *row = [iconMatrix objectAtIndex:0]) {
147 int count([row count]);
154 MSHook(id, SBUIController$init, SBUIController *self, SEL sel) {
155 if ((self = _SBUIController$init(self, sel)) != nil) {
156 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
157 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
160 if (&_contentLayer != NULL)
161 layer = _contentLayer;
162 else if (&_contentView != NULL)
163 layer = _contentView;
168 [layer setBackgroundColor:[UIColor darkGrayColor]];
172 #define Paper_ "/Library/MobileSubstrate/MobilePaper.png"
174 MSHook(UIImage *, UIImage$defaultDesktopImage, UIImage *self, SEL sel) {
175 return [UIImage imageWithContentsOfFile:@Paper_];
178 MSHook(void, SBStatusBarTimeView$tile, SBStatusBarTimeView *self, SEL sel) {
179 NSString *&_time(MSHookIvar<NSString *>(self, "_time"));
180 CGRect &_textRect(MSHookIvar<CGRect>(self, "_textRect"));
183 _time = [@"Exit Safe Mode" retain];
184 GSFontRef font([self textFont]);
185 CGSize size([_time sizeWithFont:(id)font]);
186 CGRect frame([self frame]);
187 _textRect.size = size;
188 _textRect.origin.x = (frame.size.width - size.width) / 2;
189 _textRect.origin.y = (frame.size.height - size.height) / 2;
192 #define Dylib_ "/Library/MobileSubstrate/MobileSubstrate.dylib"
195 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
197 NSLog(@"MS:Warning: Entering Safe Mode");
199 _SBButtonBar$maxIconColumns = MSHookMessage(objc_getClass("SBButtonBar"), @selector(maxIconColumns), &$SBButtonBar$maxIconColumns);
200 _SBUIController$init = MSHookMessage(objc_getClass("SBUIController"), @selector(init), &$SBUIController$init);
201 _SBStatusBar$touchesEnded$withEvent$ = MSHookMessage(objc_getClass("SBStatusBar"), @selector(touchesEnded:withEvent:), &$SBStatusBar$touchesEnded$withEvent$);
202 _SBStatusBar$mouseDown$ = MSHookMessage(objc_getClass("SBStatusBar"), @selector(mouseDown:), &$SBStatusBar$mouseDown$);
203 _SBStatusBarDataManager$_updateTimeString = MSHookMessage(objc_getClass("SBStatusBarDataManager"), @selector(_updateTimeString), &$SBStatusBarDataManager$_updateTimeString);
204 _SBStatusBarTimeView$tile = MSHookMessage(objc_getClass("SBStatusBarTimeView"), @selector(tile), &$SBStatusBarTimeView$tile);
206 _UIStatusBar$touchesBegan$withEvent$ = MSHookMessage(objc_getClass("UIStatusBar"), @selector(touchesBegan:withEvent:), &$UIStatusBar$touchesBegan$withEvent$);
208 _UIImage$defaultDesktopImage = MSHookMessage(object_getClass(objc_getClass("UIImage")), @selector(defaultDesktopImage), &$UIImage$defaultDesktopImage);
210 char *dil = getenv("DYLD_INSERT_LIBRARIES");
212 NSLog(@"MS:Error: DYLD_INSERT_LIBRARIES is unset?");
214 NSArray *dylibs([[NSString stringWithUTF8String:dil] componentsSeparatedByString:@":"]);
215 NSUInteger index([dylibs indexOfObject:@ Dylib_]);
216 if (index == NSNotFound)
217 NSLog(@"MS:Error: dylib not in DYLD_INSERT_LIBRARIES?");
218 else if ([dylibs count] == 1)
219 unsetenv("DYLD_INSERT_LIBRARIES");
221 NSMutableArray *value([[[NSMutableArray alloc] init] autorelease]);
222 [value setArray:dylibs];
223 [value removeObjectAtIndex:index];
224 setenv("DYLD_INSERT_LIBRARIES", [[value componentsJoinedByString:@":"] UTF8String], !0);
228 $SBAlertItemsController = objc_getClass("SBAlertItemsController");
230 if (Class _class = objc_getClass("SBIconController")) {
231 SEL sel(@selector(showInfoAlertIfNeeded));
232 if (Method method = class_getInstanceMethod(_class, sel))
233 method_setImplementation(method, (IMP) &SBIconController$showInfoAlertIfNeeded);