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 open lock file /var/lib/dpkg/lock - open (13 Permission denied)")
1468 // else if (error == "Could not get lock /var/lib/dpkg/lock - open (35 Resource temporarily unavailable)")
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:)];
1504 - (void) configure {
1505 NSString *dpkg = [NSString stringWithFormat:@"dpkg --configure -a --status-fd %u", statusfd_];
1506 system([dpkg UTF8String]);
1510 pkgRecords records(cache_);
1512 lock_ = new FileFd();
1513 lock_->Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1514 _assert(!_error->PendingError());
1517 // XXX: explain this with an error message
1518 _assert(list.ReadMainList());
1520 manager_ = (_system->CreatePM(cache_));
1521 _assert(manager_->GetArchives(fetcher_, &list, &records));
1522 _assert(!_error->PendingError());
1526 NSMutableArray *before = [NSMutableArray arrayWithCapacity:16]; {
1528 _assert(list.ReadMainList());
1529 for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source)
1530 [before addObject:[NSString stringWithUTF8String:(*source)->GetURI().c_str()]];
1533 if (fetcher_->Run(PulseInterval_) != pkgAcquire::Continue)
1537 pkgPackageManager::OrderResult result = manager_->DoInstall(statusfd_);
1539 if (result == pkgPackageManager::Failed)
1541 if (_error->PendingError())
1543 if (result != pkgPackageManager::Completed)
1546 NSMutableArray *after = [NSMutableArray arrayWithCapacity:16]; {
1548 _assert(list.ReadMainList());
1549 for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source)
1550 [after addObject:[NSString stringWithUTF8String:(*source)->GetURI().c_str()]];
1553 if (![before isEqualToArray:after])
1558 _assert(cache_->DelCount() == 0 && cache_->InstCount() == 0);
1559 _assert(pkgApplyStatus(cache_));
1561 if (cache_->BrokenCount() != 0) {
1562 _assert(pkgFixBroken(cache_));
1563 _assert(cache_->BrokenCount() == 0);
1564 _assert(pkgMinimizeUpgrade(cache_));
1567 _assert(pkgDistUpgrade(cache_));
1571 [self updateWithStatus:status_];
1574 - (void) updateWithStatus:(Status &)status {
1576 _assert(list.ReadMainList());
1579 lock.Fd(GetLock(_config->FindDir("Dir::State::Lists") + "lock"));
1580 _assert(!_error->PendingError());
1582 pkgAcquire fetcher(&status);
1583 _assert(list.GetIndexes(&fetcher));
1585 if (fetcher.Run(PulseInterval_) != pkgAcquire::Failed) {
1586 bool failed = false;
1587 for (pkgAcquire::ItemIterator item = fetcher.ItemsBegin(); item != fetcher.ItemsEnd(); item++)
1588 if ((*item)->Status != pkgAcquire::Item::StatDone) {
1589 (*item)->Finished();
1593 if (!failed && _config->FindB("APT::Get::List-Cleanup", true) == true) {
1594 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists")));
1595 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/"));
1598 [Metadata_ setObject:[NSDate date] forKey:@"LastUpdate"];
1603 - (void) setDelegate:(id)delegate {
1604 delegate_ = delegate;
1605 status_.setDelegate(delegate);
1606 progress_.setDelegate(delegate);
1609 - (Source *) getSource:(const pkgCache::PkgFileIterator &)file {
1610 pkgIndexFile *index(NULL);
1611 list_->FindIndex(file, index);
1612 return [sources_ objectForKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(index)]];
1618 /* Confirmation View {{{ */
1619 void AddTextView(NSMutableDictionary *fields, NSMutableArray *packages, NSString *key) {
1620 if ([packages count] == 0)
1623 UITextView *text = GetTextView([packages count] == 0 ? @"n/a" : [packages componentsJoinedByString:@", "], 120, false);
1624 [fields setObject:text forKey:key];
1626 CGColor blue(space_, 0, 0, 0.4, 1);
1627 [text setTextColor:blue];
1630 @protocol ConfirmationViewDelegate
1635 @interface ConfirmationView : UIView {
1636 Database *database_;
1638 UITransitionView *transition_;
1640 UINavigationBar *navbar_;
1641 UIPreferencesTable *table_;
1642 NSMutableDictionary *fields_;
1643 UIAlertSheet *essential_;
1648 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate;
1652 @implementation ConfirmationView
1655 [navbar_ setDelegate:nil];
1656 [transition_ setDelegate:nil];
1657 [table_ setDataSource:nil];
1659 [transition_ release];
1664 if (essential_ != nil)
1665 [essential_ release];
1670 [transition_ transition:7 toView:nil];
1674 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
1675 if (from != nil && to == nil)
1676 [self removeFromSuperview];
1679 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
1682 if (essential_ != nil)
1683 [essential_ popupAlertAnimated:YES];
1685 [delegate_ confirm];
1694 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
1695 [essential_ dismiss];
1699 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
1703 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
1705 case 0: return @"Statistics";
1706 case 1: return @"Modifications";
1708 default: _assert(false);
1712 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
1715 case 1: return [fields_ count];
1717 default: _assert(false);
1721 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
1722 if (group != 1 || row == -1)
1725 _assert(size_t(row) < [fields_ count]);
1726 return [[[fields_ allValues] objectAtIndex:row] visibleTextRect].size.height + TextViewOffset_;
1730 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
1731 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
1732 [cell setShowSelection:NO];
1735 case 0: switch (row) {
1737 [cell setTitle:@"Downloading"];
1738 [cell setValue:SizeString([database_ fetcher].FetchNeeded())];
1742 [cell setTitle:@"Resuming At"];
1743 [cell setValue:SizeString([database_ fetcher].PartialPresent())];
1747 double size([database_ cache]->UsrSize());
1750 [cell setTitle:@"Disk Freeing"];
1751 [cell setValue:SizeString(-size)];
1753 [cell setTitle:@"Disk Using"];
1754 [cell setValue:SizeString(size)];
1758 default: _assert(false);
1762 _assert(size_t(row) < [fields_ count]);
1763 [cell setTitle:[[fields_ allKeys] objectAtIndex:row]];
1764 [cell addSubview:[[fields_ allValues] objectAtIndex:row]];
1767 default: _assert(false);
1773 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate {
1774 if ((self = [super initWithFrame:[view bounds]]) != nil) {
1775 database_ = database;
1776 delegate_ = delegate;
1778 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
1779 [self addSubview:transition_];
1781 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
1783 CGSize navsize = [UINavigationBar defaultSize];
1784 CGRect navrect = {{0, 0}, navsize};
1785 CGRect bounds = [overlay_ bounds];
1787 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
1789 [navbar_ setBarStyle:1];
1790 [navbar_ setDelegate:self];
1792 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Confirm"] autorelease];
1793 [navbar_ pushNavigationItem:navitem];
1794 [navbar_ showButtonsWithLeftTitle:@"Cancel" rightTitle:@"Confirm"];
1796 fields_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1798 NSMutableArray *installing = [NSMutableArray arrayWithCapacity:16];
1799 NSMutableArray *reinstalling = [NSMutableArray arrayWithCapacity:16];
1800 NSMutableArray *upgrading = [NSMutableArray arrayWithCapacity:16];
1801 NSMutableArray *downgrading = [NSMutableArray arrayWithCapacity:16];
1802 NSMutableArray *removing = [NSMutableArray arrayWithCapacity:16];
1806 pkgCacheFile &cache([database_ cache]);
1807 NSArray *packages = [database_ packages];
1808 for (size_t i(0), e = [packages count]; i != e; ++i) {
1809 Package *package = [packages objectAtIndex:i];
1810 pkgCache::PkgIterator iterator = [package iterator];
1811 pkgDepCache::StateCache &state(cache[iterator]);
1813 NSString *name([package name]);
1815 if (state.NewInstall())
1816 [installing addObject:name];
1817 else if (!state.Delete() && (state.iFlags & pkgDepCache::ReInstall) == pkgDepCache::ReInstall)
1818 [reinstalling addObject:name];
1819 else if (state.Upgrade())
1820 [upgrading addObject:name];
1821 else if (state.Downgrade())
1822 [downgrading addObject:name];
1823 else if (state.Delete()) {
1824 if ([package essential])
1826 [removing addObject:name];
1833 essential_ = [[UIAlertSheet alloc]
1834 initWithTitle:@"Unable to Comply"
1835 buttons:[NSArray arrayWithObjects:@"Okay", nil]
1836 defaultButtonIndex:0
1841 [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."];
1844 AddTextView(fields_, installing, @"Installing");
1845 AddTextView(fields_, reinstalling, @"Reinstalling");
1846 AddTextView(fields_, upgrading, @"Upgrading");
1847 AddTextView(fields_, downgrading, @"Downgrading");
1848 AddTextView(fields_, removing, @"Removing");
1850 table_ = [[UIPreferencesTable alloc] initWithFrame:CGRectMake(
1851 0, navsize.height, bounds.size.width, bounds.size.height - navsize.height
1854 [table_ setReusesTableCells:YES];
1855 [table_ setDataSource:self];
1856 [table_ reloadData];
1858 [overlay_ addSubview:navbar_];
1859 [overlay_ addSubview:table_];
1861 [view addSubview:self];
1863 [transition_ setDelegate:self];
1865 UIView *blank = [[[UIView alloc] initWithFrame:[transition_ bounds]] autorelease];
1866 [transition_ transition:0 toView:blank];
1867 [transition_ transition:3 toView:overlay_];
1874 /* Progress Data {{{ */
1875 @interface ProgressData : NSObject {
1881 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object;
1888 @implementation ProgressData
1890 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object {
1891 if ((self = [super init]) != nil) {
1892 selector_ = selector;
1912 /* Progress View {{{ */
1913 Pcre conffile_r("^'(.*)' '(.*)' ([01]) ([01])$");
1915 @interface ProgressView : UIView <
1916 ConfigurationDelegate,
1919 _transient Database *database_;
1921 UIView *background_;
1922 UITransitionView *transition_;
1924 UINavigationBar *navbar_;
1925 UIProgressBar *progress_;
1926 UITextView *output_;
1927 UITextLabel *status_;
1931 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
1933 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database delegate:(id)delegate;
1934 - (void) setContentView:(UIView *)view;
1937 - (void) _retachThread;
1938 - (void) _detachNewThreadData:(ProgressData *)data;
1939 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title;
1943 @protocol ProgressViewDelegate
1944 - (void) progressViewIsComplete:(ProgressView *)sender;
1947 @implementation ProgressView
1950 [transition_ setDelegate:nil];
1951 [navbar_ setDelegate:nil];
1954 if (background_ != nil)
1955 [background_ release];
1956 [transition_ release];
1959 [progress_ release];
1965 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
1966 if (bootstrap_ && from == overlay_ && to == view_)
1970 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database delegate:(id)delegate {
1971 if ((self = [super initWithFrame:frame]) != nil) {
1972 database_ = database;
1973 delegate_ = delegate;
1975 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
1976 [transition_ setDelegate:self];
1978 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
1981 [overlay_ setBackgroundColor:Black_];
1983 background_ = [[UIView alloc] initWithFrame:[self bounds]];
1984 [background_ setBackgroundColor:Black_];
1985 [self addSubview:background_];
1988 [self addSubview:transition_];
1990 CGSize navsize = [UINavigationBar defaultSize];
1991 CGRect navrect = {{0, 0}, navsize};
1993 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
1994 [overlay_ addSubview:navbar_];
1996 [navbar_ setBarStyle:1];
1997 [navbar_ setDelegate:self];
1999 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:nil] autorelease];
2000 [navbar_ pushNavigationItem:navitem];
2002 CGRect bounds = [overlay_ bounds];
2003 CGSize prgsize = [UIProgressBar defaultSize];
2006 (bounds.size.width - prgsize.width) / 2,
2007 bounds.size.height - prgsize.height - 20
2010 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
2011 [overlay_ addSubview:progress_];
2013 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(
2015 bounds.size.height - prgsize.height - 50,
2016 bounds.size.width - 20,
2020 [status_ setColor:White_];
2021 [status_ setBackgroundColor:Clear_];
2023 [status_ setCentersHorizontally:YES];
2024 //[status_ setFont:font];
2026 output_ = [[UITextView alloc] initWithFrame:CGRectMake(
2028 navrect.size.height + 20,
2029 bounds.size.width - 20,
2030 bounds.size.height - navsize.height - 62 - navrect.size.height
2033 //[output_ setTextFont:@"Courier New"];
2034 [output_ setTextSize:12];
2036 [output_ setTextColor:White_];
2037 [output_ setBackgroundColor:Clear_];
2039 [output_ setMarginTop:0];
2040 [output_ setAllowsRubberBanding:YES];
2042 [overlay_ addSubview:output_];
2043 [overlay_ addSubview:status_];
2045 [progress_ setStyle:0];
2049 - (void) setContentView:(UIView *)view {
2050 view_ = [view retain];
2053 - (void) resetView {
2054 [transition_ transition:6 toView:view_];
2057 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
2058 NSString *context = [sheet context];
2059 if ([context isEqualToString:@"conffile"]) {
2060 FILE *input = [database_ input];
2064 fprintf(input, "N\n");
2069 fprintf(input, "Y\n");
2073 default: _assert(false);
2080 - (void) _retachThread {
2081 [delegate_ progressViewIsComplete:self];
2085 - (void) _detachNewThreadData:(ProgressData *)data {
2086 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
2088 [[data target] performSelector:[data selector] withObject:[data object]];
2091 [self performSelectorOnMainThread:@selector(_retachThread) withObject:nil waitUntilDone:YES];
2096 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title {
2097 UINavigationItem *item = [navbar_ topItem];
2098 [item setTitle:title];
2100 [status_ setText:nil];
2101 [output_ setText:@""];
2102 [progress_ setProgress:0];
2104 [transition_ transition:6 toView:overlay_];
2107 detachNewThreadSelector:@selector(_detachNewThreadData:)
2109 withObject:[[ProgressData alloc]
2110 initWithSelector:selector
2117 - (void) repairWithSelector:(SEL)selector {
2119 detachNewThreadSelector:selector
2122 title:@"Repairing..."
2126 - (void) setConfigurationData:(NSString *)data {
2128 performSelectorOnMainThread:@selector(_setConfigurationData:)
2134 - (void) setProgressError:(NSString *)error {
2136 performSelectorOnMainThread:@selector(_setProgressError:)
2142 - (void) setProgressTitle:(NSString *)title {
2144 performSelectorOnMainThread:@selector(_setProgressTitle:)
2150 - (void) setProgressPercent:(float)percent {
2152 performSelectorOnMainThread:@selector(_setProgressPercent:)
2153 withObject:[NSNumber numberWithFloat:percent]
2158 - (void) addProgressOutput:(NSString *)output {
2160 performSelectorOnMainThread:@selector(_addProgressOutput:)
2166 - (void) _setConfigurationData:(NSString *)data {
2167 _assert(conffile_r(data));
2169 NSString *ofile = conffile_r[1];
2170 //NSString *nfile = conffile_r[2];
2172 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
2173 initWithTitle:@"Configuration Upgrade"
2174 buttons:[NSArray arrayWithObjects:
2175 @"Keep My Old Copy",
2176 @"Accept The New Copy",
2177 // XXX: @"See What Changed",
2179 defaultButtonIndex:0
2184 [sheet setBodyText:[NSString stringWithFormat:
2185 @"The following file has been changed by both the package maintainer and by you (or for you by a script).\n\n%@"
2188 [sheet popupAlertAnimated:YES];
2191 - (void) _setProgressError:(NSString *)error {
2192 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
2193 initWithTitle:@"Package Error"
2194 buttons:[NSArray arrayWithObjects:@"Okay", nil]
2195 defaultButtonIndex:0
2200 [sheet setBodyText:error];
2201 [sheet popupAlertAnimated:YES];
2204 - (void) _setProgressTitle:(NSString *)title {
2205 [status_ setText:[title stringByAppendingString:@"..."]];
2208 - (void) _setProgressPercent:(NSNumber *)percent {
2209 [progress_ setProgress:[percent floatValue]];
2212 - (void) _addProgressOutput:(NSString *)output {
2213 [output_ setText:[NSString stringWithFormat:@"%@\n%@", [output_ text], output]];
2214 CGSize size = [output_ contentSize];
2215 CGRect rect = {{0, size.height}, {size.width, 0}};
2216 [output_ scrollRectToVisible:rect animated:YES];
2222 /* Package Cell {{{ */
2223 @interface PackageCell : UITableCell {
2226 UITextLabel *description_;
2227 UITextLabel *source_;
2228 UIImageView *trusted_;
2231 - (PackageCell *) init;
2232 - (void) setPackage:(Package *)package;
2234 - (void) _setSelected:(float)fraction;
2235 - (void) setSelected:(BOOL)selected;
2236 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
2237 - (void) _setSelectionFadeFraction:(float)fraction;
2241 @implementation PackageCell
2246 [description_ release];
2252 - (PackageCell *) init {
2253 if ((self = [super init]) != nil) {
2254 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 20);
2255 GSFontRef large = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 12);
2256 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 14);
2258 icon_ = [[UIImageView alloc] initWithFrame:CGRectMake(10, 10, 30, 30)];
2260 name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 8, 240, 25)];
2261 [name_ setBackgroundColor:Clear_];
2262 [name_ setFont:bold];
2264 source_ = [[UITextLabel alloc] initWithFrame:CGRectMake(58, 28, 225, 20)];
2265 [source_ setBackgroundColor:Clear_];
2266 [source_ setFont:large];
2268 description_ = [[UITextLabel alloc] initWithFrame:CGRectMake(12, 46, 280, 20)];
2269 [description_ setBackgroundColor:Clear_];
2270 [description_ setFont:small];
2272 trusted_ = [[UIImageView alloc] initWithFrame:CGRectMake(30, 30, 16, 16)];
2273 [trusted_ setImage:[UIImage applicationImageNamed:@"trusted.png"]];
2275 [self addSubview:icon_];
2276 [self addSubview:name_];
2277 [self addSubview:description_];
2278 [self addSubview:source_];
2286 - (void) setPackage:(Package *)package {
2287 Source *source = [package source];
2289 UIImage *image = nil;
2290 if (NSString *icon = [package icon])
2291 image = [UIImage imageAtPath:[icon substringFromIndex:6]];
2292 if (image == nil) if (NSString *icon = [source defaultIcon])
2293 image = [UIImage imageAtPath:[icon substringFromIndex:6]];
2295 image = [UIImage applicationImageNamed:@"unknown.png"];
2296 [icon_ setImage:image];
2299 CGSize size = [image size];
2300 float scale = 30 / std::max(size.width, size.height);
2301 [icon_ zoomToScale:scale];
2304 [icon_ setFrame:CGRectMake(10, 10, 30, 30)];
2306 [name_ setText:[package name]];
2307 [description_ setText:[package tagline]];
2309 NSString *label = nil;
2310 bool trusted = false;
2312 if (source != nil) {
2313 label = [source label];
2314 trusted = [source trusted];
2315 } else if ([[package id] isEqualToString:@"firmware"])
2319 label = @"Unknown/Local";
2321 NSString *from = [NSString stringWithFormat:@"from %@", label];
2323 NSString *section = Simplify([package section]);
2324 if (section != nil && ![section isEqualToString:label])
2325 from = [from stringByAppendingString:[NSString stringWithFormat:@" (%@)", section]];
2327 [source_ setText:from];
2330 [self addSubview:trusted_];
2332 [trusted_ removeFromSuperview];
2335 - (void) _setSelected:(float)fraction {
2336 CGColor black(space_,
2337 Interpolate(0.0, 1.0, fraction),
2338 Interpolate(0.0, 1.0, fraction),
2339 Interpolate(0.0, 1.0, fraction),
2342 CGColor gray(space_,
2343 Interpolate(0.4, 1.0, fraction),
2344 Interpolate(0.4, 1.0, fraction),
2345 Interpolate(0.4, 1.0, fraction),
2348 [name_ setColor:black];
2349 [description_ setColor:gray];
2350 [source_ setColor:black];
2353 - (void) setSelected:(BOOL)selected {
2354 [self _setSelected:(selected ? 1.0 : 0.0)];
2355 [super setSelected:selected];
2358 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
2360 [self _setSelected:(selected ? 1.0 : 0.0)];
2361 [super setSelected:selected withFade:fade];
2364 - (void) _setSelectionFadeFraction:(float)fraction {
2365 [self _setSelected:fraction];
2366 [super _setSelectionFadeFraction:fraction];
2371 /* Section Cell {{{ */
2372 @interface SectionCell : UITableCell {
2374 UITextLabel *count_;
2378 - (void) setSection:(Section *)section;
2380 - (void) _setSelected:(float)fraction;
2381 - (void) setSelected:(BOOL)selected;
2382 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
2383 - (void) _setSelectionFadeFraction:(float)fraction;
2387 @implementation SectionCell
2396 if ((self = [super init]) != nil) {
2397 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22);
2398 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 12);
2400 name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 9, 250, 25)];
2401 [name_ setBackgroundColor:Clear_];
2402 [name_ setFont:bold];
2404 count_ = [[UITextLabel alloc] initWithFrame:CGRectMake(11, 7, 29, 32)];
2405 [count_ setCentersHorizontally:YES];
2406 [count_ setBackgroundColor:Clear_];
2407 [count_ setFont:small];
2408 [count_ setColor:White_];
2410 UIImageView *folder = [[[UIImageView alloc] initWithFrame:CGRectMake(8, 7, 32, 32)] autorelease];
2411 [folder setImage:[UIImage applicationImageNamed:@"folder.png"]];
2413 [self addSubview:folder];
2414 [self addSubview:name_];
2415 [self addSubview:count_];
2417 [self _setSelected:0];
2424 - (void) setSection:(Section *)section {
2425 if (section == nil) {
2426 [name_ setText:@"All Packages"];
2427 [count_ setText:nil];
2429 NSString *name = [section name];
2430 [name_ setText:(name == nil ? @"(No Section)" : name)];
2431 [count_ setText:[NSString stringWithFormat:@"%d", [section count]]];
2435 - (void) _setSelected:(float)fraction {
2436 CGColor black(space_,
2437 Interpolate(0.0, 1.0, fraction),
2438 Interpolate(0.0, 1.0, fraction),
2439 Interpolate(0.0, 1.0, fraction),
2442 [name_ setColor:black];
2445 - (void) setSelected:(BOOL)selected {
2446 [self _setSelected:(selected ? 1.0 : 0.0)];
2447 [super setSelected:selected];
2450 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
2452 [self _setSelected:(selected ? 1.0 : 0.0)];
2453 [super setSelected:selected withFade:fade];
2456 - (void) _setSelectionFadeFraction:(float)fraction {
2457 [self _setSelected:fraction];
2458 [super _setSelectionFadeFraction:fraction];
2464 /* File Table {{{ */
2465 @interface FileTable : RVPage {
2466 _transient Database *database_;
2469 NSMutableArray *files_;
2473 - (id) initWithBook:(RVBook *)book database:(Database *)database;
2474 - (void) setPackage:(Package *)package;
2478 @implementation FileTable
2481 if (package_ != nil)
2490 - (int) numberOfRowsInTable:(UITable *)table {
2491 return files_ == nil ? 0 : [files_ count];
2494 - (float) table:(UITable *)table heightForRow:(int)row {
2498 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2499 if (reusing == nil) {
2500 reusing = [[[UIImageAndTextTableCell alloc] init] autorelease];
2501 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
2502 [[(UIImageAndTextTableCell *)reusing titleTextLabel] setFont:font];
2505 [(UIImageAndTextTableCell *)reusing setTitle:[files_ objectAtIndex:row]];
2509 - (BOOL) canSelectRow:(int)row {
2513 - (id) initWithBook:(RVBook *)book database:(Database *)database {
2514 if ((self = [super initWithBook:book]) != nil) {
2515 database_ = database;
2517 files_ = [[NSMutableArray arrayWithCapacity:32] retain];
2519 list_ = [[UITable alloc] initWithFrame:[self bounds]];
2520 [self addSubview:list_];
2522 UITableColumn *column = [[[UITableColumn alloc]
2523 initWithTitle:@"Name"
2525 width:[self frame].size.width
2528 [list_ setDataSource:self];
2529 [list_ setSeparatorStyle:1];
2530 [list_ addTableColumn:column];
2531 [list_ setDelegate:self];
2532 [list_ setReusesTableCells:YES];
2536 - (void) setPackage:(Package *)package {
2537 if (package_ != nil) {
2538 [package_ autorelease];
2547 [files_ removeAllObjects];
2549 if (package != nil) {
2550 package_ = [package retain];
2551 name_ = [[package id] retain];
2553 NSString *path = [NSString stringWithFormat:@"/var/lib/dpkg/info/%@.list", name_];
2556 std::ifstream fin([path UTF8String]);
2558 while (std::getline(fin, line))
2559 [files_ addObject:[NSString stringWithUTF8String:line.c_str()]];
2562 if ([files_ count] != 0) {
2563 if ([[files_ objectAtIndex:0] isEqualToString:@"/."])
2564 [files_ removeObjectAtIndex:0];
2565 [files_ sortUsingSelector:@selector(compareByPath:)];
2567 NSMutableArray *stack = [NSMutableArray arrayWithCapacity:8];
2568 [stack addObject:@"/"];
2570 for (int i(0), e([files_ count]); i != e; ++i) {
2571 NSString *file = [files_ objectAtIndex:i];
2572 while (![file hasPrefix:[stack lastObject]])
2573 [stack removeLastObject];
2574 NSString *directory = [stack lastObject];
2575 [stack addObject:[file stringByAppendingString:@"/"]];
2576 [files_ replaceObjectAtIndex:i withObject:[NSString stringWithFormat:@"%*s%@",
2577 ([stack count] - 2) * 3, "",
2578 [file substringFromIndex:[directory length]]
2587 - (void) resetViewAnimated:(BOOL)animated {
2588 [list_ resetViewAnimated:animated];
2591 - (void) reloadData {
2592 [self setPackage:[database_ packageWithName:name_]];
2593 [self reloadButtons];
2596 - (NSString *) title {
2597 return @"Installed Files";
2600 - (NSString *) backButtonTitle {
2606 /* Package View {{{ */
2607 @protocol PackageViewDelegate
2608 - (void) performPackage:(Package *)package;
2611 @interface PackageView : RVPage {
2612 _transient Database *database_;
2613 UIPreferencesTable *table_;
2616 UITextView *description_;
2617 NSMutableArray *buttons_;
2620 - (id) initWithBook:(RVBook *)book database:(Database *)database;
2621 - (void) setPackage:(Package *)package;
2625 @implementation PackageView
2628 [table_ setDataSource:nil];
2629 [table_ setDelegate:nil];
2631 if (package_ != nil)
2635 if (description_ != nil)
2636 [description_ release];
2642 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
2644 if ([package_ installed] != nil)
2646 if ([package_ source] != nil)
2651 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
2654 else if ([package_ installed] != nil && group-- == 0)
2655 return @"Installed Package";
2656 else if (group-- == 0)
2657 return @"Package Details";
2658 else if ([package_ source] != nil && group-- == 0)
2659 return @"Source Information";
2660 else _assert(false);
2663 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
2664 if (description_ == nil || group != 0 || row != 1)
2667 return [description_ visibleTextRect].size.height + TextViewOffset_;
2670 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
2673 if (description_ != nil)
2675 if ([package_ website] != nil)
2677 if ([[package_ source] trusted])
2680 } else if ([package_ installed] != nil && group-- == 0)
2682 else if (group-- == 0) {
2684 if ([package_ size] != 0)
2686 if ([package_ maintainer] != nil)
2688 if ([package_ relationships] != nil)
2691 } else if ([package_ source] != nil && group-- == 0) {
2692 Source *source = [package_ source];
2693 NSString *description = [source description];
2695 if (description != nil && ![description isEqualToString:[source label]])
2697 if ([source origin] != nil)
2700 } else _assert(false);
2703 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
2704 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
2705 [cell setShowSelection:NO];
2709 [cell setTitle:[package_ name]];
2710 [cell setValue:[package_ latest]];
2711 } else if (description_ != nil && row-- == 0) {
2712 [cell addSubview:description_];
2713 } else if ([package_ website] != nil && row-- == 0) {
2714 [cell setTitle:@"More Information"];
2715 [cell setShowDisclosure:YES];
2716 [cell setShowSelection:YES];
2717 } else if ([[package_ source] trusted] && row-- == 0) {
2718 [cell setIcon:[UIImage applicationImageNamed:@"trusted.png"]];
2719 [cell setValue:@"This package has been signed."];
2720 } else _assert(false);
2721 } else if ([package_ installed] != nil && group-- == 0) {
2723 [cell setTitle:@"Version"];
2724 NSString *installed([package_ installed]);
2725 [cell setValue:(installed == nil ? @"n/a" : installed)];
2726 } else if (row-- == 0) {
2727 [cell setTitle:@"Filesystem Content"];
2728 [cell setShowDisclosure:YES];
2729 [cell setShowSelection:YES];
2730 } else _assert(false);
2731 } else if (group-- == 0) {
2733 [cell setTitle:@"Identifier"];
2734 [cell setValue:[package_ id]];
2735 } else if (row-- == 0) {
2736 [cell setTitle:@"Section"];
2737 NSString *section([package_ section]);
2738 [cell setValue:(section == nil ? @"n/a" : section)];
2739 } else if ([package_ size] != 0 && row-- == 0) {
2740 [cell setTitle:@"Expanded Size"];
2741 [cell setValue:SizeString([package_ size])];
2742 } else if ([package_ maintainer] != nil && row-- == 0) {
2743 [cell setTitle:@"Maintainer"];
2744 [cell setValue:[[package_ maintainer] name]];
2745 [cell setShowDisclosure:YES];
2746 [cell setShowSelection:YES];
2747 } else if ([package_ relationships] != nil && row-- == 0) {
2748 [cell setTitle:@"Package Relationships"];
2749 [cell setShowDisclosure:YES];
2750 [cell setShowSelection:YES];
2751 } else _assert(false);
2752 } else if ([package_ source] != nil && group-- == 0) {
2753 Source *source = [package_ source];
2754 NSString *description = [source description];
2757 NSString *label = [source label];
2759 label = [source uri];
2760 [cell setTitle:label];
2761 [cell setValue:[source version]];
2762 } else if (description != nil && ![description isEqualToString:[source label]] && row-- == 0) {
2763 [cell setValue:description];
2764 } else if ([source origin] != nil && row-- == 0) {
2765 [cell setTitle:@"Origin"];
2766 [cell setValue:[source origin]];
2767 } else _assert(false);
2768 } else _assert(false);
2773 - (BOOL) canSelectRow:(int)row {
2777 - (void) tableRowSelected:(NSNotification *)notification {
2778 int row = [table_ selectedRow];
2779 NSString *website = [package_ website];
2780 BOOL trusted = [[package_ source] trusted];
2781 NSString *installed = [package_ installed];
2784 + (website == nil ? 0 : 1)
2786 + (installed == nil ? 0 : 3)
2788 [delegate_ openURL:[NSURL URLWithString:[NSString stringWithFormat:@"mailto:%@?subject=%@",
2789 [[package_ maintainer] email],
2790 [[NSString stringWithFormat:@"regarding apt package \"%@\"", [package_ name]] stringByAddingPercentEscapes]
2792 else if (installed && row == 5
2793 + (website == nil ? 0 : 1)
2796 FileTable *files = [[[FileTable alloc] initWithBook:book_ database:database_] autorelease];
2797 [files setDelegate:delegate_];
2798 [files setPackage:package_];
2799 [book_ pushPage:files];
2800 } else if (website != nil && row == 3) {
2801 NSURL *url = [NSURL URLWithString:website];
2802 BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease];
2803 [browser setDelegate:delegate_];
2804 [book_ pushPage:browser];
2805 [browser loadURL:url];
2809 - (void) _clickButtonWithName:(NSString *)name {
2810 if ([name isEqualToString:@"Install"])
2811 [delegate_ installPackage:package_];
2812 else if ([name isEqualToString:@"Reinstall"])
2813 [delegate_ installPackage:package_];
2814 else if ([name isEqualToString:@"Remove"])
2815 [delegate_ removePackage:package_];
2816 else if ([name isEqualToString:@"Upgrade"])
2817 [delegate_ installPackage:package_];
2818 else _assert(false);
2821 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
2822 int count = [buttons_ count];
2823 _assert(count != 0);
2824 _assert(button <= count + 1);
2826 if (count != button - 1)
2827 [self _clickButtonWithName:[buttons_ objectAtIndex:(button - 1)]];
2832 - (void) _rightButtonClicked {
2833 int count = [buttons_ count];
2834 _assert(count != 0);
2837 [self _clickButtonWithName:[buttons_ objectAtIndex:0]];
2839 NSMutableArray *buttons = [NSMutableArray arrayWithCapacity:(count + 1)];
2840 [buttons addObjectsFromArray:buttons_];
2841 [buttons addObject:@"Cancel"];
2843 [delegate_ slideUp:[[[UIAlertSheet alloc]
2846 defaultButtonIndex:2
2853 - (NSString *) rightButtonTitle {
2854 int count = [buttons_ count];
2855 return count == 0 ? nil : count != 1 ? @"Modify" : [buttons_ objectAtIndex:0];
2858 - (NSString *) title {
2862 - (id) initWithBook:(RVBook *)book database:(Database *)database {
2863 if ((self = [super initWithBook:book]) != nil) {
2864 database_ = database;
2866 table_ = [[UIPreferencesTable alloc] initWithFrame:[self bounds]];
2867 [self addSubview:table_];
2869 [table_ setDataSource:self];
2870 [table_ setDelegate:self];
2872 buttons_ = [[NSMutableArray alloc] initWithCapacity:4];
2876 - (void) setPackage:(Package *)package {
2877 if (package_ != nil) {
2878 [package_ autorelease];
2887 if (description_ != nil) {
2888 [description_ release];
2892 [buttons_ removeAllObjects];
2894 if (package != nil) {
2895 package_ = [package retain];
2896 name_ = [[package id] retain];
2898 NSString *description([package description]);
2899 if (description == nil)
2900 description = [package tagline];
2901 if (description != nil) {
2902 description_ = [GetTextView(description, 12, true) retain];
2903 [description_ setTextColor:Black_];
2906 [table_ reloadData];
2908 if ([package_ source] == nil);
2909 else if ([package_ installed] == nil)
2910 [buttons_ addObject:@"Install"];
2911 else if ([package_ upgradable])
2912 [buttons_ addObject:@"Upgrade"];
2914 [buttons_ addObject:@"Reinstall"];
2915 if ([package_ installed] != nil)
2916 [buttons_ addObject:@"Remove"];
2920 - (void) resetViewAnimated:(BOOL)animated {
2921 [table_ resetViewAnimated:animated];
2924 - (void) reloadData {
2925 [self setPackage:[database_ packageWithName:name_]];
2926 [self reloadButtons];
2931 /* Package Table {{{ */
2932 @interface PackageTable : RVPage {
2933 _transient Database *database_;
2937 NSMutableArray *packages_;
2938 NSMutableArray *sections_;
2939 UISectionList *list_;
2942 - (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object;
2944 - (void) setDelegate:(id)delegate;
2945 - (void) setObject:(id)object;
2947 - (void) reloadData;
2948 - (void) resetCursor;
2950 - (UISectionList *) list;
2952 - (void) setShouldHideHeaderInShortLists:(BOOL)hide;
2956 @implementation PackageTable
2959 [list_ setDataSource:nil];
2964 [packages_ release];
2965 [sections_ release];
2970 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
2971 return [sections_ count];
2974 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
2975 return [[sections_ objectAtIndex:section] name];
2978 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
2979 return [[sections_ objectAtIndex:section] row];
2982 - (int) numberOfRowsInTable:(UITable *)table {
2983 return [packages_ count];
2986 - (float) table:(UITable *)table heightForRow:(int)row {
2990 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2992 reusing = [[[PackageCell alloc] init] autorelease];
2993 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
2997 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
3001 - (void) tableRowSelected:(NSNotification *)notification {
3002 int row = [[notification object] selectedRow];
3006 Package *package = [packages_ objectAtIndex:row];
3007 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
3008 [view setDelegate:delegate_];
3009 [view setPackage:package];
3010 [book_ pushPage:view];
3013 - (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object {
3014 if ((self = [super initWithBook:book]) != nil) {
3015 database_ = database;
3016 title_ = [title retain];
3018 object_ = object == nil ? nil : [object retain];
3020 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
3021 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
3023 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:YES];
3024 [list_ setDataSource:self];
3026 UITableColumn *column = [[[UITableColumn alloc]
3027 initWithTitle:@"Name"
3029 width:[self frame].size.width
3032 UITable *table = [list_ table];
3033 [table setSeparatorStyle:1];
3034 [table addTableColumn:column];
3035 [table setDelegate:self];
3036 [table setReusesTableCells:YES];
3038 [self addSubview:list_];
3043 - (void) setDelegate:(id)delegate {
3044 delegate_ = delegate;
3047 - (void) setObject:(id)object {
3053 object_ = [object retain];
3056 - (void) reloadData {
3057 NSArray *packages = [database_ packages];
3059 [packages_ removeAllObjects];
3060 [sections_ removeAllObjects];
3062 for (size_t i(0); i != [packages count]; ++i) {
3063 Package *package([packages objectAtIndex:i]);
3064 if ([[package performSelector:filter_ withObject:object_] boolValue])
3065 [packages_ addObject:package];
3068 Section *section = nil;
3070 for (size_t offset(0); offset != [packages_ count]; ++offset) {
3071 Package *package = [packages_ objectAtIndex:offset];
3072 NSString *name = [package index];
3074 if (section == nil || ![[section name] isEqualToString:name]) {
3075 section = [[[Section alloc] initWithName:name row:offset] autorelease];
3076 [sections_ addObject:section];
3079 [section addToCount];
3085 - (NSString *) title {
3089 - (void) resetViewAnimated:(BOOL)animated {
3090 [list_ resetViewAnimated:animated];
3093 - (void) resetCursor {
3094 [[list_ table] scrollPointVisibleAtTopLeft:CGPointMake(0, 0) animated:NO];
3097 - (UISectionList *) list {
3101 - (void) setShouldHideHeaderInShortLists:(BOOL)hide {
3102 [list_ setShouldHideHeaderInShortLists:hide];
3108 /* Browser Implementation {{{ */
3109 @implementation BrowserView
3112 WebView *webview = [webview_ webView];
3113 [webview setFrameLoadDelegate:nil];
3114 [webview setResourceLoadDelegate:nil];
3115 [webview setUIDelegate:nil];
3117 [scroller_ setDelegate:nil];
3118 [webview_ setDelegate:nil];
3120 [scroller_ release];
3123 [indicator_ release];
3129 - (void) loadURL:(NSURL *)url cachePolicy:(NSURLRequestCachePolicy)policy {
3130 NSMutableURLRequest *request = [NSMutableURLRequest
3133 timeoutInterval:30.0
3136 [request addValue:[NSString stringWithUTF8String:Firmware_] forHTTPHeaderField:@"X-Firmware"];
3137 [request addValue:[NSString stringWithUTF8String:Machine_] forHTTPHeaderField:@"X-Machine"];
3138 [request addValue:[NSString stringWithUTF8String:SerialNumber_] forHTTPHeaderField:@"X-Serial-Number"];
3140 [self loadRequest:request];
3144 - (void) loadURL:(NSURL *)url {
3145 [self loadURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy];
3148 // XXX: this needs to add the headers
3149 - (NSURLRequest *) _addHeadersToRequest:(NSURLRequest *)request {
3153 - (void) loadRequest:(NSURLRequest *)request {
3154 [webview_ loadRequest:request];
3157 - (void) reloadURL {
3158 NSURL *url = [[[urls_ lastObject] retain] autorelease];
3159 [urls_ removeLastObject];
3160 [self loadURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData];
3163 - (WebView *) webView {
3164 return [webview_ webView];
3167 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame {
3168 [scroller_ setContentSize:frame.size];
3171 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old {
3172 [self view:sender didSetFrame:frame];
3175 - (NSURLRequest *) webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource {
3176 return [self _addHeadersToRequest:request];
3179 - (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request {
3180 if ([[[request URL] scheme] isEqualToString:@"apptapp"])
3182 [self setBackButtonTitle:title_];
3183 BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease];
3184 [browser setDelegate:delegate_];
3185 [book_ pushPage:browser];
3186 [browser loadRequest:[self _addHeadersToRequest:request]];
3187 return [browser webView];
3190 - (void) webView:(WebView *)sender willClickElement:(id)element {
3191 if (![element respondsToSelector:@selector(href)])
3193 NSString *href = [element href];
3196 if ([href hasPrefix:@"apptapp://package/"]) {
3197 NSString *name = [href substringFromIndex:18];
3198 Package *package = [database_ packageWithName:name];
3199 if (package == nil) {
3200 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
3201 initWithTitle:@"Cannot Locate Package"
3202 buttons:[NSArray arrayWithObjects:@"Close", nil]
3203 defaultButtonIndex:0
3208 [sheet setBodyText:[NSString stringWithFormat:
3209 @"The package %@ cannot be found in your current sources. I might recommend installing more sources."
3212 [sheet popupAlertAnimated:YES];
3214 [self setBackButtonTitle:title_];
3215 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
3216 [view setDelegate:delegate_];
3217 [view setPackage:package];
3218 [book_ pushPage:view];
3223 - (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame {
3224 title_ = [title retain];
3225 [self setTitle:title];
3228 - (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame {
3229 if ([frame parentFrame] != nil)
3234 [indicator_ startAnimation];
3235 [self reloadButtons];
3237 if (title_ != nil) {
3242 [self setTitle:@"Loading..."];
3244 WebView *webview = [webview_ webView];
3245 NSString *href = [webview mainFrameURL];
3246 [urls_ addObject:[NSURL URLWithString:href]];
3248 CGRect webrect = [scroller_ frame];
3249 webrect.size.height = 0;
3250 [webview_ setFrame:webrect];
3253 - (void) _finishLoading {
3256 [indicator_ stopAnimation];
3257 [self reloadButtons];
3261 - (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
3262 if ([frame parentFrame] != nil)
3264 [self _finishLoading];
3267 - (void) webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
3268 if ([frame parentFrame] != nil)
3270 [self setTitle:[error localizedDescription]];
3271 [self _finishLoading];
3274 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3275 if ((self = [super initWithBook:book]) != nil) {
3276 database_ = database;
3279 struct CGRect bounds = [self bounds];
3281 UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:bounds] autorelease];
3282 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
3283 [self addSubview:pinstripe];
3285 scroller_ = [[UIScroller alloc] initWithFrame:bounds];
3286 [self addSubview:scroller_];
3288 [scroller_ setScrollingEnabled:YES];
3289 [scroller_ setAdjustForContentSizeChange:YES];
3290 [scroller_ setClipsSubviews:YES];
3291 [scroller_ setAllowsRubberBanding:YES];
3292 [scroller_ setScrollDecelerationFactor:0.99];
3293 [scroller_ setDelegate:self];
3295 CGRect webrect = [scroller_ bounds];
3296 webrect.size.height = 0;
3298 webview_ = [[UIWebView alloc] initWithFrame:webrect];
3299 [scroller_ addSubview:webview_];
3301 [webview_ setTilingEnabled:YES];
3302 [webview_ setTileSize:CGSizeMake(webrect.size.width, 500)];
3303 [webview_ setAutoresizes:YES];
3304 [webview_ setDelegate:self];
3305 //[webview_ setEnabledGestures:2];
3307 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:0];
3308 indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(281, 42, indsize.width, indsize.height)];
3309 [indicator_ setStyle:0];
3311 Package *package([database_ packageWithName:@"cydia"]);
3312 NSString *application = package == nil ? @"Cydia" : [NSString
3313 stringWithFormat:@"Cydia/%@",
3317 WebView *webview = [webview_ webView];
3318 [webview setApplicationNameForUserAgent:application];
3319 [webview setFrameLoadDelegate:self];
3320 [webview setResourceLoadDelegate:self];
3321 [webview setUIDelegate:self];
3323 urls_ = [[NSMutableArray alloc] initWithCapacity:16];
3327 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
3331 - (void) _leftButtonClicked {
3332 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
3333 initWithTitle:@"About Cydia Packager"
3334 buttons:[NSArray arrayWithObjects:@"Close", nil]
3335 defaultButtonIndex:0
3341 @"Copyright (C) 2008\n"
3342 "Jay Freeman (saurik)\n"
3343 "saurik@saurik.com\n"
3344 "http://www.saurik.com/\n"
3347 "http://www.theokorigroup.com/\n"
3349 "College of Creative Studies,\n"
3350 "University of California,\n"
3352 "http://www.ccs.ucsb.edu/"
3355 [sheet popupAlertAnimated:YES];
3358 - (void) _rightButtonClicked {
3363 - (NSString *) leftButtonTitle {
3367 - (NSString *) rightButtonTitle {
3368 return loading_ ? @"" : @"Reload";
3371 - (NSString *) title {
3375 - (NSString *) backButtonTitle {
3379 - (void) setPageActive:(BOOL)active {
3381 [book_ addSubview:indicator_];
3383 [indicator_ removeFromSuperview];
3386 - (void) resetViewAnimated:(BOOL)animated {
3392 @interface CYBook : RVBook <
3395 _transient Database *database_;
3397 UIProgressIndicator *indicator_;
3398 UITextLabel *prompt_;
3399 UIProgressBar *progress_;
3403 - (id) initWithFrame:(CGRect)frame database:(Database *)database;
3409 /* Install View {{{ */
3410 @interface InstallView : RVPage {
3411 _transient Database *database_;
3412 NSMutableArray *packages_;
3413 NSMutableArray *sections_;
3418 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3419 - (void) reloadData;
3423 @implementation InstallView
3426 [list_ setDataSource:nil];
3427 [list_ setDelegate:nil];
3429 [packages_ release];
3430 [sections_ release];
3432 [accessory_ release];
3436 - (int) numberOfRowsInTable:(UITable *)table {
3437 return [sections_ count] + 1;
3440 - (float) table:(UITable *)table heightForRow:(int)row {
3444 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
3446 reusing = [[[SectionCell alloc] init] autorelease];
3447 [(SectionCell *)reusing setSection:(row == 0 ? nil : [sections_ objectAtIndex:(row - 1)])];
3451 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
3455 - (void) tableRowSelected:(NSNotification *)notification {
3456 int row = [[notification object] selectedRow];
3467 title = @"All Packages";
3469 section = [sections_ objectAtIndex:(row - 1)];
3470 name = [section name];
3476 title = @"(No Section)";
3480 PackageTable *table = [[[PackageTable alloc]
3484 filter:@selector(isUninstalledInSection:)
3488 [table setDelegate:delegate_];
3490 [book_ pushPage:table];
3493 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3494 if ((self = [super initWithBook:book]) != nil) {
3495 database_ = database;
3497 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
3498 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
3500 list_ = [[UITable alloc] initWithFrame:[self bounds]];
3501 [self addSubview:list_];
3503 UITableColumn *column = [[[UITableColumn alloc]
3504 initWithTitle:@"Name"
3506 width:[self frame].size.width
3509 [list_ setDataSource:self];
3510 [list_ setSeparatorStyle:1];
3511 [list_ addTableColumn:column];
3512 [list_ setDelegate:self];
3513 [list_ setReusesTableCells:YES];
3519 - (void) reloadData {
3520 NSArray *packages = [database_ packages];
3522 [packages_ removeAllObjects];
3523 [sections_ removeAllObjects];
3525 for (size_t i(0); i != [packages count]; ++i) {
3526 Package *package([packages objectAtIndex:i]);
3527 if ([package valid] && [package installed] == nil)
3528 [packages_ addObject:package];
3531 [packages_ sortUsingSelector:@selector(compareBySection:)];
3533 Section *section = nil;
3534 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
3535 Package *package = [packages_ objectAtIndex:offset];
3536 NSString *name = [package section];
3538 if (section == nil || name != nil && ![[section name] isEqualToString:name]) {
3539 section = [[[Section alloc] initWithName:name row:offset] autorelease];
3540 [sections_ addObject:section];
3543 [section addToCount];
3549 - (void) resetViewAnimated:(BOOL)animated {
3550 [list_ resetViewAnimated:animated];
3553 - (NSString *) title {
3557 - (NSString *) backButtonTitle {
3561 - (UIView *) accessoryView {
3567 /* Changes View {{{ */
3568 @interface ChangesView : RVPage {
3569 _transient Database *database_;
3570 NSMutableArray *packages_;
3571 NSMutableArray *sections_;
3572 UISectionList *list_;
3576 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3577 - (void) reloadData;
3581 @implementation ChangesView
3584 [[list_ table] setDelegate:nil];
3585 [list_ setDataSource:nil];
3587 [packages_ release];
3588 [sections_ release];
3593 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
3594 return [sections_ count];
3597 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
3598 return [[sections_ objectAtIndex:section] name];
3601 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
3602 return [[sections_ objectAtIndex:section] row];
3605 - (int) numberOfRowsInTable:(UITable *)table {
3606 return [packages_ count];
3609 - (float) table:(UITable *)table heightForRow:(int)row {
3613 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
3615 reusing = [[[PackageCell alloc] init] autorelease];
3616 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
3620 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
3624 - (void) tableRowSelected:(NSNotification *)notification {
3625 int row = [[notification object] selectedRow];
3628 Package *package = [packages_ objectAtIndex:row];
3629 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
3630 [view setDelegate:delegate_];
3631 [view setPackage:package];
3632 [book_ pushPage:view];
3635 - (void) _leftButtonClicked {
3636 [(CYBook *)book_ update];
3637 [self reloadButtons];
3640 - (void) _rightButtonClicked {
3641 [delegate_ distUpgrade];
3644 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3645 if ((self = [super initWithBook:book]) != nil) {
3646 database_ = database;
3648 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
3649 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
3651 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:NO];
3652 [self addSubview:list_];
3654 [list_ setShouldHideHeaderInShortLists:NO];
3655 [list_ setDataSource:self];
3656 //[list_ setSectionListStyle:1];
3658 UITableColumn *column = [[[UITableColumn alloc]
3659 initWithTitle:@"Name"
3661 width:[self frame].size.width
3664 UITable *table = [list_ table];
3665 [table setSeparatorStyle:1];
3666 [table addTableColumn:column];
3667 [table setDelegate:self];
3668 [table setReusesTableCells:YES];
3674 - (void) reloadData {
3675 NSArray *packages = [database_ packages];
3677 [packages_ removeAllObjects];
3678 [sections_ removeAllObjects];
3680 for (size_t i(0); i != [packages count]; ++i) {
3681 Package *package([packages objectAtIndex:i]);
3682 if ([package installed] == nil && [package valid] || [package upgradable])
3683 [packages_ addObject:package];
3686 [packages_ sortUsingSelector:@selector(compareForChanges:)];
3688 Section *upgradable = [[[Section alloc] initWithName:@"Available Upgrades" row:0] autorelease];
3689 Section *section = nil;
3692 bool unseens = false;
3694 CFLocaleRef locale = CFLocaleCopyCurrent();
3695 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
3697 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
3698 Package *package = [packages_ objectAtIndex:offset];
3700 if ([package upgradable]) {
3702 [upgradable addToCount];
3705 NSDate *seen = [package seen];
3710 name = [@"n/a ?" retain];
3712 name = (NSString *) CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen);
3715 if (section == nil || ![[section name] isEqualToString:name]) {
3716 section = [[[Section alloc] initWithName:name row:offset] autorelease];
3717 [sections_ addObject:section];
3721 [section addToCount];
3725 CFRelease(formatter);
3729 Section *last = [sections_ lastObject];
3730 size_t count = [last count];
3731 [packages_ removeObjectsInRange:NSMakeRange([packages_ count] - count, count)];
3732 [sections_ removeLastObject];
3736 [sections_ insertObject:upgradable atIndex:0];
3739 [self reloadButtons];
3742 - (void) resetViewAnimated:(BOOL)animated {
3743 [list_ resetViewAnimated:animated];
3746 - (NSString *) leftButtonTitle {
3747 return [(CYBook *)book_ updating] ? nil : @"Refresh";
3750 - (NSString *) rightButtonTitle {
3751 return upgrades_ == 0 ? nil : [NSString stringWithFormat:@"Upgrade All (%u)", upgrades_];
3754 - (NSString *) title {
3760 /* Manage View {{{ */
3761 @interface ManageView : PackageTable {
3764 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3768 @implementation ManageView
3770 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3775 filter:@selector(isInstalledInSection:)
3781 - (NSString *) title {
3782 return @"Installed Packages";
3785 - (NSString *) backButtonTitle {
3786 return @"All Packages";
3791 /* Search View {{{ */
3792 @protocol SearchViewDelegate
3793 - (void) showKeyboard:(BOOL)show;
3796 @interface SearchView : RVPage {
3798 UISearchField *field_;
3799 UITransitionView *transition_;
3800 PackageTable *table_;
3801 UIPreferencesTable *advanced_;
3807 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3808 - (void) reloadData;
3812 @implementation SearchView
3816 [[field_ textTraits] setEditingDelegate:nil];
3818 [field_ setDelegate:nil];
3820 [accessory_ release];
3822 [transition_ release];
3824 [advanced_ release];
3829 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
3833 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
3835 case 0: return @"Advanced Search (Coming Soon!)";
3837 default: _assert(false);
3841 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
3845 default: _assert(false);
3849 - (void) _showKeyboard:(BOOL)show {
3850 CGSize keysize = [UIKeyboard defaultSize];
3851 CGRect keydown = [book_ pageBounds];
3852 CGRect keyup = keydown;
3853 keyup.size.height -= keysize.height - ButtonBarHeight_;
3855 float delay = KeyboardTime_ * ButtonBarHeight_ / keysize.height;
3857 UIFrameAnimation *animation = [[[UIFrameAnimation alloc] initWithTarget:[table_ list]] autorelease];
3858 [animation setSignificantRectFields:8];
3861 [animation setStartFrame:keydown];
3862 [animation setEndFrame:keyup];
3864 [animation setStartFrame:keyup];
3865 [animation setEndFrame:keydown];
3868 UIAnimator *animator = [UIAnimator sharedAnimator];
3871 addAnimations:[NSArray arrayWithObjects:animation, nil]
3872 withDuration:(KeyboardTime_ - delay)
3877 [animator performSelector:@selector(startAnimation:) withObject:animation afterDelay:delay];
3879 [delegate_ showKeyboard:show];
3882 - (void) textFieldDidBecomeFirstResponder:(UITextField *)field {
3883 [self _showKeyboard:YES];
3886 - (void) textFieldDidResignFirstResponder:(UITextField *)field {
3887 [self _showKeyboard:NO];
3890 - (void) keyboardInputChanged:(UIFieldEditor *)editor {
3892 NSString *text([field_ text]);
3893 [field_ setClearButtonStyle:(text == nil || [text length] == 0 ? 0 : 2)];
3899 - (void) textFieldClearButtonPressed:(UITextField *)field {
3903 - (void) keyboardInputShouldDelete:(id)input {
3907 - (BOOL) keyboardInput:(id)input shouldInsertText:(NSString *)text isMarkedText:(int)marked {
3908 if ([text length] != 1 || [text characterAtIndex:0] != '\n') {
3912 [field_ resignFirstResponder];
3917 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3918 if ((self = [super initWithBook:book]) != nil) {
3919 CGRect pageBounds = [book_ pageBounds];
3921 /*UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:pageBounds] autorelease];
3922 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
3923 [self addSubview:pinstripe];*/
3925 transition_ = [[UITransitionView alloc] initWithFrame:pageBounds];
3926 [self addSubview:transition_];
3928 advanced_ = [[UIPreferencesTable alloc] initWithFrame:pageBounds];
3930 [advanced_ setReusesTableCells:YES];
3931 [advanced_ setDataSource:self];
3932 [advanced_ reloadData];
3934 dimmed_ = [[UIView alloc] initWithFrame:pageBounds];
3935 CGColor dimmed(space_, 0, 0, 0, 0.5);
3936 [dimmed_ setBackgroundColor:dimmed];
3938 table_ = [[PackageTable alloc]
3942 filter:@selector(isSearchedForBy:)
3946 [table_ setShouldHideHeaderInShortLists:NO];
3947 [transition_ transition:0 toView:table_];
3949 CGRect cnfrect = {{1, 38}, {17, 18}};
3952 area.origin.x = cnfrect.size.width + 15;
3954 area.size.width = [self bounds].size.width - area.origin.x - 18;
3955 area.size.height = [UISearchField defaultHeight];
3957 field_ = [[UISearchField alloc] initWithFrame:area];
3959 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
3960 [field_ setFont:font];
3963 [field_ setPlaceholder:@"Package Names & Descriptions"];
3964 [field_ setPaddingTop:5];
3965 [field_ setDelegate:self];
3968 UITextTraits *traits = [field_ textTraits];
3969 [traits setEditingDelegate:self];
3970 [traits setReturnKeyType:6];
3971 [traits setAutoCapsType:0];
3972 [traits setAutoCorrectionType:1];
3975 UIPushButton *configure = [[[UIPushButton alloc] initWithFrame:cnfrect] autorelease];
3976 [configure setShowPressFeedback:YES];
3977 [configure setImage:[UIImage applicationImageNamed:@"advanced.png"]];
3978 [configure addTarget:self action:@selector(configurePushed) forEvents:1];
3980 accessory_ = [[UIView alloc] initWithFrame:CGRectMake(0, 6, cnfrect.size.width + area.size.width + 6 * 3, area.size.height + 30)];
3981 [accessory_ addSubview:field_];
3982 [accessory_ addSubview:configure];
3987 LKAnimation *animation = [LKTransition animation];
3988 [animation setType:@"oglFlip"];
3989 [animation setTimingFunction:[LKTimingFunction functionWithName:@"easeInEaseOut"]];
3990 [animation setFillMode:@"extended"];
3991 [animation setTransitionFlags:3];
3992 [animation setDuration:10];
3993 [animation setSpeed:0.35];
3994 [animation setSubtype:(flipped_ ? @"fromLeft" : @"fromRight")];
3995 [[transition_ _layer] addAnimation:animation forKey:0];
3996 [transition_ transition:0 toView:(flipped_ ? (UIView *) table_ : (UIView *) advanced_)];
3997 flipped_ = !flipped_;
4000 - (void) configurePushed {
4001 [field_ resignFirstResponder];
4005 - (void) resetViewAnimated:(BOOL)animated {
4008 [table_ resetViewAnimated:animated];
4011 - (void) reloadData {
4014 [table_ setObject:[field_ text]];
4015 [table_ reloadData];
4016 [table_ resetCursor];
4019 - (UIView *) accessoryView {
4023 - (NSString *) title {
4027 - (NSString *) backButtonTitle {
4031 - (void) setDelegate:(id)delegate {
4032 [table_ setDelegate:delegate];
4033 [super setDelegate:delegate];
4039 @implementation CYBook
4043 [indicator_ release];
4045 [progress_ release];
4049 - (NSString *) getTitleForPage:(RVPage *)page {
4050 return Simplify([super getTitleForPage:page]);
4058 [navbar_ setPrompt:@""];
4059 [navbar_ addSubview:overlay_];
4060 [indicator_ startAnimation];
4061 [prompt_ setText:@"Updating Database..."];
4062 [progress_ setProgress:0];
4067 detachNewThreadSelector:@selector(_update)
4076 [overlay_ removeFromSuperview];
4077 [indicator_ stopAnimation];
4078 [delegate_ reloadData];
4080 [self setPrompt:[NSString stringWithFormat:@"Last Updated: %@", GetLastUpdate()]];
4083 - (id) initWithFrame:(CGRect)frame database:(Database *)database {
4084 if ((self = [super initWithFrame:frame]) != nil) {
4085 database_ = database;
4088 [navbar_ setBarStyle:1];
4090 CGRect ovrrect = [navbar_ bounds];
4091 ovrrect.size.height = [UINavigationBar defaultSizeWithPrompt].height - [UINavigationBar defaultSize].height;
4093 overlay_ = [[UIView alloc] initWithFrame:ovrrect];
4095 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:2];
4096 unsigned indoffset = (ovrrect.size.height - indsize.height) / 2;
4097 CGRect indrect = {{indoffset, indoffset}, indsize};
4099 indicator_ = [[UIProgressIndicator alloc] initWithFrame:indrect];
4100 [indicator_ setStyle:(Advanced_ ? 2 : 3)];
4101 [overlay_ addSubview:indicator_];
4103 CGSize prmsize = {200, indsize.width};
4106 indoffset * 2 + indsize.width,
4107 (ovrrect.size.height - prmsize.height) / 2
4110 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 12);
4112 prompt_ = [[UITextLabel alloc] initWithFrame:prmrect];
4114 [prompt_ setColor:(Advanced_ ? White_ : Black_)];
4115 [prompt_ setBackgroundColor:Clear_];
4116 [prompt_ setFont:font];
4120 [overlay_ addSubview:prompt_];
4122 CGSize prgsize = {75, 100};
4125 ovrrect.size.width - prgsize.width - 10,
4126 (ovrrect.size.height - prgsize.height) / 2
4129 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
4130 [progress_ setStyle:0];
4131 [overlay_ addSubview:progress_];
4136 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
4139 status.setDelegate(self);
4141 [database_ updateWithStatus:status];
4144 performSelectorOnMainThread:@selector(_update_)
4152 - (void) setProgressError:(NSString *)error {
4154 performSelectorOnMainThread:@selector(_setProgressError:)
4160 - (void) setProgressTitle:(NSString *)title {
4162 performSelectorOnMainThread:@selector(_setProgressTitle:)
4168 - (void) setProgressPercent:(float)percent {
4171 - (void) addProgressOutput:(NSString *)output {
4173 performSelectorOnMainThread:@selector(_addProgressOutput:)
4179 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
4183 - (void) _setProgressError:(NSString *)error {
4184 [prompt_ setText:[NSString stringWithFormat:@"Error: %@", error]];
4187 - (void) _setProgressTitle:(NSString *)title {
4188 [prompt_ setText:[title stringByAppendingString:@"..."]];
4191 - (void) _addProgressOutput:(NSString *)output {
4196 @interface Cydia : UIApplication <
4197 ConfirmationViewDelegate,
4198 ProgressViewDelegate,
4207 UIButtonBar *buttonbar_;
4209 ConfirmationView *confirm_;
4210 NSMutableArray *essential_;
4212 Database *database_;
4213 ProgressView *progress_;
4217 UIKeyboard *keyboard_;
4219 InstallView *install_;
4220 ChangesView *changes_;
4221 ManageView *manage_;
4222 SearchView *search_;
4227 @implementation Cydia
4229 - (void) _reloadData {
4230 /*UIProgressHUD *hud = [[UIProgressHUD alloc] initWithWindow:window_];
4231 [hud setText:@"Reloading Data"];
4232 [overlay_ addSubview:hud];
4235 [database_ reloadData];
4237 if (Packages_ == nil) {
4238 Packages_ = [[NSMutableDictionary alloc] initWithCapacity:128];
4239 [Metadata_ setObject:Packages_ forKey:@"Packages"];
4243 [essential_ removeAllObjects];
4245 NSArray *packages = [database_ packages];
4246 for (int i(0), e([packages count]); i != e; ++i) {
4247 Package *package = [packages objectAtIndex:i];
4248 if ([package upgradable]) {
4249 if ([package essential])
4250 [essential_ addObject:package];
4256 NSString *badge([[NSNumber numberWithInt:changes] stringValue]);
4257 [buttonbar_ setBadgeValue:badge forButton:3];
4258 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
4259 [buttonbar_ setBadgeAnimated:YES forButton:3];
4260 [self setApplicationBadge:badge];
4262 [buttonbar_ setBadgeValue:nil forButton:3];
4263 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
4264 [buttonbar_ setBadgeAnimated:NO forButton:3];
4265 [self removeApplicationBadge];
4269 _assert([Metadata_ writeToFile:@"/var/lib/cydia/metadata.plist" atomically:YES] == YES);
4273 /* XXX: this is just stupid */
4275 [install_ reloadData];
4277 [changes_ reloadData];
4279 [manage_ reloadData];
4281 [search_ reloadData];
4285 if ([packages count] == 0);
4286 else if (!Loaded_) {
4289 } else if (!Ignored_ && [essential_ count] != 0) {
4290 int count = [essential_ count];
4292 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
4293 initWithTitle:[NSString stringWithFormat:@"%d Essential Upgrade%@", count, (count == 1 ? @"" : @"s")]
4294 buttons:[NSArray arrayWithObjects:@"Upgrade Essential", @"Ignore (Temporary)", nil]
4295 defaultButtonIndex:0
4300 [sheet setBodyText:@"One or more essential packages are currently out of date. If these packages are not upgraded you are likely to encounter errors."];
4301 [sheet popupAlertAnimated:YES];
4305 [hud removeFromSuperview];*/
4308 - (void) reloadData {
4309 @synchronized (self) {
4310 if (confirm_ == nil)
4316 pkgProblemResolver *resolver = [database_ resolver];
4318 resolver->InstallProtect();
4319 if (!resolver->Resolve(true))
4324 [database_ prepare];
4326 if ([database_ cache]->BrokenCount() == 0)
4327 confirm_ = [[ConfirmationView alloc] initWithView:underlay_ database:database_ delegate:self];
4329 NSMutableArray *broken = [NSMutableArray arrayWithCapacity:16];
4330 NSArray *packages = [database_ packages];
4332 for (size_t i(0); i != [packages count]; ++i) {
4333 Package *package = [packages objectAtIndex:i];
4334 if ([package broken])
4335 [broken addObject:[package name]];
4338 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
4339 initWithTitle:[NSString stringWithFormat:@"%d Broken Packages", [database_ cache]->BrokenCount()]
4340 buttons:[NSArray arrayWithObjects:@"Okay", nil]
4341 defaultButtonIndex:0
4346 [sheet setBodyText:[NSString stringWithFormat:@"The following packages have unmet dependencies:\n\n%@", [broken componentsJoinedByString:@"\n"]]];
4347 [sheet popupAlertAnimated:YES];
4353 - (void) installPackage:(Package *)package {
4354 @synchronized (self) {
4361 - (void) removePackage:(Package *)package {
4362 @synchronized (self) {
4369 - (void) distUpgrade {
4370 @synchronized (self) {
4371 [database_ upgrade];
4377 @synchronized (self) {
4385 [overlay_ removeFromSuperview];
4389 detachNewThreadSelector:@selector(perform)
4396 - (void) bootstrap_ {
4398 [database_ upgrade];
4399 [database_ prepare];
4400 [database_ perform];
4403 - (void) bootstrap {
4405 detachNewThreadSelector:@selector(bootstrap_)
4408 title:@"Bootstrap Install..."
4412 - (void) progressViewIsComplete:(ProgressView *)progress {
4413 @synchronized (self) {
4416 if (confirm_ != nil) {
4417 [underlay_ addSubview:overlay_];
4418 [confirm_ removeFromSuperview];
4425 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
4426 NSString *context = [sheet context];
4427 if ([context isEqualToString:@"upgrade"])
4430 @synchronized (self) {
4431 for (int i = 0, e = [essential_ count]; i != e; ++i) {
4432 Package *essential = [essential_ objectAtIndex:i];
4433 [essential install];
4445 default: _assert(false);
4451 - (void) setPage:(RVPage *)page {
4452 [page resetViewAnimated:NO];
4453 [page setDelegate:self];
4454 [book_ setPage:page];
4457 - (RVPage *) _setHomePage {
4458 BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease];
4459 [self setPage:browser];
4460 [browser loadURL:[NSURL URLWithString:@"http://cydia.saurik.com/"]];
4464 - (void) buttonBarItemTapped:(id)sender {
4465 unsigned tag = [sender tag];
4467 [book_ resetViewAnimated:YES];
4472 case 1: [self _setHomePage]; break;
4474 case 2: [self setPage:install_]; break;
4475 case 3: [self setPage:changes_]; break;
4476 case 4: [self setPage:manage_]; break;
4477 case 5: [self setPage:search_]; break;
4479 default: _assert(false);
4485 - (void) applicationWillSuspend {
4486 [super applicationWillSuspend];
4489 if (FW_LEAST(1,1,3))
4490 notify_post("com.apple.language.changed");
4492 system("launchctl stop com.apple.SpringBoard");
4495 - (void) applicationDidFinishLaunching:(id)unused {
4496 _assert(pkgInitConfig(*_config));
4497 _assert(pkgInitSystem(*_config, _system));
4502 essential_ = [[NSMutableArray alloc] initWithCapacity:4];
4504 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
4505 window_ = [[UIWindow alloc] initWithContentRect:screenrect];
4507 [window_ orderFront: self];
4508 [window_ makeKey: self];
4509 [window_ _setHidden: NO];
4511 database_ = [[Database alloc] init];
4512 progress_ = [[ProgressView alloc] initWithFrame:[window_ bounds] database:database_ delegate:self];
4513 [database_ setDelegate:progress_];
4514 [window_ setContentView:progress_];
4516 underlay_ = [[UIView alloc] initWithFrame:[progress_ bounds]];
4517 [progress_ setContentView:underlay_];
4519 overlay_ = [[UIView alloc] initWithFrame:[underlay_ bounds]];
4522 [underlay_ addSubview:overlay_];
4524 book_ = [[CYBook alloc] initWithFrame:CGRectMake(
4525 0, 0, screenrect.size.width, screenrect.size.height - 48
4526 ) database:database_];
4528 [book_ setDelegate:self];
4530 [overlay_ addSubview:book_];
4532 NSArray *buttonitems = [NSArray arrayWithObjects:
4533 [NSDictionary dictionaryWithObjectsAndKeys:
4534 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
4535 @"home-up.png", kUIButtonBarButtonInfo,
4536 @"home-dn.png", kUIButtonBarButtonSelectedInfo,
4537 [NSNumber numberWithInt:1], kUIButtonBarButtonTag,
4538 self, kUIButtonBarButtonTarget,
4539 @"Home", kUIButtonBarButtonTitle,
4540 @"0", kUIButtonBarButtonType,
4543 [NSDictionary dictionaryWithObjectsAndKeys:
4544 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
4545 @"install-up.png", kUIButtonBarButtonInfo,
4546 @"install-dn.png", kUIButtonBarButtonSelectedInfo,
4547 [NSNumber numberWithInt:2], kUIButtonBarButtonTag,
4548 self, kUIButtonBarButtonTarget,
4549 @"Install", kUIButtonBarButtonTitle,
4550 @"0", kUIButtonBarButtonType,
4553 [NSDictionary dictionaryWithObjectsAndKeys:
4554 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
4555 @"changes-up.png", kUIButtonBarButtonInfo,
4556 @"changes-dn.png", kUIButtonBarButtonSelectedInfo,
4557 [NSNumber numberWithInt:3], kUIButtonBarButtonTag,
4558 self, kUIButtonBarButtonTarget,
4559 @"Changes", kUIButtonBarButtonTitle,
4560 @"0", kUIButtonBarButtonType,
4563 [NSDictionary dictionaryWithObjectsAndKeys:
4564 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
4565 @"manage-up.png", kUIButtonBarButtonInfo,
4566 @"manage-dn.png", kUIButtonBarButtonSelectedInfo,
4567 [NSNumber numberWithInt:4], kUIButtonBarButtonTag,
4568 self, kUIButtonBarButtonTarget,
4569 @"Manage", kUIButtonBarButtonTitle,
4570 @"0", kUIButtonBarButtonType,
4573 [NSDictionary dictionaryWithObjectsAndKeys:
4574 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
4575 @"search-up.png", kUIButtonBarButtonInfo,
4576 @"search-dn.png", kUIButtonBarButtonSelectedInfo,
4577 [NSNumber numberWithInt:5], kUIButtonBarButtonTag,
4578 self, kUIButtonBarButtonTarget,
4579 @"Search", kUIButtonBarButtonTitle,
4580 @"0", kUIButtonBarButtonType,
4584 buttonbar_ = [[UIButtonBar alloc]
4586 withFrame:CGRectMake(
4587 0, screenrect.size.height - ButtonBarHeight_,
4588 screenrect.size.width, ButtonBarHeight_
4590 withItemList:buttonitems
4593 [buttonbar_ setDelegate:self];
4594 [buttonbar_ setBarStyle:1];
4595 [buttonbar_ setButtonBarTrackingMode:2];
4597 int buttons[5] = {1, 2, 3, 4, 5};
4598 [buttonbar_ registerButtonGroup:0 withButtons:buttons withCount:5];
4599 [buttonbar_ showButtonGroup:0 withDuration:0];
4601 for (int i = 0; i != 5; ++i)
4602 [[buttonbar_ viewWithTag:(i + 1)] setFrame:CGRectMake(
4603 i * 64 + 2, 1, 60, ButtonBarHeight_
4606 [buttonbar_ showSelectionForButton:1];
4607 [overlay_ addSubview:buttonbar_];
4609 [UIKeyboard initImplementationNow];
4610 CGSize keysize = [UIKeyboard defaultSize];
4611 CGRect keyrect = {{0, [overlay_ bounds].size.height}, keysize};
4612 keyboard_ = [[UIKeyboard alloc] initWithFrame:keyrect];
4613 [[UIKeyboardImpl sharedInstance] setSoundsEnabled:(Sounds_Keyboard_ ? YES : NO)];
4614 [overlay_ addSubview:keyboard_];
4616 install_ = [[InstallView alloc] initWithBook:book_ database:database_];
4617 changes_ = [[ChangesView alloc] initWithBook:book_ database:database_];
4618 manage_ = [[ManageView alloc] initWithBook:book_ database:database_];
4619 search_ = [[SearchView alloc] initWithBook:book_ database:database_];
4621 [progress_ resetView];
4627 [self _setHomePage];
4630 - (void) showKeyboard:(BOOL)show {
4631 CGSize keysize = [UIKeyboard defaultSize];
4632 CGRect keydown = {{0, [overlay_ bounds].size.height}, keysize};
4633 CGRect keyup = keydown;
4634 keyup.origin.y -= keysize.height;
4636 UIFrameAnimation *animation = [[[UIFrameAnimation alloc] initWithTarget:keyboard_] autorelease];
4637 [animation setSignificantRectFields:2];
4640 [animation setStartFrame:keydown];
4641 [animation setEndFrame:keyup];
4642 [keyboard_ activate];
4644 [animation setStartFrame:keyup];
4645 [animation setEndFrame:keydown];
4646 [keyboard_ deactivate];
4649 [[UIAnimator sharedAnimator]
4650 addAnimations:[NSArray arrayWithObjects:animation, nil]
4651 withDuration:KeyboardTime_
4656 - (void) slideUp:(UIAlertSheet *)alert {
4657 [alert presentSheetInView:overlay_];
4662 void AddPreferences(NSString *plist) {
4663 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
4665 NSMutableDictionary *settings = [[[NSMutableDictionary alloc] initWithContentsOfFile:plist] autorelease];
4666 _assert(settings != NULL);
4667 NSMutableArray *items = [settings objectForKey:@"items"];
4671 for (size_t i(0); i != [items count]; ++i) {
4672 NSMutableDictionary *item([items objectAtIndex:i]);
4673 NSString *label = [item objectForKey:@"label"];
4674 if (label != nil && [label isEqualToString:@"Cydia"]) {
4681 for (size_t i(0); i != [items count]; ++i) {
4682 NSDictionary *item([items objectAtIndex:i]);
4683 NSString *label = [item objectForKey:@"label"];
4684 if (label != nil && [label isEqualToString:@"General"]) {
4685 [items insertObject:[NSDictionary dictionaryWithObjectsAndKeys:
4686 @"CydiaSettings", @"bundle",
4687 @"PSLinkCell", @"cell",
4688 [NSNumber numberWithBool:YES], @"hasIcon",
4689 [NSNumber numberWithBool:YES], @"isController",
4691 nil] atIndex:(i + 1)];
4697 _assert([settings writeToFile:plist atomically:YES] == YES);
4704 id Alloc_(id self, SEL selector) {
4705 id object = alloc_(self, selector);
4706 fprintf(stderr, "[%s]A-%p\n", self->isa->name, object);
4711 id Dealloc_(id self, SEL selector) {
4712 id object = dealloc_(self, selector);
4713 fprintf(stderr, "[%s]D-%p\n", self->isa->name, object);
4717 int main(int argc, char *argv[]) {
4718 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
4720 bootstrap_ = argc > 1 && strcmp(argv[1], "--bootstrap") == 0;
4722 Home_ = NSHomeDirectory();
4725 NSString *plist = [Home_ stringByAppendingString:@"/Library/Preferences/com.apple.preferences.sounds.plist"];
4726 if (NSDictionary *sounds = [NSDictionary dictionaryWithContentsOfFile:plist])
4727 if (NSNumber *keyboard = [sounds objectForKey:@"keyboard"])
4728 Sounds_Keyboard_ = [keyboard boolValue];
4734 /*Method alloc = class_getClassMethod([NSObject class], @selector(alloc));
4735 alloc_ = alloc->method_imp;
4736 alloc->method_imp = (IMP) &Alloc_;*/
4738 /*Method dealloc = class_getClassMethod([NSObject class], @selector(dealloc));
4739 dealloc_ = dealloc->method_imp;
4740 dealloc->method_imp = (IMP) &Dealloc_;*/
4742 if (NSDictionary *sysver = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]) {
4743 if (NSString *prover = [sysver valueForKey:@"ProductVersion"]) {
4744 Firmware_ = strdup([prover UTF8String]);
4745 NSArray *versions = [prover componentsSeparatedByString:@"."];
4746 int count = [versions count];
4747 Major_ = count > 0 ? [[versions objectAtIndex:0] intValue] : 0;
4748 Minor_ = count > 1 ? [[versions objectAtIndex:1] intValue] : 0;
4749 BugFix_ = count > 2 ? [[versions objectAtIndex:2] intValue] : 0;
4754 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
4755 char *machine = new char[size];
4756 sysctlbyname("hw.machine", machine, &size, NULL, 0);
4759 if (CFMutableDictionaryRef dict = IOServiceMatching("IOPlatformExpertDevice"))
4760 if (io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, dict)) {
4761 if (CFTypeRef serial = IORegistryEntryCreateCFProperty(service, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0)) {
4762 SerialNumber_ = strdup(CFStringGetCStringPtr((CFStringRef) serial, CFStringGetSystemEncoding()));
4766 IOObjectRelease(service);
4769 /*AddPreferences(@"/Applications/Preferences.app/Settings-iPhone.plist");
4770 AddPreferences(@"/Applications/Preferences.app/Settings-iPod.plist");*/
4772 if ((Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"]) == NULL)
4773 Metadata_ = [[NSMutableDictionary alloc] initWithCapacity:2];
4775 Packages_ = [Metadata_ objectForKey:@"Packages"];
4777 setenv("CYDIA", "", _not(int));
4778 if (access("/User", F_OK) != 0)
4779 system("/usr/libexec/cydia/firmware.sh");
4781 space_ = CGColorSpaceCreateDeviceRGB();
4783 Black_.Set(space_, 0.0, 0.0, 0.0, 1.0);
4784 Clear_.Set(space_, 0.0, 0.0, 0.0, 0.0);
4785 Red_.Set(space_, 1.0, 0.0, 0.0, 1.0);
4786 White_.Set(space_, 1.0, 1.0, 1.0, 1.0);
4788 int value = UIApplicationMain(argc, argv, [Cydia class]);
4790 CGColorSpaceRelease(space_);