X-Git-Url: https://git.saurik.com/cydia.git/blobdiff_plain/34ac1598a763feb8ced405bb834e85d7da33a6e6..3a6f9c89e5edc675d5741eb5aa66e30e798fb3aa:/MobileCydia.mm?ds=sidebyside diff --git a/MobileCydia.mm b/MobileCydia.mm index 0b8f1571..3e81b070 100644 --- a/MobileCydia.mm +++ b/MobileCydia.mm @@ -1,5 +1,5 @@ /* Cydia - iPhone UIKit Front-End for Debian APT - * Copyright (C) 2008-2014 Jay Freeman (saurik) + * Copyright (C) 2008-2015 Jay Freeman (saurik) */ /* GNU General Public License, Version 3 {{{ */ @@ -48,23 +48,22 @@ #include #include "iPhonePrivate.h" -#include - #include #include -#include #include +#include #include #include #include #include -#include +#include "fdstream.hpp" #undef ABS +#include "apt.h" #include #include #include @@ -83,8 +82,6 @@ #include #include -#include - #include #include #include @@ -92,6 +89,7 @@ #include #include +#include #include #include #include @@ -109,23 +107,15 @@ extern "C" { #include #include "Sources.h" -#include +#include "Substrate.hpp" #include "Menes/Menes.h" -#include "CyteKit/IndirectDelegate.h" -#include "CyteKit/PerlCompatibleRegEx.hpp" -#include "CyteKit/TableViewCell.h" -#include "CyteKit/TabBarController.h" -#include "CyteKit/WebScriptObject-Cyte.h" -#include "CyteKit/WebViewController.h" -#include "CyteKit/WebViewTableViewCell.h" -#include "CyteKit/stringWithUTF8Bytes.h" +#include "CyteKit/CyteKit.h" +#include "CyteKit/RegEx.hpp" #include "Cydia/MIMEAddress.h" #include "Cydia/LoadingViewController.h" #include "Cydia/ProgressEvent.h" - -#include "SDURLCache/SDURLCache.h" /* }}} */ /* Profiler {{{ */ @@ -198,10 +188,6 @@ void PrintTimes() { #define _end } /* }}} */ -// XXX: I hate clang. Apple: please get over your petty hatred of GPL and fix your gcc fork -#define synchronized(lock) \ - synchronized(static_cast(lock)) - extern NSString *Cydia_; #define lprintf(args...) fprintf(stderr, args) @@ -239,35 +225,6 @@ union SplitHash { }; // }}} -static void setreugid(uid_t uid, gid_t gid) { - _assert(setreuid(uid, uid) != -1); - _assert(setregid(gid, gid) != -1); -} - -static void setreguid(gid_t gid, uid_t uid) { - _assert(setregid(gid, gid) != -1); - _assert(setreuid(uid, uid) != -1); -} - -struct Root { - Root() { - _trace(); - setreugid(0, 0); - _assert(pthread_setugid_np(0, 0) != -1); - setreguid(501, 501); - } - - ~Root() { - _trace(); - setreugid(0, 0); - _assert(pthread_setugid_np(KAUTH_UID_NONE, KAUTH_GID_NONE) != -1); - setreguid(501, 501); - } -}; - -#define _root(code) \ - ({ Root _root; code; }) - static NSString *Colon_; NSString *Elision_; static NSString *Error_; @@ -278,6 +235,7 @@ static NSString *Cache_; [NSString stringWithFormat:@"%@/%s", Cache_, file] static void (*$SBSSetInterceptsMenuButtonForever)(bool); +static NSData *(*$SBSCopyIconImagePNGDataForDisplayIdentifier)(NSString *); static CFStringRef (*$MGCopyAnswer)(CFStringRef); @@ -288,26 +246,6 @@ static NSString *UniqueIdentifier(UIDevice *device = nil) { return [(id)$MGCopyAnswer(CFSTR("UniqueDeviceID")) autorelease]; } -static bool IsReachable(const char *name) { - SCNetworkReachabilityFlags flags; { - SCNetworkReachabilityRef reachability(SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, name)); - SCNetworkReachabilityGetFlags(reachability, &flags); - CFRelease(reachability); - } - - // XXX: this elaborate mess is what Apple is using to determine this? :( - // XXX: do we care if the user has to intervene? maybe that's ok? - return - (flags & kSCNetworkReachabilityFlagsReachable) != 0 && ( - (flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0 || ( - (flags & kSCNetworkReachabilityFlagsConnectionOnDemand) != 0 || - (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0 - ) && (flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0 || - (flags & kSCNetworkReachabilityFlagsIsWWAN) != 0 - ) - ; -} - static const NSUInteger UIViewAutoresizingFlexibleBoth(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); static _finline NSString *CydiaURL(NSString *path) { @@ -321,13 +259,8 @@ static _finline NSString *CydiaURL(NSString *path) { return [[NSString stringWithUTF8String:page] stringByAppendingString:path]; } -static void ReapZombie(pid_t pid) { - int status; - wait: - if (waitpid(pid, &status, 0) == -1) - if (errno == EINTR) - goto wait; - else _assert(false); +static NSString *ShellEscape(NSString *value) { + return [NSString stringWithFormat:@"'%@'", [value stringByReplacingOccurrencesOfString:@"'" withString:@"'\\''"]]; } static _finline void UpdateExternalStatus(uint64_t newStatus) { @@ -339,11 +272,6 @@ static _finline void UpdateExternalStatus(uint64_t newStatus) { notify_post("com.saurik.Cydia.status"); } -static CGFloat CYStatusBarHeight() { - CGSize size([[UIApplication sharedApplication] statusBarFrame].size); - return UIInterfaceOrientationIsPortrait([[UIApplication sharedApplication] statusBarOrientation]) ? size.height : size.width; -} - /* NSForcedOrderingSearch doesn't work on the iPhone */ static const NSStringCompareOptions MatchCompareOptions_ = NSLiteralSearch | NSCaseInsensitiveSearch; static const NSStringCompareOptions LaxCompareOptions_ = NSNumericSearch | NSDiacriticInsensitiveSearch | NSWidthInsensitiveSearch | NSCaseInsensitiveSearch; @@ -351,53 +279,47 @@ static const CFStringCompareFlags LaxCompareFlags_ = kCFCompareNumerically | kCF /* Insertion Sort {{{ */ -CFIndex SKBSearch_(const void *element, CFIndex elementSize, const void *list, CFIndex count, CFComparatorFunction comparator, void *context) { - const char *ptr = (const char *)list; - while (0 < count) { - CFIndex half = count / 2; - const char *probe = ptr + elementSize * half; - CFComparisonResult cr = comparator(element, probe, context); - if (0 == cr) return (probe - (const char *)list) / elementSize; - ptr = (cr < 0) ? ptr : probe + elementSize; - count = (cr < 0) ? half : (half + (count & 1) - 1); - } - return (ptr - (const char *)list) / elementSize; -} - -CFIndex CFBSearch_(const void *element, CFIndex elementSize, const void *list, CFIndex count, CFComparatorFunction comparator, void *context) { +template +size_t CFBSearch_(const Type_ &element, const void *list, size_t count, CFComparisonResult (*comparator)(Type_, Type_, void *), void *context) { const char *ptr = (const char *)list; while (0 < count) { - CFIndex half = count / 2; - const char *probe = ptr + elementSize * half; - CFComparisonResult cr = comparator(element, probe, context); - if (0 == cr) return (probe - (const char *)list) / elementSize; - ptr = (cr < 0) ? ptr : probe + elementSize; + size_t half = count / 2; + const char *probe = ptr + sizeof(Type_) * half; + CFComparisonResult cr = comparator(element, * (const Type_ *) probe, context); + if (0 == cr) return (probe - (const char *)list) / sizeof(Type_); + ptr = (cr < 0) ? ptr : probe + sizeof(Type_); count = (cr < 0) ? half : (half + (count & 1) - 1); } - return (ptr - (const char *)list) / elementSize; + return (ptr - (const char *)list) / sizeof(Type_); } -void CFArrayInsertionSortValues(CFMutableArrayRef array, CFRange range, CFComparatorFunction comparator, void *context) { - if (range.length == 0) +template +void CYArrayInsertionSortValues(Type_ *values, size_t length, CFComparisonResult (*comparator)(Type_, Type_, void *), void *context) { + if (length == 0) return; - const void **values(new const void *[range.length]); - CFArrayGetValues(array, range, values); #if HistogramInsertionSort > 0 - uint32_t total(0), *offsets(new uint32_t[range.length]); + uint32_t total(0), *offsets(new uint32_t[length]); #endif - for (CFIndex index(1); index != range.length; ++index) { - const void *value(values[index]); - //CFIndex correct(SKBSearch_(&value, sizeof(const void *), values, index, comparator, context)); - CFIndex correct(index); + for (size_t index(1); index != length; ++index) { + Type_ value(values[index]); +#if 0 + size_t correct(CFBSearch_(value, values, index, comparator, context)); +#else + size_t correct(index); while (comparator(value, values[correct - 1], context) == kCFCompareLessThan) { #if HistogramInsertionSort > 1 NSLog(@"%@ < %@", value, values[correct - 1]); #endif if (--correct == 0) break; + if (index - correct >= 8) { + correct = CFBSearch_(value, values, correct, comparator, context); + break; + } } +#endif if (correct != index) { size_t offset(index - correct); #if HistogramInsertionSort @@ -411,11 +333,8 @@ void CFArrayInsertionSortValues(CFMutableArrayRef array, CFRange range, CFCompar } } - CFArrayReplaceValues(array, range, values, range.length); - delete [] values; - #if HistogramInsertionSort > 0 - for (CFIndex index(0); index != range.length; ++index) + for (size_t index(0); index != range.length; ++index) if (offsets[index] != 0) NSLog(@"Insertion Displacement [%u]: %u", index, offsets[index]); NSLog(@"Average Insertion Displacement: %f", double(total) / range.length); @@ -425,47 +344,6 @@ void CFArrayInsertionSortValues(CFMutableArrayRef array, CFRange range, CFCompar /* }}} */ -/* Apple Bug Fixes {{{ */ -@implementation UIWebDocumentView (Cydia) - -- (void) _setScrollerOffset:(CGPoint)offset { - UIScroller *scroller([self _scroller]); - - CGSize size([scroller contentSize]); - CGSize bounds([scroller bounds].size); - - CGPoint max; - max.x = size.width - bounds.width; - max.y = size.height - bounds.height; - - // wtf Apple?! - if (max.x < 0) - max.x = 0; - if (max.y < 0) - max.y = 0; - - offset.x = offset.x < 0 ? 0 : offset.x > max.x ? max.x : offset.x; - offset.y = offset.y < 0 ? 0 : offset.y > max.y ? max.y : offset.y; - - [scroller setOffset:offset]; -} - -@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) - return 0; - else if (length > count) - length = count; - for (size_t i(0); i != length; ++i) - objects[i] = [self item:state->state++]; - state->itemsPtr = objects; - state->mutationsPtr = (unsigned long *) self; - return length; -} - /* Cydia NSString Additions {{{ */ @interface NSString (Cydia) - (NSComparisonResult) compareByPath:(NSString *)other; @@ -524,6 +402,10 @@ static _finline CFStringRef CYStringCreate(const char *data, size_t size) { CFStringCreateWithBytesNoCopy(kCFAllocatorDefault, reinterpret_cast(data), size, kCFStringEncodingISOLatin1, NO, kCFAllocatorNull); } +static _finline CFStringRef CYStringCreate(const std::string &data) { + return CYStringCreate(data.data(), data.size()); +} + static _finline CFStringRef CYStringCreate(const char *data) { return CYStringCreate(data, strlen(data)); } @@ -580,14 +462,14 @@ class CYString { cache_ = reinterpret_cast(CFRetain(rhs.cache_)); } - void copy(apr_pool_t *pool) { - char *temp(reinterpret_cast(apr_palloc(pool, size_ + 1))); + void copy(CYPool *pool) { + char *temp(pool->malloc(size_ + 1)); memcpy(temp, data_, size_); temp[size_] = '\0'; data_ = temp; } - void set(apr_pool_t *pool, const char *data, size_t size) { + void set(CYPool *pool, const char *data, size_t size) { if (size == 0) clear(); else { @@ -601,11 +483,11 @@ class CYString { } } - _finline void set(apr_pool_t *pool, const char *data) { + _finline void set(CYPool *pool, const char *data) { set(pool, data, data == NULL ? 0 : strlen(data)); } - _finline void set(apr_pool_t *pool, const std::string &rhs) { + _finline void set(CYPool *pool, const std::string &rhs) { set(pool, rhs.data(), rhs.size()); } @@ -709,7 +591,6 @@ static const NSString *UI_; static int Finish_; static bool RestartSubstrate_; -static bool UpgradeCydia_; static NSArray *Finishes_; #define SpringBoard_ "/System/Library/LaunchDaemons/com.apple.SpringBoard.plist" @@ -743,16 +624,7 @@ static _H Font18_; static _H Font18Bold_; static _H Font22Bold_; -static const char *Machine_ = NULL; -static _H System_; -static NSString *SerialNumber_ = nil; -static NSString *ChipID_ = nil; -static NSString *BBSNum_ = nil; -static _H Token_; static _H UniqueID_; -static _H UserAgent_; -static _H Product_; -static _H Safari_; static _H CollationLocale_; static _H CollationThumbs_; @@ -808,30 +680,20 @@ static CFLocaleRef Locale_; static NSArray *Languages_; static CGColorSpaceRef space_; +#define CacheState_ "/var/mobile/Library/Caches/com.saurik.Cydia/CacheState.plist" +#define SavedState_ "/var/mobile/Library/Caches/com.saurik.Cydia/SavedState.plist" + static NSDictionary *SectionMap_; -static NSMutableDictionary *Metadata_; -static _transient NSMutableDictionary *Settings_; -static _transient NSMutableDictionary *Packages_; +static _H Backgrounded_; static _transient NSMutableDictionary *Values_; static _transient NSMutableDictionary *Sections_; _H Sources_; static _transient NSNumber *Version_; -bool Changed_; static time_t now_; -bool IsWildcat_; -CGFloat ScreenScale_; -static NSString *Idiom_; -static _H Firmware_; -static NSString *Major_; - static _H SessionData_; -static _H HostConfig_; static _H BridgedHosts_; -static _H TokenHosts_; static _H InsecureHosts_; -static _H PipelinedHosts_; -static _H CachedURLs_; static NSString *kCydiaProgressEventTypeError = @"Error"; static NSString *kCydiaProgressEventTypeInformation = @"Information"; @@ -840,37 +702,13 @@ static NSString *kCydiaProgressEventTypeWarning = @"Warning"; /* }}} */ /* Display Helpers {{{ */ -inline float Interpolate(float begin, float end, float fraction) { - return (end - begin) * fraction + begin; -} - -static inline double Retina(double value) { - value *= ScreenScale_; - value = round(value); - value /= ScreenScale_; - return value; -} - -static inline CGRect Retina(CGRect value) { - value.origin.x *= ScreenScale_; - value.origin.y *= ScreenScale_; - value.size.width *= ScreenScale_; - value.size.height *= ScreenScale_; - value = CGRectIntegral(value); - value.origin.x /= ScreenScale_; - value.origin.y /= ScreenScale_; - value.size.width /= ScreenScale_; - value.size.height /= ScreenScale_; - return value; -} - static _finline const char *StripVersion_(const char *version) { const char *colon(strchr(version, ':')); return colon == NULL ? version : colon + 1; } NSString *LocalizeSection(NSString *section) { - static Pcre title_r("^(.*?) \\((.*)\\)$"); + static RegEx title_r("(.*?) \\((.*)\\)"); if (title_r(section)) { NSString *parent(title_r[1]); NSString *child(title_r[2]); @@ -888,15 +726,15 @@ NSString *Simplify(NSString *title) { const char *data = [title UTF8String]; size_t size = [title lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; - static Pcre square_r("^\\[(.*)\\]$"); + static RegEx square_r("\\[(.*)\\]"); if (square_r(data, size)) return Simplify(square_r[1]); - static Pcre paren_r("^\\((.*)\\)$"); + static RegEx paren_r("\\((.*)\\)"); if (paren_r(data, size)) return Simplify(paren_r[1]); - static Pcre title_r("^(.*?) \\((.*)\\)$"); + static RegEx title_r("(.*?) \\((.*)\\)"); if (title_r(data, size)) return Simplify(title_r[1]); @@ -904,52 +742,29 @@ NSString *Simplify(NSString *title) { } /* }}} */ -NSString *GetLastUpdate() { - NSDate *update = [Metadata_ objectForKey:@"LastUpdate"]; - - if (update == nil) - return UCLocalize("NEVER_OR_UNKNOWN"); - - CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, Locale_, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle); - CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) update); - - CFRelease(formatter); - - return [(NSString *) formatted autorelease]; -} - bool isSectionVisible(NSString *section) { NSDictionary *metadata([Sections_ objectForKey:(section ?: @"")]); NSNumber *hidden(metadata == nil ? nil : [metadata objectForKey:@"Hidden"]); return hidden == nil || ![hidden boolValue]; } -static NSObject *CYIOGetValue(const char *path, NSString *property) { - io_registry_entry_t entry(IORegistryEntryFromPath(kIOMasterPortDefault, path)); - if (entry == MACH_PORT_NULL) - return nil; - - CFTypeRef value(IORegistryEntryCreateCFProperty(entry, (CFStringRef) property, kCFAllocatorDefault, 0)); - IOObjectRelease(entry); - - if (value == NULL) - return nil; - return [(id) value autorelease]; -} +static NSString *VerifySource(NSString *href) { + static RegEx href_r("(http(s?)://|file:///)[^# ]*"); + if (!href_r(href)) { + [[[[UIAlertView alloc] + initWithTitle:[NSString stringWithFormat:Colon_, Error_, UCLocalize("INVALID_URL")] + message:UCLocalize("INVALID_URL_EX") + delegate:nil + cancelButtonTitle:UCLocalize("OK") + otherButtonTitles:nil + ] autorelease] show]; -static NSString *CYHex(NSData *data, bool reverse = false) { - if (data == nil) return nil; + } - size_t length([data length]); - uint8_t bytes[length]; - [data getBytes:bytes]; - - char string[length * 2 + 1]; - for (size_t i(0); i != length; ++i) - sprintf(string + i * 2, "%.2x", bytes[reverse ? length - i - 1 : i]); - - return [NSString stringWithUTF8String:string]; + if (![href hasSuffix:@"/"]) + href = [href stringByAppendingString:@"/"]; + return href; } @class Cydia; @@ -995,7 +810,7 @@ static NSString *CYHex(NSData *data, bool reverse = false) { - (void) _saveConfig; - (void) syncData; - (void) addSource:(NSDictionary *)source; -- (void) addTrivialSource:(NSString *)href; +- (BOOL) addTrivialSource:(NSString *)href; - (UIProgressHUD *) addProgressHUD; - (void) removeProgressHUD:(UIProgressHUD *)hud; - (void) showActionSheet:(UIActionSheet *)sheet fromItem:(UIBarButtonItem *)item; @@ -1118,9 +933,10 @@ typedef std::map< unsigned long, _H > SourceMap; @interface Database : NSObject { NSZone *zone_; - apr_pool_t *pool_; + CYPool pool_; unsigned era_; + _H delock_; pkgCacheFile cache_; pkgDepCache::Policy *policy_; @@ -1134,7 +950,7 @@ typedef std::map< unsigned long, _H > SourceMap; SourceMap sourceMap_; _H sourceList_; - CFMutableArrayRef packages_; + _H packages_; _transient NSObject *delegate_; _transient NSObject *progress_; @@ -1150,6 +966,7 @@ typedef std::map< unsigned long, _H > SourceMap; + (Database *) sharedInstance; - (unsigned) era; +- (bool) hasPackages; - (void) _readCydia:(NSNumber *)fd; - (void) _readStatus:(NSNumber *)fd; @@ -1217,7 +1034,10 @@ class SourceStatus : } //printf("Set(%s, %s)\n", fetch ? "true" : "false", uri.c_str()); - [database_ setFetch:fetch forURI:uri.c_str()]; + + auto slash(uri.rfind('/')); + if (slash != std::string::npos) + [database_ setFetch:fetch forURI:uri.substr(0, slash).c_str()]; } _finline void Set(bool fetch, pkgAcquire::Item *item) { @@ -1435,14 +1255,14 @@ struct PackageValue : char version_[8]; char name_[]; -}; +} _packed; struct MetaValue : Cytore::Block { uint32_t active_; Cytore::Offset packages_[1 << 16]; -}; +} _packed; static Cytore::File MetaFile_; // }}} @@ -1525,6 +1345,30 @@ static void PackageImport(const void *key, const void *value, void *context) { } // }}} +static NSDate *GetStatusDate() { + return [[[NSFileManager defaultManager] attributesOfItemAtPath:@"/var/lib/dpkg/status" error:NULL] fileModificationDate]; +} + +static void SaveConfig(NSObject *lock) { + @synchronized (lock) { + _trace(); + MetaFile_.Sync(); + _trace(); + } + + CFPreferencesSetMultiple((CFDictionaryRef) [NSDictionary dictionaryWithObjectsAndKeys: + Values_, @"CydiaValues", + Sections_, @"CydiaSections", + (id) Sources_, @"CydiaSources", + Version_, @"CydiaVersion", + nil], NULL, CFSTR("com.saurik.Cydia"), kCFPreferencesCurrentUser, kCFPreferencesCurrentHost); + + if (!CFPreferencesAppSynchronize(CFSTR("com.saurik.Cydia"))) + NSLog(@"CFPreferencesAppSynchronize(com.saurik.Cydia) == false"); + + CydiaWriteSources(); +} + /* Source Class {{{ */ @interface Source : NSObject { unsigned era_; @@ -1556,7 +1400,7 @@ static void PackageImport(const void *key, const void *value, void *context) { _transient NSObject *delegate_; } -- (Source *) initWithMetaIndex:(metaIndex *)index forDatabase:(Database *)database inPool:(apr_pool_t *)pool; +- (Source *) initWithMetaIndex:(metaIndex *)index forDatabase:(Database *)database inPool:(CYPool *)pool; - (NSComparisonResult) compareByName:(Source *)source; @@ -1639,7 +1483,7 @@ static void PackageImport(const void *key, const void *value, void *context) { return index_; } -- (void) setMetaIndex:(metaIndex *)index inPool:(apr_pool_t *)pool { +- (void) setMetaIndex:(metaIndex *)index inPool:(CYPool *)pool { trusted_ = index->IsTrusted(); uri_.set(pool, index->GetURI()); @@ -1658,13 +1502,10 @@ static void PackageImport(const void *key, const void *value, void *context) { _profile(Source$setMetaIndex$DescURI) for (pkgAcquire::ItemIterator item(acquire.ItemsBegin()); item != acquire.ItemsEnd(); item++) { std::string file((*item)->DescURI()); - files_.insert(file); - if (file.length() < sizeof("Packages.bz2") || file.substr(file.length() - sizeof("Packages.bz2")) != "/Packages.bz2") + auto slash(file.rfind('/')); + if (slash == std::string::npos) continue; - file = file.substr(0, file.length() - 4); - files_.insert(file); - files_.insert(file + ".gz"); - files_.insert(file + "Index"); + files_.insert(file.substr(0, slash)); } _end @@ -1715,7 +1556,7 @@ static void PackageImport(const void *key, const void *value, void *context) { authority_ = [url path]; } -- (Source *) initWithMetaIndex:(metaIndex *)index forDatabase:(Database *)database inPool:(apr_pool_t *)pool { +- (Source *) initWithMetaIndex:(metaIndex *)index forDatabase:(Database *)database inPool:(CYPool *)pool { if ((self = [super init]) != nil) { era_ = [database era]; database_ = database; @@ -1787,14 +1628,10 @@ static void PackageImport(const void *key, const void *value, void *context) { if (record_ == nil) return; else if (NSMutableArray *sections = [record_ objectForKey:@"Sections"]) { - if (![sections containsObject:section]) { + if (![sections containsObject:section]) [sections addObject:section]; - Changed_ = true; - } - } else { + } else [record_ setObject:[NSMutableArray arrayWithObject:section] forKey:@"Sections"]; - Changed_ = true; - } } - (bool) addSection:(NSString *)section { @@ -1810,10 +1647,8 @@ static void PackageImport(const void *key, const void *value, void *context) { return; if (NSMutableArray *sections = [record_ objectForKey:@"Sections"]) - if ([sections containsObject:section]) { + if ([sections containsObject:section]) [sections removeObject:section]; - Changed_ = true; - } } - (bool) removeSection:(NSString *)section { @@ -1826,7 +1661,6 @@ static void PackageImport(const void *key, const void *value, void *context) { - (void) _remove { [Sources_ removeObjectForKey:[self key]]; - Changed_ = true; } - (bool) remove { @@ -2110,7 +1944,7 @@ struct ParsedPackage { uint32_t ignored_ : 1; uint32_t pooled_ : 1; - apr_pool_t *pool_; + CYPool *pool_; uint32_t rank_; @@ -2139,8 +1973,10 @@ struct ParsedPackage { _H tags_; } -- (Package *) initWithVersion:(pkgCache::VerIterator)version withZone:(NSZone *)zone inPool:(apr_pool_t *)pool database:(Database *)database; -+ (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator withZone:(NSZone *)zone inPool:(apr_pool_t *)pool database:(Database *)database; +- (Package *) initWithVersion:(pkgCache::VerIterator)version withZone:(NSZone *)zone inPool:(CYPool *)pool database:(Database *)database; ++ (Package *) newPackageWithIterator:(pkgCache::PkgIterator)iterator withZone:(NSZone *)zone inPool:(CYPool *)pool database:(Database *)database; + ++ (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator withZone:(NSZone *)zone inPool:(CYPool *)pool database:(Database *)database; - (pkgCache::PkgIterator) iterator; - (void) parse; @@ -2171,7 +2007,6 @@ struct ParsedPackage { - (NSString *) installed; - (BOOL) uninstalled; -- (BOOL) valid; - (BOOL) upgradableAndEssential:(BOOL)essential; - (BOOL) essential; - (BOOL) broken; @@ -2357,7 +2192,7 @@ struct PackageNameOrdering : - (void) dealloc { if (!pooled_) - apr_pool_destroy(pool_); + delete pool_; if (parsed_ != NULL) delete parsed_; [super dealloc]; @@ -2518,15 +2353,7 @@ struct PackageNameOrdering : _end _profile(Package$parse$Tagline) - const char *start, *end; - if (parser->ShortDesc(start, end)) { - const char *stop(reinterpret_cast(memchr(start, '\n', end - start))); - if (stop == NULL) - stop = end; - while (stop != start && stop[-1] == '\r') - --stop; - parsed->tagline_.set(pool_, start, stop - start); - } + parsed->tagline_.set(pool_, parser->ShortDesc()); _end _profile(Package$parse$Retain) @@ -2540,11 +2367,11 @@ struct PackageNameOrdering : _end } } -- (Package *) initWithVersion:(pkgCache::VerIterator)version withZone:(NSZone *)zone inPool:(apr_pool_t *)pool database:(Database *)database { +- (Package *) initWithVersion:(pkgCache::VerIterator)version withZone:(NSZone *)zone inPool:(CYPool *)pool database:(Database *)database { if ((self = [super init]) != nil) { _profile(Package$initWithVersion) if (pool == NULL) - apr_pool_create(&pool_, NULL); + pool_ = new CYPool(); else { pool_ = pool; pooled_ = true; @@ -2555,20 +2382,15 @@ struct PackageNameOrdering : version_ = version; - pkgCache::PkgIterator iterator(version.ParentPkg()); + pkgCache::PkgIterator iterator(version_.ParentPkg()); iterator_ = iterator; _profile(Package$initWithVersion$Version) - if (!version_.end()) - file_ = version_.FileList(); - else { - pkgCache &cache([database_ cache]); - file_ = pkgCache::VerFileIterator(cache, cache.VerFileP); - } + file_ = version_.FileList(); _end _profile(Package$initWithVersion$Cache) - name_.set(NULL, iterator.Display()); + name_.set(NULL, version_.Display()); latest_.set(NULL, StripVersion_(version_.VerStr())); @@ -2620,7 +2442,7 @@ struct PackageNameOrdering : char *transform; _profile(Package$initWithVersion$Transliterate$apr_palloc) - transform = static_cast(apr_palloc(pool_, length)); + transform = pool_->malloc(length); _end _profile(Package$initWithVersion$Transliterate$u_strToUTF8WithSub$transform) u_strToUTF8WithSub(transform, length, NULL, CollationString_.data(), CollationString_.size(), 0xfffd, NULL, &code); @@ -2632,7 +2454,11 @@ struct PackageNameOrdering : } while (false); _end _profile(Package$initWithVersion$Tags) +#ifdef __arm64__ + pkgCache::TagIterator tag(version_.TagList()); +#else pkgCache::TagIterator tag(iterator.TagList()); +#endif if (!tag.end()) { tags_ = [NSMutableArray arrayWithCapacity:8]; @@ -2719,7 +2545,7 @@ struct PackageNameOrdering : _end } return self; } -+ (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator withZone:(NSZone *)zone inPool:(apr_pool_t *)pool database:(Database *)database { ++ (Package *) newPackageWithIterator:(pkgCache::PkgIterator)iterator withZone:(NSZone *)zone inPool:(CYPool *)pool database:(Database *)database { pkgCache::VerIterator version; _profile(Package$packageWithIterator$GetCandidateVer) @@ -2744,17 +2570,33 @@ struct PackageNameOrdering : ]; _end - _profile(Package$packageWithIterator$Autorelease) - package = [package autorelease]; - _end - return package; } +// XXX: just in case a Cydia extension is using this (I bet this is unlikely, though, due to CYPool?) ++ (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator withZone:(NSZone *)zone inPool:(CYPool *)pool database:(Database *)database { + return [[self newPackageWithIterator:iterator withZone:zone inPool:pool database:database] autorelease]; +} + - (pkgCache::PkgIterator) iterator { return iterator_; } +- (NSArray *) downgrades { + NSMutableArray *versions([NSMutableArray arrayWithCapacity:4]); + + for (auto version(iterator_.VersionList()); !version.end(); ++version) { + if (version == version_) + continue; + Package *package([[[Package allocWithZone:NULL] initWithVersion:version withZone:NULL inPool:NULL database:database_] autorelease]); + if ([package source] == nil) + continue; + [versions addObject:package]; + } + + return versions; +} + - (NSString *) section { if (section$_ == nil) { if (section_ == NULL) @@ -2774,7 +2616,10 @@ struct PackageNameOrdering : } - (NSString *) longSection { - return LocalizeSection([self section]); + if (NSString *section = [self section]) + return LocalizeSection(section); + else + return nil; } - (NSString *) shortSection { @@ -2844,23 +2689,12 @@ struct PackageNameOrdering : @synchronized (database_) { pkgRecords::Parser &parser([database_ records]->Lookup(file_)); - - const char *start, *end; - if (!parser.ShortDesc(start, end)) + std::string value(parser.ShortDesc()); + if (value.empty()) return nil; - - if (end - start > 200) - end = start + 200; - - /* - if (const char *stop = reinterpret_cast(memchr(start, '\n', end - start))) - end = stop; - - while (end != start && end[-1] == '\r') - --end; - */ - - return [(id) CYStringCreate(start, end - start) autorelease]; + if (value.size() > 200) + value.resize(200); + return [(id) CYStringCreate(value) autorelease]; } } - (unichar) index { @@ -2912,17 +2746,13 @@ struct PackageNameOrdering : return installed_.empty(); } -- (BOOL) valid { - return !version_.end(); -} - - (BOOL) upgradableAndEssential:(BOOL)essential { _profile(Package$upgradableAndEssential) pkgCache::VerIterator current(iterator_.CurrentVer()); if (current.end()) return essential && essential_; else - return !version_.end() && version_ != current; + return version_ != current; _end } @@ -3200,13 +3030,15 @@ struct PackageNameOrdering : NSMutableArray *applications([NSMutableArray arrayWithCapacity:2]); - static Pcre application_r("^/Applications/(.*)\\.app/Info.plist$"); + static RegEx application_r("/Applications/(.*)\\.app/Info.plist"); if (NSArray *files = [self files]) for (NSString *file in files) if (application_r(file)) { NSDictionary *info([NSDictionary dictionaryWithContentsOfFile:file]); + if (info == nil) + continue; NSString *id([info objectForKey:@"CFBundleIdentifier"]); - if ([id isEqualToString:me]) + if (id == nil || [id isEqualToString:me]) continue; NSString *display([info objectForKey:@"CFBundleDisplayName"]); @@ -3330,8 +3162,8 @@ struct PackageNameOrdering : } - (void) setIndex:(size_t)index { - if (metadata_->index_ != index) - metadata_->index_ = index; + if (metadata_->index_ != index + 1) + metadata_->index_ = index + 1; } - (CYString &) cyname { @@ -3350,6 +3182,9 @@ struct PackageNameOrdering : - (void) clear { @synchronized (database_) { + if ([database_ era] != era_ || file_.end()) + return; + pkgProblemResolver *resolver = [database_ resolver]; resolver->Clear(iterator_); @@ -3360,11 +3195,15 @@ struct PackageNameOrdering : - (void) install { @synchronized (database_) { + if ([database_ era] != era_ || file_.end()) + return; + pkgProblemResolver *resolver = [database_ resolver]; resolver->Clear(iterator_); resolver->Protect(iterator_); pkgCacheFile &cache([database_ cache]); + cache->SetCandidateVersion(version_); cache->SetReInstall(iterator_, false); cache->MarkInstall(iterator_, false); @@ -3375,6 +3214,9 @@ struct PackageNameOrdering : - (void) remove { @synchronized (database_) { + if ([database_ era] != era_ || file_.end()) + return; + pkgProblemResolver *resolver = [database_ resolver]; resolver->Clear(iterator_); resolver->Remove(iterator_); @@ -3512,25 +3354,26 @@ class CydiaLogCleaner : } - (void) releasePackages { - CFArrayApplyFunction(packages_, CFRangeMake(0, CFArrayGetCount(packages_)), reinterpret_cast(&CFRelease), NULL); - CFArrayRemoveAllValues(packages_); + packages_ = nil; +} + +- (bool) hasPackages { + return [packages_ count] != 0; } - (void) dealloc { // XXX: actually implement this thing _assert(false); [self releasePackages]; - apr_pool_destroy(pool_); NSRecycleZone(zone_); [super dealloc]; } - (void) _readCydia:(NSNumber *)fd { - __gnu_cxx::stdio_filebuf ib([fd intValue], std::ios::in); - std::istream is(&ib); + boost::fdistream is([fd intValue]); std::string line; - static Pcre finish_r("^finish:([^:]*)$"); + static RegEx finish_r("finish:([^:]*)"); while (std::getline(is, line)) { NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]); @@ -3553,12 +3396,11 @@ class CydiaLogCleaner : } - (void) _readStatus:(NSNumber *)fd { - __gnu_cxx::stdio_filebuf ib([fd intValue], std::ios::in); - std::istream is(&ib); + boost::fdistream is([fd intValue]); std::string line; - static Pcre conffile_r("^status: [^ ]* : conffile-prompt : (.*?) *$"); - static Pcre pmstatus_r("^([^:]*):([^:]*):([^:]*):(.*)$"); + static RegEx conffile_r("status: [^ ]* : conffile-prompt : (.*?) *"); + static RegEx pmstatus_r("([^:]*):([^:]*):([^:]*):(.*)"); while (std::getline(is, line)) { NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]); @@ -3610,8 +3452,7 @@ class CydiaLogCleaner : } - (void) _readOutput:(NSNumber *)fd { - __gnu_cxx::stdio_filebuf ib([fd intValue], std::ios::in); - std::istream is(&ib); + boost::fdistream is([fd intValue]); std::string line; while (std::getline(is, line)) { @@ -3638,8 +3479,12 @@ class CydiaLogCleaner : @synchronized (self) { if (static_cast(cache_) == NULL) return nil; - pkgCache::PkgIterator iterator(cache_->FindPkg([name UTF8String])); - return iterator.end() ? nil : [Package packageWithIterator:iterator withZone:NULL inPool:NULL database:self]; + pkgCache::PkgIterator iterator(cache_->FindPkg([name UTF8String] +#ifdef __arm64__ + , "any" +#endif + )); + return iterator.end() ? nil : [[Package newPackageWithIterator:iterator withZone:NULL inPool:NULL database:self] autorelease]; } } - (id) init { @@ -3651,15 +3496,7 @@ class CydiaLogCleaner : lock_ = NULL; zone_ = NSCreateZone(1024 * 1024, 256 * 1024, NO); - apr_pool_create(&pool_, NULL); - - size_t capacity(MetaFile_->active_); - if (capacity == 0) - capacity = 16384; - else - capacity += 1024; - packages_ = CFArrayCreateMutable(kCFAllocatorDefault, capacity, NULL); sourceList_ = [NSMutableArray arrayWithCapacity:16]; int fds[2]; @@ -3728,7 +3565,7 @@ class CydiaLogCleaner : } - (NSArray *) packages { - return (NSArray *) packages_; + return packages_; } - (NSArray *) sources { @@ -3760,7 +3597,7 @@ class CydiaLogCleaner : lprintf("%c:[%s]\n", warning ? 'W' : 'E', error.c_str()); - static Pcre no_pubkey("^GPG error:.* NO_PUBKEY .*$"); + static RegEx no_pubkey("GPG error:.* NO_PUBKEY .*"); if (warning && no_pubkey(error.c_str())) continue; @@ -3774,6 +3611,31 @@ class CydiaLogCleaner : return [self popErrorWithTitle:title] || !success; } +- (bool) popErrorWithTitle:(NSString *)title forReadList:(pkgSourceList &)list { + if ([self popErrorWithTitle:title forOperation:list.ReadMainList()]) + return true; + return false; + + list.Reset(); + + bool error(false); + + if (access("/etc/apt/sources.list", F_OK) == 0) + error |= [self popErrorWithTitle:title forOperation:list.ReadAppend("/etc/apt/sources.list")]; + + std::string base("/etc/apt/sources.list.d"); + if (DIR *sources = opendir(base.c_str())) { + while (dirent *source = readdir(sources)) + if (source->d_name[0] != '.' && source->d_namlen > 5 && strcmp(source->d_name + source->d_namlen - 5, ".list") == 0 && strcmp(source->d_name, "cydia.list") != 0) + error |= [self popErrorWithTitle:title forOperation:list.ReadAppend((base + "/" + source->d_name).c_str())]; + closedir(sources); + } + + error |= [self popErrorWithTitle:title forOperation:list.ReadAppend(SOURCES_LIST)]; + + return error; +} + - (void) reloadDataWithInvocation:(NSInvocation *)invocation { @synchronized (self) { ++era_; @@ -3801,7 +3663,8 @@ class CydiaLogCleaner : cache_.Close(); - apr_pool_clear(pool_); + pool_.~CYPool(); + new (&pool_) CYPool(); NSRecycleZone(zone_); zone_ = NSCreateZone(1024 * 1024, 256 * 1024, NO); @@ -3817,28 +3680,27 @@ class CydiaLogCleaner : list_ = new pkgSourceList(); _profile(reloadDataWithInvocation$ReadMainList) - if ([self popErrorWithTitle:title forOperation:list_->ReadMainList()]) + if ([self popErrorWithTitle:title forReadList:*list_]) return; _end _profile(reloadDataWithInvocation$Source$initWithMetaIndex) for (pkgSourceList::const_iterator source = list_->begin(); source != list_->end(); ++source) { - Source *object([[[Source alloc] initWithMetaIndex:*source forDatabase:self inPool:pool_] autorelease]); + Source *object([[[Source alloc] initWithMetaIndex:*source forDatabase:self inPool:&pool_] autorelease]); [sourceList_ addObject:object]; } _end - _root(_system->Lock()); - _trace(); OpProgress progress; bool opened; open: + delock_ = GetStatusDate(); _profile(reloadDataWithInvocation$pkgCacheFile) opened = cache_.Open(progress, false); _end if (!opened) { - // XXX: what if there are errors, but Open() == true? this should be merged with popError: + // XXX: this block should probably be merged with popError: in some way while (!_error->empty()) { std::string error; bool warning(!_error->PopMessage(error)); @@ -3865,9 +3727,9 @@ class CydiaLogCleaner : } } - _system->UnLock(); return; - } + } else if ([self popErrorWithTitle:title forOperation:true]) + return; _trace(); unlink("/tmp/cydia.chk"); @@ -3920,40 +3782,89 @@ class CydiaLogCleaner : } { - /*std::vector packages; - packages.reserve(std::max(10000U, [packages_ count] + 1000)); - packages_ = nil;*/ + size_t capacity(MetaFile_->active_); + if (capacity == 0) + capacity = 128*1024; + else + capacity += 1024; + std::vector packages; + packages.reserve(capacity); + size_t lost(0); + + size_t last(0); _profile(reloadDataWithInvocation$packageWithIterator) for (pkgCache::PkgIterator iterator = cache_->PkgBegin(); !iterator.end(); ++iterator) - if (Package *package = [Package packageWithIterator:iterator withZone:zone_ inPool:pool_ database:self]) - //packages.push_back(package); - CFArrayAppendValue(packages_, CFRetain(package)); + if (Package *package = [Package newPackageWithIterator:iterator withZone:zone_ inPool:&pool_ database:self]) { + if (unsigned index = package.metadata->index_) { + --index; + if (packages.size() == index) { + packages.push_back(package); + } else if (packages.size() <= index) { + packages.resize(index + 1, nil); + packages[index] = package; + continue; + } else { + std::swap(package, packages[index]); + if (package != nil) { + if (package.metadata->index_ == index + 1) + ++lost; + goto lost; + } + if (last != index) + continue; + } + } else { + ++lost; + lost: if (last == packages.size()) + packages.push_back(package); + else + packages[last] = package; + ++last; + } + + for (; last != packages.size(); ++last) + if (packages[last] == nil) + break; + } _end + for (size_t next(last + 1); last != packages.size(); ++last, ++next) { + while (true) { + if (next == packages.size()) + goto done; + if (packages[next] != nil) + break; + ++next; + } - /*if (packages.empty()) - packages_ = [[NSArray alloc] init]; - else - packages_ = [[NSArray alloc] initWithObjects:&packages.front() count:packages.size()]; - _trace();*/ + std::swap(packages[last], packages[next]); + } done:; - _profile(reloadDataWithInvocation$radix$8) - [(NSMutableArray *) packages_ radixSortUsingFunction:reinterpret_cast(&PackagePrefixRadix) withContext:reinterpret_cast(8)]; - _end + packages.resize(last); - _profile(reloadDataWithInvocation$radix$4) - [(NSMutableArray *) packages_ radixSortUsingFunction:reinterpret_cast(&PackagePrefixRadix) withContext:reinterpret_cast(4)]; - _end + if (lost > 128) { + NSLog(@"lost = %zu", lost); - _profile(reloadDataWithInvocation$radix$0) - [(NSMutableArray *) packages_ radixSortUsingFunction:reinterpret_cast(&PackagePrefixRadix) withContext:reinterpret_cast(0)]; - _end + _profile(reloadDataWithInvocation$radix$8) + CYRadixSortUsingFunction(packages.data(), packages.size(), reinterpret_cast(&PackagePrefixRadix), reinterpret_cast(8)); + _end + + _profile(reloadDataWithInvocation$radix$4) + CYRadixSortUsingFunction(packages.data(), packages.size(), reinterpret_cast(&PackagePrefixRadix), reinterpret_cast(4)); + _end + + _profile(reloadDataWithInvocation$radix$0) + CYRadixSortUsingFunction(packages.data(), packages.size(), reinterpret_cast(&PackagePrefixRadix), reinterpret_cast(0)); + _end + } _profile(reloadDataWithInvocation$insertion) - CFArrayInsertionSortValues(packages_, CFRangeMake(0, CFArrayGetCount(packages_)), reinterpret_cast(&PackageNameCompare), NULL); + CYArrayInsertionSortValues(packages.data(), packages.size(), &PackageNameCompare, NULL); _end + packages_ = [[[NSArray alloc] initWithObjects:packages.data() count:packages.size()] autorelease]; + /*_profile(reloadDataWithInvocation$CFQSortArray) CFQSortArray(&packages.front(), packages.size(), sizeof(packages.front()), reinterpret_cast(&PackageNameCompare_), NULL); _end*/ @@ -3970,11 +3881,12 @@ class CydiaLogCleaner : [packages_ sortUsingFunction:reinterpret_cast(&PackageNameCompare) context:NULL]; _end*/ - - size_t count(CFArrayGetCount(packages_)); - MetaFile_->active_ = count; - for (size_t index(0); index != count; ++index) - [(Package *) CFArrayGetValueAtIndex(packages_, index) setIndex:index]; + MetaFile_->active_ = packages.size(); + for (size_t index(0), count(packages.size()); index != count; ++index) { + auto package(packages[index]); + [package setIndex:index]; + [package release]; + } } } } @@ -3991,9 +3903,9 @@ class CydiaLogCleaner : } } - (void) configure { - NSString *dpkg = [NSString stringWithFormat:@"dpkg --configure -a --status-fd %u", statusfd_]; + NSString *dpkg = [NSString stringWithFormat:@"/usr/libexec/cydo --configure -a --status-fd %u", statusfd_]; _trace(); - _root(system([dpkg UTF8String])); + system([dpkg UTF8String]); _trace(); } @@ -4035,7 +3947,7 @@ class CydiaLogCleaner : return false; pkgSourceList list; - if ([self popErrorWithTitle:title forOperation:list.ReadMainList()]) + if ([self popErrorWithTitle:title forReadList:list]) return false; manager_ = (_system->CreatePM(cache_)); @@ -4053,7 +3965,7 @@ class CydiaLogCleaner : NSMutableArray *before = [NSMutableArray arrayWithCapacity:16]; { pkgSourceList list; - if ([self popErrorWithTitle:title forOperation:list.ReadMainList()]) + if ([self popErrorWithTitle:title forReadList:list]) return; for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source) [before addObject:[NSString stringWithUTF8String:(*source)->GetURI().c_str()]]; @@ -4094,8 +4006,25 @@ class CydiaLogCleaner : if (substrate) RestartSubstrate_ = true; - _system->UnLock(); - pkgPackageManager::OrderResult result(_root(manager_->DoInstall(statusfd_))); + if (![delock_ isEqual:GetStatusDate()]) { + [delegate_ addProgressEventOnMainThread:[CydiaProgressEvent eventWithMessage:UCLocalize("DPKG_LOCKED") ofType:kCydiaProgressEventTypeError] forTask:title]; + return; + } + + delock_ = nil; + + pkgPackageManager::OrderResult result(manager_->DoInstall(statusfd_)); + + NSString *oextended(@"/var/lib/apt/extended_states"); + NSString *nextended(Cache("extended_states")); + + struct stat info; + if (stat([nextended UTF8String], &info) != -1 && (info.st_mode & S_IFMT) == S_IFREG) + system([[NSString stringWithFormat:@"/usr/libexec/cydia/cydo /bin/cp --remove-destination %@ %@", ShellEscape(nextended), ShellEscape(oextended)] UTF8String]); + + unlink([nextended UTF8String]); + symlink([oextended UTF8String], [nextended UTF8String]); + if ([self popErrorWithTitle:title]) return; @@ -4111,7 +4040,7 @@ class CydiaLogCleaner : NSMutableArray *after = [NSMutableArray arrayWithCapacity:16]; { pkgSourceList list; - if ([self popErrorWithTitle:title forOperation:list.ReadMainList()]) + if ([self popErrorWithTitle:title forReadList:list]) return; for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source) [after addObject:[NSString stringWithUTF8String:(*source)->GetURI().c_str()]]; @@ -4121,6 +4050,10 @@ class CydiaLogCleaner : [self update]; } +- (bool) delocked { + return ![delock_ isEqual:GetStatusDate()]; +} + - (bool) upgrade { NSString *title(UCLocalize("UPGRADE")); if ([self popErrorWithTitle:title forOperation:pkgDistUpgrade(cache_)]) @@ -4136,7 +4069,7 @@ class CydiaLogCleaner : NSString *title(UCLocalize("REFRESHING_DATA")); pkgSourceList list; - if ([self popErrorWithTitle:title forOperation:list.ReadMainList()]) + if ([self popErrorWithTitle:title forReadList:list]) return; FileFd lock; @@ -4151,8 +4084,10 @@ class CydiaLogCleaner : _error->Discard(); else { [self popErrorWithTitle:title forOperation:success]; - [Metadata_ setObject:[NSDate date] forKey:@"LastUpdate"]; - Changed_ = true; + + [[NSDictionary dictionaryWithObjectsAndKeys: + [NSDate date], @"LastUpdate", + nil] writeToFile:@ CacheState_ atomically:YES]; } [delegate_ performSelectorOnMainThread:@selector(releaseNetworkActivityIndicator) withObject:nil waitUntilDone:YES]; @@ -4220,76 +4155,16 @@ class CydiaLogCleaner : @end /* }}} */ -static _H Diversions_; - -@interface Diversion : NSObject { - Pcre pattern_; - _H key_; - _H format_; -} - -@end - -@implementation Diversion - -- (id) initWithFrom:(NSString *)from to:(NSString *)to { - if ((self = [super init]) != nil) { - pattern_ = [from UTF8String]; - key_ = from; - format_ = to; - } return self; -} - -- (NSString *) divert:(NSString *)url { - return !pattern_(url) ? nil : pattern_->*format_; -} - -+ (NSURL *) divertURL:(NSURL *)url { - divert: - NSString *href([url absoluteString]); - - for (Diversion *diversion in (id) Diversions_) - if (NSString *diverted = [diversion divert:href]) { -#if !ForRelease - NSLog(@"div: %@", diverted); -#endif - url = [NSURL URLWithString:diverted]; - goto divert; - } - - return url; -} - -- (NSString *) key { - return key_; -} - -- (NSUInteger) hash { - return [key_ hash]; -} - -- (BOOL) isEqual:(Diversion *)object { - return self == object || [self class] == [object class] && [key_ isEqual:[object key]]; -} - -@end - -@interface CydiaObject : NSObject { - _H indirect_; +@interface CydiaObject : CyteObject { _transient id delegate_; } -- (id) initWithDelegate:(IndirectDelegate *)indirect; - @end -@class CydiaObject; - @interface CydiaWebViewController : CyteWebViewController { _H cydia_; } -+ (void) addDiversion:(Diversion *)diversion; + (NSURLRequest *) requestWithHeaders:(NSURLRequest *)request; + (void) didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame withCydia:(CydiaObject *)cydia; - (void) setDelegate:(id)delegate; @@ -4299,74 +4174,54 @@ static _H Diversions_; /* Web Scripting {{{ */ @implementation CydiaObject -- (id) initWithDelegate:(IndirectDelegate *)indirect { - if ((self = [super init]) != nil) { - indirect_ = (CyteWebViewController *) indirect; - } return self; -} - - (void) setDelegate:(id)delegate { delegate_ = delegate; } -+ (NSArray *) _attributeKeys { - return [NSArray arrayWithObjects: - @"bbsnum", - @"build", - @"coreFoundationVersionNumber", +- (NSArray *) attributeKeys { + return [[NSArray arrayWithObjects: + @"cells", @"device", - @"ecid", - @"firmware", - @"hostname", - @"idiom", @"mcc", @"mnc", - @"model", @"operator", @"role", - @"serial", - @"token", @"version", - nil]; -} - -- (NSArray *) attributeKeys { - return [[self class] _attributeKeys]; -} - -+ (BOOL) isKeyExcludedFromWebScript:(const char *)name { - return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name]; + nil] arrayByAddingObjectsFromArray:[super attributeKeys]]; } - (NSString *) version { return Cydia_; } -- (NSString *) build { - return System_; -} - -- (NSString *) coreFoundationVersionNumber { - return [NSString stringWithFormat:@"%.2f", kCFCoreFoundationVersionNumber]; -} - - (NSString *) device { return UniqueIdentifier(); } -- (NSString *) firmware { - return [[UIDevice currentDevice] systemVersion]; -} +- (NSArray *) cells { + auto *$_CTServerConnectionCreate(reinterpret_cast(dlsym(RTLD_DEFAULT, "_CTServerConnectionCreate"))); + if ($_CTServerConnectionCreate == NULL) + return nil; -- (NSString *) hostname { - return [[UIDevice currentDevice] name]; -} + struct CTResult { int flag; int error; }; + auto *$_CTServerConnectionCellMonitorCopyCellInfo(reinterpret_cast(dlsym(RTLD_DEFAULT, "_CTServerConnectionCellMonitorCopyCellInfo"))); + if ($_CTServerConnectionCellMonitorCopyCellInfo == NULL) + return nil; -- (NSString *) idiom { - return (id) Idiom_ ?: [NSNull null]; -} + _H connection($_CTServerConnectionCreate(NULL, NULL, NULL), true); + if (connection == nil) + return nil; -- (NSString *) mcc { + int count(0); + CFArrayRef cells(NULL); + auto result($_CTServerConnectionCellMonitorCopyCellInfo(connection, &count, &cells)); + if (result.flag != 0) + return nil; + + return [(NSArray *) cells autorelease]; +} + +- (NSString *) mcc { if (CFStringRef (*$CTSIMSupportCopyMobileSubscriberCountryCode)(CFAllocatorRef) = reinterpret_cast(dlsym(RTLD_DEFAULT, "CTSIMSupportCopyMobileSubscriberCountryCode"))) return [(NSString *) (*$CTSIMSupportCopyMobileSubscriberCountryCode)(kCFAllocatorDefault) autorelease]; return nil; @@ -4384,68 +4239,32 @@ static _H Diversions_; return nil; } -- (NSString *) bbsnum { - return (id) BBSNum_ ?: [NSNull null]; -} - -- (NSString *) ecid { - return (id) ChipID_ ?: [NSNull null]; -} - -- (NSString *) serial { - return SerialNumber_; -} - - (NSString *) role { return (id) [NSNull null]; } -- (NSString *) model { - return [NSString stringWithUTF8String:Machine_]; -} - -- (NSString *) token { - return (id) Token_ ?: [NSNull null]; -} - + (NSString *) webScriptNameForSelector:(SEL)selector { if (false); else if (selector == @selector(addBridgedHost:)) return @"addBridgedHost"; else if (selector == @selector(addInsecureHost:)) return @"addInsecureHost"; - else if (selector == @selector(addInternalRedirect::)) - return @"addInternalRedirect"; - else if (selector == @selector(addPipelinedHost:scheme:)) - return @"addPipelinedHost"; else if (selector == @selector(addSource:::)) return @"addSource"; - else if (selector == @selector(addTokenHost:)) - return @"addTokenHost"; else if (selector == @selector(addTrivialSource:)) return @"addTrivialSource"; - else if (selector == @selector(close)) - return @"close"; else if (selector == @selector(du:)) return @"du"; - else if (selector == @selector(stringWithFormat:arguments:)) - return @"format"; else if (selector == @selector(getAllSources)) return @"getAllSources"; else if (selector == @selector(getApplicationInfo:value:)) return @"getApplicationInfoValue"; - else if (selector == @selector(getKernelNumber:)) - return @"getKernelNumber"; - else if (selector == @selector(getKernelString:)) - return @"getKernelString"; + else if (selector == @selector(getDisplayIdentifiers)) + return @"getDisplayIdentifiers"; + else if (selector == @selector(getLocalizedNameForDisplayIdentifier:)) + return @"getLocalizedNameForDisplayIdentifier"; else if (selector == @selector(getInstalledPackages)) return @"getInstalledPackages"; - else if (selector == @selector(getIORegistryEntry::)) - return @"getIORegistryEntry"; - else if (selector == @selector(getLocaleIdentifier)) - return @"getLocaleIdentifier"; - else if (selector == @selector(getPreferredLanguages)) - return @"getPreferredLanguages"; else if (selector == @selector(getPackageById:)) return @"getPackageById"; else if (selector == @selector(getMetadataKeys)) @@ -4456,18 +4275,8 @@ static _H Diversions_; return @"getSessionValue"; else if (selector == @selector(installPackages:)) return @"installPackages"; - else if (selector == @selector(isReachable:)) - return @"isReachable"; - 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(registerFrame:)) - return @"registerFrame"; - else if (selector == @selector(removeButton)) - return @"removeButton"; else if (selector == @selector(saveConfig)) return @"saveConfig"; else if (selector == @selector(setMetadataValue::)) @@ -4476,42 +4285,8 @@ static _H Diversions_; 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:)) - return @"setButtonTitle"; - else if (selector == @selector(setHidesBackButton:)) - return @"setHidesBackButton"; - else if (selector == @selector(setHidesNavigationBar:)) - return @"setHidesNavigationBar"; - else if (selector == @selector(setNavigationBarStyle:)) - return @"setNavigationBarStyle"; - 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(setScrollAlwaysBounceVertical:)) - return @"setScrollAlwaysBounceVertical"; - else if (selector == @selector(setScrollIndicatorStyle:)) - return @"setScrollIndicatorStyle"; else if (selector == @selector(setToken:)) return @"setToken"; - else if (selector == @selector(setViewportWidth:)) - return @"setViewportWidth"; - else if (selector == @selector(statfs:)) - return @"statfs"; - else if (selector == @selector(supports:)) - return @"supports"; - else if (selector == @selector(unload)) - return @"unload"; else return nil; } @@ -4520,26 +4295,6 @@ static _H Diversions_; return [self webScriptNameForSelector:selector] == nil; } -- (BOOL) supports:(NSString *)feature { - return [feature isEqualToString:@"window.open"]; -} - -- (void) unload { - [delegate_ performSelectorOnMainThread:@selector(unloadData) withObject:nil waitUntilDone:NO]; -} - -- (void) setScrollAlwaysBounceVertical:(NSNumber *)value { - [indirect_ performSelectorOnMainThread:@selector(setScrollAlwaysBounceVerticalNumber:) withObject:value waitUntilDone:NO]; -} - -- (void) setScrollIndicatorStyle:(NSString *)style { - [indirect_ performSelectorOnMainThread:@selector(setScrollIndicatorStyleWithName:) withObject:style waitUntilDone:NO]; -} - -- (void) addInternalRedirect:(NSString *)from :(NSString *)to { - [CydiaWebViewController performSelectorOnMainThread:@selector(addDiversion:) withObject:[[[Diversion alloc] initWithFrom:from to:to] autorelease] waitUntilDone:NO]; -} - - (NSDictionary *) getApplicationInfo:(NSString *)display value:(NSString *)key { char path[1024]; if (SBBundlePathForDisplayIdentifier(SBSSpringBoardServerPort(), [display UTF8String], path) != 0) @@ -4550,6 +4305,14 @@ static _H Diversions_; return [info objectForKey:key]; } +- (NSArray *) getDisplayIdentifiers { + return SBSCopyApplicationDisplayIdentifiers(false, false); +} + +- (NSString *) getLocalizedNameForDisplayIdentifier:(NSString *)identifier { + return [SBSCopyLocalizedApplicationNameForDisplayIdentifier(identifier) autorelease] ?: (id) [NSNull null]; +} + - (NSNumber *) getKernelNumber:(NSString *)name { const char *string([name UTF8String]); @@ -4567,43 +4330,11 @@ static _H Diversions_; return [NSNumber numberWithInt:value]; } -- (NSString *) getKernelString:(NSString *)name { - const char *string([name UTF8String]); - - size_t size; - if (sysctlbyname(string, NULL, &size, NULL, 0) == -1) - return (id) [NSNull null]; - - char value[size + 1]; - if (sysctlbyname(string, value, &size, NULL, 0) == -1) - return (id) [NSNull null]; - - // XXX: just in case you request something ludicrous - value[size] = '\0'; - - return [NSString stringWithCString:value]; -} - -- (NSObject *) getIORegistryEntry:(NSString *)path :(NSString *)entry { - NSObject *value(CYIOGetValue([path UTF8String], entry)); - - if (value != nil) - if ([value isKindOfClass:[NSData class]]) - value = CYHex((NSData *) value); - - return value; -} - - (NSArray *) getMetadataKeys { @synchronized (Values_) { return [Values_ allKeys]; } } -- (void) registerFrame:(DOMHTMLIFrameElement *)iframe { - WebFrame *frame([iframe contentFrame]); - [indirect_ registerFrame:frame]; -} - - (id) getMetadataValue:(NSString *)key { @synchronized (Values_) { return [Values_ objectForKey:key]; @@ -4615,8 +4346,6 @@ static _H Diversions_; [Values_ removeObjectForKey:key]; else [Values_ setObject:value forKey:key]; - - [delegate_ performSelectorOnMainThread:@selector(updateValues) withObject:nil waitUntilDone:YES]; } } - (id) getSessionValue:(NSString *)key { @@ -4633,34 +4362,15 @@ static _H Diversions_; } } - (void) addBridgedHost:(NSString *)host { -@synchronized (HostConfig_) { +@synchronized (BridgedHosts_) { [BridgedHosts_ addObject:host]; } } - (void) addInsecureHost:(NSString *)host { -@synchronized (HostConfig_) { +@synchronized (InsecureHosts_) { [InsecureHosts_ addObject:host]; } } -- (void) addTokenHost:(NSString *)host { -@synchronized (HostConfig_) { - [TokenHosts_ addObject:host]; -} } - -- (void) addPipelinedHost:(NSString *)host scheme:(NSString *)scheme { -@synchronized (HostConfig_) { - if (scheme != (id) [WebUndefined undefined]) - host = [NSString stringWithFormat:@"%@:%@", [scheme lowercaseString], host]; - - [PipelinedHosts_ addObject:host]; -} } - -- (void) popViewController:(NSNumber *)value { - if (value == (id) [WebUndefined undefined]) - value = [NSNumber numberWithBool:YES]; - [indirect_ performSelectorOnMainThread:@selector(popViewControllerWithNumber:) withObject:value waitUntilDone:NO]; -} - - (void) addSource:(NSString *)href :(NSString *)distribution :(WebScriptObject *)sections { NSMutableArray *array([NSMutableArray arrayWithCapacity:[sections count]]); @@ -4675,8 +4385,12 @@ static _H Diversions_; nil] waitUntilDone:NO]; } -- (void) addTrivialSource:(NSString *)href { +- (BOOL) addTrivialSource:(NSString *)href { + href = VerifySource(href); + if (href == nil) + return NO; [delegate_ performSelectorOnMainThread:@selector(addTrivialSource:) withObject:href waitUntilDone:NO]; + return YES; } - (void) refreshSources { @@ -4710,171 +4424,50 @@ static _H Diversions_; 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; - - if (path == nil || statfs([path UTF8String], &stat) == -1) - return nil; - - return [NSArray arrayWithObjects: - [NSNumber numberWithUnsignedLong:stat.f_bsize], - [NSNumber numberWithUnsignedLong:stat.f_blocks], - [NSNumber numberWithUnsignedLong:stat.f_bfree], - nil]; -} - - (NSNumber *) du:(NSString *)path { NSNumber *value(nil); - int fds[2]; - _assert(pipe(fds) != -1); - - pid_t pid(ExecFork()); - if (pid == 0) { - _assert(dup2(fds[1], 1) != -1); - _assert(close(fds[0]) != -1); - _assert(close(fds[1]) != -1); - /* XXX: this should probably not use du */ - _root(execl("/usr/libexec/cydia/du", "du", "-s", [path UTF8String], NULL)); - exit(1); - } else { - _assert(close(fds[1]) != -1); - - if (FILE *du = fdopen(fds[0], "r")) { - char line[1024]; - while (fgets(line, sizeof(line), du) != NULL) { - size_t length(strlen(line)); - while (length != 0 && line[length - 1] == '\n') - line[--length] = '\0'; - if (char *tab = strchr(line, '\t')) { - *tab = '\0'; - value = [NSNumber numberWithUnsignedLong:strtoul(line, NULL, 0)]; - } + FILE *du(popen([[NSString stringWithFormat:@"/usr/libexec/cydia/cydo /usr/libexec/cydia/du -ks %@", ShellEscape(path)] UTF8String], "r")); + if (du != NULL) { + char line[1024]; + while (fgets(line, sizeof(line), du) != NULL) { + size_t length(strlen(line)); + while (length != 0 && line[length - 1] == '\n') + line[--length] = '\0'; + if (char *tab = strchr(line, '\t')) { + *tab = '\0'; + value = [NSNumber numberWithUnsignedLong:strtoul(line, NULL, 0)]; } - - fclose(du); - } else - _assert(close(fds[0]) != -1); - } ReapZombie(pid); + } + pclose(du); + } return value; } -- (void) close { - [indirect_ performSelectorOnMainThread:@selector(close) withObject:nil waitUntilDone:NO]; -} - -- (NSNumber *) isReachable:(NSString *)name { - return [NSNumber numberWithBool:IsReachable([name UTF8String])]; -} - - (void) installPackages:(NSArray *)packages { [delegate_ performSelectorOnMainThread:@selector(installPackages:) withObject:packages waitUntilDone:NO]; } - (NSString *) substitutePackageNames:(NSString *)message { + auto database([Database sharedInstance]); + + // XXX: this check is less racy than you'd expect, but this entire concept is a little awkward + if (![database hasPackages]) + return message; + NSMutableArray *words([[[message componentsSeparatedByString:@" "] mutableCopy] autorelease]); for (size_t i(0), e([words count]); i != e; ++i) { NSString *word([words objectAtIndex:i]); - if (Package *package = [[Database sharedInstance] packageWithName:word]) + if (Package *package = [database packageWithName:word]) [words replaceObjectAtIndex:i withObject:[package name]]; } return [words componentsJoinedByString:@" "]; } -- (void) removeButton { - [indirect_ removeButton]; -} - -- (void) setButtonImage:(NSString *)button withStyle:(NSString *)style toFunction:(id)function { - [indirect_ setButtonImage:button withStyle:style toFunction:function]; -} - -- (void) setButtonTitle:(NSString *)button withStyle:(NSString *)style toFunction:(id)function { - [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]; -} - -- (void) setHidesNavigationBar:(NSString *)value { - [indirect_ performSelectorOnMainThread:@selector(setHidesNavigationBarByNumber:) withObject:value waitUntilDone:NO]; -} - -- (void) setNavigationBarStyle:(NSString *)value { - [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; - - if (token == nil) - [Metadata_ removeObjectForKey:@"Token"]; - else - [Metadata_ setObject:Token_ forKey:@"Token"]; - - Changed_ = true; -} - - (void) setToken:(NSString *)token { - [self performSelectorOnMainThread:@selector(_setToken:) withObject:token waitUntilDone:NO]; -} - -- (void) scrollToBottom:(NSNumber *)animated { - [indirect_ performSelectorOnMainThread:@selector(scrollToBottomAnimated:) withObject:animated waitUntilDone:NO]; -} - -- (void) setViewportWidth:(float)width { - [indirect_ setViewportWidthOnMainThread:width]; -} - -- (NSString *) stringWithFormat:(NSString *)format arguments:(WebScriptObject *)arguments { - //NSLog(@"SWF:\"%@\" A:%@", format, [arguments description]); - unsigned count([arguments count]); - id values[count]; - for (unsigned i(0); i != count; ++i) - values[i] = [arguments objectAtIndex:i]; - return [[[NSString alloc] initWithFormat:format arguments:reinterpret_cast(values)] autorelease]; -} - -- (NSString *) localizedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)table { - if (reinterpret_cast(value) == [WebUndefined undefined]) - value = nil; - if (reinterpret_cast(table) == [WebUndefined undefined]) - table = nil; - return [[NSBundle mainBundle] localizedStringForKey:key value:value table:table]; + // XXX: the website expects this :/ } @end @@ -4889,7 +4482,7 @@ static _H Diversions_; if ([[[self scheme] lowercaseString] isEqualToString:@"https"]) return true; - @synchronized (HostConfig_) { + @synchronized (InsecureHosts_) { if ([InsecureHosts_ containsObject:[self host]]) return true; } @@ -4903,17 +4496,10 @@ static _H Diversions_; @implementation CydiaWebViewController - (NSURL *) navigationURL { - return request_ == nil ? nil : [NSURL URLWithString:[NSString stringWithFormat:@"cydia://url/%@", [[request_ URL] absoluteString]]]; -} - -+ (void) _initialize { - [super _initialize]; - - Diversions_ = [NSMutableSet setWithCapacity:0]; -} - -+ (void) addDiversion:(Diversion *)diversion { - [Diversions_ addObject:diversion]; + if (NSURLRequest *request = self.request) + return [NSURL URLWithString:[NSString stringWithFormat:@"cydia://url/%@", [[request URL] absoluteString]]]; + else + return nil; } - (void) webView:(WebView *)view didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame { @@ -4929,7 +4515,7 @@ static _H Diversions_; bool bridged(false); - @synchronized (HostConfig_) { + @synchronized (BridgedHosts_) { if ([scheme isEqualToString:@"file"]) bridged = true; else if ([scheme isEqualToString:@"https"]) @@ -4948,10 +4534,6 @@ static _H Diversions_; [controller addAttachmentData:[NSData dataWithContentsOfFile:@"/tmp/dpkgl.log"] mimeType:@"text/plain" fileName:@"dpkgl.log"]; } -- (NSURL *) URLWithURL:(NSURL *)url { - return [Diversion divertURL:url]; -} - - (NSURLRequest *) webView:(WebView *)view resource:(id)resource willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response fromDataSource:(WebDataSource *)source { return [CydiaWebViewController requestWithHeaders:[super webView:view resource:resource willSendRequest:request redirectResponse:response fromDataSource:source]]; } @@ -4985,23 +4567,12 @@ static _H Diversions_; if (Machine_ != NULL && [copy valueForHTTPHeaderField:@"X-Machine"] == nil) [copy setValue:[NSString stringWithUTF8String:Machine_] forHTTPHeaderField:@"X-Machine"]; - bool bridged; - bool token; - - @synchronized (HostConfig_) { + bool bridged; @synchronized (BridgedHosts_) { bridged = [BridgedHosts_ containsObject:host]; - token = [TokenHosts_ containsObject:host]; } - if ([url isCydiaSecure]) { - if (bridged) { - if (UniqueID_ != nil && [copy valueForHTTPHeaderField:@"X-Cydia-Id"] == nil) - [copy setValue:UniqueID_ forHTTPHeaderField:@"X-Cydia-Id"]; - } else if (token) { - if (Token_ != nil && [copy valueForHTTPHeaderField:@"X-Cydia-Token"] == nil) - [copy setValue:Token_ forHTTPHeaderField:@"X-Cydia-Token"]; - } - } + if ([url isCydiaSecure] && bridged && UniqueID_ != nil && [copy valueForHTTPHeaderField:@"X-Cydia-Id"] == nil) + [copy setValue:UniqueID_ forHTTPHeaderField:@"X-Cydia-Id"]; return copy; } @@ -5011,13 +4582,9 @@ static _H Diversions_; [cydia_ setDelegate:delegate]; } -- (NSString *) applicationNameForUserAgent { - return UserAgent_; -} - - (id) init { if ((self = [super initWithWidth:0 ofClass:[CydiaWebViewController class]]) != nil) { - cydia_ = [[[CydiaObject alloc] initWithDelegate:indirect_] autorelease]; + cydia_ = [[[CydiaObject alloc] initWithDelegate:self.indirect] autorelease]; } return self; } @@ -5041,42 +4608,6 @@ static _H Diversions_; @end /* }}} */ -// CydiaScript {{{ -@interface NSObject (CydiaScript) -- (id) Cydia$webScriptObjectInContext:(WebScriptObject *)context; -@end - -@implementation NSObject (CydiaScript) - -- (id) Cydia$webScriptObjectInContext:(WebScriptObject *)context { - return self; -} - -@end - -@implementation NSArray (CydiaScript) - -- (id) Cydia$webScriptObjectInContext:(WebScriptObject *)context { - WebScriptObject *object([context evaluateWebScript:@"[]"]); - for (size_t i(0), e([self count]); i != e; ++i) - [object setWebScriptValueAtIndex:i value:[[self objectAtIndex:i] Cydia$webScriptObjectInContext:context]]; - return object; -} - -@end - -@implementation NSDictionary (CydiaScript) - -- (id) Cydia$webScriptObjectInContext:(WebScriptObject *)context { - WebScriptObject *object([context evaluateWebScript:@"({})"]); - for (id i in self) - [object setValue:[[self objectForKey:i] Cydia$webScriptObjectInContext:context] forKey:i]; - return object; -} - -@end -// }}} - /* Confirmation Controller {{{ */ bool DepSubstrate(const pkgCache::VerIterator &iterator) { if (!iterator.end()) @@ -5120,7 +4651,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (void) complete { if (substrate_) RestartSubstrate_ = true; - [delegate_ confirmWithNavigationController:[self navigationController]]; + [self.delegate confirmWithNavigationController:[self navigationController]]; } - (void) alertView:(UIAlertView *)alert clickedButtonAtIndex:(NSInteger)button { @@ -5143,7 +4674,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) _doContinue { - [delegate_ cancelAndClear:NO]; + [self.delegate cancelAndClear:NO]; [self dismissModalViewControllerAnimated:YES]; } @@ -5181,8 +4712,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { issues_ = [NSMutableArray arrayWithCapacity:4]; - UpgradeCydia_ = false; - for (Package *package in packages) { pkgCache::PkgIterator iterator([package iterator]); NSString *name([package id]); @@ -5257,7 +4786,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { pkgDepCache::StateCache &state(cache[iterator]); - static Pcre special_r("^(firmware$|gsc\\.|cy\\+)"); + static RegEx special_r("(firmware|gsc\\..*|cy\\+.*)"); if (state.NewInstall()) [installs addObject:name]; @@ -5294,9 +4823,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [removes addObject:name]; } - if ([name isEqualToString:@"cydia"]) - UpgradeCydia_ = true; - substrate_ |= DepSubstrate(policy->GetCandidateVer(iterator)); substrate_ |= DepSubstrate(iterator.CurrentVer()); } @@ -5371,7 +4897,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { #endif - (void) cancelButtonClicked { - [delegate_ cancelAndClear:YES]; + [self.delegate cancelAndClear:YES]; [self dismissModalViewControllerAnimated:YES]; } @@ -5555,7 +5081,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (id) initWithDatabase:(Database *)database delegate:(id)delegate { if ((self = [super init]) != nil) { database_ = database; - delegate_ = delegate; + self.delegate = delegate; [database_ setProgressDelegate:self]; @@ -5564,7 +5090,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [self setURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/#!/progress/", UI_]]]; - [scroller_ setBackgroundColor:[UIColor blackColor]]; + [self setPageColor:[UIColor blackColor]]; [[self navigationItem] setHidesBackButton:YES]; @@ -5586,51 +5112,23 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [super viewWillAppear:animated]; } -- (void) reloadSpringBoard { - if (kCFCoreFoundationVersionNumber > 700) { // XXX: iOS 6.x - system("/bin/launchctl stop com.apple.backboardd"); - sleep(15); - system("/usr/bin/killall backboardd SpringBoard sbreload"); - return; - } - - pid_t pid(ExecFork()); - if (pid == 0) { - if (setsid() == -1) - perror("setsid"); - - pid_t pid(ExecFork()); - if (pid == 0) { - _root(execl("/usr/bin/sbreload", "sbreload", NULL)); - perror("sbreload"); - - exit(0); - } ReapZombie(pid); - - exit(0); - } ReapZombie(pid); - - sleep(15); - system("/usr/bin/killall backboardd SpringBoard sbreload"); -} - - (void) close { UpdateExternalStatus(0); if (Finish_ > 1) - [delegate_ saveState]; + [self.delegate saveState]; switch (Finish_) { case 0: - [delegate_ returnToCydia]; + [self.delegate returnToCydia]; break; case 1: - [delegate_ terminateWithSuccess]; - /*if ([delegate_ respondsToSelector:@selector(suspendWithAnimation:)]) - [delegate_ suspendWithAnimation:YES]; + [self.delegate terminateWithSuccess]; + /*if ([self.delegate respondsToSelector:@selector(suspendWithAnimation:)]) + [self.delegate suspendWithAnimation:YES]; else - [delegate_ suspend];*/ + [self.delegate suspend];*/ break; case 2: @@ -5642,9 +5140,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { goto reload; reload: { - UIProgressHUD *hud([delegate_ addProgressHUD]); + UIProgressHUD *hud([self.delegate addProgressHUD]); [hud setText:UCLocalize("LOADING")]; - [self performSelector:@selector(reloadSpringBoard) withObject:nil afterDelay:0.5]; + [self.delegate performSelector:@selector(reloadSpringBoard) withObject:nil afterDelay:0.5]; return; } @@ -5842,12 +5340,12 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { UIView *content([self contentView]); CGRect bounds([content bounds]); - content_ = [[[CyteTableViewCellContentView alloc] initWithFrame:bounds] autorelease]; - [content_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; - [content addSubview:content_]; + self.content = [[[CyteTableViewCellContentView alloc] initWithFrame:bounds] autorelease]; + [self.content setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; + [content addSubview:self.content]; - [content_ setDelegate:self]; - [content_ setOpaque:YES]; + [self.content setDelegate:self]; + [self.content setOpaque:YES]; } return self; } @@ -5866,7 +5364,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { placard_ = nil; if (package == nil) - [content_ setBackgroundColor:[UIColor whiteColor]]; + [self.content setBackgroundColor:[UIColor whiteColor]]; else { [package parse]; @@ -5926,18 +5424,18 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { placard = nil; } - [content_ setBackgroundColor:color]; + [self.content setBackgroundColor:color]; if (placard != nil) placard_ = [UIImage imageAtPath:[NSString stringWithFormat:@"%@/%@.png", App_, placard]]; } [self setNeedsDisplay]; - [content_ setNeedsDisplay]; + [self.content setNeedsDisplay]; } - (void) drawSummaryContentRect:(CGRect)rect { - bool highlighted(highlighted_); + bool highlighted(self.highlighted); float width([self bounds].size.width); if (icon_ != nil) { @@ -5980,7 +5478,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) drawNormalContentRect:(CGRect)rect { - bool highlighted(highlighted_); + bool highlighted(self.highlighted); float width([self bounds].size.width); if (icon_ != nil) { @@ -6065,12 +5563,12 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { UIView *content([self contentView]); CGRect bounds([content bounds]); - content_ = [[[CyteTableViewCellContentView alloc] initWithFrame:bounds] autorelease]; - [content_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; - [content addSubview:content_]; - [content_ setBackgroundColor:[UIColor whiteColor]]; + self.content = [[[CyteTableViewCellContentView alloc] initWithFrame:bounds] autorelease]; + [self.content setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; + [content addSubview:self.content]; + [self.content setBackgroundColor:[UIColor whiteColor]]; - [content_ setDelegate:self]; + [self.content setDelegate:self]; } return self; } @@ -6082,7 +5580,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } [metadata setObject:[NSNumber numberWithBool:([switch_ isOn] == NO)] forKey:@"Hidden"]; - Changed_ = true; } - (void) setSection:(Section *)section editing:(BOOL)editing { @@ -6116,7 +5613,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [self setAccessoryType:editing ? UITableViewCellAccessoryNone : UITableViewCellAccessoryDisclosureIndicator]; [self setSelectionStyle:editing ? UITableViewCellSelectionStyleNone : UITableViewCellSelectionStyleBlue]; - [content_ setNeedsDisplay]; + [self.content setNeedsDisplay]; } - (void) setFrame:(CGRect)frame { @@ -6131,7 +5628,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (void) drawContentRect:(CGRect)rect { - bool highlighted(highlighted_ && !editing_); + bool highlighted(self.highlighted && !editing_); [icon_ drawInRect:CGRectMake(7, 7, 32, 32)]; @@ -6259,7 +5756,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { NSString *directory = [stack lastObject]; [stack addObject:[file stringByAppendingString:@"/"]]; [files_ replaceObjectAtIndex:i withObject:[NSString stringWithFormat:@"%*s%@", - ([stack count] - 2) * 3, "", + int(([stack count] - 2) * 3), "", [file substringFromIndex:[directory length]] ]]; } @@ -6286,7 +5783,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { _H name_; bool commercial_; std::vector, _H>> buttons_; + _H sheet_; _H button_; + _H versions_; } - (id) initWithDatabase:(Database *)database forPackage:(NSString *)name withReferrer:(NSString *)referrer; @@ -6299,22 +5798,44 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { return [NSURL URLWithString:[NSString stringWithFormat:@"cydia://package/%@", (id) name_]]; } +- (void) _clickButtonWithPackage:(Package *)package { + [self.delegate installPackage:package]; +} + - (void) _clickButtonWithName:(NSString *)name { if ([name isEqualToString:@"CLEAR"]) - [delegate_ clearPackage:package_]; - else if ([name isEqualToString:@"INSTALL"]) - [delegate_ installPackage:package_]; - else if ([name isEqualToString:@"REINSTALL"]) - [delegate_ installPackage:package_]; + return [self.delegate clearPackage:package_]; else if ([name isEqualToString:@"REMOVE"]) - [delegate_ removePackage:package_]; - else if ([name isEqualToString:@"UPGRADE"]) - [delegate_ installPackage:package_]; + return [self.delegate removePackage:package_]; + else if ([name isEqualToString:@"DOWNGRADE"]) { + sheet_ = [[[UIActionSheet alloc] + initWithTitle:nil + delegate:self + cancelButtonTitle:nil + destructiveButtonTitle:nil + otherButtonTitles:nil + ] autorelease]; + + for (Package *version in (id) versions_) + [sheet_ addButtonWithTitle:[version latest]]; + [sheet_ setContext:@"version"]; + + [self.delegate showActionSheet:sheet_ fromItem:[[self navigationItem] rightBarButtonItem]]; + return; + } + + else if ([name isEqualToString:@"INSTALL"]); + else if ([name isEqualToString:@"REINSTALL"]); + else if ([name isEqualToString:@"UPGRADE"]); else _assert(false); + + [self.delegate installPackage:package_]; } - (void) actionSheet:(UIActionSheet *)sheet clickedButtonAtIndex:(NSInteger)button { NSString *context([sheet context]); + if (sheet_ == sheet) + sheet_ = nil; if ([context isEqualToString:@"modify"]) { if (button != [sheet cancelButtonIndex]) { @@ -6324,6 +5845,16 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [self _clickButtonWithName:buttons_[button].first]; } + [sheet dismissWithClickedButtonIndex:button animated:YES]; + } else if ([context isEqualToString:@"version"]) { + if (button != [sheet cancelButtonIndex]) { + Package *version([versions_ objectAtIndex:button]); + if (IsWildcat_) + [self performSelector:@selector(_clickButtonWithPackage:) withObject:version afterDelay:0]; + else + [self _clickButtonWithPackage:version]; + } + [sheet dismissWithClickedButtonIndex:button animated:YES]; } } @@ -6334,6 +5865,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { #if !AlwaysReload - (void) _customButtonClicked { + if (commercial_ && self.isLoading && [package_ uninstalled]) + return [self reloadURLWithCache:NO]; + size_t count(buttons_.size()); if (count == 0) return; @@ -6345,7 +5879,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { for (const auto &button : buttons_) [buttons addObject:button.second]; - UIActionSheet *sheet = [[[UIActionSheet alloc] + sheet_ = [[[UIActionSheet alloc] initWithTitle:nil delegate:self cancelButtonTitle:nil @@ -6353,23 +5887,14 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { otherButtonTitles:nil ] autorelease]; - for (NSString *button in buttons) [sheet addButtonWithTitle:button]; - if (!IsWildcat_) { - [sheet addButtonWithTitle:UCLocalize("CANCEL")]; - [sheet setCancelButtonIndex:[sheet numberOfButtons] - 1]; - } - [sheet setContext:@"modify"]; + for (NSString *button in buttons) + [sheet_ addButtonWithTitle:button]; + [sheet_ setContext:@"modify"]; - [delegate_ showActionSheet:sheet fromItem:[[self navigationItem] rightBarButtonItem]]; + [self.delegate showActionSheet:sheet_ fromItem:[[self navigationItem] rightBarButtonItem]]; } } -- (void) reloadButtonClicked { - if (commercial_ && function_ == nil && [package_ uninstalled]) - return; - [self customButtonClicked]; -} - - (void) applyLoadingTitle { // Don't show "Loading" as the title. Ever. } @@ -6394,7 +5919,11 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { - (void) reloadData { [super reloadData]; + [sheet_ dismissWithClickedButtonIndex:[sheet_ cancelButtonIndex] animated:YES]; + sheet_ = nil; + package_ = [database_ packageWithName:name_]; + versions_ = [package_ downgrades]; buttons_.clear(); @@ -6414,6 +5943,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { buttons_.push_back(std::make_pair(@"REINSTALL", UCLocalize("REINSTALL"))); if (![package_ uninstalled]) buttons_.push_back(std::make_pair(@"REMOVE", UCLocalize("REMOVE"))); + if ([versions_ count] != 0) + buttons_.push_back(std::make_pair(@"DOWNGRADE", UCLocalize("DOWNGRADE"))); } NSString *title; @@ -6439,7 +5970,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { /* }}} */ /* Package List Controller {{{ */ -@interface PackageListController : CyteViewController < +@interface PackageListController : CyteListController < UITableViewDataSource, UITableViewDelegate > { @@ -6447,7 +5978,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { unsigned era_; _H packages_; _H sections_; - _H list_; _H thumbs_; std::vector offset_; @@ -6457,9 +5987,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } - (id) initWithDatabase:(Database *)database title:(NSString *)title; -- (void) setDelegate:(id)delegate; -- (void) resetCursor; -- (void) clearData; - (NSArray *) sectionsForPackages:(NSMutableArray *)packages; @@ -6479,98 +6006,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { return true; } -- (void) deselectWithAnimation:(BOOL)animated { - [list_ deselectRowAtIndexPath:[list_ indexPathForSelectedRow] animated:animated]; -} - -- (void) resizeForKeyboardBounds:(CGRect)bounds duration:(NSTimeInterval)duration curve:(UIViewAnimationCurve)curve { - CGRect base = [[self view] bounds]; - base.size.height -= bounds.size.height; - base.origin = [list_ frame].origin; - - [UIView beginAnimations:nil context:NULL]; - [UIView setAnimationBeginsFromCurrentState:YES]; - [UIView setAnimationCurve:curve]; - [UIView setAnimationDuration:duration]; - [list_ setFrame:base]; - [UIView commitAnimations]; -} - -- (void) resizeForKeyboardBounds:(CGRect)bounds duration:(NSTimeInterval)duration { - [self resizeForKeyboardBounds:bounds duration:duration curve:UIViewAnimationCurveLinear]; -} - -- (void) resizeForKeyboardBounds:(CGRect)bounds { - [self resizeForKeyboardBounds:bounds duration:0]; -} - -- (void) getKeyboardCurve:(UIViewAnimationCurve *)curve duration:(NSTimeInterval *)duration forNotification:(NSNotification *)notification { - if (&UIKeyboardAnimationCurveUserInfoKey == NULL) - *curve = UIViewAnimationCurveEaseInOut; - else - [[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:curve]; - - if (&UIKeyboardAnimationDurationUserInfoKey == NULL) - *duration = 0.3; - else - [[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:duration]; -} - -- (void) keyboardWillShow:(NSNotification *)notification { - CGRect bounds; - CGPoint center; - [[[notification userInfo] objectForKey:UIKeyboardBoundsUserInfoKey] getValue:&bounds]; - [[[notification userInfo] objectForKey:UIKeyboardCenterEndUserInfoKey] getValue:¢er]; - - NSTimeInterval duration; - UIViewAnimationCurve curve; - [self getKeyboardCurve:&curve duration:&duration forNotification:notification]; - - CGRect kbframe = CGRectMake(Retina(center.x - bounds.size.width / 2), Retina(center.y - bounds.size.height / 2), bounds.size.width, bounds.size.height); - UIViewController *base = self; - while ([base parentOrPresentingViewController] != nil) - base = [base parentOrPresentingViewController]; - CGRect viewframe = [[base view] convertRect:[list_ frame] fromView:[list_ superview]]; - CGRect intersection = CGRectIntersection(viewframe, kbframe); - - if (kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber_iPhoneOS_3_0) // XXX: _UIApplicationLinkedOnOrAfter(4) - intersection.size.height += CYStatusBarHeight(); - - [self resizeForKeyboardBounds:intersection duration:duration curve:curve]; -} - -- (void) keyboardWillHide:(NSNotification *)notification { - NSTimeInterval duration; - UIViewAnimationCurve curve; - [self getKeyboardCurve:&curve duration:&duration forNotification:notification]; - - [self resizeForKeyboardBounds:CGRectZero duration:duration curve:curve]; -} - -- (void) viewWillAppear:(BOOL)animated { - [super viewWillAppear:animated]; - - [self resizeForKeyboardBounds:CGRectZero]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; -} - -- (void) viewWillDisappear:(BOOL)animated { - [super viewWillDisappear:animated]; - - [self resizeForKeyboardBounds:CGRectZero]; - [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil]; - [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil]; -} - -- (void) viewDidAppear:(BOOL)animated { - [super viewDidAppear:animated]; - [self deselectWithAnimation:animated]; -} - - (void) didSelectPackage:(Package *)package { CYPackageController *view([[[CYPackageController alloc] initWithDatabase:database_ forPackage:[package id] withReferrer:[[self referrerURL] absoluteString]] autorelease]); - [view setDelegate:delegate_]; + [view setDelegate:self.delegate]; [[self navigationController] pushViewController:view animated:YES]; } @@ -6626,8 +6064,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { return offset_[index]; } -- (void) updateHeight { - [list_ setRowHeight:([self isSummarized] ? 38 : 73)]; +- (CGFloat) rowHeight { + return [self isSummarized] ? 38 : 73; } - (id) initWithDatabase:(Database *)database title:(NSString *)title { @@ -6638,27 +6076,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { } return self; } -- (void) loadView { - UIView *view([[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease]); - [view setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight)]; - [self setView:view]; - - list_ = [[[UITableView alloc] initWithFrame:[[self view] bounds] style:UITableViewStylePlain] autorelease]; - [list_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; - [view addSubview:list_]; - - // XXX: is 20 the most optimal number here? - [list_ setSectionIndexMinimumDisplayRowCount:20]; - - [(UITableView *) list_ setDataSource:self]; - [list_ setDelegate:self]; - - [self updateHeight]; -} - - (void) releaseSubviews { - list_ = nil; - packages_ = nil; sections_ = nil; @@ -6668,14 +6086,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { [super releaseSubviews]; } -- (void) setDelegate:(id)delegate { - delegate_ = delegate; -} - -- (bool) shouldYield { - return false; -} - - (bool) shouldBlock { return false; } @@ -6704,7 +6114,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { if (![self shouldBlock]) hud = nil; else { - hud = [delegate_ addProgressHUD]; + hud = [self.delegate addProgressHUD]; [hud setText:UCLocalize("LOADING")]; } @@ -6712,7 +6122,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { packages = [self yieldToSelector:@selector(_reloadPackages)]; if (hud != nil) - [delegate_ removeProgressHUD:hud]; + [self.delegate removeProgressHUD:hud]; } while (reloading_ == 2); } else { packages = [self _reloadPackages]; @@ -6736,12 +6146,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { sections_ = [NSArray arrayWithObject:section]; } - [self updateHeight]; - - _profile(PackageTable$reloadData$List) - [(UITableView *) list_ setDataSource:self]; - [list_ reloadData]; - _end + [super _reloadData]; } PrintTimes(); @@ -6800,28 +6205,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) { return sections; } -- (void) reloadData { - [super reloadData]; - - if ([self shouldYield]) - [self performSelector:@selector(_reloadData) withObject:nil afterDelay:0]; - else - [self _reloadData]; -} - -- (void) resetCursor { - [list_ scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:NO]; -} - -- (void) clearData { - [self updateHeight]; - - [list_ setDataSource:nil]; - [list_ reloadData]; - - [self resetCursor]; -} - @end /* }}} */ /* Filtered Package List Controller {{{ */ @@ -6868,7 +6251,7 @@ typedef Function PackageSorter; _profile(PackageTable$reloadData$Filter) for (Package *package in packages) - if ([package valid] && filter(package)) + if (filter(package)) [filtered addObject:package]; _end @@ -6935,7 +6318,7 @@ static void HomeControllerReachabilityCallback(SCNetworkReachabilityRef reachabi [alert setCancelButtonIndex:0]; [alert setMessage: - @"Copyright \u00a9 2008-2014\n" + @"Copyright \u00a9 2008-2015\n" "SaurikIT, LLC\n" "\n" "Jay Freeman (saurik)\n" @@ -6958,15 +6341,6 @@ static void HomeControllerReachabilityCallback(SCNetworkReachabilityRef reachabi @end /* }}} */ -/* Cydia Navigation Controller Interface {{{ */ -@interface UINavigationController (Cydia) - -- (NSArray *) navigationURLCollection; -- (void) unloadData; - -@end -/* }}} */ - /* Cydia Tab Bar Controller {{{ */ @interface CydiaTabBarController : CyteTabBarController < UITabBarControllerDelegate, @@ -6981,7 +6355,6 @@ static void HomeControllerReachabilityCallback(SCNetworkReachabilityRef reachabi _transient NSObject *updatedelegate_; } -- (NSArray *) navigationURLCollection; - (void) beginUpdate; - (BOOL) updating; @@ -6989,19 +6362,6 @@ static void HomeControllerReachabilityCallback(SCNetworkReachabilityRef reachabi @implementation CydiaTabBarController -- (NSArray *) navigationURLCollection { - NSMutableArray *items([NSMutableArray array]); - - // XXX: Should this deal with transient view controllers? - for (id navigation in [self viewControllers]) { - NSArray *stack = [navigation performSelector:@selector(navigationURLCollection)]; - if (stack != nil) - [items addObject:stack]; - } - - return items; -} - - (id) initWithDatabase:(Database *)database { if ((self = [super init]) != nil) { database_ = database; @@ -7014,10 +6374,6 @@ static void HomeControllerReachabilityCallback(SCNetworkReachabilityRef reachabi } return self; } -- (void) setUpdate:(NSDate *)date { - [self beginUpdate]; -} - - (void) beginUpdate { if (updating_) return; @@ -7104,103 +6460,19 @@ static void HomeControllerReachabilityCallback(SCNetworkReachabilityRef reachabi @end /* }}} */ -/* Cydia Navigation Controller Implementation {{{ */ -@implementation UINavigationController (Cydia) - -- (NSArray *) navigationURLCollection { - NSMutableArray *stack([NSMutableArray array]); - - for (CyteViewController *controller in [self viewControllers]) { - NSString *url = [[controller navigationURL] absoluteString]; - if (url != nil) - [stack addObject:url]; - } - - return stack; -} - -- (void) reloadData { - [super reloadData]; - - UIViewController *visible([self visibleViewController]); - if (visible != nil) - [visible reloadData]; - - // on the iPad, this view controller is ALSO visible. :( - if (IsWildcat_) - if (UIViewController *modal = [self modalViewController]) - if ([modal modalPresentationStyle] == UIModalPresentationFormSheet) - if (UIViewController *top = [self topViewController]) - if (top != visible) - [top reloadData]; -} - -- (void) unloadData { - for (CyteViewController *page in [self viewControllers]) - [page unloadData]; - - [super unloadData]; -} - -@end -/* }}} */ - /* Cydia:// Protocol {{{ */ -@interface CydiaURLProtocol : NSURLProtocol { +@interface CydiaURLProtocol : CyteURLProtocol { } @end @implementation CydiaURLProtocol -+ (BOOL) canInitWithRequest:(NSURLRequest *)request { - NSURL *url([request URL]); - if (url == nil) - return NO; - - NSString *scheme([[url scheme] lowercaseString]); - if (scheme != nil && [scheme isEqualToString:@"cydia"]) - return YES; - if ([[url absoluteString] hasPrefix:@"about:cydia-"]) - return YES; - - return NO; ++ (NSString *) scheme { + return @"cydia"; } -+ (NSURLRequest *) canonicalRequestForRequest:(NSURLRequest *)request { - return request; -} - -- (void) _returnPNGWithImage:(UIImage *)icon forRequest:(NSURLRequest *)request { - id client([self client]); - if (icon == nil) - [client URLProtocol:self didFailWithError:[NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorFileDoesNotExist userInfo:nil]]; - else { - NSData *data(UIImagePNGRepresentation(icon)); - - NSURLResponse *response([[[NSURLResponse alloc] initWithURL:[request URL] MIMEType:@"image/png" expectedContentLength:-1 textEncodingName:nil] autorelease]); - [client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed]; - [client URLProtocol:self didLoadData:data]; - [client URLProtocolDidFinishLoading:self]; - } -} - -- (void) startLoading { - id client([self client]); - NSURLRequest *request([self request]); - - NSURL *url([request URL]); - NSString *href([url absoluteString]); - NSString *scheme([[url scheme] lowercaseString]); - - NSString *path; - - if ([scheme isEqualToString:@"cydia"]) - path = [href substringFromIndex:8]; - else if ([scheme isEqualToString:@"about"]) - path = [href substringFromIndex:12]; - else _assert(false); - +- (bool) loadForPath:(NSString *)path ofRequest:(NSURLRequest *)request { NSRange slash([path rangeOfString:@"/"]); NSString *command; @@ -7212,9 +6484,30 @@ static void HomeControllerReachabilityCallback(SCNetworkReachabilityRef reachabi path = [path substringFromIndex:(slash.location + 1)]; } - Database *database([Database sharedInstance]); + Database *database([Database sharedInstance]); + + if (false); + else if ([command isEqualToString:@"application-icon"]) { + if (path == nil) + goto fail; + path = [path stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + + UIImage *icon(nil); + + if (icon == nil && $SBSCopyIconImagePNGDataForDisplayIdentifier != NULL) { + NSData *data([$SBSCopyIconImagePNGDataForDisplayIdentifier(path) autorelease]); + icon = [UIImage imageWithData:data]; + } + + if (icon == nil) + if (NSString *file = SBSCopyIconImagePathForDisplayIdentifier(path)) + icon = [UIImage imageAtPath:file]; + + if (icon == nil) + icon = [UIImage imageNamed:@"unknown.png"]; - if ([command isEqualToString:@"package-icon"]) { + [self _returnPNGWithImage:icon forRequest:request]; + } else if ([command isEqualToString:@"package-icon"]) { if (path == nil) goto fail; path = [path stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; @@ -7239,11 +6532,10 @@ static void HomeControllerReachabilityCallback(SCNetworkReachabilityRef reachabi icon = [UIImage imageNamed:@"unknown.png"]; [self _returnPNGWithImage:icon forRequest:request]; } else fail: { - [client URLProtocol:self didFailWithError:[NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorResourceUnavailable userInfo:nil]]; + return [super loadForPath:path ofRequest:request]; } -} -- (void) stopLoading { + return true; } @end @@ -7362,7 +6654,7 @@ static void HomeControllerReachabilityCallback(SCNetworkReachabilityRef reachabi if (editing) [list_ reloadData]; else - [delegate_ updateData]; + [self.delegate updateData]; [self updateNavigationItem]; } @@ -7424,7 +6716,7 @@ static void HomeControllerReachabilityCallback(SCNetworkReachabilityRef reachabi source:[self source] section:[section name] ] autorelease]; - [controller setDelegate:delegate_]; + [controller setDelegate:self.delegate]; [[self navigationController] pushViewController:controller animated:YES]; } @@ -7495,7 +6787,7 @@ static void HomeControllerReachabilityCallback(SCNetworkReachabilityRef reachabi [section addToCount]; _profile(SectionsView$reloadData$Filter) - if (![package valid] || ![package visible]) + if (![package visible]) continue; _end @@ -7569,7 +6861,7 @@ static void HomeControllerReachabilityCallback(SCNetworkReachabilityRef reachabi } - (void) setLeftBarButtonItem { - if ([delegate_ updating]) + if ([self.delegate updating]) [[self navigationItem] setLeftBarButtonItem:[[[UIBarButtonItem alloc] initWithTitle:UCLocalize("CANCEL") style:UIBarButtonItemStyleDone @@ -7586,16 +6878,16 @@ static void HomeControllerReachabilityCallback(SCNetworkReachabilityRef reachabi } - (void) refreshButtonClicked { - if ([delegate_ requestUpdate]) + if ([self.delegate requestUpdate]) [self setLeftBarButtonItem]; } - (void) cancelButtonClicked { - [delegate_ cancelUpdate]; + [self.delegate cancelUpdate]; } - (void) upgradeButtonClicked { - [delegate_ distUpgrade]; + [self.delegate distUpgrade]; [[self navigationItem] setRightBarButtonItem:nil animated:YES]; } @@ -7702,8 +6994,6 @@ static void HomeControllerReachabilityCallback(SCNetworkReachabilityRef reachabi if (upgrades_ != 0) [sections insertObject:upgradable atIndex:0]; - [list_ reloadData]; - [[self navigationItem] setRightBarButtonItem:(upgrades_ == 0 ? nil : [[[UIBarButtonItem alloc] initWithTitle:[NSString stringWithFormat:UCLocalize("PARENTHETICAL"), UCLocalize("UPGRADE"), [NSString stringWithFormat:@"%u", upgrades_]] style:UIBarButtonItemStylePlain @@ -7940,27 +7230,22 @@ static void HomeControllerReachabilityCallback(SCNetworkReachabilityRef reachabi if (package_ == nil) return; if ([package_ setSubscribed:value]) - [delegate_ updateData]; + [self.delegate updateData]; } - (void) _updateIgnored { const char *package([name_ UTF8String]); bool on([ignoredSwitch_ isOn]); - pid_t pid(ExecFork()); - if (pid == 0) { - FILE *dpkg(_root(popen("dpkg --set-selections", "w"))); - fwrite(package, strlen(package), 1, dpkg); - - if (on) - fwrite(" hold\n", 6, 1, dpkg); - else - fwrite(" install\n", 9, 1, dpkg); + FILE *dpkg(popen("/usr/libexec/cydia/cydo --set-selections", "w")); + fwrite(package, strlen(package), 1, dpkg); - pclose(dpkg); + if (on) + fwrite(" hold\n", 6, 1, dpkg); + else + fwrite(" install\n", 9, 1, dpkg); - exit(0); - } ReapZombie(pid); + pclose(dpkg); } - (void) onIgnored:(id)control { @@ -7968,7 +7253,7 @@ static void HomeControllerReachabilityCallback(SCNetworkReachabilityRef reachabi [invocation setTarget:self]; [invocation setSelector:@selector(_updateIgnored)]; - [delegate_ reloadDataWithInvocation:invocation]; + [self.delegate reloadDataWithInvocation:invocation]; } - (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { @@ -8159,7 +7444,7 @@ static void HomeControllerReachabilityCallback(SCNetworkReachabilityRef reachabi #if !AlwaysReload - (void) queueButtonClicked { - [delegate_ queue]; + [self.delegate queue]; } #endif @@ -8209,7 +7494,7 @@ static void HomeControllerReachabilityCallback(SCNetworkReachabilityRef reachabi - (void) _setImage:(NSArray *)data { if ([url_ isEqual:[data objectAtIndex:0]]) { icon_ = [data objectAtIndex:1]; - [content_ setNeedsDisplay]; + [self.content setNeedsDisplay]; } } @@ -8243,7 +7528,7 @@ static void HomeControllerReachabilityCallback(SCNetworkReachabilityRef reachabi origin_ = [source name]; label_ = [source rooturi]; - [content_ setNeedsDisplay]; + [self.content setNeedsDisplay]; url_ = [source iconURL]; [NSThread detachNewThreadSelector:@selector(_setSource:) toTarget:self withObject:url_]; @@ -8256,7 +7541,7 @@ static void HomeControllerReachabilityCallback(SCNetworkReachabilityRef reachabi icon_ = [UIImage imageNamed:@"folder.png"]; origin_ = UCLocalize("ALL_SOURCES"); label_ = UCLocalize("ALL_SOURCES_EX"); - [content_ setNeedsDisplay]; + [self.content setNeedsDisplay]; } - (SourceCell *) initWithFrame:(CGRect)frame reuseIdentifier:(NSString *)reuseIdentifier { @@ -8264,19 +7549,19 @@ static void HomeControllerReachabilityCallback(SCNetworkReachabilityRef reachabi UIView *content([self contentView]); CGRect bounds([content bounds]); - content_ = [[[CyteTableViewCellContentView alloc] initWithFrame:bounds] autorelease]; - [content_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; - [content_ setBackgroundColor:[UIColor whiteColor]]; - [content addSubview:content_]; + self.content = [[[CyteTableViewCellContentView alloc] initWithFrame:bounds] autorelease]; + [self.content setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; + [self.content setBackgroundColor:[UIColor whiteColor]]; + [content addSubview:self.content]; - [content_ setDelegate:self]; - [content_ setOpaque:YES]; + [self.content setDelegate:self]; + [self.content setOpaque:YES]; indicator_ = [[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGraySmall] autorelease]; [indicator_ setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin];// | UIViewAutoresizingFlexibleBottomMargin]; [content addSubview:indicator_]; - [[content_ layer] setContentsGravity:kCAGravityTopLeft]; + [[self.content layer] setContentsGravity:kCAGravityTopLeft]; } return self; } @@ -8300,7 +7585,7 @@ static void HomeControllerReachabilityCallback(SCNetworkReachabilityRef reachabi } - (void) drawContentRect:(CGRect)rect { - bool highlighted(highlighted_); + bool highlighted(self.highlighted); float width(rect.size.width); if (icon_ != nil) { @@ -8444,7 +7729,7 @@ static void HomeControllerReachabilityCallback(SCNetworkReachabilityRef reachabi source:[self sourceAtIndexPath:indexPath] ] autorelease]); - [controller setDelegate:delegate_]; + [controller setDelegate:self.delegate]; [[self navigationController] pushViewController:controller animated:YES]; } @@ -8462,10 +7747,8 @@ static void HomeControllerReachabilityCallback(SCNetworkReachabilityRef reachabi if (source == nil) return; [Sources_ removeObjectForKey:[source key]]; - Changed_ = true; - [delegate_ _saveConfig]; - [delegate_ reloadDataWithInvocation:nil]; + [self.delegate syncData]; } } @@ -8474,10 +7757,10 @@ static void HomeControllerReachabilityCallback(SCNetworkReachabilityRef reachabi } - (void) complete { - [delegate_ addTrivialSource:href_]; + [self.delegate addTrivialSource:href_]; href_ = nil; - [delegate_ syncData]; + [self.delegate syncData]; } - (NSString *) getWarning { @@ -8516,9 +7799,9 @@ static void HomeControllerReachabilityCallback(SCNetworkReachabilityRef reachabi ) { NSString *warning(cydia_ ? [self yieldToSelector:@selector(getWarning)] : nil); - [delegate_ releaseNetworkActivityIndicator]; + [self.delegate releaseNetworkActivityIndicator]; - [delegate_ removeProgressHUD:hud_]; + [self.delegate removeProgressHUD:hud_]; hud_ = nil; if (cydia_) { @@ -8624,27 +7907,10 @@ static void HomeControllerReachabilityCallback(SCNetworkReachabilityRef reachabi switch (button) { case 1: { NSString *href = [[alert textField] text]; - - static Pcre href_r("^(http(s?)://|file:///)[^# ]*$"); - if (!href_r(href)) { - UIAlertView *alert = [[[UIAlertView alloc] - initWithTitle:[NSString stringWithFormat:Colon_, Error_, UCLocalize("INVALID_URL")] - message:UCLocalize("INVALID_URL_EX") - delegate:self - cancelButtonTitle:UCLocalize("OK") - otherButtonTitles:nil - ] autorelease]; - - [alert setContext:@"badurl"]; - [alert show]; - + href = VerifySource(href); + if (href == nil) break; - } - - if (![href hasSuffix:@"/"]) - href_ = [href stringByAppendingString:@"/"]; - else - href_ = href; + href_ = href; trivial_bz2_ = [[self _requestHRef:[href_ stringByAppendingString:@"Packages.bz2"] method:@"HEAD"] retain]; trivial_gz_ = [[self _requestHRef:[href_ stringByAppendingString:@"Packages.gz"] method:@"HEAD"] retain]; @@ -8652,9 +7918,9 @@ static void HomeControllerReachabilityCallback(SCNetworkReachabilityRef reachabi cydia_ = false; // XXX: this is stupid - hud_ = [delegate_ addProgressHUD]; + hud_ = [self.delegate addProgressHUD]; [hud_ setText:UCLocalize("VERIFYING_URL")]; - [delegate_ retainNetworkActivityIndicator]; + [self.delegate retainNetworkActivityIndicator]; } break; case 0: @@ -8694,7 +7960,7 @@ static void HomeControllerReachabilityCallback(SCNetworkReachabilityRef reachabi target:self action:@selector(addButtonClicked) ] autorelease] animated:animated]; - else if ([delegate_ updating]) + else if ([self.delegate updating]) [[self navigationItem] setLeftBarButtonItem:[[[UIBarButtonItem alloc] initWithTitle:UCLocalize("CANCEL") style:UIBarButtonItemStyleDone @@ -8794,7 +8060,7 @@ static void HomeControllerReachabilityCallback(SCNetworkReachabilityRef reachabi [alert setNumberOfRows:1]; [alert addTextFieldWithValue:@"http://" label:@""]; - UITextInputTraits *traits = [[alert textField] textInputTraits]; + NSObject *traits = [[alert textField] textInputTraits]; [traits setAutocapitalizationType:UITextAutocapitalizationTypeNone]; [traits setAutocorrectionType:UITextAutocorrectionTypeNo]; [traits setKeyboardType:UIKeyboardTypeURL]; @@ -8809,12 +8075,12 @@ static void HomeControllerReachabilityCallback(SCNetworkReachabilityRef reachabi } - (void) refreshButtonClicked { - if ([delegate_ requestUpdate]) + if ([self.delegate requestUpdate]) [self updateButtonsForEditingStatusAnimated:YES]; } - (void) cancelButtonClicked { - [delegate_ cancelUpdate]; + [self.delegate cancelUpdate]; } - (void) editButtonClicked { @@ -8894,64 +8160,12 @@ static void HomeControllerReachabilityCallback(SCNetworkReachabilityRef reachabi @end /* }}} */ -@interface CYURLCache : SDURLCache { -} - -@end - -@implementation CYURLCache - -- (void) logEvent:(NSString *)event forRequest:(NSURLRequest *)request { -#if !ForRelease - if (false); - else if ([event isEqualToString:@"no-cache"]) - event = @"!!!"; - else if ([event isEqualToString:@"store"]) - event = @">>>"; - else if ([event isEqualToString:@"invalid"]) - event = @"???"; - else if ([event isEqualToString:@"memory"]) - event = @"mem"; - else if ([event isEqualToString:@"disk"]) - event = @"ssd"; - else if ([event isEqualToString:@"miss"]) - event = @"---"; - - NSLog(@"%@: %@", event, [[request URL] absoluteString]); -#endif -} - -- (void) storeCachedResponse:(NSCachedURLResponse *)cached forRequest:(NSURLRequest *)request { - if (NSURLResponse *response = [cached response]) - if (NSString *mime = [response MIMEType]) - if ([mime isEqualToString:@"text/cache-manifest"]) { - NSURL *url([response URL]); - -#if !ForRelease - NSLog(@"###: %@", [url absoluteString]); -#endif - - @synchronized (HostConfig_) { - [CachedURLs_ addObject:url]; - } - } - - [super storeCachedResponse:cached forRequest:request]; -} - -- (void) createDiskCachePath { - [super createDiskCachePath]; - _root(chown([[self diskCachePath] UTF8String], 501, 501)); -} - -@end - -@interface Cydia : UIApplication < +@interface Cydia : CyteApplication < ConfirmationControllerDelegate, DatabaseDelegate, CydiaDelegate > { - _H window_; + _H window_; _H tabbar_; _H emulated_; _H appcache_; @@ -8964,7 +8178,6 @@ static void HomeControllerReachabilityCallback(SCNetworkReachabilityRef reachabi _H starturl_; unsigned locked_; - unsigned activity_; _H stash_; @@ -9004,7 +8217,7 @@ static void HomeControllerReachabilityCallback(SCNetworkReachabilityRef reachabi } - (bool) requestUpdate { - if (IsReachable("cydia.saurik.com")) { + if (CyteIsReachable("cydia.saurik.com")) { [self beginUpdate]; return true; } else { @@ -9067,30 +8280,17 @@ static void HomeControllerReachabilityCallback(SCNetworkReachabilityRef reachabi [self _loaded]; } -- (void) _saveConfig { - @synchronized (database_) { - _trace(); - MetaFile_.Sync(); - _trace(); - } - - if (Changed_) { - NSString *error(nil); - - if (NSData *data = [NSPropertyListSerialization dataFromPropertyList:Metadata_ format:NSPropertyListBinaryFormat_v1_0 errorDescription:&error]) { - _trace(); - NSError *error(nil); - if (!_root([data writeToFile:@"/var/lib/cydia/metadata.plist" options:NSAtomicWrite error:&error])) - NSLog(@"failure to save metadata data: %@", error); - _trace(); - - Changed_ = false; - } else { - NSLog(@"failure to serialize metadata: %@", error); - } - } +- (void) reloadSpringBoard { + if (kCFCoreFoundationVersionNumber >= 700) // XXX: iOS 6.x + system("/usr/libexec/cydia/cydo /bin/launchctl stop com.apple.backboardd"); + else + system("/usr/libexec/cydia/cydo /bin/launchctl stop com.apple.SpringBoard"); + sleep(15); + system("/usr/bin/killall backboardd SpringBoard"); +} - _root(CydiaWriteSources()); +- (void) _saveConfig { + SaveConfig(database_); } // Navigation controller for the queuing badge. @@ -9099,13 +8299,9 @@ static void HomeControllerReachabilityCallback(SCNetworkReachabilityRef reachabi return [controllers objectAtIndex:3]; } -- (void) unloadData { - [tabbar_ unloadData]; -} - - (void) _updateData { [self _saveConfig]; - [self unloadData]; + [window_ unloadData]; UINavigationController *navigation = [self queueNavigationController]; @@ -9117,9 +8313,11 @@ static void HomeControllerReachabilityCallback(SCNetworkReachabilityRef reachabi [[navigation tabBarItem] setBadgeValue:(Queuing_ ? UCLocalize("Q_D") : nil)]; } -- (void) _refreshIfPossible:(NSDate *)update { +- (void) _refreshIfPossible { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + NSDate *update([[NSDictionary dictionaryWithContentsOfFile:@ CacheState_] objectForKey:@"LastUpdate"]); + bool recently = false; if (update != nil) { NSTimeInterval interval([update timeIntervalSinceNow]); @@ -9132,7 +8330,7 @@ static void HomeControllerReachabilityCallback(SCNetworkReachabilityRef reachabi // - We already auto-refreshed this launch. // - Auto-refresh is disabled. // - Cydia's server is not reachable - if (recently || loaded_ || ManualRefresh || !IsReachable("cydia.saurik.com")) { + if (recently || loaded_ || ManualRefresh || !CyteIsReachable("cydia.saurik.com")) { // If we are cancelling, we need to make sure it knows it's already loaded. loaded_ = true; @@ -9141,14 +8339,14 @@ static void HomeControllerReachabilityCallback(SCNetworkReachabilityRef reachabi // We are going to load, so remember that. loaded_ = true; - [tabbar_ performSelectorOnMainThread:@selector(setUpdate:) withObject:update waitUntilDone:NO]; + [tabbar_ performSelectorOnMainThread:@selector(beginUpdate) withObject:nil waitUntilDone:NO]; } [pool release]; } - (void) refreshIfPossible { - [NSThread detachNewThreadSelector:@selector(_refreshIfPossible:) toTarget:self withObject:[Metadata_ objectForKey:@"LastUpdate"]]; + [NSThread detachNewThreadSelector:@selector(_refreshIfPossible) toTarget:self withObject:nil]; } - (void) reloadDataWithInvocation:(NSInvocation *)invocation { @@ -9222,14 +8420,9 @@ _end if (emulated_ == nil) return; - if ([window_ respondsToSelector:@selector(setRootViewController:)]) - [window_ setRootViewController:tabbar_]; - else { - [window_ addSubview:[tabbar_ view]]; - [[emulated_ view] removeFromSuperview]; - } - + [window_ setRootViewController:tabbar_]; emulated_ = nil; + [window_ setUserInteractionEnabled:YES]; } @@ -9296,12 +8489,10 @@ _end CydiaAddSource(href, distribution, sections); } -- (void) addTrivialSource:(NSString *)href { +// XXX: this method should not return anything +- (BOOL) addTrivialSource:(NSString *)href { CydiaAddSource(href, @"./"); -} - -- (void) updateValues { - Changed_ = true; + return YES; } - (void) resolve { @@ -9383,14 +8574,7 @@ _end - (void) _uicache { _trace(); - - if (UpgradeCydia_ && Finish_ > 0) { - setreugid(0, 0); - system("su -c /usr/bin/uicache mobile"); - } else { - system("/usr/bin/uicache"); - } - + system("/usr/bin/uicache"); _trace(); } @@ -9414,25 +8598,6 @@ _end [self unlockSuspend]; } -- (void) retainNetworkActivityIndicator { - if (activity_++ == 0) - [self setNetworkActivityIndicatorVisible:YES]; - -#if TraceLogging - NSLog(@"retainNetworkActivityIndicator->%d", activity_); -#endif -} - -- (void) releaseNetworkActivityIndicator { - if (--activity_ == 0) - [self setNetworkActivityIndicatorVisible:NO]; - -#if TraceLogging - NSLog(@"releaseNetworkActivityIndicator->%d", activity_); -#endif - -} - - (void) cancelAndClear:(bool)clear { @synchronized (self) { if (clear) { @@ -9463,14 +8628,14 @@ _end @synchronized (self) { for (Package *broken in (id) broken_) { [broken remove]; - NSString *id = [broken id]; - - _root({ - unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.prerm", id] UTF8String]); - unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.postrm", id] UTF8String]); - unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.preinst", id] UTF8String]); - unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.postinst", id] UTF8String]); - }); + NSString *id(ShellEscape([broken id])); + system([[NSString stringWithFormat:@"/usr/libexec/cydia/cydo /bin/rm -f" + " /var/lib/dpkg/info/%@.prerm" + " /var/lib/dpkg/info/%@.postrm" + " /var/lib/dpkg/info/%@.preinst" + " /var/lib/dpkg/info/%@.postinst" + " /var/lib/dpkg/info/%@.extrainst_" + "", id, id, id, id, id] UTF8String]); } [self resolve]; @@ -9505,7 +8670,7 @@ _end NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]); _trace(); - _root(system([command UTF8String])); + system([command UTF8String]); _trace(); [pool release]; @@ -9565,7 +8730,7 @@ _end [super applicationSuspend]; } -- (void) applicationSuspend:(__GSEvent *)event { +- (void) applicationSuspend:(GSEventRef)event { if ([self isSafeToSuspend]) [super applicationSuspend:event]; } @@ -9673,7 +8838,7 @@ _end controller = [[[SectionController alloc] initWithDatabase:database_ source:nil section:argument] autorelease]; } - if (!external && [base isEqualToString:@"sources"]) { + if ([base isEqualToString:@"sources"]) { if ([argument isEqualToString:@"add"]) { controller = [[[SourcesController alloc] initWithDatabase:database_] autorelease]; [(SourcesController *)controller showAddSourcePrompt]; @@ -9741,10 +8906,11 @@ _end } - (void) saveState { - [Metadata_ setObject:[tabbar_ navigationURLCollection] forKey:@"InterfaceState"]; - [Metadata_ setObject:[NSDate date] forKey:@"LastClosed"]; - [Metadata_ setObject:[NSNumber numberWithInt:[tabbar_ selectedIndex]] forKey:@"InterfaceIndex"]; - Changed_ = true; + [[NSDictionary dictionaryWithObjectsAndKeys: + @"InterfaceState", [tabbar_ navigationURLCollection], + @"LastClosed", [NSDate date], + @"InterfaceIndex", [NSNumber numberWithInt:[tabbar_ selectedIndex]], + nil] writeToFile:@ SavedState_ atomically:YES]; [self _saveConfig]; } @@ -9756,15 +8922,15 @@ _end - (void) applicationDidEnterBackground:(UIApplication *)application { if (kCFCoreFoundationVersionNumber < 1000 && [self isSafeToSuspend]) return [self terminateWithSuccess]; + Backgrounded_ = [NSDate date]; [self saveState]; } - (void) applicationWillEnterForeground:(UIApplication *)application { - NSDate *closed = [Metadata_ objectForKey:@"LastClosed"]; - if (closed == nil) + if (Backgrounded_ == nil) return; - NSTimeInterval interval([closed timeIntervalSinceNow]); + NSTimeInterval interval([Backgrounded_ timeIntervalSinceNow]); if (interval <= -(30*60)) { [tabbar_ setSelectedIndex:0]; @@ -9772,15 +8938,18 @@ _end } if (interval <= -(15*60)) { - if (IsReachable("cydia.saurik.com")) { + if (CyteIsReachable("cydia.saurik.com")) { [tabbar_ beginUpdate]; [appcache_ reloadURLWithCache:YES]; } } + + if ([database_ delocked]) + [self reloadData]; } - (void) setConfigurationData:(NSString *)data { - static Pcre conffile_r("^'(.*)' '(.*)' ([01]) ([01])$"); + static RegEx conffile_r("'(.*)' '(.*)' ([01]) ([01])"); if (!conffile_r(data)) { lprintf("E:invalid conffile\n"); @@ -9821,91 +8990,18 @@ _end - (void) stash { [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackOpaque]; UpdateExternalStatus(1); - [self yieldToSelector:@selector(system:) withObject:@"/usr/libexec/cydia/free.sh"]; + [self yieldToSelector:@selector(system:) withObject:@"/usr/libexec/cydia/cydo /usr/libexec/cydia/free.sh"]; UpdateExternalStatus(0); [self removeStashController]; - - pid_t pid(ExecFork()); - if (pid == 0) { - execlp("launchctl", "launchctl", "stop", "com.apple.SpringBoard", NULL); - perror("launchctl stop"); - - exit(0); - } ReapZombie(pid); -} - -- (void) setupViewControllers { - tabbar_ = [[[CydiaTabBarController alloc] initWithDatabase:database_] autorelease]; - - NSMutableArray *items; - if (kCFCoreFoundationVersionNumber < 800) { - items = [NSMutableArray arrayWithObjects: - [[[UITabBarItem alloc] initWithTitle:@"Cydia" image:[UIImage imageNamed:@"home.png"] tag:0] autorelease], - [[[UITabBarItem alloc] initWithTitle:UCLocalize("SOURCES") image:[UIImage imageNamed:@"install.png"] tag:0] autorelease], - [[[UITabBarItem alloc] initWithTitle:UCLocalize("CHANGES") image:[UIImage imageNamed:@"changes.png"] tag:0] autorelease], - [[[UITabBarItem alloc] initWithTitle:UCLocalize("INSTALLED") image:[UIImage imageNamed:@"manage.png"] tag:0] autorelease], - [[[UITabBarItem alloc] initWithTitle:UCLocalize("SEARCH") image:[UIImage imageNamed:@"search.png"] tag:0] autorelease], - nil]; - } else { - items = [NSMutableArray arrayWithObjects: - [[[UITabBarItem alloc] initWithTitle:@"Cydia" image:[UIImage imageNamed:@"home7.png"] selectedImage:[UIImage imageNamed:@"home7s.png"]] autorelease], - [[[UITabBarItem alloc] initWithTitle:UCLocalize("SOURCES") image:[UIImage imageNamed:@"install7.png"] selectedImage:[UIImage imageNamed:@"install7s.png"]] autorelease], - [[[UITabBarItem alloc] initWithTitle:UCLocalize("CHANGES") image:[UIImage imageNamed:@"changes7.png"] selectedImage:[UIImage imageNamed:@"changes7s.png"]] autorelease], - [[[UITabBarItem alloc] initWithTitle:UCLocalize("INSTALLED") image:[UIImage imageNamed:@"manage7.png"] selectedImage:[UIImage imageNamed:@"manage7s.png"]] autorelease], - [[[UITabBarItem alloc] initWithTitle:UCLocalize("SEARCH") image:[UIImage imageNamed:@"search7.png"] selectedImage:[UIImage imageNamed:@"search7s.png"]] autorelease], - nil]; - } - - NSMutableArray *controllers([NSMutableArray array]); - for (UITabBarItem *item in items) { - UINavigationController *controller([[[UINavigationController alloc] init] autorelease]); - [controller setTabBarItem:item]; - [controllers addObject:controller]; - } - [tabbar_ setViewControllers:controllers]; - - [tabbar_ setUpdateDelegate:self]; -} - -- (void) _sendMemoryWarningNotification { - if (kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber_iPhoneOS_3_0) // XXX: maybe 4_0? - [[NSNotificationCenter defaultCenter] postNotificationName:@"UIApplicationMemoryWarningNotification" object:[UIApplication sharedApplication]]; - else - [[NSNotificationCenter defaultCenter] postNotificationName:@"UIApplicationDidReceiveMemoryWarningNotification" object:[UIApplication sharedApplication]]; -} - -- (void) _sendMemoryWarningNotifications { - while (true) { - [self performSelectorOnMainThread:@selector(_sendMemoryWarningNotification) withObject:nil waitUntilDone:NO]; - sleep(2); - //usleep(2000000); - } -} - -- (void) applicationDidReceiveMemoryWarning:(UIApplication *)application { - NSLog(@"--"); - [[NSURLCache sharedURLCache] removeAllCachedResponses]; + [self reloadSpringBoard]; } - (void) applicationDidFinishLaunching:(id)unused { - //[NSThread detachNewThreadSelector:@selector(_sendMemoryWarningNotifications) toTarget:self withObject:nil]; - -_trace(); - if ([self respondsToSelector:@selector(setApplicationSupportsShakeToEdit:)]) - [self setApplicationSupportsShakeToEdit:NO]; - - @synchronized (HostConfig_) { - [BridgedHosts_ addObject:[[NSURL URLWithString:CydiaURL(@"")] host]]; - } - - [NSURLCache setSharedURLCache:[[[CYURLCache alloc] - initWithMemoryCapacity:524288 - diskCapacity:10485760 - diskPath:Cache("SDURLCache") - ] autorelease]]; + [super applicationDidFinishLaunching:unused]; + [CyteWebViewController _initialize]; - [CydiaWebViewController _initialize]; + [BridgedHosts_ addObject:[[NSURL URLWithString:CydiaURL(@"")] host]]; [NSURLProtocol registerClass:[CydiaURLProtocol class]]; @@ -9926,11 +9022,14 @@ _trace(); appcache_ = [[[AppCacheController alloc] initWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/appcache/", UI_]]] autorelease]; [appcache_ reloadData]; - window_ = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease]; + window_ = [[[CyteWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease]; [window_ orderFront:self]; [window_ makeKey:self]; [window_ setHidden:NO]; + if (access("/.cydia_no_stash", F_OK) == 0); + else { + if (false) stash: { [self addStashController]; // XXX: this would be much cleaner as a yieldToSelector: @@ -9961,15 +9060,27 @@ _trace(); Stash_("/Library/Wallpaper"); //Stash_("/usr/bin"); Stash_("/usr/include"); - Stash_("/usr/lib/pam"); Stash_("/usr/share"); //Stash_("/var/lib"); + } + database_ = [Database sharedInstance]; [database_ setDelegate:self]; [window_ setUserInteractionEnabled:NO]; - [self setupViewControllers]; + + tabbar_ = [[[CydiaTabBarController alloc] initWithDatabase:database_] autorelease]; + + [tabbar_ addViewControllers:nil, + @"Cydia", @"home.png", @"home7.png", @"home7s.png", + UCLocalize("SOURCES"), @"install.png", @"install7.png", @"install7s.png", + UCLocalize("CHANGES"), @"changes.png", @"changes7.png", @"changes7s.png", + UCLocalize("INSTALLED"), @"manage.png", @"manage7.png", @"manage7s.png", + UCLocalize("SEARCH"), @"search.png", @"search7.png", @"search7s.png", + nil]; + + [tabbar_ setUpdateDelegate:self]; CydiaLoadingViewController *loading([[[CydiaLoadingViewController alloc] init] autorelease]); UINavigationController *navigation([[[UINavigationController alloc] init] autorelease]); @@ -9982,10 +9093,7 @@ _trace(); if ([emulated_ respondsToSelector:@selector(concealTabBarSelection)]) [emulated_ concealTabBarSelection]; - if ([window_ respondsToSelector:@selector(setRootViewController:)]) - [window_ setRootViewController:emulated_]; - else - [window_ addSubview:[emulated_ view]]; + [window_ setRootViewController:emulated_]; [self performSelector:@selector(loadData) withObject:nil afterDelay:0]; _trace(); @@ -10011,8 +9119,10 @@ _trace(); [self refreshIfPossible]; [self disemulate]; - int savedIndex = [[Metadata_ objectForKey:@"InterfaceIndex"] intValue]; - NSArray *saved = [[[Metadata_ objectForKey:@"InterfaceState"] mutableCopy] autorelease]; + NSDictionary *state([NSDictionary dictionaryWithContentsOfFile:@ SavedState_]); + + int savedIndex = [[state objectForKey:@"InterfaceIndex"] intValue]; + NSArray *saved = [[[state objectForKey:@"InterfaceState"] mutableCopy] autorelease]; int standardIndex = 0; NSArray *standard = [self defaultStartPages]; @@ -10021,7 +9131,7 @@ _trace(); if (saved == nil) valid = NO; - NSDate *closed = [Metadata_ objectForKey:@"LastClosed"]; + NSDate *closed = [state objectForKey:@"LastClosed"]; if (valid && closed != nil) { NSTimeInterval interval([closed timeIntervalSinceNow]); if (interval <= -(30*60)) @@ -10076,6 +9186,11 @@ _trace(); } - (void) showActionSheet:(UIActionSheet *)sheet fromItem:(UIBarButtonItem *)item { + if (!IsWildcat_) { + [sheet addButtonWithTitle:UCLocalize("CANCEL")]; + [sheet setCancelButtonIndex:[sheet numberOfButtons] - 1]; + } + if (item != nil && IsWildcat_) { [sheet showFromBarButtonItem:item animated:YES]; } else { @@ -10115,159 +9230,76 @@ id Dealloc_(id self, SEL selector) { return object; }*/ -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] autorelease]); - - 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 (NSString *control = [copy valueForHTTPHeaderField:@"Cache-Control"]) - if ([control isEqualToString:@"max-age=0"]) - if ([CachedURLs_ containsObject:url]) { -#if !ForRelease - NSLog(@"~~~: %@", url); -#endif - - [copy setCachePolicy:NSURLRequestReturnCacheDataDontLoad]; - - [copy setValue:nil forHTTPHeaderField:@"Cache-Control"]; - [copy setValue:nil forHTTPHeaderField:@"If-Modified-Since"]; - [copy setValue:nil forHTTPHeaderField:@"If-None-Match"]; - } - } - - if ((self = _NSURLConnection$init$(self, _cmd, copy, delegate, usesCache, maxContentLength, startImmediately, connectionProperties)) != nil) { - } return self; -} - -Class $WAKWindow; - -static CGSize $WAKWindow$screenSize(WAKWindow *self, SEL _cmd) { - CGSize size([[UIScreen mainScreen] bounds].size); - /*if ([$WAKWindow respondsToSelector:@selector(hasLandscapeOrientation)]) - if ([$WAKWindow hasLandscapeOrientation]) - std::swap(size.width, size.height);*/ - return size; +static NSMutableDictionary *AutoreleaseDeepMutableCopyOfDictionary(CFTypeRef type) { + if (type == NULL) + return nil; + if (CFGetTypeID(type) != CFDictionaryGetTypeID()) + return nil; + CFTypeRef copy(CFPropertyListCreateDeepCopy(kCFAllocatorDefault, type, kCFPropertyListMutableContainers)); + CFRelease(type); + return [(NSMutableDictionary *) copy autorelease]; } -Class $NSUserDefaults; - -MSHook(id, NSUserDefaults$objectForKey$, NSUserDefaults *self, SEL _cmd, NSString *key) { - if ([key respondsToSelector:@selector(isEqualToString:)] && [key isEqualToString:@"WebKitLocalStorageDatabasePathPreferenceKey"]) - return Cache("LocalStorage"); - return _NSUserDefaults$objectForKey$(self, _cmd, key); -} +int main_store(int, char *argv[]); int main(int argc, char *argv[]) { - setreugid(501, 501); +#ifdef __arm64__ + const char *argv0(argv[0]); + if (const char *slash = strrchr(argv0, '/')) + argv0 = slash + 1; + if (false); + else if (!strcmp(argv0, "store")) + return main_store(argc, argv); +#endif + + int fd(open("/tmp/cydia.log", O_WRONLY | O_APPEND | O_CREAT, 0644)); + dup2(fd, 2); + close(fd); NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]); _trace(); + CyteInitialize(@"Cydia", Cydia_); UpdateExternalStatus(0); - UIScreen *screen([UIScreen mainScreen]); - if ([screen respondsToSelector:@selector(scale)]) - ScreenScale_ = [screen scale]; - else - ScreenScale_ = 1; - - UIDevice *device([UIDevice currentDevice]); - if ([device respondsToSelector:@selector(userInterfaceIdiom)]) { - UIUserInterfaceIdiom idiom([device userInterfaceIdiom]); - if (idiom == UIUserInterfaceIdiomPad) - IsWildcat_ = true; - } - - Idiom_ = IsWildcat_ ? @"ipad" : @"iphone"; - - Pcre pattern("^([0-9]+\\.[0-9]+)"); - - if (pattern([device systemVersion])) - Firmware_ = pattern[1]; - if (pattern(Cydia_)) - Major_ = pattern[1]; - SessionData_ = [NSMutableDictionary dictionaryWithCapacity:4]; + BridgedHosts_ = [NSMutableSet setWithCapacity:4]; + InsecureHosts_ = [NSMutableSet setWithCapacity:4]; - HostConfig_ = [[[NSObject alloc] init] autorelease]; - @synchronized (HostConfig_) { - BridgedHosts_ = [NSMutableSet setWithCapacity:4]; - TokenHosts_ = [NSMutableSet setWithCapacity:4]; - InsecureHosts_ = [NSMutableSet setWithCapacity:4]; - PipelinedHosts_ = [NSMutableSet setWithCapacity:4]; - CachedURLs_ = [NSMutableSet setWithCapacity:32]; - } - - NSString *ui(@"ui/ios"); - if (Idiom_ != nil) - ui = [ui stringByAppendingString:[NSString stringWithFormat:@"~%@", Idiom_]]; - ui = [ui stringByAppendingString:[NSString stringWithFormat:@"/%@", Major_]]; - UI_ = CydiaURL(ui); - + UI_ = CydiaURL([NSString stringWithFormat:@"ui/ios~%@/1.1", IsWildcat_ ? @"ipad" : @"iphone"]); PackageName = reinterpret_cast(method_getImplementation(class_getInstanceMethod([Package class], @selector(cyname)))); - /* Library Hacks {{{ */ - class_addMethod(objc_getClass("DOMNodeList"), @selector(countByEnumeratingWithState:objects:count:), (IMP) &DOMNodeList$countByEnumeratingWithState$objects$count$, "I20@0:4^{NSFastEnumerationState}8^@12I16"); - - $WAKWindow = objc_getClass("WAKWindow"); - if ($WAKWindow != NULL) - if (Method method = class_getInstanceMethod($WAKWindow, @selector(screenSize))) - method_setImplementation(method, (IMP) &$WAKWindow$screenSize); - - $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$)); - } - - $NSUserDefaults = objc_getClass("NSUserDefaults"); - Method NSUserDefaults$objectForKey$(class_getInstanceMethod($NSUserDefaults, @selector(objectForKey:))); - if (NSUserDefaults$objectForKey$ != NULL) { - _NSUserDefaults$objectForKey$ = reinterpret_cast(method_getImplementation(NSUserDefaults$objectForKey$)); - method_setImplementation(NSUserDefaults$objectForKey$, reinterpret_cast(&$NSUserDefaults$objectForKey$)); - } - /* }}} */ /* Set Locale {{{ */ Locale_ = CFLocaleCopyCurrent(); Languages_ = [NSLocale preferredLanguages]; - //CFStringRef locale(CFLocaleGetIdentifier(Locale_)); - //NSLog(@"%@", [Languages_ description]); + std::string languages; + const char *translation(NULL); - const char *lang; + // XXX: this isn't really a language, but this is compatible with older Cydia builds 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; - - if (lang != NULL) { - Pcre pattern("^([a-z][a-z])(?:-[A-Za-z]*)?(_[A-Z][A-Z])?$"); - lang = !pattern(lang) ? NULL : [pattern->*@"%1$@%2$@" UTF8String]; - } + if (const char *language = [(NSString *) CFLocaleGetIdentifier(Locale_) UTF8String]) { + RegEx pattern("([a-z][a-z])(?:-[A-Za-z]*)?(_[A-Z][A-Z])?"); + if (pattern(language)) { + translation = strdup([pattern->*@"%1$@%2$@" UTF8String]); + languages += translation; + languages += ","; + } + } - NSLog(@"Setting Language: %s", lang); + if (Languages_ != nil) + for (NSString *locale : Languages_) { + auto components([NSLocale componentsFromLocaleIdentifier:locale]); + NSString *language([components objectForKey:(id)kCFLocaleLanguageCode]); + if (NSString *script = [components objectForKey:(id)kCFLocaleScriptCode]) + language = [NSString stringWithFormat:@"%@-%@", language, script]; + languages += [language UTF8String]; + languages += ","; + } - if (lang != NULL) { - setenv("LANG", lang, true); - std::setlocale(LC_ALL, lang); - } + languages += "en"; + NSLog(@"Setting Language: [%s] %s", translation, languages.c_str()); /* }}} */ /* Index Collation {{{ */ if (Class $UILocalizedIndexedCollation = objc_getClass("UILocalizedIndexedCollation")) { @try { @@ -10321,36 +9353,11 @@ int main(int argc, char *argv[]) { } /* }}} */ - apr_app_initialize(&argc, const_cast(&argv), NULL); - - /* Parse Arguments {{{ */ - bool substrate(false); - - if (argc != 0) { - char **args(argv); - int arge(1); - - for (int argi(1); argi != argc; ++argi) - if (strcmp(argv[argi], "--") == 0) { - arge = argi; - argv[argi] = argv[0]; - argv += argi; - argc -= argi; - break; - } - - for (int argi(1); argi != arge; ++argi) - if (strcmp(args[argi], "--substrate") == 0) - substrate = true; - else - fprintf(stderr, "unknown argument: %s\n", args[argi]); - } - /* }}} */ - App_ = [[NSBundle mainBundle] bundlePath]; Advanced_ = YES; Cache_ = [[NSString stringWithFormat:@"%@/Library/Caches/com.saurik.Cydia", @"/var/mobile"] retain]; + mkdir([Cache_ UTF8String], 0755); /*Method alloc = class_getClassMethod([NSObject class], @selector(alloc)); alloc_ = alloc->method_imp; @@ -10362,6 +9369,7 @@ int main(int argc, char *argv[]) { void *gestalt(dlopen("/usr/lib/libMobileGestalt.dylib", RTLD_GLOBAL | RTLD_LAZY)); $MGCopyAnswer = reinterpret_cast(dlsym(gestalt, "MGCopyAnswer")); + UniqueID_ = UniqueIdentifier([UIDevice currentDevice]); /* System Information {{{ */ size_t size; @@ -10375,88 +9383,50 @@ int main(int argc, char *argv[]) { if (sysctlbyname("kern.maxproc", NULL, NULL, &maxproc, sizeof(maxproc)) == -1) perror("sysctlbyname(\"kern.maxproc\", #)"); } - - sysctlbyname("kern.osversion", NULL, &size, NULL, 0); - char *osversion = new char[size]; - if (sysctlbyname("kern.osversion", osversion, &size, NULL, 0) == -1) - perror("sysctlbyname(\"kern.osversion\", ?)"); - else - System_ = [NSString stringWithUTF8String:osversion]; - - sysctlbyname("hw.machine", NULL, &size, NULL, 0); - char *machine = new char[size]; - if (sysctlbyname("hw.machine", machine, &size, NULL, 0) == -1) - perror("sysctlbyname(\"hw.machine\", ?)"); - else - Machine_ = machine; - - int64_t usermem(0); - size = sizeof(usermem); - if (sysctlbyname("hw.usermem", &usermem, &size, NULL, 0) == -1) - usermem = 0; - - SerialNumber_ = (NSString *) CYIOGetValue("IOService:/", @"IOPlatformSerialNumber"); - ChipID_ = [CYHex((NSData *) CYIOGetValue("IODeviceTree:/chosen", @"unique-chip-id"), true) uppercaseString]; - BBSNum_ = CYHex((NSData *) CYIOGetValue("IOService:/AppleARMPE/baseband", @"snum"), false); - - UniqueID_ = UniqueIdentifier(device); - - if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:@"/Applications/MobileSafari.app/Info.plist"]) { - Product_ = [info objectForKey:@"SafariProductVersion"]; - Safari_ = [info objectForKey:@"CFBundleVersion"]; - } - - NSString *agent([NSString stringWithFormat:@"Cydia/%@ CyF/%.2f", Cydia_, kCFCoreFoundationVersionNumber]); - - if (Pcre match = Pcre("^[0-9]+(\\.[0-9]+)+", Safari_)) - agent = [NSString stringWithFormat:@"Safari/%@ %@", match[0], agent]; - if (Pcre match = Pcre("^[0-9]+[A-Z][0-9]+[a-z]?", System_)) - agent = [NSString stringWithFormat:@"Mobile/%@ %@", match[0], agent]; - if (Pcre match = Pcre("^[0-9]+(\\.[0-9]+)+", Product_)) - agent = [NSString stringWithFormat:@"Version/%@ %@", match[0], agent]; - - UserAgent_ = agent; /* }}} */ /* Load Database {{{ */ - _trace(); - Metadata_ = [[[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"] autorelease]; - _trace(); SectionMap_ = [[[NSDictionary alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Sections" ofType:@"plist"]] autorelease]; - if (Metadata_ == NULL) - Metadata_ = [NSMutableDictionary dictionaryWithCapacity:2]; - else { - Settings_ = [Metadata_ objectForKey:@"Settings"]; - - Packages_ = [Metadata_ objectForKey:@"Packages"]; - - Values_ = [Metadata_ objectForKey:@"Values"]; - Sections_ = [Metadata_ objectForKey:@"Sections"]; - Sources_ = [Metadata_ objectForKey:@"Sources"]; + _trace(); + mkdir("/var/mobile/Library/Cydia", 0755); + MetaFile_.Open("/var/mobile/Library/Cydia/metadata.cb0"); + _trace(); - Token_ = [Metadata_ objectForKey:@"Token"]; + Values_ = AutoreleaseDeepMutableCopyOfDictionary(CFPreferencesCopyAppValue(CFSTR("CydiaValues"), CFSTR("com.saurik.Cydia"))); + Sections_ = AutoreleaseDeepMutableCopyOfDictionary(CFPreferencesCopyAppValue(CFSTR("CydiaSections"), CFSTR("com.saurik.Cydia"))); + Sources_ = AutoreleaseDeepMutableCopyOfDictionary(CFPreferencesCopyAppValue(CFSTR("CydiaSources"), CFSTR("com.saurik.Cydia"))); + Version_ = [(NSNumber *) CFPreferencesCopyAppValue(CFSTR("CydiaVersion"), CFSTR("com.saurik.Cydia")) autorelease]; - Version_ = [Metadata_ objectForKey:@"Version"]; - } + _trace(); + NSDictionary *metadata([[[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"] autorelease]); - if (Values_ == nil) { + if (Values_ == nil) + Values_ = [metadata objectForKey:@"Values"]; + if (Values_ == nil) Values_ = [[[NSMutableDictionary alloc] initWithCapacity:4] autorelease]; - [Metadata_ setObject:Values_ forKey:@"Values"]; - } - if (Sections_ == nil) { + if (Sections_ == nil) + Sections_ = [metadata objectForKey:@"Sections"]; + if (Sections_ == nil) Sections_ = [[[NSMutableDictionary alloc] initWithCapacity:32] autorelease]; - [Metadata_ setObject:Sections_ forKey:@"Sections"]; - } - if (Sources_ == nil) { + if (Sources_ == nil) + Sources_ = [metadata objectForKey:@"Sources"]; + if (Sources_ == nil) Sources_ = [[[NSMutableDictionary alloc] initWithCapacity:0] autorelease]; - [Metadata_ setObject:Sources_ forKey:@"Sources"]; - } - if (Version_ == nil) { + // XXX: this wrong, but in a way that doesn't matter :/ + if (Version_ == nil) + Version_ = [metadata objectForKey:@"Version"]; + if (Version_ == nil) Version_ = [NSNumber numberWithUnsignedInt:0]; - [Metadata_ setObject:Version_ forKey:@"Version"]; + + if (NSDictionary *packages = [metadata objectForKey:@"Packages"]) { + bool fail(false); + CFDictionaryApplyFunction((CFDictionaryRef) packages, &PackageImport, &fail); + _trace(); + if (fail) + NSLog(@"unable to import package preferences... from 2010? oh well :/"); } if ([Version_ unsignedIntValue] == 0) { @@ -10466,68 +9436,36 @@ int main(int argc, char *argv[]) { CydiaAddSource(@"http://repo666.ultrasn0w.com/", @"./"); Version_ = [NSNumber numberWithUnsignedInt:1]; - [Metadata_ setObject:Version_ forKey:@"Version"]; - - [Metadata_ removeObjectForKey:@"LastUpdate"]; - Changed_ = true; + if (NSMutableDictionary *cache = [NSMutableDictionary dictionaryWithContentsOfFile:@ CacheState_]) { + [cache removeObjectForKey:@"LastUpdate"]; + [cache writeToFile:@ CacheState_ atomically:YES]; + } } _H broken([NSMutableArray array]); for (NSString *key in (id) Sources_) - if ([key rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@"# "]].location != NSNotFound) + if ([key rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@"# "]].location != NSNotFound || ![([[Sources_ objectForKey:key] objectForKey:@"URI"] ?: @"/") hasSuffix:@"/"]) [broken addObject:key]; - if ([broken count] != 0) { + if ([broken count] != 0) for (NSString *key in (id) broken) [Sources_ removeObjectForKey:key]; - Changed_ = true; - } broken = nil; - /* }}} */ - - _root(CydiaWriteSources()); - - _trace(); - mkdir("/var/mobile/Library/Cydia", 0755); - MetaFile_.Open("/var/mobile/Library/Cydia/metadata.cb0"); - _trace(); - - if (Packages_ != nil) { - bool fail(false); - CFDictionaryApplyFunction((CFDictionaryRef) Packages_, &PackageImport, &fail); - _trace(); + broken = nil; - if (!fail) { - [Metadata_ removeObjectForKey:@"Packages"]; - Packages_ = nil; - Changed_ = true; - } - } + SaveConfig(nil); + system("/usr/libexec/cydia/cydo /bin/rm -f /var/lib/cydia/metadata.plist"); + /* }}} */ Finishes_ = [NSArray arrayWithObjects:@"return", @"reopen", @"restart", @"reload", @"reboot", nil]; -#define MobileSubstrate_(name) \ - if (substrate && access("/Library/MobileSubstrate/DynamicLibraries/" #name ".dylib", F_OK) == 0) { \ - void *handle(dlopen("/Library/MobileSubstrate/DynamicLibraries/" #name ".dylib", RTLD_LAZY | RTLD_GLOBAL)); \ - if (handle == NULL) \ - NSLog(@"%s", dlerror()); \ - } - - MobileSubstrate_(Activator) - MobileSubstrate_(libstatusbar) - MobileSubstrate_(SimulatedKeyEvents) - MobileSubstrate_(WinterBoard) - - /*if (substrate && access("/Library/MobileSubstrate/MobileSubstrate.dylib", F_OK) == 0) - dlopen("/Library/MobileSubstrate/MobileSubstrate.dylib", RTLD_LAZY | RTLD_GLOBAL);*/ - if (kCFCoreFoundationVersionNumber > 1000) - _root(system([[NSString stringWithFormat:@"/usr/libexec/cydia/setnsfpn /var/lib"] UTF8String])); + system("/usr/libexec/cydia/cydo /usr/libexec/cydia/setnsfpn /var/lib"); int version([[NSString stringWithContentsOfFile:@"/var/lib/cydia/firmware.ver"] intValue]); if (access("/User", F_OK) != 0 || version != 6) { _trace(); - _root(system("/usr/libexec/cydia/firmware.sh")); + system("/usr/libexec/cydia/cydo /usr/libexec/cydia/firmware.sh"); _trace(); } @@ -10538,27 +9476,48 @@ int main(int argc, char *argv[]) { _assert(errno == ENOENT); } + system("/usr/libexec/cydia/cydo /bin/ln -sf /var/mobile/Library/Caches/com.saurik.Cydia/sources.list /etc/apt/sources.list.d/cydia.list"); + /* APT Initialization {{{ */ _assert(pkgInitConfig(*_config)); _assert(pkgInitSystem(*_config, _system)); - if (lang != NULL) - _config->Set("APT::Acquire::Translation", lang); + _config->Set("Acquire::AllowInsecureRepositories", true); + _config->Set("Acquire::Check-Valid-Until", false); + _config->Set("Dir::Bin::Methods::store", "/Applications/Cydia.app/store"); + + _config->Set("pkgCacheGen::ForceEssential", ""); + + if (translation != NULL) + _config->Set("APT::Acquire::Translation", translation); + _config->Set("Acquire::Languages", languages); // XXX: this timeout might be important :( //_config->Set("Acquire::http::Timeout", 15); + int64_t usermem(0); + size = sizeof(usermem); + if (sysctlbyname("hw.usermem", &usermem, &size, NULL, 0) == -1) + usermem = 0; _config->Set("Acquire::http::MaxParallel", usermem >= 384 * 1024 * 1024 ? 16 : 3); - mkdir([Cache_ UTF8String], 0755); mkdir([Cache("archives") UTF8String], 0755); mkdir([Cache("archives/partial") UTF8String], 0755); _config->Set("Dir::Cache", [Cache_ UTF8String]); + symlink("/var/lib/apt/extended_states", [Cache("extended_states") UTF8String]); + _config->Set("Dir::State", [Cache_ UTF8String]); + mkdir([Cache("lists") UTF8String], 0755); mkdir([Cache("lists/partial") UTF8String], 0755); mkdir([Cache("periodic") UTF8String], 0755); _config->Set("Dir::State::Lists", [Cache("lists") UTF8String]); + + std::string logs("/var/mobile/Library/Logs/Cydia"); + mkdir(logs.c_str(), 0755); + _config->Set("Dir::Log", logs); + + _config->Set("Dir::Bin::dpkg", "/usr/libexec/cydia/cydo"); /* }}} */ /* Color Choices {{{ */ space_ = CGColorSpaceCreateDeviceRGB(); @@ -10582,14 +9541,8 @@ int main(int argc, char *argv[]) { //UIKeyboardDisableAutomaticAppearance(); /* }}} */ - _root({ - chown([Cache("ApplicationCache.db") UTF8String], 501, 501); - chown([Cache("Cache.db") UTF8String], 501, 501); - chown([Cache("Cache.db-shm") UTF8String], 501, 501); - chown([Cache("Cache.db-wal") UTF8String], 501, 501); - }); - $SBSSetInterceptsMenuButtonForever = reinterpret_cast(dlsym(RTLD_DEFAULT, "SBSSetInterceptsMenuButtonForever")); + $SBSCopyIconImagePNGDataForDisplayIdentifier = reinterpret_cast(dlsym(RTLD_DEFAULT, "SBSCopyIconImagePNGDataForDisplayIdentifier")); const char *symbol(kCFCoreFoundationVersionNumber >= 800 ? "MGGetBoolAnswer" : "GSSystemHasCapability"); BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast(dlsym(RTLD_DEFAULT, symbol));