]> git.saurik.com Git - cydia.git/blobdiff - Cydia.mm
Gracefully handle someone /deleting/ the firmware package.
[cydia.git] / Cydia.mm
index f59dcc8549592f44686ecd91bd8cd18f8d4f3015..7a5a33d130aaf5e2f0dac2a48c909c4ae4c744c7 100644 (file)
--- a/Cydia.mm
+++ b/Cydia.mm
@@ -35,6 +35,9 @@
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
+// XXX: wtf/FastMalloc.h... wtf?
+#define USE_SYSTEM_MALLOC 1
+
 /* #include Directives {{{ */
 #import "UICaboodle.h"
 
 // XXX: remove
 #import <MessageUI/MailComposeController.h>
 
-#import <WebCore/WebScriptObject.h>
-//#include <WebCore/DOMHTML.h>
-
-#include <WebKit/WebFrame.h>
-#include <WebKit/WebPolicyDelegate.h>
-#include <WebKit/WebView.h>
-
-#import <WebKit/WebView-WebPrivate.h>
-
 #include <sstream>
 #include <string>
 
@@ -85,6 +79,8 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/sysctl.h>
+#include <sys/param.h>
+#include <sys/mount.h>
 
 #include <notify.h>
 #include <dlfcn.h>
@@ -102,6 +98,8 @@ extern "C" {
 
 #import "BrowserView.h"
 #import "ResetView.h"
+
+#import "substrate.h"
 /* }}} */
 
 //#define _finline __attribute__((force_inline))
@@ -174,7 +172,10 @@ void NSLogRect(const char *fix, const CGRect &rect) {
     NSLog(@"%s(%g,%g)+(%g,%g)", fix, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
 }
 
-static const NSStringCompareOptions CompareOptions_ = NSCaseInsensitiveSearch | NSNumericSearch | NSDiacriticInsensitiveSearch | NSWidthInsensitiveSearch | NSForcedOrderingSearch;
+/* NSForcedOrderingSearch doesn't work on the iPhone */
+static const NSStringCompareOptions BaseCompareOptions_ = NSNumericSearch | NSDiacriticInsensitiveSearch | NSWidthInsensitiveSearch;
+static const NSStringCompareOptions ForcedCompareOptions_ = BaseCompareOptions_;
+static const NSStringCompareOptions LaxCompareOptions_ = BaseCompareOptions_ | NSCaseInsensitiveSearch;
 
 /* iPhoneOS 2.0 Compatibility {{{ */
 #ifdef __OBJC2__
@@ -261,10 +262,11 @@ extern NSString * const kCAFilterNearest;
 
 #define lprintf(args...) fprintf(stderr, args)
 
-#define ForRelease 1
-#define ForSaurik 1 && !ForRelease
+#define ForRelease 0
+#define ForSaurik (1 && !ForRelease)
+#define IgnoreInstall (0 && !ForRelease)
 #define RecycleWebViews 0
-#define AlwaysReload 1 && !ForRelease
+#define AlwaysReload (1 && !ForRelease)
 
 /* Radix Sort {{{ */
 @interface NSMutableArray (Radix)
@@ -382,6 +384,19 @@ typedef enum {
     kUIControlAllEvents = (kUIControlEventMouseDown | kUIControlEventMouseMovedInside | kUIControlEventMouseMovedOutside | kUIControlEventMouseUpInside | kUIControlEventMouseUpOutside)
 } UIControlEventMasks;
 
+NSUInteger DOMNodeList$countByEnumeratingWithState$objects$count$(DOMNodeList *self, SEL sel, NSFastEnumerationState *state, id *objects, NSUInteger count) {
+    size_t length([self length] - state->state);
+    if (length <= 0)
+        return 0;
+    else if (length > count)
+        length = count;
+    for (size_t i(0); i != length; ++i)
+        objects[i] = [self item:state->state++];
+    state->itemsPtr = objects;
+    state->mutationsPtr = (unsigned long *) self;
+    return length;
+}
+
 @interface NSString (UIKit)
 - (NSString *) stringByAddingPercentEscapes;
 - (NSString *) stringByReplacingCharacter:(unsigned short)arg0 withCharacter:(unsigned short)arg1;
@@ -588,6 +603,7 @@ static const float KeyboardTime_ = 0.3f;
 
 #define SpringBoard_ "/System/Library/LaunchDaemons/com.apple.SpringBoard.plist"
 #define SandboxTemplate_ "/usr/share/sandbox/SandboxTemplate.sb"
+#define NotifyConfig_ "/etc/notify.conf"
 
 static CGColor Blue_;
 static CGColor Blueish_;
@@ -613,25 +629,18 @@ static UIFont *Font18Bold_;
 static UIFont *Font22Bold_;
 
 static const char *Machine_ = NULL;
-static const NSString *UniqueID_ = NULL;
-
-unsigned Major_;
-unsigned Minor_;
-unsigned BugFix_;
+static const NSString *UniqueID_ = nil;
+static const NSString *Build_ = nil;
 
 CFLocaleRef Locale_;
 CGColorSpaceRef space_;
 
-#define FW_LEAST(major, minor, bugfix) \
-    (major < Major_ || major == Major_ && \
-        (minor < Minor_ || minor == Minor_ && \
-            bugfix <= BugFix_))
-
 bool bootstrap_;
 bool reload_;
 
 static NSDictionary *SectionMap_;
 static NSMutableDictionary *Metadata_;
+static NSMutableDictionary *Indices_;
 static _transient NSMutableDictionary *Settings_;
 static _transient NSString *Role_;
 static _transient NSMutableDictionary *Packages_;
@@ -756,6 +765,7 @@ bool isSectionVisible(NSString *section) {
 - (RVPage *) pageForURL:(NSURL *)url hasTag:(int *)tag;
 - (RVPage *) pageForPackage:(NSString *)name;
 - (void) openMailToURL:(NSURL *)url;
+- (void) clearFirstResponder;
 @end
 /* }}} */
 
@@ -1055,7 +1065,7 @@ class Progress :
             return NSOrderedDescending;
     }
 
-    return [lhs compare:rhs options:CompareOptions_];
+    return [lhs compare:rhs options:LaxCompareOptions_];
 }
 
 - (NSDictionary *) record {
@@ -1225,6 +1235,7 @@ class Progress :
 
 - (Source *) source;
 - (NSString *) role;
+- (NSString *) rating;
 
 - (BOOL) matches:(NSString *)text;
 
@@ -1287,7 +1298,7 @@ class Progress :
 }
 
 + (NSArray *) _attributeKeys {
-    return [NSArray arrayWithObjects:@"applications", @"author", @"depiction", @"description", @"essential", @"homepage", @"icon", @"id", @"installed", @"latest", @"maintainer", @"name", @"purposes", @"section", @"size", @"source", @"sponsor", @"tagline", @"warnings", nil];
+    return [NSArray arrayWithObjects:@"applications", @"author", @"depiction", @"description", @"essential", @"homepage", @"icon", @"id", @"installed", @"latest", @"maintainer", @"name", @"purposes", @"rating", @"section", @"size", @"source", @"sponsor", @"tagline", @"warnings", nil];
 }
 
 - (NSArray *) attributeKeys {
@@ -1718,6 +1729,8 @@ class Progress :
         [warnings addObject:@"illegal package identifier"];
     else for (size_t i(0); i != length; ++i)
         if (
+            /* XXX: technically this is not allowed */
+            (name[i] < 'A' || name[i] > 'Z') &&
             (name[i] < 'a' || name[i] > 'z') &&
             (name[i] < '0' || name[i] > '9') &&
             (i == 0 || name[i] != '+' && name[i] != '-' && name[i] != '.')
@@ -1725,17 +1738,25 @@ class Progress :
 
     if (strcmp(name, "cydia") != 0) {
         bool cydia = false;
+        bool _private = false;
         bool stash = false;
 
+        bool repository = [[self section] isEqualToString:@"Repositories"];
+
         if (NSArray *files = [self files])
             for (NSString *file in files)
                 if (!cydia && [file isEqualToString:@"/Applications/Cydia.app"])
                     cydia = true;
+                else if (!_private && [file isEqualToString:@"/private"])
+                    _private = true;
                 else if (!stash && [file isEqualToString:@"/var/stash"])
                     stash = true;
 
-        if (cydia)
+        /* XXX: this is not sensitive enough. only some folders are valid. */
+        if (cydia && !repository)
             [warnings addObject:@"files installed into Cydia.app"];
+        if (_private)
+            [warnings addObject:@"files installed with /private/*"];
         if (stash)
             [warnings addObject:@"files installed to /var/stash"];
     }
@@ -1791,6 +1812,13 @@ class Progress :
     return role_;
 }
 
+- (NSString *) rating {
+    if (NSString *rating = [Indices_ objectForKey:@"Rating"])
+        return [rating stringByReplacingOccurrencesOfString:@"@P" withString:[id_ stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
+    else
+        return nil;
+}
+
 - (BOOL) matches:(NSString *)text {
     if (text == nil)
         return NO;
@@ -1863,7 +1891,7 @@ class Progress :
             return NSOrderedDescending;
     }
 
-    return [lhs compare:rhs options:CompareOptions_];
+    return [lhs compare:rhs options:LaxCompareOptions_];
 }
 
 - (NSComparisonResult) compareBySection:(Package *)package {
@@ -1875,9 +1903,8 @@ class Progress :
     else if (lhs != NULL && rhs == NULL)
         return NSOrderedDescending;
     else if (lhs != NULL && rhs != NULL) {
-        NSComparisonResult result = [lhs compare:rhs options:CompareOptions_];
-        if (result != NSOrderedSame)
-            return result;
+        NSComparisonResult result([lhs compare:rhs options:LaxCompareOptions_]);
+        return result != NSOrderedSame ? result : [lhs compare:rhs options:ForcedCompareOptions_];
     }
 
     return NSOrderedSame;
@@ -1997,7 +2024,7 @@ class Progress :
             return NSOrderedDescending;
     }
 
-    return [lhs compare:rhs options:CompareOptions_];
+    return [lhs compare:rhs options:LaxCompareOptions_];
 }
 
 - (Section *) initWithName:(NSString *)name {
@@ -2831,8 +2858,12 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     return @"Cancel";
 }
 
-- (NSString *) _rightButtonTitle {
+- (id) _rightButtonTitle {
+#if AlwaysReload || IgnoreInstall
+    return @"Reload";
+#else
     return issues_ == nil ? @"Confirm" : nil;
+#endif
 }
 
 - (void) _leftButtonClicked {
@@ -2841,6 +2872,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 #if !AlwaysReload
 - (void) _rightButtonClicked {
+#if IgnoreInstall
+    return [super _rightButtonClicked];
+#endif
     if (essential_ != nil)
         [essential_ popupAlertAnimated:YES];
     else {
@@ -2910,6 +2944,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     id delegate_;
     BOOL running_;
     SHA1SumValue springlist_;
+    SHA1SumValue notifyconf_;
     SHA1SumValue sandplate_;
     size_t received_;
     NSTimeInterval last_;
@@ -3129,6 +3164,15 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
             Finish_ = 4;
     }
 
+    if (Finish_ < 4) {
+        FileFd file(NotifyConfig_, FileFd::ReadOnly);
+        MMap mmap(file, MMap::ReadOnly);
+        SHA1Summation sha1;
+        sha1.Add(reinterpret_cast<uint8_t *>(mmap.Data()), mmap.Size());
+        if (!(notifyconf_ == sha1.Result()))
+            Finish_ = 4;
+    }
+
     if (Finish_ < 3) {
         FileFd file(SpringBoard_, FileFd::ReadOnly);
         MMap mmap(file, MMap::ReadOnly);
@@ -3229,6 +3273,14 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         sandplate_ = sha1.Result();
     }
 
+    {
+        FileFd file(NotifyConfig_, FileFd::ReadOnly);
+        MMap mmap(file, MMap::ReadOnly);
+        SHA1Summation sha1;
+        sha1.Add(reinterpret_cast<uint8_t *>(mmap.Data()), mmap.Size());
+        notifyconf_ = sha1.Result();
+    }
+
     {
         FileFd file(SpringBoard_, FileFd::ReadOnly);
         MMap mmap(file, MMap::ReadOnly);
@@ -3845,7 +3897,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
-    [[frame windowObject] evaluateWebScript:@"document.base.target = '_top'"];
     return [super webView:sender didFinishLoadForFrame:frame];
 }
 
@@ -3880,7 +3931,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 #endif
 
-- (NSString *) _rightButtonTitle {
+- (id) _rightButtonTitle {
     int count = [buttons_ count];
     return count == 0 ? nil : count != 1 ? @"Modify" : [buttons_ objectAtIndex:0];
 }
@@ -3927,6 +3978,10 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     }
 }
 
+- (bool) _loading {
+    return false;
+}
+
 - (void) reloadData {
     [self setPackage:[database_ packageWithName:name_]];
     [self reloadButtons];
@@ -4565,7 +4620,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     return [[list_ table] isRowDeletionEnabled] ? @"Add" : nil;
 }
 
-- (NSString *) rightButtonTitle {
+- (id) rightButtonTitle {
     return [[list_ table] isRowDeletionEnabled] ? @"Done" : @"Edit";
 }
 
@@ -4636,7 +4691,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     return @"Packages";
 }
 
-- (NSString *) rightButtonTitle {
+- (id) rightButtonTitle {
     return Role_ != nil && [Role_ isEqualToString:@"Developer"] ? nil : expert_ ? @"Expert" : @"Simple";
 }
 
@@ -4723,21 +4778,17 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 #if !AlwaysReload
-- (NSString *) _rightButtonTitle {
+- (id) _rightButtonTitle {
     return nil;
 }
 #endif
 
-@end
-/* }}} */
+- (bool) _loading {
+    return false;
+}
 
-@interface WebView (Cydia)
-- (void) setScriptDebugDelegate:(id)delegate;
-- (void) _setFormDelegate:(id)delegate;
-- (void) _setUIKitDelegate:(id)delegate;
-- (void) setWebMailDelegate:(id)delegate;
-- (void) _setLayoutInterval:(float)interval;
 @end
+/* }}} */
 
 /* Indirect Delegate {{{ */
 @interface IndirectDelegate : NSProxy {
@@ -4775,572 +4826,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 @end
 /* }}} */
-/* Browser Implementation {{{ */
-@implementation BrowserView
-
-- (void) dealloc {
-    if (challenge_ != nil)
-        [challenge_ release];
-
-    WebView *webview = [webview_ webView];
-    [webview setFrameLoadDelegate:nil];
-    [webview setResourceLoadDelegate:nil];
-    [webview setUIDelegate:nil];
-    [webview setScriptDebugDelegate:nil];
-    [webview setPolicyDelegate:nil];
-
-    [webview setDownloadDelegate:nil];
-
-    [webview _setFormDelegate:nil];
-    [webview _setUIKitDelegate:nil];
-    [webview setWebMailDelegate:nil];
-    [webview setEditingDelegate:nil];
-
-    [webview_ setDelegate:nil];
-    [webview_ setGestureDelegate:nil];
-
-    //NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
-
-    [webview close];
-
-#if RecycleWebViews
-    [webview_ removeFromSuperview];
-    [Documents_ addObject:[webview_ autorelease]];
-#else
-    [webview_ release];
-#endif
-
-    [indirect_ setDelegate:nil];
-    [indirect_ release];
-
-    [scroller_ setDelegate:nil];
-
-    [scroller_ release];
-    [urls_ release];
-    [indicator_ release];
-    if (title_ != nil)
-        [title_ release];
-    [super dealloc];
-}
-
-- (void) loadURL:(NSURL *)url cachePolicy:(NSURLRequestCachePolicy)policy {
-    [self loadRequest:[NSURLRequest
-        requestWithURL:url
-        cachePolicy:policy
-        timeoutInterval:30.0
-    ]];
-}
-
-- (void) loadURL:(NSURL *)url {
-    [self loadURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy];
-}
-
-- (NSURLRequest *) _addHeadersToRequest:(NSURLRequest *)request {
-    NSMutableURLRequest *copy = [request mutableCopy];
-
-    if (Machine_ != NULL)
-        [copy addValue:[NSString stringWithUTF8String:Machine_] forHTTPHeaderField:@"X-Machine"];
-    if (UniqueID_ != nil)
-        [copy addValue:UniqueID_ forHTTPHeaderField:@"X-Unique-ID"];
-
-    if (Role_ != nil)
-        [copy addValue:Role_ forHTTPHeaderField:@"X-Role"];
-
-    return copy;
-}
-
-- (void) loadRequest:(NSURLRequest *)request {
-    pushed_ = true;
-    [webview_ loadRequest:request];
-}
-
-- (void) reloadURL {
-    if ([urls_ count] == 0)
-        return;
-    NSURL *url = [[[urls_ lastObject] retain] autorelease];
-    [urls_ removeLastObject];
-    [self loadURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData];
-}
-
-- (WebView *) webView {
-    return [webview_ webView];
-}
-
-- (void) view:(UIView *)sender didSetFrame:(CGRect)frame {
-    [scroller_ setContentSize:frame.size];
-}
-
-- (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old {
-    [self view:sender didSetFrame:frame];
-}
-
-- (void) pushPage:(RVPage *)page {
-    [self setBackButtonTitle:title_];
-    [page setDelegate:delegate_];
-    [book_ pushPage:page];
-}
-
-- (BOOL) getSpecial:(NSURL *)url {
-    NSString *href([url absoluteString]);
-    NSString *scheme([[url scheme] lowercaseString]);
 
-    RVPage *page = nil;
-
-    if ([href hasPrefix:@"apptapp://package/"])
-        page = [delegate_ pageForPackage:[href substringFromIndex:18]];
-    else if ([scheme isEqualToString:@"cydia"]) {
-        page = [delegate_ pageForURL:url hasTag:NULL];
-        if (page == nil)
-            return false;
-    } else if (![scheme isEqualToString:@"apptapp"])
-        return false;
-
-    if (page != nil)
-        [self pushPage:page];
-    return true;
-}
-
-- (void) webView:(WebView *)sender runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame {
-    UIActionSheet *sheet = [[[UIActionSheet alloc]
-        initWithTitle:@"JavaScript Alert"
-        buttons:[NSArray arrayWithObjects:@"OK", nil]
-        defaultButtonIndex:0
-        delegate:self
-        context:@"alert"
-    ] autorelease];
-
-    [sheet setBodyText:message];
-    [sheet popupAlertAnimated:YES];
-}
-
-- (void) webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame {
-    [window setValue:delegate_ forKey:@"cydia"];
-}
-
-- (void) webView:(WebView *)sender decidePolicyForNewWindowAction:(NSDictionary *)dictionary request:(NSURLRequest *)request newFrameName:(NSString *)name decisionListener:(id<WebPolicyDecisionListener>)listener {
-    if (NSURL *url = [request URL]) {
-        if (![self getSpecial:url]) {
-            NSString *scheme([[url scheme] lowercaseString]);
-            if ([scheme isEqualToString:@"mailto"])
-                [delegate_ openMailToURL:url];
-            else goto use;
-        }
-
-        [listener ignore];
-    } else use:
-        [listener use];
-}
-
-- (void) webView:(WebView *)webView decidePolicyForMIMEType:(NSString *)type request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id<WebPolicyDecisionListener>)listener {
-    if ([WebView canShowMIMEType:type])
-        [listener use];
-    else {
-        // XXX: handle more mime types!
-        [listener ignore];
-        if (frame == [webView mainFrame])
-            [UIApp openURL:[request URL]];
-    }
-}
-
-- (void) webView:(WebView *)sender decidePolicyForNavigationAction:(NSDictionary *)action request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id<WebPolicyDecisionListener>)listener {
-    NSURL *url([request URL]);
-
-    if (url == nil) use: {
-        [listener use];
-        return;
-    }
-
-    const NSArray *capability(reinterpret_cast<const NSArray *>(GSSystemGetCapability(kGSDisplayIdentifiersCapability)));
-
-    if (
-        [capability containsObject:@"com.apple.Maps"] && [url mapsURL] ||
-        [capability containsObject:@"com.apple.youtube"] && [url youTubeURL]
-    ) {
-      open:
-        [UIApp openURL:url];
-      ignore:
-        [listener ignore];
-        return;
-    }
-
-    int store(_not(int));
-    if (NSURL *itms = [url itmsURL:&store]) {
-        NSLog(@"itms#%@#%u#%@", url, store, itms);
-        if (
-            store == 1 && [capability containsObject:@"com.apple.MobileStore"] ||
-            store == 2 && [capability containsObject:@"com.apple.AppStore"]
-        ) {
-            url = itms;
-            goto open;
-        }
-    }
-
-    NSString *scheme([[url scheme] lowercaseString]);
-
-    if ([scheme isEqualToString:@"tel"]) {
-        // XXX: intelligence
-        goto open;
-    }
-
-    if ([scheme isEqualToString:@"mailto"]) {
-        [delegate_ openMailToURL:url];
-        goto ignore;
-    }
-
-    if ([self getSpecial:url])
-        goto ignore;
-    else if ([WebView _canHandleRequest:request])
-        goto use;
-    else if ([url isSpringboardHandledURL])
-        goto open;
-    else
-        goto use;
-}
-
-- (void) webView:(WebView *)sender setStatusText:(NSString *)text {
-    //lprintf("Status:%s\n", [text UTF8String]);
-}
-
-- (void) _pushPage {
-    if (pushed_)
-        return;
-    pushed_ = true;
-    [book_ pushPage:self];
-}
-
-- (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
-    NSString *context([sheet context]);
-
-    if ([context isEqualToString:@"alert"])
-        [sheet dismiss];
-    else if ([context isEqualToString:@"challenge"]) {
-        id<NSURLAuthenticationChallengeSender> sender([challenge_ sender]);
-
-        switch (button) {
-            case 1: {
-                NSString *username([[sheet textFieldAtIndex:0] text]);
-                NSString *password([[sheet textFieldAtIndex:1] text]);
-
-                NSURLCredential *credential([NSURLCredential credentialWithUser:username password:password persistence:NSURLCredentialPersistenceForSession]);
-
-                [sender useCredential:credential forAuthenticationChallenge:challenge_];
-            } break;
-
-            case 2:
-                [sender cancelAuthenticationChallenge:challenge_];
-            break;
-
-            default:
-                _assert(false);
-        }
-
-        [challenge_ release];
-        challenge_ = nil;
-
-        [sheet dismiss];
-    }
-}
-
-- (void) webView:(WebView *)sender resource:(id)identifier didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge fromDataSource:(WebDataSource *)source {
-    challenge_ = [challenge retain];
-
-    NSURLProtectionSpace *space([challenge protectionSpace]);
-    NSString *realm([space realm]);
-    if (realm == nil)
-        realm = @"";
-
-    UIActionSheet *sheet = [[[UIActionSheet alloc]
-        initWithTitle:realm
-        buttons:[NSArray arrayWithObjects:@"Login", @"Cancel", nil]
-        defaultButtonIndex:0
-        delegate:self
-        context:@"challenge"
-    ] autorelease];
-
-    [sheet setNumberOfRows:1];
-
-    [sheet addTextFieldWithValue:@"" label:@"username"];
-    [sheet addTextFieldWithValue:@"" label:@"password"];
-
-    UITextField *username([sheet textFieldAtIndex:0]); {
-        UITextInputTraits *traits([username textInputTraits]);
-        [traits setAutocapitalizationType:UITextAutocapitalizationTypeNone];
-        [traits setAutocorrectionType:UITextAutocorrectionTypeNo];
-        [traits setKeyboardType:UIKeyboardTypeASCIICapable];
-        [traits setReturnKeyType:UIReturnKeyNext];
-    }
-
-    UITextField *password([sheet textFieldAtIndex:1]); {
-        UITextInputTraits *traits([password textInputTraits]);
-        [traits setAutocapitalizationType:UITextAutocapitalizationTypeNone];
-        [traits setAutocorrectionType:UITextAutocorrectionTypeNo];
-        [traits setKeyboardType:UIKeyboardTypeASCIICapable];
-        // XXX: UIReturnKeyDone
-        [traits setReturnKeyType:UIReturnKeyNext];
-        [traits setSecureTextEntry:YES];
-    }
-
-    [sheet popupAlertAnimated:YES];
-}
-
-- (NSURLRequest *) webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)source {
-    NSURL *url = [request URL];
-    if ([self getSpecial:url])
-        return nil;
-    [self _pushPage];
-    return [self _addHeadersToRequest:request];
-}
-
-- (WebView *) _createWebViewWithRequest:(NSURLRequest *)request pushed:(BOOL)pushed {
-    [self setBackButtonTitle:title_];
-
-    BrowserView *browser = [[[BrowserView alloc] initWithBook:book_] autorelease];
-    [browser setDelegate:delegate_];
-
-    if (pushed) {
-        [browser loadRequest:[self _addHeadersToRequest:request]];
-        [book_ pushPage:browser];
-    }
-
-    return [browser webView];
-}
-
-- (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request {
-    return [self _createWebViewWithRequest:request pushed:(request != nil)];
-}
-
-- (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request windowFeatures:(NSDictionary *)features {
-    return [self _createWebViewWithRequest:request pushed:YES];
-}
-
-- (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame {
-    if ([frame parentFrame] != nil)
-        return;
-
-    title_ = [title retain];
-    [book_ reloadTitleForPage:self];
-}
-
-- (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame {
-    if ([frame parentFrame] != nil)
-        return;
-
-    reloading_ = false;
-    loading_ = true;
-    [indicator_ startAnimation];
-    [self reloadButtons];
-
-    if (title_ != nil) {
-        [title_ release];
-        title_ = nil;
-    }
-
-    [book_ reloadTitleForPage:self];
-
-    WebView *webview = [webview_ webView];
-    NSString *href = [webview mainFrameURL];
-    [urls_ addObject:[NSURL URLWithString:href]];
-
-    [scroller_ scrollPointVisibleAtTopLeft:CGPointZero];
-
-    CGRect webrect = [scroller_ bounds];
-    webrect.size.height = 0;
-    [webview_ setFrame:webrect];
-}
-
-- (void) _finishLoading {
-    if (!reloading_) {
-        loading_ = false;
-        [indicator_ stopAnimation];
-        [self reloadButtons];
-    }
-}
-
-- (BOOL) webView:(WebView *)sender shouldScrollToPoint:(struct CGPoint)point forFrame:(WebFrame *)frame {
-    return [webview_ webView:sender shouldScrollToPoint:point forFrame:frame];
-}
-
-- (void) webView:(WebView *)sender didReceiveViewportArguments:(id)arguments forFrame:(WebFrame *)frame {
-    return [webview_ webView:sender didReceiveViewportArguments:arguments forFrame:frame];
-}
-
-- (void) webView:(WebView *)sender needsScrollNotifications:(id)notifications forFrame:(WebFrame *)frame {
-    return [webview_ webView:sender needsScrollNotifications:notifications forFrame:frame];
-}
-
-- (void) webView:(WebView *)sender didCommitLoadForFrame:(WebFrame *)frame {
-    return [webview_ webView:sender didCommitLoadForFrame:frame];
-}
-
-- (void) webView:(WebView *)sender didReceiveDocTypeForFrame:(WebFrame *)frame {
-    return [webview_ webView:sender didReceiveDocTypeForFrame:frame];
-}
-
-- (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
-    if ([frame parentFrame] == nil)
-        [self _finishLoading];
-    return [webview_ webView:sender didFinishLoadForFrame:frame];
-}
-
-- (void) webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
-    if ([frame parentFrame] != nil)
-        return;
-    [self _finishLoading];
-
-    [self loadURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@?%@",
-        [[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"error" ofType:@"html"]] absoluteString],
-        [[error localizedDescription] stringByAddingPercentEscapes]
-    ]]];
-}
-
-- (void) webView:(WebView *)sender addMessageToConsole:(NSDictionary *)dictionary {
-#if ForSaurik
-    lprintf("Console:%s\n", [[dictionary description] UTF8String]);
-#endif
-}
-
-- (id) initWithBook:(RVBook *)book {
-    if ((self = [super initWithBook:book]) != nil) {
-        loading_ = false;
-
-        struct CGRect bounds = [self bounds];
-
-        UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:bounds] autorelease];
-        [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
-        [self addSubview:pinstripe];
-
-        scroller_ = [[UIScroller alloc] initWithFrame:bounds];
-        [self addSubview:scroller_];
-
-        [scroller_ setScrollingEnabled:YES];
-        [scroller_ setAdjustForContentSizeChange:YES];
-        [scroller_ setClipsSubviews:YES];
-        [scroller_ setAllowsRubberBanding:YES];
-        [scroller_ setScrollDecelerationFactor:0.99];
-        [scroller_ setDelegate:self];
-
-        CGRect webrect = [scroller_ bounds];
-        webrect.size.height = 0;
-
-        WebView *webview;
-
-#if RecycleWebViews
-        webview_ = [Documents_ lastObject];
-        if (webview_ != nil) {
-            webview_ = [webview_ retain];
-            webview = [webview_ webView];
-            [Documents_ removeLastObject];
-            [webview_ setFrame:webrect];
-        } else {
-#else
-        if (true) {
-#endif
-            webview_ = [[UIWebDocumentView alloc] initWithFrame:webrect];
-            webview = [webview_ webView];
-
-            [webview_ setTileSize:CGSizeMake(webrect.size.width, 500)];
-
-            [webview_ setAllowsMessaging:YES];
-
-            [webview_ setTilingEnabled:YES];
-            [webview_ setDrawsGrid:NO];
-            [webview_ setLogsTilingChanges:NO];
-            [webview_ setTileMinificationFilter:kCAFilterNearest];
-            [webview_ setDetectsPhoneNumbers:NO];
-            [webview_ setAutoresizes:YES];
-
-            [webview_ setViewportSize:CGSizeMake(980, -1) forDocumentTypes:0x10];
-            [webview_ setViewportSize:CGSizeMake(320, -1) forDocumentTypes:0x2];
-            [webview_ setViewportSize:CGSizeMake(320, -1) forDocumentTypes:0x8];
-
-            [webview_ _setDocumentType:0x4];
-
-            [webview_ setZoomsFocusedFormControl:YES];
-            [webview_ setContentsPosition:7];
-            [webview_ setEnabledGestures:0xa];
-            [webview_ setValue:[NSNumber numberWithBool:YES] forGestureAttribute:UIGestureAttributeIsZoomRubberBandEnabled];
-            [webview_ setValue:[NSNumber numberWithBool:YES] forGestureAttribute:UIGestureAttributeUpdatesScroller];
-
-            [webview_ setSmoothsFonts:YES];
-
-            [webview _setUsesLoaderCache:YES];
-            [webview setGroupName:@"Cydia"];
-            //[webview _setLayoutInterval:0.5];
-        }
-
-        [webview_ setDelegate:self];
-        [webview_ setGestureDelegate:self];
-        [scroller_ addSubview:webview_];
-
-        //NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
-
-        CGSize indsize = [UIProgressIndicator defaultSizeForStyle:UIProgressIndicatorStyleMediumWhite];
-        indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(281, 12, indsize.width, indsize.height)];
-        [indicator_ setStyle:UIProgressIndicatorStyleMediumWhite];
-
-        Package *package([[Database sharedInstance] packageWithName:@"cydia"]);
-        NSString *application = package == nil ? @"Cydia" : [NSString
-            stringWithFormat:@"Cydia/%@",
-            [package installed]
-        ]; [webview setApplicationNameForUserAgent:application];
-
-        indirect_ = [[IndirectDelegate alloc] initWithDelegate:self];
-
-        [webview setFrameLoadDelegate:self];
-        [webview setResourceLoadDelegate:indirect_];
-        [webview setUIDelegate:self];
-        [webview setScriptDebugDelegate:self];
-        [webview setPolicyDelegate:self];
-
-        urls_ = [[NSMutableArray alloc] initWithCapacity:16];
-
-        [self setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
-        [scroller_ setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
-        [pinstripe setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
-    } return self;
-}
-
-- (void) didFinishGesturesInView:(UIView *)view forEvent:(id)event {
-    [webview_ redrawScaledDocument];
-}
-
-- (void) _rightButtonClicked {
-    reloading_ = true;
-    [self reloadURL];
-}
-
-- (NSString *) _rightButtonTitle {
-    return @"Reload";
-}
-
-- (NSString *) rightButtonTitle {
-    return loading_ ? @"" : [self _rightButtonTitle];
-}
-
-- (NSString *) title {
-    return title_ == nil ? @"Loading" : title_;
-}
-
-- (NSString *) backButtonTitle {
-    return @"Browser";
-}
-
-- (void) setPageActive:(BOOL)active {
-    if (!active)
-        [indicator_ removeFromSuperview];
-    else
-        [[book_ navigationBar] addSubview:indicator_];
-}
-
-- (void) resetViewAnimated:(BOOL)animated {
-}
-
-- (void) setPushed:(bool)pushed {
-    pushed_ = pushed;
-}
-
-@end
-/* }}} */
+#include <BrowserView.m>
 
 /* Cydia Book {{{ */
 @interface CYBook : RVBook <
@@ -5618,6 +5105,16 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     return request;
 }
 
+- (void) _returnPNGWithImage:(UIImage *)icon forRequest:(NSURLRequest *)request {
+    id<NSURLProtocolClient> client([self client]);
+    NSData *data(UIImagePNGRepresentation(icon));
+
+    NSURLResponse *response([[[NSURLResponse alloc] initWithURL:[request URL] MIMEType:@"image/png" expectedContentLength:-1 textEncodingName:nil] autorelease]);
+    [client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
+    [client URLProtocol:self didLoadData:data];
+    [client URLProtocolDidFinishLoading:self];
+}
+
 - (void) startLoading {
     id<NSURLProtocolClient> client([self client]);
     NSURLRequest *request([self request]);
@@ -5646,47 +5143,32 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         Package *package([database packageWithName:path]);
         if (package == nil)
             goto fail;
-
         UIImage *icon([package icon]);
-
-        NSData *data(UIImagePNGRepresentation(icon));
-
-        NSURLResponse *response([[[NSURLResponse alloc] initWithURL:[request URL] MIMEType:@"image/png" expectedContentLength:-1 textEncodingName:nil] autorelease]);
-        [client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
-        [client URLProtocol:self didLoadData:data];
-        [client URLProtocolDidFinishLoading:self];
+        [self _returnPNGWithImage:icon forRequest:request];
     } else if ([command isEqualToString:@"source-icon"]) {
         if (path == nil)
             goto fail;
         path = [path stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
         NSString *source(Simplify(path));
-
         UIImage *icon([UIImage imageAtPath:[NSString stringWithFormat:@"%@/Sources/%@.png", App_, source]]);
         if (icon == nil)
             icon = [UIImage applicationImageNamed:@"unknown.png"];
-
-        NSData *data(UIImagePNGRepresentation(icon));
-
-        NSURLResponse *response([[[NSURLResponse alloc] initWithURL:[request URL] MIMEType:@"image/png" expectedContentLength:-1 textEncodingName:nil] autorelease]);
-        [client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
-        [client URLProtocol:self didLoadData:data];
-        [client URLProtocolDidFinishLoading:self];
+        [self _returnPNGWithImage:icon forRequest:request];
+    } else if ([command isEqualToString:@"uikit-image"]) {
+        if (path == nil)
+            goto fail;
+        path = [path stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
+        UIImage *icon(_UIImageWithName(path));
+        [self _returnPNGWithImage:icon forRequest:request];
     } else if ([command isEqualToString:@"section-icon"]) {
         if (path == nil)
             goto fail;
         path = [path stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
         NSString *section(Simplify(path));
-
         UIImage *icon([UIImage imageAtPath:[NSString stringWithFormat:@"%@/Sections/%@.png", App_, section]]);
         if (icon == nil)
             icon = [UIImage applicationImageNamed:@"unknown.png"];
-
-        NSData *data(UIImagePNGRepresentation(icon));
-
-        NSURLResponse *response([[[NSURLResponse alloc] initWithURL:[request URL] MIMEType:@"image/png" expectedContentLength:-1 textEncodingName:nil] autorelease]);
-        [client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
-        [client URLProtocol:self didLoadData:data];
-        [client URLProtocolDidFinishLoading:self];
+        [self _returnPNGWithImage:icon forRequest:request];
     } else fail: {
         [client URLProtocol:self didFailWithError:[NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorResourceUnavailable userInfo:nil]];
     }
@@ -5905,7 +5387,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     return @"Sections";
 }
 
-- (NSString *) rightButtonTitle {
+- (id) rightButtonTitle {
     return [sections_ count] == 0 ? nil : editing_ ? @"Done" : @"Edit";
 }
 
@@ -6113,7 +5595,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     return [(CYBook *)book_ updating] ? nil : @"Refresh";
 }
 
-- (NSString *) rightButtonTitle {
+- (id) rightButtonTitle {
     return upgrades_ == 0 ? nil : [NSString stringWithFormat:@"Upgrade (%u)", upgrades_];
 }
 
@@ -6250,10 +5732,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     if ((self = [super initWithBook:book]) != nil) {
         CGRect pageBounds = [book_ pageBounds];
 
-        /*UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:pageBounds] autorelease];
-        [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
-        [self addSubview:pinstripe];*/
-
         transition_ = [[UITransitionView alloc] initWithFrame:pageBounds];
         [self addSubview:transition_];
 
@@ -7099,7 +6577,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
     NSString *context([sheet context]);
 
-    if ([context isEqualToString:@"fixhalf"]) {
+    if ([context isEqualToString:@"missing"])
+        [sheet dismiss];
+    else if ([context isEqualToString:@"fixhalf"]) {
         switch (button) {
             case 1:
                 @synchronized (self) {
@@ -7218,10 +6698,15 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 #if 0
     [[[MailToView alloc] initWithView:underlay_ delegate:self url:url] autorelease];
 #else
-    [UIApp openURL:url];
+    [UIApp openURL:url];// asPanel:YES];
 #endif
 }
 
+- (void) clearFirstResponder {
+    if (id responder = [window_ firstResponder])
+        [responder resignFirstResponder];
+}
+
 - (RVPage *) pageForPackage:(NSString *)name {
     if (Package *package = [database_ packageWithName:name]) {
         PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
@@ -7246,29 +6731,39 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (RVPage *) pageForURL:(NSURL *)url hasTag:(int *)tag {
-    NSString *href = [url absoluteString];
-
     if (tag != NULL)
         tag = 0;
 
-    if ([href isEqualToString:@"cydia://add-source"])
+    NSString *scheme([[url scheme] lowercaseString]);
+    if (![scheme isEqualToString:@"cydia"])
+        return nil;
+    NSString *path([url absoluteString]);
+    if ([path length] < 8)
+        return nil;
+    path = [path substringFromIndex:8];
+    if (![path hasPrefix:@"/"])
+        path = [@"/" stringByAppendingString:path];
+
+    if ([path isEqualToString:@"/add-source"])
         return [[[AddSourceView alloc] initWithBook:book_ database:database_] autorelease];
-    else if ([href isEqualToString:@"cydia://sources"])
+    else if ([path isEqualToString:@"/storage"])
+        return [self _pageForURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"storage" ofType:@"html"]] withClass:[BrowserView class]];
+    else if ([path isEqualToString:@"/sources"])
         return [[[SourceTable alloc] initWithBook:book_ database:database_] autorelease];
-    else if ([href isEqualToString:@"cydia://packages"])
+    else if ([path isEqualToString:@"/packages"])
         return [[[InstalledView alloc] initWithBook:book_ database:database_] autorelease];
-    else if ([href hasPrefix:@"cydia://url/"])
-        return [self _pageForURL:[NSURL URLWithString:[href substringFromIndex:12]] withClass:[BrowserView class]];
-    else if ([href hasPrefix:@"cydia://launch/"])
-        [self launchApplicationWithIdentifier:[href substringFromIndex:15] suspended:NO];
-    else if ([href hasPrefix:@"cydia://package-settings/"])
-        return [[[SettingsView alloc] initWithBook:book_ database:database_ package:[href substringFromIndex:25]] autorelease];
-    else if ([href hasPrefix:@"cydia://package-signature/"])
-        return [[[SignatureView alloc] initWithBook:book_ database:database_ package:[href substringFromIndex:26]] autorelease];
-    else if ([href hasPrefix:@"cydia://package/"])
-        return [self pageForPackage:[href substringFromIndex:16]];
-    else if ([href hasPrefix:@"cydia://files/"]) {
-        NSString *name = [href substringFromIndex:14];
+    else if ([path hasPrefix:@"/url/"])
+        return [self _pageForURL:[NSURL URLWithString:[path substringFromIndex:5]] withClass:[BrowserView class]];
+    else if ([path hasPrefix:@"/launch/"])
+        [self launchApplicationWithIdentifier:[path substringFromIndex:8] suspended:NO];
+    else if ([path hasPrefix:@"/package-settings/"])
+        return [[[SettingsView alloc] initWithBook:book_ database:database_ package:[path substringFromIndex:18]] autorelease];
+    else if ([path hasPrefix:@"/package-signature/"])
+        return [[[SignatureView alloc] initWithBook:book_ database:database_ package:[path substringFromIndex:19]] autorelease];
+    else if ([path hasPrefix:@"/package/"])
+        return [self pageForPackage:[path substringFromIndex:9]];
+    else if ([path hasPrefix:@"/files/"]) {
+        NSString *name = [path substringFromIndex:7];
 
         if (Package *package = [database_ packageWithName:name]) {
             FileTable *files = [[[FileTable alloc] initWithBook:book_ database:database_] autorelease];
@@ -7349,22 +6844,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         [self finish];
 }
 
-/* Web Scripting {{{ */
-+ (NSString *) webScriptNameForSelector:(SEL)selector {
-    if (selector == @selector(supports:))
-        return @"supports";
-    return nil;
-}
-
-+ (BOOL) isSelectorExcludedFromWebScript:(SEL)selector {
-    return selector != @selector(supports:);
-}
-
-- (BOOL) supports:(NSString *)feature {
-    return [feature isEqualToString:@"window.open"];
-}
-/* }}} */
-
 - (void) showKeyboard:(BOOL)show {
     CGSize keysize = [UIKeyboard defaultSize];
     CGRect keydown = {{0, [overlay_ bounds].size.height}, keysize};
@@ -7452,6 +6931,8 @@ id Dealloc_(id self, SEL selector) {
 }*/
 
 int main(int argc, char *argv[]) { _pooled
+    class_addMethod(objc_getClass("DOMNodeList"), @selector(countByEnumeratingWithState:objects:count:), (IMP) &DOMNodeList$countByEnumeratingWithState$objects$count$, "I20@0:4^{NSFastEnumerationState}8^@12I16");
+
     bool substrate(false);
 
     if (argc != 0) {
@@ -7526,9 +7007,20 @@ int main(int argc, char *argv[]) { _pooled
 
     UniqueID_ = [[UIDevice currentDevice] uniqueIdentifier];
 
+    if (NSDictionary *system = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"])
+        Build_ = [system objectForKey:@"ProductBuildVersion"];
+
     /*AddPreferences(@"/Applications/Preferences.app/Settings-iPhone.plist");
     AddPreferences(@"/Applications/Preferences.app/Settings-iPod.plist");*/
 
+    /*if ((Indices_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/indices.plist"]) == NULL)
+        Indices_ = [[NSMutableDictionary alloc] init];*/
+
+    Indices_ = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+        @"http://"/*"cache.saurik.com/"*/"cydia.saurik.com/server/rating/@", @"Rating",
+        @"http://"/*"cache.saurik.com/"*/"cydia.saurik.com/repotag/@", @"RepoTag",
+    nil];
+
     if ((Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"]) == NULL)
         Metadata_ = [[NSMutableDictionary alloc] initWithCapacity:2];
     else {
@@ -7561,8 +7053,10 @@ int main(int argc, char *argv[]) { _pooled
     Documents_ = [[[NSMutableArray alloc] initWithCapacity:4] autorelease];
 #endif
 
-    if (substrate && access("/Library/MobileSubstrate/MobileSubstrate.dylib", F_OK) == 0)
-        dlopen("/Library/MobileSubstrate/MobileSubstrate.dylib", RTLD_LAZY | RTLD_GLOBAL);
+    if (substrate && access("/Applications/WinterBoard.app/WinterBoard.dylib", F_OK) == 0)
+        dlopen("/Applications/WinterBoard.app/WinterBoard.dylib", RTLD_LAZY | RTLD_GLOBAL);
+    /*if (substrate && access("/Library/MobileSubstrate/MobileSubstrate.dylib", F_OK) == 0)
+        dlopen("/Library/MobileSubstrate/MobileSubstrate.dylib", RTLD_LAZY | RTLD_GLOBAL);*/
 
     if (access("/User", F_OK) != 0)
         system("/usr/libexec/cydia/firmware.sh");