+ NSURL *url([NSURL URLWithString:href]);
+
+ NSStringEncoding encoding;
+ NSError *error(nil);
+
+ if (NSString *warning = [NSString stringWithContentsOfURL:url usedEncoding:&encoding error:&error])
+ return [warning length] == 0 ? nil : warning;
+ return nil;
+}
+
+- (void) _endConnection:(NSURLConnection *)connection {
+ NSURLConnection **field = NULL;
+ if (connection == trivial_bz2_)
+ field = &trivial_bz2_;
+ else if (connection == trivial_gz_)
+ field = &trivial_gz_;
+ _assert(field != NULL);
+ [connection release];
+ *field = nil;
+
+ if (
+ trivial_bz2_ == nil &&
+ trivial_gz_ == nil
+ ) {
+ bool defer(false);
+
+ if (trivial_) {
+ if (NSString *warning = [self yieldToSelector:@selector(getWarning)]) {
+ defer = true;
+
+ UIActionSheet *sheet = [[[UIActionSheet alloc]
+ initWithTitle:CYLocalize("SOURCE_WARNING")
+ buttons:[NSArray arrayWithObjects:CYLocalize("ADD_ANYWAY"), CYLocalize("CANCEL"), nil]
+ defaultButtonIndex:0
+ delegate:self
+ context:@"warning"
+ ] autorelease];
+
+ [sheet setNumberOfRows:1];
+
+ [sheet setBodyText:warning];
+ [sheet popupAlertAnimated:YES];
+ } else
+ [self complete];
+ } else if (error_ != nil) {
+ UIActionSheet *sheet = [[[UIActionSheet alloc]
+ initWithTitle:CYLocalize("VERIFICATION_ERROR")
+ buttons:[NSArray arrayWithObjects:CYLocalize("OK"), nil]
+ defaultButtonIndex:0
+ delegate:self
+ context:@"urlerror"
+ ] autorelease];
+
+ [sheet setBodyText:[error_ localizedDescription]];
+ [sheet popupAlertAnimated:YES];
+ } else {
+ UIActionSheet *sheet = [[[UIActionSheet alloc]
+ initWithTitle:CYLocalize("NOT_REPOSITORY")
+ buttons:[NSArray arrayWithObjects:CYLocalize("OK"), nil]
+ defaultButtonIndex:0
+ delegate:self
+ context:@"trivial"
+ ] autorelease];
+
+ [sheet setBodyText:CYLocalize("NOT_REPOSITORY_EX")];
+ [sheet popupAlertAnimated:YES];
+ }
+
+ [delegate_ setStatusBarShowsProgress:NO];
+ [delegate_ removeProgressHUD:hud_];
+
+ [hud_ autorelease];
+ hud_ = nil;
+
+ if (!defer) {
+ [href_ release];
+ href_ = nil;
+ }
+
+ if (error_ != nil) {
+ [error_ release];
+ error_ = nil;
+ }
+ }
+}
+
+- (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response {
+ switch ([response statusCode]) {
+ case 200:
+ trivial_ = YES;
+ }
+}
+
+- (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
+ lprintf("connection:\"%s\" didFailWithError:\"%s\"", [href_ UTF8String], [[error localizedDescription] UTF8String]);
+ if (error_ != nil)
+ error_ = [error retain];
+ [self _endConnection:connection];
+}
+
+- (void) connectionDidFinishLoading:(NSURLConnection *)connection {
+ [self _endConnection:connection];
+}
+
+- (NSURLConnection *) _requestHRef:(NSString *)href method:(NSString *)method {
+ NSMutableURLRequest *request = [NSMutableURLRequest
+ requestWithURL:[NSURL URLWithString:href]
+ cachePolicy:NSURLRequestUseProtocolCachePolicy
+ timeoutInterval:20.0
+ ];
+
+ [request setHTTPMethod:method];
+
+ if (Machine_ != NULL)
+ [request setValue:[NSString stringWithUTF8String:Machine_] forHTTPHeaderField:@"X-Machine"];
+ if (UniqueID_ != nil)
+ [request setValue:UniqueID_ forHTTPHeaderField:@"X-Unique-ID"];
+
+ if (Role_ != nil)
+ [request setValue:Role_ forHTTPHeaderField:@"X-Role"];
+
+ return [[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease];
+}
+
+- (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
+ NSString *context([sheet context]);
+
+ if ([context isEqualToString:@"source"]) {
+ switch (button) {
+ case 1: {
+ NSString *href = [[sheet textField] text];
+
+ //installer_ = [[self _requestHRef:href method:@"GET"] retain];
+
+ if (![href hasSuffix:@"/"])
+ href_ = [href stringByAppendingString:@"/"];
+ else
+ href_ = href;
+ href_ = [href_ retain];
+
+ trivial_bz2_ = [[self _requestHRef:[href_ stringByAppendingString:@"Packages.bz2"] method:@"HEAD"] retain];
+ trivial_gz_ = [[self _requestHRef:[href_ stringByAppendingString:@"Packages.gz"] method:@"HEAD"] retain];
+ //trivial_bz2_ = [[self _requestHRef:[href stringByAppendingString:@"dists/Release"] method:@"HEAD"] retain];
+
+ trivial_ = false;
+
+ hud_ = [[delegate_ addProgressHUD] retain];
+ [hud_ setText:CYLocalize("VERIFYING_URL")];
+ } break;
+
+ case 2:
+ break;
+
+ default:
+ _assert(false);
+ }
+
+ [sheet dismiss];
+ } else if ([context isEqualToString:@"trivial"])
+ [sheet dismiss];
+ else if ([context isEqualToString:@"urlerror"])
+ [sheet dismiss];
+ else if ([context isEqualToString:@"warning"]) {
+ switch (button) {
+ case 1:
+ [self complete];
+ break;
+
+ case 2:
+ break;
+
+ default:
+ _assert(false);
+ }
+
+ [href_ release];
+ href_ = nil;
+
+ [sheet dismiss];
+ }
+}
+
+- (id) initWithBook:(RVBook *)book database:(Database *)database {
+ if ((self = [super initWithBook:book]) != nil) {
+ database_ = database;
+ sources_ = [[NSMutableArray arrayWithCapacity:16] retain];
+
+ //list_ = [[UITable alloc] initWithFrame:[self bounds]];
+ list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:NO];
+ [list_ setShouldHideHeaderInShortLists:NO];
+
+ [self addSubview:list_];
+ [list_ setDataSource:self];
+
+ UITableColumn *column = [[UITableColumn alloc]
+ initWithTitle:CYLocalize("NAME")
+ identifier:@"name"
+ width:[self frame].size.width
+ ];
+
+ UITable *table = [list_ table];
+ [table setSeparatorStyle:1];
+ [table addTableColumn:column];
+ [table setDelegate:self];
+
+ [self reloadData];
+
+ [self setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
+ [list_ setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
+ } return self;
+}
+
+- (void) reloadData {
+ pkgSourceList list;
+ _assert(list.ReadMainList());
+
+ [sources_ removeAllObjects];
+ [sources_ addObjectsFromArray:[database_ sources]];
+ _trace();
+ [sources_ sortUsingSelector:@selector(compareByNameAndType:)];
+ _trace();
+
+ int count = [sources_ count];
+ for (offset_ = 0; offset_ != count; ++offset_) {
+ Source *source = [sources_ objectAtIndex:offset_];
+ if ([source record] == nil)
+ break;
+ }
+
+ [list_ reloadData];
+}
+
+- (void) resetViewAnimated:(BOOL)animated {
+ [list_ resetViewAnimated:animated];
+}
+
+- (void) _leftButtonClicked {
+ /*[book_ pushPage:[[[AddSourceView alloc]
+ initWithBook:book_
+ database:database_
+ ] autorelease]];*/
+
+ UIActionSheet *sheet = [[[UIActionSheet alloc]
+ initWithTitle:CYLocalize("ENTER_APT_URL")
+ buttons:[NSArray arrayWithObjects:CYLocalize("ADD_SOURCE"), CYLocalize("CANCEL"), nil]
+ defaultButtonIndex:0
+ delegate:self
+ context:@"source"
+ ] autorelease];
+
+ [sheet setNumberOfRows:1];
+
+ [sheet addTextFieldWithValue:@"http://" label:@""];
+
+ UITextInputTraits *traits = [[sheet textField] textInputTraits];
+ [traits setAutocapitalizationType:UITextAutocapitalizationTypeNone];
+ [traits setAutocorrectionType:UITextAutocorrectionTypeNo];
+ [traits setKeyboardType:UIKeyboardTypeURL];
+ // XXX: UIReturnKeyDone
+ [traits setReturnKeyType:UIReturnKeyNext];
+
+ [sheet popupAlertAnimated:YES];
+}
+
+- (void) _rightButtonClicked {
+ UITable *table = [list_ table];
+ BOOL editing = [table isRowDeletionEnabled];
+ [table enableRowDeletion:!editing animated:YES];
+ [book_ reloadButtonsForPage:self];
+}
+
+- (NSString *) title {
+ return CYLocalize("SOURCES");
+}
+
+- (NSString *) leftButtonTitle {
+ return [[list_ table] isRowDeletionEnabled] ? CYLocalize("ADD") : nil;
+}
+
+- (id) rightButtonTitle {
+ return [[list_ table] isRowDeletionEnabled] ? CYLocalize("DONE") : CYLocalize("EDIT");
+}
+
+- (UINavigationButtonStyle) rightButtonStyle {
+ return [[list_ table] isRowDeletionEnabled] ? UINavigationButtonStyleHighlighted : UINavigationButtonStyleNormal;
+}
+
+@end
+/* }}} */
+
+/* Installed View {{{ */
+@interface InstalledView : RVPage {
+ _transient Database *database_;
+ FilteredPackageTable *packages_;
+ BOOL expert_;
+}
+
+- (id) initWithBook:(RVBook *)book database:(Database *)database;
+
+@end
+
+@implementation InstalledView
+
+- (void) dealloc {
+ [packages_ release];
+ [super dealloc];
+}
+
+- (id) initWithBook:(RVBook *)book database:(Database *)database {
+ if ((self = [super initWithBook:book]) != nil) {
+ database_ = database;
+
+ packages_ = [[FilteredPackageTable alloc]
+ initWithBook:book
+ database:database
+ title:nil
+ filter:@selector(isInstalledAndVisible:)
+ with:[NSNumber numberWithBool:YES]
+ ];
+
+ [self addSubview:packages_];
+
+ [self setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
+ [packages_ setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
+ } return self;
+}
+
+- (void) resetViewAnimated:(BOOL)animated {
+ [packages_ resetViewAnimated:animated];
+}
+
+- (void) reloadData {
+ [packages_ reloadData];
+}
+
+- (void) _rightButtonClicked {
+ [packages_ setObject:[NSNumber numberWithBool:expert_]];
+ [packages_ reloadData];
+ expert_ = !expert_;
+ [book_ reloadButtonsForPage:self];
+}
+
+- (NSString *) title {
+ return CYLocalize("INSTALLED");
+}
+
+- (NSString *) backButtonTitle {
+ return CYLocalize("PACKAGES");
+}
+
+- (id) rightButtonTitle {
+ return Role_ != nil && [Role_ isEqualToString:@"Developer"] ? nil : expert_ ? CYLocalize("EXPERT") : CYLocalize("SIMPLE");
+}
+
+- (UINavigationButtonStyle) rightButtonStyle {
+ return expert_ ? UINavigationButtonStyleHighlighted : UINavigationButtonStyleNormal;
+}
+
+- (void) setDelegate:(id)delegate {
+ [super setDelegate:delegate];
+ [packages_ setDelegate:delegate];
+}
+
+@end
+/* }}} */
+
+/* Home View {{{ */
+@interface HomeView : BrowserView {
+}
+
+@end
+
+@implementation HomeView
+
+- (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
+ NSString *context([sheet context]);
+
+ if ([context isEqualToString:@"about"])
+ [sheet dismiss];
+ else
+ [super alertSheet:sheet buttonClicked:button];
+}
+
+- (void) _leftButtonClicked {
+ UIActionSheet *sheet = [[[UIActionSheet alloc]
+ initWithTitle:CYLocalize("ABOUT_CYDIA")
+ buttons:[NSArray arrayWithObjects:CYLocalize("CLOSE"), nil]
+ defaultButtonIndex:0
+ delegate:self
+ context:@"about"
+ ] autorelease];
+
+ [sheet setBodyText:
+ @"Copyright (C) 2008-2009\n"
+ "Jay Freeman (saurik)\n"
+ "saurik@saurik.com\n"
+ "http://www.saurik.com/\n"
+ "\n"
+ "The Okori Group\n"
+ "http://www.theokorigroup.com/\n"
+ "\n"
+ "College of Creative Studies,\n"
+ "University of California,\n"
+ "Santa Barbara\n"
+ "http://www.ccs.ucsb.edu/"
+ ];
+
+ [sheet popupAlertAnimated:YES];
+}
+
+- (NSString *) leftButtonTitle {
+ return CYLocalize("ABOUT");
+}
+
+@end
+/* }}} */
+/* Manage View {{{ */
+@interface ManageView : BrowserView {
+}
+
+@end
+
+@implementation ManageView
+
+- (NSString *) title {
+ return CYLocalize("MANAGE");
+}
+
+- (void) _leftButtonClicked {
+ [delegate_ askForSettings];
+}
+
+- (NSString *) leftButtonTitle {
+ return CYLocalize("SETTINGS");
+}
+
+#if !AlwaysReload
+- (id) _rightButtonTitle {
+ return Queuing_ ? CYLocalize("QUEUE") : nil;
+}
+
+- (UINavigationButtonStyle) rightButtonStyle {
+ return Queuing_ ? UINavigationButtonStyleHighlighted : UINavigationButtonStyleNormal;
+}
+
+- (void) _rightButtonClicked {
+ [delegate_ queue];
+}
+#endif
+
+- (bool) isLoading {
+ return false;
+}
+
+@end
+/* }}} */
+
+#include <BrowserView.m>
+
+/* Cydia Book {{{ */
+@interface CYBook : RVBook <
+ ProgressDelegate
+> {
+ _transient Database *database_;
+ UINavigationBar *overlay_;
+ UINavigationBar *underlay_;