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/configuration.h>
65 #include <apt-pkg/debmetaindex.h>
66 #include <apt-pkg/error.h>
67 #include <apt-pkg/init.h>
68 #include <apt-pkg/pkgrecords.h>
69 #include <apt-pkg/sourcelist.h>
70 #include <apt-pkg/sptr.h>
72 #include <sys/sysctl.h>
76 #include <mach-o/nlist.h>
87 /* iPhoneOS 2.0 Compatibility {{{ */
89 @interface UICGColor : NSObject {
92 - (id) initWithCGColor:(CGColorRef)color;
98 - (UIFont *) fontWithSize:(CGFloat)size;
101 @interface NSObject (iPhoneOS)
102 - (CGColorRef) cgColor;
103 - (CGColorRef) CGColor;
107 @implementation NSObject (iPhoneOS)
109 - (CGColorRef) cgColor {
110 return [self CGColor];
113 - (CGColorRef) CGColor {
114 return (CGColorRef) self;
118 [[[[objc_getClass("UICGColor") alloc] initWithCGColor:[self CGColor]] autorelease] set];
123 @interface UITextView (iPhoneOS)
124 - (void) setTextSize:(float)size;
127 @implementation UITextView (iPhoneOS)
129 - (void) setTextSize:(float)size {
130 [self setFont:[[self font] fontWithSize:size]];
137 @interface NSString (UIKit)
138 - (NSString *) stringByAddingPercentEscapes;
139 - (NSString *) stringByReplacingCharacter:(unsigned short)arg0 withCharacter:(unsigned short)arg1;
142 @interface NSString (Cydia)
143 + (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length;
144 - (NSComparisonResult) compareByPath:(NSString *)other;
147 @implementation NSString (Cydia)
149 + (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length {
150 char data[length + 1];
151 memcpy(data, bytes, length);
153 return [NSString stringWithUTF8String:data];
156 - (NSComparisonResult) compareByPath:(NSString *)other {
157 NSString *prefix = [self commonPrefixWithString:other options:0];
158 size_t length = [prefix length];
160 NSRange lrange = NSMakeRange(length, [self length] - length);
161 NSRange rrange = NSMakeRange(length, [other length] - length);
163 lrange = [self rangeOfString:@"/" options:0 range:lrange];
164 rrange = [other rangeOfString:@"/" options:0 range:rrange];
166 NSComparisonResult value;
168 if (lrange.location == NSNotFound && rrange.location == NSNotFound)
169 value = NSOrderedSame;
170 else if (lrange.location == NSNotFound)
171 value = NSOrderedAscending;
172 else if (rrange.location == NSNotFound)
173 value = NSOrderedDescending;
175 value = NSOrderedSame;
177 NSString *lpath = lrange.location == NSNotFound ? [self substringFromIndex:length] :
178 [self substringWithRange:NSMakeRange(length, lrange.location - length)];
179 NSString *rpath = rrange.location == NSNotFound ? [other substringFromIndex:length] :
180 [other substringWithRange:NSMakeRange(length, rrange.location - length)];
182 NSComparisonResult result = [lpath compare:rpath];
183 return result == NSOrderedSame ? value : result;
188 /* Perl-Compatible RegEx {{{ */
198 Pcre(const char *regex) :
203 code_ = pcre_compile(regex, 0, &error, &offset, NULL);
206 fprintf(stderr, "%d:%s\n", offset, error);
210 pcre_fullinfo(code_, study_, PCRE_INFO_CAPTURECOUNT, &capture_);
211 matches_ = new int[(capture_ + 1) * 3];
219 NSString *operator [](size_t match) {
220 return [NSString stringWithUTF8Bytes:(data_ + matches_[match * 2]) length:(matches_[match * 2 + 1] - matches_[match * 2])];
223 bool operator ()(NSString *data) {
224 // XXX: length is for characters, not for bytes
225 return operator ()([data UTF8String], [data length]);
228 bool operator ()(const char *data, size_t size) {
230 return pcre_exec(code_, study_, data, size, 0, 0, matches_, (capture_ + 1) * 3) >= 0;
234 /* Mime Addresses {{{ */
235 Pcre email_r("^\"?(.*)\"? <([^>]*)>$");
237 @interface Address : NSObject {
243 - (NSString *) email;
245 + (Address *) addressWithString:(NSString *)string;
246 - (Address *) initWithString:(NSString *)string;
249 @implementation Address
258 - (NSString *) name {
262 - (NSString *) email {
266 + (Address *) addressWithString:(NSString *)string {
267 return [[[Address alloc] initWithString:string] autorelease];
270 - (Address *) initWithString:(NSString *)string {
271 if ((self = [super init]) != nil) {
272 const char *data = [string UTF8String];
273 size_t size = [string length];
275 if (email_r(data, size)) {
276 name_ = [email_r[1] retain];
277 email_ = [email_r[2] retain];
279 name_ = [[NSString alloc]
282 encoding:kCFStringEncodingUTF8
292 /* CoreGraphics Primitives {{{ */
303 CGColor(CGColorSpaceRef space, float red, float green, float blue, float alpha) :
306 Set(space, red, green, blue, alpha);
311 CGColorRelease(color_);
318 void Set(CGColorSpaceRef space, float red, float green, float blue, float alpha) {
320 float color[] = {red, green, blue, alpha};
321 color_ = CGColorCreate(space, color);
324 operator CGColorRef() {
339 /* Right Alignment {{{ */
340 @interface UIRightTextLabel : UITextLabel {
341 float _savedRightEdgeX;
342 BOOL _sizedtofit_flag;
345 - (void) setFrame:(CGRect)frame;
346 - (void) setText:(NSString *)text;
347 - (void) realignText;
350 @implementation UIRightTextLabel
352 - (void) setFrame:(CGRect)frame {
353 [super setFrame:frame];
354 if (_sizedtofit_flag == NO) {
355 _savedRightEdgeX = frame.origin.x;
360 - (void) setText:(NSString *)text {
361 [super setText:text];
365 - (void) realignText {
366 CGRect oldFrame = [self frame];
368 _sizedtofit_flag = YES;
369 [self sizeToFit]; // shrink down size so I can right align it
371 CGRect newFrame = [self frame];
373 oldFrame.origin.x = _savedRightEdgeX - newFrame.size.width;
374 oldFrame.size.width = newFrame.size.width;
375 [super setFrame:oldFrame];
376 _sizedtofit_flag = NO;
382 /* Random Global Variables {{{ */
383 static const int PulseInterval_ = 50000;
384 static const int ButtonBarHeight_ = 48;
385 static const float KeyboardTime_ = 0.4f;
387 static CGColor Black_;
388 static CGColor Clear_;
390 static CGColor White_;
392 static NSString *Home_;
393 static BOOL Sounds_Keyboard_;
395 static BOOL Advanced_;
397 static BOOL Ignored_;
399 const char *Firmware_ = NULL;
400 const char *Machine_ = NULL;
401 const char *SerialNumber_ = NULL;
407 CGColorSpaceRef space_;
409 #define FW_LEAST(major, minor, bugfix) \
410 (major < Major_ || major == Major_ && \
411 (minor < Minor_ || minor == Minor_ && \
417 static NSMutableDictionary *Metadata_;
418 static NSMutableDictionary *Packages_;
419 static bool Changed_;
422 NSString *GetLastUpdate() {
423 NSDate *update = [Metadata_ objectForKey:@"LastUpdate"];
426 return @"Never or Unknown";
428 CFLocaleRef locale = CFLocaleCopyCurrent();
429 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
430 CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) update);
432 CFRelease(formatter);
435 return [(NSString *) formatted autorelease];
438 /* Display Helpers {{{ */
439 inline float Interpolate(float begin, float end, float fraction) {
440 return (end - begin) * fraction + begin;
443 NSString *SizeString(double size) {
445 while (size > 1024) {
450 static const char *powers_[] = {"B", "kB", "MB", "GB"};
452 return [NSString stringWithFormat:@"%.1f%s", size, powers_[power]];
455 static const float TextViewOffset_ = 22;
457 UITextView *GetTextView(NSString *value, float left, bool html) {
458 UITextView *text([[[UITextView alloc] initWithFrame:CGRectMake(left, 3, 310 - left, 1000)] autorelease]);
459 [text setEditable:NO];
460 [text setTextSize:16];
462 [text setHTML:value];
464 [text setText:value];
465 [text setEnabled:NO];
467 [text setBackgroundColor:Clear_];
469 CGRect frame = [text frame];
470 [text setFrame:frame];
471 CGRect rect = [text visibleTextRect];
472 frame.size.height = rect.size.height;
473 [text setFrame:frame];
478 NSString *Simplify(NSString *title) {
479 const char *data = [title UTF8String];
480 size_t size = [title length];
482 Pcre title_r("^(.*?)( \\(.*\\))?$");
483 if (title_r(data, size))
490 /* Delegate Prototypes {{{ */
494 @protocol ProgressDelegate
495 - (void) setProgressError:(NSString *)error;
496 - (void) setProgressTitle:(NSString *)title;
497 - (void) setProgressPercent:(float)percent;
498 - (void) addProgressOutput:(NSString *)output;
501 @protocol ConfigurationDelegate
502 - (void) repairWithSelector:(SEL)selector;
503 - (void) setConfigurationData:(NSString *)data;
506 @protocol CydiaDelegate
507 - (void) installPackage:(Package *)package;
508 - (void) removePackage:(Package *)package;
509 - (void) slideUp:(UIAlertSheet *)alert;
510 - (void) distUpgrade;
514 /* Status Delegation {{{ */
516 public pkgAcquireStatus
519 _transient id<ProgressDelegate> delegate_;
527 void setDelegate(id delegate) {
528 delegate_ = delegate;
531 virtual bool MediaChange(std::string media, std::string drive) {
535 virtual void IMSHit(pkgAcquire::ItemDesc &item) {
538 virtual void Fetch(pkgAcquire::ItemDesc &item) {
539 [delegate_ setProgressTitle:[NSString stringWithUTF8String:("Downloading " + item.ShortDesc).c_str()]];
542 virtual void Done(pkgAcquire::ItemDesc &item) {
545 virtual void Fail(pkgAcquire::ItemDesc &item) {
547 item.Owner->Status == pkgAcquire::Item::StatIdle ||
548 item.Owner->Status == pkgAcquire::Item::StatDone
552 [delegate_ setProgressError:[NSString stringWithUTF8String:item.Owner->ErrorText.c_str()]];
555 virtual bool Pulse(pkgAcquire *Owner) {
556 bool value = pkgAcquireStatus::Pulse(Owner);
559 double(CurrentBytes + CurrentItems) /
560 double(TotalBytes + TotalItems)
563 [delegate_ setProgressPercent:percent];
567 virtual void Start() {
570 virtual void Stop() {
574 /* Progress Delegation {{{ */
579 _transient id<ProgressDelegate> delegate_;
582 virtual void Update() {
583 [delegate_ setProgressTitle:[NSString stringWithUTF8String:Op.c_str()]];
584 [delegate_ setProgressPercent:(Percent / 100)];
593 void setDelegate(id delegate) {
594 delegate_ = delegate;
597 virtual void Done() {
598 [delegate_ setProgressPercent:1];
603 /* Database Interface {{{ */
604 @interface Database : NSObject {
606 pkgDepCache::Policy *policy_;
607 pkgRecords *records_;
608 pkgProblemResolver *resolver_;
609 pkgAcquire *fetcher_;
611 SPtr<pkgPackageManager> manager_;
612 pkgSourceList *list_;
614 NSMutableDictionary *sources_;
615 NSMutableArray *packages_;
617 _transient id<ConfigurationDelegate, ProgressDelegate> delegate_;
625 - (void) _readStatus:(NSNumber *)fd;
626 - (void) _readOutput:(NSNumber *)fd;
630 - (Package *) packageWithName:(NSString *)name;
633 - (pkgCacheFile &) cache;
634 - (pkgDepCache::Policy *) policy;
635 - (pkgRecords *) records;
636 - (pkgProblemResolver *) resolver;
637 - (pkgAcquire &) fetcher;
638 - (NSArray *) packages;
647 - (void) updateWithStatus:(Status &)status;
649 - (void) setDelegate:(id)delegate;
650 - (Source *) getSource:(const pkgCache::PkgFileIterator &)file;
654 /* Source Class {{{ */
655 @interface Source : NSObject {
656 NSString *description_;
661 NSString *distribution_;
665 NSString *defaultIcon_;
670 - (Source *) initWithMetaIndex:(metaIndex *)index;
675 - (NSString *) distribution;
678 - (NSString *) description;
679 - (NSString *) label;
680 - (NSString *) origin;
681 - (NSString *) version;
683 - (NSString *) defaultIcon;
686 @implementation Source
690 [distribution_ release];
693 if (description_ != nil)
694 [description_ release];
701 if (defaultIcon_ != nil)
702 [defaultIcon_ release];
707 - (Source *) initWithMetaIndex:(metaIndex *)index {
708 if ((self = [super init]) != nil) {
709 trusted_ = index->IsTrusted();
711 uri_ = [[NSString stringWithUTF8String:index->GetURI().c_str()] retain];
712 distribution_ = [[NSString stringWithUTF8String:index->GetDist().c_str()] retain];
713 type_ = [[NSString stringWithUTF8String:index->GetType()] retain];
721 debReleaseIndex *dindex(dynamic_cast<debReleaseIndex *>(index));
722 if (dindex != NULL) {
723 std::ifstream release(dindex->MetaIndexFile("Release").c_str());
725 while (std::getline(release, line)) {
726 std::string::size_type colon(line.find(':'));
727 if (colon == std::string::npos)
730 std::string name(line.substr(0, colon));
731 std::string value(line.substr(colon + 1));
732 while (!value.empty() && value[0] == ' ')
733 value = value.substr(1);
735 if (name == "Default-Icon")
736 defaultIcon_ = [[NSString stringWithUTF8String:value.c_str()] retain];
737 else if (name == "Description")
738 description_ = [[NSString stringWithUTF8String:value.c_str()] retain];
739 else if (name == "Label")
740 label_ = [[NSString stringWithUTF8String:value.c_str()] retain];
741 else if (name == "Origin")
742 origin_ = [[NSString stringWithUTF8String:value.c_str()] retain];
743 else if (name == "Version")
744 version_ = [[NSString stringWithUTF8String:value.c_str()] retain];
758 - (NSString *) distribution {
759 return distribution_;
762 - (NSString *) type {
766 - (NSString *) description {
770 - (NSString *) label {
774 - (NSString *) origin {
778 - (NSString *) version {
782 - (NSString *) defaultIcon {
788 /* Relationship Class {{{ */
789 @interface Relationship : NSObject {
800 @implementation Relationship
808 - (NSString *) type {
816 - (NSString *) name {
823 /* Package Class {{{ */
824 NSString *Scour(const char *field, const char *begin, const char *end) {
825 size_t i(0), l(strlen(field));
828 const char *name = begin + i;
829 const char *colon = name + l;
830 const char *value = colon + 1;
835 memcmp(name, field, l) == 0
837 while (value != end && value[0] == ' ')
839 const char *line = std::find(value, end, '\n');
840 while (line != value && line[-1] == ' ')
843 return [NSString stringWithUTF8Bytes:value length:(line - value)];
845 begin = std::find(begin, end, '\n');
853 @interface Package : NSObject {
854 pkgCache::PkgIterator iterator_;
855 _transient Database *database_;
856 pkgCache::VerIterator version_;
857 pkgCache::VerFileIterator file_;
863 NSString *installed_;
871 NSArray *relationships_;
874 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
875 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
877 - (pkgCache::PkgIterator) iterator;
879 - (NSString *) section;
880 - (Address *) maintainer;
882 - (NSString *) description;
883 - (NSString *) index;
887 - (NSString *) latest;
888 - (NSString *) installed;
897 - (NSString *) tagline;
899 - (NSString *) website;
901 - (NSArray *) relationships;
905 - (BOOL) matches:(NSString *)text;
907 - (NSComparisonResult) compareByName:(Package *)package;
908 - (NSComparisonResult) compareBySection:(Package *)package;
909 - (NSComparisonResult) compareBySectionAndName:(Package *)package;
910 - (NSComparisonResult) compareForChanges:(Package *)package;
915 - (NSNumber *) isSearchedForBy:(NSString *)search;
916 - (NSNumber *) isInstalledInSection:(NSString *)section;
917 - (NSNumber *) isUninstalledInSection:(NSString *)section;
921 @implementation Package
928 if (installed_ != nil)
929 [installed_ release];
940 if (relationships_ != nil)
941 [relationships_ release];
946 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
947 if ((self = [super init]) != nil) {
948 iterator_ = iterator;
949 database_ = database;
951 version_ = [database_ policy]->GetCandidateVer(iterator_);
952 latest_ = version_.end() ? nil : [[NSString stringWithUTF8String:version_.VerStr()] retain];
955 file_ = version_.FileList();
957 pkgCache &cache([database_ cache]);
958 file_ = pkgCache::VerFileIterator(cache, cache.VerFileP);
961 pkgCache::VerIterator current = iterator_.CurrentVer();
962 installed_ = current.end() ? nil : [[NSString stringWithUTF8String:current.VerStr()] retain];
964 id_ = [[[NSString stringWithUTF8String:iterator_.Name()] lowercaseString] retain];
967 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
969 const char *begin, *end;
970 parser->GetRec(begin, end);
972 name_ = Scour("Name", begin, end);
974 name_ = [name_ retain];
975 tagline_ = [[NSString stringWithUTF8String:parser->ShortDesc().c_str()] retain];
976 icon_ = Scour("Icon", begin, end);
978 icon_ = [icon_ retain];
979 website_ = Scour("Website", begin, end);
981 website_ = [website_ retain];
984 NSMutableDictionary *metadata = [Packages_ objectForKey:id_];
985 if (metadata == nil || [metadata count] == 0) {
986 metadata = [NSMutableDictionary dictionaryWithObjectsAndKeys:
990 [Packages_ setObject:metadata forKey:id_];
996 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
997 return [[[Package alloc]
998 initWithIterator:iterator
1003 - (pkgCache::PkgIterator) iterator {
1007 - (NSString *) section {
1008 const char *section = iterator_.Section();
1009 return section == NULL ? nil : [[NSString stringWithUTF8String:section] stringByReplacingCharacter:'_' withCharacter:' '];
1012 - (Address *) maintainer {
1015 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1016 return [Address addressWithString:[NSString stringWithUTF8String:parser->Maintainer().c_str()]];
1020 return version_.end() ? 0 : version_->InstalledSize;
1023 - (NSString *) description {
1026 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1027 NSString *description([NSString stringWithUTF8String:parser->LongDesc().c_str()]);
1029 NSArray *lines = [description componentsSeparatedByString:@"\n"];
1030 NSMutableArray *trimmed = [NSMutableArray arrayWithCapacity:([lines count] - 1)];
1031 if ([lines count] < 2)
1034 NSCharacterSet *whitespace = [NSCharacterSet whitespaceCharacterSet];
1035 for (size_t i(1); i != [lines count]; ++i) {
1036 NSString *trim = [[lines objectAtIndex:i] stringByTrimmingCharactersInSet:whitespace];
1037 [trimmed addObject:trim];
1040 return [trimmed componentsJoinedByString:@"\n"];
1043 - (NSString *) index {
1044 NSString *index = [[[self name] substringToIndex:1] uppercaseString];
1045 return [index length] != 0 && isalpha([index characterAtIndex:0]) ? index : @"123";
1049 return [[Packages_ objectForKey:id_] objectForKey:@"FirstSeen"];
1052 - (NSString *) latest {
1056 - (NSString *) installed {
1061 return !version_.end();
1064 - (BOOL) upgradable {
1065 pkgCache::VerIterator current = iterator_.CurrentVer();
1068 return [self essential];
1070 pkgCache::VerIterator candidate = [database_ policy]->GetCandidateVer(iterator_);
1071 return !candidate.end() && candidate != current;
1075 - (BOOL) essential {
1076 return (iterator_->Flags & pkgCache::Flag::Essential) == 0 ? NO : YES;
1080 return (*[database_ cache])[iterator_].InstBroken();
1087 - (NSString *) name {
1088 return name_ == nil ? id_ : name_;
1091 - (NSString *) tagline {
1095 - (NSString *) icon {
1099 - (NSString *) website {
1103 - (NSArray *) relationships {
1104 return relationships_;
1107 - (Source *) source {
1109 source_ = file_.end() ? nil : [[database_ getSource:file_.File()] retain];
1116 - (BOOL) matches:(NSString *)text {
1122 range = [[self id] rangeOfString:text options:NSCaseInsensitiveSearch];
1123 if (range.location != NSNotFound)
1126 range = [[self name] rangeOfString:text options:NSCaseInsensitiveSearch];
1127 if (range.location != NSNotFound)
1130 range = [[self tagline] rangeOfString:text options:NSCaseInsensitiveSearch];
1131 if (range.location != NSNotFound)
1137 - (NSComparisonResult) compareByName:(Package *)package {
1138 NSString *lhs = [self name];
1139 NSString *rhs = [package name];
1141 if ([lhs length] != 0 && [rhs length] != 0) {
1142 unichar lhc = [lhs characterAtIndex:0];
1143 unichar rhc = [rhs characterAtIndex:0];
1145 if (isalpha(lhc) && !isalpha(rhc))
1146 return NSOrderedAscending;
1147 else if (!isalpha(lhc) && isalpha(rhc))
1148 return NSOrderedDescending;
1151 return [lhs caseInsensitiveCompare:rhs];
1154 - (NSComparisonResult) compareBySection:(Package *)package {
1155 NSString *lhs = [self section];
1156 NSString *rhs = [package section];
1158 if (lhs == NULL && rhs != NULL)
1159 return NSOrderedAscending;
1160 else if (lhs != NULL && rhs == NULL)
1161 return NSOrderedDescending;
1162 else if (lhs != NULL && rhs != NULL) {
1163 NSComparisonResult result = [lhs caseInsensitiveCompare:rhs];
1164 if (result != NSOrderedSame)
1168 return NSOrderedSame;
1171 - (NSComparisonResult) compareBySectionAndName:(Package *)package {
1172 NSString *lhs = [self section];
1173 NSString *rhs = [package section];
1175 if (lhs == NULL && rhs != NULL)
1176 return NSOrderedAscending;
1177 else if (lhs != NULL && rhs == NULL)
1178 return NSOrderedDescending;
1179 else if (lhs != NULL && rhs != NULL) {
1180 NSComparisonResult result = [lhs compare:rhs];
1181 if (result != NSOrderedSame)
1185 return [self compareByName:package];
1188 - (NSComparisonResult) compareForChanges:(Package *)package {
1189 BOOL lhs = [self upgradable];
1190 BOOL rhs = [package upgradable];
1193 return lhs ? NSOrderedAscending : NSOrderedDescending;
1195 switch ([[self seen] compare:[package seen]]) {
1196 case NSOrderedAscending:
1197 return NSOrderedDescending;
1200 case NSOrderedDescending:
1201 return NSOrderedAscending;
1207 return [self compareByName:package];
1211 pkgProblemResolver *resolver = [database_ resolver];
1212 resolver->Clear(iterator_);
1213 resolver->Protect(iterator_);
1214 pkgCacheFile &cache([database_ cache]);
1215 cache->MarkInstall(iterator_, false);
1216 pkgDepCache::StateCache &state((*cache)[iterator_]);
1217 if (!state.Install())
1218 cache->SetReInstall(iterator_, true);
1222 pkgProblemResolver *resolver = [database_ resolver];
1223 resolver->Clear(iterator_);
1224 resolver->Protect(iterator_);
1225 resolver->Remove(iterator_);
1226 [database_ cache]->MarkDelete(iterator_, true);
1229 - (NSNumber *) isSearchedForBy:(NSString *)search {
1230 return [NSNumber numberWithBool:([self valid] && [self matches:search])];
1233 - (NSNumber *) isInstalledInSection:(NSString *)section {
1234 return [NSNumber numberWithBool:([self installed] != nil && (section == nil || [section isEqualToString:[self section]]))];
1237 - (NSNumber *) isUninstalledInSection:(NSString *)name {
1238 NSString *section = [self section];
1240 return [NSNumber numberWithBool:([self valid] && [self installed] == nil && (
1242 section == nil && [name length] == 0 ||
1243 [name isEqualToString:section])
1249 /* Section Class {{{ */
1250 @interface Section : NSObject {
1256 - (Section *) initWithName:(NSString *)name row:(size_t)row;
1257 - (NSString *) name;
1260 - (void) addToCount;
1264 @implementation Section
1271 - (Section *) initWithName:(NSString *)name row:(size_t)row {
1272 if ((self = [super init]) != nil) {
1273 name_ = [name retain];
1278 - (NSString *) name {
1290 - (void) addToCount {
1297 /* Database Implementation {{{ */
1298 @implementation Database
1305 - (void) _readStatus:(NSNumber *)fd {
1306 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1308 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1309 std::istream is(&ib);
1312 Pcre conffile_r("^status: [^ ]* : conffile-prompt : (.*?) *$");
1313 Pcre pmstatus_r("^([^:]*):([^:]*):([^:]*):(.*)$");
1315 while (std::getline(is, line)) {
1316 const char *data(line.c_str());
1317 size_t size = line.size();
1318 fprintf(stderr, "%s\n", data);
1320 if (conffile_r(data, size)) {
1321 [delegate_ setConfigurationData:conffile_r[1]];
1322 } else if (strncmp(data, "status: ", 8) == 0) {
1323 NSString *string = [NSString stringWithUTF8String:(data + 8)];
1324 [delegate_ setProgressTitle:string];
1325 } else if (pmstatus_r(data, size)) {
1326 float percent([pmstatus_r[3] floatValue]);
1327 [delegate_ setProgressPercent:(percent / 100)];
1329 NSString *string = pmstatus_r[4];
1330 std::string type([pmstatus_r[1] UTF8String]);
1332 if (type == "pmerror")
1333 [delegate_ setProgressError:string];
1334 else if (type == "pmstatus")
1335 [delegate_ setProgressTitle:string];
1336 else if (type == "pmconffile")
1337 [delegate_ setConfigurationData:string];
1338 else _assert(false);
1339 } else _assert(false);
1346 - (void) _readOutput:(NSNumber *)fd {
1347 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1349 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1350 std::istream is(&ib);
1353 while (std::getline(is, line)) {
1354 fprintf(stderr, "%s\n", line.c_str());
1355 [delegate_ addProgressOutput:[NSString stringWithUTF8String:line.c_str()]];
1366 - (Package *) packageWithName:(NSString *)name {
1367 if (static_cast<pkgDepCache *>(cache_) == NULL)
1369 pkgCache::PkgIterator iterator(cache_->FindPkg([name UTF8String]));
1370 return iterator.end() ? nil : [Package packageWithIterator:iterator database:self];
1373 - (Database *) init {
1374 if ((self = [super init]) != nil) {
1381 sources_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1382 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
1386 _assert(pipe(fds) != -1);
1390 detachNewThreadSelector:@selector(_readStatus:)
1392 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1395 _assert(pipe(fds) != -1);
1396 _assert(dup2(fds[0], 0) != -1);
1397 _assert(close(fds[0]) != -1);
1399 input_ = fdopen(fds[1], "a");
1401 _assert(pipe(fds) != -1);
1402 _assert(dup2(fds[1], 1) != -1);
1403 _assert(close(fds[1]) != -1);
1406 detachNewThreadSelector:@selector(_readOutput:)
1408 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1413 - (pkgCacheFile &) cache {
1417 - (pkgDepCache::Policy *) policy {
1421 - (pkgRecords *) records {
1425 - (pkgProblemResolver *) resolver {
1429 - (pkgAcquire &) fetcher {
1433 - (NSArray *) packages {
1437 - (void) reloadData {
1456 if (!cache_.Open(progress_, true)) {
1458 if (!_error->PopMessage(error))
1461 fprintf(stderr, "cache_.Open():[%s]\n", error.c_str());
1463 if (error == "dpkg was interrupted, you must manually run 'dpkg --configure -a' to correct the problem. ")
1464 [delegate_ repairWithSelector:@selector(configure)];
1465 else if (error == "The package lists or status file could not be parsed or opened.")
1466 [delegate_ repairWithSelector:@selector(update)];
1467 else if (error == "Could not get lock /var/lib/dpkg/lock - open (35 Resource temporarily unavailable)")
1468 [delegate_ repairWithSelector:@selector(unlock)];
1469 //else if (error == "The list of sources could not be read.")
1470 else _assert(false);
1475 now_ = [[NSDate date] retain];
1477 policy_ = new pkgDepCache::Policy();
1478 records_ = new pkgRecords(cache_);
1479 resolver_ = new pkgProblemResolver(cache_);
1480 fetcher_ = new pkgAcquire(&status_);
1483 list_ = new pkgSourceList();
1484 _assert(list_->ReadMainList());
1486 [sources_ removeAllObjects];
1487 for (pkgSourceList::const_iterator source = list_->begin(); source != list_->end(); ++source) {
1488 std::vector<pkgIndexFile *> *indices = (*source)->GetIndexFiles();
1489 for (std::vector<pkgIndexFile *>::const_iterator index = indices->begin(); index != indices->end(); ++index)
1491 setObject:[[[Source alloc] initWithMetaIndex:*source] autorelease]
1492 forKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(*index)]
1496 [packages_ removeAllObjects];
1497 for (pkgCache::PkgIterator iterator = cache_->PkgBegin(); !iterator.end(); ++iterator)
1498 if (Package *package = [Package packageWithIterator:iterator database:self])
1499 [packages_ addObject:package];
1501 [packages_ sortUsingSelector:@selector(compareByName:)];
1505 system("killall dpkg");
1508 - (void) configure {
1509 NSString *dpkg = [NSString stringWithFormat:@"dpkg --configure -a --status-fd %u", statusfd_];
1510 system([dpkg UTF8String]);
1514 pkgRecords records(cache_);
1516 lock_ = new FileFd();
1517 lock_->Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1518 _assert(!_error->PendingError());
1521 // XXX: explain this with an error message
1522 _assert(list.ReadMainList());
1524 manager_ = (_system->CreatePM(cache_));
1525 _assert(manager_->GetArchives(fetcher_, &list, &records));
1526 _assert(!_error->PendingError());
1530 NSMutableArray *before = [NSMutableArray arrayWithCapacity:16]; {
1532 _assert(list.ReadMainList());
1533 for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source)
1534 [before addObject:[NSString stringWithUTF8String:(*source)->GetURI().c_str()]];
1537 if (fetcher_->Run(PulseInterval_) != pkgAcquire::Continue)
1541 pkgPackageManager::OrderResult result = manager_->DoInstall(statusfd_);
1543 if (result == pkgPackageManager::Failed)
1545 if (_error->PendingError())
1547 if (result != pkgPackageManager::Completed)
1550 NSMutableArray *after = [NSMutableArray arrayWithCapacity:16]; {
1552 _assert(list.ReadMainList());
1553 for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source)
1554 [after addObject:[NSString stringWithUTF8String:(*source)->GetURI().c_str()]];
1557 if (![before isEqualToArray:after])
1562 _assert(cache_->DelCount() == 0 && cache_->InstCount() == 0);
1563 _assert(pkgApplyStatus(cache_));
1565 if (cache_->BrokenCount() != 0) {
1566 _assert(pkgFixBroken(cache_));
1567 _assert(cache_->BrokenCount() == 0);
1568 _assert(pkgMinimizeUpgrade(cache_));
1571 _assert(pkgDistUpgrade(cache_));
1575 [self updateWithStatus:status_];
1578 - (void) updateWithStatus:(Status &)status {
1580 _assert(list.ReadMainList());
1583 lock.Fd(GetLock(_config->FindDir("Dir::State::Lists") + "lock"));
1584 _assert(!_error->PendingError());
1586 pkgAcquire fetcher(&status);
1587 _assert(list.GetIndexes(&fetcher));
1589 if (fetcher.Run(PulseInterval_) != pkgAcquire::Failed) {
1590 bool failed = false;
1591 for (pkgAcquire::ItemIterator item = fetcher.ItemsBegin(); item != fetcher.ItemsEnd(); item++)
1592 if ((*item)->Status != pkgAcquire::Item::StatDone) {
1593 (*item)->Finished();
1597 if (!failed && _config->FindB("APT::Get::List-Cleanup", true) == true) {
1598 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists")));
1599 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/"));
1602 [Metadata_ setObject:[NSDate date] forKey:@"LastUpdate"];
1607 - (void) setDelegate:(id)delegate {
1608 delegate_ = delegate;
1609 status_.setDelegate(delegate);
1610 progress_.setDelegate(delegate);
1613 - (Source *) getSource:(const pkgCache::PkgFileIterator &)file {
1614 pkgIndexFile *index(NULL);
1615 list_->FindIndex(file, index);
1616 return [sources_ objectForKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(index)]];
1622 /* Confirmation View {{{ */
1623 void AddTextView(NSMutableDictionary *fields, NSMutableArray *packages, NSString *key) {
1624 if ([packages count] == 0)
1627 UITextView *text = GetTextView([packages count] == 0 ? @"n/a" : [packages componentsJoinedByString:@", "], 120, false);
1628 [fields setObject:text forKey:key];
1630 CGColor blue(space_, 0, 0, 0.4, 1);
1631 [text setTextColor:blue];
1634 @protocol ConfirmationViewDelegate
1639 @interface ConfirmationView : UIView {
1640 Database *database_;
1642 UITransitionView *transition_;
1644 UINavigationBar *navbar_;
1645 UIPreferencesTable *table_;
1646 NSMutableDictionary *fields_;
1647 UIAlertSheet *essential_;
1652 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate;
1656 @implementation ConfirmationView
1659 [navbar_ setDelegate:nil];
1660 [transition_ setDelegate:nil];
1661 [table_ setDataSource:nil];
1663 [transition_ release];
1668 if (essential_ != nil)
1669 [essential_ release];
1674 [transition_ transition:7 toView:nil];
1678 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
1679 if (from != nil && to == nil)
1680 [self removeFromSuperview];
1683 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
1686 if (essential_ != nil)
1687 [essential_ popupAlertAnimated:YES];
1689 [delegate_ confirm];
1698 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
1699 [essential_ dismiss];
1703 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
1707 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
1709 case 0: return @"Statistics";
1710 case 1: return @"Modifications";
1712 default: _assert(false);
1716 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
1719 case 1: return [fields_ count];
1721 default: _assert(false);
1725 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
1726 if (group != 1 || row == -1)
1729 _assert(size_t(row) < [fields_ count]);
1730 return [[[fields_ allValues] objectAtIndex:row] visibleTextRect].size.height + TextViewOffset_;
1734 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
1735 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
1736 [cell setShowSelection:NO];
1739 case 0: switch (row) {
1741 [cell setTitle:@"Downloading"];
1742 [cell setValue:SizeString([database_ fetcher].FetchNeeded())];
1746 [cell setTitle:@"Resuming At"];
1747 [cell setValue:SizeString([database_ fetcher].PartialPresent())];
1751 double size([database_ cache]->UsrSize());
1754 [cell setTitle:@"Disk Freeing"];
1755 [cell setValue:SizeString(-size)];
1757 [cell setTitle:@"Disk Using"];
1758 [cell setValue:SizeString(size)];
1762 default: _assert(false);
1766 _assert(size_t(row) < [fields_ count]);
1767 [cell setTitle:[[fields_ allKeys] objectAtIndex:row]];
1768 [cell addSubview:[[fields_ allValues] objectAtIndex:row]];
1771 default: _assert(false);
1777 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate {
1778 if ((self = [super initWithFrame:[view bounds]]) != nil) {
1779 database_ = database;
1780 delegate_ = delegate;
1782 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
1783 [self addSubview:transition_];
1785 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
1787 CGSize navsize = [UINavigationBar defaultSize];
1788 CGRect navrect = {{0, 0}, navsize};
1789 CGRect bounds = [overlay_ bounds];
1791 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
1792 [navbar_ setBarStyle:1];
1793 [navbar_ setDelegate:self];
1795 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Confirm"] autorelease];
1796 [navbar_ pushNavigationItem:navitem];
1797 [navbar_ showButtonsWithLeftTitle:@"Cancel" rightTitle:@"Confirm"];
1799 fields_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1801 NSMutableArray *installing = [NSMutableArray arrayWithCapacity:16];
1802 NSMutableArray *reinstalling = [NSMutableArray arrayWithCapacity:16];
1803 NSMutableArray *upgrading = [NSMutableArray arrayWithCapacity:16];
1804 NSMutableArray *downgrading = [NSMutableArray arrayWithCapacity:16];
1805 NSMutableArray *removing = [NSMutableArray arrayWithCapacity:16];
1809 pkgCacheFile &cache([database_ cache]);
1810 NSArray *packages = [database_ packages];
1811 for (size_t i(0), e = [packages count]; i != e; ++i) {
1812 Package *package = [packages objectAtIndex:i];
1813 pkgCache::PkgIterator iterator = [package iterator];
1814 pkgDepCache::StateCache &state(cache[iterator]);
1816 NSString *name([package name]);
1818 if (state.NewInstall())
1819 [installing addObject:name];
1820 else if (!state.Delete() && (state.iFlags & pkgDepCache::ReInstall) == pkgDepCache::ReInstall)
1821 [reinstalling addObject:name];
1822 else if (state.Upgrade())
1823 [upgrading addObject:name];
1824 else if (state.Downgrade())
1825 [downgrading addObject:name];
1826 else if (state.Delete()) {
1827 if ([package essential])
1829 [removing addObject:name];
1836 essential_ = [[UIAlertSheet alloc]
1837 initWithTitle:@"Unable to Comply"
1838 buttons:[NSArray arrayWithObjects:@"Okay", nil]
1839 defaultButtonIndex:0
1844 [essential_ setBodyText:@"One or more of the packages you are about to remove are marked 'Essential' and cannot be removed by Cydia. Please use apt-get."];
1847 AddTextView(fields_, installing, @"Installing");
1848 AddTextView(fields_, reinstalling, @"Reinstalling");
1849 AddTextView(fields_, upgrading, @"Upgrading");
1850 AddTextView(fields_, downgrading, @"Downgrading");
1851 AddTextView(fields_, removing, @"Removing");
1853 table_ = [[UIPreferencesTable alloc] initWithFrame:CGRectMake(
1854 0, navsize.height, bounds.size.width, bounds.size.height - navsize.height
1857 [table_ setReusesTableCells:YES];
1858 [table_ setDataSource:self];
1859 [table_ reloadData];
1861 [overlay_ addSubview:navbar_];
1862 [overlay_ addSubview:table_];
1864 [view addSubview:self];
1866 [transition_ setDelegate:self];
1868 UIView *blank = [[[UIView alloc] initWithFrame:[transition_ bounds]] autorelease];
1869 [transition_ transition:0 toView:blank];
1870 [transition_ transition:3 toView:overlay_];
1877 /* Progress Data {{{ */
1878 @interface ProgressData : NSObject {
1884 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object;
1891 @implementation ProgressData
1893 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object {
1894 if ((self = [super init]) != nil) {
1895 selector_ = selector;
1915 /* Progress View {{{ */
1916 Pcre conffile_r("^'(.*)' '(.*)' ([01]) ([01])$");
1918 @interface ProgressView : UIView <
1919 ConfigurationDelegate,
1922 _transient Database *database_;
1924 UIView *background_;
1925 UITransitionView *transition_;
1927 UINavigationBar *navbar_;
1928 UIProgressBar *progress_;
1929 UITextView *output_;
1930 UITextLabel *status_;
1934 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
1936 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database delegate:(id)delegate;
1937 - (void) setContentView:(UIView *)view;
1940 - (void) _retachThread;
1941 - (void) _detachNewThreadData:(ProgressData *)data;
1942 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title;
1946 @protocol ProgressViewDelegate
1947 - (void) progressViewIsComplete:(ProgressView *)sender;
1950 @implementation ProgressView
1953 [transition_ setDelegate:nil];
1954 [navbar_ setDelegate:nil];
1957 if (background_ != nil)
1958 [background_ release];
1959 [transition_ release];
1962 [progress_ release];
1968 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
1969 if (bootstrap_ && from == overlay_ && to == view_)
1973 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database delegate:(id)delegate {
1974 if ((self = [super initWithFrame:frame]) != nil) {
1975 database_ = database;
1976 delegate_ = delegate;
1978 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
1979 [transition_ setDelegate:self];
1981 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
1984 [overlay_ setBackgroundColor:Black_];
1986 background_ = [[UIView alloc] initWithFrame:[self bounds]];
1987 [background_ setBackgroundColor:Black_];
1988 [self addSubview:background_];
1991 [self addSubview:transition_];
1993 CGSize navsize = [UINavigationBar defaultSize];
1994 CGRect navrect = {{0, 0}, navsize};
1996 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
1997 [overlay_ addSubview:navbar_];
1999 [navbar_ setBarStyle:1];
2000 [navbar_ setDelegate:self];
2002 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:nil] autorelease];
2003 [navbar_ pushNavigationItem:navitem];
2005 CGRect bounds = [overlay_ bounds];
2006 CGSize prgsize = [UIProgressBar defaultSize];
2009 (bounds.size.width - prgsize.width) / 2,
2010 bounds.size.height - prgsize.height - 20
2013 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
2014 [overlay_ addSubview:progress_];
2016 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(
2018 bounds.size.height - prgsize.height - 50,
2019 bounds.size.width - 20,
2023 [status_ setColor:White_];
2024 [status_ setBackgroundColor:Clear_];
2026 [status_ setCentersHorizontally:YES];
2027 //[status_ setFont:font];
2029 output_ = [[UITextView alloc] initWithFrame:CGRectMake(
2031 navrect.size.height + 20,
2032 bounds.size.width - 20,
2033 bounds.size.height - navsize.height - 62 - navrect.size.height
2036 //[output_ setTextFont:@"Courier New"];
2037 [output_ setTextSize:12];
2039 [output_ setTextColor:White_];
2040 [output_ setBackgroundColor:Clear_];
2042 [output_ setMarginTop:0];
2043 [output_ setAllowsRubberBanding:YES];
2045 [overlay_ addSubview:output_];
2046 [overlay_ addSubview:status_];
2048 [progress_ setStyle:0];
2052 - (void) setContentView:(UIView *)view {
2053 view_ = [view retain];
2056 - (void) resetView {
2057 [transition_ transition:6 toView:view_];
2060 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
2061 NSString *context = [sheet context];
2062 if ([context isEqualToString:@"conffile"]) {
2063 FILE *input = [database_ input];
2067 fprintf(input, "N\n");
2072 fprintf(input, "Y\n");
2076 default: _assert(false);
2083 - (void) _retachThread {
2084 [delegate_ progressViewIsComplete:self];
2088 - (void) _detachNewThreadData:(ProgressData *)data {
2089 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
2091 [[data target] performSelector:[data selector] withObject:[data object]];
2094 [self performSelectorOnMainThread:@selector(_retachThread) withObject:nil waitUntilDone:YES];
2099 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title {
2100 UINavigationItem *item = [navbar_ topItem];
2101 [item setTitle:title];
2103 [status_ setText:nil];
2104 [output_ setText:@""];
2105 [progress_ setProgress:0];
2107 [transition_ transition:6 toView:overlay_];
2110 detachNewThreadSelector:@selector(_detachNewThreadData:)
2112 withObject:[[ProgressData alloc]
2113 initWithSelector:selector
2120 - (void) repairWithSelector:(SEL)selector {
2122 detachNewThreadSelector:selector
2125 title:@"Repairing..."
2129 - (void) setConfigurationData:(NSString *)data {
2131 performSelectorOnMainThread:@selector(_setConfigurationData:)
2137 - (void) setProgressError:(NSString *)error {
2139 performSelectorOnMainThread:@selector(_setProgressError:)
2145 - (void) setProgressTitle:(NSString *)title {
2147 performSelectorOnMainThread:@selector(_setProgressTitle:)
2153 - (void) setProgressPercent:(float)percent {
2155 performSelectorOnMainThread:@selector(_setProgressPercent:)
2156 withObject:[NSNumber numberWithFloat:percent]
2161 - (void) addProgressOutput:(NSString *)output {
2163 performSelectorOnMainThread:@selector(_addProgressOutput:)
2169 - (void) _setConfigurationData:(NSString *)data {
2170 _assert(conffile_r(data));
2172 NSString *ofile = conffile_r[1];
2173 //NSString *nfile = conffile_r[2];
2175 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
2176 initWithTitle:@"Configuration Upgrade"
2177 buttons:[NSArray arrayWithObjects:
2178 @"Keep My Old Copy",
2179 @"Accept The New Copy",
2180 // XXX: @"See What Changed",
2182 defaultButtonIndex:0
2187 [sheet setBodyText:[NSString stringWithFormat:
2188 @"The following file has been changed by both the package maintainer and by you (or for you by a script).\n\n%@"
2191 [sheet popupAlertAnimated:YES];
2194 - (void) _setProgressError:(NSString *)error {
2195 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
2196 initWithTitle:@"Package Error"
2197 buttons:[NSArray arrayWithObjects:@"Okay", nil]
2198 defaultButtonIndex:0
2203 [sheet setBodyText:error];
2204 [sheet popupAlertAnimated:YES];
2207 - (void) _setProgressTitle:(NSString *)title {
2208 [status_ setText:[title stringByAppendingString:@"..."]];
2211 - (void) _setProgressPercent:(NSNumber *)percent {
2212 [progress_ setProgress:[percent floatValue]];
2215 - (void) _addProgressOutput:(NSString *)output {
2216 [output_ setText:[NSString stringWithFormat:@"%@\n%@", [output_ text], output]];
2217 CGSize size = [output_ contentSize];
2218 CGRect rect = {{0, size.height}, {size.width, 0}};
2219 [output_ scrollRectToVisible:rect animated:YES];
2225 /* Package Cell {{{ */
2226 @interface PackageCell : UITableCell {
2229 UITextLabel *description_;
2230 UITextLabel *source_;
2231 UIImageView *trusted_;
2234 - (PackageCell *) init;
2235 - (void) setPackage:(Package *)package;
2237 - (void) _setSelected:(float)fraction;
2238 - (void) setSelected:(BOOL)selected;
2239 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
2240 - (void) _setSelectionFadeFraction:(float)fraction;
2244 @implementation PackageCell
2249 [description_ release];
2255 - (PackageCell *) init {
2256 if ((self = [super init]) != nil) {
2257 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 20);
2258 GSFontRef large = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 12);
2259 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 14);
2261 icon_ = [[UIImageView alloc] initWithFrame:CGRectMake(10, 10, 30, 30)];
2263 name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 8, 240, 25)];
2264 [name_ setBackgroundColor:Clear_];
2265 [name_ setFont:bold];
2267 source_ = [[UITextLabel alloc] initWithFrame:CGRectMake(58, 28, 225, 20)];
2268 [source_ setBackgroundColor:Clear_];
2269 [source_ setFont:large];
2271 description_ = [[UITextLabel alloc] initWithFrame:CGRectMake(12, 46, 280, 20)];
2272 [description_ setBackgroundColor:Clear_];
2273 [description_ setFont:small];
2275 trusted_ = [[UIImageView alloc] initWithFrame:CGRectMake(30, 30, 16, 16)];
2276 [trusted_ setImage:[UIImage applicationImageNamed:@"trusted.png"]];
2278 [self addSubview:icon_];
2279 [self addSubview:name_];
2280 [self addSubview:description_];
2281 [self addSubview:source_];
2289 - (void) setPackage:(Package *)package {
2290 Source *source = [package source];
2292 UIImage *image = nil;
2293 if (NSString *icon = [package icon])
2294 image = [UIImage imageAtPath:[icon substringFromIndex:6]];
2295 if (image == nil) if (NSString *icon = [source defaultIcon])
2296 image = [UIImage imageAtPath:[icon substringFromIndex:6]];
2298 image = [UIImage applicationImageNamed:@"unknown.png"];
2299 [icon_ setImage:image];
2302 CGSize size = [image size];
2303 float scale = 30 / std::max(size.width, size.height);
2304 [icon_ zoomToScale:scale];
2307 [icon_ setFrame:CGRectMake(10, 10, 30, 30)];
2309 [name_ setText:[package name]];
2310 [description_ setText:[package tagline]];
2312 NSString *label = nil;
2313 bool trusted = false;
2315 if (source != nil) {
2316 label = [source label];
2317 trusted = [source trusted];
2318 } else if ([[package id] isEqualToString:@"firmware"])
2322 label = @"Unknown/Local";
2324 NSString *from = [NSString stringWithFormat:@"from %@", label];
2326 NSString *section = Simplify([package section]);
2327 if (section != nil && ![section isEqualToString:label])
2328 from = [from stringByAppendingString:[NSString stringWithFormat:@" (%@)", section]];
2330 [source_ setText:from];
2333 [self addSubview:trusted_];
2335 [trusted_ removeFromSuperview];
2338 - (void) _setSelected:(float)fraction {
2339 CGColor black(space_,
2340 Interpolate(0.0, 1.0, fraction),
2341 Interpolate(0.0, 1.0, fraction),
2342 Interpolate(0.0, 1.0, fraction),
2345 CGColor gray(space_,
2346 Interpolate(0.4, 1.0, fraction),
2347 Interpolate(0.4, 1.0, fraction),
2348 Interpolate(0.4, 1.0, fraction),
2351 [name_ setColor:black];
2352 [description_ setColor:gray];
2353 [source_ setColor:black];
2356 - (void) setSelected:(BOOL)selected {
2357 [self _setSelected:(selected ? 1.0 : 0.0)];
2358 [super setSelected:selected];
2361 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
2363 [self _setSelected:(selected ? 1.0 : 0.0)];
2364 [super setSelected:selected withFade:fade];
2367 - (void) _setSelectionFadeFraction:(float)fraction {
2368 [self _setSelected:fraction];
2369 [super _setSelectionFadeFraction:fraction];
2374 /* Section Cell {{{ */
2375 @interface SectionCell : UITableCell {
2377 UITextLabel *count_;
2381 - (void) setSection:(Section *)section;
2383 - (void) _setSelected:(float)fraction;
2384 - (void) setSelected:(BOOL)selected;
2385 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
2386 - (void) _setSelectionFadeFraction:(float)fraction;
2390 @implementation SectionCell
2399 if ((self = [super init]) != nil) {
2400 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22);
2401 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 12);
2403 name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 9, 250, 25)];
2404 [name_ setBackgroundColor:Clear_];
2405 [name_ setFont:bold];
2407 count_ = [[UITextLabel alloc] initWithFrame:CGRectMake(11, 7, 29, 32)];
2408 [count_ setCentersHorizontally:YES];
2409 [count_ setBackgroundColor:Clear_];
2410 [count_ setFont:small];
2411 [count_ setColor:White_];
2413 UIImageView *folder = [[[UIImageView alloc] initWithFrame:CGRectMake(8, 7, 32, 32)] autorelease];
2414 [folder setImage:[UIImage applicationImageNamed:@"folder.png"]];
2416 [self addSubview:folder];
2417 [self addSubview:name_];
2418 [self addSubview:count_];
2420 [self _setSelected:0];
2427 - (void) setSection:(Section *)section {
2428 if (section == nil) {
2429 [name_ setText:@"All Packages"];
2430 [count_ setText:nil];
2432 NSString *name = [section name];
2433 [name_ setText:(name == nil ? @"(No Section)" : name)];
2434 [count_ setText:[NSString stringWithFormat:@"%d", [section count]]];
2438 - (void) _setSelected:(float)fraction {
2439 CGColor black(space_,
2440 Interpolate(0.0, 1.0, fraction),
2441 Interpolate(0.0, 1.0, fraction),
2442 Interpolate(0.0, 1.0, fraction),
2445 [name_ setColor:black];
2448 - (void) setSelected:(BOOL)selected {
2449 [self _setSelected:(selected ? 1.0 : 0.0)];
2450 [super setSelected:selected];
2453 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
2455 [self _setSelected:(selected ? 1.0 : 0.0)];
2456 [super setSelected:selected withFade:fade];
2459 - (void) _setSelectionFadeFraction:(float)fraction {
2460 [self _setSelected:fraction];
2461 [super _setSelectionFadeFraction:fraction];
2467 /* File Table {{{ */
2468 @interface FileTable : RVPage {
2469 _transient Database *database_;
2472 NSMutableArray *files_;
2476 - (id) initWithBook:(RVBook *)book database:(Database *)database;
2477 - (void) setPackage:(Package *)package;
2481 @implementation FileTable
2484 if (package_ != nil)
2493 - (int) numberOfRowsInTable:(UITable *)table {
2494 return files_ == nil ? 0 : [files_ count];
2497 - (float) table:(UITable *)table heightForRow:(int)row {
2501 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2502 if (reusing == nil) {
2503 reusing = [[[UIImageAndTextTableCell alloc] init] autorelease];
2504 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
2505 [[(UIImageAndTextTableCell *)reusing titleTextLabel] setFont:font];
2508 [(UIImageAndTextTableCell *)reusing setTitle:[files_ objectAtIndex:row]];
2512 - (BOOL) canSelectRow:(int)row {
2516 - (id) initWithBook:(RVBook *)book database:(Database *)database {
2517 if ((self = [super initWithBook:book]) != nil) {
2518 database_ = database;
2520 files_ = [[NSMutableArray arrayWithCapacity:32] retain];
2522 list_ = [[UITable alloc] initWithFrame:[self bounds]];
2523 [self addSubview:list_];
2525 UITableColumn *column = [[[UITableColumn alloc]
2526 initWithTitle:@"Name"
2528 width:[self frame].size.width
2531 [list_ setDataSource:self];
2532 [list_ setSeparatorStyle:1];
2533 [list_ addTableColumn:column];
2534 [list_ setDelegate:self];
2535 [list_ setReusesTableCells:YES];
2539 - (void) setPackage:(Package *)package {
2540 if (package_ != nil) {
2541 [package_ autorelease];
2550 [files_ removeAllObjects];
2552 if (package != nil) {
2553 package_ = [package retain];
2554 name_ = [[package id] retain];
2556 NSString *list = [NSString
2557 stringWithContentsOfFile:[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.list", name_]
2558 encoding:kCFStringEncodingUTF8
2563 [files_ addObjectsFromArray:[list componentsSeparatedByString:@"\n"]];
2564 [files_ removeLastObject];
2565 [files_ removeObjectAtIndex:0];
2566 [files_ sortUsingSelector:@selector(compareByPath:)];
2568 NSMutableArray *stack = [NSMutableArray arrayWithCapacity:8];
2569 [stack addObject:@"/"];
2571 for (int i(0), e([files_ count]); i != e; ++i) {
2572 NSString *file = [files_ objectAtIndex:i];
2573 while (![file hasPrefix:[stack lastObject]])
2574 [stack removeLastObject];
2575 NSString *directory = [stack lastObject];
2576 [stack addObject:[file stringByAppendingString:@"/"]];
2577 [files_ replaceObjectAtIndex:i withObject:[NSString stringWithFormat:@"%*s%@",
2578 ([stack count] - 2) * 3, "",
2579 [file substringFromIndex:[directory length]]
2588 - (void) resetViewAnimated:(BOOL)animated {
2589 [list_ resetViewAnimated:animated];
2592 - (void) reloadData {
2593 [self setPackage:[database_ packageWithName:name_]];
2594 [self reloadButtons];
2597 - (NSString *) title {
2598 return @"Installed Files";
2601 - (NSString *) backButtonTitle {
2607 /* Package View {{{ */
2608 @protocol PackageViewDelegate
2609 - (void) performPackage:(Package *)package;
2612 @interface PackageView : RVPage {
2613 _transient Database *database_;
2614 UIPreferencesTable *table_;
2617 UITextView *description_;
2618 NSMutableArray *buttons_;
2621 - (id) initWithBook:(RVBook *)book database:(Database *)database;
2622 - (void) setPackage:(Package *)package;
2626 @implementation PackageView
2629 [table_ setDataSource:nil];
2630 [table_ setDelegate:nil];
2632 if (package_ != nil)
2636 if (description_ != nil)
2637 [description_ release];
2643 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
2645 if ([package_ installed] != nil)
2647 if ([package_ source] != nil)
2652 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
2655 else if ([package_ installed] != nil && group-- == 0)
2656 return @"Installed Package";
2657 else if (group-- == 0)
2658 return @"Package Details";
2659 else if ([package_ source] != nil && group-- == 0)
2660 return @"Source Information";
2661 else _assert(false);
2664 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
2665 if (description_ == nil || group != 0 || row != 1)
2668 return [description_ visibleTextRect].size.height + TextViewOffset_;
2671 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
2674 if (description_ != nil)
2676 if ([package_ website] != nil)
2678 if ([[package_ source] trusted])
2681 } else if ([package_ installed] != nil && group-- == 0)
2683 else if (group-- == 0) {
2685 if ([package_ size] != 0)
2687 if ([package_ maintainer] != nil)
2689 if ([package_ relationships] != nil)
2692 } else if ([package_ source] != nil && group-- == 0) {
2693 Source *source = [package_ source];
2694 NSString *description = [source description];
2696 if (description != nil && ![description isEqualToString:[source label]])
2698 if ([source origin] != nil)
2701 } else _assert(false);
2704 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
2705 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
2706 [cell setShowSelection:NO];
2710 [cell setTitle:[package_ name]];
2711 [cell setValue:[package_ latest]];
2712 } else if (description_ != nil && row-- == 0) {
2713 [cell addSubview:description_];
2714 } else if ([package_ website] != nil && row-- == 0) {
2715 [cell setTitle:@"More Information"];
2716 [cell setShowDisclosure:YES];
2717 [cell setShowSelection:YES];
2718 } else if ([[package_ source] trusted] && row-- == 0) {
2719 [cell setIcon:[UIImage applicationImageNamed:@"trusted.png"]];
2720 [cell setValue:@"This package has been signed."];
2721 } else _assert(false);
2722 } else if ([package_ installed] != nil && group-- == 0) {
2724 [cell setTitle:@"Version"];
2725 NSString *installed([package_ installed]);
2726 [cell setValue:(installed == nil ? @"n/a" : installed)];
2727 } else if (row-- == 0) {
2728 [cell setTitle:@"Filesystem Content"];
2729 [cell setShowDisclosure:YES];
2730 [cell setShowSelection:YES];
2731 } else _assert(false);
2732 } else if (group-- == 0) {
2734 [cell setTitle:@"Identifier"];
2735 [cell setValue:[package_ id]];
2736 } else if (row-- == 0) {
2737 [cell setTitle:@"Section"];
2738 NSString *section([package_ section]);
2739 [cell setValue:(section == nil ? @"n/a" : section)];
2740 } else if ([package_ size] != 0 && row-- == 0) {
2741 [cell setTitle:@"Expanded Size"];
2742 [cell setValue:SizeString([package_ size])];
2743 } else if ([package_ maintainer] != nil && row-- == 0) {
2744 [cell setTitle:@"Maintainer"];
2745 [cell setValue:[[package_ maintainer] name]];
2746 [cell setShowDisclosure:YES];
2747 [cell setShowSelection:YES];
2748 } else if ([package_ relationships] != nil && row-- == 0) {
2749 [cell setTitle:@"Package Relationships"];
2750 [cell setShowDisclosure:YES];
2751 [cell setShowSelection:YES];
2752 } else _assert(false);
2753 } else if ([package_ source] != nil && group-- == 0) {
2754 Source *source = [package_ source];
2755 NSString *description = [source description];
2758 NSString *label = [source label];
2760 label = [source uri];
2761 [cell setTitle:label];
2762 [cell setValue:[source version]];
2763 } else if (description != nil && ![description isEqualToString:[source label]] && row-- == 0) {
2764 [cell setValue:description];
2765 } else if ([source origin] != nil && row-- == 0) {
2766 [cell setTitle:@"Origin"];
2767 [cell setValue:[source origin]];
2768 } else _assert(false);
2769 } else _assert(false);
2774 - (BOOL) canSelectRow:(int)row {
2778 - (void) tableRowSelected:(NSNotification *)notification {
2779 int row = [table_ selectedRow];
2780 NSString *website = [package_ website];
2781 BOOL trusted = [[package_ source] trusted];
2782 NSString *installed = [package_ installed];
2785 + (website == nil ? 0 : 1)
2787 + (installed == nil ? 0 : 3)
2789 [delegate_ openURL:[NSURL URLWithString:[NSString stringWithFormat:@"mailto:%@?subject=%@",
2790 [[package_ maintainer] email],
2791 [[NSString stringWithFormat:@"regarding apt package \"%@\"", [package_ name]] stringByAddingPercentEscapes]
2793 else if (installed && row == 5
2794 + (website == nil ? 0 : 1)
2797 FileTable *files = [[[FileTable alloc] initWithBook:book_ database:database_] autorelease];
2798 [files setDelegate:delegate_];
2799 [files setPackage:package_];
2800 [book_ pushPage:files];
2801 } else if (website != nil && row == 3) {
2802 NSURL *url = [NSURL URLWithString:website];
2803 BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease];
2804 [browser setDelegate:delegate_];
2805 [book_ pushPage:browser];
2806 [browser loadURL:url];
2810 - (void) _clickButtonWithName:(NSString *)name {
2811 if ([name isEqualToString:@"Install"])
2812 [delegate_ installPackage:package_];
2813 else if ([name isEqualToString:@"Reinstall"])
2814 [delegate_ installPackage:package_];
2815 else if ([name isEqualToString:@"Remove"])
2816 [delegate_ removePackage:package_];
2817 else if ([name isEqualToString:@"Upgrade"])
2818 [delegate_ installPackage:package_];
2819 else _assert(false);
2822 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
2823 int count = [buttons_ count];
2824 _assert(count != 0);
2825 _assert(button <= count + 1);
2827 if (count != button - 1)
2828 [self _clickButtonWithName:[buttons_ objectAtIndex:(button - 1)]];
2833 - (void) _rightButtonClicked {
2834 int count = [buttons_ count];
2835 _assert(count != 0);
2838 [self _clickButtonWithName:[buttons_ objectAtIndex:0]];
2840 NSMutableArray *buttons = [NSMutableArray arrayWithCapacity:(count + 1)];
2841 [buttons addObjectsFromArray:buttons_];
2842 [buttons addObject:@"Cancel"];
2844 [delegate_ slideUp:[[[UIAlertSheet alloc]
2845 initWithTitle:@"Manage Package"
2847 defaultButtonIndex:2
2854 - (NSString *) rightButtonTitle {
2855 int count = [buttons_ count];
2856 return count == 0 ? nil : count != 1 ? @"Modify" : [buttons_ objectAtIndex:0];
2859 - (NSString *) title {
2863 - (id) initWithBook:(RVBook *)book database:(Database *)database {
2864 if ((self = [super initWithBook:book]) != nil) {
2865 database_ = database;
2867 table_ = [[UIPreferencesTable alloc] initWithFrame:[self bounds]];
2868 [self addSubview:table_];
2870 [table_ setDataSource:self];
2871 [table_ setDelegate:self];
2873 buttons_ = [[NSMutableArray alloc] initWithCapacity:4];
2877 - (void) setPackage:(Package *)package {
2878 if (package_ != nil) {
2879 [package_ autorelease];
2888 if (description_ != nil) {
2889 [description_ release];
2893 [buttons_ removeAllObjects];
2895 if (package != nil) {
2896 package_ = [package retain];
2897 name_ = [[package id] retain];
2899 NSString *description([package description]);
2900 if (description == nil)
2901 description = [package tagline];
2902 if (description != nil) {
2903 description_ = [GetTextView(description, 12, true) retain];
2904 [description_ setTextColor:Black_];
2907 [table_ reloadData];
2909 if ([package_ source] == nil);
2910 else if ([package_ installed] == nil)
2911 [buttons_ addObject:@"Install"];
2912 else if ([package_ upgradable])
2913 [buttons_ addObject:@"Upgrade"];
2915 [buttons_ addObject:@"Reinstall"];
2916 if ([package_ installed] != nil)
2917 [buttons_ addObject:@"Remove"];
2921 - (void) resetViewAnimated:(BOOL)animated {
2922 [table_ resetViewAnimated:animated];
2925 - (void) reloadData {
2926 [self setPackage:[database_ packageWithName:name_]];
2927 [self reloadButtons];
2932 /* Package Table {{{ */
2933 @interface PackageTable : RVPage {
2934 _transient Database *database_;
2938 NSMutableArray *packages_;
2939 NSMutableArray *sections_;
2940 UISectionList *list_;
2943 - (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object;
2945 - (void) setDelegate:(id)delegate;
2946 - (void) setObject:(id)object;
2948 - (void) reloadData;
2949 - (void) resetCursor;
2951 - (UISectionList *) list;
2953 - (void) setShouldHideHeaderInShortLists:(BOOL)hide;
2957 @implementation PackageTable
2960 [list_ setDataSource:nil];
2965 [packages_ release];
2966 [sections_ release];
2971 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
2972 return [sections_ count];
2975 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
2976 return [[sections_ objectAtIndex:section] name];
2979 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
2980 return [[sections_ objectAtIndex:section] row];
2983 - (int) numberOfRowsInTable:(UITable *)table {
2984 return [packages_ count];
2987 - (float) table:(UITable *)table heightForRow:(int)row {
2991 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2993 reusing = [[[PackageCell alloc] init] autorelease];
2994 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
2998 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
3002 - (void) tableRowSelected:(NSNotification *)notification {
3003 int row = [[notification object] selectedRow];
3007 Package *package = [packages_ objectAtIndex:row];
3008 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
3009 [view setDelegate:delegate_];
3010 [view setPackage:package];
3011 [book_ pushPage:view];
3014 - (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object {
3015 if ((self = [super initWithBook:book]) != nil) {
3016 database_ = database;
3017 title_ = [title retain];
3019 object_ = object == nil ? nil : [object retain];
3021 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
3022 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
3024 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:YES];
3025 [list_ setDataSource:self];
3027 UITableColumn *column = [[[UITableColumn alloc]
3028 initWithTitle:@"Name"
3030 width:[self frame].size.width
3033 UITable *table = [list_ table];
3034 [table setSeparatorStyle:1];
3035 [table addTableColumn:column];
3036 [table setDelegate:self];
3037 [table setReusesTableCells:YES];
3039 [self addSubview:list_];
3044 - (void) setDelegate:(id)delegate {
3045 delegate_ = delegate;
3048 - (void) setObject:(id)object {
3054 object_ = [object retain];
3057 - (void) reloadData {
3058 NSArray *packages = [database_ packages];
3060 [packages_ removeAllObjects];
3061 [sections_ removeAllObjects];
3063 for (size_t i(0); i != [packages count]; ++i) {
3064 Package *package([packages objectAtIndex:i]);
3065 if ([[package performSelector:filter_ withObject:object_] boolValue])
3066 [packages_ addObject:package];
3069 Section *section = nil;
3071 for (size_t offset(0); offset != [packages_ count]; ++offset) {
3072 Package *package = [packages_ objectAtIndex:offset];
3073 NSString *name = [package index];
3075 if (section == nil || ![[section name] isEqualToString:name]) {
3076 section = [[[Section alloc] initWithName:name row:offset] autorelease];
3077 [sections_ addObject:section];
3080 [section addToCount];
3086 - (NSString *) title {
3090 - (void) resetViewAnimated:(BOOL)animated {
3091 [list_ resetViewAnimated:animated];
3094 - (void) resetCursor {
3095 [[list_ table] scrollPointVisibleAtTopLeft:CGPointMake(0, 0) animated:NO];
3098 - (UISectionList *) list {
3102 - (void) setShouldHideHeaderInShortLists:(BOOL)hide {
3103 [list_ setShouldHideHeaderInShortLists:hide];
3109 /* Browser Implementation {{{ */
3110 @implementation BrowserView
3113 WebView *webview = [webview_ webView];
3114 [webview setFrameLoadDelegate:nil];
3115 [webview setResourceLoadDelegate:nil];
3116 [webview setUIDelegate:nil];
3118 [scroller_ setDelegate:nil];
3119 [webview_ setDelegate:nil];
3121 [scroller_ release];
3124 [indicator_ release];
3130 - (void) loadURL:(NSURL *)url cachePolicy:(NSURLRequestCachePolicy)policy {
3131 NSMutableURLRequest *request = [NSMutableURLRequest
3134 timeoutInterval:30.0
3137 [request addValue:[NSString stringWithUTF8String:Firmware_] forHTTPHeaderField:@"X-Firmware"];
3138 [request addValue:[NSString stringWithUTF8String:Machine_] forHTTPHeaderField:@"X-Machine"];
3139 [request addValue:[NSString stringWithUTF8String:SerialNumber_] forHTTPHeaderField:@"X-Serial-Number"];
3141 [self loadRequest:request];
3145 - (void) loadURL:(NSURL *)url {
3146 [self loadURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy];
3149 // XXX: this needs to add the headers
3150 - (NSURLRequest *) _addHeadersToRequest:(NSURLRequest *)request {
3154 - (void) loadRequest:(NSURLRequest *)request {
3155 [webview_ loadRequest:request];
3158 - (void) reloadURL {
3159 NSURL *url = [[[urls_ lastObject] retain] autorelease];
3160 [urls_ removeLastObject];
3161 [self loadURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData];
3164 - (WebView *) webView {
3165 return [webview_ webView];
3168 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame {
3169 [scroller_ setContentSize:frame.size];
3172 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old {
3173 [self view:sender didSetFrame:frame];
3176 - (NSURLRequest *) webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource {
3177 return [self _addHeadersToRequest:request];
3180 - (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request {
3181 if ([[[request URL] scheme] isEqualToString:@"apptapp"])
3183 [self setBackButtonTitle:title_];
3184 BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease];
3185 [browser setDelegate:delegate_];
3186 [book_ pushPage:browser];
3187 [browser loadRequest:[self _addHeadersToRequest:request]];
3188 return [browser webView];
3191 - (void) webView:(WebView *)sender willClickElement:(id)element {
3192 if (![element respondsToSelector:@selector(href)])
3194 NSString *href = [element href];
3197 if ([href hasPrefix:@"apptapp://package/"]) {
3198 NSString *name = [href substringFromIndex:18];
3199 Package *package = [database_ packageWithName:name];
3200 if (package == nil) {
3201 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
3202 initWithTitle:@"Cannot Locate Package"
3203 buttons:[NSArray arrayWithObjects:@"Close", nil]
3204 defaultButtonIndex:0
3209 [sheet setBodyText:[NSString stringWithFormat:
3210 @"The package %@ cannot be found in your current sources. I might recommend installing more sources."
3213 [sheet popupAlertAnimated:YES];
3215 [self setBackButtonTitle:title_];
3216 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
3217 [view setDelegate:delegate_];
3218 [view setPackage:package];
3219 [book_ pushPage:view];
3224 - (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame {
3225 title_ = [title retain];
3226 [self setTitle:title];
3229 - (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame {
3230 if ([frame parentFrame] != nil)
3235 [indicator_ startAnimation];
3236 [self reloadButtons];
3238 if (title_ != nil) {
3243 [self setTitle:@"Loading..."];
3245 WebView *webview = [webview_ webView];
3246 NSString *href = [webview mainFrameURL];
3247 [urls_ addObject:[NSURL URLWithString:href]];
3249 CGRect webrect = [scroller_ frame];
3250 webrect.size.height = 0;
3251 [webview_ setFrame:webrect];
3254 - (void) _finishLoading {
3257 [indicator_ stopAnimation];
3258 [self reloadButtons];
3262 - (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
3263 if ([frame parentFrame] != nil)
3265 [self _finishLoading];
3268 - (void) webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
3269 if ([frame parentFrame] != nil)
3271 [self setTitle:[error localizedDescription]];
3272 [self _finishLoading];
3275 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3276 if ((self = [super initWithBook:book]) != nil) {
3277 database_ = database;
3280 struct CGRect bounds = [self bounds];
3282 UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:bounds] autorelease];
3283 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
3284 [self addSubview:pinstripe];
3286 scroller_ = [[UIScroller alloc] initWithFrame:bounds];
3287 [self addSubview:scroller_];
3289 [scroller_ setScrollingEnabled:YES];
3290 [scroller_ setAdjustForContentSizeChange:YES];
3291 [scroller_ setClipsSubviews:YES];
3292 [scroller_ setAllowsRubberBanding:YES];
3293 [scroller_ setScrollDecelerationFactor:0.99];
3294 [scroller_ setDelegate:self];
3296 CGRect webrect = [scroller_ bounds];
3297 webrect.size.height = 0;
3299 webview_ = [[UIWebView alloc] initWithFrame:webrect];
3300 [scroller_ addSubview:webview_];
3302 [webview_ setTilingEnabled:YES];
3303 [webview_ setTileSize:CGSizeMake(webrect.size.width, 500)];
3304 [webview_ setAutoresizes:YES];
3305 [webview_ setDelegate:self];
3306 //[webview_ setEnabledGestures:2];
3308 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:0];
3309 indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(281, 42, indsize.width, indsize.height)];
3310 [indicator_ setStyle:0];
3312 Package *package([database_ packageWithName:@"cydia"]);
3313 NSString *application = package == nil ? @"Cydia" : [NSString
3314 stringWithFormat:@"Cydia/%@",
3318 WebView *webview = [webview_ webView];
3319 [webview setApplicationNameForUserAgent:application];
3320 [webview setFrameLoadDelegate:self];
3321 [webview setResourceLoadDelegate:self];
3322 [webview setUIDelegate:self];
3324 urls_ = [[NSMutableArray alloc] initWithCapacity:16];
3328 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
3332 - (void) _leftButtonClicked {
3333 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
3334 initWithTitle:@"About Cydia Packager"
3335 buttons:[NSArray arrayWithObjects:@"Close", nil]
3336 defaultButtonIndex:0
3342 @"Copyright (C) 2008\n"
3343 "Jay Freeman (saurik)\n"
3344 "saurik@saurik.com\n"
3345 "http://www.saurik.com/\n"
3348 "http://www.theokorigroup.com/\n"
3350 "College of Creative Studies,\n"
3351 "University of California,\n"
3353 "http://www.ccs.ucsb.edu/"
3356 [sheet popupAlertAnimated:YES];
3359 - (void) _rightButtonClicked {
3364 - (NSString *) leftButtonTitle {
3368 - (NSString *) rightButtonTitle {
3369 return loading_ ? @"" : @"Reload";
3372 - (NSString *) title {
3376 - (NSString *) backButtonTitle {
3380 - (void) setPageActive:(BOOL)active {
3382 [book_ addSubview:indicator_];
3384 [indicator_ removeFromSuperview];
3387 - (void) resetViewAnimated:(BOOL)animated {
3393 @interface CYBook : RVBook <
3396 _transient Database *database_;
3398 UIProgressIndicator *indicator_;
3399 UITextLabel *prompt_;
3400 UIProgressBar *progress_;
3404 - (id) initWithFrame:(CGRect)frame database:(Database *)database;
3410 /* Install View {{{ */
3411 @interface InstallView : RVPage {
3412 _transient Database *database_;
3413 NSMutableArray *packages_;
3414 NSMutableArray *sections_;
3419 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3420 - (void) reloadData;
3424 @implementation InstallView
3427 [list_ setDataSource:nil];
3428 [list_ setDelegate:nil];
3430 [packages_ release];
3431 [sections_ release];
3433 [accessory_ release];
3437 - (int) numberOfRowsInTable:(UITable *)table {
3438 return [sections_ count] + 1;
3441 - (float) table:(UITable *)table heightForRow:(int)row {
3445 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
3447 reusing = [[[SectionCell alloc] init] autorelease];
3448 [(SectionCell *)reusing setSection:(row == 0 ? nil : [sections_ objectAtIndex:(row - 1)])];
3452 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
3456 - (void) tableRowSelected:(NSNotification *)notification {
3457 int row = [[notification object] selectedRow];
3468 title = @"All Packages";
3470 section = [sections_ objectAtIndex:(row - 1)];
3471 name = [section name];
3477 title = @"(No Section)";
3481 PackageTable *table = [[[PackageTable alloc]
3485 filter:@selector(isUninstalledInSection:)
3489 [table setDelegate:delegate_];
3491 [book_ pushPage:table];
3494 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3495 if ((self = [super initWithBook:book]) != nil) {
3496 database_ = database;
3498 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
3499 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
3501 list_ = [[UITable alloc] initWithFrame:[self bounds]];
3502 [self addSubview:list_];
3504 UITableColumn *column = [[[UITableColumn alloc]
3505 initWithTitle:@"Name"
3507 width:[self frame].size.width
3510 [list_ setDataSource:self];
3511 [list_ setSeparatorStyle:1];
3512 [list_ addTableColumn:column];
3513 [list_ setDelegate:self];
3514 [list_ setReusesTableCells:YES];
3520 - (void) reloadData {
3521 NSArray *packages = [database_ packages];
3523 [packages_ removeAllObjects];
3524 [sections_ removeAllObjects];
3526 for (size_t i(0); i != [packages count]; ++i) {
3527 Package *package([packages objectAtIndex:i]);
3528 if ([package valid] && [package installed] == nil)
3529 [packages_ addObject:package];
3532 [packages_ sortUsingSelector:@selector(compareBySection:)];
3534 Section *section = nil;
3535 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
3536 Package *package = [packages_ objectAtIndex:offset];
3537 NSString *name = [package section];
3539 if (section == nil || name != nil && ![[section name] isEqualToString:name]) {
3540 section = [[[Section alloc] initWithName:name row:offset] autorelease];
3541 [sections_ addObject:section];
3544 [section addToCount];
3550 - (void) resetViewAnimated:(BOOL)animated {
3551 [list_ resetViewAnimated:animated];
3554 - (NSString *) title {
3558 - (NSString *) backButtonTitle {
3562 - (UIView *) accessoryView {
3568 /* Changes View {{{ */
3569 @interface ChangesView : RVPage {
3570 _transient Database *database_;
3571 NSMutableArray *packages_;
3572 NSMutableArray *sections_;
3573 UISectionList *list_;
3577 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3578 - (void) reloadData;
3582 @implementation ChangesView
3585 [[list_ table] setDelegate:nil];
3586 [list_ setDataSource:nil];
3588 [packages_ release];
3589 [sections_ release];
3594 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
3595 return [sections_ count];
3598 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
3599 return [[sections_ objectAtIndex:section] name];
3602 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
3603 return [[sections_ objectAtIndex:section] row];
3606 - (int) numberOfRowsInTable:(UITable *)table {
3607 return [packages_ count];
3610 - (float) table:(UITable *)table heightForRow:(int)row {
3614 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
3616 reusing = [[[PackageCell alloc] init] autorelease];
3617 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
3621 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
3625 - (void) tableRowSelected:(NSNotification *)notification {
3626 int row = [[notification object] selectedRow];
3629 Package *package = [packages_ objectAtIndex:row];
3630 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
3631 [view setDelegate:delegate_];
3632 [view setPackage:package];
3633 [book_ pushPage:view];
3636 - (void) _leftButtonClicked {
3637 [(CYBook *)book_ update];
3638 [self reloadButtons];
3641 - (void) _rightButtonClicked {
3642 [delegate_ distUpgrade];
3645 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3646 if ((self = [super initWithBook:book]) != nil) {
3647 database_ = database;
3649 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
3650 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
3652 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:NO];
3653 [self addSubview:list_];
3655 [list_ setShouldHideHeaderInShortLists:NO];
3656 [list_ setDataSource:self];
3657 //[list_ setSectionListStyle:1];
3659 UITableColumn *column = [[[UITableColumn alloc]
3660 initWithTitle:@"Name"
3662 width:[self frame].size.width
3665 UITable *table = [list_ table];
3666 [table setSeparatorStyle:1];
3667 [table addTableColumn:column];
3668 [table setDelegate:self];
3669 [table setReusesTableCells:YES];
3675 - (void) reloadData {
3676 NSArray *packages = [database_ packages];
3678 [packages_ removeAllObjects];
3679 [sections_ removeAllObjects];
3681 for (size_t i(0); i != [packages count]; ++i) {
3682 Package *package([packages objectAtIndex:i]);
3683 if ([package installed] == nil && [package valid] || [package upgradable])
3684 [packages_ addObject:package];
3687 [packages_ sortUsingSelector:@selector(compareForChanges:)];
3689 Section *upgradable = [[[Section alloc] initWithName:@"Available Upgrades" row:0] autorelease];
3690 Section *section = nil;
3693 bool unseens = false;
3695 CFLocaleRef locale = CFLocaleCopyCurrent();
3696 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
3698 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
3699 Package *package = [packages_ objectAtIndex:offset];
3701 if ([package upgradable]) {
3703 [upgradable addToCount];
3706 NSDate *seen = [package seen];
3711 name = [@"n/a ?" retain];
3713 name = (NSString *) CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen);
3716 if (section == nil || ![[section name] isEqualToString:name]) {
3717 section = [[[Section alloc] initWithName:name row:offset] autorelease];
3718 [sections_ addObject:section];
3722 [section addToCount];
3726 CFRelease(formatter);
3730 Section *last = [sections_ lastObject];
3731 size_t count = [last count];
3732 [packages_ removeObjectsInRange:NSMakeRange([packages_ count] - count, count)];
3733 [sections_ removeLastObject];
3737 [sections_ insertObject:upgradable atIndex:0];
3740 [self reloadButtons];
3743 - (void) resetViewAnimated:(BOOL)animated {
3744 [list_ resetViewAnimated:animated];
3747 - (NSString *) leftButtonTitle {
3748 return [(CYBook *)book_ updating] ? nil : @"Refresh";
3751 - (NSString *) rightButtonTitle {
3752 return upgrades_ == 0 ? nil : [NSString stringWithFormat:@"Upgrade All (%u)", upgrades_];
3755 - (NSString *) title {
3761 /* Manage View {{{ */
3762 @interface ManageView : PackageTable {
3765 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3769 @implementation ManageView
3771 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3776 filter:@selector(isInstalledInSection:)
3782 - (NSString *) title {
3783 return @"Installed Packages";
3786 - (NSString *) backButtonTitle {
3787 return @"All Packages";
3792 /* Search View {{{ */
3793 @protocol SearchViewDelegate
3794 - (void) showKeyboard:(BOOL)show;
3797 @interface SearchView : RVPage {
3799 UISearchField *field_;
3800 UITransitionView *transition_;
3801 PackageTable *table_;
3802 UIPreferencesTable *advanced_;
3808 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3809 - (void) reloadData;
3813 @implementation SearchView
3817 [[field_ textTraits] setEditingDelegate:nil];
3819 [field_ setDelegate:nil];
3821 [accessory_ release];
3823 [transition_ release];
3825 [advanced_ release];
3830 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
3834 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
3836 case 0: return @"Advanced Search (Coming Soon!)";
3838 default: _assert(false);
3842 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
3846 default: _assert(false);
3850 - (void) _showKeyboard:(BOOL)show {
3851 CGSize keysize = [UIKeyboard defaultSize];
3852 CGRect keydown = [book_ pageBounds];
3853 CGRect keyup = keydown;
3854 keyup.size.height -= keysize.height - ButtonBarHeight_;
3856 float delay = KeyboardTime_ * ButtonBarHeight_ / keysize.height;
3858 UIFrameAnimation *animation = [[[UIFrameAnimation alloc] initWithTarget:[table_ list]] autorelease];
3859 [animation setSignificantRectFields:8];
3862 [animation setStartFrame:keydown];
3863 [animation setEndFrame:keyup];
3865 [animation setStartFrame:keyup];
3866 [animation setEndFrame:keydown];
3869 UIAnimator *animator = [UIAnimator sharedAnimator];
3872 addAnimations:[NSArray arrayWithObjects:animation, nil]
3873 withDuration:(KeyboardTime_ - delay)
3878 [animator performSelector:@selector(startAnimation:) withObject:animation afterDelay:delay];
3880 [delegate_ showKeyboard:show];
3883 - (void) textFieldDidBecomeFirstResponder:(UITextField *)field {
3884 [self _showKeyboard:YES];
3887 - (void) textFieldDidResignFirstResponder:(UITextField *)field {
3888 [self _showKeyboard:NO];
3891 - (void) keyboardInputChanged:(UIFieldEditor *)editor {
3893 NSString *text([field_ text]);
3894 [field_ setClearButtonStyle:(text == nil || [text length] == 0 ? 0 : 2)];
3900 - (void) textFieldClearButtonPressed:(UITextField *)field {
3904 - (void) keyboardInputShouldDelete:(id)input {
3908 - (BOOL) keyboardInput:(id)input shouldInsertText:(NSString *)text isMarkedText:(int)marked {
3909 if ([text length] != 1 || [text characterAtIndex:0] != '\n') {
3913 [field_ resignFirstResponder];
3918 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3919 if ((self = [super initWithBook:book]) != nil) {
3920 CGRect pageBounds = [book_ pageBounds];
3922 /*UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:pageBounds] autorelease];
3923 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
3924 [self addSubview:pinstripe];*/
3926 transition_ = [[UITransitionView alloc] initWithFrame:pageBounds];
3927 [self addSubview:transition_];
3929 advanced_ = [[UIPreferencesTable alloc] initWithFrame:pageBounds];
3931 [advanced_ setReusesTableCells:YES];
3932 [advanced_ setDataSource:self];
3933 [advanced_ reloadData];
3935 dimmed_ = [[UIView alloc] initWithFrame:pageBounds];
3936 CGColor dimmed(space_, 0, 0, 0, 0.5);
3937 [dimmed_ setBackgroundColor:dimmed];
3939 table_ = [[PackageTable alloc]
3943 filter:@selector(isSearchedForBy:)
3947 [table_ setShouldHideHeaderInShortLists:NO];
3948 [transition_ transition:0 toView:table_];
3950 CGRect cnfrect = {{1, 38}, {17, 18}};
3953 area.origin.x = cnfrect.size.width + 15;
3955 area.size.width = [self bounds].size.width - area.origin.x - 18;
3956 area.size.height = [UISearchField defaultHeight];
3958 field_ = [[UISearchField alloc] initWithFrame:area];
3960 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
3961 [field_ setFont:font];
3964 [field_ setPlaceholder:@"Package Names & Descriptions"];
3965 [field_ setPaddingTop:5];
3966 [field_ setDelegate:self];
3969 UITextTraits *traits = [field_ textTraits];
3970 [traits setEditingDelegate:self];
3971 [traits setReturnKeyType:6];
3972 [traits setAutoCapsType:0];
3973 [traits setAutoCorrectionType:1];
3976 UIPushButton *configure = [[[UIPushButton alloc] initWithFrame:cnfrect] autorelease];
3977 [configure setShowPressFeedback:YES];
3978 [configure setImage:[UIImage applicationImageNamed:@"advanced.png"]];
3979 [configure addTarget:self action:@selector(configurePushed) forEvents:1];
3981 accessory_ = [[UIView alloc] initWithFrame:CGRectMake(0, 6, cnfrect.size.width + area.size.width + 6 * 3, area.size.height + 30)];
3982 [accessory_ addSubview:field_];
3983 [accessory_ addSubview:configure];
3988 LKAnimation *animation = [LKTransition animation];
3989 [animation setType:@"oglFlip"];
3990 [animation setTimingFunction:[LKTimingFunction functionWithName:@"easeInEaseOut"]];
3991 [animation setFillMode:@"extended"];
3992 [animation setTransitionFlags:3];
3993 [animation setDuration:10];
3994 [animation setSpeed:0.35];
3995 [animation setSubtype:(flipped_ ? @"fromLeft" : @"fromRight")];
3996 [[transition_ _layer] addAnimation:animation forKey:0];
3997 [transition_ transition:0 toView:(flipped_ ? (UIView *) table_ : (UIView *) advanced_)];
3998 flipped_ = !flipped_;
4001 - (void) configurePushed {
4002 [field_ resignFirstResponder];
4006 - (void) resetViewAnimated:(BOOL)animated {
4009 [table_ resetViewAnimated:animated];
4012 - (void) reloadData {
4015 [table_ setObject:[field_ text]];
4016 [table_ reloadData];
4017 [table_ resetCursor];
4020 - (UIView *) accessoryView {
4024 - (NSString *) title {
4028 - (NSString *) backButtonTitle {
4032 - (void) setDelegate:(id)delegate {
4033 [table_ setDelegate:delegate];
4034 [super setDelegate:delegate];
4040 @implementation CYBook
4044 [indicator_ release];
4046 [progress_ release];
4050 - (NSString *) getTitleForPage:(RVPage *)page {
4051 return Simplify([super getTitleForPage:page]);
4059 [navbar_ setPrompt:@""];
4060 [navbar_ addSubview:overlay_];
4061 [indicator_ startAnimation];
4062 [prompt_ setText:@"Updating Database..."];
4063 [progress_ setProgress:0];
4068 detachNewThreadSelector:@selector(_update)
4077 [overlay_ removeFromSuperview];
4078 [indicator_ stopAnimation];
4079 [delegate_ reloadData];
4081 [self setPrompt:[NSString stringWithFormat:@"Last Updated: %@", GetLastUpdate()]];
4084 - (id) initWithFrame:(CGRect)frame database:(Database *)database {
4085 if ((self = [super initWithFrame:frame]) != nil) {
4086 database_ = database;
4089 [navbar_ setBarStyle:1];
4091 CGRect ovrrect = [navbar_ bounds];
4092 ovrrect.size.height = [UINavigationBar defaultSizeWithPrompt].height - [UINavigationBar defaultSize].height;
4094 overlay_ = [[UIView alloc] initWithFrame:ovrrect];
4096 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:2];
4097 unsigned indoffset = (ovrrect.size.height - indsize.height) / 2;
4098 CGRect indrect = {{indoffset, indoffset}, indsize};
4100 indicator_ = [[UIProgressIndicator alloc] initWithFrame:indrect];
4101 [indicator_ setStyle:(Advanced_ ? 2 : 3)];
4102 [overlay_ addSubview:indicator_];
4104 CGSize prmsize = {200, indsize.width};
4107 indoffset * 2 + indsize.width,
4108 (ovrrect.size.height - prmsize.height) / 2
4111 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 12);
4113 prompt_ = [[UITextLabel alloc] initWithFrame:prmrect];
4115 [prompt_ setColor:(Advanced_ ? White_ : Black_)];
4116 [prompt_ setBackgroundColor:Clear_];
4117 [prompt_ setFont:font];
4121 [overlay_ addSubview:prompt_];
4123 CGSize prgsize = {75, 100};
4126 ovrrect.size.width - prgsize.width - 10,
4127 (ovrrect.size.height - prgsize.height) / 2
4130 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
4131 [progress_ setStyle:0];
4132 [overlay_ addSubview:progress_];
4137 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
4140 status.setDelegate(self);
4142 [database_ updateWithStatus:status];
4145 performSelectorOnMainThread:@selector(_update_)
4153 - (void) setProgressError:(NSString *)error {
4155 performSelectorOnMainThread:@selector(_setProgressError:)
4161 - (void) setProgressTitle:(NSString *)title {
4163 performSelectorOnMainThread:@selector(_setProgressTitle:)
4169 - (void) setProgressPercent:(float)percent {
4172 - (void) addProgressOutput:(NSString *)output {
4174 performSelectorOnMainThread:@selector(_addProgressOutput:)
4180 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
4184 - (void) _setProgressError:(NSString *)error {
4185 [prompt_ setText:[NSString stringWithFormat:@"Error: %@", error]];
4188 - (void) _setProgressTitle:(NSString *)title {
4189 [prompt_ setText:[title stringByAppendingString:@"..."]];
4192 - (void) _addProgressOutput:(NSString *)output {
4197 @interface Cydia : UIApplication <
4198 ConfirmationViewDelegate,
4199 ProgressViewDelegate,
4208 UIButtonBar *buttonbar_;
4210 ConfirmationView *confirm_;
4211 NSMutableArray *essential_;
4213 Database *database_;
4214 ProgressView *progress_;
4218 UIKeyboard *keyboard_;
4220 InstallView *install_;
4221 ChangesView *changes_;
4222 ManageView *manage_;
4223 SearchView *search_;
4228 @implementation Cydia
4230 - (void) _reloadData {
4231 /*UIProgressHUD *hud = [[UIProgressHUD alloc] initWithWindow:window_];
4232 [hud setText:@"Reloading Data"];
4233 [overlay_ addSubview:hud];
4236 [database_ reloadData];
4238 if (Packages_ == nil) {
4239 Packages_ = [[NSMutableDictionary alloc] initWithCapacity:128];
4240 [Metadata_ setObject:Packages_ forKey:@"Packages"];
4244 [essential_ removeAllObjects];
4246 NSArray *packages = [database_ packages];
4247 for (int i(0), e([packages count]); i != e; ++i) {
4248 Package *package = [packages objectAtIndex:i];
4249 if ([package upgradable]) {
4250 if ([package essential])
4251 [essential_ addObject:package];
4257 NSString *badge([[NSNumber numberWithInt:changes] stringValue]);
4258 [buttonbar_ setBadgeValue:badge forButton:3];
4259 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
4260 [buttonbar_ setBadgeAnimated:YES forButton:3];
4261 [self setApplicationBadge:badge];
4263 [buttonbar_ setBadgeValue:nil forButton:3];
4264 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
4265 [buttonbar_ setBadgeAnimated:NO forButton:3];
4266 [self removeApplicationBadge];
4270 _assert([Metadata_ writeToFile:@"/var/lib/cydia/metadata.plist" atomically:YES] == YES);
4274 /* XXX: this is just stupid */
4276 [install_ reloadData];
4278 [changes_ reloadData];
4280 [manage_ reloadData];
4282 [search_ reloadData];
4286 if ([packages count] == 0);
4287 else if (!Loaded_) {
4290 } else if (!Ignored_ && [essential_ count] != 0) {
4291 int count = [essential_ count];
4293 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
4294 initWithTitle:[NSString stringWithFormat:@"%d Essential Upgrade%@", count, (count == 1 ? @"" : @"s")]
4295 buttons:[NSArray arrayWithObjects:@"Upgrade Essential", @"Ignore (Temporary)", nil]
4296 defaultButtonIndex:0
4301 [sheet setBodyText:@"One or more essential packages are currently out of date. If these packages are not upgraded you are likely to encounter errors."];
4302 [sheet popupAlertAnimated:YES];
4306 [hud removeFromSuperview];*/
4309 - (void) reloadData {
4310 @synchronized (self) {
4311 if (confirm_ == nil)
4317 pkgProblemResolver *resolver = [database_ resolver];
4319 resolver->InstallProtect();
4320 if (!resolver->Resolve(true))
4325 [database_ prepare];
4327 if ([database_ cache]->BrokenCount() == 0)
4328 confirm_ = [[ConfirmationView alloc] initWithView:underlay_ database:database_ delegate:self];
4330 NSMutableArray *broken = [NSMutableArray arrayWithCapacity:16];
4331 NSArray *packages = [database_ packages];
4333 for (size_t i(0); i != [packages count]; ++i) {
4334 Package *package = [packages objectAtIndex:i];
4335 if ([package broken])
4336 [broken addObject:[package name]];
4339 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
4340 initWithTitle:[NSString stringWithFormat:@"%d Broken Packages", [database_ cache]->BrokenCount()]
4341 buttons:[NSArray arrayWithObjects:@"Okay", nil]
4342 defaultButtonIndex:0
4347 [sheet setBodyText:[NSString stringWithFormat:@"The following packages have unmet dependencies:\n\n%@", [broken componentsJoinedByString:@"\n"]]];
4348 [sheet popupAlertAnimated:YES];
4354 - (void) installPackage:(Package *)package {
4355 @synchronized (self) {
4362 - (void) removePackage:(Package *)package {
4363 @synchronized (self) {
4370 - (void) distUpgrade {
4371 @synchronized (self) {
4372 [database_ upgrade];
4378 @synchronized (self) {
4386 [overlay_ removeFromSuperview];
4390 detachNewThreadSelector:@selector(perform)
4397 - (void) bootstrap_ {
4399 [database_ upgrade];
4400 [database_ prepare];
4401 [database_ perform];
4404 - (void) bootstrap {
4406 detachNewThreadSelector:@selector(bootstrap_)
4409 title:@"Bootstrap Install..."
4413 - (void) progressViewIsComplete:(ProgressView *)progress {
4414 @synchronized (self) {
4417 if (confirm_ != nil) {
4418 [underlay_ addSubview:overlay_];
4419 [confirm_ removeFromSuperview];
4426 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
4427 NSString *context = [sheet context];
4428 if ([context isEqualToString:@"upgrade"])
4431 @synchronized (self) {
4432 for (int i = 0, e = [essential_ count]; i != e; ++i) {
4433 Package *essential = [essential_ objectAtIndex:i];
4434 [essential install];
4446 default: _assert(false);
4452 - (void) setPage:(RVPage *)page {
4453 [page resetViewAnimated:NO];
4454 [page setDelegate:self];
4455 [book_ setPage:page];
4458 - (RVPage *) _setHomePage {
4459 BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease];
4460 [self setPage:browser];
4461 [browser loadURL:[NSURL URLWithString:@"http://cydia.saurik.com/"]];
4465 - (void) buttonBarItemTapped:(id)sender {
4466 unsigned tag = [sender tag];
4468 [book_ resetViewAnimated:YES];
4473 case 1: [self _setHomePage]; break;
4475 case 2: [self setPage:install_]; break;
4476 case 3: [self setPage:changes_]; break;
4477 case 4: [self setPage:manage_]; break;
4478 case 5: [self setPage:search_]; break;
4480 default: _assert(false);
4486 - (void) applicationWillSuspend {
4487 [super applicationWillSuspend];
4490 if (FW_LEAST(1,1,3))
4491 notify_post("com.apple.language.changed");
4493 system("launchctl stop com.apple.SpringBoard");
4496 - (void) applicationDidFinishLaunching:(id)unused {
4497 _assert(pkgInitConfig(*_config));
4498 _assert(pkgInitSystem(*_config, _system));
4503 essential_ = [[NSMutableArray alloc] initWithCapacity:4];
4505 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
4506 window_ = [[UIWindow alloc] initWithContentRect:screenrect];
4508 [window_ orderFront: self];
4509 [window_ makeKey: self];
4510 [window_ _setHidden: NO];
4512 database_ = [[Database alloc] init];
4513 progress_ = [[ProgressView alloc] initWithFrame:[window_ bounds] database:database_ delegate:self];
4514 [database_ setDelegate:progress_];
4515 [window_ setContentView:progress_];
4517 underlay_ = [[UIView alloc] initWithFrame:[progress_ bounds]];
4518 [progress_ setContentView:underlay_];
4520 overlay_ = [[UIView alloc] initWithFrame:[underlay_ bounds]];
4523 [underlay_ addSubview:overlay_];
4525 book_ = [[CYBook alloc] initWithFrame:CGRectMake(
4526 0, 0, screenrect.size.width, screenrect.size.height - 48
4527 ) database:database_];
4529 [book_ setDelegate:self];
4531 [overlay_ addSubview:book_];
4533 NSArray *buttonitems = [NSArray arrayWithObjects:
4534 [NSDictionary dictionaryWithObjectsAndKeys:
4535 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
4536 @"home-up.png", kUIButtonBarButtonInfo,
4537 @"home-dn.png", kUIButtonBarButtonSelectedInfo,
4538 [NSNumber numberWithInt:1], kUIButtonBarButtonTag,
4539 self, kUIButtonBarButtonTarget,
4540 @"Home", kUIButtonBarButtonTitle,
4541 @"0", kUIButtonBarButtonType,
4544 [NSDictionary dictionaryWithObjectsAndKeys:
4545 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
4546 @"install-up.png", kUIButtonBarButtonInfo,
4547 @"install-dn.png", kUIButtonBarButtonSelectedInfo,
4548 [NSNumber numberWithInt:2], kUIButtonBarButtonTag,
4549 self, kUIButtonBarButtonTarget,
4550 @"Install", kUIButtonBarButtonTitle,
4551 @"0", kUIButtonBarButtonType,
4554 [NSDictionary dictionaryWithObjectsAndKeys:
4555 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
4556 @"changes-up.png", kUIButtonBarButtonInfo,
4557 @"changes-dn.png", kUIButtonBarButtonSelectedInfo,
4558 [NSNumber numberWithInt:3], kUIButtonBarButtonTag,
4559 self, kUIButtonBarButtonTarget,
4560 @"Changes", kUIButtonBarButtonTitle,
4561 @"0", kUIButtonBarButtonType,
4564 [NSDictionary dictionaryWithObjectsAndKeys:
4565 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
4566 @"manage-up.png", kUIButtonBarButtonInfo,
4567 @"manage-dn.png", kUIButtonBarButtonSelectedInfo,
4568 [NSNumber numberWithInt:4], kUIButtonBarButtonTag,
4569 self, kUIButtonBarButtonTarget,
4570 @"Manage", kUIButtonBarButtonTitle,
4571 @"0", kUIButtonBarButtonType,
4574 [NSDictionary dictionaryWithObjectsAndKeys:
4575 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
4576 @"search-up.png", kUIButtonBarButtonInfo,
4577 @"search-dn.png", kUIButtonBarButtonSelectedInfo,
4578 [NSNumber numberWithInt:5], kUIButtonBarButtonTag,
4579 self, kUIButtonBarButtonTarget,
4580 @"Search", kUIButtonBarButtonTitle,
4581 @"0", kUIButtonBarButtonType,
4585 buttonbar_ = [[UIButtonBar alloc]
4587 withFrame:CGRectMake(
4588 0, screenrect.size.height - ButtonBarHeight_,
4589 screenrect.size.width, ButtonBarHeight_
4591 withItemList:buttonitems
4594 [buttonbar_ setDelegate:self];
4595 [buttonbar_ setBarStyle:1];
4596 [buttonbar_ setButtonBarTrackingMode:2];
4598 int buttons[5] = {1, 2, 3, 4, 5};
4599 [buttonbar_ registerButtonGroup:0 withButtons:buttons withCount:5];
4600 [buttonbar_ showButtonGroup:0 withDuration:0];
4602 for (int i = 0; i != 5; ++i)
4603 [[buttonbar_ viewWithTag:(i + 1)] setFrame:CGRectMake(
4604 i * 64 + 2, 1, 60, ButtonBarHeight_
4607 [buttonbar_ showSelectionForButton:1];
4608 [overlay_ addSubview:buttonbar_];
4610 [UIKeyboard initImplementationNow];
4611 CGSize keysize = [UIKeyboard defaultSize];
4612 CGRect keyrect = {{0, [overlay_ bounds].size.height}, keysize};
4613 keyboard_ = [[UIKeyboard alloc] initWithFrame:keyrect];
4614 [[UIKeyboardImpl sharedInstance] setSoundsEnabled:(Sounds_Keyboard_ ? YES : NO)];
4615 [overlay_ addSubview:keyboard_];
4617 install_ = [[InstallView alloc] initWithBook:book_ database:database_];
4618 changes_ = [[ChangesView alloc] initWithBook:book_ database:database_];
4619 manage_ = [[ManageView alloc] initWithBook:book_ database:database_];
4620 search_ = [[SearchView alloc] initWithBook:book_ database:database_];
4622 [progress_ resetView];
4628 [self _setHomePage];
4631 - (void) showKeyboard:(BOOL)show {
4632 CGSize keysize = [UIKeyboard defaultSize];
4633 CGRect keydown = {{0, [overlay_ bounds].size.height}, keysize};
4634 CGRect keyup = keydown;
4635 keyup.origin.y -= keysize.height;
4637 UIFrameAnimation *animation = [[[UIFrameAnimation alloc] initWithTarget:keyboard_] autorelease];
4638 [animation setSignificantRectFields:2];
4641 [animation setStartFrame:keydown];
4642 [animation setEndFrame:keyup];
4643 [keyboard_ activate];
4645 [animation setStartFrame:keyup];
4646 [animation setEndFrame:keydown];
4647 [keyboard_ deactivate];
4650 [[UIAnimator sharedAnimator]
4651 addAnimations:[NSArray arrayWithObjects:animation, nil]
4652 withDuration:KeyboardTime_
4657 - (void) slideUp:(UIAlertSheet *)alert {
4658 [alert presentSheetFromButtonBar:buttonbar_];
4663 void AddPreferences(NSString *plist) {
4664 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
4666 NSMutableDictionary *settings = [[[NSMutableDictionary alloc] initWithContentsOfFile:plist] autorelease];
4667 _assert(settings != NULL);
4668 NSMutableArray *items = [settings objectForKey:@"items"];
4672 for (size_t i(0); i != [items count]; ++i) {
4673 NSMutableDictionary *item([items objectAtIndex:i]);
4674 NSString *label = [item objectForKey:@"label"];
4675 if (label != nil && [label isEqualToString:@"Cydia"]) {
4682 for (size_t i(0); i != [items count]; ++i) {
4683 NSDictionary *item([items objectAtIndex:i]);
4684 NSString *label = [item objectForKey:@"label"];
4685 if (label != nil && [label isEqualToString:@"General"]) {
4686 [items insertObject:[NSDictionary dictionaryWithObjectsAndKeys:
4687 @"CydiaSettings", @"bundle",
4688 @"PSLinkCell", @"cell",
4689 [NSNumber numberWithBool:YES], @"hasIcon",
4690 [NSNumber numberWithBool:YES], @"isController",
4692 nil] atIndex:(i + 1)];
4698 _assert([settings writeToFile:plist atomically:YES] == YES);
4705 id Alloc_(id self, SEL selector) {
4706 id object = alloc_(self, selector);
4707 fprintf(stderr, "[%s]A-%p\n", self->isa->name, object);
4712 id Dealloc_(id self, SEL selector) {
4713 id object = dealloc_(self, selector);
4714 fprintf(stderr, "[%s]D-%p\n", self->isa->name, object);
4718 int main(int argc, char *argv[]) {
4719 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
4721 bootstrap_ = argc > 1 && strcmp(argv[1], "--bootstrap") == 0;
4723 Home_ = NSHomeDirectory();
4726 NSString *plist = [Home_ stringByAppendingString:@"/Library/Preferences/com.apple.preferences.sounds.plist"];
4727 if (NSDictionary *sounds = [NSDictionary dictionaryWithContentsOfFile:plist])
4728 if (NSNumber *keyboard = [sounds objectForKey:@"keyboard"])
4729 Sounds_Keyboard_ = [keyboard boolValue];
4735 /*Method alloc = class_getClassMethod([NSObject class], @selector(alloc));
4736 alloc_ = alloc->method_imp;
4737 alloc->method_imp = (IMP) &Alloc_;*/
4739 /*Method dealloc = class_getClassMethod([NSObject class], @selector(dealloc));
4740 dealloc_ = dealloc->method_imp;
4741 dealloc->method_imp = (IMP) &Dealloc_;*/
4743 if (NSDictionary *sysver = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]) {
4744 if (NSString *prover = [sysver valueForKey:@"ProductVersion"]) {
4745 Firmware_ = strdup([prover UTF8String]);
4746 NSArray *versions = [prover componentsSeparatedByString:@"."];
4747 int count = [versions count];
4748 Major_ = count > 0 ? [[versions objectAtIndex:0] intValue] : 0;
4749 Minor_ = count > 1 ? [[versions objectAtIndex:1] intValue] : 0;
4750 BugFix_ = count > 2 ? [[versions objectAtIndex:2] intValue] : 0;
4755 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
4756 char *machine = new char[size];
4757 sysctlbyname("hw.machine", machine, &size, NULL, 0);
4760 if (CFMutableDictionaryRef dict = IOServiceMatching("IOPlatformExpertDevice"))
4761 if (io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, dict)) {
4762 if (CFTypeRef serial = IORegistryEntryCreateCFProperty(service, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0)) {
4763 SerialNumber_ = strdup(CFStringGetCStringPtr((CFStringRef) serial, CFStringGetSystemEncoding()));
4767 IOObjectRelease(service);
4770 /*AddPreferences(@"/Applications/Preferences.app/Settings-iPhone.plist");
4771 AddPreferences(@"/Applications/Preferences.app/Settings-iPod.plist");*/
4773 if ((Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"]) == NULL)
4774 Metadata_ = [[NSMutableDictionary alloc] initWithCapacity:2];
4776 Packages_ = [Metadata_ objectForKey:@"Packages"];
4778 setenv("CYDIA", "", _not(int));
4779 if (access("/User", F_OK) != 0)
4780 system("/usr/libexec/cydia/firmware.sh");
4782 space_ = CGColorSpaceCreateDeviceRGB();
4784 Black_.Set(space_, 0.0, 0.0, 0.0, 1.0);
4785 Clear_.Set(space_, 0.0, 0.0, 0.0, 0.0);
4786 Red_.Set(space_, 1.0, 0.0, 0.0, 1.0);
4787 White_.Set(space_, 1.0, 1.0, 1.0, 1.0);
4789 int value = UIApplicationMain(argc, argv, [Cydia class]);
4791 CGColorSpaceRelease(space_);