X-Git-Url: https://git.saurik.com/cydia.git/blobdiff_plain/900095fdf69cc72c5a0d5b1f75c4451a0bc4440e..9dac415b3549213d312f7be3f971c322a3d63a5b:/MobileCydia.mm diff --git a/MobileCydia.mm b/MobileCydia.mm index 932cb890..e278ab86 100644 --- a/MobileCydia.mm +++ b/MobileCydia.mm @@ -125,8 +125,6 @@ extern "C" { #include "SDURLCache/SDURLCache.h" #include "substrate.h" - -#include "Version.h" /* }}} */ /* Profiler {{{ */ @@ -208,6 +206,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); @@ -293,7 +320,9 @@ static _finline void UpdateExternalStatus(uint64_t newStatus) { NSDate *future([NSDate distantFuture]); NSString *mode([loop currentMode] ?: NSDefaultRunLoopMode); +_trace(); while (!stopped && [loop runMode:mode beforeDate:future]); +_trace(); return [context count] == 0 ? nil : [context objectAtIndex:0]; } @@ -360,33 +389,6 @@ static const NSStringCompareOptions MatchCompareOptions_ = NSLiteralSearch | NSC 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 *); @@ -842,9 +844,22 @@ class Pcre { const char *data_; public: + Pcre() : + code_(NULL), + study_(NULL) + { + } + Pcre(const char *regex) : + code_(NULL), study_(NULL) { + this->operator =(regex); + } + + void operator =(const char *regex) { + _assert(code_ == NULL); + const char *error; int offset; code_ = pcre_compile(regex, 0, &error, &offset, NULL); @@ -876,6 +891,10 @@ class Pcre { data_ = data; return pcre_exec(code_, study_, data, size, 0, 0, matches_, (capture_ + 1) * 3) >= 0; } + + _finline size_t size() const { + return capture_; + } }; /* }}} */ /* Mime Addresses {{{ */ @@ -1066,6 +1085,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 {{{ */ @@ -1248,7 +1277,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]; } @@ -1266,7 +1295,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]; } @@ -1486,9 +1515,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"); } @@ -1638,12 +1667,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_; } @@ -1688,20 +1717,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 { @@ -1779,22 +1797,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 { @@ -1863,7 +1877,7 @@ 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 { @@ -1871,7 +1885,7 @@ static void PackageImport(const void *key, const void *value, void *context) { } - (NSString *) label { - return label_.empty() ? authority_ : label_; + return label_.empty() ? (id) authority_ : label_; } - (NSString *) origin { @@ -2375,13 +2389,16 @@ struct PackageNameOrdering : @"purposes", @"relations", @"section", + @"selection", @"shortDescription", @"shortSection", @"simpleSection", @"size", @"source", @"sponsor", + @"state", @"support", + @"tags", @"warnings", nil]; } @@ -2930,6 +2947,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()); @@ -3068,6 +3133,10 @@ struct PackageNameOrdering : _assert(false); } +- (NSArray *) tags { + return tags_; +} + - (BOOL) hasTag:(NSString *)tag { return tags_ == nil ? NO : [tags_ containsObject:tag]; } @@ -3396,11 +3465,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]); @@ -3415,10 +3484,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]; @@ -3439,7 +3508,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]; } @@ -3576,7 +3645,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; @@ -3643,7 +3712,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; } @@ -3668,7 +3737,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; } @@ -3680,7 +3749,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; } @@ -3990,7 +4059,50 @@ static NSString *Warning_; @end /* }}} */ -/* Web Scripting {{{ */ +@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 { + if (!pattern_(url)) + return nil; + + size_t count(pattern_.size()); + id values[count]; + for (size_t i(0); i != count; ++i) + values[i] = pattern_[i + 1]; + + return [[[NSString alloc] initWithFormat:format_ arguments:reinterpret_cast(values)] autorelease]; +} + +- (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_; @@ -4000,6 +4112,17 @@ static NSString *Warning_; @end +@interface CYBrowserController : BrowserController { + CydiaObject *cydia_; +} + ++ (void) addDiversion:(Diversion *)diversion; + +@end + +static NSMutableSet *Diversions_; + +/* Web Scripting {{{ */ @implementation CydiaObject - (void) dealloc { @@ -4087,10 +4210,16 @@ static NSString *Warning_; + (NSString *) webScriptNameForSelector:(SEL)selector { if (false); + else if (selector == @selector(addBridgedHost:)) + return @"addBridgedHost"; + else if (selector == @selector(addPipelinedHost:scheme:)) + return @"addPipelinedHost"; else if (selector == @selector(addTrivialSource:)) return @"addTrivialSource"; else if (selector == @selector(close)) return @"close"; + else if (selector == @selector(divert::)) + return @"divert"; else if (selector == @selector(du:)) return @"du"; else if (selector == @selector(stringWithFormat:arguments:)) @@ -4105,18 +4234,26 @@ static NSString *Warning_; return @"getInstalledPackages"; 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(setButtonImage:withStyle:toFunction:)) return @"setButtonImage"; else if (selector == @selector(setButtonTitle:withStyle:toFunction:)) @@ -4151,6 +4288,10 @@ static NSString *Warning_; return [feature isEqualToString:@"window.open"]; } +- (void) divert:(NSString *)from :(NSString *)to { + [CYBrowserController performSelectorOnMainThread:@selector(addDiversion:) withObject:[[[Diversion alloc] initWithFrom:from to:to] autorelease] waitUntilDone:NO]; +} + - (NSNumber *) getKernelNumber:(NSString *)name { const char *string([name UTF8String]); @@ -4185,6 +4326,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]; } @@ -4304,6 +4477,10 @@ static NSString *Warning_; [indirect_ setButtonTitle:button withStyle:style toFunction:function]; } +- (void) setAllowsNavigationAction:(NSString *)value { + [indirect_ performSelectorOnMainThread:@selector(setAllowsNavigationActionByNumber:) withObject:value waitUntilDone:NO]; +} + - (void) setHidesBackButton:(NSString *)value { [indirect_ performSelectorOnMainThread:@selector(setHidesBackButtonByNumber:) withObject:value waitUntilDone:NO]; } @@ -4454,16 +4631,12 @@ static NSString *Warning_; } return self; } -// 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]; -} - - (void) loadView { [self setView:[[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease]]; - [[self view] setBackgroundColor:[self groupTableViewBackgroundColor]]; + + 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]; @@ -4490,12 +4663,6 @@ static NSString *Warning_; /* }}} */ /* Cydia Browser Controller {{{ */ -@interface CYBrowserController : BrowserController { - CydiaObject *cydia_; -} - -@end - @implementation CYBrowserController - (void) dealloc { @@ -4507,7 +4674,12 @@ static NSString *Warning_; return [NSURL URLWithString:[NSString stringWithFormat:@"cydia://url/%@", [[[webview_ request] URL] absoluteString]]]; } -- (void) setHeaders:(NSDictionary *)headers forHost:(NSString *)host { ++ (void) initialize { + Diversions_ = [[NSMutableSet alloc] initWithCapacity:0]; +} + ++ (void) addDiversion:(Diversion *)diversion { + [Diversions_ addObject:diversion]; } - (void) webView:(WebView *)view didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame { @@ -4515,39 +4687,35 @@ static NSString *Warning_; WebDataSource *source([frame dataSource]); NSURLResponse *response([source response]); - NSURL *url([response URL]); - NSString *scheme([url scheme]); - NSString *host([url host]); - if ([response isKindOfClass:[NSHTTPURLResponse class]]) { - NSHTTPURLResponse *http((NSHTTPURLResponse *) response); - NSDictionary *headers([http allHeaderFields]); - [self setHeaders:headers forHost:host]; + @synchronized (HostConfig_) { + if ([[[url scheme] lowercaseString] isEqualToString:@"https"]) + if ([BridgedHosts_ containsObject:[url host]]) + [window setValue:cydia_ forKey:@"cydia"]; } - - if ( - [host isEqualToString:@"cydia.saurik.com"] || - [host hasSuffix:@".cydia.saurik.com"] || - [scheme isEqualToString:@"file"] - ) - [window setValue:cydia_ forKey:@"cydia"]; } -- (void) _setMoreHeaders:(NSMutableURLRequest *)request { +- (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]); + + divert: + NSURL *url([copy URL]); + NSString *href([url absoluteString]); + + for (Diversion *diversion in Diversions_) + if (NSString *diverted = [diversion divert:href]) { + [copy setURL:[NSURL URLWithString:diverted]]; + goto divert; + } + if (System_ != NULL) - [request setValue:System_ forHTTPHeaderField:@"X-System"]; + [copy setValue:System_ forHTTPHeaderField:@"X-System"]; if (Machine_ != NULL) - [request setValue:[NSString stringWithUTF8String:Machine_] forHTTPHeaderField:@"X-Machine"]; + [copy 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"]; -} + [copy setValue:Token_ forHTTPHeaderField:@"X-Cydia-Token"]; -- (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]; return copy; } @@ -5112,9 +5280,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]; } @@ -5905,11 +6071,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { return [NSURL URLWithString:[NSString stringWithFormat:@"cydia://package/%@", (id) name_]]; } -- (bool) _allowNavigationAction { - // XXX: damn it... I really want this. - return true; -} - /* XXX: this is not safe at all... localization of /fail/ */ - (void) _clickButtonWithName:(NSString *)name { if ([name isEqualToString:UCLocalize("CLEAR")]) @@ -6008,6 +6169,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) reloadData { + [super reloadData]; + package_ = [database_ packageWithName:name_]; [buttons_ removeAllObjects]; @@ -6043,8 +6206,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { target:self action:@selector(customButtonClicked) ] autorelease]; - - [super reloadData]; } - (bool) isLoading { @@ -6442,17 +6603,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]); @@ -7167,7 +7317,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { NSMutableArray *sections_; NSMutableArray *filtered_; UITableView *list_; - BOOL editing_; } - (id) initWithDatabase:(Database *)database; @@ -7190,24 +7339,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]; @@ -7222,16 +7369,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 { @@ -7245,13 +7403,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]; @@ -7352,7 +7510,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) editButtonClicked { - [self setEditing:(!editing_)]; + [self setEditing:![self isEditing] animated:YES]; } @end @@ -7369,7 +7527,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { NSMutableArray *sections_; UITableView *list_; unsigned upgrades_; - BOOL hasSentFirstLoad_; } - (id) initWithDatabase:(Database *)database; @@ -7390,21 +7547,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 { @@ -7514,7 +7659,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { _trace(); } -- (void) reloadData { +- (void) _reloadData { @synchronized (database_) { era_ = [database_ era]; NSArray *packages = [database_ packages]; @@ -7612,6 +7757,11 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { PrintTimes(); } } +- (void) reloadData { + [super reloadData]; + [self performSelector:@selector(_reloadData) withObject:nil afterDelay:0]; +} + @end /* }}} */ /* Search Controller {{{ */ @@ -7688,8 +7838,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (void) reloadData { [self setObject:[search_ text]]; - [super reloadData]; [self resetCursor]; + + [super reloadData]; } - (void) didSelectPackage:(Package *)package { @@ -8083,6 +8234,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [key_ release]; key_ = [[source_ key] retain]; [self setObject:source_]; + [[self navigationItem] setTitle:[source_ label]]; [super reloadData]; @@ -8360,8 +8512,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]; } @@ -8739,6 +8889,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (void) reloadData { [super reloadData]; + [table_ reloadData]; } @@ -9101,7 +9252,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(); } @@ -9127,7 +9278,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]; } @@ -9233,7 +9384,7 @@ 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]; } @@ -9343,6 +9494,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? @@ -9353,7 +9511,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 { @@ -9623,6 +9791,10 @@ _trace(); if ([self respondsToSelector:@selector(setApplicationSupportsShakeToEdit:)]) [self setApplicationSupportsShakeToEdit:NO]; + @synchronized (HostConfig_) { + [BridgedHosts_ addObject:[[NSURL URLWithString:CydiaURL(@"")] host]]; + } + [NSURLCache setSharedURLCache:[[[SDURLCache alloc] initWithMemoryCapacity:524288 diskCapacity:10485760 @@ -9680,6 +9852,21 @@ _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) { @@ -9697,42 +9884,48 @@ _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]; + if (valid && [saved count] != [standard count]) + valid = NO; - BOOL enough = YES; - for (NSArray *entry in items) - if ([entry count] <= 0) - enough = 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]; @@ -9853,6 +10046,27 @@ MSHook(void, UIApplication$_updateApplicationAccessibility, UIApplication *self, } } +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]); + NSString *host([url host]); + NSString *scheme([[url scheme] lowercaseString]); + + 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 _trace(); @@ -9883,6 +10097,14 @@ 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)))); @@ -9897,6 +10119,13 @@ int main(int argc, char *argv[]) { _pooled method_setImplementation(UIWebDocumentView$_setUIKitDelegate$, reinterpret_cast(&$UIWebDocumentView$_setUIKitDelegate$)); } + $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$)); + } + $UIHardware = objc_getClass("UIHardware"); Method UIHardware$_playSystemSound$(class_getClassMethod($UIHardware, @selector(_playSystemSound:))); if (UIHardware$_playSystemSound$ != NULL) { @@ -9914,11 +10143,14 @@ int main(int argc, char *argv[]) { _pooled /* 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) // XXX: consider just setting to C and then falling through? lang = NULL; else { @@ -10115,7 +10347,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");