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/mmap.h>
78 #include <apt-pkg/pkgrecords.h>
79 #include <apt-pkg/sha1.h>
80 #include <apt-pkg/sourcelist.h>
81 #include <apt-pkg/sptr.h>
83 #include <sys/sysctl.h>
88 #include <mach-o/nlist.h>
99 /* iPhoneOS 2.0 Compatibility {{{ */
101 @interface UICGColor : NSObject {
104 - (id) initWithCGColor:(CGColorRef)color;
110 + (id)systemFontOfSize:(float)fp8;
111 + (id)boldSystemFontOfSize:(float)fp8;
112 - (UIFont *) fontWithSize:(CGFloat)size;
115 @interface NSObject (iPhoneOS)
116 - (CGColorRef) cgColor;
117 - (CGColorRef) CGColor;
121 @implementation NSObject (iPhoneOS)
123 - (CGColorRef) cgColor {
124 return [self CGColor];
127 - (CGColorRef) CGColor {
128 return (CGColorRef) self;
132 [[[[objc_getClass("UICGColor") alloc] initWithCGColor:[self CGColor]] autorelease] set];
137 @interface UITextView (iPhoneOS)
138 - (void) setTextSize:(float)size;
141 @implementation UITextView (iPhoneOS)
143 - (void) setTextSize:(float)size {
144 [self setFont:[[self font] fontWithSize:size]];
151 @interface UIApplication (IdleTimer)
152 - (void) setIdleTimerDisabled:(char)arg0;
157 kUIProgressIndicatorStyleLargeWhite = 0,
158 kUIProgressIndicatorStyleMediumWhite = 1,
159 kUIProgressIndicatorStyleSmallWhite = 3,
160 kUIProgressIndicatorStyleSmallBlack = 4
161 } UIProgressIndicatorStyle;
164 kUIProgressIndicatorStyleMediumWhite = 0,
165 kUIProgressIndicatorStyleSmallWhite = 2,
166 kUIProgressIndicatorStyleSmallBlack = 3
167 } UIProgressIndicatorStyle;
171 kUIControlEventMouseDown = 1 << 0,
172 kUIControlEventMouseMovedInside = 1 << 2, // mouse moved inside control target
173 kUIControlEventMouseMovedOutside = 1 << 3, // mouse moved outside control target
174 kUIControlEventMouseUpInside = 1 << 6, // mouse up inside control target
175 kUIControlEventMouseUpOutside = 1 << 7, // mouse up outside control target
176 kUIControlAllEvents = (kUIControlEventMouseDown | kUIControlEventMouseMovedInside | kUIControlEventMouseMovedOutside | kUIControlEventMouseUpInside | kUIControlEventMouseUpOutside)
177 } UIControlEventMasks;
179 @interface NSString (UIKit)
180 - (NSString *) stringByAddingPercentEscapes;
181 - (NSString *) stringByReplacingCharacter:(unsigned short)arg0 withCharacter:(unsigned short)arg1;
184 @interface NSString (Cydia)
185 + (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length;
186 - (NSComparisonResult) compareByPath:(NSString *)other;
189 @implementation NSString (Cydia)
191 + (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length {
192 char data[length + 1];
193 memcpy(data, bytes, length);
195 return [NSString stringWithUTF8String:data];
198 - (NSComparisonResult) compareByPath:(NSString *)other {
199 NSString *prefix = [self commonPrefixWithString:other options:0];
200 size_t length = [prefix length];
202 NSRange lrange = NSMakeRange(length, [self length] - length);
203 NSRange rrange = NSMakeRange(length, [other length] - length);
205 lrange = [self rangeOfString:@"/" options:0 range:lrange];
206 rrange = [other rangeOfString:@"/" options:0 range:rrange];
208 NSComparisonResult value;
210 if (lrange.location == NSNotFound && rrange.location == NSNotFound)
211 value = NSOrderedSame;
212 else if (lrange.location == NSNotFound)
213 value = NSOrderedAscending;
214 else if (rrange.location == NSNotFound)
215 value = NSOrderedDescending;
217 value = NSOrderedSame;
219 NSString *lpath = lrange.location == NSNotFound ? [self substringFromIndex:length] :
220 [self substringWithRange:NSMakeRange(length, lrange.location - length)];
221 NSString *rpath = rrange.location == NSNotFound ? [other substringFromIndex:length] :
222 [other substringWithRange:NSMakeRange(length, rrange.location - length)];
224 NSComparisonResult result = [lpath compare:rpath];
225 return result == NSOrderedSame ? value : result;
230 /* Perl-Compatible RegEx {{{ */
240 Pcre(const char *regex) :
245 code_ = pcre_compile(regex, 0, &error, &offset, NULL);
248 fprintf(stderr, "%d:%s\n", offset, error);
252 pcre_fullinfo(code_, study_, PCRE_INFO_CAPTURECOUNT, &capture_);
253 matches_ = new int[(capture_ + 1) * 3];
261 NSString *operator [](size_t match) {
262 return [NSString stringWithUTF8Bytes:(data_ + matches_[match * 2]) length:(matches_[match * 2 + 1] - matches_[match * 2])];
265 bool operator ()(NSString *data) {
266 // XXX: length is for characters, not for bytes
267 return operator ()([data UTF8String], [data length]);
270 bool operator ()(const char *data, size_t size) {
272 return pcre_exec(code_, study_, data, size, 0, 0, matches_, (capture_ + 1) * 3) >= 0;
276 /* Mime Addresses {{{ */
277 @interface Address : NSObject {
283 - (NSString *) address;
285 + (Address *) addressWithString:(NSString *)string;
286 - (Address *) initWithString:(NSString *)string;
289 @implementation Address
298 - (NSString *) name {
302 - (NSString *) address {
306 + (Address *) addressWithString:(NSString *)string {
307 return [[[Address alloc] initWithString:string] autorelease];
310 + (NSArray *) _attributeKeys {
311 return [NSArray arrayWithObjects:@"address", @"name", nil];
314 - (NSArray *) attributeKeys {
315 return [[self class] _attributeKeys];
318 + (BOOL) isKeyExcludedFromWebScript:(const char *)name {
319 return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name];
322 - (Address *) initWithString:(NSString *)string {
323 if ((self = [super init]) != nil) {
324 const char *data = [string UTF8String];
325 size_t size = [string length];
327 static Pcre address_r("^\"?(.*)\"? <([^>]*)>$");
329 if (address_r(data, size)) {
330 name_ = [address_r[1] retain];
331 address_ = [address_r[2] retain];
333 name_ = [[NSString alloc]
336 encoding:kCFStringEncodingUTF8
346 /* CoreGraphics Primitives {{{ */
357 CGColor(CGColorSpaceRef space, float red, float green, float blue, float alpha) :
360 Set(space, red, green, blue, alpha);
365 CGColorRelease(color_);
372 void Set(CGColorSpaceRef space, float red, float green, float blue, float alpha) {
374 float color[] = {red, green, blue, alpha};
375 color_ = CGColorCreate(space, color);
378 operator CGColorRef() {
393 /* Right Alignment {{{ */
394 @interface UIRightTextLabel : UITextLabel {
395 float _savedRightEdgeX;
396 BOOL _sizedtofit_flag;
399 - (void) setFrame:(CGRect)frame;
400 - (void) setText:(NSString *)text;
401 - (void) realignText;
404 @implementation UIRightTextLabel
406 - (void) setFrame:(CGRect)frame {
407 [super setFrame:frame];
408 if (_sizedtofit_flag == NO) {
409 _savedRightEdgeX = frame.origin.x;
414 - (void) setText:(NSString *)text {
415 [super setText:text];
419 - (void) realignText {
420 CGRect oldFrame = [self frame];
422 _sizedtofit_flag = YES;
423 [self sizeToFit]; // shrink down size so I can right align it
425 CGRect newFrame = [self frame];
427 oldFrame.origin.x = _savedRightEdgeX - newFrame.size.width;
428 oldFrame.size.width = newFrame.size.width;
429 [super setFrame:oldFrame];
430 _sizedtofit_flag = NO;
436 extern "C" void UISetColor(CGColorRef color);
438 /* Random Global Variables {{{ */
439 static const int PulseInterval_ = 50000;
440 static const int ButtonBarHeight_ = 48;
441 static const float KeyboardTime_ = 0.3f;
442 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];
852 debReleaseIndex *dindex(dynamic_cast<debReleaseIndex *>(index));
853 if (dindex != NULL) {
854 std::ifstream release(dindex->MetaIndexFile("Release").c_str());
856 while (std::getline(release, line)) {
857 std::string::size_type colon(line.find(':'));
858 if (colon == std::string::npos)
861 std::string name(line.substr(0, colon));
862 std::string value(line.substr(colon + 1));
863 while (!value.empty() && value[0] == ' ')
864 value = value.substr(1);
866 if (name == "Default-Icon")
867 defaultIcon_ = [[NSString stringWithUTF8String:value.c_str()] retain];
868 else if (name == "Description")
869 description_ = [[NSString stringWithUTF8String:value.c_str()] retain];
870 else if (name == "Label")
871 label_ = [[NSString stringWithUTF8String:value.c_str()] retain];
872 else if (name == "Origin")
873 origin_ = [[NSString stringWithUTF8String:value.c_str()] retain];
874 else if (name == "Version")
875 version_ = [[NSString stringWithUTF8String:value.c_str()] retain];
879 record_ = [Sources_ objectForKey:[self key]];
881 record_ = [record_ retain];
885 - (NSComparisonResult) compareByNameAndType:(Source *)source {
886 NSDictionary *lhr = [self record];
887 NSDictionary *rhr = [source record];
890 return lhr == nil ? NSOrderedDescending : NSOrderedAscending;
892 NSString *lhs = [self name];
893 NSString *rhs = [source name];
895 if ([lhs length] != 0 && [rhs length] != 0) {
896 unichar lhc = [lhs characterAtIndex:0];
897 unichar rhc = [rhs characterAtIndex:0];
899 if (isalpha(lhc) && !isalpha(rhc))
900 return NSOrderedAscending;
901 else if (!isalpha(lhc) && isalpha(rhc))
902 return NSOrderedDescending;
905 return [lhs caseInsensitiveCompare:rhs];
908 - (NSDictionary *) record {
920 - (NSString *) distribution {
921 return distribution_;
924 - (NSString *) type {
929 return [NSString stringWithFormat:@"%@:%@:%@", type_, uri_, distribution_];
932 - (NSString *) host {
933 return [[[NSURL URLWithString:[self uri]] host] lowercaseString];
936 - (NSString *) name {
937 return origin_ == nil ? [self host] : origin_;
940 - (NSString *) description {
944 - (NSString *) label {
945 return label_ == nil ? [self host] : label_;
948 - (NSString *) origin {
952 - (NSString *) version {
956 - (NSString *) defaultIcon {
962 /* Relationship Class {{{ */
963 @interface Relationship : NSObject {
974 @implementation Relationship
982 - (NSString *) type {
990 - (NSString *) name {
997 /* Package Class {{{ */
998 NSString *Scour(const char *field, const char *begin, const char *end) {
999 size_t i(0), l(strlen(field));
1002 const char *name = begin + i;
1003 const char *colon = name + l;
1004 const char *value = colon + 1;
1009 memcmp(name, field, l) == 0
1011 while (value != end && value[0] == ' ')
1013 const char *line = std::find(value, end, '\n');
1014 while (line != value && line[-1] == ' ')
1017 return [NSString stringWithUTF8Bytes:value length:(line - value)];
1019 begin = std::find(begin, end, '\n');
1027 @interface Package : NSObject {
1028 pkgCache::PkgIterator iterator_;
1029 _transient Database *database_;
1030 pkgCache::VerIterator version_;
1031 pkgCache::VerFileIterator file_;
1037 NSString *installed_;
1043 NSString *homepage_;
1044 NSString *depiction_;
1050 NSArray *relationships_;
1053 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
1054 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
1056 - (pkgCache::PkgIterator) iterator;
1058 - (NSString *) section;
1059 - (Address *) maintainer;
1061 - (NSString *) description;
1062 - (NSString *) index;
1066 - (NSString *) latest;
1067 - (NSString *) installed;
1070 - (BOOL) upgradableAndEssential:(BOOL)essential;
1076 - (BOOL) halfConfigured;
1077 - (BOOL) halfInstalled;
1079 - (NSString *) mode;
1082 - (NSString *) name;
1083 - (NSString *) tagline;
1084 - (NSString *) icon;
1085 - (NSString *) homepage;
1086 - (NSString *) depiction;
1087 - (Address *) author;
1089 - (NSArray *) relationships;
1091 - (Source *) source;
1092 - (NSString *) role;
1094 - (BOOL) matches:(NSString *)text;
1096 - (bool) hasSupportingRole;
1097 - (BOOL) hasTag:(NSString *)tag;
1099 - (NSComparisonResult) compareByName:(Package *)package;
1100 - (NSComparisonResult) compareBySection:(Package *)package;
1101 - (NSComparisonResult) compareBySectionAndName:(Package *)package;
1102 - (NSComparisonResult) compareForChanges:(Package *)package;
1107 - (NSNumber *) isVisiblySearchedForBy:(NSString *)search;
1108 - (NSNumber *) isInstalledAndVisible:(NSNumber *)number;
1109 - (NSNumber *) isVisiblyUninstalledInSection:(NSString *)section;
1110 - (NSNumber *) isVisibleInSource:(Source *)source;
1114 @implementation Package
1121 if (installed_ != nil)
1122 [installed_ release];
1130 if (homepage_ != nil)
1131 [homepage_ release];
1132 if (depiction_ != nil)
1133 [depiction_ release];
1134 if (sponsor_ != nil)
1143 if (relationships_ != nil)
1144 [relationships_ release];
1149 + (NSArray *) _attributeKeys {
1150 return [NSArray arrayWithObjects:@"author", @"depiction", @"description", @"essential", @"homepage", @"icon", @"id", @"installed", @"latest", @"maintainer", @"name", @"section", @"size", @"source", @"sponsor", @"tagline", nil];
1153 - (NSArray *) attributeKeys {
1154 return [[self class] _attributeKeys];
1157 + (BOOL) isKeyExcludedFromWebScript:(const char *)name {
1158 return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name];
1161 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
1162 if ((self = [super init]) != nil) {
1163 iterator_ = iterator;
1164 database_ = database;
1166 version_ = [database_ policy]->GetCandidateVer(iterator_);
1167 latest_ = version_.end() ? nil : [StripVersion([NSString stringWithUTF8String:version_.VerStr()]) retain];
1169 if (!version_.end())
1170 file_ = version_.FileList();
1172 pkgCache &cache([database_ cache]);
1173 file_ = pkgCache::VerFileIterator(cache, cache.VerFileP);
1176 pkgCache::VerIterator current = iterator_.CurrentVer();
1177 installed_ = current.end() ? nil : [StripVersion([NSString stringWithUTF8String:current.VerStr()]) retain];
1179 id_ = [[[NSString stringWithUTF8String:iterator_.Name()] lowercaseString] retain];
1182 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1184 const char *begin, *end;
1185 parser->GetRec(begin, end);
1187 name_ = Scour("Name", begin, end);
1189 name_ = [name_ retain];
1190 tagline_ = [[NSString stringWithUTF8String:parser->ShortDesc().c_str()] retain];
1191 icon_ = Scour("Icon", begin, end);
1193 icon_ = [icon_ retain];
1194 homepage_ = Scour("Homepage", begin, end);
1195 if (homepage_ == nil)
1196 homepage_ = Scour("Website", begin, end);
1197 if (homepage_ != nil)
1198 homepage_ = [homepage_ retain];
1199 depiction_ = Scour("Depiction", begin, end);
1200 if (depiction_ != nil)
1201 depiction_ = [depiction_ retain];
1202 NSString *sponsor = Scour("Sponsor", begin, end);
1204 sponsor_ = [[Address addressWithString:sponsor] retain];
1205 NSString *author = Scour("Author", begin, end);
1207 author_ = [[Address addressWithString:author] retain];
1208 NSString *tags = Scour("Tag", begin, end);
1210 tags_ = [[tags componentsSeparatedByString:@", "] retain];
1214 for (int i(0), e([tags_ count]); i != e; ++i) {
1215 NSString *tag = [tags_ objectAtIndex:i];
1216 if ([tag hasPrefix:@"role::"]) {
1217 role_ = [[tag substringFromIndex:6] retain];
1222 NSMutableDictionary *metadata = [Packages_ objectForKey:id_];
1223 if (metadata == nil || [metadata count] == 0) {
1224 metadata = [NSMutableDictionary dictionaryWithObjectsAndKeys:
1228 [Packages_ setObject:metadata forKey:id_];
1234 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
1235 return [[[Package alloc]
1236 initWithIterator:iterator
1241 - (pkgCache::PkgIterator) iterator {
1245 - (NSString *) section {
1246 const char *section = iterator_.Section();
1247 if (section == NULL)
1250 NSString *name = [[NSString stringWithUTF8String:section] stringByReplacingCharacter:' ' withCharacter:'_'];
1253 if (NSDictionary *value = [SectionMap_ objectForKey:name])
1254 if (NSString *rename = [value objectForKey:@"Rename"]) {
1259 return [name stringByReplacingCharacter:'_' withCharacter:' '];
1262 - (Address *) maintainer {
1265 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1266 return [Address addressWithString:[NSString stringWithUTF8String:parser->Maintainer().c_str()]];
1270 return version_.end() ? 0 : version_->InstalledSize;
1273 - (NSString *) description {
1276 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1277 NSString *description([NSString stringWithUTF8String:parser->LongDesc().c_str()]);
1279 NSArray *lines = [description componentsSeparatedByString:@"\n"];
1280 NSMutableArray *trimmed = [NSMutableArray arrayWithCapacity:([lines count] - 1)];
1281 if ([lines count] < 2)
1284 NSCharacterSet *whitespace = [NSCharacterSet whitespaceCharacterSet];
1285 for (size_t i(1); i != [lines count]; ++i) {
1286 NSString *trim = [[lines objectAtIndex:i] stringByTrimmingCharactersInSet:whitespace];
1287 [trimmed addObject:trim];
1290 return [trimmed componentsJoinedByString:@"\n"];
1293 - (NSString *) index {
1294 NSString *index = [[[self name] substringToIndex:1] uppercaseString];
1295 return [index length] != 0 && isalpha([index characterAtIndex:0]) ? index : @"123";
1299 return [[Packages_ objectForKey:id_] objectForKey:@"FirstSeen"];
1302 - (NSString *) latest {
1306 - (NSString *) installed {
1311 return !version_.end();
1314 - (BOOL) upgradableAndEssential:(BOOL)essential {
1315 pkgCache::VerIterator current = iterator_.CurrentVer();
1318 return essential && [self essential];
1320 pkgCache::VerIterator candidate = [database_ policy]->GetCandidateVer(iterator_);
1321 return !candidate.end() && candidate != current;
1325 - (BOOL) essential {
1326 return (iterator_->Flags & pkgCache::Flag::Essential) == 0 ? NO : YES;
1330 return [database_ cache][iterator_].InstBroken();
1334 NSString *section = [self section];
1335 return [self hasSupportingRole] && (section == nil || isSectionVisible(section));
1339 unsigned char current = iterator_->CurrentState;
1340 return current == pkgCache::State::HalfConfigured || current == pkgCache::State::HalfInstalled;
1343 - (BOOL) halfConfigured {
1344 return iterator_->CurrentState == pkgCache::State::HalfConfigured;
1347 - (BOOL) halfInstalled {
1348 return iterator_->CurrentState == pkgCache::State::HalfInstalled;
1352 pkgDepCache::StateCache &state([database_ cache][iterator_]);
1353 return state.Mode != pkgDepCache::ModeKeep;
1356 - (NSString *) mode {
1357 pkgDepCache::StateCache &state([database_ cache][iterator_]);
1359 switch (state.Mode) {
1360 case pkgDepCache::ModeDelete:
1361 if ((state.iFlags & pkgDepCache::Purge) != 0)
1366 case pkgDepCache::ModeKeep:
1367 if ((state.iFlags & pkgDepCache::AutoKept) != 0)
1372 case pkgDepCache::ModeInstall:
1373 if ((state.iFlags & pkgDepCache::ReInstall) != 0)
1374 return @"Reinstall";
1375 else switch (state.Status) {
1377 return @"Downgrade";
1383 return @"New Install";
1396 - (NSString *) name {
1397 return name_ == nil ? id_ : name_;
1400 - (NSString *) tagline {
1404 - (NSString *) icon {
1408 - (NSString *) homepage {
1412 - (NSString *) depiction {
1416 - (Address *) sponsor {
1420 - (Address *) author {
1424 - (NSArray *) relationships {
1425 return relationships_;
1428 - (Source *) source {
1430 source_ = file_.end() ? nil : [[database_ getSource:file_.File()] retain];
1437 - (NSString *) role {
1441 - (BOOL) matches:(NSString *)text {
1447 range = [[self id] rangeOfString:text options:NSCaseInsensitiveSearch];
1448 if (range.location != NSNotFound)
1451 range = [[self name] rangeOfString:text options:NSCaseInsensitiveSearch];
1452 if (range.location != NSNotFound)
1455 range = [[self tagline] rangeOfString:text options:NSCaseInsensitiveSearch];
1456 if (range.location != NSNotFound)
1462 - (bool) hasSupportingRole {
1465 if ([role_ isEqualToString:@"enduser"])
1467 if ([Role_ isEqualToString:@"User"])
1469 if ([role_ isEqualToString:@"hacker"])
1471 if ([Role_ isEqualToString:@"Hacker"])
1473 if ([role_ isEqualToString:@"developer"])
1475 if ([Role_ isEqualToString:@"Developer"])
1480 - (BOOL) hasTag:(NSString *)tag {
1481 return tags_ == nil ? NO : [tags_ containsObject:tag];
1484 - (NSComparisonResult) compareByName:(Package *)package {
1485 NSString *lhs = [self name];
1486 NSString *rhs = [package name];
1488 if ([lhs length] != 0 && [rhs length] != 0) {
1489 unichar lhc = [lhs characterAtIndex:0];
1490 unichar rhc = [rhs characterAtIndex:0];
1492 if (isalpha(lhc) && !isalpha(rhc))
1493 return NSOrderedAscending;
1494 else if (!isalpha(lhc) && isalpha(rhc))
1495 return NSOrderedDescending;
1498 return [lhs caseInsensitiveCompare:rhs];
1501 - (NSComparisonResult) compareBySection:(Package *)package {
1502 NSString *lhs = [self section];
1503 NSString *rhs = [package section];
1505 if (lhs == NULL && rhs != NULL)
1506 return NSOrderedAscending;
1507 else if (lhs != NULL && rhs == NULL)
1508 return NSOrderedDescending;
1509 else if (lhs != NULL && rhs != NULL) {
1510 NSComparisonResult result = [lhs caseInsensitiveCompare:rhs];
1511 if (result != NSOrderedSame)
1515 return NSOrderedSame;
1518 - (NSComparisonResult) compareBySectionAndName:(Package *)package {
1519 NSString *lhs = [self section];
1520 NSString *rhs = [package section];
1522 if (lhs == NULL && rhs != NULL)
1523 return NSOrderedAscending;
1524 else if (lhs != NULL && rhs == NULL)
1525 return NSOrderedDescending;
1526 else if (lhs != NULL && rhs != NULL) {
1527 NSComparisonResult result = [lhs compare:rhs];
1528 if (result != NSOrderedSame)
1532 return [self compareByName:package];
1535 - (NSComparisonResult) compareForChanges:(Package *)package {
1536 BOOL lhs = [self upgradableAndEssential:YES];
1537 BOOL rhs = [package upgradableAndEssential:YES];
1540 return lhs ? NSOrderedAscending : NSOrderedDescending;
1542 switch ([[self seen] compare:[package seen]]) {
1543 case NSOrderedAscending:
1544 return NSOrderedDescending;
1547 case NSOrderedDescending:
1548 return NSOrderedAscending;
1554 return [self compareByName:package];
1558 pkgProblemResolver *resolver = [database_ resolver];
1559 resolver->Clear(iterator_);
1560 resolver->Protect(iterator_);
1561 pkgCacheFile &cache([database_ cache]);
1562 cache->MarkInstall(iterator_, false);
1563 pkgDepCache::StateCache &state((*cache)[iterator_]);
1564 if (!state.Install())
1565 cache->SetReInstall(iterator_, true);
1569 pkgProblemResolver *resolver = [database_ resolver];
1570 resolver->Clear(iterator_);
1571 resolver->Protect(iterator_);
1572 resolver->Remove(iterator_);
1573 [database_ cache]->MarkDelete(iterator_, true);
1576 - (NSNumber *) isVisiblySearchedForBy:(NSString *)search {
1577 return [NSNumber numberWithBool:(
1578 [self valid] && [self visible] && [self matches:search]
1582 - (NSNumber *) isInstalledAndVisible:(NSNumber *)number {
1583 return [NSNumber numberWithBool:(
1584 (![number boolValue] || [self visible]) && [self installed] != nil
1588 - (NSNumber *) isVisiblyUninstalledInSection:(NSString *)name {
1589 NSString *section = [self section];
1591 return [NSNumber numberWithBool:(
1592 [self valid] && [self visible] &&
1593 [self installed] == nil && (
1595 section == nil && [name length] == 0 ||
1596 [name isEqualToString:section]
1601 - (NSNumber *) isVisibleInSource:(Source *)source {
1602 return [NSNumber numberWithBool:([self source] == source && [self visible])];
1607 /* Section Class {{{ */
1608 @interface Section : NSObject {
1614 - (NSComparisonResult) compareByName:(Section *)section;
1615 - (Section *) initWithName:(NSString *)name;
1616 - (Section *) initWithName:(NSString *)name row:(size_t)row;
1617 - (NSString *) name;
1620 - (void) addToCount;
1624 @implementation Section
1631 - (NSComparisonResult) compareByName:(Section *)section {
1632 NSString *lhs = [self name];
1633 NSString *rhs = [section name];
1635 if ([lhs length] != 0 && [rhs length] != 0) {
1636 unichar lhc = [lhs characterAtIndex:0];
1637 unichar rhc = [rhs characterAtIndex:0];
1639 if (isalpha(lhc) && !isalpha(rhc))
1640 return NSOrderedAscending;
1641 else if (!isalpha(lhc) && isalpha(rhc))
1642 return NSOrderedDescending;
1645 return [lhs caseInsensitiveCompare:rhs];
1648 - (Section *) initWithName:(NSString *)name {
1649 return [self initWithName:name row:0];
1652 - (Section *) initWithName:(NSString *)name row:(size_t)row {
1653 if ((self = [super init]) != nil) {
1654 name_ = [name retain];
1659 - (NSString *) name {
1671 - (void) addToCount {
1681 /* Database Implementation {{{ */
1682 @implementation Database
1689 - (void) _readCydia:(NSNumber *)fd {
1690 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1692 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1693 std::istream is(&ib);
1696 static Pcre finish_r("^finish:([^:]*)$");
1698 while (std::getline(is, line)) {
1699 const char *data(line.c_str());
1700 size_t size = line.size();
1701 fprintf(stderr, "C:%s\n", data);
1703 if (finish_r(data, size)) {
1704 NSString *finish = finish_r[1];
1705 int index = [Finishes_ indexOfObject:finish];
1706 if (index != INT_MAX && index > Finish_)
1715 - (void) _readStatus:(NSNumber *)fd {
1716 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1718 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1719 std::istream is(&ib);
1722 static Pcre conffile_r("^status: [^ ]* : conffile-prompt : (.*?) *$");
1723 static Pcre pmstatus_r("^([^:]*):([^:]*):([^:]*):(.*)$");
1725 while (std::getline(is, line)) {
1726 const char *data(line.c_str());
1727 size_t size = line.size();
1728 fprintf(stderr, "S:%s\n", data);
1730 if (conffile_r(data, size)) {
1731 [delegate_ setConfigurationData:conffile_r[1]];
1732 } else if (strncmp(data, "status: ", 8) == 0) {
1733 NSString *string = [NSString stringWithUTF8String:(data + 8)];
1734 [delegate_ setProgressTitle:string];
1735 } else if (pmstatus_r(data, size)) {
1736 std::string type([pmstatus_r[1] UTF8String]);
1737 NSString *id = pmstatus_r[2];
1739 float percent([pmstatus_r[3] floatValue]);
1740 [delegate_ setProgressPercent:(percent / 100)];
1742 NSString *string = pmstatus_r[4];
1744 if (type == "pmerror")
1745 [delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
1746 withObject:[NSArray arrayWithObjects:string, id, nil]
1749 else if (type == "pmstatus")
1750 [delegate_ setProgressTitle:string];
1751 else if (type == "pmconffile")
1752 [delegate_ setConfigurationData:string];
1753 else _assert(false);
1754 } else _assert(false);
1761 - (void) _readOutput:(NSNumber *)fd {
1762 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1764 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1765 std::istream is(&ib);
1768 while (std::getline(is, line)) {
1769 fprintf(stderr, "O:%s\n", line.c_str());
1770 [delegate_ addProgressOutput:[NSString stringWithUTF8String:line.c_str()]];
1781 - (Package *) packageWithName:(NSString *)name {
1782 if (static_cast<pkgDepCache *>(cache_) == NULL)
1784 pkgCache::PkgIterator iterator(cache_->FindPkg([name UTF8String]));
1785 return iterator.end() ? nil : [Package packageWithIterator:iterator database:self];
1788 - (Database *) init {
1789 if ((self = [super init]) != nil) {
1796 sources_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1797 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
1801 _assert(pipe(fds) != -1);
1804 _config->Set("APT::Keep-Fds::", cydiafd_);
1805 setenv("CYDIA", [[[[NSNumber numberWithInt:cydiafd_] stringValue] stringByAppendingString:@" 1"] UTF8String], _not(int));
1808 detachNewThreadSelector:@selector(_readCydia:)
1810 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1813 _assert(pipe(fds) != -1);
1817 detachNewThreadSelector:@selector(_readStatus:)
1819 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1822 _assert(pipe(fds) != -1);
1823 _assert(dup2(fds[0], 0) != -1);
1824 _assert(close(fds[0]) != -1);
1826 input_ = fdopen(fds[1], "a");
1828 _assert(pipe(fds) != -1);
1829 _assert(dup2(fds[1], 1) != -1);
1830 _assert(close(fds[1]) != -1);
1833 detachNewThreadSelector:@selector(_readOutput:)
1835 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1840 - (pkgCacheFile &) cache {
1844 - (pkgDepCache::Policy *) policy {
1848 - (pkgRecords *) records {
1852 - (pkgProblemResolver *) resolver {
1856 - (pkgAcquire &) fetcher {
1860 - (NSArray *) packages {
1864 - (NSArray *) sources {
1865 return [sources_ allValues];
1868 - (void) reloadData {
1887 if (!cache_.Open(progress_, true)) {
1889 if (!_error->PopMessage(error))
1892 fprintf(stderr, "cache_.Open():[%s]\n", error.c_str());
1894 if (error == "dpkg was interrupted, you must manually run 'dpkg --configure -a' to correct the problem. ")
1895 [delegate_ repairWithSelector:@selector(configure)];
1896 else if (error == "The package lists or status file could not be parsed or opened.")
1897 [delegate_ repairWithSelector:@selector(update)];
1898 // else if (error == "Could not open lock file /var/lib/dpkg/lock - open (13 Permission denied)")
1899 // else if (error == "Could not get lock /var/lib/dpkg/lock - open (35 Resource temporarily unavailable)")
1900 // else if (error == "The list of sources could not be read.")
1901 else _assert(false);
1906 now_ = [[NSDate date] retain];
1908 policy_ = new pkgDepCache::Policy();
1909 records_ = new pkgRecords(cache_);
1910 resolver_ = new pkgProblemResolver(cache_);
1911 fetcher_ = new pkgAcquire(&status_);
1914 list_ = new pkgSourceList();
1915 _assert(list_->ReadMainList());
1917 _assert(cache_->DelCount() == 0 && cache_->InstCount() == 0);
1918 _assert(pkgApplyStatus(cache_));
1920 if (cache_->BrokenCount() != 0) {
1921 _assert(pkgFixBroken(cache_));
1922 _assert(cache_->BrokenCount() == 0);
1923 _assert(pkgMinimizeUpgrade(cache_));
1926 [sources_ removeAllObjects];
1927 for (pkgSourceList::const_iterator source = list_->begin(); source != list_->end(); ++source) {
1928 std::vector<pkgIndexFile *> *indices = (*source)->GetIndexFiles();
1929 for (std::vector<pkgIndexFile *>::const_iterator index = indices->begin(); index != indices->end(); ++index)
1931 setObject:[[[Source alloc] initWithMetaIndex:*source] autorelease]
1932 forKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(*index)]
1936 [packages_ removeAllObjects];
1937 for (pkgCache::PkgIterator iterator = cache_->PkgBegin(); !iterator.end(); ++iterator)
1938 if (Package *package = [Package packageWithIterator:iterator database:self])
1939 [packages_ addObject:package];
1941 [packages_ sortUsingSelector:@selector(compareByName:)];
1944 - (void) configure {
1945 NSString *dpkg = [NSString stringWithFormat:@"dpkg --configure -a --status-fd %u", statusfd_];
1946 system([dpkg UTF8String]);
1954 Lock.Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1955 _assert(!_error->PendingError());
1958 fetcher.Clean(_config->FindDir("Dir::Cache::Archives"));
1961 public pkgArchiveCleaner
1964 virtual void Erase(const char *File, std::string Pkg, std::string Ver, struct stat &St) {
1969 if (!cleaner.Go(_config->FindDir("Dir::Cache::Archives") + "partial/", cache_)) {
1971 while (_error->PopMessage(error))
1972 fprintf(stderr, "ArchiveCleaner: %s\n", error.c_str());
1977 pkgRecords records(cache_);
1979 lock_ = new FileFd();
1980 lock_->Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1981 _assert(!_error->PendingError());
1984 // XXX: explain this with an error message
1985 _assert(list.ReadMainList());
1987 manager_ = (_system->CreatePM(cache_));
1988 _assert(manager_->GetArchives(fetcher_, &list, &records));
1989 _assert(!_error->PendingError());
1993 NSMutableArray *before = [NSMutableArray arrayWithCapacity:16]; {
1995 _assert(list.ReadMainList());
1996 for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source)
1997 [before addObject:[NSString stringWithUTF8String:(*source)->GetURI().c_str()]];
2000 if (fetcher_->Run(PulseInterval_) != pkgAcquire::Continue) {
2005 bool failed = false;
2006 for (pkgAcquire::ItemIterator item = fetcher_->ItemsBegin(); item != fetcher_->ItemsEnd(); item++) {
2007 if ((*item)->Status == pkgAcquire::Item::StatDone && (*item)->Complete)
2010 std::string uri = (*item)->DescURI();
2011 std::string error = (*item)->ErrorText;
2013 fprintf(stderr, "pAf:%s:%s\n", uri.c_str(), error.c_str());
2016 [delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
2017 withObject:[NSArray arrayWithObjects:[NSString stringWithUTF8String:error.c_str()], nil]
2028 pkgPackageManager::OrderResult result = manager_->DoInstall(statusfd_);
2030 if (_error->PendingError()) {
2035 if (result == pkgPackageManager::Failed) {
2040 if (result != pkgPackageManager::Completed) {
2045 NSMutableArray *after = [NSMutableArray arrayWithCapacity:16]; {
2047 _assert(list.ReadMainList());
2048 for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source)
2049 [after addObject:[NSString stringWithUTF8String:(*source)->GetURI().c_str()]];
2052 if (![before isEqualToArray:after])
2057 _assert(pkgDistUpgrade(cache_));
2061 [self updateWithStatus:status_];
2064 - (void) updateWithStatus:(Status &)status {
2066 _assert(list.ReadMainList());
2069 lock.Fd(GetLock(_config->FindDir("Dir::State::Lists") + "lock"));
2070 _assert(!_error->PendingError());
2072 pkgAcquire fetcher(&status);
2073 _assert(list.GetIndexes(&fetcher));
2075 if (fetcher.Run(PulseInterval_) != pkgAcquire::Failed) {
2076 bool failed = false;
2077 for (pkgAcquire::ItemIterator item = fetcher.ItemsBegin(); item != fetcher.ItemsEnd(); item++)
2078 if ((*item)->Status != pkgAcquire::Item::StatDone) {
2079 (*item)->Finished();
2083 if (!failed && _config->FindB("APT::Get::List-Cleanup", true) == true) {
2084 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists")));
2085 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/"));
2088 [Metadata_ setObject:[NSDate date] forKey:@"LastUpdate"];
2093 - (void) setDelegate:(id)delegate {
2094 delegate_ = delegate;
2095 status_.setDelegate(delegate);
2096 progress_.setDelegate(delegate);
2099 - (Source *) getSource:(const pkgCache::PkgFileIterator &)file {
2100 pkgIndexFile *index(NULL);
2101 list_->FindIndex(file, index);
2102 return [sources_ objectForKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(index)]];
2108 /* Confirmation View {{{ */
2109 void AddTextView(NSMutableDictionary *fields, NSMutableArray *packages, NSString *key) {
2110 if ([packages count] == 0)
2113 UITextView *text = GetTextView([packages count] == 0 ? @"n/a" : [packages componentsJoinedByString:@", "], 120, false);
2114 [fields setObject:text forKey:key];
2116 CGColor blue(space_, 0, 0, 0.4, 1);
2117 [text setTextColor:blue];
2120 @protocol ConfirmationViewDelegate
2125 @interface ConfirmationView : UIView {
2126 Database *database_;
2128 UITransitionView *transition_;
2130 UINavigationBar *navbar_;
2131 UIPreferencesTable *table_;
2132 NSMutableDictionary *fields_;
2133 UIAlertSheet *essential_;
2138 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate;
2142 @implementation ConfirmationView
2145 [navbar_ setDelegate:nil];
2146 [transition_ setDelegate:nil];
2147 [table_ setDataSource:nil];
2149 [transition_ release];
2154 if (essential_ != nil)
2155 [essential_ release];
2160 [transition_ transition:7 toView:nil];
2164 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
2165 if (from != nil && to == nil)
2166 [self removeFromSuperview];
2169 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2172 if (essential_ != nil)
2173 [essential_ popupAlertAnimated:YES];
2175 [delegate_ confirm];
2184 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
2185 NSString *context = [sheet context];
2187 if ([context isEqualToString:@"remove"])
2193 [delegate_ confirm];
2198 else if ([context isEqualToString:@"unable"])
2204 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
2208 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
2210 case 0: return @"Statistics";
2211 case 1: return @"Modifications";
2213 default: _assert(false);
2217 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
2220 case 1: return [fields_ count];
2222 default: _assert(false);
2226 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
2227 if (group != 1 || row == -1)
2230 _assert(size_t(row) < [fields_ count]);
2231 return [[[fields_ allValues] objectAtIndex:row] visibleTextRect].size.height + TextViewOffset_;
2235 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
2236 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
2237 [cell setShowSelection:NO];
2240 case 0: switch (row) {
2242 [cell setTitle:@"Downloading"];
2243 [cell setValue:SizeString([database_ fetcher].FetchNeeded())];
2247 [cell setTitle:@"Resuming At"];
2248 [cell setValue:SizeString([database_ fetcher].PartialPresent())];
2252 double size([database_ cache]->UsrSize());
2255 [cell setTitle:@"Disk Freeing"];
2256 [cell setValue:SizeString(-size)];
2258 [cell setTitle:@"Disk Using"];
2259 [cell setValue:SizeString(size)];
2263 default: _assert(false);
2267 _assert(size_t(row) < [fields_ count]);
2268 [cell setTitle:[[fields_ allKeys] objectAtIndex:row]];
2269 [cell addSubview:[[fields_ allValues] objectAtIndex:row]];
2272 default: _assert(false);
2278 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate {
2279 if ((self = [super initWithFrame:[view bounds]]) != nil) {
2280 database_ = database;
2281 delegate_ = delegate;
2283 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
2284 [self addSubview:transition_];
2286 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
2288 CGSize navsize = [UINavigationBar defaultSize];
2289 CGRect navrect = {{0, 0}, navsize};
2290 CGRect bounds = [overlay_ bounds];
2292 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
2293 [navbar_ setDelegate:self];
2295 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Confirm"] autorelease];
2296 [navbar_ pushNavigationItem:navitem];
2297 [navbar_ showButtonsWithLeftTitle:@"Cancel" rightTitle:@"Confirm"];
2299 fields_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
2301 NSMutableArray *installing = [NSMutableArray arrayWithCapacity:16];
2302 NSMutableArray *reinstalling = [NSMutableArray arrayWithCapacity:16];
2303 NSMutableArray *upgrading = [NSMutableArray arrayWithCapacity:16];
2304 NSMutableArray *downgrading = [NSMutableArray arrayWithCapacity:16];
2305 NSMutableArray *removing = [NSMutableArray arrayWithCapacity:16];
2309 pkgCacheFile &cache([database_ cache]);
2310 NSArray *packages = [database_ packages];
2311 for (size_t i(0), e = [packages count]; i != e; ++i) {
2312 Package *package = [packages objectAtIndex:i];
2313 pkgCache::PkgIterator iterator = [package iterator];
2314 pkgDepCache::StateCache &state(cache[iterator]);
2316 NSString *name([package name]);
2318 if (state.NewInstall())
2319 [installing addObject:name];
2320 else if (!state.Delete() && (state.iFlags & pkgDepCache::ReInstall) == pkgDepCache::ReInstall)
2321 [reinstalling addObject:name];
2322 else if (state.Upgrade())
2323 [upgrading addObject:name];
2324 else if (state.Downgrade())
2325 [downgrading addObject:name];
2326 else if (state.Delete()) {
2327 if ([package essential])
2329 [removing addObject:name];
2335 else if (Advanced_ || true) {
2336 essential_ = [[UIAlertSheet alloc]
2337 initWithTitle:@"Removing Essentials"
2338 buttons:[NSArray arrayWithObjects:
2339 @"Cancel Operation (Safe)",
2340 @"Force Removal (Unsafe)",
2342 defaultButtonIndex:0
2348 [essential_ setDestructiveButton:[[essential_ buttons] objectAtIndex:0]];
2350 [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."];
2352 essential_ = [[UIAlertSheet alloc]
2353 initWithTitle:@"Unable to Comply"
2354 buttons:[NSArray arrayWithObjects:@"Okay", nil]
2355 defaultButtonIndex:0
2360 [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."];
2363 AddTextView(fields_, installing, @"Installing");
2364 AddTextView(fields_, reinstalling, @"Reinstalling");
2365 AddTextView(fields_, upgrading, @"Upgrading");
2366 AddTextView(fields_, downgrading, @"Downgrading");
2367 AddTextView(fields_, removing, @"Removing");
2369 table_ = [[UIPreferencesTable alloc] initWithFrame:CGRectMake(
2370 0, navsize.height, bounds.size.width, bounds.size.height - navsize.height
2373 [table_ setReusesTableCells:YES];
2374 [table_ setDataSource:self];
2375 [table_ reloadData];
2377 [overlay_ addSubview:navbar_];
2378 [overlay_ addSubview:table_];
2380 [view addSubview:self];
2382 [transition_ setDelegate:self];
2384 UIView *blank = [[[UIView alloc] initWithFrame:[transition_ bounds]] autorelease];
2385 [transition_ transition:0 toView:blank];
2386 [transition_ transition:3 toView:overlay_];
2393 /* Progress Data {{{ */
2394 @interface ProgressData : NSObject {
2400 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object;
2407 @implementation ProgressData
2409 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object {
2410 if ((self = [super init]) != nil) {
2411 selector_ = selector;
2431 /* Progress View {{{ */
2432 @interface ProgressView : UIView <
2433 ConfigurationDelegate,
2436 _transient Database *database_;
2438 UIView *background_;
2439 UITransitionView *transition_;
2441 UINavigationBar *navbar_;
2442 UIProgressBar *progress_;
2443 UITextView *output_;
2444 UITextLabel *status_;
2445 UIPushButton *close_;
2448 SHA1SumValue springlist_;
2451 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
2453 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database delegate:(id)delegate;
2454 - (void) setContentView:(UIView *)view;
2457 - (void) _retachThread;
2458 - (void) _detachNewThreadData:(ProgressData *)data;
2459 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title;
2465 @protocol ProgressViewDelegate
2466 - (void) progressViewIsComplete:(ProgressView *)sender;
2469 @implementation ProgressView
2472 [transition_ setDelegate:nil];
2473 [navbar_ setDelegate:nil];
2476 if (background_ != nil)
2477 [background_ release];
2478 [transition_ release];
2481 [progress_ release];
2488 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
2489 if (bootstrap_ && from == overlay_ && to == view_)
2493 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database delegate:(id)delegate {
2494 if ((self = [super initWithFrame:frame]) != nil) {
2495 database_ = database;
2496 delegate_ = delegate;
2498 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
2499 [transition_ setDelegate:self];
2501 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
2504 [overlay_ setBackgroundColor:Black_];
2506 background_ = [[UIView alloc] initWithFrame:[self bounds]];
2507 [background_ setBackgroundColor:Black_];
2508 [self addSubview:background_];
2511 [self addSubview:transition_];
2513 CGSize navsize = [UINavigationBar defaultSize];
2514 CGRect navrect = {{0, 0}, navsize};
2516 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
2517 [overlay_ addSubview:navbar_];
2519 [navbar_ setBarStyle:1];
2520 [navbar_ setDelegate:self];
2522 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:nil] autorelease];
2523 [navbar_ pushNavigationItem:navitem];
2525 CGRect bounds = [overlay_ bounds];
2526 CGSize prgsize = [UIProgressBar defaultSize];
2529 (bounds.size.width - prgsize.width) / 2,
2530 bounds.size.height - prgsize.height - 20
2533 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
2534 [progress_ setStyle:0];
2536 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(
2538 bounds.size.height - prgsize.height - 50,
2539 bounds.size.width - 20,
2543 [status_ setColor:White_];
2544 [status_ setBackgroundColor:Clear_];
2546 [status_ setCentersHorizontally:YES];
2547 //[status_ setFont:font];
2549 output_ = [[UITextView alloc] initWithFrame:CGRectMake(
2551 navrect.size.height + 20,
2552 bounds.size.width - 20,
2553 bounds.size.height - navsize.height - 62 - navrect.size.height
2556 //[output_ setTextFont:@"Courier New"];
2557 [output_ setTextSize:12];
2559 [output_ setTextColor:White_];
2560 [output_ setBackgroundColor:Clear_];
2562 [output_ setMarginTop:0];
2563 [output_ setAllowsRubberBanding:YES];
2564 [output_ setEditable:NO];
2566 [overlay_ addSubview:output_];
2568 close_ = [[UIPushButton alloc] initWithFrame:CGRectMake(
2570 bounds.size.height - prgsize.height - 50,
2571 bounds.size.width - 20,
2575 [close_ setAutosizesToFit:NO];
2576 [close_ setDrawsShadow:YES];
2577 [close_ setStretchBackground:YES];
2578 [close_ setEnabled:YES];
2580 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22);
2581 [close_ setTitleFont:bold];
2584 [close_ addTarget:self action:@selector(closeButtonPushed) forEvents:kUIControlEventMouseUpInside];
2585 [close_ setBackground:[UIImage applicationImageNamed:@"green-up.png"] forState:0];
2586 [close_ setBackground:[UIImage applicationImageNamed:@"green-dn.png"] forState:1];
2590 - (void) setContentView:(UIView *)view {
2591 view_ = [view retain];
2594 - (void) resetView {
2595 [transition_ transition:6 toView:view_];
2598 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
2599 NSString *context = [sheet context];
2600 if ([context isEqualToString:@"conffile"]) {
2601 FILE *input = [database_ input];
2605 fprintf(input, "N\n");
2609 fprintf(input, "Y\n");
2620 - (void) closeButtonPushed {
2623 [delegate_ progressViewIsComplete:self];
2628 [delegate_ suspendWithAnimation:YES];
2632 system("killall SpringBoard");
2636 system("launchctl unload /System/Library/LaunchDaemons/com.apple.SpringBoard.plist; launchctl load /System/Library/LaunchDaemons/com.apple.SpringBoard.plist");
2645 - (void) _retachThread {
2646 UINavigationItem *item = [navbar_ topItem];
2647 [item setTitle:@"Complete"];
2649 [overlay_ addSubview:close_];
2650 [progress_ removeFromSuperview];
2651 [status_ removeFromSuperview];
2654 FileFd file("/System/Library/LaunchDaemons/com.apple.SpringBoard.plist", FileFd::ReadOnly);
2655 MMap mmap(file, MMap::ReadOnly);
2657 sha1.Add(reinterpret_cast<uint8_t *>(mmap.Data()), mmap.Size());
2658 if (!(springlist_ == sha1.Result()))
2663 case 0: [close_ setTitle:@"Return to Cydia"]; break;
2664 case 1: [close_ setTitle:@"Close Cydia (Restart)"]; break;
2665 case 2: [close_ setTitle:@"Restart SpringBoard"]; break;
2666 case 3: [close_ setTitle:@"Reload SpringBoard"]; break;
2667 case 4: [close_ setTitle:@"Reboot Device"]; break;
2671 notify_post("com.apple.mobile.application_installed");
2674 [delegate_ setStatusBarShowsProgress:NO];
2679 - (void) _detachNewThreadData:(ProgressData *)data {
2680 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
2682 [[data target] performSelector:[data selector] withObject:[data object]];
2685 [self performSelectorOnMainThread:@selector(_retachThread) withObject:nil waitUntilDone:YES];
2690 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title {
2691 UINavigationItem *item = [navbar_ topItem];
2692 [item setTitle:title];
2694 [status_ setText:nil];
2695 [output_ setText:@""];
2696 [progress_ setProgress:0];
2698 [close_ removeFromSuperview];
2699 [overlay_ addSubview:progress_];
2700 [overlay_ addSubview:status_];
2702 [delegate_ setStatusBarShowsProgress:YES];
2706 FileFd file("/System/Library/LaunchDaemons/com.apple.SpringBoard.plist", FileFd::ReadOnly);
2707 MMap mmap(file, MMap::ReadOnly);
2709 sha1.Add(reinterpret_cast<uint8_t *>(mmap.Data()), mmap.Size());
2710 springlist_ = sha1.Result();
2713 [transition_ transition:6 toView:overlay_];
2716 detachNewThreadSelector:@selector(_detachNewThreadData:)
2718 withObject:[[ProgressData alloc]
2719 initWithSelector:selector
2726 - (void) repairWithSelector:(SEL)selector {
2728 detachNewThreadSelector:selector
2731 title:@"Repairing..."
2735 - (void) setConfigurationData:(NSString *)data {
2737 performSelectorOnMainThread:@selector(_setConfigurationData:)
2743 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id {
2744 Package *package = id == nil ? nil : [database_ packageWithName:id];
2746 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
2747 initWithTitle:(package == nil ? @"Source Error" : [package name])
2748 buttons:[NSArray arrayWithObjects:@"Okay", nil]
2749 defaultButtonIndex:0
2754 [sheet setBodyText:error];
2755 [sheet popupAlertAnimated:YES];
2758 - (void) setProgressTitle:(NSString *)title {
2760 performSelectorOnMainThread:@selector(_setProgressTitle:)
2766 - (void) setProgressPercent:(float)percent {
2768 performSelectorOnMainThread:@selector(_setProgressPercent:)
2769 withObject:[NSNumber numberWithFloat:percent]
2774 - (void) addProgressOutput:(NSString *)output {
2776 performSelectorOnMainThread:@selector(_addProgressOutput:)
2782 - (void) _setConfigurationData:(NSString *)data {
2783 static Pcre conffile_r("^'(.*)' '(.*)' ([01]) ([01])$");
2785 _assert(conffile_r(data));
2787 NSString *ofile = conffile_r[1];
2788 //NSString *nfile = conffile_r[2];
2790 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
2791 initWithTitle:@"Configuration Upgrade"
2792 buttons:[NSArray arrayWithObjects:
2793 @"Keep My Old Copy",
2794 @"Accept The New Copy",
2795 // XXX: @"See What Changed",
2797 defaultButtonIndex:0
2802 [sheet setBodyText:[NSString stringWithFormat:
2803 @"The following file has been changed by both the package maintainer and by you (or for you by a script).\n\n%@"
2806 [sheet popupAlertAnimated:YES];
2809 - (void) _setProgressTitle:(NSString *)title {
2810 [status_ setText:[title stringByAppendingString:@"..."]];
2813 - (void) _setProgressPercent:(NSNumber *)percent {
2814 [progress_ setProgress:[percent floatValue]];
2817 - (void) _addProgressOutput:(NSString *)output {
2818 [output_ setText:[NSString stringWithFormat:@"%@\n%@", [output_ text], output]];
2819 CGSize size = [output_ contentSize];
2820 CGRect rect = {{0, size.height}, {size.width, 0}};
2821 [output_ scrollRectToVisible:rect animated:YES];
2824 - (BOOL) isRunning {
2831 /* Package Cell {{{ */
2832 @interface PackageCell : UISimpleTableCell {
2835 NSString *description_;
2837 //UIImageView *trusted_;
2839 UIImageView *badge_;
2840 UITextLabel *status_;
2844 - (PackageCell *) init;
2845 - (void) setPackage:(Package *)package;
2847 + (int) heightForPackage:(Package *)package;
2851 @implementation PackageCell
2853 - (void) clearPackage {
2864 if (description_ != nil) {
2865 [description_ release];
2869 if (source_ != nil) {
2876 [self clearPackage];
2881 //[trusted_ release];
2885 - (PackageCell *) init {
2886 if ((self = [super init]) != nil) {
2888 badge_ = [[UIImageView alloc] initWithFrame:CGRectMake(17, 70, 16, 16)];
2890 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 68, 280, 20)];
2891 [status_ setBackgroundColor:Clear_];
2892 [status_ setFont:small];
2897 - (void) setPackage:(Package *)package {
2898 [self clearPackage];
2900 Source *source = [package source];
2903 if (NSString *icon = [package icon])
2904 icon_ = [UIImage imageAtPath:[icon substringFromIndex:6]];
2905 if (icon_ == nil) if (NSString *section = [package section])
2906 icon_ = [UIImage applicationImageNamed:[NSString stringWithFormat:@"Sections/%@.png", Simplify(section)]];
2907 /*if (icon_ == nil) if (NSString *icon = [source defaultIcon])
2908 icon_ = [UIImage imageAtPath:[icon substringFromIndex:6]];*/
2910 icon_ = [UIImage applicationImageNamed:@"unknown.png"];
2912 icon_ = [icon_ retain];
2914 name_ = [[package name] retain];
2915 description_ = [[package tagline] retain];
2917 NSString *label = nil;
2918 bool trusted = false;
2920 if (source != nil) {
2921 label = [source label];
2922 trusted = [source trusted];
2923 } else if ([[package id] isEqualToString:@"firmware"])
2926 label = @"Unknown/Local";
2928 NSString *from = [NSString stringWithFormat:@"from %@", label];
2930 NSString *section = Simplify([package section]);
2931 if (section != nil && ![section isEqualToString:label])
2932 from = [from stringByAppendingString:[NSString stringWithFormat:@" (%@)", section]];
2934 source_ = [from retain];
2937 [badge_ removeFromSuperview];
2938 [status_ removeFromSuperview];
2940 if (NSString *mode = [package mode]) {
2941 [badge_ setImage:[UIImage applicationImageNamed:
2942 [mode isEqualToString:@"Remove"] || [mode isEqualToString:@"Purge"] ? @"removing.png" : @"installing.png"
2945 [status_ setText:[NSString stringWithFormat:@"Queued for %@", mode]];
2946 [status_ setColor:Blueish_];
2947 } else if ([package half]) {
2948 [badge_ setImage:[UIImage applicationImageNamed:@"damaged.png"]];
2949 [status_ setText:@"Package Damaged"];
2950 [status_ setColor:Red_];
2952 [badge_ setImage:nil];
2953 [status_ setText:nil];
2957 [self addSubview:badge_];
2958 [self addSubview:status_];
2963 - (void) drawContentInRect:(CGRect)rect selected:(BOOL)selected {
2965 [icon_ drawInRect:CGRectMake(10, 10, 30, 30)];
2972 [name_ drawAtPoint:CGPointMake(48, 8) forWidth:240 withFont:Font18Bold_ ellipsis:2];
2973 [source_ drawAtPoint:CGPointMake(58, 29) forWidth:225 withFont:Font12_ ellipsis:2];
2977 [description_ drawAtPoint:CGPointMake(12, 46) forWidth:280 withFont:Font14_ ellipsis:2];
2979 [super drawContentInRect:rect selected:selected];
2982 + (int) heightForPackage:(Package *)package {
2983 NSString *tagline([package tagline]);
2984 int height = tagline == nil || [tagline length] == 0 ? -17 : 0;
2986 if ([package hasMode] || [package half])
2995 /* Section Cell {{{ */
2996 @interface SectionCell : UISimpleTableCell {
3001 UISwitchControl *switch_;
3006 - (void) setSection:(Section *)section editing:(BOOL)editing;
3010 @implementation SectionCell
3012 - (void) clearSection {
3013 if (section_ != nil) {
3023 if (count_ != nil) {
3030 [self clearSection];
3037 if ((self = [super init]) != nil) {
3038 icon_ = [[UIImage applicationImageNamed:@"folder.png"] retain];
3040 switch_ = [[UISwitchControl alloc] initWithFrame:CGRectMake(218, 9, 60, 25)];
3041 [switch_ addTarget:self action:@selector(onSwitch:) forEvents:kUIControlEventMouseUpInside];
3045 - (void) onSwitch:(id)sender {
3046 NSMutableDictionary *metadata = [Sections_ objectForKey:section_];
3047 if (metadata == nil) {
3048 metadata = [NSMutableDictionary dictionaryWithCapacity:2];
3049 [Sections_ setObject:metadata forKey:section_];
3053 [metadata setObject:[NSNumber numberWithBool:([switch_ value] == 0)] forKey:@"Hidden"];
3056 - (void) setSection:(Section *)section editing:(BOOL)editing {
3057 if (editing != editing_) {
3059 [switch_ removeFromSuperview];
3061 [self addSubview:switch_];
3065 [self clearSection];
3067 if (section == nil) {
3068 name_ = [@"All Packages" retain];
3071 section_ = [section name];
3072 if (section_ != nil)
3073 section_ = [section_ retain];
3074 name_ = [(section_ == nil ? @"(No Section)" : section_) retain];
3075 count_ = [[NSString stringWithFormat:@"%d", [section count]] retain];
3078 [switch_ setValue:isSectionVisible(section_) animated:NO];
3082 - (void) drawContentInRect:(CGRect)rect selected:(BOOL)selected {
3083 [icon_ drawInRect:CGRectMake(8, 7, 32, 32)];
3090 [name_ drawAtPoint:CGPointMake(48, 9) forWidth:(editing_ ? 164 : 250) withFont:Font22Bold_ ellipsis:2];
3092 CGSize size = [count_ sizeWithFont:Font14_];
3096 [count_ drawAtPoint:CGPointMake(12 + (29 - size.width) / 2, 15) withFont:Font12Bold_];
3098 [super drawContentInRect:rect selected:selected];
3104 /* File Table {{{ */
3105 @interface FileTable : RVPage {
3106 _transient Database *database_;
3109 NSMutableArray *files_;
3113 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3114 - (void) setPackage:(Package *)package;
3118 @implementation FileTable
3121 if (package_ != nil)
3130 - (int) numberOfRowsInTable:(UITable *)table {
3131 return files_ == nil ? 0 : [files_ count];
3134 - (float) table:(UITable *)table heightForRow:(int)row {
3138 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
3139 if (reusing == nil) {
3140 reusing = [[[UIImageAndTextTableCell alloc] init] autorelease];
3141 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
3142 [[(UIImageAndTextTableCell *)reusing titleTextLabel] setFont:font];
3145 [(UIImageAndTextTableCell *)reusing setTitle:[files_ objectAtIndex:row]];
3149 - (BOOL) table:(UITable *)table canSelectRow:(int)row {
3153 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3154 if ((self = [super initWithBook:book]) != nil) {
3155 database_ = database;
3157 files_ = [[NSMutableArray arrayWithCapacity:32] retain];
3159 list_ = [[UITable alloc] initWithFrame:[self bounds]];
3160 [self addSubview:list_];
3162 UITableColumn *column = [[[UITableColumn alloc]
3163 initWithTitle:@"Name"
3165 width:[self frame].size.width
3168 [list_ setDataSource:self];
3169 [list_ setSeparatorStyle:1];
3170 [list_ addTableColumn:column];
3171 [list_ setDelegate:self];
3172 [list_ setReusesTableCells:YES];
3176 - (void) setPackage:(Package *)package {
3177 if (package_ != nil) {
3178 [package_ autorelease];
3187 [files_ removeAllObjects];
3189 if (package != nil) {
3190 package_ = [package retain];
3191 name_ = [[package id] retain];
3193 NSString *path = [NSString stringWithFormat:@"/var/lib/dpkg/info/%@.list", name_];
3196 std::ifstream fin([path UTF8String]);
3198 while (std::getline(fin, line))
3199 [files_ addObject:[NSString stringWithUTF8String:line.c_str()]];
3202 if ([files_ count] != 0) {
3203 if ([[files_ objectAtIndex:0] isEqualToString:@"/."])
3204 [files_ removeObjectAtIndex:0];
3205 [files_ sortUsingSelector:@selector(compareByPath:)];
3207 NSMutableArray *stack = [NSMutableArray arrayWithCapacity:8];
3208 [stack addObject:@"/"];
3210 for (int i(0), e([files_ count]); i != e; ++i) {
3211 NSString *file = [files_ objectAtIndex:i];
3212 while (![file hasPrefix:[stack lastObject]])
3213 [stack removeLastObject];
3214 NSString *directory = [stack lastObject];
3215 [stack addObject:[file stringByAppendingString:@"/"]];
3216 [files_ replaceObjectAtIndex:i withObject:[NSString stringWithFormat:@"%*s%@",
3217 ([stack count] - 2) * 3, "",
3218 [file substringFromIndex:[directory length]]
3227 - (void) resetViewAnimated:(BOOL)animated {
3228 [list_ resetViewAnimated:animated];
3231 - (void) reloadData {
3232 [self setPackage:[database_ packageWithName:name_]];
3233 [self reloadButtons];
3236 - (NSString *) title {
3237 return @"Installed Files";
3240 - (NSString *) backButtonTitle {
3246 /* Package View {{{ */
3247 @interface PackageView : BrowserView {
3250 NSMutableArray *buttons_;
3253 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3254 - (void) setPackage:(Package *)package;
3258 @implementation PackageView
3261 if (package_ != nil)
3269 - (void) _clickButtonWithName:(NSString *)name {
3270 if ([name isEqualToString:@"Install"])
3271 [delegate_ installPackage:package_];
3272 else if ([name isEqualToString:@"Reinstall"])
3273 [delegate_ installPackage:package_];
3274 else if ([name isEqualToString:@"Remove"])
3275 [delegate_ removePackage:package_];
3276 else if ([name isEqualToString:@"Upgrade"])
3277 [delegate_ installPackage:package_];
3278 else _assert(false);
3281 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
3282 int count = [buttons_ count];
3283 _assert(count != 0);
3284 _assert(button <= count + 1);
3286 if (count != button - 1)
3287 [self _clickButtonWithName:[buttons_ objectAtIndex:(button - 1)]];
3292 - (void) webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame {
3293 [window setValue:package_ forKey:@"package"];
3296 - (void) _rightButtonClicked {
3297 /*[super _rightButtonClicked];
3300 int count = [buttons_ count];
3301 _assert(count != 0);
3304 [self _clickButtonWithName:[buttons_ objectAtIndex:0]];
3306 NSMutableArray *buttons = [NSMutableArray arrayWithCapacity:(count + 1)];
3307 [buttons addObjectsFromArray:buttons_];
3308 [buttons addObject:@"Cancel"];
3310 [delegate_ slideUp:[[[UIAlertSheet alloc]
3313 defaultButtonIndex:2
3320 - (NSString *) _rightButtonTitle {
3321 int count = [buttons_ count];
3322 return count == 0 ? nil : count != 1 ? @"Modify" : [buttons_ objectAtIndex:0];
3325 - (NSString *) title {
3329 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3330 if ((self = [super initWithBook:book database:database]) != nil) {
3331 database_ = database;
3332 buttons_ = [[NSMutableArray alloc] initWithCapacity:4];
3336 - (void) setPackage:(Package *)package {
3337 if (package_ != nil) {
3338 [package_ autorelease];
3347 [buttons_ removeAllObjects];
3349 if (package != nil) {
3350 package_ = [package retain];
3351 name_ = [[package id] retain];
3353 [self loadURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"package" ofType:@"html"]]];
3355 if ([package_ source] == nil);
3356 else if ([package_ upgradableAndEssential:NO])
3357 [buttons_ addObject:@"Upgrade"];
3358 else if ([package_ installed] == nil)
3359 [buttons_ addObject:@"Install"];
3361 [buttons_ addObject:@"Reinstall"];
3362 if ([package_ installed] != nil)
3363 [buttons_ addObject:@"Remove"];
3367 - (void) reloadData {
3368 [self setPackage:[database_ packageWithName:name_]];
3369 [self reloadButtons];
3374 /* Package Table {{{ */
3375 @interface PackageTable : RVPage {
3376 _transient Database *database_;
3380 NSMutableArray *packages_;
3381 NSMutableArray *sections_;
3382 UISectionList *list_;
3385 - (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object;
3387 - (void) setDelegate:(id)delegate;
3388 - (void) setObject:(id)object;
3390 - (void) reloadData;
3391 - (void) resetCursor;
3393 - (UISectionList *) list;
3395 - (void) setShouldHideHeaderInShortLists:(BOOL)hide;
3399 @implementation PackageTable
3402 [list_ setDataSource:nil];
3407 [packages_ release];
3408 [sections_ release];
3413 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
3414 return [sections_ count];
3417 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
3418 return [[sections_ objectAtIndex:section] name];
3421 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
3422 return [[sections_ objectAtIndex:section] row];
3425 - (int) numberOfRowsInTable:(UITable *)table {
3426 return [packages_ count];
3429 - (float) table:(UITable *)table heightForRow:(int)row {
3430 return [PackageCell heightForPackage:[packages_ objectAtIndex:row]];
3433 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
3435 reusing = [[[PackageCell alloc] init] autorelease];
3436 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
3440 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
3444 - (void) tableRowSelected:(NSNotification *)notification {
3445 int row = [[notification object] selectedRow];
3449 Package *package = [packages_ objectAtIndex:row];
3450 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
3451 [view setDelegate:delegate_];
3452 [view setPackage:package];
3453 [book_ pushPage:view];
3456 - (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object {
3457 if ((self = [super initWithBook:book]) != nil) {
3458 database_ = database;
3459 title_ = [title retain];
3461 object_ = object == nil ? nil : [object retain];
3463 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
3464 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
3466 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:YES];
3467 [list_ setDataSource:self];
3469 UITableColumn *column = [[[UITableColumn alloc]
3470 initWithTitle:@"Name"
3472 width:[self frame].size.width
3475 UITable *table = [list_ table];
3476 [table setSeparatorStyle:1];
3477 [table addTableColumn:column];
3478 [table setDelegate:self];
3479 [table setReusesTableCells:YES];
3481 [self addSubview:list_];
3486 - (void) setDelegate:(id)delegate {
3487 delegate_ = delegate;
3490 - (void) setObject:(id)object {
3496 object_ = [object retain];
3499 - (void) reloadData {
3500 NSArray *packages = [database_ packages];
3502 [packages_ removeAllObjects];
3503 [sections_ removeAllObjects];
3505 for (size_t i(0); i != [packages count]; ++i) {
3506 Package *package([packages objectAtIndex:i]);
3507 if ([[package performSelector:filter_ withObject:object_] boolValue])
3508 [packages_ addObject:package];
3511 Section *section = nil;
3513 for (size_t offset(0); offset != [packages_ count]; ++offset) {
3514 Package *package = [packages_ objectAtIndex:offset];
3515 NSString *name = [package index];
3517 if (section == nil || ![[section name] isEqualToString:name]) {
3518 section = [[[Section alloc] initWithName:name row:offset] autorelease];
3519 [sections_ addObject:section];
3522 [section addToCount];
3528 - (NSString *) title {
3532 - (void) resetViewAnimated:(BOOL)animated {
3533 [list_ resetViewAnimated:animated];
3536 - (void) resetCursor {
3537 [[list_ table] scrollPointVisibleAtTopLeft:CGPointMake(0, 0) animated:NO];
3540 - (UISectionList *) list {
3544 - (void) setShouldHideHeaderInShortLists:(BOOL)hide {
3545 [list_ setShouldHideHeaderInShortLists:hide];
3551 /* Add Source View {{{ */
3552 @interface AddSourceView : RVPage {
3553 _transient Database *database_;
3556 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3560 @implementation AddSourceView
3562 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3563 if ((self = [super initWithBook:book]) != nil) {
3564 database_ = database;
3570 /* Source Cell {{{ */
3571 @interface SourceCell : UITableCell {
3574 NSString *description_;
3580 - (SourceCell *) initWithSource:(Source *)source;
3584 @implementation SourceCell
3589 [description_ release];
3594 - (SourceCell *) initWithSource:(Source *)source {
3595 if ((self = [super init]) != nil) {
3597 icon_ = [UIImage applicationImageNamed:[NSString stringWithFormat:@"Sources/%@.png", [source host]]];
3599 icon_ = [UIImage applicationImageNamed:@"unknown.png"];
3600 icon_ = [icon_ retain];
3602 origin_ = [[source name] retain];
3603 label_ = [[source uri] retain];
3604 description_ = [[source description] retain];
3608 - (void) drawContentInRect:(CGRect)rect selected:(BOOL)selected {
3610 [icon_ drawInRect:CGRectMake(10, 10, 30, 30)];
3617 [origin_ drawAtPoint:CGPointMake(48, 8) forWidth:240 withFont:Font18Bold_ ellipsis:2];
3621 [label_ drawAtPoint:CGPointMake(58, 29) forWidth:225 withFont:Font12_ ellipsis:2];
3625 [description_ drawAtPoint:CGPointMake(12, 46) forWidth:280 withFont:Font14_ ellipsis:2];
3627 [super drawContentInRect:rect selected:selected];
3632 /* Source Table {{{ */
3633 @interface SourceTable : RVPage {
3634 _transient Database *database_;
3635 UISectionList *list_;
3636 NSMutableArray *sources_;
3637 UIAlertSheet *alert_;
3641 UIProgressHUD *hud_;
3644 //NSURLConnection *installer_;
3645 NSURLConnection *trivial_bz2_;
3646 NSURLConnection *trivial_gz_;
3647 //NSURLConnection *automatic_;
3652 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3656 @implementation SourceTable
3658 - (void) _deallocConnection:(NSURLConnection *)connection {
3659 if (connection != nil) {
3660 [connection cancel];
3661 //[connection setDelegate:nil];
3662 [connection release];
3667 [[list_ table] setDelegate:nil];
3668 [list_ setDataSource:nil];
3677 //[self _deallocConnection:installer_];
3678 [self _deallocConnection:trivial_gz_];
3679 [self _deallocConnection:trivial_bz2_];
3680 //[self _deallocConnection:automatic_];
3687 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
3688 return offset_ == 0 ? 1 : 2;
3691 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
3692 switch (section + (offset_ == 0 ? 1 : 0)) {
3693 case 0: return @"Entered by User";
3694 case 1: return @"Installed by Packages";
3702 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
3703 switch (section + (offset_ == 0 ? 1 : 0)) {
3705 case 1: return offset_;
3713 - (int) numberOfRowsInTable:(UITable *)table {
3714 return [sources_ count];
3717 - (float) table:(UITable *)table heightForRow:(int)row {
3718 Source *source = [sources_ objectAtIndex:row];
3719 return [source description] == nil ? 56 : 73;
3722 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col {
3723 Source *source = [sources_ objectAtIndex:row];
3724 // XXX: weird warning, stupid selectors ;P
3725 return [[[SourceCell alloc] initWithSource:(id)source] autorelease];
3728 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
3732 - (BOOL) table:(UITable *)table canSelectRow:(int)row {
3736 - (void) tableRowSelected:(NSNotification*)notification {
3737 UITable *table([list_ table]);
3738 int row([table selectedRow]);
3742 Source *source = [sources_ objectAtIndex:row];
3744 PackageTable *packages = [[[PackageTable alloc]
3747 title:[source label]
3748 filter:@selector(isVisibleInSource:)
3752 [packages setDelegate:delegate_];
3754 [book_ pushPage:packages];
3757 - (BOOL) table:(UITable *)table canDeleteRow:(int)row {
3758 Source *source = [sources_ objectAtIndex:row];
3759 return [source record] != nil;
3762 - (void) table:(UITable *)table willSwipeToDeleteRow:(int)row {
3763 [[list_ table] setDeleteConfirmationRow:row];
3766 - (void) table:(UITable *)table deleteRow:(int)row {
3767 Source *source = [sources_ objectAtIndex:row];
3768 [Sources_ removeObjectForKey:[source key]];
3769 [delegate_ syncData];
3772 - (void) _endConnection:(NSURLConnection *)connection {
3773 NSURLConnection **field = NULL;
3774 if (connection == trivial_bz2_)
3775 field = &trivial_bz2_;
3776 else if (connection == trivial_gz_)
3777 field = &trivial_gz_;
3778 _assert(field != NULL);
3779 [connection release];
3783 trivial_bz2_ == nil &&
3786 [delegate_ setStatusBarShowsProgress:NO];
3789 [hud_ removeFromSuperview];
3794 [Sources_ setObject:[NSDictionary dictionaryWithObjectsAndKeys:
3797 @"./", @"Distribution",
3798 nil] forKey:[NSString stringWithFormat:@"deb:%@:./", href_]];
3800 [delegate_ syncData];
3801 } else if (error_ != nil) {
3802 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
3803 initWithTitle:@"Verification Error"
3804 buttons:[NSArray arrayWithObjects:@"OK", nil]
3805 defaultButtonIndex:0
3810 [sheet setBodyText:[error_ localizedDescription]];
3811 [sheet popupAlertAnimated:YES];
3813 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
3814 initWithTitle:@"Did not Find Repository"
3815 buttons:[NSArray arrayWithObjects:@"OK", nil]
3816 defaultButtonIndex:0
3821 [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."];
3822 [sheet popupAlertAnimated:YES];
3828 if (error_ != nil) {
3835 - (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response {
3836 switch ([response statusCode]) {
3842 - (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
3843 fprintf(stderr, "connection:\"%s\" didFailWithError:\"%s\"", [href_ UTF8String], [[error localizedDescription] UTF8String]);
3845 error_ = [error retain];
3846 [self _endConnection:connection];
3849 - (void) connectionDidFinishLoading:(NSURLConnection *)connection {
3850 [self _endConnection:connection];
3853 - (NSURLConnection *) _requestHRef:(NSString *)href method:(NSString *)method {
3854 NSMutableURLRequest *request = [NSMutableURLRequest
3855 requestWithURL:[NSURL URLWithString:href]
3856 cachePolicy:NSURLRequestUseProtocolCachePolicy
3857 timeoutInterval:20.0
3860 [request setHTTPMethod:method];
3862 return [[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease];
3865 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
3866 NSString *context = [sheet context];
3867 if ([context isEqualToString:@"source"])
3870 NSString *href = [[sheet textField] text];
3872 //installer_ = [[self _requestHRef:href method:@"GET"] retain];
3874 if (![href hasSuffix:@"/"])
3875 href_ = [href stringByAppendingString:@"/"];
3878 href_ = [href_ retain];
3880 trivial_bz2_ = [[self _requestHRef:[href_ stringByAppendingString:@"Packages.bz2"] method:@"HEAD"] retain];
3881 trivial_gz_ = [[self _requestHRef:[href_ stringByAppendingString:@"Packages.gz"] method:@"HEAD"] retain];
3882 //trivial_bz2_ = [[self _requestHRef:[href stringByAppendingString:@"dists/Release"] method:@"HEAD"] retain];
3886 hud_ = [delegate_ addProgressHUD];
3887 [hud_ setText:@"Verifying URL"];
3900 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3901 if ((self = [super initWithBook:book]) != nil) {
3902 database_ = database;
3903 sources_ = [[NSMutableArray arrayWithCapacity:16] retain];
3905 //list_ = [[UITable alloc] initWithFrame:[self bounds]];
3906 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:NO];
3907 [list_ setShouldHideHeaderInShortLists:NO];
3909 [self addSubview:list_];
3910 [list_ setDataSource:self];
3912 UITableColumn *column = [[UITableColumn alloc]
3913 initWithTitle:@"Name"
3915 width:[self frame].size.width
3918 UITable *table = [list_ table];
3919 [table setSeparatorStyle:1];
3920 [table addTableColumn:column];
3921 [table setDelegate:self];
3927 - (void) reloadData {
3929 _assert(list.ReadMainList());
3931 [sources_ removeAllObjects];
3932 [sources_ addObjectsFromArray:[database_ sources]];
3933 [sources_ sortUsingSelector:@selector(compareByNameAndType:)];
3935 int count = [sources_ count];
3936 for (offset_ = 0; offset_ != count; ++offset_) {
3937 Source *source = [sources_ objectAtIndex:offset_];
3938 if ([source record] == nil)
3945 - (void) resetViewAnimated:(BOOL)animated {
3946 [list_ resetViewAnimated:animated];
3949 - (void) _leftButtonClicked {
3950 /*[book_ pushPage:[[[AddSourceView alloc]
3955 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
3956 initWithTitle:@"Enter Cydia/APT URL"
3957 buttons:[NSArray arrayWithObjects:@"Add Source", @"Cancel", nil]
3958 defaultButtonIndex:0
3963 [sheet addTextFieldWithValue:@"http://" label:@""];
3965 UITextTraits *traits = [[sheet textField] textTraits];
3966 [traits setAutoCapsType:0];
3967 [traits setPreferredKeyboardType:3];
3968 [traits setAutoCorrectionType:1];
3970 [sheet popupAlertAnimated:YES];
3973 - (void) _rightButtonClicked {
3974 UITable *table = [list_ table];
3975 BOOL editing = [table isRowDeletionEnabled];
3976 [table enableRowDeletion:!editing animated:YES];
3977 [book_ reloadButtonsForPage:self];
3980 - (NSString *) title {
3984 - (NSString *) backButtonTitle {
3988 - (NSString *) leftButtonTitle {
3989 return [[list_ table] isRowDeletionEnabled] ? @"Add" : nil;
3992 - (NSString *) rightButtonTitle {
3993 return [[list_ table] isRowDeletionEnabled] ? @"Done" : @"Edit";
3996 - (RVUINavBarButtonStyle) rightButtonStyle {
3997 return [[list_ table] isRowDeletionEnabled] ? RVUINavBarButtonStyleHighlighted : RVUINavBarButtonStyleNormal;
4003 /* Installed View {{{ */
4004 @interface InstalledView : RVPage {
4005 _transient Database *database_;
4006 PackageTable *packages_;
4010 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4014 @implementation InstalledView
4017 [packages_ release];
4021 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4022 if ((self = [super initWithBook:book]) != nil) {
4023 database_ = database;
4025 packages_ = [[PackageTable alloc]
4029 filter:@selector(isInstalledAndVisible:)
4030 with:[NSNumber numberWithBool:YES]
4033 [self addSubview:packages_];
4037 - (void) resetViewAnimated:(BOOL)animated {
4038 [packages_ resetViewAnimated:animated];
4041 - (void) reloadData {
4042 [packages_ reloadData];
4045 - (void) _rightButtonClicked {
4046 [packages_ setObject:[NSNumber numberWithBool:expert_]];
4047 [packages_ reloadData];
4049 [book_ reloadButtonsForPage:self];
4052 - (NSString *) title {
4053 return @"Installed";
4056 - (NSString *) backButtonTitle {
4060 - (NSString *) rightButtonTitle {
4061 return Role_ != nil && [Role_ isEqualToString:@"Developer"] ? nil : expert_ ? @"Expert" : @"Simple";
4064 - (RVUINavBarButtonStyle) rightButtonStyle {
4065 return expert_ ? RVUINavBarButtonStyleHighlighted : RVUINavBarButtonStyleNormal;
4068 - (void) setDelegate:(id)delegate {
4069 [super setDelegate:delegate];
4070 [packages_ setDelegate:delegate];
4077 @interface HomeView : BrowserView {
4082 @implementation HomeView
4084 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
4088 - (void) _leftButtonClicked {
4089 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
4090 initWithTitle:@"About Cydia Installer"
4091 buttons:[NSArray arrayWithObjects:@"Close", nil]
4092 defaultButtonIndex:0
4098 @"Copyright (C) 2008\n"
4099 "Jay Freeman (saurik)\n"
4100 "saurik@saurik.com\n"
4101 "http://www.saurik.com/\n"
4104 "http://www.theokorigroup.com/\n"
4106 "College of Creative Studies,\n"
4107 "University of California,\n"
4109 "http://www.ccs.ucsb.edu/"
4112 [sheet popupAlertAnimated:YES];
4115 - (NSString *) leftButtonTitle {
4121 /* Manage View {{{ */
4122 @interface ManageView : BrowserView {
4127 @implementation ManageView
4129 - (NSString *) title {
4133 - (void) _leftButtonClicked {
4134 [delegate_ askForSettings];
4137 - (NSString *) leftButtonTitle {
4141 - (NSString *) _rightButtonTitle {
4148 /* Browser Implementation {{{ */
4149 @implementation BrowserView
4152 WebView *webview = [webview_ webView];
4153 [webview setFrameLoadDelegate:nil];
4154 [webview setResourceLoadDelegate:nil];
4155 [webview setUIDelegate:nil];
4157 [scroller_ setDelegate:nil];
4158 [webview_ setDelegate:nil];
4160 [scroller_ release];
4163 [indicator_ release];
4169 - (void) loadURL:(NSURL *)url cachePolicy:(NSURLRequestCachePolicy)policy {
4170 [self loadRequest:[NSURLRequest
4173 timeoutInterval:30.0
4177 - (void) loadURL:(NSURL *)url {
4178 [self loadURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy];
4181 - (NSURLRequest *) _addHeadersToRequest:(NSURLRequest *)request {
4182 NSMutableURLRequest *copy = [request mutableCopy];
4184 [copy addValue:[NSString stringWithUTF8String:Firmware_] forHTTPHeaderField:@"X-Firmware"];
4185 [copy addValue:[NSString stringWithUTF8String:Machine_] forHTTPHeaderField:@"X-Machine"];
4186 [copy addValue:[NSString stringWithUTF8String:SerialNumber_] forHTTPHeaderField:@"X-Serial-Number"];
4189 [copy addValue:Role_ forHTTPHeaderField:@"X-Role"];
4194 - (void) loadRequest:(NSURLRequest *)request {
4196 [webview_ loadRequest:request];
4199 - (void) reloadURL {
4200 NSURL *url = [[[urls_ lastObject] retain] autorelease];
4201 [urls_ removeLastObject];
4202 [self loadURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData];
4205 - (WebView *) webView {
4206 return [webview_ webView];
4209 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame {
4210 [scroller_ setContentSize:frame.size];
4213 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old {
4214 [self view:sender didSetFrame:frame];
4217 - (void) pushPage:(RVPage *)page {
4218 [self setBackButtonTitle:title_];
4219 [page setDelegate:delegate_];
4220 [book_ pushPage:page];
4223 - (void) getSpecial:(NSString *)href {
4226 if ([href hasPrefix:@"mailto:"])
4227 [delegate_ openURL:[NSURL URLWithString:href]];
4228 else if ([href isEqualToString:@"cydia://add-source"])
4229 page = [[[AddSourceView alloc] initWithBook:book_ database:database_] autorelease];
4230 else if ([href isEqualToString:@"cydia://sources"])
4231 page = [[[SourceTable alloc] initWithBook:book_ database:database_] autorelease];
4232 else if ([href isEqualToString:@"cydia://packages"])
4233 page = [[[InstalledView alloc] initWithBook:book_ database:database_] autorelease];
4234 else if ([href hasPrefix:@"cydia://files/"]) {
4235 NSString *name = [href substringFromIndex:14];
4237 if (Package *package = [database_ packageWithName:name]) {
4238 FileTable *files = [[[FileTable alloc] initWithBook:book_ database:database_] autorelease];
4239 [files setPackage:package];
4242 } else if ([href hasPrefix:@"apptapp://package/"]) {
4243 NSString *name = [href substringFromIndex:18];
4245 if (Package *package = [database_ packageWithName:name]) {
4246 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
4247 [view setPackage:package];
4250 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
4251 initWithTitle:@"Cannot Locate Package"
4252 buttons:[NSArray arrayWithObjects:@"Close", nil]
4253 defaultButtonIndex:0
4258 [sheet setBodyText:[NSString stringWithFormat:
4259 @"The package %@ cannot be found in your current sources. I might recommend installing more sources."
4262 [sheet popupAlertAnimated:YES];
4267 [self pushPage:page];
4270 - (void) webView:(WebView *)sender willClickElement:(id)element {
4271 if ([[element localName] isEqualToString:@"img"])
4272 do if ((element = [element parentNode]) == nil)
4274 while (![[element localName] isEqualToString:@"a"]);
4275 if (![element respondsToSelector:@selector(href)])
4277 NSString *href = [element href];
4280 [self getSpecial:href];
4283 - (BOOL) isSpecialScheme:(NSString *)scheme {
4285 [scheme isEqualToString:@"apptapp"] ||
4286 [scheme isEqualToString:@"cydia"] ||
4287 [scheme isEqualToString:@"mailto"];
4290 - (NSURLRequest *) webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource {
4291 NSURL *url = [request URL];
4292 if ([self isSpecialScheme:[url scheme]]) {
4293 [self getSpecial:[url absoluteString]];
4299 [book_ pushPage:self];
4302 return [self _addHeadersToRequest:request];
4305 - (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request {
4306 if (request != nil) {
4307 NSString *scheme = [[request URL] scheme];
4308 if ([self isSpecialScheme:scheme])
4312 [self setBackButtonTitle:title_];
4314 BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease];
4315 [browser setDelegate:delegate_];
4317 if (request != nil) {
4318 [browser loadRequest:[self _addHeadersToRequest:request]];
4319 [book_ pushPage:browser];
4322 return [browser webView];
4325 - (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame {
4326 if ([frame parentFrame] != nil)
4329 title_ = [title retain];
4330 [self setTitle:title];
4333 - (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame {
4334 if ([frame parentFrame] != nil)
4339 [indicator_ startAnimation];
4340 [self reloadButtons];
4342 if (title_ != nil) {
4347 [self setTitle:@"Loading..."];
4349 WebView *webview = [webview_ webView];
4350 NSString *href = [webview mainFrameURL];
4351 [urls_ addObject:[NSURL URLWithString:href]];
4353 CGRect webrect = [scroller_ frame];
4354 webrect.size.height = 0;
4355 [webview_ setFrame:webrect];
4358 - (void) _finishLoading {
4361 [indicator_ stopAnimation];
4362 [self reloadButtons];
4366 - (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
4367 if ([frame parentFrame] != nil)
4369 [self _finishLoading];
4372 - (void) webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
4373 if ([frame parentFrame] != nil)
4375 [self _finishLoading];
4377 [self loadURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@?%@",
4378 [[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"error" ofType:@"html"]] absoluteString],
4379 [[error localizedDescription] stringByAddingPercentEscapes]
4383 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4384 if ((self = [super initWithBook:book]) != nil) {
4385 database_ = database;
4388 struct CGRect bounds = [self bounds];
4390 UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:bounds] autorelease];
4391 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
4392 [self addSubview:pinstripe];
4394 scroller_ = [[UIScroller alloc] initWithFrame:bounds];
4395 [self addSubview:scroller_];
4397 [scroller_ setScrollingEnabled:YES];
4398 [scroller_ setAdjustForContentSizeChange:YES];
4399 [scroller_ setClipsSubviews:YES];
4400 [scroller_ setAllowsRubberBanding:YES];
4401 [scroller_ setScrollDecelerationFactor:0.99];
4402 [scroller_ setDelegate:self];
4404 CGRect webrect = [scroller_ bounds];
4405 webrect.size.height = 0;
4407 webview_ = [[UIWebView alloc] initWithFrame:webrect];
4408 [scroller_ addSubview:webview_];
4410 [webview_ setTilingEnabled:YES];
4411 [webview_ setTileSize:CGSizeMake(webrect.size.width, 500)];
4412 [webview_ setAutoresizes:YES];
4413 [webview_ setDelegate:self];
4414 //[webview_ setEnabledGestures:2];
4416 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:kUIProgressIndicatorStyleMediumWhite];
4417 indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(281, 42, indsize.width, indsize.height)];
4418 [indicator_ setStyle:kUIProgressIndicatorStyleMediumWhite];
4420 Package *package([database_ packageWithName:@"cydia"]);
4421 NSString *application = package == nil ? @"Cydia" : [NSString
4422 stringWithFormat:@"Cydia/%@",
4426 WebView *webview = [webview_ webView];
4427 [webview setApplicationNameForUserAgent:application];
4428 [webview setFrameLoadDelegate:self];
4429 [webview setResourceLoadDelegate:self];
4430 [webview setUIDelegate:self];
4432 urls_ = [[NSMutableArray alloc] initWithCapacity:16];
4436 - (void) _rightButtonClicked {
4441 - (NSString *) _rightButtonTitle {
4445 - (NSString *) rightButtonTitle {
4446 return loading_ ? @"" : [self _rightButtonTitle];
4449 - (NSString *) title {
4453 - (NSString *) backButtonTitle {
4457 - (void) setPageActive:(BOOL)active {
4459 [book_ addSubview:indicator_];
4461 [indicator_ removeFromSuperview];
4464 - (void) resetViewAnimated:(BOOL)animated {
4467 - (void) setPushed:(bool)pushed {
4474 @interface CYBook : RVBook <
4477 _transient Database *database_;
4479 UIProgressIndicator *indicator_;
4480 UITextLabel *prompt_;
4481 UIProgressBar *progress_;
4485 - (id) initWithFrame:(CGRect)frame database:(Database *)database;
4491 /* Install View {{{ */
4492 @interface InstallView : RVPage {
4493 _transient Database *database_;
4494 NSMutableArray *sections_;
4495 NSMutableArray *filtered_;
4496 UITransitionView *transition_;
4502 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4503 - (void) reloadData;
4508 @implementation InstallView
4511 [list_ setDataSource:nil];
4512 [list_ setDelegate:nil];
4514 [sections_ release];
4515 [filtered_ release];
4516 [transition_ release];
4518 [accessory_ release];
4522 - (int) numberOfRowsInTable:(UITable *)table {
4523 return editing_ ? [sections_ count] : [filtered_ count] + 1;
4526 - (float) table:(UITable *)table heightForRow:(int)row {
4530 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
4532 reusing = [[[SectionCell alloc] init] autorelease];
4533 [(SectionCell *)reusing setSection:(editing_ ?
4534 [sections_ objectAtIndex:row] :
4535 (row == 0 ? nil : [filtered_ objectAtIndex:(row - 1)])
4536 ) editing:editing_];
4540 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
4544 - (BOOL) table:(UITable *)table canSelectRow:(int)row {
4548 - (void) tableRowSelected:(NSNotification *)notification {
4549 int row = [[notification object] selectedRow];
4560 title = @"All Packages";
4562 section = [filtered_ objectAtIndex:(row - 1)];
4563 name = [section name];
4569 title = @"(No Section)";
4573 PackageTable *table = [[[PackageTable alloc]
4577 filter:@selector(isVisiblyUninstalledInSection:)
4581 [table setDelegate:delegate_];
4583 [book_ pushPage:table];
4586 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4587 if ((self = [super initWithBook:book]) != nil) {
4588 database_ = database;
4590 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
4591 filtered_ = [[NSMutableArray arrayWithCapacity:16] retain];
4593 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
4594 [self addSubview:transition_];
4596 list_ = [[UITable alloc] initWithFrame:[transition_ bounds]];
4597 [transition_ transition:0 toView:list_];
4599 UITableColumn *column = [[[UITableColumn alloc]
4600 initWithTitle:@"Name"
4602 width:[self frame].size.width
4605 [list_ setDataSource:self];
4606 [list_ setSeparatorStyle:1];
4607 [list_ addTableColumn:column];
4608 [list_ setDelegate:self];
4609 [list_ setReusesTableCells:YES];
4615 - (void) reloadData {
4616 NSArray *packages = [database_ packages];
4618 [sections_ removeAllObjects];
4619 [filtered_ removeAllObjects];
4621 NSMutableArray *filtered = [NSMutableArray arrayWithCapacity:[packages count]];
4622 NSMutableDictionary *sections = [NSMutableDictionary dictionaryWithCapacity:32];
4624 for (size_t i(0); i != [packages count]; ++i) {
4625 Package *package([packages objectAtIndex:i]);
4626 NSString *name([package section]);
4629 Section *section([sections objectForKey:name]);
4630 if (section == nil) {
4631 section = [[[Section alloc] initWithName:name] autorelease];
4632 [sections setObject:section forKey:name];
4636 if ([package valid] && [package installed] == nil && [package visible])
4637 [filtered addObject:package];
4640 [sections_ addObjectsFromArray:[sections allValues]];
4641 [sections_ sortUsingSelector:@selector(compareByName:)];
4643 [filtered sortUsingSelector:@selector(compareBySection:)];
4645 Section *section = nil;
4646 for (size_t offset = 0, count = [filtered count]; offset != count; ++offset) {
4647 Package *package = [filtered objectAtIndex:offset];
4648 NSString *name = [package section];
4650 if (section == nil || name != nil && ![[section name] isEqualToString:name]) {
4651 section = name == nil ?
4652 [[[Section alloc] initWithName:nil] autorelease] :
4653 [sections objectForKey:name];
4654 [filtered_ addObject:section];
4657 [section addToCount];
4663 - (void) resetView {
4665 [self _rightButtonClicked];
4668 - (void) resetViewAnimated:(BOOL)animated {
4669 [list_ resetViewAnimated:animated];
4672 - (void) _rightButtonClicked {
4673 if ((editing_ = !editing_))
4676 [delegate_ updateData];
4679 [book_ setTitle:[self title] forPage:self];
4680 [book_ reloadButtonsForPage:self];
4683 - (NSString *) title {
4684 return editing_ ? @"Section Visibility" : @"Install by Section";
4687 - (NSString *) backButtonTitle {
4691 - (NSString *) rightButtonTitle {
4692 return [sections_ count] == 0 ? nil : editing_ ? @"Done" : @"Edit";
4695 - (UIView *) accessoryView {
4701 /* Changes View {{{ */
4702 @interface ChangesView : RVPage {
4703 _transient Database *database_;
4704 NSMutableArray *packages_;
4705 NSMutableArray *sections_;
4706 UISectionList *list_;
4710 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4711 - (void) reloadData;
4715 @implementation ChangesView
4718 [[list_ table] setDelegate:nil];
4719 [list_ setDataSource:nil];
4721 [packages_ release];
4722 [sections_ release];
4727 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
4728 return [sections_ count];
4731 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
4732 return [[sections_ objectAtIndex:section] name];
4735 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
4736 return [[sections_ objectAtIndex:section] row];
4739 - (int) numberOfRowsInTable:(UITable *)table {
4740 return [packages_ count];
4743 - (float) table:(UITable *)table heightForRow:(int)row {
4744 return [PackageCell heightForPackage:[packages_ objectAtIndex:row]];
4747 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
4749 reusing = [[[PackageCell alloc] init] autorelease];
4750 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
4754 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
4758 - (void) tableRowSelected:(NSNotification *)notification {
4759 int row = [[notification object] selectedRow];
4762 Package *package = [packages_ objectAtIndex:row];
4763 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
4764 [view setDelegate:delegate_];
4765 [view setPackage:package];
4766 [book_ pushPage:view];
4769 - (void) _leftButtonClicked {
4770 [(CYBook *)book_ update];
4771 [self reloadButtons];
4774 - (void) _rightButtonClicked {
4775 [delegate_ distUpgrade];
4778 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4779 if ((self = [super initWithBook:book]) != nil) {
4780 database_ = database;
4782 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
4783 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
4785 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:NO];
4786 [self addSubview:list_];
4788 [list_ setShouldHideHeaderInShortLists:NO];
4789 [list_ setDataSource:self];
4790 //[list_ setSectionListStyle:1];
4792 UITableColumn *column = [[[UITableColumn alloc]
4793 initWithTitle:@"Name"
4795 width:[self frame].size.width
4798 UITable *table = [list_ table];
4799 [table setSeparatorStyle:1];
4800 [table addTableColumn:column];
4801 [table setDelegate:self];
4802 [table setReusesTableCells:YES];
4808 - (void) reloadData {
4809 NSArray *packages = [database_ packages];
4811 [packages_ removeAllObjects];
4812 [sections_ removeAllObjects];
4814 for (size_t i(0); i != [packages count]; ++i) {
4815 Package *package([packages objectAtIndex:i]);
4818 [package installed] == nil && [package valid] && [package visible] ||
4819 [package upgradableAndEssential:NO]
4821 [packages_ addObject:package];
4824 [packages_ sortUsingSelector:@selector(compareForChanges:)];
4826 Section *upgradable = [[[Section alloc] initWithName:@"Available Upgrades"] autorelease];
4827 Section *section = nil;
4830 bool unseens = false;
4832 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, Locale_, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
4834 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
4835 Package *package = [packages_ objectAtIndex:offset];
4837 if ([package upgradableAndEssential:YES]) {
4839 [upgradable addToCount];
4842 NSDate *seen = [package seen];
4847 name = [@"n/a ?" retain];
4849 name = (NSString *) CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen);
4852 if (section == nil || ![[section name] isEqualToString:name]) {
4853 section = [[[Section alloc] initWithName:name row:offset] autorelease];
4854 [sections_ addObject:section];
4858 [section addToCount];
4862 CFRelease(formatter);
4865 Section *last = [sections_ lastObject];
4866 size_t count = [last count];
4867 [packages_ removeObjectsInRange:NSMakeRange([packages_ count] - count, count)];
4868 [sections_ removeLastObject];
4872 [sections_ insertObject:upgradable atIndex:0];
4875 [self reloadButtons];
4878 - (void) resetViewAnimated:(BOOL)animated {
4879 [list_ resetViewAnimated:animated];
4882 - (NSString *) leftButtonTitle {
4883 return [(CYBook *)book_ updating] ? nil : @"Refresh";
4886 - (NSString *) rightButtonTitle {
4887 return upgrades_ == 0 ? nil : [NSString stringWithFormat:@"Upgrade (%u)", upgrades_];
4890 - (NSString *) title {
4896 /* Search View {{{ */
4897 @protocol SearchViewDelegate
4898 - (void) showKeyboard:(BOOL)show;
4901 @interface SearchView : RVPage {
4903 UISearchField *field_;
4904 UITransitionView *transition_;
4905 PackageTable *table_;
4906 UIPreferencesTable *advanced_;
4912 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4913 - (void) reloadData;
4917 @implementation SearchView
4921 [[field_ textTraits] setEditingDelegate:nil];
4923 [field_ setDelegate:nil];
4925 [accessory_ release];
4927 [transition_ release];
4929 [advanced_ release];
4934 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
4938 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
4940 case 0: return @"Advanced Search (Coming Soon!)";
4942 default: _assert(false);
4946 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
4950 default: _assert(false);
4954 - (void) _showKeyboard:(BOOL)show {
4955 CGSize keysize = [UIKeyboard defaultSize];
4956 CGRect keydown = [book_ pageBounds];
4957 CGRect keyup = keydown;
4958 keyup.size.height -= keysize.height - ButtonBarHeight_;
4960 float delay = KeyboardTime_ * ButtonBarHeight_ / keysize.height;
4962 UIFrameAnimation *animation = [[[UIFrameAnimation alloc] initWithTarget:[table_ list]] autorelease];
4963 [animation setSignificantRectFields:8];
4966 [animation setStartFrame:keydown];
4967 [animation setEndFrame:keyup];
4969 [animation setStartFrame:keyup];
4970 [animation setEndFrame:keydown];
4973 UIAnimator *animator = [UIAnimator sharedAnimator];
4976 addAnimations:[NSArray arrayWithObjects:animation, nil]
4977 withDuration:(KeyboardTime_ - delay)
4982 [animator performSelector:@selector(startAnimation:) withObject:animation afterDelay:delay];
4985 [delegate_ showKeyboard:show];
4989 - (void) textFieldDidBecomeFirstResponder:(UITextField *)field {
4990 [self _showKeyboard:YES];
4993 - (void) textFieldDidResignFirstResponder:(UITextField *)field {
4994 [self _showKeyboard:NO];
4997 - (void) keyboardInputChanged:(UIFieldEditor *)editor {
4999 NSString *text([field_ text]);
5000 [field_ setClearButtonStyle:(text == nil || [text length] == 0 ? 0 : 2)];
5006 - (void) textFieldClearButtonPressed:(UITextField *)field {
5010 - (void) keyboardInputShouldDelete:(id)input {
5014 - (BOOL) keyboardInput:(id)input shouldInsertText:(NSString *)text isMarkedText:(int)marked {
5015 if ([text length] != 1 || [text characterAtIndex:0] != '\n') {
5019 [field_ resignFirstResponder];
5024 - (id) initWithBook:(RVBook *)book database:(Database *)database {
5025 if ((self = [super initWithBook:book]) != nil) {
5026 CGRect pageBounds = [book_ pageBounds];
5028 /*UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:pageBounds] autorelease];
5029 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
5030 [self addSubview:pinstripe];*/
5032 transition_ = [[UITransitionView alloc] initWithFrame:pageBounds];
5033 [self addSubview:transition_];
5035 advanced_ = [[UIPreferencesTable alloc] initWithFrame:pageBounds];
5037 [advanced_ setReusesTableCells:YES];
5038 [advanced_ setDataSource:self];
5039 [advanced_ reloadData];
5041 dimmed_ = [[UIView alloc] initWithFrame:pageBounds];
5042 CGColor dimmed(space_, 0, 0, 0, 0.5);
5043 [dimmed_ setBackgroundColor:dimmed];
5045 table_ = [[PackageTable alloc]
5049 filter:@selector(isVisiblySearchedForBy:)
5053 [table_ setShouldHideHeaderInShortLists:NO];
5054 [transition_ transition:0 toView:table_];
5063 area.origin.x = /*cnfrect.origin.x + cnfrect.size.width + 4 +*/ 10;
5070 [self bounds].size.width - area.origin.x - 18;
5072 area.size.height = [UISearchField defaultHeight];
5074 field_ = [[UISearchField alloc] initWithFrame:area];
5076 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
5077 [field_ setFont:font];
5080 [field_ setPlaceholder:@"Package Names & Descriptions"];
5081 [field_ setDelegate:self];
5084 [field_ setPaddingTop:3];
5086 [field_ setPaddingTop:5];
5089 UITextTraits *traits = [field_ textTraits];
5090 [traits setAutoCapsType:0];
5091 [traits setAutoCorrectionType:1];
5092 [traits setReturnKeyType:6];
5095 [traits setEditingDelegate:self];
5098 CGRect accrect = {{0, 6}, {6 + cnfrect.size.width + 6 + area.size.width + 6, area.size.height + 30}};
5100 accessory_ = [[UIView alloc] initWithFrame:accrect];
5101 [accessory_ addSubview:field_];
5103 /*UIPushButton *configure = [[[UIPushButton alloc] initWithFrame:cnfrect] autorelease];
5104 [configure setShowPressFeedback:YES];
5105 [configure setImage:[UIImage applicationImageNamed:@"advanced.png"]];
5106 [configure addTarget:self action:@selector(configurePushed) forEvents:1];
5107 [accessory_ addSubview:configure];*/
5113 LKAnimation *animation = [LKTransition animation];
5114 [animation setType:@"oglFlip"];
5115 [animation setTimingFunction:[LKTimingFunction functionWithName:@"easeInEaseOut"]];
5116 [animation setFillMode:@"extended"];
5117 [animation setTransitionFlags:3];
5118 [animation setDuration:10];
5119 [animation setSpeed:0.35];
5120 [animation setSubtype:(flipped_ ? @"fromLeft" : @"fromRight")];
5121 [[transition_ _layer] addAnimation:animation forKey:0];
5122 [transition_ transition:0 toView:(flipped_ ? (UIView *) table_ : (UIView *) advanced_)];
5123 flipped_ = !flipped_;
5127 - (void) configurePushed {
5128 [field_ resignFirstResponder];
5132 - (void) resetViewAnimated:(BOOL)animated {
5135 [table_ resetViewAnimated:animated];
5138 - (void) reloadData {
5141 [table_ setObject:[field_ text]];
5142 [table_ reloadData];
5143 [table_ resetCursor];
5146 - (UIView *) accessoryView {
5150 - (NSString *) title {
5154 - (NSString *) backButtonTitle {
5158 - (void) setDelegate:(id)delegate {
5159 [table_ setDelegate:delegate];
5160 [super setDelegate:delegate];
5166 @implementation CYBook
5170 [indicator_ release];
5172 [progress_ release];
5176 - (NSString *) getTitleForPage:(RVPage *)page {
5177 return Simplify([super getTitleForPage:page]);
5185 [navbar_ setPrompt:@""];
5186 [navbar_ addSubview:overlay_];
5187 [indicator_ startAnimation];
5188 [prompt_ setText:@"Updating Database..."];
5189 [progress_ setProgress:0];
5194 detachNewThreadSelector:@selector(_update)
5203 [overlay_ removeFromSuperview];
5204 [indicator_ stopAnimation];
5205 [delegate_ reloadData];
5207 [self setPrompt:[NSString stringWithFormat:@"Last Updated: %@", GetLastUpdate()]];
5210 - (id) initWithFrame:(CGRect)frame database:(Database *)database {
5211 if ((self = [super initWithFrame:frame]) != nil) {
5212 database_ = database;
5214 CGRect ovrrect = [navbar_ bounds];
5215 ovrrect.size.height = ([UINavigationBar defaultSizeWithPrompt].height - [UINavigationBar defaultSize].height);
5217 overlay_ = [[UIView alloc] initWithFrame:ovrrect];
5219 bool ugly = [navbar_ _barStyle:NO] == 0;
5221 UIProgressIndicatorStyle style = ugly ?
5222 kUIProgressIndicatorStyleSmallBlack :
5223 kUIProgressIndicatorStyleSmallWhite;
5225 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:style];
5226 unsigned indoffset = (ovrrect.size.height - indsize.height) / 2;
5227 CGRect indrect = {{indoffset, indoffset}, indsize};
5229 indicator_ = [[UIProgressIndicator alloc] initWithFrame:indrect];
5230 [indicator_ setStyle:style];
5231 [overlay_ addSubview:indicator_];
5233 CGSize prmsize = {200, indsize.width + 4};
5236 indoffset * 2 + indsize.width,
5240 (ovrrect.size.height - prmsize.height) / 2
5243 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 12);
5245 prompt_ = [[UITextLabel alloc] initWithFrame:prmrect];
5247 [prompt_ setColor:(ugly ? Blueish_ : White_)];
5248 [prompt_ setBackgroundColor:Clear_];
5249 [prompt_ setFont:font];
5253 [overlay_ addSubview:prompt_];
5255 CGSize prgsize = {75, 100};
5258 ovrrect.size.width - prgsize.width - 10,
5259 (ovrrect.size.height - prgsize.height) / 2
5262 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
5263 [progress_ setStyle:0];
5264 [overlay_ addSubview:progress_];
5269 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5272 status.setDelegate(self);
5274 [database_ updateWithStatus:status];
5277 performSelectorOnMainThread:@selector(_update_)
5285 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id {
5286 [prompt_ setText:[NSString stringWithFormat:@"Error: %@", error]];
5289 - (void) setProgressTitle:(NSString *)title {
5291 performSelectorOnMainThread:@selector(_setProgressTitle:)
5297 - (void) setProgressPercent:(float)percent {
5300 - (void) addProgressOutput:(NSString *)output {
5302 performSelectorOnMainThread:@selector(_addProgressOutput:)
5308 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
5312 - (void) _setProgressTitle:(NSString *)title {
5313 [prompt_ setText:[title stringByAppendingString:@"..."]];
5316 - (void) _addProgressOutput:(NSString *)output {
5321 @interface Cydia : UIApplication <
5322 ConfirmationViewDelegate,
5323 ProgressViewDelegate,
5332 UIButtonBar *buttonbar_;
5334 ConfirmationView *confirm_;
5336 NSMutableArray *essential_;
5337 NSMutableArray *broken_;
5339 Database *database_;
5340 ProgressView *progress_;
5344 UIKeyboard *keyboard_;
5345 UIProgressHUD *hud_;
5347 InstallView *install_;
5348 ChangesView *changes_;
5349 ManageView *manage_;
5350 SearchView *search_;
5355 @implementation Cydia
5358 if ([broken_ count] != 0) {
5359 int count = [broken_ count];
5361 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
5362 initWithTitle:[NSString stringWithFormat:@"%d Half-Installed Package%@", count, (count == 1 ? @"" : @"s")]
5363 buttons:[NSArray arrayWithObjects:
5365 @"Ignore (Temporary)",
5367 defaultButtonIndex:0
5372 [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."];
5373 [sheet popupAlertAnimated:YES];
5374 } else if (!Ignored_ && [essential_ count] != 0) {
5375 int count = [essential_ count];
5377 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
5378 initWithTitle:[NSString stringWithFormat:@"%d Essential Upgrade%@", count, (count == 1 ? @"" : @"s")]
5379 buttons:[NSArray arrayWithObjects:@"Upgrade Essential", @"Ignore (Temporary)", nil]
5380 defaultButtonIndex:0
5385 [sheet setBodyText:@"One or more essential packages are currently out of date. If these upgrades are not performed you are likely to encounter errors."];
5386 [sheet popupAlertAnimated:YES];
5390 - (void) _reloadData {
5391 /*UIProgressHUD *hud = [[UIProgressHUD alloc] initWithWindow:window_];
5392 [hud setText:@"Reloading Data"];
5393 [overlay_ addSubview:hud];
5396 [database_ reloadData];
5400 [essential_ removeAllObjects];
5401 [broken_ removeAllObjects];
5403 NSArray *packages = [database_ packages];
5404 for (int i(0), e([packages count]); i != e; ++i) {
5405 Package *package = [packages objectAtIndex:i];
5407 [broken_ addObject:package];
5408 if ([package upgradableAndEssential:NO]) {
5409 if ([package essential])
5410 [essential_ addObject:package];
5416 NSString *badge([[NSNumber numberWithInt:changes] stringValue]);
5417 [buttonbar_ setBadgeValue:badge forButton:3];
5418 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
5419 [buttonbar_ setBadgeAnimated:YES forButton:3];
5420 [self setApplicationBadge:badge];
5422 [buttonbar_ setBadgeValue:nil forButton:3];
5423 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
5424 [buttonbar_ setBadgeAnimated:NO forButton:3];
5425 [self removeApplicationBadge];
5430 if ([packages count] == 0);
5439 [hud removeFromSuperview];*/
5442 - (void) _saveConfig {
5444 _assert([Metadata_ writeToFile:@"/var/lib/cydia/metadata.plist" atomically:YES] == YES);
5449 - (void) updateData {
5452 /* XXX: this is just stupid */
5454 [install_ reloadData];
5456 [changes_ reloadData];
5458 [search_ reloadData];
5468 FILE *file = fopen("/etc/apt/sources.list.d/cydia.list", "w");
5469 _assert(file != NULL);
5471 NSArray *keys = [Sources_ allKeys];
5473 for (int i(0), e([keys count]); i != e; ++i) {
5474 NSString *key = [keys objectAtIndex:i];
5475 NSDictionary *source = [Sources_ objectForKey:key];
5477 fprintf(file, "%s %s %s\n",
5478 [[source objectForKey:@"Type"] UTF8String],
5479 [[source objectForKey:@"URI"] UTF8String],
5480 [[source objectForKey:@"Distribution"] UTF8String]
5489 detachNewThreadSelector:@selector(update_)
5492 title:@"Updating Sources..."
5496 - (void) reloadData {
5497 @synchronized (self) {
5498 if (confirm_ == nil)
5504 pkgProblemResolver *resolver = [database_ resolver];
5506 resolver->InstallProtect();
5507 if (!resolver->Resolve(true))
5512 [database_ prepare];
5514 if ([database_ cache]->BrokenCount() == 0)
5515 confirm_ = [[ConfirmationView alloc] initWithView:underlay_ database:database_ delegate:self];
5517 NSMutableArray *broken = [NSMutableArray arrayWithCapacity:16];
5518 NSArray *packages = [database_ packages];
5520 for (size_t i(0); i != [packages count]; ++i) {
5521 Package *package = [packages objectAtIndex:i];
5522 if ([package broken])
5523 [broken addObject:[package name]];
5526 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
5527 initWithTitle:[NSString stringWithFormat:@"%d Broken Packages", [database_ cache]->BrokenCount()]
5528 buttons:[NSArray arrayWithObjects:@"Okay", nil]
5529 defaultButtonIndex:0
5534 [sheet setBodyText:[NSString stringWithFormat:@"The following packages have unmet dependencies:\n\n%@", [broken componentsJoinedByString:@"\n"]]];
5535 [sheet popupAlertAnimated:YES];
5541 - (void) installPackage:(Package *)package {
5542 @synchronized (self) {
5549 - (void) removePackage:(Package *)package {
5550 @synchronized (self) {
5557 - (void) distUpgrade {
5558 @synchronized (self) {
5559 [database_ upgrade];
5565 @synchronized (self) {
5573 [overlay_ removeFromSuperview];
5577 detachNewThreadSelector:@selector(perform)
5584 - (void) bootstrap_ {
5586 [database_ upgrade];
5587 [database_ prepare];
5588 [database_ perform];
5591 - (void) bootstrap {
5593 detachNewThreadSelector:@selector(bootstrap_)
5596 title:@"Bootstrap Install..."
5600 - (void) progressViewIsComplete:(ProgressView *)progress {
5601 @synchronized (self) {
5604 if (confirm_ != nil) {
5605 [underlay_ addSubview:overlay_];
5606 [confirm_ removeFromSuperview];
5613 - (void) setPage:(RVPage *)page {
5614 [page resetViewAnimated:NO];
5615 [page setDelegate:self];
5616 [book_ setPage:page];
5619 - (RVPage *) _pageForURL:(NSURL *)url withClass:(Class)_class {
5620 BrowserView *browser = [[[_class alloc] initWithBook:book_ database:database_] autorelease];
5621 [browser loadURL:url];
5625 - (void) _setHomePage {
5626 [self setPage:[self _pageForURL:[NSURL URLWithString:@"http://cydia.saurik.com/"] withClass:[HomeView class]]];
5629 - (void) buttonBarItemTapped:(id)sender {
5630 unsigned tag = [sender tag];
5632 [book_ resetViewAnimated:YES];
5634 } else if (tag_ == 2 && tag != 2)
5635 [install_ resetView];
5638 case 1: [self _setHomePage]; break;
5640 case 2: [self setPage:install_]; break;
5641 case 3: [self setPage:changes_]; break;
5642 case 4: [self setPage:manage_]; break;
5643 case 5: [self setPage:search_]; break;
5645 default: _assert(false);
5651 - (void) fixSpringBoard {
5652 pid_t pid = ExecFork();
5656 if (pid_t child = fork()) {
5657 waitpid(child, NULL, 0);
5659 execlp("launchctl", "launchctl", "unload", SpringBoard_, NULL);
5660 perror("launchctl unload");
5664 execlp("launchctl", "launchctl", "load", SpringBoard_, NULL);
5665 perror("launchctl load");
5670 - (void) applicationWillSuspend {
5675 [self fixSpringBoard];
5679 [super applicationWillSuspend];
5682 - (void) askForSettings {
5683 UIAlertSheet *role = [[[UIAlertSheet alloc]
5684 initWithTitle:@"Who Are You?"
5685 buttons:[NSArray arrayWithObjects:
5686 @"User (Graphical Only)",
5687 @"Hacker (+ Command Line)",
5688 @"Developer (No Filters)",
5690 defaultButtonIndex:-1
5695 [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."];
5696 [role popupAlertAnimated:YES];
5701 [self setStatusBarShowsProgress:NO];
5704 [hud_ removeFromSuperview];
5708 pid_t pid = ExecFork();
5710 execlp("launchctl", "launchctl", "stop", "com.apple.SpringBoard", NULL);
5711 perror("launchctl stop");
5718 [self askForSettings];
5722 overlay_ = [[UIView alloc] initWithFrame:[underlay_ bounds]];
5724 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
5725 book_ = [[CYBook alloc] initWithFrame:CGRectMake(
5726 0, 0, screenrect.size.width, screenrect.size.height - 48
5727 ) database:database_];
5729 [book_ setDelegate:self];
5731 [overlay_ addSubview:book_];
5733 NSArray *buttonitems = [NSArray arrayWithObjects:
5734 [NSDictionary dictionaryWithObjectsAndKeys:
5735 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5736 @"home-up.png", kUIButtonBarButtonInfo,
5737 @"home-dn.png", kUIButtonBarButtonSelectedInfo,
5738 [NSNumber numberWithInt:1], kUIButtonBarButtonTag,
5739 self, kUIButtonBarButtonTarget,
5740 @"Home", kUIButtonBarButtonTitle,
5741 @"0", kUIButtonBarButtonType,
5744 [NSDictionary dictionaryWithObjectsAndKeys:
5745 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5746 @"install-up.png", kUIButtonBarButtonInfo,
5747 @"install-dn.png", kUIButtonBarButtonSelectedInfo,
5748 [NSNumber numberWithInt:2], kUIButtonBarButtonTag,
5749 self, kUIButtonBarButtonTarget,
5750 @"Sections", kUIButtonBarButtonTitle,
5751 @"0", kUIButtonBarButtonType,
5754 [NSDictionary dictionaryWithObjectsAndKeys:
5755 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5756 @"changes-up.png", kUIButtonBarButtonInfo,
5757 @"changes-dn.png", kUIButtonBarButtonSelectedInfo,
5758 [NSNumber numberWithInt:3], kUIButtonBarButtonTag,
5759 self, kUIButtonBarButtonTarget,
5760 @"Changes", kUIButtonBarButtonTitle,
5761 @"0", kUIButtonBarButtonType,
5764 [NSDictionary dictionaryWithObjectsAndKeys:
5765 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5766 @"manage-up.png", kUIButtonBarButtonInfo,
5767 @"manage-dn.png", kUIButtonBarButtonSelectedInfo,
5768 [NSNumber numberWithInt:4], kUIButtonBarButtonTag,
5769 self, kUIButtonBarButtonTarget,
5770 @"Manage", kUIButtonBarButtonTitle,
5771 @"0", kUIButtonBarButtonType,
5774 [NSDictionary dictionaryWithObjectsAndKeys:
5775 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5776 @"search-up.png", kUIButtonBarButtonInfo,
5777 @"search-dn.png", kUIButtonBarButtonSelectedInfo,
5778 [NSNumber numberWithInt:5], kUIButtonBarButtonTag,
5779 self, kUIButtonBarButtonTarget,
5780 @"Search", kUIButtonBarButtonTitle,
5781 @"0", kUIButtonBarButtonType,
5785 buttonbar_ = [[UIButtonBar alloc]
5787 withFrame:CGRectMake(
5788 0, screenrect.size.height - ButtonBarHeight_,
5789 screenrect.size.width, ButtonBarHeight_
5791 withItemList:buttonitems
5794 [buttonbar_ setDelegate:self];
5795 [buttonbar_ setBarStyle:1];
5796 [buttonbar_ setButtonBarTrackingMode:2];
5798 int buttons[5] = {1, 2, 3, 4, 5};
5799 [buttonbar_ registerButtonGroup:0 withButtons:buttons withCount:5];
5800 [buttonbar_ showButtonGroup:0 withDuration:0];
5802 for (int i = 0; i != 5; ++i)
5803 [[buttonbar_ viewWithTag:(i + 1)] setFrame:CGRectMake(
5804 i * 64 + 2, 1, 60, ButtonBarHeight_
5807 [buttonbar_ showSelectionForButton:1];
5808 [overlay_ addSubview:buttonbar_];
5810 [UIKeyboard initImplementationNow];
5811 CGSize keysize = [UIKeyboard defaultSize];
5812 CGRect keyrect = {{0, [overlay_ bounds].size.height}, keysize};
5813 keyboard_ = [[UIKeyboard alloc] initWithFrame:keyrect];
5814 [[UIKeyboardImpl sharedInstance] setSoundsEnabled:(Sounds_Keyboard_ ? YES : NO)];
5815 [overlay_ addSubview:keyboard_];
5817 install_ = [[InstallView alloc] initWithBook:book_ database:database_];
5818 changes_ = [[ChangesView alloc] initWithBook:book_ database:database_];
5819 search_ = [[SearchView alloc] initWithBook:book_ database:database_];
5821 manage_ = (ManageView *) [[self
5822 _pageForURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"manage" ofType:@"html"]]
5823 withClass:[ManageView class]
5827 [underlay_ addSubview:overlay_];
5834 [self _setHomePage];
5837 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
5838 NSString *context = [sheet context];
5839 if ([context isEqualToString:@"fixhalf"])
5842 @synchronized (self) {
5843 for (int i = 0, e = [broken_ count]; i != e; ++i) {
5844 Package *broken = [broken_ objectAtIndex:i];
5847 NSString *id = [broken id];
5848 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.prerm", id] UTF8String]);
5849 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.postrm", id] UTF8String]);
5850 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.preinst", id] UTF8String]);
5851 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.postinst", id] UTF8String]);
5860 [broken_ removeAllObjects];
5867 else if ([context isEqualToString:@"role"]) {
5869 case 1: Role_ = @"User"; break;
5870 case 2: Role_ = @"Hacker"; break;
5871 case 3: Role_ = @"Developer"; break;
5878 bool reset = Settings_ != nil;
5880 Settings_ = [NSMutableDictionary dictionaryWithObjectsAndKeys:
5884 [Metadata_ setObject:Settings_ forKey:@"Settings"];
5892 } else if ([context isEqualToString:@"upgrade"])
5895 @synchronized (self) {
5896 for (int i = 0, e = [essential_ count]; i != e; ++i) {
5897 Package *essential = [essential_ objectAtIndex:i];
5898 [essential install];
5917 - (void) reorganize {
5918 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5919 system("/usr/libexec/cydia/free.sh");
5920 [self performSelectorOnMainThread:@selector(finish) withObject:nil waitUntilDone:NO];
5924 - (void) applicationSuspend:(__GSEvent *)event {
5925 if (hud_ == nil && ![progress_ isRunning])
5926 [super applicationSuspend:event];
5929 - (void) _animateSuspension:(BOOL)arg0 duration:(double)arg1 startTime:(double)arg2 scale:(float)arg3 {
5931 [super _animateSuspension:arg0 duration:arg1 startTime:arg2 scale:arg3];
5934 - (void) _setSuspended:(BOOL)value {
5936 [super _setSuspended:value];
5939 - (UIProgressHUD *) addProgressHUD {
5940 UIProgressHUD *hud = [[UIProgressHUD alloc] initWithWindow:window_];
5942 [underlay_ addSubview:hud];
5946 - (void) applicationDidFinishLaunching:(id)unused {
5947 Font12_ = [[UIFont systemFontOfSize:12] retain];
5948 Font12Bold_ = [[UIFont boldSystemFontOfSize:12] retain];
5949 Font14_ = [[UIFont systemFontOfSize:14] retain];
5950 Font18Bold_ = [[UIFont boldSystemFontOfSize:18] retain];
5951 Font22Bold_ = [[UIFont boldSystemFontOfSize:22] retain];
5953 _assert(pkgInitConfig(*_config));
5954 _assert(pkgInitSystem(*_config, _system));
5959 essential_ = [[NSMutableArray alloc] initWithCapacity:4];
5960 broken_ = [[NSMutableArray alloc] initWithCapacity:4];
5962 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
5963 window_ = [[UIWindow alloc] initWithContentRect:screenrect];
5965 [window_ orderFront:self];
5966 [window_ makeKey:self];
5967 [window_ _setHidden:NO];
5969 database_ = [[Database alloc] init];
5970 progress_ = [[ProgressView alloc] initWithFrame:[window_ bounds] database:database_ delegate:self];
5971 [database_ setDelegate:progress_];
5972 [window_ setContentView:progress_];
5974 underlay_ = [[UIView alloc] initWithFrame:[progress_ bounds]];
5975 [progress_ setContentView:underlay_];
5977 [progress_ resetView];
5980 readlink("/Applications", NULL, 0) == -1 && errno == EINVAL ||
5981 readlink("/Library/Ringtones", NULL, 0) == -1 && errno == EINVAL ||
5982 readlink("/Library/Wallpaper", NULL, 0) == -1 && errno == EINVAL ||
5983 readlink("/usr/include", NULL, 0) == -1 && errno == EINVAL ||
5984 readlink("/usr/libexec", NULL, 0) == -1 && errno == EINVAL ||
5985 readlink("/usr/share", NULL, 0) == -1 && errno == EINVAL
5987 [self setIdleTimerDisabled:YES];
5989 hud_ = [self addProgressHUD];
5990 [hud_ setText:@"Reorganizing\n\nWill Automatically\nRestart When Done"];
5992 [self setStatusBarShowsProgress:YES];
5995 detachNewThreadSelector:@selector(reorganize)
6003 - (void) showKeyboard:(BOOL)show {
6004 CGSize keysize = [UIKeyboard defaultSize];
6005 CGRect keydown = {{0, [overlay_ bounds].size.height}, keysize};
6006 CGRect keyup = keydown;
6007 keyup.origin.y -= keysize.height;
6009 UIFrameAnimation *animation = [[[UIFrameAnimation alloc] initWithTarget:keyboard_] autorelease];
6010 [animation setSignificantRectFields:2];
6013 [animation setStartFrame:keydown];
6014 [animation setEndFrame:keyup];
6015 [keyboard_ activate];
6017 [animation setStartFrame:keyup];
6018 [animation setEndFrame:keydown];
6019 [keyboard_ deactivate];
6022 [[UIAnimator sharedAnimator]
6023 addAnimations:[NSArray arrayWithObjects:animation, nil]
6024 withDuration:KeyboardTime_
6029 - (void) slideUp:(UIAlertSheet *)alert {
6031 [alert presentSheetFromButtonBar:buttonbar_];
6033 [alert presentSheetInView:overlay_];
6038 void AddPreferences(NSString *plist) {
6039 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
6041 NSMutableDictionary *settings = [[[NSMutableDictionary alloc] initWithContentsOfFile:plist] autorelease];
6042 _assert(settings != NULL);
6043 NSMutableArray *items = [settings objectForKey:@"items"];
6047 for (size_t i(0); i != [items count]; ++i) {
6048 NSMutableDictionary *item([items objectAtIndex:i]);
6049 NSString *label = [item objectForKey:@"label"];
6050 if (label != nil && [label isEqualToString:@"Cydia"]) {
6057 for (size_t i(0); i != [items count]; ++i) {
6058 NSDictionary *item([items objectAtIndex:i]);
6059 NSString *label = [item objectForKey:@"label"];
6060 if (label != nil && [label isEqualToString:@"General"]) {
6061 [items insertObject:[NSDictionary dictionaryWithObjectsAndKeys:
6062 @"CydiaSettings", @"bundle",
6063 @"PSLinkCell", @"cell",
6064 [NSNumber numberWithBool:YES], @"hasIcon",
6065 [NSNumber numberWithBool:YES], @"isController",
6067 nil] atIndex:(i + 1)];
6073 _assert([settings writeToFile:plist atomically:YES] == YES);
6080 id Alloc_(id self, SEL selector) {
6081 id object = alloc_(self, selector);
6082 fprintf(stderr, "[%s]A-%p\n", self->isa->name, object);
6087 id Dealloc_(id self, SEL selector) {
6088 id object = dealloc_(self, selector);
6089 fprintf(stderr, "[%s]D-%p\n", self->isa->name, object);
6093 int main(int argc, char *argv[]) {
6094 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
6096 bootstrap_ = argc > 1 && strcmp(argv[1], "--bootstrap") == 0;
6098 Home_ = NSHomeDirectory();
6101 NSString *plist = [Home_ stringByAppendingString:@"/Library/Preferences/com.apple.preferences.sounds.plist"];
6102 if (NSDictionary *sounds = [NSDictionary dictionaryWithContentsOfFile:plist])
6103 if (NSNumber *keyboard = [sounds objectForKey:@"keyboard"])
6104 Sounds_Keyboard_ = [keyboard boolValue];
6110 if (unlink("/var/cache/apt/pkgcache.bin") == -1)
6111 _assert(errno == ENOENT);
6112 if (unlink("/var/cache/apt/srcpkgcache.bin") == -1)
6113 _assert(errno == ENOENT);
6115 /*Method alloc = class_getClassMethod([NSObject class], @selector(alloc));
6116 alloc_ = alloc->method_imp;
6117 alloc->method_imp = (IMP) &Alloc_;*/
6119 /*Method dealloc = class_getClassMethod([NSObject class], @selector(dealloc));
6120 dealloc_ = dealloc->method_imp;
6121 dealloc->method_imp = (IMP) &Dealloc_;*/
6123 if (NSDictionary *sysver = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]) {
6124 if (NSString *prover = [sysver valueForKey:@"ProductVersion"]) {
6125 Firmware_ = strdup([prover UTF8String]);
6126 NSArray *versions = [prover componentsSeparatedByString:@"."];
6127 int count = [versions count];
6128 Major_ = count > 0 ? [[versions objectAtIndex:0] intValue] : 0;
6129 Minor_ = count > 1 ? [[versions objectAtIndex:1] intValue] : 0;
6130 BugFix_ = count > 2 ? [[versions objectAtIndex:2] intValue] : 0;
6135 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
6136 char *machine = new char[size];
6137 sysctlbyname("hw.machine", machine, &size, NULL, 0);
6140 if (CFMutableDictionaryRef dict = IOServiceMatching("IOPlatformExpertDevice"))
6141 if (io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, dict)) {
6142 if (CFTypeRef serial = IORegistryEntryCreateCFProperty(service, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0)) {
6143 SerialNumber_ = strdup(CFStringGetCStringPtr((CFStringRef) serial, CFStringGetSystemEncoding()));
6147 IOObjectRelease(service);
6150 /*AddPreferences(@"/Applications/Preferences.app/Settings-iPhone.plist");
6151 AddPreferences(@"/Applications/Preferences.app/Settings-iPod.plist");*/
6153 if ((Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"]) == NULL)
6154 Metadata_ = [[NSMutableDictionary alloc] initWithCapacity:2];
6156 Settings_ = [Metadata_ objectForKey:@"Settings"];
6158 Packages_ = [Metadata_ objectForKey:@"Packages"];
6159 Sections_ = [Metadata_ objectForKey:@"Sections"];
6160 Sources_ = [Metadata_ objectForKey:@"Sources"];
6163 if (Settings_ != nil)
6164 Role_ = [Settings_ objectForKey:@"Role"];
6166 if (Packages_ == nil) {
6167 Packages_ = [[[NSMutableDictionary alloc] initWithCapacity:128] autorelease];
6168 [Metadata_ setObject:Packages_ forKey:@"Packages"];
6171 if (Sections_ == nil) {
6172 Sections_ = [[[NSMutableDictionary alloc] initWithCapacity:32] autorelease];
6173 [Metadata_ setObject:Sections_ forKey:@"Sections"];
6176 if (Sources_ == nil) {
6177 Sources_ = [[[NSMutableDictionary alloc] initWithCapacity:0] autorelease];
6178 [Metadata_ setObject:Sources_ forKey:@"Sources"];
6181 if (access("/Library/MobileSubstrate/MobileSubstrate.dylib", F_OK) == 0)
6182 dlopen("/Library/MobileSubstrate/MobileSubstrate.dylib", RTLD_LAZY | RTLD_GLOBAL);
6184 if (access("/User", F_OK) != 0)
6185 system("/usr/libexec/cydia/firmware.sh");
6187 Locale_ = CFLocaleCopyCurrent();
6188 space_ = CGColorSpaceCreateDeviceRGB();
6190 Blue_.Set(space_, 0.2, 0.2, 1.0, 1.0);
6191 Blueish_.Set(space_, 0x19/255.f, 0x32/255.f, 0x50/255.f, 1.0);
6192 Black_.Set(space_, 0.0, 0.0, 0.0, 1.0);
6193 Clear_.Set(space_, 0.0, 0.0, 0.0, 0.0);
6194 Red_.Set(space_, 1.0, 0.0, 0.0, 1.0);
6195 White_.Set(space_, 1.0, 1.0, 1.0, 1.0);
6196 Gray_.Set(space_, 0.4, 0.4, 0.4, 1.0);
6198 Finishes_ = [NSArray arrayWithObjects:@"return", @"reopen", @"restart", @"reload", @"reboot", nil];
6200 SectionMap_ = [[[NSDictionary alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Sections" ofType:@"plist"]] autorelease];
6202 int value = UIApplicationMain(argc, argv, [Cydia class]);
6204 CGColorSpaceRelease(space_);