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/sysctl.h>
93 #include <mach-o/nlist.h>
103 #import "BrowserView.h"
104 #import "ResetView.h"
105 #import "UICaboodle.h"
108 static const NSStringCompareOptions CompareOptions_ = NSCaseInsensitiveSearch | NSNumericSearch | NSDiacriticInsensitiveSearch | NSWidthInsensitiveSearch | NSForcedOrderingSearch;
110 @interface WebView (Cydia)
111 - (void) _setLayoutInterval:(float)interval;
114 /* iPhoneOS 2.0 Compatibility {{{ */
116 @interface UICGColor : NSObject {
119 - (id) initWithCGColor:(CGColorRef)color;
122 @interface NSObject (iPhoneOS)
123 - (CGColorRef) cgColor;
124 - (CGColorRef) CGColor;
128 @implementation NSObject (iPhoneOS)
130 - (CGColorRef) cgColor {
131 return [self CGColor];
134 - (CGColorRef) CGColor {
135 return (CGColorRef) self;
139 [[[[objc_getClass("UICGColor") alloc] initWithCGColor:[self CGColor]] autorelease] set];
144 @interface UITextView (iPhoneOS)
145 - (void) setTextSize:(float)size;
148 @implementation UITextView (iPhoneOS)
150 - (void) setTextSize:(float)size {
151 [self setFont:[[self font] fontWithSize:size]];
158 @interface UIApplication (IdleTimer)
159 - (void) setIdleTimerDisabled:(char)arg0;
162 extern "C" int UIApplicationMain(int argc, char *argv[], NSString *principalClassName, NSString *delegateClassName);
164 extern NSString *kUIButtonBarButtonAction;
165 extern NSString *kUIButtonBarButtonInfo;
166 extern NSString *kUIButtonBarButtonInfoOffset;
167 extern NSString *kUIButtonBarButtonSelectedInfo;
168 extern NSString *kUIButtonBarButtonStyle;
169 extern NSString *kUIButtonBarButtonTag;
170 extern NSString *kUIButtonBarButtonTarget;
171 extern NSString *kUIButtonBarButtonTitle;
172 extern NSString *kUIButtonBarButtonTitleVerticalHeight;
173 extern NSString *kUIButtonBarButtonTitleWidth;
174 extern NSString *kUIButtonBarButtonType;
177 kUIProgressIndicatorStyleLargeWhite = 0,
178 kUIProgressIndicatorStyleMediumWhite = 1,
179 kUIProgressIndicatorStyleMediumBrown = 2,
180 kUIProgressIndicatorStyleSmallWhite = 3,
181 kUIProgressIndicatorStyleSmallBlack = 4,
182 kUIProgressIndicatorStyleTinyWhite = 5,
183 } UIProgressIndicatorStyle;
186 kUIControlEventMouseDown = 1 << 0,
187 kUIControlEventMouseMovedInside = 1 << 2, // mouse moved inside control target
188 kUIControlEventMouseMovedOutside = 1 << 3, // mouse moved outside control target
189 kUIControlEventMouseUpInside = 1 << 6, // mouse up inside control target
190 kUIControlEventMouseUpOutside = 1 << 7, // mouse up outside control target
191 kUIControlAllEvents = (kUIControlEventMouseDown | kUIControlEventMouseMovedInside | kUIControlEventMouseMovedOutside | kUIControlEventMouseUpInside | kUIControlEventMouseUpOutside)
192 } UIControlEventMasks;
194 @interface NSString (UIKit)
195 - (NSString *) stringByAddingPercentEscapes;
196 - (NSString *) stringByReplacingCharacter:(unsigned short)arg0 withCharacter:(unsigned short)arg1;
199 @interface NSString (Cydia)
200 + (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length;
201 - (NSComparisonResult) compareByPath:(NSString *)other;
204 @implementation NSString (Cydia)
206 + (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length {
207 char data[length + 1];
208 memcpy(data, bytes, length);
210 return [NSString stringWithUTF8String:data];
213 - (NSComparisonResult) compareByPath:(NSString *)other {
214 NSString *prefix = [self commonPrefixWithString:other options:0];
215 size_t length = [prefix length];
217 NSRange lrange = NSMakeRange(length, [self length] - length);
218 NSRange rrange = NSMakeRange(length, [other length] - length);
220 lrange = [self rangeOfString:@"/" options:0 range:lrange];
221 rrange = [other rangeOfString:@"/" options:0 range:rrange];
223 NSComparisonResult value;
225 if (lrange.location == NSNotFound && rrange.location == NSNotFound)
226 value = NSOrderedSame;
227 else if (lrange.location == NSNotFound)
228 value = NSOrderedAscending;
229 else if (rrange.location == NSNotFound)
230 value = NSOrderedDescending;
232 value = NSOrderedSame;
234 NSString *lpath = lrange.location == NSNotFound ? [self substringFromIndex:length] :
235 [self substringWithRange:NSMakeRange(length, lrange.location - length)];
236 NSString *rpath = rrange.location == NSNotFound ? [other substringFromIndex:length] :
237 [other substringWithRange:NSMakeRange(length, rrange.location - length)];
239 NSComparisonResult result = [lpath compare:rpath];
240 return result == NSOrderedSame ? value : result;
245 /* Perl-Compatible RegEx {{{ */
255 Pcre(const char *regex) :
260 code_ = pcre_compile(regex, 0, &error, &offset, NULL);
263 fprintf(stderr, "%d:%s\n", offset, error);
267 pcre_fullinfo(code_, study_, PCRE_INFO_CAPTURECOUNT, &capture_);
268 matches_ = new int[(capture_ + 1) * 3];
276 NSString *operator [](size_t match) {
277 return [NSString stringWithUTF8Bytes:(data_ + matches_[match * 2]) length:(matches_[match * 2 + 1] - matches_[match * 2])];
280 bool operator ()(NSString *data) {
281 // XXX: length is for characters, not for bytes
282 return operator ()([data UTF8String], [data length]);
285 bool operator ()(const char *data, size_t size) {
287 return pcre_exec(code_, study_, data, size, 0, 0, matches_, (capture_ + 1) * 3) >= 0;
291 /* Mime Addresses {{{ */
292 @interface Address : NSObject {
298 - (NSString *) address;
300 + (Address *) addressWithString:(NSString *)string;
301 - (Address *) initWithString:(NSString *)string;
304 @implementation Address
313 - (NSString *) name {
317 - (NSString *) address {
321 + (Address *) addressWithString:(NSString *)string {
322 return [[[Address alloc] initWithString:string] autorelease];
325 + (NSArray *) _attributeKeys {
326 return [NSArray arrayWithObjects:@"address", @"name", nil];
329 - (NSArray *) attributeKeys {
330 return [[self class] _attributeKeys];
333 + (BOOL) isKeyExcludedFromWebScript:(const char *)name {
334 return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name];
337 - (Address *) initWithString:(NSString *)string {
338 if ((self = [super init]) != nil) {
339 const char *data = [string UTF8String];
340 size_t size = [string length];
342 static Pcre address_r("^\"?(.*)\"? <([^>]*)>$");
344 if (address_r(data, size)) {
345 name_ = [address_r[1] retain];
346 address_ = [address_r[2] retain];
348 name_ = [[NSString alloc]
351 encoding:kCFStringEncodingUTF8
361 /* CoreGraphics Primitives {{{ */
372 CGColor(CGColorSpaceRef space, float red, float green, float blue, float alpha) :
375 Set(space, red, green, blue, alpha);
380 CGColorRelease(color_);
387 void Set(CGColorSpaceRef space, float red, float green, float blue, float alpha) {
389 float color[] = {red, green, blue, alpha};
390 color_ = CGColorCreate(space, color);
393 operator CGColorRef() {
409 extern "C" void UISetColor(CGColorRef color);
411 /* Random Global Variables {{{ */
412 static const int PulseInterval_ = 50000;
413 static const int ButtonBarHeight_ = 48;
414 static const float KeyboardTime_ = 0.3f;
415 static const char * const SpringBoard_ = "/System/Library/LaunchDaemons/com.apple.SpringBoard.plist";
417 static CGColor Blue_;
418 static CGColor Blueish_;
419 static CGColor Black_;
422 static CGColor White_;
423 static CGColor Gray_;
425 static NSString *App_;
426 static NSString *Home_;
427 static BOOL Sounds_Keyboard_;
429 static BOOL Advanced_;
431 static BOOL Ignored_;
433 static UIFont *Font12_;
434 static UIFont *Font12Bold_;
435 static UIFont *Font14_;
436 static UIFont *Font18Bold_;
437 static UIFont *Font22Bold_;
439 const char *Firmware_ = NULL;
440 const char *Machine_ = NULL;
441 const char *SerialNumber_ = NULL;
448 CGColorSpaceRef space_;
450 #define FW_LEAST(major, minor, bugfix) \
451 (major < Major_ || major == Major_ && \
452 (minor < Minor_ || minor == Minor_ && \
458 static NSDictionary *SectionMap_;
459 static NSMutableDictionary *Metadata_;
460 static _transient NSMutableDictionary *Settings_;
461 static _transient NSString *Role_;
462 static _transient NSMutableDictionary *Packages_;
463 static _transient NSMutableDictionary *Sections_;
464 static _transient NSMutableDictionary *Sources_;
465 static _transient NSMutableArray *Documents_;
466 static bool Changed_;
469 NSString *GetLastUpdate() {
470 NSDate *update = [Metadata_ objectForKey:@"LastUpdate"];
473 return @"Never or Unknown";
475 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, Locale_, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
476 CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) update);
478 CFRelease(formatter);
480 return [(NSString *) formatted autorelease];
483 /* Display Helpers {{{ */
484 inline float Interpolate(float begin, float end, float fraction) {
485 return (end - begin) * fraction + begin;
488 NSString *SizeString(double size) {
490 while (size > 1024) {
495 static const char *powers_[] = {"B", "kB", "MB", "GB"};
497 return [NSString stringWithFormat:@"%.1f%s", size, powers_[power]];
500 NSString *StripVersion(NSString *version) {
501 NSRange colon = [version rangeOfString:@":"];
502 if (colon.location != NSNotFound)
503 version = [version substringFromIndex:(colon.location + 1)];
507 static const float TextViewOffset_ = 22;
509 UITextView *GetTextView(NSString *value, float left, bool html) {
510 UITextView *text([[[UITextView alloc] initWithFrame:CGRectMake(left, 3, 310 - left, 1000)] autorelease]);
511 [text setEditable:NO];
512 [text setTextSize:16];
514 [text setHTML:value];
516 [text setText:value];
517 [text setEnabled:NO];
519 [text setBackgroundColor:[UIColor clearColor]];
521 CGRect frame = [text frame];
522 [text setFrame:frame];
523 CGRect rect = [text visibleTextRect];
524 frame.size.height = rect.size.height;
525 [text setFrame:frame];
530 NSString *Simplify(NSString *title) {
531 const char *data = [title UTF8String];
532 size_t size = [title length];
534 static Pcre square_r("^\\[(.*)\\]$");
535 if (square_r(data, size))
536 return Simplify(square_r[1]);
538 static Pcre paren_r("^\\((.*)\\)$");
539 if (paren_r(data, size))
540 return Simplify(paren_r[1]);
542 static Pcre title_r("^(.*?) \\(.*\\)$");
543 if (title_r(data, size))
544 return Simplify(title_r[1]);
550 bool isSectionVisible(NSString *section) {
551 NSDictionary *metadata = [Sections_ objectForKey:section];
552 NSNumber *hidden = metadata == nil ? nil : [metadata objectForKey:@"Hidden"];
553 return hidden == nil || ![hidden boolValue];
556 /* Delegate Prototypes {{{ */
560 @interface NSObject (ProgressDelegate)
563 @implementation NSObject(ProgressDelegate)
565 - (void) _setProgressError:(NSArray *)args {
566 [self performSelector:@selector(setProgressError:forPackage:)
567 withObject:[args objectAtIndex:0]
568 withObject:([args count] == 1 ? nil : [args objectAtIndex:1])
574 @protocol ProgressDelegate
575 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id;
576 - (void) setProgressTitle:(NSString *)title;
577 - (void) setProgressPercent:(float)percent;
578 - (void) startProgress;
579 - (void) addProgressOutput:(NSString *)output;
580 - (bool) isCancelling:(size_t)received;
583 @protocol ConfigurationDelegate
584 - (void) repairWithSelector:(SEL)selector;
585 - (void) setConfigurationData:(NSString *)data;
588 @protocol CydiaDelegate
589 - (void) installPackage:(Package *)package;
590 - (void) removePackage:(Package *)package;
591 - (void) slideUp:(UIActionSheet *)alert;
592 - (void) distUpgrade;
595 - (void) askForSettings;
596 - (UIProgressHUD *) addProgressHUD;
600 /* Status Delegation {{{ */
602 public pkgAcquireStatus
605 _transient NSObject<ProgressDelegate> *delegate_;
613 void setDelegate(id delegate) {
614 delegate_ = delegate;
617 virtual bool MediaChange(std::string media, std::string drive) {
621 virtual void IMSHit(pkgAcquire::ItemDesc &item) {
624 virtual void Fetch(pkgAcquire::ItemDesc &item) {
625 [delegate_ setProgressTitle:[NSString stringWithUTF8String:("Downloading " + item.ShortDesc).c_str()]];
628 virtual void Done(pkgAcquire::ItemDesc &item) {
631 virtual void Fail(pkgAcquire::ItemDesc &item) {
633 item.Owner->Status == pkgAcquire::Item::StatIdle ||
634 item.Owner->Status == pkgAcquire::Item::StatDone
638 [delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
639 withObject:[NSArray arrayWithObjects:[NSString stringWithUTF8String:item.Owner->ErrorText.c_str()], nil]
644 virtual bool Pulse(pkgAcquire *Owner) {
645 bool value = pkgAcquireStatus::Pulse(Owner);
648 double(CurrentBytes + CurrentItems) /
649 double(TotalBytes + TotalItems)
652 [delegate_ setProgressPercent:percent];
653 return [delegate_ isCancelling:CurrentBytes] ? false : value;
656 virtual void Start() {
657 [delegate_ startProgress];
660 virtual void Stop() {
664 /* Progress Delegation {{{ */
669 _transient id<ProgressDelegate> delegate_;
672 virtual void Update() {
673 [delegate_ setProgressTitle:[NSString stringWithUTF8String:Op.c_str()]];
674 [delegate_ setProgressPercent:(Percent / 100)];
683 void setDelegate(id delegate) {
684 delegate_ = delegate;
687 virtual void Done() {
688 [delegate_ setProgressPercent:1];
693 /* Database Interface {{{ */
694 @interface Database : NSObject {
696 pkgDepCache::Policy *policy_;
697 pkgRecords *records_;
698 pkgProblemResolver *resolver_;
699 pkgAcquire *fetcher_;
701 SPtr<pkgPackageManager> manager_;
702 pkgSourceList *list_;
704 NSMutableDictionary *sources_;
705 NSMutableArray *packages_;
707 _transient NSObject<ConfigurationDelegate, ProgressDelegate> *delegate_;
716 - (void) _readCydia:(NSNumber *)fd;
717 - (void) _readStatus:(NSNumber *)fd;
718 - (void) _readOutput:(NSNumber *)fd;
722 - (Package *) packageWithName:(NSString *)name;
725 - (pkgCacheFile &) cache;
726 - (pkgDepCache::Policy *) policy;
727 - (pkgRecords *) records;
728 - (pkgProblemResolver *) resolver;
729 - (pkgAcquire &) fetcher;
730 - (NSArray *) packages;
731 - (NSArray *) sources;
740 - (void) updateWithStatus:(Status &)status;
742 - (void) setDelegate:(id)delegate;
743 - (Source *) getSource:(const pkgCache::PkgFileIterator &)file;
747 /* Source Class {{{ */
748 @interface Source : NSObject {
749 NSString *description_;
754 NSString *distribution_;
758 NSString *defaultIcon_;
760 NSDictionary *record_;
764 - (Source *) initWithMetaIndex:(metaIndex *)index;
766 - (NSComparisonResult) compareByNameAndType:(Source *)source;
768 - (NSDictionary *) record;
772 - (NSString *) distribution;
778 - (NSString *) description;
779 - (NSString *) label;
780 - (NSString *) origin;
781 - (NSString *) version;
783 - (NSString *) defaultIcon;
787 @implementation Source
791 [distribution_ release];
794 if (description_ != nil)
795 [description_ release];
802 if (defaultIcon_ != nil)
803 [defaultIcon_ release];
810 + (NSArray *) _attributeKeys {
811 return [NSArray arrayWithObjects:@"description", @"distribution", @"host", @"key", @"label", @"name", @"origin", @"trusted", @"type", @"uri", @"version", nil];
814 - (NSArray *) attributeKeys {
815 return [[self class] _attributeKeys];
818 + (BOOL) isKeyExcludedFromWebScript:(const char *)name {
819 return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name];
822 - (Source *) initWithMetaIndex:(metaIndex *)index {
823 if ((self = [super init]) != nil) {
824 trusted_ = index->IsTrusted();
826 uri_ = [[NSString stringWithUTF8String:index->GetURI().c_str()] retain];
827 distribution_ = [[NSString stringWithUTF8String:index->GetDist().c_str()] retain];
828 type_ = [[NSString stringWithUTF8String:index->GetType()] retain];
830 debReleaseIndex *dindex(dynamic_cast<debReleaseIndex *>(index));
831 if (dindex != NULL) {
832 std::ifstream release(dindex->MetaIndexFile("Release").c_str());
834 while (std::getline(release, line)) {
835 std::string::size_type colon(line.find(':'));
836 if (colon == std::string::npos)
839 std::string name(line.substr(0, colon));
840 std::string value(line.substr(colon + 1));
841 while (!value.empty() && value[0] == ' ')
842 value = value.substr(1);
844 if (name == "Default-Icon")
845 defaultIcon_ = [[NSString stringWithUTF8String:value.c_str()] retain];
846 else if (name == "Description")
847 description_ = [[NSString stringWithUTF8String:value.c_str()] retain];
848 else if (name == "Label")
849 label_ = [[NSString stringWithUTF8String:value.c_str()] retain];
850 else if (name == "Origin")
851 origin_ = [[NSString stringWithUTF8String:value.c_str()] retain];
852 else if (name == "Version")
853 version_ = [[NSString stringWithUTF8String:value.c_str()] retain];
857 record_ = [Sources_ objectForKey:[self key]];
859 record_ = [record_ retain];
863 - (NSComparisonResult) compareByNameAndType:(Source *)source {
864 NSDictionary *lhr = [self record];
865 NSDictionary *rhr = [source record];
868 return lhr == nil ? NSOrderedDescending : NSOrderedAscending;
870 NSString *lhs = [self name];
871 NSString *rhs = [source name];
873 if ([lhs length] != 0 && [rhs length] != 0) {
874 unichar lhc = [lhs characterAtIndex:0];
875 unichar rhc = [rhs characterAtIndex:0];
877 if (isalpha(lhc) && !isalpha(rhc))
878 return NSOrderedAscending;
879 else if (!isalpha(lhc) && isalpha(rhc))
880 return NSOrderedDescending;
883 return [lhs compare:rhs options:CompareOptions_];
886 - (NSDictionary *) record {
898 - (NSString *) distribution {
899 return distribution_;
902 - (NSString *) type {
907 return [NSString stringWithFormat:@"%@:%@:%@", type_, uri_, distribution_];
910 - (NSString *) host {
911 return [[[NSURL URLWithString:[self uri]] host] lowercaseString];
914 - (NSString *) name {
915 return origin_ == nil ? [self host] : origin_;
918 - (NSString *) description {
922 - (NSString *) label {
923 return label_ == nil ? [self host] : label_;
926 - (NSString *) origin {
930 - (NSString *) version {
934 - (NSString *) defaultIcon {
940 /* Relationship Class {{{ */
941 @interface Relationship : NSObject {
952 @implementation Relationship
960 - (NSString *) type {
968 - (NSString *) name {
975 /* Package Class {{{ */
976 NSString *Scour(const char *field, const char *begin, const char *end) {
977 size_t i(0), l(strlen(field));
980 const char *name = begin + i;
981 const char *colon = name + l;
982 const char *value = colon + 1;
987 memcmp(name, field, l) == 0
989 while (value != end && value[0] == ' ')
991 const char *line = std::find(value, end, '\n');
992 while (line != value && line[-1] == ' ')
995 return [NSString stringWithUTF8Bytes:value length:(line - value)];
997 begin = std::find(begin, end, '\n');
1005 @interface Package : NSObject {
1006 pkgCache::PkgIterator iterator_;
1007 _transient Database *database_;
1008 pkgCache::VerIterator version_;
1009 pkgCache::VerFileIterator file_;
1015 NSString *installed_;
1021 NSString *depiction_;
1022 NSString *homepage_;
1028 NSArray *relationships_;
1031 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
1032 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
1034 - (pkgCache::PkgIterator) iterator;
1036 - (NSString *) section;
1037 - (Address *) maintainer;
1039 - (NSString *) description;
1040 - (NSString *) index;
1044 - (NSString *) latest;
1045 - (NSString *) installed;
1048 - (BOOL) upgradableAndEssential:(BOOL)essential;
1051 - (BOOL) unfiltered;
1055 - (BOOL) halfConfigured;
1056 - (BOOL) halfInstalled;
1058 - (NSString *) mode;
1061 - (NSString *) name;
1062 - (NSString *) tagline;
1063 - (NSString *) icon;
1064 - (NSString *) homepage;
1065 - (NSString *) depiction;
1066 - (Address *) author;
1068 - (NSArray *) relationships;
1070 - (Source *) source;
1071 - (NSString *) role;
1073 - (BOOL) matches:(NSString *)text;
1075 - (bool) hasSupportingRole;
1076 - (BOOL) hasTag:(NSString *)tag;
1078 - (NSComparisonResult) compareByName:(Package *)package;
1079 - (NSComparisonResult) compareBySection:(Package *)package;
1080 - (NSComparisonResult) compareBySectionAndName:(Package *)package;
1081 - (NSComparisonResult) compareForChanges:(Package *)package;
1086 - (NSNumber *) isUnfilteredAndSearchedForBy:(NSString *)search;
1087 - (NSNumber *) isInstalledAndVisible:(NSNumber *)number;
1088 - (NSNumber *) isVisiblyUninstalledInSection:(NSString *)section;
1089 - (NSNumber *) isVisibleInSource:(Source *)source;
1093 @implementation Package
1100 if (installed_ != nil)
1101 [installed_ release];
1109 if (depiction_ != nil)
1110 [depiction_ release];
1111 if (homepage_ != nil)
1112 [homepage_ release];
1113 if (sponsor_ != nil)
1122 if (relationships_ != nil)
1123 [relationships_ release];
1128 + (NSArray *) _attributeKeys {
1129 return [NSArray arrayWithObjects:@"author", @"depiction", @"description", @"essential", @"homepage", @"icon", @"id", @"installed", @"latest", @"maintainer", @"name", @"section", @"size", @"source", @"sponsor", @"tagline", nil];
1132 - (NSArray *) attributeKeys {
1133 return [[self class] _attributeKeys];
1136 + (BOOL) isKeyExcludedFromWebScript:(const char *)name {
1137 return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name];
1140 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
1141 if ((self = [super init]) != nil) {
1142 iterator_ = iterator;
1143 database_ = database;
1145 version_ = [database_ policy]->GetCandidateVer(iterator_);
1146 latest_ = version_.end() ? nil : [StripVersion([NSString stringWithUTF8String:version_.VerStr()]) retain];
1148 if (!version_.end())
1149 file_ = version_.FileList();
1151 pkgCache &cache([database_ cache]);
1152 file_ = pkgCache::VerFileIterator(cache, cache.VerFileP);
1155 pkgCache::VerIterator current = iterator_.CurrentVer();
1156 installed_ = current.end() ? nil : [StripVersion([NSString stringWithUTF8String:current.VerStr()]) retain];
1158 id_ = [[[NSString stringWithUTF8String:iterator_.Name()] lowercaseString] retain];
1161 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1163 const char *begin, *end;
1164 parser->GetRec(begin, end);
1166 name_ = Scour("Name", begin, end);
1168 name_ = [name_ retain];
1169 tagline_ = [[NSString stringWithUTF8String:parser->ShortDesc().c_str()] retain];
1170 icon_ = Scour("Icon", begin, end);
1172 icon_ = [icon_ retain];
1173 depiction_ = Scour("Depiction", begin, end);
1174 if (depiction_ != nil)
1175 depiction_ = [depiction_ retain];
1176 homepage_ = Scour("Homepage", begin, end);
1177 if (homepage_ == nil)
1178 homepage_ = Scour("Website", begin, end);
1179 if ([homepage_ isEqualToString:depiction_])
1181 if (homepage_ != nil)
1182 homepage_ = [homepage_ retain];
1183 NSString *sponsor = Scour("Sponsor", begin, end);
1185 sponsor_ = [[Address addressWithString:sponsor] retain];
1186 NSString *author = Scour("Author", begin, end);
1188 author_ = [[Address addressWithString:author] retain];
1189 NSString *tags = Scour("Tag", begin, end);
1191 tags_ = [[tags componentsSeparatedByString:@", "] retain];
1195 for (int i(0), e([tags_ count]); i != e; ++i) {
1196 NSString *tag = [tags_ objectAtIndex:i];
1197 if ([tag hasPrefix:@"role::"]) {
1198 role_ = [[tag substringFromIndex:6] retain];
1203 NSMutableDictionary *metadata = [Packages_ objectForKey:id_];
1204 if (metadata == nil || [metadata count] == 0) {
1205 metadata = [NSMutableDictionary dictionaryWithObjectsAndKeys:
1209 [Packages_ setObject:metadata forKey:id_];
1215 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
1216 return [[[Package alloc]
1217 initWithIterator:iterator
1222 - (pkgCache::PkgIterator) iterator {
1226 - (NSString *) section {
1227 const char *section = iterator_.Section();
1228 if (section == NULL)
1231 NSString *name = [[NSString stringWithUTF8String:section] stringByReplacingCharacter:' ' withCharacter:'_'];
1234 if (NSDictionary *value = [SectionMap_ objectForKey:name])
1235 if (NSString *rename = [value objectForKey:@"Rename"]) {
1240 return [name stringByReplacingCharacter:'_' withCharacter:' '];
1243 - (Address *) maintainer {
1246 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1247 return [Address addressWithString:[NSString stringWithUTF8String:parser->Maintainer().c_str()]];
1251 return version_.end() ? 0 : version_->InstalledSize;
1254 - (NSString *) description {
1257 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1258 NSString *description([NSString stringWithUTF8String:parser->LongDesc().c_str()]);
1260 NSArray *lines = [description componentsSeparatedByString:@"\n"];
1261 NSMutableArray *trimmed = [NSMutableArray arrayWithCapacity:([lines count] - 1)];
1262 if ([lines count] < 2)
1265 NSCharacterSet *whitespace = [NSCharacterSet whitespaceCharacterSet];
1266 for (size_t i(1); i != [lines count]; ++i) {
1267 NSString *trim = [[lines objectAtIndex:i] stringByTrimmingCharactersInSet:whitespace];
1268 [trimmed addObject:trim];
1271 return [trimmed componentsJoinedByString:@"\n"];
1274 - (NSString *) index {
1275 NSString *index = [[[self name] substringToIndex:1] uppercaseString];
1276 return [index length] != 0 && isalpha([index characterAtIndex:0]) ? index : @"123";
1280 return [[Packages_ objectForKey:id_] objectForKey:@"FirstSeen"];
1283 - (NSString *) latest {
1287 - (NSString *) installed {
1292 return !version_.end();
1295 - (BOOL) upgradableAndEssential:(BOOL)essential {
1296 pkgCache::VerIterator current = iterator_.CurrentVer();
1299 return essential && [self essential];
1301 pkgCache::VerIterator candidate = [database_ policy]->GetCandidateVer(iterator_);
1302 return !candidate.end() && candidate != current;
1306 - (BOOL) essential {
1307 return (iterator_->Flags & pkgCache::Flag::Essential) == 0 ? NO : YES;
1311 return [database_ cache][iterator_].InstBroken();
1314 - (BOOL) unfiltered {
1315 NSString *section = [self section];
1316 return section == nil || isSectionVisible(section);
1320 return [self hasSupportingRole] && [self unfiltered];
1324 unsigned char current = iterator_->CurrentState;
1325 return current == pkgCache::State::HalfConfigured || current == pkgCache::State::HalfInstalled;
1328 - (BOOL) halfConfigured {
1329 return iterator_->CurrentState == pkgCache::State::HalfConfigured;
1332 - (BOOL) halfInstalled {
1333 return iterator_->CurrentState == pkgCache::State::HalfInstalled;
1337 pkgDepCache::StateCache &state([database_ cache][iterator_]);
1338 return state.Mode != pkgDepCache::ModeKeep;
1341 - (NSString *) mode {
1342 pkgDepCache::StateCache &state([database_ cache][iterator_]);
1344 switch (state.Mode) {
1345 case pkgDepCache::ModeDelete:
1346 if ((state.iFlags & pkgDepCache::Purge) != 0)
1351 case pkgDepCache::ModeKeep:
1352 if ((state.iFlags & pkgDepCache::AutoKept) != 0)
1357 case pkgDepCache::ModeInstall:
1358 if ((state.iFlags & pkgDepCache::ReInstall) != 0)
1359 return @"Reinstall";
1360 else switch (state.Status) {
1362 return @"Downgrade";
1368 return @"New Install";
1381 - (NSString *) name {
1382 return name_ == nil ? id_ : name_;
1385 - (NSString *) tagline {
1389 - (NSString *) icon {
1393 - (NSString *) homepage {
1397 - (NSString *) depiction {
1401 - (Address *) sponsor {
1405 - (Address *) author {
1409 - (NSArray *) relationships {
1410 return relationships_;
1413 - (Source *) source {
1415 source_ = file_.end() ? nil : [[database_ getSource:file_.File()] retain];
1422 - (NSString *) role {
1426 - (BOOL) matches:(NSString *)text {
1432 range = [[self id] rangeOfString:text options:NSCaseInsensitiveSearch];
1433 if (range.location != NSNotFound)
1436 range = [[self name] rangeOfString:text options:NSCaseInsensitiveSearch];
1437 if (range.location != NSNotFound)
1440 range = [[self tagline] rangeOfString:text options:NSCaseInsensitiveSearch];
1441 if (range.location != NSNotFound)
1447 - (bool) hasSupportingRole {
1450 if ([role_ isEqualToString:@"enduser"])
1452 if ([Role_ isEqualToString:@"User"])
1454 if ([role_ isEqualToString:@"hacker"])
1456 if ([Role_ isEqualToString:@"Hacker"])
1458 if ([role_ isEqualToString:@"developer"])
1460 if ([Role_ isEqualToString:@"Developer"])
1465 - (BOOL) hasTag:(NSString *)tag {
1466 return tags_ == nil ? NO : [tags_ containsObject:tag];
1469 - (NSComparisonResult) compareByName:(Package *)package {
1470 NSString *lhs = [self name];
1471 NSString *rhs = [package name];
1473 if ([lhs length] != 0 && [rhs length] != 0) {
1474 unichar lhc = [lhs characterAtIndex:0];
1475 unichar rhc = [rhs characterAtIndex:0];
1477 if (isalpha(lhc) && !isalpha(rhc))
1478 return NSOrderedAscending;
1479 else if (!isalpha(lhc) && isalpha(rhc))
1480 return NSOrderedDescending;
1483 return [lhs compare:rhs options:CompareOptions_];
1486 - (NSComparisonResult) compareBySection:(Package *)package {
1487 NSString *lhs = [self section];
1488 NSString *rhs = [package section];
1490 if (lhs == NULL && rhs != NULL)
1491 return NSOrderedAscending;
1492 else if (lhs != NULL && rhs == NULL)
1493 return NSOrderedDescending;
1494 else if (lhs != NULL && rhs != NULL) {
1495 NSComparisonResult result = [lhs compare:rhs options:CompareOptions_];
1496 if (result != NSOrderedSame)
1500 return NSOrderedSame;
1503 - (NSComparisonResult) compareBySectionAndName:(Package *)package {
1504 NSString *lhs = [self section];
1505 NSString *rhs = [package section];
1507 if (lhs == NULL && rhs != NULL)
1508 return NSOrderedAscending;
1509 else if (lhs != NULL && rhs == NULL)
1510 return NSOrderedDescending;
1511 else if (lhs != NULL && rhs != NULL) {
1512 NSComparisonResult result = [lhs compare:rhs];
1513 if (result != NSOrderedSame)
1517 return [self compareByName:package];
1520 - (NSComparisonResult) compareForChanges:(Package *)package {
1521 BOOL lhs = [self upgradableAndEssential:YES];
1522 BOOL rhs = [package upgradableAndEssential:YES];
1525 return lhs ? NSOrderedAscending : NSOrderedDescending;
1527 switch ([[self seen] compare:[package seen]]) {
1528 case NSOrderedAscending:
1529 return NSOrderedDescending;
1532 case NSOrderedDescending:
1533 return NSOrderedAscending;
1539 return [self compareByName:package];
1543 pkgProblemResolver *resolver = [database_ resolver];
1544 resolver->Clear(iterator_);
1545 resolver->Protect(iterator_);
1546 pkgCacheFile &cache([database_ cache]);
1547 cache->MarkInstall(iterator_, false);
1548 pkgDepCache::StateCache &state((*cache)[iterator_]);
1549 if (!state.Install())
1550 cache->SetReInstall(iterator_, true);
1554 pkgProblemResolver *resolver = [database_ resolver];
1555 resolver->Clear(iterator_);
1556 resolver->Protect(iterator_);
1557 resolver->Remove(iterator_);
1558 [database_ cache]->MarkDelete(iterator_, true);
1561 - (NSNumber *) isUnfilteredAndSearchedForBy:(NSString *)search {
1562 return [NSNumber numberWithBool:(
1563 [self unfiltered] && [self matches:search]
1567 - (NSNumber *) isInstalledAndVisible:(NSNumber *)number {
1568 return [NSNumber numberWithBool:(
1569 (![number boolValue] || [self visible]) && [self installed] != nil
1573 - (NSNumber *) isVisiblyUninstalledInSection:(NSString *)name {
1574 NSString *section = [self section];
1576 return [NSNumber numberWithBool:(
1578 [self installed] == nil && (
1580 section == nil && [name length] == 0 ||
1581 [name isEqualToString:section]
1586 - (NSNumber *) isVisibleInSource:(Source *)source {
1587 return [NSNumber numberWithBool:([self source] == source && [self visible])];
1592 /* Section Class {{{ */
1593 @interface Section : NSObject {
1599 - (NSComparisonResult) compareByName:(Section *)section;
1600 - (Section *) initWithName:(NSString *)name;
1601 - (Section *) initWithName:(NSString *)name row:(size_t)row;
1602 - (NSString *) name;
1605 - (void) addToCount;
1609 @implementation Section
1616 - (NSComparisonResult) compareByName:(Section *)section {
1617 NSString *lhs = [self name];
1618 NSString *rhs = [section name];
1620 if ([lhs length] != 0 && [rhs length] != 0) {
1621 unichar lhc = [lhs characterAtIndex:0];
1622 unichar rhc = [rhs characterAtIndex:0];
1624 if (isalpha(lhc) && !isalpha(rhc))
1625 return NSOrderedAscending;
1626 else if (!isalpha(lhc) && isalpha(rhc))
1627 return NSOrderedDescending;
1630 return [lhs compare:rhs options:CompareOptions_];
1633 - (Section *) initWithName:(NSString *)name {
1634 return [self initWithName:name row:0];
1637 - (Section *) initWithName:(NSString *)name row:(size_t)row {
1638 if ((self = [super init]) != nil) {
1639 name_ = [name retain];
1644 - (NSString *) name {
1656 - (void) addToCount {
1666 /* Database Implementation {{{ */
1667 @implementation Database
1674 - (void) _readCydia:(NSNumber *)fd {
1675 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1677 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1678 std::istream is(&ib);
1681 static Pcre finish_r("^finish:([^:]*)$");
1683 while (std::getline(is, line)) {
1684 const char *data(line.c_str());
1685 size_t size = line.size();
1686 fprintf(stderr, "C:%s\n", data);
1688 if (finish_r(data, size)) {
1689 NSString *finish = finish_r[1];
1690 int index = [Finishes_ indexOfObject:finish];
1691 if (index != INT_MAX && index > Finish_)
1700 - (void) _readStatus:(NSNumber *)fd {
1701 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1703 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1704 std::istream is(&ib);
1707 static Pcre conffile_r("^status: [^ ]* : conffile-prompt : (.*?) *$");
1708 static Pcre pmstatus_r("^([^:]*):([^:]*):([^:]*):(.*)$");
1710 while (std::getline(is, line)) {
1711 const char *data(line.c_str());
1712 size_t size = line.size();
1713 fprintf(stderr, "S:%s\n", data);
1715 if (conffile_r(data, size)) {
1716 [delegate_ setConfigurationData:conffile_r[1]];
1717 } else if (strncmp(data, "status: ", 8) == 0) {
1718 NSString *string = [NSString stringWithUTF8String:(data + 8)];
1719 [delegate_ setProgressTitle:string];
1720 } else if (pmstatus_r(data, size)) {
1721 std::string type([pmstatus_r[1] UTF8String]);
1722 NSString *id = pmstatus_r[2];
1724 float percent([pmstatus_r[3] floatValue]);
1725 [delegate_ setProgressPercent:(percent / 100)];
1727 NSString *string = pmstatus_r[4];
1729 if (type == "pmerror")
1730 [delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
1731 withObject:[NSArray arrayWithObjects:string, id, nil]
1734 else if (type == "pmstatus")
1735 [delegate_ setProgressTitle:string];
1736 else if (type == "pmconffile")
1737 [delegate_ setConfigurationData:string];
1738 else _assert(false);
1739 } else _assert(false);
1746 - (void) _readOutput:(NSNumber *)fd {
1747 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1749 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1750 std::istream is(&ib);
1753 while (std::getline(is, line)) {
1754 fprintf(stderr, "O:%s\n", line.c_str());
1755 [delegate_ addProgressOutput:[NSString stringWithUTF8String:line.c_str()]];
1766 - (Package *) packageWithName:(NSString *)name {
1767 if (static_cast<pkgDepCache *>(cache_) == NULL)
1769 pkgCache::PkgIterator iterator(cache_->FindPkg([name UTF8String]));
1770 return iterator.end() ? nil : [Package packageWithIterator:iterator database:self];
1773 - (Database *) init {
1774 if ((self = [super init]) != nil) {
1781 sources_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1782 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
1786 _assert(pipe(fds) != -1);
1789 _config->Set("APT::Keep-Fds::", cydiafd_);
1790 setenv("CYDIA", [[[[NSNumber numberWithInt:cydiafd_] stringValue] stringByAppendingString:@" 1"] UTF8String], _not(int));
1793 detachNewThreadSelector:@selector(_readCydia:)
1795 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1798 _assert(pipe(fds) != -1);
1802 detachNewThreadSelector:@selector(_readStatus:)
1804 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1807 _assert(pipe(fds) != -1);
1808 _assert(dup2(fds[0], 0) != -1);
1809 _assert(close(fds[0]) != -1);
1811 input_ = fdopen(fds[1], "a");
1813 _assert(pipe(fds) != -1);
1814 _assert(dup2(fds[1], 1) != -1);
1815 _assert(close(fds[1]) != -1);
1818 detachNewThreadSelector:@selector(_readOutput:)
1820 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1825 - (pkgCacheFile &) cache {
1829 - (pkgDepCache::Policy *) policy {
1833 - (pkgRecords *) records {
1837 - (pkgProblemResolver *) resolver {
1841 - (pkgAcquire &) fetcher {
1845 - (NSArray *) packages {
1849 - (NSArray *) sources {
1850 return [sources_ allValues];
1853 - (void) reloadData {
1872 if (!cache_.Open(progress_, true)) {
1874 if (!_error->PopMessage(error))
1877 fprintf(stderr, "cache_.Open():[%s]\n", error.c_str());
1879 if (error == "dpkg was interrupted, you must manually run 'dpkg --configure -a' to correct the problem. ")
1880 [delegate_ repairWithSelector:@selector(configure)];
1881 else if (error == "The package lists or status file could not be parsed or opened.")
1882 [delegate_ repairWithSelector:@selector(update)];
1883 // else if (error == "Could not open lock file /var/lib/dpkg/lock - open (13 Permission denied)")
1884 // else if (error == "Could not get lock /var/lib/dpkg/lock - open (35 Resource temporarily unavailable)")
1885 // else if (error == "The list of sources could not be read.")
1886 else _assert(false);
1891 now_ = [[NSDate date] retain];
1893 policy_ = new pkgDepCache::Policy();
1894 records_ = new pkgRecords(cache_);
1895 resolver_ = new pkgProblemResolver(cache_);
1896 fetcher_ = new pkgAcquire(&status_);
1899 list_ = new pkgSourceList();
1900 _assert(list_->ReadMainList());
1902 _assert(cache_->DelCount() == 0 && cache_->InstCount() == 0);
1903 _assert(pkgApplyStatus(cache_));
1905 if (cache_->BrokenCount() != 0) {
1906 _assert(pkgFixBroken(cache_));
1907 _assert(cache_->BrokenCount() == 0);
1908 _assert(pkgMinimizeUpgrade(cache_));
1911 [sources_ removeAllObjects];
1912 for (pkgSourceList::const_iterator source = list_->begin(); source != list_->end(); ++source) {
1913 std::vector<pkgIndexFile *> *indices = (*source)->GetIndexFiles();
1914 for (std::vector<pkgIndexFile *>::const_iterator index = indices->begin(); index != indices->end(); ++index)
1916 setObject:[[[Source alloc] initWithMetaIndex:*source] autorelease]
1917 forKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(*index)]
1921 [packages_ removeAllObjects];
1922 for (pkgCache::PkgIterator iterator = cache_->PkgBegin(); !iterator.end(); ++iterator)
1923 if (Package *package = [Package packageWithIterator:iterator database:self])
1924 [packages_ addObject:package];
1926 [packages_ sortUsingSelector:@selector(compareByName:)];
1929 - (void) configure {
1930 NSString *dpkg = [NSString stringWithFormat:@"dpkg --configure -a --status-fd %u", statusfd_];
1931 system([dpkg UTF8String]);
1939 Lock.Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1940 _assert(!_error->PendingError());
1943 fetcher.Clean(_config->FindDir("Dir::Cache::Archives"));
1946 public pkgArchiveCleaner
1949 virtual void Erase(const char *File, std::string Pkg, std::string Ver, struct stat &St) {
1954 if (!cleaner.Go(_config->FindDir("Dir::Cache::Archives") + "partial/", cache_)) {
1956 while (_error->PopMessage(error))
1957 fprintf(stderr, "ArchiveCleaner: %s\n", error.c_str());
1962 pkgRecords records(cache_);
1964 lock_ = new FileFd();
1965 lock_->Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1966 _assert(!_error->PendingError());
1969 // XXX: explain this with an error message
1970 _assert(list.ReadMainList());
1972 manager_ = (_system->CreatePM(cache_));
1973 _assert(manager_->GetArchives(fetcher_, &list, &records));
1974 _assert(!_error->PendingError());
1978 NSMutableArray *before = [NSMutableArray arrayWithCapacity:16]; {
1980 _assert(list.ReadMainList());
1981 for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source)
1982 [before addObject:[NSString stringWithUTF8String:(*source)->GetURI().c_str()]];
1985 if (fetcher_->Run(PulseInterval_) != pkgAcquire::Continue) {
1990 bool failed = false;
1991 for (pkgAcquire::ItemIterator item = fetcher_->ItemsBegin(); item != fetcher_->ItemsEnd(); item++) {
1992 if ((*item)->Status == pkgAcquire::Item::StatDone && (*item)->Complete)
1995 std::string uri = (*item)->DescURI();
1996 std::string error = (*item)->ErrorText;
1998 fprintf(stderr, "pAf:%s:%s\n", uri.c_str(), error.c_str());
2001 [delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
2002 withObject:[NSArray arrayWithObjects:[NSString stringWithUTF8String:error.c_str()], nil]
2013 pkgPackageManager::OrderResult result = manager_->DoInstall(statusfd_);
2015 if (_error->PendingError()) {
2020 if (result == pkgPackageManager::Failed) {
2025 if (result != pkgPackageManager::Completed) {
2030 NSMutableArray *after = [NSMutableArray arrayWithCapacity:16]; {
2032 _assert(list.ReadMainList());
2033 for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source)
2034 [after addObject:[NSString stringWithUTF8String:(*source)->GetURI().c_str()]];
2037 if (![before isEqualToArray:after])
2042 _assert(pkgDistUpgrade(cache_));
2046 [self updateWithStatus:status_];
2049 - (void) updateWithStatus:(Status &)status {
2051 _assert(list.ReadMainList());
2054 lock.Fd(GetLock(_config->FindDir("Dir::State::Lists") + "lock"));
2055 _assert(!_error->PendingError());
2057 pkgAcquire fetcher(&status);
2058 _assert(list.GetIndexes(&fetcher));
2060 if (fetcher.Run(PulseInterval_) != pkgAcquire::Failed) {
2061 bool failed = false;
2062 for (pkgAcquire::ItemIterator item = fetcher.ItemsBegin(); item != fetcher.ItemsEnd(); item++)
2063 if ((*item)->Status != pkgAcquire::Item::StatDone) {
2064 (*item)->Finished();
2068 if (!failed && _config->FindB("APT::Get::List-Cleanup", true) == true) {
2069 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists")));
2070 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/"));
2073 [Metadata_ setObject:[NSDate date] forKey:@"LastUpdate"];
2078 - (void) setDelegate:(id)delegate {
2079 delegate_ = delegate;
2080 status_.setDelegate(delegate);
2081 progress_.setDelegate(delegate);
2084 - (Source *) getSource:(const pkgCache::PkgFileIterator &)file {
2085 pkgIndexFile *index(NULL);
2086 list_->FindIndex(file, index);
2087 return [sources_ objectForKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(index)]];
2093 /* Confirmation View {{{ */
2094 void AddTextView(NSMutableDictionary *fields, NSMutableArray *packages, NSString *key) {
2095 if ([packages count] == 0)
2098 UITextView *text = GetTextView([packages count] == 0 ? @"n/a" : [packages componentsJoinedByString:@", "], 120, false);
2099 [fields setObject:text forKey:key];
2101 CGColor blue(space_, 0, 0, 0.4, 1);
2102 [text setTextColor:[UIColor colorWithCGColor:blue]];
2105 bool DepSubstrate(const pkgCache::VerIterator &iterator) {
2106 if (!iterator.end())
2107 for (pkgCache::DepIterator dep(iterator.DependsList()); !dep.end(); ++dep) {
2108 if (dep->Type != pkgCache::Dep::Depends && dep->Type != pkgCache::Dep::PreDepends)
2110 pkgCache::PkgIterator package(dep.TargetPkg());
2113 if (strcmp(package.Name(), "mobilesubstrate") == 0)
2120 @protocol ConfirmationViewDelegate
2125 @interface ConfirmationView : UIView {
2126 Database *database_;
2128 UITransitionView *transition_;
2130 UINavigationBar *navbar_;
2131 UIPreferencesTable *table_;
2132 NSMutableDictionary *fields_;
2133 UIActionSheet *essential_;
2139 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate;
2143 @implementation ConfirmationView
2146 [navbar_ setDelegate:nil];
2147 [transition_ setDelegate:nil];
2148 [table_ setDataSource:nil];
2150 [transition_ release];
2155 if (essential_ != nil)
2156 [essential_ release];
2161 [transition_ transition:7 toView:nil];
2165 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
2166 if (from != nil && to == nil)
2167 [self removeFromSuperview];
2170 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2173 if (essential_ != nil)
2174 [essential_ popupAlertAnimated:YES];
2178 [delegate_ confirm];
2188 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
2189 NSString *context = [sheet context];
2191 if ([context isEqualToString:@"remove"])
2199 [delegate_ confirm];
2204 else if ([context isEqualToString:@"unable"])
2210 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
2214 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
2216 case 0: return @"Statistics";
2217 case 1: return @"Modifications";
2219 default: _assert(false);
2223 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
2226 case 1: return [fields_ count];
2228 default: _assert(false);
2232 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
2233 if (group != 1 || row == -1)
2236 _assert(size_t(row) < [fields_ count]);
2237 return [[[fields_ allValues] objectAtIndex:row] visibleTextRect].size.height + TextViewOffset_;
2241 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
2242 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
2243 [cell setShowSelection:NO];
2246 case 0: switch (row) {
2248 [cell setTitle:@"Downloading"];
2249 [cell setValue:SizeString([database_ fetcher].FetchNeeded())];
2253 [cell setTitle:@"Resuming At"];
2254 [cell setValue:SizeString([database_ fetcher].PartialPresent())];
2258 double size([database_ cache]->UsrSize());
2261 [cell setTitle:@"Disk Freeing"];
2262 [cell setValue:SizeString(-size)];
2264 [cell setTitle:@"Disk Using"];
2265 [cell setValue:SizeString(size)];
2269 default: _assert(false);
2273 _assert(size_t(row) < [fields_ count]);
2274 [cell setTitle:[[fields_ allKeys] objectAtIndex:row]];
2275 [cell addSubview:[[fields_ allValues] objectAtIndex:row]];
2278 default: _assert(false);
2284 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate {
2285 if ((self = [super initWithFrame:[view bounds]]) != nil) {
2286 database_ = database;
2287 delegate_ = delegate;
2289 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
2290 [self addSubview:transition_];
2292 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
2294 CGSize navsize = [UINavigationBar defaultSize];
2295 CGRect navrect = {{0, 0}, navsize};
2296 CGRect bounds = [overlay_ bounds];
2298 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
2299 [navbar_ setDelegate:self];
2301 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Confirm"] autorelease];
2302 [navbar_ pushNavigationItem:navitem];
2303 [navbar_ showButtonsWithLeftTitle:@"Cancel" rightTitle:@"Confirm"];
2305 fields_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
2307 NSMutableArray *installing = [NSMutableArray arrayWithCapacity:16];
2308 NSMutableArray *reinstalling = [NSMutableArray arrayWithCapacity:16];
2309 NSMutableArray *upgrading = [NSMutableArray arrayWithCapacity:16];
2310 NSMutableArray *downgrading = [NSMutableArray arrayWithCapacity:16];
2311 NSMutableArray *removing = [NSMutableArray arrayWithCapacity:16];
2315 pkgDepCache::Policy *policy([database_ policy]);
2317 pkgCacheFile &cache([database_ cache]);
2318 NSArray *packages = [database_ packages];
2319 for (size_t i(0), e = [packages count]; i != e; ++i) {
2320 Package *package = [packages objectAtIndex:i];
2321 pkgCache::PkgIterator iterator = [package iterator];
2322 pkgDepCache::StateCache &state(cache[iterator]);
2324 NSString *name([package name]);
2326 if (state.NewInstall())
2327 [installing addObject:name];
2328 else if (!state.Delete() && (state.iFlags & pkgDepCache::ReInstall) == pkgDepCache::ReInstall)
2329 [reinstalling addObject:name];
2330 else if (state.Upgrade())
2331 [upgrading addObject:name];
2332 else if (state.Downgrade())
2333 [downgrading addObject:name];
2334 else if (state.Delete()) {
2335 if ([package essential])
2337 [removing addObject:name];
2340 substrate_ |= DepSubstrate(policy->GetCandidateVer(iterator));
2341 substrate_ |= DepSubstrate(iterator.CurrentVer());
2346 else if (Advanced_ || true) {
2347 essential_ = [[UIActionSheet alloc]
2348 initWithTitle:@"Removing Essentials"
2349 buttons:[NSArray arrayWithObjects:
2350 @"Cancel Operation (Safe)",
2351 @"Force Removal (Unsafe)",
2353 defaultButtonIndex:0
2359 [essential_ setDestructiveButton:[[essential_ buttons] objectAtIndex:0]];
2361 [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."];
2363 essential_ = [[UIActionSheet alloc]
2364 initWithTitle:@"Unable to Comply"
2365 buttons:[NSArray arrayWithObjects:@"Okay", nil]
2366 defaultButtonIndex:0
2371 [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."];
2374 AddTextView(fields_, installing, @"Installing");
2375 AddTextView(fields_, reinstalling, @"Reinstalling");
2376 AddTextView(fields_, upgrading, @"Upgrading");
2377 AddTextView(fields_, downgrading, @"Downgrading");
2378 AddTextView(fields_, removing, @"Removing");
2380 table_ = [[UIPreferencesTable alloc] initWithFrame:CGRectMake(
2381 0, navsize.height, bounds.size.width, bounds.size.height - navsize.height
2384 [table_ setDataSource:self];
2385 [table_ reloadData];
2387 [overlay_ addSubview:navbar_];
2388 [overlay_ addSubview:table_];
2390 [view addSubview:self];
2392 [transition_ setDelegate:self];
2394 UIView *blank = [[[UIView alloc] initWithFrame:[transition_ bounds]] autorelease];
2395 [transition_ transition:0 toView:blank];
2396 [transition_ transition:3 toView:overlay_];
2403 /* Progress Data {{{ */
2404 @interface ProgressData : NSObject {
2410 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object;
2417 @implementation ProgressData
2419 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object {
2420 if ((self = [super init]) != nil) {
2421 selector_ = selector;
2441 /* Progress View {{{ */
2442 @interface ProgressView : UIView <
2443 ConfigurationDelegate,
2446 _transient Database *database_;
2448 UIView *background_;
2449 UITransitionView *transition_;
2451 UINavigationBar *navbar_;
2452 UIProgressBar *progress_;
2453 UITextView *output_;
2454 UITextLabel *status_;
2455 UIPushButton *close_;
2458 SHA1SumValue springlist_;
2460 NSTimeInterval last_;
2463 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
2465 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database delegate:(id)delegate;
2466 - (void) setContentView:(UIView *)view;
2469 - (void) _retachThread;
2470 - (void) _detachNewThreadData:(ProgressData *)data;
2471 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title;
2477 @protocol ProgressViewDelegate
2478 - (void) progressViewIsComplete:(ProgressView *)sender;
2481 @implementation ProgressView
2484 [transition_ setDelegate:nil];
2485 [navbar_ setDelegate:nil];
2488 if (background_ != nil)
2489 [background_ release];
2490 [transition_ release];
2493 [progress_ release];
2500 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
2501 if (bootstrap_ && from == overlay_ && to == view_)
2505 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database delegate:(id)delegate {
2506 if ((self = [super initWithFrame:frame]) != nil) {
2507 database_ = database;
2508 delegate_ = delegate;
2510 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
2511 [transition_ setDelegate:self];
2513 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
2516 [overlay_ setBackgroundColor:[UIColor blackColor]];
2518 background_ = [[UIView alloc] initWithFrame:[self bounds]];
2519 [background_ setBackgroundColor:[UIColor blackColor]];
2520 [self addSubview:background_];
2523 [self addSubview:transition_];
2525 CGSize navsize = [UINavigationBar defaultSize];
2526 CGRect navrect = {{0, 0}, navsize};
2528 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
2529 [overlay_ addSubview:navbar_];
2531 [navbar_ setBarStyle:1];
2532 [navbar_ setDelegate:self];
2534 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:nil] autorelease];
2535 [navbar_ pushNavigationItem:navitem];
2537 CGRect bounds = [overlay_ bounds];
2538 CGSize prgsize = [UIProgressBar defaultSize];
2541 (bounds.size.width - prgsize.width) / 2,
2542 bounds.size.height - prgsize.height - 20
2545 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
2546 [progress_ setStyle:0];
2548 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(
2550 bounds.size.height - prgsize.height - 50,
2551 bounds.size.width - 20,
2555 [status_ setColor:[UIColor whiteColor]];
2556 [status_ setBackgroundColor:[UIColor clearColor]];
2558 [status_ setCentersHorizontally:YES];
2559 //[status_ setFont:font];
2561 output_ = [[UITextView alloc] initWithFrame:CGRectMake(
2563 navrect.size.height + 20,
2564 bounds.size.width - 20,
2565 bounds.size.height - navsize.height - 62 - navrect.size.height
2568 //[output_ setTextFont:@"Courier New"];
2569 [output_ setTextSize:12];
2571 [output_ setTextColor:[UIColor whiteColor]];
2572 [output_ setBackgroundColor:[UIColor clearColor]];
2574 [output_ setMarginTop:0];
2575 [output_ setAllowsRubberBanding:YES];
2576 [output_ setEditable:NO];
2578 [overlay_ addSubview:output_];
2580 close_ = [[UIPushButton alloc] initWithFrame:CGRectMake(
2582 bounds.size.height - prgsize.height - 50,
2583 bounds.size.width - 20,
2587 [close_ setAutosizesToFit:NO];
2588 [close_ setDrawsShadow:YES];
2589 [close_ setStretchBackground:YES];
2590 [close_ setEnabled:YES];
2592 UIFont *bold = [UIFont boldSystemFontOfSize:22];
2593 [close_ setTitleFont:bold];
2595 [close_ addTarget:self action:@selector(closeButtonPushed) forEvents:kUIControlEventMouseUpInside];
2596 [close_ setBackground:[UIImage applicationImageNamed:@"green-up.png"] forState:0];
2597 [close_ setBackground:[UIImage applicationImageNamed:@"green-dn.png"] forState:1];
2601 - (void) setContentView:(UIView *)view {
2602 view_ = [view retain];
2605 - (void) resetView {
2606 [transition_ transition:6 toView:view_];
2609 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
2610 NSString *context = [sheet context];
2611 if ([context isEqualToString:@"conffile"]) {
2612 FILE *input = [database_ input];
2616 fprintf(input, "N\n");
2620 fprintf(input, "Y\n");
2631 - (void) closeButtonPushed {
2634 [delegate_ progressViewIsComplete:self];
2639 [delegate_ suspendWithAnimation:YES];
2643 system("launchctl stop com.apple.SpringBoard");
2647 system("launchctl unload /System/Library/LaunchDaemons/com.apple.SpringBoard.plist; launchctl load /System/Library/LaunchDaemons/com.apple.SpringBoard.plist");
2656 - (void) _retachThread {
2657 UINavigationItem *item = [navbar_ topItem];
2658 [item setTitle:@"Complete"];
2660 [overlay_ addSubview:close_];
2661 [progress_ removeFromSuperview];
2662 [status_ removeFromSuperview];
2665 FileFd file("/System/Library/LaunchDaemons/com.apple.SpringBoard.plist", FileFd::ReadOnly);
2666 MMap mmap(file, MMap::ReadOnly);
2668 sha1.Add(reinterpret_cast<uint8_t *>(mmap.Data()), mmap.Size());
2669 if (!(springlist_ == sha1.Result()))
2674 case 0: [close_ setTitle:@"Return to Cydia"]; break;
2675 case 1: [close_ setTitle:@"Close Cydia (Restart)"]; break;
2676 case 2: [close_ setTitle:@"Restart SpringBoard"]; break;
2677 case 3: [close_ setTitle:@"Reload SpringBoard"]; break;
2678 case 4: [close_ setTitle:@"Reboot Device"]; break;
2682 notify_post("com.apple.mobile.application_installed");
2685 [delegate_ setStatusBarShowsProgress:NO];
2690 - (void) _detachNewThreadData:(ProgressData *)data {
2691 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
2693 [[data target] performSelector:[data selector] withObject:[data object]];
2696 [self performSelectorOnMainThread:@selector(_retachThread) withObject:nil waitUntilDone:YES];
2701 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title {
2702 UINavigationItem *item = [navbar_ topItem];
2703 [item setTitle:title];
2705 [status_ setText:nil];
2706 [output_ setText:@""];
2707 [progress_ setProgress:0];
2710 last_ = 0;//[NSDate timeIntervalSinceReferenceDate];
2712 [close_ removeFromSuperview];
2713 [overlay_ addSubview:progress_];
2714 [overlay_ addSubview:status_];
2716 [delegate_ setStatusBarShowsProgress:YES];
2720 FileFd file("/System/Library/LaunchDaemons/com.apple.SpringBoard.plist", FileFd::ReadOnly);
2721 MMap mmap(file, MMap::ReadOnly);
2723 sha1.Add(reinterpret_cast<uint8_t *>(mmap.Data()), mmap.Size());
2724 springlist_ = sha1.Result();
2727 [transition_ transition:6 toView:overlay_];
2730 detachNewThreadSelector:@selector(_detachNewThreadData:)
2732 withObject:[[ProgressData alloc]
2733 initWithSelector:selector
2740 - (void) repairWithSelector:(SEL)selector {
2742 detachNewThreadSelector:selector
2749 - (void) setConfigurationData:(NSString *)data {
2751 performSelectorOnMainThread:@selector(_setConfigurationData:)
2757 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id {
2758 Package *package = id == nil ? nil : [database_ packageWithName:id];
2760 UIActionSheet *sheet = [[[UIActionSheet alloc]
2761 initWithTitle:(package == nil ? @"Source Error" : [package name])
2762 buttons:[NSArray arrayWithObjects:@"Okay", nil]
2763 defaultButtonIndex:0
2768 [sheet setBodyText:error];
2769 [sheet popupAlertAnimated:YES];
2772 - (void) setProgressTitle:(NSString *)title {
2774 performSelectorOnMainThread:@selector(_setProgressTitle:)
2780 - (void) setProgressPercent:(float)percent {
2782 performSelectorOnMainThread:@selector(_setProgressPercent:)
2783 withObject:[NSNumber numberWithFloat:percent]
2788 - (void) startProgress {
2789 last_ = [NSDate timeIntervalSinceReferenceDate];
2792 - (void) addProgressOutput:(NSString *)output {
2794 performSelectorOnMainThread:@selector(_addProgressOutput:)
2800 - (bool) isCancelling:(size_t)received {
2802 NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate];
2803 if (received_ != received) {
2804 received_ = received;
2806 } else if (now - last_ > 30)
2813 - (void) _setConfigurationData:(NSString *)data {
2814 static Pcre conffile_r("^'(.*)' '(.*)' ([01]) ([01])$");
2816 _assert(conffile_r(data));
2818 NSString *ofile = conffile_r[1];
2819 //NSString *nfile = conffile_r[2];
2821 UIActionSheet *sheet = [[[UIActionSheet alloc]
2822 initWithTitle:@"Configuration Upgrade"
2823 buttons:[NSArray arrayWithObjects:
2824 @"Keep My Old Copy",
2825 @"Accept The New Copy",
2826 // XXX: @"See What Changed",
2828 defaultButtonIndex:0
2833 [sheet setBodyText:[NSString stringWithFormat:
2834 @"The following file has been changed by both the package maintainer and by you (or for you by a script).\n\n%@"
2837 [sheet popupAlertAnimated:YES];
2840 - (void) _setProgressTitle:(NSString *)title {
2841 [status_ setText:title];
2844 - (void) _setProgressPercent:(NSNumber *)percent {
2845 [progress_ setProgress:[percent floatValue]];
2848 - (void) _addProgressOutput:(NSString *)output {
2849 [output_ setText:[NSString stringWithFormat:@"%@\n%@", [output_ text], output]];
2850 CGSize size = [output_ contentSize];
2851 CGRect rect = {{0, size.height}, {size.width, 0}};
2852 [output_ scrollRectToVisible:rect animated:YES];
2855 - (BOOL) isRunning {
2862 /* Package Cell {{{ */
2863 @interface PackageCell : UISimpleTableCell {
2866 NSString *description_;
2868 //UIImageView *trusted_;
2870 UIImageView *badge_;
2871 UITextLabel *status_;
2875 - (PackageCell *) init;
2876 - (void) setPackage:(Package *)package;
2878 + (int) heightForPackage:(Package *)package;
2882 @implementation PackageCell
2884 - (void) clearPackage {
2895 if (description_ != nil) {
2896 [description_ release];
2900 if (source_ != nil) {
2907 [self clearPackage];
2912 //[trusted_ release];
2916 - (PackageCell *) init {
2917 if ((self = [super init]) != nil) {
2919 badge_ = [[UIImageView alloc] initWithFrame:CGRectMake(17, 70, 16, 16)];
2921 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 68, 280, 20)];
2922 [status_ setBackgroundColor:[UIColor clearColor]];
2923 [status_ setFont:small];
2928 - (void) setPackage:(Package *)package {
2929 [self clearPackage];
2931 Source *source = [package source];
2934 if (NSString *icon = [package icon])
2935 icon_ = [UIImage imageAtPath:[icon substringFromIndex:6]];
2936 if (icon_ == nil) if (NSString *section = [package section])
2937 icon_ = [UIImage imageAtPath:[NSString stringWithFormat:@"%@/Sections/%@.png", App_, Simplify(section)]];
2938 /*if (icon_ == nil) if (NSString *icon = [source defaultIcon])
2939 icon_ = [UIImage imageAtPath:[icon substringFromIndex:6]];*/
2941 icon_ = [UIImage applicationImageNamed:@"unknown.png"];
2943 icon_ = [icon_ retain];
2945 name_ = [[package name] retain];
2946 description_ = [[package tagline] retain];
2948 NSString *label = nil;
2949 bool trusted = false;
2951 if (source != nil) {
2952 label = [source label];
2953 trusted = [source trusted];
2954 } else if ([[package id] isEqualToString:@"firmware"])
2957 label = @"Unknown/Local";
2959 NSString *from = [NSString stringWithFormat:@"from %@", label];
2961 NSString *section = Simplify([package section]);
2962 if (section != nil && ![section isEqualToString:label])
2963 from = [from stringByAppendingString:[NSString stringWithFormat:@" (%@)", section]];
2965 source_ = [from retain];
2968 [badge_ removeFromSuperview];
2969 [status_ removeFromSuperview];
2971 if (NSString *mode = [package mode]) {
2972 [badge_ setImage:[UIImage applicationImageNamed:
2973 [mode isEqualToString:@"Remove"] || [mode isEqualToString:@"Purge"] ? @"removing.png" : @"installing.png"
2976 [status_ setText:[NSString stringWithFormat:@"Queued for %@", mode]];
2977 [status_ setColor:Blueish_];
2978 } else if ([package half]) {
2979 [badge_ setImage:[UIImage applicationImageNamed:@"damaged.png"]];
2980 [status_ setText:@"Package Damaged"];
2981 [status_ setColor:[UIColor redColor]];
2983 [badge_ setImage:nil];
2984 [status_ setText:nil];
2988 [self addSubview:badge_];
2989 [self addSubview:status_];
2994 - (void) drawContentInRect:(CGRect)rect selected:(BOOL)selected {
2997 rect.size = [icon_ size];
2999 rect.size.width /= 2;
3000 rect.size.height /= 2;
3002 rect.origin.x = 25 - rect.size.width / 2;
3003 rect.origin.y = 25 - rect.size.height / 2;
3005 [icon_ drawInRect:rect];
3013 [name_ drawAtPoint:CGPointMake(48, 8) forWidth:240 withFont:Font18Bold_ ellipsis:2];
3014 [source_ drawAtPoint:CGPointMake(58, 29) forWidth:225 withFont:Font12_ ellipsis:2];
3018 [description_ drawAtPoint:CGPointMake(12, 46) forWidth:280 withFont:Font14_ ellipsis:2];
3020 [super drawContentInRect:rect selected:selected];
3023 + (int) heightForPackage:(Package *)package {
3024 NSString *tagline([package tagline]);
3025 int height = tagline == nil || [tagline length] == 0 ? -17 : 0;
3027 if ([package hasMode] || [package half])
3036 /* Section Cell {{{ */
3037 @interface SectionCell : UISimpleTableCell {
3042 _UISwitchSlider *switch_;
3047 - (void) setSection:(Section *)section editing:(BOOL)editing;
3051 @implementation SectionCell
3053 - (void) clearSection {
3054 if (section_ != nil) {
3064 if (count_ != nil) {
3071 [self clearSection];
3078 if ((self = [super init]) != nil) {
3079 icon_ = [[UIImage applicationImageNamed:@"folder.png"] retain];
3081 switch_ = [[_UISwitchSlider alloc] initWithFrame:CGRectMake(218, 9, 60, 25)];
3082 [switch_ addTarget:self action:@selector(onSwitch:) forEvents:kUIControlEventMouseUpInside];
3086 - (void) onSwitch:(id)sender {
3087 NSMutableDictionary *metadata = [Sections_ objectForKey:section_];
3088 if (metadata == nil) {
3089 metadata = [NSMutableDictionary dictionaryWithCapacity:2];
3090 [Sections_ setObject:metadata forKey:section_];
3094 [metadata setObject:[NSNumber numberWithBool:([switch_ value] == 0)] forKey:@"Hidden"];
3097 - (void) setSection:(Section *)section editing:(BOOL)editing {
3098 if (editing != editing_) {
3100 [switch_ removeFromSuperview];
3102 [self addSubview:switch_];
3106 [self clearSection];
3108 if (section == nil) {
3109 name_ = [@"All Packages" retain];
3112 section_ = [section name];
3113 if (section_ != nil)
3114 section_ = [section_ retain];
3115 name_ = [(section_ == nil ? @"(No Section)" : section_) retain];
3116 count_ = [[NSString stringWithFormat:@"%d", [section count]] retain];
3119 [switch_ setValue:isSectionVisible(section_) animated:NO];
3123 - (void) drawContentInRect:(CGRect)rect selected:(BOOL)selected {
3124 [icon_ drawInRect:CGRectMake(8, 7, 32, 32)];
3131 [name_ drawAtPoint:CGPointMake(48, 9) forWidth:(editing_ ? 164 : 250) withFont:Font22Bold_ ellipsis:2];
3133 CGSize size = [count_ sizeWithFont:Font14_];
3137 [count_ drawAtPoint:CGPointMake(12 + (29 - size.width) / 2, 15) withFont:Font12Bold_];
3139 [super drawContentInRect:rect selected:selected];
3145 /* File Table {{{ */
3146 @interface FileTable : RVPage {
3147 _transient Database *database_;
3150 NSMutableArray *files_;
3154 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3155 - (void) setPackage:(Package *)package;
3159 @implementation FileTable
3162 if (package_ != nil)
3171 - (int) numberOfRowsInTable:(UITable *)table {
3172 return files_ == nil ? 0 : [files_ count];
3175 - (float) table:(UITable *)table heightForRow:(int)row {
3179 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
3180 if (reusing == nil) {
3181 reusing = [[[UIImageAndTextTableCell alloc] init] autorelease];
3182 UIFont *font = [UIFont systemFontOfSize:16];
3183 [[(UIImageAndTextTableCell *)reusing titleTextLabel] setFont:font];
3185 [(UIImageAndTextTableCell *)reusing setTitle:[files_ objectAtIndex:row]];
3189 - (BOOL) table:(UITable *)table canSelectRow:(int)row {
3193 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3194 if ((self = [super initWithBook:book]) != nil) {
3195 database_ = database;
3197 files_ = [[NSMutableArray arrayWithCapacity:32] retain];
3199 list_ = [[UITable alloc] initWithFrame:[self bounds]];
3200 [self addSubview:list_];
3202 UITableColumn *column = [[[UITableColumn alloc]
3203 initWithTitle:@"Name"
3205 width:[self frame].size.width
3208 [list_ setDataSource:self];
3209 [list_ setSeparatorStyle:1];
3210 [list_ addTableColumn:column];
3211 [list_ setDelegate:self];
3212 [list_ setReusesTableCells:YES];
3216 - (void) setPackage:(Package *)package {
3217 if (package_ != nil) {
3218 [package_ autorelease];
3227 [files_ removeAllObjects];
3229 if (package != nil) {
3230 package_ = [package retain];
3231 name_ = [[package id] retain];
3233 NSString *path = [NSString stringWithFormat:@"/var/lib/dpkg/info/%@.list", name_];
3236 std::ifstream fin([path UTF8String]);
3238 while (std::getline(fin, line))
3239 [files_ addObject:[NSString stringWithUTF8String:line.c_str()]];
3242 if ([files_ count] != 0) {
3243 if ([[files_ objectAtIndex:0] isEqualToString:@"/."])
3244 [files_ removeObjectAtIndex:0];
3245 [files_ sortUsingSelector:@selector(compareByPath:)];
3247 NSMutableArray *stack = [NSMutableArray arrayWithCapacity:8];
3248 [stack addObject:@"/"];
3250 for (int i(0), e([files_ count]); i != e; ++i) {
3251 NSString *file = [files_ objectAtIndex:i];
3252 while (![file hasPrefix:[stack lastObject]])
3253 [stack removeLastObject];
3254 NSString *directory = [stack lastObject];
3255 [stack addObject:[file stringByAppendingString:@"/"]];
3256 [files_ replaceObjectAtIndex:i withObject:[NSString stringWithFormat:@"%*s%@",
3257 ([stack count] - 2) * 3, "",
3258 [file substringFromIndex:[directory length]]
3267 - (void) resetViewAnimated:(BOOL)animated {
3268 [list_ resetViewAnimated:animated];
3271 - (void) reloadData {
3272 [self setPackage:[database_ packageWithName:name_]];
3273 [self reloadButtons];
3276 - (NSString *) title {
3277 return @"Installed Files";
3280 - (NSString *) backButtonTitle {
3286 /* Package View {{{ */
3287 @interface PackageView : BrowserView {
3290 NSMutableArray *buttons_;
3293 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3294 - (void) setPackage:(Package *)package;
3298 @implementation PackageView
3301 if (package_ != nil)
3309 - (void) _clickButtonWithName:(NSString *)name {
3310 if ([name isEqualToString:@"Install"])
3311 [delegate_ installPackage:package_];
3312 else if ([name isEqualToString:@"Reinstall"])
3313 [delegate_ installPackage:package_];
3314 else if ([name isEqualToString:@"Remove"])
3315 [delegate_ removePackage:package_];
3316 else if ([name isEqualToString:@"Upgrade"])
3317 [delegate_ installPackage:package_];
3318 else _assert(false);
3321 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
3322 int count = [buttons_ count];
3323 _assert(count != 0);
3324 _assert(button <= count + 1);
3326 if (count != button - 1)
3327 [self _clickButtonWithName:[buttons_ objectAtIndex:(button - 1)]];
3332 #include "internals.h"
3334 - (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
3335 [[frame windowObject] evaluateWebScript:@"document.base.target = '_top'"];
3336 return [super webView:sender didFinishLoadForFrame:frame];
3339 - (void) webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame {
3340 [window setValue:package_ forKey:@"package"];
3343 - (void) _rightButtonClicked {
3344 /*[super _rightButtonClicked];
3347 int count = [buttons_ count];
3348 _assert(count != 0);
3351 [self _clickButtonWithName:[buttons_ objectAtIndex:0]];
3353 NSMutableArray *buttons = [NSMutableArray arrayWithCapacity:(count + 1)];
3354 [buttons addObjectsFromArray:buttons_];
3355 [buttons addObject:@"Cancel"];
3357 [delegate_ slideUp:[[[UIActionSheet alloc]
3360 defaultButtonIndex:2
3367 - (NSString *) _rightButtonTitle {
3368 int count = [buttons_ count];
3369 return count == 0 ? nil : count != 1 ? @"Modify" : [buttons_ objectAtIndex:0];
3372 - (NSString *) title {
3376 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3377 if ((self = [super initWithBook:book database:database]) != nil) {
3378 database_ = database;
3379 buttons_ = [[NSMutableArray alloc] initWithCapacity:4];
3383 - (void) setPackage:(Package *)package {
3384 if (package_ != nil) {
3385 [package_ autorelease];
3394 [buttons_ removeAllObjects];
3396 if (package != nil) {
3397 package_ = [package retain];
3398 name_ = [[package id] retain];
3400 [self loadURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"package" ofType:@"html"]]];
3402 if ([package_ source] == nil);
3403 else if ([package_ upgradableAndEssential:NO])
3404 [buttons_ addObject:@"Upgrade"];
3405 else if ([package_ installed] == nil)
3406 [buttons_ addObject:@"Install"];
3408 [buttons_ addObject:@"Reinstall"];
3409 if ([package_ installed] != nil)
3410 [buttons_ addObject:@"Remove"];
3414 - (void) reloadData {
3415 [self setPackage:[database_ packageWithName:name_]];
3416 [self reloadButtons];
3421 /* Package Table {{{ */
3422 @interface PackageTable : RVPage {
3423 _transient Database *database_;
3427 NSMutableArray *packages_;
3428 NSMutableArray *sections_;
3429 UISectionList *list_;
3432 - (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object;
3434 - (void) setDelegate:(id)delegate;
3435 - (void) setObject:(id)object;
3437 - (void) reloadData;
3438 - (void) resetCursor;
3440 - (UISectionList *) list;
3442 - (void) setShouldHideHeaderInShortLists:(BOOL)hide;
3446 @implementation PackageTable
3449 [list_ setDataSource:nil];
3454 [packages_ release];
3455 [sections_ release];
3460 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
3461 return [sections_ count];
3464 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
3465 return [[sections_ objectAtIndex:section] name];
3468 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
3469 return [[sections_ objectAtIndex:section] row];
3472 - (int) numberOfRowsInTable:(UITable *)table {
3473 return [packages_ count];
3476 - (float) table:(UITable *)table heightForRow:(int)row {
3477 return [PackageCell heightForPackage:[packages_ objectAtIndex:row]];
3480 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
3482 reusing = [[[PackageCell alloc] init] autorelease];
3483 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
3487 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
3491 - (void) tableRowSelected:(NSNotification *)notification {
3492 int row = [[notification object] selectedRow];
3496 Package *package = [packages_ objectAtIndex:row];
3497 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
3498 [view setDelegate:delegate_];
3499 [view setPackage:package];
3500 [book_ pushPage:view];
3503 - (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object {
3504 if ((self = [super initWithBook:book]) != nil) {
3505 database_ = database;
3506 title_ = [title retain];
3508 object_ = object == nil ? nil : [object retain];
3510 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
3511 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
3513 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:YES];
3514 [list_ setDataSource:self];
3516 UITableColumn *column = [[[UITableColumn alloc]
3517 initWithTitle:@"Name"
3519 width:[self frame].size.width
3522 UITable *table = [list_ table];
3523 [table setSeparatorStyle:1];
3524 [table addTableColumn:column];
3525 [table setDelegate:self];
3526 [table setReusesTableCells:YES];
3528 [self addSubview:list_];
3531 [self setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
3532 [list_ setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
3536 - (void) setDelegate:(id)delegate {
3537 delegate_ = delegate;
3540 - (void) setObject:(id)object {
3546 object_ = [object retain];
3549 - (void) reloadData {
3550 NSArray *packages = [database_ packages];
3552 [packages_ removeAllObjects];
3553 [sections_ removeAllObjects];
3555 for (size_t i(0); i != [packages count]; ++i) {
3556 Package *package([packages objectAtIndex:i]);
3557 if ([package valid] && [[package performSelector:filter_ withObject:object_] boolValue])
3558 [packages_ addObject:package];
3561 Section *section = nil;
3563 for (size_t offset(0); offset != [packages_ count]; ++offset) {
3564 Package *package = [packages_ objectAtIndex:offset];
3565 NSString *name = [package index];
3567 if (section == nil || ![[section name] isEqualToString:name]) {
3568 section = [[[Section alloc] initWithName:name row:offset] autorelease];
3569 [sections_ addObject:section];
3572 [section addToCount];
3578 - (NSString *) title {
3582 - (void) resetViewAnimated:(BOOL)animated {
3583 [list_ resetViewAnimated:animated];
3586 - (void) resetCursor {
3587 [[list_ table] scrollPointVisibleAtTopLeft:CGPointMake(0, 0) animated:NO];
3590 - (UISectionList *) list {
3594 - (void) setShouldHideHeaderInShortLists:(BOOL)hide {
3595 [list_ setShouldHideHeaderInShortLists:hide];
3601 /* Add Source View {{{ */
3602 @interface AddSourceView : RVPage {
3603 _transient Database *database_;
3606 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3610 @implementation AddSourceView
3612 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3613 if ((self = [super initWithBook:book]) != nil) {
3614 database_ = database;
3620 /* Source Cell {{{ */
3621 @interface SourceCell : UITableCell {
3624 NSString *description_;
3630 - (SourceCell *) initWithSource:(Source *)source;
3634 @implementation SourceCell
3639 [description_ release];
3644 - (SourceCell *) initWithSource:(Source *)source {
3645 if ((self = [super init]) != nil) {
3647 icon_ = [UIImage applicationImageNamed:[NSString stringWithFormat:@"Sources/%@.png", [source host]]];
3649 icon_ = [UIImage applicationImageNamed:@"unknown.png"];
3650 icon_ = [icon_ retain];
3652 origin_ = [[source name] retain];
3653 label_ = [[source uri] retain];
3654 description_ = [[source description] retain];
3658 - (void) drawContentInRect:(CGRect)rect selected:(BOOL)selected {
3660 [icon_ drawInRect:CGRectMake(10, 10, 30, 30)];
3667 [origin_ drawAtPoint:CGPointMake(48, 8) forWidth:240 withFont:Font18Bold_ ellipsis:2];
3671 [label_ drawAtPoint:CGPointMake(58, 29) forWidth:225 withFont:Font12_ ellipsis:2];
3675 [description_ drawAtPoint:CGPointMake(12, 46) forWidth:280 withFont:Font14_ ellipsis:2];
3677 [super drawContentInRect:rect selected:selected];
3682 /* Source Table {{{ */
3683 @interface SourceTable : RVPage {
3684 _transient Database *database_;
3685 UISectionList *list_;
3686 NSMutableArray *sources_;
3687 UIActionSheet *alert_;
3691 UIProgressHUD *hud_;
3694 //NSURLConnection *installer_;
3695 NSURLConnection *trivial_bz2_;
3696 NSURLConnection *trivial_gz_;
3697 //NSURLConnection *automatic_;
3702 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3706 @implementation SourceTable
3708 - (void) _deallocConnection:(NSURLConnection *)connection {
3709 if (connection != nil) {
3710 [connection cancel];
3711 //[connection setDelegate:nil];
3712 [connection release];
3717 [[list_ table] setDelegate:nil];
3718 [list_ setDataSource:nil];
3727 //[self _deallocConnection:installer_];
3728 [self _deallocConnection:trivial_gz_];
3729 [self _deallocConnection:trivial_bz2_];
3730 //[self _deallocConnection:automatic_];
3737 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
3738 return offset_ == 0 ? 1 : 2;
3741 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
3742 switch (section + (offset_ == 0 ? 1 : 0)) {
3743 case 0: return @"Entered by User";
3744 case 1: return @"Installed by Packages";
3752 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
3753 switch (section + (offset_ == 0 ? 1 : 0)) {
3755 case 1: return offset_;
3763 - (int) numberOfRowsInTable:(UITable *)table {
3764 return [sources_ count];
3767 - (float) table:(UITable *)table heightForRow:(int)row {
3768 Source *source = [sources_ objectAtIndex:row];
3769 return [source description] == nil ? 56 : 73;
3772 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col {
3773 Source *source = [sources_ objectAtIndex:row];
3774 // XXX: weird warning, stupid selectors ;P
3775 return [[[SourceCell alloc] initWithSource:(id)source] autorelease];
3778 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
3782 - (BOOL) table:(UITable *)table canSelectRow:(int)row {
3786 - (void) tableRowSelected:(NSNotification*)notification {
3787 UITable *table([list_ table]);
3788 int row([table selectedRow]);
3792 Source *source = [sources_ objectAtIndex:row];
3794 PackageTable *packages = [[[PackageTable alloc]
3797 title:[source label]
3798 filter:@selector(isVisibleInSource:)
3802 [packages setDelegate:delegate_];
3804 [book_ pushPage:packages];
3807 - (BOOL) table:(UITable *)table canDeleteRow:(int)row {
3808 Source *source = [sources_ objectAtIndex:row];
3809 return [source record] != nil;
3812 - (void) table:(UITable *)table willSwipeToDeleteRow:(int)row {
3813 [[list_ table] setDeleteConfirmationRow:row];
3816 - (void) table:(UITable *)table deleteRow:(int)row {
3817 Source *source = [sources_ objectAtIndex:row];
3818 [Sources_ removeObjectForKey:[source key]];
3819 [delegate_ syncData];
3822 - (void) _endConnection:(NSURLConnection *)connection {
3823 NSURLConnection **field = NULL;
3824 if (connection == trivial_bz2_)
3825 field = &trivial_bz2_;
3826 else if (connection == trivial_gz_)
3827 field = &trivial_gz_;
3828 _assert(field != NULL);
3829 [connection release];
3833 trivial_bz2_ == nil &&
3836 [delegate_ setStatusBarShowsProgress:NO];
3839 [hud_ removeFromSuperview];
3844 [Sources_ setObject:[NSDictionary dictionaryWithObjectsAndKeys:
3847 @"./", @"Distribution",
3848 nil] forKey:[NSString stringWithFormat:@"deb:%@:./", href_]];
3850 [delegate_ syncData];
3851 } else if (error_ != nil) {
3852 UIActionSheet *sheet = [[[UIActionSheet alloc]
3853 initWithTitle:@"Verification Error"
3854 buttons:[NSArray arrayWithObjects:@"OK", nil]
3855 defaultButtonIndex:0
3860 [sheet setBodyText:[error_ localizedDescription]];
3861 [sheet popupAlertAnimated:YES];
3863 UIActionSheet *sheet = [[[UIActionSheet alloc]
3864 initWithTitle:@"Did not Find Repository"
3865 buttons:[NSArray arrayWithObjects:@"OK", nil]
3866 defaultButtonIndex:0
3871 [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."];
3872 [sheet popupAlertAnimated:YES];
3878 if (error_ != nil) {
3885 - (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response {
3886 switch ([response statusCode]) {
3892 - (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
3893 fprintf(stderr, "connection:\"%s\" didFailWithError:\"%s\"", [href_ UTF8String], [[error localizedDescription] UTF8String]);
3895 error_ = [error retain];
3896 [self _endConnection:connection];
3899 - (void) connectionDidFinishLoading:(NSURLConnection *)connection {
3900 [self _endConnection:connection];
3903 - (NSURLConnection *) _requestHRef:(NSString *)href method:(NSString *)method {
3904 NSMutableURLRequest *request = [NSMutableURLRequest
3905 requestWithURL:[NSURL URLWithString:href]
3906 cachePolicy:NSURLRequestUseProtocolCachePolicy
3907 timeoutInterval:20.0
3910 [request setHTTPMethod:method];
3912 return [[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease];
3915 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
3916 NSString *context = [sheet context];
3917 if ([context isEqualToString:@"source"])
3920 NSString *href = [[sheet textField] text];
3922 //installer_ = [[self _requestHRef:href method:@"GET"] retain];
3924 if (![href hasSuffix:@"/"])
3925 href_ = [href stringByAppendingString:@"/"];
3928 href_ = [href_ retain];
3930 trivial_bz2_ = [[self _requestHRef:[href_ stringByAppendingString:@"Packages.bz2"] method:@"HEAD"] retain];
3931 trivial_gz_ = [[self _requestHRef:[href_ stringByAppendingString:@"Packages.gz"] method:@"HEAD"] retain];
3932 //trivial_bz2_ = [[self _requestHRef:[href stringByAppendingString:@"dists/Release"] method:@"HEAD"] retain];
3936 hud_ = [delegate_ addProgressHUD];
3937 [hud_ setText:@"Verifying URL"];
3950 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3951 if ((self = [super initWithBook:book]) != nil) {
3952 database_ = database;
3953 sources_ = [[NSMutableArray arrayWithCapacity:16] retain];
3955 //list_ = [[UITable alloc] initWithFrame:[self bounds]];
3956 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:NO];
3957 [list_ setShouldHideHeaderInShortLists:NO];
3959 [self addSubview:list_];
3960 [list_ setDataSource:self];
3962 UITableColumn *column = [[UITableColumn alloc]
3963 initWithTitle:@"Name"
3965 width:[self frame].size.width
3968 UITable *table = [list_ table];
3969 [table setSeparatorStyle:1];
3970 [table addTableColumn:column];
3971 [table setDelegate:self];
3975 [self setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
3976 [list_ setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
3980 - (void) reloadData {
3982 _assert(list.ReadMainList());
3984 [sources_ removeAllObjects];
3985 [sources_ addObjectsFromArray:[database_ sources]];
3986 [sources_ sortUsingSelector:@selector(compareByNameAndType:)];
3988 int count = [sources_ count];
3989 for (offset_ = 0; offset_ != count; ++offset_) {
3990 Source *source = [sources_ objectAtIndex:offset_];
3991 if ([source record] == nil)
3998 - (void) resetViewAnimated:(BOOL)animated {
3999 [list_ resetViewAnimated:animated];
4002 - (void) _leftButtonClicked {
4003 /*[book_ pushPage:[[[AddSourceView alloc]
4008 UIActionSheet *sheet = [[[UIActionSheet alloc]
4009 initWithTitle:@"Enter Cydia/APT URL"
4010 buttons:[NSArray arrayWithObjects:@"Add Source", @"Cancel", nil]
4011 defaultButtonIndex:0
4016 [sheet addTextFieldWithValue:@"http://" label:@""];
4018 UITextInputTraits *traits = [[sheet textField] textInputTraits];
4019 [traits setAutocapitalizationType:0];
4020 [traits setKeyboardType:3];
4021 [traits setAutocorrectionType:1];
4023 [sheet popupAlertAnimated:YES];
4026 - (void) _rightButtonClicked {
4027 UITable *table = [list_ table];
4028 BOOL editing = [table isRowDeletionEnabled];
4029 [table enableRowDeletion:!editing animated:YES];
4030 [book_ reloadButtonsForPage:self];
4033 - (NSString *) title {
4037 - (NSString *) backButtonTitle {
4041 - (NSString *) leftButtonTitle {
4042 return [[list_ table] isRowDeletionEnabled] ? @"Add" : nil;
4045 - (NSString *) rightButtonTitle {
4046 return [[list_ table] isRowDeletionEnabled] ? @"Done" : @"Edit";
4049 - (UINavigationButtonStyle) rightButtonStyle {
4050 return [[list_ table] isRowDeletionEnabled] ? UINavigationButtonStyleHighlighted : UINavigationButtonStyleNormal;
4056 /* Installed View {{{ */
4057 @interface InstalledView : RVPage {
4058 _transient Database *database_;
4059 PackageTable *packages_;
4063 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4067 @implementation InstalledView
4070 [packages_ release];
4074 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4075 if ((self = [super initWithBook:book]) != nil) {
4076 database_ = database;
4078 packages_ = [[PackageTable alloc]
4082 filter:@selector(isInstalledAndVisible:)
4083 with:[NSNumber numberWithBool:YES]
4086 [self addSubview:packages_];
4088 [self setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
4089 [packages_ setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
4093 - (void) resetViewAnimated:(BOOL)animated {
4094 [packages_ resetViewAnimated:animated];
4097 - (void) reloadData {
4098 [packages_ reloadData];
4101 - (void) _rightButtonClicked {
4102 [packages_ setObject:[NSNumber numberWithBool:expert_]];
4103 [packages_ reloadData];
4105 [book_ reloadButtonsForPage:self];
4108 - (NSString *) title {
4109 return @"Installed";
4112 - (NSString *) backButtonTitle {
4116 - (NSString *) rightButtonTitle {
4117 return Role_ != nil && [Role_ isEqualToString:@"Developer"] ? nil : expert_ ? @"Expert" : @"Simple";
4120 - (UINavigationButtonStyle) rightButtonStyle {
4121 return expert_ ? UINavigationButtonStyleHighlighted : UINavigationButtonStyleNormal;
4124 - (void) setDelegate:(id)delegate {
4125 [super setDelegate:delegate];
4126 [packages_ setDelegate:delegate];
4133 @interface HomeView : BrowserView {
4138 @implementation HomeView
4140 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
4144 - (void) _leftButtonClicked {
4145 UIActionSheet *sheet = [[[UIActionSheet alloc]
4146 initWithTitle:@"About Cydia Installer"
4147 buttons:[NSArray arrayWithObjects:@"Close", nil]
4148 defaultButtonIndex:0
4154 @"Copyright (C) 2008\n"
4155 "Jay Freeman (saurik)\n"
4156 "saurik@saurik.com\n"
4157 "http://www.saurik.com/\n"
4160 "http://www.theokorigroup.com/\n"
4162 "College of Creative Studies,\n"
4163 "University of California,\n"
4165 "http://www.ccs.ucsb.edu/"
4168 [sheet popupAlertAnimated:YES];
4171 - (NSString *) leftButtonTitle {
4177 /* Manage View {{{ */
4178 @interface ManageView : BrowserView {
4183 @implementation ManageView
4185 - (NSString *) title {
4189 - (void) _leftButtonClicked {
4190 [delegate_ askForSettings];
4193 - (NSString *) leftButtonTitle {
4197 - (NSString *) _rightButtonTitle {
4204 /* Indirect Delegate {{{ */
4205 @interface IndirectDelegate : NSProxy {
4206 _transient id delegate_;
4209 - (void) setDelegate:(id)delegate;
4210 - (id) initWithDelegate:(id)delegate;
4213 @implementation IndirectDelegate
4215 - (void) setDelegate:(id)delegate {
4216 delegate_ = delegate;
4219 - (id) initWithDelegate:(id)delegate {
4220 delegate_ = delegate;
4224 - (NSMethodSignature*) methodSignatureForSelector:(SEL)sel {
4225 if (delegate_ != nil)
4226 if (NSMethodSignature *sig = [delegate_ methodSignatureForSelector:sel])
4231 - (void) forwardInvocation:(NSInvocation*)inv {
4232 SEL sel = [inv selector];
4233 if (delegate_ != nil && [delegate_ respondsToSelector:sel])
4234 [inv invokeWithTarget:delegate_];
4239 /* Browser Implementation {{{ */
4240 @implementation BrowserView
4243 WebView *webview = [webview_ webView];
4244 [webview setFrameLoadDelegate:nil];
4245 [webview setResourceLoadDelegate:nil];
4246 [webview setUIDelegate:nil];
4248 [webview_ setDelegate:nil];
4249 [webview_ setGestureDelegate:nil];
4251 /*WebFrame *frame = [webview mainFrame];
4252 [frame loadHTMLString:@"" baseURL:[NSURL URLWithString:@"http://cydia.saurik.com/"]];*/
4254 //[webview_ removeFromSuperview];
4255 //[Documents_ addObject:[webview_ autorelease]];
4258 [indirect_ setDelegate:nil];
4259 [indirect_ release];
4261 [scroller_ setDelegate:nil];
4263 [scroller_ release];
4265 [indicator_ release];
4271 - (void) loadURL:(NSURL *)url cachePolicy:(NSURLRequestCachePolicy)policy {
4272 [self loadRequest:[NSURLRequest
4275 timeoutInterval:30.0
4279 - (void) loadURL:(NSURL *)url {
4280 [self loadURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy];
4283 - (NSURLRequest *) _addHeadersToRequest:(NSURLRequest *)request {
4284 NSMutableURLRequest *copy = [request mutableCopy];
4286 [copy addValue:[NSString stringWithUTF8String:Firmware_] forHTTPHeaderField:@"X-Firmware"];
4287 [copy addValue:[NSString stringWithUTF8String:Machine_] forHTTPHeaderField:@"X-Machine"];
4288 [copy addValue:[NSString stringWithUTF8String:SerialNumber_] forHTTPHeaderField:@"X-Serial-Number"];
4291 [copy addValue:Role_ forHTTPHeaderField:@"X-Role"];
4296 - (void) loadRequest:(NSURLRequest *)request {
4298 [webview_ loadRequest:request];
4301 - (void) reloadURL {
4302 NSURL *url = [[[urls_ lastObject] retain] autorelease];
4303 [urls_ removeLastObject];
4304 [self loadURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData];
4307 - (WebView *) webView {
4308 return [webview_ webView];
4311 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame {
4312 [scroller_ setContentSize:frame.size];
4315 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old {
4316 [self view:sender didSetFrame:frame];
4319 - (void) pushPage:(RVPage *)page {
4320 [self setBackButtonTitle:title_];
4321 [page setDelegate:delegate_];
4322 [book_ pushPage:page];
4325 - (RVPage *) _pageForPackage:(NSString *)name {
4326 if (Package *package = [database_ packageWithName:name]) {
4327 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
4328 [view setPackage:package];
4331 UIActionSheet *sheet = [[[UIActionSheet alloc]
4332 initWithTitle:@"Cannot Locate Package"
4333 buttons:[NSArray arrayWithObjects:@"Close", nil]
4334 defaultButtonIndex:0
4339 [sheet setBodyText:[NSString stringWithFormat:
4340 @"The package %@ cannot be found in your current sources. I might recommend installing more sources."
4343 [sheet popupAlertAnimated:YES];
4348 - (BOOL) getSpecial:(NSString *)href {
4352 [href hasPrefix:@"http://ax.phobos.apple.com/"] ||
4353 [href hasPrefix:@"http://phobos.apple.com/"] ||
4354 [href hasPrefix:@"http://www.youtube.com/watch?"] ||
4355 [href hasPrefix:@"mailto:"] ||
4356 [href hasPrefix:@"tel:"]
4358 [delegate_ openURL:[NSURL URLWithString:href]];
4359 else if ([href isEqualToString:@"cydia://add-source"])
4360 page = [[[AddSourceView alloc] initWithBook:book_ database:database_] autorelease];
4361 else if ([href isEqualToString:@"cydia://sources"])
4362 page = [[[SourceTable alloc] initWithBook:book_ database:database_] autorelease];
4363 else if ([href isEqualToString:@"cydia://packages"])
4364 page = [[[InstalledView alloc] initWithBook:book_ database:database_] autorelease];
4365 else if ([href hasPrefix:@"cydia://files/"]) {
4366 NSString *name = [href substringFromIndex:14];
4368 if (Package *package = [database_ packageWithName:name]) {
4369 FileTable *files = [[[FileTable alloc] initWithBook:book_ database:database_] autorelease];
4370 [files setPackage:package];
4373 } else if ([href hasPrefix:@"apptapp://package/"])
4374 page = [self _pageForPackage:[href substringFromIndex:18]];
4375 else if ([href hasPrefix:@"cydia://package/"])
4376 page = [self _pageForPackage:[href substringFromIndex:16]];
4377 else if (![href hasPrefix:@"apptapp:"] && ![href hasPrefix:@"cydia:"])
4381 [self pushPage:page];
4385 - (void) webView:(WebView *)sender willClickElement:(id)element {
4386 if ([[element localName] isEqualToString:@"img"])
4387 do if ((element = [element parentNode]) == nil)
4389 while (![[element localName] isEqualToString:@"a"]);
4390 if (![element respondsToSelector:@selector(href)])
4392 NSString *href = [element href];
4395 [self getSpecial:href];
4398 - (NSURLRequest *) webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource {
4399 NSURL *url = [request URL];
4400 if ([self getSpecial:[url absoluteString]])
4405 [book_ pushPage:self];
4408 return [self _addHeadersToRequest:request];
4411 - (BOOL) isSpecialScheme:(NSString *)scheme {
4413 [scheme isEqualToString:@"apptapp"] ||
4414 [scheme isEqualToString:@"cydia"] ||
4415 [scheme isEqualToString:@"mailto"] ||
4416 [scheme isEqualToString:@"tel"];
4419 - (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request {
4420 if (request != nil) {
4421 NSURL *url = [request URL];
4422 NSString *scheme = [url scheme];
4423 NSString *absolute = [url absoluteString];
4425 [self isSpecialScheme:scheme] ||
4426 [absolute hasPrefix:@"http://ax.phobos.apple.com/"] ||
4427 [absolute hasPrefix:@"http://phobos.apple.com/"] ||
4428 [absolute hasPrefix:@"http://www.yahoo.com/watch?"]
4433 [self setBackButtonTitle:title_];
4435 BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease];
4436 [browser setDelegate:delegate_];
4438 if (request != nil) {
4439 [browser loadRequest:[self _addHeadersToRequest:request]];
4440 [book_ pushPage:browser];
4443 return [browser webView];
4446 - (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame {
4447 if ([frame parentFrame] != nil)
4450 title_ = [title retain];
4451 [self setTitle:title];
4454 - (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame {
4455 if ([frame parentFrame] != nil)
4460 [indicator_ startAnimation];
4461 [self reloadButtons];
4463 if (title_ != nil) {
4468 [self setTitle:@"Loading"];
4470 WebView *webview = [webview_ webView];
4471 NSString *href = [webview mainFrameURL];
4472 [urls_ addObject:[NSURL URLWithString:href]];
4474 [scroller_ scrollPointVisibleAtTopLeft:CGPointZero];
4476 CGRect webrect = [scroller_ bounds];
4477 webrect.size.height = 0;
4478 [webview_ setFrame:webrect];
4481 - (void) _finishLoading {
4484 [indicator_ stopAnimation];
4485 [self reloadButtons];
4489 - (BOOL) webView:(WebView *)sender shouldScrollToPoint:(struct CGPoint)point forFrame:(WebFrame *)frame {
4491 return [webview_ webView:sender shouldScrollToPoint:point forFrame:frame];
4494 - (void) webView:(WebView *)sender didReceiveViewportArguments:(id)arguments forFrame:(WebFrame *)frame {
4495 return [webview_ webView:sender didReceiveViewportArguments:arguments forFrame:frame];
4498 - (void) webView:(WebView *)sender needsScrollNotifications:(id)notifications forFrame:(WebFrame *)frame {
4499 return [webview_ webView:sender needsScrollNotifications:notifications forFrame:frame];
4502 - (void) webView:(WebView *)sender didCommitLoadForFrame:(WebFrame *)frame {
4503 return [webview_ webView:sender didCommitLoadForFrame:frame];
4506 - (void) webView:(WebView *)sender didReceiveDocTypeForFrame:(WebFrame *)frame {
4507 return [webview_ webView:sender didReceiveDocTypeForFrame:frame];
4510 - (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
4511 if ([frame parentFrame] == nil)
4512 [self _finishLoading];
4513 return [webview_ webView:sender didFinishLoadForFrame:frame];
4516 - (void) webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
4517 if ([frame parentFrame] != nil)
4519 [self _finishLoading];
4521 [self loadURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@?%@",
4522 [[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"error" ofType:@"html"]] absoluteString],
4523 [[error localizedDescription] stringByAddingPercentEscapes]
4527 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4528 if ((self = [super initWithBook:book]) != nil) {
4529 database_ = database;
4532 struct CGRect bounds = [self bounds];
4534 UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:bounds] autorelease];
4535 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
4536 [self addSubview:pinstripe];
4538 scroller_ = [[UIScroller alloc] initWithFrame:bounds];
4539 [self addSubview:scroller_];
4541 [scroller_ setScrollingEnabled:YES];
4542 [scroller_ setAdjustForContentSizeChange:YES];
4543 [scroller_ setClipsSubviews:YES];
4544 [scroller_ setAllowsRubberBanding:YES];
4545 [scroller_ setScrollDecelerationFactor:0.99];
4546 [scroller_ setDelegate:self];
4548 CGRect webrect = [scroller_ bounds];
4549 webrect.size.height = 0;
4551 webview_ = [Documents_ lastObject];
4552 if (webview_ != nil) {
4553 webview_ = [webview_ retain];
4554 [Documents_ removeLastObject];
4555 [webview_ setFrame:webrect];
4557 webview_ = [[UIWebDocumentView alloc] initWithFrame:webrect];
4559 [webview_ setTileSize:CGSizeMake(webrect.size.width, 500)];
4561 [webview_ setTilingEnabled:YES];
4562 [webview_ setTileMinificationFilter:kCAFilterNearest];
4563 [webview_ setAutoresizes:YES];
4565 [webview_ setViewportSize:CGSizeMake(980, -1) forDocumentTypes:0x10];
4566 [webview_ setViewportSize:CGSizeMake(320, -1) forDocumentTypes:0x2];
4567 [webview_ setViewportSize:CGSizeMake(320, -1) forDocumentTypes:0x8];
4569 [webview_ _setDocumentType:0x4];
4571 [webview_ setZoomsFocusedFormControl:YES];
4572 [webview_ setContentsPosition:7];
4573 [webview_ setEnabledGestures:0xa];
4574 [webview_ setValue:[NSNumber numberWithBool:YES] forGestureAttribute:0x4];
4575 [webview_ setValue:[NSNumber numberWithBool:YES] forGestureAttribute:0x7];
4576 [webview_ setSmoothsFonts:YES];
4579 [webview_ setDelegate:self];
4580 [webview_ setGestureDelegate:self];
4581 [scroller_ addSubview:webview_];
4583 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:kUIProgressIndicatorStyleMediumWhite];
4584 indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(281, 12, indsize.width, indsize.height)];
4585 [indicator_ setStyle:kUIProgressIndicatorStyleMediumWhite];
4587 Package *package([database_ packageWithName:@"cydia"]);
4588 NSString *application = package == nil ? @"Cydia" : [NSString
4589 stringWithFormat:@"Cydia/%@",
4593 indirect_ = [[IndirectDelegate alloc] initWithDelegate:self];
4595 WebView *webview = [webview_ webView];
4596 [webview setApplicationNameForUserAgent:application];
4597 [webview setFrameLoadDelegate:self];
4598 [webview setResourceLoadDelegate:indirect_];
4599 [webview setUIDelegate:self];
4601 //[webview _setLayoutInterval:0.5];
4603 urls_ = [[NSMutableArray alloc] initWithCapacity:16];
4605 [self setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
4606 [scroller_ setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
4607 [pinstripe setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
4611 - (void) didFinishGesturesInView:(UIView *)view forEvent:(id)event {
4612 [webview_ redrawScaledDocument];
4615 - (void) _rightButtonClicked {
4620 - (NSString *) _rightButtonTitle {
4624 - (NSString *) rightButtonTitle {
4625 return loading_ ? @"" : [self _rightButtonTitle];
4628 - (NSString *) title {
4632 - (NSString *) backButtonTitle {
4636 - (void) setPageActive:(BOOL)active {
4638 [indicator_ removeFromSuperview];
4640 [[book_ navigationBar] addSubview:indicator_];
4643 - (void) resetViewAnimated:(BOOL)animated {
4646 - (void) setPushed:(bool)pushed {
4653 @interface CYBook : RVBook <
4656 _transient Database *database_;
4657 UINavigationBar *overlay_;
4658 UIProgressIndicator *indicator_;
4659 UITextLabel *prompt_;
4660 UIProgressBar *progress_;
4661 UINavigationButton *cancel_;
4664 NSTimeInterval last_;
4667 - (id) initWithFrame:(CGRect)frame database:(Database *)database;
4673 /* Install View {{{ */
4674 @interface InstallView : RVPage {
4675 _transient Database *database_;
4676 NSMutableArray *sections_;
4677 NSMutableArray *filtered_;
4678 UITransitionView *transition_;
4684 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4685 - (void) reloadData;
4690 @implementation InstallView
4693 [list_ setDataSource:nil];
4694 [list_ setDelegate:nil];
4696 [sections_ release];
4697 [filtered_ release];
4698 [transition_ release];
4700 [accessory_ release];
4704 - (int) numberOfRowsInTable:(UITable *)table {
4705 return editing_ ? [sections_ count] : [filtered_ count] + 1;
4708 - (float) table:(UITable *)table heightForRow:(int)row {
4712 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
4714 reusing = [[[SectionCell alloc] init] autorelease];
4715 [(SectionCell *)reusing setSection:(editing_ ?
4716 [sections_ objectAtIndex:row] :
4717 (row == 0 ? nil : [filtered_ objectAtIndex:(row - 1)])
4718 ) editing:editing_];
4722 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
4726 - (BOOL) table:(UITable *)table canSelectRow:(int)row {
4730 - (void) tableRowSelected:(NSNotification *)notification {
4731 int row = [[notification object] selectedRow];
4742 title = @"All Packages";
4744 section = [filtered_ objectAtIndex:(row - 1)];
4745 name = [section name];
4751 title = @"(No Section)";
4755 PackageTable *table = [[[PackageTable alloc]
4759 filter:@selector(isVisiblyUninstalledInSection:)
4763 [table setDelegate:delegate_];
4765 [book_ pushPage:table];
4768 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4769 if ((self = [super initWithBook:book]) != nil) {
4770 database_ = database;
4772 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
4773 filtered_ = [[NSMutableArray arrayWithCapacity:16] retain];
4775 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
4776 [self addSubview:transition_];
4778 list_ = [[UITable alloc] initWithFrame:[transition_ bounds]];
4779 [transition_ transition:0 toView:list_];
4781 UITableColumn *column = [[[UITableColumn alloc]
4782 initWithTitle:@"Name"
4784 width:[self frame].size.width
4787 [list_ setDataSource:self];
4788 [list_ setSeparatorStyle:1];
4789 [list_ addTableColumn:column];
4790 [list_ setDelegate:self];
4791 [list_ setReusesTableCells:YES];
4795 [self setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
4796 [list_ setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
4800 - (void) reloadData {
4801 NSArray *packages = [database_ packages];
4803 [sections_ removeAllObjects];
4804 [filtered_ removeAllObjects];
4806 NSMutableArray *filtered = [NSMutableArray arrayWithCapacity:[packages count]];
4807 NSMutableDictionary *sections = [NSMutableDictionary dictionaryWithCapacity:32];
4809 for (size_t i(0); i != [packages count]; ++i) {
4810 Package *package([packages objectAtIndex:i]);
4811 NSString *name([package section]);
4814 Section *section([sections objectForKey:name]);
4815 if (section == nil) {
4816 section = [[[Section alloc] initWithName:name] autorelease];
4817 [sections setObject:section forKey:name];
4821 if ([package valid] && [package installed] == nil && [package visible])
4822 [filtered addObject:package];
4825 [sections_ addObjectsFromArray:[sections allValues]];
4826 [sections_ sortUsingSelector:@selector(compareByName:)];
4828 [filtered sortUsingSelector:@selector(compareBySection:)];
4830 Section *section = nil;
4831 for (size_t offset = 0, count = [filtered count]; offset != count; ++offset) {
4832 Package *package = [filtered objectAtIndex:offset];
4833 NSString *name = [package section];
4835 if (section == nil || name != nil && ![[section name] isEqualToString:name]) {
4836 section = name == nil ?
4837 [[[Section alloc] initWithName:nil] autorelease] :
4838 [sections objectForKey:name];
4839 [filtered_ addObject:section];
4842 [section addToCount];
4848 - (void) resetView {
4850 [self _rightButtonClicked];
4853 - (void) resetViewAnimated:(BOOL)animated {
4854 [list_ resetViewAnimated:animated];
4857 - (void) _rightButtonClicked {
4858 if ((editing_ = !editing_))
4861 [delegate_ updateData];
4864 [book_ setTitle:[self title] forPage:self];
4865 [book_ reloadButtonsForPage:self];
4868 - (NSString *) title {
4869 return editing_ ? @"Section Visibility" : @"Install by Section";
4872 - (NSString *) backButtonTitle {
4876 - (NSString *) rightButtonTitle {
4877 return [sections_ count] == 0 ? nil : editing_ ? @"Done" : @"Edit";
4880 - (UINavigationButtonStyle) rightButtonStyle {
4881 return editing_ ? UINavigationButtonStyleHighlighted : UINavigationButtonStyleNormal;
4884 - (UIView *) accessoryView {
4890 /* Changes View {{{ */
4891 @interface ChangesView : RVPage {
4892 _transient Database *database_;
4893 NSMutableArray *packages_;
4894 NSMutableArray *sections_;
4895 UISectionList *list_;
4899 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4900 - (void) reloadData;
4904 @implementation ChangesView
4907 [[list_ table] setDelegate:nil];
4908 [list_ setDataSource:nil];
4910 [packages_ release];
4911 [sections_ release];
4916 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
4917 return [sections_ count];
4920 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
4921 return [[sections_ objectAtIndex:section] name];
4924 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
4925 return [[sections_ objectAtIndex:section] row];
4928 - (int) numberOfRowsInTable:(UITable *)table {
4929 return [packages_ count];
4932 - (float) table:(UITable *)table heightForRow:(int)row {
4933 return [PackageCell heightForPackage:[packages_ objectAtIndex:row]];
4936 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
4938 reusing = [[[PackageCell alloc] init] autorelease];
4939 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
4943 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
4947 - (void) tableRowSelected:(NSNotification *)notification {
4948 int row = [[notification object] selectedRow];
4951 Package *package = [packages_ objectAtIndex:row];
4952 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
4953 [view setDelegate:delegate_];
4954 [view setPackage:package];
4955 [book_ pushPage:view];
4958 - (void) _leftButtonClicked {
4959 [(CYBook *)book_ update];
4960 [self reloadButtons];
4963 - (void) _rightButtonClicked {
4964 [delegate_ distUpgrade];
4967 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4968 if ((self = [super initWithBook:book]) != nil) {
4969 database_ = database;
4971 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
4972 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
4974 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:NO];
4975 [self addSubview:list_];
4977 [list_ setShouldHideHeaderInShortLists:NO];
4978 [list_ setDataSource:self];
4979 //[list_ setSectionListStyle:1];
4981 UITableColumn *column = [[[UITableColumn alloc]
4982 initWithTitle:@"Name"
4984 width:[self frame].size.width
4987 UITable *table = [list_ table];
4988 [table setSeparatorStyle:1];
4989 [table addTableColumn:column];
4990 [table setDelegate:self];
4991 [table setReusesTableCells:YES];
4995 [self setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
4996 [list_ setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
5000 - (void) reloadData {
5001 NSArray *packages = [database_ packages];
5003 [packages_ removeAllObjects];
5004 [sections_ removeAllObjects];
5006 for (size_t i(0); i != [packages count]; ++i) {
5007 Package *package([packages objectAtIndex:i]);
5010 [package installed] == nil && [package valid] && [package visible] ||
5011 [package upgradableAndEssential:NO]
5013 [packages_ addObject:package];
5016 [packages_ sortUsingSelector:@selector(compareForChanges:)];
5018 Section *upgradable = [[[Section alloc] initWithName:@"Available Upgrades"] autorelease];
5019 Section *section = nil;
5022 bool unseens = false;
5024 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, Locale_, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
5026 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
5027 Package *package = [packages_ objectAtIndex:offset];
5029 if ([package upgradableAndEssential:YES]) {
5031 [upgradable addToCount];
5034 NSDate *seen = [package seen];
5039 name = [@"n/a ?" retain];
5041 name = (NSString *) CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen);
5044 if (section == nil || ![[section name] isEqualToString:name]) {
5045 section = [[[Section alloc] initWithName:name row:offset] autorelease];
5046 [sections_ addObject:section];
5050 [section addToCount];
5054 CFRelease(formatter);
5057 Section *last = [sections_ lastObject];
5058 size_t count = [last count];
5059 [packages_ removeObjectsInRange:NSMakeRange([packages_ count] - count, count)];
5060 [sections_ removeLastObject];
5064 [sections_ insertObject:upgradable atIndex:0];
5067 [self reloadButtons];
5070 - (void) resetViewAnimated:(BOOL)animated {
5071 [list_ resetViewAnimated:animated];
5074 - (NSString *) leftButtonTitle {
5075 return [(CYBook *)book_ updating] ? nil : @"Refresh";
5078 - (NSString *) rightButtonTitle {
5079 return upgrades_ == 0 ? nil : [NSString stringWithFormat:@"Upgrade (%u)", upgrades_];
5082 - (NSString *) title {
5088 /* Search View {{{ */
5089 @protocol SearchViewDelegate
5090 - (void) showKeyboard:(BOOL)show;
5093 @interface SearchView : RVPage {
5095 UISearchField *field_;
5096 UITransitionView *transition_;
5097 PackageTable *table_;
5098 UIPreferencesTable *advanced_;
5104 - (id) initWithBook:(RVBook *)book database:(Database *)database;
5105 - (void) reloadData;
5109 @implementation SearchView
5113 [[field_ textTraits] setEditingDelegate:nil];
5115 [field_ setDelegate:nil];
5117 [accessory_ release];
5119 [transition_ release];
5121 [advanced_ release];
5126 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
5130 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
5132 case 0: return @"Advanced Search (Coming Soon!)";
5134 default: _assert(false);
5138 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
5142 default: _assert(false);
5146 - (void) _showKeyboard:(BOOL)show {
5147 CGSize keysize = [UIKeyboard defaultSize];
5148 CGRect keydown = [book_ pageBounds];
5149 CGRect keyup = keydown;
5150 keyup.size.height -= keysize.height - ButtonBarHeight_;
5152 float delay = KeyboardTime_ * ButtonBarHeight_ / keysize.height;
5154 UIFrameAnimation *animation = [[[UIFrameAnimation alloc] initWithTarget:[table_ list]] autorelease];
5155 [animation setSignificantRectFields:8];
5158 [animation setStartFrame:keydown];
5159 [animation setEndFrame:keyup];
5161 [animation setStartFrame:keyup];
5162 [animation setEndFrame:keydown];
5165 UIAnimator *animator = [UIAnimator sharedAnimator];
5168 addAnimations:[NSArray arrayWithObjects:animation, nil]
5169 withDuration:(KeyboardTime_ - delay)
5174 [animator performSelector:@selector(startAnimation:) withObject:animation afterDelay:delay];
5177 [delegate_ showKeyboard:show];
5181 - (void) textFieldDidBecomeFirstResponder:(UITextField *)field {
5182 [self _showKeyboard:YES];
5185 - (void) textFieldDidResignFirstResponder:(UITextField *)field {
5186 [self _showKeyboard:NO];
5189 - (void) keyboardInputChanged:(UIFieldEditor *)editor {
5191 NSString *text([field_ text]);
5192 [field_ setClearButtonStyle:(text == nil || [text length] == 0 ? 0 : 2)];
5198 - (void) textFieldClearButtonPressed:(UITextField *)field {
5202 - (void) keyboardInputShouldDelete:(id)input {
5206 - (BOOL) keyboardInput:(id)input shouldInsertText:(NSString *)text isMarkedText:(int)marked {
5207 if ([text length] != 1 || [text characterAtIndex:0] != '\n') {
5211 [field_ resignFirstResponder];
5216 - (id) initWithBook:(RVBook *)book database:(Database *)database {
5217 if ((self = [super initWithBook:book]) != nil) {
5218 CGRect pageBounds = [book_ pageBounds];
5220 /*UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:pageBounds] autorelease];
5221 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
5222 [self addSubview:pinstripe];*/
5224 transition_ = [[UITransitionView alloc] initWithFrame:pageBounds];
5225 [self addSubview:transition_];
5227 advanced_ = [[UIPreferencesTable alloc] initWithFrame:pageBounds];
5229 [advanced_ setReusesTableCells:YES];
5230 [advanced_ setDataSource:self];
5231 [advanced_ reloadData];
5233 dimmed_ = [[UIView alloc] initWithFrame:pageBounds];
5234 CGColor dimmed(space_, 0, 0, 0, 0.5);
5235 [dimmed_ setBackgroundColor:[UIColor colorWithCGColor:dimmed]];
5237 table_ = [[PackageTable alloc]
5241 filter:@selector(isUnfilteredAndSearchedForBy:)
5245 [table_ setShouldHideHeaderInShortLists:NO];
5246 [transition_ transition:0 toView:table_];
5255 area.origin.x = /*cnfrect.origin.x + cnfrect.size.width + 4 +*/ 10;
5262 [self bounds].size.width - area.origin.x - 18;
5264 area.size.height = [UISearchField defaultHeight];
5266 field_ = [[UISearchField alloc] initWithFrame:area];
5268 UIFont *font = [UIFont systemFontOfSize:16];
5269 [field_ setFont:font];
5271 [field_ setPlaceholder:@"Package Names & Descriptions"];
5272 [field_ setDelegate:self];
5274 [field_ setPaddingTop:3];
5276 UITextInputTraits *traits = [field_ textInputTraits];
5277 [traits setAutocapitalizationType:0];
5278 [traits setAutocorrectionType:1];
5279 [traits setReturnKeyType:6];
5281 CGRect accrect = {{0, 6}, {6 + cnfrect.size.width + 6 + area.size.width + 6, area.size.height}};
5283 accessory_ = [[UIView alloc] initWithFrame:accrect];
5284 [accessory_ addSubview:field_];
5286 /*UIPushButton *configure = [[[UIPushButton alloc] initWithFrame:cnfrect] autorelease];
5287 [configure setShowPressFeedback:YES];
5288 [configure setImage:[UIImage applicationImageNamed:@"advanced.png"]];
5289 [configure addTarget:self action:@selector(configurePushed) forEvents:1];
5290 [accessory_ addSubview:configure];*/
5292 [self setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
5293 [table_ setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
5299 LKAnimation *animation = [LKTransition animation];
5300 [animation setType:@"oglFlip"];
5301 [animation setTimingFunction:[LKTimingFunction functionWithName:@"easeInEaseOut"]];
5302 [animation setFillMode:@"extended"];
5303 [animation setTransitionFlags:3];
5304 [animation setDuration:10];
5305 [animation setSpeed:0.35];
5306 [animation setSubtype:(flipped_ ? @"fromLeft" : @"fromRight")];
5307 [[transition_ _layer] addAnimation:animation forKey:0];
5308 [transition_ transition:0 toView:(flipped_ ? (UIView *) table_ : (UIView *) advanced_)];
5309 flipped_ = !flipped_;
5313 - (void) configurePushed {
5314 [field_ resignFirstResponder];
5318 - (void) resetViewAnimated:(BOOL)animated {
5321 [table_ resetViewAnimated:animated];
5324 - (void) reloadData {
5327 [table_ setObject:[field_ text]];
5328 [table_ reloadData];
5329 [table_ resetCursor];
5332 - (UIView *) accessoryView {
5336 - (NSString *) title {
5340 - (NSString *) backButtonTitle {
5344 - (void) setDelegate:(id)delegate {
5345 [table_ setDelegate:delegate];
5346 [super setDelegate:delegate];
5352 @implementation CYBook
5356 [indicator_ release];
5358 [progress_ release];
5363 - (NSString *) getTitleForPage:(RVPage *)page {
5364 return Simplify([super getTitleForPage:page]);
5372 [UIView beginAnimations:nil context:NULL];
5374 CGRect ovrframe = [overlay_ frame];
5375 ovrframe.origin.y = 0;
5376 [overlay_ setFrame:ovrframe];
5378 CGRect barframe = [navbar_ frame];
5379 barframe.origin.y += ovrframe.size.height;
5380 [navbar_ setFrame:barframe];
5382 CGRect trnframe = [transition_ frame];
5383 trnframe.origin.y += ovrframe.size.height;
5384 trnframe.size.height -= ovrframe.size.height;
5385 [transition_ setFrame:trnframe];
5387 [UIView endAnimations];
5389 [indicator_ startAnimation];
5390 [prompt_ setText:@"Updating Database"];
5391 [progress_ setProgress:0];
5394 last_ = [NSDate timeIntervalSinceReferenceDate];
5396 [overlay_ addSubview:cancel_];
5399 detachNewThreadSelector:@selector(_update)
5408 [indicator_ stopAnimation];
5410 [UIView beginAnimations:nil context:NULL];
5412 CGRect ovrframe = [overlay_ frame];
5413 ovrframe.origin.y = -ovrframe.size.height;
5414 [overlay_ setFrame:ovrframe];
5416 CGRect barframe = [navbar_ frame];
5417 barframe.origin.y -= ovrframe.size.height;
5418 [navbar_ setFrame:barframe];
5420 CGRect trnframe = [transition_ frame];
5421 trnframe.origin.y -= ovrframe.size.height;
5422 trnframe.size.height += ovrframe.size.height;
5423 [transition_ setFrame:trnframe];
5425 [UIView commitAnimations];
5427 [delegate_ performSelector:@selector(reloadData) withObject:nil afterDelay:0];
5430 - (id) initWithFrame:(CGRect)frame database:(Database *)database {
5431 if ((self = [super initWithFrame:frame]) != nil) {
5432 database_ = database;
5434 CGRect ovrrect = [navbar_ bounds];
5435 ovrrect.size.height = [UINavigationBar defaultSize].height;
5436 ovrrect.origin.y = -ovrrect.size.height;
5438 overlay_ = [[UINavigationBar alloc] initWithFrame:ovrrect];
5439 [self addSubview:overlay_];
5441 [overlay_ setBarStyle:1];
5442 int barstyle = [overlay_ _barStyle:NO];
5443 bool ugly = barstyle == 0;
5445 UIProgressIndicatorStyle style = ugly ?
5446 kUIProgressIndicatorStyleMediumBrown :
5447 kUIProgressIndicatorStyleMediumWhite;
5449 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:style];
5450 unsigned indoffset = (ovrrect.size.height - indsize.height) / 2;
5451 CGRect indrect = {{indoffset, indoffset}, indsize};
5453 indicator_ = [[UIProgressIndicator alloc] initWithFrame:indrect];
5454 [indicator_ setStyle:style];
5455 [overlay_ addSubview:indicator_];
5457 CGSize prmsize = {215, indsize.height + 4};
5460 indoffset * 2 + indsize.width,
5464 unsigned(ovrrect.size.height - prmsize.height) / 2
5467 UIFont *font = [UIFont systemFontOfSize:15];
5469 prompt_ = [[UITextLabel alloc] initWithFrame:prmrect];
5471 [prompt_ setColor:[UIColor colorWithCGColor:(ugly ? Blueish_ : Off_)]];
5472 [prompt_ setBackgroundColor:[UIColor clearColor]];
5473 [prompt_ setFont:font];
5475 [overlay_ addSubview:prompt_];
5477 CGSize prgsize = {75, 100};
5480 ovrrect.size.width - prgsize.width - 10,
5481 (ovrrect.size.height - prgsize.height) / 2
5484 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
5485 [progress_ setStyle:0];
5486 [overlay_ addSubview:progress_];
5488 cancel_ = [[UINavigationButton alloc] initWithTitle:@"Cancel" style:UINavigationButtonStyleHighlighted];
5489 [cancel_ addTarget:self action:@selector(_onCancel) forControlEvents:UIControlEventTouchUpInside];
5491 CGRect frame = [cancel_ frame];
5492 frame.size.width = 65;
5493 frame.origin.x = ovrrect.size.width - frame.size.width - 5;
5494 frame.origin.y = (ovrrect.size.height - frame.size.height) / 2;
5495 [cancel_ setFrame:frame];
5497 [cancel_ setBarStyle:barstyle];
5501 - (void) _onCancel {
5503 [cancel_ removeFromSuperview];
5507 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5510 status.setDelegate(self);
5512 [database_ updateWithStatus:status];
5515 performSelectorOnMainThread:@selector(_update_)
5523 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id {
5524 [prompt_ setText:[NSString stringWithFormat:@"Error: %@", error]];
5527 - (void) setProgressTitle:(NSString *)title {
5529 performSelectorOnMainThread:@selector(_setProgressTitle:)
5535 - (void) setProgressPercent:(float)percent {
5537 performSelectorOnMainThread:@selector(_setProgressPercent:)
5538 withObject:[NSNumber numberWithFloat:percent]
5543 - (void) startProgress {
5546 - (void) addProgressOutput:(NSString *)output {
5548 performSelectorOnMainThread:@selector(_addProgressOutput:)
5554 - (bool) isCancelling:(size_t)received {
5555 NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate];
5556 if (received_ != received) {
5557 received_ = received;
5559 } else if (now - last_ > 15)
5564 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
5568 - (void) _setProgressTitle:(NSString *)title {
5569 [prompt_ setText:title];
5572 - (void) _setProgressPercent:(NSNumber *)percent {
5573 [progress_ setProgress:[percent floatValue]];
5576 - (void) _addProgressOutput:(NSString *)output {
5581 @interface Cydia : UIApplication <
5582 ConfirmationViewDelegate,
5583 ProgressViewDelegate,
5592 UIToolbar *buttonbar_;
5594 ConfirmationView *confirm_;
5596 NSMutableArray *essential_;
5597 NSMutableArray *broken_;
5599 Database *database_;
5600 ProgressView *progress_;
5604 UIKeyboard *keyboard_;
5605 UIProgressHUD *hud_;
5607 InstallView *install_;
5608 ChangesView *changes_;
5609 ManageView *manage_;
5610 SearchView *search_;
5615 @implementation Cydia
5618 if ([broken_ count] != 0) {
5619 int count = [broken_ count];
5621 UIActionSheet *sheet = [[[UIActionSheet alloc]
5622 initWithTitle:[NSString stringWithFormat:@"%d Half-Installed Package%@", count, (count == 1 ? @"" : @"s")]
5623 buttons:[NSArray arrayWithObjects:
5625 @"Ignore (Temporary)",
5627 defaultButtonIndex:0
5632 [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."];
5633 [sheet popupAlertAnimated:YES];
5634 } else if (!Ignored_ && [essential_ count] != 0) {
5635 int count = [essential_ count];
5637 UIActionSheet *sheet = [[[UIActionSheet alloc]
5638 initWithTitle:[NSString stringWithFormat:@"%d Essential Upgrade%@", count, (count == 1 ? @"" : @"s")]
5639 buttons:[NSArray arrayWithObjects:@"Upgrade Essential", @"Ignore (Temporary)", nil]
5640 defaultButtonIndex:0
5645 [sheet setBodyText:@"One or more essential packages are currently out of date. If these upgrades are not performed you are likely to encounter errors."];
5646 [sheet popupAlertAnimated:YES];
5650 - (void) _reloadData {
5651 /*UIProgressHUD *hud = [[UIProgressHUD alloc] initWithWindow:window_];
5652 [hud setText:@"Reloading Data"];
5653 [overlay_ addSubview:hud];
5656 [database_ reloadData];
5660 [essential_ removeAllObjects];
5661 [broken_ removeAllObjects];
5663 NSArray *packages = [database_ packages];
5664 for (int i(0), e([packages count]); i != e; ++i) {
5665 Package *package = [packages objectAtIndex:i];
5667 [broken_ addObject:package];
5668 if ([package upgradableAndEssential:NO]) {
5669 if ([package essential])
5670 [essential_ addObject:package];
5676 NSString *badge([[NSNumber numberWithInt:changes] stringValue]);
5677 [buttonbar_ setBadgeValue:badge forButton:3];
5678 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
5679 [buttonbar_ setBadgeAnimated:YES forButton:3];
5680 [self setApplicationBadge:badge];
5682 [buttonbar_ setBadgeValue:nil forButton:3];
5683 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
5684 [buttonbar_ setBadgeAnimated:NO forButton:3];
5685 [self removeApplicationBadge];
5690 if ([packages count] == 0);
5699 [hud removeFromSuperview];*/
5702 - (void) _saveConfig {
5704 _assert([Metadata_ writeToFile:@"/var/lib/cydia/metadata.plist" atomically:YES] == YES);
5709 - (void) updateData {
5712 /* XXX: this is just stupid */
5714 [install_ reloadData];
5716 [changes_ reloadData];
5718 [search_ reloadData];
5728 FILE *file = fopen("/etc/apt/sources.list.d/cydia.list", "w");
5729 _assert(file != NULL);
5731 NSArray *keys = [Sources_ allKeys];
5733 for (int i(0), e([keys count]); i != e; ++i) {
5734 NSString *key = [keys objectAtIndex:i];
5735 NSDictionary *source = [Sources_ objectForKey:key];
5737 fprintf(file, "%s %s %s\n",
5738 [[source objectForKey:@"Type"] UTF8String],
5739 [[source objectForKey:@"URI"] UTF8String],
5740 [[source objectForKey:@"Distribution"] UTF8String]
5749 detachNewThreadSelector:@selector(update_)
5752 title:@"Updating Sources"
5756 - (void) reloadData {
5757 @synchronized (self) {
5758 if (confirm_ == nil)
5764 pkgProblemResolver *resolver = [database_ resolver];
5766 resolver->InstallProtect();
5767 if (!resolver->Resolve(true))
5772 [database_ prepare];
5774 if ([database_ cache]->BrokenCount() == 0)
5775 confirm_ = [[ConfirmationView alloc] initWithView:underlay_ database:database_ delegate:self];
5777 NSMutableArray *broken = [NSMutableArray arrayWithCapacity:16];
5778 NSArray *packages = [database_ packages];
5780 for (size_t i(0); i != [packages count]; ++i) {
5781 Package *package = [packages objectAtIndex:i];
5782 if ([package broken])
5783 [broken addObject:[package name]];
5786 UIActionSheet *sheet = [[[UIActionSheet alloc]
5787 initWithTitle:[NSString stringWithFormat:@"%d Broken Packages", [database_ cache]->BrokenCount()]
5788 buttons:[NSArray arrayWithObjects:@"Okay", nil]
5789 defaultButtonIndex:0
5794 [sheet setBodyText:[NSString stringWithFormat:@"The following packages have unmet dependencies:\n\n%@", [broken componentsJoinedByString:@"\n"]]];
5795 [sheet popupAlertAnimated:YES];
5801 - (void) installPackage:(Package *)package {
5802 @synchronized (self) {
5809 - (void) removePackage:(Package *)package {
5810 @synchronized (self) {
5817 - (void) distUpgrade {
5818 @synchronized (self) {
5819 [database_ upgrade];
5825 @synchronized (self) {
5833 [overlay_ removeFromSuperview];
5837 detachNewThreadSelector:@selector(perform)
5844 - (void) bootstrap_ {
5846 [database_ upgrade];
5847 [database_ prepare];
5848 [database_ perform];
5851 - (void) bootstrap {
5853 detachNewThreadSelector:@selector(bootstrap_)
5856 title:@"Bootstrap Install"
5860 - (void) progressViewIsComplete:(ProgressView *)progress {
5861 @synchronized (self) {
5864 if (confirm_ != nil) {
5865 [underlay_ addSubview:overlay_];
5866 [confirm_ removeFromSuperview];
5873 - (void) setPage:(RVPage *)page {
5874 [page resetViewAnimated:NO];
5875 [page setDelegate:self];
5876 [book_ setPage:page];
5879 - (RVPage *) _pageForURL:(NSURL *)url withClass:(Class)_class {
5880 BrowserView *browser = [[[_class alloc] initWithBook:book_ database:database_] autorelease];
5881 [browser loadURL:url];
5885 - (void) _setHomePage {
5886 [self setPage:[self _pageForURL:[NSURL URLWithString:@"http://cydia.saurik.com/"] withClass:[HomeView class]]];
5889 - (void) buttonBarItemTapped:(id)sender {
5890 unsigned tag = [sender tag];
5892 [book_ resetViewAnimated:YES];
5894 } else if (tag_ == 2 && tag != 2)
5895 [install_ resetView];
5898 case 1: [self _setHomePage]; break;
5900 case 2: [self setPage:install_]; break;
5901 case 3: [self setPage:changes_]; break;
5902 case 4: [self setPage:manage_]; break;
5903 case 5: [self setPage:search_]; break;
5905 default: _assert(false);
5911 - (void) fixSpringBoard {
5912 pid_t pid = ExecFork();
5916 if (pid_t child = fork()) {
5917 waitpid(child, NULL, 0);
5919 execlp("launchctl", "launchctl", "unload", SpringBoard_, NULL);
5920 perror("launchctl unload");
5924 execlp("launchctl", "launchctl", "load", SpringBoard_, NULL);
5925 perror("launchctl load");
5930 - (void) applicationWillSuspend {
5935 [self fixSpringBoard];
5939 [super applicationWillSuspend];
5942 - (void) askForSettings {
5943 UIActionSheet *role = [[[UIActionSheet alloc]
5944 initWithTitle:@"Who Are You?"
5945 buttons:[NSArray arrayWithObjects:
5946 @"User (Graphical Only)",
5947 @"Hacker (+ Command Line)",
5948 @"Developer (No Filters)",
5950 defaultButtonIndex:-1
5955 [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."];
5956 [role popupAlertAnimated:YES];
5961 [self setStatusBarShowsProgress:NO];
5964 [hud_ removeFromSuperview];
5968 pid_t pid = ExecFork();
5970 execlp("launchctl", "launchctl", "stop", "com.apple.SpringBoard", NULL);
5971 perror("launchctl stop");
5978 [self askForSettings];
5982 overlay_ = [[UIView alloc] initWithFrame:[underlay_ bounds]];
5984 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
5985 book_ = [[CYBook alloc] initWithFrame:CGRectMake(
5986 0, 0, screenrect.size.width, screenrect.size.height - 48
5987 ) database:database_];
5989 [book_ setDelegate:self];
5991 [overlay_ addSubview:book_];
5993 NSArray *buttonitems = [NSArray arrayWithObjects:
5994 [NSDictionary dictionaryWithObjectsAndKeys:
5995 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5996 @"home-up.png", kUIButtonBarButtonInfo,
5997 @"home-dn.png", kUIButtonBarButtonSelectedInfo,
5998 [NSNumber numberWithInt:1], kUIButtonBarButtonTag,
5999 self, kUIButtonBarButtonTarget,
6000 @"Home", kUIButtonBarButtonTitle,
6001 @"0", kUIButtonBarButtonType,
6004 [NSDictionary dictionaryWithObjectsAndKeys:
6005 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
6006 @"install-up.png", kUIButtonBarButtonInfo,
6007 @"install-dn.png", kUIButtonBarButtonSelectedInfo,
6008 [NSNumber numberWithInt:2], kUIButtonBarButtonTag,
6009 self, kUIButtonBarButtonTarget,
6010 @"Sections", kUIButtonBarButtonTitle,
6011 @"0", kUIButtonBarButtonType,
6014 [NSDictionary dictionaryWithObjectsAndKeys:
6015 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
6016 @"changes-up.png", kUIButtonBarButtonInfo,
6017 @"changes-dn.png", kUIButtonBarButtonSelectedInfo,
6018 [NSNumber numberWithInt:3], kUIButtonBarButtonTag,
6019 self, kUIButtonBarButtonTarget,
6020 @"Changes", kUIButtonBarButtonTitle,
6021 @"0", kUIButtonBarButtonType,
6024 [NSDictionary dictionaryWithObjectsAndKeys:
6025 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
6026 @"manage-up.png", kUIButtonBarButtonInfo,
6027 @"manage-dn.png", kUIButtonBarButtonSelectedInfo,
6028 [NSNumber numberWithInt:4], kUIButtonBarButtonTag,
6029 self, kUIButtonBarButtonTarget,
6030 @"Manage", kUIButtonBarButtonTitle,
6031 @"0", kUIButtonBarButtonType,
6034 [NSDictionary dictionaryWithObjectsAndKeys:
6035 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
6036 @"search-up.png", kUIButtonBarButtonInfo,
6037 @"search-dn.png", kUIButtonBarButtonSelectedInfo,
6038 [NSNumber numberWithInt:5], kUIButtonBarButtonTag,
6039 self, kUIButtonBarButtonTarget,
6040 @"Search", kUIButtonBarButtonTitle,
6041 @"0", kUIButtonBarButtonType,
6045 buttonbar_ = [[UIToolbar alloc]
6047 withFrame:CGRectMake(
6048 0, screenrect.size.height - ButtonBarHeight_,
6049 screenrect.size.width, ButtonBarHeight_
6051 withItemList:buttonitems
6054 [buttonbar_ setDelegate:self];
6055 [buttonbar_ setBarStyle:1];
6056 [buttonbar_ setButtonBarTrackingMode:2];
6058 int buttons[5] = {1, 2, 3, 4, 5};
6059 [buttonbar_ registerButtonGroup:0 withButtons:buttons withCount:5];
6060 [buttonbar_ showButtonGroup:0 withDuration:0];
6062 for (int i = 0; i != 5; ++i)
6063 [[buttonbar_ viewWithTag:(i + 1)] setFrame:CGRectMake(
6064 i * 64 + 2, 1, 60, ButtonBarHeight_
6067 [buttonbar_ showSelectionForButton:1];
6068 [overlay_ addSubview:buttonbar_];
6070 [UIKeyboard initImplementationNow];
6071 CGSize keysize = [UIKeyboard defaultSize];
6072 CGRect keyrect = {{0, [overlay_ bounds].size.height}, keysize};
6073 keyboard_ = [[UIKeyboard alloc] initWithFrame:keyrect];
6074 [[UIKeyboardImpl sharedInstance] setSoundsEnabled:(Sounds_Keyboard_ ? YES : NO)];
6075 [overlay_ addSubview:keyboard_];
6077 install_ = [[InstallView alloc] initWithBook:book_ database:database_];
6078 changes_ = [[ChangesView alloc] initWithBook:book_ database:database_];
6079 search_ = [[SearchView alloc] initWithBook:book_ database:database_];
6081 manage_ = (ManageView *) [[self
6082 _pageForURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"manage" ofType:@"html"]]
6083 withClass:[ManageView class]
6087 [underlay_ addSubview:overlay_];
6094 [self _setHomePage];
6097 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
6098 NSString *context = [sheet context];
6099 if ([context isEqualToString:@"fixhalf"])
6102 @synchronized (self) {
6103 for (int i = 0, e = [broken_ count]; i != e; ++i) {
6104 Package *broken = [broken_ objectAtIndex:i];
6107 NSString *id = [broken id];
6108 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.prerm", id] UTF8String]);
6109 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.postrm", id] UTF8String]);
6110 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.preinst", id] UTF8String]);
6111 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.postinst", id] UTF8String]);
6120 [broken_ removeAllObjects];
6127 else if ([context isEqualToString:@"role"]) {
6129 case 1: Role_ = @"User"; break;
6130 case 2: Role_ = @"Hacker"; break;
6131 case 3: Role_ = @"Developer"; break;
6138 bool reset = Settings_ != nil;
6140 Settings_ = [NSMutableDictionary dictionaryWithObjectsAndKeys:
6144 [Metadata_ setObject:Settings_ forKey:@"Settings"];
6152 } else if ([context isEqualToString:@"upgrade"])
6155 @synchronized (self) {
6156 for (int i = 0, e = [essential_ count]; i != e; ++i) {
6157 Package *essential = [essential_ objectAtIndex:i];
6158 [essential install];
6177 - (void) reorganize {
6178 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
6179 system("/usr/libexec/cydia/free.sh");
6180 [self performSelectorOnMainThread:@selector(finish) withObject:nil waitUntilDone:NO];
6184 - (void) applicationSuspend:(__GSEvent *)event {
6185 if (hud_ == nil && ![progress_ isRunning])
6186 [super applicationSuspend:event];
6189 - (void) _animateSuspension:(BOOL)arg0 duration:(double)arg1 startTime:(double)arg2 scale:(float)arg3 {
6191 [super _animateSuspension:arg0 duration:arg1 startTime:arg2 scale:arg3];
6194 - (void) _setSuspended:(BOOL)value {
6196 [super _setSuspended:value];
6199 - (UIProgressHUD *) addProgressHUD {
6200 UIProgressHUD *hud = [[UIProgressHUD alloc] initWithWindow:window_];
6202 [underlay_ addSubview:hud];
6206 - (void) applicationDidFinishLaunching:(id)unused {
6207 Font12_ = [[UIFont systemFontOfSize:12] retain];
6208 Font12Bold_ = [[UIFont boldSystemFontOfSize:12] retain];
6209 Font14_ = [[UIFont systemFontOfSize:14] retain];
6210 Font18Bold_ = [[UIFont boldSystemFontOfSize:18] retain];
6211 Font22Bold_ = [[UIFont boldSystemFontOfSize:22] retain];
6213 _assert(pkgInitConfig(*_config));
6214 _assert(pkgInitSystem(*_config, _system));
6219 essential_ = [[NSMutableArray alloc] initWithCapacity:4];
6220 broken_ = [[NSMutableArray alloc] initWithCapacity:4];
6222 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
6223 window_ = [[UIWindow alloc] initWithContentRect:screenrect];
6225 [window_ orderFront:self];
6226 [window_ makeKey:self];
6227 [window_ _setHidden:NO];
6229 database_ = [[Database alloc] init];
6230 progress_ = [[ProgressView alloc] initWithFrame:[window_ bounds] database:database_ delegate:self];
6231 [database_ setDelegate:progress_];
6232 [window_ setContentView:progress_];
6234 underlay_ = [[UIView alloc] initWithFrame:[progress_ bounds]];
6235 [progress_ setContentView:underlay_];
6237 [progress_ resetView];
6240 readlink("/Applications", NULL, 0) == -1 && errno == EINVAL ||
6241 readlink("/Library/Ringtones", NULL, 0) == -1 && errno == EINVAL ||
6242 readlink("/Library/Wallpaper", NULL, 0) == -1 && errno == EINVAL ||
6243 readlink("/usr/include", NULL, 0) == -1 && errno == EINVAL ||
6244 readlink("/usr/libexec", NULL, 0) == -1 && errno == EINVAL ||
6245 readlink("/usr/share", NULL, 0) == -1 && errno == EINVAL /*||
6246 readlink("/var/lib", NULL, 0) == -1 && errno == EINVAL*/
6248 [self setIdleTimerDisabled:YES];
6250 hud_ = [self addProgressHUD];
6251 [hud_ setText:@"Reorganizing\n\nWill Automatically\nRestart When Done"];
6253 [self setStatusBarShowsProgress:YES];
6256 detachNewThreadSelector:@selector(reorganize)
6264 - (void) showKeyboard:(BOOL)show {
6265 CGSize keysize = [UIKeyboard defaultSize];
6266 CGRect keydown = {{0, [overlay_ bounds].size.height}, keysize};
6267 CGRect keyup = keydown;
6268 keyup.origin.y -= keysize.height;
6270 UIFrameAnimation *animation = [[[UIFrameAnimation alloc] initWithTarget:keyboard_] autorelease];
6271 [animation setSignificantRectFields:2];
6274 [animation setStartFrame:keydown];
6275 [animation setEndFrame:keyup];
6276 [keyboard_ activate];
6278 [animation setStartFrame:keyup];
6279 [animation setEndFrame:keydown];
6280 [keyboard_ deactivate];
6283 [[UIAnimator sharedAnimator]
6284 addAnimations:[NSArray arrayWithObjects:animation, nil]
6285 withDuration:KeyboardTime_
6290 - (void) slideUp:(UIActionSheet *)alert {
6292 [alert presentSheetFromButtonBar:buttonbar_];
6294 [alert presentSheetInView:overlay_];
6299 void AddPreferences(NSString *plist) {
6300 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
6302 NSMutableDictionary *settings = [[[NSMutableDictionary alloc] initWithContentsOfFile:plist] autorelease];
6303 _assert(settings != NULL);
6304 NSMutableArray *items = [settings objectForKey:@"items"];
6308 for (size_t i(0); i != [items count]; ++i) {
6309 NSMutableDictionary *item([items objectAtIndex:i]);
6310 NSString *label = [item objectForKey:@"label"];
6311 if (label != nil && [label isEqualToString:@"Cydia"]) {
6318 for (size_t i(0); i != [items count]; ++i) {
6319 NSDictionary *item([items objectAtIndex:i]);
6320 NSString *label = [item objectForKey:@"label"];
6321 if (label != nil && [label isEqualToString:@"General"]) {
6322 [items insertObject:[NSDictionary dictionaryWithObjectsAndKeys:
6323 @"CydiaSettings", @"bundle",
6324 @"PSLinkCell", @"cell",
6325 [NSNumber numberWithBool:YES], @"hasIcon",
6326 [NSNumber numberWithBool:YES], @"isController",
6328 nil] atIndex:(i + 1)];
6334 _assert([settings writeToFile:plist atomically:YES] == YES);
6341 id Alloc_(id self, SEL selector) {
6342 id object = alloc_(self, selector);
6343 fprintf(stderr, "[%s]A-%p\n", self->isa->name, object);
6348 id Dealloc_(id self, SEL selector) {
6349 id object = dealloc_(self, selector);
6350 fprintf(stderr, "[%s]D-%p\n", self->isa->name, object);
6354 int main(int argc, char *argv[]) {
6355 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
6357 bootstrap_ = argc > 1 && strcmp(argv[1], "--bootstrap") == 0;
6359 App_ = [[NSBundle mainBundle] bundlePath];
6360 Home_ = NSHomeDirectory();
6363 NSString *plist = [Home_ stringByAppendingString:@"/Library/Preferences/com.apple.preferences.sounds.plist"];
6364 if (NSDictionary *sounds = [NSDictionary dictionaryWithContentsOfFile:plist])
6365 if (NSNumber *keyboard = [sounds objectForKey:@"keyboard"])
6366 Sounds_Keyboard_ = [keyboard boolValue];
6372 if (unlink("/var/cache/apt/pkgcache.bin") == -1)
6373 _assert(errno == ENOENT);
6374 if (unlink("/var/cache/apt/srcpkgcache.bin") == -1)
6375 _assert(errno == ENOENT);
6377 /*Method alloc = class_getClassMethod([NSObject class], @selector(alloc));
6378 alloc_ = alloc->method_imp;
6379 alloc->method_imp = (IMP) &Alloc_;*/
6381 /*Method dealloc = class_getClassMethod([NSObject class], @selector(dealloc));
6382 dealloc_ = dealloc->method_imp;
6383 dealloc->method_imp = (IMP) &Dealloc_;*/
6385 if (NSDictionary *sysver = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]) {
6386 if (NSString *prover = [sysver valueForKey:@"ProductVersion"]) {
6387 Firmware_ = strdup([prover UTF8String]);
6388 NSArray *versions = [prover componentsSeparatedByString:@"."];
6389 int count = [versions count];
6390 Major_ = count > 0 ? [[versions objectAtIndex:0] intValue] : 0;
6391 Minor_ = count > 1 ? [[versions objectAtIndex:1] intValue] : 0;
6392 BugFix_ = count > 2 ? [[versions objectAtIndex:2] intValue] : 0;
6397 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
6398 char *machine = new char[size];
6399 sysctlbyname("hw.machine", machine, &size, NULL, 0);
6402 if (CFMutableDictionaryRef dict = IOServiceMatching("IOPlatformExpertDevice"))
6403 if (io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, dict)) {
6404 if (CFTypeRef serial = IORegistryEntryCreateCFProperty(service, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0)) {
6405 SerialNumber_ = strdup(CFStringGetCStringPtr((CFStringRef) serial, CFStringGetSystemEncoding()));
6409 IOObjectRelease(service);
6412 /*AddPreferences(@"/Applications/Preferences.app/Settings-iPhone.plist");
6413 AddPreferences(@"/Applications/Preferences.app/Settings-iPod.plist");*/
6415 if ((Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"]) == NULL)
6416 Metadata_ = [[NSMutableDictionary alloc] initWithCapacity:2];
6418 Settings_ = [Metadata_ objectForKey:@"Settings"];
6420 Packages_ = [Metadata_ objectForKey:@"Packages"];
6421 Sections_ = [Metadata_ objectForKey:@"Sections"];
6422 Sources_ = [Metadata_ objectForKey:@"Sources"];
6425 if (Settings_ != nil)
6426 Role_ = [Settings_ objectForKey:@"Role"];
6428 if (Packages_ == nil) {
6429 Packages_ = [[[NSMutableDictionary alloc] initWithCapacity:128] autorelease];
6430 [Metadata_ setObject:Packages_ forKey:@"Packages"];
6433 if (Sections_ == nil) {
6434 Sections_ = [[[NSMutableDictionary alloc] initWithCapacity:32] autorelease];
6435 [Metadata_ setObject:Sections_ forKey:@"Sections"];
6438 if (Sources_ == nil) {
6439 Sources_ = [[[NSMutableDictionary alloc] initWithCapacity:0] autorelease];
6440 [Metadata_ setObject:Sources_ forKey:@"Sources"];
6443 Documents_ = [[[NSMutableArray alloc] initWithCapacity:4] autorelease];
6445 if (access("/Library/MobileSubstrate/MobileSubstrate.dylib", F_OK) == 0)
6446 dlopen("/Library/MobileSubstrate/MobileSubstrate.dylib", RTLD_LAZY | RTLD_GLOBAL);
6448 if (access("/User", F_OK) != 0)
6449 system("/usr/libexec/cydia/firmware.sh");
6451 Locale_ = CFLocaleCopyCurrent();
6452 space_ = CGColorSpaceCreateDeviceRGB();
6454 Blue_.Set(space_, 0.2, 0.2, 1.0, 1.0);
6455 Blueish_.Set(space_, 0x19/255.f, 0x32/255.f, 0x50/255.f, 1.0);
6456 Black_.Set(space_, 0.0, 0.0, 0.0, 1.0);
6457 Off_.Set(space_, 0.9, 0.9, 0.9, 1.0);
6458 Red_.Set(space_, 1.0, 0.0, 0.0, 1.0);
6459 White_.Set(space_, 1.0, 1.0, 1.0, 1.0);
6460 Gray_.Set(space_, 0.4, 0.4, 0.4, 1.0);
6462 Finishes_ = [NSArray arrayWithObjects:@"return", @"reopen", @"restart", @"reload", @"reboot", nil];
6464 SectionMap_ = [[[NSDictionary alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Sections" ofType:@"plist"]] autorelease];
6466 int value = UIApplicationMain(argc, argv, @"Cydia", @"Cydia");
6468 CGColorSpaceRelease(space_);