X-Git-Url: https://git.saurik.com/cydia.git/blobdiff_plain/10aba831171836876900e412f066286a0d847358..b13b8664e70405f065a37d67fb4eb7c39a6a438b:/MobileCydia.mm diff --git a/MobileCydia.mm b/MobileCydia.mm index 47b1d49d..b14cda12 100644 --- a/MobileCydia.mm +++ b/MobileCydia.mm @@ -307,12 +307,13 @@ static _finline void UpdateExternalStatus(uint64_t newStatus) { } - (int) yieldToPopupAlertAnimated:(BOOL)animated; + @end @implementation CYAlertView - (id) initWithTitle:(NSString *)title buttons:(NSArray *)buttons defaultButtonIndex:(int)index { - if ((self = [super init])) { + if ((self = [super init]) != nil) { [self setTitle:title]; [self setDelegate:self]; for (NSString *button in buttons) [self addButtonWithTitle:button]; @@ -366,7 +367,6 @@ static const CFStringCompareFlags LaxCompareFlags_ = kCFCompareCaseInsensitive | #define TrackResize (0 && !ForRelease) #define ManualRefresh (1 && !ForRelease) #define ShowInternals (0 && !ForRelease) -#define IgnoreInstall (0 && !ForRelease) #define AlwaysReload (0 && !ForRelease) #define TryIndexedCollation (0 && !ForRelease) @@ -872,6 +872,7 @@ class Pcre { + (Address *) addressWithString:(NSString *)string; - (Address *) initWithString:(NSString *)string; + @end @implementation Address @@ -905,7 +906,10 @@ class Pcre { } + (NSArray *) _attributeKeys { - return [NSArray arrayWithObjects:@"address", @"name", nil]; + return [NSArray arrayWithObjects: + @"address", + @"name", + nil]; } - (NSArray *) attributeKeys { @@ -980,6 +984,8 @@ class CYColor { /* Random Global Variables {{{ */ static const int PulseInterval_ = 50000; +static const NSString *UI_; + static int Finish_; static NSArray *Finishes_; @@ -1039,6 +1045,7 @@ static bool Changed_; static time_t now_; bool IsWildcat_; +static CGFloat ScreenScale_; /* }}} */ /* Display Helpers {{{ */ @@ -1046,23 +1053,6 @@ inline float Interpolate(float begin, float end, float fraction) { return (end - begin) * fraction + begin; } -/* XXX: localize this! */ -NSString *SizeString(double size) { - bool negative = size < 0; - if (negative) - size = -size; - - unsigned power = 0; - while (size > 1024) { - size /= 1024; - ++power; - } - - static const char *powers_[] = {"B", "kB", "MB", "GB"}; - - return [NSString stringWithFormat:@"%s%.1f %s", (negative ? "-" : ""), size, powers_[power]]; -} - static _finline const char *StripVersion_(const char *version) { const char *colon(strchr(version, ':')); return colon == NULL ? version : colon + 1; @@ -1118,7 +1108,7 @@ NSString *GetLastUpdate() { } bool isSectionVisible(NSString *section) { - NSDictionary *metadata([Sections_ objectForKey:section]); + NSDictionary *metadata([Sections_ objectForKey:(section ?: @"")]); NSNumber *hidden(metadata == nil ? nil : [metadata objectForKey:@"Hidden"]); return hidden == nil || ![hidden boolValue]; } @@ -1166,6 +1156,7 @@ bool isSectionVisible(NSString *section) { - (void) removeProgressHUD:(UIProgressHUD *)hud; - (CYViewController *) pageForPackage:(NSString *)name; - (void) showActionSheet:(UIActionSheet *)sheet fromItem:(UIBarButtonItem *)item; +- (void) reloadDataWithInvocation:(NSInvocation *)invocation; @end static id CydiaApp; @@ -1344,7 +1335,8 @@ typedef std::map< unsigned long, _H > SourceMap; - (pkgSourceList &) list; - (NSArray *) packages; - (NSArray *) sources; -- (void) reloadData; +- (Source *) sourceWithKey:(NSString *)key; +- (void) reloadDataWithInvocation:(NSInvocation *)invocation; - (void) configure; - (bool) prepare; @@ -1589,7 +1581,19 @@ static void PackageImport(const void *key, const void *value, void *context) { } + (NSArray *) _attributeKeys { - return [NSArray arrayWithObjects:@"description", @"distribution", @"host", @"key", @"label", @"name", @"origin", @"trusted", @"type", @"uri", @"version", nil]; + return [NSArray arrayWithObjects: + @"description", + @"distribution", + @"host", + @"key", + @"label", + @"name", + @"origin", + @"trusted", + @"type", + @"uri", + @"version", + nil]; } - (NSArray *) attributeKeys { @@ -1754,37 +1758,176 @@ static void PackageImport(const void *key, const void *value, void *context) { @end /* }}} */ -/* Relationship Class {{{ */ -@interface Relationship : NSObject { - NSString *type_; - NSString *id_; +/* CydiaOperation Class {{{ */ +@interface CydiaOperation : NSObject { + NSString *operator_; + NSString *value_; } -- (NSString *) type; -- (NSString *) id; -- (NSString *) name; +- (NSString *) operator; +- (NSString *) value; @end -@implementation Relationship +@implementation CydiaOperation - (void) dealloc { - [type_ release]; - [id_ release]; + [operator_ release]; + [value_ release]; [super dealloc]; } -- (NSString *) type { - return type_; +- (id) initWithOperator:(const char *)_operator value:(const char *)value { + if ((self = [super init]) != nil) { + operator_ = [[NSString alloc] initWithUTF8String:_operator]; + value_ = [[NSString alloc] initWithUTF8String:value]; + } return self; } -- (NSString *) id { - return id_; ++ (NSArray *) _attributeKeys { + return [NSArray arrayWithObjects: + @"operator", + @"value", + nil]; } -- (NSString *) name { - _assert(false); - return nil; +- (NSArray *) attributeKeys { + return [[self class] _attributeKeys]; +} + ++ (BOOL) isKeyExcludedFromWebScript:(const char *)name { + return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name]; +} + +- (NSString *) operator { + return operator_; +} + +- (NSString *) value { + return value_; +} + +@end +/* }}} */ +/* CydiaClause Class {{{ */ +@interface CydiaClause : NSObject { + NSString *package_; + CydiaOperation *version_; +} + +- (NSString *) package; +- (CydiaOperation *) version; + +@end + +@implementation CydiaClause + +- (void) dealloc { + [package_ release]; + [version_ release]; + [super dealloc]; +} + +- (id) initWithIterator:(pkgCache::DepIterator &)dep { + if ((self = [super init]) != nil) { + package_ = [[NSString alloc] initWithUTF8String:dep.TargetPkg().Name()]; + + if (const char *version = dep.TargetVer()) + version_ = [[CydiaOperation alloc] initWithOperator:dep.CompType() value:version]; + else + version_ = [[NSNull null] retain]; + } return self; +} + ++ (NSArray *) _attributeKeys { + return [NSArray arrayWithObjects: + @"package", + @"version", + nil]; +} + +- (NSArray *) attributeKeys { + return [[self class] _attributeKeys]; +} + ++ (BOOL) isKeyExcludedFromWebScript:(const char *)name { + return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name]; +} + +- (NSString *) package { + return package_; +} + +- (CydiaOperation *) version { + return version_; +} + +@end +/* }}} */ +/* CydiaRelation Class {{{ */ +@interface CydiaRelation : NSObject { + NSString *relationship_; + NSMutableArray *clauses_; +} + +- (NSString *) relationship; +- (NSArray *) clauses; + +@end + +@implementation CydiaRelation + +- (void) dealloc { + [relationship_ release]; + [clauses_ release]; + [super dealloc]; +} + +- (id) initWithIterator:(pkgCache::DepIterator &)dep { + if ((self = [super init]) != nil) { + relationship_ = [[NSString alloc] initWithUTF8String:dep.DepType()]; + clauses_ = [[NSMutableArray alloc] initWithCapacity:8]; + + pkgCache::DepIterator start; + pkgCache::DepIterator end; + dep.GlobOr(start, end); // ++dep + + _forever { + [clauses_ addObject:[[[CydiaClause alloc] initWithIterator:start] autorelease]]; + + // yes, seriously. (wtf?) + if (start == end) + break; + ++start; + } + } return self; +} + ++ (NSArray *) _attributeKeys { + return [NSArray arrayWithObjects: + @"clauses", + @"relationship", + nil]; +} + +- (NSArray *) attributeKeys { + return [[self class] _attributeKeys]; +} + ++ (BOOL) isKeyExcludedFromWebScript:(const char *)name { + return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name]; +} + +- (NSString *) relationship { + return relationship_; +} + +- (NSArray *) clauses { + return clauses_; +} + +- (void) addClause:(CydiaClause *)clause { + [clauses_ addObject:clause]; } @end @@ -2064,8 +2207,15 @@ struct PackageNameOrdering : } + (NSString *) webScriptNameForSelector:(SEL)selector { - if (selector == @selector(hasTag:)) + if (false); + else if (selector == @selector(clear)) + return @"clear"; + else if (selector == @selector(hasTag:)) return @"hasTag"; + else if (selector == @selector(install)) + return @"install"; + else if (selector == @selector(remove)) + return @"remove"; else return nil; } @@ -2075,7 +2225,33 @@ struct PackageNameOrdering : } + (NSArray *) _attributeKeys { - return [NSArray arrayWithObjects:@"applications", @"author", @"depiction", @"longDescription", @"essential", @"homepage", @"icon", @"id", @"installed", @"latest", @"longSection", @"maintainer", @"mode", @"name", @"purposes", @"section", @"shortDescription", @"shortSection", @"simpleSection", @"size", @"source", @"sponsor", @"support", @"warnings", nil]; + return [NSArray arrayWithObjects: + @"applications", + @"author", + @"depiction", + @"essential", + @"homepage", + @"icon", + @"id", + @"installed", + @"latest", + @"longDescription", + @"longSection", + @"maintainer", + @"mode", + @"name", + @"purposes", + @"relations", + @"section", + @"shortDescription", + @"shortSection", + @"simpleSection", + @"size", + @"source", + @"sponsor", + @"support", + @"warnings", + nil]; } - (NSArray *) attributeKeys { @@ -2086,6 +2262,14 @@ struct PackageNameOrdering : return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name]; } +- (NSArray *) relations { +@synchronized (database_) { + NSMutableArray *relations([NSMutableArray arrayWithCapacity:16]); + for (pkgCache::DepIterator dep(version_.DependsList()); !dep.end(); ++dep) + [relations addObject:[[[CydiaRelation alloc] initWithIterator:dep] autorelease]]; + return relations; +} } + - (void) parse { if (parsed_ != NULL) return; @@ -2477,7 +2661,7 @@ struct PackageNameOrdering : _end _profile(Package$visible$isSectionVisible) - if (section != nil && !isSectionVisible(section)) + if (!isSectionVisible(section)) return false; _end @@ -3019,7 +3203,7 @@ static NSString *Warning_; // XXX: actually implement this thing _assert(false); if (deadSources_) - CFRelease(deadSources_); + CFRelease(deadSources_); [self releasePackages]; apr_pool_destroy(pool_); NSRecycleZone(zone_); @@ -3216,70 +3400,11 @@ static NSString *Warning_; return sources; } -- (NSArray *) issues { - if (cache_->BrokenCount() == 0) - return nil; - - NSMutableArray *issues([NSMutableArray arrayWithCapacity:4]); - - for (Package *package in [self packages]) { - if (![package broken]) - continue; - pkgCache::PkgIterator pkg([package iterator]); - - NSMutableArray *entry([NSMutableArray arrayWithCapacity:4]); - [entry addObject:[package name]]; - [issues addObject:entry]; - - pkgCache::VerIterator ver(cache_[pkg].InstVerIter(cache_)); - if (ver.end()) - continue; - - for (pkgCache::DepIterator dep(ver.DependsList()); !dep.end(); ) { - pkgCache::DepIterator start; - pkgCache::DepIterator end; - dep.GlobOr(start, end); // ++dep - - if (!cache_->IsImportantDep(end)) - continue; - if ((cache_[end] & pkgDepCache::DepGInstall) != 0) - continue; - - NSMutableArray *failure([NSMutableArray arrayWithCapacity:4]); - [entry addObject:failure]; - [failure addObject:[NSString stringWithUTF8String:start.DepType()]]; - - NSString *name([NSString stringWithUTF8String:start.TargetPkg().Name()]); - if (Package *package = [self packageWithName:name]) - name = [package name]; - [failure addObject:name]; - - pkgCache::PkgIterator target(start.TargetPkg()); - if (target->ProvidesList != 0) - [failure addObject:@"?"]; - else { - pkgCache::VerIterator ver(cache_[target].InstVerIter(cache_)); - if (!ver.end()) - [failure addObject:[NSString stringWithUTF8String:ver.VerStr()]]; - else if (!cache_[target].CandidateVerIter(cache_).end()) - [failure addObject:@"-"]; - else if (target->ProvidesList == 0) - [failure addObject:@"!"]; - else - [failure addObject:@"%"]; - } - - _forever { - if (start.TargetVer() != 0) - [failure addObject:[NSString stringWithFormat:@"%s %s", start.CompType(), start.TargetVer()]]; - if (start == end) - break; - ++start; - } - } - } - - return issues; +- (Source *) sourceWithKey:(NSString *)key { + for (Source *source in [self sources]) { + if ([[source key] isEqualToString:key]) + return source; + } return nil; } - (bool) popErrorWithTitle:(NSString *)title { @@ -3314,7 +3439,7 @@ static NSString *Warning_; return [self popErrorWithTitle:title] || !success; } -- (void) reloadData { CYPoolStart() { +- (void) reloadDataWithInvocation:(NSInvocation *)invocation { CYPoolStart() { @synchronized (self) { ++era_; @@ -3350,10 +3475,13 @@ static NSString *Warning_; if (chk != -1) close(chk); + if (invocation != nil) + [invocation invoke]; + NSString *title(UCLocalize("DATABASE")); _trace(); - if (!cache_.Open(progress_, true)) { pop: + while (!cache_.Open(progress_, true)) { pop: std::string error; bool warning(!_error->PopMessage(error)); lprintf("cache_.Open():[%s]\n", error.c_str()); @@ -3363,15 +3491,17 @@ static NSString *Warning_; else if (error == "The package lists or status file could not be parsed or opened.") [delegate_ repairWithSelector:@selector(update)]; // else if (error == "Could not open lock file /var/lib/dpkg/lock - open (13 Permission denied)") - // else if (error == "Could not get lock /var/lib/dpkg/lock - open (35 Resource temporarily unavailable)") + else if (error == "Could not get lock /var/lib/dpkg/lock - open (35 Resource temporarily unavailable)") + [delegate_ _setProgressError:[NSString stringWithUTF8String:error.c_str()] withTitle:[NSString stringWithFormat:Colon_, Error_, title]]; // else if (error == "The list of sources could not be read.") - else + else { [delegate_ _setProgressError:[NSString stringWithUTF8String:error.c_str()] withTitle:[NSString stringWithFormat:Colon_, warning ? Warning_ : Error_, title]]; + return; + } if (warning) goto pop; _error->Discard(); - return; } _trace(); @@ -3484,12 +3614,11 @@ static NSString *Warning_; delete resolver_; resolver_ = new pkgProblemResolver(cache_); - for (pkgCache::PkgIterator iterator(cache_->PkgBegin()); !iterator.end(); ++iterator) { - if (!cache_[iterator].Keep()) { + for (pkgCache::PkgIterator iterator(cache_->PkgBegin()); !iterator.end(); ++iterator) + if (!cache_[iterator].Keep()) cache_->MarkKeep(iterator, false); + else if ((cache_[iterator].iFlags & pkgDepCache::ReInstall) != 0) cache_->SetReInstall(iterator, false); - } - } } } - (void) configure { @@ -3714,6 +3843,7 @@ static NSString *Warning_; } - (id) initWithDelegate:(IndirectDelegate *)indirect; + @end @implementation CydiaObject @@ -3734,7 +3864,13 @@ static NSString *Warning_; } + (NSArray *) _attributeKeys { - return [NSArray arrayWithObjects:@"device", @"firewire", @"imei", @"mac", @"serial", nil]; + return [NSArray arrayWithObjects: + @"device", + @"firewire", + @"imei", + @"mac", + @"serial", + nil]; } - (NSArray *) attributeKeys { @@ -3772,14 +3908,21 @@ static NSString *Warning_; #endif + (NSString *) webScriptNameForSelector:(SEL)selector { - if (selector == @selector(close)) + if (false); + else if (selector == @selector(close)) return @"close"; + else if (selector == @selector(du:)) + return @"du"; + else if (selector == @selector(stringWithFormat:arguments:)) + return @"format"; else if (selector == @selector(getInstalledPackages)) return @"getInstalledPackages"; else if (selector == @selector(getPackageById:)) return @"getPackageById"; else if (selector == @selector(installPackages:)) return @"installPackages"; + else if (selector == @selector(localizedStringForKey:value:table:)) + return @"localize"; else if (selector == @selector(setButtonImage:withStyle:toFunction:)) return @"setButtonImage"; else if (selector == @selector(setButtonTitle:withStyle:toFunction:)) @@ -3792,16 +3935,10 @@ static NSString *Warning_; return @"setToken"; else if (selector == @selector(setViewportWidth:)) return @"setViewportWidth"; - else if (selector == @selector(supports:)) - return @"supports"; - else if (selector == @selector(stringWithFormat:arguments:)) - return @"format"; - else if (selector == @selector(localizedStringForKey:value:table:)) - return @"localize"; - else if (selector == @selector(du:)) - return @"du"; else if (selector == @selector(statfs:)) return @"statfs"; + else if (selector == @selector(supports:)) + return @"supports"; else return nil; } @@ -3929,7 +4066,7 @@ static NSString *Warning_; id values[count]; for (unsigned i(0); i != count; ++i) values[i] = [arguments objectAtIndex:i]; - return [[[NSString alloc] initWithFormat:format arguments:*(reinterpret_cast(&values))] autorelease]; + return [[[NSString alloc] initWithFormat:format arguments:reinterpret_cast(values)] autorelease]; } - (NSString *) localizedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)table { @@ -3957,8 +4094,8 @@ static NSString *Warning_; @implementation CYLoadingIndicator -- (id)initWithFrame:(CGRect)frame { - if ((self = [super initWithFrame:frame])) { +- (id) initWithFrame:(CGRect)frame { + if ((self = [super initWithFrame:frame]) != nil) { container_ = [[[UIView alloc] init] autorelease]; [container_ setAutoresizingMask:UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin]; @@ -3997,32 +4134,74 @@ static NSString *Warning_; [spinner_ setFrame:spinrect]; [label_ setFrame:textrect]; [self addSubview:container_]; - } + } return self; +} - return self; +- (UILabel *) label { + return label_; } -- (UILabel *)label { return label_; } -- (UIActivityIndicatorView *)activityIndicatorView { return spinner_; } +- (UIActivityIndicatorView *) activityIndicatorView { + return spinner_; +} @end /* }}} */ /* Emulated Loading Controller {{{ */ -@interface CYEmulatedLoadingController : CYViewController { +@interface CYEmulatedLoadingController : CYViewController < + ProgressDelegate, + ConfigurationDelegate +> { + _transient Database *database_; CYLoadingIndicator *indicator_; UITabBar *tabbar_; UINavigationBar *navbar_; } + @end @implementation CYEmulatedLoadingController - (void) dealloc { [self releaseSubviews]; + [database_ setDelegate:nil]; [super dealloc]; } +- (void) setProgressError:(NSString *)error withTitle:(NSString *)title { + CYAlertView *sheet([[[CYAlertView alloc] + initWithTitle:title + buttons:[NSArray arrayWithObjects:UCLocalize("OKAY"), nil] + defaultButtonIndex:0 + ] autorelease]); + + [sheet setMessage:error]; + [sheet yieldToPopupAlertAnimated:YES]; + [sheet dismiss]; +} + +- (void) setProgressTitle:(NSString *)title { } +- (void) setProgressPercent:(float)percent { } +- (void) startProgress { } +- (void) addProgressOutput:(NSString *)output { } +- (bool) isCancelling:(size_t)received { return NO; } +- (void) setConfigurationData:(NSString *)data { } + +- (void) repairWithSelector:(SEL)selector { + [[indicator_ label] performSelectorOnMainThread:@selector(setText:) withObject:[NSString stringWithFormat:Elision_, UCLocalize("REPAIRING"), nil] waitUntilDone:YES]; + [database_ performSelector:selector]; + sleep(10); + [[indicator_ label] performSelectorOnMainThread:@selector(setText:) withObject:[NSString stringWithFormat:Elision_, UCLocalize("LOADING"), nil] waitUntilDone:YES]; +} + +- (id) initWithDatabase:(Database *)database { + if ((self = [super init]) != nil) { + database_ = database; + [database_ setDelegate:self]; + } return self; +} + - (void) loadView { [self setView:[[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease]]; [[self view] setBackgroundColor:[UIColor pinStripeColor]]; @@ -4150,6 +4329,42 @@ static NSString *Warning_; @end /* }}} */ +// CydiaScript {{{ +@interface NSObject (CydiaScript) +- (id) Cydia$webScriptObjectInContext:(WebScriptObject *)context; +@end + +@implementation NSObject (CydiaScript) + +- (id) Cydia$webScriptObjectInContext:(WebScriptObject *)context { + return self; +} + +@end + +@implementation NSArray (CydiaScript) + +- (id) Cydia$webScriptObjectInContext:(WebScriptObject *)context { + WebScriptObject *object([context evaluateWebScript:@"[]"]); + for (size_t i(0), e([self count]); i != e; ++i) + [object setWebScriptValueAtIndex:i value:[[self objectAtIndex:i] Cydia$webScriptObjectInContext:context]]; + return object; +} + +@end + +@implementation NSDictionary (CydiaScript) + +- (id) Cydia$webScriptObjectInContext:(WebScriptObject *)context { + WebScriptObject *object([context evaluateWebScript:@"({})"]); + for (id i in self) + [object setValue:[[self objectForKey:i] Cydia$webScriptObjectInContext:context] forKey:i]; + return object; +} + +@end +// }}} + /* Confirmation Controller {{{ */ bool DepSubstrate(const pkgCache::VerIterator &iterator) { if (!iterator.end()) @@ -4174,10 +4389,13 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { @interface ConfirmationController : CYBrowserController { _transient Database *database_; + UIAlertView *essential_; - NSArray *changes_; - NSArray *issues_; - NSArray *sizes_; + + NSDictionary *changes_; + NSMutableArray *issues_; + NSDictionary *sizes_; + BOOL substrate_; } @@ -4189,11 +4407,12 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (void) dealloc { [changes_ release]; - if (issues_ != nil) - [issues_ release]; + [issues_ release]; [sizes_ release]; + if (essential_ != nil) [essential_ release]; + [super dealloc]; } @@ -4230,9 +4449,11 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (void) webView:(WebView *)view didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame { [super webView:view didClearWindowObject:window forFrame:frame]; - [window setValue:changes_ forKey:@"changes"]; - [window setValue:issues_ forKey:@"issues"]; - [window setValue:sizes_ forKey:@"sizes"]; + + [window setValue:[changes_ Cydia$webScriptObjectInContext:window] forKey:@"changes"]; + [window setValue:[issues_ Cydia$webScriptObjectInContext:window] forKey:@"issues"]; + [window setValue:[sizes_ Cydia$webScriptObjectInContext:window] forKey:@"sizes"]; + [window setValue:self forKey:@"queue"]; } @@ -4240,39 +4461,127 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { if ((self = [super init]) != nil) { database_ = database; - [[self navigationItem] setTitle:UCLocalize("CONFIRM")]; - - NSMutableArray *installing = [NSMutableArray arrayWithCapacity:16]; - NSMutableArray *reinstalling = [NSMutableArray arrayWithCapacity:16]; - NSMutableArray *upgrading = [NSMutableArray arrayWithCapacity:16]; - NSMutableArray *downgrading = [NSMutableArray arrayWithCapacity:16]; - NSMutableArray *removing = [NSMutableArray arrayWithCapacity:16]; + NSMutableArray *installs([NSMutableArray arrayWithCapacity:16]); + NSMutableArray *reinstalls([NSMutableArray arrayWithCapacity:16]); + NSMutableArray *upgrades([NSMutableArray arrayWithCapacity:16]); + NSMutableArray *downgrades([NSMutableArray arrayWithCapacity:16]); + NSMutableArray *removes([NSMutableArray arrayWithCapacity:16]); bool remove(false); + pkgCacheFile &cache([database_ cache]); + NSArray *packages([database_ packages]); pkgDepCache::Policy *policy([database_ policy]); - pkgCacheFile &cache([database_ cache]); - NSArray *packages = [database_ packages]; + issues_ = [[NSMutableArray arrayWithCapacity:4] retain]; + for (Package *package in packages) { - pkgCache::PkgIterator iterator = [package iterator]; + pkgCache::PkgIterator iterator([package iterator]); + NSString *name([package id]); + + if ([package broken]) { + NSMutableArray *reasons([NSMutableArray arrayWithCapacity:4]); + + [issues_ addObject:[NSDictionary dictionaryWithObjectsAndKeys: + name, @"package", + reasons, @"reasons", + nil]]; + + pkgCache::VerIterator ver(cache[iterator].InstVerIter(cache)); + if (ver.end()) + continue; + + for (pkgCache::DepIterator dep(ver.DependsList()); !dep.end(); ) { + pkgCache::DepIterator start; + pkgCache::DepIterator end; + dep.GlobOr(start, end); // ++dep + + if (!cache->IsImportantDep(end)) + continue; + if ((cache[end] & pkgDepCache::DepGInstall) != 0) + continue; + + NSMutableArray *clauses([NSMutableArray arrayWithCapacity:4]); + + [reasons addObject:[NSDictionary dictionaryWithObjectsAndKeys: + [NSString stringWithUTF8String:start.DepType()], @"relationship", + clauses, @"clauses", + nil]]; + + _forever { + NSString *reason, *installed((NSString *) [WebUndefined undefined]); + + pkgCache::PkgIterator target(start.TargetPkg()); + if (target->ProvidesList != 0) + reason = @"missing"; + else { + pkgCache::VerIterator ver(cache[target].InstVerIter(cache)); + if (!ver.end()) { + reason = @"installed"; + installed = [NSString stringWithUTF8String:ver.VerStr()]; + } else if (!cache[target].CandidateVerIter(cache).end()) + reason = @"uninstalled"; + else if (target->ProvidesList == 0) + reason = @"uninstallable"; + else + reason = @"virtual"; + } + + NSDictionary *version(start.TargetVer() == 0 ? [NSNull null] : [NSDictionary dictionaryWithObjectsAndKeys: + [NSString stringWithUTF8String:start.CompType()], @"operator", + [NSString stringWithUTF8String:start.TargetVer()], @"value", + nil]); + + [clauses addObject:[NSDictionary dictionaryWithObjectsAndKeys: + [NSString stringWithUTF8String:start.TargetPkg().Name()], @"package", + version, @"version", + reason, @"reason", + installed, @"installed", + nil]]; + + // yes, seriously. (wtf?) + if (start == end) + break; + ++start; + } + } + } + pkgDepCache::StateCache &state(cache[iterator]); - NSString *name([package name]); + static Pcre special_r("^(firmware$|gsc\\.|cy\\+)"); if (state.NewInstall()) - [installing addObject:name]; + [installs addObject:name]; else if (!state.Delete() && (state.iFlags & pkgDepCache::ReInstall) == pkgDepCache::ReInstall) - [reinstalling addObject:name]; + [reinstalls addObject:name]; else if (state.Upgrade()) - [upgrading addObject:name]; + [upgrades addObject:name]; else if (state.Downgrade()) - [downgrading addObject:name]; - else if (state.Delete()) { + [downgrades addObject:name]; + else if (!state.Delete()) + continue; + else if (special_r(name)) + [issues_ addObject:[NSDictionary dictionaryWithObjectsAndKeys: + [NSNull null], @"package", + [NSArray arrayWithObjects: + [NSDictionary dictionaryWithObjectsAndKeys: + @"Conflicts", @"relationship", + [NSArray arrayWithObjects: + [NSDictionary dictionaryWithObjectsAndKeys: + name, @"package", + [NSNull null], @"version", + @"installed", @"reason", + nil], + nil], @"clauses", + nil], + nil], @"reasons", + nil]]; + else { if ([package essential]) remove = true; - [removing addObject:name]; - } else continue; + [removes addObject:name]; + } substrate_ |= DepSubstrate(policy->GetCandidateVer(iterator)); substrate_ |= DepSubstrate(iterator.CurrentVer()); @@ -4288,7 +4597,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { message:UCLocalize("REMOVING_ESSENTIALS_EX") delegate:self cancelButtonTitle:[NSString stringWithFormat:parenthetical, UCLocalize("CANCEL_OPERATION"), UCLocalize("SAFE")] - otherButtonTitles:[NSString stringWithFormat:parenthetical, UCLocalize("FORCE_REMOVAL"), UCLocalize("UNSAFE")], nil + otherButtonTitles: + [NSString stringWithFormat:parenthetical, UCLocalize("FORCE_REMOVAL"), UCLocalize("UNSAFE")], + nil ]; [essential_ setContext:@"remove"]; @@ -4304,24 +4615,20 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [essential_ setContext:@"unable"]; } - changes_ = [[NSArray alloc] initWithObjects: - installing, - reinstalling, - upgrading, - downgrading, - removing, + changes_ = [[NSDictionary alloc] initWithObjectsAndKeys: + installs, @"installs", + reinstalls, @"reinstalls", + upgrades, @"upgrades", + downgrades, @"downgrades", + removes, @"removes", nil]; - issues_ = [database_ issues]; - if (issues_ != nil) - issues_ = [issues_ retain]; - - sizes_ = [[NSArray alloc] initWithObjects: - SizeString([database_ fetcher].FetchNeeded()), - SizeString([database_ fetcher].PartialPresent()), + sizes_ = [[NSDictionary alloc] initWithObjectsAndKeys: + [NSNumber numberWithInteger:[database_ fetcher].FetchNeeded()], @"downloading", + [NSNumber numberWithInteger:[database_ fetcher].PartialPresent()], @"resuming", nil]; - [self loadURL:[NSURL URLWithString:CydiaURL(@"ui/confirm/")]]; + [self loadURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/confirm/", UI_]]]; [[self navigationItem] setLeftBarButtonItem:[[[UIBarButtonItem alloc] initWithTitle:UCLocalize("CANCEL") @@ -4332,9 +4639,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } return self; } +#if !AlwaysReload - (void) applyRightButton { -#if !AlwaysReload && !IgnoreInstall - if (issues_ == nil && ![self isLoading]) + if ([issues_ count] == 0 && ![self isLoading]) [[self navigationItem] setRightBarButtonItem:[[[UIBarButtonItem alloc] initWithTitle:UCLocalize("CONFIRM") style:UIBarButtonItemStyleDone @@ -4342,11 +4649,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { action:@selector(confirmButtonClicked) ] autorelease]]; else - [super applyRightButton]; -#else - [[self navigationItem] setRightBarButtonItem:nil]; -#endif + [[self navigationItem] setRightBarButtonItem:nil]; } +#endif - (void) cancelButtonClicked { [self dismissModalViewControllerAnimated:YES]; @@ -4355,9 +4660,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { #if !AlwaysReload - (void) confirmButtonClicked { -#if IgnoreInstall - return; -#endif if (essential_ != nil) [essential_ show]; else { @@ -4384,6 +4686,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (SEL) selector; - (id) target; - (id) object; + @end @implementation ProgressData @@ -4536,7 +4839,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [self positionViews]; } -- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { +- (void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { [self positionViews]; } @@ -4786,8 +5089,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { message:[NSString stringWithFormat:@"%@\n\n%@", UCLocalize("CONFIGURATION_UPGRADE_EX"), ofile] delegate:self cancelButtonTitle:UCLocalize("KEEP_OLD_COPY") - otherButtonTitles:UCLocalize("ACCEPT_NEW_COPY"), - // XXX: UCLocalize("SEE_WHAT_CHANGED"), + otherButtonTitles: + UCLocalize("ACCEPT_NEW_COPY"), + // XXX: UCLocalize("SEE_WHAT_CHANGED"), nil ] autorelease]; @@ -4972,18 +5276,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } return self; } -- (void) _setBackgroundColor { - UIColor *color; - if (NSString *mode = [package_ mode]) { - bool remove([mode isEqualToString:@"REMOVE"] || [mode isEqualToString:@"PURGE"]); - color = remove ? RemovingColor_ : InstallingColor_; - } else - color = [UIColor whiteColor]; - - [content_ setBackgroundColor:color]; - [self setNeedsDisplay]; -} - - (NSString *) accessibilityLabel { return [NSString stringWithFormat:UCLocalize("COLON_DELIMITED"), name_, description_]; } @@ -5034,11 +5326,36 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { if ((badge_ = [UIImage imageAtPath:[NSString stringWithFormat:@"%@/Purposes/%@.png", App_, purpose]]) != nil) badge_ = [badge_ retain]; - if ([package installed] != nil) - if ((placard_ = [UIImage imageAtPath:[NSString stringWithFormat:@"%@/installed.png", App_]]) != nil) + UIColor *color; + NSString *placard; + + if (NSString *mode = [package_ mode]) { + if ([mode isEqualToString:@"REMOVE"] || [mode isEqualToString:@"PURGE"]) { + color = RemovingColor_; + //placard = @"removing"; + } else { + color = InstallingColor_; + //placard = @"installing"; + } + + // XXX: the removing/installing placards are not @2x + placard = nil; + } else { + color = [UIColor whiteColor]; + + if ([package installed] != nil) + placard = @"installed"; + else + placard = nil; + } + + [content_ setBackgroundColor:color]; + + if (placard != nil) + if ((placard_ = [UIImage imageAtPath:[NSString stringWithFormat:@"%@/%@.png", App_, placard]]) != nil) placard_ = [placard_ retain]; - [self _setBackgroundColor]; + [self setNeedsDisplay]; [content_ setNeedsDisplay]; } @@ -5394,8 +5711,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { UIBarButtonItem *button_; } -- (id) initWithDatabase:(Database *)database; -- (void) setPackage:(Package *)package; +- (id) initWithDatabase:(Database *)database forPackage:(NSString *)name; @end @@ -5415,12 +5731,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [super dealloc]; } -- (void) release { - [super release]; -} - - (NSURL *) navigationURL { - return [NSURL URLWithString:[NSString stringWithFormat:@"cydia://package/%@", [package_ id]]]; + return [NSURL URLWithString:[NSString stringWithFormat:@"cydia://package/%@", name_]]; } /* XXX: this is not safe at all... localization of /fail/ */ @@ -5451,11 +5763,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } } -- (void) webView:(WebView *)view didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame { - [super webView:view didClearWindowObject:window forFrame:frame]; - [window setValue:package_ forKey:@"package"]; -} - - (bool) _allowJavaScriptPanel { return commercial_; } @@ -5516,38 +5823,27 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } #endif -- (void) viewWillAppear:(BOOL)animated { - if (![self hasLoaded]) - [self loadURL:[NSURL URLWithString:CydiaURL(@"ui/package/")]]; - [super viewWillAppear:animated]; -} - -- (id) initWithDatabase:(Database *)database { +- (id) initWithDatabase:(Database *)database forPackage:(NSString *)name { if ((self = [super init]) != nil) { database_ = database; buttons_ = [[NSMutableArray alloc] initWithCapacity:4]; + name_ = [[NSString alloc] initWithString:name]; + [self setURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/package/#!/%@", UI_, name_]]]; } return self; } -- (void) setPackage:(Package *)package { - if (package_ != nil) { +- (void) reloadData { + if (package_ != nil) [package_ autorelease]; - package_ = nil; - } - - if (name_ != nil) { - [name_ release]; - name_ = nil; - } + package_ = [database_ packageWithName:name_]; [buttons_ removeAllObjects]; - if (package != nil) { - [package parse]; + if (package_ != nil) { + [package_ parse]; - package_ = [package retain]; - name_ = [[package id] retain]; - commercial_ = [package isCommercial]; + package_ = [package_ retain]; + commercial_ = [package_ isCommercial]; if ([package_ mode] != nil) [buttons_ addObject:UCLocalize("CLEAR")]; @@ -5579,19 +5875,13 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { action:@selector(customButtonClicked) ]; - [self reloadURL]; + [super reloadData]; } - (bool) isLoading { return commercial_ ? [super isLoading] : false; } -- (void) reloadData { - [super reloadData]; - - [self setPackage:[database_ packageWithName:name_]]; -} - @end /* }}} */ @@ -5705,8 +5995,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) didSelectPackage:(Package *)package { - CYPackageController *view([[[CYPackageController alloc] initWithDatabase:database_] autorelease]); - [view setPackage:package]; + CYPackageController *view([[[CYPackageController alloc] initWithDatabase:database_ forPackage:[package id]] autorelease]); [view setDelegate:delegate_]; [[self navigationController] pushViewController:view animated:YES]; } @@ -5970,6 +6259,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { /* Home Controller {{{ */ @interface HomeController : CYBrowserController { } + @end @implementation HomeController @@ -6019,7 +6309,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (void) viewWillAppear:(BOOL)animated { if (![self hasLoaded]) - [self loadURL:[NSURL URLWithString:CydiaURL(@"ui/home/")]]; + [self loadURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/home/", UI_]]]; [super viewWillAppear:animated]; @@ -6043,6 +6333,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) queueStatusDidChange; + @end @implementation ManageController @@ -6053,14 +6344,12 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (void) viewWillAppear:(BOOL)animated { if (![self hasLoaded]) - [self loadURL:[NSURL URLWithString:CydiaURL(@"ui/manage/")]]; + [self loadURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/manage/", UI_]]]; [super viewWillAppear:animated]; } - (void) viewDidLoad { - [[self navigationItem] setTitle:UCLocalize("MANAGE")]; - [[self navigationItem] setLeftBarButtonItem:[[[UIBarButtonItem alloc] initWithTitle:UCLocalize("SETTINGS") style:UIBarButtonItemStylePlain @@ -6159,14 +6448,13 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [prompt_ setFrame:prmrect]; } -- (void)setFrame:(CGRect)frame { +- (void) setFrame:(CGRect)frame { [super setFrame:frame]; - [self positionViews]; } - (id) initWithFrame:(CGRect)frame delegate:(id)delegate { - if ((self = [super initWithFrame:frame])) { + if ((self = [super initWithFrame:frame]) != nil) { [self setAutoresizingMask:UIViewAutoresizingFlexibleWidth]; [self setBarStyle:UIBarStyleBlack]; @@ -6232,6 +6520,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { /* Cydia Tab Bar Controller {{{ */ @interface CYTabBarController : UITabBarController < + UITabBarControllerDelegate, ProgressDelegate > { _transient Database *database_; @@ -6243,6 +6532,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { _transient NSObject *updatedelegate_; id root_; + UIViewController *remembered_; + _transient UIViewController *transient_; } - (NSArray *) navigationURLCollection; @@ -6255,6 +6546,37 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { @implementation CYTabBarController +- (void) setUnselectedViewController:(UIViewController *)transient { + NSMutableArray *controllers = [[self viewControllers] mutableCopy]; + if (transient != nil) { + if (transient_ == nil) + remembered_ = [[controllers objectAtIndex:0] retain]; + transient_ = transient; + [transient_ setTabBarItem:[remembered_ tabBarItem]]; + [controllers replaceObjectAtIndex:0 withObject:transient_]; + [self setSelectedIndex:0]; + [self setViewControllers:controllers]; + [self concealTabBarSelection]; + } else if (remembered_ != nil) { + [remembered_ setTabBarItem:[transient_ tabBarItem]]; + transient_ = transient; + [controllers replaceObjectAtIndex:0 withObject:remembered_]; + [remembered_ release]; + remembered_ = nil; + [self setViewControllers:controllers]; + [self revealTabBarSelection]; + } +} + +- (UIViewController *) unselectedViewController { + return transient_; +} + +- (void) tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController { + if ([self unselectedViewController]) + [self setUnselectedViewController:nil]; +} + - (NSArray *) navigationURLCollection { NSMutableArray *items([NSMutableArray array]); @@ -6272,7 +6594,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { for (CYViewController *controller in [self viewControllers]) [controller reloadData]; - [(CYNavigationController *)[self transientViewController] reloadData]; + [(CYNavigationController *)[self unselectedViewController] reloadData]; } - (void) dealloc { @@ -6285,6 +6607,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (id) initWithDatabase:(Database *)database { if ((self = [super init]) != nil) { database_ = database; + [self setDelegate:self]; [[self view] setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarFrameChanged:) name:UIApplicationDidChangeStatusBarFrameNotification object:nil]; @@ -6523,10 +6846,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { @implementation CYNavigationController -- (void) dealloc { - [super dealloc]; -} - - (NSArray *) navigationURLCollection { NSMutableArray *stack([NSMutableArray array]); @@ -6541,6 +6860,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (void) reloadData { for (CYViewController *page in [self viewControllers]) { + // Only reload controllers that have already loaded. + // This prevents a page from accidentally loading too + // early if it hasn't been shown on the screen yet. if ([page hasLoaded]) [page reloadData]; } @@ -6681,18 +7003,15 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (id) initWithDatabase:(Database *)database section:(NSString *)name { NSString *title; - - if (name == nil) { + if (name == nil) title = UCLocalize("ALL_PACKAGES"); - } else if (![name isEqual:@""]) { + else if (![name isEqual:@""]) title = [[NSBundle mainBundle] localizedStringForKey:Simplify(name) value:nil table:@"Sections"]; - } else { + else title = UCLocalize("NO_SECTION"); - } - - section_ = name; if ((self = [super initWithDatabase:database title:title filter:@selector(isVisibleInSection:) with:name]) != nil) { + section_ = name; } return self; } @@ -6855,7 +7174,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { section = [sections objectForKey:key]; if (section == nil) { _profile(SectionsView$reloadData$Section$Allocate) - section = [[[Section alloc] initWithName:name localize:YES] autorelease]; + section = [[[Section alloc] initWithName:key localize:YES] autorelease]; [sections setObject:section forKey:key]; _end } @@ -6891,8 +7210,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { _trace(); } -- (void)editButtonClicked { - [self setEditing:!editing_]; +- (void) editButtonClicked { + [self setEditing:(!editing_)]; } @end @@ -6991,9 +7310,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (NSIndexPath *) tableView:(UITableView *)table willSelectRowAtIndexPath:(NSIndexPath *)path { Package *package([self packageAtIndexPath:path]); - CYPackageController *view([[[CYPackageController alloc] initWithDatabase:database_] autorelease]); + CYPackageController *view([[[CYPackageController alloc] initWithDatabase:database_ forPackage:[package id]] autorelease]); [view setDelegate:delegate_]; - [view setPackage:package]; [[self navigationController] pushViewController:view animated:YES]; return path; } @@ -7203,7 +7521,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } return self; } -- (void)viewDidAppear:(BOOL)animated { +- (void) viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; if (!searchloaded_) { @@ -7275,22 +7593,29 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { if (package_ == nil) return 0; - return 1; + if ([package_ installed] == nil) + return 1; + else + return 2; } - (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { if (package_ == nil) return 0; - return 2; + // both sections contain just one item right now. + return 1; } - (NSString *) tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { - return UCLocalize("CHANGE_PACKAGE_SETTINGS"); + return nil; } - (NSString *) tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section { - return UCLocalize("SHOW_ALL_CHANGES_EX"); + if (section == 0) + return UCLocalize("SHOW_ALL_CHANGES_EX"); + else + return UCLocalize("IGNORE_UPGRADES_EX"); } - (void) onSubscribed:(id)control { @@ -7301,15 +7626,50 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [delegate_ updateData]; } +- (void) _updateIgnored { + const char *package([name_ UTF8String]); + bool on([ignoredSwitch_ isOn]); + + pid_t pid(ExecFork()); + if (pid == 0) { + FILE *dpkg(popen("dpkg --set-selections", "w")); + fwrite(package, strlen(package), 1, dpkg); + + if (on) + fwrite(" hold\n", 6, 1, dpkg); + else + fwrite(" install\n", 9, 1, dpkg); + + pclose(dpkg); + + exit(0); + _assert(false); + } + + _forever { + int status; + int result(waitpid(pid, &status, 0)); + + if (result != -1) { + _assert(result == pid); + break; + } + } +} + - (void) onIgnored:(id)control { - // TODO: set Held state - possibly call out to dpkg, etc. + NSInvocation *invocation([NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:@selector(_updateIgnored)]]); + [invocation setTarget:self]; + [invocation setSelector:@selector(_updateIgnored)]; + + [delegate_ reloadDataWithInvocation:invocation]; } - (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { if (package_ == nil) return nil; - switch ([indexPath row]) { + switch ([indexPath section]) { case 0: return subscribedCell_; case 1: return ignoredCell_; @@ -7335,8 +7695,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { ignoredSwitch_ = [[UISwitch alloc] initWithFrame:CGRectMake(0, 0, 50, 20)]; [ignoredSwitch_ setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin]; [ignoredSwitch_ addTarget:self action:@selector(onIgnored:) forEvents:UIControlEventValueChanged]; - // Disable this switch, since it only reflects (not modifies) the ignored state. - [ignoredSwitch_ setUserInteractionEnabled:NO]; subscribedCell_ = [[UITableViewCell alloc] init]; [subscribedCell_ setText:UCLocalize("SHOW_ALL_CHANGES")]; @@ -7347,8 +7705,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [ignoredCell_ setText:UCLocalize("IGNORE_UPGRADES")]; [ignoredCell_ setAccessoryView:ignoredSwitch_]; [ignoredCell_ setSelectionStyle:UITableViewCellSelectionStyleNone]; - // FIXME: Ignored state is not saved. - [ignoredCell_ setUserInteractionEnabled:NO]; } - (void) viewDidLoad { @@ -7373,7 +7729,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (id) initWithDatabase:(Database *)database package:(NSString *)package { - if ((self = [super init])) { + if ((self = [super init]) != nil) { database_ = database; name_ = [package retain]; } return self; @@ -7385,11 +7741,12 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { if (package_ != nil) [package_ autorelease]; package_ = [database_ packageWithName:name_]; + if (package_ != nil) { - [package_ retain]; + package_ = [package_ retain]; [subscribedSwitch_ setOn:([package_ subscribed] ? 1 : 0) animated:NO]; [ignoredSwitch_ setOn:([package_ ignored] ? 1 : 0) animated:NO]; - } + } // XXX: what now, G? [table_ reloadData]; } @@ -7557,7 +7914,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { /* }}} */ /* Source Controller {{{ */ @interface SourceController : FilteredPackageListController { - Source *source_; + _transient Source *source_; + NSString *key_; } - (id) initWithDatabase:(Database *)database source:(Source *)source; @@ -7571,12 +7929,22 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (id) initWithDatabase:(Database *)database source:(Source *)source { - source_ = source; - if ((self = [super initWithDatabase:database title:[source label] filter:@selector(isVisibleInSource:) with:source]) != nil) { + source_ = source; + key_ = [[source key] retain]; } return self; } +- (void) reloadData { + source_ = [database_ sourceWithKey:key_]; + [key_ release]; + key_ = [[source_ key] retain]; + [self setObject:source_]; + [[self navigationItem] setTitle:[source_ label]]; + + [super reloadData]; +} + @end /* }}} */ /* Sources Controller {{{ */ @@ -7701,12 +8069,12 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [[self navigationController] pushViewController:controller animated:YES]; } -- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { +- (BOOL) tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { Source *source = [self sourceAtIndexPath:indexPath]; return [source record] != nil; } -- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { +- (void) tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { Source *source = [self sourceAtIndexPath:indexPath]; [Sources_ removeObjectForKey:[source key]]; [delegate_ syncData]; @@ -7771,7 +8139,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { message:warning delegate:self cancelButtonTitle:UCLocalize("CANCEL") - otherButtonTitles:UCLocalize("ADD_ANYWAY"), nil + otherButtonTitles: + UCLocalize("ADD_ANYWAY"), + nil ] autorelease]; [alert setContext:@"warning"]; @@ -7858,7 +8228,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { return [[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease]; } -- (void)alertView:(UIAlertView *)alert clickedButtonAtIndex:(NSInteger)button { +- (void) alertView:(UIAlertView *)alert clickedButtonAtIndex:(NSInteger)button { NSString *context([alert context]); if ([context isEqualToString:@"source"]) { @@ -7976,7 +8346,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { message:nil delegate:self cancelButtonTitle:UCLocalize("CANCEL") - otherButtonTitles:UCLocalize("ADD_SOURCE"), nil + otherButtonTitles: + UCLocalize("ADD_SOURCE"), + nil ] autorelease]; [alert setContext:@"source"]; @@ -8109,7 +8481,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (id) initWithDatabase:(Database *)database delegate:(id)delegate { - if ((self = [super init])) { + if ((self = [super init]) != nil) { database_ = database; roledelegate_ = delegate; } return self; @@ -8201,7 +8573,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { return 0; // :( } -- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { +- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { return nil; // This method is required by the protocol. } @@ -8239,6 +8611,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { UILabel *status_; UILabel *caption_; } + @end @implementation StashController @@ -8357,7 +8730,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { message:UCLocalize("HALFINSTALLED_PACKAGE_EX") delegate:self cancelButtonTitle:UCLocalize("FORCIBLY_CLEAR") - otherButtonTitles:UCLocalize("TEMPORARY_IGNORE"), nil + otherButtonTitles: + UCLocalize("TEMPORARY_IGNORE"), + nil ] autorelease]; [alert setContext:@"fixhalf"]; @@ -8370,7 +8745,10 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { message:UCLocalize("ESSENTIAL_UPGRADE_EX") delegate:self cancelButtonTitle:UCLocalize("TEMPORARY_IGNORE") - otherButtonTitles:UCLocalize("UPGRADE_ESSENTIAL"), UCLocalize("COMPLETE_UPGRADE"), nil + otherButtonTitles: + UCLocalize("UPGRADE_ESSENTIAL"), + UCLocalize("COMPLETE_UPGRADE"), + nil ] autorelease]; [alert setContext:@"upgrade"]; @@ -8476,11 +8854,11 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [NSThread detachNewThreadSelector:@selector(_refreshIfPossible) toTarget:self withObject:nil]; } -- (void) _reloadData { +- (void) _reloadDataWithInvocation:(NSInvocation *)invocation { UIProgressHUD *hud(loaded_ ? [self addProgressHUD] : nil); [hud setText:UCLocalize("RELOADING_DATA")]; - [database_ yieldToSelector:@selector(reloadData) withObject:nil]; + [database_ yieldToSelector:@selector(reloadDataWithInvocation:) withObject:invocation]; if (hud != nil) [self removeProgressHUD:hud]; @@ -8562,12 +8940,16 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { ]; } -- (void) reloadData { +- (void) reloadDataWithInvocation:(NSInvocation *)invocation { @synchronized (self) { - [self _reloadData]; + [self _reloadDataWithInvocation:invocation]; } } +- (void) reloadData { + [self reloadDataWithInvocation:nil]; +} + - (void) resolve { pkgProblemResolver *resolver = [database_ resolver]; @@ -8577,6 +8959,13 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (bool) perform { + // XXX: this is a really crappy way of doing this. + // like, seriously: this state machine is still broken, and cancelling this here doesn't really /fix/ that. + // for one, the user can still /start/ a reloading data event while they have a queue, which is stupid + // for two, this just means there is a race condition between the refresh completing and the confirmation controller appearing. + if ([tabbar_ updating]) + [tabbar_ cancelUpdate]; + if (![database_ prepare]) return false; @@ -8641,7 +9030,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (void) complete { @synchronized (self) { - [self _reloadData]; + [self _reloadDataWithInvocation:nil]; } } @@ -8709,7 +9098,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { NSString *context([alert context]); if ([context isEqualToString:@"fixhalf"]) { - if (button == [alert firstOtherButtonIndex]) { + if (button == [alert cancelButtonIndex]) { @synchronized (self) { for (Package *broken in broken_) { [broken remove]; @@ -8724,7 +9113,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [self resolve]; [self perform]; } - } else if (button == [alert cancelButtonIndex]) { + } else if (button == [alert firstOtherButtonIndex]) { [broken_ removeAllObjects]; [self _loaded]; } @@ -8812,20 +9201,10 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (CYViewController *) pageForPackage:(NSString *)name { - if (Package *package = [database_ packageWithName:name]) { - CYPackageController *view = [[[CYPackageController alloc] initWithDatabase:database_] autorelease]; - [view setPackage:package]; - return view; - } else { - NSURL *url([NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"unknown" ofType:@"html"]]); - url = [NSURL URLWithString:[[url absoluteString] stringByAppendingString:[NSString stringWithFormat:@"?%@", name]]]; - CYBrowserController *browser = [[[CYBrowserController alloc] init] autorelease]; - [browser loadURL:url]; - return browser; - } + return [[[CYPackageController alloc] initWithDatabase:database_ forPackage:name] autorelease]; } -- (CYViewController *) pageForURL:(NSURL *)url { +- (CYViewController *) pageForURL:(NSURL *)url forExternal:(BOOL)external { NSString *scheme([[url scheme] lowercaseString]); if ([[url absoluteString] length] <= [scheme length] + 3) return nil; @@ -8845,14 +9224,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { if ([base isEqualToString:@"url"]) { // This kind of URL can contain slashes in the argument, so we can't parse them below. NSString *destination = [[url absoluteString] substringFromIndex:([scheme length] + [@"://" length] + [base length] + [@"/" length])]; - controller = [[[CYBrowserController alloc] init] autorelease]; - [(CYBrowserController *)controller loadURL:[NSURL URLWithString:destination]]; - } else if ([components count] == 1) { - if ([base isEqualToString:@"storage"]) { - controller = [[[CYBrowserController alloc] init] autorelease]; - [(CYBrowserController *)controller loadURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"storage" ofType:@"html"]]]; - } - + controller = [[[CYBrowserController alloc] initWithURL:[NSURL URLWithString:destination]] autorelease]; + } else if (!external && [components count] == 1) { if ([base isEqualToString:@"manage"]) { controller = [[[ManageController alloc] init] autorelease]; } @@ -8887,37 +9260,32 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { controller = [self pageForPackage:argument]; } - if ([base isEqualToString:@"search"]) { + if (!external && [base isEqualToString:@"search"]) { controller = [[[SearchController alloc] initWithDatabase:database_] autorelease]; [(SearchController *)controller setSearchTerm:argument]; } - if ([base isEqualToString:@"sections"]) { + if (!external && [base isEqualToString:@"sections"]) { if ([argument isEqualToString:@"all"]) argument = nil; controller = [[[SectionController alloc] initWithDatabase:database_ section:argument] autorelease]; } - if ([base isEqualToString:@"sources"]) { + if (!external && [base isEqualToString:@"sources"]) { if ([argument isEqualToString:@"add"]) { controller = [[[SourcesController alloc] initWithDatabase:database_] autorelease]; [(SourcesController *)controller showAddSourcePrompt]; } else { - NSArray *sources = [database_ sources]; - for (Source *source in sources) { - if ([[source name] caseInsensitiveCompare:argument] == NSOrderedSame) { - controller = [[[SourceController alloc] initWithDatabase:database_ source:source] autorelease]; - break; - } - } + Source *source = [database_ sourceWithKey:argument]; + controller = [[[SourceController alloc] initWithDatabase:database_ source:source] autorelease]; } } - if ([base isEqualToString:@"launch"]) { + if (!external && [base isEqualToString:@"launch"]) { [self launchApplicationWithIdentifier:argument suspended:NO]; return nil; } - } else if ([components count] == 3) { + } else if (!external && [components count] == 3) { NSString *arg1 = [components objectAtIndex:1]; NSString *arg2 = [components objectAtIndex:2]; @@ -8937,13 +9305,13 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { return controller; } -- (BOOL) openCydiaURL:(NSURL *)url { - CYViewController *page([self pageForURL:url]); +- (BOOL) openCydiaURL:(NSURL *)url forExternal:(BOOL)external { + CYViewController *page([self pageForURL:url forExternal:external]); if (page != nil) { CYNavigationController *nav = [[[CYNavigationController alloc] init] autorelease]; [nav setViewControllers:[NSArray arrayWithObject:page]]; - [tabbar_ setTransientViewController:nav]; + [tabbar_ setUnselectedViewController:nav]; } return page != nil; @@ -8953,7 +9321,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [super applicationOpenURL:url]; if (!loaded_) starturl_ = [url retain]; - else [self openCydiaURL:url]; + else [self openCydiaURL:url forExternal:YES]; } - (void) applicationWillResignActive:(UIApplication *)application { @@ -9008,7 +9376,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (void) setupViewControllers { tabbar_ = [[CYTabBarController alloc] initWithDatabase:database_]; - [tabbar_ setDelegate:self]; NSMutableArray *items([NSMutableArray arrayWithObjects: [[[UITabBarItem alloc] initWithTitle:@"Cydia" image:[UIImage applicationImageNamed:@"home.png"] tag:0] autorelease], @@ -9035,12 +9402,17 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [tabbar_ setUpdateDelegate:self]; } -- (CYEmulatedLoadingController *)showEmulatedLoadingControllerInView:(UIView *)view { - static CYEmulatedLoadingController *fake = [[CYEmulatedLoadingController alloc] init]; +- (CYEmulatedLoadingController *) showEmulatedLoadingControllerInView:(UIView *)view { + static CYEmulatedLoadingController *fake = nil; + if (view != nil) { + if (fake == nil) + fake = [[CYEmulatedLoadingController alloc] initWithDatabase:database_]; [view addSubview:[fake view]]; } else { [[fake view] removeFromSuperview]; + [fake release]; + fake = nil; } return fake; @@ -9144,10 +9516,16 @@ _trace(); recently = true; } - if (recently && [Metadata_ objectForKey:@"InterfaceState"]) { - items = [[Metadata_ objectForKey:@"InterfaceState"] mutableCopy]; - selectedIndex = [[Metadata_ objectForKey:@"InterfaceIndex"] intValue]; - } else { + items = [[Metadata_ objectForKey:@"InterfaceState"] mutableCopy]; + selectedIndex = [[Metadata_ objectForKey:@"InterfaceIndex"] intValue]; + + BOOL enough = YES; + for (NSArray *entry in items) + if ([entry count] <= 0) + enough = NO; + + if (!recently || !items || !enough) { + selectedIndex = 0; items = [NSMutableArray array]; [items addObject:[NSArray arrayWithObject:@"cydia://home"]]; [items addObject:[NSArray arrayWithObject:@"cydia://sections"]]; @@ -9170,7 +9548,7 @@ _trace(); for (unsigned int nav = 0; nav < [stack count]; nav++) { NSString *addr = [stack objectAtIndex:nav]; NSURL *url = [NSURL URLWithString:addr]; - CYViewController *page = [self pageForURL:url]; + CYViewController *page = [self pageForURL:url forExternal:NO]; if (page != nil) [current addObject:page]; } @@ -9180,7 +9558,7 @@ _trace(); // (Try to) show the startup URL. if (starturl_ != nil) { - [self openCydiaURL:starturl_]; + [self openCydiaURL:starturl_ forExternal:NO]; [starturl_ release]; starturl_ = nil; } @@ -9275,6 +9653,18 @@ int main(int argc, char *argv[]) { _pooled } else IsWildcat_ = false; + UIScreen *screen([UIScreen mainScreen]); + if ([screen respondsToSelector:@selector(scale)]) + ScreenScale_ = [screen scale]; + else + ScreenScale_ = 1; + + NSMutableArray *parts([NSMutableArray arrayWithCapacity:2]); + if (ScreenScale_ > 1) + [parts addObject:@"@2x"]; + [parts addObject:(IsWildcat_ ? @"~ipad" : @"~iphone")]; + UI_ = CydiaURL([NSString stringWithFormat:@"ui/ios%@", [parts componentsJoinedByString:@""]]); + PackageName = reinterpret_cast(method_getImplementation(class_getInstanceMethod([Package class], @selector(cyname)))); /* Library Hacks {{{ */ @@ -9486,10 +9876,15 @@ int main(int argc, char *argv[]) { _pooled Finishes_ = [NSArray arrayWithObjects:@"return", @"reopen", @"restart", @"reload", @"reboot", nil]; - if (substrate && access("/Library/MobileSubstrate/DynamicLibraries/SimulatedKeyEvents.dylib", F_OK) == 0) - dlopen("/Library/MobileSubstrate/DynamicLibraries/SimulatedKeyEvents.dylib", RTLD_LAZY | RTLD_GLOBAL); - if (substrate && access("/Applications/WinterBoard.app/WinterBoard.dylib", F_OK) == 0) - dlopen("/Applications/WinterBoard.app/WinterBoard.dylib", RTLD_LAZY | RTLD_GLOBAL); +#define MobileSubstrate_(name) \ + if (substrate && access("/Library/MobileSubstrate/DynamicLibraries/" #name ".dylib", F_OK) == 0) \ + dlopen("/Library/MobileSubstrate/DynamicLibraries/" #name ".dylib", RTLD_LAZY | RTLD_GLOBAL); + + MobileSubstrate_(Activator) + MobileSubstrate_(libstatusbar) + MobileSubstrate_(SimulatedKeyEvents) + MobileSubstrate_(WinterBoard) + /*if (substrate && access("/Library/MobileSubstrate/MobileSubstrate.dylib", F_OK) == 0) dlopen("/Library/MobileSubstrate/MobileSubstrate.dylib", RTLD_LAZY | RTLD_GLOBAL);*/