]> git.saurik.com Git - cydia.git/blobdiff - Cydia.mm
Added icon for the sources tab on the iPad.
[cydia.git] / Cydia.mm
index ae69e74a6908cd644cbee17fa036ba195574c039..1dfe4313ddaf2cce36e2f08046dc077507108161 100644 (file)
--- a/Cydia.mm
+++ b/Cydia.mm
 #define USE_SYSTEM_MALLOC 1
 
 /* #include Directives {{{ */
-#import "UICaboodle/UCPlatform.h"
-#import "UICaboodle/UCLocalize.h"
+#include "UICaboodle/UCPlatform.h"
+#include "UICaboodle/UCLocalize.h"
 
 #include <objc/objc.h>
 #include <objc/runtime.h>
 
 #include <CoreGraphics/CoreGraphics.h>
-#include <GraphicsServices/GraphicsServices.h>
 #include <Foundation/Foundation.h>
 
 #if 0
 #include <CoreFoundation/CFPriv.h>
 #include <CoreFoundation/CFUniChar.h>
 
-#import <UIKit/UIKit.h>
+#include <SystemConfiguration/SystemConfiguration.h>
+
+#include <UIKit/UIKit.h>
+#include "iPhonePrivate.h"
+
+#include <IOKit/IOKitLib.h>
 
 #include <WebCore/WebCoreThread.h>
-#import <WebKit/WebDefaultUIKitDelegate.h>
 
 #include <algorithm>
 #include <iomanip>
 #include <sys/param.h>
 #include <sys/mount.h>
 
+#include <fcntl.h>
 #include <notify.h>
 #include <dlfcn.h>
 
@@ -116,53 +120,9 @@ extern "C" {
 
 #include <ext/hash_map>
 
-#import "UICaboodle/BrowserView.h"
-#import "UICaboodle/ResetView.h"
-
-#import "substrate.h"
-
-// Apple's sample Reachability code, ASPL licensed.
-#import "Reachability.h"
-/* }}} */
-
-/* Header Fixes and Updates {{{ */
-typedef enum {
-   UIModalPresentationFullScreen = 0,
-   UIModalPresentationPageSheet,
-   UIModalPresentationFormSheet,
-   UIModalPresentationCurrentContext,
-} UIModalPresentationStyle;
-
-@interface UIAlertView (Private)
-- (void)setNumberOfRows:(int)rows;
-- (void)setContext:(id)context;
-- (id)context;
-@end
-
-@interface UIViewController (UIKit)
-- (id)navigationItem;
-- (id)navigationController;
-- (id)tabBarItem;
-@end
+#include "UICaboodle/BrowserView.h"
 
-@interface UITabBarController : UIViewController {
-    id _tabBar;
-    id _containerView;
-    id _viewControllerTransitionView;
-    id _viewControllers;
-    id _tabBarItemsToViewControllers;
-    id _selectedViewController;
-    id _moreNavigationController;
-    id _customizableViewControllers;
-    id _delegate;
-    id _selectedViewControllerDuringWillAppear;
-    id _transientViewController;
-    unsigned int isShowingMoreItem:1;
-    unsigned int needsToRebuildItems:1;
-    unsigned int isBarHidden:1;
-    unsigned int editButtonOnLeft:1;
-}
-@end
+#include "substrate.h"
 /* }}} */
 
 /* Profiler {{{ */
@@ -257,6 +217,15 @@ static _finline NSString *CydiaURL(NSString *path) {
     return [[NSString stringWithUTF8String:page] stringByAppendingString:path];
 }
 
+static _finline void UpdateExternalStatus(uint64_t newStatus) {
+    int notify_token;
+    if (notify_register_check("com.saurik.Cydia.status", &notify_token) == NOTIFY_STATUS_OK) {
+        notify_set_state(notify_token, newStatus);
+        notify_cancel(notify_token);
+    }
+    notify_post("com.saurik.Cydia.status");
+}
+
 /* [NSObject yieldToSelector:(withObject:)] {{{*/
 @interface NSObject (Cydia)
 - (id) yieldToSelector:(SEL)selector withObject:(id)object;
@@ -342,6 +311,18 @@ static _finline NSString *CydiaURL(NSString *path) {
     } return self;
 }
 
+- (void) _updateFrameForDisplay {
+    [super _updateFrameForDisplay];
+    if ([self cancelButtonIndex] == -1) {
+        NSArray *buttons = [self buttons];
+        if ([buttons count]) {
+            UIImage *background = [[buttons objectAtIndex:0] backgroundForState:0];
+            for (UIThreePartButton *button in buttons)
+                [button setBackground:background forState:0];
+        }
+    }
+}
+
 - (void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
     button_ = buttonIndex + 1;
 }
@@ -351,11 +332,9 @@ static _finline NSString *CydiaURL(NSString *path) {
 }
 
 - (int) yieldToPopupAlertAnimated:(BOOL)animated {
+    [self setRunsModal:YES];
     button_ = 0;
     [self show];
-    NSRunLoop *loop([NSRunLoop currentRunLoop]);
-    NSDate *future([NSDate distantFuture]);
-    while (button_ == 0 && [loop runMode:NSDefaultRunLoopMode beforeDate:future]);
     return button_;
 }
 
@@ -394,7 +373,7 @@ static const CFStringCompareFlags LaxCompareFlags_ = kCFCompareCaseInsensitive |
 
 #define lprintf(args...) fprintf(stderr, args)
 
-#define ForRelease 0
+#define ForRelease 1
 #define TraceLogging (1 && !ForRelease)
 #define HistogramInsertionSort (0 && !ForRelease)
 #define ProfileTimes (0 && !ForRelease)
@@ -639,7 +618,9 @@ void CFArrayInsertionSortValues(CFMutableArrayRef array, CFRange range, CFCompar
 @end
 /* }}} */
 
-NSUInteger WebScriptObject$countByEnumeratingWithState$objects$count$(WebScriptObject *self, SEL sel, NSFastEnumerationState *state, id *objects, NSUInteger count) {
+@implementation WebScriptObject (NSFastEnumeration)
+
+- (NSUInteger) countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)objects count:(NSUInteger)count {
     size_t length([self count] - state->state);
     if (length <= 0)
         return 0;
@@ -652,6 +633,8 @@ NSUInteger WebScriptObject$countByEnumeratingWithState$objects$count$(WebScriptO
     return length;
 }
 
+@end
+
 NSUInteger DOMNodeList$countByEnumeratingWithState$objects$count$(DOMNodeList *self, SEL sel, NSFastEnumerationState *state, id *objects, NSUInteger count) {
     size_t length([self length] - state->state);
     if (length <= 0)
@@ -665,10 +648,6 @@ NSUInteger DOMNodeList$countByEnumeratingWithState$objects$count$(DOMNodeList *s
     return length;
 }
 
-@interface NSString (UIKit)
-- (NSString *) stringByAddingPercentEscapes;
-@end
-
 /* Cydia NSString Additions {{{ */
 @interface NSString (Cydia)
 + (NSString *) stringWithUTF8BytesNoCopy:(const char *)bytes length:(int)length;
@@ -734,7 +713,7 @@ NSUInteger DOMNodeList$countByEnumeratingWithState$objects$count$(DOMNodeList *s
 
 - (NSString *) stringByAddingPercentEscapesIncludingReserved {
     return [(id)CFURLCreateStringByAddingPercentEscapes(
-        kCFAllocatorDefault, 
+        kCFAllocatorDefault,
         (CFStringRef) self,
         NULL,
         CFSTR(";/?:@&=+$,"),
@@ -994,17 +973,17 @@ class Pcre {
 @end
 /* }}} */
 /* CoreGraphics Primitives {{{ */
-class CGColor {
+class CYColor {
   private:
     CGColorRef color_;
 
   public:
-    CGColor() :
+    CYColor() :
         color_(NULL)
     {
     }
 
-    CGColor(CGColorSpaceRef space, float red, float green, float blue, float alpha) :
+    CYColor(CGColorSpaceRef space, float red, float green, float blue, float alpha) :
         color_(NULL)
     {
         Set(space, red, green, blue, alpha);
@@ -1015,14 +994,14 @@ class CGColor {
             CGColorRelease(color_);
     }
 
-    ~CGColor() {
+    ~CYColor() {
         Clear();
     }
 
     void Set(CGColorSpaceRef space, float red, float green, float blue, float alpha) {
         Clear();
         float color[] = {red, green, blue, alpha};
-        color_ = CGColorCreate(space, color);
+        color_ = CGColorCreate(space, (CGFloat *) color);
     }
 
     operator CGColorRef() {
@@ -1045,15 +1024,15 @@ static NSArray *Finishes_;
 
 static bool Queuing_;
 
-static CGColor Blue_;
-static CGColor Blueish_;
-static CGColor Black_;
-static CGColor Off_;
-static CGColor White_;
-static CGColor Gray_;
-static CGColor Green_;
-static CGColor Purple_;
-static CGColor Purplish_;
+static CYColor Blue_;
+static CYColor Blueish_;
+static CYColor Black_;
+static CYColor Off_;
+static CYColor White_;
+static CYColor Gray_;
+static CYColor Green_;
+static CYColor Purple_;
+static CYColor Purplish_;
 
 static UIColor *InstallingColor_;
 static UIColor *RemovingColor_;
@@ -1071,14 +1050,14 @@ static UIFont *Font18Bold_;
 static UIFont *Font22Bold_;
 
 static const char *Machine_ = NULL;
-static const NSString *System_ = NULL;
-static const NSString *SerialNumber_ = nil;
-static const NSString *ChipID_ = nil;
-static const NSString *Token_ = nil;
-static const NSString *UniqueID_ = nil;
-static const NSString *Build_ = nil;
-static const NSString *Product_ = nil;
-static const NSString *Safari_ = nil;
+static NSString *System_ = nil;
+static NSString *SerialNumber_ = nil;
+static NSString *ChipID_ = nil;
+static NSString *Token_ = nil;
+static NSString *UniqueID_ = nil;
+static NSString *Build_ = nil;
+static NSString *Product_ = nil;
+static NSString *Safari_ = nil;
 
 static CFLocaleRef Locale_;
 static NSArray *Languages_;
@@ -1198,6 +1177,8 @@ bool isSectionVisible(NSString *section) {
     return hidden == nil || ![hidden boolValue];
 }
 
+@class Cydia;
+
 /* Delegate Prototypes {{{ */
 @class Package;
 @class Source;
@@ -1219,22 +1200,26 @@ bool isSectionVisible(NSString *section) {
 - (void) setConfigurationData:(NSString *)data;
 @end
 
-@class PackageView;
+@class PackageController;
 
 @protocol CydiaDelegate
-- (void) setPackageView:(PackageView *)view;
+- (void) setPackageController:(PackageController *)view;
 - (void) clearPackage:(Package *)package;
 - (void) installPackage:(Package *)package;
 - (void) installPackages:(NSArray *)packages;
 - (void) removePackage:(Package *)package;
+- (void) beginUpdate;
+- (BOOL) updating;
 - (void) distUpgrade;
+- (void) loadData;
 - (void) updateData;
 - (void) syncData;
-- (void) askForSettings;
+- (void) showSettings;
 - (UIProgressHUD *) addProgressHUD;
 - (void) removeProgressHUD:(UIProgressHUD *)hud;
-- (UIViewController *) pageForPackage:(NSString *)name;
-- (PackageView *) packageView;
+- (CYViewController *) pageForPackage:(NSString *)name;
+- (PackageController *) packageController;
+- (void) showActionSheet:(UIActionSheet *)sheet fromItem:(UIBarButtonItem *)item;
 @end
 /* }}} */
 
@@ -1425,7 +1410,7 @@ typedef std::map< unsigned long, _H<Source> > SourceMap;
 @end
 /* }}} */
 /* Delegate Helpers {{{ */
-@implementation NSObject(ProgressDelegate)
+@implementation NSObject (ProgressDelegate)
 
 - (void) _setProgressErrorPackage:(NSArray *)args {
     [self performSelector:@selector(setProgressError:forPackage:)
@@ -1450,8 +1435,11 @@ typedef std::map< unsigned long, _H<Source> > SourceMap;
 
 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id {
     Package *package = id == nil ? nil : [[Database sharedInstance] packageWithName:id];
-    // XXX: holy typecast batman!
-    [self setProgressError:error withTitle:(package == nil ? id : [package name])];
+    
+    [self performSelector:@selector(setProgressError:withTitle:)
+        withObject:error
+        withObject:(package == nil ? id : [package name])
+    ];
 }
 
 @end
@@ -2499,11 +2487,13 @@ struct PackageNameOrdering :
     UIImage *icon(nil);
     if (!icon_.empty())
         if ([icon_ hasPrefix:@"file:///"])
+            // XXX: correct escaping
             icon = [UIImage imageAtPath:[icon_ substringFromIndex:7]];
     if (icon == nil) if (section != nil)
         icon = [UIImage imageAtPath:[NSString stringWithFormat:@"%@/Sections/%@.png", App_, section]];
     if (icon == nil) if (source_ != nil) if (NSString *dicon = [source_ defaultIcon])
         if ([dicon hasPrefix:@"file:///"])
+            // XXX: correct escaping
             icon = [UIImage imageAtPath:[dicon substringFromIndex:7]];
     if (icon == nil)
         icon = [UIImage applicationImageNamed:@"unknown.png"];
@@ -3086,7 +3076,7 @@ static NSString *Warning_;
     return iterator.end() ? nil : [Package packageWithIterator:iterator withZone:NULL inPool:pool_ database:self];
 } }
 
-- (Database *) init {
+- (id) init {
     if ((self = [super init]) != nil) {
         policy_ = NULL;
         records_ = NULL;
@@ -3594,7 +3584,8 @@ static NSString *Warning_;
         return;
 
     if ([self popErrorWithTitle:title forOperation:ListUpdate(status, list, PulseInterval_)])
-        /* XXX: ignore this because users suck and don't understand why refreshing is important: return */;
+        /* XXX: ignore this because users suck and don't understand why refreshing is important: return */
+        /* XXX: why the hell is an empty if statement a clang error? */ (void) 0;
 
     [Metadata_ setObject:[NSDate date] forKey:@"LastUpdate"];
     Changed_ = true;
@@ -3614,7 +3605,7 @@ static NSString *Warning_;
 @end
 /* }}} */
 
-/* Confirmation View {{{ */
+/* Confirmation Controller {{{ */
 bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     if (!iterator.end())
         for (pkgCache::DepIterator dep(iterator.DependsList()); !dep.end(); ++dep) {
@@ -3865,7 +3856,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     id values[count];
     for (unsigned i(0); i != count; ++i)
         values[i] = [arguments objectAtIndex:i];
-    return [[[NSString alloc] initWithFormat:format arguments:reinterpret_cast<va_list>(values)] autorelease];
+    return [[[NSString alloc] initWithFormat:format arguments:*(reinterpret_cast<va_list *>(&values))] autorelease];
 }
 
 - (NSString *) localizedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)table {
@@ -3879,15 +3870,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 @end
 /* }}} */
 
-/* Cydia View Controller {{{ */
-@interface CYViewController : UCViewController { }
-@end
-
-@implementation CYViewController
-@end
-/* }}} */
-
-@interface CYBrowserController : BrowserView {
+/* Cydia Browser Controller {{{ */
+@interface CYBrowserController : BrowserController {
     CydiaObject *cydia_;
 }
 
@@ -3952,7 +3936,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (id) init {
-    if ((self = [super initWithWidth:[[self view] bounds].size.width ofClass:[CYBrowserController class]]) != nil) {
+    if ((self = [super initWithWidth:0 ofClass:[CYBrowserController class]]) != nil) {
         cydia_ = [[CydiaObject alloc] initWithDelegate:indirect_];
 
         WebView *webview([document_ webView]);
@@ -3976,14 +3960,16 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 @end
+/* }}} */
 
-@protocol ConfirmationViewDelegate
+/* Confirmation {{{ */
+@protocol ConfirmationControllerDelegate
 - (void) cancelAndClear:(bool)clear;
 - (void) confirmWithNavigationController:(UINavigationController *)navigation;
 - (void) queue;
 @end
 
-@interface ConfirmationView : CYBrowserController {
+@interface ConfirmationController : CYBrowserController {
     _transient Database *database_;
     UIAlertView *essential_;
     NSArray *changes_;
@@ -3996,7 +3982,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 @end
 
-@implementation ConfirmationView
+@implementation ConfirmationController
 
 - (void) dealloc {
     [changes_ release];
@@ -4008,22 +3994,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     [super dealloc];
 }
 
-- (void) actionSheet:(UIActionSheet *)sheet clickedButtonAtIndex:(NSInteger)button {
-    NSString *context([sheet context]);
-
-    if ([context isEqualToString:@"cancel"]) {
-        bool clear;
-
-        if      (button == [sheet cancelButtonIndex])      return;
-        else if (button == [sheet destructiveButtonIndex]) clear = true;
-        else                                               clear = false;
-        
-        [sheet dismissWithClickedButtonIndex:0xDEADBEEF animated:YES];
-        [self dismissModalViewControllerAnimated:YES];
-        [delegate_ cancelAndClear:clear];
-    }
-}
-
 - (void) alertView:(UIAlertView *)alert clickedButtonAtIndex:(NSInteger)button {
     NSString *context([alert context]);
 
@@ -4045,11 +4015,19 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     }
 }
 
+- (id) invokeDefaultMethodWithArguments:(NSArray *)args {
+    [self dismissModalViewControllerAnimated:YES];
+    [delegate_ cancelAndClear:NO];
+
+    return nil;
+}
+
 - (void) webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame {
     [super webView:sender didClearWindowObject:window forFrame:frame];
     [window setValue:changes_ forKey:@"changes"];
     [window setValue:issues_ forKey:@"issues"];
     [window setValue:sizes_ forKey:@"sizes"];
+    [window setValue:self forKey:@"queue"];
 }
 
 - (id) initWithDatabase:(Database *)database {
@@ -4140,7 +4118,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         [self loadURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"confirm" ofType:@"html"]]];
 
         UIBarButtonItem *leftItem = [[UIBarButtonItem alloc]
-            initWithTitle:[NSString stringWithFormat:UCLocalize("SLASH_DELIMITED"), UCLocalize("CANCEL"), UCLocalize("QUEUE")]
+            initWithTitle:UCLocalize("CANCEL")
+            // OLD: [NSString stringWithFormat:UCLocalize("SLASH_DELIMITED"), UCLocalize("CANCEL"), UCLocalize("QUEUE")]
             style:UIBarButtonItemStylePlain
             target:self
             action:@selector(cancelButtonClicked)
@@ -4150,7 +4129,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     } return self;
 }
 
-- (void) didFinishLoading {
+- (void) applyRightButton {
     UIBarButtonItem *rightItem = [[UIBarButtonItem alloc]
         initWithTitle:UCLocalize("CONFIRM")
         style:UIBarButtonItemStylePlain
@@ -4158,27 +4137,17 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         action:@selector(confirmButtonClicked)
     ];
 #if !AlwaysReload && !IgnoreInstall
-    if (issues_ == nil) [[self navigationItem] setRightBarButtonItem:rightItem];
-    else [[self navigationItem] setRightBarButtonItem:nil];
+    if (issues_ == nil && ![self isLoading]) [[self navigationItem] setRightBarButtonItem:rightItem];
+    else [super applyRightButton];
+#else
+    [[self navigationItem] setRightBarButtonItem:nil];
 #endif
     [rightItem release];
 }
 
 - (void) cancelButtonClicked {
-    UIActionSheet *sheet = [[UIActionSheet alloc]
-        initWithTitle:nil
-        delegate:self
-        cancelButtonTitle:nil
-        destructiveButtonTitle:nil
-        otherButtonTitles:nil
-    ];
-
-    [sheet addButtonWithTitle:UCLocalize("CANCEL_CLEAR")];
-    [sheet setDestructiveButtonIndex:[sheet numberOfButtons] - 1];
-    [sheet addButtonWithTitle:UCLocalize("CONTINUE_QUEUING")];
-    [sheet setContext:@"cancel"];
-
-    [delegate_ showActionSheet:[sheet autorelease] fromItem:[[self navigationItem] leftBarButtonItem]];
+    [self dismissModalViewControllerAnimated:YES];
+    [delegate_ cancelAndClear:YES];
 }
 
 #if !AlwaysReload
@@ -4237,8 +4206,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 @end
 /* }}} */
-/* Progress View {{{ */
-@interface ProgressView : CYViewController <
+/* Progress Controller {{{ */
+@interface ProgressController : CYViewController <
     ConfigurationDelegate,
     ProgressDelegate
 > {
@@ -4263,11 +4232,11 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 @end
 
-@protocol ProgressViewDelegate
-- (void) progressViewIsComplete:(ProgressView *)sender;
+@protocol ProgressControllerDelegate
+- (void) progressControllerIsComplete:(ProgressController *)sender;
 @end
 
-@implementation ProgressView
+@implementation ProgressController
 
 - (void) dealloc {
     [database_ setDelegate:nil];
@@ -4286,7 +4255,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         [database_ setDelegate:self];
         delegate_ = delegate;
 
-        [[self view] setBackgroundColor:(CGColor *)[UIColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:1.0f]];
+        [[self view] setBackgroundColor:[UIColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:1.0f]];
 
         progress_ = [[UIProgressBar alloc] init];
         [progress_ setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin)];
@@ -4332,7 +4301,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         (bounds.size.width - prgsize.width) / 2,
         bounds.size.height - prgsize.height - 64
     }, prgsize};
-    
+
     float closewidth = bounds.size.width - 20;
     if (closewidth > 300) closewidth = 300;
 
@@ -4360,8 +4329,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 - (void) viewWillAppear:(BOOL)animated {
     [super viewDidAppear:animated];
     [[self navigationItem] setHidesBackButton:YES];
-    [[[self navigationController] navigationBar] setBarStyle:1];
-    
+    [[[self navigationController] navigationBar] setBarStyle:UIBarStyleBlack];
+
     [self positionViews];
 }
 
@@ -4383,6 +4352,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 - (void) closeButtonPushed {
     running_ = NO;
 
+    UpdateExternalStatus(0);
+
     switch (Finish_) {
         case 0:
             [self dismissModalViewControllerAnimated:YES];
@@ -4418,7 +4389,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     [status_ removeFromSuperview];
 
     [database_ popErrorWithTitle:title_];
-    [delegate_ progressViewIsComplete:self];
+    [delegate_ progressControllerIsComplete:self];
 
     if (Finish_ < 4) {
         FileFd file;
@@ -4456,6 +4427,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
     system("su -c /usr/bin/uicache mobile");
 
+    UpdateExternalStatus(Finish_ == 0 ? 2 : 0);
+
     [delegate_ setStatusBarShowsProgress:NO];
 }
 
@@ -4467,6 +4440,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title {
+    UpdateExternalStatus(1);
+
     if (title_ != nil)
         [title_ release];
     if (title == nil)
@@ -4637,8 +4612,12 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 /* }}} */
 
 /* Cell Content View {{{ */
+@protocol ContentDelegate
+- (void) drawContentRect:(CGRect)rect;
+@end
+
 @interface ContentView : UIView {
-    _transient id delegate_;
+    _transient id<ContentDelegate> delegate_;
 }
 
 @end
@@ -4651,7 +4630,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     } return self;
 }
 
-- (void) setDelegate:(id)delegate {
+- (void) setDelegate:(id<ContentDelegate>)delegate {
     delegate_ = delegate;
 }
 
@@ -4662,7 +4641,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 @end
 /* }}} */
 /* Package Cell {{{ */
-@interface PackageCell : UITableViewCell {
+@interface PackageCell : UITableViewCell <
+    ContentDelegate
+> {
     UIImage *icon_;
     NSString *name_;
     NSString *description_;
@@ -4853,12 +4834,12 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
     if (!selected)
         UISetColor(commercial_ ? Purple_ : Black_);
-    [name_ drawAtPoint:CGPointMake(48, 8) forWidth:(width - (placard_ == nil ? 80 : 106)) withFont:Font18Bold_ ellipsis:2];
-    [source_ drawAtPoint:CGPointMake(58, 29) forWidth:(width - 95) withFont:Font12_ ellipsis:2];
+    [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];
 
     if (!selected)
         UISetColor(commercial_ ? Purplish_ : Gray_);
-    [description_ drawAtPoint:CGPointMake(12, 46) forWidth:(width - 46) withFont:Font14_ ellipsis:2];
+    [description_ drawAtPoint:CGPointMake(12, 46) forWidth:(width - 46) withFont:Font14_ lineBreakMode:UILineBreakModeTailTruncation];
 
     if (placard_ != nil)
         [placard_ drawAtPoint:CGPointMake(width - 52, 9)];
@@ -4877,7 +4858,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 @end
 /* }}} */
 /* Section Cell {{{ */
-@interface SectionCell : UITableViewCell {
+@interface SectionCell : UITableViewCell <
+    ContentDelegate
+> {
     NSString *basic_;
     NSString *section_;
     NSString *name_;
@@ -4888,7 +4871,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     BOOL editing_;
 }
 
-- (id) init;
 - (void) setSection:(Section *)section editing:(BOOL)editing;
 
 @end
@@ -4985,7 +4967,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
             [switch_ setOn:(isSectionVisible(basic_) ? 1 : 0) animated:NO];
     }
 
-    [self setAccessoryType:editing ? 0 : 1 /*UITableViewCellAccessoryDisclosureIndicator*/];
+    [self setAccessoryType:editing ? UITableViewCellAccessoryNone : UITableViewCellAccessoryDisclosureIndicator];
     [content_ setNeedsDisplay];
 }
 
@@ -4998,7 +4980,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 - (void) drawContentRect:(CGRect)rect {
     BOOL selected = [self isSelected];
-    
+
     [icon_ drawInRect:CGRectMake(8, 7, 32, 32)];
 
     if (selected)
@@ -5011,7 +4993,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     if (editing_)
         width -= 87;
 
-    [name_ drawAtPoint:CGPointMake(48, 9) forWidth:(width - 70) withFont:Font22Bold_ ellipsis:2];
+    [name_ drawAtPoint:CGPointMake(48, 9) forWidth:(width - 70) withFont:Font22Bold_ lineBreakMode:UILineBreakModeTailTruncation];
 
     CGSize size = [count_ sizeWithFont:Font14_];
 
@@ -5024,7 +5006,10 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 /* }}} */
 
 /* File Table {{{ */
-@interface FileTable : CYViewController {
+@interface FileTable : CYViewController <
+    UITableViewDataSource,
+    UITableViewDelegate
+> {
     _transient Database *database_;
     Package *package_;
     NSString *name_;
@@ -5049,13 +5034,13 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     [super dealloc];
 }
 
-- (int) tableView:(UITableView *)tableView numberOfRowsInSection:(int)section {
+- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
     return files_ == nil ? 0 : [files_ count];
 }
 
-- (float) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
-    return 24;
-}
+/*- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
+    return 24.0f;
+}*/
 
 - (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
     static NSString *reuseIdentifier = @"Cell";
@@ -5066,7 +5051,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         [cell setFont:[UIFont systemFontOfSize:16]];
     }
     [cell setText:[files_ objectAtIndex:indexPath.row]];
-    [cell setSelectionStyle:0 /*UITableViewCellSelectionStyleNone*/];
+    [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
 
     return cell;
 }
@@ -5080,6 +5065,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         files_ = [[NSMutableArray arrayWithCapacity:32] retain];
 
         list_ = [[UITableView alloc] initWithFrame:[[self view] bounds]];
+        [list_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth];
+        [list_ setRowHeight:24.0f];
         [[self view] addSubview:list_];
 
         [list_ setDataSource:self];
@@ -5138,8 +5125,10 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 @end
 /* }}} */
-/* Package View {{{ */
-@interface PackageView : CYBrowserController {
+/* Package Controller {{{ */
+@interface PackageController : CYBrowserController <
+    UIActionSheetDelegate
+> {
     _transient Database *database_;
     Package *package_;
     NSString *name_;
@@ -5152,7 +5141,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 @end
 
-@implementation PackageView
+@implementation PackageController
 
 - (void) dealloc {
     if (package_ != nil)
@@ -5165,7 +5154,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 - (void) release {
     if ([self retainCount] == 1)
-        [delegate_ setPackageView:self];
+        [delegate_ setPackageController:self];
     [super release];
 }
 
@@ -5192,10 +5181,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
             NSString *buttonName = [buttons_ objectAtIndex:button];
             [self _clickButtonWithName:buttonName];
         }
-        
+
         [sheet dismissWithClickedButtonIndex:-1 animated:YES];
-    } else {
-        [super alertSheet:sheet clickedButtonAtIndex:button];
     }
 }
 
@@ -5213,7 +5200,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 #if !AlwaysReload
-- (void) _actionButtonClicked {
+- (void) _customButtonClicked {
     int count([buttons_ count]);
     if (count == 0)
         return;
@@ -5238,16 +5225,36 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
            [sheet setCancelButtonIndex:[sheet numberOfButtons] - 1];
         }
         [sheet setContext:@"modify"];
-    
+
         [delegate_ showActionSheet:sheet fromItem:[[self navigationItem] rightBarButtonItem]];
     }
 }
 
-- (void) actionButtonClicked {
-    if (commercial_ && [self isLoading])
-        [super _rightButtonClicked];
+// 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 _actionButtonClicked];
+        [self _customButtonClicked];
+}
+
+- (void) reloadButtonClicked {
+    // Don't reload a package view by clicking the button.
+}
+
+- (void) applyLoadingTitle {
+    // Don't show "Loading" as the title. Ever.
+}
+
+- (UIBarButtonItem *) rightButton {
+    int count = [buttons_ count];
+    return [[[UIBarButtonItem alloc]
+        initWithTitle:count == 0 ? nil : count != 1 ? UCLocalize("MODIFY") : [buttons_ objectAtIndex:0]
+        style:UIBarButtonItemStylePlain
+        target:self
+        action:@selector(customButtonClicked)
+    ] autorelease];
 }
 #endif
 
@@ -5293,7 +5300,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
         if (special_ != NULL) {
             CGRect frame([document_ frame]);
-            frame.size.width = 320;
             frame.size.height = 0;
             [document_ setFrame:frame];
 
@@ -5317,18 +5323,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     }
 }
 
-- (void) didFinishLoading {
-    int count = [buttons_ count];
-    UIBarButtonItem *actionItem = [[UIBarButtonItem alloc]
-        initWithTitle:count == 0 ? nil : count != 1 ? UCLocalize("MODIFY") : [buttons_ objectAtIndex:0]
-        style:UIBarButtonItemStylePlain
-        target:self
-        action:@selector(actionButtonClicked)
-    ];
-    [[self navigationItem] setRightBarButtonItem:actionItem];
-    [actionItem release];
-}
-
 - (bool) isLoading {
     return commercial_ ? [super isLoading] : false;
 }
@@ -5340,7 +5334,10 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 @end
 /* }}} */
 /* Package Table {{{ */
-@interface PackageTable : UIView {
+@interface PackageTable : UIView <
+    UITableViewDataSource,
+    UITableViewDelegate
+> {
     _transient Database *database_;
     NSMutableArray *packages_;
     NSMutableArray *sections_;
@@ -5404,7 +5401,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (UITableViewCell *) tableView:(UITableView *)table cellForRowAtIndexPath:(NSIndexPath *)path {
-    PackageCell *cell([table dequeueReusableCellWithIdentifier:@"Package"]);
+    PackageCell *cell((PackageCell *) [table dequeueReusableCellWithIdentifier:@"Package"]);
     if (cell == nil)
         cell = [[[PackageCell alloc] init] autorelease];
     [cell setPackage:[self packageAtIndexPath:path]];
@@ -5415,10 +5412,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     [list_ deselectRowAtIndexPath:[list_ indexPathForSelectedRow] animated:animated];
 }
 
-- (CGFloat) tableView:(UITableView *)table heightForRowAtIndexPath:(NSIndexPath *)path {
-    return 73;
+/*- (CGFloat) tableView:(UITableView *)table heightForRowAtIndexPath:(NSIndexPath *)path {
     return [PackageCell heightForPackage:[self packageAtIndexPath:path]];
-}
+}*/
 
 - (NSIndexPath *) tableView:(UITableView *)table willSelectRowAtIndexPath:(NSIndexPath *)path {
     Package *package([self packageAtIndexPath:path]);
@@ -5450,6 +5446,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
         list_ = [[UITableView alloc] initWithFrame:[self bounds] style:UITableViewStylePlain];
         [list_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth];
+        [list_ setRowHeight:73.0f];
         [self addSubview:list_];
 
         [list_ setDataSource:self];
@@ -5591,8 +5588,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 @end
 /* }}} */
 
-/* Filtered Package View {{{ */
-@interface FilteredPackageView : CYViewController {
+/* Filtered Package Controller {{{ */
+@interface FilteredPackageController : CYViewController {
     _transient Database *database_;
     FilteredPackageTable *packages_;
     NSString *title_;
@@ -5601,13 +5598,13 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 - (id) initWithDatabase:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object;
 
 @end
-    
-@implementation FilteredPackageView
+
+@implementation FilteredPackageController
 
 - (void) dealloc {
     [packages_ release];
     [title_ release];
-    
+
     [super dealloc];
 }
 
@@ -5617,13 +5614,13 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (void) didSelectPackage:(Package *)package {
-    PackageView *view([delegate_ packageView]);
+    PackageController *view([delegate_ packageController]);
     [view setPackage:package];
     [view setDelegate:delegate_];
     [[self navigationController] pushViewController:view animated:YES];
 }
 
-- (id) title { return title_; }
+- (NSString *) title { return title_; }
 
 - (id) initWithDatabase:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object {
     if ((self = [super init]) != nil) {
@@ -5655,11 +5652,11 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 @end
-    
+
 /* }}} */
 
-/* Add Source View {{{ */
-@interface AddSourceView : CYViewController {
+/* Add Source Controller {{{ */
+@interface AddSourceController : CYViewController {
     _transient Database *database_;
 }
 
@@ -5667,7 +5664,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 @end
 
-@implementation AddSourceView
+@implementation AddSourceController
 
 - (id) initWithDatabase:(Database *)database {
     if ((self = [super init]) != nil) {
@@ -5678,7 +5675,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 @end
 /* }}} */
 /* Source Cell {{{ */
-@interface SourceCell : UITableViewCell {
+@interface SourceCell : UITableViewCell <
+    ContentDelegate
+> {
     UIImage *icon_;
     NSString *origin_;
     NSString *description_;
@@ -5706,7 +5705,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 - (void) setSource:(Source *)source {
     [self clearSource];
-    
+
     if (icon_ == nil)
         icon_ = [UIImage applicationImageNamed:[NSString stringWithFormat:@"Sources/%@.png", [source host]]];
     if (icon_ == nil)
@@ -5758,21 +5757,24 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
     if (!selected)
         UISetColor(Black_);
-    [origin_ drawAtPoint:CGPointMake(48, 8) forWidth:(width - 80) withFont:Font18Bold_ ellipsis:2];
+    [origin_ drawAtPoint:CGPointMake(48, 8) forWidth:(width - 80) withFont:Font18Bold_ lineBreakMode:UILineBreakModeTailTruncation];
 
     if (!selected)
         UISetColor(Blue_);
-    [label_ drawAtPoint:CGPointMake(58, 29) forWidth:(width - 95) withFont:Font12_ ellipsis:2];
+    [label_ drawAtPoint:CGPointMake(58, 29) forWidth:(width - 95) withFont:Font12_ lineBreakMode:UILineBreakModeTailTruncation];
 
     if (!selected)
         UISetColor(Gray_);
-    [description_ drawAtPoint:CGPointMake(12, 46) forWidth:(width - 40) withFont:Font14_ ellipsis:2];
+    [description_ drawAtPoint:CGPointMake(12, 46) forWidth:(width - 40) withFont:Font14_ lineBreakMode:UILineBreakModeTailTruncation];
 }
 
 @end
 /* }}} */
 /* Source Table {{{ */
-@interface SourceTable : CYViewController {
+@interface SourceTable : CYViewController <
+    UITableViewDataSource,
+    UITableViewDelegate
+> {
     _transient Database *database_;
     UITableView *list_;
     NSMutableArray *sources_;
@@ -5793,6 +5795,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 - (id) initWithDatabase:(Database *)database;
 
+- (void) updateButtonsForEditingStatus:(BOOL)editing animated:(BOOL)animated;
+
 @end
 
 @implementation SourceTable
@@ -5829,11 +5833,11 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     [list_ deselectRowAtIndexPath:[list_ indexPathForSelectedRow] animated:animated];
 }
 
-- (int) numberOfSectionsInTableView:(UITableView *)tableView {
+- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView {
     return offset_ == 0 ? 1 : 2;
 }
 
-- (NSString *) tableView:(UITableView *)tableView titleForHeaderInSection:(int)section {
+- (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");
@@ -5842,7 +5846,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     }
 }
 
-- (int) tableView:(UITableView *)tableView numberOfRowsInSection:(int)section {
+- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
     int count = [sources_ count];
     switch (section) {
         case 0: return (offset_ == 0 ? count : offset_);
@@ -5874,18 +5878,18 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     SourceCell *cell = (SourceCell *) [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
     if(cell == nil) cell = [[[SourceCell alloc] initWithFrame:CGRectZero reuseIdentifier:cellIdentifier] autorelease];
     [cell setSource:[self sourceAtIndexPath:indexPath]];
-    
+
     return cell;
 }
 
-- (int) tableView:(UITableView *)tableView accessoryTypeForRowWithIndexPath:(NSIndexPath *)indexPath {
-    return 1; //UITableViewCellAccessoryDisclosureIndicator?
+- (UITableViewCellAccessoryType) tableView:(UITableView *)tableView accessoryTypeForRowWithIndexPath:(NSIndexPath *)indexPath {
+    return UITableViewCellAccessoryDisclosureIndicator;
 }
 
 - (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
     Source *source = [self sourceAtIndexPath:indexPath];
 
-    FilteredPackageView *packages = [[[FilteredPackageView alloc]
+    FilteredPackageController *packages = [[[FilteredPackageController alloc]
         initWithDatabase:database_
         title:[source label]
         filter:@selector(isVisibleInSource:)
@@ -6033,7 +6037,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     [self _endConnection:connection];
 }
 
-- (id)title { return UCLocalize("SOURCES"); }
+- (NSString *) title { return UCLocalize("SOURCES"); }
 
 - (NSURLConnection *) _requestHRef:(NSString *)href method:(NSString *)method {
     NSMutableURLRequest *request = [NSMutableURLRequest
@@ -6115,7 +6119,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     if ((self = [super init]) != nil) {
         [[self navigationItem] setTitle:UCLocalize("SOURCES")];
         [self updateButtonsForEditingStatus:NO animated:NO];
-    
+
         database_ = database;
         sources_ = [[NSMutableArray arrayWithCapacity:16] retain];
 
@@ -6154,7 +6158,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (void) addButtonClicked {
-    /*[book_ pushPage:[[[AddSourceView alloc]
+    /*[book_ pushPage:[[[AddSourceController alloc]
         initWithBook:book_
         database:database_
     ] autorelease]];*/
@@ -6201,33 +6205,51 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     ];
     [[self navigationItem] setRightBarButtonItem:rightItem animated:animated];
     [rightItem release];
+
+    if (IsWildcat_ && !editing) {
+        UIBarButtonItem *settingsItem = [[UIBarButtonItem alloc]
+            initWithTitle:UCLocalize("SETTINGS")
+            style:UIBarButtonItemStylePlain
+            target:self
+            action:@selector(settingsButtonClicked)
+            ];
+        [[self navigationItem] setLeftBarButtonItem:settingsItem];
+        [settingsItem release];
+    }
+}
+
+- (void) settingsButtonClicked {
+    [delegate_ showSettings];
 }
 
 - (void) editButtonClicked {
     [list_ setEditing:![list_ isEditing] animated:YES];
-    
+
     [self updateButtonsForEditingStatus:[list_ isEditing] animated:YES];
 }
 
 @end
 /* }}} */
 
-/* Installed View {{{ */
-@interface InstalledView : FilteredPackageView {
+/* Installed Controller {{{ */
+@interface InstalledController : FilteredPackageController {
     BOOL expert_;
 }
 
 - (id) initWithDatabase:(Database *)database;
 
+- (void) updateRoleButton;
+- (void) queueStatusDidChange;
+
 @end
 
-@implementation InstalledView
+@implementation InstalledController
 
 - (void) dealloc {
     [super dealloc];
 }
 
-- (id) title { return UCLocalize("INSTALLED"); }
+- (NSString *) title { return UCLocalize("INSTALLED"); }
 
 - (id) initWithDatabase:(Database *)database {
     if ((self = [super initWithDatabase:database title:UCLocalize("INSTALLED") filter:@selector(isInstalledAndVisible:) with:[NSNumber numberWithBool:YES]]) != nil) {
@@ -6289,13 +6311,13 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 @end
 /* }}} */
 
-/* Home View {{{ */
-@interface HomeView : CYBrowserController {
+/* Home Controller {{{ */
+@interface HomeController : CYBrowserController {
 }
 
 @end
 
-@implementation HomeView
+@implementation HomeController
 
 - (void) _setMoreHeaders:(NSMutableURLRequest *)request {
     [super _setMoreHeaders:request];
@@ -6346,18 +6368,19 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 @end
 /* }}} */
-/* Manage View {{{ */
-@interface ManageView : CYBrowserController {
+/* Manage Controller {{{ */
+@interface ManageController : CYBrowserController {
 }
 
+- (void) queueStatusDidChange;
 @end
 
-@implementation ManageView
+@implementation ManageController
 
 - (id) init {
     if ((self = [super init]) != nil) {
         [[self navigationItem] setTitle:UCLocalize("MANAGE")];
-    
+
         UIBarButtonItem *settingsItem = [[UIBarButtonItem alloc]
             initWithTitle:UCLocalize("SETTINGS")
             style:UIBarButtonItemStylePlain
@@ -6366,25 +6389,28 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         ];
         [[self navigationItem] setLeftBarButtonItem:settingsItem];
         [settingsItem release];
-    
+
         [self queueStatusDidChange];
     } return self;
 }
 
 - (void) settingsButtonClicked {
-    [delegate_ askForSettings];
-    [delegate_ updateData];
+    [delegate_ showSettings];
 }
 
 #if !AlwaysReload
 - (void) queueButtonClicked {
     [delegate_ queue];
 }
-#endif
 
-- (void) didFinishLoading {
-    [self queueStatusDidChange];
+- (void) applyLoadingTitle {
+    // No "Loading" title.
+}
+
+- (void) applyRightButton {
+    // No right button.
 }
+#endif
 
 - (void) queueStatusDidChange {
 #if !AlwaysReload
@@ -6396,7 +6422,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
             action:@selector(queueButtonClicked)
         ];
         [[self navigationItem] setRightBarButtonItem:queueItem];
-        
+
         [queueItem release];
     } else {
         [[self navigationItem] setRightBarButtonItem:nil];
@@ -6423,70 +6449,74 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 @implementation RefreshBar
 
+- (void) positionViews {
+    CGRect frame = [cancel_ frame];
+    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])) {
         [self setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
 
         [self setTintColor:[UIColor colorWithRed:0.23 green:0.23 blue:0.23 alpha:1]];
-        [self setBarStyle:1];
+        [self setBarStyle:UIBarStyleBlack];
 
-        int barstyle([self _barStyle:NO]);
-        bool ugly(barstyle == 0);
+        UIBarStyle barstyle([self _barStyle:NO]);
+        bool ugly(barstyle == UIBarStyleDefault);
 
         UIProgressIndicatorStyle style = ugly ?
             UIProgressIndicatorStyleMediumBrown :
             UIProgressIndicatorStyleMediumWhite;
 
-        CGSize indsize([UIProgressIndicator defaultSizeForStyle:style]);
-        unsigned indoffset = ([self frame].size.height - indsize.height) / 2;
-        CGRect indrect = {{indoffset, indoffset}, indsize};
-
-        indicator_ = [[UIProgressIndicator alloc] initWithFrame:indrect];
+        indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectZero];
         [indicator_ setStyle:style];
+        [indicator_ startAnimation];
         [self addSubview:indicator_];
 
-        CGSize prmsize = {215, indsize.height + 4};
-
-        CGRect prmrect = {{
-            indoffset * 2 + indsize.width,
-            unsigned([self frame].size.height - prmsize.height) / 2 - 1
-        }, prmsize};
-
-        UIFont *font([UIFont systemFontOfSize:15]);
-
-        prompt_ = [[UITextLabel alloc] initWithFrame:prmrect];
-
+        prompt_ = [[UITextLabel alloc] initWithFrame:CGRectZero];
         [prompt_ setColor:[UIColor colorWithCGColor:(ugly ? Blueish_ : Off_)]];
         [prompt_ setBackgroundColor:[UIColor clearColor]];
-        [prompt_ setFont:font];
-
+        [prompt_ setFont:[UIFont systemFontOfSize:15]];
         [self addSubview:prompt_];
 
-        CGSize prgsize = {75, 100};
-
-        CGRect prgrect = {{
-            [self frame].size.width - prgsize.width - 10,
-            ([self frame].size.height - prgsize.height) / 2
-        } , prgsize};
-
-        progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
-        [progress_ setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
-        [self addSubview:progress_];
-
+        progress_ = [[UIProgressBar alloc] initWithFrame:CGRectZero];
+        [progress_ setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleLeftMargin];
         [progress_ setStyle:0];
+        [self addSubview:progress_];
 
         cancel_ = [[UINavigationButton alloc] initWithTitle:UCLocalize("CANCEL") style:UINavigationButtonStyleHighlighted];
-        [progress_ setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin];
+        [cancel_ setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin];
         [cancel_ addTarget:delegate action:@selector(cancelPressed) forControlEvents:UIControlEventTouchUpInside];
+        [cancel_ setBarStyle:barstyle];
 
-        CGRect frame = [cancel_ frame];
-        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];
-
-        [cancel_ setBarStyle:barstyle];    
-
-        [indicator_ startAnimation];
+        [self positionViews];
     } return self;
 }
 
@@ -6515,229 +6545,74 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 @end
 /* }}} */
 
-/* Cydia Tab Bar Controller {{{ */
-@interface CYTabBarController : UITabBarController <
-    ProgressDelegate
-> {
-    _transient Database *database_;
-    RefreshBar *refreshbar_;
+@class CYNavigationController;
 
-    bool dropped_;
-    bool updating_;
-    id updatedelegate_;
+/* Cydia Tab Bar Controller {{{ */
+@interface CYTabBarController : UITabBarController {
+    Database *database_;
 }
 
-- (id) initWithDatabase:(Database *)database;
-- (void) setDelegate:(id)delegate;
-
-@end    
+@end
 
 @implementation CYTabBarController
 
-- (void) viewDidDisappear:(BOOL)animated {
-    [super viewDidDisappear:animated];
-        
-    if (updating_) [self raiseBar:NO];
-}
+/* XXX: some logic should probably go here related to
+freeing the view controllers on tab change */
 
-- (void) viewDidAppear:(BOOL)animated {
-    [super viewDidAppear:animated];
-    
-    if (updating_) [self dropBar:NO];
+- (void) reloadData {
+    size_t count([[self viewControllers] count]);
+    for (size_t i(0); i != count; ++i) {
+        CYNavigationController *page([[self viewControllers] objectAtIndex:(count - i - 1)]);
+        [page reloadData];
+    }
 }
 
-- (void) setUpdate:(NSDate *)date {
-    [self beginUpdate];
+- (id) initWithDatabase:(Database *)database {
+    if ((self = [super init]) != nil) {
+        database_ = database;
+    } return self;
 }
 
-- (void) beginUpdate {
-    [self dropBar:YES];
-    [refreshbar_ start];
-    
-    updating_ = true;
-    
-    [NSThread
-        detachNewThreadSelector:@selector(performUpdate)
-        toTarget:self
-        withObject:nil
-    ];
+@end
+/* }}} */
+
+/* Cydia Navigation Controller {{{ */
+@interface CYNavigationController : UINavigationController {
+    _transient Database *database_;
+    id<UINavigationControllerDelegate> delegate_;
 }
 
-- (void) performUpdate { _pooled
-    Status status;
-    status.setDelegate(self);
-    [database_ updateWithStatus:status];
+- (id) initWithDatabase:(Database *)database;
+- (void) reloadData;
 
-    [self
-        performSelectorOnMainThread:@selector(completeUpdate)
-        withObject:nil
-        waitUntilDone:NO
-    ];
+@end
+
+
+@implementation CYNavigationController
+
+- (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orientation {
+    // Inherit autorotation settings for modal parents.
+    if ([self parentViewController] && [[self parentViewController] modalViewController] == self) {
+        return [[self parentViewController] shouldAutorotateToInterfaceOrientation:orientation];
+    } else {
+        return [super shouldAutorotateToInterfaceOrientation:orientation];
+    }
 }
 
-- (void) completeUpdate {
-    updating_ = false;
-    
-    [self raiseBar:YES];
-    [refreshbar_ stop];
-    [updatedelegate_ performSelector:@selector(reloadData) withObject:nil afterDelay:0];
+- (void) dealloc {
+    [super dealloc];
 }
 
-- (void) cancelUpdate {
-    [refreshbar_ cancel];
-    [self completeUpdate];
+- (void) reloadData {
+    size_t count([[self viewControllers] count]);
+    for (size_t i(0); i != count; ++i) {
+        CYViewController *page([[self viewControllers] objectAtIndex:(count - i - 1)]);
+        [page reloadData];
+    }
 }
 
-- (void) cancelPressed {
-    [self cancelUpdate];
-}
-
-- (BOOL) updating {
-    return updating_;
-}
-
-- (void) setProgressError:(NSString *)error withTitle:(NSString *)title {
-    [refreshbar_ setPrompt:[NSString stringWithFormat:UCLocalize("COLON_DELIMITED"), UCLocalize("ERROR"), error]];
-}
-
-- (void) startProgress {
-}
-
-- (void) setProgressTitle:(NSString *)title {
-    [self
-        performSelectorOnMainThread:@selector(_setProgressTitle:)
-        withObject:title
-        waitUntilDone:YES
-    ];
-}
-
-- (bool) isCancelling:(size_t)received {
-    return !updating_;
-}
-
-- (void) setProgressPercent:(float)percent {
-    [self
-        performSelectorOnMainThread:@selector(_setProgressPercent:)
-        withObject:[NSNumber numberWithFloat:percent]
-        waitUntilDone:YES
-    ];
-}
-
-- (void) addProgressOutput:(NSString *)output {
-    [self
-        performSelectorOnMainThread:@selector(_addProgressOutput:)
-        withObject:output
-        waitUntilDone:YES
-    ];
-}
-
-- (void) _setProgressTitle:(NSString *)title {
-    [refreshbar_ setPrompt:title];
-}
-
-- (void) _setProgressPercent:(NSNumber *)percent {
-    [refreshbar_ setProgress:[percent floatValue]];
-}
-
-- (void) _addProgressOutput:(NSString *)output {
-}
-
-- (void) reloadData {
-    size_t count([[self viewControllers] count]);
-    for (size_t i(0); i != count; ++i) {
-        UIViewController *page([[self viewControllers] objectAtIndex:(count - i - 1)]);
-        [page reloadData];
-    }
-}
-
-- (void) setUpdateDelegate:(id)delegate {
-    updatedelegate_ = delegate;
-}
-
-- (void) dropBar:(BOOL)animated {
-    if (dropped_)
-        return;
-    dropped_ = true;
-
-    [[[self view] superview] addSubview:refreshbar_];
-
-    if (animated) [UIView beginAnimations:nil context:NULL];
-    CGRect barframe = [refreshbar_ frame];
-    CGRect viewframe = [[self view] frame];
-    viewframe.origin.y += barframe.size.height + 20.0f;
-    viewframe.size.height -= barframe.size.height + 20.0f;
-    [[self view] setFrame:viewframe];
-    if (animated) [UIView commitAnimations];
-
-    // XXX: fix Apple's layout bug
-    [[self selectedViewController] _updateLayoutForStatusBarAndInterfaceOrientation];
-}
-
-- (void) raiseBar:(BOOL)animated {
-    if (!dropped_)
-        return;
-    dropped_ = false;
-
-    [refreshbar_ removeFromSuperview];
-
-    if (animated) [UIView beginAnimations:nil context:NULL];
-    CGRect barframe = [refreshbar_ frame];
-    CGRect viewframe = [[self view] frame];
-    viewframe.origin.y -= barframe.size.height + 20.0f;
-    viewframe.size.height += barframe.size.height + 20.0f;
-    [[self view] setFrame:viewframe];
-    if (animated) [UIView commitAnimations];
-
-    // XXX: fix Apple's layout bug
-    [[self selectedViewController] _updateLayoutForStatusBarAndInterfaceOrientation];
-}
-
-- (void) dealloc {
-    [refreshbar_ release];
-    [super dealloc];
-}
-
-- (id) initWithDatabase: (Database *)database {
-    if ((self = [super init]) != nil) {
-        database_ = database;
-
-        refreshbar_ = [[RefreshBar alloc] initWithFrame:CGRectMake(0, 20.0f, [[self view] frame].size.width, [UINavigationBar defaultSize].height) delegate:self];
-    } return self;
-}
-
-@end
-/* }}} */
-
-/* Cydia Navigation Controller {{{ */
-@interface CYNavigationController : UINavigationController <
-    ProgressDelegate
-> {
-    _transient Database *database_;
-    id delegate_;
-}
-
-- (id) initWithDatabase:(Database *)database;
-- (void) reloadData;
-
-@end
-
-
-@implementation CYNavigationController
-
-- (void) dealloc {
-    [super dealloc];
-}
-
-- (void) reloadData {
-    size_t count([[self viewControllers] count]);
-    for (size_t i(0); i != count; ++i) {
-        UIViewController *page([[self viewControllers] objectAtIndex:(count - i - 1)]);
-        [page reloadData];
-    }
-}
-
-- (void) setDelegate:(id)delegate {
-    delegate_ = delegate;
+- (void) setDelegate:(id<UINavigationControllerDelegate>)delegate {
+    delegate_ = delegate;
 }
 
 - (id) initWithDatabase:(Database *)database {
@@ -6849,8 +6724,11 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 @end
 /* }}} */
 
-/* Sections View {{{ */
-@interface SectionsView : CYViewController {
+/* Sections Controller {{{ */
+@interface SectionsController : CYViewController <
+    UITableViewDataSource,
+    UITableViewDelegate
+> {
     _transient Database *database_;
     NSMutableArray *sections_;
     NSMutableArray *filtered_;
@@ -6863,9 +6741,11 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 - (void) reloadData;
 - (void) resetView;
 
+- (void) editButtonClicked;
+
 @end
 
-@implementation SectionsView
+@implementation SectionsController
 
 - (void) dealloc {
     [list_ setDataSource:nil];
@@ -6888,13 +6768,13 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     return section;
 }
 
-- (int) tableView:(UITableView *)tableView numberOfRowsInSection:(int)section {
+- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
     return editing_ ? [sections_ count] : [filtered_ count] + 1;
 }
 
-- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
-    return 45;
-}
+/*- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
+    return 45.0f;
+}*/
 
 - (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
     static NSString *reuseIdentifier = @"SectionCell";
@@ -6925,7 +6805,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         }
     }
 
-    FilteredPackageView *table = [[[FilteredPackageView alloc]
+    FilteredPackageController *table = [[[FilteredPackageController alloc]
         initWithDatabase:database_
         title:title
         filter:@selector(isVisibleInSection:)
@@ -6937,7 +6817,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     [[self navigationController] pushViewController:table animated:YES];
 }
 
-- (id) title { return UCLocalize("SECTIONS"); }
+- (NSString *) title { return UCLocalize("SECTIONS"); }
 
 - (id) initWithDatabase:(Database *)database {
     if ((self = [super init]) != nil) {
@@ -6950,6 +6830,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
         list_ = [[UITableView alloc] initWithFrame:[[self view] bounds]];
         [list_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth];
+        [list_ setRowHeight:45.0f];
         [[self view] addSubview:list_];
 
         [list_ setDataSource:self];
@@ -7048,7 +6929,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         target:self
         action:@selector(editButtonClicked)
     ];
-    [[self navigationItem] setRightBarButtonItem:rightItem];
+    [[self navigationItem] setRightBarButtonItem:rightItem animated:[[self navigationItem] rightBarButtonItem] != nil];
     [rightItem release];
 
     [list_ reloadData];
@@ -7065,7 +6946,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         [list_ reloadData];
     else
         [delegate_ updateData];
-    
+
     [[self navigationItem] setTitle:editing_ ? UCLocalize("SECTION_VISIBILITY") : UCLocalize("SECTIONS")];
     [[[self navigationItem] rightBarButtonItem] setTitle:[sections_ count] == 0 ? nil : editing_ ? UCLocalize("DONE") : UCLocalize("EDIT")];
     [[[self navigationItem] rightBarButtonItem] setStyle:editing_ ? UIBarButtonItemStyleDone : UIBarButtonItemStylePlain];
@@ -7077,13 +6958,17 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 @end
 /* }}} */
-/* Changes View {{{ */
-@interface ChangesView : CYViewController {
+/* Changes Controller {{{ */
+@interface ChangesController : CYViewController <
+    UITableViewDataSource,
+    UITableViewDelegate
+> {
     _transient Database *database_;
     NSMutableArray *packages_;
     NSMutableArray *sections_;
     UITableView *list_;
     unsigned upgrades_;
+    BOOL hasSentFirstLoad_;
 }
 
 - (id) initWithDatabase:(Database *)database delegate:(id)delegate;
@@ -7091,7 +6976,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 @end
 
-@implementation ChangesView
+@implementation ChangesController
 
 - (void) dealloc {
     [list_ setDelegate:nil];
@@ -7105,7 +6990,12 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 - (void) viewDidAppear:(BOOL)animated {
     [super viewDidAppear:animated];
-    [list_ deselectRowAtIndexPath:[list_ indexPathForSelectedRow] animated:animated];
+    if (!hasSentFirstLoad_) {
+        hasSentFirstLoad_ = YES;
+        [self performSelector:@selector(reloadData) withObject:nil afterDelay:0.0];
+    } else {
+        [list_ deselectRowAtIndexPath:[list_ indexPathForSelectedRow] animated:animated];
+    }
 }
 
 - (NSInteger) numberOfSectionsInTableView:(UITableView *)list {
@@ -7132,21 +7022,20 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (UITableViewCell *) tableView:(UITableView *)table cellForRowAtIndexPath:(NSIndexPath *)path {
-    PackageCell *cell([table dequeueReusableCellWithIdentifier:@"Package"]);
+    PackageCell *cell((PackageCell *) [table dequeueReusableCellWithIdentifier:@"Package"]);
     if (cell == nil)
         cell = [[[PackageCell alloc] init] autorelease];
     [cell setPackage:[self packageAtIndexPath:path]];
     return cell;
 }
 
-- (CGFloat) tableView:(UITableView *)table heightForRowAtIndexPath:(NSIndexPath *)path {
-    return 73;
+/*- (CGFloat) tableView:(UITableView *)table heightForRowAtIndexPath:(NSIndexPath *)path {
     return [PackageCell heightForPackage:[self packageAtIndexPath:path]];
-}
+}*/
 
 - (NSIndexPath *) tableView:(UITableView *)table willSelectRowAtIndexPath:(NSIndexPath *)path {
     Package *package([self packageAtIndexPath:path]);
-    PackageView *view([delegate_ packageView]);
+    PackageController *view([delegate_ packageController]);
     [view setDelegate:delegate_];
     [view setPackage:package];
     [[self navigationController] pushViewController:view animated:YES];
@@ -7154,7 +7043,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (void) refreshButtonClicked {
-    [[UIApplication sharedApplication] beginUpdate];
+    [delegate_ beginUpdate];
     [[self navigationItem] setLeftBarButtonItem:nil];
 }
 
@@ -7162,7 +7051,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     [delegate_ distUpgrade];
 }
 
-- (id) title { return UCLocalize("CHANGES"); }
+- (NSString *) title { return UCLocalize("CHANGES"); }
 
 - (id) initWithDatabase:(Database *)database delegate:(id)delegate {
     if ((self = [super init]) != nil) {
@@ -7174,13 +7063,13 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
         list_ = [[UITableView alloc] initWithFrame:[[self view] bounds] style:UITableViewStylePlain];
         [list_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth];
+        [list_ setRowHeight:73.0f];
         [[self view] addSubview:list_];
 
         [list_ setDataSource:self];
         [list_ setDelegate:self];
 
         delegate_ = delegate;
-        [self reloadData];
     } return self;
 }
 
@@ -7230,7 +7119,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
             unseens = true;
             NSDate *seen;
 
-            _profile(ChangesView$reloadData$Remember)
+            _profile(ChangesController$reloadData$Remember)
                 seen = [package seen];
             _end
 
@@ -7245,7 +7134,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
                     [name autorelease];
                 }
 
-                _profile(ChangesView$reloadData$Allocate)
+                _profile(ChangesController$reloadData$Allocate)
                     name = [NSString stringWithFormat:UCLocalize("NEW_AT"), name];
                     section = [[[Section alloc] initWithName:name row:offset localize:NO] autorelease];
                     [sections_ addObject:section];
@@ -7293,15 +7182,17 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         target:self
         action:@selector(refreshButtonClicked)
     ];
-    if (![[UIApplication sharedApplication] updating]) [[self navigationItem] setLeftBarButtonItem:leftItem];
+    if (![delegate_ updating]) [[self navigationItem] setLeftBarButtonItem:leftItem];
     [leftItem release];
 }
 
 @end
 /* }}} */
-/* Search View {{{ */
-@interface SearchView : FilteredPackageView {
-    id search_;
+/* Search Controller {{{ */
+@interface SearchController : FilteredPackageController <
+    UISearchBarDelegate
+> {
+    UISearchBar *search_;
 }
 
 - (id) initWithDatabase:(Database *)database;
@@ -7309,71 +7200,84 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 @end
 
-@implementation SearchView
+@implementation SearchController
 
 - (void) dealloc {
     [search_ release];
     [super dealloc];
 }
 
-- (void) searchBarSearchButtonClicked:(id)searchBar {
+- (void) searchBarSearchButtonClicked:(UISearchBar *)searchBar {
     [packages_ setObject:[search_ text] forFilter:@selector(isUnfilteredAndSearchedForBy:)];
     [search_ resignFirstResponder];
     [self reloadData];
 }
 
-- (void) searchBar:(id)searchBar textDidChange:(NSString *)text {
+- (void) searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)text {
     [packages_ setObject:text forFilter:@selector(isUnfilteredAndSelectedForBy:)];
     [self reloadData];
 }
 
-- (id) title { return nil; }
+- (NSString *) title { return nil; }
 
 - (id) initWithDatabase:(Database *)database {
-    if ((self = [super initWithDatabase:database title:UCLocalize("SEARCH") filter:@selector(isUnfilteredAndSearchedForBy:) with:nil]) != nil) {
-        search_ = [[objc_getClass("UISearchBar") alloc] initWithFrame:CGRectMake(0, 0, [[self view] frame].size.width, 44.0f)];
+    return [super initWithDatabase:database title:UCLocalize("SEARCH") filter:@selector(isUnfilteredAndSearchedForBy:) with:nil];
+}
+
+- (void)viewDidAppear:(BOOL)animated {
+    [super viewDidAppear:animated];
+    if (!search_) {
+        search_ = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, [[self view] bounds].size.width, 44.0f)];
+        [search_ layoutSubviews];
         [search_ setPlaceholder:UCLocalize("SEARCH_EX")];
-        [search_ setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
+        UITextField *textField = [search_ searchField];
+        [textField setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin];
         [search_ setDelegate:self];
-        [[search_ searchField] setEnablesReturnKeyAutomatically:NO];
-        [[self navigationItem] setTitleView:search_];
-    } return self;
+        [textField setEnablesReturnKeyAutomatically:NO];
+        [[self navigationItem] setTitleView:textField];
+    }
 }
 
 - (void) _reloadData {
 }
 
 - (void) reloadData {
-    _profile(SearchView$reloadData)
+    _profile(SearchController$reloadData)
         [packages_ reloadData];
     _end
     PrintTimes();
     [packages_ resetCursor];
 }
 
+- (void) didSelectPackage:(Package *)package {
+    [search_ resignFirstResponder];
+    [super didSelectPackage:package];
+}
+
 @end
 /* }}} */
-/* Settings View {{{ */
-@interface SettingsView : CYViewController {
+/* Settings Controller {{{ */
+@interface SettingsController : CYViewController <
+    UITableViewDataSource,
+    UITableViewDelegate
+> {
     _transient Database *database_;
     NSString *name_;
     Package *package_;
-    UIPreferencesTable *table_;
-    _UISwitchSlider *subscribedSwitch_;
-    _UISwitchSlider *ignoredSwitch_;
-    UIPreferencesControlTableCell *subscribedCell_;
-    UIPreferencesControlTableCell *ignoredCell_;
+    UITableView *table_;
+    id subscribedSwitch_;
+    id ignoredSwitch_;
+    UITableViewCell *subscribedCell_;
+    UITableViewCell *ignoredCell_;
 }
 
 - (id) initWithDatabase:(Database *)database package:(NSString *)package;
 
 @end
 
-@implementation SettingsView
+@implementation SettingsController
 
 - (void) dealloc {
-    [table_ setDataSource:nil];
-
     [name_ release];
     if (package_ != nil)
         [package_ release];
@@ -7382,198 +7286,549 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     [ignoredSwitch_ release];
     [subscribedCell_ release];
     [ignoredCell_ release];
+
     [super dealloc];
 }
 
-- (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
-    if (package_ == nil)
-        return 0;
+- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView {
+    if (package_ == nil)
+        return 0;
+
+    return 1;
+}
+
+- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    if (package_ == nil)
+        return 0;
+
+    return 1;
+}
+
+- (NSString *) tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {
+    return UCLocalize("SHOW_ALL_CHANGES_EX");
+}
+
+- (void) onSomething:(BOOL)value withKey:(NSString *)key {
+    if (package_ == nil)
+        return;
+
+    NSMutableDictionary *metadata([package_ metadata]);
+
+    BOOL before;
+    if (NSNumber *number = [metadata objectForKey:key])
+        before = [number boolValue];
+    else
+        before = NO;
+
+    if (value != before) {
+        [metadata setObject:[NSNumber numberWithBool:value] forKey:key];
+        Changed_ = true;
+        [delegate_ updateData];
+    }
+}
+
+- (void) onSubscribed:(id)control {
+    [self onSomething:(int) [control isOn] withKey:@"IsSubscribed"];
+}
+
+- (void) onIgnored:(id)control {
+    [self onSomething:(int) [control isOn] withKey:@"IsIgnored"];
+}
+
+- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    if (package_ == nil)
+        return nil;
+
+    switch ([indexPath row]) {
+        case 0: return subscribedCell_;
+        case 1: return ignoredCell_;
+
+        _nodefault
+    }
+
+    return nil;
+}
+
+- (NSString *) title { return UCLocalize("SETTINGS"); }
+
+- (id) initWithDatabase:(Database *)database package:(NSString *)package {
+    if ((self = [super init])) {
+        database_ = database;
+        name_ = [package retain];
+
+        [[self navigationItem] setTitle:UCLocalize("SETTINGS")];
+
+        table_ = [[UITableView alloc] initWithFrame:[[self view] bounds] style:UITableViewStyleGrouped];
+        [table_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth];
+        [table_ setAllowsSelection:NO];
+        [[self view] addSubview:table_];
+
+        subscribedSwitch_ = [[objc_getClass("UISwitch") alloc] initWithFrame:CGRectMake(0, 0, 50, 20)];
+        [subscribedSwitch_ setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin];
+        [subscribedSwitch_ addTarget:self action:@selector(onSubscribed:) forEvents:UIControlEventValueChanged];
+
+        ignoredSwitch_ = [[objc_getClass("UISwitch") alloc] initWithFrame:CGRectMake(0, 0, 50, 20)];
+        [ignoredSwitch_ setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin];
+        [ignoredSwitch_ addTarget:self action:@selector(onIgnored:) forEvents:UIControlEventValueChanged];
+
+        subscribedCell_ = [[UITableViewCell alloc] init];
+        [subscribedCell_ setText:UCLocalize("SHOW_ALL_CHANGES")];
+        [subscribedCell_ setAccessoryView:subscribedSwitch_];
+
+        ignoredCell_ = [[UITableViewCell alloc] init];
+        [ignoredCell_ setText:UCLocalize("IGNORE_UPGRADES")];
+        [ignoredCell_ setAccessoryView:ignoredSwitch_];
+
+        [table_ setDataSource:self];
+        [table_ setDelegate:self];
+        [self reloadData];
+    } return self;
+}
+
+- (void) reloadData {
+    if (package_ != nil)
+        [package_ autorelease];
+    package_ = [database_ packageWithName:name_];
+    if (package_ != nil) {
+        [package_ retain];
+        [subscribedSwitch_ setOn:([package_ subscribed] ? 1 : 0) animated:NO];
+        [ignoredSwitch_ setOn:([package_ ignored] ? 1 : 0) animated:NO];
+    }
+
+    [table_ reloadData];
+}
+
+@end
+/* }}} */
+
+/* Signature Controller {{{ */
+@interface SignatureController : CYBrowserController {
+    _transient Database *database_;
+    NSString *package_;
+}
+
+- (id) initWithDatabase:(Database *)database package:(NSString *)package;
+
+@end
+
+@implementation SignatureController
+
+- (void) dealloc {
+    [package_ release];
+    [super dealloc];
+}
+
+- (void) webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame {
+    // XXX: dude!
+    [super webView:sender didClearWindowObject:window forFrame:frame];
+}
+
+- (id) initWithDatabase:(Database *)database package:(NSString *)package {
+    if ((self = [super init]) != nil) {
+        database_ = database;
+        package_ = [package retain];
+        [self reloadData];
+    } return self;
+}
+
+- (void) reloadData {
+    [self loadURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"signature" ofType:@"html"]]];
+}
+
+@end
+/* }}} */
+/* Role Controller {{{ */
+@interface RoleController : CYViewController <
+    UITableViewDataSource,
+    UITableViewDelegate
+> {
+    _transient Database *database_;
+    id roledelegate_;
+    UITableView *table_;
+    UISegmentedControl *segment_;
+    UIView *container_;
+}
+
+- (void) showDoneButton;
+- (void) resizeSegmentedControl;
+
+@end
+
+@implementation RoleController
+- (void) dealloc {
+    [table_ release];
+    [segment_ release];
+    [container_ release];
+
+    [super dealloc];
+}
+
+- (id) initWithDatabase:(Database *)database delegate:(id)delegate {
+    if ((self = [super init])) {
+        database_ = database;
+        roledelegate_ = delegate;
+
+        [[self navigationItem] setTitle:UCLocalize("WHO_ARE_YOU")];
+
+        NSArray *items = [NSArray arrayWithObjects:
+            UCLocalize("USER"),
+            UCLocalize("HACKER"),
+            UCLocalize("DEVELOPER"),
+        nil];
+        segment_ = [[UISegmentedControl alloc] initWithItems:items];
+        container_ = [[UIView alloc] initWithFrame:CGRectMake(0, 0, [[self view] frame].size.width, 44.0f)];
+        [container_ addSubview:segment_];
+
+        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];
+
+        table_ = [[UITableView alloc] initWithFrame:[[self view] bounds] style:UITableViewStyleGrouped];
+        [table_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth];
+        [table_ setDelegate:self];
+        [table_ setDataSource:self];
+        [[self view] addSubview:table_];
+        [table_ reloadData];
+    } 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) doneButtonClicked {
+    [self save];
+    [[self navigationController] dismissModalViewControllerAnimated:YES];
+}
+
+- (void) showDoneButton {
+    UIBarButtonItem *rightItem = [[UIBarButtonItem alloc]
+        initWithTitle:UCLocalize("DONE")
+        style:UIBarButtonItemStyleDone
+        target:self
+        action:@selector(doneButtonClicked)
+    ];
+    [[self navigationItem] setRightBarButtonItem:rightItem animated:[[self navigationItem] rightBarButtonItem] == nil];
+    [rightItem release];
+}
+
+- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView {
+    // XXX: For not having a single cell in the table, this sure is a lot of sections.
+    return 6;
+}
+
+- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    return 0; // :(
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    return nil; // This method is required by the protocol.
+}
+
+- (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;
+}
+
+- (CGFloat) tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
+    if (section == 3) return 44.0f;
+    else return 0;
+}
+
+- (UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
+    if (section == 3) return container_;
+    else return nil;
+}
+
+@end
+/* }}} */
+
+/* Cydia Container {{{ */
+@interface CYContainer : UIViewController <ProgressDelegate> {
+    _transient Database *database_;
+    RefreshBar *refreshbar_;
+
+    bool dropped_;
+    bool updating_;
+    id updatedelegate_;
+    UITabBarController *root_;
+}
+
+- (void) setTabBarController:(UITabBarController *)controller;
+
+- (void) dropBar:(BOOL)animated;
+- (void) beginUpdate;
+- (void) raiseBar:(BOOL)animated;
 
-    return 2;
-}
+@end
 
-- (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
-    if (package_ == nil)
-        return nil;
+@implementation CYContainer
 
-    switch (group) {
-        case 0: return nil;
-        case 1: return nil;
+// NOTE: UIWindow only sends the top controller these messages,
+//       So we have to forward them on.
 
-        _nodefault
-    }
+- (void) viewDidAppear:(BOOL)animated {
+    [super viewDidAppear:animated];
+    [root_ viewDidAppear:animated];
+}
 
-    return nil;
+- (void) viewWillAppear:(BOOL)animated {
+    [super viewWillAppear:animated];
+    [root_ viewWillAppear:animated];
 }
 
-- (BOOL) preferencesTable:(UIPreferencesTable *)table isLabelGroup:(int)group {
-    if (package_ == nil)
-        return NO;
+- (void) viewDidDisappear:(BOOL)animated {
+    [super viewDidDisappear:animated];
+    [root_ viewDidDisappear:animated];
+}
 
-    switch (group) {
-        case 0: return NO;
-        case 1: return YES;
+- (void) viewWillDisappear:(BOOL)animated {
+    [super viewWillDisappear:animated];
+    [root_ viewWillDisappear:animated];
+}
 
-        _nodefault
-    }
+- (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orientation {
+    return IsWildcat_;
+}
 
-    return NO;
+- (void) setTabBarController:(UITabBarController *)controller {
+    root_ = controller;
+    [[self view] addSubview:[root_ view]];
 }
 
-- (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
-    if (package_ == nil)
-        return 0;
+- (void) setUpdate:(NSDate *)date {
+    [self beginUpdate];
+}
 
-    switch (group) {
-        case 0: return 1;
-        case 1: return 1;
+- (void) beginUpdate {
+    [self dropBar:YES];
+    [refreshbar_ start];
 
-        _nodefault
-    }
+    updating_ = true;
 
-    return 0;
+    [NSThread
+        detachNewThreadSelector:@selector(performUpdate)
+        toTarget:self
+        withObject:nil
+    ];
 }
 
-- (void) onSomething:(UIPreferencesControlTableCell *)cell withKey:(NSString *)key {
-    if (package_ == nil)
-        return;
+- (void) performUpdate { _pooled
+    Status status;
+    status.setDelegate(self);
+    [database_ updateWithStatus:status];
 
-    _UISwitchSlider *slider([cell control]);
-    BOOL value([slider value] != 0);
-    NSMutableDictionary *metadata([package_ metadata]);
+    [self
+        performSelectorOnMainThread:@selector(completeUpdate)
+        withObject:nil
+        waitUntilDone:NO
+    ];
+}
 
-    BOOL before;
-    if (NSNumber *number = [metadata objectForKey:key])
-        before = [number boolValue];
-    else
-        before = NO;
+- (void) completeUpdate {
+    updating_ = false;
 
-    if (value != before) {
-        [metadata setObject:[NSNumber numberWithBool:value] forKey:key];
-        Changed_ = true;
-        [delegate_ updateData];
-    }
+    [self raiseBar:YES];
+    [refreshbar_ stop];
+    [updatedelegate_ performSelector:@selector(reloadData) withObject:nil afterDelay:0];
 }
 
-- (void) onSubscribed:(UIPreferencesControlTableCell *)cell {
-    [self onSomething:cell withKey:@"IsSubscribed"];
+- (void) cancelUpdate {
+    [refreshbar_ cancel];
+    [self completeUpdate];
 }
 
-- (void) onIgnored:(UIPreferencesControlTableCell *)cell {
-    [self onSomething:cell withKey:@"IsIgnored"];
+- (void) cancelPressed {
+    [self cancelUpdate];
 }
 
-- (id) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
-    if (package_ == nil)
-        return nil;
+- (BOOL) updating {
+    return updating_;
+}
 
-    switch (group) {
-        case 0: switch (row) {
-            case 0:
-                return subscribedCell_;
-            case 1:
-                return ignoredCell_;
-            _nodefault
-        } break;
-
-        case 1: switch (row) {
-            case 0: {
-                UIPreferencesControlTableCell *cell([[[UIPreferencesControlTableCell alloc] init] autorelease]);
-                [cell setShowSelection:NO];
-                [cell setTitle:UCLocalize("SHOW_ALL_CHANGES_EX")];
-                return cell;
-            }
+- (void) setProgressError:(NSString *)error withTitle:(NSString *)title {
+    [refreshbar_ setPrompt:[NSString stringWithFormat:UCLocalize("COLON_DELIMITED"), UCLocalize("ERROR"), error]];
+}
 
-            _nodefault
-        } break;
+- (void) startProgress {
+}
 
-        _nodefault
-    }
+- (void) setProgressTitle:(NSString *)title {
+    [self
+        performSelectorOnMainThread:@selector(_setProgressTitle:)
+        withObject:title
+        waitUntilDone:YES
+    ];
+}
 
-    return nil;
+- (bool) isCancelling:(size_t)received {
+    return !updating_;
 }
 
-- (id) title { return UCLocalize("SETTINGS"); }
+- (void) setProgressPercent:(float)percent {
+    [self
+        performSelectorOnMainThread:@selector(_setProgressPercent:)
+        withObject:[NSNumber numberWithFloat:percent]
+        waitUntilDone:YES
+    ];
+}
 
-- (id) initWithDatabase:(Database *)database package:(NSString *)package {
-    if ((self = [super init])) {
-        database_ = database;
-        name_ = [package retain];
+- (void) addProgressOutput:(NSString *)output {
+    [self
+        performSelectorOnMainThread:@selector(_addProgressOutput:)
+        withObject:output
+        waitUntilDone:YES
+    ];
+}
 
-        [[self navigationItem] setTitle:UCLocalize("SETTINGS")];
+- (void) _setProgressTitle:(NSString *)title {
+    [refreshbar_ setPrompt:title];
+}
 
-        table_ = [[UIPreferencesTable alloc] initWithFrame:[[self view] bounds]];
-        [[self view] addSubview:table_];
+- (void) _setProgressPercent:(NSNumber *)percent {
+    [refreshbar_ setProgress:[percent floatValue]];
+}
 
-        subscribedSwitch_ = [[_UISwitchSlider alloc] initWithFrame:CGRectMake(200, 10, 50, 20)];
-        [subscribedSwitch_ addTarget:self action:@selector(onSubscribed:) forEvents:UIControlEventTouchUpInside];
+- (void) _addProgressOutput:(NSString *)output {
+}
 
-        ignoredSwitch_ = [[_UISwitchSlider alloc] initWithFrame:CGRectMake(200, 10, 50, 20)];
-        [ignoredSwitch_ addTarget:self action:@selector(onIgnored:) forEvents:UIControlEventTouchUpInside];
+- (void) setUpdateDelegate:(id)delegate {
+    updatedelegate_ = delegate;
+}
 
-        subscribedCell_ = [[UIPreferencesControlTableCell alloc] init];
-        [subscribedCell_ setShowSelection:NO];
-        [subscribedCell_ setTitle:UCLocalize("SHOW_ALL_CHANGES")];
-        [subscribedCell_ setControl:subscribedSwitch_];
+- (void) dropBar:(BOOL)animated {
+    if (dropped_) return;
+    dropped_ = true;
 
-        ignoredCell_ = [[UIPreferencesControlTableCell alloc] init];
-        [ignoredCell_ setShowSelection:NO];
-        [ignoredCell_ setTitle:UCLocalize("IGNORE_UPGRADES")];
-        [ignoredCell_ setControl:ignoredSwitch_];
+    [[self view] addSubview:refreshbar_];
 
-        [table_ setDataSource:self];
-        [self reloadData];
-    } return self;
-}
+    if (animated) [UIView beginAnimations:nil context:NULL];
+    CGRect barframe = [refreshbar_ frame];
+    CGRect viewframe = [[root_ view] frame];
+    viewframe.origin.y += barframe.size.height;
+    viewframe.size.height -= barframe.size.height;
+    [[root_ view] setFrame:viewframe];
+    if (animated) [UIView commitAnimations];
 
-- (void) reloadData {
-    if (package_ != nil)
-        [package_ autorelease];
-    package_ = [database_ packageWithName:name_];
-    if (package_ != nil) {
-        [package_ retain];
-        [subscribedSwitch_ setValue:([package_ subscribed] ? 1 : 0) animated:NO];
-        [ignoredSwitch_ setValue:([package_ ignored] ? 1 : 0) animated:NO];
-    }
+    // Ensure bar has the proper width for our view, it might have changed
+    barframe.size.width = viewframe.size.width;
+    [refreshbar_ setFrame:barframe];
 
-    [table_ reloadData];
+    // XXX: fix Apple's layout bug
+    [[root_ selectedViewController] _updateLayoutForStatusBarAndInterfaceOrientation];
 }
 
-@end
-/* }}} */
+- (void) raiseBar:(BOOL)animated {
+    if (!dropped_) return;
+    dropped_ = false;
 
-/* Signature View {{{ */
-@interface SignatureView : CYBrowserController {
-    _transient Database *database_;
-    NSString *package_;
+    [refreshbar_ removeFromSuperview];
+
+    if (animated) [UIView beginAnimations:nil context:NULL];
+    CGRect barframe = [refreshbar_ frame];
+    CGRect viewframe = [[root_ view] frame];
+    viewframe.origin.y -= barframe.size.height;
+    viewframe.size.height += barframe.size.height;
+    [[root_ view] setFrame:viewframe];
+    if (animated) [UIView commitAnimations];
+
+    // XXX: fix Apple's layout bug
+    [[root_ selectedViewController] _updateLayoutForStatusBarAndInterfaceOrientation];
 }
 
-- (id) initWithDatabase:(Database *)database package:(NSString *)package;
+- (void) willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration {
+    // XXX: fix Apple's layout bug
+    [[root_ selectedViewController] _updateLayoutForStatusBarAndInterfaceOrientation];
+}
 
-@end
+- (void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
+    if (dropped_) {
+        [self raiseBar:NO];
+        [self dropBar:NO];
+    }
 
-@implementation SignatureView
+    // XXX: fix Apple's layout bug
+    [[root_ selectedViewController] _updateLayoutForStatusBarAndInterfaceOrientation];
+}
 
 - (void) dealloc {
-    [package_ release];
+    [refreshbar_ release];
     [super dealloc];
 }
 
-- (void) webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame {
-    // XXX: dude!
-    [super webView:sender didClearWindowObject:window forFrame:frame];
-}
-
-- (id) initWithDatabase:(Database *)database package:(NSString *)package {
+- (id) initWithDatabase:(Database *)database {
     if ((self = [super init]) != nil) {
         database_ = database;
-        package_ = [package retain];
-        [self reloadData];
-    } return self;
-}
 
-- (void) reloadData {
-    [self loadURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"signature" ofType:@"html"]]];
+        [[self view] setAutoresizingMask:UIViewAutoresizingFlexibleBoth];
+
+        refreshbar_ = [[RefreshBar alloc] initWithFrame:CGRectMake(0, 0, [[self view] frame].size.width, [UINavigationBar defaultSize].height) delegate:self];
+    } return self;
 }
 
 @end
@@ -7590,11 +7845,13 @@ typedef enum {
 } CYTabTag;
 
 @interface Cydia : UIApplication <
-    ConfirmationViewDelegate,
-    ProgressViewDelegate,
-    CydiaDelegate
+    ConfirmationControllerDelegate,
+    ProgressControllerDelegate,
+    CydiaDelegate,
+    UINavigationControllerDelegate
 > {
     UIWindow *window_;
+    CYContainer *container_;
 
     id tabbar_;
 
@@ -7608,38 +7865,39 @@ typedef enum {
     UIKeyboard *keyboard_;
     UIProgressHUD *hud_;
 
-    SectionsView *sections_;
-    ChangesView *changes_;
-    ManageView *manage_;
-    SearchView *search_;
+    SectionsController *sections_;
+    ChangesController *changes_;
+    ManageController *manage_;
+    SearchController *search_;
     SourceTable *sources_;
-    InstalledView *installed_;
+    InstalledController *installed_;
     id queueDelegate_;
 
 #if RecyclePackageViews
     NSMutableArray *details_;
 #endif
 
-       bool loaded_;
+    bool loaded_;
 }
 
-- (UIViewController *) _pageForURL:(NSURL *)url withClass:(Class)_class;
-- (void) setPage:(UIViewController *)page;
+- (CYViewController *) _pageForURL:(NSURL *)url withClass:(Class)_class;
+- (void) setPage:(CYViewController *)page;
+- (void) loadData;
 
 @end
 
 static _finline void _setHomePage(Cydia *self) {
-    [self setPage:[self _pageForURL:[NSURL URLWithString:CydiaURL(@"")] withClass:[HomeView class]]];
+    [self setPage:[self _pageForURL:[NSURL URLWithString:CydiaURL(@"")] withClass:[HomeController class]]];
 }
 
 @implementation Cydia
 
 - (void) beginUpdate {
-    [tabbar_ beginUpdate];
+    [container_ beginUpdate];
 }
 
 - (BOOL) updating {
-    return [tabbar_ updating];
+    return [container_ updating];
 }
 
 - (UIView *) rotatingContentViewForWindow:(UIWindow *)window {
@@ -7706,7 +7964,7 @@ static _finline void _setHomePage(Cydia *self) {
     if (tag_ != 4 && search_ != nil)
         [search_ reloadData];
 
-    [[tabbar_ selectedViewController] reloadData];
+    [(CYNavigationController *)[tabbar_ selectedViewController] reloadData];
 }
 
 - (int)indexOfTabWithTag:(int)tag {
@@ -7715,17 +7973,32 @@ static _finline void _setHomePage(Cydia *self) {
         if ([[controller tabBarItem] tag] == tag) return i;
         i += 1;
     }
-    
+
     return -1;
 }
 
 - (void) _refreshIfPossible {
-       NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-       
-       Reachability* reachability = [Reachability reachabilityWithHostName:@"cydia.saurik.com"];
-       NetworkStatus remoteHostStatus = [reachability currentReachabilityStatus];
-       
-       if (loaded_ || ManualRefresh || remoteHostStatus == NotReachable) loaded:
+    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+    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 (loaded_ || ManualRefresh || !reachable) loaded:
         [self performSelectorOnMainThread:@selector(_loaded) withObject:nil waitUntilDone:NO];
     else {
         loaded_ = true;
@@ -7738,19 +8011,17 @@ static _finline void _setHomePage(Cydia *self) {
                 goto loaded;
         }
 
-        [tabbar_ performSelectorOnMainThread:@selector(setUpdate:) withObject:update waitUntilDone:NO];
+        [container_ performSelectorOnMainThread:@selector(setUpdate:) withObject:update waitUntilDone:NO];
     }
 
-       [pool release];
+    [pool release];
 }
 
 - (void) refreshIfPossible {
-       [NSThread detachNewThreadSelector:@selector(_refreshIfPossible) toTarget:self withObject:nil];
+    [NSThread detachNewThreadSelector:@selector(_refreshIfPossible) toTarget:self withObject:nil];
 }
 
 - (void) _reloadData {
-    UIView *block();
-
     UIProgressHUD *hud([self addProgressHUD]);
     [hud setText:(loaded_ ? UCLocalize("RELOADING_DATA") : UCLocalize("LOADING_DATA"))];
 
@@ -7779,7 +8050,7 @@ static _finline void _setHomePage(Cydia *self) {
         NSString *badge([[NSNumber numberWithInt:changes] stringValue]);
         [[[[tabbar_ viewControllers] objectAtIndex:[self indexOfTabWithTag:kChangesTag]] tabBarItem] setBadgeValue:badge];
         [[[[tabbar_ viewControllers] objectAtIndex:[self indexOfTabWithTag:kChangesTag]] tabBarItem] setAnimatedBadge:YES];
-    
+
         if ([self respondsToSelector:@selector(setApplicationBadge:)])
             [self setApplicationBadge:badge];
         else
@@ -7787,7 +8058,7 @@ static _finline void _setHomePage(Cydia *self) {
     } else {
         [[[[tabbar_ viewControllers] objectAtIndex:[self indexOfTabWithTag:kChangesTag]] tabBarItem] setBadgeValue:nil];
         [[[[tabbar_ viewControllers] objectAtIndex:[self indexOfTabWithTag:kChangesTag]] tabBarItem] setAnimatedBadge:NO];
-    
+
         if ([self respondsToSelector:@selector(removeApplicationBadge)])
             [self removeApplicationBadge];
         else // XXX: maybe use setApplicationBadgeString also?
@@ -7796,7 +8067,7 @@ static _finline void _setHomePage(Cydia *self) {
 
     [self _updateData];
 
-       [self refreshIfPossible];
+    [self refreshIfPossible];
 }
 
 - (void) updateData {
@@ -7826,10 +8097,10 @@ static _finline void _setHomePage(Cydia *self) {
 
     [self _saveConfig];
 
-    ProgressView *progress = [[[ProgressView alloc] initWithDatabase:database_ delegate:self] autorelease];
-    UINavigationController *navigation = [[[UINavigationController alloc] initWithRootViewController:progress] autorelease];
+    ProgressController *progress = [[[ProgressController alloc] initWithDatabase:database_ delegate:self] autorelease];
+    CYNavigationController *navigation = [[[CYNavigationController alloc] initWithRootViewController:progress] autorelease];
     if (IsWildcat_) [navigation setModalPresentationStyle:UIModalPresentationFormSheet];
-    [[tabbar_ selectedViewController] presentModalViewController:navigation animated:YES];
+    [container_ presentModalViewController:navigation animated:YES];
 
     [progress
         detachNewThreadSelector:@selector(update_)
@@ -7861,13 +8132,13 @@ static _finline void _setHomePage(Cydia *self) {
     if (![database_ prepare])
         return false;
 
-    ConfirmationView *page([[[ConfirmationView alloc] initWithDatabase:database_] autorelease]);
+    ConfirmationController *page([[[ConfirmationController alloc] initWithDatabase:database_] autorelease]);
     [page setDelegate:self];
-    id confirm_ = [[UINavigationController alloc] initWithRootViewController:page];
+    CYNavigationController *confirm_ = [[CYNavigationController alloc] initWithRootViewController:page];
     [confirm_ setDelegate:self];
 
     if (IsWildcat_) [confirm_ setModalPresentationStyle:UIModalPresentationFormSheet];
-    [[tabbar_ selectedViewController] presentModalViewController:confirm_ animated:YES];
+    [container_ presentModalViewController:confirm_ animated:YES];
 
     return true;
 }
@@ -7926,16 +8197,16 @@ static _finline void _setHomePage(Cydia *self) {
 }
 
 - (void) confirmWithNavigationController:(UINavigationController *)navigation {
-    ProgressView *progress = [[[ProgressView alloc] initWithDatabase:database_ delegate:self] autorelease];
-    
+    ProgressController *progress = [[[ProgressController alloc] initWithDatabase:database_ delegate:self] autorelease];
+
     if (navigation != nil) {
         [navigation pushViewController:progress animated:YES];
     } else {
-        navigation = [[[UINavigationController alloc] initWithRootViewController:progress] autorelease];
+        navigation = [[[CYNavigationController alloc] initWithRootViewController:progress] autorelease];
         if (IsWildcat_) [navigation setModalPresentationStyle:UIModalPresentationFormSheet];
-        [[tabbar_ selectedViewController] presentModalViewController:navigation animated:YES];
+        [container_ presentModalViewController:navigation animated:YES];
     }
-    
+
     [progress
         detachNewThreadSelector:@selector(perform)
         toTarget:database_
@@ -7944,87 +8215,87 @@ static _finline void _setHomePage(Cydia *self) {
     ];
 }
 
-- (void) progressViewIsComplete:(ProgressView *)progress {
+- (void) progressControllerIsComplete:(ProgressController *)progress {
     [self complete];
 }
 
-- (void) setPage:(UIViewController *)page {
+- (void) setPage:(CYViewController *)page {
     [page setDelegate:self];
 
-    UINavigationController *navController = [tabbar_ selectedViewController];
+    CYNavigationController *navController = (CYNavigationController *) [tabbar_ selectedViewController];
     [navController setViewControllers:[NSArray arrayWithObject:page] animated:NO];
-    for (UIViewController *page in [tabbar_ viewControllers]) {
+    for (CYNavigationController *page in [tabbar_ viewControllers]) {
         if (page != navController) [page setViewControllers:nil];
     }
 }
 
-- (UIViewController *) _pageForURL:(NSURL *)url withClass:(Class)_class {
+- (CYViewController *) _pageForURL:(NSURL *)url withClass:(Class)_class {
     CYBrowserController *browser = [[[_class alloc] init] autorelease];
     [browser loadURL:url];
     return browser;
 }
 
-- (SectionsView *) sectionsView {
+- (SectionsController *) sectionsController {
     if (sections_ == nil)
-        sections_ = [[SectionsView alloc] initWithDatabase:database_];
+        sections_ = [[SectionsController alloc] initWithDatabase:database_];
     return sections_;
 }
 
-- (ChangesView *) changesView {
+- (ChangesController *) changesController {
     if (changes_ == nil)
-        changes_ = [[ChangesView alloc] initWithDatabase:database_ delegate:self];
+        changes_ = [[ChangesController alloc] initWithDatabase:database_ delegate:self];
     return changes_;
 }
 
-- (ManageView *) manageView {
+- (ManageController *) manageController {
     if (manage_ == nil) {
-        manage_ = (ManageView *) [[self
+        manage_ = (ManageController *) [[self
             _pageForURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"manage" ofType:@"html"]]
-            withClass:[ManageView class]
+            withClass:[ManageController class]
         ] retain];
         if (!IsWildcat_) queueDelegate_ = manage_;
     }
     return manage_;
 }
 
-- (SearchView *) searchView {
+- (SearchController *) searchController {
     if (search_ == nil)
-        search_ = [[SearchView alloc] initWithDatabase:database_];
+        search_ = [[SearchController alloc] initWithDatabase:database_];
     return search_;
 }
 
-- (SourceTable *) sourcesView {
+- (SourceTable *) sourcesController {
     if (sources_ == nil)
         sources_ = [[SourceTable alloc] initWithDatabase:database_];
     return sources_;
 }
 
-- (InstalledView *) installedView {
+- (InstalledController *) installedController {
     if (installed_ == nil) {
-        installed_ = [[InstalledView alloc] initWithDatabase:database_];
+        installed_ = [[InstalledController alloc] initWithDatabase:database_];
         if (IsWildcat_) queueDelegate_ = installed_;
     }
     return installed_;
 }
 
-- (void) tabBarController:(id)tabBarController didSelectViewController:(UIViewController *)viewController {    
+- (void) tabBarController:(id)tabBarController didSelectViewController:(UIViewController *)viewController {
     int tag = [[viewController tabBarItem] tag];
     if (tag == tag_) {
-        [[tabbar_ selectedViewController] popToRootViewControllerAnimated:YES];
+        [(CYNavigationController *)[tabbar_ selectedViewController] popToRootViewControllerAnimated:YES];
         return;
     } else if (tag_ == 1) {
-        [[self sectionsView] resetView];
+        [[self sectionsController] resetView];
     }
 
     switch (tag) {
         case kCydiaTag: _setHomePage(self); break;
 
-        case kSectionsTag: [self setPage:[self sectionsView]]; break;
-        case kChangesTag: [self setPage:[self changesView]]; break;
-        case kManageTag: [self setPage:[self manageView]]; break;
-        case kInstalledTag: [self setPage:[self installedView]]; break;
-        case kSourcesTag: [self setPage:[self sourcesView]]; break;
-        case kSearchTag: [self setPage:[self searchView]]; break;
+        case kSectionsTag: [self setPage:[self sectionsController]]; break;
+        case kChangesTag: [self setPage:[self changesController]]; break;
+        case kManageTag: [self setPage:[self manageController]]; break;
+        case kInstalledTag: [self setPage:[self installedController]]; break;
+        case kSourcesTag: [self setPage:[self sourcesController]]; break;
+        case kSearchTag: [self setPage:[self searchController]]; break;
 
         _nodefault
     }
@@ -8032,43 +8303,14 @@ static _finline void _setHomePage(Cydia *self) {
     tag_ = tag;
 }
 
-- (void) askForSettings {
-    NSString *parenthetical(UCLocalize("PARENTHETICAL"));
-
-    CYActionSheet *role([[[CYActionSheet alloc]
-        initWithTitle:UCLocalize("WHO_ARE_YOU")
-        buttons:[NSArray arrayWithObjects:
-            [NSString stringWithFormat:parenthetical, UCLocalize("USER"), UCLocalize("USER_EX")],
-            [NSString stringWithFormat:parenthetical, UCLocalize("HACKER"), UCLocalize("HACKER_EX")],
-            [NSString stringWithFormat:parenthetical, UCLocalize("DEVELOPER"), UCLocalize("DEVELOPER_EX")],
-        nil]
-        defaultButtonIndex:-1
-    ] autorelease]);
-
-    [role setMessage:UCLocalize("ROLE_EX")];
-
-    int button([role yieldToPopupAlertAnimated:YES]);
-
-    switch (button) {
-        case 1: Role_ = @"User"; break;
-        case 2: Role_ = @"Hacker"; break;
-        case 3: Role_ = @"Developer"; break;
-
-        _nodefault
-    }
-
-    Settings_ = [NSMutableDictionary dictionaryWithObjectsAndKeys:
-        Role_, @"Role",
-    nil];
-
-    [Metadata_ setObject:Settings_ forKey:@"Settings"];
-
-    Changed_ = true;
-
-    [role dismiss];
+- (void) showSettings {
+    RoleController *role = [[RoleController alloc] initWithDatabase:database_ delegate:self];
+    CYNavigationController *nav = [[CYNavigationController alloc] initWithRootViewController:role];
+    if (IsWildcat_) [nav setModalPresentationStyle:UIModalPresentationFormSheet];
+    [container_ presentModalViewController:nav animated:YES];
 }
 
-- (void) setPackageView:(PackageView *)view {
+- (void) setPackageController:(PackageController *)view {
     WebThreadLock();
     [view setPackage:nil];
 #if RecyclePackageViews
@@ -8078,19 +8320,19 @@ static _finline void _setHomePage(Cydia *self) {
     WebThreadUnlock();
 }
 
-- (PackageView *) _packageView {
-    return [[[PackageView alloc] initWithDatabase:database_] autorelease];
+- (PackageController *) _packageController {
+    return [[[PackageController alloc] initWithDatabase:database_] autorelease];
 }
 
-- (PackageView *) packageView {
+- (PackageController *) packageController {
 #if RecyclePackageViews
-    PackageView *view;
+    PackageController *view;
     size_t count([details_ count]);
 
     if (count == 0) {
-        view = [self _packageView];
+        view = [self _packageController];
       renew:
-        [details_ addObject:[self _packageView]];
+        [details_ addObject:[self _packageController]];
     } else {
         view = [[[details_ lastObject] retain] autorelease];
         [details_ removeLastObject];
@@ -8100,39 +8342,50 @@ static _finline void _setHomePage(Cydia *self) {
 
     return view;
 #else
-    return [self _packageView];
+    return [self _packageController];
 #endif
 }
 
+// Returns the navigation controller for the queuing badge.
+- (id) queueBadgeController {
+    int index = [self indexOfTabWithTag:kManageTag];
+    if (index == -1) index = [self indexOfTabWithTag:kInstalledTag];
+    
+    return [[tabbar_ viewControllers] objectAtIndex:index];
+}
+
 - (void) cancelAndClear:(bool)clear {
     @synchronized (self) {
         if (clear) {
-            /* XXX: clear marks instead of reloading data */
-            /*pkgCacheFile &cache([database_ cache]);
+            // Clear all marks.
+            pkgCacheFile &cache([database_ cache]);
             for (pkgCache::PkgIterator iterator = cache->PkgBegin(); !iterator.end(); ++iterator) {
-                if (!cache[iterator].Keep()) cache->MarkKeep(iterator, false, false);
+                // Unmark method taken from Synaptic Package Manager.
+                               // Thanks for being sane, unlike Aptitude.
+                               if (!cache[iterator].Keep()) {
+                                       cache->MarkKeep(iterator, false);
+                                       cache->SetReInstall(iterator, false);
+                               }
             }
 
-            [self updateData];
-            
+                       // Stop queuing.
             Queuing_ = false;
-            [[[[tabbar_ viewControllers] objectAtIndex:[self indexOfTabWithTag:kManageTag] != -1 ? [self indexOfTabWithTag:kManageTag] : [self indexOfTabWithTag:kInstalledTag]] tabBarItem] setBadgeValue:nil];
-            [queueDelegate_ queueStatusDidChange];*/
-            [self reloadData];
+            [[[self queueBadgeController] tabBarItem] setBadgeValue:nil];
         } else {
+                       // Start queuing.
             Queuing_ = true;
-
-            [[[[tabbar_ viewControllers] objectAtIndex:[self indexOfTabWithTag:kManageTag] != -1 ? [self indexOfTabWithTag:kManageTag] : [self indexOfTabWithTag:kInstalledTag]] tabBarItem] setBadgeValue:UCLocalize("Q_D")];
-            [[tabbar_ selectedViewController] reloadData];
-            
-            [queueDelegate_ queueStatusDidChange];
-        }
+            [[[self queueBadgeController] tabBarItem] setBadgeValue:UCLocalize("Q_D")];
+               }
+        
+               // Show the changes in the current view.
+        [(CYNavigationController *) [tabbar_ selectedViewController] reloadData];
+        [queueDelegate_ queueStatusDidChange];
     }
 }
 
 - (void) alertView:(UIAlertView *)alert clickedButtonAtIndex:(NSInteger)button {
     NSString *context([alert context]);
-    
+
     if ([context isEqualToString:@"fixhalf"]) {
         if (button == [alert firstOtherButtonIndex]) {
             @synchronized (self) {
@@ -8184,6 +8437,8 @@ static _finline void _setHomePage(Cydia *self) {
 }
 
 - (void) applicationSuspend:(__GSEvent *)event {
+    // FIXME: This needs to be fixed, but we no longer have a progress_.
+    //        What's the best solution?
     if (hud_ == nil)// && ![progress_ isRunning])
         [super applicationSuspend:event];
 }
@@ -8204,7 +8459,7 @@ static _finline void _setHomePage(Cydia *self) {
 
     [window_ setUserInteractionEnabled:NO];
     [hud show:YES];
-    [window_ addSubview:hud];
+    [[container_ view] addSubview:hud];
     return hud;
 }
 
@@ -8214,9 +8469,9 @@ static _finline void _setHomePage(Cydia *self) {
     [window_ setUserInteractionEnabled:YES];
 }
 
-- (UIViewController *) pageForPackage:(NSString *)name {
+- (CYViewController *) pageForPackage:(NSString *)name {
     if (Package *package = [database_ packageWithName:name]) {
-        PackageView *view([self packageView]);
+        PackageController *view([self packageController]);
         [view setPackage:package];
         return view;
     } else {
@@ -8226,7 +8481,7 @@ static _finline void _setHomePage(Cydia *self) {
     }
 }
 
-- (UIViewController *) pageForURL:(NSURL *)url hasTag:(int *)tag {
+- (CYViewController *) pageForURL:(NSURL *)url hasTag:(int *)tag {
     if (tag != NULL)
         *tag = -1;
 
@@ -8245,21 +8500,21 @@ static _finline void _setHomePage(Cydia *self) {
         path = [@"/" stringByAppendingString:path];
 
     if ([path isEqualToString:@"/add-source"])
-        return [[[AddSourceView alloc] initWithDatabase:database_] autorelease];
+        return [[[AddSourceController alloc] initWithDatabase:database_] autorelease];
     else if ([path isEqualToString:@"/storage"])
         return [self _pageForURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"storage" ofType:@"html"]] withClass:[CYBrowserController class]];
     else if ([path isEqualToString:@"/sources"])
         return [[[SourceTable alloc] initWithDatabase:database_] autorelease];
     else if ([path isEqualToString:@"/packages"])
-        return [[[InstalledView alloc] initWithDatabase:database_] autorelease];
+        return [[[InstalledController alloc] initWithDatabase:database_] autorelease];
     else if ([path hasPrefix:@"/url/"])
         return [self _pageForURL:[NSURL URLWithString:[path substringFromIndex:5]] withClass:[CYBrowserController class]];
     else if ([path hasPrefix:@"/launch/"])
         [self launchApplicationWithIdentifier:[path substringFromIndex:8] suspended:NO];
     else if ([path hasPrefix:@"/package-settings/"])
-        return [[[SettingsView alloc] initWithDatabase:database_ package:[path substringFromIndex:18]] autorelease];
+        return [[[SettingsController alloc] initWithDatabase:database_ package:[path substringFromIndex:18]] autorelease];
     else if ([path hasPrefix:@"/package-signature/"])
-        return [[[SignatureView alloc] initWithDatabase:database_ package:[path substringFromIndex:19]] autorelease];
+        return [[[SignatureController alloc] initWithDatabase:database_ package:[path substringFromIndex:19]] autorelease];
     else if ([path hasPrefix:@"/package/"])
         return [self pageForPackage:[path substringFromIndex:9]];
     else if ([path hasPrefix:@"/files/"]) {
@@ -8278,13 +8533,21 @@ static _finline void _setHomePage(Cydia *self) {
 - (void) applicationOpenURL:(NSURL *)url {
     [super applicationOpenURL:url];
     int tag;
-    if (UIViewController *page = [self pageForURL:url hasTag:&tag]) {
+    if (CYViewController *page = [self pageForURL:url hasTag:&tag]) {
         [self setPage:page];
         tag_ = tag;
         [tabbar_ setSelectedViewController:(tag_ == -1 ? nil : [[tabbar_ viewControllers] objectAtIndex:tag_])];
     }
 }
 
+- (void) applicationWillResignActive:(UIApplication *)application {
+    // Stop refreshing if you get a phone call or lock the device.
+    if ([container_ updating]) [container_ cancelUpdate];
+
+    if ([[self superclass] instancesRespondToSelector:@selector(applicationWillResignActive:)])
+        [super applicationWillResignActive:application];
+}
+
 - (void) applicationDidFinishLaunching:(id)unused {
     [CYBrowserController _initialize];
 
@@ -8342,44 +8605,48 @@ static _finline void _setHomePage(Cydia *self) {
         return;
     }
 
-    if (Role_ == nil)
-        [self askForSettings];
-
     _trace();
 
-    NSMutableArray *controllers = [NSMutableArray array];
-    [controllers addObject:[[CYNavigationController alloc] initWithDatabase:database_]];
-    [controllers addObject:[[CYNavigationController alloc] initWithDatabase:database_]];
-    [controllers addObject:[[CYNavigationController alloc] initWithDatabase:database_]];
-    if (IsWildcat_) [controllers addObject:[[CYNavigationController alloc] initWithDatabase:database_]];
-    [controllers addObject:[[CYNavigationController alloc] initWithDatabase:database_]];
-    [controllers addObject:[[CYNavigationController alloc] initWithDatabase:database_]];
-
-    NSMutableArray *items = [NSMutableArray arrayWithObjects:
+    NSMutableArray *items([NSMutableArray arrayWithObjects:
         [[[UITabBarItem alloc] initWithTitle:@"Cydia" image:[UIImage applicationImageNamed:@"home.png"] tag:kCydiaTag] autorelease],
         [[[UITabBarItem alloc] initWithTitle:UCLocalize("SECTIONS") image:[UIImage applicationImageNamed:@"install.png"] tag:kSectionsTag] autorelease],
         [[[UITabBarItem alloc] initWithTitle:UCLocalize("CHANGES") image:[UIImage applicationImageNamed:@"changes.png"] tag:kChangesTag] autorelease],
         [[[UITabBarItem alloc] initWithTitle:UCLocalize("SEARCH") image:[UIImage applicationImageNamed:@"search.png"] tag:kSearchTag] autorelease],
-        nil
-    ];
-    
+    nil]);
+
     if (IsWildcat_) {
         [items insertObject:[[[UITabBarItem alloc] initWithTitle:UCLocalize("SOURCES") image:[UIImage applicationImageNamed:@"source.png"] tag:kSourcesTag] autorelease] atIndex:3];
         [items insertObject:[[[UITabBarItem alloc] initWithTitle:UCLocalize("INSTALLED") image:[UIImage applicationImageNamed:@"manage.png"] tag:kInstalledTag] autorelease] atIndex:3];
     } else {
         [items insertObject:[[[UITabBarItem alloc] initWithTitle:UCLocalize("MANAGE") image:[UIImage applicationImageNamed:@"manage.png"] tag:kManageTag] autorelease] atIndex:3];
     }
-    
-    for (int i = 0; i < [items count]; i++) {
-        [[controllers objectAtIndex:i] setTabBarItem:[items objectAtIndex:i]];
+
+    NSMutableArray *controllers([NSMutableArray array]);
+
+    for (UITabBarItem *item in items) {
+        CYNavigationController *controller([[[CYNavigationController alloc] initWithDatabase:database_] autorelease]);
+        [controller setTabBarItem:item];
+        [controllers addObject:controller];
     }
-    
+
     tabbar_ = [[CYTabBarController alloc] initWithDatabase:database_];
-    [tabbar_ setUpdateDelegate:self];
     [tabbar_ setViewControllers:controllers];
     [tabbar_ setDelegate:self];
     [tabbar_ setSelectedIndex:0];
-    [window_ addSubview:[tabbar_ view]];
+
+    container_ = [[CYContainer alloc] initWithDatabase:database_];
+    [container_ setUpdateDelegate:self];
+    [container_ setTabBarController:tabbar_];
+    [window_ addSubview:[container_ view]];
+
+    [self performSelector:@selector(loadData) withObject:nil afterDelay:0];
+}
+
+- (void) loadData {
+    if (Role_ == nil) {
+        [self showSettings];
+        return;
+    }
 
     [UIKeyboard initImplementationNow];
 
@@ -8387,8 +8654,8 @@ static _finline void _setHomePage(Cydia *self) {
 
 #if RecyclePackageViews
     details_ = [[NSMutableArray alloc] initWithCapacity:4];
-    [details_ addObject:[self _packageView]];
-    [details_ addObject:[self _packageView]];
+    [details_ addObject:[self _packageController]];
+    [details_ addObject:[self _packageController]];
 #endif
 
     PrintTimes();
@@ -8428,6 +8695,27 @@ MSHook(void, UIWebDocumentView$_setUIKitDelegate$, UIWebDocumentView *self, SEL
     return _UIWebDocumentView$_setUIKitDelegate$(self, _cmd, delegate);
 }
 
+static NSNumber *shouldPlayKeyboardSounds;
+
+Class $UIHardware;
+
+MSHook(void, UIHardware$_playSystemSound$, Class self, SEL _cmd, int sound) {
+    switch (sound) {
+        case 1104: // Keyboard Button Clicked
+        case 1105: // Keyboard Delete Repeated
+            if (shouldPlayKeyboardSounds == nil) {
+                NSDictionary *dict([[[NSDictionary alloc] initWithContentsOfFile:@"/var/mobile/Library/Preferences/com.apple.preferences.sounds.plist"] autorelease]);
+                shouldPlayKeyboardSounds = [([dict objectForKey:@"keyboard"] ?: (id) kCFBooleanTrue) retain];
+            }
+
+            if (![shouldPlayKeyboardSounds boolValue])
+                break;
+
+        default:
+            _UIHardware$_playSystemSound$(self, _cmd, sound);
+    }
+}
+
 int main(int argc, char *argv[]) { _pooled
     _trace();
 
@@ -8440,7 +8728,6 @@ int main(int argc, char *argv[]) { _pooled
     PackageName = reinterpret_cast<CYString &(*)(Package *, SEL)>(method_getImplementation(class_getInstanceMethod([Package class], @selector(cyname))));
 
     /* Library Hacks {{{ */
-    class_addMethod(objc_getClass("WebScriptObject"), @selector(countByEnumeratingWithState:objects:count:), (IMP) &WebScriptObject$countByEnumeratingWithState$objects$count$, "I20@0:4^{NSFastEnumerationState}8^@12I16");
     class_addMethod(objc_getClass("DOMNodeList"), @selector(countByEnumeratingWithState:objects:count:), (IMP) &DOMNodeList$countByEnumeratingWithState$objects$count$, "I20@0:4^{NSFastEnumerationState}8^@12I16");
 
     $WebDefaultUIKitDelegate = objc_getClass("WebDefaultUIKitDelegate");
@@ -8449,6 +8736,13 @@ int main(int argc, char *argv[]) { _pooled
         _UIWebDocumentView$_setUIKitDelegate$ = reinterpret_cast<void (*)(UIWebDocumentView *, SEL, id)>(method_getImplementation(UIWebDocumentView$_setUIKitDelegate$));
         method_setImplementation(UIWebDocumentView$_setUIKitDelegate$, reinterpret_cast<IMP>(&$UIWebDocumentView$_setUIKitDelegate$));
     }
+
+    $UIHardware = objc_getClass("UIHardware");
+    Method UIHardware$_playSystemSound$(class_getClassMethod($UIHardware, @selector(_playSystemSound:)));
+    if (UIHardware$_playSystemSound$ != NULL) {
+        _UIHardware$_playSystemSound$ = reinterpret_cast<void (*)(Class, SEL, int)>(method_getImplementation(UIHardware$_playSystemSound$));
+        method_setImplementation(UIHardware$_playSystemSound$, reinterpret_cast<IMP>(&$UIHardware$_playSystemSound$));
+    }
     /* }}} */
     /* Set Locale {{{ */
     Locale_ = CFLocaleCopyCurrent();
@@ -8685,10 +8979,10 @@ int main(int argc, char *argv[]) { _pooled
     Warning_ = UCLocalize("WARNING");
 
     _trace();
-    int value = UIApplicationMain(argc, argv, @"Cydia", @"Cydia");
+    int value(UIApplicationMain(argc, argv, @"Cydia", @"Cydia"));
 
     CGColorSpaceRelease(space_);
     CFRelease(Locale_);
 
     return value;
-}
\ No newline at end of file
+}