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/clean.h>
65 #include <apt-pkg/configuration.h>
66 #include <apt-pkg/debmetaindex.h>
67 #include <apt-pkg/error.h>
68 #include <apt-pkg/init.h>
69 #include <apt-pkg/pkgrecords.h>
70 #include <apt-pkg/sourcelist.h>
71 #include <apt-pkg/sptr.h>
73 #include <sys/sysctl.h>
77 #include <mach-o/nlist.h>
88 /* iPhoneOS 2.0 Compatibility {{{ */
90 @interface UICGColor : NSObject {
93 - (id) initWithCGColor:(CGColorRef)color;
99 - (UIFont *) fontWithSize:(CGFloat)size;
102 @interface NSObject (iPhoneOS)
103 - (CGColorRef) cgColor;
104 - (CGColorRef) CGColor;
108 @implementation NSObject (iPhoneOS)
110 - (CGColorRef) cgColor {
111 return [self CGColor];
114 - (CGColorRef) CGColor {
115 return (CGColorRef) self;
119 [[[[objc_getClass("UICGColor") alloc] initWithCGColor:[self CGColor]] autorelease] set];
124 @interface UITextView (iPhoneOS)
125 - (void) setTextSize:(float)size;
128 @implementation UITextView (iPhoneOS)
130 - (void) setTextSize:(float)size {
131 [self setFont:[[self font] fontWithSize:size]];
140 kUIProgressIndicatorStyleMediumWhite = 1,
141 kUIProgressIndicatorStyleSmallWhite = 0,
142 kUIProgressIndicatorStyleSmallBlack = 4
143 } UIProgressIndicatorStyle;
146 kUIProgressIndicatorStyleMediumWhite = 0,
147 kUIProgressIndicatorStyleSmallWhite = 2,
148 kUIProgressIndicatorStyleSmallBlack = 3
149 } UIProgressIndicatorStyle;
153 kUIControlEventMouseDown = 1 << 0,
154 kUIControlEventMouseMovedInside = 1 << 2, // mouse moved inside control target
155 kUIControlEventMouseMovedOutside = 1 << 3, // mouse moved outside control target
156 kUIControlEventMouseUpInside = 1 << 6, // mouse up inside control target
157 kUIControlEventMouseUpOutside = 1 << 7, // mouse up outside control target
158 kUIControlAllEvents = (kUIControlEventMouseDown | kUIControlEventMouseMovedInside | kUIControlEventMouseMovedOutside | kUIControlEventMouseUpInside | kUIControlEventMouseUpOutside)
159 } UIControlEventMasks;
161 @interface NSString (UIKit)
162 - (NSString *) stringByAddingPercentEscapes;
163 - (NSString *) stringByReplacingCharacter:(unsigned short)arg0 withCharacter:(unsigned short)arg1;
166 @interface NSString (Cydia)
167 + (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length;
168 - (NSComparisonResult) compareByPath:(NSString *)other;
171 @implementation NSString (Cydia)
173 + (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length {
174 char data[length + 1];
175 memcpy(data, bytes, length);
177 return [NSString stringWithUTF8String:data];
180 - (NSComparisonResult) compareByPath:(NSString *)other {
181 NSString *prefix = [self commonPrefixWithString:other options:0];
182 size_t length = [prefix length];
184 NSRange lrange = NSMakeRange(length, [self length] - length);
185 NSRange rrange = NSMakeRange(length, [other length] - length);
187 lrange = [self rangeOfString:@"/" options:0 range:lrange];
188 rrange = [other rangeOfString:@"/" options:0 range:rrange];
190 NSComparisonResult value;
192 if (lrange.location == NSNotFound && rrange.location == NSNotFound)
193 value = NSOrderedSame;
194 else if (lrange.location == NSNotFound)
195 value = NSOrderedAscending;
196 else if (rrange.location == NSNotFound)
197 value = NSOrderedDescending;
199 value = NSOrderedSame;
201 NSString *lpath = lrange.location == NSNotFound ? [self substringFromIndex:length] :
202 [self substringWithRange:NSMakeRange(length, lrange.location - length)];
203 NSString *rpath = rrange.location == NSNotFound ? [other substringFromIndex:length] :
204 [other substringWithRange:NSMakeRange(length, rrange.location - length)];
206 NSComparisonResult result = [lpath compare:rpath];
207 return result == NSOrderedSame ? value : result;
212 /* Perl-Compatible RegEx {{{ */
222 Pcre(const char *regex) :
227 code_ = pcre_compile(regex, 0, &error, &offset, NULL);
230 fprintf(stderr, "%d:%s\n", offset, error);
234 pcre_fullinfo(code_, study_, PCRE_INFO_CAPTURECOUNT, &capture_);
235 matches_ = new int[(capture_ + 1) * 3];
243 NSString *operator [](size_t match) {
244 return [NSString stringWithUTF8Bytes:(data_ + matches_[match * 2]) length:(matches_[match * 2 + 1] - matches_[match * 2])];
247 bool operator ()(NSString *data) {
248 // XXX: length is for characters, not for bytes
249 return operator ()([data UTF8String], [data length]);
252 bool operator ()(const char *data, size_t size) {
254 return pcre_exec(code_, study_, data, size, 0, 0, matches_, (capture_ + 1) * 3) >= 0;
258 /* Mime Addresses {{{ */
259 Pcre email_r("^\"?(.*)\"? <([^>]*)>$");
261 @interface Address : NSObject {
267 - (NSString *) email;
269 + (Address *) addressWithString:(NSString *)string;
270 - (Address *) initWithString:(NSString *)string;
273 @implementation Address
282 - (NSString *) name {
286 - (NSString *) email {
290 + (Address *) addressWithString:(NSString *)string {
291 return [[[Address alloc] initWithString:string] autorelease];
294 - (Address *) initWithString:(NSString *)string {
295 if ((self = [super init]) != nil) {
296 const char *data = [string UTF8String];
297 size_t size = [string length];
299 if (email_r(data, size)) {
300 name_ = [email_r[1] retain];
301 email_ = [email_r[2] retain];
303 name_ = [[NSString alloc]
306 encoding:kCFStringEncodingUTF8
316 /* CoreGraphics Primitives {{{ */
327 CGColor(CGColorSpaceRef space, float red, float green, float blue, float alpha) :
330 Set(space, red, green, blue, alpha);
335 CGColorRelease(color_);
342 void Set(CGColorSpaceRef space, float red, float green, float blue, float alpha) {
344 float color[] = {red, green, blue, alpha};
345 color_ = CGColorCreate(space, color);
348 operator CGColorRef() {
363 /* Right Alignment {{{ */
364 @interface UIRightTextLabel : UITextLabel {
365 float _savedRightEdgeX;
366 BOOL _sizedtofit_flag;
369 - (void) setFrame:(CGRect)frame;
370 - (void) setText:(NSString *)text;
371 - (void) realignText;
374 @implementation UIRightTextLabel
376 - (void) setFrame:(CGRect)frame {
377 [super setFrame:frame];
378 if (_sizedtofit_flag == NO) {
379 _savedRightEdgeX = frame.origin.x;
384 - (void) setText:(NSString *)text {
385 [super setText:text];
389 - (void) realignText {
390 CGRect oldFrame = [self frame];
392 _sizedtofit_flag = YES;
393 [self sizeToFit]; // shrink down size so I can right align it
395 CGRect newFrame = [self frame];
397 oldFrame.origin.x = _savedRightEdgeX - newFrame.size.width;
398 oldFrame.size.width = newFrame.size.width;
399 [super setFrame:oldFrame];
400 _sizedtofit_flag = NO;
406 /* Random Global Variables {{{ */
407 static const int PulseInterval_ = 50000;
408 static const int ButtonBarHeight_ = 48;
409 static const float KeyboardTime_ = 0.4f;
410 static const char * const SpringBoard_ = "/System/Library/LaunchDaemons/com.apple.SpringBoard.plist";
416 static CGColor Blueish_;
417 static CGColor Black_;
418 static CGColor Clear_;
420 static CGColor White_;
422 static NSString *Home_;
423 static BOOL Sounds_Keyboard_;
425 static BOOL Advanced_;
427 static BOOL Ignored_;
429 const char *Firmware_ = NULL;
430 const char *Machine_ = NULL;
431 const char *SerialNumber_ = NULL;
438 CGColorSpaceRef space_;
440 #define FW_LEAST(major, minor, bugfix) \
441 (major < Major_ || major == Major_ && \
442 (minor < Minor_ || minor == Minor_ && \
448 static NSMutableDictionary *Metadata_;
449 static NSMutableDictionary *Packages_;
450 static bool Changed_;
453 NSString *GetLastUpdate() {
454 NSDate *update = [Metadata_ objectForKey:@"LastUpdate"];
457 return @"Never or Unknown";
459 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, Locale_, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
460 CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) update);
462 CFRelease(formatter);
464 return [(NSString *) formatted autorelease];
467 /* Display Helpers {{{ */
468 inline float Interpolate(float begin, float end, float fraction) {
469 return (end - begin) * fraction + begin;
472 NSString *SizeString(double size) {
474 while (size > 1024) {
479 static const char *powers_[] = {"B", "kB", "MB", "GB"};
481 return [NSString stringWithFormat:@"%.1f%s", size, powers_[power]];
484 NSString *StripVersion(NSString *version) {
485 NSRange colon = [version rangeOfString:@":"];
486 if (colon.location != NSNotFound)
487 version = [version substringFromIndex:(colon.location + 1)];
491 static const float TextViewOffset_ = 22;
493 UITextView *GetTextView(NSString *value, float left, bool html) {
494 UITextView *text([[[UITextView alloc] initWithFrame:CGRectMake(left, 3, 310 - left, 1000)] autorelease]);
495 [text setEditable:NO];
496 [text setTextSize:16];
498 [text setHTML:value];
500 [text setText:value];
501 [text setEnabled:NO];
503 [text setBackgroundColor:Clear_];
505 CGRect frame = [text frame];
506 [text setFrame:frame];
507 CGRect rect = [text visibleTextRect];
508 frame.size.height = rect.size.height;
509 [text setFrame:frame];
514 NSString *Simplify(NSString *title) {
515 const char *data = [title UTF8String];
516 size_t size = [title length];
518 Pcre title_r("^(.*?)( \\(.*\\))?$");
519 if (title_r(data, size))
526 /* Delegate Prototypes {{{ */
530 @interface NSObject (ProgressDelegate)
533 @implementation NSObject(ProgressDelegate)
535 - (void) _setProgressError:(NSArray *)args {
536 [self performSelector:@selector(setProgressError:forPackage:)
537 withObject:[args objectAtIndex:0]
538 withObject:([args count] == 1 ? nil : [args objectAtIndex:1])
544 @protocol ProgressDelegate
545 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id;
546 - (void) setProgressTitle:(NSString *)title;
547 - (void) setProgressPercent:(float)percent;
548 - (void) addProgressOutput:(NSString *)output;
551 @protocol ConfigurationDelegate
552 - (void) repairWithSelector:(SEL)selector;
553 - (void) setConfigurationData:(NSString *)data;
556 @protocol CydiaDelegate
557 - (void) installPackage:(Package *)package;
558 - (void) removePackage:(Package *)package;
559 - (void) slideUp:(UIAlertSheet *)alert;
560 - (void) distUpgrade;
564 /* Status Delegation {{{ */
566 public pkgAcquireStatus
569 _transient NSObject<ProgressDelegate> *delegate_;
577 void setDelegate(id delegate) {
578 delegate_ = delegate;
581 virtual bool MediaChange(std::string media, std::string drive) {
585 virtual void IMSHit(pkgAcquire::ItemDesc &item) {
588 virtual void Fetch(pkgAcquire::ItemDesc &item) {
589 [delegate_ setProgressTitle:[NSString stringWithUTF8String:("Downloading " + item.ShortDesc).c_str()]];
592 virtual void Done(pkgAcquire::ItemDesc &item) {
595 virtual void Fail(pkgAcquire::ItemDesc &item) {
597 item.Owner->Status == pkgAcquire::Item::StatIdle ||
598 item.Owner->Status == pkgAcquire::Item::StatDone
602 [delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
603 withObject:[NSArray arrayWithObjects:[NSString stringWithUTF8String:item.Owner->ErrorText.c_str()], nil]
608 virtual bool Pulse(pkgAcquire *Owner) {
609 bool value = pkgAcquireStatus::Pulse(Owner);
612 double(CurrentBytes + CurrentItems) /
613 double(TotalBytes + TotalItems)
616 [delegate_ setProgressPercent:percent];
620 virtual void Start() {
623 virtual void Stop() {
627 /* Progress Delegation {{{ */
632 _transient id<ProgressDelegate> delegate_;
635 virtual void Update() {
636 [delegate_ setProgressTitle:[NSString stringWithUTF8String:Op.c_str()]];
637 [delegate_ setProgressPercent:(Percent / 100)];
646 void setDelegate(id delegate) {
647 delegate_ = delegate;
650 virtual void Done() {
651 [delegate_ setProgressPercent:1];
656 /* Database Interface {{{ */
657 @interface Database : NSObject {
659 pkgDepCache::Policy *policy_;
660 pkgRecords *records_;
661 pkgProblemResolver *resolver_;
662 pkgAcquire *fetcher_;
664 SPtr<pkgPackageManager> manager_;
665 pkgSourceList *list_;
667 NSMutableDictionary *sources_;
668 NSMutableArray *packages_;
670 _transient NSObject<ConfigurationDelegate, ProgressDelegate> *delegate_;
679 - (void) _readCydia:(NSNumber *)fd;
680 - (void) _readStatus:(NSNumber *)fd;
681 - (void) _readOutput:(NSNumber *)fd;
685 - (Package *) packageWithName:(NSString *)name;
688 - (pkgCacheFile &) cache;
689 - (pkgDepCache::Policy *) policy;
690 - (pkgRecords *) records;
691 - (pkgProblemResolver *) resolver;
692 - (pkgAcquire &) fetcher;
693 - (NSArray *) packages;
702 - (void) updateWithStatus:(Status &)status;
704 - (void) setDelegate:(id)delegate;
705 - (Source *) getSource:(const pkgCache::PkgFileIterator &)file;
709 /* Source Class {{{ */
710 @interface Source : NSObject {
711 NSString *description_;
716 NSString *distribution_;
720 NSString *defaultIcon_;
725 - (Source *) initWithMetaIndex:(metaIndex *)index;
730 - (NSString *) distribution;
733 - (NSString *) description;
734 - (NSString *) label;
735 - (NSString *) origin;
736 - (NSString *) version;
738 - (NSString *) defaultIcon;
741 @implementation Source
745 [distribution_ release];
748 if (description_ != nil)
749 [description_ release];
756 if (defaultIcon_ != nil)
757 [defaultIcon_ release];
762 - (Source *) initWithMetaIndex:(metaIndex *)index {
763 if ((self = [super init]) != nil) {
764 trusted_ = index->IsTrusted();
766 uri_ = [[NSString stringWithUTF8String:index->GetURI().c_str()] retain];
767 distribution_ = [[NSString stringWithUTF8String:index->GetDist().c_str()] retain];
768 type_ = [[NSString stringWithUTF8String:index->GetType()] retain];
776 debReleaseIndex *dindex(dynamic_cast<debReleaseIndex *>(index));
777 if (dindex != NULL) {
778 std::ifstream release(dindex->MetaIndexFile("Release").c_str());
780 while (std::getline(release, line)) {
781 std::string::size_type colon(line.find(':'));
782 if (colon == std::string::npos)
785 std::string name(line.substr(0, colon));
786 std::string value(line.substr(colon + 1));
787 while (!value.empty() && value[0] == ' ')
788 value = value.substr(1);
790 if (name == "Default-Icon")
791 defaultIcon_ = [[NSString stringWithUTF8String:value.c_str()] retain];
792 else if (name == "Description")
793 description_ = [[NSString stringWithUTF8String:value.c_str()] retain];
794 else if (name == "Label")
795 label_ = [[NSString stringWithUTF8String:value.c_str()] retain];
796 else if (name == "Origin")
797 origin_ = [[NSString stringWithUTF8String:value.c_str()] retain];
798 else if (name == "Version")
799 version_ = [[NSString stringWithUTF8String:value.c_str()] retain];
813 - (NSString *) distribution {
814 return distribution_;
817 - (NSString *) type {
821 - (NSString *) description {
825 - (NSString *) label {
829 - (NSString *) origin {
833 - (NSString *) version {
837 - (NSString *) defaultIcon {
843 /* Relationship Class {{{ */
844 @interface Relationship : NSObject {
855 @implementation Relationship
863 - (NSString *) type {
871 - (NSString *) name {
878 /* Package Class {{{ */
879 NSString *Scour(const char *field, const char *begin, const char *end) {
880 size_t i(0), l(strlen(field));
883 const char *name = begin + i;
884 const char *colon = name + l;
885 const char *value = colon + 1;
890 memcmp(name, field, l) == 0
892 while (value != end && value[0] == ' ')
894 const char *line = std::find(value, end, '\n');
895 while (line != value && line[-1] == ' ')
898 return [NSString stringWithUTF8Bytes:value length:(line - value)];
900 begin = std::find(begin, end, '\n');
908 @interface Package : NSObject {
909 pkgCache::PkgIterator iterator_;
910 _transient Database *database_;
911 pkgCache::VerIterator version_;
912 pkgCache::VerFileIterator file_;
918 NSString *installed_;
928 NSArray *relationships_;
931 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
932 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
934 - (pkgCache::PkgIterator) iterator;
936 - (NSString *) section;
937 - (Address *) maintainer;
939 - (NSString *) description;
940 - (NSString *) index;
944 - (NSString *) latest;
945 - (NSString *) installed;
948 - (BOOL) upgradableAndEssential:(BOOL)essential;
953 - (BOOL) halfConfigured;
954 - (BOOL) halfInstalled;
960 - (NSString *) tagline;
962 - (NSString *) website;
963 - (Address *) author;
965 - (NSArray *) relationships;
969 - (BOOL) matches:(NSString *)text;
971 - (NSComparisonResult) compareByName:(Package *)package;
972 - (NSComparisonResult) compareBySection:(Package *)package;
973 - (NSComparisonResult) compareBySectionAndName:(Package *)package;
974 - (NSComparisonResult) compareForChanges:(Package *)package;
979 - (NSNumber *) isSearchedForBy:(NSString *)search;
980 - (NSNumber *) isInstalledInSection:(NSString *)section;
981 - (NSNumber *) isUninstalledInSection:(NSString *)section;
985 @implementation Package
992 if (installed_ != nil)
993 [installed_ release];
1001 if (website_ != nil)
1003 if (sponsor_ != nil)
1008 if (relationships_ != nil)
1009 [relationships_ release];
1014 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
1015 if ((self = [super init]) != nil) {
1016 iterator_ = iterator;
1017 database_ = database;
1019 version_ = [database_ policy]->GetCandidateVer(iterator_);
1020 latest_ = version_.end() ? nil : [StripVersion([NSString stringWithUTF8String:version_.VerStr()]) retain];
1022 if (!version_.end())
1023 file_ = version_.FileList();
1025 pkgCache &cache([database_ cache]);
1026 file_ = pkgCache::VerFileIterator(cache, cache.VerFileP);
1029 pkgCache::VerIterator current = iterator_.CurrentVer();
1030 installed_ = current.end() ? nil : [StripVersion([NSString stringWithUTF8String:current.VerStr()]) retain];
1032 id_ = [[[NSString stringWithUTF8String:iterator_.Name()] lowercaseString] retain];
1035 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1037 const char *begin, *end;
1038 parser->GetRec(begin, end);
1040 name_ = Scour("Name", begin, end);
1042 name_ = [name_ retain];
1043 tagline_ = [[NSString stringWithUTF8String:parser->ShortDesc().c_str()] retain];
1044 icon_ = Scour("Icon", begin, end);
1046 icon_ = [icon_ retain];
1047 website_ = Scour("Homepage", begin, end);
1048 if (website_ == nil)
1049 website_ = Scour("Website", begin, end);
1050 if (website_ != nil)
1051 website_ = [website_ retain];
1052 NSString *sponsor = Scour("Sponsor", begin, end);
1054 sponsor_ = [[Address addressWithString:sponsor] retain];
1055 NSString *author = Scour("Author", begin, end);
1057 author_ = [[Address addressWithString:author] retain];
1060 NSMutableDictionary *metadata = [Packages_ objectForKey:id_];
1061 if (metadata == nil || [metadata count] == 0) {
1062 metadata = [NSMutableDictionary dictionaryWithObjectsAndKeys:
1066 [Packages_ setObject:metadata forKey:id_];
1072 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
1073 return [[[Package alloc]
1074 initWithIterator:iterator
1079 - (pkgCache::PkgIterator) iterator {
1083 - (NSString *) section {
1084 const char *section = iterator_.Section();
1085 return section == NULL ? nil : [[NSString stringWithUTF8String:section] stringByReplacingCharacter:'_' withCharacter:' '];
1088 - (Address *) maintainer {
1091 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1092 return [Address addressWithString:[NSString stringWithUTF8String:parser->Maintainer().c_str()]];
1096 return version_.end() ? 0 : version_->InstalledSize;
1099 - (NSString *) description {
1102 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1103 NSString *description([NSString stringWithUTF8String:parser->LongDesc().c_str()]);
1105 NSArray *lines = [description componentsSeparatedByString:@"\n"];
1106 NSMutableArray *trimmed = [NSMutableArray arrayWithCapacity:([lines count] - 1)];
1107 if ([lines count] < 2)
1110 NSCharacterSet *whitespace = [NSCharacterSet whitespaceCharacterSet];
1111 for (size_t i(1); i != [lines count]; ++i) {
1112 NSString *trim = [[lines objectAtIndex:i] stringByTrimmingCharactersInSet:whitespace];
1113 [trimmed addObject:trim];
1116 return [trimmed componentsJoinedByString:@"\n"];
1119 - (NSString *) index {
1120 NSString *index = [[[self name] substringToIndex:1] uppercaseString];
1121 return [index length] != 0 && isalpha([index characterAtIndex:0]) ? index : @"123";
1125 return [[Packages_ objectForKey:id_] objectForKey:@"FirstSeen"];
1128 - (NSString *) latest {
1132 - (NSString *) installed {
1137 return !version_.end();
1140 - (BOOL) upgradableAndEssential:(BOOL)essential {
1141 pkgCache::VerIterator current = iterator_.CurrentVer();
1144 return essential && [self essential];
1146 pkgCache::VerIterator candidate = [database_ policy]->GetCandidateVer(iterator_);
1147 return !candidate.end() && candidate != current;
1151 - (BOOL) essential {
1152 return (iterator_->Flags & pkgCache::Flag::Essential) == 0 ? NO : YES;
1156 return [database_ cache][iterator_].InstBroken();
1160 unsigned char current = iterator_->CurrentState;
1161 return current == pkgCache::State::HalfConfigured || current == pkgCache::State::HalfInstalled;
1164 - (BOOL) halfConfigured {
1165 return iterator_->CurrentState == pkgCache::State::HalfConfigured;
1168 - (BOOL) halfInstalled {
1169 return iterator_->CurrentState == pkgCache::State::HalfInstalled;
1173 pkgDepCache::StateCache &state([database_ cache][iterator_]);
1174 return state.Mode != pkgDepCache::ModeKeep;
1177 - (NSString *) mode {
1178 pkgDepCache::StateCache &state([database_ cache][iterator_]);
1180 switch (state.Mode) {
1181 case pkgDepCache::ModeDelete:
1182 if ((state.iFlags & pkgDepCache::Purge) != 0)
1187 case pkgDepCache::ModeKeep:
1188 if ((state.iFlags & pkgDepCache::AutoKept) != 0)
1193 case pkgDepCache::ModeInstall:
1194 if ((state.iFlags & pkgDepCache::ReInstall) != 0)
1195 return @"Reinstall";
1196 else switch (state.Status) {
1198 return @"Downgrade";
1204 return @"New Install";
1217 - (NSString *) name {
1218 return name_ == nil ? id_ : name_;
1221 - (NSString *) tagline {
1225 - (NSString *) icon {
1229 - (NSString *) website {
1233 - (Address *) sponsor {
1237 - (Address *) author {
1241 - (NSArray *) relationships {
1242 return relationships_;
1245 - (Source *) source {
1247 source_ = file_.end() ? nil : [[database_ getSource:file_.File()] retain];
1254 - (BOOL) matches:(NSString *)text {
1260 range = [[self id] rangeOfString:text options:NSCaseInsensitiveSearch];
1261 if (range.location != NSNotFound)
1264 range = [[self name] rangeOfString:text options:NSCaseInsensitiveSearch];
1265 if (range.location != NSNotFound)
1268 range = [[self tagline] rangeOfString:text options:NSCaseInsensitiveSearch];
1269 if (range.location != NSNotFound)
1275 - (NSComparisonResult) compareByName:(Package *)package {
1276 NSString *lhs = [self name];
1277 NSString *rhs = [package name];
1279 if ([lhs length] != 0 && [rhs length] != 0) {
1280 unichar lhc = [lhs characterAtIndex:0];
1281 unichar rhc = [rhs characterAtIndex:0];
1283 if (isalpha(lhc) && !isalpha(rhc))
1284 return NSOrderedAscending;
1285 else if (!isalpha(lhc) && isalpha(rhc))
1286 return NSOrderedDescending;
1289 return [lhs caseInsensitiveCompare:rhs];
1292 - (NSComparisonResult) compareBySection:(Package *)package {
1293 NSString *lhs = [self section];
1294 NSString *rhs = [package section];
1296 if (lhs == NULL && rhs != NULL)
1297 return NSOrderedAscending;
1298 else if (lhs != NULL && rhs == NULL)
1299 return NSOrderedDescending;
1300 else if (lhs != NULL && rhs != NULL) {
1301 NSComparisonResult result = [lhs caseInsensitiveCompare:rhs];
1302 if (result != NSOrderedSame)
1306 return NSOrderedSame;
1309 - (NSComparisonResult) compareBySectionAndName:(Package *)package {
1310 NSString *lhs = [self section];
1311 NSString *rhs = [package section];
1313 if (lhs == NULL && rhs != NULL)
1314 return NSOrderedAscending;
1315 else if (lhs != NULL && rhs == NULL)
1316 return NSOrderedDescending;
1317 else if (lhs != NULL && rhs != NULL) {
1318 NSComparisonResult result = [lhs compare:rhs];
1319 if (result != NSOrderedSame)
1323 return [self compareByName:package];
1326 - (NSComparisonResult) compareForChanges:(Package *)package {
1327 BOOL lhs = [self upgradableAndEssential:YES];
1328 BOOL rhs = [package upgradableAndEssential:YES];
1331 return lhs ? NSOrderedAscending : NSOrderedDescending;
1333 switch ([[self seen] compare:[package seen]]) {
1334 case NSOrderedAscending:
1335 return NSOrderedDescending;
1338 case NSOrderedDescending:
1339 return NSOrderedAscending;
1345 return [self compareByName:package];
1349 pkgProblemResolver *resolver = [database_ resolver];
1350 resolver->Clear(iterator_);
1351 resolver->Protect(iterator_);
1352 pkgCacheFile &cache([database_ cache]);
1353 cache->MarkInstall(iterator_, false);
1354 pkgDepCache::StateCache &state((*cache)[iterator_]);
1355 if (!state.Install())
1356 cache->SetReInstall(iterator_, true);
1360 pkgProblemResolver *resolver = [database_ resolver];
1361 resolver->Clear(iterator_);
1362 resolver->Protect(iterator_);
1363 resolver->Remove(iterator_);
1364 [database_ cache]->MarkDelete(iterator_, true);
1367 - (NSNumber *) isSearchedForBy:(NSString *)search {
1368 return [NSNumber numberWithBool:([self valid] && [self matches:search])];
1371 - (NSNumber *) isInstalledInSection:(NSString *)section {
1372 return [NSNumber numberWithBool:([self installed] != nil && (section == nil || [section isEqualToString:[self section]]))];
1375 - (NSNumber *) isUninstalledInSection:(NSString *)name {
1376 NSString *section = [self section];
1378 return [NSNumber numberWithBool:([self valid] && [self installed] == nil && (
1380 section == nil && [name length] == 0 ||
1381 [name isEqualToString:section])
1387 /* Section Class {{{ */
1388 @interface Section : NSObject {
1394 - (Section *) initWithName:(NSString *)name row:(size_t)row;
1395 - (NSString *) name;
1398 - (void) addToCount;
1402 @implementation Section
1409 - (Section *) initWithName:(NSString *)name row:(size_t)row {
1410 if ((self = [super init]) != nil) {
1411 name_ = [name retain];
1416 - (NSString *) name {
1428 - (void) addToCount {
1435 /* Database Implementation {{{ */
1436 @implementation Database
1443 - (void) _readCydia:(NSNumber *)fd {
1444 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1446 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1447 std::istream is(&ib);
1450 while (std::getline(is, line)) {
1451 const char *data(line.c_str());
1452 //size_t size = line.size();
1453 fprintf(stderr, "C:%s\n", data);
1460 - (void) _readStatus:(NSNumber *)fd {
1461 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1463 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1464 std::istream is(&ib);
1467 Pcre conffile_r("^status: [^ ]* : conffile-prompt : (.*?) *$");
1468 Pcre pmstatus_r("^([^:]*):([^:]*):([^:]*):(.*)$");
1470 while (std::getline(is, line)) {
1471 const char *data(line.c_str());
1472 size_t size = line.size();
1473 fprintf(stderr, "S:%s\n", data);
1475 if (conffile_r(data, size)) {
1476 [delegate_ setConfigurationData:conffile_r[1]];
1477 } else if (strncmp(data, "status: ", 8) == 0) {
1478 NSString *string = [NSString stringWithUTF8String:(data + 8)];
1479 [delegate_ setProgressTitle:string];
1480 } else if (pmstatus_r(data, size)) {
1481 std::string type([pmstatus_r[1] UTF8String]);
1482 NSString *id = pmstatus_r[2];
1484 float percent([pmstatus_r[3] floatValue]);
1485 [delegate_ setProgressPercent:(percent / 100)];
1487 NSString *string = pmstatus_r[4];
1489 if (type == "pmerror")
1490 [delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
1491 withObject:[NSArray arrayWithObjects:string, id, nil]
1494 else if (type == "pmstatus")
1495 [delegate_ setProgressTitle:string];
1496 else if (type == "pmconffile")
1497 [delegate_ setConfigurationData:string];
1498 else _assert(false);
1499 } else _assert(false);
1506 - (void) _readOutput:(NSNumber *)fd {
1507 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1509 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1510 std::istream is(&ib);
1513 while (std::getline(is, line)) {
1514 fprintf(stderr, "O:%s\n", line.c_str());
1515 [delegate_ addProgressOutput:[NSString stringWithUTF8String:line.c_str()]];
1526 - (Package *) packageWithName:(NSString *)name {
1527 if (static_cast<pkgDepCache *>(cache_) == NULL)
1529 pkgCache::PkgIterator iterator(cache_->FindPkg([name UTF8String]));
1530 return iterator.end() ? nil : [Package packageWithIterator:iterator database:self];
1533 - (Database *) init {
1534 if ((self = [super init]) != nil) {
1541 sources_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1542 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
1546 _assert(pipe(fds) != -1);
1549 _config->Set("APT::Keep-Fds::", cydiafd_);
1550 setenv("CYDIA", [[[[NSNumber numberWithInt:cydiafd_] stringValue] stringByAppendingString:@" 0"] UTF8String], _not(int));
1553 detachNewThreadSelector:@selector(_readCydia:)
1555 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1558 _assert(pipe(fds) != -1);
1562 detachNewThreadSelector:@selector(_readStatus:)
1564 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1567 _assert(pipe(fds) != -1);
1568 _assert(dup2(fds[0], 0) != -1);
1569 _assert(close(fds[0]) != -1);
1571 input_ = fdopen(fds[1], "a");
1573 _assert(pipe(fds) != -1);
1574 _assert(dup2(fds[1], 1) != -1);
1575 _assert(close(fds[1]) != -1);
1578 detachNewThreadSelector:@selector(_readOutput:)
1580 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1585 - (pkgCacheFile &) cache {
1589 - (pkgDepCache::Policy *) policy {
1593 - (pkgRecords *) records {
1597 - (pkgProblemResolver *) resolver {
1601 - (pkgAcquire &) fetcher {
1605 - (NSArray *) packages {
1609 - (void) reloadData {
1628 if (!cache_.Open(progress_, true)) {
1630 if (!_error->PopMessage(error))
1633 fprintf(stderr, "cache_.Open():[%s]\n", error.c_str());
1635 if (error == "dpkg was interrupted, you must manually run 'dpkg --configure -a' to correct the problem. ")
1636 [delegate_ repairWithSelector:@selector(configure)];
1637 else if (error == "The package lists or status file could not be parsed or opened.")
1638 [delegate_ repairWithSelector:@selector(update)];
1639 // else if (error == "Could not open lock file /var/lib/dpkg/lock - open (13 Permission denied)")
1640 // else if (error == "Could not get lock /var/lib/dpkg/lock - open (35 Resource temporarily unavailable)")
1641 // else if (error == "The list of sources could not be read.")
1642 else _assert(false);
1647 now_ = [[NSDate date] retain];
1649 policy_ = new pkgDepCache::Policy();
1650 records_ = new pkgRecords(cache_);
1651 resolver_ = new pkgProblemResolver(cache_);
1652 fetcher_ = new pkgAcquire(&status_);
1655 list_ = new pkgSourceList();
1656 _assert(list_->ReadMainList());
1658 _assert(cache_->DelCount() == 0 && cache_->InstCount() == 0);
1659 _assert(pkgApplyStatus(cache_));
1661 if (cache_->BrokenCount() != 0) {
1662 _assert(pkgFixBroken(cache_));
1663 _assert(cache_->BrokenCount() == 0);
1664 _assert(pkgMinimizeUpgrade(cache_));
1667 [sources_ removeAllObjects];
1668 for (pkgSourceList::const_iterator source = list_->begin(); source != list_->end(); ++source) {
1669 std::vector<pkgIndexFile *> *indices = (*source)->GetIndexFiles();
1670 for (std::vector<pkgIndexFile *>::const_iterator index = indices->begin(); index != indices->end(); ++index)
1672 setObject:[[[Source alloc] initWithMetaIndex:*source] autorelease]
1673 forKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(*index)]
1677 [packages_ removeAllObjects];
1678 for (pkgCache::PkgIterator iterator = cache_->PkgBegin(); !iterator.end(); ++iterator)
1679 if (Package *package = [Package packageWithIterator:iterator database:self])
1680 [packages_ addObject:package];
1682 [packages_ sortUsingSelector:@selector(compareByName:)];
1685 - (void) configure {
1686 NSString *dpkg = [NSString stringWithFormat:@"dpkg --configure -a --status-fd %u", statusfd_];
1687 system([dpkg UTF8String]);
1695 Lock.Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1696 _assert(!_error->PendingError());
1699 fetcher.Clean(_config->FindDir("Dir::Cache::Archives"));
1702 public pkgArchiveCleaner
1705 virtual void Erase(const char *File, std::string Pkg, std::string Ver, struct stat &St) {
1710 if (!cleaner.Go(_config->FindDir("Dir::Cache::Archives") + "partial/", cache_)) {
1712 while (_error->PopMessage(error))
1713 fprintf(stderr, "ArchiveCleaner: %s\n", error.c_str());
1718 pkgRecords records(cache_);
1720 lock_ = new FileFd();
1721 lock_->Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1722 _assert(!_error->PendingError());
1725 // XXX: explain this with an error message
1726 _assert(list.ReadMainList());
1728 manager_ = (_system->CreatePM(cache_));
1729 _assert(manager_->GetArchives(fetcher_, &list, &records));
1730 _assert(!_error->PendingError());
1734 NSMutableArray *before = [NSMutableArray arrayWithCapacity:16]; {
1736 _assert(list.ReadMainList());
1737 for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source)
1738 [before addObject:[NSString stringWithUTF8String:(*source)->GetURI().c_str()]];
1741 if (fetcher_->Run(PulseInterval_) != pkgAcquire::Continue) {
1746 bool failed = false;
1747 for (pkgAcquire::ItemIterator item = fetcher_->ItemsBegin(); item != fetcher_->ItemsEnd(); item++) {
1748 if ((*item)->Status == pkgAcquire::Item::StatDone && (*item)->Complete)
1751 std::string uri = (*item)->DescURI();
1752 std::string error = (*item)->ErrorText;
1754 fprintf(stderr, "pAf:%s:%s\n", uri.c_str(), error.c_str());
1757 [delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
1758 withObject:[NSArray arrayWithObjects:[NSString stringWithUTF8String:error.c_str()], nil]
1769 pkgPackageManager::OrderResult result = manager_->DoInstall(statusfd_);
1771 if (_error->PendingError()) {
1776 if (result == pkgPackageManager::Failed) {
1781 if (result != pkgPackageManager::Completed) {
1786 NSMutableArray *after = [NSMutableArray arrayWithCapacity:16]; {
1788 _assert(list.ReadMainList());
1789 for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source)
1790 [after addObject:[NSString stringWithUTF8String:(*source)->GetURI().c_str()]];
1793 if (![before isEqualToArray:after])
1798 _assert(pkgDistUpgrade(cache_));
1802 [self updateWithStatus:status_];
1805 - (void) updateWithStatus:(Status &)status {
1807 _assert(list.ReadMainList());
1810 lock.Fd(GetLock(_config->FindDir("Dir::State::Lists") + "lock"));
1811 _assert(!_error->PendingError());
1813 pkgAcquire fetcher(&status);
1814 _assert(list.GetIndexes(&fetcher));
1816 if (fetcher.Run(PulseInterval_) != pkgAcquire::Failed) {
1817 bool failed = false;
1818 for (pkgAcquire::ItemIterator item = fetcher.ItemsBegin(); item != fetcher.ItemsEnd(); item++)
1819 if ((*item)->Status != pkgAcquire::Item::StatDone) {
1820 (*item)->Finished();
1824 if (!failed && _config->FindB("APT::Get::List-Cleanup", true) == true) {
1825 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists")));
1826 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/"));
1829 [Metadata_ setObject:[NSDate date] forKey:@"LastUpdate"];
1834 - (void) setDelegate:(id)delegate {
1835 delegate_ = delegate;
1836 status_.setDelegate(delegate);
1837 progress_.setDelegate(delegate);
1840 - (Source *) getSource:(const pkgCache::PkgFileIterator &)file {
1841 pkgIndexFile *index(NULL);
1842 list_->FindIndex(file, index);
1843 return [sources_ objectForKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(index)]];
1849 /* Confirmation View {{{ */
1850 void AddTextView(NSMutableDictionary *fields, NSMutableArray *packages, NSString *key) {
1851 if ([packages count] == 0)
1854 UITextView *text = GetTextView([packages count] == 0 ? @"n/a" : [packages componentsJoinedByString:@", "], 120, false);
1855 [fields setObject:text forKey:key];
1857 CGColor blue(space_, 0, 0, 0.4, 1);
1858 [text setTextColor:blue];
1861 @protocol ConfirmationViewDelegate
1866 @interface ConfirmationView : UIView {
1867 Database *database_;
1869 UITransitionView *transition_;
1871 UINavigationBar *navbar_;
1872 UIPreferencesTable *table_;
1873 NSMutableDictionary *fields_;
1874 UIAlertSheet *essential_;
1879 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate;
1883 @implementation ConfirmationView
1886 [navbar_ setDelegate:nil];
1887 [transition_ setDelegate:nil];
1888 [table_ setDataSource:nil];
1890 [transition_ release];
1895 if (essential_ != nil)
1896 [essential_ release];
1901 [transition_ transition:7 toView:nil];
1905 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
1906 if (from != nil && to == nil)
1907 [self removeFromSuperview];
1910 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
1913 if (essential_ != nil)
1914 [essential_ popupAlertAnimated:YES];
1916 [delegate_ confirm];
1925 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
1926 NSString *context = [sheet context];
1928 if ([context isEqualToString:@"remove"])
1934 [delegate_ confirm];
1939 else if ([context isEqualToString:@"unable"])
1945 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
1949 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
1951 case 0: return @"Statistics";
1952 case 1: return @"Modifications";
1954 default: _assert(false);
1958 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
1961 case 1: return [fields_ count];
1963 default: _assert(false);
1967 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
1968 if (group != 1 || row == -1)
1971 _assert(size_t(row) < [fields_ count]);
1972 return [[[fields_ allValues] objectAtIndex:row] visibleTextRect].size.height + TextViewOffset_;
1976 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
1977 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
1978 [cell setShowSelection:NO];
1981 case 0: switch (row) {
1983 [cell setTitle:@"Downloading"];
1984 [cell setValue:SizeString([database_ fetcher].FetchNeeded())];
1988 [cell setTitle:@"Resuming At"];
1989 [cell setValue:SizeString([database_ fetcher].PartialPresent())];
1993 double size([database_ cache]->UsrSize());
1996 [cell setTitle:@"Disk Freeing"];
1997 [cell setValue:SizeString(-size)];
1999 [cell setTitle:@"Disk Using"];
2000 [cell setValue:SizeString(size)];
2004 default: _assert(false);
2008 _assert(size_t(row) < [fields_ count]);
2009 [cell setTitle:[[fields_ allKeys] objectAtIndex:row]];
2010 [cell addSubview:[[fields_ allValues] objectAtIndex:row]];
2013 default: _assert(false);
2019 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate {
2020 if ((self = [super initWithFrame:[view bounds]]) != nil) {
2021 database_ = database;
2022 delegate_ = delegate;
2024 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
2025 [self addSubview:transition_];
2027 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
2029 CGSize navsize = [UINavigationBar defaultSize];
2030 CGRect navrect = {{0, 0}, navsize};
2031 CGRect bounds = [overlay_ bounds];
2033 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
2035 [navbar_ setBarStyle:1];
2036 [navbar_ setDelegate:self];
2038 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Confirm"] autorelease];
2039 [navbar_ pushNavigationItem:navitem];
2040 [navbar_ showButtonsWithLeftTitle:@"Cancel" rightTitle:@"Confirm"];
2042 fields_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
2044 NSMutableArray *installing = [NSMutableArray arrayWithCapacity:16];
2045 NSMutableArray *reinstalling = [NSMutableArray arrayWithCapacity:16];
2046 NSMutableArray *upgrading = [NSMutableArray arrayWithCapacity:16];
2047 NSMutableArray *downgrading = [NSMutableArray arrayWithCapacity:16];
2048 NSMutableArray *removing = [NSMutableArray arrayWithCapacity:16];
2052 pkgCacheFile &cache([database_ cache]);
2053 NSArray *packages = [database_ packages];
2054 for (size_t i(0), e = [packages count]; i != e; ++i) {
2055 Package *package = [packages objectAtIndex:i];
2056 pkgCache::PkgIterator iterator = [package iterator];
2057 pkgDepCache::StateCache &state(cache[iterator]);
2059 NSString *name([package name]);
2061 if (state.NewInstall())
2062 [installing addObject:name];
2063 else if (!state.Delete() && (state.iFlags & pkgDepCache::ReInstall) == pkgDepCache::ReInstall)
2064 [reinstalling addObject:name];
2065 else if (state.Upgrade())
2066 [upgrading addObject:name];
2067 else if (state.Downgrade())
2068 [downgrading addObject:name];
2069 else if (state.Delete()) {
2070 if ([package essential])
2072 [removing addObject:name];
2078 else if (Advanced_ || true) {
2079 essential_ = [[UIAlertSheet alloc]
2080 initWithTitle:@"Removing Essentials"
2081 buttons:[NSArray arrayWithObjects:
2082 @"Cancel Operation (Safe)",
2083 @"Force Removal (Unsafe)",
2085 defaultButtonIndex:0
2091 [essential_ setDestructiveButton:[[essential_ buttons] objectAtIndex:0]];
2093 [essential_ setBodyText:@"This operation involves the removal of one or more packages that are required for the continued operation of either Cydia or iPhoneOS. If you continue, you may not be able to use Cydia to repair any damage."];
2095 essential_ = [[UIAlertSheet alloc]
2096 initWithTitle:@"Unable to Comply"
2097 buttons:[NSArray arrayWithObjects:@"Okay", nil]
2098 defaultButtonIndex:0
2103 [essential_ setBodyText:@"This operation requires the removal of one or more packages that are required for the continued operation of either Cydia or iPhoneOS. In order to continue and force this operation you will need to be activate the Advanced mode under to continue and force this operation you will need to be activate the Advanced mode under Settings."];
2106 AddTextView(fields_, installing, @"Installing");
2107 AddTextView(fields_, reinstalling, @"Reinstalling");
2108 AddTextView(fields_, upgrading, @"Upgrading");
2109 AddTextView(fields_, downgrading, @"Downgrading");
2110 AddTextView(fields_, removing, @"Removing");
2112 table_ = [[UIPreferencesTable alloc] initWithFrame:CGRectMake(
2113 0, navsize.height, bounds.size.width, bounds.size.height - navsize.height
2116 [table_ setReusesTableCells:YES];
2117 [table_ setDataSource:self];
2118 [table_ reloadData];
2120 [overlay_ addSubview:navbar_];
2121 [overlay_ addSubview:table_];
2123 [view addSubview:self];
2125 [transition_ setDelegate:self];
2127 UIView *blank = [[[UIView alloc] initWithFrame:[transition_ bounds]] autorelease];
2128 [transition_ transition:0 toView:blank];
2129 [transition_ transition:3 toView:overlay_];
2136 /* Progress Data {{{ */
2137 @interface ProgressData : NSObject {
2143 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object;
2150 @implementation ProgressData
2152 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object {
2153 if ((self = [super init]) != nil) {
2154 selector_ = selector;
2174 /* Progress View {{{ */
2175 Pcre conffile_r("^'(.*)' '(.*)' ([01]) ([01])$");
2177 @interface ProgressView : UIView <
2178 ConfigurationDelegate,
2181 _transient Database *database_;
2183 UIView *background_;
2184 UITransitionView *transition_;
2186 UINavigationBar *navbar_;
2187 UIProgressBar *progress_;
2188 UITextView *output_;
2189 UITextLabel *status_;
2190 UIPushButton *close_;
2195 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
2197 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database delegate:(id)delegate;
2198 - (void) setContentView:(UIView *)view;
2201 - (void) _retachThread;
2202 - (void) _detachNewThreadData:(ProgressData *)data;
2203 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title;
2209 @protocol ProgressViewDelegate
2210 - (void) progressViewIsComplete:(ProgressView *)sender;
2213 @implementation ProgressView
2216 [transition_ setDelegate:nil];
2217 [navbar_ setDelegate:nil];
2220 if (background_ != nil)
2221 [background_ release];
2222 [transition_ release];
2225 [progress_ release];
2232 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
2233 if (bootstrap_ && from == overlay_ && to == view_)
2237 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database delegate:(id)delegate {
2238 if ((self = [super initWithFrame:frame]) != nil) {
2239 database_ = database;
2240 delegate_ = delegate;
2242 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
2243 [transition_ setDelegate:self];
2245 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
2248 [overlay_ setBackgroundColor:Black_];
2250 background_ = [[UIView alloc] initWithFrame:[self bounds]];
2251 [background_ setBackgroundColor:Black_];
2252 [self addSubview:background_];
2255 [self addSubview:transition_];
2257 CGSize navsize = [UINavigationBar defaultSize];
2258 CGRect navrect = {{0, 0}, navsize};
2260 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
2261 [overlay_ addSubview:navbar_];
2263 [navbar_ setBarStyle:1];
2264 [navbar_ setDelegate:self];
2266 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:nil] autorelease];
2267 [navbar_ pushNavigationItem:navitem];
2269 CGRect bounds = [overlay_ bounds];
2270 CGSize prgsize = [UIProgressBar defaultSize];
2273 (bounds.size.width - prgsize.width) / 2,
2274 bounds.size.height - prgsize.height - 20
2277 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
2278 [progress_ setStyle:0];
2280 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(
2282 bounds.size.height - prgsize.height - 50,
2283 bounds.size.width - 20,
2287 [status_ setColor:White_];
2288 [status_ setBackgroundColor:Clear_];
2290 [status_ setCentersHorizontally:YES];
2291 //[status_ setFont:font];
2293 output_ = [[UITextView alloc] initWithFrame:CGRectMake(
2295 navrect.size.height + 20,
2296 bounds.size.width - 20,
2297 bounds.size.height - navsize.height - 62 - navrect.size.height
2300 //[output_ setTextFont:@"Courier New"];
2301 [output_ setTextSize:12];
2303 [output_ setTextColor:White_];
2304 [output_ setBackgroundColor:Clear_];
2306 [output_ setMarginTop:0];
2307 [output_ setAllowsRubberBanding:YES];
2308 [output_ setEditable:NO];
2310 [overlay_ addSubview:output_];
2312 close_ = [[UIPushButton alloc] initWithFrame:CGRectMake(
2314 bounds.size.height - prgsize.height - 50,
2315 bounds.size.width - 20,
2319 [close_ setAutosizesToFit:NO];
2320 [close_ setDrawsShadow:YES];
2321 [close_ setStretchBackground:YES];
2322 [close_ setTitle:@"Close Window"];
2323 [close_ setEnabled:YES];
2325 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22);
2326 [close_ setTitleFont:bold];
2329 [close_ addTarget:self action:@selector(closeButtonPushed) forEvents:kUIControlEventMouseUpInside];
2330 [close_ setBackground:[UIImage applicationImageNamed:@"green-up.png"] forState:0];
2331 [close_ setBackground:[UIImage applicationImageNamed:@"green-dn.png"] forState:1];
2335 - (void) setContentView:(UIView *)view {
2336 view_ = [view retain];
2339 - (void) resetView {
2340 [transition_ transition:6 toView:view_];
2343 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
2344 NSString *context = [sheet context];
2345 if ([context isEqualToString:@"conffile"]) {
2346 FILE *input = [database_ input];
2350 fprintf(input, "N\n");
2354 fprintf(input, "Y\n");
2365 - (void) closeButtonPushed {
2366 [delegate_ progressViewIsComplete:self];
2370 - (void) _retachThread {
2371 UINavigationItem *item = [navbar_ topItem];
2372 [item setTitle:@"Complete"];
2374 [overlay_ addSubview:close_];
2375 [progress_ removeFromSuperview];
2376 [status_ removeFromSuperview];
2378 [delegate_ setStatusBarShowsProgress:NO];
2379 //[[UIApplication sharedApplication] setIdleTimerDisabled:YES];
2384 - (void) _detachNewThreadData:(ProgressData *)data {
2385 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
2387 [[data target] performSelector:[data selector] withObject:[data object]];
2390 [self performSelectorOnMainThread:@selector(_retachThread) withObject:nil waitUntilDone:YES];
2395 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title {
2396 UINavigationItem *item = [navbar_ topItem];
2397 [item setTitle:title];
2399 [status_ setText:nil];
2400 [output_ setText:@""];
2401 [progress_ setProgress:0];
2403 [close_ removeFromSuperview];
2404 [overlay_ addSubview:progress_];
2405 [overlay_ addSubview:status_];
2407 [delegate_ setStatusBarShowsProgress:YES];
2410 [transition_ transition:6 toView:overlay_];
2413 detachNewThreadSelector:@selector(_detachNewThreadData:)
2415 withObject:[[ProgressData alloc]
2416 initWithSelector:selector
2423 - (void) repairWithSelector:(SEL)selector {
2425 detachNewThreadSelector:selector
2428 title:@"Repairing..."
2432 - (void) setConfigurationData:(NSString *)data {
2434 performSelectorOnMainThread:@selector(_setConfigurationData:)
2440 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id {
2441 Package *package = id == nil ? nil : [database_ packageWithName:id];
2443 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
2444 initWithTitle:(package == nil ? @"Source Error" : [package name])
2445 buttons:[NSArray arrayWithObjects:@"Okay", nil]
2446 defaultButtonIndex:0
2451 [sheet setBodyText:error];
2452 [sheet popupAlertAnimated:YES];
2455 - (void) setProgressTitle:(NSString *)title {
2457 performSelectorOnMainThread:@selector(_setProgressTitle:)
2463 - (void) setProgressPercent:(float)percent {
2465 performSelectorOnMainThread:@selector(_setProgressPercent:)
2466 withObject:[NSNumber numberWithFloat:percent]
2471 - (void) addProgressOutput:(NSString *)output {
2473 performSelectorOnMainThread:@selector(_addProgressOutput:)
2479 - (void) _setConfigurationData:(NSString *)data {
2480 _assert(conffile_r(data));
2482 NSString *ofile = conffile_r[1];
2483 //NSString *nfile = conffile_r[2];
2485 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
2486 initWithTitle:@"Configuration Upgrade"
2487 buttons:[NSArray arrayWithObjects:
2488 @"Keep My Old Copy",
2489 @"Accept The New Copy",
2490 // XXX: @"See What Changed",
2492 defaultButtonIndex:0
2497 [sheet setBodyText:[NSString stringWithFormat:
2498 @"The following file has been changed by both the package maintainer and by you (or for you by a script).\n\n%@"
2501 [sheet popupAlertAnimated:YES];
2504 - (void) _setProgressTitle:(NSString *)title {
2505 [status_ setText:[title stringByAppendingString:@"..."]];
2508 - (void) _setProgressPercent:(NSNumber *)percent {
2509 [progress_ setProgress:[percent floatValue]];
2512 - (void) _addProgressOutput:(NSString *)output {
2513 [output_ setText:[NSString stringWithFormat:@"%@\n%@", [output_ text], output]];
2514 CGSize size = [output_ contentSize];
2515 CGRect rect = {{0, size.height}, {size.width, 0}};
2516 [output_ scrollRectToVisible:rect animated:YES];
2519 - (BOOL) isRunning {
2526 /* Package Cell {{{ */
2527 @interface PackageCell : UITableCell {
2530 UITextLabel *description_;
2531 UITextLabel *source_;
2532 //UIImageView *trusted_;
2534 UIImageView *badge_;
2535 UITextLabel *status_;
2540 - (PackageCell *) init;
2541 - (void) setPackage:(Package *)package;
2543 - (void) _setSelected:(float)fraction;
2544 - (void) setSelected:(BOOL)selected;
2545 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
2546 - (void) _setSelectionFadeFraction:(float)fraction;
2548 + (int) heightForPackage:(Package *)package;
2552 @implementation PackageCell
2557 [description_ release];
2563 //[trusted_ release];
2567 - (PackageCell *) init {
2568 if ((self = [super init]) != nil) {
2569 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 20);
2570 GSFontRef large = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 12);
2571 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 14);
2573 icon_ = [[UIImageView alloc] initWithFrame:CGRectMake(10, 10, 30, 30)];
2575 name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 8, 240, 25)];
2576 [name_ setBackgroundColor:Clear_];
2577 [name_ setFont:bold];
2579 source_ = [[UITextLabel alloc] initWithFrame:CGRectMake(58, 28, 225, 20)];
2580 [source_ setBackgroundColor:Clear_];
2581 [source_ setFont:large];
2583 description_ = [[UITextLabel alloc] initWithFrame:CGRectMake(12, 46, 280, 20)];
2584 [description_ setBackgroundColor:Clear_];
2585 [description_ setFont:small];
2587 /*trusted_ = [[UIImageView alloc] initWithFrame:CGRectMake(30, 30, 16, 16)];
2588 [trusted_ setImage:[UIImage applicationImageNamed:@"trusted.png"]];*/
2591 badge_ = [[UIImageView alloc] initWithFrame:CGRectMake(17, 70, 16, 16)];
2593 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 68, 280, 20)];
2594 [status_ setBackgroundColor:Clear_];
2595 [status_ setFont:small];
2598 /*[icon_ setImage:[UIImage applicationImageNamed:@"unknown.png"]];
2599 [icon_ zoomToScale:0.5];
2600 [icon_ setFrame:CGRectMake(10, 10, 30, 30)];*/
2602 [self addSubview:icon_];
2603 [self addSubview:name_];
2604 [self addSubview:description_];
2605 [self addSubview:source_];
2613 - (void) setPackage:(Package *)package {
2619 Source *source = [package source];
2621 UIImage *image = nil;
2622 if (NSString *icon = [package icon])
2623 image = [UIImage imageAtPath:[icon substringFromIndex:6]];
2624 if (image == nil) if (NSString *icon = [source defaultIcon])
2625 image = [UIImage imageAtPath:[icon substringFromIndex:6]];
2627 image = [UIImage applicationImageNamed:@"unknown.png"];
2628 [icon_ setImage:image];
2630 /*if (image != nil) {
2631 CGSize size = [image size];
2632 float scale = 30 / std::max(size.width, size.height);
2633 [icon_ zoomToScale:scale];
2636 [icon_ setFrame:CGRectMake(10, 10, 30, 30)];
2638 [name_ setText:[package name]];
2639 [description_ setText:[package tagline]];
2641 NSString *label = nil;
2642 bool trusted = false;
2644 if (source != nil) {
2645 label = [source label];
2646 trusted = [source trusted];
2647 } else if ([[package id] isEqualToString:@"firmware"])
2651 label = @"Unknown/Local";
2653 NSString *from = [NSString stringWithFormat:@"from %@", label];
2655 NSString *section = Simplify([package section]);
2656 if (section != nil && ![section isEqualToString:label])
2657 from = [from stringByAppendingString:[NSString stringWithFormat:@" (%@)", section]];
2659 [source_ setText:from];
2662 [badge_ removeFromSuperview];
2663 [status_ removeFromSuperview];
2665 if (NSString *mode = [package mode]) {
2666 [badge_ setImage:[UIImage applicationImageNamed:
2667 [mode isEqualToString:@"Remove"] || [mode isEqualToString:@"Purge"] ? @"removing.png" : @"installing.png"
2670 [status_ setText:[NSString stringWithFormat:@"Queued for %@", mode]];
2671 [status_ setColor:Blueish_];
2672 } else if ([package half]) {
2673 [badge_ setImage:[UIImage applicationImageNamed:@"damaged.png"]];
2674 [status_ setText:@"Package Damaged"];
2675 [status_ setColor:Red_];
2677 [badge_ setImage:nil];
2678 [status_ setText:nil];
2682 [self addSubview:badge_];
2683 [self addSubview:status_];
2688 - (void) _setSelected:(float)fraction {
2689 CGColor black(space_,
2690 Interpolate(0.0, 1.0, fraction),
2691 Interpolate(0.0, 1.0, fraction),
2692 Interpolate(0.0, 1.0, fraction),
2695 CGColor gray(space_,
2696 Interpolate(0.4, 1.0, fraction),
2697 Interpolate(0.4, 1.0, fraction),
2698 Interpolate(0.4, 1.0, fraction),
2701 [name_ setColor:black];
2702 [description_ setColor:gray];
2703 [source_ setColor:black];
2706 - (void) setSelected:(BOOL)selected {
2707 [self _setSelected:(selected ? 1.0 : 0.0)];
2708 [super setSelected:selected];
2711 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
2713 [self _setSelected:(selected ? 1.0 : 0.0)];
2714 [super setSelected:selected withFade:fade];
2717 - (void) _setSelectionFadeFraction:(float)fraction {
2718 [self _setSelected:fraction];
2719 [super _setSelectionFadeFraction:fraction];
2722 + (int) heightForPackage:(Package *)package {
2724 if ([package hasMode] || [package half])
2733 /* Section Cell {{{ */
2734 @interface SectionCell : UITableCell {
2736 UITextLabel *count_;
2740 - (void) setSection:(Section *)section;
2742 - (void) _setSelected:(float)fraction;
2743 - (void) setSelected:(BOOL)selected;
2744 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
2745 - (void) _setSelectionFadeFraction:(float)fraction;
2749 @implementation SectionCell
2758 if ((self = [super init]) != nil) {
2759 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22);
2760 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 12);
2762 name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 9, 250, 25)];
2763 [name_ setBackgroundColor:Clear_];
2764 [name_ setFont:bold];
2766 count_ = [[UITextLabel alloc] initWithFrame:CGRectMake(11, 7, 29, 32)];
2767 [count_ setCentersHorizontally:YES];
2768 [count_ setBackgroundColor:Clear_];
2769 [count_ setFont:small];
2770 [count_ setColor:White_];
2772 UIImageView *folder = [[[UIImageView alloc] initWithFrame:CGRectMake(8, 7, 32, 32)] autorelease];
2773 [folder setImage:[UIImage applicationImageNamed:@"folder.png"]];
2775 [self addSubview:folder];
2776 [self addSubview:name_];
2777 [self addSubview:count_];
2779 [self _setSelected:0];
2786 - (void) setSection:(Section *)section {
2787 if (section == nil) {
2788 [name_ setText:@"All Packages"];
2789 [count_ setText:nil];
2791 NSString *name = [section name];
2792 [name_ setText:(name == nil ? @"(No Section)" : name)];
2793 [count_ setText:[NSString stringWithFormat:@"%d", [section count]]];
2797 - (void) _setSelected:(float)fraction {
2798 CGColor black(space_,
2799 Interpolate(0.0, 1.0, fraction),
2800 Interpolate(0.0, 1.0, fraction),
2801 Interpolate(0.0, 1.0, fraction),
2804 [name_ setColor:black];
2807 - (void) setSelected:(BOOL)selected {
2808 [self _setSelected:(selected ? 1.0 : 0.0)];
2809 [super setSelected:selected];
2812 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
2814 [self _setSelected:(selected ? 1.0 : 0.0)];
2815 [super setSelected:selected withFade:fade];
2818 - (void) _setSelectionFadeFraction:(float)fraction {
2819 [self _setSelected:fraction];
2820 [super _setSelectionFadeFraction:fraction];
2826 /* File Table {{{ */
2827 @interface FileTable : RVPage {
2828 _transient Database *database_;
2831 NSMutableArray *files_;
2835 - (id) initWithBook:(RVBook *)book database:(Database *)database;
2836 - (void) setPackage:(Package *)package;
2840 @implementation FileTable
2843 if (package_ != nil)
2852 - (int) numberOfRowsInTable:(UITable *)table {
2853 return files_ == nil ? 0 : [files_ count];
2856 - (float) table:(UITable *)table heightForRow:(int)row {
2860 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2861 if (reusing == nil) {
2862 reusing = [[[UIImageAndTextTableCell alloc] init] autorelease];
2863 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
2864 [[(UIImageAndTextTableCell *)reusing titleTextLabel] setFont:font];
2867 [(UIImageAndTextTableCell *)reusing setTitle:[files_ objectAtIndex:row]];
2871 - (BOOL) table:(UITable *)table canSelectRow:(int)row {
2875 - (id) initWithBook:(RVBook *)book database:(Database *)database {
2876 if ((self = [super initWithBook:book]) != nil) {
2877 database_ = database;
2879 files_ = [[NSMutableArray arrayWithCapacity:32] retain];
2881 list_ = [[UITable alloc] initWithFrame:[self bounds]];
2882 [self addSubview:list_];
2884 UITableColumn *column = [[[UITableColumn alloc]
2885 initWithTitle:@"Name"
2887 width:[self frame].size.width
2890 [list_ setDataSource:self];
2891 [list_ setSeparatorStyle:1];
2892 [list_ addTableColumn:column];
2893 [list_ setDelegate:self];
2894 [list_ setReusesTableCells:YES];
2898 - (void) setPackage:(Package *)package {
2899 if (package_ != nil) {
2900 [package_ autorelease];
2909 [files_ removeAllObjects];
2911 if (package != nil) {
2912 package_ = [package retain];
2913 name_ = [[package id] retain];
2915 NSString *path = [NSString stringWithFormat:@"/var/lib/dpkg/info/%@.list", name_];
2918 std::ifstream fin([path UTF8String]);
2920 while (std::getline(fin, line))
2921 [files_ addObject:[NSString stringWithUTF8String:line.c_str()]];
2924 if ([files_ count] != 0) {
2925 if ([[files_ objectAtIndex:0] isEqualToString:@"/."])
2926 [files_ removeObjectAtIndex:0];
2927 [files_ sortUsingSelector:@selector(compareByPath:)];
2929 NSMutableArray *stack = [NSMutableArray arrayWithCapacity:8];
2930 [stack addObject:@"/"];
2932 for (int i(0), e([files_ count]); i != e; ++i) {
2933 NSString *file = [files_ objectAtIndex:i];
2934 while (![file hasPrefix:[stack lastObject]])
2935 [stack removeLastObject];
2936 NSString *directory = [stack lastObject];
2937 [stack addObject:[file stringByAppendingString:@"/"]];
2938 [files_ replaceObjectAtIndex:i withObject:[NSString stringWithFormat:@"%*s%@",
2939 ([stack count] - 2) * 3, "",
2940 [file substringFromIndex:[directory length]]
2949 - (void) resetViewAnimated:(BOOL)animated {
2950 [list_ resetViewAnimated:animated];
2953 - (void) reloadData {
2954 [self setPackage:[database_ packageWithName:name_]];
2955 [self reloadButtons];
2958 - (NSString *) title {
2959 return @"Installed Files";
2962 - (NSString *) backButtonTitle {
2968 /* Package View {{{ */
2969 @protocol PackageViewDelegate
2970 - (void) performPackage:(Package *)package;
2973 @interface PackageView : RVPage {
2974 _transient Database *database_;
2975 UIPreferencesTable *table_;
2978 UITextView *description_;
2979 NSMutableArray *buttons_;
2982 - (id) initWithBook:(RVBook *)book database:(Database *)database;
2983 - (void) setPackage:(Package *)package;
2987 @implementation PackageView
2990 [table_ setDataSource:nil];
2991 [table_ setDelegate:nil];
2993 if (package_ != nil)
2997 if (description_ != nil)
2998 [description_ release];
3004 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
3006 if ([package_ installed] != nil)
3008 if ([package_ source] != nil)
3013 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
3016 else if ([package_ installed] != nil && group-- == 0)
3017 return @"Installed Package";
3018 else if (group-- == 0)
3019 return @"Package Details";
3020 else if ([package_ source] != nil && group-- == 0)
3021 return @"Source Information";
3022 else _assert(false);
3025 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
3026 if (description_ == nil || group != 0 || row != 1)
3029 return [description_ visibleTextRect].size.height + TextViewOffset_;
3032 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
3035 if ([package_ author] != nil)
3037 if (description_ != nil)
3039 if ([package_ website] != nil)
3042 } else if ([package_ installed] != nil && group-- == 0)
3044 else if (group-- == 0) {
3046 if ([package_ size] != 0)
3048 if ([package_ maintainer] != nil)
3050 if ([package_ sponsor] != nil)
3052 if ([package_ relationships] != nil)
3054 if ([[package_ source] trusted])
3057 } else if ([package_ source] != nil && group-- == 0) {
3058 Source *source = [package_ source];
3059 NSString *description = [source description];
3061 if (description != nil && ![description isEqualToString:[source label]])
3063 if ([source origin] != nil)
3066 } else _assert(false);
3069 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
3070 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
3071 [cell setShowSelection:NO];
3075 } else if (row-- == 0) {
3076 [cell setTitle:[package_ name]];
3077 [cell setValue:[package_ latest]];
3078 } else if ([package_ author] != nil && row-- == 0) {
3079 [cell setTitle:@"Author"];
3080 [cell setValue:[[package_ author] name]];
3081 [cell setShowDisclosure:YES];
3082 [cell setShowSelection:YES];
3083 } else if (description_ != nil && row-- == 0) {
3084 [cell addSubview:description_];
3085 } else if ([package_ website] != nil && row-- == 0) {
3086 [cell setTitle:@"More Information"];
3087 [cell setShowDisclosure:YES];
3088 [cell setShowSelection:YES];
3089 } else _assert(false);
3090 } else if ([package_ installed] != nil && group-- == 0) {
3092 } else if (row-- == 0) {
3093 [cell setTitle:@"Version"];
3094 NSString *installed([package_ installed]);
3095 [cell setValue:(installed == nil ? @"n/a" : installed)];
3096 } else if (row-- == 0) {
3097 [cell setTitle:@"Filesystem Content"];
3098 [cell setShowDisclosure:YES];
3099 [cell setShowSelection:YES];
3100 } else _assert(false);
3101 } else if (group-- == 0) {
3103 } else if (row-- == 0) {
3104 [cell setTitle:@"Identifier"];
3105 [cell setValue:[package_ id]];
3106 } else if (row-- == 0) {
3107 [cell setTitle:@"Section"];
3108 NSString *section([package_ section]);
3109 [cell setValue:(section == nil ? @"n/a" : section)];
3110 } else if ([package_ size] != 0 && row-- == 0) {
3111 [cell setTitle:@"Expanded Size"];
3112 [cell setValue:SizeString([package_ size])];
3113 } else if ([package_ maintainer] != nil && row-- == 0) {
3114 [cell setTitle:@"Maintainer"];
3115 [cell setValue:[[package_ maintainer] name]];
3116 [cell setShowDisclosure:YES];
3117 [cell setShowSelection:YES];
3118 } else if ([package_ sponsor] != nil && row-- == 0) {
3119 [cell setTitle:@"Sponsor"];
3120 [cell setValue:[[package_ sponsor] name]];
3121 [cell setShowDisclosure:YES];
3122 [cell setShowSelection:YES];
3123 } else if ([package_ relationships] != nil && row-- == 0) {
3124 [cell setTitle:@"Package Relationships"];
3125 [cell setShowDisclosure:YES];
3126 [cell setShowSelection:YES];
3127 } else if ([[package_ source] trusted] && row-- == 0) {
3128 [cell setIcon:[UIImage applicationImageNamed:@"trusted.png"]];
3129 [cell setValue:@"This package has been signed."];
3130 } else _assert(false);
3131 } else if ([package_ source] != nil && group-- == 0) {
3132 Source *source = [package_ source];
3133 NSString *description = [source description];
3136 } else if (row-- == 0) {
3137 NSString *label = [source label];
3139 label = [source uri];
3140 [cell setTitle:label];
3141 [cell setValue:[source version]];
3142 } else if (description != nil && ![description isEqualToString:[source label]] && row-- == 0) {
3143 [cell setValue:description];
3144 } else if ([source origin] != nil && row-- == 0) {
3145 [cell setTitle:@"Origin"];
3146 [cell setValue:[source origin]];
3147 } else _assert(false);
3148 } else _assert(false);
3153 - (BOOL) canSelectRow:(int)row {
3157 - (void) tableRowSelected:(NSNotification *)notification {
3158 int row = [table_ selectedRow];
3162 #define _else else goto _label; return; } _label:
3166 } else if (row-- == 0) {
3167 } else if ([package_ author] != nil && row-- == 0) {
3168 [delegate_ openURL:[NSURL URLWithString:[NSString stringWithFormat:@"mailto:%@?subject=%@",
3169 [[package_ author] email],
3170 [[NSString stringWithFormat:@"regarding apt package \"%@\"",
3172 ] stringByAddingPercentEscapes]
3174 } else if (description_ != nil && row-- == 0) {
3175 } else if ([package_ website] != nil && row-- == 0) {
3176 NSURL *url = [NSURL URLWithString:[package_ website]];
3177 BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease];
3178 [browser setDelegate:delegate_];
3179 [book_ pushPage:browser];
3180 [browser loadURL:url];
3181 } _else if ([package_ installed] != nil) {
3183 } else if (row-- == 0) {
3184 } else if (row-- == 0) {
3185 FileTable *files = [[[FileTable alloc] initWithBook:book_ database:database_] autorelease];
3186 [files setDelegate:delegate_];
3187 [files setPackage:package_];
3188 [book_ pushPage:files];
3191 } else if (row-- == 0) {
3192 } else if (row-- == 0) {
3193 } else if ([package_ size] != 0 && row-- == 0) {
3194 } else if ([package_ maintainer] != nil && row-- == 0) {
3195 [delegate_ openURL:[NSURL URLWithString:[NSString stringWithFormat:@"mailto:%@?subject=%@",
3196 [[package_ maintainer] email],
3197 [[NSString stringWithFormat:@"regarding apt package \"%@\"",
3199 ] stringByAddingPercentEscapes]
3201 } else if ([package_ sponsor] != nil && row-- == 0) {
3202 NSURL *url = [NSURL URLWithString:[[package_ sponsor] email]];
3203 BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease];
3204 [browser setDelegate:delegate_];
3205 [book_ pushPage:browser];
3206 [browser loadURL:url];
3207 } else if ([package_ relationships] != nil && row-- == 0) {
3208 } else if ([[package_ source] trusted] && row-- == 0) {
3209 } _else if ([package_ source] != nil) {
3210 Source *source = [package_ source];
3211 NSString *description = [source description];
3214 } else if (row-- == 0) {
3215 } else if (description != nil && ![description isEqualToString:[source label]] && row-- == 0) {
3216 } else if ([source origin] != nil && row-- == 0) {
3217 } _else _assert(false);
3222 - (void) _clickButtonWithName:(NSString *)name {
3223 if ([name isEqualToString:@"Install"])
3224 [delegate_ installPackage:package_];
3225 else if ([name isEqualToString:@"Reinstall"])
3226 [delegate_ installPackage:package_];
3227 else if ([name isEqualToString:@"Remove"])
3228 [delegate_ removePackage:package_];
3229 else if ([name isEqualToString:@"Upgrade"])
3230 [delegate_ installPackage:package_];
3231 else _assert(false);
3234 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
3235 int count = [buttons_ count];
3236 _assert(count != 0);
3237 _assert(button <= count + 1);
3239 if (count != button - 1)
3240 [self _clickButtonWithName:[buttons_ objectAtIndex:(button - 1)]];
3245 - (void) _rightButtonClicked {
3246 int count = [buttons_ count];
3247 _assert(count != 0);
3250 [self _clickButtonWithName:[buttons_ objectAtIndex:0]];
3252 NSMutableArray *buttons = [NSMutableArray arrayWithCapacity:(count + 1)];
3253 [buttons addObjectsFromArray:buttons_];
3254 [buttons addObject:@"Cancel"];
3256 [delegate_ slideUp:[[[UIAlertSheet alloc]
3259 defaultButtonIndex:2
3266 - (NSString *) rightButtonTitle {
3267 int count = [buttons_ count];
3268 return count == 0 ? nil : count != 1 ? @"Modify" : [buttons_ objectAtIndex:0];
3271 - (NSString *) title {
3275 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3276 if ((self = [super initWithBook:book]) != nil) {
3277 database_ = database;
3279 table_ = [[UIPreferencesTable alloc] initWithFrame:[self bounds]];
3280 [self addSubview:table_];
3282 [table_ setDataSource:self];
3283 [table_ setDelegate:self];
3285 buttons_ = [[NSMutableArray alloc] initWithCapacity:4];
3289 - (void) setPackage:(Package *)package {
3290 if (package_ != nil) {
3291 [package_ autorelease];
3300 if (description_ != nil) {
3301 [description_ release];
3305 [buttons_ removeAllObjects];
3307 if (package != nil) {
3308 package_ = [package retain];
3309 name_ = [[package id] retain];
3311 NSString *description([package description]);
3312 if (description == nil)
3313 description = [package tagline];
3314 if (description != nil) {
3315 description_ = [GetTextView(description, 12, true) retain];
3316 [description_ setTextColor:Black_];
3319 [table_ reloadData];
3321 if ([package_ source] == nil);
3322 else if ([package_ upgradableAndEssential:NO])
3323 [buttons_ addObject:@"Upgrade"];
3324 else if ([package_ installed] == nil)
3325 [buttons_ addObject:@"Install"];
3327 [buttons_ addObject:@"Reinstall"];
3328 if ([package_ installed] != nil)
3329 [buttons_ addObject:@"Remove"];
3333 - (void) resetViewAnimated:(BOOL)animated {
3334 [table_ resetViewAnimated:animated];
3337 - (void) reloadData {
3338 [self setPackage:[database_ packageWithName:name_]];
3339 [self reloadButtons];
3344 /* Package Table {{{ */
3345 @interface PackageTable : RVPage {
3346 _transient Database *database_;
3350 NSMutableArray *packages_;
3351 NSMutableArray *sections_;
3352 UISectionList *list_;
3355 - (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object;
3357 - (void) setDelegate:(id)delegate;
3358 - (void) setObject:(id)object;
3360 - (void) reloadData;
3361 - (void) resetCursor;
3363 - (UISectionList *) list;
3365 - (void) setShouldHideHeaderInShortLists:(BOOL)hide;
3369 @implementation PackageTable
3372 [list_ setDataSource:nil];
3377 [packages_ release];
3378 [sections_ release];
3383 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
3384 return [sections_ count];
3387 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
3388 return [[sections_ objectAtIndex:section] name];
3391 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
3392 return [[sections_ objectAtIndex:section] row];
3395 - (int) numberOfRowsInTable:(UITable *)table {
3396 return [packages_ count];
3399 - (float) table:(UITable *)table heightForRow:(int)row {
3400 return [PackageCell heightForPackage:[packages_ objectAtIndex:row]];
3403 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
3405 reusing = [[[PackageCell alloc] init] autorelease];
3406 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
3410 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
3414 - (void) tableRowSelected:(NSNotification *)notification {
3415 int row = [[notification object] selectedRow];
3419 Package *package = [packages_ objectAtIndex:row];
3420 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
3421 [view setDelegate:delegate_];
3422 [view setPackage:package];
3423 [book_ pushPage:view];
3426 - (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object {
3427 if ((self = [super initWithBook:book]) != nil) {
3428 database_ = database;
3429 title_ = [title retain];
3431 object_ = object == nil ? nil : [object retain];
3433 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
3434 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
3436 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:YES];
3437 [list_ setDataSource:self];
3439 UITableColumn *column = [[[UITableColumn alloc]
3440 initWithTitle:@"Name"
3442 width:[self frame].size.width
3445 UITable *table = [list_ table];
3446 [table setSeparatorStyle:1];
3447 [table addTableColumn:column];
3448 [table setDelegate:self];
3449 [table setReusesTableCells:YES];
3451 [self addSubview:list_];
3456 - (void) setDelegate:(id)delegate {
3457 delegate_ = delegate;
3460 - (void) setObject:(id)object {
3466 object_ = [object retain];
3469 - (void) reloadData {
3470 NSArray *packages = [database_ packages];
3472 [packages_ removeAllObjects];
3473 [sections_ removeAllObjects];
3475 for (size_t i(0); i != [packages count]; ++i) {
3476 Package *package([packages objectAtIndex:i]);
3477 if ([[package performSelector:filter_ withObject:object_] boolValue])
3478 [packages_ addObject:package];
3481 Section *section = nil;
3483 for (size_t offset(0); offset != [packages_ count]; ++offset) {
3484 Package *package = [packages_ objectAtIndex:offset];
3485 NSString *name = [package index];
3487 if (section == nil || ![[section name] isEqualToString:name]) {
3488 section = [[[Section alloc] initWithName:name row:offset] autorelease];
3489 [sections_ addObject:section];
3492 [section addToCount];
3498 - (NSString *) title {
3502 - (void) resetViewAnimated:(BOOL)animated {
3503 [list_ resetViewAnimated:animated];
3506 - (void) resetCursor {
3507 [[list_ table] scrollPointVisibleAtTopLeft:CGPointMake(0, 0) animated:NO];
3510 - (UISectionList *) list {
3514 - (void) setShouldHideHeaderInShortLists:(BOOL)hide {
3515 [list_ setShouldHideHeaderInShortLists:hide];
3521 /* Browser Implementation {{{ */
3522 @implementation BrowserView
3525 WebView *webview = [webview_ webView];
3526 [webview setFrameLoadDelegate:nil];
3527 [webview setResourceLoadDelegate:nil];
3528 [webview setUIDelegate:nil];
3530 [scroller_ setDelegate:nil];
3531 [webview_ setDelegate:nil];
3533 [scroller_ release];
3536 [indicator_ release];
3542 - (void) loadURL:(NSURL *)url cachePolicy:(NSURLRequestCachePolicy)policy {
3543 NSMutableURLRequest *request = [NSMutableURLRequest
3546 timeoutInterval:30.0
3549 [request addValue:[NSString stringWithUTF8String:Firmware_] forHTTPHeaderField:@"X-Firmware"];
3550 [request addValue:[NSString stringWithUTF8String:Machine_] forHTTPHeaderField:@"X-Machine"];
3551 [request addValue:[NSString stringWithUTF8String:SerialNumber_] forHTTPHeaderField:@"X-Serial-Number"];
3553 [self loadRequest:request];
3557 - (void) loadURL:(NSURL *)url {
3558 [self loadURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy];
3561 // XXX: this needs to add the headers
3562 - (NSURLRequest *) _addHeadersToRequest:(NSURLRequest *)request {
3566 - (void) loadRequest:(NSURLRequest *)request {
3568 [webview_ loadRequest:request];
3571 - (void) reloadURL {
3572 NSURL *url = [[[urls_ lastObject] retain] autorelease];
3573 [urls_ removeLastObject];
3574 [self loadURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData];
3577 - (WebView *) webView {
3578 return [webview_ webView];
3581 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame {
3582 [scroller_ setContentSize:frame.size];
3585 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old {
3586 [self view:sender didSetFrame:frame];
3589 - (void) getAppTapp:(NSString *)href {
3590 if ([href hasPrefix:@"apptapp://package/"]) {
3591 NSString *name = [href substringFromIndex:18];
3592 Package *package = [database_ packageWithName:name];
3593 if (package == nil) {
3594 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
3595 initWithTitle:@"Cannot Locate Package"
3596 buttons:[NSArray arrayWithObjects:@"Close", nil]
3597 defaultButtonIndex:0
3602 [sheet setBodyText:[NSString stringWithFormat:
3603 @"The package %@ cannot be found in your current sources. I might recommend installing more sources."
3606 [sheet popupAlertAnimated:YES];
3608 [self setBackButtonTitle:title_];
3609 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
3610 [view setDelegate:delegate_];
3611 [view setPackage:package];
3612 [book_ pushPage:view];
3617 - (void) webView:(WebView *)sender willClickElement:(id)element {
3618 if (![element respondsToSelector:@selector(href)])
3620 NSString *href = [element href];
3623 if ([href hasPrefix:@"apptapp://package/"])
3624 [self getAppTapp:href];
3627 - (NSURLRequest *) webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource {
3628 if ([[[request URL] scheme] isEqualToString:@"apptapp"]) {
3629 [self getAppTapp:[[request URL] absoluteString]];
3635 [book_ pushPage:self];
3638 return [self _addHeadersToRequest:request];
3641 - (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request {
3642 if (request != nil && [[[request URL] scheme] isEqualToString:@"apptapp"])
3645 [self setBackButtonTitle:title_];
3647 BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease];
3648 [browser setDelegate:delegate_];
3650 if (request != nil) {
3651 [browser loadRequest:[self _addHeadersToRequest:request]];
3652 [book_ pushPage:browser];
3655 return [browser webView];
3659 - (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame {
3660 title_ = [title retain];
3661 [self setTitle:title];
3664 - (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame {
3665 if ([frame parentFrame] != nil)
3670 [indicator_ startAnimation];
3671 [self reloadButtons];
3673 if (title_ != nil) {
3678 [self setTitle:@"Loading..."];
3680 WebView *webview = [webview_ webView];
3681 NSString *href = [webview mainFrameURL];
3682 [urls_ addObject:[NSURL URLWithString:href]];
3684 CGRect webrect = [scroller_ frame];
3685 webrect.size.height = 0;
3686 [webview_ setFrame:webrect];
3689 - (void) _finishLoading {
3692 [indicator_ stopAnimation];
3693 [self reloadButtons];
3697 - (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
3698 if ([frame parentFrame] != nil)
3700 [self _finishLoading];
3703 - (void) webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
3704 if ([frame parentFrame] != nil)
3706 [self setTitle:[error localizedDescription]];
3707 [self _finishLoading];
3710 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3711 if ((self = [super initWithBook:book]) != nil) {
3712 database_ = database;
3715 struct CGRect bounds = [self bounds];
3717 UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:bounds] autorelease];
3718 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
3719 [self addSubview:pinstripe];
3721 scroller_ = [[UIScroller alloc] initWithFrame:bounds];
3722 [self addSubview:scroller_];
3724 [scroller_ setScrollingEnabled:YES];
3725 [scroller_ setAdjustForContentSizeChange:YES];
3726 [scroller_ setClipsSubviews:YES];
3727 [scroller_ setAllowsRubberBanding:YES];
3728 [scroller_ setScrollDecelerationFactor:0.99];
3729 [scroller_ setDelegate:self];
3731 CGRect webrect = [scroller_ bounds];
3732 webrect.size.height = 0;
3734 webview_ = [[UIWebView alloc] initWithFrame:webrect];
3735 [scroller_ addSubview:webview_];
3737 [webview_ setTilingEnabled:YES];
3738 [webview_ setTileSize:CGSizeMake(webrect.size.width, 500)];
3739 [webview_ setAutoresizes:YES];
3740 [webview_ setDelegate:self];
3741 //[webview_ setEnabledGestures:2];
3743 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:kUIProgressIndicatorStyleMediumWhite];
3744 indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(281, 42, indsize.width, indsize.height)];
3745 [indicator_ setStyle:kUIProgressIndicatorStyleMediumWhite];
3747 Package *package([database_ packageWithName:@"cydia"]);
3748 NSString *application = package == nil ? @"Cydia" : [NSString
3749 stringWithFormat:@"Cydia/%@",
3753 WebView *webview = [webview_ webView];
3754 [webview setApplicationNameForUserAgent:application];
3755 [webview setFrameLoadDelegate:self];
3756 [webview setResourceLoadDelegate:self];
3757 [webview setUIDelegate:self];
3759 urls_ = [[NSMutableArray alloc] initWithCapacity:16];
3763 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
3767 - (void) _leftButtonClicked {
3768 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
3769 initWithTitle:@"About Cydia Installer"
3770 buttons:[NSArray arrayWithObjects:@"Close", nil]
3771 defaultButtonIndex:0
3777 @"Copyright (C) 2008\n"
3778 "Jay Freeman (saurik)\n"
3779 "saurik@saurik.com\n"
3780 "http://www.saurik.com/\n"
3783 "http://www.theokorigroup.com/\n"
3785 "College of Creative Studies,\n"
3786 "University of California,\n"
3788 "http://www.ccs.ucsb.edu/"
3791 [sheet popupAlertAnimated:YES];
3794 - (void) _rightButtonClicked {
3799 - (NSString *) leftButtonTitle {
3803 - (NSString *) rightButtonTitle {
3804 return loading_ ? @"" : @"Reload";
3807 - (NSString *) title {
3811 - (NSString *) backButtonTitle {
3815 - (void) setPageActive:(BOOL)active {
3817 [book_ addSubview:indicator_];
3819 [indicator_ removeFromSuperview];
3822 - (void) resetViewAnimated:(BOOL)animated {
3825 - (void) setPushed:(bool)pushed {
3832 @interface CYBook : RVBook <
3835 _transient Database *database_;
3837 UIProgressIndicator *indicator_;
3838 UITextLabel *prompt_;
3839 UIProgressBar *progress_;
3843 - (id) initWithFrame:(CGRect)frame database:(Database *)database;
3849 /* Source Cell {{{ */
3850 @interface SourceCell : UITableCell {
3851 UITextLabel *description_;
3852 UIRightTextLabel *label_;
3853 UITextLabel *origin_;
3858 - (SourceCell *) initWithSource:(Source *)source;
3860 - (void) _setSelected:(float)fraction;
3861 - (void) setSelected:(BOOL)selected;
3862 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
3863 - (void) _setSelectionFadeFraction:(float)fraction;
3867 @implementation SourceCell
3870 [description_ release];
3876 - (SourceCell *) initWithSource:(Source *)source {
3877 if ((self = [super init]) != nil) {
3878 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 20);
3879 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 14);
3881 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
3882 float clear[] = {0, 0, 0, 0};
3884 NSString *description = [source description];
3885 if (description == nil)
3886 description = [source uri];
3888 description_ = [[UITextLabel alloc] initWithFrame:CGRectMake(12, 7, 270, 25)];
3889 [description_ setBackgroundColor:CGColorCreate(space, clear)];
3890 [description_ setFont:bold];
3891 [description_ setText:description];
3893 NSString *label = [source label];
3895 label = [source type];
3897 label_ = [[UIRightTextLabel alloc] initWithFrame:CGRectMake(290, 32, 90, 25)];
3898 [label_ setBackgroundColor:CGColorCreate(space, clear)];
3899 [label_ setFont:small];
3900 [label_ setText:label];
3902 NSString *origin = [source origin];
3904 origin = [source distribution];
3906 origin_ = [[UITextLabel alloc] initWithFrame:CGRectMake(13, 35, 315, 20)];
3907 [origin_ setBackgroundColor:CGColorCreate(space, clear)];
3908 [origin_ setFont:small];
3909 [origin_ setText:origin];
3911 [self addSubview:description_];
3912 [self addSubview:label_];
3913 [self addSubview:origin_];
3920 - (void) _setSelected:(float)fraction {
3921 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
3924 Interpolate(0.0, 1.0, fraction),
3925 Interpolate(0.0, 1.0, fraction),
3926 Interpolate(0.0, 1.0, fraction),
3930 Interpolate(0.2, 1.0, fraction),
3931 Interpolate(0.2, 1.0, fraction),
3932 Interpolate(1.0, 1.0, fraction),
3936 Interpolate(0.4, 1.0, fraction),
3937 Interpolate(0.4, 1.0, fraction),
3938 Interpolate(0.4, 1.0, fraction),
3941 [description_ setColor:CGColorCreate(space, black)];
3942 [label_ setColor:CGColorCreate(space, blue)];
3943 [origin_ setColor:CGColorCreate(space, gray)];
3946 - (void) setSelected:(BOOL)selected {
3947 [self _setSelected:(selected ? 1.0 : 0.0)];
3948 [super setSelected:selected];
3951 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
3953 [self _setSelected:(selected ? 1.0 : 0.0)];
3954 [super setSelected:selected withFade:fade];
3957 - (void) _setSelectionFadeFraction:(float)fraction {
3958 [self _setSelected:fraction];
3959 [super _setSelectionFadeFraction:fraction];
3964 /* Source Table {{{ */
3965 @interface SourceTable : RVPage {
3966 _transient Database *database_;
3967 UISectionList *list_;
3968 NSMutableArray *sources_;
3969 UIAlertSheet *alert_;
3972 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3976 @implementation SourceTable
3979 [list_ setDataSource:nil];
3981 if (sources_ != nil)
3987 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
3991 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
3995 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
3999 - (int) numberOfRowsInTable:(UITable *)table {
4000 return [sources_ count];
4003 - (float) table:(UITable *)table heightForRow:(int)row {
4007 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col {
4008 return [[[SourceCell alloc] initWithSource:[sources_ objectAtIndex:row]] autorelease];
4011 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
4015 - (void) tableRowSelected:(NSNotification*)notification {
4016 UITable *table([list_ table]);
4017 int row([table selectedRow]);
4021 [table selectRow:-1 byExtendingSelection:NO withFade:YES];
4024 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4025 if ((self = [super initWithBook:book]) != nil) {
4026 database_ = database;
4029 list_ = [[UISectionList alloc] initWithFrame:[self bounds]];
4031 [self addSubview:list_];
4033 [list_ setDataSource:self];
4034 [list_ setShouldHideHeaderInShortLists:NO];
4036 UITableColumn *column = [[UITableColumn alloc]
4037 initWithTitle:@"Name"
4039 width:[self frame].size.width
4042 UITable *table = [list_ table];
4043 [table setSeparatorStyle:1];
4044 [table addTableColumn:column];
4045 [table setDelegate:self];
4049 - (void) reloadData {
4051 _assert(list.ReadMainList());
4053 if (sources_ != nil)
4056 sources_ = [[NSMutableArray arrayWithCapacity:16] retain];
4057 for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source)
4058 [sources_ addObject:[[[Source alloc] initWithMetaIndex:*source] autorelease]];
4063 - (void) resetViewAnimated:(BOOL)animated {
4064 [list_ resetViewAnimated:animated];
4067 - (NSString *) leftTitle {
4068 return @"Refresh All";
4071 - (NSString *) rightTitle {
4078 /* Install View {{{ */
4079 @interface InstallView : RVPage {
4080 _transient Database *database_;
4081 NSMutableArray *packages_;
4082 NSMutableArray *sections_;
4087 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4088 - (void) reloadData;
4092 @implementation InstallView
4095 [list_ setDataSource:nil];
4096 [list_ setDelegate:nil];
4098 [packages_ release];
4099 [sections_ release];
4101 [accessory_ release];
4105 - (int) numberOfRowsInTable:(UITable *)table {
4106 return [sections_ count] + 1;
4109 - (float) table:(UITable *)table heightForRow:(int)row {
4113 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
4115 reusing = [[[SectionCell alloc] init] autorelease];
4116 [(SectionCell *)reusing setSection:(row == 0 ? nil : [sections_ objectAtIndex:(row - 1)])];
4120 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
4124 - (void) tableRowSelected:(NSNotification *)notification {
4125 int row = [[notification object] selectedRow];
4136 title = @"All Packages";
4138 section = [sections_ objectAtIndex:(row - 1)];
4139 name = [section name];
4145 title = @"(No Section)";
4149 PackageTable *table = [[[PackageTable alloc]
4153 filter:@selector(isUninstalledInSection:)
4157 [table setDelegate:delegate_];
4159 [book_ pushPage:table];
4162 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4163 if ((self = [super initWithBook:book]) != nil) {
4164 database_ = database;
4166 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
4167 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
4169 list_ = [[UITable alloc] initWithFrame:[self bounds]];
4170 [self addSubview:list_];
4172 UITableColumn *column = [[[UITableColumn alloc]
4173 initWithTitle:@"Name"
4175 width:[self frame].size.width
4178 [list_ setDataSource:self];
4179 [list_ setSeparatorStyle:1];
4180 [list_ addTableColumn:column];
4181 [list_ setDelegate:self];
4182 [list_ setReusesTableCells:YES];
4188 - (void) reloadData {
4189 NSArray *packages = [database_ packages];
4191 [packages_ removeAllObjects];
4192 [sections_ removeAllObjects];
4194 for (size_t i(0); i != [packages count]; ++i) {
4195 Package *package([packages objectAtIndex:i]);
4196 if ([package valid] && [package installed] == nil)
4197 [packages_ addObject:package];
4200 [packages_ sortUsingSelector:@selector(compareBySection:)];
4202 Section *section = nil;
4203 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
4204 Package *package = [packages_ objectAtIndex:offset];
4205 NSString *name = [package section];
4207 if (section == nil || name != nil && ![[section name] isEqualToString:name]) {
4208 section = [[[Section alloc] initWithName:name row:offset] autorelease];
4209 [sections_ addObject:section];
4212 [section addToCount];
4218 - (void) resetViewAnimated:(BOOL)animated {
4219 [list_ resetViewAnimated:animated];
4222 - (NSString *) title {
4226 - (NSString *) backButtonTitle {
4230 - (UIView *) accessoryView {
4236 /* Changes View {{{ */
4237 @interface ChangesView : RVPage {
4238 _transient Database *database_;
4239 NSMutableArray *packages_;
4240 NSMutableArray *sections_;
4241 UISectionList *list_;
4245 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4246 - (void) reloadData;
4250 @implementation ChangesView
4253 [[list_ table] setDelegate:nil];
4254 [list_ setDataSource:nil];
4256 [packages_ release];
4257 [sections_ release];
4262 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
4263 return [sections_ count];
4266 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
4267 return [[sections_ objectAtIndex:section] name];
4270 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
4271 return [[sections_ objectAtIndex:section] row];
4274 - (int) numberOfRowsInTable:(UITable *)table {
4275 return [packages_ count];
4278 - (float) table:(UITable *)table heightForRow:(int)row {
4279 return [PackageCell heightForPackage:[packages_ objectAtIndex:row]];
4282 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
4284 reusing = [[[PackageCell alloc] init] autorelease];
4285 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
4289 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
4293 - (void) tableRowSelected:(NSNotification *)notification {
4294 int row = [[notification object] selectedRow];
4297 Package *package = [packages_ objectAtIndex:row];
4298 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
4299 [view setDelegate:delegate_];
4300 [view setPackage:package];
4301 [book_ pushPage:view];
4304 - (void) _leftButtonClicked {
4305 [(CYBook *)book_ update];
4306 [self reloadButtons];
4309 - (void) _rightButtonClicked {
4310 [delegate_ distUpgrade];
4313 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4314 if ((self = [super initWithBook:book]) != nil) {
4315 database_ = database;
4317 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
4318 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
4320 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:NO];
4321 [self addSubview:list_];
4323 [list_ setShouldHideHeaderInShortLists:NO];
4324 [list_ setDataSource:self];
4325 //[list_ setSectionListStyle:1];
4327 UITableColumn *column = [[[UITableColumn alloc]
4328 initWithTitle:@"Name"
4330 width:[self frame].size.width
4333 UITable *table = [list_ table];
4334 [table setSeparatorStyle:1];
4335 [table addTableColumn:column];
4336 [table setDelegate:self];
4337 [table setReusesTableCells:YES];
4343 - (void) reloadData {
4344 NSArray *packages = [database_ packages];
4346 [packages_ removeAllObjects];
4347 [sections_ removeAllObjects];
4349 for (size_t i(0); i != [packages count]; ++i) {
4350 Package *package([packages objectAtIndex:i]);
4351 if ([package installed] == nil && [package valid] || [package upgradableAndEssential:NO])
4352 [packages_ addObject:package];
4355 [packages_ sortUsingSelector:@selector(compareForChanges:)];
4357 Section *upgradable = [[[Section alloc] initWithName:@"Available Upgrades" row:0] autorelease];
4358 Section *section = nil;
4361 bool unseens = false;
4363 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, Locale_, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
4365 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
4366 Package *package = [packages_ objectAtIndex:offset];
4368 if ([package upgradableAndEssential:YES]) {
4370 [upgradable addToCount];
4373 NSDate *seen = [package seen];
4378 name = [@"n/a ?" retain];
4380 name = (NSString *) CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen);
4383 if (section == nil || ![[section name] isEqualToString:name]) {
4384 section = [[[Section alloc] initWithName:name row:offset] autorelease];
4385 [sections_ addObject:section];
4389 [section addToCount];
4393 CFRelease(formatter);
4396 Section *last = [sections_ lastObject];
4397 size_t count = [last count];
4398 [packages_ removeObjectsInRange:NSMakeRange([packages_ count] - count, count)];
4399 [sections_ removeLastObject];
4403 [sections_ insertObject:upgradable atIndex:0];
4406 [self reloadButtons];
4409 - (void) resetViewAnimated:(BOOL)animated {
4410 [list_ resetViewAnimated:animated];
4413 - (NSString *) leftButtonTitle {
4414 return [(CYBook *)book_ updating] ? nil : @"Refresh";
4417 - (NSString *) rightButtonTitle {
4418 return upgrades_ == 0 ? nil : [NSString stringWithFormat:@"Upgrade All (%u)", upgrades_];
4421 - (NSString *) title {
4427 /* Manage View {{{ */
4428 @interface ManageView : RVPage {
4429 _transient Database *database_;
4430 PackageTable *packages_;
4431 SourceTable *sources_;
4434 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4438 @implementation ManageView
4441 [packages_ release];
4446 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4447 if ((self = [super initWithBook:book]) != nil) {
4448 database_ = database;
4450 packages_ = [[PackageTable alloc]
4454 filter:@selector(isInstalledInSection:)
4458 sources_ = [[SourceTable alloc]
4463 [self addSubview:packages_];
4467 - (void) resetViewAnimated:(BOOL)animated {
4468 [packages_ resetViewAnimated:animated];
4469 [sources_ resetViewAnimated:animated];
4472 - (void) reloadData {
4473 [packages_ reloadData];
4474 [sources_ reloadData];
4477 - (NSString *) title {
4478 return @"Installed Packages";
4481 - (NSString *) backButtonTitle {
4485 - (void) setDelegate:(id)delegate {
4486 [super setDelegate:delegate];
4487 [packages_ setDelegate:delegate];
4488 [sources_ setDelegate:delegate];
4493 /* Search View {{{ */
4494 @protocol SearchViewDelegate
4495 - (void) showKeyboard:(BOOL)show;
4498 @interface SearchView : RVPage {
4500 UISearchField *field_;
4501 UITransitionView *transition_;
4502 PackageTable *table_;
4503 UIPreferencesTable *advanced_;
4509 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4510 - (void) reloadData;
4514 @implementation SearchView
4518 [[field_ textTraits] setEditingDelegate:nil];
4520 [field_ setDelegate:nil];
4522 [accessory_ release];
4524 [transition_ release];
4526 [advanced_ release];
4531 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
4535 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
4537 case 0: return @"Advanced Search (Coming Soon!)";
4539 default: _assert(false);
4543 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
4547 default: _assert(false);
4551 - (void) _showKeyboard:(BOOL)show {
4552 CGSize keysize = [UIKeyboard defaultSize];
4553 CGRect keydown = [book_ pageBounds];
4554 CGRect keyup = keydown;
4555 keyup.size.height -= keysize.height - ButtonBarHeight_;
4557 float delay = KeyboardTime_ * ButtonBarHeight_ / keysize.height;
4559 UIFrameAnimation *animation = [[[UIFrameAnimation alloc] initWithTarget:[table_ list]] autorelease];
4560 [animation setSignificantRectFields:8];
4563 [animation setStartFrame:keydown];
4564 [animation setEndFrame:keyup];
4566 [animation setStartFrame:keyup];
4567 [animation setEndFrame:keydown];
4570 UIAnimator *animator = [UIAnimator sharedAnimator];
4573 addAnimations:[NSArray arrayWithObjects:animation, nil]
4574 withDuration:(KeyboardTime_ - delay)
4579 [animator performSelector:@selector(startAnimation:) withObject:animation afterDelay:delay];
4582 [delegate_ showKeyboard:show];
4586 - (void) textFieldDidBecomeFirstResponder:(UITextField *)field {
4587 [self _showKeyboard:YES];
4590 - (void) textFieldDidResignFirstResponder:(UITextField *)field {
4591 [self _showKeyboard:NO];
4594 - (void) keyboardInputChanged:(UIFieldEditor *)editor {
4596 NSString *text([field_ text]);
4597 [field_ setClearButtonStyle:(text == nil || [text length] == 0 ? 0 : 2)];
4603 - (void) textFieldClearButtonPressed:(UITextField *)field {
4607 - (void) keyboardInputShouldDelete:(id)input {
4611 - (BOOL) keyboardInput:(id)input shouldInsertText:(NSString *)text isMarkedText:(int)marked {
4612 if ([text length] != 1 || [text characterAtIndex:0] != '\n') {
4616 [field_ resignFirstResponder];
4621 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4622 if ((self = [super initWithBook:book]) != nil) {
4623 CGRect pageBounds = [book_ pageBounds];
4625 /*UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:pageBounds] autorelease];
4626 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
4627 [self addSubview:pinstripe];*/
4629 transition_ = [[UITransitionView alloc] initWithFrame:pageBounds];
4630 [self addSubview:transition_];
4632 advanced_ = [[UIPreferencesTable alloc] initWithFrame:pageBounds];
4634 [advanced_ setReusesTableCells:YES];
4635 [advanced_ setDataSource:self];
4636 [advanced_ reloadData];
4638 dimmed_ = [[UIView alloc] initWithFrame:pageBounds];
4639 CGColor dimmed(space_, 0, 0, 0, 0.5);
4640 [dimmed_ setBackgroundColor:dimmed];
4642 table_ = [[PackageTable alloc]
4646 filter:@selector(isSearchedForBy:)
4650 [table_ setShouldHideHeaderInShortLists:NO];
4651 [transition_ transition:0 toView:table_];
4660 area.origin.x = cnfrect.origin.x + cnfrect.size.width + 14;
4667 [self bounds].size.width - area.origin.x - 18;
4669 area.size.height = [UISearchField defaultHeight];
4671 field_ = [[UISearchField alloc] initWithFrame:area];
4673 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
4674 [field_ setFont:font];
4677 [field_ setPlaceholder:@"Package Names & Descriptions"];
4678 [field_ setDelegate:self];
4681 [field_ setPaddingTop:3];
4683 [field_ setPaddingTop:5];
4687 UITextTraits *traits = [field_ textTraits];
4688 [traits setEditingDelegate:self];
4689 [traits setReturnKeyType:6];
4690 [traits setAutoCapsType:0];
4691 [traits setAutoCorrectionType:1];
4694 CGRect accrect = {{0, 6}, {6 + cnfrect.size.width + 6 + area.size.width + 6, area.size.height + 30}};
4696 accessory_ = [[UIView alloc] initWithFrame:accrect];
4697 [accessory_ addSubview:field_];
4699 UIPushButton *configure = [[[UIPushButton alloc] initWithFrame:cnfrect] autorelease];
4700 [configure setShowPressFeedback:YES];
4701 [configure setImage:[UIImage applicationImageNamed:@"advanced.png"]];
4702 [configure addTarget:self action:@selector(configurePushed) forEvents:1];
4703 [accessory_ addSubview:configure];
4709 LKAnimation *animation = [LKTransition animation];
4710 [animation setType:@"oglFlip"];
4711 [animation setTimingFunction:[LKTimingFunction functionWithName:@"easeInEaseOut"]];
4712 [animation setFillMode:@"extended"];
4713 [animation setTransitionFlags:3];
4714 [animation setDuration:10];
4715 [animation setSpeed:0.35];
4716 [animation setSubtype:(flipped_ ? @"fromLeft" : @"fromRight")];
4717 [[transition_ _layer] addAnimation:animation forKey:0];
4718 [transition_ transition:0 toView:(flipped_ ? (UIView *) table_ : (UIView *) advanced_)];
4719 flipped_ = !flipped_;
4723 - (void) configurePushed {
4724 [field_ resignFirstResponder];
4728 - (void) resetViewAnimated:(BOOL)animated {
4731 [table_ resetViewAnimated:animated];
4734 - (void) reloadData {
4737 [table_ setObject:[field_ text]];
4738 [table_ reloadData];
4739 [table_ resetCursor];
4742 - (UIView *) accessoryView {
4746 - (NSString *) title {
4750 - (NSString *) backButtonTitle {
4754 - (void) setDelegate:(id)delegate {
4755 [table_ setDelegate:delegate];
4756 [super setDelegate:delegate];
4762 @implementation CYBook
4766 [indicator_ release];
4768 [progress_ release];
4772 - (NSString *) getTitleForPage:(RVPage *)page {
4773 return Simplify([super getTitleForPage:page]);
4781 [navbar_ setPrompt:@""];
4782 [navbar_ addSubview:overlay_];
4783 [indicator_ startAnimation];
4784 [prompt_ setText:@"Updating Database..."];
4785 [progress_ setProgress:0];
4790 detachNewThreadSelector:@selector(_update)
4799 [overlay_ removeFromSuperview];
4800 [indicator_ stopAnimation];
4801 [delegate_ reloadData];
4803 [self setPrompt:[NSString stringWithFormat:@"Last Updated: %@", GetLastUpdate()]];
4806 - (id) initWithFrame:(CGRect)frame database:(Database *)database {
4807 if ((self = [super initWithFrame:frame]) != nil) {
4808 database_ = database;
4811 [navbar_ setBarStyle:1];
4813 CGRect ovrrect = [navbar_ bounds];
4814 ovrrect.size.height = ([UINavigationBar defaultSizeWithPrompt].height - [UINavigationBar defaultSize].height);
4816 overlay_ = [[UIView alloc] initWithFrame:ovrrect];
4818 UIProgressIndicatorStyle style = Advanced_ ?
4819 kUIProgressIndicatorStyleSmallWhite :
4820 kUIProgressIndicatorStyleSmallBlack;
4822 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:style];
4823 unsigned indoffset = (ovrrect.size.height - indsize.height) / 2;
4824 CGRect indrect = {{indoffset, indoffset}, indsize};
4826 indicator_ = [[UIProgressIndicator alloc] initWithFrame:indrect];
4827 [indicator_ setStyle:style];
4828 [overlay_ addSubview:indicator_];
4830 CGSize prmsize = {200, indsize.width + 4};
4833 indoffset * 2 + indsize.width,
4837 (ovrrect.size.height - prmsize.height) / 2
4840 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 12);
4842 prompt_ = [[UITextLabel alloc] initWithFrame:prmrect];
4844 [prompt_ setColor:(Advanced_ ? White_ : Blueish_)];
4845 [prompt_ setBackgroundColor:Clear_];
4846 [prompt_ setFont:font];
4850 [overlay_ addSubview:prompt_];
4852 CGSize prgsize = {75, 100};
4855 ovrrect.size.width - prgsize.width - 10,
4856 (ovrrect.size.height - prgsize.height) / 2
4859 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
4860 [progress_ setStyle:0];
4861 [overlay_ addSubview:progress_];
4866 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
4869 status.setDelegate(self);
4871 [database_ updateWithStatus:status];
4874 performSelectorOnMainThread:@selector(_update_)
4882 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id {
4883 [prompt_ setText:[NSString stringWithFormat:@"Error: %@", error]];
4886 - (void) setProgressTitle:(NSString *)title {
4888 performSelectorOnMainThread:@selector(_setProgressTitle:)
4894 - (void) setProgressPercent:(float)percent {
4897 - (void) addProgressOutput:(NSString *)output {
4899 performSelectorOnMainThread:@selector(_addProgressOutput:)
4905 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
4909 - (void) _setProgressTitle:(NSString *)title {
4910 [prompt_ setText:[title stringByAppendingString:@"..."]];
4913 - (void) _addProgressOutput:(NSString *)output {
4918 @interface Cydia : UIApplication <
4919 ConfirmationViewDelegate,
4920 ProgressViewDelegate,
4929 UIButtonBar *buttonbar_;
4931 ConfirmationView *confirm_;
4933 NSMutableArray *essential_;
4934 NSMutableArray *broken_;
4936 Database *database_;
4937 ProgressView *progress_;
4941 UIKeyboard *keyboard_;
4942 UIProgressHUD *hud_;
4944 InstallView *install_;
4945 ChangesView *changes_;
4946 ManageView *manage_;
4947 SearchView *search_;
4952 @implementation Cydia
4955 if ([broken_ count] != 0) {
4956 int count = [broken_ count];
4958 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
4959 initWithTitle:[NSString stringWithFormat:@"%d Half-Installed Package%@", count, (count == 1 ? @"" : @"s")]
4960 buttons:[NSArray arrayWithObjects:
4962 @"Ignore (Temporary)",
4964 defaultButtonIndex:0
4969 [sheet setBodyText:@"When the shell scripts associated with packages fail, they are left in a bad state known as either half-configured or half-installed. These errors don't go away and instead continue to cause issues. These scripts can be deleted and the packages forcibly removed."];
4970 [sheet popupAlertAnimated:YES];
4971 } else if (!Ignored_ && [essential_ count] != 0) {
4972 int count = [essential_ count];
4974 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
4975 initWithTitle:[NSString stringWithFormat:@"%d Essential Upgrade%@", count, (count == 1 ? @"" : @"s")]
4976 buttons:[NSArray arrayWithObjects:@"Upgrade Essential", @"Ignore (Temporary)", nil]
4977 defaultButtonIndex:0
4982 [sheet setBodyText:@"One or more essential packages are currently out of date. If these upgrades are not performed you are likely to encounter errors."];
4983 [sheet popupAlertAnimated:YES];
4987 - (void) _reloadData {
4988 /*UIProgressHUD *hud = [[UIProgressHUD alloc] initWithWindow:window_];
4989 [hud setText:@"Reloading Data"];
4990 [overlay_ addSubview:hud];
4993 [database_ reloadData];
4995 if (Packages_ == nil) {
4996 Packages_ = [[NSMutableDictionary alloc] initWithCapacity:128];
4997 [Metadata_ setObject:Packages_ forKey:@"Packages"];
5002 [essential_ removeAllObjects];
5003 [broken_ removeAllObjects];
5005 NSArray *packages = [database_ packages];
5006 for (int i(0), e([packages count]); i != e; ++i) {
5007 Package *package = [packages objectAtIndex:i];
5009 [broken_ addObject:package];
5010 if ([package upgradableAndEssential:NO]) {
5011 if ([package essential])
5012 [essential_ addObject:package];
5018 NSString *badge([[NSNumber numberWithInt:changes] stringValue]);
5019 [buttonbar_ setBadgeValue:badge forButton:3];
5020 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
5021 [buttonbar_ setBadgeAnimated:YES forButton:3];
5022 [self setApplicationBadge:badge];
5024 [buttonbar_ setBadgeValue:nil forButton:3];
5025 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
5026 [buttonbar_ setBadgeAnimated:NO forButton:3];
5027 [self removeApplicationBadge];
5031 _assert([Metadata_ writeToFile:@"/var/lib/cydia/metadata.plist" atomically:YES] == YES);
5035 /* XXX: this is just stupid */
5037 [install_ reloadData];
5039 [changes_ reloadData];
5041 [manage_ reloadData];
5043 [search_ reloadData];
5047 if ([packages count] == 0);
5056 [hud removeFromSuperview];*/
5059 - (void) reloadData {
5060 @synchronized (self) {
5061 if (confirm_ == nil)
5067 pkgProblemResolver *resolver = [database_ resolver];
5069 resolver->InstallProtect();
5070 if (!resolver->Resolve(true))
5075 [database_ prepare];
5077 if ([database_ cache]->BrokenCount() == 0)
5078 confirm_ = [[ConfirmationView alloc] initWithView:underlay_ database:database_ delegate:self];
5080 NSMutableArray *broken = [NSMutableArray arrayWithCapacity:16];
5081 NSArray *packages = [database_ packages];
5083 for (size_t i(0); i != [packages count]; ++i) {
5084 Package *package = [packages objectAtIndex:i];
5085 if ([package broken])
5086 [broken addObject:[package name]];
5089 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
5090 initWithTitle:[NSString stringWithFormat:@"%d Broken Packages", [database_ cache]->BrokenCount()]
5091 buttons:[NSArray arrayWithObjects:@"Okay", nil]
5092 defaultButtonIndex:0
5097 [sheet setBodyText:[NSString stringWithFormat:@"The following packages have unmet dependencies:\n\n%@", [broken componentsJoinedByString:@"\n"]]];
5098 [sheet popupAlertAnimated:YES];
5104 - (void) installPackage:(Package *)package {
5105 @synchronized (self) {
5112 - (void) removePackage:(Package *)package {
5113 @synchronized (self) {
5120 - (void) distUpgrade {
5121 @synchronized (self) {
5122 [database_ upgrade];
5128 @synchronized (self) {
5136 [overlay_ removeFromSuperview];
5140 detachNewThreadSelector:@selector(perform)
5147 - (void) bootstrap_ {
5149 [database_ upgrade];
5150 [database_ prepare];
5151 [database_ perform];
5154 - (void) bootstrap {
5156 detachNewThreadSelector:@selector(bootstrap_)
5159 title:@"Bootstrap Install..."
5163 - (void) progressViewIsComplete:(ProgressView *)progress {
5164 @synchronized (self) {
5167 if (confirm_ != nil) {
5168 [underlay_ addSubview:overlay_];
5169 [confirm_ removeFromSuperview];
5176 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
5177 NSString *context = [sheet context];
5178 if ([context isEqualToString:@"fixhalf"])
5181 @synchronized (self) {
5182 for (int i = 0, e = [broken_ count]; i != e; ++i) {
5183 Package *broken = [broken_ objectAtIndex:i];
5186 NSString *id = [broken id];
5187 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.prerm", id] UTF8String]);
5188 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.postrm", id] UTF8String]);
5189 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.preinst", id] UTF8String]);
5190 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.postinst", id] UTF8String]);
5199 [broken_ removeAllObjects];
5206 else if ([context isEqualToString:@"upgrade"])
5209 @synchronized (self) {
5210 for (int i = 0, e = [essential_ count]; i != e; ++i) {
5211 Package *essential = [essential_ objectAtIndex:i];
5212 [essential install];
5231 - (void) setPage:(RVPage *)page {
5232 [page resetViewAnimated:NO];
5233 [page setDelegate:self];
5234 [book_ setPage:page];
5237 - (RVPage *) _setHomePage {
5238 BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease];
5239 [self setPage:browser];
5240 [browser loadURL:[NSURL URLWithString:@"http://cydia.saurik.com/"]];
5244 - (void) buttonBarItemTapped:(id)sender {
5245 unsigned tag = [sender tag];
5247 [book_ resetViewAnimated:YES];
5252 case 1: [self _setHomePage]; break;
5254 case 2: [self setPage:install_]; break;
5255 case 3: [self setPage:changes_]; break;
5256 case 4: [self setPage:manage_]; break;
5257 case 5: [self setPage:search_]; break;
5259 default: _assert(false);
5265 - (void) applicationWillSuspend {
5270 notify_post("com.apple.mobile.application_installed");
5271 notify_post("com.apple.mobile.application_uninstalled");
5273 pid_t pid = ExecFork();
5279 if (pid_t child = fork()) {
5280 waitpid(child, NULL, 0);
5282 execlp("launchctl", "launchctl", "unload", SpringBoard_, NULL);
5283 perror("launchctl unload");
5287 execlp("launchctl", "launchctl", "load", SpringBoard_, NULL);
5288 perror("launchctl load");
5294 [super applicationWillSuspend];
5299 [self setStatusBarShowsProgress:NO];
5302 [hud_ removeFromSuperview];
5307 [self suspendWithAnimation:YES];
5311 overlay_ = [[UIView alloc] initWithFrame:[underlay_ bounds]];
5313 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
5314 book_ = [[CYBook alloc] initWithFrame:CGRectMake(
5315 0, 0, screenrect.size.width, screenrect.size.height - 48
5316 ) database:database_];
5318 [book_ setDelegate:self];
5320 [overlay_ addSubview:book_];
5322 NSArray *buttonitems = [NSArray arrayWithObjects:
5323 [NSDictionary dictionaryWithObjectsAndKeys:
5324 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5325 @"home-up.png", kUIButtonBarButtonInfo,
5326 @"home-dn.png", kUIButtonBarButtonSelectedInfo,
5327 [NSNumber numberWithInt:1], kUIButtonBarButtonTag,
5328 self, kUIButtonBarButtonTarget,
5329 @"Home", kUIButtonBarButtonTitle,
5330 @"0", kUIButtonBarButtonType,
5333 [NSDictionary dictionaryWithObjectsAndKeys:
5334 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5335 @"install-up.png", kUIButtonBarButtonInfo,
5336 @"install-dn.png", kUIButtonBarButtonSelectedInfo,
5337 [NSNumber numberWithInt:2], kUIButtonBarButtonTag,
5338 self, kUIButtonBarButtonTarget,
5339 @"Install", kUIButtonBarButtonTitle,
5340 @"0", kUIButtonBarButtonType,
5343 [NSDictionary dictionaryWithObjectsAndKeys:
5344 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5345 @"changes-up.png", kUIButtonBarButtonInfo,
5346 @"changes-dn.png", kUIButtonBarButtonSelectedInfo,
5347 [NSNumber numberWithInt:3], kUIButtonBarButtonTag,
5348 self, kUIButtonBarButtonTarget,
5349 @"Changes", kUIButtonBarButtonTitle,
5350 @"0", kUIButtonBarButtonType,
5353 [NSDictionary dictionaryWithObjectsAndKeys:
5354 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5355 @"manage-up.png", kUIButtonBarButtonInfo,
5356 @"manage-dn.png", kUIButtonBarButtonSelectedInfo,
5357 [NSNumber numberWithInt:4], kUIButtonBarButtonTag,
5358 self, kUIButtonBarButtonTarget,
5359 @"Manage", kUIButtonBarButtonTitle,
5360 @"0", kUIButtonBarButtonType,
5363 [NSDictionary dictionaryWithObjectsAndKeys:
5364 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5365 @"search-up.png", kUIButtonBarButtonInfo,
5366 @"search-dn.png", kUIButtonBarButtonSelectedInfo,
5367 [NSNumber numberWithInt:5], kUIButtonBarButtonTag,
5368 self, kUIButtonBarButtonTarget,
5369 @"Search", kUIButtonBarButtonTitle,
5370 @"0", kUIButtonBarButtonType,
5374 buttonbar_ = [[UIButtonBar alloc]
5376 withFrame:CGRectMake(
5377 0, screenrect.size.height - ButtonBarHeight_,
5378 screenrect.size.width, ButtonBarHeight_
5380 withItemList:buttonitems
5383 [buttonbar_ setDelegate:self];
5384 [buttonbar_ setBarStyle:1];
5385 [buttonbar_ setButtonBarTrackingMode:2];
5387 int buttons[5] = {1, 2, 3, 4, 5};
5388 [buttonbar_ registerButtonGroup:0 withButtons:buttons withCount:5];
5389 [buttonbar_ showButtonGroup:0 withDuration:0];
5391 for (int i = 0; i != 5; ++i)
5392 [[buttonbar_ viewWithTag:(i + 1)] setFrame:CGRectMake(
5393 i * 64 + 2, 1, 60, ButtonBarHeight_
5396 [buttonbar_ showSelectionForButton:1];
5397 [overlay_ addSubview:buttonbar_];
5399 [UIKeyboard initImplementationNow];
5400 CGSize keysize = [UIKeyboard defaultSize];
5401 CGRect keyrect = {{0, [overlay_ bounds].size.height}, keysize};
5402 keyboard_ = [[UIKeyboard alloc] initWithFrame:keyrect];
5403 [[UIKeyboardImpl sharedInstance] setSoundsEnabled:(Sounds_Keyboard_ ? YES : NO)];
5404 [overlay_ addSubview:keyboard_];
5406 install_ = [[InstallView alloc] initWithBook:book_ database:database_];
5407 changes_ = [[ChangesView alloc] initWithBook:book_ database:database_];
5408 manage_ = [[ManageView alloc] initWithBook:book_ database:database_];
5409 search_ = [[SearchView alloc] initWithBook:book_ database:database_];
5412 [underlay_ addSubview:overlay_];
5419 [self _setHomePage];
5422 - (void) reorganize {
5423 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5424 system("/usr/libexec/cydia/free.sh");
5425 [self performSelectorOnMainThread:@selector(finish) withObject:nil waitUntilDone:NO];
5429 - (void) applicationSuspend:(__GSEvent *)event {
5430 if (hud_ == nil && ![progress_ isRunning])
5431 [super applicationSuspend:event];
5434 - (void) applicationDidFinishLaunching:(id)unused {
5435 _assert(pkgInitConfig(*_config));
5436 _assert(pkgInitSystem(*_config, _system));
5441 essential_ = [[NSMutableArray alloc] initWithCapacity:4];
5442 broken_ = [[NSMutableArray alloc] initWithCapacity:4];
5444 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
5445 window_ = [[UIWindow alloc] initWithContentRect:screenrect];
5447 [window_ orderFront: self];
5448 [window_ makeKey: self];
5449 [window_ _setHidden: NO];
5451 database_ = [[Database alloc] init];
5452 progress_ = [[ProgressView alloc] initWithFrame:[window_ bounds] database:database_ delegate:self];
5453 [database_ setDelegate:progress_];
5454 [window_ setContentView:progress_];
5456 underlay_ = [[UIView alloc] initWithFrame:[progress_ bounds]];
5457 [progress_ setContentView:underlay_];
5459 [progress_ resetView];
5462 readlink("/Applications", NULL, 0) == -1 && errno == EINVAL ||
5463 readlink("/usr/share", NULL, 0) == -1 && errno == EINVAL ||
5464 readlink("/Library/Ringtones", NULL, 0) == -1 && errno == EINVAL ||
5465 readlink("/Library/Wallpapers", NULL, 0) == -1 && errno == EINVAL
5467 hud_ = [[UIProgressHUD alloc] initWithWindow:window_];
5468 [hud_ setText:@"Reorganizing\nOne Minute!\nPlease Wait...\nDO NOT STOP"];
5470 [underlay_ addSubview:hud_];
5472 [self setStatusBarShowsProgress:YES];
5475 detachNewThreadSelector:@selector(reorganize)
5483 - (void) showKeyboard:(BOOL)show {
5484 CGSize keysize = [UIKeyboard defaultSize];
5485 CGRect keydown = {{0, [overlay_ bounds].size.height}, keysize};
5486 CGRect keyup = keydown;
5487 keyup.origin.y -= keysize.height;
5489 UIFrameAnimation *animation = [[[UIFrameAnimation alloc] initWithTarget:keyboard_] autorelease];
5490 [animation setSignificantRectFields:2];
5493 [animation setStartFrame:keydown];
5494 [animation setEndFrame:keyup];
5495 [keyboard_ activate];
5497 [animation setStartFrame:keyup];
5498 [animation setEndFrame:keydown];
5499 [keyboard_ deactivate];
5502 [[UIAnimator sharedAnimator]
5503 addAnimations:[NSArray arrayWithObjects:animation, nil]
5504 withDuration:KeyboardTime_
5509 - (void) slideUp:(UIAlertSheet *)alert {
5511 [alert presentSheetFromButtonBar:buttonbar_];
5513 [alert presentSheetInView:overlay_];
5518 void AddPreferences(NSString *plist) {
5519 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5521 NSMutableDictionary *settings = [[[NSMutableDictionary alloc] initWithContentsOfFile:plist] autorelease];
5522 _assert(settings != NULL);
5523 NSMutableArray *items = [settings objectForKey:@"items"];
5527 for (size_t i(0); i != [items count]; ++i) {
5528 NSMutableDictionary *item([items objectAtIndex:i]);
5529 NSString *label = [item objectForKey:@"label"];
5530 if (label != nil && [label isEqualToString:@"Cydia"]) {
5537 for (size_t i(0); i != [items count]; ++i) {
5538 NSDictionary *item([items objectAtIndex:i]);
5539 NSString *label = [item objectForKey:@"label"];
5540 if (label != nil && [label isEqualToString:@"General"]) {
5541 [items insertObject:[NSDictionary dictionaryWithObjectsAndKeys:
5542 @"CydiaSettings", @"bundle",
5543 @"PSLinkCell", @"cell",
5544 [NSNumber numberWithBool:YES], @"hasIcon",
5545 [NSNumber numberWithBool:YES], @"isController",
5547 nil] atIndex:(i + 1)];
5553 _assert([settings writeToFile:plist atomically:YES] == YES);
5560 id Alloc_(id self, SEL selector) {
5561 id object = alloc_(self, selector);
5562 fprintf(stderr, "[%s]A-%p\n", self->isa->name, object);
5567 id Dealloc_(id self, SEL selector) {
5568 id object = dealloc_(self, selector);
5569 fprintf(stderr, "[%s]D-%p\n", self->isa->name, object);
5573 int main(int argc, char *argv[]) {
5574 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5576 bootstrap_ = argc > 1 && strcmp(argv[1], "--bootstrap") == 0;
5578 Home_ = NSHomeDirectory();
5581 NSString *plist = [Home_ stringByAppendingString:@"/Library/Preferences/com.apple.preferences.sounds.plist"];
5582 if (NSDictionary *sounds = [NSDictionary dictionaryWithContentsOfFile:plist])
5583 if (NSNumber *keyboard = [sounds objectForKey:@"keyboard"])
5584 Sounds_Keyboard_ = [keyboard boolValue];
5590 if (unlink("/var/cache/apt/pkgcache.bin") == -1)
5591 _assert(errno == ENOENT);
5592 if (unlink("/var/cache/apt/srcpkgcache.bin") == -1)
5593 _assert(errno == ENOENT);
5595 /*Method alloc = class_getClassMethod([NSObject class], @selector(alloc));
5596 alloc_ = alloc->method_imp;
5597 alloc->method_imp = (IMP) &Alloc_;*/
5599 /*Method dealloc = class_getClassMethod([NSObject class], @selector(dealloc));
5600 dealloc_ = dealloc->method_imp;
5601 dealloc->method_imp = (IMP) &Dealloc_;*/
5603 if (NSDictionary *sysver = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]) {
5604 if (NSString *prover = [sysver valueForKey:@"ProductVersion"]) {
5605 Firmware_ = strdup([prover UTF8String]);
5606 NSArray *versions = [prover componentsSeparatedByString:@"."];
5607 int count = [versions count];
5608 Major_ = count > 0 ? [[versions objectAtIndex:0] intValue] : 0;
5609 Minor_ = count > 1 ? [[versions objectAtIndex:1] intValue] : 0;
5610 BugFix_ = count > 2 ? [[versions objectAtIndex:2] intValue] : 0;
5615 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
5616 char *machine = new char[size];
5617 sysctlbyname("hw.machine", machine, &size, NULL, 0);
5620 if (CFMutableDictionaryRef dict = IOServiceMatching("IOPlatformExpertDevice"))
5621 if (io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, dict)) {
5622 if (CFTypeRef serial = IORegistryEntryCreateCFProperty(service, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0)) {
5623 SerialNumber_ = strdup(CFStringGetCStringPtr((CFStringRef) serial, CFStringGetSystemEncoding()));
5627 IOObjectRelease(service);
5630 /*AddPreferences(@"/Applications/Preferences.app/Settings-iPhone.plist");
5631 AddPreferences(@"/Applications/Preferences.app/Settings-iPod.plist");*/
5633 if ((Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"]) == NULL)
5634 Metadata_ = [[NSMutableDictionary alloc] initWithCapacity:2];
5636 Packages_ = [Metadata_ objectForKey:@"Packages"];
5638 if (access("/User", F_OK) != 0)
5639 system("/usr/libexec/cydia/firmware.sh");
5641 Locale_ = CFLocaleCopyCurrent();
5642 space_ = CGColorSpaceCreateDeviceRGB();
5644 Blueish_.Set(space_, 0x19/255.f, 0x32/255.f, 0x50/255.f, 1.0);
5645 Black_.Set(space_, 0.0, 0.0, 0.0, 1.0);
5646 Clear_.Set(space_, 0.0, 0.0, 0.0, 0.0);
5647 Red_.Set(space_, 1.0, 0.0, 0.0, 1.0);
5648 White_.Set(space_, 1.0, 1.0, 1.0, 1.0);
5650 int value = UIApplicationMain(argc, argv, [Cydia class]);
5652 CGColorSpaceRelease(space_);