X-Git-Url: https://git.saurik.com/cydia.git/blobdiff_plain/d13577cfab7807489a69822d33776562428d002f..947a8eefa4cc11fbccdb9b1495ec0f0f28663bd9:/MobileCydia.mm?ds=sidebyside diff --git a/MobileCydia.mm b/MobileCydia.mm index 5c3cf2c6..05486472 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,21 @@ extern "C" { #include #include -#include #include -#include "UICaboodle/BrowserView.h" -#include "SDURLCache/SDURLCache.h" +#include "Menes/Menes.h" + +#include "CyteKit/PerlCompatibleRegEx.hpp" +#include "CyteKit/WebScriptObject-Cyte.h" +#include "CyteKit/WebViewController.h" +#include "CyteKit/stringWithUTF8Bytes.h" -#include "substrate.h" +#include "Cydia/ProgressEvent.h" -#include "Version.h" +#include "SDURLCache/SDURLCache.h" + +#include /* }}} */ /* Profiler {{{ */ @@ -208,6 +213,35 @@ void PrintTimes() { while (false); \ [_pool release]; +#define Cydia_ CYDIA_VERSION + +#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); @@ -239,154 +273,11 @@ 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]; -} - -@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 *); @@ -568,38 +459,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 +474,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 +481,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,52 +674,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_; @@ -1028,7 +824,6 @@ static UIColor *InstallingColor_; static UIColor *RemovingColor_; static NSString *App_; -static NSString *Home_; static BOOL Advanced_; static BOOL Ignored_; @@ -1067,6 +862,16 @@ static time_t now_; bool IsWildcat_; static CGFloat ScreenScale_; static NSString *Idiom_; + +static NSMutableDictionary *SessionData_; +static NSObject *HostConfig_; +static NSMutableSet *BridgedHosts_; +static NSMutableSet *PipelinedHosts_; + +static NSString *kCydiaProgressEventTypeError = @"Error"; +static NSString *kCydiaProgressEventTypeInformation = @"Information"; +static NSString *kCydiaProgressEventTypeStatus = @"Status"; +static NSString *kCydiaProgressEventTypeWarning = @"Warning"; /* }}} */ /* Display Helpers {{{ */ @@ -1134,6 +939,34 @@ bool isSectionVisible(NSString *section) { return hidden == nil || ![hidden boolValue]; } +static id 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, bool capital) { + 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, capital ? "%.2X" : "%.2x", bytes[reverse ? length - i - 1 : i]); + + return [NSString stringWithUTF8String:string]; +} + @class Cydia; /* Delegate Prototypes {{{ */ @@ -1166,57 +999,12 @@ bool isSectionVisible(NSString *section) { - (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; @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 @@ -1249,7 +1037,7 @@ class Status : virtual void Fetch(pkgAcquire::ItemDesc &item) { NSString *name([NSString stringWithUTF8String:item.ShortDesc.c_str()]); - CydiaProgressEvent *event([CydiaProgressEvent eventWithMessage:[NSString stringWithFormat:UCLocalize("DOWNLOADING_"), name] ofType:@"STATUS" forItem:item]); + CydiaProgressEvent *event([CydiaProgressEvent eventWithMessage:[NSString stringWithFormat:UCLocalize("DOWNLOADING_"), name] ofType:kCydiaProgressEventTypeStatus forItem:item]); [delegate_ performSelectorOnMainThread:@selector(addProgressEvent:) withObject:event waitUntilDone:YES]; } @@ -1267,7 +1055,7 @@ class Status : if (error.empty()) return; - CydiaProgressEvent *event([CydiaProgressEvent eventWithMessage:[NSString stringWithUTF8String:error.c_str()] ofType:@"ERROR" forItem:item]); + CydiaProgressEvent *event([CydiaProgressEvent eventWithMessage:[NSString stringWithUTF8String:error.c_str()] ofType:kCydiaProgressEventTypeError forItem:item]); [delegate_ performSelectorOnMainThread:@selector(addProgressEvent:) withObject:event waitUntilDone:YES]; } @@ -1487,9 +1275,9 @@ typedef std::map< unsigned long, _H > SourceMap; if (value != nil) { NSString *mode(nil); { NSString *type([self type]); - if ([type isEqualToString:@"ERROR"]) + if ([type isEqualToString:kCydiaProgressEventTypeError]) mode = UCLocalize("ERROR"); - else if ([type isEqualToString:@"WARNING"]) + else if ([type isEqualToString:kCydiaProgressEventTypeWarning]) mode = UCLocalize("WARNING"); } @@ -1639,12 +1427,12 @@ static void PackageImport(const void *key, const void *value, void *context) { CYString type_; CYString version_; - NSString *host_; - NSString *authority_; + _H host_; + _H authority_; CYString defaultIcon_; - NSDictionary *record_; + _H record_; BOOL trusted_; } @@ -1665,7 +1453,7 @@ static void PackageImport(const void *key, const void *value, void *context) { - (NSString *) host; - (NSString *) name; -- (NSString *) description; +- (NSString *) shortDescription; - (NSString *) label; - (NSString *) origin; - (NSString *) version; @@ -1689,20 +1477,9 @@ static void PackageImport(const void *key, const void *value, void *context) { version_.clear(); defaultIcon_.clear(); - if (record_ != nil) { - [record_ release]; - record_ = nil; - } - - if (host_ != nil) { - [host_ release]; - host_ = nil; - } - - if (authority_ != nil) { - [authority_ release]; - authority_ = nil; - } + record_ = nil; + host_ = nil; + authority_ = nil; } - (void) dealloc { @@ -1713,13 +1490,13 @@ static void PackageImport(const void *key, const void *value, void *context) { + (NSArray *) _attributeKeys { return [NSArray arrayWithObjects: - @"description", @"distribution", @"host", @"key", @"label", @"name", @"origin", + @"shortDescription", @"trusted", @"type", @"uri", @@ -1780,22 +1557,18 @@ static void PackageImport(const void *key, const void *value, void *context) { } record_ = [Sources_ objectForKey:[self key]]; - if (record_ != nil) - record_ = [record_ retain]; NSURL *url([NSURL URLWithString:uri_]); host_ = [url host]; if (host_ != nil) - host_ = [[host_ lowercaseString] retain]; + host_ = [host_ lowercaseString]; if (host_ != nil) - authority_ = host_; + // XXX: this is due to a bug in _H<> + authority_ = (id) host_; else authority_ = [url path]; - - if (authority_ != nil) - authority_ = [authority_ retain]; } - (Source *) initWithMetaIndex:(metaIndex *)index inPool:(apr_pool_t *)pool { @@ -1864,15 +1637,15 @@ static void PackageImport(const void *key, const void *value, void *context) { } - (NSString *) name { - return origin_.empty() ? authority_ : origin_; + return origin_.empty() ? (id) authority_ : origin_; } -- (NSString *) description { +- (NSString *) shortDescription { return description_; } - (NSString *) label { - return label_.empty() ? authority_ : label_; + return label_.empty() ? (id) authority_ : label_; } - (NSString *) origin { @@ -2376,13 +2149,16 @@ struct PackageNameOrdering : @"purposes", @"relations", @"section", + @"selection", @"shortDescription", @"shortSection", @"simpleSection", @"size", @"source", @"sponsor", + @"state", @"support", + @"tags", @"warnings", nil]; } @@ -2931,6 +2707,54 @@ struct PackageNameOrdering : return files; } +- (NSString *) state { +@synchronized (database_) { + if ([database_ era] != era_ || file_.end()) + return nil; + + switch (iterator_->CurrentState) { + case pkgCache::State::NotInstalled: + return @"NotInstalled"; + case pkgCache::State::UnPacked: + return @"UnPacked"; + case pkgCache::State::HalfConfigured: + return @"HalfConfigured"; + case pkgCache::State::HalfInstalled: + return @"HalfInstalled"; + case pkgCache::State::ConfigFiles: + return @"ConfigFiles"; + case pkgCache::State::Installed: + return @"Installed"; + case pkgCache::State::TriggersAwaited: + return @"TriggersAwaited"; + case pkgCache::State::TriggersPending: + return @"TriggersPending"; + } + + return (NSString *) [NSNull null]; +} } + +- (NSString *) selection { +@synchronized (database_) { + if ([database_ era] != era_ || file_.end()) + return nil; + + switch (iterator_->SelectedState) { + case pkgCache::State::Unknown: + return @"Unknown"; + case pkgCache::State::Install: + return @"Install"; + case pkgCache::State::Hold: + return @"Hold"; + case pkgCache::State::DeInstall: + return @"DeInstall"; + case pkgCache::State::Purge: + return @"Purge"; + } + + return (NSString *) [NSNull null]; +} } + - (NSArray *) warnings { NSMutableArray *warnings([NSMutableArray arrayWithCapacity:4]); const char *name(iterator_.Name()); @@ -3044,7 +2868,10 @@ struct PackageNameOrdering : [self parse]; - range = [[self shortDescription] rangeOfString:text options:MatchCompareOptions_]; + NSString *description([self shortDescription]); + NSUInteger length([description length]); + + range = [[self shortDescription] rangeOfString:text options:MatchCompareOptions_ range:NSMakeRange(0, std::min(length, 100))]; if (range.location != NSNotFound) return YES; @@ -3069,6 +2896,10 @@ struct PackageNameOrdering : _assert(false); } +- (NSArray *) tags { + return tags_; +} + - (BOOL) hasTag:(NSString *)tag { return tags_ == nil ? NO : [tags_ containsObject:tag]; } @@ -3397,11 +3228,11 @@ static NSString *Warning_; [delegate_ performSelectorOnMainThread:@selector(setConfigurationData:) withObject:conffile_r[1] waitUntilDone:YES]; } else if (strncmp(data, "status: ", 8) == 0) { // status: : {unpacked,half-configured,installed} - CydiaProgressEvent *event([CydiaProgressEvent eventWithMessage:[NSString stringWithUTF8String:(data + 8)] ofType:@"STATUS"]); + CydiaProgressEvent *event([CydiaProgressEvent eventWithMessage:[NSString stringWithUTF8String:(data + 8)] ofType:kCydiaProgressEventTypeStatus]); [progress_ performSelectorOnMainThread:@selector(addProgressEvent:) withObject:event waitUntilDone:YES]; } else if (strncmp(data, "processing: ", 12) == 0) { // processing: configure: config-test - CydiaProgressEvent *event([CydiaProgressEvent eventWithMessage:[NSString stringWithUTF8String:(data + 12)] ofType:@"STATUS"]); + CydiaProgressEvent *event([CydiaProgressEvent eventWithMessage:[NSString stringWithUTF8String:(data + 12)] ofType:kCydiaProgressEventTypeStatus]); [progress_ performSelectorOnMainThread:@selector(addProgressEvent:) withObject:event waitUntilDone:YES]; } else if (pmstatus_r(data, size)) { std::string type([pmstatus_r[1] UTF8String]); @@ -3416,10 +3247,10 @@ static NSString *Warning_; NSString *string = pmstatus_r[4]; if (type == "pmerror") { - CydiaProgressEvent *event([CydiaProgressEvent eventWithMessage:string ofType:@"ERROR" forPackage:package]); + CydiaProgressEvent *event([CydiaProgressEvent eventWithMessage:string ofType:kCydiaProgressEventTypeError forPackage:package]); [progress_ performSelectorOnMainThread:@selector(addProgressEvent:) withObject:event waitUntilDone:YES]; } else if (type == "pmstatus") { - CydiaProgressEvent *event([CydiaProgressEvent eventWithMessage:string ofType:@"STATUS" forPackage:package]); + CydiaProgressEvent *event([CydiaProgressEvent eventWithMessage:string ofType:kCydiaProgressEventTypeStatus forPackage:package]); [progress_ performSelectorOnMainThread:@selector(addProgressEvent:) withObject:event waitUntilDone:YES]; } else if (type == "pmconffile") [delegate_ performSelectorOnMainThread:@selector(setConfigurationData:) withObject:string waitUntilDone:YES]; @@ -3440,7 +3271,7 @@ static NSString *Warning_; while (std::getline(is, line)) { lprintf("O:%s\n", line.c_str()); - CydiaProgressEvent *event([CydiaProgressEvent eventWithMessage:[NSString stringWithUTF8String:line.c_str()] ofType:@"INFORMATION"]); + CydiaProgressEvent *event([CydiaProgressEvent eventWithMessage:[NSString stringWithUTF8String:line.c_str()] ofType:kCydiaProgressEventTypeInformation]); [progress_ performSelectorOnMainThread:@selector(addProgressEvent:) withObject:event waitUntilDone:YES]; } @@ -3577,7 +3408,7 @@ static NSString *Warning_; lprintf("%c:[%s]\n", warning ? 'W' : 'E', error.c_str()); - [delegate_ addProgressEventOnMainThread:[CydiaProgressEvent eventWithMessage:[NSString stringWithUTF8String:error.c_str()] ofType:(warning ? @"WARNING" : @"ERROR")] forTask:title]; + [delegate_ addProgressEventOnMainThread:[CydiaProgressEvent eventWithMessage:[NSString stringWithUTF8String:error.c_str()] ofType:(warning ? kCydiaProgressEventTypeWarning : kCydiaProgressEventTypeError)] forTask:title]; } return fatal; @@ -3644,7 +3475,7 @@ static NSString *Warning_; // else if (error == "Malformed Status line") // else if (error == "The list of sources could not be read.") else { - [delegate_ addProgressEventOnMainThread:[CydiaProgressEvent eventWithMessage:[NSString stringWithUTF8String:error.c_str()] ofType:(warning ? @"WARNING" : @"ERROR")] forTask:title]; + [delegate_ addProgressEventOnMainThread:[CydiaProgressEvent eventWithMessage:[NSString stringWithUTF8String:error.c_str()] ofType:(warning ? kCydiaProgressEventTypeWarning : kCydiaProgressEventTypeError)] forTask:title]; return; } @@ -3669,7 +3500,7 @@ static NSString *Warning_; return; if (cache_->DelCount() != 0 || cache_->InstCount() != 0) { - [delegate_ addProgressEventOnMainThread:[CydiaProgressEvent eventWithMessage:UCLocalize("COUNTS_NONZERO_EX") ofType:@"ERROR"] forTask:title]; + [delegate_ addProgressEventOnMainThread:[CydiaProgressEvent eventWithMessage:UCLocalize("COUNTS_NONZERO_EX") ofType:kCydiaProgressEventTypeError] forTask:title]; return; } @@ -3681,7 +3512,7 @@ static NSString *Warning_; return; if (cache_->BrokenCount() != 0) { - [delegate_ addProgressEventOnMainThread:[CydiaProgressEvent eventWithMessage:UCLocalize("STILL_BROKEN_EX") ofType:@"ERROR"] forTask:title]; + [delegate_ addProgressEventOnMainThread:[CydiaProgressEvent eventWithMessage:UCLocalize("STILL_BROKEN_EX") ofType:kCydiaProgressEventTypeError] forTask:title]; return; } @@ -3991,7 +3822,60 @@ static NSString *Warning_; @end /* }}} */ -/* Web Scripting {{{ */ +static NSMutableSet *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 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_; _transient id delegate_; @@ -4001,6 +3885,15 @@ static NSString *Warning_; @end +@interface CydiaWebViewController : CyteWebViewController { + CydiaObject *cydia_; +} + ++ (void) addDiversion:(Diversion *)diversion; + +@end + +/* Web Scripting {{{ */ @implementation CydiaObject - (void) dealloc { @@ -4088,6 +3981,12 @@ static NSString *Warning_; + (NSString *) webScriptNameForSelector:(SEL)selector { if (false); + else if (selector == @selector(addBridgedHost:)) + return @"addBridgedHost"; + else if (selector == @selector(addInternalRedirect::)) + return @"addInternalRedirect"; + else if (selector == @selector(addPipelinedHost:scheme:)) + return @"addPipelinedHost"; else if (selector == @selector(addTrivialSource:)) return @"addTrivialSource"; else if (selector == @selector(close)) @@ -4104,18 +4003,34 @@ static NSString *Warning_; return @"getKernelString"; else if (selector == @selector(getInstalledPackages)) return @"getInstalledPackages"; + 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(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(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:)) @@ -4126,8 +4041,12 @@ static NSString *Warning_; return @"setHidesNavigationBar"; else if (selector == @selector(setNavigationBarStyle:)) return @"setNavigationBarStyle"; - else if (selector == @selector(setPopupHook:)) - return @"setPopupHook"; + else if (selector == @selector(setNavigationBarTintRed:green:blue:alpha:)) + return @"setNavigationBarTintColor"; + 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:)) @@ -4148,6 +4067,10 @@ static NSString *Warning_; return [feature isEqualToString:@"window.open"]; } +- (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]); @@ -4182,6 +4105,38 @@ static NSString *Warning_; return [NSString stringWithCString:value]; } +- (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) 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) addTrivialSource:(NSString *)href { [delegate_ performSelectorOnMainThread:@selector(addTrivialSource:) withObject:href waitUntilDone:NO]; } @@ -4213,6 +4168,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; @@ -4278,6 +4241,17 @@ static NSString *Warning_; [delegate_ performSelectorOnMainThread:@selector(installPackages:) withObject:packages waitUntilDone:NO]; } +- (NSString *) substitutePackageNames:(NSString *)message { + NSMutableArray *words([[message componentsSeparatedByString:@" "] mutableCopy]); + for (size_t i(0), e([words count]); i != e; ++i) { + NSString *word([words objectAtIndex:i]); + if (Package *package = [[Database sharedInstance] packageWithName:word]) + [words replaceObjectAtIndex:i withObject:[package name]]; + } + + return [words componentsJoinedByString:@" "]; +} + - (void) removeButton { [indirect_ removeButton]; } @@ -4290,6 +4264,14 @@ 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]; +} + - (void) setHidesBackButton:(NSString *)value { [indirect_ performSelectorOnMainThread:@selector(setHidesBackButtonByNumber:) withObject:value waitUntilDone:NO]; } @@ -4302,6 +4284,20 @@ static NSString *Warning_; [indirect_ performSelectorOnMainThread:@selector(setNavigationBarStyle:) withObject:value waitUntilDone:NO]; } +- (void) setNavigationBarTintRed:(NSNumber *)red green:(NSNumber *)green blue:(NSNumber *)blue alpha:(NSNumber *)alpha { + float opacity(alpha == (id) [WebUndefined undefined] ? 1 : [alpha floatValue]); + UIColor *color([UIColor colorWithRed:[red floatValue] green:[green floatValue] blue:[blue floatValue] alpha:opacity]); + [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; @@ -4317,10 +4313,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]; } @@ -4417,7 +4409,7 @@ static NSString *Warning_; @end /* }}} */ /* Emulated Loading Controller {{{ */ -@interface CYEmulatedLoadingController : CYViewController { +@interface CYEmulatedLoadingController : CyteViewController { _transient Database *database_; _H indicator_; _H tabbar_; @@ -4436,7 +4428,10 @@ static NSString *Warning_; - (void) loadView { [self setView:[[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease]]; - [[self view] setBackgroundColor:[UIColor pinStripeColor]]; + + UITableView *table([[[UITableView alloc] initWithFrame:[[self view] bounds] style:UITableViewStyleGrouped] autorelease]); + [table setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; + [[self view] addSubview:table]; indicator_ = [[[CYLoadingIndicator alloc] initWithFrame:[[self view] bounds]] autorelease]; [indicator_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; @@ -4463,13 +4458,7 @@ static NSString *Warning_; /* }}} */ /* Cydia Browser Controller {{{ */ -@interface CYBrowserController : BrowserController { - CydiaObject *cydia_; -} - -@end - -@implementation CYBrowserController +@implementation CydiaWebViewController - (void) dealloc { [cydia_ release]; @@ -4477,10 +4466,15 @@ static NSString *Warning_; } - (NSURL *) navigationURL { - return [NSURL URLWithString:[NSString stringWithFormat:@"cydia://url/%@", [[[webview_ request] URL] absoluteString]]]; + return [NSURL URLWithString:[NSString stringWithFormat:@"cydia://url/%@", [[request_ URL] absoluteString]]]; +} + ++ (void) initialize { + Diversions_ = [[NSMutableSet alloc] initWithCapacity:0]; } -- (void) setHeaders:(NSDictionary *)headers forHost:(NSString *)host { ++ (void) addDiversion:(Diversion *)diversion { + [Diversions_ addObject:diversion]; } - (void) webView:(WebView *)view didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame { @@ -4488,39 +4482,37 @@ static NSString *Warning_; WebDataSource *source([frame dataSource]); NSURLResponse *response([source response]); - NSURL *url([response URL]); - NSString *scheme([url scheme]); - NSString *host([url host]); + NSString *scheme([[url scheme] lowercaseString]); + + bool bridged(false); - if ([response isKindOfClass:[NSHTTPURLResponse class]]) { - NSHTTPURLResponse *http((NSHTTPURLResponse *) response); - NSDictionary *headers([http allHeaderFields]); - [self setHeaders:headers forHost:host]; + @synchronized (HostConfig_) { + if ([scheme isEqualToString:@"file"]) + bridged = true; + else if ([scheme isEqualToString:@"https"]) + if ([BridgedHosts_ containsObject:[url host]]) + bridged = true; } - if ( - [host isEqualToString:@"cydia.saurik.com"] || - [host hasSuffix:@".cydia.saurik.com"] || - [scheme isEqualToString:@"file"] - ) + if (bridged) [window setValue:cydia_ forKey:@"cydia"]; } -- (void) _setMoreHeaders:(NSMutableURLRequest *)request { - if (System_ != NULL) - [request setValue:System_ forHTTPHeaderField:@"X-System"]; - if (Machine_ != NULL) - [request setValue:[NSString stringWithUTF8String:Machine_] forHTTPHeaderField:@"X-Machine"]; - if (Token_ != nil) - [request setValue:Token_ forHTTPHeaderField:@"X-Cydia-Token"]; - if (Role_ != nil) - [request setValue:Role_ forHTTPHeaderField:@"X-Role"]; +- (NSURL *) URLWithURL:(NSURL *)url { + return [Diversion divertURL:url]; } - (NSURLRequest *) webView:(WebView *)view resource:(id)resource willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response fromDataSource:(WebDataSource *)source { NSMutableURLRequest *copy([[super webView:view resource:resource willSendRequest:request redirectResponse:response fromDataSource:source] mutableCopy]); - [self _setMoreHeaders:copy]; + + if (System_ != NULL) + [copy setValue:System_ forHTTPHeaderField:@"X-System"]; + if (Machine_ != NULL) + [copy setValue:[NSString stringWithUTF8String:Machine_] forHTTPHeaderField:@"X-Machine"]; + if (Token_ != nil) + [copy setValue:Token_ forHTTPHeaderField:@"X-Cydia-Token"]; + return copy; } @@ -4530,7 +4522,7 @@ static NSString *Warning_; } - (id) init { - if ((self = [super initWithWidth:0 ofClass:[CYBrowserController class]]) != nil) { + if ((self = [super initWithWidth:0 ofClass:[CydiaWebViewController class]]) != nil) { cydia_ = [[CydiaObject alloc] initWithDelegate:indirect_]; WebView *webview([[webview_ _documentView] webView]); @@ -4609,7 +4601,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (void) queue; @end -@interface ConfirmationController : CYBrowserController { +@interface ConfirmationController : CydiaWebViewController { _transient Database *database_; UIAlertView *essential_; @@ -4780,13 +4772,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: @@ -5021,7 +5016,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { @end /* }}} */ /* Progress Controller {{{ */ -@interface ProgressController : CYBrowserController < +@interface ProgressController : CydiaWebViewController < ProgressDelegate > { _transient Database *database_; @@ -5085,9 +5080,7 @@ 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]; } @@ -5137,7 +5130,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 @@ -5721,7 +5714,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { /* }}} */ /* File Table {{{ */ -@interface FileTable : CYViewController < +@interface FileTable : CyteViewController < UITableViewDataSource, UITableViewDelegate > { @@ -5787,6 +5780,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) viewDidLoad { + [super viewDidLoad]; + [[self navigationItem] setTitle:UCLocalize("INSTALLED_FILES")]; } @@ -5857,15 +5852,15 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { @end /* }}} */ /* Package Controller {{{ */ -@interface CYPackageController : CYBrowserController < +@interface CYPackageController : CydiaWebViewController < UIActionSheetDelegate > { _transient Database *database_; - Package *package_; - NSString *name_; + _H package_; + _H name_; bool commercial_; - NSMutableArray *buttons_; - UIBarButtonItem *button_; + _H buttons_; + _H button_; } - (id) initWithDatabase:(Database *)database forPackage:(NSString *)name; @@ -5874,22 +5869,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { @implementation CYPackageController -- (void) dealloc { - if (package_ != nil) - [package_ release]; - if (name_ != nil) - [name_ release]; - - [buttons_ release]; - - if (button_ != nil) - [button_ release]; - - [super dealloc]; -} - - (NSURL *) navigationURL { - return [NSURL URLWithString:[NSString stringWithFormat:@"cydia://package/%@", name_]]; + return [NSURL URLWithString:[NSString stringWithFormat:@"cydia://package/%@", (id) name_]]; } /* XXX: this is not safe at all... localization of /fail/ */ @@ -5983,23 +5964,22 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (id) initWithDatabase:(Database *)database forPackage:(NSString *)name { if ((self = [super init]) != nil) { database_ = database; - buttons_ = [[NSMutableArray alloc] initWithCapacity:4]; - name_ = [[NSString alloc] initWithString:name]; - [self setURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/#!/package/%@", UI_, name_]]]; + buttons_ = [NSMutableArray arrayWithCapacity:4]; + name_ = [NSString stringWithString:name]; + [self setURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/#!/package/%@", UI_, (id) name_]]]; } return self; } - (void) reloadData { - if (package_ != nil) - [package_ autorelease]; + [super reloadData]; + package_ = [database_ packageWithName:name_]; [buttons_ removeAllObjects]; if (package_ != nil) { - [package_ parse]; + [(Package *) package_ parse]; - package_ = [package_ retain]; commercial_ = [package_ isCommercial]; if ([package_ mode] != nil) @@ -6015,9 +5995,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [buttons_ addObject:UCLocalize("REMOVE")]; } - if (button_ != nil) - [button_ release]; - NSString *title; switch ([buttons_ count]) { case 0: title = nil; break; @@ -6025,14 +6002,12 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { default: title = UCLocalize("MODIFY"); break; } - button_ = [[UIBarButtonItem alloc] + button_ = [[[UIBarButtonItem alloc] initWithTitle:title style:UIBarButtonItemStylePlain target:self action:@selector(customButtonClicked) - ]; - - [super reloadData]; + ] autorelease]; } - (bool) isLoading { @@ -6043,7 +6018,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { /* }}} */ /* Package List Controller {{{ */ -@interface PackageListController : CYViewController < +@interface PackageListController : CyteViewController < UITableViewDataSource, UITableViewDelegate > { @@ -6413,7 +6388,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { /* }}} */ /* Home Controller {{{ */ -@interface HomeController : CYBrowserController { +@interface HomeController : CydiaWebViewController { } @end @@ -6423,6 +6398,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; } @@ -6430,17 +6406,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { return [NSURL URLWithString:@"cydia://home"]; } -- (void) _setMoreHeaders:(NSMutableURLRequest *)request { - [super _setMoreHeaders:request]; - - if (ChipID_ != nil) - [request setValue:ChipID_ forHTTPHeaderField:@"X-Chip-ID"]; - if (UniqueID_ != nil) - [request setValue:UniqueID_ forHTTPHeaderField:@"X-Unique-ID"]; - if (PLMN_ != nil) - [request setValue:PLMN_ forHTTPHeaderField:@"X-Carrier-ID"]; -} - - (void) aboutButtonClicked { UIAlertView *alert([[[UIAlertView alloc] init] autorelease]); @@ -6449,7 +6414,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/" @@ -6459,6 +6426,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) viewDidLoad { + [super viewDidLoad]; + [[self navigationItem] setLeftBarButtonItem:[[[UIBarButtonItem alloc] initWithTitle:UCLocalize("ABOUT") style:UIBarButtonItemStylePlain @@ -6467,10 +6436,15 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { ] autorelease]]; } +- (void) unloadData { + [super unloadData]; + [self reloadData]; +} + @end /* }}} */ /* Manage Controller {{{ */ -@interface ManageController : CYBrowserController { +@interface ManageController : CydiaWebViewController { } - (void) queueStatusDidChange; @@ -6490,52 +6464,39 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) viewDidLoad { + [super viewDidLoad]; + [[self navigationItem] setLeftBarButtonItem:[[[UIBarButtonItem alloc] initWithTitle:UCLocalize("SETTINGS") style:UIBarButtonItemStylePlain target:self action:@selector(settingsButtonClicked) ] autorelease]]; - - [self queueStatusDidChange]; } - (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 @@ -6658,7 +6619,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 < @@ -6683,6 +6651,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (void) beginUpdate; - (void) raiseBar:(BOOL)animated; - (BOOL) updating; +- (void) unloadData; @end @@ -6732,11 +6701,17 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { return items; } -- (void) reloadData { - for (CYViewController *controller in [self viewControllers]) - [controller reloadData]; +- (void) unloadData { + UIViewController *selected([self selectedViewController]); + for (UINavigationController *controller in [self viewControllers]) + [controller unloadData]; + + [selected reloadData]; - [(CYNavigationController *)[self unselectedViewController] reloadData]; + if (UIViewController *unselected = [self unselectedViewController]) + [unselected reloadData]; + + [super unloadData]; } - (void) dealloc { @@ -6948,25 +6923,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]; @@ -6976,23 +6940,17 @@ 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; + if (UIViewController *visible = [self visibleViewController]) + [visible 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 @@ -7113,7 +7071,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { /* Section Controller {{{ */ @interface SectionController : FilteredPackageListController { - NSString *section_; + _H section_; } - (id) initWithDatabase:(Database *)database section:(NSString *)section; @@ -7147,7 +7105,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { @end /* }}} */ /* Sections Controller {{{ */ -@interface SectionsController : CYViewController < +@interface SectionsController : CyteViewController < UITableViewDataSource, UITableViewDelegate > { @@ -7155,7 +7113,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { NSMutableArray *sections_; NSMutableArray *filtered_; UITableView *list_; - BOOL editing_; } - (id) initWithDatabase:(Database *)database; @@ -7178,24 +7135,22 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (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]; @@ -7210,16 +7165,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 { @@ -7233,13 +7199,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]; @@ -7265,6 +7231,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) viewDidLoad { + [super viewDidLoad]; + [[self navigationItem] setTitle:UCLocalize("SECTIONS")]; } @@ -7340,14 +7308,14 @@ 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 > { @@ -7357,7 +7325,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { NSMutableArray *sections_; UITableView *list_; unsigned upgrades_; - BOOL hasSentFirstLoad_; } - (id) initWithDatabase:(Database *)database; @@ -7378,21 +7345,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { 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 { @@ -7466,6 +7421,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) viewDidLoad { + [super viewDidLoad]; + [[self navigationItem] setTitle:UCLocalize("CHANGES")]; } @@ -7502,7 +7459,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { _trace(); } -- (void) reloadData { +- (void) _reloadData { @synchronized (database_) { era_ = [database_ era]; NSArray *packages = [database_ packages]; @@ -7600,18 +7557,22 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { PrintTimes(); } } +- (void) reloadData { + [super reloadData]; + [self performSelector:@selector(_reloadData) withObject:nil afterDelay:0]; +} + @end /* }}} */ /* Search Controller {{{ */ @interface SearchController : FilteredPackageListController < UISearchBarDelegate > { - UISearchBar *search_; + _H search_; BOOL searchloaded_; } -- (id) initWithDatabase:(Database *)database; -- (void) setSearchTerm:(NSString *)term; +- (id) initWithDatabase:(Database *)database query:(NSString *)query; - (void) reloadData; @end @@ -7619,7 +7580,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { @implementation SearchController - (void) dealloc { - [search_ release]; + [search_ setDelegate:nil]; [super dealloc]; } @@ -7630,11 +7591,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { return [NSURL URLWithString:[NSString stringWithFormat:@"cydia://search/%@", [search_ text]]]; } -- (void) setSearchTerm:(NSString *)searchTerm { - [search_ setText:searchTerm]; - [self reloadData]; -} - - (void) searchBarSearchButtonClicked:(UISearchBar *)searchBar { [self setObject:[search_ text] forFilter:@selector(isUnfilteredAndSearchedForBy:)]; [search_ resignFirstResponder]; @@ -7646,9 +7602,13 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [self reloadData]; } -- (id) initWithDatabase:(Database *)database { - if ((self = [super initWithDatabase:database title:UCLocalize("SEARCH") filter:@selector(isUnfilteredAndSearchedForBy:) with:nil])) { - search_ = [[UISearchBar alloc] init]; +- (id) initWithDatabase:(Database *)database query:(NSString *)query { + if ((self = [super initWithDatabase:database title:UCLocalize("SEARCH") filter:@selector(isUnfilteredAndSearchedForBy:) with:query])) { + search_ = [[[UISearchBar alloc] init] autorelease]; + [search_ setDelegate:self]; + + if (query != nil) + [search_ setText:query]; } return self; } @@ -7668,7 +7628,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { textField = MSHookIvar(search_, "_searchField"); [textField setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin]; - [search_ setDelegate:self]; [textField setEnablesReturnKeyAutomatically:NO]; [[self navigationItem] setTitleView:textField]; } @@ -7676,8 +7635,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (void) reloadData { [self setObject:[search_ text]]; - [super reloadData]; [self resetCursor]; + + [super reloadData]; } - (void) didSelectPackage:(Package *)package { @@ -7688,7 +7648,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { @end /* }}} */ /* Package Settings Controller {{{ */ -@interface PackageSettingsController : CYViewController < +@interface PackageSettingsController : CyteViewController < UITableViewDataSource, UITableViewDelegate > { @@ -7839,6 +7799,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) viewDidLoad { + [super viewDidLoad]; + [[self navigationItem] setTitle:UCLocalize("SETTINGS")]; } @@ -8071,6 +8033,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [key_ release]; key_ = [[source_ key] retain]; [self setObject:source_]; + [[self navigationItem] setTitle:[source_ label]]; [super reloadData]; @@ -8079,7 +8042,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { @end /* }}} */ /* Sources Controller {{{ */ -@interface SourcesController : CYViewController < +@interface SourcesController : CyteViewController < UITableViewDataSource, UITableViewDelegate > { @@ -8348,8 +8311,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [request setValue:[NSString stringWithUTF8String:Machine_] forHTTPHeaderField:@"X-Machine"]; if (UniqueID_ != nil) [request setValue:UniqueID_ forHTTPHeaderField:@"X-Unique-ID"]; - if (Role_ != nil) - [request setValue:Role_ forHTTPHeaderField:@"X-Role"]; return [[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease]; } @@ -8425,6 +8386,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) viewDidLoad { + [super viewDidLoad]; + [[self navigationItem] setTitle:UCLocalize("SOURCES")]; [self updateButtonsForEditingStatus:NO animated:NO]; } @@ -8536,7 +8499,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { /* }}} */ /* Settings Controller {{{ */ -@interface SettingsController : CYViewController < +@interface SettingsController : CyteViewController < UITableViewDataSource, UITableViewDelegate > { @@ -8581,6 +8544,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) viewDidLoad { + [super viewDidLoad]; + [[self navigationItem] setTitle:UCLocalize("WHO_ARE_YOU")]; int index = -1; @@ -8727,13 +8692,14 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (void) reloadData { [super reloadData]; + [table_ reloadData]; } @end /* }}} */ /* Stash Controller {{{ */ -@interface StashController : CYViewController { +@interface StashController : CyteViewController { UIActivityIndicatorView *spinner_; UILabel *status_; UILabel *caption_; @@ -8807,6 +8773,35 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { @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 +} + +@end + @interface Cydia : UIApplication < ConfirmationControllerDelegate, DatabaseDelegate, @@ -8908,17 +8903,21 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } // 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]; - [tabbar_ reloadData]; + [self unloadData]; - CYNavigationController *navigation = [self queueNavigationController]; + UINavigationController *navigation = [self queueNavigationController]; id queuedelegate = nil; if ([[navigation viewControllers] count] > 0) @@ -9054,7 +9053,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (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]; @@ -9089,7 +9088,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (void) repairWithInvocation:(NSInvocation *)invocation { _trace(); - [self invokeNewProgress:invocation forController:nil withTitle:UCLocalize("REPAIRING")]; + [self invokeNewProgress:invocation forController:nil withTitle:@"REPAIRING"]; _trace(); } @@ -9115,7 +9114,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { fclose(file); - [self detachNewProgressSelector:@selector(update_) toTarget:self forController:nil title:UCLocalize("UPDATING_SOURCES")]; + [self detachNewProgressSelector:@selector(update_) toTarget:self forController:nil title:@"UPDATING_SOURCES"]; [self complete]; } @@ -9161,8 +9160,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]; @@ -9221,17 +9219,13 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (void) confirmWithNavigationController:(UINavigationController *)navigation { Queuing_ = false; ++locked_; - [self detachNewProgressSelector:@selector(perform) toTarget:database_ forController:navigation title:UCLocalize("RUNNING")]; + [self detachNewProgressSelector:@selector(perform) toTarget:database_ forController:navigation title:@"RUNNING"]; --locked_; [self complete]; } - (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 { @@ -9331,6 +9325,13 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (BOOL) isSafeToSuspend { + if (locked_ != 0) { +#if !ForRelease + NSLog(@"isSafeToSuspend: locked_ != 0"); +#endif + return false; + } + // Use external process status API internally. // This is probably a really bad idea. // XXX: what is the point of this? does this solve anything at all? @@ -9341,7 +9342,17 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { notify_cancel(notify_token); } - return locked_ == 0 && status == 0; + if (status != 0) { +#if !ForRelease + NSLog(@"isSafeToSuspend: status != 0"); +#endif + return false; + } + +#if !ForRelease + NSLog(@"isSafeToSuspend: -> true"); +#endif + return true; } - (void) applicationSuspend:(__GSEvent *)event { @@ -9364,28 +9375,32 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [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 show:YES]; ++locked_; return hud; } - (void) removeProgressHUD:(UIProgressHUD *)hud { + --locked_; [hud show:NO]; [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; @@ -9400,12 +9415,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]; @@ -9424,7 +9439,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"]) { @@ -9442,8 +9457,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"]) { @@ -9487,10 +9501,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]; } @@ -9597,7 +9611,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]; } @@ -9611,16 +9625,23 @@ _trace(); if ([self respondsToSelector:@selector(setApplicationSupportsShakeToEdit:)]) [self setApplicationSupportsShakeToEdit:NO]; - [NSURLCache setSharedURLCache:[[[SDURLCache alloc] + @synchronized (HostConfig_) { + [BridgedHosts_ addObject:[[NSURL URLWithString:CydiaURL(@"")] host]]; + } + + [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]]; + // this would disallow http{,s} URLs from accessing this data + //[WebView registerURLSchemeAsLocal:@"cydia"]; + Font12_ = [[UIFont systemFontOfSize:12] retain]; Font12Bold_ = [[UIFont boldSystemFontOfSize:12] retain]; Font14_ = [[UIFont systemFontOfSize:14] retain]; @@ -9630,6 +9651,9 @@ _trace(); essential_ = [[NSMutableArray alloc] initWithCapacity:4]; broken_ = [[NSMutableArray alloc] initWithCapacity:4]; + // XXX: I really need this thing... like, seriously... I'm sorry + [[[CydiaWebViewController alloc] initWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/appcache/", UI_]]] reloadData]; + window_ = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; [window_ orderFront:self]; [window_ makeKey:self]; @@ -9668,11 +9692,26 @@ _trace(); _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) @@ -9685,51 +9724,57 @@ _trace(); [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]; } @@ -9793,52 +9838,63 @@ MSHook(void, UIWebDocumentView$_setUIKitDelegate$, UIWebDocumentView *self, SEL return _UIWebDocumentView$_setUIKitDelegate$(self, _cmd, delegate); } -static NSNumber *shouldPlayKeyboardSounds; +static NSSet *MobilizedFiles_; -Class $UIHardware; +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]; + } -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]; - } + return url; +} - if (![shouldPlayKeyboardSounds boolValue]) - break; +Class $CFXPreferencesPropertyListSource; +@class CFXPreferencesPropertyListSource; - default: - _UIHardware$_playSystemSound$(self, _cmd, sound); - } +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; } -Class $UIApplication; +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; +} -MSHook(void, UIApplication$_updateApplicationAccessibility, UIApplication *self, SEL _cmd) { - static BOOL initialized = NO; - static BOOL started = NO; +Class $NSURLConnection; - NSDictionary *dict([[[NSDictionary alloc] initWithContentsOfFile:@"/var/mobile/Library/Preferences/com.apple.Accessibility.plist"] autorelease]); - BOOL enabled = [[dict objectForKey:@"VoiceOverTouchEnabled"] boolValue] || [[dict objectForKey:@"VoiceOverTouchEnabledByiTunes"] boolValue]; +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]); - if ([self respondsToSelector:@selector(_accessibilityBundlePrincipalClass)]) { - id bundle = [self performSelector:@selector(_accessibilityBundlePrincipalClass)]; - if (![bundle respondsToSelector:@selector(_accessibilityStopServer)]) return; - if (![bundle respondsToSelector:@selector(_accessibilityStartServer)]) return; + NSURL *url([copy URL]); + NSString *host([url host]); + NSString *scheme([[url scheme] lowercaseString]); - if (initialized && !enabled) { - initialized = NO; - [bundle performSelector:@selector(_accessibilityStopServer)]; - } else if (enabled) { - initialized = YES; - if (!started) { - started = YES; - [bundle performSelector:@selector(_accessibilityStartServer)]; - } - } + NSString *compound([NSString stringWithFormat:@"%@:%@", scheme, host]); + + @synchronized (HostConfig_) { + if ([copy respondsToSelector:@selector(setHTTPShouldUsePipelining:)]) + if ([PipelinedHosts_ containsObject:host] || [PipelinedHosts_ containsObject:compound]) + [copy setHTTPShouldUsePipelining:YES]; } + + if ((self = _NSURLConnection$init$(self, _cmd, copy, delegate, usesCache, maxContentLength, startImmediately, connectionProperties)) != nil) { + } return self; } int main(int argc, char *argv[]) { _pooled @@ -9871,13 +9927,40 @@ int main(int argc, char *argv[]) { _pooled NSLog(@"unknown UIUserInterfaceIdiom!"); } + SessionData_ = [[NSMutableDictionary alloc] initWithCapacity:4]; + + HostConfig_ = [[NSObject alloc] init]; + @synchronized (HostConfig_) { + BridgedHosts_ = [NSMutableSet setWithCapacity:4]; + PipelinedHosts_ = [NSMutableSet setWithCapacity:4]; + } + 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) { @@ -9885,37 +9968,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); + + if (lang != NULL) { + Pcre pattern("^([a-z][a-z])(?:-[A-Za-z]*)?(_[A-Z][A-Z])?$"); + lang = !pattern(lang) ? NULL : [pattern->*@"%1$@%2$@" UTF8String]; } - //std::setlocale(LC_ALL, lang); 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); @@ -9945,7 +10031,6 @@ int main(int argc, char *argv[]) { _pooled /* }}} */ App_ = [[NSBundle mainBundle] bundlePath]; - Home_ = NSHomeDirectory(); Advanced_ = YES; setuid(0); @@ -9986,28 +10071,8 @@ 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_ = CYIOGetValue("IOService:/", @"IOPlatformSerialNumber"); + ChipID_ = CYHex(CYIOGetValue("IODeviceTree:/chosen", @"unique-chip-id"), true, true); UniqueID_ = [[UIDevice currentDevice] uniqueIdentifier]; @@ -10104,7 +10169,7 @@ int main(int argc, char *argv[]) { _pooled if (access("/tmp/.cydia.fw", F_OK) == 0) { unlink("/tmp/.cydia.fw"); goto firmware; - } else if (access("/User", F_OK) != 0 || version < 2) { + } else if (access("/User", F_OK) != 0 || version < 4) { firmware: _trace(); system("/usr/libexec/cydia/firmware.sh");