]>
Commit | Line | Data |
---|---|---|
df972f42 | 1 | /* Cydia Substrate - Powerful Code Insertion Platform |
f66bee76 | 2 | * Copyright (C) 2008-2011 Jay Freeman (saurik) |
25f84761 JF |
3 | */ |
4 | ||
df972f42 | 5 | /* GNU Lesser General Public License, Version 3 {{{ */ |
25f84761 | 6 | /* |
5bb6a76c | 7 | * Substrate is free software: you can redistribute it and/or modify it under |
df972f42 JF |
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. | |
25f84761 | 11 | * |
5bb6a76c | 12 | * Substrate is distributed in the hope that it will be useful, but WITHOUT |
df972f42 JF |
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. | |
25f84761 | 16 | * |
df972f42 | 17 | * You should have received a copy of the GNU Lesser General Public License |
5bb6a76c | 18 | * along with Substrate. If not, see <http://www.gnu.org/licenses/>. |
df972f42 JF |
19 | **/ |
20 | /* }}} */ | |
25f84761 JF |
21 | |
22 | #import <CoreFoundation/CoreFoundation.h> | |
23 | #import <Foundation/Foundation.h> | |
24 | #import <CoreGraphics/CGGeometry.h> | |
39f17851 JF |
25 | #import <UIKit/UIKit.h> |
26 | ||
f6ceb738 | 27 | #include "CydiaSubstrate.h" |
25f84761 | 28 | |
d641d519 JF |
29 | MSClassHook(UIStatusBar) |
30 | ||
31 | MSClassHook(UIImage) | |
32 | MSMetaClassHook(UIImage) | |
33 | ||
34 | MSClassHook(SBAlertItemsController) | |
35 | MSClassHook(SBButtonBar) | |
36 | MSClassHook(SBStatusBar) | |
37 | MSClassHook(SBStatusBarDataManager) | |
38 | MSClassHook(SBStatusBarTimeView) | |
39 | MSClassHook(SBUIController) | |
2c75d26c | 40 | |
39f17851 | 41 | Class $SafeModeAlertItem; |
39f17851 | 42 | |
2c75d26c JF |
43 | @interface SBAlertItem : NSObject { |
44 | } | |
45 | - (UIAlertView *) alertSheet; | |
46 | - (void) dismiss; | |
47 | @end | |
48 | ||
49 | @interface SBAlertItemsController : NSObject { | |
50 | } | |
51 | + (SBAlertItemsController *) sharedInstance; | |
52 | - (void) activateAlertItem:(SBAlertItem *)item; | |
53 | @end | |
54 | ||
55 | @interface SBStatusBarTimeView : UIView { | |
56 | } | |
57 | - (id) textFont; | |
58 | @end | |
59 | ||
88d77501 JF |
60 | @interface UIApplication (CydiaSubstrate) |
61 | - (void) applicationOpenURL:(id)url; | |
62 | @end | |
63 | ||
64 | @interface UIAlertView (CydiaSubstrate) | |
65 | - (void) setForceHorizontalButtonsLayout:(BOOL)force; | |
66 | - (void) setBodyText:(NSString *)body; | |
67 | - (void) setNumberOfRows:(NSInteger)rows; | |
68 | @end | |
69 | ||
39f17851 JF |
70 | void SafeModeAlertItem$alertSheet$buttonClicked$(id self, SEL sel, id sheet, int button) { |
71 | switch (button) { | |
72 | case 1: | |
73 | break; | |
74 | ||
75 | case 2: | |
76 | exit(0); | |
77 | break; | |
78 | ||
79 | case 3: | |
88d77501 | 80 | [[UIApplication sharedApplication] applicationOpenURL:[NSURL URLWithString:@"http://cydia.saurik.com/safemode/"]]; |
39f17851 JF |
81 | break; |
82 | } | |
83 | ||
84 | [self dismiss]; | |
85 | } | |
86 | ||
87 | void SafeModeAlertItem$configure$requirePasscodeForActions$(id self, SEL sel, BOOL configure, BOOL require) { | |
2c75d26c | 88 | UIAlertView *sheet([self alertSheet]); |
39f17851 | 89 | [sheet setDelegate:self]; |
b4f9ed46 | 90 | [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."]; |
39f17851 JF |
91 | [sheet addButtonWithTitle:@"OK"]; |
92 | [sheet addButtonWithTitle:@"Restart"]; | |
93 | [sheet addButtonWithTitle:@"Help"]; | |
94 | [sheet setNumberOfRows:1]; | |
e5a54d69 JF |
95 | if ([sheet respondsToSelector:@selector(setForceHorizontalButtonsLayout:)]) |
96 | [sheet setForceHorizontalButtonsLayout:YES]; | |
39f17851 JF |
97 | } |
98 | ||
99 | void SafeModeAlertItem$performUnlockAction(id self, SEL sel) { | |
100 | [[$SBAlertItemsController sharedInstance] activateAlertItem:self]; | |
101 | } | |
102 | ||
103 | static void MSAlert() { | |
104 | if ($SafeModeAlertItem == nil) | |
105 | $SafeModeAlertItem = objc_lookUpClass("SafeModeAlertItem"); | |
106 | if ($SafeModeAlertItem == nil) { | |
107 | $SafeModeAlertItem = objc_allocateClassPair(objc_getClass("SBAlertItem"), "SafeModeAlertItem", 0); | |
108 | if ($SafeModeAlertItem == nil) | |
109 | return; | |
110 | ||
111 | class_addMethod($SafeModeAlertItem, @selector(alertSheet:buttonClicked:), (IMP) &SafeModeAlertItem$alertSheet$buttonClicked$, "v@:@i"); | |
112 | class_addMethod($SafeModeAlertItem, @selector(configure:requirePasscodeForActions:), (IMP) &SafeModeAlertItem$configure$requirePasscodeForActions$, "v@:cc"); | |
113 | class_addMethod($SafeModeAlertItem, @selector(performUnlockAction), (IMP) SafeModeAlertItem$performUnlockAction, "v@:"); | |
114 | objc_registerClassPair($SafeModeAlertItem); | |
115 | } | |
116 | ||
117 | if ($SBAlertItemsController != nil) | |
a938d168 | 118 | [[$SBAlertItemsController sharedInstance] activateAlertItem:[[[$SafeModeAlertItem alloc] init] autorelease]]; |
39f17851 JF |
119 | } |
120 | ||
d641d519 | 121 | MSInstanceMessageHook2(void, SBStatusBar, touchesEnded,withEvent, id, touches, id, event) { |
b4f9ed46 | 122 | MSAlert(); |
d641d519 | 123 | MSOldCall(touches, event); |
b4f9ed46 JF |
124 | } |
125 | ||
d641d519 | 126 | MSInstanceMessageHook1(void, SBStatusBar, mouseDown, void *, event) { |
39f17851 | 127 | MSAlert(); |
d641d519 | 128 | MSOldCall(event); |
39f17851 JF |
129 | } |
130 | ||
d641d519 | 131 | MSInstanceMessageHook2(void, UIStatusBar, touchesBegan,withEvent, void *, touches, void *, event) { |
e5a54d69 | 132 | MSAlert(); |
d641d519 | 133 | MSOldCall(touches, event); |
e5a54d69 JF |
134 | } |
135 | ||
d641d519 | 136 | MSInstanceMessageHook0(void, SBStatusBarDataManager, _updateTimeString) { |
22a7ee91 JF |
137 | char *_data(&MSHookIvar<char>(self, "_data")); |
138 | if (_data == NULL) | |
139 | return; | |
140 | ||
141 | Ivar _itemIsEnabled(object_getInstanceVariable(self, "_itemIsEnabled", NULL)); | |
142 | if (_itemIsEnabled == NULL) | |
143 | return; | |
144 | ||
145 | Ivar _itemIsCloaked(object_getInstanceVariable(self, "_itemIsCloaked", NULL)); | |
146 | if (_itemIsCloaked == NULL) | |
147 | return; | |
148 | ||
149 | size_t enabledOffset(ivar_getOffset(_itemIsEnabled)); | |
150 | size_t cloakedOffset(ivar_getOffset(_itemIsCloaked)); | |
151 | if (enabledOffset >= cloakedOffset) | |
152 | return; | |
153 | ||
154 | size_t offset(cloakedOffset - enabledOffset); | |
155 | char *timeString(_data + offset); | |
156 | strcpy(timeString, "Exit Safe Mode"); | |
e5a54d69 JF |
157 | } |
158 | ||
39f17851 | 159 | static void SBIconController$showInfoAlertIfNeeded(id self, SEL sel) { |
25f84761 | 160 | static bool loaded = false; |
39f17851 JF |
161 | if (loaded) |
162 | return; | |
163 | loaded = true; | |
164 | MSAlert(); | |
25f84761 JF |
165 | } |
166 | ||
d641d519 | 167 | MSInstanceMessageHook0(int, SBButtonBar, maxIconColumns) { |
25f84761 JF |
168 | static int max; |
169 | if (max == 0) { | |
d641d519 | 170 | max = MSOldCall(); |
25f84761 JF |
171 | if (NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]) |
172 | if (NSDictionary *iconState = [defaults objectForKey:@"iconState"]) | |
173 | if (NSDictionary *buttonBar = [iconState objectForKey:@"buttonBar"]) | |
174 | if (NSArray *iconMatrix = [buttonBar objectForKey:@"iconMatrix"]) | |
175 | if ([iconMatrix count] != 0) | |
176 | if (NSArray *row = [iconMatrix objectAtIndex:0]) { | |
177 | int count([row count]); | |
178 | if (max < count) | |
179 | max = count; | |
180 | } | |
181 | } return max; | |
182 | } | |
183 | ||
d641d519 JF |
184 | MSInstanceMessageHook0(id, SBUIController, init) { |
185 | if ((self = MSOldCall()) != nil) { | |
b4f9ed46 JF |
186 | UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer")); |
187 | UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView")); | |
188 | ||
189 | UIView *layer; | |
190 | if (&_contentLayer != NULL) | |
191 | layer = _contentLayer; | |
192 | else if (&_contentView != NULL) | |
193 | layer = _contentView; | |
194 | else | |
195 | layer = nil; | |
196 | ||
197 | if (layer != nil) | |
198 | [layer setBackgroundColor:[UIColor darkGrayColor]]; | |
199 | } return self; | |
25f84761 JF |
200 | } |
201 | ||
1c74ea29 | 202 | #define Paper_ "/Library/MobileSubstrate/MobileSafety.png" |
dbbe0f32 | 203 | |
d641d519 | 204 | MSClassMessageHook0(UIImage *, UIImage, defaultDesktopImage) { |
dbbe0f32 JF |
205 | return [UIImage imageWithContentsOfFile:@Paper_]; |
206 | } | |
207 | ||
d641d519 | 208 | MSInstanceMessageHook0(void, SBStatusBarTimeView, tile) { |
39f17851 JF |
209 | NSString *&_time(MSHookIvar<NSString *>(self, "_time")); |
210 | CGRect &_textRect(MSHookIvar<CGRect>(self, "_textRect")); | |
25f84761 | 211 | if (_time != nil) |
39f17851 | 212 | [_time release]; |
dbbe0f32 | 213 | _time = [@"Exit Safe Mode" retain]; |
2c75d26c | 214 | id font([self textFont]); |
88d77501 | 215 | CGSize size([_time sizeWithFont:font]); |
39f17851 | 216 | CGRect frame([self frame]); |
39f17851 JF |
217 | _textRect.size = size; |
218 | _textRect.origin.x = (frame.size.width - size.width) / 2; | |
219 | _textRect.origin.y = (frame.size.height - size.height) / 2; | |
25f84761 JF |
220 | } |
221 | ||
222 | #define Dylib_ "/Library/MobileSubstrate/MobileSubstrate.dylib" | |
223 | ||
63918068 | 224 | MSInitialize { |
d641d519 | 225 | NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]); |
10586051 | 226 | |
25f84761 JF |
227 | NSLog(@"MS:Warning: Entering Safe Mode"); |
228 | ||
d641d519 | 229 | char *dil(getenv("DYLD_INSERT_LIBRARIES")); |
25f84761 JF |
230 | if (dil == NULL) |
231 | NSLog(@"MS:Error: DYLD_INSERT_LIBRARIES is unset?"); | |
232 | else { | |
233 | NSArray *dylibs([[NSString stringWithUTF8String:dil] componentsSeparatedByString:@":"]); | |
234 | NSUInteger index([dylibs indexOfObject:@ Dylib_]); | |
235 | if (index == NSNotFound) | |
236 | NSLog(@"MS:Error: dylib not in DYLD_INSERT_LIBRARIES?"); | |
237 | else if ([dylibs count] == 1) | |
238 | unsetenv("DYLD_INSERT_LIBRARIES"); | |
239 | else { | |
240 | NSMutableArray *value([[[NSMutableArray alloc] init] autorelease]); | |
241 | [value setArray:dylibs]; | |
242 | [value removeObjectAtIndex:index]; | |
243 | setenv("DYLD_INSERT_LIBRARIES", [[value componentsJoinedByString:@":"] UTF8String], !0); | |
244 | } | |
245 | } | |
246 | ||
39f17851 JF |
247 | $SBAlertItemsController = objc_getClass("SBAlertItemsController"); |
248 | ||
25f84761 JF |
249 | if (Class _class = objc_getClass("SBIconController")) { |
250 | SEL sel(@selector(showInfoAlertIfNeeded)); | |
251 | if (Method method = class_getInstanceMethod(_class, sel)) | |
39f17851 | 252 | method_setImplementation(method, (IMP) &SBIconController$showInfoAlertIfNeeded); |
25f84761 | 253 | } |
10586051 JF |
254 | |
255 | [pool release]; | |
25f84761 | 256 | } |