1 /* Cydia Substrate - Powerful Code Insertion Platform
2 * Copyright (C) 2008-2011 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(AAAccountManager)
35 MSMetaClassHook(AAAccountManager)
37 MSClassHook(SBAlertItemsController)
38 MSClassHook(SBButtonBar)
39 MSClassHook(SBIconController)
40 MSClassHook(SBStatusBar)
41 MSClassHook(SBStatusBarDataManager)
42 MSClassHook(SBStatusBarTimeView)
43 MSClassHook(SBUIController)
45 Class $SafeModeAlertItem;
47 @interface SBAlertItem : NSObject {
49 - (UIAlertView *) alertSheet;
53 @interface SBAlertItemsController : NSObject {
55 + (SBAlertItemsController *) sharedInstance;
56 - (void) activateAlertItem:(SBAlertItem *)item;
59 @interface SBStatusBarTimeView : UIView {
64 @interface UIApplication (CydiaSubstrate)
65 - (void) applicationOpenURL:(id)url;
68 @interface UIAlertView (CydiaSubstrate)
69 - (void) setForceHorizontalButtonsLayout:(BOOL)force;
70 - (void) setBodyText:(NSString *)body;
71 - (void) setNumberOfRows:(NSInteger)rows;
74 void SafeModeAlertItem$alertSheet$buttonClicked$(id self, SEL sel, id sheet, int button) {
84 [[UIApplication sharedApplication] applicationOpenURL:[NSURL URLWithString:@"http://cydia.saurik.com/safemode/"]];
91 void SafeModeAlertItem$configure$requirePasscodeForActions$(id self, SEL sel, BOOL configure, BOOL require) {
92 UIAlertView *sheet([self alertSheet]);
93 [sheet setDelegate:self];
94 [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."];
95 [sheet addButtonWithTitle:@"OK"];
96 [sheet addButtonWithTitle:@"Restart"];
97 [sheet addButtonWithTitle:@"Help"];
98 [sheet setNumberOfRows:1];
99 if ([sheet respondsToSelector:@selector(setForceHorizontalButtonsLayout:)])
100 [sheet setForceHorizontalButtonsLayout:YES];
103 void SafeModeAlertItem$performUnlockAction(id self, SEL sel) {
104 [[$SBAlertItemsController sharedInstance] activateAlertItem:self];
107 static void MSAlert() {
108 if ($SafeModeAlertItem == nil)
109 $SafeModeAlertItem = objc_lookUpClass("SafeModeAlertItem");
110 if ($SafeModeAlertItem == nil) {
111 $SafeModeAlertItem = objc_allocateClassPair(objc_getClass("SBAlertItem"), "SafeModeAlertItem", 0);
112 if ($SafeModeAlertItem == nil)
115 class_addMethod($SafeModeAlertItem, @selector(alertSheet:buttonClicked:), (IMP) &SafeModeAlertItem$alertSheet$buttonClicked$, "v@:@i");
116 class_addMethod($SafeModeAlertItem, @selector(configure:requirePasscodeForActions:), (IMP) &SafeModeAlertItem$configure$requirePasscodeForActions$, "v@:cc");
117 class_addMethod($SafeModeAlertItem, @selector(performUnlockAction), (IMP) SafeModeAlertItem$performUnlockAction, "v@:");
118 objc_registerClassPair($SafeModeAlertItem);
121 if ($SBAlertItemsController != nil)
122 [[$SBAlertItemsController sharedInstance] activateAlertItem:[[[$SafeModeAlertItem alloc] init] autorelease]];
125 MSInstanceMessageHook2(void, SBStatusBar, touchesEnded,withEvent, id, touches, id, event) {
127 MSOldCall(touches, event);
130 MSInstanceMessageHook1(void, SBStatusBar, mouseDown, void *, event) {
135 MSInstanceMessageHook2(void, UIStatusBar, touchesBegan,withEvent, void *, touches, void *, event) {
137 MSOldCall(touches, event);
140 MSInstanceMessageHook0(void, SBStatusBarDataManager, _updateTimeString) {
141 char *_data(&MSHookIvar<char>(self, "_data"));
145 Ivar _itemIsEnabled(object_getInstanceVariable(self, "_itemIsEnabled", NULL));
146 if (_itemIsEnabled == NULL)
149 Ivar _itemIsCloaked(object_getInstanceVariable(self, "_itemIsCloaked", NULL));
150 if (_itemIsCloaked == NULL)
153 size_t enabledOffset(ivar_getOffset(_itemIsEnabled));
154 size_t cloakedOffset(ivar_getOffset(_itemIsCloaked));
155 if (enabledOffset >= cloakedOffset)
158 size_t offset(cloakedOffset - enabledOffset);
159 char *timeString(_data + offset);
160 strcpy(timeString, "Exit Safe Mode");
163 static bool alerted_;
165 static void AlertIfNeeded() {
172 MSClassMessageHook0(void, AAAccountManager, showMobileMeOfferIfNecessary) {
176 MSInstanceMessageHook0(void, SBIconController, showInfoAlertIfNeeded) {
180 MSInstanceMessageHook0(int, SBButtonBar, maxIconColumns) {
184 if (NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults])
185 if (NSDictionary *iconState = [defaults objectForKey:@"iconState"])
186 if (NSDictionary *buttonBar = [iconState objectForKey:@"buttonBar"])
187 if (NSArray *iconMatrix = [buttonBar objectForKey:@"iconMatrix"])
188 if ([iconMatrix count] != 0)
189 if (NSArray *row = [iconMatrix objectAtIndex:0]) {
190 int count([row count]);
197 MSInstanceMessageHook0(id, SBUIController, init) {
198 if ((self = MSOldCall()) != nil) {
199 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
200 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
203 if (&_contentLayer != NULL)
204 layer = _contentLayer;
205 else if (&_contentView != NULL)
206 layer = _contentView;
211 [layer setBackgroundColor:[UIColor darkGrayColor]];
215 #define Paper_ "/Library/MobileSubstrate/MobileSafety.png"
217 MSClassMessageHook0(UIImage *, UIImage, defaultDesktopImage) {
218 return [UIImage imageWithContentsOfFile:@Paper_];
221 MSInstanceMessageHook0(void, SBStatusBarTimeView, tile) {
222 NSString *&_time(MSHookIvar<NSString *>(self, "_time"));
223 CGRect &_textRect(MSHookIvar<CGRect>(self, "_textRect"));
226 _time = [@"Exit Safe Mode" retain];
227 id font([self textFont]);
228 CGSize size([_time sizeWithFont:font]);
229 CGRect frame([self frame]);
230 _textRect.size = size;
231 _textRect.origin.x = (frame.size.width - size.width) / 2;
232 _textRect.origin.y = (frame.size.height - size.height) / 2;
235 #define Dylib_ "/Library/MobileSubstrate/MobileSubstrate.dylib"
238 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
240 NSLog(@"MS:Warning: Entering Safe Mode");
242 char *dil(getenv("DYLD_INSERT_LIBRARIES"));
244 NSLog(@"MS:Error: DYLD_INSERT_LIBRARIES is unset?");
246 NSArray *dylibs([[NSString stringWithUTF8String:dil] componentsSeparatedByString:@":"]);
247 NSUInteger index([dylibs indexOfObject:@ Dylib_]);
248 if (index == NSNotFound)
249 NSLog(@"MS:Error: dylib not in DYLD_INSERT_LIBRARIES?");
250 else if ([dylibs count] == 1)
251 unsetenv("DYLD_INSERT_LIBRARIES");
253 NSMutableArray *value([[[NSMutableArray alloc] init] autorelease]);
254 [value setArray:dylibs];
255 [value removeObjectAtIndex:index];
256 setenv("DYLD_INSERT_LIBRARIES", [[value componentsJoinedByString:@":"] UTF8String], !0);