1 /* Cydia Substrate - Powerful Code Insertion Platform
2 * Copyright (C) 2008-2010 Jay Freeman (saurik)
5 /* GNU Lesser General Public License, Version 3 {{{ */
7 * Cycript is free software: you can redistribute it and/or modify it under
8 * the terms of the GNU Lesser General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
12 * Cycript is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 * License for more details.
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with Cycript. If not, see <http://www.gnu.org/licenses/>.
22 #import <CoreFoundation/CoreFoundation.h>
23 #import <Foundation/Foundation.h>
24 #import <CoreGraphics/CGGeometry.h>
25 #import <UIKit/UIKit.h>
27 #import <SpringBoard/SBAlertItem.h>
28 #import <SpringBoard/SBAlertItemsController.h>
29 #import <SpringBoard/SBButtonBar.h>
30 #import <SpringBoard/SBStatusBarController.h>
31 #import <SpringBoard/SBStatusBarDataManager.h>
32 #import <SpringBoard/SBStatusBarTimeView.h>
33 #import <SpringBoard/SBUIController.h>
35 #include <substrate.h>
37 Class $SafeModeAlertItem;
38 Class $SBAlertItemsController;
40 void SafeModeAlertItem$alertSheet$buttonClicked$(id self, SEL sel, id sheet, int button) {
50 [UIApp applicationOpenURL:[NSURL URLWithString:@"http://cydia.saurik.com/safemode/"]];
57 void SafeModeAlertItem$configure$requirePasscodeForActions$(id self, SEL sel, BOOL configure, BOOL require) {
58 id sheet([self alertSheet]);
59 [sheet setDelegate:self];
60 [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."];
61 [sheet addButtonWithTitle:@"OK"];
62 [sheet addButtonWithTitle:@"Restart"];
63 [sheet addButtonWithTitle:@"Help"];
64 [sheet setNumberOfRows:1];
65 if ([sheet respondsToSelector:@selector(setForceHorizontalButtonsLayout:)])
66 [sheet setForceHorizontalButtonsLayout:YES];
69 void SafeModeAlertItem$performUnlockAction(id self, SEL sel) {
70 [[$SBAlertItemsController sharedInstance] activateAlertItem:self];
73 static void MSAlert() {
74 if ($SafeModeAlertItem == nil)
75 $SafeModeAlertItem = objc_lookUpClass("SafeModeAlertItem");
76 if ($SafeModeAlertItem == nil) {
77 $SafeModeAlertItem = objc_allocateClassPair(objc_getClass("SBAlertItem"), "SafeModeAlertItem", 0);
78 if ($SafeModeAlertItem == nil)
81 class_addMethod($SafeModeAlertItem, @selector(alertSheet:buttonClicked:), (IMP) &SafeModeAlertItem$alertSheet$buttonClicked$, "v@:@i");
82 class_addMethod($SafeModeAlertItem, @selector(configure:requirePasscodeForActions:), (IMP) &SafeModeAlertItem$configure$requirePasscodeForActions$, "v@:cc");
83 class_addMethod($SafeModeAlertItem, @selector(performUnlockAction), (IMP) SafeModeAlertItem$performUnlockAction, "v@:");
84 objc_registerClassPair($SafeModeAlertItem);
87 if ($SBAlertItemsController != nil)
88 [[$SBAlertItemsController sharedInstance] activateAlertItem:[[[$SafeModeAlertItem alloc] init] autorelease]];
91 MSHook(void, SBStatusBar$touchesEnded$withEvent$, SBStatusBar *self, SEL sel, id touches, id event) {
93 _SBStatusBar$touchesEnded$withEvent$(self, sel, touches, event);
96 MSHook(void, SBStatusBar$mouseDown$, SBStatusBar *self, SEL sel, GSEventRef event) {
98 _SBStatusBar$mouseDown$(self, sel, event);
101 MSHook(void, UIStatusBar$touchesBegan$withEvent$, id self, SEL sel, void *arg0, void *arg1) {
103 _UIStatusBar$touchesBegan$withEvent$(self, sel, arg0, arg1);
106 MSHook(void, SBStatusBarDataManager$_updateTimeString, id self, SEL sel) {
107 if (char *_data = &MSHookIvar<char>(self, "_data")) {
108 char *timeString(_data + 20);
109 strcpy(timeString, "Exit Safe Mode");
113 static void SBIconController$showInfoAlertIfNeeded(id self, SEL sel) {
114 static bool loaded = false;
121 MSHook(int, SBButtonBar$maxIconColumns, SBButtonBar *self, SEL sel) {
124 max = _SBButtonBar$maxIconColumns(self, sel);
125 if (NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults])
126 if (NSDictionary *iconState = [defaults objectForKey:@"iconState"])
127 if (NSDictionary *buttonBar = [iconState objectForKey:@"buttonBar"])
128 if (NSArray *iconMatrix = [buttonBar objectForKey:@"iconMatrix"])
129 if ([iconMatrix count] != 0)
130 if (NSArray *row = [iconMatrix objectAtIndex:0]) {
131 int count([row count]);
138 MSHook(id, SBUIController$init, SBUIController *self, SEL sel) {
139 if ((self = _SBUIController$init(self, sel)) != nil) {
140 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
141 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
144 if (&_contentLayer != NULL)
145 layer = _contentLayer;
146 else if (&_contentView != NULL)
147 layer = _contentView;
152 [layer setBackgroundColor:[UIColor darkGrayColor]];
156 #define Paper_ "/Library/MobileSubstrate/MobilePaper.png"
158 MSHook(UIImage *, UIImage$defaultDesktopImage, UIImage *self, SEL sel) {
159 return [UIImage imageWithContentsOfFile:@Paper_];
162 MSHook(void, SBStatusBarTimeView$tile, SBStatusBarTimeView *self, SEL sel) {
163 NSString *&_time(MSHookIvar<NSString *>(self, "_time"));
164 CGRect &_textRect(MSHookIvar<CGRect>(self, "_textRect"));
167 _time = [@"Exit Safe Mode" retain];
168 GSFontRef font([self textFont]);
169 CGSize size([_time sizeWithFont:(id)font]);
170 CGRect frame([self frame]);
171 _textRect.size = size;
172 _textRect.origin.x = (frame.size.width - size.width) / 2;
173 _textRect.origin.y = (frame.size.height - size.height) / 2;
176 #define Dylib_ "/Library/MobileSubstrate/MobileSubstrate.dylib"
179 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
181 NSLog(@"MS:Warning: Entering Safe Mode");
183 _SBButtonBar$maxIconColumns = MSHookMessage(objc_getClass("SBButtonBar"), @selector(maxIconColumns), &$SBButtonBar$maxIconColumns);
184 _SBUIController$init = MSHookMessage(objc_getClass("SBUIController"), @selector(init), &$SBUIController$init);
185 _SBStatusBar$touchesEnded$withEvent$ = MSHookMessage(objc_getClass("SBStatusBar"), @selector(touchesEnded:withEvent:), &$SBStatusBar$touchesEnded$withEvent$);
186 _SBStatusBar$mouseDown$ = MSHookMessage(objc_getClass("SBStatusBar"), @selector(mouseDown:), &$SBStatusBar$mouseDown$);
187 _SBStatusBarDataManager$_updateTimeString = MSHookMessage(objc_getClass("SBStatusBarDataManager"), @selector(_updateTimeString), &$SBStatusBarDataManager$_updateTimeString);
188 _SBStatusBarTimeView$tile = MSHookMessage(objc_getClass("SBStatusBarTimeView"), @selector(tile), &$SBStatusBarTimeView$tile);
190 _UIStatusBar$touchesBegan$withEvent$ = MSHookMessage(objc_getClass("UIStatusBar"), @selector(touchesBegan:withEvent:), &$UIStatusBar$touchesBegan$withEvent$);
192 _UIImage$defaultDesktopImage = MSHookMessage(object_getClass(objc_getClass("UIImage")), @selector(defaultDesktopImage), &$UIImage$defaultDesktopImage);
194 char *dil = getenv("DYLD_INSERT_LIBRARIES");
196 NSLog(@"MS:Error: DYLD_INSERT_LIBRARIES is unset?");
198 NSArray *dylibs([[NSString stringWithUTF8String:dil] componentsSeparatedByString:@":"]);
199 NSUInteger index([dylibs indexOfObject:@ Dylib_]);
200 if (index == NSNotFound)
201 NSLog(@"MS:Error: dylib not in DYLD_INSERT_LIBRARIES?");
202 else if ([dylibs count] == 1)
203 unsetenv("DYLD_INSERT_LIBRARIES");
205 NSMutableArray *value([[[NSMutableArray alloc] init] autorelease]);
206 [value setArray:dylibs];
207 [value removeObjectAtIndex:index];
208 setenv("DYLD_INSERT_LIBRARIES", [[value componentsJoinedByString:@":"] UTF8String], !0);
212 $SBAlertItemsController = objc_getClass("SBAlertItemsController");
214 if (Class _class = objc_getClass("SBIconController")) {
215 SEL sel(@selector(showInfoAlertIfNeeded));
216 if (Method method = class_getInstanceMethod(_class, sel))
217 method_setImplementation(method, (IMP) &SBIconController$showInfoAlertIfNeeded);