1 /* Cydia - iPhone UIKit Front-End for Debian APT
2 * Copyright (C) 2008 Jay Freeman (saurik)
6 * Redistribution and use in source and binary
7 * forms, with or without modification, are permitted
8 * provided that the following conditions are met:
10 * 1. Redistributions of source code must retain the
11 * above copyright notice, this list of conditions
12 * and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the
14 * above copyright notice, this list of conditions
15 * and the following disclaimer in the documentation
16 * and/or other materials provided with the
18 * 3. The name of the author may not be used to endorse
19 * or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS''
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
24 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
33 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
35 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 #define UITextTraits UITextInputTraits
40 #define textTraits textInputTraits
41 #define setAutoCapsType setAutocapitalizationType
42 #define setAutoCorrectionType setAutocorrectionType
45 /* #include Directives {{{ */
46 #include <objc/objc.h>
47 #include <objc/runtime.h>
49 #include <CoreGraphics/CoreGraphics.h>
50 #include <GraphicsServices/GraphicsServices.h>
51 #include <Foundation/Foundation.h>
52 #include <UIKit/UIKit.h>
53 #include <WebCore/DOMHTML.h>
55 #import "BrowserView.h"
57 #import "UICaboodle.h"
59 #include <WebKit/WebFrame.h>
60 #include <WebKit/WebView.h>
65 #include <ext/stdio_filebuf.h>
67 #include <apt-pkg/acquire.h>
68 #include <apt-pkg/acquire-item.h>
69 #include <apt-pkg/algorithms.h>
70 #include <apt-pkg/cachefile.h>
71 #include <apt-pkg/clean.h>
72 #include <apt-pkg/configuration.h>
73 #include <apt-pkg/debmetaindex.h>
74 #include <apt-pkg/error.h>
75 #include <apt-pkg/init.h>
76 #include <apt-pkg/pkgrecords.h>
77 #include <apt-pkg/sourcelist.h>
78 #include <apt-pkg/sptr.h>
80 #include <sys/sysctl.h>
84 #include <mach-o/nlist.h>
95 /* iPhoneOS 2.0 Compatibility {{{ */
97 @interface UICGColor : NSObject {
100 - (id) initWithCGColor:(CGColorRef)color;
106 - (UIFont *) fontWithSize:(CGFloat)size;
109 @interface NSObject (iPhoneOS)
110 - (CGColorRef) cgColor;
111 - (CGColorRef) CGColor;
115 @implementation NSObject (iPhoneOS)
117 - (CGColorRef) cgColor {
118 return [self CGColor];
121 - (CGColorRef) CGColor {
122 return (CGColorRef) self;
126 [[[[objc_getClass("UICGColor") alloc] initWithCGColor:[self CGColor]] autorelease] set];
131 @interface UITextView (iPhoneOS)
132 - (void) setTextSize:(float)size;
135 @implementation UITextView (iPhoneOS)
137 - (void) setTextSize:(float)size {
138 [self setFont:[[self font] fontWithSize:size]];
145 @interface UIApplication (IdleTimer)
146 - (void) setIdleTimerDisabled:(char)arg0;
151 kUIProgressIndicatorStyleMediumWhite = 1,
152 kUIProgressIndicatorStyleSmallWhite = 0,
153 kUIProgressIndicatorStyleSmallBlack = 4
154 } UIProgressIndicatorStyle;
157 kUIProgressIndicatorStyleMediumWhite = 0,
158 kUIProgressIndicatorStyleSmallWhite = 2,
159 kUIProgressIndicatorStyleSmallBlack = 3
160 } UIProgressIndicatorStyle;
164 kUIControlEventMouseDown = 1 << 0,
165 kUIControlEventMouseMovedInside = 1 << 2, // mouse moved inside control target
166 kUIControlEventMouseMovedOutside = 1 << 3, // mouse moved outside control target
167 kUIControlEventMouseUpInside = 1 << 6, // mouse up inside control target
168 kUIControlEventMouseUpOutside = 1 << 7, // mouse up outside control target
169 kUIControlAllEvents = (kUIControlEventMouseDown | kUIControlEventMouseMovedInside | kUIControlEventMouseMovedOutside | kUIControlEventMouseUpInside | kUIControlEventMouseUpOutside)
170 } UIControlEventMasks;
172 @interface NSString (UIKit)
173 - (NSString *) stringByAddingPercentEscapes;
174 - (NSString *) stringByReplacingCharacter:(unsigned short)arg0 withCharacter:(unsigned short)arg1;
177 @interface NSString (Cydia)
178 + (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length;
179 - (NSComparisonResult) compareByPath:(NSString *)other;
182 @implementation NSString (Cydia)
184 + (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length {
185 char data[length + 1];
186 memcpy(data, bytes, length);
188 return [NSString stringWithUTF8String:data];
191 - (NSComparisonResult) compareByPath:(NSString *)other {
192 NSString *prefix = [self commonPrefixWithString:other options:0];
193 size_t length = [prefix length];
195 NSRange lrange = NSMakeRange(length, [self length] - length);
196 NSRange rrange = NSMakeRange(length, [other length] - length);
198 lrange = [self rangeOfString:@"/" options:0 range:lrange];
199 rrange = [other rangeOfString:@"/" options:0 range:rrange];
201 NSComparisonResult value;
203 if (lrange.location == NSNotFound && rrange.location == NSNotFound)
204 value = NSOrderedSame;
205 else if (lrange.location == NSNotFound)
206 value = NSOrderedAscending;
207 else if (rrange.location == NSNotFound)
208 value = NSOrderedDescending;
210 value = NSOrderedSame;
212 NSString *lpath = lrange.location == NSNotFound ? [self substringFromIndex:length] :
213 [self substringWithRange:NSMakeRange(length, lrange.location - length)];
214 NSString *rpath = rrange.location == NSNotFound ? [other substringFromIndex:length] :
215 [other substringWithRange:NSMakeRange(length, rrange.location - length)];
217 NSComparisonResult result = [lpath compare:rpath];
218 return result == NSOrderedSame ? value : result;
223 /* Perl-Compatible RegEx {{{ */
233 Pcre(const char *regex) :
238 code_ = pcre_compile(regex, 0, &error, &offset, NULL);
241 fprintf(stderr, "%d:%s\n", offset, error);
245 pcre_fullinfo(code_, study_, PCRE_INFO_CAPTURECOUNT, &capture_);
246 matches_ = new int[(capture_ + 1) * 3];
254 NSString *operator [](size_t match) {
255 return [NSString stringWithUTF8Bytes:(data_ + matches_[match * 2]) length:(matches_[match * 2 + 1] - matches_[match * 2])];
258 bool operator ()(NSString *data) {
259 // XXX: length is for characters, not for bytes
260 return operator ()([data UTF8String], [data length]);
263 bool operator ()(const char *data, size_t size) {
265 return pcre_exec(code_, study_, data, size, 0, 0, matches_, (capture_ + 1) * 3) >= 0;
269 /* Mime Addresses {{{ */
270 Pcre email_r("^\"?(.*)\"? <([^>]*)>$");
272 @interface Address : NSObject {
278 - (NSString *) email;
280 + (Address *) addressWithString:(NSString *)string;
281 - (Address *) initWithString:(NSString *)string;
284 @implementation Address
293 - (NSString *) name {
297 - (NSString *) email {
301 + (Address *) addressWithString:(NSString *)string {
302 return [[[Address alloc] initWithString:string] autorelease];
305 - (Address *) initWithString:(NSString *)string {
306 if ((self = [super init]) != nil) {
307 const char *data = [string UTF8String];
308 size_t size = [string length];
310 if (email_r(data, size)) {
311 name_ = [email_r[1] retain];
312 email_ = [email_r[2] retain];
314 name_ = [[NSString alloc]
317 encoding:kCFStringEncodingUTF8
327 /* CoreGraphics Primitives {{{ */
338 CGColor(CGColorSpaceRef space, float red, float green, float blue, float alpha) :
341 Set(space, red, green, blue, alpha);
346 CGColorRelease(color_);
353 void Set(CGColorSpaceRef space, float red, float green, float blue, float alpha) {
355 float color[] = {red, green, blue, alpha};
356 color_ = CGColorCreate(space, color);
359 operator CGColorRef() {
374 /* Right Alignment {{{ */
375 @interface UIRightTextLabel : UITextLabel {
376 float _savedRightEdgeX;
377 BOOL _sizedtofit_flag;
380 - (void) setFrame:(CGRect)frame;
381 - (void) setText:(NSString *)text;
382 - (void) realignText;
385 @implementation UIRightTextLabel
387 - (void) setFrame:(CGRect)frame {
388 [super setFrame:frame];
389 if (_sizedtofit_flag == NO) {
390 _savedRightEdgeX = frame.origin.x;
395 - (void) setText:(NSString *)text {
396 [super setText:text];
400 - (void) realignText {
401 CGRect oldFrame = [self frame];
403 _sizedtofit_flag = YES;
404 [self sizeToFit]; // shrink down size so I can right align it
406 CGRect newFrame = [self frame];
408 oldFrame.origin.x = _savedRightEdgeX - newFrame.size.width;
409 oldFrame.size.width = newFrame.size.width;
410 [super setFrame:oldFrame];
411 _sizedtofit_flag = NO;
417 /* Random Global Variables {{{ */
418 static const int PulseInterval_ = 50000;
419 static const int ButtonBarHeight_ = 48;
420 static const float KeyboardTime_ = 0.3f;
421 static const char * const SpringBoard_ = "/System/Library/LaunchDaemons/com.apple.SpringBoard.plist";
427 static CGColor Blueish_;
428 static CGColor Black_;
429 static CGColor Clear_;
431 static CGColor White_;
433 static NSString *Home_;
434 static BOOL Sounds_Keyboard_;
436 static BOOL Advanced_;
438 static BOOL Ignored_;
440 const char *Firmware_ = NULL;
441 const char *Machine_ = NULL;
442 const char *SerialNumber_ = NULL;
449 CGColorSpaceRef space_;
451 #define FW_LEAST(major, minor, bugfix) \
452 (major < Major_ || major == Major_ && \
453 (minor < Minor_ || minor == Minor_ && \
459 static NSMutableDictionary *Metadata_;
460 static NSMutableDictionary *Packages_;
461 static NSMutableDictionary *Sections_;
462 static bool Changed_;
465 NSString *GetLastUpdate() {
466 NSDate *update = [Metadata_ objectForKey:@"LastUpdate"];
469 return @"Never or Unknown";
471 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, Locale_, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
472 CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) update);
474 CFRelease(formatter);
476 return [(NSString *) formatted autorelease];
479 /* Display Helpers {{{ */
480 inline float Interpolate(float begin, float end, float fraction) {
481 return (end - begin) * fraction + begin;
484 NSString *SizeString(double size) {
486 while (size > 1024) {
491 static const char *powers_[] = {"B", "kB", "MB", "GB"};
493 return [NSString stringWithFormat:@"%.1f%s", size, powers_[power]];
496 NSString *StripVersion(NSString *version) {
497 NSRange colon = [version rangeOfString:@":"];
498 if (colon.location != NSNotFound)
499 version = [version substringFromIndex:(colon.location + 1)];
503 static const float TextViewOffset_ = 22;
505 UITextView *GetTextView(NSString *value, float left, bool html) {
506 UITextView *text([[[UITextView alloc] initWithFrame:CGRectMake(left, 3, 310 - left, 1000)] autorelease]);
507 [text setEditable:NO];
508 [text setTextSize:16];
510 [text setHTML:value];
512 [text setText:value];
513 [text setEnabled:NO];
515 [text setBackgroundColor:Clear_];
517 CGRect frame = [text frame];
518 [text setFrame:frame];
519 CGRect rect = [text visibleTextRect];
520 frame.size.height = rect.size.height;
521 [text setFrame:frame];
526 NSString *Simplify(NSString *title) {
527 const char *data = [title UTF8String];
528 size_t size = [title length];
530 Pcre title_r("^(.*?)( \\(.*\\))?$");
531 if (title_r(data, size))
538 bool isSectionVisible(NSString *section) {
539 NSDictionary *metadata = [Sections_ objectForKey:section];
540 NSNumber *hidden = metadata == nil ? nil : [metadata objectForKey:@"Hidden"];
541 return hidden == nil || ![hidden boolValue];
544 /* Delegate Prototypes {{{ */
548 @interface NSObject (ProgressDelegate)
551 @implementation NSObject(ProgressDelegate)
553 - (void) _setProgressError:(NSArray *)args {
554 [self performSelector:@selector(setProgressError:forPackage:)
555 withObject:[args objectAtIndex:0]
556 withObject:([args count] == 1 ? nil : [args objectAtIndex:1])
562 @protocol ProgressDelegate
563 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id;
564 - (void) setProgressTitle:(NSString *)title;
565 - (void) setProgressPercent:(float)percent;
566 - (void) addProgressOutput:(NSString *)output;
569 @protocol ConfigurationDelegate
570 - (void) repairWithSelector:(SEL)selector;
571 - (void) setConfigurationData:(NSString *)data;
574 @protocol CydiaDelegate
575 - (void) installPackage:(Package *)package;
576 - (void) removePackage:(Package *)package;
577 - (void) slideUp:(UIAlertSheet *)alert;
578 - (void) distUpgrade;
583 /* Status Delegation {{{ */
585 public pkgAcquireStatus
588 _transient NSObject<ProgressDelegate> *delegate_;
596 void setDelegate(id delegate) {
597 delegate_ = delegate;
600 virtual bool MediaChange(std::string media, std::string drive) {
604 virtual void IMSHit(pkgAcquire::ItemDesc &item) {
607 virtual void Fetch(pkgAcquire::ItemDesc &item) {
608 [delegate_ setProgressTitle:[NSString stringWithUTF8String:("Downloading " + item.ShortDesc).c_str()]];
611 virtual void Done(pkgAcquire::ItemDesc &item) {
614 virtual void Fail(pkgAcquire::ItemDesc &item) {
616 item.Owner->Status == pkgAcquire::Item::StatIdle ||
617 item.Owner->Status == pkgAcquire::Item::StatDone
621 [delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
622 withObject:[NSArray arrayWithObjects:[NSString stringWithUTF8String:item.Owner->ErrorText.c_str()], nil]
627 virtual bool Pulse(pkgAcquire *Owner) {
628 bool value = pkgAcquireStatus::Pulse(Owner);
631 double(CurrentBytes + CurrentItems) /
632 double(TotalBytes + TotalItems)
635 [delegate_ setProgressPercent:percent];
639 virtual void Start() {
642 virtual void Stop() {
646 /* Progress Delegation {{{ */
651 _transient id<ProgressDelegate> delegate_;
654 virtual void Update() {
655 [delegate_ setProgressTitle:[NSString stringWithUTF8String:Op.c_str()]];
656 [delegate_ setProgressPercent:(Percent / 100)];
665 void setDelegate(id delegate) {
666 delegate_ = delegate;
669 virtual void Done() {
670 [delegate_ setProgressPercent:1];
675 /* Database Interface {{{ */
676 @interface Database : NSObject {
678 pkgDepCache::Policy *policy_;
679 pkgRecords *records_;
680 pkgProblemResolver *resolver_;
681 pkgAcquire *fetcher_;
683 SPtr<pkgPackageManager> manager_;
684 pkgSourceList *list_;
686 NSMutableDictionary *sources_;
687 NSMutableArray *packages_;
689 _transient NSObject<ConfigurationDelegate, ProgressDelegate> *delegate_;
698 - (void) _readCydia:(NSNumber *)fd;
699 - (void) _readStatus:(NSNumber *)fd;
700 - (void) _readOutput:(NSNumber *)fd;
704 - (Package *) packageWithName:(NSString *)name;
707 - (pkgCacheFile &) cache;
708 - (pkgDepCache::Policy *) policy;
709 - (pkgRecords *) records;
710 - (pkgProblemResolver *) resolver;
711 - (pkgAcquire &) fetcher;
712 - (NSArray *) packages;
721 - (void) updateWithStatus:(Status &)status;
723 - (void) setDelegate:(id)delegate;
724 - (Source *) getSource:(const pkgCache::PkgFileIterator &)file;
728 /* Source Class {{{ */
729 @interface Source : NSObject {
730 NSString *description_;
735 NSString *distribution_;
739 NSString *defaultIcon_;
744 - (Source *) initWithMetaIndex:(metaIndex *)index;
749 - (NSString *) distribution;
752 - (NSString *) description;
753 - (NSString *) label;
754 - (NSString *) origin;
755 - (NSString *) version;
757 - (NSString *) defaultIcon;
760 @implementation Source
764 [distribution_ release];
767 if (description_ != nil)
768 [description_ release];
775 if (defaultIcon_ != nil)
776 [defaultIcon_ release];
781 - (Source *) initWithMetaIndex:(metaIndex *)index {
782 if ((self = [super init]) != nil) {
783 trusted_ = index->IsTrusted();
785 uri_ = [[NSString stringWithUTF8String:index->GetURI().c_str()] retain];
786 distribution_ = [[NSString stringWithUTF8String:index->GetDist().c_str()] retain];
787 type_ = [[NSString stringWithUTF8String:index->GetType()] retain];
795 debReleaseIndex *dindex(dynamic_cast<debReleaseIndex *>(index));
796 if (dindex != NULL) {
797 std::ifstream release(dindex->MetaIndexFile("Release").c_str());
799 while (std::getline(release, line)) {
800 std::string::size_type colon(line.find(':'));
801 if (colon == std::string::npos)
804 std::string name(line.substr(0, colon));
805 std::string value(line.substr(colon + 1));
806 while (!value.empty() && value[0] == ' ')
807 value = value.substr(1);
809 if (name == "Default-Icon")
810 defaultIcon_ = [[NSString stringWithUTF8String:value.c_str()] retain];
811 else if (name == "Description")
812 description_ = [[NSString stringWithUTF8String:value.c_str()] retain];
813 else if (name == "Label")
814 label_ = [[NSString stringWithUTF8String:value.c_str()] retain];
815 else if (name == "Origin")
816 origin_ = [[NSString stringWithUTF8String:value.c_str()] retain];
817 else if (name == "Version")
818 version_ = [[NSString stringWithUTF8String:value.c_str()] retain];
832 - (NSString *) distribution {
833 return distribution_;
836 - (NSString *) type {
840 - (NSString *) description {
844 - (NSString *) label {
848 - (NSString *) origin {
852 - (NSString *) version {
856 - (NSString *) defaultIcon {
862 /* Relationship Class {{{ */
863 @interface Relationship : NSObject {
874 @implementation Relationship
882 - (NSString *) type {
890 - (NSString *) name {
897 /* Package Class {{{ */
898 NSString *Scour(const char *field, const char *begin, const char *end) {
899 size_t i(0), l(strlen(field));
902 const char *name = begin + i;
903 const char *colon = name + l;
904 const char *value = colon + 1;
909 memcmp(name, field, l) == 0
911 while (value != end && value[0] == ' ')
913 const char *line = std::find(value, end, '\n');
914 while (line != value && line[-1] == ' ')
917 return [NSString stringWithUTF8Bytes:value length:(line - value)];
919 begin = std::find(begin, end, '\n');
927 @interface Package : NSObject {
928 pkgCache::PkgIterator iterator_;
929 _transient Database *database_;
930 pkgCache::VerIterator version_;
931 pkgCache::VerFileIterator file_;
937 NSString *installed_;
948 NSArray *relationships_;
951 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
952 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
954 - (pkgCache::PkgIterator) iterator;
956 - (NSString *) section;
957 - (Address *) maintainer;
959 - (NSString *) description;
960 - (NSString *) index;
964 - (NSString *) latest;
965 - (NSString *) installed;
968 - (BOOL) upgradableAndEssential:(BOOL)essential;
974 - (BOOL) halfConfigured;
975 - (BOOL) halfInstalled;
981 - (NSString *) tagline;
983 - (NSString *) website;
984 - (Address *) author;
986 - (NSArray *) relationships;
990 - (BOOL) matches:(NSString *)text;
992 - (bool) hasUsefulPurpose;
993 - (BOOL) hasTag:(NSString *)tag;
995 - (NSComparisonResult) compareByName:(Package *)package;
996 - (NSComparisonResult) compareBySection:(Package *)package;
997 - (NSComparisonResult) compareBySectionAndName:(Package *)package;
998 - (NSComparisonResult) compareForChanges:(Package *)package;
1003 - (NSNumber *) isSearchedForBy:(NSString *)search;
1004 - (NSNumber *) isInstalledInSection:(NSString *)section;
1005 - (NSNumber *) isUninstalledInSection:(NSString *)section;
1009 @implementation Package
1016 if (installed_ != nil)
1017 [installed_ release];
1025 if (website_ != nil)
1027 if (sponsor_ != nil)
1034 if (relationships_ != nil)
1035 [relationships_ release];
1040 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
1041 if ((self = [super init]) != nil) {
1042 iterator_ = iterator;
1043 database_ = database;
1045 version_ = [database_ policy]->GetCandidateVer(iterator_);
1046 latest_ = version_.end() ? nil : [StripVersion([NSString stringWithUTF8String:version_.VerStr()]) retain];
1048 if (!version_.end())
1049 file_ = version_.FileList();
1051 pkgCache &cache([database_ cache]);
1052 file_ = pkgCache::VerFileIterator(cache, cache.VerFileP);
1055 pkgCache::VerIterator current = iterator_.CurrentVer();
1056 installed_ = current.end() ? nil : [StripVersion([NSString stringWithUTF8String:current.VerStr()]) retain];
1058 id_ = [[[NSString stringWithUTF8String:iterator_.Name()] lowercaseString] retain];
1061 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1063 const char *begin, *end;
1064 parser->GetRec(begin, end);
1066 name_ = Scour("Name", begin, end);
1068 name_ = [name_ retain];
1069 tagline_ = [[NSString stringWithUTF8String:parser->ShortDesc().c_str()] retain];
1070 icon_ = Scour("Icon", begin, end);
1072 icon_ = [icon_ retain];
1073 website_ = Scour("Homepage", begin, end);
1074 if (website_ == nil)
1075 website_ = Scour("Website", begin, end);
1076 if (website_ != nil)
1077 website_ = [website_ retain];
1078 NSString *sponsor = Scour("Sponsor", begin, end);
1080 sponsor_ = [[Address addressWithString:sponsor] retain];
1081 NSString *author = Scour("Author", begin, end);
1083 author_ = [[Address addressWithString:author] retain];
1084 NSString *tags = Scour("Tag", begin, end);
1086 tags_ = [[tags componentsSeparatedByString:@", "] retain];
1089 NSMutableDictionary *metadata = [Packages_ objectForKey:id_];
1090 if (metadata == nil || [metadata count] == 0) {
1091 metadata = [NSMutableDictionary dictionaryWithObjectsAndKeys:
1095 [Packages_ setObject:metadata forKey:id_];
1101 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
1102 return [[[Package alloc]
1103 initWithIterator:iterator
1108 - (pkgCache::PkgIterator) iterator {
1112 - (NSString *) section {
1113 const char *section = iterator_.Section();
1114 return section == NULL ? nil : [[NSString stringWithUTF8String:section] stringByReplacingCharacter:'_' withCharacter:' '];
1117 - (Address *) maintainer {
1120 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1121 return [Address addressWithString:[NSString stringWithUTF8String:parser->Maintainer().c_str()]];
1125 return version_.end() ? 0 : version_->InstalledSize;
1128 - (NSString *) description {
1131 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1132 NSString *description([NSString stringWithUTF8String:parser->LongDesc().c_str()]);
1134 NSArray *lines = [description componentsSeparatedByString:@"\n"];
1135 NSMutableArray *trimmed = [NSMutableArray arrayWithCapacity:([lines count] - 1)];
1136 if ([lines count] < 2)
1139 NSCharacterSet *whitespace = [NSCharacterSet whitespaceCharacterSet];
1140 for (size_t i(1); i != [lines count]; ++i) {
1141 NSString *trim = [[lines objectAtIndex:i] stringByTrimmingCharactersInSet:whitespace];
1142 [trimmed addObject:trim];
1145 return [trimmed componentsJoinedByString:@"\n"];
1148 - (NSString *) index {
1149 NSString *index = [[[self name] substringToIndex:1] uppercaseString];
1150 return [index length] != 0 && isalpha([index characterAtIndex:0]) ? index : @"123";
1154 return [[Packages_ objectForKey:id_] objectForKey:@"FirstSeen"];
1157 - (NSString *) latest {
1161 - (NSString *) installed {
1166 return !version_.end();
1169 - (BOOL) upgradableAndEssential:(BOOL)essential {
1170 pkgCache::VerIterator current = iterator_.CurrentVer();
1173 return essential && [self essential];
1175 pkgCache::VerIterator candidate = [database_ policy]->GetCandidateVer(iterator_);
1176 return !candidate.end() && candidate != current;
1180 - (BOOL) essential {
1181 return (iterator_->Flags & pkgCache::Flag::Essential) == 0 ? NO : YES;
1185 return [database_ cache][iterator_].InstBroken();
1189 NSString *section = [self section];
1190 return [self hasUsefulPurpose] && (section == nil || isSectionVisible(section));
1194 unsigned char current = iterator_->CurrentState;
1195 return current == pkgCache::State::HalfConfigured || current == pkgCache::State::HalfInstalled;
1198 - (BOOL) halfConfigured {
1199 return iterator_->CurrentState == pkgCache::State::HalfConfigured;
1202 - (BOOL) halfInstalled {
1203 return iterator_->CurrentState == pkgCache::State::HalfInstalled;
1207 pkgDepCache::StateCache &state([database_ cache][iterator_]);
1208 return state.Mode != pkgDepCache::ModeKeep;
1211 - (NSString *) mode {
1212 pkgDepCache::StateCache &state([database_ cache][iterator_]);
1214 switch (state.Mode) {
1215 case pkgDepCache::ModeDelete:
1216 if ((state.iFlags & pkgDepCache::Purge) != 0)
1221 case pkgDepCache::ModeKeep:
1222 if ((state.iFlags & pkgDepCache::AutoKept) != 0)
1227 case pkgDepCache::ModeInstall:
1228 if ((state.iFlags & pkgDepCache::ReInstall) != 0)
1229 return @"Reinstall";
1230 else switch (state.Status) {
1232 return @"Downgrade";
1238 return @"New Install";
1251 - (NSString *) name {
1252 return name_ == nil ? id_ : name_;
1255 - (NSString *) tagline {
1259 - (NSString *) icon {
1263 - (NSString *) website {
1267 - (Address *) sponsor {
1271 - (Address *) author {
1275 - (NSArray *) relationships {
1276 return relationships_;
1279 - (Source *) source {
1281 source_ = file_.end() ? nil : [[database_ getSource:file_.File()] retain];
1288 - (BOOL) matches:(NSString *)text {
1294 range = [[self id] rangeOfString:text options:NSCaseInsensitiveSearch];
1295 if (range.location != NSNotFound)
1298 range = [[self name] rangeOfString:text options:NSCaseInsensitiveSearch];
1299 if (range.location != NSNotFound)
1302 range = [[self tagline] rangeOfString:text options:NSCaseInsensitiveSearch];
1303 if (range.location != NSNotFound)
1309 - (bool) hasUsefulPurpose {
1312 bool purpose(false);
1314 for (int i(0), e([tags_ count]); i != e; ++i) {
1315 NSString *tag = [tags_ objectAtIndex:i];
1316 if ([tag hasPrefix:@"purpose::"]) {
1317 bool purpose(false);
1318 if ([tag isEqualToString:@"purpose::console"]) {
1320 } else if ([tag isEqualToString:@"purpose::library"]) {
1322 } else if ([tag isEqualToString:@"purpose::x"]) {
1332 - (BOOL) hasTag:(NSString *)tag {
1333 return tags_ == nil ? NO : [tags_ containsObject:tag];
1336 - (NSComparisonResult) compareByName:(Package *)package {
1337 NSString *lhs = [self name];
1338 NSString *rhs = [package name];
1340 if ([lhs length] != 0 && [rhs length] != 0) {
1341 unichar lhc = [lhs characterAtIndex:0];
1342 unichar rhc = [rhs characterAtIndex:0];
1344 if (isalpha(lhc) && !isalpha(rhc))
1345 return NSOrderedAscending;
1346 else if (!isalpha(lhc) && isalpha(rhc))
1347 return NSOrderedDescending;
1350 return [lhs caseInsensitiveCompare:rhs];
1353 - (NSComparisonResult) compareBySection:(Package *)package {
1354 NSString *lhs = [self section];
1355 NSString *rhs = [package section];
1357 if (lhs == NULL && rhs != NULL)
1358 return NSOrderedAscending;
1359 else if (lhs != NULL && rhs == NULL)
1360 return NSOrderedDescending;
1361 else if (lhs != NULL && rhs != NULL) {
1362 NSComparisonResult result = [lhs caseInsensitiveCompare:rhs];
1363 if (result != NSOrderedSame)
1367 return NSOrderedSame;
1370 - (NSComparisonResult) compareBySectionAndName:(Package *)package {
1371 NSString *lhs = [self section];
1372 NSString *rhs = [package section];
1374 if (lhs == NULL && rhs != NULL)
1375 return NSOrderedAscending;
1376 else if (lhs != NULL && rhs == NULL)
1377 return NSOrderedDescending;
1378 else if (lhs != NULL && rhs != NULL) {
1379 NSComparisonResult result = [lhs compare:rhs];
1380 if (result != NSOrderedSame)
1384 return [self compareByName:package];
1387 - (NSComparisonResult) compareForChanges:(Package *)package {
1388 BOOL lhs = [self upgradableAndEssential:YES];
1389 BOOL rhs = [package upgradableAndEssential:YES];
1392 return lhs ? NSOrderedAscending : NSOrderedDescending;
1394 switch ([[self seen] compare:[package seen]]) {
1395 case NSOrderedAscending:
1396 return NSOrderedDescending;
1399 case NSOrderedDescending:
1400 return NSOrderedAscending;
1406 return [self compareByName:package];
1410 pkgProblemResolver *resolver = [database_ resolver];
1411 resolver->Clear(iterator_);
1412 resolver->Protect(iterator_);
1413 pkgCacheFile &cache([database_ cache]);
1414 cache->MarkInstall(iterator_, false);
1415 pkgDepCache::StateCache &state((*cache)[iterator_]);
1416 if (!state.Install())
1417 cache->SetReInstall(iterator_, true);
1421 pkgProblemResolver *resolver = [database_ resolver];
1422 resolver->Clear(iterator_);
1423 resolver->Protect(iterator_);
1424 resolver->Remove(iterator_);
1425 [database_ cache]->MarkDelete(iterator_, true);
1428 - (NSNumber *) isSearchedForBy:(NSString *)search {
1429 return [NSNumber numberWithBool:([self valid] && [self matches:search])];
1432 - (NSNumber *) isInstalledInSection:(NSString *)section {
1433 return [NSNumber numberWithBool:([self installed] != nil && (section == nil || [section isEqualToString:[self section]]))];
1436 - (NSNumber *) isUninstalledInSection:(NSString *)name {
1437 NSString *section = [self section];
1439 return [NSNumber numberWithBool:([self valid] && [self installed] == nil && (
1440 (name == nil && [self visible] ||
1441 section == nil && [name length] == 0 ||
1442 [name isEqualToString:section])
1448 /* Section Class {{{ */
1449 @interface Section : NSObject {
1455 - (NSComparisonResult) compareByName:(Section *)section;
1456 - (Section *) initWithName:(NSString *)name;
1457 - (Section *) initWithName:(NSString *)name row:(size_t)row;
1458 - (NSString *) name;
1461 - (void) addToCount;
1465 @implementation Section
1472 - (NSComparisonResult) compareByName:(Section *)section {
1473 NSString *lhs = [self name];
1474 NSString *rhs = [section name];
1476 if ([lhs length] != 0 && [rhs length] != 0) {
1477 unichar lhc = [lhs characterAtIndex:0];
1478 unichar rhc = [rhs characterAtIndex:0];
1480 if (isalpha(lhc) && !isalpha(rhc))
1481 return NSOrderedAscending;
1482 else if (!isalpha(lhc) && isalpha(rhc))
1483 return NSOrderedDescending;
1486 return [lhs caseInsensitiveCompare:rhs];
1489 - (Section *) initWithName:(NSString *)name {
1490 return [self initWithName:name row:0];
1493 - (Section *) initWithName:(NSString *)name row:(size_t)row {
1494 if ((self = [super init]) != nil) {
1495 name_ = [name retain];
1500 - (NSString *) name {
1512 - (void) addToCount {
1519 /* Database Implementation {{{ */
1520 @implementation Database
1527 - (void) _readCydia:(NSNumber *)fd {
1528 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1530 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1531 std::istream is(&ib);
1534 while (std::getline(is, line)) {
1535 const char *data(line.c_str());
1536 //size_t size = line.size();
1537 fprintf(stderr, "C:%s\n", data);
1544 - (void) _readStatus:(NSNumber *)fd {
1545 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1547 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1548 std::istream is(&ib);
1551 Pcre conffile_r("^status: [^ ]* : conffile-prompt : (.*?) *$");
1552 Pcre pmstatus_r("^([^:]*):([^:]*):([^:]*):(.*)$");
1554 while (std::getline(is, line)) {
1555 const char *data(line.c_str());
1556 size_t size = line.size();
1557 fprintf(stderr, "S:%s\n", data);
1559 if (conffile_r(data, size)) {
1560 [delegate_ setConfigurationData:conffile_r[1]];
1561 } else if (strncmp(data, "status: ", 8) == 0) {
1562 NSString *string = [NSString stringWithUTF8String:(data + 8)];
1563 [delegate_ setProgressTitle:string];
1564 } else if (pmstatus_r(data, size)) {
1565 std::string type([pmstatus_r[1] UTF8String]);
1566 NSString *id = pmstatus_r[2];
1568 float percent([pmstatus_r[3] floatValue]);
1569 [delegate_ setProgressPercent:(percent / 100)];
1571 NSString *string = pmstatus_r[4];
1573 if (type == "pmerror")
1574 [delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
1575 withObject:[NSArray arrayWithObjects:string, id, nil]
1578 else if (type == "pmstatus")
1579 [delegate_ setProgressTitle:string];
1580 else if (type == "pmconffile")
1581 [delegate_ setConfigurationData:string];
1582 else _assert(false);
1583 } else _assert(false);
1590 - (void) _readOutput:(NSNumber *)fd {
1591 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1593 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1594 std::istream is(&ib);
1597 while (std::getline(is, line)) {
1598 fprintf(stderr, "O:%s\n", line.c_str());
1599 [delegate_ addProgressOutput:[NSString stringWithUTF8String:line.c_str()]];
1610 - (Package *) packageWithName:(NSString *)name {
1611 if (static_cast<pkgDepCache *>(cache_) == NULL)
1613 pkgCache::PkgIterator iterator(cache_->FindPkg([name UTF8String]));
1614 return iterator.end() ? nil : [Package packageWithIterator:iterator database:self];
1617 - (Database *) init {
1618 if ((self = [super init]) != nil) {
1625 sources_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1626 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
1630 _assert(pipe(fds) != -1);
1633 _config->Set("APT::Keep-Fds::", cydiafd_);
1634 setenv("CYDIA", [[[[NSNumber numberWithInt:cydiafd_] stringValue] stringByAppendingString:@" 0"] UTF8String], _not(int));
1637 detachNewThreadSelector:@selector(_readCydia:)
1639 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1642 _assert(pipe(fds) != -1);
1646 detachNewThreadSelector:@selector(_readStatus:)
1648 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1651 _assert(pipe(fds) != -1);
1652 _assert(dup2(fds[0], 0) != -1);
1653 _assert(close(fds[0]) != -1);
1655 input_ = fdopen(fds[1], "a");
1657 _assert(pipe(fds) != -1);
1658 _assert(dup2(fds[1], 1) != -1);
1659 _assert(close(fds[1]) != -1);
1662 detachNewThreadSelector:@selector(_readOutput:)
1664 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1669 - (pkgCacheFile &) cache {
1673 - (pkgDepCache::Policy *) policy {
1677 - (pkgRecords *) records {
1681 - (pkgProblemResolver *) resolver {
1685 - (pkgAcquire &) fetcher {
1689 - (NSArray *) packages {
1693 - (void) reloadData {
1712 if (!cache_.Open(progress_, true)) {
1714 if (!_error->PopMessage(error))
1717 fprintf(stderr, "cache_.Open():[%s]\n", error.c_str());
1719 if (error == "dpkg was interrupted, you must manually run 'dpkg --configure -a' to correct the problem. ")
1720 [delegate_ repairWithSelector:@selector(configure)];
1721 else if (error == "The package lists or status file could not be parsed or opened.")
1722 [delegate_ repairWithSelector:@selector(update)];
1723 // else if (error == "Could not open lock file /var/lib/dpkg/lock - open (13 Permission denied)")
1724 // else if (error == "Could not get lock /var/lib/dpkg/lock - open (35 Resource temporarily unavailable)")
1725 // else if (error == "The list of sources could not be read.")
1726 else _assert(false);
1731 now_ = [[NSDate date] retain];
1733 policy_ = new pkgDepCache::Policy();
1734 records_ = new pkgRecords(cache_);
1735 resolver_ = new pkgProblemResolver(cache_);
1736 fetcher_ = new pkgAcquire(&status_);
1739 list_ = new pkgSourceList();
1740 _assert(list_->ReadMainList());
1742 _assert(cache_->DelCount() == 0 && cache_->InstCount() == 0);
1743 _assert(pkgApplyStatus(cache_));
1745 if (cache_->BrokenCount() != 0) {
1746 _assert(pkgFixBroken(cache_));
1747 _assert(cache_->BrokenCount() == 0);
1748 _assert(pkgMinimizeUpgrade(cache_));
1751 [sources_ removeAllObjects];
1752 for (pkgSourceList::const_iterator source = list_->begin(); source != list_->end(); ++source) {
1753 std::vector<pkgIndexFile *> *indices = (*source)->GetIndexFiles();
1754 for (std::vector<pkgIndexFile *>::const_iterator index = indices->begin(); index != indices->end(); ++index)
1756 setObject:[[[Source alloc] initWithMetaIndex:*source] autorelease]
1757 forKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(*index)]
1761 [packages_ removeAllObjects];
1762 for (pkgCache::PkgIterator iterator = cache_->PkgBegin(); !iterator.end(); ++iterator)
1763 if (Package *package = [Package packageWithIterator:iterator database:self])
1764 [packages_ addObject:package];
1766 [packages_ sortUsingSelector:@selector(compareByName:)];
1769 - (void) configure {
1770 NSString *dpkg = [NSString stringWithFormat:@"dpkg --configure -a --status-fd %u", statusfd_];
1771 system([dpkg UTF8String]);
1779 Lock.Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1780 _assert(!_error->PendingError());
1783 fetcher.Clean(_config->FindDir("Dir::Cache::Archives"));
1786 public pkgArchiveCleaner
1789 virtual void Erase(const char *File, std::string Pkg, std::string Ver, struct stat &St) {
1794 if (!cleaner.Go(_config->FindDir("Dir::Cache::Archives") + "partial/", cache_)) {
1796 while (_error->PopMessage(error))
1797 fprintf(stderr, "ArchiveCleaner: %s\n", error.c_str());
1802 pkgRecords records(cache_);
1804 lock_ = new FileFd();
1805 lock_->Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1806 _assert(!_error->PendingError());
1809 // XXX: explain this with an error message
1810 _assert(list.ReadMainList());
1812 manager_ = (_system->CreatePM(cache_));
1813 _assert(manager_->GetArchives(fetcher_, &list, &records));
1814 _assert(!_error->PendingError());
1818 NSMutableArray *before = [NSMutableArray arrayWithCapacity:16]; {
1820 _assert(list.ReadMainList());
1821 for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source)
1822 [before addObject:[NSString stringWithUTF8String:(*source)->GetURI().c_str()]];
1825 if (fetcher_->Run(PulseInterval_) != pkgAcquire::Continue) {
1830 bool failed = false;
1831 for (pkgAcquire::ItemIterator item = fetcher_->ItemsBegin(); item != fetcher_->ItemsEnd(); item++) {
1832 if ((*item)->Status == pkgAcquire::Item::StatDone && (*item)->Complete)
1835 std::string uri = (*item)->DescURI();
1836 std::string error = (*item)->ErrorText;
1838 fprintf(stderr, "pAf:%s:%s\n", uri.c_str(), error.c_str());
1841 [delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
1842 withObject:[NSArray arrayWithObjects:[NSString stringWithUTF8String:error.c_str()], nil]
1853 pkgPackageManager::OrderResult result = manager_->DoInstall(statusfd_);
1855 if (_error->PendingError()) {
1860 if (result == pkgPackageManager::Failed) {
1865 if (result != pkgPackageManager::Completed) {
1870 NSMutableArray *after = [NSMutableArray arrayWithCapacity:16]; {
1872 _assert(list.ReadMainList());
1873 for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source)
1874 [after addObject:[NSString stringWithUTF8String:(*source)->GetURI().c_str()]];
1877 if (![before isEqualToArray:after])
1882 _assert(pkgDistUpgrade(cache_));
1886 [self updateWithStatus:status_];
1889 - (void) updateWithStatus:(Status &)status {
1891 _assert(list.ReadMainList());
1894 lock.Fd(GetLock(_config->FindDir("Dir::State::Lists") + "lock"));
1895 _assert(!_error->PendingError());
1897 pkgAcquire fetcher(&status);
1898 _assert(list.GetIndexes(&fetcher));
1900 if (fetcher.Run(PulseInterval_) != pkgAcquire::Failed) {
1901 bool failed = false;
1902 for (pkgAcquire::ItemIterator item = fetcher.ItemsBegin(); item != fetcher.ItemsEnd(); item++)
1903 if ((*item)->Status != pkgAcquire::Item::StatDone) {
1904 (*item)->Finished();
1908 if (!failed && _config->FindB("APT::Get::List-Cleanup", true) == true) {
1909 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists")));
1910 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/"));
1913 [Metadata_ setObject:[NSDate date] forKey:@"LastUpdate"];
1918 - (void) setDelegate:(id)delegate {
1919 delegate_ = delegate;
1920 status_.setDelegate(delegate);
1921 progress_.setDelegate(delegate);
1924 - (Source *) getSource:(const pkgCache::PkgFileIterator &)file {
1925 pkgIndexFile *index(NULL);
1926 list_->FindIndex(file, index);
1927 return [sources_ objectForKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(index)]];
1933 /* Confirmation View {{{ */
1934 void AddTextView(NSMutableDictionary *fields, NSMutableArray *packages, NSString *key) {
1935 if ([packages count] == 0)
1938 UITextView *text = GetTextView([packages count] == 0 ? @"n/a" : [packages componentsJoinedByString:@", "], 120, false);
1939 [fields setObject:text forKey:key];
1941 CGColor blue(space_, 0, 0, 0.4, 1);
1942 [text setTextColor:blue];
1945 @protocol ConfirmationViewDelegate
1950 @interface ConfirmationView : UIView {
1951 Database *database_;
1953 UITransitionView *transition_;
1955 UINavigationBar *navbar_;
1956 UIPreferencesTable *table_;
1957 NSMutableDictionary *fields_;
1958 UIAlertSheet *essential_;
1963 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate;
1967 @implementation ConfirmationView
1970 [navbar_ setDelegate:nil];
1971 [transition_ setDelegate:nil];
1972 [table_ setDataSource:nil];
1974 [transition_ release];
1979 if (essential_ != nil)
1980 [essential_ release];
1985 [transition_ transition:7 toView:nil];
1989 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
1990 if (from != nil && to == nil)
1991 [self removeFromSuperview];
1994 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
1997 if (essential_ != nil)
1998 [essential_ popupAlertAnimated:YES];
2000 [delegate_ confirm];
2009 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
2010 NSString *context = [sheet context];
2012 if ([context isEqualToString:@"remove"])
2018 [delegate_ confirm];
2023 else if ([context isEqualToString:@"unable"])
2029 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
2033 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
2035 case 0: return @"Statistics";
2036 case 1: return @"Modifications";
2038 default: _assert(false);
2042 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
2045 case 1: return [fields_ count];
2047 default: _assert(false);
2051 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
2052 if (group != 1 || row == -1)
2055 _assert(size_t(row) < [fields_ count]);
2056 return [[[fields_ allValues] objectAtIndex:row] visibleTextRect].size.height + TextViewOffset_;
2060 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
2061 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
2062 [cell setShowSelection:NO];
2065 case 0: switch (row) {
2067 [cell setTitle:@"Downloading"];
2068 [cell setValue:SizeString([database_ fetcher].FetchNeeded())];
2072 [cell setTitle:@"Resuming At"];
2073 [cell setValue:SizeString([database_ fetcher].PartialPresent())];
2077 double size([database_ cache]->UsrSize());
2080 [cell setTitle:@"Disk Freeing"];
2081 [cell setValue:SizeString(-size)];
2083 [cell setTitle:@"Disk Using"];
2084 [cell setValue:SizeString(size)];
2088 default: _assert(false);
2092 _assert(size_t(row) < [fields_ count]);
2093 [cell setTitle:[[fields_ allKeys] objectAtIndex:row]];
2094 [cell addSubview:[[fields_ allValues] objectAtIndex:row]];
2097 default: _assert(false);
2103 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate {
2104 if ((self = [super initWithFrame:[view bounds]]) != nil) {
2105 database_ = database;
2106 delegate_ = delegate;
2108 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
2109 [self addSubview:transition_];
2111 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
2113 CGSize navsize = [UINavigationBar defaultSize];
2114 CGRect navrect = {{0, 0}, navsize};
2115 CGRect bounds = [overlay_ bounds];
2117 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
2119 [navbar_ setBarStyle:1];
2120 [navbar_ setDelegate:self];
2122 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Confirm"] autorelease];
2123 [navbar_ pushNavigationItem:navitem];
2124 [navbar_ showButtonsWithLeftTitle:@"Cancel" rightTitle:@"Confirm"];
2126 fields_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
2128 NSMutableArray *installing = [NSMutableArray arrayWithCapacity:16];
2129 NSMutableArray *reinstalling = [NSMutableArray arrayWithCapacity:16];
2130 NSMutableArray *upgrading = [NSMutableArray arrayWithCapacity:16];
2131 NSMutableArray *downgrading = [NSMutableArray arrayWithCapacity:16];
2132 NSMutableArray *removing = [NSMutableArray arrayWithCapacity:16];
2136 pkgCacheFile &cache([database_ cache]);
2137 NSArray *packages = [database_ packages];
2138 for (size_t i(0), e = [packages count]; i != e; ++i) {
2139 Package *package = [packages objectAtIndex:i];
2140 pkgCache::PkgIterator iterator = [package iterator];
2141 pkgDepCache::StateCache &state(cache[iterator]);
2143 NSString *name([package name]);
2145 if (state.NewInstall())
2146 [installing addObject:name];
2147 else if (!state.Delete() && (state.iFlags & pkgDepCache::ReInstall) == pkgDepCache::ReInstall)
2148 [reinstalling addObject:name];
2149 else if (state.Upgrade())
2150 [upgrading addObject:name];
2151 else if (state.Downgrade())
2152 [downgrading addObject:name];
2153 else if (state.Delete()) {
2154 if ([package essential])
2156 [removing addObject:name];
2162 else if (Advanced_ || true) {
2163 essential_ = [[UIAlertSheet alloc]
2164 initWithTitle:@"Removing Essentials"
2165 buttons:[NSArray arrayWithObjects:
2166 @"Cancel Operation (Safe)",
2167 @"Force Removal (Unsafe)",
2169 defaultButtonIndex:0
2175 [essential_ setDestructiveButton:[[essential_ buttons] objectAtIndex:0]];
2177 [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."];
2179 essential_ = [[UIAlertSheet alloc]
2180 initWithTitle:@"Unable to Comply"
2181 buttons:[NSArray arrayWithObjects:@"Okay", nil]
2182 defaultButtonIndex:0
2187 [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."];
2190 AddTextView(fields_, installing, @"Installing");
2191 AddTextView(fields_, reinstalling, @"Reinstalling");
2192 AddTextView(fields_, upgrading, @"Upgrading");
2193 AddTextView(fields_, downgrading, @"Downgrading");
2194 AddTextView(fields_, removing, @"Removing");
2196 table_ = [[UIPreferencesTable alloc] initWithFrame:CGRectMake(
2197 0, navsize.height, bounds.size.width, bounds.size.height - navsize.height
2200 [table_ setReusesTableCells:YES];
2201 [table_ setDataSource:self];
2202 [table_ reloadData];
2204 [overlay_ addSubview:navbar_];
2205 [overlay_ addSubview:table_];
2207 [view addSubview:self];
2209 [transition_ setDelegate:self];
2211 UIView *blank = [[[UIView alloc] initWithFrame:[transition_ bounds]] autorelease];
2212 [transition_ transition:0 toView:blank];
2213 [transition_ transition:3 toView:overlay_];
2220 /* Progress Data {{{ */
2221 @interface ProgressData : NSObject {
2227 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object;
2234 @implementation ProgressData
2236 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object {
2237 if ((self = [super init]) != nil) {
2238 selector_ = selector;
2258 /* Progress View {{{ */
2259 Pcre conffile_r("^'(.*)' '(.*)' ([01]) ([01])$");
2261 @interface ProgressView : UIView <
2262 ConfigurationDelegate,
2265 _transient Database *database_;
2267 UIView *background_;
2268 UITransitionView *transition_;
2270 UINavigationBar *navbar_;
2271 UIProgressBar *progress_;
2272 UITextView *output_;
2273 UITextLabel *status_;
2274 UIPushButton *close_;
2279 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
2281 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database delegate:(id)delegate;
2282 - (void) setContentView:(UIView *)view;
2285 - (void) _retachThread;
2286 - (void) _detachNewThreadData:(ProgressData *)data;
2287 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title;
2293 @protocol ProgressViewDelegate
2294 - (void) progressViewIsComplete:(ProgressView *)sender;
2297 @implementation ProgressView
2300 [transition_ setDelegate:nil];
2301 [navbar_ setDelegate:nil];
2304 if (background_ != nil)
2305 [background_ release];
2306 [transition_ release];
2309 [progress_ release];
2316 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
2317 if (bootstrap_ && from == overlay_ && to == view_)
2321 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database delegate:(id)delegate {
2322 if ((self = [super initWithFrame:frame]) != nil) {
2323 database_ = database;
2324 delegate_ = delegate;
2326 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
2327 [transition_ setDelegate:self];
2329 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
2332 [overlay_ setBackgroundColor:Black_];
2334 background_ = [[UIView alloc] initWithFrame:[self bounds]];
2335 [background_ setBackgroundColor:Black_];
2336 [self addSubview:background_];
2339 [self addSubview:transition_];
2341 CGSize navsize = [UINavigationBar defaultSize];
2342 CGRect navrect = {{0, 0}, navsize};
2344 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
2345 [overlay_ addSubview:navbar_];
2347 [navbar_ setBarStyle:1];
2348 [navbar_ setDelegate:self];
2350 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:nil] autorelease];
2351 [navbar_ pushNavigationItem:navitem];
2353 CGRect bounds = [overlay_ bounds];
2354 CGSize prgsize = [UIProgressBar defaultSize];
2357 (bounds.size.width - prgsize.width) / 2,
2358 bounds.size.height - prgsize.height - 20
2361 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
2362 [progress_ setStyle:0];
2364 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(
2366 bounds.size.height - prgsize.height - 50,
2367 bounds.size.width - 20,
2371 [status_ setColor:White_];
2372 [status_ setBackgroundColor:Clear_];
2374 [status_ setCentersHorizontally:YES];
2375 //[status_ setFont:font];
2377 output_ = [[UITextView alloc] initWithFrame:CGRectMake(
2379 navrect.size.height + 20,
2380 bounds.size.width - 20,
2381 bounds.size.height - navsize.height - 62 - navrect.size.height
2384 //[output_ setTextFont:@"Courier New"];
2385 [output_ setTextSize:12];
2387 [output_ setTextColor:White_];
2388 [output_ setBackgroundColor:Clear_];
2390 [output_ setMarginTop:0];
2391 [output_ setAllowsRubberBanding:YES];
2392 [output_ setEditable:NO];
2394 [overlay_ addSubview:output_];
2396 close_ = [[UIPushButton alloc] initWithFrame:CGRectMake(
2398 bounds.size.height - prgsize.height - 50,
2399 bounds.size.width - 20,
2403 [close_ setAutosizesToFit:NO];
2404 [close_ setDrawsShadow:YES];
2405 [close_ setStretchBackground:YES];
2406 [close_ setTitle:@"Close Window"];
2407 [close_ setEnabled:YES];
2409 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22);
2410 [close_ setTitleFont:bold];
2413 [close_ addTarget:self action:@selector(closeButtonPushed) forEvents:kUIControlEventMouseUpInside];
2414 [close_ setBackground:[UIImage applicationImageNamed:@"green-up.png"] forState:0];
2415 [close_ setBackground:[UIImage applicationImageNamed:@"green-dn.png"] forState:1];
2419 - (void) setContentView:(UIView *)view {
2420 view_ = [view retain];
2423 - (void) resetView {
2424 [transition_ transition:6 toView:view_];
2427 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
2428 NSString *context = [sheet context];
2429 if ([context isEqualToString:@"conffile"]) {
2430 FILE *input = [database_ input];
2434 fprintf(input, "N\n");
2438 fprintf(input, "Y\n");
2449 - (void) closeButtonPushed {
2450 [delegate_ progressViewIsComplete:self];
2454 - (void) _retachThread {
2455 UINavigationItem *item = [navbar_ topItem];
2456 [item setTitle:@"Complete"];
2458 [overlay_ addSubview:close_];
2459 [progress_ removeFromSuperview];
2460 [status_ removeFromSuperview];
2463 notify_post("com.apple.mobile.application_installed");
2466 [delegate_ setStatusBarShowsProgress:NO];
2471 - (void) _detachNewThreadData:(ProgressData *)data {
2472 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
2474 [[data target] performSelector:[data selector] withObject:[data object]];
2477 [self performSelectorOnMainThread:@selector(_retachThread) withObject:nil waitUntilDone:YES];
2482 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title {
2483 UINavigationItem *item = [navbar_ topItem];
2484 [item setTitle:title];
2486 [status_ setText:nil];
2487 [output_ setText:@""];
2488 [progress_ setProgress:0];
2490 [close_ removeFromSuperview];
2491 [overlay_ addSubview:progress_];
2492 [overlay_ addSubview:status_];
2494 [delegate_ setStatusBarShowsProgress:YES];
2497 [transition_ transition:6 toView:overlay_];
2500 detachNewThreadSelector:@selector(_detachNewThreadData:)
2502 withObject:[[ProgressData alloc]
2503 initWithSelector:selector
2510 - (void) repairWithSelector:(SEL)selector {
2512 detachNewThreadSelector:selector
2515 title:@"Repairing..."
2519 - (void) setConfigurationData:(NSString *)data {
2521 performSelectorOnMainThread:@selector(_setConfigurationData:)
2527 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id {
2528 Package *package = id == nil ? nil : [database_ packageWithName:id];
2530 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
2531 initWithTitle:(package == nil ? @"Source Error" : [package name])
2532 buttons:[NSArray arrayWithObjects:@"Okay", nil]
2533 defaultButtonIndex:0
2538 [sheet setBodyText:error];
2539 [sheet popupAlertAnimated:YES];
2542 - (void) setProgressTitle:(NSString *)title {
2544 performSelectorOnMainThread:@selector(_setProgressTitle:)
2550 - (void) setProgressPercent:(float)percent {
2552 performSelectorOnMainThread:@selector(_setProgressPercent:)
2553 withObject:[NSNumber numberWithFloat:percent]
2558 - (void) addProgressOutput:(NSString *)output {
2560 performSelectorOnMainThread:@selector(_addProgressOutput:)
2566 - (void) _setConfigurationData:(NSString *)data {
2567 _assert(conffile_r(data));
2569 NSString *ofile = conffile_r[1];
2570 //NSString *nfile = conffile_r[2];
2572 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
2573 initWithTitle:@"Configuration Upgrade"
2574 buttons:[NSArray arrayWithObjects:
2575 @"Keep My Old Copy",
2576 @"Accept The New Copy",
2577 // XXX: @"See What Changed",
2579 defaultButtonIndex:0
2584 [sheet setBodyText:[NSString stringWithFormat:
2585 @"The following file has been changed by both the package maintainer and by you (or for you by a script).\n\n%@"
2588 [sheet popupAlertAnimated:YES];
2591 - (void) _setProgressTitle:(NSString *)title {
2592 [status_ setText:[title stringByAppendingString:@"..."]];
2595 - (void) _setProgressPercent:(NSNumber *)percent {
2596 [progress_ setProgress:[percent floatValue]];
2599 - (void) _addProgressOutput:(NSString *)output {
2600 [output_ setText:[NSString stringWithFormat:@"%@\n%@", [output_ text], output]];
2601 CGSize size = [output_ contentSize];
2602 CGRect rect = {{0, size.height}, {size.width, 0}};
2603 [output_ scrollRectToVisible:rect animated:YES];
2606 - (BOOL) isRunning {
2613 /* Package Cell {{{ */
2614 @interface PackageCell : UITableCell {
2617 UITextLabel *description_;
2618 UITextLabel *source_;
2619 //UIImageView *trusted_;
2621 UIImageView *badge_;
2622 UITextLabel *status_;
2627 - (PackageCell *) init;
2628 - (void) setPackage:(Package *)package;
2630 - (void) _setSelected:(float)fraction;
2631 - (void) setSelected:(BOOL)selected;
2632 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
2633 - (void) _setSelectionFadeFraction:(float)fraction;
2635 + (int) heightForPackage:(Package *)package;
2639 @implementation PackageCell
2644 [description_ release];
2650 //[trusted_ release];
2654 - (PackageCell *) init {
2655 if ((self = [super init]) != nil) {
2656 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 20);
2657 GSFontRef large = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 12);
2658 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 14);
2660 icon_ = [[UIImageView alloc] initWithFrame:CGRectMake(10, 10, 30, 30)];
2662 name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 8, 240, 25)];
2663 [name_ setBackgroundColor:Clear_];
2664 [name_ setFont:bold];
2666 source_ = [[UITextLabel alloc] initWithFrame:CGRectMake(58, 28, 225, 20)];
2667 [source_ setBackgroundColor:Clear_];
2668 [source_ setFont:large];
2670 description_ = [[UITextLabel alloc] initWithFrame:CGRectMake(12, 46, 280, 20)];
2671 [description_ setBackgroundColor:Clear_];
2672 [description_ setFont:small];
2674 /*trusted_ = [[UIImageView alloc] initWithFrame:CGRectMake(30, 30, 16, 16)];
2675 [trusted_ setImage:[UIImage applicationImageNamed:@"trusted.png"]];*/
2678 badge_ = [[UIImageView alloc] initWithFrame:CGRectMake(17, 70, 16, 16)];
2680 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 68, 280, 20)];
2681 [status_ setBackgroundColor:Clear_];
2682 [status_ setFont:small];
2685 /*[icon_ setImage:[UIImage applicationImageNamed:@"unknown.png"]];
2686 [icon_ zoomToScale:0.5];
2687 [icon_ setFrame:CGRectMake(10, 10, 30, 30)];*/
2689 [self addSubview:icon_];
2690 [self addSubview:name_];
2691 [self addSubview:description_];
2692 [self addSubview:source_];
2700 - (void) setPackage:(Package *)package {
2706 Source *source = [package source];
2708 UIImage *image = nil;
2709 if (NSString *icon = [package icon])
2710 image = [UIImage imageAtPath:[icon substringFromIndex:6]];
2711 if (image == nil) if (NSString *section = [package section])
2712 image = [UIImage applicationImageNamed:[Simplify(section) stringByAppendingString:@".png"]];
2713 /*if (image == nil) if (NSString *icon = [source defaultIcon])
2714 image = [UIImage imageAtPath:[icon substringFromIndex:6]];*/
2716 image = [UIImage applicationImageNamed:@"unknown.png"];
2717 [icon_ setImage:image];
2719 /*if (image != nil) {
2720 CGSize size = [image size];
2721 float scale = 30 / std::max(size.width, size.height);
2722 [icon_ zoomToScale:scale];
2725 [icon_ setFrame:CGRectMake(10, 10, 30, 30)];
2727 [name_ setText:[package name]];
2728 [description_ setText:[package tagline]];
2730 NSString *label = nil;
2731 bool trusted = false;
2733 if (source != nil) {
2734 label = [source label];
2735 trusted = [source trusted];
2736 } else if ([[package id] isEqualToString:@"firmware"])
2740 label = @"Unknown/Local";
2742 NSString *from = [NSString stringWithFormat:@"from %@", label];
2744 NSString *section = Simplify([package section]);
2745 if (section != nil && ![section isEqualToString:label])
2746 from = [from stringByAppendingString:[NSString stringWithFormat:@" (%@)", section]];
2748 [source_ setText:from];
2751 [badge_ removeFromSuperview];
2752 [status_ removeFromSuperview];
2754 if (NSString *mode = [package mode]) {
2755 [badge_ setImage:[UIImage applicationImageNamed:
2756 [mode isEqualToString:@"Remove"] || [mode isEqualToString:@"Purge"] ? @"removing.png" : @"installing.png"
2759 [status_ setText:[NSString stringWithFormat:@"Queued for %@", mode]];
2760 [status_ setColor:Blueish_];
2761 } else if ([package half]) {
2762 [badge_ setImage:[UIImage applicationImageNamed:@"damaged.png"]];
2763 [status_ setText:@"Package Damaged"];
2764 [status_ setColor:Red_];
2766 [badge_ setImage:nil];
2767 [status_ setText:nil];
2771 [self addSubview:badge_];
2772 [self addSubview:status_];
2777 - (void) _setSelected:(float)fraction {
2778 CGColor black(space_,
2779 Interpolate(0.0, 1.0, fraction),
2780 Interpolate(0.0, 1.0, fraction),
2781 Interpolate(0.0, 1.0, fraction),
2784 CGColor gray(space_,
2785 Interpolate(0.4, 1.0, fraction),
2786 Interpolate(0.4, 1.0, fraction),
2787 Interpolate(0.4, 1.0, fraction),
2790 [name_ setColor:black];
2791 [description_ setColor:gray];
2792 [source_ setColor:black];
2795 - (void) setSelected:(BOOL)selected {
2796 [self _setSelected:(selected ? 1.0 : 0.0)];
2797 [super setSelected:selected];
2800 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
2802 [self _setSelected:(selected ? 1.0 : 0.0)];
2803 [super setSelected:selected withFade:fade];
2806 - (void) _setSelectionFadeFraction:(float)fraction {
2807 [self _setSelected:fraction];
2808 [super _setSelectionFadeFraction:fraction];
2811 + (int) heightForPackage:(Package *)package {
2812 NSString *tagline([package tagline]);
2813 int height = tagline == nil || [tagline length] == 0 ? -15 : 0;
2815 if ([package hasMode] || [package half])
2824 /* Section Cell {{{ */
2825 @interface SectionCell : UITableCell {
2828 UITextLabel *count_;
2829 UISwitchControl *switch_;
2834 - (void) setSection:(Section *)section editing:(BOOL)editing;
2836 - (void) _setSelected:(float)fraction;
2837 - (void) setSelected:(BOOL)selected;
2838 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
2839 - (void) _setSelectionFadeFraction:(float)fraction;
2843 @implementation SectionCell
2846 if (section_ != nil)
2855 if ((self = [super init]) != nil) {
2856 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22);
2857 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 12);
2859 name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
2860 [name_ setBackgroundColor:Clear_];
2861 [name_ setFont:bold];
2863 count_ = [[UITextLabel alloc] initWithFrame:CGRectMake(11, 7, 29, 32)];
2864 [count_ setCentersHorizontally:YES];
2865 [count_ setBackgroundColor:Clear_];
2866 [count_ setFont:small];
2867 [count_ setColor:White_];
2869 UIImageView *folder = [[[UIImageView alloc] initWithFrame:CGRectMake(8, 7, 32, 32)] autorelease];
2870 [folder setImage:[UIImage applicationImageNamed:@"folder.png"]];
2872 switch_ = [[UISwitchControl alloc] initWithFrame:CGRectMake(218, 9, 60, 25)];
2873 [switch_ addTarget:self action:@selector(onSwitch:) forEvents:kUIControlEventMouseUpInside];
2875 [self addSubview:folder];
2876 [self addSubview:name_];
2877 [self addSubview:count_];
2879 [self _setSelected:0];
2886 - (void) onSwitch:(id)sender {
2887 NSMutableDictionary *metadata = [Sections_ objectForKey:section_];
2888 if (metadata == nil) {
2889 metadata = [NSMutableDictionary dictionaryWithCapacity:2];
2890 [Sections_ setObject:metadata forKey:section_];
2894 [metadata setObject:[NSNumber numberWithBool:([switch_ value] == 0)] forKey:@"Hidden"];
2897 - (void) setSection:(Section *)section editing:(BOOL)editing {
2898 if (editing != editing_) {
2900 [switch_ removeFromSuperview];
2902 [self addSubview:switch_];
2906 if (section_ != nil) {
2911 if (section == nil) {
2912 [name_ setText:@"All Packages"];
2913 [count_ setText:nil];
2915 section_ = [section name];
2916 if (section_ != nil)
2917 section_ = [section_ retain];
2918 [name_ setText:(section_ == nil ? @"(No Section)" : section_)];
2919 [count_ setText:[NSString stringWithFormat:@"%d", [section count]]];
2922 [switch_ setValue:isSectionVisible(section_) animated:NO];
2925 [name_ setFrame:CGRectMake(48, 9, editing_ ? 165 : 250, 25)];
2928 - (void) _setSelected:(float)fraction {
2929 CGColor black(space_,
2930 Interpolate(0.0, 1.0, fraction),
2931 Interpolate(0.0, 1.0, fraction),
2932 Interpolate(0.0, 1.0, fraction),
2935 [name_ setColor:black];
2938 - (void) setSelected:(BOOL)selected {
2939 [self _setSelected:(selected ? 1.0 : 0.0)];
2940 [super setSelected:selected];
2943 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
2945 [self _setSelected:(selected ? 1.0 : 0.0)];
2946 [super setSelected:selected withFade:fade];
2949 - (void) _setSelectionFadeFraction:(float)fraction {
2950 [self _setSelected:fraction];
2951 [super _setSelectionFadeFraction:fraction];
2957 /* File Table {{{ */
2958 @interface FileTable : RVPage {
2959 _transient Database *database_;
2962 NSMutableArray *files_;
2966 - (id) initWithBook:(RVBook *)book database:(Database *)database;
2967 - (void) setPackage:(Package *)package;
2971 @implementation FileTable
2974 if (package_ != nil)
2983 - (int) numberOfRowsInTable:(UITable *)table {
2984 return files_ == nil ? 0 : [files_ count];
2987 - (float) table:(UITable *)table heightForRow:(int)row {
2991 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2992 if (reusing == nil) {
2993 reusing = [[[UIImageAndTextTableCell alloc] init] autorelease];
2994 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
2995 [[(UIImageAndTextTableCell *)reusing titleTextLabel] setFont:font];
2998 [(UIImageAndTextTableCell *)reusing setTitle:[files_ objectAtIndex:row]];
3002 - (BOOL) table:(UITable *)table canSelectRow:(int)row {
3006 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3007 if ((self = [super initWithBook:book]) != nil) {
3008 database_ = database;
3010 files_ = [[NSMutableArray arrayWithCapacity:32] retain];
3012 list_ = [[UITable alloc] initWithFrame:[self bounds]];
3013 [self addSubview:list_];
3015 UITableColumn *column = [[[UITableColumn alloc]
3016 initWithTitle:@"Name"
3018 width:[self frame].size.width
3021 [list_ setDataSource:self];
3022 [list_ setSeparatorStyle:1];
3023 [list_ addTableColumn:column];
3024 [list_ setDelegate:self];
3025 [list_ setReusesTableCells:YES];
3029 - (void) setPackage:(Package *)package {
3030 if (package_ != nil) {
3031 [package_ autorelease];
3040 [files_ removeAllObjects];
3042 if (package != nil) {
3043 package_ = [package retain];
3044 name_ = [[package id] retain];
3046 NSString *path = [NSString stringWithFormat:@"/var/lib/dpkg/info/%@.list", name_];
3049 std::ifstream fin([path UTF8String]);
3051 while (std::getline(fin, line))
3052 [files_ addObject:[NSString stringWithUTF8String:line.c_str()]];
3055 if ([files_ count] != 0) {
3056 if ([[files_ objectAtIndex:0] isEqualToString:@"/."])
3057 [files_ removeObjectAtIndex:0];
3058 [files_ sortUsingSelector:@selector(compareByPath:)];
3060 NSMutableArray *stack = [NSMutableArray arrayWithCapacity:8];
3061 [stack addObject:@"/"];
3063 for (int i(0), e([files_ count]); i != e; ++i) {
3064 NSString *file = [files_ objectAtIndex:i];
3065 while (![file hasPrefix:[stack lastObject]])
3066 [stack removeLastObject];
3067 NSString *directory = [stack lastObject];
3068 [stack addObject:[file stringByAppendingString:@"/"]];
3069 [files_ replaceObjectAtIndex:i withObject:[NSString stringWithFormat:@"%*s%@",
3070 ([stack count] - 2) * 3, "",
3071 [file substringFromIndex:[directory length]]
3080 - (void) resetViewAnimated:(BOOL)animated {
3081 [list_ resetViewAnimated:animated];
3084 - (void) reloadData {
3085 [self setPackage:[database_ packageWithName:name_]];
3086 [self reloadButtons];
3089 - (NSString *) title {
3090 return @"Installed Files";
3093 - (NSString *) backButtonTitle {
3099 /* Package View {{{ */
3100 @protocol PackageViewDelegate
3101 - (void) performPackage:(Package *)package;
3104 @interface PackageView : RVPage {
3105 _transient Database *database_;
3106 UIPreferencesTable *table_;
3109 UITextView *description_;
3110 NSMutableArray *buttons_;
3113 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3114 - (void) setPackage:(Package *)package;
3118 @implementation PackageView
3121 [table_ setDataSource:nil];
3122 [table_ setDelegate:nil];
3124 if (package_ != nil)
3128 if (description_ != nil)
3129 [description_ release];
3135 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
3137 if ([package_ installed] != nil)
3139 if ([package_ source] != nil)
3144 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
3147 else if ([package_ installed] != nil && group-- == 0)
3148 return @"Installed Package";
3149 else if (group-- == 0)
3150 return @"Package Details";
3151 else if ([package_ source] != nil && group-- == 0)
3152 return @"Source Information";
3153 else _assert(false);
3156 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
3157 if (description_ == nil || group != 0 || row != ([package_ author] == nil ? 1 : 2))
3160 return [description_ visibleTextRect].size.height + TextViewOffset_;
3163 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
3166 if ([package_ author] != nil)
3168 if (description_ != nil)
3170 if ([package_ website] != nil)
3173 } else if ([package_ installed] != nil && group-- == 0)
3175 else if (group-- == 0) {
3177 if ([package_ size] != 0)
3179 if ([package_ maintainer] != nil)
3181 if ([package_ sponsor] != nil)
3183 if ([package_ relationships] != nil)
3185 if ([[package_ source] trusted])
3188 } else if ([package_ source] != nil && group-- == 0) {
3189 Source *source = [package_ source];
3190 NSString *description = [source description];
3192 if (description != nil && ![description isEqualToString:[source label]])
3194 if ([source origin] != nil)
3197 } else _assert(false);
3200 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
3201 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
3202 [cell setShowSelection:NO];
3206 } else if (row-- == 0) {
3207 [cell setTitle:[package_ name]];
3208 [cell setValue:[package_ latest]];
3209 } else if ([package_ author] != nil && row-- == 0) {
3210 [cell setTitle:@"Author"];
3211 [cell setValue:[[package_ author] name]];
3212 [cell setShowDisclosure:YES];
3213 [cell setShowSelection:YES];
3214 } else if (description_ != nil && row-- == 0) {
3215 [cell addSubview:description_];
3216 } else if ([package_ website] != nil && row-- == 0) {
3217 [cell setTitle:@"More Information"];
3218 [cell setShowDisclosure:YES];
3219 [cell setShowSelection:YES];
3220 } else _assert(false);
3221 } else if ([package_ installed] != nil && group-- == 0) {
3223 } else if (row-- == 0) {
3224 [cell setTitle:@"Version"];
3225 NSString *installed([package_ installed]);
3226 [cell setValue:(installed == nil ? @"n/a" : installed)];
3227 } else if (row-- == 0) {
3228 [cell setTitle:@"Filesystem Content"];
3229 [cell setShowDisclosure:YES];
3230 [cell setShowSelection:YES];
3231 } else _assert(false);
3232 } else if (group-- == 0) {
3234 } else if (row-- == 0) {
3235 [cell setTitle:@"Identifier"];
3236 [cell setValue:[package_ id]];
3237 } else if (row-- == 0) {
3238 [cell setTitle:@"Section"];
3239 NSString *section([package_ section]);
3240 [cell setValue:(section == nil ? @"n/a" : section)];
3241 } else if ([package_ size] != 0 && row-- == 0) {
3242 [cell setTitle:@"Expanded Size"];
3243 [cell setValue:SizeString([package_ size])];
3244 } else if ([package_ maintainer] != nil && row-- == 0) {
3245 [cell setTitle:@"Maintainer"];
3246 [cell setValue:[[package_ maintainer] name]];
3247 [cell setShowDisclosure:YES];
3248 [cell setShowSelection:YES];
3249 } else if ([package_ sponsor] != nil && row-- == 0) {
3250 [cell setTitle:@"Sponsor"];
3251 [cell setValue:[[package_ sponsor] name]];
3252 [cell setShowDisclosure:YES];
3253 [cell setShowSelection:YES];
3254 } else if ([package_ relationships] != nil && row-- == 0) {
3255 [cell setTitle:@"Package Relationships"];
3256 [cell setShowDisclosure:YES];
3257 [cell setShowSelection:YES];
3258 } else if ([[package_ source] trusted] && row-- == 0) {
3259 [cell setIcon:[UIImage applicationImageNamed:@"trusted.png"]];
3260 [cell setValue:@"This package has been signed."];
3261 } else _assert(false);
3262 } else if ([package_ source] != nil && group-- == 0) {
3263 Source *source = [package_ source];
3264 NSString *description = [source description];
3267 } else if (row-- == 0) {
3268 NSString *label = [source label];
3270 label = [source uri];
3271 [cell setTitle:label];
3272 [cell setValue:[source version]];
3273 } else if (description != nil && ![description isEqualToString:[source label]] && row-- == 0) {
3274 [cell setValue:description];
3275 } else if ([source origin] != nil && row-- == 0) {
3276 [cell setTitle:@"Origin"];
3277 [cell setValue:[source origin]];
3278 } else _assert(false);
3279 } else _assert(false);
3284 - (BOOL) canSelectRow:(int)row {
3288 - (void) tableRowSelected:(NSNotification *)notification {
3289 int row = [table_ selectedRow];
3293 #define _else else goto _label; return; } _label:
3297 } else if (row-- == 0) {
3298 } else if ([package_ author] != nil && row-- == 0) {
3299 [delegate_ openURL:[NSURL URLWithString:[NSString stringWithFormat:@"mailto:%@?subject=%@",
3300 [[package_ author] email],
3301 [[NSString stringWithFormat:@"regarding apt package \"%@\"",
3303 ] stringByAddingPercentEscapes]
3305 } else if (description_ != nil && row-- == 0) {
3306 } else if ([package_ website] != nil && row-- == 0) {
3307 NSURL *url = [NSURL URLWithString:[package_ website]];
3308 BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease];
3309 [browser setDelegate:delegate_];
3310 [book_ pushPage:browser];
3311 [browser loadURL:url];
3312 } _else if ([package_ installed] != nil) {
3314 } else if (row-- == 0) {
3315 } else if (row-- == 0) {
3316 FileTable *files = [[[FileTable alloc] initWithBook:book_ database:database_] autorelease];
3317 [files setDelegate:delegate_];
3318 [files setPackage:package_];
3319 [book_ pushPage:files];
3322 } else if (row-- == 0) {
3323 } else if (row-- == 0) {
3324 } else if ([package_ size] != 0 && row-- == 0) {
3325 } else if ([package_ maintainer] != nil && row-- == 0) {
3326 [delegate_ openURL:[NSURL URLWithString:[NSString stringWithFormat:@"mailto:%@?subject=%@",
3327 [[package_ maintainer] email],
3328 [[NSString stringWithFormat:@"regarding apt package \"%@\"",
3330 ] stringByAddingPercentEscapes]
3332 } else if ([package_ sponsor] != nil && row-- == 0) {
3333 NSURL *url = [NSURL URLWithString:[[package_ sponsor] email]];
3334 BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease];
3335 [browser setDelegate:delegate_];
3336 [book_ pushPage:browser];
3337 [browser loadURL:url];
3338 } else if ([package_ relationships] != nil && row-- == 0) {
3339 } else if ([[package_ source] trusted] && row-- == 0) {
3340 } _else if ([package_ source] != nil) {
3341 Source *source = [package_ source];
3342 NSString *description = [source description];
3345 } else if (row-- == 0) {
3346 } else if (description != nil && ![description isEqualToString:[source label]] && row-- == 0) {
3347 } else if ([source origin] != nil && row-- == 0) {
3348 } _else _assert(false);
3353 - (void) _clickButtonWithName:(NSString *)name {
3354 if ([name isEqualToString:@"Install"])
3355 [delegate_ installPackage:package_];
3356 else if ([name isEqualToString:@"Reinstall"])
3357 [delegate_ installPackage:package_];
3358 else if ([name isEqualToString:@"Remove"])
3359 [delegate_ removePackage:package_];
3360 else if ([name isEqualToString:@"Upgrade"])
3361 [delegate_ installPackage:package_];
3362 else _assert(false);
3365 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
3366 int count = [buttons_ count];
3367 _assert(count != 0);
3368 _assert(button <= count + 1);
3370 if (count != button - 1)
3371 [self _clickButtonWithName:[buttons_ objectAtIndex:(button - 1)]];
3376 - (void) _rightButtonClicked {
3377 int count = [buttons_ count];
3378 _assert(count != 0);
3381 [self _clickButtonWithName:[buttons_ objectAtIndex:0]];
3383 NSMutableArray *buttons = [NSMutableArray arrayWithCapacity:(count + 1)];
3384 [buttons addObjectsFromArray:buttons_];
3385 [buttons addObject:@"Cancel"];
3387 [delegate_ slideUp:[[[UIAlertSheet alloc]
3390 defaultButtonIndex:2
3397 - (NSString *) rightButtonTitle {
3398 int count = [buttons_ count];
3399 return count == 0 ? nil : count != 1 ? @"Modify" : [buttons_ objectAtIndex:0];
3402 - (NSString *) title {
3406 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3407 if ((self = [super initWithBook:book]) != nil) {
3408 database_ = database;
3410 table_ = [[UIPreferencesTable alloc] initWithFrame:[self bounds]];
3411 [self addSubview:table_];
3413 [table_ setDataSource:self];
3414 [table_ setDelegate:self];
3416 buttons_ = [[NSMutableArray alloc] initWithCapacity:4];
3420 - (void) setPackage:(Package *)package {
3421 if (package_ != nil) {
3422 [package_ autorelease];
3431 if (description_ != nil) {
3432 [description_ release];
3436 [buttons_ removeAllObjects];
3438 if (package != nil) {
3439 package_ = [package retain];
3440 name_ = [[package id] retain];
3442 NSString *description([package description]);
3443 if (description == nil)
3444 description = [package tagline];
3445 if (description != nil) {
3446 description_ = [GetTextView(description, 12, true) retain];
3447 [description_ setTextColor:Black_];
3450 [table_ reloadData];
3452 if ([package_ source] == nil);
3453 else if ([package_ upgradableAndEssential:NO])
3454 [buttons_ addObject:@"Upgrade"];
3455 else if ([package_ installed] == nil)
3456 [buttons_ addObject:@"Install"];
3458 [buttons_ addObject:@"Reinstall"];
3459 if ([package_ installed] != nil)
3460 [buttons_ addObject:@"Remove"];
3464 - (void) resetViewAnimated:(BOOL)animated {
3465 [table_ resetViewAnimated:animated];
3468 - (void) reloadData {
3469 [self setPackage:[database_ packageWithName:name_]];
3470 [self reloadButtons];
3475 /* Package Table {{{ */
3476 @interface PackageTable : RVPage {
3477 _transient Database *database_;
3481 NSMutableArray *packages_;
3482 NSMutableArray *sections_;
3483 UISectionList *list_;
3486 - (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object;
3488 - (void) setDelegate:(id)delegate;
3489 - (void) setObject:(id)object;
3491 - (void) reloadData;
3492 - (void) resetCursor;
3494 - (UISectionList *) list;
3496 - (void) setShouldHideHeaderInShortLists:(BOOL)hide;
3500 @implementation PackageTable
3503 [list_ setDataSource:nil];
3508 [packages_ release];
3509 [sections_ release];
3514 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
3515 return [sections_ count];
3518 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
3519 return [[sections_ objectAtIndex:section] name];
3522 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
3523 return [[sections_ objectAtIndex:section] row];
3526 - (int) numberOfRowsInTable:(UITable *)table {
3527 return [packages_ count];
3530 - (float) table:(UITable *)table heightForRow:(int)row {
3531 return [PackageCell heightForPackage:[packages_ objectAtIndex:row]];
3534 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
3536 reusing = [[[PackageCell alloc] init] autorelease];
3537 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
3541 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
3545 - (void) tableRowSelected:(NSNotification *)notification {
3546 int row = [[notification object] selectedRow];
3550 Package *package = [packages_ objectAtIndex:row];
3551 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
3552 [view setDelegate:delegate_];
3553 [view setPackage:package];
3554 [book_ pushPage:view];
3557 - (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object {
3558 if ((self = [super initWithBook:book]) != nil) {
3559 database_ = database;
3560 title_ = [title retain];
3562 object_ = object == nil ? nil : [object retain];
3564 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
3565 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
3567 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:YES];
3568 [list_ setDataSource:self];
3570 UITableColumn *column = [[[UITableColumn alloc]
3571 initWithTitle:@"Name"
3573 width:[self frame].size.width
3576 UITable *table = [list_ table];
3577 [table setSeparatorStyle:1];
3578 [table addTableColumn:column];
3579 [table setDelegate:self];
3580 [table setReusesTableCells:YES];
3582 [self addSubview:list_];
3587 - (void) setDelegate:(id)delegate {
3588 delegate_ = delegate;
3591 - (void) setObject:(id)object {
3597 object_ = [object retain];
3600 - (void) reloadData {
3601 NSArray *packages = [database_ packages];
3603 [packages_ removeAllObjects];
3604 [sections_ removeAllObjects];
3606 for (size_t i(0); i != [packages count]; ++i) {
3607 Package *package([packages objectAtIndex:i]);
3608 if ([[package performSelector:filter_ withObject:object_] boolValue])
3609 [packages_ addObject:package];
3612 Section *section = nil;
3614 for (size_t offset(0); offset != [packages_ count]; ++offset) {
3615 Package *package = [packages_ objectAtIndex:offset];
3616 NSString *name = [package index];
3618 if (section == nil || ![[section name] isEqualToString:name]) {
3619 section = [[[Section alloc] initWithName:name row:offset] autorelease];
3620 [sections_ addObject:section];
3623 [section addToCount];
3629 - (NSString *) title {
3633 - (void) resetViewAnimated:(BOOL)animated {
3634 [list_ resetViewAnimated:animated];
3637 - (void) resetCursor {
3638 [[list_ table] scrollPointVisibleAtTopLeft:CGPointMake(0, 0) animated:NO];
3641 - (UISectionList *) list {
3645 - (void) setShouldHideHeaderInShortLists:(BOOL)hide {
3646 [list_ setShouldHideHeaderInShortLists:hide];
3652 /* Browser Implementation {{{ */
3653 @implementation BrowserView
3656 WebView *webview = [webview_ webView];
3657 [webview setFrameLoadDelegate:nil];
3658 [webview setResourceLoadDelegate:nil];
3659 [webview setUIDelegate:nil];
3661 [scroller_ setDelegate:nil];
3662 [webview_ setDelegate:nil];
3664 [scroller_ release];
3667 [indicator_ release];
3673 - (void) loadURL:(NSURL *)url cachePolicy:(NSURLRequestCachePolicy)policy {
3674 NSMutableURLRequest *request = [NSMutableURLRequest
3677 timeoutInterval:30.0
3680 [request addValue:[NSString stringWithUTF8String:Firmware_] forHTTPHeaderField:@"X-Firmware"];
3681 [request addValue:[NSString stringWithUTF8String:Machine_] forHTTPHeaderField:@"X-Machine"];
3682 [request addValue:[NSString stringWithUTF8String:SerialNumber_] forHTTPHeaderField:@"X-Serial-Number"];
3684 [self loadRequest:request];
3688 - (void) loadURL:(NSURL *)url {
3689 [self loadURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy];
3692 // XXX: this needs to add the headers
3693 - (NSURLRequest *) _addHeadersToRequest:(NSURLRequest *)request {
3697 - (void) loadRequest:(NSURLRequest *)request {
3699 [webview_ loadRequest:request];
3702 - (void) reloadURL {
3703 NSURL *url = [[[urls_ lastObject] retain] autorelease];
3704 [urls_ removeLastObject];
3705 [self loadURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData];
3708 - (WebView *) webView {
3709 return [webview_ webView];
3712 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame {
3713 [scroller_ setContentSize:frame.size];
3716 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old {
3717 [self view:sender didSetFrame:frame];
3720 - (void) getAppTapp:(NSString *)href {
3721 if ([href hasPrefix:@"apptapp://package/"]) {
3722 NSString *name = [href substringFromIndex:18];
3723 Package *package = [database_ packageWithName:name];
3724 if (package == nil) {
3725 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
3726 initWithTitle:@"Cannot Locate Package"
3727 buttons:[NSArray arrayWithObjects:@"Close", nil]
3728 defaultButtonIndex:0
3733 [sheet setBodyText:[NSString stringWithFormat:
3734 @"The package %@ cannot be found in your current sources. I might recommend installing more sources."
3737 [sheet popupAlertAnimated:YES];
3739 [self setBackButtonTitle:title_];
3740 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
3741 [view setDelegate:delegate_];
3742 [view setPackage:package];
3743 [book_ pushPage:view];
3748 - (void) webView:(WebView *)sender willClickElement:(id)element {
3749 if (![element respondsToSelector:@selector(href)])
3751 NSString *href = [element href];
3754 if ([href hasPrefix:@"apptapp://package/"])
3755 [self getAppTapp:href];
3758 - (NSURLRequest *) webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource {
3759 if ([[[request URL] scheme] isEqualToString:@"apptapp"]) {
3760 [self getAppTapp:[[request URL] absoluteString]];
3766 [book_ pushPage:self];
3769 return [self _addHeadersToRequest:request];
3772 - (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request {
3773 if (request != nil && [[[request URL] scheme] isEqualToString:@"apptapp"])
3776 [self setBackButtonTitle:title_];
3778 BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease];
3779 [browser setDelegate:delegate_];
3781 if (request != nil) {
3782 [browser loadRequest:[self _addHeadersToRequest:request]];
3783 [book_ pushPage:browser];
3786 return [browser webView];
3790 - (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame {
3791 title_ = [title retain];
3792 [self setTitle:title];
3795 - (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame {
3796 if ([frame parentFrame] != nil)
3801 [indicator_ startAnimation];
3802 [self reloadButtons];
3804 if (title_ != nil) {
3809 [self setTitle:@"Loading..."];
3811 WebView *webview = [webview_ webView];
3812 NSString *href = [webview mainFrameURL];
3813 [urls_ addObject:[NSURL URLWithString:href]];
3815 CGRect webrect = [scroller_ frame];
3816 webrect.size.height = 0;
3817 [webview_ setFrame:webrect];
3820 - (void) _finishLoading {
3823 [indicator_ stopAnimation];
3824 [self reloadButtons];
3828 - (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
3829 if ([frame parentFrame] != nil)
3831 [self _finishLoading];
3834 - (void) webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
3835 if ([frame parentFrame] != nil)
3837 [self _finishLoading];
3838 [self loadURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@?%@",
3839 [[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"home" ofType:@"html"]] absoluteString],
3840 [[error localizedDescription] stringByAddingPercentEscapes]
3844 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3845 if ((self = [super initWithBook:book]) != nil) {
3846 database_ = database;
3849 struct CGRect bounds = [self bounds];
3851 UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:bounds] autorelease];
3852 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
3853 [self addSubview:pinstripe];
3855 scroller_ = [[UIScroller alloc] initWithFrame:bounds];
3856 [self addSubview:scroller_];
3858 [scroller_ setScrollingEnabled:YES];
3859 [scroller_ setAdjustForContentSizeChange:YES];
3860 [scroller_ setClipsSubviews:YES];
3861 [scroller_ setAllowsRubberBanding:YES];
3862 [scroller_ setScrollDecelerationFactor:0.99];
3863 [scroller_ setDelegate:self];
3865 CGRect webrect = [scroller_ bounds];
3866 webrect.size.height = 0;
3868 webview_ = [[UIWebView alloc] initWithFrame:webrect];
3869 [scroller_ addSubview:webview_];
3871 [webview_ setTilingEnabled:YES];
3872 [webview_ setTileSize:CGSizeMake(webrect.size.width, 500)];
3873 [webview_ setAutoresizes:YES];
3874 [webview_ setDelegate:self];
3875 //[webview_ setEnabledGestures:2];
3877 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:kUIProgressIndicatorStyleMediumWhite];
3878 indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(281, 42, indsize.width, indsize.height)];
3879 [indicator_ setStyle:kUIProgressIndicatorStyleMediumWhite];
3881 Package *package([database_ packageWithName:@"cydia"]);
3882 NSString *application = package == nil ? @"Cydia" : [NSString
3883 stringWithFormat:@"Cydia/%@",
3887 WebView *webview = [webview_ webView];
3888 [webview setApplicationNameForUserAgent:application];
3889 [webview setFrameLoadDelegate:self];
3890 [webview setResourceLoadDelegate:self];
3891 [webview setUIDelegate:self];
3893 urls_ = [[NSMutableArray alloc] initWithCapacity:16];
3897 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
3901 - (void) _leftButtonClicked {
3902 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
3903 initWithTitle:@"About Cydia Installer"
3904 buttons:[NSArray arrayWithObjects:@"Close", nil]
3905 defaultButtonIndex:0
3911 @"Copyright (C) 2008\n"
3912 "Jay Freeman (saurik)\n"
3913 "saurik@saurik.com\n"
3914 "http://www.saurik.com/\n"
3917 "http://www.theokorigroup.com/\n"
3919 "College of Creative Studies,\n"
3920 "University of California,\n"
3922 "http://www.ccs.ucsb.edu/"
3925 [sheet popupAlertAnimated:YES];
3928 - (void) _rightButtonClicked {
3933 - (NSString *) leftButtonTitle {
3937 - (NSString *) rightButtonTitle {
3938 return loading_ ? @"" : @"Reload";
3941 - (NSString *) title {
3945 - (NSString *) backButtonTitle {
3949 - (void) setPageActive:(BOOL)active {
3951 [book_ addSubview:indicator_];
3953 [indicator_ removeFromSuperview];
3956 - (void) resetViewAnimated:(BOOL)animated {
3959 - (void) setPushed:(bool)pushed {
3966 @interface CYBook : RVBook <
3969 _transient Database *database_;
3971 UIProgressIndicator *indicator_;
3972 UITextLabel *prompt_;
3973 UIProgressBar *progress_;
3977 - (id) initWithFrame:(CGRect)frame database:(Database *)database;
3983 /* Source Cell {{{ */
3984 @interface SourceCell : UITableCell {
3985 UITextLabel *description_;
3986 UIRightTextLabel *label_;
3987 UITextLabel *origin_;
3992 - (SourceCell *) initWithSource:(Source *)source;
3994 - (void) _setSelected:(float)fraction;
3995 - (void) setSelected:(BOOL)selected;
3996 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
3997 - (void) _setSelectionFadeFraction:(float)fraction;
4001 @implementation SourceCell
4004 [description_ release];
4010 - (SourceCell *) initWithSource:(Source *)source {
4011 if ((self = [super init]) != nil) {
4012 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 20);
4013 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 14);
4015 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
4016 float clear[] = {0, 0, 0, 0};
4018 NSString *description = [source description];
4019 if (description == nil)
4020 description = [source uri];
4022 description_ = [[UITextLabel alloc] initWithFrame:CGRectMake(12, 7, 270, 25)];
4023 [description_ setBackgroundColor:CGColorCreate(space, clear)];
4024 [description_ setFont:bold];
4025 [description_ setText:description];
4027 NSString *label = [source label];
4029 label = [source type];
4031 label_ = [[UIRightTextLabel alloc] initWithFrame:CGRectMake(290, 32, 90, 25)];
4032 [label_ setBackgroundColor:CGColorCreate(space, clear)];
4033 [label_ setFont:small];
4034 [label_ setText:label];
4036 NSString *origin = [source origin];
4038 origin = [source distribution];
4040 origin_ = [[UITextLabel alloc] initWithFrame:CGRectMake(13, 35, 315, 20)];
4041 [origin_ setBackgroundColor:CGColorCreate(space, clear)];
4042 [origin_ setFont:small];
4043 [origin_ setText:origin];
4045 [self addSubview:description_];
4046 [self addSubview:label_];
4047 [self addSubview:origin_];
4054 - (void) _setSelected:(float)fraction {
4055 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
4058 Interpolate(0.0, 1.0, fraction),
4059 Interpolate(0.0, 1.0, fraction),
4060 Interpolate(0.0, 1.0, fraction),
4064 Interpolate(0.2, 1.0, fraction),
4065 Interpolate(0.2, 1.0, fraction),
4066 Interpolate(1.0, 1.0, fraction),
4070 Interpolate(0.4, 1.0, fraction),
4071 Interpolate(0.4, 1.0, fraction),
4072 Interpolate(0.4, 1.0, fraction),
4075 [description_ setColor:CGColorCreate(space, black)];
4076 [label_ setColor:CGColorCreate(space, blue)];
4077 [origin_ setColor:CGColorCreate(space, gray)];
4080 - (void) setSelected:(BOOL)selected {
4081 [self _setSelected:(selected ? 1.0 : 0.0)];
4082 [super setSelected:selected];
4085 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
4087 [self _setSelected:(selected ? 1.0 : 0.0)];
4088 [super setSelected:selected withFade:fade];
4091 - (void) _setSelectionFadeFraction:(float)fraction {
4092 [self _setSelected:fraction];
4093 [super _setSelectionFadeFraction:fraction];
4098 /* Source Table {{{ */
4099 @interface SourceTable : RVPage {
4100 _transient Database *database_;
4101 UISectionList *list_;
4102 NSMutableArray *sources_;
4103 UIAlertSheet *alert_;
4106 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4110 @implementation SourceTable
4113 [list_ setDataSource:nil];
4115 if (sources_ != nil)
4121 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
4125 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
4129 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
4133 - (int) numberOfRowsInTable:(UITable *)table {
4134 return [sources_ count];
4137 - (float) table:(UITable *)table heightForRow:(int)row {
4141 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col {
4142 return [[[SourceCell alloc] initWithSource:[sources_ objectAtIndex:row]] autorelease];
4145 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
4149 - (void) tableRowSelected:(NSNotification*)notification {
4150 UITable *table([list_ table]);
4151 int row([table selectedRow]);
4155 [table selectRow:-1 byExtendingSelection:NO withFade:YES];
4158 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4159 if ((self = [super initWithBook:book]) != nil) {
4160 database_ = database;
4163 list_ = [[UISectionList alloc] initWithFrame:[self bounds]];
4165 [self addSubview:list_];
4167 [list_ setDataSource:self];
4168 [list_ setShouldHideHeaderInShortLists:NO];
4170 UITableColumn *column = [[UITableColumn alloc]
4171 initWithTitle:@"Name"
4173 width:[self frame].size.width
4176 UITable *table = [list_ table];
4177 [table setSeparatorStyle:1];
4178 [table addTableColumn:column];
4179 [table setDelegate:self];
4183 - (void) reloadData {
4185 _assert(list.ReadMainList());
4187 if (sources_ != nil)
4190 sources_ = [[NSMutableArray arrayWithCapacity:16] retain];
4191 for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source)
4192 [sources_ addObject:[[[Source alloc] initWithMetaIndex:*source] autorelease]];
4197 - (void) resetViewAnimated:(BOOL)animated {
4198 [list_ resetViewAnimated:animated];
4201 - (NSString *) leftTitle {
4202 return @"Refresh All";
4205 - (NSString *) rightTitle {
4212 /* Install View {{{ */
4213 @interface InstallView : RVPage {
4214 _transient Database *database_;
4215 NSMutableArray *sections_;
4216 NSMutableArray *filtered_;
4217 UITransitionView *transition_;
4223 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4224 - (void) reloadData;
4229 @implementation InstallView
4232 [list_ setDataSource:nil];
4233 [list_ setDelegate:nil];
4235 [sections_ release];
4236 [filtered_ release];
4237 [transition_ release];
4239 [accessory_ release];
4243 - (int) numberOfRowsInTable:(UITable *)table {
4244 return editing_ ? [sections_ count] : [filtered_ count] + 1;
4247 - (float) table:(UITable *)table heightForRow:(int)row {
4251 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
4253 reusing = [[[SectionCell alloc] init] autorelease];
4254 [(SectionCell *)reusing setSection:(editing_ ?
4255 [sections_ objectAtIndex:row] :
4256 (row == 0 ? nil : [filtered_ objectAtIndex:(row - 1)])
4257 ) editing:editing_];
4261 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
4265 - (BOOL) table:(UITable *)table canSelectRow:(int)row {
4269 - (void) tableRowSelected:(NSNotification *)notification {
4270 int row = [[notification object] selectedRow];
4281 title = @"All Packages";
4283 section = [filtered_ objectAtIndex:(row - 1)];
4284 name = [section name];
4290 title = @"(No Section)";
4294 PackageTable *table = [[[PackageTable alloc]
4298 filter:@selector(isUninstalledInSection:)
4302 [table setDelegate:delegate_];
4304 [book_ pushPage:table];
4307 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4308 if ((self = [super initWithBook:book]) != nil) {
4309 database_ = database;
4311 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
4312 filtered_ = [[NSMutableArray arrayWithCapacity:16] retain];
4314 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
4315 [self addSubview:transition_];
4317 list_ = [[UITable alloc] initWithFrame:[transition_ bounds]];
4318 [transition_ transition:0 toView:list_];
4320 UITableColumn *column = [[[UITableColumn alloc]
4321 initWithTitle:@"Name"
4323 width:[self frame].size.width
4326 [list_ setDataSource:self];
4327 [list_ setSeparatorStyle:1];
4328 [list_ addTableColumn:column];
4329 [list_ setDelegate:self];
4330 [list_ setReusesTableCells:YES];
4336 - (void) reloadData {
4337 NSArray *packages = [database_ packages];
4339 [sections_ removeAllObjects];
4340 [filtered_ removeAllObjects];
4342 NSMutableArray *filtered = [NSMutableArray arrayWithCapacity:[packages count]];
4343 NSMutableDictionary *sections = [NSMutableDictionary dictionaryWithCapacity:32];
4345 for (size_t i(0); i != [packages count]; ++i) {
4346 Package *package([packages objectAtIndex:i]);
4347 NSString *name([package section]);
4350 Section *section([sections objectForKey:name]);
4351 if (section == nil) {
4352 section = [[[Section alloc] initWithName:name] autorelease];
4353 [sections setObject:section forKey:name];
4357 if ([package valid] && [package installed] == nil && [package visible])
4358 [filtered addObject:package];
4361 [sections_ addObjectsFromArray:[sections allValues]];
4362 [sections_ sortUsingSelector:@selector(compareByName:)];
4364 [filtered sortUsingSelector:@selector(compareBySection:)];
4366 Section *section = nil;
4367 for (size_t offset = 0, count = [filtered count]; offset != count; ++offset) {
4368 Package *package = [filtered objectAtIndex:offset];
4369 NSString *name = [package section];
4371 if (section == nil || name != nil && ![[section name] isEqualToString:name]) {
4372 section = name == nil ?
4373 [[[Section alloc] initWithName:nil] autorelease] :
4374 [sections objectForKey:name];
4375 [filtered_ addObject:section];
4378 [section addToCount];
4384 - (void) resetView {
4386 [self _rightButtonClicked];
4389 - (void) resetViewAnimated:(BOOL)animated {
4390 [list_ resetViewAnimated:animated];
4393 - (void) _rightButtonClicked {
4394 if ((editing_ = !editing_))
4397 [delegate_ updateData];
4400 [book_ setTitle:[self title] forPage:self];
4401 [book_ reloadButtonsForPage:self];
4404 - (NSString *) title {
4405 return editing_ ? @"Section Visibility" : @"Install by Section";
4408 - (NSString *) backButtonTitle {
4412 - (NSString *) rightButtonTitle {
4413 return [sections_ count] == 0 ? nil : editing_ ? @"Done" : @"Edit";
4416 - (UIView *) accessoryView {
4422 /* Changes View {{{ */
4423 @interface ChangesView : RVPage {
4424 _transient Database *database_;
4425 NSMutableArray *packages_;
4426 NSMutableArray *sections_;
4427 UISectionList *list_;
4431 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4432 - (void) reloadData;
4436 @implementation ChangesView
4439 [[list_ table] setDelegate:nil];
4440 [list_ setDataSource:nil];
4442 [packages_ release];
4443 [sections_ release];
4448 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
4449 return [sections_ count];
4452 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
4453 return [[sections_ objectAtIndex:section] name];
4456 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
4457 return [[sections_ objectAtIndex:section] row];
4460 - (int) numberOfRowsInTable:(UITable *)table {
4461 return [packages_ count];
4464 - (float) table:(UITable *)table heightForRow:(int)row {
4465 return [PackageCell heightForPackage:[packages_ objectAtIndex:row]];
4468 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
4470 reusing = [[[PackageCell alloc] init] autorelease];
4471 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
4475 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
4479 - (void) tableRowSelected:(NSNotification *)notification {
4480 int row = [[notification object] selectedRow];
4483 Package *package = [packages_ objectAtIndex:row];
4484 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
4485 [view setDelegate:delegate_];
4486 [view setPackage:package];
4487 [book_ pushPage:view];
4490 - (void) _leftButtonClicked {
4491 [(CYBook *)book_ update];
4492 [self reloadButtons];
4495 - (void) _rightButtonClicked {
4496 [delegate_ distUpgrade];
4499 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4500 if ((self = [super initWithBook:book]) != nil) {
4501 database_ = database;
4503 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
4504 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
4506 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:NO];
4507 [self addSubview:list_];
4509 [list_ setShouldHideHeaderInShortLists:NO];
4510 [list_ setDataSource:self];
4511 //[list_ setSectionListStyle:1];
4513 UITableColumn *column = [[[UITableColumn alloc]
4514 initWithTitle:@"Name"
4516 width:[self frame].size.width
4519 UITable *table = [list_ table];
4520 [table setSeparatorStyle:1];
4521 [table addTableColumn:column];
4522 [table setDelegate:self];
4523 [table setReusesTableCells:YES];
4529 - (void) reloadData {
4530 NSArray *packages = [database_ packages];
4532 [packages_ removeAllObjects];
4533 [sections_ removeAllObjects];
4535 for (size_t i(0); i != [packages count]; ++i) {
4536 Package *package([packages objectAtIndex:i]);
4539 [package installed] == nil && [package valid] && [package visible] ||
4540 [package upgradableAndEssential:NO]
4542 [packages_ addObject:package];
4545 [packages_ sortUsingSelector:@selector(compareForChanges:)];
4547 Section *upgradable = [[[Section alloc] initWithName:@"Available Upgrades"] autorelease];
4548 Section *section = nil;
4551 bool unseens = false;
4553 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, Locale_, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
4555 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
4556 Package *package = [packages_ objectAtIndex:offset];
4558 if ([package upgradableAndEssential:YES]) {
4560 [upgradable addToCount];
4563 NSDate *seen = [package seen];
4568 name = [@"n/a ?" retain];
4570 name = (NSString *) CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen);
4573 if (section == nil || ![[section name] isEqualToString:name]) {
4574 section = [[[Section alloc] initWithName:name row:offset] autorelease];
4575 [sections_ addObject:section];
4579 [section addToCount];
4583 CFRelease(formatter);
4586 Section *last = [sections_ lastObject];
4587 size_t count = [last count];
4588 [packages_ removeObjectsInRange:NSMakeRange([packages_ count] - count, count)];
4589 [sections_ removeLastObject];
4593 [sections_ insertObject:upgradable atIndex:0];
4596 [self reloadButtons];
4599 - (void) resetViewAnimated:(BOOL)animated {
4600 [list_ resetViewAnimated:animated];
4603 - (NSString *) leftButtonTitle {
4604 return [(CYBook *)book_ updating] ? nil : @"Refresh";
4607 - (NSString *) rightButtonTitle {
4608 return upgrades_ == 0 ? nil : [NSString stringWithFormat:@"Upgrade All (%u)", upgrades_];
4611 - (NSString *) title {
4617 /* Manage View {{{ */
4618 @interface ManageView : RVPage {
4619 _transient Database *database_;
4620 PackageTable *packages_;
4621 SourceTable *sources_;
4624 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4628 @implementation ManageView
4631 [packages_ release];
4636 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4637 if ((self = [super initWithBook:book]) != nil) {
4638 database_ = database;
4640 packages_ = [[PackageTable alloc]
4644 filter:@selector(isInstalledInSection:)
4648 sources_ = [[SourceTable alloc]
4653 [self addSubview:packages_];
4657 - (void) resetViewAnimated:(BOOL)animated {
4658 [packages_ resetViewAnimated:animated];
4659 [sources_ resetViewAnimated:animated];
4662 - (void) reloadData {
4663 [packages_ reloadData];
4664 [sources_ reloadData];
4667 - (NSString *) title {
4668 return @"Installed Packages";
4671 - (NSString *) backButtonTitle {
4675 - (void) setDelegate:(id)delegate {
4676 [super setDelegate:delegate];
4677 [packages_ setDelegate:delegate];
4678 [sources_ setDelegate:delegate];
4683 /* Search View {{{ */
4684 @protocol SearchViewDelegate
4685 - (void) showKeyboard:(BOOL)show;
4688 @interface SearchView : RVPage {
4690 UISearchField *field_;
4691 UITransitionView *transition_;
4692 PackageTable *table_;
4693 UIPreferencesTable *advanced_;
4699 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4700 - (void) reloadData;
4704 @implementation SearchView
4708 [[field_ textTraits] setEditingDelegate:nil];
4710 [field_ setDelegate:nil];
4712 [accessory_ release];
4714 [transition_ release];
4716 [advanced_ release];
4721 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
4725 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
4727 case 0: return @"Advanced Search (Coming Soon!)";
4729 default: _assert(false);
4733 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
4737 default: _assert(false);
4741 - (void) _showKeyboard:(BOOL)show {
4742 CGSize keysize = [UIKeyboard defaultSize];
4743 CGRect keydown = [book_ pageBounds];
4744 CGRect keyup = keydown;
4745 keyup.size.height -= keysize.height - ButtonBarHeight_;
4747 float delay = KeyboardTime_ * ButtonBarHeight_ / keysize.height;
4749 UIFrameAnimation *animation = [[[UIFrameAnimation alloc] initWithTarget:[table_ list]] autorelease];
4750 [animation setSignificantRectFields:8];
4753 [animation setStartFrame:keydown];
4754 [animation setEndFrame:keyup];
4756 [animation setStartFrame:keyup];
4757 [animation setEndFrame:keydown];
4760 UIAnimator *animator = [UIAnimator sharedAnimator];
4763 addAnimations:[NSArray arrayWithObjects:animation, nil]
4764 withDuration:(KeyboardTime_ - delay)
4769 [animator performSelector:@selector(startAnimation:) withObject:animation afterDelay:delay];
4772 [delegate_ showKeyboard:show];
4776 - (void) textFieldDidBecomeFirstResponder:(UITextField *)field {
4777 [self _showKeyboard:YES];
4780 - (void) textFieldDidResignFirstResponder:(UITextField *)field {
4781 [self _showKeyboard:NO];
4784 - (void) keyboardInputChanged:(UIFieldEditor *)editor {
4786 NSString *text([field_ text]);
4787 [field_ setClearButtonStyle:(text == nil || [text length] == 0 ? 0 : 2)];
4793 - (void) textFieldClearButtonPressed:(UITextField *)field {
4797 - (void) keyboardInputShouldDelete:(id)input {
4801 - (BOOL) keyboardInput:(id)input shouldInsertText:(NSString *)text isMarkedText:(int)marked {
4802 if ([text length] != 1 || [text characterAtIndex:0] != '\n') {
4806 [field_ resignFirstResponder];
4811 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4812 if ((self = [super initWithBook:book]) != nil) {
4813 CGRect pageBounds = [book_ pageBounds];
4815 /*UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:pageBounds] autorelease];
4816 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
4817 [self addSubview:pinstripe];*/
4819 transition_ = [[UITransitionView alloc] initWithFrame:pageBounds];
4820 [self addSubview:transition_];
4822 advanced_ = [[UIPreferencesTable alloc] initWithFrame:pageBounds];
4824 [advanced_ setReusesTableCells:YES];
4825 [advanced_ setDataSource:self];
4826 [advanced_ reloadData];
4828 dimmed_ = [[UIView alloc] initWithFrame:pageBounds];
4829 CGColor dimmed(space_, 0, 0, 0, 0.5);
4830 [dimmed_ setBackgroundColor:dimmed];
4832 table_ = [[PackageTable alloc]
4836 filter:@selector(isSearchedForBy:)
4840 [table_ setShouldHideHeaderInShortLists:NO];
4841 [transition_ transition:0 toView:table_];
4850 area.origin.x = /*cnfrect.origin.x + cnfrect.size.width + 4 +*/ 10;
4857 [self bounds].size.width - area.origin.x - 18;
4859 area.size.height = [UISearchField defaultHeight];
4861 field_ = [[UISearchField alloc] initWithFrame:area];
4863 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
4864 [field_ setFont:font];
4867 [field_ setPlaceholder:@"Package Names & Descriptions"];
4868 [field_ setDelegate:self];
4871 [field_ setPaddingTop:3];
4873 [field_ setPaddingTop:5];
4876 UITextTraits *traits = [field_ textTraits];
4877 [traits setAutoCapsType:0];
4878 [traits setAutoCorrectionType:1];
4879 [traits setReturnKeyType:6];
4882 [traits setEditingDelegate:self];
4885 CGRect accrect = {{0, 6}, {6 + cnfrect.size.width + 6 + area.size.width + 6, area.size.height + 30}};
4887 accessory_ = [[UIView alloc] initWithFrame:accrect];
4888 [accessory_ addSubview:field_];
4890 /*UIPushButton *configure = [[[UIPushButton alloc] initWithFrame:cnfrect] autorelease];
4891 [configure setShowPressFeedback:YES];
4892 [configure setImage:[UIImage applicationImageNamed:@"advanced.png"]];
4893 [configure addTarget:self action:@selector(configurePushed) forEvents:1];
4894 [accessory_ addSubview:configure];*/
4900 LKAnimation *animation = [LKTransition animation];
4901 [animation setType:@"oglFlip"];
4902 [animation setTimingFunction:[LKTimingFunction functionWithName:@"easeInEaseOut"]];
4903 [animation setFillMode:@"extended"];
4904 [animation setTransitionFlags:3];
4905 [animation setDuration:10];
4906 [animation setSpeed:0.35];
4907 [animation setSubtype:(flipped_ ? @"fromLeft" : @"fromRight")];
4908 [[transition_ _layer] addAnimation:animation forKey:0];
4909 [transition_ transition:0 toView:(flipped_ ? (UIView *) table_ : (UIView *) advanced_)];
4910 flipped_ = !flipped_;
4914 - (void) configurePushed {
4915 [field_ resignFirstResponder];
4919 - (void) resetViewAnimated:(BOOL)animated {
4922 [table_ resetViewAnimated:animated];
4925 - (void) reloadData {
4928 [table_ setObject:[field_ text]];
4929 [table_ reloadData];
4930 [table_ resetCursor];
4933 - (UIView *) accessoryView {
4937 - (NSString *) title {
4941 - (NSString *) backButtonTitle {
4945 - (void) setDelegate:(id)delegate {
4946 [table_ setDelegate:delegate];
4947 [super setDelegate:delegate];
4953 @implementation CYBook
4957 [indicator_ release];
4959 [progress_ release];
4963 - (NSString *) getTitleForPage:(RVPage *)page {
4964 return Simplify([super getTitleForPage:page]);
4972 [navbar_ setPrompt:@""];
4973 [navbar_ addSubview:overlay_];
4974 [indicator_ startAnimation];
4975 [prompt_ setText:@"Updating Database..."];
4976 [progress_ setProgress:0];
4981 detachNewThreadSelector:@selector(_update)
4990 [overlay_ removeFromSuperview];
4991 [indicator_ stopAnimation];
4992 [delegate_ reloadData];
4994 [self setPrompt:[NSString stringWithFormat:@"Last Updated: %@", GetLastUpdate()]];
4997 - (id) initWithFrame:(CGRect)frame database:(Database *)database {
4998 if ((self = [super initWithFrame:frame]) != nil) {
4999 database_ = database;
5002 [navbar_ setBarStyle:1];
5004 CGRect ovrrect = [navbar_ bounds];
5005 ovrrect.size.height = ([UINavigationBar defaultSizeWithPrompt].height - [UINavigationBar defaultSize].height);
5007 overlay_ = [[UIView alloc] initWithFrame:ovrrect];
5009 UIProgressIndicatorStyle style = Advanced_ ?
5010 kUIProgressIndicatorStyleSmallWhite :
5011 kUIProgressIndicatorStyleSmallBlack;
5013 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:style];
5014 unsigned indoffset = (ovrrect.size.height - indsize.height) / 2;
5015 CGRect indrect = {{indoffset, indoffset}, indsize};
5017 indicator_ = [[UIProgressIndicator alloc] initWithFrame:indrect];
5018 [indicator_ setStyle:style];
5019 [overlay_ addSubview:indicator_];
5021 CGSize prmsize = {200, indsize.width + 4};
5024 indoffset * 2 + indsize.width,
5028 (ovrrect.size.height - prmsize.height) / 2
5031 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 12);
5033 prompt_ = [[UITextLabel alloc] initWithFrame:prmrect];
5035 [prompt_ setColor:(Advanced_ ? White_ : Blueish_)];
5036 [prompt_ setBackgroundColor:Clear_];
5037 [prompt_ setFont:font];
5041 [overlay_ addSubview:prompt_];
5043 CGSize prgsize = {75, 100};
5046 ovrrect.size.width - prgsize.width - 10,
5047 (ovrrect.size.height - prgsize.height) / 2
5050 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
5051 [progress_ setStyle:0];
5052 [overlay_ addSubview:progress_];
5057 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5060 status.setDelegate(self);
5062 [database_ updateWithStatus:status];
5065 performSelectorOnMainThread:@selector(_update_)
5073 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id {
5074 [prompt_ setText:[NSString stringWithFormat:@"Error: %@", error]];
5077 - (void) setProgressTitle:(NSString *)title {
5079 performSelectorOnMainThread:@selector(_setProgressTitle:)
5085 - (void) setProgressPercent:(float)percent {
5088 - (void) addProgressOutput:(NSString *)output {
5090 performSelectorOnMainThread:@selector(_addProgressOutput:)
5096 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
5100 - (void) _setProgressTitle:(NSString *)title {
5101 [prompt_ setText:[title stringByAppendingString:@"..."]];
5104 - (void) _addProgressOutput:(NSString *)output {
5109 @interface Cydia : UIApplication <
5110 ConfirmationViewDelegate,
5111 ProgressViewDelegate,
5120 UIButtonBar *buttonbar_;
5122 ConfirmationView *confirm_;
5124 NSMutableArray *essential_;
5125 NSMutableArray *broken_;
5127 Database *database_;
5128 ProgressView *progress_;
5132 UIKeyboard *keyboard_;
5133 UIProgressHUD *hud_;
5135 InstallView *install_;
5136 ChangesView *changes_;
5137 ManageView *manage_;
5138 SearchView *search_;
5143 @implementation Cydia
5146 if ([broken_ count] != 0) {
5147 int count = [broken_ count];
5149 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
5150 initWithTitle:[NSString stringWithFormat:@"%d Half-Installed Package%@", count, (count == 1 ? @"" : @"s")]
5151 buttons:[NSArray arrayWithObjects:
5153 @"Ignore (Temporary)",
5155 defaultButtonIndex:0
5160 [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."];
5161 [sheet popupAlertAnimated:YES];
5162 } else if (!Ignored_ && [essential_ count] != 0) {
5163 int count = [essential_ count];
5165 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
5166 initWithTitle:[NSString stringWithFormat:@"%d Essential Upgrade%@", count, (count == 1 ? @"" : @"s")]
5167 buttons:[NSArray arrayWithObjects:@"Upgrade Essential", @"Ignore (Temporary)", nil]
5168 defaultButtonIndex:0
5173 [sheet setBodyText:@"One or more essential packages are currently out of date. If these upgrades are not performed you are likely to encounter errors."];
5174 [sheet popupAlertAnimated:YES];
5178 - (void) _reloadData {
5179 /*UIProgressHUD *hud = [[UIProgressHUD alloc] initWithWindow:window_];
5180 [hud setText:@"Reloading Data"];
5181 [overlay_ addSubview:hud];
5184 [database_ reloadData];
5186 if (Packages_ == nil) {
5187 Packages_ = [[NSMutableDictionary alloc] initWithCapacity:128];
5188 [Metadata_ setObject:Packages_ forKey:@"Packages"];
5191 if (Sections_ == nil) {
5192 Sections_ = [[NSMutableDictionary alloc] initWithCapacity:32];
5193 [Metadata_ setObject:Sections_ forKey:@"Sections"];
5198 [essential_ removeAllObjects];
5199 [broken_ removeAllObjects];
5201 NSArray *packages = [database_ packages];
5202 for (int i(0), e([packages count]); i != e; ++i) {
5203 Package *package = [packages objectAtIndex:i];
5205 [broken_ addObject:package];
5206 if ([package upgradableAndEssential:NO]) {
5207 if ([package essential])
5208 [essential_ addObject:package];
5214 NSString *badge([[NSNumber numberWithInt:changes] stringValue]);
5215 [buttonbar_ setBadgeValue:badge forButton:3];
5216 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
5217 [buttonbar_ setBadgeAnimated:YES forButton:3];
5218 [self setApplicationBadge:badge];
5220 [buttonbar_ setBadgeValue:nil forButton:3];
5221 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
5222 [buttonbar_ setBadgeAnimated:NO forButton:3];
5223 [self removeApplicationBadge];
5228 if ([packages count] == 0);
5237 [hud removeFromSuperview];*/
5240 - (void) updateData {
5242 _assert([Metadata_ writeToFile:@"/var/lib/cydia/metadata.plist" atomically:YES] == YES);
5246 /* XXX: this is just stupid */
5248 [install_ reloadData];
5250 [changes_ reloadData];
5252 [manage_ reloadData];
5254 [search_ reloadData];
5259 - (void) reloadData {
5260 @synchronized (self) {
5261 if (confirm_ == nil)
5267 pkgProblemResolver *resolver = [database_ resolver];
5269 resolver->InstallProtect();
5270 if (!resolver->Resolve(true))
5275 [database_ prepare];
5277 if ([database_ cache]->BrokenCount() == 0)
5278 confirm_ = [[ConfirmationView alloc] initWithView:underlay_ database:database_ delegate:self];
5280 NSMutableArray *broken = [NSMutableArray arrayWithCapacity:16];
5281 NSArray *packages = [database_ packages];
5283 for (size_t i(0); i != [packages count]; ++i) {
5284 Package *package = [packages objectAtIndex:i];
5285 if ([package broken])
5286 [broken addObject:[package name]];
5289 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
5290 initWithTitle:[NSString stringWithFormat:@"%d Broken Packages", [database_ cache]->BrokenCount()]
5291 buttons:[NSArray arrayWithObjects:@"Okay", nil]
5292 defaultButtonIndex:0
5297 [sheet setBodyText:[NSString stringWithFormat:@"The following packages have unmet dependencies:\n\n%@", [broken componentsJoinedByString:@"\n"]]];
5298 [sheet popupAlertAnimated:YES];
5304 - (void) installPackage:(Package *)package {
5305 @synchronized (self) {
5312 - (void) removePackage:(Package *)package {
5313 @synchronized (self) {
5320 - (void) distUpgrade {
5321 @synchronized (self) {
5322 [database_ upgrade];
5328 @synchronized (self) {
5336 [overlay_ removeFromSuperview];
5340 detachNewThreadSelector:@selector(perform)
5347 - (void) bootstrap_ {
5349 [database_ upgrade];
5350 [database_ prepare];
5351 [database_ perform];
5354 - (void) bootstrap {
5356 detachNewThreadSelector:@selector(bootstrap_)
5359 title:@"Bootstrap Install..."
5363 - (void) progressViewIsComplete:(ProgressView *)progress {
5364 @synchronized (self) {
5367 if (confirm_ != nil) {
5368 [underlay_ addSubview:overlay_];
5369 [confirm_ removeFromSuperview];
5376 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
5377 NSString *context = [sheet context];
5378 if ([context isEqualToString:@"fixhalf"])
5381 @synchronized (self) {
5382 for (int i = 0, e = [broken_ count]; i != e; ++i) {
5383 Package *broken = [broken_ objectAtIndex:i];
5386 NSString *id = [broken id];
5387 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.prerm", id] UTF8String]);
5388 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.postrm", id] UTF8String]);
5389 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.preinst", id] UTF8String]);
5390 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.postinst", id] UTF8String]);
5399 [broken_ removeAllObjects];
5406 else if ([context isEqualToString:@"upgrade"])
5409 @synchronized (self) {
5410 for (int i = 0, e = [essential_ count]; i != e; ++i) {
5411 Package *essential = [essential_ objectAtIndex:i];
5412 [essential install];
5431 - (void) setPage:(RVPage *)page {
5432 [page resetViewAnimated:NO];
5433 [page setDelegate:self];
5434 [book_ setPage:page];
5437 - (RVPage *) _setHomePage {
5438 BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease];
5439 [self setPage:browser];
5440 [browser loadURL:[NSURL URLWithString:@"http://cydia.saurik.com/"]];
5444 - (void) buttonBarItemTapped:(id)sender {
5445 unsigned tag = [sender tag];
5447 [book_ resetViewAnimated:YES];
5449 } else if (tag_ == 2 && tag != 2)
5450 [install_ resetView];
5453 case 1: [self _setHomePage]; break;
5455 case 2: [self setPage:install_]; break;
5456 case 3: [self setPage:changes_]; break;
5457 case 4: [self setPage:manage_]; break;
5458 case 5: [self setPage:search_]; break;
5460 default: _assert(false);
5466 - (void) fixSpringBoard {
5467 pid_t pid = ExecFork();
5471 if (pid_t child = fork()) {
5472 waitpid(child, NULL, 0);
5474 execlp("launchctl", "launchctl", "unload", SpringBoard_, NULL);
5475 perror("launchctl unload");
5479 execlp("launchctl", "launchctl", "load", SpringBoard_, NULL);
5480 perror("launchctl load");
5485 - (void) applicationWillSuspend {
5490 [self fixSpringBoard];
5494 [super applicationWillSuspend];
5499 [self setStatusBarShowsProgress:NO];
5502 [hud_ removeFromSuperview];
5506 pid_t pid = ExecFork();
5508 execlp("launchctl", "launchctl", "stop", "com.apple.SpringBoard", NULL);
5509 perror("launchctl stop");
5515 overlay_ = [[UIView alloc] initWithFrame:[underlay_ bounds]];
5517 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
5518 book_ = [[CYBook alloc] initWithFrame:CGRectMake(
5519 0, 0, screenrect.size.width, screenrect.size.height - 48
5520 ) database:database_];
5522 [book_ setDelegate:self];
5524 [overlay_ addSubview:book_];
5526 NSArray *buttonitems = [NSArray arrayWithObjects:
5527 [NSDictionary dictionaryWithObjectsAndKeys:
5528 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5529 @"home-up.png", kUIButtonBarButtonInfo,
5530 @"home-dn.png", kUIButtonBarButtonSelectedInfo,
5531 [NSNumber numberWithInt:1], kUIButtonBarButtonTag,
5532 self, kUIButtonBarButtonTarget,
5533 @"Home", kUIButtonBarButtonTitle,
5534 @"0", kUIButtonBarButtonType,
5537 [NSDictionary dictionaryWithObjectsAndKeys:
5538 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5539 @"install-up.png", kUIButtonBarButtonInfo,
5540 @"install-dn.png", kUIButtonBarButtonSelectedInfo,
5541 [NSNumber numberWithInt:2], kUIButtonBarButtonTag,
5542 self, kUIButtonBarButtonTarget,
5543 @"Sections", kUIButtonBarButtonTitle,
5544 @"0", kUIButtonBarButtonType,
5547 [NSDictionary dictionaryWithObjectsAndKeys:
5548 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5549 @"changes-up.png", kUIButtonBarButtonInfo,
5550 @"changes-dn.png", kUIButtonBarButtonSelectedInfo,
5551 [NSNumber numberWithInt:3], kUIButtonBarButtonTag,
5552 self, kUIButtonBarButtonTarget,
5553 @"Changes", kUIButtonBarButtonTitle,
5554 @"0", kUIButtonBarButtonType,
5557 [NSDictionary dictionaryWithObjectsAndKeys:
5558 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5559 @"manage-up.png", kUIButtonBarButtonInfo,
5560 @"manage-dn.png", kUIButtonBarButtonSelectedInfo,
5561 [NSNumber numberWithInt:4], kUIButtonBarButtonTag,
5562 self, kUIButtonBarButtonTarget,
5563 @"Manage", kUIButtonBarButtonTitle,
5564 @"0", kUIButtonBarButtonType,
5567 [NSDictionary dictionaryWithObjectsAndKeys:
5568 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5569 @"search-up.png", kUIButtonBarButtonInfo,
5570 @"search-dn.png", kUIButtonBarButtonSelectedInfo,
5571 [NSNumber numberWithInt:5], kUIButtonBarButtonTag,
5572 self, kUIButtonBarButtonTarget,
5573 @"Search", kUIButtonBarButtonTitle,
5574 @"0", kUIButtonBarButtonType,
5578 buttonbar_ = [[UIButtonBar alloc]
5580 withFrame:CGRectMake(
5581 0, screenrect.size.height - ButtonBarHeight_,
5582 screenrect.size.width, ButtonBarHeight_
5584 withItemList:buttonitems
5587 [buttonbar_ setDelegate:self];
5588 [buttonbar_ setBarStyle:1];
5589 [buttonbar_ setButtonBarTrackingMode:2];
5591 int buttons[5] = {1, 2, 3, 4, 5};
5592 [buttonbar_ registerButtonGroup:0 withButtons:buttons withCount:5];
5593 [buttonbar_ showButtonGroup:0 withDuration:0];
5595 for (int i = 0; i != 5; ++i)
5596 [[buttonbar_ viewWithTag:(i + 1)] setFrame:CGRectMake(
5597 i * 64 + 2, 1, 60, ButtonBarHeight_
5600 [buttonbar_ showSelectionForButton:1];
5601 [overlay_ addSubview:buttonbar_];
5603 [UIKeyboard initImplementationNow];
5604 CGSize keysize = [UIKeyboard defaultSize];
5605 CGRect keyrect = {{0, [overlay_ bounds].size.height}, keysize};
5606 keyboard_ = [[UIKeyboard alloc] initWithFrame:keyrect];
5607 [[UIKeyboardImpl sharedInstance] setSoundsEnabled:(Sounds_Keyboard_ ? YES : NO)];
5608 [overlay_ addSubview:keyboard_];
5610 install_ = [[InstallView alloc] initWithBook:book_ database:database_];
5611 changes_ = [[ChangesView alloc] initWithBook:book_ database:database_];
5612 manage_ = [[ManageView alloc] initWithBook:book_ database:database_];
5613 search_ = [[SearchView alloc] initWithBook:book_ database:database_];
5616 [underlay_ addSubview:overlay_];
5623 [self _setHomePage];
5626 - (void) reorganize {
5627 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5628 system("/usr/libexec/cydia/free.sh");
5629 [self performSelectorOnMainThread:@selector(finish) withObject:nil waitUntilDone:NO];
5633 - (void) applicationSuspend:(__GSEvent *)event {
5634 if (hud_ == nil && ![progress_ isRunning])
5635 [super applicationSuspend:event];
5638 - (void) _animateSuspension:(BOOL)arg0 duration:(double)arg1 startTime:(double)arg2 scale:(float)arg3 {
5640 [super _animateSuspension:arg0 duration:arg1 startTime:arg2 scale:arg3];
5643 - (void) _setSuspended:(BOOL)value {
5645 [super _setSuspended:value];
5648 - (void) applicationDidFinishLaunching:(id)unused {
5649 _assert(pkgInitConfig(*_config));
5650 _assert(pkgInitSystem(*_config, _system));
5655 essential_ = [[NSMutableArray alloc] initWithCapacity:4];
5656 broken_ = [[NSMutableArray alloc] initWithCapacity:4];
5658 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
5659 window_ = [[UIWindow alloc] initWithContentRect:screenrect];
5661 [window_ orderFront: self];
5662 [window_ makeKey: self];
5663 [window_ _setHidden: NO];
5665 database_ = [[Database alloc] init];
5666 progress_ = [[ProgressView alloc] initWithFrame:[window_ bounds] database:database_ delegate:self];
5667 [database_ setDelegate:progress_];
5668 [window_ setContentView:progress_];
5670 underlay_ = [[UIView alloc] initWithFrame:[progress_ bounds]];
5671 [progress_ setContentView:underlay_];
5673 [progress_ resetView];
5676 readlink("/Applications", NULL, 0) == -1 && errno == EINVAL ||
5677 readlink("/Library/Ringtones", NULL, 0) == -1 && errno == EINVAL ||
5678 readlink("/Library/Wallpaper", NULL, 0) == -1 && errno == EINVAL ||
5679 readlink("/usr/include", NULL, 0) == -1 && errno == EINVAL ||
5680 readlink("/usr/libexec", NULL, 0) == -1 && errno == EINVAL ||
5681 readlink("/usr/share", NULL, 0) == -1 && errno == EINVAL
5683 [self setIdleTimerDisabled:YES];
5685 hud_ = [[UIProgressHUD alloc] initWithWindow:window_];
5686 [hud_ setText:@"Reorganizing\n\nWill Automatically\nRestart When Done"];
5688 [underlay_ addSubview:hud_];
5690 [self setStatusBarShowsProgress:YES];
5693 detachNewThreadSelector:@selector(reorganize)
5701 - (void) showKeyboard:(BOOL)show {
5702 CGSize keysize = [UIKeyboard defaultSize];
5703 CGRect keydown = {{0, [overlay_ bounds].size.height}, keysize};
5704 CGRect keyup = keydown;
5705 keyup.origin.y -= keysize.height;
5707 UIFrameAnimation *animation = [[[UIFrameAnimation alloc] initWithTarget:keyboard_] autorelease];
5708 [animation setSignificantRectFields:2];
5711 [animation setStartFrame:keydown];
5712 [animation setEndFrame:keyup];
5713 [keyboard_ activate];
5715 [animation setStartFrame:keyup];
5716 [animation setEndFrame:keydown];
5717 [keyboard_ deactivate];
5720 [[UIAnimator sharedAnimator]
5721 addAnimations:[NSArray arrayWithObjects:animation, nil]
5722 withDuration:KeyboardTime_
5727 - (void) slideUp:(UIAlertSheet *)alert {
5729 [alert presentSheetFromButtonBar:buttonbar_];
5731 [alert presentSheetInView:overlay_];
5736 void AddPreferences(NSString *plist) {
5737 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5739 NSMutableDictionary *settings = [[[NSMutableDictionary alloc] initWithContentsOfFile:plist] autorelease];
5740 _assert(settings != NULL);
5741 NSMutableArray *items = [settings objectForKey:@"items"];
5745 for (size_t i(0); i != [items count]; ++i) {
5746 NSMutableDictionary *item([items objectAtIndex:i]);
5747 NSString *label = [item objectForKey:@"label"];
5748 if (label != nil && [label isEqualToString:@"Cydia"]) {
5755 for (size_t i(0); i != [items count]; ++i) {
5756 NSDictionary *item([items objectAtIndex:i]);
5757 NSString *label = [item objectForKey:@"label"];
5758 if (label != nil && [label isEqualToString:@"General"]) {
5759 [items insertObject:[NSDictionary dictionaryWithObjectsAndKeys:
5760 @"CydiaSettings", @"bundle",
5761 @"PSLinkCell", @"cell",
5762 [NSNumber numberWithBool:YES], @"hasIcon",
5763 [NSNumber numberWithBool:YES], @"isController",
5765 nil] atIndex:(i + 1)];
5771 _assert([settings writeToFile:plist atomically:YES] == YES);
5778 id Alloc_(id self, SEL selector) {
5779 id object = alloc_(self, selector);
5780 fprintf(stderr, "[%s]A-%p\n", self->isa->name, object);
5785 id Dealloc_(id self, SEL selector) {
5786 id object = dealloc_(self, selector);
5787 fprintf(stderr, "[%s]D-%p\n", self->isa->name, object);
5791 int main(int argc, char *argv[]) {
5792 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5794 bootstrap_ = argc > 1 && strcmp(argv[1], "--bootstrap") == 0;
5796 Home_ = NSHomeDirectory();
5799 NSString *plist = [Home_ stringByAppendingString:@"/Library/Preferences/com.apple.preferences.sounds.plist"];
5800 if (NSDictionary *sounds = [NSDictionary dictionaryWithContentsOfFile:plist])
5801 if (NSNumber *keyboard = [sounds objectForKey:@"keyboard"])
5802 Sounds_Keyboard_ = [keyboard boolValue];
5808 if (unlink("/var/cache/apt/pkgcache.bin") == -1)
5809 _assert(errno == ENOENT);
5810 if (unlink("/var/cache/apt/srcpkgcache.bin") == -1)
5811 _assert(errno == ENOENT);
5813 /*Method alloc = class_getClassMethod([NSObject class], @selector(alloc));
5814 alloc_ = alloc->method_imp;
5815 alloc->method_imp = (IMP) &Alloc_;*/
5817 /*Method dealloc = class_getClassMethod([NSObject class], @selector(dealloc));
5818 dealloc_ = dealloc->method_imp;
5819 dealloc->method_imp = (IMP) &Dealloc_;*/
5821 if (NSDictionary *sysver = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]) {
5822 if (NSString *prover = [sysver valueForKey:@"ProductVersion"]) {
5823 Firmware_ = strdup([prover UTF8String]);
5824 NSArray *versions = [prover componentsSeparatedByString:@"."];
5825 int count = [versions count];
5826 Major_ = count > 0 ? [[versions objectAtIndex:0] intValue] : 0;
5827 Minor_ = count > 1 ? [[versions objectAtIndex:1] intValue] : 0;
5828 BugFix_ = count > 2 ? [[versions objectAtIndex:2] intValue] : 0;
5833 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
5834 char *machine = new char[size];
5835 sysctlbyname("hw.machine", machine, &size, NULL, 0);
5838 if (CFMutableDictionaryRef dict = IOServiceMatching("IOPlatformExpertDevice"))
5839 if (io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, dict)) {
5840 if (CFTypeRef serial = IORegistryEntryCreateCFProperty(service, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0)) {
5841 SerialNumber_ = strdup(CFStringGetCStringPtr((CFStringRef) serial, CFStringGetSystemEncoding()));
5845 IOObjectRelease(service);
5848 /*AddPreferences(@"/Applications/Preferences.app/Settings-iPhone.plist");
5849 AddPreferences(@"/Applications/Preferences.app/Settings-iPod.plist");*/
5851 if ((Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"]) == NULL)
5852 Metadata_ = [[NSMutableDictionary alloc] initWithCapacity:2];
5854 Packages_ = [Metadata_ objectForKey:@"Packages"];
5855 Sections_ = [Metadata_ objectForKey:@"Sections"];
5858 if (access("/User", F_OK) != 0)
5859 system("/usr/libexec/cydia/firmware.sh");
5861 Locale_ = CFLocaleCopyCurrent();
5862 space_ = CGColorSpaceCreateDeviceRGB();
5864 Blueish_.Set(space_, 0x19/255.f, 0x32/255.f, 0x50/255.f, 1.0);
5865 Black_.Set(space_, 0.0, 0.0, 0.0, 1.0);
5866 Clear_.Set(space_, 0.0, 0.0, 0.0, 0.0);
5867 Red_.Set(space_, 1.0, 0.0, 0.0, 1.0);
5868 White_.Set(space_, 1.0, 1.0, 1.0, 1.0);
5870 int value = UIApplicationMain(argc, argv, [Cydia class]);
5872 CGColorSpaceRelease(space_);