]> git.saurik.com Git - safemode-ios.git/blob - MobileSafety.mm
a1d93cc84a0d35b91fd725e2a11fcb5b1244fc99
[safemode-ios.git] / MobileSafety.mm
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
29 MSClassHook(UIStatusBar)
30
31 MSClassHook(UIImage)
32 MSMetaClassHook(UIImage)
33
34 MSClassHook(AAAccountManager)
35 MSMetaClassHook(AAAccountManager)
36
37 MSClassHook(SBAlertItemsController)
38 MSClassHook(SBButtonBar)
39 MSClassHook(SBIconController)
40 MSClassHook(SBStatusBar)
41 MSClassHook(SBStatusBarDataManager)
42 MSClassHook(SBStatusBarTimeView)
43 MSClassHook(SBUIController)
44
45 Class $SafeModeAlertItem;
46
47 @interface SBAlertItem : NSObject {
48 }
49 - (UIAlertView *) alertSheet;
50 - (void) dismiss;
51 @end
52
53 @interface SBAlertItemsController : NSObject {
54 }
55 + (SBAlertItemsController *) sharedInstance;
56 - (void) activateAlertItem:(SBAlertItem *)item;
57 @end
58
59 @interface SBStatusBarTimeView : UIView {
60 }
61 - (id) textFont;
62 @end
63
64 @interface UIApplication (CydiaSubstrate)
65 - (void) applicationOpenURL:(id)url;
66 @end
67
68 @interface UIAlertView (CydiaSubstrate)
69 - (void) setForceHorizontalButtonsLayout:(BOOL)force;
70 - (void) setBodyText:(NSString *)body;
71 - (void) setNumberOfRows:(NSInteger)rows;
72 @end
73
74 void SafeModeAlertItem$alertSheet$buttonClicked$(id self, SEL sel, id sheet, int button) {
75 switch (button) {
76 case 1:
77 break;
78
79 case 2:
80 exit(0);
81 break;
82
83 case 3:
84 [[UIApplication sharedApplication] applicationOpenURL:[NSURL URLWithString:@"http://cydia.saurik.com/safemode/"]];
85 break;
86 }
87
88 [self dismiss];
89 }
90
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];
101 }
102
103 void SafeModeAlertItem$performUnlockAction(id self, SEL sel) {
104 [[$SBAlertItemsController sharedInstance] activateAlertItem:self];
105 }
106
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)
113 return;
114
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);
119 }
120
121 if ($SBAlertItemsController != nil)
122 [[$SBAlertItemsController sharedInstance] activateAlertItem:[[[$SafeModeAlertItem alloc] init] autorelease]];
123 }
124
125 MSInstanceMessageHook2(void, SBStatusBar, touchesEnded,withEvent, id, touches, id, event) {
126 MSAlert();
127 MSOldCall(touches, event);
128 }
129
130 MSInstanceMessageHook1(void, SBStatusBar, mouseDown, void *, event) {
131 MSAlert();
132 MSOldCall(event);
133 }
134
135 MSInstanceMessageHook2(void, UIStatusBar, touchesBegan,withEvent, void *, touches, void *, event) {
136 MSAlert();
137 MSOldCall(touches, event);
138 }
139
140 MSInstanceMessageHook0(void, SBStatusBarDataManager, _updateTimeString) {
141 char *_data(&MSHookIvar<char>(self, "_data"));
142 if (_data == NULL)
143 return;
144
145 Ivar _itemIsEnabled(object_getInstanceVariable(self, "_itemIsEnabled", NULL));
146 if (_itemIsEnabled == NULL)
147 return;
148
149 Ivar _itemIsCloaked(object_getInstanceVariable(self, "_itemIsCloaked", NULL));
150 if (_itemIsCloaked == NULL)
151 return;
152
153 size_t enabledOffset(ivar_getOffset(_itemIsEnabled));
154 size_t cloakedOffset(ivar_getOffset(_itemIsCloaked));
155 if (enabledOffset >= cloakedOffset)
156 return;
157
158 size_t offset(cloakedOffset - enabledOffset);
159 char *timeString(_data + offset);
160 strcpy(timeString, "Exit Safe Mode");
161 }
162
163 static bool alerted_;
164
165 static void AlertIfNeeded() {
166 if (alerted_)
167 return;
168 alerted_ = true;
169 MSAlert();
170 }
171
172 MSClassMessageHook0(void, AAAccountManager, showMobileMeOfferIfNecessary) {
173 AlertIfNeeded();
174 }
175
176 MSInstanceMessageHook0(void, SBIconController, showInfoAlertIfNeeded) {
177 AlertIfNeeded();
178 }
179
180 MSInstanceMessageHook0(int, SBButtonBar, maxIconColumns) {
181 static int max;
182 if (max == 0) {
183 max = MSOldCall();
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]);
191 if (max < count)
192 max = count;
193 }
194 } return max;
195 }
196
197 MSInstanceMessageHook0(id, SBUIController, init) {
198 if ((self = MSOldCall()) != nil) {
199 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
200 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
201
202 UIView *layer;
203 if (&_contentLayer != NULL)
204 layer = _contentLayer;
205 else if (&_contentView != NULL)
206 layer = _contentView;
207 else
208 layer = nil;
209
210 if (layer != nil)
211 [layer setBackgroundColor:[UIColor darkGrayColor]];
212 } return self;
213 }
214
215 #define Paper_ "/Library/MobileSubstrate/MobileSafety.png"
216
217 MSClassMessageHook0(UIImage *, UIImage, defaultDesktopImage) {
218 return [UIImage imageWithContentsOfFile:@Paper_];
219 }
220
221 MSInstanceMessageHook0(void, SBStatusBarTimeView, tile) {
222 NSString *&_time(MSHookIvar<NSString *>(self, "_time"));
223 CGRect &_textRect(MSHookIvar<CGRect>(self, "_textRect"));
224 if (_time != nil)
225 [_time release];
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;
233 }
234
235 #define Dylib_ "/Library/MobileSubstrate/MobileSubstrate.dylib"
236
237 MSInitialize {
238 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
239
240 NSLog(@"MS:Warning: Entering Safe Mode");
241
242 char *dil(getenv("DYLD_INSERT_LIBRARIES"));
243 if (dil == NULL)
244 NSLog(@"MS:Error: DYLD_INSERT_LIBRARIES is unset?");
245 else {
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");
252 else {
253 NSMutableArray *value([[[NSMutableArray alloc] init] autorelease]);
254 [value setArray:dylibs];
255 [value removeObjectAtIndex:index];
256 setenv("DYLD_INSERT_LIBRARIES", [[value componentsJoinedByString:@":"] UTF8String], !0);
257 }
258 }
259
260 [pool release];
261 }