1 /* Cydia - iPhone UIKit Front-End for Debian APT
2 * Copyright (C) 2008 Jay Freeman (saurik)
6 * Redistribution and use in source and binary
7 * forms, with or without modification, are permitted
8 * provided that the following conditions are met:
10 * 1. Redistributions of source code must retain the
11 * above copyright notice, this list of conditions
12 * and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the
14 * above copyright notice, this list of conditions
15 * and the following disclaimer in the documentation
16 * and/or other materials provided with the
18 * 3. The name of the author may not be used to endorse
19 * or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS''
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
24 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
33 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
35 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 /* #include Directives {{{ */
39 #include <objc/objc.h>
40 #include <objc/runtime.h>
42 #include <CoreGraphics/CoreGraphics.h>
43 #include <GraphicsServices/GraphicsServices.h>
44 #include <Foundation/Foundation.h>
45 #include <UIKit/UIKit.h>
46 #include <WebCore/DOMHTML.h>
48 #import "BrowserView.h"
50 #import "UICaboodle.h"
52 #include <WebKit/WebFrame.h>
53 #include <WebKit/WebView.h>
58 #include <ext/stdio_filebuf.h>
60 #include <apt-pkg/acquire.h>
61 #include <apt-pkg/acquire-item.h>
62 #include <apt-pkg/algorithms.h>
63 #include <apt-pkg/cachefile.h>
64 #include <apt-pkg/configuration.h>
65 #include <apt-pkg/debmetaindex.h>
66 #include <apt-pkg/error.h>
67 #include <apt-pkg/init.h>
68 #include <apt-pkg/pkgrecords.h>
69 #include <apt-pkg/sourcelist.h>
70 #include <apt-pkg/sptr.h>
72 #include <sys/sysctl.h>
76 #include <mach-o/nlist.h>
87 /* Miscellaneous Messages {{{ */
88 @interface NSString (Cydia)
89 - (NSString *) stringByAddingPercentEscapes;
90 - (NSString *) stringByReplacingCharacter:(unsigned short)arg0 withCharacter:(unsigned short)arg1;
93 /* iPhoneOS 2.0 Compatibility {{{ */
95 @interface UICGColor : NSObject {
98 - (id) initWithCGColor:(CGColorRef)color;
104 - (UIFont *) fontWithSize:(CGFloat)size;
107 @interface NSObject (iPhoneOS)
108 - (CGColorRef) cgColor;
109 - (CGColorRef) CGColor;
113 @implementation NSObject (iPhoneOS)
115 - (CGColorRef) cgColor {
116 return [self CGColor];
119 - (CGColorRef) CGColor {
120 return (CGColorRef) self;
124 [[[[objc_getClass("UICGColor") alloc] initWithCGColor:[self CGColor]] autorelease] set];
129 @interface UITextView (iPhoneOS)
130 - (void) setTextSize:(float)size;
133 @implementation UITextView (iPhoneOS)
135 - (void) setTextSize:(float)size {
136 [self setFont:[[self font] fontWithSize:size]];
143 /* Perl-Compatible RegEx {{{ */
153 Pcre(const char *regex) :
158 code_ = pcre_compile(regex, 0, &error, &offset, NULL);
161 fprintf(stderr, "%d:%s\n", offset, error);
165 pcre_fullinfo(code_, study_, PCRE_INFO_CAPTURECOUNT, &capture_);
166 matches_ = new int[(capture_ + 1) * 3];
174 NSString *operator [](size_t match) {
176 stringWithCString:(data_ + matches_[match * 2])
177 length:(matches_[match * 2 + 1] - matches_[match * 2])
181 bool operator ()(const char *data, size_t size) {
183 return pcre_exec(code_, study_, data, size, 0, 0, matches_, (capture_ + 1) * 3) >= 0;
187 /* Mime Addresses {{{ */
188 Pcre email_r("^\"?(.*)\"? <([^>]*)>$");
190 @interface Address : NSObject {
196 - (NSString *) email;
198 + (Address *) addressWithString:(NSString *)string;
199 - (Address *) initWithString:(NSString *)string;
202 @implementation Address
211 - (NSString *) name {
215 - (NSString *) email {
219 + (Address *) addressWithString:(NSString *)string {
220 return [[[Address alloc] initWithString:string] autorelease];
223 - (Address *) initWithString:(NSString *)string {
224 if ((self = [super init]) != nil) {
225 const char *data = [string UTF8String];
226 size_t size = [string length];
228 if (email_r(data, size)) {
229 name_ = [email_r[1] retain];
230 email_ = [email_r[2] retain];
232 name_ = [[NSString stringWithCString:data length:size] retain];
240 /* CoreGraphics Primitives {{{ */
251 CGColor(CGColorSpaceRef space, float red, float green, float blue, float alpha) :
254 Set(space, red, green, blue, alpha);
259 CGColorRelease(color_);
266 void Set(CGColorSpaceRef space, float red, float green, float blue, float alpha) {
268 float color[] = {red, green, blue, alpha};
269 color_ = CGColorCreate(space, color);
272 operator CGColorRef() {
287 /* Right Alignment {{{ */
288 @interface UIRightTextLabel : UITextLabel {
289 float _savedRightEdgeX;
290 BOOL _sizedtofit_flag;
293 - (void) setFrame:(CGRect)frame;
294 - (void) setText:(NSString *)text;
295 - (void) realignText;
298 @implementation UIRightTextLabel
300 - (void) setFrame:(CGRect)frame {
301 [super setFrame:frame];
302 if (_sizedtofit_flag == NO) {
303 _savedRightEdgeX = frame.origin.x;
308 - (void) setText:(NSString *)text {
309 [super setText:text];
313 - (void) realignText {
314 CGRect oldFrame = [self frame];
316 _sizedtofit_flag = YES;
317 [self sizeToFit]; // shrink down size so I can right align it
319 CGRect newFrame = [self frame];
321 oldFrame.origin.x = _savedRightEdgeX - newFrame.size.width;
322 oldFrame.size.width = newFrame.size.width;
323 [super setFrame:oldFrame];
324 _sizedtofit_flag = NO;
330 /* Random Global Variables {{{ */
331 static const int PulseInterval_ = 50000;
333 static CGColor Black_;
334 static CGColor Clear_;
336 static CGColor White_;
338 static NSString *Home_;
339 static BOOL Sounds_Keyboard_;
341 const char *Firmware_ = NULL;
342 const char *Machine_ = NULL;
343 const char *SerialNumber_ = NULL;
349 CGColorSpaceRef space_;
351 #define FW_LEAST(major, minor, bugfix) \
352 (major < Major_ || major == Major_ && \
353 (minor < Minor_ || minor == Minor_ && \
359 static NSMutableDictionary *Metadata_;
360 static NSMutableDictionary *Packages_;
361 static bool Changed_;
364 NSString *GetLastUpdate() {
365 NSDate *update = [Metadata_ objectForKey:@"LastUpdate"];
368 return @"Never or Unknown";
370 CFLocaleRef locale = CFLocaleCopyCurrent();
371 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
372 CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) update);
374 CFRelease(formatter);
377 return [(NSString *) formatted autorelease];
380 /* Display Helpers {{{ */
381 inline float Interpolate(float begin, float end, float fraction) {
382 return (end - begin) * fraction + begin;
385 NSString *SizeString(double size) {
387 while (size > 1024) {
392 static const char *powers_[] = {"B", "kB", "MB", "GB"};
394 return [NSString stringWithFormat:@"%.1f%s", size, powers_[power]];
397 static const float TextViewOffset_ = 22;
399 UITextView *GetTextView(NSString *value, float left, bool html) {
400 UITextView *text([[[UITextView alloc] initWithFrame:CGRectMake(left, 3, 310 - left, 1000)] autorelease]);
401 [text setEditable:NO];
402 [text setTextSize:16];
404 [text setHTML:value];
406 [text setText:value];
407 [text setEnabled:NO];
409 [text setBackgroundColor:Clear_];
411 CGRect frame = [text frame];
412 [text setFrame:frame];
413 CGRect rect = [text visibleTextRect];
414 frame.size.height = rect.size.height;
415 [text setFrame:frame];
420 NSString *Simplify(NSString *title) {
421 const char *data = [title UTF8String];
422 size_t size = [title length];
424 Pcre title_r("^(.*?)( \\(.*\\))?$");
425 if (title_r(data, size))
432 /* Delegate Prototypes {{{ */
436 @protocol ProgressDelegate
437 - (void) setProgressError:(NSString *)error;
438 - (void) setProgressTitle:(NSString *)title;
439 - (void) setProgressPercent:(float)percent;
440 - (void) addProgressOutput:(NSString *)output;
443 @protocol CydiaDelegate
444 - (void) installPackage:(Package *)package;
445 - (void) removePackage:(Package *)package;
446 - (void) slideUp:(UIAlertSheet *)alert;
447 - (void) distUpgrade;
451 /* Status Delegation {{{ */
453 public pkgAcquireStatus
456 _transient id<ProgressDelegate> delegate_;
464 void setDelegate(id delegate) {
465 delegate_ = delegate;
468 virtual bool MediaChange(std::string media, std::string drive) {
472 virtual void IMSHit(pkgAcquire::ItemDesc &item) {
475 virtual void Fetch(pkgAcquire::ItemDesc &item) {
476 [delegate_ setProgressTitle:[NSString stringWithCString:("Downloading " + item.ShortDesc).c_str()]];
479 virtual void Done(pkgAcquire::ItemDesc &item) {
482 virtual void Fail(pkgAcquire::ItemDesc &item) {
484 item.Owner->Status == pkgAcquire::Item::StatIdle ||
485 item.Owner->Status == pkgAcquire::Item::StatDone
489 [delegate_ setProgressError:[NSString stringWithCString:item.Owner->ErrorText.c_str()]];
492 virtual bool Pulse(pkgAcquire *Owner) {
493 bool value = pkgAcquireStatus::Pulse(Owner);
496 double(CurrentBytes + CurrentItems) /
497 double(TotalBytes + TotalItems)
500 [delegate_ setProgressPercent:percent];
504 virtual void Start() {
507 virtual void Stop() {
511 /* Progress Delegation {{{ */
516 _transient id<ProgressDelegate> delegate_;
519 virtual void Update() {
520 [delegate_ setProgressTitle:[NSString stringWithCString:Op.c_str()]];
521 [delegate_ setProgressPercent:(Percent / 100)];
530 void setDelegate(id delegate) {
531 delegate_ = delegate;
534 virtual void Done() {
535 [delegate_ setProgressPercent:1];
540 /* Database Interface {{{ */
541 @interface Database : NSObject {
543 pkgRecords *records_;
544 pkgProblemResolver *resolver_;
545 pkgAcquire *fetcher_;
547 SPtr<pkgPackageManager> manager_;
548 pkgSourceList *list_;
550 NSMutableDictionary *sources_;
551 NSMutableArray *packages_;
553 _transient id delegate_;
559 - (void) _readStatus:(NSNumber *)fd;
560 - (void) _readOutput:(NSNumber *)fd;
562 - (Package *) packageWithName:(NSString *)name;
565 - (pkgCacheFile &) cache;
566 - (pkgRecords *) records;
567 - (pkgProblemResolver *) resolver;
568 - (pkgAcquire &) fetcher;
569 - (NSArray *) packages;
577 - (void) updateWithStatus:(Status &)status;
579 - (void) setDelegate:(id)delegate;
580 - (Source *) getSource:(const pkgCache::PkgFileIterator &)file;
584 /* Source Class {{{ */
585 @interface Source : NSObject {
586 NSString *description_;
591 NSString *distribution_;
595 NSString *defaultIcon_;
600 - (Source *) initWithMetaIndex:(metaIndex *)index;
605 - (NSString *) distribution;
608 - (NSString *) description;
609 - (NSString *) label;
610 - (NSString *) origin;
611 - (NSString *) version;
613 - (NSString *) defaultIcon;
616 @implementation Source
620 [distribution_ release];
623 if (description_ != nil)
624 [description_ release];
631 if (defaultIcon_ != nil)
632 [defaultIcon_ release];
637 - (Source *) initWithMetaIndex:(metaIndex *)index {
638 if ((self = [super init]) != nil) {
639 trusted_ = index->IsTrusted();
641 uri_ = [[NSString stringWithCString:index->GetURI().c_str()] retain];
642 distribution_ = [[NSString stringWithCString:index->GetDist().c_str()] retain];
643 type_ = [[NSString stringWithCString:index->GetType()] retain];
651 debReleaseIndex *dindex(dynamic_cast<debReleaseIndex *>(index));
652 if (dindex != NULL) {
653 std::ifstream release(dindex->MetaIndexFile("Release").c_str());
655 while (std::getline(release, line)) {
656 std::string::size_type colon(line.find(':'));
657 if (colon == std::string::npos)
660 std::string name(line.substr(0, colon));
661 std::string value(line.substr(colon + 1));
662 while (!value.empty() && value[0] == ' ')
663 value = value.substr(1);
665 if (name == "Default-Icon")
666 defaultIcon_ = [[NSString stringWithCString:value.c_str()] retain];
667 else if (name == "Description")
668 description_ = [[NSString stringWithCString:value.c_str()] retain];
669 else if (name == "Label")
670 label_ = [[NSString stringWithCString:value.c_str()] retain];
671 else if (name == "Origin")
672 origin_ = [[NSString stringWithCString:value.c_str()] retain];
673 else if (name == "Version")
674 version_ = [[NSString stringWithCString:value.c_str()] retain];
688 - (NSString *) distribution {
689 return distribution_;
692 - (NSString *) type {
696 - (NSString *) description {
700 - (NSString *) label {
704 - (NSString *) origin {
708 - (NSString *) version {
712 - (NSString *) defaultIcon {
718 /* Package Class {{{ */
719 NSString *Scour(const char *field, const char *begin, const char *end) {
720 size_t i(0), l(strlen(field));
723 const char *name = begin + i;
724 const char *colon = name + l;
725 const char *value = colon + 1;
730 memcmp(name, field, l) == 0
732 while (value != end && value[0] == ' ')
734 const char *line = std::find(value, end, '\n');
735 while (line != value && line[-1] == ' ')
737 return [NSString stringWithCString:value length:(line - value)];
739 begin = std::find(begin, end, '\n');
747 @interface Package : NSObject {
748 pkgCache::PkgIterator iterator_;
749 _transient Database *database_;
750 pkgCache::VerIterator version_;
751 pkgCache::VerFileIterator file_;
757 NSString *installed_;
766 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database version:(pkgCache::VerIterator)version file:(pkgCache::VerFileIterator)file;
767 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
769 - (NSString *) section;
770 - (Address *) maintainer;
772 - (NSString *) description;
773 - (NSString *) index;
777 - (NSString *) latest;
778 - (NSString *) installed;
785 - (NSString *) tagline;
787 - (NSString *) website;
791 - (BOOL) matches:(NSString *)text;
793 - (NSComparisonResult) compareByName:(Package *)package;
794 - (NSComparisonResult) compareBySection:(Package *)package;
795 - (NSComparisonResult) compareBySectionAndName:(Package *)package;
796 - (NSComparisonResult) compareForChanges:(Package *)package;
801 - (NSNumber *) isSearchedForBy:(NSString *)search;
802 - (NSNumber *) isInstalledInSection:(NSString *)section;
803 - (NSNumber *) isUninstalledInSection:(NSString *)section;
807 @implementation Package
814 if (installed_ != nil)
815 [installed_ release];
829 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database version:(pkgCache::VerIterator)version file:(pkgCache::VerFileIterator)file {
830 if ((self = [super init]) != nil) {
831 iterator_ = iterator;
832 database_ = database;
837 latest_ = [[NSString stringWithCString:version_.VerStr()] retain];
838 installed_ = iterator_.CurrentVer().end() ? nil : [[NSString stringWithCString:iterator_.CurrentVer().VerStr()] retain];
840 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
842 const char *begin, *end;
843 parser->GetRec(begin, end);
845 id_ = [[[NSString stringWithCString:iterator_.Name()] lowercaseString] retain];
846 name_ = Scour("Name", begin, end);
848 name_ = [name_ retain];
849 tagline_ = [[NSString stringWithCString:parser->ShortDesc().c_str()] retain];
850 icon_ = Scour("Icon", begin, end);
852 icon_ = [icon_ retain];
853 website_ = Scour("Website", begin, end);
855 website_ = [website_ retain];
857 NSMutableDictionary *metadata = [Packages_ objectForKey:id_];
858 if (metadata == nil || [metadata count] == 0) {
859 metadata = [NSMutableDictionary dictionaryWithObjectsAndKeys:
863 [Packages_ setObject:metadata forKey:id_];
869 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
870 for (pkgCache::VerIterator version = iterator.VersionList(); !version.end(); ++version)
871 for (pkgCache::VerFileIterator file = version.FileList(); !file.end(); ++file)
872 return [[[Package alloc]
873 initWithIterator:iterator
881 - (NSString *) section {
882 const char *section = iterator_.Section();
883 return section == NULL ? nil : [[NSString stringWithCString:section] stringByReplacingCharacter:'_' withCharacter:' '];
886 - (Address *) maintainer {
887 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
888 return [Address addressWithString:[NSString stringWithCString:parser->Maintainer().c_str()]];
892 return version_->InstalledSize;
895 - (NSString *) description {
896 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
897 NSString *description([NSString stringWithCString:parser->LongDesc().c_str()]);
899 NSArray *lines = [description componentsSeparatedByString:@"\n"];
900 NSMutableArray *trimmed = [NSMutableArray arrayWithCapacity:([lines count] - 1)];
901 if ([lines count] < 2)
904 NSCharacterSet *whitespace = [NSCharacterSet whitespaceCharacterSet];
905 for (size_t i(1); i != [lines count]; ++i) {
906 NSString *trim = [[lines objectAtIndex:i] stringByTrimmingCharactersInSet:whitespace];
907 [trimmed addObject:trim];
910 return [trimmed componentsJoinedByString:@"\n"];
913 - (NSString *) index {
914 NSString *index = [[[self name] substringToIndex:1] uppercaseString];
915 return [index length] != 0 && isalpha([index characterAtIndex:0]) ? index : @"123";
919 return [[Packages_ objectForKey:id_] objectForKey:@"FirstSeen"];
922 - (NSString *) latest {
926 - (NSString *) installed {
930 - (BOOL) upgradable {
931 if (NSString *installed = [self installed])
932 return [[self latest] compare:installed] != NSOrderedSame ? YES : NO;
934 return [self essential];
938 return (iterator_->Flags & pkgCache::Flag::Essential) == 0 ? NO : YES;
942 return (*[database_ cache])[iterator_].InstBroken();
949 - (NSString *) name {
950 return name_ == nil ? id_ : name_;
953 - (NSString *) tagline {
957 - (NSString *) icon {
961 - (NSString *) website {
965 - (Source *) source {
967 source_ = [[database_ getSource:file_.File()] retain];
974 - (BOOL) matches:(NSString *)text {
980 range = [[self id] rangeOfString:text options:NSCaseInsensitiveSearch];
981 if (range.location != NSNotFound)
984 range = [[self name] rangeOfString:text options:NSCaseInsensitiveSearch];
985 if (range.location != NSNotFound)
988 range = [[self tagline] rangeOfString:text options:NSCaseInsensitiveSearch];
989 if (range.location != NSNotFound)
995 - (NSComparisonResult) compareByName:(Package *)package {
996 NSString *lhs = [self name];
997 NSString *rhs = [package name];
999 if ([lhs length] != 0 && [rhs length] != 0) {
1000 unichar lhc = [lhs characterAtIndex:0];
1001 unichar rhc = [rhs characterAtIndex:0];
1003 if (isalpha(lhc) && !isalpha(rhc))
1004 return NSOrderedAscending;
1005 else if (!isalpha(lhc) && isalpha(rhc))
1006 return NSOrderedDescending;
1009 return [lhs caseInsensitiveCompare:rhs];
1012 - (NSComparisonResult) compareBySection:(Package *)package {
1013 NSString *lhs = [self section];
1014 NSString *rhs = [package section];
1016 if (lhs == NULL && rhs != NULL)
1017 return NSOrderedAscending;
1018 else if (lhs != NULL && rhs == NULL)
1019 return NSOrderedDescending;
1020 else if (lhs != NULL && rhs != NULL) {
1021 NSComparisonResult result = [lhs caseInsensitiveCompare:rhs];
1022 if (result != NSOrderedSame)
1026 return NSOrderedSame;
1029 - (NSComparisonResult) compareBySectionAndName:(Package *)package {
1030 NSString *lhs = [self section];
1031 NSString *rhs = [package section];
1033 if (lhs == NULL && rhs != NULL)
1034 return NSOrderedAscending;
1035 else if (lhs != NULL && rhs == NULL)
1036 return NSOrderedDescending;
1037 else if (lhs != NULL && rhs != NULL) {
1038 NSComparisonResult result = [lhs compare:rhs];
1039 if (result != NSOrderedSame)
1043 return [self compareByName:package];
1046 - (NSComparisonResult) compareForChanges:(Package *)package {
1047 BOOL lhs = [self upgradable];
1048 BOOL rhs = [package upgradable];
1051 return lhs ? NSOrderedAscending : NSOrderedDescending;
1053 switch ([[self seen] compare:[package seen]]) {
1054 case NSOrderedAscending:
1055 return NSOrderedDescending;
1058 case NSOrderedDescending:
1059 return NSOrderedAscending;
1065 return [self compareByName:package];
1069 pkgProblemResolver *resolver = [database_ resolver];
1070 resolver->Clear(iterator_);
1071 resolver->Protect(iterator_);
1072 pkgCacheFile &cache([database_ cache]);
1073 cache->MarkInstall(iterator_, false);
1074 pkgDepCache::StateCache &state((*cache)[iterator_]);
1075 if (!state.Install())
1076 cache->SetReInstall(iterator_, true);
1080 pkgProblemResolver *resolver = [database_ resolver];
1081 resolver->Clear(iterator_);
1082 resolver->Protect(iterator_);
1083 resolver->Remove(iterator_);
1084 [database_ cache]->MarkDelete(iterator_, true);
1087 - (NSNumber *) isSearchedForBy:(NSString *)search {
1088 return [NSNumber numberWithBool:[self matches:search]];
1091 - (NSNumber *) isInstalledInSection:(NSString *)section {
1092 return [NSNumber numberWithBool:([self installed] != nil && (section == nil || [section isEqualToString:[self section]]))];
1095 - (NSNumber *) isUninstalledInSection:(NSString *)section {
1096 return [NSNumber numberWithBool:([self installed] == nil && (section == nil || [section isEqualToString:[self section]]))];
1101 /* Section Class {{{ */
1102 @interface Section : NSObject {
1108 - (Section *) initWithName:(NSString *)name row:(size_t)row;
1109 - (NSString *) name;
1112 - (void) addToCount;
1116 @implementation Section
1123 - (Section *) initWithName:(NSString *)name row:(size_t)row {
1124 if ((self = [super init]) != nil) {
1125 name_ = [name retain];
1130 - (NSString *) name {
1142 - (void) addToCount {
1149 /* Database Implementation {{{ */
1150 @implementation Database
1157 - (void) _readStatus:(NSNumber *)fd {
1158 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1160 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1161 std::istream is(&ib);
1166 pcre *code = pcre_compile("^([^:]*):([^:]*):([^:]*):(.*)$", 0, &error, &offset, NULL);
1168 pcre_extra *study = NULL;
1170 pcre_fullinfo(code, study, PCRE_INFO_CAPTURECOUNT, &capture);
1171 int matches[(capture + 1) * 3];
1173 while (std::getline(is, line)) {
1174 const char *data(line.c_str());
1176 _assert(pcre_exec(code, study, data, line.size(), 0, 0, matches, sizeof(matches) / sizeof(matches[0])) >= 0);
1178 std::istringstream buffer(line.substr(matches[6], matches[7] - matches[6]));
1181 [delegate_ setProgressPercent:(percent / 100)];
1183 NSString *string = [NSString stringWithCString:(data + matches[8]) length:(matches[9] - matches[8])];
1184 std::string type(line.substr(matches[2], matches[3] - matches[2]));
1186 if (type == "pmerror")
1187 [delegate_ setProgressError:string];
1188 else if (type == "pmstatus")
1189 [delegate_ setProgressTitle:string];
1190 else if (type == "pmconffile")
1192 else _assert(false);
1199 - (void) _readOutput:(NSNumber *)fd {
1200 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1202 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1203 std::istream is(&ib);
1206 while (std::getline(is, line))
1207 [delegate_ addProgressOutput:[NSString stringWithCString:line.c_str()]];
1213 - (Package *) packageWithName:(NSString *)name {
1214 pkgCache::PkgIterator iterator(cache_->FindPkg([name UTF8String]));
1215 return iterator.end() ? nil : [Package packageWithIterator:iterator database:self];
1218 - (Database *) init {
1219 if ((self = [super init]) != nil) {
1225 sources_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1226 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
1230 _assert(pipe(fds) != -1);
1234 detachNewThreadSelector:@selector(_readStatus:)
1236 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1239 _assert(pipe(fds) != -1);
1240 _assert(dup2(fds[1], 1) != -1);
1241 _assert(close(fds[1]) != -1);
1244 detachNewThreadSelector:@selector(_readOutput:)
1246 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1251 - (pkgCacheFile &) cache {
1255 - (pkgRecords *) records {
1259 - (pkgProblemResolver *) resolver {
1263 - (pkgAcquire &) fetcher {
1267 - (NSArray *) packages {
1271 - (void) reloadData {
1281 if (!cache_.Open(progress_, true)) {
1282 fprintf(stderr, "repairing corrupted database...\n");
1284 [self updateWithStatus:status_];
1285 _assert(cache_.Open(progress_, true));
1288 now_ = [[NSDate date] retain];
1290 records_ = new pkgRecords(cache_);
1291 resolver_ = new pkgProblemResolver(cache_);
1292 fetcher_ = new pkgAcquire(&status_);
1295 list_ = new pkgSourceList();
1296 _assert(list_->ReadMainList());
1298 [sources_ removeAllObjects];
1299 for (pkgSourceList::const_iterator source = list_->begin(); source != list_->end(); ++source) {
1300 std::vector<pkgIndexFile *> *indices = (*source)->GetIndexFiles();
1301 for (std::vector<pkgIndexFile *>::const_iterator index = indices->begin(); index != indices->end(); ++index)
1303 setObject:[[[Source alloc] initWithMetaIndex:*source] autorelease]
1304 forKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(*index)]
1308 [packages_ removeAllObjects];
1309 for (pkgCache::PkgIterator iterator = cache_->PkgBegin(); !iterator.end(); ++iterator)
1310 if (Package *package = [Package packageWithIterator:iterator database:self])
1311 if ([package source] != nil || [package installed] != nil)
1312 [packages_ addObject:package];
1314 [packages_ sortUsingSelector:@selector(compareByName:)];
1318 pkgRecords records(cache_);
1320 lock_ = new FileFd();
1321 lock_->Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1322 _assert(!_error->PendingError());
1325 // XXX: explain this with an error message
1326 _assert(list.ReadMainList());
1328 manager_ = (_system->CreatePM(cache_));
1329 _assert(manager_->GetArchives(fetcher_, &list, &records));
1330 _assert(!_error->PendingError());
1334 NSMutableArray *before = [NSMutableArray arrayWithCapacity:16]; {
1336 _assert(list.ReadMainList());
1337 for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source)
1338 [before addObject:[NSString stringWithUTF8String:(*source)->GetURI().c_str()]];
1341 if (fetcher_->Run(PulseInterval_) != pkgAcquire::Continue)
1345 pkgPackageManager::OrderResult result = manager_->DoInstall(statusfd_);
1347 if (result == pkgPackageManager::Failed)
1349 if (_error->PendingError())
1351 if (result != pkgPackageManager::Completed)
1354 NSMutableArray *after = [NSMutableArray arrayWithCapacity:16]; {
1356 _assert(list.ReadMainList());
1357 for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source)
1358 [after addObject:[NSString stringWithUTF8String:(*source)->GetURI().c_str()]];
1361 if (![before isEqualToArray:after])
1366 _assert(cache_->DelCount() == 0 && cache_->InstCount() == 0);
1367 _assert(pkgApplyStatus(cache_));
1369 if (cache_->BrokenCount() != 0) {
1370 _assert(pkgFixBroken(cache_));
1371 _assert(cache_->BrokenCount() == 0);
1372 _assert(pkgMinimizeUpgrade(cache_));
1375 _assert(pkgDistUpgrade(cache_));
1379 [self updateWithStatus:status_];
1382 - (void) updateWithStatus:(Status &)status {
1384 _assert(list.ReadMainList());
1387 lock.Fd(GetLock(_config->FindDir("Dir::State::Lists") + "lock"));
1388 _assert(!_error->PendingError());
1390 pkgAcquire fetcher(&status);
1391 _assert(list.GetIndexes(&fetcher));
1393 if (fetcher.Run(PulseInterval_) != pkgAcquire::Failed) {
1394 bool failed = false;
1395 for (pkgAcquire::ItemIterator item = fetcher.ItemsBegin(); item != fetcher.ItemsEnd(); item++)
1396 if ((*item)->Status != pkgAcquire::Item::StatDone) {
1397 (*item)->Finished();
1401 if (!failed && _config->FindB("APT::Get::List-Cleanup", true) == true) {
1402 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists")));
1403 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/"));
1406 [Metadata_ setObject:[NSDate date] forKey:@"LastUpdate"];
1411 - (void) setDelegate:(id)delegate {
1412 delegate_ = delegate;
1413 status_.setDelegate(delegate);
1414 progress_.setDelegate(delegate);
1417 - (Source *) getSource:(const pkgCache::PkgFileIterator &)file {
1418 pkgIndexFile *index(NULL);
1419 list_->FindIndex(file, index);
1420 return [sources_ objectForKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(index)]];
1426 /* Confirmation View {{{ */
1427 void AddTextView(NSMutableDictionary *fields, NSMutableArray *packages, NSString *key) {
1428 if ([packages count] == 0)
1431 UITextView *text = GetTextView([packages count] == 0 ? @"n/a" : [packages componentsJoinedByString:@", "], 120, false);
1432 [fields setObject:text forKey:key];
1434 CGColor blue(space_, 0, 0, 0.4, 1);
1435 [text setTextColor:blue];
1438 @protocol ConfirmationViewDelegate
1443 @interface ConfirmationView : UIView {
1444 Database *database_;
1446 UITransitionView *transition_;
1448 UINavigationBar *navbar_;
1449 UIPreferencesTable *table_;
1450 NSMutableDictionary *fields_;
1451 UIAlertSheet *essential_;
1456 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate;
1460 @implementation ConfirmationView
1463 [navbar_ setDelegate:nil];
1464 [transition_ setDelegate:nil];
1465 [table_ setDataSource:nil];
1467 [transition_ release];
1472 if (essential_ != nil)
1473 [essential_ release];
1478 [transition_ transition:7 toView:nil];
1482 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
1483 if (from != nil && to == nil)
1484 [self removeFromSuperview];
1487 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
1490 if (essential_ != nil)
1491 [essential_ popupAlertAnimated:YES];
1493 [delegate_ confirm];
1502 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
1503 [essential_ dismiss];
1507 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
1511 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
1513 case 0: return @"Statistics";
1514 case 1: return @"Modifications";
1516 default: _assert(false);
1520 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
1523 case 1: return [fields_ count];
1525 default: _assert(false);
1529 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
1530 if (group != 1 || row == -1)
1533 _assert(size_t(row) < [fields_ count]);
1534 return [[[fields_ allValues] objectAtIndex:row] visibleTextRect].size.height + TextViewOffset_;
1538 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
1539 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
1540 [cell setShowSelection:NO];
1543 case 0: switch (row) {
1545 [cell setTitle:@"Downloading"];
1546 [cell setValue:SizeString([database_ fetcher].FetchNeeded())];
1550 [cell setTitle:@"Resuming At"];
1551 [cell setValue:SizeString([database_ fetcher].PartialPresent())];
1555 double size([database_ cache]->UsrSize());
1558 [cell setTitle:@"Disk Freeing"];
1559 [cell setValue:SizeString(-size)];
1561 [cell setTitle:@"Disk Using"];
1562 [cell setValue:SizeString(size)];
1566 default: _assert(false);
1570 _assert(size_t(row) < [fields_ count]);
1571 [cell setTitle:[[fields_ allKeys] objectAtIndex:row]];
1572 [cell addSubview:[[fields_ allValues] objectAtIndex:row]];
1575 default: _assert(false);
1581 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate {
1582 if ((self = [super initWithFrame:[view bounds]]) != nil) {
1583 database_ = database;
1584 delegate_ = delegate;
1586 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
1587 [self addSubview:transition_];
1589 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
1591 CGSize navsize = [UINavigationBar defaultSize];
1592 CGRect navrect = {{0, 0}, navsize};
1593 CGRect bounds = [overlay_ bounds];
1595 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
1596 [navbar_ setBarStyle:1];
1597 [navbar_ setDelegate:self];
1599 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Confirm"] autorelease];
1600 [navbar_ pushNavigationItem:navitem];
1601 [navbar_ showButtonsWithLeftTitle:@"Cancel" rightTitle:@"Confirm"];
1603 fields_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1605 NSMutableArray *installing = [NSMutableArray arrayWithCapacity:16];
1606 NSMutableArray *reinstalling = [NSMutableArray arrayWithCapacity:16];
1607 NSMutableArray *upgrading = [NSMutableArray arrayWithCapacity:16];
1608 NSMutableArray *downgrading = [NSMutableArray arrayWithCapacity:16];
1609 NSMutableArray *removing = [NSMutableArray arrayWithCapacity:16];
1613 pkgCacheFile &cache([database_ cache]);
1614 for (pkgCache::PkgIterator iterator = cache->PkgBegin(); !iterator.end(); ++iterator) {
1615 Package *package([Package packageWithIterator:iterator database:database_]);
1616 NSString *name([package name]);
1617 bool essential((iterator->Flags & pkgCache::Flag::Essential) != 0);
1618 pkgDepCache::StateCache &state(cache[iterator]);
1620 if (state.NewInstall())
1621 [installing addObject:name];
1622 else if (!state.Delete() && (state.iFlags & pkgDepCache::ReInstall) == pkgDepCache::ReInstall)
1623 [reinstalling addObject:name];
1624 else if (state.Upgrade())
1625 [upgrading addObject:name];
1626 else if (state.Downgrade())
1627 [downgrading addObject:name];
1628 else if (state.Delete()) {
1631 [removing addObject:name];
1638 essential_ = [[UIAlertSheet alloc]
1639 initWithTitle:@"Unable to Comply"
1640 buttons:[NSArray arrayWithObjects:@"Okay", nil]
1641 defaultButtonIndex:0
1646 [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."];
1649 AddTextView(fields_, installing, @"Installing");
1650 AddTextView(fields_, reinstalling, @"Reinstalling");
1651 AddTextView(fields_, upgrading, @"Upgrading");
1652 AddTextView(fields_, downgrading, @"Downgrading");
1653 AddTextView(fields_, removing, @"Removing");
1655 table_ = [[UIPreferencesTable alloc] initWithFrame:CGRectMake(
1656 0, navsize.height, bounds.size.width, bounds.size.height - navsize.height
1659 [table_ setReusesTableCells:YES];
1660 [table_ setDataSource:self];
1661 [table_ reloadData];
1663 [overlay_ addSubview:navbar_];
1664 [overlay_ addSubview:table_];
1666 [view addSubview:self];
1668 [transition_ setDelegate:self];
1670 UIView *blank = [[[UIView alloc] initWithFrame:[transition_ bounds]] autorelease];
1671 [transition_ transition:0 toView:blank];
1672 [transition_ transition:3 toView:overlay_];
1679 /* Progress Data {{{ */
1680 @interface ProgressData : NSObject {
1686 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object;
1693 @implementation ProgressData
1695 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object {
1696 if ((self = [super init]) != nil) {
1697 selector_ = selector;
1717 /* Progress View {{{ */
1718 @interface ProgressView : UIView <
1722 UIView *background_;
1723 UITransitionView *transition_;
1725 UINavigationBar *navbar_;
1726 UIProgressBar *progress_;
1727 UITextView *output_;
1728 UITextLabel *status_;
1732 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
1734 - (ProgressView *) initWithFrame:(struct CGRect)frame delegate:(id)delegate;
1735 - (void) setContentView:(UIView *)view;
1738 - (void) _retachThread;
1739 - (void) _detachNewThreadData:(ProgressData *)data;
1740 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title;
1744 @protocol ProgressViewDelegate
1745 - (void) progressViewIsComplete:(ProgressView *)sender;
1748 @implementation ProgressView
1751 [transition_ setDelegate:nil];
1752 [navbar_ setDelegate:nil];
1755 if (background_ != nil)
1756 [background_ release];
1757 [transition_ release];
1760 [progress_ release];
1766 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
1767 if (bootstrap_ && from == overlay_ && to == view_)
1771 - (ProgressView *) initWithFrame:(struct CGRect)frame delegate:(id)delegate {
1772 if ((self = [super initWithFrame:frame]) != nil) {
1773 delegate_ = delegate;
1775 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
1776 [transition_ setDelegate:self];
1778 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
1781 [overlay_ setBackgroundColor:Black_];
1783 background_ = [[UIView alloc] initWithFrame:[self bounds]];
1784 [background_ setBackgroundColor:Black_];
1785 [self addSubview:background_];
1788 [self addSubview:transition_];
1790 CGSize navsize = [UINavigationBar defaultSize];
1791 CGRect navrect = {{0, 0}, navsize};
1793 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
1794 [overlay_ addSubview:navbar_];
1796 [navbar_ setBarStyle:1];
1797 [navbar_ setDelegate:self];
1799 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:nil] autorelease];
1800 [navbar_ pushNavigationItem:navitem];
1802 CGRect bounds = [overlay_ bounds];
1803 CGSize prgsize = [UIProgressBar defaultSize];
1806 (bounds.size.width - prgsize.width) / 2,
1807 bounds.size.height - prgsize.height - 20
1810 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
1811 [overlay_ addSubview:progress_];
1813 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(
1815 bounds.size.height - prgsize.height - 50,
1816 bounds.size.width - 20,
1820 [status_ setColor:White_];
1821 [status_ setBackgroundColor:Clear_];
1823 [status_ setCentersHorizontally:YES];
1824 //[status_ setFont:font];
1826 output_ = [[UITextView alloc] initWithFrame:CGRectMake(
1828 navrect.size.height + 20,
1829 bounds.size.width - 20,
1830 bounds.size.height - navsize.height - 62 - navrect.size.height
1833 //[output_ setTextFont:@"Courier New"];
1834 [output_ setTextSize:12];
1836 [output_ setTextColor:White_];
1837 [output_ setBackgroundColor:Clear_];
1839 [output_ setMarginTop:0];
1840 [output_ setAllowsRubberBanding:YES];
1842 [overlay_ addSubview:output_];
1843 [overlay_ addSubview:status_];
1845 [progress_ setStyle:0];
1849 - (void) setContentView:(UIView *)view {
1850 view_ = [view retain];
1853 - (void) resetView {
1854 [transition_ transition:6 toView:view_];
1857 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
1861 - (void) _retachThread {
1862 [delegate_ progressViewIsComplete:self];
1866 - (void) _detachNewThreadData:(ProgressData *)data {
1867 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1869 [[data target] performSelector:[data selector] withObject:[data object]];
1872 [self performSelectorOnMainThread:@selector(_retachThread) withObject:nil waitUntilDone:YES];
1877 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title {
1878 [navbar_ popNavigationItem];
1879 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:title] autorelease];
1880 [navbar_ pushNavigationItem:navitem];
1882 [status_ setText:nil];
1883 [output_ setText:@""];
1884 [progress_ setProgress:0];
1886 [transition_ transition:6 toView:overlay_];
1889 detachNewThreadSelector:@selector(_detachNewThreadData:)
1891 withObject:[[ProgressData alloc]
1892 initWithSelector:selector
1899 - (void) setProgressError:(NSString *)error {
1901 performSelectorOnMainThread:@selector(_setProgressError:)
1907 - (void) setProgressTitle:(NSString *)title {
1909 performSelectorOnMainThread:@selector(_setProgressTitle:)
1915 - (void) setProgressPercent:(float)percent {
1917 performSelectorOnMainThread:@selector(_setProgressPercent:)
1918 withObject:[NSNumber numberWithFloat:percent]
1923 - (void) addProgressOutput:(NSString *)output {
1925 performSelectorOnMainThread:@selector(_addProgressOutput:)
1931 - (void) _setProgressError:(NSString *)error {
1932 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
1933 initWithTitle:@"Package Error"
1934 buttons:[NSArray arrayWithObjects:@"Okay", nil]
1935 defaultButtonIndex:0
1940 [sheet setBodyText:error];
1941 [sheet popupAlertAnimated:YES];
1944 - (void) _setProgressTitle:(NSString *)title {
1945 [status_ setText:[title stringByAppendingString:@"..."]];
1948 - (void) _setProgressPercent:(NSNumber *)percent {
1949 [progress_ setProgress:[percent floatValue]];
1952 - (void) _addProgressOutput:(NSString *)output {
1953 [output_ setText:[NSString stringWithFormat:@"%@\n%@", [output_ text], output]];
1954 CGSize size = [output_ contentSize];
1955 CGRect rect = {{0, size.height}, {size.width, 0}};
1956 [output_ scrollRectToVisible:rect animated:YES];
1962 /* Package Cell {{{ */
1963 @interface PackageCell : UITableCell {
1966 UITextLabel *description_;
1967 UITextLabel *source_;
1968 UIImageView *trusted_;
1971 - (PackageCell *) init;
1972 - (void) setPackage:(Package *)package;
1974 - (void) _setSelected:(float)fraction;
1975 - (void) setSelected:(BOOL)selected;
1976 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
1977 - (void) _setSelectionFadeFraction:(float)fraction;
1981 @implementation PackageCell
1986 [description_ release];
1992 - (PackageCell *) init {
1993 if ((self = [super init]) != nil) {
1994 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 20);
1995 GSFontRef large = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 12);
1996 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 14);
1998 icon_ = [[UIImageView alloc] initWithFrame:CGRectMake(10, 10, 30, 30)];
2000 name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 8, 240, 25)];
2001 [name_ setBackgroundColor:Clear_];
2002 [name_ setFont:bold];
2004 source_ = [[UITextLabel alloc] initWithFrame:CGRectMake(58, 28, 225, 20)];
2005 [source_ setBackgroundColor:Clear_];
2006 [source_ setFont:large];
2008 description_ = [[UITextLabel alloc] initWithFrame:CGRectMake(12, 46, 280, 20)];
2009 [description_ setBackgroundColor:Clear_];
2010 [description_ setFont:small];
2012 trusted_ = [[UIImageView alloc] initWithFrame:CGRectMake(30, 30, 16, 16)];
2013 [trusted_ setImage:[UIImage applicationImageNamed:@"trusted.png"]];
2015 [self addSubview:icon_];
2016 [self addSubview:name_];
2017 [self addSubview:description_];
2018 [self addSubview:source_];
2026 - (void) setPackage:(Package *)package {
2027 Source *source = [package source];
2029 UIImage *image = nil;
2030 if (NSString *icon = [package icon])
2031 image = [UIImage imageAtPath:[icon substringFromIndex:6]];
2032 if (image == nil) if (NSString *icon = [source defaultIcon])
2033 image = [UIImage imageAtPath:[icon substringFromIndex:6]];
2035 image = [UIImage applicationImageNamed:@"unknown.png"];
2036 [icon_ setImage:image];
2039 CGSize size = [image size];
2040 float scale = 30 / std::max(size.width, size.height);
2041 [icon_ zoomToScale:scale];
2044 [icon_ setFrame:CGRectMake(10, 10, 30, 30)];
2046 [name_ setText:[package name]];
2047 [description_ setText:[package tagline]];
2052 if (source != nil) {
2053 label = [source label];
2054 trusted = [source trusted];
2055 } else if ([[package id] isEqualToString:@"firmware"]) {
2059 label = @"Unknown/Local";
2063 [source_ setText:[NSString stringWithFormat:@"from %@ (%@)", label, Simplify([package section])]];
2066 [self addSubview:trusted_];
2068 [trusted_ removeFromSuperview];
2071 - (void) _setSelected:(float)fraction {
2072 CGColor black(space_,
2073 Interpolate(0.0, 1.0, fraction),
2074 Interpolate(0.0, 1.0, fraction),
2075 Interpolate(0.0, 1.0, fraction),
2078 CGColor gray(space_,
2079 Interpolate(0.4, 1.0, fraction),
2080 Interpolate(0.4, 1.0, fraction),
2081 Interpolate(0.4, 1.0, fraction),
2084 [name_ setColor:black];
2085 [description_ setColor:gray];
2086 [source_ setColor:black];
2089 - (void) setSelected:(BOOL)selected {
2090 [self _setSelected:(selected ? 1.0 : 0.0)];
2091 [super setSelected:selected];
2094 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
2096 [self _setSelected:(selected ? 1.0 : 0.0)];
2097 [super setSelected:selected withFade:fade];
2100 - (void) _setSelectionFadeFraction:(float)fraction {
2101 [self _setSelected:fraction];
2102 [super _setSelectionFadeFraction:fraction];
2107 /* Section Cell {{{ */
2108 @interface SectionCell : UITableCell {
2110 UITextLabel *count_;
2114 - (void) setSection:(Section *)section;
2116 - (void) _setSelected:(float)fraction;
2117 - (void) setSelected:(BOOL)selected;
2118 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
2119 - (void) _setSelectionFadeFraction:(float)fraction;
2123 @implementation SectionCell
2132 if ((self = [super init]) != nil) {
2133 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22);
2134 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 12);
2136 name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 9, 250, 25)];
2137 [name_ setBackgroundColor:Clear_];
2138 [name_ setFont:bold];
2140 count_ = [[UITextLabel alloc] initWithFrame:CGRectMake(11, 7, 29, 32)];
2141 [count_ setCentersHorizontally:YES];
2142 [count_ setBackgroundColor:Clear_];
2143 [count_ setFont:small];
2144 [count_ setColor:White_];
2146 UIImageView *folder = [[[UIImageView alloc] initWithFrame:CGRectMake(8, 7, 32, 32)] autorelease];
2147 [folder setImage:[UIImage applicationImageNamed:@"folder.png"]];
2149 [self addSubview:folder];
2150 [self addSubview:name_];
2151 [self addSubview:count_];
2153 [self _setSelected:0];
2160 - (void) setSection:(Section *)section {
2161 if (section == nil) {
2162 [name_ setText:@"All Packages"];
2163 [count_ setText:nil];
2165 NSString *name = [section name];
2166 [name_ setText:(name == nil ? @"(No Section)" : name)];
2167 [count_ setText:[NSString stringWithFormat:@"%d", [section count]]];
2171 - (void) _setSelected:(float)fraction {
2172 CGColor black(space_,
2173 Interpolate(0.0, 1.0, fraction),
2174 Interpolate(0.0, 1.0, fraction),
2175 Interpolate(0.0, 1.0, fraction),
2178 [name_ setColor:black];
2181 - (void) setSelected:(BOOL)selected {
2182 [self _setSelected:(selected ? 1.0 : 0.0)];
2183 [super setSelected:selected];
2186 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
2188 [self _setSelected:(selected ? 1.0 : 0.0)];
2189 [super setSelected:selected withFade:fade];
2192 - (void) _setSelectionFadeFraction:(float)fraction {
2193 [self _setSelected:fraction];
2194 [super _setSelectionFadeFraction:fraction];
2200 /* File Table {{{ */
2201 @interface FileTable : RVPage {
2202 _transient Database *database_;
2205 NSMutableArray *files_;
2209 - (id) initWithBook:(RVBook *)book database:(Database *)database;
2210 - (void) setPackage:(Package *)package;
2214 @implementation FileTable
2217 if (package_ != nil)
2226 - (int) numberOfRowsInTable:(UITable *)table {
2227 return files_ == nil ? 0 : [files_ count];
2230 - (float) table:(UITable *)table heightForRow:(int)row {
2234 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2235 if (reusing == nil) {
2236 reusing = [[[UIImageAndTextTableCell alloc] init] autorelease];
2237 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
2238 [[(UIImageAndTextTableCell *)reusing titleTextLabel] setFont:font];
2241 [(UIImageAndTextTableCell *)reusing setTitle:[files_ objectAtIndex:row]];
2245 - (BOOL) canSelectRow:(int)row {
2249 - (id) initWithBook:(RVBook *)book database:(Database *)database {
2250 if ((self = [super initWithBook:book]) != nil) {
2251 database_ = database;
2253 files_ = [[NSMutableArray arrayWithCapacity:32] retain];
2255 list_ = [[UITable alloc] initWithFrame:[self bounds]];
2256 [self addSubview:list_];
2258 UITableColumn *column = [[[UITableColumn alloc]
2259 initWithTitle:@"Name"
2261 width:[self frame].size.width
2264 [list_ setDataSource:self];
2265 [list_ setSeparatorStyle:1];
2266 [list_ addTableColumn:column];
2267 [list_ setDelegate:self];
2268 [list_ setReusesTableCells:YES];
2272 - (void) setPackage:(Package *)package {
2273 if (package_ != nil) {
2274 [package_ autorelease];
2283 [files_ removeAllObjects];
2285 if (package != nil) {
2286 package_ = [package retain];
2287 name_ = [[package id] retain];
2289 NSString *list = [NSString
2290 stringWithContentsOfFile:[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.list", name_]
2291 encoding:kCFStringEncodingUTF8
2296 [files_ addObjectsFromArray:[list componentsSeparatedByString:@"\n"]];
2297 [files_ removeLastObject];
2298 [files_ sortUsingSelector:@selector(compare:)];
2305 - (void) resetViewAnimated:(BOOL)animated {
2306 [list_ resetViewAnimated:animated];
2309 - (void) reloadData {
2310 [self setPackage:[database_ packageWithName:name_]];
2311 [self reloadButtons];
2314 - (NSString *) title {
2315 return @"File Contents";
2320 /* Package View {{{ */
2321 @protocol PackageViewDelegate
2322 - (void) performPackage:(Package *)package;
2325 @interface PackageView : RVPage {
2326 _transient Database *database_;
2327 UIPreferencesTable *table_;
2330 UITextView *description_;
2333 - (id) initWithBook:(RVBook *)book database:(Database *)database;
2334 - (void) setPackage:(Package *)package;
2338 @implementation PackageView
2341 [table_ setDataSource:nil];
2342 [table_ setDelegate:nil];
2344 if (package_ != nil)
2348 if (description_ != nil)
2349 [description_ release];
2354 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
2356 if ([package_ installed] != nil)
2358 if ([package_ source] != nil)
2363 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
2366 else if ([package_ installed] != nil && group-- == 0)
2367 return @"Installed Package";
2368 else if (group-- == 0)
2369 return @"Package Details";
2370 else if ([package_ source] != nil && group-- == 0)
2371 return @"Source Information";
2372 else _assert(false);
2375 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
2376 if (group != 0 || row != 1)
2379 return [description_ visibleTextRect].size.height + TextViewOffset_;
2382 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
2385 if ([package_ website] != nil)
2387 if ([[package_ source] trusted])
2390 } else if ([package_ installed] != nil && group-- == 0)
2392 else if (group-- == 0)
2394 else if ([package_ source] != nil && group-- == 0)
2396 else _assert(false);
2399 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
2400 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
2401 [cell setShowSelection:NO];
2406 [cell setTitle:[package_ name]];
2407 [cell setValue:[package_ latest]];
2411 [cell addSubview:description_];
2415 if ([package_ website] != nil) {
2416 [cell setTitle:@"More Information"];
2417 [cell setShowDisclosure:YES];
2418 [cell setShowSelection:YES];
2422 [cell setIcon:[UIImage applicationImageNamed:@"trusted.png"]];
2423 [cell setValue:@"This package has been signed."];
2426 default: _assert(false);
2428 else if ([package_ installed] != nil && group-- == 0)
2431 [cell setTitle:@"Version"];
2432 NSString *installed([package_ installed]);
2433 [cell setValue:(installed == nil ? @"n/a" : installed)];
2437 [cell setTitle:@"File Content"];
2438 [cell setShowDisclosure:YES];
2439 [cell setShowSelection:YES];
2442 default: _assert(false);
2444 else if (group-- == 0)
2447 [cell setTitle:@"Identifier"];
2448 [cell setValue:[package_ id]];
2452 [cell setTitle:@"Section"];
2453 NSString *section([package_ section]);
2454 [cell setValue:(section == nil ? @"n/a" : section)];
2458 [cell setTitle:@"Expanded Size"];
2459 [cell setValue:SizeString([package_ size])];
2463 [cell setTitle:@"Maintainer"];
2464 [cell setValue:[[package_ maintainer] name]];
2465 [cell setShowDisclosure:YES];
2466 [cell setShowSelection:YES];
2469 default: _assert(false);
2471 else if ([package_ source] != nil && group-- == 0)
2474 [cell setTitle:[[package_ source] label]];
2475 [cell setValue:[[package_ source] version]];
2479 [cell setValue:[[package_ source] description]];
2483 [cell setTitle:@"Origin"];
2484 [cell setValue:[[package_ source] origin]];
2487 default: _assert(false);
2489 else _assert(false);
2494 - (BOOL) canSelectRow:(int)row {
2498 - (void) tableRowSelected:(NSNotification *)notification {
2499 int row = [table_ selectedRow];
2500 NSString *website = [package_ website];
2501 BOOL trusted = [[package_ source] trusted];
2502 NSString *installed = [package_ installed];
2505 + (website == nil ? 0 : 1)
2507 + (installed == nil ? 0 : 3)
2509 [delegate_ openURL:[NSURL URLWithString:[NSString stringWithFormat:@"mailto:%@?subject=%@",
2510 [[package_ maintainer] email],
2511 [[NSString stringWithFormat:@"regarding apt package \"%@\"", [package_ name]] stringByAddingPercentEscapes]
2513 else if (installed && row == 5
2514 + (website == nil ? 0 : 1)
2517 FileTable *files = [[[FileTable alloc] initWithBook:book_ database:database_] autorelease];
2518 [files setDelegate:delegate_];
2519 [files setPackage:package_];
2520 [book_ pushPage:files];
2521 } else if (website != nil && row == 3) {
2522 NSURL *url = [NSURL URLWithString:website];
2523 BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease];
2524 [browser setDelegate:delegate_];
2525 [book_ pushPage:browser];
2526 [browser loadURL:url];
2530 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
2532 case 1: [delegate_ installPackage:package_]; break;
2533 case 2: [delegate_ removePackage:package_]; break;
2539 - (void) _rightButtonClicked {
2540 if ([package_ installed] == nil)
2541 [delegate_ installPackage:package_];
2543 NSMutableArray *buttons = [NSMutableArray arrayWithCapacity:6];
2545 if ([package_ upgradable])
2546 [buttons addObject:@"Upgrade"];
2548 [buttons addObject:@"Reinstall"];
2550 [buttons addObject:@"Remove"];
2551 [buttons addObject:@"Cancel"];
2553 [delegate_ slideUp:[[[UIAlertSheet alloc]
2554 initWithTitle:@"Manage Package"
2556 defaultButtonIndex:2
2563 - (NSString *) rightButtonTitle {
2564 _assert(package_ != nil);
2565 return [package_ installed] == nil ? @"Install" : @"Modify";
2568 - (NSString *) title {
2572 - (id) initWithBook:(RVBook *)book database:(Database *)database {
2573 if ((self = [super initWithBook:book]) != nil) {
2574 database_ = database;
2576 table_ = [[UIPreferencesTable alloc] initWithFrame:[self bounds]];
2577 [self addSubview:table_];
2579 [table_ setDataSource:self];
2580 [table_ setDelegate:self];
2584 - (void) setPackage:(Package *)package {
2585 if (package_ != nil) {
2586 [package_ autorelease];
2595 if (description_ != nil) {
2596 [description_ release];
2600 if (package != nil) {
2601 package_ = [package retain];
2602 name_ = [[package id] retain];
2604 NSString *description([package description]);
2605 if (description == nil)
2606 description = [package tagline];
2607 description_ = [GetTextView(description, 12, true) retain];
2609 [description_ setTextColor:Black_];
2611 [table_ reloadData];
2615 - (void) resetViewAnimated:(BOOL)animated {
2616 [table_ resetViewAnimated:animated];
2619 - (void) reloadData {
2620 [self setPackage:[database_ packageWithName:name_]];
2621 [self reloadButtons];
2626 /* Package Table {{{ */
2627 @interface PackageTable : RVPage {
2628 _transient Database *database_;
2632 NSMutableArray *packages_;
2633 NSMutableArray *sections_;
2634 UISectionList *list_;
2637 - (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object;
2639 - (void) setDelegate:(id)delegate;
2640 - (void) setObject:(id)object;
2642 - (void) reloadData;
2643 - (void) resetCursor;
2645 - (void) setShouldHideHeaderInShortLists:(BOOL)hide;
2649 @implementation PackageTable
2652 [list_ setDataSource:nil];
2657 [packages_ release];
2658 [sections_ release];
2663 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
2664 return [sections_ count];
2667 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
2668 return [[sections_ objectAtIndex:section] name];
2671 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
2672 return [[sections_ objectAtIndex:section] row];
2675 - (int) numberOfRowsInTable:(UITable *)table {
2676 return [packages_ count];
2679 - (float) table:(UITable *)table heightForRow:(int)row {
2683 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2685 reusing = [[[PackageCell alloc] init] autorelease];
2686 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
2690 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
2694 - (void) tableRowSelected:(NSNotification *)notification {
2695 int row = [[notification object] selectedRow];
2699 Package *package = [packages_ objectAtIndex:row];
2700 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
2701 [view setDelegate:delegate_];
2702 [view setPackage:package];
2703 [book_ pushPage:view];
2706 - (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object {
2707 if ((self = [super initWithBook:book]) != nil) {
2708 database_ = database;
2709 title_ = [title retain];
2711 object_ = object == nil ? nil : [object retain];
2713 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
2714 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
2716 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:YES];
2717 [list_ setDataSource:self];
2719 UITableColumn *column = [[[UITableColumn alloc]
2720 initWithTitle:@"Name"
2722 width:[self frame].size.width
2725 UITable *table = [list_ table];
2726 [table setSeparatorStyle:1];
2727 [table addTableColumn:column];
2728 [table setDelegate:self];
2729 [table setReusesTableCells:YES];
2731 [self addSubview:list_];
2736 - (void) setDelegate:(id)delegate {
2737 delegate_ = delegate;
2740 - (void) setObject:(id)object {
2746 object_ = [object retain];
2749 - (void) reloadData {
2750 NSArray *packages = [database_ packages];
2752 [packages_ removeAllObjects];
2753 [sections_ removeAllObjects];
2755 for (size_t i(0); i != [packages count]; ++i) {
2756 Package *package([packages objectAtIndex:i]);
2757 if ([[package performSelector:filter_ withObject:object_] boolValue])
2758 [packages_ addObject:package];
2761 Section *section = nil;
2763 for (size_t offset(0); offset != [packages_ count]; ++offset) {
2764 Package *package = [packages_ objectAtIndex:offset];
2765 NSString *name = [package index];
2767 if (section == nil || ![[section name] isEqualToString:name]) {
2768 section = [[[Section alloc] initWithName:name row:offset] autorelease];
2769 [sections_ addObject:section];
2772 [section addToCount];
2778 - (NSString *) title {
2782 - (void) resetViewAnimated:(BOOL)animated {
2783 [list_ resetViewAnimated:animated];
2786 - (void) resetCursor {
2787 [[list_ table] scrollPointVisibleAtTopLeft:CGPointMake(0, 0) animated:NO];
2790 - (void) setShouldHideHeaderInShortLists:(BOOL)hide {
2791 [list_ setShouldHideHeaderInShortLists:hide];
2797 /* Browser Implementation {{{ */
2798 @implementation BrowserView
2801 WebView *webview = [webview_ webView];
2802 [webview setFrameLoadDelegate:nil];
2803 [webview setResourceLoadDelegate:nil];
2804 [webview setUIDelegate:nil];
2806 [scroller_ setDelegate:nil];
2807 [webview_ setDelegate:nil];
2809 [scroller_ release];
2812 [indicator_ release];
2818 - (void) loadURL:(NSURL *)url cachePolicy:(NSURLRequestCachePolicy)policy {
2819 NSMutableURLRequest *request = [NSMutableURLRequest
2822 timeoutInterval:30.0
2825 [request addValue:[NSString stringWithCString:Firmware_] forHTTPHeaderField:@"X-Firmware"];
2826 [request addValue:[NSString stringWithCString:Machine_] forHTTPHeaderField:@"X-Machine"];
2827 [request addValue:[NSString stringWithCString:SerialNumber_] forHTTPHeaderField:@"X-Serial-Number"];
2829 [self loadRequest:request];
2833 - (void) loadURL:(NSURL *)url {
2834 [self loadURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy];
2837 // XXX: this needs to add the headers
2838 - (NSURLRequest *) _addHeadersToRequest:(NSURLRequest *)request {
2842 - (void) loadRequest:(NSURLRequest *)request {
2843 [webview_ loadRequest:request];
2846 - (void) reloadURL {
2847 NSURL *url = [[[urls_ lastObject] retain] autorelease];
2848 [urls_ removeLastObject];
2849 [self loadURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData];
2852 - (WebView *) webView {
2853 return [webview_ webView];
2856 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame {
2857 [scroller_ setContentSize:frame.size];
2860 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old {
2861 [self view:sender didSetFrame:frame];
2864 - (NSURLRequest *) webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource {
2865 return [self _addHeadersToRequest:request];
2868 - (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request {
2869 if ([[[request URL] scheme] isEqualToString:@"apptapp"])
2871 [self setBackButtonTitle:title_];
2872 BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease];
2873 [browser setDelegate:delegate_];
2874 [book_ pushPage:browser];
2875 [browser loadRequest:[self _addHeadersToRequest:request]];
2876 return [browser webView];
2879 - (void) webView:(WebView *)sender willClickElement:(id)element {
2880 if (![element respondsToSelector:@selector(href)])
2882 NSString *href = [element href];
2885 if ([href hasPrefix:@"apptapp://package/"]) {
2886 NSString *name = [href substringFromIndex:18];
2887 Package *package = [database_ packageWithName:name];
2888 if (package == nil) {
2889 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
2890 initWithTitle:@"Cannot Locate Package"
2891 buttons:[NSArray arrayWithObjects:@"Close", nil]
2892 defaultButtonIndex:0
2897 [sheet setBodyText:[NSString stringWithFormat:
2898 @"The package %@ cannot be found in your current sources. I might recommend installing more sources."
2901 [sheet popupAlertAnimated:YES];
2903 [self setBackButtonTitle:title_];
2904 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
2905 [view setDelegate:delegate_];
2906 [view setPackage:package];
2907 [book_ pushPage:view];
2912 - (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame {
2913 title_ = [title retain];
2914 [self setTitle:title];
2917 - (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame {
2918 if ([frame parentFrame] != nil)
2923 [indicator_ startAnimation];
2924 [self reloadButtons];
2926 if (title_ != nil) {
2931 [self setTitle:@"Loading..."];
2933 WebView *webview = [webview_ webView];
2934 NSString *href = [webview mainFrameURL];
2935 [urls_ addObject:[NSURL URLWithString:href]];
2937 CGRect webrect = [scroller_ frame];
2938 webrect.size.height = 0;
2939 [webview_ setFrame:webrect];
2942 - (void) _finishLoading {
2945 [indicator_ stopAnimation];
2946 [self reloadButtons];
2950 - (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
2951 if ([frame parentFrame] != nil)
2953 [self _finishLoading];
2956 - (void) webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
2957 if ([frame parentFrame] != nil)
2959 [self setTitle:[error localizedDescription]];
2960 [self _finishLoading];
2963 - (id) initWithBook:(RVBook *)book database:(Database *)database {
2964 if ((self = [super initWithBook:book]) != nil) {
2965 database_ = database;
2968 struct CGRect bounds = [self bounds];
2970 UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:bounds] autorelease];
2971 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
2972 [self addSubview:pinstripe];
2974 scroller_ = [[UIScroller alloc] initWithFrame:bounds];
2975 [self addSubview:scroller_];
2977 [scroller_ setScrollingEnabled:YES];
2978 [scroller_ setAdjustForContentSizeChange:YES];
2979 [scroller_ setClipsSubviews:YES];
2980 [scroller_ setAllowsRubberBanding:YES];
2981 [scroller_ setScrollDecelerationFactor:0.99];
2982 [scroller_ setDelegate:self];
2984 CGRect webrect = [scroller_ bounds];
2985 webrect.size.height = 0;
2987 webview_ = [[UIWebView alloc] initWithFrame:webrect];
2988 [scroller_ addSubview:webview_];
2990 [webview_ setTilingEnabled:YES];
2991 [webview_ setTileSize:CGSizeMake(webrect.size.width, 500)];
2992 [webview_ setAutoresizes:YES];
2993 [webview_ setDelegate:self];
2994 //[webview_ setEnabledGestures:2];
2996 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:0];
2997 indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(281, 43, indsize.width, indsize.height)];
2998 [indicator_ setStyle:0];
3000 Package *package([database_ packageWithName:@"cydia"]);
3001 NSString *application = package == nil ? @"Cydia" : [NSString
3002 stringWithFormat:@"Cydia/%@",
3006 WebView *webview = [webview_ webView];
3007 [webview setApplicationNameForUserAgent:application];
3008 [webview setFrameLoadDelegate:self];
3009 [webview setResourceLoadDelegate:self];
3010 [webview setUIDelegate:self];
3012 urls_ = [[NSMutableArray alloc] initWithCapacity:16];
3016 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
3020 - (void) _leftButtonClicked {
3021 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
3022 initWithTitle:@"About Cydia Packager"
3023 buttons:[NSArray arrayWithObjects:@"Close", nil]
3024 defaultButtonIndex:0
3030 @"Copyright (C) 2008\n"
3031 "Jay Freeman (saurik)\n"
3032 "saurik@saurik.com\n"
3033 "http://www.saurik.com/\n"
3036 "http://www.theokorigroup.com/\n"
3038 "College of Creative Studies,\n"
3039 "University of California,\n"
3041 "http://www.ccs.ucsb.edu/"
3044 [sheet popupAlertAnimated:YES];
3047 - (void) _rightButtonClicked {
3052 - (NSString *) leftButtonTitle {
3056 - (NSString *) rightButtonTitle {
3057 return loading_ ? @"" : @"Reload";
3060 - (NSString *) title {
3064 - (NSString *) backButtonTitle {
3068 - (void) setPageActive:(BOOL)active {
3070 [book_ addSubview:indicator_];
3072 [indicator_ removeFromSuperview];
3075 - (void) resetViewAnimated:(BOOL)animated {
3081 @interface CYBook : RVBook <
3084 _transient Database *database_;
3086 UIProgressIndicator *indicator_;
3087 UITextLabel *prompt_;
3088 UIProgressBar *progress_;
3092 - (id) initWithFrame:(CGRect)frame database:(Database *)database;
3098 /* Install View {{{ */
3099 @interface InstallView : RVPage {
3100 _transient Database *database_;
3101 NSMutableArray *packages_;
3102 NSMutableArray *sections_;
3106 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3107 - (void) reloadData;
3111 @implementation InstallView
3114 [list_ setDataSource:nil];
3115 [list_ setDelegate:nil];
3117 [packages_ release];
3118 [sections_ release];
3123 - (int) numberOfRowsInTable:(UITable *)table {
3124 return [sections_ count] + 1;
3127 - (float) table:(UITable *)table heightForRow:(int)row {
3131 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
3133 reusing = [[[SectionCell alloc] init] autorelease];
3134 [(SectionCell *)reusing setSection:(row == 0 ? nil : [sections_ objectAtIndex:(row - 1)])];
3138 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
3142 - (void) tableRowSelected:(NSNotification *)notification {
3143 int row = [[notification object] selectedRow];
3152 title = @"All Packages";
3154 section = [sections_ objectAtIndex:(row - 1)];
3155 title = [section name];
3158 PackageTable *table = [[[PackageTable alloc]
3162 filter:@selector(isUninstalledInSection:)
3163 with:(section == nil ? nil : [section name])
3166 [table setDelegate:delegate_];
3168 [book_ pushPage:table];
3171 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3172 if ((self = [super initWithBook:book]) != nil) {
3173 database_ = database;
3175 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
3176 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
3178 list_ = [[UITable alloc] initWithFrame:[self bounds]];
3179 [self addSubview:list_];
3181 UITableColumn *column = [[[UITableColumn alloc]
3182 initWithTitle:@"Name"
3184 width:[self frame].size.width
3187 [list_ setDataSource:self];
3188 [list_ setSeparatorStyle:1];
3189 [list_ addTableColumn:column];
3190 [list_ setDelegate:self];
3191 [list_ setReusesTableCells:YES];
3197 - (void) reloadData {
3198 NSArray *packages = [database_ packages];
3200 [packages_ removeAllObjects];
3201 [sections_ removeAllObjects];
3203 for (size_t i(0); i != [packages count]; ++i) {
3204 Package *package([packages objectAtIndex:i]);
3205 if ([package installed] == nil)
3206 [packages_ addObject:package];
3209 [packages_ sortUsingSelector:@selector(compareBySection:)];
3211 Section *section = nil;
3212 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
3213 Package *package = [packages_ objectAtIndex:offset];
3214 NSString *name = [package section];
3216 if (section == nil || name != nil && ![[section name] isEqualToString:name]) {
3217 section = [[[Section alloc] initWithName:name row:offset] autorelease];
3218 [sections_ addObject:section];
3221 [section addToCount];
3227 - (void) resetViewAnimated:(BOOL)animated {
3228 [list_ resetViewAnimated:animated];
3231 - (NSString *) title {
3235 - (NSString *) backButtonTitle {
3241 /* Changes View {{{ */
3242 @interface ChangesView : RVPage {
3243 _transient Database *database_;
3244 NSMutableArray *packages_;
3245 NSMutableArray *sections_;
3246 UISectionList *list_;
3250 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3251 - (void) reloadData;
3255 @implementation ChangesView
3258 [[list_ table] setDelegate:nil];
3259 [list_ setDataSource:nil];
3261 [packages_ release];
3262 [sections_ release];
3267 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
3268 return [sections_ count];
3271 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
3272 return [[sections_ objectAtIndex:section] name];
3275 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
3276 return [[sections_ objectAtIndex:section] row];
3279 - (int) numberOfRowsInTable:(UITable *)table {
3280 return [packages_ count];
3283 - (float) table:(UITable *)table heightForRow:(int)row {
3287 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
3289 reusing = [[[PackageCell alloc] init] autorelease];
3290 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
3294 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
3298 - (void) tableRowSelected:(NSNotification *)notification {
3299 int row = [[notification object] selectedRow];
3302 Package *package = [packages_ objectAtIndex:row];
3303 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
3304 [view setDelegate:delegate_];
3305 [view setPackage:package];
3306 [book_ pushPage:view];
3309 - (void) _leftButtonClicked {
3310 [(CYBook *)book_ update];
3311 [self reloadButtons];
3314 - (void) _rightButtonClicked {
3315 [delegate_ distUpgrade];
3318 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3319 if ((self = [super initWithBook:book]) != nil) {
3320 database_ = database;
3322 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
3323 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
3325 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:NO];
3326 [self addSubview:list_];
3328 [list_ setShouldHideHeaderInShortLists:NO];
3329 [list_ setDataSource:self];
3330 //[list_ setSectionListStyle:1];
3332 UITableColumn *column = [[[UITableColumn alloc]
3333 initWithTitle:@"Name"
3335 width:[self frame].size.width
3338 UITable *table = [list_ table];
3339 [table setSeparatorStyle:1];
3340 [table addTableColumn:column];
3341 [table setDelegate:self];
3342 [table setReusesTableCells:YES];
3348 - (void) reloadData {
3349 NSArray *packages = [database_ packages];
3351 [packages_ removeAllObjects];
3352 [sections_ removeAllObjects];
3354 for (size_t i(0); i != [packages count]; ++i) {
3355 Package *package([packages objectAtIndex:i]);
3356 if ([package installed] == nil || [package upgradable])
3357 [packages_ addObject:package];
3360 [packages_ sortUsingSelector:@selector(compareForChanges:)];
3362 Section *upgradable = [[[Section alloc] initWithName:@"Available Upgrades" row:0] autorelease];
3363 Section *section = nil;
3366 bool unseens = false;
3368 CFLocaleRef locale = CFLocaleCopyCurrent();
3369 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
3371 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
3372 Package *package = [packages_ objectAtIndex:offset];
3374 if ([package upgradable]) {
3376 [upgradable addToCount];
3379 NSDate *seen = [package seen];
3384 name = [@"n/a ?" retain];
3386 name = (NSString *) CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen);
3389 if (section == nil || ![[section name] isEqualToString:name]) {
3390 section = [[[Section alloc] initWithName:name row:offset] autorelease];
3391 [sections_ addObject:section];
3395 [section addToCount];
3399 CFRelease(formatter);
3403 Section *last = [sections_ lastObject];
3404 size_t count = [last count];
3405 [packages_ removeObjectsInRange:NSMakeRange([packages_ count] - count, count)];
3406 [sections_ removeLastObject];
3410 [sections_ insertObject:upgradable atIndex:0];
3413 [self reloadButtons];
3416 - (void) resetViewAnimated:(BOOL)animated {
3417 [list_ resetViewAnimated:animated];
3420 - (NSString *) leftButtonTitle {
3421 return [(CYBook *)book_ updating] ? nil : @"Refresh";
3424 - (NSString *) rightButtonTitle {
3425 return upgrades_ == 0 ? nil : [NSString stringWithFormat:@"Upgrade All (%u)", upgrades_];
3428 - (NSString *) title {
3434 /* Manage View {{{ */
3435 @interface ManageView : PackageTable {
3438 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3442 @implementation ManageView
3444 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3449 filter:@selector(isInstalledInSection:)
3455 - (NSString *) title {
3456 return @"Installed Packages";
3459 - (NSString *) backButtonTitle {
3460 return @"All Packages";
3465 /* Search View {{{ */
3466 @protocol SearchViewDelegate
3467 - (void) showKeyboard:(BOOL)show;
3470 @interface SearchView : RVPage {
3472 UISearchField *field_;
3473 UITransitionView *transition_;
3474 PackageTable *table_;
3475 UIPreferencesTable *advanced_;
3481 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3482 - (void) reloadData;
3486 @implementation SearchView
3490 [[field_ textTraits] setEditingDelegate:nil];
3492 [field_ setDelegate:nil];
3494 [accessory_ release];
3496 [transition_ release];
3498 [advanced_ release];
3503 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
3507 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
3509 case 0: return @"Advanced Search (Coming Soon!)";
3511 default: _assert(false);
3515 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
3519 default: _assert(false);
3523 - (void) textFieldDidBecomeFirstResponder:(UITextField *)field {
3524 [delegate_ showKeyboard:YES];
3527 - (void) textFieldDidResignFirstResponder:(UITextField *)field {
3528 [delegate_ showKeyboard:NO];
3531 - (void) keyboardInputChanged:(UIFieldEditor *)editor {
3533 NSString *text([field_ text]);
3534 [field_ setClearButtonStyle:(text == nil || [text length] == 0 ? 0 : 2)];
3540 - (void) textFieldClearButtonPressed:(UITextField *)field {
3544 - (void) keyboardInputShouldDelete:(id)input {
3548 - (BOOL) keyboardInput:(id)input shouldInsertText:(NSString *)text isMarkedText:(int)marked {
3549 if ([text length] != 1 || [text characterAtIndex:0] != '\n') {
3553 [field_ resignFirstResponder];
3558 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3559 if ((self = [super initWithBook:book]) != nil) {
3560 CGRect pageBounds = [book_ pageBounds];
3562 /*UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:pageBounds] autorelease];
3563 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
3564 [self addSubview:pinstripe];*/
3566 transition_ = [[UITransitionView alloc] initWithFrame:pageBounds];
3567 [self addSubview:transition_];
3569 advanced_ = [[UIPreferencesTable alloc] initWithFrame:pageBounds];
3571 [advanced_ setReusesTableCells:YES];
3572 [advanced_ setDataSource:self];
3573 [advanced_ reloadData];
3575 dimmed_ = [[UIView alloc] initWithFrame:pageBounds];
3576 CGColor dimmed(space_, 0, 0, 0, 0.5);
3577 [dimmed_ setBackgroundColor:dimmed];
3579 table_ = [[PackageTable alloc]
3583 filter:@selector(isSearchedForBy:)
3587 [table_ setShouldHideHeaderInShortLists:NO];
3588 [transition_ transition:0 toView:table_];
3590 CGRect cnfrect = {{1, 38}, {17, 18}};
3593 area.origin.x = cnfrect.size.width + 15;
3595 area.size.width = [self bounds].size.width - area.origin.x - 18;
3596 area.size.height = [UISearchField defaultHeight];
3598 field_ = [[UISearchField alloc] initWithFrame:area];
3600 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
3601 [field_ setFont:font];
3604 [field_ setPlaceholder:@"Package Names & Descriptions"];
3605 [field_ setPaddingTop:5];
3606 [field_ setDelegate:self];
3609 UITextTraits *traits = [field_ textTraits];
3610 [traits setEditingDelegate:self];
3611 [traits setReturnKeyType:6];
3612 [traits setAutoCapsType:0];
3613 [traits setAutoCorrectionType:1];
3616 UIPushButton *configure = [[[UIPushButton alloc] initWithFrame:cnfrect] autorelease];
3617 [configure setShowPressFeedback:YES];
3618 [configure setImage:[UIImage applicationImageNamed:@"advanced.png"]];
3619 [configure addTarget:self action:@selector(configurePushed) forEvents:1];
3621 accessory_ = [[UIView alloc] initWithFrame:CGRectMake(0, 6, cnfrect.size.width + area.size.width + 6 * 3, area.size.height + 30)];
3622 [accessory_ addSubview:field_];
3623 [accessory_ addSubview:configure];
3628 LKAnimation *animation = [LKTransition animation];
3629 [animation setType:@"oglFlip"];
3630 [animation setTimingFunction:[LKTimingFunction functionWithName:@"easeInEaseOut"]];
3631 [animation setFillMode:@"extended"];
3632 [animation setTransitionFlags:3];
3633 [animation setDuration:10];
3634 [animation setSpeed:0.35];
3635 [animation setSubtype:(flipped_ ? @"fromLeft" : @"fromRight")];
3636 [[transition_ _layer] addAnimation:animation forKey:0];
3637 [transition_ transition:0 toView:(flipped_ ? (UIView *) table_ : (UIView *) advanced_)];
3638 flipped_ = !flipped_;
3641 - (void) configurePushed {
3642 [field_ resignFirstResponder];
3646 - (void) resetViewAnimated:(BOOL)animated {
3649 [table_ resetViewAnimated:animated];
3652 - (void) reloadData {
3655 [table_ setObject:[field_ text]];
3656 [table_ reloadData];
3657 [table_ resetCursor];
3660 - (UIView *) accessoryView {
3664 - (NSString *) title {
3668 - (NSString *) backButtonTitle {
3672 - (void) setDelegate:(id)delegate {
3673 [table_ setDelegate:delegate];
3674 [super setDelegate:delegate];
3680 @implementation CYBook
3684 [indicator_ release];
3686 [progress_ release];
3690 - (NSString *) getTitleForPage:(RVPage *)page {
3691 return Simplify([super getTitleForPage:page]);
3699 [navbar_ setPrompt:@""];
3700 [navbar_ addSubview:overlay_];
3701 [indicator_ startAnimation];
3702 [prompt_ setText:@"Updating Database..."];
3703 [progress_ setProgress:0];
3708 detachNewThreadSelector:@selector(_update)
3717 [overlay_ removeFromSuperview];
3718 [indicator_ stopAnimation];
3719 [delegate_ reloadData];
3721 [self setPrompt:[NSString stringWithFormat:@"Last Updated: %@", GetLastUpdate()]];
3724 - (id) initWithFrame:(CGRect)frame database:(Database *)database {
3725 if ((self = [super initWithFrame:frame]) != nil) {
3726 database_ = database;
3728 CGRect ovrrect = [navbar_ bounds];
3729 ovrrect.size.height = [UINavigationBar defaultSizeWithPrompt].height - [UINavigationBar defaultSize].height;
3731 overlay_ = [[UIView alloc] initWithFrame:ovrrect];
3733 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:2];
3734 unsigned indoffset = (ovrrect.size.height - indsize.height) / 2;
3735 CGRect indrect = {{indoffset, indoffset}, indsize};
3737 indicator_ = [[UIProgressIndicator alloc] initWithFrame:indrect];
3738 [indicator_ setStyle:2];
3739 [overlay_ addSubview:indicator_];
3741 CGSize prmsize = {200, indsize.width};
3744 indoffset * 2 + indsize.width,
3745 (ovrrect.size.height - prmsize.height) / 2
3748 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 12);
3750 prompt_ = [[UITextLabel alloc] initWithFrame:prmrect];
3752 [prompt_ setColor:White_];
3753 [prompt_ setBackgroundColor:Clear_];
3754 [prompt_ setFont:font];
3758 [overlay_ addSubview:prompt_];
3760 CGSize prgsize = {75, 100};
3763 ovrrect.size.width - prgsize.width - 10,
3764 (ovrrect.size.height - prgsize.height) / 2
3767 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
3768 [progress_ setStyle:0];
3769 [overlay_ addSubview:progress_];
3774 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
3777 status.setDelegate(self);
3779 [database_ updateWithStatus:status];
3782 performSelectorOnMainThread:@selector(_update_)
3790 - (void) setProgressError:(NSString *)error {
3792 performSelectorOnMainThread:@selector(_setProgressError:)
3798 - (void) setProgressTitle:(NSString *)title {
3800 performSelectorOnMainThread:@selector(_setProgressTitle:)
3806 - (void) setProgressPercent:(float)percent {
3809 - (void) addProgressOutput:(NSString *)output {
3811 performSelectorOnMainThread:@selector(_addProgressOutput:)
3817 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
3821 - (void) _setProgressError:(NSString *)error {
3822 [prompt_ setText:[NSString stringWithFormat:@"Error: %@", error]];
3825 - (void) _setProgressTitle:(NSString *)title {
3826 [prompt_ setText:[title stringByAppendingString:@"..."]];
3829 - (void) _addProgressOutput:(NSString *)output {
3834 @interface Cydia : UIApplication <
3835 ConfirmationViewDelegate,
3836 ProgressViewDelegate,
3845 UIButtonBar *buttonbar_;
3847 ConfirmationView *confirm_;
3849 Database *database_;
3850 ProgressView *progress_;
3854 UIKeyboard *keyboard_;
3856 InstallView *install_;
3857 ChangesView *changes_;
3858 ManageView *manage_;
3859 SearchView *search_;
3864 @implementation Cydia
3866 - (void) _reloadData {
3867 /*UIProgressHUD *hud = [[UIProgressHUD alloc] initWithWindow:window_];
3868 [hud setText:@"Reloading Data"];
3869 [overlay_ addSubview:hud];
3872 [database_ reloadData];
3874 if (Packages_ == nil) {
3875 Packages_ = [[NSMutableDictionary alloc] initWithCapacity:128];
3876 [Metadata_ setObject:Packages_ forKey:@"Packages"];
3881 NSArray *packages = [database_ packages];
3882 for (int i(0), e([packages count]); i != e; ++i) {
3883 Package *package = [packages objectAtIndex:i];
3884 if ([package upgradable])
3889 NSString *badge([[NSNumber numberWithInt:changes] stringValue]);
3890 [buttonbar_ setBadgeValue:badge forButton:3];
3891 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
3892 [buttonbar_ setBadgeAnimated:YES forButton:3];
3893 [self setApplicationBadge:badge];
3895 [buttonbar_ setBadgeValue:nil forButton:3];
3896 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
3897 [buttonbar_ setBadgeAnimated:NO forButton:3];
3898 [self removeApplicationBadge];
3902 _assert([Metadata_ writeToFile:@"/var/lib/cydia/metadata.plist" atomically:YES] == YES);
3906 /* XXX: this is just stupid */
3908 [install_ reloadData];
3910 [changes_ reloadData];
3912 [manage_ reloadData];
3914 [search_ reloadData];
3919 [hud removeFromSuperview];*/
3922 - (void) reloadData {
3923 @synchronized (self) {
3924 if (confirm_ == nil)
3930 pkgProblemResolver *resolver = [database_ resolver];
3932 resolver->InstallProtect();
3933 if (!resolver->Resolve(true))
3938 [database_ prepare];
3940 if ([database_ cache]->BrokenCount() == 0)
3941 confirm_ = [[ConfirmationView alloc] initWithView:underlay_ database:database_ delegate:self];
3943 NSMutableArray *broken = [NSMutableArray arrayWithCapacity:16];
3944 NSArray *packages = [database_ packages];
3946 for (size_t i(0); i != [packages count]; ++i) {
3947 Package *package = [packages objectAtIndex:i];
3948 if ([package broken])
3949 [broken addObject:[package name]];
3952 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
3953 initWithTitle:[NSString stringWithFormat:@"%d Broken Packages", [database_ cache]->BrokenCount()]
3954 buttons:[NSArray arrayWithObjects:@"Okay", nil]
3955 defaultButtonIndex:0
3960 [sheet setBodyText:[NSString stringWithFormat:@"The following packages have unmet dependencies:\n\n%@", [broken componentsJoinedByString:@"\n"]]];
3961 [sheet popupAlertAnimated:YES];
3967 - (void) installPackage:(Package *)package {
3968 @synchronized (self) {
3975 - (void) removePackage:(Package *)package {
3976 @synchronized (self) {
3983 - (void) distUpgrade {
3984 @synchronized (self) {
3985 [database_ upgrade];
3991 @synchronized (self) {
3999 [overlay_ removeFromSuperview];
4003 detachNewThreadSelector:@selector(perform)
4010 - (void) bootstrap_ {
4012 [database_ upgrade];
4013 [database_ prepare];
4014 [database_ perform];
4017 - (void) bootstrap {
4019 detachNewThreadSelector:@selector(bootstrap_)
4022 title:@"Bootstrap Install..."
4026 - (void) progressViewIsComplete:(ProgressView *)progress {
4027 @synchronized (self) {
4030 if (confirm_ != nil) {
4031 [underlay_ addSubview:overlay_];
4032 [confirm_ removeFromSuperview];
4039 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
4043 - (void) setPage:(RVPage *)page {
4044 [page resetViewAnimated:NO];
4045 [page setDelegate:self];
4046 [book_ setPage:page];
4049 - (RVPage *) _setHomePage {
4050 BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease];
4051 [self setPage:browser];
4052 [browser loadURL:[NSURL URLWithString:@"http://cydia.saurik.com/"]];
4056 - (void) buttonBarItemTapped:(id)sender {
4057 unsigned tag = [sender tag];
4059 [book_ resetViewAnimated:YES];
4064 case 1: [self _setHomePage]; break;
4066 case 2: [self setPage:install_]; break;
4067 case 3: [self setPage:changes_]; break;
4068 case 4: [self setPage:manage_]; break;
4069 case 5: [self setPage:search_]; break;
4071 default: _assert(false);
4077 - (void) applicationWillSuspend {
4078 [super applicationWillSuspend];
4081 if (FW_LEAST(1,1,3))
4082 notify_post("com.apple.language.changed");
4084 system("launchctl stop com.apple.SpringBoard");
4087 - (void) applicationDidFinishLaunching:(id)unused {
4088 _assert(pkgInitConfig(*_config));
4089 _assert(pkgInitSystem(*_config, _system));
4094 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
4095 window_ = [[UIWindow alloc] initWithContentRect:screenrect];
4097 [window_ orderFront: self];
4098 [window_ makeKey: self];
4099 [window_ _setHidden: NO];
4101 progress_ = [[ProgressView alloc] initWithFrame:[window_ bounds] delegate:self];
4102 [window_ setContentView:progress_];
4104 underlay_ = [[UIView alloc] initWithFrame:[progress_ bounds]];
4105 [progress_ setContentView:underlay_];
4107 overlay_ = [[UIView alloc] initWithFrame:[underlay_ bounds]];
4110 [underlay_ addSubview:overlay_];
4112 database_ = [[Database alloc] init];
4113 [database_ setDelegate:progress_];
4115 book_ = [[CYBook alloc] initWithFrame:CGRectMake(
4116 0, 0, screenrect.size.width, screenrect.size.height - 48
4117 ) database:database_];
4119 [book_ setDelegate:self];
4121 [overlay_ addSubview:book_];
4123 NSArray *buttonitems = [NSArray arrayWithObjects:
4124 [NSDictionary dictionaryWithObjectsAndKeys:
4125 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
4126 @"home-up.png", kUIButtonBarButtonInfo,
4127 @"home-dn.png", kUIButtonBarButtonSelectedInfo,
4128 [NSNumber numberWithInt:1], kUIButtonBarButtonTag,
4129 self, kUIButtonBarButtonTarget,
4130 @"Home", kUIButtonBarButtonTitle,
4131 @"0", kUIButtonBarButtonType,
4134 [NSDictionary dictionaryWithObjectsAndKeys:
4135 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
4136 @"install-up.png", kUIButtonBarButtonInfo,
4137 @"install-dn.png", kUIButtonBarButtonSelectedInfo,
4138 [NSNumber numberWithInt:2], kUIButtonBarButtonTag,
4139 self, kUIButtonBarButtonTarget,
4140 @"Install", kUIButtonBarButtonTitle,
4141 @"0", kUIButtonBarButtonType,
4144 [NSDictionary dictionaryWithObjectsAndKeys:
4145 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
4146 @"changes-up.png", kUIButtonBarButtonInfo,
4147 @"changes-dn.png", kUIButtonBarButtonSelectedInfo,
4148 [NSNumber numberWithInt:3], kUIButtonBarButtonTag,
4149 self, kUIButtonBarButtonTarget,
4150 @"Changes", kUIButtonBarButtonTitle,
4151 @"0", kUIButtonBarButtonType,
4154 [NSDictionary dictionaryWithObjectsAndKeys:
4155 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
4156 @"manage-up.png", kUIButtonBarButtonInfo,
4157 @"manage-dn.png", kUIButtonBarButtonSelectedInfo,
4158 [NSNumber numberWithInt:4], kUIButtonBarButtonTag,
4159 self, kUIButtonBarButtonTarget,
4160 @"Manage", kUIButtonBarButtonTitle,
4161 @"0", kUIButtonBarButtonType,
4164 [NSDictionary dictionaryWithObjectsAndKeys:
4165 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
4166 @"search-up.png", kUIButtonBarButtonInfo,
4167 @"search-dn.png", kUIButtonBarButtonSelectedInfo,
4168 [NSNumber numberWithInt:5], kUIButtonBarButtonTag,
4169 self, kUIButtonBarButtonTarget,
4170 @"Search", kUIButtonBarButtonTitle,
4171 @"0", kUIButtonBarButtonType,
4175 buttonbar_ = [[UIButtonBar alloc]
4177 withFrame:CGRectMake(
4178 0, screenrect.size.height - 48,
4179 screenrect.size.width, 48
4181 withItemList:buttonitems
4184 [buttonbar_ setDelegate:self];
4185 [buttonbar_ setBarStyle:1];
4186 [buttonbar_ setButtonBarTrackingMode:2];
4188 int buttons[5] = {1, 2, 3, 4, 5};
4189 [buttonbar_ registerButtonGroup:0 withButtons:buttons withCount:5];
4190 [buttonbar_ showButtonGroup:0 withDuration:0];
4192 for (int i = 0; i != 5; ++i)
4193 [[buttonbar_ viewWithTag:(i + 1)] setFrame:CGRectMake(
4194 i * 64 + 2, 1, 60, 48
4197 [buttonbar_ showSelectionForButton:1];
4198 [overlay_ addSubview:buttonbar_];
4200 [UIKeyboard initImplementationNow];
4201 CGSize keysize = [UIKeyboard defaultSize];
4202 CGRect keyrect = {{0, [overlay_ bounds].size.height}, keysize};
4203 keyboard_ = [[UIKeyboard alloc] initWithFrame:keyrect];
4204 [[UIKeyboardImpl sharedInstance] setSoundsEnabled:(Sounds_Keyboard_ ? YES : NO)];
4205 [overlay_ addSubview:keyboard_];
4207 install_ = [[InstallView alloc] initWithBook:book_ database:database_];
4208 changes_ = [[ChangesView alloc] initWithBook:book_ database:database_];
4209 manage_ = [[ManageView alloc] initWithBook:book_ database:database_];
4210 search_ = [[SearchView alloc] initWithBook:book_ database:database_];
4215 [progress_ resetView];
4220 [self _setHomePage];
4223 - (void) showKeyboard:(BOOL)show {
4224 CGSize keysize = [UIKeyboard defaultSize];
4225 CGRect keydown = {{0, [overlay_ bounds].size.height}, keysize};
4226 CGRect keyup = keydown;
4227 keyup.origin.y -= keysize.height;
4229 UIFrameAnimation *animation = [[[UIFrameAnimation alloc] initWithTarget:keyboard_] autorelease];
4230 [animation setSignificantRectFields:2];
4233 [animation setStartFrame:keydown];
4234 [animation setEndFrame:keyup];
4235 [keyboard_ activate];
4237 [animation setStartFrame:keyup];
4238 [animation setEndFrame:keydown];
4239 [keyboard_ deactivate];
4242 [[UIAnimator sharedAnimator]
4243 addAnimations:[NSArray arrayWithObjects:animation, nil]
4249 - (void) slideUp:(UIAlertSheet *)alert {
4250 [alert presentSheetFromButtonBar:buttonbar_];
4255 void AddPreferences(NSString *plist) {
4256 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
4258 NSMutableDictionary *settings = [[[NSMutableDictionary alloc] initWithContentsOfFile:plist] autorelease];
4259 _assert(settings != NULL);
4260 NSMutableArray *items = [settings objectForKey:@"items"];
4264 for (size_t i(0); i != [items count]; ++i) {
4265 NSMutableDictionary *item([items objectAtIndex:i]);
4266 NSString *label = [item objectForKey:@"label"];
4267 if (label != nil && [label isEqualToString:@"Cydia"]) {
4274 for (size_t i(0); i != [items count]; ++i) {
4275 NSDictionary *item([items objectAtIndex:i]);
4276 NSString *label = [item objectForKey:@"label"];
4277 if (label != nil && [label isEqualToString:@"General"]) {
4278 [items insertObject:[NSDictionary dictionaryWithObjectsAndKeys:
4279 @"CydiaSettings", @"bundle",
4280 @"PSLinkCell", @"cell",
4281 [NSNumber numberWithBool:YES], @"hasIcon",
4282 [NSNumber numberWithBool:YES], @"isController",
4284 nil] atIndex:(i + 1)];
4290 _assert([settings writeToFile:plist atomically:YES] == YES);
4297 id Alloc_(id self, SEL selector) {
4298 id object = alloc_(self, selector);
4299 fprintf(stderr, "[%s]A-%p\n", self->isa->name, object);
4304 id Dealloc_(id self, SEL selector) {
4305 id object = dealloc_(self, selector);
4306 fprintf(stderr, "[%s]D-%p\n", self->isa->name, object);
4310 int main(int argc, char *argv[]) {
4311 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
4313 bootstrap_ = argc > 1 && strcmp(argv[1], "--bootstrap") == 0;
4315 Home_ = NSHomeDirectory();
4318 NSString *plist = [Home_ stringByAppendingString:@"/Library/Preferences/com.apple.preferences.sounds.plist"];
4319 if (NSDictionary *sounds = [NSDictionary dictionaryWithContentsOfFile:plist])
4320 if (NSNumber *keyboard = [sounds objectForKey:@"keyboard"])
4321 Sounds_Keyboard_ = [keyboard boolValue];
4327 /*Method alloc = class_getClassMethod([NSObject class], @selector(alloc));
4328 alloc_ = alloc->method_imp;
4329 alloc->method_imp = (IMP) &Alloc_;*/
4331 /*Method dealloc = class_getClassMethod([NSObject class], @selector(dealloc));
4332 dealloc_ = dealloc->method_imp;
4333 dealloc->method_imp = (IMP) &Dealloc_;*/
4335 if (NSDictionary *sysver = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]) {
4336 if (NSString *prover = [sysver valueForKey:@"ProductVersion"]) {
4337 Firmware_ = strdup([prover UTF8String]);
4338 NSArray *versions = [prover componentsSeparatedByString:@"."];
4339 int count = [versions count];
4340 Major_ = count > 0 ? [[versions objectAtIndex:0] intValue] : 0;
4341 Minor_ = count > 1 ? [[versions objectAtIndex:1] intValue] : 0;
4342 BugFix_ = count > 2 ? [[versions objectAtIndex:2] intValue] : 0;
4347 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
4348 char *machine = new char[size];
4349 sysctlbyname("hw.machine", machine, &size, NULL, 0);
4352 if (CFMutableDictionaryRef dict = IOServiceMatching("IOPlatformExpertDevice"))
4353 if (io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, dict)) {
4354 if (CFTypeRef serial = IORegistryEntryCreateCFProperty(service, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0)) {
4355 SerialNumber_ = strdup(CFStringGetCStringPtr((CFStringRef) serial, CFStringGetSystemEncoding()));
4359 IOObjectRelease(service);
4362 /*AddPreferences(@"/Applications/Preferences.app/Settings-iPhone.plist");
4363 AddPreferences(@"/Applications/Preferences.app/Settings-iPod.plist");*/
4365 if ((Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"]) == NULL)
4366 Metadata_ = [[NSMutableDictionary alloc] initWithCapacity:2];
4368 Packages_ = [Metadata_ objectForKey:@"Packages"];
4370 setenv("CYDIA", "", _not(int));
4371 if (access("/User", F_OK) != 0)
4372 system("/usr/libexec/cydia/firmware.sh");
4373 system("dpkg --configure -a");
4375 space_ = CGColorSpaceCreateDeviceRGB();
4377 Black_.Set(space_, 0.0, 0.0, 0.0, 1.0);
4378 Clear_.Set(space_, 0.0, 0.0, 0.0, 0.0);
4379 Red_.Set(space_, 1.0, 0.0, 0.0, 1.0);
4380 White_.Set(space_, 1.0, 1.0, 1.0, 1.0);
4382 int value = UIApplicationMain(argc, argv, [Cydia class]);
4384 CGColorSpaceRelease(space_);