X-Git-Url: https://git.saurik.com/cydia.git/blobdiff_plain/1aa295469003a507738adb02f9c536263909337d..b13b8664e70405f065a37d67fb4eb7c39a6a438b:/MobileCydia.mm diff --git a/MobileCydia.mm b/MobileCydia.mm index b2cb42fe..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]; @@ -871,6 +872,7 @@ class Pcre { + (Address *) addressWithString:(NSString *)string; - (Address *) initWithString:(NSString *)string; + @end @implementation Address @@ -904,7 +906,10 @@ class Pcre { } + (NSArray *) _attributeKeys { - return [NSArray arrayWithObjects:@"address", @"name", nil]; + return [NSArray arrayWithObjects: + @"address", + @"name", + nil]; } - (NSArray *) attributeKeys { @@ -1048,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; @@ -1120,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]; } @@ -1168,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; @@ -1346,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; @@ -1591,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 { @@ -1756,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 @@ -2066,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; } @@ -2077,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 { @@ -2088,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; @@ -2479,7 +2661,7 @@ struct PackageNameOrdering : _end _profile(Package$visible$isSectionVisible) - if (section != nil && !isSectionVisible(section)) + if (!isSectionVisible(section)) return false; _end @@ -3021,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_); @@ -3218,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 { @@ -3316,7 +3439,7 @@ static NSString *Warning_; return [self popErrorWithTitle:title] || !success; } -- (void) reloadData { CYPoolStart() { +- (void) reloadDataWithInvocation:(NSInvocation *)invocation { CYPoolStart() { @synchronized (self) { ++era_; @@ -3352,6 +3475,9 @@ static NSString *Warning_; if (chk != -1) close(chk); + if (invocation != nil) + [invocation invoke]; + NSString *title(UCLocalize("DATABASE")); _trace(); @@ -3488,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 { @@ -3718,6 +3843,7 @@ static NSString *Warning_; } - (id) initWithDelegate:(IndirectDelegate *)indirect; + @end @implementation CydiaObject @@ -3738,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 { @@ -3776,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:)) @@ -3796,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; } @@ -3961,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]; @@ -4001,13 +4134,16 @@ 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 /* }}} */ @@ -4021,6 +4157,7 @@ static NSString *Warning_; UITabBar *tabbar_; UINavigationBar *navbar_; } + @end @implementation CYEmulatedLoadingController @@ -4059,7 +4196,7 @@ static NSString *Warning_; } - (id) initWithDatabase:(Database *)database { - if ((self = [super init])) { + if ((self = [super init]) != nil) { database_ = database; [database_ setDelegate:self]; } return self; @@ -4192,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()) @@ -4216,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_; } @@ -4231,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]; } @@ -4272,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"]; } @@ -4282,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()); @@ -4348,21 +4615,17 @@ 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:[NSString stringWithFormat:@"%@/confirm/", UI_]]]; @@ -4376,9 +4639,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } return self; } -- (void) applyRightButton { #if !AlwaysReload - if (issues_ == nil && ![self isLoading]) +- (void) applyRightButton { + if ([issues_ count] == 0 && ![self isLoading]) [[self navigationItem] setRightBarButtonItem:[[[UIBarButtonItem alloc] initWithTitle:UCLocalize("CONFIRM") style:UIBarButtonItemStyleDone @@ -4386,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]; @@ -4425,6 +4686,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (SEL) selector; - (id) target; - (id) object; + @end @implementation ProgressData @@ -4577,7 +4839,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [self positionViews]; } -- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { +- (void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { [self positionViews]; } @@ -5566,12 +5828,11 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { database_ = database; buttons_ = [[NSMutableArray alloc] initWithCapacity:4]; name_ = [[NSString alloc] initWithString:name]; + [self setURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/package/#!/%@", UI_, name_]]]; } return self; } - (void) reloadData { - [super reloadData]; - if (package_ != nil) [package_ autorelease]; package_ = [database_ packageWithName:name_]; @@ -5614,7 +5875,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { action:@selector(customButtonClicked) ]; - [self loadURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/package/#!/%@", UI_, name_]]]; + [super reloadData]; } - (bool) isLoading { @@ -5998,6 +6259,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { /* Home Controller {{{ */ @interface HomeController : CYBrowserController { } + @end @implementation HomeController @@ -6071,6 +6333,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) queueStatusDidChange; + @end @implementation ManageController @@ -6087,8 +6350,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) viewDidLoad { - [[self navigationItem] setTitle:UCLocalize("MANAGE")]; - [[self navigationItem] setLeftBarButtonItem:[[[UIBarButtonItem alloc] initWithTitle:UCLocalize("SETTINGS") style:UIBarButtonItemStylePlain @@ -6187,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]; @@ -6950,8 +7210,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { _trace(); } -- (void)editButtonClicked { - [self setEditing:!editing_]; +- (void) editButtonClicked { + [self setEditing:(!editing_)]; } @end @@ -7261,7 +7521,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } return self; } -- (void)viewDidAppear:(BOOL)animated { +- (void) viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; if (!searchloaded_) { @@ -7333,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 { @@ -7359,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_; @@ -7393,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")]; @@ -7405,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 { @@ -7431,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; @@ -7443,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]; } @@ -7615,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; @@ -7629,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 {{{ */ @@ -7759,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]; @@ -7918,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"]) { @@ -8171,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; @@ -8263,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. } @@ -8301,6 +8611,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { UILabel *status_; UILabel *caption_; } + @end @implementation StashController @@ -8543,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]; @@ -8629,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]; @@ -8644,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; @@ -8708,7 +9030,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (void) complete { @synchronized (self) { - [self _reloadData]; + [self _reloadDataWithInvocation:nil]; } } @@ -8882,7 +9204,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { 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; @@ -8903,7 +9225,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { // 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] initWithURL:[NSURL URLWithString:destination]] autorelease]; - } else if ([components count] == 1) { + } else if (!external && [components count] == 1) { if ([base isEqualToString:@"manage"]) { controller = [[[ManageController alloc] init] autorelease]; } @@ -8938,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]; @@ -8988,8 +9305,8 @@ 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]; @@ -9004,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 { @@ -9085,7 +9402,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [tabbar_ setUpdateDelegate:self]; } -- (CYEmulatedLoadingController *)showEmulatedLoadingControllerInView:(UIView *)view { +- (CYEmulatedLoadingController *) showEmulatedLoadingControllerInView:(UIView *)view { static CYEmulatedLoadingController *fake = nil; if (view != nil) { @@ -9231,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]; } @@ -9241,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; } @@ -9559,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);*/