]> git.saurik.com Git - safemode-ios.git/blob - MobileSafety.mm
Checkpointing thumb details.
[safemode-ios.git] / MobileSafety.mm
1 /* Cydia Substrate - Meta-Library Insert for iPhoneOS
2 * Copyright (C) 2008 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/SBContentLayer.h>
46 #import <SpringBoard/SBStatusBarController.h>
47 #import <SpringBoard/SBStatusBarTimeView.h>
48
49 #import <SpringBoard/SBSlidingAlertDisplay.h>
50
51 #include <substrate.h>
52
53 @protocol MobileSubstrate
54 - (id) ms$initWithSize:(CGSize)size;
55 - (int) ms$maxIconColumns;
56 @end
57
58 Class $SafeModeAlertItem;
59 Class $SBAlertItemsController;
60
61 void SafeModeAlertItem$alertSheet$buttonClicked$(id self, SEL sel, id sheet, int button) {
62 switch (button) {
63 case 1:
64 break;
65
66 case 2:
67 exit(0);
68 break;
69
70 case 3:
71 [UIApp applicationOpenURL:[NSURL URLWithString:@"http://cydia.saurik.com/safemode/"] asPanel:NO];
72 break;
73 }
74
75 [self dismiss];
76 }
77
78 void SafeModeAlertItem$configure$requirePasscodeForActions$(id self, SEL sel, BOOL configure, BOOL require) {
79 UIModalView *sheet([self alertSheet]);
80 [sheet setDelegate:self];
81 [sheet setBodyText:@"We apologize for the inconvenience, but SpringBoard has just crashed.\n\nA recent software installation, upgrade, or removal might have been the cause of this.\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."];
82 [sheet addButtonWithTitle:@"OK"];
83 [sheet addButtonWithTitle:@"Restart"];
84 [sheet addButtonWithTitle:@"Help"];
85 [sheet setNumberOfRows:1];
86 }
87
88 void SafeModeAlertItem$performUnlockAction(id self, SEL sel) {
89 [[$SBAlertItemsController sharedInstance] activateAlertItem:self];
90 }
91
92 static void MSAlert() {
93 if ($SafeModeAlertItem == nil)
94 $SafeModeAlertItem = objc_lookUpClass("SafeModeAlertItem");
95 if ($SafeModeAlertItem == nil) {
96 $SafeModeAlertItem = objc_allocateClassPair(objc_getClass("SBAlertItem"), "SafeModeAlertItem", 0);
97 if ($SafeModeAlertItem == nil)
98 return;
99
100 class_addMethod($SafeModeAlertItem, @selector(alertSheet:buttonClicked:), (IMP) &SafeModeAlertItem$alertSheet$buttonClicked$, "v@:@i");
101 class_addMethod($SafeModeAlertItem, @selector(configure:requirePasscodeForActions:), (IMP) &SafeModeAlertItem$configure$requirePasscodeForActions$, "v@:cc");
102 class_addMethod($SafeModeAlertItem, @selector(performUnlockAction), (IMP) SafeModeAlertItem$performUnlockAction, "v@:");
103 objc_registerClassPair($SafeModeAlertItem);
104 }
105
106 if ($SBAlertItemsController != nil)
107 [[$SBAlertItemsController sharedInstance] activateAlertItem:[[$SafeModeAlertItem alloc] init]];
108 }
109
110 MSHook(void, SBStatusBar$mouseDown$, SBStatusBar *self, SEL sel, GSEventRef event) {
111 MSAlert();
112 _SBStatusBar$mouseDown$(self, sel, event);
113 }
114
115 static void SBIconController$showInfoAlertIfNeeded(id self, SEL sel) {
116 static bool loaded = false;
117 if (loaded)
118 return;
119 loaded = true;
120 MSAlert();
121 }
122
123 static int SBButtonBar$maxIconColumns(id<MobileSubstrate> self, SEL sel) {
124 static int max;
125 if (max == 0) {
126 max = [self ms$maxIconColumns];
127 if (NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults])
128 if (NSDictionary *iconState = [defaults objectForKey:@"iconState"])
129 if (NSDictionary *buttonBar = [iconState objectForKey:@"buttonBar"])
130 if (NSArray *iconMatrix = [buttonBar objectForKey:@"iconMatrix"])
131 if ([iconMatrix count] != 0)
132 if (NSArray *row = [iconMatrix objectAtIndex:0]) {
133 int count([row count]);
134 if (max < count)
135 max = count;
136 }
137 } return max;
138 }
139
140 static id SBContentLayer$initWithSize$(SBContentLayer<MobileSubstrate> *self, SEL sel, CGSize size) {
141 self = [self ms$initWithSize:size];
142 if (self == nil)
143 return nil;
144 [self setBackgroundColor:[UIColor darkGrayColor]];
145 return self;
146 }
147
148 /*MSHook(void, SBSlidingAlertDisplay$updateDesktopImage$, SBSlidingAlertDisplay *self, SEL sel, UIImage *image) {
149 NSString *text(@"\"Sad iPhone\" by Geoff Stearns");
150 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
151 if (_backgroundView != nil)
152 text = nil;
153 _SBSlidingAlertDisplay$updateDesktopImage$(self, sel, image);
154 if (text != nil) {
155 UIFont *font([UIFont systemFontOfSize:12]);
156 CGRect rect([self frame]);
157 CGSize size([text sizeWithFont:font]);
158 rect.origin.y = 385 - 3 - 14;//size.height;
159 rect.size.height = size.height;
160
161 UITextView *view([[UITextView alloc] initWithFrame:rect]);
162 [view setTextAlignment:UITextAlignmentCenter];
163 [view setMarginTop:0];
164 [view setFont:font];
165 [view setText:text];
166 [view setTextColor:[UIColor grayColor]];
167 [view setBackgroundColor:[UIColor clearColor]];
168
169 [self insertSubview:view aboveSubview:_backgroundView];
170 }
171 }*/
172
173 #define Paper_ "/Library/MobileSubstrate/MobilePaper.png"
174
175 MSHook(UIImage *, UIImage$defaultDesktopImage, UIImage *self, SEL sel) {
176 return [UIImage imageWithContentsOfFile:@Paper_];
177 }
178
179 MSHook(void, SBStatusBarTimeView$tile, SBStatusBarTimeView *self, SEL sel) {
180 NSString *&_time(MSHookIvar<NSString *>(self, "_time"));
181 CGRect &_textRect(MSHookIvar<CGRect>(self, "_textRect"));
182 if (_time != nil)
183 [_time release];
184 _time = [@"Exit Safe Mode" retain];
185 GSFontRef font([self textFont]);
186 CGSize size([_time sizeWithFont:(id)font]);
187 CGRect frame([self frame]);
188 _textRect.size = size;
189 _textRect.origin.x = (frame.size.width - size.width) / 2;
190 _textRect.origin.y = (frame.size.height - size.height) / 2;
191 }
192
193 #define Dylib_ "/Library/MobileSubstrate/MobileSubstrate.dylib"
194
195 extern "C" void MSInitialize() {
196 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
197
198 NSLog(@"MS:Warning: Entering Safe Mode");
199
200 MSHookMessage(objc_getClass("SBButtonBar"), @selector(maxIconColumns), (IMP) &SBButtonBar$maxIconColumns, "ms$");
201 MSHookMessage(objc_getClass("SBContentLayer"), @selector(initWithSize:), (IMP) &SBContentLayer$initWithSize$, "ms$");
202 _SBStatusBar$mouseDown$ = MSHookMessage(objc_getClass("SBStatusBar"), @selector(mouseDown:), &$SBStatusBar$mouseDown$);
203 _SBStatusBarTimeView$tile = MSHookMessage(objc_getClass("SBStatusBarTimeView"), @selector(tile), &$SBStatusBarTimeView$tile);
204
205 _UIImage$defaultDesktopImage = MSHookMessage(object_getClass(objc_getClass("UIImage")), @selector(defaultDesktopImage), &$UIImage$defaultDesktopImage);
206 //_SBSlidingAlertDisplay$updateDesktopImage$ = MSHookMessage(objc_getClass("SBSlidingAlertDisplay"), @selector(updateDesktopImage:), &$SBSlidingAlertDisplay$updateDesktopImage$);
207
208 char *dil = getenv("DYLD_INSERT_LIBRARIES");
209 if (dil == NULL)
210 NSLog(@"MS:Error: DYLD_INSERT_LIBRARIES is unset?");
211 else {
212 NSArray *dylibs([[NSString stringWithUTF8String:dil] componentsSeparatedByString:@":"]);
213 NSUInteger index([dylibs indexOfObject:@ Dylib_]);
214 if (index == NSNotFound)
215 NSLog(@"MS:Error: dylib not in DYLD_INSERT_LIBRARIES?");
216 else if ([dylibs count] == 1)
217 unsetenv("DYLD_INSERT_LIBRARIES");
218 else {
219 NSMutableArray *value([[[NSMutableArray alloc] init] autorelease]);
220 [value setArray:dylibs];
221 [value removeObjectAtIndex:index];
222 setenv("DYLD_INSERT_LIBRARIES", [[value componentsJoinedByString:@":"] UTF8String], !0);
223 }
224 }
225
226 $SBAlertItemsController = objc_getClass("SBAlertItemsController");
227
228 if (Class _class = objc_getClass("SBIconController")) {
229 SEL sel(@selector(showInfoAlertIfNeeded));
230 if (Method method = class_getInstanceMethod(_class, sel))
231 method_setImplementation(method, (IMP) &SBIconController$showInfoAlertIfNeeded);
232 }
233
234 [pool release];
235 }