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