]> git.saurik.com Git - safemode-ios.git/blob - MobileSafety.mm
Fixed various 3.x bugs.
[safemode-ios.git] / MobileSafety.mm
1 /* Cydia Substrate - Meta-Library Insert for iPhoneOS
2 * Copyright (C) 2008-2009 Jay Freeman (saurik)
3 */
4
5 /*
6 * Redistribution and use in source and binary
7 * forms, with or without modification, are permitted
8 * provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the
11 * above copyright notice, this list of conditions
12 * and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the
14 * above copyright notice, this list of conditions
15 * and the following disclaimer in the documentation
16 * and/or other materials provided with the
17 * distribution.
18 * 3. The name of the author may not be used to endorse
19 * or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS''
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
24 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
33 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
35 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37
38 #import <CoreFoundation/CoreFoundation.h>
39 #import <Foundation/Foundation.h>
40 #import <CoreGraphics/CGGeometry.h>
41 #import <UIKit/UIKit.h>
42
43 #import <SpringBoard/SBAlertItem.h>
44 #import <SpringBoard/SBAlertItemsController.h>
45 #import <SpringBoard/SBButtonBar.h>
46 #import <SpringBoard/SBStatusBarController.h>
47 #import <SpringBoard/SBStatusBarTimeView.h>
48 #import <SpringBoard/SBUIController.h>
49
50 #include <substrate.h>
51
52 Class $SafeModeAlertItem;
53 Class $SBAlertItemsController;
54
55 void SafeModeAlertItem$alertSheet$buttonClicked$(id self, SEL sel, id sheet, int button) {
56 switch (button) {
57 case 1:
58 break;
59
60 case 2:
61 exit(0);
62 break;
63
64 case 3:
65 [UIApp applicationOpenURL:[NSURL URLWithString:@"http://cydia.saurik.com/safemode/"]];
66 break;
67 }
68
69 [self dismiss];
70 }
71
72 void SafeModeAlertItem$configure$requirePasscodeForActions$(id self, SEL sel, BOOL configure, BOOL require) {
73 UIModalView *sheet([self alertSheet]);
74 [sheet setDelegate:self];
75 [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."];
76 [sheet addButtonWithTitle:@"OK"];
77 [sheet addButtonWithTitle:@"Restart"];
78 [sheet addButtonWithTitle:@"Help"];
79 [sheet setNumberOfRows:1];
80 }
81
82 void SafeModeAlertItem$performUnlockAction(id self, SEL sel) {
83 [[$SBAlertItemsController sharedInstance] activateAlertItem:self];
84 }
85
86 static void MSAlert() {
87 if ($SafeModeAlertItem == nil)
88 $SafeModeAlertItem = objc_lookUpClass("SafeModeAlertItem");
89 if ($SafeModeAlertItem == nil) {
90 $SafeModeAlertItem = objc_allocateClassPair(objc_getClass("SBAlertItem"), "SafeModeAlertItem", 0);
91 if ($SafeModeAlertItem == nil)
92 return;
93
94 class_addMethod($SafeModeAlertItem, @selector(alertSheet:buttonClicked:), (IMP) &SafeModeAlertItem$alertSheet$buttonClicked$, "v@:@i");
95 class_addMethod($SafeModeAlertItem, @selector(configure:requirePasscodeForActions:), (IMP) &SafeModeAlertItem$configure$requirePasscodeForActions$, "v@:cc");
96 class_addMethod($SafeModeAlertItem, @selector(performUnlockAction), (IMP) SafeModeAlertItem$performUnlockAction, "v@:");
97 objc_registerClassPair($SafeModeAlertItem);
98 }
99
100 if ($SBAlertItemsController != nil)
101 [[$SBAlertItemsController sharedInstance] activateAlertItem:[[$SafeModeAlertItem alloc] init]];
102 }
103
104 MSHook(void, SBStatusBar$touchesEnded$withEvent$, SBStatusBar *self, SEL sel, id touches, id event) {
105 MSAlert();
106 _SBStatusBar$touchesEnded$withEvent$(self, sel, touches, event);
107 }
108
109 MSHook(void, SBStatusBar$mouseDown$, SBStatusBar *self, SEL sel, GSEventRef event) {
110 MSAlert();
111 _SBStatusBar$mouseDown$(self, sel, event);
112 }
113
114 static void SBIconController$showInfoAlertIfNeeded(id self, SEL sel) {
115 static bool loaded = false;
116 if (loaded)
117 return;
118 loaded = true;
119 MSAlert();
120 }
121
122 MSHook(int, SBButtonBar$maxIconColumns, SBButtonBar *self, SEL sel) {
123 static int max;
124 if (max == 0) {
125 max = _SBButtonBar$maxIconColumns(self, sel);
126 if (NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults])
127 if (NSDictionary *iconState = [defaults objectForKey:@"iconState"])
128 if (NSDictionary *buttonBar = [iconState objectForKey:@"buttonBar"])
129 if (NSArray *iconMatrix = [buttonBar objectForKey:@"iconMatrix"])
130 if ([iconMatrix count] != 0)
131 if (NSArray *row = [iconMatrix objectAtIndex:0]) {
132 int count([row count]);
133 if (max < count)
134 max = count;
135 }
136 } return max;
137 }
138
139 MSHook(id, SBUIController$init, SBUIController *self, SEL sel) {
140 if ((self = _SBUIController$init(self, sel)) != nil) {
141 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
142 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
143
144 UIView *layer;
145 if (&_contentLayer != NULL)
146 layer = _contentLayer;
147 else if (&_contentView != NULL)
148 layer = _contentView;
149 else
150 layer = nil;
151
152 if (layer != nil)
153 [layer setBackgroundColor:[UIColor darkGrayColor]];
154 } return self;
155 }
156
157 #define Paper_ "/Library/MobileSubstrate/MobilePaper.png"
158
159 MSHook(UIImage *, UIImage$defaultDesktopImage, UIImage *self, SEL sel) {
160 return [UIImage imageWithContentsOfFile:@Paper_];
161 }
162
163 MSHook(void, SBStatusBarTimeView$tile, SBStatusBarTimeView *self, SEL sel) {
164 NSString *&_time(MSHookIvar<NSString *>(self, "_time"));
165 CGRect &_textRect(MSHookIvar<CGRect>(self, "_textRect"));
166 if (_time != nil)
167 [_time release];
168 _time = [@"Exit Safe Mode" retain];
169 GSFontRef font([self textFont]);
170 CGSize size([_time sizeWithFont:(id)font]);
171 CGRect frame([self frame]);
172 _textRect.size = size;
173 _textRect.origin.x = (frame.size.width - size.width) / 2;
174 _textRect.origin.y = (frame.size.height - size.height) / 2;
175 }
176
177 #define Dylib_ "/Library/MobileSubstrate/MobileSubstrate.dylib"
178
179 extern "C" void MSInitialize() {
180 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
181
182 NSLog(@"MS:Warning: Entering Safe Mode");
183
184 _SBButtonBar$maxIconColumns = MSHookMessage(objc_getClass("SBButtonBar"), @selector(maxIconColumns), &$SBButtonBar$maxIconColumns);
185 _SBUIController$init = MSHookMessage(objc_getClass("SBUIController"), @selector(init), &$SBUIController$init);
186 _SBStatusBar$touchesEnded$withEvent$ = MSHookMessage(objc_getClass("SBStatusBar"), @selector(touchesEnded:withEvent:), &$SBStatusBar$touchesEnded$withEvent$);
187 _SBStatusBar$mouseDown$ = MSHookMessage(objc_getClass("SBStatusBar"), @selector(mouseDown:), &$SBStatusBar$mouseDown$);
188 _SBStatusBarTimeView$tile = MSHookMessage(objc_getClass("SBStatusBarTimeView"), @selector(tile), &$SBStatusBarTimeView$tile);
189
190 _UIImage$defaultDesktopImage = MSHookMessage(object_getClass(objc_getClass("UIImage")), @selector(defaultDesktopImage), &$UIImage$defaultDesktopImage);
191
192 char *dil = getenv("DYLD_INSERT_LIBRARIES");
193 if (dil == NULL)
194 NSLog(@"MS:Error: DYLD_INSERT_LIBRARIES is unset?");
195 else {
196 NSArray *dylibs([[NSString stringWithUTF8String:dil] componentsSeparatedByString:@":"]);
197 NSUInteger index([dylibs indexOfObject:@ Dylib_]);
198 if (index == NSNotFound)
199 NSLog(@"MS:Error: dylib not in DYLD_INSERT_LIBRARIES?");
200 else if ([dylibs count] == 1)
201 unsetenv("DYLD_INSERT_LIBRARIES");
202 else {
203 NSMutableArray *value([[[NSMutableArray alloc] init] autorelease]);
204 [value setArray:dylibs];
205 [value removeObjectAtIndex:index];
206 setenv("DYLD_INSERT_LIBRARIES", [[value componentsJoinedByString:@":"] UTF8String], !0);
207 }
208 }
209
210 $SBAlertItemsController = objc_getClass("SBAlertItemsController");
211
212 if (Class _class = objc_getClass("SBIconController")) {
213 SEL sel(@selector(showInfoAlertIfNeeded));
214 if (Method method = class_getInstanceMethod(_class, sel))
215 method_setImplementation(method, (IMP) &SBIconController$showInfoAlertIfNeeded);
216 }
217
218 [pool release];
219 }