1 /* Cydia - iPhone UIKit Front-End for Debian APT
2 * Copyright (C) 2008 Jay Freeman (saurik)
6 * Redistribution and use in source and binary
7 * forms, with or without modification, are permitted
8 * provided that the following conditions are met:
10 * 1. Redistributions of source code must retain the
11 * above copyright notice, this list of conditions
12 * and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the
14 * above copyright notice, this list of conditions
15 * and the following disclaimer in the documentation
16 * and/or other materials provided with the
18 * 3. The name of the author may not be used to endorse
19 * or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS''
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
24 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
33 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
35 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 /* #include Directives {{{ */
39 #include <objc/objc.h>
40 #include <objc/runtime.h>
42 #include <CoreGraphics/CoreGraphics.h>
43 #include <GraphicsServices/GraphicsServices.h>
44 #include <Foundation/Foundation.h>
46 #include <WebCore/DOMHTML.h>
47 #import <QuartzCore/CALayer.h>
49 #import <UIKit/UIKit.h>
52 #import <UIKit/UIActionSheet-Private.h>
53 #import <UIKit/UIControl-UIControlPrivate.h>
54 #import <UIKit/UIImage-UIImageDeprecated.h>
55 #import <UIKit/UIImage-UIImagePrivate.h>
56 #import <UIKit/UINavigationBar-Static.h>
57 #import <UIKit/UIProgressHUD-Deprecated.h>
58 #import <UIKit/UIToolbar-UIButtonBarPrivate.h>
59 #import <UIKit/UIView-Deprecated.h>
60 #import <UIKit/UIWindow-Static.h>
63 #import <UIKit/NSString-UIStringDrawingDeprecated.h>
65 #include <WebKit/WebFrame.h>
66 #include <WebKit/WebView.h>
71 #include <ext/stdio_filebuf.h>
73 #include <apt-pkg/acquire.h>
74 #include <apt-pkg/acquire-item.h>
75 #include <apt-pkg/algorithms.h>
76 #include <apt-pkg/cachefile.h>
77 #include <apt-pkg/clean.h>
78 #include <apt-pkg/configuration.h>
79 #include <apt-pkg/debmetaindex.h>
80 #include <apt-pkg/error.h>
81 #include <apt-pkg/init.h>
82 #include <apt-pkg/mmap.h>
83 #include <apt-pkg/pkgrecords.h>
84 #include <apt-pkg/sha1.h>
85 #include <apt-pkg/sourcelist.h>
86 #include <apt-pkg/sptr.h>
88 #include <sys/types.h>
90 #include <sys/sysctl.h>
96 #include <mach-o/nlist.h>
106 #import "BrowserView.h"
107 #import "ResetView.h"
108 #import "UICaboodle.h"
111 static const NSStringCompareOptions CompareOptions_ = NSCaseInsensitiveSearch | NSNumericSearch | NSDiacriticInsensitiveSearch | NSWidthInsensitiveSearch | NSForcedOrderingSearch;
113 @interface WebView (Cydia)
114 - (void) _setLayoutInterval:(float)interval;
117 /* iPhoneOS 2.0 Compatibility {{{ */
119 @interface UICGColor : NSObject {
122 - (id) initWithCGColor:(CGColorRef)color;
125 @interface NSObject (iPhoneOS)
126 - (CGColorRef) cgColor;
127 - (CGColorRef) CGColor;
131 @implementation NSObject (iPhoneOS)
133 - (CGColorRef) cgColor {
134 return [self CGColor];
137 - (CGColorRef) CGColor {
138 return (CGColorRef) self;
142 [[[[objc_getClass("UICGColor") alloc] initWithCGColor:[self CGColor]] autorelease] set];
147 @interface UITextView (iPhoneOS)
148 - (void) setTextSize:(float)size;
151 @implementation UITextView (iPhoneOS)
153 - (void) setTextSize:(float)size {
154 [self setFont:[[self font] fontWithSize:size]];
161 @interface UIApplication (IdleTimer)
162 - (void) setIdleTimerDisabled:(char)arg0;
165 /* Information Dictionaries {{{ */
166 @interface NSMutableArray (Cydia)
167 - (void) addInfoDictionary:(NSDictionary *)info;
170 @implementation NSMutableArray (Cydia)
172 - (void) addInfoDictionary:(NSDictionary *)info {
173 [self addObject:info];
178 @interface NSMutableDictionary (Cydia)
179 - (void) addInfoDictionary:(NSDictionary *)info;
182 @implementation NSMutableDictionary (Cydia)
184 - (void) addInfoDictionary:(NSDictionary *)info {
185 NSString *bundle = [info objectForKey:@"CFBundleIdentifier"];
186 [self setObject:info forKey:bundle];
192 extern "C" int UIApplicationMain(int argc, char *argv[], NSString *principalClassName, NSString *delegateClassName);
194 extern NSString *kUIButtonBarButtonAction;
195 extern NSString *kUIButtonBarButtonInfo;
196 extern NSString *kUIButtonBarButtonInfoOffset;
197 extern NSString *kUIButtonBarButtonSelectedInfo;
198 extern NSString *kUIButtonBarButtonStyle;
199 extern NSString *kUIButtonBarButtonTag;
200 extern NSString *kUIButtonBarButtonTarget;
201 extern NSString *kUIButtonBarButtonTitle;
202 extern NSString *kUIButtonBarButtonTitleVerticalHeight;
203 extern NSString *kUIButtonBarButtonTitleWidth;
204 extern NSString *kUIButtonBarButtonType;
207 kUIProgressIndicatorStyleLargeWhite = 0,
208 kUIProgressIndicatorStyleMediumWhite = 1,
209 kUIProgressIndicatorStyleMediumBrown = 2,
210 kUIProgressIndicatorStyleSmallWhite = 3,
211 kUIProgressIndicatorStyleSmallBlack = 4,
212 kUIProgressIndicatorStyleTinyWhite = 5,
213 } UIProgressIndicatorStyle;
216 kUIControlEventMouseDown = 1 << 0,
217 kUIControlEventMouseMovedInside = 1 << 2, // mouse moved inside control target
218 kUIControlEventMouseMovedOutside = 1 << 3, // mouse moved outside control target
219 kUIControlEventMouseUpInside = 1 << 6, // mouse up inside control target
220 kUIControlEventMouseUpOutside = 1 << 7, // mouse up outside control target
221 kUIControlAllEvents = (kUIControlEventMouseDown | kUIControlEventMouseMovedInside | kUIControlEventMouseMovedOutside | kUIControlEventMouseUpInside | kUIControlEventMouseUpOutside)
222 } UIControlEventMasks;
224 @interface NSString (UIKit)
225 - (NSString *) stringByAddingPercentEscapes;
226 - (NSString *) stringByReplacingCharacter:(unsigned short)arg0 withCharacter:(unsigned short)arg1;
229 @interface NSString (Cydia)
230 + (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length;
231 - (NSComparisonResult) compareByPath:(NSString *)other;
234 @implementation NSString (Cydia)
236 + (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length {
237 char data[length + 1];
238 memcpy(data, bytes, length);
240 return [NSString stringWithUTF8String:data];
243 - (NSComparisonResult) compareByPath:(NSString *)other {
244 NSString *prefix = [self commonPrefixWithString:other options:0];
245 size_t length = [prefix length];
247 NSRange lrange = NSMakeRange(length, [self length] - length);
248 NSRange rrange = NSMakeRange(length, [other length] - length);
250 lrange = [self rangeOfString:@"/" options:0 range:lrange];
251 rrange = [other rangeOfString:@"/" options:0 range:rrange];
253 NSComparisonResult value;
255 if (lrange.location == NSNotFound && rrange.location == NSNotFound)
256 value = NSOrderedSame;
257 else if (lrange.location == NSNotFound)
258 value = NSOrderedAscending;
259 else if (rrange.location == NSNotFound)
260 value = NSOrderedDescending;
262 value = NSOrderedSame;
264 NSString *lpath = lrange.location == NSNotFound ? [self substringFromIndex:length] :
265 [self substringWithRange:NSMakeRange(length, lrange.location - length)];
266 NSString *rpath = rrange.location == NSNotFound ? [other substringFromIndex:length] :
267 [other substringWithRange:NSMakeRange(length, rrange.location - length)];
269 NSComparisonResult result = [lpath compare:rpath];
270 return result == NSOrderedSame ? value : result;
275 /* Perl-Compatible RegEx {{{ */
285 Pcre(const char *regex) :
290 code_ = pcre_compile(regex, 0, &error, &offset, NULL);
293 fprintf(stderr, "%d:%s\n", offset, error);
297 pcre_fullinfo(code_, study_, PCRE_INFO_CAPTURECOUNT, &capture_);
298 matches_ = new int[(capture_ + 1) * 3];
306 NSString *operator [](size_t match) {
307 return [NSString stringWithUTF8Bytes:(data_ + matches_[match * 2]) length:(matches_[match * 2 + 1] - matches_[match * 2])];
310 bool operator ()(NSString *data) {
311 // XXX: length is for characters, not for bytes
312 return operator ()([data UTF8String], [data length]);
315 bool operator ()(const char *data, size_t size) {
317 return pcre_exec(code_, study_, data, size, 0, 0, matches_, (capture_ + 1) * 3) >= 0;
321 /* Mime Addresses {{{ */
322 @interface Address : NSObject {
328 - (NSString *) address;
330 + (Address *) addressWithString:(NSString *)string;
331 - (Address *) initWithString:(NSString *)string;
334 @implementation Address
343 - (NSString *) name {
347 - (NSString *) address {
351 + (Address *) addressWithString:(NSString *)string {
352 return [[[Address alloc] initWithString:string] autorelease];
355 + (NSArray *) _attributeKeys {
356 return [NSArray arrayWithObjects:@"address", @"name", nil];
359 - (NSArray *) attributeKeys {
360 return [[self class] _attributeKeys];
363 + (BOOL) isKeyExcludedFromWebScript:(const char *)name {
364 return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name];
367 - (Address *) initWithString:(NSString *)string {
368 if ((self = [super init]) != nil) {
369 const char *data = [string UTF8String];
370 size_t size = [string length];
372 static Pcre address_r("^\"?(.*)\"? <([^>]*)>$");
374 if (address_r(data, size)) {
375 name_ = [address_r[1] retain];
376 address_ = [address_r[2] retain];
378 name_ = [[NSString alloc]
381 encoding:kCFStringEncodingUTF8
391 /* CoreGraphics Primitives {{{ */
402 CGColor(CGColorSpaceRef space, float red, float green, float blue, float alpha) :
405 Set(space, red, green, blue, alpha);
410 CGColorRelease(color_);
417 void Set(CGColorSpaceRef space, float red, float green, float blue, float alpha) {
419 float color[] = {red, green, blue, alpha};
420 color_ = CGColorCreate(space, color);
423 operator CGColorRef() {
429 extern "C" void UISetColor(CGColorRef color);
431 /* Random Global Variables {{{ */
432 static const int PulseInterval_ = 50000;
433 static const int ButtonBarHeight_ = 48;
434 static const float KeyboardTime_ = 0.3f;
435 static const char * const SpringBoard_ = "/System/Library/LaunchDaemons/com.apple.SpringBoard.plist";
437 static CGColor Blue_;
438 static CGColor Blueish_;
439 static CGColor Black_;
442 static CGColor White_;
443 static CGColor Gray_;
445 static NSString *App_;
446 static NSString *Home_;
447 static BOOL Sounds_Keyboard_;
449 static BOOL Advanced_;
451 static BOOL Ignored_;
453 static UIFont *Font12_;
454 static UIFont *Font12Bold_;
455 static UIFont *Font14_;
456 static UIFont *Font18Bold_;
457 static UIFont *Font22Bold_;
459 static const char *Firmware_ = NULL;
460 static const char *Machine_ = NULL;
461 static const NSString *UniqueID_ = NULL;
468 CGColorSpaceRef space_;
470 #define FW_LEAST(major, minor, bugfix) \
471 (major < Major_ || major == Major_ && \
472 (minor < Minor_ || minor == Minor_ && \
478 static NSDictionary *SectionMap_;
479 static NSMutableDictionary *Metadata_;
480 static _transient NSMutableDictionary *Settings_;
481 static _transient NSString *Role_;
482 static _transient NSMutableDictionary *Packages_;
483 static _transient NSMutableDictionary *Sections_;
484 static _transient NSMutableDictionary *Sources_;
485 static _transient NSMutableArray *Documents_;
486 static bool Changed_;
489 NSString *GetLastUpdate() {
490 NSDate *update = [Metadata_ objectForKey:@"LastUpdate"];
493 return @"Never or Unknown";
495 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, Locale_, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
496 CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) update);
498 CFRelease(formatter);
500 return [(NSString *) formatted autorelease];
503 /* Display Helpers {{{ */
504 inline float Interpolate(float begin, float end, float fraction) {
505 return (end - begin) * fraction + begin;
508 NSString *SizeString(double size) {
510 while (size > 1024) {
515 static const char *powers_[] = {"B", "kB", "MB", "GB"};
517 return [NSString stringWithFormat:@"%.1f%s", size, powers_[power]];
520 NSString *StripVersion(NSString *version) {
521 NSRange colon = [version rangeOfString:@":"];
522 if (colon.location != NSNotFound)
523 version = [version substringFromIndex:(colon.location + 1)];
527 static const float TextViewOffset_ = 22;
529 UITextView *GetTextView(NSString *value, float left, bool html) {
530 UITextView *text([[[UITextView alloc] initWithFrame:CGRectMake(left, 3, 310 - left, 1000)] autorelease]);
531 [text setEditable:NO];
532 [text setTextSize:16];
534 [text setHTML:value];
536 [text setText:value];
537 [text setEnabled:NO];
539 [text setBackgroundColor:[UIColor clearColor]];
541 CGRect frame = [text frame];
542 [text setFrame:frame];
543 CGRect rect = [text visibleTextRect];
544 frame.size.height = rect.size.height;
545 [text setFrame:frame];
550 NSString *Simplify(NSString *title) {
551 const char *data = [title UTF8String];
552 size_t size = [title length];
554 static Pcre square_r("^\\[(.*)\\]$");
555 if (square_r(data, size))
556 return Simplify(square_r[1]);
558 static Pcre paren_r("^\\((.*)\\)$");
559 if (paren_r(data, size))
560 return Simplify(paren_r[1]);
562 static Pcre title_r("^(.*?) \\(.*\\)$");
563 if (title_r(data, size))
564 return Simplify(title_r[1]);
570 bool isSectionVisible(NSString *section) {
571 NSDictionary *metadata = [Sections_ objectForKey:section];
572 NSNumber *hidden = metadata == nil ? nil : [metadata objectForKey:@"Hidden"];
573 return hidden == nil || ![hidden boolValue];
576 /* Delegate Prototypes {{{ */
580 @interface NSObject (ProgressDelegate)
583 @implementation NSObject(ProgressDelegate)
585 - (void) _setProgressError:(NSArray *)args {
586 [self performSelector:@selector(setProgressError:forPackage:)
587 withObject:[args objectAtIndex:0]
588 withObject:([args count] == 1 ? nil : [args objectAtIndex:1])
594 @protocol ProgressDelegate
595 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id;
596 - (void) setProgressTitle:(NSString *)title;
597 - (void) setProgressPercent:(float)percent;
598 - (void) startProgress;
599 - (void) addProgressOutput:(NSString *)output;
600 - (bool) isCancelling:(size_t)received;
603 @protocol ConfigurationDelegate
604 - (void) repairWithSelector:(SEL)selector;
605 - (void) setConfigurationData:(NSString *)data;
608 @protocol CydiaDelegate
609 - (void) installPackage:(Package *)package;
610 - (void) removePackage:(Package *)package;
611 - (void) slideUp:(UIActionSheet *)alert;
612 - (void) distUpgrade;
615 - (void) askForSettings;
616 - (UIProgressHUD *) addProgressHUD;
620 /* Status Delegation {{{ */
622 public pkgAcquireStatus
625 _transient NSObject<ProgressDelegate> *delegate_;
633 void setDelegate(id delegate) {
634 delegate_ = delegate;
637 virtual bool MediaChange(std::string media, std::string drive) {
641 virtual void IMSHit(pkgAcquire::ItemDesc &item) {
644 virtual void Fetch(pkgAcquire::ItemDesc &item) {
645 [delegate_ setProgressTitle:[NSString stringWithUTF8String:("Downloading " + item.ShortDesc).c_str()]];
648 virtual void Done(pkgAcquire::ItemDesc &item) {
651 virtual void Fail(pkgAcquire::ItemDesc &item) {
653 item.Owner->Status == pkgAcquire::Item::StatIdle ||
654 item.Owner->Status == pkgAcquire::Item::StatDone
658 [delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
659 withObject:[NSArray arrayWithObjects:[NSString stringWithUTF8String:item.Owner->ErrorText.c_str()], nil]
664 virtual bool Pulse(pkgAcquire *Owner) {
665 bool value = pkgAcquireStatus::Pulse(Owner);
668 double(CurrentBytes + CurrentItems) /
669 double(TotalBytes + TotalItems)
672 [delegate_ setProgressPercent:percent];
673 return [delegate_ isCancelling:CurrentBytes] ? false : value;
676 virtual void Start() {
677 [delegate_ startProgress];
680 virtual void Stop() {
684 /* Progress Delegation {{{ */
689 _transient id<ProgressDelegate> delegate_;
692 virtual void Update() {
693 [delegate_ setProgressTitle:[NSString stringWithUTF8String:Op.c_str()]];
694 [delegate_ setProgressPercent:(Percent / 100)];
703 void setDelegate(id delegate) {
704 delegate_ = delegate;
707 virtual void Done() {
708 [delegate_ setProgressPercent:1];
713 /* Database Interface {{{ */
714 @interface Database : NSObject {
716 pkgDepCache::Policy *policy_;
717 pkgRecords *records_;
718 pkgProblemResolver *resolver_;
719 pkgAcquire *fetcher_;
721 SPtr<pkgPackageManager> manager_;
722 pkgSourceList *list_;
724 NSMutableDictionary *sources_;
725 NSMutableArray *packages_;
727 _transient NSObject<ConfigurationDelegate, ProgressDelegate> *delegate_;
736 - (void) _readCydia:(NSNumber *)fd;
737 - (void) _readStatus:(NSNumber *)fd;
738 - (void) _readOutput:(NSNumber *)fd;
742 - (Package *) packageWithName:(NSString *)name;
745 - (pkgCacheFile &) cache;
746 - (pkgDepCache::Policy *) policy;
747 - (pkgRecords *) records;
748 - (pkgProblemResolver *) resolver;
749 - (pkgAcquire &) fetcher;
750 - (NSArray *) packages;
751 - (NSArray *) sources;
760 - (void) updateWithStatus:(Status &)status;
762 - (void) setDelegate:(id)delegate;
763 - (Source *) getSource:(const pkgCache::PkgFileIterator &)file;
767 /* Source Class {{{ */
768 @interface Source : NSObject {
769 NSString *description_;
774 NSString *distribution_;
778 NSString *defaultIcon_;
780 NSDictionary *record_;
784 - (Source *) initWithMetaIndex:(metaIndex *)index;
786 - (NSComparisonResult) compareByNameAndType:(Source *)source;
788 - (NSDictionary *) record;
792 - (NSString *) distribution;
798 - (NSString *) description;
799 - (NSString *) label;
800 - (NSString *) origin;
801 - (NSString *) version;
803 - (NSString *) defaultIcon;
807 @implementation Source
811 [distribution_ release];
814 if (description_ != nil)
815 [description_ release];
822 if (defaultIcon_ != nil)
823 [defaultIcon_ release];
830 + (NSArray *) _attributeKeys {
831 return [NSArray arrayWithObjects:@"description", @"distribution", @"host", @"key", @"label", @"name", @"origin", @"trusted", @"type", @"uri", @"version", nil];
834 - (NSArray *) attributeKeys {
835 return [[self class] _attributeKeys];
838 + (BOOL) isKeyExcludedFromWebScript:(const char *)name {
839 return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name];
842 - (Source *) initWithMetaIndex:(metaIndex *)index {
843 if ((self = [super init]) != nil) {
844 trusted_ = index->IsTrusted();
846 uri_ = [[NSString stringWithUTF8String:index->GetURI().c_str()] retain];
847 distribution_ = [[NSString stringWithUTF8String:index->GetDist().c_str()] retain];
848 type_ = [[NSString stringWithUTF8String:index->GetType()] retain];
850 debReleaseIndex *dindex(dynamic_cast<debReleaseIndex *>(index));
851 if (dindex != NULL) {
852 std::ifstream release(dindex->MetaIndexFile("Release").c_str());
854 while (std::getline(release, line)) {
855 std::string::size_type colon(line.find(':'));
856 if (colon == std::string::npos)
859 std::string name(line.substr(0, colon));
860 std::string value(line.substr(colon + 1));
861 while (!value.empty() && value[0] == ' ')
862 value = value.substr(1);
864 if (name == "Default-Icon")
865 defaultIcon_ = [[NSString stringWithUTF8String:value.c_str()] retain];
866 else if (name == "Description")
867 description_ = [[NSString stringWithUTF8String:value.c_str()] retain];
868 else if (name == "Label")
869 label_ = [[NSString stringWithUTF8String:value.c_str()] retain];
870 else if (name == "Origin")
871 origin_ = [[NSString stringWithUTF8String:value.c_str()] retain];
872 else if (name == "Version")
873 version_ = [[NSString stringWithUTF8String:value.c_str()] retain];
877 record_ = [Sources_ objectForKey:[self key]];
879 record_ = [record_ retain];
883 - (NSComparisonResult) compareByNameAndType:(Source *)source {
884 NSDictionary *lhr = [self record];
885 NSDictionary *rhr = [source record];
888 return lhr == nil ? NSOrderedDescending : NSOrderedAscending;
890 NSString *lhs = [self name];
891 NSString *rhs = [source name];
893 if ([lhs length] != 0 && [rhs length] != 0) {
894 unichar lhc = [lhs characterAtIndex:0];
895 unichar rhc = [rhs characterAtIndex:0];
897 if (isalpha(lhc) && !isalpha(rhc))
898 return NSOrderedAscending;
899 else if (!isalpha(lhc) && isalpha(rhc))
900 return NSOrderedDescending;
903 return [lhs compare:rhs options:CompareOptions_];
906 - (NSDictionary *) record {
918 - (NSString *) distribution {
919 return distribution_;
922 - (NSString *) type {
927 return [NSString stringWithFormat:@"%@:%@:%@", type_, uri_, distribution_];
930 - (NSString *) host {
931 return [[[NSURL URLWithString:[self uri]] host] lowercaseString];
934 - (NSString *) name {
935 return origin_ == nil ? [self host] : origin_;
938 - (NSString *) description {
942 - (NSString *) label {
943 return label_ == nil ? [self host] : label_;
946 - (NSString *) origin {
950 - (NSString *) version {
954 - (NSString *) defaultIcon {
960 /* Relationship Class {{{ */
961 @interface Relationship : NSObject {
972 @implementation Relationship
980 - (NSString *) type {
988 - (NSString *) name {
995 /* Package Class {{{ */
996 NSString *Scour(const char *field, const char *begin, const char *end) {
997 size_t i(0), l(strlen(field));
1000 const char *name = begin + i;
1001 const char *colon = name + l;
1002 const char *value = colon + 1;
1007 memcmp(name, field, l) == 0
1009 while (value != end && value[0] == ' ')
1011 const char *line = std::find(value, end, '\n');
1012 while (line != value && line[-1] == ' ')
1015 return [NSString stringWithUTF8Bytes:value length:(line - value)];
1017 begin = std::find(begin, end, '\n');
1025 @interface Package : NSObject {
1026 pkgCache::PkgIterator iterator_;
1027 _transient Database *database_;
1028 pkgCache::VerIterator version_;
1029 pkgCache::VerFileIterator file_;
1035 NSString *installed_;
1041 NSString *depiction_;
1042 NSString *homepage_;
1048 NSArray *relationships_;
1051 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
1052 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
1054 - (pkgCache::PkgIterator) iterator;
1056 - (NSString *) section;
1057 - (Address *) maintainer;
1059 - (NSString *) description;
1060 - (NSString *) index;
1064 - (NSString *) latest;
1065 - (NSString *) installed;
1068 - (BOOL) upgradableAndEssential:(BOOL)essential;
1071 - (BOOL) unfiltered;
1075 - (BOOL) halfConfigured;
1076 - (BOOL) halfInstalled;
1078 - (NSString *) mode;
1081 - (NSString *) name;
1082 - (NSString *) tagline;
1083 - (NSString *) icon;
1084 - (NSString *) homepage;
1085 - (NSString *) depiction;
1086 - (Address *) author;
1088 - (NSArray *) relationships;
1090 - (Source *) source;
1091 - (NSString *) role;
1093 - (BOOL) matches:(NSString *)text;
1095 - (bool) hasSupportingRole;
1096 - (BOOL) hasTag:(NSString *)tag;
1098 - (NSComparisonResult) compareByName:(Package *)package;
1099 - (NSComparisonResult) compareBySection:(Package *)package;
1100 - (NSComparisonResult) compareBySectionAndName:(Package *)package;
1101 - (NSComparisonResult) compareForChanges:(Package *)package;
1106 - (NSNumber *) isUnfilteredAndSearchedForBy:(NSString *)search;
1107 - (NSNumber *) isInstalledAndVisible:(NSNumber *)number;
1108 - (NSNumber *) isVisiblyUninstalledInSection:(NSString *)section;
1109 - (NSNumber *) isVisibleInSource:(Source *)source;
1113 @implementation Package
1120 if (installed_ != nil)
1121 [installed_ release];
1129 if (depiction_ != nil)
1130 [depiction_ release];
1131 if (homepage_ != nil)
1132 [homepage_ release];
1133 if (sponsor_ != nil)
1142 if (relationships_ != nil)
1143 [relationships_ release];
1148 + (NSArray *) _attributeKeys {
1149 return [NSArray arrayWithObjects:@"author", @"depiction", @"description", @"essential", @"homepage", @"icon", @"id", @"installed", @"latest", @"maintainer", @"name", @"section", @"size", @"source", @"sponsor", @"tagline", nil];
1152 - (NSArray *) attributeKeys {
1153 return [[self class] _attributeKeys];
1156 + (BOOL) isKeyExcludedFromWebScript:(const char *)name {
1157 return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name];
1160 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
1161 if ((self = [super init]) != nil) {
1162 iterator_ = iterator;
1163 database_ = database;
1165 version_ = [database_ policy]->GetCandidateVer(iterator_);
1166 latest_ = version_.end() ? nil : [StripVersion([NSString stringWithUTF8String:version_.VerStr()]) retain];
1168 if (!version_.end())
1169 file_ = version_.FileList();
1171 pkgCache &cache([database_ cache]);
1172 file_ = pkgCache::VerFileIterator(cache, cache.VerFileP);
1175 pkgCache::VerIterator current = iterator_.CurrentVer();
1176 installed_ = current.end() ? nil : [StripVersion([NSString stringWithUTF8String:current.VerStr()]) retain];
1178 id_ = [[[NSString stringWithUTF8String:iterator_.Name()] lowercaseString] retain];
1181 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1183 const char *begin, *end;
1184 parser->GetRec(begin, end);
1186 name_ = Scour("Name", begin, end);
1188 name_ = [name_ retain];
1189 tagline_ = [[NSString stringWithUTF8String:parser->ShortDesc().c_str()] retain];
1190 icon_ = Scour("Icon", begin, end);
1192 icon_ = [icon_ retain];
1193 depiction_ = Scour("Depiction", begin, end);
1194 if (depiction_ != nil)
1195 depiction_ = [depiction_ retain];
1196 homepage_ = Scour("Homepage", begin, end);
1197 if (homepage_ == nil)
1198 homepage_ = Scour("Website", begin, end);
1199 if ([homepage_ isEqualToString:depiction_])
1201 if (homepage_ != nil)
1202 homepage_ = [homepage_ retain];
1203 NSString *sponsor = Scour("Sponsor", begin, end);
1205 sponsor_ = [[Address addressWithString:sponsor] retain];
1206 NSString *author = Scour("Author", begin, end);
1208 author_ = [[Address addressWithString:author] retain];
1209 NSString *tags = Scour("Tag", begin, end);
1211 tags_ = [[tags componentsSeparatedByString:@", "] retain];
1215 for (int i(0), e([tags_ count]); i != e; ++i) {
1216 NSString *tag = [tags_ objectAtIndex:i];
1217 if ([tag hasPrefix:@"role::"]) {
1218 role_ = [[tag substringFromIndex:6] retain];
1223 NSMutableDictionary *metadata = [Packages_ objectForKey:id_];
1224 if (metadata == nil || [metadata count] == 0) {
1225 metadata = [NSMutableDictionary dictionaryWithObjectsAndKeys:
1229 [Packages_ setObject:metadata forKey:id_];
1235 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
1236 return [[[Package alloc]
1237 initWithIterator:iterator
1242 - (pkgCache::PkgIterator) iterator {
1246 - (NSString *) section {
1247 const char *section = iterator_.Section();
1248 if (section == NULL)
1251 NSString *name = [[NSString stringWithUTF8String:section] stringByReplacingCharacter:' ' withCharacter:'_'];
1254 if (NSDictionary *value = [SectionMap_ objectForKey:name])
1255 if (NSString *rename = [value objectForKey:@"Rename"]) {
1260 return [name stringByReplacingCharacter:'_' withCharacter:' '];
1263 - (Address *) maintainer {
1266 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1267 return [Address addressWithString:[NSString stringWithUTF8String:parser->Maintainer().c_str()]];
1271 return version_.end() ? 0 : version_->InstalledSize;
1274 - (NSString *) description {
1277 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1278 NSString *description([NSString stringWithUTF8String:parser->LongDesc().c_str()]);
1280 NSArray *lines = [description componentsSeparatedByString:@"\n"];
1281 NSMutableArray *trimmed = [NSMutableArray arrayWithCapacity:([lines count] - 1)];
1282 if ([lines count] < 2)
1285 NSCharacterSet *whitespace = [NSCharacterSet whitespaceCharacterSet];
1286 for (size_t i(1); i != [lines count]; ++i) {
1287 NSString *trim = [[lines objectAtIndex:i] stringByTrimmingCharactersInSet:whitespace];
1288 [trimmed addObject:trim];
1291 return [trimmed componentsJoinedByString:@"\n"];
1294 - (NSString *) index {
1295 NSString *index = [[[self name] substringToIndex:1] uppercaseString];
1296 return [index length] != 0 && isalpha([index characterAtIndex:0]) ? index : @"123";
1300 return [[Packages_ objectForKey:id_] objectForKey:@"FirstSeen"];
1303 - (NSString *) latest {
1307 - (NSString *) installed {
1312 return !version_.end();
1315 - (BOOL) upgradableAndEssential:(BOOL)essential {
1316 pkgCache::VerIterator current = iterator_.CurrentVer();
1319 return essential && [self essential];
1321 pkgCache::VerIterator candidate = [database_ policy]->GetCandidateVer(iterator_);
1322 return !candidate.end() && candidate != current;
1326 - (BOOL) essential {
1327 return (iterator_->Flags & pkgCache::Flag::Essential) == 0 ? NO : YES;
1331 return [database_ cache][iterator_].InstBroken();
1334 - (BOOL) unfiltered {
1335 NSString *section = [self section];
1336 return section == nil || isSectionVisible(section);
1340 return [self hasSupportingRole] && [self unfiltered];
1344 unsigned char current = iterator_->CurrentState;
1345 return current == pkgCache::State::HalfConfigured || current == pkgCache::State::HalfInstalled;
1348 - (BOOL) halfConfigured {
1349 return iterator_->CurrentState == pkgCache::State::HalfConfigured;
1352 - (BOOL) halfInstalled {
1353 return iterator_->CurrentState == pkgCache::State::HalfInstalled;
1357 pkgDepCache::StateCache &state([database_ cache][iterator_]);
1358 return state.Mode != pkgDepCache::ModeKeep;
1361 - (NSString *) mode {
1362 pkgDepCache::StateCache &state([database_ cache][iterator_]);
1364 switch (state.Mode) {
1365 case pkgDepCache::ModeDelete:
1366 if ((state.iFlags & pkgDepCache::Purge) != 0)
1371 case pkgDepCache::ModeKeep:
1372 if ((state.iFlags & pkgDepCache::AutoKept) != 0)
1377 case pkgDepCache::ModeInstall:
1378 if ((state.iFlags & pkgDepCache::ReInstall) != 0)
1379 return @"Reinstall";
1380 else switch (state.Status) {
1382 return @"Downgrade";
1388 return @"New Install";
1401 - (NSString *) name {
1402 return name_ == nil ? id_ : name_;
1405 - (NSString *) tagline {
1409 - (NSString *) icon {
1413 - (NSString *) homepage {
1417 - (NSString *) depiction {
1421 - (Address *) sponsor {
1425 - (Address *) author {
1429 - (NSArray *) relationships {
1430 return relationships_;
1433 - (Source *) source {
1435 source_ = file_.end() ? nil : [[database_ getSource:file_.File()] retain];
1442 - (NSString *) role {
1446 - (BOOL) matches:(NSString *)text {
1452 range = [[self id] rangeOfString:text options:NSCaseInsensitiveSearch];
1453 if (range.location != NSNotFound)
1456 range = [[self name] rangeOfString:text options:NSCaseInsensitiveSearch];
1457 if (range.location != NSNotFound)
1460 range = [[self tagline] rangeOfString:text options:NSCaseInsensitiveSearch];
1461 if (range.location != NSNotFound)
1467 - (bool) hasSupportingRole {
1470 if ([role_ isEqualToString:@"enduser"])
1472 if ([Role_ isEqualToString:@"User"])
1474 if ([role_ isEqualToString:@"hacker"])
1476 if ([Role_ isEqualToString:@"Hacker"])
1478 if ([role_ isEqualToString:@"developer"])
1480 if ([Role_ isEqualToString:@"Developer"])
1485 - (BOOL) hasTag:(NSString *)tag {
1486 return tags_ == nil ? NO : [tags_ containsObject:tag];
1489 - (NSComparisonResult) compareByName:(Package *)package {
1490 NSString *lhs = [self name];
1491 NSString *rhs = [package name];
1493 if ([lhs length] != 0 && [rhs length] != 0) {
1494 unichar lhc = [lhs characterAtIndex:0];
1495 unichar rhc = [rhs characterAtIndex:0];
1497 if (isalpha(lhc) && !isalpha(rhc))
1498 return NSOrderedAscending;
1499 else if (!isalpha(lhc) && isalpha(rhc))
1500 return NSOrderedDescending;
1503 return [lhs compare:rhs options:CompareOptions_];
1506 - (NSComparisonResult) compareBySection:(Package *)package {
1507 NSString *lhs = [self section];
1508 NSString *rhs = [package section];
1510 if (lhs == NULL && rhs != NULL)
1511 return NSOrderedAscending;
1512 else if (lhs != NULL && rhs == NULL)
1513 return NSOrderedDescending;
1514 else if (lhs != NULL && rhs != NULL) {
1515 NSComparisonResult result = [lhs compare:rhs options:CompareOptions_];
1516 if (result != NSOrderedSame)
1520 return NSOrderedSame;
1523 - (NSComparisonResult) compareBySectionAndName:(Package *)package {
1524 NSString *lhs = [self section];
1525 NSString *rhs = [package section];
1527 if (lhs == NULL && rhs != NULL)
1528 return NSOrderedAscending;
1529 else if (lhs != NULL && rhs == NULL)
1530 return NSOrderedDescending;
1531 else if (lhs != NULL && rhs != NULL) {
1532 NSComparisonResult result = [lhs compare:rhs];
1533 if (result != NSOrderedSame)
1537 return [self compareByName:package];
1540 - (NSComparisonResult) compareForChanges:(Package *)package {
1541 BOOL lhs = [self upgradableAndEssential:YES];
1542 BOOL rhs = [package upgradableAndEssential:YES];
1545 return lhs ? NSOrderedAscending : NSOrderedDescending;
1547 switch ([[self seen] compare:[package seen]]) {
1548 case NSOrderedAscending:
1549 return NSOrderedDescending;
1552 case NSOrderedDescending:
1553 return NSOrderedAscending;
1559 return [self compareByName:package];
1563 pkgProblemResolver *resolver = [database_ resolver];
1564 resolver->Clear(iterator_);
1565 resolver->Protect(iterator_);
1566 pkgCacheFile &cache([database_ cache]);
1567 cache->MarkInstall(iterator_, false);
1568 pkgDepCache::StateCache &state((*cache)[iterator_]);
1569 if (!state.Install())
1570 cache->SetReInstall(iterator_, true);
1574 pkgProblemResolver *resolver = [database_ resolver];
1575 resolver->Clear(iterator_);
1576 resolver->Protect(iterator_);
1577 resolver->Remove(iterator_);
1578 [database_ cache]->MarkDelete(iterator_, true);
1581 - (NSNumber *) isUnfilteredAndSearchedForBy:(NSString *)search {
1582 return [NSNumber numberWithBool:(
1583 [self unfiltered] && [self matches:search]
1587 - (NSNumber *) isInstalledAndVisible:(NSNumber *)number {
1588 return [NSNumber numberWithBool:(
1589 (![number boolValue] || [self visible]) && [self installed] != nil
1593 - (NSNumber *) isVisiblyUninstalledInSection:(NSString *)name {
1594 NSString *section = [self section];
1596 return [NSNumber numberWithBool:(
1598 [self installed] == nil && (
1600 section == nil && [name length] == 0 ||
1601 [name isEqualToString:section]
1606 - (NSNumber *) isVisibleInSource:(Source *)source {
1607 return [NSNumber numberWithBool:([self source] == source && [self visible])];
1612 /* Section Class {{{ */
1613 @interface Section : NSObject {
1619 - (NSComparisonResult) compareByName:(Section *)section;
1620 - (Section *) initWithName:(NSString *)name;
1621 - (Section *) initWithName:(NSString *)name row:(size_t)row;
1622 - (NSString *) name;
1625 - (void) addToCount;
1629 @implementation Section
1636 - (NSComparisonResult) compareByName:(Section *)section {
1637 NSString *lhs = [self name];
1638 NSString *rhs = [section name];
1640 if ([lhs length] != 0 && [rhs length] != 0) {
1641 unichar lhc = [lhs characterAtIndex:0];
1642 unichar rhc = [rhs characterAtIndex:0];
1644 if (isalpha(lhc) && !isalpha(rhc))
1645 return NSOrderedAscending;
1646 else if (!isalpha(lhc) && isalpha(rhc))
1647 return NSOrderedDescending;
1650 return [lhs compare:rhs options:CompareOptions_];
1653 - (Section *) initWithName:(NSString *)name {
1654 return [self initWithName:name row:0];
1657 - (Section *) initWithName:(NSString *)name row:(size_t)row {
1658 if ((self = [super init]) != nil) {
1659 name_ = [name retain];
1664 - (NSString *) name {
1676 - (void) addToCount {
1686 /* Database Implementation {{{ */
1687 @implementation Database
1694 - (void) _readCydia:(NSNumber *)fd {
1695 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1697 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1698 std::istream is(&ib);
1701 static Pcre finish_r("^finish:([^:]*)$");
1703 while (std::getline(is, line)) {
1704 const char *data(line.c_str());
1705 size_t size = line.size();
1706 fprintf(stderr, "C:%s\n", data);
1708 if (finish_r(data, size)) {
1709 NSString *finish = finish_r[1];
1710 int index = [Finishes_ indexOfObject:finish];
1711 if (index != INT_MAX && index > Finish_)
1720 - (void) _readStatus:(NSNumber *)fd {
1721 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1723 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1724 std::istream is(&ib);
1727 static Pcre conffile_r("^status: [^ ]* : conffile-prompt : (.*?) *$");
1728 static Pcre pmstatus_r("^([^:]*):([^:]*):([^:]*):(.*)$");
1730 while (std::getline(is, line)) {
1731 const char *data(line.c_str());
1732 size_t size = line.size();
1733 fprintf(stderr, "S:%s\n", data);
1735 if (conffile_r(data, size)) {
1736 [delegate_ setConfigurationData:conffile_r[1]];
1737 } else if (strncmp(data, "status: ", 8) == 0) {
1738 NSString *string = [NSString stringWithUTF8String:(data + 8)];
1739 [delegate_ setProgressTitle:string];
1740 } else if (pmstatus_r(data, size)) {
1741 std::string type([pmstatus_r[1] UTF8String]);
1742 NSString *id = pmstatus_r[2];
1744 float percent([pmstatus_r[3] floatValue]);
1745 [delegate_ setProgressPercent:(percent / 100)];
1747 NSString *string = pmstatus_r[4];
1749 if (type == "pmerror")
1750 [delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
1751 withObject:[NSArray arrayWithObjects:string, id, nil]
1754 else if (type == "pmstatus")
1755 [delegate_ setProgressTitle:string];
1756 else if (type == "pmconffile")
1757 [delegate_ setConfigurationData:string];
1758 else _assert(false);
1759 } else _assert(false);
1766 - (void) _readOutput:(NSNumber *)fd {
1767 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1769 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1770 std::istream is(&ib);
1773 while (std::getline(is, line)) {
1774 fprintf(stderr, "O:%s\n", line.c_str());
1775 [delegate_ addProgressOutput:[NSString stringWithUTF8String:line.c_str()]];
1786 - (Package *) packageWithName:(NSString *)name {
1787 if (static_cast<pkgDepCache *>(cache_) == NULL)
1789 pkgCache::PkgIterator iterator(cache_->FindPkg([name UTF8String]));
1790 return iterator.end() ? nil : [Package packageWithIterator:iterator database:self];
1793 - (Database *) init {
1794 if ((self = [super init]) != nil) {
1801 sources_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1802 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
1806 _assert(pipe(fds) != -1);
1809 _config->Set("APT::Keep-Fds::", cydiafd_);
1810 setenv("CYDIA", [[[[NSNumber numberWithInt:cydiafd_] stringValue] stringByAppendingString:@" 1"] UTF8String], _not(int));
1813 detachNewThreadSelector:@selector(_readCydia:)
1815 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1818 _assert(pipe(fds) != -1);
1822 detachNewThreadSelector:@selector(_readStatus:)
1824 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1827 _assert(pipe(fds) != -1);
1828 _assert(dup2(fds[0], 0) != -1);
1829 _assert(close(fds[0]) != -1);
1831 input_ = fdopen(fds[1], "a");
1833 _assert(pipe(fds) != -1);
1834 _assert(dup2(fds[1], 1) != -1);
1835 _assert(close(fds[1]) != -1);
1838 detachNewThreadSelector:@selector(_readOutput:)
1840 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1845 - (pkgCacheFile &) cache {
1849 - (pkgDepCache::Policy *) policy {
1853 - (pkgRecords *) records {
1857 - (pkgProblemResolver *) resolver {
1861 - (pkgAcquire &) fetcher {
1865 - (NSArray *) packages {
1869 - (NSArray *) sources {
1870 return [sources_ allValues];
1873 - (void) reloadData {
1892 if (!cache_.Open(progress_, true)) {
1894 if (!_error->PopMessage(error))
1897 fprintf(stderr, "cache_.Open():[%s]\n", error.c_str());
1899 if (error == "dpkg was interrupted, you must manually run 'dpkg --configure -a' to correct the problem. ")
1900 [delegate_ repairWithSelector:@selector(configure)];
1901 else if (error == "The package lists or status file could not be parsed or opened.")
1902 [delegate_ repairWithSelector:@selector(update)];
1903 // else if (error == "Could not open lock file /var/lib/dpkg/lock - open (13 Permission denied)")
1904 // else if (error == "Could not get lock /var/lib/dpkg/lock - open (35 Resource temporarily unavailable)")
1905 // else if (error == "The list of sources could not be read.")
1906 else _assert(false);
1911 now_ = [[NSDate date] retain];
1913 policy_ = new pkgDepCache::Policy();
1914 records_ = new pkgRecords(cache_);
1915 resolver_ = new pkgProblemResolver(cache_);
1916 fetcher_ = new pkgAcquire(&status_);
1919 list_ = new pkgSourceList();
1920 _assert(list_->ReadMainList());
1922 _assert(cache_->DelCount() == 0 && cache_->InstCount() == 0);
1923 _assert(pkgApplyStatus(cache_));
1925 if (cache_->BrokenCount() != 0) {
1926 _assert(pkgFixBroken(cache_));
1927 _assert(cache_->BrokenCount() == 0);
1928 _assert(pkgMinimizeUpgrade(cache_));
1931 [sources_ removeAllObjects];
1932 for (pkgSourceList::const_iterator source = list_->begin(); source != list_->end(); ++source) {
1933 std::vector<pkgIndexFile *> *indices = (*source)->GetIndexFiles();
1934 for (std::vector<pkgIndexFile *>::const_iterator index = indices->begin(); index != indices->end(); ++index)
1936 setObject:[[[Source alloc] initWithMetaIndex:*source] autorelease]
1937 forKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(*index)]
1941 [packages_ removeAllObjects];
1942 for (pkgCache::PkgIterator iterator = cache_->PkgBegin(); !iterator.end(); ++iterator)
1943 if (Package *package = [Package packageWithIterator:iterator database:self])
1944 [packages_ addObject:package];
1946 [packages_ sortUsingSelector:@selector(compareByName:)];
1949 - (void) configure {
1950 NSString *dpkg = [NSString stringWithFormat:@"dpkg --configure -a --status-fd %u", statusfd_];
1951 system([dpkg UTF8String]);
1959 Lock.Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1960 _assert(!_error->PendingError());
1963 fetcher.Clean(_config->FindDir("Dir::Cache::Archives"));
1966 public pkgArchiveCleaner
1969 virtual void Erase(const char *File, std::string Pkg, std::string Ver, struct stat &St) {
1974 if (!cleaner.Go(_config->FindDir("Dir::Cache::Archives") + "partial/", cache_)) {
1976 while (_error->PopMessage(error))
1977 fprintf(stderr, "ArchiveCleaner: %s\n", error.c_str());
1982 pkgRecords records(cache_);
1984 lock_ = new FileFd();
1985 lock_->Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1986 _assert(!_error->PendingError());
1989 // XXX: explain this with an error message
1990 _assert(list.ReadMainList());
1992 manager_ = (_system->CreatePM(cache_));
1993 _assert(manager_->GetArchives(fetcher_, &list, &records));
1994 _assert(!_error->PendingError());
1998 NSMutableArray *before = [NSMutableArray arrayWithCapacity:16]; {
2000 _assert(list.ReadMainList());
2001 for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source)
2002 [before addObject:[NSString stringWithUTF8String:(*source)->GetURI().c_str()]];
2005 if (fetcher_->Run(PulseInterval_) != pkgAcquire::Continue) {
2010 bool failed = false;
2011 for (pkgAcquire::ItemIterator item = fetcher_->ItemsBegin(); item != fetcher_->ItemsEnd(); item++) {
2012 if ((*item)->Status == pkgAcquire::Item::StatDone && (*item)->Complete)
2015 std::string uri = (*item)->DescURI();
2016 std::string error = (*item)->ErrorText;
2018 fprintf(stderr, "pAf:%s:%s\n", uri.c_str(), error.c_str());
2021 [delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
2022 withObject:[NSArray arrayWithObjects:[NSString stringWithUTF8String:error.c_str()], nil]
2033 pkgPackageManager::OrderResult result = manager_->DoInstall(statusfd_);
2035 if (_error->PendingError()) {
2040 if (result == pkgPackageManager::Failed) {
2045 if (result != pkgPackageManager::Completed) {
2050 NSMutableArray *after = [NSMutableArray arrayWithCapacity:16]; {
2052 _assert(list.ReadMainList());
2053 for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source)
2054 [after addObject:[NSString stringWithUTF8String:(*source)->GetURI().c_str()]];
2057 if (![before isEqualToArray:after])
2062 _assert(pkgDistUpgrade(cache_));
2066 [self updateWithStatus:status_];
2069 - (void) updateWithStatus:(Status &)status {
2071 _assert(list.ReadMainList());
2074 lock.Fd(GetLock(_config->FindDir("Dir::State::Lists") + "lock"));
2075 _assert(!_error->PendingError());
2077 pkgAcquire fetcher(&status);
2078 _assert(list.GetIndexes(&fetcher));
2080 if (fetcher.Run(PulseInterval_) != pkgAcquire::Failed) {
2081 bool failed = false;
2082 for (pkgAcquire::ItemIterator item = fetcher.ItemsBegin(); item != fetcher.ItemsEnd(); item++)
2083 if ((*item)->Status != pkgAcquire::Item::StatDone) {
2084 (*item)->Finished();
2088 if (!failed && _config->FindB("APT::Get::List-Cleanup", true) == true) {
2089 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists")));
2090 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/"));
2093 [Metadata_ setObject:[NSDate date] forKey:@"LastUpdate"];
2098 - (void) setDelegate:(id)delegate {
2099 delegate_ = delegate;
2100 status_.setDelegate(delegate);
2101 progress_.setDelegate(delegate);
2104 - (Source *) getSource:(const pkgCache::PkgFileIterator &)file {
2105 pkgIndexFile *index(NULL);
2106 list_->FindIndex(file, index);
2107 return [sources_ objectForKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(index)]];
2113 /* Confirmation View {{{ */
2114 void AddTextView(NSMutableDictionary *fields, NSMutableArray *packages, NSString *key) {
2115 if ([packages count] == 0)
2118 UITextView *text = GetTextView([packages count] == 0 ? @"n/a" : [packages componentsJoinedByString:@", "], 120, false);
2119 [fields setObject:text forKey:key];
2121 CGColor blue(space_, 0, 0, 0.4, 1);
2122 [text setTextColor:[UIColor colorWithCGColor:blue]];
2125 bool DepSubstrate(const pkgCache::VerIterator &iterator) {
2126 if (!iterator.end())
2127 for (pkgCache::DepIterator dep(iterator.DependsList()); !dep.end(); ++dep) {
2128 if (dep->Type != pkgCache::Dep::Depends && dep->Type != pkgCache::Dep::PreDepends)
2130 pkgCache::PkgIterator package(dep.TargetPkg());
2133 if (strcmp(package.Name(), "mobilesubstrate") == 0)
2140 @protocol ConfirmationViewDelegate
2145 @interface ConfirmationView : UIView {
2146 Database *database_;
2148 UITransitionView *transition_;
2150 UINavigationBar *navbar_;
2151 UIPreferencesTable *table_;
2152 NSMutableDictionary *fields_;
2153 UIActionSheet *essential_;
2159 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate;
2163 @implementation ConfirmationView
2166 [navbar_ setDelegate:nil];
2167 [transition_ setDelegate:nil];
2168 [table_ setDataSource:nil];
2170 [transition_ release];
2175 if (essential_ != nil)
2176 [essential_ release];
2181 [transition_ transition:7 toView:nil];
2185 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
2186 if (from != nil && to == nil)
2187 [self removeFromSuperview];
2190 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2193 if (essential_ != nil)
2194 [essential_ popupAlertAnimated:YES];
2198 [delegate_ confirm];
2208 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
2209 NSString *context = [sheet context];
2211 if ([context isEqualToString:@"remove"])
2219 [delegate_ confirm];
2224 else if ([context isEqualToString:@"unable"])
2230 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
2234 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
2236 case 0: return @"Statistics";
2237 case 1: return @"Modifications";
2239 default: _assert(false);
2243 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
2246 case 1: return [fields_ count];
2248 default: _assert(false);
2252 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
2253 if (group != 1 || row == -1)
2256 _assert(size_t(row) < [fields_ count]);
2257 return [[[fields_ allValues] objectAtIndex:row] visibleTextRect].size.height + TextViewOffset_;
2261 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
2262 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
2263 [cell setShowSelection:NO];
2266 case 0: switch (row) {
2268 [cell setTitle:@"Downloading"];
2269 [cell setValue:SizeString([database_ fetcher].FetchNeeded())];
2273 [cell setTitle:@"Resuming At"];
2274 [cell setValue:SizeString([database_ fetcher].PartialPresent())];
2278 double size([database_ cache]->UsrSize());
2281 [cell setTitle:@"Disk Freeing"];
2282 [cell setValue:SizeString(-size)];
2284 [cell setTitle:@"Disk Using"];
2285 [cell setValue:SizeString(size)];
2289 default: _assert(false);
2293 _assert(size_t(row) < [fields_ count]);
2294 [cell setTitle:[[fields_ allKeys] objectAtIndex:row]];
2295 [cell addSubview:[[fields_ allValues] objectAtIndex:row]];
2298 default: _assert(false);
2304 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate {
2305 if ((self = [super initWithFrame:[view bounds]]) != nil) {
2306 database_ = database;
2307 delegate_ = delegate;
2309 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
2310 [self addSubview:transition_];
2312 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
2314 CGSize navsize = [UINavigationBar defaultSize];
2315 CGRect navrect = {{0, 0}, navsize};
2316 CGRect bounds = [overlay_ bounds];
2318 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
2319 [navbar_ setDelegate:self];
2321 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Confirm"] autorelease];
2322 [navbar_ pushNavigationItem:navitem];
2323 [navbar_ showButtonsWithLeftTitle:@"Cancel" rightTitle:@"Confirm"];
2325 fields_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
2327 NSMutableArray *installing = [NSMutableArray arrayWithCapacity:16];
2328 NSMutableArray *reinstalling = [NSMutableArray arrayWithCapacity:16];
2329 NSMutableArray *upgrading = [NSMutableArray arrayWithCapacity:16];
2330 NSMutableArray *downgrading = [NSMutableArray arrayWithCapacity:16];
2331 NSMutableArray *removing = [NSMutableArray arrayWithCapacity:16];
2335 pkgDepCache::Policy *policy([database_ policy]);
2337 pkgCacheFile &cache([database_ cache]);
2338 NSArray *packages = [database_ packages];
2339 for (size_t i(0), e = [packages count]; i != e; ++i) {
2340 Package *package = [packages objectAtIndex:i];
2341 pkgCache::PkgIterator iterator = [package iterator];
2342 pkgDepCache::StateCache &state(cache[iterator]);
2344 NSString *name([package name]);
2346 if (state.NewInstall())
2347 [installing addObject:name];
2348 else if (!state.Delete() && (state.iFlags & pkgDepCache::ReInstall) == pkgDepCache::ReInstall)
2349 [reinstalling addObject:name];
2350 else if (state.Upgrade())
2351 [upgrading addObject:name];
2352 else if (state.Downgrade())
2353 [downgrading addObject:name];
2354 else if (state.Delete()) {
2355 if ([package essential])
2357 [removing addObject:name];
2360 substrate_ |= DepSubstrate(policy->GetCandidateVer(iterator));
2361 substrate_ |= DepSubstrate(iterator.CurrentVer());
2366 else if (Advanced_ || true) {
2367 essential_ = [[UIActionSheet alloc]
2368 initWithTitle:@"Removing Essentials"
2369 buttons:[NSArray arrayWithObjects:
2370 @"Cancel Operation (Safe)",
2371 @"Force Removal (Unsafe)",
2373 defaultButtonIndex:0
2379 [essential_ setDestructiveButton:[[essential_ buttons] objectAtIndex:0]];
2381 [essential_ setBodyText:@"This operation involves the removal of one or more packages that are required for the continued operation of either Cydia or iPhoneOS. If you continue, you may not be able to use Cydia to repair any damage."];
2383 essential_ = [[UIActionSheet alloc]
2384 initWithTitle:@"Unable to Comply"
2385 buttons:[NSArray arrayWithObjects:@"Okay", nil]
2386 defaultButtonIndex:0
2391 [essential_ setBodyText:@"This operation requires the removal of one or more packages that are required for the continued operation of either Cydia or iPhoneOS. In order to continue and force this operation you will need to be activate the Advanced mode under to continue and force this operation you will need to be activate the Advanced mode under Settings."];
2394 AddTextView(fields_, installing, @"Installing");
2395 AddTextView(fields_, reinstalling, @"Reinstalling");
2396 AddTextView(fields_, upgrading, @"Upgrading");
2397 AddTextView(fields_, downgrading, @"Downgrading");
2398 AddTextView(fields_, removing, @"Removing");
2400 table_ = [[UIPreferencesTable alloc] initWithFrame:CGRectMake(
2401 0, navsize.height, bounds.size.width, bounds.size.height - navsize.height
2404 [table_ setDataSource:self];
2405 [table_ reloadData];
2407 [overlay_ addSubview:navbar_];
2408 [overlay_ addSubview:table_];
2410 [view addSubview:self];
2412 [transition_ setDelegate:self];
2414 UIView *blank = [[[UIView alloc] initWithFrame:[transition_ bounds]] autorelease];
2415 [transition_ transition:0 toView:blank];
2416 [transition_ transition:3 toView:overlay_];
2423 /* Progress Data {{{ */
2424 @interface ProgressData : NSObject {
2430 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object;
2437 @implementation ProgressData
2439 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object {
2440 if ((self = [super init]) != nil) {
2441 selector_ = selector;
2461 /* Progress View {{{ */
2462 @interface ProgressView : UIView <
2463 ConfigurationDelegate,
2466 _transient Database *database_;
2468 UIView *background_;
2469 UITransitionView *transition_;
2471 UINavigationBar *navbar_;
2472 UIProgressBar *progress_;
2473 UITextView *output_;
2474 UITextLabel *status_;
2475 UIPushButton *close_;
2478 SHA1SumValue springlist_;
2480 NSTimeInterval last_;
2483 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
2485 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database delegate:(id)delegate;
2486 - (void) setContentView:(UIView *)view;
2489 - (void) _retachThread;
2490 - (void) _detachNewThreadData:(ProgressData *)data;
2491 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title;
2497 @protocol ProgressViewDelegate
2498 - (void) progressViewIsComplete:(ProgressView *)sender;
2501 @implementation ProgressView
2504 [transition_ setDelegate:nil];
2505 [navbar_ setDelegate:nil];
2508 if (background_ != nil)
2509 [background_ release];
2510 [transition_ release];
2513 [progress_ release];
2520 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
2521 if (bootstrap_ && from == overlay_ && to == view_)
2525 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database delegate:(id)delegate {
2526 if ((self = [super initWithFrame:frame]) != nil) {
2527 database_ = database;
2528 delegate_ = delegate;
2530 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
2531 [transition_ setDelegate:self];
2533 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
2536 [overlay_ setBackgroundColor:[UIColor blackColor]];
2538 background_ = [[UIView alloc] initWithFrame:[self bounds]];
2539 [background_ setBackgroundColor:[UIColor blackColor]];
2540 [self addSubview:background_];
2543 [self addSubview:transition_];
2545 CGSize navsize = [UINavigationBar defaultSize];
2546 CGRect navrect = {{0, 0}, navsize};
2548 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
2549 [overlay_ addSubview:navbar_];
2551 [navbar_ setBarStyle:1];
2552 [navbar_ setDelegate:self];
2554 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:nil] autorelease];
2555 [navbar_ pushNavigationItem:navitem];
2557 CGRect bounds = [overlay_ bounds];
2558 CGSize prgsize = [UIProgressBar defaultSize];
2561 (bounds.size.width - prgsize.width) / 2,
2562 bounds.size.height - prgsize.height - 20
2565 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
2566 [progress_ setStyle:0];
2568 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(
2570 bounds.size.height - prgsize.height - 50,
2571 bounds.size.width - 20,
2575 [status_ setColor:[UIColor whiteColor]];
2576 [status_ setBackgroundColor:[UIColor clearColor]];
2578 [status_ setCentersHorizontally:YES];
2579 //[status_ setFont:font];
2581 output_ = [[UITextView alloc] initWithFrame:CGRectMake(
2583 navrect.size.height + 20,
2584 bounds.size.width - 20,
2585 bounds.size.height - navsize.height - 62 - navrect.size.height
2588 //[output_ setTextFont:@"Courier New"];
2589 [output_ setTextSize:12];
2591 [output_ setTextColor:[UIColor whiteColor]];
2592 [output_ setBackgroundColor:[UIColor clearColor]];
2594 [output_ setMarginTop:0];
2595 [output_ setAllowsRubberBanding:YES];
2596 [output_ setEditable:NO];
2598 [overlay_ addSubview:output_];
2600 close_ = [[UIPushButton alloc] initWithFrame:CGRectMake(
2602 bounds.size.height - prgsize.height - 50,
2603 bounds.size.width - 20,
2607 [close_ setAutosizesToFit:NO];
2608 [close_ setDrawsShadow:YES];
2609 [close_ setStretchBackground:YES];
2610 [close_ setEnabled:YES];
2612 UIFont *bold = [UIFont boldSystemFontOfSize:22];
2613 [close_ setTitleFont:bold];
2615 [close_ addTarget:self action:@selector(closeButtonPushed) forEvents:kUIControlEventMouseUpInside];
2616 [close_ setBackground:[UIImage applicationImageNamed:@"green-up.png"] forState:0];
2617 [close_ setBackground:[UIImage applicationImageNamed:@"green-dn.png"] forState:1];
2621 - (void) setContentView:(UIView *)view {
2622 view_ = [view retain];
2625 - (void) resetView {
2626 [transition_ transition:6 toView:view_];
2629 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
2630 NSString *context = [sheet context];
2631 if ([context isEqualToString:@"conffile"]) {
2632 FILE *input = [database_ input];
2636 fprintf(input, "N\n");
2640 fprintf(input, "Y\n");
2651 - (void) closeButtonPushed {
2654 [delegate_ progressViewIsComplete:self];
2659 [delegate_ suspendWithAnimation:YES];
2663 system("launchctl stop com.apple.SpringBoard");
2667 system("launchctl unload /System/Library/LaunchDaemons/com.apple.SpringBoard.plist; launchctl load /System/Library/LaunchDaemons/com.apple.SpringBoard.plist");
2676 - (void) _retachThread {
2677 UINavigationItem *item = [navbar_ topItem];
2678 [item setTitle:@"Complete"];
2680 [overlay_ addSubview:close_];
2681 [progress_ removeFromSuperview];
2682 [status_ removeFromSuperview];
2685 FileFd file("/System/Library/LaunchDaemons/com.apple.SpringBoard.plist", FileFd::ReadOnly);
2686 MMap mmap(file, MMap::ReadOnly);
2688 sha1.Add(reinterpret_cast<uint8_t *>(mmap.Data()), mmap.Size());
2689 if (!(springlist_ == sha1.Result()))
2694 case 0: [close_ setTitle:@"Return to Cydia"]; break;
2695 case 1: [close_ setTitle:@"Close Cydia (Restart)"]; break;
2696 case 2: [close_ setTitle:@"Restart SpringBoard"]; break;
2697 case 3: [close_ setTitle:@"Reload SpringBoard"]; break;
2698 case 4: [close_ setTitle:@"Reboot Device"]; break;
2701 #define Cache_ "/User/Library/Caches/com.apple.mobile.installation.plist"
2703 if (NSMutableDictionary *cache = [[NSMutableDictionary alloc] initWithContentsOfFile:@ Cache_]) {
2704 [cache autorelease];
2706 NSFileManager *manager = [NSFileManager defaultManager];
2707 NSError *error = nil;
2709 id system = [cache objectForKey:@"System"];
2714 if (stat(Cache_, &info) == -1)
2717 [system removeAllObjects];
2719 if (NSArray *apps = [manager contentsOfDirectoryAtPath:@"/Applications" error:&error]) {
2720 for (NSString *app in apps)
2721 if ([app hasSuffix:@".app"]) {
2722 NSString *path = [@"/Applications" stringByAppendingPathComponent:app];
2723 NSString *plist = [path stringByAppendingPathComponent:@"Info.plist"];
2724 if (NSMutableDictionary *info = [[NSMutableDictionary alloc] initWithContentsOfFile:plist]) {
2726 [info setObject:path forKey:@"Path"];
2727 [info setObject:@"System" forKey:@"ApplicationType"];
2728 [system addInfoDictionary:info];
2733 [cache writeToFile:@Cache_ atomically:YES];
2735 if (chown(Cache_, info.st_uid, info.st_gid) == -1)
2737 if (chmod(Cache_, info.st_mode) == -1)
2741 fprintf(stderr, "%s\n", error == nil ? strerror(errno) : [[error localizedDescription] UTF8String]);
2744 notify_post("com.apple.mobile.application_installed");
2746 [delegate_ setStatusBarShowsProgress:NO];
2751 - (void) _detachNewThreadData:(ProgressData *)data {
2752 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
2754 [[data target] performSelector:[data selector] withObject:[data object]];
2757 [self performSelectorOnMainThread:@selector(_retachThread) withObject:nil waitUntilDone:YES];
2762 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title {
2763 UINavigationItem *item = [navbar_ topItem];
2764 [item setTitle:title];
2766 [status_ setText:nil];
2767 [output_ setText:@""];
2768 [progress_ setProgress:0];
2771 last_ = 0;//[NSDate timeIntervalSinceReferenceDate];
2773 [close_ removeFromSuperview];
2774 [overlay_ addSubview:progress_];
2775 [overlay_ addSubview:status_];
2777 [delegate_ setStatusBarShowsProgress:YES];
2781 FileFd file("/System/Library/LaunchDaemons/com.apple.SpringBoard.plist", FileFd::ReadOnly);
2782 MMap mmap(file, MMap::ReadOnly);
2784 sha1.Add(reinterpret_cast<uint8_t *>(mmap.Data()), mmap.Size());
2785 springlist_ = sha1.Result();
2788 [transition_ transition:6 toView:overlay_];
2791 detachNewThreadSelector:@selector(_detachNewThreadData:)
2793 withObject:[[ProgressData alloc]
2794 initWithSelector:selector
2801 - (void) repairWithSelector:(SEL)selector {
2803 detachNewThreadSelector:selector
2810 - (void) setConfigurationData:(NSString *)data {
2812 performSelectorOnMainThread:@selector(_setConfigurationData:)
2818 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id {
2819 Package *package = id == nil ? nil : [database_ packageWithName:id];
2821 UIActionSheet *sheet = [[[UIActionSheet alloc]
2822 initWithTitle:(package == nil ? @"Source Error" : [package name])
2823 buttons:[NSArray arrayWithObjects:@"Okay", nil]
2824 defaultButtonIndex:0
2829 [sheet setBodyText:error];
2830 [sheet popupAlertAnimated:YES];
2833 - (void) setProgressTitle:(NSString *)title {
2835 performSelectorOnMainThread:@selector(_setProgressTitle:)
2841 - (void) setProgressPercent:(float)percent {
2843 performSelectorOnMainThread:@selector(_setProgressPercent:)
2844 withObject:[NSNumber numberWithFloat:percent]
2849 - (void) startProgress {
2850 last_ = [NSDate timeIntervalSinceReferenceDate];
2853 - (void) addProgressOutput:(NSString *)output {
2855 performSelectorOnMainThread:@selector(_addProgressOutput:)
2861 - (bool) isCancelling:(size_t)received {
2863 NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate];
2864 if (received_ != received) {
2865 received_ = received;
2867 } else if (now - last_ > 30)
2874 - (void) _setConfigurationData:(NSString *)data {
2875 static Pcre conffile_r("^'(.*)' '(.*)' ([01]) ([01])$");
2877 _assert(conffile_r(data));
2879 NSString *ofile = conffile_r[1];
2880 //NSString *nfile = conffile_r[2];
2882 UIActionSheet *sheet = [[[UIActionSheet alloc]
2883 initWithTitle:@"Configuration Upgrade"
2884 buttons:[NSArray arrayWithObjects:
2885 @"Keep My Old Copy",
2886 @"Accept The New Copy",
2887 // XXX: @"See What Changed",
2889 defaultButtonIndex:0
2894 [sheet setBodyText:[NSString stringWithFormat:
2895 @"The following file has been changed by both the package maintainer and by you (or for you by a script).\n\n%@"
2898 [sheet popupAlertAnimated:YES];
2901 - (void) _setProgressTitle:(NSString *)title {
2902 [status_ setText:title];
2905 - (void) _setProgressPercent:(NSNumber *)percent {
2906 [progress_ setProgress:[percent floatValue]];
2909 - (void) _addProgressOutput:(NSString *)output {
2910 [output_ setText:[NSString stringWithFormat:@"%@\n%@", [output_ text], output]];
2911 CGSize size = [output_ contentSize];
2912 CGRect rect = {{0, size.height}, {size.width, 0}};
2913 [output_ scrollRectToVisible:rect animated:YES];
2916 - (BOOL) isRunning {
2923 /* Package Cell {{{ */
2924 @interface PackageCell : UISimpleTableCell {
2927 NSString *description_;
2929 //UIImageView *trusted_;
2931 UIImageView *badge_;
2932 UITextLabel *status_;
2936 - (PackageCell *) init;
2937 - (void) setPackage:(Package *)package;
2939 + (int) heightForPackage:(Package *)package;
2943 @implementation PackageCell
2945 - (void) clearPackage {
2956 if (description_ != nil) {
2957 [description_ release];
2961 if (source_ != nil) {
2968 [self clearPackage];
2973 //[trusted_ release];
2977 - (PackageCell *) init {
2978 if ((self = [super init]) != nil) {
2980 badge_ = [[UIImageView alloc] initWithFrame:CGRectMake(17, 70, 16, 16)];
2982 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 68, 280, 20)];
2983 [status_ setBackgroundColor:[UIColor clearColor]];
2984 [status_ setFont:small];
2989 - (void) setPackage:(Package *)package {
2990 [self clearPackage];
2992 Source *source = [package source];
2995 if (NSString *icon = [package icon])
2996 icon_ = [UIImage imageAtPath:[icon substringFromIndex:6]];
2997 if (icon_ == nil) if (NSString *section = [package section])
2998 icon_ = [UIImage imageAtPath:[NSString stringWithFormat:@"%@/Sections/%@.png", App_, Simplify(section)]];
2999 /*if (icon_ == nil) if (NSString *icon = [source defaultIcon])
3000 icon_ = [UIImage imageAtPath:[icon substringFromIndex:6]];*/
3002 icon_ = [UIImage applicationImageNamed:@"unknown.png"];
3004 icon_ = [icon_ retain];
3006 name_ = [[package name] retain];
3007 description_ = [[package tagline] retain];
3009 NSString *label = nil;
3010 bool trusted = false;
3012 if (source != nil) {
3013 label = [source label];
3014 trusted = [source trusted];
3015 } else if ([[package id] isEqualToString:@"firmware"])
3018 label = @"Unknown/Local";
3020 NSString *from = [NSString stringWithFormat:@"from %@", label];
3022 NSString *section = Simplify([package section]);
3023 if (section != nil && ![section isEqualToString:label])
3024 from = [from stringByAppendingString:[NSString stringWithFormat:@" (%@)", section]];
3026 source_ = [from retain];
3029 [badge_ removeFromSuperview];
3030 [status_ removeFromSuperview];
3032 if (NSString *mode = [package mode]) {
3033 [badge_ setImage:[UIImage applicationImageNamed:
3034 [mode isEqualToString:@"Remove"] || [mode isEqualToString:@"Purge"] ? @"removing.png" : @"installing.png"
3037 [status_ setText:[NSString stringWithFormat:@"Queued for %@", mode]];
3038 [status_ setColor:Blueish_];
3039 } else if ([package half]) {
3040 [badge_ setImage:[UIImage applicationImageNamed:@"damaged.png"]];
3041 [status_ setText:@"Package Damaged"];
3042 [status_ setColor:[UIColor redColor]];
3044 [badge_ setImage:nil];
3045 [status_ setText:nil];
3049 [self addSubview:badge_];
3050 [self addSubview:status_];
3055 - (void) drawContentInRect:(CGRect)rect selected:(BOOL)selected {
3058 rect.size = [icon_ size];
3060 rect.size.width /= 2;
3061 rect.size.height /= 2;
3063 rect.origin.x = 25 - rect.size.width / 2;
3064 rect.origin.y = 25 - rect.size.height / 2;
3066 [icon_ drawInRect:rect];
3074 [name_ drawAtPoint:CGPointMake(48, 8) forWidth:240 withFont:Font18Bold_ ellipsis:2];
3075 [source_ drawAtPoint:CGPointMake(58, 29) forWidth:225 withFont:Font12_ ellipsis:2];
3079 [description_ drawAtPoint:CGPointMake(12, 46) forWidth:280 withFont:Font14_ ellipsis:2];
3081 [super drawContentInRect:rect selected:selected];
3084 + (int) heightForPackage:(Package *)package {
3085 NSString *tagline([package tagline]);
3086 int height = tagline == nil || [tagline length] == 0 ? -17 : 0;
3088 if ([package hasMode] || [package half])
3097 /* Section Cell {{{ */
3098 @interface SectionCell : UISimpleTableCell {
3103 _UISwitchSlider *switch_;
3108 - (void) setSection:(Section *)section editing:(BOOL)editing;
3112 @implementation SectionCell
3114 - (void) clearSection {
3115 if (section_ != nil) {
3125 if (count_ != nil) {
3132 [self clearSection];
3139 if ((self = [super init]) != nil) {
3140 icon_ = [[UIImage applicationImageNamed:@"folder.png"] retain];
3142 switch_ = [[_UISwitchSlider alloc] initWithFrame:CGRectMake(218, 9, 60, 25)];
3143 [switch_ addTarget:self action:@selector(onSwitch:) forEvents:kUIControlEventMouseUpInside];
3147 - (void) onSwitch:(id)sender {
3148 NSMutableDictionary *metadata = [Sections_ objectForKey:section_];
3149 if (metadata == nil) {
3150 metadata = [NSMutableDictionary dictionaryWithCapacity:2];
3151 [Sections_ setObject:metadata forKey:section_];
3155 [metadata setObject:[NSNumber numberWithBool:([switch_ value] == 0)] forKey:@"Hidden"];
3158 - (void) setSection:(Section *)section editing:(BOOL)editing {
3159 if (editing != editing_) {
3161 [switch_ removeFromSuperview];
3163 [self addSubview:switch_];
3167 [self clearSection];
3169 if (section == nil) {
3170 name_ = [@"All Packages" retain];
3173 section_ = [section name];
3174 if (section_ != nil)
3175 section_ = [section_ retain];
3176 name_ = [(section_ == nil ? @"(No Section)" : section_) retain];
3177 count_ = [[NSString stringWithFormat:@"%d", [section count]] retain];
3180 [switch_ setValue:isSectionVisible(section_) animated:NO];
3184 - (void) drawContentInRect:(CGRect)rect selected:(BOOL)selected {
3185 [icon_ drawInRect:CGRectMake(8, 7, 32, 32)];
3192 [name_ drawAtPoint:CGPointMake(48, 9) forWidth:(editing_ ? 164 : 250) withFont:Font22Bold_ ellipsis:2];
3194 CGSize size = [count_ sizeWithFont:Font14_];
3198 [count_ drawAtPoint:CGPointMake(12 + (29 - size.width) / 2, 15) withFont:Font12Bold_];
3200 [super drawContentInRect:rect selected:selected];
3206 /* File Table {{{ */
3207 @interface FileTable : RVPage {
3208 _transient Database *database_;
3211 NSMutableArray *files_;
3215 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3216 - (void) setPackage:(Package *)package;
3220 @implementation FileTable
3223 if (package_ != nil)
3232 - (int) numberOfRowsInTable:(UITable *)table {
3233 return files_ == nil ? 0 : [files_ count];
3236 - (float) table:(UITable *)table heightForRow:(int)row {
3240 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
3241 if (reusing == nil) {
3242 reusing = [[[UIImageAndTextTableCell alloc] init] autorelease];
3243 UIFont *font = [UIFont systemFontOfSize:16];
3244 [[(UIImageAndTextTableCell *)reusing titleTextLabel] setFont:font];
3246 [(UIImageAndTextTableCell *)reusing setTitle:[files_ objectAtIndex:row]];
3250 - (BOOL) table:(UITable *)table canSelectRow:(int)row {
3254 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3255 if ((self = [super initWithBook:book]) != nil) {
3256 database_ = database;
3258 files_ = [[NSMutableArray arrayWithCapacity:32] retain];
3260 list_ = [[UITable alloc] initWithFrame:[self bounds]];
3261 [self addSubview:list_];
3263 UITableColumn *column = [[[UITableColumn alloc]
3264 initWithTitle:@"Name"
3266 width:[self frame].size.width
3269 [list_ setDataSource:self];
3270 [list_ setSeparatorStyle:1];
3271 [list_ addTableColumn:column];
3272 [list_ setDelegate:self];
3273 [list_ setReusesTableCells:YES];
3277 - (void) setPackage:(Package *)package {
3278 if (package_ != nil) {
3279 [package_ autorelease];
3288 [files_ removeAllObjects];
3290 if (package != nil) {
3291 package_ = [package retain];
3292 name_ = [[package id] retain];
3294 NSString *path = [NSString stringWithFormat:@"/var/lib/dpkg/info/%@.list", name_];
3297 std::ifstream fin([path UTF8String]);
3299 while (std::getline(fin, line))
3300 [files_ addObject:[NSString stringWithUTF8String:line.c_str()]];
3303 if ([files_ count] != 0) {
3304 if ([[files_ objectAtIndex:0] isEqualToString:@"/."])
3305 [files_ removeObjectAtIndex:0];
3306 [files_ sortUsingSelector:@selector(compareByPath:)];
3308 NSMutableArray *stack = [NSMutableArray arrayWithCapacity:8];
3309 [stack addObject:@"/"];
3311 for (int i(0), e([files_ count]); i != e; ++i) {
3312 NSString *file = [files_ objectAtIndex:i];
3313 while (![file hasPrefix:[stack lastObject]])
3314 [stack removeLastObject];
3315 NSString *directory = [stack lastObject];
3316 [stack addObject:[file stringByAppendingString:@"/"]];
3317 [files_ replaceObjectAtIndex:i withObject:[NSString stringWithFormat:@"%*s%@",
3318 ([stack count] - 2) * 3, "",
3319 [file substringFromIndex:[directory length]]
3328 - (void) resetViewAnimated:(BOOL)animated {
3329 [list_ resetViewAnimated:animated];
3332 - (void) reloadData {
3333 [self setPackage:[database_ packageWithName:name_]];
3334 [self reloadButtons];
3337 - (NSString *) title {
3338 return @"Installed Files";
3341 - (NSString *) backButtonTitle {
3347 /* Package View {{{ */
3348 @interface PackageView : BrowserView {
3351 NSMutableArray *buttons_;
3354 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3355 - (void) setPackage:(Package *)package;
3359 @implementation PackageView
3362 if (package_ != nil)
3370 - (void) _clickButtonWithName:(NSString *)name {
3371 if ([name isEqualToString:@"Install"])
3372 [delegate_ installPackage:package_];
3373 else if ([name isEqualToString:@"Reinstall"])
3374 [delegate_ installPackage:package_];
3375 else if ([name isEqualToString:@"Remove"])
3376 [delegate_ removePackage:package_];
3377 else if ([name isEqualToString:@"Upgrade"])
3378 [delegate_ installPackage:package_];
3379 else _assert(false);
3382 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
3383 int count = [buttons_ count];
3384 _assert(count != 0);
3385 _assert(button <= count + 1);
3387 if (count != button - 1)
3388 [self _clickButtonWithName:[buttons_ objectAtIndex:(button - 1)]];
3393 - (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
3394 [[frame windowObject] evaluateWebScript:@"document.base.target = '_top'"];
3395 return [super webView:sender didFinishLoadForFrame:frame];
3398 - (void) webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame {
3399 [window setValue:package_ forKey:@"package"];
3402 - (void) _rightButtonClicked {
3403 /*[super _rightButtonClicked];
3406 int count = [buttons_ count];
3407 _assert(count != 0);
3410 [self _clickButtonWithName:[buttons_ objectAtIndex:0]];
3412 NSMutableArray *buttons = [NSMutableArray arrayWithCapacity:(count + 1)];
3413 [buttons addObjectsFromArray:buttons_];
3414 [buttons addObject:@"Cancel"];
3416 [delegate_ slideUp:[[[UIActionSheet alloc]
3419 defaultButtonIndex:2
3426 - (NSString *) _rightButtonTitle {
3427 int count = [buttons_ count];
3428 return count == 0 ? nil : count != 1 ? @"Modify" : [buttons_ objectAtIndex:0];
3431 - (NSString *) title {
3435 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3436 if ((self = [super initWithBook:book database:database]) != nil) {
3437 database_ = database;
3438 buttons_ = [[NSMutableArray alloc] initWithCapacity:4];
3442 - (void) setPackage:(Package *)package {
3443 if (package_ != nil) {
3444 [package_ autorelease];
3453 [buttons_ removeAllObjects];
3455 if (package != nil) {
3456 package_ = [package retain];
3457 name_ = [[package id] retain];
3459 [self loadURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"package" ofType:@"html"]]];
3461 if ([package_ source] == nil);
3462 else if ([package_ upgradableAndEssential:NO])
3463 [buttons_ addObject:@"Upgrade"];
3464 else if ([package_ installed] == nil)
3465 [buttons_ addObject:@"Install"];
3467 [buttons_ addObject:@"Reinstall"];
3468 if ([package_ installed] != nil)
3469 [buttons_ addObject:@"Remove"];
3473 - (void) reloadData {
3474 [self setPackage:[database_ packageWithName:name_]];
3475 [self reloadButtons];
3480 /* Package Table {{{ */
3481 @interface PackageTable : RVPage {
3482 _transient Database *database_;
3486 NSMutableArray *packages_;
3487 NSMutableArray *sections_;
3488 UISectionList *list_;
3491 - (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object;
3493 - (void) setDelegate:(id)delegate;
3494 - (void) setObject:(id)object;
3496 - (void) reloadData;
3497 - (void) resetCursor;
3499 - (UISectionList *) list;
3501 - (void) setShouldHideHeaderInShortLists:(BOOL)hide;
3505 @implementation PackageTable
3508 [list_ setDataSource:nil];
3513 [packages_ release];
3514 [sections_ release];
3519 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
3520 return [sections_ count];
3523 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
3524 return [[sections_ objectAtIndex:section] name];
3527 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
3528 return [[sections_ objectAtIndex:section] row];
3531 - (int) numberOfRowsInTable:(UITable *)table {
3532 return [packages_ count];
3535 - (float) table:(UITable *)table heightForRow:(int)row {
3536 return [PackageCell heightForPackage:[packages_ objectAtIndex:row]];
3539 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
3541 reusing = [[[PackageCell alloc] init] autorelease];
3542 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
3546 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
3550 - (void) tableRowSelected:(NSNotification *)notification {
3551 int row = [[notification object] selectedRow];
3555 Package *package = [packages_ objectAtIndex:row];
3556 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
3557 [view setDelegate:delegate_];
3558 [view setPackage:package];
3559 [book_ pushPage:view];
3562 - (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object {
3563 if ((self = [super initWithBook:book]) != nil) {
3564 database_ = database;
3565 title_ = [title retain];
3567 object_ = object == nil ? nil : [object retain];
3569 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
3570 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
3572 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:YES];
3573 [list_ setDataSource:self];
3575 UITableColumn *column = [[[UITableColumn alloc]
3576 initWithTitle:@"Name"
3578 width:[self frame].size.width
3581 UITable *table = [list_ table];
3582 [table setSeparatorStyle:1];
3583 [table addTableColumn:column];
3584 [table setDelegate:self];
3585 [table setReusesTableCells:YES];
3587 [self addSubview:list_];
3590 [self setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
3591 [list_ setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
3595 - (void) setDelegate:(id)delegate {
3596 delegate_ = delegate;
3599 - (void) setObject:(id)object {
3605 object_ = [object retain];
3608 - (void) reloadData {
3609 NSArray *packages = [database_ packages];
3611 [packages_ removeAllObjects];
3612 [sections_ removeAllObjects];
3614 for (size_t i(0); i != [packages count]; ++i) {
3615 Package *package([packages objectAtIndex:i]);
3616 if ([package valid] && [[package performSelector:filter_ withObject:object_] boolValue])
3617 [packages_ addObject:package];
3620 Section *section = nil;
3622 for (size_t offset(0); offset != [packages_ count]; ++offset) {
3623 Package *package = [packages_ objectAtIndex:offset];
3624 NSString *name = [package index];
3626 if (section == nil || ![[section name] isEqualToString:name]) {
3627 section = [[[Section alloc] initWithName:name row:offset] autorelease];
3628 [sections_ addObject:section];
3631 [section addToCount];
3637 - (NSString *) title {
3641 - (void) resetViewAnimated:(BOOL)animated {
3642 [list_ resetViewAnimated:animated];
3645 - (void) resetCursor {
3646 [[list_ table] scrollPointVisibleAtTopLeft:CGPointMake(0, 0) animated:NO];
3649 - (UISectionList *) list {
3653 - (void) setShouldHideHeaderInShortLists:(BOOL)hide {
3654 [list_ setShouldHideHeaderInShortLists:hide];
3660 /* Add Source View {{{ */
3661 @interface AddSourceView : RVPage {
3662 _transient Database *database_;
3665 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3669 @implementation AddSourceView
3671 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3672 if ((self = [super initWithBook:book]) != nil) {
3673 database_ = database;
3679 /* Source Cell {{{ */
3680 @interface SourceCell : UITableCell {
3683 NSString *description_;
3689 - (SourceCell *) initWithSource:(Source *)source;
3693 @implementation SourceCell
3698 [description_ release];
3703 - (SourceCell *) initWithSource:(Source *)source {
3704 if ((self = [super init]) != nil) {
3706 icon_ = [UIImage applicationImageNamed:[NSString stringWithFormat:@"Sources/%@.png", [source host]]];
3708 icon_ = [UIImage applicationImageNamed:@"unknown.png"];
3709 icon_ = [icon_ retain];
3711 origin_ = [[source name] retain];
3712 label_ = [[source uri] retain];
3713 description_ = [[source description] retain];
3717 - (void) drawContentInRect:(CGRect)rect selected:(BOOL)selected {
3719 [icon_ drawInRect:CGRectMake(10, 10, 30, 30)];
3726 [origin_ drawAtPoint:CGPointMake(48, 8) forWidth:240 withFont:Font18Bold_ ellipsis:2];
3730 [label_ drawAtPoint:CGPointMake(58, 29) forWidth:225 withFont:Font12_ ellipsis:2];
3734 [description_ drawAtPoint:CGPointMake(12, 46) forWidth:280 withFont:Font14_ ellipsis:2];
3736 [super drawContentInRect:rect selected:selected];
3741 /* Source Table {{{ */
3742 @interface SourceTable : RVPage {
3743 _transient Database *database_;
3744 UISectionList *list_;
3745 NSMutableArray *sources_;
3746 UIActionSheet *alert_;
3750 UIProgressHUD *hud_;
3753 //NSURLConnection *installer_;
3754 NSURLConnection *trivial_bz2_;
3755 NSURLConnection *trivial_gz_;
3756 //NSURLConnection *automatic_;
3761 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3765 @implementation SourceTable
3767 - (void) _deallocConnection:(NSURLConnection *)connection {
3768 if (connection != nil) {
3769 [connection cancel];
3770 //[connection setDelegate:nil];
3771 [connection release];
3776 [[list_ table] setDelegate:nil];
3777 [list_ setDataSource:nil];
3786 //[self _deallocConnection:installer_];
3787 [self _deallocConnection:trivial_gz_];
3788 [self _deallocConnection:trivial_bz2_];
3789 //[self _deallocConnection:automatic_];
3796 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
3797 return offset_ == 0 ? 1 : 2;
3800 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
3801 switch (section + (offset_ == 0 ? 1 : 0)) {
3802 case 0: return @"Entered by User";
3803 case 1: return @"Installed by Packages";
3811 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
3812 switch (section + (offset_ == 0 ? 1 : 0)) {
3814 case 1: return offset_;
3822 - (int) numberOfRowsInTable:(UITable *)table {
3823 return [sources_ count];
3826 - (float) table:(UITable *)table heightForRow:(int)row {
3827 Source *source = [sources_ objectAtIndex:row];
3828 return [source description] == nil ? 56 : 73;
3831 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col {
3832 Source *source = [sources_ objectAtIndex:row];
3833 // XXX: weird warning, stupid selectors ;P
3834 return [[[SourceCell alloc] initWithSource:(id)source] autorelease];
3837 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
3841 - (BOOL) table:(UITable *)table canSelectRow:(int)row {
3845 - (void) tableRowSelected:(NSNotification*)notification {
3846 UITable *table([list_ table]);
3847 int row([table selectedRow]);
3851 Source *source = [sources_ objectAtIndex:row];
3853 PackageTable *packages = [[[PackageTable alloc]
3856 title:[source label]
3857 filter:@selector(isVisibleInSource:)
3861 [packages setDelegate:delegate_];
3863 [book_ pushPage:packages];
3866 - (BOOL) table:(UITable *)table canDeleteRow:(int)row {
3867 Source *source = [sources_ objectAtIndex:row];
3868 return [source record] != nil;
3871 - (void) table:(UITable *)table willSwipeToDeleteRow:(int)row {
3872 [[list_ table] setDeleteConfirmationRow:row];
3875 - (void) table:(UITable *)table deleteRow:(int)row {
3876 Source *source = [sources_ objectAtIndex:row];
3877 [Sources_ removeObjectForKey:[source key]];
3878 [delegate_ syncData];
3881 - (void) _endConnection:(NSURLConnection *)connection {
3882 NSURLConnection **field = NULL;
3883 if (connection == trivial_bz2_)
3884 field = &trivial_bz2_;
3885 else if (connection == trivial_gz_)
3886 field = &trivial_gz_;
3887 _assert(field != NULL);
3888 [connection release];
3892 trivial_bz2_ == nil &&
3895 [delegate_ setStatusBarShowsProgress:NO];
3898 [hud_ removeFromSuperview];
3903 [Sources_ setObject:[NSDictionary dictionaryWithObjectsAndKeys:
3906 @"./", @"Distribution",
3907 nil] forKey:[NSString stringWithFormat:@"deb:%@:./", href_]];
3909 [delegate_ syncData];
3910 } else if (error_ != nil) {
3911 UIActionSheet *sheet = [[[UIActionSheet alloc]
3912 initWithTitle:@"Verification Error"
3913 buttons:[NSArray arrayWithObjects:@"OK", nil]
3914 defaultButtonIndex:0
3919 [sheet setBodyText:[error_ localizedDescription]];
3920 [sheet popupAlertAnimated:YES];
3922 UIActionSheet *sheet = [[[UIActionSheet alloc]
3923 initWithTitle:@"Did not Find Repository"
3924 buttons:[NSArray arrayWithObjects:@"OK", nil]
3925 defaultButtonIndex:0
3930 [sheet setBodyText:@"The indicated repository could not be found. This could be because you are trying to add a legacy Installer repository (these are not supported). Also, this interface is only capable of working with exact repository URLs. If you host a repository and are having issues please contact the author of Cydia with any questions you have."];
3931 [sheet popupAlertAnimated:YES];
3937 if (error_ != nil) {
3944 - (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response {
3945 switch ([response statusCode]) {
3951 - (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
3952 fprintf(stderr, "connection:\"%s\" didFailWithError:\"%s\"", [href_ UTF8String], [[error localizedDescription] UTF8String]);
3954 error_ = [error retain];
3955 [self _endConnection:connection];
3958 - (void) connectionDidFinishLoading:(NSURLConnection *)connection {
3959 [self _endConnection:connection];
3962 - (NSURLConnection *) _requestHRef:(NSString *)href method:(NSString *)method {
3963 NSMutableURLRequest *request = [NSMutableURLRequest
3964 requestWithURL:[NSURL URLWithString:href]
3965 cachePolicy:NSURLRequestUseProtocolCachePolicy
3966 timeoutInterval:20.0
3969 [request setHTTPMethod:method];
3971 return [[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease];
3974 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
3975 NSString *context = [sheet context];
3976 if ([context isEqualToString:@"source"])
3979 NSString *href = [[sheet textField] text];
3981 //installer_ = [[self _requestHRef:href method:@"GET"] retain];
3983 if (![href hasSuffix:@"/"])
3984 href_ = [href stringByAppendingString:@"/"];
3987 href_ = [href_ retain];
3989 trivial_bz2_ = [[self _requestHRef:[href_ stringByAppendingString:@"Packages.bz2"] method:@"HEAD"] retain];
3990 trivial_gz_ = [[self _requestHRef:[href_ stringByAppendingString:@"Packages.gz"] method:@"HEAD"] retain];
3991 //trivial_bz2_ = [[self _requestHRef:[href stringByAppendingString:@"dists/Release"] method:@"HEAD"] retain];
3995 hud_ = [delegate_ addProgressHUD];
3996 [hud_ setText:@"Verifying URL"];
4009 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4010 if ((self = [super initWithBook:book]) != nil) {
4011 database_ = database;
4012 sources_ = [[NSMutableArray arrayWithCapacity:16] retain];
4014 //list_ = [[UITable alloc] initWithFrame:[self bounds]];
4015 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:NO];
4016 [list_ setShouldHideHeaderInShortLists:NO];
4018 [self addSubview:list_];
4019 [list_ setDataSource:self];
4021 UITableColumn *column = [[UITableColumn alloc]
4022 initWithTitle:@"Name"
4024 width:[self frame].size.width
4027 UITable *table = [list_ table];
4028 [table setSeparatorStyle:1];
4029 [table addTableColumn:column];
4030 [table setDelegate:self];
4034 [self setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
4035 [list_ setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
4039 - (void) reloadData {
4041 _assert(list.ReadMainList());
4043 [sources_ removeAllObjects];
4044 [sources_ addObjectsFromArray:[database_ sources]];
4045 [sources_ sortUsingSelector:@selector(compareByNameAndType:)];
4047 int count = [sources_ count];
4048 for (offset_ = 0; offset_ != count; ++offset_) {
4049 Source *source = [sources_ objectAtIndex:offset_];
4050 if ([source record] == nil)
4057 - (void) resetViewAnimated:(BOOL)animated {
4058 [list_ resetViewAnimated:animated];
4061 - (void) _leftButtonClicked {
4062 /*[book_ pushPage:[[[AddSourceView alloc]
4067 UIActionSheet *sheet = [[[UIActionSheet alloc]
4068 initWithTitle:@"Enter Cydia/APT URL"
4069 buttons:[NSArray arrayWithObjects:@"Add Source", @"Cancel", nil]
4070 defaultButtonIndex:0
4075 [sheet addTextFieldWithValue:@"http://" label:@""];
4077 UITextInputTraits *traits = [[sheet textField] textInputTraits];
4078 [traits setAutocapitalizationType:0];
4079 [traits setKeyboardType:3];
4080 [traits setAutocorrectionType:1];
4082 [sheet popupAlertAnimated:YES];
4085 - (void) _rightButtonClicked {
4086 UITable *table = [list_ table];
4087 BOOL editing = [table isRowDeletionEnabled];
4088 [table enableRowDeletion:!editing animated:YES];
4089 [book_ reloadButtonsForPage:self];
4092 - (NSString *) title {
4096 - (NSString *) backButtonTitle {
4100 - (NSString *) leftButtonTitle {
4101 return [[list_ table] isRowDeletionEnabled] ? @"Add" : nil;
4104 - (NSString *) rightButtonTitle {
4105 return [[list_ table] isRowDeletionEnabled] ? @"Done" : @"Edit";
4108 - (UINavigationButtonStyle) rightButtonStyle {
4109 return [[list_ table] isRowDeletionEnabled] ? UINavigationButtonStyleHighlighted : UINavigationButtonStyleNormal;
4115 /* Installed View {{{ */
4116 @interface InstalledView : RVPage {
4117 _transient Database *database_;
4118 PackageTable *packages_;
4122 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4126 @implementation InstalledView
4129 [packages_ release];
4133 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4134 if ((self = [super initWithBook:book]) != nil) {
4135 database_ = database;
4137 packages_ = [[PackageTable alloc]
4141 filter:@selector(isInstalledAndVisible:)
4142 with:[NSNumber numberWithBool:YES]
4145 [self addSubview:packages_];
4147 [self setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
4148 [packages_ setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
4152 - (void) resetViewAnimated:(BOOL)animated {
4153 [packages_ resetViewAnimated:animated];
4156 - (void) reloadData {
4157 [packages_ reloadData];
4160 - (void) _rightButtonClicked {
4161 [packages_ setObject:[NSNumber numberWithBool:expert_]];
4162 [packages_ reloadData];
4164 [book_ reloadButtonsForPage:self];
4167 - (NSString *) title {
4168 return @"Installed";
4171 - (NSString *) backButtonTitle {
4175 - (NSString *) rightButtonTitle {
4176 return Role_ != nil && [Role_ isEqualToString:@"Developer"] ? nil : expert_ ? @"Expert" : @"Simple";
4179 - (UINavigationButtonStyle) rightButtonStyle {
4180 return expert_ ? UINavigationButtonStyleHighlighted : UINavigationButtonStyleNormal;
4183 - (void) setDelegate:(id)delegate {
4184 [super setDelegate:delegate];
4185 [packages_ setDelegate:delegate];
4192 @interface HomeView : BrowserView {
4197 @implementation HomeView
4199 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
4203 - (void) _leftButtonClicked {
4204 UIActionSheet *sheet = [[[UIActionSheet alloc]
4205 initWithTitle:@"About Cydia Installer"
4206 buttons:[NSArray arrayWithObjects:@"Close", nil]
4207 defaultButtonIndex:0
4213 @"Copyright (C) 2008\n"
4214 "Jay Freeman (saurik)\n"
4215 "saurik@saurik.com\n"
4216 "http://www.saurik.com/\n"
4219 "http://www.theokorigroup.com/\n"
4221 "College of Creative Studies,\n"
4222 "University of California,\n"
4224 "http://www.ccs.ucsb.edu/"
4227 [sheet popupAlertAnimated:YES];
4230 - (NSString *) leftButtonTitle {
4236 /* Manage View {{{ */
4237 @interface ManageView : BrowserView {
4242 @implementation ManageView
4244 - (NSString *) title {
4248 - (void) _leftButtonClicked {
4249 [delegate_ askForSettings];
4252 - (NSString *) leftButtonTitle {
4256 - (NSString *) _rightButtonTitle {
4263 /* Indirect Delegate {{{ */
4264 @interface IndirectDelegate : NSProxy {
4265 _transient id delegate_;
4268 - (void) setDelegate:(id)delegate;
4269 - (id) initWithDelegate:(id)delegate;
4272 @implementation IndirectDelegate
4274 - (void) setDelegate:(id)delegate {
4275 delegate_ = delegate;
4278 - (id) initWithDelegate:(id)delegate {
4279 delegate_ = delegate;
4283 - (void) doesNotRecognizeSelector:(SEL)sel {
4284 fprintf(stderr, "doesNotRecognizeSelector:@selector(%s)", sel_getName(sel));
4287 - (NSMethodSignature*) methodSignatureForSelector:(SEL)sel {
4288 if (delegate_ != nil)
4289 if (NSMethodSignature *sig = [delegate_ methodSignatureForSelector:sel])
4294 - (void) forwardInvocation:(NSInvocation*)inv {
4295 SEL sel = [inv selector];
4296 if (delegate_ != nil && [delegate_ respondsToSelector:sel])
4297 [inv invokeWithTarget:delegate_];
4302 /* Browser Implementation {{{ */
4303 @implementation BrowserView
4306 WebView *webview = [webview_ webView];
4307 [webview setFrameLoadDelegate:nil];
4308 [webview setResourceLoadDelegate:nil];
4309 [webview setUIDelegate:nil];
4311 [webview_ setDelegate:nil];
4312 [webview_ setGestureDelegate:nil];
4314 /*WebFrame *frame = [webview mainFrame];
4315 [frame loadHTMLString:@"" baseURL:[NSURL URLWithString:@"http://cydia.saurik.com/"]];*/
4317 //[webview_ removeFromSuperview];
4318 //[Documents_ addObject:[webview_ autorelease]];
4321 [indirect_ setDelegate:nil];
4322 [indirect_ release];
4324 [scroller_ setDelegate:nil];
4326 [scroller_ release];
4328 [indicator_ release];
4334 - (void) loadURL:(NSURL *)url cachePolicy:(NSURLRequestCachePolicy)policy {
4335 [self loadRequest:[NSURLRequest
4338 timeoutInterval:30.0
4342 - (void) loadURL:(NSURL *)url {
4343 [self loadURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy];
4346 - (NSURLRequest *) _addHeadersToRequest:(NSURLRequest *)request {
4347 NSMutableURLRequest *copy = [request mutableCopy];
4349 [copy addValue:[NSString stringWithUTF8String:Firmware_] forHTTPHeaderField:@"X-Firmware"];
4350 [copy addValue:[NSString stringWithUTF8String:Machine_] forHTTPHeaderField:@"X-Machine"];
4351 [copy addValue:UniqueID_ forHTTPHeaderField:@"X-Unique-ID"];
4354 [copy addValue:Role_ forHTTPHeaderField:@"X-Role"];
4359 - (void) loadRequest:(NSURLRequest *)request {
4361 [webview_ loadRequest:request];
4364 - (void) reloadURL {
4365 if ([urls_ count] == 0)
4367 NSURL *url = [[[urls_ lastObject] retain] autorelease];
4368 [urls_ removeLastObject];
4369 [self loadURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData];
4372 - (WebView *) webView {
4373 return [webview_ webView];
4376 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame {
4377 [scroller_ setContentSize:frame.size];
4380 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old {
4381 [self view:sender didSetFrame:frame];
4384 - (void) pushPage:(RVPage *)page {
4385 [self setBackButtonTitle:title_];
4386 [page setDelegate:delegate_];
4387 [book_ pushPage:page];
4390 - (RVPage *) _pageForPackage:(NSString *)name {
4391 if (Package *package = [database_ packageWithName:name]) {
4392 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
4393 [view setPackage:package];
4396 UIActionSheet *sheet = [[[UIActionSheet alloc]
4397 initWithTitle:@"Cannot Locate Package"
4398 buttons:[NSArray arrayWithObjects:@"Close", nil]
4399 defaultButtonIndex:0
4404 [sheet setBodyText:[NSString stringWithFormat:
4405 @"The package %@ cannot be found in your current sources. I might recommend installing more sources."
4408 [sheet popupAlertAnimated:YES];
4413 - (BOOL) getSpecial:(NSString *)href {
4417 [href hasPrefix:@"http://ax.phobos.apple.com/"] ||
4418 [href hasPrefix:@"http://phobos.apple.com/"] ||
4419 [href hasPrefix:@"http://www.youtube.com/watch?"] ||
4420 [href hasPrefix:@"tel:"]
4422 [delegate_ openURL:[NSURL URLWithString:href]];
4423 else if ([href hasPrefix:@"mailto:"]) {
4424 [delegate_ openURL:[NSURL URLWithString:href]];
4425 } else if ([href isEqualToString:@"cydia://add-source"])
4426 page = [[[AddSourceView alloc] initWithBook:book_ database:database_] autorelease];
4427 else if ([href isEqualToString:@"cydia://sources"])
4428 page = [[[SourceTable alloc] initWithBook:book_ database:database_] autorelease];
4429 else if ([href isEqualToString:@"cydia://packages"])
4430 page = [[[InstalledView alloc] initWithBook:book_ database:database_] autorelease];
4431 else if ([href hasPrefix:@"cydia://files/"]) {
4432 NSString *name = [href substringFromIndex:14];
4434 if (Package *package = [database_ packageWithName:name]) {
4435 FileTable *files = [[[FileTable alloc] initWithBook:book_ database:database_] autorelease];
4436 [files setPackage:package];
4439 } else if ([href hasPrefix:@"apptapp://package/"])
4440 page = [self _pageForPackage:[href substringFromIndex:18]];
4441 else if ([href hasPrefix:@"cydia://package/"])
4442 page = [self _pageForPackage:[href substringFromIndex:16]];
4443 else if (![href hasPrefix:@"apptapp:"] && ![href hasPrefix:@"cydia:"])
4447 [self pushPage:page];
4451 - (void) webView:(WebView *)sender willClickElement:(id)element {
4452 if ([[element localName] isEqualToString:@"img"])
4453 do if ((element = [element parentNode]) == nil)
4455 while (![[element localName] isEqualToString:@"a"]);
4456 if (![element respondsToSelector:@selector(href)])
4458 NSString *href = [element href];
4461 [self getSpecial:href];
4464 - (NSURLRequest *) webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource {
4465 NSURL *url = [request URL];
4466 if ([self getSpecial:[url absoluteString]])
4471 [book_ pushPage:self];
4474 return [self _addHeadersToRequest:request];
4477 - (BOOL) isSpecialScheme:(NSString *)scheme {
4479 [scheme isEqualToString:@"apptapp"] ||
4480 [scheme isEqualToString:@"cydia"] ||
4481 [scheme isEqualToString:@"mailto"] ||
4482 [scheme isEqualToString:@"tel"];
4485 - (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request {
4486 if (request != nil) {
4487 NSURL *url = [request URL];
4488 NSString *scheme = [url scheme];
4489 NSString *absolute = [url absoluteString];
4491 [self isSpecialScheme:scheme] ||
4492 [absolute hasPrefix:@"http://ax.phobos.apple.com/"] ||
4493 [absolute hasPrefix:@"http://phobos.apple.com/"] ||
4494 [absolute hasPrefix:@"http://www.yahoo.com/watch?"]
4499 [self setBackButtonTitle:title_];
4501 BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease];
4502 [browser setDelegate:delegate_];
4504 if (request != nil) {
4505 [browser loadRequest:[self _addHeadersToRequest:request]];
4506 [book_ pushPage:browser];
4509 return [browser webView];
4512 - (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame {
4513 if ([frame parentFrame] != nil)
4516 title_ = [title retain];
4517 [self setTitle:title];
4520 - (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame {
4521 if ([frame parentFrame] != nil)
4526 [indicator_ startAnimation];
4527 [self reloadButtons];
4529 if (title_ != nil) {
4534 [self setTitle:@"Loading"];
4536 WebView *webview = [webview_ webView];
4537 NSString *href = [webview mainFrameURL];
4538 [urls_ addObject:[NSURL URLWithString:href]];
4540 CGRect webrect = [scroller_ bounds];
4541 webrect.size.height = 0;
4542 [webview_ setFrame:webrect];
4544 [scroller_ scrollPointVisibleAtTopLeft:CGPointZero];
4547 - (void) _finishLoading {
4550 [indicator_ stopAnimation];
4551 [self reloadButtons];
4555 - (BOOL) webView:(WebView *)sender shouldScrollToPoint:(struct CGPoint)point forFrame:(WebFrame *)frame {
4557 return [webview_ webView:sender shouldScrollToPoint:point forFrame:frame];
4560 - (void) webView:(WebView *)sender didReceiveViewportArguments:(id)arguments forFrame:(WebFrame *)frame {
4561 return [webview_ webView:sender didReceiveViewportArguments:arguments forFrame:frame];
4564 - (void) webView:(WebView *)sender needsScrollNotifications:(id)notifications forFrame:(WebFrame *)frame {
4565 return [webview_ webView:sender needsScrollNotifications:notifications forFrame:frame];
4568 - (void) webView:(WebView *)sender didCommitLoadForFrame:(WebFrame *)frame {
4569 return [webview_ webView:sender didCommitLoadForFrame:frame];
4572 - (void) webView:(WebView *)sender didReceiveDocTypeForFrame:(WebFrame *)frame {
4573 return [webview_ webView:sender didReceiveDocTypeForFrame:frame];
4576 - (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
4577 if ([frame parentFrame] == nil)
4578 [self _finishLoading];
4579 return [webview_ webView:sender didFinishLoadForFrame:frame];
4582 - (void) webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
4583 if ([frame parentFrame] != nil)
4585 [self _finishLoading];
4587 [self loadURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@?%@",
4588 [[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"error" ofType:@"html"]] absoluteString],
4589 [[error localizedDescription] stringByAddingPercentEscapes]
4593 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4594 if ((self = [super initWithBook:book]) != nil) {
4595 database_ = database;
4598 struct CGRect bounds = [self bounds];
4600 UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:bounds] autorelease];
4601 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
4602 [self addSubview:pinstripe];
4604 scroller_ = [[UIScroller alloc] initWithFrame:bounds];
4605 [self addSubview:scroller_];
4607 [scroller_ setScrollingEnabled:YES];
4608 [scroller_ setAdjustForContentSizeChange:YES];
4609 [scroller_ setClipsSubviews:YES];
4610 [scroller_ setAllowsRubberBanding:YES];
4611 [scroller_ setScrollDecelerationFactor:0.99];
4612 [scroller_ setDelegate:self];
4614 CGRect webrect = [scroller_ bounds];
4615 webrect.size.height = 0;
4617 webview_ = [Documents_ lastObject];
4618 if (webview_ != nil) {
4619 webview_ = [webview_ retain];
4620 [Documents_ removeLastObject];
4621 [webview_ setFrame:webrect];
4623 webview_ = [[UIWebDocumentView alloc] initWithFrame:webrect];
4625 [webview_ setTileSize:CGSizeMake(webrect.size.width, 500)];
4627 [webview_ setTilingEnabled:YES];
4628 [webview_ setTileMinificationFilter:kCAFilterNearest];
4629 [webview_ setAutoresizes:YES];
4631 [webview_ setViewportSize:CGSizeMake(980, -1) forDocumentTypes:0x10];
4632 [webview_ setViewportSize:CGSizeMake(320, -1) forDocumentTypes:0x2];
4633 [webview_ setViewportSize:CGSizeMake(320, -1) forDocumentTypes:0x8];
4635 [webview_ _setDocumentType:0x4];
4637 [webview_ setZoomsFocusedFormControl:YES];
4638 [webview_ setContentsPosition:7];
4639 [webview_ setEnabledGestures:0xa];
4640 [webview_ setValue:[NSNumber numberWithBool:YES] forGestureAttribute:0x4];
4641 [webview_ setValue:[NSNumber numberWithBool:YES] forGestureAttribute:0x7];
4642 [webview_ setSmoothsFonts:YES];
4645 [webview_ setDelegate:self];
4646 [webview_ setGestureDelegate:self];
4647 [scroller_ addSubview:webview_];
4649 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:kUIProgressIndicatorStyleMediumWhite];
4650 indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(281, 12, indsize.width, indsize.height)];
4651 [indicator_ setStyle:kUIProgressIndicatorStyleMediumWhite];
4653 Package *package([database_ packageWithName:@"cydia"]);
4654 NSString *application = package == nil ? @"Cydia" : [NSString
4655 stringWithFormat:@"Cydia/%@",
4659 indirect_ = [[IndirectDelegate alloc] initWithDelegate:self];
4661 WebView *webview = [webview_ webView];
4662 [webview setApplicationNameForUserAgent:application];
4663 [webview setFrameLoadDelegate:self];
4664 [webview setResourceLoadDelegate:indirect_];
4665 [webview setUIDelegate:self];
4667 //[webview _setLayoutInterval:0.5];
4669 urls_ = [[NSMutableArray alloc] initWithCapacity:16];
4671 [self setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
4672 [scroller_ setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
4673 [pinstripe setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
4677 - (void) didFinishGesturesInView:(UIView *)view forEvent:(id)event {
4678 [webview_ redrawScaledDocument];
4681 - (void) _rightButtonClicked {
4686 - (NSString *) _rightButtonTitle {
4690 - (NSString *) rightButtonTitle {
4691 return loading_ ? @"" : [self _rightButtonTitle];
4694 - (NSString *) title {
4698 - (NSString *) backButtonTitle {
4702 - (void) setPageActive:(BOOL)active {
4704 [indicator_ removeFromSuperview];
4706 [[book_ navigationBar] addSubview:indicator_];
4709 - (void) resetViewAnimated:(BOOL)animated {
4712 - (void) setPushed:(bool)pushed {
4719 @interface CYBook : RVBook <
4722 _transient Database *database_;
4723 UINavigationBar *overlay_;
4724 UIProgressIndicator *indicator_;
4725 UITextLabel *prompt_;
4726 UIProgressBar *progress_;
4727 UINavigationButton *cancel_;
4730 NSTimeInterval last_;
4733 - (id) initWithFrame:(CGRect)frame database:(Database *)database;
4739 /* Install View {{{ */
4740 @interface InstallView : RVPage {
4741 _transient Database *database_;
4742 NSMutableArray *sections_;
4743 NSMutableArray *filtered_;
4744 UITransitionView *transition_;
4750 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4751 - (void) reloadData;
4756 @implementation InstallView
4759 [list_ setDataSource:nil];
4760 [list_ setDelegate:nil];
4762 [sections_ release];
4763 [filtered_ release];
4764 [transition_ release];
4766 [accessory_ release];
4770 - (int) numberOfRowsInTable:(UITable *)table {
4771 return editing_ ? [sections_ count] : [filtered_ count] + 1;
4774 - (float) table:(UITable *)table heightForRow:(int)row {
4778 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
4780 reusing = [[[SectionCell alloc] init] autorelease];
4781 [(SectionCell *)reusing setSection:(editing_ ?
4782 [sections_ objectAtIndex:row] :
4783 (row == 0 ? nil : [filtered_ objectAtIndex:(row - 1)])
4784 ) editing:editing_];
4788 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
4792 - (BOOL) table:(UITable *)table canSelectRow:(int)row {
4796 - (void) tableRowSelected:(NSNotification *)notification {
4797 int row = [[notification object] selectedRow];
4808 title = @"All Packages";
4810 section = [filtered_ objectAtIndex:(row - 1)];
4811 name = [section name];
4817 title = @"(No Section)";
4821 PackageTable *table = [[[PackageTable alloc]
4825 filter:@selector(isVisiblyUninstalledInSection:)
4829 [table setDelegate:delegate_];
4831 [book_ pushPage:table];
4834 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4835 if ((self = [super initWithBook:book]) != nil) {
4836 database_ = database;
4838 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
4839 filtered_ = [[NSMutableArray arrayWithCapacity:16] retain];
4841 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
4842 [self addSubview:transition_];
4844 list_ = [[UITable alloc] initWithFrame:[transition_ bounds]];
4845 [transition_ transition:0 toView:list_];
4847 UITableColumn *column = [[[UITableColumn alloc]
4848 initWithTitle:@"Name"
4850 width:[self frame].size.width
4853 [list_ setDataSource:self];
4854 [list_ setSeparatorStyle:1];
4855 [list_ addTableColumn:column];
4856 [list_ setDelegate:self];
4857 [list_ setReusesTableCells:YES];
4861 [self setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
4862 [list_ setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
4866 - (void) reloadData {
4867 NSArray *packages = [database_ packages];
4869 [sections_ removeAllObjects];
4870 [filtered_ removeAllObjects];
4872 NSMutableArray *filtered = [NSMutableArray arrayWithCapacity:[packages count]];
4873 NSMutableDictionary *sections = [NSMutableDictionary dictionaryWithCapacity:32];
4875 for (size_t i(0); i != [packages count]; ++i) {
4876 Package *package([packages objectAtIndex:i]);
4877 NSString *name([package section]);
4880 Section *section([sections objectForKey:name]);
4881 if (section == nil) {
4882 section = [[[Section alloc] initWithName:name] autorelease];
4883 [sections setObject:section forKey:name];
4887 if ([package valid] && [package installed] == nil && [package visible])
4888 [filtered addObject:package];
4891 [sections_ addObjectsFromArray:[sections allValues]];
4892 [sections_ sortUsingSelector:@selector(compareByName:)];
4894 [filtered sortUsingSelector:@selector(compareBySection:)];
4896 Section *section = nil;
4897 for (size_t offset = 0, count = [filtered count]; offset != count; ++offset) {
4898 Package *package = [filtered objectAtIndex:offset];
4899 NSString *name = [package section];
4901 if (section == nil || name != nil && ![[section name] isEqualToString:name]) {
4902 section = name == nil ?
4903 [[[Section alloc] initWithName:nil] autorelease] :
4904 [sections objectForKey:name];
4905 [filtered_ addObject:section];
4908 [section addToCount];
4914 - (void) resetView {
4916 [self _rightButtonClicked];
4919 - (void) resetViewAnimated:(BOOL)animated {
4920 [list_ resetViewAnimated:animated];
4923 - (void) _rightButtonClicked {
4924 if ((editing_ = !editing_))
4927 [delegate_ updateData];
4930 [book_ setTitle:[self title] forPage:self];
4931 [book_ reloadButtonsForPage:self];
4934 - (NSString *) title {
4935 return editing_ ? @"Section Visibility" : @"Install by Section";
4938 - (NSString *) backButtonTitle {
4942 - (NSString *) rightButtonTitle {
4943 return [sections_ count] == 0 ? nil : editing_ ? @"Done" : @"Edit";
4946 - (UINavigationButtonStyle) rightButtonStyle {
4947 return editing_ ? UINavigationButtonStyleHighlighted : UINavigationButtonStyleNormal;
4950 - (UIView *) accessoryView {
4956 /* Changes View {{{ */
4957 @interface ChangesView : RVPage {
4958 _transient Database *database_;
4959 NSMutableArray *packages_;
4960 NSMutableArray *sections_;
4961 UISectionList *list_;
4965 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4966 - (void) reloadData;
4970 @implementation ChangesView
4973 [[list_ table] setDelegate:nil];
4974 [list_ setDataSource:nil];
4976 [packages_ release];
4977 [sections_ release];
4982 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
4983 return [sections_ count];
4986 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
4987 return [[sections_ objectAtIndex:section] name];
4990 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
4991 return [[sections_ objectAtIndex:section] row];
4994 - (int) numberOfRowsInTable:(UITable *)table {
4995 return [packages_ count];
4998 - (float) table:(UITable *)table heightForRow:(int)row {
4999 return [PackageCell heightForPackage:[packages_ objectAtIndex:row]];
5002 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
5004 reusing = [[[PackageCell alloc] init] autorelease];
5005 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
5009 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
5013 - (void) tableRowSelected:(NSNotification *)notification {
5014 int row = [[notification object] selectedRow];
5017 Package *package = [packages_ objectAtIndex:row];
5018 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
5019 [view setDelegate:delegate_];
5020 [view setPackage:package];
5021 [book_ pushPage:view];
5024 - (void) _leftButtonClicked {
5025 [(CYBook *)book_ update];
5026 [self reloadButtons];
5029 - (void) _rightButtonClicked {
5030 [delegate_ distUpgrade];
5033 - (id) initWithBook:(RVBook *)book database:(Database *)database {
5034 if ((self = [super initWithBook:book]) != nil) {
5035 database_ = database;
5037 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
5038 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
5040 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:NO];
5041 [self addSubview:list_];
5043 [list_ setShouldHideHeaderInShortLists:NO];
5044 [list_ setDataSource:self];
5045 //[list_ setSectionListStyle:1];
5047 UITableColumn *column = [[[UITableColumn alloc]
5048 initWithTitle:@"Name"
5050 width:[self frame].size.width
5053 UITable *table = [list_ table];
5054 [table setSeparatorStyle:1];
5055 [table addTableColumn:column];
5056 [table setDelegate:self];
5057 [table setReusesTableCells:YES];
5061 [self setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
5062 [list_ setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
5066 - (void) reloadData {
5067 NSArray *packages = [database_ packages];
5069 [packages_ removeAllObjects];
5070 [sections_ removeAllObjects];
5072 for (size_t i(0); i != [packages count]; ++i) {
5073 Package *package([packages objectAtIndex:i]);
5076 [package installed] == nil && [package valid] && [package visible] ||
5077 [package upgradableAndEssential:NO]
5079 [packages_ addObject:package];
5082 [packages_ sortUsingSelector:@selector(compareForChanges:)];
5084 Section *upgradable = [[[Section alloc] initWithName:@"Available Upgrades"] autorelease];
5085 Section *section = nil;
5088 bool unseens = false;
5090 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, Locale_, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
5092 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
5093 Package *package = [packages_ objectAtIndex:offset];
5095 if ([package upgradableAndEssential:YES]) {
5097 [upgradable addToCount];
5100 NSDate *seen = [package seen];
5105 name = [@"n/a ?" retain];
5107 name = (NSString *) CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen);
5110 if (section == nil || ![[section name] isEqualToString:name]) {
5111 section = [[[Section alloc] initWithName:name row:offset] autorelease];
5112 [sections_ addObject:section];
5116 [section addToCount];
5120 CFRelease(formatter);
5123 Section *last = [sections_ lastObject];
5124 size_t count = [last count];
5125 [packages_ removeObjectsInRange:NSMakeRange([packages_ count] - count, count)];
5126 [sections_ removeLastObject];
5130 [sections_ insertObject:upgradable atIndex:0];
5133 [self reloadButtons];
5136 - (void) resetViewAnimated:(BOOL)animated {
5137 [list_ resetViewAnimated:animated];
5140 - (NSString *) leftButtonTitle {
5141 return [(CYBook *)book_ updating] ? nil : @"Refresh";
5144 - (NSString *) rightButtonTitle {
5145 return upgrades_ == 0 ? nil : [NSString stringWithFormat:@"Upgrade (%u)", upgrades_];
5148 - (NSString *) title {
5154 /* Search View {{{ */
5155 @protocol SearchViewDelegate
5156 - (void) showKeyboard:(BOOL)show;
5159 @interface SearchView : RVPage {
5161 UISearchField *field_;
5162 UITransitionView *transition_;
5163 PackageTable *table_;
5164 UIPreferencesTable *advanced_;
5170 - (id) initWithBook:(RVBook *)book database:(Database *)database;
5171 - (void) reloadData;
5175 @implementation SearchView
5178 [field_ setDelegate:nil];
5180 [accessory_ release];
5182 [transition_ release];
5184 [advanced_ release];
5189 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
5193 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
5195 case 0: return @"Advanced Search (Coming Soon!)";
5197 default: _assert(false);
5201 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
5205 default: _assert(false);
5209 - (void) _showKeyboard:(BOOL)show {
5210 CGSize keysize = [UIKeyboard defaultSize];
5211 CGRect keydown = [book_ pageBounds];
5212 CGRect keyup = keydown;
5213 keyup.size.height -= keysize.height - ButtonBarHeight_;
5215 float delay = KeyboardTime_ * ButtonBarHeight_ / keysize.height;
5217 UIFrameAnimation *animation = [[[UIFrameAnimation alloc] initWithTarget:[table_ list]] autorelease];
5218 [animation setSignificantRectFields:8];
5221 [animation setStartFrame:keydown];
5222 [animation setEndFrame:keyup];
5224 [animation setStartFrame:keyup];
5225 [animation setEndFrame:keydown];
5228 UIAnimator *animator = [UIAnimator sharedAnimator];
5231 addAnimations:[NSArray arrayWithObjects:animation, nil]
5232 withDuration:(KeyboardTime_ - delay)
5237 [animator performSelector:@selector(startAnimation:) withObject:animation afterDelay:delay];
5239 [delegate_ showKeyboard:show];
5242 - (void) textFieldDidBecomeFirstResponder:(UITextField *)field {
5243 [self _showKeyboard:YES];
5246 - (void) textFieldDidResignFirstResponder:(UITextField *)field {
5247 [self _showKeyboard:NO];
5250 - (void) keyboardInputChanged:(UIFieldEditor *)editor {
5252 NSString *text([field_ text]);
5253 [field_ setClearButtonStyle:(text == nil || [text length] == 0 ? 0 : 2)];
5259 - (void) textFieldClearButtonPressed:(UITextField *)field {
5263 - (void) keyboardInputShouldDelete:(id)input {
5267 - (BOOL) keyboardInput:(id)input shouldInsertText:(NSString *)text isMarkedText:(int)marked {
5268 if ([text length] != 1 || [text characterAtIndex:0] != '\n') {
5272 [field_ resignFirstResponder];
5277 - (id) initWithBook:(RVBook *)book database:(Database *)database {
5278 if ((self = [super initWithBook:book]) != nil) {
5279 CGRect pageBounds = [book_ pageBounds];
5281 /*UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:pageBounds] autorelease];
5282 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
5283 [self addSubview:pinstripe];*/
5285 transition_ = [[UITransitionView alloc] initWithFrame:pageBounds];
5286 [self addSubview:transition_];
5288 advanced_ = [[UIPreferencesTable alloc] initWithFrame:pageBounds];
5290 [advanced_ setReusesTableCells:YES];
5291 [advanced_ setDataSource:self];
5292 [advanced_ reloadData];
5294 dimmed_ = [[UIView alloc] initWithFrame:pageBounds];
5295 CGColor dimmed(space_, 0, 0, 0, 0.5);
5296 [dimmed_ setBackgroundColor:[UIColor colorWithCGColor:dimmed]];
5298 table_ = [[PackageTable alloc]
5302 filter:@selector(isUnfilteredAndSearchedForBy:)
5306 [table_ setShouldHideHeaderInShortLists:NO];
5307 [transition_ transition:0 toView:table_];
5316 area.origin.x = /*cnfrect.origin.x + cnfrect.size.width + 4 +*/ 10;
5323 [self bounds].size.width - area.origin.x - 18;
5325 area.size.height = [UISearchField defaultHeight];
5327 field_ = [[UISearchField alloc] initWithFrame:area];
5329 UIFont *font = [UIFont systemFontOfSize:16];
5330 [field_ setFont:font];
5332 [field_ setPlaceholder:@"Package Names & Descriptions"];
5333 [field_ setDelegate:self];
5335 [field_ setPaddingTop:5];
5337 UITextInputTraits *traits = [field_ textInputTraits];
5338 [traits setAutocapitalizationType:0];
5339 [traits setAutocorrectionType:1];
5340 [traits setReturnKeyType:6];
5342 CGRect accrect = {{0, 6}, {6 + cnfrect.size.width + 6 + area.size.width + 6, area.size.height}};
5344 accessory_ = [[UIView alloc] initWithFrame:accrect];
5345 [accessory_ addSubview:field_];
5347 /*UIPushButton *configure = [[[UIPushButton alloc] initWithFrame:cnfrect] autorelease];
5348 [configure setShowPressFeedback:YES];
5349 [configure setImage:[UIImage applicationImageNamed:@"advanced.png"]];
5350 [configure addTarget:self action:@selector(configurePushed) forEvents:1];
5351 [accessory_ addSubview:configure];*/
5353 [self setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
5354 [table_ setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
5360 LKAnimation *animation = [LKTransition animation];
5361 [animation setType:@"oglFlip"];
5362 [animation setTimingFunction:[LKTimingFunction functionWithName:@"easeInEaseOut"]];
5363 [animation setFillMode:@"extended"];
5364 [animation setTransitionFlags:3];
5365 [animation setDuration:10];
5366 [animation setSpeed:0.35];
5367 [animation setSubtype:(flipped_ ? @"fromLeft" : @"fromRight")];
5368 [[transition_ _layer] addAnimation:animation forKey:0];
5369 [transition_ transition:0 toView:(flipped_ ? (UIView *) table_ : (UIView *) advanced_)];
5370 flipped_ = !flipped_;
5374 - (void) configurePushed {
5375 [field_ resignFirstResponder];
5379 - (void) resetViewAnimated:(BOOL)animated {
5382 [table_ resetViewAnimated:animated];
5385 - (void) reloadData {
5388 [table_ setObject:[field_ text]];
5389 [table_ reloadData];
5390 [table_ resetCursor];
5393 - (UIView *) accessoryView {
5397 - (NSString *) title {
5401 - (NSString *) backButtonTitle {
5405 - (void) setDelegate:(id)delegate {
5406 [table_ setDelegate:delegate];
5407 [super setDelegate:delegate];
5413 @implementation CYBook
5417 [indicator_ release];
5419 [progress_ release];
5424 - (NSString *) getTitleForPage:(RVPage *)page {
5425 return Simplify([super getTitleForPage:page]);
5433 [UIView beginAnimations:nil context:NULL];
5435 CGRect ovrframe = [overlay_ frame];
5436 ovrframe.origin.y = 0;
5437 [overlay_ setFrame:ovrframe];
5439 CGRect barframe = [navbar_ frame];
5440 barframe.origin.y += ovrframe.size.height;
5441 [navbar_ setFrame:barframe];
5443 CGRect trnframe = [transition_ frame];
5444 trnframe.origin.y += ovrframe.size.height;
5445 trnframe.size.height -= ovrframe.size.height;
5446 [transition_ setFrame:trnframe];
5448 [UIView endAnimations];
5450 [indicator_ startAnimation];
5451 [prompt_ setText:@"Updating Database"];
5452 [progress_ setProgress:0];
5455 last_ = [NSDate timeIntervalSinceReferenceDate];
5457 [overlay_ addSubview:cancel_];
5460 detachNewThreadSelector:@selector(_update)
5469 [indicator_ stopAnimation];
5471 [UIView beginAnimations:nil context:NULL];
5473 CGRect ovrframe = [overlay_ frame];
5474 ovrframe.origin.y = -ovrframe.size.height;
5475 [overlay_ setFrame:ovrframe];
5477 CGRect barframe = [navbar_ frame];
5478 barframe.origin.y -= ovrframe.size.height;
5479 [navbar_ setFrame:barframe];
5481 CGRect trnframe = [transition_ frame];
5482 trnframe.origin.y -= ovrframe.size.height;
5483 trnframe.size.height += ovrframe.size.height;
5484 [transition_ setFrame:trnframe];
5486 [UIView commitAnimations];
5488 [delegate_ performSelector:@selector(reloadData) withObject:nil afterDelay:0];
5491 - (id) initWithFrame:(CGRect)frame database:(Database *)database {
5492 if ((self = [super initWithFrame:frame]) != nil) {
5493 database_ = database;
5495 CGRect ovrrect = [navbar_ bounds];
5496 ovrrect.size.height = [UINavigationBar defaultSize].height;
5497 ovrrect.origin.y = -ovrrect.size.height;
5499 overlay_ = [[UINavigationBar alloc] initWithFrame:ovrrect];
5500 [self addSubview:overlay_];
5502 [overlay_ setBarStyle:1];
5503 int barstyle = [overlay_ _barStyle:NO];
5504 bool ugly = barstyle == 0;
5506 UIProgressIndicatorStyle style = ugly ?
5507 kUIProgressIndicatorStyleMediumBrown :
5508 kUIProgressIndicatorStyleMediumWhite;
5510 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:style];
5511 unsigned indoffset = (ovrrect.size.height - indsize.height) / 2;
5512 CGRect indrect = {{indoffset, indoffset}, indsize};
5514 indicator_ = [[UIProgressIndicator alloc] initWithFrame:indrect];
5515 [indicator_ setStyle:style];
5516 [overlay_ addSubview:indicator_];
5518 CGSize prmsize = {215, indsize.height + 4};
5521 indoffset * 2 + indsize.width,
5525 unsigned(ovrrect.size.height - prmsize.height) / 2
5528 UIFont *font = [UIFont systemFontOfSize:15];
5530 prompt_ = [[UITextLabel alloc] initWithFrame:prmrect];
5532 [prompt_ setColor:[UIColor colorWithCGColor:(ugly ? Blueish_ : Off_)]];
5533 [prompt_ setBackgroundColor:[UIColor clearColor]];
5534 [prompt_ setFont:font];
5536 [overlay_ addSubview:prompt_];
5538 CGSize prgsize = {75, 100};
5541 ovrrect.size.width - prgsize.width - 10,
5542 (ovrrect.size.height - prgsize.height) / 2
5545 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
5546 [progress_ setStyle:0];
5547 [overlay_ addSubview:progress_];
5549 cancel_ = [[UINavigationButton alloc] initWithTitle:@"Cancel" style:UINavigationButtonStyleHighlighted];
5550 [cancel_ addTarget:self action:@selector(_onCancel) forControlEvents:UIControlEventTouchUpInside];
5552 CGRect frame = [cancel_ frame];
5553 frame.size.width = 65;
5554 frame.origin.x = ovrrect.size.width - frame.size.width - 5;
5555 frame.origin.y = (ovrrect.size.height - frame.size.height) / 2;
5556 [cancel_ setFrame:frame];
5558 [cancel_ setBarStyle:barstyle];
5562 - (void) _onCancel {
5564 [cancel_ removeFromSuperview];
5568 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5571 status.setDelegate(self);
5573 [database_ updateWithStatus:status];
5576 performSelectorOnMainThread:@selector(_update_)
5584 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id {
5585 [prompt_ setText:[NSString stringWithFormat:@"Error: %@", error]];
5588 - (void) setProgressTitle:(NSString *)title {
5590 performSelectorOnMainThread:@selector(_setProgressTitle:)
5596 - (void) setProgressPercent:(float)percent {
5598 performSelectorOnMainThread:@selector(_setProgressPercent:)
5599 withObject:[NSNumber numberWithFloat:percent]
5604 - (void) startProgress {
5607 - (void) addProgressOutput:(NSString *)output {
5609 performSelectorOnMainThread:@selector(_addProgressOutput:)
5615 - (bool) isCancelling:(size_t)received {
5616 NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate];
5617 if (received_ != received) {
5618 received_ = received;
5620 } else if (now - last_ > 15)
5625 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
5629 - (void) _setProgressTitle:(NSString *)title {
5630 [prompt_ setText:title];
5633 - (void) _setProgressPercent:(NSNumber *)percent {
5634 [progress_ setProgress:[percent floatValue]];
5637 - (void) _addProgressOutput:(NSString *)output {
5642 @interface Cydia : UIApplication <
5643 ConfirmationViewDelegate,
5644 ProgressViewDelegate,
5653 UIToolbar *buttonbar_;
5655 ConfirmationView *confirm_;
5657 NSMutableArray *essential_;
5658 NSMutableArray *broken_;
5660 Database *database_;
5661 ProgressView *progress_;
5665 UIKeyboard *keyboard_;
5666 UIProgressHUD *hud_;
5668 InstallView *install_;
5669 ChangesView *changes_;
5670 ManageView *manage_;
5671 SearchView *search_;
5676 @implementation Cydia
5679 if ([broken_ count] != 0) {
5680 int count = [broken_ count];
5682 UIActionSheet *sheet = [[[UIActionSheet alloc]
5683 initWithTitle:[NSString stringWithFormat:@"%d Half-Installed Package%@", count, (count == 1 ? @"" : @"s")]
5684 buttons:[NSArray arrayWithObjects:
5686 @"Ignore (Temporary)",
5688 defaultButtonIndex:0
5693 [sheet setBodyText:@"When the shell scripts associated with packages fail, they are left in a bad state known as either half-configured or half-installed. These errors don't go away and instead continue to cause issues. These scripts can be deleted and the packages forcibly removed."];
5694 [sheet popupAlertAnimated:YES];
5695 } else if (!Ignored_ && [essential_ count] != 0) {
5696 int count = [essential_ count];
5698 UIActionSheet *sheet = [[[UIActionSheet alloc]
5699 initWithTitle:[NSString stringWithFormat:@"%d Essential Upgrade%@", count, (count == 1 ? @"" : @"s")]
5700 buttons:[NSArray arrayWithObjects:@"Upgrade Essential", @"Ignore (Temporary)", nil]
5701 defaultButtonIndex:0
5706 [sheet setBodyText:@"One or more essential packages are currently out of date. If these upgrades are not performed you are likely to encounter errors."];
5707 [sheet popupAlertAnimated:YES];
5711 - (void) _reloadData {
5712 /*UIProgressHUD *hud = [[UIProgressHUD alloc] initWithWindow:window_];
5713 [hud setText:@"Reloading Data"];
5714 [overlay_ addSubview:hud];
5717 [database_ reloadData];
5721 [essential_ removeAllObjects];
5722 [broken_ removeAllObjects];
5724 NSArray *packages = [database_ packages];
5725 for (int i(0), e([packages count]); i != e; ++i) {
5726 Package *package = [packages objectAtIndex:i];
5728 [broken_ addObject:package];
5729 if ([package upgradableAndEssential:NO]) {
5730 if ([package essential])
5731 [essential_ addObject:package];
5737 NSString *badge([[NSNumber numberWithInt:changes] stringValue]);
5738 [buttonbar_ setBadgeValue:badge forButton:3];
5739 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
5740 [buttonbar_ setBadgeAnimated:YES forButton:3];
5741 [self setApplicationBadge:badge];
5743 [buttonbar_ setBadgeValue:nil forButton:3];
5744 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
5745 [buttonbar_ setBadgeAnimated:NO forButton:3];
5746 [self removeApplicationBadge];
5751 if ([packages count] == 0);
5760 [hud removeFromSuperview];*/
5763 - (void) _saveConfig {
5765 _assert([Metadata_ writeToFile:@"/var/lib/cydia/metadata.plist" atomically:YES] == YES);
5770 - (void) updateData {
5773 /* XXX: this is just stupid */
5775 [install_ reloadData];
5777 [changes_ reloadData];
5779 [search_ reloadData];
5789 FILE *file = fopen("/etc/apt/sources.list.d/cydia.list", "w");
5790 _assert(file != NULL);
5792 NSArray *keys = [Sources_ allKeys];
5794 for (int i(0), e([keys count]); i != e; ++i) {
5795 NSString *key = [keys objectAtIndex:i];
5796 NSDictionary *source = [Sources_ objectForKey:key];
5798 fprintf(file, "%s %s %s\n",
5799 [[source objectForKey:@"Type"] UTF8String],
5800 [[source objectForKey:@"URI"] UTF8String],
5801 [[source objectForKey:@"Distribution"] UTF8String]
5810 detachNewThreadSelector:@selector(update_)
5813 title:@"Updating Sources"
5817 - (void) reloadData {
5818 @synchronized (self) {
5819 if (confirm_ == nil)
5825 pkgProblemResolver *resolver = [database_ resolver];
5827 resolver->InstallProtect();
5828 if (!resolver->Resolve(true))
5833 [database_ prepare];
5835 if ([database_ cache]->BrokenCount() == 0)
5836 confirm_ = [[ConfirmationView alloc] initWithView:underlay_ database:database_ delegate:self];
5838 NSMutableArray *broken = [NSMutableArray arrayWithCapacity:16];
5839 NSArray *packages = [database_ packages];
5841 for (size_t i(0); i != [packages count]; ++i) {
5842 Package *package = [packages objectAtIndex:i];
5843 if ([package broken])
5844 [broken addObject:[package name]];
5847 UIActionSheet *sheet = [[[UIActionSheet alloc]
5848 initWithTitle:[NSString stringWithFormat:@"%d Broken Packages", [database_ cache]->BrokenCount()]
5849 buttons:[NSArray arrayWithObjects:@"Okay", nil]
5850 defaultButtonIndex:0
5855 [sheet setBodyText:[NSString stringWithFormat:@"The following packages have unmet dependencies:\n\n%@", [broken componentsJoinedByString:@"\n"]]];
5856 [sheet popupAlertAnimated:YES];
5862 - (void) installPackage:(Package *)package {
5863 @synchronized (self) {
5870 - (void) removePackage:(Package *)package {
5871 @synchronized (self) {
5878 - (void) distUpgrade {
5879 @synchronized (self) {
5880 [database_ upgrade];
5886 @synchronized (self) {
5894 [overlay_ removeFromSuperview];
5898 detachNewThreadSelector:@selector(perform)
5905 - (void) bootstrap_ {
5907 [database_ upgrade];
5908 [database_ prepare];
5909 [database_ perform];
5912 - (void) bootstrap {
5914 detachNewThreadSelector:@selector(bootstrap_)
5917 title:@"Bootstrap Install"
5921 - (void) progressViewIsComplete:(ProgressView *)progress {
5922 @synchronized (self) {
5925 if (confirm_ != nil) {
5926 [underlay_ addSubview:overlay_];
5927 [confirm_ removeFromSuperview];
5934 - (void) setPage:(RVPage *)page {
5935 [page resetViewAnimated:NO];
5936 [page setDelegate:self];
5937 [book_ setPage:page];
5940 - (RVPage *) _pageForURL:(NSURL *)url withClass:(Class)_class {
5941 BrowserView *browser = [[[_class alloc] initWithBook:book_ database:database_] autorelease];
5942 [browser loadURL:url];
5946 - (void) _setHomePage {
5947 [self setPage:[self _pageForURL:[NSURL URLWithString:@"http://cydia.saurik.com/"] withClass:[HomeView class]]];
5950 - (void) buttonBarItemTapped:(id)sender {
5951 unsigned tag = [sender tag];
5953 [book_ resetViewAnimated:YES];
5955 } else if (tag_ == 2 && tag != 2)
5956 [install_ resetView];
5959 case 1: [self _setHomePage]; break;
5961 case 2: [self setPage:install_]; break;
5962 case 3: [self setPage:changes_]; break;
5963 case 4: [self setPage:manage_]; break;
5964 case 5: [self setPage:search_]; break;
5966 default: _assert(false);
5972 - (void) applicationWillSuspend {
5974 [super applicationWillSuspend];
5977 - (void) askForSettings {
5978 UIActionSheet *role = [[[UIActionSheet alloc]
5979 initWithTitle:@"Who Are You?"
5980 buttons:[NSArray arrayWithObjects:
5981 @"User (Graphical Only)",
5982 @"Hacker (+ Command Line)",
5983 @"Developer (No Filters)",
5985 defaultButtonIndex:-1
5990 [role setBodyText:@"Not all of the packages available via Cydia are designed to be used by all users. Please categorize yourself so that Cydia can apply helpful filters.\n\nThis choice can be changed from \"Settings\" under the \"Manage\" tab."];
5991 [role popupAlertAnimated:YES];
5996 [self setStatusBarShowsProgress:NO];
5999 [hud_ removeFromSuperview];
6003 pid_t pid = ExecFork();
6005 execlp("launchctl", "launchctl", "stop", "com.apple.SpringBoard", NULL);
6006 perror("launchctl stop");
6013 [self askForSettings];
6017 overlay_ = [[UIView alloc] initWithFrame:[underlay_ bounds]];
6019 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
6020 book_ = [[CYBook alloc] initWithFrame:CGRectMake(
6021 0, 0, screenrect.size.width, screenrect.size.height - 48
6022 ) database:database_];
6024 [book_ setDelegate:self];
6026 [overlay_ addSubview:book_];
6028 NSArray *buttonitems = [NSArray arrayWithObjects:
6029 [NSDictionary dictionaryWithObjectsAndKeys:
6030 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
6031 @"home-up.png", kUIButtonBarButtonInfo,
6032 @"home-dn.png", kUIButtonBarButtonSelectedInfo,
6033 [NSNumber numberWithInt:1], kUIButtonBarButtonTag,
6034 self, kUIButtonBarButtonTarget,
6035 @"Home", kUIButtonBarButtonTitle,
6036 @"0", kUIButtonBarButtonType,
6039 [NSDictionary dictionaryWithObjectsAndKeys:
6040 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
6041 @"install-up.png", kUIButtonBarButtonInfo,
6042 @"install-dn.png", kUIButtonBarButtonSelectedInfo,
6043 [NSNumber numberWithInt:2], kUIButtonBarButtonTag,
6044 self, kUIButtonBarButtonTarget,
6045 @"Sections", kUIButtonBarButtonTitle,
6046 @"0", kUIButtonBarButtonType,
6049 [NSDictionary dictionaryWithObjectsAndKeys:
6050 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
6051 @"changes-up.png", kUIButtonBarButtonInfo,
6052 @"changes-dn.png", kUIButtonBarButtonSelectedInfo,
6053 [NSNumber numberWithInt:3], kUIButtonBarButtonTag,
6054 self, kUIButtonBarButtonTarget,
6055 @"Changes", kUIButtonBarButtonTitle,
6056 @"0", kUIButtonBarButtonType,
6059 [NSDictionary dictionaryWithObjectsAndKeys:
6060 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
6061 @"manage-up.png", kUIButtonBarButtonInfo,
6062 @"manage-dn.png", kUIButtonBarButtonSelectedInfo,
6063 [NSNumber numberWithInt:4], kUIButtonBarButtonTag,
6064 self, kUIButtonBarButtonTarget,
6065 @"Manage", kUIButtonBarButtonTitle,
6066 @"0", kUIButtonBarButtonType,
6069 [NSDictionary dictionaryWithObjectsAndKeys:
6070 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
6071 @"search-up.png", kUIButtonBarButtonInfo,
6072 @"search-dn.png", kUIButtonBarButtonSelectedInfo,
6073 [NSNumber numberWithInt:5], kUIButtonBarButtonTag,
6074 self, kUIButtonBarButtonTarget,
6075 @"Search", kUIButtonBarButtonTitle,
6076 @"0", kUIButtonBarButtonType,
6080 buttonbar_ = [[UIToolbar alloc]
6082 withFrame:CGRectMake(
6083 0, screenrect.size.height - ButtonBarHeight_,
6084 screenrect.size.width, ButtonBarHeight_
6086 withItemList:buttonitems
6089 [buttonbar_ setDelegate:self];
6090 [buttonbar_ setBarStyle:1];
6091 [buttonbar_ setButtonBarTrackingMode:2];
6093 int buttons[5] = {1, 2, 3, 4, 5};
6094 [buttonbar_ registerButtonGroup:0 withButtons:buttons withCount:5];
6095 [buttonbar_ showButtonGroup:0 withDuration:0];
6097 for (int i = 0; i != 5; ++i)
6098 [[buttonbar_ viewWithTag:(i + 1)] setFrame:CGRectMake(
6099 i * 64 + 2, 1, 60, ButtonBarHeight_
6102 [buttonbar_ showSelectionForButton:1];
6103 [overlay_ addSubview:buttonbar_];
6105 [UIKeyboard initImplementationNow];
6106 CGSize keysize = [UIKeyboard defaultSize];
6107 CGRect keyrect = {{0, [overlay_ bounds].size.height}, keysize};
6108 keyboard_ = [[UIKeyboard alloc] initWithFrame:keyrect];
6109 [[UIKeyboardImpl sharedInstance] setSoundsEnabled:(Sounds_Keyboard_ ? YES : NO)];
6110 [overlay_ addSubview:keyboard_];
6112 install_ = [[InstallView alloc] initWithBook:book_ database:database_];
6113 changes_ = [[ChangesView alloc] initWithBook:book_ database:database_];
6114 search_ = [[SearchView alloc] initWithBook:book_ database:database_];
6116 manage_ = (ManageView *) [[self
6117 _pageForURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"manage" ofType:@"html"]]
6118 withClass:[ManageView class]
6122 [underlay_ addSubview:overlay_];
6129 [self _setHomePage];
6132 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
6133 NSString *context = [sheet context];
6134 if ([context isEqualToString:@"fixhalf"])
6137 @synchronized (self) {
6138 for (int i = 0, e = [broken_ count]; i != e; ++i) {
6139 Package *broken = [broken_ objectAtIndex:i];
6142 NSString *id = [broken id];
6143 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.prerm", id] UTF8String]);
6144 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.postrm", id] UTF8String]);
6145 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.preinst", id] UTF8String]);
6146 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.postinst", id] UTF8String]);
6155 [broken_ removeAllObjects];
6162 else if ([context isEqualToString:@"role"]) {
6164 case 1: Role_ = @"User"; break;
6165 case 2: Role_ = @"Hacker"; break;
6166 case 3: Role_ = @"Developer"; break;
6173 bool reset = Settings_ != nil;
6175 Settings_ = [NSMutableDictionary dictionaryWithObjectsAndKeys:
6179 [Metadata_ setObject:Settings_ forKey:@"Settings"];
6187 } else if ([context isEqualToString:@"upgrade"])
6190 @synchronized (self) {
6191 for (int i = 0, e = [essential_ count]; i != e; ++i) {
6192 Package *essential = [essential_ objectAtIndex:i];
6193 [essential install];
6212 - (void) reorganize {
6213 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
6214 system("/usr/libexec/cydia/free.sh");
6215 [self performSelectorOnMainThread:@selector(finish) withObject:nil waitUntilDone:NO];
6219 - (void) applicationSuspend:(__GSEvent *)event {
6220 if (hud_ == nil && ![progress_ isRunning])
6221 [super applicationSuspend:event];
6224 - (void) _animateSuspension:(BOOL)arg0 duration:(double)arg1 startTime:(double)arg2 scale:(float)arg3 {
6226 [super _animateSuspension:arg0 duration:arg1 startTime:arg2 scale:arg3];
6229 - (void) _setSuspended:(BOOL)value {
6231 [super _setSuspended:value];
6234 - (UIProgressHUD *) addProgressHUD {
6235 UIProgressHUD *hud = [[UIProgressHUD alloc] initWithWindow:window_];
6237 [underlay_ addSubview:hud];
6241 - (void) applicationDidFinishLaunching:(id)unused {
6242 Font12_ = [[UIFont systemFontOfSize:12] retain];
6243 Font12Bold_ = [[UIFont boldSystemFontOfSize:12] retain];
6244 Font14_ = [[UIFont systemFontOfSize:14] retain];
6245 Font18Bold_ = [[UIFont boldSystemFontOfSize:18] retain];
6246 Font22Bold_ = [[UIFont boldSystemFontOfSize:22] retain];
6248 _assert(pkgInitConfig(*_config));
6249 _assert(pkgInitSystem(*_config, _system));
6254 essential_ = [[NSMutableArray alloc] initWithCapacity:4];
6255 broken_ = [[NSMutableArray alloc] initWithCapacity:4];
6257 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
6258 window_ = [[UIWindow alloc] initWithContentRect:screenrect];
6260 [window_ orderFront:self];
6261 [window_ makeKey:self];
6262 [window_ _setHidden:NO];
6264 database_ = [[Database alloc] init];
6265 progress_ = [[ProgressView alloc] initWithFrame:[window_ bounds] database:database_ delegate:self];
6266 [database_ setDelegate:progress_];
6267 [window_ setContentView:progress_];
6269 underlay_ = [[UIView alloc] initWithFrame:[progress_ bounds]];
6270 [progress_ setContentView:underlay_];
6272 [progress_ resetView];
6275 readlink("/Applications", NULL, 0) == -1 && errno == EINVAL ||
6276 readlink("/Library/Ringtones", NULL, 0) == -1 && errno == EINVAL ||
6277 readlink("/Library/Wallpaper", NULL, 0) == -1 && errno == EINVAL ||
6278 readlink("/usr/include", NULL, 0) == -1 && errno == EINVAL ||
6279 readlink("/usr/libexec", NULL, 0) == -1 && errno == EINVAL ||
6280 readlink("/usr/share", NULL, 0) == -1 && errno == EINVAL /*||
6281 readlink("/var/lib", NULL, 0) == -1 && errno == EINVAL*/
6283 [self setIdleTimerDisabled:YES];
6285 hud_ = [self addProgressHUD];
6286 [hud_ setText:@"Reorganizing\n\nWill Automatically\nRestart When Done"];
6288 [self setStatusBarShowsProgress:YES];
6291 detachNewThreadSelector:@selector(reorganize)
6299 - (void) showKeyboard:(BOOL)show {
6300 CGSize keysize = [UIKeyboard defaultSize];
6301 CGRect keydown = {{0, [overlay_ bounds].size.height}, keysize};
6302 CGRect keyup = keydown;
6303 keyup.origin.y -= keysize.height;
6305 UIFrameAnimation *animation = [[[UIFrameAnimation alloc] initWithTarget:keyboard_] autorelease];
6306 [animation setSignificantRectFields:2];
6309 [animation setStartFrame:keydown];
6310 [animation setEndFrame:keyup];
6311 [keyboard_ activate];
6313 [animation setStartFrame:keyup];
6314 [animation setEndFrame:keydown];
6315 [keyboard_ deactivate];
6318 [[UIAnimator sharedAnimator]
6319 addAnimations:[NSArray arrayWithObjects:animation, nil]
6320 withDuration:KeyboardTime_
6325 - (void) slideUp:(UIActionSheet *)alert {
6327 [alert presentSheetFromButtonBar:buttonbar_];
6329 [alert presentSheetInView:overlay_];
6334 void AddPreferences(NSString *plist) {
6335 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
6337 NSMutableDictionary *settings = [[[NSMutableDictionary alloc] initWithContentsOfFile:plist] autorelease];
6338 _assert(settings != NULL);
6339 NSMutableArray *items = [settings objectForKey:@"items"];
6343 for (size_t i(0); i != [items count]; ++i) {
6344 NSMutableDictionary *item([items objectAtIndex:i]);
6345 NSString *label = [item objectForKey:@"label"];
6346 if (label != nil && [label isEqualToString:@"Cydia"]) {
6353 for (size_t i(0); i != [items count]; ++i) {
6354 NSDictionary *item([items objectAtIndex:i]);
6355 NSString *label = [item objectForKey:@"label"];
6356 if (label != nil && [label isEqualToString:@"General"]) {
6357 [items insertObject:[NSDictionary dictionaryWithObjectsAndKeys:
6358 @"CydiaSettings", @"bundle",
6359 @"PSLinkCell", @"cell",
6360 [NSNumber numberWithBool:YES], @"hasIcon",
6361 [NSNumber numberWithBool:YES], @"isController",
6363 nil] atIndex:(i + 1)];
6369 _assert([settings writeToFile:plist atomically:YES] == YES);
6376 id Alloc_(id self, SEL selector) {
6377 id object = alloc_(self, selector);
6378 fprintf(stderr, "[%s]A-%p\n", self->isa->name, object);
6383 id Dealloc_(id self, SEL selector) {
6384 id object = dealloc_(self, selector);
6385 fprintf(stderr, "[%s]D-%p\n", self->isa->name, object);
6389 int main(int argc, char *argv[]) {
6390 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
6392 bootstrap_ = argc > 1 && strcmp(argv[1], "--bootstrap") == 0;
6394 App_ = [[NSBundle mainBundle] bundlePath];
6395 Home_ = NSHomeDirectory();
6396 Locale_ = CFLocaleCopyCurrent();
6399 NSString *plist = [Home_ stringByAppendingString:@"/Library/Preferences/com.apple.preferences.sounds.plist"];
6400 if (NSDictionary *sounds = [NSDictionary dictionaryWithContentsOfFile:plist])
6401 if (NSNumber *keyboard = [sounds objectForKey:@"keyboard"])
6402 Sounds_Keyboard_ = [keyboard boolValue];
6408 if (unlink("/var/cache/apt/pkgcache.bin") == -1)
6409 _assert(errno == ENOENT);
6410 if (unlink("/var/cache/apt/srcpkgcache.bin") == -1)
6411 _assert(errno == ENOENT);
6413 /*Method alloc = class_getClassMethod([NSObject class], @selector(alloc));
6414 alloc_ = alloc->method_imp;
6415 alloc->method_imp = (IMP) &Alloc_;*/
6417 /*Method dealloc = class_getClassMethod([NSObject class], @selector(dealloc));
6418 dealloc_ = dealloc->method_imp;
6419 dealloc->method_imp = (IMP) &Dealloc_;*/
6421 if (NSDictionary *sysver = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]) {
6422 if (NSString *prover = [sysver valueForKey:@"ProductVersion"]) {
6423 Firmware_ = strdup([prover UTF8String]);
6424 NSArray *versions = [prover componentsSeparatedByString:@"."];
6425 int count = [versions count];
6426 Major_ = count > 0 ? [[versions objectAtIndex:0] intValue] : 0;
6427 Minor_ = count > 1 ? [[versions objectAtIndex:1] intValue] : 0;
6428 BugFix_ = count > 2 ? [[versions objectAtIndex:2] intValue] : 0;
6433 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
6434 char *machine = new char[size];
6435 sysctlbyname("hw.machine", machine, &size, NULL, 0);
6438 UniqueID_ = [[UIDevice currentDevice] uniqueIdentifier];
6440 /*AddPreferences(@"/Applications/Preferences.app/Settings-iPhone.plist");
6441 AddPreferences(@"/Applications/Preferences.app/Settings-iPod.plist");*/
6443 if ((Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"]) == NULL)
6444 Metadata_ = [[NSMutableDictionary alloc] initWithCapacity:2];
6446 Settings_ = [Metadata_ objectForKey:@"Settings"];
6448 Packages_ = [Metadata_ objectForKey:@"Packages"];
6449 Sections_ = [Metadata_ objectForKey:@"Sections"];
6450 Sources_ = [Metadata_ objectForKey:@"Sources"];
6453 if (Settings_ != nil)
6454 Role_ = [Settings_ objectForKey:@"Role"];
6456 if (Packages_ == nil) {
6457 Packages_ = [[[NSMutableDictionary alloc] initWithCapacity:128] autorelease];
6458 [Metadata_ setObject:Packages_ forKey:@"Packages"];
6461 if (Sections_ == nil) {
6462 Sections_ = [[[NSMutableDictionary alloc] initWithCapacity:32] autorelease];
6463 [Metadata_ setObject:Sections_ forKey:@"Sections"];
6466 if (Sources_ == nil) {
6467 Sources_ = [[[NSMutableDictionary alloc] initWithCapacity:0] autorelease];
6468 [Metadata_ setObject:Sources_ forKey:@"Sources"];
6471 Documents_ = [[[NSMutableArray alloc] initWithCapacity:4] autorelease];
6473 if (access("/Library/MobileSubstrate/MobileSubstrate.dylib", F_OK) == 0)
6474 dlopen("/Library/MobileSubstrate/MobileSubstrate.dylib", RTLD_LAZY | RTLD_GLOBAL);
6476 if (access("/User", F_OK) != 0)
6477 system("/usr/libexec/cydia/firmware.sh");
6479 _assert([[NSFileManager defaultManager]
6480 createDirectoryAtPath:@"/var/cache/apt/archives/partial"
6481 withIntermediateDirectories:YES
6486 space_ = CGColorSpaceCreateDeviceRGB();
6488 Blue_.Set(space_, 0.2, 0.2, 1.0, 1.0);
6489 Blueish_.Set(space_, 0x19/255.f, 0x32/255.f, 0x50/255.f, 1.0);
6490 Black_.Set(space_, 0.0, 0.0, 0.0, 1.0);
6491 Off_.Set(space_, 0.9, 0.9, 0.9, 1.0);
6492 Red_.Set(space_, 1.0, 0.0, 0.0, 1.0);
6493 White_.Set(space_, 1.0, 1.0, 1.0, 1.0);
6494 Gray_.Set(space_, 0.4, 0.4, 0.4, 1.0);
6496 Finishes_ = [NSArray arrayWithObjects:@"return", @"reopen", @"restart", @"reload", @"reboot", nil];
6498 SectionMap_ = [[[NSDictionary alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Sections" ofType:@"plist"]] autorelease];
6500 UIApplicationUseLegacyEvents(YES);
6501 UIKeyboardDisableAutomaticAppearance();
6503 int value = UIApplicationMain(argc, argv, @"Cydia", @"Cydia");
6505 CGColorSpaceRelease(space_);