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]];
147 kUIProgressIndicatorStyleMediumWhite = 1,
148 kUIProgressIndicatorStyleSmallWhite = 0,
149 kUIProgressIndicatorStyleSmallBlack = 4
150 } UIProgressIndicatorStyle;
153 kUIProgressIndicatorStyleMediumWhite = 0,
154 kUIProgressIndicatorStyleSmallWhite = 2,
155 kUIProgressIndicatorStyleSmallBlack = 3
156 } UIProgressIndicatorStyle;
160 kUIControlEventMouseDown = 1 << 0,
161 kUIControlEventMouseMovedInside = 1 << 2, // mouse moved inside control target
162 kUIControlEventMouseMovedOutside = 1 << 3, // mouse moved outside control target
163 kUIControlEventMouseUpInside = 1 << 6, // mouse up inside control target
164 kUIControlEventMouseUpOutside = 1 << 7, // mouse up outside control target
165 kUIControlAllEvents = (kUIControlEventMouseDown | kUIControlEventMouseMovedInside | kUIControlEventMouseMovedOutside | kUIControlEventMouseUpInside | kUIControlEventMouseUpOutside)
166 } UIControlEventMasks;
168 @interface NSString (UIKit)
169 - (NSString *) stringByAddingPercentEscapes;
170 - (NSString *) stringByReplacingCharacter:(unsigned short)arg0 withCharacter:(unsigned short)arg1;
173 @interface NSString (Cydia)
174 + (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length;
175 - (NSComparisonResult) compareByPath:(NSString *)other;
178 @implementation NSString (Cydia)
180 + (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length {
181 char data[length + 1];
182 memcpy(data, bytes, length);
184 return [NSString stringWithUTF8String:data];
187 - (NSComparisonResult) compareByPath:(NSString *)other {
188 NSString *prefix = [self commonPrefixWithString:other options:0];
189 size_t length = [prefix length];
191 NSRange lrange = NSMakeRange(length, [self length] - length);
192 NSRange rrange = NSMakeRange(length, [other length] - length);
194 lrange = [self rangeOfString:@"/" options:0 range:lrange];
195 rrange = [other rangeOfString:@"/" options:0 range:rrange];
197 NSComparisonResult value;
199 if (lrange.location == NSNotFound && rrange.location == NSNotFound)
200 value = NSOrderedSame;
201 else if (lrange.location == NSNotFound)
202 value = NSOrderedAscending;
203 else if (rrange.location == NSNotFound)
204 value = NSOrderedDescending;
206 value = NSOrderedSame;
208 NSString *lpath = lrange.location == NSNotFound ? [self substringFromIndex:length] :
209 [self substringWithRange:NSMakeRange(length, lrange.location - length)];
210 NSString *rpath = rrange.location == NSNotFound ? [other substringFromIndex:length] :
211 [other substringWithRange:NSMakeRange(length, rrange.location - length)];
213 NSComparisonResult result = [lpath compare:rpath];
214 return result == NSOrderedSame ? value : result;
219 /* Perl-Compatible RegEx {{{ */
229 Pcre(const char *regex) :
234 code_ = pcre_compile(regex, 0, &error, &offset, NULL);
237 fprintf(stderr, "%d:%s\n", offset, error);
241 pcre_fullinfo(code_, study_, PCRE_INFO_CAPTURECOUNT, &capture_);
242 matches_ = new int[(capture_ + 1) * 3];
250 NSString *operator [](size_t match) {
251 return [NSString stringWithUTF8Bytes:(data_ + matches_[match * 2]) length:(matches_[match * 2 + 1] - matches_[match * 2])];
254 bool operator ()(NSString *data) {
255 // XXX: length is for characters, not for bytes
256 return operator ()([data UTF8String], [data length]);
259 bool operator ()(const char *data, size_t size) {
261 return pcre_exec(code_, study_, data, size, 0, 0, matches_, (capture_ + 1) * 3) >= 0;
265 /* Mime Addresses {{{ */
266 Pcre email_r("^\"?(.*)\"? <([^>]*)>$");
268 @interface Address : NSObject {
274 - (NSString *) email;
276 + (Address *) addressWithString:(NSString *)string;
277 - (Address *) initWithString:(NSString *)string;
280 @implementation Address
289 - (NSString *) name {
293 - (NSString *) email {
297 + (Address *) addressWithString:(NSString *)string {
298 return [[[Address alloc] initWithString:string] autorelease];
301 - (Address *) initWithString:(NSString *)string {
302 if ((self = [super init]) != nil) {
303 const char *data = [string UTF8String];
304 size_t size = [string length];
306 if (email_r(data, size)) {
307 name_ = [email_r[1] retain];
308 email_ = [email_r[2] retain];
310 name_ = [[NSString alloc]
313 encoding:kCFStringEncodingUTF8
323 /* CoreGraphics Primitives {{{ */
334 CGColor(CGColorSpaceRef space, float red, float green, float blue, float alpha) :
337 Set(space, red, green, blue, alpha);
342 CGColorRelease(color_);
349 void Set(CGColorSpaceRef space, float red, float green, float blue, float alpha) {
351 float color[] = {red, green, blue, alpha};
352 color_ = CGColorCreate(space, color);
355 operator CGColorRef() {
370 /* Right Alignment {{{ */
371 @interface UIRightTextLabel : UITextLabel {
372 float _savedRightEdgeX;
373 BOOL _sizedtofit_flag;
376 - (void) setFrame:(CGRect)frame;
377 - (void) setText:(NSString *)text;
378 - (void) realignText;
381 @implementation UIRightTextLabel
383 - (void) setFrame:(CGRect)frame {
384 [super setFrame:frame];
385 if (_sizedtofit_flag == NO) {
386 _savedRightEdgeX = frame.origin.x;
391 - (void) setText:(NSString *)text {
392 [super setText:text];
396 - (void) realignText {
397 CGRect oldFrame = [self frame];
399 _sizedtofit_flag = YES;
400 [self sizeToFit]; // shrink down size so I can right align it
402 CGRect newFrame = [self frame];
404 oldFrame.origin.x = _savedRightEdgeX - newFrame.size.width;
405 oldFrame.size.width = newFrame.size.width;
406 [super setFrame:oldFrame];
407 _sizedtofit_flag = NO;
413 /* Random Global Variables {{{ */
414 static const int PulseInterval_ = 50000;
415 static const int ButtonBarHeight_ = 48;
416 static const float KeyboardTime_ = 0.3f;
417 static const char * const SpringBoard_ = "/System/Library/LaunchDaemons/com.apple.SpringBoard.plist";
423 static CGColor Blueish_;
424 static CGColor Black_;
425 static CGColor Clear_;
427 static CGColor White_;
429 static NSString *Home_;
430 static BOOL Sounds_Keyboard_;
432 static BOOL Advanced_;
434 static BOOL Ignored_;
436 const char *Firmware_ = NULL;
437 const char *Machine_ = NULL;
438 const char *SerialNumber_ = NULL;
445 CGColorSpaceRef space_;
447 #define FW_LEAST(major, minor, bugfix) \
448 (major < Major_ || major == Major_ && \
449 (minor < Minor_ || minor == Minor_ && \
455 static NSMutableDictionary *Metadata_;
456 static NSMutableDictionary *Packages_;
457 static NSMutableDictionary *Sections_;
458 static bool Changed_;
461 NSString *GetLastUpdate() {
462 NSDate *update = [Metadata_ objectForKey:@"LastUpdate"];
465 return @"Never or Unknown";
467 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, Locale_, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
468 CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) update);
470 CFRelease(formatter);
472 return [(NSString *) formatted autorelease];
475 /* Display Helpers {{{ */
476 inline float Interpolate(float begin, float end, float fraction) {
477 return (end - begin) * fraction + begin;
480 NSString *SizeString(double size) {
482 while (size > 1024) {
487 static const char *powers_[] = {"B", "kB", "MB", "GB"};
489 return [NSString stringWithFormat:@"%.1f%s", size, powers_[power]];
492 NSString *StripVersion(NSString *version) {
493 NSRange colon = [version rangeOfString:@":"];
494 if (colon.location != NSNotFound)
495 version = [version substringFromIndex:(colon.location + 1)];
499 static const float TextViewOffset_ = 22;
501 UITextView *GetTextView(NSString *value, float left, bool html) {
502 UITextView *text([[[UITextView alloc] initWithFrame:CGRectMake(left, 3, 310 - left, 1000)] autorelease]);
503 [text setEditable:NO];
504 [text setTextSize:16];
506 [text setHTML:value];
508 [text setText:value];
509 [text setEnabled:NO];
511 [text setBackgroundColor:Clear_];
513 CGRect frame = [text frame];
514 [text setFrame:frame];
515 CGRect rect = [text visibleTextRect];
516 frame.size.height = rect.size.height;
517 [text setFrame:frame];
522 NSString *Simplify(NSString *title) {
523 const char *data = [title UTF8String];
524 size_t size = [title length];
526 Pcre title_r("^(.*?)( \\(.*\\))?$");
527 if (title_r(data, size))
534 bool isSectionVisible(NSString *section) {
535 NSDictionary *metadata = [Sections_ objectForKey:section];
536 NSNumber *hidden = metadata == nil ? nil : [metadata objectForKey:@"Hidden"];
537 return hidden == nil || ![hidden boolValue];
540 /* Delegate Prototypes {{{ */
544 @interface NSObject (ProgressDelegate)
547 @implementation NSObject(ProgressDelegate)
549 - (void) _setProgressError:(NSArray *)args {
550 [self performSelector:@selector(setProgressError:forPackage:)
551 withObject:[args objectAtIndex:0]
552 withObject:([args count] == 1 ? nil : [args objectAtIndex:1])
558 @protocol ProgressDelegate
559 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id;
560 - (void) setProgressTitle:(NSString *)title;
561 - (void) setProgressPercent:(float)percent;
562 - (void) addProgressOutput:(NSString *)output;
565 @protocol ConfigurationDelegate
566 - (void) repairWithSelector:(SEL)selector;
567 - (void) setConfigurationData:(NSString *)data;
570 @protocol CydiaDelegate
571 - (void) installPackage:(Package *)package;
572 - (void) removePackage:(Package *)package;
573 - (void) slideUp:(UIAlertSheet *)alert;
574 - (void) distUpgrade;
579 /* Status Delegation {{{ */
581 public pkgAcquireStatus
584 _transient NSObject<ProgressDelegate> *delegate_;
592 void setDelegate(id delegate) {
593 delegate_ = delegate;
596 virtual bool MediaChange(std::string media, std::string drive) {
600 virtual void IMSHit(pkgAcquire::ItemDesc &item) {
603 virtual void Fetch(pkgAcquire::ItemDesc &item) {
604 [delegate_ setProgressTitle:[NSString stringWithUTF8String:("Downloading " + item.ShortDesc).c_str()]];
607 virtual void Done(pkgAcquire::ItemDesc &item) {
610 virtual void Fail(pkgAcquire::ItemDesc &item) {
612 item.Owner->Status == pkgAcquire::Item::StatIdle ||
613 item.Owner->Status == pkgAcquire::Item::StatDone
617 [delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
618 withObject:[NSArray arrayWithObjects:[NSString stringWithUTF8String:item.Owner->ErrorText.c_str()], nil]
623 virtual bool Pulse(pkgAcquire *Owner) {
624 bool value = pkgAcquireStatus::Pulse(Owner);
627 double(CurrentBytes + CurrentItems) /
628 double(TotalBytes + TotalItems)
631 [delegate_ setProgressPercent:percent];
635 virtual void Start() {
638 virtual void Stop() {
642 /* Progress Delegation {{{ */
647 _transient id<ProgressDelegate> delegate_;
650 virtual void Update() {
651 [delegate_ setProgressTitle:[NSString stringWithUTF8String:Op.c_str()]];
652 [delegate_ setProgressPercent:(Percent / 100)];
661 void setDelegate(id delegate) {
662 delegate_ = delegate;
665 virtual void Done() {
666 [delegate_ setProgressPercent:1];
671 /* Database Interface {{{ */
672 @interface Database : NSObject {
674 pkgDepCache::Policy *policy_;
675 pkgRecords *records_;
676 pkgProblemResolver *resolver_;
677 pkgAcquire *fetcher_;
679 SPtr<pkgPackageManager> manager_;
680 pkgSourceList *list_;
682 NSMutableDictionary *sources_;
683 NSMutableArray *packages_;
685 _transient NSObject<ConfigurationDelegate, ProgressDelegate> *delegate_;
694 - (void) _readCydia:(NSNumber *)fd;
695 - (void) _readStatus:(NSNumber *)fd;
696 - (void) _readOutput:(NSNumber *)fd;
700 - (Package *) packageWithName:(NSString *)name;
703 - (pkgCacheFile &) cache;
704 - (pkgDepCache::Policy *) policy;
705 - (pkgRecords *) records;
706 - (pkgProblemResolver *) resolver;
707 - (pkgAcquire &) fetcher;
708 - (NSArray *) packages;
717 - (void) updateWithStatus:(Status &)status;
719 - (void) setDelegate:(id)delegate;
720 - (Source *) getSource:(const pkgCache::PkgFileIterator &)file;
724 /* Source Class {{{ */
725 @interface Source : NSObject {
726 NSString *description_;
731 NSString *distribution_;
735 NSString *defaultIcon_;
740 - (Source *) initWithMetaIndex:(metaIndex *)index;
745 - (NSString *) distribution;
748 - (NSString *) description;
749 - (NSString *) label;
750 - (NSString *) origin;
751 - (NSString *) version;
753 - (NSString *) defaultIcon;
756 @implementation Source
760 [distribution_ release];
763 if (description_ != nil)
764 [description_ release];
771 if (defaultIcon_ != nil)
772 [defaultIcon_ release];
777 - (Source *) initWithMetaIndex:(metaIndex *)index {
778 if ((self = [super init]) != nil) {
779 trusted_ = index->IsTrusted();
781 uri_ = [[NSString stringWithUTF8String:index->GetURI().c_str()] retain];
782 distribution_ = [[NSString stringWithUTF8String:index->GetDist().c_str()] retain];
783 type_ = [[NSString stringWithUTF8String:index->GetType()] retain];
791 debReleaseIndex *dindex(dynamic_cast<debReleaseIndex *>(index));
792 if (dindex != NULL) {
793 std::ifstream release(dindex->MetaIndexFile("Release").c_str());
795 while (std::getline(release, line)) {
796 std::string::size_type colon(line.find(':'));
797 if (colon == std::string::npos)
800 std::string name(line.substr(0, colon));
801 std::string value(line.substr(colon + 1));
802 while (!value.empty() && value[0] == ' ')
803 value = value.substr(1);
805 if (name == "Default-Icon")
806 defaultIcon_ = [[NSString stringWithUTF8String:value.c_str()] retain];
807 else if (name == "Description")
808 description_ = [[NSString stringWithUTF8String:value.c_str()] retain];
809 else if (name == "Label")
810 label_ = [[NSString stringWithUTF8String:value.c_str()] retain];
811 else if (name == "Origin")
812 origin_ = [[NSString stringWithUTF8String:value.c_str()] retain];
813 else if (name == "Version")
814 version_ = [[NSString stringWithUTF8String:value.c_str()] retain];
828 - (NSString *) distribution {
829 return distribution_;
832 - (NSString *) type {
836 - (NSString *) description {
840 - (NSString *) label {
844 - (NSString *) origin {
848 - (NSString *) version {
852 - (NSString *) defaultIcon {
858 /* Relationship Class {{{ */
859 @interface Relationship : NSObject {
870 @implementation Relationship
878 - (NSString *) type {
886 - (NSString *) name {
893 /* Package Class {{{ */
894 NSString *Scour(const char *field, const char *begin, const char *end) {
895 size_t i(0), l(strlen(field));
898 const char *name = begin + i;
899 const char *colon = name + l;
900 const char *value = colon + 1;
905 memcmp(name, field, l) == 0
907 while (value != end && value[0] == ' ')
909 const char *line = std::find(value, end, '\n');
910 while (line != value && line[-1] == ' ')
913 return [NSString stringWithUTF8Bytes:value length:(line - value)];
915 begin = std::find(begin, end, '\n');
923 @interface Package : NSObject {
924 pkgCache::PkgIterator iterator_;
925 _transient Database *database_;
926 pkgCache::VerIterator version_;
927 pkgCache::VerFileIterator file_;
933 NSString *installed_;
944 NSArray *relationships_;
947 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
948 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
950 - (pkgCache::PkgIterator) iterator;
952 - (NSString *) section;
953 - (Address *) maintainer;
955 - (NSString *) description;
956 - (NSString *) index;
960 - (NSString *) latest;
961 - (NSString *) installed;
964 - (BOOL) upgradableAndEssential:(BOOL)essential;
970 - (BOOL) halfConfigured;
971 - (BOOL) halfInstalled;
977 - (NSString *) tagline;
979 - (NSString *) website;
980 - (Address *) author;
982 - (NSArray *) relationships;
986 - (BOOL) matches:(NSString *)text;
988 - (bool) hasUsefulPurpose;
989 - (BOOL) hasTag:(NSString *)tag;
991 - (NSComparisonResult) compareByName:(Package *)package;
992 - (NSComparisonResult) compareBySection:(Package *)package;
993 - (NSComparisonResult) compareBySectionAndName:(Package *)package;
994 - (NSComparisonResult) compareForChanges:(Package *)package;
999 - (NSNumber *) isSearchedForBy:(NSString *)search;
1000 - (NSNumber *) isInstalledInSection:(NSString *)section;
1001 - (NSNumber *) isUninstalledInSection:(NSString *)section;
1005 @implementation Package
1012 if (installed_ != nil)
1013 [installed_ release];
1021 if (website_ != nil)
1023 if (sponsor_ != nil)
1030 if (relationships_ != nil)
1031 [relationships_ release];
1036 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
1037 if ((self = [super init]) != nil) {
1038 iterator_ = iterator;
1039 database_ = database;
1041 version_ = [database_ policy]->GetCandidateVer(iterator_);
1042 latest_ = version_.end() ? nil : [StripVersion([NSString stringWithUTF8String:version_.VerStr()]) retain];
1044 if (!version_.end())
1045 file_ = version_.FileList();
1047 pkgCache &cache([database_ cache]);
1048 file_ = pkgCache::VerFileIterator(cache, cache.VerFileP);
1051 pkgCache::VerIterator current = iterator_.CurrentVer();
1052 installed_ = current.end() ? nil : [StripVersion([NSString stringWithUTF8String:current.VerStr()]) retain];
1054 id_ = [[[NSString stringWithUTF8String:iterator_.Name()] lowercaseString] retain];
1057 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1059 const char *begin, *end;
1060 parser->GetRec(begin, end);
1062 name_ = Scour("Name", begin, end);
1064 name_ = [name_ retain];
1065 tagline_ = [[NSString stringWithUTF8String:parser->ShortDesc().c_str()] retain];
1066 icon_ = Scour("Icon", begin, end);
1068 icon_ = [icon_ retain];
1069 website_ = Scour("Homepage", begin, end);
1070 if (website_ == nil)
1071 website_ = Scour("Website", begin, end);
1072 if (website_ != nil)
1073 website_ = [website_ retain];
1074 NSString *sponsor = Scour("Sponsor", begin, end);
1076 sponsor_ = [[Address addressWithString:sponsor] retain];
1077 NSString *author = Scour("Author", begin, end);
1079 author_ = [[Address addressWithString:author] retain];
1080 NSString *tags = Scour("Tag", begin, end);
1082 tags_ = [[tags componentsSeparatedByString:@", "] retain];
1085 NSMutableDictionary *metadata = [Packages_ objectForKey:id_];
1086 if (metadata == nil || [metadata count] == 0) {
1087 metadata = [NSMutableDictionary dictionaryWithObjectsAndKeys:
1091 [Packages_ setObject:metadata forKey:id_];
1097 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
1098 return [[[Package alloc]
1099 initWithIterator:iterator
1104 - (pkgCache::PkgIterator) iterator {
1108 - (NSString *) section {
1109 const char *section = iterator_.Section();
1110 return section == NULL ? nil : [[NSString stringWithUTF8String:section] stringByReplacingCharacter:'_' withCharacter:' '];
1113 - (Address *) maintainer {
1116 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1117 return [Address addressWithString:[NSString stringWithUTF8String:parser->Maintainer().c_str()]];
1121 return version_.end() ? 0 : version_->InstalledSize;
1124 - (NSString *) description {
1127 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1128 NSString *description([NSString stringWithUTF8String:parser->LongDesc().c_str()]);
1130 NSArray *lines = [description componentsSeparatedByString:@"\n"];
1131 NSMutableArray *trimmed = [NSMutableArray arrayWithCapacity:([lines count] - 1)];
1132 if ([lines count] < 2)
1135 NSCharacterSet *whitespace = [NSCharacterSet whitespaceCharacterSet];
1136 for (size_t i(1); i != [lines count]; ++i) {
1137 NSString *trim = [[lines objectAtIndex:i] stringByTrimmingCharactersInSet:whitespace];
1138 [trimmed addObject:trim];
1141 return [trimmed componentsJoinedByString:@"\n"];
1144 - (NSString *) index {
1145 NSString *index = [[[self name] substringToIndex:1] uppercaseString];
1146 return [index length] != 0 && isalpha([index characterAtIndex:0]) ? index : @"123";
1150 return [[Packages_ objectForKey:id_] objectForKey:@"FirstSeen"];
1153 - (NSString *) latest {
1157 - (NSString *) installed {
1162 return !version_.end();
1165 - (BOOL) upgradableAndEssential:(BOOL)essential {
1166 pkgCache::VerIterator current = iterator_.CurrentVer();
1169 return essential && [self essential];
1171 pkgCache::VerIterator candidate = [database_ policy]->GetCandidateVer(iterator_);
1172 return !candidate.end() && candidate != current;
1176 - (BOOL) essential {
1177 return (iterator_->Flags & pkgCache::Flag::Essential) == 0 ? NO : YES;
1181 return [database_ cache][iterator_].InstBroken();
1185 NSString *section = [self section];
1186 return [self hasUsefulPurpose] && (section == nil || isSectionVisible(section));
1190 unsigned char current = iterator_->CurrentState;
1191 return current == pkgCache::State::HalfConfigured || current == pkgCache::State::HalfInstalled;
1194 - (BOOL) halfConfigured {
1195 return iterator_->CurrentState == pkgCache::State::HalfConfigured;
1198 - (BOOL) halfInstalled {
1199 return iterator_->CurrentState == pkgCache::State::HalfInstalled;
1203 pkgDepCache::StateCache &state([database_ cache][iterator_]);
1204 return state.Mode != pkgDepCache::ModeKeep;
1207 - (NSString *) mode {
1208 pkgDepCache::StateCache &state([database_ cache][iterator_]);
1210 switch (state.Mode) {
1211 case pkgDepCache::ModeDelete:
1212 if ((state.iFlags & pkgDepCache::Purge) != 0)
1217 case pkgDepCache::ModeKeep:
1218 if ((state.iFlags & pkgDepCache::AutoKept) != 0)
1223 case pkgDepCache::ModeInstall:
1224 if ((state.iFlags & pkgDepCache::ReInstall) != 0)
1225 return @"Reinstall";
1226 else switch (state.Status) {
1228 return @"Downgrade";
1234 return @"New Install";
1247 - (NSString *) name {
1248 return name_ == nil ? id_ : name_;
1251 - (NSString *) tagline {
1255 - (NSString *) icon {
1259 - (NSString *) website {
1263 - (Address *) sponsor {
1267 - (Address *) author {
1271 - (NSArray *) relationships {
1272 return relationships_;
1275 - (Source *) source {
1277 source_ = file_.end() ? nil : [[database_ getSource:file_.File()] retain];
1284 - (BOOL) matches:(NSString *)text {
1290 range = [[self id] rangeOfString:text options:NSCaseInsensitiveSearch];
1291 if (range.location != NSNotFound)
1294 range = [[self name] rangeOfString:text options:NSCaseInsensitiveSearch];
1295 if (range.location != NSNotFound)
1298 range = [[self tagline] rangeOfString:text options:NSCaseInsensitiveSearch];
1299 if (range.location != NSNotFound)
1305 - (bool) hasUsefulPurpose {
1308 bool purpose(false);
1310 for (int i(0), e([tags_ count]); i != e; ++i) {
1311 NSString *tag = [tags_ objectAtIndex:i];
1312 if ([tag hasPrefix:@"purpose::"]) {
1313 bool purpose(false);
1314 if ([tag isEqualToString:@"purpose::console"]) {
1316 } else if ([tag isEqualToString:@"purpose::library"]) {
1318 } else if ([tag isEqualToString:@"purpose::x"]) {
1328 - (BOOL) hasTag:(NSString *)tag {
1329 return tags_ == nil ? NO : [tags_ containsObject:tag];
1332 - (NSComparisonResult) compareByName:(Package *)package {
1333 NSString *lhs = [self name];
1334 NSString *rhs = [package name];
1336 if ([lhs length] != 0 && [rhs length] != 0) {
1337 unichar lhc = [lhs characterAtIndex:0];
1338 unichar rhc = [rhs characterAtIndex:0];
1340 if (isalpha(lhc) && !isalpha(rhc))
1341 return NSOrderedAscending;
1342 else if (!isalpha(lhc) && isalpha(rhc))
1343 return NSOrderedDescending;
1346 return [lhs caseInsensitiveCompare:rhs];
1349 - (NSComparisonResult) compareBySection:(Package *)package {
1350 NSString *lhs = [self section];
1351 NSString *rhs = [package section];
1353 if (lhs == NULL && rhs != NULL)
1354 return NSOrderedAscending;
1355 else if (lhs != NULL && rhs == NULL)
1356 return NSOrderedDescending;
1357 else if (lhs != NULL && rhs != NULL) {
1358 NSComparisonResult result = [lhs caseInsensitiveCompare:rhs];
1359 if (result != NSOrderedSame)
1363 return NSOrderedSame;
1366 - (NSComparisonResult) compareBySectionAndName:(Package *)package {
1367 NSString *lhs = [self section];
1368 NSString *rhs = [package section];
1370 if (lhs == NULL && rhs != NULL)
1371 return NSOrderedAscending;
1372 else if (lhs != NULL && rhs == NULL)
1373 return NSOrderedDescending;
1374 else if (lhs != NULL && rhs != NULL) {
1375 NSComparisonResult result = [lhs compare:rhs];
1376 if (result != NSOrderedSame)
1380 return [self compareByName:package];
1383 - (NSComparisonResult) compareForChanges:(Package *)package {
1384 BOOL lhs = [self upgradableAndEssential:YES];
1385 BOOL rhs = [package upgradableAndEssential:YES];
1388 return lhs ? NSOrderedAscending : NSOrderedDescending;
1390 switch ([[self seen] compare:[package seen]]) {
1391 case NSOrderedAscending:
1392 return NSOrderedDescending;
1395 case NSOrderedDescending:
1396 return NSOrderedAscending;
1402 return [self compareByName:package];
1406 pkgProblemResolver *resolver = [database_ resolver];
1407 resolver->Clear(iterator_);
1408 resolver->Protect(iterator_);
1409 pkgCacheFile &cache([database_ cache]);
1410 cache->MarkInstall(iterator_, false);
1411 pkgDepCache::StateCache &state((*cache)[iterator_]);
1412 if (!state.Install())
1413 cache->SetReInstall(iterator_, true);
1417 pkgProblemResolver *resolver = [database_ resolver];
1418 resolver->Clear(iterator_);
1419 resolver->Protect(iterator_);
1420 resolver->Remove(iterator_);
1421 [database_ cache]->MarkDelete(iterator_, true);
1424 - (NSNumber *) isSearchedForBy:(NSString *)search {
1425 return [NSNumber numberWithBool:([self valid] && [self matches:search])];
1428 - (NSNumber *) isInstalledInSection:(NSString *)section {
1429 return [NSNumber numberWithBool:([self installed] != nil && (section == nil || [section isEqualToString:[self section]]))];
1432 - (NSNumber *) isUninstalledInSection:(NSString *)name {
1433 NSString *section = [self section];
1435 return [NSNumber numberWithBool:([self valid] && [self installed] == nil && (
1436 (name == nil && [self visible] ||
1437 section == nil && [name length] == 0 ||
1438 [name isEqualToString:section])
1444 /* Section Class {{{ */
1445 @interface Section : NSObject {
1451 - (NSComparisonResult) compareByName:(Section *)section;
1452 - (Section *) initWithName:(NSString *)name;
1453 - (Section *) initWithName:(NSString *)name row:(size_t)row;
1454 - (NSString *) name;
1457 - (void) addToCount;
1461 @implementation Section
1468 - (NSComparisonResult) compareByName:(Section *)section {
1469 NSString *lhs = [self name];
1470 NSString *rhs = [section name];
1472 if ([lhs length] != 0 && [rhs length] != 0) {
1473 unichar lhc = [lhs characterAtIndex:0];
1474 unichar rhc = [rhs characterAtIndex:0];
1476 if (isalpha(lhc) && !isalpha(rhc))
1477 return NSOrderedAscending;
1478 else if (!isalpha(lhc) && isalpha(rhc))
1479 return NSOrderedDescending;
1482 return [lhs caseInsensitiveCompare:rhs];
1485 - (Section *) initWithName:(NSString *)name {
1486 return [self initWithName:name row:0];
1489 - (Section *) initWithName:(NSString *)name row:(size_t)row {
1490 if ((self = [super init]) != nil) {
1491 name_ = [name retain];
1496 - (NSString *) name {
1508 - (void) addToCount {
1515 /* Database Implementation {{{ */
1516 @implementation Database
1523 - (void) _readCydia:(NSNumber *)fd {
1524 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1526 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1527 std::istream is(&ib);
1530 while (std::getline(is, line)) {
1531 const char *data(line.c_str());
1532 //size_t size = line.size();
1533 fprintf(stderr, "C:%s\n", data);
1540 - (void) _readStatus:(NSNumber *)fd {
1541 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1543 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1544 std::istream is(&ib);
1547 Pcre conffile_r("^status: [^ ]* : conffile-prompt : (.*?) *$");
1548 Pcre pmstatus_r("^([^:]*):([^:]*):([^:]*):(.*)$");
1550 while (std::getline(is, line)) {
1551 const char *data(line.c_str());
1552 size_t size = line.size();
1553 fprintf(stderr, "S:%s\n", data);
1555 if (conffile_r(data, size)) {
1556 [delegate_ setConfigurationData:conffile_r[1]];
1557 } else if (strncmp(data, "status: ", 8) == 0) {
1558 NSString *string = [NSString stringWithUTF8String:(data + 8)];
1559 [delegate_ setProgressTitle:string];
1560 } else if (pmstatus_r(data, size)) {
1561 std::string type([pmstatus_r[1] UTF8String]);
1562 NSString *id = pmstatus_r[2];
1564 float percent([pmstatus_r[3] floatValue]);
1565 [delegate_ setProgressPercent:(percent / 100)];
1567 NSString *string = pmstatus_r[4];
1569 if (type == "pmerror")
1570 [delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
1571 withObject:[NSArray arrayWithObjects:string, id, nil]
1574 else if (type == "pmstatus")
1575 [delegate_ setProgressTitle:string];
1576 else if (type == "pmconffile")
1577 [delegate_ setConfigurationData:string];
1578 else _assert(false);
1579 } else _assert(false);
1586 - (void) _readOutput:(NSNumber *)fd {
1587 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1589 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1590 std::istream is(&ib);
1593 while (std::getline(is, line)) {
1594 fprintf(stderr, "O:%s\n", line.c_str());
1595 [delegate_ addProgressOutput:[NSString stringWithUTF8String:line.c_str()]];
1606 - (Package *) packageWithName:(NSString *)name {
1607 if (static_cast<pkgDepCache *>(cache_) == NULL)
1609 pkgCache::PkgIterator iterator(cache_->FindPkg([name UTF8String]));
1610 return iterator.end() ? nil : [Package packageWithIterator:iterator database:self];
1613 - (Database *) init {
1614 if ((self = [super init]) != nil) {
1621 sources_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1622 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
1626 _assert(pipe(fds) != -1);
1629 _config->Set("APT::Keep-Fds::", cydiafd_);
1630 setenv("CYDIA", [[[[NSNumber numberWithInt:cydiafd_] stringValue] stringByAppendingString:@" 0"] UTF8String], _not(int));
1633 detachNewThreadSelector:@selector(_readCydia:)
1635 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1638 _assert(pipe(fds) != -1);
1642 detachNewThreadSelector:@selector(_readStatus:)
1644 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1647 _assert(pipe(fds) != -1);
1648 _assert(dup2(fds[0], 0) != -1);
1649 _assert(close(fds[0]) != -1);
1651 input_ = fdopen(fds[1], "a");
1653 _assert(pipe(fds) != -1);
1654 _assert(dup2(fds[1], 1) != -1);
1655 _assert(close(fds[1]) != -1);
1658 detachNewThreadSelector:@selector(_readOutput:)
1660 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1665 - (pkgCacheFile &) cache {
1669 - (pkgDepCache::Policy *) policy {
1673 - (pkgRecords *) records {
1677 - (pkgProblemResolver *) resolver {
1681 - (pkgAcquire &) fetcher {
1685 - (NSArray *) packages {
1689 - (void) reloadData {
1708 if (!cache_.Open(progress_, true)) {
1710 if (!_error->PopMessage(error))
1713 fprintf(stderr, "cache_.Open():[%s]\n", error.c_str());
1715 if (error == "dpkg was interrupted, you must manually run 'dpkg --configure -a' to correct the problem. ")
1716 [delegate_ repairWithSelector:@selector(configure)];
1717 else if (error == "The package lists or status file could not be parsed or opened.")
1718 [delegate_ repairWithSelector:@selector(update)];
1719 // else if (error == "Could not open lock file /var/lib/dpkg/lock - open (13 Permission denied)")
1720 // else if (error == "Could not get lock /var/lib/dpkg/lock - open (35 Resource temporarily unavailable)")
1721 // else if (error == "The list of sources could not be read.")
1722 else _assert(false);
1727 now_ = [[NSDate date] retain];
1729 policy_ = new pkgDepCache::Policy();
1730 records_ = new pkgRecords(cache_);
1731 resolver_ = new pkgProblemResolver(cache_);
1732 fetcher_ = new pkgAcquire(&status_);
1735 list_ = new pkgSourceList();
1736 _assert(list_->ReadMainList());
1738 _assert(cache_->DelCount() == 0 && cache_->InstCount() == 0);
1739 _assert(pkgApplyStatus(cache_));
1741 if (cache_->BrokenCount() != 0) {
1742 _assert(pkgFixBroken(cache_));
1743 _assert(cache_->BrokenCount() == 0);
1744 _assert(pkgMinimizeUpgrade(cache_));
1747 [sources_ removeAllObjects];
1748 for (pkgSourceList::const_iterator source = list_->begin(); source != list_->end(); ++source) {
1749 std::vector<pkgIndexFile *> *indices = (*source)->GetIndexFiles();
1750 for (std::vector<pkgIndexFile *>::const_iterator index = indices->begin(); index != indices->end(); ++index)
1752 setObject:[[[Source alloc] initWithMetaIndex:*source] autorelease]
1753 forKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(*index)]
1757 [packages_ removeAllObjects];
1758 for (pkgCache::PkgIterator iterator = cache_->PkgBegin(); !iterator.end(); ++iterator)
1759 if (Package *package = [Package packageWithIterator:iterator database:self])
1760 [packages_ addObject:package];
1762 [packages_ sortUsingSelector:@selector(compareByName:)];
1765 - (void) configure {
1766 NSString *dpkg = [NSString stringWithFormat:@"dpkg --configure -a --status-fd %u", statusfd_];
1767 system([dpkg UTF8String]);
1775 Lock.Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1776 _assert(!_error->PendingError());
1779 fetcher.Clean(_config->FindDir("Dir::Cache::Archives"));
1782 public pkgArchiveCleaner
1785 virtual void Erase(const char *File, std::string Pkg, std::string Ver, struct stat &St) {
1790 if (!cleaner.Go(_config->FindDir("Dir::Cache::Archives") + "partial/", cache_)) {
1792 while (_error->PopMessage(error))
1793 fprintf(stderr, "ArchiveCleaner: %s\n", error.c_str());
1798 pkgRecords records(cache_);
1800 lock_ = new FileFd();
1801 lock_->Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1802 _assert(!_error->PendingError());
1805 // XXX: explain this with an error message
1806 _assert(list.ReadMainList());
1808 manager_ = (_system->CreatePM(cache_));
1809 _assert(manager_->GetArchives(fetcher_, &list, &records));
1810 _assert(!_error->PendingError());
1814 NSMutableArray *before = [NSMutableArray arrayWithCapacity:16]; {
1816 _assert(list.ReadMainList());
1817 for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source)
1818 [before addObject:[NSString stringWithUTF8String:(*source)->GetURI().c_str()]];
1821 if (fetcher_->Run(PulseInterval_) != pkgAcquire::Continue) {
1826 bool failed = false;
1827 for (pkgAcquire::ItemIterator item = fetcher_->ItemsBegin(); item != fetcher_->ItemsEnd(); item++) {
1828 if ((*item)->Status == pkgAcquire::Item::StatDone && (*item)->Complete)
1831 std::string uri = (*item)->DescURI();
1832 std::string error = (*item)->ErrorText;
1834 fprintf(stderr, "pAf:%s:%s\n", uri.c_str(), error.c_str());
1837 [delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
1838 withObject:[NSArray arrayWithObjects:[NSString stringWithUTF8String:error.c_str()], nil]
1849 pkgPackageManager::OrderResult result = manager_->DoInstall(statusfd_);
1851 if (_error->PendingError()) {
1856 if (result == pkgPackageManager::Failed) {
1861 if (result != pkgPackageManager::Completed) {
1866 NSMutableArray *after = [NSMutableArray arrayWithCapacity:16]; {
1868 _assert(list.ReadMainList());
1869 for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source)
1870 [after addObject:[NSString stringWithUTF8String:(*source)->GetURI().c_str()]];
1873 if (![before isEqualToArray:after])
1878 _assert(pkgDistUpgrade(cache_));
1882 [self updateWithStatus:status_];
1885 - (void) updateWithStatus:(Status &)status {
1887 _assert(list.ReadMainList());
1890 lock.Fd(GetLock(_config->FindDir("Dir::State::Lists") + "lock"));
1891 _assert(!_error->PendingError());
1893 pkgAcquire fetcher(&status);
1894 _assert(list.GetIndexes(&fetcher));
1896 if (fetcher.Run(PulseInterval_) != pkgAcquire::Failed) {
1897 bool failed = false;
1898 for (pkgAcquire::ItemIterator item = fetcher.ItemsBegin(); item != fetcher.ItemsEnd(); item++)
1899 if ((*item)->Status != pkgAcquire::Item::StatDone) {
1900 (*item)->Finished();
1904 if (!failed && _config->FindB("APT::Get::List-Cleanup", true) == true) {
1905 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists")));
1906 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/"));
1909 [Metadata_ setObject:[NSDate date] forKey:@"LastUpdate"];
1914 - (void) setDelegate:(id)delegate {
1915 delegate_ = delegate;
1916 status_.setDelegate(delegate);
1917 progress_.setDelegate(delegate);
1920 - (Source *) getSource:(const pkgCache::PkgFileIterator &)file {
1921 pkgIndexFile *index(NULL);
1922 list_->FindIndex(file, index);
1923 return [sources_ objectForKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(index)]];
1929 /* Confirmation View {{{ */
1930 void AddTextView(NSMutableDictionary *fields, NSMutableArray *packages, NSString *key) {
1931 if ([packages count] == 0)
1934 UITextView *text = GetTextView([packages count] == 0 ? @"n/a" : [packages componentsJoinedByString:@", "], 120, false);
1935 [fields setObject:text forKey:key];
1937 CGColor blue(space_, 0, 0, 0.4, 1);
1938 [text setTextColor:blue];
1941 @protocol ConfirmationViewDelegate
1946 @interface ConfirmationView : UIView {
1947 Database *database_;
1949 UITransitionView *transition_;
1951 UINavigationBar *navbar_;
1952 UIPreferencesTable *table_;
1953 NSMutableDictionary *fields_;
1954 UIAlertSheet *essential_;
1959 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate;
1963 @implementation ConfirmationView
1966 [navbar_ setDelegate:nil];
1967 [transition_ setDelegate:nil];
1968 [table_ setDataSource:nil];
1970 [transition_ release];
1975 if (essential_ != nil)
1976 [essential_ release];
1981 [transition_ transition:7 toView:nil];
1985 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
1986 if (from != nil && to == nil)
1987 [self removeFromSuperview];
1990 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
1993 if (essential_ != nil)
1994 [essential_ popupAlertAnimated:YES];
1996 [delegate_ confirm];
2005 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
2006 NSString *context = [sheet context];
2008 if ([context isEqualToString:@"remove"])
2014 [delegate_ confirm];
2019 else if ([context isEqualToString:@"unable"])
2025 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
2029 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
2031 case 0: return @"Statistics";
2032 case 1: return @"Modifications";
2034 default: _assert(false);
2038 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
2041 case 1: return [fields_ count];
2043 default: _assert(false);
2047 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
2048 if (group != 1 || row == -1)
2051 _assert(size_t(row) < [fields_ count]);
2052 return [[[fields_ allValues] objectAtIndex:row] visibleTextRect].size.height + TextViewOffset_;
2056 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
2057 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
2058 [cell setShowSelection:NO];
2061 case 0: switch (row) {
2063 [cell setTitle:@"Downloading"];
2064 [cell setValue:SizeString([database_ fetcher].FetchNeeded())];
2068 [cell setTitle:@"Resuming At"];
2069 [cell setValue:SizeString([database_ fetcher].PartialPresent())];
2073 double size([database_ cache]->UsrSize());
2076 [cell setTitle:@"Disk Freeing"];
2077 [cell setValue:SizeString(-size)];
2079 [cell setTitle:@"Disk Using"];
2080 [cell setValue:SizeString(size)];
2084 default: _assert(false);
2088 _assert(size_t(row) < [fields_ count]);
2089 [cell setTitle:[[fields_ allKeys] objectAtIndex:row]];
2090 [cell addSubview:[[fields_ allValues] objectAtIndex:row]];
2093 default: _assert(false);
2099 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate {
2100 if ((self = [super initWithFrame:[view bounds]]) != nil) {
2101 database_ = database;
2102 delegate_ = delegate;
2104 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
2105 [self addSubview:transition_];
2107 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
2109 CGSize navsize = [UINavigationBar defaultSize];
2110 CGRect navrect = {{0, 0}, navsize};
2111 CGRect bounds = [overlay_ bounds];
2113 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
2115 [navbar_ setBarStyle:1];
2116 [navbar_ setDelegate:self];
2118 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Confirm"] autorelease];
2119 [navbar_ pushNavigationItem:navitem];
2120 [navbar_ showButtonsWithLeftTitle:@"Cancel" rightTitle:@"Confirm"];
2122 fields_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
2124 NSMutableArray *installing = [NSMutableArray arrayWithCapacity:16];
2125 NSMutableArray *reinstalling = [NSMutableArray arrayWithCapacity:16];
2126 NSMutableArray *upgrading = [NSMutableArray arrayWithCapacity:16];
2127 NSMutableArray *downgrading = [NSMutableArray arrayWithCapacity:16];
2128 NSMutableArray *removing = [NSMutableArray arrayWithCapacity:16];
2132 pkgCacheFile &cache([database_ cache]);
2133 NSArray *packages = [database_ packages];
2134 for (size_t i(0), e = [packages count]; i != e; ++i) {
2135 Package *package = [packages objectAtIndex:i];
2136 pkgCache::PkgIterator iterator = [package iterator];
2137 pkgDepCache::StateCache &state(cache[iterator]);
2139 NSString *name([package name]);
2141 if (state.NewInstall())
2142 [installing addObject:name];
2143 else if (!state.Delete() && (state.iFlags & pkgDepCache::ReInstall) == pkgDepCache::ReInstall)
2144 [reinstalling addObject:name];
2145 else if (state.Upgrade())
2146 [upgrading addObject:name];
2147 else if (state.Downgrade())
2148 [downgrading addObject:name];
2149 else if (state.Delete()) {
2150 if ([package essential])
2152 [removing addObject:name];
2158 else if (Advanced_ || true) {
2159 essential_ = [[UIAlertSheet alloc]
2160 initWithTitle:@"Removing Essentials"
2161 buttons:[NSArray arrayWithObjects:
2162 @"Cancel Operation (Safe)",
2163 @"Force Removal (Unsafe)",
2165 defaultButtonIndex:0
2171 [essential_ setDestructiveButton:[[essential_ buttons] objectAtIndex:0]];
2173 [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."];
2175 essential_ = [[UIAlertSheet alloc]
2176 initWithTitle:@"Unable to Comply"
2177 buttons:[NSArray arrayWithObjects:@"Okay", nil]
2178 defaultButtonIndex:0
2183 [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."];
2186 AddTextView(fields_, installing, @"Installing");
2187 AddTextView(fields_, reinstalling, @"Reinstalling");
2188 AddTextView(fields_, upgrading, @"Upgrading");
2189 AddTextView(fields_, downgrading, @"Downgrading");
2190 AddTextView(fields_, removing, @"Removing");
2192 table_ = [[UIPreferencesTable alloc] initWithFrame:CGRectMake(
2193 0, navsize.height, bounds.size.width, bounds.size.height - navsize.height
2196 [table_ setReusesTableCells:YES];
2197 [table_ setDataSource:self];
2198 [table_ reloadData];
2200 [overlay_ addSubview:navbar_];
2201 [overlay_ addSubview:table_];
2203 [view addSubview:self];
2205 [transition_ setDelegate:self];
2207 UIView *blank = [[[UIView alloc] initWithFrame:[transition_ bounds]] autorelease];
2208 [transition_ transition:0 toView:blank];
2209 [transition_ transition:3 toView:overlay_];
2216 /* Progress Data {{{ */
2217 @interface ProgressData : NSObject {
2223 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object;
2230 @implementation ProgressData
2232 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object {
2233 if ((self = [super init]) != nil) {
2234 selector_ = selector;
2254 /* Progress View {{{ */
2255 Pcre conffile_r("^'(.*)' '(.*)' ([01]) ([01])$");
2257 @interface ProgressView : UIView <
2258 ConfigurationDelegate,
2261 _transient Database *database_;
2263 UIView *background_;
2264 UITransitionView *transition_;
2266 UINavigationBar *navbar_;
2267 UIProgressBar *progress_;
2268 UITextView *output_;
2269 UITextLabel *status_;
2270 UIPushButton *close_;
2275 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
2277 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database delegate:(id)delegate;
2278 - (void) setContentView:(UIView *)view;
2281 - (void) _retachThread;
2282 - (void) _detachNewThreadData:(ProgressData *)data;
2283 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title;
2289 @protocol ProgressViewDelegate
2290 - (void) progressViewIsComplete:(ProgressView *)sender;
2293 @implementation ProgressView
2296 [transition_ setDelegate:nil];
2297 [navbar_ setDelegate:nil];
2300 if (background_ != nil)
2301 [background_ release];
2302 [transition_ release];
2305 [progress_ release];
2312 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
2313 if (bootstrap_ && from == overlay_ && to == view_)
2317 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database delegate:(id)delegate {
2318 if ((self = [super initWithFrame:frame]) != nil) {
2319 database_ = database;
2320 delegate_ = delegate;
2322 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
2323 [transition_ setDelegate:self];
2325 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
2328 [overlay_ setBackgroundColor:Black_];
2330 background_ = [[UIView alloc] initWithFrame:[self bounds]];
2331 [background_ setBackgroundColor:Black_];
2332 [self addSubview:background_];
2335 [self addSubview:transition_];
2337 CGSize navsize = [UINavigationBar defaultSize];
2338 CGRect navrect = {{0, 0}, navsize};
2340 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
2341 [overlay_ addSubview:navbar_];
2343 [navbar_ setBarStyle:1];
2344 [navbar_ setDelegate:self];
2346 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:nil] autorelease];
2347 [navbar_ pushNavigationItem:navitem];
2349 CGRect bounds = [overlay_ bounds];
2350 CGSize prgsize = [UIProgressBar defaultSize];
2353 (bounds.size.width - prgsize.width) / 2,
2354 bounds.size.height - prgsize.height - 20
2357 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
2358 [progress_ setStyle:0];
2360 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(
2362 bounds.size.height - prgsize.height - 50,
2363 bounds.size.width - 20,
2367 [status_ setColor:White_];
2368 [status_ setBackgroundColor:Clear_];
2370 [status_ setCentersHorizontally:YES];
2371 //[status_ setFont:font];
2373 output_ = [[UITextView alloc] initWithFrame:CGRectMake(
2375 navrect.size.height + 20,
2376 bounds.size.width - 20,
2377 bounds.size.height - navsize.height - 62 - navrect.size.height
2380 //[output_ setTextFont:@"Courier New"];
2381 [output_ setTextSize:12];
2383 [output_ setTextColor:White_];
2384 [output_ setBackgroundColor:Clear_];
2386 [output_ setMarginTop:0];
2387 [output_ setAllowsRubberBanding:YES];
2388 [output_ setEditable:NO];
2390 [overlay_ addSubview:output_];
2392 close_ = [[UIPushButton alloc] initWithFrame:CGRectMake(
2394 bounds.size.height - prgsize.height - 50,
2395 bounds.size.width - 20,
2399 [close_ setAutosizesToFit:NO];
2400 [close_ setDrawsShadow:YES];
2401 [close_ setStretchBackground:YES];
2402 [close_ setTitle:@"Close Window"];
2403 [close_ setEnabled:YES];
2405 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22);
2406 [close_ setTitleFont:bold];
2409 [close_ addTarget:self action:@selector(closeButtonPushed) forEvents:kUIControlEventMouseUpInside];
2410 [close_ setBackground:[UIImage applicationImageNamed:@"green-up.png"] forState:0];
2411 [close_ setBackground:[UIImage applicationImageNamed:@"green-dn.png"] forState:1];
2415 - (void) setContentView:(UIView *)view {
2416 view_ = [view retain];
2419 - (void) resetView {
2420 [transition_ transition:6 toView:view_];
2423 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
2424 NSString *context = [sheet context];
2425 if ([context isEqualToString:@"conffile"]) {
2426 FILE *input = [database_ input];
2430 fprintf(input, "N\n");
2434 fprintf(input, "Y\n");
2445 - (void) closeButtonPushed {
2446 [delegate_ progressViewIsComplete:self];
2450 - (void) _retachThread {
2451 UINavigationItem *item = [navbar_ topItem];
2452 [item setTitle:@"Complete"];
2454 [overlay_ addSubview:close_];
2455 [progress_ removeFromSuperview];
2456 [status_ removeFromSuperview];
2459 notify_post("com.apple.mobile.application_installed");
2462 [delegate_ setStatusBarShowsProgress:NO];
2463 //[[UIApplication sharedApplication] setIdleTimerDisabled:YES];
2468 - (void) _detachNewThreadData:(ProgressData *)data {
2469 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
2471 [[data target] performSelector:[data selector] withObject:[data object]];
2474 [self performSelectorOnMainThread:@selector(_retachThread) withObject:nil waitUntilDone:YES];
2479 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title {
2480 UINavigationItem *item = [navbar_ topItem];
2481 [item setTitle:title];
2483 [status_ setText:nil];
2484 [output_ setText:@""];
2485 [progress_ setProgress:0];
2487 [close_ removeFromSuperview];
2488 [overlay_ addSubview:progress_];
2489 [overlay_ addSubview:status_];
2491 [delegate_ setStatusBarShowsProgress:YES];
2494 [transition_ transition:6 toView:overlay_];
2497 detachNewThreadSelector:@selector(_detachNewThreadData:)
2499 withObject:[[ProgressData alloc]
2500 initWithSelector:selector
2507 - (void) repairWithSelector:(SEL)selector {
2509 detachNewThreadSelector:selector
2512 title:@"Repairing..."
2516 - (void) setConfigurationData:(NSString *)data {
2518 performSelectorOnMainThread:@selector(_setConfigurationData:)
2524 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id {
2525 Package *package = id == nil ? nil : [database_ packageWithName:id];
2527 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
2528 initWithTitle:(package == nil ? @"Source Error" : [package name])
2529 buttons:[NSArray arrayWithObjects:@"Okay", nil]
2530 defaultButtonIndex:0
2535 [sheet setBodyText:error];
2536 [sheet popupAlertAnimated:YES];
2539 - (void) setProgressTitle:(NSString *)title {
2541 performSelectorOnMainThread:@selector(_setProgressTitle:)
2547 - (void) setProgressPercent:(float)percent {
2549 performSelectorOnMainThread:@selector(_setProgressPercent:)
2550 withObject:[NSNumber numberWithFloat:percent]
2555 - (void) addProgressOutput:(NSString *)output {
2557 performSelectorOnMainThread:@selector(_addProgressOutput:)
2563 - (void) _setConfigurationData:(NSString *)data {
2564 _assert(conffile_r(data));
2566 NSString *ofile = conffile_r[1];
2567 //NSString *nfile = conffile_r[2];
2569 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
2570 initWithTitle:@"Configuration Upgrade"
2571 buttons:[NSArray arrayWithObjects:
2572 @"Keep My Old Copy",
2573 @"Accept The New Copy",
2574 // XXX: @"See What Changed",
2576 defaultButtonIndex:0
2581 [sheet setBodyText:[NSString stringWithFormat:
2582 @"The following file has been changed by both the package maintainer and by you (or for you by a script).\n\n%@"
2585 [sheet popupAlertAnimated:YES];
2588 - (void) _setProgressTitle:(NSString *)title {
2589 [status_ setText:[title stringByAppendingString:@"..."]];
2592 - (void) _setProgressPercent:(NSNumber *)percent {
2593 [progress_ setProgress:[percent floatValue]];
2596 - (void) _addProgressOutput:(NSString *)output {
2597 [output_ setText:[NSString stringWithFormat:@"%@\n%@", [output_ text], output]];
2598 CGSize size = [output_ contentSize];
2599 CGRect rect = {{0, size.height}, {size.width, 0}};
2600 [output_ scrollRectToVisible:rect animated:YES];
2603 - (BOOL) isRunning {
2610 /* Package Cell {{{ */
2611 @interface PackageCell : UITableCell {
2614 UITextLabel *description_;
2615 UITextLabel *source_;
2616 //UIImageView *trusted_;
2618 UIImageView *badge_;
2619 UITextLabel *status_;
2624 - (PackageCell *) init;
2625 - (void) setPackage:(Package *)package;
2627 - (void) _setSelected:(float)fraction;
2628 - (void) setSelected:(BOOL)selected;
2629 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
2630 - (void) _setSelectionFadeFraction:(float)fraction;
2632 + (int) heightForPackage:(Package *)package;
2636 @implementation PackageCell
2641 [description_ release];
2647 //[trusted_ release];
2651 - (PackageCell *) init {
2652 if ((self = [super init]) != nil) {
2653 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 20);
2654 GSFontRef large = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 12);
2655 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 14);
2657 icon_ = [[UIImageView alloc] initWithFrame:CGRectMake(10, 10, 30, 30)];
2659 name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 8, 240, 25)];
2660 [name_ setBackgroundColor:Clear_];
2661 [name_ setFont:bold];
2663 source_ = [[UITextLabel alloc] initWithFrame:CGRectMake(58, 28, 225, 20)];
2664 [source_ setBackgroundColor:Clear_];
2665 [source_ setFont:large];
2667 description_ = [[UITextLabel alloc] initWithFrame:CGRectMake(12, 46, 280, 20)];
2668 [description_ setBackgroundColor:Clear_];
2669 [description_ setFont:small];
2671 /*trusted_ = [[UIImageView alloc] initWithFrame:CGRectMake(30, 30, 16, 16)];
2672 [trusted_ setImage:[UIImage applicationImageNamed:@"trusted.png"]];*/
2675 badge_ = [[UIImageView alloc] initWithFrame:CGRectMake(17, 70, 16, 16)];
2677 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 68, 280, 20)];
2678 [status_ setBackgroundColor:Clear_];
2679 [status_ setFont:small];
2682 /*[icon_ setImage:[UIImage applicationImageNamed:@"unknown.png"]];
2683 [icon_ zoomToScale:0.5];
2684 [icon_ setFrame:CGRectMake(10, 10, 30, 30)];*/
2686 [self addSubview:icon_];
2687 [self addSubview:name_];
2688 [self addSubview:description_];
2689 [self addSubview:source_];
2697 - (void) setPackage:(Package *)package {
2703 Source *source = [package source];
2705 UIImage *image = nil;
2706 if (NSString *icon = [package icon])
2707 image = [UIImage imageAtPath:[icon substringFromIndex:6]];
2708 if (image == nil) if (NSString *section = [package section])
2709 image = [UIImage applicationImageNamed:[Simplify(section) stringByAppendingString:@".png"]];
2710 /*if (image == nil) if (NSString *icon = [source defaultIcon])
2711 image = [UIImage imageAtPath:[icon substringFromIndex:6]];*/
2713 image = [UIImage applicationImageNamed:@"unknown.png"];
2714 [icon_ setImage:image];
2716 /*if (image != nil) {
2717 CGSize size = [image size];
2718 float scale = 30 / std::max(size.width, size.height);
2719 [icon_ zoomToScale:scale];
2722 [icon_ setFrame:CGRectMake(10, 10, 30, 30)];
2724 [name_ setText:[package name]];
2725 [description_ setText:[package tagline]];
2727 NSString *label = nil;
2728 bool trusted = false;
2730 if (source != nil) {
2731 label = [source label];
2732 trusted = [source trusted];
2733 } else if ([[package id] isEqualToString:@"firmware"])
2737 label = @"Unknown/Local";
2739 NSString *from = [NSString stringWithFormat:@"from %@", label];
2741 NSString *section = Simplify([package section]);
2742 if (section != nil && ![section isEqualToString:label])
2743 from = [from stringByAppendingString:[NSString stringWithFormat:@" (%@)", section]];
2745 [source_ setText:from];
2748 [badge_ removeFromSuperview];
2749 [status_ removeFromSuperview];
2751 if (NSString *mode = [package mode]) {
2752 [badge_ setImage:[UIImage applicationImageNamed:
2753 [mode isEqualToString:@"Remove"] || [mode isEqualToString:@"Purge"] ? @"removing.png" : @"installing.png"
2756 [status_ setText:[NSString stringWithFormat:@"Queued for %@", mode]];
2757 [status_ setColor:Blueish_];
2758 } else if ([package half]) {
2759 [badge_ setImage:[UIImage applicationImageNamed:@"damaged.png"]];
2760 [status_ setText:@"Package Damaged"];
2761 [status_ setColor:Red_];
2763 [badge_ setImage:nil];
2764 [status_ setText:nil];
2768 [self addSubview:badge_];
2769 [self addSubview:status_];
2774 - (void) _setSelected:(float)fraction {
2775 CGColor black(space_,
2776 Interpolate(0.0, 1.0, fraction),
2777 Interpolate(0.0, 1.0, fraction),
2778 Interpolate(0.0, 1.0, fraction),
2781 CGColor gray(space_,
2782 Interpolate(0.4, 1.0, fraction),
2783 Interpolate(0.4, 1.0, fraction),
2784 Interpolate(0.4, 1.0, fraction),
2787 [name_ setColor:black];
2788 [description_ setColor:gray];
2789 [source_ setColor:black];
2792 - (void) setSelected:(BOOL)selected {
2793 [self _setSelected:(selected ? 1.0 : 0.0)];
2794 [super setSelected:selected];
2797 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
2799 [self _setSelected:(selected ? 1.0 : 0.0)];
2800 [super setSelected:selected withFade:fade];
2803 - (void) _setSelectionFadeFraction:(float)fraction {
2804 [self _setSelected:fraction];
2805 [super _setSelectionFadeFraction:fraction];
2808 + (int) heightForPackage:(Package *)package {
2809 NSString *tagline([package tagline]);
2810 int height = tagline == nil || [tagline length] == 0 ? -15 : 0;
2812 if ([package hasMode] || [package half])
2821 /* Section Cell {{{ */
2822 @interface SectionCell : UITableCell {
2825 UITextLabel *count_;
2826 UISwitchControl *switch_;
2831 - (void) setSection:(Section *)section editing:(BOOL)editing;
2833 - (void) _setSelected:(float)fraction;
2834 - (void) setSelected:(BOOL)selected;
2835 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
2836 - (void) _setSelectionFadeFraction:(float)fraction;
2840 @implementation SectionCell
2843 if (section_ != nil)
2852 if ((self = [super init]) != nil) {
2853 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22);
2854 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 12);
2856 name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
2857 [name_ setBackgroundColor:Clear_];
2858 [name_ setFont:bold];
2860 count_ = [[UITextLabel alloc] initWithFrame:CGRectMake(11, 7, 29, 32)];
2861 [count_ setCentersHorizontally:YES];
2862 [count_ setBackgroundColor:Clear_];
2863 [count_ setFont:small];
2864 [count_ setColor:White_];
2866 UIImageView *folder = [[[UIImageView alloc] initWithFrame:CGRectMake(8, 7, 32, 32)] autorelease];
2867 [folder setImage:[UIImage applicationImageNamed:@"folder.png"]];
2869 switch_ = [[UISwitchControl alloc] initWithFrame:CGRectMake(218, 9, 60, 25)];
2870 [switch_ addTarget:self action:@selector(onSwitch:) forEvents:kUIControlEventMouseUpInside];
2872 [self addSubview:folder];
2873 [self addSubview:name_];
2874 [self addSubview:count_];
2876 [self _setSelected:0];
2883 - (void) onSwitch:(id)sender {
2884 NSMutableDictionary *metadata = [Sections_ objectForKey:section_];
2885 if (metadata == nil) {
2886 metadata = [NSMutableDictionary dictionaryWithCapacity:2];
2887 [Sections_ setObject:metadata forKey:section_];
2891 [metadata setObject:[NSNumber numberWithBool:([switch_ value] == 0)] forKey:@"Hidden"];
2894 - (void) setSection:(Section *)section editing:(BOOL)editing {
2895 if (editing != editing_) {
2897 [switch_ removeFromSuperview];
2899 [self addSubview:switch_];
2903 if (section_ != nil) {
2908 if (section == nil) {
2909 [name_ setText:@"All Packages"];
2910 [count_ setText:nil];
2912 section_ = [section name];
2913 if (section_ != nil)
2914 section_ = [section_ retain];
2915 [name_ setText:(section_ == nil ? @"(No Section)" : section_)];
2916 [count_ setText:[NSString stringWithFormat:@"%d", [section count]]];
2919 [switch_ setValue:isSectionVisible(section_) animated:NO];
2922 [name_ setFrame:CGRectMake(48, 9, editing_ ? 165 : 250, 25)];
2925 - (void) _setSelected:(float)fraction {
2926 CGColor black(space_,
2927 Interpolate(0.0, 1.0, fraction),
2928 Interpolate(0.0, 1.0, fraction),
2929 Interpolate(0.0, 1.0, fraction),
2932 [name_ setColor:black];
2935 - (void) setSelected:(BOOL)selected {
2936 [self _setSelected:(selected ? 1.0 : 0.0)];
2937 [super setSelected:selected];
2940 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
2942 [self _setSelected:(selected ? 1.0 : 0.0)];
2943 [super setSelected:selected withFade:fade];
2946 - (void) _setSelectionFadeFraction:(float)fraction {
2947 [self _setSelected:fraction];
2948 [super _setSelectionFadeFraction:fraction];
2954 /* File Table {{{ */
2955 @interface FileTable : RVPage {
2956 _transient Database *database_;
2959 NSMutableArray *files_;
2963 - (id) initWithBook:(RVBook *)book database:(Database *)database;
2964 - (void) setPackage:(Package *)package;
2968 @implementation FileTable
2971 if (package_ != nil)
2980 - (int) numberOfRowsInTable:(UITable *)table {
2981 return files_ == nil ? 0 : [files_ count];
2984 - (float) table:(UITable *)table heightForRow:(int)row {
2988 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2989 if (reusing == nil) {
2990 reusing = [[[UIImageAndTextTableCell alloc] init] autorelease];
2991 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
2992 [[(UIImageAndTextTableCell *)reusing titleTextLabel] setFont:font];
2995 [(UIImageAndTextTableCell *)reusing setTitle:[files_ objectAtIndex:row]];
2999 - (BOOL) table:(UITable *)table canSelectRow:(int)row {
3003 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3004 if ((self = [super initWithBook:book]) != nil) {
3005 database_ = database;
3007 files_ = [[NSMutableArray arrayWithCapacity:32] retain];
3009 list_ = [[UITable alloc] initWithFrame:[self bounds]];
3010 [self addSubview:list_];
3012 UITableColumn *column = [[[UITableColumn alloc]
3013 initWithTitle:@"Name"
3015 width:[self frame].size.width
3018 [list_ setDataSource:self];
3019 [list_ setSeparatorStyle:1];
3020 [list_ addTableColumn:column];
3021 [list_ setDelegate:self];
3022 [list_ setReusesTableCells:YES];
3026 - (void) setPackage:(Package *)package {
3027 if (package_ != nil) {
3028 [package_ autorelease];
3037 [files_ removeAllObjects];
3039 if (package != nil) {
3040 package_ = [package retain];
3041 name_ = [[package id] retain];
3043 NSString *path = [NSString stringWithFormat:@"/var/lib/dpkg/info/%@.list", name_];
3046 std::ifstream fin([path UTF8String]);
3048 while (std::getline(fin, line))
3049 [files_ addObject:[NSString stringWithUTF8String:line.c_str()]];
3052 if ([files_ count] != 0) {
3053 if ([[files_ objectAtIndex:0] isEqualToString:@"/."])
3054 [files_ removeObjectAtIndex:0];
3055 [files_ sortUsingSelector:@selector(compareByPath:)];
3057 NSMutableArray *stack = [NSMutableArray arrayWithCapacity:8];
3058 [stack addObject:@"/"];
3060 for (int i(0), e([files_ count]); i != e; ++i) {
3061 NSString *file = [files_ objectAtIndex:i];
3062 while (![file hasPrefix:[stack lastObject]])
3063 [stack removeLastObject];
3064 NSString *directory = [stack lastObject];
3065 [stack addObject:[file stringByAppendingString:@"/"]];
3066 [files_ replaceObjectAtIndex:i withObject:[NSString stringWithFormat:@"%*s%@",
3067 ([stack count] - 2) * 3, "",
3068 [file substringFromIndex:[directory length]]
3077 - (void) resetViewAnimated:(BOOL)animated {
3078 [list_ resetViewAnimated:animated];
3081 - (void) reloadData {
3082 [self setPackage:[database_ packageWithName:name_]];
3083 [self reloadButtons];
3086 - (NSString *) title {
3087 return @"Installed Files";
3090 - (NSString *) backButtonTitle {
3096 /* Package View {{{ */
3097 @protocol PackageViewDelegate
3098 - (void) performPackage:(Package *)package;
3101 @interface PackageView : RVPage {
3102 _transient Database *database_;
3103 UIPreferencesTable *table_;
3106 UITextView *description_;
3107 NSMutableArray *buttons_;
3110 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3111 - (void) setPackage:(Package *)package;
3115 @implementation PackageView
3118 [table_ setDataSource:nil];
3119 [table_ setDelegate:nil];
3121 if (package_ != nil)
3125 if (description_ != nil)
3126 [description_ release];
3132 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
3134 if ([package_ installed] != nil)
3136 if ([package_ source] != nil)
3141 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
3144 else if ([package_ installed] != nil && group-- == 0)
3145 return @"Installed Package";
3146 else if (group-- == 0)
3147 return @"Package Details";
3148 else if ([package_ source] != nil && group-- == 0)
3149 return @"Source Information";
3150 else _assert(false);
3153 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
3154 if (description_ == nil || group != 0 || row != ([package_ author] == nil ? 1 : 2))
3157 return [description_ visibleTextRect].size.height + TextViewOffset_;
3160 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
3163 if ([package_ author] != nil)
3165 if (description_ != nil)
3167 if ([package_ website] != nil)
3170 } else if ([package_ installed] != nil && group-- == 0)
3172 else if (group-- == 0) {
3174 if ([package_ size] != 0)
3176 if ([package_ maintainer] != nil)
3178 if ([package_ sponsor] != nil)
3180 if ([package_ relationships] != nil)
3182 if ([[package_ source] trusted])
3185 } else if ([package_ source] != nil && group-- == 0) {
3186 Source *source = [package_ source];
3187 NSString *description = [source description];
3189 if (description != nil && ![description isEqualToString:[source label]])
3191 if ([source origin] != nil)
3194 } else _assert(false);
3197 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
3198 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
3199 [cell setShowSelection:NO];
3203 } else if (row-- == 0) {
3204 [cell setTitle:[package_ name]];
3205 [cell setValue:[package_ latest]];
3206 } else if ([package_ author] != nil && row-- == 0) {
3207 [cell setTitle:@"Author"];
3208 [cell setValue:[[package_ author] name]];
3209 [cell setShowDisclosure:YES];
3210 [cell setShowSelection:YES];
3211 } else if (description_ != nil && row-- == 0) {
3212 [cell addSubview:description_];
3213 } else if ([package_ website] != nil && row-- == 0) {
3214 [cell setTitle:@"More Information"];
3215 [cell setShowDisclosure:YES];
3216 [cell setShowSelection:YES];
3217 } else _assert(false);
3218 } else if ([package_ installed] != nil && group-- == 0) {
3220 } else if (row-- == 0) {
3221 [cell setTitle:@"Version"];
3222 NSString *installed([package_ installed]);
3223 [cell setValue:(installed == nil ? @"n/a" : installed)];
3224 } else if (row-- == 0) {
3225 [cell setTitle:@"Filesystem Content"];
3226 [cell setShowDisclosure:YES];
3227 [cell setShowSelection:YES];
3228 } else _assert(false);
3229 } else if (group-- == 0) {
3231 } else if (row-- == 0) {
3232 [cell setTitle:@"Identifier"];
3233 [cell setValue:[package_ id]];
3234 } else if (row-- == 0) {
3235 [cell setTitle:@"Section"];
3236 NSString *section([package_ section]);
3237 [cell setValue:(section == nil ? @"n/a" : section)];
3238 } else if ([package_ size] != 0 && row-- == 0) {
3239 [cell setTitle:@"Expanded Size"];
3240 [cell setValue:SizeString([package_ size])];
3241 } else if ([package_ maintainer] != nil && row-- == 0) {
3242 [cell setTitle:@"Maintainer"];
3243 [cell setValue:[[package_ maintainer] name]];
3244 [cell setShowDisclosure:YES];
3245 [cell setShowSelection:YES];
3246 } else if ([package_ sponsor] != nil && row-- == 0) {
3247 [cell setTitle:@"Sponsor"];
3248 [cell setValue:[[package_ sponsor] name]];
3249 [cell setShowDisclosure:YES];
3250 [cell setShowSelection:YES];
3251 } else if ([package_ relationships] != nil && row-- == 0) {
3252 [cell setTitle:@"Package Relationships"];
3253 [cell setShowDisclosure:YES];
3254 [cell setShowSelection:YES];
3255 } else if ([[package_ source] trusted] && row-- == 0) {
3256 [cell setIcon:[UIImage applicationImageNamed:@"trusted.png"]];
3257 [cell setValue:@"This package has been signed."];
3258 } else _assert(false);
3259 } else if ([package_ source] != nil && group-- == 0) {
3260 Source *source = [package_ source];
3261 NSString *description = [source description];
3264 } else if (row-- == 0) {
3265 NSString *label = [source label];
3267 label = [source uri];
3268 [cell setTitle:label];
3269 [cell setValue:[source version]];
3270 } else if (description != nil && ![description isEqualToString:[source label]] && row-- == 0) {
3271 [cell setValue:description];
3272 } else if ([source origin] != nil && row-- == 0) {
3273 [cell setTitle:@"Origin"];
3274 [cell setValue:[source origin]];
3275 } else _assert(false);
3276 } else _assert(false);
3281 - (BOOL) canSelectRow:(int)row {
3285 - (void) tableRowSelected:(NSNotification *)notification {
3286 int row = [table_ selectedRow];
3290 #define _else else goto _label; return; } _label:
3294 } else if (row-- == 0) {
3295 } else if ([package_ author] != nil && row-- == 0) {
3296 [delegate_ openURL:[NSURL URLWithString:[NSString stringWithFormat:@"mailto:%@?subject=%@",
3297 [[package_ author] email],
3298 [[NSString stringWithFormat:@"regarding apt package \"%@\"",
3300 ] stringByAddingPercentEscapes]
3302 } else if (description_ != nil && row-- == 0) {
3303 } else if ([package_ website] != nil && row-- == 0) {
3304 NSURL *url = [NSURL URLWithString:[package_ website]];
3305 BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease];
3306 [browser setDelegate:delegate_];
3307 [book_ pushPage:browser];
3308 [browser loadURL:url];
3309 } _else if ([package_ installed] != nil) {
3311 } else if (row-- == 0) {
3312 } else if (row-- == 0) {
3313 FileTable *files = [[[FileTable alloc] initWithBook:book_ database:database_] autorelease];
3314 [files setDelegate:delegate_];
3315 [files setPackage:package_];
3316 [book_ pushPage:files];
3319 } else if (row-- == 0) {
3320 } else if (row-- == 0) {
3321 } else if ([package_ size] != 0 && row-- == 0) {
3322 } else if ([package_ maintainer] != nil && row-- == 0) {
3323 [delegate_ openURL:[NSURL URLWithString:[NSString stringWithFormat:@"mailto:%@?subject=%@",
3324 [[package_ maintainer] email],
3325 [[NSString stringWithFormat:@"regarding apt package \"%@\"",
3327 ] stringByAddingPercentEscapes]
3329 } else if ([package_ sponsor] != nil && row-- == 0) {
3330 NSURL *url = [NSURL URLWithString:[[package_ sponsor] email]];
3331 BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease];
3332 [browser setDelegate:delegate_];
3333 [book_ pushPage:browser];
3334 [browser loadURL:url];
3335 } else if ([package_ relationships] != nil && row-- == 0) {
3336 } else if ([[package_ source] trusted] && row-- == 0) {
3337 } _else if ([package_ source] != nil) {
3338 Source *source = [package_ source];
3339 NSString *description = [source description];
3342 } else if (row-- == 0) {
3343 } else if (description != nil && ![description isEqualToString:[source label]] && row-- == 0) {
3344 } else if ([source origin] != nil && row-- == 0) {
3345 } _else _assert(false);
3350 - (void) _clickButtonWithName:(NSString *)name {
3351 if ([name isEqualToString:@"Install"])
3352 [delegate_ installPackage:package_];
3353 else if ([name isEqualToString:@"Reinstall"])
3354 [delegate_ installPackage:package_];
3355 else if ([name isEqualToString:@"Remove"])
3356 [delegate_ removePackage:package_];
3357 else if ([name isEqualToString:@"Upgrade"])
3358 [delegate_ installPackage:package_];
3359 else _assert(false);
3362 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
3363 int count = [buttons_ count];
3364 _assert(count != 0);
3365 _assert(button <= count + 1);
3367 if (count != button - 1)
3368 [self _clickButtonWithName:[buttons_ objectAtIndex:(button - 1)]];
3373 - (void) _rightButtonClicked {
3374 int count = [buttons_ count];
3375 _assert(count != 0);
3378 [self _clickButtonWithName:[buttons_ objectAtIndex:0]];
3380 NSMutableArray *buttons = [NSMutableArray arrayWithCapacity:(count + 1)];
3381 [buttons addObjectsFromArray:buttons_];
3382 [buttons addObject:@"Cancel"];
3384 [delegate_ slideUp:[[[UIAlertSheet alloc]
3387 defaultButtonIndex:2
3394 - (NSString *) rightButtonTitle {
3395 int count = [buttons_ count];
3396 return count == 0 ? nil : count != 1 ? @"Modify" : [buttons_ objectAtIndex:0];
3399 - (NSString *) title {
3403 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3404 if ((self = [super initWithBook:book]) != nil) {
3405 database_ = database;
3407 table_ = [[UIPreferencesTable alloc] initWithFrame:[self bounds]];
3408 [self addSubview:table_];
3410 [table_ setDataSource:self];
3411 [table_ setDelegate:self];
3413 buttons_ = [[NSMutableArray alloc] initWithCapacity:4];
3417 - (void) setPackage:(Package *)package {
3418 if (package_ != nil) {
3419 [package_ autorelease];
3428 if (description_ != nil) {
3429 [description_ release];
3433 [buttons_ removeAllObjects];
3435 if (package != nil) {
3436 package_ = [package retain];
3437 name_ = [[package id] retain];
3439 NSString *description([package description]);
3440 if (description == nil)
3441 description = [package tagline];
3442 if (description != nil) {
3443 description_ = [GetTextView(description, 12, true) retain];
3444 [description_ setTextColor:Black_];
3447 [table_ reloadData];
3449 if ([package_ source] == nil);
3450 else if ([package_ upgradableAndEssential:NO])
3451 [buttons_ addObject:@"Upgrade"];
3452 else if ([package_ installed] == nil)
3453 [buttons_ addObject:@"Install"];
3455 [buttons_ addObject:@"Reinstall"];
3456 if ([package_ installed] != nil)
3457 [buttons_ addObject:@"Remove"];
3461 - (void) resetViewAnimated:(BOOL)animated {
3462 [table_ resetViewAnimated:animated];
3465 - (void) reloadData {
3466 [self setPackage:[database_ packageWithName:name_]];
3467 [self reloadButtons];
3472 /* Package Table {{{ */
3473 @interface PackageTable : RVPage {
3474 _transient Database *database_;
3478 NSMutableArray *packages_;
3479 NSMutableArray *sections_;
3480 UISectionList *list_;
3483 - (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object;
3485 - (void) setDelegate:(id)delegate;
3486 - (void) setObject:(id)object;
3488 - (void) reloadData;
3489 - (void) resetCursor;
3491 - (UISectionList *) list;
3493 - (void) setShouldHideHeaderInShortLists:(BOOL)hide;
3497 @implementation PackageTable
3500 [list_ setDataSource:nil];
3505 [packages_ release];
3506 [sections_ release];
3511 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
3512 return [sections_ count];
3515 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
3516 return [[sections_ objectAtIndex:section] name];
3519 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
3520 return [[sections_ objectAtIndex:section] row];
3523 - (int) numberOfRowsInTable:(UITable *)table {
3524 return [packages_ count];
3527 - (float) table:(UITable *)table heightForRow:(int)row {
3528 return [PackageCell heightForPackage:[packages_ objectAtIndex:row]];
3531 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
3533 reusing = [[[PackageCell alloc] init] autorelease];
3534 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
3538 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
3542 - (void) tableRowSelected:(NSNotification *)notification {
3543 int row = [[notification object] selectedRow];
3547 Package *package = [packages_ objectAtIndex:row];
3548 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
3549 [view setDelegate:delegate_];
3550 [view setPackage:package];
3551 [book_ pushPage:view];
3554 - (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object {
3555 if ((self = [super initWithBook:book]) != nil) {
3556 database_ = database;
3557 title_ = [title retain];
3559 object_ = object == nil ? nil : [object retain];
3561 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
3562 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
3564 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:YES];
3565 [list_ setDataSource:self];
3567 UITableColumn *column = [[[UITableColumn alloc]
3568 initWithTitle:@"Name"
3570 width:[self frame].size.width
3573 UITable *table = [list_ table];
3574 [table setSeparatorStyle:1];
3575 [table addTableColumn:column];
3576 [table setDelegate:self];
3577 [table setReusesTableCells:YES];
3579 [self addSubview:list_];
3584 - (void) setDelegate:(id)delegate {
3585 delegate_ = delegate;
3588 - (void) setObject:(id)object {
3594 object_ = [object retain];
3597 - (void) reloadData {
3598 NSArray *packages = [database_ packages];
3600 [packages_ removeAllObjects];
3601 [sections_ removeAllObjects];
3603 for (size_t i(0); i != [packages count]; ++i) {
3604 Package *package([packages objectAtIndex:i]);
3605 if ([[package performSelector:filter_ withObject:object_] boolValue])
3606 [packages_ addObject:package];
3609 Section *section = nil;
3611 for (size_t offset(0); offset != [packages_ count]; ++offset) {
3612 Package *package = [packages_ objectAtIndex:offset];
3613 NSString *name = [package index];
3615 if (section == nil || ![[section name] isEqualToString:name]) {
3616 section = [[[Section alloc] initWithName:name row:offset] autorelease];
3617 [sections_ addObject:section];
3620 [section addToCount];
3626 - (NSString *) title {
3630 - (void) resetViewAnimated:(BOOL)animated {
3631 [list_ resetViewAnimated:animated];
3634 - (void) resetCursor {
3635 [[list_ table] scrollPointVisibleAtTopLeft:CGPointMake(0, 0) animated:NO];
3638 - (UISectionList *) list {
3642 - (void) setShouldHideHeaderInShortLists:(BOOL)hide {
3643 [list_ setShouldHideHeaderInShortLists:hide];
3649 /* Browser Implementation {{{ */
3650 @implementation BrowserView
3653 WebView *webview = [webview_ webView];
3654 [webview setFrameLoadDelegate:nil];
3655 [webview setResourceLoadDelegate:nil];
3656 [webview setUIDelegate:nil];
3658 [scroller_ setDelegate:nil];
3659 [webview_ setDelegate:nil];
3661 [scroller_ release];
3664 [indicator_ release];
3670 - (void) loadURL:(NSURL *)url cachePolicy:(NSURLRequestCachePolicy)policy {
3671 NSMutableURLRequest *request = [NSMutableURLRequest
3674 timeoutInterval:30.0
3677 [request addValue:[NSString stringWithUTF8String:Firmware_] forHTTPHeaderField:@"X-Firmware"];
3678 [request addValue:[NSString stringWithUTF8String:Machine_] forHTTPHeaderField:@"X-Machine"];
3679 [request addValue:[NSString stringWithUTF8String:SerialNumber_] forHTTPHeaderField:@"X-Serial-Number"];
3681 [self loadRequest:request];
3685 - (void) loadURL:(NSURL *)url {
3686 [self loadURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy];
3689 // XXX: this needs to add the headers
3690 - (NSURLRequest *) _addHeadersToRequest:(NSURLRequest *)request {
3694 - (void) loadRequest:(NSURLRequest *)request {
3696 [webview_ loadRequest:request];
3699 - (void) reloadURL {
3700 NSURL *url = [[[urls_ lastObject] retain] autorelease];
3701 [urls_ removeLastObject];
3702 [self loadURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData];
3705 - (WebView *) webView {
3706 return [webview_ webView];
3709 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame {
3710 [scroller_ setContentSize:frame.size];
3713 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old {
3714 [self view:sender didSetFrame:frame];
3717 - (void) getAppTapp:(NSString *)href {
3718 if ([href hasPrefix:@"apptapp://package/"]) {
3719 NSString *name = [href substringFromIndex:18];
3720 Package *package = [database_ packageWithName:name];
3721 if (package == nil) {
3722 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
3723 initWithTitle:@"Cannot Locate Package"
3724 buttons:[NSArray arrayWithObjects:@"Close", nil]
3725 defaultButtonIndex:0
3730 [sheet setBodyText:[NSString stringWithFormat:
3731 @"The package %@ cannot be found in your current sources. I might recommend installing more sources."
3734 [sheet popupAlertAnimated:YES];
3736 [self setBackButtonTitle:title_];
3737 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
3738 [view setDelegate:delegate_];
3739 [view setPackage:package];
3740 [book_ pushPage:view];
3745 - (void) webView:(WebView *)sender willClickElement:(id)element {
3746 if (![element respondsToSelector:@selector(href)])
3748 NSString *href = [element href];
3751 if ([href hasPrefix:@"apptapp://package/"])
3752 [self getAppTapp:href];
3755 - (NSURLRequest *) webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource {
3756 if ([[[request URL] scheme] isEqualToString:@"apptapp"]) {
3757 [self getAppTapp:[[request URL] absoluteString]];
3763 [book_ pushPage:self];
3766 return [self _addHeadersToRequest:request];
3769 - (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request {
3770 if (request != nil && [[[request URL] scheme] isEqualToString:@"apptapp"])
3773 [self setBackButtonTitle:title_];
3775 BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease];
3776 [browser setDelegate:delegate_];
3778 if (request != nil) {
3779 [browser loadRequest:[self _addHeadersToRequest:request]];
3780 [book_ pushPage:browser];
3783 return [browser webView];
3787 - (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame {
3788 title_ = [title retain];
3789 [self setTitle:title];
3792 - (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame {
3793 if ([frame parentFrame] != nil)
3798 [indicator_ startAnimation];
3799 [self reloadButtons];
3801 if (title_ != nil) {
3806 [self setTitle:@"Loading..."];
3808 WebView *webview = [webview_ webView];
3809 NSString *href = [webview mainFrameURL];
3810 [urls_ addObject:[NSURL URLWithString:href]];
3812 CGRect webrect = [scroller_ frame];
3813 webrect.size.height = 0;
3814 [webview_ setFrame:webrect];
3817 - (void) _finishLoading {
3820 [indicator_ stopAnimation];
3821 [self reloadButtons];
3825 - (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
3826 if ([frame parentFrame] != nil)
3828 [self _finishLoading];
3831 - (void) webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
3832 if ([frame parentFrame] != nil)
3834 [self _finishLoading];
3835 [self loadURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@?%@",
3836 [[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"home" ofType:@"html"]] absoluteString],
3837 [[error localizedDescription] stringByAddingPercentEscapes]
3841 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3842 if ((self = [super initWithBook:book]) != nil) {
3843 database_ = database;
3846 struct CGRect bounds = [self bounds];
3848 UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:bounds] autorelease];
3849 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
3850 [self addSubview:pinstripe];
3852 scroller_ = [[UIScroller alloc] initWithFrame:bounds];
3853 [self addSubview:scroller_];
3855 [scroller_ setScrollingEnabled:YES];
3856 [scroller_ setAdjustForContentSizeChange:YES];
3857 [scroller_ setClipsSubviews:YES];
3858 [scroller_ setAllowsRubberBanding:YES];
3859 [scroller_ setScrollDecelerationFactor:0.99];
3860 [scroller_ setDelegate:self];
3862 CGRect webrect = [scroller_ bounds];
3863 webrect.size.height = 0;
3865 webview_ = [[UIWebView alloc] initWithFrame:webrect];
3866 [scroller_ addSubview:webview_];
3868 [webview_ setTilingEnabled:YES];
3869 [webview_ setTileSize:CGSizeMake(webrect.size.width, 500)];
3870 [webview_ setAutoresizes:YES];
3871 [webview_ setDelegate:self];
3872 //[webview_ setEnabledGestures:2];
3874 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:kUIProgressIndicatorStyleMediumWhite];
3875 indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(281, 42, indsize.width, indsize.height)];
3876 [indicator_ setStyle:kUIProgressIndicatorStyleMediumWhite];
3878 Package *package([database_ packageWithName:@"cydia"]);
3879 NSString *application = package == nil ? @"Cydia" : [NSString
3880 stringWithFormat:@"Cydia/%@",
3884 WebView *webview = [webview_ webView];
3885 [webview setApplicationNameForUserAgent:application];
3886 [webview setFrameLoadDelegate:self];
3887 [webview setResourceLoadDelegate:self];
3888 [webview setUIDelegate:self];
3890 urls_ = [[NSMutableArray alloc] initWithCapacity:16];
3894 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
3898 - (void) _leftButtonClicked {
3899 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
3900 initWithTitle:@"About Cydia Installer"
3901 buttons:[NSArray arrayWithObjects:@"Close", nil]
3902 defaultButtonIndex:0
3908 @"Copyright (C) 2008\n"
3909 "Jay Freeman (saurik)\n"
3910 "saurik@saurik.com\n"
3911 "http://www.saurik.com/\n"
3914 "http://www.theokorigroup.com/\n"
3916 "College of Creative Studies,\n"
3917 "University of California,\n"
3919 "http://www.ccs.ucsb.edu/"
3922 [sheet popupAlertAnimated:YES];
3925 - (void) _rightButtonClicked {
3930 - (NSString *) leftButtonTitle {
3934 - (NSString *) rightButtonTitle {
3935 return loading_ ? @"" : @"Reload";
3938 - (NSString *) title {
3942 - (NSString *) backButtonTitle {
3946 - (void) setPageActive:(BOOL)active {
3948 [book_ addSubview:indicator_];
3950 [indicator_ removeFromSuperview];
3953 - (void) resetViewAnimated:(BOOL)animated {
3956 - (void) setPushed:(bool)pushed {
3963 @interface CYBook : RVBook <
3966 _transient Database *database_;
3968 UIProgressIndicator *indicator_;
3969 UITextLabel *prompt_;
3970 UIProgressBar *progress_;
3974 - (id) initWithFrame:(CGRect)frame database:(Database *)database;
3980 /* Source Cell {{{ */
3981 @interface SourceCell : UITableCell {
3982 UITextLabel *description_;
3983 UIRightTextLabel *label_;
3984 UITextLabel *origin_;
3989 - (SourceCell *) initWithSource:(Source *)source;
3991 - (void) _setSelected:(float)fraction;
3992 - (void) setSelected:(BOOL)selected;
3993 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
3994 - (void) _setSelectionFadeFraction:(float)fraction;
3998 @implementation SourceCell
4001 [description_ release];
4007 - (SourceCell *) initWithSource:(Source *)source {
4008 if ((self = [super init]) != nil) {
4009 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 20);
4010 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 14);
4012 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
4013 float clear[] = {0, 0, 0, 0};
4015 NSString *description = [source description];
4016 if (description == nil)
4017 description = [source uri];
4019 description_ = [[UITextLabel alloc] initWithFrame:CGRectMake(12, 7, 270, 25)];
4020 [description_ setBackgroundColor:CGColorCreate(space, clear)];
4021 [description_ setFont:bold];
4022 [description_ setText:description];
4024 NSString *label = [source label];
4026 label = [source type];
4028 label_ = [[UIRightTextLabel alloc] initWithFrame:CGRectMake(290, 32, 90, 25)];
4029 [label_ setBackgroundColor:CGColorCreate(space, clear)];
4030 [label_ setFont:small];
4031 [label_ setText:label];
4033 NSString *origin = [source origin];
4035 origin = [source distribution];
4037 origin_ = [[UITextLabel alloc] initWithFrame:CGRectMake(13, 35, 315, 20)];
4038 [origin_ setBackgroundColor:CGColorCreate(space, clear)];
4039 [origin_ setFont:small];
4040 [origin_ setText:origin];
4042 [self addSubview:description_];
4043 [self addSubview:label_];
4044 [self addSubview:origin_];
4051 - (void) _setSelected:(float)fraction {
4052 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
4055 Interpolate(0.0, 1.0, fraction),
4056 Interpolate(0.0, 1.0, fraction),
4057 Interpolate(0.0, 1.0, fraction),
4061 Interpolate(0.2, 1.0, fraction),
4062 Interpolate(0.2, 1.0, fraction),
4063 Interpolate(1.0, 1.0, fraction),
4067 Interpolate(0.4, 1.0, fraction),
4068 Interpolate(0.4, 1.0, fraction),
4069 Interpolate(0.4, 1.0, fraction),
4072 [description_ setColor:CGColorCreate(space, black)];
4073 [label_ setColor:CGColorCreate(space, blue)];
4074 [origin_ setColor:CGColorCreate(space, gray)];
4077 - (void) setSelected:(BOOL)selected {
4078 [self _setSelected:(selected ? 1.0 : 0.0)];
4079 [super setSelected:selected];
4082 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
4084 [self _setSelected:(selected ? 1.0 : 0.0)];
4085 [super setSelected:selected withFade:fade];
4088 - (void) _setSelectionFadeFraction:(float)fraction {
4089 [self _setSelected:fraction];
4090 [super _setSelectionFadeFraction:fraction];
4095 /* Source Table {{{ */
4096 @interface SourceTable : RVPage {
4097 _transient Database *database_;
4098 UISectionList *list_;
4099 NSMutableArray *sources_;
4100 UIAlertSheet *alert_;
4103 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4107 @implementation SourceTable
4110 [list_ setDataSource:nil];
4112 if (sources_ != nil)
4118 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
4122 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
4126 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
4130 - (int) numberOfRowsInTable:(UITable *)table {
4131 return [sources_ count];
4134 - (float) table:(UITable *)table heightForRow:(int)row {
4138 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col {
4139 return [[[SourceCell alloc] initWithSource:[sources_ objectAtIndex:row]] autorelease];
4142 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
4146 - (void) tableRowSelected:(NSNotification*)notification {
4147 UITable *table([list_ table]);
4148 int row([table selectedRow]);
4152 [table selectRow:-1 byExtendingSelection:NO withFade:YES];
4155 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4156 if ((self = [super initWithBook:book]) != nil) {
4157 database_ = database;
4160 list_ = [[UISectionList alloc] initWithFrame:[self bounds]];
4162 [self addSubview:list_];
4164 [list_ setDataSource:self];
4165 [list_ setShouldHideHeaderInShortLists:NO];
4167 UITableColumn *column = [[UITableColumn alloc]
4168 initWithTitle:@"Name"
4170 width:[self frame].size.width
4173 UITable *table = [list_ table];
4174 [table setSeparatorStyle:1];
4175 [table addTableColumn:column];
4176 [table setDelegate:self];
4180 - (void) reloadData {
4182 _assert(list.ReadMainList());
4184 if (sources_ != nil)
4187 sources_ = [[NSMutableArray arrayWithCapacity:16] retain];
4188 for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source)
4189 [sources_ addObject:[[[Source alloc] initWithMetaIndex:*source] autorelease]];
4194 - (void) resetViewAnimated:(BOOL)animated {
4195 [list_ resetViewAnimated:animated];
4198 - (NSString *) leftTitle {
4199 return @"Refresh All";
4202 - (NSString *) rightTitle {
4209 /* Install View {{{ */
4210 @interface InstallView : RVPage {
4211 _transient Database *database_;
4212 NSMutableArray *sections_;
4213 NSMutableArray *filtered_;
4214 UITransitionView *transition_;
4220 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4221 - (void) reloadData;
4226 @implementation InstallView
4229 [list_ setDataSource:nil];
4230 [list_ setDelegate:nil];
4232 [sections_ release];
4233 [filtered_ release];
4234 [transition_ release];
4236 [accessory_ release];
4240 - (int) numberOfRowsInTable:(UITable *)table {
4241 return editing_ ? [sections_ count] : [filtered_ count] + 1;
4244 - (float) table:(UITable *)table heightForRow:(int)row {
4248 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
4250 reusing = [[[SectionCell alloc] init] autorelease];
4251 [(SectionCell *)reusing setSection:(editing_ ?
4252 [sections_ objectAtIndex:row] :
4253 (row == 0 ? nil : [filtered_ objectAtIndex:(row - 1)])
4254 ) editing:editing_];
4258 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
4262 - (BOOL) table:(UITable *)table canSelectRow:(int)row {
4266 - (void) tableRowSelected:(NSNotification *)notification {
4267 int row = [[notification object] selectedRow];
4278 title = @"All Packages";
4280 section = [filtered_ objectAtIndex:(row - 1)];
4281 name = [section name];
4287 title = @"(No Section)";
4291 PackageTable *table = [[[PackageTable alloc]
4295 filter:@selector(isUninstalledInSection:)
4299 [table setDelegate:delegate_];
4301 [book_ pushPage:table];
4304 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4305 if ((self = [super initWithBook:book]) != nil) {
4306 database_ = database;
4308 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
4309 filtered_ = [[NSMutableArray arrayWithCapacity:16] retain];
4311 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
4312 [self addSubview:transition_];
4314 list_ = [[UITable alloc] initWithFrame:[transition_ bounds]];
4315 [transition_ transition:0 toView:list_];
4317 UITableColumn *column = [[[UITableColumn alloc]
4318 initWithTitle:@"Name"
4320 width:[self frame].size.width
4323 [list_ setDataSource:self];
4324 [list_ setSeparatorStyle:1];
4325 [list_ addTableColumn:column];
4326 [list_ setDelegate:self];
4327 [list_ setReusesTableCells:YES];
4333 - (void) reloadData {
4334 NSArray *packages = [database_ packages];
4336 [sections_ removeAllObjects];
4337 [filtered_ removeAllObjects];
4339 NSMutableArray *filtered = [NSMutableArray arrayWithCapacity:[packages count]];
4340 NSMutableDictionary *sections = [NSMutableDictionary dictionaryWithCapacity:32];
4342 for (size_t i(0); i != [packages count]; ++i) {
4343 Package *package([packages objectAtIndex:i]);
4344 NSString *name([package section]);
4347 Section *section([sections objectForKey:name]);
4348 if (section == nil) {
4349 section = [[[Section alloc] initWithName:name] autorelease];
4350 [sections setObject:section forKey:name];
4354 if ([package valid] && [package installed] == nil && [package visible])
4355 [filtered addObject:package];
4358 [sections_ addObjectsFromArray:[sections allValues]];
4359 [sections_ sortUsingSelector:@selector(compareByName:)];
4361 [filtered sortUsingSelector:@selector(compareBySection:)];
4363 Section *section = nil;
4364 for (size_t offset = 0, count = [filtered count]; offset != count; ++offset) {
4365 Package *package = [filtered objectAtIndex:offset];
4366 NSString *name = [package section];
4368 if (section == nil || name != nil && ![[section name] isEqualToString:name]) {
4369 section = name == nil ?
4370 [[[Section alloc] initWithName:nil] autorelease] :
4371 [sections objectForKey:name];
4372 [filtered_ addObject:section];
4375 [section addToCount];
4381 - (void) resetView {
4383 [self _rightButtonClicked];
4386 - (void) resetViewAnimated:(BOOL)animated {
4387 [list_ resetViewAnimated:animated];
4390 - (void) _rightButtonClicked {
4391 if ((editing_ = !editing_))
4394 [delegate_ updateData];
4397 [book_ setTitle:[self title] forPage:self];
4398 [book_ reloadButtonsForPage:self];
4401 - (NSString *) title {
4402 return editing_ ? @"Section Visibility" : @"Install by Section";
4405 - (NSString *) backButtonTitle {
4409 - (NSString *) rightButtonTitle {
4410 return [sections_ count] == 0 ? nil : editing_ ? @"Done" : @"Edit";
4413 - (UIView *) accessoryView {
4419 /* Changes View {{{ */
4420 @interface ChangesView : RVPage {
4421 _transient Database *database_;
4422 NSMutableArray *packages_;
4423 NSMutableArray *sections_;
4424 UISectionList *list_;
4428 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4429 - (void) reloadData;
4433 @implementation ChangesView
4436 [[list_ table] setDelegate:nil];
4437 [list_ setDataSource:nil];
4439 [packages_ release];
4440 [sections_ release];
4445 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
4446 return [sections_ count];
4449 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
4450 return [[sections_ objectAtIndex:section] name];
4453 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
4454 return [[sections_ objectAtIndex:section] row];
4457 - (int) numberOfRowsInTable:(UITable *)table {
4458 return [packages_ count];
4461 - (float) table:(UITable *)table heightForRow:(int)row {
4462 return [PackageCell heightForPackage:[packages_ objectAtIndex:row]];
4465 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
4467 reusing = [[[PackageCell alloc] init] autorelease];
4468 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
4472 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
4476 - (void) tableRowSelected:(NSNotification *)notification {
4477 int row = [[notification object] selectedRow];
4480 Package *package = [packages_ objectAtIndex:row];
4481 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
4482 [view setDelegate:delegate_];
4483 [view setPackage:package];
4484 [book_ pushPage:view];
4487 - (void) _leftButtonClicked {
4488 [(CYBook *)book_ update];
4489 [self reloadButtons];
4492 - (void) _rightButtonClicked {
4493 [delegate_ distUpgrade];
4496 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4497 if ((self = [super initWithBook:book]) != nil) {
4498 database_ = database;
4500 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
4501 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
4503 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:NO];
4504 [self addSubview:list_];
4506 [list_ setShouldHideHeaderInShortLists:NO];
4507 [list_ setDataSource:self];
4508 //[list_ setSectionListStyle:1];
4510 UITableColumn *column = [[[UITableColumn alloc]
4511 initWithTitle:@"Name"
4513 width:[self frame].size.width
4516 UITable *table = [list_ table];
4517 [table setSeparatorStyle:1];
4518 [table addTableColumn:column];
4519 [table setDelegate:self];
4520 [table setReusesTableCells:YES];
4526 - (void) reloadData {
4527 NSArray *packages = [database_ packages];
4529 [packages_ removeAllObjects];
4530 [sections_ removeAllObjects];
4532 for (size_t i(0); i != [packages count]; ++i) {
4533 Package *package([packages objectAtIndex:i]);
4536 [package installed] == nil && [package valid] && [package visible] ||
4537 [package upgradableAndEssential:NO]
4539 [packages_ addObject:package];
4542 [packages_ sortUsingSelector:@selector(compareForChanges:)];
4544 Section *upgradable = [[[Section alloc] initWithName:@"Available Upgrades"] autorelease];
4545 Section *section = nil;
4548 bool unseens = false;
4550 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, Locale_, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
4552 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
4553 Package *package = [packages_ objectAtIndex:offset];
4555 if ([package upgradableAndEssential:YES]) {
4557 [upgradable addToCount];
4560 NSDate *seen = [package seen];
4565 name = [@"n/a ?" retain];
4567 name = (NSString *) CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen);
4570 if (section == nil || ![[section name] isEqualToString:name]) {
4571 section = [[[Section alloc] initWithName:name row:offset] autorelease];
4572 [sections_ addObject:section];
4576 [section addToCount];
4580 CFRelease(formatter);
4583 Section *last = [sections_ lastObject];
4584 size_t count = [last count];
4585 [packages_ removeObjectsInRange:NSMakeRange([packages_ count] - count, count)];
4586 [sections_ removeLastObject];
4590 [sections_ insertObject:upgradable atIndex:0];
4593 [self reloadButtons];
4596 - (void) resetViewAnimated:(BOOL)animated {
4597 [list_ resetViewAnimated:animated];
4600 - (NSString *) leftButtonTitle {
4601 return [(CYBook *)book_ updating] ? nil : @"Refresh";
4604 - (NSString *) rightButtonTitle {
4605 return upgrades_ == 0 ? nil : [NSString stringWithFormat:@"Upgrade All (%u)", upgrades_];
4608 - (NSString *) title {
4614 /* Manage View {{{ */
4615 @interface ManageView : RVPage {
4616 _transient Database *database_;
4617 PackageTable *packages_;
4618 SourceTable *sources_;
4621 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4625 @implementation ManageView
4628 [packages_ release];
4633 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4634 if ((self = [super initWithBook:book]) != nil) {
4635 database_ = database;
4637 packages_ = [[PackageTable alloc]
4641 filter:@selector(isInstalledInSection:)
4645 sources_ = [[SourceTable alloc]
4650 [self addSubview:packages_];
4654 - (void) resetViewAnimated:(BOOL)animated {
4655 [packages_ resetViewAnimated:animated];
4656 [sources_ resetViewAnimated:animated];
4659 - (void) reloadData {
4660 [packages_ reloadData];
4661 [sources_ reloadData];
4664 - (NSString *) title {
4665 return @"Installed Packages";
4668 - (NSString *) backButtonTitle {
4672 - (void) setDelegate:(id)delegate {
4673 [super setDelegate:delegate];
4674 [packages_ setDelegate:delegate];
4675 [sources_ setDelegate:delegate];
4680 /* Search View {{{ */
4681 @protocol SearchViewDelegate
4682 - (void) showKeyboard:(BOOL)show;
4685 @interface SearchView : RVPage {
4687 UISearchField *field_;
4688 UITransitionView *transition_;
4689 PackageTable *table_;
4690 UIPreferencesTable *advanced_;
4696 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4697 - (void) reloadData;
4701 @implementation SearchView
4705 [[field_ textTraits] setEditingDelegate:nil];
4707 [field_ setDelegate:nil];
4709 [accessory_ release];
4711 [transition_ release];
4713 [advanced_ release];
4718 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
4722 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
4724 case 0: return @"Advanced Search (Coming Soon!)";
4726 default: _assert(false);
4730 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
4734 default: _assert(false);
4738 - (void) _showKeyboard:(BOOL)show {
4739 CGSize keysize = [UIKeyboard defaultSize];
4740 CGRect keydown = [book_ pageBounds];
4741 CGRect keyup = keydown;
4742 keyup.size.height -= keysize.height - ButtonBarHeight_;
4744 float delay = KeyboardTime_ * ButtonBarHeight_ / keysize.height;
4746 UIFrameAnimation *animation = [[[UIFrameAnimation alloc] initWithTarget:[table_ list]] autorelease];
4747 [animation setSignificantRectFields:8];
4750 [animation setStartFrame:keydown];
4751 [animation setEndFrame:keyup];
4753 [animation setStartFrame:keyup];
4754 [animation setEndFrame:keydown];
4757 UIAnimator *animator = [UIAnimator sharedAnimator];
4760 addAnimations:[NSArray arrayWithObjects:animation, nil]
4761 withDuration:(KeyboardTime_ - delay)
4766 [animator performSelector:@selector(startAnimation:) withObject:animation afterDelay:delay];
4769 [delegate_ showKeyboard:show];
4773 - (void) textFieldDidBecomeFirstResponder:(UITextField *)field {
4774 [self _showKeyboard:YES];
4777 - (void) textFieldDidResignFirstResponder:(UITextField *)field {
4778 [self _showKeyboard:NO];
4781 - (void) keyboardInputChanged:(UIFieldEditor *)editor {
4783 NSString *text([field_ text]);
4784 [field_ setClearButtonStyle:(text == nil || [text length] == 0 ? 0 : 2)];
4790 - (void) textFieldClearButtonPressed:(UITextField *)field {
4794 - (void) keyboardInputShouldDelete:(id)input {
4798 - (BOOL) keyboardInput:(id)input shouldInsertText:(NSString *)text isMarkedText:(int)marked {
4799 if ([text length] != 1 || [text characterAtIndex:0] != '\n') {
4803 [field_ resignFirstResponder];
4808 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4809 if ((self = [super initWithBook:book]) != nil) {
4810 CGRect pageBounds = [book_ pageBounds];
4812 /*UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:pageBounds] autorelease];
4813 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
4814 [self addSubview:pinstripe];*/
4816 transition_ = [[UITransitionView alloc] initWithFrame:pageBounds];
4817 [self addSubview:transition_];
4819 advanced_ = [[UIPreferencesTable alloc] initWithFrame:pageBounds];
4821 [advanced_ setReusesTableCells:YES];
4822 [advanced_ setDataSource:self];
4823 [advanced_ reloadData];
4825 dimmed_ = [[UIView alloc] initWithFrame:pageBounds];
4826 CGColor dimmed(space_, 0, 0, 0, 0.5);
4827 [dimmed_ setBackgroundColor:dimmed];
4829 table_ = [[PackageTable alloc]
4833 filter:@selector(isSearchedForBy:)
4837 [table_ setShouldHideHeaderInShortLists:NO];
4838 [transition_ transition:0 toView:table_];
4847 area.origin.x = /*cnfrect.origin.x + cnfrect.size.width + 4 +*/ 10;
4854 [self bounds].size.width - area.origin.x - 18;
4856 area.size.height = [UISearchField defaultHeight];
4858 field_ = [[UISearchField alloc] initWithFrame:area];
4860 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
4861 [field_ setFont:font];
4864 [field_ setPlaceholder:@"Package Names & Descriptions"];
4865 [field_ setDelegate:self];
4868 [field_ setPaddingTop:3];
4870 [field_ setPaddingTop:5];
4873 UITextTraits *traits = [field_ textTraits];
4874 [traits setAutoCapsType:0];
4875 [traits setAutoCorrectionType:1];
4876 [traits setReturnKeyType:6];
4879 [traits setEditingDelegate:self];
4882 CGRect accrect = {{0, 6}, {6 + cnfrect.size.width + 6 + area.size.width + 6, area.size.height + 30}};
4884 accessory_ = [[UIView alloc] initWithFrame:accrect];
4885 [accessory_ addSubview:field_];
4887 /*UIPushButton *configure = [[[UIPushButton alloc] initWithFrame:cnfrect] autorelease];
4888 [configure setShowPressFeedback:YES];
4889 [configure setImage:[UIImage applicationImageNamed:@"advanced.png"]];
4890 [configure addTarget:self action:@selector(configurePushed) forEvents:1];
4891 [accessory_ addSubview:configure];*/
4897 LKAnimation *animation = [LKTransition animation];
4898 [animation setType:@"oglFlip"];
4899 [animation setTimingFunction:[LKTimingFunction functionWithName:@"easeInEaseOut"]];
4900 [animation setFillMode:@"extended"];
4901 [animation setTransitionFlags:3];
4902 [animation setDuration:10];
4903 [animation setSpeed:0.35];
4904 [animation setSubtype:(flipped_ ? @"fromLeft" : @"fromRight")];
4905 [[transition_ _layer] addAnimation:animation forKey:0];
4906 [transition_ transition:0 toView:(flipped_ ? (UIView *) table_ : (UIView *) advanced_)];
4907 flipped_ = !flipped_;
4911 - (void) configurePushed {
4912 [field_ resignFirstResponder];
4916 - (void) resetViewAnimated:(BOOL)animated {
4919 [table_ resetViewAnimated:animated];
4922 - (void) reloadData {
4925 [table_ setObject:[field_ text]];
4926 [table_ reloadData];
4927 [table_ resetCursor];
4930 - (UIView *) accessoryView {
4934 - (NSString *) title {
4938 - (NSString *) backButtonTitle {
4942 - (void) setDelegate:(id)delegate {
4943 [table_ setDelegate:delegate];
4944 [super setDelegate:delegate];
4950 @implementation CYBook
4954 [indicator_ release];
4956 [progress_ release];
4960 - (NSString *) getTitleForPage:(RVPage *)page {
4961 return Simplify([super getTitleForPage:page]);
4969 [navbar_ setPrompt:@""];
4970 [navbar_ addSubview:overlay_];
4971 [indicator_ startAnimation];
4972 [prompt_ setText:@"Updating Database..."];
4973 [progress_ setProgress:0];
4978 detachNewThreadSelector:@selector(_update)
4987 [overlay_ removeFromSuperview];
4988 [indicator_ stopAnimation];
4989 [delegate_ reloadData];
4991 [self setPrompt:[NSString stringWithFormat:@"Last Updated: %@", GetLastUpdate()]];
4994 - (id) initWithFrame:(CGRect)frame database:(Database *)database {
4995 if ((self = [super initWithFrame:frame]) != nil) {
4996 database_ = database;
4999 [navbar_ setBarStyle:1];
5001 CGRect ovrrect = [navbar_ bounds];
5002 ovrrect.size.height = ([UINavigationBar defaultSizeWithPrompt].height - [UINavigationBar defaultSize].height);
5004 overlay_ = [[UIView alloc] initWithFrame:ovrrect];
5006 UIProgressIndicatorStyle style = Advanced_ ?
5007 kUIProgressIndicatorStyleSmallWhite :
5008 kUIProgressIndicatorStyleSmallBlack;
5010 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:style];
5011 unsigned indoffset = (ovrrect.size.height - indsize.height) / 2;
5012 CGRect indrect = {{indoffset, indoffset}, indsize};
5014 indicator_ = [[UIProgressIndicator alloc] initWithFrame:indrect];
5015 [indicator_ setStyle:style];
5016 [overlay_ addSubview:indicator_];
5018 CGSize prmsize = {200, indsize.width + 4};
5021 indoffset * 2 + indsize.width,
5025 (ovrrect.size.height - prmsize.height) / 2
5028 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 12);
5030 prompt_ = [[UITextLabel alloc] initWithFrame:prmrect];
5032 [prompt_ setColor:(Advanced_ ? White_ : Blueish_)];
5033 [prompt_ setBackgroundColor:Clear_];
5034 [prompt_ setFont:font];
5038 [overlay_ addSubview:prompt_];
5040 CGSize prgsize = {75, 100};
5043 ovrrect.size.width - prgsize.width - 10,
5044 (ovrrect.size.height - prgsize.height) / 2
5047 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
5048 [progress_ setStyle:0];
5049 [overlay_ addSubview:progress_];
5054 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5057 status.setDelegate(self);
5059 [database_ updateWithStatus:status];
5062 performSelectorOnMainThread:@selector(_update_)
5070 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id {
5071 [prompt_ setText:[NSString stringWithFormat:@"Error: %@", error]];
5074 - (void) setProgressTitle:(NSString *)title {
5076 performSelectorOnMainThread:@selector(_setProgressTitle:)
5082 - (void) setProgressPercent:(float)percent {
5085 - (void) addProgressOutput:(NSString *)output {
5087 performSelectorOnMainThread:@selector(_addProgressOutput:)
5093 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
5097 - (void) _setProgressTitle:(NSString *)title {
5098 [prompt_ setText:[title stringByAppendingString:@"..."]];
5101 - (void) _addProgressOutput:(NSString *)output {
5106 @interface Cydia : UIApplication <
5107 ConfirmationViewDelegate,
5108 ProgressViewDelegate,
5117 UIButtonBar *buttonbar_;
5119 ConfirmationView *confirm_;
5121 NSMutableArray *essential_;
5122 NSMutableArray *broken_;
5124 Database *database_;
5125 ProgressView *progress_;
5129 UIKeyboard *keyboard_;
5130 UIProgressHUD *hud_;
5132 InstallView *install_;
5133 ChangesView *changes_;
5134 ManageView *manage_;
5135 SearchView *search_;
5140 @implementation Cydia
5143 if ([broken_ count] != 0) {
5144 int count = [broken_ count];
5146 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
5147 initWithTitle:[NSString stringWithFormat:@"%d Half-Installed Package%@", count, (count == 1 ? @"" : @"s")]
5148 buttons:[NSArray arrayWithObjects:
5150 @"Ignore (Temporary)",
5152 defaultButtonIndex:0
5157 [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."];
5158 [sheet popupAlertAnimated:YES];
5159 } else if (!Ignored_ && [essential_ count] != 0) {
5160 int count = [essential_ count];
5162 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
5163 initWithTitle:[NSString stringWithFormat:@"%d Essential Upgrade%@", count, (count == 1 ? @"" : @"s")]
5164 buttons:[NSArray arrayWithObjects:@"Upgrade Essential", @"Ignore (Temporary)", nil]
5165 defaultButtonIndex:0
5170 [sheet setBodyText:@"One or more essential packages are currently out of date. If these upgrades are not performed you are likely to encounter errors."];
5171 [sheet popupAlertAnimated:YES];
5175 - (void) _reloadData {
5176 /*UIProgressHUD *hud = [[UIProgressHUD alloc] initWithWindow:window_];
5177 [hud setText:@"Reloading Data"];
5178 [overlay_ addSubview:hud];
5181 [database_ reloadData];
5183 if (Packages_ == nil) {
5184 Packages_ = [[NSMutableDictionary alloc] initWithCapacity:128];
5185 [Metadata_ setObject:Packages_ forKey:@"Packages"];
5188 if (Sections_ == nil) {
5189 Sections_ = [[NSMutableDictionary alloc] initWithCapacity:32];
5190 [Metadata_ setObject:Sections_ forKey:@"Sections"];
5195 [essential_ removeAllObjects];
5196 [broken_ removeAllObjects];
5198 NSArray *packages = [database_ packages];
5199 for (int i(0), e([packages count]); i != e; ++i) {
5200 Package *package = [packages objectAtIndex:i];
5202 [broken_ addObject:package];
5203 if ([package upgradableAndEssential:NO]) {
5204 if ([package essential])
5205 [essential_ addObject:package];
5211 NSString *badge([[NSNumber numberWithInt:changes] stringValue]);
5212 [buttonbar_ setBadgeValue:badge forButton:3];
5213 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
5214 [buttonbar_ setBadgeAnimated:YES forButton:3];
5215 [self setApplicationBadge:badge];
5217 [buttonbar_ setBadgeValue:nil forButton:3];
5218 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
5219 [buttonbar_ setBadgeAnimated:NO forButton:3];
5220 [self removeApplicationBadge];
5225 if ([packages count] == 0);
5234 [hud removeFromSuperview];*/
5237 - (void) updateData {
5239 _assert([Metadata_ writeToFile:@"/var/lib/cydia/metadata.plist" atomically:YES] == YES);
5243 /* XXX: this is just stupid */
5245 [install_ reloadData];
5247 [changes_ reloadData];
5249 [manage_ reloadData];
5251 [search_ reloadData];
5256 - (void) reloadData {
5257 @synchronized (self) {
5258 if (confirm_ == nil)
5264 pkgProblemResolver *resolver = [database_ resolver];
5266 resolver->InstallProtect();
5267 if (!resolver->Resolve(true))
5272 [database_ prepare];
5274 if ([database_ cache]->BrokenCount() == 0)
5275 confirm_ = [[ConfirmationView alloc] initWithView:underlay_ database:database_ delegate:self];
5277 NSMutableArray *broken = [NSMutableArray arrayWithCapacity:16];
5278 NSArray *packages = [database_ packages];
5280 for (size_t i(0); i != [packages count]; ++i) {
5281 Package *package = [packages objectAtIndex:i];
5282 if ([package broken])
5283 [broken addObject:[package name]];
5286 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
5287 initWithTitle:[NSString stringWithFormat:@"%d Broken Packages", [database_ cache]->BrokenCount()]
5288 buttons:[NSArray arrayWithObjects:@"Okay", nil]
5289 defaultButtonIndex:0
5294 [sheet setBodyText:[NSString stringWithFormat:@"The following packages have unmet dependencies:\n\n%@", [broken componentsJoinedByString:@"\n"]]];
5295 [sheet popupAlertAnimated:YES];
5301 - (void) installPackage:(Package *)package {
5302 @synchronized (self) {
5309 - (void) removePackage:(Package *)package {
5310 @synchronized (self) {
5317 - (void) distUpgrade {
5318 @synchronized (self) {
5319 [database_ upgrade];
5325 @synchronized (self) {
5333 [overlay_ removeFromSuperview];
5337 detachNewThreadSelector:@selector(perform)
5344 - (void) bootstrap_ {
5346 [database_ upgrade];
5347 [database_ prepare];
5348 [database_ perform];
5351 - (void) bootstrap {
5353 detachNewThreadSelector:@selector(bootstrap_)
5356 title:@"Bootstrap Install..."
5360 - (void) progressViewIsComplete:(ProgressView *)progress {
5361 @synchronized (self) {
5364 if (confirm_ != nil) {
5365 [underlay_ addSubview:overlay_];
5366 [confirm_ removeFromSuperview];
5373 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
5374 NSString *context = [sheet context];
5375 if ([context isEqualToString:@"fixhalf"])
5378 @synchronized (self) {
5379 for (int i = 0, e = [broken_ count]; i != e; ++i) {
5380 Package *broken = [broken_ objectAtIndex:i];
5383 NSString *id = [broken id];
5384 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.prerm", id] UTF8String]);
5385 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.postrm", id] UTF8String]);
5386 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.preinst", id] UTF8String]);
5387 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.postinst", id] UTF8String]);
5396 [broken_ removeAllObjects];
5403 else if ([context isEqualToString:@"upgrade"])
5406 @synchronized (self) {
5407 for (int i = 0, e = [essential_ count]; i != e; ++i) {
5408 Package *essential = [essential_ objectAtIndex:i];
5409 [essential install];
5428 - (void) setPage:(RVPage *)page {
5429 [page resetViewAnimated:NO];
5430 [page setDelegate:self];
5431 [book_ setPage:page];
5434 - (RVPage *) _setHomePage {
5435 BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease];
5436 [self setPage:browser];
5437 [browser loadURL:[NSURL URLWithString:@"http://cydia.saurik.com/"]];
5441 - (void) buttonBarItemTapped:(id)sender {
5442 unsigned tag = [sender tag];
5444 [book_ resetViewAnimated:YES];
5446 } else if (tag_ == 2 && tag != 2)
5447 [install_ resetView];
5450 case 1: [self _setHomePage]; break;
5452 case 2: [self setPage:install_]; break;
5453 case 3: [self setPage:changes_]; break;
5454 case 4: [self setPage:manage_]; break;
5455 case 5: [self setPage:search_]; break;
5457 default: _assert(false);
5463 - (void) fixSpringBoard {
5464 pid_t pid = ExecFork();
5468 if (pid_t child = fork()) {
5469 waitpid(child, NULL, 0);
5471 execlp("launchctl", "launchctl", "unload", SpringBoard_, NULL);
5472 perror("launchctl unload");
5476 execlp("launchctl", "launchctl", "load", SpringBoard_, NULL);
5477 perror("launchctl load");
5482 - (void) applicationWillSuspend {
5487 [self fixSpringBoard];
5491 [super applicationWillSuspend];
5496 [self setStatusBarShowsProgress:NO];
5499 [hud_ removeFromSuperview];
5503 pid_t pid = ExecFork();
5505 execlp("launchctl", "launchctl", "stop", "com.apple.SpringBoard", NULL);
5506 perror("launchctl stop");
5512 overlay_ = [[UIView alloc] initWithFrame:[underlay_ bounds]];
5514 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
5515 book_ = [[CYBook alloc] initWithFrame:CGRectMake(
5516 0, 0, screenrect.size.width, screenrect.size.height - 48
5517 ) database:database_];
5519 [book_ setDelegate:self];
5521 [overlay_ addSubview:book_];
5523 NSArray *buttonitems = [NSArray arrayWithObjects:
5524 [NSDictionary dictionaryWithObjectsAndKeys:
5525 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5526 @"home-up.png", kUIButtonBarButtonInfo,
5527 @"home-dn.png", kUIButtonBarButtonSelectedInfo,
5528 [NSNumber numberWithInt:1], kUIButtonBarButtonTag,
5529 self, kUIButtonBarButtonTarget,
5530 @"Home", kUIButtonBarButtonTitle,
5531 @"0", kUIButtonBarButtonType,
5534 [NSDictionary dictionaryWithObjectsAndKeys:
5535 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5536 @"install-up.png", kUIButtonBarButtonInfo,
5537 @"install-dn.png", kUIButtonBarButtonSelectedInfo,
5538 [NSNumber numberWithInt:2], kUIButtonBarButtonTag,
5539 self, kUIButtonBarButtonTarget,
5540 @"Sections", kUIButtonBarButtonTitle,
5541 @"0", kUIButtonBarButtonType,
5544 [NSDictionary dictionaryWithObjectsAndKeys:
5545 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5546 @"changes-up.png", kUIButtonBarButtonInfo,
5547 @"changes-dn.png", kUIButtonBarButtonSelectedInfo,
5548 [NSNumber numberWithInt:3], kUIButtonBarButtonTag,
5549 self, kUIButtonBarButtonTarget,
5550 @"Changes", kUIButtonBarButtonTitle,
5551 @"0", kUIButtonBarButtonType,
5554 [NSDictionary dictionaryWithObjectsAndKeys:
5555 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5556 @"manage-up.png", kUIButtonBarButtonInfo,
5557 @"manage-dn.png", kUIButtonBarButtonSelectedInfo,
5558 [NSNumber numberWithInt:4], kUIButtonBarButtonTag,
5559 self, kUIButtonBarButtonTarget,
5560 @"Manage", kUIButtonBarButtonTitle,
5561 @"0", kUIButtonBarButtonType,
5564 [NSDictionary dictionaryWithObjectsAndKeys:
5565 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5566 @"search-up.png", kUIButtonBarButtonInfo,
5567 @"search-dn.png", kUIButtonBarButtonSelectedInfo,
5568 [NSNumber numberWithInt:5], kUIButtonBarButtonTag,
5569 self, kUIButtonBarButtonTarget,
5570 @"Search", kUIButtonBarButtonTitle,
5571 @"0", kUIButtonBarButtonType,
5575 buttonbar_ = [[UIButtonBar alloc]
5577 withFrame:CGRectMake(
5578 0, screenrect.size.height - ButtonBarHeight_,
5579 screenrect.size.width, ButtonBarHeight_
5581 withItemList:buttonitems
5584 [buttonbar_ setDelegate:self];
5585 [buttonbar_ setBarStyle:1];
5586 [buttonbar_ setButtonBarTrackingMode:2];
5588 int buttons[5] = {1, 2, 3, 4, 5};
5589 [buttonbar_ registerButtonGroup:0 withButtons:buttons withCount:5];
5590 [buttonbar_ showButtonGroup:0 withDuration:0];
5592 for (int i = 0; i != 5; ++i)
5593 [[buttonbar_ viewWithTag:(i + 1)] setFrame:CGRectMake(
5594 i * 64 + 2, 1, 60, ButtonBarHeight_
5597 [buttonbar_ showSelectionForButton:1];
5598 [overlay_ addSubview:buttonbar_];
5600 [UIKeyboard initImplementationNow];
5601 CGSize keysize = [UIKeyboard defaultSize];
5602 CGRect keyrect = {{0, [overlay_ bounds].size.height}, keysize};
5603 keyboard_ = [[UIKeyboard alloc] initWithFrame:keyrect];
5604 [[UIKeyboardImpl sharedInstance] setSoundsEnabled:(Sounds_Keyboard_ ? YES : NO)];
5605 [overlay_ addSubview:keyboard_];
5607 install_ = [[InstallView alloc] initWithBook:book_ database:database_];
5608 changes_ = [[ChangesView alloc] initWithBook:book_ database:database_];
5609 manage_ = [[ManageView alloc] initWithBook:book_ database:database_];
5610 search_ = [[SearchView alloc] initWithBook:book_ database:database_];
5613 [underlay_ addSubview:overlay_];
5620 [self _setHomePage];
5623 - (void) reorganize {
5624 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5625 system("/usr/libexec/cydia/free.sh");
5626 [self performSelectorOnMainThread:@selector(finish) withObject:nil waitUntilDone:NO];
5630 - (void) applicationSuspend:(__GSEvent *)event {
5631 if (hud_ == nil && ![progress_ isRunning])
5632 [super applicationSuspend:event];
5635 - (void) _animateSuspension:(BOOL)arg0 duration:(double)arg1 startTime:(double)arg2 scale:(float)arg3 {
5637 [super _animateSuspension:arg0 duration:arg1 startTime:arg2 scale:arg3];
5640 - (void) _setSuspended:(BOOL)value {
5642 [super _setSuspended:value];
5645 - (void) applicationDidFinishLaunching:(id)unused {
5646 _assert(pkgInitConfig(*_config));
5647 _assert(pkgInitSystem(*_config, _system));
5652 essential_ = [[NSMutableArray alloc] initWithCapacity:4];
5653 broken_ = [[NSMutableArray alloc] initWithCapacity:4];
5655 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
5656 window_ = [[UIWindow alloc] initWithContentRect:screenrect];
5658 [window_ orderFront: self];
5659 [window_ makeKey: self];
5660 [window_ _setHidden: NO];
5662 database_ = [[Database alloc] init];
5663 progress_ = [[ProgressView alloc] initWithFrame:[window_ bounds] database:database_ delegate:self];
5664 [database_ setDelegate:progress_];
5665 [window_ setContentView:progress_];
5667 underlay_ = [[UIView alloc] initWithFrame:[progress_ bounds]];
5668 [progress_ setContentView:underlay_];
5670 [progress_ resetView];
5673 readlink("/Applications", NULL, 0) == -1 && errno == EINVAL ||
5674 readlink("/Library/Ringtones", NULL, 0) == -1 && errno == EINVAL ||
5675 readlink("/Library/Wallpaper", NULL, 0) == -1 && errno == EINVAL ||
5676 readlink("/usr/include", NULL, 0) == -1 && errno == EINVAL ||
5677 readlink("/usr/libexec", NULL, 0) == -1 && errno == EINVAL ||
5678 readlink("/usr/share", NULL, 0) == -1 && errno == EINVAL
5680 hud_ = [[UIProgressHUD alloc] initWithWindow:window_];
5681 [hud_ setText:@"Reorganizing\n\nWill Automatically\nRestart When Done"];
5683 [underlay_ addSubview:hud_];
5685 [self setStatusBarShowsProgress:YES];
5688 detachNewThreadSelector:@selector(reorganize)
5696 - (void) showKeyboard:(BOOL)show {
5697 CGSize keysize = [UIKeyboard defaultSize];
5698 CGRect keydown = {{0, [overlay_ bounds].size.height}, keysize};
5699 CGRect keyup = keydown;
5700 keyup.origin.y -= keysize.height;
5702 UIFrameAnimation *animation = [[[UIFrameAnimation alloc] initWithTarget:keyboard_] autorelease];
5703 [animation setSignificantRectFields:2];
5706 [animation setStartFrame:keydown];
5707 [animation setEndFrame:keyup];
5708 [keyboard_ activate];
5710 [animation setStartFrame:keyup];
5711 [animation setEndFrame:keydown];
5712 [keyboard_ deactivate];
5715 [[UIAnimator sharedAnimator]
5716 addAnimations:[NSArray arrayWithObjects:animation, nil]
5717 withDuration:KeyboardTime_
5722 - (void) slideUp:(UIAlertSheet *)alert {
5724 [alert presentSheetFromButtonBar:buttonbar_];
5726 [alert presentSheetInView:overlay_];
5731 void AddPreferences(NSString *plist) {
5732 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5734 NSMutableDictionary *settings = [[[NSMutableDictionary alloc] initWithContentsOfFile:plist] autorelease];
5735 _assert(settings != NULL);
5736 NSMutableArray *items = [settings objectForKey:@"items"];
5740 for (size_t i(0); i != [items count]; ++i) {
5741 NSMutableDictionary *item([items objectAtIndex:i]);
5742 NSString *label = [item objectForKey:@"label"];
5743 if (label != nil && [label isEqualToString:@"Cydia"]) {
5750 for (size_t i(0); i != [items count]; ++i) {
5751 NSDictionary *item([items objectAtIndex:i]);
5752 NSString *label = [item objectForKey:@"label"];
5753 if (label != nil && [label isEqualToString:@"General"]) {
5754 [items insertObject:[NSDictionary dictionaryWithObjectsAndKeys:
5755 @"CydiaSettings", @"bundle",
5756 @"PSLinkCell", @"cell",
5757 [NSNumber numberWithBool:YES], @"hasIcon",
5758 [NSNumber numberWithBool:YES], @"isController",
5760 nil] atIndex:(i + 1)];
5766 _assert([settings writeToFile:plist atomically:YES] == YES);
5773 id Alloc_(id self, SEL selector) {
5774 id object = alloc_(self, selector);
5775 fprintf(stderr, "[%s]A-%p\n", self->isa->name, object);
5780 id Dealloc_(id self, SEL selector) {
5781 id object = dealloc_(self, selector);
5782 fprintf(stderr, "[%s]D-%p\n", self->isa->name, object);
5786 int main(int argc, char *argv[]) {
5787 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5789 bootstrap_ = argc > 1 && strcmp(argv[1], "--bootstrap") == 0;
5791 Home_ = NSHomeDirectory();
5794 NSString *plist = [Home_ stringByAppendingString:@"/Library/Preferences/com.apple.preferences.sounds.plist"];
5795 if (NSDictionary *sounds = [NSDictionary dictionaryWithContentsOfFile:plist])
5796 if (NSNumber *keyboard = [sounds objectForKey:@"keyboard"])
5797 Sounds_Keyboard_ = [keyboard boolValue];
5803 if (unlink("/var/cache/apt/pkgcache.bin") == -1)
5804 _assert(errno == ENOENT);
5805 if (unlink("/var/cache/apt/srcpkgcache.bin") == -1)
5806 _assert(errno == ENOENT);
5808 /*Method alloc = class_getClassMethod([NSObject class], @selector(alloc));
5809 alloc_ = alloc->method_imp;
5810 alloc->method_imp = (IMP) &Alloc_;*/
5812 /*Method dealloc = class_getClassMethod([NSObject class], @selector(dealloc));
5813 dealloc_ = dealloc->method_imp;
5814 dealloc->method_imp = (IMP) &Dealloc_;*/
5816 if (NSDictionary *sysver = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]) {
5817 if (NSString *prover = [sysver valueForKey:@"ProductVersion"]) {
5818 Firmware_ = strdup([prover UTF8String]);
5819 NSArray *versions = [prover componentsSeparatedByString:@"."];
5820 int count = [versions count];
5821 Major_ = count > 0 ? [[versions objectAtIndex:0] intValue] : 0;
5822 Minor_ = count > 1 ? [[versions objectAtIndex:1] intValue] : 0;
5823 BugFix_ = count > 2 ? [[versions objectAtIndex:2] intValue] : 0;
5828 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
5829 char *machine = new char[size];
5830 sysctlbyname("hw.machine", machine, &size, NULL, 0);
5833 if (CFMutableDictionaryRef dict = IOServiceMatching("IOPlatformExpertDevice"))
5834 if (io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, dict)) {
5835 if (CFTypeRef serial = IORegistryEntryCreateCFProperty(service, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0)) {
5836 SerialNumber_ = strdup(CFStringGetCStringPtr((CFStringRef) serial, CFStringGetSystemEncoding()));
5840 IOObjectRelease(service);
5843 /*AddPreferences(@"/Applications/Preferences.app/Settings-iPhone.plist");
5844 AddPreferences(@"/Applications/Preferences.app/Settings-iPod.plist");*/
5846 if ((Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"]) == NULL)
5847 Metadata_ = [[NSMutableDictionary alloc] initWithCapacity:2];
5849 Packages_ = [Metadata_ objectForKey:@"Packages"];
5850 Sections_ = [Metadata_ objectForKey:@"Sections"];
5853 if (access("/User", F_OK) != 0)
5854 system("/usr/libexec/cydia/firmware.sh");
5856 Locale_ = CFLocaleCopyCurrent();
5857 space_ = CGColorSpaceCreateDeviceRGB();
5859 Blueish_.Set(space_, 0x19/255.f, 0x32/255.f, 0x50/255.f, 1.0);
5860 Black_.Set(space_, 0.0, 0.0, 0.0, 1.0);
5861 Clear_.Set(space_, 0.0, 0.0, 0.0, 0.0);
5862 Red_.Set(space_, 1.0, 0.0, 0.0, 1.0);
5863 White_.Set(space_, 1.0, 1.0, 1.0, 1.0);
5865 int value = UIApplicationMain(argc, argv, [Cydia class]);
5867 CGColorSpaceRelease(space_);