X-Git-Url: https://git.saurik.com/cydia.git/blobdiff_plain/e4123ce0f74c829513f5c5370a8cf90262a6ee64..5ad3e6d9a0a9a6972b5fb8fea108ea7168757ea5:/MobileCydia.mm diff --git a/MobileCydia.mm b/MobileCydia.mm index e9c8908c..a54c7b73 100644 --- a/MobileCydia.mm +++ b/MobileCydia.mm @@ -41,8 +41,8 @@ #define USE_SYSTEM_MALLOC 1 /* #include Directives {{{ */ -#include "UICaboodle/UCPlatform.h" -#include "UICaboodle/UCLocalize.h" +#include "CyteKit/UCPlatform.h" +#include "CyteKit/Localize.h" #include #include @@ -117,16 +117,23 @@ extern "C" { #include #include -#include #include -#include "UICaboodle/BrowserView.h" -#include "SDURLCache/SDURLCache.h" +#include +#include "Menes/Menes.h" -#include "substrate.h" +#include "CyteKit/PerlCompatibleRegEx.hpp" +#include "CyteKit/TableViewCell.h" +#include "CyteKit/WebScriptObject-Cyte.h" +#include "CyteKit/WebViewController.h" +#include "CyteKit/stringWithUTF8Bytes.h" -#include "Version.h" +#include "Cydia/MIMEAddress.h" +#include "Cydia/LoadingViewController.h" +#include "Cydia/ProgressEvent.h" + +#include "SDURLCache/SDURLCache.h" /* }}} */ /* Profiler {{{ */ @@ -199,14 +206,35 @@ void PrintTimes() { #define _end } /* }}} */ -#define _pooled _H _pool([[NSAutoreleasePool alloc] init], true); +#include "Version.h" +#define Cydia_ CYDIA_VERSION -#define CYPoolStart() \ - NSAutoreleasePool *_pool([[NSAutoreleasePool alloc] init]); \ - do -#define CYPoolEnd() \ - while (false); \ - [_pool release]; +#define lprintf(args...) fprintf(stderr, args) + +#define ForRelease 1 +#define TraceLogging (1 && !ForRelease) +#define HistogramInsertionSort (!ForRelease ? 0 : 0) +#define ProfileTimes (0 && !ForRelease) +#define ForSaurik (0 && !ForRelease) +#define LogBrowser (0 && !ForRelease) +#define TrackResize (0 && !ForRelease) +#define ManualRefresh (1 && !ForRelease) +#define ShowInternals (0 && !ForRelease) +#define AlwaysReload (0 && !ForRelease) +#define TryIndexedCollation (0 && !ForRelease) + +#if !TraceLogging +#undef _trace +#define _trace(args...) +#endif + +#if !ProfileTimes +#undef _profile +#define _profile(name) { +#undef _end +#define _end } +#define PrintTimes() do {} while (false) +#endif // Hash Functions/Structures {{{ extern "C" uint32_t hashlittle(const void *key, size_t length, uint32_t initval = 0); @@ -217,6 +245,11 @@ union SplitHash { }; // }}} +static NSString *Colon_; +NSString *Elision_; +static NSString *Error_; +static NSString *Warning_; + static const NSUInteger UIViewAutoresizingFlexibleBoth(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); static _finline NSString *CydiaURL(NSString *path) { @@ -239,231 +272,16 @@ static _finline void UpdateExternalStatus(uint64_t newStatus) { notify_post("com.saurik.Cydia.status"); } -/* [NSObject yieldToSelector:(withObject:)] {{{*/ -@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]); - - NSMethodSignature *signature([self methodSignatureForSelector:selector]); - [context removeAllObjects]; - if ([signature methodReturnLength] != 0 && value != nil) - [context addObject:value]; - - stopped = true; - - [self - performSelectorOnMainThread:@selector(doNothing) - withObject:nil - waitUntilDone:NO - ]; -} - -- (id) yieldToSelector:(SEL)selector withObject:(id)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]); - NSString *mode([loop currentMode] ?: NSDefaultRunLoopMode); - - while (!stopped && [loop runMode:mode beforeDate:future]); - - return [context count] == 0 ? nil : [context objectAtIndex:0]; -} - -- (id) yieldToSelector:(SEL)selector { - return [self yieldToSelector:selector withObject:nil]; +static CGFloat CYStatusBarHeight(UIInterfaceOrientation orientation) { + CGSize size([[UIApplication sharedApplication] statusBarFrame].size); + return UIInterfaceOrientationIsPortrait(orientation) ? size.height : size.width; } -@end -/* }}} */ - -/* Cydia Alert View {{{ */ -@interface CYAlertView : UIAlertView { - unsigned button_; -} - -- (int) yieldToPopupAlertAnimated:(BOOL)animated; - -@end - -@implementation CYAlertView - -- (id) initWithTitle:(NSString *)title buttons:(NSArray *)buttons defaultButtonIndex:(int)index { - if ((self = [super init]) != nil) { - [self setTitle:title]; - [self setDelegate:self]; - for (NSString *button in buttons) [self addButtonWithTitle:button]; - [self setCancelButtonIndex:index]; - } return self; -} - -- (void) _updateFrameForDisplay { - [super _updateFrameForDisplay]; - if ([self cancelButtonIndex] == -1) { - NSArray *buttons = [self buttons]; - if ([buttons count]) { - UIImage *background = [[buttons objectAtIndex:0] backgroundForState:0]; - for (UIThreePartButton *button in buttons) - [button setBackground:background forState:0]; - } - } -} - -- (void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { - button_ = buttonIndex + 1; -} - -- (void) dismiss { - [self dismissWithClickedButtonIndex:-1 animated:YES]; -} - -- (int) yieldToPopupAlertAnimated:(BOOL)animated { - [self setRunsModal:YES]; - button_ = 0; - [self show]; - return button_; -} - -@end -/* }}} */ - /* NSForcedOrderingSearch doesn't work on the iPhone */ static const NSStringCompareOptions MatchCompareOptions_ = NSLiteralSearch | NSCaseInsensitiveSearch; static const NSStringCompareOptions LaxCompareOptions_ = NSNumericSearch | NSDiacriticInsensitiveSearch | NSWidthInsensitiveSearch | NSCaseInsensitiveSearch; static const CFStringCompareFlags LaxCompareFlags_ = kCFCompareCaseInsensitive | kCFCompareNonliteral | kCFCompareLocalized | kCFCompareNumerically | kCFCompareWidthInsensitive | kCFCompareForcedOrdering; -#define lprintf(args...) fprintf(stderr, args) - -#define ForRelease 1 -#define TraceLogging (1 && !ForRelease) -#define HistogramInsertionSort (!ForRelease ? 0 : 0) -#define ProfileTimes (0 && !ForRelease) -#define ForSaurik (0 && !ForRelease) -#define LogBrowser (0 && !ForRelease) -#define TrackResize (0 && !ForRelease) -#define ManualRefresh (1 && !ForRelease) -#define ShowInternals (0 && !ForRelease) -#define AlwaysReload (0 && !ForRelease) -#define TryIndexedCollation (0 && !ForRelease) - -#if !TraceLogging -#undef _trace -#define _trace(args...) -#endif - -#if !ProfileTimes -#undef _profile -#define _profile(name) { -#undef _end -#define _end } -#define PrintTimes() do {} while (false) -#endif - -/* Radix Sort {{{ */ -typedef uint32_t (*SKRadixFunction)(id, void *); - -@interface NSMutableArray (Radix) -- (void) radixSortUsingFunction:(SKRadixFunction)function withContext:(void *)argument; -@end - -struct RadixItem_ { - size_t index; - uint32_t key; -}; - -@implementation NSMutableArray (Radix) - -- (void) radixSortUsingFunction:(SKRadixFunction)function withContext:(void *)argument { - size_t count([self count]); - struct RadixItem_ *swap(new RadixItem_[count * 2]); - - for (size_t i(0); i != count; ++i) { - RadixItem_ &item(swap[i]); - item.index = i; - - id object([self objectAtIndex:i]); - item.key = function(object, argument); - } - - struct RadixItem_ *lhs(swap), *rhs(swap + count); - - static const size_t width = 32; - static const size_t bits = 11; - static const size_t slots = 1 << bits; - static const size_t passes = (width + (bits - 1)) / bits; - - size_t *hist(new size_t[slots]); - - for (size_t pass(0); pass != passes; ++pass) { - memset(hist, 0, sizeof(size_t) * slots); - - for (size_t i(0); i != count; ++i) { - uint32_t key(lhs[i].key); - key >>= pass * bits; - key &= _not(uint32_t) >> width - bits; - ++hist[key]; - } - - size_t offset(0); - for (size_t i(0); i != slots; ++i) { - size_t local(offset); - offset += hist[i]; - hist[i] = local; - } - - for (size_t i(0); i != count; ++i) { - uint32_t key(lhs[i].key); - key >>= pass * bits; - key &= _not(uint32_t) >> width - bits; - rhs[hist[key]++] = lhs[i]; - } - - RadixItem_ *tmp(lhs); - lhs = rhs; - rhs = tmp; - } - - delete [] hist; - - const void **values(new const void *[count]); - for (size_t i(0); i != count; ++i) - values[i] = [self objectAtIndex:lhs[i].index]; - CFArrayReplaceValues((CFMutableArrayRef) self, CFRangeMake(0, count), values, count); - delete [] values; - - delete [] swap; -} - -@end -/* }}} */ /* Insertion Sort {{{ */ CFIndex SKBSearch_(const void *element, CFIndex elementSize, const void *list, CFIndex count, CFComparatorFunction comparator, void *context) { @@ -568,38 +386,6 @@ void CFArrayInsertionSortValues(CFMutableArrayRef array, CFRange range, CFCompar @end /* }}} */ -@interface NSInvocation (Cydia) -+ (NSInvocation *) invocationWithSelector:(SEL)selector forTarget:(id)target; -@end - -@implementation NSInvocation (Cydia) - -+ (NSInvocation *) invocationWithSelector:(SEL)selector forTarget:(id)target { - NSInvocation *invocation([NSInvocation invocationWithMethodSignature:[target methodSignatureForSelector:selector]]); - [invocation setTarget:target]; - [invocation setSelector:selector]; - return invocation; -} - -@end - -@implementation WebScriptObject (NSFastEnumeration) - -- (NSUInteger) countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)objects count:(NSUInteger)count { - size_t length([self count] - state->state); - if (length <= 0) - return 0; - else if (length > count) - length = count; - for (size_t i(0); i != length; ++i) - objects[i] = [self objectAtIndex:state->state++]; - state->itemsPtr = objects; - state->mutationsPtr = (unsigned long *) self; - return length; -} - -@end - NSUInteger DOMNodeList$countByEnumeratingWithState$objects$count$(DOMNodeList *self, SEL sel, NSFastEnumerationState *state, id *objects, NSUInteger count) { size_t length([self length] - state->state); if (length <= 0) @@ -615,9 +401,6 @@ NSUInteger DOMNodeList$countByEnumeratingWithState$objects$count$(DOMNodeList *s /* Cydia NSString Additions {{{ */ @interface NSString (Cydia) -+ (NSString *) stringWithUTF8BytesNoCopy:(const char *)bytes length:(int)length; -+ (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length withZone:(NSZone *)zone inPool:(apr_pool_t *)pool; -+ (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length; - (NSComparisonResult) compareByPath:(NSString *)other; - (NSString *) stringByCachingURLWithCurrentCDN; - (NSString *) stringByAddingPercentEscapesIncludingReserved; @@ -625,20 +408,6 @@ NSUInteger DOMNodeList$countByEnumeratingWithState$objects$count$(DOMNodeList *s @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 withZone:(NSZone *)zone inPool:(apr_pool_t *)pool { - char *data(reinterpret_cast(apr_palloc(pool, length))); - memcpy(data, bytes, length); - return [[[NSString allocWithZone:zone] initWithBytesNoCopy:data 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]; -} - - (NSComparisonResult) compareByPath:(NSString *)other { NSString *prefix = [self commonPrefixWithString:other options:0]; size_t length = [prefix length]; @@ -832,132 +601,6 @@ struct NSStringMapEqual : }; /* }}} */ -/* Perl-Compatible RegEx {{{ */ -class Pcre { - private: - pcre *code_; - pcre_extra *study_; - int capture_; - int *matches_; - const char *data_; - - public: - Pcre(const char *regex) : - study_(NULL) - { - const char *error; - int offset; - code_ = pcre_compile(regex, 0, &error, &offset, NULL); - - if (code_ == NULL) { - lprintf("%d:%s\n", offset, error); - _assert(false); - } - - pcre_fullinfo(code_, study_, PCRE_INFO_CAPTURECOUNT, &capture_); - matches_ = new int[(capture_ + 1) * 3]; - } - - ~Pcre() { - pcre_free(code_); - delete matches_; - } - - NSString *operator [](size_t match) { - return [NSString stringWithUTF8Bytes:(data_ + matches_[match * 2]) length:(matches_[match * 2 + 1] - matches_[match * 2])]; - } - - bool operator ()(NSString *data) { - // XXX: length is for characters, not for bytes - return operator ()([data UTF8String], [data length]); - } - - bool operator ()(const char *data, size_t size) { - data_ = data; - return pcre_exec(code_, study_, data, size, 0, 0, matches_, (capture_ + 1) * 3) >= 0; - } -}; -/* }}} */ -/* Mime Addresses {{{ */ -@interface Address : NSObject { - NSString *name_; - NSString *address_; -} - -- (NSString *) name; -- (NSString *) address; - -- (void) setAddress:(NSString *)address; - -+ (Address *) addressWithString:(NSString *)string; -- (Address *) initWithString:(NSString *)string; - -@end - -@implementation Address - -- (void) dealloc { - [name_ release]; - if (address_ != nil) - [address_ release]; - [super dealloc]; -} - -- (NSString *) name { - return name_; -} - -- (NSString *) address { - return address_; -} - -- (void) setAddress:(NSString *)address { - if (address_ != nil) - [address_ autorelease]; - if (address == nil) - address_ = nil; - else - address_ = [address retain]; -} - -+ (Address *) addressWithString:(NSString *)string { - return [[[Address alloc] initWithString:string] autorelease]; -} - -+ (NSArray *) _attributeKeys { - return [NSArray arrayWithObjects: - @"address", - @"name", - nil]; -} - -- (NSArray *) attributeKeys { - return [[self class] _attributeKeys]; -} - -+ (BOOL) isKeyExcludedFromWebScript:(const char *)name { - return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name]; -} - -- (Address *) initWithString:(NSString *)string { - if ((self = [super init]) != nil) { - const char *data = [string UTF8String]; - size_t size = [string length]; - - static Pcre address_r("^\"?(.*)\"? <([^>]*)>$"); - - if (address_r(data, size)) { - name_ = [address_r[1] retain]; - address_ = [address_r[2] retain]; - } else { - name_ = [string retain]; - address_ = nil; - } - } return self; -} - -@end -/* }}} */ /* CoreGraphics Primitives {{{ */ class CYColor { private: @@ -1032,16 +675,17 @@ static NSString *App_; static BOOL Advanced_; static BOOL Ignored_; -static UIFont *Font12_; -static UIFont *Font12Bold_; -static UIFont *Font14_; -static UIFont *Font18Bold_; -static UIFont *Font22Bold_; +static _H Font12_; +static _H Font12Bold_; +static _H Font14_; +static _H Font18Bold_; +static _H Font22Bold_; static const char *Machine_ = NULL; static NSString *System_ = nil; static NSString *SerialNumber_ = nil; static NSString *ChipID_ = nil; +static NSString *BBSNum_ = nil; static _H Token_; static NSString *UniqueID_ = nil; static NSString *PLMN_ = nil; @@ -1058,8 +702,11 @@ static NSMutableDictionary *Metadata_; static _transient NSMutableDictionary *Settings_; static _transient NSString *Role_; static _transient NSMutableDictionary *Packages_; +static _transient NSMutableDictionary *Values_; static _transient NSMutableDictionary *Sections_; static _transient NSMutableDictionary *Sources_; +static _transient NSNumber *Version_; +static _transient _H CydiaSource_; static bool Changed_; static time_t now_; @@ -1067,7 +714,13 @@ bool IsWildcat_; static CGFloat ScreenScale_; static NSString *Idiom_; -static NSMutableSet *CydiaHosts_; +static _H SessionData_; +static _H HostConfig_; +static _H BridgedHosts_; +static _H TokenHosts_; +static _H InsecureHosts_; +static _H PipelinedHosts_; +static _H CachedURLs_; static NSString *kCydiaProgressEventTypeError = @"Error"; static NSString *kCydiaProgressEventTypeInformation = @"Information"; @@ -1075,6 +728,45 @@ static NSString *kCydiaProgressEventTypeStatus = @"Status"; static NSString *kCydiaProgressEventTypeWarning = @"Warning"; /* }}} */ +static void AddSource(NSDictionary *source) { + [Sources_ setObject:source forKey:[NSString stringWithFormat:@"%@:%@:%@", [source objectForKey:@"Type"], [source objectForKey:@"URI"], [source objectForKey:@"Distribution"]]]; + Changed_ = true; +} + +static void AddSource(NSString *href, NSString *distribution, NSArray *sections = nil) { + AddSource([NSMutableDictionary dictionaryWithObjectsAndKeys: + @"deb", @"Type", + href, @"URI", + distribution, @"Distribution", + sections ?: [NSMutableArray array], @"Sections", + nil]); +} + +static void WriteSources() { + FILE *file(fopen("/etc/apt/sources.list.d/cydia.list", "w")); + _assert(file != NULL); + + fprintf(file, "deb http://%s/ tangelo-3.7 main\n", + [CydiaSource_ UTF8String] + ); + + for (NSString *key in [Sources_ allKeys]) { + NSDictionary *source([Sources_ objectForKey:key]); + + NSArray *sections([source objectForKey:@"Sections"] ?: [NSArray array]); + + fprintf(file, "%s %s %s%s%s\n", + [[source objectForKey:@"Type"] UTF8String], + [[source objectForKey:@"URI"] UTF8String], + [[source objectForKey:@"Distribution"] UTF8String], + [sections count] == 0 ? "" : " ", + [[sections componentsJoinedByString:@" "] UTF8String] + ); + } + + fclose(file); +} + /* Display Helpers {{{ */ inline float Interpolate(float begin, float end, float fraction) { return (end - begin) * fraction + begin; @@ -1140,6 +832,34 @@ bool isSectionVisible(NSString *section) { return hidden == nil || ![hidden boolValue]; } +static NSObject *CYIOGetValue(const char *path, NSString *property) { + io_registry_entry_t entry(IORegistryEntryFromPath(kIOMasterPortDefault, path)); + if (entry == MACH_PORT_NULL) + return nil; + + CFTypeRef value(IORegistryEntryCreateCFProperty(entry, (CFStringRef) property, kCFAllocatorDefault, 0)); + IOObjectRelease(entry); + + if (value == NULL) + return nil; + return [(id) value autorelease]; +} + +static NSString *CYHex(NSData *data, bool reverse = false) { + if (data == nil) + return nil; + + size_t length([data length]); + uint8_t bytes[length]; + [data getBytes:bytes]; + + char string[length * 2 + 1]; + for (size_t i(0); i != length; ++i) + sprintf(string + i * 2, "%.2x", bytes[reverse ? length - i - 1 : i]); + + return [NSString stringWithUTF8String:string]; +} + @class Cydia; /* Delegate Prototypes {{{ */ @@ -1156,6 +876,8 @@ bool isSectionVisible(NSString *section) { @class CYPackageController; @protocol CydiaDelegate +- (void) returnToCydia; +- (void) saveState; - (void) retainNetworkActivityIndicator; - (void) releaseNetworkActivityIndicator; - (void) clearPackage:(Package *)package; @@ -1168,62 +890,17 @@ bool isSectionVisible(NSString *section) { - (void) loadData; - (void) updateData; - (void) syncData; +- (void) addSource:(NSDictionary *)source; - (void) addTrivialSource:(NSString *)href; - (void) showSettings; - (UIProgressHUD *) addProgressHUD; - (void) removeProgressHUD:(UIProgressHUD *)hud; -- (CYViewController *) pageForPackage:(NSString *)name; +- (CyteViewController *) pageForPackage:(NSString *)name; - (void) showActionSheet:(UIActionSheet *)sheet fromItem:(UIBarButtonItem *)item; - (void) reloadDataWithInvocation:(NSInvocation *)invocation; -- (void) addCydiaHost:(NSString *)host; @end /* }}} */ -/* ProgressEvent Interface/Delegate {{{ */ -@interface CydiaProgressEvent : NSObject { - _H message_; - _H type_; - - _H item_; - _H package_; - _H url_; - _H version_; -} - -+ (CydiaProgressEvent *) eventWithMessage:(NSString *)message ofType:(NSString *)type; -+ (CydiaProgressEvent *) eventWithMessage:(NSString *)message ofType:(NSString *)type forPackage:(NSString *)package; -+ (CydiaProgressEvent *) eventWithMessage:(NSString *)message ofType:(NSString *)type forItem:(pkgAcquire::ItemDesc &)item; - -- (id) initWithMessage:(NSString *)message ofType:(NSString *)type; - -- (NSString *) message; -- (NSString *) type; - -- (NSArray *) item; -- (NSString *) package; -- (NSString *) url; -- (NSString *) version; - -- (void) setItem:(NSArray *)item; -- (void) setPackage:(NSString *)package; -- (void) setURL:(NSString *)url; -- (void) setVersion:(NSString *)version; - -- (NSString *) compound:(NSString *)value; -- (NSString *) compoundMessage; -- (NSString *) compoundTitle; - -@end - -@protocol ProgressDelegate -- (void) addProgressEvent:(CydiaProgressEvent *)event; -- (void) setProgressPercent:(NSNumber *)percent; -- (void) setProgressStatus:(NSDictionary *)status; -- (void) setProgressCancellable:(NSNumber *)cancellable; -- (bool) isProgressCancelled; -- (void) setTitle:(NSString *)title; -@end -/* }}} */ /* Status Delegation {{{ */ class Status : public pkgAcquireStatus @@ -1252,6 +929,7 @@ class Status : } virtual void IMSHit(pkgAcquire::ItemDesc &item) { + Done(item); } virtual void Fetch(pkgAcquire::ItemDesc &item) { @@ -1261,6 +939,9 @@ class Status : } virtual void Done(pkgAcquire::ItemDesc &item) { + NSString *name([NSString stringWithUTF8String:item.ShortDesc.c_str()]); + CydiaProgressEvent *event([CydiaProgressEvent eventWithMessage:[NSString stringWithFormat:Colon_, UCLocalize("DONE"), name] ofType:kCydiaProgressEventTypeStatus forItem:item]); + [delegate_ performSelectorOnMainThread:@selector(addProgressEvent:) withObject:event waitUntilDone:YES]; } virtual void Fail(pkgAcquire::ItemDesc &item) { @@ -1337,7 +1018,7 @@ typedef std::map< unsigned long, _H > SourceMap; pkgSourceList *list_; SourceMap sourceMap_; - NSMutableArray *sourceList_; + _H sourceList_; CFMutableArrayRef packages_; @@ -1644,6 +1325,7 @@ static void PackageImport(const void *key, const void *value, void *context) { CYString uri_; CYString distribution_; CYString type_; + CYString base_; CYString version_; _H host_; @@ -1668,11 +1350,14 @@ static void PackageImport(const void *key, const void *value, void *context) { - (NSString *) uri; - (NSString *) distribution; - (NSString *) type; + +- (NSString *) base; + - (NSString *) key; - (NSString *) host; - (NSString *) name; -- (NSString *) description; +- (NSString *) shortDescription; - (NSString *) label; - (NSString *) origin; - (NSString *) version; @@ -1688,6 +1373,8 @@ static void PackageImport(const void *key, const void *value, void *context) { distribution_.clear(); type_.clear(); + base_.clear(); + description_.clear(); label_.clear(); origin_.clear(); @@ -1701,21 +1388,32 @@ static void PackageImport(const void *key, const void *value, void *context) { authority_ = nil; } -- (void) dealloc { - // XXX: this is a very inefficient way to call these deconstructors - [self _clear]; - [super dealloc]; ++ (NSString *) webScriptNameForSelector:(SEL)selector { + if (false); + else if (selector == @selector(addSection:)) + return @"addSection"; + else if (selector == @selector(removeSection:)) + return @"removeSection"; + else if (selector == @selector(remove)) + return @"remove"; + else + return nil; +} + ++ (BOOL) isSelectorExcludedFromWebScript:(SEL)selector { + return [self webScriptNameForSelector:selector] == nil; } + (NSArray *) _attributeKeys { return [NSArray arrayWithObjects: - @"description", @"distribution", @"host", @"key", @"label", @"name", @"origin", + @"sections", + @"shortDescription", @"trusted", @"type", @"uri", @@ -1742,6 +1440,8 @@ static void PackageImport(const void *key, const void *value, void *context) { debReleaseIndex *dindex(dynamic_cast(index)); if (dindex != NULL) { + base_.set(pool, dindex->MetaIndexURI("")); + FileFd fd; if (!fd.Open(dindex->MetaIndexFile("Release"), FileFd::ReadOnly)) _error->Discard(); @@ -1784,8 +1484,7 @@ static void PackageImport(const void *key, const void *value, void *context) { host_ = [host_ lowercaseString]; if (host_ != nil) - // XXX: this is due to a bug in _H<> - authority_ = (id) host_; + authority_ = host_; else authority_ = [url path]; } @@ -1800,7 +1499,7 @@ static void PackageImport(const void *key, const void *value, void *context) { NSDictionary *lhr = [self record]; NSDictionary *rhr = [source record]; - if (lhr != rhr) + if ((lhr == nil) != (rhr == nil)) return lhr == nil ? NSOrderedDescending : NSOrderedAscending; NSString *lhs = [self name]; @@ -1827,6 +1526,62 @@ static void PackageImport(const void *key, const void *value, void *context) { return support_.empty() ? nil : [static_cast(support_) stringByReplacingOccurrencesOfString:@"*" withString:package]; } +- (NSArray *) sections { + return record_ == nil ? (id) [NSNull null] : [record_ objectForKey:@"Sections"] ?: [NSArray array]; +} + +- (void) _addSection:(NSString *)section { + if (record_ == nil) + return; + else if (NSMutableArray *sections = [record_ objectForKey:@"Sections"]) { + if (![sections containsObject:section]) { + [sections addObject:section]; + Changed_ = true; + } + } else { + [record_ setObject:[NSMutableArray arrayWithObject:section] forKey:@"Sections"]; + Changed_ = true; + } +} + +- (bool) addSection:(NSString *)section { + if (record_ == nil) + return false; + + [self performSelectorOnMainThread:@selector(_addSection:) withObject:section waitUntilDone:NO]; + return true; +} + +- (void) _removeSection:(NSString *)section { + if (record_ == nil) + return; + + if (NSMutableArray *sections = [record_ objectForKey:@"Sections"]) + if ([sections containsObject:section]) { + [sections removeObject:section]; + Changed_ = true; + } +} + +- (bool) removeSection:(NSString *)section { + if (record_ == nil) + return false; + + [self performSelectorOnMainThread:@selector(_removeSection:) withObject:section waitUntilDone:NO]; + return true; +} + +- (void) _remove { + [Sources_ removeObjectForKey:[self key]]; + Changed_ = true; +} + +- (bool) remove { + bool value(record_ != nil); + [self performSelectorOnMainThread:@selector(_remove) withObject:nil waitUntilDone:NO]; + return value; +} + - (NSDictionary *) record { return record_; } @@ -1847,6 +1602,10 @@ static void PackageImport(const void *key, const void *value, void *context) { return type_; } +- (NSString *) base { + return base_; +} + - (NSString *) key { return [NSString stringWithFormat:@"%@:%@:%@", (NSString *) type_, (NSString *) uri_, (NSString *) distribution_]; } @@ -1859,7 +1618,7 @@ static void PackageImport(const void *key, const void *value, void *context) { return origin_.empty() ? (id) authority_ : origin_; } -- (NSString *) description { +- (NSString *) shortDescription { return description_; } @@ -1883,8 +1642,8 @@ static void PackageImport(const void *key, const void *value, void *context) { /* }}} */ /* CydiaOperation Class {{{ */ @interface CydiaOperation : NSObject { - NSString *operator_; - NSString *value_; + _H operator_; + _H value_; } - (NSString *) operator; @@ -1894,16 +1653,10 @@ static void PackageImport(const void *key, const void *value, void *context) { @implementation CydiaOperation -- (void) dealloc { - [operator_ release]; - [value_ release]; - [super dealloc]; -} - - (id) initWithOperator:(const char *)_operator value:(const char *)value { if ((self = [super init]) != nil) { - operator_ = [[NSString alloc] initWithUTF8String:_operator]; - value_ = [[NSString alloc] initWithUTF8String:value]; + operator_ = [NSString stringWithUTF8String:_operator]; + value_ = [NSString stringWithUTF8String:value]; } return self; } @@ -1934,8 +1687,8 @@ static void PackageImport(const void *key, const void *value, void *context) { /* }}} */ /* CydiaClause Class {{{ */ @interface CydiaClause : NSObject { - NSString *package_; - CydiaOperation *version_; + _H package_; + _H version_; } - (NSString *) package; @@ -1945,20 +1698,14 @@ static void PackageImport(const void *key, const void *value, void *context) { @implementation CydiaClause -- (void) dealloc { - [package_ release]; - [version_ release]; - [super dealloc]; -} - - (id) initWithIterator:(pkgCache::DepIterator &)dep { if ((self = [super init]) != nil) { - package_ = [[NSString alloc] initWithUTF8String:dep.TargetPkg().Name()]; + package_ = [NSString stringWithUTF8String:dep.TargetPkg().Name()]; if (const char *version = dep.TargetVer()) - version_ = [[CydiaOperation alloc] initWithOperator:dep.CompType() value:version]; + version_ = [[[CydiaOperation alloc] initWithOperator:dep.CompType() value:version] autorelease]; else - version_ = [[NSNull null] retain]; + version_ = (id) [NSNull null]; } return self; } @@ -1989,8 +1736,8 @@ static void PackageImport(const void *key, const void *value, void *context) { /* }}} */ /* CydiaRelation Class {{{ */ @interface CydiaRelation : NSObject { - NSString *relationship_; - NSMutableArray *clauses_; + _H relationship_; + _H clauses_; } - (NSString *) relationship; @@ -2000,16 +1747,10 @@ static void PackageImport(const void *key, const void *value, void *context) { @implementation CydiaRelation -- (void) dealloc { - [relationship_ release]; - [clauses_ release]; - [super dealloc]; -} - - (id) initWithIterator:(pkgCache::DepIterator &)dep { if ((self = [super init]) != nil) { - relationship_ = [[NSString alloc] initWithUTF8String:dep.DepType()]; - clauses_ = [[NSMutableArray alloc] initWithCapacity:8]; + relationship_ = [NSString stringWithUTF8String:dep.DepType()]; + clauses_ = [NSMutableArray arrayWithCapacity:8]; pkgCache::DepIterator start; pkgCache::DepIterator end; @@ -2059,6 +1800,7 @@ static void PackageImport(const void *key, const void *value, void *context) { struct ParsedPackage { CYString tagline_; + CYString architecture_; CYString icon_; CYString depiction_; @@ -2080,6 +1822,8 @@ struct ParsedPackage { apr_pool_t *pool_; + uint32_t rank_; + _transient Database *database_; pkgCache::VerIterator version_; @@ -2095,12 +1839,12 @@ struct ParsedPackage { const char *section_; _transient NSString *section$_; - Source *source_; + _H source_; PackageValue *metadata_; ParsedPackage *parsed_; - NSMutableArray *tags_; + _H tags_; } - (Package *) initWithVersion:(pkgCache::VerIterator)version withZone:(NSZone *)zone inPool:(apr_pool_t *)pool database:(Database *)database; @@ -2117,7 +1861,7 @@ struct ParsedPackage { - (NSString *) uri; -- (Address *) maintainer; +- (MIMEAddress *) maintainer; - (size_t) size; - (NSString *) longDescription; - (NSString *) shortDescription; @@ -2153,7 +1897,7 @@ struct ParsedPackage { - (UIImage *) icon; - (NSString *) homepage; - (NSString *) depiction; -- (Address *) author; +- (MIMEAddress *) author; - (NSString *) support; @@ -2163,7 +1907,8 @@ struct ParsedPackage { - (Source *) source; -- (BOOL) matches:(NSString *)text; +- (uint32_t) rank; +- (BOOL) matches:(NSArray *)query; - (bool) hasSupportingRole; - (BOOL) hasTag:(NSString *)tag; @@ -2180,7 +1925,7 @@ struct ParsedPackage { - (void) install; - (void) remove; -- (bool) isUnfilteredAndSearchedForBy:(NSString *)search; +- (bool) isUnfilteredAndSearchedForBy:(NSArray *)query; - (bool) isUnfilteredAndSelectedForBy:(NSString *)search; - (bool) isInstalledAndUnfiltered:(NSNumber *)number; - (bool) isVisibleInSection:(NSString *)section; @@ -2322,10 +2067,6 @@ struct PackageNameOrdering : - (void) dealloc { if (parsed_ != NULL) delete parsed_; - if (source_ != nil) - [source_ release]; - if (tags_ != nil) - [tags_ release]; [super dealloc]; } @@ -2352,6 +2093,7 @@ struct PackageNameOrdering : + (NSArray *) _attributeKeys { return [NSArray arrayWithObjects: @"applications", + @"architecture", @"author", @"depiction", @"essential", @@ -2398,6 +2140,12 @@ struct PackageNameOrdering : return relations; } } +- (NSString *) architecture { + [self parse]; +@synchronized (database_) { + return parsed_->architecture_.empty() ? [NSNull null] : (id) parsed_->architecture_; +} } + - (NSString *) getField:(NSString *)name { @synchronized (database_) { if ([database_ era] != era_ || file_.end()) @@ -2436,6 +2184,7 @@ struct PackageNameOrdering : const char *name_; CYString *value_; } names[] = { + {"architecture", &parsed->architecture_}, {"icon", &parsed->icon_}, {"depiction", &parsed->depiction_}, {"homepage", &parsed->homepage_}, @@ -2514,7 +2263,7 @@ struct PackageNameOrdering : _profile(Package$initWithVersion$Tags) pkgCache::TagIterator tag(iterator.TagList()); if (!tag.end()) { - tags_ = [[NSMutableArray alloc] initWithCapacity:8]; + tags_ = [NSMutableArray arrayWithCapacity:8]; do { const char *name(tag.Name()); [tags_ addObject:[(NSString *)CYStringCreate(name) autorelease]]; @@ -2663,14 +2412,14 @@ struct PackageNameOrdering : #endif } -- (Address *) maintainer { +- (MIMEAddress *) maintainer { @synchronized (database_) { if ([database_ era] != era_ || file_.end()) return nil; pkgRecords::Parser *parser = &[database_ records]->Lookup(file_); const std::string &maintainer(parser->Maintainer()); - return maintainer.empty() ? nil : [Address addressWithString:[NSString stringWithUTF8String:maintainer.c_str()]]; + return maintainer.empty() ? nil : [MIMEAddress addressWithString:[NSString stringWithUTF8String:maintainer.c_str()]]; } } - (size_t) size { @@ -2704,8 +2453,29 @@ struct PackageNameOrdering : } } - (NSString *) shortDescription { - return parsed_ == NULL ? nil : static_cast(parsed_->tagline_); -} + if (parsed_ != NULL) + return static_cast(parsed_->tagline_); + +@synchronized (database_) { + pkgRecords::Parser &parser([database_ records]->Lookup(file_)); + + const char *start, *end; + if (!parser.ShortDesc(start, end)) + return nil; + + if (end - start > 200) + end = start + 200; + + /* + if (const char *stop = reinterpret_cast(memchr(start, '\n', end - start))) + end = stop; + + while (end != start && end[-1] == '\r') + --end; + */ + + return [(id) CYStringCreate(start, end - start) autorelease]; +} } - (unichar) index { _profile(Package$index) @@ -2877,14 +2647,12 @@ struct PackageNameOrdering : if (parsed_ != NULL) if (NSString *href = parsed_->icon_) if ([href hasPrefix:@"file:///"]) - // XXX: correct escaping - icon = [UIImage imageAtPath:[href substringFromIndex:7]]; + icon = [UIImage imageAtPath:[[href substringFromIndex:7] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; if (icon == nil) if (section != nil) - icon = [UIImage imageAtPath:[NSString stringWithFormat:@"%@/Sections/%@.png", App_, section]]; + icon = [UIImage imageAtPath:[NSString stringWithFormat:@"%@/Sections/%@.png", App_, [section stringByReplacingOccurrencesOfString:@" " withString:@"_"]]]; if (icon == nil) if (Source *source = [self source]) if (NSString *dicon = [source defaultIcon]) if ([dicon hasPrefix:@"file:///"]) - // XXX: correct escaping - icon = [UIImage imageAtPath:[dicon substringFromIndex:7]]; + icon = [UIImage imageAtPath:[[dicon substringFromIndex:7] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; if (icon == nil) icon = [UIImage applicationImageNamed:@"unknown.png"]; return icon; @@ -2898,12 +2666,12 @@ struct PackageNameOrdering : return parsed_ != NULL && !parsed_->depiction_.empty() ? parsed_->depiction_ : [[self source] depictionForPackage:id_]; } -- (Address *) sponsor { - return parsed_ == NULL || parsed_->sponsor_.empty() ? nil : [Address addressWithString:parsed_->sponsor_]; +- (MIMEAddress *) sponsor { + return parsed_ == NULL || parsed_->sponsor_.empty() ? nil : [MIMEAddress addressWithString:parsed_->sponsor_]; } -- (Address *) author { - return parsed_ == NULL || parsed_->author_.empty() ? nil : [Address addressWithString:parsed_->author_]; +- (MIMEAddress *) author { + return parsed_ == NULL || parsed_->author_.empty() ? nil : [MIMEAddress addressWithString:parsed_->author_]; } - (NSString *) support { @@ -3064,34 +2832,58 @@ struct PackageNameOrdering : if ([database_ era] != era_ || file_.end()) source_ = (Source *) [NSNull null]; else - source_ = [([database_ getSource:file_.File()] ?: (Source *) [NSNull null]) retain]; + source_ = [database_ getSource:file_.File()] ?: (Source *) [NSNull null]; } } return source_ == (Source *) [NSNull null] ? nil : source_; } -- (BOOL) matches:(NSString *)text { - if (text == nil) +- (uint32_t) rank { + return rank_; +} + +- (BOOL) matches:(NSArray *)query { + if (query == nil || [query count] == 0) return NO; + rank_ = 0; + + NSString *string; NSRange range; + NSUInteger length; - range = [[self id] rangeOfString:text options:MatchCompareOptions_]; - if (range.location != NSNotFound) - return YES; + string = [self name]; + length = [string length]; - range = [[self name] rangeOfString:text options:MatchCompareOptions_]; - if (range.location != NSNotFound) - return YES; + for (NSString *term in query) { + range = [string rangeOfString:term options:MatchCompareOptions_]; + if (range.location != NSNotFound) + rank_ -= 6 * 1000000 / length; + } - [self parse]; + if (rank_ == 0) { + string = [self id]; + length = [string length]; - range = [[self shortDescription] rangeOfString:text options:MatchCompareOptions_]; - if (range.location != NSNotFound) - return YES; + for (NSString *term in query) { + range = [string rangeOfString:term options:MatchCompareOptions_]; + if (range.location != NSNotFound) + rank_ -= 6 * 1000000 / length; + } + } - return NO; + string = [self shortDescription]; + length = [string length]; + NSUInteger stop(std::min(length, 200)); + + for (NSString *term in query) { + range = [string rangeOfString:term options:MatchCompareOptions_ range:NSMakeRange(0, stop)]; + if (range.location != NSNotFound) + rank_ -= 2 * 100000; + } + + return rank_ != 0; } - (bool) hasSupportingRole { @@ -3121,7 +2913,7 @@ struct PackageNameOrdering : } - (NSString *) primaryPurpose { - for (NSString *tag in tags_) + for (NSString *tag in (NSArray *) tags_) if ([tag hasPrefix:@"purpose::"]) return [tag substringFromIndex:9]; return nil; @@ -3129,7 +2921,7 @@ struct PackageNameOrdering : - (NSArray *) purposes { NSMutableArray *purposes([NSMutableArray arrayWithCapacity:2]); - for (NSString *tag in tags_) + for (NSString *tag in (NSArray *) tags_) if ([tag hasPrefix:@"purpose::"]) [purposes addObject:[tag substringFromIndex:9]]; return [purposes count] == 0 ? nil : purposes; @@ -3195,7 +2987,7 @@ struct PackageNameOrdering : cache->MarkDelete(iterator_, true); } } -- (bool) isUnfilteredAndSearchedForBy:(NSString *)search { +- (bool) isUnfilteredAndSearchedForBy:(NSArray *)query { _profile(Package$isUnfilteredAndSearchedForBy) bool value(true); @@ -3204,7 +2996,7 @@ struct PackageNameOrdering : _end _profile(Package$isUnfilteredAndSearchedForBy$Match) - value &= [self matches:search]; + value &= [self matches:query]; _end return value; @@ -3252,11 +3044,11 @@ struct PackageNameOrdering : /* }}} */ /* Section Class {{{ */ @interface Section : NSObject { - NSString *name_; + _H name_; unichar index_; size_t row_; size_t count_; - NSString *localized_; + _H localized_; } - (NSComparisonResult) compareByLocalized:(Section *)section; @@ -3280,13 +3072,6 @@ struct PackageNameOrdering : @implementation Section -- (void) dealloc { - [name_ release]; - if (localized_ != nil) - [localized_ release]; - [super dealloc]; -} - - (NSComparisonResult) compareByLocalized:(Section *)section { NSString *lhs(localized_); NSString *rhs([section localized]); @@ -3307,7 +3092,7 @@ struct PackageNameOrdering : - (Section *) initWithName:(NSString *)name localized:(NSString *)localized { if ((self = [self initWithName:name localize:NO]) != nil) { if (localized != nil) - localized_ = [localized retain]; + localized_ = localized; } return self; } @@ -3317,18 +3102,18 @@ struct PackageNameOrdering : - (Section *) initWithName:(NSString *)name row:(size_t)row localize:(BOOL)localize { if ((self = [super init]) != nil) { - name_ = [name retain]; + name_ = name; index_ = '\0'; row_ = row; if (localize) - localized_ = [LocalizeSection(name_) retain]; + localized_ = LocalizeSection(name_); } return self; } /* XXX: localize the index thingees */ - (Section *) initWithIndex:(unichar)index row:(size_t)row { if ((self = [super init]) != nil) { - name_ = [[NSString stringWithCharacters:&index length:1] retain]; + name_ = [NSString stringWithCharacters:&index length:1]; index_ = index; row_ = row; } return self; @@ -3369,18 +3154,22 @@ struct PackageNameOrdering : @end /* }}} */ -static NSString *Colon_; -static NSString *Elision_; -static NSString *Error_; -static NSString *Warning_; +class CydiaLogCleaner : + public pkgArchiveCleaner +{ + protected: + virtual void Erase(const char *File, std::string Pkg, std::string Ver, struct stat &St) { + unlink(File); + } +}; /* Database Implementation {{{ */ @implementation Database + (Database *) sharedInstance { - static Database *instance; + static _H instance; if (instance == nil) - instance = [[Database alloc] init]; + instance = [[[Database alloc] init] autorelease]; return instance; } @@ -3396,14 +3185,13 @@ static NSString *Warning_; - (void) dealloc { // XXX: actually implement this thing _assert(false); - [sourceList_ release]; [self releasePackages]; apr_pool_destroy(pool_); NSRecycleZone(zone_); [super dealloc]; } -- (void) _readCydia:(NSNumber *)fd { _pooled +- (void) _readCydia:(NSNumber *)fd { __gnu_cxx::stdio_filebuf ib([fd intValue], std::ios::in); std::istream is(&ib); std::string line; @@ -3411,6 +3199,8 @@ static NSString *Warning_; static Pcre finish_r("^finish:([^:]*)$"); while (std::getline(is, line)) { + NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]); + const char *data(line.c_str()); size_t size = line.size(); lprintf("C:%s\n", data); @@ -3421,12 +3211,14 @@ static NSString *Warning_; if (index != INT_MAX && index > Finish_) Finish_ = index; } + + [pool release]; } _assume(false); } -- (void) _readStatus:(NSNumber *)fd { _pooled +- (void) _readStatus:(NSNumber *)fd { __gnu_cxx::stdio_filebuf ib([fd intValue], std::ios::in); std::istream is(&ib); std::string line; @@ -3435,6 +3227,8 @@ static NSString *Warning_; static Pcre pmstatus_r("^([^:]*):([^:]*):([^:]*):(.*)$"); while (std::getline(is, line)) { + NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]); + const char *data(line.c_str()); size_t size(line.size()); lprintf("S:%s\n", data); @@ -3474,21 +3268,27 @@ static NSString *Warning_; lprintf("E:unknown pmstatus\n"); } else lprintf("E:unknown status\n"); + + [pool release]; } _assume(false); } -- (void) _readOutput:(NSNumber *)fd { _pooled +- (void) _readOutput:(NSNumber *)fd { __gnu_cxx::stdio_filebuf ib([fd intValue], std::ios::in); std::istream is(&ib); std::string line; while (std::getline(is, line)) { + NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]); + lprintf("O:%s\n", line.c_str()); CydiaProgressEvent *event([CydiaProgressEvent eventWithMessage:[NSString stringWithUTF8String:line.c_str()] ofType:kCydiaProgressEventTypeInformation]); [progress_ performSelectorOnMainThread:@selector(addProgressEvent:) withObject:event waitUntilDone:YES]; + + [pool release]; } _assume(false); @@ -3499,6 +3299,8 @@ static NSString *Warning_; } - (Package *) packageWithName:(NSString *)name { + if (name == nil) + return nil; @synchronized (self) { if (static_cast(cache_) == NULL) return nil; @@ -3524,7 +3326,7 @@ static NSString *Warning_; capacity += 1024; packages_ = CFArrayCreateMutable(kCFAllocatorDefault, capacity, NULL); - sourceList_ = [[NSMutableArray alloc] initWithCapacity:16]; + sourceList_ = [NSMutableArray arrayWithCapacity:16]; int fds[2]; @@ -3634,7 +3436,7 @@ static NSString *Warning_; return [self popErrorWithTitle:title] || !success; } -- (void) reloadDataWithInvocation:(NSInvocation *)invocation { CYPoolStart() { +- (void) reloadDataWithInvocation:(NSInvocation *)invocation { @synchronized (self) { ++era_; @@ -3753,7 +3555,6 @@ static NSString *Warning_; { /*std::vector packages; packages.reserve(std::max(10000U, [packages_ count] + 1000)); - [packages_ release]; packages_ = nil;*/ _trace(); @@ -3761,7 +3562,7 @@ static NSString *Warning_; for (pkgCache::PkgIterator iterator = cache_->PkgBegin(); !iterator.end(); ++iterator) if (Package *package = [Package packageWithIterator:iterator withZone:zone_ inPool:pool_ database:self]) //packages.push_back(package); - CFArrayAppendValue(packages_, [package retain]); + CFArrayAppendValue(packages_, CFRetain(package)); _trace(); @@ -3771,9 +3572,9 @@ static NSString *Warning_; packages_ = [[NSArray alloc] initWithObjects:&packages.front() count:packages.size()]; _trace();*/ - [(NSMutableArray *) packages_ radixSortUsingFunction:reinterpret_cast(&PackagePrefixRadix) withContext:reinterpret_cast(16)]; - [(NSMutableArray *) packages_ radixSortUsingFunction:reinterpret_cast(&PackagePrefixRadix) withContext:reinterpret_cast(4)]; - [(NSMutableArray *) packages_ radixSortUsingFunction:reinterpret_cast(&PackagePrefixRadix) withContext:reinterpret_cast(0)]; + [(NSMutableArray *) packages_ radixSortUsingFunction:reinterpret_cast(&PackagePrefixRadix) withContext:reinterpret_cast(16)]; + [(NSMutableArray *) packages_ radixSortUsingFunction:reinterpret_cast(&PackagePrefixRadix) withContext:reinterpret_cast(4)]; + [(NSMutableArray *) packages_ radixSortUsingFunction:reinterpret_cast(&PackagePrefixRadix) withContext:reinterpret_cast(0)]; /*_trace(); PrintTimes(); @@ -3801,7 +3602,7 @@ static NSString *Warning_; _trace(); } -} } CYPoolEnd() _trace(); } +} } - (void) clear { @synchronized (self) { @@ -3838,15 +3639,7 @@ static NSString *Warning_; pkgAcquire fetcher; fetcher.Clean(_config->FindDir("Dir::Cache::Archives")); - class LogCleaner : - public pkgArchiveCleaner - { - protected: - virtual void Erase(const char *File, std::string Pkg, std::string Ver, struct stat &St) { - unlink(File); - } - } cleaner; - + CydiaLogCleaner cleaner; if ([self popErrorWithTitle:title forOperation:cleaner.Go(_config->FindDir("Dir::Cache::Archives") + "partial/", cache_)]) return false; @@ -3977,13 +3770,13 @@ static NSString *Warning_; bool success(ListUpdate(status, list, PulseInterval_)); if (status.WasCancelled()) _error->Discard(); - else + else { [self popErrorWithTitle:title forOperation:success]; + [Metadata_ setObject:[NSDate date] forKey:@"LastUpdate"]; + Changed_ = true; + } [delegate_ performSelectorOnMainThread:@selector(releaseNetworkActivityIndicator) withObject:nil waitUntilDone:YES]; - - [Metadata_ setObject:[NSDate date] forKey:@"LastUpdate"]; - Changed_ = true; } - (void) setDelegate:(NSObject *)delegate { @@ -4038,9 +3831,62 @@ static NSString *Warning_; @end /* }}} */ -/* Web Scripting {{{ */ +static _H Diversions_; + +@interface Diversion : NSObject { + Pcre pattern_; + _H key_; + _H format_; +} + +@end + +@implementation Diversion + +- (id) initWithFrom:(NSString *)from to:(NSString *)to { + if ((self = [super init]) != nil) { + pattern_ = [from UTF8String]; + key_ = from; + format_ = to; + } return self; +} + +- (NSString *) divert:(NSString *)url { + return !pattern_(url) ? nil : pattern_->*format_; +} + ++ (NSURL *) divertURL:(NSURL *)url { + divert: + NSString *href([url absoluteString]); + + for (Diversion *diversion in (id) Diversions_) + if (NSString *diverted = [diversion divert:href]) { +#if !ForRelease + NSLog(@"div: %@", diverted); +#endif + url = [NSURL URLWithString:diverted]; + goto divert; + } + + return url; +} + +- (NSString *) key { + return key_; +} + +- (NSUInteger) hash { + return [key_ hash]; +} + +- (BOOL) isEqual:(Diversion *)object { + return self == object || [self class] == [object class] && [key_ isEqual:[object key]]; +} + +@end + @interface CydiaObject : NSObject { - id indirect_; + _H indirect_; _transient id delegate_; } @@ -4048,16 +3894,20 @@ static NSString *Warning_; @end -@implementation CydiaObject - -- (void) dealloc { - [indirect_ release]; - [super dealloc]; +@interface CydiaWebViewController : CyteWebViewController { + _H cydia_; } ++ (void) addDiversion:(Diversion *)diversion; + +@end + +/* Web Scripting {{{ */ +@implementation CydiaObject + - (id) initWithDelegate:(IndirectDelegate *)indirect { if ((self = [super init]) != nil) { - indirect_ = [indirect retain]; + indirect_ = indirect; } return self; } @@ -4067,6 +3917,8 @@ static NSString *Warning_; + (NSArray *) _attributeKeys { return [NSArray arrayWithObjects: + @"bbsnum", + @"cydiaSource", @"device", @"ecid", @"firmware", @@ -4113,6 +3965,10 @@ static NSString *Warning_; return (id) PLMN_ ?: [NSNull null]; } +- (NSString *) bbsnum { + return (id) BBSNum_ ?: [NSNull null]; +} + - (NSString *) ecid { return (id) ChipID_ ?: [NSNull null]; } @@ -4135,8 +3991,18 @@ static NSString *Warning_; + (NSString *) webScriptNameForSelector:(SEL)selector { if (false); - else if (selector == @selector(addCydiaHost:)) - return @"addCydiaHost"; + else if (selector == @selector(addBridgedHost:)) + return @"addBridgedHost"; + else if (selector == @selector(addInsecureHost:)) + return @"addInsecureHost"; + else if (selector == @selector(addInternalRedirect::)) + return @"addInternalRedirect"; + else if (selector == @selector(addPipelinedHost:scheme:)) + return @"addPipelinedHost"; + else if (selector == @selector(addSource:::)) + return @"addSource"; + else if (selector == @selector(addTokenHost:)) + return @"addTokenHost"; else if (selector == @selector(addTrivialSource:)) return @"addTrivialSource"; else if (selector == @selector(close)) @@ -4153,22 +4019,46 @@ static NSString *Warning_; return @"getKernelString"; else if (selector == @selector(getInstalledPackages)) return @"getInstalledPackages"; + else if (selector == @selector(getIORegistryEntry::)) + return @"getIORegistryEntry"; + else if (selector == @selector(getLocaleIdentifier)) + return @"getLocaleIdentifier"; + else if (selector == @selector(getPreferredLanguages)) + return @"getPreferredLanguages"; else if (selector == @selector(getPackageById:)) return @"getPackageById"; + else if (selector == @selector(getMetadataKeys)) + return @"getMetadataKeys"; + else if (selector == @selector(getMetadataValue:)) + return @"getMetadataValue"; + else if (selector == @selector(getSessionValue:)) + return @"getSessionValue"; else if (selector == @selector(installPackages:)) return @"installPackages"; else if (selector == @selector(localizedStringForKey:value:table:)) return @"localize"; + else if (selector == @selector(popViewController:)) + return @"popViewController"; else if (selector == @selector(refreshSources)) return @"refreshSources"; else if (selector == @selector(removeButton)) return @"removeButton"; + else if (selector == @selector(saveConfig)) + return @"saveConfig"; + else if (selector == @selector(setCydiaSource:)) + return @"setCydiaSource"; + else if (selector == @selector(setMetadataValue::)) + return @"setMetadataValue"; + else if (selector == @selector(setSessionValue::)) + return @"setSessionValue"; else if (selector == @selector(substitutePackageNames:)) return @"substitutePackageNames"; else if (selector == @selector(scrollToBottom:)) return @"scrollToBottom"; else if (selector == @selector(setAllowsNavigationAction:)) return @"setAllowsNavigationAction"; + else if (selector == @selector(setBadgeValue:)) + return @"setBadgeValue"; else if (selector == @selector(setButtonImage:withStyle:toFunction:)) return @"setButtonImage"; else if (selector == @selector(setButtonTitle:withStyle:toFunction:)) @@ -4181,8 +4071,10 @@ static NSString *Warning_; return @"setNavigationBarStyle"; else if (selector == @selector(setNavigationBarTintRed:green:blue:alpha:)) return @"setNavigationBarTintColor"; - else if (selector == @selector(setPopupHook:)) - return @"setPopupHook"; + else if (selector == @selector(setPasteboardString:)) + return @"setPasteboardString"; + else if (selector == @selector(setPasteboardURL:)) + return @"setPasteboardURL"; else if (selector == @selector(setToken:)) return @"setToken"; else if (selector == @selector(setViewportWidth:)) @@ -4191,6 +4083,8 @@ static NSString *Warning_; return @"statfs"; else if (selector == @selector(supports:)) return @"supports"; + else if (selector == @selector(unload)) + return @"unload"; else return nil; } @@ -4203,6 +4097,14 @@ static NSString *Warning_; return [feature isEqualToString:@"window.open"]; } +- (void) unload { + [delegate_ performSelectorOnMainThread:@selector(unloadData) withObject:nil waitUntilDone:NO]; +} + +- (void) addInternalRedirect:(NSString *)from :(NSString *)to { + [CydiaWebViewController performSelectorOnMainThread:@selector(addDiversion:) withObject:[[[Diversion alloc] initWithFrom:from to:to] autorelease] waitUntilDone:NO]; +} + - (NSNumber *) getKernelNumber:(NSString *)name { const char *string([name UTF8String]); @@ -4237,8 +4139,109 @@ static NSString *Warning_; return [NSString stringWithCString:value]; } -- (void) addCydiaHost:(NSString *)host { - [delegate_ performSelectorOnMainThread:@selector(addCydiaHost:) withObject:host waitUntilDone:NO]; +- (NSObject *) getIORegistryEntry:(NSString *)path :(NSString *)entry { + NSObject *value(CYIOGetValue([path UTF8String], entry)); + + if (value != nil) + if ([value isKindOfClass:[NSData class]]) + value = CYHex((NSData *) value); + + return value; +} + +- (void) _setCydiaSource:(NSString *)source { + @synchronized (HostConfig_) { + CydiaSource_ = source; + [Metadata_ setObject:source forKey:@"CydiaSource"]; + } + + Changed_ = true; +} + +- (void) setCydiaSource:(NSString *)source { + [self performSelectorOnMainThread:@selector(_setCydiaSource:) withObject:source waitUntilDone:NO]; +} + +- (NSString *) cydiaSource { + @synchronized (HostConfig_) { + return (id) CydiaSource_ ?: [NSNull null]; + } +} + +- (NSArray *) getMetadataKeys { +@synchronized (Values_) { + return [Values_ allKeys]; +} } + +- (id) getMetadataValue:(NSString *)key { +@synchronized (Values_) { + return [Values_ objectForKey:key]; +} } + +- (void) setMetadataValue:(NSString *)key :(NSString *)value { +@synchronized (Values_) { + if (value == nil || value == (id) [WebUndefined undefined] || value == (id) [NSNull null]) + [Values_ removeObjectForKey:key]; + else + [Values_ setObject:value forKey:key]; + + [delegate_ performSelectorOnMainThread:@selector(updateValues) withObject:nil waitUntilDone:YES]; +} } + +- (id) getSessionValue:(NSString *)key { +@synchronized (SessionData_) { + return [SessionData_ objectForKey:key]; +} } + +- (void) setSessionValue:(NSString *)key :(NSString *)value { +@synchronized (SessionData_) { + if (value == (id) [WebUndefined undefined]) + [SessionData_ removeObjectForKey:key]; + else + [SessionData_ setObject:value forKey:key]; +} } + +- (void) addBridgedHost:(NSString *)host { +@synchronized (HostConfig_) { + [BridgedHosts_ addObject:host]; +} } + +- (void) addInsecureHost:(NSString *)host { +@synchronized (HostConfig_) { + [InsecureHosts_ addObject:host]; +} } + +- (void) addTokenHost:(NSString *)host { +@synchronized (HostConfig_) { + [TokenHosts_ addObject:host]; +} } + +- (void) addPipelinedHost:(NSString *)host scheme:(NSString *)scheme { +@synchronized (HostConfig_) { + if (scheme != (id) [WebUndefined undefined]) + host = [NSString stringWithFormat:@"%@:%@", [scheme lowercaseString], host]; + + [PipelinedHosts_ addObject:host]; +} } + +- (void) popViewController:(NSNumber *)value { + if (value == (id) [WebUndefined undefined]) + value = [NSNumber numberWithBool:YES]; + [indirect_ performSelectorOnMainThread:@selector(popViewControllerWithNumber:) withObject:value waitUntilDone:NO]; +} + +- (void) addSource:(NSString *)href :(NSString *)distribution :(WebScriptObject *)sections { + NSMutableArray *array([NSMutableArray arrayWithCapacity:[sections count]]); + + for (NSString *section in sections) + [array addObject:section]; + + [delegate_ performSelectorOnMainThread:@selector(addSource:) withObject:[NSMutableDictionary dictionaryWithObjectsAndKeys: + @"deb", @"Type", + href, @"URI", + distribution, @"Distribution", + array, @"Sections", + nil] waitUntilDone:NO]; } - (void) addTrivialSource:(NSString *)href { @@ -4249,6 +4252,10 @@ static NSString *Warning_; [delegate_ performSelectorOnMainThread:@selector(syncData) withObject:nil waitUntilDone:NO]; } +- (void) saveConfig { + [delegate_ performSelectorOnMainThread:@selector(_saveConfig) withObject:nil waitUntilDone:NO]; +} + - (NSArray *) getAllSources { return [[Database sharedInstance] sources]; } @@ -4272,6 +4279,14 @@ static NSString *Warning_; return (Package *) [NSNull null]; } +- (NSString *) getLocaleIdentifier { + return Locale_ == NULL ? (NSString *) [NSNull null] : (NSString *) CFLocaleGetIdentifier(Locale_); +} + +- (NSArray *) getPreferredLanguages { + return Languages_; +} + - (NSArray *) statfs:(NSString *)path { struct statfs stat; @@ -4360,6 +4375,10 @@ static NSString *Warning_; [indirect_ setButtonTitle:button withStyle:style toFunction:function]; } +- (void) setBadgeValue:(id)value { + [indirect_ performSelectorOnMainThread:@selector(setBadgeValue:) withObject:value waitUntilDone:NO]; +} + - (void) setAllowsNavigationAction:(NSString *)value { [indirect_ performSelectorOnMainThread:@selector(setAllowsNavigationActionByNumber:) withObject:value waitUntilDone:NO]; } @@ -4382,6 +4401,14 @@ static NSString *Warning_; [indirect_ performSelectorOnMainThread:@selector(setNavigationBarTintColor:) withObject:color waitUntilDone:NO]; } +- (void) setPasteboardString:(NSString *)value { + [[objc_getClass("UIPasteboard") generalPasteboard] setString:value]; +} + +- (void) setPasteboardURL:(NSString *)value { + [[objc_getClass("UIPasteboard") generalPasteboard] setURL:[NSURL URLWithString:value]]; +} + - (void) _setToken:(NSString *)token { Token_ = token; @@ -4397,10 +4424,6 @@ static NSString *Warning_; [self performSelectorOnMainThread:@selector(_setToken:) withObject:token waitUntilDone:NO]; } -- (void) setPopupHook:(id)function { - [indirect_ setPopupHook:function]; -} - - (void) scrollToBottom:(NSNumber *)animated { [indirect_ performSelectorOnMainThread:@selector(scrollToBottomAnimated:) withObject:animated waitUntilDone:NO]; } @@ -4429,165 +4452,93 @@ static NSString *Warning_; @end /* }}} */ -/* @ Loading... Indicator {{{ */ -@interface CYLoadingIndicator : UIView { - _H spinner_; - _H label_; - _H container_; -} - -@property (readonly, nonatomic) UILabel *label; -@property (readonly, nonatomic) UIActivityIndicatorView *activityIndicatorView; - +@interface NSURL (CydiaSecure) @end -@implementation CYLoadingIndicator - -- (id) initWithFrame:(CGRect)frame { - if ((self = [super initWithFrame:frame]) != nil) { - container_ = [[[UIView alloc] init] autorelease]; - [container_ setAutoresizingMask:UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin]; - - spinner_ = [[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray] autorelease]; - [spinner_ startAnimating]; - [container_ addSubview:spinner_]; - - label_ = [[[UILabel alloc] init] autorelease]; - [label_ setFont:[UIFont boldSystemFontOfSize:15.0f]]; - [label_ setBackgroundColor:[UIColor clearColor]]; - [label_ setTextColor:[UIColor blackColor]]; - [label_ setShadowColor:[UIColor whiteColor]]; - [label_ setShadowOffset:CGSizeMake(0, 1)]; - [label_ setText:[NSString stringWithFormat:Elision_, UCLocalize("LOADING"), nil]]; - [container_ addSubview:label_]; - - CGSize viewsize = frame.size; - CGSize spinnersize = [spinner_ bounds].size; - CGSize textsize = [[label_ text] sizeWithFont:[label_ font]]; - float bothwidth = spinnersize.width + textsize.width + 5.0f; - - CGRect containrect = { - CGPointMake(floorf((viewsize.width / 2) - (bothwidth / 2)), floorf((viewsize.height / 2) - (spinnersize.height / 2))), - CGSizeMake(bothwidth, spinnersize.height) - }; - CGRect textrect = { - CGPointMake(spinnersize.width + 5.0f, floorf((spinnersize.height / 2) - (textsize.height / 2))), - textsize - }; - CGRect spinrect = { - CGPointZero, - spinnersize - }; - - [container_ setFrame:containrect]; - [spinner_ setFrame:spinrect]; - [label_ setFrame:textrect]; - [self addSubview:container_]; - } return self; -} +@implementation NSURL (CydiaSecure) -- (UILabel *) label { - return label_; -} +- (bool) isCydiaSecure { + if ([[[self scheme] lowercaseString] isEqualToString:@"https"]) + return true; -- (UIActivityIndicatorView *) activityIndicatorView { - return spinner_; -} + @synchronized (HostConfig_) { + if ([InsecureHosts_ containsObject:[self host]]) + return true; + } -@end -/* }}} */ -/* Emulated Loading Controller {{{ */ -@interface CYEmulatedLoadingController : CYViewController { - _transient Database *database_; - _H indicator_; - _H tabbar_; - _H navbar_; + return false; } @end -@implementation CYEmulatedLoadingController - -- (id) initWithDatabase:(Database *)database { - if ((self = [super init]) != nil) { - database_ = database; - } return self; -} +/* Cydia Browser Controller {{{ */ +@implementation CydiaWebViewController -// XXX: factor this out somewhere -- (UIColor *) groupTableViewBackgroundColor { - UIDevice *device([UIDevice currentDevice]); - bool iPad([device respondsToSelector:@selector(userInterfaceIdiom)] && [device userInterfaceIdiom] == UIUserInterfaceIdiomPad); - return iPad ? [UIColor colorWithRed:0.821 green:0.834 blue:0.860 alpha:1] : [UIColor groupTableViewBackgroundColor]; +- (NSURL *) navigationURL { + return request_ == nil ? nil : [NSURL URLWithString:[NSString stringWithFormat:@"cydia://url/%@", [[request_ URL] absoluteString]]]; } -- (void) loadView { - [self setView:[[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease]]; - [[self view] setBackgroundColor:[self groupTableViewBackgroundColor]]; - - indicator_ = [[[CYLoadingIndicator alloc] initWithFrame:[[self view] bounds]] autorelease]; - [indicator_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; - [[self view] addSubview:indicator_]; - - tabbar_ = [[[UITabBar alloc] initWithFrame:CGRectMake(0, 0, 0, 49.0f)] autorelease]; - [tabbar_ setFrame:CGRectMake(0.0f, [[self view] bounds].size.height - [tabbar_ bounds].size.height, [[self view] bounds].size.width, [tabbar_ bounds].size.height)]; - [tabbar_ setAutoresizingMask:UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth]; - [[self view] addSubview:tabbar_]; - - navbar_ = [[[UINavigationBar alloc] initWithFrame:CGRectMake(0, 0, 0, 44.0f)] autorelease]; - [navbar_ setFrame:CGRectMake(0.0f, 0.0f, [[self view] bounds].size.width, [navbar_ bounds].size.height)]; - [navbar_ setAutoresizingMask:UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleWidth]; - [[self view] addSubview:navbar_]; ++ (void) initialize { + Diversions_ = [NSMutableSet setWithCapacity:0]; } -- (void) releaseSubviews { - indicator_ = nil; - tabbar_ = nil; - navbar_ = nil; ++ (void) addDiversion:(Diversion *)diversion { + [Diversions_ addObject:diversion]; } -@end -/* }}} */ - -/* Cydia Browser Controller {{{ */ -@interface CYBrowserController : BrowserController { - CydiaObject *cydia_; -} +- (void) webView:(WebView *)view didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame { + [super webView:view didClearWindowObject:window forFrame:frame]; -@end + WebDataSource *source([frame dataSource]); + NSURLResponse *response([source response]); + NSURL *url([response URL]); + NSString *scheme([[url scheme] lowercaseString]); -@implementation CYBrowserController + bool bridged(false); -- (void) dealloc { - [cydia_ release]; - [super dealloc]; -} + @synchronized (HostConfig_) { + if ([scheme isEqualToString:@"file"]) + bridged = true; + else if ([scheme isEqualToString:@"https"]) + if ([BridgedHosts_ containsObject:[url host]]) + bridged = true; + } -- (NSURL *) navigationURL { - return [NSURL URLWithString:[NSString stringWithFormat:@"cydia://url/%@", [[[webview_ request] URL] absoluteString]]]; + if (bridged) + [window setValue:cydia_ forKey:@"cydia"]; } -- (void) webView:(WebView *)view didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame { - [super webView:view didClearWindowObject:window forFrame:frame]; +- (void) _setupMail:(MFMailComposeViewController *)controller { + [controller addAttachmentData:[NSData dataWithContentsOfFile:@"/tmp/cydia.log"] mimeType:@"text/plain" fileName:@"cydia.log"]; - WebDataSource *source([frame dataSource]); - NSURLResponse *response([source response]); - NSURL *url([response URL]); + system("/usr/bin/dpkg -l >/tmp/dpkgl.log"); + [controller addAttachmentData:[NSData dataWithContentsOfFile:@"/tmp/dpkgl.log"] mimeType:@"text/plain" fileName:@"dpkgl.log"]; +} - if ([[[url scheme] lowercaseString] isEqualToString:@"https"]) - if ([CydiaHosts_ containsObject:[url host]]) - [window setValue:cydia_ forKey:@"cydia"]; +- (NSURL *) URLWithURL:(NSURL *)url { + return [Diversion divertURL:url]; } - (NSURLRequest *) webView:(WebView *)view resource:(id)resource willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response fromDataSource:(WebDataSource *)source { + NSURL *url([request URL]); + NSString *host([url host]); + NSMutableURLRequest *copy([[super webView:view resource:resource willSendRequest:request redirectResponse:response fromDataSource:source] mutableCopy]); - if (System_ != NULL) + if (System_ != NULL && [copy valueForHTTPHeaderField:@"X-System"] == nil) [copy setValue:System_ forHTTPHeaderField:@"X-System"]; - if (Machine_ != NULL) + if (Machine_ != NULL && [copy valueForHTTPHeaderField:@"X-Machine"] == nil) [copy setValue:[NSString stringWithUTF8String:Machine_] forHTTPHeaderField:@"X-Machine"]; - if (Token_ != nil) - [copy setValue:Token_ forHTTPHeaderField:@"X-Cydia-Token"]; + + bool token; + @synchronized (HostConfig_) { + token = [TokenHosts_ containsObject:host] || [BridgedHosts_ containsObject:host]; + } + + if ([url isCydiaSecure] && token) { + if (Token_ != nil && [copy valueForHTTPHeaderField:@"X-Cydia-Token"] == nil) + [copy setValue:Token_ forHTTPHeaderField:@"X-Cydia-Token"]; + } return copy; } @@ -4597,23 +4548,35 @@ static NSString *Warning_; [cydia_ setDelegate:delegate]; } -- (id) init { - if ((self = [super initWithWidth:0 ofClass:[CYBrowserController class]]) != nil) { - cydia_ = [[CydiaObject alloc] initWithDelegate:indirect_]; +- (NSString *) applicationNameForUserAgent { + NSString *application([NSString stringWithFormat:@"Cydia/%@", @ Cydia_]); + + if (Safari_ != nil) + application = [NSString stringWithFormat:@"Safari/%@ %@", Safari_, application]; + if (Build_ != nil) + application = [NSString stringWithFormat:@"Mobile/%@ %@", Build_, application]; + if (Product_ != nil) + application = [NSString stringWithFormat:@"Version/%@ %@", Product_, application]; + + return application; +} + +- (id) init { + if ((self = [super initWithWidth:0 ofClass:[CydiaWebViewController class]]) != nil) { + cydia_ = [[[CydiaObject alloc] initWithDelegate:indirect_] autorelease]; + } return self; +} + +@end - WebView *webview([[webview_ _documentView] webView]); +@interface AppCacheController : CydiaWebViewController { +} - NSString *application([NSString stringWithFormat:@"Cydia/%@", @ Cydia_]); +@end - if (Safari_ != nil) - application = [NSString stringWithFormat:@"Safari/%@ %@", Safari_, application]; - if (Build_ != nil) - application = [NSString stringWithFormat:@"Mobile/%@ %@", Build_, application]; - if (Product_ != nil) - application = [NSString stringWithFormat:@"Version/%@ %@", Product_, application]; +@implementation AppCacheController - [webview setApplicationNameForUserAgent:application]; - } return self; +- (void) didReceiveMemoryWarning { } @end @@ -4677,14 +4640,14 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (void) queue; @end -@interface ConfirmationController : CYBrowserController { +@interface ConfirmationController : CydiaWebViewController { _transient Database *database_; - UIAlertView *essential_; + _H essential_; - NSDictionary *changes_; - NSMutableArray *issues_; - NSDictionary *sizes_; + _H changes_; + _H issues_; + _H sizes_; BOOL substrate_; } @@ -4695,17 +4658,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { @implementation ConfirmationController -- (void) dealloc { - [changes_ release]; - [issues_ release]; - [sizes_ release]; - - if (essential_ != nil) - [essential_ release]; - - [super dealloc]; -} - - (void) complete { if (substrate_) RestartSubstrate_ = true; @@ -4732,8 +4684,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) _doContinue { - [self dismissModalViewControllerAnimated:YES]; [delegate_ cancelAndClear:NO]; + [self dismissModalViewControllerAnimated:YES]; } - (id) invokeDefaultMethodWithArguments:(NSArray *)args { @@ -4745,9 +4697,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [super webView:view didClearWindowObject:window forFrame:frame]; [window setValue:[[NSDictionary dictionaryWithObjectsAndKeys: - changes_, @"changes", - issues_, @"issues", - sizes_, @"sizes", + (id) changes_, @"changes", + (id) issues_, @"issues", + (id) sizes_, @"sizes", self, @"queue", nil] Cydia$webScriptObjectInContext:window] forKey:@"cydiaConfirm"]; } @@ -4768,7 +4720,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { NSArray *packages([database_ packages]); pkgDepCache::Policy *policy([database_ policy]); - issues_ = [[NSMutableArray arrayWithCapacity:4] retain]; + issues_ = [NSMutableArray arrayWithCapacity:4]; for (Package *package in packages) { pkgCache::PkgIterator iterator([package iterator]); @@ -4848,13 +4800,16 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { if (state.NewInstall()) [installs addObject:name]; + // XXX: else if (state.Install()) else if (!state.Delete() && (state.iFlags & pkgDepCache::ReInstall) == pkgDepCache::ReInstall) [reinstalls addObject:name]; + // XXX: move before previous if else if (state.Upgrade()) [upgrades addObject:name]; else if (state.Downgrade()) [downgrades addObject:name]; else if (!state.Delete()) + // XXX: _assert(state.Keep()); continue; else if (special_r(name)) [issues_ addObject:[NSDictionary dictionaryWithObjectsAndKeys: @@ -4887,7 +4842,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { else if (Advanced_) { NSString *parenthetical(UCLocalize("PARENTHETICAL")); - essential_ = [[UIAlertView alloc] + essential_ = [[[UIAlertView alloc] initWithTitle:UCLocalize("REMOVING_ESSENTIALS") message:UCLocalize("REMOVING_ESSENTIALS_EX") delegate:self @@ -4895,22 +4850,22 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { otherButtonTitles: [NSString stringWithFormat:parenthetical, UCLocalize("FORCE_REMOVAL"), UCLocalize("UNSAFE")], nil - ]; + ] autorelease]; [essential_ setContext:@"remove"]; } else { - essential_ = [[UIAlertView alloc] + essential_ = [[[UIAlertView alloc] initWithTitle:UCLocalize("UNABLE_TO_COMPLY") message:UCLocalize("UNABLE_TO_COMPLY_EX") delegate:self cancelButtonTitle:UCLocalize("OKAY") otherButtonTitles:nil - ]; + ] autorelease]; [essential_ setContext:@"unable"]; } - changes_ = [[NSDictionary alloc] initWithObjectsAndKeys: + changes_ = [NSDictionary dictionaryWithObjectsAndKeys: installs, @"installs", reinstalls, @"reinstalls", upgrades, @"upgrades", @@ -4918,22 +4873,24 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { removes, @"removes", nil]; - sizes_ = [[NSDictionary alloc] initWithObjectsAndKeys: + sizes_ = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithInteger:[database_ fetcher].FetchNeeded()], @"downloading", [NSNumber numberWithInteger:[database_ fetcher].PartialPresent()], @"resuming", nil]; [self setURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/#!/confirm/", UI_]]]; - - [[self navigationItem] setLeftBarButtonItem:[[[UIBarButtonItem alloc] - initWithTitle:UCLocalize("CANCEL") - style:UIBarButtonItemStylePlain - target:self - action:@selector(cancelButtonClicked) - ] autorelease]]; } return self; } +- (UIBarButtonItem *) leftButton { + return [[[UIBarButtonItem alloc] + initWithTitle:UCLocalize("CANCEL") + style:UIBarButtonItemStylePlain + target:self + action:@selector(cancelButtonClicked) + ] autorelease]; +} + #if !AlwaysReload - (void) applyRightButton { if ([issues_ count] == 0 && ![self isLoading]) @@ -5089,11 +5046,11 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { @end /* }}} */ /* Progress Controller {{{ */ -@interface ProgressController : CYBrowserController < +@interface ProgressController : CydiaWebViewController < ProgressDelegate > { _transient Database *database_; - _H progress_; + _H progress_; unsigned cancel_; } @@ -5110,17 +5067,20 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (void) dealloc { [database_ setProgressDelegate:nil]; - [progress_ setDelegate:nil]; [super dealloc]; } -- (void) updateCancel { - [[self navigationItem] setLeftBarButtonItem:(cancel_ == 1 ? [[[UIBarButtonItem alloc] +- (UIBarButtonItem *) leftButton { + return cancel_ == 1 ? [[[UIBarButtonItem alloc] initWithTitle:UCLocalize("CANCEL") style:UIBarButtonItemStylePlain target:self action:@selector(cancel) - ] autorelease] : nil)]; + ] autorelease] : nil; +} + +- (void) updateCancel { + [super applyLeftButton]; } - (id) initWithDatabase:(Database *)database delegate:(id)delegate { @@ -5153,17 +5113,19 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) viewWillAppear:(BOOL)animated { - if (![self hasLoaded]) - [[[self navigationController] navigationBar] setBarStyle:UIBarStyleBlack]; - + [[[self navigationController] navigationBar] setBarStyle:UIBarStyleBlack]; [super viewWillAppear:animated]; } - (void) close { UpdateExternalStatus(0); + if (Finish_ > 1) + [delegate_ saveState]; + switch (Finish_) { case 0: + [delegate_ returnToCydia]; break; case 1: @@ -5205,7 +5167,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (UIBarButtonItem *) rightButton { - return [[progress_ running] boolValue] ? nil : [[[UIBarButtonItem alloc] + return [[progress_ running] boolValue] ? [super rightButton] : [[[UIBarButtonItem alloc] initWithTitle:UCLocalize("CLOSE") style:UIBarButtonItemStylePlain target:self @@ -5356,89 +5318,22 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { @end /* }}} */ -/* Cell Content View {{{ */ -@protocol ContentDelegate -- (void) drawContentRect:(CGRect)rect; -@end - -@interface ContentView : UIView { - _transient id delegate_; -} - -@end - -@implementation ContentView - -- (id) initWithFrame:(CGRect)frame { - if ((self = [super initWithFrame:frame]) != nil) { - [self setNeedsDisplayOnBoundsChange:YES]; - } return self; -} - -- (void) setDelegate:(id)delegate { - delegate_ = delegate; -} - -- (void) drawRect:(CGRect)rect { - [super drawRect:rect]; - [delegate_ drawContentRect:rect]; -} - -@end -/* }}} */ -/* Cydia TableView Cell {{{ */ -@interface CYTableViewCell : UITableViewCell { - ContentView *content_; - bool highlighted_; -} - -@end - -@implementation CYTableViewCell - -- (void) dealloc { - [content_ release]; - [super dealloc]; -} - -- (void) _updateHighlightColorsForView:(id)view highlighted:(BOOL)highlighted { - //NSLog(@"_updateHighlightColorsForView:%@ highlighted:%s [content_=%@]", view, highlighted ? "YES" : "NO", content_); - - if (view == content_) { - //NSLog(@"_updateHighlightColorsForView:content_ highlighted:%s", highlighted ? "YES" : "NO", content_); - highlighted_ = highlighted; - } - - [super _updateHighlightColorsForView:view highlighted:highlighted]; -} - -- (void) setSelected:(BOOL)selected animated:(BOOL)animated { - //NSLog(@"setSelected:%s animated:%s", selected ? "YES" : "NO", animated ? "YES" : "NO"); - highlighted_ = selected; - - [super setSelected:selected animated:animated]; - [content_ setNeedsDisplay]; -} - -@end -/* }}} */ - /* Package Cell {{{ */ -@interface PackageCell : CYTableViewCell < - ContentDelegate +@interface PackageCell : CyteTableViewCell < + CyteTableViewCellDelegate > { - UIImage *icon_; - NSString *name_; - NSString *description_; + _H icon_; + _H name_; + _H description_; bool commercial_; - NSString *source_; - UIImage *badge_; - Package *package_; - UIImage *placard_; + _H source_; + _H badge_; + _H placard_; + bool summarized_; } - (PackageCell *) init; -- (void) setPackage:(Package *)package; +- (void) setPackage:(Package *)package asSummary:(bool)summary; - (void) drawContentRect:(CGRect)rect; @@ -5446,53 +5341,13 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { @implementation PackageCell -- (void) clearPackage { - if (icon_ != nil) { - [icon_ release]; - icon_ = nil; - } - - if (name_ != nil) { - [name_ release]; - name_ = nil; - } - - if (description_ != nil) { - [description_ release]; - description_ = nil; - } - - if (source_ != nil) { - [source_ release]; - source_ = nil; - } - - if (badge_ != nil) { - [badge_ release]; - badge_ = nil; - } - - if (placard_ != nil) { - [placard_ release]; - placard_ = nil; - } - - [package_ release]; - package_ = nil; -} - -- (void) dealloc { - [self clearPackage]; - [super dealloc]; -} - - (PackageCell *) init { CGRect frame(CGRectMake(0, 0, 320, 74)); if ((self = [super initWithFrame:frame reuseIdentifier:@"Package"]) != nil) { UIView *content([self contentView]); CGRect bounds([content bounds]); - content_ = [[ContentView alloc] initWithFrame:bounds]; + content_ = [[[CyteTableViewCellContentView alloc] initWithFrame:bounds] autorelease]; [content_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; [content addSubview:content_]; @@ -5502,101 +5357,148 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (NSString *) accessibilityLabel { - return [NSString stringWithFormat:UCLocalize("COLON_DELIMITED"), name_, description_]; + return [NSString stringWithFormat:UCLocalize("COLON_DELIMITED"), (id) name_, (id) description_]; } -- (void) setPackage:(Package *)package { - [self clearPackage]; - [package parse]; +- (void) setPackage:(Package *)package asSummary:(bool)summary { + summarized_ = summary; - Source *source = [package source]; + icon_ = nil; + name_ = nil; + description_ = nil; + source_ = nil; + badge_ = nil; + placard_ = nil; - icon_ = [[package icon] retain]; - name_ = [[package name] retain]; + if (package == nil) + [content_ setBackgroundColor:[UIColor whiteColor]]; + else { + [package parse]; - if (IsWildcat_) - description_ = [package longDescription]; - if (description_ == nil) - description_ = [package shortDescription]; - if (description_ != nil) - description_ = [description_ retain]; + Source *source = [package source]; - commercial_ = [package isCommercial]; + icon_ = [package icon]; - package_ = [package retain]; + if (NSString *name = [package name]) + name_ = [NSString stringWithString:name]; - NSString *label = nil; - bool trusted = false; + NSString *description(nil); - if (source != nil) { - label = [source label]; - trusted = [source trusted]; - } else if ([[package id] isEqualToString:@"firmware"]) - label = UCLocalize("APPLE"); - else - label = [NSString stringWithFormat:UCLocalize("SLASH_DELIMITED"), UCLocalize("UNKNOWN"), UCLocalize("LOCAL")]; + if (description == nil && IsWildcat_) + description = [package longDescription]; + if (description == nil) + description = [package shortDescription]; - NSString *from(label); + if (description != nil) + description_ = [NSString stringWithString:description]; - NSString *section = [package simpleSection]; - if (section != nil && ![section isEqualToString:label]) { - section = [[NSBundle mainBundle] localizedStringForKey:section value:nil table:@"Sections"]; - from = [NSString stringWithFormat:UCLocalize("PARENTHETICAL"), from, section]; - } + commercial_ = [package isCommercial]; - from = [NSString stringWithFormat:UCLocalize("FROM"), from]; - source_ = [from retain]; + NSString *label = nil; + bool trusted = false; - if (NSString *purpose = [package primaryPurpose]) - if ((badge_ = [UIImage imageAtPath:[NSString stringWithFormat:@"%@/Purposes/%@.png", App_, purpose]]) != nil) - badge_ = [badge_ retain]; + if (source != nil) { + label = [source label]; + trusted = [source trusted]; + } else if ([[package id] isEqualToString:@"firmware"]) + label = UCLocalize("APPLE"); + else + label = [NSString stringWithFormat:UCLocalize("SLASH_DELIMITED"), UCLocalize("UNKNOWN"), UCLocalize("LOCAL")]; - UIColor *color; - NSString *placard; + NSString *from(label); - if (NSString *mode = [package_ mode]) { - if ([mode isEqualToString:@"REMOVE"] || [mode isEqualToString:@"PURGE"]) { - color = RemovingColor_; - //placard = @"removing"; - } else { - color = InstallingColor_; - //placard = @"installing"; + NSString *section = [package simpleSection]; + if (section != nil && ![section isEqualToString:label]) { + section = [[NSBundle mainBundle] localizedStringForKey:section value:nil table:@"Sections"]; + from = [NSString stringWithFormat:UCLocalize("PARENTHETICAL"), from, section]; } - // XXX: the removing/installing placards are not @2x - placard = nil; - } else { - color = [UIColor whiteColor]; + source_ = [NSString stringWithFormat:UCLocalize("FROM"), from]; - if ([package installed] != nil) - placard = @"installed"; - else + if (NSString *purpose = [package primaryPurpose]) + badge_ = [UIImage imageAtPath:[NSString stringWithFormat:@"%@/Purposes/%@.png", App_, purpose]]; + + UIColor *color; + NSString *placard; + + if (NSString *mode = [package mode]) { + if ([mode isEqualToString:@"REMOVE"] || [mode isEqualToString:@"PURGE"]) { + color = RemovingColor_; + //placard = @"removing"; + } else { + color = InstallingColor_; + //placard = @"installing"; + } + + // XXX: the removing/installing placards are not @2x placard = nil; - } + } else { + color = [UIColor whiteColor]; + + if ([package installed] != nil) + placard = @"installed"; + else + placard = nil; + } - [content_ setBackgroundColor:color]; + [content_ setBackgroundColor:color]; - if (placard != nil) - if ((placard_ = [UIImage imageAtPath:[NSString stringWithFormat:@"%@/%@.png", App_, placard]]) != nil) - placard_ = [placard_ retain]; + if (placard != nil) + placard_ = [UIImage imageAtPath:[NSString stringWithFormat:@"%@/%@.png", App_, placard]]; + } [self setNeedsDisplay]; [content_ setNeedsDisplay]; } -- (void) drawContentRect:(CGRect)rect { +- (void) drawSummaryContentRect:(CGRect)rect { bool highlighted(highlighted_); float width([self bounds].size.width); -#if 0 - CGContextRef context(UIGraphicsGetCurrentContext()); - [([[self selectedBackgroundView] superview] != nil ? [UIColor clearColor] : [self backgroundColor]) set]; - CGContextFillRect(context, rect); -#endif + if (icon_ != nil) { + CGRect rect; + rect.size = [(UIImage *) icon_ size]; + + rect.size.width /= 4; + rect.size.height /= 4; + + rect.origin.x = 14 - rect.size.width / 4; + rect.origin.y = 14 - rect.size.height / 4; + + [icon_ drawInRect:rect]; + } + + if (badge_ != nil) { + CGRect rect; + rect.size = [(UIImage *) badge_ size]; + + rect.size.width /= 4; + rect.size.height /= 4; + + rect.origin.x = 20 - rect.size.width / 4; + rect.origin.y = 20 - rect.size.height / 4; + + [badge_ drawInRect:rect]; + } + + if (highlighted) + UISetColor(White_); + + if (!highlighted) + UISetColor(commercial_ ? Purple_ : Black_); + [name_ drawAtPoint:CGPointMake(36, 8) forWidth:(width - (placard_ == nil ? 68 : 94)) withFont:Font18Bold_ lineBreakMode:UILineBreakModeTailTruncation]; + + if (placard_ != nil) + [placard_ drawAtPoint:CGPointMake(width - 52, 9)]; +} + +- (void) drawNormalContentRect:(CGRect)rect { + bool highlighted(highlighted_); + float width([self bounds].size.width); if (icon_ != nil) { CGRect rect; - rect.size = [icon_ size]; + rect.size = [(UIImage *) icon_ size]; rect.size.width /= 2; rect.size.height /= 2; @@ -5609,7 +5511,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { if (badge_ != nil) { CGRect rect; - rect.size = [badge_ size]; + rect.size = [(UIImage *) badge_ size]; rect.size.width /= 2; rect.size.height /= 2; @@ -5636,18 +5538,25 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [placard_ drawAtPoint:CGPointMake(width - 52, 9)]; } +- (void) drawContentRect:(CGRect)rect { + if (summarized_) + [self drawSummaryContentRect:rect]; + else + [self drawNormalContentRect:rect]; +} + @end /* }}} */ /* Section Cell {{{ */ -@interface SectionCell : CYTableViewCell < - ContentDelegate +@interface SectionCell : CyteTableViewCell < + CyteTableViewCellDelegate > { - NSString *basic_; - NSString *section_; - NSString *name_; - NSString *count_; - UIImage *icon_; - UISwitch *switch_; + _H basic_; + _H section_; + _H name_; + _H count_; + _H icon_; + _H switch_; BOOL editing_; } @@ -5657,45 +5566,16 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { @implementation SectionCell -- (void) clearSection { - if (basic_ != nil) { - [basic_ release]; - basic_ = nil; - } - - if (section_ != nil) { - [section_ release]; - section_ = nil; - } - - if (name_ != nil) { - [name_ release]; - name_ = nil; - } - - if (count_ != nil) { - [count_ release]; - count_ = nil; - } -} - -- (void) dealloc { - [self clearSection]; - [icon_ release]; - [switch_ release]; - [super dealloc]; -} - - (id) initWithFrame:(CGRect)frame reuseIdentifier:(NSString *)reuseIdentifier { if ((self = [super initWithFrame:frame reuseIdentifier:reuseIdentifier]) != nil) { - icon_ = [[UIImage applicationImageNamed:@"folder.png"] retain]; - switch_ = [[UISwitch alloc] initWithFrame:CGRectMake(218, 9, 60, 25)]; + icon_ = [UIImage applicationImageNamed:@"folder.png"]; + switch_ = [[[UISwitch alloc] initWithFrame:CGRectMake(218, 9, 60, 25)] autorelease]; [switch_ addTarget:self action:@selector(onSwitch:) forEvents:UIControlEventValueChanged]; UIView *content([self contentView]); CGRect bounds([content bounds]); - content_ = [[ContentView alloc] initWithFrame:bounds]; + content_ = [[[CyteTableViewCellContentView alloc] initWithFrame:bounds] autorelease]; [content_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; [content addSubview:content_]; [content_ setBackgroundColor:[UIColor whiteColor]]; @@ -5724,22 +5604,20 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { editing_ = editing; } - [self clearSection]; + basic_ = nil; + section_ = nil; + name_ = nil; + count_ = nil; if (section == nil) { - name_ = [UCLocalize("ALL_PACKAGES") retain]; + name_ = UCLocalize("ALL_PACKAGES"); count_ = nil; } else { basic_ = [section name]; - if (basic_ != nil) - basic_ = [basic_ retain]; - section_ = [section localized]; - if (section_ != nil) - section_ = [section_ retain]; - name_ = [(section_ == nil || [section_ length] == 0 ? UCLocalize("NO_SECTION") : section_) retain]; - count_ = [[NSString stringWithFormat:@"%d", [section count]] retain]; + name_ = section_ == nil || [section_ length] == 0 ? UCLocalize("NO_SECTION") : (NSString *) section_; + count_ = [NSString stringWithFormat:@"%d", [section count]]; if (editing_) [switch_ setOn:(isSectionVisible(basic_) ? 1 : 0) animated:NO]; @@ -5789,15 +5667,15 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { /* }}} */ /* File Table {{{ */ -@interface FileTable : CYViewController < +@interface FileTable : CyteViewController < UITableViewDataSource, UITableViewDelegate > { _transient Database *database_; - Package *package_; - NSString *name_; - NSMutableArray *files_; - UITableView *list_; + _H package_; + _H name_; + _H files_; + _H list_; } - (id) initWithDatabase:(Database *)database; @@ -5807,16 +5685,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { @implementation FileTable -- (void) dealloc { - [self releaseSubviews]; - - [package_ release]; - [name_ release]; - [files_ release]; - - [super dealloc]; -} - - (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return files_ == nil ? 0 : [files_ count]; } @@ -5846,47 +5714,44 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (void) loadView { [self setView:[[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease]]; - list_ = [[UITableView alloc] initWithFrame:[[self view] bounds]]; + list_ = [[[UITableView alloc] initWithFrame:[[self view] bounds]] autorelease]; [list_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; [list_ setRowHeight:24.0f]; - [list_ setDataSource:self]; + [(UITableView *) list_ setDataSource:self]; [list_ setDelegate:self]; [[self view] addSubview:list_]; } - (void) viewDidLoad { + [super viewDidLoad]; + [[self navigationItem] setTitle:UCLocalize("INSTALLED_FILES")]; } - (void) releaseSubviews { - [list_ release]; list_ = nil; + + package_ = nil; + files_ = nil; + + [super releaseSubviews]; } - (id) initWithDatabase:(Database *)database { if ((self = [super init]) != nil) { database_ = database; - - files_ = [[NSMutableArray arrayWithCapacity:32] retain]; } return self; } - (void) setPackage:(Package *)package { - if (package_ != nil) { - [package_ autorelease]; - package_ = nil; - } - - if (name_ != nil) { - [name_ release]; - name_ = nil; - } + package_ = nil; + name_ = nil; - [files_ removeAllObjects]; + files_ = [NSMutableArray arrayWithCapacity:32]; if (package != nil) { - package_ = [package retain]; - name_ = [[package id] retain]; + package_ = package; + name_ = [package id]; if (NSArray *files = [package files]) [files_ addObjectsFromArray:files]; @@ -5925,7 +5790,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { @end /* }}} */ /* Package Controller {{{ */ -@interface CYPackageController : CYBrowserController < +@interface CYPackageController : CydiaWebViewController < UIActionSheetDelegate > { _transient Database *database_; @@ -6038,12 +5903,14 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { if ((self = [super init]) != nil) { database_ = database; buttons_ = [NSMutableArray arrayWithCapacity:4]; - name_ = [NSString stringWithString:name]; + name_ = name == nil ? @"" : [NSString stringWithString:name]; [self setURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/#!/package/%@", UI_, (id) name_]]]; } return self; } - (void) reloadData { + [super reloadData]; + package_ = [database_ packageWithName:name_]; [buttons_ removeAllObjects]; @@ -6079,8 +5946,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { target:self action:@selector(customButtonClicked) ] autorelease]; - - [super reloadData]; } - (bool) isLoading { @@ -6091,37 +5956,36 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { /* }}} */ /* Package List Controller {{{ */ -@interface PackageListController : CYViewController < +@interface PackageListController : CyteViewController < UITableViewDataSource, UITableViewDelegate > { _transient Database *database_; unsigned era_; - NSMutableArray *packages_; - NSMutableArray *sections_; - UITableView *list_; - NSMutableArray *index_; - NSMutableDictionary *indices_; - NSString *title_; + _H packages_; + _H sections_; + _H list_; + _H index_; + _H indices_; + _H title_; + unsigned reloading_; } - (id) initWithDatabase:(Database *)database title:(NSString *)title; - (void) setDelegate:(id)delegate; - (void) resetCursor; +- (void) clearData; @end @implementation PackageListController -- (void) dealloc { - [packages_ release]; - [sections_ release]; - [list_ release]; - [index_ release]; - [indices_ release]; - [title_ release]; +- (bool) isSummarized { + return false; +} - [super dealloc]; +- (bool) showsSections { + return true; } - (void) deselectWithAnimation:(BOOL)animated { @@ -6149,15 +6013,27 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [self resizeForKeyboardBounds:bounds duration:0]; } +- (void) getKeyboardCurve:(UIViewAnimationCurve *)curve duration:(NSTimeInterval *)duration forNotification:(NSNotification *)notification { + if (&UIKeyboardAnimationCurveUserInfoKey == NULL) + *curve = UIViewAnimationCurveEaseInOut; + else + [[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:curve]; + + if (&UIKeyboardAnimationDurationUserInfoKey == NULL) + *duration = 0.3; + else + [[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:duration]; +} + - (void) keyboardWillShow:(NSNotification *)notification { CGRect bounds; CGPoint center; - NSTimeInterval duration; - UIViewAnimationCurve curve; [[[notification userInfo] objectForKey:UIKeyboardBoundsUserInfoKey] getValue:&bounds]; [[[notification userInfo] objectForKey:UIKeyboardCenterEndUserInfoKey] getValue:¢er]; - [[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&curve]; - [[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&duration]; + + NSTimeInterval duration; + UIViewAnimationCurve curve; + [self getKeyboardCurve:&curve duration:&duration forNotification:notification]; CGRect kbframe = CGRectMake(round(center.x - bounds.size.width / 2.0), round(center.y - bounds.size.height / 2.0), bounds.size.width, bounds.size.height); UIViewController *base = self; @@ -6166,14 +6042,16 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { CGRect viewframe = [[base view] convertRect:[list_ frame] fromView:[list_ superview]]; CGRect intersection = CGRectIntersection(viewframe, kbframe); + if (kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber_iPhoneOS_3_0) // XXX: _UIApplicationLinkedOnOrAfter(4) + intersection.size.height += CYStatusBarHeight([self interfaceOrientation]); + [self resizeForKeyboardBounds:intersection duration:duration curve:curve]; } - (void) keyboardWillHide:(NSNotification *)notification { NSTimeInterval duration; UIViewAnimationCurve curve; - [[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&curve]; - [[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&duration]; + [self getKeyboardCurve:&curve duration:&duration forNotification:notification]; [self resizeForKeyboardBounds:CGRectZero duration:duration curve:curve]; } @@ -6243,7 +6121,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { PackageCell *cell((PackageCell *) [table dequeueReusableCellWithIdentifier:@"Package"]); if (cell == nil) cell = [[[PackageCell alloc] init] autorelease]; - [cell setPackage:[self packageAtIndexPath:path]]; + + Package *package([database_ packageWithName:[[self packageAtIndexPath:path] id]]); + [cell setPackage:package asSummary:[self isSummarized]]; return cell; } @@ -6254,8 +6134,10 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (NSArray *) sectionIndexTitlesForTableView:(UITableView *)tableView { - // XXX: is 20 the most optimal number here? - return [packages_ count] > 20 ? index_ : nil; + if (![self showsSections]) + return nil; + + return index_; } - (NSInteger) tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index { @@ -6268,63 +6150,107 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { return index; } +- (void) updateHeight { + [list_ setRowHeight:([self isSummarized] ? 38 : 73)]; +} + - (id) initWithDatabase:(Database *)database title:(NSString *)title { if ((self = [super init]) != nil) { database_ = database; title_ = [title copy]; [[self navigationItem] setTitle:title_]; + } return self; +} -#if TryIndexedCollation - if ([[self class] hasIndexedCollation]) - index_ = [[[objc_getClass("UILocalizedIndexedCollation") currentCollation] sectionIndexTitles] retain] - else -#endif - index_ = [[NSMutableArray alloc] initWithCapacity:32]; +- (void) loadView { + [self setView:[[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease]]; - indices_ = [[NSMutableDictionary alloc] initWithCapacity:32]; + list_ = [[[UITableView alloc] initWithFrame:[[self view] bounds] style:UITableViewStylePlain] autorelease]; + [list_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; + [[self view] addSubview:list_]; + + // XXX: is 20 the most optimal number here? + [list_ setSectionIndexMinimumDisplayRowCount:20]; - packages_ = [[NSMutableArray arrayWithCapacity:16] retain]; - sections_ = [[NSMutableArray arrayWithCapacity:16] retain]; + [(UITableView *) list_ setDataSource:self]; + [list_ setDelegate:self]; - list_ = [[UITableView alloc] initWithFrame:[[self view] bounds] style:UITableViewStylePlain]; - [list_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; - [list_ setRowHeight:73]; - [[self view] addSubview:list_]; + [self updateHeight]; +} - [list_ setDataSource:self]; - [list_ setDelegate:self]; - } return self; +- (void) releaseSubviews { + list_ = nil; + + packages_ = nil; + sections_ = nil; + index_ = nil; + indices_ = nil; + + [super releaseSubviews]; } - (void) setDelegate:(id)delegate { delegate_ = delegate; } -- (bool) hasPackage:(Package *)package { - return true; +- (bool) shouldYield { + return false; } -- (void) reloadData { - [super reloadData]; +- (bool) shouldBlock { + return false; +} +- (NSMutableArray *) _reloadPackages { +@synchronized (database_) { era_ = [database_ era]; - NSArray *packages = [database_ packages]; + NSArray *packages([database_ packages]); + + return [NSMutableArray arrayWithArray:packages]; +} } + +- (void) _reloadData { + if (reloading_ != 0) { + reloading_ = 2; + return; + } + + NSArray *packages; + + if ([self shouldYield]) { + do { + UIProgressHUD *hud; + + if (![self shouldBlock]) + hud = nil; + else { + hud = [delegate_ addProgressHUD]; + [hud setText:UCLocalize("LOADING")]; + } + + reloading_ = 1; + packages = [self yieldToSelector:@selector(_reloadPackages)]; + + if (hud != nil) + [delegate_ removeProgressHUD:hud]; + } while (reloading_ == 2); - [packages_ removeAllObjects]; - [sections_ removeAllObjects]; + reloading_ = 0; + } else { + packages = [self _reloadPackages]; + } - _profile(PackageTable$reloadData$Filter) - for (Package *package in packages) - if ([self hasPackage:package]) - [packages_ addObject:package]; - _end + packages_ = packages; - [indices_ removeAllObjects]; + indices_ = [NSMutableDictionary dictionaryWithCapacity:32]; + sections_ = [NSMutableArray arrayWithCapacity:16]; Section *section = nil; #if TryIndexedCollation if ([[self class] hasIndexedCollation]) { + index_ = [[objc_getClass("UILocalizedIndexedCollation") currentCollation] sectionIndexTitles]; + id collation = [objc_getClass("UILocalizedIndexedCollation") currentCollation]; NSArray *titles = [collation sectionIndexTitles]; int secidx = -1; @@ -6357,7 +6283,13 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } else #endif { - [index_ removeAllObjects]; + index_ = [NSMutableArray arrayWithCapacity:32]; + + bool sectioned([self showsSections]); + if (!sectioned) { + section = [[[Section alloc] initWithName:nil localize:false] autorelease]; + [sections_ addObject:section]; + } _profile(PackageTable$reloadData$Section) for (size_t offset(0), end([packages_ count]); offset != end; ++offset) { @@ -6369,7 +6301,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { index = [package index]; _end - if (section == nil || [section index] != index) { + if (sectioned && (section == nil || [section index] != index)) { _profile(PackageTable$reloadData$Section$Allocate) section = [[[Section alloc] initWithIndex:index row:offset] autorelease]; _end @@ -6387,13 +6319,34 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { _end } + [self updateHeight]; + _profile(PackageTable$reloadData$List) + [(UITableView *) list_ setDataSource:self]; [list_ reloadData]; _end } +- (void) reloadData { + [super reloadData]; + + if ([self shouldYield]) + [self performSelector:@selector(_reloadData) withObject:nil afterDelay:0]; + else + [self _reloadData]; +} + - (void) resetCursor { - [list_ scrollRectToVisible:CGRectMake(0, 0, 0, 0) animated:NO]; + [list_ scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:NO]; +} + +- (void) clearData { + [self updateHeight]; + + [list_ setDataSource:nil]; + [list_ reloadData]; + + [self resetCursor]; } @end @@ -6402,25 +6355,27 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { @interface FilteredPackageListController : PackageListController { SEL filter_; IMP imp_; - id object_; + _H object_; } - (void) setObject:(id)object; - (void) setObject:(id)object forFilter:(SEL)filter; +- (SEL) filter; +- (void) setFilter:(SEL)filter; + - (id) initWithDatabase:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object; @end @implementation FilteredPackageListController -- (void) dealloc { - if (object_ != nil) - [object_ release]; - [super dealloc]; +- (SEL) filter { + return filter_; } - (void) setFilter:(SEL)filter { +@synchronized (self) { filter_ = filter; /* XXX: this is an unsafe optimization of doomy hell */ @@ -6428,27 +6383,44 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { _assert(method != NULL); imp_ = method_getImplementation(method); _assert(imp_ != NULL); -} +} } - (void) setObject:(id)object { - if (object_ != nil) - [object_ release]; - if (object == nil) - object_ = nil; - else - object_ = [object retain]; -} +@synchronized (self) { + object_ = object; +} } - (void) setObject:(id)object forFilter:(SEL)filter { +@synchronized (self) { [self setFilter:filter]; [self setObject:object]; -} +} } + +- (NSMutableArray *) _reloadPackages { +@synchronized (database_) { + era_ = [database_ era]; + NSArray *packages([database_ packages]); + + NSMutableArray *filtered([NSMutableArray arrayWithCapacity:[packages count]]); + + IMP imp; + SEL filter; + _H object; -- (bool) hasPackage:(Package *)package { - _profile(FilteredPackageTable$hasPackage) - return [package valid] && (*reinterpret_cast(imp_))(package, filter_, object_); + @synchronized (self) { + imp = imp_; + filter = filter_; + object = object_; + } + + _profile(PackageTable$reloadData$Filter) + for (Package *package in packages) + if ([package valid] && (*reinterpret_cast(imp))(package, filter, object)) + [filtered addObject:package]; _end -} + + return filtered; +} } - (id) initWithDatabase:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object { if ((self = [super initWithDatabase:database title:title]) != nil) { @@ -6461,7 +6433,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { /* }}} */ /* Home Controller {{{ */ -@interface HomeController : CYBrowserController { +@interface HomeController : CydiaWebViewController { } @end @@ -6471,6 +6443,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (id) init { if ((self = [super init]) != nil) { [self setURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/#!/home/", UI_]]]; + [self reloadData]; } return self; } @@ -6478,6 +6451,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { return [NSURL URLWithString:@"cydia://home"]; } +- (void) didReceiveMemoryWarning { +} + - (void) aboutButtonClicked { UIAlertView *alert([[[UIAlertView alloc] init] autorelease]); @@ -6486,7 +6462,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [alert setCancelButtonIndex:0]; [alert setMessage: - @"Copyright (C) 2008-2011\n" + @"Copyright \u00a9 2008-2011\n" + "SaurikIT, LLC\n" + "\n" "Jay Freeman (saurik)\n" "saurik@saurik.com\n" "http://www.saurik.com/" @@ -6495,19 +6473,19 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [alert show]; } -- (void) viewDidLoad { - [[self navigationItem] setLeftBarButtonItem:[[[UIBarButtonItem alloc] +- (UIBarButtonItem *) leftButton { + return [[[UIBarButtonItem alloc] initWithTitle:UCLocalize("ABOUT") style:UIBarButtonItemStylePlain target:self action:@selector(aboutButtonClicked) - ] autorelease]]; + ] autorelease]; } @end /* }}} */ /* Manage Controller {{{ */ -@interface ManageController : CYBrowserController { +@interface ManageController : CydiaWebViewController { } - (void) queueStatusDidChange; @@ -6526,53 +6504,38 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { return [NSURL URLWithString:@"cydia://manage"]; } -- (void) viewDidLoad { - [[self navigationItem] setLeftBarButtonItem:[[[UIBarButtonItem alloc] +- (UIBarButtonItem *) leftButton { + return [[[UIBarButtonItem alloc] initWithTitle:UCLocalize("SETTINGS") style:UIBarButtonItemStylePlain target:self action:@selector(settingsButtonClicked) - ] autorelease]]; - - [self queueStatusDidChange]; + ] autorelease]; } - (void) settingsButtonClicked { [delegate_ showSettings]; } -#if !AlwaysReload - (void) queueButtonClicked { [delegate_ queue]; } -- (void) applyLoadingTitle { - // Disable "Loading" title. -} - -- (void) applyRightButton { - // Disable right button. +- (UIBarButtonItem *) customButton { + return Queuing_ ? [[[UIBarButtonItem alloc] + initWithTitle:UCLocalize("QUEUE") + style:UIBarButtonItemStyleDone + target:self + action:@selector(queueButtonClicked) + ] autorelease] : [super customButton]; } -#endif - (void) queueStatusDidChange { -#if !AlwaysReload - if (!IsWildcat_ && Queuing_) { - [[self navigationItem] setRightBarButtonItem:[[[UIBarButtonItem alloc] - initWithTitle:UCLocalize("QUEUE") - style:UIBarButtonItemStyleDone - target:self - action:@selector(queueButtonClicked) - ] autorelease]]; - } else { - [[self navigationItem] setRightBarButtonItem:nil]; - } -#endif + [self applyRightButton]; } - (bool) isLoading { - // Never show as loading. - return false; + return !Queuing_ && [super isLoading]; } @end @@ -6580,24 +6543,16 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { /* Refresh Bar {{{ */ @interface RefreshBar : UINavigationBar { - UIProgressIndicator *indicator_; - UITextLabel *prompt_; - UIProgressBar *progress_; - UINavigationButton *cancel_; + _H indicator_; + _H prompt_; + _H progress_; + _H cancel_; } @end @implementation RefreshBar -- (void) dealloc { - [indicator_ release]; - [prompt_ release]; - [progress_ release]; - [cancel_ release]; - [super dealloc]; -} - - (void) positionViews { CGRect frame = [cancel_ frame]; frame.size = [cancel_ sizeThatFits:frame.size]; @@ -6643,23 +6598,23 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { UIProgressIndicatorStyleMediumBrown : UIProgressIndicatorStyleMediumWhite; - indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectZero]; - [indicator_ setStyle:style]; + indicator_ = [[[UIProgressIndicator alloc] initWithFrame:CGRectZero] autorelease]; + [(UIProgressIndicator *) indicator_ setStyle:style]; [indicator_ startAnimation]; [self addSubview:indicator_]; - prompt_ = [[UITextLabel alloc] initWithFrame:CGRectZero]; + prompt_ = [[[UITextLabel alloc] initWithFrame:CGRectZero] autorelease]; [prompt_ setColor:[UIColor colorWithCGColor:(ugly ? Blueish_ : Off_)]]; [prompt_ setBackgroundColor:[UIColor clearColor]]; [prompt_ setFont:[UIFont systemFontOfSize:15]]; [self addSubview:prompt_]; - progress_ = [[UIProgressBar alloc] initWithFrame:CGRectZero]; + progress_ = [[[UIProgressBar alloc] initWithFrame:CGRectZero] autorelease]; [progress_ setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleLeftMargin]; - [progress_ setStyle:0]; + [(UIProgressBar *) progress_ setStyle:0]; [self addSubview:progress_]; - cancel_ = [[UINavigationButton alloc] initWithTitle:UCLocalize("CANCEL") style:UINavigationButtonStyleHighlighted]; + cancel_ = [[[UINavigationButton alloc] initWithTitle:UCLocalize("CANCEL") style:UINavigationButtonStyleHighlighted] autorelease]; [cancel_ setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin]; [cancel_ addTarget:delegate action:@selector(cancelPressed) forControlEvents:UIControlEventTouchUpInside]; [cancel_ setBarStyle:barstyle]; @@ -6695,7 +6650,14 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { @end /* }}} */ -@class CYNavigationController; +/* Cydia Navigation Controller Interface {{{ */ +@interface UINavigationController (Cydia) + +- (NSArray *) navigationURLCollection; +- (void) unloadData; + +@end +/* }}} */ /* Cydia Tab Bar Controller {{{ */ @interface CYTabBarController : UITabBarController < @@ -6703,15 +6665,14 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { ProgressDelegate > { _transient Database *database_; - RefreshBar *refreshbar_; + _H refreshbar_; bool dropped_; bool updating_; // XXX: ok, "updatedelegate_"?... _transient NSObject *updatedelegate_; - id root_; - UIViewController *remembered_; + _H remembered_; _transient UIViewController *transient_; } @@ -6720,6 +6681,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (void) beginUpdate; - (void) raiseBar:(BOOL)animated; - (BOOL) updating; +- (void) unloadData; @end @@ -6729,7 +6691,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { NSMutableArray *controllers = [[self viewControllers] mutableCopy]; if (transient != nil) { if (transient_ == nil) - remembered_ = [[controllers objectAtIndex:0] retain]; + remembered_ = [controllers objectAtIndex:0]; transient_ = transient; [transient_ setTabBarItem:[remembered_ tabBarItem]]; [controllers replaceObjectAtIndex:0 withObject:transient_]; @@ -6740,7 +6702,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [remembered_ setTabBarItem:[transient_ tabBarItem]]; transient_ = transient; [controllers replaceObjectAtIndex:0 withObject:remembered_]; - [remembered_ release]; remembered_ = nil; [self setViewControllers:controllers]; [self revealTabBarSelection]; @@ -6769,15 +6730,22 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { return items; } -- (void) reloadData { - for (CYViewController *controller in [self viewControllers]) - [controller reloadData]; +- (void) unloadData { + [super unloadData]; + + for (UINavigationController *controller in [self viewControllers]) + [controller unloadData]; + + if (UIViewController *selected = [self selectedViewController]) + [selected reloadData]; - [(CYNavigationController *)[self unselectedViewController] reloadData]; + if (UIViewController *unselected = [self unselectedViewController]) { + [unselected unloadData]; + [unselected reloadData]; + } } - (void) dealloc { - [refreshbar_ release]; [[NSNotificationCenter defaultCenter] removeObserver:self]; [super dealloc]; @@ -6791,7 +6759,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [[self view] setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarFrameChanged:) name:UIApplicationDidChangeStatusBarFrameNotification object:nil]; - refreshbar_ = [[RefreshBar alloc] initWithFrame:CGRectMake(0, 0, [[self view] frame].size.width, [UINavigationBar defaultSize].height) delegate:self]; + refreshbar_ = [[[RefreshBar alloc] initWithFrame:CGRectMake(0, 0, [[self view] frame].size.width, [UINavigationBar defaultSize].height) delegate:self] autorelease]; } return self; } @@ -6800,7 +6768,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) beginUpdate { - [refreshbar_ start]; + [(RefreshBar *) refreshbar_ start]; [self dropBar:YES]; [updatedelegate_ retainNetworkActivityIndicator]; @@ -6813,7 +6781,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { ]; } -- (void) performUpdate { _pooled +- (void) performUpdate { + NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]); + Status status; status.setDelegate(self); [database_ updateWithStatus:status]; @@ -6823,6 +6793,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { withObject:nil waitUntilDone:NO ]; + + [pool release]; } - (void) stopUpdateWithSelector:(SEL)selector { @@ -6878,14 +6850,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { updatedelegate_ = delegate; } -- (CGFloat) statusBarHeight { - if (UIInterfaceOrientationIsPortrait([self interfaceOrientation])) { - return [[UIApplication sharedApplication] statusBarFrame].size.height; - } else { - return [[UIApplication sharedApplication] statusBarFrame].size.width; - } -} - - (UIView *) transitionView { if ([self respondsToSelector:@selector(_transitionView)]) return [self _transitionView]; @@ -6904,7 +6868,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { CGRect barframe([refreshbar_ frame]); if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iPhoneOS_3_0) // XXX: _UIApplicationLinkedOnOrAfter(4) - barframe.origin.y = [self statusBarHeight]; + barframe.origin.y = CYStatusBarHeight([self interfaceOrientation]); else barframe.origin.y = 0; @@ -6924,9 +6888,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { // Ensure bar has the proper width for our view, it might have changed barframe.size.width = viewframe.size.width; [refreshbar_ setFrame:barframe]; - - // XXX: fix Apple's layout bug - [[root_ selectedViewController] _updateLayoutForStatusBarAndInterfaceOrientation]; } - (void) raiseBar:(BOOL)animated { @@ -6949,17 +6910,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { if (animated) [UIView commitAnimations]; - - // XXX: fix Apple's layout bug - // SRK [[self selectedViewController] _updateLayoutForStatusBarAndInterfaceOrientation]; -} - -#if 0 -- (void) willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration { - // XXX: fix Apple's layout bug - // SRK [[self selectedViewController] _updateLayoutForStatusBarAndInterfaceOrientation]; } -#endif - (void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { bool dropped(dropped_); @@ -6971,9 +6922,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { if (dropped) [self dropBar:NO]; - - // XXX: fix Apple's layout bug - // SRK [[self selectedViewController] _updateLayoutForStatusBarAndInterfaceOrientation]; } - (void) statusBarFrameChanged:(NSNotification *)notification { @@ -6985,25 +6933,14 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { @end /* }}} */ -/* Cydia Navigation Controller {{{ */ -@interface CYNavigationController : UINavigationController { - _transient Database *database_; - _transient id delegate_; -} - -- (NSArray *) navigationURLCollection; -- (id) initWithDatabase:(Database *)database; -- (void) reloadData; - -@end - -@implementation CYNavigationController +/* Cydia Navigation Controller Implementation {{{ */ +@implementation UINavigationController (Cydia) - (NSArray *) navigationURLCollection { NSMutableArray *stack([NSMutableArray array]); - for (CYViewController *controller in [self viewControllers]) { + for (CyteViewController *controller in [self viewControllers]) { NSString *url = [[controller navigationURL] absoluteString]; if (url != nil) [stack addObject:url]; @@ -7013,23 +6950,24 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) reloadData { - for (CYViewController *page in [self viewControllers]) { - // Only reload controllers that have already loaded. - // This prevents a page from accidentally loading too - // early if it hasn't been shown on the screen yet. - if ([page hasLoaded]) - [page reloadData]; - } -} + [super reloadData]; -- (void) setDelegate:(id)delegate { - delegate_ = delegate; + UIViewController *visible([self visibleViewController]); + if (visible != nil) + [visible reloadData]; + + // on the iPad, this view controller is ALSO visible. :( + if (IsWildcat_) + if (UIViewController *top = [self topViewController]) + if (top != visible) + [top reloadData]; } -- (id) initWithDatabase:(Database *)database { - if ((self = [super init]) != nil) { - database_ = database; - } return self; +- (void) unloadData { + for (CyteViewController *page in [self viewControllers]) + [page unloadData]; + + [super unloadData]; } @end @@ -7111,6 +7049,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { Package *package([database packageWithName:path]); if (package == nil) goto fail; + [package parse]; UIImage *icon([package icon]); [self _returnPNGWithImage:icon forRequest:request]; } else if ([command isEqualToString:@"source-icon"]) { @@ -7132,8 +7071,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { if (path == nil) goto fail; path = [path stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; - NSString *section(Simplify(path)); - UIImage *icon([UIImage imageAtPath:[NSString stringWithFormat:@"%@/Sections/%@.png", App_, section]]); + UIImage *icon([UIImage imageAtPath:[NSString stringWithFormat:@"%@/Sections/%@.png", App_, [path stringByReplacingOccurrencesOfString:@" " withString:@"_"]]]); if (icon == nil) icon = [UIImage applicationImageNamed:@"unknown.png"]; [self _returnPNGWithImage:icon forRequest:request]; @@ -7184,15 +7122,14 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { @end /* }}} */ /* Sections Controller {{{ */ -@interface SectionsController : CYViewController < +@interface SectionsController : CyteViewController < UITableViewDataSource, UITableViewDelegate > { _transient Database *database_; - NSMutableArray *sections_; - NSMutableArray *filtered_; - UITableView *list_; - BOOL editing_; + _H sections_; + _H filtered_; + _H list_; } - (id) initWithDatabase:(Database *)database; @@ -7202,37 +7139,27 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { @implementation SectionsController -- (void) dealloc { - [self releaseSubviews]; - [sections_ release]; - [filtered_ release]; - - [super dealloc]; -} - - (NSURL *) navigationURL { return [NSURL URLWithString:@"cydia://sections"]; } - (void) updateNavigationItem { - [[self navigationItem] setTitle:editing_ ? UCLocalize("SECTION_VISIBILITY") : UCLocalize("SECTIONS")]; + [[self navigationItem] setTitle:[self isEditing] ? UCLocalize("SECTION_VISIBILITY") : UCLocalize("SECTIONS")]; if ([sections_ count] == 0) { [[self navigationItem] setRightBarButtonItem:nil]; } else { [[self navigationItem] setRightBarButtonItem:[[UIBarButtonItem alloc] - initWithBarButtonSystemItem:(editing_ ? UIBarButtonSystemItemDone : UIBarButtonSystemItemEdit) + initWithBarButtonSystemItem:([self isEditing] ? UIBarButtonSystemItemDone : UIBarButtonSystemItemEdit) target:self action:@selector(editButtonClicked) ] animated:([[self navigationItem] rightBarButtonItem] != nil)]; } } -- (BOOL) isEditing { - return editing_; -} +- (void) setEditing:(BOOL)editing animated:(BOOL)animated { + [super setEditing:editing animated:animated]; -- (void) setEditing:(BOOL)editing { - if ((editing_ = editing)) + if (editing) [list_ reloadData]; else [delegate_ updateData]; @@ -7247,16 +7174,27 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (void) viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; - if (editing_) [self setEditing:NO]; + if ([self isEditing]) [self setEditing:NO]; } - (Section *) sectionAtIndexPath:(NSIndexPath *)indexPath { - Section *section = (editing_ ? [sections_ objectAtIndex:[indexPath row]] : ([indexPath row] == 0 ? nil : [filtered_ objectAtIndex:([indexPath row] - 1)])); + Section *section = nil; + int index = [indexPath row]; + if (![self isEditing]) { + index -= 1; + if (index >= 0) + section = [filtered_ objectAtIndex:index]; + } else { + section = [sections_ objectAtIndex:index]; + } return section; } - (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - return editing_ ? [sections_ count] : [filtered_ count] + 1; + if ([self isEditing]) + return [sections_ count]; + else + return [filtered_ count] + 1; } /*- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { @@ -7270,13 +7208,13 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { if (cell == nil) cell = [[[SectionCell alloc] initWithFrame:CGRectZero reuseIdentifier:reuseIdentifier] autorelease]; - [cell setSection:[self sectionAtIndexPath:indexPath] editing:editing_]; + [cell setSection:[self sectionAtIndexPath:indexPath] editing:[self isEditing]]; return cell; } - (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { - if (editing_) + if ([self isEditing]) return; Section *section = [self sectionAtIndexPath:indexPath]; @@ -7293,29 +7231,32 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (void) loadView { [self setView:[[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease]]; - list_ = [[UITableView alloc] initWithFrame:[[self view] bounds]]; + list_ = [[[UITableView alloc] initWithFrame:[[self view] bounds]] autorelease]; [list_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; [list_ setRowHeight:45.0f]; - [list_ setDataSource:self]; + [(UITableView *) list_ setDataSource:self]; [list_ setDelegate:self]; [[self view] addSubview:list_]; } - (void) viewDidLoad { + [super viewDidLoad]; + [[self navigationItem] setTitle:UCLocalize("SECTIONS")]; } - (void) releaseSubviews { - [list_ release]; list_ = nil; + + sections_ = nil; + filtered_ = nil; + + [super releaseSubviews]; } - (id) initWithDatabase:(Database *)database { if ((self = [super init]) != nil) { database_ = database; - - sections_ = [[NSMutableArray arrayWithCapacity:16] retain]; - filtered_ = [[NSMutableArray arrayWithCapacity:16] retain]; } return self; } @@ -7324,8 +7265,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { NSArray *packages = [database_ packages]; - [sections_ removeAllObjects]; - [filtered_ removeAllObjects]; + sections_ = [NSMutableArray arrayWithCapacity:16]; + filtered_ = [NSMutableArray arrayWithCapacity:16]; NSMutableDictionary *sections([NSMutableDictionary dictionaryWithCapacity:32]); @@ -7361,7 +7302,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [sections_ sortUsingSelector:@selector(compareByLocalized:)]; - for (Section *section in sections_) { + for (Section *section in (id) sections_) { size_t count([section row]); if (count == 0) continue; @@ -7377,24 +7318,23 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) editButtonClicked { - [self setEditing:(!editing_)]; + [self setEditing:![self isEditing] animated:YES]; } @end /* }}} */ /* Changes Controller {{{ */ -@interface ChangesController : CYViewController < +@interface ChangesController : CyteViewController < UITableViewDataSource, UITableViewDelegate > { _transient Database *database_; unsigned era_; - CFMutableArrayRef packages_; - NSMutableArray *sections_; - UITableView *list_; + _H packages_; + _H sections_; + _H list_; unsigned upgrades_; - BOOL hasSentFirstLoad_; } - (id) initWithDatabase:(Database *)database; @@ -7403,33 +7343,13 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { @implementation ChangesController -- (void) dealloc { - [self releaseSubviews]; - CFRelease(packages_); - [sections_ release]; - - [super dealloc]; -} - - (NSURL *) navigationURL { return [NSURL URLWithString:@"cydia://changes"]; } -- (void) viewWillAppear:(BOOL)animated { - // Loads after it appears, so don't load beforehand. - loaded_ = YES; - [super viewWillAppear:animated]; -} - - (void) viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; - - if (!hasSentFirstLoad_) { - hasSentFirstLoad_ = YES; - [self performSelector:@selector(reloadData) withObject:nil afterDelay:0.0]; - } else { - [list_ deselectRowAtIndexPath:[list_ indexPathForSelectedRow] animated:animated]; - } + [list_ deselectRowAtIndexPath:[list_ indexPathForSelectedRow] animated:animated]; } - (NSInteger) numberOfSectionsInTableView:(UITableView *)list { @@ -7449,10 +7369,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { return [[sections_ objectAtIndex:section] count]; } -- (Package *) packageAtIndex:(NSUInteger)index { - return (Package *) CFArrayGetValueAtIndex(packages_, index); -} - - (Package *) packageAtIndexPath:(NSIndexPath *)path { @synchronized (database_) { if ([database_ era] != era_) @@ -7463,14 +7379,16 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { return nil; Section *section([sections_ objectAtIndex:sectionIndex]); NSInteger row([path row]); - return [[[self packageAtIndex:([section row] + row)] retain] autorelease]; + return [[[packages_ objectAtIndex:([section row] + row)] retain] autorelease]; } } - (UITableViewCell *) tableView:(UITableView *)table cellForRowAtIndexPath:(NSIndexPath *)path { PackageCell *cell((PackageCell *) [table dequeueReusableCellWithIdentifier:@"Package"]); if (cell == nil) cell = [[[PackageCell alloc] init] autorelease]; - [cell setPackage:[self packageAtIndexPath:path]]; + + Package *package([database_ packageWithName:[[self packageAtIndexPath:path] id]]); + [cell setPackage:package asSummary:false]; return cell; } @@ -7489,72 +7407,83 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (void) upgradeButtonClicked { [delegate_ distUpgrade]; + [[self navigationItem] setRightBarButtonItem:nil animated:YES]; } - (void) loadView { [self setView:[[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease]]; - list_ = [[UITableView alloc] initWithFrame:[[self view] bounds] style:UITableViewStylePlain]; + list_ = [[[UITableView alloc] initWithFrame:[[self view] bounds] style:UITableViewStylePlain] autorelease]; [list_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; [list_ setRowHeight:73]; - [list_ setDataSource:self]; + [(UITableView *) list_ setDataSource:self]; [list_ setDelegate:self]; [[self view] addSubview:list_]; } - (void) viewDidLoad { + [super viewDidLoad]; + [[self navigationItem] setTitle:UCLocalize("CHANGES")]; } - (void) releaseSubviews { - [list_ release]; list_ = nil; + + packages_ = nil; + sections_ = nil; + + [super releaseSubviews]; } - (id) initWithDatabase:(Database *)database { if ((self = [super init]) != nil) { database_ = database; - - packages_ = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL); - sections_ = [[NSMutableArray arrayWithCapacity:16] retain]; } return self; } -// this mostly works because reloadData (below) is @synchronized (database_) -// XXX: that said, I've been running into problems with NSRangeExceptions :( -- (void) _reloadPackages:(NSArray *)packages { - CFRelease(packages_); - packages_ = CFArrayCreateMutable(kCFAllocatorDefault, [packages count], NULL); +- (NSMutableArray *) _reloadPackages { +@synchronized (database_) { + era_ = [database_ era]; + NSArray *packages([database_ packages]); + + NSMutableArray *filtered([NSMutableArray arrayWithCapacity:[packages count]]); _trace(); _profile(ChangesController$_reloadPackages$Filter) for (Package *package in packages) if ([package upgradableAndEssential:YES] || [package visible]) - CFArrayAppendValue(packages_, package); + CFArrayAppendValue((CFMutableArrayRef) filtered, package); _end _trace(); _profile(ChangesController$_reloadPackages$radixSort) - [(NSMutableArray *) packages_ radixSortUsingFunction:reinterpret_cast(&PackageChangesRadix) withContext:NULL]; + [filtered radixSortUsingFunction:reinterpret_cast(&PackageChangesRadix) withContext:NULL]; _end _trace(); -} -- (void) reloadData { -@synchronized (database_) { - era_ = [database_ era]; - NSArray *packages = [database_ packages]; + return filtered; +} } - [sections_ removeAllObjects]; +- (void) _reloadData { + NSArray *packages; -#if 1 - UIProgressHUD *hud([delegate_ addProgressHUD]); - [hud setText:UCLocalize("LOADING")]; - //NSLog(@"HUD:%@::%@", delegate_, hud); - [self yieldToSelector:@selector(_reloadPackages:) withObject:packages]; - [delegate_ removeProgressHUD:hud]; -#else - [self _reloadPackages:packages]; -#endif + reload: + if (true) { + UIProgressHUD *hud([delegate_ addProgressHUD]); + [hud setText:UCLocalize("LOADING")]; + //NSLog(@"HUD:%@::%@", delegate_, hud); + packages = [self yieldToSelector:@selector(_reloadPackages)]; + [delegate_ removeProgressHUD:hud]; + } else { + packages = [self _reloadPackages]; + } + +@synchronized (database_) { + if (era_ != [database_ era]) + goto reload; + + packages_ = packages; + sections_ = [NSMutableArray arrayWithCapacity:16]; Section *upgradable = [[[Section alloc] initWithName:UCLocalize("AVAILABLE_UPGRADES") localize:NO] autorelease]; Section *ignored = nil; @@ -7566,8 +7495,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { CFDateFormatterRef formatter(CFDateFormatterCreate(NULL, Locale_, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle)); - for (size_t offset = 0, count = CFArrayGetCount(packages_); offset != count; ++offset) { - Package *package = [self packageAtIndex:offset]; + for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) { + Package *package = [packages_ objectAtIndex:offset]; BOOL uae = [package upgradableAndEssential:YES]; @@ -7607,7 +7536,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { if (unseens) { Section *last = [sections_ lastObject]; size_t count = [last count]; - CFArrayReplaceValues(packages_, CFRangeMake(CFArrayGetCount(packages_) - count, count), NULL, 0); + [packages_ removeObjectsInRange:NSMakeRange([packages_ count] - count, count)]; [sections_ removeLastObject]; } @@ -7618,48 +7547,45 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [list_ reloadData]; - if (upgrades_ > 0) - [[self navigationItem] setRightBarButtonItem:[[[UIBarButtonItem alloc] - initWithTitle:[NSString stringWithFormat:UCLocalize("PARENTHETICAL"), UCLocalize("UPGRADE"), [NSString stringWithFormat:@"%u", upgrades_]] - style:UIBarButtonItemStylePlain - target:self - action:@selector(upgradeButtonClicked) - ] autorelease]]; + [[self navigationItem] setRightBarButtonItem:(upgrades_ == 0 ? nil : [[[UIBarButtonItem alloc] + initWithTitle:[NSString stringWithFormat:UCLocalize("PARENTHETICAL"), UCLocalize("UPGRADE"), [NSString stringWithFormat:@"%u", upgrades_]] + style:UIBarButtonItemStylePlain + target:self + action:@selector(upgradeButtonClicked) + ] autorelease]) animated:YES]; - if (![delegate_ updating]) - [[self navigationItem] setLeftBarButtonItem:[[[UIBarButtonItem alloc] - initWithTitle:UCLocalize("REFRESH") - style:UIBarButtonItemStylePlain - target:self - action:@selector(refreshButtonClicked) - ] autorelease]]; + [[self navigationItem] setLeftBarButtonItem:([delegate_ updating] ? nil : [[[UIBarButtonItem alloc] + initWithTitle:UCLocalize("REFRESH") + style:UIBarButtonItemStylePlain + target:self + action:@selector(refreshButtonClicked) + ] autorelease]) animated:YES]; PrintTimes(); } } +- (void) reloadData { + [super reloadData]; + [self performSelector:@selector(_reloadData) withObject:nil afterDelay:0]; +} + @end /* }}} */ /* Search Controller {{{ */ @interface SearchController : FilteredPackageListController < UISearchBarDelegate > { - _H search_; + _H search_; BOOL searchloaded_; } -- (id) initWithDatabase:(Database *)database; -- (void) setSearchTerm:(NSString *)term; +- (id) initWithDatabase:(Database *)database query:(NSString *)query; - (void) reloadData; @end @implementation SearchController -- (void) dealloc { - [search_ setDelegate:nil]; - [super dealloc]; -} - - (NSURL *) navigationURL { if ([search_ text] == nil || [[search_ text] isEqualToString:@""]) return [NSURL URLWithString:@"cydia://search"]; @@ -7667,26 +7593,74 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { return [NSURL URLWithString:[NSString stringWithFormat:@"cydia://search/%@", [search_ text]]]; } -- (void) setSearchTerm:(NSString *)searchTerm { - [search_ setText:searchTerm]; +- (void) useSearch { + [self setObject:[[search_ text] componentsSeparatedByString:@" "] forFilter:@selector(isUnfilteredAndSearchedForBy:)]; + [self clearData]; [self reloadData]; } -- (void) searchBarSearchButtonClicked:(UISearchBar *)searchBar { - [self setObject:[search_ text] forFilter:@selector(isUnfilteredAndSearchedForBy:)]; - [search_ resignFirstResponder]; +- (void) viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + + if ([self filter] == @selector(isUnfilteredAndSelectedForBy:)) + [self useSearch]; +} + +- (void) searchBarTextDidBeginEditing:(UISearchBar *)searchBar { + [self setObject:[search_ text] forFilter:@selector(isUnfilteredAndSelectedForBy:)]; + [self clearData]; [self reloadData]; } +- (void) searchBarButtonClicked:(UISearchBar *)searchBar { + [search_ resignFirstResponder]; + [self useSearch]; +} + +- (void) searchBarCancelButtonClicked:(UISearchBar *)searchBar { + [search_ setText:@""]; + [self searchBarButtonClicked:searchBar]; +} + +- (void) searchBarSearchButtonClicked:(UISearchBar *)searchBar { + [self searchBarButtonClicked:searchBar]; +} + - (void) searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)text { [self setObject:text forFilter:@selector(isUnfilteredAndSelectedForBy:)]; [self reloadData]; } -- (id) initWithDatabase:(Database *)database { - if ((self = [super initWithDatabase:database title:UCLocalize("SEARCH") filter:@selector(isUnfilteredAndSearchedForBy:) with:nil])) { +- (bool) shouldYield { + return YES; +} + +- (bool) shouldBlock { + return [self filter] == @selector(isUnfilteredAndSearchedForBy:); +} + +- (bool) isSummarized { + return [self filter] == @selector(isUnfilteredAndSelectedForBy:); +} + +- (bool) showsSections { + return false; +} + +- (NSMutableArray *) _reloadPackages { + NSMutableArray *packages([super _reloadPackages]); + if ([self filter] == @selector(isUnfilteredAndSearchedForBy:)) + [packages radixSortUsingSelector:@selector(rank)]; + return packages; +} + +- (id) initWithDatabase:(Database *)database query:(NSString *)query { + if ((self = [super initWithDatabase:database title:UCLocalize("SEARCH") filter:@selector(isUnfilteredAndSearchedForBy:) with:[query componentsSeparatedByString:@" "]])) { search_ = [[[UISearchBar alloc] init] autorelease]; [search_ setDelegate:self]; + + if (query != nil) + [search_ setText:query]; } return self; } @@ -7712,9 +7686,14 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) reloadData { - [self setObject:[search_ text]]; - [super reloadData]; + id object([search_ text]); + if ([self filter] == @selector(isUnfilteredAndSearchedForBy:)) + object = [object componentsSeparatedByString:@" "]; + + [self setObject:object]; [self resetCursor]; + + [super reloadData]; } - (void) didSelectPackage:(Package *)package { @@ -7725,18 +7704,18 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { @end /* }}} */ /* Package Settings Controller {{{ */ -@interface PackageSettingsController : CYViewController < +@interface PackageSettingsController : CyteViewController < UITableViewDataSource, UITableViewDelegate > { _transient Database *database_; - NSString *name_; - Package *package_; - UITableView *table_; - UISwitch *subscribedSwitch_; - UISwitch *ignoredSwitch_; - UITableViewCell *subscribedCell_; - UITableViewCell *ignoredCell_; + _H name_; + _H package_; + _H table_; + _H subscribedSwitch_; + _H ignoredSwitch_; + _H subscribedCell_; + _H ignoredCell_; } - (id) initWithDatabase:(Database *)database package:(NSString *)package; @@ -7745,16 +7724,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { @implementation PackageSettingsController -- (void) dealloc { - [self releaseSubviews]; - [name_ release]; - [package_ release]; - - [super dealloc]; -} - - (NSURL *) navigationURL { - return [NSURL URLWithString:[NSString stringWithFormat:@"cydia://package/%@/settings", [package_ id]]]; + return [NSURL URLWithString:[NSString stringWithFormat:@"cydia://package/%@/settings", (id) name_]]; } - (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView { @@ -7850,68 +7821,60 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (void) loadView { [self setView:[[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease]]; - table_ = [[UITableView alloc] initWithFrame:[[self view] bounds] style:UITableViewStyleGrouped]; + table_ = [[[UITableView alloc] initWithFrame:[[self view] bounds] style:UITableViewStyleGrouped] autorelease]; [table_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; - [table_ setDataSource:self]; + [(UITableView *) table_ setDataSource:self]; [table_ setDelegate:self]; [[self view] addSubview:table_]; - subscribedSwitch_ = [[UISwitch alloc] initWithFrame:CGRectMake(0, 0, 50, 20)]; + subscribedSwitch_ = [[[UISwitch alloc] initWithFrame:CGRectMake(0, 0, 50, 20)] autorelease]; [subscribedSwitch_ setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin]; [subscribedSwitch_ addTarget:self action:@selector(onSubscribed:) forEvents:UIControlEventValueChanged]; - ignoredSwitch_ = [[UISwitch alloc] initWithFrame:CGRectMake(0, 0, 50, 20)]; + ignoredSwitch_ = [[[UISwitch alloc] initWithFrame:CGRectMake(0, 0, 50, 20)] autorelease]; [ignoredSwitch_ setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin]; [ignoredSwitch_ addTarget:self action:@selector(onIgnored:) forEvents:UIControlEventValueChanged]; - subscribedCell_ = [[UITableViewCell alloc] init]; + subscribedCell_ = [[[UITableViewCell alloc] init] autorelease]; [subscribedCell_ setText:UCLocalize("SHOW_ALL_CHANGES")]; [subscribedCell_ setAccessoryView:subscribedSwitch_]; [subscribedCell_ setSelectionStyle:UITableViewCellSelectionStyleNone]; - ignoredCell_ = [[UITableViewCell alloc] init]; + ignoredCell_ = [[[UITableViewCell alloc] init] autorelease]; [ignoredCell_ setText:UCLocalize("IGNORE_UPGRADES")]; [ignoredCell_ setAccessoryView:ignoredSwitch_]; [ignoredCell_ setSelectionStyle:UITableViewCellSelectionStyleNone]; } - (void) viewDidLoad { + [super viewDidLoad]; + [[self navigationItem] setTitle:UCLocalize("SETTINGS")]; } - (void) releaseSubviews { - [ignoredCell_ release]; ignoredCell_ = nil; - - [subscribedCell_ release]; subscribedCell_ = nil; - - [table_ release]; table_ = nil; - - [ignoredSwitch_ release]; ignoredSwitch_ = nil; - - [subscribedSwitch_ release]; subscribedSwitch_ = nil; + + [super releaseSubviews]; } - (id) initWithDatabase:(Database *)database package:(NSString *)package { if ((self = [super init]) != nil) { database_ = database; - name_ = [package retain]; + name_ = package; } return self; } - (void) reloadData { [super reloadData]; - if (package_ != nil) - [package_ autorelease]; package_ = [database_ packageWithName:name_]; if (package_ != nil) { - package_ = [package_ retain]; [subscribedSwitch_ setOn:([package_ subscribed] ? 1 : 0) animated:NO]; [ignoredSwitch_ setOn:([package_ ignored] ? 1 : 0) animated:NO]; } // XXX: what now, G? @@ -7936,10 +7899,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { @implementation InstalledController -- (void) dealloc { - [super dealloc]; -} - - (NSURL *) navigationURL { return [NSURL URLWithString:@"cydia://installed"]; } @@ -7996,48 +7955,58 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { /* }}} */ /* Source Cell {{{ */ -@interface SourceCell : CYTableViewCell < - ContentDelegate +@interface SourceCell : CyteTableViewCell < + CyteTableViewCellDelegate > { - UIImage *icon_; - NSString *origin_; - NSString *label_; + _H icon_; + _H origin_; + _H label_; } - (void) setSource:(Source *)source; @end -@implementation SourceCell +@implementation SourceCell + +- (void) _setImage:(UIImage *)image { + icon_ = image; + [content_ setNeedsDisplay]; +} + +- (void) _setSource:(Source *)source { + NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]); + + if (NSString *base = [source base]) + if ([base length] != 0) { + NSURL *url([NSURL URLWithString:[base stringByAppendingString:@"CydiaIcon.png"]]); + + if (NSData *data = [NSURLConnection + sendSynchronousRequest:[NSURLRequest + requestWithURL:url + //cachePolicy:NSURLRequestUseProtocolCachePolicy + //timeoutInterval:5 + ] -- (void) clearSource { - [icon_ release]; - [origin_ release]; - [label_ release]; + returningResponse:NULL + error:NULL + ]) + if (UIImage *image = [UIImage imageWithData:data]) + [self performSelectorOnMainThread:@selector(_setImage:) withObject:image waitUntilDone:NO]; + } - icon_ = nil; - origin_ = nil; - label_ = nil; + [pool release]; } - (void) setSource:(Source *)source { - [self clearSource]; + icon_ = [UIImage applicationImageNamed:@"unknown.png"]; - if (icon_ == nil) - icon_ = [UIImage applicationImageNamed:[NSString stringWithFormat:@"Sources/%@.png", [source host]]]; - if (icon_ == nil) - icon_ = [UIImage applicationImageNamed:@"unknown.png"]; - icon_ = [icon_ retain]; - - origin_ = [[source name] retain]; - label_ = [[source uri] retain]; + origin_ = [source name]; + label_ = [source uri]; [content_ setNeedsDisplay]; -} -- (void) dealloc { - [self clearSource]; - [super dealloc]; + [NSThread detachNewThreadSelector:@selector(_setSource:) toTarget:self withObject:source]; } - (SourceCell *) initWithFrame:(CGRect)frame reuseIdentifier:(NSString *)reuseIdentifier { @@ -8045,7 +8014,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { UIView *content([self contentView]); CGRect bounds([content bounds]); - content_ = [[ContentView alloc] initWithFrame:bounds]; + content_ = [[[CyteTableViewCellContentView alloc] initWithFrame:bounds] autorelease]; [content_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; [content_ setBackgroundColor:[UIColor whiteColor]]; [content addSubview:content_]; @@ -8083,7 +8052,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { /* Source Controller {{{ */ @interface SourceController : FilteredPackageListController { _transient Source *source_; - NSString *key_; + _H key_; } - (id) initWithDatabase:(Database *)database source:(Source *)source; @@ -8093,21 +8062,21 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { @implementation SourceController - (NSURL *) navigationURL { - return [NSURL URLWithString:[NSString stringWithFormat:@"cydia://sources/%@", [source_ name]]]; + return [NSURL URLWithString:[NSString stringWithFormat:@"cydia://sources/%@", [key_ stringByAddingPercentEscapesIncludingReserved]]]; } - (id) initWithDatabase:(Database *)database source:(Source *)source { if ((self = [super initWithDatabase:database title:[source label] filter:@selector(isVisibleInSource:) with:source]) != nil) { source_ = source; - key_ = [[source key] retain]; + key_ = [source key]; } return self; } - (void) reloadData { source_ = [database_ sourceWithKey:key_]; - [key_ release]; - key_ = [[source_ key] retain]; + key_ = [source_ key]; [self setObject:source_]; + [[self navigationItem] setTitle:[source_ label]]; [super reloadData]; @@ -8116,18 +8085,18 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { @end /* }}} */ /* Sources Controller {{{ */ -@interface SourcesController : CYViewController < +@interface SourcesController : CyteViewController < UITableViewDataSource, UITableViewDelegate > { _transient Database *database_; - UITableView *list_; - NSMutableArray *sources_; + _H list_; + _H sources_; int offset_; - NSString *href_; - UIProgressHUD *hud_; - NSError *error_; + _H href_; + _H hud_; + _H error_; //NSURLConnection *installer_; NSURLConnection *trivial_; @@ -8154,19 +8123,12 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) dealloc { - [self releaseSubviews]; - - [href_ release]; - [hud_ release]; - [error_ release]; - //[self _releaseConnection:installer_]; [self _releaseConnection:trivial_]; [self _releaseConnection:trivial_gz_]; [self _releaseConnection:trivial_bz2_]; //[self _releaseConnection:automatic_]; - [sources_ release]; [super dealloc]; } @@ -8243,9 +8205,11 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { - Source *source = [self sourceAtIndexPath:indexPath]; - [Sources_ removeObjectForKey:[source key]]; - [delegate_ syncData]; + if (editingStyle == UITableViewCellEditingStyleDelete) { + Source *source = [self sourceAtIndexPath:indexPath]; + [Sources_ removeObjectForKey:[source key]]; + [delegate_ syncData]; + } } - (void) complete { @@ -8291,6 +8255,11 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { trivial_bz2_ == nil && trivial_gz_ == nil ) { + [delegate_ releaseNetworkActivityIndicator]; + + [delegate_ removeProgressHUD:hud_]; + hud_ = nil; + bool defer(false); if (cydia_) { @@ -8336,21 +8305,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [alert show]; } - [delegate_ releaseNetworkActivityIndicator]; - - [delegate_ removeProgressHUD:hud_]; - [hud_ autorelease]; - hud_ = nil; - - if (!defer) { - [href_ release]; - href_ = nil; - } - - if (error_ != nil) { - [error_ release]; - error_ = nil; - } + href_ = nil; + error_ = nil; } } @@ -8363,8 +8319,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { lprintf("connection:\"%s\" didFailWithError:\"%s\"", [href_ UTF8String], [[error localizedDescription] UTF8String]); - if (error_ != nil) - error_ = [error retain]; + error_ = error; [self _endConnection:connection]; } @@ -8373,8 +8328,10 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (NSURLConnection *) _requestHRef:(NSString *)href method:(NSString *)method { + NSURL *url([NSURL URLWithString:href]); + NSMutableURLRequest *request = [NSMutableURLRequest - requestWithURL:[NSURL URLWithString:href] + requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:120.0 ]; @@ -8383,8 +8340,11 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { if (Machine_ != NULL) [request setValue:[NSString stringWithUTF8String:Machine_] forHTTPHeaderField:@"X-Machine"]; - if (UniqueID_ != nil) - [request setValue:UniqueID_ forHTTPHeaderField:@"X-Unique-ID"]; + + if ([url isCydiaSecure]) { + if (UniqueID_ != nil) + [request setValue:UniqueID_ forHTTPHeaderField:@"X-Unique-ID"]; + } return [[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease]; } @@ -8403,7 +8363,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { href_ = [href stringByAppendingString:@"/"]; else href_ = href; - href_ = [href_ retain]; trivial_ = [[self _requestHRef:[href_ stringByAppendingString:@"Packages"] method:@"HEAD"] retain]; trivial_bz2_ = [[self _requestHRef:[href_ stringByAppendingString:@"Packages.bz2"] method:@"HEAD"] retain]; @@ -8413,7 +8372,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { cydia_ = false; // XXX: this is stupid - hud_ = [[delegate_ addProgressHUD] retain]; + hud_ = [delegate_ addProgressHUD]; [hud_ setText:UCLocalize("VERIFYING_URL")]; [delegate_ retainNetworkActivityIndicator]; } break; @@ -8441,7 +8400,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { _nodefault } - [href_ release]; href_ = nil; [alert dismissWithClickedButtonIndex:-1 animated:YES]; @@ -8451,28 +8409,32 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (void) loadView { [self setView:[[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease]]; - list_ = [[UITableView alloc] initWithFrame:[[self view] bounds] style:UITableViewStylePlain]; + list_ = [[[UITableView alloc] initWithFrame:[[self view] bounds] style:UITableViewStylePlain] autorelease]; [list_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; [list_ setRowHeight:56]; - [list_ setDataSource:self]; + [(UITableView *) list_ setDataSource:self]; [list_ setDelegate:self]; [[self view] addSubview:list_]; } - (void) viewDidLoad { + [super viewDidLoad]; + [[self navigationItem] setTitle:UCLocalize("SOURCES")]; [self updateButtonsForEditingStatus:NO animated:NO]; } - (void) releaseSubviews { - [list_ release]; list_ = nil; + + sources_ = nil; + + [super releaseSubviews]; } - (id) initWithDatabase:(Database *)database { if ((self = [super init]) != nil) { database_ = database; - sources_ = [[NSMutableArray arrayWithCapacity:16] retain]; } return self; } @@ -8483,7 +8445,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { if ([database_ popErrorWithTitle:UCLocalize("SOURCES") forOperation:list.ReadMainList()]) return; - [sources_ removeAllObjects]; + sources_ = [NSMutableArray arrayWithCapacity:16]; [sources_ addObjectsFromArray:[database_ sources]]; _trace(); [sources_ sortUsingSelector:@selector(compareByNameAndType:)]; @@ -8514,7 +8476,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { ] autorelease]; [alert setContext:@"source"]; - [alert setTransform:CGAffineTransformTranslate([alert transform], 0.0, 100.0)]; [alert setNumberOfRows:1]; [alert addTextFieldWithValue:@"http://" label:@""]; @@ -8571,16 +8532,16 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { /* }}} */ /* Settings Controller {{{ */ -@interface SettingsController : CYViewController < +@interface SettingsController : CyteViewController < UITableViewDataSource, UITableViewDelegate > { _transient Database *database_; // XXX: ok, "roledelegate_"?... _transient id roledelegate_; - UITableView *table_; - UISegmentedControl *segment_; - UIView *container_; + _H table_; + _H segment_; + _H container_; } - (void) showDoneButton; @@ -8590,19 +8551,13 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { @implementation SettingsController -- (void) dealloc { - [self releaseSubviews]; - - [super dealloc]; -} - - (void) loadView { [self setView:[[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease]]; - table_ = [[UITableView alloc] initWithFrame:[[self view] bounds] style:UITableViewStyleGrouped]; + table_ = [[[UITableView alloc] initWithFrame:[[self view] bounds] style:UITableViewStyleGrouped] autorelease]; [table_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; [table_ setDelegate:self]; - [table_ setDataSource:self]; + [(UITableView *) table_ setDataSource:self]; [[self view] addSubview:table_]; NSArray *items = [NSArray arrayWithObjects: @@ -8610,12 +8565,14 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { UCLocalize("HACKER"), UCLocalize("DEVELOPER"), nil]; - segment_ = [[UISegmentedControl alloc] initWithItems:items]; - container_ = [[UIView alloc] initWithFrame:CGRectMake(0, 0, [[self view] frame].size.width, 44.0f)]; + segment_ = [[[UISegmentedControl alloc] initWithItems:items] autorelease]; + container_ = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, [[self view] frame].size.width, 44.0f)] autorelease]; [container_ addSubview:segment_]; } - (void) viewDidLoad { + [super viewDidLoad]; + [[self navigationItem] setTitle:UCLocalize("WHO_ARE_YOU")]; int index = -1; @@ -8632,14 +8589,11 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) releaseSubviews { - [table_ release]; table_ = nil; - - [segment_ release]; segment_ = nil; - - [container_ release]; container_ = nil; + + [super releaseSubviews]; } - (id) initWithDatabase:(Database *)database delegate:(id)delegate { @@ -8762,28 +8716,23 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (void) reloadData { [super reloadData]; + [table_ reloadData]; } @end /* }}} */ /* Stash Controller {{{ */ -@interface StashController : CYViewController { - UIActivityIndicatorView *spinner_; - UILabel *status_; - UILabel *caption_; +@interface StashController : CyteViewController { + _H spinner_; + _H status_; + _H caption_; } @end @implementation StashController -- (void) dealloc { - [self releaseSubviews]; - - [super dealloc]; -} - - (void) loadView { [self setView:[[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease]]; [[self view] setBackgroundColor:[UIColor viewFlipsideBackgroundColor]]; @@ -8829,19 +8778,63 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) releaseSubviews { - [spinner_ release]; spinner_ = nil; - - [status_ release]; status_ = nil; - - [caption_ release]; caption_ = nil; + + [super releaseSubviews]; } @end /* }}} */ +@interface CYURLCache : SDURLCache { +} + +@end + +@implementation CYURLCache + +- (void) logEvent:(NSString *)event forRequest:(NSURLRequest *)request { +#if !ForRelease + if (false); + else if ([event isEqualToString:@"no-cache"]) + event = @"!!!"; + else if ([event isEqualToString:@"store"]) + event = @">>>"; + else if ([event isEqualToString:@"invalid"]) + event = @"???"; + else if ([event isEqualToString:@"memory"]) + event = @"mem"; + else if ([event isEqualToString:@"disk"]) + event = @"ssd"; + else if ([event isEqualToString:@"miss"]) + event = @"---"; + + NSLog(@"%@: %@", event, [[request URL] absoluteString]); +#endif +} + +- (void) storeCachedResponse:(NSCachedURLResponse *)cached forRequest:(NSURLRequest *)request { + if (NSURLResponse *response = [cached response]) + if (NSString *mime = [response MIMEType]) + if ([mime isEqualToString:@"text/cache-manifest"]) { + NSURL *url([response URL]); + +#if !ForRelease + NSLog(@"###: %@", [url absoluteString]); +#endif + + @synchronized (HostConfig_) { + [CachedURLs_ addObject:url]; + } + } + + [super storeCachedResponse:cached forRequest:request]; +} + +@end + @interface Cydia : UIApplication < ConfirmationControllerDelegate, DatabaseDelegate, @@ -8849,23 +8842,21 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { UINavigationControllerDelegate, UITabBarControllerDelegate > { - // XXX: evaluate all fields for _transient + _H window_; + _H tabbar_; + _H emulated_; - UIWindow *window_; - CYTabBarController *tabbar_; - CYEmulatedLoadingController *emulated_; - - NSMutableArray *essential_; - NSMutableArray *broken_; + _H essential_; + _H broken_; Database *database_; - NSURL *starturl_; + _H starturl_; unsigned locked_; unsigned activity_; - StashController *stash_; + _H stash_; bool loaded_; } @@ -8920,6 +8911,10 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } } +- (void) returnToCydia { + [self _loaded]; +} + - (void) _saveConfig { _trace(); MetaFile_.Sync(); @@ -8940,20 +8935,25 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { NSLog(@"failure to serialize metadata: %@", error); } } + + WriteSources(); } // Navigation controller for the queuing badge. -- (CYNavigationController *) queueNavigationController { +- (UINavigationController *) queueNavigationController { NSArray *controllers = [tabbar_ viewControllers]; return [controllers objectAtIndex:3]; } +- (void) unloadData { + [tabbar_ unloadData]; +} + - (void) _updateData { [self _saveConfig]; + [self unloadData]; - [tabbar_ reloadData]; - - CYNavigationController *navigation = [self queueNavigationController]; + UINavigationController *navigation = [self queueNavigationController]; id queuedelegate = nil; if ([[navigation viewControllers] count] > 0) @@ -8978,37 +8978,36 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { // - We already auto-refreshed this launch. // - Auto-refresh is disabled. if (recently || loaded_ || ManualRefresh) { - [self performSelectorOnMainThread:@selector(_loaded) withObject:nil waitUntilDone:NO]; - // If we are cancelling, we need to make sure it knows it's already loaded. loaded_ = true; - return; + + [self performSelectorOnMainThread:@selector(_loaded) withObject:nil waitUntilDone:NO]; } else { // We are going to load, so remember that. loaded_ = true; - } - SCNetworkReachabilityFlags flags; { - SCNetworkReachabilityRef reachability(SCNetworkReachabilityCreateWithName(NULL, "cydia.saurik.com")); - SCNetworkReachabilityGetFlags(reachability, &flags); - CFRelease(reachability); - } + SCNetworkReachabilityFlags flags; { + SCNetworkReachabilityRef reachability(SCNetworkReachabilityCreateWithName(NULL, "cydia.saurik.com")); + SCNetworkReachabilityGetFlags(reachability, &flags); + CFRelease(reachability); + } - // XXX: this elaborate mess is what Apple is using to determine this? :( - // XXX: do we care if the user has to intervene? maybe that's ok? - bool reachable( - (flags & kSCNetworkReachabilityFlagsReachable) != 0 && ( - (flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0 || ( - (flags & kSCNetworkReachabilityFlagsConnectionOnDemand) != 0 || - (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0 - ) && (flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0 || - (flags & kSCNetworkReachabilityFlagsIsWWAN) != 0 - ) - ); + // XXX: this elaborate mess is what Apple is using to determine this? :( + // XXX: do we care if the user has to intervene? maybe that's ok? + bool reachable( + (flags & kSCNetworkReachabilityFlagsReachable) != 0 && ( + (flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0 || ( + (flags & kSCNetworkReachabilityFlagsConnectionOnDemand) != 0 || + (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0 + ) && (flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0 || + (flags & kSCNetworkReachabilityFlagsIsWWAN) != 0 + ) + ); - // If we can reach the server, auto-refresh! - if (reachable) - [tabbar_ performSelectorOnMainThread:@selector(setUpdate:) withObject:update waitUntilDone:NO]; + // If we can reach the server, auto-refresh! + if (reachable) + [tabbar_ performSelectorOnMainThread:@selector(setUpdate:) withObject:update waitUntilDone:NO]; + } [pool release]; } @@ -9017,7 +9016,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [NSThread detachNewThreadSelector:@selector(_refreshIfPossible:) toTarget:self withObject:[Metadata_ objectForKey:@"LastUpdate"]]; } -- (void) _reloadDataWithInvocation:(NSInvocation *)invocation { +- (void) reloadDataWithInvocation:(NSInvocation *)invocation { +@synchronized (self) { UIProgressHUD *hud(loaded_ ? [self addProgressHUD] : nil); [hud setText:UCLocalize("RELOADING_DATA")]; @@ -9042,8 +9042,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } } - NSLog(@"changes:#%u", changes); - UITabBarItem *changesItem = [[[tabbar_ viewControllers] objectAtIndex:2] tabBarItem]; if (changes != 0) { _trace(); @@ -9059,9 +9057,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } [self _updateData]; - - [self refreshIfPossible]; -} +} } - (void) updateData { [self _updateData]; @@ -9069,12 +9065,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (void) update_ { [database_ update]; -} - -- (void) complete { - @synchronized (self) { - [self _reloadDataWithInvocation:nil]; - } + [self performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:YES]; } - (void) disemulate { @@ -9083,13 +9074,12 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [window_ addSubview:[tabbar_ view]]; [[emulated_ view] removeFromSuperview]; - [emulated_ release]; emulated_ = nil; [window_ setUserInteractionEnabled:YES]; } - (void) presentModalViewController:(UIViewController *)controller force:(BOOL)force { - UINavigationController *navigation([[[CYNavigationController alloc] initWithRootViewController:controller] autorelease]); + UINavigationController *navigation([[[UINavigationController alloc] initWithRootViewController:controller] autorelease]); if (IsWildcat_) [navigation setModalPresentationStyle:UIModalPresentationFormSheet]; @@ -9132,47 +9122,31 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [self performSelectorOnMainThread:@selector(repairWithInvocation:) withObject:[NSInvocation invocationWithSelector:selector forTarget:database_] waitUntilDone:YES]; } +- (void) reloadData { + [self reloadDataWithInvocation:nil]; + if ([database_ progressDelegate] == nil) + [self _loaded]; +} + - (void) syncData { [self _saveConfig]; - - FILE *file(fopen("/etc/apt/sources.list.d/cydia.list", "w")); - _assert(file != NULL); - - for (NSString *key in [Sources_ allKeys]) { - NSDictionary *source([Sources_ objectForKey:key]); - - fprintf(file, "%s %s %s\n", - [[source objectForKey:@"Type"] UTF8String], - [[source objectForKey:@"URI"] UTF8String], - [[source objectForKey:@"Distribution"] UTF8String] - ); - } - - fclose(file); - [self detachNewProgressSelector:@selector(update_) toTarget:self forController:nil title:@"UPDATING_SOURCES"]; - - [self complete]; } -- (void) addTrivialSource:(NSString *)href { - [Sources_ setObject:[NSDictionary dictionaryWithObjectsAndKeys: - @"deb", @"Type", - href, @"URI", - @"./", @"Distribution", - nil] forKey:[NSString stringWithFormat:@"deb:%@:./", href]]; +- (void) addSource:(NSDictionary *) source { + AddSource(source); +} - Changed_ = true; +- (void) addSource:(NSString *)href withDistribution:(NSString *)distribution andSections:(NSArray *)sections { + AddSource(href, distribution, sections); } -- (void) reloadDataWithInvocation:(NSInvocation *)invocation { - @synchronized (self) { - [self _reloadDataWithInvocation:invocation]; - } +- (void) addTrivialSource:(NSString *)href { + AddSource(href, @"./"); } -- (void) reloadData { - [self reloadDataWithInvocation:nil]; +- (void) updateValues { + Changed_ = true; } - (void) resolve { @@ -9196,8 +9170,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { ConfirmationController *page([[[ConfirmationController alloc] initWithDatabase:database_] autorelease]); [page setDelegate:self]; - CYNavigationController *confirm_([[[CYNavigationController alloc] initWithRootViewController:page] autorelease]); - [confirm_ setDelegate:self]; + UINavigationController *confirm_([[[UINavigationController alloc] initWithRootViewController:page] autorelease]); if (IsWildcat_) [confirm_ setModalPresentationStyle:UIModalPresentationFormSheet]; @@ -9253,20 +9226,21 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } } +- (void) perform_ { + [database_ perform]; + [self performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:YES]; +} + - (void) confirmWithNavigationController:(UINavigationController *)navigation { Queuing_ = false; ++locked_; - [self detachNewProgressSelector:@selector(perform) toTarget:database_ forController:navigation title:@"RUNNING"]; + [self detachNewProgressSelector:@selector(perform_) toTarget:self forController:navigation title:@"RUNNING"]; --locked_; - [self complete]; + [self refreshIfPossible]; } - (void) showSettings { - SettingsController *role = [[[SettingsController alloc] initWithDatabase:database_ delegate:self] autorelease]; - CYNavigationController *nav = [[[CYNavigationController alloc] initWithRootViewController:role] autorelease]; - if (IsWildcat_) - [nav setModalPresentationStyle:UIModalPresentationFormSheet]; - [tabbar_ presentModalViewController:nav animated:YES]; + [self presentModalViewController:[[[SettingsController alloc] initWithDatabase:database_ delegate:self] autorelease] force:NO]; } - (void) retainNetworkActivityIndicator { @@ -9316,7 +9290,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } else if ([context isEqualToString:@"fixhalf"]) { if (button == [alert cancelButtonIndex]) { @synchronized (self) { - for (Package *broken in broken_) { + for (Package *broken in (id) broken_) { [broken remove]; NSString *id = [broken id]; @@ -9338,7 +9312,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } else if ([context isEqualToString:@"upgrade"]) { if (button == [alert firstOtherButtonIndex]) { @synchronized (self) { - for (Package *essential in essential_) + for (Package *essential in (id) essential_) [essential install]; [self resolve]; @@ -9354,10 +9328,14 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } } -- (void) system:(NSString *)command { _pooled +- (void) system:(NSString *)command { + NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]); + _trace(); system([command UTF8String]); _trace(); + + [pool release]; } - (void) applicationWillSuspend { @@ -9412,32 +9390,36 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (UIProgressHUD *) addProgressHUD { - UIProgressHUD *hud([[[UIProgressHUD alloc] initWithWindow:window_] autorelease]); + UIProgressHUD *hud([[[UIProgressHUD alloc] init] autorelease]); [hud setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; [window_ setUserInteractionEnabled:NO]; - [hud show:YES]; - UIViewController *target = tabbar_; - while ([target modalViewController] != nil) target = [target modalViewController]; - [[target view] addSubview:hud]; + UIViewController *target(tabbar_); + if (UIViewController *modal = [target modalViewController]) + target = modal; + + UIView *view([target view]); + [view addSubview:hud]; + + [hud showInView:[tabbar_ view]]; ++locked_; return hud; } - (void) removeProgressHUD:(UIProgressHUD *)hud { - [hud show:NO]; + --locked_; + [hud hide]; [hud removeFromSuperview]; [window_ setUserInteractionEnabled:YES]; - --locked_; } -- (CYViewController *) pageForPackage:(NSString *)name { +- (CyteViewController *) pageForPackage:(NSString *)name { return [[[CYPackageController alloc] initWithDatabase:database_ forPackage:name] autorelease]; } -- (CYViewController *) pageForURL:(NSURL *)url forExternal:(BOOL)external { +- (CyteViewController *) pageForURL:(NSURL *)url forExternal:(BOOL)external { NSString *scheme([[url scheme] lowercaseString]); if ([[url absoluteString] length] <= [scheme length] + 3) return nil; @@ -9452,12 +9434,12 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { NSString *base([components objectAtIndex:0]); - CYViewController *controller = nil; + CyteViewController *controller = nil; if ([base isEqualToString:@"url"]) { // This kind of URL can contain slashes in the argument, so we can't parse them below. NSString *destination = [[url absoluteString] substringFromIndex:([scheme length] + [@"://" length] + [base length] + [@"/" length])]; - controller = [[[CYBrowserController alloc] initWithURL:[NSURL URLWithString:destination]] autorelease]; + controller = [[[CydiaWebViewController alloc] initWithURL:[NSURL URLWithString:destination]] autorelease]; } else if (!external && [components count] == 1) { if ([base isEqualToString:@"manage"]) { controller = [[[ManageController alloc] init] autorelease]; @@ -9476,7 +9458,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } if ([base isEqualToString:@"search"]) { - controller = [[[SearchController alloc] initWithDatabase:database_] autorelease]; + controller = [[[SearchController alloc] initWithDatabase:database_ query:nil] autorelease]; } if ([base isEqualToString:@"changes"]) { @@ -9494,8 +9476,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } if (!external && [base isEqualToString:@"search"]) { - controller = [[[SearchController alloc] initWithDatabase:database_] autorelease]; - [(SearchController *)controller setSearchTerm:argument]; + controller = [[[SearchController alloc] initWithDatabase:database_ query:argument] autorelease]; } if (!external && [base isEqualToString:@"sections"]) { @@ -9509,7 +9490,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { controller = [[[SourcesController alloc] initWithDatabase:database_] autorelease]; [(SourcesController *)controller showAddSourcePrompt]; } else { - Source *source = [database_ sourceWithKey:argument]; + Source *source = [database_ sourceWithKey:[argument stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; controller = [[[SourceController alloc] initWithDatabase:database_ source:source] autorelease]; } } @@ -9539,10 +9520,10 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (BOOL) openCydiaURL:(NSURL *)url forExternal:(BOOL)external { - CYViewController *page([self pageForURL:url forExternal:external]); + CyteViewController *page([self pageForURL:url forExternal:external]); if (page != nil) { - CYNavigationController *nav = [[[CYNavigationController alloc] init] autorelease]; + UINavigationController *nav = [[[UINavigationController alloc] init] autorelease]; [nav setViewControllers:[NSArray arrayWithObject:page]]; [tabbar_ setUnselectedViewController:nav]; } @@ -9553,8 +9534,10 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (void) applicationOpenURL:(NSURL *)url { [super applicationOpenURL:url]; - if (!loaded_) starturl_ = [url retain]; - else [self openCydiaURL:url forExternal:YES]; + if (!loaded_) + starturl_ = url; + else + [self openCydiaURL:url forExternal:YES]; } - (void) applicationWillResignActive:(UIApplication *)application { @@ -9566,15 +9549,19 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [super applicationWillResignActive:application]; } -- (void) applicationWillTerminate:(UIApplication *)application { - Changed_ = true; +- (void) saveState { [Metadata_ setObject:[tabbar_ navigationURLCollection] forKey:@"InterfaceState"]; [Metadata_ setObject:[NSDate date] forKey:@"LastClosed"]; [Metadata_ setObject:[NSNumber numberWithInt:[tabbar_ selectedIndex]] forKey:@"InterfaceIndex"]; + Changed_ = true; [self _saveConfig]; } +- (void) applicationWillTerminate:(UIApplication *)application { + [self saveState]; +} + - (void) setConfigurationData:(NSString *)data { static Pcre conffile_r("^'(.*)' '(.*)' ([01]) ([01])$"); @@ -9604,13 +9591,13 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (void) addStashController { ++locked_; - stash_ = [[StashController alloc] init]; + stash_ = [[[StashController alloc] init] autorelease]; [window_ addSubview:[stash_ view]]; } - (void) removeStashController { [[stash_ view] removeFromSuperview]; - [stash_ release]; + stash_ = nil; --locked_; } @@ -9631,7 +9618,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) setupViewControllers { - tabbar_ = [[CYTabBarController alloc] initWithDatabase:database_]; + tabbar_ = [[[CYTabBarController alloc] initWithDatabase:database_] autorelease]; NSMutableArray *items([NSMutableArray arrayWithObjects: [[[UITabBarItem alloc] initWithTitle:@"Cydia" image:[UIImage applicationImageNamed:@"home.png"] tag:0] autorelease], @@ -9649,7 +9636,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { NSMutableArray *controllers([NSMutableArray array]); for (UITabBarItem *item in items) { - CYNavigationController *controller([[[CYNavigationController alloc] initWithDatabase:database_] autorelease]); + UINavigationController *controller([[[UINavigationController alloc] init] autorelease]); [controller setTabBarItem:item]; [controllers addObject:controller]; } @@ -9658,37 +9645,54 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [tabbar_ setUpdateDelegate:self]; } -- (void) addCydiaHost:(NSString *)host { - [CydiaHosts_ addObject:host]; +- (void) _sendMemoryWarningNotification { + [[NSNotificationCenter defaultCenter] postNotificationName:@"UIApplicationDidReceiveMemoryWarningNotification" object:[UIApplication sharedApplication]]; +} + +- (void) _sendMemoryWarningNotifications { + while (true) { + [self performSelectorOnMainThread:@selector(_sendMemoryWarningNotification) withObject:nil waitUntilDone:NO]; + usleep(250000); + } } - (void) applicationDidFinishLaunching:(id)unused { + //[NSThread detachNewThreadSelector:@selector(_sendMemoryWarningNotifications) toTarget:self withObject:nil]; + _trace(); if ([self respondsToSelector:@selector(setApplicationSupportsShakeToEdit:)]) [self setApplicationSupportsShakeToEdit:NO]; - [self addCydiaHost:[[NSURL URLWithString:CydiaURL(@"")] host]]; + @synchronized (HostConfig_) { + [BridgedHosts_ addObject:[[NSURL URLWithString:CydiaURL(@"")] host]]; + } - [NSURLCache setSharedURLCache:[[[SDURLCache alloc] + [NSURLCache setSharedURLCache:[[[CYURLCache alloc] initWithMemoryCapacity:524288 diskCapacity:10485760 diskPath:[NSString stringWithFormat:@"%@/Library/Caches/com.saurik.Cydia/SDURLCache", @"/var/root"] ] autorelease]]; - [CYBrowserController _initialize]; + [CydiaWebViewController _initialize]; [NSURLProtocol registerClass:[CydiaURLProtocol class]]; - Font12_ = [[UIFont systemFontOfSize:12] retain]; - Font12Bold_ = [[UIFont boldSystemFontOfSize:12] retain]; - Font14_ = [[UIFont systemFontOfSize:14] retain]; - Font18Bold_ = [[UIFont boldSystemFontOfSize:18] retain]; - Font22Bold_ = [[UIFont boldSystemFontOfSize:22] retain]; + // this would disallow http{,s} URLs from accessing this data + //[WebView registerURLSchemeAsLocal:@"cydia"]; + + Font12_ = [UIFont systemFontOfSize:12]; + Font12Bold_ = [UIFont boldSystemFontOfSize:12]; + Font14_ = [UIFont systemFontOfSize:14]; + Font18Bold_ = [UIFont boldSystemFontOfSize:18]; + Font22Bold_ = [UIFont boldSystemFontOfSize:22]; - essential_ = [[NSMutableArray alloc] initWithCapacity:4]; - broken_ = [[NSMutableArray alloc] initWithCapacity:4]; + essential_ = [NSMutableArray arrayWithCapacity:4]; + broken_ = [NSMutableArray arrayWithCapacity:4]; - window_ = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; + // XXX: I really need this thing... like, seriously... I'm sorry + [[[AppCacheController alloc] initWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/appcache/", UI_]]] reloadData]; + + window_ = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease]; [window_ orderFront:self]; [window_ makeKey:self]; [window_ setHidden:NO]; @@ -9719,18 +9723,33 @@ _trace(); [window_ setUserInteractionEnabled:NO]; [self setupViewControllers]; - emulated_ = [[CYEmulatedLoadingController alloc] initWithDatabase:database_]; + emulated_ = [[[CydiaLoadingViewController alloc] init] autorelease]; [window_ addSubview:[emulated_ view]]; [self performSelector:@selector(loadData) withObject:nil afterDelay:0]; _trace(); } +- (NSArray *) defaultStartPages { + NSMutableArray *standard = [NSMutableArray array]; + [standard addObject:[NSArray arrayWithObject:@"cydia://home"]]; + [standard addObject:[NSArray arrayWithObject:@"cydia://sections"]]; + [standard addObject:[NSArray arrayWithObject:@"cydia://changes"]]; + if (!IsWildcat_) { + [standard addObject:[NSArray arrayWithObject:@"cydia://manage"]]; + } else { + [standard addObject:[NSArray arrayWithObject:@"cydia://installed"]]; + [standard addObject:[NSArray arrayWithObject:@"cydia://sources"]]; + } + [standard addObject:[NSArray arrayWithObject:@"cydia://search"]]; + return standard; +} + - (void) loadData { _trace(); if (Role_ == nil) { [window_ setUserInteractionEnabled:YES]; - [self presentModalViewController:[[[SettingsController alloc] initWithDatabase:database_ delegate:self] autorelease] force:NO]; + [self showSettings]; return; } else { if ([emulated_ modalViewController] != nil) @@ -9738,56 +9757,63 @@ _trace(); [window_ setUserInteractionEnabled:NO]; } - [self reloadData]; + [self reloadDataWithInvocation:nil]; + [self refreshIfPossible]; PrintTimes(); [self disemulate]; - int selectedIndex = 0; - NSMutableArray *items = nil; + int savedIndex = [[Metadata_ objectForKey:@"InterfaceIndex"] intValue]; + NSArray *saved = [[Metadata_ objectForKey:@"InterfaceState"] mutableCopy]; + int standardIndex = 0; + NSArray *standard = [self defaultStartPages]; - bool recently = false; - NSDate *closed([Metadata_ objectForKey:@"LastClosed"]); - if (closed != nil) { + BOOL valid = YES; + + if (saved == nil) + valid = NO; + + NSDate *closed = [Metadata_ objectForKey:@"LastClosed"]; + if (valid && closed != nil) { NSTimeInterval interval([closed timeIntervalSinceNow]); // XXX: Is 15 minutes the optimal time here? - if (interval <= 0 && interval > -(15*60)) - recently = true; + if (interval > 0 && interval <= -(15*60)) + valid = NO; } - items = [[Metadata_ objectForKey:@"InterfaceState"] mutableCopy]; - selectedIndex = [[Metadata_ objectForKey:@"InterfaceIndex"] intValue]; - - BOOL enough = YES; - for (NSArray *entry in items) - if ([entry count] <= 0) - enough = NO; + if (valid && [saved count] != [standard count]) + valid = NO; - if (!recently || !items || !enough) { - selectedIndex = 0; - items = [NSMutableArray array]; - [items addObject:[NSArray arrayWithObject:@"cydia://home"]]; - [items addObject:[NSArray arrayWithObject:@"cydia://sections"]]; - [items addObject:[NSArray arrayWithObject:@"cydia://changes"]]; - if (!IsWildcat_) { - [items addObject:[NSArray arrayWithObject:@"cydia://manage"]]; - } else { - [items addObject:[NSArray arrayWithObject:@"cydia://installed"]]; - [items addObject:[NSArray arrayWithObject:@"cydia://sources"]]; + if (valid) { + for (unsigned int i = 0; i < [standard count]; i++) { + NSArray *std = [standard objectAtIndex:i], *sav = [saved objectAtIndex:i]; + // XXX: The "hasPrefix" sanity check here could be, in theory, fooled, + // but it's good enough for now. + if ([sav count] == 0 || ![[sav objectAtIndex:0] hasPrefix:[std objectAtIndex:0]]) { + valid = NO; + break; + } } - [items addObject:[NSArray arrayWithObject:@"cydia://search"]]; } - [tabbar_ setSelectedIndex:selectedIndex]; + NSArray *items = nil; + if (valid) { + [tabbar_ setSelectedIndex:savedIndex]; + items = saved; + } else { + [tabbar_ setSelectedIndex:standardIndex]; + items = standard; + } + for (unsigned int tab = 0; tab < [[tabbar_ viewControllers] count]; tab++) { NSArray *stack = [items objectAtIndex:tab]; - CYNavigationController *navigation = [[tabbar_ viewControllers] objectAtIndex:tab]; + UINavigationController *navigation = [[tabbar_ viewControllers] objectAtIndex:tab]; NSMutableArray *current = [NSMutableArray array]; for (unsigned int nav = 0; nav < [stack count]; nav++) { NSString *addr = [stack objectAtIndex:nav]; NSURL *url = [NSURL URLWithString:addr]; - CYViewController *page = [self pageForURL:url forExternal:NO]; + CyteViewController *page = [self pageForURL:url forExternal:NO]; if (page != nil) [current addObject:page]; } @@ -9798,7 +9824,6 @@ _trace(); // (Try to) show the startup URL. if (starturl_ != nil) { [self openCydiaURL:starturl_ forExternal:NO]; - [starturl_ release]; starturl_ = nil; } } @@ -9851,55 +9876,84 @@ MSHook(void, UIWebDocumentView$_setUIKitDelegate$, UIWebDocumentView *self, SEL return _UIWebDocumentView$_setUIKitDelegate$(self, _cmd, delegate); } -static NSNumber *shouldPlayKeyboardSounds; +static NSSet *MobilizedFiles_; + +static NSURL *MobilizeURL(NSURL *url) { + NSString *path([url path]); + if ([path hasPrefix:@"/var/root/"]) { + NSString *file([path substringFromIndex:10]); + if ([MobilizedFiles_ containsObject:file]) + url = [NSURL fileURLWithPath:[@"/var/mobile/" stringByAppendingString:file] isDirectory:NO]; + } -Class $UIHardware; + return url; +} -MSHook(void, UIHardware$_playSystemSound$, Class self, SEL _cmd, int sound) { - switch (sound) { - case 1104: // Keyboard Button Clicked - case 1105: // Keyboard Delete Repeated - if (shouldPlayKeyboardSounds == nil) { - NSDictionary *dict([[[NSDictionary alloc] initWithContentsOfFile:@"/var/mobile/Library/Preferences/com.apple.preferences.sounds.plist"] autorelease]); - shouldPlayKeyboardSounds = [([dict objectForKey:@"keyboard"] ?: (id) kCFBooleanTrue) retain]; - } +Class $CFXPreferencesPropertyListSource; +@class CFXPreferencesPropertyListSource; - if (![shouldPlayKeyboardSounds boolValue]) - break; +MSHook(BOOL, CFXPreferencesPropertyListSource$_backingPlistChangedSinceLastSync, CFXPreferencesPropertyListSource *self, SEL _cmd) { + NSURL *&url(MSHookIvar(self, "_url")), *old(url); + NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]); + url = MobilizeURL(url); + BOOL value(_CFXPreferencesPropertyListSource$_backingPlistChangedSinceLastSync(self, _cmd)); + //NSLog(@"%@ %s", [url absoluteString], value ? "YES" : "NO"); + url = old; + [pool release]; + return value; +} - default: - _UIHardware$_playSystemSound$(self, _cmd, sound); - } +MSHook(void *, CFXPreferencesPropertyListSource$createPlistFromDisk, CFXPreferencesPropertyListSource *self, SEL _cmd) { + NSURL *&url(MSHookIvar(self, "_url")), *old(url); + NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]); + url = MobilizeURL(url); + void *value(_CFXPreferencesPropertyListSource$createPlistFromDisk(self, _cmd)); + //NSLog(@"%@ %@", [url absoluteString], value); + url = old; + [pool release]; + return value; } -Class $UIApplication; +Class $NSURLConnection; + +MSHook(id, NSURLConnection$init$, NSURLConnection *self, SEL _cmd, NSURLRequest *request, id delegate, BOOL usesCache, int64_t maxContentLength, BOOL startImmediately, NSDictionary *connectionProperties) { + NSMutableURLRequest *copy([request mutableCopy]); + + NSURL *url([copy URL]); -MSHook(void, UIApplication$_updateApplicationAccessibility, UIApplication *self, SEL _cmd) { - static BOOL initialized = NO; - static BOOL started = NO; + NSString *href([url absoluteString]); + NSString *host([url host]); + NSString *scheme([[url scheme] lowercaseString]); - NSDictionary *dict([[[NSDictionary alloc] initWithContentsOfFile:@"/var/mobile/Library/Preferences/com.apple.Accessibility.plist"] autorelease]); - BOOL enabled = [[dict objectForKey:@"VoiceOverTouchEnabled"] boolValue] || [[dict objectForKey:@"VoiceOverTouchEnabledByiTunes"] boolValue]; + NSString *compound([NSString stringWithFormat:@"%@:%@", scheme, host]); - if ([self respondsToSelector:@selector(_accessibilityBundlePrincipalClass)]) { - id bundle = [self performSelector:@selector(_accessibilityBundlePrincipalClass)]; - if (![bundle respondsToSelector:@selector(_accessibilityStopServer)]) return; - if (![bundle respondsToSelector:@selector(_accessibilityStartServer)]) return; + @synchronized (HostConfig_) { + if ([copy respondsToSelector:@selector(setHTTPShouldUsePipelining:)]) + if ([PipelinedHosts_ containsObject:host] || [PipelinedHosts_ containsObject:compound]) + [copy setHTTPShouldUsePipelining:YES]; - if (initialized && !enabled) { - initialized = NO; - [bundle performSelector:@selector(_accessibilityStopServer)]; - } else if (enabled) { - initialized = YES; - if (!started) { - started = YES; - [bundle performSelector:@selector(_accessibilityStartServer)]; - } - } + if (NSString *control = [copy valueForHTTPHeaderField:@"Cache-Control"]) + if ([control isEqualToString:@"max-age=0"]) + if ([CachedURLs_ containsObject:href]) { +#if !ForRelease + NSLog(@"~~~: %@", href); +#endif + + [copy setCachePolicy:NSURLRequestReturnCacheDataDontLoad]; + + [copy setValue:nil forHTTPHeaderField:@"Cache-Control"]; + [copy setValue:nil forHTTPHeaderField:@"If-Modified-Since"]; + [copy setValue:nil forHTTPHeaderField:@"If-None-Match"]; + } } + + if ((self = _NSURLConnection$init$(self, _cmd, copy, delegate, usesCache, maxContentLength, startImmediately, connectionProperties)) != nil) { + } return self; } -int main(int argc, char *argv[]) { _pooled +int main(int argc, char *argv[]) { + NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]); + _trace(); UpdateExternalStatus(0); @@ -9929,15 +9983,43 @@ int main(int argc, char *argv[]) { _pooled NSLog(@"unknown UIUserInterfaceIdiom!"); } - CydiaHosts_ = [NSMutableSet setWithCapacity:2]; + SessionData_ = [NSMutableDictionary dictionaryWithCapacity:4]; + + HostConfig_ = [[[NSObject alloc] init] autorelease]; + @synchronized (HostConfig_) { + BridgedHosts_ = [NSMutableSet setWithCapacity:4]; + TokenHosts_ = [NSMutableSet setWithCapacity:4]; + InsecureHosts_ = [NSMutableSet setWithCapacity:4]; + PipelinedHosts_ = [NSMutableSet setWithCapacity:4]; + CachedURLs_ = [NSMutableSet setWithCapacity:32]; + } UI_ = CydiaURL([NSString stringWithFormat:@"ui/ios~%@", Idiom_]); PackageName = reinterpret_cast(method_getImplementation(class_getInstanceMethod([Package class], @selector(cyname)))); + MobilizedFiles_ = [NSMutableSet setWithObjects: + @"Library/Preferences/com.apple.Accessibility.plist", + @"Library/Preferences/com.apple.preferences.sounds.plist", + nil]; + /* Library Hacks {{{ */ class_addMethod(objc_getClass("DOMNodeList"), @selector(countByEnumeratingWithState:objects:count:), (IMP) &DOMNodeList$countByEnumeratingWithState$objects$count$, "I20@0:4^{NSFastEnumerationState}8^@12I16"); + $CFXPreferencesPropertyListSource = objc_getClass("CFXPreferencesPropertyListSource"); + + Method CFXPreferencesPropertyListSource$_backingPlistChangedSinceLastSync(class_getInstanceMethod($CFXPreferencesPropertyListSource, @selector(_backingPlistChangedSinceLastSync))); + if (CFXPreferencesPropertyListSource$_backingPlistChangedSinceLastSync != NULL) { + _CFXPreferencesPropertyListSource$_backingPlistChangedSinceLastSync = reinterpret_cast(method_getImplementation(CFXPreferencesPropertyListSource$_backingPlistChangedSinceLastSync)); + method_setImplementation(CFXPreferencesPropertyListSource$_backingPlistChangedSinceLastSync, reinterpret_cast(&$CFXPreferencesPropertyListSource$_backingPlistChangedSinceLastSync)); + } + + Method CFXPreferencesPropertyListSource$createPlistFromDisk(class_getInstanceMethod($CFXPreferencesPropertyListSource, @selector(createPlistFromDisk))); + if (CFXPreferencesPropertyListSource$createPlistFromDisk != NULL) { + _CFXPreferencesPropertyListSource$createPlistFromDisk = reinterpret_cast(method_getImplementation(CFXPreferencesPropertyListSource$createPlistFromDisk)); + method_setImplementation(CFXPreferencesPropertyListSource$createPlistFromDisk, reinterpret_cast(&$CFXPreferencesPropertyListSource$createPlistFromDisk)); + } + $WebDefaultUIKitDelegate = objc_getClass("WebDefaultUIKitDelegate"); Method UIWebDocumentView$_setUIKitDelegate$(class_getInstanceMethod([WebView class], @selector(_setUIKitDelegate:))); if (UIWebDocumentView$_setUIKitDelegate$ != NULL) { @@ -9945,37 +10027,40 @@ int main(int argc, char *argv[]) { _pooled method_setImplementation(UIWebDocumentView$_setUIKitDelegate$, reinterpret_cast(&$UIWebDocumentView$_setUIKitDelegate$)); } - $UIHardware = objc_getClass("UIHardware"); - Method UIHardware$_playSystemSound$(class_getClassMethod($UIHardware, @selector(_playSystemSound:))); - if (UIHardware$_playSystemSound$ != NULL) { - _UIHardware$_playSystemSound$ = reinterpret_cast(method_getImplementation(UIHardware$_playSystemSound$)); - method_setImplementation(UIHardware$_playSystemSound$, reinterpret_cast(&$UIHardware$_playSystemSound$)); - } - - $UIApplication = objc_getClass("UIApplication"); - Method UIApplication$_updateApplicationAccessibility(class_getInstanceMethod($UIApplication, @selector(_updateApplicationAccessibility))); - if (UIApplication$_updateApplicationAccessibility != NULL) { - _UIApplication$_updateApplicationAccessibility = reinterpret_cast(method_getImplementation(UIApplication$_updateApplicationAccessibility)); - method_setImplementation(UIApplication$_updateApplicationAccessibility, reinterpret_cast(&$UIApplication$_updateApplicationAccessibility)); + $NSURLConnection = objc_getClass("NSURLConnection"); + Method NSURLConnection$init$(class_getInstanceMethod($NSURLConnection, @selector(_initWithRequest:delegate:usesCache:maxContentLength:startImmediately:connectionProperties:))); + if (NSURLConnection$init$ != NULL) { + _NSURLConnection$init$ = reinterpret_cast(method_getImplementation(NSURLConnection$init$)); + method_setImplementation(NSURLConnection$init$, reinterpret_cast(&$NSURLConnection$init$)); } /* }}} */ /* Set Locale {{{ */ Locale_ = CFLocaleCopyCurrent(); Languages_ = [NSLocale preferredLanguages]; + //CFStringRef locale(CFLocaleGetIdentifier(Locale_)); //NSLog(@"%@", [Languages_ description]); const char *lang; - if (Languages_ == nil || [Languages_ count] == 0) + if (Locale_ != NULL) + lang = [(NSString *) CFLocaleGetIdentifier(Locale_) UTF8String]; + else if (Languages_ != nil && [Languages_ count] != 0) + lang = [[Languages_ objectAtIndex:0] UTF8String]; + else // XXX: consider just setting to C and then falling through? lang = NULL; - else { - lang = [[Languages_ objectAtIndex:0] UTF8String]; - setenv("LANG", lang, true); - std::setlocale(LC_ALL, lang); + + if (lang != NULL) { + Pcre pattern("^([a-z][a-z])(?:-[A-Za-z]*)?(_[A-Z][A-Z])?$"); + lang = !pattern(lang) ? NULL : [pattern->*@"%1$@%2$@" UTF8String]; } NSLog(@"Setting Language: %s", lang); + + if (lang != NULL) { + setenv("LANG", lang, true); + std::setlocale(LC_ALL, lang); + } /* }}} */ apr_app_initialize(&argc, const_cast(&argv), NULL); @@ -10045,30 +10130,11 @@ int main(int argc, char *argv[]) { _pooled else Machine_ = machine; - if (CFMutableDictionaryRef dict = IOServiceMatching("IOPlatformExpertDevice")) { - if (io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, dict)) { - if (CFTypeRef serial = IORegistryEntryCreateCFProperty(service, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0)) { - SerialNumber_ = [NSString stringWithString:(NSString *)serial]; - CFRelease(serial); - } - - if (CFTypeRef ecid = IORegistryEntrySearchCFProperty(service, kIODeviceTreePlane, CFSTR("unique-chip-id"), kCFAllocatorDefault, kIORegistryIterateRecursively)) { - NSData *data((NSData *) ecid); - size_t length([data length]); - uint8_t bytes[length]; - [data getBytes:bytes]; - char string[length * 2 + 1]; - for (size_t i(0); i != length; ++i) - sprintf(string + i * 2, "%.2X", bytes[length - i - 1]); - ChipID_ = [NSString stringWithUTF8String:string]; - CFRelease(ecid); - } - - IOObjectRelease(service); - } - } + SerialNumber_ = (NSString *) CYIOGetValue("IOService:/", @"IOPlatformSerialNumber"); + ChipID_ = [CYHex((NSData *) CYIOGetValue("IODeviceTree:/chosen", @"unique-chip-id"), true) uppercaseString]; + BBSNum_ = CYHex((NSData *) CYIOGetValue("IOService:/AppleARMPE/baseband", @"snum"), false); - UniqueID_ = [[UIDevice currentDevice] uniqueIdentifier]; + UniqueID_ = [device uniqueIdentifier]; CFStringRef (*$CTSIMSupportCopyMobileSubscriberCountryCode)(CFAllocatorRef); $CTSIMSupportCopyMobileSubscriberCountryCode = reinterpret_cast(dlsym(RTLD_DEFAULT, "CTSIMSupportCopyMobileSubscriberCountryCode")); @@ -10105,15 +10171,28 @@ int main(int argc, char *argv[]) { _pooled Settings_ = [Metadata_ objectForKey:@"Settings"]; Packages_ = [Metadata_ objectForKey:@"Packages"]; + + Values_ = [Metadata_ objectForKey:@"Values"]; Sections_ = [Metadata_ objectForKey:@"Sections"]; Sources_ = [Metadata_ objectForKey:@"Sources"]; Token_ = [Metadata_ objectForKey:@"Token"]; + + Version_ = [Metadata_ objectForKey:@"Version"]; + + @synchronized (HostConfig_) { + CydiaSource_ = [Metadata_ objectForKey:@"CydiaSource"]; + } } if (Settings_ != nil) Role_ = [Settings_ objectForKey:@"Role"]; + if (Values_ == nil) { + Values_ = [[[NSMutableDictionary alloc] initWithCapacity:4] autorelease]; + [Metadata_ setObject:Values_ forKey:@"Values"]; + } + if (Sections_ == nil) { Sections_ = [[[NSMutableDictionary alloc] initWithCapacity:32] autorelease]; [Metadata_ setObject:Sections_ forKey:@"Sections"]; @@ -10123,8 +10202,36 @@ int main(int argc, char *argv[]) { _pooled Sources_ = [[[NSMutableDictionary alloc] initWithCapacity:0] autorelease]; [Metadata_ setObject:Sources_ forKey:@"Sources"]; } + + if (Version_ == nil) { + Version_ = [NSNumber numberWithUnsignedInt:0]; + [Metadata_ setObject:Version_ forKey:@"Version"]; + } + + @synchronized (HostConfig_) { + if (CydiaSource_ == nil) { + CydiaSource_ = @"apt.saurik.com"; + [Metadata_ setObject:CydiaSource_ forKey:@"CydiaSource"]; + } + } + + if ([Version_ unsignedIntValue] == 0) { + AddSource(@"http://apt.thebigboss.org/repofiles/cydia/", @"stable", [NSMutableArray arrayWithObject:@"main"]); + AddSource(@"http://apt.modmyi.com/", @"stable", [NSMutableArray arrayWithObject:@"main"]); + AddSource(@"http://cydia.zodttd.com/repo/cydia/", @"stable", [NSMutableArray arrayWithObject:@"main"]); + AddSource(@"http://repo666.ultrasn0w.com/", @"./"); + + Version_ = [NSNumber numberWithUnsignedInt:1]; + [Metadata_ setObject:Version_ forKey:@"Version"]; + + [Metadata_ removeObjectForKey:@"LastUpdate"]; + + Changed_ = true; + } /* }}} */ + WriteSources(); + _trace(); MetaFile_.Open("/var/lib/cydia/metadata.cb0"); _trace(); @@ -10232,5 +10339,6 @@ int main(int argc, char *argv[]) { _pooled CGColorSpaceRelease(space_); CFRelease(Locale_); + [pool release]; return value; }