]> git.saurik.com Git - safemode-ios.git/blame - MobileSafety.mm
Fix the 'it Safe Mode' bug on 4.2+. (chpwn)
[safemode-ios.git] / MobileSafety.mm
CommitLineData
df972f42 1/* Cydia Substrate - Powerful Code Insertion Platform
f66bee76 2 * Copyright (C) 2008-2011 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
d641d519
JF
29MSClassHook(UIStatusBar)
30
31MSClassHook(UIImage)
32MSMetaClassHook(UIImage)
33
34MSClassHook(SBAlertItemsController)
35MSClassHook(SBButtonBar)
36MSClassHook(SBStatusBar)
37MSClassHook(SBStatusBarDataManager)
38MSClassHook(SBStatusBarTimeView)
39MSClassHook(SBUIController)
2c75d26c 40
39f17851 41Class $SafeModeAlertItem;
39f17851 42
2c75d26c
JF
43@interface SBAlertItem : NSObject {
44}
45- (UIAlertView *) alertSheet;
46- (void) dismiss;
47@end
48
49@interface SBAlertItemsController : NSObject {
50}
51+ (SBAlertItemsController *) sharedInstance;
52- (void) activateAlertItem:(SBAlertItem *)item;
53@end
54
55@interface SBStatusBarTimeView : UIView {
56}
57- (id) textFont;
58@end
59
88d77501
JF
60@interface UIApplication (CydiaSubstrate)
61- (void) applicationOpenURL:(id)url;
62@end
63
64@interface UIAlertView (CydiaSubstrate)
65- (void) setForceHorizontalButtonsLayout:(BOOL)force;
66- (void) setBodyText:(NSString *)body;
67- (void) setNumberOfRows:(NSInteger)rows;
68@end
69
39f17851
JF
70void SafeModeAlertItem$alertSheet$buttonClicked$(id self, SEL sel, id sheet, int button) {
71 switch (button) {
72 case 1:
73 break;
74
75 case 2:
76 exit(0);
77 break;
78
79 case 3:
88d77501 80 [[UIApplication sharedApplication] applicationOpenURL:[NSURL URLWithString:@"http://cydia.saurik.com/safemode/"]];
39f17851
JF
81 break;
82 }
83
84 [self dismiss];
85}
86
87void SafeModeAlertItem$configure$requirePasscodeForActions$(id self, SEL sel, BOOL configure, BOOL require) {
2c75d26c 88 UIAlertView *sheet([self alertSheet]);
39f17851 89 [sheet setDelegate:self];
b4f9ed46 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."];
39f17851
JF
91 [sheet addButtonWithTitle:@"OK"];
92 [sheet addButtonWithTitle:@"Restart"];
93 [sheet addButtonWithTitle:@"Help"];
94 [sheet setNumberOfRows:1];
e5a54d69
JF
95 if ([sheet respondsToSelector:@selector(setForceHorizontalButtonsLayout:)])
96 [sheet setForceHorizontalButtonsLayout:YES];
39f17851
JF
97}
98
99void SafeModeAlertItem$performUnlockAction(id self, SEL sel) {
100 [[$SBAlertItemsController sharedInstance] activateAlertItem:self];
101}
102
103static 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)
109 return;
110
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);
115 }
116
117 if ($SBAlertItemsController != nil)
a938d168 118 [[$SBAlertItemsController sharedInstance] activateAlertItem:[[[$SafeModeAlertItem alloc] init] autorelease]];
39f17851
JF
119}
120
d641d519 121MSInstanceMessageHook2(void, SBStatusBar, touchesEnded,withEvent, id, touches, id, event) {
b4f9ed46 122 MSAlert();
d641d519 123 MSOldCall(touches, event);
b4f9ed46
JF
124}
125
d641d519 126MSInstanceMessageHook1(void, SBStatusBar, mouseDown, void *, event) {
39f17851 127 MSAlert();
d641d519 128 MSOldCall(event);
39f17851
JF
129}
130
d641d519 131MSInstanceMessageHook2(void, UIStatusBar, touchesBegan,withEvent, void *, touches, void *, event) {
e5a54d69 132 MSAlert();
d641d519 133 MSOldCall(touches, event);
e5a54d69
JF
134}
135
d641d519 136MSInstanceMessageHook0(void, SBStatusBarDataManager, _updateTimeString) {
22a7ee91
JF
137 char *_data(&MSHookIvar<char>(self, "_data"));
138 if (_data == NULL)
139 return;
140
141 Ivar _itemIsEnabled(object_getInstanceVariable(self, "_itemIsEnabled", NULL));
142 if (_itemIsEnabled == NULL)
143 return;
144
145 Ivar _itemIsCloaked(object_getInstanceVariable(self, "_itemIsCloaked", NULL));
146 if (_itemIsCloaked == NULL)
147 return;
148
149 size_t enabledOffset(ivar_getOffset(_itemIsEnabled));
150 size_t cloakedOffset(ivar_getOffset(_itemIsCloaked));
151 if (enabledOffset >= cloakedOffset)
152 return;
153
154 size_t offset(cloakedOffset - enabledOffset);
155 char *timeString(_data + offset);
156 strcpy(timeString, "Exit Safe Mode");
e5a54d69
JF
157}
158
39f17851 159static void SBIconController$showInfoAlertIfNeeded(id self, SEL sel) {
25f84761 160 static bool loaded = false;
39f17851
JF
161 if (loaded)
162 return;
163 loaded = true;
164 MSAlert();
25f84761
JF
165}
166
d641d519 167MSInstanceMessageHook0(int, SBButtonBar, maxIconColumns) {
25f84761
JF
168 static int max;
169 if (max == 0) {
d641d519 170 max = MSOldCall();
25f84761
JF
171 if (NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults])
172 if (NSDictionary *iconState = [defaults objectForKey:@"iconState"])
173 if (NSDictionary *buttonBar = [iconState objectForKey:@"buttonBar"])
174 if (NSArray *iconMatrix = [buttonBar objectForKey:@"iconMatrix"])
175 if ([iconMatrix count] != 0)
176 if (NSArray *row = [iconMatrix objectAtIndex:0]) {
177 int count([row count]);
178 if (max < count)
179 max = count;
180 }
181 } return max;
182}
183
d641d519
JF
184MSInstanceMessageHook0(id, SBUIController, init) {
185 if ((self = MSOldCall()) != nil) {
b4f9ed46
JF
186 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
187 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
188
189 UIView *layer;
190 if (&_contentLayer != NULL)
191 layer = _contentLayer;
192 else if (&_contentView != NULL)
193 layer = _contentView;
194 else
195 layer = nil;
196
197 if (layer != nil)
198 [layer setBackgroundColor:[UIColor darkGrayColor]];
199 } return self;
25f84761
JF
200}
201
1c74ea29 202#define Paper_ "/Library/MobileSubstrate/MobileSafety.png"
dbbe0f32 203
d641d519 204MSClassMessageHook0(UIImage *, UIImage, defaultDesktopImage) {
dbbe0f32
JF
205 return [UIImage imageWithContentsOfFile:@Paper_];
206}
207
d641d519 208MSInstanceMessageHook0(void, SBStatusBarTimeView, tile) {
39f17851
JF
209 NSString *&_time(MSHookIvar<NSString *>(self, "_time"));
210 CGRect &_textRect(MSHookIvar<CGRect>(self, "_textRect"));
25f84761 211 if (_time != nil)
39f17851 212 [_time release];
dbbe0f32 213 _time = [@"Exit Safe Mode" retain];
2c75d26c 214 id font([self textFont]);
88d77501 215 CGSize size([_time sizeWithFont:font]);
39f17851 216 CGRect frame([self frame]);
39f17851
JF
217 _textRect.size = size;
218 _textRect.origin.x = (frame.size.width - size.width) / 2;
219 _textRect.origin.y = (frame.size.height - size.height) / 2;
25f84761
JF
220}
221
222#define Dylib_ "/Library/MobileSubstrate/MobileSubstrate.dylib"
223
63918068 224MSInitialize {
d641d519 225 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
10586051 226
25f84761
JF
227 NSLog(@"MS:Warning: Entering Safe Mode");
228
d641d519 229 char *dil(getenv("DYLD_INSERT_LIBRARIES"));
25f84761
JF
230 if (dil == NULL)
231 NSLog(@"MS:Error: DYLD_INSERT_LIBRARIES is unset?");
232 else {
233 NSArray *dylibs([[NSString stringWithUTF8String:dil] componentsSeparatedByString:@":"]);
234 NSUInteger index([dylibs indexOfObject:@ Dylib_]);
235 if (index == NSNotFound)
236 NSLog(@"MS:Error: dylib not in DYLD_INSERT_LIBRARIES?");
237 else if ([dylibs count] == 1)
238 unsetenv("DYLD_INSERT_LIBRARIES");
239 else {
240 NSMutableArray *value([[[NSMutableArray alloc] init] autorelease]);
241 [value setArray:dylibs];
242 [value removeObjectAtIndex:index];
243 setenv("DYLD_INSERT_LIBRARIES", [[value componentsJoinedByString:@":"] UTF8String], !0);
244 }
245 }
246
39f17851
JF
247 $SBAlertItemsController = objc_getClass("SBAlertItemsController");
248
25f84761
JF
249 if (Class _class = objc_getClass("SBIconController")) {
250 SEL sel(@selector(showInfoAlertIfNeeded));
251 if (Method method = class_getInstanceMethod(_class, sel))
39f17851 252 method_setImplementation(method, (IMP) &SBIconController$showInfoAlertIfNeeded);
25f84761 253 }
10586051
JF
254
255 [pool release];
25f84761 256}