]> git.saurik.com Git - safemode-ios.git/blob - MobileSafety.mm
Completely redid Mobile Safe Mode, added MobileUnions (unreleased), and performed...
[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 #include <substrate.h>
50
51 @protocol MobileSubstrate
52 - (id) ms$initWithSize:(CGSize)size;
53 - (int) ms$maxIconColumns;
54 @end
55
56 Class $SafeModeAlertItem;
57 Class $SBAlertItemsController;
58
59 void SafeModeAlertItem$alertSheet$buttonClicked$(id self, SEL sel, id sheet, int button) {
60 switch (button) {
61 case 1:
62 break;
63
64 case 2:
65 exit(0);
66 break;
67
68 case 3:
69 [UIApp openURL:[NSURL URLWithString:@"http://cydia.saurik.com/safemode/"]];
70 break;
71 }
72
73 [self dismiss];
74 }
75
76 void SafeModeAlertItem$configure$requirePasscodeForActions$(id self, SEL sel, BOOL configure, BOOL require) {
77 UIModalView *sheet([self alertSheet]);
78 [sheet setDelegate:self];
79 [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."];
80 [sheet addButtonWithTitle:@"OK"];
81 [sheet addButtonWithTitle:@"Restart"];
82 [sheet addButtonWithTitle:@"Help"];
83 [sheet setNumberOfRows:1];
84 }
85
86 void SafeModeAlertItem$performUnlockAction(id self, SEL sel) {
87 [[$SBAlertItemsController sharedInstance] activateAlertItem:self];
88 }
89
90 static void MSAlert() {
91 if ($SafeModeAlertItem == nil)
92 $SafeModeAlertItem = objc_lookUpClass("SafeModeAlertItem");
93 if ($SafeModeAlertItem == nil) {
94 $SafeModeAlertItem = objc_allocateClassPair(objc_getClass("SBAlertItem"), "SafeModeAlertItem", 0);
95 if ($SafeModeAlertItem == nil)
96 return;
97
98 class_addMethod($SafeModeAlertItem, @selector(alertSheet:buttonClicked:), (IMP) &SafeModeAlertItem$alertSheet$buttonClicked$, "v@:@i");
99 class_addMethod($SafeModeAlertItem, @selector(configure:requirePasscodeForActions:), (IMP) &SafeModeAlertItem$configure$requirePasscodeForActions$, "v@:cc");
100 class_addMethod($SafeModeAlertItem, @selector(performUnlockAction), (IMP) SafeModeAlertItem$performUnlockAction, "v@:");
101 objc_registerClassPair($SafeModeAlertItem);
102 }
103
104 if ($SBAlertItemsController != nil)
105 [[$SBAlertItemsController sharedInstance] activateAlertItem:[[$SafeModeAlertItem alloc] init]];
106 }
107
108 MSHook(void, SBStatusBar$mouseDown$, SBStatusBar *self, SEL sel, GSEventRef event) {
109 MSAlert();
110 _SBStatusBar$mouseDown$(self, sel, event);
111 }
112
113 static void SBIconController$showInfoAlertIfNeeded(id self, SEL sel) {
114 static bool loaded = false;
115 if (loaded)
116 return;
117 loaded = true;
118 MSAlert();
119 }
120
121 static int SBButtonBar$maxIconColumns(id<MobileSubstrate> self, SEL sel) {
122 static int max;
123 if (max == 0) {
124 max = [self ms$maxIconColumns];
125 if (NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults])
126 if (NSDictionary *iconState = [defaults objectForKey:@"iconState"])
127 if (NSDictionary *buttonBar = [iconState objectForKey:@"buttonBar"])
128 if (NSArray *iconMatrix = [buttonBar objectForKey:@"iconMatrix"])
129 if ([iconMatrix count] != 0)
130 if (NSArray *row = [iconMatrix objectAtIndex:0]) {
131 int count([row count]);
132 if (max < count)
133 max = count;
134 }
135 } return max;
136 }
137
138 static id SBContentLayer$initWithSize$(SBContentLayer<MobileSubstrate> *self, SEL sel, CGSize size) {
139 self = [self ms$initWithSize:size];
140 if (self == nil)
141 return nil;
142 [self setBackgroundColor:[UIColor darkGrayColor]];
143 return self;
144 }
145
146 MSHook(void, SBStatusBarTimeView$tile, SBStatusBarTimeView *self, SEL sel) {
147 NSString *&_time(MSHookIvar<NSString *>(self, "_time"));
148 CGRect &_textRect(MSHookIvar<CGRect>(self, "_textRect"));
149 if (_time != nil)
150 [_time release];
151 _time = [@"Safe Mode, Click!" retain];
152 GSFontRef font([self textFont]);
153 CGSize size([_time sizeWithFont:(id)font]);
154 CGRect frame([self frame]);
155 NSLog(@"%f:%f,%f:%f:%u", size.height, size.width, frame.size.height, frame.size.width, [[(id) objc_getClass("SBStatusBarController") sharedStatusBarController] statusBarOrientation]);
156 _textRect.size = size;
157 _textRect.origin.x = (frame.size.width - size.width) / 2;
158 _textRect.origin.y = (frame.size.height - size.height) / 2;
159 }
160
161 #define Dylib_ "/Library/MobileSubstrate/MobileSubstrate.dylib"
162
163 extern "C" void MSInitialize() {
164 NSLog(@"MS:Warning: Entering Safe Mode");
165
166 MSHookMessage(objc_getClass("SBButtonBar"), @selector(maxIconColumns), (IMP) &SBButtonBar$maxIconColumns, "ms$");
167 MSHookMessage(objc_getClass("SBContentLayer"), @selector(initWithSize:), (IMP) &SBContentLayer$initWithSize$, "ms$");
168 _SBStatusBar$mouseDown$ = MSHookMessage(objc_getClass("SBStatusBar"), @selector(mouseDown:), &$SBStatusBar$mouseDown$);
169 _SBStatusBarTimeView$tile = MSHookMessage(objc_getClass("SBStatusBarTimeView"), @selector(tile), &$SBStatusBarTimeView$tile);
170
171 char *dil = getenv("DYLD_INSERT_LIBRARIES");
172 if (dil == NULL)
173 NSLog(@"MS:Error: DYLD_INSERT_LIBRARIES is unset?");
174 else {
175 NSArray *dylibs([[NSString stringWithUTF8String:dil] componentsSeparatedByString:@":"]);
176 NSUInteger index([dylibs indexOfObject:@ Dylib_]);
177 if (index == NSNotFound)
178 NSLog(@"MS:Error: dylib not in DYLD_INSERT_LIBRARIES?");
179 else if ([dylibs count] == 1)
180 unsetenv("DYLD_INSERT_LIBRARIES");
181 else {
182 NSMutableArray *value([[[NSMutableArray alloc] init] autorelease]);
183 [value setArray:dylibs];
184 [value removeObjectAtIndex:index];
185 setenv("DYLD_INSERT_LIBRARIES", [[value componentsJoinedByString:@":"] UTF8String], !0);
186 }
187 }
188
189 $SBAlertItemsController = objc_getClass("SBAlertItemsController");
190
191 if (Class _class = objc_getClass("SBIconController")) {
192 SEL sel(@selector(showInfoAlertIfNeeded));
193 if (Method method = class_getInstanceMethod(_class, sel))
194 method_setImplementation(method, (IMP) &SBIconController$showInfoAlertIfNeeded);
195 }
196 }