]> git.saurik.com Git - safemode-ios.git/blame - MobileSafety.mm
Rename MobilePaper.* to MobileSafety.*.
[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/*
5bb6a76c 7 * Substrate is free software: you can redistribute it and/or modify it under
df972f42
JF
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 *
5bb6a76c 12 * Substrate is distributed in the hope that it will be useful, but WITHOUT
df972f42
JF
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 17 * You should have received a copy of the GNU Lesser General Public License
5bb6a76c 18 * along with Substrate. If not, see <http://www.gnu.org/licenses/>.
df972f42
JF
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
f6ceb738 27#include "CydiaSubstrate.h"
25f84761 28
2c75d26c
JF
29@class SBButtonBar;
30@class SBStatusBar;
31@class SBUIController;
32
39f17851
JF
33Class $SafeModeAlertItem;
34Class $SBAlertItemsController;
35
2c75d26c
JF
36@interface SBAlertItem : NSObject {
37}
38- (UIAlertView *) alertSheet;
39- (void) dismiss;
40@end
41
42@interface SBAlertItemsController : NSObject {
43}
44+ (SBAlertItemsController *) sharedInstance;
45- (void) activateAlertItem:(SBAlertItem *)item;
46@end
47
48@interface SBStatusBarTimeView : UIView {
49}
50- (id) textFont;
51@end
52
88d77501
JF
53@interface UIApplication (CydiaSubstrate)
54- (void) applicationOpenURL:(id)url;
55@end
56
57@interface UIAlertView (CydiaSubstrate)
58- (void) setForceHorizontalButtonsLayout:(BOOL)force;
59- (void) setBodyText:(NSString *)body;
60- (void) setNumberOfRows:(NSInteger)rows;
61@end
62
39f17851
JF
63void SafeModeAlertItem$alertSheet$buttonClicked$(id self, SEL sel, id sheet, int button) {
64 switch (button) {
65 case 1:
66 break;
67
68 case 2:
69 exit(0);
70 break;
71
72 case 3:
88d77501 73 [[UIApplication sharedApplication] applicationOpenURL:[NSURL URLWithString:@"http://cydia.saurik.com/safemode/"]];
39f17851
JF
74 break;
75 }
76
77 [self dismiss];
78}
79
80void SafeModeAlertItem$configure$requirePasscodeForActions$(id self, SEL sel, BOOL configure, BOOL require) {
2c75d26c 81 UIAlertView *sheet([self alertSheet]);
39f17851 82 [sheet setDelegate:self];
b4f9ed46 83 [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
84 [sheet addButtonWithTitle:@"OK"];
85 [sheet addButtonWithTitle:@"Restart"];
86 [sheet addButtonWithTitle:@"Help"];
87 [sheet setNumberOfRows:1];
e5a54d69
JF
88 if ([sheet respondsToSelector:@selector(setForceHorizontalButtonsLayout:)])
89 [sheet setForceHorizontalButtonsLayout:YES];
39f17851
JF
90}
91
92void SafeModeAlertItem$performUnlockAction(id self, SEL sel) {
93 [[$SBAlertItemsController sharedInstance] activateAlertItem:self];
94}
95
96static void MSAlert() {
97 if ($SafeModeAlertItem == nil)
98 $SafeModeAlertItem = objc_lookUpClass("SafeModeAlertItem");
99 if ($SafeModeAlertItem == nil) {
100 $SafeModeAlertItem = objc_allocateClassPair(objc_getClass("SBAlertItem"), "SafeModeAlertItem", 0);
101 if ($SafeModeAlertItem == nil)
102 return;
103
104 class_addMethod($SafeModeAlertItem, @selector(alertSheet:buttonClicked:), (IMP) &SafeModeAlertItem$alertSheet$buttonClicked$, "v@:@i");
105 class_addMethod($SafeModeAlertItem, @selector(configure:requirePasscodeForActions:), (IMP) &SafeModeAlertItem$configure$requirePasscodeForActions$, "v@:cc");
106 class_addMethod($SafeModeAlertItem, @selector(performUnlockAction), (IMP) SafeModeAlertItem$performUnlockAction, "v@:");
107 objc_registerClassPair($SafeModeAlertItem);
108 }
109
110 if ($SBAlertItemsController != nil)
a938d168 111 [[$SBAlertItemsController sharedInstance] activateAlertItem:[[[$SafeModeAlertItem alloc] init] autorelease]];
39f17851
JF
112}
113
b4f9ed46
JF
114MSHook(void, SBStatusBar$touchesEnded$withEvent$, SBStatusBar *self, SEL sel, id touches, id event) {
115 MSAlert();
116 _SBStatusBar$touchesEnded$withEvent$(self, sel, touches, event);
117}
118
88d77501 119MSHook(void, SBStatusBar$mouseDown$, SBStatusBar *self, SEL sel, void *event) {
39f17851
JF
120 MSAlert();
121 _SBStatusBar$mouseDown$(self, sel, event);
122}
123
e5a54d69
JF
124MSHook(void, UIStatusBar$touchesBegan$withEvent$, id self, SEL sel, void *arg0, void *arg1) {
125 MSAlert();
126 _UIStatusBar$touchesBegan$withEvent$(self, sel, arg0, arg1);
127}
128
129MSHook(void, SBStatusBarDataManager$_updateTimeString, id self, SEL sel) {
130 if (char *_data = &MSHookIvar<char>(self, "_data")) {
131 char *timeString(_data + 20);
132 strcpy(timeString, "Exit Safe Mode");
133 }
134}
135
39f17851 136static void SBIconController$showInfoAlertIfNeeded(id self, SEL sel) {
25f84761 137 static bool loaded = false;
39f17851
JF
138 if (loaded)
139 return;
140 loaded = true;
141 MSAlert();
25f84761
JF
142}
143
b4f9ed46 144MSHook(int, SBButtonBar$maxIconColumns, SBButtonBar *self, SEL sel) {
25f84761
JF
145 static int max;
146 if (max == 0) {
b4f9ed46 147 max = _SBButtonBar$maxIconColumns(self, sel);
25f84761
JF
148 if (NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults])
149 if (NSDictionary *iconState = [defaults objectForKey:@"iconState"])
150 if (NSDictionary *buttonBar = [iconState objectForKey:@"buttonBar"])
151 if (NSArray *iconMatrix = [buttonBar objectForKey:@"iconMatrix"])
152 if ([iconMatrix count] != 0)
153 if (NSArray *row = [iconMatrix objectAtIndex:0]) {
154 int count([row count]);
155 if (max < count)
156 max = count;
157 }
158 } return max;
159}
160
b4f9ed46
JF
161MSHook(id, SBUIController$init, SBUIController *self, SEL sel) {
162 if ((self = _SBUIController$init(self, sel)) != nil) {
163 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
164 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
165
166 UIView *layer;
167 if (&_contentLayer != NULL)
168 layer = _contentLayer;
169 else if (&_contentView != NULL)
170 layer = _contentView;
171 else
172 layer = nil;
173
174 if (layer != nil)
175 [layer setBackgroundColor:[UIColor darkGrayColor]];
176 } return self;
25f84761
JF
177}
178
1c74ea29 179#define Paper_ "/Library/MobileSubstrate/MobileSafety.png"
dbbe0f32
JF
180
181MSHook(UIImage *, UIImage$defaultDesktopImage, UIImage *self, SEL sel) {
182 return [UIImage imageWithContentsOfFile:@Paper_];
183}
184
39f17851
JF
185MSHook(void, SBStatusBarTimeView$tile, SBStatusBarTimeView *self, SEL sel) {
186 NSString *&_time(MSHookIvar<NSString *>(self, "_time"));
187 CGRect &_textRect(MSHookIvar<CGRect>(self, "_textRect"));
25f84761 188 if (_time != nil)
39f17851 189 [_time release];
dbbe0f32 190 _time = [@"Exit Safe Mode" retain];
2c75d26c 191 id font([self textFont]);
88d77501 192 CGSize size([_time sizeWithFont:font]);
39f17851 193 CGRect frame([self frame]);
39f17851
JF
194 _textRect.size = size;
195 _textRect.origin.x = (frame.size.width - size.width) / 2;
196 _textRect.origin.y = (frame.size.height - size.height) / 2;
25f84761
JF
197}
198
199#define Dylib_ "/Library/MobileSubstrate/MobileSubstrate.dylib"
200
63918068 201MSInitialize {
10586051
JF
202 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
203
25f84761
JF
204 NSLog(@"MS:Warning: Entering Safe Mode");
205
b4f9ed46
JF
206 _SBButtonBar$maxIconColumns = MSHookMessage(objc_getClass("SBButtonBar"), @selector(maxIconColumns), &$SBButtonBar$maxIconColumns);
207 _SBUIController$init = MSHookMessage(objc_getClass("SBUIController"), @selector(init), &$SBUIController$init);
208 _SBStatusBar$touchesEnded$withEvent$ = MSHookMessage(objc_getClass("SBStatusBar"), @selector(touchesEnded:withEvent:), &$SBStatusBar$touchesEnded$withEvent$);
39f17851 209 _SBStatusBar$mouseDown$ = MSHookMessage(objc_getClass("SBStatusBar"), @selector(mouseDown:), &$SBStatusBar$mouseDown$);
e5a54d69 210 _SBStatusBarDataManager$_updateTimeString = MSHookMessage(objc_getClass("SBStatusBarDataManager"), @selector(_updateTimeString), &$SBStatusBarDataManager$_updateTimeString);
39f17851 211 _SBStatusBarTimeView$tile = MSHookMessage(objc_getClass("SBStatusBarTimeView"), @selector(tile), &$SBStatusBarTimeView$tile);
25f84761 212
e5a54d69
JF
213 _UIStatusBar$touchesBegan$withEvent$ = MSHookMessage(objc_getClass("UIStatusBar"), @selector(touchesBegan:withEvent:), &$UIStatusBar$touchesBegan$withEvent$);
214
dbbe0f32 215 _UIImage$defaultDesktopImage = MSHookMessage(object_getClass(objc_getClass("UIImage")), @selector(defaultDesktopImage), &$UIImage$defaultDesktopImage);
dbbe0f32 216
25f84761
JF
217 char *dil = getenv("DYLD_INSERT_LIBRARIES");
218 if (dil == NULL)
219 NSLog(@"MS:Error: DYLD_INSERT_LIBRARIES is unset?");
220 else {
221 NSArray *dylibs([[NSString stringWithUTF8String:dil] componentsSeparatedByString:@":"]);
222 NSUInteger index([dylibs indexOfObject:@ Dylib_]);
223 if (index == NSNotFound)
224 NSLog(@"MS:Error: dylib not in DYLD_INSERT_LIBRARIES?");
225 else if ([dylibs count] == 1)
226 unsetenv("DYLD_INSERT_LIBRARIES");
227 else {
228 NSMutableArray *value([[[NSMutableArray alloc] init] autorelease]);
229 [value setArray:dylibs];
230 [value removeObjectAtIndex:index];
231 setenv("DYLD_INSERT_LIBRARIES", [[value componentsJoinedByString:@":"] UTF8String], !0);
232 }
233 }
234
39f17851
JF
235 $SBAlertItemsController = objc_getClass("SBAlertItemsController");
236
25f84761
JF
237 if (Class _class = objc_getClass("SBIconController")) {
238 SEL sel(@selector(showInfoAlertIfNeeded));
239 if (Method method = class_getInstanceMethod(_class, sel))
39f17851 240 method_setImplementation(method, (IMP) &SBIconController$showInfoAlertIfNeeded);
25f84761 241 }
10586051
JF
242
243 [pool release];
25f84761 244}