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