diff options
author | Jay Freeman (saurik) <saurik@saurik.com> | 2010-10-28 02:25:18 -0700 |
---|---|---|
committer | Jay Freeman (saurik) <saurik@saurik.com> | 2010-11-01 22:56:25 -0700 |
commit | e17a8c4f2ae16f8daab460936a9b130d024173dd (patch) | |
tree | 1544816ffb283219f2de45b0a8e99d6f7ebe24f6 /Cydia.mm | |
parent | 6067f1b8116d8fb2502359f430b9d958e10807b9 (diff) |
Rename Cydia.* to MobileCydia.* and add Cydia.frappliance.
Diffstat (limited to 'Cydia.mm')
-rw-r--r-- | Cydia.mm | 9018 |
1 files changed, 0 insertions, 9018 deletions
diff --git a/Cydia.mm b/Cydia.mm deleted file mode 100644 index a9c4ada..0000000 --- a/Cydia.mm +++ /dev/null @@ -1,9018 +0,0 @@ -/* Cydia - iPhone UIKit Front-End for Debian APT - * Copyright (C) 2008-2010 Jay Freeman (saurik) -*/ - -/* Modified BSD License {{{ */ -/* - * Redistribution and use in source and binary - * forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the - * above copyright notice, this list of conditions - * and the following disclaimer. - * 2. Redistributions in binary form must reproduce the - * above copyright notice, this list of conditions - * and the following disclaimer in the documentation - * and/or other materials provided with the - * distribution. - * 3. The name of the author may not be used to endorse - * or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -/* }}} */ - -// XXX: wtf/FastMalloc.h... wtf? -#define USE_SYSTEM_MALLOC 1 - -/* #include Directives {{{ */ -#include "UICaboodle/UCPlatform.h" -#include "UICaboodle/UCLocalize.h" - -#include <objc/objc.h> -#include <objc/runtime.h> - -#include <CoreGraphics/CoreGraphics.h> -#include <Foundation/Foundation.h> - -#if 0 -#define DEPLOYMENT_TARGET_MACOSX 1 -#define CF_BUILDING_CF 1 -#include <CoreFoundation/CFInternal.h> -#endif - -#include <CoreFoundation/CFPriv.h> -#include <CoreFoundation/CFUniChar.h> - -#include <SystemConfiguration/SystemConfiguration.h> - -#include <UIKit/UIKit.h> -#include "iPhonePrivate.h" - -#include <IOKit/IOKitLib.h> - -#include <WebCore/WebCoreThread.h> - -#include <algorithm> -#include <iomanip> -#include <sstream> -#include <string> - -#include <ext/stdio_filebuf.h> - -#undef ABS - -#include <apt-pkg/acquire.h> -#include <apt-pkg/acquire-item.h> -#include <apt-pkg/algorithms.h> -#include <apt-pkg/cachefile.h> -#include <apt-pkg/clean.h> -#include <apt-pkg/configuration.h> -#include <apt-pkg/debindexfile.h> -#include <apt-pkg/debmetaindex.h> -#include <apt-pkg/error.h> -#include <apt-pkg/init.h> -#include <apt-pkg/mmap.h> -#include <apt-pkg/pkgrecords.h> -#include <apt-pkg/sha1.h> -#include <apt-pkg/sourcelist.h> -#include <apt-pkg/sptr.h> -#include <apt-pkg/strutl.h> -#include <apt-pkg/tagfile.h> - -#include <apr-1/apr_pools.h> - -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/sysctl.h> -#include <sys/param.h> -#include <sys/mount.h> - -#include <fcntl.h> -#include <notify.h> -#include <dlfcn.h> - -extern "C" { -#include <mach-o/nlist.h> -} - -#include <cstdio> -#include <cstdlib> -#include <cstring> - -#include <errno.h> -#include <pcre.h> - -#include <ext/hash_map> - -#include "UICaboodle/BrowserView.h" - -#include "substrate.h" -/* }}} */ - -/* Profiler {{{ */ -struct timeval _ltv; -bool _itv; - -#define _timestamp ({ \ - struct timeval tv; \ - gettimeofday(&tv, NULL); \ - tv.tv_sec * 1000000 + tv.tv_usec; \ -}) - -typedef std::vector<class ProfileTime *> TimeList; -TimeList times_; - -class ProfileTime { - private: - const char *name_; - uint64_t total_; - uint64_t count_; - - public: - ProfileTime(const char *name) : - name_(name), - total_(0) - { - times_.push_back(this); - } - - void AddTime(uint64_t time) { - total_ += time; - ++count_; - } - - void Print() { - if (total_ != 0) - std::cerr << std::setw(5) << count_ << ", " << std::setw(7) << total_ << " : " << name_ << std::endl; - total_ = 0; - count_ = 0; - } -}; - -class ProfileTimer { - private: - ProfileTime &time_; - uint64_t start_; - - public: - ProfileTimer(ProfileTime &time) : - time_(time), - start_(_timestamp) - { - } - - ~ProfileTimer() { - time_.AddTime(_timestamp - start_); - } -}; - -void PrintTimes() { - for (TimeList::const_iterator i(times_.begin()); i != times_.end(); ++i) - (*i)->Print(); - std::cerr << "========" << std::endl; -} - -#define _profile(name) { \ - static ProfileTime name(#name); \ - ProfileTimer _ ## name(name); - -#define _end } -/* }}} */ - -#define _pooled _H<NSAutoreleasePool> _pool([[NSAutoreleasePool alloc] init], true); - -static const NSUInteger UIViewAutoresizingFlexibleBoth(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); - -void NSLogPoint(const char *fix, const CGPoint &point) { - NSLog(@"%s(%g,%g)", fix, point.x, point.y); -} - -void NSLogRect(const char *fix, const CGRect &rect) { - NSLog(@"%s(%g,%g)+(%g,%g)", fix, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height); -} - -static _finline NSString *CydiaURL(NSString *path) { - char page[25]; - page[0] = 'h'; page[1] = 't'; page[2] = 't'; page[3] = 'p'; page[4] = ':'; - page[5] = '/'; page[6] = '/'; page[7] = 'c'; page[8] = 'y'; page[9] = 'd'; - page[10] = 'i'; page[11] = 'a'; page[12] = '.'; page[13] = 's'; page[14] = 'a'; - page[15] = 'u'; page[16] = 'r'; page[17] = 'i'; page[18] = 'k'; page[19] = '.'; - page[20] = 'c'; page[21] = 'o'; page[22] = 'm'; page[23] = '/'; page[24] = '\0'; - return [[NSString stringWithUTF8String:page] stringByAppendingString:path]; -} - -static _finline void UpdateExternalStatus(uint64_t newStatus) { - int notify_token; - if (notify_register_check("com.saurik.Cydia.status", ¬ify_token) == NOTIFY_STATUS_OK) { - notify_set_state(notify_token, newStatus); - notify_cancel(notify_token); - } - notify_post("com.saurik.Cydia.status"); -} - -/* [NSObject yieldToSelector:(withObject:)] {{{*/ -@interface NSObject (Cydia) -- (id) yieldToSelector:(SEL)selector withObject:(id)object; -- (id) yieldToSelector:(SEL)selector; -@end - -@implementation NSObject (Cydia) - -- (void) doNothing { -} - -- (void) _yieldToContext:(NSMutableArray *)context { _pooled - SEL selector(reinterpret_cast<SEL>([[context objectAtIndex:0] pointerValue])); - id object([[context objectAtIndex:1] nonretainedObjectValue]); - volatile bool &stopped(*reinterpret_cast<bool *>([[context objectAtIndex:2] pointerValue])); - - /* XXX: deal with exceptions */ - id value([self performSelector:selector withObject:object]); - - NSMethodSignature *signature([self methodSignatureForSelector:selector]); - [context removeAllObjects]; - if ([signature methodReturnLength] != 0 && value != nil) - [context addObject:value]; - - stopped = true; - - [self - performSelectorOnMainThread:@selector(doNothing) - withObject:nil - waitUntilDone:NO - ]; -} - -- (id) yieldToSelector:(SEL)selector withObject:(id)object { - /*return [self performSelector:selector withObject:object];*/ - - volatile bool stopped(false); - - NSMutableArray *context([NSMutableArray arrayWithObjects: - [NSValue valueWithPointer:selector], - [NSValue valueWithNonretainedObject:object], - [NSValue valueWithPointer:const_cast<bool *>(&stopped)], - nil]); - - NSThread *thread([[[NSThread alloc] - initWithTarget:self - selector:@selector(_yieldToContext:) - object:context - ] autorelease]); - - [thread start]; - - NSRunLoop *loop([NSRunLoop currentRunLoop]); - NSDate *future([NSDate distantFuture]); - - while (!stopped && [loop runMode:NSDefaultRunLoopMode beforeDate:future]); - - return [context count] == 0 ? nil : [context objectAtIndex:0]; -} - -- (id) yieldToSelector:(SEL)selector { - return [self yieldToSelector:selector withObject:nil]; -} - -@end -/* }}} */ - -@interface CYActionSheet : UIAlertView { - unsigned button_; -} - -- (int) yieldToPopupAlertAnimated:(BOOL)animated; -@end - -@implementation CYActionSheet - -- (id) initWithTitle:(NSString *)title buttons:(NSArray *)buttons defaultButtonIndex:(int)index { - if ((self = [super init])) { - [self setTitle:title]; - [self setDelegate:self]; - for (NSString *button in buttons) [self addButtonWithTitle:button]; - [self setCancelButtonIndex:index]; - } return self; -} - -- (void) _updateFrameForDisplay { - [super _updateFrameForDisplay]; - if ([self cancelButtonIndex] == -1) { - NSArray *buttons = [self buttons]; - if ([buttons count]) { - UIImage *background = [[buttons objectAtIndex:0] backgroundForState:0]; - for (UIThreePartButton *button in buttons) - [button setBackground:background forState:0]; - } - } -} - -- (void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { - button_ = buttonIndex + 1; -} - -- (void) dismiss { - [self dismissWithClickedButtonIndex:-1 animated:YES]; -} - -- (int) yieldToPopupAlertAnimated:(BOOL)animated { - [self setRunsModal:YES]; - button_ = 0; - [self show]; - return button_; -} - -@end - -/* NSForcedOrderingSearch doesn't work on the iPhone */ -static const NSStringCompareOptions MatchCompareOptions_ = NSLiteralSearch | NSCaseInsensitiveSearch; -static const NSStringCompareOptions LaxCompareOptions_ = NSNumericSearch | NSDiacriticInsensitiveSearch | NSWidthInsensitiveSearch | NSCaseInsensitiveSearch; -static const CFStringCompareFlags LaxCompareFlags_ = kCFCompareCaseInsensitive | kCFCompareNonliteral | kCFCompareLocalized | kCFCompareNumerically | kCFCompareWidthInsensitive | kCFCompareForcedOrdering; - -/* Information Dictionaries {{{ */ -@interface NSMutableArray (Cydia) -- (void) addInfoDictionary:(NSDictionary *)info; -@end - -@implementation NSMutableArray (Cydia) - -- (void) addInfoDictionary:(NSDictionary *)info { - [self addObject:info]; -} - -@end - -@interface NSMutableDictionary (Cydia) -- (void) addInfoDictionary:(NSDictionary *)info; -@end - -@implementation NSMutableDictionary (Cydia) - -- (void) addInfoDictionary:(NSDictionary *)info { - [self setObject:info forKey:[info objectForKey:@"CFBundleIdentifier"]]; -} - -@end -/* }}} */ - -#define lprintf(args...) fprintf(stderr, args) - -#define ForRelease 1 -#define TraceLogging (1 && !ForRelease) -#define HistogramInsertionSort (0 && !ForRelease) -#define ProfileTimes (0 && !ForRelease) -#define ForSaurik (0 && !ForRelease) -#define LogBrowser (0 && !ForRelease) -#define TrackResize (0 && !ForRelease) -#define ManualRefresh (0 && !ForRelease) -#define ShowInternals (0 && !ForRelease) -#define IgnoreInstall (0 && !ForRelease) -#define RecycleWebViews 0 -#define RecyclePackageViews (0 && ForRelease) -#define AlwaysReload (1 && !ForRelease) - -#if !TraceLogging -#undef _trace -#define _trace(args...) -#endif - -#if !ProfileTimes -#undef _profile -#define _profile(name) { -#undef _end -#define _end } -#define PrintTimes() do {} while (false) -#endif - -/* Radix Sort {{{ */ -typedef uint32_t (*SKRadixFunction)(id, void *); - -@interface NSMutableArray (Radix) -- (void) radixSortUsingSelector:(SEL)selector withObject:(id)object; -- (void) radixSortUsingFunction:(SKRadixFunction)function withContext:(void *)argument; -@end - -struct RadixItem_ { - size_t index; - uint32_t key; -}; - -static void RadixSort_(NSMutableArray *self, size_t count, struct RadixItem_ *swap) { - struct RadixItem_ *lhs(swap), *rhs(swap + count); - - static const size_t width = 32; - static const size_t bits = 11; - static const size_t slots = 1 << bits; - static const size_t passes = (width + (bits - 1)) / bits; - - size_t *hist(new size_t[slots]); - - for (size_t pass(0); pass != passes; ++pass) { - memset(hist, 0, sizeof(size_t) * slots); - - for (size_t i(0); i != count; ++i) { - uint32_t key(lhs[i].key); - key >>= pass * bits; - key &= _not(uint32_t) >> width - bits; - ++hist[key]; - } - - size_t offset(0); - for (size_t i(0); i != slots; ++i) { - size_t local(offset); - offset += hist[i]; - hist[i] = local; - } - - for (size_t i(0); i != count; ++i) { - uint32_t key(lhs[i].key); - key >>= pass * bits; - key &= _not(uint32_t) >> width - bits; - rhs[hist[key]++] = lhs[i]; - } - - RadixItem_ *tmp(lhs); - lhs = rhs; - rhs = tmp; - } - - delete [] hist; - - NSMutableArray *values([NSMutableArray arrayWithCapacity:count]); - for (size_t i(0); i != count; ++i) - [values addObject:[self objectAtIndex:lhs[i].index]]; - [self setArray:values]; - - delete [] swap; -} - -@implementation NSMutableArray (Radix) - -- (void) radixSortUsingSelector:(SEL)selector withObject:(id)object { - size_t count([self count]); - if (count == 0) - return; - -#if 0 - NSInvocation *invocation([NSInvocation invocationWithMethodSignature:[NSMethodSignature signatureWithObjCTypes:"L12@0:4@8"]]); - [invocation setSelector:selector]; - [invocation setArgument:&object atIndex:2]; -#else - /* XXX: this is an unsafe optimization of doomy hell */ - Method method(class_getInstanceMethod([[self objectAtIndex:0] class], selector)); - _assert(method != NULL); - uint32_t (*imp)(id, SEL, id) = reinterpret_cast<uint32_t (*)(id, SEL, id)>(method_getImplementation(method)); - _assert(imp != NULL); -#endif - - struct RadixItem_ *swap(new RadixItem_[count * 2]); - - for (size_t i(0); i != count; ++i) { - RadixItem_ &item(swap[i]); - item.index = i; - - id object([self objectAtIndex:i]); - -#if 0 - [invocation setTarget:object]; - [invocation invoke]; - [invocation getReturnValue:&item.key]; -#else - item.key = imp(object, selector, object); -#endif - } - - RadixSort_(self, count, swap); -} - -- (void) radixSortUsingFunction:(SKRadixFunction)function withContext:(void *)argument { - size_t count([self count]); - struct RadixItem_ *swap(new RadixItem_[count * 2]); - - for (size_t i(0); i != count; ++i) { - RadixItem_ &item(swap[i]); - item.index = i; - - id object([self objectAtIndex:i]); - item.key = function(object, argument); - } - - RadixSort_(self, count, swap); -} - -@end -/* }}} */ -/* 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) { - 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; -} - -void CFArrayInsertionSortValues(CFMutableArrayRef array, CFRange range, CFComparatorFunction comparator, void *context) { - if (range.length == 0) - return; - const void **values(new const void *[range.length]); - CFArrayGetValues(array, range, values); - -#if HistogramInsertionSort - uint32_t total(0), *offsets(new uint32_t[range.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); - while (comparator(value, values[correct - 1], context) == kCFCompareLessThan) - if (--correct == 0) - break; - if (correct != index) { - size_t offset(index - correct); -#if HistogramInsertionSort - total += offset; - ++offsets[offset]; - if (offset > 10) - NSLog(@"Heavy Insertion Displacement: %u = %@", offset, value); -#endif - memmove(values + correct + 1, values + correct, sizeof(const void *) * offset); - values[correct] = value; - } - } - - CFArrayReplaceValues(array, range, values, range.length); - delete [] values; - -#if HistogramInsertionSort - for (CFIndex 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); - delete [] offsets; -#endif -} - -/* }}} */ - -/* 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 -/* }}} */ - -@implementation WebScriptObject (NSFastEnumeration) - -- (NSUInteger) countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)objects count:(NSUInteger)count { - size_t length([self count] - state->state); - if (length <= 0) - return 0; - else if (length > count) - length = count; - for (size_t i(0); i != length; ++i) - objects[i] = [self objectAtIndex:state->state++]; - state->itemsPtr = objects; - state->mutationsPtr = (unsigned long *) self; - return length; -} - -@end - -NSUInteger DOMNodeList$countByEnumeratingWithState$objects$count$(DOMNodeList *self, SEL sel, NSFastEnumerationState *state, id *objects, NSUInteger count) { - size_t length([self length] - state->state); - if (length <= 0) - 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) -+ (NSString *) stringWithUTF8BytesNoCopy:(const char *)bytes length:(int)length; -+ (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length withZone:(NSZone *)zone inPool:(apr_pool_t *)pool; -+ (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length; -- (NSComparisonResult) compareByPath:(NSString *)other; -- (NSString *) stringByCachingURLWithCurrentCDN; -- (NSString *) stringByAddingPercentEscapesIncludingReserved; -@end - -@implementation NSString (Cydia) - -+ (NSString *) stringWithUTF8BytesNoCopy:(const char *)bytes length:(int)length { - return [[[NSString alloc] initWithBytesNoCopy:const_cast<char *>(bytes) length:length encoding:NSUTF8StringEncoding freeWhenDone:NO] autorelease]; -} - -+ (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length withZone:(NSZone *)zone inPool:(apr_pool_t *)pool { - char *data(reinterpret_cast<char *>(apr_palloc(pool, length))); - memcpy(data, bytes, length); - return [[[NSString allocWithZone:zone] initWithBytesNoCopy:data length:length encoding:NSUTF8StringEncoding freeWhenDone:NO] autorelease]; -} - -+ (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length { - return [[[NSString alloc] initWithBytes:bytes length:length encoding:NSUTF8StringEncoding] autorelease]; -} - -- (NSComparisonResult) compareByPath:(NSString *)other { - NSString *prefix = [self commonPrefixWithString:other options:0]; - size_t length = [prefix length]; - - NSRange lrange = NSMakeRange(length, [self length] - length); - NSRange rrange = NSMakeRange(length, [other length] - length); - - lrange = [self rangeOfString:@"/" options:0 range:lrange]; - rrange = [other rangeOfString:@"/" options:0 range:rrange]; - - NSComparisonResult value; - - if (lrange.location == NSNotFound && rrange.location == NSNotFound) - value = NSOrderedSame; - else if (lrange.location == NSNotFound) - value = NSOrderedAscending; - else if (rrange.location == NSNotFound) - value = NSOrderedDescending; - else - value = NSOrderedSame; - - NSString *lpath = lrange.location == NSNotFound ? [self substringFromIndex:length] : - [self substringWithRange:NSMakeRange(length, lrange.location - length)]; - NSString *rpath = rrange.location == NSNotFound ? [other substringFromIndex:length] : - [other substringWithRange:NSMakeRange(length, rrange.location - length)]; - - NSComparisonResult result = [lpath compare:rpath]; - return result == NSOrderedSame ? value : result; -} - -- (NSString *) stringByCachingURLWithCurrentCDN { - return [self - stringByReplacingOccurrencesOfString:@"://cydia.saurik.com/" - withString:@"://cache.cydia.saurik.com/" - ]; -} - -- (NSString *) stringByAddingPercentEscapesIncludingReserved { - return [(id)CFURLCreateStringByAddingPercentEscapes( - kCFAllocatorDefault, - (CFStringRef) self, - NULL, - CFSTR(";/?:@&=+$,"), - kCFStringEncodingUTF8 - ) autorelease]; -} - -@end -/* }}} */ - -/* C++ NSString Wrapper Cache {{{ */ -class CYString { - private: - char *data_; - size_t size_; - CFStringRef cache_; - - _finline void clear_() { - if (cache_ != NULL) { - CFRelease(cache_); - cache_ = NULL; - } - } - - public: - _finline bool empty() const { - return size_ == 0; - } - - _finline size_t size() const { - return size_; - } - - _finline char *data() const { - return data_; - } - - _finline void clear() { - size_ = 0; - clear_(); - } - - _finline CYString() : - data_(0), - size_(0), - cache_(NULL) - { - } - - _finline ~CYString() { - clear_(); - } - - void operator =(const CYString &rhs) { - data_ = rhs.data_; - size_ = rhs.size_; - - if (rhs.cache_ == nil) - cache_ = NULL; - else - cache_ = reinterpret_cast<CFStringRef>(CFRetain(rhs.cache_)); - } - - void set(apr_pool_t *pool, const char *data, size_t size) { - if (size == 0) - clear(); - else { - clear_(); - - char *temp(reinterpret_cast<char *>(apr_palloc(pool, size + 1))); - memcpy(temp, data, size); - temp[size] = '\0'; - data_ = temp; - size_ = size; - } - } - - _finline void set(apr_pool_t *pool, const char *data) { - set(pool, data, data == NULL ? 0 : strlen(data)); - } - - _finline void set(apr_pool_t *pool, const std::string &rhs) { - set(pool, rhs.data(), rhs.size()); - } - - bool operator ==(const CYString &rhs) const { - return size_ == rhs.size_ && memcmp(data_, rhs.data_, size_) == 0; - } - - operator CFStringRef() { - if (cache_ == NULL) { - if (size_ == 0) - return nil; - cache_ = CFStringCreateWithBytesNoCopy(kCFAllocatorDefault, reinterpret_cast<uint8_t *>(data_), size_, kCFStringEncodingUTF8, NO, kCFAllocatorNull); - if (cache_ == NULL) - cache_ = CFStringCreateWithBytesNoCopy(kCFAllocatorDefault, reinterpret_cast<uint8_t *>(data_), size_, kCFStringEncodingISOLatin1, NO, kCFAllocatorNull); - } return cache_; - } - - _finline operator id() { - return (NSString *) static_cast<CFStringRef>(*this); - } -}; -/* }}} */ -/* C++ NSString Algorithm Adapters {{{ */ -extern "C" { - CF_EXPORT CFHashCode CFStringHashNSString(CFStringRef str); -} - -struct NSStringMapHash : - std::unary_function<NSString *, size_t> -{ - _finline size_t operator ()(NSString *value) const { - return CFStringHashNSString((CFStringRef) value); - } -}; - -struct NSStringMapLess : - std::binary_function<NSString *, NSString *, bool> -{ - _finline bool operator ()(NSString *lhs, NSString *rhs) const { - return [lhs compare:rhs] == NSOrderedAscending; - } -}; - -struct NSStringMapEqual : - std::binary_function<NSString *, NSString *, bool> -{ - _finline bool operator ()(NSString *lhs, NSString *rhs) const { - return CFStringCompare((CFStringRef) lhs, (CFStringRef) rhs, 0) == kCFCompareEqualTo; - //CFEqual((CFTypeRef) lhs, (CFTypeRef) rhs); - //[lhs isEqualToString:rhs]; - } -}; -/* }}} */ - -/* Perl-Compatible RegEx {{{ */ -class Pcre { - private: - pcre *code_; - pcre_extra *study_; - int capture_; - int *matches_; - const char *data_; - - public: - Pcre(const char *regex) : - study_(NULL) - { - const char *error; - int offset; - code_ = pcre_compile(regex, 0, &error, &offset, NULL); - - if (code_ == NULL) { - lprintf("%d:%s\n", offset, error); - _assert(false); - } - - pcre_fullinfo(code_, study_, PCRE_INFO_CAPTURECOUNT, &capture_); - matches_ = new int[(capture_ + 1) * 3]; - } - - ~Pcre() { - pcre_free(code_); - delete matches_; - } - - NSString *operator [](size_t match) { - return [NSString stringWithUTF8Bytes:(data_ + matches_[match * 2]) length:(matches_[match * 2 + 1] - matches_[match * 2])]; - } - - bool operator ()(NSString *data) { - // XXX: length is for characters, not for bytes - return operator ()([data UTF8String], [data length]); - } - - bool operator ()(const char *data, size_t size) { - data_ = data; - return pcre_exec(code_, study_, data, size, 0, 0, matches_, (capture_ + 1) * 3) >= 0; - } -}; -/* }}} */ -/* Mime Addresses {{{ */ -@interface Address : NSObject { - NSString *name_; - NSString *address_; -} - -- (NSString *) name; -- (NSString *) address; - -- (void) setAddress:(NSString *)address; - -+ (Address *) addressWithString:(NSString *)string; -- (Address *) initWithString:(NSString *)string; -@end - -@implementation Address - -- (void) dealloc { - [name_ release]; - if (address_ != nil) - [address_ release]; - [super dealloc]; -} - -- (NSString *) name { - return name_; -} - -- (NSString *) address { - return address_; -} - -- (void) setAddress:(NSString *)address { - if (address_ != nil) - [address_ autorelease]; - if (address == nil) - address_ = nil; - else - address_ = [address retain]; -} - -+ (Address *) addressWithString:(NSString *)string { - return [[[Address alloc] initWithString:string] autorelease]; -} - -+ (NSArray *) _attributeKeys { - return [NSArray arrayWithObjects:@"address", @"name", nil]; -} - -- (NSArray *) attributeKeys { - return [[self class] _attributeKeys]; -} - -+ (BOOL) isKeyExcludedFromWebScript:(const char *)name { - return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name]; -} - -- (Address *) initWithString:(NSString *)string { - if ((self = [super init]) != nil) { - const char *data = [string UTF8String]; - size_t size = [string length]; - - static Pcre address_r("^\"?(.*)\"? <([^>]*)>$"); - - if (address_r(data, size)) { - name_ = [address_r[1] retain]; - address_ = [address_r[2] retain]; - } else { - name_ = [string retain]; - address_ = nil; - } - } return self; -} - -@end -/* }}} */ -/* CoreGraphics Primitives {{{ */ -class CYColor { - private: - CGColorRef color_; - - public: - CYColor() : - color_(NULL) - { - } - - CYColor(CGColorSpaceRef space, float red, float green, float blue, float alpha) : - color_(NULL) - { - Set(space, red, green, blue, alpha); - } - - void Clear() { - if (color_ != NULL) - CGColorRelease(color_); - } - - ~CYColor() { - Clear(); - } - - void Set(CGColorSpaceRef space, float red, float green, float blue, float alpha) { - Clear(); - float color[] = {red, green, blue, alpha}; - color_ = CGColorCreate(space, (CGFloat *) color); - } - - operator CGColorRef() { - return color_; - } -}; -/* }}} */ - -/* Random Global Variables {{{ */ -static const int PulseInterval_ = 50000; -static const int ButtonBarWidth_ = 60; -static const int ButtonBarHeight_ = 48; -static const float KeyboardTime_ = 0.3f; - -static int Finish_; -static NSArray *Finishes_; - -#define SpringBoard_ "/System/Library/LaunchDaemons/com.apple.SpringBoard.plist" -#define NotifyConfig_ "/etc/notify.conf" - -static bool Queuing_; - -static CYColor Blue_; -static CYColor Blueish_; -static CYColor Black_; -static CYColor Off_; -static CYColor White_; -static CYColor Gray_; -static CYColor Green_; -static CYColor Purple_; -static CYColor Purplish_; - -static UIColor *InstallingColor_; -static UIColor *RemovingColor_; - -static NSString *App_; -static NSString *Home_; - -static BOOL Advanced_; -static BOOL Ignored_; - -static UIFont *Font12_; -static UIFont *Font12Bold_; -static UIFont *Font14_; -static UIFont *Font18Bold_; -static UIFont *Font22Bold_; - -static const char *Machine_ = NULL; -static NSString *System_ = nil; -static NSString *SerialNumber_ = nil; -static NSString *ChipID_ = nil; -static NSString *Token_ = nil; -static NSString *UniqueID_ = nil; -static NSString *Build_ = nil; -static NSString *Product_ = nil; -static NSString *Safari_ = nil; - -static CFLocaleRef Locale_; -static NSArray *Languages_; -static CGColorSpaceRef space_; - -static NSDictionary *SectionMap_; -static NSMutableDictionary *Metadata_; -static _transient NSMutableDictionary *Settings_; -static _transient NSString *Role_; -static _transient NSMutableDictionary *Packages_; -static _transient NSMutableDictionary *Sections_; -static _transient NSMutableDictionary *Sources_; -static bool Changed_; -static NSDate *now_; - -static bool IsWildcat_; - -#if RecycleWebViews -static NSMutableArray *Documents_; -#endif -/* }}} */ - -/* Display Helpers {{{ */ -inline float Interpolate(float begin, float end, float fraction) { - return (end - begin) * fraction + begin; -} - -/* XXX: localize this! */ -NSString *SizeString(double size) { - bool negative = size < 0; - if (negative) - size = -size; - - unsigned power = 0; - while (size > 1024) { - size /= 1024; - ++power; - } - - static const char *powers_[] = {"B", "kB", "MB", "GB"}; - - return [NSString stringWithFormat:@"%s%.1f %s", (negative ? "-" : ""), size, powers_[power]]; -} - -static _finline CFStringRef CFCString(const char *value) { - return CFStringCreateWithBytesNoCopy(kCFAllocatorDefault, reinterpret_cast<const uint8_t *>(value), strlen(value), kCFStringEncodingUTF8, NO, kCFAllocatorNull); -} - -const char *StripVersion_(const char *version) { - const char *colon(strchr(version, ':')); - if (colon != NULL) - version = colon + 1; - return version; -} - -CFStringRef StripVersion(const char *version) { - const char *colon(strchr(version, ':')); - if (colon != NULL) - version = colon + 1; - return CFStringCreateWithBytes(kCFAllocatorDefault, reinterpret_cast<const uint8_t *>(version), strlen(version), kCFStringEncodingUTF8, NO); - // XXX: performance - return CFCString(version); -} - -NSString *LocalizeSection(NSString *section) { - static Pcre title_r("^(.*?) \\((.*)\\)$"); - if (title_r(section)) { - NSString *parent(title_r[1]); - NSString *child(title_r[2]); - - return [NSString stringWithFormat:UCLocalize("PARENTHETICAL"), - LocalizeSection(parent), - LocalizeSection(child) - ]; - } - - return [[NSBundle mainBundle] localizedStringForKey:section value:nil table:@"Sections"]; -} - -NSString *Simplify(NSString *title) { - const char *data = [title UTF8String]; - size_t size = [title length]; - - static Pcre square_r("^\\[(.*)\\]$"); - if (square_r(data, size)) - return Simplify(square_r[1]); - - static Pcre paren_r("^\\((.*)\\)$"); - if (paren_r(data, size)) - return Simplify(paren_r[1]); - - static Pcre title_r("^(.*?) \\((.*)\\)$"); - if (title_r(data, size)) - return Simplify(title_r[1]); - - return 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]; -} - -@class Cydia; - -/* Delegate Prototypes {{{ */ -@class Package; -@class Source; - -@interface NSObject (ProgressDelegate) -@end - -@protocol ProgressDelegate -- (void) setProgressError:(NSString *)error withTitle:(NSString *)id; -- (void) setProgressTitle:(NSString *)title; -- (void) setProgressPercent:(float)percent; -- (void) startProgress; -- (void) addProgressOutput:(NSString *)output; -- (bool) isCancelling:(size_t)received; -@end - -@protocol ConfigurationDelegate -- (void) repairWithSelector:(SEL)selector; -- (void) setConfigurationData:(NSString *)data; -@end - -@class PackageController; - -@protocol CydiaDelegate -- (void) setPackageController:(PackageController *)view; -- (void) clearPackage:(Package *)package; -- (void) installPackage:(Package *)package; -- (void) installPackages:(NSArray *)packages; -- (void) removePackage:(Package *)package; -- (void) beginUpdate; -- (BOOL) updating; -- (void) distUpgrade; -- (void) loadData; -- (void) updateData; -- (void) syncData; -- (void) showSettings; -- (UIProgressHUD *) addProgressHUD; -- (void) removeProgressHUD:(UIProgressHUD *)hud; -- (CYViewController *) pageForPackage:(NSString *)name; -- (PackageController *) packageController; -- (void) showActionSheet:(UIActionSheet *)sheet fromItem:(UIBarButtonItem *)item; -@end -/* }}} */ - -/* Status Delegation {{{ */ -class Status : - public pkgAcquireStatus -{ - private: - _transient NSObject<ProgressDelegate> *delegate_; - - public: - Status() : - delegate_(nil) - { - } - - void setDelegate(id delegate) { - delegate_ = delegate; - } - - NSObject<ProgressDelegate> *getDelegate() const { - return delegate_; - } - - virtual bool MediaChange(std::string media, std::string drive) { - return false; - } - - virtual void IMSHit(pkgAcquire::ItemDesc &item) { - } - - virtual void Fetch(pkgAcquire::ItemDesc &item) { - //NSString *name([NSString stringWithUTF8String:item.ShortDesc.c_str()]); - [delegate_ setProgressTitle:[NSString stringWithFormat:UCLocalize("DOWNLOADING_"), [NSString stringWithUTF8String:item.ShortDesc.c_str()]]]; - } - - virtual void Done(pkgAcquire::ItemDesc &item) { - } - - virtual void Fail(pkgAcquire::ItemDesc &item) { - if ( - item.Owner->Status == pkgAcquire::Item::StatIdle || - item.Owner->Status == pkgAcquire::Item::StatDone - ) - return; - - std::string &error(item.Owner->ErrorText); - if (error.empty()) - return; - - NSString *description([NSString stringWithUTF8String:item.Description.c_str()]); - NSArray *fields([description componentsSeparatedByString:@" "]); - NSString *source([fields count] == 0 ? nil : [fields objectAtIndex:0]); - - [delegate_ performSelectorOnMainThread:@selector(_setProgressErrorPackage:) - withObject:[NSArray arrayWithObjects: - [NSString stringWithUTF8String:error.c_str()], - source, - nil] - waitUntilDone:YES - ]; - } - - virtual bool Pulse(pkgAcquire *Owner) { - bool value = pkgAcquireStatus::Pulse(Owner); - - float percent( - double(CurrentBytes + CurrentItems) / - double(TotalBytes + TotalItems) - ); - - [delegate_ setProgressPercent:percent]; - return [delegate_ isCancelling:CurrentBytes] ? false : value; - } - - virtual void Start() { - [delegate_ startProgress]; - } - - virtual void Stop() { - } -}; -/* }}} */ -/* Progress Delegation {{{ */ -class Progress : - public OpProgress -{ - private: - _transient id<ProgressDelegate> delegate_; - float percent_; - - protected: - virtual void Update() { - /*if (abs(Percent - percent_) > 2) - //NSLog(@"%s:%s:%f", Op.c_str(), SubOp.c_str(), Percent); - percent_ = Percent; - }*/ - - /*[delegate_ setProgressTitle:[NSString stringWithUTF8String:Op.c_str()]]; - [delegate_ setProgressPercent:(Percent / 100)];*/ - } - - public: - Progress() : - delegate_(nil), - percent_(0) - { - } - - void setDelegate(id delegate) { - delegate_ = delegate; - } - - id getDelegate() const { - return delegate_; - } - - virtual void Done() { - //NSLog(@"DONE"); - //[delegate_ setProgressPercent:1]; - } -}; -/* }}} */ - -/* Database Interface {{{ */ -typedef std::map< unsigned long, _H<Source> > SourceMap; - -@interface Database : NSObject { - NSZone *zone_; - apr_pool_t *pool_; - - unsigned era_; - - pkgCacheFile cache_; - pkgDepCache::Policy *policy_; - pkgRecords *records_; - pkgProblemResolver *resolver_; - pkgAcquire *fetcher_; - FileFd *lock_; - SPtr<pkgPackageManager> manager_; - pkgSourceList *list_; - - SourceMap sources_; - NSMutableArray *packages_; - - _transient NSObject<ConfigurationDelegate, ProgressDelegate> *delegate_; - Status status_; - Progress progress_; - - int cydiafd_; - int statusfd_; - FILE *input_; -} - -+ (Database *) sharedInstance; -- (unsigned) era; - -- (void) _readCydia:(NSNumber *)fd; -- (void) _readStatus:(NSNumber *)fd; -- (void) _readOutput:(NSNumber *)fd; - -- (FILE *) input; - -- (Package *) packageWithName:(NSString *)name; - -- (pkgCacheFile &) cache; -- (pkgDepCache::Policy *) policy; -- (pkgRecords *) records; -- (pkgProblemResolver *) resolver; -- (pkgAcquire &) fetcher; -- (pkgSourceList &) list; -- (NSArray *) packages; -- (NSArray *) sources; -- (void) reloadData; - -- (void) configure; -- (bool) prepare; -- (void) perform; -- (bool) upgrade; -- (void) update; - -- (void) setVisible; - -- (void) updateWithStatus:(Status &)status; - -- (void) setDelegate:(id)delegate; -- (Source *) getSource:(pkgCache::PkgFileIterator)file; -@end -/* }}} */ -/* Delegate Helpers {{{ */ -@implementation NSObject (ProgressDelegate) - -- (void) _setProgressErrorPackage:(NSArray *)args { - [self performSelector:@selector(setProgressError:forPackage:) - withObject:[args objectAtIndex:0] - withObject:([args count] == 1 ? nil : [args objectAtIndex:1]) - ]; -} - -- (void) _setProgressErrorTitle:(NSArray *)args { - [self performSelector:@selector(setProgressError:withTitle:) - withObject:[args objectAtIndex:0] - withObject:([args count] == 1 ? nil : [args objectAtIndex:1]) - ]; -} - -- (void) _setProgressError:(NSString *)error withTitle:(NSString *)title { - [self performSelectorOnMainThread:@selector(_setProgressErrorTitle:) - withObject:[NSArray arrayWithObjects:error, title, nil] - waitUntilDone:YES - ]; -} - -- (void) setProgressError:(NSString *)error forPackage:(NSString *)id { - Package *package = id == nil ? nil : [[Database sharedInstance] packageWithName:id]; - - [self performSelector:@selector(setProgressError:withTitle:) - withObject:error - withObject:(package == nil ? id : [package name]) - ]; -} - -@end -/* }}} */ - -/* Source Class {{{ */ -@interface Source : NSObject { - CYString depiction_; - CYString description_; - CYString label_; - CYString origin_; - CYString support_; - - CYString uri_; - CYString distribution_; - CYString type_; - CYString version_; - - NSString *host_; - NSString *authority_; - - CYString defaultIcon_; - - NSDictionary *record_; - BOOL trusted_; -} - -- (Source *) initWithMetaIndex:(metaIndex *)index inPool:(apr_pool_t *)pool; - -- (NSComparisonResult) compareByNameAndType:(Source *)source; - -- (NSString *) depictionForPackage:(NSString *)package; -- (NSString *) supportForPackage:(NSString *)package; - -- (NSDictionary *) record; -- (BOOL) trusted; - -- (NSString *) uri; -- (NSString *) distribution; -- (NSString *) type; -- (NSString *) key; -- (NSString *) host; - -- (NSString *) name; -- (NSString *) description; -- (NSString *) label; -- (NSString *) origin; -- (NSString *) version; - -- (NSString *) defaultIcon; - -@end - -@implementation Source - -- (void) _clear { - uri_.clear(); - distribution_.clear(); - type_.clear(); - - description_.clear(); - label_.clear(); - origin_.clear(); - depiction_.clear(); - support_.clear(); - version_.clear(); - defaultIcon_.clear(); - - if (record_ != nil) { - [record_ release]; - record_ = nil; - } - - if (host_ != nil) { - [host_ release]; - host_ = nil; - } - - if (authority_ != nil) { - [authority_ release]; - authority_ = nil; - } -} - -- (void) dealloc { - [self _clear]; - [super dealloc]; -} - -+ (NSArray *) _attributeKeys { - return [NSArray arrayWithObjects:@"description", @"distribution", @"host", @"key", @"label", @"name", @"origin", @"trusted", @"type", @"uri", @"version", nil]; -} - -- (NSArray *) attributeKeys { - return [[self class] _attributeKeys]; -} - -+ (BOOL) isKeyExcludedFromWebScript:(const char *)name { - return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name]; -} - -- (void) setMetaIndex:(metaIndex *)index inPool:(apr_pool_t *)pool { - [self _clear]; - - trusted_ = index->IsTrusted(); - - uri_.set(pool, index->GetURI()); - distribution_.set(pool, index->GetDist()); - type_.set(pool, index->GetType()); - - debReleaseIndex *dindex(dynamic_cast<debReleaseIndex *>(index)); - if (dindex != NULL) { - FileFd fd; - if (!fd.Open(dindex->MetaIndexFile("Release"), FileFd::ReadOnly)) - _error->Discard(); - else { - pkgTagFile tags(&fd); - - pkgTagSection section; - tags.Step(section); - - struct { - const char *name_; - CYString *value_; - } names[] = { - {"default-icon", &defaultIcon_}, - {"depiction", &depiction_}, - {"description", &description_}, - {"label", &label_}, - {"origin", &origin_}, - {"support", &support_}, - {"version", &version_}, - }; - - for (size_t i(0); i != sizeof(names) / sizeof(names[0]); ++i) { - const char *start, *end; - - if (section.Find(names[i].name_, start, end)) { - CYString &value(*names[i].value_); - value.set(pool, start, end - start); - } - } - } - } - - record_ = [Sources_ objectForKey:[self key]]; - if (record_ != nil) - record_ = [record_ retain]; - - NSURL *url([NSURL URLWithString:uri_]); - - host_ = [url host]; - if (host_ != nil) - host_ = [[host_ lowercaseString] retain]; - - if (host_ != nil) - authority_ = host_; - else - authority_ = [url path]; - - if (authority_ != nil) - authority_ = [authority_ retain]; -} - -- (Source *) initWithMetaIndex:(metaIndex *)index inPool:(apr_pool_t *)pool { - if ((self = [super init]) != nil) { - [self setMetaIndex:index inPool:pool]; - } return self; -} - -- (NSComparisonResult) compareByNameAndType:(Source *)source { - NSDictionary *lhr = [self record]; - NSDictionary *rhr = [source record]; - - if (lhr != rhr) - return lhr == nil ? NSOrderedDescending : NSOrderedAscending; - - NSString *lhs = [self name]; - NSString *rhs = [source name]; - - if ([lhs length] != 0 && [rhs length] != 0) { - unichar lhc = [lhs characterAtIndex:0]; - unichar rhc = [rhs characterAtIndex:0]; - - if (isalpha(lhc) && !isalpha(rhc)) - return NSOrderedAscending; - else if (!isalpha(lhc) && isalpha(rhc)) - return NSOrderedDescending; - } - - return [lhs compare:rhs options:LaxCompareOptions_]; -} - -- (NSString *) depictionForPackage:(NSString *)package { - return depiction_.empty() ? nil : [static_cast<id>(depiction_) stringByReplacingOccurrencesOfString:@"*" withString:package]; -} - -- (NSString *) supportForPackage:(NSString *)package { - return support_.empty() ? nil : [static_cast<id>(support_) stringByReplacingOccurrencesOfString:@"*" withString:package]; -} - -- (NSDictionary *) record { - return record_; -} - -- (BOOL) trusted { - return trusted_; -} - -- (NSString *) uri { - return uri_; -} - -- (NSString *) distribution { - return distribution_; -} - -- (NSString *) type { - return type_; -} - -- (NSString *) key { - return [NSString stringWithFormat:@"%@:%@:%@", (NSString *) type_, (NSString *) uri_, (NSString *) distribution_]; -} - -- (NSString *) host { - return host_; -} - -- (NSString *) name { - return origin_.empty() ? authority_ : origin_; -} - -- (NSString *) description { - return description_; -} - -- (NSString *) label { - return label_.empty() ? authority_ : label_; -} - -- (NSString *) origin { - return origin_; -} - -- (NSString *) version { - return version_; -} - -- (NSString *) defaultIcon { - return defaultIcon_; -} - -@end -/* }}} */ -/* Relationship Class {{{ */ -@interface Relationship : NSObject { - NSString *type_; - NSString *id_; -} - -- (NSString *) type; -- (NSString *) id; -- (NSString *) name; - -@end - -@implementation Relationship - -- (void) dealloc { - [type_ release]; - [id_ release]; - [super dealloc]; -} - -- (NSString *) type { - return type_; -} - -- (NSString *) id { - return id_; -} - -- (NSString *) name { - _assert(false); - return nil; -} - -@end -/* }}} */ -/* Package Class {{{ */ -@interface Package : NSObject { - unsigned era_; - apr_pool_t *pool_; - - pkgCache::VerIterator version_; - pkgCache::PkgIterator iterator_; - _transient Database *database_; - pkgCache::VerFileIterator file_; - - Source *source_; - bool cached_; - bool parsed_; - - CYString section_; - NSString *section$_; - bool essential_; - bool required_; - bool visible_; - bool obsolete_; - - NSString *latest_; - CYString installed_; - - CYString id_; - CYString name_; - CYString tagline_; - CYString icon_; - CYString depiction_; - CYString homepage_; - - CYString sponsor_; - Address *sponsor$_; - - CYString author_; - Address *author$_; - - CYString bugs_; - CYString support_; - NSMutableArray *tags_; - NSString *role_; - - NSArray *relationships_; - - NSMutableDictionary *metadata_; - _transient NSDate *firstSeen_; - _transient NSDate *lastSeen_; - bool subscribed_; -} - -- (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; - -- (pkgCache::PkgIterator) iterator; -- (void) parse; - -- (NSString *) section; -- (NSString *) simpleSection; - -- (NSString *) longSection; -- (NSString *) shortSection; - -- (NSString *) uri; - -- (Address *) maintainer; -- (size_t) size; -- (NSString *) longDescription; -- (NSString *) shortDescription; -- (unichar) index; - -- (NSMutableDictionary *) metadata; -- (NSDate *) seen; -- (BOOL) subscribed; -- (BOOL) ignored; - -- (NSString *) latest; -- (NSString *) installed; -- (BOOL) uninstalled; - -- (BOOL) valid; -- (BOOL) upgradableAndEssential:(BOOL)essential; -- (BOOL) essential; -- (BOOL) broken; -- (BOOL) unfiltered; -- (BOOL) visible; - -- (BOOL) half; -- (BOOL) halfConfigured; -- (BOOL) halfInstalled; -- (BOOL) hasMode; -- (NSString *) mode; - -- (void) setVisible; - -- (NSString *) id; -- (NSString *) name; -- (UIImage *) icon; -- (NSString *) homepage; -- (NSString *) depiction; -- (Address *) author; - -- (NSString *) support; - -- (NSArray *) files; -- (NSArray *) relationships; -- (NSArray *) warnings; -- (NSArray *) applications; - -- (Source *) source; -- (NSString *) role; - -- (BOOL) matches:(NSString *)text; - -- (bool) hasSupportingRole; -- (BOOL) hasTag:(NSString *)tag; -- (NSString *) primaryPurpose; -- (NSArray *) purposes; -- (bool) isCommercial; - -- (CYString &) cyname; - -- (uint32_t) compareBySection:(NSArray *)sections; - -- (uint32_t) compareForChanges; - -- (void) install; -- (void) remove; - -- (bool) isUnfilteredAndSearchedForBy:(NSString *)search; -- (bool) isUnfilteredAndSelectedForBy:(NSString *)search; -- (bool) isInstalledAndVisible:(NSNumber *)number; -- (bool) isVisibleInSection:(NSString *)section; -- (bool) isVisibleInSource:(Source *)source; - -@end - -uint32_t PackageChangesRadix(Package *self, void *) { - union { - uint32_t key; - - struct { - uint32_t timestamp : 30; - uint32_t ignored : 1; - uint32_t upgradable : 1; - } bits; - } value; - - bool upgradable([self upgradableAndEssential:YES]); - value.bits.upgradable = upgradable ? 1 : 0; - - if (upgradable) { - value.bits.timestamp = 0; - value.bits.ignored = [self ignored] ? 0 : 1; - value.bits.upgradable = 1; - } else { - value.bits.timestamp = static_cast<uint32_t>([[self seen] timeIntervalSince1970]) >> 2; - value.bits.ignored = 0; - value.bits.upgradable = 0; - } - - return _not(uint32_t) - value.key; -} - -_finline static void Stifle(uint8_t &value) { -} - -uint32_t PackagePrefixRadix(Package *self, void *context) { - size_t offset(reinterpret_cast<size_t>(context)); - CYString &name([self cyname]); - - size_t size(name.size()); - if (size == 0) - return 0; - char *text(name.data()); - - size_t zeros; - if (!isdigit(text[0])) - zeros = 0; - else { - size_t digits(1); - while (size != digits && isdigit(text[digits])) - if (++digits == 4) - break; - zeros = 4 - digits; - } - - uint8_t data[4]; - - // 0.607997 - - if (offset == 0 && zeros != 0) { - memset(data, '0', zeros); - memcpy(data + zeros, text, 4 - zeros); - } else { - /* XXX: there's some danger here if you request a non-zero offset < 4 and it gets zero padded */ - if (size <= offset - zeros) - return 0; - - text += offset - zeros; - size -= offset - zeros; - - if (size >= 4) - memcpy(data, text, 4); - else { - memcpy(data, text, size); - memset(data + size, 0, 4 - size); - } - - for (size_t i(0); i != 4; ++i) - if (isalpha(data[i])) - data[i] &= 0xdf; - } - - if (offset == 0) - data[0] = (data[0] & 0x3f) | "\x80\x00\xc0\x40"[data[0] >> 6]; - - /* XXX: ntohl may be more honest */ - return OSSwapInt32(*reinterpret_cast<uint32_t *>(data)); -} - -CYString &(*PackageName)(Package *self, SEL sel); - -CFComparisonResult PackageNameCompare(Package *lhs, Package *rhs, void *arg) { - _profile(PackageNameCompare) - CYString &lhi(PackageName(lhs, @selector(cyname))); - CYString &rhi(PackageName(rhs, @selector(cyname))); - CFStringRef lhn(lhi), rhn(rhi); - - if (lhn == NULL) - return rhn == NULL ? NSOrderedSame : NSOrderedAscending; - else if (rhn == NULL) - return NSOrderedDescending; - - _profile(PackageNameCompare$NumbersLast) - if (!lhi.empty() && !rhi.empty()) { - UniChar lhc(CFStringGetCharacterAtIndex(lhn, 0)); - UniChar rhc(CFStringGetCharacterAtIndex(rhn, 0)); - bool lha(CFUniCharIsMemberOf(lhc, kCFUniCharLetterCharacterSet)); - if (lha != CFUniCharIsMemberOf(rhc, kCFUniCharLetterCharacterSet)) - return lha ? NSOrderedAscending : NSOrderedDescending; - } - _end - - CFIndex length = CFStringGetLength(lhn); - - _profile(PackageNameCompare$Compare) - return CFStringCompareWithOptionsAndLocale(lhn, rhn, CFRangeMake(0, length), LaxCompareFlags_, Locale_); - _end - _end -} - -CFComparisonResult PackageNameCompare_(Package **lhs, Package **rhs, void *context) { - return PackageNameCompare(*lhs, *rhs, context); -} - -struct PackageNameOrdering : - std::binary_function<Package *, Package *, bool> -{ - _finline bool operator ()(Package *lhs, Package *rhs) const { - return PackageNameCompare(lhs, rhs, NULL) == NSOrderedAscending; - } -}; - -@implementation Package - -- (NSString *) description { - return [NSString stringWithFormat:@"<Package:%@>", static_cast<NSString *>(name_)]; -} - -- (void) dealloc { - if (source_ != nil) - [source_ release]; - if (section$_ != nil) - [section$_ release]; - - if (latest_ != nil) - [latest_ release]; - - if (sponsor$_ != nil) - [sponsor$_ release]; - if (author$_ != nil) - [author$_ release]; - if (tags_ != nil) - [tags_ release]; - if (role_ != nil) - [role_ release]; - - if (relationships_ != nil) - [relationships_ release]; - if (metadata_ != nil) - [metadata_ release]; - - [super dealloc]; -} - -+ (NSString *) webScriptNameForSelector:(SEL)selector { - if (selector == @selector(hasTag:)) - return @"hasTag"; - else - return nil; -} - -+ (BOOL) isSelectorExcludedFromWebScript:(SEL)selector { - return [self webScriptNameForSelector:selector] == nil; -} - -+ (NSArray *) _attributeKeys { - return [NSArray arrayWithObjects:@"applications", @"author", @"depiction", @"longDescription", @"essential", @"homepage", @"icon", @"id", @"installed", @"latest", @"longSection", @"maintainer", @"mode", @"name", @"purposes", @"section", @"shortDescription", @"shortSection", @"simpleSection", @"size", @"source", @"sponsor", @"support", @"warnings", nil]; -} - -- (NSArray *) attributeKeys { - return [[self class] _attributeKeys]; -} - -+ (BOOL) isKeyExcludedFromWebScript:(const char *)name { - return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name]; -} - -- (void) parse { - if (parsed_) - return; - parsed_ = true; - if (file_.end()) - return; - - _profile(Package$parse) - pkgRecords::Parser *parser; - - _profile(Package$parse$Lookup) - parser = &[database_ records]->Lookup(file_); - _end - - CYString website; - - _profile(Package$parse$Find) - struct { - const char *name_; - CYString *value_; - } names[] = { - {"icon", &icon_}, - {"depiction", &depiction_}, - {"homepage", &homepage_}, - {"website", &website}, - {"bugs", &bugs_}, - {"support", &support_}, - {"sponsor", &sponsor_}, - {"author", &author_}, - }; - - for (size_t i(0); i != sizeof(names) / sizeof(names[0]); ++i) { - const char *start, *end; - - if (parser->Find(names[i].name_, start, end)) { - CYString &value(*names[i].value_); - _profile(Package$parse$Value) - value.set(pool_, start, end - start); - _end - } - } - _end - - _profile(Package$parse$Tagline) - const char *start, *end; - if (parser->ShortDesc(start, end)) { - const char *stop(reinterpret_cast<const char *>(memchr(start, '\n', end - start))); - if (stop == NULL) - stop = end; - while (stop != start && stop[-1] == '\r') - --stop; - tagline_.set(pool_, start, stop - start); - } - _end - - _profile(Package$parse$Retain) - if (homepage_.empty()) - homepage_ = website; - if (homepage_ == depiction_) - homepage_.clear(); - _end - _end -} - -- (void) setVisible { - visible_ = required_ && [self unfiltered]; -} - -- (Package *) initWithVersion:(pkgCache::VerIterator)version withZone:(NSZone *)zone inPool:(apr_pool_t *)pool database:(Database *)database { - if ((self = [super init]) != nil) { - _profile(Package$initWithVersion) - @synchronized (database) { - era_ = [database era]; - pool_ = pool; - - version_ = version; - iterator_ = version.ParentPkg(); - database_ = database; - - _profile(Package$initWithVersion$Latest) - latest_ = (NSString *) StripVersion(version_.VerStr()); - _end - - pkgCache::VerIterator current; - _profile(Package$initWithVersion$Versions) - current = iterator_.CurrentVer(); - if (!current.end()) - installed_.set(pool_, StripVersion_(current.VerStr())); - - if (!version_.end()) - file_ = version_.FileList(); - else { - pkgCache &cache([database_ cache]); - file_ = pkgCache::VerFileIterator(cache, cache.VerFileP); - } - _end - - _profile(Package$initWithVersion$Name) - id_.set(pool_, iterator_.Name()); - name_.set(pool, iterator_.Display()); - _end - - if (!file_.end()) { - _profile(Package$initWithVersion$Source) - source_ = [database_ getSource:file_.File()]; - if (source_ != nil) - [source_ retain]; - cached_ = true; - _end - } - - required_ = true; - - _profile(Package$initWithVersion$Tags) - pkgCache::TagIterator tag(iterator_.TagList()); - if (!tag.end()) { - tags_ = [[NSMutableArray alloc] initWithCapacity:8]; - do { - const char *name(tag.Name()); - [tags_ addObject:(NSString *)CFCString(name)]; - if (role_ == nil && strncmp(name, "role::", 6) == 0 /*&& strcmp(name, "role::leaper") != 0*/) - role_ = (NSString *) CFCString(name + 6); - if (required_ && strncmp(name, "require::", 9) == 0 && ( - true - )) - required_ = false; - ++tag; - } while (!tag.end()); - } - _end - - bool changed(false); - NSString *key([static_cast<id>(id_) lowercaseString]); - - _profile(Package$initWithVersion$Metadata) - metadata_ = [Packages_ objectForKey:key]; - - if (metadata_ == nil) { - firstSeen_ = now_; - - metadata_ = [[NSMutableDictionary dictionaryWithObjectsAndKeys: - firstSeen_, @"FirstSeen", - latest_, @"LastVersion", - nil] mutableCopy]; - - changed = true; - } else { - firstSeen_ = [metadata_ objectForKey:@"FirstSeen"]; - lastSeen_ = [metadata_ objectForKey:@"LastSeen"]; - - if (NSNumber *subscribed = [metadata_ objectForKey:@"IsSubscribed"]) - subscribed_ = [subscribed boolValue]; - - NSString *version([metadata_ objectForKey:@"LastVersion"]); - - if (firstSeen_ == nil) { - firstSeen_ = lastSeen_ == nil ? now_ : lastSeen_; - [metadata_ setObject:firstSeen_ forKey:@"FirstSeen"]; - changed = true; - } - - if (version == nil) { - [metadata_ setObject:latest_ forKey:@"LastVersion"]; - changed = true; - } else if (![version isEqualToString:latest_]) { - [metadata_ setObject:latest_ forKey:@"LastVersion"]; - lastSeen_ = now_; - [metadata_ setObject:lastSeen_ forKey:@"LastSeen"]; - changed = true; - } - } - - metadata_ = [metadata_ retain]; - - if (changed) { - [Packages_ setObject:metadata_ forKey:key]; - Changed_ = true; - } - _end - - _profile(Package$initWithVersion$Section) - section_.set(pool_, iterator_.Section()); - _end - - obsolete_ = [self hasTag:@"cydia::obsolete"]; - essential_ = ((iterator_->Flags & pkgCache::Flag::Essential) == 0 ? NO : YES) || [self hasTag:@"cydia::essential"]; - [self setVisible]; - } _end } return self; -} - -+ (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator withZone:(NSZone *)zone inPool:(apr_pool_t *)pool database:(Database *)database { -@synchronized ([Database class]) { - pkgCache::VerIterator version; - - _profile(Package$packageWithIterator$GetCandidateVer) - version = [database policy]->GetCandidateVer(iterator); - _end - - if (version.end()) - return nil; - - return [[[Package alloc] - initWithVersion:version - withZone:zone - inPool:pool - database:database - ] autorelease]; -} } - -- (pkgCache::PkgIterator) iterator { - return iterator_; -} - -- (NSString *) section { - if (section$_ == nil) { - if (section_.empty()) - return nil; - - std::replace(section_.data(), section_.data() + section_.size(), ' ', '_'); - NSString *name(section_); - - lookup: - if (NSDictionary *value = [SectionMap_ objectForKey:name]) - if (NSString *rename = [value objectForKey:@"Rename"]) { - name = rename; - goto lookup; - } - - section$_ = [[name stringByReplacingCharacter:'_' withCharacter:' '] retain]; - } return section$_; -} - -- (NSString *) simpleSection { - if (NSString *section = [self section]) - return Simplify(section); - else - return nil; -} - -- (NSString *) longSection { - return LocalizeSection([self section]); -} - -- (NSString *) shortSection { - return [[NSBundle mainBundle] localizedStringForKey:[self simpleSection] value:nil table:@"Sections"]; -} - -- (NSString *) uri { - return nil; -#if 0 - pkgIndexFile *index; - pkgCache::PkgFileIterator file(file_.File()); - if (![database_ list].FindIndex(file, index)) - return nil; - return [NSString stringWithUTF8String:iterator_->Path]; - //return [NSString stringWithUTF8String:file.Site()]; - //return [NSString stringWithUTF8String:index->ArchiveURI(file.FileName()).c_str()]; -#endif -} - -- (Address *) maintainer { - if (file_.end()) - return nil; - pkgRecords::Parser *parser = &[database_ records]->Lookup(file_); - const std::string &maintainer(parser->Maintainer()); - return maintainer.empty() ? nil : [Address addressWithString:[NSString stringWithUTF8String:maintainer.c_str()]]; -} - -- (size_t) size { - return version_.end() ? 0 : version_->InstalledSize; -} - -- (NSString *) longDescription { - if (file_.end()) - return nil; - pkgRecords::Parser *parser = &[database_ records]->Lookup(file_); - NSString *description([NSString stringWithUTF8String:parser->LongDesc().c_str()]); - - NSArray *lines = [description componentsSeparatedByString:@"\n"]; - NSMutableArray *trimmed = [NSMutableArray arrayWithCapacity:([lines count] - 1)]; - if ([lines count] < 2) - return nil; - - NSCharacterSet *whitespace = [NSCharacterSet whitespaceCharacterSet]; - for (size_t i(1), e([lines count]); i != e; ++i) { - NSString *trim = [[lines objectAtIndex:i] stringByTrimmingCharactersInSet:whitespace]; - [trimmed addObject:trim]; - } - - return [trimmed componentsJoinedByString:@"\n"]; -} - -- (NSString *) shortDescription { - return tagline_; -} - -- (unichar) index { - _profile(Package$index) - CFStringRef name((CFStringRef) [self name]); - if (CFStringGetLength(name) == 0) - return '#'; - UniChar character(CFStringGetCharacterAtIndex(name, 0)); - if (!CFUniCharIsMemberOf(character, kCFUniCharLetterCharacterSet)) - return '#'; - return toupper(character); - _end -} - -- (NSMutableDictionary *) metadata { - return metadata_; -} - -- (NSDate *) seen { - if (subscribed_ && lastSeen_ != nil) - return lastSeen_; - return firstSeen_; -} - -- (BOOL) subscribed { - return subscribed_; -} - -- (BOOL) ignored { - NSDictionary *metadata([self metadata]); - if (NSNumber *ignored = [metadata objectForKey:@"IsIgnored"]) - return [ignored boolValue]; - else - return false; -} - -- (NSString *) latest { - return latest_; -} - -- (NSString *) installed { - return installed_; -} - -- (BOOL) uninstalled { - 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_ && visible_; - else - return !version_.end() && version_ != current;// && (!essential || ![database_ cache][iterator_].Keep()); - _end -} - -- (BOOL) essential { - return essential_; -} - -- (BOOL) broken { - return [database_ cache][iterator_].InstBroken(); -} - -- (BOOL) unfiltered { - NSString *section([self section]); - return !obsolete_ && [self hasSupportingRole] && (section == nil || isSectionVisible(section)); -} - -- (BOOL) visible { - return visible_; -} - -- (BOOL) half { - unsigned char current(iterator_->CurrentState); - return current == pkgCache::State::HalfConfigured || current == pkgCache::State::HalfInstalled; -} - -- (BOOL) halfConfigured { - return iterator_->CurrentState == pkgCache::State::HalfConfigured; -} - -- (BOOL) halfInstalled { - return iterator_->CurrentState == pkgCache::State::HalfInstalled; -} - -- (BOOL) hasMode { - pkgDepCache::StateCache &state([database_ cache][iterator_]); - return state.Mode != pkgDepCache::ModeKeep; -} - -- (NSString *) mode { - pkgDepCache::StateCache &state([database_ cache][iterator_]); - - switch (state.Mode) { - case pkgDepCache::ModeDelete: - if ((state.iFlags & pkgDepCache::Purge) != 0) - return @"PURGE"; - else - return @"REMOVE"; - case pkgDepCache::ModeKeep: - if ((state.iFlags & pkgDepCache::ReInstall) != 0) - return @"REINSTALL"; - /*else if ((state.iFlags & pkgDepCache::AutoKept) != 0) - return nil;*/ - else - return nil; - case pkgDepCache::ModeInstall: - /*if ((state.iFlags & pkgDepCache::ReInstall) != 0) - return @"REINSTALL"; - else*/ switch (state.Status) { - case -1: - return @"DOWNGRADE"; - case 0: - return @"INSTALL"; - case 1: - return @"UPGRADE"; - case 2: - return @"NEW_INSTALL"; - _nodefault - } - _nodefault - } -} - -- (NSString *) id { - return id_; -} - -- (NSString *) name { - return name_.empty() ? id_ : name_; -} - -- (UIImage *) icon { - NSString *section = [self simpleSection]; - - UIImage *icon(nil); - if (!icon_.empty()) - if ([static_cast<id>(icon_) hasPrefix:@"file:///"]) - // XXX: correct escaping - icon = [UIImage imageAtPath:[static_cast<id>(icon_) substringFromIndex:7]]; - if (icon == nil) if (section != nil) - icon = [UIImage imageAtPath:[NSString stringWithFormat:@"%@/Sections/%@.png", App_, section]]; - if (icon == nil) if (source_ != nil) if (NSString *dicon = [source_ defaultIcon]) - if ([dicon hasPrefix:@"file:///"]) - // XXX: correct escaping - icon = [UIImage imageAtPath:[dicon substringFromIndex:7]]; - if (icon == nil) - icon = [UIImage applicationImageNamed:@"unknown.png"]; - return icon; -} - -- (NSString *) homepage { - return homepage_; -} - -- (NSString *) depiction { - return !depiction_.empty() ? depiction_ : [[self source] depictionForPackage:id_]; -} - -- (Address *) sponsor { - if (sponsor$_ == nil) { - if (sponsor_.empty()) - return nil; - sponsor$_ = [[Address addressWithString:sponsor_] retain]; - } return sponsor$_; -} - -- (Address *) author { - if (author$_ == nil) { - if (author_.empty()) - return nil; - author$_ = [[Address addressWithString:author_] retain]; - } return author$_; -} - -- (NSString *) support { - return !bugs_.empty() ? bugs_ : [[self source] supportForPackage:id_]; -} - -- (NSArray *) files { - NSString *path = [NSString stringWithFormat:@"/var/lib/dpkg/info/%@.list", static_cast<NSString *>(id_)]; - NSMutableArray *files = [NSMutableArray arrayWithCapacity:128]; - - std::ifstream fin; - fin.open([path UTF8String]); - if (!fin.is_open()) - return nil; - - std::string line; - while (std::getline(fin, line)) - [files addObject:[NSString stringWithUTF8String:line.c_str()]]; - - return files; -} - -- (NSArray *) relationships { - return relationships_; -} - -- (NSArray *) warnings { - NSMutableArray *warnings([NSMutableArray arrayWithCapacity:4]); - const char *name(iterator_.Name()); - - size_t length(strlen(name)); - if (length < 2) invalid: - [warnings addObject:UCLocalize("ILLEGAL_PACKAGE_IDENTIFIER")]; - else for (size_t i(0); i != length; ++i) - if ( - /* XXX: technically this is not allowed */ - (name[i] < 'A' || name[i] > 'Z') && - (name[i] < 'a' || name[i] > 'z') && - (name[i] < '0' || name[i] > '9') && - (i == 0 || name[i] != '+' && name[i] != '-' && name[i] != '.') - ) goto invalid; - - if (strcmp(name, "cydia") != 0) { - bool cydia = false; - bool user = false; - bool _private = false; - bool stash = false; - - bool repository = [[self section] isEqualToString:@"Repositories"]; - - if (NSArray *files = [self files]) - for (NSString *file in files) - if (!cydia && [file isEqualToString:@"/Applications/Cydia.app"]) - cydia = true; - else if (!user && [file isEqualToString:@"/User"]) - user = true; - else if (!_private && [file isEqualToString:@"/private"]) - _private = true; - else if (!stash && [file isEqualToString:@"/var/stash"]) - stash = true; - - /* XXX: this is not sensitive enough. only some folders are valid. */ - if (cydia && !repository) - [warnings addObject:[NSString stringWithFormat:UCLocalize("FILES_INSTALLED_TO"), @"Cydia.app"]]; - if (user) - [warnings addObject:[NSString stringWithFormat:UCLocalize("FILES_INSTALLED_TO"), @"/User"]]; - if (_private) - [warnings addObject:[NSString stringWithFormat:UCLocalize("FILES_INSTALLED_TO"), @"/private"]]; - if (stash) - [warnings addObject:[NSString stringWithFormat:UCLocalize("FILES_INSTALLED_TO"), @"/var/stash"]]; - } - - return [warnings count] == 0 ? nil : warnings; -} - -- (NSArray *) applications { - NSString *me([[NSBundle mainBundle] bundleIdentifier]); - - NSMutableArray *applications([NSMutableArray arrayWithCapacity:2]); - - static Pcre 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]); - NSString *id([info objectForKey:@"CFBundleIdentifier"]); - if ([id isEqualToString:me]) - continue; - - NSString *display([info objectForKey:@"CFBundleDisplayName"]); - if (display == nil) - display = application_r[1]; - - NSString *bundle([file stringByDeletingLastPathComponent]); - NSString *icon([info objectForKey:@"CFBundleIconFile"]); - if (icon == nil || [icon length] == 0) - icon = @"icon.png"; - NSURL *url([NSURL fileURLWithPath:[bundle stringByAppendingPathComponent:icon]]); - - NSMutableArray *application([NSMutableArray arrayWithCapacity:2]); - [applications addObject:application]; - - [application addObject:id]; - [application addObject:display]; - [application addObject:url]; - } - - return [applications count] == 0 ? nil : applications; -} - -- (Source *) source { - if (!cached_) { - @synchronized (database_) { - if ([database_ era] != era_ || file_.end()) - source_ = nil; - else { - source_ = [database_ getSource:file_.File()]; - if (source_ != nil) - [source_ retain]; - } - - cached_ = true; - } - } - - return source_; -} - -- (NSString *) role { - return role_; -} - -- (BOOL) matches:(NSString *)text { - if (text == nil) - return NO; - - NSRange range; - - range = [[self id] rangeOfString:text options:MatchCompareOptions_]; - if (range.location != NSNotFound) - return YES; - - range = [[self name] rangeOfString:text options:MatchCompareOptions_]; - if (range.location != NSNotFound) - return YES; - - range = [[self shortDescription] rangeOfString:text options:MatchCompareOptions_]; - if (range.location != NSNotFound) - return YES; - - return NO; -} - -- (bool) hasSupportingRole { - if (role_ == nil) - return true; - if ([role_ isEqualToString:@"enduser"]) - return true; - if ([Role_ isEqualToString:@"User"]) - return false; - if ([role_ isEqualToString:@"hacker"]) - return true; - if ([Role_ isEqualToString:@"Hacker"]) - return false; - if ([role_ isEqualToString:@"developer"]) - return true; - if ([Role_ isEqualToString:@"Developer"]) - return false; - _assert(false); -} - -- (BOOL) hasTag:(NSString *)tag { - return tags_ == nil ? NO : [tags_ containsObject:tag]; -} - -- (NSString *) primaryPurpose { - for (NSString *tag in tags_) - if ([tag hasPrefix:@"purpose::"]) - return [tag substringFromIndex:9]; - return nil; -} - -- (NSArray *) purposes { - NSMutableArray *purposes([NSMutableArray arrayWithCapacity:2]); - for (NSString *tag in tags_) - if ([tag hasPrefix:@"purpose::"]) - [purposes addObject:[tag substringFromIndex:9]]; - return [purposes count] == 0 ? nil : purposes; -} - -- (bool) isCommercial { - return [self hasTag:@"cydia::commercial"]; -} - -- (CYString &) cyname { - return name_.empty() ? id_ : name_; -} - -- (uint32_t) compareBySection:(NSArray *)sections { - NSString *section([self section]); - for (size_t i(0), e([sections count]); i != e; ++i) { - if ([section isEqualToString:[[sections objectAtIndex:i] name]]) - return i; - } - - return _not(uint32_t); -} - -- (uint32_t) compareForChanges { - union { - uint32_t key; - - struct { - uint32_t timestamp : 30; - uint32_t ignored : 1; - uint32_t upgradable : 1; - } bits; - } value; - - bool upgradable([self upgradableAndEssential:YES]); - value.bits.upgradable = upgradable ? 1 : 0; - - if (upgradable) { - value.bits.timestamp = 0; - value.bits.ignored = [self ignored] ? 0 : 1; - value.bits.upgradable = 1; - } else { - value.bits.timestamp = static_cast<uint32_t>([[self seen] timeIntervalSince1970]) >> 2; - value.bits.ignored = 0; - value.bits.upgradable = 0; - } - - return _not(uint32_t) - value.key; -} - -- (void) clear { - pkgProblemResolver *resolver = [database_ resolver]; - resolver->Clear(iterator_); - resolver->Protect(iterator_); -} - -- (void) install { - pkgProblemResolver *resolver = [database_ resolver]; - resolver->Clear(iterator_); - resolver->Protect(iterator_); - pkgCacheFile &cache([database_ cache]); - cache->MarkInstall(iterator_, false); - pkgDepCache::StateCache &state((*cache)[iterator_]); - if (!state.Install()) - cache->SetReInstall(iterator_, true); -} - -- (void) remove { - pkgProblemResolver *resolver = [database_ resolver]; - resolver->Clear(iterator_); - resolver->Protect(iterator_); - resolver->Remove(iterator_); - [database_ cache]->MarkDelete(iterator_, true); -} - -- (bool) isUnfilteredAndSearchedForBy:(NSString *)search { - _profile(Package$isUnfilteredAndSearchedForBy) - bool value(true); - - _profile(Package$isUnfilteredAndSearchedForBy$Unfiltered) - value &= [self unfiltered]; - _end - - _profile(Package$isUnfilteredAndSearchedForBy$Match) - value &= [self matches:search]; - _end - - return value; - _end -} - -- (bool) isUnfilteredAndSelectedForBy:(NSString *)search { - if ([search length] == 0) - return false; - - _profile(Package$isUnfilteredAndSelectedForBy) - bool value(true); - - _profile(Package$isUnfilteredAndSelectedForBy$Unfiltered) - value &= [self unfiltered]; - _end - - _profile(Package$isUnfilteredAndSelectedForBy$Match) - value &= [[self name] compare:search options:MatchCompareOptions_ range:NSMakeRange(0, [search length])] == NSOrderedSame; - _end - - return value; - _end -} - -- (bool) isInstalledAndVisible:(NSNumber *)number { - return (![number boolValue] || [self visible]) && ![self uninstalled]; -} - -- (bool) isVisibleInSection:(NSString *)name { - NSString *section = [self section]; - - return - [self visible] && ( - name == nil || - section == nil && [name length] == 0 || - [name isEqualToString:section] - ); -} - -- (bool) isVisibleInSource:(Source *)source { - return [self source] == source && [self visible]; -} - -@end -/* }}} */ -/* Section Class {{{ */ -@interface Section : NSObject { - NSString *name_; - unichar index_; - size_t row_; - size_t count_; - NSString *localized_; -} - -- (NSComparisonResult) compareByLocalized:(Section *)section; -- (Section *) initWithName:(NSString *)name localized:(NSString *)localized; -- (Section *) initWithName:(NSString *)name localize:(BOOL)localize; -- (Section *) initWithName:(NSString *)name row:(size_t)row localize:(BOOL)localize; -- (Section *) initWithIndex:(unichar)index row:(size_t)row; -- (NSString *) name; -- (unichar) index; - -- (size_t) row; -- (size_t) count; - -- (void) addToRow; -- (void) addToCount; - -- (void) setCount:(size_t)count; -- (NSString *) localized; - -@end - -@implementation Section - -- (void) dealloc { - [name_ release]; - if (localized_ != nil) - [localized_ release]; - [super dealloc]; -} - -- (NSComparisonResult) compareByLocalized:(Section *)section { - NSString *lhs(localized_); - NSString *rhs([section localized]); - - /*if ([lhs length] != 0 && [rhs length] != 0) { - unichar lhc = [lhs characterAtIndex:0]; - unichar rhc = [rhs characterAtIndex:0]; - - if (isalpha(lhc) && !isalpha(rhc)) - return NSOrderedAscending; - else if (!isalpha(lhc) && isalpha(rhc)) - return NSOrderedDescending; - }*/ - - return [lhs compare:rhs options:LaxCompareOptions_]; -} - -- (Section *) initWithName:(NSString *)name localized:(NSString *)localized { - if ((self = [self initWithName:name localize:NO]) != nil) { - if (localized != nil) - localized_ = [localized retain]; - } return self; -} - -- (Section *) initWithName:(NSString *)name localize:(BOOL)localize { - return [self initWithName:name row:0 localize:localize]; -} - -- (Section *) initWithName:(NSString *)name row:(size_t)row localize:(BOOL)localize { - if ((self = [super init]) != nil) { - name_ = [name retain]; - index_ = '\0'; - row_ = row; - if (localize) - localized_ = [LocalizeSection(name_) retain]; - } return self; -} - -/* XXX: localize the index thingees */ -- (Section *) initWithIndex:(unichar)index row:(size_t)row { - if ((self = [super init]) != nil) { - name_ = [[NSString stringWithCharacters:&index length:1] retain]; - index_ = index; - row_ = row; - } return self; -} - -- (NSString *) name { - return name_; -} - -- (unichar) index { - return index_; -} - -- (size_t) row { - return row_; -} - -- (size_t) count { - return count_; -} - -- (void) addToRow { - ++row_; -} - -- (void) addToCount { - ++count_; -} - -- (void) setCount:(size_t)count { - count_ = count; -} - -- (NSString *) localized { - return localized_; -} - -@end -/* }}} */ - -static NSString *Colon_; -static NSString *Error_; -static NSString *Warning_; - -/* Database Implementation {{{ */ -@implementation Database - -+ (Database *) sharedInstance { - static Database *instance; - if (instance == nil) - instance = [[Database alloc] init]; - return instance; -} - -- (unsigned) era { - return era_; -} - -- (void) dealloc { - _assert(false); - NSRecycleZone(zone_); - // XXX: malloc_destroy_zone(zone_); - apr_pool_destroy(pool_); - [super dealloc]; -} - -- (void) _readCydia:(NSNumber *)fd { _pooled - __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in); - std::istream is(&ib); - std::string line; - - static Pcre finish_r("^finish:([^:]*)$"); - - while (std::getline(is, line)) { - const char *data(line.c_str()); - size_t size = line.size(); - lprintf("C:%s\n", data); - - if (finish_r(data, size)) { - NSString *finish = finish_r[1]; - int index = [Finishes_ indexOfObject:finish]; - if (index != INT_MAX && index > Finish_) - Finish_ = index; - } - } - - _assume(false); -} - -- (void) _readStatus:(NSNumber *)fd { _pooled - __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in); - std::istream is(&ib); - std::string line; - - static Pcre conffile_r("^status: [^ ]* : conffile-prompt : (.*?) *$"); - static Pcre pmstatus_r("^([^:]*):([^:]*):([^:]*):(.*)$"); - - while (std::getline(is, line)) { - const char *data(line.c_str()); - size_t size(line.size()); - lprintf("S:%s\n", data); - - if (conffile_r(data, size)) { - [delegate_ setConfigurationData:conffile_r[1]]; - } else if (strncmp(data, "status: ", 8) == 0) { - NSString *string = [NSString stringWithUTF8String:(data + 8)]; - [delegate_ setProgressTitle:string]; - } else if (pmstatus_r(data, size)) { - std::string type([pmstatus_r[1] UTF8String]); - NSString *id = pmstatus_r[2]; - - float percent([pmstatus_r[3] floatValue]); - [delegate_ setProgressPercent:(percent / 100)]; - - NSString *string = pmstatus_r[4]; - - if (type == "pmerror") - [delegate_ performSelectorOnMainThread:@selector(_setProgressErrorPackage:) - withObject:[NSArray arrayWithObjects:string, id, nil] - waitUntilDone:YES - ]; - else if (type == "pmstatus") { - [delegate_ setProgressTitle:string]; - } else if (type == "pmconffile") - [delegate_ setConfigurationData:string]; - else - lprintf("E:unknown pmstatus\n"); - } else - lprintf("E:unknown status\n"); - } - - _assume(false); -} - -- (void) _readOutput:(NSNumber *)fd { _pooled - __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in); - std::istream is(&ib); - std::string line; - - while (std::getline(is, line)) { - lprintf("O:%s\n", line.c_str()); - [delegate_ addProgressOutput:[NSString stringWithUTF8String:line.c_str()]]; - } - - _assume(false); -} - -- (FILE *) input { - return input_; -} - -- (Package *) packageWithName:(NSString *)name { -@synchronized ([Database class]) { - if (static_cast<pkgDepCache *>(cache_) == NULL) - return nil; - pkgCache::PkgIterator iterator(cache_->FindPkg([name UTF8String])); - return iterator.end() ? nil : [Package packageWithIterator:iterator withZone:NULL inPool:pool_ database:self]; -} } - -- (id) init { - if ((self = [super init]) != nil) { - policy_ = NULL; - records_ = NULL; - resolver_ = NULL; - fetcher_ = NULL; - lock_ = NULL; - - zone_ = NSCreateZone(1024 * 1024, 256 * 1024, NO); - apr_pool_create(&pool_, NULL); - - packages_ = [[NSMutableArray alloc] init]; - - int fds[2]; - - _assert(pipe(fds) != -1); - cydiafd_ = fds[1]; - - _config->Set("APT::Keep-Fds::", cydiafd_); - setenv("CYDIA", [[[[NSNumber numberWithInt:cydiafd_] stringValue] stringByAppendingString:@" 1"] UTF8String], _not(int)); - - [NSThread - detachNewThreadSelector:@selector(_readCydia:) - toTarget:self - withObject:[[NSNumber numberWithInt:fds[0]] retain] - ]; - - _assert(pipe(fds) != -1); - statusfd_ = fds[1]; - - [NSThread - detachNewThreadSelector:@selector(_readStatus:) - toTarget:self - withObject:[[NSNumber numberWithInt:fds[0]] retain] - ]; - - _assert(pipe(fds) != -1); - _assert(dup2(fds[0], 0) != -1); - _assert(close(fds[0]) != -1); - - input_ = fdopen(fds[1], "a"); - - _assert(pipe(fds) != -1); - _assert(dup2(fds[1], 1) != -1); - _assert(close(fds[1]) != -1); - - [NSThread - detachNewThreadSelector:@selector(_readOutput:) - toTarget:self - withObject:[[NSNumber numberWithInt:fds[0]] retain] - ]; - } return self; -} - -- (pkgCacheFile &) cache { - return cache_; -} - -- (pkgDepCache::Policy *) policy { - return policy_; -} - -- (pkgRecords *) records { - return records_; -} - -- (pkgProblemResolver *) resolver { - return resolver_; -} - -- (pkgAcquire &) fetcher { - return *fetcher_; -} - -- (pkgSourceList &) list { - return *list_; -} - -- (NSArray *) packages { - return packages_; -} - -- (NSArray *) sources { - NSMutableArray *sources([NSMutableArray arrayWithCapacity:sources_.size()]); - for (SourceMap::const_iterator i(sources_.begin()); i != sources_.end(); ++i) - [sources addObject:i->second]; - return sources; -} - -- (NSArray *) issues { - if (cache_->BrokenCount() == 0) - return nil; - - NSMutableArray *issues([NSMutableArray arrayWithCapacity:4]); - - for (Package *package in packages_) { - if (![package broken]) - continue; - pkgCache::PkgIterator pkg([package iterator]); - - NSMutableArray *entry([NSMutableArray arrayWithCapacity:4]); - [entry addObject:[package name]]; - [issues addObject:entry]; - - pkgCache::VerIterator ver(cache_[pkg].InstVerIter(cache_)); - if (ver.end()) - continue; - - for (pkgCache::DepIterator dep(ver.DependsList()); !dep.end(); ) { - pkgCache::DepIterator start; - pkgCache::DepIterator end; - dep.GlobOr(start, end); // ++dep - - if (!cache_->IsImportantDep(end)) - continue; - if ((cache_[end] & pkgDepCache::DepGInstall) != 0) - continue; - - NSMutableArray *failure([NSMutableArray arrayWithCapacity:4]); - [entry addObject:failure]; - [failure addObject:[NSString stringWithUTF8String:start.DepType()]]; - - NSString *name([NSString stringWithUTF8String:start.TargetPkg().Name()]); - if (Package *package = [self packageWithName:name]) - name = [package name]; - [failure addObject:name]; - - pkgCache::PkgIterator target(start.TargetPkg()); - if (target->ProvidesList != 0) - [failure addObject:@"?"]; - else { - pkgCache::VerIterator ver(cache_[target].InstVerIter(cache_)); - if (!ver.end()) - [failure addObject:[NSString stringWithUTF8String:ver.VerStr()]]; - else if (!cache_[target].CandidateVerIter(cache_).end()) - [failure addObject:@"-"]; - else if (target->ProvidesList == 0) - [failure addObject:@"!"]; - else - [failure addObject:@"%"]; - } - - _forever { - if (start.TargetVer() != 0) - [failure addObject:[NSString stringWithFormat:@"%s %s", start.CompType(), start.TargetVer()]]; - if (start == end) - break; - ++start; - } - } - } - - return issues; -} - -- (bool) popErrorWithTitle:(NSString *)title { - bool fatal(false); - std::string message; - - while (!_error->empty()) { - std::string error; - bool warning(!_error->PopMessage(error)); - if (!warning) - fatal = true; - for (;;) { - size_t size(error.size()); - if (size == 0 || error[size - 1] != '\n') - break; - error.resize(size - 1); - } - lprintf("%c:[%s]\n", warning ? 'W' : 'E', error.c_str()); - - if (!message.empty()) - message += "\n\n"; - message += error; - } - - if (fatal && !message.empty()) - [delegate_ _setProgressError:[NSString stringWithUTF8String:message.c_str()] withTitle:[NSString stringWithFormat:Colon_, fatal ? Error_ : Warning_, title]]; - - return fatal; -} - -- (bool) popErrorWithTitle:(NSString *)title forOperation:(bool)success { - return [self popErrorWithTitle:title] || !success; -} - -- (void) reloadData { _pooled -@synchronized ([Database class]) { - @synchronized (self) { - ++era_; - } - - [packages_ removeAllObjects]; - sources_.clear(); - - _error->Discard(); - - delete list_; - list_ = NULL; - manager_ = NULL; - delete lock_; - lock_ = NULL; - delete fetcher_; - fetcher_ = NULL; - delete resolver_; - resolver_ = NULL; - delete records_; - records_ = NULL; - delete policy_; - policy_ = NULL; - - if (now_ != nil) { - [now_ release]; - now_ = nil; - } - - cache_.Close(); - - apr_pool_clear(pool_); - NSRecycleZone(zone_); - - int chk(creat("/tmp/cydia.chk", 0644)); - if (chk != -1) - close(chk); - - NSString *title(UCLocalize("DATABASE")); - - _trace(); - if (!cache_.Open(progress_, true)) { pop: - std::string error; - bool warning(!_error->PopMessage(error)); - lprintf("cache_.Open():[%s]\n", error.c_str()); - - if (error == "dpkg was interrupted, you must manually run 'dpkg --configure -a' to correct the problem. ") - [delegate_ repairWithSelector:@selector(configure)]; - else if (error == "The package lists or status file could not be parsed or opened.") - [delegate_ repairWithSelector:@selector(update)]; - // else if (error == "Could not open lock file /var/lib/dpkg/lock - open (13 Permission denied)") - // else if (error == "Could not get lock /var/lib/dpkg/lock - open (35 Resource temporarily unavailable)") - // else if (error == "The list of sources could not be read.") - else - [delegate_ _setProgressError:[NSString stringWithUTF8String:error.c_str()] withTitle:[NSString stringWithFormat:Colon_, warning ? Warning_ : Error_, title]]; - - if (warning) - goto pop; - _error->Discard(); - return; - } - _trace(); - - unlink("/tmp/cydia.chk"); - - now_ = [[NSDate date] retain]; - - policy_ = new pkgDepCache::Policy(); - records_ = new pkgRecords(cache_); - resolver_ = new pkgProblemResolver(cache_); - fetcher_ = new pkgAcquire(&status_); - lock_ = NULL; - - list_ = new pkgSourceList(); - if ([self popErrorWithTitle:title forOperation:list_->ReadMainList()]) - return; - - if (cache_->DelCount() != 0 || cache_->InstCount() != 0) { - [delegate_ _setProgressError:@"COUNTS_NONZERO_EX" withTitle:title]; - return; - } - - if ([self popErrorWithTitle:title forOperation:pkgApplyStatus(cache_)]) - return; - - if (cache_->BrokenCount() != 0) { - if ([self popErrorWithTitle:title forOperation:pkgFixBroken(cache_)]) - return; - - if (cache_->BrokenCount() != 0) { - [delegate_ _setProgressError:@"STILL_BROKEN_EX" withTitle:title]; - return; - } - - if ([self popErrorWithTitle:title forOperation:pkgMinimizeUpgrade(cache_)]) - return; - } - - _trace(); - - for (pkgSourceList::const_iterator source = list_->begin(); source != list_->end(); ++source) { - std::vector<pkgIndexFile *> *indices = (*source)->GetIndexFiles(); - for (std::vector<pkgIndexFile *>::const_iterator index = indices->begin(); index != indices->end(); ++index) - // XXX: this could be more intelligent - if (dynamic_cast<debPackagesIndex *>(*index) != NULL) { - pkgCache::PkgFileIterator cached((*index)->FindInCache(cache_)); - if (!cached.end()) - sources_[cached->ID] = [[[Source alloc] initWithMetaIndex:*source inPool:pool_] autorelease]; - } - } - - _trace(); - - { - /*std::vector<Package *> packages; - packages.reserve(std::max(10000U, [packages_ count] + 1000)); - [packages_ release]; - packages_ = nil;*/ - - _trace(); - - 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); - [packages_ addObject:package]; - - _trace(); - - /*if (packages.empty()) - packages_ = [[NSArray alloc] init]; - else - packages_ = [[NSArray alloc] initWithObjects:&packages.front() count:packages.size()]; - _trace();*/ - - [packages_ radixSortUsingFunction:reinterpret_cast<SKRadixFunction>(&PackagePrefixRadix) withContext:reinterpret_cast<void *>(16)]; - [packages_ radixSortUsingFunction:reinterpret_cast<SKRadixFunction>(&PackagePrefixRadix) withContext:reinterpret_cast<void *>(4)]; - [packages_ radixSortUsingFunction:reinterpret_cast<SKRadixFunction>(&PackagePrefixRadix) withContext:reinterpret_cast<void *>(0)]; - - /*_trace(); - PrintTimes(); - _trace();*/ - - _trace(); - - /*if (!packages.empty()) - CFQSortArray(&packages.front(), packages.size(), sizeof(packages.front()), reinterpret_cast<CFComparatorFunction>(&PackageNameCompare_), NULL);*/ - //std::sort(packages.begin(), packages.end(), PackageNameOrdering()); - - //CFArraySortValues((CFMutableArrayRef) packages_, CFRangeMake(0, [packages_ count]), reinterpret_cast<CFComparatorFunction>(&PackageNameCompare), NULL); - - CFArrayInsertionSortValues((CFMutableArrayRef) packages_, CFRangeMake(0, [packages_ count]), reinterpret_cast<CFComparatorFunction>(&PackageNameCompare), NULL); - - //[packages_ sortUsingFunction:reinterpret_cast<NSComparisonResult (*)(id, id, void *)>(&PackageNameCompare) context:NULL]; - - _trace(); - } -} } - -- (void) configure { - NSString *dpkg = [NSString stringWithFormat:@"dpkg --configure -a --status-fd %u", statusfd_]; - system([dpkg UTF8String]); -} - -- (bool) clean { - // XXX: I don't remember this condition - if (lock_ != NULL) - return false; - - FileFd Lock; - Lock.Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock")); - - NSString *title(UCLocalize("CLEAN_ARCHIVES")); - - if ([self popErrorWithTitle:title]) - return false; - - pkgAcquire fetcher; - fetcher.Clean(_config->FindDir("Dir::Cache::Archives")); - - class LogCleaner : - public pkgArchiveCleaner - { - protected: - virtual void Erase(const char *File, std::string Pkg, std::string Ver, struct stat &St) { - unlink(File); - } - } cleaner; - - if ([self popErrorWithTitle:title forOperation:cleaner.Go(_config->FindDir("Dir::Cache::Archives") + "partial/", cache_)]) - return false; - - return true; -} - -- (bool) prepare { - fetcher_->Shutdown(); - - pkgRecords records(cache_); - - lock_ = new FileFd(); - lock_->Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock")); - - NSString *title(UCLocalize("PREPARE_ARCHIVES")); - - if ([self popErrorWithTitle:title]) - return false; - - pkgSourceList list; - if ([self popErrorWithTitle:title forOperation:list.ReadMainList()]) - return false; - - manager_ = (_system->CreatePM(cache_)); - if ([self popErrorWithTitle:title forOperation:manager_->GetArchives(fetcher_, &list, &records)]) - return false; - - return true; -} - -- (void) perform { - NSString *title(UCLocalize("PERFORM_SELECTIONS")); - - NSMutableArray *before = [NSMutableArray arrayWithCapacity:16]; { - pkgSourceList list; - if ([self popErrorWithTitle:title forOperation:list.ReadMainList()]) - return; - for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source) - [before addObject:[NSString stringWithUTF8String:(*source)->GetURI().c_str()]]; - } - - if (fetcher_->Run(PulseInterval_) != pkgAcquire::Continue) { - _trace(); - return; - } - - bool failed = false; - for (pkgAcquire::ItemIterator item = fetcher_->ItemsBegin(); item != fetcher_->ItemsEnd(); item++) { - if ((*item)->Status == pkgAcquire::Item::StatDone && (*item)->Complete) - continue; - if ((*item)->Status == pkgAcquire::Item::StatIdle) - continue; - - std::string uri = (*item)->DescURI(); - std::string error = (*item)->ErrorText; - - lprintf("pAf:%s:%s\n", uri.c_str(), error.c_str()); - failed = true; - - [delegate_ performSelectorOnMainThread:@selector(_setProgressErrorPackage:) - withObject:[NSArray arrayWithObjects: - [NSString stringWithUTF8String:error.c_str()], - nil] - waitUntilDone:YES - ]; - } - - if (failed) { - _trace(); - return; - } - - _system->UnLock(); - pkgPackageManager::OrderResult result = manager_->DoInstall(statusfd_); - - if (_error->PendingError()) { - _trace(); - return; - } - - if (result == pkgPackageManager::Failed) { - _trace(); - return; - } - - if (result != pkgPackageManager::Completed) { - _trace(); - return; - } - - NSMutableArray *after = [NSMutableArray arrayWithCapacity:16]; { - pkgSourceList list; - if ([self popErrorWithTitle:title forOperation:list.ReadMainList()]) - return; - for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source) - [after addObject:[NSString stringWithUTF8String:(*source)->GetURI().c_str()]]; - } - - if (![before isEqualToArray:after]) - [self update]; -} - -- (bool) upgrade { - NSString *title(UCLocalize("UPGRADE")); - if ([self popErrorWithTitle:title forOperation:pkgDistUpgrade(cache_)]) - return false; - return true; -} - -- (void) update { - [self updateWithStatus:status_]; -} - -- (void) setVisible { - for (Package *package in packages_) - [package setVisible]; -} - -- (void) updateWithStatus:(Status &)status { - _transient NSObject<ProgressDelegate> *delegate(status.getDelegate()); - NSString *title(UCLocalize("REFRESHING_DATA")); - - pkgSourceList list; - if (!list.ReadMainList()) - [delegate _setProgressError:@"Unable to read source list." withTitle:title]; - - FileFd lock; - lock.Fd(GetLock(_config->FindDir("Dir::State::Lists") + "lock")); - if ([self popErrorWithTitle:title]) - return; - - if ([self popErrorWithTitle:title forOperation:ListUpdate(status, list, PulseInterval_)]) - /* XXX: ignore this because users suck and don't understand why refreshing is important: return */ - /* XXX: why the hell is an empty if statement a clang error? */ (void) 0; - - [Metadata_ setObject:[NSDate date] forKey:@"LastUpdate"]; - Changed_ = true; -} - -- (void) setDelegate:(id)delegate { - delegate_ = delegate; - status_.setDelegate(delegate); - progress_.setDelegate(delegate); -} - -- (Source *) getSource:(pkgCache::PkgFileIterator)file { - SourceMap::const_iterator i(sources_.find(file->ID)); - return i == sources_.end() ? nil : i->second; -} - -@end -/* }}} */ - -/* Confirmation Controller {{{ */ -bool DepSubstrate(const pkgCache::VerIterator &iterator) { - if (!iterator.end()) - for (pkgCache::DepIterator dep(iterator.DependsList()); !dep.end(); ++dep) { - if (dep->Type != pkgCache::Dep::Depends && dep->Type != pkgCache::Dep::PreDepends) - continue; - pkgCache::PkgIterator package(dep.TargetPkg()); - if (package.end()) - continue; - if (strcmp(package.Name(), "mobilesubstrate") == 0) - return true; - } - - return false; -} -/* }}} */ - -/* Web Scripting {{{ */ -@interface CydiaObject : NSObject { - id indirect_; - id delegate_; -} - -- (id) initWithDelegate:(IndirectDelegate *)indirect; -@end - -@implementation CydiaObject - -- (void) dealloc { - [indirect_ release]; - [super dealloc]; -} - -- (id) initWithDelegate:(IndirectDelegate *)indirect { - if ((self = [super init]) != nil) { - indirect_ = [indirect retain]; - } return self; -} - -- (void) setDelegate:(id)delegate { - delegate_ = delegate; -} - -+ (NSArray *) _attributeKeys { - return [NSArray arrayWithObjects:@"device", @"firewire", @"imei", @"mac", @"serial", nil]; -} - -- (NSArray *) attributeKeys { - return [[self class] _attributeKeys]; -} - -+ (BOOL) isKeyExcludedFromWebScript:(const char *)name { - return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name]; -} - -- (NSString *) device { - return [[UIDevice currentDevice] uniqueIdentifier]; -} - -#if 0 // XXX: implement! -- (NSString *) mac { - if (![indirect_ promptForSensitive:@"Mac Address"]) - return nil; -} - -- (NSString *) serial { - if (![indirect_ promptForSensitive:@"Serial #"]) - return nil; -} - -- (NSString *) firewire { - if (![indirect_ promptForSensitive:@"Firewire GUID"]) - return nil; -} - -- (NSString *) imei { - if (![indirect_ promptForSensitive:@"IMEI"]) - return nil; -} -#endif - -+ (NSString *) webScriptNameForSelector:(SEL)selector { - if (selector == @selector(close)) - return @"close"; - else if (selector == @selector(getInstalledPackages)) - return @"getInstalledPackages"; - else if (selector == @selector(getPackageById:)) - return @"getPackageById"; - else if (selector == @selector(installPackages:)) - return @"installPackages"; - else if (selector == @selector(setAutoPopup:)) - return @"setAutoPopup"; - else if (selector == @selector(setButtonImage:withStyle:toFunction:)) - return @"setButtonImage"; - else if (selector == @selector(setButtonTitle:withStyle:toFunction:)) - return @"setButtonTitle"; - else if (selector == @selector(setFinishHook:)) - return @"setFinishHook"; - else if (selector == @selector(setPopupHook:)) - return @"setPopupHook"; - else if (selector == @selector(setSpecial:)) - return @"setSpecial"; - else if (selector == @selector(setToken:)) - return @"setToken"; - else if (selector == @selector(setViewportWidth:)) - return @"setViewportWidth"; - else if (selector == @selector(supports:)) - return @"supports"; - else if (selector == @selector(stringWithFormat:arguments:)) - return @"format"; - else if (selector == @selector(localizedStringForKey:value:table:)) - return @"localize"; - else if (selector == @selector(du:)) - return @"du"; - else if (selector == @selector(statfs:)) - return @"statfs"; - else - return nil; -} - -+ (BOOL) isSelectorExcludedFromWebScript:(SEL)selector { - return [self webScriptNameForSelector:selector] == nil; -} - -- (BOOL) supports:(NSString *)feature { - return [feature isEqualToString:@"window.open"]; -} - -- (NSArray *) getInstalledPackages { - NSArray *packages([[Database sharedInstance] packages]); - NSMutableArray *installed([NSMutableArray arrayWithCapacity:[packages count]]); - for (Package *package in packages) - if ([package installed] != nil) - [installed addObject:package]; - return installed; -} - -- (Package *) getPackageById:(NSString *)id { - Package *package([[Database sharedInstance] packageWithName:id]); - [package parse]; - return package; -} - -- (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 */ - execl("/usr/libexec/cydia/du", "du", "-s", [path UTF8String], NULL); - exit(1); - _assert(false); - } - - _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)]; - } - } - - fclose(du); - } else _assert(close(fds[0])); - - int status; - wait: - if (waitpid(pid, &status, 0) == -1) - if (errno == EINTR) - goto wait; - else _assert(false); - - return value; -} - -- (void) close { - [indirect_ close]; -} - -- (void) installPackages:(NSArray *)packages { - [delegate_ performSelectorOnMainThread:@selector(installPackages:) withObject:packages waitUntilDone:NO]; -} - -- (void) setAutoPopup:(BOOL)popup { - [indirect_ setAutoPopup:popup]; -} - -- (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) setSpecial:(id)function { - [indirect_ setSpecial:function]; -} - -- (void) setToken:(NSString *)token { - if (Token_ != nil) - [Token_ release]; - Token_ = [token retain]; - - [Metadata_ setObject:Token_ forKey:@"Token"]; - Changed_ = true; -} - -- (void) setFinishHook:(id)function { - [indirect_ setFinishHook:function]; -} - -- (void) setPopupHook:(id)function { - [indirect_ setPopupHook:function]; -} - -- (void) setViewportWidth:(float)width { - [indirect_ setViewportWidth: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<va_list *>(&values))] autorelease]; -} - -- (NSString *) localizedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)table { - if (reinterpret_cast<id>(value) == [WebUndefined undefined]) - value = nil; - if (reinterpret_cast<id>(table) == [WebUndefined undefined]) - table = nil; - return [[NSBundle mainBundle] localizedStringForKey:key value:value table:table]; -} - -@end -/* }}} */ - -/* Cydia Browser Controller {{{ */ -@interface CYBrowserController : BrowserController { - CydiaObject *cydia_; -} - -@end - -@implementation CYBrowserController - -- (void) dealloc { - [cydia_ release]; - [super dealloc]; -} - -- (void) setHeaders:(NSDictionary *)headers forHost:(NSString *)host { -} - -- (void) webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame { - [super webView:sender didClearWindowObject:window forFrame:frame]; - - WebDataSource *source([frame dataSource]); - NSURLResponse *response([source response]); - NSURL *url([response URL]); - NSString *scheme([url scheme]); - - NSHTTPURLResponse *http; - if (scheme != nil && ([scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"])) - http = (NSHTTPURLResponse *) response; - else - http = nil; - - NSDictionary *headers([http allHeaderFields]); - NSString *host([url host]); - [self setHeaders:headers forHost:host]; - - if ( - [host isEqualToString:@"cydia.saurik.com"] || - [host hasSuffix:@".cydia.saurik.com"] || - [scheme isEqualToString:@"file"] - ) - [window setValue:cydia_ forKey:@"cydia"]; -} - -- (void) _setMoreHeaders:(NSMutableURLRequest *)request { - if (System_ != NULL) - [request setValue:System_ forHTTPHeaderField:@"X-System"]; - if (Machine_ != NULL) - [request setValue:[NSString stringWithUTF8String:Machine_] forHTTPHeaderField:@"X-Machine"]; - if (Token_ != nil) - [request setValue:Token_ forHTTPHeaderField:@"X-Cydia-Token"]; - if (Role_ != nil) - [request setValue:Role_ forHTTPHeaderField:@"X-Role"]; -} - -- (NSURLRequest *) webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)source { - NSMutableURLRequest *copy = [request mutableCopy]; - [self _setMoreHeaders:copy]; - return copy; -} - -- (void) setDelegate:(id)delegate { - [super setDelegate:delegate]; - [cydia_ setDelegate:delegate]; -} - -- (id) init { - if ((self = [super initWithWidth:0 ofClass:[CYBrowserController class]]) != nil) { - cydia_ = [[CydiaObject alloc] initWithDelegate:indirect_]; - - WebView *webview([document_ webView]); - - Package *package([[Database sharedInstance] packageWithName:@"cydia"]); - - NSString *application = package == nil ? @"Cydia" : [NSString - stringWithFormat:@"Cydia/%@", - [package installed] - ]; - - if (Safari_ != nil) - application = [NSString stringWithFormat:@"Safari/%@ %@", Safari_, application]; - if (Build_ != nil) - application = [NSString stringWithFormat:@"Mobile/%@ %@", Build_, application]; - if (Product_ != nil) - application = [NSString stringWithFormat:@"Version/%@ %@", Product_, application]; - - [webview setApplicationNameForUserAgent:application]; - } return self; -} - -@end -/* }}} */ - -/* Confirmation {{{ */ -@protocol ConfirmationControllerDelegate -- (void) cancelAndClear:(bool)clear; -- (void) confirmWithNavigationController:(UINavigationController *)navigation; -- (void) queue; -@end - -@interface ConfirmationController : CYBrowserController { - _transient Database *database_; - UIAlertView *essential_; - NSArray *changes_; - NSArray *issues_; - NSArray *sizes_; - BOOL substrate_; -} - -- (id) initWithDatabase:(Database *)database; - -@end - -@implementation ConfirmationController - -- (void) dealloc { - [changes_ release]; - if (issues_ != nil) - [issues_ release]; - [sizes_ release]; - if (essential_ != nil) - [essential_ release]; - [super dealloc]; -} - -- (void) alertView:(UIAlertView *)alert clickedButtonAtIndex:(NSInteger)button { - NSString *context([alert context]); - - if ([context isEqualToString:@"remove"]) { - if (button == [alert cancelButtonIndex]) { - [self dismissModalViewControllerAnimated:YES]; - } else if (button == [alert firstOtherButtonIndex]) { - if (substrate_) - Finish_ = 2; - [delegate_ confirmWithNavigationController:[self navigationController]]; - } - - [alert dismissWithClickedButtonIndex:-1 animated:YES]; - } else if ([context isEqualToString:@"unable"]) { - [self dismissModalViewControllerAnimated:YES]; - [alert dismissWithClickedButtonIndex:-1 animated:YES]; - } else { - [super alertView:alert clickedButtonAtIndex:button]; - } -} - -- (id) invokeDefaultMethodWithArguments:(NSArray *)args { - [self dismissModalViewControllerAnimated:YES]; - [delegate_ cancelAndClear:NO]; - - return nil; -} - -- (void) webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame { - [super webView:sender didClearWindowObject:window forFrame:frame]; - [window setValue:changes_ forKey:@"changes"]; - [window setValue:issues_ forKey:@"issues"]; - [window setValue:sizes_ forKey:@"sizes"]; - [window setValue:self forKey:@"queue"]; -} - -- (id) initWithDatabase:(Database *)database { - if ((self = [super init]) != nil) { - database_ = database; - - [[self navigationItem] setTitle:UCLocalize("CONFIRM")]; - - NSMutableArray *installing = [NSMutableArray arrayWithCapacity:16]; - NSMutableArray *reinstalling = [NSMutableArray arrayWithCapacity:16]; - NSMutableArray *upgrading = [NSMutableArray arrayWithCapacity:16]; - NSMutableArray *downgrading = [NSMutableArray arrayWithCapacity:16]; - NSMutableArray *removing = [NSMutableArray arrayWithCapacity:16]; - - bool remove(false); - - pkgDepCache::Policy *policy([database_ policy]); - - pkgCacheFile &cache([database_ cache]); - NSArray *packages = [database_ packages]; - for (Package *package in packages) { - pkgCache::PkgIterator iterator = [package iterator]; - pkgDepCache::StateCache &state(cache[iterator]); - - NSString *name([package name]); - - if (state.NewInstall()) - [installing addObject:name]; - else if (!state.Delete() && (state.iFlags & pkgDepCache::ReInstall) == pkgDepCache::ReInstall) - [reinstalling addObject:name]; - else if (state.Upgrade()) - [upgrading addObject:name]; - else if (state.Downgrade()) - [downgrading addObject:name]; - else if (state.Delete()) { - if ([package essential]) - remove = true; - [removing addObject:name]; - } else continue; - - substrate_ |= DepSubstrate(policy->GetCandidateVer(iterator)); - substrate_ |= DepSubstrate(iterator.CurrentVer()); - } - - if (!remove) - essential_ = nil; - else if (Advanced_) { - NSString *parenthetical(UCLocalize("PARENTHETICAL")); - - essential_ = [[UIAlertView alloc] - initWithTitle:UCLocalize("REMOVING_ESSENTIALS") - message:UCLocalize("REMOVING_ESSENTIALS_EX") - delegate:self - cancelButtonTitle:[NSString stringWithFormat:parenthetical, UCLocalize("CANCEL_OPERATION"), UCLocalize("SAFE")] - otherButtonTitles:[NSString stringWithFormat:parenthetical, UCLocalize("FORCE_REMOVAL"), UCLocalize("UNSAFE")], nil - ]; - - [essential_ setContext:@"remove"]; - } else { - essential_ = [[UIAlertView alloc] - initWithTitle:UCLocalize("UNABLE_TO_COMPLY") - message:UCLocalize("UNABLE_TO_COMPLY_EX") - delegate:self - cancelButtonTitle:UCLocalize("OKAY") - otherButtonTitles:nil - ]; - - [essential_ setContext:@"unable"]; - } - - changes_ = [[NSArray alloc] initWithObjects: - installing, - reinstalling, - upgrading, - downgrading, - removing, - nil]; - - issues_ = [database_ issues]; - if (issues_ != nil) - issues_ = [issues_ retain]; - - sizes_ = [[NSArray alloc] initWithObjects: - SizeString([database_ fetcher].FetchNeeded()), - SizeString([database_ fetcher].PartialPresent()), - nil]; - - [self loadURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"confirm" ofType:@"html"]]]; - - UIBarButtonItem *leftItem = [[UIBarButtonItem alloc] - initWithTitle:UCLocalize("CANCEL") - // OLD: [NSString stringWithFormat:UCLocalize("SLASH_DELIMITED"), UCLocalize("CANCEL"), UCLocalize("QUEUE")] - style:UIBarButtonItemStylePlain - target:self - action:@selector(cancelButtonClicked) - ]; - [[self navigationItem] setLeftBarButtonItem:leftItem]; - [leftItem release]; - } return self; -} - -- (void) applyRightButton { - UIBarButtonItem *rightItem = [[UIBarButtonItem alloc] - initWithTitle:UCLocalize("CONFIRM") - style:UIBarButtonItemStylePlain - target:self - action:@selector(confirmButtonClicked) - ]; -#if !AlwaysReload && !IgnoreInstall - if (issues_ == nil && ![self isLoading]) [[self navigationItem] setRightBarButtonItem:rightItem]; - else [super applyRightButton]; -#else - [[self navigationItem] setRightBarButtonItem:nil]; -#endif - [rightItem release]; -} - -- (void) cancelButtonClicked { - [self dismissModalViewControllerAnimated:YES]; - [delegate_ cancelAndClear:YES]; -} - -#if !AlwaysReload -- (void) confirmButtonClicked { -#if IgnoreInstall - return; -#endif - if (essential_ != nil) - [essential_ show]; - else { - if (substrate_) - Finish_ = 2; - [delegate_ confirmWithNavigationController:[self navigationController]]; - } -} -#endif - -@end -/* }}} */ - -/* Progress Data {{{ */ -@interface ProgressData : NSObject { - SEL selector_; - id target_; - id object_; -} - -- (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object; - -- (SEL) selector; -- (id) target; -- (id) object; -@end - -@implementation ProgressData - -- (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object { - if ((self = [super init]) != nil) { - selector_ = selector; - target_ = target; - object_ = object; - } return self; -} - -- (SEL) selector { - return selector_; -} - -- (id) target { - return target_; -} - -- (id) object { - return object_; -} - -@end -/* }}} */ -/* Progress Controller {{{ */ -@interface ProgressController : CYViewController < - ConfigurationDelegate, - ProgressDelegate -> { - _transient Database *database_; - UIProgressBar *progress_; - UITextView *output_; - UITextLabel *status_; - UIPushButton *close_; - BOOL running_; - SHA1SumValue springlist_; - SHA1SumValue notifyconf_; - NSString *title_; -} - -- (id) initWithDatabase:(Database *)database delegate:(id)delegate; - -- (void) _retachThread; -- (void) _detachNewThreadData:(ProgressData *)data; -- (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title; - -- (BOOL) isRunning; - -@end - -@protocol ProgressControllerDelegate -- (void) progressControllerIsComplete:(ProgressController *)sender; -@end - -@implementation ProgressController - -- (void) dealloc { - [database_ setDelegate:nil]; - [progress_ release]; - [output_ release]; - [status_ release]; - [close_ release]; - if (title_ != nil) - [title_ release]; - [super dealloc]; -} - -- (id) initWithDatabase:(Database *)database delegate:(id)delegate { - if ((self = [super init]) != nil) { - database_ = database; - [database_ setDelegate:self]; - delegate_ = delegate; - - [[self view] setBackgroundColor:[UIColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:1.0f]]; - - progress_ = [[UIProgressBar alloc] init]; - [progress_ setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin)]; - [progress_ setStyle:0]; - - status_ = [[UITextLabel alloc] init]; - [status_ setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin)]; - [status_ setColor:[UIColor whiteColor]]; - [status_ setBackgroundColor:[UIColor clearColor]]; - [status_ setCentersHorizontally:YES]; - //[status_ setFont:font]; - - output_ = [[UITextView alloc] init]; - - [output_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; - //[output_ setTextFont:@"Courier New"]; - [output_ setFont:[[output_ font] fontWithSize:12]]; - [output_ setTextColor:[UIColor whiteColor]]; - [output_ setBackgroundColor:[UIColor clearColor]]; - [output_ setMarginTop:0]; - [output_ setAllowsRubberBanding:YES]; - [output_ setEditable:NO]; - [[self view] addSubview:output_]; - - close_ = [[UIPushButton alloc] init]; - [close_ setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin)]; - [close_ setAutosizesToFit:NO]; - [close_ setDrawsShadow:YES]; - [close_ setStretchBackground:YES]; - [close_ setEnabled:YES]; - [close_ setTitleFont:[UIFont boldSystemFontOfSize:22]]; - [close_ addTarget:self action:@selector(closeButtonPushed) forEvents:UIControlEventTouchUpInside]; - [close_ setBackground:[UIImage applicationImageNamed:@"green-up.png"] forState:0]; - [close_ setBackground:[UIImage applicationImageNamed:@"green-dn.png"] forState:1]; - } return self; -} - -- (void) positionViews { - CGRect bounds = [[self view] bounds]; - CGSize prgsize = [UIProgressBar defaultSize]; - - CGRect prgrect = {{ - (bounds.size.width - prgsize.width) / 2, - bounds.size.height - prgsize.height - 64 - }, prgsize}; - - float closewidth = bounds.size.width - 20; - if (closewidth > 300) closewidth = 300; - - [progress_ setFrame:prgrect]; - [status_ setFrame:CGRectMake( - 10, - bounds.size.height - prgsize.height - 94, - bounds.size.width - 20, - 24 - )]; - [output_ setFrame:CGRectMake( - 10, - 20, - bounds.size.width - 20, - bounds.size.height - 106 - )]; - [close_ setFrame:CGRectMake( - (bounds.size.width - closewidth) / 2, - bounds.size.height - prgsize.height - 94, - closewidth, - 32 + prgsize.height - )]; -} - -- (void) viewWillAppear:(BOOL)animated { - [super viewDidAppear:animated]; - [[self navigationItem] setHidesBackButton:YES]; - [[[self navigationController] navigationBar] setBarStyle:UIBarStyleBlack]; - - [self positionViews]; -} - -- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { - [self positionViews]; -} - -- (void) alertView:(UIAlertView *)alert clickedButtonAtIndex:(NSInteger)button { - NSString *context([alert context]); - - if ([context isEqualToString:@"conffile"]) { - FILE *input = [database_ input]; - if (button == [alert cancelButtonIndex]) fprintf(input, "N\n"); - else if (button == [alert firstOtherButtonIndex]) fprintf(input, "Y\n"); - fflush(input); - } -} - -- (void) closeButtonPushed { - running_ = NO; - - UpdateExternalStatus(0); - - switch (Finish_) { - case 0: - [self dismissModalViewControllerAnimated:YES]; - break; - - case 1: - [delegate_ terminateWithSuccess]; - /*if ([delegate_ respondsToSelector:@selector(suspendWithAnimation:)]) - [delegate_ suspendWithAnimation:YES]; - else - [delegate_ suspend];*/ - break; - - case 2: - system("launchctl stop com.apple.SpringBoard"); - break; - - case 3: - system("launchctl unload "SpringBoard_"; launchctl load "SpringBoard_); - break; - - case 4: - system("reboot"); - break; - } -} - -- (void) _retachThread { - [[self navigationItem] setTitle:UCLocalize("COMPLETE")]; - - [[self view] addSubview:close_]; - [progress_ removeFromSuperview]; - [status_ removeFromSuperview]; - - [database_ popErrorWithTitle:title_]; - [delegate_ progressControllerIsComplete:self]; - - if (Finish_ < 4) { - FileFd file; - if (!file.Open(NotifyConfig_, FileFd::ReadOnly)) - _error->Discard(); - else { - MMap mmap(file, MMap::ReadOnly); - SHA1Summation sha1; - sha1.Add(reinterpret_cast<uint8_t *>(mmap.Data()), mmap.Size()); - if (!(notifyconf_ == sha1.Result())) - Finish_ = 4; - } - } - - if (Finish_ < 3) { - FileFd file; - if (!file.Open(SpringBoard_, FileFd::ReadOnly)) - _error->Discard(); - else { - MMap mmap(file, MMap::ReadOnly); - SHA1Summation sha1; - sha1.Add(reinterpret_cast<uint8_t *>(mmap.Data()), mmap.Size()); - if (!(springlist_ == sha1.Result())) - Finish_ = 3; - } - } - - switch (Finish_) { - case 0: [close_ setTitle:UCLocalize("RETURN_TO_CYDIA")]; break; /* XXX: Maybe UCLocalize("DONE")? */ - case 1: [close_ setTitle:UCLocalize("CLOSE_CYDIA")]; break; - case 2: [close_ setTitle:UCLocalize("RESTART_SPRINGBOARD")]; break; - case 3: [close_ setTitle:UCLocalize("RELOAD_SPRINGBOARD")]; break; - case 4: [close_ setTitle:UCLocalize("REBOOT_DEVICE")]; break; - } - - system("su -c /usr/bin/uicache mobile"); - - UpdateExternalStatus(Finish_ == 0 ? 2 : 0); - - [delegate_ setStatusBarShowsProgress:NO]; -} - -- (void) _detachNewThreadData:(ProgressData *)data { _pooled - [[data target] performSelector:[data selector] withObject:[data object]]; - [data release]; - - [self performSelectorOnMainThread:@selector(_retachThread) withObject:nil waitUntilDone:YES]; -} - -- (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title { - UpdateExternalStatus(1); - - if (title_ != nil) - [title_ release]; - if (title == nil) - title_ = nil; - else - title_ = [title retain]; - - [[self navigationItem] setTitle:title_]; - - [status_ setText:nil]; - [output_ setText:@""]; - [progress_ setProgress:0]; - - [close_ removeFromSuperview]; - [[self view] addSubview:progress_]; - [[self view] addSubview:status_]; - - [delegate_ setStatusBarShowsProgress:YES]; - running_ = YES; - - { - FileFd file; - if (!file.Open(NotifyConfig_, FileFd::ReadOnly)) - _error->Discard(); - else { - MMap mmap(file, MMap::ReadOnly); - SHA1Summation sha1; - sha1.Add(reinterpret_cast<uint8_t *>(mmap.Data()), mmap.Size()); - notifyconf_ = sha1.Result(); - } - } - - { - FileFd file; - if (!file.Open(SpringBoard_, FileFd::ReadOnly)) - _error->Discard(); - else { - MMap mmap(file, MMap::ReadOnly); - SHA1Summation sha1; - sha1.Add(reinterpret_cast<uint8_t *>(mmap.Data()), mmap.Size()); - springlist_ = sha1.Result(); - } - } - - [NSThread - detachNewThreadSelector:@selector(_detachNewThreadData:) - toTarget:self - withObject:[[ProgressData alloc] - initWithSelector:selector - target:target - object:object - ] - ]; -} - -- (void) repairWithSelector:(SEL)selector { - [self - detachNewThreadSelector:selector - toTarget:database_ - withObject:nil - title:UCLocalize("REPAIRING") - ]; -} - -- (void) setConfigurationData:(NSString *)data { - [self - performSelectorOnMainThread:@selector(_setConfigurationData:) - withObject:data - waitUntilDone:YES - ]; -} - -- (void) setProgressError:(NSString *)error withTitle:(NSString *)title { - CYActionSheet *sheet([[[CYActionSheet alloc] - initWithTitle:title - buttons:[NSArray arrayWithObjects:UCLocalize("OKAY"), nil] - defaultButtonIndex:0 - ] autorelease]); - - [sheet setMessage:error]; - [sheet yieldToPopupAlertAnimated:YES]; - [sheet dismiss]; -} - -- (void) setProgressTitle:(NSString *)title { - [self - performSelectorOnMainThread:@selector(_setProgressTitle:) - withObject:title - waitUntilDone:YES - ]; -} - -- (void) setProgressPercent:(float)percent { - [self - performSelectorOnMainThread:@selector(_setProgressPercent:) - withObject:[NSNumber numberWithFloat:percent] - waitUntilDone:YES - ]; -} - -- (void) startProgress { -} - -- (void) addProgressOutput:(NSString *)output { - [self - performSelectorOnMainThread:@selector(_addProgressOutput:) - withObject:output - waitUntilDone:YES - ]; -} - -- (bool) isCancelling:(size_t)received { - return false; -} - -- (void) _setConfigurationData:(NSString *)data { - static Pcre conffile_r("^'(.*)' '(.*)' ([01]) ([01])$"); - - if (!conffile_r(data)) { - lprintf("E:invalid conffile\n"); - return; - } - - NSString *ofile = conffile_r[1]; - //NSString *nfile = conffile_r[2]; - - UIAlertView *alert = [[[UIAlertView alloc] - initWithTitle:UCLocalize("CONFIGURATION_UPGRADE") - message:[NSString stringWithFormat:@"%@\n\n%@", UCLocalize("CONFIGURATION_UPGRADE_EX"), ofile] - delegate:self - cancelButtonTitle:UCLocalize("KEEP_OLD_COPY") - otherButtonTitles:UCLocalize("ACCEPT_NEW_COPY"), - // XXX: UCLocalize("SEE_WHAT_CHANGED"), - nil - ] autorelease]; - - [alert setContext:@"conffile"]; - [alert show]; -} - -- (void) _setProgressTitle:(NSString *)title { - NSMutableArray *words([[title componentsSeparatedByString:@" "] mutableCopy]); - for (size_t i(0), e([words count]); i != e; ++i) { - NSString *word([words objectAtIndex:i]); - if (Package *package = [database_ packageWithName:word]) - [words replaceObjectAtIndex:i withObject:[package name]]; - } - - [status_ setText:[words componentsJoinedByString:@" "]]; -} - -- (void) _setProgressPercent:(NSNumber *)percent { - [progress_ setProgress:[percent floatValue]]; -} - -- (void) _addProgressOutput:(NSString *)output { - [output_ setText:[NSString stringWithFormat:@"%@\n%@", [output_ text], output]]; - CGSize size = [output_ contentSize]; - CGRect rect = {{0, size.height}, {size.width, 0}}; - [output_ scrollRectToVisible:rect animated:YES]; -} - -- (BOOL) isRunning { - return running_; -} - -@end -/* }}} */ - -/* Cell Content View {{{ */ -@protocol ContentDelegate -- (void) drawContentRect:(CGRect)rect; -@end - -@interface ContentView : UIView { - _transient id<ContentDelegate> delegate_; -} - -@end - -@implementation ContentView -- (id) initWithFrame:(CGRect)frame { - if ((self = [super initWithFrame:frame]) != nil) { - /* Fix landscape stretching. */ - [self setNeedsDisplayOnBoundsChange:YES]; - } return self; -} - -- (void) setDelegate:(id<ContentDelegate>)delegate { - delegate_ = delegate; -} - -- (void) drawRect:(CGRect)rect { - [super drawRect:rect]; - [delegate_ drawContentRect:rect]; -} -@end -/* }}} */ -/* Package Cell {{{ */ -@interface PackageCell : UITableViewCell < - ContentDelegate -> { - UIImage *icon_; - NSString *name_; - NSString *description_; - bool commercial_; - NSString *source_; - UIImage *badge_; - Package *package_; - UIColor *color_; - ContentView *content_; - BOOL faded_; - float fade_; - UIImage *placard_; -} - -- (PackageCell *) init; -- (void) setPackage:(Package *)package; - -+ (int) heightForPackage:(Package *)package; -- (void) drawContentRect:(CGRect)rect; - -@end - -@implementation PackageCell - -- (void) clearPackage { - if (icon_ != nil) { - [icon_ release]; - icon_ = nil; - } - - if (name_ != nil) { - [name_ release]; - name_ = nil; - } - - if (description_ != nil) { - [description_ release]; - description_ = nil; - } - - if (source_ != nil) { - [source_ release]; - source_ = nil; - } - - if (badge_ != nil) { - [badge_ release]; - badge_ = nil; - } - - if (placard_ != nil) { - [placard_ release]; - placard_ = nil; - } - - [package_ release]; - package_ = nil; -} - -- (void) dealloc { - [self clearPackage]; - [content_ release]; - [color_ release]; - [super dealloc]; -} - -- (float) fade { - return faded_ ? [self selectionPercent] : fade_; -} - -- (PackageCell *) init { - CGRect frame(CGRectMake(0, 0, 320, 74)); - if ((self = [super initWithFrame:frame reuseIdentifier:@"Package"]) != nil) { - UIView *content([self contentView]); - CGRect bounds([content bounds]); - - content_ = [[ContentView alloc] initWithFrame:bounds]; - [content_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; - [content addSubview:content_]; - - [content_ setDelegate:self]; - [content_ setOpaque:YES]; - if ([self respondsToSelector:@selector(selectionPercent)]) - faded_ = YES; - } return self; -} - -- (void) _setBackgroundColor { - UIColor *color; - if (NSString *mode = [package_ mode]) { - bool remove([mode isEqualToString:@"REMOVE"] || [mode isEqualToString:@"PURGE"]); - color = remove ? RemovingColor_ : InstallingColor_; - } else - color = [UIColor whiteColor]; - - [content_ setBackgroundColor:color]; - [self setNeedsDisplay]; -} - -- (void) setPackage:(Package *)package { - [self clearPackage]; - [package parse]; - - Source *source = [package source]; - - icon_ = [[package icon] retain]; - name_ = [[package name] retain]; - - if (IsWildcat_) - description_ = [package longDescription]; - if (description_ == nil) - description_ = [package shortDescription]; - if (description_ != nil) - description_ = [description_ retain]; - - commercial_ = [package isCommercial]; - - package_ = [package retain]; - - NSString *label = nil; - bool trusted = false; - - if (source != nil) { - label = [source label]; - trusted = [source trusted]; - } else if ([[package id] isEqualToString:@"firmware"]) - label = UCLocalize("APPLE"); - else - label = [NSString stringWithFormat:UCLocalize("SLASH_DELIMITED"), UCLocalize("UNKNOWN"), UCLocalize("LOCAL")]; - - NSString *from(label); - - NSString *section = [package simpleSection]; - if (section != nil && ![section isEqualToString:label]) { - section = [[NSBundle mainBundle] localizedStringForKey:section value:nil table:@"Sections"]; - from = [NSString stringWithFormat:UCLocalize("PARENTHETICAL"), from, section]; - } - - from = [NSString stringWithFormat:UCLocalize("FROM"), from]; - source_ = [from retain]; - - if (NSString *purpose = [package primaryPurpose]) - if ((badge_ = [UIImage imageAtPath:[NSString stringWithFormat:@"%@/Purposes/%@.png", App_, purpose]]) != nil) - badge_ = [badge_ retain]; - - if ([package installed] != nil) - if ((placard_ = [UIImage imageAtPath:[NSString stringWithFormat:@"%@/installed.png", App_]]) != nil) - placard_ = [placard_ retain]; - - [self _setBackgroundColor]; - [content_ setNeedsDisplay]; -} - -- (void) drawContentRect:(CGRect)rect { - bool selected([self isSelected]); - float width([self bounds].size.width); - -#if 0 - CGContextRef context(UIGraphicsGetCurrentContext()); - [([[self selectedBackgroundView] superview] != nil ? [UIColor clearColor] : [self backgroundColor]) set]; - CGContextFillRect(context, rect); -#endif - - if (icon_ != nil) { - CGRect rect; - rect.size = [icon_ size]; - - rect.size.width /= 2; - rect.size.height /= 2; - - rect.origin.x = 25 - rect.size.width / 2; - rect.origin.y = 25 - rect.size.height / 2; - - [icon_ drawInRect:rect]; - } - - if (badge_ != nil) { - CGSize size = [badge_ size]; - - [badge_ drawAtPoint:CGPointMake( - 36 - size.width / 2, - 36 - size.height / 2 - )]; - } - - if (selected) - UISetColor(White_); - - if (!selected) - UISetColor(commercial_ ? Purple_ : Black_); - [name_ drawAtPoint:CGPointMake(48, 8) forWidth:(width - (placard_ == nil ? 80 : 106)) withFont:Font18Bold_ lineBreakMode:UILineBreakModeTailTruncation]; - [source_ drawAtPoint:CGPointMake(58, 29) forWidth:(width - 95) withFont:Font12_ lineBreakMode:UILineBreakModeTailTruncation]; - - if (!selected) - UISetColor(commercial_ ? Purplish_ : Gray_); - [description_ drawAtPoint:CGPointMake(12, 46) forWidth:(width - 46) withFont:Font14_ lineBreakMode:UILineBreakModeTailTruncation]; - - if (placard_ != nil) - [placard_ drawAtPoint:CGPointMake(width - 52, 9)]; -} - -- (void) setSelected:(BOOL)selected animated:(BOOL)fade { - //[self _setBackgroundColor]; - [super setSelected:selected animated:fade]; - [content_ setNeedsDisplay]; -} - -+ (int) heightForPackage:(Package *)package { - return 73; -} - -@end -/* }}} */ -/* Section Cell {{{ */ -@interface SectionCell : UITableViewCell < - ContentDelegate -> { - NSString *basic_; - NSString *section_; - NSString *name_; - NSString *count_; - UIImage *icon_; - ContentView *content_; - id switch_; - BOOL editing_; -} - -- (void) setSection:(Section *)section editing:(BOOL)editing; - -@end - -@implementation SectionCell - -- (void) clearSection { - if (basic_ != nil) { - [basic_ release]; - basic_ = nil; - } - - if (section_ != nil) { - [section_ release]; - section_ = nil; - } - - if (name_ != nil) { - [name_ release]; - name_ = nil; - } - - if (count_ != nil) { - [count_ release]; - count_ = nil; - } -} - -- (void) dealloc { - [self clearSection]; - [icon_ release]; - [switch_ release]; - [content_ release]; - - [super dealloc]; -} - -- (id) initWithFrame:(CGRect)frame reuseIdentifier:(NSString *)reuseIdentifier { - if ((self = [super initWithFrame:frame reuseIdentifier:reuseIdentifier]) != nil) { - icon_ = [[UIImage applicationImageNamed:@"folder.png"] retain]; - switch_ = [[objc_getClass("UISwitch") alloc] initWithFrame:CGRectMake(218, 9, 60, 25)]; - [switch_ addTarget:self action:@selector(onSwitch:) forEvents:UIControlEventValueChanged]; - - UIView *content([self contentView]); - CGRect bounds([content bounds]); - - content_ = [[ContentView alloc] initWithFrame:bounds]; - [content_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; - [content addSubview:content_]; - [content_ setBackgroundColor:[UIColor whiteColor]]; - - [content_ setDelegate:self]; - } return self; -} - -- (void) onSwitch:(id)sender { - NSMutableDictionary *metadata = [Sections_ objectForKey:basic_]; - if (metadata == nil) { - metadata = [NSMutableDictionary dictionaryWithCapacity:2]; - [Sections_ setObject:metadata forKey:basic_]; - } - - Changed_ = true; - [metadata setObject:[NSNumber numberWithBool:([switch_ isOn] == NO)] forKey:@"Hidden"]; -} - -- (void) setSection:(Section *)section editing:(BOOL)editing { - if (editing != editing_) { - if (editing_) - [switch_ removeFromSuperview]; - else - [self addSubview:switch_]; - editing_ = editing; - } - - [self clearSection]; - - if (section == nil) { - name_ = [UCLocalize("ALL_PACKAGES") retain]; - count_ = nil; - } else { - basic_ = [section name]; - if (basic_ != nil) - basic_ = [basic_ retain]; - - section_ = [section localized]; - if (section_ != nil) - section_ = [section_ retain]; - - name_ = [(section_ == nil || [section_ length] == 0 ? UCLocalize("NO_SECTION") : section_) retain]; - count_ = [[NSString stringWithFormat:@"%d", [section count]] retain]; - - if (editing_) - [switch_ setOn:(isSectionVisible(basic_) ? 1 : 0) animated:NO]; - } - - [self setAccessoryType:editing ? UITableViewCellAccessoryNone : UITableViewCellAccessoryDisclosureIndicator]; - [content_ setNeedsDisplay]; -} - -- (void) setFrame:(CGRect)frame { - [super setFrame:frame]; - - CGRect rect([switch_ frame]); - [switch_ setFrame:CGRectMake(frame.size.width - 102, 9, rect.size.width, rect.size.height)]; -} - -- (void) drawContentRect:(CGRect)rect { - BOOL selected = [self isSelected]; - - [icon_ drawInRect:CGRectMake(8, 7, 32, 32)]; - - if (selected) - UISetColor(White_); - - if (!selected) - UISetColor(Black_); - - float width(rect.size.width); - if (editing_) - width -= 87; - - [name_ drawAtPoint:CGPointMake(48, 9) forWidth:(width - 70) withFont:Font22Bold_ lineBreakMode:UILineBreakModeTailTruncation]; - - CGSize size = [count_ sizeWithFont:Font14_]; - - UISetColor(White_); - if (count_ != nil) - [count_ drawAtPoint:CGPointMake(13 + (29 - size.width) / 2, 16) withFont:Font12Bold_]; -} - -@end -/* }}} */ - -/* File Table {{{ */ -@interface FileTable : CYViewController < - UITableViewDataSource, - UITableViewDelegate -> { - _transient Database *database_; - Package *package_; - NSString *name_; - NSMutableArray *files_; - UITableView *list_; -} - -- (id) initWithDatabase:(Database *)database; -- (void) setPackage:(Package *)package; - -@end - -@implementation FileTable - -- (void) dealloc { - if (package_ != nil) - [package_ release]; - if (name_ != nil) - [name_ release]; - [files_ release]; - [list_ release]; - [super dealloc]; -} - -- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - return files_ == nil ? 0 : [files_ count]; -} - -/*- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { - return 24.0f; -}*/ - -- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { - static NSString *reuseIdentifier = @"Cell"; - - UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier]; - if (cell == nil) { - cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:reuseIdentifier] autorelease]; - [cell setFont:[UIFont systemFontOfSize:16]]; - } - [cell setText:[files_ objectAtIndex:indexPath.row]]; - [cell setSelectionStyle:UITableViewCellSelectionStyleNone]; - - return cell; -} - -- (id) initWithDatabase:(Database *)database { - if ((self = [super init]) != nil) { - database_ = database; - - [[self navigationItem] setTitle:UCLocalize("INSTALLED_FILES")]; - - files_ = [[NSMutableArray arrayWithCapacity:32] retain]; - - list_ = [[UITableView alloc] initWithFrame:[[self view] bounds]]; - [list_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; - [list_ setRowHeight:24.0f]; - [[self view] addSubview:list_]; - - [list_ setDataSource:self]; - [list_ setDelegate:self]; - } return self; -} - -- (void) setPackage:(Package *)package { - if (package_ != nil) { - [package_ autorelease]; - package_ = nil; - } - - if (name_ != nil) { - [name_ release]; - name_ = nil; - } - - [files_ removeAllObjects]; - - if (package != nil) { - package_ = [package retain]; - name_ = [[package id] retain]; - - if (NSArray *files = [package files]) - [files_ addObjectsFromArray:files]; - - if ([files_ count] != 0) { - if ([[files_ objectAtIndex:0] isEqualToString:@"/."]) - [files_ removeObjectAtIndex:0]; - [files_ sortUsingSelector:@selector(compareByPath:)]; - - NSMutableArray *stack = [NSMutableArray arrayWithCapacity:8]; - [stack addObject:@"/"]; - - for (int i(0), e([files_ count]); i != e; ++i) { - NSString *file = [files_ objectAtIndex:i]; - while (![file hasPrefix:[stack lastObject]]) - [stack removeLastObject]; - NSString *directory = [stack lastObject]; - [stack addObject:[file stringByAppendingString:@"/"]]; - [files_ replaceObjectAtIndex:i withObject:[NSString stringWithFormat:@"%*s%@", - ([stack count] - 2) * 3, "", - [file substringFromIndex:[directory length]] - ]]; - } - } - } - - [list_ reloadData]; -} - -- (void) reloadData { - [self setPackage:[database_ packageWithName:name_]]; -} - -@end -/* }}} */ -/* Package Controller {{{ */ -@interface PackageController : CYBrowserController < - UIActionSheetDelegate -> { - _transient Database *database_; - Package *package_; - NSString *name_; - bool commercial_; - NSMutableArray *buttons_; -} - -- (id) initWithDatabase:(Database *)database; -- (void) setPackage:(Package *)package; - -@end - -@implementation PackageController - -- (void) dealloc { - if (package_ != nil) - [package_ release]; - if (name_ != nil) - [name_ release]; - [buttons_ release]; - [super dealloc]; -} - -- (void) release { - if ([self retainCount] == 1) - [delegate_ setPackageController:self]; - [super release]; -} - -/* XXX: this is not safe at all... localization of /fail/ */ -- (void) _clickButtonWithName:(NSString *)name { - if ([name isEqualToString:UCLocalize("CLEAR")]) - [delegate_ clearPackage:package_]; - else if ([name isEqualToString:UCLocalize("INSTALL")]) - [delegate_ installPackage:package_]; - else if ([name isEqualToString:UCLocalize("REINSTALL")]) - [delegate_ installPackage:package_]; - else if ([name isEqualToString:UCLocalize("REMOVE")]) - [delegate_ removePackage:package_]; - else if ([name isEqualToString:UCLocalize("UPGRADE")]) - [delegate_ installPackage:package_]; - else _assert(false); -} - -- (void) actionSheet:(UIActionSheet *)sheet clickedButtonAtIndex:(NSInteger)button { - NSString *context([sheet context]); - - if ([context isEqualToString:@"modify"]) { - if (button != [sheet cancelButtonIndex]) { - NSString *buttonName = [buttons_ objectAtIndex:button]; - [self _clickButtonWithName:buttonName]; - } - - [sheet dismissWithClickedButtonIndex:-1 animated:YES]; - } -} - -- (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame { - return [super webView:sender didFinishLoadForFrame:frame]; -} - -- (void) webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame { - [super webView:sender didClearWindowObject:window forFrame:frame]; - [window setValue:package_ forKey:@"package"]; -} - -- (bool) _allowJavaScriptPanel { - return commercial_; -} - -#if !AlwaysReload -- (void) _customButtonClicked { - int count([buttons_ count]); - if (count == 0) - return; - - if (count == 1) - [self _clickButtonWithName:[buttons_ objectAtIndex:0]]; - else { - NSMutableArray *buttons = [NSMutableArray arrayWithCapacity:count]; - [buttons addObjectsFromArray:buttons_]; - - UIActionSheet *sheet = [[[UIActionSheet alloc] - initWithTitle:nil - delegate:self - cancelButtonTitle:nil - destructiveButtonTitle:nil - 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"]; - - [delegate_ showActionSheet:sheet fromItem:[[self navigationItem] rightBarButtonItem]]; - } -} - -// We don't want to allow non-commercial packages to do custom things to the install button, -// so it must call customButtonClicked with a custom commercial_ == 1 fallthrough. -- (void) customButtonClicked { - if (commercial_) - [super customButtonClicked]; - else - [self _customButtonClicked]; -} - -- (void) reloadButtonClicked { - // Don't reload a package view by clicking the button. -} - -- (void) applyLoadingTitle { - // Don't show "Loading" as the title. Ever. -} - -- (UIBarButtonItem *) rightButton { - int count = [buttons_ count]; - return [[[UIBarButtonItem alloc] - initWithTitle:count == 0 ? nil : count != 1 ? UCLocalize("MODIFY") : [buttons_ objectAtIndex:0] - style:UIBarButtonItemStylePlain - target:self - action:@selector(customButtonClicked) - ] autorelease]; -} -#endif - -- (id) initWithDatabase:(Database *)database { - if ((self = [super init]) != nil) { - database_ = database; - buttons_ = [[NSMutableArray alloc] initWithCapacity:4]; - [self loadURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"package" ofType:@"html"]]]; - } return self; -} - -- (void) setPackage:(Package *)package { - if (package_ != nil) { - [package_ autorelease]; - package_ = nil; - } - - if (name_ != nil) { - [name_ release]; - name_ = nil; - } - - [buttons_ removeAllObjects]; - - if (package != nil) { - [package parse]; - - package_ = [package retain]; - name_ = [[package id] retain]; - commercial_ = [package isCommercial]; - - if ([package_ mode] != nil) - [buttons_ addObject:UCLocalize("CLEAR")]; - if ([package_ source] == nil); - else if ([package_ upgradableAndEssential:NO]) - [buttons_ addObject:UCLocalize("UPGRADE")]; - else if ([package_ uninstalled]) - [buttons_ addObject:UCLocalize("INSTALL")]; - else - [buttons_ addObject:UCLocalize("REINSTALL")]; - if (![package_ uninstalled]) - [buttons_ addObject:UCLocalize("REMOVE")]; - - if (special_ != NULL) { - CGRect frame([document_ frame]); - frame.size.height = 0; - [document_ setFrame:frame]; - - if ([scroller_ respondsToSelector:@selector(scrollPointVisibleAtTopLeft:)]) - [scroller_ scrollPointVisibleAtTopLeft:CGPointZero]; - else - [scroller_ scrollRectToVisible:CGRectZero animated:NO]; - - WebThreadLock(); - [[[document_ webView] windowScriptObject] setValue:package_ forKey:@"package"]; - - [self setButtonTitle:nil withStyle:nil toFunction:nil]; - - [self setFinishHook:nil]; - [self setPopupHook:nil]; - WebThreadUnlock(); - - //[self yieldToSelector:@selector(callFunction:) withObject:special_]; - [super callFunction:special_]; - } - } -} - -- (bool) isLoading { - return commercial_ ? [super isLoading] : false; -} - -- (void) reloadData { - [self setPackage:[database_ packageWithName:name_]]; -} - -@end -/* }}} */ -/* Package Table {{{ */ -@interface PackageTable : UIView < - UITableViewDataSource, - UITableViewDelegate -> { - _transient Database *database_; - NSMutableArray *packages_; - NSMutableArray *sections_; - UITableView *list_; - NSMutableArray *index_; - NSMutableDictionary *indices_; - id target_; - SEL action_; - id delegate_; -} - -- (id) initWithFrame:(CGRect)frame database:(Database *)database target:(id)target action:(SEL)action; - -- (void) setDelegate:(id)delegate; - -- (void) reloadData; -- (void) resetCursor; - -- (UITableView *) list; - -- (void) setShouldHideHeaderInShortLists:(BOOL)hide; - -- (void) deselectWithAnimation:(BOOL)animated; - -@end - -@implementation PackageTable - -- (void) dealloc { - [packages_ release]; - [sections_ release]; - [list_ release]; - [index_ release]; - [indices_ release]; - - [super dealloc]; -} - -- (NSInteger) numberOfSectionsInTableView:(UITableView *)list { - NSInteger count([sections_ count]); - return count == 0 ? 1 : count; -} - -- (NSString *) tableView:(UITableView *)list titleForHeaderInSection:(NSInteger)section { - if ([sections_ count] == 0) - return nil; - return [[sections_ objectAtIndex:section] name]; -} - -- (NSInteger) tableView:(UITableView *)list numberOfRowsInSection:(NSInteger)section { - if ([sections_ count] == 0) - return 0; - return [[sections_ objectAtIndex:section] count]; -} - -- (Package *) packageAtIndexPath:(NSIndexPath *)path { - Section *section([sections_ objectAtIndex:[path section]]); - NSInteger row([path row]); - Package *package([packages_ objectAtIndex:([section row] + row)]); - return package; -} - -- (UITableViewCell *) tableView:(UITableView *)table cellForRowAtIndexPath:(NSIndexPath *)path { - PackageCell *cell((PackageCell *) [table dequeueReusableCellWithIdentifier:@"Package"]); - if (cell == nil) - cell = [[[PackageCell alloc] init] autorelease]; - [cell setPackage:[self packageAtIndexPath:path]]; - return cell; -} - -- (void) deselectWithAnimation:(BOOL)animated { - [list_ deselectRowAtIndexPath:[list_ indexPathForSelectedRow] animated:animated]; -} - -/*- (CGFloat) tableView:(UITableView *)table heightForRowAtIndexPath:(NSIndexPath *)path { - return [PackageCell heightForPackage:[self packageAtIndexPath:path]]; -}*/ - -- (NSIndexPath *) tableView:(UITableView *)table willSelectRowAtIndexPath:(NSIndexPath *)path { - Package *package([self packageAtIndexPath:path]); - package = [database_ packageWithName:[package id]]; - [target_ performSelector:action_ withObject:package]; - return path; -} - -- (NSArray *) sectionIndexTitlesForTableView:(UITableView *)tableView { - return [packages_ count] > 20 ? index_ : nil; -} - -- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index { - return index; -} - -- (id) initWithFrame:(CGRect)frame database:(Database *)database target:(id)target action:(SEL)action { - if ((self = [super initWithFrame:frame]) != nil) { - database_ = database; - - target_ = target; - action_ = action; - - index_ = [[NSMutableArray alloc] initWithCapacity:32]; - indices_ = [[NSMutableDictionary alloc] initWithCapacity:32]; - - packages_ = [[NSMutableArray arrayWithCapacity:16] retain]; - sections_ = [[NSMutableArray arrayWithCapacity:16] retain]; - - list_ = [[UITableView alloc] initWithFrame:[self bounds] style:UITableViewStylePlain]; - [list_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; - [list_ setRowHeight:73.0f]; - [self addSubview:list_]; - - [list_ setDataSource:self]; - [list_ setDelegate:self]; - } return self; -} - -- (void) setDelegate:(id)delegate { - delegate_ = delegate; -} - -- (bool) hasPackage:(Package *)package { - return true; -} - -- (void) reloadData { - NSArray *packages = [database_ packages]; - - [packages_ removeAllObjects]; - [sections_ removeAllObjects]; - - _profile(PackageTable$reloadData$Filter) - for (Package *package in packages) - if ([self hasPackage:package]) - [packages_ addObject:package]; - _end - - [index_ removeAllObjects]; - [indices_ removeAllObjects]; - - Section *section = nil; - - _profile(PackageTable$reloadData$Section) - for (size_t offset(0), end([packages_ count]); offset != end; ++offset) { - Package *package; - unichar index; - - _profile(PackageTable$reloadData$Section$Package) - package = [packages_ objectAtIndex:offset]; - index = [package index]; - _end - - if (section == nil || [section index] != index) { - _profile(PackageTable$reloadData$Section$Allocate) - section = [[[Section alloc] initWithIndex:index row:offset] autorelease]; - _end - - [index_ addObject:[section name]]; - //[indices_ setObject:[NSNumber numberForInt:[sections_ count]] forKey:index]; - - _profile(PackageTable$reloadData$Section$Add) - [sections_ addObject:section]; - _end - } - - [section addToCount]; - } - _end - - _profile(PackageTable$reloadData$List) - [list_ reloadData]; - _end -} - -- (void) resetCursor { - [list_ scrollRectToVisible:CGRectMake(0, 0, 0, 0) animated:NO]; -} - -- (UITableView *) list { - return list_; -} - -- (void) setShouldHideHeaderInShortLists:(BOOL)hide { - //XXX:[list_ setShouldHideHeaderInShortLists:hide]; -} - -@end -/* }}} */ -/* Filtered Package Table {{{ */ -@interface FilteredPackageTable : PackageTable { - SEL filter_; - IMP imp_; - id object_; -} - -- (void) setObject:(id)object; -- (void) setObject:(id)object forFilter:(SEL)filter; - -- (id) initWithFrame:(CGRect)frame database:(Database *)database target:(id)target action:(SEL)action filter:(SEL)filter with:(id)object; - -@end - -@implementation FilteredPackageTable - -- (void) dealloc { - if (object_ != nil) - [object_ release]; - [super dealloc]; -} - -- (void) setFilter:(SEL)filter { - filter_ = filter; - - /* XXX: this is an unsafe optimization of doomy hell */ - Method method(class_getInstanceMethod([Package class], filter)); - _assert(method != NULL); - imp_ = method_getImplementation(method); - _assert(imp_ != NULL); -} - -- (void) setObject:(id)object { - if (object_ != nil) - [object_ release]; - if (object == nil) - object_ = nil; - else - object_ = [object retain]; -} - -- (void) setObject:(id)object forFilter:(SEL)filter { - [self setFilter:filter]; - [self setObject:object]; -} - -- (bool) hasPackage:(Package *)package { - _profile(FilteredPackageTable$hasPackage) - return [package valid] && (*reinterpret_cast<bool (*)(id, SEL, id)>(imp_))(package, filter_, object_); - _end -} - -- (id) initWithFrame:(CGRect)frame database:(Database *)database target:(id)target action:(SEL)action filter:(SEL)filter with:(id)object { - if ((self = [super initWithFrame:frame database:database target:target action:action]) != nil) { - [self setFilter:filter]; - object_ = [object retain]; - [self reloadData]; - } return self; -} - -@end -/* }}} */ - -/* Filtered Package Controller {{{ */ -@interface FilteredPackageController : CYViewController { - _transient Database *database_; - FilteredPackageTable *packages_; - NSString *title_; -} - -- (id) initWithDatabase:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object; - -@end - -@implementation FilteredPackageController - -- (void) dealloc { - [packages_ release]; - [title_ release]; - - [super dealloc]; -} - -- (void) viewDidAppear:(BOOL)animated { - [super viewDidAppear:animated]; - [packages_ deselectWithAnimation:animated]; -} - -- (void) didSelectPackage:(Package *)package { - PackageController *view([delegate_ packageController]); - [view setPackage:package]; - [view setDelegate:delegate_]; - [[self navigationController] pushViewController:view animated:YES]; -} - -- (NSString *) title { return title_; } - -- (id) initWithDatabase:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object { - if ((self = [super init]) != nil) { - database_ = database; - title_ = [title copy]; - [[self navigationItem] setTitle:title_]; - - packages_ = [[FilteredPackageTable alloc] - initWithFrame:[[self view] bounds] - database:database - target:self - action:@selector(didSelectPackage:) - filter:filter - with:object - ]; - - [packages_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; - [[self view] addSubview:packages_]; - } return self; -} - -- (void) reloadData { - [packages_ reloadData]; -} - -- (void) setDelegate:(id)delegate { - [super setDelegate:delegate]; - [packages_ setDelegate:delegate]; -} - -@end - -/* }}} */ - -/* Add Source Controller {{{ */ -@interface AddSourceController : CYViewController { - _transient Database *database_; -} - -- (id) initWithDatabase:(Database *)database; - -@end - -@implementation AddSourceController - -- (id) initWithDatabase:(Database *)database { - if ((self = [super init]) != nil) { - database_ = database; - } return self; -} - -@end -/* }}} */ -/* Source Cell {{{ */ -@interface SourceCell : UITableViewCell < - ContentDelegate -> { - UIImage *icon_; - NSString *origin_; - NSString *description_; - NSString *label_; - ContentView *content_; -} - -- (void) setSource:(Source *)source; - -@end - -@implementation SourceCell - -- (void) clearSource { - [icon_ release]; - [origin_ release]; - [description_ release]; - [label_ release]; - - icon_ = nil; - origin_ = nil; - description_ = nil; - label_ = nil; -} - -- (void) setSource:(Source *)source { - [self clearSource]; - - if (icon_ == nil) - icon_ = [UIImage applicationImageNamed:[NSString stringWithFormat:@"Sources/%@.png", [source host]]]; - if (icon_ == nil) - icon_ = [UIImage applicationImageNamed:@"unknown.png"]; - icon_ = [icon_ retain]; - - origin_ = [[source name] retain]; - label_ = [[source uri] retain]; - description_ = [[source description] retain]; - - [content_ setNeedsDisplay]; -} - -- (void) dealloc { - [self clearSource]; - [content_ release]; - [super dealloc]; -} - -- (SourceCell *) initWithFrame:(CGRect)frame reuseIdentifier:(NSString *)reuseIdentifier { - if ((self = [super initWithFrame:frame reuseIdentifier:reuseIdentifier]) != nil) { - UIView *content([self contentView]); - CGRect bounds([content bounds]); - - content_ = [[ContentView alloc] initWithFrame:bounds]; - [content_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; - [content_ setBackgroundColor:[UIColor whiteColor]]; - [content addSubview:content_]; - - [content_ setDelegate:self]; - [content_ setOpaque:YES]; - } return self; -} - -- (void) setSelected:(BOOL)selected animated:(BOOL)animated { - [super setSelected:selected animated:animated]; - [content_ setNeedsDisplay]; -} - -- (void) drawContentRect:(CGRect)rect { - bool selected([self isSelected]); - float width(rect.size.width); - - if (icon_ != nil) - [icon_ drawInRect:CGRectMake(10, 10, 30, 30)]; - - if (selected) - UISetColor(White_); - - if (!selected) - UISetColor(Black_); - [origin_ drawAtPoint:CGPointMake(48, 8) forWidth:(width - 80) withFont:Font18Bold_ lineBreakMode:UILineBreakModeTailTruncation]; - - if (!selected) - UISetColor(Blue_); - [label_ drawAtPoint:CGPointMake(58, 29) forWidth:(width - 95) withFont:Font12_ lineBreakMode:UILineBreakModeTailTruncation]; - - if (!selected) - UISetColor(Gray_); - [description_ drawAtPoint:CGPointMake(12, 46) forWidth:(width - 40) withFont:Font14_ lineBreakMode:UILineBreakModeTailTruncation]; -} - -@end -/* }}} */ -/* Source Table {{{ */ -@interface SourceTable : CYViewController < - UITableViewDataSource, - UITableViewDelegate -> { - _transient Database *database_; - UITableView *list_; - NSMutableArray *sources_; - int offset_; - - NSString *href_; - UIProgressHUD *hud_; - NSError *error_; - - //NSURLConnection *installer_; - NSURLConnection *trivial_; - NSURLConnection *trivial_bz2_; - NSURLConnection *trivial_gz_; - //NSURLConnection *automatic_; - - BOOL cydia_; -} - -- (id) initWithDatabase:(Database *)database; - -- (void) updateButtonsForEditingStatus:(BOOL)editing animated:(BOOL)animated; - -@end - -@implementation SourceTable - -- (void) _deallocConnection:(NSURLConnection *)connection { - if (connection != nil) { - [connection cancel]; - //[connection setDelegate:nil]; - [connection release]; - } -} - -- (void) dealloc { - if (href_ != nil) - [href_ release]; - if (hud_ != nil) - [hud_ release]; - if (error_ != nil) - [error_ release]; - - //[self _deallocConnection:installer_]; - [self _deallocConnection:trivial_]; - [self _deallocConnection:trivial_gz_]; - [self _deallocConnection:trivial_bz2_]; - //[self _deallocConnection:automatic_]; - - [sources_ release]; - [list_ release]; - [super dealloc]; -} - -- (void) viewDidAppear:(BOOL)animated { - [super viewDidAppear:animated]; - [list_ deselectRowAtIndexPath:[list_ indexPathForSelectedRow] animated:animated]; -} - -- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView { - return offset_ == 0 ? 1 : 2; -} - -- (NSString *) tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { - switch (section + (offset_ == 0 ? 1 : 0)) { - case 0: return UCLocalize("ENTERED_BY_USER"); - case 1: return UCLocalize("INSTALLED_BY_PACKAGE"); - - _nodefault - } -} - -- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - int count = [sources_ count]; - switch (section) { - case 0: return (offset_ == 0 ? count : offset_); - case 1: return count - offset_; - - _nodefault - } -} - -- (Source *) sourceAtIndexPath:(NSIndexPath *)indexPath { - unsigned idx = 0; - switch (indexPath.section) { - case 0: idx = indexPath.row; break; - case 1: idx = indexPath.row + offset_; break; - - _nodefault - } - return [sources_ objectAtIndex:idx]; -} - -- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { - Source *source = [self sourceAtIndexPath:indexPath]; - return [source description] == nil ? 56 : 73; -} - -- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { - static NSString *cellIdentifier = @"SourceCell"; - - SourceCell *cell = (SourceCell *) [tableView dequeueReusableCellWithIdentifier:cellIdentifier]; - if(cell == nil) cell = [[[SourceCell alloc] initWithFrame:CGRectZero reuseIdentifier:cellIdentifier] autorelease]; - [cell setSource:[self sourceAtIndexPath:indexPath]]; - - return cell; -} - -- (UITableViewCellAccessoryType) tableView:(UITableView *)tableView accessoryTypeForRowWithIndexPath:(NSIndexPath *)indexPath { - return UITableViewCellAccessoryDisclosureIndicator; -} - -- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { - Source *source = [self sourceAtIndexPath:indexPath]; - - FilteredPackageController *packages = [[[FilteredPackageController alloc] - initWithDatabase:database_ - title:[source label] - filter:@selector(isVisibleInSource:) - with:source - ] autorelease]; - - [packages setDelegate:delegate_]; - - [[self navigationController] pushViewController:packages animated:YES]; -} - -- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { - Source *source = [self sourceAtIndexPath:indexPath]; - return [source record] != nil; -} - -- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { - Source *source = [self sourceAtIndexPath:indexPath]; - [Sources_ removeObjectForKey:[source key]]; - [delegate_ syncData]; -} - -- (void) complete { - [Sources_ setObject:[NSDictionary dictionaryWithObjectsAndKeys: - @"deb", @"Type", - href_, @"URI", - @"./", @"Distribution", - nil] forKey:[NSString stringWithFormat:@"deb:%@:./", href_]]; - - [delegate_ syncData]; -} - -- (NSString *) getWarning { - NSString *href(href_); - NSRange colon([href rangeOfString:@"://"]); - if (colon.location != NSNotFound) - href = [href substringFromIndex:(colon.location + 3)]; - href = [href stringByAddingPercentEscapes]; - href = [CydiaURL(@"api/repotag/") stringByAppendingString:href]; - href = [href stringByCachingURLWithCurrentCDN]; - - NSURL *url([NSURL URLWithString:href]); - - NSStringEncoding encoding; - NSError *error(nil); - - if (NSString *warning = [NSString stringWithContentsOfURL:url usedEncoding:&encoding error:&error]) - return [warning length] == 0 ? nil : warning; - return nil; -} - -- (void) _endConnection:(NSURLConnection *)connection { - NSURLConnection **field = NULL; - if (connection == trivial_) - field = &trivial_; - else if (connection == trivial_bz2_) - field = &trivial_bz2_; - else if (connection == trivial_gz_) - field = &trivial_gz_; - _assert(field != NULL); - [connection release]; - *field = nil; - - if ( - trivial_ == nil && - trivial_bz2_ == nil && - trivial_gz_ == nil - ) { - bool defer(false); - - if (cydia_) { - if (NSString *warning = [self yieldToSelector:@selector(getWarning)]) { - defer = true; - - UIAlertView *alert = [[[UIAlertView alloc] - initWithTitle:UCLocalize("SOURCE_WARNING") - message:warning - delegate:self - cancelButtonTitle:UCLocalize("CANCEL") - otherButtonTitles:UCLocalize("ADD_ANYWAY"), nil - ] autorelease]; - - [alert setContext:@"warning"]; - [alert setNumberOfRows:1]; - [alert show]; - } else - [self complete]; - } else if (error_ != nil) { - UIAlertView *alert = [[[UIAlertView alloc] - initWithTitle:UCLocalize("VERIFICATION_ERROR") - message:[error_ localizedDescription] - delegate:self - cancelButtonTitle:UCLocalize("OK") - otherButtonTitles:nil - ] autorelease]; - - [alert setContext:@"urlerror"]; - [alert show]; - } else { - UIAlertView *alert = [[[UIAlertView alloc] - initWithTitle:UCLocalize("NOT_REPOSITORY") - message:UCLocalize("NOT_REPOSITORY_EX") - delegate:self - cancelButtonTitle:UCLocalize("OK") - otherButtonTitles:nil - ] autorelease]; - - [alert setContext:@"trivial"]; - [alert show]; - } - - [delegate_ setStatusBarShowsProgress:NO]; - [delegate_ removeProgressHUD:hud_]; - - [hud_ autorelease]; - hud_ = nil; - - if (!defer) { - [href_ release]; - href_ = nil; - } - - if (error_ != nil) { - [error_ release]; - error_ = nil; - } - } -} - -- (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response { - switch ([response statusCode]) { - case 200: - cydia_ = YES; - } -} - -- (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { - lprintf("connection:\"%s\" didFailWithError:\"%s\"", [href_ UTF8String], [[error localizedDescription] UTF8String]); - if (error_ != nil) - error_ = [error retain]; - [self _endConnection:connection]; -} - -- (void) connectionDidFinishLoading:(NSURLConnection *)connection { - [self _endConnection:connection]; -} - -- (NSString *) title { return UCLocalize("SOURCES"); } - -- (NSURLConnection *) _requestHRef:(NSString *)href method:(NSString *)method { - NSMutableURLRequest *request = [NSMutableURLRequest - requestWithURL:[NSURL URLWithString:href] - cachePolicy:NSURLRequestUseProtocolCachePolicy - timeoutInterval:120.0 - ]; - - [request setHTTPMethod:method]; - - if (Machine_ != NULL) - [request setValue:[NSString stringWithUTF8String:Machine_] forHTTPHeaderField:@"X-Machine"]; - if (UniqueID_ != nil) - [request setValue:UniqueID_ forHTTPHeaderField:@"X-Unique-ID"]; - if (Role_ != nil) - [request setValue:Role_ forHTTPHeaderField:@"X-Role"]; - - return [[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease]; -} - -- (void)alertView:(UIAlertView *)alert clickedButtonAtIndex:(NSInteger)button { - NSString *context([alert context]); - - if ([context isEqualToString:@"source"]) { - switch (button) { - case 1: { - NSString *href = [[alert textField] text]; - - //installer_ = [[self _requestHRef:href method:@"GET"] retain]; - - if (![href hasSuffix:@"/"]) - href_ = [href stringByAppendingString:@"/"]; - else - href_ = href; - href_ = [href_ retain]; - - trivial_ = [[self _requestHRef:[href_ stringByAppendingString:@"Packages"] method:@"HEAD"] retain]; - trivial_bz2_ = [[self _requestHRef:[href_ stringByAppendingString:@"Packages.bz2"] method:@"HEAD"] retain]; - trivial_gz_ = [[self _requestHRef:[href_ stringByAppendingString:@"Packages.gz"] method:@"HEAD"] retain]; - //trivial_bz2_ = [[self _requestHRef:[href stringByAppendingString:@"dists/Release"] method:@"HEAD"] retain]; - - cydia_ = false; - - hud_ = [[delegate_ addProgressHUD] retain]; - [hud_ setText:UCLocalize("VERIFYING_URL")]; - } break; - - case 0: - break; - - _nodefault - } - - [alert dismissWithClickedButtonIndex:-1 animated:YES]; - } else if ([context isEqualToString:@"trivial"]) - [alert dismissWithClickedButtonIndex:-1 animated:YES]; - else if ([context isEqualToString:@"urlerror"]) - [alert dismissWithClickedButtonIndex:-1 animated:YES]; - else if ([context isEqualToString:@"warning"]) { - switch (button) { - case 1: - [self complete]; - break; - - case 0: - break; - - _nodefault - } - - [href_ release]; - href_ = nil; - - [alert dismissWithClickedButtonIndex:-1 animated:YES]; - } -} - -- (id) initWithDatabase:(Database *)database { - if ((self = [super init]) != nil) { - [[self navigationItem] setTitle:UCLocalize("SOURCES")]; - [self updateButtonsForEditingStatus:NO animated:NO]; - - database_ = database; - sources_ = [[NSMutableArray arrayWithCapacity:16] retain]; - - list_ = [[UITableView alloc] initWithFrame:[[self view] bounds] style:UITableViewStylePlain]; - [list_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; - [[self view] addSubview:list_]; - - [list_ setDataSource:self]; - [list_ setDelegate:self]; - - [self reloadData]; - } return self; -} - -- (void) reloadData { - pkgSourceList list; - if (!list.ReadMainList()) - return; - - [sources_ removeAllObjects]; - [sources_ addObjectsFromArray:[database_ sources]]; - _trace(); - [sources_ sortUsingSelector:@selector(compareByNameAndType:)]; - _trace(); - - int count([sources_ count]); - offset_ = 0; - for (int i = 0; i != count; i++) { - if ([[sources_ objectAtIndex:i] record] == nil) break; - else offset_++; - } - - [list_ setEditing:NO]; - [self updateButtonsForEditingStatus:NO animated:NO]; - [list_ reloadData]; -} - -- (void) addButtonClicked { - /*[book_ pushPage:[[[AddSourceController alloc] - initWithBook:book_ - database:database_ - ] autorelease]];*/ - - UIAlertView *alert = [[[UIAlertView alloc] - initWithTitle:UCLocalize("ENTER_APT_URL") - message:nil - delegate:self - cancelButtonTitle:UCLocalize("CANCEL") - otherButtonTitles:UCLocalize("ADD_SOURCE"), nil - ] autorelease]; - - [alert setContext:@"source"]; - [alert setTransform:CGAffineTransformTranslate([alert transform], 0.0, 100.0)]; - - [alert setNumberOfRows:1]; - [alert addTextFieldWithValue:@"http://" label:@""]; - - UITextInputTraits *traits = [[alert textField] textInputTraits]; - [traits setAutocapitalizationType:UITextAutocapitalizationTypeNone]; - [traits setAutocorrectionType:UITextAutocorrectionTypeNo]; - [traits setKeyboardType:UIKeyboardTypeURL]; - // XXX: UIReturnKeyDone - [traits setReturnKeyType:UIReturnKeyNext]; - - [alert show]; -} - -- (void) updateButtonsForEditingStatus:(BOOL)editing animated:(BOOL)animated { - UIBarButtonItem *leftItem = [[UIBarButtonItem alloc] - initWithTitle:UCLocalize("ADD") - style:UIBarButtonItemStylePlain - target:self - action:@selector(addButtonClicked) - ]; - [[self navigationItem] setLeftBarButtonItem:editing ? leftItem : [[self navigationItem] backBarButtonItem] animated:animated]; - [leftItem release]; - - UIBarButtonItem *rightItem = [[UIBarButtonItem alloc] - initWithTitle:editing ? UCLocalize("DONE") : UCLocalize("EDIT") - style:editing ? UIBarButtonItemStyleDone : UIBarButtonItemStylePlain - target:self - action:@selector(editButtonClicked) - ]; - [[self navigationItem] setRightBarButtonItem:rightItem animated:animated]; - [rightItem release]; - - if (IsWildcat_ && !editing) { - UIBarButtonItem *settingsItem = [[UIBarButtonItem alloc] - initWithTitle:UCLocalize("SETTINGS") - style:UIBarButtonItemStylePlain - target:self - action:@selector(settingsButtonClicked) - ]; - [[self navigationItem] setLeftBarButtonItem:settingsItem]; - [settingsItem release]; - } -} - -- (void) settingsButtonClicked { - [delegate_ showSettings]; -} - -- (void) editButtonClicked { - [list_ setEditing:![list_ isEditing] animated:YES]; - - [self updateButtonsForEditingStatus:[list_ isEditing] animated:YES]; -} - -@end -/* }}} */ - -/* Installed Controller {{{ */ -@interface InstalledController : FilteredPackageController { - BOOL expert_; -} - -- (id) initWithDatabase:(Database *)database; - -- (void) updateRoleButton; -- (void) queueStatusDidChange; - -@end - -@implementation InstalledController - -- (void) dealloc { - [super dealloc]; -} - -- (NSString *) title { return UCLocalize("INSTALLED"); } - -- (id) initWithDatabase:(Database *)database { - if ((self = [super initWithDatabase:database title:UCLocalize("INSTALLED") filter:@selector(isInstalledAndVisible:) with:[NSNumber numberWithBool:YES]]) != nil) { - [self updateRoleButton]; - [self queueStatusDidChange]; - } return self; -} - -#if !AlwaysReload -- (void) queueButtonClicked { - [delegate_ queue]; -} -#endif - -- (void) queueStatusDidChange { -#if !AlwaysReload - if (IsWildcat_) { - UIBarButtonItem *queueItem = [[UIBarButtonItem alloc] - initWithTitle:UCLocalize("QUEUE") - style:UIBarButtonItemStyleDone - target:self - action:@selector(queueButtonClicked) - ]; - if (Queuing_) [[self navigationItem] setLeftBarButtonItem:queueItem]; - else [[self navigationItem] setLeftBarButtonItem:nil]; - [queueItem release]; - } -#endif -} - -- (void) reloadData { - [packages_ reloadData]; -} - -- (void) updateRoleButton { - UIBarButtonItem *rightItem = [[UIBarButtonItem alloc] - initWithTitle:expert_ ? UCLocalize("EXPERT") : UCLocalize("SIMPLE") - style:expert_ ? UIBarButtonItemStyleDone : UIBarButtonItemStylePlain - target:self - action:@selector(roleButtonClicked) - ]; - if (Role_ != nil && ![Role_ isEqualToString:@"Developer"]) [[self navigationItem] setRightBarButtonItem:rightItem]; - [rightItem release]; -} - -- (void) roleButtonClicked { - [packages_ setObject:[NSNumber numberWithBool:expert_]]; - [packages_ reloadData]; - expert_ = !expert_; - - [self updateRoleButton]; -} - -- (void) setDelegate:(id)delegate { - [super setDelegate:delegate]; - [packages_ setDelegate:delegate]; -} - -@end -/* }}} */ - -/* Home Controller {{{ */ -@interface HomeController : CYBrowserController { -} - -@end - -@implementation HomeController - -- (void) _setMoreHeaders:(NSMutableURLRequest *)request { - [super _setMoreHeaders:request]; - if (ChipID_ != nil) - [request setValue:ChipID_ forHTTPHeaderField:@"X-Chip-ID"]; - if (UniqueID_ != nil) - [request setValue:UniqueID_ forHTTPHeaderField:@"X-Unique-ID"]; -} - -- (void) aboutButtonClicked { - UIAlertView *alert = [[[UIAlertView alloc] init] autorelease]; - [alert setTitle:UCLocalize("ABOUT_CYDIA")]; - [alert addButtonWithTitle:UCLocalize("CLOSE")]; - [alert setCancelButtonIndex:0]; - - [alert setMessage: - @"Copyright (C) 2008-2010\n" - "Jay Freeman (saurik)\n" - "saurik@saurik.com\n" - "http://www.saurik.com/" - ]; - - [alert show]; -} - -- (void) viewWillAppear:(BOOL)animated { - [super viewWillAppear:animated]; - [[self navigationController] setNavigationBarHidden:YES animated:animated]; -} - -- (void) viewWillDisappear:(BOOL)animated { - [super viewWillDisappear:animated]; - [[self navigationController] setNavigationBarHidden:NO animated:animated]; -} - -- (id) init { - if ((self = [super init]) != nil) { - UIBarButtonItem *aboutItem = [[UIBarButtonItem alloc] - initWithTitle:UCLocalize("ABOUT") - style:UIBarButtonItemStylePlain - target:self - action:@selector(aboutButtonClicked) - ]; - [[self navigationItem] setLeftBarButtonItem:aboutItem]; - [aboutItem release]; - } return self; -} - -@end -/* }}} */ -/* Manage Controller {{{ */ -@interface ManageController : CYBrowserController { -} - -- (void) queueStatusDidChange; -@end - -@implementation ManageController - -- (id) init { - if ((self = [super init]) != nil) { - [[self navigationItem] setTitle:UCLocalize("MANAGE")]; - - UIBarButtonItem *settingsItem = [[UIBarButtonItem alloc] - initWithTitle:UCLocalize("SETTINGS") - style:UIBarButtonItemStylePlain - target:self - action:@selector(settingsButtonClicked) - ]; - [[self navigationItem] setLeftBarButtonItem:settingsItem]; - [settingsItem release]; - - [self queueStatusDidChange]; - } return self; -} - -- (void) settingsButtonClicked { - [delegate_ showSettings]; -} - -#if !AlwaysReload -- (void) queueButtonClicked { - [delegate_ queue]; -} - -- (void) applyLoadingTitle { - // No "Loading" title. -} - -- (void) applyRightButton { - // No right button. -} -#endif - -- (void) queueStatusDidChange { -#if !AlwaysReload - if (!IsWildcat_ && Queuing_) { - UIBarButtonItem *queueItem = [[UIBarButtonItem alloc] - initWithTitle:UCLocalize("QUEUE") - style:UIBarButtonItemStyleDone - target:self - action:@selector(queueButtonClicked) - ]; - [[self navigationItem] setRightBarButtonItem:queueItem]; - - [queueItem release]; - } else { - [[self navigationItem] setRightBarButtonItem:nil]; - } -#endif -} - -- (bool) isLoading { - return false; -} - -@end -/* }}} */ - -/* Refresh Bar {{{ */ -@interface RefreshBar : UINavigationBar { - UIProgressIndicator *indicator_; - UITextLabel *prompt_; - UIProgressBar *progress_; - UINavigationButton *cancel_; -} - -@end - -@implementation RefreshBar - -- (void) positionViews { - CGRect frame = [cancel_ frame]; - frame.origin.x = [self frame].size.width - frame.size.width - 5; - frame.origin.y = ([self frame].size.height - frame.size.height) / 2; - [cancel_ setFrame:frame]; - - CGSize prgsize = {75, 100}; - CGRect prgrect = {{ - [self frame].size.width - prgsize.width - 10, - ([self frame].size.height - prgsize.height) / 2 - } , prgsize}; - [progress_ setFrame:prgrect]; - - CGSize indsize([UIProgressIndicator defaultSizeForStyle:[indicator_ activityIndicatorViewStyle]]); - unsigned indoffset = ([self frame].size.height - indsize.height) / 2; - CGRect indrect = {{indoffset, indoffset}, indsize}; - [indicator_ setFrame:indrect]; - - CGSize prmsize = {215, indsize.height + 4}; - CGRect prmrect = {{ - indoffset * 2 + indsize.width, - unsigned([self frame].size.height - prmsize.height) / 2 - 1 - }, prmsize}; - [prompt_ setFrame:prmrect]; -} - -- (void)setFrame:(CGRect)frame { - [super setFrame:frame]; - - [self positionViews]; -} - -- (id) initWithFrame:(CGRect)frame delegate:(id)delegate { - if ((self = [super initWithFrame:frame])) { - [self setAutoresizingMask:UIViewAutoresizingFlexibleWidth]; - - [self setTintColor:[UIColor colorWithRed:0.23 green:0.23 blue:0.23 alpha:1]]; - [self setBarStyle:UIBarStyleBlack]; - - UIBarStyle barstyle([self _barStyle:NO]); - bool ugly(barstyle == UIBarStyleDefault); - - UIProgressIndicatorStyle style = ugly ? - UIProgressIndicatorStyleMediumBrown : - UIProgressIndicatorStyleMediumWhite; - - indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectZero]; - [indicator_ setStyle:style]; - [indicator_ startAnimation]; - [self addSubview:indicator_]; - - prompt_ = [[UITextLabel alloc] initWithFrame:CGRectZero]; - [prompt_ setColor:[UIColor colorWithCGColor:(ugly ? Blueish_ : Off_)]]; - [prompt_ setBackgroundColor:[UIColor clearColor]]; - [prompt_ setFont:[UIFont systemFontOfSize:15]]; - [self addSubview:prompt_]; - - progress_ = [[UIProgressBar alloc] initWithFrame:CGRectZero]; - [progress_ setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleLeftMargin]; - [progress_ setStyle:0]; - [self addSubview:progress_]; - - cancel_ = [[UINavigationButton alloc] initWithTitle:UCLocalize("CANCEL") style:UINavigationButtonStyleHighlighted]; - [cancel_ setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin]; - [cancel_ addTarget:delegate action:@selector(cancelPressed) forControlEvents:UIControlEventTouchUpInside]; - [cancel_ setBarStyle:barstyle]; - - [self positionViews]; - } return self; -} - -- (void) cancel { - [cancel_ removeFromSuperview]; -} - -- (void) start { - [prompt_ setText:UCLocalize("UPDATING_DATABASE")]; - [progress_ setProgress:0]; - [self addSubview:cancel_]; -} - -- (void) stop { - [cancel_ removeFromSuperview]; -} - -- (void) setPrompt:(NSString *)prompt { - [prompt_ setText:prompt]; -} - -- (void) setProgress:(float)progress { - [progress_ setProgress:progress]; -} - -@end -/* }}} */ - -@class CYNavigationController; - -/* Cydia Tab Bar Controller {{{ */ -@interface CYTabBarController : UITabBarController { - Database *database_; -} - -@end - -@implementation CYTabBarController - -/* XXX: some logic should probably go here related to -freeing the view controllers on tab change */ - -- (void) reloadData { - size_t count([[self viewControllers] count]); - for (size_t i(0); i != count; ++i) { - CYNavigationController *page([[self viewControllers] objectAtIndex:(count - i - 1)]); - [page reloadData]; - } -} - -- (id) initWithDatabase:(Database *)database { - if ((self = [super init]) != nil) { - database_ = database; - } return self; -} - -@end -/* }}} */ - -/* Cydia Navigation Controller {{{ */ -@interface CYNavigationController : UINavigationController { - _transient Database *database_; - id<UINavigationControllerDelegate> delegate_; -} - -- (id) initWithDatabase:(Database *)database; -- (void) reloadData; - -@end - - -@implementation CYNavigationController - -- (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orientation { - // Inherit autorotation settings for modal parents. - if ([self parentViewController] && [[self parentViewController] modalViewController] == self) { - return [[self parentViewController] shouldAutorotateToInterfaceOrientation:orientation]; - } else { - return [super shouldAutorotateToInterfaceOrientation:orientation]; - } -} - -- (void) dealloc { - [super dealloc]; -} - -- (void) reloadData { - size_t count([[self viewControllers] count]); - for (size_t i(0); i != count; ++i) { - CYViewController *page([[self viewControllers] objectAtIndex:(count - i - 1)]); - [page reloadData]; - } -} - -- (void) setDelegate:(id<UINavigationControllerDelegate>)delegate { - delegate_ = delegate; -} - -- (id) initWithDatabase:(Database *)database { - if ((self = [super init]) != nil) { - database_ = database; - } return self; -} - -@end -/* }}} */ -/* Cydia:// Protocol {{{ */ -@interface CydiaURLProtocol : NSURLProtocol { -} - -@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 NO; - return YES; -} - -+ (NSURLRequest *) canonicalRequestForRequest:(NSURLRequest *)request { - return request; -} - -- (void) _returnPNGWithImage:(UIImage *)icon forRequest:(NSURLRequest *)request { - id<NSURLProtocolClient> 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<NSURLProtocolClient> client([self client]); - NSURLRequest *request([self request]); - - NSURL *url([request URL]); - NSString *href([url absoluteString]); - - NSString *path([href substringFromIndex:8]); - NSRange slash([path rangeOfString:@"/"]); - - NSString *command; - if (slash.location == NSNotFound) { - command = path; - path = nil; - } else { - command = [path substringToIndex:slash.location]; - path = [path substringFromIndex:(slash.location + 1)]; - } - - Database *database([Database sharedInstance]); - - if ([command isEqualToString:@"package-icon"]) { - if (path == nil) - goto fail; - path = [path stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; - Package *package([database packageWithName:path]); - if (package == nil) - goto fail; - UIImage *icon([package icon]); - [self _returnPNGWithImage:icon forRequest:request]; - } else if ([command isEqualToString:@"source-icon"]) { - if (path == nil) - goto fail; - path = [path stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; - NSString *source(Simplify(path)); - UIImage *icon([UIImage imageAtPath:[NSString stringWithFormat:@"%@/Sources/%@.png", App_, source]]); - if (icon == nil) - icon = [UIImage applicationImageNamed:@"unknown.png"]; - [self _returnPNGWithImage:icon forRequest:request]; - } else if ([command isEqualToString:@"uikit-image"]) { - if (path == nil) - goto fail; - path = [path stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; - UIImage *icon(_UIImageWithName(path)); - [self _returnPNGWithImage:icon forRequest:request]; - } else if ([command isEqualToString:@"section-icon"]) { - if (path == nil) - goto fail; - path = [path stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; - NSString *section(Simplify(path)); - UIImage *icon([UIImage imageAtPath:[NSString stringWithFormat:@"%@/Sections/%@.png", App_, section]]); - if (icon == nil) - icon = [UIImage applicationImageNamed:@"unknown.png"]; - [self _returnPNGWithImage:icon forRequest:request]; - } else fail: { - [client URLProtocol:self didFailWithError:[NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorResourceUnavailable userInfo:nil]]; - } -} - -- (void) stopLoading { -} - -@end -/* }}} */ - -/* Sections Controller {{{ */ -@interface SectionsController : CYViewController < - UITableViewDataSource, - UITableViewDelegate -> { - _transient Database *database_; - NSMutableArray *sections_; - NSMutableArray *filtered_; - UITableView *list_; - UIView *accessory_; - BOOL editing_; -} - -- (id) initWithDatabase:(Database *)database; -- (void) reloadData; -- (void) resetView; - -- (void) editButtonClicked; - -@end - -@implementation SectionsController - -- (void) dealloc { - [list_ setDataSource:nil]; - [list_ setDelegate:nil]; - - [sections_ release]; - [filtered_ release]; - [list_ release]; - [accessory_ release]; - [super dealloc]; -} - -- (void) viewDidAppear:(BOOL)animated { - [super viewDidAppear:animated]; - [list_ deselectRowAtIndexPath:[list_ indexPathForSelectedRow] animated:animated]; -} - -- (Section *) sectionAtIndexPath:(NSIndexPath *)indexPath { - Section *section = (editing_ ? [sections_ objectAtIndex:[indexPath row]] : ([indexPath row] == 0 ? nil : [filtered_ objectAtIndex:([indexPath row] - 1)])); - return section; -} - -- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - return editing_ ? [sections_ count] : [filtered_ count] + 1; -} - -/*- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { - return 45.0f; -}*/ - -- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { - static NSString *reuseIdentifier = @"SectionCell"; - - SectionCell *cell = (SectionCell *) [tableView dequeueReusableCellWithIdentifier:reuseIdentifier]; - if (cell == nil) cell = [[[SectionCell alloc] initWithFrame:CGRectZero reuseIdentifier:reuseIdentifier] autorelease]; - [cell setSection:[self sectionAtIndexPath:indexPath] editing:editing_]; - - return cell; -} - -- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { - Section *section = [self sectionAtIndexPath:indexPath]; - NSString *name = [section name]; - NSString *title; - - if ([indexPath row] == 0) { - section = nil; - name = nil; - title = UCLocalize("ALL_PACKAGES"); - } else { - if (name != nil) { - name = [NSString stringWithString:name]; - title = [[NSBundle mainBundle] localizedStringForKey:Simplify(name) value:nil table:@"Sections"]; - } else { - name = @""; - title = UCLocalize("NO_SECTION"); - } - } - - FilteredPackageController *table = [[[FilteredPackageController alloc] - initWithDatabase:database_ - title:title - filter:@selector(isVisibleInSection:) - with:name - ] autorelease]; - - [table setDelegate:delegate_]; - - [[self navigationController] pushViewController:table animated:YES]; -} - -- (NSString *) title { return UCLocalize("SECTIONS"); } - -- (id) initWithDatabase:(Database *)database { - if ((self = [super init]) != nil) { - database_ = database; - - [[self navigationItem] setTitle:UCLocalize("SECTIONS")]; - - sections_ = [[NSMutableArray arrayWithCapacity:16] retain]; - filtered_ = [[NSMutableArray arrayWithCapacity:16] retain]; - - list_ = [[UITableView alloc] initWithFrame:[[self view] bounds]]; - [list_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; - [list_ setRowHeight:45.0f]; - [[self view] addSubview:list_]; - - [list_ setDataSource:self]; - [list_ setDelegate:self]; - - [self reloadData]; - } return self; -} - -- (void) reloadData { - NSArray *packages = [database_ packages]; - - [sections_ removeAllObjects]; - [filtered_ removeAllObjects]; - -#if 0 - typedef __gnu_cxx::hash_map<NSString *, Section *, NSStringMapHash, NSStringMapEqual> SectionMap; - SectionMap sections; - sections.resize(64); -#else - NSMutableDictionary *sections([NSMutableDictionary dictionaryWithCapacity:32]); -#endif - - _trace(); - for (Package *package in packages) { - NSString *name([package section]); - NSString *key(name == nil ? @"" : name); - -#if 0 - Section **section; - - _profile(SectionsView$reloadData$Section) - section = §ions[key]; - if (*section == nil) { - _profile(SectionsView$reloadData$Section$Allocate) - *section = [[[Section alloc] initWithName:name localize:YES] autorelease]; - _end - } - _end - - [*section addToCount]; - - _profile(SectionsView$reloadData$Filter) - if (![package valid] || ![package visible]) - continue; - _end - - [*section addToRow]; -#else - Section *section; - - _profile(SectionsView$reloadData$Section) - section = [sections objectForKey:key]; - if (section == nil) { - _profile(SectionsView$reloadData$Section$Allocate) - section = [[[Section alloc] initWithName:name localize:YES] autorelease]; - [sections setObject:section forKey:key]; - _end - } - _end - - [section addToCount]; - - _profile(SectionsView$reloadData$Filter) - if (![package valid] || ![package visible]) - continue; - _end - - [section addToRow]; -#endif - } - _trace(); - -#if 0 - for (SectionMap::const_iterator i(sections.begin()), e(sections.end()); i != e; ++i) - [sections_ addObject:i->second]; -#else - [sections_ addObjectsFromArray:[sections allValues]]; -#endif - - [sections_ sortUsingSelector:@selector(compareByLocalized:)]; - - for (Section *section in sections_) { - size_t count([section row]); - if (count == 0) - continue; - - section = [[[Section alloc] initWithName:[section name] localized:[section localized]] autorelease]; - [section setCount:count]; - [filtered_ addObject:section]; - } - - UIBarButtonItem *rightItem = [[UIBarButtonItem alloc] - initWithTitle:[sections_ count] == 0 ? nil : UCLocalize("EDIT") - style:UIBarButtonItemStylePlain - target:self - action:@selector(editButtonClicked) - ]; - [[self navigationItem] setRightBarButtonItem:rightItem animated:[[self navigationItem] rightBarButtonItem] != nil]; - [rightItem release]; - - [list_ reloadData]; - _trace(); -} - -- (void) resetView { - if (editing_) - [self editButtonClicked]; -} - -- (void) editButtonClicked { - if ((editing_ = !editing_)) - [list_ reloadData]; - else - [delegate_ updateData]; - - [[self navigationItem] setTitle:editing_ ? UCLocalize("SECTION_VISIBILITY") : UCLocalize("SECTIONS")]; - [[[self navigationItem] rightBarButtonItem] setTitle:[sections_ count] == 0 ? nil : editing_ ? UCLocalize("DONE") : UCLocalize("EDIT")]; - [[[self navigationItem] rightBarButtonItem] setStyle:editing_ ? UIBarButtonItemStyleDone : UIBarButtonItemStylePlain]; -} - -- (UIView *) accessoryView { - return accessory_; -} - -@end -/* }}} */ -/* Changes Controller {{{ */ -@interface ChangesController : CYViewController < - UITableViewDataSource, - UITableViewDelegate -> { - _transient Database *database_; - NSMutableArray *packages_; - NSMutableArray *sections_; - UITableView *list_; - unsigned upgrades_; - BOOL hasSentFirstLoad_; -} - -- (id) initWithDatabase:(Database *)database delegate:(id)delegate; -- (void) reloadData; - -@end - -@implementation ChangesController - -- (void) dealloc { - [list_ setDelegate:nil]; - [list_ setDataSource:nil]; - - [packages_ release]; - [sections_ release]; - [list_ release]; - [super dealloc]; -} - -- (void) viewDidAppear:(BOOL)animated { - [super viewDidAppear:animated]; - if (!hasSentFirstLoad_) { - hasSentFirstLoad_ = YES; - [self performSelector:@selector(reloadData) withObject:nil afterDelay:0.0]; - } else { - [list_ deselectRowAtIndexPath:[list_ indexPathForSelectedRow] animated:animated]; - } -} - -- (NSInteger) numberOfSectionsInTableView:(UITableView *)list { - NSInteger count([sections_ count]); - return count == 0 ? 1 : count; -} - -- (NSString *) tableView:(UITableView *)list titleForHeaderInSection:(NSInteger)section { - if ([sections_ count] == 0) - return nil; - return [[sections_ objectAtIndex:section] name]; -} - -- (NSInteger) tableView:(UITableView *)list numberOfRowsInSection:(NSInteger)section { - if ([sections_ count] == 0) - return 0; - return [[sections_ objectAtIndex:section] count]; -} - -- (Package *) packageAtIndexPath:(NSIndexPath *)path { - Section *section([sections_ objectAtIndex:[path section]]); - NSInteger row([path row]); - return [packages_ objectAtIndex:([section row] + row)]; -} - -- (UITableViewCell *) tableView:(UITableView *)table cellForRowAtIndexPath:(NSIndexPath *)path { - PackageCell *cell((PackageCell *) [table dequeueReusableCellWithIdentifier:@"Package"]); - if (cell == nil) - cell = [[[PackageCell alloc] init] autorelease]; - [cell setPackage:[self packageAtIndexPath:path]]; - return cell; -} - -/*- (CGFloat) tableView:(UITableView *)table heightForRowAtIndexPath:(NSIndexPath *)path { - return [PackageCell heightForPackage:[self packageAtIndexPath:path]]; -}*/ - -- (NSIndexPath *) tableView:(UITableView *)table willSelectRowAtIndexPath:(NSIndexPath *)path { - Package *package([self packageAtIndexPath:path]); - PackageController *view([delegate_ packageController]); - [view setDelegate:delegate_]; - [view setPackage:package]; - [[self navigationController] pushViewController:view animated:YES]; - return path; -} - -- (void) refreshButtonClicked { - [delegate_ beginUpdate]; - [[self navigationItem] setLeftBarButtonItem:nil]; -} - -- (void) upgradeButtonClicked { - [delegate_ distUpgrade]; -} - -- (NSString *) title { return UCLocalize("CHANGES"); } - -- (id) initWithDatabase:(Database *)database delegate:(id)delegate { - if ((self = [super init]) != nil) { - database_ = database; - [[self navigationItem] setTitle:UCLocalize("CHANGES")]; - - packages_ = [[NSMutableArray arrayWithCapacity:16] retain]; - sections_ = [[NSMutableArray arrayWithCapacity:16] retain]; - - list_ = [[UITableView alloc] initWithFrame:[[self view] bounds] style:UITableViewStylePlain]; - [list_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; - [list_ setRowHeight:73.0f]; - [[self view] addSubview:list_]; - - [list_ setDataSource:self]; - [list_ setDelegate:self]; - - delegate_ = delegate; - } return self; -} - -- (void) _reloadPackages:(NSArray *)packages { - _trace(); - for (Package *package in packages) - if ( - [package uninstalled] && [package valid] && [package visible] || - [package upgradableAndEssential:YES] - ) - [packages_ addObject:package]; - - _trace(); - [packages_ radixSortUsingFunction:reinterpret_cast<SKRadixFunction>(&PackageChangesRadix) withContext:NULL]; - _trace(); -} - -- (void) reloadData { - NSArray *packages = [database_ packages]; - - [packages_ removeAllObjects]; - [sections_ removeAllObjects]; - - UIProgressHUD *hud([delegate_ addProgressHUD]); - // XXX: localize - [hud setText:@"Loading Changes"]; - NSLog(@"HUD:%@::%@", delegate_, hud); - [self yieldToSelector:@selector(_reloadPackages:) withObject:packages]; - [delegate_ removeProgressHUD:hud]; - - Section *upgradable = [[[Section alloc] initWithName:UCLocalize("AVAILABLE_UPGRADES") localize:NO] autorelease]; - Section *ignored = [[[Section alloc] initWithName:UCLocalize("IGNORED_UPGRADES") localize:NO] autorelease]; - Section *section = nil; - NSDate *last = nil; - - upgrades_ = 0; - bool unseens = false; - - CFDateFormatterRef formatter(CFDateFormatterCreate(NULL, Locale_, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle)); - - for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) { - Package *package = [packages_ objectAtIndex:offset]; - - BOOL uae = [package upgradableAndEssential:YES]; - - if (!uae) { - unseens = true; - NSDate *seen; - - _profile(ChangesController$reloadData$Remember) - seen = [package seen]; - _end - - if (section == nil || last != seen && (seen == nil || [seen compare:last] != NSOrderedSame)) { - last = seen; - - NSString *name; - if (seen == nil) - name = UCLocalize("UNKNOWN"); - else { - name = (NSString *) CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen); - [name autorelease]; - } - - _profile(ChangesController$reloadData$Allocate) - name = [NSString stringWithFormat:UCLocalize("NEW_AT"), name]; - section = [[[Section alloc] initWithName:name row:offset localize:NO] autorelease]; - [sections_ addObject:section]; - _end - } - - [section addToCount]; - } else if ([package ignored]) - [ignored addToCount]; - else { - ++upgrades_; - [upgradable addToCount]; - } - } - _trace(); - - CFRelease(formatter); - - if (unseens) { - Section *last = [sections_ lastObject]; - size_t count = [last count]; - [packages_ removeObjectsInRange:NSMakeRange([packages_ count] - count, count)]; - [sections_ removeLastObject]; - } - - if ([ignored count] != 0) - [sections_ insertObject:ignored atIndex:0]; - if (upgrades_ != 0) - [sections_ insertObject:upgradable atIndex:0]; - - [list_ reloadData]; - - UIBarButtonItem *rightItem = [[UIBarButtonItem alloc] - initWithTitle:[NSString stringWithFormat:UCLocalize("PARENTHETICAL"), UCLocalize("UPGRADE"), [NSString stringWithFormat:@"%u", upgrades_]] - style:UIBarButtonItemStylePlain - target:self - action:@selector(upgradeButtonClicked) - ]; - if (upgrades_ > 0) [[self navigationItem] setRightBarButtonItem:rightItem]; - [rightItem release]; - - UIBarButtonItem *leftItem = [[UIBarButtonItem alloc] - initWithTitle:UCLocalize("REFRESH") - style:UIBarButtonItemStylePlain - target:self - action:@selector(refreshButtonClicked) - ]; - if (![delegate_ updating]) [[self navigationItem] setLeftBarButtonItem:leftItem]; - [leftItem release]; -} - -@end -/* }}} */ -/* Search Controller {{{ */ -@interface SearchController : FilteredPackageController < - UISearchBarDelegate -> { - UISearchBar *search_; -} - -- (id) initWithDatabase:(Database *)database; -- (void) reloadData; - -@end - -@implementation SearchController - -- (void) dealloc { - [search_ release]; - [super dealloc]; -} - -- (void) searchBarSearchButtonClicked:(UISearchBar *)searchBar { - [packages_ setObject:[search_ text] forFilter:@selector(isUnfilteredAndSearchedForBy:)]; - [search_ resignFirstResponder]; - [self reloadData]; -} - -- (void) searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)text { - [packages_ setObject:text forFilter:@selector(isUnfilteredAndSelectedForBy:)]; - [self reloadData]; -} - -- (NSString *) title { return nil; } - -- (id) initWithDatabase:(Database *)database { - return [super initWithDatabase:database title:UCLocalize("SEARCH") filter:@selector(isUnfilteredAndSearchedForBy:) with:nil]; -} - -- (void)viewDidAppear:(BOOL)animated { - [super viewDidAppear:animated]; - if (!search_) { - search_ = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, [[self view] bounds].size.width, 44.0f)]; - [search_ layoutSubviews]; - [search_ setPlaceholder:UCLocalize("SEARCH_EX")]; - UITextField *textField = [search_ searchField]; - [textField setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin]; - [search_ setDelegate:self]; - [textField setEnablesReturnKeyAutomatically:NO]; - [[self navigationItem] setTitleView:textField]; - } -} - -- (void) _reloadData { -} - -- (void) reloadData { - _profile(SearchController$reloadData) - [packages_ reloadData]; - _end - PrintTimes(); - [packages_ resetCursor]; -} - -- (void) didSelectPackage:(Package *)package { - [search_ resignFirstResponder]; - [super didSelectPackage:package]; -} - -@end -/* }}} */ -/* Settings Controller {{{ */ -@interface SettingsController : CYViewController < - UITableViewDataSource, - UITableViewDelegate -> { - _transient Database *database_; - NSString *name_; - Package *package_; - UITableView *table_; - id subscribedSwitch_; - id ignoredSwitch_; - UITableViewCell *subscribedCell_; - UITableViewCell *ignoredCell_; -} - -- (id) initWithDatabase:(Database *)database package:(NSString *)package; - -@end - -@implementation SettingsController - -- (void) dealloc { - [name_ release]; - if (package_ != nil) - [package_ release]; - [table_ release]; - [subscribedSwitch_ release]; - [ignoredSwitch_ release]; - [subscribedCell_ release]; - [ignoredCell_ release]; - - [super dealloc]; -} - -- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView { - if (package_ == nil) - return 0; - - return 1; -} - -- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - if (package_ == nil) - return 0; - - return 1; -} - -- (NSString *) tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section { - return UCLocalize("SHOW_ALL_CHANGES_EX"); -} - -- (void) onSomething:(BOOL)value withKey:(NSString *)key { - if (package_ == nil) - return; - - NSMutableDictionary *metadata([package_ metadata]); - - BOOL before; - if (NSNumber *number = [metadata objectForKey:key]) - before = [number boolValue]; - else - before = NO; - - if (value != before) { - [metadata setObject:[NSNumber numberWithBool:value] forKey:key]; - Changed_ = true; - [delegate_ updateData]; - } -} - -- (void) onSubscribed:(id)control { - [self onSomething:(int) [control isOn] withKey:@"IsSubscribed"]; -} - -- (void) onIgnored:(id)control { - [self onSomething:(int) [control isOn] withKey:@"IsIgnored"]; -} - -- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { - if (package_ == nil) - return nil; - - switch ([indexPath row]) { - case 0: return subscribedCell_; - case 1: return ignoredCell_; - - _nodefault - } - - return nil; -} - -- (NSString *) title { return UCLocalize("SETTINGS"); } - -- (id) initWithDatabase:(Database *)database package:(NSString *)package { - if ((self = [super init])) { - database_ = database; - name_ = [package retain]; - - [[self navigationItem] setTitle:UCLocalize("SETTINGS")]; - - table_ = [[UITableView alloc] initWithFrame:[[self view] bounds] style:UITableViewStyleGrouped]; - [table_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; - [[self view] addSubview:table_]; - - subscribedSwitch_ = [[objc_getClass("UISwitch") alloc] initWithFrame:CGRectMake(0, 0, 50, 20)]; - [subscribedSwitch_ setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin]; - [subscribedSwitch_ addTarget:self action:@selector(onSubscribed:) forEvents:UIControlEventValueChanged]; - - ignoredSwitch_ = [[objc_getClass("UISwitch") alloc] initWithFrame:CGRectMake(0, 0, 50, 20)]; - [ignoredSwitch_ setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin]; - [ignoredSwitch_ addTarget:self action:@selector(onIgnored:) forEvents:UIControlEventValueChanged]; - - subscribedCell_ = [[UITableViewCell alloc] init]; - [subscribedCell_ setText:UCLocalize("SHOW_ALL_CHANGES")]; - [subscribedCell_ setAccessoryView:subscribedSwitch_]; - [subscribedCell_ setSelectionStyle:UITableViewCellSelectionStyleNone]; - - ignoredCell_ = [[UITableViewCell alloc] init]; - [ignoredCell_ setText:UCLocalize("IGNORE_UPGRADES")]; - [ignoredCell_ setAccessoryView:ignoredSwitch_]; - [ignoredCell_ setSelectionStyle:UITableViewCellSelectionStyleNone]; - - [table_ setDataSource:self]; - [table_ setDelegate:self]; - [self reloadData]; - } return self; -} - -- (void) reloadData { - if (package_ != nil) - [package_ autorelease]; - package_ = [database_ packageWithName:name_]; - if (package_ != nil) { - [package_ retain]; - [subscribedSwitch_ setOn:([package_ subscribed] ? 1 : 0) animated:NO]; - [ignoredSwitch_ setOn:([package_ ignored] ? 1 : 0) animated:NO]; - } - - [table_ reloadData]; -} - -@end -/* }}} */ - -/* Signature Controller {{{ */ -@interface SignatureController : CYBrowserController { - _transient Database *database_; - NSString *package_; -} - -- (id) initWithDatabase:(Database *)database package:(NSString *)package; - -@end - -@implementation SignatureController - -- (void) dealloc { - [package_ release]; - [super dealloc]; -} - -- (void) webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame { - // XXX: dude! - [super webView:sender didClearWindowObject:window forFrame:frame]; -} - -- (id) initWithDatabase:(Database *)database package:(NSString *)package { - if ((self = [super init]) != nil) { - database_ = database; - package_ = [package retain]; - [self reloadData]; - } return self; -} - -- (void) reloadData { - [self loadURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"signature" ofType:@"html"]]]; -} - -@end -/* }}} */ -/* Role Controller {{{ */ -@interface RoleController : CYViewController < - UITableViewDataSource, - UITableViewDelegate -> { - _transient Database *database_; - id roledelegate_; - UITableView *table_; - UISegmentedControl *segment_; - UIView *container_; -} - -- (void) showDoneButton; -- (void) resizeSegmentedControl; - -@end - -@implementation RoleController -- (void) dealloc { - [table_ release]; - [segment_ release]; - [container_ release]; - - [super dealloc]; -} - -- (id) initWithDatabase:(Database *)database delegate:(id)delegate { - if ((self = [super init])) { - database_ = database; - roledelegate_ = delegate; - - [[self navigationItem] setTitle:UCLocalize("WHO_ARE_YOU")]; - - NSArray *items = [NSArray arrayWithObjects: - UCLocalize("USER"), - UCLocalize("HACKER"), - UCLocalize("DEVELOPER"), - nil]; - segment_ = [[UISegmentedControl alloc] initWithItems:items]; - container_ = [[UIView alloc] initWithFrame:CGRectMake(0, 0, [[self view] frame].size.width, 44.0f)]; - [container_ addSubview:segment_]; - - int index = -1; - if ([Role_ isEqualToString:@"User"]) index = 0; - if ([Role_ isEqualToString:@"Hacker"]) index = 1; - if ([Role_ isEqualToString:@"Developer"]) index = 2; - if (index != -1) { - [segment_ setSelectedSegmentIndex:index]; - [self showDoneButton]; - } - - [segment_ addTarget:self action:@selector(segmentChanged:) forControlEvents:UIControlEventValueChanged]; - [self resizeSegmentedControl]; - - table_ = [[UITableView alloc] initWithFrame:[[self view] bounds] style:UITableViewStyleGrouped]; - [table_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; - [table_ setDelegate:self]; - [table_ setDataSource:self]; - [[self view] addSubview:table_]; - [table_ reloadData]; - } return self; -} - -- (void) resizeSegmentedControl { - CGFloat width = [[self view] frame].size.width; - [segment_ setFrame:CGRectMake(width / 32.0f, 0, width - (width / 32.0f * 2.0f), 44.0f)]; -} - -- (void) viewWillAppear:(BOOL)animated { - [super viewWillAppear:animated]; - - [self resizeSegmentedControl]; -} - -- (void) willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration { - [self resizeSegmentedControl]; -} - -- (void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { - [self resizeSegmentedControl]; -} - -- (void) save { - NSString *role(nil); - - switch ([segment_ selectedSegmentIndex]) { - case 0: role = @"User"; break; - case 1: role = @"Hacker"; break; - case 2: role = @"Developer"; break; - - _nodefault - } - - if (![role isEqualToString:Role_]) { - bool rolling(Role_ == nil); - Role_ = role; - - Settings_ = [NSMutableDictionary dictionaryWithObjectsAndKeys: - Role_, @"Role", - nil]; - - [Metadata_ setObject:Settings_ forKey:@"Settings"]; - - Changed_ = true; - - if (rolling) - [roledelegate_ loadData]; - else - [roledelegate_ updateData]; - } -} - -- (void) segmentChanged:(UISegmentedControl *)control { - [self showDoneButton]; -} - -- (void) doneButtonClicked { - [self save]; - [[self navigationController] dismissModalViewControllerAnimated:YES]; -} - -- (void) showDoneButton { - UIBarButtonItem *rightItem = [[UIBarButtonItem alloc] - initWithTitle:UCLocalize("DONE") - style:UIBarButtonItemStyleDone - target:self - action:@selector(doneButtonClicked) - ]; - [[self navigationItem] setRightBarButtonItem:rightItem animated:[[self navigationItem] rightBarButtonItem] == nil]; - [rightItem release]; -} - -- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView { - // XXX: For not having a single cell in the table, this sure is a lot of sections. - return 6; -} - -- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - return 0; // :( -} - -- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { - return nil; // This method is required by the protocol. -} - -- (NSString *) tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section { - if (section == 1) - return UCLocalize("ROLE_EX"); - if (section == 4) - return [NSString stringWithFormat: - @"%@: %@\n%@: %@\n%@: %@", - UCLocalize("USER"), UCLocalize("USER_EX"), - UCLocalize("HACKER"), UCLocalize("HACKER_EX"), - UCLocalize("DEVELOPER"), UCLocalize("DEVELOPER_EX") - ]; - else return nil; -} - -- (CGFloat) tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { - if (section == 3) return 44.0f; - else return 0; -} - -- (UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { - if (section == 3) return container_; - else return nil; -} - -@end -/* }}} */ - -/* Cydia Container {{{ */ -@interface CYContainer : UIViewController <ProgressDelegate> { - _transient Database *database_; - RefreshBar *refreshbar_; - - bool dropped_; - bool updating_; - id updatedelegate_; - UITabBarController *root_; -} - -- (void) setTabBarController:(UITabBarController *)controller; - -- (void) dropBar:(BOOL)animated; -- (void) beginUpdate; -- (void) raiseBar:(BOOL)animated; -- (BOOL) updating; - -@end - -@implementation CYContainer - -- (BOOL) _reallyWantsFullScreenLayout { - return YES; -} - -// NOTE: UIWindow only sends the top controller these messages, -// So we have to forward them on. - -- (void) viewDidAppear:(BOOL)animated { - [super viewDidAppear:animated]; - [root_ viewDidAppear:animated]; -} - -- (void) viewWillAppear:(BOOL)animated { - [super viewWillAppear:animated]; - [root_ viewWillAppear:animated]; -} - -- (void) viewDidDisappear:(BOOL)animated { - [super viewDidDisappear:animated]; - [root_ viewDidDisappear:animated]; -} - -- (void) viewWillDisappear:(BOOL)animated { - [super viewWillDisappear:animated]; - [root_ viewWillDisappear:animated]; -} - -- (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orientation { - return IsWildcat_; -} - -- (void) setTabBarController:(UITabBarController *)controller { - root_ = controller; - [[self view] addSubview:[root_ view]]; -} - -- (void) setUpdate:(NSDate *)date { - [self beginUpdate]; -} - -- (void) beginUpdate { - [self dropBar:YES]; - [refreshbar_ start]; - - updating_ = true; - - [NSThread - detachNewThreadSelector:@selector(performUpdate) - toTarget:self - withObject:nil - ]; -} - -- (void) performUpdate { _pooled - Status status; - status.setDelegate(self); - [database_ updateWithStatus:status]; - - [self - performSelectorOnMainThread:@selector(completeUpdate) - withObject:nil - waitUntilDone:NO - ]; -} - -- (void) completeUpdate { - updating_ = false; - - [self raiseBar:YES]; - [refreshbar_ stop]; - [updatedelegate_ performSelector:@selector(reloadData) withObject:nil afterDelay:0]; -} - -- (void) cancelUpdate { - [refreshbar_ cancel]; - [self completeUpdate]; -} - -- (void) cancelPressed { - [self cancelUpdate]; -} - -- (BOOL) updating { - return updating_; -} - -- (void) setProgressError:(NSString *)error withTitle:(NSString *)title { - [refreshbar_ setPrompt:[NSString stringWithFormat:UCLocalize("COLON_DELIMITED"), UCLocalize("ERROR"), error]]; -} - -- (void) startProgress { -} - -- (void) setProgressTitle:(NSString *)title { - [self - performSelectorOnMainThread:@selector(_setProgressTitle:) - withObject:title - waitUntilDone:YES - ]; -} - -- (bool) isCancelling:(size_t)received { - return !updating_; -} - -- (void) setProgressPercent:(float)percent { - [self - performSelectorOnMainThread:@selector(_setProgressPercent:) - withObject:[NSNumber numberWithFloat:percent] - waitUntilDone:YES - ]; -} - -- (void) addProgressOutput:(NSString *)output { - [self - performSelectorOnMainThread:@selector(_addProgressOutput:) - withObject:output - waitUntilDone:YES - ]; -} - -- (void) _setProgressTitle:(NSString *)title { - [refreshbar_ setPrompt:title]; -} - -- (void) _setProgressPercent:(NSNumber *)percent { - [refreshbar_ setProgress:[percent floatValue]]; -} - -- (void) _addProgressOutput:(NSString *)output { -} - -- (void) setUpdateDelegate:(id)delegate { - updatedelegate_ = delegate; -} - -- (CGFloat) statusBarHeight { - if (UIInterfaceOrientationIsPortrait([self interfaceOrientation])) { - return [[UIApplication sharedApplication] statusBarFrame].size.height; - } else { - return [[UIApplication sharedApplication] statusBarFrame].size.width; - } -} - -- (void) dropBar:(BOOL)animated { - if (dropped_) return; - dropped_ = true; - - [[self view] addSubview:refreshbar_]; - - CGFloat sboffset = [self statusBarHeight]; - - CGRect barframe = [refreshbar_ frame]; - barframe.origin.y = sboffset; - [refreshbar_ setFrame:barframe]; - - if (animated) [UIView beginAnimations:nil context:NULL]; - CGRect viewframe = [[root_ view] frame]; - viewframe.origin.y += barframe.size.height + sboffset; - viewframe.size.height -= barframe.size.height + sboffset; - [[root_ view] setFrame:viewframe]; - if (animated) [UIView commitAnimations]; - - // Ensure bar has the proper width for our view, it might have changed - barframe.size.width = viewframe.size.width; - [refreshbar_ setFrame:barframe]; - - // XXX: fix Apple's layout bug - [[root_ selectedViewController] _updateLayoutForStatusBarAndInterfaceOrientation]; -} - -- (void) raiseBar:(BOOL)animated { - if (!dropped_) return; - dropped_ = false; - - [refreshbar_ removeFromSuperview]; - - CGFloat sboffset = [self statusBarHeight]; - - if (animated) [UIView beginAnimations:nil context:NULL]; - CGRect barframe = [refreshbar_ frame]; - CGRect viewframe = [[root_ view] frame]; - viewframe.origin.y -= barframe.size.height + sboffset; - viewframe.size.height += barframe.size.height + sboffset; - [[root_ view] setFrame:viewframe]; - if (animated) [UIView commitAnimations]; - - // XXX: fix Apple's layout bug - [[root_ selectedViewController] _updateLayoutForStatusBarAndInterfaceOrientation]; -} - -- (void) willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration { - // XXX: fix Apple's layout bug - [[root_ selectedViewController] _updateLayoutForStatusBarAndInterfaceOrientation]; -} - -- (void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { - if (dropped_) { - [self raiseBar:NO]; - [self dropBar:NO]; - } - - // XXX: fix Apple's layout bug - [[root_ selectedViewController] _updateLayoutForStatusBarAndInterfaceOrientation]; -} - -- (void) statusBarFrameChanged:(NSNotification *)notification { - if (dropped_) { - [self raiseBar:NO]; - [self dropBar:NO]; - } -} - -- (void) dealloc { - [refreshbar_ release]; - [[NSNotificationCenter defaultCenter] removeObserver:self]; - [super dealloc]; -} - -- (id) initWithDatabase:(Database *)database { - if ((self = [super init]) != nil) { - database_ = database; - - [[self view] setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarFrameChanged:) name:UIApplicationDidChangeStatusBarFrameNotification object:nil]; - - refreshbar_ = [[RefreshBar alloc] initWithFrame:CGRectMake(0, 0, [[self view] frame].size.width, [UINavigationBar defaultSize].height) delegate:self]; - } return self; -} - -@end -/* }}} */ - -typedef enum { - kCydiaTag = 0, - kSectionsTag = 1, - kChangesTag = 2, - kManageTag = 3, - kInstalledTag = 4, - kSourcesTag = 5, - kSearchTag = 6 -} CYTabTag; - -@interface Cydia : UIApplication < - ConfirmationControllerDelegate, - ProgressControllerDelegate, - CydiaDelegate, - UINavigationControllerDelegate -> { - UIWindow *window_; - CYContainer *container_; - - id tabbar_; - - NSMutableArray *essential_; - NSMutableArray *broken_; - - Database *database_; - - int tag_; - - UIKeyboard *keyboard_; - UIProgressHUD *hud_; - - SectionsController *sections_; - ChangesController *changes_; - ManageController *manage_; - SearchController *search_; - SourceTable *sources_; - InstalledController *installed_; - id queueDelegate_; - -#if RecyclePackageViews - NSMutableArray *details_; -#endif - - bool loaded_; -} - -- (CYViewController *) _pageForURL:(NSURL *)url withClass:(Class)_class; -- (void) setPage:(CYViewController *)page; -- (void) loadData; - -@end - -static _finline void _setHomePage(Cydia *self) { - [self setPage:[self _pageForURL:[NSURL URLWithString:CydiaURL(@"")] withClass:[HomeController class]]]; -} - -@implementation Cydia - -- (void) beginUpdate { - [container_ beginUpdate]; -} - -- (BOOL) updating { - return [container_ updating]; -} - -- (UIView *) rotatingContentViewForWindow:(UIWindow *)window { - return window_; -} - -- (void) _loaded { - if ([broken_ count] != 0) { - int count = [broken_ count]; - - UIAlertView *alert = [[[UIAlertView alloc] - initWithTitle:(count == 1 ? UCLocalize("HALFINSTALLED_PACKAGE") : [NSString stringWithFormat:UCLocalize("HALFINSTALLED_PACKAGES"), count]) - message:UCLocalize("HALFINSTALLED_PACKAGE_EX") - delegate:self - cancelButtonTitle:UCLocalize("FORCIBLY_CLEAR") - otherButtonTitles:UCLocalize("TEMPORARY_IGNORE"), nil - ] autorelease]; - - [alert setContext:@"fixhalf"]; - [alert show]; - } else if (!Ignored_ && [essential_ count] != 0) { - int count = [essential_ count]; - - UIAlertView *alert = [[[UIAlertView alloc] - initWithTitle:(count == 1 ? UCLocalize("ESSENTIAL_UPGRADE") : [NSString stringWithFormat:UCLocalize("ESSENTIAL_UPGRADES"), count]) - message:UCLocalize("ESSENTIAL_UPGRADE_EX") - delegate:self - cancelButtonTitle:UCLocalize("TEMPORARY_IGNORE") - otherButtonTitles:UCLocalize("UPGRADE_ESSENTIAL"), UCLocalize("COMPLETE_UPGRADE"), nil - ] autorelease]; - - [alert setContext:@"upgrade"]; - [alert show]; - } -} - -- (void) _saveConfig { - if (Changed_) { - _trace(); - NSString *error(nil); - if (NSData *data = [NSPropertyListSerialization dataFromPropertyList:Metadata_ format:NSPropertyListBinaryFormat_v1_0 errorDescription:&error]) { - _trace(); - NSError *error(nil); - if (![data writeToFile:@"/var/lib/cydia/metadata.plist" options:NSAtomicWrite error:&error]) - NSLog(@"failure to save metadata data: %@", error); - _trace(); - } else { - NSLog(@"failure to serialize metadata: %@", error); - return; - } - - Changed_ = false; - } -} - -- (void) _updateData { - [self _saveConfig]; - - /* XXX: this is just stupid */ - if (tag_ != 1 && sections_ != nil) - [sections_ reloadData]; - if (tag_ != 2 && changes_ != nil) - [changes_ reloadData]; - if (tag_ != 4 && search_ != nil) - [search_ reloadData]; - - [(CYNavigationController *)[tabbar_ selectedViewController] reloadData]; -} - -- (int)indexOfTabWithTag:(int)tag { - int i = 0; - for (UINavigationController *controller in [tabbar_ viewControllers]) { - if ([[controller tabBarItem] tag] == tag) return i; - i += 1; - } - - return -1; -} - -- (void) _refreshIfPossible { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - SCNetworkReachabilityFlags flags; { - SCNetworkReachabilityRef reachability(SCNetworkReachabilityCreateWithName(NULL, "cydia.saurik.com")); - SCNetworkReachabilityGetFlags(reachability, &flags); - CFRelease(reachability); - } - - // XXX: this elaborate mess is what Apple is using to determine this? :( - // XXX: do we care if the user has to intervene? maybe that's ok? - bool reachable( - (flags & kSCNetworkReachabilityFlagsReachable) != 0 && ( - (flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0 || ( - (flags & kSCNetworkReachabilityFlagsConnectionOnDemand) != 0 || - (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0 - ) && (flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0 || - (flags & kSCNetworkReachabilityFlagsIsWWAN) != 0 - ) - ); - - if (loaded_ || ManualRefresh || !reachable) loaded: - [self performSelectorOnMainThread:@selector(_loaded) withObject:nil waitUntilDone:NO]; - else { - loaded_ = true; - - NSDate *update([Metadata_ objectForKey:@"LastUpdate"]); - - if (update != nil) { - NSTimeInterval interval([update timeIntervalSinceNow]); - if (interval <= 0 && interval > -(15*60)) - goto loaded; - } - - [container_ performSelectorOnMainThread:@selector(setUpdate:) withObject:update waitUntilDone:NO]; - } - - [pool release]; -} - -- (void) refreshIfPossible { - [NSThread detachNewThreadSelector:@selector(_refreshIfPossible) toTarget:self withObject:nil]; -} - -- (void) _reloadData { - UIProgressHUD *hud([self addProgressHUD]); - [hud setText:(loaded_ ? UCLocalize("RELOADING_DATA") : UCLocalize("LOADING_DATA"))]; - - [database_ yieldToSelector:@selector(reloadData) withObject:nil]; - _trace(); - - [self removeProgressHUD:hud]; - - size_t changes(0); - - [essential_ removeAllObjects]; - [broken_ removeAllObjects]; - - NSArray *packages([database_ packages]); - for (Package *package in packages) { - if ([package half]) - [broken_ addObject:package]; - if ([package upgradableAndEssential:NO]) { - if ([package essential]) - [essential_ addObject:package]; - ++changes; - } - } - - if (changes != 0) { - NSString *badge([[NSNumber numberWithInt:changes] stringValue]); - [[[[tabbar_ viewControllers] objectAtIndex:[self indexOfTabWithTag:kChangesTag]] tabBarItem] setBadgeValue:badge]; - [[[[tabbar_ viewControllers] objectAtIndex:[self indexOfTabWithTag:kChangesTag]] tabBarItem] setAnimatedBadge:YES]; - - if ([self respondsToSelector:@selector(setApplicationBadge:)]) - [self setApplicationBadge:badge]; - else - [self setApplicationBadgeString:badge]; - } else { - [[[[tabbar_ viewControllers] objectAtIndex:[self indexOfTabWithTag:kChangesTag]] tabBarItem] setBadgeValue:nil]; - [[[[tabbar_ viewControllers] objectAtIndex:[self indexOfTabWithTag:kChangesTag]] tabBarItem] setAnimatedBadge:NO]; - - if ([self respondsToSelector:@selector(removeApplicationBadge)]) - [self removeApplicationBadge]; - else // XXX: maybe use setApplicationBadgeString also? - [self setApplicationIconBadgeNumber:0]; - } - - [self _updateData]; - - [self refreshIfPossible]; -} - -- (void) updateData { - [database_ setVisible]; - [self _updateData]; -} - -- (void) update_ { - [database_ update]; -} - -- (void) syncData { - FILE *file(fopen("/etc/apt/sources.list.d/cydia.list", "w")); - _assert(file != NULL); - - for (NSString *key in [Sources_ allKeys]) { - NSDictionary *source([Sources_ objectForKey:key]); - - fprintf(file, "%s %s %s\n", - [[source objectForKey:@"Type"] UTF8String], - [[source objectForKey:@"URI"] UTF8String], - [[source objectForKey:@"Distribution"] UTF8String] - ); - } - - fclose(file); - - [self _saveConfig]; - - ProgressController *progress = [[[ProgressController alloc] initWithDatabase:database_ delegate:self] autorelease]; - CYNavigationController *navigation = [[[CYNavigationController alloc] initWithRootViewController:progress] autorelease]; - if (IsWildcat_) [navigation setModalPresentationStyle:UIModalPresentationFormSheet]; - [container_ presentModalViewController:navigation animated:YES]; - - [progress - detachNewThreadSelector:@selector(update_) - toTarget:self - withObject:nil - title:UCLocalize("UPDATING_SOURCES") - ]; -} - -- (void) reloadData { - @synchronized (self) { - [self _reloadData]; - } -} - -- (void) resolve { - pkgProblemResolver *resolver = [database_ resolver]; - - resolver->InstallProtect(); - if (!resolver->Resolve(true)) - _error->Discard(); -} - -- (CGRect) popUpBounds { - return [[tabbar_ view] bounds]; -} - -- (bool) perform { - if (![database_ prepare]) - return false; - - ConfirmationController *page([[[ConfirmationController alloc] initWithDatabase:database_] autorelease]); - [page setDelegate:self]; - CYNavigationController *confirm_ = [[CYNavigationController alloc] initWithRootViewController:page]; - [confirm_ setDelegate:self]; - - if (IsWildcat_) [confirm_ setModalPresentationStyle:UIModalPresentationFormSheet]; - [container_ presentModalViewController:confirm_ animated:YES]; - - return true; -} - -- (void) queue { - @synchronized (self) { - [self perform]; - } -} - -- (void) clearPackage:(Package *)package { - @synchronized (self) { - [package clear]; - [self resolve]; - [self perform]; - } -} - -- (void) installPackages:(NSArray *)packages { - @synchronized (self) { - for (Package *package in packages) - [package install]; - [self resolve]; - [self perform]; - } -} - -- (void) installPackage:(Package *)package { - @synchronized (self) { - [package install]; - [self resolve]; - [self perform]; - } -} - -- (void) removePackage:(Package *)package { - @synchronized (self) { - [package remove]; - [self resolve]; - [self perform]; - } -} - -- (void) distUpgrade { - @synchronized (self) { - if (![database_ upgrade]) - return; - [self perform]; - } -} - -- (void) complete { - @synchronized (self) { - [self _reloadData]; - } -} - -- (void) confirmWithNavigationController:(UINavigationController *)navigation { - ProgressController *progress = [[[ProgressController alloc] initWithDatabase:database_ delegate:self] autorelease]; - - if (navigation != nil) { - [navigation pushViewController:progress animated:YES]; - } else { - navigation = [[[CYNavigationController alloc] initWithRootViewController:progress] autorelease]; - if (IsWildcat_) [navigation setModalPresentationStyle:UIModalPresentationFormSheet]; - [container_ presentModalViewController:navigation animated:YES]; - } - - [progress - detachNewThreadSelector:@selector(perform) - toTarget:database_ - withObject:nil - title:UCLocalize("RUNNING") - ]; -} - -- (void) progressControllerIsComplete:(ProgressController *)progress { - [self complete]; -} - -- (void) setPage:(CYViewController *)page { - [page setDelegate:self]; - - CYNavigationController *navController = (CYNavigationController *) [tabbar_ selectedViewController]; - [navController setViewControllers:[NSArray arrayWithObject:page]]; - for (CYNavigationController *page in [tabbar_ viewControllers]) { - if (page != navController) [page setViewControllers:nil]; - } -} - -- (CYViewController *) _pageForURL:(NSURL *)url withClass:(Class)_class { - CYBrowserController *browser = [[[_class alloc] init] autorelease]; - [browser loadURL:url]; - return browser; -} - -- (SectionsController *) sectionsController { - if (sections_ == nil) - sections_ = [[SectionsController alloc] initWithDatabase:database_]; - return sections_; -} - -- (ChangesController *) changesController { - if (changes_ == nil) - changes_ = [[ChangesController alloc] initWithDatabase:database_ delegate:self]; - return changes_; -} - -- (ManageController *) manageController { - if (manage_ == nil) { - manage_ = (ManageController *) [[self - _pageForURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"manage" ofType:@"html"]] - withClass:[ManageController class] - ] retain]; - if (!IsWildcat_) queueDelegate_ = manage_; - } - return manage_; -} - -- (SearchController *) searchController { - if (search_ == nil) - search_ = [[SearchController alloc] initWithDatabase:database_]; - return search_; -} - -- (SourceTable *) sourcesController { - if (sources_ == nil) - sources_ = [[SourceTable alloc] initWithDatabase:database_]; - return sources_; -} - -- (InstalledController *) installedController { - if (installed_ == nil) { - installed_ = [[InstalledController alloc] initWithDatabase:database_]; - if (IsWildcat_) queueDelegate_ = installed_; - } - return installed_; -} - -- (void) tabBarController:(id)tabBarController didSelectViewController:(UIViewController *)viewController { - int tag = [[viewController tabBarItem] tag]; - if (tag == tag_) { - [(CYNavigationController *)[tabbar_ selectedViewController] popToRootViewControllerAnimated:YES]; - return; - } else if (tag_ == 1) { - [[self sectionsController] resetView]; - } - - switch (tag) { - case kCydiaTag: _setHomePage(self); break; - - case kSectionsTag: [self setPage:[self sectionsController]]; break; - case kChangesTag: [self setPage:[self changesController]]; break; - case kManageTag: [self setPage:[self manageController]]; break; - case kInstalledTag: [self setPage:[self installedController]]; break; - case kSourcesTag: [self setPage:[self sourcesController]]; break; - case kSearchTag: [self setPage:[self searchController]]; break; - - _nodefault - } - - tag_ = tag; -} - -- (void) showSettings { - RoleController *role = [[RoleController alloc] initWithDatabase:database_ delegate:self]; - CYNavigationController *nav = [[CYNavigationController alloc] initWithRootViewController:role]; - if (IsWildcat_) [nav setModalPresentationStyle:UIModalPresentationFormSheet]; - [container_ presentModalViewController:nav animated:YES]; -} - -- (void) setPackageController:(PackageController *)view { - WebThreadLock(); - [view setPackage:nil]; -#if RecyclePackageViews - if ([details_ count] < 3) - [details_ addObject:view]; -#endif - WebThreadUnlock(); -} - -- (PackageController *) _packageController { - return [[[PackageController alloc] initWithDatabase:database_] autorelease]; -} - -- (PackageController *) packageController { -#if RecyclePackageViews - PackageController *view; - size_t count([details_ count]); - - if (count == 0) { - view = [self _packageController]; - renew: - [details_ addObject:[self _packageController]]; - } else { - view = [[[details_ lastObject] retain] autorelease]; - [details_ removeLastObject]; - if (count == 1) - goto renew; - } - - return view; -#else - return [self _packageController]; -#endif -} - -// Returns the navigation controller for the queuing badge. -- (id) queueBadgeController { - int index = [self indexOfTabWithTag:kManageTag]; - if (index == -1) index = [self indexOfTabWithTag:kInstalledTag]; - - return [[tabbar_ viewControllers] objectAtIndex:index]; -} - -- (void) cancelAndClear:(bool)clear { - @synchronized (self) { - if (clear) { - // Clear all marks. - pkgCacheFile &cache([database_ cache]); - for (pkgCache::PkgIterator iterator = cache->PkgBegin(); !iterator.end(); ++iterator) { - // Unmark method taken from Synaptic Package Manager. - // Thanks for being sane, unlike Aptitude. - if (!cache[iterator].Keep()) { - cache->MarkKeep(iterator, false); - cache->SetReInstall(iterator, false); - } - } - - // Stop queuing. - Queuing_ = false; - [[[self queueBadgeController] tabBarItem] setBadgeValue:nil]; - } else { - // Start queuing. - Queuing_ = true; - [[[self queueBadgeController] tabBarItem] setBadgeValue:UCLocalize("Q_D")]; - } - - // Show the changes in the current view. - [(CYNavigationController *) [tabbar_ selectedViewController] reloadData]; - [queueDelegate_ queueStatusDidChange]; - } -} - -- (void) alertView:(UIAlertView *)alert clickedButtonAtIndex:(NSInteger)button { - NSString *context([alert context]); - - if ([context isEqualToString:@"fixhalf"]) { - if (button == [alert firstOtherButtonIndex]) { - @synchronized (self) { - for (Package *broken in broken_) { - [broken remove]; - - NSString *id = [broken id]; - 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]); - } - - [self resolve]; - [self perform]; - } - } else if (button == [alert cancelButtonIndex]) { - [broken_ removeAllObjects]; - [self _loaded]; - } - - [alert dismissWithClickedButtonIndex:-1 animated:YES]; - } else if ([context isEqualToString:@"upgrade"]) { - if (button == [alert firstOtherButtonIndex]) { - @synchronized (self) { - for (Package *essential in essential_) - [essential install]; - - [self resolve]; - [self perform]; - } - } else if (button == [alert firstOtherButtonIndex] + 1) { - [self distUpgrade]; - } else if (button == [alert cancelButtonIndex]) { - Ignored_ = YES; - } - - [alert dismissWithClickedButtonIndex:-1 animated:YES]; - } -} - -- (void) system:(NSString *)command { _pooled - system([command UTF8String]); -} - -- (void) applicationWillSuspend { - [database_ clean]; - [super applicationWillSuspend]; -} - -- (void) applicationSuspend:(__GSEvent *)event { - // FIXME: This needs to be fixed, but we no longer have a progress_. - // What's the best solution? - if (hud_ == nil)// && ![progress_ isRunning]) - [super applicationSuspend:event]; -} - -- (void) _animateSuspension:(BOOL)arg0 duration:(double)arg1 startTime:(double)arg2 scale:(float)arg3 { - if (hud_ == nil) - [super _animateSuspension:arg0 duration:arg1 startTime:arg2 scale:arg3]; -} - -- (void) _setSuspended:(BOOL)value { - if (hud_ == nil) - [super _setSuspended:value]; -} - -- (UIProgressHUD *) addProgressHUD { - UIProgressHUD *hud([[[UIProgressHUD alloc] initWithWindow:window_] autorelease]); - [hud setAutoresizingMask:UIViewAutoresizingFlexibleBoth]; - - [window_ setUserInteractionEnabled:NO]; - [hud show:YES]; - [[container_ view] addSubview:hud]; - return hud; -} - -- (void) removeProgressHUD:(UIProgressHUD *)hud { - [hud show:NO]; - [hud removeFromSuperview]; - [window_ setUserInteractionEnabled:YES]; -} - -- (CYViewController *) pageForPackage:(NSString *)name { - if (Package *package = [database_ packageWithName:name]) { - PackageController *view([self packageController]); - [view setPackage:package]; - return view; - } else { - NSURL *url([NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"unknown" ofType:@"html"]]); - url = [NSURL URLWithString:[[url absoluteString] stringByAppendingString:[NSString stringWithFormat:@"?%@", name]]]; - return [self _pageForURL:url withClass:[CYBrowserController class]]; - } -} - -- (CYViewController *) pageForURL:(NSURL *)url hasTag:(int *)tag { - if (tag != NULL) - *tag = -1; - - NSString *href([url absoluteString]); - if ([href hasPrefix:@"apptapp://package/"]) - return [self pageForPackage:[href substringFromIndex:18]]; - - NSString *scheme([[url scheme] lowercaseString]); - if (![scheme isEqualToString:@"cydia"]) - return nil; - NSString *path([url absoluteString]); - if ([path length] < 8) - return nil; - path = [path substringFromIndex:8]; - if (![path hasPrefix:@"/"]) - path = [@"/" stringByAppendingString:path]; - - if ([path isEqualToString:@"/add-source"]) - return [[[AddSourceController alloc] initWithDatabase:database_] autorelease]; - else if ([path isEqualToString:@"/storage"]) - return [self _pageForURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"storage" ofType:@"html"]] withClass:[CYBrowserController class]]; - else if ([path isEqualToString:@"/sources"]) - return [[[SourceTable alloc] initWithDatabase:database_] autorelease]; - else if ([path isEqualToString:@"/packages"]) - return [[[InstalledController alloc] initWithDatabase:database_] autorelease]; - else if ([path hasPrefix:@"/url/"]) - return [self _pageForURL:[NSURL URLWithString:[path substringFromIndex:5]] withClass:[CYBrowserController class]]; - else if ([path hasPrefix:@"/launch/"]) - [self launchApplicationWithIdentifier:[path substringFromIndex:8] suspended:NO]; - else if ([path hasPrefix:@"/package-settings/"]) - return [[[SettingsController alloc] initWithDatabase:database_ package:[path substringFromIndex:18]] autorelease]; - else if ([path hasPrefix:@"/package-signature/"]) - return [[[SignatureController alloc] initWithDatabase:database_ package:[path substringFromIndex:19]] autorelease]; - else if ([path hasPrefix:@"/package/"]) - return [self pageForPackage:[path substringFromIndex:9]]; - else if ([path hasPrefix:@"/files/"]) { - NSString *name = [path substringFromIndex:7]; - - if (Package *package = [database_ packageWithName:name]) { - FileTable *files = [[[FileTable alloc] initWithDatabase:database_] autorelease]; - [files setPackage:package]; - return files; - } - } - - return nil; -} - -- (void) applicationOpenURL:(NSURL *)url { - [super applicationOpenURL:url]; - int tag; - if (CYViewController *page = [self pageForURL:url hasTag:&tag]) { - [self setPage:page]; - tag_ = tag; - [tabbar_ setSelectedViewController:(tag_ == -1 ? nil : [[tabbar_ viewControllers] objectAtIndex:tag_])]; - } -} - -- (void) applicationWillResignActive:(UIApplication *)application { - // Stop refreshing if you get a phone call or lock the device. - if ([container_ updating]) [container_ cancelUpdate]; - - if ([[self superclass] instancesRespondToSelector:@selector(applicationWillResignActive:)]) - [super applicationWillResignActive:application]; -} - -- (void) applicationDidFinishLaunching:(id)unused { - [CYBrowserController _initialize]; - - [NSURLProtocol registerClass:[CydiaURLProtocol class]]; - - Font12_ = [[UIFont systemFontOfSize:12] retain]; - Font12Bold_ = [[UIFont boldSystemFontOfSize:12] retain]; - Font14_ = [[UIFont systemFontOfSize:14] retain]; - Font18Bold_ = [[UIFont boldSystemFontOfSize:18] retain]; - Font22Bold_ = [[UIFont boldSystemFontOfSize:22] retain]; - - tag_ = 0; - - essential_ = [[NSMutableArray alloc] initWithCapacity:4]; - broken_ = [[NSMutableArray alloc] initWithCapacity:4]; - - UIScreen *screen([UIScreen mainScreen]); - - window_ = [[UIWindow alloc] initWithFrame:[screen bounds]]; - [window_ orderFront:self]; - [window_ makeKey:self]; - [window_ setHidden:NO]; - - database_ = [Database sharedInstance]; - - if ( - readlink("/Applications", NULL, 0) == -1 && errno == EINVAL || - readlink("/Library/Ringtones", NULL, 0) == -1 && errno == EINVAL || - readlink("/Library/Wallpaper", NULL, 0) == -1 && errno == EINVAL || - //readlink("/usr/bin", NULL, 0) == -1 && errno == EINVAL || - readlink("/usr/include", NULL, 0) == -1 && errno == EINVAL || - readlink("/usr/lib/pam", NULL, 0) == -1 && errno == EINVAL || - readlink("/usr/libexec", NULL, 0) == -1 && errno == EINVAL || - readlink("/usr/share", NULL, 0) == -1 && errno == EINVAL || - //readlink("/var/lib", NULL, 0) == -1 && errno == EINVAL || - false - ) { - [self setIdleTimerDisabled:YES]; - - hud_ = [self addProgressHUD]; - [hud_ setText:@"Reorganizing:\n\nWill Automatically\nClose When Done"]; - [self setStatusBarShowsProgress:YES]; - - [self yieldToSelector:@selector(system:) withObject:@"/usr/libexec/cydia/free.sh"]; - - [self setStatusBarShowsProgress:NO]; - [self removeProgressHUD:hud_]; - hud_ = nil; - - if (ExecFork() == 0) { - execlp("launchctl", "launchctl", "stop", "com.apple.SpringBoard", NULL); - perror("launchctl stop"); - } - - return; - } - - _trace(); - - NSMutableArray *items([NSMutableArray arrayWithObjects: - [[[UITabBarItem alloc] initWithTitle:@"Cydia" image:[UIImage applicationImageNamed:@"home.png"] tag:kCydiaTag] autorelease], - [[[UITabBarItem alloc] initWithTitle:UCLocalize("SECTIONS") image:[UIImage applicationImageNamed:@"install.png"] tag:kSectionsTag] autorelease], - [[[UITabBarItem alloc] initWithTitle:UCLocalize("CHANGES") image:[UIImage applicationImageNamed:@"changes.png"] tag:kChangesTag] autorelease], - [[[UITabBarItem alloc] initWithTitle:UCLocalize("SEARCH") image:[UIImage applicationImageNamed:@"search.png"] tag:kSearchTag] autorelease], - nil]); - - if (IsWildcat_) { - [items insertObject:[[[UITabBarItem alloc] initWithTitle:UCLocalize("SOURCES") image:[UIImage applicationImageNamed:@"source.png"] tag:kSourcesTag] autorelease] atIndex:3]; - [items insertObject:[[[UITabBarItem alloc] initWithTitle:UCLocalize("INSTALLED") image:[UIImage applicationImageNamed:@"manage.png"] tag:kInstalledTag] autorelease] atIndex:3]; - } else { - [items insertObject:[[[UITabBarItem alloc] initWithTitle:UCLocalize("MANAGE") image:[UIImage applicationImageNamed:@"manage.png"] tag:kManageTag] autorelease] atIndex:3]; - } - - NSMutableArray *controllers([NSMutableArray array]); - - for (UITabBarItem *item in items) { - CYNavigationController *controller([[[CYNavigationController alloc] initWithDatabase:database_] autorelease]); - [controller setTabBarItem:item]; - [controllers addObject:controller]; - } - - tabbar_ = [[CYTabBarController alloc] initWithDatabase:database_]; - [tabbar_ setViewControllers:controllers]; - [tabbar_ setDelegate:self]; - [tabbar_ setSelectedIndex:0]; - - container_ = [[CYContainer alloc] initWithDatabase:database_]; - [container_ setUpdateDelegate:self]; - [container_ setTabBarController:tabbar_]; - [window_ addSubview:[container_ view]]; - - [self performSelector:@selector(loadData) withObject:nil afterDelay:0]; -} - -- (void) loadData { - if (Role_ == nil) { - [self showSettings]; - return; - } - - [UIKeyboard initImplementationNow]; - - [self reloadData]; - -#if RecyclePackageViews - details_ = [[NSMutableArray alloc] initWithCapacity:4]; - [details_ addObject:[self _packageController]]; - [details_ addObject:[self _packageController]]; -#endif - - PrintTimes(); - - _setHomePage(self); -} - -- (void) showActionSheet:(UIActionSheet *)sheet fromItem:(UIBarButtonItem *)item { - if (item != nil && IsWildcat_) { - [sheet showFromBarButtonItem:item animated:YES]; - } else { - [sheet showInView:window_]; - } -} - -@end - -/*IMP alloc_; -id Alloc_(id self, SEL selector) { - id object = alloc_(self, selector); - lprintf("[%s]A-%p\n", self->isa->name, object); - return object; -}*/ - -/*IMP dealloc_; -id Dealloc_(id self, SEL selector) { - id object = dealloc_(self, selector); - lprintf("[%s]D-%p\n", self->isa->name, object); - return object; -}*/ - -Class $WebDefaultUIKitDelegate; - -MSHook(void, UIWebDocumentView$_setUIKitDelegate$, UIWebDocumentView *self, SEL _cmd, id delegate) { - if (delegate == nil && $WebDefaultUIKitDelegate != nil) - delegate = [$WebDefaultUIKitDelegate sharedUIKitDelegate]; - return _UIWebDocumentView$_setUIKitDelegate$(self, _cmd, delegate); -} - -static NSNumber *shouldPlayKeyboardSounds; - -Class $UIHardware; - -MSHook(void, UIHardware$_playSystemSound$, Class self, SEL _cmd, int sound) { - switch (sound) { - case 1104: // Keyboard Button Clicked - case 1105: // Keyboard Delete Repeated - if (shouldPlayKeyboardSounds == nil) { - NSDictionary *dict([[[NSDictionary alloc] initWithContentsOfFile:@"/var/mobile/Library/Preferences/com.apple.preferences.sounds.plist"] autorelease]); - shouldPlayKeyboardSounds = [([dict objectForKey:@"keyboard"] ?: (id) kCFBooleanTrue) retain]; - } - - if (![shouldPlayKeyboardSounds boolValue]) - break; - - default: - _UIHardware$_playSystemSound$(self, _cmd, sound); - } -} - -int main(int argc, char *argv[]) { _pooled - _trace(); - - if (Class $UIDevice = objc_getClass("UIDevice")) { - UIDevice *device([$UIDevice currentDevice]); - IsWildcat_ = [device respondsToSelector:@selector(isWildcat)] && [device isWildcat]; - } else - IsWildcat_ = false; - - PackageName = reinterpret_cast<CYString &(*)(Package *, SEL)>(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"); - - $WebDefaultUIKitDelegate = objc_getClass("WebDefaultUIKitDelegate"); - Method UIWebDocumentView$_setUIKitDelegate$(class_getInstanceMethod([WebView class], @selector(_setUIKitDelegate:))); - if (UIWebDocumentView$_setUIKitDelegate$ != NULL) { - _UIWebDocumentView$_setUIKitDelegate$ = reinterpret_cast<void (*)(UIWebDocumentView *, SEL, id)>(method_getImplementation(UIWebDocumentView$_setUIKitDelegate$)); - method_setImplementation(UIWebDocumentView$_setUIKitDelegate$, reinterpret_cast<IMP>(&$UIWebDocumentView$_setUIKitDelegate$)); - } - - $UIHardware = objc_getClass("UIHardware"); - Method UIHardware$_playSystemSound$(class_getClassMethod($UIHardware, @selector(_playSystemSound:))); - if (UIHardware$_playSystemSound$ != NULL) { - _UIHardware$_playSystemSound$ = reinterpret_cast<void (*)(Class, SEL, int)>(method_getImplementation(UIHardware$_playSystemSound$)); - method_setImplementation(UIHardware$_playSystemSound$, reinterpret_cast<IMP>(&$UIHardware$_playSystemSound$)); - } - /* }}} */ - /* Set Locale {{{ */ - Locale_ = CFLocaleCopyCurrent(); - Languages_ = [NSLocale preferredLanguages]; - //CFStringRef locale(CFLocaleGetIdentifier(Locale_)); - //NSLog(@"%@", [Languages_ description]); - - const char *lang; - if (Languages_ == nil || [Languages_ count] == 0) - // XXX: consider just setting to C and then falling through? - lang = NULL; - else { - lang = [[Languages_ objectAtIndex:0] UTF8String]; - setenv("LANG", lang, true); - } - - //std::setlocale(LC_ALL, lang); - NSLog(@"Setting Language: %s", lang); - /* }}} */ - - apr_app_initialize(&argc, const_cast<const char * const **>(&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]; - Home_ = NSHomeDirectory(); - Advanced_ = YES; - - setuid(0); - setgid(0); - - /*Method alloc = class_getClassMethod([NSObject class], @selector(alloc)); - alloc_ = alloc->method_imp; - alloc->method_imp = (IMP) &Alloc_;*/ - - /*Method dealloc = class_getClassMethod([NSObject class], @selector(dealloc)); - dealloc_ = dealloc->method_imp; - dealloc->method_imp = (IMP) &Dealloc_;*/ - - /* System Information {{{ */ - size_t size; - - int maxproc; - size = sizeof(maxproc); - if (sysctlbyname("kern.maxproc", &maxproc, &size, NULL, 0) == -1) - perror("sysctlbyname(\"kern.maxproc\", ?)"); - else if (maxproc < 64) { - maxproc = 64; - 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; - - if (CFMutableDictionaryRef dict = IOServiceMatching("IOPlatformExpertDevice")) { - if (io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, dict)) { - if (CFTypeRef serial = IORegistryEntryCreateCFProperty(service, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0)) { - SerialNumber_ = [NSString stringWithString:(NSString *)serial]; - CFRelease(serial); - } - - if (CFTypeRef ecid = IORegistryEntrySearchCFProperty(service, kIODeviceTreePlane, CFSTR("unique-chip-id"), kCFAllocatorDefault, kIORegistryIterateRecursively)) { - NSData *data((NSData *) ecid); - size_t length([data length]); - uint8_t bytes[length]; - [data getBytes:bytes]; - char string[length * 2 + 1]; - for (size_t i(0); i != length; ++i) - sprintf(string + i * 2, "%.2X", bytes[length - i - 1]); - ChipID_ = [NSString stringWithUTF8String:string]; - CFRelease(ecid); - } - - IOObjectRelease(service); - } - } - - UniqueID_ = [[UIDevice currentDevice] uniqueIdentifier]; - - if (NSDictionary *system = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]) - Build_ = [system objectForKey:@"ProductBuildVersion"]; - if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:@"/Applications/MobileSafari.app/Info.plist"]) { - Product_ = [info objectForKey:@"SafariProductVersion"]; - Safari_ = [info objectForKey:@"CFBundleVersion"]; - } - /* }}} */ - /* 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]; - _trace(); - - if (Metadata_ == NULL) - Metadata_ = [NSMutableDictionary dictionaryWithCapacity:2]; - else { - Settings_ = [Metadata_ objectForKey:@"Settings"]; - - Packages_ = [Metadata_ objectForKey:@"Packages"]; - Sections_ = [Metadata_ objectForKey:@"Sections"]; - Sources_ = [Metadata_ objectForKey:@"Sources"]; - - Token_ = [Metadata_ objectForKey:@"Token"]; - } - - if (Settings_ != nil) - Role_ = [Settings_ objectForKey:@"Role"]; - - if (Packages_ == nil) { - Packages_ = [[[NSMutableDictionary alloc] initWithCapacity:128] autorelease]; - [Metadata_ setObject:Packages_ forKey:@"Packages"]; - } - - if (Sections_ == nil) { - Sections_ = [[[NSMutableDictionary alloc] initWithCapacity:32] autorelease]; - [Metadata_ setObject:Sections_ forKey:@"Sections"]; - } - - if (Sources_ == nil) { - Sources_ = [[[NSMutableDictionary alloc] initWithCapacity:0] autorelease]; - [Metadata_ setObject:Sources_ forKey:@"Sources"]; - } - /* }}} */ - -#if RecycleWebViews - Documents_ = [[[NSMutableArray alloc] initWithCapacity:4] autorelease]; -#endif - - Finishes_ = [NSArray arrayWithObjects:@"return", @"reopen", @"restart", @"reload", @"reboot", nil]; - - if (substrate && access("/Library/MobileSubstrate/DynamicLibraries/SimulatedKeyEvents.dylib", F_OK) == 0) - dlopen("/Library/MobileSubstrate/DynamicLibraries/SimulatedKeyEvents.dylib", RTLD_LAZY | RTLD_GLOBAL); - if (substrate && access("/Applications/WinterBoard.app/WinterBoard.dylib", F_OK) == 0) - dlopen("/Applications/WinterBoard.app/WinterBoard.dylib", RTLD_LAZY | RTLD_GLOBAL); - /*if (substrate && access("/Library/MobileSubstrate/MobileSubstrate.dylib", F_OK) == 0) - dlopen("/Library/MobileSubstrate/MobileSubstrate.dylib", RTLD_LAZY | RTLD_GLOBAL);*/ - - int version([[NSString stringWithContentsOfFile:@"/var/lib/cydia/firmware.ver"] intValue]); - - if (access("/tmp/.cydia.fw", F_OK) == 0) { - unlink("/tmp/.cydia.fw"); - goto firmware; - } else if (access("/User", F_OK) != 0 || version < 2) { - firmware: - _trace(); - system("/usr/libexec/cydia/firmware.sh"); - _trace(); - } - - _assert([[NSFileManager defaultManager] - createDirectoryAtPath:@"/var/cache/apt/archives/partial" - withIntermediateDirectories:YES - attributes:nil - error:NULL - ]); - - if (access("/tmp/cydia.chk", F_OK) == 0) { - if (unlink("/var/cache/apt/pkgcache.bin") == -1) - _assert(errno == ENOENT); - if (unlink("/var/cache/apt/srcpkgcache.bin") == -1) - _assert(errno == ENOENT); - } - - /* APT Initialization {{{ */ - _assert(pkgInitConfig(*_config)); - _assert(pkgInitSystem(*_config, _system)); - - if (lang != NULL) - _config->Set("APT::Acquire::Translation", lang); - _config->Set("Acquire::http::Timeout", 15); - _config->Set("Acquire::http::MaxParallel", 3); - /* }}} */ - /* Color Choices {{{ */ - space_ = CGColorSpaceCreateDeviceRGB(); - - Blue_.Set(space_, 0.2, 0.2, 1.0, 1.0); - Blueish_.Set(space_, 0x19/255.f, 0x32/255.f, 0x50/255.f, 1.0); - Black_.Set(space_, 0.0, 0.0, 0.0, 1.0); - Off_.Set(space_, 0.9, 0.9, 0.9, 1.0); - White_.Set(space_, 1.0, 1.0, 1.0, 1.0); - Gray_.Set(space_, 0.4, 0.4, 0.4, 1.0); - Green_.Set(space_, 0.0, 0.5, 0.0, 1.0); - Purple_.Set(space_, 0.0, 0.0, 0.7, 1.0); - Purplish_.Set(space_, 0.4, 0.4, 0.8, 1.0); - - InstallingColor_ = [UIColor colorWithRed:0.88f green:1.00f blue:0.88f alpha:1.00f]; - RemovingColor_ = [UIColor colorWithRed:1.00f green:0.88f blue:0.88f alpha:1.00f]; - /* }}}*/ - /* UIKit Configuration {{{ */ - void (*$GSFontSetUseLegacyFontMetrics)(BOOL)(reinterpret_cast<void (*)(BOOL)>(dlsym(RTLD_DEFAULT, "GSFontSetUseLegacyFontMetrics"))); - if ($GSFontSetUseLegacyFontMetrics != NULL) - $GSFontSetUseLegacyFontMetrics(YES); - - // XXX: I have a feeling this was important - //UIKeyboardDisableAutomaticAppearance(); - /* }}} */ - - Colon_ = UCLocalize("COLON_DELIMITED"); - Error_ = UCLocalize("ERROR"); - Warning_ = UCLocalize("WARNING"); - - _trace(); - int value(UIApplicationMain(argc, argv, @"Cydia", @"Cydia")); - - CGColorSpaceRelease(space_); - CFRelease(Locale_); - - return value; -} |