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];
2379 notify_post("com.apple.mobile.application_installed");
2382 [delegate_ setStatusBarShowsProgress:NO];
2383 //[[UIApplication sharedApplication] setIdleTimerDisabled:YES];
2388 - (void) _detachNewThreadData:(ProgressData *)data {
2389 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
2391 [[data target] performSelector:[data selector] withObject:[data object]];
2394 [self performSelectorOnMainThread:@selector(_retachThread) withObject:nil waitUntilDone:YES];
2399 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title {
2400 UINavigationItem *item = [navbar_ topItem];
2401 [item setTitle:title];
2403 [status_ setText:nil];
2404 [output_ setText:@""];
2405 [progress_ setProgress:0];
2407 [close_ removeFromSuperview];
2408 [overlay_ addSubview:progress_];
2409 [overlay_ addSubview:status_];
2411 [delegate_ setStatusBarShowsProgress:YES];
2414 [transition_ transition:6 toView:overlay_];
2417 detachNewThreadSelector:@selector(_detachNewThreadData:)
2419 withObject:[[ProgressData alloc]
2420 initWithSelector:selector
2427 - (void) repairWithSelector:(SEL)selector {
2429 detachNewThreadSelector:selector
2432 title:@"Repairing..."
2436 - (void) setConfigurationData:(NSString *)data {
2438 performSelectorOnMainThread:@selector(_setConfigurationData:)
2444 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id {
2445 Package *package = id == nil ? nil : [database_ packageWithName:id];
2447 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
2448 initWithTitle:(package == nil ? @"Source Error" : [package name])
2449 buttons:[NSArray arrayWithObjects:@"Okay", nil]
2450 defaultButtonIndex:0
2455 [sheet setBodyText:error];
2456 [sheet popupAlertAnimated:YES];
2459 - (void) setProgressTitle:(NSString *)title {
2461 performSelectorOnMainThread:@selector(_setProgressTitle:)
2467 - (void) setProgressPercent:(float)percent {
2469 performSelectorOnMainThread:@selector(_setProgressPercent:)
2470 withObject:[NSNumber numberWithFloat:percent]
2475 - (void) addProgressOutput:(NSString *)output {
2477 performSelectorOnMainThread:@selector(_addProgressOutput:)
2483 - (void) _setConfigurationData:(NSString *)data {
2484 _assert(conffile_r(data));
2486 NSString *ofile = conffile_r[1];
2487 //NSString *nfile = conffile_r[2];
2489 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
2490 initWithTitle:@"Configuration Upgrade"
2491 buttons:[NSArray arrayWithObjects:
2492 @"Keep My Old Copy",
2493 @"Accept The New Copy",
2494 // XXX: @"See What Changed",
2496 defaultButtonIndex:0
2501 [sheet setBodyText:[NSString stringWithFormat:
2502 @"The following file has been changed by both the package maintainer and by you (or for you by a script).\n\n%@"
2505 [sheet popupAlertAnimated:YES];
2508 - (void) _setProgressTitle:(NSString *)title {
2509 [status_ setText:[title stringByAppendingString:@"..."]];
2512 - (void) _setProgressPercent:(NSNumber *)percent {
2513 [progress_ setProgress:[percent floatValue]];
2516 - (void) _addProgressOutput:(NSString *)output {
2517 [output_ setText:[NSString stringWithFormat:@"%@\n%@", [output_ text], output]];
2518 CGSize size = [output_ contentSize];
2519 CGRect rect = {{0, size.height}, {size.width, 0}};
2520 [output_ scrollRectToVisible:rect animated:YES];
2523 - (BOOL) isRunning {
2530 /* Package Cell {{{ */
2531 @interface PackageCell : UITableCell {
2534 UITextLabel *description_;
2535 UITextLabel *source_;
2536 //UIImageView *trusted_;
2538 UIImageView *badge_;
2539 UITextLabel *status_;
2544 - (PackageCell *) init;
2545 - (void) setPackage:(Package *)package;
2547 - (void) _setSelected:(float)fraction;
2548 - (void) setSelected:(BOOL)selected;
2549 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
2550 - (void) _setSelectionFadeFraction:(float)fraction;
2552 + (int) heightForPackage:(Package *)package;
2556 @implementation PackageCell
2561 [description_ release];
2567 //[trusted_ release];
2571 - (PackageCell *) init {
2572 if ((self = [super init]) != nil) {
2573 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 20);
2574 GSFontRef large = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 12);
2575 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 14);
2577 icon_ = [[UIImageView alloc] initWithFrame:CGRectMake(10, 10, 30, 30)];
2579 name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 8, 240, 25)];
2580 [name_ setBackgroundColor:Clear_];
2581 [name_ setFont:bold];
2583 source_ = [[UITextLabel alloc] initWithFrame:CGRectMake(58, 28, 225, 20)];
2584 [source_ setBackgroundColor:Clear_];
2585 [source_ setFont:large];
2587 description_ = [[UITextLabel alloc] initWithFrame:CGRectMake(12, 46, 280, 20)];
2588 [description_ setBackgroundColor:Clear_];
2589 [description_ setFont:small];
2591 /*trusted_ = [[UIImageView alloc] initWithFrame:CGRectMake(30, 30, 16, 16)];
2592 [trusted_ setImage:[UIImage applicationImageNamed:@"trusted.png"]];*/
2595 badge_ = [[UIImageView alloc] initWithFrame:CGRectMake(17, 70, 16, 16)];
2597 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 68, 280, 20)];
2598 [status_ setBackgroundColor:Clear_];
2599 [status_ setFont:small];
2602 /*[icon_ setImage:[UIImage applicationImageNamed:@"unknown.png"]];
2603 [icon_ zoomToScale:0.5];
2604 [icon_ setFrame:CGRectMake(10, 10, 30, 30)];*/
2606 [self addSubview:icon_];
2607 [self addSubview:name_];
2608 [self addSubview:description_];
2609 [self addSubview:source_];
2617 - (void) setPackage:(Package *)package {
2623 Source *source = [package source];
2625 UIImage *image = nil;
2626 if (NSString *icon = [package icon])
2627 image = [UIImage imageAtPath:[icon substringFromIndex:6]];
2628 if (image == nil) if (NSString *icon = [source defaultIcon])
2629 image = [UIImage imageAtPath:[icon substringFromIndex:6]];
2631 image = [UIImage applicationImageNamed:@"unknown.png"];
2632 [icon_ setImage:image];
2634 /*if (image != nil) {
2635 CGSize size = [image size];
2636 float scale = 30 / std::max(size.width, size.height);
2637 [icon_ zoomToScale:scale];
2640 [icon_ setFrame:CGRectMake(10, 10, 30, 30)];
2642 [name_ setText:[package name]];
2643 [description_ setText:[package tagline]];
2645 NSString *label = nil;
2646 bool trusted = false;
2648 if (source != nil) {
2649 label = [source label];
2650 trusted = [source trusted];
2651 } else if ([[package id] isEqualToString:@"firmware"])
2655 label = @"Unknown/Local";
2657 NSString *from = [NSString stringWithFormat:@"from %@", label];
2659 NSString *section = Simplify([package section]);
2660 if (section != nil && ![section isEqualToString:label])
2661 from = [from stringByAppendingString:[NSString stringWithFormat:@" (%@)", section]];
2663 [source_ setText:from];
2666 [badge_ removeFromSuperview];
2667 [status_ removeFromSuperview];
2669 if (NSString *mode = [package mode]) {
2670 [badge_ setImage:[UIImage applicationImageNamed:
2671 [mode isEqualToString:@"Remove"] || [mode isEqualToString:@"Purge"] ? @"removing.png" : @"installing.png"
2674 [status_ setText:[NSString stringWithFormat:@"Queued for %@", mode]];
2675 [status_ setColor:Blueish_];
2676 } else if ([package half]) {
2677 [badge_ setImage:[UIImage applicationImageNamed:@"damaged.png"]];
2678 [status_ setText:@"Package Damaged"];
2679 [status_ setColor:Red_];
2681 [badge_ setImage:nil];
2682 [status_ setText:nil];
2686 [self addSubview:badge_];
2687 [self addSubview:status_];
2692 - (void) _setSelected:(float)fraction {
2693 CGColor black(space_,
2694 Interpolate(0.0, 1.0, fraction),
2695 Interpolate(0.0, 1.0, fraction),
2696 Interpolate(0.0, 1.0, fraction),
2699 CGColor gray(space_,
2700 Interpolate(0.4, 1.0, fraction),
2701 Interpolate(0.4, 1.0, fraction),
2702 Interpolate(0.4, 1.0, fraction),
2705 [name_ setColor:black];
2706 [description_ setColor:gray];
2707 [source_ setColor:black];
2710 - (void) setSelected:(BOOL)selected {
2711 [self _setSelected:(selected ? 1.0 : 0.0)];
2712 [super setSelected:selected];
2715 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
2717 [self _setSelected:(selected ? 1.0 : 0.0)];
2718 [super setSelected:selected withFade:fade];
2721 - (void) _setSelectionFadeFraction:(float)fraction {
2722 [self _setSelected:fraction];
2723 [super _setSelectionFadeFraction:fraction];
2726 + (int) heightForPackage:(Package *)package {
2728 if ([package hasMode] || [package half])
2737 /* Section Cell {{{ */
2738 @interface SectionCell : UITableCell {
2740 UITextLabel *count_;
2744 - (void) setSection:(Section *)section;
2746 - (void) _setSelected:(float)fraction;
2747 - (void) setSelected:(BOOL)selected;
2748 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
2749 - (void) _setSelectionFadeFraction:(float)fraction;
2753 @implementation SectionCell
2762 if ((self = [super init]) != nil) {
2763 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22);
2764 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 12);
2766 name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 9, 250, 25)];
2767 [name_ setBackgroundColor:Clear_];
2768 [name_ setFont:bold];
2770 count_ = [[UITextLabel alloc] initWithFrame:CGRectMake(11, 7, 29, 32)];
2771 [count_ setCentersHorizontally:YES];
2772 [count_ setBackgroundColor:Clear_];
2773 [count_ setFont:small];
2774 [count_ setColor:White_];
2776 UIImageView *folder = [[[UIImageView alloc] initWithFrame:CGRectMake(8, 7, 32, 32)] autorelease];
2777 [folder setImage:[UIImage applicationImageNamed:@"folder.png"]];
2779 [self addSubview:folder];
2780 [self addSubview:name_];
2781 [self addSubview:count_];
2783 [self _setSelected:0];
2790 - (void) setSection:(Section *)section {
2791 if (section == nil) {
2792 [name_ setText:@"All Packages"];
2793 [count_ setText:nil];
2795 NSString *name = [section name];
2796 [name_ setText:(name == nil ? @"(No Section)" : name)];
2797 [count_ setText:[NSString stringWithFormat:@"%d", [section count]]];
2801 - (void) _setSelected:(float)fraction {
2802 CGColor black(space_,
2803 Interpolate(0.0, 1.0, fraction),
2804 Interpolate(0.0, 1.0, fraction),
2805 Interpolate(0.0, 1.0, fraction),
2808 [name_ setColor:black];
2811 - (void) setSelected:(BOOL)selected {
2812 [self _setSelected:(selected ? 1.0 : 0.0)];
2813 [super setSelected:selected];
2816 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
2818 [self _setSelected:(selected ? 1.0 : 0.0)];
2819 [super setSelected:selected withFade:fade];
2822 - (void) _setSelectionFadeFraction:(float)fraction {
2823 [self _setSelected:fraction];
2824 [super _setSelectionFadeFraction:fraction];
2830 /* File Table {{{ */
2831 @interface FileTable : RVPage {
2832 _transient Database *database_;
2835 NSMutableArray *files_;
2839 - (id) initWithBook:(RVBook *)book database:(Database *)database;
2840 - (void) setPackage:(Package *)package;
2844 @implementation FileTable
2847 if (package_ != nil)
2856 - (int) numberOfRowsInTable:(UITable *)table {
2857 return files_ == nil ? 0 : [files_ count];
2860 - (float) table:(UITable *)table heightForRow:(int)row {
2864 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2865 if (reusing == nil) {
2866 reusing = [[[UIImageAndTextTableCell alloc] init] autorelease];
2867 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
2868 [[(UIImageAndTextTableCell *)reusing titleTextLabel] setFont:font];
2871 [(UIImageAndTextTableCell *)reusing setTitle:[files_ objectAtIndex:row]];
2875 - (BOOL) table:(UITable *)table canSelectRow:(int)row {
2879 - (id) initWithBook:(RVBook *)book database:(Database *)database {
2880 if ((self = [super initWithBook:book]) != nil) {
2881 database_ = database;
2883 files_ = [[NSMutableArray arrayWithCapacity:32] retain];
2885 list_ = [[UITable alloc] initWithFrame:[self bounds]];
2886 [self addSubview:list_];
2888 UITableColumn *column = [[[UITableColumn alloc]
2889 initWithTitle:@"Name"
2891 width:[self frame].size.width
2894 [list_ setDataSource:self];
2895 [list_ setSeparatorStyle:1];
2896 [list_ addTableColumn:column];
2897 [list_ setDelegate:self];
2898 [list_ setReusesTableCells:YES];
2902 - (void) setPackage:(Package *)package {
2903 if (package_ != nil) {
2904 [package_ autorelease];
2913 [files_ removeAllObjects];
2915 if (package != nil) {
2916 package_ = [package retain];
2917 name_ = [[package id] retain];
2919 NSString *path = [NSString stringWithFormat:@"/var/lib/dpkg/info/%@.list", name_];
2922 std::ifstream fin([path UTF8String]);
2924 while (std::getline(fin, line))
2925 [files_ addObject:[NSString stringWithUTF8String:line.c_str()]];
2928 if ([files_ count] != 0) {
2929 if ([[files_ objectAtIndex:0] isEqualToString:@"/."])
2930 [files_ removeObjectAtIndex:0];
2931 [files_ sortUsingSelector:@selector(compareByPath:)];
2933 NSMutableArray *stack = [NSMutableArray arrayWithCapacity:8];
2934 [stack addObject:@"/"];
2936 for (int i(0), e([files_ count]); i != e; ++i) {
2937 NSString *file = [files_ objectAtIndex:i];
2938 while (![file hasPrefix:[stack lastObject]])
2939 [stack removeLastObject];
2940 NSString *directory = [stack lastObject];
2941 [stack addObject:[file stringByAppendingString:@"/"]];
2942 [files_ replaceObjectAtIndex:i withObject:[NSString stringWithFormat:@"%*s%@",
2943 ([stack count] - 2) * 3, "",
2944 [file substringFromIndex:[directory length]]
2953 - (void) resetViewAnimated:(BOOL)animated {
2954 [list_ resetViewAnimated:animated];
2957 - (void) reloadData {
2958 [self setPackage:[database_ packageWithName:name_]];
2959 [self reloadButtons];
2962 - (NSString *) title {
2963 return @"Installed Files";
2966 - (NSString *) backButtonTitle {
2972 /* Package View {{{ */
2973 @protocol PackageViewDelegate
2974 - (void) performPackage:(Package *)package;
2977 @interface PackageView : RVPage {
2978 _transient Database *database_;
2979 UIPreferencesTable *table_;
2982 UITextView *description_;
2983 NSMutableArray *buttons_;
2986 - (id) initWithBook:(RVBook *)book database:(Database *)database;
2987 - (void) setPackage:(Package *)package;
2991 @implementation PackageView
2994 [table_ setDataSource:nil];
2995 [table_ setDelegate:nil];
2997 if (package_ != nil)
3001 if (description_ != nil)
3002 [description_ release];
3008 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
3010 if ([package_ installed] != nil)
3012 if ([package_ source] != nil)
3017 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
3020 else if ([package_ installed] != nil && group-- == 0)
3021 return @"Installed Package";
3022 else if (group-- == 0)
3023 return @"Package Details";
3024 else if ([package_ source] != nil && group-- == 0)
3025 return @"Source Information";
3026 else _assert(false);
3029 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
3030 if (description_ == nil || group != 0 || row != 1)
3033 return [description_ visibleTextRect].size.height + TextViewOffset_;
3036 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
3039 if ([package_ author] != nil)
3041 if (description_ != nil)
3043 if ([package_ website] != nil)
3046 } else if ([package_ installed] != nil && group-- == 0)
3048 else if (group-- == 0) {
3050 if ([package_ size] != 0)
3052 if ([package_ maintainer] != nil)
3054 if ([package_ sponsor] != nil)
3056 if ([package_ relationships] != nil)
3058 if ([[package_ source] trusted])
3061 } else if ([package_ source] != nil && group-- == 0) {
3062 Source *source = [package_ source];
3063 NSString *description = [source description];
3065 if (description != nil && ![description isEqualToString:[source label]])
3067 if ([source origin] != nil)
3070 } else _assert(false);
3073 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
3074 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
3075 [cell setShowSelection:NO];
3079 } else if (row-- == 0) {
3080 [cell setTitle:[package_ name]];
3081 [cell setValue:[package_ latest]];
3082 } else if ([package_ author] != nil && row-- == 0) {
3083 [cell setTitle:@"Author"];
3084 [cell setValue:[[package_ author] name]];
3085 [cell setShowDisclosure:YES];
3086 [cell setShowSelection:YES];
3087 } else if (description_ != nil && row-- == 0) {
3088 [cell addSubview:description_];
3089 } else if ([package_ website] != nil && row-- == 0) {
3090 [cell setTitle:@"More Information"];
3091 [cell setShowDisclosure:YES];
3092 [cell setShowSelection:YES];
3093 } else _assert(false);
3094 } else if ([package_ installed] != nil && group-- == 0) {
3096 } else if (row-- == 0) {
3097 [cell setTitle:@"Version"];
3098 NSString *installed([package_ installed]);
3099 [cell setValue:(installed == nil ? @"n/a" : installed)];
3100 } else if (row-- == 0) {
3101 [cell setTitle:@"Filesystem Content"];
3102 [cell setShowDisclosure:YES];
3103 [cell setShowSelection:YES];
3104 } else _assert(false);
3105 } else if (group-- == 0) {
3107 } else if (row-- == 0) {
3108 [cell setTitle:@"Identifier"];
3109 [cell setValue:[package_ id]];
3110 } else if (row-- == 0) {
3111 [cell setTitle:@"Section"];
3112 NSString *section([package_ section]);
3113 [cell setValue:(section == nil ? @"n/a" : section)];
3114 } else if ([package_ size] != 0 && row-- == 0) {
3115 [cell setTitle:@"Expanded Size"];
3116 [cell setValue:SizeString([package_ size])];
3117 } else if ([package_ maintainer] != nil && row-- == 0) {
3118 [cell setTitle:@"Maintainer"];
3119 [cell setValue:[[package_ maintainer] name]];
3120 [cell setShowDisclosure:YES];
3121 [cell setShowSelection:YES];
3122 } else if ([package_ sponsor] != nil && row-- == 0) {
3123 [cell setTitle:@"Sponsor"];
3124 [cell setValue:[[package_ sponsor] name]];
3125 [cell setShowDisclosure:YES];
3126 [cell setShowSelection:YES];
3127 } else if ([package_ relationships] != nil && row-- == 0) {
3128 [cell setTitle:@"Package Relationships"];
3129 [cell setShowDisclosure:YES];
3130 [cell setShowSelection:YES];
3131 } else if ([[package_ source] trusted] && row-- == 0) {
3132 [cell setIcon:[UIImage applicationImageNamed:@"trusted.png"]];
3133 [cell setValue:@"This package has been signed."];
3134 } else _assert(false);
3135 } else if ([package_ source] != nil && group-- == 0) {
3136 Source *source = [package_ source];
3137 NSString *description = [source description];
3140 } else if (row-- == 0) {
3141 NSString *label = [source label];
3143 label = [source uri];
3144 [cell setTitle:label];
3145 [cell setValue:[source version]];
3146 } else if (description != nil && ![description isEqualToString:[source label]] && row-- == 0) {
3147 [cell setValue:description];
3148 } else if ([source origin] != nil && row-- == 0) {
3149 [cell setTitle:@"Origin"];
3150 [cell setValue:[source origin]];
3151 } else _assert(false);
3152 } else _assert(false);
3157 - (BOOL) canSelectRow:(int)row {
3161 - (void) tableRowSelected:(NSNotification *)notification {
3162 int row = [table_ selectedRow];
3166 #define _else else goto _label; return; } _label:
3170 } else if (row-- == 0) {
3171 } else if ([package_ author] != nil && row-- == 0) {
3172 [delegate_ openURL:[NSURL URLWithString:[NSString stringWithFormat:@"mailto:%@?subject=%@",
3173 [[package_ author] email],
3174 [[NSString stringWithFormat:@"regarding apt package \"%@\"",
3176 ] stringByAddingPercentEscapes]
3178 } else if (description_ != nil && row-- == 0) {
3179 } else if ([package_ website] != nil && row-- == 0) {
3180 NSURL *url = [NSURL URLWithString:[package_ website]];
3181 BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease];
3182 [browser setDelegate:delegate_];
3183 [book_ pushPage:browser];
3184 [browser loadURL:url];
3185 } _else if ([package_ installed] != nil) {
3187 } else if (row-- == 0) {
3188 } else if (row-- == 0) {
3189 FileTable *files = [[[FileTable alloc] initWithBook:book_ database:database_] autorelease];
3190 [files setDelegate:delegate_];
3191 [files setPackage:package_];
3192 [book_ pushPage:files];
3195 } else if (row-- == 0) {
3196 } else if (row-- == 0) {
3197 } else if ([package_ size] != 0 && row-- == 0) {
3198 } else if ([package_ maintainer] != nil && row-- == 0) {
3199 [delegate_ openURL:[NSURL URLWithString:[NSString stringWithFormat:@"mailto:%@?subject=%@",
3200 [[package_ maintainer] email],
3201 [[NSString stringWithFormat:@"regarding apt package \"%@\"",
3203 ] stringByAddingPercentEscapes]
3205 } else if ([package_ sponsor] != nil && row-- == 0) {
3206 NSURL *url = [NSURL URLWithString:[[package_ sponsor] email]];
3207 BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease];
3208 [browser setDelegate:delegate_];
3209 [book_ pushPage:browser];
3210 [browser loadURL:url];
3211 } else if ([package_ relationships] != nil && row-- == 0) {
3212 } else if ([[package_ source] trusted] && row-- == 0) {
3213 } _else if ([package_ source] != nil) {
3214 Source *source = [package_ source];
3215 NSString *description = [source description];
3218 } else if (row-- == 0) {
3219 } else if (description != nil && ![description isEqualToString:[source label]] && row-- == 0) {
3220 } else if ([source origin] != nil && row-- == 0) {
3221 } _else _assert(false);
3226 - (void) _clickButtonWithName:(NSString *)name {
3227 if ([name isEqualToString:@"Install"])
3228 [delegate_ installPackage:package_];
3229 else if ([name isEqualToString:@"Reinstall"])
3230 [delegate_ installPackage:package_];
3231 else if ([name isEqualToString:@"Remove"])
3232 [delegate_ removePackage:package_];
3233 else if ([name isEqualToString:@"Upgrade"])
3234 [delegate_ installPackage:package_];
3235 else _assert(false);
3238 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
3239 int count = [buttons_ count];
3240 _assert(count != 0);
3241 _assert(button <= count + 1);
3243 if (count != button - 1)
3244 [self _clickButtonWithName:[buttons_ objectAtIndex:(button - 1)]];
3249 - (void) _rightButtonClicked {
3250 int count = [buttons_ count];
3251 _assert(count != 0);
3254 [self _clickButtonWithName:[buttons_ objectAtIndex:0]];
3256 NSMutableArray *buttons = [NSMutableArray arrayWithCapacity:(count + 1)];
3257 [buttons addObjectsFromArray:buttons_];
3258 [buttons addObject:@"Cancel"];
3260 [delegate_ slideUp:[[[UIAlertSheet alloc]
3263 defaultButtonIndex:2
3270 - (NSString *) rightButtonTitle {
3271 int count = [buttons_ count];
3272 return count == 0 ? nil : count != 1 ? @"Modify" : [buttons_ objectAtIndex:0];
3275 - (NSString *) title {
3279 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3280 if ((self = [super initWithBook:book]) != nil) {
3281 database_ = database;
3283 table_ = [[UIPreferencesTable alloc] initWithFrame:[self bounds]];
3284 [self addSubview:table_];
3286 [table_ setDataSource:self];
3287 [table_ setDelegate:self];
3289 buttons_ = [[NSMutableArray alloc] initWithCapacity:4];
3293 - (void) setPackage:(Package *)package {
3294 if (package_ != nil) {
3295 [package_ autorelease];
3304 if (description_ != nil) {
3305 [description_ release];
3309 [buttons_ removeAllObjects];
3311 if (package != nil) {
3312 package_ = [package retain];
3313 name_ = [[package id] retain];
3315 NSString *description([package description]);
3316 if (description == nil)
3317 description = [package tagline];
3318 if (description != nil) {
3319 description_ = [GetTextView(description, 12, true) retain];
3320 [description_ setTextColor:Black_];
3323 [table_ reloadData];
3325 if ([package_ source] == nil);
3326 else if ([package_ upgradableAndEssential:NO])
3327 [buttons_ addObject:@"Upgrade"];
3328 else if ([package_ installed] == nil)
3329 [buttons_ addObject:@"Install"];
3331 [buttons_ addObject:@"Reinstall"];
3332 if ([package_ installed] != nil)
3333 [buttons_ addObject:@"Remove"];
3337 - (void) resetViewAnimated:(BOOL)animated {
3338 [table_ resetViewAnimated:animated];
3341 - (void) reloadData {
3342 [self setPackage:[database_ packageWithName:name_]];
3343 [self reloadButtons];
3348 /* Package Table {{{ */
3349 @interface PackageTable : RVPage {
3350 _transient Database *database_;
3354 NSMutableArray *packages_;
3355 NSMutableArray *sections_;
3356 UISectionList *list_;
3359 - (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object;
3361 - (void) setDelegate:(id)delegate;
3362 - (void) setObject:(id)object;
3364 - (void) reloadData;
3365 - (void) resetCursor;
3367 - (UISectionList *) list;
3369 - (void) setShouldHideHeaderInShortLists:(BOOL)hide;
3373 @implementation PackageTable
3376 [list_ setDataSource:nil];
3381 [packages_ release];
3382 [sections_ release];
3387 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
3388 return [sections_ count];
3391 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
3392 return [[sections_ objectAtIndex:section] name];
3395 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
3396 return [[sections_ objectAtIndex:section] row];
3399 - (int) numberOfRowsInTable:(UITable *)table {
3400 return [packages_ count];
3403 - (float) table:(UITable *)table heightForRow:(int)row {
3404 return [PackageCell heightForPackage:[packages_ objectAtIndex:row]];
3407 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
3409 reusing = [[[PackageCell alloc] init] autorelease];
3410 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
3414 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
3418 - (void) tableRowSelected:(NSNotification *)notification {
3419 int row = [[notification object] selectedRow];
3423 Package *package = [packages_ objectAtIndex:row];
3424 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
3425 [view setDelegate:delegate_];
3426 [view setPackage:package];
3427 [book_ pushPage:view];
3430 - (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object {
3431 if ((self = [super initWithBook:book]) != nil) {
3432 database_ = database;
3433 title_ = [title retain];
3435 object_ = object == nil ? nil : [object retain];
3437 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
3438 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
3440 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:YES];
3441 [list_ setDataSource:self];
3443 UITableColumn *column = [[[UITableColumn alloc]
3444 initWithTitle:@"Name"
3446 width:[self frame].size.width
3449 UITable *table = [list_ table];
3450 [table setSeparatorStyle:1];
3451 [table addTableColumn:column];
3452 [table setDelegate:self];
3453 [table setReusesTableCells:YES];
3455 [self addSubview:list_];
3460 - (void) setDelegate:(id)delegate {
3461 delegate_ = delegate;
3464 - (void) setObject:(id)object {
3470 object_ = [object retain];
3473 - (void) reloadData {
3474 NSArray *packages = [database_ packages];
3476 [packages_ removeAllObjects];
3477 [sections_ removeAllObjects];
3479 for (size_t i(0); i != [packages count]; ++i) {
3480 Package *package([packages objectAtIndex:i]);
3481 if ([[package performSelector:filter_ withObject:object_] boolValue])
3482 [packages_ addObject:package];
3485 Section *section = nil;
3487 for (size_t offset(0); offset != [packages_ count]; ++offset) {
3488 Package *package = [packages_ objectAtIndex:offset];
3489 NSString *name = [package index];
3491 if (section == nil || ![[section name] isEqualToString:name]) {
3492 section = [[[Section alloc] initWithName:name row:offset] autorelease];
3493 [sections_ addObject:section];
3496 [section addToCount];
3502 - (NSString *) title {
3506 - (void) resetViewAnimated:(BOOL)animated {
3507 [list_ resetViewAnimated:animated];
3510 - (void) resetCursor {
3511 [[list_ table] scrollPointVisibleAtTopLeft:CGPointMake(0, 0) animated:NO];
3514 - (UISectionList *) list {
3518 - (void) setShouldHideHeaderInShortLists:(BOOL)hide {
3519 [list_ setShouldHideHeaderInShortLists:hide];
3525 /* Browser Implementation {{{ */
3526 @implementation BrowserView
3529 WebView *webview = [webview_ webView];
3530 [webview setFrameLoadDelegate:nil];
3531 [webview setResourceLoadDelegate:nil];
3532 [webview setUIDelegate:nil];
3534 [scroller_ setDelegate:nil];
3535 [webview_ setDelegate:nil];
3537 [scroller_ release];
3540 [indicator_ release];
3546 - (void) loadURL:(NSURL *)url cachePolicy:(NSURLRequestCachePolicy)policy {
3547 NSMutableURLRequest *request = [NSMutableURLRequest
3550 timeoutInterval:30.0
3553 [request addValue:[NSString stringWithUTF8String:Firmware_] forHTTPHeaderField:@"X-Firmware"];
3554 [request addValue:[NSString stringWithUTF8String:Machine_] forHTTPHeaderField:@"X-Machine"];
3555 [request addValue:[NSString stringWithUTF8String:SerialNumber_] forHTTPHeaderField:@"X-Serial-Number"];
3557 [self loadRequest:request];
3561 - (void) loadURL:(NSURL *)url {
3562 [self loadURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy];
3565 // XXX: this needs to add the headers
3566 - (NSURLRequest *) _addHeadersToRequest:(NSURLRequest *)request {
3570 - (void) loadRequest:(NSURLRequest *)request {
3572 [webview_ loadRequest:request];
3575 - (void) reloadURL {
3576 NSURL *url = [[[urls_ lastObject] retain] autorelease];
3577 [urls_ removeLastObject];
3578 [self loadURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData];
3581 - (WebView *) webView {
3582 return [webview_ webView];
3585 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame {
3586 [scroller_ setContentSize:frame.size];
3589 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old {
3590 [self view:sender didSetFrame:frame];
3593 - (void) getAppTapp:(NSString *)href {
3594 if ([href hasPrefix:@"apptapp://package/"]) {
3595 NSString *name = [href substringFromIndex:18];
3596 Package *package = [database_ packageWithName:name];
3597 if (package == nil) {
3598 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
3599 initWithTitle:@"Cannot Locate Package"
3600 buttons:[NSArray arrayWithObjects:@"Close", nil]
3601 defaultButtonIndex:0
3606 [sheet setBodyText:[NSString stringWithFormat:
3607 @"The package %@ cannot be found in your current sources. I might recommend installing more sources."
3610 [sheet popupAlertAnimated:YES];
3612 [self setBackButtonTitle:title_];
3613 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
3614 [view setDelegate:delegate_];
3615 [view setPackage:package];
3616 [book_ pushPage:view];
3621 - (void) webView:(WebView *)sender willClickElement:(id)element {
3622 if (![element respondsToSelector:@selector(href)])
3624 NSString *href = [element href];
3627 if ([href hasPrefix:@"apptapp://package/"])
3628 [self getAppTapp:href];
3631 - (NSURLRequest *) webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource {
3632 if ([[[request URL] scheme] isEqualToString:@"apptapp"]) {
3633 [self getAppTapp:[[request URL] absoluteString]];
3639 [book_ pushPage:self];
3642 return [self _addHeadersToRequest:request];
3645 - (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request {
3646 if (request != nil && [[[request URL] scheme] isEqualToString:@"apptapp"])
3649 [self setBackButtonTitle:title_];
3651 BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease];
3652 [browser setDelegate:delegate_];
3654 if (request != nil) {
3655 [browser loadRequest:[self _addHeadersToRequest:request]];
3656 [book_ pushPage:browser];
3659 return [browser webView];
3663 - (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame {
3664 title_ = [title retain];
3665 [self setTitle:title];
3668 - (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame {
3669 if ([frame parentFrame] != nil)
3674 [indicator_ startAnimation];
3675 [self reloadButtons];
3677 if (title_ != nil) {
3682 [self setTitle:@"Loading..."];
3684 WebView *webview = [webview_ webView];
3685 NSString *href = [webview mainFrameURL];
3686 [urls_ addObject:[NSURL URLWithString:href]];
3688 CGRect webrect = [scroller_ frame];
3689 webrect.size.height = 0;
3690 [webview_ setFrame:webrect];
3693 - (void) _finishLoading {
3696 [indicator_ stopAnimation];
3697 [self reloadButtons];
3701 - (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
3702 if ([frame parentFrame] != nil)
3704 [self _finishLoading];
3707 - (void) webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
3708 if ([frame parentFrame] != nil)
3710 [self setTitle:[error localizedDescription]];
3711 [self _finishLoading];
3714 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3715 if ((self = [super initWithBook:book]) != nil) {
3716 database_ = database;
3719 struct CGRect bounds = [self bounds];
3721 UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:bounds] autorelease];
3722 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
3723 [self addSubview:pinstripe];
3725 scroller_ = [[UIScroller alloc] initWithFrame:bounds];
3726 [self addSubview:scroller_];
3728 [scroller_ setScrollingEnabled:YES];
3729 [scroller_ setAdjustForContentSizeChange:YES];
3730 [scroller_ setClipsSubviews:YES];
3731 [scroller_ setAllowsRubberBanding:YES];
3732 [scroller_ setScrollDecelerationFactor:0.99];
3733 [scroller_ setDelegate:self];
3735 CGRect webrect = [scroller_ bounds];
3736 webrect.size.height = 0;
3738 webview_ = [[UIWebView alloc] initWithFrame:webrect];
3739 [scroller_ addSubview:webview_];
3741 [webview_ setTilingEnabled:YES];
3742 [webview_ setTileSize:CGSizeMake(webrect.size.width, 500)];
3743 [webview_ setAutoresizes:YES];
3744 [webview_ setDelegate:self];
3745 //[webview_ setEnabledGestures:2];
3747 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:kUIProgressIndicatorStyleMediumWhite];
3748 indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(281, 42, indsize.width, indsize.height)];
3749 [indicator_ setStyle:kUIProgressIndicatorStyleMediumWhite];
3751 Package *package([database_ packageWithName:@"cydia"]);
3752 NSString *application = package == nil ? @"Cydia" : [NSString
3753 stringWithFormat:@"Cydia/%@",
3757 WebView *webview = [webview_ webView];
3758 [webview setApplicationNameForUserAgent:application];
3759 [webview setFrameLoadDelegate:self];
3760 [webview setResourceLoadDelegate:self];
3761 [webview setUIDelegate:self];
3763 urls_ = [[NSMutableArray alloc] initWithCapacity:16];
3767 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
3771 - (void) _leftButtonClicked {
3772 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
3773 initWithTitle:@"About Cydia Installer"
3774 buttons:[NSArray arrayWithObjects:@"Close", nil]
3775 defaultButtonIndex:0
3781 @"Copyright (C) 2008\n"
3782 "Jay Freeman (saurik)\n"
3783 "saurik@saurik.com\n"
3784 "http://www.saurik.com/\n"
3787 "http://www.theokorigroup.com/\n"
3789 "College of Creative Studies,\n"
3790 "University of California,\n"
3792 "http://www.ccs.ucsb.edu/"
3795 [sheet popupAlertAnimated:YES];
3798 - (void) _rightButtonClicked {
3803 - (NSString *) leftButtonTitle {
3807 - (NSString *) rightButtonTitle {
3808 return loading_ ? @"" : @"Reload";
3811 - (NSString *) title {
3815 - (NSString *) backButtonTitle {
3819 - (void) setPageActive:(BOOL)active {
3821 [book_ addSubview:indicator_];
3823 [indicator_ removeFromSuperview];
3826 - (void) resetViewAnimated:(BOOL)animated {
3829 - (void) setPushed:(bool)pushed {
3836 @interface CYBook : RVBook <
3839 _transient Database *database_;
3841 UIProgressIndicator *indicator_;
3842 UITextLabel *prompt_;
3843 UIProgressBar *progress_;
3847 - (id) initWithFrame:(CGRect)frame database:(Database *)database;
3853 /* Source Cell {{{ */
3854 @interface SourceCell : UITableCell {
3855 UITextLabel *description_;
3856 UIRightTextLabel *label_;
3857 UITextLabel *origin_;
3862 - (SourceCell *) initWithSource:(Source *)source;
3864 - (void) _setSelected:(float)fraction;
3865 - (void) setSelected:(BOOL)selected;
3866 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
3867 - (void) _setSelectionFadeFraction:(float)fraction;
3871 @implementation SourceCell
3874 [description_ release];
3880 - (SourceCell *) initWithSource:(Source *)source {
3881 if ((self = [super init]) != nil) {
3882 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 20);
3883 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 14);
3885 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
3886 float clear[] = {0, 0, 0, 0};
3888 NSString *description = [source description];
3889 if (description == nil)
3890 description = [source uri];
3892 description_ = [[UITextLabel alloc] initWithFrame:CGRectMake(12, 7, 270, 25)];
3893 [description_ setBackgroundColor:CGColorCreate(space, clear)];
3894 [description_ setFont:bold];
3895 [description_ setText:description];
3897 NSString *label = [source label];
3899 label = [source type];
3901 label_ = [[UIRightTextLabel alloc] initWithFrame:CGRectMake(290, 32, 90, 25)];
3902 [label_ setBackgroundColor:CGColorCreate(space, clear)];
3903 [label_ setFont:small];
3904 [label_ setText:label];
3906 NSString *origin = [source origin];
3908 origin = [source distribution];
3910 origin_ = [[UITextLabel alloc] initWithFrame:CGRectMake(13, 35, 315, 20)];
3911 [origin_ setBackgroundColor:CGColorCreate(space, clear)];
3912 [origin_ setFont:small];
3913 [origin_ setText:origin];
3915 [self addSubview:description_];
3916 [self addSubview:label_];
3917 [self addSubview:origin_];
3924 - (void) _setSelected:(float)fraction {
3925 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
3928 Interpolate(0.0, 1.0, fraction),
3929 Interpolate(0.0, 1.0, fraction),
3930 Interpolate(0.0, 1.0, fraction),
3934 Interpolate(0.2, 1.0, fraction),
3935 Interpolate(0.2, 1.0, fraction),
3936 Interpolate(1.0, 1.0, fraction),
3940 Interpolate(0.4, 1.0, fraction),
3941 Interpolate(0.4, 1.0, fraction),
3942 Interpolate(0.4, 1.0, fraction),
3945 [description_ setColor:CGColorCreate(space, black)];
3946 [label_ setColor:CGColorCreate(space, blue)];
3947 [origin_ setColor:CGColorCreate(space, gray)];
3950 - (void) setSelected:(BOOL)selected {
3951 [self _setSelected:(selected ? 1.0 : 0.0)];
3952 [super setSelected:selected];
3955 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
3957 [self _setSelected:(selected ? 1.0 : 0.0)];
3958 [super setSelected:selected withFade:fade];
3961 - (void) _setSelectionFadeFraction:(float)fraction {
3962 [self _setSelected:fraction];
3963 [super _setSelectionFadeFraction:fraction];
3968 /* Source Table {{{ */
3969 @interface SourceTable : RVPage {
3970 _transient Database *database_;
3971 UISectionList *list_;
3972 NSMutableArray *sources_;
3973 UIAlertSheet *alert_;
3976 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3980 @implementation SourceTable
3983 [list_ setDataSource:nil];
3985 if (sources_ != nil)
3991 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
3995 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
3999 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
4003 - (int) numberOfRowsInTable:(UITable *)table {
4004 return [sources_ count];
4007 - (float) table:(UITable *)table heightForRow:(int)row {
4011 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col {
4012 return [[[SourceCell alloc] initWithSource:[sources_ objectAtIndex:row]] autorelease];
4015 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
4019 - (void) tableRowSelected:(NSNotification*)notification {
4020 UITable *table([list_ table]);
4021 int row([table selectedRow]);
4025 [table selectRow:-1 byExtendingSelection:NO withFade:YES];
4028 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4029 if ((self = [super initWithBook:book]) != nil) {
4030 database_ = database;
4033 list_ = [[UISectionList alloc] initWithFrame:[self bounds]];
4035 [self addSubview:list_];
4037 [list_ setDataSource:self];
4038 [list_ setShouldHideHeaderInShortLists:NO];
4040 UITableColumn *column = [[UITableColumn alloc]
4041 initWithTitle:@"Name"
4043 width:[self frame].size.width
4046 UITable *table = [list_ table];
4047 [table setSeparatorStyle:1];
4048 [table addTableColumn:column];
4049 [table setDelegate:self];
4053 - (void) reloadData {
4055 _assert(list.ReadMainList());
4057 if (sources_ != nil)
4060 sources_ = [[NSMutableArray arrayWithCapacity:16] retain];
4061 for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source)
4062 [sources_ addObject:[[[Source alloc] initWithMetaIndex:*source] autorelease]];
4067 - (void) resetViewAnimated:(BOOL)animated {
4068 [list_ resetViewAnimated:animated];
4071 - (NSString *) leftTitle {
4072 return @"Refresh All";
4075 - (NSString *) rightTitle {
4082 /* Install View {{{ */
4083 @interface InstallView : RVPage {
4084 _transient Database *database_;
4085 NSMutableArray *packages_;
4086 NSMutableArray *sections_;
4091 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4092 - (void) reloadData;
4096 @implementation InstallView
4099 [list_ setDataSource:nil];
4100 [list_ setDelegate:nil];
4102 [packages_ release];
4103 [sections_ release];
4105 [accessory_ release];
4109 - (int) numberOfRowsInTable:(UITable *)table {
4110 return [sections_ count] + 1;
4113 - (float) table:(UITable *)table heightForRow:(int)row {
4117 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
4119 reusing = [[[SectionCell alloc] init] autorelease];
4120 [(SectionCell *)reusing setSection:(row == 0 ? nil : [sections_ objectAtIndex:(row - 1)])];
4124 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
4128 - (void) tableRowSelected:(NSNotification *)notification {
4129 int row = [[notification object] selectedRow];
4140 title = @"All Packages";
4142 section = [sections_ objectAtIndex:(row - 1)];
4143 name = [section name];
4149 title = @"(No Section)";
4153 PackageTable *table = [[[PackageTable alloc]
4157 filter:@selector(isUninstalledInSection:)
4161 [table setDelegate:delegate_];
4163 [book_ pushPage:table];
4166 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4167 if ((self = [super initWithBook:book]) != nil) {
4168 database_ = database;
4170 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
4171 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
4173 list_ = [[UITable alloc] initWithFrame:[self bounds]];
4174 [self addSubview:list_];
4176 UITableColumn *column = [[[UITableColumn alloc]
4177 initWithTitle:@"Name"
4179 width:[self frame].size.width
4182 [list_ setDataSource:self];
4183 [list_ setSeparatorStyle:1];
4184 [list_ addTableColumn:column];
4185 [list_ setDelegate:self];
4186 [list_ setReusesTableCells:YES];
4192 - (void) reloadData {
4193 NSArray *packages = [database_ packages];
4195 [packages_ removeAllObjects];
4196 [sections_ removeAllObjects];
4198 for (size_t i(0); i != [packages count]; ++i) {
4199 Package *package([packages objectAtIndex:i]);
4200 if ([package valid] && [package installed] == nil)
4201 [packages_ addObject:package];
4204 [packages_ sortUsingSelector:@selector(compareBySection:)];
4206 Section *section = nil;
4207 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
4208 Package *package = [packages_ objectAtIndex:offset];
4209 NSString *name = [package section];
4211 if (section == nil || name != nil && ![[section name] isEqualToString:name]) {
4212 section = [[[Section alloc] initWithName:name row:offset] autorelease];
4213 [sections_ addObject:section];
4216 [section addToCount];
4222 - (void) resetViewAnimated:(BOOL)animated {
4223 [list_ resetViewAnimated:animated];
4226 - (NSString *) title {
4230 - (NSString *) backButtonTitle {
4234 - (UIView *) accessoryView {
4240 /* Changes View {{{ */
4241 @interface ChangesView : RVPage {
4242 _transient Database *database_;
4243 NSMutableArray *packages_;
4244 NSMutableArray *sections_;
4245 UISectionList *list_;
4249 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4250 - (void) reloadData;
4254 @implementation ChangesView
4257 [[list_ table] setDelegate:nil];
4258 [list_ setDataSource:nil];
4260 [packages_ release];
4261 [sections_ release];
4266 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
4267 return [sections_ count];
4270 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
4271 return [[sections_ objectAtIndex:section] name];
4274 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
4275 return [[sections_ objectAtIndex:section] row];
4278 - (int) numberOfRowsInTable:(UITable *)table {
4279 return [packages_ count];
4282 - (float) table:(UITable *)table heightForRow:(int)row {
4283 return [PackageCell heightForPackage:[packages_ objectAtIndex:row]];
4286 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
4288 reusing = [[[PackageCell alloc] init] autorelease];
4289 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
4293 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
4297 - (void) tableRowSelected:(NSNotification *)notification {
4298 int row = [[notification object] selectedRow];
4301 Package *package = [packages_ objectAtIndex:row];
4302 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
4303 [view setDelegate:delegate_];
4304 [view setPackage:package];
4305 [book_ pushPage:view];
4308 - (void) _leftButtonClicked {
4309 [(CYBook *)book_ update];
4310 [self reloadButtons];
4313 - (void) _rightButtonClicked {
4314 [delegate_ distUpgrade];
4317 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4318 if ((self = [super initWithBook:book]) != nil) {
4319 database_ = database;
4321 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
4322 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
4324 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:NO];
4325 [self addSubview:list_];
4327 [list_ setShouldHideHeaderInShortLists:NO];
4328 [list_ setDataSource:self];
4329 //[list_ setSectionListStyle:1];
4331 UITableColumn *column = [[[UITableColumn alloc]
4332 initWithTitle:@"Name"
4334 width:[self frame].size.width
4337 UITable *table = [list_ table];
4338 [table setSeparatorStyle:1];
4339 [table addTableColumn:column];
4340 [table setDelegate:self];
4341 [table setReusesTableCells:YES];
4347 - (void) reloadData {
4348 NSArray *packages = [database_ packages];
4350 [packages_ removeAllObjects];
4351 [sections_ removeAllObjects];
4353 for (size_t i(0); i != [packages count]; ++i) {
4354 Package *package([packages objectAtIndex:i]);
4355 if ([package installed] == nil && [package valid] || [package upgradableAndEssential:NO])
4356 [packages_ addObject:package];
4359 [packages_ sortUsingSelector:@selector(compareForChanges:)];
4361 Section *upgradable = [[[Section alloc] initWithName:@"Available Upgrades" row:0] autorelease];
4362 Section *section = nil;
4365 bool unseens = false;
4367 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, Locale_, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
4369 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
4370 Package *package = [packages_ objectAtIndex:offset];
4372 if ([package upgradableAndEssential:YES]) {
4374 [upgradable addToCount];
4377 NSDate *seen = [package seen];
4382 name = [@"n/a ?" retain];
4384 name = (NSString *) CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen);
4387 if (section == nil || ![[section name] isEqualToString:name]) {
4388 section = [[[Section alloc] initWithName:name row:offset] autorelease];
4389 [sections_ addObject:section];
4393 [section addToCount];
4397 CFRelease(formatter);
4400 Section *last = [sections_ lastObject];
4401 size_t count = [last count];
4402 [packages_ removeObjectsInRange:NSMakeRange([packages_ count] - count, count)];
4403 [sections_ removeLastObject];
4407 [sections_ insertObject:upgradable atIndex:0];
4410 [self reloadButtons];
4413 - (void) resetViewAnimated:(BOOL)animated {
4414 [list_ resetViewAnimated:animated];
4417 - (NSString *) leftButtonTitle {
4418 return [(CYBook *)book_ updating] ? nil : @"Refresh";
4421 - (NSString *) rightButtonTitle {
4422 return upgrades_ == 0 ? nil : [NSString stringWithFormat:@"Upgrade All (%u)", upgrades_];
4425 - (NSString *) title {
4431 /* Manage View {{{ */
4432 @interface ManageView : RVPage {
4433 _transient Database *database_;
4434 PackageTable *packages_;
4435 SourceTable *sources_;
4438 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4442 @implementation ManageView
4445 [packages_ release];
4450 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4451 if ((self = [super initWithBook:book]) != nil) {
4452 database_ = database;
4454 packages_ = [[PackageTable alloc]
4458 filter:@selector(isInstalledInSection:)
4462 sources_ = [[SourceTable alloc]
4467 [self addSubview:packages_];
4471 - (void) resetViewAnimated:(BOOL)animated {
4472 [packages_ resetViewAnimated:animated];
4473 [sources_ resetViewAnimated:animated];
4476 - (void) reloadData {
4477 [packages_ reloadData];
4478 [sources_ reloadData];
4481 - (NSString *) title {
4482 return @"Installed Packages";
4485 - (NSString *) backButtonTitle {
4489 - (void) setDelegate:(id)delegate {
4490 [super setDelegate:delegate];
4491 [packages_ setDelegate:delegate];
4492 [sources_ setDelegate:delegate];
4497 /* Search View {{{ */
4498 @protocol SearchViewDelegate
4499 - (void) showKeyboard:(BOOL)show;
4502 @interface SearchView : RVPage {
4504 UISearchField *field_;
4505 UITransitionView *transition_;
4506 PackageTable *table_;
4507 UIPreferencesTable *advanced_;
4513 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4514 - (void) reloadData;
4518 @implementation SearchView
4522 [[field_ textTraits] setEditingDelegate:nil];
4524 [field_ setDelegate:nil];
4526 [accessory_ release];
4528 [transition_ release];
4530 [advanced_ release];
4535 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
4539 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
4541 case 0: return @"Advanced Search (Coming Soon!)";
4543 default: _assert(false);
4547 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
4551 default: _assert(false);
4555 - (void) _showKeyboard:(BOOL)show {
4556 CGSize keysize = [UIKeyboard defaultSize];
4557 CGRect keydown = [book_ pageBounds];
4558 CGRect keyup = keydown;
4559 keyup.size.height -= keysize.height - ButtonBarHeight_;
4561 float delay = KeyboardTime_ * ButtonBarHeight_ / keysize.height;
4563 UIFrameAnimation *animation = [[[UIFrameAnimation alloc] initWithTarget:[table_ list]] autorelease];
4564 [animation setSignificantRectFields:8];
4567 [animation setStartFrame:keydown];
4568 [animation setEndFrame:keyup];
4570 [animation setStartFrame:keyup];
4571 [animation setEndFrame:keydown];
4574 UIAnimator *animator = [UIAnimator sharedAnimator];
4577 addAnimations:[NSArray arrayWithObjects:animation, nil]
4578 withDuration:(KeyboardTime_ - delay)
4583 [animator performSelector:@selector(startAnimation:) withObject:animation afterDelay:delay];
4586 [delegate_ showKeyboard:show];
4590 - (void) textFieldDidBecomeFirstResponder:(UITextField *)field {
4591 [self _showKeyboard:YES];
4594 - (void) textFieldDidResignFirstResponder:(UITextField *)field {
4595 [self _showKeyboard:NO];
4598 - (void) keyboardInputChanged:(UIFieldEditor *)editor {
4600 NSString *text([field_ text]);
4601 [field_ setClearButtonStyle:(text == nil || [text length] == 0 ? 0 : 2)];
4607 - (void) textFieldClearButtonPressed:(UITextField *)field {
4611 - (void) keyboardInputShouldDelete:(id)input {
4615 - (BOOL) keyboardInput:(id)input shouldInsertText:(NSString *)text isMarkedText:(int)marked {
4616 if ([text length] != 1 || [text characterAtIndex:0] != '\n') {
4620 [field_ resignFirstResponder];
4625 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4626 if ((self = [super initWithBook:book]) != nil) {
4627 CGRect pageBounds = [book_ pageBounds];
4629 /*UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:pageBounds] autorelease];
4630 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
4631 [self addSubview:pinstripe];*/
4633 transition_ = [[UITransitionView alloc] initWithFrame:pageBounds];
4634 [self addSubview:transition_];
4636 advanced_ = [[UIPreferencesTable alloc] initWithFrame:pageBounds];
4638 [advanced_ setReusesTableCells:YES];
4639 [advanced_ setDataSource:self];
4640 [advanced_ reloadData];
4642 dimmed_ = [[UIView alloc] initWithFrame:pageBounds];
4643 CGColor dimmed(space_, 0, 0, 0, 0.5);
4644 [dimmed_ setBackgroundColor:dimmed];
4646 table_ = [[PackageTable alloc]
4650 filter:@selector(isSearchedForBy:)
4654 [table_ setShouldHideHeaderInShortLists:NO];
4655 [transition_ transition:0 toView:table_];
4664 area.origin.x = cnfrect.origin.x + cnfrect.size.width + 14;
4671 [self bounds].size.width - area.origin.x - 18;
4673 area.size.height = [UISearchField defaultHeight];
4675 field_ = [[UISearchField alloc] initWithFrame:area];
4677 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
4678 [field_ setFont:font];
4681 [field_ setPlaceholder:@"Package Names & Descriptions"];
4682 [field_ setDelegate:self];
4685 [field_ setPaddingTop:3];
4687 [field_ setPaddingTop:5];
4691 UITextTraits *traits = [field_ textTraits];
4692 [traits setEditingDelegate:self];
4693 [traits setReturnKeyType:6];
4694 [traits setAutoCapsType:0];
4695 [traits setAutoCorrectionType:1];
4698 CGRect accrect = {{0, 6}, {6 + cnfrect.size.width + 6 + area.size.width + 6, area.size.height + 30}};
4700 accessory_ = [[UIView alloc] initWithFrame:accrect];
4701 [accessory_ addSubview:field_];
4703 UIPushButton *configure = [[[UIPushButton alloc] initWithFrame:cnfrect] autorelease];
4704 [configure setShowPressFeedback:YES];
4705 [configure setImage:[UIImage applicationImageNamed:@"advanced.png"]];
4706 [configure addTarget:self action:@selector(configurePushed) forEvents:1];
4707 [accessory_ addSubview:configure];
4713 LKAnimation *animation = [LKTransition animation];
4714 [animation setType:@"oglFlip"];
4715 [animation setTimingFunction:[LKTimingFunction functionWithName:@"easeInEaseOut"]];
4716 [animation setFillMode:@"extended"];
4717 [animation setTransitionFlags:3];
4718 [animation setDuration:10];
4719 [animation setSpeed:0.35];
4720 [animation setSubtype:(flipped_ ? @"fromLeft" : @"fromRight")];
4721 [[transition_ _layer] addAnimation:animation forKey:0];
4722 [transition_ transition:0 toView:(flipped_ ? (UIView *) table_ : (UIView *) advanced_)];
4723 flipped_ = !flipped_;
4727 - (void) configurePushed {
4728 [field_ resignFirstResponder];
4732 - (void) resetViewAnimated:(BOOL)animated {
4735 [table_ resetViewAnimated:animated];
4738 - (void) reloadData {
4741 [table_ setObject:[field_ text]];
4742 [table_ reloadData];
4743 [table_ resetCursor];
4746 - (UIView *) accessoryView {
4750 - (NSString *) title {
4754 - (NSString *) backButtonTitle {
4758 - (void) setDelegate:(id)delegate {
4759 [table_ setDelegate:delegate];
4760 [super setDelegate:delegate];
4766 @implementation CYBook
4770 [indicator_ release];
4772 [progress_ release];
4776 - (NSString *) getTitleForPage:(RVPage *)page {
4777 return Simplify([super getTitleForPage:page]);
4785 [navbar_ setPrompt:@""];
4786 [navbar_ addSubview:overlay_];
4787 [indicator_ startAnimation];
4788 [prompt_ setText:@"Updating Database..."];
4789 [progress_ setProgress:0];
4794 detachNewThreadSelector:@selector(_update)
4803 [overlay_ removeFromSuperview];
4804 [indicator_ stopAnimation];
4805 [delegate_ reloadData];
4807 [self setPrompt:[NSString stringWithFormat:@"Last Updated: %@", GetLastUpdate()]];
4810 - (id) initWithFrame:(CGRect)frame database:(Database *)database {
4811 if ((self = [super initWithFrame:frame]) != nil) {
4812 database_ = database;
4815 [navbar_ setBarStyle:1];
4817 CGRect ovrrect = [navbar_ bounds];
4818 ovrrect.size.height = ([UINavigationBar defaultSizeWithPrompt].height - [UINavigationBar defaultSize].height);
4820 overlay_ = [[UIView alloc] initWithFrame:ovrrect];
4822 UIProgressIndicatorStyle style = Advanced_ ?
4823 kUIProgressIndicatorStyleSmallWhite :
4824 kUIProgressIndicatorStyleSmallBlack;
4826 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:style];
4827 unsigned indoffset = (ovrrect.size.height - indsize.height) / 2;
4828 CGRect indrect = {{indoffset, indoffset}, indsize};
4830 indicator_ = [[UIProgressIndicator alloc] initWithFrame:indrect];
4831 [indicator_ setStyle:style];
4832 [overlay_ addSubview:indicator_];
4834 CGSize prmsize = {200, indsize.width + 4};
4837 indoffset * 2 + indsize.width,
4841 (ovrrect.size.height - prmsize.height) / 2
4844 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 12);
4846 prompt_ = [[UITextLabel alloc] initWithFrame:prmrect];
4848 [prompt_ setColor:(Advanced_ ? White_ : Blueish_)];
4849 [prompt_ setBackgroundColor:Clear_];
4850 [prompt_ setFont:font];
4854 [overlay_ addSubview:prompt_];
4856 CGSize prgsize = {75, 100};
4859 ovrrect.size.width - prgsize.width - 10,
4860 (ovrrect.size.height - prgsize.height) / 2
4863 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
4864 [progress_ setStyle:0];
4865 [overlay_ addSubview:progress_];
4870 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
4873 status.setDelegate(self);
4875 [database_ updateWithStatus:status];
4878 performSelectorOnMainThread:@selector(_update_)
4886 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id {
4887 [prompt_ setText:[NSString stringWithFormat:@"Error: %@", error]];
4890 - (void) setProgressTitle:(NSString *)title {
4892 performSelectorOnMainThread:@selector(_setProgressTitle:)
4898 - (void) setProgressPercent:(float)percent {
4901 - (void) addProgressOutput:(NSString *)output {
4903 performSelectorOnMainThread:@selector(_addProgressOutput:)
4909 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
4913 - (void) _setProgressTitle:(NSString *)title {
4914 [prompt_ setText:[title stringByAppendingString:@"..."]];
4917 - (void) _addProgressOutput:(NSString *)output {
4922 @interface Cydia : UIApplication <
4923 ConfirmationViewDelegate,
4924 ProgressViewDelegate,
4933 UIButtonBar *buttonbar_;
4935 ConfirmationView *confirm_;
4937 NSMutableArray *essential_;
4938 NSMutableArray *broken_;
4940 Database *database_;
4941 ProgressView *progress_;
4945 UIKeyboard *keyboard_;
4946 UIProgressHUD *hud_;
4948 InstallView *install_;
4949 ChangesView *changes_;
4950 ManageView *manage_;
4951 SearchView *search_;
4956 @implementation Cydia
4959 if ([broken_ count] != 0) {
4960 int count = [broken_ count];
4962 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
4963 initWithTitle:[NSString stringWithFormat:@"%d Half-Installed Package%@", count, (count == 1 ? @"" : @"s")]
4964 buttons:[NSArray arrayWithObjects:
4966 @"Ignore (Temporary)",
4968 defaultButtonIndex:0
4973 [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."];
4974 [sheet popupAlertAnimated:YES];
4975 } else if (!Ignored_ && [essential_ count] != 0) {
4976 int count = [essential_ count];
4978 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
4979 initWithTitle:[NSString stringWithFormat:@"%d Essential Upgrade%@", count, (count == 1 ? @"" : @"s")]
4980 buttons:[NSArray arrayWithObjects:@"Upgrade Essential", @"Ignore (Temporary)", nil]
4981 defaultButtonIndex:0
4986 [sheet setBodyText:@"One or more essential packages are currently out of date. If these upgrades are not performed you are likely to encounter errors."];
4987 [sheet popupAlertAnimated:YES];
4991 - (void) _reloadData {
4992 /*UIProgressHUD *hud = [[UIProgressHUD alloc] initWithWindow:window_];
4993 [hud setText:@"Reloading Data"];
4994 [overlay_ addSubview:hud];
4997 [database_ reloadData];
4999 if (Packages_ == nil) {
5000 Packages_ = [[NSMutableDictionary alloc] initWithCapacity:128];
5001 [Metadata_ setObject:Packages_ forKey:@"Packages"];
5006 [essential_ removeAllObjects];
5007 [broken_ removeAllObjects];
5009 NSArray *packages = [database_ packages];
5010 for (int i(0), e([packages count]); i != e; ++i) {
5011 Package *package = [packages objectAtIndex:i];
5013 [broken_ addObject:package];
5014 if ([package upgradableAndEssential:NO]) {
5015 if ([package essential])
5016 [essential_ addObject:package];
5022 NSString *badge([[NSNumber numberWithInt:changes] stringValue]);
5023 [buttonbar_ setBadgeValue:badge forButton:3];
5024 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
5025 [buttonbar_ setBadgeAnimated:YES forButton:3];
5026 [self setApplicationBadge:badge];
5028 [buttonbar_ setBadgeValue:nil forButton:3];
5029 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
5030 [buttonbar_ setBadgeAnimated:NO forButton:3];
5031 [self removeApplicationBadge];
5035 _assert([Metadata_ writeToFile:@"/var/lib/cydia/metadata.plist" atomically:YES] == YES);
5039 /* XXX: this is just stupid */
5041 [install_ reloadData];
5043 [changes_ reloadData];
5045 [manage_ reloadData];
5047 [search_ reloadData];
5051 if ([packages count] == 0);
5060 [hud removeFromSuperview];*/
5063 - (void) reloadData {
5064 @synchronized (self) {
5065 if (confirm_ == nil)
5071 pkgProblemResolver *resolver = [database_ resolver];
5073 resolver->InstallProtect();
5074 if (!resolver->Resolve(true))
5079 [database_ prepare];
5081 if ([database_ cache]->BrokenCount() == 0)
5082 confirm_ = [[ConfirmationView alloc] initWithView:underlay_ database:database_ delegate:self];
5084 NSMutableArray *broken = [NSMutableArray arrayWithCapacity:16];
5085 NSArray *packages = [database_ packages];
5087 for (size_t i(0); i != [packages count]; ++i) {
5088 Package *package = [packages objectAtIndex:i];
5089 if ([package broken])
5090 [broken addObject:[package name]];
5093 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
5094 initWithTitle:[NSString stringWithFormat:@"%d Broken Packages", [database_ cache]->BrokenCount()]
5095 buttons:[NSArray arrayWithObjects:@"Okay", nil]
5096 defaultButtonIndex:0
5101 [sheet setBodyText:[NSString stringWithFormat:@"The following packages have unmet dependencies:\n\n%@", [broken componentsJoinedByString:@"\n"]]];
5102 [sheet popupAlertAnimated:YES];
5108 - (void) installPackage:(Package *)package {
5109 @synchronized (self) {
5116 - (void) removePackage:(Package *)package {
5117 @synchronized (self) {
5124 - (void) distUpgrade {
5125 @synchronized (self) {
5126 [database_ upgrade];
5132 @synchronized (self) {
5140 [overlay_ removeFromSuperview];
5144 detachNewThreadSelector:@selector(perform)
5151 - (void) bootstrap_ {
5153 [database_ upgrade];
5154 [database_ prepare];
5155 [database_ perform];
5158 - (void) bootstrap {
5160 detachNewThreadSelector:@selector(bootstrap_)
5163 title:@"Bootstrap Install..."
5167 - (void) progressViewIsComplete:(ProgressView *)progress {
5168 @synchronized (self) {
5171 if (confirm_ != nil) {
5172 [underlay_ addSubview:overlay_];
5173 [confirm_ removeFromSuperview];
5180 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
5181 NSString *context = [sheet context];
5182 if ([context isEqualToString:@"fixhalf"])
5185 @synchronized (self) {
5186 for (int i = 0, e = [broken_ count]; i != e; ++i) {
5187 Package *broken = [broken_ objectAtIndex:i];
5190 NSString *id = [broken id];
5191 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.prerm", id] UTF8String]);
5192 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.postrm", id] UTF8String]);
5193 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.preinst", id] UTF8String]);
5194 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.postinst", id] UTF8String]);
5203 [broken_ removeAllObjects];
5210 else if ([context isEqualToString:@"upgrade"])
5213 @synchronized (self) {
5214 for (int i = 0, e = [essential_ count]; i != e; ++i) {
5215 Package *essential = [essential_ objectAtIndex:i];
5216 [essential install];
5235 - (void) setPage:(RVPage *)page {
5236 [page resetViewAnimated:NO];
5237 [page setDelegate:self];
5238 [book_ setPage:page];
5241 - (RVPage *) _setHomePage {
5242 BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease];
5243 [self setPage:browser];
5244 [browser loadURL:[NSURL URLWithString:@"http://cydia.saurik.com/"]];
5248 - (void) buttonBarItemTapped:(id)sender {
5249 unsigned tag = [sender tag];
5251 [book_ resetViewAnimated:YES];
5256 case 1: [self _setHomePage]; break;
5258 case 2: [self setPage:install_]; break;
5259 case 3: [self setPage:changes_]; break;
5260 case 4: [self setPage:manage_]; break;
5261 case 5: [self setPage:search_]; break;
5263 default: _assert(false);
5269 - (void) fixSpringBoard {
5270 pid_t pid = ExecFork();
5274 if (pid_t child = fork()) {
5275 waitpid(child, NULL, 0);
5277 execlp("launchctl", "launchctl", "unload", SpringBoard_, NULL);
5278 perror("launchctl unload");
5282 execlp("launchctl", "launchctl", "load", SpringBoard_, NULL);
5283 perror("launchctl load");
5288 - (void) applicationWillSuspend {
5293 [self fixSpringBoard];
5297 [super applicationWillSuspend];
5302 [self setStatusBarShowsProgress:NO];
5305 [hud_ removeFromSuperview];
5310 [self fixSpringBoard];
5314 overlay_ = [[UIView alloc] initWithFrame:[underlay_ bounds]];
5316 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
5317 book_ = [[CYBook alloc] initWithFrame:CGRectMake(
5318 0, 0, screenrect.size.width, screenrect.size.height - 48
5319 ) database:database_];
5321 [book_ setDelegate:self];
5323 [overlay_ addSubview:book_];
5325 NSArray *buttonitems = [NSArray arrayWithObjects:
5326 [NSDictionary dictionaryWithObjectsAndKeys:
5327 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5328 @"home-up.png", kUIButtonBarButtonInfo,
5329 @"home-dn.png", kUIButtonBarButtonSelectedInfo,
5330 [NSNumber numberWithInt:1], kUIButtonBarButtonTag,
5331 self, kUIButtonBarButtonTarget,
5332 @"Home", kUIButtonBarButtonTitle,
5333 @"0", kUIButtonBarButtonType,
5336 [NSDictionary dictionaryWithObjectsAndKeys:
5337 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5338 @"install-up.png", kUIButtonBarButtonInfo,
5339 @"install-dn.png", kUIButtonBarButtonSelectedInfo,
5340 [NSNumber numberWithInt:2], kUIButtonBarButtonTag,
5341 self, kUIButtonBarButtonTarget,
5342 @"Install", kUIButtonBarButtonTitle,
5343 @"0", kUIButtonBarButtonType,
5346 [NSDictionary dictionaryWithObjectsAndKeys:
5347 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5348 @"changes-up.png", kUIButtonBarButtonInfo,
5349 @"changes-dn.png", kUIButtonBarButtonSelectedInfo,
5350 [NSNumber numberWithInt:3], kUIButtonBarButtonTag,
5351 self, kUIButtonBarButtonTarget,
5352 @"Changes", kUIButtonBarButtonTitle,
5353 @"0", kUIButtonBarButtonType,
5356 [NSDictionary dictionaryWithObjectsAndKeys:
5357 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5358 @"manage-up.png", kUIButtonBarButtonInfo,
5359 @"manage-dn.png", kUIButtonBarButtonSelectedInfo,
5360 [NSNumber numberWithInt:4], kUIButtonBarButtonTag,
5361 self, kUIButtonBarButtonTarget,
5362 @"Manage", kUIButtonBarButtonTitle,
5363 @"0", kUIButtonBarButtonType,
5366 [NSDictionary dictionaryWithObjectsAndKeys:
5367 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5368 @"search-up.png", kUIButtonBarButtonInfo,
5369 @"search-dn.png", kUIButtonBarButtonSelectedInfo,
5370 [NSNumber numberWithInt:5], kUIButtonBarButtonTag,
5371 self, kUIButtonBarButtonTarget,
5372 @"Search", kUIButtonBarButtonTitle,
5373 @"0", kUIButtonBarButtonType,
5377 buttonbar_ = [[UIButtonBar alloc]
5379 withFrame:CGRectMake(
5380 0, screenrect.size.height - ButtonBarHeight_,
5381 screenrect.size.width, ButtonBarHeight_
5383 withItemList:buttonitems
5386 [buttonbar_ setDelegate:self];
5387 [buttonbar_ setBarStyle:1];
5388 [buttonbar_ setButtonBarTrackingMode:2];
5390 int buttons[5] = {1, 2, 3, 4, 5};
5391 [buttonbar_ registerButtonGroup:0 withButtons:buttons withCount:5];
5392 [buttonbar_ showButtonGroup:0 withDuration:0];
5394 for (int i = 0; i != 5; ++i)
5395 [[buttonbar_ viewWithTag:(i + 1)] setFrame:CGRectMake(
5396 i * 64 + 2, 1, 60, ButtonBarHeight_
5399 [buttonbar_ showSelectionForButton:1];
5400 [overlay_ addSubview:buttonbar_];
5402 [UIKeyboard initImplementationNow];
5403 CGSize keysize = [UIKeyboard defaultSize];
5404 CGRect keyrect = {{0, [overlay_ bounds].size.height}, keysize};
5405 keyboard_ = [[UIKeyboard alloc] initWithFrame:keyrect];
5406 [[UIKeyboardImpl sharedInstance] setSoundsEnabled:(Sounds_Keyboard_ ? YES : NO)];
5407 [overlay_ addSubview:keyboard_];
5409 install_ = [[InstallView alloc] initWithBook:book_ database:database_];
5410 changes_ = [[ChangesView alloc] initWithBook:book_ database:database_];
5411 manage_ = [[ManageView alloc] initWithBook:book_ database:database_];
5412 search_ = [[SearchView alloc] initWithBook:book_ database:database_];
5415 [underlay_ addSubview:overlay_];
5422 [self _setHomePage];
5425 - (void) reorganize {
5426 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5427 system("/usr/libexec/cydia/free.sh");
5428 [self performSelectorOnMainThread:@selector(finish) withObject:nil waitUntilDone:NO];
5432 - (void) applicationSuspend:(__GSEvent *)event {
5433 if (hud_ == nil && ![progress_ isRunning])
5434 [super applicationSuspend:event];
5437 - (void) applicationDidFinishLaunching:(id)unused {
5438 _assert(pkgInitConfig(*_config));
5439 _assert(pkgInitSystem(*_config, _system));
5444 essential_ = [[NSMutableArray alloc] initWithCapacity:4];
5445 broken_ = [[NSMutableArray alloc] initWithCapacity:4];
5447 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
5448 window_ = [[UIWindow alloc] initWithContentRect:screenrect];
5450 [window_ orderFront: self];
5451 [window_ makeKey: self];
5452 [window_ _setHidden: NO];
5454 database_ = [[Database alloc] init];
5455 progress_ = [[ProgressView alloc] initWithFrame:[window_ bounds] database:database_ delegate:self];
5456 [database_ setDelegate:progress_];
5457 [window_ setContentView:progress_];
5459 underlay_ = [[UIView alloc] initWithFrame:[progress_ bounds]];
5460 [progress_ setContentView:underlay_];
5462 [progress_ resetView];
5465 readlink("/Applications", NULL, 0) == -1 && errno == EINVAL ||
5466 readlink("/usr/share", NULL, 0) == -1 && errno == EINVAL ||
5467 readlink("/Library/Ringtones", NULL, 0) == -1 && errno == EINVAL ||
5468 readlink("/Library/Wallpaper", NULL, 0) == -1 && errno == EINVAL
5470 hud_ = [[UIProgressHUD alloc] initWithWindow:window_];
5471 [hud_ setText:@"Reorganizing\nOne Minute!\nPlease Wait...\nDO NOT STOP"];
5473 [underlay_ addSubview:hud_];
5475 [self setStatusBarShowsProgress:YES];
5478 detachNewThreadSelector:@selector(reorganize)
5486 - (void) showKeyboard:(BOOL)show {
5487 CGSize keysize = [UIKeyboard defaultSize];
5488 CGRect keydown = {{0, [overlay_ bounds].size.height}, keysize};
5489 CGRect keyup = keydown;
5490 keyup.origin.y -= keysize.height;
5492 UIFrameAnimation *animation = [[[UIFrameAnimation alloc] initWithTarget:keyboard_] autorelease];
5493 [animation setSignificantRectFields:2];
5496 [animation setStartFrame:keydown];
5497 [animation setEndFrame:keyup];
5498 [keyboard_ activate];
5500 [animation setStartFrame:keyup];
5501 [animation setEndFrame:keydown];
5502 [keyboard_ deactivate];
5505 [[UIAnimator sharedAnimator]
5506 addAnimations:[NSArray arrayWithObjects:animation, nil]
5507 withDuration:KeyboardTime_
5512 - (void) slideUp:(UIAlertSheet *)alert {
5514 [alert presentSheetFromButtonBar:buttonbar_];
5516 [alert presentSheetInView:overlay_];
5521 void AddPreferences(NSString *plist) {
5522 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5524 NSMutableDictionary *settings = [[[NSMutableDictionary alloc] initWithContentsOfFile:plist] autorelease];
5525 _assert(settings != NULL);
5526 NSMutableArray *items = [settings objectForKey:@"items"];
5530 for (size_t i(0); i != [items count]; ++i) {
5531 NSMutableDictionary *item([items objectAtIndex:i]);
5532 NSString *label = [item objectForKey:@"label"];
5533 if (label != nil && [label isEqualToString:@"Cydia"]) {
5540 for (size_t i(0); i != [items count]; ++i) {
5541 NSDictionary *item([items objectAtIndex:i]);
5542 NSString *label = [item objectForKey:@"label"];
5543 if (label != nil && [label isEqualToString:@"General"]) {
5544 [items insertObject:[NSDictionary dictionaryWithObjectsAndKeys:
5545 @"CydiaSettings", @"bundle",
5546 @"PSLinkCell", @"cell",
5547 [NSNumber numberWithBool:YES], @"hasIcon",
5548 [NSNumber numberWithBool:YES], @"isController",
5550 nil] atIndex:(i + 1)];
5556 _assert([settings writeToFile:plist atomically:YES] == YES);
5563 id Alloc_(id self, SEL selector) {
5564 id object = alloc_(self, selector);
5565 fprintf(stderr, "[%s]A-%p\n", self->isa->name, object);
5570 id Dealloc_(id self, SEL selector) {
5571 id object = dealloc_(self, selector);
5572 fprintf(stderr, "[%s]D-%p\n", self->isa->name, object);
5576 int main(int argc, char *argv[]) {
5577 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5579 bootstrap_ = argc > 1 && strcmp(argv[1], "--bootstrap") == 0;
5581 Home_ = NSHomeDirectory();
5584 NSString *plist = [Home_ stringByAppendingString:@"/Library/Preferences/com.apple.preferences.sounds.plist"];
5585 if (NSDictionary *sounds = [NSDictionary dictionaryWithContentsOfFile:plist])
5586 if (NSNumber *keyboard = [sounds objectForKey:@"keyboard"])
5587 Sounds_Keyboard_ = [keyboard boolValue];
5593 if (unlink("/var/cache/apt/pkgcache.bin") == -1)
5594 _assert(errno == ENOENT);
5595 if (unlink("/var/cache/apt/srcpkgcache.bin") == -1)
5596 _assert(errno == ENOENT);
5598 /*Method alloc = class_getClassMethod([NSObject class], @selector(alloc));
5599 alloc_ = alloc->method_imp;
5600 alloc->method_imp = (IMP) &Alloc_;*/
5602 /*Method dealloc = class_getClassMethod([NSObject class], @selector(dealloc));
5603 dealloc_ = dealloc->method_imp;
5604 dealloc->method_imp = (IMP) &Dealloc_;*/
5606 if (NSDictionary *sysver = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]) {
5607 if (NSString *prover = [sysver valueForKey:@"ProductVersion"]) {
5608 Firmware_ = strdup([prover UTF8String]);
5609 NSArray *versions = [prover componentsSeparatedByString:@"."];
5610 int count = [versions count];
5611 Major_ = count > 0 ? [[versions objectAtIndex:0] intValue] : 0;
5612 Minor_ = count > 1 ? [[versions objectAtIndex:1] intValue] : 0;
5613 BugFix_ = count > 2 ? [[versions objectAtIndex:2] intValue] : 0;
5618 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
5619 char *machine = new char[size];
5620 sysctlbyname("hw.machine", machine, &size, NULL, 0);
5623 if (CFMutableDictionaryRef dict = IOServiceMatching("IOPlatformExpertDevice"))
5624 if (io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, dict)) {
5625 if (CFTypeRef serial = IORegistryEntryCreateCFProperty(service, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0)) {
5626 SerialNumber_ = strdup(CFStringGetCStringPtr((CFStringRef) serial, CFStringGetSystemEncoding()));
5630 IOObjectRelease(service);
5633 /*AddPreferences(@"/Applications/Preferences.app/Settings-iPhone.plist");
5634 AddPreferences(@"/Applications/Preferences.app/Settings-iPod.plist");*/
5636 if ((Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"]) == NULL)
5637 Metadata_ = [[NSMutableDictionary alloc] initWithCapacity:2];
5639 Packages_ = [Metadata_ objectForKey:@"Packages"];
5641 if (access("/User", F_OK) != 0)
5642 system("/usr/libexec/cydia/firmware.sh");
5644 Locale_ = CFLocaleCopyCurrent();
5645 space_ = CGColorSpaceCreateDeviceRGB();
5647 Blueish_.Set(space_, 0x19/255.f, 0x32/255.f, 0x50/255.f, 1.0);
5648 Black_.Set(space_, 0.0, 0.0, 0.0, 1.0);
5649 Clear_.Set(space_, 0.0, 0.0, 0.0, 0.0);
5650 Red_.Set(space_, 1.0, 0.0, 0.0, 1.0);
5651 White_.Set(space_, 1.0, 1.0, 1.0, 1.0);
5653 int value = UIApplicationMain(argc, argv, [Cydia class]);
5655 CGColorSpaceRelease(space_);