]> git.saurik.com Git - safemode-ios.git/blame - MobileSafety.mm
Replace libsubstrate.dylib with CydiaSubstrate.framework.
[safemode-ios.git] / MobileSafety.mm
CommitLineData
df972f42 1/* Cydia Substrate - Powerful Code Insertion Platform
a938d168 2 * Copyright (C) 2008-2010 Jay Freeman (saurik)
25f84761
JF
3*/
4
df972f42 5/* GNU Lesser General Public License, Version 3 {{{ */
25f84761 6/*
df972f42
JF
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.
25f84761 11 *
df972f42
JF
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.
25f84761 16 *
df972f42
JF
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/>.
19**/
20/* }}} */
25f84761
JF
21
22#import <CoreFoundation/CoreFoundation.h>
23#import <Foundation/Foundation.h>
24#import <CoreGraphics/CGGeometry.h>
39f17851
JF
25#import <UIKit/UIKit.h>
26
27#import <SpringBoard/SBAlertItem.h>
28#import <SpringBoard/SBAlertItemsController.h>
b4f9ed46 29#import <SpringBoard/SBButtonBar.h>
39f17851 30#import <SpringBoard/SBStatusBarController.h>
e5a54d69 31#import <SpringBoard/SBStatusBarDataManager.h>
39f17851 32#import <SpringBoard/SBStatusBarTimeView.h>
b4f9ed46 33#import <SpringBoard/SBUIController.h>
dbbe0f32 34
f6ceb738 35#include "CydiaSubstrate.h"
25f84761 36
39f17851
JF
37Class $SafeModeAlertItem;
38Class $SBAlertItemsController;
39
40void SafeModeAlertItem$alertSheet$buttonClicked$(id self, SEL sel, id sheet, int button) {
41 switch (button) {
42 case 1:
43 break;
44
45 case 2:
46 exit(0);
47 break;
48
49 case 3:
b4f9ed46 50 [UIApp applicationOpenURL:[NSURL URLWithString:@"http://cydia.saurik.com/safemode/"]];
39f17851
JF
51 break;
52 }
53
54 [self dismiss];
55}
56
57void SafeModeAlertItem$configure$requirePasscodeForActions$(id self, SEL sel, BOOL configure, BOOL require) {
e5a54d69 58 id sheet([self alertSheet]);
39f17851 59 [sheet setDelegate:self];
b4f9ed46 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."];
39f17851
JF
61 [sheet addButtonWithTitle:@"OK"];
62 [sheet addButtonWithTitle:@"Restart"];
63 [sheet addButtonWithTitle:@"Help"];
64 [sheet setNumberOfRows:1];
e5a54d69
JF
65 if ([sheet respondsToSelector:@selector(setForceHorizontalButtonsLayout:)])
66 [sheet setForceHorizontalButtonsLayout:YES];
39f17851
JF
67}
68
69void SafeModeAlertItem$performUnlockAction(id self, SEL sel) {
70 [[$SBAlertItemsController sharedInstance] activateAlertItem:self];
71}
72
73static 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)
79 return;
80
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);
85 }
86
87 if ($SBAlertItemsController != nil)
a938d168 88 [[$SBAlertItemsController sharedInstance] activateAlertItem:[[[$SafeModeAlertItem alloc] init] autorelease]];
39f17851
JF
89}
90
b4f9ed46
JF
91MSHook(void, SBStatusBar$touchesEnded$withEvent$, SBStatusBar *self, SEL sel, id touches, id event) {
92 MSAlert();
93 _SBStatusBar$touchesEnded$withEvent$(self, sel, touches, event);
94}
95
39f17851
JF
96MSHook(void, SBStatusBar$mouseDown$, SBStatusBar *self, SEL sel, GSEventRef event) {
97 MSAlert();
98 _SBStatusBar$mouseDown$(self, sel, event);
99}
100
e5a54d69
JF
101MSHook(void, UIStatusBar$touchesBegan$withEvent$, id self, SEL sel, void *arg0, void *arg1) {
102 MSAlert();
103 _UIStatusBar$touchesBegan$withEvent$(self, sel, arg0, arg1);
104}
105
106MSHook(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");
110 }
111}
112
39f17851 113static void SBIconController$showInfoAlertIfNeeded(id self, SEL sel) {
25f84761 114 static bool loaded = false;
39f17851
JF
115 if (loaded)
116 return;
117 loaded = true;
118 MSAlert();
25f84761
JF
119}
120
b4f9ed46 121MSHook(int, SBButtonBar$maxIconColumns, SBButtonBar *self, SEL sel) {
25f84761
JF
122 static int max;
123 if (max == 0) {
b4f9ed46 124 max = _SBButtonBar$maxIconColumns(self, sel);
25f84761
JF
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]);
132 if (max < count)
133 max = count;
134 }
135 } return max;
136}
137
b4f9ed46
JF
138MSHook(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"));
142
143 UIView *layer;
144 if (&_contentLayer != NULL)
145 layer = _contentLayer;
146 else if (&_contentView != NULL)
147 layer = _contentView;
148 else
149 layer = nil;
150
151 if (layer != nil)
152 [layer setBackgroundColor:[UIColor darkGrayColor]];
153 } return self;
25f84761
JF
154}
155
dbbe0f32
JF
156#define Paper_ "/Library/MobileSubstrate/MobilePaper.png"
157
158MSHook(UIImage *, UIImage$defaultDesktopImage, UIImage *self, SEL sel) {
159 return [UIImage imageWithContentsOfFile:@Paper_];
160}
161
39f17851
JF
162MSHook(void, SBStatusBarTimeView$tile, SBStatusBarTimeView *self, SEL sel) {
163 NSString *&_time(MSHookIvar<NSString *>(self, "_time"));
164 CGRect &_textRect(MSHookIvar<CGRect>(self, "_textRect"));
25f84761 165 if (_time != nil)
39f17851 166 [_time release];
dbbe0f32 167 _time = [@"Exit Safe Mode" retain];
39f17851
JF
168 GSFontRef font([self textFont]);
169 CGSize size([_time sizeWithFont:(id)font]);
170 CGRect frame([self frame]);
39f17851
JF
171 _textRect.size = size;
172 _textRect.origin.x = (frame.size.width - size.width) / 2;
173 _textRect.origin.y = (frame.size.height - size.height) / 2;
25f84761
JF
174}
175
176#define Dylib_ "/Library/MobileSubstrate/MobileSubstrate.dylib"
177
63918068 178MSInitialize {
10586051
JF
179 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
180
25f84761
JF
181 NSLog(@"MS:Warning: Entering Safe Mode");
182
b4f9ed46
JF
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$);
39f17851 186 _SBStatusBar$mouseDown$ = MSHookMessage(objc_getClass("SBStatusBar"), @selector(mouseDown:), &$SBStatusBar$mouseDown$);
e5a54d69 187 _SBStatusBarDataManager$_updateTimeString = MSHookMessage(objc_getClass("SBStatusBarDataManager"), @selector(_updateTimeString), &$SBStatusBarDataManager$_updateTimeString);
39f17851 188 _SBStatusBarTimeView$tile = MSHookMessage(objc_getClass("SBStatusBarTimeView"), @selector(tile), &$SBStatusBarTimeView$tile);
25f84761 189
e5a54d69
JF
190 _UIStatusBar$touchesBegan$withEvent$ = MSHookMessage(objc_getClass("UIStatusBar"), @selector(touchesBegan:withEvent:), &$UIStatusBar$touchesBegan$withEvent$);
191
dbbe0f32 192 _UIImage$defaultDesktopImage = MSHookMessage(object_getClass(objc_getClass("UIImage")), @selector(defaultDesktopImage), &$UIImage$defaultDesktopImage);
dbbe0f32 193
25f84761
JF
194 char *dil = getenv("DYLD_INSERT_LIBRARIES");
195 if (dil == NULL)
196 NSLog(@"MS:Error: DYLD_INSERT_LIBRARIES is unset?");
197 else {
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");
204 else {
205 NSMutableArray *value([[[NSMutableArray alloc] init] autorelease]);
206 [value setArray:dylibs];
207 [value removeObjectAtIndex:index];
208 setenv("DYLD_INSERT_LIBRARIES", [[value componentsJoinedByString:@":"] UTF8String], !0);
209 }
210 }
211
39f17851
JF
212 $SBAlertItemsController = objc_getClass("SBAlertItemsController");
213
25f84761
JF
214 if (Class _class = objc_getClass("SBIconController")) {
215 SEL sel(@selector(showInfoAlertIfNeeded));
216 if (Method method = class_getInstanceMethod(_class, sel))
39f17851 217 method_setImplementation(method, (IMP) &SBIconController$showInfoAlertIfNeeded);
25f84761 218 }
10586051
JF
219
220 [pool release];
25f84761 221}