1 /* Cydia Substrate - Powerful Code Insertion Platform
2 * Copyright (C) 2008-2010 Jay Freeman (saurik)
5 /* GNU Lesser General Public License, Version 3 {{{ */
7 * Substrate 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 * Substrate 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 Substrate. 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 #include "CydiaSubstrate.h"
29 MSClassHook(UIStatusBar)
32 MSMetaClassHook(UIImage)
34 MSClassHook(SBAlertItemsController)
35 MSClassHook(SBButtonBar)
36 MSClassHook(SBStatusBar)
37 MSClassHook(SBStatusBarDataManager)
38 MSClassHook(SBStatusBarTimeView)
39 MSClassHook(SBUIController)
41 Class $SafeModeAlertItem;
43 @interface SBAlertItem : NSObject {
45 - (UIAlertView *) alertSheet;
49 @interface SBAlertItemsController : NSObject {
51 + (SBAlertItemsController *) sharedInstance;
52 - (void) activateAlertItem:(SBAlertItem *)item;
55 @interface SBStatusBarTimeView : UIView {
60 @interface UIApplication (CydiaSubstrate)
61 - (void) applicationOpenURL:(id)url;
64 @interface UIAlertView (CydiaSubstrate)
65 - (void) setForceHorizontalButtonsLayout:(BOOL)force;
66 - (void) setBodyText:(NSString *)body;
67 - (void) setNumberOfRows:(NSInteger)rows;
70 void SafeModeAlertItem$alertSheet$buttonClicked$(id self, SEL sel, id sheet, int button) {
80 [[UIApplication sharedApplication] applicationOpenURL:[NSURL URLWithString:@"http://cydia.saurik.com/safemode/"]];
87 void SafeModeAlertItem$configure$requirePasscodeForActions$(id self, SEL sel, BOOL configure, BOOL require) {
88 UIAlertView *sheet([self alertSheet]);
89 [sheet setDelegate:self];
90 [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."];
91 [sheet addButtonWithTitle:@"OK"];
92 [sheet addButtonWithTitle:@"Restart"];
93 [sheet addButtonWithTitle:@"Help"];
94 [sheet setNumberOfRows:1];
95 if ([sheet respondsToSelector:@selector(setForceHorizontalButtonsLayout:)])
96 [sheet setForceHorizontalButtonsLayout:YES];
99 void SafeModeAlertItem$performUnlockAction(id self, SEL sel) {
100 [[$SBAlertItemsController sharedInstance] activateAlertItem:self];
103 static void MSAlert() {
104 if ($SafeModeAlertItem == nil)
105 $SafeModeAlertItem = objc_lookUpClass("SafeModeAlertItem");
106 if ($SafeModeAlertItem == nil) {
107 $SafeModeAlertItem = objc_allocateClassPair(objc_getClass("SBAlertItem"), "SafeModeAlertItem", 0);
108 if ($SafeModeAlertItem == nil)
111 class_addMethod($SafeModeAlertItem, @selector(alertSheet:buttonClicked:), (IMP) &SafeModeAlertItem$alertSheet$buttonClicked$, "v@:@i");
112 class_addMethod($SafeModeAlertItem, @selector(configure:requirePasscodeForActions:), (IMP) &SafeModeAlertItem$configure$requirePasscodeForActions$, "v@:cc");
113 class_addMethod($SafeModeAlertItem, @selector(performUnlockAction), (IMP) SafeModeAlertItem$performUnlockAction, "v@:");
114 objc_registerClassPair($SafeModeAlertItem);
117 if ($SBAlertItemsController != nil)
118 [[$SBAlertItemsController sharedInstance] activateAlertItem:[[[$SafeModeAlertItem alloc] init] autorelease]];
121 MSInstanceMessageHook2(void, SBStatusBar, touchesEnded,withEvent, id, touches, id, event) {
123 MSOldCall(touches, event);
126 MSInstanceMessageHook1(void, SBStatusBar, mouseDown, void *, event) {
131 MSInstanceMessageHook2(void, UIStatusBar, touchesBegan,withEvent, void *, touches, void *, event) {
133 MSOldCall(touches, event);
136 MSInstanceMessageHook0(void, SBStatusBarDataManager, _updateTimeString) {
137 if (char *_data = &MSHookIvar<char>(self, "_data")) {
138 char *timeString(_data + 20);
139 strcpy(timeString, "Exit Safe Mode");
143 static void SBIconController$showInfoAlertIfNeeded(id self, SEL sel) {
144 static bool loaded = false;
151 MSInstanceMessageHook0(int, SBButtonBar, maxIconColumns) {
155 if (NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults])
156 if (NSDictionary *iconState = [defaults objectForKey:@"iconState"])
157 if (NSDictionary *buttonBar = [iconState objectForKey:@"buttonBar"])
158 if (NSArray *iconMatrix = [buttonBar objectForKey:@"iconMatrix"])
159 if ([iconMatrix count] != 0)
160 if (NSArray *row = [iconMatrix objectAtIndex:0]) {
161 int count([row count]);
168 MSInstanceMessageHook0(id, SBUIController, init) {
169 if ((self = MSOldCall()) != nil) {
170 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
171 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
174 if (&_contentLayer != NULL)
175 layer = _contentLayer;
176 else if (&_contentView != NULL)
177 layer = _contentView;
182 [layer setBackgroundColor:[UIColor darkGrayColor]];
186 #define Paper_ "/Library/MobileSubstrate/MobileSafety.png"
188 MSClassMessageHook0(UIImage *, UIImage, defaultDesktopImage) {
189 return [UIImage imageWithContentsOfFile:@Paper_];
192 MSInstanceMessageHook0(void, SBStatusBarTimeView, tile) {
193 NSString *&_time(MSHookIvar<NSString *>(self, "_time"));
194 CGRect &_textRect(MSHookIvar<CGRect>(self, "_textRect"));
197 _time = [@"Exit Safe Mode" retain];
198 id font([self textFont]);
199 CGSize size([_time sizeWithFont:font]);
200 CGRect frame([self frame]);
201 _textRect.size = size;
202 _textRect.origin.x = (frame.size.width - size.width) / 2;
203 _textRect.origin.y = (frame.size.height - size.height) / 2;
206 #define Dylib_ "/Library/MobileSubstrate/MobileSubstrate.dylib"
209 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
211 NSLog(@"MS:Warning: Entering Safe Mode");
213 char *dil(getenv("DYLD_INSERT_LIBRARIES"));
215 NSLog(@"MS:Error: DYLD_INSERT_LIBRARIES is unset?");
217 NSArray *dylibs([[NSString stringWithUTF8String:dil] componentsSeparatedByString:@":"]);
218 NSUInteger index([dylibs indexOfObject:@ Dylib_]);
219 if (index == NSNotFound)
220 NSLog(@"MS:Error: dylib not in DYLD_INSERT_LIBRARIES?");
221 else if ([dylibs count] == 1)
222 unsetenv("DYLD_INSERT_LIBRARIES");
224 NSMutableArray *value([[[NSMutableArray alloc] init] autorelease]);
225 [value setArray:dylibs];
226 [value removeObjectAtIndex:index];
227 setenv("DYLD_INSERT_LIBRARIES", [[value componentsJoinedByString:@":"] UTF8String], !0);
231 $SBAlertItemsController = objc_getClass("SBAlertItemsController");
233 if (Class _class = objc_getClass("SBIconController")) {
234 SEL sel(@selector(showInfoAlertIfNeeded));
235 if (Method method = class_getInstanceMethod(_class, sel))
236 method_setImplementation(method, (IMP) &SBIconController$showInfoAlertIfNeeded);