]> git.saurik.com Git - cydia.git/blobdiff - MobileCydia.mm
Rely on GetIndexes instead of ComputeIndexTargets.
[cydia.git] / MobileCydia.mm
index d253aa8b9bcfecac78e463ec20fd99e73ad351e6..900e76ed56f69fac1784374b658f9126315f3857 100644 (file)
@@ -1,40 +1,22 @@
 /* Cydia - iPhone UIKit Front-End for Debian APT
- * Copyright (C) 2008-2011  Jay Freeman (saurik)
+ * Copyright (C) 2008-2013  Jay Freeman (saurik)
 */
 
-/* Modified BSD License {{{ */
+/* GNU General Public License, Version 3 {{{ */
 /*
- *        Redistribution and use in source and binary
- * forms, with or without modification, are permitted
- * provided that the following conditions are met:
+ * Cydia is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation, either version 3 of the License,
+ * or (at your option) any later version.
  *
- * 1. Redistributions of source code must retain the
- *    above copyright notice, this list of conditions
- *    and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the
- *    above copyright notice, this list of conditions
- *    and the following disclaimer in the documentation
- *    and/or other materials provided with the
- *    distribution.
- * 3. The name of the author may not be used to endorse
- *    or promote products derived from this software
- *    without specific prior written permission.
+ * Cydia is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
+ * You should have received a copy of the GNU General Public License
+ * along with Cydia.  If not, see <http://www.gnu.org/licenses/>.
+**/
 /* }}} */
 
 // XXX: wtf/FastMalloc.h... wtf?
@@ -56,7 +38,6 @@
 #include <CoreFoundation/CFInternal.h>
 #endif
 
-#include <CoreFoundation/CFPriv.h>
 #include <CoreFoundation/CFUniChar.h>
 
 #include <SystemConfiguration/SystemConfiguration.h>
 
 #include <IOKit/IOKitLib.h>
 
+#include <QuartzCore/CALayer.h>
+
 #include <WebCore/WebCoreThread.h>
+#include <WebKit/DOMHTMLIFrameElement.h>
 
 #include <algorithm>
 #include <iomanip>
+#include <set>
 #include <sstream>
 #include <string>
 
@@ -119,19 +104,25 @@ extern "C" {
 #include <errno.h>
 
 #include <Cytore.hpp>
+#include "Sources.h"
 
+#include <CydiaSubstrate/CydiaSubstrate.h>
 #include "Menes/Menes.h"
 
+#include "CyteKit/IndirectDelegate.h"
 #include "CyteKit/PerlCompatibleRegEx.hpp"
+#include "CyteKit/TableViewCell.h"
+#include "CyteKit/TabBarController.h"
 #include "CyteKit/WebScriptObject-Cyte.h"
 #include "CyteKit/WebViewController.h"
+#include "CyteKit/WebViewTableViewCell.h"
 #include "CyteKit/stringWithUTF8Bytes.h"
 
+#include "Cydia/MIMEAddress.h"
+#include "Cydia/LoadingViewController.h"
 #include "Cydia/ProgressEvent.h"
 
 #include "SDURLCache/SDURLCache.h"
-
-#include <CydiaSubstrate/CydiaSubstrate.h>
 /* }}} */
 
 /* Profiler {{{ */
@@ -204,16 +195,11 @@ void PrintTimes() {
 #define _end }
 /* }}} */
 
-#define _pooled _H<NSAutoreleasePool> _pool([[NSAutoreleasePool alloc] init], true);
-
-#define CYPoolStart() \
-    NSAutoreleasePool *_pool([[NSAutoreleasePool alloc] init]); \
-    do
-#define CYPoolEnd() \
-    while (false); \
-    [_pool release];
+// XXX: I hate clang. Apple: please get over your petty hatred of GPL and fix your gcc fork
+#define synchronized(lock) \
+    synchronized(static_cast<NSObject *>(lock))
 
-#define Cydia_ CYDIA_VERSION
+extern NSString *Cydia_;
 
 #define lprintf(args...) fprintf(stderr, args)
 
@@ -251,6 +237,44 @@ union SplitHash {
 };
 // }}}
 
+static NSString *Colon_;
+NSString *Elision_;
+static NSString *Error_;
+static NSString *Warning_;
+
+static NSString *Cache_;
+
+static void (*$SBSSetInterceptsMenuButtonForever)(bool);
+
+static CFStringRef (*$MGCopyAnswer)(CFStringRef);
+
+static NSString *UniqueIdentifier(UIDevice *device = nil) {
+    if (kCFCoreFoundationVersionNumber < 800) // iOS 7.x
+        return [device ?: [UIDevice currentDevice] uniqueIdentifier];
+    else
+        return [(id)$MGCopyAnswer(CFSTR("UniqueDeviceID")) autorelease];
+}
+
+static bool IsReachable(const char *name) {
+    SCNetworkReachabilityFlags flags; {
+        SCNetworkReachabilityRef reachability(SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, name));
+        SCNetworkReachabilityGetFlags(reachability, &flags);
+        CFRelease(reachability);
+    }
+
+    // XXX: this elaborate mess is what Apple is using to determine this? :(
+    // XXX: do we care if the user has to intervene? maybe that's ok?
+    return
+        (flags & kSCNetworkReachabilityFlagsReachable) != 0 && (
+            (flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0 || (
+                (flags & kSCNetworkReachabilityFlagsConnectionOnDemand) != 0 ||
+                (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0
+            ) && (flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0 ||
+            (flags & kSCNetworkReachabilityFlagsIsWWAN) != 0
+        )
+    ;
+}
+
 static const NSUInteger UIViewAutoresizingFlexibleBoth(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
 
 static _finline NSString *CydiaURL(NSString *path) {
@@ -264,6 +288,15 @@ static _finline NSString *CydiaURL(NSString *path) {
     return [[NSString stringWithUTF8String:page] stringByAppendingString:path];
 }
 
+static void ReapZombie(pid_t pid) {
+    int status;
+  wait:
+    if (waitpid(pid, &status, 0) == -1)
+        if (errno == EINTR)
+            goto wait;
+        else _assert(false);
+}
+
 static _finline void UpdateExternalStatus(uint64_t newStatus) {
     int notify_token;
     if (notify_register_check("com.saurik.Cydia.status", &notify_token) == NOTIFY_STATUS_OK) {
@@ -273,88 +306,16 @@ static _finline void UpdateExternalStatus(uint64_t newStatus) {
     notify_post("com.saurik.Cydia.status");
 }
 
+static CGFloat CYStatusBarHeight() {
+    CGSize size([[UIApplication sharedApplication] statusBarFrame].size);
+    return UIInterfaceOrientationIsPortrait([[UIApplication sharedApplication] statusBarOrientation]) ? size.height : size.width;
+}
+
 /* NSForcedOrderingSearch doesn't work on the iPhone */
 static const NSStringCompareOptions MatchCompareOptions_ = NSLiteralSearch | NSCaseInsensitiveSearch;
 static const NSStringCompareOptions LaxCompareOptions_ = NSNumericSearch | NSDiacriticInsensitiveSearch | NSWidthInsensitiveSearch | NSCaseInsensitiveSearch;
 static const CFStringCompareFlags LaxCompareFlags_ = kCFCompareCaseInsensitive | kCFCompareNonliteral | kCFCompareLocalized | kCFCompareNumerically | kCFCompareWidthInsensitive | kCFCompareForcedOrdering;
 
-/* Radix Sort {{{ */
-typedef uint32_t (*SKRadixFunction)(id, void *);
-
-@interface NSMutableArray (Radix)
-- (void) radixSortUsingFunction:(SKRadixFunction)function withContext:(void *)argument;
-@end
-
-struct RadixItem_ {
-    size_t index;
-    uint32_t key;
-};
-
-@implementation NSMutableArray (Radix)
-
-- (void) radixSortUsingFunction:(SKRadixFunction)function withContext:(void *)argument {
-    size_t count([self count]);
-    struct RadixItem_ *swap(new RadixItem_[count * 2]);
-
-    for (size_t i(0); i != count; ++i) {
-        RadixItem_ &item(swap[i]);
-        item.index = i;
-
-        id object([self objectAtIndex:i]);
-        item.key = function(object, argument);
-    }
-
-    struct RadixItem_ *lhs(swap), *rhs(swap + count);
-
-    static const size_t width = 32;
-    static const size_t bits = 11;
-    static const size_t slots = 1 << bits;
-    static const size_t passes = (width + (bits - 1)) / bits;
-
-    size_t *hist(new size_t[slots]);
-
-    for (size_t pass(0); pass != passes; ++pass) {
-        memset(hist, 0, sizeof(size_t) * slots);
-
-        for (size_t i(0); i != count; ++i) {
-            uint32_t key(lhs[i].key);
-            key >>= pass * bits;
-            key &= _not(uint32_t) >> width - bits;
-            ++hist[key];
-        }
-
-        size_t offset(0);
-        for (size_t i(0); i != slots; ++i) {
-            size_t local(offset);
-            offset += hist[i];
-            hist[i] = local;
-        }
-
-        for (size_t i(0); i != count; ++i) {
-            uint32_t key(lhs[i].key);
-            key >>= pass * bits;
-            key &= _not(uint32_t) >> width - bits;
-            rhs[hist[key]++] = lhs[i];
-        }
-
-        RadixItem_ *tmp(lhs);
-        lhs = rhs;
-        rhs = tmp;
-    }
-
-    delete [] hist;
-
-    const void **values(new const void *[count]);
-    for (size_t i(0); i != count; ++i)
-        values[i] = [self objectAtIndex:lhs[i].index];
-    CFArrayReplaceValues((CFMutableArrayRef) self, CFRangeMake(0, count), values, count);
-    delete [] values;
-
-    delete [] swap;
-}
-
-@end
-/* }}} */
 /* Insertion Sort {{{ */
 
 CFIndex SKBSearch_(const void *element, CFIndex elementSize, const void *list, CFIndex count, CFComparatorFunction comparator, void *context) {
@@ -475,7 +436,6 @@ NSUInteger DOMNodeList$countByEnumeratingWithState$objects$count$(DOMNodeList *s
 /* Cydia NSString Additions {{{ */
 @interface NSString (Cydia)
 - (NSComparisonResult) compareByPath:(NSString *)other;
-- (NSString *) stringByCachingURLWithCurrentCDN;
 - (NSString *) stringByAddingPercentEscapesIncludingReserved;
 @end
 
@@ -511,13 +471,6 @@ NSUInteger DOMNodeList$countByEnumeratingWithState$objects$count$(DOMNodeList *s
     return result == NSOrderedSame ? value : result;
 }
 
-- (NSString *) stringByCachingURLWithCurrentCDN {
-    return [self
-        stringByReplacingOccurrencesOfString:@"://cydia.saurik.com/"
-        withString:@"://cache.cydia.saurik.com/"
-    ];
-}
-
 - (NSString *) stringByAddingPercentEscapesIncludingReserved {
     return [(id)CFURLCreateStringByAddingPercentEscapes(
         kCFAllocatorDefault,
@@ -674,74 +627,6 @@ struct NSStringMapEqual :
 };
 /* }}} */
 
-/* Mime Addresses {{{ */
-@interface Address : NSObject {
-    _H<NSString> name_;
-    _H<NSString> address_;
-}
-
-- (NSString *) name;
-- (NSString *) address;
-
-- (void) setAddress:(NSString *)address;
-
-+ (Address *) addressWithString:(NSString *)string;
-- (Address *) initWithString:(NSString *)string;
-
-@end
-
-@implementation Address
-
-- (NSString *) name {
-    return name_;
-}
-
-- (NSString *) address {
-    return address_;
-}
-
-- (void) setAddress:(NSString *)address {
-    address_ = address;
-}
-
-+ (Address *) addressWithString:(NSString *)string {
-    return [[[Address alloc] initWithString:string] autorelease];
-}
-
-+ (NSArray *) _attributeKeys {
-    return [NSArray arrayWithObjects:
-        @"address",
-        @"name",
-    nil];
-}
-
-- (NSArray *) attributeKeys {
-    return [[self class] _attributeKeys];
-}
-
-+ (BOOL) isKeyExcludedFromWebScript:(const char *)name {
-    return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name];
-}
-
-- (Address *) initWithString:(NSString *)string {
-    if ((self = [super init]) != nil) {
-        const char *data = [string UTF8String];
-        size_t size = [string length];
-
-        static Pcre address_r("^\"?(.*)\"? <([^>]*)>$");
-
-        if (address_r(data, size)) {
-            name_ = address_r[1];
-            address_ = address_r[2];
-        } else {
-            name_ = string;
-            address_ = nil;
-        }
-    } return self;
-}
-
-@end
-/* }}} */
 /* CoreGraphics Primitives {{{ */
 class CYColor {
   private:
@@ -785,7 +670,7 @@ class CYColor {
 /* }}} */
 
 /* Random Global Variables {{{ */
-static const int PulseInterval_ = 50000;
+static int PulseInterval_ = 500000;
 
 static const NSString *UI_;
 
@@ -801,6 +686,7 @@ static bool Queuing_;
 static CYColor Blue_;
 static CYColor Blueish_;
 static CYColor Black_;
+static CYColor Folder_;
 static CYColor Off_;
 static CYColor White_;
 static CYColor Gray_;
@@ -819,20 +705,20 @@ static BOOL Ignored_;
 static _H<UIFont> Font12_;
 static _H<UIFont> Font12Bold_;
 static _H<UIFont> Font14_;
+static _H<UIFont> Font18_;
 static _H<UIFont> Font18Bold_;
 static _H<UIFont> Font22Bold_;
 
 static const char *Machine_ = NULL;
-static NSString *System_ = nil;
+static _H<NSString> System_;
 static NSString *SerialNumber_ = nil;
 static NSString *ChipID_ = nil;
 static NSString *BBSNum_ = nil;
 static _H<NSString> Token_;
-static NSString *UniqueID_ = nil;
-static NSString *PLMN_ = nil;
-static NSString *Build_ = nil;
-static NSString *Product_ = nil;
-static NSString *Safari_ = nil;
+static _H<NSString> UniqueID_;
+static _H<NSString> UserAgent_;
+static _H<NSString> Product_;
+static _H<NSString> Safari_;
 
 static CFLocaleRef Locale_;
 static NSArray *Languages_;
@@ -841,21 +727,27 @@ static CGColorSpaceRef space_;
 static NSDictionary *SectionMap_;
 static NSMutableDictionary *Metadata_;
 static _transient NSMutableDictionary *Settings_;
-static _transient NSString *Role_;
 static _transient NSMutableDictionary *Packages_;
+static _transient NSMutableDictionary *Values_;
 static _transient NSMutableDictionary *Sections_;
-static _transient NSMutableDictionary *Sources_;
-static bool Changed_;
+_H<NSMutableDictionary> Sources_;
+static _transient NSNumber *Version_;
+bool Changed_;
 static time_t now_;
 
 bool IsWildcat_;
 static CGFloat ScreenScale_;
 static NSString *Idiom_;
+static _H<NSString> Firmware_;
+static NSString *Major_;
 
 static _H<NSMutableDictionary> SessionData_;
 static _H<NSObject> HostConfig_;
 static _H<NSMutableSet> BridgedHosts_;
+static _H<NSMutableSet> TokenHosts_;
+static _H<NSMutableSet> InsecureHosts_;
 static _H<NSMutableSet> PipelinedHosts_;
+static _H<NSMutableSet> CachedURLs_;
 
 static NSString *kCydiaProgressEventTypeError = @"Error";
 static NSString *kCydiaProgressEventTypeInformation = @"Information";
@@ -971,7 +863,19 @@ static NSString *CYHex(NSData *data, bool reverse = false) {
 
 @class CYPackageController;
 
+@protocol SourceDelegate
+- (void) setFetch:(NSNumber *)fetch;
+@end
+
+@protocol FetchDelegate
+- (bool) isSourceCancelled;
+- (void) startSourceFetch:(NSString *)uri;
+- (void) stopSourceFetch:(NSString *)uri;
+@end
+
 @protocol CydiaDelegate
+- (void) returnToCydia;
+- (void) saveState;
 - (void) retainNetworkActivityIndicator;
 - (void) releaseNetworkActivityIndicator;
 - (void) clearPackage:(Package *)package;
@@ -980,48 +884,73 @@ static NSString *CYHex(NSData *data, bool reverse = false) {
 - (void) removePackage:(Package *)package;
 - (void) beginUpdate;
 - (BOOL) updating;
+- (bool) requestUpdate;
 - (void) distUpgrade;
 - (void) loadData;
 - (void) updateData;
+- (void) _saveConfig;
 - (void) syncData;
+- (void) addSource:(NSDictionary *)source;
 - (void) addTrivialSource:(NSString *)href;
-- (void) showSettings;
 - (UIProgressHUD *) addProgressHUD;
 - (void) removeProgressHUD:(UIProgressHUD *)hud;
-- (CyteViewController *) pageForPackage:(NSString *)name;
 - (void) showActionSheet:(UIActionSheet *)sheet fromItem:(UIBarButtonItem *)item;
 - (void) reloadDataWithInvocation:(NSInvocation *)invocation;
 @end
 /* }}} */
 
-/* Status Delegation {{{ */
-class Status :
+/* CancelStatus {{{ */
+class CancelStatus :
     public pkgAcquireStatus
 {
   private:
-    _transient NSObject<ProgressDelegate> *delegate_;
     bool cancelled_;
 
   public:
-    Status() :
-        delegate_(nil),
+    CancelStatus() :
         cancelled_(false)
     {
     }
 
-    void setDelegate(NSObject<ProgressDelegate> *delegate) {
-        delegate_ = delegate;
+    virtual bool MediaChange(std::string media, std::string drive) {
+        return false;
+    }
+
+    virtual void IMSHit(pkgAcquire::ItemDesc &item) {
+        Done(item);
     }
 
-    NSObject<ProgressDelegate> *getDelegate() const {
-        return delegate_;
+    virtual bool Pulse_(pkgAcquire *Owner) = 0;
+
+    virtual bool Pulse(pkgAcquire *Owner) {
+        if (pkgAcquireStatus::Pulse(Owner) && Pulse_(Owner))
+            return true;
+        else {
+            cancelled_ = true;
+            return false;
+        }
     }
 
-    virtual bool MediaChange(std::string media, std::string drive) {
-        return false;
+    _finline bool WasCancelled() const {
+        return cancelled_;
+    }
+};
+/* }}} */
+/* DelegateStatus {{{ */
+class CydiaStatus :
+    public CancelStatus
+{
+  private:
+    _transient NSObject<ProgressDelegate> *delegate_;
+
+  public:
+    CydiaStatus() :
+        delegate_(nil)
+    {
     }
 
-    virtual void IMSHit(pkgAcquire::ItemDesc &item) {
+    void setDelegate(NSObject<ProgressDelegate> *delegate) {
+        delegate_ = delegate;
     }
 
     virtual void Fetch(pkgAcquire::ItemDesc &item) {
@@ -1031,6 +960,9 @@ class Status :
     }
 
     virtual void Done(pkgAcquire::ItemDesc &item) {
+        NSString *name([NSString stringWithUTF8String:item.ShortDesc.c_str()]);
+        CydiaProgressEvent *event([CydiaProgressEvent eventWithMessage:[NSString stringWithFormat:Colon_, UCLocalize("DONE"), name] ofType:kCydiaProgressEventTypeStatus forItem:item]);
+        [delegate_ performSelectorOnMainThread:@selector(addProgressEvent:) withObject:event waitUntilDone:YES];
     }
 
     virtual void Fail(pkgAcquire::ItemDesc &item) {
@@ -1048,9 +980,7 @@ class Status :
         [delegate_ performSelectorOnMainThread:@selector(addProgressEvent:) withObject:event waitUntilDone:YES];
     }
 
-    virtual bool Pulse(pkgAcquire *Owner) {
-        bool value = pkgAcquireStatus::Pulse(Owner);
-
+    virtual bool Pulse_(pkgAcquire *Owner) {
         double percent(
             double(CurrentBytes + CurrentItems) /
             double(TotalBytes + TotalItems)
@@ -1064,16 +994,7 @@ class Status :
             [NSNumber numberWithDouble:CurrentCPS], @"Speed",
         nil] waitUntilDone:YES];
 
-        if (value && ![delegate_ isProgressCancelled])
-            return true;
-        else {
-            cancelled_ = true;
-            return false;
-        }
-    }
-
-    _finline bool WasCancelled() const {
-        return cancelled_;
+        return ![delegate_ isProgressCancelled];
     }
 
     virtual void Start() {
@@ -1114,7 +1035,7 @@ typedef std::map< unsigned long, _H<Source> > SourceMap;
     _transient NSObject<DatabaseDelegate> *delegate_;
     _transient NSObject<ProgressDelegate> *progress_;
 
-    Status status_;
+    CydiaStatus status_;
 
     int cydiafd_;
     int statusfd_;
@@ -1151,7 +1072,7 @@ typedef std::map< unsigned long, _H<Source> > SourceMap;
 - (bool) upgrade;
 - (void) update;
 
-- (void) updateWithStatus:(Status &)status;
+- (void) updateWithStatus:(CancelStatus &)status;
 
 - (void) setDelegate:(NSObject<DatabaseDelegate> *)delegate;
 
@@ -1159,11 +1080,61 @@ typedef std::map< unsigned long, _H<Source> > SourceMap;
 - (NSObject<ProgressDelegate> *) progressDelegate;
 
 - (Source *) getSource:(pkgCache::PkgFileIterator)file;
+- (void) setFetch:(bool)fetch forURI:(const char *)uri;
+- (void) resetFetch;
 
 - (NSString *) mappedSectionForPointer:(const char *)pointer;
 
 @end
 /* }}} */
+/* SourceStatus {{{ */
+class SourceStatus :
+    public CancelStatus
+{
+  private:
+    _transient NSObject<FetchDelegate> *delegate_;
+    _transient Database *database_;
+
+  public:
+    SourceStatus(NSObject<FetchDelegate> *delegate, Database *database) :
+        delegate_(delegate),
+        database_(database)
+    {
+    }
+
+    void Set(bool fetch, pkgAcquire::ItemDesc &desc) {
+        desc.Owner->ID = 0;
+        [database_ setFetch:fetch forURI:desc.Owner->DescURI().c_str()];
+    }
+
+    virtual void Fetch(pkgAcquire::ItemDesc &desc) {
+        Set(true, desc);
+    }
+
+    virtual void Done(pkgAcquire::ItemDesc &desc) {
+        Set(false, desc);
+    }
+
+    virtual void Fail(pkgAcquire::ItemDesc &desc) {
+        Set(false, desc);
+    }
+
+    virtual bool Pulse_(pkgAcquire *Owner) {
+        for (pkgAcquire::ItemCIterator item = Owner->ItemsBegin(); item != Owner->ItemsEnd(); ++item)
+            if ((*item)->ID != 0);
+            else if ((*item)->Status == pkgAcquire::Item::StatIdle) {
+                (*item)->ID = 1;
+                [database_ setFetch:true forURI:(*item)->DescURI().c_str()];
+            } else (*item)->ID = 0;
+        return ![delegate_ isSourceCancelled];
+    }
+
+    virtual void Stop() {
+        pkgAcquireStatus::Stop();
+        [database_ resetFetch];
+    }
+};
+/* }}} */
 /* ProgressEvent Implementation {{{ */
 @implementation CydiaProgressEvent
 
@@ -1405,6 +1376,10 @@ static void PackageImport(const void *key, const void *value, void *context) {
 
 /* Source Class {{{ */
 @interface Source : NSObject {
+    unsigned era_;
+    Database *database_;
+    metaIndex *index_;
+
     CYString depiction_;
     CYString description_;
     CYString label_;
@@ -1414,6 +1389,7 @@ static void PackageImport(const void *key, const void *value, void *context) {
     CYString uri_;
     CYString distribution_;
     CYString type_;
+    CYString base_;
     CYString version_;
 
     _H<NSString> host_;
@@ -1421,23 +1397,29 @@ static void PackageImport(const void *key, const void *value, void *context) {
 
     CYString defaultIcon_;
 
-    _H<NSDictionary> record_;
+    _H<NSMutableDictionary> record_;
     BOOL trusted_;
+
+    std::set<std::string> fetches_;
+    std::set<std::string> files_;
+    _transient NSObject<SourceDelegate> *delegate_;
 }
 
-- (Source *) initWithMetaIndex:(metaIndex *)index inPool:(apr_pool_t *)pool;
+- (Source *) initWithMetaIndex:(metaIndex *)index forDatabase:(Database *)database inPool:(apr_pool_t *)pool;
 
-- (NSComparisonResult) compareByNameAndType:(Source *)source;
+- (NSComparisonResult) compareByName:(Source *)source;
 
 - (NSString *) depictionForPackage:(NSString *)package;
 - (NSString *) supportForPackage:(NSString *)package;
 
+- (metaIndex *) metaIndex;
 - (NSDictionary *) record;
 - (BOOL) trusted;
 
-- (NSString *) uri;
+- (NSString *) rooturi;
 - (NSString *) distribution;
 - (NSString *) type;
+
 - (NSString *) key;
 - (NSString *) host;
 
@@ -1448,41 +1430,48 @@ static void PackageImport(const void *key, const void *value, void *context) {
 - (NSString *) version;
 
 - (NSString *) defaultIcon;
+- (NSURL *) iconURL;
+
+- (void) setFetch:(bool)fetch forURI:(const char *)uri;
+- (void) resetFetch;
 
 @end
 
 @implementation Source
 
-- (void) _clear {
-    uri_.clear();
-    distribution_.clear();
-    type_.clear();
-
-    description_.clear();
-    label_.clear();
-    origin_.clear();
-    depiction_.clear();
-    support_.clear();
-    version_.clear();
-    defaultIcon_.clear();
++ (NSString *) webScriptNameForSelector:(SEL)selector {
+    if (false);
+    else if (selector == @selector(addSection:))
+        return @"addSection";
+    else if (selector == @selector(getField:))
+        return @"getField";
+    else if (selector == @selector(removeSection:))
+        return @"removeSection";
+    else if (selector == @selector(remove))
+        return @"remove";
+    else
+        return nil;
+}
 
-    record_ = nil;
-    host_ = nil;
-    authority_ = nil;
++ (BOOL) isSelectorExcludedFromWebScript:(SEL)selector {
+    return [self webScriptNameForSelector:selector] == nil;
 }
 
 + (NSArray *) _attributeKeys {
     return [NSArray arrayWithObjects:
+        @"baseuri",
         @"distribution",
         @"host",
         @"key",
+        @"iconuri",
         @"label",
         @"name",
         @"origin",
+        @"rooturi",
+        @"sections",
         @"shortDescription",
         @"trusted",
         @"type",
-        @"uri",
         @"version",
     nil];
 }
@@ -1495,9 +1484,11 @@ static void PackageImport(const void *key, const void *value, void *context) {
     return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name];
 }
 
-- (void) setMetaIndex:(metaIndex *)index inPool:(apr_pool_t *)pool {
-    [self _clear];
+- (metaIndex *) metaIndex {
+    return index_;
+}
 
+- (void) setMetaIndex:(metaIndex *)index inPool:(apr_pool_t *)pool {
     trusted_ = index->IsTrusted();
 
     uri_.set(pool, index->GetURI());
@@ -1506,6 +1497,22 @@ static void PackageImport(const void *key, const void *value, void *context) {
 
     debReleaseIndex *dindex(dynamic_cast<debReleaseIndex *>(index));
     if (dindex != NULL) {
+        std::string file(dindex->MetaIndexURI(""));
+        base_.set(pool, file);
+
+        pkgAcquire acquire;
+        dindex->GetIndexes(&acquire, true);
+        for (pkgAcquire::ItemIterator item(acquire.ItemsBegin()); item != acquire.ItemsEnd(); item++) {
+            std::string file((*item)->DescURI());
+            files_.insert(file);
+            if (file.length() < sizeof("Packages.bz2") || file.substr(file.length() - sizeof("Packages.bz2")) != "/Packages.bz2")
+                continue;
+            file = file.substr(0, file.length() - 4);
+            files_.insert(file);
+            files_.insert(file + ".gz");
+            files_.insert(file + "Index");
+        }
+
         FileFd fd;
         if (!fd.Open(dindex->MetaIndexFile("Release"), FileFd::ReadOnly))
             _error->Discard();
@@ -1548,25 +1555,49 @@ static void PackageImport(const void *key, const void *value, void *context) {
         host_ = [host_ lowercaseString];
 
     if (host_ != nil)
-        // XXX: this is due to a bug in _H<>
-        authority_ = (id) host_;
+        authority_ = host_;
     else
         authority_ = [url path];
 }
 
-- (Source *) initWithMetaIndex:(metaIndex *)index inPool:(apr_pool_t *)pool {
+- (Source *) initWithMetaIndex:(metaIndex *)index forDatabase:(Database *)database inPool:(apr_pool_t *)pool {
     if ((self = [super init]) != nil) {
+        era_ = [database era];
+        database_ = database;
+        index_ = index;
+
         [self setMetaIndex:index inPool:pool];
     } return self;
 }
 
-- (NSComparisonResult) compareByNameAndType:(Source *)source {
-    NSDictionary *lhr = [self record];
-    NSDictionary *rhr = [source record];
+- (NSString *) getField:(NSString *)name {
+@synchronized (database_) {
+    if ([database_ era] != era_ || index_ == NULL)
+        return nil;
+
+    debReleaseIndex *dindex(dynamic_cast<debReleaseIndex *>(index_));
+    if (dindex == NULL)
+        return nil;
+
+    FileFd fd;
+    if (!fd.Open(dindex->MetaIndexFile("Release"), FileFd::ReadOnly)) {
+         _error->Discard();
+         return nil;
+    }
+
+    pkgTagFile tags(&fd);
+
+    pkgTagSection section;
+    tags.Step(section);
 
-    if (lhr != rhr)
-        return lhr == nil ? NSOrderedDescending : NSOrderedAscending;
+    const char *start, *end;
+    if (!section.Find([name UTF8String], start, end))
+        return (NSString *) [NSNull null];
+
+    return [NSString stringWithString:[(NSString *) CYStringCreate(start, end - start) autorelease]];
+} }
 
+- (NSComparisonResult) compareByName:(Source *)source {
     NSString *lhs = [self name];
     NSString *rhs = [source name];
 
@@ -1591,27 +1622,100 @@ static void PackageImport(const void *key, const void *value, void *context) {
     return support_.empty() ? nil : [static_cast<id>(support_) stringByReplacingOccurrencesOfString:@"*" withString:package];
 }
 
-- (NSDictionary *) record {
-    return record_;
+- (NSArray *) sections {
+    return record_ == nil ? (id) [NSNull null] : [record_ objectForKey:@"Sections"] ?: [NSArray array];
 }
 
-- (BOOL) trusted {
-    return trusted_;
+- (void) _addSection:(NSString *)section {
+    if (record_ == nil)
+        return;
+    else if (NSMutableArray *sections = [record_ objectForKey:@"Sections"]) {
+        if (![sections containsObject:section]) {
+            [sections addObject:section];
+            Changed_ = true;
+        }
+    } else {
+        [record_ setObject:[NSMutableArray arrayWithObject:section] forKey:@"Sections"];
+        Changed_ = true;
+    }
 }
 
-- (NSString *) uri {
-    return uri_;
-}
+- (bool) addSection:(NSString *)section {
+    if (record_ == nil)
+        return false;
 
-- (NSString *) distribution {
-    return distribution_;
+    [self performSelectorOnMainThread:@selector(_addSection:) withObject:section waitUntilDone:NO];
+    return true;
 }
 
-- (NSString *) type {
-    return type_;
+- (void) _removeSection:(NSString *)section {
+    if (record_ == nil)
+        return;
+
+    if (NSMutableArray *sections = [record_ objectForKey:@"Sections"])
+        if ([sections containsObject:section]) {
+            [sections removeObject:section];
+            Changed_ = true;
+        }
 }
 
-- (NSString *) key {
+- (bool) removeSection:(NSString *)section {
+    if (record_ == nil)
+        return false;
+
+    [self performSelectorOnMainThread:@selector(_removeSection:) withObject:section waitUntilDone:NO];
+    return true;
+}
+
+- (void) _remove {
+    [Sources_ removeObjectForKey:[self key]];
+    Changed_ = true;
+}
+
+- (bool) remove {
+    bool value(record_ != nil);
+    [self performSelectorOnMainThread:@selector(_remove) withObject:nil waitUntilDone:NO];
+    return value;
+}
+
+- (NSDictionary *) record {
+    return record_;
+}
+
+- (BOOL) trusted {
+    return trusted_;
+}
+
+- (NSString *) rooturi {
+    return uri_;
+}
+
+- (NSString *) distribution {
+    return distribution_;
+}
+
+- (NSString *) type {
+    return type_;
+}
+
+- (NSString *) baseuri {
+    return base_.empty() ? nil : (id) base_;
+}
+
+- (NSString *) iconuri {
+    if (NSString *base = [self baseuri])
+        return [base stringByAppendingString:@"CydiaIcon.png"];
+
+    return nil;
+}
+
+- (NSURL *) iconURL {
+    if (NSString *uri = [self iconuri])
+        return [NSURL URLWithString:uri];
+    return nil;
+}
+
+- (NSString *) key {
     return [NSString stringWithFormat:@"%@:%@:%@", (NSString *) type_, (NSString *) uri_, (NSString *) distribution_];
 }
 
@@ -1643,6 +1747,31 @@ static void PackageImport(const void *key, const void *value, void *context) {
     return defaultIcon_;
 }
 
+- (void) setDelegate:(NSObject<SourceDelegate> *)delegate {
+    delegate_ = delegate;
+}
+
+- (bool) fetch {
+    return !fetches_.empty();
+}
+
+- (void) setFetch:(bool)fetch forURI:(const char *)uri {
+    if (!fetch) {
+        if (fetches_.erase(uri) == 0)
+            return;
+    } else if (files_.find(uri) == files_.end())
+        return;
+    else if (!fetches_.insert(uri).second)
+        return;
+
+    [delegate_ performSelectorOnMainThread:@selector(setFetch:) withObject:[NSNumber numberWithBool:[self fetch]] waitUntilDone:NO];
+}
+
+- (void) resetFetch {
+    fetches_.clear();
+    [delegate_ performSelectorOnMainThread:@selector(setFetch:) withObject:[NSNumber numberWithBool:NO] waitUntilDone:NO];
+}
+
 @end
 /* }}} */
 /* CydiaOperation Class {{{ */
@@ -1803,29 +1932,31 @@ static void PackageImport(const void *key, const void *value, void *context) {
 /* }}} */
 /* Package Class {{{ */
 struct ParsedPackage {
+    CYString md5sum_;
     CYString tagline_;
 
+    CYString architecture_;
     CYString icon_;
 
     CYString depiction_;
     CYString homepage_;
-
-    CYString sponsor_;
     CYString author_;
 
-    CYString bugs_;
     CYString support_;
 };
 
 @interface Package : NSObject {
-    uint32_t era_ : 26;
+    uint32_t era_ : 25;
     uint32_t role_ : 3;
     uint32_t essential_ : 1;
     uint32_t obsolete_ : 1;
     uint32_t ignored_ : 1;
+    uint32_t pooled_ : 1;
 
     apr_pool_t *pool_;
 
+    uint32_t rank_;
+
     _transient Database *database_;
 
     pkgCache::VerIterator version_;
@@ -1863,7 +1994,7 @@ struct ParsedPackage {
 
 - (NSString *) uri;
 
-- (Address *) maintainer;
+- (MIMEAddress *) maintainer;
 - (size_t) size;
 - (NSString *) longDescription;
 - (NSString *) shortDescription;
@@ -1899,7 +2030,7 @@ struct ParsedPackage {
 - (UIImage *) icon;
 - (NSString *) homepage;
 - (NSString *) depiction;
-- (Address *) author;
+- (MIMEAddress *) author;
 
 - (NSString *) support;
 
@@ -1909,9 +2040,9 @@ struct ParsedPackage {
 
 - (Source *) source;
 
-- (BOOL) matches:(NSString *)text;
+- (uint32_t) rank;
+- (BOOL) matches:(NSArray *)query;
 
-- (bool) hasSupportingRole;
 - (BOOL) hasTag:(NSString *)tag;
 - (NSString *) primaryPurpose;
 - (NSArray *) purposes;
@@ -1926,10 +2057,10 @@ struct ParsedPackage {
 - (void) install;
 - (void) remove;
 
-- (bool) isUnfilteredAndSearchedForBy:(NSString *)search;
+- (bool) isUnfilteredAndSearchedForBy:(NSArray *)query;
 - (bool) isUnfilteredAndSelectedForBy:(NSString *)search;
 - (bool) isInstalledAndUnfiltered:(NSNumber *)number;
-- (bool) isVisibleInSection:(NSString *)section;
+- (bool) isVisibleInSection:(NSString *)section source:(Source *)source;
 - (bool) isVisibleInSource:(Source *)source;
 
 @end
@@ -2025,9 +2156,9 @@ CFComparisonResult PackageNameCompare(Package *lhs, Package *rhs, void *arg) {
         CFStringRef lhn(lhi), rhn(rhi);
 
         if (lhn == NULL)
-            return rhn == NULL ? NSOrderedSame : NSOrderedAscending;
+            return rhn == NULL ? kCFCompareEqualTo : kCFCompareLessThan;
         else if (rhn == NULL)
-            return NSOrderedDescending;
+            return kCFCompareGreaterThan;
 
         _profile(PackageNameCompare$NumbersLast)
             if (!lhi.empty() && !rhi.empty()) {
@@ -2035,7 +2166,7 @@ CFComparisonResult PackageNameCompare(Package *lhs, Package *rhs, void *arg) {
                 UniChar rhc(CFStringGetCharacterAtIndex(rhn, 0));
                 bool lha(CFUniCharIsMemberOf(lhc, kCFUniCharLetterCharacterSet));
                 if (lha != CFUniCharIsMemberOf(rhc, kCFUniCharLetterCharacterSet))
-                    return lha ? NSOrderedAscending : NSOrderedDescending;
+                    return lha ? kCFCompareLessThan : kCFCompareGreaterThan;
             }
         _end
 
@@ -2055,7 +2186,7 @@ struct PackageNameOrdering :
     std::binary_function<Package *, Package *, bool>
 {
     _finline bool operator ()(Package *lhs, Package *rhs) const {
-        return PackageNameCompare(lhs, rhs, NULL) == NSOrderedAscending;
+        return PackageNameCompare(lhs, rhs, NULL) == kCFCompareLessThan;
     }
 };
 
@@ -2066,6 +2197,8 @@ struct PackageNameOrdering :
 }
 
 - (void) dealloc {
+    if (!pooled_)
+        apr_pool_destroy(pool_);
     if (parsed_ != NULL)
         delete parsed_;
     [super dealloc];
@@ -2077,6 +2210,8 @@ struct PackageNameOrdering :
         return @"clear";
     else if (selector == @selector(getField:))
         return @"getField";
+    else if (selector == @selector(getRecord))
+        return @"getRecord";
     else if (selector == @selector(hasTag:))
         return @"hasTag";
     else if (selector == @selector(install))
@@ -2094,6 +2229,7 @@ struct PackageNameOrdering :
 + (NSArray *) _attributeKeys {
     return [NSArray arrayWithObjects:
         @"applications",
+        @"architecture",
         @"author",
         @"depiction",
         @"essential",
@@ -2105,6 +2241,7 @@ struct PackageNameOrdering :
         @"longDescription",
         @"longSection",
         @"maintainer",
+        @"md5sum",
         @"mode",
         @"name",
         @"purposes",
@@ -2116,7 +2253,6 @@ struct PackageNameOrdering :
         @"simpleSection",
         @"size",
         @"source",
-        @"sponsor",
         @"state",
         @"support",
         @"tags",
@@ -2140,6 +2276,12 @@ struct PackageNameOrdering :
     return relations;
 } }
 
+- (NSString *) architecture {
+    [self parse];
+@synchronized (database_) {
+    return parsed_->architecture_.empty() ? [NSNull null] : (id) parsed_->architecture_;
+} }
+
 - (NSString *) getField:(NSString *)name {
 @synchronized (database_) {
     if ([database_ era] != era_ || file_.end())
@@ -2151,7 +2293,20 @@ struct PackageNameOrdering :
     if (!parser.Find([name UTF8String], start, end))
         return (NSString *) [NSNull null];
 
-    return [(NSString *) CYStringCreate(start, end - start) autorelease];
+    return [NSString stringWithString:[(NSString *) CYStringCreate(start, end - start) autorelease]];
+} }
+
+- (NSString *) getRecord {
+@synchronized (database_) {
+    if ([database_ era] != era_ || file_.end())
+        return nil;
+
+    pkgRecords::Parser &parser([database_ records]->Lookup(file_));
+
+    const char *start, *end;
+    parser.GetRec(start, end);
+
+    return [NSString stringWithString:[(NSString *) CYStringCreate(start, end - start) autorelease]];
 } }
 
 - (void) parse {
@@ -2171,6 +2326,7 @@ struct PackageNameOrdering :
             parser = &[database_ records]->Lookup(file_);
         _end
 
+        CYString bugs;
         CYString website;
 
         _profile(Package$parse$Find)
@@ -2178,14 +2334,15 @@ struct PackageNameOrdering :
                 const char *name_;
                 CYString *value_;
             } names[] = {
+                {"architecture", &parsed->architecture_},
                 {"icon", &parsed->icon_},
                 {"depiction", &parsed->depiction_},
                 {"homepage", &parsed->homepage_},
                 {"website", &website},
-                {"bugs", &parsed->bugs_},
+                {"bugs", &bugs},
                 {"support", &parsed->support_},
-                {"sponsor", &parsed->sponsor_},
                 {"author", &parsed->author_},
+                {"md5sum", &parsed->md5sum_},
             };
 
             for (size_t i(0); i != sizeof(names) / sizeof(names[0]); ++i) {
@@ -2217,6 +2374,8 @@ struct PackageNameOrdering :
                 parsed->homepage_ = website;
             if (parsed->homepage_ == parsed->depiction_)
                 parsed->homepage_.clear();
+            if (parsed->support_.empty())
+                parsed->support_ = bugs;
         _end
     _end
 } }
@@ -2224,7 +2383,12 @@ struct PackageNameOrdering :
 - (Package *) initWithVersion:(pkgCache::VerIterator)version withZone:(NSZone *)zone inPool:(apr_pool_t *)pool database:(Database *)database {
     if ((self = [super init]) != nil) {
     _profile(Package$initWithVersion)
-        pool_ = pool;
+        if (pool == NULL)
+            apr_pool_create(&pool_, NULL);
+        else {
+            pool_ = pool;
+            pooled_ = true;
+        }
 
         database_ = database;
         era_ = [database era];
@@ -2257,9 +2421,14 @@ struct PackageNameOrdering :
             pkgCache::TagIterator tag(iterator.TagList());
             if (!tag.end()) {
                 tags_ = [NSMutableArray arrayWithCapacity:8];
-                do {
+
+                goto tag; for (; !tag.end(); ++tag) tag: {
                     const char *name(tag.Name());
-                    [tags_ addObject:[(NSString *)CYStringCreate(name) autorelease]];
+                    NSString *string((NSString *) CYStringCreate(name));
+                    if (string == nil)
+                        continue;
+
+                    [tags_ addObject:[string autorelease]];
 
                     if (role_ == 0 && strncmp(name, "role::", 6) == 0 /*&& strcmp(name, "role::leaper") != 0*/) {
                         if (strcmp(name + 6, "enduser") == 0)
@@ -2280,9 +2449,7 @@ struct PackageNameOrdering :
                         else if (strcmp(name + 7, "obsolete") == 0)
                             obsolete_ = true;
                     }
-
-                    ++tag;
-                } while (!tag.end());
+                }
             }
         _end
 
@@ -2320,7 +2487,7 @@ struct PackageNameOrdering :
         _end
 
         _profile(Package$initWithVersion$Section)
-            section_ = iterator.Section();
+            section_ = version_.Section();
         _end
 
         _profile(Package$initWithVersion$Flags)
@@ -2405,16 +2572,20 @@ struct PackageNameOrdering :
 #endif
 }
 
-- (Address *) maintainer {
+- (MIMEAddress *) maintainer {
 @synchronized (database_) {
     if ([database_ era] != era_ || file_.end())
         return nil;
 
     pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
     const std::string &maintainer(parser->Maintainer());
-    return maintainer.empty() ? nil : [Address addressWithString:[NSString stringWithUTF8String:maintainer.c_str()]];
+    return maintainer.empty() ? nil : [MIMEAddress addressWithString:[NSString stringWithUTF8String:maintainer.c_str()]];
 } }
 
+- (NSString *) md5sum {
+    return parsed_ == NULL ? nil : (id) parsed_->md5sum_;
+}
+
 - (size_t) size {
 @synchronized (database_) {
     if ([database_ era] != era_ || version_.end())
@@ -2446,8 +2617,29 @@ struct PackageNameOrdering :
 } }
 
 - (NSString *) shortDescription {
-    return parsed_ == NULL ? nil : static_cast<NSString *>(parsed_->tagline_);
-}
+    if (parsed_ != NULL)
+        return static_cast<NSString *>(parsed_->tagline_);
+
+@synchronized (database_) {
+    pkgRecords::Parser &parser([database_ records]->Lookup(file_));
+
+    const char *start, *end;
+    if (!parser.ShortDesc(start, end))
+        return nil;
+
+    if (end - start > 200)
+        end = start + 200;
+
+    /*
+    if (const char *stop = reinterpret_cast<const char *>(memchr(start, '\n', end - start)))
+        end = stop;
+
+    while (end != start && end[-1] == '\r')
+        --end;
+    */
+
+    return [(id) CYStringCreate(start, end - start) autorelease];
+} }
 
 - (unichar) index {
     _profile(Package$index)
@@ -2526,8 +2718,8 @@ struct PackageNameOrdering :
             return false;
     _end
 
-    _profile(Package$unfiltered$hasSupportingRole)
-        if (_unlikely(![self hasSupportingRole]))
+    _profile(Package$unfiltered$role)
+        if (_unlikely(role_ > 3))
             return false;
     _end
 
@@ -2566,11 +2758,19 @@ struct PackageNameOrdering :
 }
 
 - (BOOL) hasMode {
+@synchronized (database_) {
+    if ([database_ era] != era_ || iterator_.end())
+        return NO;
+
     pkgDepCache::StateCache &state([database_ cache][iterator_]);
     return state.Mode != pkgDepCache::ModeKeep;
-}
+} }
 
 - (NSString *) mode {
+@synchronized (database_) {
+    if ([database_ era] != era_ || iterator_.end())
+        return nil;
+
     pkgDepCache::StateCache &state([database_ cache][iterator_]);
 
     switch (state.Mode) {
@@ -2602,7 +2802,7 @@ struct PackageNameOrdering :
             }
         _nodefault
     }
-}
+} }
 
 - (NSString *) id {
     return id_;
@@ -2619,14 +2819,12 @@ struct PackageNameOrdering :
     if (parsed_ != NULL)
         if (NSString *href = parsed_->icon_)
             if ([href hasPrefix:@"file:///"])
-                // XXX: correct escaping
-                icon = [UIImage imageAtPath:[href substringFromIndex:7]];
+                icon = [UIImage imageAtPath:[[href substringFromIndex:7] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
     if (icon == nil) if (section != nil)
-        icon = [UIImage imageAtPath:[NSString stringWithFormat:@"%@/Sections/%@.png", App_, section]];
+        icon = [UIImage imageAtPath:[NSString stringWithFormat:@"%@/Sections/%@.png", App_, [section stringByReplacingOccurrencesOfString:@" " withString:@"_"]]];
     if (icon == nil) if (Source *source = [self source]) if (NSString *dicon = [source defaultIcon])
         if ([dicon hasPrefix:@"file:///"])
-            // XXX: correct escaping
-            icon = [UIImage imageAtPath:[dicon substringFromIndex:7]];
+            icon = [UIImage imageAtPath:[[dicon substringFromIndex:7] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
     if (icon == nil)
         icon = [UIImage applicationImageNamed:@"unknown.png"];
     return icon;
@@ -2640,16 +2838,12 @@ struct PackageNameOrdering :
     return parsed_ != NULL && !parsed_->depiction_.empty() ? parsed_->depiction_ : [[self source] depictionForPackage:id_];
 }
 
-- (Address *) sponsor {
-    return parsed_ == NULL || parsed_->sponsor_.empty() ? nil : [Address addressWithString:parsed_->sponsor_];
-}
-
-- (Address *) author {
-    return parsed_ == NULL || parsed_->author_.empty() ? nil : [Address addressWithString:parsed_->author_];
+- (MIMEAddress *) author {
+    return parsed_ == NULL || parsed_->author_.empty() ? nil : [MIMEAddress addressWithString:parsed_->author_];
 }
 
 - (NSString *) support {
-    return parsed_ != NULL && !parsed_->bugs_.empty() ? parsed_->bugs_ : [[self source] supportForPackage:id_];
+    return parsed_ != NULL && !parsed_->support_.empty() ? parsed_->support_ : [[self source] supportForPackage:id_];
 }
 
 - (NSArray *) files {
@@ -2785,7 +2979,8 @@ struct PackageNameOrdering :
 
                 NSString *bundle([file stringByDeletingLastPathComponent]);
                 NSString *icon([info objectForKey:@"CFBundleIconFile"]);
-                if (icon == nil || [icon length] == 0)
+                // XXX: maybe this should check if this is really a string, not just for length
+                if (icon == nil || ![icon respondsToSelector:@selector(length)] || [icon length] == 0)
                     icon = @"icon.png";
                 NSURL *url([NSURL fileURLWithPath:[bundle stringByAppendingPathComponent:icon]]);
 
@@ -2813,48 +3008,51 @@ struct PackageNameOrdering :
     return source_ == (Source *) [NSNull null] ? nil : source_;
 }
 
-- (BOOL) matches:(NSString *)text {
-    if (text == nil)
+- (uint32_t) rank {
+    return rank_;
+}
+
+- (BOOL) matches:(NSArray *)query {
+    if (query == nil || [query count] == 0)
         return NO;
 
+    rank_ = 0;
+
+    NSString *string;
     NSRange range;
+    NSUInteger length;
 
-    range = [[self id] rangeOfString:text options:MatchCompareOptions_];
-    if (range.location != NSNotFound)
-        return YES;
+    string = [self name];
+    length = [string length];
 
-    range = [[self name] rangeOfString:text options:MatchCompareOptions_];
-    if (range.location != NSNotFound)
-        return YES;
+    for (NSString *term in query) {
+        range = [string rangeOfString:term options:MatchCompareOptions_];
+        if (range.location != NSNotFound)
+            rank_ -= 6 * 1000000 / length;
+    }
 
-    [self parse];
+    if (rank_ == 0) {
+        string = [self id];
+        length = [string length];
 
-    NSString *description([self shortDescription]);
-    NSUInteger length([description length]);
+        for (NSString *term in query) {
+            range = [string rangeOfString:term options:MatchCompareOptions_];
+            if (range.location != NSNotFound)
+                rank_ -= 6 * 1000000 / length;
+        }
+    }
 
-    range = [[self shortDescription] rangeOfString:text options:MatchCompareOptions_ range:NSMakeRange(0, std::min<NSUInteger>(length, 100))];
-    if (range.location != NSNotFound)
-        return YES;
+    string = [self shortDescription];
+    length = [string length];
+    NSUInteger stop(std::min<NSUInteger>(length, 200));
 
-    return NO;
-}
+    for (NSString *term in query) {
+        range = [string rangeOfString:term options:MatchCompareOptions_ range:NSMakeRange(0, stop)];
+        if (range.location != NSNotFound)
+            rank_ -= 2 * 100000;
+    }
 
-- (bool) hasSupportingRole {
-    if (role_ == 0)
-        return true;
-    if (role_ == 1)
-        return true;
-    if ([Role_ isEqualToString:@"User"])
-        return false;
-    if (role_ == 2)
-        return true;
-    if ([Role_ isEqualToString:@"Hacker"])
-        return false;
-    if (role_ == 3)
-        return true;
-    if ([Role_ isEqualToString:@"Developer"])
-        return false;
-    _assert(false);
+    return rank_ != 0;
 }
 
 - (NSArray *) tags {
@@ -2940,7 +3138,7 @@ struct PackageNameOrdering :
     cache->MarkDelete(iterator_, true);
 } }
 
-- (bool) isUnfilteredAndSearchedForBy:(NSString *)search {
+- (bool) isUnfilteredAndSearchedForBy:(NSArray *)query {
     _profile(Package$isUnfilteredAndSearchedForBy)
         bool value(true);
 
@@ -2949,7 +3147,7 @@ struct PackageNameOrdering :
         _end
 
         _profile(Package$isUnfilteredAndSearchedForBy$Match)
-            value &= [self matches:search];
+            value &= [self matches:query];
         _end
 
         return value;
@@ -2976,16 +3174,19 @@ struct PackageNameOrdering :
 }
 
 - (bool) isInstalledAndUnfiltered:(NSNumber *)number {
-    return ![self uninstalled] && (![number boolValue] && role_ != 7 || [self unfiltered]);
+    return ![self uninstalled] && role_ <= ([number boolValue] ? 1 : 3);
 }
 
-- (bool) isVisibleInSection:(NSString *)name {
+- (bool) isVisibleInSection:(NSString *)name source:(Source *)source {
     NSString *section([self section]);
 
     return (
         name == nil ||
         section == nil && [name length] == 0 ||
         [name isEqualToString:section]
+    ) && (
+        source == nil ||
+        [self source] == source
     ) && [self visible];
 }
 
@@ -3107,10 +3308,14 @@ struct PackageNameOrdering :
 @end
 /* }}} */
 
-static NSString *Colon_;
-static NSString *Elision_;
-static NSString *Error_;
-static NSString *Warning_;
+class CydiaLogCleaner :
+    public pkgArchiveCleaner
+{
+  protected:
+    virtual void Erase(const char *File, std::string Pkg, std::string Ver, struct stat &St) {
+        unlink(File);
+    }
+};
 
 /* Database Implementation {{{ */
 @implementation Database
@@ -3140,7 +3345,7 @@ static NSString *Warning_;
     [super dealloc];
 }
 
-- (void) _readCydia:(NSNumber *)fd { _pooled
+- (void) _readCydia:(NSNumber *)fd {
     __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
     std::istream is(&ib);
     std::string line;
@@ -3148,6 +3353,8 @@ static NSString *Warning_;
     static Pcre finish_r("^finish:([^:]*)$");
 
     while (std::getline(is, line)) {
+        NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
+
         const char *data(line.c_str());
         size_t size = line.size();
         lprintf("C:%s\n", data);
@@ -3158,12 +3365,14 @@ static NSString *Warning_;
             if (index != INT_MAX && index > Finish_)
                 Finish_ = index;
         }
+
+        [pool release];
     }
 
     _assume(false);
 }
 
-- (void) _readStatus:(NSNumber *)fd { _pooled
+- (void) _readStatus:(NSNumber *)fd {
     __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
     std::istream is(&ib);
     std::string line;
@@ -3172,6 +3381,8 @@ static NSString *Warning_;
     static Pcre pmstatus_r("^([^:]*):([^:]*):([^:]*):(.*)$");
 
     while (std::getline(is, line)) {
+        NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
+
         const char *data(line.c_str());
         size_t size(line.size());
         lprintf("S:%s\n", data);
@@ -3211,21 +3422,27 @@ static NSString *Warning_;
                 lprintf("E:unknown pmstatus\n");
         } else
             lprintf("E:unknown status\n");
+
+        [pool release];
     }
 
     _assume(false);
 }
 
-- (void) _readOutput:(NSNumber *)fd { _pooled
+- (void) _readOutput:(NSNumber *)fd {
     __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
     std::istream is(&ib);
     std::string line;
 
     while (std::getline(is, line)) {
+        NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
+
         lprintf("O:%s\n", line.c_str());
 
         CydiaProgressEvent *event([CydiaProgressEvent eventWithMessage:[NSString stringWithUTF8String:line.c_str()] ofType:kCydiaProgressEventTypeInformation]);
         [progress_ performSelectorOnMainThread:@selector(addProgressEvent:) withObject:event waitUntilDone:YES];
+
+        [pool release];
     }
 
     _assume(false);
@@ -3236,11 +3453,13 @@ static NSString *Warning_;
 }
 
 - (Package *) packageWithName:(NSString *)name {
+    if (name == nil)
+        return nil;
 @synchronized (self) {
     if (static_cast<pkgDepCache *>(cache_) == NULL)
         return nil;
     pkgCache::PkgIterator iterator(cache_->FindPkg([name UTF8String]));
-    return iterator.end() ? nil : [Package packageWithIterator:iterator withZone:NULL inPool:pool_ database:self];
+    return iterator.end() ? nil : [Package packageWithIterator:iterator withZone:NULL inPool:NULL database:self];
 } }
 
 - (id) init {
@@ -3361,6 +3580,10 @@ static NSString *Warning_;
 
         lprintf("%c:[%s]\n", warning ? 'W' : 'E', error.c_str());
 
+        static Pcre no_pubkey("^GPG error:.* NO_PUBKEY .*$");
+        if (warning && no_pubkey(error.c_str()))
+            continue;
+
         [delegate_ addProgressEventOnMainThread:[CydiaProgressEvent eventWithMessage:[NSString stringWithUTF8String:error.c_str()] ofType:(warning ? kCydiaProgressEventTypeWarning : kCydiaProgressEventTypeError)] forTask:title];
     }
 
@@ -3371,7 +3594,7 @@ static NSString *Warning_;
     return [self popErrorWithTitle:title] || !success;
 }
 
-- (void) reloadDataWithInvocation:(NSInvocation *)invocation { CYPoolStart() {
+- (void) reloadDataWithInvocation:(NSInvocation *)invocation {
 @synchronized (self) {
     ++era_;
 
@@ -3412,29 +3635,47 @@ static NSString *Warning_;
 
     NSString *title(UCLocalize("DATABASE"));
 
+    list_ = new pkgSourceList();
+    if ([self popErrorWithTitle:title forOperation:list_->ReadMainList()])
+        return;
+
+    for (pkgSourceList::const_iterator source = list_->begin(); source != list_->end(); ++source) {
+        Source *object([[[Source alloc] initWithMetaIndex:*source forDatabase:self inPool:pool_] autorelease]);
+        [sourceList_ addObject:object];
+    }
+
     _trace();
     OpProgress progress;
-    while (!cache_.Open(progress, true)) { pop:
-        std::string error;
-        bool warning(!_error->PopMessage(error));
-        lprintf("cache_.Open():[%s]\n", error.c_str());
-
-        if (error == "dpkg was interrupted, you must manually run 'dpkg --configure -a' to correct the problem. ")
-            [delegate_ repairWithSelector:@selector(configure)];
-        else if (error == "The package lists or status file could not be parsed or opened.")
-            [delegate_ repairWithSelector:@selector(update)];
-        // else if (error == "Could not get lock /var/lib/dpkg/lock - open (35 Resource temporarily unavailable)")
-        // else if (error == "Could not open lock file /var/lib/dpkg/lock - open (13 Permission denied)")
-        // else if (error == "Malformed Status line")
-        // else if (error == "The list of sources could not be read.")
-        else {
+  open:
+    if (!cache_.Open(progress, true)) {
+        // XXX: what if there are errors, but Open() == true? this should be merged with popError:
+        while (!_error->empty()) {
+            std::string error;
+            bool warning(!_error->PopMessage(error));
+
+            lprintf("cache_.Open():[%s]\n", error.c_str());
+
             [delegate_ addProgressEventOnMainThread:[CydiaProgressEvent eventWithMessage:[NSString stringWithUTF8String:error.c_str()] ofType:(warning ? kCydiaProgressEventTypeWarning : kCydiaProgressEventTypeError)] forTask:title];
-            return;
+
+            SEL repair(NULL);
+            if (false);
+            else if (error == "dpkg was interrupted, you must manually run 'dpkg --configure -a' to correct the problem. ")
+                repair = @selector(configure);
+            //else if (error == "The package lists or status file could not be parsed or opened.")
+            //    repair = @selector(update);
+            // else if (error == "Could not get lock /var/lib/dpkg/lock - open (35 Resource temporarily unavailable)")
+            // else if (error == "Could not open lock file /var/lib/dpkg/lock - open (13 Permission denied)")
+            // else if (error == "Malformed Status line")
+            // else if (error == "The list of sources could not be read.")
+
+            if (repair != NULL) {
+                _error->Discard();
+                [delegate_ repairWithSelector:repair];
+                goto open;
+            }
         }
 
-        if (warning)
-            goto pop;
-        _error->Discard();
+        return;
     }
     _trace();
 
@@ -3448,10 +3689,6 @@ static NSString *Warning_;
     fetcher_ = new pkgAcquire(&status_);
     lock_ = NULL;
 
-    list_ = new pkgSourceList();
-    if ([self popErrorWithTitle:title forOperation:list_->ReadMainList()])
-        return;
-
     if (cache_->DelCount() != 0 || cache_->InstCount() != 0) {
         [delegate_ addProgressEventOnMainThread:[CydiaProgressEvent eventWithMessage:UCLocalize("COUNTS_NONZERO_EX") ofType:kCydiaProgressEventTypeError] forTask:title];
         return;
@@ -3473,11 +3710,9 @@ static NSString *Warning_;
             return;
     }
 
-    for (pkgSourceList::const_iterator source = list_->begin(); source != list_->end(); ++source) {
-        Source *object([[[Source alloc] initWithMetaIndex:*source inPool:pool_] autorelease]);
-        [sourceList_ addObject:object];
-
-        std::vector<pkgIndexFile *> *indices = (*source)->GetIndexFiles();
+    for (Source *object in (id) sourceList_) {
+        metaIndex *source([object metaIndex]);
+        std::vector<pkgIndexFile *> *indices = source->GetIndexFiles();
         for (std::vector<pkgIndexFile *>::const_iterator index = indices->begin(); index != indices->end(); ++index)
             // XXX: this could be more intelligent
             if (dynamic_cast<debPackagesIndex *>(*index) != NULL) {
@@ -3507,9 +3742,9 @@ static NSString *Warning_;
             packages_ = [[NSArray alloc] initWithObjects:&packages.front() count:packages.size()];
         _trace();*/
 
-        [(NSMutableArray *) packages_ radixSortUsingFunction:reinterpret_cast<SKRadixFunction>(&PackagePrefixRadix) withContext:reinterpret_cast<void *>(16)];
-        [(NSMutableArray *) packages_ radixSortUsingFunction:reinterpret_cast<SKRadixFunction>(&PackagePrefixRadix) withContext:reinterpret_cast<void *>(4)];
-        [(NSMutableArray *) packages_ radixSortUsingFunction:reinterpret_cast<SKRadixFunction>(&PackagePrefixRadix) withContext:reinterpret_cast<void *>(0)];
+        [(NSMutableArray *) packages_ radixSortUsingFunction:reinterpret_cast<MenesRadixSortFunction>(&PackagePrefixRadix) withContext:reinterpret_cast<void *>(16)];
+        [(NSMutableArray *) packages_ radixSortUsingFunction:reinterpret_cast<MenesRadixSortFunction>(&PackagePrefixRadix) withContext:reinterpret_cast<void *>(4)];
+        [(NSMutableArray *) packages_ radixSortUsingFunction:reinterpret_cast<MenesRadixSortFunction>(&PackagePrefixRadix) withContext:reinterpret_cast<void *>(0)];
 
         /*_trace();
         PrintTimes();
@@ -3537,7 +3772,7 @@ static NSString *Warning_;
 
         _trace();
     }
-} } CYPoolEnd() _trace(); }
+} }
 
 - (void) clear {
 @synchronized (self) {
@@ -3559,6 +3794,7 @@ static NSString *Warning_;
 }
 
 - (bool) clean {
+@synchronized (self) {
     // XXX: I don't remember this condition
     if (lock_ != NULL)
         return false;
@@ -3574,20 +3810,12 @@ static NSString *Warning_;
     pkgAcquire fetcher;
     fetcher.Clean(_config->FindDir("Dir::Cache::Archives"));
 
-    class LogCleaner :
-        public pkgArchiveCleaner
-    {
-      protected:
-        virtual void Erase(const char *File, std::string Pkg, std::string Ver, struct stat &St) {
-            unlink(File);
-        }
-    } cleaner;
-
+    CydiaLogCleaner cleaner;
     if ([self popErrorWithTitle:title forOperation:cleaner.Go(_config->FindDir("Dir::Cache::Archives") + "partial/", cache_)])
         return false;
 
     return true;
-}
+} }
 
 - (bool) prepare {
     fetcher_->Shutdown();
@@ -3642,7 +3870,14 @@ static NSString *Warning_;
         if ((*item)->Status == pkgAcquire::Item::StatIdle)
             continue;
 
+        std::string uri = (*item)->DescURI();
+        std::string error = (*item)->ErrorText;
+
+        lprintf("pAf:%s:%s\n", uri.c_str(), error.c_str());
         failed = true;
+
+        CydiaProgressEvent *event([CydiaProgressEvent eventWithMessage:[NSString stringWithUTF8String:error.c_str()] ofType:kCydiaProgressEventTypeError]);
+        [delegate_ addProgressEventOnMainThread:event forTask:title];
     }
 
     [delegate_ performSelectorOnMainThread:@selector(releaseNetworkActivityIndicator) withObject:nil waitUntilDone:YES];
@@ -3657,11 +3892,8 @@ static NSString *Warning_;
 
     _system->UnLock();
     pkgPackageManager::OrderResult result = manager_->DoInstall(statusfd_);
-
-    if (_error->PendingError()) {
-        _trace();
+    if ([self popErrorWithTitle:title])
         return;
-    }
 
     if (result == pkgPackageManager::Failed) {
         _trace();
@@ -3696,7 +3928,7 @@ static NSString *Warning_;
     [self updateWithStatus:status_];
 }
 
-- (void) updateWithStatus:(Status &)status {
+- (void) updateWithStatus:(CancelStatus &)status {
     NSString *title(UCLocalize("REFRESHING_DATA"));
 
     pkgSourceList list;
@@ -3740,6 +3972,16 @@ static NSString *Warning_;
     return i == sourceMap_.end() ? nil : i->second;
 }
 
+- (void) setFetch:(bool)fetch forURI:(const char *)uri {
+    for (Source *source in (id) sourceList_)
+        [source setFetch:fetch forURI:uri];
+}
+
+- (void) resetFetch {
+    for (Source *source in (id) sourceList_)
+        [source resetFetch];
+}
+
 - (NSString *) mappedSectionForPointer:(const char *)section {
     _H<NSString> *mapped;
 
@@ -3829,7 +4071,7 @@ static _H<NSMutableSet> Diversions_;
 @end
 
 @interface CydiaObject : NSObject {
-    _H<IndirectDelegate> indirect_;
+    _H<CyteWebViewController> indirect_;
     _transient id delegate_;
 }
 
@@ -3837,11 +4079,16 @@ static _H<NSMutableSet> Diversions_;
 
 @end
 
+@class CydiaObject;
+
 @interface CydiaWebViewController : CyteWebViewController {
     _H<CydiaObject> cydia_;
 }
 
 + (void) addDiversion:(Diversion *)diversion;
++ (NSURLRequest *) requestWithHeaders:(NSURLRequest *)request;
++ (void) didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame withCydia:(CydiaObject *)cydia;
+- (void) setDelegate:(id)delegate;
 
 @end
 
@@ -3850,7 +4097,7 @@ static _H<NSMutableSet> Diversions_;
 
 - (id) initWithDelegate:(IndirectDelegate *)indirect {
     if ((self = [super init]) != nil) {
-        indirect_ = indirect;
+        indirect_ = (CyteWebViewController *) indirect;
     } return self;
 }
 
@@ -3861,13 +4108,17 @@ static _H<NSMutableSet> Diversions_;
 + (NSArray *) _attributeKeys {
     return [NSArray arrayWithObjects:
         @"bbsnum",
+        @"build",
+        @"coreFoundationVersionNumber",
         @"device",
         @"ecid",
         @"firmware",
         @"hostname",
         @"idiom",
+        @"mcc",
+        @"mnc",
         @"model",
-        @"plmn",
+        @"operator",
         @"role",
         @"serial",
         @"token",
@@ -3884,11 +4135,19 @@ static _H<NSMutableSet> Diversions_;
 }
 
 - (NSString *) version {
-    return @ Cydia_;
+    return Cydia_;
+}
+
+- (NSString *) build {
+    return System_;
+}
+
+- (NSString *) coreFoundationVersionNumber {
+    return [NSString stringWithFormat:@"%.2f", kCFCoreFoundationVersionNumber];
 }
 
 - (NSString *) device {
-    return [[UIDevice currentDevice] uniqueIdentifier];
+    return UniqueIdentifier();
 }
 
 - (NSString *) firmware {
@@ -3903,8 +4162,22 @@ static _H<NSMutableSet> Diversions_;
     return (id) Idiom_ ?: [NSNull null];
 }
 
-- (NSString *) plmn {
-    return (id) PLMN_ ?: [NSNull null];
+- (NSString *) mcc {
+    if (CFStringRef (*$CTSIMSupportCopyMobileSubscriberCountryCode)(CFAllocatorRef) = reinterpret_cast<CFStringRef (*)(CFAllocatorRef)>(dlsym(RTLD_DEFAULT, "CTSIMSupportCopyMobileSubscriberCountryCode")))
+        return [(NSString *) (*$CTSIMSupportCopyMobileSubscriberCountryCode)(kCFAllocatorDefault) autorelease];
+    return nil;
+}
+
+- (NSString *) mnc {
+    if (CFStringRef (*$CTSIMSupportCopyMobileSubscriberNetworkCode)(CFAllocatorRef) = reinterpret_cast<CFStringRef (*)(CFAllocatorRef)>(dlsym(RTLD_DEFAULT, "CTSIMSupportCopyMobileSubscriberNetworkCode")))
+        return [(NSString *) (*$CTSIMSupportCopyMobileSubscriberNetworkCode)(kCFAllocatorDefault) autorelease];
+    return nil;
+}
+
+- (NSString *) operator {
+    if (CFStringRef (*$CTRegistrationCopyOperatorName)(CFAllocatorRef) = reinterpret_cast<CFStringRef (*)(CFAllocatorRef)>(dlsym(RTLD_DEFAULT, "CTRegistrationCopyOperatorName")))
+        return [(NSString *) (*$CTRegistrationCopyOperatorName)(kCFAllocatorDefault) autorelease];
+    return nil;
 }
 
 - (NSString *) bbsnum {
@@ -3920,7 +4193,7 @@ static _H<NSMutableSet> Diversions_;
 }
 
 - (NSString *) role {
-    return (id) Role_ ?: [NSNull null];
+    return (id) [NSNull null];
 }
 
 - (NSString *) model {
@@ -3935,10 +4208,16 @@ static _H<NSMutableSet> Diversions_;
     if (false);
     else if (selector == @selector(addBridgedHost:))
         return @"addBridgedHost";
+    else if (selector == @selector(addInsecureHost:))
+        return @"addInsecureHost";
     else if (selector == @selector(addInternalRedirect::))
         return @"addInternalRedirect";
     else if (selector == @selector(addPipelinedHost:scheme:))
         return @"addPipelinedHost";
+    else if (selector == @selector(addSource:::))
+        return @"addSource";
+    else if (selector == @selector(addTokenHost:))
+        return @"addTokenHost";
     else if (selector == @selector(addTrivialSource:))
         return @"addTrivialSource";
     else if (selector == @selector(close))
@@ -3948,7 +4227,9 @@ static _H<NSMutableSet> Diversions_;
     else if (selector == @selector(stringWithFormat:arguments:))
         return @"format";
     else if (selector == @selector(getAllSources))
-        return @"getAllSourcs";
+        return @"getAllSources";
+    else if (selector == @selector(getApplicationInfo:value:))
+        return @"getApplicationInfoValue";
     else if (selector == @selector(getKernelNumber:))
         return @"getKernelNumber";
     else if (selector == @selector(getKernelString:))
@@ -3963,18 +4244,30 @@ static _H<NSMutableSet> Diversions_;
         return @"getPreferredLanguages";
     else if (selector == @selector(getPackageById:))
         return @"getPackageById";
+    else if (selector == @selector(getMetadataKeys))
+        return @"getMetadataKeys";
+    else if (selector == @selector(getMetadataValue:))
+        return @"getMetadataValue";
     else if (selector == @selector(getSessionValue:))
         return @"getSessionValue";
     else if (selector == @selector(installPackages:))
         return @"installPackages";
+    else if (selector == @selector(isReachable:))
+        return @"isReachable";
     else if (selector == @selector(localizedStringForKey:value:table:))
         return @"localize";
     else if (selector == @selector(popViewController:))
         return @"popViewController";
     else if (selector == @selector(refreshSources))
         return @"refreshSources";
+    else if (selector == @selector(registerFrame:))
+        return @"registerFrame";
     else if (selector == @selector(removeButton))
         return @"removeButton";
+    else if (selector == @selector(saveConfig))
+        return @"saveConfig";
+    else if (selector == @selector(setMetadataValue::))
+        return @"setMetadataValue";
     else if (selector == @selector(setSessionValue::))
         return @"setSessionValue";
     else if (selector == @selector(substitutePackageNames:))
@@ -4001,6 +4294,10 @@ static _H<NSMutableSet> Diversions_;
         return @"setPasteboardString";
     else if (selector == @selector(setPasteboardURL:))
         return @"setPasteboardURL";
+    else if (selector == @selector(setScrollAlwaysBounceVertical:))
+        return @"setScrollAlwaysBounceVertical";
+    else if (selector == @selector(setScrollIndicatorStyle:))
+        return @"setScrollIndicatorStyle";
     else if (selector == @selector(setToken:))
         return @"setToken";
     else if (selector == @selector(setViewportWidth:))
@@ -4009,6 +4306,8 @@ static _H<NSMutableSet> Diversions_;
         return @"statfs";
     else if (selector == @selector(supports:))
         return @"supports";
+    else if (selector == @selector(unload))
+        return @"unload";
     else
         return nil;
 }
@@ -4021,10 +4320,32 @@ static _H<NSMutableSet> Diversions_;
     return [feature isEqualToString:@"window.open"];
 }
 
+- (void) unload {
+    [delegate_ performSelectorOnMainThread:@selector(unloadData) withObject:nil waitUntilDone:NO];
+}
+
+- (void) setScrollAlwaysBounceVertical:(NSNumber *)value {
+    [indirect_ performSelectorOnMainThread:@selector(setScrollAlwaysBounceVerticalNumber:) withObject:value waitUntilDone:NO];
+}
+
+- (void) setScrollIndicatorStyle:(NSString *)style {
+    [indirect_ performSelectorOnMainThread:@selector(setScrollIndicatorStyleWithName:) withObject:style waitUntilDone:NO];
+}
+
 - (void) addInternalRedirect:(NSString *)from :(NSString *)to {
     [CydiaWebViewController performSelectorOnMainThread:@selector(addDiversion:) withObject:[[[Diversion alloc] initWithFrom:from to:to] autorelease] waitUntilDone:NO];
 }
 
+- (NSDictionary *) getApplicationInfo:(NSString *)display value:(NSString *)key {
+    char path[1024];
+    if (SBBundlePathForDisplayIdentifier(SBSSpringBoardServerPort(), [display UTF8String], path) != 0)
+        return (id) [NSNull null];
+    NSDictionary *info([NSDictionary dictionaryWithContentsOfFile:[[NSString stringWithUTF8String:path] stringByAppendingString:@"/Info.plist"]]);
+    if (info == nil)
+        return (id) [NSNull null];
+    return [info objectForKey:key];
+}
+
 - (NSNumber *) getKernelNumber:(NSString *)name {
     const char *string([name UTF8String]);
 
@@ -4069,6 +4390,31 @@ static _H<NSMutableSet> Diversions_;
     return value;
 }
 
+- (NSArray *) getMetadataKeys {
+@synchronized (Values_) {
+    return [Values_ allKeys];
+} }
+
+- (void) registerFrame:(DOMHTMLIFrameElement *)iframe {
+    WebFrame *frame([iframe contentFrame]);
+    [indirect_ registerFrame:frame];
+}
+
+- (id) getMetadataValue:(NSString *)key {
+@synchronized (Values_) {
+    return [Values_ objectForKey:key];
+} }
+
+- (void) setMetadataValue:(NSString *)key :(NSString *)value {
+@synchronized (Values_) {
+    if (value == nil || value == (id) [WebUndefined undefined] || value == (id) [NSNull null])
+        [Values_ removeObjectForKey:key];
+    else
+        [Values_ setObject:value forKey:key];
+
+    [delegate_ performSelectorOnMainThread:@selector(updateValues) withObject:nil waitUntilDone:YES];
+} }
+
 - (id) getSessionValue:(NSString *)key {
 @synchronized (SessionData_) {
     return [SessionData_ objectForKey:key];
@@ -4087,6 +4433,16 @@ static _H<NSMutableSet> Diversions_;
     [BridgedHosts_ addObject:host];
 } }
 
+- (void) addInsecureHost:(NSString *)host {
+@synchronized (HostConfig_) {
+    [InsecureHosts_ addObject:host];
+} }
+
+- (void) addTokenHost:(NSString *)host {
+@synchronized (HostConfig_) {
+    [TokenHosts_ addObject:host];
+} }
+
 - (void) addPipelinedHost:(NSString *)host scheme:(NSString *)scheme {
 @synchronized (HostConfig_) {
     if (scheme != (id) [WebUndefined undefined])
@@ -4101,6 +4457,20 @@ static _H<NSMutableSet> Diversions_;
     [indirect_ performSelectorOnMainThread:@selector(popViewControllerWithNumber:) withObject:value waitUntilDone:NO];
 }
 
+- (void) addSource:(NSString *)href :(NSString *)distribution :(WebScriptObject *)sections {
+    NSMutableArray *array([NSMutableArray arrayWithCapacity:[sections count]]);
+
+    for (NSString *section in sections)
+        [array addObject:section];
+
+    [delegate_ performSelectorOnMainThread:@selector(addSource:) withObject:[NSMutableDictionary dictionaryWithObjectsAndKeys:
+        @"deb", @"Type",
+        href, @"URI",
+        distribution, @"Distribution",
+        array, @"Sections",
+    nil] waitUntilDone:NO];
+}
+
 - (void) addTrivialSource:(NSString *)href {
     [delegate_ performSelectorOnMainThread:@selector(addTrivialSource:) withObject:href waitUntilDone:NO];
 }
@@ -4109,6 +4479,10 @@ static _H<NSMutableSet> Diversions_;
     [delegate_ performSelectorOnMainThread:@selector(syncData) withObject:nil waitUntilDone:NO];
 }
 
+- (void) saveConfig {
+    [delegate_ performSelectorOnMainThread:@selector(_saveConfig) withObject:nil waitUntilDone:NO];
+}
+
 - (NSArray *) getAllSources {
     return [[Database sharedInstance] sources];
 }
@@ -4167,32 +4541,25 @@ static _H<NSMutableSet> Diversions_;
         /* XXX: this should probably not use du */
         execl("/usr/libexec/cydia/du", "du", "-s", [path UTF8String], NULL);
         exit(1);
-        _assert(false);
-    }
-
-    _assert(close(fds[1]) != -1);
+    } else {
+        _assert(close(fds[1]) != -1);
 
-    if (FILE *du = fdopen(fds[0], "r")) {
-        char line[1024];
-        while (fgets(line, sizeof(line), du) != NULL) {
-            size_t length(strlen(line));
-            while (length != 0 && line[length - 1] == '\n')
-                line[--length] = '\0';
-            if (char *tab = strchr(line, '\t')) {
-                *tab = '\0';
-                value = [NSNumber numberWithUnsignedLong:strtoul(line, NULL, 0)];
+        if (FILE *du = fdopen(fds[0], "r")) {
+            char line[1024];
+            while (fgets(line, sizeof(line), du) != NULL) {
+                size_t length(strlen(line));
+                while (length != 0 && line[length - 1] == '\n')
+                    line[--length] = '\0';
+                if (char *tab = strchr(line, '\t')) {
+                    *tab = '\0';
+                    value = [NSNumber numberWithUnsignedLong:strtoul(line, NULL, 0)];
+                }
             }
-        }
-
-        fclose(du);
-    } else _assert(close(fds[0]));
 
-    int status;
-  wait:
-    if (waitpid(pid, &status, 0) == -1)
-        if (errno == EINTR)
-            goto wait;
-        else _assert(false);
+            fclose(du);
+        } else
+            _assert(close(fds[0]) != -1);
+    } ReapZombie(pid);
 
     return value;
 }
@@ -4201,12 +4568,16 @@ static _H<NSMutableSet> Diversions_;
     [indirect_ performSelectorOnMainThread:@selector(close) withObject:nil waitUntilDone:NO];
 }
 
+- (NSNumber *) isReachable:(NSString *)name {
+    return [NSNumber numberWithBool:IsReachable([name UTF8String])];
+}
+
 - (void) installPackages:(NSArray *)packages {
     [delegate_ performSelectorOnMainThread:@selector(installPackages:) withObject:packages waitUntilDone:NO];
 }
 
 - (NSString *) substitutePackageNames:(NSString *)message {
-    NSMutableArray *words([[message componentsSeparatedByString:@" "] mutableCopy]);
+    NSMutableArray *words([[[message componentsSeparatedByString:@" "] mutableCopy] autorelease]);
     for (size_t i(0), e([words count]); i != e; ++i) {
         NSString *word([words objectAtIndex:i]);
         if (Package *package = [[Database sharedInstance] packageWithName:word])
@@ -4305,121 +4676,24 @@ static _H<NSMutableSet> Diversions_;
 @end
 /* }}} */
 
-/* @ Loading... Indicator {{{ */
-@interface CYLoadingIndicator : UIView {
-    _H<UIActivityIndicatorView> spinner_;
-    _H<UILabel> label_;
-    _H<UIView> container_;
-}
-
-@property (readonly, nonatomic) UILabel *label;
-@property (readonly, nonatomic) UIActivityIndicatorView *activityIndicatorView;
-
+@interface NSURL (CydiaSecure)
 @end
 
-@implementation CYLoadingIndicator
-
-- (id) initWithFrame:(CGRect)frame {
-    if ((self = [super initWithFrame:frame]) != nil) {
-        container_ = [[[UIView alloc] init] autorelease];
-        [container_ setAutoresizingMask:UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin];
-
-        spinner_ = [[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray] autorelease];
-        [spinner_ startAnimating];
-        [container_ addSubview:spinner_];
-
-        label_ = [[[UILabel alloc] init] autorelease];
-        [label_ setFont:[UIFont boldSystemFontOfSize:15.0f]];
-        [label_ setBackgroundColor:[UIColor clearColor]];
-        [label_ setTextColor:[UIColor blackColor]];
-        [label_ setShadowColor:[UIColor whiteColor]];
-        [label_ setShadowOffset:CGSizeMake(0, 1)];
-        [label_ setText:[NSString stringWithFormat:Elision_, UCLocalize("LOADING"), nil]];
-        [container_ addSubview:label_];
-
-        CGSize viewsize = frame.size;
-        CGSize spinnersize = [spinner_ bounds].size;
-        CGSize textsize = [[label_ text] sizeWithFont:[label_ font]];
-        float bothwidth = spinnersize.width + textsize.width + 5.0f;
-
-        CGRect containrect = {
-            CGPointMake(floorf((viewsize.width / 2) - (bothwidth / 2)), floorf((viewsize.height / 2) - (spinnersize.height / 2))),
-            CGSizeMake(bothwidth, spinnersize.height)
-        };
-        CGRect textrect = {
-            CGPointMake(spinnersize.width + 5.0f, floorf((spinnersize.height / 2) - (textsize.height / 2))),
-            textsize
-        };
-        CGRect spinrect = {
-            CGPointZero,
-            spinnersize
-        };
-
-        [container_ setFrame:containrect];
-        [spinner_ setFrame:spinrect];
-        [label_ setFrame:textrect];
-        [self addSubview:container_];
-    } return self;
-}
+@implementation NSURL (CydiaSecure)
 
-- (UILabel *) label {
-    return label_;
-}
-
-- (UIActivityIndicatorView *) activityIndicatorView {
-    return spinner_;
-}
-
-@end
-/* }}} */
-/* Emulated Loading Controller {{{ */
-@interface CYEmulatedLoadingController : CyteViewController {
-    _transient Database *database_;
-    _H<CYLoadingIndicator> indicator_;
-    _H<UITabBar> tabbar_;
-    _H<UINavigationBar> navbar_;
-}
-
-@end
-
-@implementation CYEmulatedLoadingController
-
-- (id) initWithDatabase:(Database *)database {
-    if ((self = [super init]) != nil) {
-        database_ = database;
-    } return self;
-}
-
-- (void) loadView {
-    [self setView:[[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease]];
-
-    UITableView *table([[[UITableView alloc] initWithFrame:[[self view] bounds] style:UITableViewStyleGrouped] autorelease]);
-    [table setAutoresizingMask:UIViewAutoresizingFlexibleBoth];
-    [[self view] addSubview:table];
-
-    indicator_ = [[[CYLoadingIndicator alloc] initWithFrame:[[self view] bounds]] autorelease];
-    [indicator_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth];
-    [[self view] addSubview:indicator_];
-
-    tabbar_ = [[[UITabBar alloc] initWithFrame:CGRectMake(0, 0, 0, 49.0f)] autorelease];
-    [tabbar_ setFrame:CGRectMake(0.0f, [[self view] bounds].size.height - [tabbar_ bounds].size.height, [[self view] bounds].size.width, [tabbar_ bounds].size.height)];
-    [tabbar_ setAutoresizingMask:UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth];
-    [[self view] addSubview:tabbar_];
+- (bool) isCydiaSecure {
+    if ([[[self scheme] lowercaseString] isEqualToString:@"https"])
+        return true;
 
-    navbar_ = [[[UINavigationBar alloc] initWithFrame:CGRectMake(0, 0, 0, 44.0f)] autorelease];
-    [navbar_ setFrame:CGRectMake(0.0f, 0.0f, [[self view] bounds].size.width, [navbar_ bounds].size.height)];
-    [navbar_ setAutoresizingMask:UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleWidth];
-    [[self view] addSubview:navbar_];
-}
+    @synchronized (HostConfig_) {
+        if ([InsecureHosts_ containsObject:[self host]])
+            return true;
+    }
 
-- (void) releaseSubviews {
-    indicator_ = nil;
-    tabbar_ = nil;
-    navbar_ = nil;
+    return false;
 }
 
 @end
-/* }}} */
 
 /* Cydia Browser Controller {{{ */
 @implementation CydiaWebViewController
@@ -4428,7 +4702,9 @@ static _H<NSMutableSet> Diversions_;
     return request_ == nil ? nil : [NSURL URLWithString:[NSString stringWithFormat:@"cydia://url/%@", [[request_ URL] absoluteString]]];
 }
 
-+ (void) initialize {
++ (void) _initialize {
+    [super _initialize];
+
     Diversions_ = [NSMutableSet setWithCapacity:0];
 }
 
@@ -4438,7 +4714,10 @@ static _H<NSMutableSet> Diversions_;
 
 - (void) webView:(WebView *)view didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame {
     [super webView:view didClearWindowObject:window forFrame:frame];
+    [CydiaWebViewController didClearWindowObject:window forFrame:frame withCydia:cydia_];
+}
 
++ (void) didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame withCydia:(CydiaObject *)cydia {
     WebDataSource *source([frame dataSource]);
     NSURLResponse *response([source response]);
     NSURL *url([response URL]);
@@ -4455,7 +4734,14 @@ static _H<NSMutableSet> Diversions_;
     }
 
     if (bridged)
-        [window setValue:cydia_ forKey:@"cydia"];
+        [window setValue:cydia forKey:@"cydia"];
+}
+
+- (void) _setupMail:(MFMailComposeViewController *)controller {
+    [controller addAttachmentData:[NSData dataWithContentsOfFile:@"/tmp/cydia.log"] mimeType:@"text/plain" fileName:@"cydia.log"];
+
+    system("/usr/bin/dpkg -l >/tmp/dpkgl.log");
+    [controller addAttachmentData:[NSData dataWithContentsOfFile:@"/tmp/dpkgl.log"] mimeType:@"text/plain" fileName:@"dpkgl.log"];
 }
 
 - (NSURL *) URLWithURL:(NSURL *)url {
@@ -4463,14 +4749,51 @@ static _H<NSMutableSet> Diversions_;
 }
 
 - (NSURLRequest *) webView:(WebView *)view resource:(id)resource willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response fromDataSource:(WebDataSource *)source {
-    NSMutableURLRequest *copy([[super webView:view resource:resource willSendRequest:request redirectResponse:response fromDataSource:source] mutableCopy]);
+    return [CydiaWebViewController requestWithHeaders:[super webView:view resource:resource willSendRequest:request redirectResponse:response fromDataSource:source]];
+}
 
-    if (System_ != NULL)
-        [copy setValue:System_ forHTTPHeaderField:@"X-System"];
-    if (Machine_ != NULL)
++ (NSURLRequest *) requestWithHeaders:(NSURLRequest *)request {
+    NSMutableURLRequest *copy([[request mutableCopy] autorelease]);
+
+    NSURL *url([copy URL]);
+    NSString *href([url absoluteString]);
+    NSString *host([url host]);
+
+    if ([href hasPrefix:@"https://cydia.saurik.com/TSS/"]) {
+        if (NSString *agent = [copy valueForHTTPHeaderField:@"X-User-Agent"]) {
+            [copy setValue:agent forHTTPHeaderField:@"User-Agent"];
+            [copy setValue:nil forHTTPHeaderField:@"X-User-Agent"];
+        }
+
+        [copy setValue:nil forHTTPHeaderField:@"Referer"];
+        [copy setValue:nil forHTTPHeaderField:@"Origin"];
+
+        [copy setURL:[NSURL URLWithString:[@"http://gs.apple.com/TSS/" stringByAppendingString:[href substringFromIndex:29]]]];
+        return copy;
+    }
+
+    if ([copy valueForHTTPHeaderField:@"X-Cydia-Cf"] == nil)
+        [copy setValue:[NSString stringWithFormat:@"%.2f", kCFCoreFoundationVersionNumber] forHTTPHeaderField:@"X-Cydia-Cf"];
+    if (Machine_ != NULL && [copy valueForHTTPHeaderField:@"X-Machine"] == nil)
         [copy setValue:[NSString stringWithUTF8String:Machine_] forHTTPHeaderField:@"X-Machine"];
-    if (Token_ != nil)
-        [copy setValue:Token_ forHTTPHeaderField:@"X-Cydia-Token"];
+
+    bool bridged;
+    bool token;
+
+    @synchronized (HostConfig_) {
+        bridged = [BridgedHosts_ containsObject:host];
+        token = [TokenHosts_ containsObject:host];
+    }
+
+    if ([url isCydiaSecure]) {
+        if (bridged) {
+            if (UniqueID_ != nil && [copy valueForHTTPHeaderField:@"X-Cydia-Id"] == nil)
+                [copy setValue:UniqueID_ forHTTPHeaderField:@"X-Cydia-Id"];
+        } else if (token) {
+            if (Token_ != nil && [copy valueForHTTPHeaderField:@"X-Cydia-Token"] == nil)
+                [copy setValue:Token_ forHTTPHeaderField:@"X-Cydia-Token"];
+        }
+    }
 
     return copy;
 }
@@ -4480,23 +4803,31 @@ static _H<NSMutableSet> Diversions_;
     [cydia_ setDelegate:delegate];
 }
 
+- (NSString *) applicationNameForUserAgent {
+    return UserAgent_;
+}
+
 - (id) init {
     if ((self = [super initWithWidth:0 ofClass:[CydiaWebViewController class]]) != nil) {
         cydia_ = [[[CydiaObject alloc] initWithDelegate:indirect_] autorelease];
+    } return self;
+}
+
+@end
+
+@interface AppCacheController : CydiaWebViewController {
+}
 
-        WebView *webview([[webview_ _documentView] webView]);
+@end
 
-        NSString *application([NSString stringWithFormat:@"Cydia/%@", @ Cydia_]);
+@implementation AppCacheController
 
-        if (Safari_ != nil)
-            application = [NSString stringWithFormat:@"Safari/%@ %@", Safari_, application];
-        if (Build_ != nil)
-            application = [NSString stringWithFormat:@"Mobile/%@ %@", Build_, application];
-        if (Product_ != nil)
-            application = [NSString stringWithFormat:@"Version/%@ %@", Product_, application];
+- (void) didReceiveMemoryWarning {
+    // XXX: this doesn't work
+}
 
-        [webview setApplicationNameForUserAgent:application];
-    } return self;
+- (bool) retainsNetworkActivityIndicator {
+    return false;
 }
 
 @end
@@ -4591,7 +4922,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         if (button == [alert cancelButtonIndex])
             [self dismissModalViewControllerAnimated:YES];
         else if (button == [alert firstOtherButtonIndex]) {
-            [self complete];
+            [self performSelector:@selector(complete) withObject:nil afterDelay:0];
         }
 
         [alert dismissWithClickedButtonIndex:-1 animated:YES];
@@ -4604,8 +4935,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (void) _doContinue {
-    [self dismissModalViewControllerAnimated:YES];
     [delegate_ cancelAndClear:NO];
+    [self dismissModalViewControllerAnimated:YES];
 }
 
 - (id) invokeDefaultMethodWithArguments:(NSArray *)args {
@@ -4694,7 +5025,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
                                 reason = @"virtual";
                         }
 
-                        NSDictionary *version(start.TargetVer() == 0 ? [NSNull null] : [NSDictionary dictionaryWithObjectsAndKeys:
+                        NSDictionary *version(start.TargetVer() == 0 ? (NSDictionary *) [NSNull null] : [NSDictionary dictionaryWithObjectsAndKeys:
                             [NSString stringWithUTF8String:start.CompType()], @"operator",
                             [NSString stringWithUTF8String:start.TargetVer()], @"value",
                         nil]);
@@ -4773,6 +5104,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
             ] autorelease];
 
             [essential_ setContext:@"remove"];
+            [essential_ setNumberOfRows:2];
         } else {
             essential_ = [[[UIAlertView alloc]
                 initWithTitle:UCLocalize("UNABLE_TO_COMPLY")
@@ -4826,8 +5158,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 #endif
 
 - (void) cancelButtonClicked {
-    [self dismissModalViewControllerAnimated:YES];
     [delegate_ cancelAndClear:YES];
+    [self dismissModalViewControllerAnimated:YES];
 }
 
 #if !AlwaysReload
@@ -4891,6 +5223,10 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     } return self;
 }
 
+- (id) delegate {
+    return delegate_;
+}
+
 - (void) setDelegate:(id)delegate {
     delegate_ = delegate;
 }
@@ -4970,7 +5306,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     ProgressDelegate
 > {
     _transient Database *database_;
-    _H<CydiaProgressData> progress_;
+    _H<CydiaProgressData, 1> progress_;
     unsigned cancel_;
 }
 
@@ -4987,7 +5323,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 - (void) dealloc {
     [database_ setProgressDelegate:nil];
-    [progress_ setDelegate:nil];
     [super dealloc];
 }
 
@@ -5038,11 +5373,43 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     [super viewWillAppear:animated];
 }
 
+- (void) reloadSpringBoard {
+    if (kCFCoreFoundationVersionNumber > 700) { // XXX: iOS 6.x
+        system("/bin/launchctl stop com.apple.backboardd");
+        sleep(15);
+        system("/usr/bin/killall backboardd SpringBoard sbreload");
+        return;
+    }
+
+    pid_t pid(ExecFork());
+    if (pid == 0) {
+        if (setsid() == -1)
+            perror("setsid");
+
+        pid_t pid(ExecFork());
+        if (pid == 0) {
+            execl("/usr/bin/sbreload", "sbreload", NULL);
+            perror("sbreload");
+
+            exit(0);
+        } ReapZombie(pid);
+
+        exit(0);
+    } ReapZombie(pid);
+
+    sleep(15);
+    system("/usr/bin/killall backboardd SpringBoard sbreload");
+}
+
 - (void) close {
     UpdateExternalStatus(0);
 
+    if (Finish_ > 1)
+        [delegate_ saveState];
+
     switch (Finish_) {
         case 0:
+            [delegate_ returnToCydia];
         break;
 
         case 1:
@@ -5061,10 +5428,12 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
             _trace();
             goto reload;
 
-        reload:
-            system("/usr/bin/sbreload");
-            _trace();
-        break;
+        reload: {
+            UIProgressHUD *hud([delegate_ addProgressHUD]);
+            [hud setText:UCLocalize("LOADING")];
+            [self performSelector:@selector(reloadSpringBoard) withObject:nil afterDelay:0.5];
+            return;
+        }
 
         case 4:
             _trace();
@@ -5169,10 +5538,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         case 4: [progress_ setFinish:UCLocalize("REBOOT_DEVICE")]; break;
     }
 
-    _trace();
-    system("su -c /usr/bin/uicache mobile");
-    _trace();
-
     UpdateExternalStatus(Finish_ == 0 ? 0 : 2);
 
     [progress_ setRunning:false];
@@ -5235,71 +5600,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 @end
 /* }}} */
 
-/* Cell Content View {{{ */
-@protocol ContentDelegate
-- (void) drawContentRect:(CGRect)rect;
-@end
-
-@interface ContentView : UIView {
-    _transient id<ContentDelegate> delegate_;
-}
-
-@end
-
-@implementation ContentView
-
-- (id) initWithFrame:(CGRect)frame {
-    if ((self = [super initWithFrame:frame]) != nil) {
-        [self setNeedsDisplayOnBoundsChange:YES];
-    } return self;
-}
-
-- (void) setDelegate:(id<ContentDelegate>)delegate {
-    delegate_ = delegate;
-}
-
-- (void) drawRect:(CGRect)rect {
-    [super drawRect:rect];
-    [delegate_ drawContentRect:rect];
-}
-
-@end
-/* }}} */
-/* Cydia TableView Cell {{{ */
-@interface CYTableViewCell : UITableViewCell {
-    _H<ContentView> content_;
-    bool highlighted_;
-}
-
-@end
-
-@implementation CYTableViewCell
-
-- (void) _updateHighlightColorsForView:(UIView *)view highlighted:(BOOL)highlighted {
-    //NSLog(@"_updateHighlightColorsForView:%@ highlighted:%s [content_=%@]", view, highlighted ? "YES" : "NO", content_);
-
-    if (view == (UIView *) content_) {
-        //NSLog(@"_updateHighlightColorsForView:content_ highlighted:%s", highlighted ? "YES" : "NO", content_);
-        highlighted_ = highlighted;
-    }
-
-    [super _updateHighlightColorsForView:view highlighted:highlighted];
-}
-
-- (void) setSelected:(BOOL)selected animated:(BOOL)animated {
-    //NSLog(@"setSelected:%s animated:%s", selected ? "YES" : "NO", animated ? "YES" : "NO");
-    highlighted_ = selected;
-
-    [super setSelected:selected animated:animated];
-    [content_ setNeedsDisplay];
-}
-
-@end
-/* }}} */
-
 /* Package Cell {{{ */
-@interface PackageCell : CYTableViewCell <
-    ContentDelegate
+@interface PackageCell : CyteTableViewCell <
+    CyteTableViewCellDelegate
 > {
     _H<UIImage> icon_;
     _H<NSString> name_;
@@ -5307,7 +5610,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     bool commercial_;
     _H<NSString> source_;
     _H<UIImage> badge_;
-    _H<Package> package_;
     _H<UIImage> placard_;
     bool summarized_;
 }
@@ -5327,7 +5629,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         UIView *content([self contentView]);
         CGRect bounds([content bounds]);
 
-        content_ = [[[ContentView alloc] initWithFrame:bounds] autorelease];
+        content_ = [[[CyteTableViewCellContentView alloc] initWithFrame:bounds] autorelease];
         [content_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth];
         [content addSubview:content_];
 
@@ -5337,7 +5639,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (NSString *) accessibilityLabel {
-    return [NSString stringWithFormat:UCLocalize("COLON_DELIMITED"), (id) name_, (id) description_];
+    return name_;
 }
 
 - (void) setPackage:(Package *)package asSummary:(bool)summary {
@@ -5349,76 +5651,74 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     source_ = nil;
     badge_ = nil;
     placard_ = nil;
-    package_ = nil;
 
-    [package parse];
+    if (package == nil)
+        [content_ setBackgroundColor:[UIColor whiteColor]];
+    else {
+        [package parse];
 
-    Source *source = [package source];
+        Source *source = [package source];
 
-    icon_ = [package icon];
-    name_ = [package name];
+        icon_ = [package icon];
 
-    if (IsWildcat_)
-        description_ = [package longDescription];
-    if (description_ == nil)
-        description_ = [package shortDescription];
+        if (NSString *name = [package name])
+            name_ = [NSString stringWithString:name];
 
-    commercial_ = [package isCommercial];
+        if (NSString *description = [package shortDescription])
+            description_ = [NSString stringWithString:description];
 
-    package_ = package;
+        commercial_ = [package isCommercial];
 
-    NSString *label = nil;
-    bool trusted = false;
+        NSString *label = nil;
+        bool trusted = false;
 
-    if (source != nil) {
-        label = [source label];
-        trusted = [source trusted];
-    } else if ([[package id] isEqualToString:@"firmware"])
-        label = UCLocalize("APPLE");
-    else
-        label = [NSString stringWithFormat:UCLocalize("SLASH_DELIMITED"), UCLocalize("UNKNOWN"), UCLocalize("LOCAL")];
+        if (source != nil) {
+            label = [source label];
+            trusted = [source trusted];
+        } else if ([[package id] isEqualToString:@"firmware"])
+            label = UCLocalize("APPLE");
+        else
+            label = [NSString stringWithFormat:UCLocalize("SLASH_DELIMITED"), UCLocalize("UNKNOWN"), UCLocalize("LOCAL")];
 
-    NSString *from(label);
+        NSString *from(label);
 
-    NSString *section = [package simpleSection];
-    if (section != nil && ![section isEqualToString:label]) {
-        section = [[NSBundle mainBundle] localizedStringForKey:section value:nil table:@"Sections"];
-        from = [NSString stringWithFormat:UCLocalize("PARENTHETICAL"), from, section];
-    }
+        NSString *section = [package simpleSection];
+        if (section != nil && ![section isEqualToString:label]) {
+            section = [[NSBundle mainBundle] localizedStringForKey:section value:nil table:@"Sections"];
+            from = [NSString stringWithFormat:UCLocalize("PARENTHETICAL"), from, section];
+        }
 
-    source_ = [NSString stringWithFormat:UCLocalize("FROM"), from];
+        source_ = [NSString stringWithFormat:UCLocalize("FROM"), from];
 
-    if (NSString *purpose = [package primaryPurpose])
-        badge_ = [UIImage imageAtPath:[NSString stringWithFormat:@"%@/Purposes/%@.png", App_, purpose]];
+        if (NSString *purpose = [package primaryPurpose])
+            badge_ = [UIImage imageAtPath:[NSString stringWithFormat:@"%@/Purposes/%@.png", App_, purpose]];
 
-    UIColor *color;
-    NSString *placard;
+        UIColor *color;
+        NSString *placard;
 
-    if (NSString *mode = [package_ mode]) {
-        if ([mode isEqualToString:@"REMOVE"] || [mode isEqualToString:@"PURGE"]) {
-            color = RemovingColor_;
-            //placard = @"removing";
+        if (NSString *mode = [package mode]) {
+            if ([mode isEqualToString:@"REMOVE"] || [mode isEqualToString:@"PURGE"]) {
+                color = RemovingColor_;
+                placard = @"removing";
+            } else {
+                color = InstallingColor_;
+                placard = @"installing";
+            }
         } else {
-            color = InstallingColor_;
-            //placard = @"installing";
+            color = [UIColor whiteColor];
+
+            if ([package installed] != nil)
+                placard = @"installed";
+            else
+                placard = nil;
         }
 
-        // XXX: the removing/installing placards are not @2x
-        placard = nil;
-    } else {
-        color = [UIColor whiteColor];
+        [content_ setBackgroundColor:color];
 
-        if ([package installed] != nil)
-            placard = @"installed";
-        else
-            placard = nil;
+        if (placard != nil)
+            placard_ = [UIImage imageAtPath:[NSString stringWithFormat:@"%@/%@.png", App_, placard]];
     }
 
-    [content_ setBackgroundColor:color];
-
-    if (placard != nil)
-        placard_ = [UIImage imageAtPath:[NSString stringWithFormat:@"%@/%@.png", App_, placard]];
-
     [self setNeedsDisplay];
     [content_ setNeedsDisplay];
 }
@@ -5431,11 +5731,13 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         CGRect rect;
         rect.size = [(UIImage *) icon_ size];
 
-        rect.size.width /= 4;
-        rect.size.height /= 4;
+        while (rect.size.width > 16 || rect.size.height > 16) {
+            rect.size.width /= 2;
+            rect.size.height /= 2;
+        }
 
-        rect.origin.x = 14 - rect.size.width / 4;
-        rect.origin.y = 14 - rect.size.height / 4;
+        rect.origin.x = 19 - rect.size.width / 2;
+        rect.origin.y = 19 - rect.size.height / 2;
 
         [icon_ drawInRect:rect];
     }
@@ -5447,21 +5749,21 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         rect.size.width /= 4;
         rect.size.height /= 4;
 
-        rect.origin.x = 20 - rect.size.width / 4;
-        rect.origin.y = 20 - rect.size.height / 4;
+        rect.origin.x = 25 - rect.size.width / 2;
+        rect.origin.y = 25 - rect.size.height / 2;
 
         [badge_ drawInRect:rect];
     }
 
-    if (highlighted)
+    if (highlighted && kCFCoreFoundationVersionNumber < 800)
         UISetColor(White_);
 
     if (!highlighted)
         UISetColor(commercial_ ? Purple_ : Black_);
-    [name_ drawAtPoint:CGPointMake(36, 8) forWidth:(width - (placard_ == nil ? 68 : 94)) withFont:Font18Bold_ lineBreakMode:UILineBreakModeTailTruncation];
+    [name_ drawAtPoint:CGPointMake(36, 8) forWidth:(width - (placard_ == nil ? 68 : 94)) withFont:Font18Bold_ lineBreakMode:NSLineBreakByTruncatingTail];
 
     if (placard_ != nil)
-        [placard_ drawAtPoint:CGPointMake(width - 52, 9)];
+        [placard_ drawAtPoint:CGPointMake(width - 52, 11)];
 }
 
 - (void) drawNormalContentRect:(CGRect)rect {
@@ -5472,8 +5774,10 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         CGRect rect;
         rect.size = [(UIImage *) icon_ size];
 
-        rect.size.width /= 2;
-        rect.size.height /= 2;
+        while (rect.size.width > 32 || rect.size.height > 32) {
+            rect.size.width /= 2;
+            rect.size.height /= 2;
+        }
 
         rect.origin.x = 25 - rect.size.width / 2;
         rect.origin.y = 25 - rect.size.height / 2;
@@ -5494,17 +5798,17 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         [badge_ drawInRect:rect];
     }
 
-    if (highlighted)
+    if (highlighted && kCFCoreFoundationVersionNumber < 800)
         UISetColor(White_);
 
     if (!highlighted)
         UISetColor(commercial_ ? Purple_ : Black_);
-    [name_ drawAtPoint:CGPointMake(48, 8) forWidth:(width - (placard_ == nil ? 80 : 106)) withFont:Font18Bold_ lineBreakMode:UILineBreakModeTailTruncation];
-    [source_ drawAtPoint:CGPointMake(58, 29) forWidth:(width - 95) withFont:Font12_ lineBreakMode:UILineBreakModeTailTruncation];
+    [name_ drawAtPoint:CGPointMake(48, 8) forWidth:(width - (placard_ == nil ? 80 : 106)) withFont:Font18Bold_ lineBreakMode:NSLineBreakByTruncatingTail];
+    [source_ drawAtPoint:CGPointMake(58, 29) forWidth:(width - 95) withFont:Font12_ lineBreakMode:NSLineBreakByTruncatingTail];
 
     if (!highlighted)
         UISetColor(commercial_ ? Purplish_ : Gray_);
-    [description_ drawAtPoint:CGPointMake(12, 46) forWidth:(width - 46) withFont:Font14_ lineBreakMode:UILineBreakModeTailTruncation];
+    [description_ drawAtPoint:CGPointMake(12, 46) forWidth:(width - 46) withFont:Font14_ lineBreakMode:NSLineBreakByTruncatingTail];
 
     if (placard_ != nil)
         [placard_ drawAtPoint:CGPointMake(width - 52, 9)];
@@ -5520,8 +5824,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 @end
 /* }}} */
 /* Section Cell {{{ */
-@interface SectionCell : CYTableViewCell <
-    ContentDelegate
+@interface SectionCell : CyteTableViewCell <
+    CyteTableViewCellDelegate
 > {
     _H<NSString> basic_;
     _H<NSString> section_;
@@ -5541,13 +5845,14 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 - (id) initWithFrame:(CGRect)frame reuseIdentifier:(NSString *)reuseIdentifier {
     if ((self = [super initWithFrame:frame reuseIdentifier:reuseIdentifier]) != nil) {
         icon_ = [UIImage applicationImageNamed:@"folder.png"];
+        // XXX: this initial frame is wrong, but is fixed later
         switch_ = [[[UISwitch alloc] initWithFrame:CGRectMake(218, 9, 60, 25)] autorelease];
         [switch_ addTarget:self action:@selector(onSwitch:) forEvents:UIControlEventValueChanged];
 
         UIView *content([self contentView]);
         CGRect bounds([content bounds]);
 
-        content_ = [[[ContentView alloc] initWithFrame:bounds] autorelease];
+        content_ = [[[CyteTableViewCellContentView alloc] initWithFrame:bounds] autorelease];
         [content_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth];
         [content addSubview:content_];
         [content_ setBackgroundColor:[UIColor whiteColor]];
@@ -5589,7 +5894,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         section_ = [section localized];
 
         name_  = section_ == nil || [section_ length] == 0 ? UCLocalize("NO_SECTION") : (NSString *) section_;
-        count_ = [NSString stringWithFormat:@"%d", [section count]];
+        count_ = [NSString stringWithFormat:@"%zd", [section count]];
 
         if (editing_)
             [switch_ setOn:(isSectionVisible(basic_) ? 1 : 0) animated:NO];
@@ -5605,7 +5910,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     [super setFrame:frame];
 
     CGRect rect([switch_ frame]);
-    [switch_ setFrame:CGRectMake(frame.size.width - 102, 9, rect.size.width, rect.size.height)];
+    [switch_ setFrame:CGRectMake(frame.size.width - rect.size.width - 9, 9, rect.size.width, rect.size.height)];
 }
 
 - (NSString *) accessibilityLabel {
@@ -5615,24 +5920,24 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 - (void) drawContentRect:(CGRect)rect {
     bool highlighted(highlighted_ && !editing_);
 
-    [icon_ drawInRect:CGRectMake(8, 7, 32, 32)];
+    [icon_ drawInRect:CGRectMake(7, 7, 32, 32)];
 
-    if (highlighted)
+    if (highlighted && kCFCoreFoundationVersionNumber < 800)
         UISetColor(White_);
 
     float width(rect.size.width);
     if (editing_)
-        width -= 87;
+        width -= 9 + [switch_ frame].size.width;
 
     if (!highlighted)
         UISetColor(Black_);
-    [name_ drawAtPoint:CGPointMake(48, 9) forWidth:(width - 70) withFont:Font22Bold_ lineBreakMode:UILineBreakModeTailTruncation];
+    [name_ drawAtPoint:CGPointMake(48, 12) forWidth:(width - 58) withFont:Font18_ lineBreakMode:NSLineBreakByTruncatingTail];
 
     CGSize size = [count_ sizeWithFont:Font14_];
 
-    UISetColor(White_);
+    UISetColor(Folder_);
     if (count_ != nil)
-        [count_ drawAtPoint:CGPointMake(13 + (29 - size.width) / 2, 16) withFont:Font12Bold_];
+        [count_ drawAtPoint:CGPointMake(10 + (30 - size.width) / 2, 18) withFont:Font12Bold_];
 }
 
 @end
@@ -5647,7 +5952,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     _H<Package> package_;
     _H<NSString> name_;
     _H<NSMutableArray> files_;
-    _H<UITableView> list_;
+    _H<UITableView, 2> list_;
 }
 
 - (id) initWithDatabase:(Database *)database;
@@ -5657,12 +5962,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 @implementation FileTable
 
-- (void) dealloc {
-    [(UITableView *) list_ setDataSource:nil];
-    [list_ setDelegate:nil];
-    [super dealloc];
-}
-
 - (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
     return files_ == nil ? 0 : [files_ count];
 }
@@ -5690,14 +5989,12 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (void) loadView {
-    [self setView:[[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease]];
-
-    list_ = [[[UITableView alloc] initWithFrame:[[self view] bounds]] autorelease];
+    list_ = [[[UITableView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease];
     [list_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth];
     [list_ setRowHeight:24.0f];
     [(UITableView *) list_ setDataSource:self];
     [list_ setDelegate:self];
-    [[self view] addSubview:list_];
+    [self setView:list_];
 }
 
 - (void) viewDidLoad {
@@ -5708,13 +6005,16 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 - (void) releaseSubviews {
     list_ = nil;
+
+    package_ = nil;
+    files_ = nil;
+
+    [super releaseSubviews];
 }
 
 - (id) initWithDatabase:(Database *)database {
     if ((self = [super init]) != nil) {
         database_ = database;
-
-        files_ = [NSMutableArray arrayWithCapacity:32];
     } return self;
 }
 
@@ -5722,7 +6022,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     package_ = nil;
     name_ = nil;
 
-    [files_ removeAllObjects];
+    files_ = [NSMutableArray arrayWithCapacity:32];
 
     if (package != nil) {
         package_ = package;
@@ -5776,7 +6076,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     _H<UIBarButtonItem> button_;
 }
 
-- (id) initWithDatabase:(Database *)database forPackage:(NSString *)name;
+- (id) initWithDatabase:(Database *)database forPackage:(NSString *)name withReferrer:(NSString *)referrer;
 
 @end
 
@@ -5849,20 +6149,10 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     }
 }
 
-// We don't want to allow non-commercial packages to do custom things to the install button,
-// so it must call customButtonClicked with a custom commercial_ == 1 fallthrough.
-- (void) customButtonClicked {
-    if (commercial_)
-        [super customButtonClicked];
-    else
-        [self _customButtonClicked];
-}
-
 - (void) reloadButtonClicked {
-    // Don't reload a commerical package by tapping the loading button,
-    // but if it's not an Install button, we should forward it on.
-    if (![package_ uninstalled])
-        [self _customButtonClicked];
+    if (commercial_ && function_ == nil && [package_ uninstalled])
+        return;
+    [self customButtonClicked];
 }
 
 - (void) applyLoadingTitle {
@@ -5874,12 +6164,12 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 #endif
 
-- (id) initWithDatabase:(Database *)database forPackage:(NSString *)name {
+- (id) initWithDatabase:(Database *)database forPackage:(NSString *)name withReferrer:(NSString *)referrer {
     if ((self = [super init]) != nil) {
         database_ = database;
         buttons_ = [NSMutableArray arrayWithCapacity:4];
-        name_ = [NSString stringWithString:name];
-        [self setURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/#!/package/%@", UI_, (id) name_]]];
+        name_ = name == nil ? @"" : [NSString stringWithString:name];
+        [self setURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/#!/package/%@", UI_, (id) name_]] withReferrer:referrer];
     } return self;
 }
 
@@ -5937,12 +6227,13 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 > {
     _transient Database *database_;
     unsigned era_;
-    _H<NSMutableArray> packages_;
+    _H<NSArray> packages_;
     _H<NSMutableArray> sections_;
-    _H<UITableView> list_;
+    _H<UITableView, 2> list_;
     _H<NSMutableArray> index_;
     _H<NSMutableDictionary> indices_;
     _H<NSString> title_;
+    unsigned reloading_;
 }
 
 - (id) initWithDatabase:(Database *)database title:(NSString *)title;
@@ -5954,16 +6245,18 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 @implementation PackageListController
 
-- (void) dealloc {
-    [list_ setDataSource:nil];
-    [list_ setDelegate:nil];
-    [super dealloc];
+- (NSURL *) referrerURL {
+    return [self navigationURL];
 }
 
 - (bool) isSummarized {
     return false;
 }
 
+- (bool) showsSections {
+    return true;
+}
+
 - (void) deselectWithAnimation:(BOOL)animated {
     [list_ deselectRowAtIndexPath:[list_ indexPathForSelectedRow] animated:animated];
 }
@@ -5989,31 +6282,45 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     [self resizeForKeyboardBounds:bounds duration:0];
 }
 
+- (void) getKeyboardCurve:(UIViewAnimationCurve *)curve duration:(NSTimeInterval *)duration forNotification:(NSNotification *)notification {
+    if (&UIKeyboardAnimationCurveUserInfoKey == NULL)
+        *curve = UIViewAnimationCurveEaseInOut;
+    else
+        [[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:curve];
+
+    if (&UIKeyboardAnimationDurationUserInfoKey == NULL)
+        *duration = 0.3;
+    else
+        [[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:duration];
+}
+
 - (void) keyboardWillShow:(NSNotification *)notification {
     CGRect bounds;
     CGPoint center;
-    NSTimeInterval duration;
-    UIViewAnimationCurve curve;
     [[[notification userInfo] objectForKey:UIKeyboardBoundsUserInfoKey] getValue:&bounds];
     [[[notification userInfo] objectForKey:UIKeyboardCenterEndUserInfoKey] getValue:&center];
-    [[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&curve];
-    [[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&duration];
+
+    NSTimeInterval duration;
+    UIViewAnimationCurve curve;
+    [self getKeyboardCurve:&curve duration:&duration forNotification:notification];
 
     CGRect kbframe = CGRectMake(round(center.x - bounds.size.width / 2.0), round(center.y - bounds.size.height / 2.0), bounds.size.width, bounds.size.height);
     UIViewController *base = self;
-    while ([base parentViewController] != nil)
-        base = [base parentViewController];
+    while ([base parentOrPresentingViewController] != nil)
+        base = [base parentOrPresentingViewController];
     CGRect viewframe = [[base view] convertRect:[list_ frame] fromView:[list_ superview]];
     CGRect intersection = CGRectIntersection(viewframe, kbframe);
 
+    if (kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber_iPhoneOS_3_0) // XXX: _UIApplicationLinkedOnOrAfter(4)
+        intersection.size.height += CYStatusBarHeight();
+
     [self resizeForKeyboardBounds:intersection duration:duration curve:curve];
 }
 
 - (void) keyboardWillHide:(NSNotification *)notification {
     NSTimeInterval duration;
     UIViewAnimationCurve curve;
-    [[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&curve];
-    [[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&duration];
+    [self getKeyboardCurve:&curve duration:&duration forNotification:notification];
 
     [self resizeForKeyboardBounds:CGRectZero duration:duration curve:curve];
 }
@@ -6040,7 +6347,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (void) didSelectPackage:(Package *)package {
-    CYPackageController *view([[[CYPackageController alloc] initWithDatabase:database_ forPackage:[package id]] autorelease]);
+    CYPackageController *view([[[CYPackageController alloc] initWithDatabase:database_ forPackage:[package id] withReferrer:[[self referrerURL] absoluteString]] autorelease]);
     [view setDelegate:delegate_];
     [[self navigationController] pushViewController:view animated:YES];
 }
@@ -6083,7 +6390,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     PackageCell *cell((PackageCell *) [table dequeueReusableCellWithIdentifier:@"Package"]);
     if (cell == nil)
         cell = [[[PackageCell alloc] init] autorelease];
-    [cell setPackage:[self packageAtIndexPath:path] asSummary:[self isSummarized]];
+
+    Package *package([database_ packageWithName:[[self packageAtIndexPath:path] id]]);
+    [cell setPackage:package asSummary:[self isSummarized]];
     return cell;
 }
 
@@ -6094,7 +6403,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (NSArray *) sectionIndexTitlesForTableView:(UITableView *)tableView {
-    if ([self isSummarized])
+    if (![self showsSections])
         return nil;
 
     return index_;
@@ -6119,75 +6428,104 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         database_ = database;
         title_ = [title copy];
         [[self navigationItem] setTitle:title_];
+    } return self;
+}
 
-#if TryIndexedCollation
-        if ([[self class] hasIndexedCollation])
-            index_ = [[objc_getClass("UILocalizedIndexedCollation") currentCollation] sectionIndexTitles];
-        else
-#endif
-            index_ = [NSMutableArray arrayWithCapacity:32];
+- (void) loadView {
+    UIView *view([[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease]);
+    [view setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight)];
+    [self setView:view];
 
-        indices_ = [NSMutableDictionary dictionaryWithCapacity:32];
+    list_ = [[[UITableView alloc] initWithFrame:[[self view] bounds] style:UITableViewStylePlain] autorelease];
+    [list_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth];
+    [view addSubview:list_];
 
-        packages_ = [NSMutableArray arrayWithCapacity:16];
-        sections_ = [NSMutableArray arrayWithCapacity:16];
+    // XXX: is 20 the most optimal number here?
+    [list_ setSectionIndexMinimumDisplayRowCount:20];
+
+    [(UITableView *) list_ setDataSource:self];
+    [list_ setDelegate:self];
 
-        list_ = [[[UITableView alloc] initWithFrame:[[self view] bounds] style:UITableViewStylePlain] autorelease];
-        [list_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth];
-        [[self view] addSubview:list_];
+    [self updateHeight];
+}
 
-        // XXX: is 20 the most optimal number here?
-        [list_ setSectionIndexMinimumDisplayRowCount:20];
+- (void) releaseSubviews {
+    list_ = nil;
 
-        [(UITableView *) list_ setDataSource:self];
-        [list_ setDelegate:self];
+    packages_ = nil;
+    sections_ = nil;
+    index_ = nil;
+    indices_ = nil;
 
-        [self updateHeight];
-    } return self;
+    [super releaseSubviews];
 }
 
 - (void) setDelegate:(id)delegate {
     delegate_ = delegate;
 }
 
-- (bool) hasPackage:(Package *)package {
-    return true;
+- (bool) shouldYield {
+    return false;
 }
 
-- (bool) shouldYield {
+- (bool) shouldBlock {
     return false;
 }
 
-- (void) _reloadPackages:(NSArray *)packages {
-    [packages_ removeAllObjects];
-    [sections_ removeAllObjects];
+- (NSMutableArray *) _reloadPackages {
+@synchronized (database_) {
+    era_ = [database_ era];
+    NSArray *packages([database_ packages]);
 
-    _profile(PackageTable$reloadData$Filter)
-        for (Package *package in packages)
-            if ([self hasPackage:package])
-                [packages_ addObject:package];
-    _end
-}
+    return [NSMutableArray arrayWithArray:packages];
+} }
 
 - (void) _reloadData {
-    era_ = [database_ era];
-    NSArray *packages = [database_ packages];
+    if (reloading_ != 0) {
+        reloading_ = 2;
+        return;
+    }
+
+    NSArray *packages;
 
+  reload:
     if ([self shouldYield]) {
-        UIProgressHUD *hud([delegate_ addProgressHUD]);
-        [hud setText:UCLocalize("LOADING")];
-        [self yieldToSelector:@selector(_reloadPackages:) withObject:packages];
-        [delegate_ removeProgressHUD:hud];
+        do {
+            UIProgressHUD *hud;
+
+            if (![self shouldBlock])
+                hud = nil;
+            else {
+                hud = [delegate_ addProgressHUD];
+                [hud setText:UCLocalize("LOADING")];
+            }
+
+            reloading_ = 1;
+            packages = [self yieldToSelector:@selector(_reloadPackages)];
+
+            if (hud != nil)
+                [delegate_ removeProgressHUD:hud];
+        } while (reloading_ == 2);
     } else {
-        [self _reloadPackages:packages];
+        packages = [self _reloadPackages];
     }
 
-    [indices_ removeAllObjects];
+@synchronized (database_) {
+    if (era_ != [database_ era])
+        goto reload;
+    reloading_ = 0;
+
+    packages_ = packages;
+
+    indices_ = [NSMutableDictionary dictionaryWithCapacity:32];
+    sections_ = [NSMutableArray arrayWithCapacity:16];
 
     Section *section = nil;
 
 #if TryIndexedCollation
     if ([[self class] hasIndexedCollation]) {
+        index_ = [[objc_getClass("UILocalizedIndexedCollation") currentCollation] sectionIndexTitles];
+
         id collation = [objc_getClass("UILocalizedIndexedCollation") currentCollation];
         NSArray *titles = [collation sectionIndexTitles];
         int secidx = -1;
@@ -6220,10 +6558,10 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     } else
 #endif
     {
-        [index_ removeAllObjects];
+        index_ = [NSMutableArray arrayWithCapacity:32];
 
-        bool summary([self isSummarized]);
-        if (summary) {
+        bool sectioned([self showsSections]);
+        if (!sectioned) {
             section = [[[Section alloc] initWithName:nil localize:false] autorelease];
             [sections_ addObject:section];
         }
@@ -6238,7 +6576,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
                     index = [package index];
                 _end
 
-                if (!summary && (section == nil || [section index] != index)) {
+                if (sectioned && (section == nil || [section index] != index)) {
                     _profile(PackageTable$reloadData$Section$Allocate)
                         section = [[[Section alloc] initWithIndex:index row:offset] autorelease];
                     _end
@@ -6262,11 +6600,15 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         [(UITableView *) list_ setDataSource:self];
         [list_ reloadData];
     _end
-}
+} }
 
 - (void) reloadData {
     [super reloadData];
-    [self performSelector:@selector(_reloadData) withObject:nil afterDelay:0];
+
+    if ([self shouldYield])
+        [self performSelector:@selector(_reloadData) withObject:nil afterDelay:0];
+    else
+        [self _reloadData];
 }
 
 - (void) resetCursor {
@@ -6289,10 +6631,15 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     SEL filter_;
     IMP imp_;
     _H<NSObject> object_;
+    _H<NSObject> stuff_;
 }
 
 - (void) setObject:(id)object;
+- (void) setStuff:(id)object;
+- (void) setObject:(id)object andStuff:(id)stuff;
+
 - (void) setObject:(id)object forFilter:(SEL)filter;
+- (void) setObject:(id)object andStuff:(id)stuff forFilter:(SEL)filter;
 
 - (SEL) filter;
 - (void) setFilter:(SEL)filter;
@@ -6308,6 +6655,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (void) setFilter:(SEL)filter {
+@synchronized (self) {
     filter_ = filter;
 
     /* XXX: this is an unsafe optimization of doomy hell */
@@ -6315,27 +6663,77 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     _assert(method != NULL);
     imp_ = method_getImplementation(method);
     _assert(imp_ != NULL);
-}
+} }
 
 - (void) setObject:(id)object {
+@synchronized (self) {
     object_ = object;
-}
+} }
+
+- (void) setStuff:(id)stuff {
+@synchronized (self) {
+    stuff_ = stuff;
+} }
+
+- (void) setObject:(id)object andStuff:(id)stuff {
+@synchronized (self) {
+    object_ = object;
+    stuff_ = stuff;
+} }
 
 - (void) setObject:(id)object forFilter:(SEL)filter {
+@synchronized (self) {
     [self setFilter:filter];
-    [self setObject:object];
-}
+    object_ = object;
+} }
+
+- (void) setObject:(id)object andStuff:(id)stuff forFilter:(SEL)filter {
+@synchronized (self) {
+    [self setFilter:filter];
+    object_ = object;
+    stuff_ = stuff;
+} }
+
+- (NSMutableArray *) _reloadPackages {
+@synchronized (database_) {
+    era_ = [database_ era];
+    NSArray *packages([database_ packages]);
+
+    NSMutableArray *filtered([NSMutableArray arrayWithCapacity:[packages count]]);
+
+    IMP imp;
+    SEL filter;
+    _H<NSObject> object;
+    _H<NSObject> stuff;
+
+    @synchronized (self) {
+        imp = imp_;
+        filter = filter_;
+        object = object_;
+        stuff = stuff_;
+    }
 
-- (bool) hasPackage:(Package *)package {
-    _profile(FilteredPackageTable$hasPackage)
-        return [package valid] && (*reinterpret_cast<bool (*)(id, SEL, id)>(imp_))(package, filter_, object_);
+    _profile(PackageTable$reloadData$Filter)
+        for (Package *package in packages)
+            if ([package valid] && (*reinterpret_cast<bool (*)(id, SEL, id, id)>(imp))(package, filter, object, stuff))
+                [filtered addObject:package];
     _end
-}
+
+    return filtered;
+} }
 
 - (id) initWithDatabase:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object {
     if ((self = [super initWithDatabase:database title:title]) != nil) {
         [self setFilter:filter];
-        [self setObject:object];
+        object_ = object;
+    } return self;
+}
+
+- (id) initWithDatabase:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object with:(id)stuff {
+    if ((self = [super initWithDatabase:database title:title]) != nil) {
+        [self setFilter:filter];
+        object_ = object;
+        stuff_ = stuff;
     } return self;
 }
 
@@ -6344,19 +6742,41 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 /* Home Controller {{{ */
 @interface HomeController : CydiaWebViewController {
+    CFRunLoopRef runloop_;
+    SCNetworkReachabilityRef reachability_;
 }
 
 @end
 
 @implementation HomeController
 
+static void HomeControllerReachabilityCallback(SCNetworkReachabilityRef reachability, SCNetworkReachabilityFlags flags, void *info) {
+    [(HomeController *) info dispatchEvent:@"CydiaReachabilityCallback"];
+}
+
 - (id) init {
     if ((self = [super init]) != nil) {
         [self setURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/#!/home/", UI_]]];
         [self reloadData];
+
+        reachability_ = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, "cydia.saurik.com");
+        if (reachability_ != NULL) {
+            SCNetworkReachabilityContext context = {0, self, NULL, NULL, NULL};
+            SCNetworkReachabilitySetCallback(reachability_, HomeControllerReachabilityCallback, &context);
+
+            CFRunLoopRef runloop(CFRunLoopGetCurrent());
+            if (SCNetworkReachabilityScheduleWithRunLoop(reachability_, runloop, kCFRunLoopDefaultMode))
+                runloop_ = runloop;
+        }
     } return self;
 }
 
+- (void) dealloc {
+    if (reachability_ != NULL && runloop_ != NULL)
+        SCNetworkReachabilityUnscheduleFromRunLoop(reachability_, runloop_, kCFRunLoopDefaultMode);
+    [super dealloc];
+}
+
 - (NSURL *) navigationURL {
     return [NSURL URLWithString:@"cydia://home"];
 }
@@ -6369,7 +6789,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     [alert setCancelButtonIndex:0];
 
     [alert setMessage:
-        @"Copyright \u00a9 2008-2011\n"
+        @"Copyright \u00a9 2008-2013\n"
         "SaurikIT, LLC\n"
         "\n"
         "Jay Freeman (saurik)\n"
@@ -6389,176 +6809,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     ] autorelease];
 }
 
-- (void) unloadData {
-    [super unloadData];
-    [self reloadData];
-}
-
-@end
-/* }}} */
-/* Manage Controller {{{ */
-@interface ManageController : CydiaWebViewController {
-}
-
-- (void) queueStatusDidChange;
-
-@end
-
-@implementation ManageController
-
-- (id) init {
-    if ((self = [super init]) != nil) {
-        [self setURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/#!/manage/", UI_]]];
-    } return self;
-}
-
-- (NSURL *) navigationURL {
-    return [NSURL URLWithString:@"cydia://manage"];
-}
-
-- (UIBarButtonItem *) leftButton {
-    return [[[UIBarButtonItem alloc]
-        initWithTitle:UCLocalize("SETTINGS")
-        style:UIBarButtonItemStylePlain
-        target:self
-        action:@selector(settingsButtonClicked)
-    ] autorelease];
-}
-
-- (void) settingsButtonClicked {
-    [delegate_ showSettings];
-}
-
-- (void) queueButtonClicked {
-    [delegate_ queue];
-}
-
-- (UIBarButtonItem *) customButton {
-    return Queuing_ ? [[[UIBarButtonItem alloc]
-        initWithTitle:UCLocalize("QUEUE")
-        style:UIBarButtonItemStyleDone
-        target:self
-        action:@selector(queueButtonClicked)
-    ] autorelease] : [super customButton];
-}
-
-- (void) queueStatusDidChange {
-    [self applyRightButton];
-}
-
-- (bool) isLoading {
-    return !Queuing_ && [super isLoading];
-}
-
-@end
-/* }}} */
-
-/* Refresh Bar {{{ */
-@interface RefreshBar : UINavigationBar {
-    _H<UIProgressIndicator> indicator_;
-    _H<UITextLabel> prompt_;
-    _H<UIProgressBar> progress_;
-    _H<UINavigationButton> cancel_;
-}
-
-@end
-
-@implementation RefreshBar
-
-- (void) positionViews {
-    CGRect frame = [cancel_ frame];
-    frame.size = [cancel_ sizeThatFits:frame.size];
-    frame.origin.x = [self frame].size.width - frame.size.width - 5;
-    frame.origin.y = ([self frame].size.height - frame.size.height) / 2;
-    [cancel_ setFrame:frame];
-
-    CGSize prgsize = {75, 100};
-    CGRect prgrect = {{
-        [self frame].size.width - prgsize.width - 10,
-        ([self frame].size.height - prgsize.height) / 2
-    } , prgsize};
-    [progress_ setFrame:prgrect];
-
-    CGSize indsize([UIProgressIndicator defaultSizeForStyle:[indicator_ activityIndicatorViewStyle]]);
-    unsigned indoffset = ([self frame].size.height - indsize.height) / 2;
-    CGRect indrect = {{indoffset, indoffset}, indsize};
-    [indicator_ setFrame:indrect];
-
-    CGSize prmsize = {215, indsize.height + 4};
-    CGRect prmrect = {{
-        indoffset * 2 + indsize.width,
-        unsigned([self frame].size.height - prmsize.height) / 2 - 1
-    }, prmsize};
-    [prompt_ setFrame:prmrect];
-}
-
-- (void) setFrame:(CGRect)frame {
-    [super setFrame:frame];
-    [self positionViews];
-}
-
-- (id) initWithFrame:(CGRect)frame delegate:(id)delegate {
-    if ((self = [super initWithFrame:frame]) != nil) {
-        [self setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
-
-        [self setBarStyle:UIBarStyleBlack];
-
-        UIBarStyle barstyle([self _barStyle:NO]);
-        bool ugly(barstyle == UIBarStyleDefault);
-
-        UIProgressIndicatorStyle style = ugly ?
-            UIProgressIndicatorStyleMediumBrown :
-            UIProgressIndicatorStyleMediumWhite;
-
-        indicator_ = [[[UIProgressIndicator alloc] initWithFrame:CGRectZero] autorelease];
-        [(UIProgressIndicator *) indicator_ setStyle:style];
-        [indicator_ startAnimation];
-        [self addSubview:indicator_];
-
-        prompt_ = [[[UITextLabel alloc] initWithFrame:CGRectZero] autorelease];
-        [prompt_ setColor:[UIColor colorWithCGColor:(ugly ? Blueish_ : Off_)]];
-        [prompt_ setBackgroundColor:[UIColor clearColor]];
-        [prompt_ setFont:[UIFont systemFontOfSize:15]];
-        [self addSubview:prompt_];
-
-        progress_ = [[[UIProgressBar alloc] initWithFrame:CGRectZero] autorelease];
-        [progress_ setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleLeftMargin];
-        [(UIProgressBar *) progress_ setStyle:0];
-        [self addSubview:progress_];
-
-        cancel_ = [[[UINavigationButton alloc] initWithTitle:UCLocalize("CANCEL") style:UINavigationButtonStyleHighlighted] autorelease];
-        [cancel_ setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin];
-        [cancel_ addTarget:delegate action:@selector(cancelPressed) forControlEvents:UIControlEventTouchUpInside];
-        [cancel_ setBarStyle:barstyle];
-
-        [self positionViews];
-    } return self;
-}
-
-- (void) setCancellable:(bool)cancellable {
-    if (cancellable)
-        [self addSubview:cancel_];
-    else
-        [cancel_ removeFromSuperview];
-}
-
-- (void) start {
-    [prompt_ setText:UCLocalize("UPDATING_DATABASE")];
-    [progress_ setProgress:0];
-}
-
-- (void) stop {
-    [self setCancellable:NO];
-}
-
-- (void) setPrompt:(NSString *)prompt {
-    [prompt_ setText:prompt];
-}
-
-- (void) setProgress:(float)progress {
-    [progress_ setProgress:progress];
-}
-
 @end
 /* }}} */
 
@@ -6572,62 +6822,26 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 /* }}} */
 
 /* Cydia Tab Bar Controller {{{ */
-@interface CYTabBarController : UITabBarController <
+@interface CydiaTabBarController : CyteTabBarController <
     UITabBarControllerDelegate,
-    ProgressDelegate
+    FetchDelegate
 > {
     _transient Database *database_;
-    _H<RefreshBar> refreshbar_;
 
-    bool dropped_;
+    _H<UIActivityIndicatorView> indicator_;
+
     bool updating_;
     // XXX: ok, "updatedelegate_"?...
     _transient NSObject<CydiaDelegate> *updatedelegate_;
-
-    _H<UIViewController> remembered_;
-    _transient UIViewController *transient_;
 }
 
 - (NSArray *) navigationURLCollection;
-- (void) dropBar:(BOOL)animated;
 - (void) beginUpdate;
-- (void) raiseBar:(BOOL)animated;
 - (BOOL) updating;
-- (void) unloadData;
 
 @end
 
-@implementation CYTabBarController
-
-- (void) setUnselectedViewController:(UIViewController *)transient {
-    NSMutableArray *controllers = [[self viewControllers] mutableCopy];
-    if (transient != nil) {
-        if (transient_ == nil)
-            remembered_ = [controllers objectAtIndex:0];
-        transient_ = transient;
-        [transient_ setTabBarItem:[remembered_ tabBarItem]];
-        [controllers replaceObjectAtIndex:0 withObject:transient_];
-        [self setSelectedIndex:0];
-        [self setViewControllers:controllers];
-        [self concealTabBarSelection];
-    } else if (remembered_ != nil) {
-        [remembered_ setTabBarItem:[transient_ tabBarItem]];
-        transient_ = transient;
-        [controllers replaceObjectAtIndex:0 withObject:remembered_];
-        remembered_ = nil;
-        [self setViewControllers:controllers];
-        [self revealTabBarSelection];
-    }
-}
-
-- (UIViewController *) unselectedViewController {
-    return transient_;
-}
-
-- (void) tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
-    if ([self unselectedViewController])
-        [self setUnselectedViewController:nil];
-}
+@implementation CydiaTabBarController
 
 - (NSArray *) navigationURLCollection {
     NSMutableArray *items([NSMutableArray array]);
@@ -6642,35 +6856,15 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     return items;
 }
 
-- (void) unloadData {
-    UIViewController *selected([self selectedViewController]);
-    for (UINavigationController *controller in [self viewControllers])
-        [controller unloadData];
-
-    [selected reloadData];
-
-    if (UIViewController *unselected = [self unselectedViewController])
-        [unselected reloadData];
-
-    [super unloadData];
-}
-
-- (void) dealloc {
-    [refreshbar_ setDelegate:nil];
-    [[NSNotificationCenter defaultCenter] removeObserver:self];
-
-    [super dealloc];
-}
-
 - (id) initWithDatabase:(Database *)database {
     if ((self = [super init]) != nil) {
         database_ = database;
         [self setDelegate:self];
 
-        [[self view] setAutoresizingMask:UIViewAutoresizingFlexibleBoth];
-        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarFrameChanged:) name:UIApplicationDidChangeStatusBarFrameNotification object:nil];
+        indicator_ = [[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteTiny] autorelease];
+        [indicator_ setOrigin:CGPointMake(kCFCoreFoundationVersionNumber >= 800 ? 2 : 4, 2)];
 
-        refreshbar_ = [[[RefreshBar alloc] initWithFrame:CGRectMake(0, 0, [[self view] frame].size.width, [UINavigationBar defaultSize].height) delegate:self] autorelease];
+        [[self view] setAutoresizingMask:UIViewAutoresizingFlexibleBoth];
     } return self;
 }
 
@@ -6679,8 +6873,17 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (void) beginUpdate {
-    [(RefreshBar *) refreshbar_ start];
-    [self dropBar:YES];
+    if (updating_)
+        return;
+
+    UIViewController *controller([[self viewControllers] objectAtIndex:1]);
+    UITabBarItem *item([controller tabBarItem]);
+
+    [item setBadgeValue:@""];
+    UIView *badge(MSHookIvar<UIView *>([item view], "_badge"));
+
+    [indicator_ startAnimating];
+    [badge addSubview:indicator_];
 
     [updatedelegate_ retainNetworkActivityIndicator];
     updating_ = true;
@@ -6692,9 +6895,10 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     ];
 }
 
-- (void) performUpdate { _pooled
-    Status status;
-    status.setDelegate(self);
+- (void) performUpdate {
+    NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
+
+    SourceStatus status(self, database_);
     [database_ updateWithStatus:status];
 
     [self
@@ -6702,14 +6906,19 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         withObject:nil
         waitUntilDone:NO
     ];
+
+    [pool release];
 }
 
 - (void) stopUpdateWithSelector:(SEL)selector {
     updating_ = false;
     [updatedelegate_ releaseNetworkActivityIndicator];
 
-    [self raiseBar:YES];
-    [refreshbar_ stop];
+    UIViewController *controller([[self viewControllers] objectAtIndex:1]);
+    [[controller tabBarItem] setBadgeValue:nil];
+
+    [indicator_ removeFromSuperview];
+    [indicator_ stopAnimating];
 
     [updatedelegate_ performSelector:selector withObject:nil afterDelay:0];
 }
@@ -6721,7 +6930,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (void) cancelUpdate {
-    [self stopUpdateWithSelector:@selector(updateData)];
+    [self stopUpdateWithSelector:@selector(updateDataAndLoad)];
 }
 
 - (void) cancelPressed {
@@ -6732,118 +6941,27 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     return updating_;
 }
 
-- (void) addProgressEvent:(CydiaProgressEvent *)event {
-    [refreshbar_ setPrompt:[event compoundMessage]];
-}
-
-- (bool) isProgressCancelled {
+- (bool) isSourceCancelled {
     return !updating_;
 }
 
-- (void) setProgressCancellable:(NSNumber *)cancellable {
-    [refreshbar_ setCancellable:(updating_ && [cancellable boolValue])];
-}
-
-- (void) setProgressPercent:(NSNumber *)percent {
-    [refreshbar_ setProgress:[percent floatValue]];
+- (void) startSourceFetch:(NSString *)uri {
 }
 
-- (void) setProgressStatus:(NSDictionary *)status {
-    if (status != nil)
-        [self setProgressPercent:[status objectForKey:@"Percent"]];
+- (void) stopSourceFetch:(NSString *)uri {
 }
 
 - (void) setUpdateDelegate:(id)delegate {
     updatedelegate_ = delegate;
 }
 
-- (CGFloat) statusBarHeight {
-    if (UIInterfaceOrientationIsPortrait([self interfaceOrientation])) {
-        return [[UIApplication sharedApplication] statusBarFrame].size.height;
-    } else {
-        return [[UIApplication sharedApplication] statusBarFrame].size.width;
-    }
-}
-
 - (UIView *) transitionView {
-    if ([self respondsToSelector:@selector(_transitionView)])
-        return [self _transitionView];
-    else
+    if (![self respondsToSelector:@selector(_transitionView)])
         return MSHookIvar<id>(self, "_viewControllerTransitionView");
-}
-
-- (void) dropBar:(BOOL)animated {
-    if (dropped_)
-        return;
-    dropped_ = true;
-
-    UIView *transition([self transitionView]);
-    [[self view] addSubview:refreshbar_];
-
-    CGRect barframe([refreshbar_ frame]);
-
-    if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iPhoneOS_3_0) // XXX: _UIApplicationLinkedOnOrAfter(4)
-        barframe.origin.y = [self statusBarHeight];
+    else if (kCFCoreFoundationVersionNumber < 800)
+        return [self _transitionView];
     else
-        barframe.origin.y = 0;
-
-    [refreshbar_ setFrame:barframe];
-
-    if (animated)
-        [UIView beginAnimations:nil context:NULL];
-
-    CGRect viewframe = [transition frame];
-    viewframe.origin.y += barframe.size.height;
-    viewframe.size.height -= barframe.size.height;
-    [transition setFrame:viewframe];
-
-    if (animated)
-        [UIView commitAnimations];
-
-    // Ensure bar has the proper width for our view, it might have changed
-    barframe.size.width = viewframe.size.width;
-    [refreshbar_ setFrame:barframe];
-}
-
-- (void) raiseBar:(BOOL)animated {
-    if (!dropped_)
-        return;
-    dropped_ = false;
-
-    UIView *transition([self transitionView]);
-    [refreshbar_ removeFromSuperview];
-
-    CGRect barframe([refreshbar_ frame]);
-
-    if (animated)
-        [UIView beginAnimations:nil context:NULL];
-
-    CGRect viewframe = [transition frame];
-    viewframe.origin.y -= barframe.size.height;
-    viewframe.size.height += barframe.size.height;
-    [transition setFrame:viewframe];
-
-    if (animated)
-        [UIView commitAnimations];
-}
-
-- (void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
-    bool dropped(dropped_);
-
-    if (dropped)
-        [self raiseBar:NO];
-
-    [super didRotateFromInterfaceOrientation:fromInterfaceOrientation];
-
-    if (dropped)
-        [self dropBar:NO];
-}
-
-- (void) statusBarFrameChanged:(NSNotification *)notification {
-    if (dropped_) {
-        [self raiseBar:NO];
-        [self dropBar:NO];
-    }
+        return [[[self _transitionView] superview] superview];
 }
 
 @end
@@ -6867,8 +6985,15 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 - (void) reloadData {
     [super reloadData];
 
-    if (UIViewController *visible = [self visibleViewController])
+    UIViewController *visible([self visibleViewController]);
+    if (visible != nil)
         [visible reloadData];
+
+    // on the iPad, this view controller is ALSO visible. :(
+    if (IsWildcat_)
+        if (UIViewController *top = [self topViewController])
+            if (top != visible)
+                [top reloadData];
 }
 
 - (void) unloadData {
@@ -6957,17 +7082,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         Package *package([database packageWithName:path]);
         if (package == nil)
             goto fail;
+        [package parse];
         UIImage *icon([package icon]);
         [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"];
-        [self _returnPNGWithImage:icon forRequest:request];
     } else if ([command isEqualToString:@"uikit-image"]) {
         if (path == nil)
             goto fail;
@@ -6978,8 +7095,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         if (path == nil)
             goto fail;
         path = [path stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
-        NSString *section(Simplify(path));
-        UIImage *icon([UIImage imageAtPath:[NSString stringWithFormat:@"%@/Sections/%@.png", App_, section]]);
+        UIImage *icon([UIImage imageAtPath:[NSString stringWithFormat:@"%@/Sections/%@.png", App_, [path stringByReplacingOccurrencesOfString:@" " withString:@"_"]]]);
         if (icon == nil)
             icon = [UIImage applicationImageNamed:@"unknown.png"];
         [self _returnPNGWithImage:icon forRequest:request];
@@ -6996,37 +7112,52 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 /* Section Controller {{{ */
 @interface SectionController : FilteredPackageListController {
+    _H<NSString> key_;
     _H<NSString> section_;
 }
 
-- (id) initWithDatabase:(Database *)database section:(NSString *)section;
+- (id) initWithDatabase:(Database *)database source:(Source *)source section:(NSString *)section;
 
 @end
 
 @implementation SectionController
 
-- (NSURL *) navigationURL {
-    NSString *name = section_;
-    if (name == nil)
-        name = @"all";
+- (NSURL *) referrerURL {
+    NSString *name(section_);
+    name = name ?: @"*";
+    NSString *key(key_);
+    key = key ?: @"*";
+    return [NSURL URLWithString:[NSString stringWithFormat:@"%@/#!/sections/%@/%@", UI_, [key stringByAddingPercentEscapesIncludingReserved], [name stringByAddingPercentEscapesIncludingReserved]]];
+}
 
-    return [NSURL URLWithString:[NSString stringWithFormat:@"cydia://sections/%@", name]];
+- (NSURL *) navigationURL {
+    NSString *name(section_);
+    name = name ?: @"*";
+    NSString *key(key_);
+    key = key ?: @"*";
+    return [NSURL URLWithString:[NSString stringWithFormat:@"cydia://sections/%@/%@", [key stringByAddingPercentEscapesIncludingReserved], [name stringByAddingPercentEscapesIncludingReserved]]];
 }
 
-- (id) initWithDatabase:(Database *)database section:(NSString *)name {
+- (id) initWithDatabase:(Database *)database source:(Source *)source section:(NSString *)section {
     NSString *title;
-    if (name == nil)
+    if (section == nil)
         title = UCLocalize("ALL_PACKAGES");
-    else if (![name isEqual:@""])
-        title = [[NSBundle mainBundle] localizedStringForKey:Simplify(name) value:nil table:@"Sections"];
+    else if (![section isEqual:@""])
+        title = [[NSBundle mainBundle] localizedStringForKey:Simplify(section) value:nil table:@"Sections"];
     else
         title = UCLocalize("NO_SECTION");
 
-    if ((self = [super initWithDatabase:database title:title filter:@selector(isVisibleInSection:) with:name]) != nil) {
-        section_ = name;
+    if ((self = [super initWithDatabase:database title:title filter:@selector(isVisibleInSection:source:) with:section with:source]) != nil) {
+        key_ = [source key];
+        section_ = section;
     } return self;
 }
 
+- (void) reloadData {
+    [super setStuff:[database_ sourceWithKey:key_]];
+    [super reloadData];
+}
+
 @end
 /* }}} */
 /* Sections Controller {{{ */
@@ -7035,12 +7166,13 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     UITableViewDelegate
 > {
     _transient Database *database_;
+    _H<NSString> key_;
     _H<NSMutableArray> sections_;
     _H<NSMutableArray> filtered_;
-    _H<UITableView> list_;
+    _H<UITableView, 2> list_;
 }
 
-- (id) initWithDatabase:(Database *)database;
+- (id) initWithDatabase:(Database *)database source:(Source *)source;
 - (void) editButtonClicked;
 
 @end
@@ -7048,7 +7180,13 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 @implementation SectionsController
 
 - (NSURL *) navigationURL {
-    return [NSURL URLWithString:@"cydia://sections"];
+    return [NSURL URLWithString:[NSString stringWithFormat:@"cydia://sources/%@", [key_ stringByAddingPercentEscapesIncludingReserved]]];
+}
+
+- (Source *) source {
+    if (key_ == nil)
+        return nil;
+    return [database_ sourceWithKey:key_];
 }
 
 - (void) updateNavigationItem {
@@ -7082,14 +7220,14 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 - (void) viewWillDisappear:(BOOL)animated {
     [super viewWillDisappear:animated];
-    if ([self isEditing]) [self setEditing:NO];
+    [self setEditing:NO];
 }
 
 - (Section *) sectionAtIndexPath:(NSIndexPath *)indexPath {
     Section *section = nil;
     int index = [indexPath row];
     if (![self isEditing]) {
-        index -= 1; 
+        index -= 1;
         if (index >= 0)
             section = [filtered_ objectAtIndex:index];
     } else {
@@ -7129,6 +7267,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
     SectionController *controller = [[[SectionController alloc]
         initWithDatabase:database_
+        source:[self source]
         section:[section name]
     ] autorelease];
     [controller setDelegate:delegate_];
@@ -7137,14 +7276,12 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (void) loadView {
-    [self setView:[[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease]];
-
-    list_ = [[[UITableView alloc] initWithFrame:[[self view] bounds]] autorelease];
+    list_ = [[[UITableView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease];
     [list_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth];
-    [list_ setRowHeight:45.0f];
+    [list_ setRowHeight:46];
     [(UITableView *) list_ setDataSource:self];
     [list_ setDelegate:self];
-    [[self view] addSubview:list_];
+    [self setView:list_];
 }
 
 - (void) viewDidLoad {
@@ -7155,14 +7292,17 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 - (void) releaseSubviews {
     list_ = nil;
+
+    sections_ = nil;
+    filtered_ = nil;
+
+    [super releaseSubviews];
 }
 
-- (id) initWithDatabase:(Database *)database {
+- (id) initWithDatabase:(Database *)database source:(Source *)source {
     if ((self = [super init]) != nil) {
         database_ = database;
-
-        sections_ = [NSMutableArray arrayWithCapacity:16];
-        filtered_ = [NSMutableArray arrayWithCapacity:16];
+        key_ = [source key];
     } return self;
 }
 
@@ -7171,13 +7311,18 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
     NSArray *packages = [database_ packages];
 
-    [sections_ removeAllObjects];
-    [filtered_ removeAllObjects];
+    sections_ = [NSMutableArray arrayWithCapacity:16];
+    filtered_ = [NSMutableArray arrayWithCapacity:16];
 
     NSMutableDictionary *sections([NSMutableDictionary dictionaryWithCapacity:32]);
 
+    Source *source([self source]);
+
     _trace();
     for (Package *package in packages) {
+        if (source != nil && [package source] != source)
+            continue;
+
         NSString *name([package section]);
         NSString *key(name == nil ? @"" : name);
 
@@ -7237,9 +7382,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 > {
     _transient Database *database_;
     unsigned era_;
-    CFMutableArrayRef packages_;
+    _H<NSMutableArray> packages_;
     _H<NSMutableArray> sections_;
-    _H<UITableView> list_;
+    _H<UITableView, 2> list_;
     unsigned upgrades_;
 }
 
@@ -7249,11 +7394,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 @implementation ChangesController
 
-- (void) dealloc {
-    CFRelease(packages_);
-    [super dealloc];
-}
-
 - (NSURL *) navigationURL {
     return [NSURL URLWithString:@"cydia://changes"];
 }
@@ -7280,10 +7420,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     return [[sections_ objectAtIndex:section] count];
 }
 
-- (Package *) packageAtIndex:(NSUInteger)index {
-    return (Package *) CFArrayGetValueAtIndex(packages_, index);
-}
-
 - (Package *) packageAtIndexPath:(NSIndexPath *)path {
 @synchronized (database_) {
     if ([database_ era] != era_)
@@ -7294,43 +7430,76 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         return nil;
     Section *section([sections_ objectAtIndex:sectionIndex]);
     NSInteger row([path row]);
-    return [[[self packageAtIndex:([section row] + row)] retain] autorelease];
+    return [[[packages_ objectAtIndex:([section row] + row)] retain] autorelease];
 } }
 
 - (UITableViewCell *) tableView:(UITableView *)table cellForRowAtIndexPath:(NSIndexPath *)path {
     PackageCell *cell((PackageCell *) [table dequeueReusableCellWithIdentifier:@"Package"]);
     if (cell == nil)
         cell = [[[PackageCell alloc] init] autorelease];
-    [cell setPackage:[self packageAtIndexPath:path] asSummary:false];
+
+    Package *package([database_ packageWithName:[[self packageAtIndexPath:path] id]]);
+    [cell setPackage:package asSummary:false];
     return cell;
 }
 
 - (NSIndexPath *) tableView:(UITableView *)table willSelectRowAtIndexPath:(NSIndexPath *)path {
     Package *package([self packageAtIndexPath:path]);
-    CYPackageController *view([[[CYPackageController alloc] initWithDatabase:database_ forPackage:[package id]] autorelease]);
+    CYPackageController *view([[[CYPackageController alloc] initWithDatabase:database_ forPackage:[package id] withReferrer:[NSString stringWithFormat:@"%@/#!/changes/", UI_]] autorelease]);
     [view setDelegate:delegate_];
     [[self navigationController] pushViewController:view animated:YES];
     return path;
 }
 
-- (void) refreshButtonClicked {
-    [delegate_ beginUpdate];
-    [[self navigationItem] setLeftBarButtonItem:nil animated:YES];
-}
+- (void) alertView:(UIAlertView *)alert clickedButtonAtIndex:(NSInteger)button {
+    NSString *context([alert context]);
 
-- (void) upgradeButtonClicked {
-    [delegate_ distUpgrade];
+    if ([context isEqualToString:@"norefresh"])
+        [alert dismissWithClickedButtonIndex:-1 animated:YES];
 }
 
-- (void) loadView {
-    [self setView:[[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease]];
-
-    list_ = [[[UITableView alloc] initWithFrame:[[self view] bounds] style:UITableViewStylePlain] autorelease];
-    [list_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth];
+- (void) setLeftBarButtonItem {
+    if ([delegate_ updating])
+        [[self navigationItem] setLeftBarButtonItem:[[[UIBarButtonItem alloc]
+            initWithTitle:UCLocalize("CANCEL")
+            style:UIBarButtonItemStyleDone
+            target:self
+            action:@selector(cancelButtonClicked)
+        ] autorelease] animated:YES];
+    else
+        [[self navigationItem] setLeftBarButtonItem:[[[UIBarButtonItem alloc]
+            initWithTitle:UCLocalize("REFRESH")
+            style:UIBarButtonItemStylePlain
+            target:self
+            action:@selector(refreshButtonClicked)
+        ] autorelease] animated:YES];
+}
+
+- (void) refreshButtonClicked {
+    if ([delegate_ requestUpdate])
+        [self setLeftBarButtonItem];
+}
+
+- (void) cancelButtonClicked {
+    [delegate_ cancelUpdate];
+}
+
+- (void) upgradeButtonClicked {
+    [delegate_ distUpgrade];
+    [[self navigationItem] setRightBarButtonItem:nil animated:YES];
+}
+
+- (void) loadView {
+    UIView *view([[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease]);
+    [view setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight)];
+    [self setView:view];
+
+    list_ = [[[UITableView alloc] initWithFrame:[view bounds] style:UITableViewStylePlain] autorelease];
+    [list_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth];
     [list_ setRowHeight:73];
     [(UITableView *) list_ setDataSource:self];
     [list_ setDelegate:self];
-    [[self view] addSubview:list_];
+    [view addSubview:list_];
 }
 
 - (void) viewDidLoad {
@@ -7341,52 +7510,63 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 - (void) releaseSubviews {
     list_ = nil;
+
+    packages_ = nil;
+    sections_ = nil;
+
+    [super releaseSubviews];
 }
 
 - (id) initWithDatabase:(Database *)database {
     if ((self = [super init]) != nil) {
         database_ = database;
-
-        packages_ = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
-        sections_ = [NSMutableArray arrayWithCapacity:16];
     } return self;
 }
 
-// this mostly works because reloadData (below) is @synchronized (database_)
-// XXX: that said, I've been running into problems with NSRangeExceptions :(
-- (void) _reloadPackages:(NSArray *)packages {
-    CFRelease(packages_);
-    packages_ = CFArrayCreateMutable(kCFAllocatorDefault, [packages count], NULL);
+- (NSMutableArray *) _reloadPackages {
+@synchronized (database_) {
+    era_ = [database_ era];
+    NSArray *packages([database_ packages]);
+
+    NSMutableArray *filtered([NSMutableArray arrayWithCapacity:[packages count]]);
 
     _trace();
     _profile(ChangesController$_reloadPackages$Filter)
         for (Package *package in packages)
             if ([package upgradableAndEssential:YES] || [package visible])
-                CFArrayAppendValue(packages_, package);
+                CFArrayAppendValue((CFMutableArrayRef) filtered, package);
     _end
     _trace();
     _profile(ChangesController$_reloadPackages$radixSort)
-        [(NSMutableArray *) packages_ radixSortUsingFunction:reinterpret_cast<SKRadixFunction>(&PackageChangesRadix) withContext:NULL];
+        [filtered radixSortUsingFunction:reinterpret_cast<MenesRadixSortFunction>(&PackageChangesRadix) withContext:NULL];
     _end
     _trace();
-}
+
+    return filtered;
+} }
 
 - (void) _reloadData {
-@synchronized (database_) {
-    era_ = [database_ era];
-    NSArray *packages = [database_ packages];
+    [self setLeftBarButtonItem];
 
-#if 1
-    UIProgressHUD *hud([delegate_ addProgressHUD]);
-    [hud setText:UCLocalize("LOADING")];
-    //NSLog(@"HUD:%@::%@", delegate_, hud);
-    [self yieldToSelector:@selector(_reloadPackages:) withObject:packages];
-    [delegate_ removeProgressHUD:hud];
-#else
-    [self _reloadPackages:packages];
-#endif
+    NSMutableArray *packages;
+
+  reload:
+    if (true) {
+        UIProgressHUD *hud([delegate_ addProgressHUD]);
+        [hud setText:UCLocalize("LOADING")];
+        //NSLog(@"HUD:%@::%@", delegate_, hud);
+        packages = [self yieldToSelector:@selector(_reloadPackages)];
+        [delegate_ removeProgressHUD:hud];
+    } else {
+        packages = [self _reloadPackages];
+    }
+
+@synchronized (database_) {
+    if (era_ != [database_ era])
+        goto reload;
 
-    [sections_ removeAllObjects];
+    packages_ = packages;
+    sections_ = [NSMutableArray arrayWithCapacity:16];
 
     Section *upgradable = [[[Section alloc] initWithName:UCLocalize("AVAILABLE_UPGRADES") localize:NO] autorelease];
     Section *ignored = nil;
@@ -7398,8 +7578,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
     CFDateFormatterRef formatter(CFDateFormatterCreate(NULL, Locale_, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle));
 
-    for (size_t offset = 0, count = CFArrayGetCount(packages_); offset != count; ++offset) {
-        Package *package = [self packageAtIndex:offset];
+    for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
+        Package *package = [packages_ objectAtIndex:offset];
 
         BOOL uae = [package upgradableAndEssential:YES];
 
@@ -7439,7 +7619,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     if (unseens) {
         Section *last = [sections_ lastObject];
         size_t count = [last count];
-        CFArrayReplaceValues(packages_, CFRangeMake(CFArrayGetCount(packages_) - count, count), NULL, 0);
+        [packages_ removeObjectsInRange:NSMakeRange([packages_ count] - count, count)];
         [sections_ removeLastObject];
     }
 
@@ -7450,21 +7630,12 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
     [list_ reloadData];
 
-    if (upgrades_ > 0)
-        [[self navigationItem] setRightBarButtonItem:[[[UIBarButtonItem alloc]
-            initWithTitle:[NSString stringWithFormat:UCLocalize("PARENTHETICAL"), UCLocalize("UPGRADE"), [NSString stringWithFormat:@"%u", upgrades_]]
-            style:UIBarButtonItemStylePlain
-            target:self
-            action:@selector(upgradeButtonClicked)
-        ] autorelease]];
-
-    if (![delegate_ updating])
-        [[self navigationItem] setLeftBarButtonItem:[[[UIBarButtonItem alloc]
-            initWithTitle:UCLocalize("REFRESH")
-            style:UIBarButtonItemStylePlain
-            target:self
-            action:@selector(refreshButtonClicked)
-        ] autorelease]];
+    [[self navigationItem] setRightBarButtonItem:(upgrades_ == 0 ? nil : [[[UIBarButtonItem alloc]
+        initWithTitle:[NSString stringWithFormat:UCLocalize("PARENTHETICAL"), UCLocalize("UPGRADE"), [NSString stringWithFormat:@"%u", upgrades_]]
+        style:UIBarButtonItemStylePlain
+        target:self
+        action:@selector(upgradeButtonClicked)
+    ] autorelease]) animated:YES];
 
     PrintTimes();
 } }
@@ -7480,7 +7651,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 @interface SearchController : FilteredPackageListController <
     UISearchBarDelegate
 > {
-    _H<UISearchBar> search_;
+    _H<UISearchBar, 1> search_;
     BOOL searchloaded_;
 }
 
@@ -7491,31 +7662,32 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 @implementation SearchController
 
-- (void) dealloc {
-    [search_ setDelegate:nil];
-    [super dealloc];
+- (NSURL *) referrerURL {
+    return [NSURL URLWithString:[NSString stringWithFormat:@"%@/#!/search?q=%@", UI_, [([search_ text] ?: @"") stringByAddingPercentEscapesIncludingReserved]]];
 }
 
 - (NSURL *) navigationURL {
     if ([search_ text] == nil || [[search_ text] isEqualToString:@""])
         return [NSURL URLWithString:@"cydia://search"];
     else
-        return [NSURL URLWithString:[NSString stringWithFormat:@"cydia://search/%@", [search_ text]]];
+        return [NSURL URLWithString:[NSString stringWithFormat:@"cydia://search/%@", [[search_ text] stringByAddingPercentEscapesIncludingReserved]]];
+}
+
+- (NSArray *) termsForQuery:(NSString *)query {
+    NSMutableArray *terms([NSMutableArray arrayWithCapacity:2]);
+    for (NSString *component in [query componentsSeparatedByString:@" "])
+        if ([component length] != 0)
+            [terms addObject:component];
+
+    return terms;
 }
 
 - (void) useSearch {
-    [self setObject:[search_ text] forFilter:@selector(isUnfilteredAndSearchedForBy:)];
+    [self setObject:[self termsForQuery:[search_ text]] forFilter:@selector(isUnfilteredAndSearchedForBy:)];
     [self clearData];
     [self reloadData];
 }
 
-- (void) viewWillAppear:(BOOL)animated {
-    [super viewWillAppear:animated];
-
-    if ([self filter] == @selector(isUnfilteredAndSelectedForBy:))
-        [self useSearch];
-}
-
 - (void) searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
     [self setObject:[search_ text] forFilter:@selector(isUnfilteredAndSelectedForBy:)];
     [self clearData];
@@ -7542,6 +7714,10 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (bool) shouldYield {
+    return YES;
+}
+
+- (bool) shouldBlock {
     return [self filter] == @selector(isUnfilteredAndSearchedForBy:);
 }
 
@@ -7549,8 +7725,19 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     return [self filter] == @selector(isUnfilteredAndSelectedForBy:);
 }
 
+- (bool) showsSections {
+    return false;
+}
+
+- (NSMutableArray *) _reloadPackages {
+    NSMutableArray *packages([super _reloadPackages]);
+    if ([self filter] == @selector(isUnfilteredAndSearchedForBy:))
+        [packages radixSortUsingSelector:@selector(rank)];
+    return packages;
+}
+
 - (id) initWithDatabase:(Database *)database query:(NSString *)query {
-    if ((self = [super initWithDatabase:database title:UCLocalize("SEARCH") filter:@selector(isUnfilteredAndSearchedForBy:) with:query])) {
+    if ((self = [super initWithDatabase:database title:UCLocalize("SEARCH") filter:@selector(isUnfilteredAndSearchedForBy:) with:[self termsForQuery:query]])) {
         search_ = [[[UISearchBar alloc] init] autorelease];
         [search_ setDelegate:self];
 
@@ -7578,10 +7765,17 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         [textField setEnablesReturnKeyAutomatically:NO];
         [[self navigationItem] setTitleView:textField];
     }
+
+    if ([self isSummarized])
+        [search_ becomeFirstResponder];
 }
 
 - (void) reloadData {
-    [self setObject:[search_ text]];
+    id object([search_ text]);
+    if ([self filter] == @selector(isUnfilteredAndSearchedForBy:))
+        object = [self termsForQuery:object];
+
+    [self setObject:object];
     [self resetCursor];
 
     [super reloadData];
@@ -7602,7 +7796,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     _transient Database *database_;
     _H<NSString> name_;
     _H<Package> package_;
-    _H<UITableView> table_;
+    _H<UITableView, 2> table_;
     _H<UISwitch> subscribedSwitch_;
     _H<UISwitch> ignoredSwitch_;
     _H<UITableViewCell> subscribedCell_;
@@ -7616,7 +7810,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 @implementation PackageSettingsController
 
 - (NSURL *) navigationURL {
-    return [NSURL URLWithString:[NSString stringWithFormat:@"cydia://package/%@/settings", [package_ id]]];
+    return [NSURL URLWithString:[NSString stringWithFormat:@"cydia://package/%@/settings", (id) name_]];
 }
 
 - (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView {
@@ -7673,18 +7867,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         pclose(dpkg);
 
         exit(0);
-        _assert(false);
-    }
-
-    _forever {
-        int status;
-        int result(waitpid(pid, &status, 0));
-
-        if (result != -1) {
-            _assert(result == pid);
-            break;
-        }
-    }
+    } ReapZombie(pid);
 }
 
 - (void) onIgnored:(id)control {
@@ -7710,13 +7893,15 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (void) loadView {
-    [self setView:[[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease]];
+    UIView *view([[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease]);
+    [view setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight)];
+    [self setView:view];
 
     table_ = [[[UITableView alloc] initWithFrame:[[self view] bounds] style:UITableViewStyleGrouped] autorelease];
     [table_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth];
     [(UITableView *) table_ setDataSource:self];
     [table_ setDelegate:self];
-    [[self view] addSubview:table_];
+    [view addSubview:table_];
 
     subscribedSwitch_ = [[[UISwitch alloc] initWithFrame:CGRectMake(0, 0, 50, 20)] autorelease];
     [subscribedSwitch_ setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin];
@@ -7749,6 +7934,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     table_ = nil;
     ignoredSwitch_ = nil;
     subscribedSwitch_ = nil;
+
+    [super releaseSubviews];
 }
 
 - (id) initWithDatabase:(Database *)database package:(NSString *)package {
@@ -7776,20 +7963,17 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 /* Installed Controller {{{ */
 @interface InstalledController : FilteredPackageListController {
-    BOOL expert_;
 }
 
 - (id) initWithDatabase:(Database *)database;
-
-- (void) updateRoleButton;
 - (void) queueStatusDidChange;
 
 @end
 
 @implementation InstalledController
 
-- (void) dealloc {
-    [super dealloc];
+- (NSURL *) referrerURL {
+    return [NSURL URLWithString:[NSString stringWithFormat:@"%@/#!/installed/", UI_]];
 }
 
 - (NSURL *) navigationURL {
@@ -7798,7 +7982,13 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 - (id) initWithDatabase:(Database *)database {
     if ((self = [super initWithDatabase:database title:UCLocalize("INSTALLED") filter:@selector(isInstalledAndUnfiltered:) with:[NSNumber numberWithBool:YES]]) != nil) {
-        [self updateRoleButton];
+        UISegmentedControl *segmented([[[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:UCLocalize("SIMPLE"), UCLocalize("EXPERT"), nil]] autorelease]);
+        [segmented setSelectedSegmentIndex:0];
+        [segmented setSegmentedControlStyle:UISegmentedControlStyleBar];
+        [[self navigationItem] setTitleView:segmented];
+
+        [segmented addTarget:self action:@selector(modeChanged:) forEvents:UIControlEventValueChanged];
+
         [self queueStatusDidChange];
     } return self;
 }
@@ -7811,67 +8001,98 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 - (void) queueStatusDidChange {
 #if !AlwaysReload
-    if (IsWildcat_) {
-        if (Queuing_) {
-            [[self navigationItem] setLeftBarButtonItem:[[[UIBarButtonItem alloc]
-                initWithTitle:UCLocalize("QUEUE")
-                style:UIBarButtonItemStyleDone
-                target:self
-                action:@selector(queueButtonClicked)
-            ] autorelease]];
-        } else {
-            [[self navigationItem] setLeftBarButtonItem:nil];
-        }
-    }
-#endif
-}
-
-- (void) updateRoleButton {
-    if (Role_ != nil && ![Role_ isEqualToString:@"Developer"])
-        [[self navigationItem] setRightBarButtonItem:[[[UIBarButtonItem alloc]
-            initWithTitle:(expert_ ? UCLocalize("EXPERT") : UCLocalize("SIMPLE"))
-            style:(expert_ ? UIBarButtonItemStyleDone : UIBarButtonItemStylePlain)
+    if (Queuing_) {
+        [[self navigationItem] setLeftBarButtonItem:[[[UIBarButtonItem alloc]
+            initWithTitle:UCLocalize("QUEUE")
+            style:UIBarButtonItemStyleDone
             target:self
-            action:@selector(roleButtonClicked)
+            action:@selector(queueButtonClicked)
         ] autorelease]];
+    } else {
+        [[self navigationItem] setLeftBarButtonItem:nil];
+    }
+#endif
 }
 
-- (void) roleButtonClicked {
-    [self setObject:[NSNumber numberWithBool:expert_]];
+- (void) modeChanged:(UISegmentedControl *)segmented {
+    bool simple([segmented selectedSegmentIndex] == 0);
+    [self setObject:[NSNumber numberWithBool:simple]];
     [self reloadData];
-    expert_ = !expert_;
-
-    [self updateRoleButton];
 }
 
 @end
 /* }}} */
 
 /* Source Cell {{{ */
-@interface SourceCell : CYTableViewCell <
-    ContentDelegate
+@interface SourceCell : CyteTableViewCell <
+    CyteTableViewCellDelegate,
+    SourceDelegate
 > {
+    _H<Source, 1> source_;
+    _H<NSURL> url_;
     _H<UIImage> icon_;
     _H<NSString> origin_;
     _H<NSString> label_;
+    _H<UIActivityIndicatorView> indicator_;
 }
 
 - (void) setSource:(Source *)source;
+- (void) setFetch:(NSNumber *)fetch;
 
 @end
 
 @implementation SourceCell
 
+- (void) _setImage:(NSArray *)data {
+    if ([url_ isEqual:[data objectAtIndex:0]]) {
+        icon_ = [data objectAtIndex:1];
+        [content_ setNeedsDisplay];
+    }
+}
+
+- (void) _setSource:(NSURL *) url {
+    NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
+
+    if (NSData *data = [NSURLConnection
+        sendSynchronousRequest:[NSURLRequest
+            requestWithURL:url
+            cachePolicy:NSURLRequestUseProtocolCachePolicy
+            timeoutInterval:10
+        ]
+
+        returningResponse:NULL
+        error:NULL
+    ])
+        if (UIImage *image = [UIImage imageWithData:data])
+            [self performSelectorOnMainThread:@selector(_setImage:) withObject:[NSArray arrayWithObjects:url, image, nil] waitUntilDone:NO];
+
+    [pool release];
+}
+
 - (void) setSource:(Source *)source {
-    icon_ = nil;
-    if (icon_ == nil)
-        icon_ = [UIImage applicationImageNamed:[NSString stringWithFormat:@"Sources/%@.png", [source host]]];
-    if (icon_ == nil)
-        icon_ = [UIImage applicationImageNamed:@"unknown.png"];
+    source_ = source;
+    [source_ setDelegate:self];
+
+    [self setFetch:[NSNumber numberWithBool:[source_ fetch]]];
+
+    icon_ = [UIImage applicationImageNamed:@"unknown.png"];
 
     origin_ = [source name];
-    label_ = [source uri];
+    label_ = [source rooturi];
+
+    [content_ setNeedsDisplay];
+
+    url_ = [source iconURL];
+    [NSThread detachNewThreadSelector:@selector(_setSource:) toTarget:self withObject:url_];
+}
 
+- (void) setAllSource {
+    source_ = nil;
+    [indicator_ stopAnimating];
+
+    icon_ = [UIImage applicationImageNamed:@"folder.png"];
+    origin_ = UCLocalize("ALL_SOURCES");
+    label_ = UCLocalize("ALL_SOURCES_EX");
     [content_ setNeedsDisplay];
 }
 
@@ -7880,72 +8101,77 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         UIView *content([self contentView]);
         CGRect bounds([content bounds]);
 
-        content_ = [[[ContentView alloc] initWithFrame:bounds] autorelease];
+        content_ = [[[CyteTableViewCellContentView alloc] initWithFrame:bounds] autorelease];
         [content_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth];
         [content_ setBackgroundColor:[UIColor whiteColor]];
         [content addSubview:content_];
 
         [content_ setDelegate:self];
         [content_ setOpaque:YES];
+
+        indicator_ = [[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGraySmall] autorelease];
+        [indicator_ setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin];// | UIViewAutoresizingFlexibleBottomMargin];
+        [content addSubview:indicator_];
+
+        [[content_ layer] setContentsGravity:kCAGravityTopLeft];
     } return self;
 }
 
+- (void) layoutSubviews {
+    [super layoutSubviews];
+
+    UIView *content([self contentView]);
+    CGRect bounds([content bounds]);
+
+    CGRect frame([indicator_ frame]);
+    frame.origin.x = bounds.size.width - frame.size.width;
+    frame.origin.y = (bounds.size.height - frame.size.height) / 2;
+
+    if (kCFCoreFoundationVersionNumber < 800)
+        frame.origin.x -= 8;
+    [indicator_ setFrame:frame];
+}
+
 - (NSString *) accessibilityLabel {
-    return label_;
+    return origin_;
 }
 
 - (void) drawContentRect:(CGRect)rect {
     bool highlighted(highlighted_);
     float width(rect.size.width);
 
-    if (icon_ != nil)
-        [icon_ drawInRect:CGRectMake(10, 10, 30, 30)];
+    if (icon_ != nil) {
+        CGRect rect;
+        rect.size = [(UIImage *) icon_ size];
+
+        while (rect.size.width > 32 || rect.size.height > 32) {
+            rect.size.width /= 2;
+            rect.size.height /= 2;
+        }
+
+        rect.origin.x = 26 - rect.size.width / 2;
+        rect.origin.y = 26 - rect.size.height / 2;
+
+        [icon_ drawInRect:rect];
+    }
 
-    if (highlighted)
+    if (highlighted && kCFCoreFoundationVersionNumber < 800)
         UISetColor(White_);
 
     if (!highlighted)
         UISetColor(Black_);
-    [origin_ drawAtPoint:CGPointMake(48, 8) forWidth:(width - 80) withFont:Font18Bold_ lineBreakMode:UILineBreakModeTailTruncation];
+    [origin_ drawAtPoint:CGPointMake(52, 8) forWidth:(width - 61) withFont:Font18Bold_ lineBreakMode:NSLineBreakByTruncatingTail];
 
     if (!highlighted)
-        UISetColor(Blue_);
-    [label_ drawAtPoint:CGPointMake(58, 29) forWidth:(width - 95) withFont:Font12_ lineBreakMode:UILineBreakModeTailTruncation];
-}
-
-@end
-/* }}} */
-/* Source Controller {{{ */
-@interface SourceController : FilteredPackageListController {
-    _transient Source *source_;
-    _H<NSString> key_;
-}
-
-- (id) initWithDatabase:(Database *)database source:(Source *)source;
-
-@end
-
-@implementation SourceController
-
-- (NSURL *) navigationURL {
-    return [NSURL URLWithString:[NSString stringWithFormat:@"cydia://sources/%@", [source_ name]]];
-}
-
-- (id) initWithDatabase:(Database *)database source:(Source *)source {
-    if ((self = [super initWithDatabase:database title:[source label] filter:@selector(isVisibleInSource:) with:source]) != nil) {
-        source_ = source;
-        key_ = [source key];
-    } return self;
+        UISetColor(Gray_);
+    [label_ drawAtPoint:CGPointMake(52, 29) forWidth:(width - 61) withFont:Font12_ lineBreakMode:NSLineBreakByTruncatingTail];
 }
 
-- (void) reloadData {
-    source_ = [database_ sourceWithKey:key_];
-    key_ = [source_ key];
-    [self setObject:source_];
-
-    [[self navigationItem] setTitle:[source_ label]];
-
-    [super reloadData];
+- (void) setFetch:(NSNumber *)fetch {
+    if ([fetch boolValue])
+        [indicator_ startAnimating];
+    else
+        [indicator_ stopAnimating];
 }
 
 @end
@@ -7956,7 +8182,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     UITableViewDelegate
 > {
     _transient Database *database_;
-    _H<UITableView> list_;
+    unsigned era_;
+
+    _H<UITableView, 2> list_;
     _H<NSMutableArray> sources_;
     int offset_;
 
@@ -7964,17 +8192,14 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     _H<UIProgressHUD> hud_;
     _H<NSError> error_;
 
-    //NSURLConnection *installer_;
-    NSURLConnection *trivial_;
     NSURLConnection *trivial_bz2_;
     NSURLConnection *trivial_gz_;
-    //NSURLConnection *automatic_;
 
     BOOL cydia_;
 }
 
 - (id) initWithDatabase:(Database *)database;
-- (void) updateButtonsForEditingStatus:(BOOL)editing animated:(BOOL)animated;
+- (void) updateButtonsForEditingStatusAnimated:(BOOL)animated;
 
 @end
 
@@ -7989,11 +8214,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (void) dealloc {
-    //[self _releaseConnection:installer_];
-    [self _releaseConnection:trivial_];
     [self _releaseConnection:trivial_gz_];
     [self _releaseConnection:trivial_bz2_];
-    //[self _releaseConnection:automatic_];
 
     [super dealloc];
 }
@@ -8008,78 +8230,90 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView {
-    return offset_ == 0 ? 1 : 2;
+    return 2;
 }
 
 - (NSString *) tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
-    switch (section + (offset_ == 0 ? 1 : 0)) {
-        case 0: return UCLocalize("ENTERED_BY_USER");
-        case 1: return UCLocalize("INSTALLED_BY_PACKAGE");
-
-        _nodefault
-    }
+    if (section == 1)
+        return UCLocalize("INDIVIDUAL_SOURCES");
+    return nil;
 }
 
 - (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
-    int count = [sources_ count];
     switch (section) {
-        case 0: return (offset_ == 0 ? count : offset_);
-        case 1: return count - offset_;
-
-        _nodefault
+        case 0: return 1;
+        case 1: return [sources_ count];
+        default: return 0;
     }
 }
 
 - (Source *) sourceAtIndexPath:(NSIndexPath *)indexPath {
-    unsigned idx = 0;
-    switch (indexPath.section) {
-        case 0: idx = indexPath.row; break;
-        case 1: idx = indexPath.row + offset_; break;
-
-        _nodefault
-    }
-    return [sources_ objectAtIndex:idx];
-}
+@synchronized (database_) {
+    if ([database_ era] != era_)
+        return nil;
+    if ([indexPath section] != 1)
+        return nil;
+    NSUInteger index([indexPath row]);
+    if (index >= [sources_ count])
+        return nil;
+    return [sources_ objectAtIndex:index];
+} }
 
 - (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
     static NSString *cellIdentifier = @"SourceCell";
 
     SourceCell *cell = (SourceCell *) [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
-    if(cell == nil) cell = [[[SourceCell alloc] initWithFrame:CGRectZero reuseIdentifier:cellIdentifier] autorelease];
-    [cell setSource:[self sourceAtIndexPath:indexPath]];
+    if (cell == nil) cell = [[[SourceCell alloc] initWithFrame:CGRectZero reuseIdentifier:cellIdentifier] autorelease];
     [cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
 
+    Source *source([self sourceAtIndexPath:indexPath]);
+    if (source == nil)
+        [cell setAllSource];
+    else
+        [cell setSource:source];
+
     return cell;
 }
 
 - (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
-    Source *source = [self sourceAtIndexPath:indexPath];
-
-    SourceController *controller = [[[SourceController alloc]
+    SectionsController *controller([[[SectionsController alloc]
         initWithDatabase:database_
-        source:source
-    ] autorelease];
+        source:[self sourceAtIndexPath:indexPath]
+    ] autorelease]);
 
     [controller setDelegate:delegate_];
-
     [[self navigationController] pushViewController:controller animated:YES];
 }
 
 - (BOOL) tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
+    if ([indexPath section] != 1)
+        return false;
     Source *source = [self sourceAtIndexPath:indexPath];
     return [source record] != nil;
 }
 
 - (void) tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
+    _assert([indexPath section] == 1);
     if (editingStyle ==  UITableViewCellEditingStyleDelete) {
         Source *source = [self sourceAtIndexPath:indexPath];
+        if (source == nil) return;
+
         [Sources_ removeObjectForKey:[source key]];
-        [delegate_ syncData];
+        Changed_ = true;
+
+        [delegate_ _saveConfig];
+        [delegate_ reloadDataWithInvocation:nil];
     }
 }
 
+- (void) tableView:(UITableView *)tableView didEndEditingRowAtIndexPath:(NSIndexPath *)indexPath {
+    [self updateButtonsForEditingStatusAnimated:YES];
+}
+
 - (void) complete {
     [delegate_ addTrivialSource:href_];
+    href_ = nil;
+
     [delegate_ syncData];
 }
 
@@ -8090,7 +8324,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         href = [href substringFromIndex:(colon.location + 3)];
     href = [href stringByAddingPercentEscapes];
     href = [CydiaURL(@"api/repotag/") stringByAppendingString:href];
-    href = [href stringByCachingURLWithCurrentCDN];
 
     NSURL *url([NSURL URLWithString:href]);
 
@@ -8106,9 +8339,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     // XXX: the memory management in this method is horribly awkward
 
     NSURLConnection **field = NULL;
-    if (connection == trivial_)
-        field = &trivial_;
-    else if (connection == trivial_bz2_)
+    if (connection == trivial_bz2_)
         field = &trivial_bz2_;
     else if (connection == trivial_gz_)
         field = &trivial_gz_;
@@ -8117,21 +8348,18 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     *field = nil;
 
     if (
-        trivial_ == nil &&
         trivial_bz2_ == nil &&
         trivial_gz_ == nil
     ) {
+        NSString *warning(cydia_ ? [self yieldToSelector:@selector(getWarning)] : nil);
+
         [delegate_ releaseNetworkActivityIndicator];
 
         [delegate_ removeProgressHUD:hud_];
         hud_ = nil;
 
-        bool defer(false);
-
         if (cydia_) {
-            if (NSString *warning = [self yieldToSelector:@selector(getWarning)]) {
-                defer = true;
-
+            if (warning != nil) {
                 UIAlertView *alert = [[[UIAlertView alloc]
                     initWithTitle:UCLocalize("SOURCE_WARNING")
                     message:warning
@@ -8145,8 +8373,13 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
                 [alert setContext:@"warning"];
                 [alert setNumberOfRows:1];
                 [alert show];
-            } else
-                [self complete];
+
+                // XXX: there used to be this great mechanism called yieldToPopup... who deleted it?
+                error_ = nil;
+                return;
+            }
+
+            [self complete];
         } else if (error_ != nil) {
             UIAlertView *alert = [[[UIAlertView alloc]
                 initWithTitle:UCLocalize("VERIFICATION_ERROR")
@@ -8158,6 +8391,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
             [alert setContext:@"urlerror"];
             [alert show];
+
+            href_ = nil;
         } else {
             UIAlertView *alert = [[[UIAlertView alloc]
                 initWithTitle:UCLocalize("NOT_REPOSITORY")
@@ -8169,9 +8404,10 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
             [alert setContext:@"trivial"];
             [alert show];
+
+            href_ = nil;
         }
 
-        href_ = nil;
         error_ = nil;
     }
 }
@@ -8184,7 +8420,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
-    lprintf("connection:\"%s\" didFailWithError:\"%s\"", [href_ UTF8String], [[error localizedDescription] UTF8String]);
+    lprintf("connection:\"%s\" didFailWithError:\"%s\"\n", [href_ UTF8String], [[error localizedDescription] UTF8String]);
     error_ = error;
     [self _endConnection:connection];
 }
@@ -8194,19 +8430,27 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (NSURLConnection *) _requestHRef:(NSString *)href method:(NSString *)method {
+    NSURL *url([NSURL URLWithString:href]);
+
     NSMutableURLRequest *request = [NSMutableURLRequest
-        requestWithURL:[NSURL URLWithString:href]
+        requestWithURL:url
         cachePolicy:NSURLRequestUseProtocolCachePolicy
-        timeoutInterval:120.0
+        timeoutInterval:10
     ];
 
     [request setHTTPMethod:method];
 
     if (Machine_ != NULL)
         [request setValue:[NSString stringWithUTF8String:Machine_] forHTTPHeaderField:@"X-Machine"];
+
     if (UniqueID_ != nil)
         [request setValue:UniqueID_ forHTTPHeaderField:@"X-Unique-ID"];
 
+    if ([url isCydiaSecure]) {
+        if (UniqueID_ != nil)
+            [request setValue:UniqueID_ forHTTPHeaderField:@"X-Cydia-Id"];
+    }
+
     return [[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease];
 }
 
@@ -8218,17 +8462,29 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
             case 1: {
                 NSString *href = [[alert textField] text];
 
-                //installer_ = [[self _requestHRef:href method:@"GET"] retain];
+                static Pcre href_r("^http(s?)://[^# ]*$");
+                if (!href_r(href)) {
+                    UIAlertView *alert = [[[UIAlertView alloc]
+                        initWithTitle:Error_
+                        message:UCLocalize("INVALID_URL")
+                        delegate:self
+                        cancelButtonTitle:UCLocalize("OK")
+                        otherButtonTitles:nil
+                    ] autorelease];
+
+                    [alert setContext:@"badurl"];
+                    [alert show];
+
+                    break;
+                }
 
                 if (![href hasSuffix:@"/"])
                     href_ = [href stringByAppendingString:@"/"];
                 else
                     href_ = href;
 
-                trivial_ = [[self _requestHRef:[href_ stringByAppendingString:@"Packages"] method:@"HEAD"] retain];
                 trivial_bz2_ = [[self _requestHRef:[href_ stringByAppendingString:@"Packages.bz2"] method:@"HEAD"] retain];
                 trivial_gz_ = [[self _requestHRef:[href_ stringByAppendingString:@"Packages.gz"] method:@"HEAD"] retain];
-                //trivial_bz2_ = [[self _requestHRef:[href stringByAppendingString:@"dists/Release"] method:@"HEAD"] retain];
 
                 cydia_ = false;
 
@@ -8252,7 +8508,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     else if ([context isEqualToString:@"warning"]) {
         switch (button) {
             case 1:
-                [self complete];
+                [self performSelector:@selector(complete) withObject:nil afterDelay:0];
             break;
 
             case 0:
@@ -8261,52 +8517,91 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
             _nodefault
         }
 
-        href_ = nil;
-
         [alert dismissWithClickedButtonIndex:-1 animated:YES];
     }
 }
 
-- (void) loadView {
-    [self setView:[[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease]];
+- (void) updateButtonsForEditingStatusAnimated:(BOOL)animated {
+    BOOL editing([list_ isEditing]);
 
-    list_ = [[[UITableView alloc] initWithFrame:[[self view] bounds] style:UITableViewStylePlain] autorelease];
+    if (editing)
+        [[self navigationItem] setLeftBarButtonItem:[[[UIBarButtonItem alloc]
+            initWithTitle:UCLocalize("ADD")
+            style:UIBarButtonItemStylePlain
+            target:self
+            action:@selector(addButtonClicked)
+        ] autorelease] animated:animated];
+    else if ([delegate_ updating])
+        [[self navigationItem] setLeftBarButtonItem:[[[UIBarButtonItem alloc]
+            initWithTitle:UCLocalize("CANCEL")
+            style:UIBarButtonItemStyleDone
+            target:self
+            action:@selector(cancelButtonClicked)
+        ] autorelease] animated:animated];
+    else
+        [[self navigationItem] setLeftBarButtonItem:[[[UIBarButtonItem alloc]
+            initWithTitle:UCLocalize("REFRESH")
+            style:UIBarButtonItemStylePlain
+            target:self
+            action:@selector(refreshButtonClicked)
+        ] autorelease] animated:animated];
+
+    [[self navigationItem] setRightBarButtonItem:[[[UIBarButtonItem alloc]
+        initWithTitle:(editing ? UCLocalize("DONE") : UCLocalize("EDIT"))
+        style:(editing ? UIBarButtonItemStyleDone : UIBarButtonItemStylePlain)
+        target:self
+        action:@selector(editButtonClicked)
+    ] autorelease] animated:animated];
+}
+
+- (void) loadView {
+    list_ = [[[UITableView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame] style:UITableViewStylePlain] autorelease];
     [list_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth];
-    [list_ setRowHeight:56];
+    [list_ setRowHeight:53];
     [(UITableView *) list_ setDataSource:self];
     [list_ setDelegate:self];
-    [[self view] addSubview:list_];
+    [self setView:list_];
 }
 
 - (void) viewDidLoad {
     [super viewDidLoad];
 
     [[self navigationItem] setTitle:UCLocalize("SOURCES")];
-    [self updateButtonsForEditingStatus:NO animated:NO];
+    [self updateButtonsForEditingStatusAnimated:NO];
+}
+
+- (void) viewWillAppear:(BOOL)animated {
+    [super viewWillAppear:animated];
+
+    [list_ setEditing:NO];
+    [self updateButtonsForEditingStatusAnimated:NO];
 }
 
 - (void) releaseSubviews {
     list_ = nil;
+
+    sources_ = nil;
+
+    [super releaseSubviews];
 }
 
 - (id) initWithDatabase:(Database *)database {
     if ((self = [super init]) != nil) {
         database_ = database;
-        sources_ = [NSMutableArray arrayWithCapacity:16];
     } return self;
 }
 
 - (void) reloadData {
     [super reloadData];
+    [self updateButtonsForEditingStatusAnimated:YES];
 
-    pkgSourceList list;
-    if ([database_ popErrorWithTitle:UCLocalize("SOURCES") forOperation:list.ReadMainList()])
-        return;
+@synchronized (database_) {
+    era_ = [database_ era];
 
-    [sources_ removeAllObjects];
+    sources_ = [NSMutableArray arrayWithCapacity:16];
     [sources_ addObjectsFromArray:[database_ sources]];
     _trace();
-    [sources_ sortUsingSelector:@selector(compareByNameAndType:)];
+    [sources_ sortUsingSelector:@selector(compareByName:)];
     _trace();
 
     int count([sources_ count]);
@@ -8317,10 +8612,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         offset_++;
     }
 
-    [list_ setEditing:NO];
-    [self updateButtonsForEditingStatus:NO animated:NO];
     [list_ reloadData];
-}
+} }
 
 - (void) showAddSourcePrompt {
     UIAlertView *alert = [[[UIAlertView alloc]
@@ -8336,248 +8629,39 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     [alert setContext:@"source"];
 
     [alert setNumberOfRows:1];
-    [alert addTextFieldWithValue:@"http://" label:@""];
-
-    UITextInputTraits *traits = [[alert textField] textInputTraits];
-    [traits setAutocapitalizationType:UITextAutocapitalizationTypeNone];
-    [traits setAutocorrectionType:UITextAutocorrectionTypeNo];
-    [traits setKeyboardType:UIKeyboardTypeURL];
-    // XXX: UIReturnKeyDone
-    [traits setReturnKeyType:UIReturnKeyNext];
-
-    [alert show];
-}
-
-- (void) addButtonClicked {
-    [self showAddSourcePrompt];
-}
-
-- (void) updateButtonsForEditingStatus:(BOOL)editing animated:(BOOL)animated {
-    [[self navigationItem] setLeftBarButtonItem:(editing ? [[[UIBarButtonItem alloc]
-        initWithTitle:UCLocalize("ADD")
-        style:UIBarButtonItemStylePlain
-        target:self
-        action:@selector(addButtonClicked)
-    ] autorelease] : [[self navigationItem] backBarButtonItem]) animated:animated];
-
-    [[self navigationItem] setRightBarButtonItem:[[[UIBarButtonItem alloc]
-        initWithTitle:(editing ? UCLocalize("DONE") : UCLocalize("EDIT"))
-        style:(editing ? UIBarButtonItemStyleDone : UIBarButtonItemStylePlain)
-        target:self
-        action:@selector(editButtonClicked)
-    ] autorelease] animated:animated];
-
-    if (IsWildcat_ && !editing)
-        [[self navigationItem] setLeftBarButtonItem:[[[UIBarButtonItem alloc]
-            initWithTitle:UCLocalize("SETTINGS")
-            style:UIBarButtonItemStylePlain
-            target:self
-            action:@selector(settingsButtonClicked)
-        ] autorelease]];
-}
-
-- (void) settingsButtonClicked {
-    [delegate_ showSettings];
-}
-
-- (void) editButtonClicked {
-    [list_ setEditing:![list_ isEditing] animated:YES];
-
-    [self updateButtonsForEditingStatus:[list_ isEditing] animated:YES];
-}
-
-@end
-/* }}} */
-
-/* Settings Controller {{{ */
-@interface SettingsController : CyteViewController <
-    UITableViewDataSource,
-    UITableViewDelegate
-> {
-    _transient Database *database_;
-    // XXX: ok, "roledelegate_"?...
-    _transient id roledelegate_;
-    _H<UITableView> table_;
-    _H<UISegmentedControl> segment_;
-    _H<UIView> container_;
-}
-
-- (void) showDoneButton;
-- (void) resizeSegmentedControl;
-
-@end
-
-@implementation SettingsController
-
-- (void) loadView {
-    [self setView:[[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease]];
-
-    table_ = [[[UITableView alloc] initWithFrame:[[self view] bounds] style:UITableViewStyleGrouped] autorelease];
-    [table_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth];
-    [table_ setDelegate:self];
-    [(UITableView *) table_ setDataSource:self];
-    [[self view] addSubview:table_];
-
-    NSArray *items = [NSArray arrayWithObjects:
-        UCLocalize("USER"),
-        UCLocalize("HACKER"),
-        UCLocalize("DEVELOPER"),
-    nil];
-    segment_ = [[[UISegmentedControl alloc] initWithItems:items] autorelease];
-    container_ = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, [[self view] frame].size.width, 44.0f)] autorelease];
-    [container_ addSubview:segment_];
-}
-
-- (void) viewDidLoad {
-    [super viewDidLoad];
-
-    [[self navigationItem] setTitle:UCLocalize("WHO_ARE_YOU")];
-
-    int index = -1;
-    if ([Role_ isEqualToString:@"User"]) index = 0;
-    if ([Role_ isEqualToString:@"Hacker"]) index = 1;
-    if ([Role_ isEqualToString:@"Developer"]) index = 2;
-    if (index != -1) {
-        [segment_ setSelectedSegmentIndex:index];
-        [self showDoneButton];
-    }
-
-    [segment_ addTarget:self action:@selector(segmentChanged:) forControlEvents:UIControlEventValueChanged];
-    [self resizeSegmentedControl];
-}
-
-- (void) releaseSubviews {
-    table_ = nil;
-    segment_ = nil;
-    container_ = nil;
-}
-
-- (id) initWithDatabase:(Database *)database delegate:(id)delegate {
-    if ((self = [super init]) != nil) {
-        database_ = database;
-        roledelegate_ = delegate;
-    } return self;
-}
-
-- (void) resizeSegmentedControl {
-    CGFloat width = [[self view] frame].size.width;
-    [segment_ setFrame:CGRectMake(width / 32.0f, 0, width - (width / 32.0f * 2.0f), 44.0f)];
-}
-
-- (void) viewWillAppear:(BOOL)animated {
-    [super viewWillAppear:animated];
-
-    [self resizeSegmentedControl];
-}
-
-- (void) willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration {
-    [self resizeSegmentedControl];
-}
-
-- (void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
-    [self resizeSegmentedControl];
-}
-
-- (void) save {
-    NSString *role(nil);
-
-    switch ([segment_ selectedSegmentIndex]) {
-        case 0: role = @"User"; break;
-        case 1: role = @"Hacker"; break;
-        case 2: role = @"Developer"; break;
-
-        _nodefault
-    }
-
-    if (![role isEqualToString:Role_]) {
-        bool rolling(Role_ == nil);
-        Role_ = role;
-
-        Settings_ = [NSMutableDictionary dictionaryWithObjectsAndKeys:
-            Role_, @"Role",
-        nil];
-
-        [Metadata_ setObject:Settings_ forKey:@"Settings"];
-        Changed_ = true;
-
-        if (rolling)
-            [roledelegate_ loadData];
-        else
-            [roledelegate_ updateData];
-    }
-}
-
-- (void) segmentChanged:(UISegmentedControl *)control {
-    [self showDoneButton];
-}
-
-- (void) saveAndClose {
-    [self save];
-
-    [[self navigationItem] setRightBarButtonItem:nil];
-    [[self navigationController] dismissModalViewControllerAnimated:YES];
-}
-
-- (void) doneButtonClicked {
-    UIActivityIndicatorView *spinner = [[[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(0, 0, 20.0f, 20.0f)] autorelease];
-    [spinner startAnimating];
-    UIBarButtonItem *spinItem = [[[UIBarButtonItem alloc] initWithCustomView:spinner] autorelease];
-    [[self navigationItem] setRightBarButtonItem:spinItem];
-
-    [self performSelector:@selector(saveAndClose) withObject:nil afterDelay:0];
-}
-
-- (void) showDoneButton {
-    [[self navigationItem] setRightBarButtonItem:[[[UIBarButtonItem alloc]
-        initWithTitle:UCLocalize("DONE")
-        style:UIBarButtonItemStyleDone
-        target:self
-        action:@selector(doneButtonClicked)
-    ] autorelease] animated:([[self navigationItem] rightBarButtonItem] == nil)];
-}
-
-- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView {
-    // XXX: For not having a single cell in the table, this sure is a lot of sections.
-    return 6;
-}
+    [alert addTextFieldWithValue:@"http://" label:@""];
 
-- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
-    return 0; // :(
-}
+    UITextInputTraits *traits = [[alert textField] textInputTraits];
+    [traits setAutocapitalizationType:UITextAutocapitalizationTypeNone];
+    [traits setAutocorrectionType:UITextAutocorrectionTypeNo];
+    [traits setKeyboardType:UIKeyboardTypeURL];
+    // XXX: UIReturnKeyDone
+    [traits setReturnKeyType:UIReturnKeyNext];
 
-- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
-    return nil; // This method is required by the protocol.
+    [alert show];
 }
 
-- (NSString *) tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {
-    if (section == 1)
-        return UCLocalize("ROLE_EX");
-    if (section == 4)
-        return [NSString stringWithFormat:
-            @"%@: %@\n%@: %@\n%@: %@",
-            UCLocalize("USER"), UCLocalize("USER_EX"),
-            UCLocalize("HACKER"), UCLocalize("HACKER_EX"),
-            UCLocalize("DEVELOPER"), UCLocalize("DEVELOPER_EX")
-        ];
-    else return nil;
+- (void) addButtonClicked {
+    [self showAddSourcePrompt];
 }
 
-- (CGFloat) tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
-    return section == 3 ? 44.0f : 0;
+- (void) refreshButtonClicked {
+    if ([delegate_ requestUpdate])
+        [self updateButtonsForEditingStatusAnimated:YES];
 }
 
-- (UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
-    return section == 3 ? container_ : nil;
+- (void) cancelButtonClicked {
+    [delegate_ cancelUpdate];
 }
 
-- (void) reloadData {
-    [super reloadData];
-
-    [table_ reloadData];
+- (void) editButtonClicked {
+    [list_ setEditing:![list_ isEditing] animated:YES];
+    [self updateButtonsForEditingStatusAnimated:YES];
 }
 
 @end
 /* }}} */
+
 /* Stash Controller {{{ */
 @interface StashController : CyteViewController {
     _H<UIActivityIndicatorView> spinner_;
@@ -8590,8 +8674,11 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 @implementation StashController
 
 - (void) loadView {
-    [self setView:[[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease]];
-    [[self view] setBackgroundColor:[UIColor viewFlipsideBackgroundColor]];
+    UIView *view([[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease]);
+    [view setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight)];
+    [self setView:view];
+
+    [view setBackgroundColor:[UIColor viewFlipsideBackgroundColor]];
 
     spinner_ = [[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge] autorelease];
     CGRect spinrect = [spinner_ frame];
@@ -8599,7 +8686,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     spinrect.origin.y = [[self view] frame].size.height - 80.0f;
     [spinner_ setFrame:spinrect];
     [spinner_ setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin];
-    [[self view] addSubview:spinner_];
+    [view addSubview:spinner_];
     [spinner_ startAnimating];
 
     CGRect captrect;
@@ -8614,8 +8701,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     [caption_ setTextColor:[UIColor whiteColor]];
     [caption_ setBackgroundColor:[UIColor clearColor]];
     [caption_ setShadowColor:[UIColor blackColor]];
-    [caption_ setTextAlignment:UITextAlignmentCenter];
-    [[self view] addSubview:caption_];
+    [caption_ setTextAlignment:NSTextAlignmentCenter];
+    [view addSubview:caption_];
 
     CGRect statusrect;
     statusrect.size.width = [[self view] frame].size.width;
@@ -8629,8 +8716,16 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     [status_ setTextColor:[UIColor whiteColor]];
     [status_ setBackgroundColor:[UIColor clearColor]];
     [status_ setShadowColor:[UIColor blackColor]];
-    [status_ setTextAlignment:UITextAlignmentCenter];
-    [[self view] addSubview:status_];
+    [status_ setTextAlignment:NSTextAlignmentCenter];
+    [view addSubview:status_];
+}
+
+- (void) releaseSubviews {
+    spinner_ = nil;
+    status_ = nil;
+    caption_ = nil;
+
+    [super releaseSubviews];
 }
 
 @end
@@ -8663,6 +8758,24 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 #endif
 }
 
+- (void) storeCachedResponse:(NSCachedURLResponse *)cached forRequest:(NSURLRequest *)request {
+    if (NSURLResponse *response = [cached response])
+        if (NSString *mime = [response MIMEType])
+            if ([mime isEqualToString:@"text/cache-manifest"]) {
+                NSURL *url([response URL]);
+
+#if !ForRelease
+                NSLog(@"###: %@", [url absoluteString]);
+#endif
+
+                @synchronized (HostConfig_) {
+                    [CachedURLs_ addObject:url];
+                }
+            }
+
+    [super storeCachedResponse:cached forRequest:request];
+}
+
 @end
 
 @interface Cydia : UIApplication <
@@ -8673,8 +8786,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     UITabBarControllerDelegate
 > {
     _H<UIWindow> window_;
-    _H<CYTabBarController> tabbar_;
-    _H<CYEmulatedLoadingController> emulated_;
+    _H<CydiaTabBarController> tabbar_;
+    _H<CydiaLoadingViewController> emulated_;
 
     _H<NSMutableArray> essential_;
     _H<NSMutableArray> broken_;
@@ -8697,10 +8810,52 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 @implementation Cydia
 
+- (void) lockSuspend {
+    if (locked_++ == 0) {
+        if ($SBSSetInterceptsMenuButtonForever != NULL)
+            (*$SBSSetInterceptsMenuButtonForever)(true);
+
+        [self setIdleTimerDisabled:YES];
+    }
+}
+
+- (void) unlockSuspend {
+    if (--locked_ == 0) {
+        [self setIdleTimerDisabled:NO];
+
+        if ($SBSSetInterceptsMenuButtonForever != NULL)
+            (*$SBSSetInterceptsMenuButtonForever)(false);
+    }
+}
+
 - (void) beginUpdate {
     [tabbar_ beginUpdate];
 }
 
+- (void) cancelUpdate {
+    [tabbar_ cancelUpdate];
+}
+
+- (bool) requestUpdate {
+    if (IsReachable("cydia.saurik.com")) {
+        [self beginUpdate];
+        return true;
+    } else {
+        UIAlertView *alert = [[[UIAlertView alloc]
+            initWithTitle:[NSString stringWithFormat:Colon_, Error_, UCLocalize("REFRESH")]
+            message:@"Host Unreachable" // XXX: Localize
+            delegate:self
+            cancelButtonTitle:UCLocalize("OK")
+            otherButtonTitles:nil
+        ] autorelease];
+
+        [alert setContext:@"norefresh"];
+        [alert show];
+
+        return false;
+    }
+}
+
 - (BOOL) updating {
     return [tabbar_ updating];
 }
@@ -8713,7 +8868,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
             initWithTitle:(count == 1 ? UCLocalize("HALFINSTALLED_PACKAGE") : [NSString stringWithFormat:UCLocalize("HALFINSTALLED_PACKAGES"), count])
             message:UCLocalize("HALFINSTALLED_PACKAGE_EX")
             delegate:self
-            cancelButtonTitle:UCLocalize("FORCIBLY_CLEAR")
+            cancelButtonTitle:[NSString stringWithFormat:UCLocalize("PARENTHETICAL"), UCLocalize("FORCIBLY_CLEAR"), UCLocalize("UNSAFE")]
             otherButtonTitles:
                 UCLocalize("TEMPORARY_IGNORE"),
             nil
@@ -8741,10 +8896,16 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     }
 }
 
+- (void) returnToCydia {
+    [self _loaded];
+}
+
 - (void) _saveConfig {
-    _trace();
-    MetaFile_.Sync();
-    _trace();
+    @synchronized (database_) {
+        _trace();
+        MetaFile_.Sync();
+        _trace();
+    }
 
     if (Changed_) {
         NSString *error(nil);
@@ -8761,6 +8922,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
             NSLog(@"failure to serialize metadata: %@", error);
         }
     }
+
+    CydiaWriteSources();
 }
 
 // Navigation controller for the queuing badge.
@@ -8775,7 +8938,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 - (void) _updateData {
     [self _saveConfig];
-
     [self unloadData];
 
     UINavigationController *navigation = [self queueNavigationController];
@@ -8802,38 +8964,18 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     //  - We already refreshed recently.
     //  - We already auto-refreshed this launch.
     //  - Auto-refresh is disabled.
-    if (recently || loaded_ || ManualRefresh) {
-        [self performSelectorOnMainThread:@selector(_loaded) withObject:nil waitUntilDone:NO];
-
+    //  - Cydia's server is not reachable
+    if (recently || loaded_ || ManualRefresh || !IsReachable("cydia.saurik.com")) {
         // If we are cancelling, we need to make sure it knows it's already loaded.
         loaded_ = true;
-        return;
+
+        [self performSelectorOnMainThread:@selector(_loaded) withObject:nil waitUntilDone:NO];
     } else {
         // We are going to load, so remember that.
         loaded_ = true;
-    }
-
-    SCNetworkReachabilityFlags flags; {
-        SCNetworkReachabilityRef reachability(SCNetworkReachabilityCreateWithName(NULL, "cydia.saurik.com"));
-        SCNetworkReachabilityGetFlags(reachability, &flags);
-        CFRelease(reachability);
-    }
-
-    // XXX: this elaborate mess is what Apple is using to determine this? :(
-    // XXX: do we care if the user has to intervene? maybe that's ok?
-    bool reachable(
-        (flags & kSCNetworkReachabilityFlagsReachable) != 0 && (
-            (flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0 || (
-                (flags & kSCNetworkReachabilityFlagsConnectionOnDemand) != 0 ||
-                (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0
-            ) && (flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0 ||
-            (flags & kSCNetworkReachabilityFlagsIsWWAN) != 0
-        )
-    );
 
-    // If we can reach the server, auto-refresh!
-    if (reachable)
         [tabbar_ performSelectorOnMainThread:@selector(setUpdate:) withObject:update waitUntilDone:NO];
+    }
 
     [pool release];
 }
@@ -8842,15 +8984,14 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     [NSThread detachNewThreadSelector:@selector(_refreshIfPossible:) toTarget:self withObject:[Metadata_ objectForKey:@"LastUpdate"]];
 }
 
-- (void) _reloadDataWithInvocation:(NSInvocation *)invocation {
+- (void) reloadDataWithInvocation:(NSInvocation *)invocation {
+@synchronized (self) {
     UIProgressHUD *hud(loaded_ ? [self addProgressHUD] : nil);
-    [hud setText:UCLocalize("RELOADING_DATA")];
+    if (hud != nil)
+        [hud setText:UCLocalize("RELOADING_DATA")];
 
     [database_ yieldToSelector:@selector(reloadDataWithInvocation:) withObject:invocation];
 
-    if (hud != nil)
-        [self removeProgressHUD:hud];
-
     size_t changes(0);
 
     [essential_ removeAllObjects];
@@ -8860,15 +9001,13 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     for (Package *package in packages) {
         if ([package half])
             [broken_ addObject:package];
-        if ([package upgradableAndEssential:NO]) {
-            if ([package essential])
+        if ([package upgradableAndEssential:YES] && ![package ignored]) {
+            if ([package essential] && [package installed] != nil)
                 [essential_ addObject:package];
             ++changes;
         }
     }
 
-    NSLog(@"changes:#%u", changes);
-
     UITabBarItem *changesItem = [[[tabbar_ viewControllers] objectAtIndex:2] tabBarItem];
     if (changes != 0) {
         _trace();
@@ -8885,21 +9024,23 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
     [self _updateData];
 
-    [self refreshIfPossible];
-}
+    if (hud != nil)
+        [self removeProgressHUD:hud];
+} }
 
 - (void) updateData {
     [self _updateData];
 }
 
-- (void) update_ {
-    [database_ update];
+- (void) updateDataAndLoad {
+    [self _updateData];
+    if ([database_ progressDelegate] == nil)
+        [self _loaded];
 }
 
-- (void) complete {
-    @synchronized (self) {
-        [self _reloadDataWithInvocation:nil];
-    }
+- (void) update_ {
+    [database_ update];
+    [self performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:YES];
 }
 
 - (void) disemulate {
@@ -8907,6 +9048,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         return;
 
     [window_ addSubview:[tabbar_ view]];
+    if ([window_ respondsToSelector:@selector(setRootViewController:)])
+        [window_ setRootViewController:tabbar_];
     [[emulated_ view] removeFromSuperview];
     emulated_ = nil;
     [window_ setUserInteractionEnabled:YES];
@@ -8956,47 +9099,31 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     [self performSelectorOnMainThread:@selector(repairWithInvocation:) withObject:[NSInvocation invocationWithSelector:selector forTarget:database_] waitUntilDone:YES];
 }
 
+- (void) reloadData {
+    [self reloadDataWithInvocation:nil];
+    if ([database_ progressDelegate] == nil)
+        [self _loaded];
+}
+
 - (void) syncData {
     [self _saveConfig];
-
-    FILE *file(fopen("/etc/apt/sources.list.d/cydia.list", "w"));
-    _assert(file != NULL);
-
-    for (NSString *key in [Sources_ allKeys]) {
-        NSDictionary *source([Sources_ objectForKey:key]);
-
-        fprintf(file, "%s %s %s\n",
-            [[source objectForKey:@"Type"] UTF8String],
-            [[source objectForKey:@"URI"] UTF8String],
-            [[source objectForKey:@"Distribution"] UTF8String]
-        );
-    }
-
-    fclose(file);
-
     [self detachNewProgressSelector:@selector(update_) toTarget:self forController:nil title:@"UPDATING_SOURCES"];
-
-    [self complete];
 }
 
-- (void) addTrivialSource:(NSString *)href {
-    [Sources_ setObject:[NSDictionary dictionaryWithObjectsAndKeys:
-        @"deb", @"Type",
-        href, @"URI",
-        @"./", @"Distribution",
-    nil] forKey:[NSString stringWithFormat:@"deb:%@:./", href]];
+- (void) addSource:(NSDictionary *) source {
+    CydiaAddSource(source);
+}
 
-    Changed_ = true;
+- (void) addSource:(NSString *)href withDistribution:(NSString *)distribution andSections:(NSArray *)sections {
+    CydiaAddSource(href, distribution, sections);
 }
 
-- (void) reloadDataWithInvocation:(NSInvocation *)invocation {
-    @synchronized (self) {
-        [self _reloadDataWithInvocation:invocation];
-    }
+- (void) addTrivialSource:(NSString *)href {
+    CydiaAddSource(href, @"./");
 }
 
-- (void) reloadData {
-    [self reloadDataWithInvocation:nil];
+- (void) updateValues {
+    Changed_ = true;
 }
 
 - (void) resolve {
@@ -9076,16 +9203,30 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     }
 }
 
-- (void) confirmWithNavigationController:(UINavigationController *)navigation {
-    Queuing_ = false;
-    ++locked_;
-    [self detachNewProgressSelector:@selector(perform) toTarget:database_ forController:navigation title:@"RUNNING"];
-    --locked_;
-    [self complete];
+- (void) _uicache {
+    _trace();
+    system("su -c /usr/bin/uicache mobile");
+    _trace();
+}
+
+- (void) uicache {
+    UIProgressHUD *hud([self addProgressHUD]);
+    [hud setText:UCLocalize("LOADING")];
+    [self yieldToSelector:@selector(_uicache)];
+    [self removeProgressHUD:hud];
+}
+
+- (void) perform_ {
+    [database_ perform];
+    [self performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:YES];
+    [self performSelectorOnMainThread:@selector(uicache) withObject:nil waitUntilDone:YES];
 }
 
-- (void) showSettings {
-    [self presentModalViewController:[[[SettingsController alloc] initWithDatabase:database_ delegate:self] autorelease] force:NO];
+- (void) confirmWithNavigationController:(UINavigationController *)navigation {
+    Queuing_ = false;
+    [self lockSuspend];
+    [self detachNewProgressSelector:@selector(perform_) toTarget:self forController:navigation title:@"RUNNING"];
+    [self unlockSuspend];
 }
 
 - (void) retainNetworkActivityIndicator {
@@ -9173,10 +9314,14 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     }
 }
 
-- (void) system:(NSString *)command { _pooled
+- (void) system:(NSString *)command {
+    NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
+
     _trace();
     system([command UTF8String]);
     _trace();
+
+    [pool release];
 }
 
 - (void) applicationWillSuspend {
@@ -9231,7 +9376,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (UIProgressHUD *) addProgressHUD {
-    UIProgressHUD *hud([[[UIProgressHUD alloc] initWithWindow:window_] autorelease]);
+    UIProgressHUD *hud([[[UIProgressHUD alloc] init] autorelease]);
     [hud setAutoresizingMask:UIViewAutoresizingFlexibleBoth];
 
     [window_ setUserInteractionEnabled:NO];
@@ -9240,35 +9385,36 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     if (UIViewController *modal = [target modalViewController])
         target = modal;
 
-    UIView *view([target view]);
-    [view addSubview:hud];
+    [hud showInView:[target view]];
 
-    [hud show:YES];
-
-    ++locked_;
+    [self lockSuspend];
     return hud;
 }
 
 - (void) removeProgressHUD:(UIProgressHUD *)hud {
-    --locked_;
-    [hud show:NO];
+    [self unlockSuspend];
+    [hud hide];
     [hud removeFromSuperview];
     [window_ setUserInteractionEnabled:YES];
 }
 
-- (CyteViewController *) pageForPackage:(NSString *)name {
-    return [[[CYPackageController alloc] initWithDatabase:database_ forPackage:name] autorelease];
+- (CyteViewController *) pageForPackage:(NSString *)name withReferrer:(NSString *)referrer {
+    return [[[CYPackageController alloc] initWithDatabase:database_ forPackage:name withReferrer:referrer] autorelease];
 }
 
-- (CyteViewController *) pageForURL:(NSURL *)url forExternal:(BOOL)external {
+- (CyteViewController *) pageForURL:(NSURL *)url forExternal:(BOOL)external withReferrer:(NSString *)referrer {
     NSString *scheme([[url scheme] lowercaseString]);
     if ([[url absoluteString] length] <= [scheme length] + 3)
         return nil;
     NSString *path([[url absoluteString] substringFromIndex:[scheme length] + 3]);
-    NSArray *components([path pathComponents]);
+    NSArray *components([path componentsSeparatedByString:@"/"]);
 
-    if ([scheme isEqualToString:@"apptapp"] && [components count] > 0 && [[components objectAtIndex:0] isEqualToString:@"package"])
-        return [self pageForPackage:[components objectAtIndex:1]];
+    if ([scheme isEqualToString:@"apptapp"] && [components count] > 0 && [[components objectAtIndex:0] isEqualToString:@"package"]) {
+        CyteViewController *controller([self pageForPackage:[components objectAtIndex:1] withReferrer:referrer]);
+        if (controller != nil)
+            [controller setDelegate:self];
+        return controller;
+    }
 
     if ([components count] < 1 || ![scheme isEqualToString:@"cydia"])
         return nil;
@@ -9282,10 +9428,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         NSString *destination = [[url absoluteString] substringFromIndex:([scheme length] + [@"://" length] + [base length] + [@"/" length])];
         controller = [[[CydiaWebViewController alloc] initWithURL:[NSURL URLWithString:destination]] autorelease];
     } else if (!external && [components count] == 1) {
-        if ([base isEqualToString:@"manage"]) {
-            controller = [[[ManageController alloc] init] autorelease];
-        }
-
         if ([base isEqualToString:@"sources"]) {
             controller = [[[SourcesController alloc] initWithDatabase:database_] autorelease];
         }
@@ -9295,7 +9437,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         }
 
         if ([base isEqualToString:@"sections"]) {
-            controller = [[[SectionsController alloc] initWithDatabase:database_] autorelease];
+            controller = [[[SectionsController alloc] initWithDatabase:database_ source:nil] autorelease];
         }
 
         if ([base isEqualToString:@"search"]) {
@@ -9310,10 +9452,10 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
             controller = [[[InstalledController alloc] initWithDatabase:database_] autorelease];
         }
     } else if ([components count] == 2) {
-        NSString *argument = [components objectAtIndex:1];
+        NSString *argument = [[components objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
 
         if ([base isEqualToString:@"package"]) {
-            controller = [self pageForPackage:argument];
+            controller = [self pageForPackage:argument withReferrer:referrer];
         }
 
         if (!external && [base isEqualToString:@"search"]) {
@@ -9321,9 +9463,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         }
 
         if (!external && [base isEqualToString:@"sections"]) {
-            if ([argument isEqualToString:@"all"])
+            if ([argument isEqualToString:@"all"] || [argument isEqualToString:@"*"])
                 argument = nil;
-            controller = [[[SectionController alloc] initWithDatabase:database_ section:argument] autorelease];
+            controller = [[[SectionController alloc] initWithDatabase:database_ source:nil section:argument] autorelease];
         }
 
         if (!external && [base isEqualToString:@"sources"]) {
@@ -9331,8 +9473,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
                 controller = [[[SourcesController alloc] initWithDatabase:database_] autorelease];
                 [(SourcesController *)controller showAddSourcePrompt];
             } else {
-                Source *source = [database_ sourceWithKey:argument];
-                controller = [[[SourceController alloc] initWithDatabase:database_ source:source] autorelease];
+                Source *source([database_ sourceWithKey:argument]);
+                controller = [[[SectionsController alloc] initWithDatabase:database_ source:source] autorelease];
             }
         }
 
@@ -9341,8 +9483,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
             return nil;
         }
     } else if (!external && [components count] == 3) {
-        NSString *arg1 = [components objectAtIndex:1];
-        NSString *arg2 = [components objectAtIndex:2];
+        NSString *arg1 = [[components objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
+        NSString *arg2 = [[components objectAtIndex:2] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
 
         if ([base isEqualToString:@"package"]) {
             if ([arg2 isEqualToString:@"settings"]) {
@@ -9354,6 +9496,12 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
                 }
             }
         }
+
+        if ([base isEqualToString:@"sections"]) {
+            Source *source([arg1 isEqualToString:@"*"] ? nil : [database_ sourceWithKey:arg1]);
+            NSString *section([arg2 isEqualToString:@"*"] ? nil : arg2);
+            controller = [[[SectionController alloc] initWithDatabase:database_ source:source section:section] autorelease];
+        }
     }
 
     [controller setDelegate:self];
@@ -9361,13 +9509,10 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (BOOL) openCydiaURL:(NSURL *)url forExternal:(BOOL)external {
-    CyteViewController *page([self pageForURL:url forExternal:external]);
+    CyteViewController *page([self pageForURL:url forExternal:external withReferrer:nil]);
 
-    if (page != nil) {
-        UINavigationController *nav = [[[UINavigationController alloc] init] autorelease];
-        [nav setViewControllers:[NSArray arrayWithObject:page]];
-        [tabbar_ setUnselectedViewController:nav];
-    }
+    if (page != nil)
+        [tabbar_ setUnselectedViewController:page];
 
     return page != nil;
 }
@@ -9390,15 +9535,19 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         [super applicationWillResignActive:application];
 }
 
-- (void) applicationWillTerminate:(UIApplication *)application {
-    Changed_ = true;
+- (void) saveState {
     [Metadata_ setObject:[tabbar_ navigationURLCollection] forKey:@"InterfaceState"];
     [Metadata_ setObject:[NSDate date] forKey:@"LastClosed"];
     [Metadata_ setObject:[NSNumber numberWithInt:[tabbar_ selectedIndex]] forKey:@"InterfaceIndex"];
+    Changed_ = true;
 
     [self _saveConfig];
 }
 
+- (void) applicationWillTerminate:(UIApplication *)application {
+    [self saveState];
+}
+
 - (void) setConfigurationData:(NSString *)data {
     static Pcre conffile_r("^'(.*)' '(.*)' ([01]) ([01])$");
 
@@ -9427,7 +9576,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (void) addStashController {
-    ++locked_;
+    [self lockSuspend];
     stash_ = [[[StashController alloc] init] autorelease];
     [window_ addSubview:[stash_ view]];
 }
@@ -9435,12 +9584,10 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 - (void) removeStashController {
     [[stash_ view] removeFromSuperview];
     stash_ = nil;
-    --locked_;
+    [self unlockSuspend];
 }
 
 - (void) stash {
-    [self setIdleTimerDisabled:YES];
-
     [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackOpaque];
     UpdateExternalStatus(1);
     [self yieldToSelector:@selector(system:) withObject:@"/usr/libexec/cydia/free.sh"];
@@ -9448,27 +9595,35 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
     [self removeStashController];
 
-    if (ExecFork() == 0) {
+    pid_t pid(ExecFork());
+    if (pid == 0) {
         execlp("launchctl", "launchctl", "stop", "com.apple.SpringBoard", NULL);
         perror("launchctl stop");
-    }
+
+        exit(0);
+    } ReapZombie(pid);
 }
 
 - (void) setupViewControllers {
-    tabbar_ = [[[CYTabBarController alloc] initWithDatabase:database_] autorelease];
-
-    NSMutableArray *items([NSMutableArray arrayWithObjects:
-        [[[UITabBarItem alloc] initWithTitle:@"Cydia" image:[UIImage applicationImageNamed:@"home.png"] tag:0] autorelease],
-        [[[UITabBarItem alloc] initWithTitle:UCLocalize("SECTIONS") image:[UIImage applicationImageNamed:@"install.png"] tag:0] autorelease],
-        [[[UITabBarItem alloc] initWithTitle:UCLocalize("CHANGES") image:[UIImage applicationImageNamed:@"changes.png"] tag:0] autorelease],
-        [[[UITabBarItem alloc] initWithTitle:UCLocalize("SEARCH") image:[UIImage applicationImageNamed:@"search.png"] tag:0] autorelease],
-    nil]);
-
-    if (IsWildcat_) {
-        [items insertObject:[[[UITabBarItem alloc] initWithTitle:UCLocalize("SOURCES") image:[UIImage applicationImageNamed:@"source.png"] tag:0] autorelease] atIndex:3];
-        [items insertObject:[[[UITabBarItem alloc] initWithTitle:UCLocalize("INSTALLED") image:[UIImage applicationImageNamed:@"manage.png"] tag:0] autorelease] atIndex:3];
+    tabbar_ = [[[CydiaTabBarController alloc] initWithDatabase:database_] autorelease];
+
+    NSMutableArray *items;
+    if (kCFCoreFoundationVersionNumber < 800) {
+        items = [NSMutableArray arrayWithObjects:
+            [[[UITabBarItem alloc] initWithTitle:@"Cydia" image:[UIImage applicationImageNamed:@"home.png"] tag:0] autorelease],
+            [[[UITabBarItem alloc] initWithTitle:UCLocalize("SOURCES") image:[UIImage applicationImageNamed:@"install.png"] tag:0] autorelease],
+            [[[UITabBarItem alloc] initWithTitle:UCLocalize("CHANGES") image:[UIImage applicationImageNamed:@"changes.png"] tag:0] autorelease],
+            [[[UITabBarItem alloc] initWithTitle:UCLocalize("INSTALLED") image:[UIImage applicationImageNamed:@"manage.png"] tag:0] autorelease],
+            [[[UITabBarItem alloc] initWithTitle:UCLocalize("SEARCH") image:[UIImage applicationImageNamed:@"search.png"] tag:0] autorelease],
+        nil];
     } else {
-        [items insertObject:[[[UITabBarItem alloc] initWithTitle:UCLocalize("MANAGE") image:[UIImage applicationImageNamed:@"manage.png"] tag:0] autorelease] atIndex:3];
+        items = [NSMutableArray arrayWithObjects:
+            [[[UITabBarItem alloc] initWithTitle:@"Cydia" image:[UIImage applicationImageNamed:@"home7.png"] selectedImage:[UIImage applicationImageNamed:@"home7s.png"]] autorelease],
+            [[[UITabBarItem alloc] initWithTitle:UCLocalize("SOURCES") image:[UIImage applicationImageNamed:@"install7.png"] selectedImage:[UIImage applicationImageNamed:@"install7s.png"]] autorelease],
+            [[[UITabBarItem alloc] initWithTitle:UCLocalize("CHANGES") image:[UIImage applicationImageNamed:@"changes7.png"] selectedImage:[UIImage applicationImageNamed:@"changes7s.png"]] autorelease],
+            [[[UITabBarItem alloc] initWithTitle:UCLocalize("INSTALLED") image:[UIImage applicationImageNamed:@"manage7.png"] selectedImage:[UIImage applicationImageNamed:@"manage7s.png"]] autorelease],
+            [[[UITabBarItem alloc] initWithTitle:UCLocalize("SEARCH") image:[UIImage applicationImageNamed:@"search7.png"] selectedImage:[UIImage applicationImageNamed:@"search7s.png"]] autorelease],
+        nil];
     }
 
     NSMutableArray *controllers([NSMutableArray array]);
@@ -9482,7 +9637,29 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     [tabbar_ setUpdateDelegate:self];
 }
 
+- (void) _sendMemoryWarningNotification {
+    if (kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber_iPhoneOS_3_0) // XXX: maybe 4_0?
+        [[NSNotificationCenter defaultCenter] postNotificationName:@"UIApplicationMemoryWarningNotification" object:[UIApplication sharedApplication]];
+    else
+        [[NSNotificationCenter defaultCenter] postNotificationName:@"UIApplicationDidReceiveMemoryWarningNotification" object:[UIApplication sharedApplication]];
+}
+
+- (void) _sendMemoryWarningNotifications {
+    while (true) {
+        [self performSelectorOnMainThread:@selector(_sendMemoryWarningNotification) withObject:nil waitUntilDone:NO];
+        sleep(2);
+        //usleep(2000000);
+    }
+}
+
+- (void) applicationDidReceiveMemoryWarning:(UIApplication *)application {
+    NSLog(@"--");
+    [[NSURLCache sharedURLCache] removeAllCachedResponses];
+}
+
 - (void) applicationDidFinishLaunching:(id)unused {
+    //[NSThread detachNewThreadSelector:@selector(_sendMemoryWarningNotifications) toTarget:self withObject:nil];
+
 _trace();
     if ([self respondsToSelector:@selector(setApplicationSupportsShakeToEdit:)])
         [self setApplicationSupportsShakeToEdit:NO];
@@ -9494,7 +9671,7 @@ _trace();
     [NSURLCache setSharedURLCache:[[[CYURLCache alloc]
         initWithMemoryCapacity:524288
         diskCapacity:10485760
-        diskPath:[NSString stringWithFormat:@"%@/Library/Caches/com.saurik.Cydia/SDURLCache", @"/var/root"]
+        diskPath:[NSString stringWithFormat:@"%@/SDURLCache", Cache_]
     ] autorelease]];
 
     [CydiaWebViewController _initialize];
@@ -9507,6 +9684,7 @@ _trace();
     Font12_ = [UIFont systemFontOfSize:12];
     Font12Bold_ = [UIFont boldSystemFontOfSize:12];
     Font14_ = [UIFont systemFontOfSize:14];
+    Font18_ = [UIFont systemFontOfSize:18];
     Font18Bold_ = [UIFont boldSystemFontOfSize:18];
     Font22Bold_ = [UIFont boldSystemFontOfSize:22];
 
@@ -9514,25 +9692,14 @@ _trace();
     broken_ = [NSMutableArray arrayWithCapacity:4];
 
     // XXX: I really need this thing... like, seriously... I'm sorry
-    [[[CydiaWebViewController alloc] initWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/appcache/", UI_]]] reloadData];
+    [[[AppCacheController alloc] initWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/appcache/", UI_]]] reloadData];
 
     window_ = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
     [window_ orderFront:self];
     [window_ makeKey:self];
     [window_ setHidden:NO];
 
-    if (
-        readlink("/Applications", NULL, 0) == -1 && errno == EINVAL ||
-        readlink("/Library/Ringtones", NULL, 0) == -1 && errno == EINVAL ||
-        readlink("/Library/Wallpaper", NULL, 0) == -1 && errno == EINVAL ||
-        //readlink("/usr/bin", NULL, 0) == -1 && errno == EINVAL ||
-        readlink("/usr/include", NULL, 0) == -1 && errno == EINVAL ||
-        readlink("/usr/lib/pam", NULL, 0) == -1 && errno == EINVAL ||
-        readlink("/usr/libexec", NULL, 0) == -1 && errno == EINVAL ||
-        readlink("/usr/share", NULL, 0) == -1 && errno == EINVAL ||
-        //readlink("/var/lib", NULL, 0) == -1 && errno == EINVAL ||
-        false
-    ) {
+    if (false) stash: {
         [self addStashController];
         // XXX: this would be much cleaner as a yieldToSelector:
         // that way the removeStashController could happen right here inline
@@ -9541,14 +9708,41 @@ _trace();
         return;
     }
 
+    struct stat root;
+    int error(stat("/", &root));
+    _assert(error != -1);
+
+    #define Stash_(path) do { \
+        struct stat folder; \
+        int error(lstat((path), &folder)); \
+        if (error != -1 && ( \
+            folder.st_dev == root.st_dev && \
+            S_ISDIR(folder.st_mode) \
+        ) || error == -1 && ( \
+            errno == ENOENT || \
+            errno == ENOTDIR \
+        )) goto stash; \
+    } while (false)
+
+    Stash_("/Applications");
+    Stash_("/Library/Ringtones");
+    Stash_("/Library/Wallpaper");
+    //Stash_("/usr/bin");
+    Stash_("/usr/include");
+    Stash_("/usr/lib/pam");
+    Stash_("/usr/share");
+    //Stash_("/var/lib");
+
     database_ = [Database sharedInstance];
     [database_ setDelegate:self];
 
     [window_ setUserInteractionEnabled:NO];
     [self setupViewControllers];
 
-    emulated_ = [[[CYEmulatedLoadingController alloc] initWithDatabase:database_] autorelease];
+    emulated_ = [[[CydiaLoadingViewController alloc] init] autorelease];
     [window_ addSubview:[emulated_ view]];
+    if ([window_ respondsToSelector:@selector(setRootViewController:)])
+        [window_ setRootViewController:emulated_];
 
     [self performSelector:@selector(loadData) withObject:nil afterDelay:0];
 _trace();
@@ -9557,37 +9751,27 @@ _trace();
 - (NSArray *) defaultStartPages {
     NSMutableArray *standard = [NSMutableArray array];
     [standard addObject:[NSArray arrayWithObject:@"cydia://home"]];
-    [standard addObject:[NSArray arrayWithObject:@"cydia://sections"]];
+    [standard addObject:[NSArray arrayWithObject:@"cydia://sources"]];
     [standard addObject:[NSArray arrayWithObject:@"cydia://changes"]];
-    if (!IsWildcat_) {
-        [standard addObject:[NSArray arrayWithObject:@"cydia://manage"]];
-    } else {
-        [standard addObject:[NSArray arrayWithObject:@"cydia://installed"]];
-        [standard addObject:[NSArray arrayWithObject:@"cydia://sources"]];
-    }
+    [standard addObject:[NSArray arrayWithObject:@"cydia://installed"]];
     [standard addObject:[NSArray arrayWithObject:@"cydia://search"]];
     return standard;
 }
 
 - (void) loadData {
 _trace();
-    if (Role_ == nil) {
-        [window_ setUserInteractionEnabled:YES];
-        [self showSettings];
-        return;
-    } else {
-        if ([emulated_ modalViewController] != nil)
-            [emulated_ dismissModalViewControllerAnimated:YES];
-        [window_ setUserInteractionEnabled:NO];
-    }
+    if ([emulated_ modalViewController] != nil)
+        [emulated_ dismissModalViewControllerAnimated:YES];
+    [window_ setUserInteractionEnabled:NO];
 
-    [self reloadData];
+    [self reloadDataWithInvocation:nil];
+    [self refreshIfPossible];
     PrintTimes();
 
     [self disemulate];
 
     int savedIndex = [[Metadata_ objectForKey:@"InterfaceIndex"] intValue];
-    NSArray *saved = [[Metadata_ objectForKey:@"InterfaceState"] mutableCopy];
+    NSArray *saved = [[[Metadata_ objectForKey:@"InterfaceState"] mutableCopy] autorelease];
     int standardIndex = 0;
     NSArray *standard = [self defaultStartPages];
 
@@ -9599,8 +9783,8 @@ _trace();
     NSDate *closed = [Metadata_ objectForKey:@"LastClosed"];
     if (valid && closed != nil) {
         NSTimeInterval interval([closed timeIntervalSinceNow]);
-        // XXX: Is 15 minutes the optimal time here?
-        if (interval > 0 && interval <= -(15*60))
+        // XXX: Is 30 minutes the optimal time here?
+        if (interval <= -(30*60))
             valid = NO;
     }
 
@@ -9636,7 +9820,7 @@ _trace();
         for (unsigned int nav = 0; nav < [stack count]; nav++) {
             NSString *addr = [stack objectAtIndex:nav];
             NSURL *url = [NSURL URLWithString:addr];
-            CyteViewController *page = [self pageForURL:url forExternal:NO];
+            CyteViewController *page = [self pageForURL:url forExternal:NO withReferrer:nil];
             if (page != nil)
                 [current addObject:page];
         }
@@ -9691,14 +9875,6 @@ id Dealloc_(id self, SEL selector) {
     return object;
 }*/
 
-Class $WebDefaultUIKitDelegate;
-
-MSHook(void, UIWebDocumentView$_setUIKitDelegate$, UIWebDocumentView *self, SEL _cmd, id delegate) {
-    if (delegate == nil && $WebDefaultUIKitDelegate != nil)
-        delegate = [$WebDefaultUIKitDelegate sharedUIKitDelegate];
-    return _UIWebDocumentView$_setUIKitDelegate$(self, _cmd, delegate);
-}
-
 static NSSet *MobilizedFiles_;
 
 static NSURL *MobilizeURL(NSURL *url) {
@@ -9740,9 +9916,10 @@ MSHook(void *, CFXPreferencesPropertyListSource$createPlistFromDisk, CFXPreferen
 Class $NSURLConnection;
 
 MSHook(id, NSURLConnection$init$, NSURLConnection *self, SEL _cmd, NSURLRequest *request, id delegate, BOOL usesCache, int64_t maxContentLength, BOOL startImmediately, NSDictionary *connectionProperties) {
-    NSMutableURLRequest *copy([request mutableCopy]);
+    NSMutableURLRequest *copy([[request mutableCopy] autorelease]);
 
     NSURL *url([copy URL]);
+
     NSString *host([url host]);
     NSString *scheme([[url scheme] lowercaseString]);
 
@@ -9752,23 +9929,51 @@ MSHook(id, NSURLConnection$init$, NSURLConnection *self, SEL _cmd, NSURLRequest
         if ([copy respondsToSelector:@selector(setHTTPShouldUsePipelining:)])
             if ([PipelinedHosts_ containsObject:host] || [PipelinedHosts_ containsObject:compound])
                 [copy setHTTPShouldUsePipelining:YES];
+
+        if (NSString *control = [copy valueForHTTPHeaderField:@"Cache-Control"])
+            if ([control isEqualToString:@"max-age=0"])
+                if ([CachedURLs_ containsObject:url]) {
+#if !ForRelease
+                    NSLog(@"~~~: %@", url);
+#endif
+
+                    [copy setCachePolicy:NSURLRequestReturnCacheDataDontLoad];
+
+                    [copy setValue:nil forHTTPHeaderField:@"Cache-Control"];
+                    [copy setValue:nil forHTTPHeaderField:@"If-Modified-Since"];
+                    [copy setValue:nil forHTTPHeaderField:@"If-None-Match"];
+                }
     }
 
     if ((self = _NSURLConnection$init$(self, _cmd, copy, delegate, usesCache, maxContentLength, startImmediately, connectionProperties)) != nil) {
     } return self;
 }
 
-int main(int argc, char *argv[]) { _pooled
+Class $WAKWindow;
+
+static CGSize $WAKWindow$screenSize(WAKWindow *self, SEL _cmd) {
+    CGSize size([[UIScreen mainScreen] bounds].size);
+    /*if ([$WAKWindow respondsToSelector:@selector(hasLandscapeOrientation)])
+        if ([$WAKWindow hasLandscapeOrientation])
+            std::swap(size.width, size.height);*/
+    return size;
+}
+
+Class $NSUserDefaults;
+
+MSHook(id, NSUserDefaults$objectForKey$, NSUserDefaults *self, SEL _cmd, NSString *key) {
+    if ([key respondsToSelector:@selector(isEqualToString:)] && [key isEqualToString:@"WebKitLocalStorageDatabasePathPreferenceKey"])
+        return [NSString stringWithFormat:@"%@/LocalStorage", Cache_];
+    return _NSUserDefaults$objectForKey$(self, _cmd, key);
+}
+
+int main(int argc, char *argv[]) {
+    NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
+
     _trace();
 
     UpdateExternalStatus(0);
 
-    if (Class $UIDevice = objc_getClass("UIDevice")) {
-        UIDevice *device([$UIDevice currentDevice]);
-        IsWildcat_ = [device respondsToSelector:@selector(isWildcat)] && [device isWildcat];
-    } else
-        IsWildcat_ = false;
-
     UIScreen *screen([UIScreen mainScreen]);
     if ([screen respondsToSelector:@selector(scale)])
         ScreenScale_ = [screen scale];
@@ -9776,27 +9981,37 @@ int main(int argc, char *argv[]) { _pooled
         ScreenScale_ = 1;
 
     UIDevice *device([UIDevice currentDevice]);
-    if (![device respondsToSelector:@selector(userInterfaceIdiom)])
-        Idiom_ = @"iphone";
-    else {
+    if ([device respondsToSelector:@selector(userInterfaceIdiom)]) {
         UIUserInterfaceIdiom idiom([device userInterfaceIdiom]);
-        if (idiom == UIUserInterfaceIdiomPhone)
-            Idiom_ = @"iphone";
-        else if (idiom == UIUserInterfaceIdiomPad)
-            Idiom_ = @"ipad";
-        else
-            NSLog(@"unknown UIUserInterfaceIdiom!");
+        if (idiom == UIUserInterfaceIdiomPad)
+            IsWildcat_ = true;
     }
 
+    Idiom_ = IsWildcat_ ? @"ipad" : @"iphone";
+
+    Pcre pattern("^([0-9]+\\.[0-9]+)");
+
+    if (pattern([device systemVersion]))
+        Firmware_ = pattern[1];
+    if (pattern(Cydia_))
+        Major_ = pattern[1];
+
     SessionData_ = [NSMutableDictionary dictionaryWithCapacity:4];
 
     HostConfig_ = [[[NSObject alloc] init] autorelease];
     @synchronized (HostConfig_) {
         BridgedHosts_ = [NSMutableSet setWithCapacity:4];
+        TokenHosts_ = [NSMutableSet setWithCapacity:4];
+        InsecureHosts_ = [NSMutableSet setWithCapacity:4];
         PipelinedHosts_ = [NSMutableSet setWithCapacity:4];
+        CachedURLs_ = [NSMutableSet setWithCapacity:32];
     }
 
-    UI_ = CydiaURL([NSString stringWithFormat:@"ui/ios~%@", Idiom_]);
+    NSString *ui(@"ui/ios");
+    if (Idiom_ != nil)
+        ui = [ui stringByAppendingString:[NSString stringWithFormat:@"~%@", Idiom_]];
+    ui = [ui stringByAppendingString:[NSString stringWithFormat:@"/%@", Major_]];
+    UI_ = CydiaURL(ui);
 
     PackageName = reinterpret_cast<CYString &(*)(Package *, SEL)>(method_getImplementation(class_getInstanceMethod([Package class], @selector(cyname))));
 
@@ -9808,6 +10023,11 @@ int main(int argc, char *argv[]) { _pooled
     /* Library Hacks {{{ */
     class_addMethod(objc_getClass("DOMNodeList"), @selector(countByEnumeratingWithState:objects:count:), (IMP) &DOMNodeList$countByEnumeratingWithState$objects$count$, "I20@0:4^{NSFastEnumerationState}8^@12I16");
 
+    $WAKWindow = objc_getClass("WAKWindow");
+    if ($WAKWindow != NULL)
+        if (Method method = class_getInstanceMethod($WAKWindow, @selector(screenSize)))
+            method_setImplementation(method, (IMP) &$WAKWindow$screenSize);
+
     $CFXPreferencesPropertyListSource = objc_getClass("CFXPreferencesPropertyListSource");
 
     Method CFXPreferencesPropertyListSource$_backingPlistChangedSinceLastSync(class_getInstanceMethod($CFXPreferencesPropertyListSource, @selector(_backingPlistChangedSinceLastSync)));
@@ -9822,19 +10042,19 @@ int main(int argc, char *argv[]) { _pooled
         method_setImplementation(CFXPreferencesPropertyListSource$createPlistFromDisk, reinterpret_cast<IMP>(&$CFXPreferencesPropertyListSource$createPlistFromDisk));
     }
 
-    $WebDefaultUIKitDelegate = objc_getClass("WebDefaultUIKitDelegate");
-    Method UIWebDocumentView$_setUIKitDelegate$(class_getInstanceMethod([WebView class], @selector(_setUIKitDelegate:)));
-    if (UIWebDocumentView$_setUIKitDelegate$ != NULL) {
-        _UIWebDocumentView$_setUIKitDelegate$ = reinterpret_cast<void (*)(UIWebDocumentView *, SEL, id)>(method_getImplementation(UIWebDocumentView$_setUIKitDelegate$));
-        method_setImplementation(UIWebDocumentView$_setUIKitDelegate$, reinterpret_cast<IMP>(&$UIWebDocumentView$_setUIKitDelegate$));
-    }
-
     $NSURLConnection = objc_getClass("NSURLConnection");
     Method NSURLConnection$init$(class_getInstanceMethod($NSURLConnection, @selector(_initWithRequest:delegate:usesCache:maxContentLength:startImmediately:connectionProperties:)));
     if (NSURLConnection$init$ != NULL) {
         _NSURLConnection$init$ = reinterpret_cast<id (*)(NSURLConnection *, SEL, NSURLRequest *, id, BOOL, int64_t, BOOL, NSDictionary *)>(method_getImplementation(NSURLConnection$init$));
         method_setImplementation(NSURLConnection$init$, reinterpret_cast<IMP>(&$NSURLConnection$init$));
     }
+
+    $NSUserDefaults = objc_getClass("NSUserDefaults");
+    Method NSUserDefaults$objectForKey$(class_getInstanceMethod($NSUserDefaults, @selector(objectForKey:)));
+    if (NSUserDefaults$objectForKey$ != NULL) {
+        _NSUserDefaults$objectForKey$ = reinterpret_cast<id (*)(NSUserDefaults *, SEL, NSString *)>(method_getImplementation(NSUserDefaults$objectForKey$));
+        method_setImplementation(NSUserDefaults$objectForKey$, reinterpret_cast<IMP>(&$NSUserDefaults$objectForKey$));
+    }
     /* }}} */
     /* Set Locale {{{ */
     Locale_ = CFLocaleCopyCurrent();
@@ -9897,6 +10117,11 @@ int main(int argc, char *argv[]) { _pooled
     setuid(0);
     setgid(0);
 
+    if (access("/var/mobile/Library/Keyboard/UserDictionary.sqlite", F_OK) == 0)
+        system("mkdir -p /var/root/Library/Keyboard; cp -af /var/mobile/Library/Keyboard/UserDictionary.sqlite /var/root/Library/Keyboard/");
+
+    Cache_ = [[NSString stringWithFormat:@"%@/Library/Caches/com.saurik.Cydia", @"/var/root"] retain];
+
     /*Method alloc = class_getClassMethod([NSObject class], @selector(alloc));
     alloc_ = alloc->method_imp;
     alloc->method_imp = (IMP) &Alloc_;*/
@@ -9905,6 +10130,9 @@ int main(int argc, char *argv[]) { _pooled
     dealloc_ = dealloc->method_imp;
     dealloc->method_imp = (IMP) &Dealloc_;*/
 
+    void *gestalt(dlopen("/usr/lib/libMobileGestalt.dylib", RTLD_GLOBAL | RTLD_LAZY));
+    $MGCopyAnswer = reinterpret_cast<CFStringRef (*)(CFStringRef)>(dlsym(gestalt, "MGCopyAnswer"));
+
     /* System Information {{{ */
     size_t size;
 
@@ -9936,30 +10164,23 @@ int main(int argc, char *argv[]) { _pooled
     ChipID_ = [CYHex((NSData *) CYIOGetValue("IODeviceTree:/chosen", @"unique-chip-id"), true) uppercaseString];
     BBSNum_ = CYHex((NSData *) CYIOGetValue("IOService:/AppleARMPE/baseband", @"snum"), false);
 
-    UniqueID_ = [[UIDevice currentDevice] uniqueIdentifier];
-
-    CFStringRef (*$CTSIMSupportCopyMobileSubscriberCountryCode)(CFAllocatorRef);
-    $CTSIMSupportCopyMobileSubscriberCountryCode = reinterpret_cast<CFStringRef (*)(CFAllocatorRef)>(dlsym(RTLD_DEFAULT, "CTSIMSupportCopyMobileSubscriberCountryCode"));
-    CFStringRef mcc($CTSIMSupportCopyMobileSubscriberCountryCode == NULL ? NULL : (*$CTSIMSupportCopyMobileSubscriberCountryCode)(kCFAllocatorDefault));
-
-    CFStringRef (*$CTSIMSupportCopyMobileSubscriberNetworkCode)(CFAllocatorRef);
-    $CTSIMSupportCopyMobileSubscriberNetworkCode = reinterpret_cast<CFStringRef (*)(CFAllocatorRef)>(dlsym(RTLD_DEFAULT, "CTSIMSupportCopyMobileSubscriberCountryCode"));
-    CFStringRef mnc($CTSIMSupportCopyMobileSubscriberNetworkCode == NULL ? NULL : (*$CTSIMSupportCopyMobileSubscriberNetworkCode)(kCFAllocatorDefault));
+    UniqueID_ = UniqueIdentifier(device);
 
-    if (mcc != NULL && mnc != NULL)
-        PLMN_ = [NSString stringWithFormat:@"%@%@", mcc, mnc];
-
-    if (mnc != NULL)
-        CFRelease(mnc);
-    if (mcc != NULL)
-        CFRelease(mcc);
-
-    if (NSDictionary *system = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"])
-        Build_ = [system objectForKey:@"ProductBuildVersion"];
     if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:@"/Applications/MobileSafari.app/Info.plist"]) {
         Product_ = [info objectForKey:@"SafariProductVersion"];
         Safari_ = [info objectForKey:@"CFBundleVersion"];
     }
+
+    NSString *agent([NSString stringWithFormat:@"Cydia/%@ CyF/%.2f", Cydia_, kCFCoreFoundationVersionNumber]);
+
+    if (Pcre match = Pcre("^[0-9]+(\\.[0-9]+)+", Safari_))
+        agent = [NSString stringWithFormat:@"Safari/%@ %@", match[0], agent];
+    if (Pcre match = Pcre("^[0-9]+[A-Z][0-9]+[a-z]?", System_))
+        agent = [NSString stringWithFormat:@"Mobile/%@ %@", match[0], agent];
+    if (Pcre match = Pcre("^[0-9]+(\\.[0-9]+)+", Product_))
+        agent = [NSString stringWithFormat:@"Version/%@ %@", match[0], agent];
+
+    UserAgent_ = agent;
     /* }}} */
     /* Load Database {{{ */
     _trace();
@@ -9973,14 +10194,20 @@ int main(int argc, char *argv[]) { _pooled
         Settings_ = [Metadata_ objectForKey:@"Settings"];
 
         Packages_ = [Metadata_ objectForKey:@"Packages"];
+
+        Values_ = [Metadata_ objectForKey:@"Values"];
         Sections_ = [Metadata_ objectForKey:@"Sections"];
         Sources_ = [Metadata_ objectForKey:@"Sources"];
 
         Token_ = [Metadata_ objectForKey:@"Token"];
+
+        Version_ = [Metadata_ objectForKey:@"Version"];
     }
 
-    if (Settings_ != nil)
-        Role_ = [Settings_ objectForKey:@"Role"];
+    if (Values_ == nil) {
+        Values_ = [[[NSMutableDictionary alloc] initWithCapacity:4] autorelease];
+        [Metadata_ setObject:Values_ forKey:@"Values"];
+    }
 
     if (Sections_ == nil) {
         Sections_ = [[[NSMutableDictionary alloc] initWithCapacity:32] autorelease];
@@ -9991,8 +10218,39 @@ int main(int argc, char *argv[]) { _pooled
         Sources_ = [[[NSMutableDictionary alloc] initWithCapacity:0] autorelease];
         [Metadata_ setObject:Sources_ forKey:@"Sources"];
     }
+
+    if (Version_ == nil) {
+        Version_ = [NSNumber numberWithUnsignedInt:0];
+        [Metadata_ setObject:Version_ forKey:@"Version"];
+    }
+
+    if ([Version_ unsignedIntValue] == 0) {
+        CydiaAddSource(@"http://apt.thebigboss.org/repofiles/cydia/", @"stable", [NSMutableArray arrayWithObject:@"main"]);
+        CydiaAddSource(@"http://apt.modmyi.com/", @"stable", [NSMutableArray arrayWithObject:@"main"]);
+        CydiaAddSource(@"http://cydia.zodttd.com/repo/cydia/", @"stable", [NSMutableArray arrayWithObject:@"main"]);
+        CydiaAddSource(@"http://repo666.ultrasn0w.com/", @"./");
+
+        Version_ = [NSNumber numberWithUnsignedInt:1];
+        [Metadata_ setObject:Version_ forKey:@"Version"];
+
+        [Metadata_ removeObjectForKey:@"LastUpdate"];
+
+        Changed_ = true;
+    }
+
+    _H<NSMutableArray> broken([NSMutableArray array]);
+    for (NSString *key in (id) Sources_)
+        if ([key rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@"# "]].location != NSNotFound)
+            [broken addObject:key];
+    if ([broken count] != 0) {
+        for (NSString *key in (id) broken)
+            [Sources_ removeObjectForKey:key];
+        Changed_ = true;
+    } broken = nil;
     /* }}} */
 
+    CydiaWriteSources();
+
     _trace();
     MetaFile_.Open("/var/lib/cydia/metadata.cb0");
     _trace();
@@ -10028,11 +10286,7 @@ int main(int argc, char *argv[]) { _pooled
 
     int version([[NSString stringWithContentsOfFile:@"/var/lib/cydia/firmware.ver"] intValue]);
 
-    if (access("/tmp/.cydia.fw", F_OK) == 0) {
-        unlink("/tmp/.cydia.fw");
-        goto firmware;
-    } else if (access("/User", F_OK) != 0 || version < 4) {
-      firmware:
+    if (access("/User", F_OK) != 0 || version != 6) {
         _trace();
         system("/usr/libexec/cydia/firmware.sh");
         _trace();
@@ -10070,6 +10324,7 @@ int main(int argc, char *argv[]) { _pooled
     Blue_.Set(space_, 0.2, 0.2, 1.0, 1.0);
     Blueish_.Set(space_, 0x19/255.f, 0x32/255.f, 0x50/255.f, 1.0);
     Black_.Set(space_, 0.0, 0.0, 0.0, 1.0);
+    Folder_.Set(space_, 0x8e/255.f, 0x8e/255.f, 0x93/255.f, 1.0);
     Off_.Set(space_, 0.9, 0.9, 0.9, 1.0);
     White_.Set(space_, 1.0, 1.0, 1.0, 1.0);
     Gray_.Set(space_, 0.4, 0.4, 0.4, 1.0);
@@ -10081,14 +10336,18 @@ int main(int argc, char *argv[]) { _pooled
     RemovingColor_ = [UIColor colorWithRed:1.00f green:0.88f blue:0.88f alpha:1.00f];
     /* }}}*/
     /* UIKit Configuration {{{ */
-    void (*$GSFontSetUseLegacyFontMetrics)(BOOL)(reinterpret_cast<void (*)(BOOL)>(dlsym(RTLD_DEFAULT, "GSFontSetUseLegacyFontMetrics")));
-    if ($GSFontSetUseLegacyFontMetrics != NULL)
-        $GSFontSetUseLegacyFontMetrics(YES);
-
     // XXX: I have a feeling this was important
     //UIKeyboardDisableAutomaticAppearance();
     /* }}} */
 
+    $SBSSetInterceptsMenuButtonForever = reinterpret_cast<void (*)(bool)>(dlsym(RTLD_DEFAULT, "SBSSetInterceptsMenuButtonForever"));
+
+    const char *symbol(kCFCoreFoundationVersionNumber >= 800 ? "MGGetBoolAnswer" : "GSSystemHasCapability");
+    BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast<BOOL (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, symbol));
+    bool fast = GSSystemHasCapability != NULL && GSSystemHasCapability(CFSTR("armv7"));
+
+    PulseInterval_ = fast ? 50000 : 500000;
+
     Colon_ = UCLocalize("COLON_DELIMITED");
     Elision_ = UCLocalize("ELISION");
     Error_ = UCLocalize("ERROR");
@@ -10100,5 +10359,6 @@ int main(int argc, char *argv[]) { _pooled
     CGColorSpaceRelease(space_);
     CFRelease(Locale_);
 
+    [pool release];
     return value;
 }