1 /* Cydia Substrate - Meta-Library Insert for iPhoneOS
2 * Copyright (C) 2008 Jay Freeman (saurik)
6 * Redistribution and use in source and binary
7 * forms, with or without modification, are permitted
8 * provided that the following conditions are met:
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
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.
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.
38 #import <CoreFoundation/CoreFoundation.h>
39 #import <Foundation/Foundation.h>
40 #import <CoreGraphics/CGGeometry.h>
41 #import <UIKit/UIKit.h>
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>
49 #include <substrate.h>
51 @protocol MobileSubstrate
52 - (id) ms$initWithSize:(CGSize)size;
53 - (int) ms$maxIconColumns;
56 Class $SafeModeAlertItem;
57 Class $SBAlertItemsController;
59 void SafeModeAlertItem$alertSheet$buttonClicked$(id self, SEL sel, id sheet, int button) {
69 [UIApp openURL:[NSURL URLWithString:@"http://cydia.saurik.com/safemode/"]];
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];
86 void SafeModeAlertItem$performUnlockAction(id self, SEL sel) {
87 [[$SBAlertItemsController sharedInstance] activateAlertItem:self];
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)
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);
104 if ($SBAlertItemsController != nil)
105 [[$SBAlertItemsController sharedInstance] activateAlertItem:[[$SafeModeAlertItem alloc] init]];
108 MSHook(void, SBStatusBar$mouseDown$, SBStatusBar *self, SEL sel, GSEventRef event) {
110 _SBStatusBar$mouseDown$(self, sel, event);
113 static void SBIconController$showInfoAlertIfNeeded(id self, SEL sel) {
114 static bool loaded = false;
121 static int SBButtonBar$maxIconColumns(id<MobileSubstrate> self, SEL sel) {
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]);
138 static id SBContentLayer$initWithSize$(SBContentLayer<MobileSubstrate> *self, SEL sel, CGSize size) {
139 self = [self ms$initWithSize:size];
142 [self setBackgroundColor:[UIColor darkGrayColor]];
146 MSHook(void, SBStatusBarTimeView$tile, SBStatusBarTimeView *self, SEL sel) {
147 NSString *&_time(MSHookIvar<NSString *>(self, "_time"));
148 CGRect &_textRect(MSHookIvar<CGRect>(self, "_textRect"));
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;
161 #define Dylib_ "/Library/MobileSubstrate/MobileSubstrate.dylib"
163 extern "C" void MSInitialize() {
164 NSLog(@"MS:Warning: Entering Safe Mode");
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);
171 char *dil = getenv("DYLD_INSERT_LIBRARIES");
173 NSLog(@"MS:Error: DYLD_INSERT_LIBRARIES is unset?");
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");
182 NSMutableArray *value([[[NSMutableArray alloc] init] autorelease]);
183 [value setArray:dylibs];
184 [value removeObjectAtIndex:index];
185 setenv("DYLD_INSERT_LIBRARIES", [[value componentsJoinedByString:@":"] UTF8String], !0);
189 $SBAlertItemsController = objc_getClass("SBAlertItemsController");
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);