X-Git-Url: https://git.saurik.com/cydia.git/blobdiff_plain/686e302fd0fed7758b531ad8329d60963a622a4e..9856894f5f6603e9938128d85cebf7f5792d452d:/Cydia.mm diff --git a/Cydia.mm b/Cydia.mm index 470f276b..8702e29a 100644 --- a/Cydia.mm +++ b/Cydia.mm @@ -1,7 +1,9 @@ /* #include Directives {{{ */ #include #include -#import +#include + +#include #include #include @@ -19,12 +21,14 @@ #include #include +#include extern "C" { #include } -#include +#include +#include #include #include @@ -39,10 +43,14 @@ extern "C" { exit(-1); \ } \ while (false) + +#define _not(type) ((type) ~ (type) 0) /* }}} */ /* Miscellaneous Messages {{{ */ @interface WebView - (void) setApplicationNameForUserAgent:(NSString *)applicationName; +- (id) frameLoadDelegate; +- (void) setFrameLoadDelegate:(id)delegate; @end @interface NSString (Cydia) @@ -51,6 +59,12 @@ while (false) @end /* }}} */ +#ifdef SRK_ASPEN +#define UITable UITableView +#endif + +OBJC_EXPORT const char *class_getName(Class cls); + /* Reset View (UIView) {{{ */ @interface UIView (CYResetView) - (void) resetViewAnimated:(BOOL)animated; @@ -59,7 +73,7 @@ while (false) @implementation UIView (CYResetView) - (void) resetViewAnimated:(BOOL)animated { - fprintf(stderr, "%s\n", self->isa->name); + fprintf(stderr, "%s\n", class_getName(self->isa)); _assert(false); } @@ -169,13 +183,42 @@ class GSFont { /* }}} */ static const int PulseInterval_ = 50000; + +const char *Firmware_ = NULL; const char *Machine_ = NULL; const char *SerialNumber_ = NULL; +unsigned Major_; +unsigned Minor_; +unsigned BugFix_; + +#define FW_LEAST(major, minor, bugfix) \ + (major < Major_ || major == Major_ && \ + (minor < Minor_ || minor == Minor_ && \ + bugfix <= BugFix_)) + +bool bootstrap_ = false; + static NSMutableDictionary *Metadata_; static NSMutableDictionary *Packages_; static NSDate *now_; +NSString *GetLastUpdate() { + NSDate *update = [Metadata_ objectForKey:@"LastUpdate"]; + + if (update == nil) + return @"Never or Unknown"; + + CFLocaleRef locale = CFLocaleCopyCurrent(); + CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle); + CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) update); + + CFRelease(formatter); + CFRelease(locale); + + return [(NSString *) formatted autorelease]; +} + @protocol ProgressDelegate - (void) setError:(NSString *)error; - (void) setTitle:(NSString *)title; @@ -428,6 +471,7 @@ inline float interpolate(float begin, float end, float fraction) { /* }}} */ @class Package; +@class Source; /* Database Interface {{{ */ @interface Database : NSObject { @@ -437,6 +481,10 @@ inline float interpolate(float begin, float end, float fraction) { pkgAcquire *fetcher_; FileFd *lock_; SPtr manager_; + pkgSourceList *list_; + + NSMutableDictionary *sources_; + NSMutableArray *packages_; id delegate_; Status status_; @@ -456,6 +504,7 @@ inline float interpolate(float begin, float end, float fraction) { - (pkgRecords *) records; - (pkgProblemResolver *) resolver; - (pkgAcquire &) fetcher; +- (NSArray *) packages; - (void) reloadData; - (void) prepare; @@ -464,11 +513,13 @@ inline float interpolate(float begin, float end, float fraction) { - (void) upgrade; - (void) setDelegate:(id)delegate; +- (Source *) getSource:(const pkgCache::PkgFileIterator &)file; @end /* }}} */ /* Reset View {{{ */ @interface ResetView : UIView { + UIPushButton *configure_; UIPushButton *reload_; NSMutableArray *views_; UINavigationBar *navbar_; @@ -480,14 +531,17 @@ inline float interpolate(float begin, float end, float fraction) { - (void) dealloc; - (void) navigationBar:(UINavigationBar *)navbar poppedItem:(UINavigationItem *)item; +- (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button; - (id) initWithFrame:(CGRect)frame; - (void) setDelegate:(id)delegate; + +- (void) configurePushed; - (void) reloadPushed; - (void) pushView:(UIView *)view withTitle:(NSString *)title backButtonTitle:(NSString *)back rightButton:(NSString *)right; - (void) popViews:(unsigned)views; -- (void) resetView; +- (void) resetView:(BOOL)clear; - (void) _resetView; - (void) setPrompt; @end @@ -495,6 +549,7 @@ inline float interpolate(float begin, float end, float fraction) { @implementation ResetView - (void) dealloc { + [configure_ release]; [reload_ release]; [transition_ release]; [navbar_ release]; @@ -506,11 +561,15 @@ inline float interpolate(float begin, float end, float fraction) { [views_ removeLastObject]; UIView *view([views_ lastObject]); [view resetViewAnimated:!resetting_]; - if (!resetting_) - [transition_ transition:2 toView:view]; - if ([views_ count] == 1) + if (!resetting_) { + [transition_ transition:2 toView:view]; [self _resetView]; + } +} + +- (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button { + [sheet dismiss]; } - (id) initWithFrame:(CGRect)frame { @@ -531,12 +590,19 @@ inline float interpolate(float begin, float end, float fraction) { bounds.origin.x, bounds.origin.y + navsize.height, bounds.size.width, bounds.size.height - navsize.height )]; - //reload_ = [[UIPushButton alloc] initWithFrame:CGRectMake(284, 8, 29, 23)]; - reload_ = [[UIPushButton alloc] initWithFrame:CGRectMake(282, 5, 29, 23)]; + //configure_ = [[UIPushButton alloc] initWithFrame:CGRectMake(15, 9, 17, 18)]; + configure_ = [[UIPushButton alloc] initWithFrame:CGRectMake(10, 9, 17, 18)]; + [configure_ setShowPressFeedback:YES]; + [configure_ setImage:[UIImage applicationImageNamed:@"configure.png"]]; + [configure_ addTarget:self action:@selector(configurePushed) forEvents:1]; + + //reload_ = [[UIPushButton alloc] initWithFrame:CGRectMake(288, 5, 18, 22)]; + reload_ = [[UIPushButton alloc] initWithFrame:CGRectMake(293, 5, 18, 22)]; [reload_ setShowPressFeedback:YES]; [reload_ setImage:[UIImage applicationImageNamed:@"reload.png"]]; [reload_ addTarget:self action:@selector(reloadPushed) forEvents:1]; + [navbar_ addSubview:configure_]; [navbar_ addSubview:reload_]; [self addSubview:transition_]; @@ -547,6 +613,19 @@ inline float interpolate(float begin, float end, float fraction) { delegate_ = delegate; } +- (void) configurePushed { + UIAlertSheet *sheet = [[[UIAlertSheet alloc] + initWithTitle:@"Sources Unimplemented" + buttons:[NSArray arrayWithObjects:@"Okay", nil] + defaultButtonIndex:0 + delegate:self + context:self + ] autorelease]; + + [sheet setBodyText:@"This feature will be implemented soon. In the mean time, you may add sources by adding .list files to '/etc/apt/sources.list.d' or modifying '/etc/apt/sources.list'."]; + [sheet popupAlertAnimated:YES]; +} + - (void) reloadPushed { [delegate_ update]; } @@ -568,36 +647,34 @@ inline float interpolate(float begin, float end, float fraction) { [navbar_ popNavigationItem]; resetting_ = false; + [self _resetView]; [transition_ transition:2 toView:[views_ lastObject]]; } -- (void) resetView { +- (void) resetView:(BOOL)clear { resetting_ = true; - if ([[navbar_ navigationItems] count] == 1) - [self _resetView]; - else do - [navbar_ popNavigationItem]; - while ([[navbar_ navigationItems] count] != 1); + + if ([views_ count] > 1) { + [navbar_ disableAnimation]; + while ([views_ count] != (clear ? 1 : 2)) + [navbar_ popNavigationItem]; + [navbar_ enableAnimation]; + if (!clear) + [navbar_ popNavigationItem]; + } + resetting_ = false; - [transition_ transition:0 toView:[views_ lastObject]]; + [self _resetView]; + [transition_ transition:(clear ? 0 : 2) toView:[views_ lastObject]]; } - (void) _resetView { + [navbar_ showButtonsWithLeftTitle:nil rightTitle:nil]; } - (void) setPrompt { - NSDate *update = [Metadata_ objectForKey:@"LastUpdate"]; - - CFLocaleRef locale = CFLocaleCopyCurrent(); - CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle); - CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) update); - - [navbar_ setPrompt:[NSString stringWithFormat:@"Last Updated: %@", (NSString *) formatted]]; - - CFRelease(formatter); - CFRelease(formatted); - CFRelease(locale); + [navbar_ setPrompt:[NSString stringWithFormat:@"Last Updated: %@", GetLastUpdate()]]; } @end @@ -794,23 +871,31 @@ void AddTextView(NSMutableDictionary *fields, NSMutableArray *packages, NSString NSMutableArray *upgrading = [NSMutableArray arrayWithCapacity:16]; NSMutableArray *removing = [NSMutableArray arrayWithCapacity:16]; - bool essential(false); + bool install(false); + bool upgrade(false); + bool remove(false); pkgCacheFile &cache([database_ cache]); for (pkgCache::PkgIterator iterator = cache->PkgBegin(); !iterator.end(); ++iterator) { NSString *name([NSString stringWithCString:iterator.Name()]); - if (cache[iterator].NewInstall()) + bool essential((iterator->Flags & pkgCache::Flag::Essential) != 0); + + if (cache[iterator].NewInstall()) { + if (essential) + install = true; [installing addObject:name]; - else if (cache[iterator].Upgrade()) + } else if (cache[iterator].Upgrade()) { + if (essential) + upgrade = true; [upgrading addObject:name]; - else if (cache[iterator].Delete()) { + } else if (cache[iterator].Delete()) { + if (essential) + remove = true; [removing addObject:name]; - if ((iterator->Flags & pkgCache::Flag::Essential) != 0) - essential = true; } } - if (!essential) + if (!remove) essential_ = nil; else { essential_ = [[UIAlertSheet alloc] @@ -852,6 +937,138 @@ void AddTextView(NSMutableDictionary *fields, NSMutableArray *packages, NSString @end /* }}} */ +/* Source Class {{{ */ +@interface Source : NSObject { + NSString *description_; + NSString *label_; + NSString *origin_; + + NSString *uri_; + NSString *distribution_; + NSString *type_; + NSString *version_; + + NSString *defaultIcon_; + + BOOL trusted_; +} + +- (void) dealloc; + +- (Source *) initWithMetaIndex:(metaIndex *)index; + +- (BOOL) trusted; + +- (NSString *) uri; +- (NSString *) distribution; +- (NSString *) type; + +- (NSString *) description; +- (NSString *) label; +- (NSString *) origin; +- (NSString *) version; + +- (NSString *) defaultIcon; +@end + +@implementation Source + +- (void) dealloc { + [uri_ release]; + [distribution_ release]; + [type_ release]; + + if (description_ != nil) + [description_ release]; + if (label_ != nil) + [label_ release]; + if (origin_ != nil) + [origin_ release]; + if (version_ != nil) + [version_ release]; + + [super dealloc]; +} + +- (Source *) initWithMetaIndex:(metaIndex *)index { + if ((self = [super init]) != nil) { + trusted_ = index->IsTrusted(); + + uri_ = [[NSString stringWithCString:index->GetURI().c_str()] retain]; + distribution_ = [[NSString stringWithCString:index->GetDist().c_str()] retain]; + type_ = [[NSString stringWithCString:index->GetType()] retain]; + + description_ = nil; + label_ = nil; + origin_ = nil; + + debReleaseIndex *dindex(dynamic_cast(index)); + if (dindex != NULL) { + std::ifstream release(dindex->MetaIndexFile("Release").c_str()); + std::string line; + while (std::getline(release, line)) { + std::string::size_type colon(line.find(':')); + if (colon == std::string::npos) + continue; + + std::string name(line.substr(0, colon)); + std::string value(line.substr(colon + 1)); + while (!value.empty() && value[0] == ' ') + value = value.substr(1); + + if (name == "Default-Icon") + defaultIcon_ = [[NSString stringWithCString:value.c_str()] retain]; + else if (name == "Description") + description_ = [[NSString stringWithCString:value.c_str()] retain]; + else if (name == "Label") + label_ = [[NSString stringWithCString:value.c_str()] retain]; + else if (name == "Origin") + origin_ = [[NSString stringWithCString:value.c_str()] retain]; + else if (name == "Version") + version_ = [[NSString stringWithCString:value.c_str()] retain]; + } + } + } return self; +} + +- (BOOL) trusted { + return trusted_; +} + +- (NSString *) uri { + return uri_; +} + +- (NSString *) distribution { + return distribution_; +} + +- (NSString *) type { + return type_; +} + +- (NSString *) description { + return description_; +} + +- (NSString *) label { + return label_; +} + +- (NSString *) origin { + return origin_; +} + +- (NSString *) version { + return version_; +} + +- (NSString *) defaultIcon { + return defaultIcon_; +} + +@end +/* }}} */ /* Package Class {{{ */ NSString *Scour(const char *field, const char *begin, const char *end) { size_t i(0), l(strlen(field)); @@ -886,6 +1103,7 @@ NSString *Scour(const char *field, const char *begin, const char *end) { Database *database_; pkgCache::VerIterator version_; pkgCache::VerFileIterator file_; + Source *source_; NSString *latest_; NSString *installed_; @@ -894,7 +1112,7 @@ NSString *Scour(const char *field, const char *begin, const char *end) { NSString *name_; NSString *tagline_; NSString *icon_; - NSString *bundle_; + NSString *website_; } - (void) dealloc; @@ -913,12 +1131,16 @@ NSString *Scour(const char *field, const char *begin, const char *end) { - (NSString *) latest; - (NSString *) installed; - (BOOL) upgradable; +- (BOOL) essential; +- (BOOL) broken; - (NSString *) id; - (NSString *) name; - (NSString *) tagline; - (NSString *) icon; -- (NSString *) bundle; +- (NSString *) website; + +- (Source *) source; - (BOOL) matches:(NSString *)text; @@ -943,8 +1165,12 @@ NSString *Scour(const char *field, const char *begin, const char *end) { [tagline_ release]; if (icon_ != nil) [icon_ release]; - if (bundle_ != nil) - [bundle_ release]; + if (website_ != nil) + [website_ release]; + + if (source_ != nil) + [source_ release]; + [super dealloc]; } @@ -972,12 +1198,14 @@ NSString *Scour(const char *field, const char *begin, const char *end) { icon_ = Scour("Icon", begin, end); if (icon_ != nil) icon_ = [icon_ retain]; - bundle_ = Scour("Bundle", begin, end); - if (bundle_ != nil) - bundle_ = [bundle_ retain]; + website_ = Scour("Website", begin, end); + if (website_ != nil) + website_ = [website_ retain]; + + source_ = [[database_ getSource:file_.File()] retain]; NSMutableDictionary *metadata = [Packages_ objectForKey:id_]; - if (metadata == nil) { + if (metadata == nil || [metadata count] == 0) { metadata = [NSMutableDictionary dictionaryWithObjectsAndKeys: now_, @"FirstSeen", nil]; @@ -1000,7 +1228,8 @@ NSString *Scour(const char *field, const char *begin, const char *end) { } - (NSString *) section { - return [[NSString stringWithCString:iterator_.Section()] stringByReplacingCharacter:'_' withCharacter:' ']; + const char *section = iterator_.Section(); + return section == NULL ? nil : [[NSString stringWithCString:section] stringByReplacingCharacter:'_' withCharacter:' ']; } - (Address *) maintainer { @@ -1031,7 +1260,8 @@ NSString *Scour(const char *field, const char *begin, const char *end) { } - (NSString *) index { - return [[[self name] substringToIndex:1] uppercaseString]; + NSString *index = [[[self name] substringToIndex:1] uppercaseString]; + return [index length] != 0 && isalpha([index characterAtIndex:0]) ? index : @"123"; } - (NSDate *) seen { @@ -1047,8 +1277,18 @@ NSString *Scour(const char *field, const char *begin, const char *end) { } - (BOOL) upgradable { - NSString *installed = [self installed]; - return installed != nil && [[self latest] compare:installed] != NSOrderedSame ? YES : NO; + if (NSString *installed = [self installed]) + return [[self latest] compare:installed] != NSOrderedSame ? YES : NO; + else + return [self essential]; +} + +- (BOOL) essential { + return (iterator_->Flags & pkgCache::Flag::Essential) == 0 ? NO : YES; +} + +- (BOOL) broken { + return (*[database_ cache])[iterator_].InstBroken(); } - (NSString *) id { @@ -1067,8 +1307,12 @@ NSString *Scour(const char *field, const char *begin, const char *end) { return icon_; } -- (NSString *) bundle { - return bundle_; +- (NSString *) website { + return website_; +} + +- (Source *) source { + return source_; } - (BOOL) matches:(NSString *)text { @@ -1077,6 +1321,10 @@ NSString *Scour(const char *field, const char *begin, const char *end) { NSRange range; + range = [[self id] rangeOfString:text options:NSCaseInsensitiveSearch]; + if (range.location != NSNotFound) + return YES; + range = [[self name] rangeOfString:text options:NSCaseInsensitiveSearch]; if (range.location != NSNotFound) return YES; @@ -1089,13 +1337,36 @@ NSString *Scour(const char *field, const char *begin, const char *end) { } - (NSComparisonResult) compareByName:(Package *)package { - return [[self name] caseInsensitiveCompare:[package name]]; + NSString *lhs = [self name]; + NSString *rhs = [package name]; + + if ([lhs length] != 0 && [rhs length] != 0) { + unichar lhc = [lhs characterAtIndex:0]; + unichar rhc = [rhs characterAtIndex:0]; + + if (isalpha(lhc) && !isalpha(rhc)) + return NSOrderedAscending; + else if (!isalpha(lhc) && isalpha(rhc)) + return NSOrderedDescending; + } + + return [lhs caseInsensitiveCompare:rhs]; } - (NSComparisonResult) compareBySectionAndName:(Package *)package { - NSComparisonResult result = [[self section] caseInsensitiveCompare:[package section]]; - if (result != NSOrderedSame) - return result; + NSString *lhs = [self section]; + NSString *rhs = [package section]; + + if (lhs == NULL && rhs != NULL) + return NSOrderedAscending; + else if (lhs != NULL && rhs == NULL) + return NSOrderedDescending; + else if (lhs != NULL && rhs != NULL) { + NSComparisonResult result = [lhs compare:rhs]; + if (result != NSOrderedSame) + return result; + } + return [self compareByName:package]; } @@ -1236,14 +1507,14 @@ NSString *Scour(const char *field, const char *begin, const char *end) { } - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table { - return 2; + return 3; } - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group { switch (group) { case 0: return nil; - case 1: return @"Details"; - case 2: return @"Source"; + case 1: return @"Package Details"; + case 2: return @"Source Information"; default: _assert(false); } @@ -1258,9 +1529,9 @@ NSString *Scour(const char *field, const char *begin, const char *end) { - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group { switch (group) { - case 0: return 2; + case 0: return [package_ website] == nil ? 2 : 3; case 1: return 5; - case 2: return 0; + case 2: return 3; default: _assert(false); } @@ -1281,6 +1552,12 @@ NSString *Scour(const char *field, const char *begin, const char *end) { [cell addSubview:description_]; break; + case 2: + [cell setTitle:@"More Information"]; + [cell setShowDisclosure:YES]; + [cell setShowSelection:YES]; + break; + default: _assert(false); } break; @@ -1296,10 +1573,11 @@ NSString *Scour(const char *field, const char *begin, const char *end) { [cell setValue:(installed == nil ? @"n/a" : installed)]; } break; - case 2: + case 2: { [cell setTitle:@"Section"]; - [cell setValue:[package_ section]]; - break; + NSString *section([package_ section]); + [cell setValue:(section == nil ? @"n/a" : section)]; + } break; case 3: [cell setTitle:@"Expanded Size"]; @@ -1317,6 +1595,21 @@ NSString *Scour(const char *field, const char *begin, const char *end) { } break; case 2: switch (row) { + case 0: + [cell setTitle:[[package_ source] label]]; + [cell setValue:[[package_ source] version]]; + break; + + case 1: + [cell setValue:[[package_ source] description]]; + break; + + case 2: + [cell setTitle:@"Origin"]; + [cell setValue:[[package_ source] origin]]; + break; + + default: _assert(false); } break; default: _assert(false); @@ -1330,15 +1623,16 @@ NSString *Scour(const char *field, const char *begin, const char *end) { } - (void) tableRowSelected:(NSNotification *)notification { - printf("%d\n", [table_ selectedRow]); - switch ([table_ selectedRow]) { - case 8: - [delegate_ openURL:[NSURL URLWithString:[NSString stringWithFormat:@"mailto:%@?subject=%@", - [[package_ maintainer] email], - [[NSString stringWithFormat:@"regarding apt package \"%@\"", [package_ name]] stringByAddingPercentEscapes] - ]]]; - break; - } + int row = [table_ selectedRow]; + NSString *website = [package_ website]; + + if (row == (website == nil ? 8 : 9)) + [delegate_ openURL:[NSURL URLWithString:[NSString stringWithFormat:@"mailto:%@?subject=%@", + [[package_ maintainer] email], + [[NSString stringWithFormat:@"regarding apt package \"%@\"", [package_ name]] stringByAddingPercentEscapes] + ]]]; + else if (website != nil && row == 3) + [delegate_ openURL:[NSURL URLWithString:website]]; } - (Package *) package { @@ -1391,9 +1685,12 @@ NSString *Scour(const char *field, const char *begin, const char *end) { /* }}} */ /* Package Cell {{{ */ @interface PackageCell : UITableCell { + UIImageView *icon_; UITextLabel *name_; - UITextLabel *version_; UITextLabel *description_; + UITextLabel *source_; + UITextLabel *version_; + UIImageView *trusted_; SEL versioner_; } @@ -1412,9 +1709,12 @@ NSString *Scour(const char *field, const char *begin, const char *end) { @implementation PackageCell - (void) dealloc { + [icon_ release]; [name_ release]; - [version_ release]; [description_ release]; + [source_ release]; + [version_ release]; + [trusted_ release]; [super dealloc]; } @@ -1430,21 +1730,33 @@ NSString *Scour(const char *field, const char *begin, const char *end) { CGColor clear(space, 0, 0, 0, 0); - name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(12, 7, 250, 25)]; + icon_ = [[UIImageView alloc] initWithFrame:CGRectMake(10, 10, 30, 30)]; + + name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 12, 240, 25)]; [name_ setBackgroundColor:clear]; [name_ setFont:bold]; - version_ = [[UIRightTextLabel alloc] initWithFrame:CGRectMake(286, 7, 70, 25)]; + description_ = [[UITextLabel alloc] initWithFrame:CGRectMake(12, 46, 280, 20)]; + [description_ setBackgroundColor:clear]; + [description_ setFont:small]; + + source_ = [[UITextLabel alloc] initWithFrame:CGRectMake(12, 72, 225, 20)]; + [source_ setBackgroundColor:clear]; + [source_ setFont:large]; + + version_ = [[UIRightTextLabel alloc] initWithFrame:CGRectMake(286, 69, 70, 25)]; [version_ setBackgroundColor:clear]; [version_ setFont:large]; - description_ = [[UITextLabel alloc] initWithFrame:CGRectMake(13, 35, 315, 20)]; - [description_ setBackgroundColor:clear]; - [description_ setFont:small]; + //trusted_ = [[UIImageView alloc] initWithFrame:CGRectMake(278, 7, 16, 16)]; + trusted_ = [[UIImageView alloc] initWithFrame:CGRectMake(30, 30, 16, 16)]; + [trusted_ setImage:[UIImage applicationImageNamed:@"trusted.png"]]; + [self addSubview:icon_]; [self addSubview:name_]; - [self addSubview:version_]; [self addSubview:description_]; + [self addSubview:source_]; + [self addSubview:version_]; CGColorSpaceRelease(space); @@ -1455,9 +1767,43 @@ NSString *Scour(const char *field, const char *begin, const char *end) { } - (void) setPackage:(Package *)package { + Source *source = [package source]; + + UIImage *image = nil; + if (NSString *icon = [package icon]) + image = [UIImage imageAtPath:[icon substringFromIndex:6]]; + if (image == nil) if (NSString *icon = [source defaultIcon]) + image = [UIImage imageAtPath:[icon substringFromIndex:6]]; + if (image == nil) + image = [UIImage applicationImageNamed:@"unknown.png"]; + + [icon_ setImage:image]; + [icon_ zoomToScale:0.5f]; + [icon_ setFrame:CGRectMake(10, 10, 30, 30)]; + [name_ setText:[package name]]; [version_ setText:[package latest]]; [description_ setText:[package tagline]]; + + NSString *label; + bool trusted; + + if (source != nil) { + label = [source label]; + trusted = [source trusted]; + } else if ([[package id] isEqualToString:@"firmware"]) { + label = @"Apple"; + trusted = false; + } else { + label = @"Unknown/Local"; + trusted = false; + } + + [source_ setText:[NSString stringWithFormat:@"from %@", label]]; + + [trusted_ removeFromSuperview]; + if (trusted) + [self addSubview:trusted_]; } - (void) _setSelected:(float)fraction { @@ -1482,8 +1828,9 @@ NSString *Scour(const char *field, const char *begin, const char *end) { 1.0); [name_ setColor:black]; - [version_ setColor:blue]; [description_ setColor:gray]; + [source_ setColor:black]; + [version_ setColor:blue]; CGColorSpaceRelease(space); } @@ -1583,6 +1930,9 @@ NSString *Scour(const char *field, const char *begin, const char *end) { fetcher_ = NULL; lock_ = NULL; + sources_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain]; + packages_ = [[NSMutableArray arrayWithCapacity:16] retain]; + int fds[2]; _assert(pipe(fds) != -1); @@ -1622,19 +1972,52 @@ NSString *Scour(const char *field, const char *begin, const char *end) { return *fetcher_; } +- (NSArray *) packages { + return packages_; +} + - (void) reloadData { _error->Discard(); + delete list_; manager_ = NULL; delete lock_; delete fetcher_; delete resolver_; delete records_; cache_.Close(); - _assert(cache_.Open(progress_, true)); + + if (!cache_.Open(progress_, true)) { + fprintf(stderr, "repairing corrupted database...\n"); + _error->Discard(); + [self update]; + _assert(cache_.Open(progress_, true)); + } + + now_ = [NSDate date]; + records_ = new pkgRecords(cache_); resolver_ = new pkgProblemResolver(cache_); fetcher_ = new pkgAcquire(&status_); lock_ = NULL; + + list_ = new pkgSourceList(); + _assert(list_->ReadMainList()); + + [sources_ removeAllObjects]; + for (pkgSourceList::const_iterator source = list_->begin(); source != list_->end(); ++source) { + std::vector *indices = (*source)->GetIndexFiles(); + for (std::vector::const_iterator index = indices->begin(); index != indices->end(); ++index) + [sources_ + setObject:[[[Source alloc] initWithMetaIndex:*source] autorelease] + forKey:[NSNumber numberWithLong:reinterpret_cast(*index)] + ]; + } + + [packages_ removeAllObjects]; + for (pkgCache::PkgIterator iterator = cache_->PkgBegin(); !iterator.end(); ++iterator) + if (Package *package = [Package packageWithIterator:iterator database:self]) + if ([package source] != nil || [package installed] != nil) + [packages_ addObject:package]; } - (void) prepare { @@ -1713,6 +2096,12 @@ NSString *Scour(const char *field, const char *begin, const char *end) { progress_.setDelegate(delegate); } +- (Source *) getSource:(const pkgCache::PkgFileIterator &)file { + pkgIndexFile *index(NULL); + list_->FindIndex(file, index); + return [sources_ objectForKey:[NSNumber numberWithLong:reinterpret_cast(index)]]; +} + @end /* }}} */ @@ -1771,6 +2160,8 @@ NSString *Scour(const char *field, const char *begin, const char *end) { - (void) dealloc; +- (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to; + - (ProgressView *) initWithFrame:(struct CGRect)frame delegate:(id)delegate; - (void) setContentView:(UIView *)view; - (void) resetView; @@ -1802,7 +2193,8 @@ NSString *Scour(const char *field, const char *begin, const char *end) { - (void) dealloc { [view_ release]; - [background_ release]; + if (background_ != nil) + [background_ release]; [transition_ release]; [overlay_ release]; [navbar_ release]; @@ -1812,6 +2204,11 @@ NSString *Scour(const char *field, const char *begin, const char *end) { [super dealloc]; } +- (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to { + if (bootstrap_ && from == overlay_ && to == view_) + exit(0); +} + - (ProgressView *) initWithFrame:(struct CGRect)frame delegate:(id)delegate { if ((self = [super initWithFrame:frame]) != nil) { delegate_ = delegate; @@ -1822,15 +2219,21 @@ NSString *Scour(const char *field, const char *begin, const char *end) { CGColor white(space, 1.0, 1.0, 1.0, 1.0); CGColor clear(space, 0.0, 0.0, 0.0, 0.0); - background_ = [[UIView alloc] initWithFrame:[self bounds]]; - [background_ setBackgroundColor:black]; - [self addSubview:background_]; - transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]]; - [self addSubview:transition_]; + [transition_ setDelegate:self]; overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]]; + if (bootstrap_) + [overlay_ setBackgroundColor:black]; + else { + background_ = [[UIView alloc] initWithFrame:[self bounds]]; + [background_ setBackgroundColor:black]; + [self addSubview:background_]; + } + + [self addSubview:transition_]; + CGSize navsize = [UINavigationBar defaultSize]; CGRect navrect = {{0, 0}, navsize}; @@ -2067,7 +2470,7 @@ NSString *Scour(const char *field, const char *begin, const char *end) { } - (float) table:(UITable *)table heightForRow:(int)row { - return 64; + return 100; } - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing { @@ -2185,7 +2588,7 @@ NSString *Scour(const char *field, const char *begin, const char *end) { CGColor clear(space, 0, 0, 0, 0); CGColor white(space, 1, 1, 1, 1); - name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(47, 9, 250, 25)]; + name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 9, 250, 25)]; [name_ setBackgroundColor:clear]; [name_ setFont:bold]; @@ -2216,7 +2619,8 @@ NSString *Scour(const char *field, const char *begin, const char *end) { [name_ setText:@"All Packages"]; [count_ setText:nil]; } else { - [name_ setText:[section name]]; + NSString *name = [section name]; + [name_ setText:(name == nil ? @"(No Section)" : name)]; [count_ setText:[NSString stringWithFormat:@"%d", [section count]]]; } } @@ -2431,10 +2835,10 @@ NSString *Scour(const char *field, const char *begin, const char *end) { Package *package = [packages_ objectAtIndex:offset]; NSString *name = [package section]; - if (section == nil || ![[section name] isEqual:name]) { + if (section == nil || name != nil && ![[section name] isEqual:name]) { section = [[[Section alloc] initWithName:name row:offset] autorelease]; - if ([name isEqualToString:section_]) + if (name == nil || [name isEqualToString:section_]) nsection = section; [sections addObject:section]; } @@ -2459,12 +2863,15 @@ NSString *Scour(const char *field, const char *begin, const char *end) { else if (package_ != nil) ++views; - if (nsection != nil) + if (table_ != nil && section_ == nil) + [table_ setPackages:packages_]; + else if (nsection != nil) [table_ setPackages:[nsection packages]]; else if (section_ != nil) ++views; - [self popViews:views]; + if (views != 0) + [self popViews:views]; [self setPrompt]; } @@ -2540,7 +2947,7 @@ NSString *Scour(const char *field, const char *begin, const char *end) { } - (float) table:(UITable *)table heightForRow:(int)row { - return 64; + return 100; } - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing { @@ -2560,8 +2967,17 @@ NSString *Scour(const char *field, const char *begin, const char *end) { } - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button { - if (button == 1) - [delegate_ upgrade]; + switch (button) { + case 0: + [[view_ package] install]; + [delegate_ resolve]; + [delegate_ perform]; + break; + + case 1: + [delegate_ upgrade]; + break; + } } - (void) packageTable:(id)table packageSelected:(Package *)package { @@ -2641,11 +3057,19 @@ NSString *Scour(const char *field, const char *begin, const char *end) { else { NSDate *seen = [package seen]; - CFLocaleRef locale = CFLocaleCopyCurrent(); - CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle); - CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen); - - NSString *name = (NSString *) formatted; + NSString *name; + CFStringRef formatted = NULL; + + if (seen == nil) + name = @"n/a ?"; + else { + CFLocaleRef locale = CFLocaleCopyCurrent(); + CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle); + formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen); + name = (NSString *) formatted; + CFRelease(formatter); + CFRelease(locale); + } if (section == nil || ![[section name] isEqual:name]) { section = [[[Section alloc] initWithName:name row:offset] autorelease]; @@ -2654,9 +3078,8 @@ NSString *Scour(const char *field, const char *begin, const char *end) { [section addPackage:package]; - CFRelease(formatter); - CFRelease(formatted); - CFRelease(locale); + if (formatted != NULL) + CFRelease(formatted); } } @@ -2670,15 +3093,14 @@ NSString *Scour(const char *field, const char *begin, const char *end) { [view_ setPackage:npackage]; else if (package_ != nil) [self popViews:1]; - if ([views_ count] == 1) - [self _resetView]; + [self _resetView]; [self setPrompt]; } - (void) _resetView { - [navbar_ showButtonsWithLeftTitle:(count_ == 0 ? nil : @"Upgrade All") rightTitle:nil]; - [super _resetView]; + if ([views_ count] == 1) + [navbar_ showButtonsWithLeftTitle:(count_ == 0 ? nil : @"Upgrade All") rightTitle:nil]; } - (size_t) count { @@ -2950,7 +3372,11 @@ NSString *Scour(const char *field, const char *begin, const char *end) { /* XXX: for the love of god just fix this */ [navbar_ removeFromSuperview]; + [reload_ removeFromSuperview]; + [configure_ removeFromSuperview]; [self addSubview:navbar_]; + [self addSubview:reload_]; + [self addSubview:configure_]; } return self; } @@ -3035,6 +3461,7 @@ NSString *Scour(const char *field, const char *begin, const char *end) { SearchView *search_; bool restart_; + unsigned tag_; UIKeyboard *keyboard_; } @@ -3059,6 +3486,8 @@ NSString *Scour(const char *field, const char *begin, const char *end) { - (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old; +- (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame; + - (void) applicationWillSuspend; - (void) applicationDidFinishLaunching:(id)unused; @end @@ -3072,11 +3501,11 @@ NSString *Scour(const char *field, const char *begin, const char *end) { timeoutInterval:30.0 ]; + [request addValue:[NSString stringWithCString:Firmware_] forHTTPHeaderField:@"X-Firmware"]; [request addValue:[NSString stringWithCString:Machine_] forHTTPHeaderField:@"X-Machine"]; [request addValue:[NSString stringWithCString:SerialNumber_] forHTTPHeaderField:@"X-Serial-Number"]; [webview_ loadRequest:request]; - [indicator_ startAnimation]; } - (void) reloadData:(BOOL)reset { @@ -3089,27 +3518,23 @@ NSString *Scour(const char *field, const char *begin, const char *end) { [Metadata_ setObject:Packages_ forKey:@"Packages"]; } - now_ = [NSDate date]; - - NSMutableArray *packages = [NSMutableArray arrayWithCapacity:count]; - for (pkgCache::PkgIterator iterator = [database_ cache]->PkgBegin(); !iterator.end(); ++iterator) - if (Package *package = [Package packageWithIterator:iterator database:database_]) - [packages addObject:package]; + NSArray *packages = [database_ packages]; [install_ setPackages:packages]; [changes_ setPackages:packages]; [manage_ setPackages:packages]; [search_ setPackages:packages]; - //[self setPrompt]; if (size_t count = [changes_ count]) { NSString *badge([[NSNumber numberWithInt:count] stringValue]); [buttonbar_ setBadgeValue:badge forButton:3]; - [buttonbar_ setBadgeAnimated:YES forButton:3]; + if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)]) + [buttonbar_ setBadgeAnimated:YES forButton:3]; [self setApplicationBadge:badge]; } else { [buttonbar_ setBadgeValue:nil forButton:3]; - [buttonbar_ setBadgeAnimated:NO forButton:3]; + if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)]) + [buttonbar_ setBadgeAnimated:NO forButton:3]; [self removeApplicationBadge]; } @@ -3117,17 +3542,7 @@ NSString *Scour(const char *field, const char *begin, const char *end) { } - (void) setPrompt { - NSDate *update = [Metadata_ objectForKey:@"LastUpdate"]; - - CFLocaleRef locale = CFLocaleCopyCurrent(); - CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle); - CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) update); - - [navbar_ setPrompt:[NSString stringWithFormat:@"Last Updated: %@", (NSString *) formatted]]; - - CFRelease(formatter); - CFRelease(formatted); - CFRelease(locale); + [navbar_ setPrompt:[NSString stringWithFormat:@"Last Updated: %@", GetLastUpdate()]]; } - (void) resolve { @@ -3140,7 +3555,32 @@ NSString *Scour(const char *field, const char *begin, const char *end) { - (void) perform { [database_ prepare]; - confirm_ = [[ConfirmationView alloc] initWithView:underlay_ database:database_ delegate:self]; + + if ([database_ cache]->BrokenCount() == 0) + confirm_ = [[ConfirmationView alloc] initWithView:underlay_ database:database_ delegate:self]; + else { + NSMutableArray *broken = [NSMutableArray arrayWithCapacity:16]; + NSArray *packages = [database_ packages]; + + for (size_t i(0); i != [packages count]; ++i) { + Package *package = [packages objectAtIndex:i]; + if ([package broken]) + [broken addObject:[package name]]; + } + + UIAlertSheet *sheet = [[[UIAlertSheet alloc] + initWithTitle:[NSString stringWithFormat:@"%d Broken Packages", [database_ cache]->BrokenCount()] + buttons:[NSArray arrayWithObjects:@"Okay", nil] + defaultButtonIndex:0 + delegate:self + context:self + ] autorelease]; + + [sheet setBodyText:[NSString stringWithFormat:@"The following packages have unmet dependencies:\n\n%@", [broken componentsJoinedByString:@"\n"]]]; + [sheet popupAlertAnimated:YES]; + + [self reloadData:NO]; + } } - (void) upgrade { @@ -3166,6 +3606,22 @@ NSString *Scour(const char *field, const char *begin, const char *end) { ]; } +- (void) bootstrap_ { + [database_ update]; + [database_ upgrade]; + [database_ prepare]; + [database_ perform]; +} + +- (void) bootstrap { + [progress_ + detachNewThreadSelector:@selector(bootstrap_) + toTarget:self + withObject:nil + title:@"Bootstrap Install..." + ]; +} + - (void) update { [progress_ detachNewThreadSelector:@selector(update) @@ -3234,8 +3690,9 @@ NSString *Scour(const char *field, const char *begin, const char *end) { - (void) buttonBarItemTapped:(id)sender { UIView *view; + unsigned tag = [sender tag]; - switch ([sender tag]) { + switch (tag) { case 1: view = featured_; break; case 2: view = install_; break; case 3: view = changes_; break; @@ -3246,19 +3703,34 @@ NSString *Scour(const char *field, const char *begin, const char *end) { _assert(false); } - if ([view respondsToSelector:@selector(resetView)]) - [(id) view resetView]; + if ([view respondsToSelector:@selector(resetView:)]) + [(id) view resetView:(tag == tag_ ? NO : YES)]; + tag_ = tag; [transition_ transition:0 toView:view]; } -- (void) view:(UIView *)view didSetFrame:(CGRect)frame oldFrame:(CGRect)old { +- (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old { [scroller_ setContentSize:frame.size]; [indicator_ stopAnimation]; } +- (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame { + [navbar_ setPrompt:title]; +} + +- (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame { + [navbar_ setPrompt:@"Loading..."]; + [indicator_ startAnimation]; +} + - (void) applicationWillSuspend { if (restart_) - system("launchctl stop com.apple.SpringBoard"); + if (FW_LEAST(1,1,3)) + notify_post("com.apple.language.changed"); + else + system("launchctl stop com.apple.SpringBoard"); + + [super applicationWillSuspend]; } - (void) applicationDidFinishLaunching:(id)unused { @@ -3267,8 +3739,8 @@ NSString *Scour(const char *field, const char *begin, const char *end) { confirm_ = nil; restart_ = false; + tag_ = 1; - _trace(); CGRect screenrect = [UIHardware fullScreenApplicationContentRect]; window_ = [[UIWindow alloc] initWithContentRect:screenrect]; @@ -3283,7 +3755,9 @@ NSString *Scour(const char *field, const char *begin, const char *end) { [progress_ setContentView:underlay_]; overlay_ = [[UIView alloc] initWithFrame:[underlay_ bounds]]; - [underlay_ addSubview:overlay_]; + + if (!bootstrap_) + [underlay_ addSubview:overlay_]; transition_ = [[UITransitionView alloc] initWithFrame:CGRectMake( 0, 0, screenrect.size.width, screenrect.size.height - 48 @@ -3301,7 +3775,6 @@ NSString *Scour(const char *field, const char *begin, const char *end) { [navbar_ setBarStyle:1]; [navbar_ setDelegate:self]; - [navbar_ setPrompt:@"Welcome to Cydia Packager"]; [navbar_ showButtonsWithLeftTitle:@"About" rightTitle:@"Reload"]; @@ -3326,7 +3799,10 @@ NSString *Scour(const char *field, const char *begin, const char *end) { [scroller_ setScrollDecelerationFactor:0.99]; [scroller_ setDelegate:self]; - webview_ = [[UIWebView alloc] initWithFrame:[scroller_ bounds]]; + CGRect webrect = [scroller_ bounds]; + webrect.size.height = 0; + + webview_ = [[UIWebView alloc] initWithFrame:webrect]; [scroller_ addSubview:webview_]; [webview_ setTilingEnabled:YES]; @@ -3416,57 +3892,52 @@ NSString *Scour(const char *field, const char *begin, const char *end) { [buttonbar_ showSelectionForButton:1]; [transition_ transition:0 toView:featured_]; - _trace(); [overlay_ addSubview:buttonbar_]; - _trace(); [UIKeyboard initImplementationNow]; - _trace(); CGRect edtrect = [overlay_ bounds]; edtrect.origin.y += navsize.height; edtrect.size.height -= navsize.height; - _trace(); CGSize keysize = [UIKeyboard defaultSize]; CGRect keyrect = {{0, [overlay_ bounds].size.height - keysize.height}, keysize}; keyboard_ = [[UIKeyboard alloc] initWithFrame:keyrect]; - _trace(); database_ = [[Database alloc] init]; [database_ setDelegate:progress_]; - _trace(); install_ = [[InstallView alloc] initWithFrame:[transition_ bounds]]; [install_ setDelegate:self]; - _trace(); changes_ = [[ChangesView alloc] initWithFrame:[transition_ bounds]]; [changes_ setDelegate:self]; - _trace(); manage_ = [[ManageView alloc] initWithFrame:[transition_ bounds]]; [manage_ setDelegate:self]; - _trace(); search_ = [[SearchView alloc] initWithFrame:[transition_ bounds]]; [search_ setDelegate:self]; - _trace(); [self reloadData:NO]; - _trace(); - [progress_ resetView]; - _trace(); Package *package([database_ packageWithName:@"cydia"]); - NSString *application = package == nil ? @"Cydia" : [NSString stringWithFormat:@"Cydia/%@", [package installed]]; + NSString *application = package == nil ? @"Cydia" : [NSString + stringWithFormat:@"Cydia/%@", + [package installed] + ]; + WebView *webview = [webview_ webView]; [webview setApplicationNameForUserAgent:application]; + [webview setFrameLoadDelegate:self]; - _trace(); url_ = [NSURL URLWithString:@"http://cydia.saurik.com/"]; [self loadNews]; - _trace(); + + [progress_ resetView]; + + if (bootstrap_) + [self bootstrap]; } - (void) showKeyboard:(BOOL)show { @@ -3534,6 +4005,8 @@ int main(int argc, char *argv[]) { if (nl[0].n_type != N_UNDF) *(int *) nl[0].n_value = 0; + bootstrap_ = argc > 1 && strcmp(argv[1], "--bootstrap") == 0; + setuid(0); setgid(0); @@ -3543,6 +4016,17 @@ int main(int argc, char *argv[]) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + if (NSDictionary *sysver = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]) { + if (NSString *prover = [sysver valueForKey:@"ProductVersion"]) { + Firmware_ = strdup([prover cString]); + NSArray *versions = [prover componentsSeparatedByString:@"."]; + int count = [versions count]; + Major_ = count > 0 ? [[versions objectAtIndex:0] intValue] : 0; + Minor_ = count > 1 ? [[versions objectAtIndex:1] intValue] : 0; + BugFix_ = count > 2 ? [[versions objectAtIndex:2] intValue] : 0; + } + } + size_t size; sysctlbyname("hw.machine", NULL, &size, NULL, 0); char *machine = new char[size]; @@ -3559,14 +4043,19 @@ int main(int argc, char *argv[]) { IOObjectRelease(service); } - AddPreferences(@"/Applications/Preferences.app/Settings-iPhone.plist"); - AddPreferences(@"/Applications/Preferences.app/Settings-iPod.plist"); + /*AddPreferences(@"/Applications/Preferences.app/Settings-iPhone.plist"); + AddPreferences(@"/Applications/Preferences.app/Settings-iPod.plist");*/ if ((Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"]) == NULL) Metadata_ = [[NSMutableDictionary alloc] initWithCapacity:2]; else Packages_ = [Metadata_ objectForKey:@"Packages"]; + setenv("CYDIA", "", _not(int)); + if (access("/User", F_OK) != 0) + system("/usr/libexec/cydia/firmware.sh"); + system("dpkg --configure -a"); + UIApplicationMain(argc, argv, [Cydia class]); [pool release]; return 0;