1 /* Cydia - iPhone UIKit Front-End for Debian APT
2 * Copyright (C) 2008 Jay Freeman (saurik)
6 * Redistribution and use in source and binary
7 * forms, with or without modification, are permitted
8 * provided that the following conditions are met:
10 * 1. Redistributions of source code must retain the
11 * above copyright notice, this list of conditions
12 * and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the
14 * above copyright notice, this list of conditions
15 * and the following disclaimer in the documentation
16 * and/or other materials provided with the
18 * 3. The name of the author may not be used to endorse
19 * or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS''
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
24 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
33 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
35 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 /* #include Directives {{{ */
39 #include <objc/objc.h>
40 #include <objc/runtime.h>
42 #include <CoreGraphics/CoreGraphics.h>
43 #include <GraphicsServices/GraphicsServices.h>
44 #include <Foundation/Foundation.h>
45 #include <UIKit/UIKit.h>
46 #include <WebCore/DOMHTML.h>
48 #import "BrowserView.h"
50 #import "UICaboodle.h"
52 #include <WebKit/WebFrame.h>
53 #include <WebKit/WebView.h>
58 #include <ext/stdio_filebuf.h>
60 #include <apt-pkg/acquire.h>
61 #include <apt-pkg/acquire-item.h>
62 #include <apt-pkg/algorithms.h>
63 #include <apt-pkg/cachefile.h>
64 #include <apt-pkg/clean.h>
65 #include <apt-pkg/configuration.h>
66 #include <apt-pkg/debmetaindex.h>
67 #include <apt-pkg/error.h>
68 #include <apt-pkg/init.h>
69 #include <apt-pkg/pkgrecords.h>
70 #include <apt-pkg/sourcelist.h>
71 #include <apt-pkg/sptr.h>
73 #include <sys/sysctl.h>
77 #include <mach-o/nlist.h>
88 /* iPhoneOS 2.0 Compatibility {{{ */
90 @interface UICGColor : NSObject {
93 - (id) initWithCGColor:(CGColorRef)color;
99 - (UIFont *) fontWithSize:(CGFloat)size;
102 @interface NSObject (iPhoneOS)
103 - (CGColorRef) cgColor;
104 - (CGColorRef) CGColor;
108 @implementation NSObject (iPhoneOS)
110 - (CGColorRef) cgColor {
111 return [self CGColor];
114 - (CGColorRef) CGColor {
115 return (CGColorRef) self;
119 [[[[objc_getClass("UICGColor") alloc] initWithCGColor:[self CGColor]] autorelease] set];
124 @interface UITextView (iPhoneOS)
125 - (void) setTextSize:(float)size;
128 @implementation UITextView (iPhoneOS)
130 - (void) setTextSize:(float)size {
131 [self setFont:[[self font] fontWithSize:size]];
139 kUIControlEventMouseDown = 1 << 0,
140 kUIControlEventMouseMovedInside = 1 << 2, // mouse moved inside control target
141 kUIControlEventMouseMovedOutside = 1 << 3, // mouse moved outside control target
142 kUIControlEventMouseUpInside = 1 << 6, // mouse up inside control target
143 kUIControlEventMouseUpOutside = 1 << 7, // mouse up outside control target
144 kUIControlAllEvents = (kUIControlEventMouseDown | kUIControlEventMouseMovedInside | kUIControlEventMouseMovedOutside | kUIControlEventMouseUpInside | kUIControlEventMouseUpOutside)
145 } UIControlEventMasks;
147 @interface NSString (UIKit)
148 - (NSString *) stringByAddingPercentEscapes;
149 - (NSString *) stringByReplacingCharacter:(unsigned short)arg0 withCharacter:(unsigned short)arg1;
152 @interface NSString (Cydia)
153 + (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length;
154 - (NSComparisonResult) compareByPath:(NSString *)other;
157 @implementation NSString (Cydia)
159 + (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length {
160 char data[length + 1];
161 memcpy(data, bytes, length);
163 return [NSString stringWithUTF8String:data];
166 - (NSComparisonResult) compareByPath:(NSString *)other {
167 NSString *prefix = [self commonPrefixWithString:other options:0];
168 size_t length = [prefix length];
170 NSRange lrange = NSMakeRange(length, [self length] - length);
171 NSRange rrange = NSMakeRange(length, [other length] - length);
173 lrange = [self rangeOfString:@"/" options:0 range:lrange];
174 rrange = [other rangeOfString:@"/" options:0 range:rrange];
176 NSComparisonResult value;
178 if (lrange.location == NSNotFound && rrange.location == NSNotFound)
179 value = NSOrderedSame;
180 else if (lrange.location == NSNotFound)
181 value = NSOrderedAscending;
182 else if (rrange.location == NSNotFound)
183 value = NSOrderedDescending;
185 value = NSOrderedSame;
187 NSString *lpath = lrange.location == NSNotFound ? [self substringFromIndex:length] :
188 [self substringWithRange:NSMakeRange(length, lrange.location - length)];
189 NSString *rpath = rrange.location == NSNotFound ? [other substringFromIndex:length] :
190 [other substringWithRange:NSMakeRange(length, rrange.location - length)];
192 NSComparisonResult result = [lpath compare:rpath];
193 return result == NSOrderedSame ? value : result;
198 /* Perl-Compatible RegEx {{{ */
208 Pcre(const char *regex) :
213 code_ = pcre_compile(regex, 0, &error, &offset, NULL);
216 fprintf(stderr, "%d:%s\n", offset, error);
220 pcre_fullinfo(code_, study_, PCRE_INFO_CAPTURECOUNT, &capture_);
221 matches_ = new int[(capture_ + 1) * 3];
229 NSString *operator [](size_t match) {
230 return [NSString stringWithUTF8Bytes:(data_ + matches_[match * 2]) length:(matches_[match * 2 + 1] - matches_[match * 2])];
233 bool operator ()(NSString *data) {
234 // XXX: length is for characters, not for bytes
235 return operator ()([data UTF8String], [data length]);
238 bool operator ()(const char *data, size_t size) {
240 return pcre_exec(code_, study_, data, size, 0, 0, matches_, (capture_ + 1) * 3) >= 0;
244 /* Mime Addresses {{{ */
245 Pcre email_r("^\"?(.*)\"? <([^>]*)>$");
247 @interface Address : NSObject {
253 - (NSString *) email;
255 + (Address *) addressWithString:(NSString *)string;
256 - (Address *) initWithString:(NSString *)string;
259 @implementation Address
268 - (NSString *) name {
272 - (NSString *) email {
276 + (Address *) addressWithString:(NSString *)string {
277 return [[[Address alloc] initWithString:string] autorelease];
280 - (Address *) initWithString:(NSString *)string {
281 if ((self = [super init]) != nil) {
282 const char *data = [string UTF8String];
283 size_t size = [string length];
285 if (email_r(data, size)) {
286 name_ = [email_r[1] retain];
287 email_ = [email_r[2] retain];
289 name_ = [[NSString alloc]
292 encoding:kCFStringEncodingUTF8
302 /* CoreGraphics Primitives {{{ */
313 CGColor(CGColorSpaceRef space, float red, float green, float blue, float alpha) :
316 Set(space, red, green, blue, alpha);
321 CGColorRelease(color_);
328 void Set(CGColorSpaceRef space, float red, float green, float blue, float alpha) {
330 float color[] = {red, green, blue, alpha};
331 color_ = CGColorCreate(space, color);
334 operator CGColorRef() {
349 /* Right Alignment {{{ */
350 @interface UIRightTextLabel : UITextLabel {
351 float _savedRightEdgeX;
352 BOOL _sizedtofit_flag;
355 - (void) setFrame:(CGRect)frame;
356 - (void) setText:(NSString *)text;
357 - (void) realignText;
360 @implementation UIRightTextLabel
362 - (void) setFrame:(CGRect)frame {
363 [super setFrame:frame];
364 if (_sizedtofit_flag == NO) {
365 _savedRightEdgeX = frame.origin.x;
370 - (void) setText:(NSString *)text {
371 [super setText:text];
375 - (void) realignText {
376 CGRect oldFrame = [self frame];
378 _sizedtofit_flag = YES;
379 [self sizeToFit]; // shrink down size so I can right align it
381 CGRect newFrame = [self frame];
383 oldFrame.origin.x = _savedRightEdgeX - newFrame.size.width;
384 oldFrame.size.width = newFrame.size.width;
385 [super setFrame:oldFrame];
386 _sizedtofit_flag = NO;
392 /* Random Global Variables {{{ */
393 static const int PulseInterval_ = 50000;
394 static const int ButtonBarHeight_ = 48;
395 static const float KeyboardTime_ = 0.4f;
396 static const char * const SpringBoard_ = "/System/Library/LaunchDaemons/com.apple.SpringBoard.plist";
402 static CGColor Blueish_;
403 static CGColor Black_;
404 static CGColor Clear_;
406 static CGColor White_;
408 static NSString *Home_;
409 static BOOL Sounds_Keyboard_;
411 static BOOL Advanced_;
413 static BOOL Ignored_;
415 const char *Firmware_ = NULL;
416 const char *Machine_ = NULL;
417 const char *SerialNumber_ = NULL;
424 CGColorSpaceRef space_;
426 #define FW_LEAST(major, minor, bugfix) \
427 (major < Major_ || major == Major_ && \
428 (minor < Minor_ || minor == Minor_ && \
434 static NSMutableDictionary *Metadata_;
435 static NSMutableDictionary *Packages_;
436 static bool Changed_;
439 NSString *GetLastUpdate() {
440 NSDate *update = [Metadata_ objectForKey:@"LastUpdate"];
443 return @"Never or Unknown";
445 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, Locale_, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
446 CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) update);
448 CFRelease(formatter);
450 return [(NSString *) formatted autorelease];
453 /* Display Helpers {{{ */
454 inline float Interpolate(float begin, float end, float fraction) {
455 return (end - begin) * fraction + begin;
458 NSString *SizeString(double size) {
460 while (size > 1024) {
465 static const char *powers_[] = {"B", "kB", "MB", "GB"};
467 return [NSString stringWithFormat:@"%.1f%s", size, powers_[power]];
470 NSString *StripVersion(NSString *version) {
471 NSRange colon = [version rangeOfString:@":"];
472 if (colon.location != NSNotFound)
473 version = [version substringFromIndex:(colon.location + 1)];
477 static const float TextViewOffset_ = 22;
479 UITextView *GetTextView(NSString *value, float left, bool html) {
480 UITextView *text([[[UITextView alloc] initWithFrame:CGRectMake(left, 3, 310 - left, 1000)] autorelease]);
481 [text setEditable:NO];
482 [text setTextSize:16];
484 [text setHTML:value];
486 [text setText:value];
487 [text setEnabled:NO];
489 [text setBackgroundColor:Clear_];
491 CGRect frame = [text frame];
492 [text setFrame:frame];
493 CGRect rect = [text visibleTextRect];
494 frame.size.height = rect.size.height;
495 [text setFrame:frame];
500 NSString *Simplify(NSString *title) {
501 const char *data = [title UTF8String];
502 size_t size = [title length];
504 Pcre title_r("^(.*?)( \\(.*\\))?$");
505 if (title_r(data, size))
512 /* Delegate Prototypes {{{ */
516 @interface NSObject (ProgressDelegate)
519 @implementation NSObject(ProgressDelegate)
521 - (void) _setProgressError:(NSArray *)args {
522 [self performSelector:@selector(setProgressError:forPackage:)
523 withObject:[args objectAtIndex:0]
524 withObject:([args count] == 1 ? nil : [args objectAtIndex:1])
530 @protocol ProgressDelegate
531 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id;
532 - (void) setProgressTitle:(NSString *)title;
533 - (void) setProgressPercent:(float)percent;
534 - (void) addProgressOutput:(NSString *)output;
537 @protocol ConfigurationDelegate
538 - (void) repairWithSelector:(SEL)selector;
539 - (void) setConfigurationData:(NSString *)data;
542 @protocol CydiaDelegate
543 - (void) installPackage:(Package *)package;
544 - (void) removePackage:(Package *)package;
545 - (void) slideUp:(UIAlertSheet *)alert;
546 - (void) distUpgrade;
550 /* Status Delegation {{{ */
552 public pkgAcquireStatus
555 _transient NSObject<ProgressDelegate> *delegate_;
563 void setDelegate(id delegate) {
564 delegate_ = delegate;
567 virtual bool MediaChange(std::string media, std::string drive) {
571 virtual void IMSHit(pkgAcquire::ItemDesc &item) {
574 virtual void Fetch(pkgAcquire::ItemDesc &item) {
575 [delegate_ setProgressTitle:[NSString stringWithUTF8String:("Downloading " + item.ShortDesc).c_str()]];
578 virtual void Done(pkgAcquire::ItemDesc &item) {
581 virtual void Fail(pkgAcquire::ItemDesc &item) {
583 item.Owner->Status == pkgAcquire::Item::StatIdle ||
584 item.Owner->Status == pkgAcquire::Item::StatDone
588 [delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
589 withObject:[NSArray arrayWithObjects:[NSString stringWithUTF8String:item.Owner->ErrorText.c_str()], nil]
594 virtual bool Pulse(pkgAcquire *Owner) {
595 bool value = pkgAcquireStatus::Pulse(Owner);
598 double(CurrentBytes + CurrentItems) /
599 double(TotalBytes + TotalItems)
602 [delegate_ setProgressPercent:percent];
606 virtual void Start() {
609 virtual void Stop() {
613 /* Progress Delegation {{{ */
618 _transient id<ProgressDelegate> delegate_;
621 virtual void Update() {
622 [delegate_ setProgressTitle:[NSString stringWithUTF8String:Op.c_str()]];
623 [delegate_ setProgressPercent:(Percent / 100)];
632 void setDelegate(id delegate) {
633 delegate_ = delegate;
636 virtual void Done() {
637 [delegate_ setProgressPercent:1];
642 /* Database Interface {{{ */
643 @interface Database : NSObject {
645 pkgDepCache::Policy *policy_;
646 pkgRecords *records_;
647 pkgProblemResolver *resolver_;
648 pkgAcquire *fetcher_;
650 SPtr<pkgPackageManager> manager_;
651 pkgSourceList *list_;
653 NSMutableDictionary *sources_;
654 NSMutableArray *packages_;
656 _transient NSObject<ConfigurationDelegate, ProgressDelegate> *delegate_;
665 - (void) _readCydia:(NSNumber *)fd;
666 - (void) _readStatus:(NSNumber *)fd;
667 - (void) _readOutput:(NSNumber *)fd;
671 - (Package *) packageWithName:(NSString *)name;
674 - (pkgCacheFile &) cache;
675 - (pkgDepCache::Policy *) policy;
676 - (pkgRecords *) records;
677 - (pkgProblemResolver *) resolver;
678 - (pkgAcquire &) fetcher;
679 - (NSArray *) packages;
688 - (void) updateWithStatus:(Status &)status;
690 - (void) setDelegate:(id)delegate;
691 - (Source *) getSource:(const pkgCache::PkgFileIterator &)file;
695 /* Source Class {{{ */
696 @interface Source : NSObject {
697 NSString *description_;
702 NSString *distribution_;
706 NSString *defaultIcon_;
711 - (Source *) initWithMetaIndex:(metaIndex *)index;
716 - (NSString *) distribution;
719 - (NSString *) description;
720 - (NSString *) label;
721 - (NSString *) origin;
722 - (NSString *) version;
724 - (NSString *) defaultIcon;
727 @implementation Source
731 [distribution_ release];
734 if (description_ != nil)
735 [description_ release];
742 if (defaultIcon_ != nil)
743 [defaultIcon_ release];
748 - (Source *) initWithMetaIndex:(metaIndex *)index {
749 if ((self = [super init]) != nil) {
750 trusted_ = index->IsTrusted();
752 uri_ = [[NSString stringWithUTF8String:index->GetURI().c_str()] retain];
753 distribution_ = [[NSString stringWithUTF8String:index->GetDist().c_str()] retain];
754 type_ = [[NSString stringWithUTF8String:index->GetType()] retain];
762 debReleaseIndex *dindex(dynamic_cast<debReleaseIndex *>(index));
763 if (dindex != NULL) {
764 std::ifstream release(dindex->MetaIndexFile("Release").c_str());
766 while (std::getline(release, line)) {
767 std::string::size_type colon(line.find(':'));
768 if (colon == std::string::npos)
771 std::string name(line.substr(0, colon));
772 std::string value(line.substr(colon + 1));
773 while (!value.empty() && value[0] == ' ')
774 value = value.substr(1);
776 if (name == "Default-Icon")
777 defaultIcon_ = [[NSString stringWithUTF8String:value.c_str()] retain];
778 else if (name == "Description")
779 description_ = [[NSString stringWithUTF8String:value.c_str()] retain];
780 else if (name == "Label")
781 label_ = [[NSString stringWithUTF8String:value.c_str()] retain];
782 else if (name == "Origin")
783 origin_ = [[NSString stringWithUTF8String:value.c_str()] retain];
784 else if (name == "Version")
785 version_ = [[NSString stringWithUTF8String:value.c_str()] retain];
799 - (NSString *) distribution {
800 return distribution_;
803 - (NSString *) type {
807 - (NSString *) description {
811 - (NSString *) label {
815 - (NSString *) origin {
819 - (NSString *) version {
823 - (NSString *) defaultIcon {
829 /* Relationship Class {{{ */
830 @interface Relationship : NSObject {
841 @implementation Relationship
849 - (NSString *) type {
857 - (NSString *) name {
864 /* Package Class {{{ */
865 NSString *Scour(const char *field, const char *begin, const char *end) {
866 size_t i(0), l(strlen(field));
869 const char *name = begin + i;
870 const char *colon = name + l;
871 const char *value = colon + 1;
876 memcmp(name, field, l) == 0
878 while (value != end && value[0] == ' ')
880 const char *line = std::find(value, end, '\n');
881 while (line != value && line[-1] == ' ')
884 return [NSString stringWithUTF8Bytes:value length:(line - value)];
886 begin = std::find(begin, end, '\n');
894 @interface Package : NSObject {
895 pkgCache::PkgIterator iterator_;
896 _transient Database *database_;
897 pkgCache::VerIterator version_;
898 pkgCache::VerFileIterator file_;
904 NSString *installed_;
913 NSArray *relationships_;
916 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
917 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
919 - (pkgCache::PkgIterator) iterator;
921 - (NSString *) section;
922 - (Address *) maintainer;
924 - (NSString *) description;
925 - (NSString *) index;
929 - (NSString *) latest;
930 - (NSString *) installed;
933 - (BOOL) upgradableAndEssential:(BOOL)essential;
938 - (BOOL) halfConfigured;
939 - (BOOL) halfInstalled;
945 - (NSString *) tagline;
947 - (NSString *) website;
948 - (Address *) author;
950 - (NSArray *) relationships;
954 - (BOOL) matches:(NSString *)text;
956 - (NSComparisonResult) compareByName:(Package *)package;
957 - (NSComparisonResult) compareBySection:(Package *)package;
958 - (NSComparisonResult) compareBySectionAndName:(Package *)package;
959 - (NSComparisonResult) compareForChanges:(Package *)package;
964 - (NSNumber *) isSearchedForBy:(NSString *)search;
965 - (NSNumber *) isInstalledInSection:(NSString *)section;
966 - (NSNumber *) isUninstalledInSection:(NSString *)section;
970 @implementation Package
977 if (installed_ != nil)
978 [installed_ release];
991 if (relationships_ != nil)
992 [relationships_ release];
997 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
998 if ((self = [super init]) != nil) {
999 iterator_ = iterator;
1000 database_ = database;
1002 version_ = [database_ policy]->GetCandidateVer(iterator_);
1003 latest_ = version_.end() ? nil : [StripVersion([NSString stringWithUTF8String:version_.VerStr()]) retain];
1005 if (!version_.end())
1006 file_ = version_.FileList();
1008 pkgCache &cache([database_ cache]);
1009 file_ = pkgCache::VerFileIterator(cache, cache.VerFileP);
1012 pkgCache::VerIterator current = iterator_.CurrentVer();
1013 installed_ = current.end() ? nil : [StripVersion([NSString stringWithUTF8String:current.VerStr()]) retain];
1015 id_ = [[[NSString stringWithUTF8String:iterator_.Name()] lowercaseString] retain];
1018 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1020 const char *begin, *end;
1021 parser->GetRec(begin, end);
1023 name_ = Scour("Name", begin, end);
1025 name_ = [name_ retain];
1026 tagline_ = [[NSString stringWithUTF8String:parser->ShortDesc().c_str()] retain];
1027 icon_ = Scour("Icon", begin, end);
1029 icon_ = [icon_ retain];
1030 website_ = Scour("Homepage", begin, end);
1031 if (website_ == nil)
1032 website_ = Scour("Website", begin, end);
1033 if (website_ != nil)
1034 website_ = [website_ retain];
1035 NSString *author = Scour("Author", begin, end);
1037 author_ = [Address addressWithString:author];
1040 NSMutableDictionary *metadata = [Packages_ objectForKey:id_];
1041 if (metadata == nil || [metadata count] == 0) {
1042 metadata = [NSMutableDictionary dictionaryWithObjectsAndKeys:
1046 [Packages_ setObject:metadata forKey:id_];
1052 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
1053 return [[[Package alloc]
1054 initWithIterator:iterator
1059 - (pkgCache::PkgIterator) iterator {
1063 - (NSString *) section {
1064 const char *section = iterator_.Section();
1065 return section == NULL ? nil : [[NSString stringWithUTF8String:section] stringByReplacingCharacter:'_' withCharacter:' '];
1068 - (Address *) maintainer {
1071 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1072 return [Address addressWithString:[NSString stringWithUTF8String:parser->Maintainer().c_str()]];
1076 return version_.end() ? 0 : version_->InstalledSize;
1079 - (NSString *) description {
1082 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1083 NSString *description([NSString stringWithUTF8String:parser->LongDesc().c_str()]);
1085 NSArray *lines = [description componentsSeparatedByString:@"\n"];
1086 NSMutableArray *trimmed = [NSMutableArray arrayWithCapacity:([lines count] - 1)];
1087 if ([lines count] < 2)
1090 NSCharacterSet *whitespace = [NSCharacterSet whitespaceCharacterSet];
1091 for (size_t i(1); i != [lines count]; ++i) {
1092 NSString *trim = [[lines objectAtIndex:i] stringByTrimmingCharactersInSet:whitespace];
1093 [trimmed addObject:trim];
1096 return [trimmed componentsJoinedByString:@"\n"];
1099 - (NSString *) index {
1100 NSString *index = [[[self name] substringToIndex:1] uppercaseString];
1101 return [index length] != 0 && isalpha([index characterAtIndex:0]) ? index : @"123";
1105 return [[Packages_ objectForKey:id_] objectForKey:@"FirstSeen"];
1108 - (NSString *) latest {
1112 - (NSString *) installed {
1117 return !version_.end();
1120 - (BOOL) upgradableAndEssential:(BOOL)essential {
1121 pkgCache::VerIterator current = iterator_.CurrentVer();
1124 return essential && [self essential];
1126 pkgCache::VerIterator candidate = [database_ policy]->GetCandidateVer(iterator_);
1127 return !candidate.end() && candidate != current;
1131 - (BOOL) essential {
1132 return (iterator_->Flags & pkgCache::Flag::Essential) == 0 ? NO : YES;
1136 return [database_ cache][iterator_].InstBroken();
1140 unsigned char current = iterator_->CurrentState;
1141 return current == pkgCache::State::HalfConfigured || current == pkgCache::State::HalfInstalled;
1144 - (BOOL) halfConfigured {
1145 return iterator_->CurrentState == pkgCache::State::HalfConfigured;
1148 - (BOOL) halfInstalled {
1149 return iterator_->CurrentState == pkgCache::State::HalfInstalled;
1153 pkgDepCache::StateCache &state([database_ cache][iterator_]);
1154 return state.Mode != pkgDepCache::ModeKeep;
1157 - (NSString *) mode {
1158 pkgDepCache::StateCache &state([database_ cache][iterator_]);
1160 switch (state.Mode) {
1161 case pkgDepCache::ModeDelete:
1162 if ((state.iFlags & pkgDepCache::Purge) != 0)
1167 case pkgDepCache::ModeKeep:
1168 if ((state.iFlags & pkgDepCache::AutoKept) != 0)
1173 case pkgDepCache::ModeInstall:
1174 if ((state.iFlags & pkgDepCache::ReInstall) != 0)
1175 return @"Reinstall";
1176 else switch (state.Status) {
1178 return @"Downgrade";
1184 return @"New Install";
1197 - (NSString *) name {
1198 return name_ == nil ? id_ : name_;
1201 - (NSString *) tagline {
1205 - (NSString *) icon {
1209 - (NSString *) website {
1213 - (Address *) author {
1217 - (NSArray *) relationships {
1218 return relationships_;
1221 - (Source *) source {
1223 source_ = file_.end() ? nil : [[database_ getSource:file_.File()] retain];
1230 - (BOOL) matches:(NSString *)text {
1236 range = [[self id] rangeOfString:text options:NSCaseInsensitiveSearch];
1237 if (range.location != NSNotFound)
1240 range = [[self name] rangeOfString:text options:NSCaseInsensitiveSearch];
1241 if (range.location != NSNotFound)
1244 range = [[self tagline] rangeOfString:text options:NSCaseInsensitiveSearch];
1245 if (range.location != NSNotFound)
1251 - (NSComparisonResult) compareByName:(Package *)package {
1252 NSString *lhs = [self name];
1253 NSString *rhs = [package name];
1255 if ([lhs length] != 0 && [rhs length] != 0) {
1256 unichar lhc = [lhs characterAtIndex:0];
1257 unichar rhc = [rhs characterAtIndex:0];
1259 if (isalpha(lhc) && !isalpha(rhc))
1260 return NSOrderedAscending;
1261 else if (!isalpha(lhc) && isalpha(rhc))
1262 return NSOrderedDescending;
1265 return [lhs caseInsensitiveCompare:rhs];
1268 - (NSComparisonResult) compareBySection:(Package *)package {
1269 NSString *lhs = [self section];
1270 NSString *rhs = [package section];
1272 if (lhs == NULL && rhs != NULL)
1273 return NSOrderedAscending;
1274 else if (lhs != NULL && rhs == NULL)
1275 return NSOrderedDescending;
1276 else if (lhs != NULL && rhs != NULL) {
1277 NSComparisonResult result = [lhs caseInsensitiveCompare:rhs];
1278 if (result != NSOrderedSame)
1282 return NSOrderedSame;
1285 - (NSComparisonResult) compareBySectionAndName:(Package *)package {
1286 NSString *lhs = [self section];
1287 NSString *rhs = [package section];
1289 if (lhs == NULL && rhs != NULL)
1290 return NSOrderedAscending;
1291 else if (lhs != NULL && rhs == NULL)
1292 return NSOrderedDescending;
1293 else if (lhs != NULL && rhs != NULL) {
1294 NSComparisonResult result = [lhs compare:rhs];
1295 if (result != NSOrderedSame)
1299 return [self compareByName:package];
1302 - (NSComparisonResult) compareForChanges:(Package *)package {
1303 BOOL lhs = [self upgradableAndEssential:YES];
1304 BOOL rhs = [package upgradableAndEssential:YES];
1307 return lhs ? NSOrderedAscending : NSOrderedDescending;
1309 switch ([[self seen] compare:[package seen]]) {
1310 case NSOrderedAscending:
1311 return NSOrderedDescending;
1314 case NSOrderedDescending:
1315 return NSOrderedAscending;
1321 return [self compareByName:package];
1325 pkgProblemResolver *resolver = [database_ resolver];
1326 resolver->Clear(iterator_);
1327 resolver->Protect(iterator_);
1328 pkgCacheFile &cache([database_ cache]);
1329 cache->MarkInstall(iterator_, false);
1330 pkgDepCache::StateCache &state((*cache)[iterator_]);
1331 if (!state.Install())
1332 cache->SetReInstall(iterator_, true);
1336 pkgProblemResolver *resolver = [database_ resolver];
1337 resolver->Clear(iterator_);
1338 resolver->Protect(iterator_);
1339 resolver->Remove(iterator_);
1340 [database_ cache]->MarkDelete(iterator_, true);
1343 - (NSNumber *) isSearchedForBy:(NSString *)search {
1344 return [NSNumber numberWithBool:([self valid] && [self matches:search])];
1347 - (NSNumber *) isInstalledInSection:(NSString *)section {
1348 return [NSNumber numberWithBool:([self installed] != nil && (section == nil || [section isEqualToString:[self section]]))];
1351 - (NSNumber *) isUninstalledInSection:(NSString *)name {
1352 NSString *section = [self section];
1354 return [NSNumber numberWithBool:([self valid] && [self installed] == nil && (
1356 section == nil && [name length] == 0 ||
1357 [name isEqualToString:section])
1363 /* Section Class {{{ */
1364 @interface Section : NSObject {
1370 - (Section *) initWithName:(NSString *)name row:(size_t)row;
1371 - (NSString *) name;
1374 - (void) addToCount;
1378 @implementation Section
1385 - (Section *) initWithName:(NSString *)name row:(size_t)row {
1386 if ((self = [super init]) != nil) {
1387 name_ = [name retain];
1392 - (NSString *) name {
1404 - (void) addToCount {
1411 /* Database Implementation {{{ */
1412 @implementation Database
1419 - (void) _readCydia:(NSNumber *)fd {
1420 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1422 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1423 std::istream is(&ib);
1426 while (std::getline(is, line)) {
1427 const char *data(line.c_str());
1428 //size_t size = line.size();
1429 fprintf(stderr, "C:%s\n", data);
1436 - (void) _readStatus:(NSNumber *)fd {
1437 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1439 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1440 std::istream is(&ib);
1443 Pcre conffile_r("^status: [^ ]* : conffile-prompt : (.*?) *$");
1444 Pcre pmstatus_r("^([^:]*):([^:]*):([^:]*):(.*)$");
1446 while (std::getline(is, line)) {
1447 const char *data(line.c_str());
1448 size_t size = line.size();
1449 fprintf(stderr, "S:%s\n", data);
1451 if (conffile_r(data, size)) {
1452 [delegate_ setConfigurationData:conffile_r[1]];
1453 } else if (strncmp(data, "status: ", 8) == 0) {
1454 NSString *string = [NSString stringWithUTF8String:(data + 8)];
1455 [delegate_ setProgressTitle:string];
1456 } else if (pmstatus_r(data, size)) {
1457 std::string type([pmstatus_r[1] UTF8String]);
1458 NSString *id = pmstatus_r[2];
1460 float percent([pmstatus_r[3] floatValue]);
1461 [delegate_ setProgressPercent:(percent / 100)];
1463 NSString *string = pmstatus_r[4];
1465 if (type == "pmerror")
1466 [delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
1467 withObject:[NSArray arrayWithObjects:string, id, nil]
1470 else if (type == "pmstatus")
1471 [delegate_ setProgressTitle:string];
1472 else if (type == "pmconffile")
1473 [delegate_ setConfigurationData:string];
1474 else _assert(false);
1475 } else _assert(false);
1482 - (void) _readOutput:(NSNumber *)fd {
1483 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1485 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1486 std::istream is(&ib);
1489 while (std::getline(is, line)) {
1490 fprintf(stderr, "O:%s\n", line.c_str());
1491 [delegate_ addProgressOutput:[NSString stringWithUTF8String:line.c_str()]];
1502 - (Package *) packageWithName:(NSString *)name {
1503 if (static_cast<pkgDepCache *>(cache_) == NULL)
1505 pkgCache::PkgIterator iterator(cache_->FindPkg([name UTF8String]));
1506 return iterator.end() ? nil : [Package packageWithIterator:iterator database:self];
1509 - (Database *) init {
1510 if ((self = [super init]) != nil) {
1517 sources_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1518 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
1522 _assert(pipe(fds) != -1);
1525 _config->Set("APT::Keep-Fds::", cydiafd_);
1526 setenv("CYDIA", [[[[NSNumber numberWithInt:cydiafd_] stringValue] stringByAppendingString:@" 0"] UTF8String], _not(int));
1529 detachNewThreadSelector:@selector(_readCydia:)
1531 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1534 _assert(pipe(fds) != -1);
1538 detachNewThreadSelector:@selector(_readStatus:)
1540 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1543 _assert(pipe(fds) != -1);
1544 _assert(dup2(fds[0], 0) != -1);
1545 _assert(close(fds[0]) != -1);
1547 input_ = fdopen(fds[1], "a");
1549 _assert(pipe(fds) != -1);
1550 _assert(dup2(fds[1], 1) != -1);
1551 _assert(close(fds[1]) != -1);
1554 detachNewThreadSelector:@selector(_readOutput:)
1556 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1561 - (pkgCacheFile &) cache {
1565 - (pkgDepCache::Policy *) policy {
1569 - (pkgRecords *) records {
1573 - (pkgProblemResolver *) resolver {
1577 - (pkgAcquire &) fetcher {
1581 - (NSArray *) packages {
1585 - (void) reloadData {
1604 if (!cache_.Open(progress_, true)) {
1606 if (!_error->PopMessage(error))
1609 fprintf(stderr, "cache_.Open():[%s]\n", error.c_str());
1611 if (error == "dpkg was interrupted, you must manually run 'dpkg --configure -a' to correct the problem. ")
1612 [delegate_ repairWithSelector:@selector(configure)];
1613 else if (error == "The package lists or status file could not be parsed or opened.")
1614 [delegate_ repairWithSelector:@selector(update)];
1615 // else if (error == "Could not open lock file /var/lib/dpkg/lock - open (13 Permission denied)")
1616 // else if (error == "Could not get lock /var/lib/dpkg/lock - open (35 Resource temporarily unavailable)")
1617 // else if (error == "The list of sources could not be read.")
1618 else _assert(false);
1623 now_ = [[NSDate date] retain];
1625 policy_ = new pkgDepCache::Policy();
1626 records_ = new pkgRecords(cache_);
1627 resolver_ = new pkgProblemResolver(cache_);
1628 fetcher_ = new pkgAcquire(&status_);
1631 list_ = new pkgSourceList();
1632 _assert(list_->ReadMainList());
1634 _assert(cache_->DelCount() == 0 && cache_->InstCount() == 0);
1635 _assert(pkgApplyStatus(cache_));
1637 if (cache_->BrokenCount() != 0) {
1638 _assert(pkgFixBroken(cache_));
1639 _assert(cache_->BrokenCount() == 0);
1640 _assert(pkgMinimizeUpgrade(cache_));
1643 [sources_ removeAllObjects];
1644 for (pkgSourceList::const_iterator source = list_->begin(); source != list_->end(); ++source) {
1645 std::vector<pkgIndexFile *> *indices = (*source)->GetIndexFiles();
1646 for (std::vector<pkgIndexFile *>::const_iterator index = indices->begin(); index != indices->end(); ++index)
1648 setObject:[[[Source alloc] initWithMetaIndex:*source] autorelease]
1649 forKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(*index)]
1653 [packages_ removeAllObjects];
1654 for (pkgCache::PkgIterator iterator = cache_->PkgBegin(); !iterator.end(); ++iterator)
1655 if (Package *package = [Package packageWithIterator:iterator database:self])
1656 [packages_ addObject:package];
1658 [packages_ sortUsingSelector:@selector(compareByName:)];
1661 - (void) configure {
1662 NSString *dpkg = [NSString stringWithFormat:@"dpkg --configure -a --status-fd %u", statusfd_];
1663 system([dpkg UTF8String]);
1671 Lock.Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1672 _assert(!_error->PendingError());
1675 fetcher.Clean(_config->FindDir("Dir::Cache::Archives"));
1678 public pkgArchiveCleaner
1681 virtual void Erase(const char *File, std::string Pkg, std::string Ver, struct stat &St) {
1686 if (!cleaner.Go(_config->FindDir("Dir::Cache::Archives") + "partial/", cache_)) {
1688 while (_error->PopMessage(error))
1689 fprintf(stderr, "ArchiveCleaner: %s\n", error.c_str());
1694 pkgRecords records(cache_);
1696 lock_ = new FileFd();
1697 lock_->Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1698 _assert(!_error->PendingError());
1701 // XXX: explain this with an error message
1702 _assert(list.ReadMainList());
1704 manager_ = (_system->CreatePM(cache_));
1705 _assert(manager_->GetArchives(fetcher_, &list, &records));
1706 _assert(!_error->PendingError());
1710 NSMutableArray *before = [NSMutableArray arrayWithCapacity:16]; {
1712 _assert(list.ReadMainList());
1713 for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source)
1714 [before addObject:[NSString stringWithUTF8String:(*source)->GetURI().c_str()]];
1717 if (fetcher_->Run(PulseInterval_) != pkgAcquire::Continue)
1721 pkgPackageManager::OrderResult result = manager_->DoInstall(statusfd_);
1723 if (result == pkgPackageManager::Failed)
1725 if (_error->PendingError())
1727 if (result != pkgPackageManager::Completed)
1730 NSMutableArray *after = [NSMutableArray arrayWithCapacity:16]; {
1732 _assert(list.ReadMainList());
1733 for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source)
1734 [after addObject:[NSString stringWithUTF8String:(*source)->GetURI().c_str()]];
1737 if (![before isEqualToArray:after])
1742 _assert(pkgDistUpgrade(cache_));
1746 [self updateWithStatus:status_];
1749 - (void) updateWithStatus:(Status &)status {
1751 _assert(list.ReadMainList());
1754 lock.Fd(GetLock(_config->FindDir("Dir::State::Lists") + "lock"));
1755 _assert(!_error->PendingError());
1757 pkgAcquire fetcher(&status);
1758 _assert(list.GetIndexes(&fetcher));
1760 if (fetcher.Run(PulseInterval_) != pkgAcquire::Failed) {
1761 bool failed = false;
1762 for (pkgAcquire::ItemIterator item = fetcher.ItemsBegin(); item != fetcher.ItemsEnd(); item++)
1763 if ((*item)->Status != pkgAcquire::Item::StatDone) {
1764 (*item)->Finished();
1768 if (!failed && _config->FindB("APT::Get::List-Cleanup", true) == true) {
1769 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists")));
1770 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/"));
1773 [Metadata_ setObject:[NSDate date] forKey:@"LastUpdate"];
1778 - (void) setDelegate:(id)delegate {
1779 delegate_ = delegate;
1780 status_.setDelegate(delegate);
1781 progress_.setDelegate(delegate);
1784 - (Source *) getSource:(const pkgCache::PkgFileIterator &)file {
1785 pkgIndexFile *index(NULL);
1786 list_->FindIndex(file, index);
1787 return [sources_ objectForKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(index)]];
1793 /* Confirmation View {{{ */
1794 void AddTextView(NSMutableDictionary *fields, NSMutableArray *packages, NSString *key) {
1795 if ([packages count] == 0)
1798 UITextView *text = GetTextView([packages count] == 0 ? @"n/a" : [packages componentsJoinedByString:@", "], 120, false);
1799 [fields setObject:text forKey:key];
1801 CGColor blue(space_, 0, 0, 0.4, 1);
1802 [text setTextColor:blue];
1805 @protocol ConfirmationViewDelegate
1810 @interface ConfirmationView : UIView {
1811 Database *database_;
1813 UITransitionView *transition_;
1815 UINavigationBar *navbar_;
1816 UIPreferencesTable *table_;
1817 NSMutableDictionary *fields_;
1818 UIAlertSheet *essential_;
1823 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate;
1827 @implementation ConfirmationView
1830 [navbar_ setDelegate:nil];
1831 [transition_ setDelegate:nil];
1832 [table_ setDataSource:nil];
1834 [transition_ release];
1839 if (essential_ != nil)
1840 [essential_ release];
1845 [transition_ transition:7 toView:nil];
1849 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
1850 if (from != nil && to == nil)
1851 [self removeFromSuperview];
1854 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
1857 if (essential_ != nil)
1858 [essential_ popupAlertAnimated:YES];
1860 [delegate_ confirm];
1869 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
1870 NSString *context = [sheet context];
1872 if ([context isEqualToString:@"remove"])
1878 [delegate_ confirm];
1883 else if ([context isEqualToString:@"unable"])
1889 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
1893 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
1895 case 0: return @"Statistics";
1896 case 1: return @"Modifications";
1898 default: _assert(false);
1902 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
1905 case 1: return [fields_ count];
1907 default: _assert(false);
1911 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
1912 if (group != 1 || row == -1)
1915 _assert(size_t(row) < [fields_ count]);
1916 return [[[fields_ allValues] objectAtIndex:row] visibleTextRect].size.height + TextViewOffset_;
1920 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
1921 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
1922 [cell setShowSelection:NO];
1925 case 0: switch (row) {
1927 [cell setTitle:@"Downloading"];
1928 [cell setValue:SizeString([database_ fetcher].FetchNeeded())];
1932 [cell setTitle:@"Resuming At"];
1933 [cell setValue:SizeString([database_ fetcher].PartialPresent())];
1937 double size([database_ cache]->UsrSize());
1940 [cell setTitle:@"Disk Freeing"];
1941 [cell setValue:SizeString(-size)];
1943 [cell setTitle:@"Disk Using"];
1944 [cell setValue:SizeString(size)];
1948 default: _assert(false);
1952 _assert(size_t(row) < [fields_ count]);
1953 [cell setTitle:[[fields_ allKeys] objectAtIndex:row]];
1954 [cell addSubview:[[fields_ allValues] objectAtIndex:row]];
1957 default: _assert(false);
1963 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate {
1964 if ((self = [super initWithFrame:[view bounds]]) != nil) {
1965 database_ = database;
1966 delegate_ = delegate;
1968 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
1969 [self addSubview:transition_];
1971 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
1973 CGSize navsize = [UINavigationBar defaultSize];
1974 CGRect navrect = {{0, 0}, navsize};
1975 CGRect bounds = [overlay_ bounds];
1977 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
1979 [navbar_ setBarStyle:1];
1980 [navbar_ setDelegate:self];
1982 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Confirm"] autorelease];
1983 [navbar_ pushNavigationItem:navitem];
1984 [navbar_ showButtonsWithLeftTitle:@"Cancel" rightTitle:@"Confirm"];
1986 fields_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1988 NSMutableArray *installing = [NSMutableArray arrayWithCapacity:16];
1989 NSMutableArray *reinstalling = [NSMutableArray arrayWithCapacity:16];
1990 NSMutableArray *upgrading = [NSMutableArray arrayWithCapacity:16];
1991 NSMutableArray *downgrading = [NSMutableArray arrayWithCapacity:16];
1992 NSMutableArray *removing = [NSMutableArray arrayWithCapacity:16];
1996 pkgCacheFile &cache([database_ cache]);
1997 NSArray *packages = [database_ packages];
1998 for (size_t i(0), e = [packages count]; i != e; ++i) {
1999 Package *package = [packages objectAtIndex:i];
2000 pkgCache::PkgIterator iterator = [package iterator];
2001 pkgDepCache::StateCache &state(cache[iterator]);
2003 NSString *name([package name]);
2005 if (state.NewInstall())
2006 [installing addObject:name];
2007 else if (!state.Delete() && (state.iFlags & pkgDepCache::ReInstall) == pkgDepCache::ReInstall)
2008 [reinstalling addObject:name];
2009 else if (state.Upgrade())
2010 [upgrading addObject:name];
2011 else if (state.Downgrade())
2012 [downgrading addObject:name];
2013 else if (state.Delete()) {
2014 if ([package essential])
2016 [removing addObject:name];
2022 else if (Advanced_ || true) {
2023 essential_ = [[UIAlertSheet alloc]
2024 initWithTitle:@"Removing Essentials"
2025 buttons:[NSArray arrayWithObjects:
2026 @"Cancel Operation (Safe)",
2027 @"Force Removal (Unsafe)",
2029 defaultButtonIndex:0
2035 [essential_ setDestructiveButton:[[essential_ buttons] objectAtIndex:0]];
2037 [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."];
2039 essential_ = [[UIAlertSheet alloc]
2040 initWithTitle:@"Unable to Comply"
2041 buttons:[NSArray arrayWithObjects:@"Okay", nil]
2042 defaultButtonIndex:0
2047 [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."];
2050 AddTextView(fields_, installing, @"Installing");
2051 AddTextView(fields_, reinstalling, @"Reinstalling");
2052 AddTextView(fields_, upgrading, @"Upgrading");
2053 AddTextView(fields_, downgrading, @"Downgrading");
2054 AddTextView(fields_, removing, @"Removing");
2056 table_ = [[UIPreferencesTable alloc] initWithFrame:CGRectMake(
2057 0, navsize.height, bounds.size.width, bounds.size.height - navsize.height
2060 [table_ setReusesTableCells:YES];
2061 [table_ setDataSource:self];
2062 [table_ reloadData];
2064 [overlay_ addSubview:navbar_];
2065 [overlay_ addSubview:table_];
2067 [view addSubview:self];
2069 [transition_ setDelegate:self];
2071 UIView *blank = [[[UIView alloc] initWithFrame:[transition_ bounds]] autorelease];
2072 [transition_ transition:0 toView:blank];
2073 [transition_ transition:3 toView:overlay_];
2080 /* Progress Data {{{ */
2081 @interface ProgressData : NSObject {
2087 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object;
2094 @implementation ProgressData
2096 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object {
2097 if ((self = [super init]) != nil) {
2098 selector_ = selector;
2118 /* Progress View {{{ */
2119 Pcre conffile_r("^'(.*)' '(.*)' ([01]) ([01])$");
2121 @interface ProgressView : UIView <
2122 ConfigurationDelegate,
2125 _transient Database *database_;
2127 UIView *background_;
2128 UITransitionView *transition_;
2130 UINavigationBar *navbar_;
2131 UIProgressBar *progress_;
2132 UITextView *output_;
2133 UITextLabel *status_;
2134 UIPushButton *close_;
2138 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
2140 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database delegate:(id)delegate;
2141 - (void) setContentView:(UIView *)view;
2144 - (void) _retachThread;
2145 - (void) _detachNewThreadData:(ProgressData *)data;
2146 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title;
2150 @protocol ProgressViewDelegate
2151 - (void) progressViewIsComplete:(ProgressView *)sender;
2154 @implementation ProgressView
2157 [transition_ setDelegate:nil];
2158 [navbar_ setDelegate:nil];
2161 if (background_ != nil)
2162 [background_ release];
2163 [transition_ release];
2166 [progress_ release];
2173 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
2174 if (bootstrap_ && from == overlay_ && to == view_)
2178 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database delegate:(id)delegate {
2179 if ((self = [super initWithFrame:frame]) != nil) {
2180 database_ = database;
2181 delegate_ = delegate;
2183 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
2184 [transition_ setDelegate:self];
2186 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
2189 [overlay_ setBackgroundColor:Black_];
2191 background_ = [[UIView alloc] initWithFrame:[self bounds]];
2192 [background_ setBackgroundColor:Black_];
2193 [self addSubview:background_];
2196 [self addSubview:transition_];
2198 CGSize navsize = [UINavigationBar defaultSize];
2199 CGRect navrect = {{0, 0}, navsize};
2201 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
2202 [overlay_ addSubview:navbar_];
2204 [navbar_ setBarStyle:1];
2205 [navbar_ setDelegate:self];
2207 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:nil] autorelease];
2208 [navbar_ pushNavigationItem:navitem];
2210 CGRect bounds = [overlay_ bounds];
2211 CGSize prgsize = [UIProgressBar defaultSize];
2214 (bounds.size.width - prgsize.width) / 2,
2215 bounds.size.height - prgsize.height - 20
2218 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
2219 [progress_ setStyle:0];
2221 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(
2223 bounds.size.height - prgsize.height - 50,
2224 bounds.size.width - 20,
2228 [status_ setColor:White_];
2229 [status_ setBackgroundColor:Clear_];
2231 [status_ setCentersHorizontally:YES];
2232 //[status_ setFont:font];
2234 output_ = [[UITextView alloc] initWithFrame:CGRectMake(
2236 navrect.size.height + 20,
2237 bounds.size.width - 20,
2238 bounds.size.height - navsize.height - 62 - navrect.size.height
2241 //[output_ setTextFont:@"Courier New"];
2242 [output_ setTextSize:12];
2244 [output_ setTextColor:White_];
2245 [output_ setBackgroundColor:Clear_];
2247 [output_ setMarginTop:0];
2248 [output_ setAllowsRubberBanding:YES];
2250 [overlay_ addSubview:output_];
2252 close_ = [[UIPushButton alloc] initWithFrame:CGRectMake(
2254 bounds.size.height - prgsize.height - 50,
2255 bounds.size.width - 20,
2259 [close_ setAutosizesToFit:NO];
2260 [close_ setDrawsShadow:YES];
2261 [close_ setStretchBackground:YES];
2262 [close_ setTitle:@"Close Window"];
2263 [close_ setEnabled:YES];
2265 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22);
2266 [close_ setTitleFont:bold];
2269 [close_ addTarget:self action:@selector(closeButtonPushed) forEvents:kUIControlEventMouseUpInside];
2270 [close_ setBackground:[UIImage applicationImageNamed:@"green-up.png"] forState:0];
2271 [close_ setBackground:[UIImage applicationImageNamed:@"green-dn.png"] forState:1];
2275 - (void) setContentView:(UIView *)view {
2276 view_ = [view retain];
2279 - (void) resetView {
2280 [transition_ transition:6 toView:view_];
2283 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
2284 NSString *context = [sheet context];
2285 if ([context isEqualToString:@"conffile"]) {
2286 FILE *input = [database_ input];
2290 fprintf(input, "N\n");
2294 fprintf(input, "Y\n");
2305 - (void) closeButtonPushed {
2306 [delegate_ progressViewIsComplete:self];
2310 - (void) _retachThread {
2311 [overlay_ addSubview:close_];
2312 [progress_ removeFromSuperview];
2313 [status_ removeFromSuperview];
2316 - (void) _detachNewThreadData:(ProgressData *)data {
2317 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
2319 [[data target] performSelector:[data selector] withObject:[data object]];
2322 [self performSelectorOnMainThread:@selector(_retachThread) withObject:nil waitUntilDone:YES];
2327 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title {
2328 UINavigationItem *item = [navbar_ topItem];
2329 [item setTitle:title];
2331 [status_ setText:nil];
2332 [output_ setText:@""];
2333 [progress_ setProgress:0];
2335 [close_ removeFromSuperview];
2336 [overlay_ addSubview:progress_];
2337 [overlay_ addSubview:status_];
2339 [transition_ transition:6 toView:overlay_];
2342 detachNewThreadSelector:@selector(_detachNewThreadData:)
2344 withObject:[[ProgressData alloc]
2345 initWithSelector:selector
2352 - (void) repairWithSelector:(SEL)selector {
2354 detachNewThreadSelector:selector
2357 title:@"Repairing..."
2361 - (void) setConfigurationData:(NSString *)data {
2363 performSelectorOnMainThread:@selector(_setConfigurationData:)
2369 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id {
2370 Package *package = id == nil ? nil : [database_ packageWithName:id];
2372 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
2373 initWithTitle:(package == nil ? @"Source Error" : [package name])
2374 buttons:[NSArray arrayWithObjects:@"Okay", nil]
2375 defaultButtonIndex:0
2380 [sheet setBodyText:error];
2381 [sheet popupAlertAnimated:YES];
2384 - (void) setProgressTitle:(NSString *)title {
2386 performSelectorOnMainThread:@selector(_setProgressTitle:)
2392 - (void) setProgressPercent:(float)percent {
2394 performSelectorOnMainThread:@selector(_setProgressPercent:)
2395 withObject:[NSNumber numberWithFloat:percent]
2400 - (void) addProgressOutput:(NSString *)output {
2402 performSelectorOnMainThread:@selector(_addProgressOutput:)
2408 - (void) _setConfigurationData:(NSString *)data {
2409 _assert(conffile_r(data));
2411 NSString *ofile = conffile_r[1];
2412 //NSString *nfile = conffile_r[2];
2414 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
2415 initWithTitle:@"Configuration Upgrade"
2416 buttons:[NSArray arrayWithObjects:
2417 @"Keep My Old Copy",
2418 @"Accept The New Copy",
2419 // XXX: @"See What Changed",
2421 defaultButtonIndex:0
2426 [sheet setBodyText:[NSString stringWithFormat:
2427 @"The following file has been changed by both the package maintainer and by you (or for you by a script).\n\n%@"
2430 [sheet popupAlertAnimated:YES];
2433 - (void) _setProgressTitle:(NSString *)title {
2434 [status_ setText:[title stringByAppendingString:@"..."]];
2437 - (void) _setProgressPercent:(NSNumber *)percent {
2438 [progress_ setProgress:[percent floatValue]];
2441 - (void) _addProgressOutput:(NSString *)output {
2442 [output_ setText:[NSString stringWithFormat:@"%@\n%@", [output_ text], output]];
2443 CGSize size = [output_ contentSize];
2444 CGRect rect = {{0, size.height}, {size.width, 0}};
2445 [output_ scrollRectToVisible:rect animated:YES];
2451 /* Package Cell {{{ */
2452 @interface PackageCell : UITableCell {
2455 UITextLabel *description_;
2456 UITextLabel *source_;
2457 //UIImageView *trusted_;
2459 UIImageView *badge_;
2460 UITextLabel *status_;
2465 - (PackageCell *) init;
2466 - (void) setPackage:(Package *)package;
2468 - (void) _setSelected:(float)fraction;
2469 - (void) setSelected:(BOOL)selected;
2470 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
2471 - (void) _setSelectionFadeFraction:(float)fraction;
2473 + (int) heightForPackage:(Package *)package;
2477 @implementation PackageCell
2482 [description_ release];
2488 //[trusted_ release];
2492 - (PackageCell *) init {
2493 if ((self = [super init]) != nil) {
2494 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 20);
2495 GSFontRef large = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 12);
2496 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 14);
2498 icon_ = [[UIImageView alloc] initWithFrame:CGRectMake(10, 10, 30, 30)];
2500 name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 8, 240, 25)];
2501 [name_ setBackgroundColor:Clear_];
2502 [name_ setFont:bold];
2504 source_ = [[UITextLabel alloc] initWithFrame:CGRectMake(58, 28, 225, 20)];
2505 [source_ setBackgroundColor:Clear_];
2506 [source_ setFont:large];
2508 description_ = [[UITextLabel alloc] initWithFrame:CGRectMake(12, 46, 280, 20)];
2509 [description_ setBackgroundColor:Clear_];
2510 [description_ setFont:small];
2512 /*trusted_ = [[UIImageView alloc] initWithFrame:CGRectMake(30, 30, 16, 16)];
2513 [trusted_ setImage:[UIImage applicationImageNamed:@"trusted.png"]];*/
2516 badge_ = [[UIImageView alloc] initWithFrame:CGRectMake(17, 70, 16, 16)];
2518 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 68, 280, 20)];
2519 [status_ setBackgroundColor:Clear_];
2520 [status_ setFont:small];
2523 /*[icon_ setImage:[UIImage applicationImageNamed:@"unknown.png"]];
2524 [icon_ zoomToScale:0.5];
2525 [icon_ setFrame:CGRectMake(10, 10, 30, 30)];*/
2527 [self addSubview:icon_];
2528 [self addSubview:name_];
2529 [self addSubview:description_];
2530 [self addSubview:source_];
2538 - (void) setPackage:(Package *)package {
2544 Source *source = [package source];
2546 UIImage *image = nil;
2547 if (NSString *icon = [package icon])
2548 image = [UIImage imageAtPath:[icon substringFromIndex:6]];
2549 if (image == nil) if (NSString *icon = [source defaultIcon])
2550 image = [UIImage imageAtPath:[icon substringFromIndex:6]];
2552 image = [UIImage applicationImageNamed:@"unknown.png"];
2553 [icon_ setImage:image];
2555 /*if (image != nil) {
2556 CGSize size = [image size];
2557 float scale = 30 / std::max(size.width, size.height);
2558 [icon_ zoomToScale:scale];
2561 [icon_ setFrame:CGRectMake(10, 10, 30, 30)];
2563 [name_ setText:[package name]];
2564 [description_ setText:[package tagline]];
2566 NSString *label = nil;
2567 bool trusted = false;
2569 if (source != nil) {
2570 label = [source label];
2571 trusted = [source trusted];
2572 } else if ([[package id] isEqualToString:@"firmware"])
2576 label = @"Unknown/Local";
2578 NSString *from = [NSString stringWithFormat:@"from %@", label];
2580 NSString *section = Simplify([package section]);
2581 if (section != nil && ![section isEqualToString:label])
2582 from = [from stringByAppendingString:[NSString stringWithFormat:@" (%@)", section]];
2584 [source_ setText:from];
2587 [badge_ removeFromSuperview];
2588 [status_ removeFromSuperview];
2590 if (NSString *mode = [package mode]) {
2591 [badge_ setImage:[UIImage applicationImageNamed:
2592 [mode isEqualToString:@"Remove"] || [mode isEqualToString:@"Purge"] ? @"removing.png" : @"installing.png"
2595 [status_ setText:[NSString stringWithFormat:@"Queued for %@", mode]];
2596 [status_ setColor:Blueish_];
2597 } else if ([package half]) {
2598 [badge_ setImage:[UIImage applicationImageNamed:@"damaged.png"]];
2599 [status_ setText:@"Package Damaged"];
2600 [status_ setColor:Red_];
2602 [badge_ setImage:nil];
2603 [status_ setText:nil];
2607 [self addSubview:badge_];
2608 [self addSubview:status_];
2613 - (void) _setSelected:(float)fraction {
2614 CGColor black(space_,
2615 Interpolate(0.0, 1.0, fraction),
2616 Interpolate(0.0, 1.0, fraction),
2617 Interpolate(0.0, 1.0, fraction),
2620 CGColor gray(space_,
2621 Interpolate(0.4, 1.0, fraction),
2622 Interpolate(0.4, 1.0, fraction),
2623 Interpolate(0.4, 1.0, fraction),
2626 [name_ setColor:black];
2627 [description_ setColor:gray];
2628 [source_ setColor:black];
2631 - (void) setSelected:(BOOL)selected {
2632 [self _setSelected:(selected ? 1.0 : 0.0)];
2633 [super setSelected:selected];
2636 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
2638 [self _setSelected:(selected ? 1.0 : 0.0)];
2639 [super setSelected:selected withFade:fade];
2642 - (void) _setSelectionFadeFraction:(float)fraction {
2643 [self _setSelected:fraction];
2644 [super _setSelectionFadeFraction:fraction];
2647 + (int) heightForPackage:(Package *)package {
2649 if ([package hasMode] || [package half])
2658 /* Section Cell {{{ */
2659 @interface SectionCell : UITableCell {
2661 UITextLabel *count_;
2665 - (void) setSection:(Section *)section;
2667 - (void) _setSelected:(float)fraction;
2668 - (void) setSelected:(BOOL)selected;
2669 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
2670 - (void) _setSelectionFadeFraction:(float)fraction;
2674 @implementation SectionCell
2683 if ((self = [super init]) != nil) {
2684 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22);
2685 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 12);
2687 name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 9, 250, 25)];
2688 [name_ setBackgroundColor:Clear_];
2689 [name_ setFont:bold];
2691 count_ = [[UITextLabel alloc] initWithFrame:CGRectMake(11, 7, 29, 32)];
2692 [count_ setCentersHorizontally:YES];
2693 [count_ setBackgroundColor:Clear_];
2694 [count_ setFont:small];
2695 [count_ setColor:White_];
2697 UIImageView *folder = [[[UIImageView alloc] initWithFrame:CGRectMake(8, 7, 32, 32)] autorelease];
2698 [folder setImage:[UIImage applicationImageNamed:@"folder.png"]];
2700 [self addSubview:folder];
2701 [self addSubview:name_];
2702 [self addSubview:count_];
2704 [self _setSelected:0];
2711 - (void) setSection:(Section *)section {
2712 if (section == nil) {
2713 [name_ setText:@"All Packages"];
2714 [count_ setText:nil];
2716 NSString *name = [section name];
2717 [name_ setText:(name == nil ? @"(No Section)" : name)];
2718 [count_ setText:[NSString stringWithFormat:@"%d", [section count]]];
2722 - (void) _setSelected:(float)fraction {
2723 CGColor black(space_,
2724 Interpolate(0.0, 1.0, fraction),
2725 Interpolate(0.0, 1.0, fraction),
2726 Interpolate(0.0, 1.0, fraction),
2729 [name_ setColor:black];
2732 - (void) setSelected:(BOOL)selected {
2733 [self _setSelected:(selected ? 1.0 : 0.0)];
2734 [super setSelected:selected];
2737 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
2739 [self _setSelected:(selected ? 1.0 : 0.0)];
2740 [super setSelected:selected withFade:fade];
2743 - (void) _setSelectionFadeFraction:(float)fraction {
2744 [self _setSelected:fraction];
2745 [super _setSelectionFadeFraction:fraction];
2751 /* File Table {{{ */
2752 @interface FileTable : RVPage {
2753 _transient Database *database_;
2756 NSMutableArray *files_;
2760 - (id) initWithBook:(RVBook *)book database:(Database *)database;
2761 - (void) setPackage:(Package *)package;
2765 @implementation FileTable
2768 if (package_ != nil)
2777 - (int) numberOfRowsInTable:(UITable *)table {
2778 return files_ == nil ? 0 : [files_ count];
2781 - (float) table:(UITable *)table heightForRow:(int)row {
2785 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2786 if (reusing == nil) {
2787 reusing = [[[UIImageAndTextTableCell alloc] init] autorelease];
2788 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
2789 [[(UIImageAndTextTableCell *)reusing titleTextLabel] setFont:font];
2792 [(UIImageAndTextTableCell *)reusing setTitle:[files_ objectAtIndex:row]];
2796 - (BOOL) canSelectRow:(int)row {
2800 - (id) initWithBook:(RVBook *)book database:(Database *)database {
2801 if ((self = [super initWithBook:book]) != nil) {
2802 database_ = database;
2804 files_ = [[NSMutableArray arrayWithCapacity:32] retain];
2806 list_ = [[UITable alloc] initWithFrame:[self bounds]];
2807 [self addSubview:list_];
2809 UITableColumn *column = [[[UITableColumn alloc]
2810 initWithTitle:@"Name"
2812 width:[self frame].size.width
2815 [list_ setDataSource:self];
2816 [list_ setSeparatorStyle:1];
2817 [list_ addTableColumn:column];
2818 [list_ setDelegate:self];
2819 [list_ setReusesTableCells:YES];
2823 - (void) setPackage:(Package *)package {
2824 if (package_ != nil) {
2825 [package_ autorelease];
2834 [files_ removeAllObjects];
2836 if (package != nil) {
2837 package_ = [package retain];
2838 name_ = [[package id] retain];
2840 NSString *path = [NSString stringWithFormat:@"/var/lib/dpkg/info/%@.list", name_];
2843 std::ifstream fin([path UTF8String]);
2845 while (std::getline(fin, line))
2846 [files_ addObject:[NSString stringWithUTF8String:line.c_str()]];
2849 if ([files_ count] != 0) {
2850 if ([[files_ objectAtIndex:0] isEqualToString:@"/."])
2851 [files_ removeObjectAtIndex:0];
2852 [files_ sortUsingSelector:@selector(compareByPath:)];
2854 NSMutableArray *stack = [NSMutableArray arrayWithCapacity:8];
2855 [stack addObject:@"/"];
2857 for (int i(0), e([files_ count]); i != e; ++i) {
2858 NSString *file = [files_ objectAtIndex:i];
2859 while (![file hasPrefix:[stack lastObject]])
2860 [stack removeLastObject];
2861 NSString *directory = [stack lastObject];
2862 [stack addObject:[file stringByAppendingString:@"/"]];
2863 [files_ replaceObjectAtIndex:i withObject:[NSString stringWithFormat:@"%*s%@",
2864 ([stack count] - 2) * 3, "",
2865 [file substringFromIndex:[directory length]]
2874 - (void) resetViewAnimated:(BOOL)animated {
2875 [list_ resetViewAnimated:animated];
2878 - (void) reloadData {
2879 [self setPackage:[database_ packageWithName:name_]];
2880 [self reloadButtons];
2883 - (NSString *) title {
2884 return @"Installed Files";
2887 - (NSString *) backButtonTitle {
2893 /* Package View {{{ */
2894 @protocol PackageViewDelegate
2895 - (void) performPackage:(Package *)package;
2898 @interface PackageView : RVPage {
2899 _transient Database *database_;
2900 UIPreferencesTable *table_;
2903 UITextView *description_;
2904 NSMutableArray *buttons_;
2907 - (id) initWithBook:(RVBook *)book database:(Database *)database;
2908 - (void) setPackage:(Package *)package;
2912 @implementation PackageView
2915 [table_ setDataSource:nil];
2916 [table_ setDelegate:nil];
2918 if (package_ != nil)
2922 if (description_ != nil)
2923 [description_ release];
2929 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
2931 if ([package_ installed] != nil)
2933 if ([package_ source] != nil)
2938 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
2941 else if ([package_ installed] != nil && group-- == 0)
2942 return @"Installed Package";
2943 else if (group-- == 0)
2944 return @"Package Details";
2945 else if ([package_ source] != nil && group-- == 0)
2946 return @"Source Information";
2947 else _assert(false);
2950 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
2951 if (description_ == nil || group != 0 || row != 1)
2954 return [description_ visibleTextRect].size.height + TextViewOffset_;
2957 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
2960 if ([package_ author] != nil)
2962 if (description_ != nil)
2964 if ([package_ website] != nil)
2967 } else if ([package_ installed] != nil && group-- == 0)
2969 else if (group-- == 0) {
2971 if ([package_ size] != 0)
2973 if ([package_ maintainer] != nil)
2975 if ([package_ relationships] != nil)
2977 if ([[package_ source] trusted])
2980 } else if ([package_ source] != nil && group-- == 0) {
2981 Source *source = [package_ source];
2982 NSString *description = [source description];
2984 if (description != nil && ![description isEqualToString:[source label]])
2986 if ([source origin] != nil)
2989 } else _assert(false);
2992 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
2993 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
2994 [cell setShowSelection:NO];
2998 } else if (row-- == 0) {
2999 [cell setTitle:[package_ name]];
3000 [cell setValue:[package_ latest]];
3001 } else if ([package_ author] != nil && row-- == 0) {
3002 [cell setTitle:@"Author"];
3003 [cell setValue:[[package_ author] name]];
3004 [cell setShowDisclosure:YES];
3005 [cell setShowSelection:YES];
3006 } else if (description_ != nil && row-- == 0) {
3007 [cell addSubview:description_];
3008 } else if ([package_ website] != nil && row-- == 0) {
3009 [cell setTitle:@"More Information"];
3010 [cell setShowDisclosure:YES];
3011 [cell setShowSelection:YES];
3012 } else _assert(false);
3013 } else if ([package_ installed] != nil && group-- == 0) {
3015 } else if (row-- == 0) {
3016 [cell setTitle:@"Version"];
3017 NSString *installed([package_ installed]);
3018 [cell setValue:(installed == nil ? @"n/a" : installed)];
3019 } else if (row-- == 0) {
3020 [cell setTitle:@"Filesystem Content"];
3021 [cell setShowDisclosure:YES];
3022 [cell setShowSelection:YES];
3023 } else _assert(false);
3024 } else if (group-- == 0) {
3026 } else if (row-- == 0) {
3027 [cell setTitle:@"Identifier"];
3028 [cell setValue:[package_ id]];
3029 } else if (row-- == 0) {
3030 [cell setTitle:@"Section"];
3031 NSString *section([package_ section]);
3032 [cell setValue:(section == nil ? @"n/a" : section)];
3033 } else if ([package_ size] != 0 && row-- == 0) {
3034 [cell setTitle:@"Expanded Size"];
3035 [cell setValue:SizeString([package_ size])];
3036 } else if ([package_ maintainer] != nil && row-- == 0) {
3037 [cell setTitle:@"Maintainer"];
3038 [cell setValue:[[package_ maintainer] name]];
3039 [cell setShowDisclosure:YES];
3040 [cell setShowSelection:YES];
3041 } else if ([package_ relationships] != nil && row-- == 0) {
3042 [cell setTitle:@"Package Relationships"];
3043 [cell setShowDisclosure:YES];
3044 [cell setShowSelection:YES];
3045 } else if ([[package_ source] trusted] && row-- == 0) {
3046 [cell setIcon:[UIImage applicationImageNamed:@"trusted.png"]];
3047 [cell setValue:@"This package has been signed."];
3048 } else _assert(false);
3049 } else if ([package_ source] != nil && group-- == 0) {
3050 Source *source = [package_ source];
3051 NSString *description = [source description];
3054 } else if (row-- == 0) {
3055 NSString *label = [source label];
3057 label = [source uri];
3058 [cell setTitle:label];
3059 [cell setValue:[source version]];
3060 } else if (description != nil && ![description isEqualToString:[source label]] && row-- == 0) {
3061 [cell setValue:description];
3062 } else if ([source origin] != nil && row-- == 0) {
3063 [cell setTitle:@"Origin"];
3064 [cell setValue:[source origin]];
3065 } else _assert(false);
3066 } else _assert(false);
3071 - (BOOL) canSelectRow:(int)row {
3075 - (void) tableRowSelected:(NSNotification *)notification {
3076 int row = [table_ selectedRow];
3080 #define _else else goto _label; return; } _label:
3084 } else if (row-- == 0) {
3085 } else if ([package_ author] != nil && row-- == 0) {
3086 [delegate_ openURL:[NSURL URLWithString:[NSString stringWithFormat:@"mailto:%@?subject=%@",
3087 [[package_ author] email],
3088 [[NSString stringWithFormat:@"regarding apt package \"%@\"",
3090 ] stringByAddingPercentEscapes]
3092 } else if (description_ != nil && row-- == 0) {
3093 } else if ([package_ website] != nil && row-- == 0) {
3094 NSURL *url = [NSURL URLWithString:[package_ website]];
3095 BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease];
3096 [browser setDelegate:delegate_];
3097 [book_ pushPage:browser];
3098 [browser loadURL:url];
3099 } _else if ([package_ installed] != nil) {
3101 } else if (row-- == 0) {
3102 } else if (row-- == 0) {
3103 FileTable *files = [[[FileTable alloc] initWithBook:book_ database:database_] autorelease];
3104 [files setDelegate:delegate_];
3105 [files setPackage:package_];
3106 [book_ pushPage:files];
3109 } else if (row-- == 0) {
3110 } else if (row-- == 0) {
3111 } else if ([package_ size] != 0 && row-- == 0) {
3112 } else if ([package_ maintainer] != nil && row-- == 0) {
3113 [delegate_ openURL:[NSURL URLWithString:[NSString stringWithFormat:@"mailto:%@?subject=%@",
3114 [[package_ maintainer] email],
3115 [[NSString stringWithFormat:@"regarding apt package \"%@\"",
3117 ] stringByAddingPercentEscapes]
3119 } else if ([package_ relationships] != nil && row-- == 0) {
3120 } else if ([[package_ source] trusted] && row-- == 0) {
3121 } _else if ([package_ source] != nil) {
3122 Source *source = [package_ source];
3123 NSString *description = [source description];
3126 } else if (row-- == 0) {
3127 } else if (description != nil && ![description isEqualToString:[source label]] && row-- == 0) {
3128 } else if ([source origin] != nil && row-- == 0) {
3129 } _else _assert(false);
3132 - (void) _clickButtonWithName:(NSString *)name {
3133 if ([name isEqualToString:@"Install"])
3134 [delegate_ installPackage:package_];
3135 else if ([name isEqualToString:@"Reinstall"])
3136 [delegate_ installPackage:package_];
3137 else if ([name isEqualToString:@"Remove"])
3138 [delegate_ removePackage:package_];
3139 else if ([name isEqualToString:@"Upgrade"])
3140 [delegate_ installPackage:package_];
3141 else _assert(false);
3144 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
3145 int count = [buttons_ count];
3146 _assert(count != 0);
3147 _assert(button <= count + 1);
3149 if (count != button - 1)
3150 [self _clickButtonWithName:[buttons_ objectAtIndex:(button - 1)]];
3155 - (void) _rightButtonClicked {
3156 int count = [buttons_ count];
3157 _assert(count != 0);
3160 [self _clickButtonWithName:[buttons_ objectAtIndex:0]];
3162 NSMutableArray *buttons = [NSMutableArray arrayWithCapacity:(count + 1)];
3163 [buttons addObjectsFromArray:buttons_];
3164 [buttons addObject:@"Cancel"];
3166 [delegate_ slideUp:[[[UIAlertSheet alloc]
3169 defaultButtonIndex:2
3176 - (NSString *) rightButtonTitle {
3177 int count = [buttons_ count];
3178 return count == 0 ? nil : count != 1 ? @"Modify" : [buttons_ objectAtIndex:0];
3181 - (NSString *) title {
3185 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3186 if ((self = [super initWithBook:book]) != nil) {
3187 database_ = database;
3189 table_ = [[UIPreferencesTable alloc] initWithFrame:[self bounds]];
3190 [self addSubview:table_];
3192 [table_ setDataSource:self];
3193 [table_ setDelegate:self];
3195 buttons_ = [[NSMutableArray alloc] initWithCapacity:4];
3199 - (void) setPackage:(Package *)package {
3200 if (package_ != nil) {
3201 [package_ autorelease];
3210 if (description_ != nil) {
3211 [description_ release];
3215 [buttons_ removeAllObjects];
3217 if (package != nil) {
3218 package_ = [package retain];
3219 name_ = [[package id] retain];
3221 NSString *description([package description]);
3222 if (description == nil)
3223 description = [package tagline];
3224 if (description != nil) {
3225 description_ = [GetTextView(description, 12, true) retain];
3226 [description_ setTextColor:Black_];
3229 [table_ reloadData];
3231 if ([package_ source] == nil);
3232 else if ([package_ upgradableAndEssential:NO])
3233 [buttons_ addObject:@"Upgrade"];
3234 else if ([package_ installed] == nil)
3235 [buttons_ addObject:@"Install"];
3237 [buttons_ addObject:@"Reinstall"];
3238 if ([package_ installed] != nil)
3239 [buttons_ addObject:@"Remove"];
3243 - (void) resetViewAnimated:(BOOL)animated {
3244 [table_ resetViewAnimated:animated];
3247 - (void) reloadData {
3248 [self setPackage:[database_ packageWithName:name_]];
3249 [self reloadButtons];
3254 /* Package Table {{{ */
3255 @interface PackageTable : RVPage {
3256 _transient Database *database_;
3260 NSMutableArray *packages_;
3261 NSMutableArray *sections_;
3262 UISectionList *list_;
3265 - (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object;
3267 - (void) setDelegate:(id)delegate;
3268 - (void) setObject:(id)object;
3270 - (void) reloadData;
3271 - (void) resetCursor;
3273 - (UISectionList *) list;
3275 - (void) setShouldHideHeaderInShortLists:(BOOL)hide;
3279 @implementation PackageTable
3282 [list_ setDataSource:nil];
3287 [packages_ release];
3288 [sections_ release];
3293 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
3294 return [sections_ count];
3297 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
3298 return [[sections_ objectAtIndex:section] name];
3301 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
3302 return [[sections_ objectAtIndex:section] row];
3305 - (int) numberOfRowsInTable:(UITable *)table {
3306 return [packages_ count];
3309 - (float) table:(UITable *)table heightForRow:(int)row {
3310 return [PackageCell heightForPackage:[packages_ objectAtIndex:row]];
3313 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
3315 reusing = [[[PackageCell alloc] init] autorelease];
3316 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
3320 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
3324 - (void) tableRowSelected:(NSNotification *)notification {
3325 int row = [[notification object] selectedRow];
3329 Package *package = [packages_ objectAtIndex:row];
3330 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
3331 [view setDelegate:delegate_];
3332 [view setPackage:package];
3333 [book_ pushPage:view];
3336 - (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object {
3337 if ((self = [super initWithBook:book]) != nil) {
3338 database_ = database;
3339 title_ = [title retain];
3341 object_ = object == nil ? nil : [object retain];
3343 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
3344 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
3346 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:YES];
3347 [list_ setDataSource:self];
3349 UITableColumn *column = [[[UITableColumn alloc]
3350 initWithTitle:@"Name"
3352 width:[self frame].size.width
3355 UITable *table = [list_ table];
3356 [table setSeparatorStyle:1];
3357 [table addTableColumn:column];
3358 [table setDelegate:self];
3359 [table setReusesTableCells:YES];
3361 [self addSubview:list_];
3366 - (void) setDelegate:(id)delegate {
3367 delegate_ = delegate;
3370 - (void) setObject:(id)object {
3376 object_ = [object retain];
3379 - (void) reloadData {
3380 NSArray *packages = [database_ packages];
3382 [packages_ removeAllObjects];
3383 [sections_ removeAllObjects];
3385 for (size_t i(0); i != [packages count]; ++i) {
3386 Package *package([packages objectAtIndex:i]);
3387 if ([[package performSelector:filter_ withObject:object_] boolValue])
3388 [packages_ addObject:package];
3391 Section *section = nil;
3393 for (size_t offset(0); offset != [packages_ count]; ++offset) {
3394 Package *package = [packages_ objectAtIndex:offset];
3395 NSString *name = [package index];
3397 if (section == nil || ![[section name] isEqualToString:name]) {
3398 section = [[[Section alloc] initWithName:name row:offset] autorelease];
3399 [sections_ addObject:section];
3402 [section addToCount];
3408 - (NSString *) title {
3412 - (void) resetViewAnimated:(BOOL)animated {
3413 [list_ resetViewAnimated:animated];
3416 - (void) resetCursor {
3417 [[list_ table] scrollPointVisibleAtTopLeft:CGPointMake(0, 0) animated:NO];
3420 - (UISectionList *) list {
3424 - (void) setShouldHideHeaderInShortLists:(BOOL)hide {
3425 [list_ setShouldHideHeaderInShortLists:hide];
3431 /* Browser Implementation {{{ */
3432 @implementation BrowserView
3435 WebView *webview = [webview_ webView];
3436 [webview setFrameLoadDelegate:nil];
3437 [webview setResourceLoadDelegate:nil];
3438 [webview setUIDelegate:nil];
3440 [scroller_ setDelegate:nil];
3441 [webview_ setDelegate:nil];
3443 [scroller_ release];
3446 [indicator_ release];
3452 - (void) loadURL:(NSURL *)url cachePolicy:(NSURLRequestCachePolicy)policy {
3453 NSMutableURLRequest *request = [NSMutableURLRequest
3456 timeoutInterval:30.0
3459 [request addValue:[NSString stringWithUTF8String:Firmware_] forHTTPHeaderField:@"X-Firmware"];
3460 [request addValue:[NSString stringWithUTF8String:Machine_] forHTTPHeaderField:@"X-Machine"];
3461 [request addValue:[NSString stringWithUTF8String:SerialNumber_] forHTTPHeaderField:@"X-Serial-Number"];
3463 [self loadRequest:request];
3467 - (void) loadURL:(NSURL *)url {
3468 [self loadURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy];
3471 // XXX: this needs to add the headers
3472 - (NSURLRequest *) _addHeadersToRequest:(NSURLRequest *)request {
3476 - (void) loadRequest:(NSURLRequest *)request {
3477 [webview_ loadRequest:request];
3480 - (void) reloadURL {
3481 NSURL *url = [[[urls_ lastObject] retain] autorelease];
3482 [urls_ removeLastObject];
3483 [self loadURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData];
3486 - (WebView *) webView {
3487 return [webview_ webView];
3490 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame {
3491 [scroller_ setContentSize:frame.size];
3494 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old {
3495 [self view:sender didSetFrame:frame];
3498 - (NSURLRequest *) webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource {
3499 return [self _addHeadersToRequest:request];
3502 - (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request {
3503 if ([[[request URL] scheme] isEqualToString:@"apptapp"])
3505 [self setBackButtonTitle:title_];
3506 BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease];
3507 [browser setDelegate:delegate_];
3508 [book_ pushPage:browser];
3509 [browser loadRequest:[self _addHeadersToRequest:request]];
3510 return [browser webView];
3513 - (void) webView:(WebView *)sender willClickElement:(id)element {
3514 if (![element respondsToSelector:@selector(href)])
3516 NSString *href = [element href];
3519 if ([href hasPrefix:@"apptapp://package/"]) {
3520 NSString *name = [href substringFromIndex:18];
3521 Package *package = [database_ packageWithName:name];
3522 if (package == nil) {
3523 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
3524 initWithTitle:@"Cannot Locate Package"
3525 buttons:[NSArray arrayWithObjects:@"Close", nil]
3526 defaultButtonIndex:0
3531 [sheet setBodyText:[NSString stringWithFormat:
3532 @"The package %@ cannot be found in your current sources. I might recommend installing more sources."
3535 [sheet popupAlertAnimated:YES];
3537 [self setBackButtonTitle:title_];
3538 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
3539 [view setDelegate:delegate_];
3540 [view setPackage:package];
3541 [book_ pushPage:view];
3546 - (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame {
3547 title_ = [title retain];
3548 [self setTitle:title];
3551 - (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame {
3552 if ([frame parentFrame] != nil)
3557 [indicator_ startAnimation];
3558 [self reloadButtons];
3560 if (title_ != nil) {
3565 [self setTitle:@"Loading..."];
3567 WebView *webview = [webview_ webView];
3568 NSString *href = [webview mainFrameURL];
3569 [urls_ addObject:[NSURL URLWithString:href]];
3571 CGRect webrect = [scroller_ frame];
3572 webrect.size.height = 0;
3573 [webview_ setFrame:webrect];
3576 - (void) _finishLoading {
3579 [indicator_ stopAnimation];
3580 [self reloadButtons];
3584 - (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
3585 if ([frame parentFrame] != nil)
3587 [self _finishLoading];
3590 - (void) webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
3591 if ([frame parentFrame] != nil)
3593 [self setTitle:[error localizedDescription]];
3594 [self _finishLoading];
3597 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3598 if ((self = [super initWithBook:book]) != nil) {
3599 database_ = database;
3602 struct CGRect bounds = [self bounds];
3604 UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:bounds] autorelease];
3605 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
3606 [self addSubview:pinstripe];
3608 scroller_ = [[UIScroller alloc] initWithFrame:bounds];
3609 [self addSubview:scroller_];
3611 [scroller_ setScrollingEnabled:YES];
3612 [scroller_ setAdjustForContentSizeChange:YES];
3613 [scroller_ setClipsSubviews:YES];
3614 [scroller_ setAllowsRubberBanding:YES];
3615 [scroller_ setScrollDecelerationFactor:0.99];
3616 [scroller_ setDelegate:self];
3618 CGRect webrect = [scroller_ bounds];
3619 webrect.size.height = 0;
3621 webview_ = [[UIWebView alloc] initWithFrame:webrect];
3622 [scroller_ addSubview:webview_];
3624 [webview_ setTilingEnabled:YES];
3625 [webview_ setTileSize:CGSizeMake(webrect.size.width, 500)];
3626 [webview_ setAutoresizes:YES];
3627 [webview_ setDelegate:self];
3628 //[webview_ setEnabledGestures:2];
3630 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:0];
3631 indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(281, 42, indsize.width, indsize.height)];
3632 [indicator_ setStyle:0];
3634 Package *package([database_ packageWithName:@"cydia"]);
3635 NSString *application = package == nil ? @"Cydia" : [NSString
3636 stringWithFormat:@"Cydia/%@",
3640 WebView *webview = [webview_ webView];
3641 [webview setApplicationNameForUserAgent:application];
3642 [webview setFrameLoadDelegate:self];
3643 [webview setResourceLoadDelegate:self];
3644 [webview setUIDelegate:self];
3646 urls_ = [[NSMutableArray alloc] initWithCapacity:16];
3650 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
3654 - (void) _leftButtonClicked {
3655 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
3656 initWithTitle:@"About Cydia Installer"
3657 buttons:[NSArray arrayWithObjects:@"Close", nil]
3658 defaultButtonIndex:0
3664 @"Copyright (C) 2008\n"
3665 "Jay Freeman (saurik)\n"
3666 "saurik@saurik.com\n"
3667 "http://www.saurik.com/\n"
3670 "http://www.theokorigroup.com/\n"
3672 "College of Creative Studies,\n"
3673 "University of California,\n"
3675 "http://www.ccs.ucsb.edu/"
3678 [sheet popupAlertAnimated:YES];
3681 - (void) _rightButtonClicked {
3686 - (NSString *) leftButtonTitle {
3690 - (NSString *) rightButtonTitle {
3691 return loading_ ? @"" : @"Reload";
3694 - (NSString *) title {
3698 - (NSString *) backButtonTitle {
3702 - (void) setPageActive:(BOOL)active {
3704 [book_ addSubview:indicator_];
3706 [indicator_ removeFromSuperview];
3709 - (void) resetViewAnimated:(BOOL)animated {
3715 @interface CYBook : RVBook <
3718 _transient Database *database_;
3720 UIProgressIndicator *indicator_;
3721 UITextLabel *prompt_;
3722 UIProgressBar *progress_;
3726 - (id) initWithFrame:(CGRect)frame database:(Database *)database;
3732 /* Install View {{{ */
3733 @interface InstallView : RVPage {
3734 _transient Database *database_;
3735 NSMutableArray *packages_;
3736 NSMutableArray *sections_;
3741 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3742 - (void) reloadData;
3746 @implementation InstallView
3749 [list_ setDataSource:nil];
3750 [list_ setDelegate:nil];
3752 [packages_ release];
3753 [sections_ release];
3755 [accessory_ release];
3759 - (int) numberOfRowsInTable:(UITable *)table {
3760 return [sections_ count] + 1;
3763 - (float) table:(UITable *)table heightForRow:(int)row {
3767 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
3769 reusing = [[[SectionCell alloc] init] autorelease];
3770 [(SectionCell *)reusing setSection:(row == 0 ? nil : [sections_ objectAtIndex:(row - 1)])];
3774 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
3778 - (void) tableRowSelected:(NSNotification *)notification {
3779 int row = [[notification object] selectedRow];
3790 title = @"All Packages";
3792 section = [sections_ objectAtIndex:(row - 1)];
3793 name = [section name];
3799 title = @"(No Section)";
3803 PackageTable *table = [[[PackageTable alloc]
3807 filter:@selector(isUninstalledInSection:)
3811 [table setDelegate:delegate_];
3813 [book_ pushPage:table];
3816 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3817 if ((self = [super initWithBook:book]) != nil) {
3818 database_ = database;
3820 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
3821 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
3823 list_ = [[UITable alloc] initWithFrame:[self bounds]];
3824 [self addSubview:list_];
3826 UITableColumn *column = [[[UITableColumn alloc]
3827 initWithTitle:@"Name"
3829 width:[self frame].size.width
3832 [list_ setDataSource:self];
3833 [list_ setSeparatorStyle:1];
3834 [list_ addTableColumn:column];
3835 [list_ setDelegate:self];
3836 [list_ setReusesTableCells:YES];
3842 - (void) reloadData {
3843 NSArray *packages = [database_ packages];
3845 [packages_ removeAllObjects];
3846 [sections_ removeAllObjects];
3848 for (size_t i(0); i != [packages count]; ++i) {
3849 Package *package([packages objectAtIndex:i]);
3850 if ([package valid] && [package installed] == nil)
3851 [packages_ addObject:package];
3854 [packages_ sortUsingSelector:@selector(compareBySection:)];
3856 Section *section = nil;
3857 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
3858 Package *package = [packages_ objectAtIndex:offset];
3859 NSString *name = [package section];
3861 if (section == nil || name != nil && ![[section name] isEqualToString:name]) {
3862 section = [[[Section alloc] initWithName:name row:offset] autorelease];
3863 [sections_ addObject:section];
3866 [section addToCount];
3872 - (void) resetViewAnimated:(BOOL)animated {
3873 [list_ resetViewAnimated:animated];
3876 - (NSString *) title {
3880 - (NSString *) backButtonTitle {
3884 - (UIView *) accessoryView {
3890 /* Changes View {{{ */
3891 @interface ChangesView : RVPage {
3892 _transient Database *database_;
3893 NSMutableArray *packages_;
3894 NSMutableArray *sections_;
3895 UISectionList *list_;
3899 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3900 - (void) reloadData;
3904 @implementation ChangesView
3907 [[list_ table] setDelegate:nil];
3908 [list_ setDataSource:nil];
3910 [packages_ release];
3911 [sections_ release];
3916 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
3917 return [sections_ count];
3920 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
3921 return [[sections_ objectAtIndex:section] name];
3924 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
3925 return [[sections_ objectAtIndex:section] row];
3928 - (int) numberOfRowsInTable:(UITable *)table {
3929 return [packages_ count];
3932 - (float) table:(UITable *)table heightForRow:(int)row {
3933 return [PackageCell heightForPackage:[packages_ objectAtIndex:row]];
3936 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
3938 reusing = [[[PackageCell alloc] init] autorelease];
3939 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
3943 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
3947 - (void) tableRowSelected:(NSNotification *)notification {
3948 int row = [[notification object] selectedRow];
3951 Package *package = [packages_ objectAtIndex:row];
3952 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
3953 [view setDelegate:delegate_];
3954 [view setPackage:package];
3955 [book_ pushPage:view];
3958 - (void) _leftButtonClicked {
3959 [(CYBook *)book_ update];
3960 [self reloadButtons];
3963 - (void) _rightButtonClicked {
3964 [delegate_ distUpgrade];
3967 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3968 if ((self = [super initWithBook:book]) != nil) {
3969 database_ = database;
3971 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
3972 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
3974 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:NO];
3975 [self addSubview:list_];
3977 [list_ setShouldHideHeaderInShortLists:NO];
3978 [list_ setDataSource:self];
3979 //[list_ setSectionListStyle:1];
3981 UITableColumn *column = [[[UITableColumn alloc]
3982 initWithTitle:@"Name"
3984 width:[self frame].size.width
3987 UITable *table = [list_ table];
3988 [table setSeparatorStyle:1];
3989 [table addTableColumn:column];
3990 [table setDelegate:self];
3991 [table setReusesTableCells:YES];
3997 - (void) reloadData {
3998 NSArray *packages = [database_ packages];
4000 [packages_ removeAllObjects];
4001 [sections_ removeAllObjects];
4003 for (size_t i(0); i != [packages count]; ++i) {
4004 Package *package([packages objectAtIndex:i]);
4005 if ([package installed] == nil && [package valid] || [package upgradableAndEssential:NO])
4006 [packages_ addObject:package];
4009 [packages_ sortUsingSelector:@selector(compareForChanges:)];
4011 Section *upgradable = [[[Section alloc] initWithName:@"Available Upgrades" row:0] autorelease];
4012 Section *section = nil;
4015 bool unseens = false;
4017 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, Locale_, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
4019 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
4020 Package *package = [packages_ objectAtIndex:offset];
4022 if ([package upgradableAndEssential:YES]) {
4024 [upgradable addToCount];
4027 NSDate *seen = [package seen];
4032 name = [@"n/a ?" retain];
4034 name = (NSString *) CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen);
4037 if (section == nil || ![[section name] isEqualToString:name]) {
4038 section = [[[Section alloc] initWithName:name row:offset] autorelease];
4039 [sections_ addObject:section];
4043 [section addToCount];
4047 CFRelease(formatter);
4050 Section *last = [sections_ lastObject];
4051 size_t count = [last count];
4052 [packages_ removeObjectsInRange:NSMakeRange([packages_ count] - count, count)];
4053 [sections_ removeLastObject];
4057 [sections_ insertObject:upgradable atIndex:0];
4060 [self reloadButtons];
4063 - (void) resetViewAnimated:(BOOL)animated {
4064 [list_ resetViewAnimated:animated];
4067 - (NSString *) leftButtonTitle {
4068 return [(CYBook *)book_ updating] ? nil : @"Refresh";
4071 - (NSString *) rightButtonTitle {
4072 return upgrades_ == 0 ? nil : [NSString stringWithFormat:@"Upgrade All (%u)", upgrades_];
4075 - (NSString *) title {
4081 /* Manage View {{{ */
4082 @interface ManageView : PackageTable {
4085 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4089 @implementation ManageView
4091 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4096 filter:@selector(isInstalledInSection:)
4102 - (NSString *) title {
4103 return @"Installed Packages";
4106 - (NSString *) backButtonTitle {
4107 return @"All Packages";
4112 /* Search View {{{ */
4113 @protocol SearchViewDelegate
4114 - (void) showKeyboard:(BOOL)show;
4117 @interface SearchView : RVPage {
4119 UISearchField *field_;
4120 UITransitionView *transition_;
4121 PackageTable *table_;
4122 UIPreferencesTable *advanced_;
4128 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4129 - (void) reloadData;
4133 @implementation SearchView
4137 [[field_ textTraits] setEditingDelegate:nil];
4139 [field_ setDelegate:nil];
4141 [accessory_ release];
4143 [transition_ release];
4145 [advanced_ release];
4150 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
4154 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
4156 case 0: return @"Advanced Search (Coming Soon!)";
4158 default: _assert(false);
4162 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
4166 default: _assert(false);
4170 - (void) _showKeyboard:(BOOL)show {
4171 CGSize keysize = [UIKeyboard defaultSize];
4172 CGRect keydown = [book_ pageBounds];
4173 CGRect keyup = keydown;
4174 keyup.size.height -= keysize.height - ButtonBarHeight_;
4176 float delay = KeyboardTime_ * ButtonBarHeight_ / keysize.height;
4178 UIFrameAnimation *animation = [[[UIFrameAnimation alloc] initWithTarget:[table_ list]] autorelease];
4179 [animation setSignificantRectFields:8];
4182 [animation setStartFrame:keydown];
4183 [animation setEndFrame:keyup];
4185 [animation setStartFrame:keyup];
4186 [animation setEndFrame:keydown];
4189 UIAnimator *animator = [UIAnimator sharedAnimator];
4192 addAnimations:[NSArray arrayWithObjects:animation, nil]
4193 withDuration:(KeyboardTime_ - delay)
4198 [animator performSelector:@selector(startAnimation:) withObject:animation afterDelay:delay];
4200 [delegate_ showKeyboard:show];
4203 - (void) textFieldDidBecomeFirstResponder:(UITextField *)field {
4204 [self _showKeyboard:YES];
4207 - (void) textFieldDidResignFirstResponder:(UITextField *)field {
4208 [self _showKeyboard:NO];
4211 - (void) keyboardInputChanged:(UIFieldEditor *)editor {
4213 NSString *text([field_ text]);
4214 [field_ setClearButtonStyle:(text == nil || [text length] == 0 ? 0 : 2)];
4220 - (void) textFieldClearButtonPressed:(UITextField *)field {
4224 - (void) keyboardInputShouldDelete:(id)input {
4228 - (BOOL) keyboardInput:(id)input shouldInsertText:(NSString *)text isMarkedText:(int)marked {
4229 if ([text length] != 1 || [text characterAtIndex:0] != '\n') {
4233 [field_ resignFirstResponder];
4238 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4239 if ((self = [super initWithBook:book]) != nil) {
4240 CGRect pageBounds = [book_ pageBounds];
4242 /*UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:pageBounds] autorelease];
4243 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
4244 [self addSubview:pinstripe];*/
4246 transition_ = [[UITransitionView alloc] initWithFrame:pageBounds];
4247 [self addSubview:transition_];
4249 advanced_ = [[UIPreferencesTable alloc] initWithFrame:pageBounds];
4251 [advanced_ setReusesTableCells:YES];
4252 [advanced_ setDataSource:self];
4253 [advanced_ reloadData];
4255 dimmed_ = [[UIView alloc] initWithFrame:pageBounds];
4256 CGColor dimmed(space_, 0, 0, 0, 0.5);
4257 [dimmed_ setBackgroundColor:dimmed];
4259 table_ = [[PackageTable alloc]
4263 filter:@selector(isSearchedForBy:)
4267 [table_ setShouldHideHeaderInShortLists:NO];
4268 [transition_ transition:0 toView:table_];
4270 CGRect cnfrect = {{1, 38}, {17, 18}};
4273 area.origin.x = cnfrect.size.width + 15;
4275 area.size.width = [self bounds].size.width - area.origin.x - 18;
4276 area.size.height = [UISearchField defaultHeight];
4278 field_ = [[UISearchField alloc] initWithFrame:area];
4280 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
4281 [field_ setFont:font];
4284 [field_ setPlaceholder:@"Package Names & Descriptions"];
4285 [field_ setPaddingTop:5];
4286 [field_ setDelegate:self];
4289 UITextTraits *traits = [field_ textTraits];
4290 [traits setEditingDelegate:self];
4291 [traits setReturnKeyType:6];
4292 [traits setAutoCapsType:0];
4293 [traits setAutoCorrectionType:1];
4296 UIPushButton *configure = [[[UIPushButton alloc] initWithFrame:cnfrect] autorelease];
4297 [configure setShowPressFeedback:YES];
4298 [configure setImage:[UIImage applicationImageNamed:@"advanced.png"]];
4299 [configure addTarget:self action:@selector(configurePushed) forEvents:1];
4301 accessory_ = [[UIView alloc] initWithFrame:CGRectMake(0, 6, cnfrect.size.width + area.size.width + 6 * 3, area.size.height + 30)];
4302 [accessory_ addSubview:field_];
4303 [accessory_ addSubview:configure];
4309 LKAnimation *animation = [LKTransition animation];
4310 [animation setType:@"oglFlip"];
4311 [animation setTimingFunction:[LKTimingFunction functionWithName:@"easeInEaseOut"]];
4312 [animation setFillMode:@"extended"];
4313 [animation setTransitionFlags:3];
4314 [animation setDuration:10];
4315 [animation setSpeed:0.35];
4316 [animation setSubtype:(flipped_ ? @"fromLeft" : @"fromRight")];
4317 [[transition_ _layer] addAnimation:animation forKey:0];
4318 [transition_ transition:0 toView:(flipped_ ? (UIView *) table_ : (UIView *) advanced_)];
4319 flipped_ = !flipped_;
4323 - (void) configurePushed {
4324 [field_ resignFirstResponder];
4328 - (void) resetViewAnimated:(BOOL)animated {
4331 [table_ resetViewAnimated:animated];
4334 - (void) reloadData {
4337 [table_ setObject:[field_ text]];
4338 [table_ reloadData];
4339 [table_ resetCursor];
4342 - (UIView *) accessoryView {
4346 - (NSString *) title {
4350 - (NSString *) backButtonTitle {
4354 - (void) setDelegate:(id)delegate {
4355 [table_ setDelegate:delegate];
4356 [super setDelegate:delegate];
4362 @implementation CYBook
4366 [indicator_ release];
4368 [progress_ release];
4372 - (NSString *) getTitleForPage:(RVPage *)page {
4373 return Simplify([super getTitleForPage:page]);
4381 [navbar_ setPrompt:@""];
4382 [navbar_ addSubview:overlay_];
4383 [indicator_ startAnimation];
4384 [prompt_ setText:@"Updating Database..."];
4385 [progress_ setProgress:0];
4390 detachNewThreadSelector:@selector(_update)
4399 [overlay_ removeFromSuperview];
4400 [indicator_ stopAnimation];
4401 [delegate_ reloadData];
4403 [self setPrompt:[NSString stringWithFormat:@"Last Updated: %@", GetLastUpdate()]];
4406 - (id) initWithFrame:(CGRect)frame database:(Database *)database {
4407 if ((self = [super initWithFrame:frame]) != nil) {
4408 database_ = database;
4411 [navbar_ setBarStyle:1];
4413 CGRect ovrrect = [navbar_ bounds];
4414 ovrrect.size.height = [UINavigationBar defaultSizeWithPrompt].height - [UINavigationBar defaultSize].height;
4416 overlay_ = [[UIView alloc] initWithFrame:ovrrect];
4418 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:2];
4419 unsigned indoffset = (ovrrect.size.height - indsize.height) / 2;
4420 CGRect indrect = {{indoffset, indoffset}, indsize};
4422 indicator_ = [[UIProgressIndicator alloc] initWithFrame:indrect];
4423 [indicator_ setStyle:(Advanced_ ? 2 : 3)];
4424 [overlay_ addSubview:indicator_];
4426 CGSize prmsize = {200, indsize.width};
4429 indoffset * 2 + indsize.width,
4430 (ovrrect.size.height - prmsize.height) / 2
4433 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 12);
4435 prompt_ = [[UITextLabel alloc] initWithFrame:prmrect];
4437 [prompt_ setColor:(Advanced_ ? White_ : Blueish_)];
4438 [prompt_ setBackgroundColor:Clear_];
4439 [prompt_ setFont:font];
4443 [overlay_ addSubview:prompt_];
4445 CGSize prgsize = {75, 100};
4448 ovrrect.size.width - prgsize.width - 10,
4449 (ovrrect.size.height - prgsize.height) / 2
4452 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
4453 [progress_ setStyle:0];
4454 [overlay_ addSubview:progress_];
4459 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
4462 status.setDelegate(self);
4464 [database_ updateWithStatus:status];
4467 performSelectorOnMainThread:@selector(_update_)
4475 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id {
4476 [prompt_ setText:[NSString stringWithFormat:@"Error: %@", error]];
4479 - (void) setProgressTitle:(NSString *)title {
4481 performSelectorOnMainThread:@selector(_setProgressTitle:)
4487 - (void) setProgressPercent:(float)percent {
4490 - (void) addProgressOutput:(NSString *)output {
4492 performSelectorOnMainThread:@selector(_addProgressOutput:)
4498 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
4502 - (void) _setProgressTitle:(NSString *)title {
4503 [prompt_ setText:[title stringByAppendingString:@"..."]];
4506 - (void) _addProgressOutput:(NSString *)output {
4511 @interface Cydia : UIApplication <
4512 ConfirmationViewDelegate,
4513 ProgressViewDelegate,
4522 UIButtonBar *buttonbar_;
4524 ConfirmationView *confirm_;
4526 NSMutableArray *essential_;
4527 NSMutableArray *broken_;
4529 Database *database_;
4530 ProgressView *progress_;
4534 UIKeyboard *keyboard_;
4536 InstallView *install_;
4537 ChangesView *changes_;
4538 ManageView *manage_;
4539 SearchView *search_;
4544 @implementation Cydia
4547 if ([broken_ count] != 0) {
4548 int count = [broken_ count];
4550 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
4551 initWithTitle:[NSString stringWithFormat:@"%d Half-Installed Package%@", count, (count == 1 ? @"" : @"s")]
4552 buttons:[NSArray arrayWithObjects:
4554 @"Ignore (Temporary)",
4556 defaultButtonIndex:0
4561 [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."];
4562 [sheet popupAlertAnimated:YES];
4563 } else if (!Ignored_ && [essential_ count] != 0) {
4564 int count = [essential_ count];
4566 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
4567 initWithTitle:[NSString stringWithFormat:@"%d Essential Upgrade%@", count, (count == 1 ? @"" : @"s")]
4568 buttons:[NSArray arrayWithObjects:@"Upgrade Essential", @"Ignore (Temporary)", nil]
4569 defaultButtonIndex:0
4574 [sheet setBodyText:@"One or more essential packages are currently out of date. If these upgrades are not performed you are likely to encounter errors."];
4575 [sheet popupAlertAnimated:YES];
4579 - (void) _reloadData {
4580 /*UIProgressHUD *hud = [[UIProgressHUD alloc] initWithWindow:window_];
4581 [hud setText:@"Reloading Data"];
4582 [overlay_ addSubview:hud];
4585 [database_ reloadData];
4587 if (Packages_ == nil) {
4588 Packages_ = [[NSMutableDictionary alloc] initWithCapacity:128];
4589 [Metadata_ setObject:Packages_ forKey:@"Packages"];
4594 [essential_ removeAllObjects];
4595 [broken_ removeAllObjects];
4597 NSArray *packages = [database_ packages];
4598 for (int i(0), e([packages count]); i != e; ++i) {
4599 Package *package = [packages objectAtIndex:i];
4601 [broken_ addObject:package];
4602 if ([package upgradableAndEssential:NO]) {
4603 if ([package essential])
4604 [essential_ addObject:package];
4610 NSString *badge([[NSNumber numberWithInt:changes] stringValue]);
4611 [buttonbar_ setBadgeValue:badge forButton:3];
4612 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
4613 [buttonbar_ setBadgeAnimated:YES forButton:3];
4614 [self setApplicationBadge:badge];
4616 [buttonbar_ setBadgeValue:nil forButton:3];
4617 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
4618 [buttonbar_ setBadgeAnimated:NO forButton:3];
4619 [self removeApplicationBadge];
4623 _assert([Metadata_ writeToFile:@"/var/lib/cydia/metadata.plist" atomically:YES] == YES);
4627 /* XXX: this is just stupid */
4629 [install_ reloadData];
4631 [changes_ reloadData];
4633 [manage_ reloadData];
4635 [search_ reloadData];
4639 if ([packages count] == 0);
4648 [hud removeFromSuperview];*/
4651 - (void) reloadData {
4652 @synchronized (self) {
4653 if (confirm_ == nil)
4659 pkgProblemResolver *resolver = [database_ resolver];
4661 resolver->InstallProtect();
4662 if (!resolver->Resolve(true))
4667 [database_ prepare];
4669 if ([database_ cache]->BrokenCount() == 0)
4670 confirm_ = [[ConfirmationView alloc] initWithView:underlay_ database:database_ delegate:self];
4672 NSMutableArray *broken = [NSMutableArray arrayWithCapacity:16];
4673 NSArray *packages = [database_ packages];
4675 for (size_t i(0); i != [packages count]; ++i) {
4676 Package *package = [packages objectAtIndex:i];
4677 if ([package broken])
4678 [broken addObject:[package name]];
4681 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
4682 initWithTitle:[NSString stringWithFormat:@"%d Broken Packages", [database_ cache]->BrokenCount()]
4683 buttons:[NSArray arrayWithObjects:@"Okay", nil]
4684 defaultButtonIndex:0
4689 [sheet setBodyText:[NSString stringWithFormat:@"The following packages have unmet dependencies:\n\n%@", [broken componentsJoinedByString:@"\n"]]];
4690 [sheet popupAlertAnimated:YES];
4696 - (void) installPackage:(Package *)package {
4697 @synchronized (self) {
4704 - (void) removePackage:(Package *)package {
4705 @synchronized (self) {
4712 - (void) distUpgrade {
4713 @synchronized (self) {
4714 [database_ upgrade];
4720 @synchronized (self) {
4728 [overlay_ removeFromSuperview];
4732 detachNewThreadSelector:@selector(perform)
4739 - (void) bootstrap_ {
4741 [database_ upgrade];
4742 [database_ prepare];
4743 [database_ perform];
4746 - (void) bootstrap {
4748 detachNewThreadSelector:@selector(bootstrap_)
4751 title:@"Bootstrap Install..."
4755 - (void) progressViewIsComplete:(ProgressView *)progress {
4756 @synchronized (self) {
4759 if (confirm_ != nil) {
4760 [underlay_ addSubview:overlay_];
4761 [confirm_ removeFromSuperview];
4768 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
4769 NSString *context = [sheet context];
4770 if ([context isEqualToString:@"fixhalf"])
4773 @synchronized (self) {
4774 for (int i = 0, e = [broken_ count]; i != e; ++i) {
4775 Package *broken = [broken_ objectAtIndex:i];
4778 NSString *id = [broken id];
4779 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.prerm", id] UTF8String]);
4780 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.postrm", id] UTF8String]);
4781 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.preinst", id] UTF8String]);
4782 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.postinst", id] UTF8String]);
4791 [broken_ removeAllObjects];
4798 else if ([context isEqualToString:@"upgrade"])
4801 @synchronized (self) {
4802 for (int i = 0, e = [essential_ count]; i != e; ++i) {
4803 Package *essential = [essential_ objectAtIndex:i];
4804 [essential install];
4823 - (void) setPage:(RVPage *)page {
4824 [page resetViewAnimated:NO];
4825 [page setDelegate:self];
4826 [book_ setPage:page];
4829 - (RVPage *) _setHomePage {
4830 BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease];
4831 [self setPage:browser];
4832 [browser loadURL:[NSURL URLWithString:@"http://cydia.saurik.com/"]];
4836 - (void) buttonBarItemTapped:(id)sender {
4837 unsigned tag = [sender tag];
4839 [book_ resetViewAnimated:YES];
4844 case 1: [self _setHomePage]; break;
4846 case 2: [self setPage:install_]; break;
4847 case 3: [self setPage:changes_]; break;
4848 case 4: [self setPage:manage_]; break;
4849 case 5: [self setPage:search_]; break;
4851 default: _assert(false);
4857 - (void) applicationWillSuspend {
4858 [super applicationWillSuspend];
4863 pid_t pid = ExecFork();
4866 if (pid_t child = fork())
4867 waitpid(child, NULL, 0);
4869 execlp("launchctl", "launchctl", "unload", SpringBoard_, NULL);
4872 execlp("launchctl", "launchctl", "load", SpringBoard_, NULL);
4878 - (void) applicationDidFinishLaunching:(id)unused {
4879 _assert(pkgInitConfig(*_config));
4880 _assert(pkgInitSystem(*_config, _system));
4885 essential_ = [[NSMutableArray alloc] initWithCapacity:4];
4886 broken_ = [[NSMutableArray alloc] initWithCapacity:4];
4888 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
4889 window_ = [[UIWindow alloc] initWithContentRect:screenrect];
4891 [window_ orderFront: self];
4892 [window_ makeKey: self];
4893 [window_ _setHidden: NO];
4895 database_ = [[Database alloc] init];
4896 progress_ = [[ProgressView alloc] initWithFrame:[window_ bounds] database:database_ delegate:self];
4897 [database_ setDelegate:progress_];
4898 [window_ setContentView:progress_];
4900 underlay_ = [[UIView alloc] initWithFrame:[progress_ bounds]];
4901 [progress_ setContentView:underlay_];
4903 overlay_ = [[UIView alloc] initWithFrame:[underlay_ bounds]];
4906 [underlay_ addSubview:overlay_];
4908 book_ = [[CYBook alloc] initWithFrame:CGRectMake(
4909 0, 0, screenrect.size.width, screenrect.size.height - 48
4910 ) database:database_];
4912 [book_ setDelegate:self];
4914 [overlay_ addSubview:book_];
4916 NSArray *buttonitems = [NSArray arrayWithObjects:
4917 [NSDictionary dictionaryWithObjectsAndKeys:
4918 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
4919 @"home-up.png", kUIButtonBarButtonInfo,
4920 @"home-dn.png", kUIButtonBarButtonSelectedInfo,
4921 [NSNumber numberWithInt:1], kUIButtonBarButtonTag,
4922 self, kUIButtonBarButtonTarget,
4923 @"Home", kUIButtonBarButtonTitle,
4924 @"0", kUIButtonBarButtonType,
4927 [NSDictionary dictionaryWithObjectsAndKeys:
4928 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
4929 @"install-up.png", kUIButtonBarButtonInfo,
4930 @"install-dn.png", kUIButtonBarButtonSelectedInfo,
4931 [NSNumber numberWithInt:2], kUIButtonBarButtonTag,
4932 self, kUIButtonBarButtonTarget,
4933 @"Install", kUIButtonBarButtonTitle,
4934 @"0", kUIButtonBarButtonType,
4937 [NSDictionary dictionaryWithObjectsAndKeys:
4938 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
4939 @"changes-up.png", kUIButtonBarButtonInfo,
4940 @"changes-dn.png", kUIButtonBarButtonSelectedInfo,
4941 [NSNumber numberWithInt:3], kUIButtonBarButtonTag,
4942 self, kUIButtonBarButtonTarget,
4943 @"Changes", kUIButtonBarButtonTitle,
4944 @"0", kUIButtonBarButtonType,
4947 [NSDictionary dictionaryWithObjectsAndKeys:
4948 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
4949 @"manage-up.png", kUIButtonBarButtonInfo,
4950 @"manage-dn.png", kUIButtonBarButtonSelectedInfo,
4951 [NSNumber numberWithInt:4], kUIButtonBarButtonTag,
4952 self, kUIButtonBarButtonTarget,
4953 @"Manage", kUIButtonBarButtonTitle,
4954 @"0", kUIButtonBarButtonType,
4957 [NSDictionary dictionaryWithObjectsAndKeys:
4958 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
4959 @"search-up.png", kUIButtonBarButtonInfo,
4960 @"search-dn.png", kUIButtonBarButtonSelectedInfo,
4961 [NSNumber numberWithInt:5], kUIButtonBarButtonTag,
4962 self, kUIButtonBarButtonTarget,
4963 @"Search", kUIButtonBarButtonTitle,
4964 @"0", kUIButtonBarButtonType,
4968 buttonbar_ = [[UIButtonBar alloc]
4970 withFrame:CGRectMake(
4971 0, screenrect.size.height - ButtonBarHeight_,
4972 screenrect.size.width, ButtonBarHeight_
4974 withItemList:buttonitems
4977 [buttonbar_ setDelegate:self];
4978 [buttonbar_ setBarStyle:1];
4979 [buttonbar_ setButtonBarTrackingMode:2];
4981 int buttons[5] = {1, 2, 3, 4, 5};
4982 [buttonbar_ registerButtonGroup:0 withButtons:buttons withCount:5];
4983 [buttonbar_ showButtonGroup:0 withDuration:0];
4985 for (int i = 0; i != 5; ++i)
4986 [[buttonbar_ viewWithTag:(i + 1)] setFrame:CGRectMake(
4987 i * 64 + 2, 1, 60, ButtonBarHeight_
4990 [buttonbar_ showSelectionForButton:1];
4991 [overlay_ addSubview:buttonbar_];
4993 [UIKeyboard initImplementationNow];
4994 CGSize keysize = [UIKeyboard defaultSize];
4995 CGRect keyrect = {{0, [overlay_ bounds].size.height}, keysize};
4996 keyboard_ = [[UIKeyboard alloc] initWithFrame:keyrect];
4997 [[UIKeyboardImpl sharedInstance] setSoundsEnabled:(Sounds_Keyboard_ ? YES : NO)];
4998 [overlay_ addSubview:keyboard_];
5000 install_ = [[InstallView alloc] initWithBook:book_ database:database_];
5001 changes_ = [[ChangesView alloc] initWithBook:book_ database:database_];
5002 manage_ = [[ManageView alloc] initWithBook:book_ database:database_];
5003 search_ = [[SearchView alloc] initWithBook:book_ database:database_];
5005 [progress_ resetView];
5011 [self _setHomePage];
5014 - (void) showKeyboard:(BOOL)show {
5015 CGSize keysize = [UIKeyboard defaultSize];
5016 CGRect keydown = {{0, [overlay_ bounds].size.height}, keysize};
5017 CGRect keyup = keydown;
5018 keyup.origin.y -= keysize.height;
5020 UIFrameAnimation *animation = [[[UIFrameAnimation alloc] initWithTarget:keyboard_] autorelease];
5021 [animation setSignificantRectFields:2];
5024 [animation setStartFrame:keydown];
5025 [animation setEndFrame:keyup];
5026 [keyboard_ activate];
5028 [animation setStartFrame:keyup];
5029 [animation setEndFrame:keydown];
5030 [keyboard_ deactivate];
5033 [[UIAnimator sharedAnimator]
5034 addAnimations:[NSArray arrayWithObjects:animation, nil]
5035 withDuration:KeyboardTime_
5040 - (void) slideUp:(UIAlertSheet *)alert {
5042 [alert presentSheetFromButtonBar:buttonbar_];
5044 [alert presentSheetInView:overlay_];
5049 void AddPreferences(NSString *plist) {
5050 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5052 NSMutableDictionary *settings = [[[NSMutableDictionary alloc] initWithContentsOfFile:plist] autorelease];
5053 _assert(settings != NULL);
5054 NSMutableArray *items = [settings objectForKey:@"items"];
5058 for (size_t i(0); i != [items count]; ++i) {
5059 NSMutableDictionary *item([items objectAtIndex:i]);
5060 NSString *label = [item objectForKey:@"label"];
5061 if (label != nil && [label isEqualToString:@"Cydia"]) {
5068 for (size_t i(0); i != [items count]; ++i) {
5069 NSDictionary *item([items objectAtIndex:i]);
5070 NSString *label = [item objectForKey:@"label"];
5071 if (label != nil && [label isEqualToString:@"General"]) {
5072 [items insertObject:[NSDictionary dictionaryWithObjectsAndKeys:
5073 @"CydiaSettings", @"bundle",
5074 @"PSLinkCell", @"cell",
5075 [NSNumber numberWithBool:YES], @"hasIcon",
5076 [NSNumber numberWithBool:YES], @"isController",
5078 nil] atIndex:(i + 1)];
5084 _assert([settings writeToFile:plist atomically:YES] == YES);
5091 id Alloc_(id self, SEL selector) {
5092 id object = alloc_(self, selector);
5093 fprintf(stderr, "[%s]A-%p\n", self->isa->name, object);
5098 id Dealloc_(id self, SEL selector) {
5099 id object = dealloc_(self, selector);
5100 fprintf(stderr, "[%s]D-%p\n", self->isa->name, object);
5104 int main(int argc, char *argv[]) {
5105 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5107 bootstrap_ = argc > 1 && strcmp(argv[1], "--bootstrap") == 0;
5109 Home_ = NSHomeDirectory();
5112 NSString *plist = [Home_ stringByAppendingString:@"/Library/Preferences/com.apple.preferences.sounds.plist"];
5113 if (NSDictionary *sounds = [NSDictionary dictionaryWithContentsOfFile:plist])
5114 if (NSNumber *keyboard = [sounds objectForKey:@"keyboard"])
5115 Sounds_Keyboard_ = [keyboard boolValue];
5121 /*Method alloc = class_getClassMethod([NSObject class], @selector(alloc));
5122 alloc_ = alloc->method_imp;
5123 alloc->method_imp = (IMP) &Alloc_;*/
5125 /*Method dealloc = class_getClassMethod([NSObject class], @selector(dealloc));
5126 dealloc_ = dealloc->method_imp;
5127 dealloc->method_imp = (IMP) &Dealloc_;*/
5129 if (NSDictionary *sysver = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]) {
5130 if (NSString *prover = [sysver valueForKey:@"ProductVersion"]) {
5131 Firmware_ = strdup([prover UTF8String]);
5132 NSArray *versions = [prover componentsSeparatedByString:@"."];
5133 int count = [versions count];
5134 Major_ = count > 0 ? [[versions objectAtIndex:0] intValue] : 0;
5135 Minor_ = count > 1 ? [[versions objectAtIndex:1] intValue] : 0;
5136 BugFix_ = count > 2 ? [[versions objectAtIndex:2] intValue] : 0;
5141 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
5142 char *machine = new char[size];
5143 sysctlbyname("hw.machine", machine, &size, NULL, 0);
5146 if (CFMutableDictionaryRef dict = IOServiceMatching("IOPlatformExpertDevice"))
5147 if (io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, dict)) {
5148 if (CFTypeRef serial = IORegistryEntryCreateCFProperty(service, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0)) {
5149 SerialNumber_ = strdup(CFStringGetCStringPtr((CFStringRef) serial, CFStringGetSystemEncoding()));
5153 IOObjectRelease(service);
5156 /*AddPreferences(@"/Applications/Preferences.app/Settings-iPhone.plist");
5157 AddPreferences(@"/Applications/Preferences.app/Settings-iPod.plist");*/
5159 if ((Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"]) == NULL)
5160 Metadata_ = [[NSMutableDictionary alloc] initWithCapacity:2];
5162 Packages_ = [Metadata_ objectForKey:@"Packages"];
5164 if (access("/User", F_OK) != 0)
5165 system("/usr/libexec/cydia/firmware.sh");
5167 Locale_ = CFLocaleCopyCurrent();
5168 space_ = CGColorSpaceCreateDeviceRGB();
5170 Blueish_.Set(space_, 0x19/255.f, 0x32/255.f, 0x50/255.f, 1.0);
5171 Black_.Set(space_, 0.0, 0.0, 0.0, 1.0);
5172 Clear_.Set(space_, 0.0, 0.0, 0.0, 0.0);
5173 Red_.Set(space_, 1.0, 0.0, 0.0, 1.0);
5174 White_.Set(space_, 1.0, 1.0, 1.0, 1.0);
5176 int value = UIApplicationMain(argc, argv, [Cydia class]);
5178 CGColorSpaceRelease(space_);