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.
39 #define UITextTraits UITextInputTraits
40 #define textTraits textInputTraits
41 #define setAutoCapsType setAutocapitalizationType
42 #define setAutoCorrectionType setAutocorrectionType
43 #define setPreferredKeyboardType setKeyboardType
46 /* #include Directives {{{ */
47 #include <objc/objc.h>
48 #include <objc/runtime.h>
50 #include <CoreGraphics/CoreGraphics.h>
51 #include <GraphicsServices/GraphicsServices.h>
52 #include <Foundation/Foundation.h>
53 #include <UIKit/UIKit.h>
54 #include <WebCore/DOMHTML.h>
56 #import "BrowserView.h"
58 #import "UICaboodle.h"
60 #include <WebKit/WebFrame.h>
61 #include <WebKit/WebView.h>
66 #include <ext/stdio_filebuf.h>
68 #include <apt-pkg/acquire.h>
69 #include <apt-pkg/acquire-item.h>
70 #include <apt-pkg/algorithms.h>
71 #include <apt-pkg/cachefile.h>
72 #include <apt-pkg/clean.h>
73 #include <apt-pkg/configuration.h>
74 #include <apt-pkg/debmetaindex.h>
75 #include <apt-pkg/error.h>
76 #include <apt-pkg/init.h>
77 #include <apt-pkg/pkgrecords.h>
78 #include <apt-pkg/sourcelist.h>
79 #include <apt-pkg/sptr.h>
81 #include <sys/sysctl.h>
85 #include <mach-o/nlist.h>
96 /* iPhoneOS 2.0 Compatibility {{{ */
98 @interface UICGColor : NSObject {
101 - (id) initWithCGColor:(CGColorRef)color;
107 + (id)systemFontOfSize:(float)fp8;
108 + (id)boldSystemFontOfSize:(float)fp8;
109 - (UIFont *) fontWithSize:(CGFloat)size;
112 @interface NSObject (iPhoneOS)
113 - (CGColorRef) cgColor;
114 - (CGColorRef) CGColor;
118 @implementation NSObject (iPhoneOS)
120 - (CGColorRef) cgColor {
121 return [self CGColor];
124 - (CGColorRef) CGColor {
125 return (CGColorRef) self;
129 [[[[objc_getClass("UICGColor") alloc] initWithCGColor:[self CGColor]] autorelease] set];
134 @interface UITextView (iPhoneOS)
135 - (void) setTextSize:(float)size;
138 @implementation UITextView (iPhoneOS)
140 - (void) setTextSize:(float)size {
141 [self setFont:[[self font] fontWithSize:size]];
148 @interface UIApplication (IdleTimer)
149 - (void) setIdleTimerDisabled:(char)arg0;
154 kUIProgressIndicatorStyleMediumWhite = 1,
155 kUIProgressIndicatorStyleSmallWhite = 0,
156 kUIProgressIndicatorStyleSmallBlack = 4
157 } UIProgressIndicatorStyle;
160 kUIProgressIndicatorStyleMediumWhite = 0,
161 kUIProgressIndicatorStyleSmallWhite = 2,
162 kUIProgressIndicatorStyleSmallBlack = 3
163 } UIProgressIndicatorStyle;
167 kUIControlEventMouseDown = 1 << 0,
168 kUIControlEventMouseMovedInside = 1 << 2, // mouse moved inside control target
169 kUIControlEventMouseMovedOutside = 1 << 3, // mouse moved outside control target
170 kUIControlEventMouseUpInside = 1 << 6, // mouse up inside control target
171 kUIControlEventMouseUpOutside = 1 << 7, // mouse up outside control target
172 kUIControlAllEvents = (kUIControlEventMouseDown | kUIControlEventMouseMovedInside | kUIControlEventMouseMovedOutside | kUIControlEventMouseUpInside | kUIControlEventMouseUpOutside)
173 } UIControlEventMasks;
175 @interface NSString (UIKit)
176 - (NSString *) stringByAddingPercentEscapes;
177 - (NSString *) stringByReplacingCharacter:(unsigned short)arg0 withCharacter:(unsigned short)arg1;
180 @interface NSString (Cydia)
181 + (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length;
182 - (NSComparisonResult) compareByPath:(NSString *)other;
185 @implementation NSString (Cydia)
187 + (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length {
188 char data[length + 1];
189 memcpy(data, bytes, length);
191 return [NSString stringWithUTF8String:data];
194 - (NSComparisonResult) compareByPath:(NSString *)other {
195 NSString *prefix = [self commonPrefixWithString:other options:0];
196 size_t length = [prefix length];
198 NSRange lrange = NSMakeRange(length, [self length] - length);
199 NSRange rrange = NSMakeRange(length, [other length] - length);
201 lrange = [self rangeOfString:@"/" options:0 range:lrange];
202 rrange = [other rangeOfString:@"/" options:0 range:rrange];
204 NSComparisonResult value;
206 if (lrange.location == NSNotFound && rrange.location == NSNotFound)
207 value = NSOrderedSame;
208 else if (lrange.location == NSNotFound)
209 value = NSOrderedAscending;
210 else if (rrange.location == NSNotFound)
211 value = NSOrderedDescending;
213 value = NSOrderedSame;
215 NSString *lpath = lrange.location == NSNotFound ? [self substringFromIndex:length] :
216 [self substringWithRange:NSMakeRange(length, lrange.location - length)];
217 NSString *rpath = rrange.location == NSNotFound ? [other substringFromIndex:length] :
218 [other substringWithRange:NSMakeRange(length, rrange.location - length)];
220 NSComparisonResult result = [lpath compare:rpath];
221 return result == NSOrderedSame ? value : result;
226 /* Perl-Compatible RegEx {{{ */
236 Pcre(const char *regex) :
241 code_ = pcre_compile(regex, 0, &error, &offset, NULL);
244 fprintf(stderr, "%d:%s\n", offset, error);
248 pcre_fullinfo(code_, study_, PCRE_INFO_CAPTURECOUNT, &capture_);
249 matches_ = new int[(capture_ + 1) * 3];
257 NSString *operator [](size_t match) {
258 return [NSString stringWithUTF8Bytes:(data_ + matches_[match * 2]) length:(matches_[match * 2 + 1] - matches_[match * 2])];
261 bool operator ()(NSString *data) {
262 // XXX: length is for characters, not for bytes
263 return operator ()([data UTF8String], [data length]);
266 bool operator ()(const char *data, size_t size) {
268 return pcre_exec(code_, study_, data, size, 0, 0, matches_, (capture_ + 1) * 3) >= 0;
272 /* Mime Addresses {{{ */
273 @interface Address : NSObject {
279 - (NSString *) address;
281 + (Address *) addressWithString:(NSString *)string;
282 - (Address *) initWithString:(NSString *)string;
285 @implementation Address
294 - (NSString *) name {
298 - (NSString *) address {
302 + (Address *) addressWithString:(NSString *)string {
303 return [[[Address alloc] initWithString:string] autorelease];
306 + (NSArray *) _attributeKeys {
307 return [NSArray arrayWithObjects:@"address", @"name", nil];
310 - (NSArray *) attributeKeys {
311 return [[self class] _attributeKeys];
314 + (BOOL) isKeyExcludedFromWebScript:(const char *)name {
315 return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name];
318 - (Address *) initWithString:(NSString *)string {
319 if ((self = [super init]) != nil) {
320 const char *data = [string UTF8String];
321 size_t size = [string length];
323 static Pcre address_r("^\"?(.*)\"? <([^>]*)>$");
325 if (address_r(data, size)) {
326 name_ = [address_r[1] retain];
327 address_ = [address_r[2] retain];
329 name_ = [[NSString alloc]
332 encoding:kCFStringEncodingUTF8
342 /* CoreGraphics Primitives {{{ */
353 CGColor(CGColorSpaceRef space, float red, float green, float blue, float alpha) :
356 Set(space, red, green, blue, alpha);
361 CGColorRelease(color_);
368 void Set(CGColorSpaceRef space, float red, float green, float blue, float alpha) {
370 float color[] = {red, green, blue, alpha};
371 color_ = CGColorCreate(space, color);
374 operator CGColorRef() {
389 /* Right Alignment {{{ */
390 @interface UIRightTextLabel : UITextLabel {
391 float _savedRightEdgeX;
392 BOOL _sizedtofit_flag;
395 - (void) setFrame:(CGRect)frame;
396 - (void) setText:(NSString *)text;
397 - (void) realignText;
400 @implementation UIRightTextLabel
402 - (void) setFrame:(CGRect)frame {
403 [super setFrame:frame];
404 if (_sizedtofit_flag == NO) {
405 _savedRightEdgeX = frame.origin.x;
410 - (void) setText:(NSString *)text {
411 [super setText:text];
415 - (void) realignText {
416 CGRect oldFrame = [self frame];
418 _sizedtofit_flag = YES;
419 [self sizeToFit]; // shrink down size so I can right align it
421 CGRect newFrame = [self frame];
423 oldFrame.origin.x = _savedRightEdgeX - newFrame.size.width;
424 oldFrame.size.width = newFrame.size.width;
425 [super setFrame:oldFrame];
426 _sizedtofit_flag = NO;
432 extern "C" void UISetColor(CGColorRef color);
434 /* Random Global Variables {{{ */
435 static const int PulseInterval_ = 50000;
436 static const int ButtonBarHeight_ = 48;
437 static const float KeyboardTime_ = 0.3f;
438 static const char * const SpringBoard_ = "/System/Library/LaunchDaemons/com.apple.SpringBoard.plist";
440 static CGColor Blue_;
441 static CGColor Blueish_;
442 static CGColor Black_;
443 static CGColor Clear_;
445 static CGColor White_;
446 static CGColor Gray_;
448 static NSString *Home_;
449 static BOOL Sounds_Keyboard_;
451 static BOOL Advanced_;
453 static BOOL Ignored_;
455 static UIFont *Font12_;
456 static UIFont *Font12Bold_;
457 static UIFont *Font14_;
458 static UIFont *Font18Bold_;
459 static UIFont *Font22Bold_;
461 const char *Firmware_ = NULL;
462 const char *Machine_ = NULL;
463 const char *SerialNumber_ = NULL;
470 CGColorSpaceRef space_;
472 #define FW_LEAST(major, minor, bugfix) \
473 (major < Major_ || major == Major_ && \
474 (minor < Minor_ || minor == Minor_ && \
480 static NSDictionary *SectionMap_;
481 static NSMutableDictionary *Metadata_;
482 static _transient NSMutableDictionary *Settings_;
483 static _transient NSString *Role_;
484 static _transient NSMutableDictionary *Packages_;
485 static _transient NSMutableDictionary *Sections_;
486 static _transient NSMutableDictionary *Sources_;
487 static bool Changed_;
490 NSString *GetLastUpdate() {
491 NSDate *update = [Metadata_ objectForKey:@"LastUpdate"];
494 return @"Never or Unknown";
496 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, Locale_, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
497 CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) update);
499 CFRelease(formatter);
501 return [(NSString *) formatted autorelease];
504 /* Display Helpers {{{ */
505 inline float Interpolate(float begin, float end, float fraction) {
506 return (end - begin) * fraction + begin;
509 NSString *SizeString(double size) {
511 while (size > 1024) {
516 static const char *powers_[] = {"B", "kB", "MB", "GB"};
518 return [NSString stringWithFormat:@"%.1f%s", size, powers_[power]];
521 NSString *StripVersion(NSString *version) {
522 NSRange colon = [version rangeOfString:@":"];
523 if (colon.location != NSNotFound)
524 version = [version substringFromIndex:(colon.location + 1)];
528 static const float TextViewOffset_ = 22;
530 UITextView *GetTextView(NSString *value, float left, bool html) {
531 UITextView *text([[[UITextView alloc] initWithFrame:CGRectMake(left, 3, 310 - left, 1000)] autorelease]);
532 [text setEditable:NO];
533 [text setTextSize:16];
535 [text setHTML:value];
537 [text setText:value];
538 [text setEnabled:NO];
540 [text setBackgroundColor:Clear_];
542 CGRect frame = [text frame];
543 [text setFrame:frame];
544 CGRect rect = [text visibleTextRect];
545 frame.size.height = rect.size.height;
546 [text setFrame:frame];
551 NSString *Simplify(NSString *title) {
552 const char *data = [title UTF8String];
553 size_t size = [title length];
555 static Pcre square_r("^\\[(.*)\\]$");
556 if (square_r(data, size))
557 return Simplify(square_r[1]);
559 static Pcre paren_r("^\\((.*)\\)$");
560 if (paren_r(data, size))
561 return Simplify(paren_r[1]);
563 static Pcre title_r("^(.*?) \\(.*\\)$");
564 if (title_r(data, size))
565 return Simplify(title_r[1]);
571 bool isSectionVisible(NSString *section) {
572 NSDictionary *metadata = [Sections_ objectForKey:section];
573 NSNumber *hidden = metadata == nil ? nil : [metadata objectForKey:@"Hidden"];
574 return hidden == nil || ![hidden boolValue];
577 /* Delegate Prototypes {{{ */
581 @interface NSObject (ProgressDelegate)
584 @implementation NSObject(ProgressDelegate)
586 - (void) _setProgressError:(NSArray *)args {
587 [self performSelector:@selector(setProgressError:forPackage:)
588 withObject:[args objectAtIndex:0]
589 withObject:([args count] == 1 ? nil : [args objectAtIndex:1])
595 @protocol ProgressDelegate
596 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id;
597 - (void) setProgressTitle:(NSString *)title;
598 - (void) setProgressPercent:(float)percent;
599 - (void) addProgressOutput:(NSString *)output;
602 @protocol ConfigurationDelegate
603 - (void) repairWithSelector:(SEL)selector;
604 - (void) setConfigurationData:(NSString *)data;
607 @protocol CydiaDelegate
608 - (void) installPackage:(Package *)package;
609 - (void) removePackage:(Package *)package;
610 - (void) slideUp:(UIAlertSheet *)alert;
611 - (void) distUpgrade;
614 - (void) askForSettings;
615 - (UIProgressHUD *) addProgressHUD;
619 /* Status Delegation {{{ */
621 public pkgAcquireStatus
624 _transient NSObject<ProgressDelegate> *delegate_;
632 void setDelegate(id delegate) {
633 delegate_ = delegate;
636 virtual bool MediaChange(std::string media, std::string drive) {
640 virtual void IMSHit(pkgAcquire::ItemDesc &item) {
643 virtual void Fetch(pkgAcquire::ItemDesc &item) {
644 [delegate_ setProgressTitle:[NSString stringWithUTF8String:("Downloading " + item.ShortDesc).c_str()]];
647 virtual void Done(pkgAcquire::ItemDesc &item) {
650 virtual void Fail(pkgAcquire::ItemDesc &item) {
652 item.Owner->Status == pkgAcquire::Item::StatIdle ||
653 item.Owner->Status == pkgAcquire::Item::StatDone
657 [delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
658 withObject:[NSArray arrayWithObjects:[NSString stringWithUTF8String:item.Owner->ErrorText.c_str()], nil]
663 virtual bool Pulse(pkgAcquire *Owner) {
664 bool value = pkgAcquireStatus::Pulse(Owner);
667 double(CurrentBytes + CurrentItems) /
668 double(TotalBytes + TotalItems)
671 [delegate_ setProgressPercent:percent];
675 virtual void Start() {
678 virtual void Stop() {
682 /* Progress Delegation {{{ */
687 _transient id<ProgressDelegate> delegate_;
690 virtual void Update() {
691 [delegate_ setProgressTitle:[NSString stringWithUTF8String:Op.c_str()]];
692 [delegate_ setProgressPercent:(Percent / 100)];
701 void setDelegate(id delegate) {
702 delegate_ = delegate;
705 virtual void Done() {
706 [delegate_ setProgressPercent:1];
711 /* Database Interface {{{ */
712 @interface Database : NSObject {
714 pkgDepCache::Policy *policy_;
715 pkgRecords *records_;
716 pkgProblemResolver *resolver_;
717 pkgAcquire *fetcher_;
719 SPtr<pkgPackageManager> manager_;
720 pkgSourceList *list_;
722 NSMutableDictionary *sources_;
723 NSMutableArray *packages_;
725 _transient NSObject<ConfigurationDelegate, ProgressDelegate> *delegate_;
734 - (void) _readCydia:(NSNumber *)fd;
735 - (void) _readStatus:(NSNumber *)fd;
736 - (void) _readOutput:(NSNumber *)fd;
740 - (Package *) packageWithName:(NSString *)name;
743 - (pkgCacheFile &) cache;
744 - (pkgDepCache::Policy *) policy;
745 - (pkgRecords *) records;
746 - (pkgProblemResolver *) resolver;
747 - (pkgAcquire &) fetcher;
748 - (NSArray *) packages;
749 - (NSArray *) sources;
758 - (void) updateWithStatus:(Status &)status;
760 - (void) setDelegate:(id)delegate;
761 - (Source *) getSource:(const pkgCache::PkgFileIterator &)file;
765 /* Source Class {{{ */
766 @interface Source : NSObject {
767 NSString *description_;
772 NSString *distribution_;
776 NSString *defaultIcon_;
778 NSDictionary *record_;
782 - (Source *) initWithMetaIndex:(metaIndex *)index;
784 - (NSComparisonResult) compareByNameAndType:(Source *)source;
786 - (NSDictionary *) record;
790 - (NSString *) distribution;
796 - (NSString *) description;
797 - (NSString *) label;
798 - (NSString *) origin;
799 - (NSString *) version;
801 - (NSString *) defaultIcon;
805 @implementation Source
809 [distribution_ release];
812 if (description_ != nil)
813 [description_ release];
820 if (defaultIcon_ != nil)
821 [defaultIcon_ release];
828 + (NSArray *) _attributeKeys {
829 return [NSArray arrayWithObjects:@"description", @"distribution", @"host", @"key", @"label", @"name", @"origin", @"trusted", @"type", @"uri", @"version", nil];
832 - (NSArray *) attributeKeys {
833 return [[self class] _attributeKeys];
836 + (BOOL) isKeyExcludedFromWebScript:(const char *)name {
837 return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name];
840 - (Source *) initWithMetaIndex:(metaIndex *)index {
841 if ((self = [super init]) != nil) {
842 trusted_ = index->IsTrusted();
844 uri_ = [[NSString stringWithUTF8String:index->GetURI().c_str()] retain];
845 distribution_ = [[NSString stringWithUTF8String:index->GetDist().c_str()] retain];
846 type_ = [[NSString stringWithUTF8String:index->GetType()] retain];
854 debReleaseIndex *dindex(dynamic_cast<debReleaseIndex *>(index));
855 if (dindex != NULL) {
856 std::ifstream release(dindex->MetaIndexFile("Release").c_str());
858 while (std::getline(release, line)) {
859 std::string::size_type colon(line.find(':'));
860 if (colon == std::string::npos)
863 std::string name(line.substr(0, colon));
864 std::string value(line.substr(colon + 1));
865 while (!value.empty() && value[0] == ' ')
866 value = value.substr(1);
868 if (name == "Default-Icon")
869 defaultIcon_ = [[NSString stringWithUTF8String:value.c_str()] retain];
870 else if (name == "Description")
871 description_ = [[NSString stringWithUTF8String:value.c_str()] retain];
872 else if (name == "Label")
873 label_ = [[NSString stringWithUTF8String:value.c_str()] retain];
874 else if (name == "Origin")
875 origin_ = [[NSString stringWithUTF8String:value.c_str()] retain];
876 else if (name == "Version")
877 version_ = [[NSString stringWithUTF8String:value.c_str()] retain];
881 record_ = [Sources_ objectForKey:[self key]];
883 record_ = [record_ retain];
887 - (NSComparisonResult) compareByNameAndType:(Source *)source {
888 NSDictionary *lhr = [self record];
889 NSDictionary *rhr = [source record];
892 return lhr == nil ? NSOrderedDescending : NSOrderedAscending;
894 NSString *lhs = [self name];
895 NSString *rhs = [source name];
897 if ([lhs length] != 0 && [rhs length] != 0) {
898 unichar lhc = [lhs characterAtIndex:0];
899 unichar rhc = [rhs characterAtIndex:0];
901 if (isalpha(lhc) && !isalpha(rhc))
902 return NSOrderedAscending;
903 else if (!isalpha(lhc) && isalpha(rhc))
904 return NSOrderedDescending;
907 return [lhs caseInsensitiveCompare:rhs];
910 - (NSDictionary *) record {
922 - (NSString *) distribution {
923 return distribution_;
926 - (NSString *) type {
931 return [NSString stringWithFormat:@"%@:%@:%@", type_, uri_, distribution_];
934 - (NSString *) host {
935 return [[[NSURL URLWithString:[self uri]] host] lowercaseString];
938 - (NSString *) name {
939 return origin_ == nil ? [self host] : origin_;
942 - (NSString *) description {
946 - (NSString *) label {
947 return label_ == nil ? [self host] : label_;
950 - (NSString *) origin {
954 - (NSString *) version {
958 - (NSString *) defaultIcon {
964 /* Relationship Class {{{ */
965 @interface Relationship : NSObject {
976 @implementation Relationship
984 - (NSString *) type {
992 - (NSString *) name {
999 /* Package Class {{{ */
1000 NSString *Scour(const char *field, const char *begin, const char *end) {
1001 size_t i(0), l(strlen(field));
1004 const char *name = begin + i;
1005 const char *colon = name + l;
1006 const char *value = colon + 1;
1011 memcmp(name, field, l) == 0
1013 while (value != end && value[0] == ' ')
1015 const char *line = std::find(value, end, '\n');
1016 while (line != value && line[-1] == ' ')
1019 return [NSString stringWithUTF8Bytes:value length:(line - value)];
1021 begin = std::find(begin, end, '\n');
1029 @interface Package : NSObject {
1030 pkgCache::PkgIterator iterator_;
1031 _transient Database *database_;
1032 pkgCache::VerIterator version_;
1033 pkgCache::VerFileIterator file_;
1039 NSString *installed_;
1045 NSString *homepage_;
1051 NSArray *relationships_;
1054 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
1055 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
1057 - (pkgCache::PkgIterator) iterator;
1059 - (NSString *) section;
1060 - (Address *) maintainer;
1062 - (NSString *) description;
1063 - (NSString *) index;
1067 - (NSString *) latest;
1068 - (NSString *) installed;
1071 - (BOOL) upgradableAndEssential:(BOOL)essential;
1077 - (BOOL) halfConfigured;
1078 - (BOOL) halfInstalled;
1080 - (NSString *) mode;
1083 - (NSString *) name;
1084 - (NSString *) tagline;
1085 - (NSString *) icon;
1086 - (NSString *) homepage;
1087 - (Address *) author;
1089 - (NSArray *) relationships;
1091 - (Source *) source;
1092 - (NSString *) role;
1094 - (BOOL) matches:(NSString *)text;
1096 - (bool) hasSupportingRole;
1097 - (BOOL) hasTag:(NSString *)tag;
1099 - (NSComparisonResult) compareByName:(Package *)package;
1100 - (NSComparisonResult) compareBySection:(Package *)package;
1101 - (NSComparisonResult) compareBySectionAndName:(Package *)package;
1102 - (NSComparisonResult) compareForChanges:(Package *)package;
1107 - (NSNumber *) isVisiblySearchedForBy:(NSString *)search;
1108 - (NSNumber *) isInstalledAndVisible:(NSNumber *)number;
1109 - (NSNumber *) isVisiblyUninstalledInSection:(NSString *)section;
1110 - (NSNumber *) isVisibleInSource:(Source *)source;
1114 @implementation Package
1121 if (installed_ != nil)
1122 [installed_ release];
1130 if (homepage_ != nil)
1131 [homepage_ release];
1132 if (sponsor_ != nil)
1141 if (relationships_ != nil)
1142 [relationships_ release];
1147 + (NSArray *) _attributeKeys {
1148 return [NSArray arrayWithObjects:@"author", @"description", @"essential", @"homepage", @"icon", @"id", @"installed", @"latest", @"maintainer", @"name", @"section", @"size", @"source", @"sponsor", @"tagline", nil];
1151 - (NSArray *) attributeKeys {
1152 return [[self class] _attributeKeys];
1155 + (BOOL) isKeyExcludedFromWebScript:(const char *)name {
1156 return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name];
1159 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
1160 if ((self = [super init]) != nil) {
1161 iterator_ = iterator;
1162 database_ = database;
1164 version_ = [database_ policy]->GetCandidateVer(iterator_);
1165 latest_ = version_.end() ? nil : [StripVersion([NSString stringWithUTF8String:version_.VerStr()]) retain];
1167 if (!version_.end())
1168 file_ = version_.FileList();
1170 pkgCache &cache([database_ cache]);
1171 file_ = pkgCache::VerFileIterator(cache, cache.VerFileP);
1174 pkgCache::VerIterator current = iterator_.CurrentVer();
1175 installed_ = current.end() ? nil : [StripVersion([NSString stringWithUTF8String:current.VerStr()]) retain];
1177 id_ = [[[NSString stringWithUTF8String:iterator_.Name()] lowercaseString] retain];
1180 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1182 const char *begin, *end;
1183 parser->GetRec(begin, end);
1185 name_ = Scour("Name", begin, end);
1187 name_ = [name_ retain];
1188 tagline_ = [[NSString stringWithUTF8String:parser->ShortDesc().c_str()] retain];
1189 icon_ = Scour("Icon", begin, end);
1191 icon_ = [icon_ retain];
1192 homepage_ = Scour("Homepage", begin, end);
1193 if (homepage_ == nil)
1194 homepage_ = Scour("Website", begin, end);
1195 if (homepage_ != nil)
1196 homepage_ = [homepage_ retain];
1197 NSString *sponsor = Scour("Sponsor", begin, end);
1199 sponsor_ = [[Address addressWithString:sponsor] retain];
1200 NSString *author = Scour("Author", begin, end);
1202 author_ = [[Address addressWithString:author] retain];
1203 NSString *tags = Scour("Tag", begin, end);
1205 tags_ = [[tags componentsSeparatedByString:@", "] retain];
1209 for (int i(0), e([tags_ count]); i != e; ++i) {
1210 NSString *tag = [tags_ objectAtIndex:i];
1211 if ([tag hasPrefix:@"role::"]) {
1212 role_ = [[tag substringFromIndex:6] retain];
1217 NSMutableDictionary *metadata = [Packages_ objectForKey:id_];
1218 if (metadata == nil || [metadata count] == 0) {
1219 metadata = [NSMutableDictionary dictionaryWithObjectsAndKeys:
1223 [Packages_ setObject:metadata forKey:id_];
1229 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
1230 return [[[Package alloc]
1231 initWithIterator:iterator
1236 - (pkgCache::PkgIterator) iterator {
1240 - (NSString *) section {
1241 const char *section = iterator_.Section();
1242 if (section == NULL)
1245 NSString *name = [[NSString stringWithUTF8String:section] stringByReplacingCharacter:' ' withCharacter:'_'];
1248 if (NSDictionary *value = [SectionMap_ objectForKey:name])
1249 if (NSString *rename = [value objectForKey:@"Rename"]) {
1254 return [name stringByReplacingCharacter:'_' withCharacter:' '];
1257 - (Address *) maintainer {
1260 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1261 return [Address addressWithString:[NSString stringWithUTF8String:parser->Maintainer().c_str()]];
1265 return version_.end() ? 0 : version_->InstalledSize;
1268 - (NSString *) description {
1271 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1272 NSString *description([NSString stringWithUTF8String:parser->LongDesc().c_str()]);
1274 NSArray *lines = [description componentsSeparatedByString:@"\n"];
1275 NSMutableArray *trimmed = [NSMutableArray arrayWithCapacity:([lines count] - 1)];
1276 if ([lines count] < 2)
1279 NSCharacterSet *whitespace = [NSCharacterSet whitespaceCharacterSet];
1280 for (size_t i(1); i != [lines count]; ++i) {
1281 NSString *trim = [[lines objectAtIndex:i] stringByTrimmingCharactersInSet:whitespace];
1282 [trimmed addObject:trim];
1285 return [trimmed componentsJoinedByString:@"\n"];
1288 - (NSString *) index {
1289 NSString *index = [[[self name] substringToIndex:1] uppercaseString];
1290 return [index length] != 0 && isalpha([index characterAtIndex:0]) ? index : @"123";
1294 return [[Packages_ objectForKey:id_] objectForKey:@"FirstSeen"];
1297 - (NSString *) latest {
1301 - (NSString *) installed {
1306 return !version_.end();
1309 - (BOOL) upgradableAndEssential:(BOOL)essential {
1310 pkgCache::VerIterator current = iterator_.CurrentVer();
1313 return essential && [self essential];
1315 pkgCache::VerIterator candidate = [database_ policy]->GetCandidateVer(iterator_);
1316 return !candidate.end() && candidate != current;
1320 - (BOOL) essential {
1321 return (iterator_->Flags & pkgCache::Flag::Essential) == 0 ? NO : YES;
1325 return [database_ cache][iterator_].InstBroken();
1329 NSString *section = [self section];
1330 return [self hasSupportingRole] && (section == nil || isSectionVisible(section));
1334 unsigned char current = iterator_->CurrentState;
1335 return current == pkgCache::State::HalfConfigured || current == pkgCache::State::HalfInstalled;
1338 - (BOOL) halfConfigured {
1339 return iterator_->CurrentState == pkgCache::State::HalfConfigured;
1342 - (BOOL) halfInstalled {
1343 return iterator_->CurrentState == pkgCache::State::HalfInstalled;
1347 pkgDepCache::StateCache &state([database_ cache][iterator_]);
1348 return state.Mode != pkgDepCache::ModeKeep;
1351 - (NSString *) mode {
1352 pkgDepCache::StateCache &state([database_ cache][iterator_]);
1354 switch (state.Mode) {
1355 case pkgDepCache::ModeDelete:
1356 if ((state.iFlags & pkgDepCache::Purge) != 0)
1361 case pkgDepCache::ModeKeep:
1362 if ((state.iFlags & pkgDepCache::AutoKept) != 0)
1367 case pkgDepCache::ModeInstall:
1368 if ((state.iFlags & pkgDepCache::ReInstall) != 0)
1369 return @"Reinstall";
1370 else switch (state.Status) {
1372 return @"Downgrade";
1378 return @"New Install";
1391 - (NSString *) name {
1392 return name_ == nil ? id_ : name_;
1395 - (NSString *) tagline {
1399 - (NSString *) icon {
1403 - (NSString *) homepage {
1407 - (Address *) sponsor {
1411 - (Address *) author {
1415 - (NSArray *) relationships {
1416 return relationships_;
1419 - (Source *) source {
1421 source_ = file_.end() ? nil : [[database_ getSource:file_.File()] retain];
1428 - (NSString *) role {
1432 - (BOOL) matches:(NSString *)text {
1438 range = [[self id] rangeOfString:text options:NSCaseInsensitiveSearch];
1439 if (range.location != NSNotFound)
1442 range = [[self name] rangeOfString:text options:NSCaseInsensitiveSearch];
1443 if (range.location != NSNotFound)
1446 range = [[self tagline] rangeOfString:text options:NSCaseInsensitiveSearch];
1447 if (range.location != NSNotFound)
1453 - (bool) hasSupportingRole {
1456 if ([role_ isEqualToString:@"enduser"])
1458 if ([Role_ isEqualToString:@"User"])
1460 if ([role_ isEqualToString:@"hacker"])
1462 if ([Role_ isEqualToString:@"Hacker"])
1464 if ([role_ isEqualToString:@"developer"])
1466 if ([Role_ isEqualToString:@"Developer"])
1471 - (BOOL) hasTag:(NSString *)tag {
1472 return tags_ == nil ? NO : [tags_ containsObject:tag];
1475 - (NSComparisonResult) compareByName:(Package *)package {
1476 NSString *lhs = [self name];
1477 NSString *rhs = [package name];
1479 if ([lhs length] != 0 && [rhs length] != 0) {
1480 unichar lhc = [lhs characterAtIndex:0];
1481 unichar rhc = [rhs characterAtIndex:0];
1483 if (isalpha(lhc) && !isalpha(rhc))
1484 return NSOrderedAscending;
1485 else if (!isalpha(lhc) && isalpha(rhc))
1486 return NSOrderedDescending;
1489 return [lhs caseInsensitiveCompare:rhs];
1492 - (NSComparisonResult) compareBySection:(Package *)package {
1493 NSString *lhs = [self section];
1494 NSString *rhs = [package section];
1496 if (lhs == NULL && rhs != NULL)
1497 return NSOrderedAscending;
1498 else if (lhs != NULL && rhs == NULL)
1499 return NSOrderedDescending;
1500 else if (lhs != NULL && rhs != NULL) {
1501 NSComparisonResult result = [lhs caseInsensitiveCompare:rhs];
1502 if (result != NSOrderedSame)
1506 return NSOrderedSame;
1509 - (NSComparisonResult) compareBySectionAndName:(Package *)package {
1510 NSString *lhs = [self section];
1511 NSString *rhs = [package section];
1513 if (lhs == NULL && rhs != NULL)
1514 return NSOrderedAscending;
1515 else if (lhs != NULL && rhs == NULL)
1516 return NSOrderedDescending;
1517 else if (lhs != NULL && rhs != NULL) {
1518 NSComparisonResult result = [lhs compare:rhs];
1519 if (result != NSOrderedSame)
1523 return [self compareByName:package];
1526 - (NSComparisonResult) compareForChanges:(Package *)package {
1527 BOOL lhs = [self upgradableAndEssential:YES];
1528 BOOL rhs = [package upgradableAndEssential:YES];
1531 return lhs ? NSOrderedAscending : NSOrderedDescending;
1533 switch ([[self seen] compare:[package seen]]) {
1534 case NSOrderedAscending:
1535 return NSOrderedDescending;
1538 case NSOrderedDescending:
1539 return NSOrderedAscending;
1545 return [self compareByName:package];
1549 pkgProblemResolver *resolver = [database_ resolver];
1550 resolver->Clear(iterator_);
1551 resolver->Protect(iterator_);
1552 pkgCacheFile &cache([database_ cache]);
1553 cache->MarkInstall(iterator_, false);
1554 pkgDepCache::StateCache &state((*cache)[iterator_]);
1555 if (!state.Install())
1556 cache->SetReInstall(iterator_, true);
1560 pkgProblemResolver *resolver = [database_ resolver];
1561 resolver->Clear(iterator_);
1562 resolver->Protect(iterator_);
1563 resolver->Remove(iterator_);
1564 [database_ cache]->MarkDelete(iterator_, true);
1567 - (NSNumber *) isVisiblySearchedForBy:(NSString *)search {
1568 return [NSNumber numberWithBool:(
1569 [self valid] && [self visible] && [self matches:search]
1573 - (NSNumber *) isInstalledAndVisible:(NSNumber *)number {
1574 return [NSNumber numberWithBool:(
1575 (![number boolValue] || [self visible]) && [self installed] != nil
1579 - (NSNumber *) isVisiblyUninstalledInSection:(NSString *)name {
1580 NSString *section = [self section];
1582 return [NSNumber numberWithBool:(
1583 [self valid] && [self visible] &&
1584 [self installed] == nil && (
1586 section == nil && [name length] == 0 ||
1587 [name isEqualToString:section]
1592 - (NSNumber *) isVisibleInSource:(Source *)source {
1593 return [NSNumber numberWithBool:([self source] == source && [self visible])];
1598 /* Section Class {{{ */
1599 @interface Section : NSObject {
1605 - (NSComparisonResult) compareByName:(Section *)section;
1606 - (Section *) initWithName:(NSString *)name;
1607 - (Section *) initWithName:(NSString *)name row:(size_t)row;
1608 - (NSString *) name;
1611 - (void) addToCount;
1615 @implementation Section
1622 - (NSComparisonResult) compareByName:(Section *)section {
1623 NSString *lhs = [self name];
1624 NSString *rhs = [section name];
1626 if ([lhs length] != 0 && [rhs length] != 0) {
1627 unichar lhc = [lhs characterAtIndex:0];
1628 unichar rhc = [rhs characterAtIndex:0];
1630 if (isalpha(lhc) && !isalpha(rhc))
1631 return NSOrderedAscending;
1632 else if (!isalpha(lhc) && isalpha(rhc))
1633 return NSOrderedDescending;
1636 return [lhs caseInsensitiveCompare:rhs];
1639 - (Section *) initWithName:(NSString *)name {
1640 return [self initWithName:name row:0];
1643 - (Section *) initWithName:(NSString *)name row:(size_t)row {
1644 if ((self = [super init]) != nil) {
1645 name_ = [name retain];
1650 - (NSString *) name {
1662 - (void) addToCount {
1672 /* Database Implementation {{{ */
1673 @implementation Database
1680 - (void) _readCydia:(NSNumber *)fd {
1681 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1683 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1684 std::istream is(&ib);
1687 static Pcre finish_r("^finish:([^:]*)$");
1689 while (std::getline(is, line)) {
1690 const char *data(line.c_str());
1691 size_t size = line.size();
1692 fprintf(stderr, "C:%s\n", data);
1694 if (finish_r(data, size)) {
1695 NSString *finish = finish_r[1];
1696 int index = [Finishes_ indexOfObject:finish];
1697 if (index != INT_MAX && index > Finish_)
1706 - (void) _readStatus:(NSNumber *)fd {
1707 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1709 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1710 std::istream is(&ib);
1713 static Pcre conffile_r("^status: [^ ]* : conffile-prompt : (.*?) *$");
1714 static Pcre pmstatus_r("^([^:]*):([^:]*):([^:]*):(.*)$");
1716 while (std::getline(is, line)) {
1717 const char *data(line.c_str());
1718 size_t size = line.size();
1719 fprintf(stderr, "S:%s\n", data);
1721 if (conffile_r(data, size)) {
1722 [delegate_ setConfigurationData:conffile_r[1]];
1723 } else if (strncmp(data, "status: ", 8) == 0) {
1724 NSString *string = [NSString stringWithUTF8String:(data + 8)];
1725 [delegate_ setProgressTitle:string];
1726 } else if (pmstatus_r(data, size)) {
1727 std::string type([pmstatus_r[1] UTF8String]);
1728 NSString *id = pmstatus_r[2];
1730 float percent([pmstatus_r[3] floatValue]);
1731 [delegate_ setProgressPercent:(percent / 100)];
1733 NSString *string = pmstatus_r[4];
1735 if (type == "pmerror")
1736 [delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
1737 withObject:[NSArray arrayWithObjects:string, id, nil]
1740 else if (type == "pmstatus")
1741 [delegate_ setProgressTitle:string];
1742 else if (type == "pmconffile")
1743 [delegate_ setConfigurationData:string];
1744 else _assert(false);
1745 } else _assert(false);
1752 - (void) _readOutput:(NSNumber *)fd {
1753 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1755 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1756 std::istream is(&ib);
1759 while (std::getline(is, line)) {
1760 fprintf(stderr, "O:%s\n", line.c_str());
1761 [delegate_ addProgressOutput:[NSString stringWithUTF8String:line.c_str()]];
1772 - (Package *) packageWithName:(NSString *)name {
1773 if (static_cast<pkgDepCache *>(cache_) == NULL)
1775 pkgCache::PkgIterator iterator(cache_->FindPkg([name UTF8String]));
1776 return iterator.end() ? nil : [Package packageWithIterator:iterator database:self];
1779 - (Database *) init {
1780 if ((self = [super init]) != nil) {
1787 sources_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1788 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
1792 _assert(pipe(fds) != -1);
1795 _config->Set("APT::Keep-Fds::", cydiafd_);
1796 setenv("CYDIA", [[[[NSNumber numberWithInt:cydiafd_] stringValue] stringByAppendingString:@" 1"] UTF8String], _not(int));
1799 detachNewThreadSelector:@selector(_readCydia:)
1801 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1804 _assert(pipe(fds) != -1);
1808 detachNewThreadSelector:@selector(_readStatus:)
1810 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1813 _assert(pipe(fds) != -1);
1814 _assert(dup2(fds[0], 0) != -1);
1815 _assert(close(fds[0]) != -1);
1817 input_ = fdopen(fds[1], "a");
1819 _assert(pipe(fds) != -1);
1820 _assert(dup2(fds[1], 1) != -1);
1821 _assert(close(fds[1]) != -1);
1824 detachNewThreadSelector:@selector(_readOutput:)
1826 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1831 - (pkgCacheFile &) cache {
1835 - (pkgDepCache::Policy *) policy {
1839 - (pkgRecords *) records {
1843 - (pkgProblemResolver *) resolver {
1847 - (pkgAcquire &) fetcher {
1851 - (NSArray *) packages {
1855 - (NSArray *) sources {
1856 return [sources_ allValues];
1859 - (void) reloadData {
1878 if (!cache_.Open(progress_, true)) {
1880 if (!_error->PopMessage(error))
1883 fprintf(stderr, "cache_.Open():[%s]\n", error.c_str());
1885 if (error == "dpkg was interrupted, you must manually run 'dpkg --configure -a' to correct the problem. ")
1886 [delegate_ repairWithSelector:@selector(configure)];
1887 else if (error == "The package lists or status file could not be parsed or opened.")
1888 [delegate_ repairWithSelector:@selector(update)];
1889 // else if (error == "Could not open lock file /var/lib/dpkg/lock - open (13 Permission denied)")
1890 // else if (error == "Could not get lock /var/lib/dpkg/lock - open (35 Resource temporarily unavailable)")
1891 // else if (error == "The list of sources could not be read.")
1892 else _assert(false);
1897 now_ = [[NSDate date] retain];
1899 policy_ = new pkgDepCache::Policy();
1900 records_ = new pkgRecords(cache_);
1901 resolver_ = new pkgProblemResolver(cache_);
1902 fetcher_ = new pkgAcquire(&status_);
1905 list_ = new pkgSourceList();
1906 _assert(list_->ReadMainList());
1908 _assert(cache_->DelCount() == 0 && cache_->InstCount() == 0);
1909 _assert(pkgApplyStatus(cache_));
1911 if (cache_->BrokenCount() != 0) {
1912 _assert(pkgFixBroken(cache_));
1913 _assert(cache_->BrokenCount() == 0);
1914 _assert(pkgMinimizeUpgrade(cache_));
1917 [sources_ removeAllObjects];
1918 for (pkgSourceList::const_iterator source = list_->begin(); source != list_->end(); ++source) {
1919 std::vector<pkgIndexFile *> *indices = (*source)->GetIndexFiles();
1920 for (std::vector<pkgIndexFile *>::const_iterator index = indices->begin(); index != indices->end(); ++index)
1922 setObject:[[[Source alloc] initWithMetaIndex:*source] autorelease]
1923 forKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(*index)]
1927 [packages_ removeAllObjects];
1928 for (pkgCache::PkgIterator iterator = cache_->PkgBegin(); !iterator.end(); ++iterator)
1929 if (Package *package = [Package packageWithIterator:iterator database:self])
1930 [packages_ addObject:package];
1932 [packages_ sortUsingSelector:@selector(compareByName:)];
1935 - (void) configure {
1936 NSString *dpkg = [NSString stringWithFormat:@"dpkg --configure -a --status-fd %u", statusfd_];
1937 system([dpkg UTF8String]);
1945 Lock.Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1946 _assert(!_error->PendingError());
1949 fetcher.Clean(_config->FindDir("Dir::Cache::Archives"));
1952 public pkgArchiveCleaner
1955 virtual void Erase(const char *File, std::string Pkg, std::string Ver, struct stat &St) {
1960 if (!cleaner.Go(_config->FindDir("Dir::Cache::Archives") + "partial/", cache_)) {
1962 while (_error->PopMessage(error))
1963 fprintf(stderr, "ArchiveCleaner: %s\n", error.c_str());
1968 pkgRecords records(cache_);
1970 lock_ = new FileFd();
1971 lock_->Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1972 _assert(!_error->PendingError());
1975 // XXX: explain this with an error message
1976 _assert(list.ReadMainList());
1978 manager_ = (_system->CreatePM(cache_));
1979 _assert(manager_->GetArchives(fetcher_, &list, &records));
1980 _assert(!_error->PendingError());
1984 NSMutableArray *before = [NSMutableArray arrayWithCapacity:16]; {
1986 _assert(list.ReadMainList());
1987 for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source)
1988 [before addObject:[NSString stringWithUTF8String:(*source)->GetURI().c_str()]];
1991 if (fetcher_->Run(PulseInterval_) != pkgAcquire::Continue) {
1996 bool failed = false;
1997 for (pkgAcquire::ItemIterator item = fetcher_->ItemsBegin(); item != fetcher_->ItemsEnd(); item++) {
1998 if ((*item)->Status == pkgAcquire::Item::StatDone && (*item)->Complete)
2001 std::string uri = (*item)->DescURI();
2002 std::string error = (*item)->ErrorText;
2004 fprintf(stderr, "pAf:%s:%s\n", uri.c_str(), error.c_str());
2007 [delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
2008 withObject:[NSArray arrayWithObjects:[NSString stringWithUTF8String:error.c_str()], nil]
2019 pkgPackageManager::OrderResult result = manager_->DoInstall(statusfd_);
2021 if (_error->PendingError()) {
2026 if (result == pkgPackageManager::Failed) {
2031 if (result != pkgPackageManager::Completed) {
2036 NSMutableArray *after = [NSMutableArray arrayWithCapacity:16]; {
2038 _assert(list.ReadMainList());
2039 for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source)
2040 [after addObject:[NSString stringWithUTF8String:(*source)->GetURI().c_str()]];
2043 if (![before isEqualToArray:after])
2048 _assert(pkgDistUpgrade(cache_));
2052 [self updateWithStatus:status_];
2055 - (void) updateWithStatus:(Status &)status {
2057 _assert(list.ReadMainList());
2060 lock.Fd(GetLock(_config->FindDir("Dir::State::Lists") + "lock"));
2061 _assert(!_error->PendingError());
2063 pkgAcquire fetcher(&status);
2064 _assert(list.GetIndexes(&fetcher));
2066 if (fetcher.Run(PulseInterval_) != pkgAcquire::Failed) {
2067 bool failed = false;
2068 for (pkgAcquire::ItemIterator item = fetcher.ItemsBegin(); item != fetcher.ItemsEnd(); item++)
2069 if ((*item)->Status != pkgAcquire::Item::StatDone) {
2070 (*item)->Finished();
2074 if (!failed && _config->FindB("APT::Get::List-Cleanup", true) == true) {
2075 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists")));
2076 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/"));
2079 [Metadata_ setObject:[NSDate date] forKey:@"LastUpdate"];
2084 - (void) setDelegate:(id)delegate {
2085 delegate_ = delegate;
2086 status_.setDelegate(delegate);
2087 progress_.setDelegate(delegate);
2090 - (Source *) getSource:(const pkgCache::PkgFileIterator &)file {
2091 pkgIndexFile *index(NULL);
2092 list_->FindIndex(file, index);
2093 return [sources_ objectForKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(index)]];
2099 /* Confirmation View {{{ */
2100 void AddTextView(NSMutableDictionary *fields, NSMutableArray *packages, NSString *key) {
2101 if ([packages count] == 0)
2104 UITextView *text = GetTextView([packages count] == 0 ? @"n/a" : [packages componentsJoinedByString:@", "], 120, false);
2105 [fields setObject:text forKey:key];
2107 CGColor blue(space_, 0, 0, 0.4, 1);
2108 [text setTextColor:blue];
2111 @protocol ConfirmationViewDelegate
2116 @interface ConfirmationView : UIView {
2117 Database *database_;
2119 UITransitionView *transition_;
2121 UINavigationBar *navbar_;
2122 UIPreferencesTable *table_;
2123 NSMutableDictionary *fields_;
2124 UIAlertSheet *essential_;
2129 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate;
2133 @implementation ConfirmationView
2136 [navbar_ setDelegate:nil];
2137 [transition_ setDelegate:nil];
2138 [table_ setDataSource:nil];
2140 [transition_ release];
2145 if (essential_ != nil)
2146 [essential_ release];
2151 [transition_ transition:7 toView:nil];
2155 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
2156 if (from != nil && to == nil)
2157 [self removeFromSuperview];
2160 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2163 if (essential_ != nil)
2164 [essential_ popupAlertAnimated:YES];
2166 [delegate_ confirm];
2175 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
2176 NSString *context = [sheet context];
2178 if ([context isEqualToString:@"remove"])
2184 [delegate_ confirm];
2189 else if ([context isEqualToString:@"unable"])
2195 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
2199 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
2201 case 0: return @"Statistics";
2202 case 1: return @"Modifications";
2204 default: _assert(false);
2208 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
2211 case 1: return [fields_ count];
2213 default: _assert(false);
2217 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
2218 if (group != 1 || row == -1)
2221 _assert(size_t(row) < [fields_ count]);
2222 return [[[fields_ allValues] objectAtIndex:row] visibleTextRect].size.height + TextViewOffset_;
2226 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
2227 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
2228 [cell setShowSelection:NO];
2231 case 0: switch (row) {
2233 [cell setTitle:@"Downloading"];
2234 [cell setValue:SizeString([database_ fetcher].FetchNeeded())];
2238 [cell setTitle:@"Resuming At"];
2239 [cell setValue:SizeString([database_ fetcher].PartialPresent())];
2243 double size([database_ cache]->UsrSize());
2246 [cell setTitle:@"Disk Freeing"];
2247 [cell setValue:SizeString(-size)];
2249 [cell setTitle:@"Disk Using"];
2250 [cell setValue:SizeString(size)];
2254 default: _assert(false);
2258 _assert(size_t(row) < [fields_ count]);
2259 [cell setTitle:[[fields_ allKeys] objectAtIndex:row]];
2260 [cell addSubview:[[fields_ allValues] objectAtIndex:row]];
2263 default: _assert(false);
2269 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate {
2270 if ((self = [super initWithFrame:[view bounds]]) != nil) {
2271 database_ = database;
2272 delegate_ = delegate;
2274 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
2275 [self addSubview:transition_];
2277 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
2279 CGSize navsize = [UINavigationBar defaultSize];
2280 CGRect navrect = {{0, 0}, navsize};
2281 CGRect bounds = [overlay_ bounds];
2283 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
2285 [navbar_ setBarStyle:1];
2286 [navbar_ setDelegate:self];
2288 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Confirm"] autorelease];
2289 [navbar_ pushNavigationItem:navitem];
2290 [navbar_ showButtonsWithLeftTitle:@"Cancel" rightTitle:@"Confirm"];
2292 fields_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
2294 NSMutableArray *installing = [NSMutableArray arrayWithCapacity:16];
2295 NSMutableArray *reinstalling = [NSMutableArray arrayWithCapacity:16];
2296 NSMutableArray *upgrading = [NSMutableArray arrayWithCapacity:16];
2297 NSMutableArray *downgrading = [NSMutableArray arrayWithCapacity:16];
2298 NSMutableArray *removing = [NSMutableArray arrayWithCapacity:16];
2302 pkgCacheFile &cache([database_ cache]);
2303 NSArray *packages = [database_ packages];
2304 for (size_t i(0), e = [packages count]; i != e; ++i) {
2305 Package *package = [packages objectAtIndex:i];
2306 pkgCache::PkgIterator iterator = [package iterator];
2307 pkgDepCache::StateCache &state(cache[iterator]);
2309 NSString *name([package name]);
2311 if (state.NewInstall())
2312 [installing addObject:name];
2313 else if (!state.Delete() && (state.iFlags & pkgDepCache::ReInstall) == pkgDepCache::ReInstall)
2314 [reinstalling addObject:name];
2315 else if (state.Upgrade())
2316 [upgrading addObject:name];
2317 else if (state.Downgrade())
2318 [downgrading addObject:name];
2319 else if (state.Delete()) {
2320 if ([package essential])
2322 [removing addObject:name];
2328 else if (Advanced_ || true) {
2329 essential_ = [[UIAlertSheet alloc]
2330 initWithTitle:@"Removing Essentials"
2331 buttons:[NSArray arrayWithObjects:
2332 @"Cancel Operation (Safe)",
2333 @"Force Removal (Unsafe)",
2335 defaultButtonIndex:0
2341 [essential_ setDestructiveButton:[[essential_ buttons] objectAtIndex:0]];
2343 [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."];
2345 essential_ = [[UIAlertSheet alloc]
2346 initWithTitle:@"Unable to Comply"
2347 buttons:[NSArray arrayWithObjects:@"Okay", nil]
2348 defaultButtonIndex:0
2353 [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."];
2356 AddTextView(fields_, installing, @"Installing");
2357 AddTextView(fields_, reinstalling, @"Reinstalling");
2358 AddTextView(fields_, upgrading, @"Upgrading");
2359 AddTextView(fields_, downgrading, @"Downgrading");
2360 AddTextView(fields_, removing, @"Removing");
2362 table_ = [[UIPreferencesTable alloc] initWithFrame:CGRectMake(
2363 0, navsize.height, bounds.size.width, bounds.size.height - navsize.height
2366 [table_ setReusesTableCells:YES];
2367 [table_ setDataSource:self];
2368 [table_ reloadData];
2370 [overlay_ addSubview:navbar_];
2371 [overlay_ addSubview:table_];
2373 [view addSubview:self];
2375 [transition_ setDelegate:self];
2377 UIView *blank = [[[UIView alloc] initWithFrame:[transition_ bounds]] autorelease];
2378 [transition_ transition:0 toView:blank];
2379 [transition_ transition:3 toView:overlay_];
2386 /* Progress Data {{{ */
2387 @interface ProgressData : NSObject {
2393 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object;
2400 @implementation ProgressData
2402 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object {
2403 if ((self = [super init]) != nil) {
2404 selector_ = selector;
2424 /* Progress View {{{ */
2425 @interface ProgressView : UIView <
2426 ConfigurationDelegate,
2429 _transient Database *database_;
2431 UIView *background_;
2432 UITransitionView *transition_;
2434 UINavigationBar *navbar_;
2435 UIProgressBar *progress_;
2436 UITextView *output_;
2437 UITextLabel *status_;
2438 UIPushButton *close_;
2443 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
2445 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database delegate:(id)delegate;
2446 - (void) setContentView:(UIView *)view;
2449 - (void) _retachThread;
2450 - (void) _detachNewThreadData:(ProgressData *)data;
2451 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title;
2457 @protocol ProgressViewDelegate
2458 - (void) progressViewIsComplete:(ProgressView *)sender;
2461 @implementation ProgressView
2464 [transition_ setDelegate:nil];
2465 [navbar_ setDelegate:nil];
2468 if (background_ != nil)
2469 [background_ release];
2470 [transition_ release];
2473 [progress_ release];
2480 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
2481 if (bootstrap_ && from == overlay_ && to == view_)
2485 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database delegate:(id)delegate {
2486 if ((self = [super initWithFrame:frame]) != nil) {
2487 database_ = database;
2488 delegate_ = delegate;
2490 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
2491 [transition_ setDelegate:self];
2493 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
2496 [overlay_ setBackgroundColor:Black_];
2498 background_ = [[UIView alloc] initWithFrame:[self bounds]];
2499 [background_ setBackgroundColor:Black_];
2500 [self addSubview:background_];
2503 [self addSubview:transition_];
2505 CGSize navsize = [UINavigationBar defaultSize];
2506 CGRect navrect = {{0, 0}, navsize};
2508 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
2509 [overlay_ addSubview:navbar_];
2511 [navbar_ setBarStyle:1];
2512 [navbar_ setDelegate:self];
2514 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:nil] autorelease];
2515 [navbar_ pushNavigationItem:navitem];
2517 CGRect bounds = [overlay_ bounds];
2518 CGSize prgsize = [UIProgressBar defaultSize];
2521 (bounds.size.width - prgsize.width) / 2,
2522 bounds.size.height - prgsize.height - 20
2525 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
2526 [progress_ setStyle:0];
2528 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(
2530 bounds.size.height - prgsize.height - 50,
2531 bounds.size.width - 20,
2535 [status_ setColor:White_];
2536 [status_ setBackgroundColor:Clear_];
2538 [status_ setCentersHorizontally:YES];
2539 //[status_ setFont:font];
2541 output_ = [[UITextView alloc] initWithFrame:CGRectMake(
2543 navrect.size.height + 20,
2544 bounds.size.width - 20,
2545 bounds.size.height - navsize.height - 62 - navrect.size.height
2548 //[output_ setTextFont:@"Courier New"];
2549 [output_ setTextSize:12];
2551 [output_ setTextColor:White_];
2552 [output_ setBackgroundColor:Clear_];
2554 [output_ setMarginTop:0];
2555 [output_ setAllowsRubberBanding:YES];
2556 [output_ setEditable:NO];
2558 [overlay_ addSubview:output_];
2560 close_ = [[UIPushButton alloc] initWithFrame:CGRectMake(
2562 bounds.size.height - prgsize.height - 50,
2563 bounds.size.width - 20,
2567 [close_ setAutosizesToFit:NO];
2568 [close_ setDrawsShadow:YES];
2569 [close_ setStretchBackground:YES];
2570 [close_ setEnabled:YES];
2572 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22);
2573 [close_ setTitleFont:bold];
2576 [close_ addTarget:self action:@selector(closeButtonPushed) forEvents:kUIControlEventMouseUpInside];
2577 [close_ setBackground:[UIImage applicationImageNamed:@"green-up.png"] forState:0];
2578 [close_ setBackground:[UIImage applicationImageNamed:@"green-dn.png"] forState:1];
2582 - (void) setContentView:(UIView *)view {
2583 view_ = [view retain];
2586 - (void) resetView {
2587 [transition_ transition:6 toView:view_];
2590 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
2591 NSString *context = [sheet context];
2592 if ([context isEqualToString:@"conffile"]) {
2593 FILE *input = [database_ input];
2597 fprintf(input, "N\n");
2601 fprintf(input, "Y\n");
2612 - (void) closeButtonPushed {
2615 [delegate_ progressViewIsComplete:self];
2620 [delegate_ suspendWithAnimation:YES];
2624 system("killall SpringBoard");
2628 system("launchctl unload /System/Library/LaunchDaemons/com.apple.SpringBoard.plist; launchctl load /System/Library/LaunchDaemons/com.apple.SpringBoard.plist");
2637 - (void) _retachThread {
2638 UINavigationItem *item = [navbar_ topItem];
2639 [item setTitle:@"Complete"];
2641 [overlay_ addSubview:close_];
2642 [progress_ removeFromSuperview];
2643 [status_ removeFromSuperview];
2646 case 0: [close_ setTitle:@"Return to Cydia"]; break;
2647 case 1: [close_ setTitle:@"Close Cydia (Restart)"]; break;
2648 case 2: [close_ setTitle:@"Restart SpringBoard"]; break;
2649 case 3: [close_ setTitle:@"Reload SpringBoard"]; break;
2650 case 4: [close_ setTitle:@"Reboot Device"]; break;
2654 notify_post("com.apple.mobile.application_installed");
2657 [delegate_ setStatusBarShowsProgress:NO];
2662 - (void) _detachNewThreadData:(ProgressData *)data {
2663 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
2665 [[data target] performSelector:[data selector] withObject:[data object]];
2668 [self performSelectorOnMainThread:@selector(_retachThread) withObject:nil waitUntilDone:YES];
2673 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title {
2674 UINavigationItem *item = [navbar_ topItem];
2675 [item setTitle:title];
2677 [status_ setText:nil];
2678 [output_ setText:@""];
2679 [progress_ setProgress:0];
2681 [close_ removeFromSuperview];
2682 [overlay_ addSubview:progress_];
2683 [overlay_ addSubview:status_];
2685 [delegate_ setStatusBarShowsProgress:YES];
2688 [transition_ transition:6 toView:overlay_];
2691 detachNewThreadSelector:@selector(_detachNewThreadData:)
2693 withObject:[[ProgressData alloc]
2694 initWithSelector:selector
2701 - (void) repairWithSelector:(SEL)selector {
2703 detachNewThreadSelector:selector
2706 title:@"Repairing..."
2710 - (void) setConfigurationData:(NSString *)data {
2712 performSelectorOnMainThread:@selector(_setConfigurationData:)
2718 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id {
2719 Package *package = id == nil ? nil : [database_ packageWithName:id];
2721 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
2722 initWithTitle:(package == nil ? @"Source Error" : [package name])
2723 buttons:[NSArray arrayWithObjects:@"Okay", nil]
2724 defaultButtonIndex:0
2729 [sheet setBodyText:error];
2730 [sheet popupAlertAnimated:YES];
2733 - (void) setProgressTitle:(NSString *)title {
2735 performSelectorOnMainThread:@selector(_setProgressTitle:)
2741 - (void) setProgressPercent:(float)percent {
2743 performSelectorOnMainThread:@selector(_setProgressPercent:)
2744 withObject:[NSNumber numberWithFloat:percent]
2749 - (void) addProgressOutput:(NSString *)output {
2751 performSelectorOnMainThread:@selector(_addProgressOutput:)
2757 - (void) _setConfigurationData:(NSString *)data {
2758 static Pcre conffile_r("^'(.*)' '(.*)' ([01]) ([01])$");
2760 _assert(conffile_r(data));
2762 NSString *ofile = conffile_r[1];
2763 //NSString *nfile = conffile_r[2];
2765 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
2766 initWithTitle:@"Configuration Upgrade"
2767 buttons:[NSArray arrayWithObjects:
2768 @"Keep My Old Copy",
2769 @"Accept The New Copy",
2770 // XXX: @"See What Changed",
2772 defaultButtonIndex:0
2777 [sheet setBodyText:[NSString stringWithFormat:
2778 @"The following file has been changed by both the package maintainer and by you (or for you by a script).\n\n%@"
2781 [sheet popupAlertAnimated:YES];
2784 - (void) _setProgressTitle:(NSString *)title {
2785 [status_ setText:[title stringByAppendingString:@"..."]];
2788 - (void) _setProgressPercent:(NSNumber *)percent {
2789 [progress_ setProgress:[percent floatValue]];
2792 - (void) _addProgressOutput:(NSString *)output {
2793 [output_ setText:[NSString stringWithFormat:@"%@\n%@", [output_ text], output]];
2794 CGSize size = [output_ contentSize];
2795 CGRect rect = {{0, size.height}, {size.width, 0}};
2796 [output_ scrollRectToVisible:rect animated:YES];
2799 - (BOOL) isRunning {
2806 /* Package Cell {{{ */
2807 @interface PackageCell : UISimpleTableCell {
2810 NSString *description_;
2812 //UIImageView *trusted_;
2814 UIImageView *badge_;
2815 UITextLabel *status_;
2819 - (PackageCell *) init;
2820 - (void) setPackage:(Package *)package;
2822 + (int) heightForPackage:(Package *)package;
2826 @implementation PackageCell
2828 - (void) clearPackage {
2839 if (description_ != nil) {
2840 [description_ release];
2844 if (source_ != nil) {
2851 [self clearPackage];
2856 //[trusted_ release];
2860 - (PackageCell *) init {
2861 if ((self = [super init]) != nil) {
2863 badge_ = [[UIImageView alloc] initWithFrame:CGRectMake(17, 70, 16, 16)];
2865 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 68, 280, 20)];
2866 [status_ setBackgroundColor:Clear_];
2867 [status_ setFont:small];
2872 - (void) setPackage:(Package *)package {
2873 [self clearPackage];
2875 Source *source = [package source];
2878 if (NSString *icon = [package icon])
2879 icon_ = [UIImage imageAtPath:[icon substringFromIndex:6]];
2880 if (icon_ == nil) if (NSString *section = [package section])
2881 icon_ = [UIImage applicationImageNamed:[NSString stringWithFormat:@"Sections/%@.png", Simplify(section)]];
2882 /*if (icon_ == nil) if (NSString *icon = [source defaultIcon])
2883 icon_ = [UIImage imageAtPath:[icon substringFromIndex:6]];*/
2885 icon_ = [UIImage applicationImageNamed:@"unknown.png"];
2887 icon_ = [icon_ retain];
2889 name_ = [[package name] retain];
2890 description_ = [[package tagline] retain];
2892 NSString *label = nil;
2893 bool trusted = false;
2895 if (source != nil) {
2896 label = [source label];
2897 trusted = [source trusted];
2898 } else if ([[package id] isEqualToString:@"firmware"])
2901 label = @"Unknown/Local";
2903 NSString *from = [NSString stringWithFormat:@"from %@", label];
2905 NSString *section = Simplify([package section]);
2906 if (section != nil && ![section isEqualToString:label])
2907 from = [from stringByAppendingString:[NSString stringWithFormat:@" (%@)", section]];
2909 source_ = [from retain];
2912 [badge_ removeFromSuperview];
2913 [status_ removeFromSuperview];
2915 if (NSString *mode = [package mode]) {
2916 [badge_ setImage:[UIImage applicationImageNamed:
2917 [mode isEqualToString:@"Remove"] || [mode isEqualToString:@"Purge"] ? @"removing.png" : @"installing.png"
2920 [status_ setText:[NSString stringWithFormat:@"Queued for %@", mode]];
2921 [status_ setColor:Blueish_];
2922 } else if ([package half]) {
2923 [badge_ setImage:[UIImage applicationImageNamed:@"damaged.png"]];
2924 [status_ setText:@"Package Damaged"];
2925 [status_ setColor:Red_];
2927 [badge_ setImage:nil];
2928 [status_ setText:nil];
2932 [self addSubview:badge_];
2933 [self addSubview:status_];
2938 - (void) drawContentInRect:(CGRect)rect selected:(BOOL)selected {
2940 [icon_ drawInRect:CGRectMake(10, 10, 30, 30)];
2947 [name_ drawAtPoint:CGPointMake(48, 8) forWidth:240 withFont:Font18Bold_ ellipsis:2];
2948 [source_ drawAtPoint:CGPointMake(58, 29) forWidth:225 withFont:Font12_ ellipsis:2];
2952 [description_ drawAtPoint:CGPointMake(12, 46) forWidth:280 withFont:Font14_ ellipsis:2];
2954 [super drawContentInRect:rect selected:selected];
2957 + (int) heightForPackage:(Package *)package {
2958 NSString *tagline([package tagline]);
2959 int height = tagline == nil || [tagline length] == 0 ? -17 : 0;
2961 if ([package hasMode] || [package half])
2970 /* Section Cell {{{ */
2971 @interface SectionCell : UISimpleTableCell {
2976 UISwitchControl *switch_;
2981 - (void) setSection:(Section *)section editing:(BOOL)editing;
2985 @implementation SectionCell
2987 - (void) clearSection {
2988 if (section_ != nil) {
2998 if (count_ != nil) {
3005 [self clearSection];
3012 if ((self = [super init]) != nil) {
3013 icon_ = [[UIImage applicationImageNamed:@"folder.png"] retain];
3015 switch_ = [[UISwitchControl alloc] initWithFrame:CGRectMake(218, 9, 60, 25)];
3016 [switch_ addTarget:self action:@selector(onSwitch:) forEvents:kUIControlEventMouseUpInside];
3020 - (void) onSwitch:(id)sender {
3021 NSMutableDictionary *metadata = [Sections_ objectForKey:section_];
3022 if (metadata == nil) {
3023 metadata = [NSMutableDictionary dictionaryWithCapacity:2];
3024 [Sections_ setObject:metadata forKey:section_];
3028 [metadata setObject:[NSNumber numberWithBool:([switch_ value] == 0)] forKey:@"Hidden"];
3031 - (void) setSection:(Section *)section editing:(BOOL)editing {
3032 if (editing != editing_) {
3034 [switch_ removeFromSuperview];
3036 [self addSubview:switch_];
3040 [self clearSection];
3042 if (section == nil) {
3043 name_ = [@"All Packages" retain];
3046 section_ = [section name];
3047 if (section_ != nil)
3048 section_ = [section_ retain];
3049 name_ = [(section_ == nil ? @"(No Section)" : section_) retain];
3050 count_ = [[NSString stringWithFormat:@"%d", [section count]] retain];
3053 [switch_ setValue:isSectionVisible(section_) animated:NO];
3057 - (void) drawContentInRect:(CGRect)rect selected:(BOOL)selected {
3058 [icon_ drawInRect:CGRectMake(8, 7, 32, 32)];
3065 [name_ drawAtPoint:CGPointMake(48, 9) forWidth:(editing_ ? 164 : 250) withFont:Font22Bold_ ellipsis:2];
3067 CGSize size = [count_ sizeWithFont:Font14_];
3071 [count_ drawAtPoint:CGPointMake(12 + (29 - size.width) / 2, 15) withFont:Font12Bold_];
3073 [super drawContentInRect:rect selected:selected];
3079 /* File Table {{{ */
3080 @interface FileTable : RVPage {
3081 _transient Database *database_;
3084 NSMutableArray *files_;
3088 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3089 - (void) setPackage:(Package *)package;
3093 @implementation FileTable
3096 if (package_ != nil)
3105 - (int) numberOfRowsInTable:(UITable *)table {
3106 return files_ == nil ? 0 : [files_ count];
3109 - (float) table:(UITable *)table heightForRow:(int)row {
3113 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
3114 if (reusing == nil) {
3115 reusing = [[[UIImageAndTextTableCell alloc] init] autorelease];
3116 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
3117 [[(UIImageAndTextTableCell *)reusing titleTextLabel] setFont:font];
3120 [(UIImageAndTextTableCell *)reusing setTitle:[files_ objectAtIndex:row]];
3124 - (BOOL) table:(UITable *)table canSelectRow:(int)row {
3128 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3129 if ((self = [super initWithBook:book]) != nil) {
3130 database_ = database;
3132 files_ = [[NSMutableArray arrayWithCapacity:32] retain];
3134 list_ = [[UITable alloc] initWithFrame:[self bounds]];
3135 [self addSubview:list_];
3137 UITableColumn *column = [[[UITableColumn alloc]
3138 initWithTitle:@"Name"
3140 width:[self frame].size.width
3143 [list_ setDataSource:self];
3144 [list_ setSeparatorStyle:1];
3145 [list_ addTableColumn:column];
3146 [list_ setDelegate:self];
3147 [list_ setReusesTableCells:YES];
3151 - (void) setPackage:(Package *)package {
3152 if (package_ != nil) {
3153 [package_ autorelease];
3162 [files_ removeAllObjects];
3164 if (package != nil) {
3165 package_ = [package retain];
3166 name_ = [[package id] retain];
3168 NSString *path = [NSString stringWithFormat:@"/var/lib/dpkg/info/%@.list", name_];
3171 std::ifstream fin([path UTF8String]);
3173 while (std::getline(fin, line))
3174 [files_ addObject:[NSString stringWithUTF8String:line.c_str()]];
3177 if ([files_ count] != 0) {
3178 if ([[files_ objectAtIndex:0] isEqualToString:@"/."])
3179 [files_ removeObjectAtIndex:0];
3180 [files_ sortUsingSelector:@selector(compareByPath:)];
3182 NSMutableArray *stack = [NSMutableArray arrayWithCapacity:8];
3183 [stack addObject:@"/"];
3185 for (int i(0), e([files_ count]); i != e; ++i) {
3186 NSString *file = [files_ objectAtIndex:i];
3187 while (![file hasPrefix:[stack lastObject]])
3188 [stack removeLastObject];
3189 NSString *directory = [stack lastObject];
3190 [stack addObject:[file stringByAppendingString:@"/"]];
3191 [files_ replaceObjectAtIndex:i withObject:[NSString stringWithFormat:@"%*s%@",
3192 ([stack count] - 2) * 3, "",
3193 [file substringFromIndex:[directory length]]
3202 - (void) resetViewAnimated:(BOOL)animated {
3203 [list_ resetViewAnimated:animated];
3206 - (void) reloadData {
3207 [self setPackage:[database_ packageWithName:name_]];
3208 [self reloadButtons];
3211 - (NSString *) title {
3212 return @"Installed Files";
3215 - (NSString *) backButtonTitle {
3221 /* Package View {{{ */
3222 @interface PackageView : BrowserView {
3225 NSMutableArray *buttons_;
3228 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3229 - (void) setPackage:(Package *)package;
3233 @implementation PackageView
3236 if (package_ != nil)
3244 - (void) _clickButtonWithName:(NSString *)name {
3245 if ([name isEqualToString:@"Install"])
3246 [delegate_ installPackage:package_];
3247 else if ([name isEqualToString:@"Reinstall"])
3248 [delegate_ installPackage:package_];
3249 else if ([name isEqualToString:@"Remove"])
3250 [delegate_ removePackage:package_];
3251 else if ([name isEqualToString:@"Upgrade"])
3252 [delegate_ installPackage:package_];
3253 else _assert(false);
3256 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
3257 int count = [buttons_ count];
3258 _assert(count != 0);
3259 _assert(button <= count + 1);
3261 if (count != button - 1)
3262 [self _clickButtonWithName:[buttons_ objectAtIndex:(button - 1)]];
3267 - (void) webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame {
3268 [window setValue:package_ forKey:@"package"];
3271 - (void) _rightButtonClicked {
3272 /*[super _rightButtonClicked];
3275 int count = [buttons_ count];
3276 _assert(count != 0);
3279 [self _clickButtonWithName:[buttons_ objectAtIndex:0]];
3281 NSMutableArray *buttons = [NSMutableArray arrayWithCapacity:(count + 1)];
3282 [buttons addObjectsFromArray:buttons_];
3283 [buttons addObject:@"Cancel"];
3285 [delegate_ slideUp:[[[UIAlertSheet alloc]
3288 defaultButtonIndex:2
3295 - (NSString *) _rightButtonTitle {
3296 int count = [buttons_ count];
3297 return count == 0 ? nil : count != 1 ? @"Modify" : [buttons_ objectAtIndex:0];
3300 - (NSString *) title {
3304 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3305 if ((self = [super initWithBook:book database:database]) != nil) {
3306 database_ = database;
3307 buttons_ = [[NSMutableArray alloc] initWithCapacity:4];
3311 - (void) setPackage:(Package *)package {
3312 if (package_ != nil) {
3313 [package_ autorelease];
3322 [buttons_ removeAllObjects];
3324 if (package != nil) {
3325 package_ = [package retain];
3326 name_ = [[package id] retain];
3328 [self loadURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"package" ofType:@"html"]]];
3330 if ([package_ source] == nil);
3331 else if ([package_ upgradableAndEssential:NO])
3332 [buttons_ addObject:@"Upgrade"];
3333 else if ([package_ installed] == nil)
3334 [buttons_ addObject:@"Install"];
3336 [buttons_ addObject:@"Reinstall"];
3337 if ([package_ installed] != nil)
3338 [buttons_ addObject:@"Remove"];
3342 - (void) reloadData {
3343 [self setPackage:[database_ packageWithName:name_]];
3344 [self reloadButtons];
3349 /* Package Table {{{ */
3350 @interface PackageTable : RVPage {
3351 _transient Database *database_;
3355 NSMutableArray *packages_;
3356 NSMutableArray *sections_;
3357 UISectionList *list_;
3360 - (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object;
3362 - (void) setDelegate:(id)delegate;
3363 - (void) setObject:(id)object;
3365 - (void) reloadData;
3366 - (void) resetCursor;
3368 - (UISectionList *) list;
3370 - (void) setShouldHideHeaderInShortLists:(BOOL)hide;
3374 @implementation PackageTable
3377 [list_ setDataSource:nil];
3382 [packages_ release];
3383 [sections_ release];
3388 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
3389 return [sections_ count];
3392 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
3393 return [[sections_ objectAtIndex:section] name];
3396 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
3397 return [[sections_ objectAtIndex:section] row];
3400 - (int) numberOfRowsInTable:(UITable *)table {
3401 return [packages_ count];
3404 - (float) table:(UITable *)table heightForRow:(int)row {
3405 return [PackageCell heightForPackage:[packages_ objectAtIndex:row]];
3408 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
3410 reusing = [[[PackageCell alloc] init] autorelease];
3411 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
3415 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
3419 - (void) tableRowSelected:(NSNotification *)notification {
3420 int row = [[notification object] selectedRow];
3424 Package *package = [packages_ objectAtIndex:row];
3425 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
3426 [view setDelegate:delegate_];
3427 [view setPackage:package];
3428 [book_ pushPage:view];
3431 - (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object {
3432 if ((self = [super initWithBook:book]) != nil) {
3433 database_ = database;
3434 title_ = [title retain];
3436 object_ = object == nil ? nil : [object retain];
3438 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
3439 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
3441 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:YES];
3442 [list_ setDataSource:self];
3444 UITableColumn *column = [[[UITableColumn alloc]
3445 initWithTitle:@"Name"
3447 width:[self frame].size.width
3450 UITable *table = [list_ table];
3451 [table setSeparatorStyle:1];
3452 [table addTableColumn:column];
3453 [table setDelegate:self];
3454 [table setReusesTableCells:YES];
3456 [self addSubview:list_];
3461 - (void) setDelegate:(id)delegate {
3462 delegate_ = delegate;
3465 - (void) setObject:(id)object {
3471 object_ = [object retain];
3474 - (void) reloadData {
3475 NSArray *packages = [database_ packages];
3477 [packages_ removeAllObjects];
3478 [sections_ removeAllObjects];
3480 for (size_t i(0); i != [packages count]; ++i) {
3481 Package *package([packages objectAtIndex:i]);
3482 if ([[package performSelector:filter_ withObject:object_] boolValue])
3483 [packages_ addObject:package];
3486 Section *section = nil;
3488 for (size_t offset(0); offset != [packages_ count]; ++offset) {
3489 Package *package = [packages_ objectAtIndex:offset];
3490 NSString *name = [package index];
3492 if (section == nil || ![[section name] isEqualToString:name]) {
3493 section = [[[Section alloc] initWithName:name row:offset] autorelease];
3494 [sections_ addObject:section];
3497 [section addToCount];
3503 - (NSString *) title {
3507 - (void) resetViewAnimated:(BOOL)animated {
3508 [list_ resetViewAnimated:animated];
3511 - (void) resetCursor {
3512 [[list_ table] scrollPointVisibleAtTopLeft:CGPointMake(0, 0) animated:NO];
3515 - (UISectionList *) list {
3519 - (void) setShouldHideHeaderInShortLists:(BOOL)hide {
3520 [list_ setShouldHideHeaderInShortLists:hide];
3526 /* Add Source View {{{ */
3527 @interface AddSourceView : RVPage {
3528 _transient Database *database_;
3531 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3535 @implementation AddSourceView
3537 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3538 if ((self = [super initWithBook:book]) != nil) {
3539 database_ = database;
3545 /* Source Cell {{{ */
3546 @interface SourceCell : UITableCell {
3549 NSString *description_;
3555 - (SourceCell *) initWithSource:(Source *)source;
3559 @implementation SourceCell
3564 [description_ release];
3569 - (SourceCell *) initWithSource:(Source *)source {
3570 if ((self = [super init]) != nil) {
3572 icon_ = [UIImage applicationImageNamed:[NSString stringWithFormat:@"Sources/%@.png", [source host]]];
3574 icon_ = [UIImage applicationImageNamed:@"unknown.png"];
3575 icon_ = [icon_ retain];
3577 origin_ = [[source name] retain];
3578 label_ = [[source uri] retain];
3579 description_ = [[source description] retain];
3583 - (void) drawContentInRect:(CGRect)rect selected:(BOOL)selected {
3585 [icon_ drawInRect:CGRectMake(10, 10, 30, 30)];
3592 [origin_ drawAtPoint:CGPointMake(48, 8) forWidth:240 withFont:Font18Bold_ ellipsis:2];
3596 [label_ drawAtPoint:CGPointMake(58, 29) forWidth:225 withFont:Font12_ ellipsis:2];
3600 [description_ drawAtPoint:CGPointMake(12, 46) forWidth:280 withFont:Font14_ ellipsis:2];
3602 [super drawContentInRect:rect selected:selected];
3607 /* Source Table {{{ */
3608 @interface SourceTable : RVPage {
3609 _transient Database *database_;
3610 UISectionList *list_;
3611 NSMutableArray *sources_;
3612 UIAlertSheet *alert_;
3616 UIProgressHUD *hud_;
3619 //NSURLConnection *installer_;
3620 NSURLConnection *trivial_bz2_;
3621 NSURLConnection *trivial_gz_;
3622 //NSURLConnection *automatic_;
3627 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3631 @implementation SourceTable
3633 - (void) _deallocConnection:(NSURLConnection *)connection {
3634 if (connection != nil) {
3635 [connection cancel];
3636 //[connection setDelegate:nil];
3637 [connection release];
3642 [[list_ table] setDelegate:nil];
3643 [list_ setDataSource:nil];
3652 //[self _deallocConnection:installer_];
3653 [self _deallocConnection:trivial_gz_];
3654 [self _deallocConnection:trivial_bz2_];
3655 //[self _deallocConnection:automatic_];
3662 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
3663 return offset_ == 0 ? 1 : 2;
3666 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
3667 switch (section + (offset_ == 0 ? 1 : 0)) {
3668 case 0: return @"Entered by User";
3669 case 1: return @"Installed by Packages";
3677 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
3678 switch (section + (offset_ == 0 ? 1 : 0)) {
3680 case 1: return offset_;
3688 - (int) numberOfRowsInTable:(UITable *)table {
3689 return [sources_ count];
3692 - (float) table:(UITable *)table heightForRow:(int)row {
3693 Source *source = [sources_ objectAtIndex:row];
3694 return [source description] == nil ? 56 : 73;
3697 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col {
3698 Source *source = [sources_ objectAtIndex:row];
3699 // XXX: weird warning, stupid selectors ;P
3700 return [[[SourceCell alloc] initWithSource:(id)source] autorelease];
3703 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
3707 - (BOOL) table:(UITable *)table canSelectRow:(int)row {
3711 - (void) tableRowSelected:(NSNotification*)notification {
3712 UITable *table([list_ table]);
3713 int row([table selectedRow]);
3717 Source *source = [sources_ objectAtIndex:row];
3719 PackageTable *packages = [[[PackageTable alloc]
3722 title:[source label]
3723 filter:@selector(isVisibleInSource:)
3727 [packages setDelegate:delegate_];
3729 [book_ pushPage:packages];
3732 - (BOOL) table:(UITable *)table canDeleteRow:(int)row {
3733 Source *source = [sources_ objectAtIndex:row];
3734 return [source record] != nil;
3737 - (void) table:(UITable *)table willSwipeToDeleteRow:(int)row {
3738 [[list_ table] setDeleteConfirmationRow:row];
3741 - (void) table:(UITable *)table deleteRow:(int)row {
3742 Source *source = [sources_ objectAtIndex:row];
3743 [Sources_ removeObjectForKey:[source key]];
3744 [delegate_ syncData];
3747 - (void) _endConnection:(NSURLConnection *)connection {
3748 NSURLConnection **field = NULL;
3749 if (connection == trivial_bz2_)
3750 field = &trivial_bz2_;
3751 else if (connection == trivial_gz_)
3752 field = &trivial_gz_;
3753 _assert(field != NULL);
3754 [connection release];
3758 trivial_bz2_ == nil &&
3761 [delegate_ setStatusBarShowsProgress:NO];
3764 [hud_ removeFromSuperview];
3769 [Sources_ setObject:[NSDictionary dictionaryWithObjectsAndKeys:
3772 @"./", @"Distribution",
3773 nil] forKey:[NSString stringWithFormat:@"deb:%@:./", href_]];
3775 [delegate_ syncData];
3776 } else if (error_ != nil) {
3777 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
3778 initWithTitle:@"Verification Error"
3779 buttons:[NSArray arrayWithObjects:@"OK", nil]
3780 defaultButtonIndex:0
3785 [sheet setBodyText:[error_ localizedDescription]];
3786 [sheet popupAlertAnimated:YES];
3788 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
3789 initWithTitle:@"Did not Find Repository"
3790 buttons:[NSArray arrayWithObjects:@"OK", nil]
3791 defaultButtonIndex:0
3796 [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."];
3797 [sheet popupAlertAnimated:YES];
3803 if (error_ != nil) {
3810 - (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response {
3811 switch ([response statusCode]) {
3817 - (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
3818 fprintf(stderr, "connection:\"%s\" didFailWithError:\"%s\"", [href_ UTF8String], [[error localizedDescription] UTF8String]);
3820 error_ = [error retain];
3821 [self _endConnection:connection];
3824 - (void) connectionDidFinishLoading:(NSURLConnection *)connection {
3825 [self _endConnection:connection];
3828 - (NSURLConnection *) _requestHRef:(NSString *)href method:(NSString *)method {
3829 NSMutableURLRequest *request = [NSMutableURLRequest
3830 requestWithURL:[NSURL URLWithString:href]
3831 cachePolicy:NSURLRequestUseProtocolCachePolicy
3832 timeoutInterval:20.0
3835 [request setHTTPMethod:method];
3837 return [[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease];
3840 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
3841 NSString *context = [sheet context];
3842 if ([context isEqualToString:@"source"])
3845 NSString *href = [[sheet textField] text];
3847 //installer_ = [[self _requestHRef:href method:@"GET"] retain];
3849 if (![href hasSuffix:@"/"])
3850 href_ = [href stringByAppendingString:@"/"];
3853 href_ = [href_ retain];
3855 trivial_bz2_ = [[self _requestHRef:[href_ stringByAppendingString:@"Packages.bz2"] method:@"HEAD"] retain];
3856 trivial_gz_ = [[self _requestHRef:[href_ stringByAppendingString:@"Packages.gz"] method:@"HEAD"] retain];
3857 //trivial_bz2_ = [[self _requestHRef:[href stringByAppendingString:@"dists/Release"] method:@"HEAD"] retain];
3861 hud_ = [delegate_ addProgressHUD];
3862 [hud_ setText:@"Verifying URL"];
3875 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3876 if ((self = [super initWithBook:book]) != nil) {
3877 database_ = database;
3878 sources_ = [[NSMutableArray arrayWithCapacity:16] retain];
3880 //list_ = [[UITable alloc] initWithFrame:[self bounds]];
3881 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:NO];
3882 [list_ setShouldHideHeaderInShortLists:NO];
3884 [self addSubview:list_];
3885 [list_ setDataSource:self];
3887 UITableColumn *column = [[UITableColumn alloc]
3888 initWithTitle:@"Name"
3890 width:[self frame].size.width
3893 UITable *table = [list_ table];
3894 [table setSeparatorStyle:1];
3895 [table addTableColumn:column];
3896 [table setDelegate:self];
3902 - (void) reloadData {
3904 _assert(list.ReadMainList());
3906 [sources_ removeAllObjects];
3907 [sources_ addObjectsFromArray:[database_ sources]];
3908 [sources_ sortUsingSelector:@selector(compareByNameAndType:)];
3910 int count = [sources_ count];
3911 for (offset_ = 0; offset_ != count; ++offset_) {
3912 Source *source = [sources_ objectAtIndex:offset_];
3913 if ([source record] == nil)
3920 - (void) resetViewAnimated:(BOOL)animated {
3921 [list_ resetViewAnimated:animated];
3924 - (void) _leftButtonClicked {
3925 /*[book_ pushPage:[[[AddSourceView alloc]
3930 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
3931 initWithTitle:@"Enter Cydia/APT URL"
3932 buttons:[NSArray arrayWithObjects:@"Add Source", @"Cancel", nil]
3933 defaultButtonIndex:0
3938 [sheet addTextFieldWithValue:@"http://" label:@""];
3940 UITextTraits *traits = [[sheet textField] textTraits];
3941 [traits setAutoCapsType:0];
3942 [traits setPreferredKeyboardType:3];
3943 [traits setAutoCorrectionType:1];
3945 [sheet popupAlertAnimated:YES];
3948 - (void) _rightButtonClicked {
3949 UITable *table = [list_ table];
3950 BOOL editing = [table isRowDeletionEnabled];
3951 [table enableRowDeletion:!editing animated:YES];
3952 [book_ reloadButtonsForPage:self];
3955 - (NSString *) title {
3959 - (NSString *) backButtonTitle {
3963 - (NSString *) leftButtonTitle {
3964 return [[list_ table] isRowDeletionEnabled] ? @"Add" : nil;
3967 - (NSString *) rightButtonTitle {
3968 return [[list_ table] isRowDeletionEnabled] ? @"Done" : @"Edit";
3971 - (RVUINavBarButtonStyle) rightButtonStyle {
3972 return [[list_ table] isRowDeletionEnabled] ? RVUINavBarButtonStyleHighlighted : RVUINavBarButtonStyleNormal;
3978 /* Installed View {{{ */
3979 @interface InstalledView : RVPage {
3980 _transient Database *database_;
3981 PackageTable *packages_;
3985 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3989 @implementation InstalledView
3992 [packages_ release];
3996 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3997 if ((self = [super initWithBook:book]) != nil) {
3998 database_ = database;
4000 packages_ = [[PackageTable alloc]
4004 filter:@selector(isInstalledAndVisible:)
4005 with:[NSNumber numberWithBool:YES]
4008 [self addSubview:packages_];
4012 - (void) resetViewAnimated:(BOOL)animated {
4013 [packages_ resetViewAnimated:animated];
4016 - (void) reloadData {
4017 [packages_ reloadData];
4020 - (void) _rightButtonClicked {
4021 [packages_ setObject:[NSNumber numberWithBool:expert_]];
4022 [packages_ reloadData];
4024 [book_ reloadButtonsForPage:self];
4027 - (NSString *) title {
4028 return @"Installed";
4031 - (NSString *) backButtonTitle {
4035 - (NSString *) rightButtonTitle {
4036 return Role_ != nil && [Role_ isEqualToString:@"Developer"] ? nil : expert_ ? @"Expert" : @"Simple";
4039 - (RVUINavBarButtonStyle) rightButtonStyle {
4040 return expert_ ? RVUINavBarButtonStyleHighlighted : RVUINavBarButtonStyleNormal;
4043 - (void) setDelegate:(id)delegate {
4044 [super setDelegate:delegate];
4045 [packages_ setDelegate:delegate];
4052 @interface HomeView : BrowserView {
4057 @implementation HomeView
4059 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
4063 - (void) _leftButtonClicked {
4064 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
4065 initWithTitle:@"About Cydia Installer"
4066 buttons:[NSArray arrayWithObjects:@"Close", nil]
4067 defaultButtonIndex:0
4073 @"Copyright (C) 2008\n"
4074 "Jay Freeman (saurik)\n"
4075 "saurik@saurik.com\n"
4076 "http://www.saurik.com/\n"
4079 "http://www.theokorigroup.com/\n"
4081 "College of Creative Studies,\n"
4082 "University of California,\n"
4084 "http://www.ccs.ucsb.edu/"
4087 [sheet popupAlertAnimated:YES];
4090 - (NSString *) leftButtonTitle {
4096 /* Manage View {{{ */
4097 @interface ManageView : BrowserView {
4102 @implementation ManageView
4104 - (NSString *) title {
4108 - (void) _leftButtonClicked {
4109 [delegate_ askForSettings];
4112 - (NSString *) leftButtonTitle {
4116 - (NSString *) _rightButtonTitle {
4123 /* Browser Implementation {{{ */
4124 @implementation BrowserView
4127 WebView *webview = [webview_ webView];
4128 [webview setFrameLoadDelegate:nil];
4129 [webview setResourceLoadDelegate:nil];
4130 [webview setUIDelegate:nil];
4132 [scroller_ setDelegate:nil];
4133 [webview_ setDelegate:nil];
4135 [scroller_ release];
4138 [indicator_ release];
4144 - (void) loadURL:(NSURL *)url cachePolicy:(NSURLRequestCachePolicy)policy {
4145 [self loadRequest:[NSURLRequest
4148 timeoutInterval:30.0
4152 - (void) loadURL:(NSURL *)url {
4153 [self loadURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy];
4156 - (NSURLRequest *) _addHeadersToRequest:(NSURLRequest *)request {
4157 NSMutableURLRequest *copy = [request mutableCopy];
4159 [copy addValue:[NSString stringWithUTF8String:Firmware_] forHTTPHeaderField:@"X-Firmware"];
4160 [copy addValue:[NSString stringWithUTF8String:Machine_] forHTTPHeaderField:@"X-Machine"];
4161 [copy addValue:[NSString stringWithUTF8String:SerialNumber_] forHTTPHeaderField:@"X-Serial-Number"];
4164 [copy addValue:Role_ forHTTPHeaderField:@"X-Role"];
4169 - (void) loadRequest:(NSURLRequest *)request {
4171 [webview_ loadRequest:request];
4174 - (void) reloadURL {
4175 NSURL *url = [[[urls_ lastObject] retain] autorelease];
4176 [urls_ removeLastObject];
4177 [self loadURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData];
4180 - (WebView *) webView {
4181 return [webview_ webView];
4184 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame {
4185 [scroller_ setContentSize:frame.size];
4188 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old {
4189 [self view:sender didSetFrame:frame];
4192 - (void) pushPage:(RVPage *)page {
4193 [self setBackButtonTitle:title_];
4194 [page setDelegate:delegate_];
4195 [book_ pushPage:page];
4198 - (void) getSpecial:(NSString *)href {
4201 if ([href hasPrefix:@"mailto:"])
4202 [delegate_ openURL:[NSURL URLWithString:href]];
4203 else if ([href isEqualToString:@"cydia://add-source"])
4204 page = [[[AddSourceView alloc] initWithBook:book_ database:database_] autorelease];
4205 else if ([href isEqualToString:@"cydia://sources"])
4206 page = [[[SourceTable alloc] initWithBook:book_ database:database_] autorelease];
4207 else if ([href isEqualToString:@"cydia://packages"])
4208 page = [[[InstalledView alloc] initWithBook:book_ database:database_] autorelease];
4209 else if ([href hasPrefix:@"cydia://files/"]) {
4210 NSString *name = [href substringFromIndex:14];
4212 if (Package *package = [database_ packageWithName:name]) {
4213 FileTable *files = [[[FileTable alloc] initWithBook:book_ database:database_] autorelease];
4214 [files setPackage:package];
4217 } else if ([href hasPrefix:@"apptapp://package/"]) {
4218 NSString *name = [href substringFromIndex:18];
4220 if (Package *package = [database_ packageWithName:name]) {
4221 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
4222 [view setPackage:package];
4225 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
4226 initWithTitle:@"Cannot Locate Package"
4227 buttons:[NSArray arrayWithObjects:@"Close", nil]
4228 defaultButtonIndex:0
4233 [sheet setBodyText:[NSString stringWithFormat:
4234 @"The package %@ cannot be found in your current sources. I might recommend installing more sources."
4237 [sheet popupAlertAnimated:YES];
4242 [self pushPage:page];
4245 - (void) webView:(WebView *)sender willClickElement:(id)element {
4246 if ([[element localName] isEqualToString:@"img"])
4247 do if ((element = [element parentNode]) == nil)
4249 while (![[element localName] isEqualToString:@"a"]);
4250 if (![element respondsToSelector:@selector(href)])
4252 NSString *href = [element href];
4255 [self getSpecial:href];
4258 - (BOOL) isSpecialScheme:(NSString *)scheme {
4260 [scheme isEqualToString:@"apptapp"] ||
4261 [scheme isEqualToString:@"cydia"] ||
4262 [scheme isEqualToString:@"mailto"];
4265 - (NSURLRequest *) webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource {
4266 NSURL *url = [request URL];
4267 if ([self isSpecialScheme:[url scheme]]) {
4268 [self getSpecial:[url absoluteString]];
4274 [book_ pushPage:self];
4277 return [self _addHeadersToRequest:request];
4280 - (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request {
4281 if (request != nil) {
4282 NSString *scheme = [[request URL] scheme];
4283 if ([self isSpecialScheme:scheme])
4287 [self setBackButtonTitle:title_];
4289 BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease];
4290 [browser setDelegate:delegate_];
4292 if (request != nil) {
4293 [browser loadRequest:[self _addHeadersToRequest:request]];
4294 [book_ pushPage:browser];
4297 return [browser webView];
4300 - (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame {
4301 title_ = [title retain];
4302 [self setTitle:title];
4305 - (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame {
4306 if ([frame parentFrame] != nil)
4311 [indicator_ startAnimation];
4312 [self reloadButtons];
4314 if (title_ != nil) {
4319 [self setTitle:@"Loading..."];
4321 WebView *webview = [webview_ webView];
4322 NSString *href = [webview mainFrameURL];
4323 [urls_ addObject:[NSURL URLWithString:href]];
4325 CGRect webrect = [scroller_ frame];
4326 webrect.size.height = 0;
4327 [webview_ setFrame:webrect];
4330 - (void) _finishLoading {
4333 [indicator_ stopAnimation];
4334 [self reloadButtons];
4338 - (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
4339 if ([frame parentFrame] != nil)
4341 [self _finishLoading];
4344 - (void) webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
4345 if ([frame parentFrame] != nil)
4347 [self _finishLoading];
4349 [self loadURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@?%@",
4350 [[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"error" ofType:@"html"]] absoluteString],
4351 [[error localizedDescription] stringByAddingPercentEscapes]
4355 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4356 if ((self = [super initWithBook:book]) != nil) {
4357 database_ = database;
4360 struct CGRect bounds = [self bounds];
4362 UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:bounds] autorelease];
4363 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
4364 [self addSubview:pinstripe];
4366 scroller_ = [[UIScroller alloc] initWithFrame:bounds];
4367 [self addSubview:scroller_];
4369 [scroller_ setScrollingEnabled:YES];
4370 [scroller_ setAdjustForContentSizeChange:YES];
4371 [scroller_ setClipsSubviews:YES];
4372 [scroller_ setAllowsRubberBanding:YES];
4373 [scroller_ setScrollDecelerationFactor:0.99];
4374 [scroller_ setDelegate:self];
4376 CGRect webrect = [scroller_ bounds];
4377 webrect.size.height = 0;
4379 webview_ = [[UIWebView alloc] initWithFrame:webrect];
4380 [scroller_ addSubview:webview_];
4382 [webview_ setTilingEnabled:YES];
4383 [webview_ setTileSize:CGSizeMake(webrect.size.width, 500)];
4384 [webview_ setAutoresizes:YES];
4385 [webview_ setDelegate:self];
4386 //[webview_ setEnabledGestures:2];
4388 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:kUIProgressIndicatorStyleMediumWhite];
4389 indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(281, 42, indsize.width, indsize.height)];
4390 [indicator_ setStyle:kUIProgressIndicatorStyleMediumWhite];
4392 Package *package([database_ packageWithName:@"cydia"]);
4393 NSString *application = package == nil ? @"Cydia" : [NSString
4394 stringWithFormat:@"Cydia/%@",
4398 WebView *webview = [webview_ webView];
4399 [webview setApplicationNameForUserAgent:application];
4400 [webview setFrameLoadDelegate:self];
4401 [webview setResourceLoadDelegate:self];
4402 [webview setUIDelegate:self];
4404 urls_ = [[NSMutableArray alloc] initWithCapacity:16];
4408 - (void) _rightButtonClicked {
4413 - (NSString *) _rightButtonTitle {
4417 - (NSString *) rightButtonTitle {
4418 return loading_ ? @"" : [self _rightButtonTitle];
4421 - (NSString *) title {
4425 - (NSString *) backButtonTitle {
4429 - (void) setPageActive:(BOOL)active {
4431 [book_ addSubview:indicator_];
4433 [indicator_ removeFromSuperview];
4436 - (void) resetViewAnimated:(BOOL)animated {
4439 - (void) setPushed:(bool)pushed {
4446 @interface CYBook : RVBook <
4449 _transient Database *database_;
4451 UIProgressIndicator *indicator_;
4452 UITextLabel *prompt_;
4453 UIProgressBar *progress_;
4457 - (id) initWithFrame:(CGRect)frame database:(Database *)database;
4463 /* Install View {{{ */
4464 @interface InstallView : RVPage {
4465 _transient Database *database_;
4466 NSMutableArray *sections_;
4467 NSMutableArray *filtered_;
4468 UITransitionView *transition_;
4474 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4475 - (void) reloadData;
4480 @implementation InstallView
4483 [list_ setDataSource:nil];
4484 [list_ setDelegate:nil];
4486 [sections_ release];
4487 [filtered_ release];
4488 [transition_ release];
4490 [accessory_ release];
4494 - (int) numberOfRowsInTable:(UITable *)table {
4495 return editing_ ? [sections_ count] : [filtered_ count] + 1;
4498 - (float) table:(UITable *)table heightForRow:(int)row {
4502 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
4504 reusing = [[[SectionCell alloc] init] autorelease];
4505 [(SectionCell *)reusing setSection:(editing_ ?
4506 [sections_ objectAtIndex:row] :
4507 (row == 0 ? nil : [filtered_ objectAtIndex:(row - 1)])
4508 ) editing:editing_];
4512 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
4516 - (BOOL) table:(UITable *)table canSelectRow:(int)row {
4520 - (void) tableRowSelected:(NSNotification *)notification {
4521 int row = [[notification object] selectedRow];
4532 title = @"All Packages";
4534 section = [filtered_ objectAtIndex:(row - 1)];
4535 name = [section name];
4541 title = @"(No Section)";
4545 PackageTable *table = [[[PackageTable alloc]
4549 filter:@selector(isVisiblyUninstalledInSection:)
4553 [table setDelegate:delegate_];
4555 [book_ pushPage:table];
4558 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4559 if ((self = [super initWithBook:book]) != nil) {
4560 database_ = database;
4562 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
4563 filtered_ = [[NSMutableArray arrayWithCapacity:16] retain];
4565 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
4566 [self addSubview:transition_];
4568 list_ = [[UITable alloc] initWithFrame:[transition_ bounds]];
4569 [transition_ transition:0 toView:list_];
4571 UITableColumn *column = [[[UITableColumn alloc]
4572 initWithTitle:@"Name"
4574 width:[self frame].size.width
4577 [list_ setDataSource:self];
4578 [list_ setSeparatorStyle:1];
4579 [list_ addTableColumn:column];
4580 [list_ setDelegate:self];
4581 [list_ setReusesTableCells:YES];
4587 - (void) reloadData {
4588 NSArray *packages = [database_ packages];
4590 [sections_ removeAllObjects];
4591 [filtered_ removeAllObjects];
4593 NSMutableArray *filtered = [NSMutableArray arrayWithCapacity:[packages count]];
4594 NSMutableDictionary *sections = [NSMutableDictionary dictionaryWithCapacity:32];
4596 for (size_t i(0); i != [packages count]; ++i) {
4597 Package *package([packages objectAtIndex:i]);
4598 NSString *name([package section]);
4601 Section *section([sections objectForKey:name]);
4602 if (section == nil) {
4603 section = [[[Section alloc] initWithName:name] autorelease];
4604 [sections setObject:section forKey:name];
4608 if ([package valid] && [package installed] == nil && [package visible])
4609 [filtered addObject:package];
4612 [sections_ addObjectsFromArray:[sections allValues]];
4613 [sections_ sortUsingSelector:@selector(compareByName:)];
4615 [filtered sortUsingSelector:@selector(compareBySection:)];
4617 Section *section = nil;
4618 for (size_t offset = 0, count = [filtered count]; offset != count; ++offset) {
4619 Package *package = [filtered objectAtIndex:offset];
4620 NSString *name = [package section];
4622 if (section == nil || name != nil && ![[section name] isEqualToString:name]) {
4623 section = name == nil ?
4624 [[[Section alloc] initWithName:nil] autorelease] :
4625 [sections objectForKey:name];
4626 [filtered_ addObject:section];
4629 [section addToCount];
4635 - (void) resetView {
4637 [self _rightButtonClicked];
4640 - (void) resetViewAnimated:(BOOL)animated {
4641 [list_ resetViewAnimated:animated];
4644 - (void) _rightButtonClicked {
4645 if ((editing_ = !editing_))
4648 [delegate_ updateData];
4651 [book_ setTitle:[self title] forPage:self];
4652 [book_ reloadButtonsForPage:self];
4655 - (NSString *) title {
4656 return editing_ ? @"Section Visibility" : @"Install by Section";
4659 - (NSString *) backButtonTitle {
4663 - (NSString *) rightButtonTitle {
4664 return [sections_ count] == 0 ? nil : editing_ ? @"Done" : @"Edit";
4667 - (UIView *) accessoryView {
4673 /* Changes View {{{ */
4674 @interface ChangesView : RVPage {
4675 _transient Database *database_;
4676 NSMutableArray *packages_;
4677 NSMutableArray *sections_;
4678 UISectionList *list_;
4682 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4683 - (void) reloadData;
4687 @implementation ChangesView
4690 [[list_ table] setDelegate:nil];
4691 [list_ setDataSource:nil];
4693 [packages_ release];
4694 [sections_ release];
4699 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
4700 return [sections_ count];
4703 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
4704 return [[sections_ objectAtIndex:section] name];
4707 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
4708 return [[sections_ objectAtIndex:section] row];
4711 - (int) numberOfRowsInTable:(UITable *)table {
4712 return [packages_ count];
4715 - (float) table:(UITable *)table heightForRow:(int)row {
4716 return [PackageCell heightForPackage:[packages_ objectAtIndex:row]];
4719 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
4721 reusing = [[[PackageCell alloc] init] autorelease];
4722 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
4726 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
4730 - (void) tableRowSelected:(NSNotification *)notification {
4731 int row = [[notification object] selectedRow];
4734 Package *package = [packages_ objectAtIndex:row];
4735 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
4736 [view setDelegate:delegate_];
4737 [view setPackage:package];
4738 [book_ pushPage:view];
4741 - (void) _leftButtonClicked {
4742 [(CYBook *)book_ update];
4743 [self reloadButtons];
4746 - (void) _rightButtonClicked {
4747 [delegate_ distUpgrade];
4750 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4751 if ((self = [super initWithBook:book]) != nil) {
4752 database_ = database;
4754 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
4755 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
4757 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:NO];
4758 [self addSubview:list_];
4760 [list_ setShouldHideHeaderInShortLists:NO];
4761 [list_ setDataSource:self];
4762 //[list_ setSectionListStyle:1];
4764 UITableColumn *column = [[[UITableColumn alloc]
4765 initWithTitle:@"Name"
4767 width:[self frame].size.width
4770 UITable *table = [list_ table];
4771 [table setSeparatorStyle:1];
4772 [table addTableColumn:column];
4773 [table setDelegate:self];
4774 [table setReusesTableCells:YES];
4780 - (void) reloadData {
4781 NSArray *packages = [database_ packages];
4783 [packages_ removeAllObjects];
4784 [sections_ removeAllObjects];
4786 for (size_t i(0); i != [packages count]; ++i) {
4787 Package *package([packages objectAtIndex:i]);
4790 [package installed] == nil && [package valid] && [package visible] ||
4791 [package upgradableAndEssential:NO]
4793 [packages_ addObject:package];
4796 [packages_ sortUsingSelector:@selector(compareForChanges:)];
4798 Section *upgradable = [[[Section alloc] initWithName:@"Available Upgrades"] autorelease];
4799 Section *section = nil;
4802 bool unseens = false;
4804 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, Locale_, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
4806 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
4807 Package *package = [packages_ objectAtIndex:offset];
4809 if ([package upgradableAndEssential:YES]) {
4811 [upgradable addToCount];
4814 NSDate *seen = [package seen];
4819 name = [@"n/a ?" retain];
4821 name = (NSString *) CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen);
4824 if (section == nil || ![[section name] isEqualToString:name]) {
4825 section = [[[Section alloc] initWithName:name row:offset] autorelease];
4826 [sections_ addObject:section];
4830 [section addToCount];
4834 CFRelease(formatter);
4837 Section *last = [sections_ lastObject];
4838 size_t count = [last count];
4839 [packages_ removeObjectsInRange:NSMakeRange([packages_ count] - count, count)];
4840 [sections_ removeLastObject];
4844 [sections_ insertObject:upgradable atIndex:0];
4847 [self reloadButtons];
4850 - (void) resetViewAnimated:(BOOL)animated {
4851 [list_ resetViewAnimated:animated];
4854 - (NSString *) leftButtonTitle {
4855 return [(CYBook *)book_ updating] ? nil : @"Refresh";
4858 - (NSString *) rightButtonTitle {
4859 return upgrades_ == 0 ? nil : [NSString stringWithFormat:@"Upgrade (%u)", upgrades_];
4862 - (NSString *) title {
4868 /* Search View {{{ */
4869 @protocol SearchViewDelegate
4870 - (void) showKeyboard:(BOOL)show;
4873 @interface SearchView : RVPage {
4875 UISearchField *field_;
4876 UITransitionView *transition_;
4877 PackageTable *table_;
4878 UIPreferencesTable *advanced_;
4884 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4885 - (void) reloadData;
4889 @implementation SearchView
4893 [[field_ textTraits] setEditingDelegate:nil];
4895 [field_ setDelegate:nil];
4897 [accessory_ release];
4899 [transition_ release];
4901 [advanced_ release];
4906 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
4910 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
4912 case 0: return @"Advanced Search (Coming Soon!)";
4914 default: _assert(false);
4918 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
4922 default: _assert(false);
4926 - (void) _showKeyboard:(BOOL)show {
4927 CGSize keysize = [UIKeyboard defaultSize];
4928 CGRect keydown = [book_ pageBounds];
4929 CGRect keyup = keydown;
4930 keyup.size.height -= keysize.height - ButtonBarHeight_;
4932 float delay = KeyboardTime_ * ButtonBarHeight_ / keysize.height;
4934 UIFrameAnimation *animation = [[[UIFrameAnimation alloc] initWithTarget:[table_ list]] autorelease];
4935 [animation setSignificantRectFields:8];
4938 [animation setStartFrame:keydown];
4939 [animation setEndFrame:keyup];
4941 [animation setStartFrame:keyup];
4942 [animation setEndFrame:keydown];
4945 UIAnimator *animator = [UIAnimator sharedAnimator];
4948 addAnimations:[NSArray arrayWithObjects:animation, nil]
4949 withDuration:(KeyboardTime_ - delay)
4954 [animator performSelector:@selector(startAnimation:) withObject:animation afterDelay:delay];
4957 [delegate_ showKeyboard:show];
4961 - (void) textFieldDidBecomeFirstResponder:(UITextField *)field {
4962 [self _showKeyboard:YES];
4965 - (void) textFieldDidResignFirstResponder:(UITextField *)field {
4966 [self _showKeyboard:NO];
4969 - (void) keyboardInputChanged:(UIFieldEditor *)editor {
4971 NSString *text([field_ text]);
4972 [field_ setClearButtonStyle:(text == nil || [text length] == 0 ? 0 : 2)];
4978 - (void) textFieldClearButtonPressed:(UITextField *)field {
4982 - (void) keyboardInputShouldDelete:(id)input {
4986 - (BOOL) keyboardInput:(id)input shouldInsertText:(NSString *)text isMarkedText:(int)marked {
4987 if ([text length] != 1 || [text characterAtIndex:0] != '\n') {
4991 [field_ resignFirstResponder];
4996 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4997 if ((self = [super initWithBook:book]) != nil) {
4998 CGRect pageBounds = [book_ pageBounds];
5000 /*UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:pageBounds] autorelease];
5001 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
5002 [self addSubview:pinstripe];*/
5004 transition_ = [[UITransitionView alloc] initWithFrame:pageBounds];
5005 [self addSubview:transition_];
5007 advanced_ = [[UIPreferencesTable alloc] initWithFrame:pageBounds];
5009 [advanced_ setReusesTableCells:YES];
5010 [advanced_ setDataSource:self];
5011 [advanced_ reloadData];
5013 dimmed_ = [[UIView alloc] initWithFrame:pageBounds];
5014 CGColor dimmed(space_, 0, 0, 0, 0.5);
5015 [dimmed_ setBackgroundColor:dimmed];
5017 table_ = [[PackageTable alloc]
5021 filter:@selector(isVisiblySearchedForBy:)
5025 [table_ setShouldHideHeaderInShortLists:NO];
5026 [transition_ transition:0 toView:table_];
5035 area.origin.x = /*cnfrect.origin.x + cnfrect.size.width + 4 +*/ 10;
5042 [self bounds].size.width - area.origin.x - 18;
5044 area.size.height = [UISearchField defaultHeight];
5046 field_ = [[UISearchField alloc] initWithFrame:area];
5048 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
5049 [field_ setFont:font];
5052 [field_ setPlaceholder:@"Package Names & Descriptions"];
5053 [field_ setDelegate:self];
5056 [field_ setPaddingTop:3];
5058 [field_ setPaddingTop:5];
5061 UITextTraits *traits = [field_ textTraits];
5062 [traits setAutoCapsType:0];
5063 [traits setAutoCorrectionType:1];
5064 [traits setReturnKeyType:6];
5067 [traits setEditingDelegate:self];
5070 CGRect accrect = {{0, 6}, {6 + cnfrect.size.width + 6 + area.size.width + 6, area.size.height + 30}};
5072 accessory_ = [[UIView alloc] initWithFrame:accrect];
5073 [accessory_ addSubview:field_];
5075 /*UIPushButton *configure = [[[UIPushButton alloc] initWithFrame:cnfrect] autorelease];
5076 [configure setShowPressFeedback:YES];
5077 [configure setImage:[UIImage applicationImageNamed:@"advanced.png"]];
5078 [configure addTarget:self action:@selector(configurePushed) forEvents:1];
5079 [accessory_ addSubview:configure];*/
5085 LKAnimation *animation = [LKTransition animation];
5086 [animation setType:@"oglFlip"];
5087 [animation setTimingFunction:[LKTimingFunction functionWithName:@"easeInEaseOut"]];
5088 [animation setFillMode:@"extended"];
5089 [animation setTransitionFlags:3];
5090 [animation setDuration:10];
5091 [animation setSpeed:0.35];
5092 [animation setSubtype:(flipped_ ? @"fromLeft" : @"fromRight")];
5093 [[transition_ _layer] addAnimation:animation forKey:0];
5094 [transition_ transition:0 toView:(flipped_ ? (UIView *) table_ : (UIView *) advanced_)];
5095 flipped_ = !flipped_;
5099 - (void) configurePushed {
5100 [field_ resignFirstResponder];
5104 - (void) resetViewAnimated:(BOOL)animated {
5107 [table_ resetViewAnimated:animated];
5110 - (void) reloadData {
5113 [table_ setObject:[field_ text]];
5114 [table_ reloadData];
5115 [table_ resetCursor];
5118 - (UIView *) accessoryView {
5122 - (NSString *) title {
5126 - (NSString *) backButtonTitle {
5130 - (void) setDelegate:(id)delegate {
5131 [table_ setDelegate:delegate];
5132 [super setDelegate:delegate];
5138 @implementation CYBook
5142 [indicator_ release];
5144 [progress_ release];
5148 - (NSString *) getTitleForPage:(RVPage *)page {
5149 return Simplify([super getTitleForPage:page]);
5157 [navbar_ setPrompt:@""];
5158 [navbar_ addSubview:overlay_];
5159 [indicator_ startAnimation];
5160 [prompt_ setText:@"Updating Database..."];
5161 [progress_ setProgress:0];
5166 detachNewThreadSelector:@selector(_update)
5175 [overlay_ removeFromSuperview];
5176 [indicator_ stopAnimation];
5177 [delegate_ reloadData];
5179 [self setPrompt:[NSString stringWithFormat:@"Last Updated: %@", GetLastUpdate()]];
5182 - (id) initWithFrame:(CGRect)frame database:(Database *)database {
5183 if ((self = [super initWithFrame:frame]) != nil) {
5184 database_ = database;
5187 [navbar_ setBarStyle:1];
5189 CGRect ovrrect = [navbar_ bounds];
5190 ovrrect.size.height = ([UINavigationBar defaultSizeWithPrompt].height - [UINavigationBar defaultSize].height);
5192 overlay_ = [[UIView alloc] initWithFrame:ovrrect];
5194 UIProgressIndicatorStyle style = Advanced_ ?
5195 kUIProgressIndicatorStyleSmallWhite :
5196 kUIProgressIndicatorStyleSmallBlack;
5198 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:style];
5199 unsigned indoffset = (ovrrect.size.height - indsize.height) / 2;
5200 CGRect indrect = {{indoffset, indoffset}, indsize};
5202 indicator_ = [[UIProgressIndicator alloc] initWithFrame:indrect];
5203 [indicator_ setStyle:style];
5204 [overlay_ addSubview:indicator_];
5206 CGSize prmsize = {200, indsize.width + 4};
5209 indoffset * 2 + indsize.width,
5213 (ovrrect.size.height - prmsize.height) / 2
5216 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 12);
5218 prompt_ = [[UITextLabel alloc] initWithFrame:prmrect];
5220 [prompt_ setColor:(Advanced_ ? White_ : Blueish_)];
5221 [prompt_ setBackgroundColor:Clear_];
5222 [prompt_ setFont:font];
5226 [overlay_ addSubview:prompt_];
5228 CGSize prgsize = {75, 100};
5231 ovrrect.size.width - prgsize.width - 10,
5232 (ovrrect.size.height - prgsize.height) / 2
5235 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
5236 [progress_ setStyle:0];
5237 [overlay_ addSubview:progress_];
5242 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5245 status.setDelegate(self);
5247 [database_ updateWithStatus:status];
5250 performSelectorOnMainThread:@selector(_update_)
5258 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id {
5259 [prompt_ setText:[NSString stringWithFormat:@"Error: %@", error]];
5262 - (void) setProgressTitle:(NSString *)title {
5264 performSelectorOnMainThread:@selector(_setProgressTitle:)
5270 - (void) setProgressPercent:(float)percent {
5273 - (void) addProgressOutput:(NSString *)output {
5275 performSelectorOnMainThread:@selector(_addProgressOutput:)
5281 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
5285 - (void) _setProgressTitle:(NSString *)title {
5286 [prompt_ setText:[title stringByAppendingString:@"..."]];
5289 - (void) _addProgressOutput:(NSString *)output {
5294 @interface Cydia : UIApplication <
5295 ConfirmationViewDelegate,
5296 ProgressViewDelegate,
5305 UIButtonBar *buttonbar_;
5307 ConfirmationView *confirm_;
5309 NSMutableArray *essential_;
5310 NSMutableArray *broken_;
5312 Database *database_;
5313 ProgressView *progress_;
5317 UIKeyboard *keyboard_;
5318 UIProgressHUD *hud_;
5320 InstallView *install_;
5321 ChangesView *changes_;
5322 ManageView *manage_;
5323 SearchView *search_;
5328 @implementation Cydia
5331 if ([broken_ count] != 0) {
5332 int count = [broken_ count];
5334 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
5335 initWithTitle:[NSString stringWithFormat:@"%d Half-Installed Package%@", count, (count == 1 ? @"" : @"s")]
5336 buttons:[NSArray arrayWithObjects:
5338 @"Ignore (Temporary)",
5340 defaultButtonIndex:0
5345 [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."];
5346 [sheet popupAlertAnimated:YES];
5347 } else if (!Ignored_ && [essential_ count] != 0) {
5348 int count = [essential_ count];
5350 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
5351 initWithTitle:[NSString stringWithFormat:@"%d Essential Upgrade%@", count, (count == 1 ? @"" : @"s")]
5352 buttons:[NSArray arrayWithObjects:@"Upgrade Essential", @"Ignore (Temporary)", nil]
5353 defaultButtonIndex:0
5358 [sheet setBodyText:@"One or more essential packages are currently out of date. If these upgrades are not performed you are likely to encounter errors."];
5359 [sheet popupAlertAnimated:YES];
5363 - (void) _reloadData {
5364 /*UIProgressHUD *hud = [[UIProgressHUD alloc] initWithWindow:window_];
5365 [hud setText:@"Reloading Data"];
5366 [overlay_ addSubview:hud];
5369 [database_ reloadData];
5373 [essential_ removeAllObjects];
5374 [broken_ removeAllObjects];
5376 NSArray *packages = [database_ packages];
5377 for (int i(0), e([packages count]); i != e; ++i) {
5378 Package *package = [packages objectAtIndex:i];
5380 [broken_ addObject:package];
5381 if ([package upgradableAndEssential:NO]) {
5382 if ([package essential])
5383 [essential_ addObject:package];
5389 NSString *badge([[NSNumber numberWithInt:changes] stringValue]);
5390 [buttonbar_ setBadgeValue:badge forButton:3];
5391 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
5392 [buttonbar_ setBadgeAnimated:YES forButton:3];
5393 [self setApplicationBadge:badge];
5395 [buttonbar_ setBadgeValue:nil forButton:3];
5396 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
5397 [buttonbar_ setBadgeAnimated:NO forButton:3];
5398 [self removeApplicationBadge];
5403 if ([packages count] == 0);
5412 [hud removeFromSuperview];*/
5415 - (void) _saveConfig {
5417 _assert([Metadata_ writeToFile:@"/var/lib/cydia/metadata.plist" atomically:YES] == YES);
5422 - (void) updateData {
5425 /* XXX: this is just stupid */
5427 [install_ reloadData];
5429 [changes_ reloadData];
5431 [search_ reloadData];
5441 FILE *file = fopen("/etc/apt/sources.list.d/cydia.list", "w");
5442 _assert(file != NULL);
5444 NSArray *keys = [Sources_ allKeys];
5446 for (int i(0), e([keys count]); i != e; ++i) {
5447 NSString *key = [keys objectAtIndex:i];
5448 NSDictionary *source = [Sources_ objectForKey:key];
5450 fprintf(file, "%s %s %s\n",
5451 [[source objectForKey:@"Type"] UTF8String],
5452 [[source objectForKey:@"URI"] UTF8String],
5453 [[source objectForKey:@"Distribution"] UTF8String]
5462 detachNewThreadSelector:@selector(update_)
5465 title:@"Updating Sources..."
5469 - (void) reloadData {
5470 @synchronized (self) {
5471 if (confirm_ == nil)
5477 pkgProblemResolver *resolver = [database_ resolver];
5479 resolver->InstallProtect();
5480 if (!resolver->Resolve(true))
5485 [database_ prepare];
5487 if ([database_ cache]->BrokenCount() == 0)
5488 confirm_ = [[ConfirmationView alloc] initWithView:underlay_ database:database_ delegate:self];
5490 NSMutableArray *broken = [NSMutableArray arrayWithCapacity:16];
5491 NSArray *packages = [database_ packages];
5493 for (size_t i(0); i != [packages count]; ++i) {
5494 Package *package = [packages objectAtIndex:i];
5495 if ([package broken])
5496 [broken addObject:[package name]];
5499 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
5500 initWithTitle:[NSString stringWithFormat:@"%d Broken Packages", [database_ cache]->BrokenCount()]
5501 buttons:[NSArray arrayWithObjects:@"Okay", nil]
5502 defaultButtonIndex:0
5507 [sheet setBodyText:[NSString stringWithFormat:@"The following packages have unmet dependencies:\n\n%@", [broken componentsJoinedByString:@"\n"]]];
5508 [sheet popupAlertAnimated:YES];
5514 - (void) installPackage:(Package *)package {
5515 @synchronized (self) {
5522 - (void) removePackage:(Package *)package {
5523 @synchronized (self) {
5530 - (void) distUpgrade {
5531 @synchronized (self) {
5532 [database_ upgrade];
5538 @synchronized (self) {
5546 [overlay_ removeFromSuperview];
5550 detachNewThreadSelector:@selector(perform)
5557 - (void) bootstrap_ {
5559 [database_ upgrade];
5560 [database_ prepare];
5561 [database_ perform];
5564 - (void) bootstrap {
5566 detachNewThreadSelector:@selector(bootstrap_)
5569 title:@"Bootstrap Install..."
5573 - (void) progressViewIsComplete:(ProgressView *)progress {
5574 @synchronized (self) {
5577 if (confirm_ != nil) {
5578 [underlay_ addSubview:overlay_];
5579 [confirm_ removeFromSuperview];
5586 - (void) setPage:(RVPage *)page {
5587 [page resetViewAnimated:NO];
5588 [page setDelegate:self];
5589 [book_ setPage:page];
5592 - (RVPage *) _pageForURL:(NSURL *)url withClass:(Class)_class {
5593 BrowserView *browser = [[[_class alloc] initWithBook:book_ database:database_] autorelease];
5594 [browser loadURL:url];
5598 - (void) _setHomePage {
5599 [self setPage:[self _pageForURL:[NSURL URLWithString:@"http://cydia.saurik.com/"] withClass:[HomeView class]]];
5602 - (void) buttonBarItemTapped:(id)sender {
5603 unsigned tag = [sender tag];
5605 [book_ resetViewAnimated:YES];
5607 } else if (tag_ == 2 && tag != 2)
5608 [install_ resetView];
5611 case 1: [self _setHomePage]; break;
5613 case 2: [self setPage:install_]; break;
5614 case 3: [self setPage:changes_]; break;
5615 case 4: [self setPage:manage_]; break;
5616 case 5: [self setPage:search_]; break;
5618 default: _assert(false);
5624 - (void) fixSpringBoard {
5625 pid_t pid = ExecFork();
5629 if (pid_t child = fork()) {
5630 waitpid(child, NULL, 0);
5632 execlp("launchctl", "launchctl", "unload", SpringBoard_, NULL);
5633 perror("launchctl unload");
5637 execlp("launchctl", "launchctl", "load", SpringBoard_, NULL);
5638 perror("launchctl load");
5643 - (void) applicationWillSuspend {
5648 [self fixSpringBoard];
5652 [super applicationWillSuspend];
5655 - (void) askForSettings {
5656 UIAlertSheet *role = [[[UIAlertSheet alloc]
5657 initWithTitle:@"Who Are You?"
5658 buttons:[NSArray arrayWithObjects:
5659 @"User (Graphical Only)",
5660 @"Hacker (+ Command Line)",
5661 @"Developer (No Filters)",
5663 defaultButtonIndex:-1
5668 [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."];
5669 [role popupAlertAnimated:YES];
5674 [self setStatusBarShowsProgress:NO];
5677 [hud_ removeFromSuperview];
5681 pid_t pid = ExecFork();
5683 execlp("launchctl", "launchctl", "stop", "com.apple.SpringBoard", NULL);
5684 perror("launchctl stop");
5691 [self askForSettings];
5695 overlay_ = [[UIView alloc] initWithFrame:[underlay_ bounds]];
5697 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
5698 book_ = [[CYBook alloc] initWithFrame:CGRectMake(
5699 0, 0, screenrect.size.width, screenrect.size.height - 48
5700 ) database:database_];
5702 [book_ setDelegate:self];
5704 [overlay_ addSubview:book_];
5706 NSArray *buttonitems = [NSArray arrayWithObjects:
5707 [NSDictionary dictionaryWithObjectsAndKeys:
5708 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5709 @"home-up.png", kUIButtonBarButtonInfo,
5710 @"home-dn.png", kUIButtonBarButtonSelectedInfo,
5711 [NSNumber numberWithInt:1], kUIButtonBarButtonTag,
5712 self, kUIButtonBarButtonTarget,
5713 @"Home", kUIButtonBarButtonTitle,
5714 @"0", kUIButtonBarButtonType,
5717 [NSDictionary dictionaryWithObjectsAndKeys:
5718 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5719 @"install-up.png", kUIButtonBarButtonInfo,
5720 @"install-dn.png", kUIButtonBarButtonSelectedInfo,
5721 [NSNumber numberWithInt:2], kUIButtonBarButtonTag,
5722 self, kUIButtonBarButtonTarget,
5723 @"Sections", kUIButtonBarButtonTitle,
5724 @"0", kUIButtonBarButtonType,
5727 [NSDictionary dictionaryWithObjectsAndKeys:
5728 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5729 @"changes-up.png", kUIButtonBarButtonInfo,
5730 @"changes-dn.png", kUIButtonBarButtonSelectedInfo,
5731 [NSNumber numberWithInt:3], kUIButtonBarButtonTag,
5732 self, kUIButtonBarButtonTarget,
5733 @"Changes", kUIButtonBarButtonTitle,
5734 @"0", kUIButtonBarButtonType,
5737 [NSDictionary dictionaryWithObjectsAndKeys:
5738 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5739 @"manage-up.png", kUIButtonBarButtonInfo,
5740 @"manage-dn.png", kUIButtonBarButtonSelectedInfo,
5741 [NSNumber numberWithInt:4], kUIButtonBarButtonTag,
5742 self, kUIButtonBarButtonTarget,
5743 @"Manage", kUIButtonBarButtonTitle,
5744 @"0", kUIButtonBarButtonType,
5747 [NSDictionary dictionaryWithObjectsAndKeys:
5748 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5749 @"search-up.png", kUIButtonBarButtonInfo,
5750 @"search-dn.png", kUIButtonBarButtonSelectedInfo,
5751 [NSNumber numberWithInt:5], kUIButtonBarButtonTag,
5752 self, kUIButtonBarButtonTarget,
5753 @"Search", kUIButtonBarButtonTitle,
5754 @"0", kUIButtonBarButtonType,
5758 buttonbar_ = [[UIButtonBar alloc]
5760 withFrame:CGRectMake(
5761 0, screenrect.size.height - ButtonBarHeight_,
5762 screenrect.size.width, ButtonBarHeight_
5764 withItemList:buttonitems
5767 [buttonbar_ setDelegate:self];
5768 [buttonbar_ setBarStyle:1];
5769 [buttonbar_ setButtonBarTrackingMode:2];
5771 int buttons[5] = {1, 2, 3, 4, 5};
5772 [buttonbar_ registerButtonGroup:0 withButtons:buttons withCount:5];
5773 [buttonbar_ showButtonGroup:0 withDuration:0];
5775 for (int i = 0; i != 5; ++i)
5776 [[buttonbar_ viewWithTag:(i + 1)] setFrame:CGRectMake(
5777 i * 64 + 2, 1, 60, ButtonBarHeight_
5780 [buttonbar_ showSelectionForButton:1];
5781 [overlay_ addSubview:buttonbar_];
5783 [UIKeyboard initImplementationNow];
5784 CGSize keysize = [UIKeyboard defaultSize];
5785 CGRect keyrect = {{0, [overlay_ bounds].size.height}, keysize};
5786 keyboard_ = [[UIKeyboard alloc] initWithFrame:keyrect];
5787 [[UIKeyboardImpl sharedInstance] setSoundsEnabled:(Sounds_Keyboard_ ? YES : NO)];
5788 [overlay_ addSubview:keyboard_];
5790 install_ = [[InstallView alloc] initWithBook:book_ database:database_];
5791 changes_ = [[ChangesView alloc] initWithBook:book_ database:database_];
5792 search_ = [[SearchView alloc] initWithBook:book_ database:database_];
5794 manage_ = (ManageView *) [[self
5795 _pageForURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"manage" ofType:@"html"]]
5796 withClass:[ManageView class]
5800 [underlay_ addSubview:overlay_];
5807 [self _setHomePage];
5810 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
5811 NSString *context = [sheet context];
5812 if ([context isEqualToString:@"fixhalf"])
5815 @synchronized (self) {
5816 for (int i = 0, e = [broken_ count]; i != e; ++i) {
5817 Package *broken = [broken_ objectAtIndex:i];
5820 NSString *id = [broken id];
5821 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.prerm", id] UTF8String]);
5822 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.postrm", id] UTF8String]);
5823 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.preinst", id] UTF8String]);
5824 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.postinst", id] UTF8String]);
5833 [broken_ removeAllObjects];
5840 else if ([context isEqualToString:@"role"]) {
5842 case 1: Role_ = @"User"; break;
5843 case 2: Role_ = @"Hacker"; break;
5844 case 3: Role_ = @"Developer"; break;
5851 bool reset = Settings_ != nil;
5853 Settings_ = [NSMutableDictionary dictionaryWithObjectsAndKeys:
5857 [Metadata_ setObject:Settings_ forKey:@"Settings"];
5865 } else if ([context isEqualToString:@"upgrade"])
5868 @synchronized (self) {
5869 for (int i = 0, e = [essential_ count]; i != e; ++i) {
5870 Package *essential = [essential_ objectAtIndex:i];
5871 [essential install];
5890 - (void) reorganize {
5891 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5892 system("/usr/libexec/cydia/free.sh");
5893 [self performSelectorOnMainThread:@selector(finish) withObject:nil waitUntilDone:NO];
5897 - (void) applicationSuspend:(__GSEvent *)event {
5898 if (hud_ == nil && ![progress_ isRunning])
5899 [super applicationSuspend:event];
5902 - (void) _animateSuspension:(BOOL)arg0 duration:(double)arg1 startTime:(double)arg2 scale:(float)arg3 {
5904 [super _animateSuspension:arg0 duration:arg1 startTime:arg2 scale:arg3];
5907 - (void) _setSuspended:(BOOL)value {
5909 [super _setSuspended:value];
5912 - (UIProgressHUD *) addProgressHUD {
5913 UIProgressHUD *hud = [[UIProgressHUD alloc] initWithWindow:window_];
5915 [underlay_ addSubview:hud];
5919 - (void) applicationDidFinishLaunching:(id)unused {
5920 Font12_ = [[UIFont systemFontOfSize:12] retain];
5921 Font12Bold_ = [[UIFont boldSystemFontOfSize:12] retain];
5922 Font14_ = [[UIFont systemFontOfSize:14] retain];
5923 Font18Bold_ = [[UIFont boldSystemFontOfSize:18] retain];
5924 Font22Bold_ = [[UIFont boldSystemFontOfSize:22] retain];
5926 _assert(pkgInitConfig(*_config));
5927 _assert(pkgInitSystem(*_config, _system));
5932 essential_ = [[NSMutableArray alloc] initWithCapacity:4];
5933 broken_ = [[NSMutableArray alloc] initWithCapacity:4];
5935 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
5936 window_ = [[UIWindow alloc] initWithContentRect:screenrect];
5938 [window_ orderFront:self];
5939 [window_ makeKey:self];
5940 [window_ _setHidden:NO];
5942 database_ = [[Database alloc] init];
5943 progress_ = [[ProgressView alloc] initWithFrame:[window_ bounds] database:database_ delegate:self];
5944 [database_ setDelegate:progress_];
5945 [window_ setContentView:progress_];
5947 underlay_ = [[UIView alloc] initWithFrame:[progress_ bounds]];
5948 [progress_ setContentView:underlay_];
5950 [progress_ resetView];
5953 readlink("/Applications", NULL, 0) == -1 && errno == EINVAL ||
5954 readlink("/Library/Ringtones", NULL, 0) == -1 && errno == EINVAL ||
5955 readlink("/Library/Wallpaper", NULL, 0) == -1 && errno == EINVAL ||
5956 readlink("/usr/include", NULL, 0) == -1 && errno == EINVAL ||
5957 readlink("/usr/libexec", NULL, 0) == -1 && errno == EINVAL ||
5958 readlink("/usr/share", NULL, 0) == -1 && errno == EINVAL
5960 [self setIdleTimerDisabled:YES];
5962 hud_ = [self addProgressHUD];
5963 [hud_ setText:@"Reorganizing\n\nWill Automatically\nRestart When Done"];
5965 [self setStatusBarShowsProgress:YES];
5968 detachNewThreadSelector:@selector(reorganize)
5976 - (void) showKeyboard:(BOOL)show {
5977 CGSize keysize = [UIKeyboard defaultSize];
5978 CGRect keydown = {{0, [overlay_ bounds].size.height}, keysize};
5979 CGRect keyup = keydown;
5980 keyup.origin.y -= keysize.height;
5982 UIFrameAnimation *animation = [[[UIFrameAnimation alloc] initWithTarget:keyboard_] autorelease];
5983 [animation setSignificantRectFields:2];
5986 [animation setStartFrame:keydown];
5987 [animation setEndFrame:keyup];
5988 [keyboard_ activate];
5990 [animation setStartFrame:keyup];
5991 [animation setEndFrame:keydown];
5992 [keyboard_ deactivate];
5995 [[UIAnimator sharedAnimator]
5996 addAnimations:[NSArray arrayWithObjects:animation, nil]
5997 withDuration:KeyboardTime_
6002 - (void) slideUp:(UIAlertSheet *)alert {
6004 [alert presentSheetFromButtonBar:buttonbar_];
6006 [alert presentSheetInView:overlay_];
6011 void AddPreferences(NSString *plist) {
6012 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
6014 NSMutableDictionary *settings = [[[NSMutableDictionary alloc] initWithContentsOfFile:plist] autorelease];
6015 _assert(settings != NULL);
6016 NSMutableArray *items = [settings objectForKey:@"items"];
6020 for (size_t i(0); i != [items count]; ++i) {
6021 NSMutableDictionary *item([items objectAtIndex:i]);
6022 NSString *label = [item objectForKey:@"label"];
6023 if (label != nil && [label isEqualToString:@"Cydia"]) {
6030 for (size_t i(0); i != [items count]; ++i) {
6031 NSDictionary *item([items objectAtIndex:i]);
6032 NSString *label = [item objectForKey:@"label"];
6033 if (label != nil && [label isEqualToString:@"General"]) {
6034 [items insertObject:[NSDictionary dictionaryWithObjectsAndKeys:
6035 @"CydiaSettings", @"bundle",
6036 @"PSLinkCell", @"cell",
6037 [NSNumber numberWithBool:YES], @"hasIcon",
6038 [NSNumber numberWithBool:YES], @"isController",
6040 nil] atIndex:(i + 1)];
6046 _assert([settings writeToFile:plist atomically:YES] == YES);
6053 id Alloc_(id self, SEL selector) {
6054 id object = alloc_(self, selector);
6055 fprintf(stderr, "[%s]A-%p\n", self->isa->name, object);
6060 id Dealloc_(id self, SEL selector) {
6061 id object = dealloc_(self, selector);
6062 fprintf(stderr, "[%s]D-%p\n", self->isa->name, object);
6066 int main(int argc, char *argv[]) {
6067 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
6069 bootstrap_ = argc > 1 && strcmp(argv[1], "--bootstrap") == 0;
6071 Home_ = NSHomeDirectory();
6074 NSString *plist = [Home_ stringByAppendingString:@"/Library/Preferences/com.apple.preferences.sounds.plist"];
6075 if (NSDictionary *sounds = [NSDictionary dictionaryWithContentsOfFile:plist])
6076 if (NSNumber *keyboard = [sounds objectForKey:@"keyboard"])
6077 Sounds_Keyboard_ = [keyboard boolValue];
6083 if (unlink("/var/cache/apt/pkgcache.bin") == -1)
6084 _assert(errno == ENOENT);
6085 if (unlink("/var/cache/apt/srcpkgcache.bin") == -1)
6086 _assert(errno == ENOENT);
6088 /*Method alloc = class_getClassMethod([NSObject class], @selector(alloc));
6089 alloc_ = alloc->method_imp;
6090 alloc->method_imp = (IMP) &Alloc_;*/
6092 /*Method dealloc = class_getClassMethod([NSObject class], @selector(dealloc));
6093 dealloc_ = dealloc->method_imp;
6094 dealloc->method_imp = (IMP) &Dealloc_;*/
6096 if (NSDictionary *sysver = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]) {
6097 if (NSString *prover = [sysver valueForKey:@"ProductVersion"]) {
6098 Firmware_ = strdup([prover UTF8String]);
6099 NSArray *versions = [prover componentsSeparatedByString:@"."];
6100 int count = [versions count];
6101 Major_ = count > 0 ? [[versions objectAtIndex:0] intValue] : 0;
6102 Minor_ = count > 1 ? [[versions objectAtIndex:1] intValue] : 0;
6103 BugFix_ = count > 2 ? [[versions objectAtIndex:2] intValue] : 0;
6108 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
6109 char *machine = new char[size];
6110 sysctlbyname("hw.machine", machine, &size, NULL, 0);
6113 if (CFMutableDictionaryRef dict = IOServiceMatching("IOPlatformExpertDevice"))
6114 if (io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, dict)) {
6115 if (CFTypeRef serial = IORegistryEntryCreateCFProperty(service, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0)) {
6116 SerialNumber_ = strdup(CFStringGetCStringPtr((CFStringRef) serial, CFStringGetSystemEncoding()));
6120 IOObjectRelease(service);
6123 /*AddPreferences(@"/Applications/Preferences.app/Settings-iPhone.plist");
6124 AddPreferences(@"/Applications/Preferences.app/Settings-iPod.plist");*/
6126 if ((Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"]) == NULL)
6127 Metadata_ = [[NSMutableDictionary alloc] initWithCapacity:2];
6129 Settings_ = [Metadata_ objectForKey:@"Settings"];
6131 Packages_ = [Metadata_ objectForKey:@"Packages"];
6132 Sections_ = [Metadata_ objectForKey:@"Sections"];
6133 Sources_ = [Metadata_ objectForKey:@"Sources"];
6136 if (Settings_ != nil)
6137 Role_ = [Settings_ objectForKey:@"Role"];
6139 if (Packages_ == nil) {
6140 Packages_ = [[[NSMutableDictionary alloc] initWithCapacity:128] autorelease];
6141 [Metadata_ setObject:Packages_ forKey:@"Packages"];
6144 if (Sections_ == nil) {
6145 Sections_ = [[[NSMutableDictionary alloc] initWithCapacity:32] autorelease];
6146 [Metadata_ setObject:Sections_ forKey:@"Sections"];
6149 if (Sources_ == nil) {
6150 Sources_ = [[[NSMutableDictionary alloc] initWithCapacity:0] autorelease];
6151 [Metadata_ setObject:Sources_ forKey:@"Sources"];
6154 if (access("/User", F_OK) != 0)
6155 system("/usr/libexec/cydia/firmware.sh");
6157 Locale_ = CFLocaleCopyCurrent();
6158 space_ = CGColorSpaceCreateDeviceRGB();
6160 Blue_.Set(space_, 0.2, 0.2, 1.0, 1.0);
6161 Blueish_.Set(space_, 0x19/255.f, 0x32/255.f, 0x50/255.f, 1.0);
6162 Black_.Set(space_, 0.0, 0.0, 0.0, 1.0);
6163 Clear_.Set(space_, 0.0, 0.0, 0.0, 0.0);
6164 Red_.Set(space_, 1.0, 0.0, 0.0, 1.0);
6165 White_.Set(space_, 1.0, 1.0, 1.0, 1.0);
6166 Gray_.Set(space_, 0.4, 0.4, 0.4, 1.0);
6168 Finishes_ = [NSArray arrayWithObjects:@"return", @"reopen", @"restart", @"reload", @"reboot", nil];
6170 SectionMap_ = [[[NSDictionary alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Sections" ofType:@"plist"]] autorelease];
6172 int value = UIApplicationMain(argc, argv, [Cydia class]);
6174 CGColorSpaceRelease(space_);