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