1 /* Cydia - iPhone UIKit Front-End for Debian APT
2 * Copyright (C) 2008 Jay Freeman (saurik)
6 * Redistribution and use in source and binary
7 * forms, with or without modification, are permitted
8 * provided that the following conditions are met:
10 * 1. Redistributions of source code must retain the
11 * above copyright notice, this list of conditions
12 * and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the
14 * above copyright notice, this list of conditions
15 * and the following disclaimer in the documentation
16 * and/or other materials provided with the
18 * 3. The name of the author may not be used to endorse
19 * or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS''
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
24 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
33 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
35 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 /* #include Directives {{{ */
39 #include <CoreGraphics/CoreGraphics.h>
40 #include <GraphicsServices/GraphicsServices.h>
41 #include <Foundation/Foundation.h>
42 #include <UIKit/UIKit.h>
43 #include <WebCore/DOMHTML.h>
45 #include <WebKit/WebFrame.h>
46 #include <WebKit/WebView.h>
48 #include <objc/objc.h>
49 #include <objc/runtime.h>
52 #include <ext/stdio_filebuf.h>
54 #include <apt-pkg/acquire.h>
55 #include <apt-pkg/acquire-item.h>
56 #include <apt-pkg/algorithms.h>
57 #include <apt-pkg/cachefile.h>
58 #include <apt-pkg/configuration.h>
59 #include <apt-pkg/debmetaindex.h>
60 #include <apt-pkg/error.h>
61 #include <apt-pkg/init.h>
62 #include <apt-pkg/pkgrecords.h>
63 #include <apt-pkg/sourcelist.h>
64 #include <apt-pkg/sptr.h>
66 #include <sys/sysctl.h>
70 #include <mach-o/nlist.h>
80 /* Extension Keywords {{{ */
81 #define _trace() fprintf(stderr, "_trace()@%s:%u[%s]\n", __FILE__, __LINE__, __FUNCTION__)
83 #define _assert(test) do \
85 fprintf(stderr, "_assert(%d:%s)@%s:%u[%s]\n", errno, #test, __FILE__, __LINE__, __FUNCTION__); \
90 #define _not(type) ((type) ~ (type) 0)
95 /* Miscellaneous Messages {{{ */
96 @interface NSString (Cydia)
97 - (NSString *) stringByAddingPercentEscapes;
98 - (NSString *) stringByReplacingCharacter:(unsigned short)arg0 withCharacter:(unsigned short)arg1;
101 /* External Constants {{{ */
102 extern NSString *kUIButtonBarButtonAction;
103 extern NSString *kUIButtonBarButtonInfo;
104 extern NSString *kUIButtonBarButtonInfoOffset;
105 extern NSString *kUIButtonBarButtonSelectedInfo;
106 extern NSString *kUIButtonBarButtonStyle;
107 extern NSString *kUIButtonBarButtonTag;
108 extern NSString *kUIButtonBarButtonTarget;
109 extern NSString *kUIButtonBarButtonTitle;
110 extern NSString *kUIButtonBarButtonTitleVerticalHeight;
111 extern NSString *kUIButtonBarButtonTitleWidth;
112 extern NSString *kUIButtonBarButtonType;
119 #define $_ fprintf(stderr, "+");_trace();
120 #define _$ fprintf(stderr, "-");_trace();
123 /* iPhoneOS 2.0 Compatibility {{{ */
125 @interface UICGColor : NSObject {
128 - (id) initWithCGColor:(CGColorRef)color;
134 - (UIFont *) fontWithSize:(CGFloat)size;
137 @interface NSObject (iPhoneOS)
138 - (CGColorRef) cgColor;
139 - (CGColorRef) CGColor;
143 @implementation NSObject (iPhoneOS)
145 - (CGColorRef) cgColor {
146 return [self CGColor];
149 - (CGColorRef) CGColor {
150 return (CGColorRef) self;
154 [[[[objc_getClass("UICGColor") alloc] initWithCGColor:[self CGColor]] autorelease] set];
159 @interface UITextView (iPhoneOS)
160 - (void) setTextSize:(float)size;
163 @implementation UITextView (iPhoneOS)
165 - (void) setTextSize:(float)size {
166 [self setFont:[[self font] fontWithSize:size]];
173 OBJC_EXPORT const char *class_getName(Class cls);
175 /* Reset View (UIView) {{{ */
176 @interface UIView (RVBook)
177 - (void) resetViewAnimated:(BOOL)animated;
181 @implementation UIView (RVBook)
183 - (void) resetViewAnimated:(BOOL)animated {
184 fprintf(stderr, "%s\n", class_getName(self->isa));
189 fprintf(stderr, "%s\n", class_getName(self->isa));
195 /* Reset View (UITable) {{{ */
196 @interface UITable (RVBook)
197 - (void) resetViewAnimated:(BOOL)animated;
201 @implementation UITable (RVBook)
203 - (void) resetViewAnimated:(BOOL)animated {
204 [self selectRow:-1 byExtendingSelection:NO withFade:animated];
213 /* Reset View (UISectionList) {{{ */
214 @interface UISectionList (RVBook)
215 - (void) resetViewAnimated:(BOOL)animated;
219 @implementation UISectionList (RVBook)
221 - (void) resetViewAnimated:(BOOL)animated {
222 [[self table] resetViewAnimated:animated];
226 [[self table] clearView];
232 /* Perl-Compatible RegEx {{{ */
242 Pcre(const char *regex) :
247 code_ = pcre_compile(regex, 0, &error, &offset, NULL);
250 fprintf(stderr, "%d:%s\n", offset, error);
254 pcre_fullinfo(code_, study_, PCRE_INFO_CAPTURECOUNT, &capture_);
255 matches_ = new int[(capture_ + 1) * 3];
263 NSString *operator [](size_t match) {
265 stringWithCString:(data_ + matches_[match * 2])
266 length:(matches_[match * 2 + 1] - matches_[match * 2])
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 Pcre email_r("^\"?(.*)\"? <([^>]*)>$");
279 @interface Address : NSObject {
285 - (NSString *) email;
287 + (Address *) addressWithString:(NSString *)string;
288 - (Address *) initWithString:(NSString *)string;
291 @implementation Address
300 - (NSString *) name {
304 - (NSString *) email {
308 + (Address *) addressWithString:(NSString *)string {
309 return [[[Address alloc] initWithString:string] autorelease];
312 - (Address *) initWithString:(NSString *)string {
313 if ((self = [super init]) != nil) {
314 const char *data = [string UTF8String];
315 size_t size = [string length];
317 if (email_r(data, size)) {
318 name_ = [email_r[1] retain];
319 email_ = [email_r[2] retain];
321 name_ = [[NSString stringWithCString:data length:size] retain];
329 /* CoreGraphics Primitives {{{ */
340 CGColor(CGColorSpaceRef space, float red, float green, float blue, float alpha) :
343 Set(space, red, green, blue, alpha);
348 CGColorRelease(color_);
355 void Set(CGColorSpaceRef space, float red, float green, float blue, float alpha) {
357 float color[] = {red, green, blue, alpha};
358 color_ = CGColorCreate(space, color);
361 operator CGColorRef() {
376 /* Right Alignment {{{ */
377 @interface UIRightTextLabel : UITextLabel {
378 float _savedRightEdgeX;
379 BOOL _sizedtofit_flag;
382 - (void) setFrame:(CGRect)frame;
383 - (void) setText:(NSString *)text;
384 - (void) realignText;
387 @implementation UIRightTextLabel
389 - (void) setFrame:(CGRect)frame {
390 [super setFrame:frame];
391 if (_sizedtofit_flag == NO) {
392 _savedRightEdgeX = frame.origin.x;
397 - (void) setText:(NSString *)text {
398 [super setText:text];
402 - (void) realignText {
403 CGRect oldFrame = [self frame];
405 _sizedtofit_flag = YES;
406 [self sizeToFit]; // shrink down size so I can right align it
408 CGRect newFrame = [self frame];
410 oldFrame.origin.x = _savedRightEdgeX - newFrame.size.width;
411 oldFrame.size.width = newFrame.size.width;
412 [super setFrame:oldFrame];
413 _sizedtofit_flag = NO;
419 /* Random Global Variables {{{ */
420 static const int PulseInterval_ = 50000;
422 static CGColor Black_;
423 static CGColor Clear_;
425 static CGColor White_;
427 const char *Firmware_ = NULL;
428 const char *Machine_ = NULL;
429 const char *SerialNumber_ = NULL;
435 CGColorSpaceRef space_;
437 #define FW_LEAST(major, minor, bugfix) \
438 (major < Major_ || major == Major_ && \
439 (minor < Minor_ || minor == Minor_ && \
445 static NSMutableDictionary *Metadata_;
446 static NSMutableDictionary *Packages_;
449 NSString *GetLastUpdate() {
450 NSDate *update = [Metadata_ objectForKey:@"LastUpdate"];
453 return @"Never or Unknown";
455 CFLocaleRef locale = CFLocaleCopyCurrent();
456 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
457 CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) update);
459 CFRelease(formatter);
462 return [(NSString *) formatted autorelease];
465 /* Display Helpers {{{ */
466 inline float Interpolate(float begin, float end, float fraction) {
467 return (end - begin) * fraction + begin;
470 NSString *SizeString(double size) {
472 while (size > 1024) {
477 static const char *powers_[] = {"B", "kB", "MB", "GB"};
479 return [NSString stringWithFormat:@"%.1f%s", size, powers_[power]];
482 static const float TextViewOffset_ = 22;
484 UITextView *GetTextView(NSString *value, float left, bool html) {
485 UITextView *text([[[UITextView alloc] initWithFrame:CGRectMake(left, 3, 310 - left, 1000)] autorelease]);
486 [text setEditable:NO];
487 [text setTextSize:16];
489 [text setHTML:value];
491 [text setText:value];
492 [text setEnabled:NO];
494 [text setBackgroundColor:Clear_];
496 CGRect frame = [text frame];
497 [text setFrame:frame];
498 CGRect rect = [text visibleTextRect];
499 frame.size.height = rect.size.height;
500 [text setFrame:frame];
509 @protocol ProgressDelegate
510 - (void) setProgressError:(NSString *)error;
511 - (void) setProgressTitle:(NSString *)title;
512 - (void) setProgressPercent:(float)percent;
513 - (void) addProgressOutput:(NSString *)output;
516 @protocol CydiaDelegate
517 - (void) installPackage:(Package *)package;
518 - (void) removePackage:(Package *)package;
519 - (void) slideUp:(UIAlertSheet *)alert;
520 - (void) distUpgrade;
523 /* Status Delegation {{{ */
525 public pkgAcquireStatus
528 _transient id<ProgressDelegate> delegate_;
536 void setDelegate(id delegate) {
537 delegate_ = delegate;
540 virtual bool MediaChange(std::string media, std::string drive) {
544 virtual void IMSHit(pkgAcquire::ItemDesc &item) {
547 virtual void Fetch(pkgAcquire::ItemDesc &item) {
548 [delegate_ setProgressTitle:[NSString stringWithCString:("Downloading " + item.ShortDesc).c_str()]];
551 virtual void Done(pkgAcquire::ItemDesc &item) {
554 virtual void Fail(pkgAcquire::ItemDesc &item) {
556 item.Owner->Status == pkgAcquire::Item::StatIdle ||
557 item.Owner->Status == pkgAcquire::Item::StatDone
561 [delegate_ setProgressError:[NSString stringWithCString:item.Owner->ErrorText.c_str()]];
564 virtual bool Pulse(pkgAcquire *Owner) {
565 bool value = pkgAcquireStatus::Pulse(Owner);
568 double(CurrentBytes + CurrentItems) /
569 double(TotalBytes + TotalItems)
572 [delegate_ setProgressPercent:percent];
576 virtual void Start() {
579 virtual void Stop() {
583 /* Progress Delegation {{{ */
588 _transient id<ProgressDelegate> delegate_;
591 virtual void Update() {
592 [delegate_ setProgressTitle:[NSString stringWithCString:Op.c_str()]];
593 [delegate_ setProgressPercent:(Percent / 100)];
602 void setDelegate(id delegate) {
603 delegate_ = delegate;
606 virtual void Done() {
607 [delegate_ setProgressPercent:1];
612 /* Database Interface {{{ */
613 @interface Database : NSObject {
615 pkgRecords *records_;
616 pkgProblemResolver *resolver_;
617 pkgAcquire *fetcher_;
619 SPtr<pkgPackageManager> manager_;
620 pkgSourceList *list_;
622 NSMutableDictionary *sources_;
623 NSMutableArray *packages_;
625 _transient id delegate_;
631 - (void) _readStatus:(NSNumber *)fd;
632 - (void) _readOutput:(NSNumber *)fd;
634 - (Package *) packageWithName:(NSString *)name;
637 - (pkgCacheFile &) cache;
638 - (pkgRecords *) records;
639 - (pkgProblemResolver *) resolver;
640 - (pkgAcquire &) fetcher;
641 - (NSArray *) packages;
649 - (void) updateWithStatus:(Status &)status;
651 - (void) setDelegate:(id)delegate;
652 - (Source *) getSource:(const pkgCache::PkgFileIterator &)file;
656 /* Source Class {{{ */
657 @interface Source : NSObject {
658 NSString *description_;
663 NSString *distribution_;
667 NSString *defaultIcon_;
672 - (Source *) initWithMetaIndex:(metaIndex *)index;
677 - (NSString *) distribution;
680 - (NSString *) description;
681 - (NSString *) label;
682 - (NSString *) origin;
683 - (NSString *) version;
685 - (NSString *) defaultIcon;
688 @implementation Source
692 [distribution_ release];
695 if (description_ != nil)
696 [description_ release];
703 if (defaultIcon_ != nil)
704 [defaultIcon_ release];
709 - (Source *) initWithMetaIndex:(metaIndex *)index {
710 if ((self = [super init]) != nil) {
711 trusted_ = index->IsTrusted();
713 uri_ = [[NSString stringWithCString:index->GetURI().c_str()] retain];
714 distribution_ = [[NSString stringWithCString:index->GetDist().c_str()] retain];
715 type_ = [[NSString stringWithCString:index->GetType()] retain];
723 debReleaseIndex *dindex(dynamic_cast<debReleaseIndex *>(index));
724 if (dindex != NULL) {
725 std::ifstream release(dindex->MetaIndexFile("Release").c_str());
727 while (std::getline(release, line)) {
728 std::string::size_type colon(line.find(':'));
729 if (colon == std::string::npos)
732 std::string name(line.substr(0, colon));
733 std::string value(line.substr(colon + 1));
734 while (!value.empty() && value[0] == ' ')
735 value = value.substr(1);
737 if (name == "Default-Icon")
738 defaultIcon_ = [[NSString stringWithCString:value.c_str()] retain];
739 else if (name == "Description")
740 description_ = [[NSString stringWithCString:value.c_str()] retain];
741 else if (name == "Label")
742 label_ = [[NSString stringWithCString:value.c_str()] retain];
743 else if (name == "Origin")
744 origin_ = [[NSString stringWithCString:value.c_str()] retain];
745 else if (name == "Version")
746 version_ = [[NSString stringWithCString:value.c_str()] retain];
760 - (NSString *) distribution {
761 return distribution_;
764 - (NSString *) type {
768 - (NSString *) description {
772 - (NSString *) label {
776 - (NSString *) origin {
780 - (NSString *) version {
784 - (NSString *) defaultIcon {
790 /* Package Class {{{ */
791 NSString *Scour(const char *field, const char *begin, const char *end) {
792 size_t i(0), l(strlen(field));
795 const char *name = begin + i;
796 const char *colon = name + l;
797 const char *value = colon + 1;
802 memcmp(name, field, l) == 0
804 while (value != end && value[0] == ' ')
806 const char *line = std::find(value, end, '\n');
807 while (line != value && line[-1] == ' ')
809 return [NSString stringWithCString:value length:(line - value)];
811 begin = std::find(begin, end, '\n');
819 @interface Package : NSObject {
820 pkgCache::PkgIterator iterator_;
821 _transient Database *database_;
822 pkgCache::VerIterator version_;
823 pkgCache::VerFileIterator file_;
827 NSString *installed_;
836 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database version:(pkgCache::VerIterator)version file:(pkgCache::VerFileIterator)file;
837 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
839 - (NSString *) section;
840 - (Address *) maintainer;
842 - (NSString *) description;
843 - (NSString *) index;
847 - (NSString *) latest;
848 - (NSString *) installed;
855 - (NSString *) tagline;
857 - (NSString *) website;
861 - (BOOL) matches:(NSString *)text;
863 - (NSComparisonResult) compareByName:(Package *)package;
864 - (NSComparisonResult) compareBySection:(Package *)package;
865 - (NSComparisonResult) compareBySectionAndName:(Package *)package;
866 - (NSComparisonResult) compareForChanges:(Package *)package;
871 - (NSNumber *) isSearchedForBy:(NSString *)search;
872 - (NSNumber *) isInstalledInSection:(NSString *)section;
873 - (NSNumber *) isUninstalledInSection:(NSString *)section;
877 @implementation Package
881 if (installed_ != nil)
882 [installed_ release];
898 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database version:(pkgCache::VerIterator)version file:(pkgCache::VerFileIterator)file {
899 if ((self = [super init]) != nil) {
900 iterator_ = iterator;
901 database_ = database;
906 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
908 const char *begin, *end;
909 parser->GetRec(begin, end);
911 latest_ = [[NSString stringWithCString:version_.VerStr()] retain];
912 installed_ = iterator_.CurrentVer().end() ? nil : [[NSString stringWithCString:iterator_.CurrentVer().VerStr()] retain];
914 id_ = [[[NSString stringWithCString:iterator_.Name()] lowercaseString] retain];
915 name_ = Scour("Name", begin, end);
917 name_ = [name_ retain];
918 tagline_ = [[NSString stringWithCString:parser->ShortDesc().c_str()] retain];
919 icon_ = Scour("Icon", begin, end);
921 icon_ = [icon_ retain];
922 website_ = Scour("Website", begin, end);
924 website_ = [website_ retain];
926 source_ = [[database_ getSource:file_.File()] retain];
928 NSMutableDictionary *metadata = [Packages_ objectForKey:id_];
929 if (metadata == nil || [metadata count] == 0) {
930 metadata = [NSMutableDictionary dictionaryWithObjectsAndKeys:
934 [Packages_ setObject:metadata forKey:id_];
939 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
940 for (pkgCache::VerIterator version = iterator.VersionList(); !version.end(); ++version)
941 for (pkgCache::VerFileIterator file = version.FileList(); !file.end(); ++file)
942 return [[[Package alloc]
943 initWithIterator:iterator
951 - (NSString *) section {
952 const char *section = iterator_.Section();
953 return section == NULL ? nil : [[NSString stringWithCString:section] stringByReplacingCharacter:'_' withCharacter:' '];
956 - (Address *) maintainer {
957 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
958 return [Address addressWithString:[NSString stringWithCString:parser->Maintainer().c_str()]];
962 return version_->InstalledSize;
965 - (NSString *) description {
966 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
967 NSString *description([NSString stringWithCString:parser->LongDesc().c_str()]);
969 NSArray *lines = [description componentsSeparatedByString:@"\n"];
970 NSMutableArray *trimmed = [NSMutableArray arrayWithCapacity:([lines count] - 1)];
971 if ([lines count] < 2)
974 NSCharacterSet *whitespace = [NSCharacterSet whitespaceCharacterSet];
975 for (size_t i(1); i != [lines count]; ++i) {
976 NSString *trim = [[lines objectAtIndex:i] stringByTrimmingCharactersInSet:whitespace];
977 [trimmed addObject:trim];
980 return [trimmed componentsJoinedByString:@"\n"];
983 - (NSString *) index {
984 NSString *index = [[[self name] substringToIndex:1] uppercaseString];
985 return [index length] != 0 && isalpha([index characterAtIndex:0]) ? index : @"123";
989 return [[Packages_ objectForKey:id_] objectForKey:@"FirstSeen"];
992 - (NSString *) latest {
996 - (NSString *) installed {
1000 - (BOOL) upgradable {
1001 if (NSString *installed = [self installed])
1002 return [[self latest] compare:installed] != NSOrderedSame ? YES : NO;
1004 return [self essential];
1007 - (BOOL) essential {
1008 return (iterator_->Flags & pkgCache::Flag::Essential) == 0 ? NO : YES;
1012 return (*[database_ cache])[iterator_].InstBroken();
1019 - (NSString *) name {
1020 return name_ == nil ? id_ : name_;
1023 - (NSString *) tagline {
1027 - (NSString *) icon {
1031 - (NSString *) website {
1035 - (Source *) source {
1039 - (BOOL) matches:(NSString *)text {
1045 range = [[self id] rangeOfString:text options:NSCaseInsensitiveSearch];
1046 if (range.location != NSNotFound)
1049 range = [[self name] rangeOfString:text options:NSCaseInsensitiveSearch];
1050 if (range.location != NSNotFound)
1053 range = [[self tagline] rangeOfString:text options:NSCaseInsensitiveSearch];
1054 if (range.location != NSNotFound)
1060 - (NSComparisonResult) compareByName:(Package *)package {
1061 NSString *lhs = [self name];
1062 NSString *rhs = [package name];
1064 if ([lhs length] != 0 && [rhs length] != 0) {
1065 unichar lhc = [lhs characterAtIndex:0];
1066 unichar rhc = [rhs characterAtIndex:0];
1068 if (isalpha(lhc) && !isalpha(rhc))
1069 return NSOrderedAscending;
1070 else if (!isalpha(lhc) && isalpha(rhc))
1071 return NSOrderedDescending;
1074 return [lhs caseInsensitiveCompare:rhs];
1077 - (NSComparisonResult) compareBySection:(Package *)package {
1078 NSString *lhs = [self section];
1079 NSString *rhs = [package section];
1081 if (lhs == NULL && rhs != NULL)
1082 return NSOrderedAscending;
1083 else if (lhs != NULL && rhs == NULL)
1084 return NSOrderedDescending;
1085 else if (lhs != NULL && rhs != NULL) {
1086 NSComparisonResult result = [lhs compare:rhs];
1087 if (result != NSOrderedSame)
1091 return NSOrderedSame;
1094 - (NSComparisonResult) compareBySectionAndName:(Package *)package {
1095 NSString *lhs = [self section];
1096 NSString *rhs = [package section];
1098 if (lhs == NULL && rhs != NULL)
1099 return NSOrderedAscending;
1100 else if (lhs != NULL && rhs == NULL)
1101 return NSOrderedDescending;
1102 else if (lhs != NULL && rhs != NULL) {
1103 NSComparisonResult result = [lhs compare:rhs];
1104 if (result != NSOrderedSame)
1108 return [self compareByName:package];
1111 - (NSComparisonResult) compareForChanges:(Package *)package {
1112 BOOL lhs = [self upgradable];
1113 BOOL rhs = [package upgradable];
1116 return lhs ? NSOrderedAscending : NSOrderedDescending;
1118 switch ([[self seen] compare:[package seen]]) {
1119 case NSOrderedAscending:
1120 return NSOrderedDescending;
1123 case NSOrderedDescending:
1124 return NSOrderedAscending;
1130 return [self compareByName:package];
1134 pkgProblemResolver *resolver = [database_ resolver];
1135 resolver->Clear(iterator_);
1136 resolver->Protect(iterator_);
1137 pkgCacheFile &cache([database_ cache]);
1138 cache->MarkInstall(iterator_, false);
1139 pkgDepCache::StateCache &state((*cache)[iterator_]);
1140 if (!state.Install())
1141 cache->SetReInstall(iterator_, true);
1145 pkgProblemResolver *resolver = [database_ resolver];
1146 resolver->Clear(iterator_);
1147 resolver->Protect(iterator_);
1148 resolver->Remove(iterator_);
1149 [database_ cache]->MarkDelete(iterator_, true);
1152 - (NSNumber *) isSearchedForBy:(NSString *)search {
1153 return [NSNumber numberWithBool:[self matches:search]];
1156 - (NSNumber *) isInstalledInSection:(NSString *)section {
1157 return [NSNumber numberWithBool:([self installed] != nil && (section == nil || [section isEqualToString:[self section]]))];
1160 - (NSNumber *) isUninstalledInSection:(NSString *)section {
1161 return [NSNumber numberWithBool:([self installed] == nil && (section == nil || [section isEqualToString:[self section]]))];
1166 /* Section Class {{{ */
1167 @interface Section : NSObject {
1173 - (Section *) initWithName:(NSString *)name row:(size_t)row;
1174 - (NSString *) name;
1177 - (void) addToCount;
1181 @implementation Section
1188 - (Section *) initWithName:(NSString *)name row:(size_t)row {
1189 if ((self = [super init]) != nil) {
1190 name_ = [name retain];
1195 - (NSString *) name {
1207 - (void) addToCount {
1214 /* Database Implementation {{{ */
1215 @implementation Database
1222 - (void) _readStatus:(NSNumber *)fd {
1223 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1225 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1226 std::istream is(&ib);
1231 pcre *code = pcre_compile("^([^:]*):([^:]*):([^:]*):(.*)$", 0, &error, &offset, NULL);
1233 pcre_extra *study = NULL;
1235 pcre_fullinfo(code, study, PCRE_INFO_CAPTURECOUNT, &capture);
1236 int matches[(capture + 1) * 3];
1238 while (std::getline(is, line)) {
1239 const char *data(line.c_str());
1241 _assert(pcre_exec(code, study, data, line.size(), 0, 0, matches, sizeof(matches) / sizeof(matches[0])) >= 0);
1243 std::istringstream buffer(line.substr(matches[6], matches[7] - matches[6]));
1246 [delegate_ setProgressPercent:(percent / 100)];
1248 NSString *string = [NSString stringWithCString:(data + matches[8]) length:(matches[9] - matches[8])];
1249 std::string type(line.substr(matches[2], matches[3] - matches[2]));
1251 if (type == "pmerror")
1252 [delegate_ setProgressError:string];
1253 else if (type == "pmstatus")
1254 [delegate_ setProgressTitle:string];
1255 else if (type == "pmconffile")
1257 else _assert(false);
1264 - (void) _readOutput:(NSNumber *)fd {
1265 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1267 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1268 std::istream is(&ib);
1271 while (std::getline(is, line))
1272 [delegate_ addProgressOutput:[NSString stringWithCString:line.c_str()]];
1278 - (Package *) packageWithName:(NSString *)name {
1279 pkgCache::PkgIterator iterator(cache_->FindPkg([name UTF8String]));
1280 return iterator.end() ? nil : [Package packageWithIterator:iterator database:self];
1283 - (Database *) init {
1284 if ((self = [super init]) != nil) {
1290 sources_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1291 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
1295 _assert(pipe(fds) != -1);
1299 detachNewThreadSelector:@selector(_readStatus:)
1301 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1304 _assert(pipe(fds) != -1);
1305 _assert(dup2(fds[1], 1) != -1);
1306 _assert(close(fds[1]) != -1);
1309 detachNewThreadSelector:@selector(_readOutput:)
1311 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1316 - (pkgCacheFile &) cache {
1320 - (pkgRecords *) records {
1324 - (pkgProblemResolver *) resolver {
1328 - (pkgAcquire &) fetcher {
1332 - (NSArray *) packages {
1336 - (void) reloadData {
1346 if (!cache_.Open(progress_, true)) {
1347 fprintf(stderr, "repairing corrupted database...\n");
1349 [self updateWithStatus:status_];
1350 _assert(cache_.Open(progress_, true));
1353 now_ = [[NSDate date] retain];
1355 records_ = new pkgRecords(cache_);
1356 resolver_ = new pkgProblemResolver(cache_);
1357 fetcher_ = new pkgAcquire(&status_);
1360 list_ = new pkgSourceList();
1361 _assert(list_->ReadMainList());
1363 [sources_ removeAllObjects];
1364 for (pkgSourceList::const_iterator source = list_->begin(); source != list_->end(); ++source) {
1365 std::vector<pkgIndexFile *> *indices = (*source)->GetIndexFiles();
1366 for (std::vector<pkgIndexFile *>::const_iterator index = indices->begin(); index != indices->end(); ++index)
1368 setObject:[[[Source alloc] initWithMetaIndex:*source] autorelease]
1369 forKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(*index)]
1373 [packages_ removeAllObjects];
1374 for (pkgCache::PkgIterator iterator = cache_->PkgBegin(); !iterator.end(); ++iterator)
1375 if (Package *package = [Package packageWithIterator:iterator database:self])
1376 if ([package source] != nil || [package installed] != nil)
1377 [packages_ addObject:package];
1381 pkgRecords records(cache_);
1383 lock_ = new FileFd();
1384 lock_->Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1385 _assert(!_error->PendingError());
1388 // XXX: explain this with an error message
1389 _assert(list.ReadMainList());
1391 manager_ = (_system->CreatePM(cache_));
1392 _assert(manager_->GetArchives(fetcher_, &list, &records));
1393 _assert(!_error->PendingError());
1397 if (fetcher_->Run(PulseInterval_) != pkgAcquire::Continue)
1401 pkgPackageManager::OrderResult result = manager_->DoInstall(statusfd_);
1403 if (result == pkgPackageManager::Failed)
1405 if (_error->PendingError())
1407 if (result != pkgPackageManager::Completed)
1412 _assert(cache_->DelCount() == 0 && cache_->InstCount() == 0);
1413 _assert(pkgApplyStatus(cache_));
1415 if (cache_->BrokenCount() != 0) {
1416 _assert(pkgFixBroken(cache_));
1417 _assert(cache_->BrokenCount() == 0);
1418 _assert(pkgMinimizeUpgrade(cache_));
1421 _assert(pkgDistUpgrade(cache_));
1425 [self updateWithStatus:status_];
1428 - (void) updateWithStatus:(Status &)status {
1430 _assert(list.ReadMainList());
1433 lock.Fd(GetLock(_config->FindDir("Dir::State::Lists") + "lock"));
1434 _assert(!_error->PendingError());
1436 pkgAcquire fetcher(&status);
1437 _assert(list.GetIndexes(&fetcher));
1439 if (fetcher.Run(PulseInterval_) != pkgAcquire::Failed) {
1440 bool failed = false;
1441 for (pkgAcquire::ItemIterator item = fetcher.ItemsBegin(); item != fetcher.ItemsEnd(); item++)
1442 if ((*item)->Status != pkgAcquire::Item::StatDone) {
1443 (*item)->Finished();
1447 if (!failed && _config->FindB("APT::Get::List-Cleanup", true) == true) {
1448 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists")));
1449 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/"));
1452 [Metadata_ setObject:[NSDate date] forKey:@"LastUpdate"];
1456 - (void) setDelegate:(id)delegate {
1457 delegate_ = delegate;
1458 status_.setDelegate(delegate);
1459 progress_.setDelegate(delegate);
1462 - (Source *) getSource:(const pkgCache::PkgFileIterator &)file {
1463 pkgIndexFile *index(NULL);
1464 list_->FindIndex(file, index);
1465 return [sources_ objectForKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(index)]];
1471 /* RVPage Interface {{{ */
1474 @interface RVPage : UIView {
1475 _transient RVBook *book_;
1476 _transient id delegate_;
1479 - (NSString *) title;
1480 - (NSString *) backButtonTitle;
1481 - (NSString *) rightButtonTitle;
1482 - (NSString *) leftButtonTitle;
1483 - (UIView *) accessoryView;
1485 - (void) _rightButtonClicked;
1486 - (void) _leftButtonClicked;
1488 - (void) setPageActive:(BOOL)active;
1489 - (void) resetViewAnimated:(BOOL)animated;
1491 - (void) setTitle:(NSString *)title;
1492 - (void) setBackButtonTitle:(NSString *)title;
1494 - (void) reloadButtons;
1495 - (void) reloadData;
1497 - (id) initWithBook:(RVBook *)book;
1499 - (void) setDelegate:(id)delegate;
1503 /* Reset View {{{ */
1504 @protocol RVDelegate
1505 - (void) setPageActive:(BOOL)active with:(id)object;
1506 - (void) resetViewAnimated:(BOOL)animated with:(id)object;
1507 - (void) reloadDataWith:(id)object;
1510 @interface RVBook : UIView {
1511 NSMutableArray *pages_;
1512 UINavigationBar *navbar_;
1513 UITransitionView *transition_;
1515 _transient id delegate_;
1518 - (id) initWithFrame:(CGRect)frame;
1519 - (void) setDelegate:(id)delegate;
1521 - (void) setPage:(RVPage *)page;
1523 - (void) pushPage:(RVPage *)page;
1524 - (void) popPages:(unsigned)pages;
1526 - (void) setPrompt:(NSString *)prompt;
1528 - (void) resetViewAnimated:(BOOL)animated;
1529 - (void) resetViewAnimated:(BOOL)animated toPage:(RVPage *)page;
1531 - (void) setTitle:(NSString *)title forPage:(RVPage *)page;
1532 - (void) setBackButtonTitle:(NSString *)title forPage:(RVPage *)page;
1533 - (void) reloadButtonsForPage:(RVPage *)page;
1535 - (void) reloadData;
1537 - (CGRect) pageBounds;
1541 @implementation RVBook
1544 [navbar_ setDelegate:nil];
1548 [transition_ release];
1552 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
1553 _assert([pages_ count] != 0);
1554 RVPage *page = [pages_ lastObject];
1556 case 0: [page _rightButtonClicked]; break;
1557 case 1: [page _leftButtonClicked]; break;
1561 - (void) navigationBar:(UINavigationBar *)navbar poppedItem:(UINavigationItem *)item {
1562 _assert([pages_ count] != 0);
1564 [[pages_ lastObject] setPageActive:NO];
1565 [pages_ removeLastObject];
1567 [self resetViewAnimated:YES toPage:[pages_ lastObject]];
1570 - (id) initWithFrame:(CGRect)frame {
1571 if ((self = [super initWithFrame:frame]) != nil) {
1572 pages_ = [[NSMutableArray arrayWithCapacity:4] retain];
1574 struct CGRect bounds = [self bounds];
1575 CGSize navsize = [UINavigationBar defaultSizeWithPrompt];
1576 CGRect navrect = {{0, 0}, navsize};
1578 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
1579 [self addSubview:navbar_];
1581 [navbar_ setBarStyle:1];
1582 [navbar_ setDelegate:self];
1584 [navbar_ setPrompt:@""];
1586 transition_ = [[UITransitionView alloc] initWithFrame:CGRectMake(
1587 bounds.origin.x, bounds.origin.y + navsize.height, bounds.size.width, bounds.size.height - navsize.height
1590 [self addSubview:transition_];
1594 - (void) setDelegate:(id)delegate {
1595 delegate_ = delegate;
1598 - (void) setPage:(RVPage *)page {
1599 if ([pages_ count] != 0)
1600 [[pages_ lastObject] setPageActive:NO];
1602 [navbar_ disableAnimation];
1604 for (unsigned i(0), pages([pages_ count]); i != pages; ++i)
1605 [navbar_ popNavigationItem];
1608 [self pushPage:page];
1609 [navbar_ enableAnimation];
1612 - (void) pushPage:(RVPage *)page {
1613 if ([pages_ count] != 0)
1614 [[pages_ lastObject] setPageActive:NO];
1616 NSString *title = [page title]; {
1617 const char *data = [title UTF8String];
1618 size_t size = [title length];
1620 Pcre title_r("^(.*?)( \\(.*\\))?$");
1621 if (title_r(data, size))
1625 NSString *backButtonTitle = [page backButtonTitle];
1626 if (backButtonTitle == nil)
1627 backButtonTitle = title;
1629 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:title] autorelease];
1630 [navitem setBackButtonTitle:backButtonTitle];
1631 [navbar_ pushNavigationItem:navitem];
1633 BOOL animated = [pages_ count] == 0 ? NO : YES;
1634 [transition_ transition:(animated ? 1 : 0) toView:page];
1635 [page setPageActive:YES];
1637 [pages_ addObject:page];
1638 [self reloadButtonsForPage:page];
1640 [navbar_ setAccessoryView:[page accessoryView] animate:animated goingBack:NO];
1643 - (void) popPages:(unsigned)pages {
1647 [[pages_ lastObject] setPageActive:NO];
1650 for (unsigned i(0); i != pages; ++i)
1651 [navbar_ popNavigationItem];
1654 [self resetViewAnimated:YES toPage:[pages_ lastObject]];
1657 - (void) setPrompt:(NSString *)prompt {
1658 [navbar_ setPrompt:prompt];
1661 - (void) resetViewAnimated:(BOOL)animated {
1664 if ([pages_ count] > 1) {
1665 [navbar_ disableAnimation];
1666 while ([pages_ count] != (animated ? 2 : 1))
1667 [navbar_ popNavigationItem];
1668 [navbar_ enableAnimation];
1670 [navbar_ popNavigationItem];
1675 [self resetViewAnimated:animated toPage:[pages_ lastObject]];
1678 - (void) resetViewAnimated:(BOOL)animated toPage:(RVPage *)page {
1679 [page resetViewAnimated:animated];
1680 [transition_ transition:(animated ? 2 : 0) toView:page];
1681 [page setPageActive:YES];
1682 [self reloadButtonsForPage:page];
1683 [navbar_ setAccessoryView:[page accessoryView] animate:animated goingBack:YES];
1686 - (void) setTitle:(NSString *)title forPage:(RVPage *)page {
1687 if ([pages_ count] == 0 || page != [pages_ lastObject])
1689 UINavigationItem *navitem = [navbar_ topItem];
1690 [navitem setTitle:title];
1693 - (void) setBackButtonTitle:(NSString *)title forPage:(RVPage *)page {
1694 if ([pages_ count] == 0 || page != [pages_ lastObject])
1696 UINavigationItem *navitem = [navbar_ topItem];
1697 [navitem setBackButtonTitle:title];
1700 - (void) reloadButtonsForPage:(RVPage *)page {
1701 if ([pages_ count] == 0 || page != [pages_ lastObject])
1703 NSString *leftButtonTitle([pages_ count] == 1 ? [page leftButtonTitle] : nil);
1704 [navbar_ showButtonsWithLeftTitle:leftButtonTitle rightTitle:[page rightButtonTitle]];
1707 - (void) reloadData {
1708 for (int i(0), e([pages_ count]); i != e; ++i) {
1709 RVPage *page([pages_ objectAtIndex:(e - i - 1)]);
1714 - (CGRect) pageBounds {
1715 return [transition_ bounds];
1720 /* RVPage Implementation {{{ */
1721 @implementation RVPage
1723 - (NSString *) title {
1724 [self doesNotRecognizeSelector:_cmd];
1728 - (NSString *) backButtonTitle {
1732 - (NSString *) leftButtonTitle {
1736 - (NSString *) rightButtonTitle {
1740 - (void) _rightButtonClicked {
1741 [self doesNotRecognizeSelector:_cmd];
1744 - (void) _leftButtonClicked {
1745 [self doesNotRecognizeSelector:_cmd];
1748 - (UIView *) accessoryView {
1752 - (void) setPageActive:(BOOL)active {
1755 - (void) resetViewAnimated:(BOOL)animated {
1756 [self doesNotRecognizeSelector:_cmd];
1759 - (void) setTitle:(NSString *)title {
1760 [book_ setTitle:title forPage:self];
1763 - (void) setBackButtonTitle:(NSString *)title {
1764 [book_ setBackButtonTitle:title forPage:self];
1767 - (void) reloadButtons {
1768 [book_ reloadButtonsForPage:self];
1771 - (void) reloadData {
1774 - (id) initWithBook:(RVBook *)book {
1775 if ((self = [super initWithFrame:[book pageBounds]]) != nil) {
1780 - (void) setDelegate:(id)delegate {
1781 delegate_ = delegate;
1787 /* Confirmation View {{{ */
1788 void AddTextView(NSMutableDictionary *fields, NSMutableArray *packages, NSString *key) {
1789 if ([packages count] == 0)
1792 UITextView *text = GetTextView([packages count] == 0 ? @"n/a" : [packages componentsJoinedByString:@", "], 120, false);
1793 [fields setObject:text forKey:key];
1795 CGColor blue(space_, 0, 0, 0.4, 1);
1796 [text setTextColor:blue];
1799 @protocol ConfirmationViewDelegate
1804 @interface ConfirmationView : UIView {
1805 Database *database_;
1807 UITransitionView *transition_;
1809 UINavigationBar *navbar_;
1810 UIPreferencesTable *table_;
1811 NSMutableDictionary *fields_;
1812 UIAlertSheet *essential_;
1817 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate;
1821 @implementation ConfirmationView
1824 [navbar_ setDelegate:nil];
1825 [transition_ setDelegate:nil];
1826 [table_ setDataSource:nil];
1828 [transition_ release];
1833 if (essential_ != nil)
1834 [essential_ release];
1839 [transition_ transition:7 toView:nil];
1843 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
1844 if (from != nil && to == nil)
1845 [self removeFromSuperview];
1848 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
1851 if (essential_ != nil)
1852 [essential_ popupAlertAnimated:YES];
1854 [delegate_ confirm];
1863 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
1864 [essential_ dismiss];
1868 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
1872 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
1874 case 0: return @"Statistics";
1875 case 1: return @"Modifications";
1877 default: _assert(false);
1881 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
1884 case 1: return [fields_ count];
1886 default: _assert(false);
1890 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
1891 if (group != 1 || row == -1)
1894 _assert(size_t(row) < [fields_ count]);
1895 return [[[fields_ allValues] objectAtIndex:row] visibleTextRect].size.height + TextViewOffset_;
1899 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
1900 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
1901 [cell setShowSelection:NO];
1904 case 0: switch (row) {
1906 [cell setTitle:@"Downloading"];
1907 [cell setValue:SizeString([database_ fetcher].FetchNeeded())];
1911 [cell setTitle:@"Resuming At"];
1912 [cell setValue:SizeString([database_ fetcher].PartialPresent())];
1916 double size([database_ cache]->UsrSize());
1919 [cell setTitle:@"Disk Freeing"];
1920 [cell setValue:SizeString(-size)];
1922 [cell setTitle:@"Disk Using"];
1923 [cell setValue:SizeString(size)];
1927 default: _assert(false);
1931 _assert(size_t(row) < [fields_ count]);
1932 [cell setTitle:[[fields_ allKeys] objectAtIndex:row]];
1933 [cell addSubview:[[fields_ allValues] objectAtIndex:row]];
1936 default: _assert(false);
1942 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate {
1943 if ((self = [super initWithFrame:[view bounds]]) != nil) {
1944 database_ = database;
1945 delegate_ = delegate;
1947 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
1948 [self addSubview:transition_];
1950 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
1952 CGSize navsize = [UINavigationBar defaultSize];
1953 CGRect navrect = {{0, 0}, navsize};
1954 CGRect bounds = [overlay_ bounds];
1956 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
1957 [navbar_ setBarStyle:1];
1958 [navbar_ setDelegate:self];
1960 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Confirm"] autorelease];
1961 [navbar_ pushNavigationItem:navitem];
1962 [navbar_ showButtonsWithLeftTitle:@"Cancel" rightTitle:@"Confirm"];
1964 fields_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1966 NSMutableArray *installing = [NSMutableArray arrayWithCapacity:16];
1967 NSMutableArray *reinstalling = [NSMutableArray arrayWithCapacity:16];
1968 NSMutableArray *upgrading = [NSMutableArray arrayWithCapacity:16];
1969 NSMutableArray *downgrading = [NSMutableArray arrayWithCapacity:16];
1970 NSMutableArray *removing = [NSMutableArray arrayWithCapacity:16];
1974 pkgCacheFile &cache([database_ cache]);
1975 for (pkgCache::PkgIterator iterator = cache->PkgBegin(); !iterator.end(); ++iterator) {
1976 Package *package([Package packageWithIterator:iterator database:database_]);
1977 NSString *name([package name]);
1978 bool essential((iterator->Flags & pkgCache::Flag::Essential) != 0);
1979 pkgDepCache::StateCache &state(cache[iterator]);
1981 if (state.NewInstall())
1982 [installing addObject:name];
1983 else if (!state.Delete() && (state.iFlags & pkgDepCache::ReInstall) == pkgDepCache::ReInstall)
1984 [reinstalling addObject:name];
1985 else if (state.Upgrade())
1986 [upgrading addObject:name];
1987 else if (state.Downgrade())
1988 [downgrading addObject:name];
1989 else if (state.Delete()) {
1992 [removing addObject:name];
1999 essential_ = [[UIAlertSheet alloc]
2000 initWithTitle:@"Unable to Comply"
2001 buttons:[NSArray arrayWithObjects:@"Okay", nil]
2002 defaultButtonIndex:0
2007 [essential_ setBodyText:@"One or more of the packages you are about to remove are marked 'Essential' and cannot be removed by Cydia. Please use apt-get."];
2010 AddTextView(fields_, installing, @"Installing");
2011 AddTextView(fields_, reinstalling, @"Reinstalling");
2012 AddTextView(fields_, upgrading, @"Upgrading");
2013 AddTextView(fields_, downgrading, @"Downgrading");
2014 AddTextView(fields_, removing, @"Removing");
2016 table_ = [[UIPreferencesTable alloc] initWithFrame:CGRectMake(
2017 0, navsize.height, bounds.size.width, bounds.size.height - navsize.height
2020 [table_ setReusesTableCells:YES];
2021 [table_ setDataSource:self];
2022 [table_ reloadData];
2024 [overlay_ addSubview:navbar_];
2025 [overlay_ addSubview:table_];
2027 [view addSubview:self];
2029 [transition_ setDelegate:self];
2031 UIView *blank = [[[UIView alloc] initWithFrame:[transition_ bounds]] autorelease];
2032 [transition_ transition:0 toView:blank];
2033 [transition_ transition:3 toView:overlay_];
2040 /* Progress Data {{{ */
2041 @interface ProgressData : NSObject {
2047 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object;
2054 @implementation ProgressData
2056 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object {
2057 if ((self = [super init]) != nil) {
2058 selector_ = selector;
2078 /* Progress View {{{ */
2079 @interface ProgressView : UIView <
2083 UIView *background_;
2084 UITransitionView *transition_;
2086 UINavigationBar *navbar_;
2087 UIProgressBar *progress_;
2088 UITextView *output_;
2089 UITextLabel *status_;
2093 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
2095 - (ProgressView *) initWithFrame:(struct CGRect)frame delegate:(id)delegate;
2096 - (void) setContentView:(UIView *)view;
2099 - (void) _retachThread;
2100 - (void) _detachNewThreadData:(ProgressData *)data;
2101 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title;
2105 @protocol ProgressViewDelegate
2106 - (void) progressViewIsComplete:(ProgressView *)sender;
2109 @implementation ProgressView
2112 [transition_ setDelegate:nil];
2113 [navbar_ setDelegate:nil];
2116 if (background_ != nil)
2117 [background_ release];
2118 [transition_ release];
2121 [progress_ release];
2127 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
2128 if (bootstrap_ && from == overlay_ && to == view_)
2132 - (ProgressView *) initWithFrame:(struct CGRect)frame delegate:(id)delegate {
2133 if ((self = [super initWithFrame:frame]) != nil) {
2134 delegate_ = delegate;
2136 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
2137 [transition_ setDelegate:self];
2139 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
2142 [overlay_ setBackgroundColor:Black_];
2144 background_ = [[UIView alloc] initWithFrame:[self bounds]];
2145 [background_ setBackgroundColor:Black_];
2146 [self addSubview:background_];
2149 [self addSubview:transition_];
2151 CGSize navsize = [UINavigationBar defaultSize];
2152 CGRect navrect = {{0, 0}, navsize};
2154 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
2155 [overlay_ addSubview:navbar_];
2157 [navbar_ setBarStyle:1];
2158 [navbar_ setDelegate:self];
2160 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:nil] autorelease];
2161 [navbar_ pushNavigationItem:navitem];
2163 CGRect bounds = [overlay_ bounds];
2164 CGSize prgsize = [UIProgressBar defaultSize];
2167 (bounds.size.width - prgsize.width) / 2,
2168 bounds.size.height - prgsize.height - 20
2171 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
2172 [overlay_ addSubview:progress_];
2174 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(
2176 bounds.size.height - prgsize.height - 50,
2177 bounds.size.width - 20,
2181 [status_ setColor:White_];
2182 [status_ setBackgroundColor:Clear_];
2184 [status_ setCentersHorizontally:YES];
2185 //[status_ setFont:font];
2187 output_ = [[UITextView alloc] initWithFrame:CGRectMake(
2189 navrect.size.height + 20,
2190 bounds.size.width - 20,
2191 bounds.size.height - navsize.height - 62 - navrect.size.height
2194 //[output_ setTextFont:@"Courier New"];
2195 [output_ setTextSize:12];
2197 [output_ setTextColor:White_];
2198 [output_ setBackgroundColor:Clear_];
2200 [output_ setMarginTop:0];
2201 [output_ setAllowsRubberBanding:YES];
2203 [overlay_ addSubview:output_];
2204 [overlay_ addSubview:status_];
2206 [progress_ setStyle:0];
2210 - (void) setContentView:(UIView *)view {
2211 view_ = [view retain];
2214 - (void) resetView {
2215 [transition_ transition:6 toView:view_];
2218 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
2222 - (void) _retachThread {
2223 [delegate_ progressViewIsComplete:self];
2227 - (void) _detachNewThreadData:(ProgressData *)data {
2228 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
2230 [[data target] performSelector:[data selector] withObject:[data object]];
2233 [self performSelectorOnMainThread:@selector(_retachThread) withObject:nil waitUntilDone:YES];
2238 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title {
2239 [navbar_ popNavigationItem];
2240 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:title] autorelease];
2241 [navbar_ pushNavigationItem:navitem];
2243 [status_ setText:nil];
2244 [output_ setText:@""];
2245 [progress_ setProgress:0];
2247 [transition_ transition:6 toView:overlay_];
2250 detachNewThreadSelector:@selector(_detachNewThreadData:)
2252 withObject:[[ProgressData alloc]
2253 initWithSelector:selector
2260 - (void) setProgressError:(NSString *)error {
2262 performSelectorOnMainThread:@selector(_setProgressError:)
2268 - (void) setProgressTitle:(NSString *)title {
2270 performSelectorOnMainThread:@selector(_setProgressTitle:)
2276 - (void) setProgressPercent:(float)percent {
2278 performSelectorOnMainThread:@selector(_setProgressPercent:)
2279 withObject:[NSNumber numberWithFloat:percent]
2284 - (void) addProgressOutput:(NSString *)output {
2286 performSelectorOnMainThread:@selector(_addProgressOutput:)
2292 - (void) _setProgressError:(NSString *)error {
2293 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
2294 initWithTitle:@"Package Error"
2295 buttons:[NSArray arrayWithObjects:@"Okay", nil]
2296 defaultButtonIndex:0
2301 [sheet setBodyText:error];
2302 [sheet popupAlertAnimated:YES];
2305 - (void) _setProgressTitle:(NSString *)title {
2306 [status_ setText:[title stringByAppendingString:@"..."]];
2309 - (void) _setProgressPercent:(NSNumber *)percent {
2310 [progress_ setProgress:[percent floatValue]];
2313 - (void) _addProgressOutput:(NSString *)output {
2314 [output_ setText:[NSString stringWithFormat:@"%@\n%@", [output_ text], output]];
2315 CGSize size = [output_ contentSize];
2316 CGRect rect = {{0, size.height}, {size.width, 0}};
2317 [output_ scrollRectToVisible:rect animated:YES];
2323 /* Package Cell {{{ */
2324 @interface PackageCell : UITableCell {
2327 UITextLabel *description_;
2328 UITextLabel *source_;
2329 UIImageView *trusted_;
2332 - (PackageCell *) init;
2333 - (void) setPackage:(Package *)package;
2335 - (void) _setSelected:(float)fraction;
2336 - (void) setSelected:(BOOL)selected;
2337 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
2338 - (void) _setSelectionFadeFraction:(float)fraction;
2342 @implementation PackageCell
2347 [description_ release];
2353 - (PackageCell *) init {
2354 if ((self = [super init]) != nil) {
2355 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 20);
2356 GSFontRef large = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 12);
2357 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 14);
2359 icon_ = [[UIImageView alloc] initWithFrame:CGRectMake(10, 10, 30, 30)];
2360 [icon_ zoomToScale:0.5f];
2362 name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 8, 240, 25)];
2363 [name_ setBackgroundColor:Clear_];
2364 [name_ setFont:bold];
2366 source_ = [[UITextLabel alloc] initWithFrame:CGRectMake(58, 28, 225, 20)];
2367 [source_ setBackgroundColor:Clear_];
2368 [source_ setFont:large];
2370 description_ = [[UITextLabel alloc] initWithFrame:CGRectMake(12, 46, 280, 20)];
2371 [description_ setBackgroundColor:Clear_];
2372 [description_ setFont:small];
2374 trusted_ = [[UIImageView alloc] initWithFrame:CGRectMake(30, 30, 16, 16)];
2375 [trusted_ setImage:[UIImage applicationImageNamed:@"trusted.png"]];
2377 [self addSubview:icon_];
2378 [self addSubview:name_];
2379 [self addSubview:description_];
2380 [self addSubview:source_];
2388 - (void) setPackage:(Package *)package {
2389 Source *source = [package source];
2391 UIImage *image = nil;
2392 if (NSString *icon = [package icon])
2393 image = [UIImage imageAtPath:[icon substringFromIndex:6]];
2394 if (image == nil) if (NSString *icon = [source defaultIcon])
2395 image = [UIImage imageAtPath:[icon substringFromIndex:6]];
2397 image = [UIImage applicationImageNamed:@"unknown.png"];
2399 [icon_ setImage:image];
2400 [icon_ setFrame:CGRectMake(10, 10, 30, 30)];
2402 [name_ setText:[package name]];
2403 [description_ setText:[package tagline]];
2408 if (source != nil) {
2409 label = [source label];
2410 trusted = [source trusted];
2411 } else if ([[package id] isEqualToString:@"firmware"]) {
2415 label = @"Unknown/Local";
2419 [source_ setText:[NSString stringWithFormat:@"from %@", label]];
2422 [self addSubview:trusted_];
2424 [trusted_ removeFromSuperview];
2427 - (void) _setSelected:(float)fraction {
2428 CGColor black(space_,
2429 Interpolate(0.0, 1.0, fraction),
2430 Interpolate(0.0, 1.0, fraction),
2431 Interpolate(0.0, 1.0, fraction),
2434 CGColor gray(space_,
2435 Interpolate(0.4, 1.0, fraction),
2436 Interpolate(0.4, 1.0, fraction),
2437 Interpolate(0.4, 1.0, fraction),
2440 [name_ setColor:black];
2441 [description_ setColor:gray];
2442 [source_ setColor:black];
2445 - (void) setSelected:(BOOL)selected {
2446 [self _setSelected:(selected ? 1.0 : 0.0)];
2447 [super setSelected:selected];
2450 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
2452 [self _setSelected:(selected ? 1.0 : 0.0)];
2453 [super setSelected:selected withFade:fade];
2456 - (void) _setSelectionFadeFraction:(float)fraction {
2457 [self _setSelected:fraction];
2458 [super _setSelectionFadeFraction:fraction];
2463 /* Section Cell {{{ */
2464 @interface SectionCell : UITableCell {
2466 UITextLabel *count_;
2470 - (void) setSection:(Section *)section;
2472 - (void) _setSelected:(float)fraction;
2473 - (void) setSelected:(BOOL)selected;
2474 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
2475 - (void) _setSelectionFadeFraction:(float)fraction;
2479 @implementation SectionCell
2488 if ((self = [super init]) != nil) {
2489 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22);
2490 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 12);
2492 name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 9, 250, 25)];
2493 [name_ setBackgroundColor:Clear_];
2494 [name_ setFont:bold];
2496 count_ = [[UITextLabel alloc] initWithFrame:CGRectMake(11, 7, 29, 32)];
2497 [count_ setCentersHorizontally:YES];
2498 [count_ setBackgroundColor:Clear_];
2499 [count_ setFont:small];
2500 [count_ setColor:White_];
2502 UIImageView *folder = [[[UIImageView alloc] initWithFrame:CGRectMake(8, 7, 32, 32)] autorelease];
2503 [folder setImage:[UIImage applicationImageNamed:@"folder.png"]];
2505 [self addSubview:folder];
2506 [self addSubview:name_];
2507 [self addSubview:count_];
2509 [self _setSelected:0];
2516 - (void) setSection:(Section *)section {
2517 if (section == nil) {
2518 [name_ setText:@"All Packages"];
2519 [count_ setText:nil];
2521 NSString *name = [section name];
2522 [name_ setText:(name == nil ? @"(No Section)" : name)];
2523 [count_ setText:[NSString stringWithFormat:@"%d", [section count]]];
2527 - (void) _setSelected:(float)fraction {
2528 CGColor black(space_,
2529 Interpolate(0.0, 1.0, fraction),
2530 Interpolate(0.0, 1.0, fraction),
2531 Interpolate(0.0, 1.0, fraction),
2534 [name_ setColor:black];
2537 - (void) setSelected:(BOOL)selected {
2538 [self _setSelected:(selected ? 1.0 : 0.0)];
2539 [super setSelected:selected];
2542 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
2544 [self _setSelected:(selected ? 1.0 : 0.0)];
2545 [super setSelected:selected withFade:fade];
2548 - (void) _setSelectionFadeFraction:(float)fraction {
2549 [self _setSelected:fraction];
2550 [super _setSelectionFadeFraction:fraction];
2556 /* Browser Interface {{{ */
2557 @interface BrowserView : RVPage {
2558 _transient Database *database_;
2559 UIScroller *scroller_;
2560 UIWebView *webview_;
2561 NSMutableArray *urls_;
2562 UIProgressIndicator *indicator_;
2568 - (void) loadURL:(NSURL *)url cachePolicy:(NSURLRequestCachePolicy)policy;
2569 - (void) loadURL:(NSURL *)url;
2571 - (void) loadRequest:(NSURLRequest *)request;
2574 - (WebView *) webView;
2576 - (id) initWithBook:(RVBook *)book database:(Database *)database;
2581 /* Package View {{{ */
2582 @protocol PackageViewDelegate
2583 - (void) performPackage:(Package *)package;
2586 @interface PackageView : RVPage {
2587 _transient Database *database_;
2588 UIPreferencesTable *table_;
2591 UITextView *description_;
2594 - (id) initWithBook:(RVBook *)book database:(Database *)database;
2595 - (void) setPackage:(Package *)package;
2599 @implementation PackageView
2602 [table_ setDataSource:nil];
2603 [table_ setDelegate:nil];
2605 if (package_ != nil)
2609 if (description_ != nil)
2610 [description_ release];
2615 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
2616 return [package_ source] == nil ? 2 : 3;
2619 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
2622 case 1: return @"Package Details";
2623 case 2: return @"Source Information";
2625 default: _assert(false);
2629 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
2630 if (group != 0 || row != 1)
2633 return [description_ visibleTextRect].size.height + TextViewOffset_;
2636 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
2638 case 0: return [package_ website] == nil ? 2 : 3;
2642 default: _assert(false);
2646 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
2647 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
2648 [cell setShowSelection:NO];
2651 case 0: switch (row) {
2653 [cell setTitle:[package_ name]];
2654 [cell setValue:[package_ latest]];
2658 [cell addSubview:description_];
2662 [cell setTitle:@"More Information"];
2663 [cell setShowDisclosure:YES];
2664 [cell setShowSelection:YES];
2667 default: _assert(false);
2670 case 1: switch (row) {
2672 [cell setTitle:@"Identifier"];
2673 [cell setValue:[package_ id]];
2677 [cell setTitle:@"Installed Version"];
2678 NSString *installed([package_ installed]);
2679 [cell setValue:(installed == nil ? @"n/a" : installed)];
2683 [cell setTitle:@"Section"];
2684 NSString *section([package_ section]);
2685 [cell setValue:(section == nil ? @"n/a" : section)];
2689 [cell setTitle:@"Expanded Size"];
2690 [cell setValue:SizeString([package_ size])];
2694 [cell setTitle:@"Maintainer"];
2695 [cell setValue:[[package_ maintainer] name]];
2696 [cell setShowDisclosure:YES];
2697 [cell setShowSelection:YES];
2700 default: _assert(false);
2703 case 2: switch (row) {
2705 [cell setTitle:[[package_ source] label]];
2706 [cell setValue:[[package_ source] version]];
2710 [cell setValue:[[package_ source] description]];
2714 [cell setTitle:@"Origin"];
2715 [cell setValue:[[package_ source] origin]];
2718 default: _assert(false);
2721 default: _assert(false);
2727 - (BOOL) canSelectRow:(int)row {
2731 - (void) tableRowSelected:(NSNotification *)notification {
2732 int row = [table_ selectedRow];
2733 NSString *website = [package_ website];
2735 if (row == (website == nil ? 8 : 9))
2736 [delegate_ openURL:[NSURL URLWithString:[NSString stringWithFormat:@"mailto:%@?subject=%@",
2737 [[package_ maintainer] email],
2738 [[NSString stringWithFormat:@"regarding apt package \"%@\"", [package_ name]] stringByAddingPercentEscapes]
2740 else if (website != nil && row == 3) {
2741 NSURL *url = [NSURL URLWithString:website];
2742 BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease];
2743 [browser setDelegate:delegate_];
2744 [book_ pushPage:browser];
2745 [browser loadURL:url];
2749 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
2751 case 1: [delegate_ installPackage:package_]; break;
2752 case 2: [delegate_ removePackage:package_]; break;
2758 - (void) _rightButtonClicked {
2759 if ([package_ installed] == nil)
2760 [delegate_ installPackage:package_];
2762 NSMutableArray *buttons = [NSMutableArray arrayWithCapacity:6];
2764 if ([package_ upgradable])
2765 [buttons addObject:@"Upgrade"];
2767 [buttons addObject:@"Reinstall"];
2769 [buttons addObject:@"Remove"];
2770 [buttons addObject:@"Cancel"];
2772 [delegate_ slideUp:[[[UIAlertSheet alloc]
2773 initWithTitle:@"Manage Package"
2775 defaultButtonIndex:2
2782 - (NSString *) rightButtonTitle {
2783 _assert(package_ != nil);
2784 return [package_ installed] == nil ? @"Install" : @"Manage";
2787 - (NSString *) title {
2791 - (id) initWithBook:(RVBook *)book database:(Database *)database {
2792 if ((self = [super initWithBook:book]) != nil) {
2793 database_ = database;
2795 table_ = [[UIPreferencesTable alloc] initWithFrame:[self bounds]];
2796 [self addSubview:table_];
2798 [table_ setDataSource:self];
2799 [table_ setDelegate:self];
2803 - (void) setPackage:(Package *)package {
2804 if (package_ != nil) {
2805 [package_ autorelease];
2814 if (description_ != nil) {
2815 [description_ release];
2819 if (package != nil) {
2820 package_ = [package retain];
2821 name_ = [[package id] retain];
2823 NSString *description([package description]);
2824 if (description == nil)
2825 description = [package tagline];
2826 description_ = [GetTextView(description, 12, true) retain];
2828 [description_ setTextColor:Black_];
2830 [table_ reloadData];
2834 - (void) resetViewAnimated:(BOOL)animated {
2835 [table_ resetViewAnimated:animated];
2838 - (void) reloadData {
2839 [self setPackage:[database_ packageWithName:name_]];
2840 [self reloadButtons];
2845 /* Package Table {{{ */
2846 @interface PackageTable : RVPage {
2847 _transient Database *database_;
2851 NSMutableArray *packages_;
2852 NSMutableArray *sections_;
2853 UISectionList *list_;
2856 - (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object;
2858 - (void) setDelegate:(id)delegate;
2859 - (void) reloadData;
2863 @implementation PackageTable
2866 [list_ setDataSource:nil];
2871 [packages_ release];
2872 [sections_ release];
2877 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
2878 return [sections_ count];
2881 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
2882 return [[sections_ objectAtIndex:section] name];
2885 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
2886 return [[sections_ objectAtIndex:section] row];
2889 - (int) numberOfRowsInTable:(UITable *)table {
2890 return [packages_ count];
2893 - (float) table:(UITable *)table heightForRow:(int)row {
2897 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2899 reusing = [[[PackageCell alloc] init] autorelease];
2900 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
2904 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
2908 - (void) tableRowSelected:(NSNotification *)notification {
2909 int row = [[notification object] selectedRow];
2913 Package *package = [packages_ objectAtIndex:row];
2914 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
2915 [view setDelegate:delegate_];
2916 [view setPackage:package];
2917 [book_ pushPage:view];
2920 - (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object {
2921 if ((self = [super initWithBook:book]) != nil) {
2922 database_ = database;
2923 title_ = [title retain];
2925 object_ = object == nil ? nil : [object retain];
2927 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
2928 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
2930 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:YES];
2931 [list_ setDataSource:self];
2933 UITableColumn *column = [[[UITableColumn alloc]
2934 initWithTitle:@"Name"
2936 width:[self frame].size.width
2939 UITable *table = [list_ table];
2940 [table setSeparatorStyle:1];
2941 [table addTableColumn:column];
2942 [table setDelegate:self];
2943 [table setReusesTableCells:YES];
2945 [self addSubview:list_];
2950 - (void) setDelegate:(id)delegate {
2951 delegate_ = delegate;
2954 - (void) reloadData {
2955 NSArray *packages = [database_ packages];
2957 [packages_ removeAllObjects];
2958 [sections_ removeAllObjects];
2960 for (size_t i(0); i != [packages count]; ++i) {
2961 Package *package([packages objectAtIndex:i]);
2962 if ([[package performSelector:filter_ withObject:object_] boolValue])
2963 [packages_ addObject:package];
2966 [packages_ sortUsingSelector:@selector(compareByName:)];
2968 Section *section = nil;
2970 for (size_t offset(0); offset != [packages_ count]; ++offset) {
2971 Package *package = [packages_ objectAtIndex:offset];
2972 NSString *name = [package index];
2974 if (section == nil || ![[section name] isEqualToString:name]) {
2975 section = [[[Section alloc] initWithName:name row:offset] autorelease];
2976 [sections_ addObject:section];
2979 [section addToCount];
2985 - (NSString *) title {
2989 - (void) resetViewAnimated:(BOOL)animated {
2990 [list_ resetViewAnimated:animated];
2996 /* Browser Implementation {{{ */
2997 @implementation BrowserView
3000 WebView *webview = [webview_ webView];
3001 [webview setFrameLoadDelegate:nil];
3002 [webview setResourceLoadDelegate:nil];
3003 [webview setUIDelegate:nil];
3005 [scroller_ setDelegate:nil];
3006 [webview_ setDelegate:nil];
3008 [scroller_ release];
3011 [indicator_ release];
3017 - (void) loadURL:(NSURL *)url cachePolicy:(NSURLRequestCachePolicy)policy {
3018 NSMutableURLRequest *request = [NSMutableURLRequest
3021 timeoutInterval:30.0
3024 [request addValue:[NSString stringWithCString:Firmware_] forHTTPHeaderField:@"X-Firmware"];
3025 [request addValue:[NSString stringWithCString:Machine_] forHTTPHeaderField:@"X-Machine"];
3026 [request addValue:[NSString stringWithCString:SerialNumber_] forHTTPHeaderField:@"X-Serial-Number"];
3028 [self loadRequest:request];
3032 - (void) loadURL:(NSURL *)url {
3033 [self loadURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy];
3036 // XXX: this needs to add the headers
3037 - (NSURLRequest *) _addHeadersToRequest:(NSURLRequest *)request {
3041 - (void) loadRequest:(NSURLRequest *)request {
3042 [webview_ loadRequest:request];
3045 - (void) reloadURL {
3046 NSURL *url = [[[urls_ lastObject] retain] autorelease];
3047 [urls_ removeLastObject];
3048 [self loadURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData];
3051 - (WebView *) webView {
3052 return [webview_ webView];
3055 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame {
3056 [scroller_ setContentSize:frame.size];
3059 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old {
3060 [self view:sender didSetFrame:frame];
3063 - (NSURLRequest *) webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource {
3064 return [self _addHeadersToRequest:request];
3067 - (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request {
3068 [self setBackButtonTitle:title_];
3069 BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease];
3070 [browser setDelegate:delegate_];
3071 [book_ pushPage:browser];
3072 [browser loadRequest:[self _addHeadersToRequest:request]];
3073 return [browser webView];
3076 - (void) webView:(WebView *)sender willClickElement:(id)element {
3077 if (![element respondsToSelector:@selector(href)])
3079 NSString *href = [element href];
3082 if ([href hasPrefix:@"apptapp://package/"]) {
3083 NSString *name = [href substringFromIndex:18];
3084 Package *package = [database_ packageWithName:name];
3085 if (package == nil) {
3086 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
3087 initWithTitle:@"Cannot Locate Package"
3088 buttons:[NSArray arrayWithObjects:@"Close", nil]
3089 defaultButtonIndex:0
3094 [sheet setBodyText:[NSString stringWithFormat:
3095 @"The package %@ cannot be found in your current sources. I might recommend intalling more sources."
3098 [sheet popupAlertAnimated:YES];
3100 [self setBackButtonTitle:title_];
3101 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
3102 [view setDelegate:delegate_];
3103 [view setPackage:package];
3104 [book_ pushPage:view];
3109 - (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame {
3110 title_ = [title retain];
3111 [self setTitle:title];
3114 - (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame {
3115 if ([frame parentFrame] != nil)
3119 [indicator_ startAnimation];
3120 [self reloadButtons];
3122 if (title_ != nil) {
3127 [self setTitle:@"Loading..."];
3129 WebView *webview = [webview_ webView];
3130 NSString *href = [webview mainFrameURL];
3131 [urls_ addObject:[NSURL URLWithString:href]];
3133 CGRect webrect = [scroller_ frame];
3134 webrect.size.height = 0;
3135 [webview_ setFrame:webrect];
3138 - (void) _finishLoading {
3140 [indicator_ stopAnimation];
3141 [self reloadButtons];
3144 - (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
3145 if ([frame parentFrame] != nil)
3147 [self _finishLoading];
3150 - (void) webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
3151 if ([frame parentFrame] != nil)
3153 [self setTitle:[error localizedDescription]];
3154 [self _finishLoading];
3157 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3158 if ((self = [super initWithBook:book]) != nil) {
3159 database_ = database;
3162 struct CGRect bounds = [self bounds];
3164 UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:bounds] autorelease];
3165 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
3166 [self addSubview:pinstripe];
3168 scroller_ = [[UIScroller alloc] initWithFrame:bounds];
3169 [self addSubview:scroller_];
3171 [scroller_ setScrollingEnabled:YES];
3172 [scroller_ setAdjustForContentSizeChange:YES];
3173 [scroller_ setClipsSubviews:YES];
3174 [scroller_ setAllowsRubberBanding:YES];
3175 [scroller_ setScrollDecelerationFactor:0.99];
3176 [scroller_ setDelegate:self];
3178 CGRect webrect = [scroller_ bounds];
3179 webrect.size.height = 0;
3181 webview_ = [[UIWebView alloc] initWithFrame:webrect];
3182 [scroller_ addSubview:webview_];
3184 [webview_ setTilingEnabled:YES];
3185 [webview_ setTileSize:CGSizeMake(webrect.size.width, 500)];
3186 [webview_ setAutoresizes:YES];
3187 [webview_ setDelegate:self];
3188 //[webview_ setEnabledGestures:2];
3190 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:0];
3191 indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(281, 43, indsize.width, indsize.height)];
3192 [indicator_ setStyle:0];
3194 Package *package([database_ packageWithName:@"cydia"]);
3195 NSString *application = package == nil ? @"Cydia" : [NSString
3196 stringWithFormat:@"Cydia/%@",
3200 WebView *webview = [webview_ webView];
3201 [webview setApplicationNameForUserAgent:application];
3202 [webview setFrameLoadDelegate:self];
3203 [webview setResourceLoadDelegate:self];
3204 [webview setUIDelegate:self];
3206 urls_ = [[NSMutableArray alloc] initWithCapacity:16];
3210 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
3214 - (void) _leftButtonClicked {
3215 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
3216 initWithTitle:@"About Cydia Packager"
3217 buttons:[NSArray arrayWithObjects:@"Close", nil]
3218 defaultButtonIndex:0
3224 @"Copyright (C) 2008\n"
3225 "Jay Freeman (saurik)\n"
3226 "saurik@saurik.com\n"
3227 "http://www.saurik.com/\n"
3230 "http://www.theokorigroup.com/\n"
3232 "College of Creative Studies,\n"
3233 "University of California,\n"
3235 "http://www.ccs.ucsb.edu/"
3238 [sheet popupAlertAnimated:YES];
3241 - (void) _rightButtonClicked {
3245 - (NSString *) leftButtonTitle {
3249 - (NSString *) rightButtonTitle {
3250 return loading_ ? @"" : @"Reload";
3253 - (NSString *) title {
3257 - (NSString *) backButtonTitle {
3261 - (void) setPageActive:(BOOL)active {
3263 [book_ addSubview:indicator_];
3265 [indicator_ removeFromSuperview];
3268 - (void) resetViewAnimated:(BOOL)animated {
3274 /* Install View {{{ */
3275 @interface InstallView : RVPage {
3276 _transient Database *database_;
3277 NSMutableArray *packages_;
3278 NSMutableArray *sections_;
3282 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3283 - (void) reloadData;
3287 @implementation InstallView
3290 [list_ setDataSource:nil];
3291 [list_ setDelegate:nil];
3293 [packages_ release];
3294 [sections_ release];
3299 - (int) numberOfRowsInTable:(UITable *)table {
3300 return [sections_ count] + 1;
3303 - (float) table:(UITable *)table heightForRow:(int)row {
3307 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
3309 reusing = [[[SectionCell alloc] init] autorelease];
3310 [(SectionCell *)reusing setSection:(row == 0 ? nil : [sections_ objectAtIndex:(row - 1)])];
3314 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
3318 - (void) tableRowSelected:(NSNotification *)notification {
3319 int row = [[notification object] selectedRow];
3328 title = @"All Packages";
3330 section = [sections_ objectAtIndex:(row - 1)];
3331 title = [section name];
3334 PackageTable *table = [[[PackageTable alloc]
3338 filter:@selector(isUninstalledInSection:)
3339 with:(section == nil ? nil : [section name])
3342 [table setDelegate:delegate_];
3344 [book_ pushPage:table];
3347 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3348 if ((self = [super initWithBook:book]) != nil) {
3349 database_ = database;
3351 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
3352 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
3354 list_ = [[UITable alloc] initWithFrame:[self bounds]];
3355 [self addSubview:list_];
3357 UITableColumn *column = [[[UITableColumn alloc]
3358 initWithTitle:@"Name"
3360 width:[self frame].size.width
3363 [list_ setDataSource:self];
3364 [list_ setSeparatorStyle:1];
3365 [list_ addTableColumn:column];
3366 [list_ setDelegate:self];
3367 [list_ setReusesTableCells:YES];
3373 - (void) reloadData {
3374 NSArray *packages = [database_ packages];
3376 [packages_ removeAllObjects];
3377 [sections_ removeAllObjects];
3379 for (size_t i(0); i != [packages count]; ++i) {
3380 Package *package([packages objectAtIndex:i]);
3381 if ([package installed] == nil)
3382 [packages_ addObject:package];
3385 [packages_ sortUsingSelector:@selector(compareBySection:)];
3387 Section *section = nil;
3388 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
3389 Package *package = [packages_ objectAtIndex:offset];
3390 NSString *name = [package section];
3392 if (section == nil || name != nil && ![[section name] isEqualToString:name]) {
3393 section = [[[Section alloc] initWithName:name row:offset] autorelease];
3394 [sections_ addObject:section];
3397 [section addToCount];
3403 - (void) resetViewAnimated:(BOOL)animated {
3404 [list_ resetViewAnimated:animated];
3407 - (NSString *) title {
3411 - (NSString *) backButtonTitle {
3417 /* Changes View {{{ */
3418 @interface ChangesView : RVPage {
3419 _transient Database *database_;
3420 NSMutableArray *packages_;
3421 NSMutableArray *sections_;
3422 UISectionList *list_;
3426 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3427 - (void) reloadData;
3431 @implementation ChangesView
3434 [[list_ table] setDelegate:nil];
3435 [list_ setDataSource:nil];
3437 [packages_ release];
3438 [sections_ release];
3443 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
3444 return [sections_ count];
3447 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
3448 return [[sections_ objectAtIndex:section] name];
3451 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
3452 return [[sections_ objectAtIndex:section] row];
3455 - (int) numberOfRowsInTable:(UITable *)table {
3456 return [packages_ count];
3459 - (float) table:(UITable *)table heightForRow:(int)row {
3463 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
3465 reusing = [[[PackageCell alloc] init] autorelease];
3466 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
3470 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
3474 - (void) tableRowSelected:(NSNotification *)notification {
3475 int row = [[notification object] selectedRow];
3478 Package *package = [packages_ objectAtIndex:row];
3479 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
3480 [view setDelegate:delegate_];
3481 [view setPackage:package];
3482 [book_ pushPage:view];
3485 - (void) _rightButtonClicked {
3486 [delegate_ distUpgrade];
3489 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3490 if ((self = [super initWithBook:book]) != nil) {
3491 database_ = database;
3493 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
3494 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
3496 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:NO];
3497 [self addSubview:list_];
3499 [list_ setShouldHideHeaderInShortLists:NO];
3500 [list_ setDataSource:self];
3501 //[list_ setSectionListStyle:1];
3503 UITableColumn *column = [[[UITableColumn alloc]
3504 initWithTitle:@"Name"
3506 width:[self frame].size.width
3509 UITable *table = [list_ table];
3510 [table setSeparatorStyle:1];
3511 [table addTableColumn:column];
3512 [table setDelegate:self];
3513 [table setReusesTableCells:YES];
3519 - (void) reloadData {
3520 NSArray *packages = [database_ packages];
3522 [packages_ removeAllObjects];
3523 [sections_ removeAllObjects];
3525 for (size_t i(0); i != [packages count]; ++i) {
3526 Package *package([packages objectAtIndex:i]);
3527 if ([package installed] == nil || [package upgradable])
3528 [packages_ addObject:package];
3531 [packages_ sortUsingSelector:@selector(compareForChanges:)];
3533 Section *upgradable = [[[Section alloc] initWithName:@"Available Upgrades" row:0] autorelease];
3534 Section *section = nil;
3537 bool unseens = false;
3539 CFLocaleRef locale = CFLocaleCopyCurrent();
3540 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
3542 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
3543 Package *package = [packages_ objectAtIndex:offset];
3545 if ([package upgradable]) {
3547 [upgradable addToCount];
3550 NSDate *seen = [package seen];
3555 name = [@"n/a ?" retain];
3557 name = (NSString *) CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen);
3560 if (section == nil || ![[section name] isEqualToString:name]) {
3561 section = [[[Section alloc] initWithName:name row:offset] autorelease];
3562 [sections_ addObject:section];
3566 [section addToCount];
3570 CFRelease(formatter);
3574 Section *last = [sections_ lastObject];
3575 size_t count = [last count];
3576 [packages_ removeObjectsInRange:NSMakeRange([packages_ count] - count, count)];
3577 [sections_ removeLastObject];
3581 [sections_ insertObject:upgradable atIndex:0];
3584 [self reloadButtons];
3587 - (void) resetViewAnimated:(BOOL)animated {
3588 [list_ resetViewAnimated:animated];
3591 - (NSString *) rightButtonTitle {
3592 return upgrades_ == 0 ? nil : [NSString stringWithFormat:@"Upgrade All (%u)", upgrades_];
3595 - (NSString *) title {
3601 /* Search View {{{ */
3602 @protocol SearchViewDelegate
3603 - (void) showKeyboard:(BOOL)show;
3606 @interface SearchView : PackageTable {
3608 UISearchField *field_;
3611 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3612 - (void) reloadData;
3616 @implementation SearchView
3620 [[field_ textTraits] setEditingDelegate:nil];
3622 [field_ setDelegate:nil];
3624 [accessory_ release];
3629 - (void) textFieldDidBecomeFirstResponder:(UITextField *)field {
3630 [delegate_ showKeyboard:YES];
3631 [list_ setEnabled:NO];
3633 /*CGColor dimmed(alpha, 0, 0, 0, 0.5);
3634 [editor_ setBackgroundColor:dimmed];*/
3637 - (void) textFieldDidResignFirstResponder:(UITextField *)field {
3638 [list_ setEnabled:YES];
3639 [delegate_ showKeyboard:NO];
3642 - (void) keyboardInputChanged:(UIFieldEditor *)editor {
3643 NSString *text([field_ text]);
3644 [field_ setClearButtonStyle:(text == nil || [text length] == 0 ? 0 : 2)];
3647 - (BOOL) keyboardInput:(id)input shouldInsertText:(NSString *)text isMarkedText:(int)marked {
3648 if ([text length] != 1 || [text characterAtIndex:0] != '\n')
3652 [field_ resignFirstResponder];
3656 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3661 filter:@selector(isSearchedForBy:)
3664 CGRect cnfrect = {{0, 36}, {17, 18}};
3667 area.origin.x = cnfrect.size.width + 6;
3669 area.size.width = [self bounds].size.width - area.origin.x - 12;
3670 area.size.height = [UISearchField defaultHeight];
3672 field_ = [[UISearchField alloc] initWithFrame:area];
3674 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
3675 [field_ setFont:font];
3678 [field_ setPlaceholder:@"Package Names & Descriptions"];
3679 [field_ setPaddingTop:5];
3680 [field_ setDelegate:self];
3683 UITextTraits *traits = [field_ textTraits];
3684 [traits setEditingDelegate:self];
3685 [traits setReturnKeyType:6];
3686 [traits setAutoCapsType:0];
3687 [traits setAutoCorrectionType:1];
3690 UIPushButton *configure = [[[UIPushButton alloc] initWithFrame:cnfrect] autorelease];
3691 [configure setShowPressFeedback:YES];
3692 [configure setImage:[UIImage applicationImageNamed:@"configure.png"]];
3693 [configure addTarget:self action:@selector(configurePushed) forEvents:1];
3695 accessory_ = [[UIView alloc] initWithFrame:CGRectMake(0, 6, cnfrect.size.width + area.size.width + 6 * 3, area.size.height + 30)];
3696 [accessory_ addSubview:field_];
3697 [accessory_ addSubview:configure];
3701 - (void) configurePushed {
3702 // XXX: implement flippy advanced panel
3705 - (void) reloadData {
3706 object_ = [[field_ text] retain];
3708 [[list_ table] scrollPointVisibleAtTopLeft:CGPointMake(0, 0) animated:NO];
3711 - (UIView *) accessoryView {
3715 - (NSString *) backButtonTitle {
3722 @interface CYBook : RVBook <
3725 _transient Database *database_;
3727 UIProgressIndicator *indicator_;
3728 UITextLabel *prompt_;
3729 UIProgressBar *progress_;
3732 - (id) initWithFrame:(CGRect)frame database:(Database *)database;
3737 @implementation CYBook
3741 [indicator_ release];
3743 [progress_ release];
3748 [navbar_ addSubview:overlay_];
3749 [indicator_ startAnimation];
3750 [prompt_ setText:@"Updating Database..."];
3751 [progress_ setProgress:0];
3754 detachNewThreadSelector:@selector(_update)
3761 [overlay_ removeFromSuperview];
3762 [indicator_ stopAnimation];
3763 [delegate_ reloadData];
3765 [self setPrompt:[NSString stringWithFormat:@"Last Updated: %@", GetLastUpdate()]];
3768 - (id) initWithFrame:(CGRect)frame database:(Database *)database {
3769 if ((self = [super initWithFrame:frame]) != nil) {
3770 database_ = database;
3772 CGRect ovrrect = [navbar_ bounds];
3773 ovrrect.size.height = [UINavigationBar defaultSizeWithPrompt].height - [UINavigationBar defaultSize].height;
3775 overlay_ = [[UIView alloc] initWithFrame:ovrrect];
3777 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:2];
3778 unsigned indoffset = (ovrrect.size.height - indsize.height) / 2;
3779 CGRect indrect = {{indoffset, indoffset}, indsize};
3781 indicator_ = [[UIProgressIndicator alloc] initWithFrame:indrect];
3782 [indicator_ setStyle:2];
3783 [overlay_ addSubview:indicator_];
3785 CGSize prmsize = {200, indsize.width};
3788 indoffset * 2 + indsize.width,
3789 (ovrrect.size.height - prmsize.height) / 2
3792 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 12);
3794 prompt_ = [[UITextLabel alloc] initWithFrame:prmrect];
3796 [prompt_ setColor:White_];
3797 [prompt_ setBackgroundColor:Clear_];
3798 [prompt_ setFont:font];
3802 [overlay_ addSubview:prompt_];
3804 CGSize prgsize = {75, 100};
3807 ovrrect.size.width - prgsize.width - 10,
3808 (ovrrect.size.height - prgsize.height) / 2
3811 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
3812 [progress_ setStyle:0];
3813 [overlay_ addSubview:progress_];
3818 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
3821 status.setDelegate(self);
3823 [database_ updateWithStatus:status];
3826 performSelectorOnMainThread:@selector(_update_)
3834 - (void) setProgressError:(NSString *)error {
3836 performSelectorOnMainThread:@selector(_setProgressError:)
3842 - (void) setProgressTitle:(NSString *)title {
3844 performSelectorOnMainThread:@selector(_setProgressTitle:)
3850 - (void) setProgressPercent:(float)percent {
3853 - (void) addProgressOutput:(NSString *)output {
3855 performSelectorOnMainThread:@selector(_addProgressOutput:)
3861 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
3865 - (void) _setProgressError:(NSString *)error {
3866 [prompt_ setText:[NSString stringWithFormat:@"Error: %@", error]];
3869 - (void) _setProgressTitle:(NSString *)title {
3870 [prompt_ setText:[title stringByAppendingString:@"..."]];
3873 - (void) _addProgressOutput:(NSString *)output {
3878 @interface Cydia : UIApplication <
3879 ConfirmationViewDelegate,
3880 ProgressViewDelegate,
3889 UIButtonBar *buttonbar_;
3891 ConfirmationView *confirm_;
3893 Database *database_;
3894 ProgressView *progress_;
3898 UIKeyboard *keyboard_;
3903 @implementation Cydia
3905 - (void) _reloadData {
3906 /*UIProgressHUD *hud = [[UIProgressHUD alloc] initWithWindow:window_];
3907 [hud setText:@"Reloading Data"];
3908 [overlay_ addSubview:hud];
3911 [database_ reloadData];
3915 if (Packages_ == nil) {
3916 Packages_ = [[NSMutableDictionary alloc] initWithCapacity:count];
3917 [Metadata_ setObject:Packages_ forKey:@"Packages"];
3922 NSArray *packages = [database_ packages];
3923 for (int i(0), e([packages count]); i != e; ++i) {
3924 Package *package = [packages objectAtIndex:i];
3925 if ([package upgradable])
3930 NSString *badge([[NSNumber numberWithInt:changes] stringValue]);
3931 [buttonbar_ setBadgeValue:badge forButton:3];
3932 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
3933 [buttonbar_ setBadgeAnimated:YES forButton:3];
3934 [self setApplicationBadge:badge];
3936 [buttonbar_ setBadgeValue:nil forButton:3];
3937 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
3938 [buttonbar_ setBadgeAnimated:NO forButton:3];
3939 [self removeApplicationBadge];
3942 _assert([Metadata_ writeToFile:@"/var/lib/cydia/metadata.plist" atomically:YES] == YES);
3946 [hud removeFromSuperview];*/
3949 - (void) reloadData {
3950 @synchronized (self) {
3951 if (confirm_ == nil)
3957 pkgProblemResolver *resolver = [database_ resolver];
3959 resolver->InstallProtect();
3960 if (!resolver->Resolve(true))
3965 [database_ prepare];
3967 if ([database_ cache]->BrokenCount() == 0)
3968 confirm_ = [[ConfirmationView alloc] initWithView:underlay_ database:database_ delegate:self];
3970 NSMutableArray *broken = [NSMutableArray arrayWithCapacity:16];
3971 NSArray *packages = [database_ packages];
3973 for (size_t i(0); i != [packages count]; ++i) {
3974 Package *package = [packages objectAtIndex:i];
3975 if ([package broken])
3976 [broken addObject:[package name]];
3979 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
3980 initWithTitle:[NSString stringWithFormat:@"%d Broken Packages", [database_ cache]->BrokenCount()]
3981 buttons:[NSArray arrayWithObjects:@"Okay", nil]
3982 defaultButtonIndex:0
3987 [sheet setBodyText:[NSString stringWithFormat:@"The following packages have unmet dependencies:\n\n%@", [broken componentsJoinedByString:@"\n"]]];
3988 [sheet popupAlertAnimated:YES];
3994 - (void) installPackage:(Package *)package {
3995 @synchronized (self) {
4002 - (void) removePackage:(Package *)package {
4003 @synchronized (self) {
4010 - (void) distUpgrade {
4011 @synchronized (self) {
4012 [database_ upgrade];
4018 @synchronized (self) {
4026 [overlay_ removeFromSuperview];
4030 detachNewThreadSelector:@selector(perform)
4037 - (void) bootstrap_ {
4039 [database_ upgrade];
4040 [database_ prepare];
4041 [database_ perform];
4044 - (void) bootstrap {
4046 detachNewThreadSelector:@selector(bootstrap_)
4049 title:@"Bootstrap Install..."
4053 - (void) progressViewIsComplete:(ProgressView *)progress {
4054 @synchronized (self) {
4057 if (confirm_ != nil) {
4058 [underlay_ addSubview:overlay_];
4059 [confirm_ removeFromSuperview];
4066 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
4070 - (void) setPage:(RVPage *)page {
4071 [page setDelegate:self];
4072 [book_ setPage:page];
4075 - (RVPage *) _setNewsPage {
4076 BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease];
4077 [self setPage:browser];
4078 [browser loadURL:[NSURL URLWithString:@"http://cydia.saurik.com/"]];
4082 - (void) buttonBarItemTapped:(id)sender {
4083 unsigned tag = [sender tag];
4087 [self _setNewsPage];
4091 [self setPage:[[[InstallView alloc] initWithBook:book_ database:database_] autorelease]];
4095 [self setPage:[[[ChangesView alloc] initWithBook:book_ database:database_] autorelease]];
4099 [self setPage:[[[PackageTable alloc]
4103 filter:@selector(isInstalledInSection:)
4109 [self setPage:[[[SearchView alloc] initWithBook:book_ database:database_] autorelease]];
4119 - (void) applicationWillSuspend {
4120 [super applicationWillSuspend];
4123 if (FW_LEAST(1,1,3))
4124 notify_post("com.apple.language.changed");
4126 system("launchctl stop com.apple.SpringBoard");
4129 - (void) applicationDidFinishLaunching:(id)unused {
4130 _assert(pkgInitConfig(*_config));
4131 _assert(pkgInitSystem(*_config, _system));
4136 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
4137 window_ = [[UIWindow alloc] initWithContentRect:screenrect];
4139 [window_ orderFront: self];
4140 [window_ makeKey: self];
4141 [window_ _setHidden: NO];
4143 progress_ = [[ProgressView alloc] initWithFrame:[window_ bounds] delegate:self];
4144 [window_ setContentView:progress_];
4146 underlay_ = [[UIView alloc] initWithFrame:[progress_ bounds]];
4147 [progress_ setContentView:underlay_];
4149 overlay_ = [[UIView alloc] initWithFrame:[underlay_ bounds]];
4152 [underlay_ addSubview:overlay_];
4154 database_ = [[Database alloc] init];
4155 [database_ setDelegate:progress_];
4157 book_ = [[CYBook alloc] initWithFrame:CGRectMake(
4158 0, 0, screenrect.size.width, screenrect.size.height - 48
4159 ) database:database_];
4161 [book_ setDelegate:self];
4163 [overlay_ addSubview:book_];
4165 NSArray *buttonitems = [NSArray arrayWithObjects:
4166 [NSDictionary dictionaryWithObjectsAndKeys:
4167 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
4168 @"news-up.png", kUIButtonBarButtonInfo,
4169 @"news-dn.png", kUIButtonBarButtonSelectedInfo,
4170 [NSNumber numberWithInt:1], kUIButtonBarButtonTag,
4171 self, kUIButtonBarButtonTarget,
4172 @"News", kUIButtonBarButtonTitle,
4173 @"0", kUIButtonBarButtonType,
4176 [NSDictionary dictionaryWithObjectsAndKeys:
4177 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
4178 @"install-up.png", kUIButtonBarButtonInfo,
4179 @"install-dn.png", kUIButtonBarButtonSelectedInfo,
4180 [NSNumber numberWithInt:2], kUIButtonBarButtonTag,
4181 self, kUIButtonBarButtonTarget,
4182 @"Install", kUIButtonBarButtonTitle,
4183 @"0", kUIButtonBarButtonType,
4186 [NSDictionary dictionaryWithObjectsAndKeys:
4187 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
4188 @"changes-up.png", kUIButtonBarButtonInfo,
4189 @"changes-dn.png", kUIButtonBarButtonSelectedInfo,
4190 [NSNumber numberWithInt:3], kUIButtonBarButtonTag,
4191 self, kUIButtonBarButtonTarget,
4192 @"Changes", kUIButtonBarButtonTitle,
4193 @"0", kUIButtonBarButtonType,
4196 [NSDictionary dictionaryWithObjectsAndKeys:
4197 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
4198 @"manage-up.png", kUIButtonBarButtonInfo,
4199 @"manage-dn.png", kUIButtonBarButtonSelectedInfo,
4200 [NSNumber numberWithInt:4], kUIButtonBarButtonTag,
4201 self, kUIButtonBarButtonTarget,
4202 @"Manage", kUIButtonBarButtonTitle,
4203 @"0", kUIButtonBarButtonType,
4206 [NSDictionary dictionaryWithObjectsAndKeys:
4207 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
4208 @"search-up.png", kUIButtonBarButtonInfo,
4209 @"search-dn.png", kUIButtonBarButtonSelectedInfo,
4210 [NSNumber numberWithInt:5], kUIButtonBarButtonTag,
4211 self, kUIButtonBarButtonTarget,
4212 @"Search", kUIButtonBarButtonTitle,
4213 @"0", kUIButtonBarButtonType,
4217 buttonbar_ = [[UIButtonBar alloc]
4219 withFrame:CGRectMake(
4220 0, screenrect.size.height - 48,
4221 screenrect.size.width, 48
4223 withItemList:buttonitems
4226 [buttonbar_ setDelegate:self];
4227 [buttonbar_ setBarStyle:1];
4228 [buttonbar_ setButtonBarTrackingMode:2];
4230 int buttons[5] = {1, 2, 3, 4, 5};
4231 [buttonbar_ registerButtonGroup:0 withButtons:buttons withCount:5];
4232 [buttonbar_ showButtonGroup:0 withDuration:0];
4234 for (int i = 0; i != 5; ++i)
4235 [[buttonbar_ viewWithTag:(i + 1)] setFrame:CGRectMake(
4236 i * 64 + 2, 1, 60, 48
4239 [buttonbar_ showSelectionForButton:1];
4240 [overlay_ addSubview:buttonbar_];
4242 [UIKeyboard initImplementationNow];
4243 CGSize keysize = [UIKeyboard defaultSize];
4244 CGRect keyrect = {{0, [overlay_ bounds].size.height - keysize.height}, keysize};
4245 keyboard_ = [[UIKeyboard alloc] initWithFrame:keyrect];
4250 [progress_ resetView];
4255 [self _setNewsPage];
4258 - (void) showKeyboard:(BOOL)show {
4260 [overlay_ addSubview:keyboard_];
4262 [keyboard_ removeFromSuperview];
4265 - (void) slideUp:(UIAlertSheet *)alert {
4266 [alert presentSheetFromButtonBar:buttonbar_];
4271 void AddPreferences(NSString *plist) {
4272 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
4274 NSMutableDictionary *settings = [[[NSMutableDictionary alloc] initWithContentsOfFile:plist] autorelease];
4275 _assert(settings != NULL);
4276 NSMutableArray *items = [settings objectForKey:@"items"];
4280 for (size_t i(0); i != [items count]; ++i) {
4281 NSMutableDictionary *item([items objectAtIndex:i]);
4282 NSString *label = [item objectForKey:@"label"];
4283 if (label != nil && [label isEqualToString:@"Cydia"]) {
4290 for (size_t i(0); i != [items count]; ++i) {
4291 NSDictionary *item([items objectAtIndex:i]);
4292 NSString *label = [item objectForKey:@"label"];
4293 if (label != nil && [label isEqualToString:@"General"]) {
4294 [items insertObject:[NSDictionary dictionaryWithObjectsAndKeys:
4295 @"CydiaSettings", @"bundle",
4296 @"PSLinkCell", @"cell",
4297 [NSNumber numberWithBool:YES], @"hasIcon",
4298 [NSNumber numberWithBool:YES], @"isController",
4300 nil] atIndex:(i + 1)];
4306 _assert([settings writeToFile:plist atomically:YES] == YES);
4313 id Alloc_(id self, SEL selector) {
4314 id object = alloc_(self, selector);
4315 fprintf(stderr, "[%s]A-%p\n", self->isa->name, object);
4320 id Dealloc_(id self, SEL selector) {
4321 id object = dealloc_(self, selector);
4322 fprintf(stderr, "[%s]D-%p\n", self->isa->name, object);
4326 int main(int argc, char *argv[]) {
4327 bootstrap_ = argc > 1 && strcmp(argv[1], "--bootstrap") == 0;
4332 /*Method alloc = class_getClassMethod([NSObject class], @selector(alloc));
4333 alloc_ = alloc->method_imp;
4334 alloc->method_imp = (IMP) &Alloc_;*/
4336 /*Method dealloc = class_getClassMethod([NSObject class], @selector(dealloc));
4337 dealloc_ = dealloc->method_imp;
4338 dealloc->method_imp = (IMP) &Dealloc_;*/
4340 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
4342 if (NSDictionary *sysver = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]) {
4343 if (NSString *prover = [sysver valueForKey:@"ProductVersion"]) {
4344 Firmware_ = strdup([prover UTF8String]);
4345 NSArray *versions = [prover componentsSeparatedByString:@"."];
4346 int count = [versions count];
4347 Major_ = count > 0 ? [[versions objectAtIndex:0] intValue] : 0;
4348 Minor_ = count > 1 ? [[versions objectAtIndex:1] intValue] : 0;
4349 BugFix_ = count > 2 ? [[versions objectAtIndex:2] intValue] : 0;
4354 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
4355 char *machine = new char[size];
4356 sysctlbyname("hw.machine", machine, &size, NULL, 0);
4359 if (CFMutableDictionaryRef dict = IOServiceMatching("IOPlatformExpertDevice"))
4360 if (io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, dict)) {
4361 if (CFTypeRef serial = IORegistryEntryCreateCFProperty(service, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0)) {
4362 SerialNumber_ = strdup(CFStringGetCStringPtr((CFStringRef) serial, CFStringGetSystemEncoding()));
4366 IOObjectRelease(service);
4369 /*AddPreferences(@"/Applications/Preferences.app/Settings-iPhone.plist");
4370 AddPreferences(@"/Applications/Preferences.app/Settings-iPod.plist");*/
4372 if ((Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"]) == NULL)
4373 Metadata_ = [[NSMutableDictionary alloc] initWithCapacity:2];
4375 Packages_ = [Metadata_ objectForKey:@"Packages"];
4377 setenv("CYDIA", "", _not(int));
4378 if (access("/User", F_OK) != 0)
4379 system("/usr/libexec/cydia/firmware.sh");
4380 system("dpkg --configure -a");
4382 space_ = CGColorSpaceCreateDeviceRGB();
4384 Black_.Set(space_, 0.0, 0.0, 0.0, 1.0);
4385 Clear_.Set(space_, 0.0, 0.0, 0.0, 0.0);
4386 Red_.Set(space_, 1.0, 0.0, 0.0, 1.0);
4387 White_.Set(space_, 1.0, 1.0, 1.0, 1.0);
4389 int value = UIApplicationMain(argc, argv, [Cydia class]);
4391 CGColorSpaceRelease(space_);