]> git.saurik.com Git - safemode-ios.git/blame_incremental - MobileSafety.mm
Fix the 'it Safe Mode' bug on 4.2+. (chpwn)
[safemode-ios.git] / MobileSafety.mm
... / ...
CommitLineData
1/* Cydia Substrate - Powerful Code Insertion Platform
2 * Copyright (C) 2008-2011 Jay Freeman (saurik)
3*/
4
5/* GNU Lesser General Public License, Version 3 {{{ */
6/*
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.
11 *
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.
16 *
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/>.
19**/
20/* }}} */
21
22#import <CoreFoundation/CoreFoundation.h>
23#import <Foundation/Foundation.h>
24#import <CoreGraphics/CGGeometry.h>
25#import <UIKit/UIKit.h>
26
27#include "CydiaSubstrate.h"
28
29MSClassHook(UIStatusBar)
30
31MSClassHook(UIImage)
32MSMetaClassHook(UIImage)
33
34MSClassHook(SBAlertItemsController)
35MSClassHook(SBButtonBar)
36MSClassHook(SBStatusBar)
37MSClassHook(SBStatusBarDataManager)
38MSClassHook(SBStatusBarTimeView)
39MSClassHook(SBUIController)
40
41Class $SafeModeAlertItem;
42
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
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
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:
80 [[UIApplication sharedApplication] applicationOpenURL:[NSURL URLWithString:@"http://cydia.saurik.com/safemode/"]];
81 break;
82 }
83
84 [self dismiss];
85}
86
87void 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];
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)
118 [[$SBAlertItemsController sharedInstance] activateAlertItem:[[[$SafeModeAlertItem alloc] init] autorelease]];
119}
120
121MSInstanceMessageHook2(void, SBStatusBar, touchesEnded,withEvent, id, touches, id, event) {
122 MSAlert();
123 MSOldCall(touches, event);
124}
125
126MSInstanceMessageHook1(void, SBStatusBar, mouseDown, void *, event) {
127 MSAlert();
128 MSOldCall(event);
129}
130
131MSInstanceMessageHook2(void, UIStatusBar, touchesBegan,withEvent, void *, touches, void *, event) {
132 MSAlert();
133 MSOldCall(touches, event);
134}
135
136MSInstanceMessageHook0(void, SBStatusBarDataManager, _updateTimeString) {
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");
157}
158
159static void SBIconController$showInfoAlertIfNeeded(id self, SEL sel) {
160 static bool loaded = false;
161 if (loaded)
162 return;
163 loaded = true;
164 MSAlert();
165}
166
167MSInstanceMessageHook0(int, SBButtonBar, maxIconColumns) {
168 static int max;
169 if (max == 0) {
170 max = MSOldCall();
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
184MSInstanceMessageHook0(id, SBUIController, init) {
185 if ((self = MSOldCall()) != nil) {
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;
200}
201
202#define Paper_ "/Library/MobileSubstrate/MobileSafety.png"
203
204MSClassMessageHook0(UIImage *, UIImage, defaultDesktopImage) {
205 return [UIImage imageWithContentsOfFile:@Paper_];
206}
207
208MSInstanceMessageHook0(void, SBStatusBarTimeView, tile) {
209 NSString *&_time(MSHookIvar<NSString *>(self, "_time"));
210 CGRect &_textRect(MSHookIvar<CGRect>(self, "_textRect"));
211 if (_time != nil)
212 [_time release];
213 _time = [@"Exit Safe Mode" retain];
214 id font([self textFont]);
215 CGSize size([_time sizeWithFont:font]);
216 CGRect frame([self frame]);
217 _textRect.size = size;
218 _textRect.origin.x = (frame.size.width - size.width) / 2;
219 _textRect.origin.y = (frame.size.height - size.height) / 2;
220}
221
222#define Dylib_ "/Library/MobileSubstrate/MobileSubstrate.dylib"
223
224MSInitialize {
225 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
226
227 NSLog(@"MS:Warning: Entering Safe Mode");
228
229 char *dil(getenv("DYLD_INSERT_LIBRARIES"));
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
247 $SBAlertItemsController = objc_getClass("SBAlertItemsController");
248
249 if (Class _class = objc_getClass("SBIconController")) {
250 SEL sel(@selector(showInfoAlertIfNeeded));
251 if (Method method = class_getInstanceMethod(_class, sel))
252 method_setImplementation(method, (IMP) &SBIconController$showInfoAlertIfNeeded);
253 }
254
255 [pool release];
256}