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";
444 static CGColor Blue_;
445 static CGColor Blueish_;
446 static CGColor Black_;
447 static CGColor Clear_;
449 static CGColor White_;
450 static CGColor Gray_;
452 static NSString *Home_;
453 static BOOL Sounds_Keyboard_;
455 static BOOL Advanced_;
457 static BOOL Ignored_;
459 static UIFont *Font12_;
460 static UIFont *Font12Bold_;
461 static UIFont *Font14_;
462 static UIFont *Font18Bold_;
463 static UIFont *Font22Bold_;
465 const char *Firmware_ = NULL;
466 const char *Machine_ = NULL;
467 const char *SerialNumber_ = NULL;
474 CGColorSpaceRef space_;
476 #define FW_LEAST(major, minor, bugfix) \
477 (major < Major_ || major == Major_ && \
478 (minor < Minor_ || minor == Minor_ && \
484 static NSDictionary *SectionMap_;
485 static NSMutableDictionary *Metadata_;
486 static _transient NSMutableDictionary *Settings_;
487 static _transient NSString *Role_;
488 static _transient NSMutableDictionary *Packages_;
489 static _transient NSMutableDictionary *Sections_;
490 static _transient NSMutableDictionary *Sources_;
491 static bool Changed_;
494 NSString *GetLastUpdate() {
495 NSDate *update = [Metadata_ objectForKey:@"LastUpdate"];
498 return @"Never or Unknown";
500 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, Locale_, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
501 CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) update);
503 CFRelease(formatter);
505 return [(NSString *) formatted autorelease];
508 /* Display Helpers {{{ */
509 inline float Interpolate(float begin, float end, float fraction) {
510 return (end - begin) * fraction + begin;
513 NSString *SizeString(double size) {
515 while (size > 1024) {
520 static const char *powers_[] = {"B", "kB", "MB", "GB"};
522 return [NSString stringWithFormat:@"%.1f%s", size, powers_[power]];
525 NSString *StripVersion(NSString *version) {
526 NSRange colon = [version rangeOfString:@":"];
527 if (colon.location != NSNotFound)
528 version = [version substringFromIndex:(colon.location + 1)];
532 static const float TextViewOffset_ = 22;
534 UITextView *GetTextView(NSString *value, float left, bool html) {
535 UITextView *text([[[UITextView alloc] initWithFrame:CGRectMake(left, 3, 310 - left, 1000)] autorelease]);
536 [text setEditable:NO];
537 [text setTextSize:16];
539 [text setHTML:value];
541 [text setText:value];
542 [text setEnabled:NO];
544 [text setBackgroundColor:Clear_];
546 CGRect frame = [text frame];
547 [text setFrame:frame];
548 CGRect rect = [text visibleTextRect];
549 frame.size.height = rect.size.height;
550 [text setFrame:frame];
555 NSString *Simplify(NSString *title) {
556 const char *data = [title UTF8String];
557 size_t size = [title length];
559 static Pcre square_r("^\\[(.*)\\]$");
560 if (square_r(data, size))
561 return Simplify(square_r[1]);
563 static Pcre paren_r("^\\((.*)\\)$");
564 if (paren_r(data, size))
565 return Simplify(paren_r[1]);
567 static Pcre title_r("^(.*?) \\(.*\\)$");
568 if (title_r(data, size))
569 return Simplify(title_r[1]);
575 bool isSectionVisible(NSString *section) {
576 NSDictionary *metadata = [Sections_ objectForKey:section];
577 NSNumber *hidden = metadata == nil ? nil : [metadata objectForKey:@"Hidden"];
578 return hidden == nil || ![hidden boolValue];
581 /* Delegate Prototypes {{{ */
585 @interface NSObject (ProgressDelegate)
588 @implementation NSObject(ProgressDelegate)
590 - (void) _setProgressError:(NSArray *)args {
591 [self performSelector:@selector(setProgressError:forPackage:)
592 withObject:[args objectAtIndex:0]
593 withObject:([args count] == 1 ? nil : [args objectAtIndex:1])
599 @protocol ProgressDelegate
600 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id;
601 - (void) setProgressTitle:(NSString *)title;
602 - (void) setProgressPercent:(float)percent;
603 - (void) addProgressOutput:(NSString *)output;
606 @protocol ConfigurationDelegate
607 - (void) repairWithSelector:(SEL)selector;
608 - (void) setConfigurationData:(NSString *)data;
611 @protocol CydiaDelegate
612 - (void) installPackage:(Package *)package;
613 - (void) removePackage:(Package *)package;
614 - (void) slideUp:(UIAlertSheet *)alert;
615 - (void) distUpgrade;
618 - (void) askForSettings;
619 - (UIProgressHUD *) addProgressHUD;
623 /* Status Delegation {{{ */
625 public pkgAcquireStatus
628 _transient NSObject<ProgressDelegate> *delegate_;
636 void setDelegate(id delegate) {
637 delegate_ = delegate;
640 virtual bool MediaChange(std::string media, std::string drive) {
644 virtual void IMSHit(pkgAcquire::ItemDesc &item) {
647 virtual void Fetch(pkgAcquire::ItemDesc &item) {
648 [delegate_ setProgressTitle:[NSString stringWithUTF8String:("Downloading " + item.ShortDesc).c_str()]];
651 virtual void Done(pkgAcquire::ItemDesc &item) {
654 virtual void Fail(pkgAcquire::ItemDesc &item) {
656 item.Owner->Status == pkgAcquire::Item::StatIdle ||
657 item.Owner->Status == pkgAcquire::Item::StatDone
661 [delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
662 withObject:[NSArray arrayWithObjects:[NSString stringWithUTF8String:item.Owner->ErrorText.c_str()], nil]
667 virtual bool Pulse(pkgAcquire *Owner) {
668 bool value = pkgAcquireStatus::Pulse(Owner);
671 double(CurrentBytes + CurrentItems) /
672 double(TotalBytes + TotalItems)
675 [delegate_ setProgressPercent:percent];
679 virtual void Start() {
682 virtual void Stop() {
686 /* Progress Delegation {{{ */
691 _transient id<ProgressDelegate> delegate_;
694 virtual void Update() {
695 [delegate_ setProgressTitle:[NSString stringWithUTF8String:Op.c_str()]];
696 [delegate_ setProgressPercent:(Percent / 100)];
705 void setDelegate(id delegate) {
706 delegate_ = delegate;
709 virtual void Done() {
710 [delegate_ setProgressPercent:1];
715 /* Database Interface {{{ */
716 @interface Database : NSObject {
718 pkgDepCache::Policy *policy_;
719 pkgRecords *records_;
720 pkgProblemResolver *resolver_;
721 pkgAcquire *fetcher_;
723 SPtr<pkgPackageManager> manager_;
724 pkgSourceList *list_;
726 NSMutableDictionary *sources_;
727 NSMutableArray *packages_;
729 _transient NSObject<ConfigurationDelegate, ProgressDelegate> *delegate_;
738 - (void) _readCydia:(NSNumber *)fd;
739 - (void) _readStatus:(NSNumber *)fd;
740 - (void) _readOutput:(NSNumber *)fd;
744 - (Package *) packageWithName:(NSString *)name;
747 - (pkgCacheFile &) cache;
748 - (pkgDepCache::Policy *) policy;
749 - (pkgRecords *) records;
750 - (pkgProblemResolver *) resolver;
751 - (pkgAcquire &) fetcher;
752 - (NSArray *) packages;
753 - (NSArray *) sources;
762 - (void) updateWithStatus:(Status &)status;
764 - (void) setDelegate:(id)delegate;
765 - (Source *) getSource:(const pkgCache::PkgFileIterator &)file;
769 /* Source Class {{{ */
770 @interface Source : NSObject {
771 NSString *description_;
776 NSString *distribution_;
780 NSString *defaultIcon_;
782 NSDictionary *record_;
786 - (Source *) initWithMetaIndex:(metaIndex *)index;
788 - (NSComparisonResult) compareByNameAndType:(Source *)source;
790 - (NSDictionary *) record;
794 - (NSString *) distribution;
800 - (NSString *) description;
801 - (NSString *) label;
802 - (NSString *) origin;
803 - (NSString *) version;
805 - (NSString *) defaultIcon;
809 @implementation Source
813 [distribution_ release];
816 if (description_ != nil)
817 [description_ release];
824 if (defaultIcon_ != nil)
825 [defaultIcon_ release];
832 + (NSArray *) _attributeKeys {
833 return [NSArray arrayWithObjects:@"description", @"distribution", @"host", @"key", @"label", @"name", @"origin", @"trusted", @"type", @"uri", @"version", nil];
836 - (NSArray *) attributeKeys {
837 return [[self class] _attributeKeys];
840 + (BOOL) isKeyExcludedFromWebScript:(const char *)name {
841 return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name];
844 - (Source *) initWithMetaIndex:(metaIndex *)index {
845 if ((self = [super init]) != nil) {
846 trusted_ = index->IsTrusted();
848 uri_ = [[NSString stringWithUTF8String:index->GetURI().c_str()] retain];
849 distribution_ = [[NSString stringWithUTF8String:index->GetDist().c_str()] retain];
850 type_ = [[NSString stringWithUTF8String:index->GetType()] retain];
858 debReleaseIndex *dindex(dynamic_cast<debReleaseIndex *>(index));
859 if (dindex != NULL) {
860 std::ifstream release(dindex->MetaIndexFile("Release").c_str());
862 while (std::getline(release, line)) {
863 std::string::size_type colon(line.find(':'));
864 if (colon == std::string::npos)
867 std::string name(line.substr(0, colon));
868 std::string value(line.substr(colon + 1));
869 while (!value.empty() && value[0] == ' ')
870 value = value.substr(1);
872 if (name == "Default-Icon")
873 defaultIcon_ = [[NSString stringWithUTF8String:value.c_str()] retain];
874 else if (name == "Description")
875 description_ = [[NSString stringWithUTF8String:value.c_str()] retain];
876 else if (name == "Label")
877 label_ = [[NSString stringWithUTF8String:value.c_str()] retain];
878 else if (name == "Origin")
879 origin_ = [[NSString stringWithUTF8String:value.c_str()] retain];
880 else if (name == "Version")
881 version_ = [[NSString stringWithUTF8String:value.c_str()] retain];
885 record_ = [Sources_ objectForKey:[self key]];
887 record_ = [record_ retain];
891 - (NSComparisonResult) compareByNameAndType:(Source *)source {
892 NSDictionary *lhr = [self record];
893 NSDictionary *rhr = [source record];
896 return lhr == nil ? NSOrderedDescending : NSOrderedAscending;
898 NSString *lhs = [self name];
899 NSString *rhs = [source name];
901 if ([lhs length] != 0 && [rhs length] != 0) {
902 unichar lhc = [lhs characterAtIndex:0];
903 unichar rhc = [rhs characterAtIndex:0];
905 if (isalpha(lhc) && !isalpha(rhc))
906 return NSOrderedAscending;
907 else if (!isalpha(lhc) && isalpha(rhc))
908 return NSOrderedDescending;
911 return [lhs caseInsensitiveCompare:rhs];
914 - (NSDictionary *) record {
926 - (NSString *) distribution {
927 return distribution_;
930 - (NSString *) type {
935 return [NSString stringWithFormat:@"%@:%@:%@", type_, uri_, distribution_];
938 - (NSString *) host {
939 return [[[NSURL URLWithString:[self uri]] host] lowercaseString];
942 - (NSString *) name {
943 return origin_ == nil ? [self host] : origin_;
946 - (NSString *) description {
950 - (NSString *) label {
951 return label_ == nil ? [self host] : label_;
954 - (NSString *) origin {
958 - (NSString *) version {
962 - (NSString *) defaultIcon {
968 /* Relationship Class {{{ */
969 @interface Relationship : NSObject {
980 @implementation Relationship
988 - (NSString *) type {
996 - (NSString *) name {
1003 /* Package Class {{{ */
1004 NSString *Scour(const char *field, const char *begin, const char *end) {
1005 size_t i(0), l(strlen(field));
1008 const char *name = begin + i;
1009 const char *colon = name + l;
1010 const char *value = colon + 1;
1015 memcmp(name, field, l) == 0
1017 while (value != end && value[0] == ' ')
1019 const char *line = std::find(value, end, '\n');
1020 while (line != value && line[-1] == ' ')
1023 return [NSString stringWithUTF8Bytes:value length:(line - value)];
1025 begin = std::find(begin, end, '\n');
1033 @interface Package : NSObject {
1034 pkgCache::PkgIterator iterator_;
1035 _transient Database *database_;
1036 pkgCache::VerIterator version_;
1037 pkgCache::VerFileIterator file_;
1043 NSString *installed_;
1049 NSString *homepage_;
1055 NSArray *relationships_;
1058 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
1059 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
1061 - (pkgCache::PkgIterator) iterator;
1063 - (NSString *) section;
1064 - (Address *) maintainer;
1066 - (NSString *) description;
1067 - (NSString *) index;
1071 - (NSString *) latest;
1072 - (NSString *) installed;
1075 - (BOOL) upgradableAndEssential:(BOOL)essential;
1081 - (BOOL) halfConfigured;
1082 - (BOOL) halfInstalled;
1084 - (NSString *) mode;
1087 - (NSString *) name;
1088 - (NSString *) tagline;
1089 - (NSString *) icon;
1090 - (NSString *) homepage;
1091 - (Address *) author;
1093 - (NSArray *) relationships;
1095 - (Source *) source;
1096 - (NSString *) role;
1098 - (BOOL) matches:(NSString *)text;
1100 - (bool) hasSupportingRole;
1101 - (BOOL) hasTag:(NSString *)tag;
1103 - (NSComparisonResult) compareByName:(Package *)package;
1104 - (NSComparisonResult) compareBySection:(Package *)package;
1105 - (NSComparisonResult) compareBySectionAndName:(Package *)package;
1106 - (NSComparisonResult) compareForChanges:(Package *)package;
1111 - (NSNumber *) isVisiblySearchedForBy:(NSString *)search;
1112 - (NSNumber *) isInstalledAndVisible:(NSNumber *)number;
1113 - (NSNumber *) isVisiblyUninstalledInSection:(NSString *)section;
1114 - (NSNumber *) isVisibleInSource:(Source *)source;
1118 @implementation Package
1125 if (installed_ != nil)
1126 [installed_ release];
1134 if (homepage_ != nil)
1135 [homepage_ release];
1136 if (sponsor_ != nil)
1145 if (relationships_ != nil)
1146 [relationships_ release];
1151 + (NSArray *) _attributeKeys {
1152 return [NSArray arrayWithObjects:@"author", @"description", @"essential", @"homepage", @"icon", @"id", @"installed", @"latest", @"maintainer", @"name", @"section", @"size", @"source", @"sponsor", @"tagline", nil];
1155 - (NSArray *) attributeKeys {
1156 return [[self class] _attributeKeys];
1159 + (BOOL) isKeyExcludedFromWebScript:(const char *)name {
1160 return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name];
1163 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
1164 if ((self = [super init]) != nil) {
1165 iterator_ = iterator;
1166 database_ = database;
1168 version_ = [database_ policy]->GetCandidateVer(iterator_);
1169 latest_ = version_.end() ? nil : [StripVersion([NSString stringWithUTF8String:version_.VerStr()]) retain];
1171 if (!version_.end())
1172 file_ = version_.FileList();
1174 pkgCache &cache([database_ cache]);
1175 file_ = pkgCache::VerFileIterator(cache, cache.VerFileP);
1178 pkgCache::VerIterator current = iterator_.CurrentVer();
1179 installed_ = current.end() ? nil : [StripVersion([NSString stringWithUTF8String:current.VerStr()]) retain];
1181 id_ = [[[NSString stringWithUTF8String:iterator_.Name()] lowercaseString] retain];
1184 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1186 const char *begin, *end;
1187 parser->GetRec(begin, end);
1189 name_ = Scour("Name", begin, end);
1191 name_ = [name_ retain];
1192 tagline_ = [[NSString stringWithUTF8String:parser->ShortDesc().c_str()] retain];
1193 icon_ = Scour("Icon", begin, end);
1195 icon_ = [icon_ retain];
1196 homepage_ = Scour("Homepage", begin, end);
1197 if (homepage_ == nil)
1198 homepage_ = Scour("Website", begin, end);
1199 if (homepage_ != nil)
1200 homepage_ = [homepage_ retain];
1201 NSString *sponsor = Scour("Sponsor", begin, end);
1203 sponsor_ = [[Address addressWithString:sponsor] retain];
1204 NSString *author = Scour("Author", begin, end);
1206 author_ = [[Address addressWithString:author] retain];
1207 NSString *tags = Scour("Tag", begin, end);
1209 tags_ = [[tags componentsSeparatedByString:@", "] retain];
1213 for (int i(0), e([tags_ count]); i != e; ++i) {
1214 NSString *tag = [tags_ objectAtIndex:i];
1215 if ([tag hasPrefix:@"role::"]) {
1216 role_ = [[tag substringFromIndex:6] retain];
1221 NSMutableDictionary *metadata = [Packages_ objectForKey:id_];
1222 if (metadata == nil || [metadata count] == 0) {
1223 metadata = [NSMutableDictionary dictionaryWithObjectsAndKeys:
1227 [Packages_ setObject:metadata forKey:id_];
1233 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
1234 return [[[Package alloc]
1235 initWithIterator:iterator
1240 - (pkgCache::PkgIterator) iterator {
1244 - (NSString *) section {
1245 const char *section = iterator_.Section();
1246 if (section == NULL)
1249 NSString *name = [[NSString stringWithUTF8String:section] stringByReplacingCharacter:' ' withCharacter:'_'];
1252 if (NSDictionary *value = [SectionMap_ objectForKey:name])
1253 if (NSString *rename = [value objectForKey:@"Rename"]) {
1258 return [name stringByReplacingCharacter:'_' withCharacter:' '];
1261 - (Address *) maintainer {
1264 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1265 return [Address addressWithString:[NSString stringWithUTF8String:parser->Maintainer().c_str()]];
1269 return version_.end() ? 0 : version_->InstalledSize;
1272 - (NSString *) description {
1275 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1276 NSString *description([NSString stringWithUTF8String:parser->LongDesc().c_str()]);
1278 NSArray *lines = [description componentsSeparatedByString:@"\n"];
1279 NSMutableArray *trimmed = [NSMutableArray arrayWithCapacity:([lines count] - 1)];
1280 if ([lines count] < 2)
1283 NSCharacterSet *whitespace = [NSCharacterSet whitespaceCharacterSet];
1284 for (size_t i(1); i != [lines count]; ++i) {
1285 NSString *trim = [[lines objectAtIndex:i] stringByTrimmingCharactersInSet:whitespace];
1286 [trimmed addObject:trim];
1289 return [trimmed componentsJoinedByString:@"\n"];
1292 - (NSString *) index {
1293 NSString *index = [[[self name] substringToIndex:1] uppercaseString];
1294 return [index length] != 0 && isalpha([index characterAtIndex:0]) ? index : @"123";
1298 return [[Packages_ objectForKey:id_] objectForKey:@"FirstSeen"];
1301 - (NSString *) latest {
1305 - (NSString *) installed {
1310 return !version_.end();
1313 - (BOOL) upgradableAndEssential:(BOOL)essential {
1314 pkgCache::VerIterator current = iterator_.CurrentVer();
1317 return essential && [self essential];
1319 pkgCache::VerIterator candidate = [database_ policy]->GetCandidateVer(iterator_);
1320 return !candidate.end() && candidate != current;
1324 - (BOOL) essential {
1325 return (iterator_->Flags & pkgCache::Flag::Essential) == 0 ? NO : YES;
1329 return [database_ cache][iterator_].InstBroken();
1333 NSString *section = [self section];
1334 return [self hasSupportingRole] && (section == nil || isSectionVisible(section));
1338 unsigned char current = iterator_->CurrentState;
1339 return current == pkgCache::State::HalfConfigured || current == pkgCache::State::HalfInstalled;
1342 - (BOOL) halfConfigured {
1343 return iterator_->CurrentState == pkgCache::State::HalfConfigured;
1346 - (BOOL) halfInstalled {
1347 return iterator_->CurrentState == pkgCache::State::HalfInstalled;
1351 pkgDepCache::StateCache &state([database_ cache][iterator_]);
1352 return state.Mode != pkgDepCache::ModeKeep;
1355 - (NSString *) mode {
1356 pkgDepCache::StateCache &state([database_ cache][iterator_]);
1358 switch (state.Mode) {
1359 case pkgDepCache::ModeDelete:
1360 if ((state.iFlags & pkgDepCache::Purge) != 0)
1365 case pkgDepCache::ModeKeep:
1366 if ((state.iFlags & pkgDepCache::AutoKept) != 0)
1371 case pkgDepCache::ModeInstall:
1372 if ((state.iFlags & pkgDepCache::ReInstall) != 0)
1373 return @"Reinstall";
1374 else switch (state.Status) {
1376 return @"Downgrade";
1382 return @"New Install";
1395 - (NSString *) name {
1396 return name_ == nil ? id_ : name_;
1399 - (NSString *) tagline {
1403 - (NSString *) icon {
1407 - (NSString *) homepage {
1411 - (Address *) sponsor {
1415 - (Address *) author {
1419 - (NSArray *) relationships {
1420 return relationships_;
1423 - (Source *) source {
1425 source_ = file_.end() ? nil : [[database_ getSource:file_.File()] retain];
1432 - (NSString *) role {
1436 - (BOOL) matches:(NSString *)text {
1442 range = [[self id] rangeOfString:text options:NSCaseInsensitiveSearch];
1443 if (range.location != NSNotFound)
1446 range = [[self name] rangeOfString:text options:NSCaseInsensitiveSearch];
1447 if (range.location != NSNotFound)
1450 range = [[self tagline] rangeOfString:text options:NSCaseInsensitiveSearch];
1451 if (range.location != NSNotFound)
1457 - (bool) hasSupportingRole {
1460 if ([role_ isEqualToString:@"enduser"])
1462 if ([Role_ isEqualToString:@"User"])
1464 if ([role_ isEqualToString:@"hacker"])
1466 if ([Role_ isEqualToString:@"Hacker"])
1468 if ([role_ isEqualToString:@"developer"])
1470 if ([Role_ isEqualToString:@"Developer"])
1475 - (BOOL) hasTag:(NSString *)tag {
1476 return tags_ == nil ? NO : [tags_ containsObject:tag];
1479 - (NSComparisonResult) compareByName:(Package *)package {
1480 NSString *lhs = [self name];
1481 NSString *rhs = [package name];
1483 if ([lhs length] != 0 && [rhs length] != 0) {
1484 unichar lhc = [lhs characterAtIndex:0];
1485 unichar rhc = [rhs characterAtIndex:0];
1487 if (isalpha(lhc) && !isalpha(rhc))
1488 return NSOrderedAscending;
1489 else if (!isalpha(lhc) && isalpha(rhc))
1490 return NSOrderedDescending;
1493 return [lhs caseInsensitiveCompare:rhs];
1496 - (NSComparisonResult) compareBySection:(Package *)package {
1497 NSString *lhs = [self section];
1498 NSString *rhs = [package section];
1500 if (lhs == NULL && rhs != NULL)
1501 return NSOrderedAscending;
1502 else if (lhs != NULL && rhs == NULL)
1503 return NSOrderedDescending;
1504 else if (lhs != NULL && rhs != NULL) {
1505 NSComparisonResult result = [lhs caseInsensitiveCompare:rhs];
1506 if (result != NSOrderedSame)
1510 return NSOrderedSame;
1513 - (NSComparisonResult) compareBySectionAndName:(Package *)package {
1514 NSString *lhs = [self section];
1515 NSString *rhs = [package section];
1517 if (lhs == NULL && rhs != NULL)
1518 return NSOrderedAscending;
1519 else if (lhs != NULL && rhs == NULL)
1520 return NSOrderedDescending;
1521 else if (lhs != NULL && rhs != NULL) {
1522 NSComparisonResult result = [lhs compare:rhs];
1523 if (result != NSOrderedSame)
1527 return [self compareByName:package];
1530 - (NSComparisonResult) compareForChanges:(Package *)package {
1531 BOOL lhs = [self upgradableAndEssential:YES];
1532 BOOL rhs = [package upgradableAndEssential:YES];
1535 return lhs ? NSOrderedAscending : NSOrderedDescending;
1537 switch ([[self seen] compare:[package seen]]) {
1538 case NSOrderedAscending:
1539 return NSOrderedDescending;
1542 case NSOrderedDescending:
1543 return NSOrderedAscending;
1549 return [self compareByName:package];
1553 pkgProblemResolver *resolver = [database_ resolver];
1554 resolver->Clear(iterator_);
1555 resolver->Protect(iterator_);
1556 pkgCacheFile &cache([database_ cache]);
1557 cache->MarkInstall(iterator_, false);
1558 pkgDepCache::StateCache &state((*cache)[iterator_]);
1559 if (!state.Install())
1560 cache->SetReInstall(iterator_, true);
1564 pkgProblemResolver *resolver = [database_ resolver];
1565 resolver->Clear(iterator_);
1566 resolver->Protect(iterator_);
1567 resolver->Remove(iterator_);
1568 [database_ cache]->MarkDelete(iterator_, true);
1571 - (NSNumber *) isVisiblySearchedForBy:(NSString *)search {
1572 return [NSNumber numberWithBool:(
1573 [self valid] && [self visible] && [self matches:search]
1577 - (NSNumber *) isInstalledAndVisible:(NSNumber *)number {
1578 return [NSNumber numberWithBool:(
1579 (![number boolValue] || [self visible]) && [self installed] != nil
1583 - (NSNumber *) isVisiblyUninstalledInSection:(NSString *)name {
1584 NSString *section = [self section];
1586 return [NSNumber numberWithBool:(
1587 [self valid] && [self visible] &&
1588 [self installed] == nil && (
1590 section == nil && [name length] == 0 ||
1591 [name isEqualToString:section]
1596 - (NSNumber *) isVisibleInSource:(Source *)source {
1597 return [NSNumber numberWithBool:([self source] == source && [self visible])];
1602 /* Section Class {{{ */
1603 @interface Section : NSObject {
1609 - (NSComparisonResult) compareByName:(Section *)section;
1610 - (Section *) initWithName:(NSString *)name;
1611 - (Section *) initWithName:(NSString *)name row:(size_t)row;
1612 - (NSString *) name;
1615 - (void) addToCount;
1619 @implementation Section
1626 - (NSComparisonResult) compareByName:(Section *)section {
1627 NSString *lhs = [self name];
1628 NSString *rhs = [section name];
1630 if ([lhs length] != 0 && [rhs length] != 0) {
1631 unichar lhc = [lhs characterAtIndex:0];
1632 unichar rhc = [rhs characterAtIndex:0];
1634 if (isalpha(lhc) && !isalpha(rhc))
1635 return NSOrderedAscending;
1636 else if (!isalpha(lhc) && isalpha(rhc))
1637 return NSOrderedDescending;
1640 return [lhs caseInsensitiveCompare:rhs];
1643 - (Section *) initWithName:(NSString *)name {
1644 return [self initWithName:name row:0];
1647 - (Section *) initWithName:(NSString *)name row:(size_t)row {
1648 if ((self = [super init]) != nil) {
1649 name_ = [name retain];
1654 - (NSString *) name {
1666 - (void) addToCount {
1673 /* Database Implementation {{{ */
1674 @implementation Database
1681 - (void) _readCydia:(NSNumber *)fd {
1682 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1684 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1685 std::istream is(&ib);
1688 while (std::getline(is, line)) {
1689 const char *data(line.c_str());
1690 //size_t size = line.size();
1691 fprintf(stderr, "C:%s\n", data);
1698 - (void) _readStatus:(NSNumber *)fd {
1699 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1701 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1702 std::istream is(&ib);
1705 static Pcre conffile_r("^status: [^ ]* : conffile-prompt : (.*?) *$");
1706 static Pcre pmstatus_r("^([^:]*):([^:]*):([^:]*):(.*)$");
1708 while (std::getline(is, line)) {
1709 const char *data(line.c_str());
1710 size_t size = line.size();
1711 fprintf(stderr, "S:%s\n", data);
1713 if (conffile_r(data, size)) {
1714 [delegate_ setConfigurationData:conffile_r[1]];
1715 } else if (strncmp(data, "status: ", 8) == 0) {
1716 NSString *string = [NSString stringWithUTF8String:(data + 8)];
1717 [delegate_ setProgressTitle:string];
1718 } else if (pmstatus_r(data, size)) {
1719 std::string type([pmstatus_r[1] UTF8String]);
1720 NSString *id = pmstatus_r[2];
1722 float percent([pmstatus_r[3] floatValue]);
1723 [delegate_ setProgressPercent:(percent / 100)];
1725 NSString *string = pmstatus_r[4];
1727 if (type == "pmerror")
1728 [delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
1729 withObject:[NSArray arrayWithObjects:string, id, nil]
1732 else if (type == "pmstatus")
1733 [delegate_ setProgressTitle:string];
1734 else if (type == "pmconffile")
1735 [delegate_ setConfigurationData:string];
1736 else _assert(false);
1737 } else _assert(false);
1744 - (void) _readOutput:(NSNumber *)fd {
1745 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1747 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1748 std::istream is(&ib);
1751 while (std::getline(is, line)) {
1752 fprintf(stderr, "O:%s\n", line.c_str());
1753 [delegate_ addProgressOutput:[NSString stringWithUTF8String:line.c_str()]];
1764 - (Package *) packageWithName:(NSString *)name {
1765 if (static_cast<pkgDepCache *>(cache_) == NULL)
1767 pkgCache::PkgIterator iterator(cache_->FindPkg([name UTF8String]));
1768 return iterator.end() ? nil : [Package packageWithIterator:iterator database:self];
1771 - (Database *) init {
1772 if ((self = [super init]) != nil) {
1779 sources_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1780 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
1784 _assert(pipe(fds) != -1);
1787 _config->Set("APT::Keep-Fds::", cydiafd_);
1788 setenv("CYDIA", [[[[NSNumber numberWithInt:cydiafd_] stringValue] stringByAppendingString:@" 0"] UTF8String], _not(int));
1791 detachNewThreadSelector:@selector(_readCydia:)
1793 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1796 _assert(pipe(fds) != -1);
1800 detachNewThreadSelector:@selector(_readStatus:)
1802 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1805 _assert(pipe(fds) != -1);
1806 _assert(dup2(fds[0], 0) != -1);
1807 _assert(close(fds[0]) != -1);
1809 input_ = fdopen(fds[1], "a");
1811 _assert(pipe(fds) != -1);
1812 _assert(dup2(fds[1], 1) != -1);
1813 _assert(close(fds[1]) != -1);
1816 detachNewThreadSelector:@selector(_readOutput:)
1818 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1823 - (pkgCacheFile &) cache {
1827 - (pkgDepCache::Policy *) policy {
1831 - (pkgRecords *) records {
1835 - (pkgProblemResolver *) resolver {
1839 - (pkgAcquire &) fetcher {
1843 - (NSArray *) packages {
1847 - (NSArray *) sources {
1848 return [sources_ allValues];
1851 - (void) reloadData {
1870 if (!cache_.Open(progress_, true)) {
1872 if (!_error->PopMessage(error))
1875 fprintf(stderr, "cache_.Open():[%s]\n", error.c_str());
1877 if (error == "dpkg was interrupted, you must manually run 'dpkg --configure -a' to correct the problem. ")
1878 [delegate_ repairWithSelector:@selector(configure)];
1879 else if (error == "The package lists or status file could not be parsed or opened.")
1880 [delegate_ repairWithSelector:@selector(update)];
1881 // else if (error == "Could not open lock file /var/lib/dpkg/lock - open (13 Permission denied)")
1882 // else if (error == "Could not get lock /var/lib/dpkg/lock - open (35 Resource temporarily unavailable)")
1883 // else if (error == "The list of sources could not be read.")
1884 else _assert(false);
1889 now_ = [[NSDate date] retain];
1891 policy_ = new pkgDepCache::Policy();
1892 records_ = new pkgRecords(cache_);
1893 resolver_ = new pkgProblemResolver(cache_);
1894 fetcher_ = new pkgAcquire(&status_);
1897 list_ = new pkgSourceList();
1898 _assert(list_->ReadMainList());
1900 _assert(cache_->DelCount() == 0 && cache_->InstCount() == 0);
1901 _assert(pkgApplyStatus(cache_));
1903 if (cache_->BrokenCount() != 0) {
1904 _assert(pkgFixBroken(cache_));
1905 _assert(cache_->BrokenCount() == 0);
1906 _assert(pkgMinimizeUpgrade(cache_));
1909 [sources_ removeAllObjects];
1910 for (pkgSourceList::const_iterator source = list_->begin(); source != list_->end(); ++source) {
1911 std::vector<pkgIndexFile *> *indices = (*source)->GetIndexFiles();
1912 for (std::vector<pkgIndexFile *>::const_iterator index = indices->begin(); index != indices->end(); ++index)
1914 setObject:[[[Source alloc] initWithMetaIndex:*source] autorelease]
1915 forKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(*index)]
1919 [packages_ removeAllObjects];
1920 for (pkgCache::PkgIterator iterator = cache_->PkgBegin(); !iterator.end(); ++iterator)
1921 if (Package *package = [Package packageWithIterator:iterator database:self])
1922 [packages_ addObject:package];
1924 [packages_ sortUsingSelector:@selector(compareByName:)];
1927 - (void) configure {
1928 NSString *dpkg = [NSString stringWithFormat:@"dpkg --configure -a --status-fd %u", statusfd_];
1929 system([dpkg UTF8String]);
1937 Lock.Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1938 _assert(!_error->PendingError());
1941 fetcher.Clean(_config->FindDir("Dir::Cache::Archives"));
1944 public pkgArchiveCleaner
1947 virtual void Erase(const char *File, std::string Pkg, std::string Ver, struct stat &St) {
1952 if (!cleaner.Go(_config->FindDir("Dir::Cache::Archives") + "partial/", cache_)) {
1954 while (_error->PopMessage(error))
1955 fprintf(stderr, "ArchiveCleaner: %s\n", error.c_str());
1960 pkgRecords records(cache_);
1962 lock_ = new FileFd();
1963 lock_->Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1964 _assert(!_error->PendingError());
1967 // XXX: explain this with an error message
1968 _assert(list.ReadMainList());
1970 manager_ = (_system->CreatePM(cache_));
1971 _assert(manager_->GetArchives(fetcher_, &list, &records));
1972 _assert(!_error->PendingError());
1976 NSMutableArray *before = [NSMutableArray arrayWithCapacity:16]; {
1978 _assert(list.ReadMainList());
1979 for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source)
1980 [before addObject:[NSString stringWithUTF8String:(*source)->GetURI().c_str()]];
1983 if (fetcher_->Run(PulseInterval_) != pkgAcquire::Continue) {
1988 bool failed = false;
1989 for (pkgAcquire::ItemIterator item = fetcher_->ItemsBegin(); item != fetcher_->ItemsEnd(); item++) {
1990 if ((*item)->Status == pkgAcquire::Item::StatDone && (*item)->Complete)
1993 std::string uri = (*item)->DescURI();
1994 std::string error = (*item)->ErrorText;
1996 fprintf(stderr, "pAf:%s:%s\n", uri.c_str(), error.c_str());
1999 [delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
2000 withObject:[NSArray arrayWithObjects:[NSString stringWithUTF8String:error.c_str()], nil]
2011 pkgPackageManager::OrderResult result = manager_->DoInstall(statusfd_);
2013 if (_error->PendingError()) {
2018 if (result == pkgPackageManager::Failed) {
2023 if (result != pkgPackageManager::Completed) {
2028 NSMutableArray *after = [NSMutableArray arrayWithCapacity:16]; {
2030 _assert(list.ReadMainList());
2031 for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source)
2032 [after addObject:[NSString stringWithUTF8String:(*source)->GetURI().c_str()]];
2035 if (![before isEqualToArray:after])
2040 _assert(pkgDistUpgrade(cache_));
2044 [self updateWithStatus:status_];
2047 - (void) updateWithStatus:(Status &)status {
2049 _assert(list.ReadMainList());
2052 lock.Fd(GetLock(_config->FindDir("Dir::State::Lists") + "lock"));
2053 _assert(!_error->PendingError());
2055 pkgAcquire fetcher(&status);
2056 _assert(list.GetIndexes(&fetcher));
2058 if (fetcher.Run(PulseInterval_) != pkgAcquire::Failed) {
2059 bool failed = false;
2060 for (pkgAcquire::ItemIterator item = fetcher.ItemsBegin(); item != fetcher.ItemsEnd(); item++)
2061 if ((*item)->Status != pkgAcquire::Item::StatDone) {
2062 (*item)->Finished();
2066 if (!failed && _config->FindB("APT::Get::List-Cleanup", true) == true) {
2067 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists")));
2068 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/"));
2071 [Metadata_ setObject:[NSDate date] forKey:@"LastUpdate"];
2076 - (void) setDelegate:(id)delegate {
2077 delegate_ = delegate;
2078 status_.setDelegate(delegate);
2079 progress_.setDelegate(delegate);
2082 - (Source *) getSource:(const pkgCache::PkgFileIterator &)file {
2083 pkgIndexFile *index(NULL);
2084 list_->FindIndex(file, index);
2085 return [sources_ objectForKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(index)]];
2091 /* Confirmation View {{{ */
2092 void AddTextView(NSMutableDictionary *fields, NSMutableArray *packages, NSString *key) {
2093 if ([packages count] == 0)
2096 UITextView *text = GetTextView([packages count] == 0 ? @"n/a" : [packages componentsJoinedByString:@", "], 120, false);
2097 [fields setObject:text forKey:key];
2099 CGColor blue(space_, 0, 0, 0.4, 1);
2100 [text setTextColor:blue];
2103 @protocol ConfirmationViewDelegate
2108 @interface ConfirmationView : UIView {
2109 Database *database_;
2111 UITransitionView *transition_;
2113 UINavigationBar *navbar_;
2114 UIPreferencesTable *table_;
2115 NSMutableDictionary *fields_;
2116 UIAlertSheet *essential_;
2121 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate;
2125 @implementation ConfirmationView
2128 [navbar_ setDelegate:nil];
2129 [transition_ setDelegate:nil];
2130 [table_ setDataSource:nil];
2132 [transition_ release];
2137 if (essential_ != nil)
2138 [essential_ release];
2143 [transition_ transition:7 toView:nil];
2147 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
2148 if (from != nil && to == nil)
2149 [self removeFromSuperview];
2152 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2155 if (essential_ != nil)
2156 [essential_ popupAlertAnimated:YES];
2158 [delegate_ confirm];
2167 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
2168 NSString *context = [sheet context];
2170 if ([context isEqualToString:@"remove"])
2176 [delegate_ confirm];
2181 else if ([context isEqualToString:@"unable"])
2187 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
2191 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
2193 case 0: return @"Statistics";
2194 case 1: return @"Modifications";
2196 default: _assert(false);
2200 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
2203 case 1: return [fields_ count];
2205 default: _assert(false);
2209 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
2210 if (group != 1 || row == -1)
2213 _assert(size_t(row) < [fields_ count]);
2214 return [[[fields_ allValues] objectAtIndex:row] visibleTextRect].size.height + TextViewOffset_;
2218 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
2219 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
2220 [cell setShowSelection:NO];
2223 case 0: switch (row) {
2225 [cell setTitle:@"Downloading"];
2226 [cell setValue:SizeString([database_ fetcher].FetchNeeded())];
2230 [cell setTitle:@"Resuming At"];
2231 [cell setValue:SizeString([database_ fetcher].PartialPresent())];
2235 double size([database_ cache]->UsrSize());
2238 [cell setTitle:@"Disk Freeing"];
2239 [cell setValue:SizeString(-size)];
2241 [cell setTitle:@"Disk Using"];
2242 [cell setValue:SizeString(size)];
2246 default: _assert(false);
2250 _assert(size_t(row) < [fields_ count]);
2251 [cell setTitle:[[fields_ allKeys] objectAtIndex:row]];
2252 [cell addSubview:[[fields_ allValues] objectAtIndex:row]];
2255 default: _assert(false);
2261 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate {
2262 if ((self = [super initWithFrame:[view bounds]]) != nil) {
2263 database_ = database;
2264 delegate_ = delegate;
2266 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
2267 [self addSubview:transition_];
2269 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
2271 CGSize navsize = [UINavigationBar defaultSize];
2272 CGRect navrect = {{0, 0}, navsize};
2273 CGRect bounds = [overlay_ bounds];
2275 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
2277 [navbar_ setBarStyle:1];
2278 [navbar_ setDelegate:self];
2280 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Confirm"] autorelease];
2281 [navbar_ pushNavigationItem:navitem];
2282 [navbar_ showButtonsWithLeftTitle:@"Cancel" rightTitle:@"Confirm"];
2284 fields_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
2286 NSMutableArray *installing = [NSMutableArray arrayWithCapacity:16];
2287 NSMutableArray *reinstalling = [NSMutableArray arrayWithCapacity:16];
2288 NSMutableArray *upgrading = [NSMutableArray arrayWithCapacity:16];
2289 NSMutableArray *downgrading = [NSMutableArray arrayWithCapacity:16];
2290 NSMutableArray *removing = [NSMutableArray arrayWithCapacity:16];
2294 pkgCacheFile &cache([database_ cache]);
2295 NSArray *packages = [database_ packages];
2296 for (size_t i(0), e = [packages count]; i != e; ++i) {
2297 Package *package = [packages objectAtIndex:i];
2298 pkgCache::PkgIterator iterator = [package iterator];
2299 pkgDepCache::StateCache &state(cache[iterator]);
2301 NSString *name([package name]);
2303 if (state.NewInstall())
2304 [installing addObject:name];
2305 else if (!state.Delete() && (state.iFlags & pkgDepCache::ReInstall) == pkgDepCache::ReInstall)
2306 [reinstalling addObject:name];
2307 else if (state.Upgrade())
2308 [upgrading addObject:name];
2309 else if (state.Downgrade())
2310 [downgrading addObject:name];
2311 else if (state.Delete()) {
2312 if ([package essential])
2314 [removing addObject:name];
2320 else if (Advanced_ || true) {
2321 essential_ = [[UIAlertSheet alloc]
2322 initWithTitle:@"Removing Essentials"
2323 buttons:[NSArray arrayWithObjects:
2324 @"Cancel Operation (Safe)",
2325 @"Force Removal (Unsafe)",
2327 defaultButtonIndex:0
2333 [essential_ setDestructiveButton:[[essential_ buttons] objectAtIndex:0]];
2335 [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."];
2337 essential_ = [[UIAlertSheet alloc]
2338 initWithTitle:@"Unable to Comply"
2339 buttons:[NSArray arrayWithObjects:@"Okay", nil]
2340 defaultButtonIndex:0
2345 [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."];
2348 AddTextView(fields_, installing, @"Installing");
2349 AddTextView(fields_, reinstalling, @"Reinstalling");
2350 AddTextView(fields_, upgrading, @"Upgrading");
2351 AddTextView(fields_, downgrading, @"Downgrading");
2352 AddTextView(fields_, removing, @"Removing");
2354 table_ = [[UIPreferencesTable alloc] initWithFrame:CGRectMake(
2355 0, navsize.height, bounds.size.width, bounds.size.height - navsize.height
2358 [table_ setReusesTableCells:YES];
2359 [table_ setDataSource:self];
2360 [table_ reloadData];
2362 [overlay_ addSubview:navbar_];
2363 [overlay_ addSubview:table_];
2365 [view addSubview:self];
2367 [transition_ setDelegate:self];
2369 UIView *blank = [[[UIView alloc] initWithFrame:[transition_ bounds]] autorelease];
2370 [transition_ transition:0 toView:blank];
2371 [transition_ transition:3 toView:overlay_];
2378 /* Progress Data {{{ */
2379 @interface ProgressData : NSObject {
2385 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object;
2392 @implementation ProgressData
2394 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object {
2395 if ((self = [super init]) != nil) {
2396 selector_ = selector;
2416 /* Progress View {{{ */
2417 @interface ProgressView : UIView <
2418 ConfigurationDelegate,
2421 _transient Database *database_;
2423 UIView *background_;
2424 UITransitionView *transition_;
2426 UINavigationBar *navbar_;
2427 UIProgressBar *progress_;
2428 UITextView *output_;
2429 UITextLabel *status_;
2430 UIPushButton *close_;
2435 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
2437 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database delegate:(id)delegate;
2438 - (void) setContentView:(UIView *)view;
2441 - (void) _retachThread;
2442 - (void) _detachNewThreadData:(ProgressData *)data;
2443 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title;
2449 @protocol ProgressViewDelegate
2450 - (void) progressViewIsComplete:(ProgressView *)sender;
2453 @implementation ProgressView
2456 [transition_ setDelegate:nil];
2457 [navbar_ setDelegate:nil];
2460 if (background_ != nil)
2461 [background_ release];
2462 [transition_ release];
2465 [progress_ release];
2472 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
2473 if (bootstrap_ && from == overlay_ && to == view_)
2477 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database delegate:(id)delegate {
2478 if ((self = [super initWithFrame:frame]) != nil) {
2479 database_ = database;
2480 delegate_ = delegate;
2482 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
2483 [transition_ setDelegate:self];
2485 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
2488 [overlay_ setBackgroundColor:Black_];
2490 background_ = [[UIView alloc] initWithFrame:[self bounds]];
2491 [background_ setBackgroundColor:Black_];
2492 [self addSubview:background_];
2495 [self addSubview:transition_];
2497 CGSize navsize = [UINavigationBar defaultSize];
2498 CGRect navrect = {{0, 0}, navsize};
2500 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
2501 [overlay_ addSubview:navbar_];
2503 [navbar_ setBarStyle:1];
2504 [navbar_ setDelegate:self];
2506 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:nil] autorelease];
2507 [navbar_ pushNavigationItem:navitem];
2509 CGRect bounds = [overlay_ bounds];
2510 CGSize prgsize = [UIProgressBar defaultSize];
2513 (bounds.size.width - prgsize.width) / 2,
2514 bounds.size.height - prgsize.height - 20
2517 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
2518 [progress_ setStyle:0];
2520 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(
2522 bounds.size.height - prgsize.height - 50,
2523 bounds.size.width - 20,
2527 [status_ setColor:White_];
2528 [status_ setBackgroundColor:Clear_];
2530 [status_ setCentersHorizontally:YES];
2531 //[status_ setFont:font];
2533 output_ = [[UITextView alloc] initWithFrame:CGRectMake(
2535 navrect.size.height + 20,
2536 bounds.size.width - 20,
2537 bounds.size.height - navsize.height - 62 - navrect.size.height
2540 //[output_ setTextFont:@"Courier New"];
2541 [output_ setTextSize:12];
2543 [output_ setTextColor:White_];
2544 [output_ setBackgroundColor:Clear_];
2546 [output_ setMarginTop:0];
2547 [output_ setAllowsRubberBanding:YES];
2548 [output_ setEditable:NO];
2550 [overlay_ addSubview:output_];
2552 close_ = [[UIPushButton alloc] initWithFrame:CGRectMake(
2554 bounds.size.height - prgsize.height - 50,
2555 bounds.size.width - 20,
2559 [close_ setAutosizesToFit:NO];
2560 [close_ setDrawsShadow:YES];
2561 [close_ setStretchBackground:YES];
2562 [close_ setTitle:@"Return to Cydia"];
2563 [close_ setEnabled:YES];
2565 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22);
2566 [close_ setTitleFont:bold];
2569 [close_ addTarget:self action:@selector(closeButtonPushed) forEvents:kUIControlEventMouseUpInside];
2570 [close_ setBackground:[UIImage applicationImageNamed:@"green-up.png"] forState:0];
2571 [close_ setBackground:[UIImage applicationImageNamed:@"green-dn.png"] forState:1];
2575 - (void) setContentView:(UIView *)view {
2576 view_ = [view retain];
2579 - (void) resetView {
2580 [transition_ transition:6 toView:view_];
2583 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
2584 NSString *context = [sheet context];
2585 if ([context isEqualToString:@"conffile"]) {
2586 FILE *input = [database_ input];
2590 fprintf(input, "N\n");
2594 fprintf(input, "Y\n");
2605 - (void) closeButtonPushed {
2606 [delegate_ progressViewIsComplete:self];
2610 - (void) _retachThread {
2611 UINavigationItem *item = [navbar_ topItem];
2612 [item setTitle:@"Complete"];
2614 [overlay_ addSubview:close_];
2615 [progress_ removeFromSuperview];
2616 [status_ removeFromSuperview];
2619 notify_post("com.apple.mobile.application_installed");
2622 [delegate_ setStatusBarShowsProgress:NO];
2627 - (void) _detachNewThreadData:(ProgressData *)data {
2628 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
2630 [[data target] performSelector:[data selector] withObject:[data object]];
2633 [self performSelectorOnMainThread:@selector(_retachThread) withObject:nil waitUntilDone:YES];
2638 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title {
2639 UINavigationItem *item = [navbar_ topItem];
2640 [item setTitle:title];
2642 [status_ setText:nil];
2643 [output_ setText:@""];
2644 [progress_ setProgress:0];
2646 [close_ removeFromSuperview];
2647 [overlay_ addSubview:progress_];
2648 [overlay_ addSubview:status_];
2650 [delegate_ setStatusBarShowsProgress:YES];
2653 [transition_ transition:6 toView:overlay_];
2656 detachNewThreadSelector:@selector(_detachNewThreadData:)
2658 withObject:[[ProgressData alloc]
2659 initWithSelector:selector
2666 - (void) repairWithSelector:(SEL)selector {
2668 detachNewThreadSelector:selector
2671 title:@"Repairing..."
2675 - (void) setConfigurationData:(NSString *)data {
2677 performSelectorOnMainThread:@selector(_setConfigurationData:)
2683 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id {
2684 Package *package = id == nil ? nil : [database_ packageWithName:id];
2686 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
2687 initWithTitle:(package == nil ? @"Source Error" : [package name])
2688 buttons:[NSArray arrayWithObjects:@"Okay", nil]
2689 defaultButtonIndex:0
2694 [sheet setBodyText:error];
2695 [sheet popupAlertAnimated:YES];
2698 - (void) setProgressTitle:(NSString *)title {
2700 performSelectorOnMainThread:@selector(_setProgressTitle:)
2706 - (void) setProgressPercent:(float)percent {
2708 performSelectorOnMainThread:@selector(_setProgressPercent:)
2709 withObject:[NSNumber numberWithFloat:percent]
2714 - (void) addProgressOutput:(NSString *)output {
2716 performSelectorOnMainThread:@selector(_addProgressOutput:)
2722 - (void) _setConfigurationData:(NSString *)data {
2723 static Pcre conffile_r("^'(.*)' '(.*)' ([01]) ([01])$");
2725 _assert(conffile_r(data));
2727 NSString *ofile = conffile_r[1];
2728 //NSString *nfile = conffile_r[2];
2730 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
2731 initWithTitle:@"Configuration Upgrade"
2732 buttons:[NSArray arrayWithObjects:
2733 @"Keep My Old Copy",
2734 @"Accept The New Copy",
2735 // XXX: @"See What Changed",
2737 defaultButtonIndex:0
2742 [sheet setBodyText:[NSString stringWithFormat:
2743 @"The following file has been changed by both the package maintainer and by you (or for you by a script).\n\n%@"
2746 [sheet popupAlertAnimated:YES];
2749 - (void) _setProgressTitle:(NSString *)title {
2750 [status_ setText:[title stringByAppendingString:@"..."]];
2753 - (void) _setProgressPercent:(NSNumber *)percent {
2754 [progress_ setProgress:[percent floatValue]];
2757 - (void) _addProgressOutput:(NSString *)output {
2758 [output_ setText:[NSString stringWithFormat:@"%@\n%@", [output_ text], output]];
2759 CGSize size = [output_ contentSize];
2760 CGRect rect = {{0, size.height}, {size.width, 0}};
2761 [output_ scrollRectToVisible:rect animated:YES];
2764 - (BOOL) isRunning {
2771 /* Package Cell {{{ */
2772 @interface PackageCell : UISimpleTableCell {
2775 NSString *description_;
2777 //UIImageView *trusted_;
2779 UIImageView *badge_;
2780 UITextLabel *status_;
2784 - (PackageCell *) init;
2785 - (void) setPackage:(Package *)package;
2787 + (int) heightForPackage:(Package *)package;
2791 @implementation PackageCell
2793 - (void) clearPackage {
2804 if (description_ != nil) {
2805 [description_ release];
2809 if (source_ != nil) {
2816 [self clearPackage];
2821 //[trusted_ release];
2825 - (PackageCell *) init {
2826 if ((self = [super init]) != nil) {
2828 badge_ = [[UIImageView alloc] initWithFrame:CGRectMake(17, 70, 16, 16)];
2830 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 68, 280, 20)];
2831 [status_ setBackgroundColor:Clear_];
2832 [status_ setFont:small];
2837 - (void) setPackage:(Package *)package {
2838 [self clearPackage];
2840 Source *source = [package source];
2843 if (NSString *icon = [package icon])
2844 icon_ = [UIImage imageAtPath:[icon substringFromIndex:6]];
2845 if (icon_ == nil) if (NSString *section = [package section])
2846 icon_ = [UIImage applicationImageNamed:[NSString stringWithFormat:@"Sections/%@.png", Simplify(section)]];
2847 /*if (icon_ == nil) if (NSString *icon = [source defaultIcon])
2848 icon_ = [UIImage imageAtPath:[icon substringFromIndex:6]];*/
2850 icon_ = [UIImage applicationImageNamed:@"unknown.png"];
2852 icon_ = [icon_ retain];
2854 name_ = [[package name] retain];
2855 description_ = [[package tagline] retain];
2857 NSString *label = nil;
2858 bool trusted = false;
2860 if (source != nil) {
2861 label = [source label];
2862 trusted = [source trusted];
2863 } else if ([[package id] isEqualToString:@"firmware"])
2866 label = @"Unknown/Local";
2868 NSString *from = [NSString stringWithFormat:@"from %@", label];
2870 NSString *section = Simplify([package section]);
2871 if (section != nil && ![section isEqualToString:label])
2872 from = [from stringByAppendingString:[NSString stringWithFormat:@" (%@)", section]];
2874 source_ = [from retain];
2877 [badge_ removeFromSuperview];
2878 [status_ removeFromSuperview];
2880 if (NSString *mode = [package mode]) {
2881 [badge_ setImage:[UIImage applicationImageNamed:
2882 [mode isEqualToString:@"Remove"] || [mode isEqualToString:@"Purge"] ? @"removing.png" : @"installing.png"
2885 [status_ setText:[NSString stringWithFormat:@"Queued for %@", mode]];
2886 [status_ setColor:Blueish_];
2887 } else if ([package half]) {
2888 [badge_ setImage:[UIImage applicationImageNamed:@"damaged.png"]];
2889 [status_ setText:@"Package Damaged"];
2890 [status_ setColor:Red_];
2892 [badge_ setImage:nil];
2893 [status_ setText:nil];
2897 [self addSubview:badge_];
2898 [self addSubview:status_];
2903 - (void) drawContentInRect:(CGRect)rect selected:(BOOL)selected {
2905 [icon_ drawInRect:CGRectMake(10, 10, 30, 30)];
2912 [name_ drawAtPoint:CGPointMake(48, 8) forWidth:240 withFont:Font18Bold_ ellipsis:2];
2913 [source_ drawAtPoint:CGPointMake(58, 29) forWidth:225 withFont:Font12_ ellipsis:2];
2917 [description_ drawAtPoint:CGPointMake(12, 46) forWidth:280 withFont:Font14_ ellipsis:2];
2919 [super drawContentInRect:rect selected:selected];
2922 + (int) heightForPackage:(Package *)package {
2923 NSString *tagline([package tagline]);
2924 int height = tagline == nil || [tagline length] == 0 ? -17 : 0;
2926 if ([package hasMode] || [package half])
2935 /* Section Cell {{{ */
2936 @interface SectionCell : UISimpleTableCell {
2941 UISwitchControl *switch_;
2946 - (void) setSection:(Section *)section editing:(BOOL)editing;
2950 @implementation SectionCell
2952 - (void) clearSection {
2953 if (section_ != nil) {
2963 if (count_ != nil) {
2970 [self clearSection];
2977 if ((self = [super init]) != nil) {
2978 icon_ = [[UIImage applicationImageNamed:@"folder.png"] retain];
2980 switch_ = [[UISwitchControl alloc] initWithFrame:CGRectMake(218, 9, 60, 25)];
2981 [switch_ addTarget:self action:@selector(onSwitch:) forEvents:kUIControlEventMouseUpInside];
2985 - (void) onSwitch:(id)sender {
2986 NSMutableDictionary *metadata = [Sections_ objectForKey:section_];
2987 if (metadata == nil) {
2988 metadata = [NSMutableDictionary dictionaryWithCapacity:2];
2989 [Sections_ setObject:metadata forKey:section_];
2993 [metadata setObject:[NSNumber numberWithBool:([switch_ value] == 0)] forKey:@"Hidden"];
2996 - (void) setSection:(Section *)section editing:(BOOL)editing {
2997 if (editing != editing_) {
2999 [switch_ removeFromSuperview];
3001 [self addSubview:switch_];
3005 [self clearSection];
3007 if (section == nil) {
3008 name_ = [@"All Packages" retain];
3011 section_ = [section name];
3012 if (section_ != nil)
3013 section_ = [section_ retain];
3014 name_ = [(section_ == nil ? @"(No Section)" : section_) retain];
3015 count_ = [[NSString stringWithFormat:@"%d", [section count]] retain];
3018 [switch_ setValue:isSectionVisible(section_) animated:NO];
3022 - (void) drawContentInRect:(CGRect)rect selected:(BOOL)selected {
3023 [icon_ drawInRect:CGRectMake(8, 7, 32, 32)];
3030 [name_ drawAtPoint:CGPointMake(48, 9) forWidth:(editing_ ? 164 : 250) withFont:Font22Bold_ ellipsis:2];
3032 CGSize size = [count_ sizeWithFont:Font14_];
3036 [count_ drawAtPoint:CGPointMake(12 + (29 - size.width) / 2, 15) withFont:Font12Bold_];
3038 [super drawContentInRect:rect selected:selected];
3044 /* File Table {{{ */
3045 @interface FileTable : RVPage {
3046 _transient Database *database_;
3049 NSMutableArray *files_;
3053 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3054 - (void) setPackage:(Package *)package;
3058 @implementation FileTable
3061 if (package_ != nil)
3070 - (int) numberOfRowsInTable:(UITable *)table {
3071 return files_ == nil ? 0 : [files_ count];
3074 - (float) table:(UITable *)table heightForRow:(int)row {
3078 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
3079 if (reusing == nil) {
3080 reusing = [[[UIImageAndTextTableCell alloc] init] autorelease];
3081 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
3082 [[(UIImageAndTextTableCell *)reusing titleTextLabel] setFont:font];
3085 [(UIImageAndTextTableCell *)reusing setTitle:[files_ objectAtIndex:row]];
3089 - (BOOL) table:(UITable *)table canSelectRow:(int)row {
3093 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3094 if ((self = [super initWithBook:book]) != nil) {
3095 database_ = database;
3097 files_ = [[NSMutableArray arrayWithCapacity:32] retain];
3099 list_ = [[UITable alloc] initWithFrame:[self bounds]];
3100 [self addSubview:list_];
3102 UITableColumn *column = [[[UITableColumn alloc]
3103 initWithTitle:@"Name"
3105 width:[self frame].size.width
3108 [list_ setDataSource:self];
3109 [list_ setSeparatorStyle:1];
3110 [list_ addTableColumn:column];
3111 [list_ setDelegate:self];
3112 [list_ setReusesTableCells:YES];
3116 - (void) setPackage:(Package *)package {
3117 if (package_ != nil) {
3118 [package_ autorelease];
3127 [files_ removeAllObjects];
3129 if (package != nil) {
3130 package_ = [package retain];
3131 name_ = [[package id] retain];
3133 NSString *path = [NSString stringWithFormat:@"/var/lib/dpkg/info/%@.list", name_];
3136 std::ifstream fin([path UTF8String]);
3138 while (std::getline(fin, line))
3139 [files_ addObject:[NSString stringWithUTF8String:line.c_str()]];
3142 if ([files_ count] != 0) {
3143 if ([[files_ objectAtIndex:0] isEqualToString:@"/."])
3144 [files_ removeObjectAtIndex:0];
3145 [files_ sortUsingSelector:@selector(compareByPath:)];
3147 NSMutableArray *stack = [NSMutableArray arrayWithCapacity:8];
3148 [stack addObject:@"/"];
3150 for (int i(0), e([files_ count]); i != e; ++i) {
3151 NSString *file = [files_ objectAtIndex:i];
3152 while (![file hasPrefix:[stack lastObject]])
3153 [stack removeLastObject];
3154 NSString *directory = [stack lastObject];
3155 [stack addObject:[file stringByAppendingString:@"/"]];
3156 [files_ replaceObjectAtIndex:i withObject:[NSString stringWithFormat:@"%*s%@",
3157 ([stack count] - 2) * 3, "",
3158 [file substringFromIndex:[directory length]]
3167 - (void) resetViewAnimated:(BOOL)animated {
3168 [list_ resetViewAnimated:animated];
3171 - (void) reloadData {
3172 [self setPackage:[database_ packageWithName:name_]];
3173 [self reloadButtons];
3176 - (NSString *) title {
3177 return @"Installed Files";
3180 - (NSString *) backButtonTitle {
3186 /* Package View {{{ */
3187 @interface PackageView : BrowserView {
3190 NSMutableArray *buttons_;
3193 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3194 - (void) setPackage:(Package *)package;
3198 @implementation PackageView
3201 if (package_ != nil)
3209 - (void) _clickButtonWithName:(NSString *)name {
3210 if ([name isEqualToString:@"Install"])
3211 [delegate_ installPackage:package_];
3212 else if ([name isEqualToString:@"Reinstall"])
3213 [delegate_ installPackage:package_];
3214 else if ([name isEqualToString:@"Remove"])
3215 [delegate_ removePackage:package_];
3216 else if ([name isEqualToString:@"Upgrade"])
3217 [delegate_ installPackage:package_];
3218 else _assert(false);
3221 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
3222 int count = [buttons_ count];
3223 _assert(count != 0);
3224 _assert(button <= count + 1);
3226 if (count != button - 1)
3227 [self _clickButtonWithName:[buttons_ objectAtIndex:(button - 1)]];
3232 - (void) webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame {
3234 NSLog(@"%@", package_);
3235 [window setValue:package_ forKey:@"package"];
3238 - (void) _rightButtonClicked {
3239 /*[super _rightButtonClicked];
3242 int count = [buttons_ count];
3243 _assert(count != 0);
3246 [self _clickButtonWithName:[buttons_ objectAtIndex:0]];
3248 NSMutableArray *buttons = [NSMutableArray arrayWithCapacity:(count + 1)];
3249 [buttons addObjectsFromArray:buttons_];
3250 [buttons addObject:@"Cancel"];
3252 [delegate_ slideUp:[[[UIAlertSheet alloc]
3255 defaultButtonIndex:2
3262 - (NSString *) _rightButtonTitle {
3263 int count = [buttons_ count];
3264 return count == 0 ? nil : count != 1 ? @"Modify" : [buttons_ objectAtIndex:0];
3267 - (NSString *) title {
3271 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3272 if ((self = [super initWithBook:book database:database]) != nil) {
3273 database_ = database;
3274 buttons_ = [[NSMutableArray alloc] initWithCapacity:4];
3278 - (void) setPackage:(Package *)package {
3279 if (package_ != nil) {
3280 [package_ autorelease];
3289 [buttons_ removeAllObjects];
3291 if (package != nil) {
3292 package_ = [package retain];
3293 name_ = [[package id] retain];
3295 [self loadURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"package" ofType:@"html"]]];
3297 if ([package_ source] == nil);
3298 else if ([package_ upgradableAndEssential:NO])
3299 [buttons_ addObject:@"Upgrade"];
3300 else if ([package_ installed] == nil)
3301 [buttons_ addObject:@"Install"];
3303 [buttons_ addObject:@"Reinstall"];
3304 if ([package_ installed] != nil)
3305 [buttons_ addObject:@"Remove"];
3309 - (void) reloadData {
3310 [self setPackage:[database_ packageWithName:name_]];
3311 [self reloadButtons];
3316 /* Package Table {{{ */
3317 @interface PackageTable : RVPage {
3318 _transient Database *database_;
3322 NSMutableArray *packages_;
3323 NSMutableArray *sections_;
3324 UISectionList *list_;
3327 - (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object;
3329 - (void) setDelegate:(id)delegate;
3330 - (void) setObject:(id)object;
3332 - (void) reloadData;
3333 - (void) resetCursor;
3335 - (UISectionList *) list;
3337 - (void) setShouldHideHeaderInShortLists:(BOOL)hide;
3341 @implementation PackageTable
3344 [list_ setDataSource:nil];
3349 [packages_ release];
3350 [sections_ release];
3355 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
3356 return [sections_ count];
3359 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
3360 return [[sections_ objectAtIndex:section] name];
3363 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
3364 return [[sections_ objectAtIndex:section] row];
3367 - (int) numberOfRowsInTable:(UITable *)table {
3368 return [packages_ count];
3371 - (float) table:(UITable *)table heightForRow:(int)row {
3372 return [PackageCell heightForPackage:[packages_ objectAtIndex:row]];
3375 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
3377 reusing = [[[PackageCell alloc] init] autorelease];
3378 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
3382 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
3386 - (void) tableRowSelected:(NSNotification *)notification {
3387 int row = [[notification object] selectedRow];
3391 Package *package = [packages_ objectAtIndex:row];
3392 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
3393 [view setDelegate:delegate_];
3394 [view setPackage:package];
3395 [book_ pushPage:view];
3398 - (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object {
3399 if ((self = [super initWithBook:book]) != nil) {
3400 database_ = database;
3401 title_ = [title retain];
3403 object_ = object == nil ? nil : [object retain];
3405 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
3406 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
3408 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:YES];
3409 [list_ setDataSource:self];
3411 UITableColumn *column = [[[UITableColumn alloc]
3412 initWithTitle:@"Name"
3414 width:[self frame].size.width
3417 UITable *table = [list_ table];
3418 [table setSeparatorStyle:1];
3419 [table addTableColumn:column];
3420 [table setDelegate:self];
3421 [table setReusesTableCells:YES];
3423 [self addSubview:list_];
3428 - (void) setDelegate:(id)delegate {
3429 delegate_ = delegate;
3432 - (void) setObject:(id)object {
3438 object_ = [object retain];
3441 - (void) reloadData {
3442 NSArray *packages = [database_ packages];
3444 [packages_ removeAllObjects];
3445 [sections_ removeAllObjects];
3447 for (size_t i(0); i != [packages count]; ++i) {
3448 Package *package([packages objectAtIndex:i]);
3449 if ([[package performSelector:filter_ withObject:object_] boolValue])
3450 [packages_ addObject:package];
3453 Section *section = nil;
3455 for (size_t offset(0); offset != [packages_ count]; ++offset) {
3456 Package *package = [packages_ objectAtIndex:offset];
3457 NSString *name = [package index];
3459 if (section == nil || ![[section name] isEqualToString:name]) {
3460 section = [[[Section alloc] initWithName:name row:offset] autorelease];
3461 [sections_ addObject:section];
3464 [section addToCount];
3470 - (NSString *) title {
3474 - (void) resetViewAnimated:(BOOL)animated {
3475 [list_ resetViewAnimated:animated];
3478 - (void) resetCursor {
3479 [[list_ table] scrollPointVisibleAtTopLeft:CGPointMake(0, 0) animated:NO];
3482 - (UISectionList *) list {
3486 - (void) setShouldHideHeaderInShortLists:(BOOL)hide {
3487 [list_ setShouldHideHeaderInShortLists:hide];
3493 /* Add Source View {{{ */
3494 @interface AddSourceView : RVPage {
3495 _transient Database *database_;
3498 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3502 @implementation AddSourceView
3504 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3505 if ((self = [super initWithBook:book]) != nil) {
3506 database_ = database;
3512 /* Source Cell {{{ */
3513 @interface SourceCell : UITableCell {
3516 NSString *description_;
3522 - (SourceCell *) initWithSource:(Source *)source;
3526 @implementation SourceCell
3531 [description_ release];
3536 - (SourceCell *) initWithSource:(Source *)source {
3537 if ((self = [super init]) != nil) {
3539 icon_ = [UIImage applicationImageNamed:[NSString stringWithFormat:@"Sources/%@.png", [source host]]];
3541 icon_ = [UIImage applicationImageNamed:@"unknown.png"];
3542 icon_ = [icon_ retain];
3544 origin_ = [[source name] retain];
3545 label_ = [[source uri] retain];
3546 description_ = [[source description] retain];
3550 - (void) drawContentInRect:(CGRect)rect selected:(BOOL)selected {
3552 [icon_ drawInRect:CGRectMake(10, 10, 30, 30)];
3559 [origin_ drawAtPoint:CGPointMake(48, 8) forWidth:240 withFont:Font18Bold_ ellipsis:2];
3563 [label_ drawAtPoint:CGPointMake(58, 29) forWidth:225 withFont:Font12_ ellipsis:2];
3567 [description_ drawAtPoint:CGPointMake(12, 46) forWidth:280 withFont:Font14_ ellipsis:2];
3569 [super drawContentInRect:rect selected:selected];
3574 /* Source Table {{{ */
3575 @interface SourceTable : RVPage {
3576 _transient Database *database_;
3577 UISectionList *list_;
3578 NSMutableArray *sources_;
3579 UIAlertSheet *alert_;
3583 UIProgressHUD *hud_;
3586 //NSURLConnection *installer_;
3587 NSURLConnection *trivial_bz2_;
3588 NSURLConnection *trivial_gz_;
3589 //NSURLConnection *automatic_;
3594 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3598 @implementation SourceTable
3600 - (void) _deallocConnection:(NSURLConnection *)connection {
3601 if (connection != nil) {
3602 [connection cancel];
3603 //[connection setDelegate:nil];
3604 [connection release];
3609 [[list_ table] setDelegate:nil];
3610 [list_ setDataSource:nil];
3619 //[self _deallocConnection:installer_];
3620 [self _deallocConnection:trivial_gz_];
3621 [self _deallocConnection:trivial_bz2_];
3622 //[self _deallocConnection:automatic_];
3629 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
3630 return offset_ == 0 ? 1 : 2;
3633 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
3634 switch (section + (offset_ == 0 ? 1 : 0)) {
3635 case 0: return @"Entered by User";
3636 case 1: return @"Installed by Packages";
3644 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
3645 switch (section + (offset_ == 0 ? 1 : 0)) {
3647 case 1: return offset_;
3655 - (int) numberOfRowsInTable:(UITable *)table {
3656 return [sources_ count];
3659 - (float) table:(UITable *)table heightForRow:(int)row {
3660 Source *source = [sources_ objectAtIndex:row];
3661 return [source description] == nil ? 56 : 73;
3664 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col {
3665 Source *source = [sources_ objectAtIndex:row];
3666 // XXX: weird warning, stupid selectors ;P
3667 return [[[SourceCell alloc] initWithSource:(id)source] autorelease];
3670 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
3674 - (BOOL) table:(UITable *)table canSelectRow:(int)row {
3678 - (void) tableRowSelected:(NSNotification*)notification {
3679 UITable *table([list_ table]);
3680 int row([table selectedRow]);
3684 Source *source = [sources_ objectAtIndex:row];
3686 PackageTable *packages = [[[PackageTable alloc]
3689 title:[source label]
3690 filter:@selector(isVisibleInSource:)
3694 [packages setDelegate:delegate_];
3696 [book_ pushPage:packages];
3699 - (BOOL) table:(UITable *)table canDeleteRow:(int)row {
3700 Source *source = [sources_ objectAtIndex:row];
3701 return [source record] != nil;
3704 - (void) table:(UITable *)table willSwipeToDeleteRow:(int)row {
3705 [[list_ table] setDeleteConfirmationRow:row];
3708 - (void) table:(UITable *)table deleteRow:(int)row {
3709 Source *source = [sources_ objectAtIndex:row];
3710 [Sources_ removeObjectForKey:[source key]];
3711 [delegate_ syncData];
3714 - (void) _endConnection:(NSURLConnection *)connection {
3715 NSURLConnection **field = NULL;
3716 if (connection == trivial_bz2_)
3717 field = &trivial_bz2_;
3718 else if (connection == trivial_gz_)
3719 field = &trivial_gz_;
3720 _assert(field != NULL);
3721 [connection release];
3725 trivial_bz2_ == nil &&
3728 [delegate_ setStatusBarShowsProgress:NO];
3731 [hud_ removeFromSuperview];
3736 [Sources_ setObject:[NSDictionary dictionaryWithObjectsAndKeys:
3739 @"./", @"Distribution",
3740 nil] forKey:[NSString stringWithFormat:@"deb:%@:./", href_]];
3742 [delegate_ syncData];
3743 } else if (error_ != nil) {
3744 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
3745 initWithTitle:@"Verification Error"
3746 buttons:[NSArray arrayWithObjects:@"OK", nil]
3747 defaultButtonIndex:0
3752 [sheet setBodyText:[error_ localizedDescription]];
3753 [sheet popupAlertAnimated:YES];
3755 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
3756 initWithTitle:@"Did not Find Repository"
3757 buttons:[NSArray arrayWithObjects:@"OK", nil]
3758 defaultButtonIndex:0
3763 [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."];
3764 [sheet popupAlertAnimated:YES];
3770 if (error_ != nil) {
3777 - (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response {
3778 switch ([response statusCode]) {
3784 - (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
3785 fprintf(stderr, "connection:\"%s\" didFailWithError:\"%s\"", [href_ UTF8String], [[error localizedDescription] UTF8String]);
3787 error_ = [error retain];
3788 [self _endConnection:connection];
3791 - (void) connectionDidFinishLoading:(NSURLConnection *)connection {
3792 [self _endConnection:connection];
3795 - (NSURLConnection *) _requestHRef:(NSString *)href method:(NSString *)method {
3796 NSMutableURLRequest *request = [NSMutableURLRequest
3797 requestWithURL:[NSURL URLWithString:href]
3798 cachePolicy:NSURLRequestUseProtocolCachePolicy
3799 timeoutInterval:20.0
3802 [request setHTTPMethod:method];
3804 return [[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease];
3807 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
3808 NSString *context = [sheet context];
3809 if ([context isEqualToString:@"source"])
3812 NSString *href = [[sheet textField] text];
3814 //installer_ = [[self _requestHRef:href method:@"GET"] retain];
3816 if (![href hasSuffix:@"/"])
3817 href_ = [href stringByAppendingString:@"/"];
3820 href_ = [href_ retain];
3822 trivial_bz2_ = [[self _requestHRef:[href_ stringByAppendingString:@"Packages.bz2"] method:@"HEAD"] retain];
3823 trivial_gz_ = [[self _requestHRef:[href_ stringByAppendingString:@"Packages.gz"] method:@"HEAD"] retain];
3824 //trivial_bz2_ = [[self _requestHRef:[href stringByAppendingString:@"dists/Release"] method:@"HEAD"] retain];
3828 hud_ = [delegate_ addProgressHUD];
3829 [hud_ setText:@"Verifying URL"];
3842 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3843 if ((self = [super initWithBook:book]) != nil) {
3844 database_ = database;
3845 sources_ = [[NSMutableArray arrayWithCapacity:16] retain];
3847 //list_ = [[UITable alloc] initWithFrame:[self bounds]];
3848 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:NO];
3849 [list_ setShouldHideHeaderInShortLists:NO];
3851 [self addSubview:list_];
3852 [list_ setDataSource:self];
3854 UITableColumn *column = [[UITableColumn alloc]
3855 initWithTitle:@"Name"
3857 width:[self frame].size.width
3860 UITable *table = [list_ table];
3861 [table setSeparatorStyle:1];
3862 [table addTableColumn:column];
3863 [table setDelegate:self];
3869 - (void) reloadData {
3871 _assert(list.ReadMainList());
3873 [sources_ removeAllObjects];
3874 [sources_ addObjectsFromArray:[database_ sources]];
3875 [sources_ sortUsingSelector:@selector(compareByNameAndType:)];
3877 int count = [sources_ count];
3878 for (offset_ = 0; offset_ != count; ++offset_) {
3879 Source *source = [sources_ objectAtIndex:offset_];
3880 if ([source record] == nil)
3887 - (void) resetViewAnimated:(BOOL)animated {
3888 [list_ resetViewAnimated:animated];
3891 - (void) _leftButtonClicked {
3892 /*[book_ pushPage:[[[AddSourceView alloc]
3897 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
3898 initWithTitle:@"Enter Cydia/APT URL"
3899 buttons:[NSArray arrayWithObjects:@"Add Source", @"Cancel", nil]
3900 defaultButtonIndex:0
3905 [sheet addTextFieldWithValue:@"http://" label:@""];
3907 UITextTraits *traits = [[sheet textField] textTraits];
3908 [traits setAutoCapsType:0];
3909 [traits setPreferredKeyboardType:3];
3910 [traits setAutoCorrectionType:1];
3912 [sheet popupAlertAnimated:YES];
3915 - (void) _rightButtonClicked {
3916 UITable *table = [list_ table];
3917 BOOL editing = [table isRowDeletionEnabled];
3918 [table enableRowDeletion:!editing animated:YES];
3919 [book_ reloadButtonsForPage:self];
3922 - (NSString *) title {
3926 - (NSString *) backButtonTitle {
3930 - (NSString *) leftButtonTitle {
3931 return [[list_ table] isRowDeletionEnabled] ? @"Add" : nil;
3934 - (NSString *) rightButtonTitle {
3935 return [[list_ table] isRowDeletionEnabled] ? @"Done" : @"Edit";
3938 - (RVUINavBarButtonStyle) rightButtonStyle {
3939 return [[list_ table] isRowDeletionEnabled] ? RVUINavBarButtonStyleHighlighted : RVUINavBarButtonStyleNormal;
3945 /* Installed View {{{ */
3946 @interface InstalledView : RVPage {
3947 _transient Database *database_;
3948 PackageTable *packages_;
3952 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3956 @implementation InstalledView
3959 [packages_ release];
3963 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3964 if ((self = [super initWithBook:book]) != nil) {
3965 database_ = database;
3967 packages_ = [[PackageTable alloc]
3971 filter:@selector(isInstalledAndVisible:)
3972 with:[NSNumber numberWithBool:YES]
3975 [self addSubview:packages_];
3979 - (void) resetViewAnimated:(BOOL)animated {
3980 [packages_ resetViewAnimated:animated];
3983 - (void) reloadData {
3984 [packages_ reloadData];
3987 - (void) _rightButtonClicked {
3988 [packages_ setObject:[NSNumber numberWithBool:expert_]];
3989 [packages_ reloadData];
3991 [book_ reloadButtonsForPage:self];
3994 - (NSString *) title {
3995 return @"Installed";
3998 - (NSString *) backButtonTitle {
4002 - (NSString *) rightButtonTitle {
4003 return Role_ != nil && [Role_ isEqualToString:@"Developer"] ? nil : expert_ ? @"Expert" : @"Simple";
4006 - (RVUINavBarButtonStyle) rightButtonStyle {
4007 return expert_ ? RVUINavBarButtonStyleHighlighted : RVUINavBarButtonStyleNormal;
4010 - (void) setDelegate:(id)delegate {
4011 [super setDelegate:delegate];
4012 [packages_ setDelegate:delegate];
4019 @interface HomeView : BrowserView {
4024 @implementation HomeView
4026 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
4030 - (void) _leftButtonClicked {
4031 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
4032 initWithTitle:@"About Cydia Installer"
4033 buttons:[NSArray arrayWithObjects:@"Close", nil]
4034 defaultButtonIndex:0
4040 @"Copyright (C) 2008\n"
4041 "Jay Freeman (saurik)\n"
4042 "saurik@saurik.com\n"
4043 "http://www.saurik.com/\n"
4046 "http://www.theokorigroup.com/\n"
4048 "College of Creative Studies,\n"
4049 "University of California,\n"
4051 "http://www.ccs.ucsb.edu/"
4054 [sheet popupAlertAnimated:YES];
4057 - (NSString *) leftButtonTitle {
4063 /* Manage View {{{ */
4064 @interface ManageView : BrowserView {
4069 @implementation ManageView
4071 - (NSString *) title {
4075 - (void) _leftButtonClicked {
4076 [delegate_ askForSettings];
4079 - (NSString *) leftButtonTitle {
4083 - (NSString *) _rightButtonTitle {
4090 /* Browser Implementation {{{ */
4091 @implementation BrowserView
4094 WebView *webview = [webview_ webView];
4095 [webview setFrameLoadDelegate:nil];
4096 [webview setResourceLoadDelegate:nil];
4097 [webview setUIDelegate:nil];
4099 [scroller_ setDelegate:nil];
4100 [webview_ setDelegate:nil];
4102 [scroller_ release];
4105 [indicator_ release];
4111 - (void) loadURL:(NSURL *)url cachePolicy:(NSURLRequestCachePolicy)policy {
4112 [self loadRequest:[NSURLRequest
4115 timeoutInterval:30.0
4119 - (void) loadURL:(NSURL *)url {
4120 [self loadURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy];
4123 - (NSURLRequest *) _addHeadersToRequest:(NSURLRequest *)request {
4124 NSMutableURLRequest *copy = [request mutableCopy];
4126 [copy addValue:[NSString stringWithUTF8String:Firmware_] forHTTPHeaderField:@"X-Firmware"];
4127 [copy addValue:[NSString stringWithUTF8String:Machine_] forHTTPHeaderField:@"X-Machine"];
4128 [copy addValue:[NSString stringWithUTF8String:SerialNumber_] forHTTPHeaderField:@"X-Serial-Number"];
4131 [copy addValue:Role_ forHTTPHeaderField:@"X-Role"];
4136 - (void) loadRequest:(NSURLRequest *)request {
4138 [webview_ loadRequest:request];
4141 - (void) reloadURL {
4142 NSURL *url = [[[urls_ lastObject] retain] autorelease];
4143 [urls_ removeLastObject];
4144 [self loadURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData];
4147 - (WebView *) webView {
4148 return [webview_ webView];
4151 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame {
4152 [scroller_ setContentSize:frame.size];
4155 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old {
4156 [self view:sender didSetFrame:frame];
4159 - (void) pushPage:(RVPage *)page {
4160 [self setBackButtonTitle:title_];
4161 [page setDelegate:delegate_];
4162 [book_ pushPage:page];
4165 - (void) getSpecial:(NSString *)href {
4168 if ([href hasPrefix:@"mailto:"])
4169 [delegate_ openURL:[NSURL URLWithString:href]];
4170 else if ([href isEqualToString:@"cydia://add-source"])
4171 page = [[[AddSourceView alloc] initWithBook:book_ database:database_] autorelease];
4172 else if ([href isEqualToString:@"cydia://sources"])
4173 page = [[[SourceTable alloc] initWithBook:book_ database:database_] autorelease];
4174 else if ([href isEqualToString:@"cydia://packages"])
4175 page = [[[InstalledView alloc] initWithBook:book_ database:database_] autorelease];
4176 else if ([href hasPrefix:@"cydia://files/"]) {
4177 NSString *name = [href substringFromIndex:14];
4179 if (Package *package = [database_ packageWithName:name]) {
4180 FileTable *files = [[[FileTable alloc] initWithBook:book_ database:database_] autorelease];
4181 [files setPackage:package];
4184 } else if ([href hasPrefix:@"apptapp://package/"]) {
4185 NSString *name = [href substringFromIndex:18];
4187 if (Package *package = [database_ packageWithName:name]) {
4188 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
4189 [view setPackage:package];
4192 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
4193 initWithTitle:@"Cannot Locate Package"
4194 buttons:[NSArray arrayWithObjects:@"Close", nil]
4195 defaultButtonIndex:0
4200 [sheet setBodyText:[NSString stringWithFormat:
4201 @"The package %@ cannot be found in your current sources. I might recommend installing more sources."
4204 [sheet popupAlertAnimated:YES];
4209 [self pushPage:page];
4212 - (void) webView:(WebView *)sender willClickElement:(id)element {
4213 if ([[element localName] isEqualToString:@"img"])
4214 do if ((element = [element parentNode]) == nil)
4216 while (![[element localName] isEqualToString:@"a"]);
4217 if (![element respondsToSelector:@selector(href)])
4219 NSString *href = [element href];
4222 [self getSpecial:href];
4225 - (BOOL) isSpecialScheme:(NSString *)scheme {
4227 [scheme isEqualToString:@"apptapp"] ||
4228 [scheme isEqualToString:@"cydia"] ||
4229 [scheme isEqualToString:@"mailto"];
4232 - (NSURLRequest *) webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource {
4233 NSURL *url = [request URL];
4234 if ([self isSpecialScheme:[url scheme]]) {
4235 [self getSpecial:[url absoluteString]];
4241 [book_ pushPage:self];
4244 return [self _addHeadersToRequest:request];
4247 - (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request {
4248 if (request != nil) {
4249 NSString *scheme = [[request URL] scheme];
4250 if ([self isSpecialScheme:scheme])
4254 [self setBackButtonTitle:title_];
4256 BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease];
4257 [browser setDelegate:delegate_];
4259 if (request != nil) {
4260 [browser loadRequest:[self _addHeadersToRequest:request]];
4261 [book_ pushPage:browser];
4264 return [browser webView];
4267 - (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame {
4268 title_ = [title retain];
4269 [self setTitle:title];
4272 - (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame {
4273 if ([frame parentFrame] != nil)
4278 [indicator_ startAnimation];
4279 [self reloadButtons];
4281 if (title_ != nil) {
4286 [self setTitle:@"Loading..."];
4288 WebView *webview = [webview_ webView];
4289 NSString *href = [webview mainFrameURL];
4290 [urls_ addObject:[NSURL URLWithString:href]];
4292 CGRect webrect = [scroller_ frame];
4293 webrect.size.height = 0;
4294 [webview_ setFrame:webrect];
4297 - (void) _finishLoading {
4300 [indicator_ stopAnimation];
4301 [self reloadButtons];
4305 - (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
4306 if ([frame parentFrame] != nil)
4308 [self _finishLoading];
4311 - (void) webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
4312 if ([frame parentFrame] != nil)
4314 [self _finishLoading];
4316 [self loadURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@?%@",
4317 [[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"error" ofType:@"html"]] absoluteString],
4318 [[error localizedDescription] stringByAddingPercentEscapes]
4322 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4323 if ((self = [super initWithBook:book]) != nil) {
4324 database_ = database;
4327 struct CGRect bounds = [self bounds];
4329 UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:bounds] autorelease];
4330 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
4331 [self addSubview:pinstripe];
4333 scroller_ = [[UIScroller alloc] initWithFrame:bounds];
4334 [self addSubview:scroller_];
4336 [scroller_ setScrollingEnabled:YES];
4337 [scroller_ setAdjustForContentSizeChange:YES];
4338 [scroller_ setClipsSubviews:YES];
4339 [scroller_ setAllowsRubberBanding:YES];
4340 [scroller_ setScrollDecelerationFactor:0.99];
4341 [scroller_ setDelegate:self];
4343 CGRect webrect = [scroller_ bounds];
4344 webrect.size.height = 0;
4346 webview_ = [[UIWebView alloc] initWithFrame:webrect];
4347 [scroller_ addSubview:webview_];
4349 [webview_ setTilingEnabled:YES];
4350 [webview_ setTileSize:CGSizeMake(webrect.size.width, 500)];
4351 [webview_ setAutoresizes:YES];
4352 [webview_ setDelegate:self];
4353 //[webview_ setEnabledGestures:2];
4355 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:kUIProgressIndicatorStyleMediumWhite];
4356 indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(281, 42, indsize.width, indsize.height)];
4357 [indicator_ setStyle:kUIProgressIndicatorStyleMediumWhite];
4359 Package *package([database_ packageWithName:@"cydia"]);
4360 NSString *application = package == nil ? @"Cydia" : [NSString
4361 stringWithFormat:@"Cydia/%@",
4365 WebView *webview = [webview_ webView];
4366 [webview setApplicationNameForUserAgent:application];
4367 [webview setFrameLoadDelegate:self];
4368 [webview setResourceLoadDelegate:self];
4369 [webview setUIDelegate:self];
4371 urls_ = [[NSMutableArray alloc] initWithCapacity:16];
4375 - (void) _rightButtonClicked {
4380 - (NSString *) _rightButtonTitle {
4384 - (NSString *) rightButtonTitle {
4385 return loading_ ? @"" : [self _rightButtonTitle];
4388 - (NSString *) title {
4392 - (NSString *) backButtonTitle {
4396 - (void) setPageActive:(BOOL)active {
4398 [book_ addSubview:indicator_];
4400 [indicator_ removeFromSuperview];
4403 - (void) resetViewAnimated:(BOOL)animated {
4406 - (void) setPushed:(bool)pushed {
4413 @interface CYBook : RVBook <
4416 _transient Database *database_;
4418 UIProgressIndicator *indicator_;
4419 UITextLabel *prompt_;
4420 UIProgressBar *progress_;
4424 - (id) initWithFrame:(CGRect)frame database:(Database *)database;
4430 /* Install View {{{ */
4431 @interface InstallView : RVPage {
4432 _transient Database *database_;
4433 NSMutableArray *sections_;
4434 NSMutableArray *filtered_;
4435 UITransitionView *transition_;
4441 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4442 - (void) reloadData;
4447 @implementation InstallView
4450 [list_ setDataSource:nil];
4451 [list_ setDelegate:nil];
4453 [sections_ release];
4454 [filtered_ release];
4455 [transition_ release];
4457 [accessory_ release];
4461 - (int) numberOfRowsInTable:(UITable *)table {
4462 return editing_ ? [sections_ count] : [filtered_ count] + 1;
4465 - (float) table:(UITable *)table heightForRow:(int)row {
4469 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
4471 reusing = [[[SectionCell alloc] init] autorelease];
4472 [(SectionCell *)reusing setSection:(editing_ ?
4473 [sections_ objectAtIndex:row] :
4474 (row == 0 ? nil : [filtered_ objectAtIndex:(row - 1)])
4475 ) editing:editing_];
4479 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
4483 - (BOOL) table:(UITable *)table canSelectRow:(int)row {
4487 - (void) tableRowSelected:(NSNotification *)notification {
4488 int row = [[notification object] selectedRow];
4499 title = @"All Packages";
4501 section = [filtered_ objectAtIndex:(row - 1)];
4502 name = [section name];
4508 title = @"(No Section)";
4512 PackageTable *table = [[[PackageTable alloc]
4516 filter:@selector(isVisiblyUninstalledInSection:)
4520 [table setDelegate:delegate_];
4522 [book_ pushPage:table];
4525 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4526 if ((self = [super initWithBook:book]) != nil) {
4527 database_ = database;
4529 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
4530 filtered_ = [[NSMutableArray arrayWithCapacity:16] retain];
4532 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
4533 [self addSubview:transition_];
4535 list_ = [[UITable alloc] initWithFrame:[transition_ bounds]];
4536 [transition_ transition:0 toView:list_];
4538 UITableColumn *column = [[[UITableColumn alloc]
4539 initWithTitle:@"Name"
4541 width:[self frame].size.width
4544 [list_ setDataSource:self];
4545 [list_ setSeparatorStyle:1];
4546 [list_ addTableColumn:column];
4547 [list_ setDelegate:self];
4548 [list_ setReusesTableCells:YES];
4554 - (void) reloadData {
4555 NSArray *packages = [database_ packages];
4557 [sections_ removeAllObjects];
4558 [filtered_ removeAllObjects];
4560 NSMutableArray *filtered = [NSMutableArray arrayWithCapacity:[packages count]];
4561 NSMutableDictionary *sections = [NSMutableDictionary dictionaryWithCapacity:32];
4563 for (size_t i(0); i != [packages count]; ++i) {
4564 Package *package([packages objectAtIndex:i]);
4565 NSString *name([package section]);
4568 Section *section([sections objectForKey:name]);
4569 if (section == nil) {
4570 section = [[[Section alloc] initWithName:name] autorelease];
4571 [sections setObject:section forKey:name];
4575 if ([package valid] && [package installed] == nil && [package visible])
4576 [filtered addObject:package];
4579 [sections_ addObjectsFromArray:[sections allValues]];
4580 [sections_ sortUsingSelector:@selector(compareByName:)];
4582 [filtered sortUsingSelector:@selector(compareBySection:)];
4584 Section *section = nil;
4585 for (size_t offset = 0, count = [filtered count]; offset != count; ++offset) {
4586 Package *package = [filtered objectAtIndex:offset];
4587 NSString *name = [package section];
4589 if (section == nil || name != nil && ![[section name] isEqualToString:name]) {
4590 section = name == nil ?
4591 [[[Section alloc] initWithName:nil] autorelease] :
4592 [sections objectForKey:name];
4593 [filtered_ addObject:section];
4596 [section addToCount];
4602 - (void) resetView {
4604 [self _rightButtonClicked];
4607 - (void) resetViewAnimated:(BOOL)animated {
4608 [list_ resetViewAnimated:animated];
4611 - (void) _rightButtonClicked {
4612 if ((editing_ = !editing_))
4615 [delegate_ updateData];
4618 [book_ setTitle:[self title] forPage:self];
4619 [book_ reloadButtonsForPage:self];
4622 - (NSString *) title {
4623 return editing_ ? @"Section Visibility" : @"Install by Section";
4626 - (NSString *) backButtonTitle {
4630 - (NSString *) rightButtonTitle {
4631 return [sections_ count] == 0 ? nil : editing_ ? @"Done" : @"Edit";
4634 - (UIView *) accessoryView {
4640 /* Changes View {{{ */
4641 @interface ChangesView : RVPage {
4642 _transient Database *database_;
4643 NSMutableArray *packages_;
4644 NSMutableArray *sections_;
4645 UISectionList *list_;
4649 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4650 - (void) reloadData;
4654 @implementation ChangesView
4657 [[list_ table] setDelegate:nil];
4658 [list_ setDataSource:nil];
4660 [packages_ release];
4661 [sections_ release];
4666 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
4667 return [sections_ count];
4670 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
4671 return [[sections_ objectAtIndex:section] name];
4674 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
4675 return [[sections_ objectAtIndex:section] row];
4678 - (int) numberOfRowsInTable:(UITable *)table {
4679 return [packages_ count];
4682 - (float) table:(UITable *)table heightForRow:(int)row {
4683 return [PackageCell heightForPackage:[packages_ objectAtIndex:row]];
4686 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
4688 reusing = [[[PackageCell alloc] init] autorelease];
4689 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
4693 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
4697 - (void) tableRowSelected:(NSNotification *)notification {
4698 int row = [[notification object] selectedRow];
4701 Package *package = [packages_ objectAtIndex:row];
4702 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
4703 [view setDelegate:delegate_];
4704 [view setPackage:package];
4705 [book_ pushPage:view];
4708 - (void) _leftButtonClicked {
4709 [(CYBook *)book_ update];
4710 [self reloadButtons];
4713 - (void) _rightButtonClicked {
4714 [delegate_ distUpgrade];
4717 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4718 if ((self = [super initWithBook:book]) != nil) {
4719 database_ = database;
4721 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
4722 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
4724 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:NO];
4725 [self addSubview:list_];
4727 [list_ setShouldHideHeaderInShortLists:NO];
4728 [list_ setDataSource:self];
4729 //[list_ setSectionListStyle:1];
4731 UITableColumn *column = [[[UITableColumn alloc]
4732 initWithTitle:@"Name"
4734 width:[self frame].size.width
4737 UITable *table = [list_ table];
4738 [table setSeparatorStyle:1];
4739 [table addTableColumn:column];
4740 [table setDelegate:self];
4741 [table setReusesTableCells:YES];
4747 - (void) reloadData {
4748 NSArray *packages = [database_ packages];
4750 [packages_ removeAllObjects];
4751 [sections_ removeAllObjects];
4753 for (size_t i(0); i != [packages count]; ++i) {
4754 Package *package([packages objectAtIndex:i]);
4757 [package installed] == nil && [package valid] && [package visible] ||
4758 [package upgradableAndEssential:NO]
4760 [packages_ addObject:package];
4763 [packages_ sortUsingSelector:@selector(compareForChanges:)];
4765 Section *upgradable = [[[Section alloc] initWithName:@"Available Upgrades"] autorelease];
4766 Section *section = nil;
4769 bool unseens = false;
4771 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, Locale_, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
4773 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
4774 Package *package = [packages_ objectAtIndex:offset];
4776 if ([package upgradableAndEssential:YES]) {
4778 [upgradable addToCount];
4781 NSDate *seen = [package seen];
4786 name = [@"n/a ?" retain];
4788 name = (NSString *) CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen);
4791 if (section == nil || ![[section name] isEqualToString:name]) {
4792 section = [[[Section alloc] initWithName:name row:offset] autorelease];
4793 [sections_ addObject:section];
4797 [section addToCount];
4801 CFRelease(formatter);
4804 Section *last = [sections_ lastObject];
4805 size_t count = [last count];
4806 [packages_ removeObjectsInRange:NSMakeRange([packages_ count] - count, count)];
4807 [sections_ removeLastObject];
4811 [sections_ insertObject:upgradable atIndex:0];
4814 [self reloadButtons];
4817 - (void) resetViewAnimated:(BOOL)animated {
4818 [list_ resetViewAnimated:animated];
4821 - (NSString *) leftButtonTitle {
4822 return [(CYBook *)book_ updating] ? nil : @"Refresh";
4825 - (NSString *) rightButtonTitle {
4826 return upgrades_ == 0 ? nil : [NSString stringWithFormat:@"Upgrade (%u)", upgrades_];
4829 - (NSString *) title {
4835 /* Search View {{{ */
4836 @protocol SearchViewDelegate
4837 - (void) showKeyboard:(BOOL)show;
4840 @interface SearchView : RVPage {
4842 UISearchField *field_;
4843 UITransitionView *transition_;
4844 PackageTable *table_;
4845 UIPreferencesTable *advanced_;
4851 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4852 - (void) reloadData;
4856 @implementation SearchView
4860 [[field_ textTraits] setEditingDelegate:nil];
4862 [field_ setDelegate:nil];
4864 [accessory_ release];
4866 [transition_ release];
4868 [advanced_ release];
4873 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
4877 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
4879 case 0: return @"Advanced Search (Coming Soon!)";
4881 default: _assert(false);
4885 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
4889 default: _assert(false);
4893 - (void) _showKeyboard:(BOOL)show {
4894 CGSize keysize = [UIKeyboard defaultSize];
4895 CGRect keydown = [book_ pageBounds];
4896 CGRect keyup = keydown;
4897 keyup.size.height -= keysize.height - ButtonBarHeight_;
4899 float delay = KeyboardTime_ * ButtonBarHeight_ / keysize.height;
4901 UIFrameAnimation *animation = [[[UIFrameAnimation alloc] initWithTarget:[table_ list]] autorelease];
4902 [animation setSignificantRectFields:8];
4905 [animation setStartFrame:keydown];
4906 [animation setEndFrame:keyup];
4908 [animation setStartFrame:keyup];
4909 [animation setEndFrame:keydown];
4912 UIAnimator *animator = [UIAnimator sharedAnimator];
4915 addAnimations:[NSArray arrayWithObjects:animation, nil]
4916 withDuration:(KeyboardTime_ - delay)
4921 [animator performSelector:@selector(startAnimation:) withObject:animation afterDelay:delay];
4924 [delegate_ showKeyboard:show];
4928 - (void) textFieldDidBecomeFirstResponder:(UITextField *)field {
4929 [self _showKeyboard:YES];
4932 - (void) textFieldDidResignFirstResponder:(UITextField *)field {
4933 [self _showKeyboard:NO];
4936 - (void) keyboardInputChanged:(UIFieldEditor *)editor {
4938 NSString *text([field_ text]);
4939 [field_ setClearButtonStyle:(text == nil || [text length] == 0 ? 0 : 2)];
4945 - (void) textFieldClearButtonPressed:(UITextField *)field {
4949 - (void) keyboardInputShouldDelete:(id)input {
4953 - (BOOL) keyboardInput:(id)input shouldInsertText:(NSString *)text isMarkedText:(int)marked {
4954 if ([text length] != 1 || [text characterAtIndex:0] != '\n') {
4958 [field_ resignFirstResponder];
4963 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4964 if ((self = [super initWithBook:book]) != nil) {
4965 CGRect pageBounds = [book_ pageBounds];
4967 /*UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:pageBounds] autorelease];
4968 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
4969 [self addSubview:pinstripe];*/
4971 transition_ = [[UITransitionView alloc] initWithFrame:pageBounds];
4972 [self addSubview:transition_];
4974 advanced_ = [[UIPreferencesTable alloc] initWithFrame:pageBounds];
4976 [advanced_ setReusesTableCells:YES];
4977 [advanced_ setDataSource:self];
4978 [advanced_ reloadData];
4980 dimmed_ = [[UIView alloc] initWithFrame:pageBounds];
4981 CGColor dimmed(space_, 0, 0, 0, 0.5);
4982 [dimmed_ setBackgroundColor:dimmed];
4984 table_ = [[PackageTable alloc]
4988 filter:@selector(isVisiblySearchedForBy:)
4992 [table_ setShouldHideHeaderInShortLists:NO];
4993 [transition_ transition:0 toView:table_];
5002 area.origin.x = /*cnfrect.origin.x + cnfrect.size.width + 4 +*/ 10;
5009 [self bounds].size.width - area.origin.x - 18;
5011 area.size.height = [UISearchField defaultHeight];
5013 field_ = [[UISearchField alloc] initWithFrame:area];
5015 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
5016 [field_ setFont:font];
5019 [field_ setPlaceholder:@"Package Names & Descriptions"];
5020 [field_ setDelegate:self];
5023 [field_ setPaddingTop:3];
5025 [field_ setPaddingTop:5];
5028 UITextTraits *traits = [field_ textTraits];
5029 [traits setAutoCapsType:0];
5030 [traits setAutoCorrectionType:1];
5031 [traits setReturnKeyType:6];
5034 [traits setEditingDelegate:self];
5037 CGRect accrect = {{0, 6}, {6 + cnfrect.size.width + 6 + area.size.width + 6, area.size.height + 30}};
5039 accessory_ = [[UIView alloc] initWithFrame:accrect];
5040 [accessory_ addSubview:field_];
5042 /*UIPushButton *configure = [[[UIPushButton alloc] initWithFrame:cnfrect] autorelease];
5043 [configure setShowPressFeedback:YES];
5044 [configure setImage:[UIImage applicationImageNamed:@"advanced.png"]];
5045 [configure addTarget:self action:@selector(configurePushed) forEvents:1];
5046 [accessory_ addSubview:configure];*/
5052 LKAnimation *animation = [LKTransition animation];
5053 [animation setType:@"oglFlip"];
5054 [animation setTimingFunction:[LKTimingFunction functionWithName:@"easeInEaseOut"]];
5055 [animation setFillMode:@"extended"];
5056 [animation setTransitionFlags:3];
5057 [animation setDuration:10];
5058 [animation setSpeed:0.35];
5059 [animation setSubtype:(flipped_ ? @"fromLeft" : @"fromRight")];
5060 [[transition_ _layer] addAnimation:animation forKey:0];
5061 [transition_ transition:0 toView:(flipped_ ? (UIView *) table_ : (UIView *) advanced_)];
5062 flipped_ = !flipped_;
5066 - (void) configurePushed {
5067 [field_ resignFirstResponder];
5071 - (void) resetViewAnimated:(BOOL)animated {
5074 [table_ resetViewAnimated:animated];
5077 - (void) reloadData {
5080 [table_ setObject:[field_ text]];
5081 [table_ reloadData];
5082 [table_ resetCursor];
5085 - (UIView *) accessoryView {
5089 - (NSString *) title {
5093 - (NSString *) backButtonTitle {
5097 - (void) setDelegate:(id)delegate {
5098 [table_ setDelegate:delegate];
5099 [super setDelegate:delegate];
5105 @implementation CYBook
5109 [indicator_ release];
5111 [progress_ release];
5115 - (NSString *) getTitleForPage:(RVPage *)page {
5116 return Simplify([super getTitleForPage:page]);
5124 [navbar_ setPrompt:@""];
5125 [navbar_ addSubview:overlay_];
5126 [indicator_ startAnimation];
5127 [prompt_ setText:@"Updating Database..."];
5128 [progress_ setProgress:0];
5133 detachNewThreadSelector:@selector(_update)
5142 [overlay_ removeFromSuperview];
5143 [indicator_ stopAnimation];
5144 [delegate_ reloadData];
5146 [self setPrompt:[NSString stringWithFormat:@"Last Updated: %@", GetLastUpdate()]];
5149 - (id) initWithFrame:(CGRect)frame database:(Database *)database {
5150 if ((self = [super initWithFrame:frame]) != nil) {
5151 database_ = database;
5154 [navbar_ setBarStyle:1];
5156 CGRect ovrrect = [navbar_ bounds];
5157 ovrrect.size.height = ([UINavigationBar defaultSizeWithPrompt].height - [UINavigationBar defaultSize].height);
5159 overlay_ = [[UIView alloc] initWithFrame:ovrrect];
5161 UIProgressIndicatorStyle style = Advanced_ ?
5162 kUIProgressIndicatorStyleSmallWhite :
5163 kUIProgressIndicatorStyleSmallBlack;
5165 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:style];
5166 unsigned indoffset = (ovrrect.size.height - indsize.height) / 2;
5167 CGRect indrect = {{indoffset, indoffset}, indsize};
5169 indicator_ = [[UIProgressIndicator alloc] initWithFrame:indrect];
5170 [indicator_ setStyle:style];
5171 [overlay_ addSubview:indicator_];
5173 CGSize prmsize = {200, indsize.width + 4};
5176 indoffset * 2 + indsize.width,
5180 (ovrrect.size.height - prmsize.height) / 2
5183 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 12);
5185 prompt_ = [[UITextLabel alloc] initWithFrame:prmrect];
5187 [prompt_ setColor:(Advanced_ ? White_ : Blueish_)];
5188 [prompt_ setBackgroundColor:Clear_];
5189 [prompt_ setFont:font];
5193 [overlay_ addSubview:prompt_];
5195 CGSize prgsize = {75, 100};
5198 ovrrect.size.width - prgsize.width - 10,
5199 (ovrrect.size.height - prgsize.height) / 2
5202 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
5203 [progress_ setStyle:0];
5204 [overlay_ addSubview:progress_];
5209 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5212 status.setDelegate(self);
5214 [database_ updateWithStatus:status];
5217 performSelectorOnMainThread:@selector(_update_)
5225 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id {
5226 [prompt_ setText:[NSString stringWithFormat:@"Error: %@", error]];
5229 - (void) setProgressTitle:(NSString *)title {
5231 performSelectorOnMainThread:@selector(_setProgressTitle:)
5237 - (void) setProgressPercent:(float)percent {
5240 - (void) addProgressOutput:(NSString *)output {
5242 performSelectorOnMainThread:@selector(_addProgressOutput:)
5248 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
5252 - (void) _setProgressTitle:(NSString *)title {
5253 [prompt_ setText:[title stringByAppendingString:@"..."]];
5256 - (void) _addProgressOutput:(NSString *)output {
5261 @interface Cydia : UIApplication <
5262 ConfirmationViewDelegate,
5263 ProgressViewDelegate,
5272 UIButtonBar *buttonbar_;
5274 ConfirmationView *confirm_;
5276 NSMutableArray *essential_;
5277 NSMutableArray *broken_;
5279 Database *database_;
5280 ProgressView *progress_;
5284 UIKeyboard *keyboard_;
5285 UIProgressHUD *hud_;
5287 InstallView *install_;
5288 ChangesView *changes_;
5289 ManageView *manage_;
5290 SearchView *search_;
5295 @implementation Cydia
5298 if ([broken_ count] != 0) {
5299 int count = [broken_ count];
5301 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
5302 initWithTitle:[NSString stringWithFormat:@"%d Half-Installed Package%@", count, (count == 1 ? @"" : @"s")]
5303 buttons:[NSArray arrayWithObjects:
5305 @"Ignore (Temporary)",
5307 defaultButtonIndex:0
5312 [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."];
5313 [sheet popupAlertAnimated:YES];
5314 } else if (!Ignored_ && [essential_ count] != 0) {
5315 int count = [essential_ count];
5317 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
5318 initWithTitle:[NSString stringWithFormat:@"%d Essential Upgrade%@", count, (count == 1 ? @"" : @"s")]
5319 buttons:[NSArray arrayWithObjects:@"Upgrade Essential", @"Ignore (Temporary)", nil]
5320 defaultButtonIndex:0
5325 [sheet setBodyText:@"One or more essential packages are currently out of date. If these upgrades are not performed you are likely to encounter errors."];
5326 [sheet popupAlertAnimated:YES];
5330 - (void) _reloadData {
5331 /*UIProgressHUD *hud = [[UIProgressHUD alloc] initWithWindow:window_];
5332 [hud setText:@"Reloading Data"];
5333 [overlay_ addSubview:hud];
5336 [database_ reloadData];
5340 [essential_ removeAllObjects];
5341 [broken_ removeAllObjects];
5343 NSArray *packages = [database_ packages];
5344 for (int i(0), e([packages count]); i != e; ++i) {
5345 Package *package = [packages objectAtIndex:i];
5347 [broken_ addObject:package];
5348 if ([package upgradableAndEssential:NO]) {
5349 if ([package essential])
5350 [essential_ addObject:package];
5356 NSString *badge([[NSNumber numberWithInt:changes] stringValue]);
5357 [buttonbar_ setBadgeValue:badge forButton:3];
5358 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
5359 [buttonbar_ setBadgeAnimated:YES forButton:3];
5360 [self setApplicationBadge:badge];
5362 [buttonbar_ setBadgeValue:nil forButton:3];
5363 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
5364 [buttonbar_ setBadgeAnimated:NO forButton:3];
5365 [self removeApplicationBadge];
5370 if ([packages count] == 0);
5379 [hud removeFromSuperview];*/
5382 - (void) _saveConfig {
5384 _assert([Metadata_ writeToFile:@"/var/lib/cydia/metadata.plist" atomically:YES] == YES);
5389 - (void) updateData {
5392 /* XXX: this is just stupid */
5394 [install_ reloadData];
5396 [changes_ reloadData];
5398 [search_ reloadData];
5408 FILE *file = fopen("/etc/apt/sources.list.d/cydia.list", "w");
5409 _assert(file != NULL);
5411 NSArray *keys = [Sources_ allKeys];
5413 for (int i(0), e([keys count]); i != e; ++i) {
5414 NSString *key = [keys objectAtIndex:i];
5415 NSDictionary *source = [Sources_ objectForKey:key];
5417 fprintf(file, "%s %s %s\n",
5418 [[source objectForKey:@"Type"] UTF8String],
5419 [[source objectForKey:@"URI"] UTF8String],
5420 [[source objectForKey:@"Distribution"] UTF8String]
5429 detachNewThreadSelector:@selector(update_)
5432 title:@"Updating Sources..."
5436 - (void) reloadData {
5437 @synchronized (self) {
5438 if (confirm_ == nil)
5444 pkgProblemResolver *resolver = [database_ resolver];
5446 resolver->InstallProtect();
5447 if (!resolver->Resolve(true))
5452 [database_ prepare];
5454 if ([database_ cache]->BrokenCount() == 0)
5455 confirm_ = [[ConfirmationView alloc] initWithView:underlay_ database:database_ delegate:self];
5457 NSMutableArray *broken = [NSMutableArray arrayWithCapacity:16];
5458 NSArray *packages = [database_ packages];
5460 for (size_t i(0); i != [packages count]; ++i) {
5461 Package *package = [packages objectAtIndex:i];
5462 if ([package broken])
5463 [broken addObject:[package name]];
5466 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
5467 initWithTitle:[NSString stringWithFormat:@"%d Broken Packages", [database_ cache]->BrokenCount()]
5468 buttons:[NSArray arrayWithObjects:@"Okay", nil]
5469 defaultButtonIndex:0
5474 [sheet setBodyText:[NSString stringWithFormat:@"The following packages have unmet dependencies:\n\n%@", [broken componentsJoinedByString:@"\n"]]];
5475 [sheet popupAlertAnimated:YES];
5481 - (void) installPackage:(Package *)package {
5482 @synchronized (self) {
5489 - (void) removePackage:(Package *)package {
5490 @synchronized (self) {
5497 - (void) distUpgrade {
5498 @synchronized (self) {
5499 [database_ upgrade];
5505 @synchronized (self) {
5513 [overlay_ removeFromSuperview];
5517 detachNewThreadSelector:@selector(perform)
5524 - (void) bootstrap_ {
5526 [database_ upgrade];
5527 [database_ prepare];
5528 [database_ perform];
5531 - (void) bootstrap {
5533 detachNewThreadSelector:@selector(bootstrap_)
5536 title:@"Bootstrap Install..."
5540 - (void) progressViewIsComplete:(ProgressView *)progress {
5541 @synchronized (self) {
5544 if (confirm_ != nil) {
5545 [underlay_ addSubview:overlay_];
5546 [confirm_ removeFromSuperview];
5553 - (void) setPage:(RVPage *)page {
5554 [page resetViewAnimated:NO];
5555 [page setDelegate:self];
5556 [book_ setPage:page];
5559 - (RVPage *) _pageForURL:(NSURL *)url withClass:(Class)_class {
5560 BrowserView *browser = [[[_class alloc] initWithBook:book_ database:database_] autorelease];
5561 [browser loadURL:url];
5565 - (void) _setHomePage {
5566 [self setPage:[self _pageForURL:[NSURL URLWithString:@"http://cydia.saurik.com/"] withClass:[HomeView class]]];
5569 - (void) buttonBarItemTapped:(id)sender {
5570 unsigned tag = [sender tag];
5572 [book_ resetViewAnimated:YES];
5574 } else if (tag_ == 2 && tag != 2)
5575 [install_ resetView];
5578 case 1: [self _setHomePage]; break;
5580 case 2: [self setPage:install_]; break;
5581 case 3: [self setPage:changes_]; break;
5582 case 4: [self setPage:manage_]; break;
5583 case 5: [self setPage:search_]; break;
5585 default: _assert(false);
5591 - (void) fixSpringBoard {
5592 pid_t pid = ExecFork();
5596 if (pid_t child = fork()) {
5597 waitpid(child, NULL, 0);
5599 execlp("launchctl", "launchctl", "unload", SpringBoard_, NULL);
5600 perror("launchctl unload");
5604 execlp("launchctl", "launchctl", "load", SpringBoard_, NULL);
5605 perror("launchctl load");
5610 - (void) applicationWillSuspend {
5615 [self fixSpringBoard];
5619 [super applicationWillSuspend];
5622 - (void) askForSettings {
5623 UIAlertSheet *role = [[[UIAlertSheet alloc]
5624 initWithTitle:@"Who Are You?"
5625 buttons:[NSArray arrayWithObjects:
5626 @"User (Graphical Only)",
5627 @"Hacker (+ Command Line)",
5628 @"Developer (No Filters)",
5630 defaultButtonIndex:-1
5635 [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."];
5636 [role popupAlertAnimated:YES];
5641 [self setStatusBarShowsProgress:NO];
5644 [hud_ removeFromSuperview];
5648 pid_t pid = ExecFork();
5650 execlp("launchctl", "launchctl", "stop", "com.apple.SpringBoard", NULL);
5651 perror("launchctl stop");
5658 [self askForSettings];
5662 overlay_ = [[UIView alloc] initWithFrame:[underlay_ bounds]];
5664 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
5665 book_ = [[CYBook alloc] initWithFrame:CGRectMake(
5666 0, 0, screenrect.size.width, screenrect.size.height - 48
5667 ) database:database_];
5669 [book_ setDelegate:self];
5671 [overlay_ addSubview:book_];
5673 NSArray *buttonitems = [NSArray arrayWithObjects:
5674 [NSDictionary dictionaryWithObjectsAndKeys:
5675 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5676 @"home-up.png", kUIButtonBarButtonInfo,
5677 @"home-dn.png", kUIButtonBarButtonSelectedInfo,
5678 [NSNumber numberWithInt:1], kUIButtonBarButtonTag,
5679 self, kUIButtonBarButtonTarget,
5680 @"Home", kUIButtonBarButtonTitle,
5681 @"0", kUIButtonBarButtonType,
5684 [NSDictionary dictionaryWithObjectsAndKeys:
5685 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5686 @"install-up.png", kUIButtonBarButtonInfo,
5687 @"install-dn.png", kUIButtonBarButtonSelectedInfo,
5688 [NSNumber numberWithInt:2], kUIButtonBarButtonTag,
5689 self, kUIButtonBarButtonTarget,
5690 @"Sections", kUIButtonBarButtonTitle,
5691 @"0", kUIButtonBarButtonType,
5694 [NSDictionary dictionaryWithObjectsAndKeys:
5695 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5696 @"changes-up.png", kUIButtonBarButtonInfo,
5697 @"changes-dn.png", kUIButtonBarButtonSelectedInfo,
5698 [NSNumber numberWithInt:3], kUIButtonBarButtonTag,
5699 self, kUIButtonBarButtonTarget,
5700 @"Changes", kUIButtonBarButtonTitle,
5701 @"0", kUIButtonBarButtonType,
5704 [NSDictionary dictionaryWithObjectsAndKeys:
5705 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5706 @"manage-up.png", kUIButtonBarButtonInfo,
5707 @"manage-dn.png", kUIButtonBarButtonSelectedInfo,
5708 [NSNumber numberWithInt:4], kUIButtonBarButtonTag,
5709 self, kUIButtonBarButtonTarget,
5710 @"Manage", kUIButtonBarButtonTitle,
5711 @"0", kUIButtonBarButtonType,
5714 [NSDictionary dictionaryWithObjectsAndKeys:
5715 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5716 @"search-up.png", kUIButtonBarButtonInfo,
5717 @"search-dn.png", kUIButtonBarButtonSelectedInfo,
5718 [NSNumber numberWithInt:5], kUIButtonBarButtonTag,
5719 self, kUIButtonBarButtonTarget,
5720 @"Search", kUIButtonBarButtonTitle,
5721 @"0", kUIButtonBarButtonType,
5725 buttonbar_ = [[UIButtonBar alloc]
5727 withFrame:CGRectMake(
5728 0, screenrect.size.height - ButtonBarHeight_,
5729 screenrect.size.width, ButtonBarHeight_
5731 withItemList:buttonitems
5734 [buttonbar_ setDelegate:self];
5735 [buttonbar_ setBarStyle:1];
5736 [buttonbar_ setButtonBarTrackingMode:2];
5738 int buttons[5] = {1, 2, 3, 4, 5};
5739 [buttonbar_ registerButtonGroup:0 withButtons:buttons withCount:5];
5740 [buttonbar_ showButtonGroup:0 withDuration:0];
5742 for (int i = 0; i != 5; ++i)
5743 [[buttonbar_ viewWithTag:(i + 1)] setFrame:CGRectMake(
5744 i * 64 + 2, 1, 60, ButtonBarHeight_
5747 [buttonbar_ showSelectionForButton:1];
5748 [overlay_ addSubview:buttonbar_];
5750 [UIKeyboard initImplementationNow];
5751 CGSize keysize = [UIKeyboard defaultSize];
5752 CGRect keyrect = {{0, [overlay_ bounds].size.height}, keysize};
5753 keyboard_ = [[UIKeyboard alloc] initWithFrame:keyrect];
5754 [[UIKeyboardImpl sharedInstance] setSoundsEnabled:(Sounds_Keyboard_ ? YES : NO)];
5755 [overlay_ addSubview:keyboard_];
5757 install_ = [[InstallView alloc] initWithBook:book_ database:database_];
5758 changes_ = [[ChangesView alloc] initWithBook:book_ database:database_];
5759 search_ = [[SearchView alloc] initWithBook:book_ database:database_];
5761 manage_ = (ManageView *) [[self
5762 _pageForURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"manage" ofType:@"html"]]
5763 withClass:[ManageView class]
5767 [underlay_ addSubview:overlay_];
5774 [self _setHomePage];
5777 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
5778 NSString *context = [sheet context];
5779 if ([context isEqualToString:@"fixhalf"])
5782 @synchronized (self) {
5783 for (int i = 0, e = [broken_ count]; i != e; ++i) {
5784 Package *broken = [broken_ objectAtIndex:i];
5787 NSString *id = [broken id];
5788 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.prerm", id] UTF8String]);
5789 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.postrm", id] UTF8String]);
5790 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.preinst", id] UTF8String]);
5791 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.postinst", id] UTF8String]);
5800 [broken_ removeAllObjects];
5807 else if ([context isEqualToString:@"role"]) {
5809 case 1: Role_ = @"User"; break;
5810 case 2: Role_ = @"Hacker"; break;
5811 case 3: Role_ = @"Developer"; break;
5818 bool reset = Settings_ != nil;
5820 Settings_ = [NSMutableDictionary dictionaryWithObjectsAndKeys:
5824 [Metadata_ setObject:Settings_ forKey:@"Settings"];
5832 } else if ([context isEqualToString:@"upgrade"])
5835 @synchronized (self) {
5836 for (int i = 0, e = [essential_ count]; i != e; ++i) {
5837 Package *essential = [essential_ objectAtIndex:i];
5838 [essential install];
5857 - (void) reorganize {
5858 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5859 system("/usr/libexec/cydia/free.sh");
5860 [self performSelectorOnMainThread:@selector(finish) withObject:nil waitUntilDone:NO];
5864 - (void) applicationSuspend:(__GSEvent *)event {
5865 if (hud_ == nil && ![progress_ isRunning])
5866 [super applicationSuspend:event];
5869 - (void) _animateSuspension:(BOOL)arg0 duration:(double)arg1 startTime:(double)arg2 scale:(float)arg3 {
5871 [super _animateSuspension:arg0 duration:arg1 startTime:arg2 scale:arg3];
5874 - (void) _setSuspended:(BOOL)value {
5876 [super _setSuspended:value];
5879 - (UIProgressHUD *) addProgressHUD {
5880 UIProgressHUD *hud = [[UIProgressHUD alloc] initWithWindow:window_];
5882 [underlay_ addSubview:hud];
5886 - (void) applicationDidFinishLaunching:(id)unused {
5887 Font12_ = [[UIFont systemFontOfSize:12] retain];
5888 Font12Bold_ = [[UIFont boldSystemFontOfSize:12] retain];
5889 Font14_ = [[UIFont systemFontOfSize:14] retain];
5890 Font18Bold_ = [[UIFont boldSystemFontOfSize:18] retain];
5891 Font22Bold_ = [[UIFont boldSystemFontOfSize:22] retain];
5893 _assert(pkgInitConfig(*_config));
5894 _assert(pkgInitSystem(*_config, _system));
5899 essential_ = [[NSMutableArray alloc] initWithCapacity:4];
5900 broken_ = [[NSMutableArray alloc] initWithCapacity:4];
5902 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
5903 window_ = [[UIWindow alloc] initWithContentRect:screenrect];
5905 [window_ orderFront:self];
5906 [window_ makeKey:self];
5907 [window_ _setHidden:NO];
5909 database_ = [[Database alloc] init];
5910 progress_ = [[ProgressView alloc] initWithFrame:[window_ bounds] database:database_ delegate:self];
5911 [database_ setDelegate:progress_];
5912 [window_ setContentView:progress_];
5914 underlay_ = [[UIView alloc] initWithFrame:[progress_ bounds]];
5915 [progress_ setContentView:underlay_];
5917 [progress_ resetView];
5920 readlink("/Applications", NULL, 0) == -1 && errno == EINVAL ||
5921 readlink("/Library/Ringtones", NULL, 0) == -1 && errno == EINVAL ||
5922 readlink("/Library/Wallpaper", NULL, 0) == -1 && errno == EINVAL ||
5923 readlink("/usr/include", NULL, 0) == -1 && errno == EINVAL ||
5924 readlink("/usr/libexec", NULL, 0) == -1 && errno == EINVAL ||
5925 readlink("/usr/share", NULL, 0) == -1 && errno == EINVAL
5927 [self setIdleTimerDisabled:YES];
5929 hud_ = [self addProgressHUD];
5930 [hud_ setText:@"Reorganizing\n\nWill Automatically\nRestart When Done"];
5932 [self setStatusBarShowsProgress:YES];
5935 detachNewThreadSelector:@selector(reorganize)
5943 - (void) showKeyboard:(BOOL)show {
5944 CGSize keysize = [UIKeyboard defaultSize];
5945 CGRect keydown = {{0, [overlay_ bounds].size.height}, keysize};
5946 CGRect keyup = keydown;
5947 keyup.origin.y -= keysize.height;
5949 UIFrameAnimation *animation = [[[UIFrameAnimation alloc] initWithTarget:keyboard_] autorelease];
5950 [animation setSignificantRectFields:2];
5953 [animation setStartFrame:keydown];
5954 [animation setEndFrame:keyup];
5955 [keyboard_ activate];
5957 [animation setStartFrame:keyup];
5958 [animation setEndFrame:keydown];
5959 [keyboard_ deactivate];
5962 [[UIAnimator sharedAnimator]
5963 addAnimations:[NSArray arrayWithObjects:animation, nil]
5964 withDuration:KeyboardTime_
5969 - (void) slideUp:(UIAlertSheet *)alert {
5971 [alert presentSheetFromButtonBar:buttonbar_];
5973 [alert presentSheetInView:overlay_];
5978 void AddPreferences(NSString *plist) {
5979 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5981 NSMutableDictionary *settings = [[[NSMutableDictionary alloc] initWithContentsOfFile:plist] autorelease];
5982 _assert(settings != NULL);
5983 NSMutableArray *items = [settings objectForKey:@"items"];
5987 for (size_t i(0); i != [items count]; ++i) {
5988 NSMutableDictionary *item([items objectAtIndex:i]);
5989 NSString *label = [item objectForKey:@"label"];
5990 if (label != nil && [label isEqualToString:@"Cydia"]) {
5997 for (size_t i(0); i != [items count]; ++i) {
5998 NSDictionary *item([items objectAtIndex:i]);
5999 NSString *label = [item objectForKey:@"label"];
6000 if (label != nil && [label isEqualToString:@"General"]) {
6001 [items insertObject:[NSDictionary dictionaryWithObjectsAndKeys:
6002 @"CydiaSettings", @"bundle",
6003 @"PSLinkCell", @"cell",
6004 [NSNumber numberWithBool:YES], @"hasIcon",
6005 [NSNumber numberWithBool:YES], @"isController",
6007 nil] atIndex:(i + 1)];
6013 _assert([settings writeToFile:plist atomically:YES] == YES);
6020 id Alloc_(id self, SEL selector) {
6021 id object = alloc_(self, selector);
6022 fprintf(stderr, "[%s]A-%p\n", self->isa->name, object);
6027 id Dealloc_(id self, SEL selector) {
6028 id object = dealloc_(self, selector);
6029 fprintf(stderr, "[%s]D-%p\n", self->isa->name, object);
6033 int main(int argc, char *argv[]) {
6034 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
6036 bootstrap_ = argc > 1 && strcmp(argv[1], "--bootstrap") == 0;
6038 Home_ = NSHomeDirectory();
6041 NSString *plist = [Home_ stringByAppendingString:@"/Library/Preferences/com.apple.preferences.sounds.plist"];
6042 if (NSDictionary *sounds = [NSDictionary dictionaryWithContentsOfFile:plist])
6043 if (NSNumber *keyboard = [sounds objectForKey:@"keyboard"])
6044 Sounds_Keyboard_ = [keyboard boolValue];
6050 if (unlink("/var/cache/apt/pkgcache.bin") == -1)
6051 _assert(errno == ENOENT);
6052 if (unlink("/var/cache/apt/srcpkgcache.bin") == -1)
6053 _assert(errno == ENOENT);
6055 /*Method alloc = class_getClassMethod([NSObject class], @selector(alloc));
6056 alloc_ = alloc->method_imp;
6057 alloc->method_imp = (IMP) &Alloc_;*/
6059 /*Method dealloc = class_getClassMethod([NSObject class], @selector(dealloc));
6060 dealloc_ = dealloc->method_imp;
6061 dealloc->method_imp = (IMP) &Dealloc_;*/
6063 if (NSDictionary *sysver = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]) {
6064 if (NSString *prover = [sysver valueForKey:@"ProductVersion"]) {
6065 Firmware_ = strdup([prover UTF8String]);
6066 NSArray *versions = [prover componentsSeparatedByString:@"."];
6067 int count = [versions count];
6068 Major_ = count > 0 ? [[versions objectAtIndex:0] intValue] : 0;
6069 Minor_ = count > 1 ? [[versions objectAtIndex:1] intValue] : 0;
6070 BugFix_ = count > 2 ? [[versions objectAtIndex:2] intValue] : 0;
6075 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
6076 char *machine = new char[size];
6077 sysctlbyname("hw.machine", machine, &size, NULL, 0);
6080 if (CFMutableDictionaryRef dict = IOServiceMatching("IOPlatformExpertDevice"))
6081 if (io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, dict)) {
6082 if (CFTypeRef serial = IORegistryEntryCreateCFProperty(service, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0)) {
6083 SerialNumber_ = strdup(CFStringGetCStringPtr((CFStringRef) serial, CFStringGetSystemEncoding()));
6087 IOObjectRelease(service);
6090 /*AddPreferences(@"/Applications/Preferences.app/Settings-iPhone.plist");
6091 AddPreferences(@"/Applications/Preferences.app/Settings-iPod.plist");*/
6093 if ((Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"]) == NULL)
6094 Metadata_ = [[NSMutableDictionary alloc] initWithCapacity:2];
6096 Settings_ = [Metadata_ objectForKey:@"Settings"];
6098 Packages_ = [Metadata_ objectForKey:@"Packages"];
6099 Sections_ = [Metadata_ objectForKey:@"Sections"];
6100 Sources_ = [Metadata_ objectForKey:@"Sources"];
6103 if (Settings_ != nil)
6104 Role_ = [Settings_ objectForKey:@"Role"];
6106 if (Packages_ == nil) {
6107 Packages_ = [[[NSMutableDictionary alloc] initWithCapacity:128] autorelease];
6108 [Metadata_ setObject:Packages_ forKey:@"Packages"];
6111 if (Sections_ == nil) {
6112 Sections_ = [[[NSMutableDictionary alloc] initWithCapacity:32] autorelease];
6113 [Metadata_ setObject:Sections_ forKey:@"Sections"];
6116 if (Sources_ == nil) {
6117 Sources_ = [[[NSMutableDictionary alloc] initWithCapacity:0] autorelease];
6118 [Metadata_ setObject:Sources_ forKey:@"Sources"];
6121 if (access("/User", F_OK) != 0)
6122 system("/usr/libexec/cydia/firmware.sh");
6124 Locale_ = CFLocaleCopyCurrent();
6125 space_ = CGColorSpaceCreateDeviceRGB();
6127 Blue_.Set(space_, 0.2, 0.2, 1.0, 1.0);
6128 Blueish_.Set(space_, 0x19/255.f, 0x32/255.f, 0x50/255.f, 1.0);
6129 Black_.Set(space_, 0.0, 0.0, 0.0, 1.0);
6130 Clear_.Set(space_, 0.0, 0.0, 0.0, 0.0);
6131 Red_.Set(space_, 1.0, 0.0, 0.0, 1.0);
6132 White_.Set(space_, 1.0, 1.0, 1.0, 1.0);
6133 Gray_.Set(space_, 0.4, 0.4, 0.4, 1.0);
6135 SectionMap_ = [[[NSDictionary alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Sections" ofType:@"plist"]] autorelease];
6137 int value = UIApplicationMain(argc, argv, [Cydia class]);
6139 CGColorSpaceRelease(space_);