X-Git-Url: https://git.saurik.com/cydia.git/blobdiff_plain/6565453ace2265368e4a2116f75ed2f5bfeeb0c3..e124f5222a28c2a3e2081155cbaa02017b763b93:/Cydia.mm diff --git a/Cydia.mm b/Cydia.mm index 4b3fa9f1..d898ef3a 100644 --- a/Cydia.mm +++ b/Cydia.mm @@ -35,9 +35,13 @@ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +// XXX: wtf/FastMalloc.h... wtf? +#define USE_SYSTEM_MALLOC 1 + /* #include Directives {{{ */ #import "UICaboodle.h" +#include #include #include @@ -52,22 +56,7 @@ // XXX: remove #import -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#import -#import - -#import - +#include #include #include @@ -92,6 +81,8 @@ #include #include #include +#include +#include #include #include @@ -109,6 +100,8 @@ extern "C" { #import "BrowserView.h" #import "ResetView.h" + +#import "substrate.h" /* }}} */ //#define _finline __attribute__((force_inline)) @@ -123,14 +116,71 @@ bool _itv; exit(0); \ } while (false) -static uint64_t profile_; - #define _timestamp ({ \ struct timeval tv; \ gettimeofday(&tv, NULL); \ tv.tv_sec * 1000000 + tv.tv_usec; \ }) +typedef std::vector TimeList; +TimeList times_; + +class ProfileTime { + private: + const char *name_; + uint64_t total_; + uint64_t count_; + + public: + ProfileTime(const char *name) : + name_(name), + total_(0) + { + times_.push_back(this); + } + + void AddTime(uint64_t time) { + total_ += time; + ++count_; + } + + void Print() { + if (total_ != 0) + std::cerr << std::setw(5) << count_ << ", " << std::setw(7) << total_ << " : " << name_ << std::endl; + total_ = 0; + count_ = 0; + } +}; + +class ProfileTimer { + private: + ProfileTime &time_; + uint64_t start_; + + public: + ProfileTimer(ProfileTime &time) : + time_(time), + start_(_timestamp) + { + } + + ~ProfileTimer() { + time_.AddTime(_timestamp - start_); + } +}; + +void PrintTimes() { + for (TimeList::const_iterator i(times_.begin()); i != times_.end(); ++i) + (*i)->Print(); + std::cerr << "========" << std::endl; +} + +#define _profile(name) { \ + static ProfileTime name(#name); \ + ProfileTimer _ ## name(name); + +#define _end } + /* Objective-C Handle<> {{{ */ template class _H { @@ -181,7 +231,72 @@ void NSLogRect(const char *fix, const CGRect &rect) { NSLog(@"%s(%g,%g)+(%g,%g)", fix, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height); } +@interface NSObject (Cydia) +- (id) yieldToSelector:(SEL)selector withObject:(id)object; +- (id) yieldToSelector:(SEL)selector; +@end + +@implementation NSObject (Cydia) + +- (void) doNothing { +} + +- (void) _yieldToContext:(NSMutableArray *)context { _pooled + SEL selector(reinterpret_cast([[context objectAtIndex:0] pointerValue])); + id object([[context objectAtIndex:1] nonretainedObjectValue]); + volatile bool &stopped(*reinterpret_cast([[context objectAtIndex:2] pointerValue])); + + /* XXX: deal with exceptions */ + id value([self performSelector:selector withObject:object]); + + [context removeAllObjects]; + if (value != nil) + [context addObject:value]; + + stopped = true; + + [self + performSelectorOnMainThread:@selector(doNothing) + withObject:nil + waitUntilDone:NO + ]; +} + +- (id) yieldToSelector:(SEL)selector withObject:(id)object { + /*return [self performSelector:selector withObject:object];*/ + + volatile bool stopped(false); + + NSMutableArray *context([NSMutableArray arrayWithObjects: + [NSValue valueWithPointer:selector], + [NSValue valueWithNonretainedObject:object], + [NSValue valueWithPointer:const_cast(&stopped)], + nil]); + + NSThread *thread([[[NSThread alloc] + initWithTarget:self + selector:@selector(_yieldToContext:) + object:context + ] autorelease]); + + [thread start]; + + NSRunLoop *loop([NSRunLoop currentRunLoop]); + NSDate *future([NSDate distantFuture]); + + while (!stopped && [loop runMode:NSDefaultRunLoopMode beforeDate:future]); + + return [context count] == 0 ? nil : [context objectAtIndex:0]; +} + +- (id) yieldToSelector:(SEL)selector { + return [self yieldToSelector:selector withObject:nil]; +} + +@end + /* NSForcedOrderingSearch doesn't work on the iPhone */ +static const NSStringCompareOptions MatchCompareOptions_ = NSLiteralSearch | NSCaseInsensitiveSearch; static const NSStringCompareOptions BaseCompareOptions_ = NSNumericSearch | NSDiacriticInsensitiveSearch | NSWidthInsensitiveSearch; static const NSStringCompareOptions ForcedCompareOptions_ = BaseCompareOptions_; static const NSStringCompareOptions LaxCompareOptions_ = BaseCompareOptions_ | NSCaseInsensitiveSearch; @@ -238,18 +353,13 @@ extern NSString * const kCAFilterNearest; @implementation PopTransitionView -- (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to { +- (void) transitionViewDidComplete:(UITransitionView *)view fromView:(UIView *)from toView:(UIView *)to { if (from != nil && to == nil) [self removeFromSuperview]; } @end -@interface UIView (PopUpView) -- (void) popFromSuperviewAnimated:(BOOL)animated; -- (void) popSubview:(UIView *)view; -@end - @implementation UIView (PopUpView) - (void) popFromSuperviewAnimated:(BOOL)animated { @@ -271,11 +381,23 @@ extern NSString * const kCAFilterNearest; #define lprintf(args...) fprintf(stderr, args) -#define ForRelease 0 +#define ForRelease 1 #define ForSaurik (1 && !ForRelease) +#define ShowInternals (1 && !ForRelease) +#define IgnoreInstall (0 && !ForRelease) #define RecycleWebViews 0 #define AlwaysReload (1 && !ForRelease) +#if ForRelease +#undef _trace +#define _trace(args...) +#undef _profile +#define _profile(name) { +#undef _end +#define _end } +#define PrintTimes() do {} while (false) +#endif + /* Radix Sort {{{ */ @interface NSMutableArray (Radix) - (void) radixSortUsingSelector:(SEL)selector withObject:(id)object; @@ -411,12 +533,19 @@ NSUInteger DOMNodeList$countByEnumeratingWithState$objects$count$(DOMNodeList *s @end @interface NSString (Cydia) ++ (NSString *) stringWithUTF8BytesNoCopy:(const char *)bytes length:(int)length; + (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length; - (NSComparisonResult) compareByPath:(NSString *)other; +- (NSString *) stringByCachingURLWithCurrentCDN; +- (NSString *) stringByAddingPercentEscapesIncludingReserved; @end @implementation NSString (Cydia) ++ (NSString *) stringWithUTF8BytesNoCopy:(const char *)bytes length:(int)length { + return [[[NSString alloc] initWithBytesNoCopy:const_cast(bytes) length:length encoding:NSUTF8StringEncoding freeWhenDone:NO] autorelease]; +} + + (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length { return [[[NSString alloc] initWithBytes:bytes length:length encoding:NSUTF8StringEncoding] autorelease]; } @@ -451,6 +580,26 @@ NSUInteger DOMNodeList$countByEnumeratingWithState$objects$count$(DOMNodeList *s return result == NSOrderedSame ? value : result; } +- (NSString *) stringByCachingURLWithCurrentCDN { + return [self + stringByReplacingOccurrencesOfString:@"://" + withString:@"://ne.edgecastcdn.net/8003A4/" + options:0 + /* XXX: this is somewhat inaccurate */ + range:NSMakeRange(0, 10) + ]; +} + +- (NSString *) stringByAddingPercentEscapesIncludingReserved { + return [(id)CFURLCreateStringByAddingPercentEscapes( + kCFAllocatorDefault, + (CFStringRef) self, + NULL, + CFSTR(";/?:@&=+$,"), + kCFStringEncodingUTF8 + ) autorelease]; +} + @end /* Perl-Compatible RegEx {{{ */ @@ -611,6 +760,7 @@ static const float KeyboardTime_ = 0.3f; #define SpringBoard_ "/System/Library/LaunchDaemons/com.apple.SpringBoard.plist" #define SandboxTemplate_ "/usr/share/sandbox/SandboxTemplate.sb" +#define NotifyConfig_ "/etc/notify.conf" static CGColor Blue_; static CGColor Blueish_; @@ -624,9 +774,7 @@ static NSString *Home_; static BOOL Sounds_Keyboard_; static BOOL Advanced_; -#if !ForSaurik static BOOL Loaded_; -#endif static BOOL Ignored_; static UIFont *Font12_; @@ -636,26 +784,19 @@ static UIFont *Font18Bold_; static UIFont *Font22Bold_; static const char *Machine_ = NULL; -static const NSString *UniqueID_ = NULL; - -unsigned Major_; -unsigned Minor_; -unsigned BugFix_; +static const NSString *UniqueID_ = nil; +static const NSString *Build_ = nil; +static const NSString *Product_ = nil; +static const NSString *Safari_ = nil; CFLocaleRef Locale_; CGColorSpaceRef space_; -#define FW_LEAST(major, minor, bugfix) \ - (major < Major_ || major == Major_ && \ - (minor < Minor_ || minor == Minor_ && \ - bugfix <= BugFix_)) - bool bootstrap_; bool reload_; static NSDictionary *SectionMap_; static NSMutableDictionary *Metadata_; -static NSMutableDictionary *Indices_; static _transient NSMutableDictionary *Settings_; static _transient NSString *Role_; static _transient NSMutableDictionary *Packages_; @@ -777,6 +918,7 @@ bool isSectionVisible(NSString *section) { - (void) syncData; - (void) askForSettings; - (UIProgressHUD *) addProgressHUD; +- (void) removeProgressHUD:(UIProgressHUD *)hud; - (RVPage *) pageForURL:(NSURL *)url hasTag:(int *)tag; - (RVPage *) pageForPackage:(NSString *)name; - (void) openMailToURL:(NSURL *)url; @@ -869,8 +1011,8 @@ class Progress : protected: virtual void Update() { - [delegate_ setProgressTitle:[NSString stringWithUTF8String:Op.c_str()]]; - [delegate_ setProgressPercent:(Percent / 100)]; + /*[delegate_ setProgressTitle:[NSString stringWithUTF8String:Op.c_str()]]; + [delegate_ setProgressPercent:(Percent / 100)];*/ } public: @@ -884,13 +1026,15 @@ class Progress : } virtual void Done() { - [delegate_ setProgressPercent:1]; + //[delegate_ setProgressPercent:1]; } }; /* }}} */ /* Database Interface {{{ */ @interface Database : NSObject { + unsigned era_; + pkgCacheFile cache_; pkgDepCache::Policy *policy_; pkgRecords *records_; @@ -913,6 +1057,7 @@ class Progress : } + (Database *) sharedInstance; +- (unsigned) era; - (void) _readCydia:(NSNumber *)fd; - (void) _readStatus:(NSNumber *)fd; @@ -927,6 +1072,7 @@ class Progress : - (pkgRecords *) records; - (pkgProblemResolver *) resolver; - (pkgAcquire &) fetcher; +- (pkgSourceList &) list; - (NSArray *) packages; - (NSArray *) sources; - (void) reloadData; @@ -986,24 +1132,26 @@ class Progress : @implementation Source -- (void) dealloc { - [uri_ release]; - [distribution_ release]; - [type_ release]; +#define _clear(field) \ + if (field != nil) \ + [field release]; \ + field = nil; - if (description_ != nil) - [description_ release]; - if (label_ != nil) - [label_ release]; - if (origin_ != nil) - [origin_ release]; - if (version_ != nil) - [version_ release]; - if (defaultIcon_ != nil) - [defaultIcon_ release]; - if (record_ != nil) - [record_ release]; +- (void) _clear { + _clear(uri_) + _clear(distribution_) + _clear(type_) + + _clear(description_) + _clear(label_) + _clear(origin_) + _clear(version_) + _clear(defaultIcon_) + _clear(record_) +} +- (void) dealloc { + [self _clear]; [super dealloc]; } @@ -1019,44 +1167,50 @@ class Progress : return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name]; } -- (Source *) initWithMetaIndex:(metaIndex *)index { - if ((self = [super init]) != nil) { - trusted_ = index->IsTrusted(); - - uri_ = [[NSString stringWithUTF8String:index->GetURI().c_str()] retain]; - distribution_ = [[NSString stringWithUTF8String:index->GetDist().c_str()] retain]; - type_ = [[NSString stringWithUTF8String:index->GetType()] retain]; - - 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; +- (void) setMetaIndex:(metaIndex *)index { + [self _clear]; - 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 stringWithUTF8String:value.c_str()] retain]; - else if (name == "Description") - description_ = [[NSString stringWithUTF8String:value.c_str()] retain]; - else if (name == "Label") - label_ = [[NSString stringWithUTF8String:value.c_str()] retain]; - else if (name == "Origin") - origin_ = [[NSString stringWithUTF8String:value.c_str()] retain]; - else if (name == "Version") - version_ = [[NSString stringWithUTF8String:value.c_str()] retain]; - } + trusted_ = index->IsTrusted(); + + uri_ = [[NSString stringWithUTF8String:index->GetURI().c_str()] retain]; + distribution_ = [[NSString stringWithUTF8String:index->GetDist().c_str()] retain]; + type_ = [[NSString stringWithUTF8String:index->GetType()] retain]; + + 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 stringWithUTF8String:value.c_str()] retain]; + else if (name == "Description") + description_ = [[NSString stringWithUTF8String:value.c_str()] retain]; + else if (name == "Label") + label_ = [[NSString stringWithUTF8String:value.c_str()] retain]; + else if (name == "Origin") + origin_ = [[NSString stringWithUTF8String:value.c_str()] retain]; + else if (name == "Version") + version_ = [[NSString stringWithUTF8String:value.c_str()] retain]; } + } + + record_ = [Sources_ objectForKey:[self key]]; + if (record_ != nil) + record_ = [record_ retain]; +} - record_ = [Sources_ objectForKey:[self key]]; - if (record_ != nil) - record_ = [record_ retain]; +- (Source *) initWithMetaIndex:(metaIndex *)index { + if ((self = [super init]) != nil) { + [self setMetaIndex:index]; } return self; } @@ -1174,6 +1328,8 @@ class Progress : /* }}} */ /* Package Class {{{ */ @interface Package : NSObject { + unsigned era_; + pkgCache::PkgIterator iterator_; _transient Database *database_; pkgCache::VerIterator version_; @@ -1183,6 +1339,7 @@ class Progress : bool cached_; NSString *section_; + bool essential_; NSString *latest_; NSString *installed_; @@ -1209,10 +1366,12 @@ class Progress : - (NSString *) section; - (NSString *) simpleSection; +- (NSString *) uri; + - (Address *) maintainer; - (size_t) size; - (NSString *) description; -- (NSString *) index; +- (unichar) index; - (NSMutableDictionary *) metadata; - (NSDate *) seen; @@ -1250,7 +1409,6 @@ class Progress : - (Source *) source; - (NSString *) role; -- (NSString *) rating; - (BOOL) matches:(NSString *)text; @@ -1267,10 +1425,10 @@ class Progress : - (void) install; - (void) remove; -- (NSNumber *) isUnfilteredAndSearchedForBy:(NSString *)search; -- (NSNumber *) isInstalledAndVisible:(NSNumber *)number; -- (NSNumber *) isVisiblyUninstalledInSection:(NSString *)section; -- (NSNumber *) isVisibleInSource:(Source *)source; +- (bool) isUnfilteredAndSearchedForBy:(NSString *)search; +- (bool) isInstalledAndVisible:(NSNumber *)number; +- (bool) isVisiblyUninstalledInSection:(NSString *)section; +- (bool) isVisibleInSource:(Source *)source; @end @@ -1279,7 +1437,6 @@ class Progress : - (void) dealloc { if (source_ != nil) [source_ release]; - if (section_ != nil) [section_ release]; @@ -1313,7 +1470,7 @@ class Progress : } + (NSArray *) _attributeKeys { - return [NSArray arrayWithObjects:@"applications", @"author", @"depiction", @"description", @"essential", @"homepage", @"icon", @"id", @"installed", @"latest", @"maintainer", @"name", @"purposes", @"rating", @"section", @"size", @"source", @"sponsor", @"tagline", @"warnings", nil]; + return [NSArray arrayWithObjects:@"applications", @"author", @"depiction", @"description", @"essential", @"homepage", @"icon", @"id", @"installed", @"latest", @"maintainer", @"name", @"purposes", @"section", @"size", @"source", @"sponsor", @"tagline", @"warnings", nil]; } - (NSArray *) attributeKeys { @@ -1326,156 +1483,215 @@ class Progress : - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database { if ((self = [super init]) != nil) { + _profile(Package$initWithIterator) + @synchronized (database) { + era_ = [database era]; + iterator_ = iterator; database_ = database; - version_ = [database_ policy]->GetCandidateVer(iterator_); + _profile(Package$initWithIterator$Control) + _end + + _profile(Package$initWithIterator$Version) + version_ = [database_ policy]->GetCandidateVer(iterator_); + _end + NSString *latest = version_.end() ? nil : [NSString stringWithUTF8String:version_.VerStr()]; - latest_ = latest == nil ? nil : [StripVersion(latest) retain]; - pkgCache::VerIterator current = iterator_.CurrentVer(); - NSString *installed = current.end() ? nil : [NSString stringWithUTF8String:current.VerStr()]; - installed_ = [StripVersion(installed) retain]; + _profile(Package$initWithIterator$Latest) + latest_ = latest == nil ? nil : [StripVersion(latest) retain]; + _end - if (!version_.end()) - file_ = version_.FileList(); - else { - pkgCache &cache([database_ cache]); - file_ = pkgCache::VerFileIterator(cache, cache.VerFileP); - } + pkgCache::VerIterator current; + NSString *installed; - id_ = [[NSString stringWithUTF8String:iterator_.Name()] retain]; - - if (!file_.end()) { - pkgRecords::Parser *parser = &[database_ records]->Lookup(file_); - - const char *begin, *end; - parser->GetRec(begin, end); - - NSString *website(nil); - NSString *sponsor(nil); - NSString *author(nil); - NSString *tag(nil); - - struct { - const char *name_; - NSString **value_; - } names[] = { - {"name", &name_}, - {"icon", &icon_}, - {"depiction", &depiction_}, - {"homepage", &homepage_}, - {"website", &website}, - {"sponsor", &sponsor}, - {"author", &author}, - {"tag", &tag}, - }; - - while (begin != end) - if (*begin == '\n') { - ++begin; - continue; - } else if (isblank(*begin)) next: { - begin = static_cast(memchr(begin + 1, '\n', end - begin - 1)); - if (begin == NULL) - break; - } else if (const char *colon = static_cast(memchr(begin, ':', end - begin))) { - const char *name(begin); - size_t size(colon - begin); - - begin = static_cast(memchr(begin, '\n', end - begin)); - - { - const char *stop(begin == NULL ? end : begin); - while (stop[-1] == '\r') - --stop; - while (++colon != stop && isblank(*colon)); - - for (size_t i(0); i != sizeof(names) / sizeof(names[0]); ++i) - if (strncasecmp(names[i].name_, name, size) == 0) { - NSString *value([NSString stringWithUTF8Bytes:colon length:(stop - colon)]); - *names[i].value_ = value; - break; - } - } + _profile(Package$initWithIterator$Current) + current = iterator_.CurrentVer(); + installed = current.end() ? nil : [NSString stringWithUTF8String:current.VerStr()]; + _end - if (begin == NULL) - break; - ++begin; - } else goto next; - - if (name_ != nil) - name_ = [name_ retain]; - tagline_ = [[NSString stringWithUTF8String:parser->ShortDesc().c_str()] retain]; - if (icon_ != nil) - icon_ = [icon_ retain]; - if (depiction_ != nil) - depiction_ = [depiction_ retain]; - if (homepage_ == nil) - homepage_ = website; - if ([homepage_ isEqualToString:depiction_]) - homepage_ = nil; - if (homepage_ != nil) - homepage_ = [homepage_ retain]; - if (sponsor != nil) - sponsor_ = [[Address addressWithString:sponsor] retain]; - if (author != nil) - author_ = [[Address addressWithString:author] retain]; - if (tag != nil) - tags_ = [[tag componentsSeparatedByString:@", "] retain]; - } + _profile(Package$initWithIterator$Installed) + installed_ = [StripVersion(installed) retain]; + _end - if (tags_ != nil) - for (int i(0), e([tags_ count]); i != e; ++i) { - NSString *tag = [tags_ objectAtIndex:i]; - if ([tag hasPrefix:@"role::"]) { - role_ = [[tag substringFromIndex:6] retain]; - break; - } + _profile(Package$initWithIterator$File) + if (!version_.end()) + file_ = version_.FileList(); + else { + pkgCache &cache([database_ cache]); + file_ = pkgCache::VerFileIterator(cache, cache.VerFileP); } + _end + + _profile(Package$initWithIterator$Name) + id_ = [[NSString stringWithUTF8String:iterator_.Name()] retain]; + _end + + if (!file_.end()) + _profile(Package$initWithIterator$Parse) + pkgRecords::Parser *parser; + + _profile(Package$initWithIterator$Parse$Lookup) + parser = &[database_ records]->Lookup(file_); + _end + + const char *begin, *end; + parser->GetRec(begin, end); + + NSString *website(nil); + NSString *sponsor(nil); + NSString *author(nil); + NSString *tag(nil); + + struct { + const char *name_; + NSString **value_; + } names[] = { + {"name", &name_}, + {"icon", &icon_}, + {"depiction", &depiction_}, + {"homepage", &homepage_}, + {"website", &website}, + {"sponsor", &sponsor}, + {"author", &author}, + {"tag", &tag}, + }; + + while (begin != end) + if (*begin == '\n') { + ++begin; + continue; + } else if (isblank(*begin)) next: { + begin = static_cast(memchr(begin + 1, '\n', end - begin - 1)); + if (begin == NULL) + break; + } else if (const char *colon = static_cast(memchr(begin, ':', end - begin))) { + const char *name(begin); + size_t size(colon - begin); + + begin = static_cast(memchr(begin, '\n', end - begin)); + + { + const char *stop(begin == NULL ? end : begin); + while (stop[-1] == '\r') + --stop; + while (++colon != stop && isblank(*colon)); + + for (size_t i(0); i != sizeof(names) / sizeof(names[0]); ++i) + if (strncasecmp(names[i].name_, name, size) == 0) { + NSString *value; + + _profile(Package$initWithIterator$Parse$Value) + value = [NSString stringWithUTF8Bytes:colon length:(stop - colon)]; + _end + + *names[i].value_ = value; + break; + } + } + + if (begin == NULL) + break; + ++begin; + } else goto next; + + _profile(Package$initWithIterator$Parse$Retain) + if (name_ != nil) + name_ = [name_ retain]; + _profile(Package$initWithIterator$Parse$Tagline) + tagline_ = [[NSString stringWithUTF8String:parser->ShortDesc().c_str()] retain]; + _end + if (icon_ != nil) + icon_ = [icon_ retain]; + if (depiction_ != nil) + depiction_ = [depiction_ retain]; + if (homepage_ == nil) + homepage_ = website; + if ([homepage_ isEqualToString:depiction_]) + homepage_ = nil; + if (homepage_ != nil) + homepage_ = [homepage_ retain]; + if (sponsor != nil) + sponsor_ = [[Address addressWithString:sponsor] retain]; + if (author != nil) + author_ = [[Address addressWithString:author] retain]; + if (tag != nil) + tags_ = [[tag componentsSeparatedByString:@", "] retain]; + _end + _end + + _profile(Package$initWithIterator$Tags) + if (tags_ != nil) + for (NSString *tag in tags_) + if ([tag hasPrefix:@"role::"]) { + role_ = [[tag substringFromIndex:6] retain]; + break; + } + _end NSString *solid(latest == nil ? installed : latest); bool changed(false); NSString *key([id_ lowercaseString]); - NSMutableDictionary *metadata = [Packages_ objectForKey:key]; - if (metadata == nil) { - metadata = [[NSMutableDictionary dictionaryWithObjectsAndKeys: - now_, @"FirstSeen", - nil] mutableCopy]; + _profile(Package$initWithIterator$Metadata) + NSMutableDictionary *metadata = [Packages_ objectForKey:key]; + if (metadata == nil) { + metadata = [[NSMutableDictionary dictionaryWithObjectsAndKeys: + now_, @"FirstSeen", + nil] mutableCopy]; - if (solid != nil) - [metadata setObject:solid forKey:@"LastVersion"]; - changed = true; - } else { - NSDate *first([metadata objectForKey:@"FirstSeen"]); - NSDate *last([metadata objectForKey:@"LastSeen"]); - NSString *version([metadata objectForKey:@"LastVersion"]); - - if (first == nil) { - first = last == nil ? now_ : last; - [metadata setObject:first forKey:@"FirstSeen"]; + if (solid != nil) + [metadata setObject:solid forKey:@"LastVersion"]; changed = true; + } else { + NSDate *first([metadata objectForKey:@"FirstSeen"]); + NSDate *last([metadata objectForKey:@"LastSeen"]); + NSString *version([metadata objectForKey:@"LastVersion"]); + + if (first == nil) { + first = last == nil ? now_ : last; + [metadata setObject:first forKey:@"FirstSeen"]; + changed = true; + } + + if (solid != nil) + if (version == nil) { + [metadata setObject:solid forKey:@"LastVersion"]; + changed = true; + } else if (![version isEqualToString:solid]) { + [metadata setObject:solid forKey:@"LastVersion"]; + last = now_; + [metadata setObject:last forKey:@"LastSeen"]; + changed = true; + } } - if (solid != nil) - if (version == nil) { - [metadata setObject:solid forKey:@"LastVersion"]; - changed = true; - } else if (![version isEqualToString:solid]) { - [metadata setObject:solid forKey:@"LastVersion"]; - last = now_; - [metadata setObject:last forKey:@"LastSeen"]; - changed = true; + if (changed) { + [Packages_ setObject:metadata forKey:key]; + Changed_ = true; + } + _end + + const char *section(iterator_.Section()); + if (section == NULL) + section_ = nil; + else { + NSString *name([[NSString stringWithUTF8String:section] stringByReplacingCharacter:' ' withCharacter:'_']); + + lookup: + if (NSDictionary *value = [SectionMap_ objectForKey:name]) + if (NSString *rename = [value objectForKey:@"Rename"]) { + name = rename; + goto lookup; } - } - if (changed) { - [Packages_ setObject:metadata forKey:key]; - Changed_ = true; + section_ = [[name stringByReplacingCharacter:'_' withCharacter:' '] retain]; } - } return self; + + essential_ = (iterator_->Flags & pkgCache::Flag::Essential) == 0 ? NO : YES; + } _end } return self; } + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database { @@ -1490,23 +1706,6 @@ class Progress : } - (NSString *) section { - if (section_ != nil) - return section_; - - const char *section = iterator_.Section(); - if (section == NULL) - return nil; - - NSString *name = [[NSString stringWithUTF8String:section] stringByReplacingCharacter:' ' withCharacter:'_']; - - lookup: - if (NSDictionary *value = [SectionMap_ objectForKey:name]) - if (NSString *rename = [value objectForKey:@"Rename"]) { - name = rename; - goto lookup; - } - - section_ = [[name stringByReplacingCharacter:'_' withCharacter:' '] retain]; return section_; } @@ -1515,14 +1714,27 @@ class Progress : return Simplify(section); else return nil; +} +- (NSString *) uri { + return nil; +#if 0 + pkgIndexFile *index; + pkgCache::PkgFileIterator file(file_.File()); + if (![database_ list].FindIndex(file, index)) + return nil; + return [NSString stringWithUTF8String:iterator_->Path]; + //return [NSString stringWithUTF8String:file.Site()]; + //return [NSString stringWithUTF8String:index->ArchiveURI(file.FileName()).c_str()]; +#endif } - (Address *) maintainer { if (file_.end()) return nil; pkgRecords::Parser *parser = &[database_ records]->Lookup(file_); - return [Address addressWithString:[NSString stringWithUTF8String:parser->Maintainer().c_str()]]; + const std::string &maintainer(parser->Maintainer()); + return maintainer.empty() ? nil : [Address addressWithString:[NSString stringWithUTF8String:maintainer.c_str()]]; } - (size_t) size { @@ -1541,7 +1753,7 @@ class Progress : return nil; NSCharacterSet *whitespace = [NSCharacterSet whitespaceCharacterSet]; - for (size_t i(1); i != [lines count]; ++i) { + for (size_t i(1), e([lines count]); i != e; ++i) { NSString *trim = [[lines objectAtIndex:i] stringByTrimmingCharactersInSet:whitespace]; [trimmed addObject:trim]; } @@ -1549,9 +1761,16 @@ class Progress : return [trimmed componentsJoinedByString:@"\n"]; } -- (NSString *) index { - NSString *index = [[[self name] substringToIndex:1] uppercaseString]; - return [index length] != 0 && isalpha([index characterAtIndex:0]) ? index : @"123"; +- (unichar) index { + _profile(Package$index) + NSString *name([self name]); + if ([name length] == 0) + return '#'; + unichar character([name characterAtIndex:0]); + if (!isalpha(character)) + return '#'; + return toupper(character); + _end } - (NSMutableDictionary *) metadata { @@ -1597,14 +1816,16 @@ class Progress : - (BOOL) upgradableAndEssential:(BOOL)essential { pkgCache::VerIterator current = iterator_.CurrentVer(); + bool value; if (current.end()) - return essential && [self essential]; + value = essential && [self essential] && [self visible]; else - return !version_.end() && version_ != current; + value = !version_.end() && version_ != current;// && (!essential || ![database_ cache][iterator_].Keep()); + return value; } - (BOOL) essential { - return (iterator_->Flags & pkgCache::Flag::Essential) == 0 ? NO : YES; + return essential_; } - (BOOL) broken { @@ -1688,12 +1909,14 @@ class Progress : NSString *section = [self simpleSection]; UIImage *icon(nil); - if (NSString *icon = icon_) - icon = [UIImage imageAtPath:[icon_ substringFromIndex:6]]; + if (icon_ != nil) + if ([icon_ hasPrefix:@"file:///"]) + icon = [UIImage imageAtPath:[icon_ substringFromIndex:7]]; if (icon == nil) if (section != nil) icon = [UIImage imageAtPath:[NSString stringWithFormat:@"%@/Sections/%@.png", App_, section]]; - if (icon == nil) if (source_ != nil) if (NSString *icon = [source_ defaultIcon]) - icon = [UIImage imageAtPath:[icon substringFromIndex:6]]; + if (icon == nil) if (source_ != nil) if (NSString *dicon = [source_ defaultIcon]) + if ([dicon hasPrefix:@"file:///"]) + icon = [UIImage imageAtPath:[dicon substringFromIndex:7]]; if (icon == nil) icon = [UIImage applicationImageNamed:@"unknown.png"]; return icon; @@ -1744,6 +1967,8 @@ class Progress : [warnings addObject:@"illegal package identifier"]; else for (size_t i(0); i != length; ++i) if ( + /* XXX: technically this is not allowed */ + (name[i] < 'A' || name[i] > 'Z') && (name[i] < 'a' || name[i] > 'z') && (name[i] < '0' || name[i] > '9') && (i == 0 || name[i] != '+' && name[i] != '-' && name[i] != '.') @@ -1751,17 +1976,25 @@ class Progress : if (strcmp(name, "cydia") != 0) { bool cydia = false; + bool _private = false; bool stash = false; + bool repository = [[self section] isEqualToString:@"Repositories"]; + if (NSArray *files = [self files]) for (NSString *file in files) if (!cydia && [file isEqualToString:@"/Applications/Cydia.app"]) cydia = true; + else if (!_private && [file isEqualToString:@"/private"]) + _private = true; else if (!stash && [file isEqualToString:@"/var/stash"]) stash = true; - if (cydia) + /* XXX: this is not sensitive enough. only some folders are valid. */ + if (cydia && !repository) [warnings addObject:@"files installed into Cydia.app"]; + if (_private) + [warnings addObject:@"files installed with /private/*"]; if (stash) [warnings addObject:@"files installed to /var/stash"]; } @@ -1806,8 +2039,17 @@ class Progress : - (Source *) source { if (!cached_) { - source_ = file_.end() ? nil : [[database_ getSource:file_.File()] retain]; - cached_ = true; + @synchronized (database_) { + if ([database_ era] != era_ || file_.end()) + source_ = nil; + else { + source_ = [database_ getSource:file_.File()]; + if (source_ != nil) + [source_ retain]; + } + + cached_ = true; + } } return source_; @@ -1817,28 +2059,21 @@ class Progress : return role_; } -- (NSString *) rating { - if (NSString *rating = [Indices_ objectForKey:@"Rating"]) - return [rating stringByReplacingOccurrencesOfString:@"@P" withString:[id_ stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; - else - return nil; -} - - (BOOL) matches:(NSString *)text { if (text == nil) return NO; NSRange range; - range = [[self id] rangeOfString:text options:NSCaseInsensitiveSearch]; + range = [[self id] rangeOfString:text options:MatchCompareOptions_]; if (range.location != NSNotFound) return YES; - range = [[self name] rangeOfString:text options:NSCaseInsensitiveSearch]; + range = [[self name] rangeOfString:text options:MatchCompareOptions_]; if (range.location != NSNotFound) return YES; - range = [[self tagline] rangeOfString:text options:NSCaseInsensitiveSearch]; + range = [[self tagline] rangeOfString:text options:MatchCompareOptions_]; if (range.location != NSNotFound) return YES; @@ -1926,9 +2161,10 @@ class Progress : } bits; } value; - value.bits.upgradable = [self upgradableAndEssential:YES] ? 1 : 0; + bool upgradable([self upgradableAndEssential:YES]); + value.bits.upgradable = upgradable ? 1 : 0; - if ([self upgradableAndEssential:YES]) { + if (upgradable) { value.bits.timestamp = 0; value.bits.ignored = [self ignored] ? 0 : 1; value.bits.upgradable = 1; @@ -1960,33 +2196,40 @@ class Progress : [database_ cache]->MarkDelete(iterator_, true); } -- (NSNumber *) isUnfilteredAndSearchedForBy:(NSString *)search { - return [NSNumber numberWithBool:( - [self unfiltered] && [self matches:search] - )]; +- (bool) isUnfilteredAndSearchedForBy:(NSString *)search { + _profile(Package$isUnfilteredAndSearchedForBy) + bool value(true); + + _profile(Package$isUnfilteredAndSearchedForBy$Unfiltered) + value &= [self unfiltered]; + _end + + _profile(Package$isUnfilteredAndSearchedForBy$Match) + value &= [self matches:search]; + _end + + return value; + _end } -- (NSNumber *) isInstalledAndVisible:(NSNumber *)number { - return [NSNumber numberWithBool:( - (![number boolValue] || [self visible]) && [self installed] != nil - )]; +- (bool) isInstalledAndVisible:(NSNumber *)number { + return (![number boolValue] || [self visible]) && [self installed] != nil; } -- (NSNumber *) isVisiblyUninstalledInSection:(NSString *)name { +- (bool) isVisiblyUninstalledInSection:(NSString *)name { NSString *section = [self section]; - return [NSNumber numberWithBool:( + return [self visible] && [self installed] == nil && ( name == nil || section == nil && [name length] == 0 || [name isEqualToString:section] - ) - )]; + ); } -- (NSNumber *) isVisibleInSource:(Source *)source { - return [NSNumber numberWithBool:([self source] == source && [self visible])]; +- (bool) isVisibleInSource:(Source *)source { + return [self source] == source && [self visible]; } @end @@ -1994,6 +2237,7 @@ class Progress : /* Section Class {{{ */ @interface Section : NSObject { NSString *name_; + unichar index_; size_t row_; size_t count_; } @@ -2001,7 +2245,9 @@ class Progress : - (NSComparisonResult) compareByName:(Section *)section; - (Section *) initWithName:(NSString *)name; - (Section *) initWithName:(NSString *)name row:(size_t)row; +- (Section *) initWithIndex:(unichar)index row:(size_t)row; - (NSString *) name; +- (unichar) index; - (size_t) row; - (size_t) count; - (void) addToCount; @@ -2039,6 +2285,15 @@ class Progress : - (Section *) initWithName:(NSString *)name row:(size_t)row { if ((self = [super init]) != nil) { name_ = [name retain]; + index_ = '\0'; + row_ = row; + } return self; +} + +- (Section *) initWithIndex:(unichar)index row:(size_t)row { + if ((self = [super init]) != nil) { + name_ = [(index == '#' ? @"123" : [NSString stringWithCharacters:&index length:1]) retain]; + index_ = index; row_ = row; } return self; } @@ -2047,6 +2302,10 @@ class Progress : return name_; } +- (unichar) index { + return index_; +} + - (size_t) row { return row_; } @@ -2075,6 +2334,10 @@ static NSArray *Finishes_; return instance; } +- (unsigned) era { + return era_; +} + - (void) dealloc { _assert(false); [super dealloc]; @@ -2242,6 +2505,10 @@ static NSArray *Finishes_; return *fetcher_; } +- (pkgSourceList &) list { + return *list_; +} + - (NSArray *) packages { return packages_; } @@ -2314,7 +2581,11 @@ static NSArray *Finishes_; return issues; } -- (void) reloadData { +- (void) reloadData { _pooled + @synchronized (self) { + ++era_; + } + _error->Discard(); delete list_; @@ -2386,13 +2657,15 @@ static NSArray *Finishes_; [packages_ removeAllObjects]; _trace(); - profile_ = 0; for (pkgCache::PkgIterator iterator = cache_->PkgBegin(); !iterator.end(); ++iterator) if (Package *package = [Package packageWithIterator:iterator database:self]) [packages_ addObject:package]; _trace(); [packages_ sortUsingSelector:@selector(compareByName:)]; _trace(); + + _config->Set("Acquire::http::Timeout", 15); + _config->Set("Acquire::http::MaxParallel", 4); } - (void) configure { @@ -2468,7 +2741,9 @@ static NSArray *Finishes_; failed = true; [delegate_ performSelectorOnMainThread:@selector(_setProgressError:) - withObject:[NSArray arrayWithObjects:[NSString stringWithUTF8String:error.c_str()], nil] + withObject:[NSArray arrayWithObjects: + [NSString stringWithUTF8String:error.c_str()], + nil] waitUntilDone:YES ]; } @@ -2778,8 +3053,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { pkgCacheFile &cache([database_ cache]); NSArray *packages = [database_ packages]; - for (size_t i(0), e = [packages count]; i != e; ++i) { - Package *package = [packages objectAtIndex:i]; + for (Package *package in packages) { pkgCache::PkgIterator iterator = [package iterator]; pkgDepCache::StateCache &state(cache[iterator]); @@ -2863,8 +3137,16 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { return @"Cancel"; } -- (NSString *) _rightButtonTitle { - return issues_ == nil ? @"Confirm" : nil; +- (id) rightButtonTitle { + return issues_ != nil ? nil : [super rightButtonTitle]; +} + +- (id) _rightButtonTitle { +#if AlwaysReload || IgnoreInstall + return [super _rightButtonTitle]; +#else + return @"Confirm"; +#endif } - (void) _leftButtonClicked { @@ -2873,6 +3155,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { #if !AlwaysReload - (void) _rightButtonClicked { +#if IgnoreInstall + return [super _rightButtonClicked]; +#endif if (essential_ != nil) [essential_ popupAlertAnimated:YES]; else { @@ -2942,9 +3227,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { id delegate_; BOOL running_; SHA1SumValue springlist_; + SHA1SumValue notifyconf_; SHA1SumValue sandplate_; - size_t received_; - NSTimeInterval last_; } - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to; @@ -3044,6 +3328,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [status_ setCentersHorizontally:YES]; //[status_ setFont:font]; + _trace(); output_ = [[UITextView alloc] initWithFrame:CGRectMake( 10, @@ -3051,6 +3336,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { bounds.size.width - 20, bounds.size.height - navsize.height - 62 - navrect.size.height )]; + _trace(); //[output_ setTextFont:@"Courier New"]; [output_ setTextSize:12]; @@ -3096,7 +3382,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button { NSString *context([sheet context]); - if ([context isEqualToString:@"conffile"]) { + if ([context isEqualToString:@"error"]) + [sheet dismiss]; + else if ([context isEqualToString:@"conffile"]) { FILE *input = [database_ input]; switch (button) { @@ -3161,6 +3449,15 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { Finish_ = 4; } + if (Finish_ < 4) { + FileFd file(NotifyConfig_, FileFd::ReadOnly); + MMap mmap(file, MMap::ReadOnly); + SHA1Summation sha1; + sha1.Add(reinterpret_cast(mmap.Data()), mmap.Size()); + if (!(notifyconf_ == sha1.Result())) + Finish_ = 4; + } + if (Finish_ < 3) { FileFd file(SpringBoard_, FileFd::ReadOnly); MMap mmap(file, MMap::ReadOnly); @@ -3243,9 +3540,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [output_ setText:@""]; [progress_ setProgress:0]; - received_ = 0; - last_ = 0;//[NSDate timeIntervalSinceReferenceDate]; - [close_ removeFromSuperview]; [overlay_ addSubview:progress_]; [overlay_ addSubview:status_]; @@ -3261,6 +3555,14 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { sandplate_ = sha1.Result(); } + { + FileFd file(NotifyConfig_, FileFd::ReadOnly); + MMap mmap(file, MMap::ReadOnly); + SHA1Summation sha1; + sha1.Add(reinterpret_cast(mmap.Data()), mmap.Size()); + notifyconf_ = sha1.Result(); + } + { FileFd file(SpringBoard_, FileFd::ReadOnly); MMap mmap(file, MMap::ReadOnly); @@ -3331,7 +3633,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) startProgress { - last_ = [NSDate timeIntervalSinceReferenceDate]; } - (void) addProgressOutput:(NSString *)output { @@ -3343,15 +3644,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (bool) isCancelling:(size_t)received { - if (last_ != 0) { - NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate]; - if (received_ != received) { - received_ = received; - last_ = now; - } else if (now - last_ > 30) - return true; - } - return false; } @@ -3885,6 +4177,10 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [super webView:sender didClearWindowObject:window forFrame:frame]; } +- (bool) _allowJavaScriptPanel { + return false; +} + #if !AlwaysReload - (void) _rightButtonClicked { /*[super _rightButtonClicked]; @@ -3911,7 +4207,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } #endif -- (NSString *) _rightButtonTitle { +- (id) _rightButtonTitle { int count = [buttons_ count]; return count == 0 ? nil : count != 1 ? @"Modify" : [buttons_ objectAtIndex:0]; } @@ -3973,17 +4269,14 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { @interface PackageTable : RVPage { _transient Database *database_; NSString *title_; - SEL filter_; - id object_; NSMutableArray *packages_; NSMutableArray *sections_; UISectionList *list_; } -- (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object; +- (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title; - (void) setDelegate:(id)delegate; -- (void) setObject:(id)object; - (void) reloadData; - (void) resetCursor; @@ -4000,8 +4293,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [list_ setDataSource:nil]; [title_ release]; - if (object_ != nil) - [object_ release]; [packages_ release]; [sections_ release]; [list_ release]; @@ -4045,18 +4336,17 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { return; Package *package = [packages_ objectAtIndex:row]; + package = [database_ packageWithName:[package id]]; PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease]; - [view setDelegate:delegate_]; [view setPackage:package]; + [view setDelegate:delegate_]; [book_ pushPage:view]; } -- (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object { +- (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title { if ((self = [super initWithBook:book]) != nil) { database_ = database; title_ = [title retain]; - filter_ = filter; - object_ = object == nil ? nil : [object retain]; packages_ = [[NSMutableArray arrayWithCapacity:16] retain]; sections_ = [[NSMutableArray arrayWithCapacity:16] retain]; @@ -4077,7 +4367,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [table setReusesTableCells:YES]; [self addSubview:list_]; - [self reloadData]; [self setAutoresizingMask:UIViewAutoresizingFlexibleHeight]; [list_ setAutoresizingMask:UIViewAutoresizingFlexibleHeight]; @@ -4088,13 +4377,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { delegate_ = delegate; } -- (void) setObject:(id)object { - if (object_ != nil) - [object_ release]; - if (object == nil) - object_ = nil; - else - object_ = [object retain]; +- (bool) hasPackage:(Package *)package { + return true; } - (void) reloadData { @@ -4103,27 +4387,41 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [packages_ removeAllObjects]; [sections_ removeAllObjects]; - for (size_t i(0); i != [packages count]; ++i) { - Package *package([packages objectAtIndex:i]); - if ([package valid] && [[package performSelector:filter_ withObject:object_] boolValue]) - [packages_ addObject:package]; - } + _profile(PackageTable$reloadData$Filter) + for (Package *package in packages) + if ([self hasPackage:package]) + [packages_ addObject:package]; + _end Section *section = nil; - for (size_t offset(0); offset != [packages_ count]; ++offset) { - Package *package = [packages_ objectAtIndex:offset]; - NSString *name = [package index]; + _profile(PackageTable$reloadData$Section) + for (size_t offset(0), end([packages_ count]); offset != end; ++offset) { + Package *package; + unichar index; - if (section == nil || ![[section name] isEqualToString:name]) { - section = [[[Section alloc] initWithName:name row:offset] autorelease]; - [sections_ addObject:section]; - } + _profile(PackageTable$reloadData$Section$Package) + package = [packages_ objectAtIndex:offset]; + index = [package index]; + _end - [section addToCount]; - } + if (section == nil || [section index] != index) { + _profile(PackageTable$reloadData$Section$Allocate) + section = [[[Section alloc] initWithIndex:index row:offset] autorelease]; + _end - [list_ reloadData]; + _profile(PackageTable$reloadData$Section$Add) + [sections_ addObject:section]; + _end + } + + [section addToCount]; + } + _end + + _profile(PackageTable$reloadData$List) + [list_ reloadData]; + _end } - (NSString *) title { @@ -4148,15 +4446,67 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { @end /* }}} */ - -/* Add Source View {{{ */ -@interface AddSourceView : RVPage { - _transient Database *database_; +/* Filtered Package Table {{{ */ +@interface FilteredPackageTable : PackageTable { + SEL filter_; + IMP imp_; + id object_; } -- (id) initWithBook:(RVBook *)book database:(Database *)database; +- (void) setObject:(id)object; -@end +- (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object; + +@end + +@implementation FilteredPackageTable + +- (void) dealloc { + if (object_ != nil) + [object_ release]; + [super dealloc]; +} + +- (void) setObject:(id)object { + if (object_ != nil) + [object_ release]; + if (object == nil) + object_ = nil; + else + object_ = [object retain]; +} + +- (bool) hasPackage:(Package *)package { + _profile(FilteredPackageTable$hasPackage) + return [package valid] && (*reinterpret_cast(imp_))(package, filter_, object_); + _end +} + +- (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object { + if ((self = [super initWithBook:book database:database title:title]) != nil) { + filter_ = filter; + object_ = object == nil ? nil : [object retain]; + + /* XXX: this is an unsafe optimization of doomy hell */ + Method method = class_getInstanceMethod([Package class], filter); + imp_ = method_getImplementation(method); + _assert(imp_ != NULL); + + [self reloadData]; + } return self; +} + +@end +/* }}} */ + +/* Add Source View {{{ */ +@interface AddSourceView : RVPage { + _transient Database *database_; +} + +- (id) initWithBook:(RVBook *)book database:(Database *)database; + +@end @implementation AddSourceView @@ -4342,7 +4692,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { Source *source = [sources_ objectAtIndex:row]; - PackageTable *packages = [[[PackageTable alloc] + PackageTable *packages = [[[FilteredPackageTable alloc] initWithBook:book_ database:database_ title:[source label] @@ -4370,6 +4720,35 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [delegate_ syncData]; } +- (void) complete { + [Sources_ setObject:[NSDictionary dictionaryWithObjectsAndKeys: + @"deb", @"Type", + href_, @"URI", + @"./", @"Distribution", + nil] forKey:[NSString stringWithFormat:@"deb:%@:./", href_]]; + + [delegate_ syncData]; +} + +- (NSString *) getWarning { + NSString *href(href_); + NSRange colon([href rangeOfString:@"://"]); + if (colon.location != NSNotFound) + href = [href substringFromIndex:(colon.location + 3)]; + href = [href stringByAddingPercentEscapes]; + href = [@"http://cydia.saurik.com/api/repotag/" stringByAppendingString:href]; + href = [href stringByCachingURLWithCurrentCDN]; + + NSURL *url([NSURL URLWithString:href]); + + NSStringEncoding encoding; + NSError *error(nil); + + if (NSString *warning = [NSString stringWithContentsOfURL:url usedEncoding:&encoding error:&error]) + return [warning length] == 0 ? nil : warning; + return nil; +} + - (void) _endConnection:(NSURLConnection *)connection { NSURLConnection **field = NULL; if (connection == trivial_bz2_) @@ -4384,21 +4763,26 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { trivial_bz2_ == nil && trivial_gz_ == nil ) { - [delegate_ setStatusBarShowsProgress:NO]; - - [hud_ show:NO]; - [hud_ removeFromSuperview]; - [hud_ autorelease]; - hud_ = nil; + bool defer(false); if (trivial_) { - [Sources_ setObject:[NSDictionary dictionaryWithObjectsAndKeys: - @"deb", @"Type", - href_, @"URI", - @"./", @"Distribution", - nil] forKey:[NSString stringWithFormat:@"deb:%@:./", href_]]; - - [delegate_ syncData]; + if (NSString *warning = [self yieldToSelector:@selector(getWarning)]) { + defer = true; + + UIActionSheet *sheet = [[[UIActionSheet alloc] + initWithTitle:@"Source Warning" + buttons:[NSArray arrayWithObjects:@"Add Anyway", @"Cancel", nil] + defaultButtonIndex:0 + delegate:self + context:@"warning" + ] autorelease]; + + [sheet setNumberOfRows:1]; + + [sheet setBodyText:warning]; + [sheet popupAlertAnimated:YES]; + } else + [self complete]; } else if (error_ != nil) { UIActionSheet *sheet = [[[UIActionSheet alloc] initWithTitle:@"Verification Error" @@ -4423,8 +4807,16 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [sheet popupAlertAnimated:YES]; } - [href_ release]; - href_ = nil; + [delegate_ setStatusBarShowsProgress:NO]; + [delegate_ removeProgressHUD:hud_]; + + [hud_ autorelease]; + hud_ = nil; + + if (!defer) { + [href_ release]; + href_ = nil; + } if (error_ != nil) { [error_ release]; @@ -4485,7 +4877,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { trivial_ = false; - hud_ = [delegate_ addProgressHUD]; + hud_ = [[delegate_ addProgressHUD] retain]; [hud_ setText:@"Verifying URL"]; } break; @@ -4501,6 +4893,24 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [sheet dismiss]; else if ([context isEqualToString:@"urlerror"]) [sheet dismiss]; + else if ([context isEqualToString:@"warning"]) { + switch (button) { + case 1: + [self complete]; + break; + + case 2: + break; + + default: + _assert(false); + } + + [href_ release]; + href_ = nil; + + [sheet dismiss]; + } } - (id) initWithBook:(RVBook *)book database:(Database *)database { @@ -4600,7 +5010,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { return [[list_ table] isRowDeletionEnabled] ? @"Add" : nil; } -- (NSString *) rightButtonTitle { +- (id) rightButtonTitle { return [[list_ table] isRowDeletionEnabled] ? @"Done" : @"Edit"; } @@ -4614,7 +5024,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { /* Installed View {{{ */ @interface InstalledView : RVPage { _transient Database *database_; - PackageTable *packages_; + FilteredPackageTable *packages_; BOOL expert_; } @@ -4633,7 +5043,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { if ((self = [super initWithBook:book]) != nil) { database_ = database; - packages_ = [[PackageTable alloc] + packages_ = [[FilteredPackageTable alloc] initWithBook:book database:database title:nil @@ -4671,7 +5081,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { return @"Packages"; } -- (NSString *) rightButtonTitle { +- (id) rightButtonTitle { return Role_ != nil && [Role_ isEqualToString:@"Developer"] ? nil : expert_ ? @"Expert" : @"Simple"; } @@ -4714,7 +5124,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { ] autorelease]; [sheet setBodyText: - @"Copyright (C) 2008\n" + @"Copyright (C) 2008-2009\n" "Jay Freeman (saurik)\n" "saurik@saurik.com\n" "http://www.saurik.com/\n" @@ -4758,7 +5168,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } #if !AlwaysReload -- (NSString *) _rightButtonTitle { +- (id) _rightButtonTitle { return nil; } #endif @@ -4770,791 +5180,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { @end /* }}} */ -@interface WebView (Cydia) -- (void) setScriptDebugDelegate:(id)delegate; -- (void) _setFormDelegate:(id)delegate; -- (void) _setUIKitDelegate:(id)delegate; -- (void) setWebMailDelegate:(id)delegate; -- (void) _setLayoutInterval:(float)interval; -@end - -/* Indirect Delegate {{{ */ -@interface IndirectDelegate : NSProxy { - _transient volatile id delegate_; -} - -- (void) setDelegate:(id)delegate; -- (id) initWithDelegate:(id)delegate; -@end - -@implementation IndirectDelegate - -- (void) setDelegate:(id)delegate { - delegate_ = delegate; -} - -- (id) initWithDelegate:(id)delegate { - delegate_ = delegate; - return self; -} - -- (NSMethodSignature*) methodSignatureForSelector:(SEL)sel { - if (delegate_ != nil) - if (NSMethodSignature *sig = [delegate_ methodSignatureForSelector:sel]) - return sig; - // XXX: I fucking hate Apple so very very bad - return [NSMethodSignature signatureWithObjCTypes:"v@:"]; -} - -- (void) forwardInvocation:(NSInvocation *)inv { - SEL sel = [inv selector]; - if (delegate_ != nil && [delegate_ respondsToSelector:sel]) - [inv invokeWithTarget:delegate_]; -} - -@end -/* }}} */ -/* Browser Implementation {{{ */ -@implementation BrowserView -#include "internals.h" - -- (void) dealloc { - if (challenge_ != nil) - [challenge_ release]; - - WebView *webview = [webview_ webView]; - [webview setFrameLoadDelegate:nil]; - [webview setResourceLoadDelegate:nil]; - [webview setUIDelegate:nil]; - [webview setScriptDebugDelegate:nil]; - [webview setPolicyDelegate:nil]; - - [webview setDownloadDelegate:nil]; - - [webview _setFormDelegate:nil]; - [webview _setUIKitDelegate:nil]; - [webview setWebMailDelegate:nil]; - [webview setEditingDelegate:nil]; - - [webview_ setDelegate:nil]; - [webview_ setGestureDelegate:nil]; - - //NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; - - [webview close]; - -#if RecycleWebViews - [webview_ removeFromSuperview]; - [Documents_ addObject:[webview_ autorelease]]; -#else - [webview_ release]; -#endif - - [indirect_ setDelegate:nil]; - [indirect_ release]; - - [scroller_ setDelegate:nil]; - - if (button_ != nil) - [button_ release]; - if (style_ != nil) - [style_ release]; - if (function_ != nil) - [function_ release]; - - [scroller_ release]; - [urls_ release]; - [indicator_ release]; - if (confirm_ != nil) - [confirm_ release]; - if (title_ != nil) - [title_ release]; - [super dealloc]; -} - -- (void) loadURL:(NSURL *)url cachePolicy:(NSURLRequestCachePolicy)policy { - [self loadRequest:[NSURLRequest - requestWithURL:url - cachePolicy:policy - timeoutInterval:30.0 - ]]; -} - -- (void) loadURL:(NSURL *)url { - [self loadURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy]; -} - -- (NSURLRequest *) _addHeadersToRequest:(NSURLRequest *)request { - NSMutableURLRequest *copy = [request mutableCopy]; - - if (Machine_ != NULL) - [copy addValue:[NSString stringWithUTF8String:Machine_] forHTTPHeaderField:@"X-Machine"]; - if (UniqueID_ != nil) - [copy addValue:UniqueID_ forHTTPHeaderField:@"X-Unique-ID"]; - - if (Role_ != nil) - [copy addValue:Role_ forHTTPHeaderField:@"X-Role"]; - - return copy; -} - -- (void) loadRequest:(NSURLRequest *)request { - pushed_ = true; - [webview_ loadRequest:request]; -} - -- (void) reloadURL { - if ([urls_ count] == 0) - return; - NSURL *url = [[[urls_ lastObject] retain] autorelease]; - [urls_ removeLastObject]; - [self loadURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData]; -} - -- (WebView *) webView { - return [webview_ webView]; -} - -- (void) view:(UIView *)sender didSetFrame:(CGRect)frame { - [scroller_ setContentSize:frame.size]; -} - -- (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old { - [self view:sender didSetFrame:frame]; -} - -- (void) pushPage:(RVPage *)page { - [self setBackButtonTitle:title_]; - [page setDelegate:delegate_]; - [book_ pushPage:page]; -} - -- (BOOL) getSpecial:(NSURL *)url { - NSString *href([url absoluteString]); - NSString *scheme([[url scheme] lowercaseString]); - - RVPage *page = nil; - - if ([href hasPrefix:@"apptapp://package/"]) - page = [delegate_ pageForPackage:[href substringFromIndex:18]]; - else if ([scheme isEqualToString:@"cydia"]) { - page = [delegate_ pageForURL:url hasTag:NULL]; - if (page == nil) - return false; - } else if (![scheme isEqualToString:@"apptapp"]) - return false; - - if (page != nil) - [self pushPage:page]; - return true; -} - -- (void) webView:(WebView *)sender runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame { - UIActionSheet *sheet = [[[UIActionSheet alloc] - initWithTitle:nil - buttons:[NSArray arrayWithObjects:@"OK", nil] - defaultButtonIndex:0 - delegate:self - context:@"alert" - ] autorelease]; - - [sheet setBodyText:message]; - [sheet popupAlertAnimated:YES]; -} - -- (BOOL) webView:(WebView *)sender runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame { - UIActionSheet *sheet = [[[UIActionSheet alloc] - initWithTitle:nil - buttons:[NSArray arrayWithObjects:@"OK", @"Cancel", nil] - defaultButtonIndex:0 - delegate:self - context:@"confirm" - ] autorelease]; - - [sheet setNumberOfRows:1]; - [sheet setBodyText:message]; - [sheet popupAlertAnimated:YES]; - - NSRunLoop *loop([NSRunLoop currentRunLoop]); - NSDate *future([NSDate distantFuture]); - - while (confirm_ == nil && [loop runMode:NSDefaultRunLoopMode beforeDate:future]); - - NSNumber *confirm([confirm_ autorelease]); - confirm_ = nil; - return [confirm boolValue]; -} - -/* Web Scripting {{{ */ -+ (NSString *) webScriptNameForSelector:(SEL)selector { - if (selector == @selector(getPackageById:)) - return @"getPackageById"; - else if (selector == @selector(setButtonTitle:withStyle:toFunction:)) - return @"setButtonTitle"; - else if (selector == @selector(supports:)) - return @"supports"; - else - return nil; -} - -+ (BOOL) isSelectorExcludedFromWebScript:(SEL)selector { - return [self webScriptNameForSelector:selector] == nil; -} - -- (BOOL) supports:(NSString *)feature { - return [feature isEqualToString:@"window.open"]; -} - -- (Package *) getPackageById:(NSString *)id { - return [[Database sharedInstance] packageWithName:id]; -} - -- (void) setButtonTitle:(NSString *)button withStyle:(NSString *)style toFunction:(id)function { - if (button_ != nil) - [button_ autorelease]; - button_ = button == nil ? nil : [button retain]; - - if (style_ != nil) - [style_ autorelease]; - style_ = style == nil ? nil : [style retain]; - - if (function_ != nil) - [function_ autorelease]; - function_ = function == nil ? nil : [function retain]; -} -/* }}} */ - -- (void) webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame { - [window setValue:self forKey:@"cydia"]; -} - -- (void) webView:(WebView *)sender decidePolicyForNewWindowAction:(NSDictionary *)action request:(NSURLRequest *)request newFrameName:(NSString *)name decisionListener:(id)listener { - if (NSURL *url = [request URL]) { - if (name != nil && [name isEqualToString:@"_open"]) - [delegate_ openURL:url]; - - NSLog(@"win:%@:%@", url, [action description]); - if (![self getSpecial:url]) { - NSString *scheme([[url scheme] lowercaseString]); - if ([scheme isEqualToString:@"mailto"]) - [delegate_ openMailToURL:url]; - else goto use; - } - - [listener ignore]; - } else use: - [listener use]; -} - -- (void) webView:(WebView *)webView decidePolicyForMIMEType:(NSString *)type request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id)listener { - if ([WebView canShowMIMEType:type]) - [listener use]; - else { - // XXX: handle more mime types! - [listener ignore]; - if (frame == [webView mainFrame]) - [UIApp openURL:[request URL]]; - } -} - -- (void) webView:(WebView *)sender decidePolicyForNavigationAction:(NSDictionary *)action request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id)listener { - NSURL *url([request URL]); - - if (url == nil) use: { - [listener use]; - return; - } - else NSLog(@"nav:%@:%@", url, [action description]); - - const NSArray *capability(reinterpret_cast(GSSystemGetCapability(kGSDisplayIdentifiersCapability))); - - if ( - [capability containsObject:@"com.apple.Maps"] && [url mapsURL] || - [capability containsObject:@"com.apple.youtube"] && [url youTubeURL] - ) { - open: - [UIApp openURL:url]; - ignore: - [listener ignore]; - return; - } - - int store(_not(int)); - if (NSURL *itms = [url itmsURL:&store]) { - NSLog(@"itms#%@#%u#%@", url, store, itms); - if ( - store == 1 && [capability containsObject:@"com.apple.MobileStore"] || - store == 2 && [capability containsObject:@"com.apple.AppStore"] - ) { - url = itms; - goto open; - } - } - - NSString *scheme([[url scheme] lowercaseString]); - - if ([scheme isEqualToString:@"tel"]) { - // XXX: intelligence - goto open; - } - - if ([scheme isEqualToString:@"mailto"]) { - [delegate_ openMailToURL:url]; - goto ignore; - } - - if ([self getSpecial:url]) - goto ignore; - else if ([WebView _canHandleRequest:request]) - goto use; - else if ([url isSpringboardHandledURL]) - goto open; - else - goto use; -} - -- (void) webView:(WebView *)sender setStatusText:(NSString *)text { - //lprintf("Status:%s\n", [text UTF8String]); -} - -- (void) _pushPage { - if (pushed_) - return; - pushed_ = true; - [book_ pushPage:self]; -} - -- (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button { - NSString *context([sheet context]); - - if ([context isEqualToString:@"alert"]) - [sheet dismiss]; - else if ([context isEqualToString:@"confirm"]) { - switch (button) { - case 1: - confirm_ = [NSNumber numberWithBool:YES]; - break; - - case 2: - confirm_ = [NSNumber numberWithBool:NO]; - break; - } - - [sheet dismiss]; - } else if ([context isEqualToString:@"challenge"]) { - id sender([challenge_ sender]); - - switch (button) { - case 1: { - NSString *username([[sheet textFieldAtIndex:0] text]); - NSString *password([[sheet textFieldAtIndex:1] text]); - - NSURLCredential *credential([NSURLCredential credentialWithUser:username password:password persistence:NSURLCredentialPersistenceForSession]); - - [sender useCredential:credential forAuthenticationChallenge:challenge_]; - } break; - - case 2: - [sender cancelAuthenticationChallenge:challenge_]; - break; - - default: - _assert(false); - } - - [challenge_ release]; - challenge_ = nil; - - [sheet dismiss]; - } -} - -- (void) webView:(WebView *)sender resource:(id)identifier didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge fromDataSource:(WebDataSource *)source { - challenge_ = [challenge retain]; - - NSURLProtectionSpace *space([challenge protectionSpace]); - NSString *realm([space realm]); - if (realm == nil) - realm = @""; - - UIActionSheet *sheet = [[[UIActionSheet alloc] - initWithTitle:realm - buttons:[NSArray arrayWithObjects:@"Login", @"Cancel", nil] - defaultButtonIndex:0 - delegate:self - context:@"challenge" - ] autorelease]; - - [sheet setNumberOfRows:1]; - - [sheet addTextFieldWithValue:@"" label:@"username"]; - [sheet addTextFieldWithValue:@"" label:@"password"]; - - UITextField *username([sheet textFieldAtIndex:0]); { - UITextInputTraits *traits([username textInputTraits]); - [traits setAutocapitalizationType:UITextAutocapitalizationTypeNone]; - [traits setAutocorrectionType:UITextAutocorrectionTypeNo]; - [traits setKeyboardType:UIKeyboardTypeASCIICapable]; - [traits setReturnKeyType:UIReturnKeyNext]; - } - - UITextField *password([sheet textFieldAtIndex:1]); { - UITextInputTraits *traits([password textInputTraits]); - [traits setAutocapitalizationType:UITextAutocapitalizationTypeNone]; - [traits setAutocorrectionType:UITextAutocorrectionTypeNo]; - [traits setKeyboardType:UIKeyboardTypeASCIICapable]; - // XXX: UIReturnKeyDone - [traits setReturnKeyType:UIReturnKeyNext]; - [traits setSecureTextEntry:YES]; - } - - [sheet popupAlertAnimated:YES]; -} - -- (NSURLRequest *) webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)source { - NSURL *url = [request URL]; - if ([self getSpecial:url]) - return nil; - [self _pushPage]; - return [self _addHeadersToRequest:request]; -} - -- (WebView *) _createWebViewWithRequest:(NSURLRequest *)request pushed:(BOOL)pushed { - [self setBackButtonTitle:title_]; - - BrowserView *browser = [[[BrowserView alloc] initWithBook:book_] autorelease]; - [browser setDelegate:delegate_]; - - if (pushed) { - [browser loadRequest:[self _addHeadersToRequest:request]]; - [book_ pushPage:browser]; - } - - return [browser webView]; -} - -- (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request { - return [self _createWebViewWithRequest:request pushed:(request != nil)]; -} - -- (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request windowFeatures:(NSDictionary *)features { - return [self _createWebViewWithRequest:request pushed:YES]; -} - -- (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame { - if ([frame parentFrame] != nil) - return; - - title_ = [title retain]; - [book_ reloadTitleForPage:self]; -} - -- (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame { - if ([frame parentFrame] != nil) - return; - - reloading_ = false; - loading_ = true; - [self reloadButtons]; - - if (title_ != nil) { - [title_ release]; - title_ = nil; - } - - if (button_ != nil) { - [button_ release]; - button_ = nil; - } - - if (style_ != nil) { - [style_ release]; - style_ = nil; - } - - if (function_ != nil) { - [function_ release]; - function_ = nil; - } - - [book_ reloadTitleForPage:self]; - - WebView *webview = [webview_ webView]; - NSString *href = [webview mainFrameURL]; - [urls_ addObject:[NSURL URLWithString:href]]; - - [scroller_ scrollPointVisibleAtTopLeft:CGPointZero]; - - CGRect webrect = [scroller_ bounds]; - webrect.size.height = 0; - [webview_ setFrame:webrect]; -} - -- (void) _finishLoading { - if (!reloading_) { - loading_ = false; - [self reloadButtons]; - } -} - -- (bool) _loading { - return loading_; -} - -- (void) reloadButtons { - if ([self _loading]) - [indicator_ startAnimation]; - else - [indicator_ stopAnimation]; - [super reloadButtons]; -} - -- (BOOL) webView:(WebView *)sender shouldScrollToPoint:(struct CGPoint)point forFrame:(WebFrame *)frame { - return [webview_ webView:sender shouldScrollToPoint:point forFrame:frame]; -} - -- (void) webView:(WebView *)sender didReceiveViewportArguments:(id)arguments forFrame:(WebFrame *)frame { - return [webview_ webView:sender didReceiveViewportArguments:arguments forFrame:frame]; -} - -- (void) webView:(WebView *)sender needsScrollNotifications:(id)notifications forFrame:(WebFrame *)frame { - return [webview_ webView:sender needsScrollNotifications:notifications forFrame:frame]; -} - -- (void) webView:(WebView *)sender didCommitLoadForFrame:(WebFrame *)frame { - return [webview_ webView:sender didCommitLoadForFrame:frame]; -} - -- (void) webView:(WebView *)sender didReceiveDocTypeForFrame:(WebFrame *)frame { - return [webview_ webView:sender didReceiveDocTypeForFrame:frame]; -} - -- (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame { - if ([frame parentFrame] == nil) { - [self _finishLoading]; - - if (DOMDocument *document = [frame DOMDocument]) - if (DOMNodeList *bodies = [document getElementsByTagName:@"body"]) - for (DOMHTMLBodyElement *body in bodies) { - DOMCSSStyleDeclaration *style([document getComputedStyle:body pseudoElement:nil]); - - bool colored(false); - - if (DOMCSSPrimitiveValue *color = static_cast([style getPropertyCSSValue:@"background-color"])) { - DOMRGBColor *rgb([color getRGBColorValue]); - - float alpha([[rgb alpha] getFloatValue:DOM_CSS_NUMBER]); - NSLog(@"alpha:%g", alpha); - - if (alpha != 0) { - colored = true; - - [scroller_ setBackgroundColor:[UIColor - colorWithRed:([[rgb red] getFloatValue:DOM_CSS_NUMBER] / 255) - green:([[rgb green] getFloatValue:DOM_CSS_NUMBER] / 255) - blue:([[rgb blue] getFloatValue:DOM_CSS_NUMBER] / 255) - alpha:alpha - ]]; - } - } - - if (!colored) - [scroller_ setBackgroundColor:[UIColor pinStripeColor]]; - break; - } - } - - return [webview_ webView:sender didFinishLoadForFrame:frame]; -} - -- (void) webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame { - if ([frame parentFrame] != nil) - return; - [self _finishLoading]; - - [self loadURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@?%@", - [[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"error" ofType:@"html"]] absoluteString], - [[error localizedDescription] stringByAddingPercentEscapes] - ]]]; -} - -- (void) webView:(WebView *)sender addMessageToConsole:(NSDictionary *)dictionary { -#if ForSaurik - lprintf("Console:%s\n", [[dictionary description] UTF8String]); -#endif -} - -- (id) initWithBook:(RVBook *)book { - if ((self = [super initWithBook:book]) != nil) { - loading_ = false; - - struct CGRect bounds = [self bounds]; - - scroller_ = [[UIScroller alloc] initWithFrame:bounds]; - [self addSubview:scroller_]; - - [scroller_ setShowBackgroundShadow:NO]; - [scroller_ setFixedBackgroundPattern:YES]; - [scroller_ setBackgroundColor:[UIColor pinStripeColor]]; - - [scroller_ setScrollingEnabled:YES]; - [scroller_ setAdjustForContentSizeChange:YES]; - [scroller_ setClipsSubviews:YES]; - [scroller_ setAllowsRubberBanding:YES]; - [scroller_ setScrollDecelerationFactor:0.99]; - [scroller_ setDelegate:self]; - - CGRect webrect = [scroller_ bounds]; - webrect.size.height = 0; - - WebView *webview; - -#if RecycleWebViews - webview_ = [Documents_ lastObject]; - if (webview_ != nil) { - webview_ = [webview_ retain]; - webview = [webview_ webView]; - [Documents_ removeLastObject]; - [webview_ setFrame:webrect]; - } else { -#else - if (true) { -#endif - webview_ = [[UIWebDocumentView alloc] initWithFrame:webrect]; - webview = [webview_ webView]; - - // XXX: this is terribly (too?) expensive - [webview_ setDrawsBackground:NO]; - - [webview_ setTileSize:CGSizeMake(webrect.size.width, 500)]; - - [webview_ setAllowsMessaging:YES]; - - [webview_ setTilingEnabled:YES]; - [webview_ setDrawsGrid:NO]; - [webview_ setLogsTilingChanges:NO]; - [webview_ setTileMinificationFilter:kCAFilterNearest]; - [webview_ setDetectsPhoneNumbers:NO]; - [webview_ setAutoresizes:YES]; - - [webview_ setMinimumScale:0.25f forDocumentTypes:0x10]; - [webview_ setInitialScale:UIWebViewScalesToFitScale forDocumentTypes:0x10]; - [webview_ setViewportSize:CGSizeMake(980, UIWebViewGrowsAndShrinksToFitHeight) forDocumentTypes:0x10]; - - [webview_ setViewportSize:CGSizeMake(320, UIWebViewGrowsAndShrinksToFitHeight) forDocumentTypes:0x2]; - - [webview_ setMinimumScale:1.0f forDocumentTypes:0x8]; - [webview_ setInitialScale:UIWebViewScalesToFitScale forDocumentTypes:0x8]; - [webview_ setViewportSize:CGSizeMake(320, UIWebViewGrowsAndShrinksToFitHeight) forDocumentTypes:0x8]; - - [webview_ _setDocumentType:0x4]; - - [webview_ setZoomsFocusedFormControl:YES]; - [webview_ setContentsPosition:7]; - [webview_ setEnabledGestures:0xa]; - [webview_ setValue:[NSNumber numberWithBool:YES] forGestureAttribute:UIGestureAttributeIsZoomRubberBandEnabled]; - [webview_ setValue:[NSNumber numberWithBool:YES] forGestureAttribute:UIGestureAttributeUpdatesScroller]; - - [webview_ setSmoothsFonts:YES]; - - [webview _setUsesLoaderCache:YES]; - [webview setGroupName:@"Cydia"]; - [webview _setLayoutInterval:0]; - } - - [webview_ setDelegate:self]; - [webview_ setGestureDelegate:self]; - [scroller_ addSubview:webview_]; - - //NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; - - CGSize indsize = [UIProgressIndicator defaultSizeForStyle:UIProgressIndicatorStyleMediumWhite]; - indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(281, 12, indsize.width, indsize.height)]; - [indicator_ setStyle:UIProgressIndicatorStyleMediumWhite]; - - Package *package([[Database sharedInstance] packageWithName:@"cydia"]); - NSString *application = package == nil ? @"Cydia" : [NSString - stringWithFormat:@"Cydia/%@", - [package installed] - ]; [webview setApplicationNameForUserAgent:application]; - - indirect_ = [[IndirectDelegate alloc] initWithDelegate:self]; - - [webview setFrameLoadDelegate:self]; - [webview setResourceLoadDelegate:indirect_]; - [webview setUIDelegate:self]; - [webview setScriptDebugDelegate:self]; - [webview setPolicyDelegate:self]; - - urls_ = [[NSMutableArray alloc] initWithCapacity:16]; - - [self setAutoresizingMask:UIViewAutoresizingFlexibleHeight]; - [scroller_ setAutoresizingMask:UIViewAutoresizingFlexibleHeight]; - } return self; -} - -- (void) didFinishGesturesInView:(UIView *)view forEvent:(id)event { - [webview_ redrawScaledDocument]; -} - -- (void) _rightButtonClicked { - if (function_ == nil) { - reloading_ = true; - [self reloadURL]; - } else { - [delegate_ clearFirstResponder]; - JSObjectRef function([function_ JSObject]); - JSGlobalContextRef context([[[webview_ webView] mainFrame] globalContext]); - JSObjectCallAsFunction(context, function, NULL, 0, NULL, NULL); - } -} - -- (NSString *) _rightButtonTitle { - return button_ != nil ? button_ : @"Reload"; -} - -- (NSString *) rightButtonTitle { - return [self _loading] ? @"" : [self _rightButtonTitle]; -} - -- (UINavigationButtonStyle) rightButtonStyle { - if (style_ == nil) normal: - return UINavigationButtonStyleNormal; - else if ([style_ isEqualToString:@"Normal"]) - return UINavigationButtonStyleNormal; - else if ([style_ isEqualToString:@"Back"]) - return UINavigationButtonStyleBack; - else if ([style_ isEqualToString:@"Highlighted"]) - return UINavigationButtonStyleHighlighted; - else if ([style_ isEqualToString:@"Destructive"]) - return UINavigationButtonStyleDestructive; - else goto normal; -} - -- (NSString *) title { - return title_ == nil ? @"Loading" : title_; -} - -- (NSString *) backButtonTitle { - return @"Browser"; -} - -- (void) setPageActive:(BOOL)active { - if (!active) - [indicator_ removeFromSuperview]; - else - [[book_ navigationBar] addSubview:indicator_]; -} - -- (void) resetViewAnimated:(BOOL)animated { -} - -- (void) setPushed:(bool)pushed { - pushed_ = pushed; -} - -@end -/* }}} */ +#include /* Cydia Book {{{ */ @interface CYBook : RVBook < @@ -5568,8 +5194,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { UIProgressBar *progress_; UINavigationButton *cancel_; bool updating_; - size_t received_; - NSTimeInterval last_; } - (id) initWithFrame:(CGRect)frame database:(Database *)database; @@ -5619,8 +5243,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [prompt_ setText:@"Updating Database"]; [progress_ setProgress:0]; - received_ = 0; - last_ = [NSDate timeIntervalSinceReferenceDate]; updating_ = true; [overlay_ addSubview:cancel_]; @@ -5784,12 +5406,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (bool) isCancelling:(size_t)received { - NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate]; - if (received_ != received) { - received_ = received; - last_ = now; - } else if (now - last_ > 15) - return true; return !updating_; } @@ -5834,12 +5450,16 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (void) _returnPNGWithImage:(UIImage *)icon forRequest:(NSURLRequest *)request { id client([self client]); - NSData *data(UIImagePNGRepresentation(icon)); + if (icon == nil) + [client URLProtocol:self didFailWithError:[NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorFileDoesNotExist userInfo:nil]]; + else { + NSData *data(UIImagePNGRepresentation(icon)); - NSURLResponse *response([[[NSURLResponse alloc] initWithURL:[request URL] MIMEType:@"image/png" expectedContentLength:-1 textEncodingName:nil] autorelease]); - [client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed]; - [client URLProtocol:self didLoadData:data]; - [client URLProtocolDidFinishLoading:self]; + NSURLResponse *response([[[NSURLResponse alloc] initWithURL:[request URL] MIMEType:@"image/png" expectedContentLength:-1 textEncodingName:nil] autorelease]); + [client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed]; + [client URLProtocol:self didLoadData:data]; + [client URLProtocolDidFinishLoading:self]; + } } - (void) startLoading { @@ -5907,8 +5527,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { @end /* }}} */ -/* Install View {{{ */ -@interface InstallView : RVPage { +/* Sections View {{{ */ +@interface SectionsView : RVPage { _transient Database *database_; NSMutableArray *sections_; NSMutableArray *filtered_; @@ -5924,7 +5544,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { @end -@implementation InstallView +@implementation SectionsView - (void) dealloc { [list_ setDataSource:nil]; @@ -5989,7 +5609,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } } - PackageTable *table = [[[PackageTable alloc] + PackageTable *table = [[[FilteredPackageTable alloc] initWithBook:book_ database:database_ title:title @@ -6044,8 +5664,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { NSMutableDictionary *sections = [NSMutableDictionary dictionaryWithCapacity:32]; _trace(); - for (size_t i(0); i != [packages count]; ++i) { - Package *package([packages objectAtIndex:i]); + for (Package *package in packages) { NSString *name([package section]); if (name != nil) { @@ -6069,8 +5688,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { _trace(); Section *section = nil; - for (size_t offset = 0, count = [filtered count]; offset != count; ++offset) { - Package *package = [filtered objectAtIndex:offset]; + for (Package *package in filtered) { NSString *name = [package section]; if (section == nil || name != nil && ![[section name] isEqualToString:name]) { @@ -6114,7 +5732,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { return @"Sections"; } -- (NSString *) rightButtonTitle { +- (id) rightButtonTitle { return [sections_ count] == 0 ? nil : editing_ ? @"Done" : @"Edit"; } @@ -6245,15 +5863,12 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [sections_ removeAllObjects]; _trace(); - for (size_t i(0); i != [packages count]; ++i) { - Package *package([packages objectAtIndex:i]); - + for (Package *package in packages) if ( [package installed] == nil && [package valid] && [package visible] || - [package upgradableAndEssential:NO] + [package upgradableAndEssential:YES] ) [packages_ addObject:package]; - } _trace(); [packages_ radixSortUsingSelector:@selector(compareForChanges) withObject:nil]; @@ -6322,7 +5937,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { return [(CYBook *)book_ updating] ? nil : @"Refresh"; } -- (NSString *) rightButtonTitle { +- (id) rightButtonTitle { return upgrades_ == 0 ? nil : [NSString stringWithFormat:@"Upgrade (%u)", upgrades_]; } @@ -6341,7 +5956,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { UIView *accessory_; UISearchField *field_; UITransitionView *transition_; - PackageTable *table_; + FilteredPackageTable *table_; UIPreferencesTable *advanced_; UIView *dimmed_; bool flipped_; @@ -6459,10 +6074,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { if ((self = [super initWithBook:book]) != nil) { CGRect pageBounds = [book_ pageBounds]; - /*UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:pageBounds] autorelease]; - [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]]; - [self addSubview:pinstripe];*/ - transition_ = [[UITransitionView alloc] initWithFrame:pageBounds]; [self addSubview:transition_]; @@ -6476,7 +6087,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { CGColor dimmed(space_, 0, 0, 0, 0.5); [dimmed_ setBackgroundColor:[UIColor colorWithCGColor:dimmed]]; - table_ = [[PackageTable alloc] + table_ = [[FilteredPackageTable alloc] initWithBook:book database:database title:nil @@ -6570,7 +6181,10 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { if (flipped_) [self flipPage]; [table_ setObject:[field_ text]]; - [table_ reloadData]; + _profile(SearchView$reloadData) + [table_ reloadData]; + _end + PrintTimes(); [table_ resetCursor]; } @@ -6851,7 +6465,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { UIKeyboard *keyboard_; UIProgressHUD *hud_; - InstallView *install_; + SectionsView *sections_; ChangesView *changes_; ManageView *manage_; SearchView *search_; @@ -6899,12 +6513,17 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) _reloadData { - /*UIProgressHUD *hud = [[UIProgressHUD alloc] initWithWindow:window_]; - [hud setText:@"Reloading Data"]; - [overlay_ addSubview:hud]; - [hud show:YES];*/ + UIView *block(); - [database_ reloadData]; + static bool loaded(false); + UIProgressHUD *hud([self addProgressHUD]); + [hud setText:(loaded ? @"Reloading Data" : @"Loading Data")]; + loaded = true; + + [database_ yieldToSelector:@selector(reloadData) withObject:nil]; + _trace(); + + [self removeProgressHUD:hud]; size_t changes(0); @@ -6937,20 +6556,21 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [self updateData]; -#if !ForSaurik + // XXX: what is this line of code for? if ([packages count] == 0); - else if (Loaded_) -#endif + else if (Loaded_ || ForSaurik) loaded: [self _loaded]; -#if !ForSaurik else { Loaded_ = YES; + + if (NSDate *update = [Metadata_ objectForKey:@"LastUpdate"]) { + NSTimeInterval interval([update timeIntervalSinceNow]); + if (interval <= 0 && interval > -600) + goto loaded; + } + [book_ update]; } -#endif - - /*[hud show:NO]; - [hud removeFromSuperview];*/ } - (void) _saveConfig { @@ -6966,8 +6586,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [self _saveConfig]; /* XXX: this is just stupid */ - if (tag_ != 2 && install_ != nil) - [install_ reloadData]; + if (tag_ != 2 && sections_ != nil) + [sections_ reloadData]; if (tag_ != 3 && changes_ != nil) [changes_ reloadData]; if (tag_ != 5 && search_ != nil) @@ -6986,8 +6606,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { NSArray *keys = [Sources_ allKeys]; - for (int i(0), e([keys count]); i != e; ++i) { - NSString *key = [keys objectAtIndex:i]; + for (NSString *key in keys) { NSDictionary *source = [Sources_ objectForKey:key]; fprintf(file, "%s %s %s\n", @@ -7024,17 +6643,25 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { _error->Discard(); } +- (void) popUpBook:(RVBook *)book { + [underlay_ popSubview:book]; +} + +- (CGRect) popUpBounds { + return [underlay_ bounds]; +} + - (void) perform { [database_ prepare]; - confirm_ = [[RVBook alloc] initWithFrame:[underlay_ bounds]]; + confirm_ = [[RVBook alloc] initWithFrame:[self popUpBounds]]; [confirm_ setDelegate:self]; ConfirmationView *page([[[ConfirmationView alloc] initWithBook:confirm_ database:database_] autorelease]); [page setDelegate:self]; [confirm_ setPage:page]; - [underlay_ popSubview:confirm_]; + [self popUpBook:confirm_]; } - (void) installPackage:(Package *)package { @@ -7129,12 +6756,12 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [book_ resetViewAnimated:YES]; return; } else if (tag_ == 2 && tag != 2) - [install_ resetView]; + [sections_ resetView]; switch (tag) { case 1: [self _setHomePage]; break; - case 2: [self setPage:install_]; break; + case 2: [self setPage:sections_]; break; case 3: [self setPage:changes_]; break; case 4: [self setPage:manage_]; break; case 5: [self setPage:search_]; break; @@ -7170,9 +6797,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (void) finish { if (hud_ != nil) { [self setStatusBarShowsProgress:NO]; + [self removeProgressHUD:hud_]; - [hud_ show:NO]; - [hud_ removeFromSuperview]; [hud_ autorelease]; hud_ = nil; @@ -7190,6 +6816,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { return; } + _trace(); overlay_ = [[UIView alloc] initWithFrame:[underlay_ bounds]]; CGRect screenrect = [UIHardware fullScreenApplicationContentRect]; @@ -7290,7 +6917,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [self reloadData]; - install_ = [[InstallView alloc] initWithBook:book_ database:database_]; + sections_ = [[SectionsView alloc] initWithBook:book_ database:database_]; changes_ = [[ChangesView alloc] initWithBook:book_ database:database_]; search_ = [[SearchView alloc] initWithBook:book_ database:database_]; @@ -7299,6 +6926,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { withClass:[ManageView class] ] retain]; + PrintTimes(); + if (bootstrap_) [self bootstrap]; else @@ -7308,12 +6937,13 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button { NSString *context([sheet context]); - if ([context isEqualToString:@"fixhalf"]) { + if ([context isEqualToString:@"missing"]) + [sheet dismiss]; + else if ([context isEqualToString:@"fixhalf"]) { switch (button) { case 1: @synchronized (self) { - for (int i = 0, e = [broken_ count]; i != e; ++i) { - Package *broken = [broken_ objectAtIndex:i]; + for (Package *broken in broken_) { [broken remove]; NSString *id = [broken id]; @@ -7369,10 +6999,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { switch (button) { case 1: @synchronized (self) { - for (int i = 0, e = [essential_ count]; i != e; ++i) { - Package *essential = [essential_ objectAtIndex:i]; + for (Package *essential in essential_) [essential install]; - } [self resolve]; [self perform]; @@ -7416,12 +7044,19 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (UIProgressHUD *) addProgressHUD { - UIProgressHUD *hud = [[UIProgressHUD alloc] initWithWindow:window_]; + UIProgressHUD *hud([[[UIProgressHUD alloc] initWithWindow:window_] autorelease]); + [window_ setUserInteractionEnabled:NO]; [hud show:YES]; - [underlay_ addSubview:hud]; + [progress_ addSubview:hud]; return hud; } +- (void) removeProgressHUD:(UIProgressHUD *)hud { + [hud show:NO]; + [hud removeFromSuperview]; + [window_ setUserInteractionEnabled:YES]; +} + - (void) openMailToURL:(NSURL *)url { // XXX: this makes me sad #if 0 @@ -7460,29 +7095,39 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (RVPage *) pageForURL:(NSURL *)url hasTag:(int *)tag { - NSString *href = [url absoluteString]; - if (tag != NULL) tag = 0; - if ([href isEqualToString:@"cydia://add-source"]) + NSString *scheme([[url scheme] lowercaseString]); + if (![scheme isEqualToString:@"cydia"]) + return nil; + NSString *path([url absoluteString]); + if ([path length] < 8) + return nil; + path = [path substringFromIndex:8]; + if (![path hasPrefix:@"/"]) + path = [@"/" stringByAppendingString:path]; + + if ([path isEqualToString:@"/add-source"]) return [[[AddSourceView alloc] initWithBook:book_ database:database_] autorelease]; - else if ([href isEqualToString:@"cydia://sources"]) + else if ([path isEqualToString:@"/storage"]) + return [self _pageForURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"storage" ofType:@"html"]] withClass:[BrowserView class]]; + else if ([path isEqualToString:@"/sources"]) return [[[SourceTable alloc] initWithBook:book_ database:database_] autorelease]; - else if ([href isEqualToString:@"cydia://packages"]) + else if ([path isEqualToString:@"/packages"]) return [[[InstalledView alloc] initWithBook:book_ database:database_] autorelease]; - else if ([href hasPrefix:@"cydia://url/"]) - return [self _pageForURL:[NSURL URLWithString:[href substringFromIndex:12]] withClass:[BrowserView class]]; - else if ([href hasPrefix:@"cydia://launch/"]) - [self launchApplicationWithIdentifier:[href substringFromIndex:15] suspended:NO]; - else if ([href hasPrefix:@"cydia://package-settings/"]) - return [[[SettingsView alloc] initWithBook:book_ database:database_ package:[href substringFromIndex:25]] autorelease]; - else if ([href hasPrefix:@"cydia://package-signature/"]) - return [[[SignatureView alloc] initWithBook:book_ database:database_ package:[href substringFromIndex:26]] autorelease]; - else if ([href hasPrefix:@"cydia://package/"]) - return [self pageForPackage:[href substringFromIndex:16]]; - else if ([href hasPrefix:@"cydia://files/"]) { - NSString *name = [href substringFromIndex:14]; + else if ([path hasPrefix:@"/url/"]) + return [self _pageForURL:[NSURL URLWithString:[path substringFromIndex:5]] withClass:[BrowserView class]]; + else if ([path hasPrefix:@"/launch/"]) + [self launchApplicationWithIdentifier:[path substringFromIndex:8] suspended:NO]; + else if ([path hasPrefix:@"/package-settings/"]) + return [[[SettingsView alloc] initWithBook:book_ database:database_ package:[path substringFromIndex:18]] autorelease]; + else if ([path hasPrefix:@"/package-signature/"]) + return [[[SignatureView alloc] initWithBook:book_ database:database_ package:[path substringFromIndex:19]] autorelease]; + else if ([path hasPrefix:@"/package/"]) + return [self pageForPackage:[path substringFromIndex:9]]; + else if ([path hasPrefix:@"/files/"]) { + NSString *name = [path substringFromIndex:7]; if (Package *package = [database_ packageWithName:name]) { FileTable *files = [[[FileTable alloc] initWithBook:book_ database:database_] autorelease]; @@ -7505,6 +7150,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) applicationDidFinishLaunching:(id)unused { + _trace(); Font12_ = [[UIFont systemFontOfSize:12] retain]; Font12Bold_ = [[UIFont boldSystemFontOfSize:12] retain]; Font14_ = [[UIFont systemFontOfSize:14] retain]; @@ -7549,7 +7195,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { ) { [self setIdleTimerDisabled:YES]; - hud_ = [self addProgressHUD]; + hud_ = [[self addProgressHUD] retain]; [hud_ setText:@"Reorganizing\n\nWill Automatically\nClose When Done"]; [self setStatusBarShowsProgress:YES]; @@ -7605,8 +7251,7 @@ void AddPreferences(NSString *plist) { _pooled bool cydia(false); - for (size_t i(0); i != [items count]; ++i) { - NSMutableDictionary *item([items objectAtIndex:i]); + for (NSMutableDictionary *item in items) { NSString *label = [item objectForKey:@"label"]; if (label != nil && [label isEqualToString:@"Cydia"]) { cydia = true; @@ -7650,6 +7295,7 @@ id Dealloc_(id self, SEL selector) { }*/ int main(int argc, char *argv[]) { _pooled + _trace(); class_addMethod(objc_getClass("DOMNodeList"), @selector(countByEnumeratingWithState:objects:count:), (IMP) &DOMNodeList$countByEnumeratingWithState$objects$count$, "I20@0:4^{NSFastEnumerationState}8^@12I16"); bool substrate(false); @@ -7726,13 +7372,21 @@ int main(int argc, char *argv[]) { _pooled UniqueID_ = [[UIDevice currentDevice] uniqueIdentifier]; + if (NSDictionary *system = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]) + Build_ = [system objectForKey:@"ProductBuildVersion"]; + if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:@"/Applications/MobileSafari.app/Info.plist"]) { + Product_ = [info objectForKey:@"SafariProductVersion"]; + Safari_ = [info objectForKey:@"CFBundleVersion"]; + } + /*AddPreferences(@"/Applications/Preferences.app/Settings-iPhone.plist"); AddPreferences(@"/Applications/Preferences.app/Settings-iPod.plist");*/ - if ((Indices_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/indices.plist"]) == NULL) - Indices_ = [[NSMutableDictionary alloc] init]; + _trace(); + Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"]; + _trace(); - if ((Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"]) == NULL) + if (Metadata_ == NULL) Metadata_ = [[NSMutableDictionary alloc] initWithCapacity:2]; else { Settings_ = [Metadata_ objectForKey:@"Settings"]; @@ -7764,11 +7418,16 @@ int main(int argc, char *argv[]) { _pooled Documents_ = [[[NSMutableArray alloc] initWithCapacity:4] autorelease]; #endif - if (substrate && access("/Library/MobileSubstrate/MobileSubstrate.dylib", F_OK) == 0) - dlopen("/Library/MobileSubstrate/MobileSubstrate.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); + /*if (substrate && access("/Library/MobileSubstrate/MobileSubstrate.dylib", F_OK) == 0) + dlopen("/Library/MobileSubstrate/MobileSubstrate.dylib", RTLD_LAZY | RTLD_GLOBAL);*/ - if (access("/User", F_OK) != 0) + if (access("/User", F_OK) != 0) { + _trace(); system("/usr/libexec/cydia/firmware.sh"); + _trace(); + } _assert([[NSFileManager defaultManager] createDirectoryAtPath:@"/var/cache/apt/archives/partial" @@ -7793,6 +7452,7 @@ int main(int argc, char *argv[]) { _pooled UIApplicationUseLegacyEvents(YES); UIKeyboardDisableAutomaticAppearance(); + _trace(); int value = UIApplicationMain(argc, argv, @"Cydia", @"Cydia"); CGColorSpaceRelease(space_);