1 /* Cydia - iPhone UIKit Front-End for Debian APT
2 * Copyright (C) 2008 Jay Freeman (saurik)
6 * Redistribution and use in source and binary
7 * forms, with or without modification, are permitted
8 * provided that the following conditions are met:
10 * 1. Redistributions of source code must retain the
11 * above copyright notice, this list of conditions
12 * and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the
14 * above copyright notice, this list of conditions
15 * and the following disclaimer in the documentation
16 * and/or other materials provided with the
18 * 3. The name of the author may not be used to endorse
19 * or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS''
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
24 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
33 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
35 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 #define UITextTraits UITextInputTraits
40 #define textTraits textInputTraits
41 #define setAutoCapsType setAutocapitalizationType
42 #define setAutoCorrectionType setAutocorrectionType
43 #define setPreferredKeyboardType setKeyboardType
46 /* #include Directives {{{ */
47 #include <objc/objc.h>
48 #include <objc/runtime.h>
50 #include <CoreGraphics/CoreGraphics.h>
51 #include <GraphicsServices/GraphicsServices.h>
52 #include <Foundation/Foundation.h>
53 #include <UIKit/UIKit.h>
54 #include <WebCore/DOMHTML.h>
56 #import "BrowserView.h"
58 #import "UICaboodle.h"
60 #include <WebKit/WebFrame.h>
61 #include <WebKit/WebView.h>
66 #include <ext/stdio_filebuf.h>
68 #include <apt-pkg/acquire.h>
69 #include <apt-pkg/acquire-item.h>
70 #include <apt-pkg/algorithms.h>
71 #include <apt-pkg/cachefile.h>
72 #include <apt-pkg/clean.h>
73 #include <apt-pkg/configuration.h>
74 #include <apt-pkg/debmetaindex.h>
75 #include <apt-pkg/error.h>
76 #include <apt-pkg/init.h>
77 #include <apt-pkg/mmap.h>
78 #include <apt-pkg/pkgrecords.h>
79 #include <apt-pkg/sha1.h>
80 #include <apt-pkg/sourcelist.h>
81 #include <apt-pkg/sptr.h>
83 #include <sys/sysctl.h>
88 #include <mach-o/nlist.h>
99 /* iPhoneOS 2.0 Compatibility {{{ */
101 @interface UICGColor : NSObject {
104 - (id) initWithCGColor:(CGColorRef)color;
110 + (id)systemFontOfSize:(float)fp8;
111 + (id)boldSystemFontOfSize:(float)fp8;
112 - (UIFont *) fontWithSize:(CGFloat)size;
115 @interface NSObject (iPhoneOS)
116 - (CGColorRef) cgColor;
117 - (CGColorRef) CGColor;
121 @implementation NSObject (iPhoneOS)
123 - (CGColorRef) cgColor {
124 return [self CGColor];
127 - (CGColorRef) CGColor {
128 return (CGColorRef) self;
132 [[[[objc_getClass("UICGColor") alloc] initWithCGColor:[self CGColor]] autorelease] set];
137 @interface UITextView (iPhoneOS)
138 - (void) setTextSize:(float)size;
141 @implementation UITextView (iPhoneOS)
143 - (void) setTextSize:(float)size {
144 [self setFont:[[self font] fontWithSize:size]];
151 @interface UIApplication (IdleTimer)
152 - (void) setIdleTimerDisabled:(char)arg0;
157 kUIProgressIndicatorStyleLargeWhite = 0,
158 kUIProgressIndicatorStyleMediumWhite = 1,
159 kUIProgressIndicatorStyleSmallWhite = 3,
160 kUIProgressIndicatorStyleSmallBlack = 4
161 } UIProgressIndicatorStyle;
164 kUIProgressIndicatorStyleMediumWhite = 0,
165 kUIProgressIndicatorStyleSmallWhite = 2,
166 kUIProgressIndicatorStyleSmallBlack = 3
167 } UIProgressIndicatorStyle;
171 kUIControlEventMouseDown = 1 << 0,
172 kUIControlEventMouseMovedInside = 1 << 2, // mouse moved inside control target
173 kUIControlEventMouseMovedOutside = 1 << 3, // mouse moved outside control target
174 kUIControlEventMouseUpInside = 1 << 6, // mouse up inside control target
175 kUIControlEventMouseUpOutside = 1 << 7, // mouse up outside control target
176 kUIControlAllEvents = (kUIControlEventMouseDown | kUIControlEventMouseMovedInside | kUIControlEventMouseMovedOutside | kUIControlEventMouseUpInside | kUIControlEventMouseUpOutside)
177 } UIControlEventMasks;
179 @interface NSString (UIKit)
180 - (NSString *) stringByAddingPercentEscapes;
181 - (NSString *) stringByReplacingCharacter:(unsigned short)arg0 withCharacter:(unsigned short)arg1;
184 @interface NSString (Cydia)
185 + (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length;
186 - (NSComparisonResult) compareByPath:(NSString *)other;
189 @implementation NSString (Cydia)
191 + (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length {
192 char data[length + 1];
193 memcpy(data, bytes, length);
195 return [NSString stringWithUTF8String:data];
198 - (NSComparisonResult) compareByPath:(NSString *)other {
199 NSString *prefix = [self commonPrefixWithString:other options:0];
200 size_t length = [prefix length];
202 NSRange lrange = NSMakeRange(length, [self length] - length);
203 NSRange rrange = NSMakeRange(length, [other length] - length);
205 lrange = [self rangeOfString:@"/" options:0 range:lrange];
206 rrange = [other rangeOfString:@"/" options:0 range:rrange];
208 NSComparisonResult value;
210 if (lrange.location == NSNotFound && rrange.location == NSNotFound)
211 value = NSOrderedSame;
212 else if (lrange.location == NSNotFound)
213 value = NSOrderedAscending;
214 else if (rrange.location == NSNotFound)
215 value = NSOrderedDescending;
217 value = NSOrderedSame;
219 NSString *lpath = lrange.location == NSNotFound ? [self substringFromIndex:length] :
220 [self substringWithRange:NSMakeRange(length, lrange.location - length)];
221 NSString *rpath = rrange.location == NSNotFound ? [other substringFromIndex:length] :
222 [other substringWithRange:NSMakeRange(length, rrange.location - length)];
224 NSComparisonResult result = [lpath compare:rpath];
225 return result == NSOrderedSame ? value : result;
230 /* Perl-Compatible RegEx {{{ */
240 Pcre(const char *regex) :
245 code_ = pcre_compile(regex, 0, &error, &offset, NULL);
248 fprintf(stderr, "%d:%s\n", offset, error);
252 pcre_fullinfo(code_, study_, PCRE_INFO_CAPTURECOUNT, &capture_);
253 matches_ = new int[(capture_ + 1) * 3];
261 NSString *operator [](size_t match) {
262 return [NSString stringWithUTF8Bytes:(data_ + matches_[match * 2]) length:(matches_[match * 2 + 1] - matches_[match * 2])];
265 bool operator ()(NSString *data) {
266 // XXX: length is for characters, not for bytes
267 return operator ()([data UTF8String], [data length]);
270 bool operator ()(const char *data, size_t size) {
272 return pcre_exec(code_, study_, data, size, 0, 0, matches_, (capture_ + 1) * 3) >= 0;
276 /* Mime Addresses {{{ */
277 @interface Address : NSObject {
283 - (NSString *) address;
285 + (Address *) addressWithString:(NSString *)string;
286 - (Address *) initWithString:(NSString *)string;
289 @implementation Address
298 - (NSString *) name {
302 - (NSString *) address {
306 + (Address *) addressWithString:(NSString *)string {
307 return [[[Address alloc] initWithString:string] autorelease];
310 + (NSArray *) _attributeKeys {
311 return [NSArray arrayWithObjects:@"address", @"name", nil];
314 - (NSArray *) attributeKeys {
315 return [[self class] _attributeKeys];
318 + (BOOL) isKeyExcludedFromWebScript:(const char *)name {
319 return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name];
322 - (Address *) initWithString:(NSString *)string {
323 if ((self = [super init]) != nil) {
324 const char *data = [string UTF8String];
325 size_t size = [string length];
327 static Pcre address_r("^\"?(.*)\"? <([^>]*)>$");
329 if (address_r(data, size)) {
330 name_ = [address_r[1] retain];
331 address_ = [address_r[2] retain];
333 name_ = [[NSString alloc]
336 encoding:kCFStringEncodingUTF8
346 /* CoreGraphics Primitives {{{ */
357 CGColor(CGColorSpaceRef space, float red, float green, float blue, float alpha) :
360 Set(space, red, green, blue, alpha);
365 CGColorRelease(color_);
372 void Set(CGColorSpaceRef space, float red, float green, float blue, float alpha) {
374 float color[] = {red, green, blue, alpha};
375 color_ = CGColorCreate(space, color);
378 operator CGColorRef() {
393 /* Right Alignment {{{ */
394 @interface UIRightTextLabel : UITextLabel {
395 float _savedRightEdgeX;
396 BOOL _sizedtofit_flag;
399 - (void) setFrame:(CGRect)frame;
400 - (void) setText:(NSString *)text;
401 - (void) realignText;
404 @implementation UIRightTextLabel
406 - (void) setFrame:(CGRect)frame {
407 [super setFrame:frame];
408 if (_sizedtofit_flag == NO) {
409 _savedRightEdgeX = frame.origin.x;
414 - (void) setText:(NSString *)text {
415 [super setText:text];
419 - (void) realignText {
420 CGRect oldFrame = [self frame];
422 _sizedtofit_flag = YES;
423 [self sizeToFit]; // shrink down size so I can right align it
425 CGRect newFrame = [self frame];
427 oldFrame.origin.x = _savedRightEdgeX - newFrame.size.width;
428 oldFrame.size.width = newFrame.size.width;
429 [super setFrame:oldFrame];
430 _sizedtofit_flag = NO;
436 extern "C" void UISetColor(CGColorRef color);
438 /* Random Global Variables {{{ */
439 static const int PulseInterval_ = 50000;
440 static const int ButtonBarHeight_ = 48;
441 static const float KeyboardTime_ = 0.3f;
442 static const char * const SpringBoard_ = "/System/Library/LaunchDaemons/com.apple.SpringBoard.plist";
444 static CGColor Blue_;
445 static CGColor Blueish_;
446 static CGColor Black_;
447 static CGColor Clear_;
449 static CGColor White_;
450 static CGColor Gray_;
452 static NSString *Home_;
453 static BOOL Sounds_Keyboard_;
455 static BOOL Advanced_;
457 static BOOL Ignored_;
459 static UIFont *Font12_;
460 static UIFont *Font12Bold_;
461 static UIFont *Font14_;
462 static UIFont *Font18Bold_;
463 static UIFont *Font22Bold_;
465 const char *Firmware_ = NULL;
466 const char *Machine_ = NULL;
467 const char *SerialNumber_ = NULL;
474 CGColorSpaceRef space_;
476 #define FW_LEAST(major, minor, bugfix) \
477 (major < Major_ || major == Major_ && \
478 (minor < Minor_ || minor == Minor_ && \
484 static NSDictionary *SectionMap_;
485 static NSMutableDictionary *Metadata_;
486 static _transient NSMutableDictionary *Settings_;
487 static _transient NSString *Role_;
488 static _transient NSMutableDictionary *Packages_;
489 static _transient NSMutableDictionary *Sections_;
490 static _transient NSMutableDictionary *Sources_;
491 static bool Changed_;
494 NSString *GetLastUpdate() {
495 NSDate *update = [Metadata_ objectForKey:@"LastUpdate"];
498 return @"Never or Unknown";
500 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, Locale_, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
501 CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) update);
503 CFRelease(formatter);
505 return [(NSString *) formatted autorelease];
508 /* Display Helpers {{{ */
509 inline float Interpolate(float begin, float end, float fraction) {
510 return (end - begin) * fraction + begin;
513 NSString *SizeString(double size) {
515 while (size > 1024) {
520 static const char *powers_[] = {"B", "kB", "MB", "GB"};
522 return [NSString stringWithFormat:@"%.1f%s", size, powers_[power]];
525 NSString *StripVersion(NSString *version) {
526 NSRange colon = [version rangeOfString:@":"];
527 if (colon.location != NSNotFound)
528 version = [version substringFromIndex:(colon.location + 1)];
532 static const float TextViewOffset_ = 22;
534 UITextView *GetTextView(NSString *value, float left, bool html) {
535 UITextView *text([[[UITextView alloc] initWithFrame:CGRectMake(left, 3, 310 - left, 1000)] autorelease]);
536 [text setEditable:NO];
537 [text setTextSize:16];
539 [text setHTML:value];
541 [text setText:value];
542 [text setEnabled:NO];
544 [text setBackgroundColor:Clear_];
546 CGRect frame = [text frame];
547 [text setFrame:frame];
548 CGRect rect = [text visibleTextRect];
549 frame.size.height = rect.size.height;
550 [text setFrame:frame];
555 NSString *Simplify(NSString *title) {
556 const char *data = [title UTF8String];
557 size_t size = [title length];
559 static Pcre square_r("^\\[(.*)\\]$");
560 if (square_r(data, size))
561 return Simplify(square_r[1]);
563 static Pcre paren_r("^\\((.*)\\)$");
564 if (paren_r(data, size))
565 return Simplify(paren_r[1]);
567 static Pcre title_r("^(.*?) \\(.*\\)$");
568 if (title_r(data, size))
569 return Simplify(title_r[1]);
575 bool isSectionVisible(NSString *section) {
576 NSDictionary *metadata = [Sections_ objectForKey:section];
577 NSNumber *hidden = metadata == nil ? nil : [metadata objectForKey:@"Hidden"];
578 return hidden == nil || ![hidden boolValue];
581 /* Delegate Prototypes {{{ */
585 @interface NSObject (ProgressDelegate)
588 @implementation NSObject(ProgressDelegate)
590 - (void) _setProgressError:(NSArray *)args {
591 [self performSelector:@selector(setProgressError:forPackage:)
592 withObject:[args objectAtIndex:0]
593 withObject:([args count] == 1 ? nil : [args objectAtIndex:1])
599 @protocol ProgressDelegate
600 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id;
601 - (void) setProgressTitle:(NSString *)title;
602 - (void) setProgressPercent:(float)percent;
603 - (void) addProgressOutput:(NSString *)output;
606 @protocol ConfigurationDelegate
607 - (void) repairWithSelector:(SEL)selector;
608 - (void) setConfigurationData:(NSString *)data;
611 @protocol CydiaDelegate
612 - (void) installPackage:(Package *)package;
613 - (void) removePackage:(Package *)package;
614 - (void) slideUp:(UIAlertSheet *)alert;
615 - (void) distUpgrade;
618 - (void) askForSettings;
619 - (UIProgressHUD *) addProgressHUD;
623 /* Status Delegation {{{ */
625 public pkgAcquireStatus
628 _transient NSObject<ProgressDelegate> *delegate_;
636 void setDelegate(id delegate) {
637 delegate_ = delegate;
640 virtual bool MediaChange(std::string media, std::string drive) {
644 virtual void IMSHit(pkgAcquire::ItemDesc &item) {
647 virtual void Fetch(pkgAcquire::ItemDesc &item) {
648 [delegate_ setProgressTitle:[NSString stringWithUTF8String:("Downloading " + item.ShortDesc).c_str()]];
651 virtual void Done(pkgAcquire::ItemDesc &item) {
654 virtual void Fail(pkgAcquire::ItemDesc &item) {
656 item.Owner->Status == pkgAcquire::Item::StatIdle ||
657 item.Owner->Status == pkgAcquire::Item::StatDone
661 [delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
662 withObject:[NSArray arrayWithObjects:[NSString stringWithUTF8String:item.Owner->ErrorText.c_str()], nil]
667 virtual bool Pulse(pkgAcquire *Owner) {
668 bool value = pkgAcquireStatus::Pulse(Owner);
671 double(CurrentBytes + CurrentItems) /
672 double(TotalBytes + TotalItems)
675 [delegate_ setProgressPercent:percent];
679 virtual void Start() {
682 virtual void Stop() {
686 /* Progress Delegation {{{ */
691 _transient id<ProgressDelegate> delegate_;
694 virtual void Update() {
695 [delegate_ setProgressTitle:[NSString stringWithUTF8String:Op.c_str()]];
696 [delegate_ setProgressPercent:(Percent / 100)];
705 void setDelegate(id delegate) {
706 delegate_ = delegate;
709 virtual void Done() {
710 [delegate_ setProgressPercent:1];
715 /* Database Interface {{{ */
716 @interface Database : NSObject {
718 pkgDepCache::Policy *policy_;
719 pkgRecords *records_;
720 pkgProblemResolver *resolver_;
721 pkgAcquire *fetcher_;
723 SPtr<pkgPackageManager> manager_;
724 pkgSourceList *list_;
726 NSMutableDictionary *sources_;
727 NSMutableArray *packages_;
729 _transient NSObject<ConfigurationDelegate, ProgressDelegate> *delegate_;
738 - (void) _readCydia:(NSNumber *)fd;
739 - (void) _readStatus:(NSNumber *)fd;
740 - (void) _readOutput:(NSNumber *)fd;
744 - (Package *) packageWithName:(NSString *)name;
747 - (pkgCacheFile &) cache;
748 - (pkgDepCache::Policy *) policy;
749 - (pkgRecords *) records;
750 - (pkgProblemResolver *) resolver;
751 - (pkgAcquire &) fetcher;
752 - (NSArray *) packages;
753 - (NSArray *) sources;
762 - (void) updateWithStatus:(Status &)status;
764 - (void) setDelegate:(id)delegate;
765 - (Source *) getSource:(const pkgCache::PkgFileIterator &)file;
769 /* Source Class {{{ */
770 @interface Source : NSObject {
771 NSString *description_;
776 NSString *distribution_;
780 NSString *defaultIcon_;
782 NSDictionary *record_;
786 - (Source *) initWithMetaIndex:(metaIndex *)index;
788 - (NSComparisonResult) compareByNameAndType:(Source *)source;
790 - (NSDictionary *) record;
794 - (NSString *) distribution;
800 - (NSString *) description;
801 - (NSString *) label;
802 - (NSString *) origin;
803 - (NSString *) version;
805 - (NSString *) defaultIcon;
809 @implementation Source
813 [distribution_ release];
816 if (description_ != nil)
817 [description_ release];
824 if (defaultIcon_ != nil)
825 [defaultIcon_ release];
832 + (NSArray *) _attributeKeys {
833 return [NSArray arrayWithObjects:@"description", @"distribution", @"host", @"key", @"label", @"name", @"origin", @"trusted", @"type", @"uri", @"version", nil];
836 - (NSArray *) attributeKeys {
837 return [[self class] _attributeKeys];
840 + (BOOL) isKeyExcludedFromWebScript:(const char *)name {
841 return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name];
844 - (Source *) initWithMetaIndex:(metaIndex *)index {
845 if ((self = [super init]) != nil) {
846 trusted_ = index->IsTrusted();
848 uri_ = [[NSString stringWithUTF8String:index->GetURI().c_str()] retain];
849 distribution_ = [[NSString stringWithUTF8String:index->GetDist().c_str()] retain];
850 type_ = [[NSString stringWithUTF8String:index->GetType()] retain];
858 debReleaseIndex *dindex(dynamic_cast<debReleaseIndex *>(index));
859 if (dindex != NULL) {
860 std::ifstream release(dindex->MetaIndexFile("Release").c_str());
862 while (std::getline(release, line)) {
863 std::string::size_type colon(line.find(':'));
864 if (colon == std::string::npos)
867 std::string name(line.substr(0, colon));
868 std::string value(line.substr(colon + 1));
869 while (!value.empty() && value[0] == ' ')
870 value = value.substr(1);
872 if (name == "Default-Icon")
873 defaultIcon_ = [[NSString stringWithUTF8String:value.c_str()] retain];
874 else if (name == "Description")
875 description_ = [[NSString stringWithUTF8String:value.c_str()] retain];
876 else if (name == "Label")
877 label_ = [[NSString stringWithUTF8String:value.c_str()] retain];
878 else if (name == "Origin")
879 origin_ = [[NSString stringWithUTF8String:value.c_str()] retain];
880 else if (name == "Version")
881 version_ = [[NSString stringWithUTF8String:value.c_str()] retain];
885 record_ = [Sources_ objectForKey:[self key]];
887 record_ = [record_ retain];
891 - (NSComparisonResult) compareByNameAndType:(Source *)source {
892 NSDictionary *lhr = [self record];
893 NSDictionary *rhr = [source record];
896 return lhr == nil ? NSOrderedDescending : NSOrderedAscending;
898 NSString *lhs = [self name];
899 NSString *rhs = [source name];
901 if ([lhs length] != 0 && [rhs length] != 0) {
902 unichar lhc = [lhs characterAtIndex:0];
903 unichar rhc = [rhs characterAtIndex:0];
905 if (isalpha(lhc) && !isalpha(rhc))
906 return NSOrderedAscending;
907 else if (!isalpha(lhc) && isalpha(rhc))
908 return NSOrderedDescending;
911 return [lhs caseInsensitiveCompare:rhs];
914 - (NSDictionary *) record {
926 - (NSString *) distribution {
927 return distribution_;
930 - (NSString *) type {
935 return [NSString stringWithFormat:@"%@:%@:%@", type_, uri_, distribution_];
938 - (NSString *) host {
939 return [[[NSURL URLWithString:[self uri]] host] lowercaseString];
942 - (NSString *) name {
943 return origin_ == nil ? [self host] : origin_;
946 - (NSString *) description {
950 - (NSString *) label {
951 return label_ == nil ? [self host] : label_;
954 - (NSString *) origin {
958 - (NSString *) version {
962 - (NSString *) defaultIcon {
968 /* Relationship Class {{{ */
969 @interface Relationship : NSObject {
980 @implementation Relationship
988 - (NSString *) type {
996 - (NSString *) name {
1003 /* Package Class {{{ */
1004 NSString *Scour(const char *field, const char *begin, const char *end) {
1005 size_t i(0), l(strlen(field));
1008 const char *name = begin + i;
1009 const char *colon = name + l;
1010 const char *value = colon + 1;
1015 memcmp(name, field, l) == 0
1017 while (value != end && value[0] == ' ')
1019 const char *line = std::find(value, end, '\n');
1020 while (line != value && line[-1] == ' ')
1023 return [NSString stringWithUTF8Bytes:value length:(line - value)];
1025 begin = std::find(begin, end, '\n');
1033 @interface Package : NSObject {
1034 pkgCache::PkgIterator iterator_;
1035 _transient Database *database_;
1036 pkgCache::VerIterator version_;
1037 pkgCache::VerFileIterator file_;
1043 NSString *installed_;
1049 NSString *homepage_;
1055 NSArray *relationships_;
1058 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
1059 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
1061 - (pkgCache::PkgIterator) iterator;
1063 - (NSString *) section;
1064 - (Address *) maintainer;
1066 - (NSString *) description;
1067 - (NSString *) index;
1071 - (NSString *) latest;
1072 - (NSString *) installed;
1075 - (BOOL) upgradableAndEssential:(BOOL)essential;
1081 - (BOOL) halfConfigured;
1082 - (BOOL) halfInstalled;
1084 - (NSString *) mode;
1087 - (NSString *) name;
1088 - (NSString *) tagline;
1089 - (NSString *) icon;
1090 - (NSString *) homepage;
1091 - (Address *) author;
1093 - (NSArray *) relationships;
1095 - (Source *) source;
1096 - (NSString *) role;
1098 - (BOOL) matches:(NSString *)text;
1100 - (bool) hasSupportingRole;
1101 - (BOOL) hasTag:(NSString *)tag;
1103 - (NSComparisonResult) compareByName:(Package *)package;
1104 - (NSComparisonResult) compareBySection:(Package *)package;
1105 - (NSComparisonResult) compareBySectionAndName:(Package *)package;
1106 - (NSComparisonResult) compareForChanges:(Package *)package;
1111 - (NSNumber *) isVisiblySearchedForBy:(NSString *)search;
1112 - (NSNumber *) isInstalledAndVisible:(NSNumber *)number;
1113 - (NSNumber *) isVisiblyUninstalledInSection:(NSString *)section;
1114 - (NSNumber *) isVisibleInSource:(Source *)source;
1118 @implementation Package
1125 if (installed_ != nil)
1126 [installed_ release];
1134 if (homepage_ != nil)
1135 [homepage_ release];
1136 if (sponsor_ != nil)
1145 if (relationships_ != nil)
1146 [relationships_ release];
1151 + (NSArray *) _attributeKeys {
1152 return [NSArray arrayWithObjects:@"author", @"description", @"essential", @"homepage", @"icon", @"id", @"installed", @"latest", @"maintainer", @"name", @"section", @"size", @"source", @"sponsor", @"tagline", nil];
1155 - (NSArray *) attributeKeys {
1156 return [[self class] _attributeKeys];
1159 + (BOOL) isKeyExcludedFromWebScript:(const char *)name {
1160 return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name];
1163 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
1164 if ((self = [super init]) != nil) {
1165 iterator_ = iterator;
1166 database_ = database;
1168 version_ = [database_ policy]->GetCandidateVer(iterator_);
1169 latest_ = version_.end() ? nil : [StripVersion([NSString stringWithUTF8String:version_.VerStr()]) retain];
1171 if (!version_.end())
1172 file_ = version_.FileList();
1174 pkgCache &cache([database_ cache]);
1175 file_ = pkgCache::VerFileIterator(cache, cache.VerFileP);
1178 pkgCache::VerIterator current = iterator_.CurrentVer();
1179 installed_ = current.end() ? nil : [StripVersion([NSString stringWithUTF8String:current.VerStr()]) retain];
1181 id_ = [[[NSString stringWithUTF8String:iterator_.Name()] lowercaseString] retain];
1184 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1186 const char *begin, *end;
1187 parser->GetRec(begin, end);
1189 name_ = Scour("Name", begin, end);
1191 name_ = [name_ retain];
1192 tagline_ = [[NSString stringWithUTF8String:parser->ShortDesc().c_str()] retain];
1193 icon_ = Scour("Icon", begin, end);
1195 icon_ = [icon_ retain];
1196 homepage_ = Scour("Homepage", begin, end);
1197 if (homepage_ == nil)
1198 homepage_ = Scour("Website", begin, end);
1199 if (homepage_ != nil)
1200 homepage_ = [homepage_ retain];
1201 NSString *sponsor = Scour("Sponsor", begin, end);
1203 sponsor_ = [[Address addressWithString:sponsor] retain];
1204 NSString *author = Scour("Author", begin, end);
1206 author_ = [[Address addressWithString:author] retain];
1207 NSString *tags = Scour("Tag", begin, end);
1209 tags_ = [[tags componentsSeparatedByString:@", "] retain];
1213 for (int i(0), e([tags_ count]); i != e; ++i) {
1214 NSString *tag = [tags_ objectAtIndex:i];
1215 if ([tag hasPrefix:@"role::"]) {
1216 role_ = [[tag substringFromIndex:6] retain];
1221 NSMutableDictionary *metadata = [Packages_ objectForKey:id_];
1222 if (metadata == nil || [metadata count] == 0) {
1223 metadata = [NSMutableDictionary dictionaryWithObjectsAndKeys:
1227 [Packages_ setObject:metadata forKey:id_];
1233 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
1234 return [[[Package alloc]
1235 initWithIterator:iterator
1240 - (pkgCache::PkgIterator) iterator {
1244 - (NSString *) section {
1245 const char *section = iterator_.Section();
1246 if (section == NULL)
1249 NSString *name = [[NSString stringWithUTF8String:section] stringByReplacingCharacter:' ' withCharacter:'_'];
1252 if (NSDictionary *value = [SectionMap_ objectForKey:name])
1253 if (NSString *rename = [value objectForKey:@"Rename"]) {
1258 return [name stringByReplacingCharacter:'_' withCharacter:' '];
1261 - (Address *) maintainer {
1264 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1265 return [Address addressWithString:[NSString stringWithUTF8String:parser->Maintainer().c_str()]];
1269 return version_.end() ? 0 : version_->InstalledSize;
1272 - (NSString *) description {
1275 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1276 NSString *description([NSString stringWithUTF8String:parser->LongDesc().c_str()]);
1278 NSArray *lines = [description componentsSeparatedByString:@"\n"];
1279 NSMutableArray *trimmed = [NSMutableArray arrayWithCapacity:([lines count] - 1)];
1280 if ([lines count] < 2)
1283 NSCharacterSet *whitespace = [NSCharacterSet whitespaceCharacterSet];
1284 for (size_t i(1); i != [lines count]; ++i) {
1285 NSString *trim = [[lines objectAtIndex:i] stringByTrimmingCharactersInSet:whitespace];
1286 [trimmed addObject:trim];
1289 return [trimmed componentsJoinedByString:@"\n"];
1292 - (NSString *) index {
1293 NSString *index = [[[self name] substringToIndex:1] uppercaseString];
1294 return [index length] != 0 && isalpha([index characterAtIndex:0]) ? index : @"123";
1298 return [[Packages_ objectForKey:id_] objectForKey:@"FirstSeen"];
1301 - (NSString *) latest {
1305 - (NSString *) installed {
1310 return !version_.end();
1313 - (BOOL) upgradableAndEssential:(BOOL)essential {
1314 pkgCache::VerIterator current = iterator_.CurrentVer();
1317 return essential && [self essential];
1319 pkgCache::VerIterator candidate = [database_ policy]->GetCandidateVer(iterator_);
1320 return !candidate.end() && candidate != current;
1324 - (BOOL) essential {
1325 return (iterator_->Flags & pkgCache::Flag::Essential) == 0 ? NO : YES;
1329 return [database_ cache][iterator_].InstBroken();
1333 NSString *section = [self section];
1334 return [self hasSupportingRole] && (section == nil || isSectionVisible(section));
1338 unsigned char current = iterator_->CurrentState;
1339 return current == pkgCache::State::HalfConfigured || current == pkgCache::State::HalfInstalled;
1342 - (BOOL) halfConfigured {
1343 return iterator_->CurrentState == pkgCache::State::HalfConfigured;
1346 - (BOOL) halfInstalled {
1347 return iterator_->CurrentState == pkgCache::State::HalfInstalled;
1351 pkgDepCache::StateCache &state([database_ cache][iterator_]);
1352 return state.Mode != pkgDepCache::ModeKeep;
1355 - (NSString *) mode {
1356 pkgDepCache::StateCache &state([database_ cache][iterator_]);
1358 switch (state.Mode) {
1359 case pkgDepCache::ModeDelete:
1360 if ((state.iFlags & pkgDepCache::Purge) != 0)
1365 case pkgDepCache::ModeKeep:
1366 if ((state.iFlags & pkgDepCache::AutoKept) != 0)
1371 case pkgDepCache::ModeInstall:
1372 if ((state.iFlags & pkgDepCache::ReInstall) != 0)
1373 return @"Reinstall";
1374 else switch (state.Status) {
1376 return @"Downgrade";
1382 return @"New Install";
1395 - (NSString *) name {
1396 return name_ == nil ? id_ : name_;
1399 - (NSString *) tagline {
1403 - (NSString *) icon {
1407 - (NSString *) homepage {
1411 - (Address *) sponsor {
1415 - (Address *) author {
1419 - (NSArray *) relationships {
1420 return relationships_;
1423 - (Source *) source {
1425 source_ = file_.end() ? nil : [[database_ getSource:file_.File()] retain];
1432 - (NSString *) role {
1436 - (BOOL) matches:(NSString *)text {
1442 range = [[self id] rangeOfString:text options:NSCaseInsensitiveSearch];
1443 if (range.location != NSNotFound)
1446 range = [[self name] rangeOfString:text options:NSCaseInsensitiveSearch];
1447 if (range.location != NSNotFound)
1450 range = [[self tagline] rangeOfString:text options:NSCaseInsensitiveSearch];
1451 if (range.location != NSNotFound)
1457 - (bool) hasSupportingRole {
1460 if ([role_ isEqualToString:@"enduser"])
1462 if ([Role_ isEqualToString:@"User"])
1464 if ([role_ isEqualToString:@"hacker"])
1466 if ([Role_ isEqualToString:@"Hacker"])
1468 if ([role_ isEqualToString:@"developer"])
1470 if ([Role_ isEqualToString:@"Developer"])
1475 - (BOOL) hasTag:(NSString *)tag {
1476 return tags_ == nil ? NO : [tags_ containsObject:tag];
1479 - (NSComparisonResult) compareByName:(Package *)package {
1480 NSString *lhs = [self name];
1481 NSString *rhs = [package name];
1483 if ([lhs length] != 0 && [rhs length] != 0) {
1484 unichar lhc = [lhs characterAtIndex:0];
1485 unichar rhc = [rhs characterAtIndex:0];
1487 if (isalpha(lhc) && !isalpha(rhc))
1488 return NSOrderedAscending;
1489 else if (!isalpha(lhc) && isalpha(rhc))
1490 return NSOrderedDescending;
1493 return [lhs caseInsensitiveCompare:rhs];
1496 - (NSComparisonResult) compareBySection:(Package *)package {
1497 NSString *lhs = [self section];
1498 NSString *rhs = [package section];
1500 if (lhs == NULL && rhs != NULL)
1501 return NSOrderedAscending;
1502 else if (lhs != NULL && rhs == NULL)
1503 return NSOrderedDescending;
1504 else if (lhs != NULL && rhs != NULL) {
1505 NSComparisonResult result = [lhs caseInsensitiveCompare:rhs];
1506 if (result != NSOrderedSame)
1510 return NSOrderedSame;
1513 - (NSComparisonResult) compareBySectionAndName:(Package *)package {
1514 NSString *lhs = [self section];
1515 NSString *rhs = [package section];
1517 if (lhs == NULL && rhs != NULL)
1518 return NSOrderedAscending;
1519 else if (lhs != NULL && rhs == NULL)
1520 return NSOrderedDescending;
1521 else if (lhs != NULL && rhs != NULL) {
1522 NSComparisonResult result = [lhs compare:rhs];
1523 if (result != NSOrderedSame)
1527 return [self compareByName:package];
1530 - (NSComparisonResult) compareForChanges:(Package *)package {
1531 BOOL lhs = [self upgradableAndEssential:YES];
1532 BOOL rhs = [package upgradableAndEssential:YES];
1535 return lhs ? NSOrderedAscending : NSOrderedDescending;
1537 switch ([[self seen] compare:[package seen]]) {
1538 case NSOrderedAscending:
1539 return NSOrderedDescending;
1542 case NSOrderedDescending:
1543 return NSOrderedAscending;
1549 return [self compareByName:package];
1553 pkgProblemResolver *resolver = [database_ resolver];
1554 resolver->Clear(iterator_);
1555 resolver->Protect(iterator_);
1556 pkgCacheFile &cache([database_ cache]);
1557 cache->MarkInstall(iterator_, false);
1558 pkgDepCache::StateCache &state((*cache)[iterator_]);
1559 if (!state.Install())
1560 cache->SetReInstall(iterator_, true);
1564 pkgProblemResolver *resolver = [database_ resolver];
1565 resolver->Clear(iterator_);
1566 resolver->Protect(iterator_);
1567 resolver->Remove(iterator_);
1568 [database_ cache]->MarkDelete(iterator_, true);
1571 - (NSNumber *) isVisiblySearchedForBy:(NSString *)search {
1572 return [NSNumber numberWithBool:(
1573 [self valid] && [self visible] && [self matches:search]
1577 - (NSNumber *) isInstalledAndVisible:(NSNumber *)number {
1578 return [NSNumber numberWithBool:(
1579 (![number boolValue] || [self visible]) && [self installed] != nil
1583 - (NSNumber *) isVisiblyUninstalledInSection:(NSString *)name {
1584 NSString *section = [self section];
1586 return [NSNumber numberWithBool:(
1587 [self valid] && [self visible] &&
1588 [self installed] == nil && (
1590 section == nil && [name length] == 0 ||
1591 [name isEqualToString:section]
1596 - (NSNumber *) isVisibleInSource:(Source *)source {
1597 return [NSNumber numberWithBool:([self source] == source && [self visible])];
1602 /* Section Class {{{ */
1603 @interface Section : NSObject {
1609 - (NSComparisonResult) compareByName:(Section *)section;
1610 - (Section *) initWithName:(NSString *)name;
1611 - (Section *) initWithName:(NSString *)name row:(size_t)row;
1612 - (NSString *) name;
1615 - (void) addToCount;
1619 @implementation Section
1626 - (NSComparisonResult) compareByName:(Section *)section {
1627 NSString *lhs = [self name];
1628 NSString *rhs = [section name];
1630 if ([lhs length] != 0 && [rhs length] != 0) {
1631 unichar lhc = [lhs characterAtIndex:0];
1632 unichar rhc = [rhs characterAtIndex:0];
1634 if (isalpha(lhc) && !isalpha(rhc))
1635 return NSOrderedAscending;
1636 else if (!isalpha(lhc) && isalpha(rhc))
1637 return NSOrderedDescending;
1640 return [lhs caseInsensitiveCompare:rhs];
1643 - (Section *) initWithName:(NSString *)name {
1644 return [self initWithName:name row:0];
1647 - (Section *) initWithName:(NSString *)name row:(size_t)row {
1648 if ((self = [super init]) != nil) {
1649 name_ = [name retain];
1654 - (NSString *) name {
1666 - (void) addToCount {
1676 /* Database Implementation {{{ */
1677 @implementation Database
1684 - (void) _readCydia:(NSNumber *)fd {
1685 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1687 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1688 std::istream is(&ib);
1691 static Pcre finish_r("^finish:([^:]*)$");
1693 while (std::getline(is, line)) {
1694 const char *data(line.c_str());
1695 size_t size = line.size();
1696 fprintf(stderr, "C:%s\n", data);
1698 if (finish_r(data, size)) {
1699 NSString *finish = finish_r[1];
1700 int index = [Finishes_ indexOfObject:finish];
1701 if (index != INT_MAX && index > Finish_)
1710 - (void) _readStatus:(NSNumber *)fd {
1711 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1713 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1714 std::istream is(&ib);
1717 static Pcre conffile_r("^status: [^ ]* : conffile-prompt : (.*?) *$");
1718 static Pcre pmstatus_r("^([^:]*):([^:]*):([^:]*):(.*)$");
1720 while (std::getline(is, line)) {
1721 const char *data(line.c_str());
1722 size_t size = line.size();
1723 fprintf(stderr, "S:%s\n", data);
1725 if (conffile_r(data, size)) {
1726 [delegate_ setConfigurationData:conffile_r[1]];
1727 } else if (strncmp(data, "status: ", 8) == 0) {
1728 NSString *string = [NSString stringWithUTF8String:(data + 8)];
1729 [delegate_ setProgressTitle:string];
1730 } else if (pmstatus_r(data, size)) {
1731 std::string type([pmstatus_r[1] UTF8String]);
1732 NSString *id = pmstatus_r[2];
1734 float percent([pmstatus_r[3] floatValue]);
1735 [delegate_ setProgressPercent:(percent / 100)];
1737 NSString *string = pmstatus_r[4];
1739 if (type == "pmerror")
1740 [delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
1741 withObject:[NSArray arrayWithObjects:string, id, nil]
1744 else if (type == "pmstatus")
1745 [delegate_ setProgressTitle:string];
1746 else if (type == "pmconffile")
1747 [delegate_ setConfigurationData:string];
1748 else _assert(false);
1749 } else _assert(false);
1756 - (void) _readOutput:(NSNumber *)fd {
1757 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1759 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1760 std::istream is(&ib);
1763 while (std::getline(is, line)) {
1764 fprintf(stderr, "O:%s\n", line.c_str());
1765 [delegate_ addProgressOutput:[NSString stringWithUTF8String:line.c_str()]];
1776 - (Package *) packageWithName:(NSString *)name {
1777 if (static_cast<pkgDepCache *>(cache_) == NULL)
1779 pkgCache::PkgIterator iterator(cache_->FindPkg([name UTF8String]));
1780 return iterator.end() ? nil : [Package packageWithIterator:iterator database:self];
1783 - (Database *) init {
1784 if ((self = [super init]) != nil) {
1791 sources_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1792 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
1796 _assert(pipe(fds) != -1);
1799 _config->Set("APT::Keep-Fds::", cydiafd_);
1800 setenv("CYDIA", [[[[NSNumber numberWithInt:cydiafd_] stringValue] stringByAppendingString:@" 1"] UTF8String], _not(int));
1803 detachNewThreadSelector:@selector(_readCydia:)
1805 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1808 _assert(pipe(fds) != -1);
1812 detachNewThreadSelector:@selector(_readStatus:)
1814 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1817 _assert(pipe(fds) != -1);
1818 _assert(dup2(fds[0], 0) != -1);
1819 _assert(close(fds[0]) != -1);
1821 input_ = fdopen(fds[1], "a");
1823 _assert(pipe(fds) != -1);
1824 _assert(dup2(fds[1], 1) != -1);
1825 _assert(close(fds[1]) != -1);
1828 detachNewThreadSelector:@selector(_readOutput:)
1830 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1835 - (pkgCacheFile &) cache {
1839 - (pkgDepCache::Policy *) policy {
1843 - (pkgRecords *) records {
1847 - (pkgProblemResolver *) resolver {
1851 - (pkgAcquire &) fetcher {
1855 - (NSArray *) packages {
1859 - (NSArray *) sources {
1860 return [sources_ allValues];
1863 - (void) reloadData {
1882 if (!cache_.Open(progress_, true)) {
1884 if (!_error->PopMessage(error))
1887 fprintf(stderr, "cache_.Open():[%s]\n", error.c_str());
1889 if (error == "dpkg was interrupted, you must manually run 'dpkg --configure -a' to correct the problem. ")
1890 [delegate_ repairWithSelector:@selector(configure)];
1891 else if (error == "The package lists or status file could not be parsed or opened.")
1892 [delegate_ repairWithSelector:@selector(update)];
1893 // else if (error == "Could not open lock file /var/lib/dpkg/lock - open (13 Permission denied)")
1894 // else if (error == "Could not get lock /var/lib/dpkg/lock - open (35 Resource temporarily unavailable)")
1895 // else if (error == "The list of sources could not be read.")
1896 else _assert(false);
1901 now_ = [[NSDate date] retain];
1903 policy_ = new pkgDepCache::Policy();
1904 records_ = new pkgRecords(cache_);
1905 resolver_ = new pkgProblemResolver(cache_);
1906 fetcher_ = new pkgAcquire(&status_);
1909 list_ = new pkgSourceList();
1910 _assert(list_->ReadMainList());
1912 _assert(cache_->DelCount() == 0 && cache_->InstCount() == 0);
1913 _assert(pkgApplyStatus(cache_));
1915 if (cache_->BrokenCount() != 0) {
1916 _assert(pkgFixBroken(cache_));
1917 _assert(cache_->BrokenCount() == 0);
1918 _assert(pkgMinimizeUpgrade(cache_));
1921 [sources_ removeAllObjects];
1922 for (pkgSourceList::const_iterator source = list_->begin(); source != list_->end(); ++source) {
1923 std::vector<pkgIndexFile *> *indices = (*source)->GetIndexFiles();
1924 for (std::vector<pkgIndexFile *>::const_iterator index = indices->begin(); index != indices->end(); ++index)
1926 setObject:[[[Source alloc] initWithMetaIndex:*source] autorelease]
1927 forKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(*index)]
1931 [packages_ removeAllObjects];
1932 for (pkgCache::PkgIterator iterator = cache_->PkgBegin(); !iterator.end(); ++iterator)
1933 if (Package *package = [Package packageWithIterator:iterator database:self])
1934 [packages_ addObject:package];
1936 [packages_ sortUsingSelector:@selector(compareByName:)];
1939 - (void) configure {
1940 NSString *dpkg = [NSString stringWithFormat:@"dpkg --configure -a --status-fd %u", statusfd_];
1941 system([dpkg UTF8String]);
1949 Lock.Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1950 _assert(!_error->PendingError());
1953 fetcher.Clean(_config->FindDir("Dir::Cache::Archives"));
1956 public pkgArchiveCleaner
1959 virtual void Erase(const char *File, std::string Pkg, std::string Ver, struct stat &St) {
1964 if (!cleaner.Go(_config->FindDir("Dir::Cache::Archives") + "partial/", cache_)) {
1966 while (_error->PopMessage(error))
1967 fprintf(stderr, "ArchiveCleaner: %s\n", error.c_str());
1972 pkgRecords records(cache_);
1974 lock_ = new FileFd();
1975 lock_->Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1976 _assert(!_error->PendingError());
1979 // XXX: explain this with an error message
1980 _assert(list.ReadMainList());
1982 manager_ = (_system->CreatePM(cache_));
1983 _assert(manager_->GetArchives(fetcher_, &list, &records));
1984 _assert(!_error->PendingError());
1988 NSMutableArray *before = [NSMutableArray arrayWithCapacity:16]; {
1990 _assert(list.ReadMainList());
1991 for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source)
1992 [before addObject:[NSString stringWithUTF8String:(*source)->GetURI().c_str()]];
1995 if (fetcher_->Run(PulseInterval_) != pkgAcquire::Continue) {
2000 bool failed = false;
2001 for (pkgAcquire::ItemIterator item = fetcher_->ItemsBegin(); item != fetcher_->ItemsEnd(); item++) {
2002 if ((*item)->Status == pkgAcquire::Item::StatDone && (*item)->Complete)
2005 std::string uri = (*item)->DescURI();
2006 std::string error = (*item)->ErrorText;
2008 fprintf(stderr, "pAf:%s:%s\n", uri.c_str(), error.c_str());
2011 [delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
2012 withObject:[NSArray arrayWithObjects:[NSString stringWithUTF8String:error.c_str()], nil]
2023 pkgPackageManager::OrderResult result = manager_->DoInstall(statusfd_);
2025 if (_error->PendingError()) {
2030 if (result == pkgPackageManager::Failed) {
2035 if (result != pkgPackageManager::Completed) {
2040 NSMutableArray *after = [NSMutableArray arrayWithCapacity:16]; {
2042 _assert(list.ReadMainList());
2043 for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source)
2044 [after addObject:[NSString stringWithUTF8String:(*source)->GetURI().c_str()]];
2047 if (![before isEqualToArray:after])
2052 _assert(pkgDistUpgrade(cache_));
2056 [self updateWithStatus:status_];
2059 - (void) updateWithStatus:(Status &)status {
2061 _assert(list.ReadMainList());
2064 lock.Fd(GetLock(_config->FindDir("Dir::State::Lists") + "lock"));
2065 _assert(!_error->PendingError());
2067 pkgAcquire fetcher(&status);
2068 _assert(list.GetIndexes(&fetcher));
2070 if (fetcher.Run(PulseInterval_) != pkgAcquire::Failed) {
2071 bool failed = false;
2072 for (pkgAcquire::ItemIterator item = fetcher.ItemsBegin(); item != fetcher.ItemsEnd(); item++)
2073 if ((*item)->Status != pkgAcquire::Item::StatDone) {
2074 (*item)->Finished();
2078 if (!failed && _config->FindB("APT::Get::List-Cleanup", true) == true) {
2079 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists")));
2080 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/"));
2083 [Metadata_ setObject:[NSDate date] forKey:@"LastUpdate"];
2088 - (void) setDelegate:(id)delegate {
2089 delegate_ = delegate;
2090 status_.setDelegate(delegate);
2091 progress_.setDelegate(delegate);
2094 - (Source *) getSource:(const pkgCache::PkgFileIterator &)file {
2095 pkgIndexFile *index(NULL);
2096 list_->FindIndex(file, index);
2097 return [sources_ objectForKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(index)]];
2103 /* Confirmation View {{{ */
2104 void AddTextView(NSMutableDictionary *fields, NSMutableArray *packages, NSString *key) {
2105 if ([packages count] == 0)
2108 UITextView *text = GetTextView([packages count] == 0 ? @"n/a" : [packages componentsJoinedByString:@", "], 120, false);
2109 [fields setObject:text forKey:key];
2111 CGColor blue(space_, 0, 0, 0.4, 1);
2112 [text setTextColor:blue];
2115 @protocol ConfirmationViewDelegate
2120 @interface ConfirmationView : UIView {
2121 Database *database_;
2123 UITransitionView *transition_;
2125 UINavigationBar *navbar_;
2126 UIPreferencesTable *table_;
2127 NSMutableDictionary *fields_;
2128 UIAlertSheet *essential_;
2133 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate;
2137 @implementation ConfirmationView
2140 [navbar_ setDelegate:nil];
2141 [transition_ setDelegate:nil];
2142 [table_ setDataSource:nil];
2144 [transition_ release];
2149 if (essential_ != nil)
2150 [essential_ release];
2155 [transition_ transition:7 toView:nil];
2159 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
2160 if (from != nil && to == nil)
2161 [self removeFromSuperview];
2164 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2167 if (essential_ != nil)
2168 [essential_ popupAlertAnimated:YES];
2170 [delegate_ confirm];
2179 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
2180 NSString *context = [sheet context];
2182 if ([context isEqualToString:@"remove"])
2188 [delegate_ confirm];
2193 else if ([context isEqualToString:@"unable"])
2199 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
2203 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
2205 case 0: return @"Statistics";
2206 case 1: return @"Modifications";
2208 default: _assert(false);
2212 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
2215 case 1: return [fields_ count];
2217 default: _assert(false);
2221 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
2222 if (group != 1 || row == -1)
2225 _assert(size_t(row) < [fields_ count]);
2226 return [[[fields_ allValues] objectAtIndex:row] visibleTextRect].size.height + TextViewOffset_;
2230 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
2231 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
2232 [cell setShowSelection:NO];
2235 case 0: switch (row) {
2237 [cell setTitle:@"Downloading"];
2238 [cell setValue:SizeString([database_ fetcher].FetchNeeded())];
2242 [cell setTitle:@"Resuming At"];
2243 [cell setValue:SizeString([database_ fetcher].PartialPresent())];
2247 double size([database_ cache]->UsrSize());
2250 [cell setTitle:@"Disk Freeing"];
2251 [cell setValue:SizeString(-size)];
2253 [cell setTitle:@"Disk Using"];
2254 [cell setValue:SizeString(size)];
2258 default: _assert(false);
2262 _assert(size_t(row) < [fields_ count]);
2263 [cell setTitle:[[fields_ allKeys] objectAtIndex:row]];
2264 [cell addSubview:[[fields_ allValues] objectAtIndex:row]];
2267 default: _assert(false);
2273 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate {
2274 if ((self = [super initWithFrame:[view bounds]]) != nil) {
2275 database_ = database;
2276 delegate_ = delegate;
2278 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
2279 [self addSubview:transition_];
2281 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
2283 CGSize navsize = [UINavigationBar defaultSize];
2284 CGRect navrect = {{0, 0}, navsize};
2285 CGRect bounds = [overlay_ bounds];
2287 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
2288 [navbar_ setDelegate:self];
2290 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Confirm"] autorelease];
2291 [navbar_ pushNavigationItem:navitem];
2292 [navbar_ showButtonsWithLeftTitle:@"Cancel" rightTitle:@"Confirm"];
2294 fields_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
2296 NSMutableArray *installing = [NSMutableArray arrayWithCapacity:16];
2297 NSMutableArray *reinstalling = [NSMutableArray arrayWithCapacity:16];
2298 NSMutableArray *upgrading = [NSMutableArray arrayWithCapacity:16];
2299 NSMutableArray *downgrading = [NSMutableArray arrayWithCapacity:16];
2300 NSMutableArray *removing = [NSMutableArray arrayWithCapacity:16];
2304 pkgCacheFile &cache([database_ cache]);
2305 NSArray *packages = [database_ packages];
2306 for (size_t i(0), e = [packages count]; i != e; ++i) {
2307 Package *package = [packages objectAtIndex:i];
2308 pkgCache::PkgIterator iterator = [package iterator];
2309 pkgDepCache::StateCache &state(cache[iterator]);
2311 NSString *name([package name]);
2313 if (state.NewInstall())
2314 [installing addObject:name];
2315 else if (!state.Delete() && (state.iFlags & pkgDepCache::ReInstall) == pkgDepCache::ReInstall)
2316 [reinstalling addObject:name];
2317 else if (state.Upgrade())
2318 [upgrading addObject:name];
2319 else if (state.Downgrade())
2320 [downgrading addObject:name];
2321 else if (state.Delete()) {
2322 if ([package essential])
2324 [removing addObject:name];
2330 else if (Advanced_ || true) {
2331 essential_ = [[UIAlertSheet alloc]
2332 initWithTitle:@"Removing Essentials"
2333 buttons:[NSArray arrayWithObjects:
2334 @"Cancel Operation (Safe)",
2335 @"Force Removal (Unsafe)",
2337 defaultButtonIndex:0
2343 [essential_ setDestructiveButton:[[essential_ buttons] objectAtIndex:0]];
2345 [essential_ setBodyText:@"This operation involves the removal of one or more packages that are required for the continued operation of either Cydia or iPhoneOS. If you continue, you may not be able to use Cydia to repair any damage."];
2347 essential_ = [[UIAlertSheet alloc]
2348 initWithTitle:@"Unable to Comply"
2349 buttons:[NSArray arrayWithObjects:@"Okay", nil]
2350 defaultButtonIndex:0
2355 [essential_ setBodyText:@"This operation requires the removal of one or more packages that are required for the continued operation of either Cydia or iPhoneOS. In order to continue and force this operation you will need to be activate the Advanced mode under to continue and force this operation you will need to be activate the Advanced mode under Settings."];
2358 AddTextView(fields_, installing, @"Installing");
2359 AddTextView(fields_, reinstalling, @"Reinstalling");
2360 AddTextView(fields_, upgrading, @"Upgrading");
2361 AddTextView(fields_, downgrading, @"Downgrading");
2362 AddTextView(fields_, removing, @"Removing");
2364 table_ = [[UIPreferencesTable alloc] initWithFrame:CGRectMake(
2365 0, navsize.height, bounds.size.width, bounds.size.height - navsize.height
2368 [table_ setReusesTableCells:YES];
2369 [table_ setDataSource:self];
2370 [table_ reloadData];
2372 [overlay_ addSubview:navbar_];
2373 [overlay_ addSubview:table_];
2375 [view addSubview:self];
2377 [transition_ setDelegate:self];
2379 UIView *blank = [[[UIView alloc] initWithFrame:[transition_ bounds]] autorelease];
2380 [transition_ transition:0 toView:blank];
2381 [transition_ transition:3 toView:overlay_];
2388 /* Progress Data {{{ */
2389 @interface ProgressData : NSObject {
2395 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object;
2402 @implementation ProgressData
2404 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object {
2405 if ((self = [super init]) != nil) {
2406 selector_ = selector;
2426 /* Progress View {{{ */
2427 @interface ProgressView : UIView <
2428 ConfigurationDelegate,
2431 _transient Database *database_;
2433 UIView *background_;
2434 UITransitionView *transition_;
2436 UINavigationBar *navbar_;
2437 UIProgressBar *progress_;
2438 UITextView *output_;
2439 UITextLabel *status_;
2440 UIPushButton *close_;
2443 SHA1SumValue springlist_;
2446 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
2448 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database delegate:(id)delegate;
2449 - (void) setContentView:(UIView *)view;
2452 - (void) _retachThread;
2453 - (void) _detachNewThreadData:(ProgressData *)data;
2454 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title;
2460 @protocol ProgressViewDelegate
2461 - (void) progressViewIsComplete:(ProgressView *)sender;
2464 @implementation ProgressView
2467 [transition_ setDelegate:nil];
2468 [navbar_ setDelegate:nil];
2471 if (background_ != nil)
2472 [background_ release];
2473 [transition_ release];
2476 [progress_ release];
2483 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
2484 if (bootstrap_ && from == overlay_ && to == view_)
2488 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database delegate:(id)delegate {
2489 if ((self = [super initWithFrame:frame]) != nil) {
2490 database_ = database;
2491 delegate_ = delegate;
2493 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
2494 [transition_ setDelegate:self];
2496 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
2499 [overlay_ setBackgroundColor:Black_];
2501 background_ = [[UIView alloc] initWithFrame:[self bounds]];
2502 [background_ setBackgroundColor:Black_];
2503 [self addSubview:background_];
2506 [self addSubview:transition_];
2508 CGSize navsize = [UINavigationBar defaultSize];
2509 CGRect navrect = {{0, 0}, navsize};
2511 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
2512 [overlay_ addSubview:navbar_];
2514 [navbar_ setBarStyle:1];
2515 [navbar_ setDelegate:self];
2517 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:nil] autorelease];
2518 [navbar_ pushNavigationItem:navitem];
2520 CGRect bounds = [overlay_ bounds];
2521 CGSize prgsize = [UIProgressBar defaultSize];
2524 (bounds.size.width - prgsize.width) / 2,
2525 bounds.size.height - prgsize.height - 20
2528 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
2529 [progress_ setStyle:0];
2531 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(
2533 bounds.size.height - prgsize.height - 50,
2534 bounds.size.width - 20,
2538 [status_ setColor:White_];
2539 [status_ setBackgroundColor:Clear_];
2541 [status_ setCentersHorizontally:YES];
2542 //[status_ setFont:font];
2544 output_ = [[UITextView alloc] initWithFrame:CGRectMake(
2546 navrect.size.height + 20,
2547 bounds.size.width - 20,
2548 bounds.size.height - navsize.height - 62 - navrect.size.height
2551 //[output_ setTextFont:@"Courier New"];
2552 [output_ setTextSize:12];
2554 [output_ setTextColor:White_];
2555 [output_ setBackgroundColor:Clear_];
2557 [output_ setMarginTop:0];
2558 [output_ setAllowsRubberBanding:YES];
2559 [output_ setEditable:NO];
2561 [overlay_ addSubview:output_];
2563 close_ = [[UIPushButton alloc] initWithFrame:CGRectMake(
2565 bounds.size.height - prgsize.height - 50,
2566 bounds.size.width - 20,
2570 [close_ setAutosizesToFit:NO];
2571 [close_ setDrawsShadow:YES];
2572 [close_ setStretchBackground:YES];
2573 [close_ setEnabled:YES];
2575 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22);
2576 [close_ setTitleFont:bold];
2579 [close_ addTarget:self action:@selector(closeButtonPushed) forEvents:kUIControlEventMouseUpInside];
2580 [close_ setBackground:[UIImage applicationImageNamed:@"green-up.png"] forState:0];
2581 [close_ setBackground:[UIImage applicationImageNamed:@"green-dn.png"] forState:1];
2585 - (void) setContentView:(UIView *)view {
2586 view_ = [view retain];
2589 - (void) resetView {
2590 [transition_ transition:6 toView:view_];
2593 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
2594 NSString *context = [sheet context];
2595 if ([context isEqualToString:@"conffile"]) {
2596 FILE *input = [database_ input];
2600 fprintf(input, "N\n");
2604 fprintf(input, "Y\n");
2615 - (void) closeButtonPushed {
2618 [delegate_ progressViewIsComplete:self];
2623 [delegate_ suspendWithAnimation:YES];
2627 system("killall SpringBoard");
2631 system("launchctl unload /System/Library/LaunchDaemons/com.apple.SpringBoard.plist; launchctl load /System/Library/LaunchDaemons/com.apple.SpringBoard.plist");
2640 - (void) _retachThread {
2641 UINavigationItem *item = [navbar_ topItem];
2642 [item setTitle:@"Complete"];
2644 [overlay_ addSubview:close_];
2645 [progress_ removeFromSuperview];
2646 [status_ removeFromSuperview];
2649 FileFd file("/System/Library/LaunchDaemons/com.apple.SpringBoard.plist", FileFd::ReadOnly);
2650 MMap mmap(file, MMap::ReadOnly);
2652 sha1.Add(reinterpret_cast<uint8_t *>(mmap.Data()), mmap.Size());
2653 if (!(springlist_ == sha1.Result()))
2658 case 0: [close_ setTitle:@"Return to Cydia"]; break;
2659 case 1: [close_ setTitle:@"Close Cydia (Restart)"]; break;
2660 case 2: [close_ setTitle:@"Restart SpringBoard"]; break;
2661 case 3: [close_ setTitle:@"Reload SpringBoard"]; break;
2662 case 4: [close_ setTitle:@"Reboot Device"]; break;
2666 notify_post("com.apple.mobile.application_installed");
2669 [delegate_ setStatusBarShowsProgress:NO];
2674 - (void) _detachNewThreadData:(ProgressData *)data {
2675 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
2677 [[data target] performSelector:[data selector] withObject:[data object]];
2680 [self performSelectorOnMainThread:@selector(_retachThread) withObject:nil waitUntilDone:YES];
2685 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title {
2686 UINavigationItem *item = [navbar_ topItem];
2687 [item setTitle:title];
2689 [status_ setText:nil];
2690 [output_ setText:@""];
2691 [progress_ setProgress:0];
2693 [close_ removeFromSuperview];
2694 [overlay_ addSubview:progress_];
2695 [overlay_ addSubview:status_];
2697 [delegate_ setStatusBarShowsProgress:YES];
2701 FileFd file("/System/Library/LaunchDaemons/com.apple.SpringBoard.plist", FileFd::ReadOnly);
2702 MMap mmap(file, MMap::ReadOnly);
2704 sha1.Add(reinterpret_cast<uint8_t *>(mmap.Data()), mmap.Size());
2705 springlist_ = sha1.Result();
2708 [transition_ transition:6 toView:overlay_];
2711 detachNewThreadSelector:@selector(_detachNewThreadData:)
2713 withObject:[[ProgressData alloc]
2714 initWithSelector:selector
2721 - (void) repairWithSelector:(SEL)selector {
2723 detachNewThreadSelector:selector
2726 title:@"Repairing..."
2730 - (void) setConfigurationData:(NSString *)data {
2732 performSelectorOnMainThread:@selector(_setConfigurationData:)
2738 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id {
2739 Package *package = id == nil ? nil : [database_ packageWithName:id];
2741 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
2742 initWithTitle:(package == nil ? @"Source Error" : [package name])
2743 buttons:[NSArray arrayWithObjects:@"Okay", nil]
2744 defaultButtonIndex:0
2749 [sheet setBodyText:error];
2750 [sheet popupAlertAnimated:YES];
2753 - (void) setProgressTitle:(NSString *)title {
2755 performSelectorOnMainThread:@selector(_setProgressTitle:)
2761 - (void) setProgressPercent:(float)percent {
2763 performSelectorOnMainThread:@selector(_setProgressPercent:)
2764 withObject:[NSNumber numberWithFloat:percent]
2769 - (void) addProgressOutput:(NSString *)output {
2771 performSelectorOnMainThread:@selector(_addProgressOutput:)
2777 - (void) _setConfigurationData:(NSString *)data {
2778 static Pcre conffile_r("^'(.*)' '(.*)' ([01]) ([01])$");
2780 _assert(conffile_r(data));
2782 NSString *ofile = conffile_r[1];
2783 //NSString *nfile = conffile_r[2];
2785 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
2786 initWithTitle:@"Configuration Upgrade"
2787 buttons:[NSArray arrayWithObjects:
2788 @"Keep My Old Copy",
2789 @"Accept The New Copy",
2790 // XXX: @"See What Changed",
2792 defaultButtonIndex:0
2797 [sheet setBodyText:[NSString stringWithFormat:
2798 @"The following file has been changed by both the package maintainer and by you (or for you by a script).\n\n%@"
2801 [sheet popupAlertAnimated:YES];
2804 - (void) _setProgressTitle:(NSString *)title {
2805 [status_ setText:[title stringByAppendingString:@"..."]];
2808 - (void) _setProgressPercent:(NSNumber *)percent {
2809 [progress_ setProgress:[percent floatValue]];
2812 - (void) _addProgressOutput:(NSString *)output {
2813 [output_ setText:[NSString stringWithFormat:@"%@\n%@", [output_ text], output]];
2814 CGSize size = [output_ contentSize];
2815 CGRect rect = {{0, size.height}, {size.width, 0}};
2816 [output_ scrollRectToVisible:rect animated:YES];
2819 - (BOOL) isRunning {
2826 /* Package Cell {{{ */
2827 @interface PackageCell : UISimpleTableCell {
2830 NSString *description_;
2832 //UIImageView *trusted_;
2834 UIImageView *badge_;
2835 UITextLabel *status_;
2839 - (PackageCell *) init;
2840 - (void) setPackage:(Package *)package;
2842 + (int) heightForPackage:(Package *)package;
2846 @implementation PackageCell
2848 - (void) clearPackage {
2859 if (description_ != nil) {
2860 [description_ release];
2864 if (source_ != nil) {
2871 [self clearPackage];
2876 //[trusted_ release];
2880 - (PackageCell *) init {
2881 if ((self = [super init]) != nil) {
2883 badge_ = [[UIImageView alloc] initWithFrame:CGRectMake(17, 70, 16, 16)];
2885 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 68, 280, 20)];
2886 [status_ setBackgroundColor:Clear_];
2887 [status_ setFont:small];
2892 - (void) setPackage:(Package *)package {
2893 [self clearPackage];
2895 Source *source = [package source];
2898 if (NSString *icon = [package icon])
2899 icon_ = [UIImage imageAtPath:[icon substringFromIndex:6]];
2900 if (icon_ == nil) if (NSString *section = [package section])
2901 icon_ = [UIImage applicationImageNamed:[NSString stringWithFormat:@"Sections/%@.png", Simplify(section)]];
2902 /*if (icon_ == nil) if (NSString *icon = [source defaultIcon])
2903 icon_ = [UIImage imageAtPath:[icon substringFromIndex:6]];*/
2905 icon_ = [UIImage applicationImageNamed:@"unknown.png"];
2907 icon_ = [icon_ retain];
2909 name_ = [[package name] retain];
2910 description_ = [[package tagline] retain];
2912 NSString *label = nil;
2913 bool trusted = false;
2915 if (source != nil) {
2916 label = [source label];
2917 trusted = [source trusted];
2918 } else if ([[package id] isEqualToString:@"firmware"])
2921 label = @"Unknown/Local";
2923 NSString *from = [NSString stringWithFormat:@"from %@", label];
2925 NSString *section = Simplify([package section]);
2926 if (section != nil && ![section isEqualToString:label])
2927 from = [from stringByAppendingString:[NSString stringWithFormat:@" (%@)", section]];
2929 source_ = [from retain];
2932 [badge_ removeFromSuperview];
2933 [status_ removeFromSuperview];
2935 if (NSString *mode = [package mode]) {
2936 [badge_ setImage:[UIImage applicationImageNamed:
2937 [mode isEqualToString:@"Remove"] || [mode isEqualToString:@"Purge"] ? @"removing.png" : @"installing.png"
2940 [status_ setText:[NSString stringWithFormat:@"Queued for %@", mode]];
2941 [status_ setColor:Blueish_];
2942 } else if ([package half]) {
2943 [badge_ setImage:[UIImage applicationImageNamed:@"damaged.png"]];
2944 [status_ setText:@"Package Damaged"];
2945 [status_ setColor:Red_];
2947 [badge_ setImage:nil];
2948 [status_ setText:nil];
2952 [self addSubview:badge_];
2953 [self addSubview:status_];
2958 - (void) drawContentInRect:(CGRect)rect selected:(BOOL)selected {
2960 [icon_ drawInRect:CGRectMake(10, 10, 30, 30)];
2967 [name_ drawAtPoint:CGPointMake(48, 8) forWidth:240 withFont:Font18Bold_ ellipsis:2];
2968 [source_ drawAtPoint:CGPointMake(58, 29) forWidth:225 withFont:Font12_ ellipsis:2];
2972 [description_ drawAtPoint:CGPointMake(12, 46) forWidth:280 withFont:Font14_ ellipsis:2];
2974 [super drawContentInRect:rect selected:selected];
2977 + (int) heightForPackage:(Package *)package {
2978 NSString *tagline([package tagline]);
2979 int height = tagline == nil || [tagline length] == 0 ? -17 : 0;
2981 if ([package hasMode] || [package half])
2990 /* Section Cell {{{ */
2991 @interface SectionCell : UISimpleTableCell {
2996 UISwitchControl *switch_;
3001 - (void) setSection:(Section *)section editing:(BOOL)editing;
3005 @implementation SectionCell
3007 - (void) clearSection {
3008 if (section_ != nil) {
3018 if (count_ != nil) {
3025 [self clearSection];
3032 if ((self = [super init]) != nil) {
3033 icon_ = [[UIImage applicationImageNamed:@"folder.png"] retain];
3035 switch_ = [[UISwitchControl alloc] initWithFrame:CGRectMake(218, 9, 60, 25)];
3036 [switch_ addTarget:self action:@selector(onSwitch:) forEvents:kUIControlEventMouseUpInside];
3040 - (void) onSwitch:(id)sender {
3041 NSMutableDictionary *metadata = [Sections_ objectForKey:section_];
3042 if (metadata == nil) {
3043 metadata = [NSMutableDictionary dictionaryWithCapacity:2];
3044 [Sections_ setObject:metadata forKey:section_];
3048 [metadata setObject:[NSNumber numberWithBool:([switch_ value] == 0)] forKey:@"Hidden"];
3051 - (void) setSection:(Section *)section editing:(BOOL)editing {
3052 if (editing != editing_) {
3054 [switch_ removeFromSuperview];
3056 [self addSubview:switch_];
3060 [self clearSection];
3062 if (section == nil) {
3063 name_ = [@"All Packages" retain];
3066 section_ = [section name];
3067 if (section_ != nil)
3068 section_ = [section_ retain];
3069 name_ = [(section_ == nil ? @"(No Section)" : section_) retain];
3070 count_ = [[NSString stringWithFormat:@"%d", [section count]] retain];
3073 [switch_ setValue:isSectionVisible(section_) animated:NO];
3077 - (void) drawContentInRect:(CGRect)rect selected:(BOOL)selected {
3078 [icon_ drawInRect:CGRectMake(8, 7, 32, 32)];
3085 [name_ drawAtPoint:CGPointMake(48, 9) forWidth:(editing_ ? 164 : 250) withFont:Font22Bold_ ellipsis:2];
3087 CGSize size = [count_ sizeWithFont:Font14_];
3091 [count_ drawAtPoint:CGPointMake(12 + (29 - size.width) / 2, 15) withFont:Font12Bold_];
3093 [super drawContentInRect:rect selected:selected];
3099 /* File Table {{{ */
3100 @interface FileTable : RVPage {
3101 _transient Database *database_;
3104 NSMutableArray *files_;
3108 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3109 - (void) setPackage:(Package *)package;
3113 @implementation FileTable
3116 if (package_ != nil)
3125 - (int) numberOfRowsInTable:(UITable *)table {
3126 return files_ == nil ? 0 : [files_ count];
3129 - (float) table:(UITable *)table heightForRow:(int)row {
3133 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
3134 if (reusing == nil) {
3135 reusing = [[[UIImageAndTextTableCell alloc] init] autorelease];
3136 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
3137 [[(UIImageAndTextTableCell *)reusing titleTextLabel] setFont:font];
3140 [(UIImageAndTextTableCell *)reusing setTitle:[files_ objectAtIndex:row]];
3144 - (BOOL) table:(UITable *)table canSelectRow:(int)row {
3148 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3149 if ((self = [super initWithBook:book]) != nil) {
3150 database_ = database;
3152 files_ = [[NSMutableArray arrayWithCapacity:32] retain];
3154 list_ = [[UITable alloc] initWithFrame:[self bounds]];
3155 [self addSubview:list_];
3157 UITableColumn *column = [[[UITableColumn alloc]
3158 initWithTitle:@"Name"
3160 width:[self frame].size.width
3163 [list_ setDataSource:self];
3164 [list_ setSeparatorStyle:1];
3165 [list_ addTableColumn:column];
3166 [list_ setDelegate:self];
3167 [list_ setReusesTableCells:YES];
3171 - (void) setPackage:(Package *)package {
3172 if (package_ != nil) {
3173 [package_ autorelease];
3182 [files_ removeAllObjects];
3184 if (package != nil) {
3185 package_ = [package retain];
3186 name_ = [[package id] retain];
3188 NSString *path = [NSString stringWithFormat:@"/var/lib/dpkg/info/%@.list", name_];
3191 std::ifstream fin([path UTF8String]);
3193 while (std::getline(fin, line))
3194 [files_ addObject:[NSString stringWithUTF8String:line.c_str()]];
3197 if ([files_ count] != 0) {
3198 if ([[files_ objectAtIndex:0] isEqualToString:@"/."])
3199 [files_ removeObjectAtIndex:0];
3200 [files_ sortUsingSelector:@selector(compareByPath:)];
3202 NSMutableArray *stack = [NSMutableArray arrayWithCapacity:8];
3203 [stack addObject:@"/"];
3205 for (int i(0), e([files_ count]); i != e; ++i) {
3206 NSString *file = [files_ objectAtIndex:i];
3207 while (![file hasPrefix:[stack lastObject]])
3208 [stack removeLastObject];
3209 NSString *directory = [stack lastObject];
3210 [stack addObject:[file stringByAppendingString:@"/"]];
3211 [files_ replaceObjectAtIndex:i withObject:[NSString stringWithFormat:@"%*s%@",
3212 ([stack count] - 2) * 3, "",
3213 [file substringFromIndex:[directory length]]
3222 - (void) resetViewAnimated:(BOOL)animated {
3223 [list_ resetViewAnimated:animated];
3226 - (void) reloadData {
3227 [self setPackage:[database_ packageWithName:name_]];
3228 [self reloadButtons];
3231 - (NSString *) title {
3232 return @"Installed Files";
3235 - (NSString *) backButtonTitle {
3241 /* Package View {{{ */
3242 @interface PackageView : BrowserView {
3245 NSMutableArray *buttons_;
3248 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3249 - (void) setPackage:(Package *)package;
3253 @implementation PackageView
3256 if (package_ != nil)
3264 - (void) _clickButtonWithName:(NSString *)name {
3265 if ([name isEqualToString:@"Install"])
3266 [delegate_ installPackage:package_];
3267 else if ([name isEqualToString:@"Reinstall"])
3268 [delegate_ installPackage:package_];
3269 else if ([name isEqualToString:@"Remove"])
3270 [delegate_ removePackage:package_];
3271 else if ([name isEqualToString:@"Upgrade"])
3272 [delegate_ installPackage:package_];
3273 else _assert(false);
3276 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
3277 int count = [buttons_ count];
3278 _assert(count != 0);
3279 _assert(button <= count + 1);
3281 if (count != button - 1)
3282 [self _clickButtonWithName:[buttons_ objectAtIndex:(button - 1)]];
3287 - (void) webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame {
3288 [window setValue:package_ forKey:@"package"];
3291 - (void) _rightButtonClicked {
3292 /*[super _rightButtonClicked];
3295 int count = [buttons_ count];
3296 _assert(count != 0);
3299 [self _clickButtonWithName:[buttons_ objectAtIndex:0]];
3301 NSMutableArray *buttons = [NSMutableArray arrayWithCapacity:(count + 1)];
3302 [buttons addObjectsFromArray:buttons_];
3303 [buttons addObject:@"Cancel"];
3305 [delegate_ slideUp:[[[UIAlertSheet alloc]
3308 defaultButtonIndex:2
3315 - (NSString *) _rightButtonTitle {
3316 int count = [buttons_ count];
3317 return count == 0 ? nil : count != 1 ? @"Modify" : [buttons_ objectAtIndex:0];
3320 - (NSString *) title {
3324 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3325 if ((self = [super initWithBook:book database:database]) != nil) {
3326 database_ = database;
3327 buttons_ = [[NSMutableArray alloc] initWithCapacity:4];
3331 - (void) setPackage:(Package *)package {
3332 if (package_ != nil) {
3333 [package_ autorelease];
3342 [buttons_ removeAllObjects];
3344 if (package != nil) {
3345 package_ = [package retain];
3346 name_ = [[package id] retain];
3348 [self loadURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"package" ofType:@"html"]]];
3350 if ([package_ source] == nil);
3351 else if ([package_ upgradableAndEssential:NO])
3352 [buttons_ addObject:@"Upgrade"];
3353 else if ([package_ installed] == nil)
3354 [buttons_ addObject:@"Install"];
3356 [buttons_ addObject:@"Reinstall"];
3357 if ([package_ installed] != nil)
3358 [buttons_ addObject:@"Remove"];
3362 - (void) reloadData {
3363 [self setPackage:[database_ packageWithName:name_]];
3364 [self reloadButtons];
3369 /* Package Table {{{ */
3370 @interface PackageTable : RVPage {
3371 _transient Database *database_;
3375 NSMutableArray *packages_;
3376 NSMutableArray *sections_;
3377 UISectionList *list_;
3380 - (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object;
3382 - (void) setDelegate:(id)delegate;
3383 - (void) setObject:(id)object;
3385 - (void) reloadData;
3386 - (void) resetCursor;
3388 - (UISectionList *) list;
3390 - (void) setShouldHideHeaderInShortLists:(BOOL)hide;
3394 @implementation PackageTable
3397 [list_ setDataSource:nil];
3402 [packages_ release];
3403 [sections_ release];
3408 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
3409 return [sections_ count];
3412 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
3413 return [[sections_ objectAtIndex:section] name];
3416 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
3417 return [[sections_ objectAtIndex:section] row];
3420 - (int) numberOfRowsInTable:(UITable *)table {
3421 return [packages_ count];
3424 - (float) table:(UITable *)table heightForRow:(int)row {
3425 return [PackageCell heightForPackage:[packages_ objectAtIndex:row]];
3428 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
3430 reusing = [[[PackageCell alloc] init] autorelease];
3431 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
3435 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
3439 - (void) tableRowSelected:(NSNotification *)notification {
3440 int row = [[notification object] selectedRow];
3444 Package *package = [packages_ objectAtIndex:row];
3445 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
3446 [view setDelegate:delegate_];
3447 [view setPackage:package];
3448 [book_ pushPage:view];
3451 - (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object {
3452 if ((self = [super initWithBook:book]) != nil) {
3453 database_ = database;
3454 title_ = [title retain];
3456 object_ = object == nil ? nil : [object retain];
3458 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
3459 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
3461 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:YES];
3462 [list_ setDataSource:self];
3464 UITableColumn *column = [[[UITableColumn alloc]
3465 initWithTitle:@"Name"
3467 width:[self frame].size.width
3470 UITable *table = [list_ table];
3471 [table setSeparatorStyle:1];
3472 [table addTableColumn:column];
3473 [table setDelegate:self];
3474 [table setReusesTableCells:YES];
3476 [self addSubview:list_];
3481 - (void) setDelegate:(id)delegate {
3482 delegate_ = delegate;
3485 - (void) setObject:(id)object {
3491 object_ = [object retain];
3494 - (void) reloadData {
3495 NSArray *packages = [database_ packages];
3497 [packages_ removeAllObjects];
3498 [sections_ removeAllObjects];
3500 for (size_t i(0); i != [packages count]; ++i) {
3501 Package *package([packages objectAtIndex:i]);
3502 if ([[package performSelector:filter_ withObject:object_] boolValue])
3503 [packages_ addObject:package];
3506 Section *section = nil;
3508 for (size_t offset(0); offset != [packages_ count]; ++offset) {
3509 Package *package = [packages_ objectAtIndex:offset];
3510 NSString *name = [package index];
3512 if (section == nil || ![[section name] isEqualToString:name]) {
3513 section = [[[Section alloc] initWithName:name row:offset] autorelease];
3514 [sections_ addObject:section];
3517 [section addToCount];
3523 - (NSString *) title {
3527 - (void) resetViewAnimated:(BOOL)animated {
3528 [list_ resetViewAnimated:animated];
3531 - (void) resetCursor {
3532 [[list_ table] scrollPointVisibleAtTopLeft:CGPointMake(0, 0) animated:NO];
3535 - (UISectionList *) list {
3539 - (void) setShouldHideHeaderInShortLists:(BOOL)hide {
3540 [list_ setShouldHideHeaderInShortLists:hide];
3546 /* Add Source View {{{ */
3547 @interface AddSourceView : RVPage {
3548 _transient Database *database_;
3551 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3555 @implementation AddSourceView
3557 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3558 if ((self = [super initWithBook:book]) != nil) {
3559 database_ = database;
3565 /* Source Cell {{{ */
3566 @interface SourceCell : UITableCell {
3569 NSString *description_;
3575 - (SourceCell *) initWithSource:(Source *)source;
3579 @implementation SourceCell
3584 [description_ release];
3589 - (SourceCell *) initWithSource:(Source *)source {
3590 if ((self = [super init]) != nil) {
3592 icon_ = [UIImage applicationImageNamed:[NSString stringWithFormat:@"Sources/%@.png", [source host]]];
3594 icon_ = [UIImage applicationImageNamed:@"unknown.png"];
3595 icon_ = [icon_ retain];
3597 origin_ = [[source name] retain];
3598 label_ = [[source uri] retain];
3599 description_ = [[source description] retain];
3603 - (void) drawContentInRect:(CGRect)rect selected:(BOOL)selected {
3605 [icon_ drawInRect:CGRectMake(10, 10, 30, 30)];
3612 [origin_ drawAtPoint:CGPointMake(48, 8) forWidth:240 withFont:Font18Bold_ ellipsis:2];
3616 [label_ drawAtPoint:CGPointMake(58, 29) forWidth:225 withFont:Font12_ ellipsis:2];
3620 [description_ drawAtPoint:CGPointMake(12, 46) forWidth:280 withFont:Font14_ ellipsis:2];
3622 [super drawContentInRect:rect selected:selected];
3627 /* Source Table {{{ */
3628 @interface SourceTable : RVPage {
3629 _transient Database *database_;
3630 UISectionList *list_;
3631 NSMutableArray *sources_;
3632 UIAlertSheet *alert_;
3636 UIProgressHUD *hud_;
3639 //NSURLConnection *installer_;
3640 NSURLConnection *trivial_bz2_;
3641 NSURLConnection *trivial_gz_;
3642 //NSURLConnection *automatic_;
3647 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3651 @implementation SourceTable
3653 - (void) _deallocConnection:(NSURLConnection *)connection {
3654 if (connection != nil) {
3655 [connection cancel];
3656 //[connection setDelegate:nil];
3657 [connection release];
3662 [[list_ table] setDelegate:nil];
3663 [list_ setDataSource:nil];
3672 //[self _deallocConnection:installer_];
3673 [self _deallocConnection:trivial_gz_];
3674 [self _deallocConnection:trivial_bz2_];
3675 //[self _deallocConnection:automatic_];
3682 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
3683 return offset_ == 0 ? 1 : 2;
3686 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
3687 switch (section + (offset_ == 0 ? 1 : 0)) {
3688 case 0: return @"Entered by User";
3689 case 1: return @"Installed by Packages";
3697 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
3698 switch (section + (offset_ == 0 ? 1 : 0)) {
3700 case 1: return offset_;
3708 - (int) numberOfRowsInTable:(UITable *)table {
3709 return [sources_ count];
3712 - (float) table:(UITable *)table heightForRow:(int)row {
3713 Source *source = [sources_ objectAtIndex:row];
3714 return [source description] == nil ? 56 : 73;
3717 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col {
3718 Source *source = [sources_ objectAtIndex:row];
3719 // XXX: weird warning, stupid selectors ;P
3720 return [[[SourceCell alloc] initWithSource:(id)source] autorelease];
3723 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
3727 - (BOOL) table:(UITable *)table canSelectRow:(int)row {
3731 - (void) tableRowSelected:(NSNotification*)notification {
3732 UITable *table([list_ table]);
3733 int row([table selectedRow]);
3737 Source *source = [sources_ objectAtIndex:row];
3739 PackageTable *packages = [[[PackageTable alloc]
3742 title:[source label]
3743 filter:@selector(isVisibleInSource:)
3747 [packages setDelegate:delegate_];
3749 [book_ pushPage:packages];
3752 - (BOOL) table:(UITable *)table canDeleteRow:(int)row {
3753 Source *source = [sources_ objectAtIndex:row];
3754 return [source record] != nil;
3757 - (void) table:(UITable *)table willSwipeToDeleteRow:(int)row {
3758 [[list_ table] setDeleteConfirmationRow:row];
3761 - (void) table:(UITable *)table deleteRow:(int)row {
3762 Source *source = [sources_ objectAtIndex:row];
3763 [Sources_ removeObjectForKey:[source key]];
3764 [delegate_ syncData];
3767 - (void) _endConnection:(NSURLConnection *)connection {
3768 NSURLConnection **field = NULL;
3769 if (connection == trivial_bz2_)
3770 field = &trivial_bz2_;
3771 else if (connection == trivial_gz_)
3772 field = &trivial_gz_;
3773 _assert(field != NULL);
3774 [connection release];
3778 trivial_bz2_ == nil &&
3781 [delegate_ setStatusBarShowsProgress:NO];
3784 [hud_ removeFromSuperview];
3789 [Sources_ setObject:[NSDictionary dictionaryWithObjectsAndKeys:
3792 @"./", @"Distribution",
3793 nil] forKey:[NSString stringWithFormat:@"deb:%@:./", href_]];
3795 [delegate_ syncData];
3796 } else if (error_ != nil) {
3797 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
3798 initWithTitle:@"Verification Error"
3799 buttons:[NSArray arrayWithObjects:@"OK", nil]
3800 defaultButtonIndex:0
3805 [sheet setBodyText:[error_ localizedDescription]];
3806 [sheet popupAlertAnimated:YES];
3808 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
3809 initWithTitle:@"Did not Find Repository"
3810 buttons:[NSArray arrayWithObjects:@"OK", nil]
3811 defaultButtonIndex:0
3816 [sheet setBodyText:@"The indicated repository could not be found. This could be because you are trying to add a legacy Installer repository (these are not supported). Also, this interface is only capable of working with exact repository URLs. If you host a repository and are having issues please contact the author of Cydia with any questions you have."];
3817 [sheet popupAlertAnimated:YES];
3823 if (error_ != nil) {
3830 - (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response {
3831 switch ([response statusCode]) {
3837 - (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
3838 fprintf(stderr, "connection:\"%s\" didFailWithError:\"%s\"", [href_ UTF8String], [[error localizedDescription] UTF8String]);
3840 error_ = [error retain];
3841 [self _endConnection:connection];
3844 - (void) connectionDidFinishLoading:(NSURLConnection *)connection {
3845 [self _endConnection:connection];
3848 - (NSURLConnection *) _requestHRef:(NSString *)href method:(NSString *)method {
3849 NSMutableURLRequest *request = [NSMutableURLRequest
3850 requestWithURL:[NSURL URLWithString:href]
3851 cachePolicy:NSURLRequestUseProtocolCachePolicy
3852 timeoutInterval:20.0
3855 [request setHTTPMethod:method];
3857 return [[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease];
3860 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
3861 NSString *context = [sheet context];
3862 if ([context isEqualToString:@"source"])
3865 NSString *href = [[sheet textField] text];
3867 //installer_ = [[self _requestHRef:href method:@"GET"] retain];
3869 if (![href hasSuffix:@"/"])
3870 href_ = [href stringByAppendingString:@"/"];
3873 href_ = [href_ retain];
3875 trivial_bz2_ = [[self _requestHRef:[href_ stringByAppendingString:@"Packages.bz2"] method:@"HEAD"] retain];
3876 trivial_gz_ = [[self _requestHRef:[href_ stringByAppendingString:@"Packages.gz"] method:@"HEAD"] retain];
3877 //trivial_bz2_ = [[self _requestHRef:[href stringByAppendingString:@"dists/Release"] method:@"HEAD"] retain];
3881 hud_ = [delegate_ addProgressHUD];
3882 [hud_ setText:@"Verifying URL"];
3895 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3896 if ((self = [super initWithBook:book]) != nil) {
3897 database_ = database;
3898 sources_ = [[NSMutableArray arrayWithCapacity:16] retain];
3900 //list_ = [[UITable alloc] initWithFrame:[self bounds]];
3901 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:NO];
3902 [list_ setShouldHideHeaderInShortLists:NO];
3904 [self addSubview:list_];
3905 [list_ setDataSource:self];
3907 UITableColumn *column = [[UITableColumn alloc]
3908 initWithTitle:@"Name"
3910 width:[self frame].size.width
3913 UITable *table = [list_ table];
3914 [table setSeparatorStyle:1];
3915 [table addTableColumn:column];
3916 [table setDelegate:self];
3922 - (void) reloadData {
3924 _assert(list.ReadMainList());
3926 [sources_ removeAllObjects];
3927 [sources_ addObjectsFromArray:[database_ sources]];
3928 [sources_ sortUsingSelector:@selector(compareByNameAndType:)];
3930 int count = [sources_ count];
3931 for (offset_ = 0; offset_ != count; ++offset_) {
3932 Source *source = [sources_ objectAtIndex:offset_];
3933 if ([source record] == nil)
3940 - (void) resetViewAnimated:(BOOL)animated {
3941 [list_ resetViewAnimated:animated];
3944 - (void) _leftButtonClicked {
3945 /*[book_ pushPage:[[[AddSourceView alloc]
3950 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
3951 initWithTitle:@"Enter Cydia/APT URL"
3952 buttons:[NSArray arrayWithObjects:@"Add Source", @"Cancel", nil]
3953 defaultButtonIndex:0
3958 [sheet addTextFieldWithValue:@"http://" label:@""];
3960 UITextTraits *traits = [[sheet textField] textTraits];
3961 [traits setAutoCapsType:0];
3962 [traits setPreferredKeyboardType:3];
3963 [traits setAutoCorrectionType:1];
3965 [sheet popupAlertAnimated:YES];
3968 - (void) _rightButtonClicked {
3969 UITable *table = [list_ table];
3970 BOOL editing = [table isRowDeletionEnabled];
3971 [table enableRowDeletion:!editing animated:YES];
3972 [book_ reloadButtonsForPage:self];
3975 - (NSString *) title {
3979 - (NSString *) backButtonTitle {
3983 - (NSString *) leftButtonTitle {
3984 return [[list_ table] isRowDeletionEnabled] ? @"Add" : nil;
3987 - (NSString *) rightButtonTitle {
3988 return [[list_ table] isRowDeletionEnabled] ? @"Done" : @"Edit";
3991 - (RVUINavBarButtonStyle) rightButtonStyle {
3992 return [[list_ table] isRowDeletionEnabled] ? RVUINavBarButtonStyleHighlighted : RVUINavBarButtonStyleNormal;
3998 /* Installed View {{{ */
3999 @interface InstalledView : RVPage {
4000 _transient Database *database_;
4001 PackageTable *packages_;
4005 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4009 @implementation InstalledView
4012 [packages_ release];
4016 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4017 if ((self = [super initWithBook:book]) != nil) {
4018 database_ = database;
4020 packages_ = [[PackageTable alloc]
4024 filter:@selector(isInstalledAndVisible:)
4025 with:[NSNumber numberWithBool:YES]
4028 [self addSubview:packages_];
4032 - (void) resetViewAnimated:(BOOL)animated {
4033 [packages_ resetViewAnimated:animated];
4036 - (void) reloadData {
4037 [packages_ reloadData];
4040 - (void) _rightButtonClicked {
4041 [packages_ setObject:[NSNumber numberWithBool:expert_]];
4042 [packages_ reloadData];
4044 [book_ reloadButtonsForPage:self];
4047 - (NSString *) title {
4048 return @"Installed";
4051 - (NSString *) backButtonTitle {
4055 - (NSString *) rightButtonTitle {
4056 return Role_ != nil && [Role_ isEqualToString:@"Developer"] ? nil : expert_ ? @"Expert" : @"Simple";
4059 - (RVUINavBarButtonStyle) rightButtonStyle {
4060 return expert_ ? RVUINavBarButtonStyleHighlighted : RVUINavBarButtonStyleNormal;
4063 - (void) setDelegate:(id)delegate {
4064 [super setDelegate:delegate];
4065 [packages_ setDelegate:delegate];
4072 @interface HomeView : BrowserView {
4077 @implementation HomeView
4079 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
4083 - (void) _leftButtonClicked {
4084 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
4085 initWithTitle:@"About Cydia Installer"
4086 buttons:[NSArray arrayWithObjects:@"Close", nil]
4087 defaultButtonIndex:0
4093 @"Copyright (C) 2008\n"
4094 "Jay Freeman (saurik)\n"
4095 "saurik@saurik.com\n"
4096 "http://www.saurik.com/\n"
4099 "http://www.theokorigroup.com/\n"
4101 "College of Creative Studies,\n"
4102 "University of California,\n"
4104 "http://www.ccs.ucsb.edu/"
4107 [sheet popupAlertAnimated:YES];
4110 - (NSString *) leftButtonTitle {
4116 /* Manage View {{{ */
4117 @interface ManageView : BrowserView {
4122 @implementation ManageView
4124 - (NSString *) title {
4128 - (void) _leftButtonClicked {
4129 [delegate_ askForSettings];
4132 - (NSString *) leftButtonTitle {
4136 - (NSString *) _rightButtonTitle {
4143 /* Browser Implementation {{{ */
4144 @implementation BrowserView
4147 WebView *webview = [webview_ webView];
4148 [webview setFrameLoadDelegate:nil];
4149 [webview setResourceLoadDelegate:nil];
4150 [webview setUIDelegate:nil];
4152 [scroller_ setDelegate:nil];
4153 [webview_ setDelegate:nil];
4155 [scroller_ release];
4158 [indicator_ release];
4164 - (void) loadURL:(NSURL *)url cachePolicy:(NSURLRequestCachePolicy)policy {
4165 [self loadRequest:[NSURLRequest
4168 timeoutInterval:30.0
4172 - (void) loadURL:(NSURL *)url {
4173 [self loadURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy];
4176 - (NSURLRequest *) _addHeadersToRequest:(NSURLRequest *)request {
4177 NSMutableURLRequest *copy = [request mutableCopy];
4179 [copy addValue:[NSString stringWithUTF8String:Firmware_] forHTTPHeaderField:@"X-Firmware"];
4180 [copy addValue:[NSString stringWithUTF8String:Machine_] forHTTPHeaderField:@"X-Machine"];
4181 [copy addValue:[NSString stringWithUTF8String:SerialNumber_] forHTTPHeaderField:@"X-Serial-Number"];
4184 [copy addValue:Role_ forHTTPHeaderField:@"X-Role"];
4189 - (void) loadRequest:(NSURLRequest *)request {
4191 [webview_ loadRequest:request];
4194 - (void) reloadURL {
4195 NSURL *url = [[[urls_ lastObject] retain] autorelease];
4196 [urls_ removeLastObject];
4197 [self loadURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData];
4200 - (WebView *) webView {
4201 return [webview_ webView];
4204 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame {
4205 [scroller_ setContentSize:frame.size];
4208 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old {
4209 [self view:sender didSetFrame:frame];
4212 - (void) pushPage:(RVPage *)page {
4213 [self setBackButtonTitle:title_];
4214 [page setDelegate:delegate_];
4215 [book_ pushPage:page];
4218 - (void) getSpecial:(NSString *)href {
4221 if ([href hasPrefix:@"mailto:"])
4222 [delegate_ openURL:[NSURL URLWithString:href]];
4223 else if ([href isEqualToString:@"cydia://add-source"])
4224 page = [[[AddSourceView alloc] initWithBook:book_ database:database_] autorelease];
4225 else if ([href isEqualToString:@"cydia://sources"])
4226 page = [[[SourceTable alloc] initWithBook:book_ database:database_] autorelease];
4227 else if ([href isEqualToString:@"cydia://packages"])
4228 page = [[[InstalledView alloc] initWithBook:book_ database:database_] autorelease];
4229 else if ([href hasPrefix:@"cydia://files/"]) {
4230 NSString *name = [href substringFromIndex:14];
4232 if (Package *package = [database_ packageWithName:name]) {
4233 FileTable *files = [[[FileTable alloc] initWithBook:book_ database:database_] autorelease];
4234 [files setPackage:package];
4237 } else if ([href hasPrefix:@"apptapp://package/"]) {
4238 NSString *name = [href substringFromIndex:18];
4240 if (Package *package = [database_ packageWithName:name]) {
4241 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
4242 [view setPackage:package];
4245 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
4246 initWithTitle:@"Cannot Locate Package"
4247 buttons:[NSArray arrayWithObjects:@"Close", nil]
4248 defaultButtonIndex:0
4253 [sheet setBodyText:[NSString stringWithFormat:
4254 @"The package %@ cannot be found in your current sources. I might recommend installing more sources."
4257 [sheet popupAlertAnimated:YES];
4262 [self pushPage:page];
4265 - (void) webView:(WebView *)sender willClickElement:(id)element {
4266 if ([[element localName] isEqualToString:@"img"])
4267 do if ((element = [element parentNode]) == nil)
4269 while (![[element localName] isEqualToString:@"a"]);
4270 if (![element respondsToSelector:@selector(href)])
4272 NSString *href = [element href];
4275 [self getSpecial:href];
4278 - (BOOL) isSpecialScheme:(NSString *)scheme {
4280 [scheme isEqualToString:@"apptapp"] ||
4281 [scheme isEqualToString:@"cydia"] ||
4282 [scheme isEqualToString:@"mailto"];
4285 - (NSURLRequest *) webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource {
4286 NSURL *url = [request URL];
4287 if ([self isSpecialScheme:[url scheme]]) {
4288 [self getSpecial:[url absoluteString]];
4294 [book_ pushPage:self];
4297 return [self _addHeadersToRequest:request];
4300 - (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request {
4301 if (request != nil) {
4302 NSString *scheme = [[request URL] scheme];
4303 if ([self isSpecialScheme:scheme])
4307 [self setBackButtonTitle:title_];
4309 BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease];
4310 [browser setDelegate:delegate_];
4312 if (request != nil) {
4313 [browser loadRequest:[self _addHeadersToRequest:request]];
4314 [book_ pushPage:browser];
4317 return [browser webView];
4320 - (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame {
4321 title_ = [title retain];
4322 [self setTitle:title];
4325 - (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame {
4326 if ([frame parentFrame] != nil)
4331 [indicator_ startAnimation];
4332 [self reloadButtons];
4334 if (title_ != nil) {
4339 [self setTitle:@"Loading..."];
4341 WebView *webview = [webview_ webView];
4342 NSString *href = [webview mainFrameURL];
4343 [urls_ addObject:[NSURL URLWithString:href]];
4345 CGRect webrect = [scroller_ frame];
4346 webrect.size.height = 0;
4347 [webview_ setFrame:webrect];
4350 - (void) _finishLoading {
4353 [indicator_ stopAnimation];
4354 [self reloadButtons];
4358 - (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
4359 if ([frame parentFrame] != nil)
4361 [self _finishLoading];
4364 - (void) webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
4365 if ([frame parentFrame] != nil)
4367 [self _finishLoading];
4369 [self loadURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@?%@",
4370 [[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"error" ofType:@"html"]] absoluteString],
4371 [[error localizedDescription] stringByAddingPercentEscapes]
4375 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4376 if ((self = [super initWithBook:book]) != nil) {
4377 database_ = database;
4380 struct CGRect bounds = [self bounds];
4382 UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:bounds] autorelease];
4383 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
4384 [self addSubview:pinstripe];
4386 scroller_ = [[UIScroller alloc] initWithFrame:bounds];
4387 [self addSubview:scroller_];
4389 [scroller_ setScrollingEnabled:YES];
4390 [scroller_ setAdjustForContentSizeChange:YES];
4391 [scroller_ setClipsSubviews:YES];
4392 [scroller_ setAllowsRubberBanding:YES];
4393 [scroller_ setScrollDecelerationFactor:0.99];
4394 [scroller_ setDelegate:self];
4396 CGRect webrect = [scroller_ bounds];
4397 webrect.size.height = 0;
4399 webview_ = [[UIWebView alloc] initWithFrame:webrect];
4400 [scroller_ addSubview:webview_];
4402 [webview_ setTilingEnabled:YES];
4403 [webview_ setTileSize:CGSizeMake(webrect.size.width, 500)];
4404 [webview_ setAutoresizes:YES];
4405 [webview_ setDelegate:self];
4406 //[webview_ setEnabledGestures:2];
4408 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:kUIProgressIndicatorStyleMediumWhite];
4409 indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(281, 42, indsize.width, indsize.height)];
4410 [indicator_ setStyle:kUIProgressIndicatorStyleMediumWhite];
4412 Package *package([database_ packageWithName:@"cydia"]);
4413 NSString *application = package == nil ? @"Cydia" : [NSString
4414 stringWithFormat:@"Cydia/%@",
4418 WebView *webview = [webview_ webView];
4419 [webview setApplicationNameForUserAgent:application];
4420 [webview setFrameLoadDelegate:self];
4421 [webview setResourceLoadDelegate:self];
4422 [webview setUIDelegate:self];
4424 urls_ = [[NSMutableArray alloc] initWithCapacity:16];
4428 - (void) _rightButtonClicked {
4433 - (NSString *) _rightButtonTitle {
4437 - (NSString *) rightButtonTitle {
4438 return loading_ ? @"" : [self _rightButtonTitle];
4441 - (NSString *) title {
4445 - (NSString *) backButtonTitle {
4449 - (void) setPageActive:(BOOL)active {
4451 [book_ addSubview:indicator_];
4453 [indicator_ removeFromSuperview];
4456 - (void) resetViewAnimated:(BOOL)animated {
4459 - (void) setPushed:(bool)pushed {
4466 @interface CYBook : RVBook <
4469 _transient Database *database_;
4471 UIProgressIndicator *indicator_;
4472 UITextLabel *prompt_;
4473 UIProgressBar *progress_;
4477 - (id) initWithFrame:(CGRect)frame database:(Database *)database;
4483 /* Install View {{{ */
4484 @interface InstallView : RVPage {
4485 _transient Database *database_;
4486 NSMutableArray *sections_;
4487 NSMutableArray *filtered_;
4488 UITransitionView *transition_;
4494 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4495 - (void) reloadData;
4500 @implementation InstallView
4503 [list_ setDataSource:nil];
4504 [list_ setDelegate:nil];
4506 [sections_ release];
4507 [filtered_ release];
4508 [transition_ release];
4510 [accessory_ release];
4514 - (int) numberOfRowsInTable:(UITable *)table {
4515 return editing_ ? [sections_ count] : [filtered_ count] + 1;
4518 - (float) table:(UITable *)table heightForRow:(int)row {
4522 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
4524 reusing = [[[SectionCell alloc] init] autorelease];
4525 [(SectionCell *)reusing setSection:(editing_ ?
4526 [sections_ objectAtIndex:row] :
4527 (row == 0 ? nil : [filtered_ objectAtIndex:(row - 1)])
4528 ) editing:editing_];
4532 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
4536 - (BOOL) table:(UITable *)table canSelectRow:(int)row {
4540 - (void) tableRowSelected:(NSNotification *)notification {
4541 int row = [[notification object] selectedRow];
4552 title = @"All Packages";
4554 section = [filtered_ objectAtIndex:(row - 1)];
4555 name = [section name];
4561 title = @"(No Section)";
4565 PackageTable *table = [[[PackageTable alloc]
4569 filter:@selector(isVisiblyUninstalledInSection:)
4573 [table setDelegate:delegate_];
4575 [book_ pushPage:table];
4578 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4579 if ((self = [super initWithBook:book]) != nil) {
4580 database_ = database;
4582 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
4583 filtered_ = [[NSMutableArray arrayWithCapacity:16] retain];
4585 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
4586 [self addSubview:transition_];
4588 list_ = [[UITable alloc] initWithFrame:[transition_ bounds]];
4589 [transition_ transition:0 toView:list_];
4591 UITableColumn *column = [[[UITableColumn alloc]
4592 initWithTitle:@"Name"
4594 width:[self frame].size.width
4597 [list_ setDataSource:self];
4598 [list_ setSeparatorStyle:1];
4599 [list_ addTableColumn:column];
4600 [list_ setDelegate:self];
4601 [list_ setReusesTableCells:YES];
4607 - (void) reloadData {
4608 NSArray *packages = [database_ packages];
4610 [sections_ removeAllObjects];
4611 [filtered_ removeAllObjects];
4613 NSMutableArray *filtered = [NSMutableArray arrayWithCapacity:[packages count]];
4614 NSMutableDictionary *sections = [NSMutableDictionary dictionaryWithCapacity:32];
4616 for (size_t i(0); i != [packages count]; ++i) {
4617 Package *package([packages objectAtIndex:i]);
4618 NSString *name([package section]);
4621 Section *section([sections objectForKey:name]);
4622 if (section == nil) {
4623 section = [[[Section alloc] initWithName:name] autorelease];
4624 [sections setObject:section forKey:name];
4628 if ([package valid] && [package installed] == nil && [package visible])
4629 [filtered addObject:package];
4632 [sections_ addObjectsFromArray:[sections allValues]];
4633 [sections_ sortUsingSelector:@selector(compareByName:)];
4635 [filtered sortUsingSelector:@selector(compareBySection:)];
4637 Section *section = nil;
4638 for (size_t offset = 0, count = [filtered count]; offset != count; ++offset) {
4639 Package *package = [filtered objectAtIndex:offset];
4640 NSString *name = [package section];
4642 if (section == nil || name != nil && ![[section name] isEqualToString:name]) {
4643 section = name == nil ?
4644 [[[Section alloc] initWithName:nil] autorelease] :
4645 [sections objectForKey:name];
4646 [filtered_ addObject:section];
4649 [section addToCount];
4655 - (void) resetView {
4657 [self _rightButtonClicked];
4660 - (void) resetViewAnimated:(BOOL)animated {
4661 [list_ resetViewAnimated:animated];
4664 - (void) _rightButtonClicked {
4665 if ((editing_ = !editing_))
4668 [delegate_ updateData];
4671 [book_ setTitle:[self title] forPage:self];
4672 [book_ reloadButtonsForPage:self];
4675 - (NSString *) title {
4676 return editing_ ? @"Section Visibility" : @"Install by Section";
4679 - (NSString *) backButtonTitle {
4683 - (NSString *) rightButtonTitle {
4684 return [sections_ count] == 0 ? nil : editing_ ? @"Done" : @"Edit";
4687 - (UIView *) accessoryView {
4693 /* Changes View {{{ */
4694 @interface ChangesView : RVPage {
4695 _transient Database *database_;
4696 NSMutableArray *packages_;
4697 NSMutableArray *sections_;
4698 UISectionList *list_;
4702 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4703 - (void) reloadData;
4707 @implementation ChangesView
4710 [[list_ table] setDelegate:nil];
4711 [list_ setDataSource:nil];
4713 [packages_ release];
4714 [sections_ release];
4719 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
4720 return [sections_ count];
4723 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
4724 return [[sections_ objectAtIndex:section] name];
4727 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
4728 return [[sections_ objectAtIndex:section] row];
4731 - (int) numberOfRowsInTable:(UITable *)table {
4732 return [packages_ count];
4735 - (float) table:(UITable *)table heightForRow:(int)row {
4736 return [PackageCell heightForPackage:[packages_ objectAtIndex:row]];
4739 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
4741 reusing = [[[PackageCell alloc] init] autorelease];
4742 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
4746 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
4750 - (void) tableRowSelected:(NSNotification *)notification {
4751 int row = [[notification object] selectedRow];
4754 Package *package = [packages_ objectAtIndex:row];
4755 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
4756 [view setDelegate:delegate_];
4757 [view setPackage:package];
4758 [book_ pushPage:view];
4761 - (void) _leftButtonClicked {
4762 [(CYBook *)book_ update];
4763 [self reloadButtons];
4766 - (void) _rightButtonClicked {
4767 [delegate_ distUpgrade];
4770 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4771 if ((self = [super initWithBook:book]) != nil) {
4772 database_ = database;
4774 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
4775 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
4777 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:NO];
4778 [self addSubview:list_];
4780 [list_ setShouldHideHeaderInShortLists:NO];
4781 [list_ setDataSource:self];
4782 //[list_ setSectionListStyle:1];
4784 UITableColumn *column = [[[UITableColumn alloc]
4785 initWithTitle:@"Name"
4787 width:[self frame].size.width
4790 UITable *table = [list_ table];
4791 [table setSeparatorStyle:1];
4792 [table addTableColumn:column];
4793 [table setDelegate:self];
4794 [table setReusesTableCells:YES];
4800 - (void) reloadData {
4801 NSArray *packages = [database_ packages];
4803 [packages_ removeAllObjects];
4804 [sections_ removeAllObjects];
4806 for (size_t i(0); i != [packages count]; ++i) {
4807 Package *package([packages objectAtIndex:i]);
4810 [package installed] == nil && [package valid] && [package visible] ||
4811 [package upgradableAndEssential:NO]
4813 [packages_ addObject:package];
4816 [packages_ sortUsingSelector:@selector(compareForChanges:)];
4818 Section *upgradable = [[[Section alloc] initWithName:@"Available Upgrades"] autorelease];
4819 Section *section = nil;
4822 bool unseens = false;
4824 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, Locale_, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
4826 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
4827 Package *package = [packages_ objectAtIndex:offset];
4829 if ([package upgradableAndEssential:YES]) {
4831 [upgradable addToCount];
4834 NSDate *seen = [package seen];
4839 name = [@"n/a ?" retain];
4841 name = (NSString *) CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen);
4844 if (section == nil || ![[section name] isEqualToString:name]) {
4845 section = [[[Section alloc] initWithName:name row:offset] autorelease];
4846 [sections_ addObject:section];
4850 [section addToCount];
4854 CFRelease(formatter);
4857 Section *last = [sections_ lastObject];
4858 size_t count = [last count];
4859 [packages_ removeObjectsInRange:NSMakeRange([packages_ count] - count, count)];
4860 [sections_ removeLastObject];
4864 [sections_ insertObject:upgradable atIndex:0];
4867 [self reloadButtons];
4870 - (void) resetViewAnimated:(BOOL)animated {
4871 [list_ resetViewAnimated:animated];
4874 - (NSString *) leftButtonTitle {
4875 return [(CYBook *)book_ updating] ? nil : @"Refresh";
4878 - (NSString *) rightButtonTitle {
4879 return upgrades_ == 0 ? nil : [NSString stringWithFormat:@"Upgrade (%u)", upgrades_];
4882 - (NSString *) title {
4888 /* Search View {{{ */
4889 @protocol SearchViewDelegate
4890 - (void) showKeyboard:(BOOL)show;
4893 @interface SearchView : RVPage {
4895 UISearchField *field_;
4896 UITransitionView *transition_;
4897 PackageTable *table_;
4898 UIPreferencesTable *advanced_;
4904 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4905 - (void) reloadData;
4909 @implementation SearchView
4913 [[field_ textTraits] setEditingDelegate:nil];
4915 [field_ setDelegate:nil];
4917 [accessory_ release];
4919 [transition_ release];
4921 [advanced_ release];
4926 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
4930 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
4932 case 0: return @"Advanced Search (Coming Soon!)";
4934 default: _assert(false);
4938 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
4942 default: _assert(false);
4946 - (void) _showKeyboard:(BOOL)show {
4947 CGSize keysize = [UIKeyboard defaultSize];
4948 CGRect keydown = [book_ pageBounds];
4949 CGRect keyup = keydown;
4950 keyup.size.height -= keysize.height - ButtonBarHeight_;
4952 float delay = KeyboardTime_ * ButtonBarHeight_ / keysize.height;
4954 UIFrameAnimation *animation = [[[UIFrameAnimation alloc] initWithTarget:[table_ list]] autorelease];
4955 [animation setSignificantRectFields:8];
4958 [animation setStartFrame:keydown];
4959 [animation setEndFrame:keyup];
4961 [animation setStartFrame:keyup];
4962 [animation setEndFrame:keydown];
4965 UIAnimator *animator = [UIAnimator sharedAnimator];
4968 addAnimations:[NSArray arrayWithObjects:animation, nil]
4969 withDuration:(KeyboardTime_ - delay)
4974 [animator performSelector:@selector(startAnimation:) withObject:animation afterDelay:delay];
4977 [delegate_ showKeyboard:show];
4981 - (void) textFieldDidBecomeFirstResponder:(UITextField *)field {
4982 [self _showKeyboard:YES];
4985 - (void) textFieldDidResignFirstResponder:(UITextField *)field {
4986 [self _showKeyboard:NO];
4989 - (void) keyboardInputChanged:(UIFieldEditor *)editor {
4991 NSString *text([field_ text]);
4992 [field_ setClearButtonStyle:(text == nil || [text length] == 0 ? 0 : 2)];
4998 - (void) textFieldClearButtonPressed:(UITextField *)field {
5002 - (void) keyboardInputShouldDelete:(id)input {
5006 - (BOOL) keyboardInput:(id)input shouldInsertText:(NSString *)text isMarkedText:(int)marked {
5007 if ([text length] != 1 || [text characterAtIndex:0] != '\n') {
5011 [field_ resignFirstResponder];
5016 - (id) initWithBook:(RVBook *)book database:(Database *)database {
5017 if ((self = [super initWithBook:book]) != nil) {
5018 CGRect pageBounds = [book_ pageBounds];
5020 /*UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:pageBounds] autorelease];
5021 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
5022 [self addSubview:pinstripe];*/
5024 transition_ = [[UITransitionView alloc] initWithFrame:pageBounds];
5025 [self addSubview:transition_];
5027 advanced_ = [[UIPreferencesTable alloc] initWithFrame:pageBounds];
5029 [advanced_ setReusesTableCells:YES];
5030 [advanced_ setDataSource:self];
5031 [advanced_ reloadData];
5033 dimmed_ = [[UIView alloc] initWithFrame:pageBounds];
5034 CGColor dimmed(space_, 0, 0, 0, 0.5);
5035 [dimmed_ setBackgroundColor:dimmed];
5037 table_ = [[PackageTable alloc]
5041 filter:@selector(isVisiblySearchedForBy:)
5045 [table_ setShouldHideHeaderInShortLists:NO];
5046 [transition_ transition:0 toView:table_];
5055 area.origin.x = /*cnfrect.origin.x + cnfrect.size.width + 4 +*/ 10;
5062 [self bounds].size.width - area.origin.x - 18;
5064 area.size.height = [UISearchField defaultHeight];
5066 field_ = [[UISearchField alloc] initWithFrame:area];
5068 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
5069 [field_ setFont:font];
5072 [field_ setPlaceholder:@"Package Names & Descriptions"];
5073 [field_ setDelegate:self];
5076 [field_ setPaddingTop:3];
5078 [field_ setPaddingTop:5];
5081 UITextTraits *traits = [field_ textTraits];
5082 [traits setAutoCapsType:0];
5083 [traits setAutoCorrectionType:1];
5084 [traits setReturnKeyType:6];
5087 [traits setEditingDelegate:self];
5090 CGRect accrect = {{0, 6}, {6 + cnfrect.size.width + 6 + area.size.width + 6, area.size.height + 30}};
5092 accessory_ = [[UIView alloc] initWithFrame:accrect];
5093 [accessory_ addSubview:field_];
5095 /*UIPushButton *configure = [[[UIPushButton alloc] initWithFrame:cnfrect] autorelease];
5096 [configure setShowPressFeedback:YES];
5097 [configure setImage:[UIImage applicationImageNamed:@"advanced.png"]];
5098 [configure addTarget:self action:@selector(configurePushed) forEvents:1];
5099 [accessory_ addSubview:configure];*/
5105 LKAnimation *animation = [LKTransition animation];
5106 [animation setType:@"oglFlip"];
5107 [animation setTimingFunction:[LKTimingFunction functionWithName:@"easeInEaseOut"]];
5108 [animation setFillMode:@"extended"];
5109 [animation setTransitionFlags:3];
5110 [animation setDuration:10];
5111 [animation setSpeed:0.35];
5112 [animation setSubtype:(flipped_ ? @"fromLeft" : @"fromRight")];
5113 [[transition_ _layer] addAnimation:animation forKey:0];
5114 [transition_ transition:0 toView:(flipped_ ? (UIView *) table_ : (UIView *) advanced_)];
5115 flipped_ = !flipped_;
5119 - (void) configurePushed {
5120 [field_ resignFirstResponder];
5124 - (void) resetViewAnimated:(BOOL)animated {
5127 [table_ resetViewAnimated:animated];
5130 - (void) reloadData {
5133 [table_ setObject:[field_ text]];
5134 [table_ reloadData];
5135 [table_ resetCursor];
5138 - (UIView *) accessoryView {
5142 - (NSString *) title {
5146 - (NSString *) backButtonTitle {
5150 - (void) setDelegate:(id)delegate {
5151 [table_ setDelegate:delegate];
5152 [super setDelegate:delegate];
5158 @implementation CYBook
5162 [indicator_ release];
5164 [progress_ release];
5168 - (NSString *) getTitleForPage:(RVPage *)page {
5169 return Simplify([super getTitleForPage:page]);
5177 [navbar_ setPrompt:@""];
5178 [navbar_ addSubview:overlay_];
5179 [indicator_ startAnimation];
5180 [prompt_ setText:@"Updating Database..."];
5181 [progress_ setProgress:0];
5186 detachNewThreadSelector:@selector(_update)
5195 [overlay_ removeFromSuperview];
5196 [indicator_ stopAnimation];
5197 [delegate_ reloadData];
5199 [self setPrompt:[NSString stringWithFormat:@"Last Updated: %@", GetLastUpdate()]];
5202 - (id) initWithFrame:(CGRect)frame database:(Database *)database {
5203 if ((self = [super initWithFrame:frame]) != nil) {
5204 database_ = database;
5206 CGRect ovrrect = [navbar_ bounds];
5207 ovrrect.size.height = ([UINavigationBar defaultSizeWithPrompt].height - [UINavigationBar defaultSize].height);
5209 overlay_ = [[UIView alloc] initWithFrame:ovrrect];
5211 bool ugly = [navbar_ _barStyle:NO] == 0;
5213 UIProgressIndicatorStyle style = ugly ?
5214 kUIProgressIndicatorStyleSmallBlack :
5215 kUIProgressIndicatorStyleSmallWhite;
5217 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:style];
5218 unsigned indoffset = (ovrrect.size.height - indsize.height) / 2;
5219 CGRect indrect = {{indoffset, indoffset}, indsize};
5221 indicator_ = [[UIProgressIndicator alloc] initWithFrame:indrect];
5222 [indicator_ setStyle:style];
5223 [overlay_ addSubview:indicator_];
5225 CGSize prmsize = {200, indsize.width + 4};
5228 indoffset * 2 + indsize.width,
5232 (ovrrect.size.height - prmsize.height) / 2
5235 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 12);
5237 prompt_ = [[UITextLabel alloc] initWithFrame:prmrect];
5239 [prompt_ setColor:(ugly ? Blueish_ : White_)];
5240 [prompt_ setBackgroundColor:Clear_];
5241 [prompt_ setFont:font];
5245 [overlay_ addSubview:prompt_];
5247 CGSize prgsize = {75, 100};
5250 ovrrect.size.width - prgsize.width - 10,
5251 (ovrrect.size.height - prgsize.height) / 2
5254 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
5255 [progress_ setStyle:0];
5256 [overlay_ addSubview:progress_];
5261 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5264 status.setDelegate(self);
5266 [database_ updateWithStatus:status];
5269 performSelectorOnMainThread:@selector(_update_)
5277 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id {
5278 [prompt_ setText:[NSString stringWithFormat:@"Error: %@", error]];
5281 - (void) setProgressTitle:(NSString *)title {
5283 performSelectorOnMainThread:@selector(_setProgressTitle:)
5289 - (void) setProgressPercent:(float)percent {
5292 - (void) addProgressOutput:(NSString *)output {
5294 performSelectorOnMainThread:@selector(_addProgressOutput:)
5300 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
5304 - (void) _setProgressTitle:(NSString *)title {
5305 [prompt_ setText:[title stringByAppendingString:@"..."]];
5308 - (void) _addProgressOutput:(NSString *)output {
5313 @interface Cydia : UIApplication <
5314 ConfirmationViewDelegate,
5315 ProgressViewDelegate,
5324 UIButtonBar *buttonbar_;
5326 ConfirmationView *confirm_;
5328 NSMutableArray *essential_;
5329 NSMutableArray *broken_;
5331 Database *database_;
5332 ProgressView *progress_;
5336 UIKeyboard *keyboard_;
5337 UIProgressHUD *hud_;
5339 InstallView *install_;
5340 ChangesView *changes_;
5341 ManageView *manage_;
5342 SearchView *search_;
5347 @implementation Cydia
5350 if ([broken_ count] != 0) {
5351 int count = [broken_ count];
5353 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
5354 initWithTitle:[NSString stringWithFormat:@"%d Half-Installed Package%@", count, (count == 1 ? @"" : @"s")]
5355 buttons:[NSArray arrayWithObjects:
5357 @"Ignore (Temporary)",
5359 defaultButtonIndex:0
5364 [sheet setBodyText:@"When the shell scripts associated with packages fail, they are left in a bad state known as either half-configured or half-installed. These errors don't go away and instead continue to cause issues. These scripts can be deleted and the packages forcibly removed."];
5365 [sheet popupAlertAnimated:YES];
5366 } else if (!Ignored_ && [essential_ count] != 0) {
5367 int count = [essential_ count];
5369 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
5370 initWithTitle:[NSString stringWithFormat:@"%d Essential Upgrade%@", count, (count == 1 ? @"" : @"s")]
5371 buttons:[NSArray arrayWithObjects:@"Upgrade Essential", @"Ignore (Temporary)", nil]
5372 defaultButtonIndex:0
5377 [sheet setBodyText:@"One or more essential packages are currently out of date. If these upgrades are not performed you are likely to encounter errors."];
5378 [sheet popupAlertAnimated:YES];
5382 - (void) _reloadData {
5383 /*UIProgressHUD *hud = [[UIProgressHUD alloc] initWithWindow:window_];
5384 [hud setText:@"Reloading Data"];
5385 [overlay_ addSubview:hud];
5388 [database_ reloadData];
5392 [essential_ removeAllObjects];
5393 [broken_ removeAllObjects];
5395 NSArray *packages = [database_ packages];
5396 for (int i(0), e([packages count]); i != e; ++i) {
5397 Package *package = [packages objectAtIndex:i];
5399 [broken_ addObject:package];
5400 if ([package upgradableAndEssential:NO]) {
5401 if ([package essential])
5402 [essential_ addObject:package];
5408 NSString *badge([[NSNumber numberWithInt:changes] stringValue]);
5409 [buttonbar_ setBadgeValue:badge forButton:3];
5410 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
5411 [buttonbar_ setBadgeAnimated:YES forButton:3];
5412 [self setApplicationBadge:badge];
5414 [buttonbar_ setBadgeValue:nil forButton:3];
5415 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
5416 [buttonbar_ setBadgeAnimated:NO forButton:3];
5417 [self removeApplicationBadge];
5422 if ([packages count] == 0);
5431 [hud removeFromSuperview];*/
5434 - (void) _saveConfig {
5436 _assert([Metadata_ writeToFile:@"/var/lib/cydia/metadata.plist" atomically:YES] == YES);
5441 - (void) updateData {
5444 /* XXX: this is just stupid */
5446 [install_ reloadData];
5448 [changes_ reloadData];
5450 [search_ reloadData];
5460 FILE *file = fopen("/etc/apt/sources.list.d/cydia.list", "w");
5461 _assert(file != NULL);
5463 NSArray *keys = [Sources_ allKeys];
5465 for (int i(0), e([keys count]); i != e; ++i) {
5466 NSString *key = [keys objectAtIndex:i];
5467 NSDictionary *source = [Sources_ objectForKey:key];
5469 fprintf(file, "%s %s %s\n",
5470 [[source objectForKey:@"Type"] UTF8String],
5471 [[source objectForKey:@"URI"] UTF8String],
5472 [[source objectForKey:@"Distribution"] UTF8String]
5481 detachNewThreadSelector:@selector(update_)
5484 title:@"Updating Sources..."
5488 - (void) reloadData {
5489 @synchronized (self) {
5490 if (confirm_ == nil)
5496 pkgProblemResolver *resolver = [database_ resolver];
5498 resolver->InstallProtect();
5499 if (!resolver->Resolve(true))
5504 [database_ prepare];
5506 if ([database_ cache]->BrokenCount() == 0)
5507 confirm_ = [[ConfirmationView alloc] initWithView:underlay_ database:database_ delegate:self];
5509 NSMutableArray *broken = [NSMutableArray arrayWithCapacity:16];
5510 NSArray *packages = [database_ packages];
5512 for (size_t i(0); i != [packages count]; ++i) {
5513 Package *package = [packages objectAtIndex:i];
5514 if ([package broken])
5515 [broken addObject:[package name]];
5518 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
5519 initWithTitle:[NSString stringWithFormat:@"%d Broken Packages", [database_ cache]->BrokenCount()]
5520 buttons:[NSArray arrayWithObjects:@"Okay", nil]
5521 defaultButtonIndex:0
5526 [sheet setBodyText:[NSString stringWithFormat:@"The following packages have unmet dependencies:\n\n%@", [broken componentsJoinedByString:@"\n"]]];
5527 [sheet popupAlertAnimated:YES];
5533 - (void) installPackage:(Package *)package {
5534 @synchronized (self) {
5541 - (void) removePackage:(Package *)package {
5542 @synchronized (self) {
5549 - (void) distUpgrade {
5550 @synchronized (self) {
5551 [database_ upgrade];
5557 @synchronized (self) {
5565 [overlay_ removeFromSuperview];
5569 detachNewThreadSelector:@selector(perform)
5576 - (void) bootstrap_ {
5578 [database_ upgrade];
5579 [database_ prepare];
5580 [database_ perform];
5583 - (void) bootstrap {
5585 detachNewThreadSelector:@selector(bootstrap_)
5588 title:@"Bootstrap Install..."
5592 - (void) progressViewIsComplete:(ProgressView *)progress {
5593 @synchronized (self) {
5596 if (confirm_ != nil) {
5597 [underlay_ addSubview:overlay_];
5598 [confirm_ removeFromSuperview];
5605 - (void) setPage:(RVPage *)page {
5606 [page resetViewAnimated:NO];
5607 [page setDelegate:self];
5608 [book_ setPage:page];
5611 - (RVPage *) _pageForURL:(NSURL *)url withClass:(Class)_class {
5612 BrowserView *browser = [[[_class alloc] initWithBook:book_ database:database_] autorelease];
5613 [browser loadURL:url];
5617 - (void) _setHomePage {
5618 [self setPage:[self _pageForURL:[NSURL URLWithString:@"http://cydia.saurik.com/"] withClass:[HomeView class]]];
5621 - (void) buttonBarItemTapped:(id)sender {
5622 unsigned tag = [sender tag];
5624 [book_ resetViewAnimated:YES];
5626 } else if (tag_ == 2 && tag != 2)
5627 [install_ resetView];
5630 case 1: [self _setHomePage]; break;
5632 case 2: [self setPage:install_]; break;
5633 case 3: [self setPage:changes_]; break;
5634 case 4: [self setPage:manage_]; break;
5635 case 5: [self setPage:search_]; break;
5637 default: _assert(false);
5643 - (void) fixSpringBoard {
5644 pid_t pid = ExecFork();
5648 if (pid_t child = fork()) {
5649 waitpid(child, NULL, 0);
5651 execlp("launchctl", "launchctl", "unload", SpringBoard_, NULL);
5652 perror("launchctl unload");
5656 execlp("launchctl", "launchctl", "load", SpringBoard_, NULL);
5657 perror("launchctl load");
5662 - (void) applicationWillSuspend {
5667 [self fixSpringBoard];
5671 [super applicationWillSuspend];
5674 - (void) askForSettings {
5675 UIAlertSheet *role = [[[UIAlertSheet alloc]
5676 initWithTitle:@"Who Are You?"
5677 buttons:[NSArray arrayWithObjects:
5678 @"User (Graphical Only)",
5679 @"Hacker (+ Command Line)",
5680 @"Developer (No Filters)",
5682 defaultButtonIndex:-1
5687 [role setBodyText:@"Not all of the packages available via Cydia are designed to be used by all users. Please categorize yourself so that Cydia can apply helpful filters.\n\nThis choice can be changed from \"Settings\" under the \"Manage\" tab."];
5688 [role popupAlertAnimated:YES];
5693 [self setStatusBarShowsProgress:NO];
5696 [hud_ removeFromSuperview];
5700 pid_t pid = ExecFork();
5702 execlp("launchctl", "launchctl", "stop", "com.apple.SpringBoard", NULL);
5703 perror("launchctl stop");
5710 [self askForSettings];
5714 overlay_ = [[UIView alloc] initWithFrame:[underlay_ bounds]];
5716 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
5717 book_ = [[CYBook alloc] initWithFrame:CGRectMake(
5718 0, 0, screenrect.size.width, screenrect.size.height - 48
5719 ) database:database_];
5721 [book_ setDelegate:self];
5723 [overlay_ addSubview:book_];
5725 NSArray *buttonitems = [NSArray arrayWithObjects:
5726 [NSDictionary dictionaryWithObjectsAndKeys:
5727 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5728 @"home-up.png", kUIButtonBarButtonInfo,
5729 @"home-dn.png", kUIButtonBarButtonSelectedInfo,
5730 [NSNumber numberWithInt:1], kUIButtonBarButtonTag,
5731 self, kUIButtonBarButtonTarget,
5732 @"Home", kUIButtonBarButtonTitle,
5733 @"0", kUIButtonBarButtonType,
5736 [NSDictionary dictionaryWithObjectsAndKeys:
5737 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5738 @"install-up.png", kUIButtonBarButtonInfo,
5739 @"install-dn.png", kUIButtonBarButtonSelectedInfo,
5740 [NSNumber numberWithInt:2], kUIButtonBarButtonTag,
5741 self, kUIButtonBarButtonTarget,
5742 @"Sections", kUIButtonBarButtonTitle,
5743 @"0", kUIButtonBarButtonType,
5746 [NSDictionary dictionaryWithObjectsAndKeys:
5747 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5748 @"changes-up.png", kUIButtonBarButtonInfo,
5749 @"changes-dn.png", kUIButtonBarButtonSelectedInfo,
5750 [NSNumber numberWithInt:3], kUIButtonBarButtonTag,
5751 self, kUIButtonBarButtonTarget,
5752 @"Changes", kUIButtonBarButtonTitle,
5753 @"0", kUIButtonBarButtonType,
5756 [NSDictionary dictionaryWithObjectsAndKeys:
5757 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5758 @"manage-up.png", kUIButtonBarButtonInfo,
5759 @"manage-dn.png", kUIButtonBarButtonSelectedInfo,
5760 [NSNumber numberWithInt:4], kUIButtonBarButtonTag,
5761 self, kUIButtonBarButtonTarget,
5762 @"Manage", kUIButtonBarButtonTitle,
5763 @"0", kUIButtonBarButtonType,
5766 [NSDictionary dictionaryWithObjectsAndKeys:
5767 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5768 @"search-up.png", kUIButtonBarButtonInfo,
5769 @"search-dn.png", kUIButtonBarButtonSelectedInfo,
5770 [NSNumber numberWithInt:5], kUIButtonBarButtonTag,
5771 self, kUIButtonBarButtonTarget,
5772 @"Search", kUIButtonBarButtonTitle,
5773 @"0", kUIButtonBarButtonType,
5777 buttonbar_ = [[UIButtonBar alloc]
5779 withFrame:CGRectMake(
5780 0, screenrect.size.height - ButtonBarHeight_,
5781 screenrect.size.width, ButtonBarHeight_
5783 withItemList:buttonitems
5786 [buttonbar_ setDelegate:self];
5787 [buttonbar_ setBarStyle:1];
5788 [buttonbar_ setButtonBarTrackingMode:2];
5790 int buttons[5] = {1, 2, 3, 4, 5};
5791 [buttonbar_ registerButtonGroup:0 withButtons:buttons withCount:5];
5792 [buttonbar_ showButtonGroup:0 withDuration:0];
5794 for (int i = 0; i != 5; ++i)
5795 [[buttonbar_ viewWithTag:(i + 1)] setFrame:CGRectMake(
5796 i * 64 + 2, 1, 60, ButtonBarHeight_
5799 [buttonbar_ showSelectionForButton:1];
5800 [overlay_ addSubview:buttonbar_];
5802 [UIKeyboard initImplementationNow];
5803 CGSize keysize = [UIKeyboard defaultSize];
5804 CGRect keyrect = {{0, [overlay_ bounds].size.height}, keysize};
5805 keyboard_ = [[UIKeyboard alloc] initWithFrame:keyrect];
5806 [[UIKeyboardImpl sharedInstance] setSoundsEnabled:(Sounds_Keyboard_ ? YES : NO)];
5807 [overlay_ addSubview:keyboard_];
5809 install_ = [[InstallView alloc] initWithBook:book_ database:database_];
5810 changes_ = [[ChangesView alloc] initWithBook:book_ database:database_];
5811 search_ = [[SearchView alloc] initWithBook:book_ database:database_];
5813 manage_ = (ManageView *) [[self
5814 _pageForURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"manage" ofType:@"html"]]
5815 withClass:[ManageView class]
5819 [underlay_ addSubview:overlay_];
5826 [self _setHomePage];
5829 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
5830 NSString *context = [sheet context];
5831 if ([context isEqualToString:@"fixhalf"])
5834 @synchronized (self) {
5835 for (int i = 0, e = [broken_ count]; i != e; ++i) {
5836 Package *broken = [broken_ objectAtIndex:i];
5839 NSString *id = [broken id];
5840 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.prerm", id] UTF8String]);
5841 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.postrm", id] UTF8String]);
5842 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.preinst", id] UTF8String]);
5843 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.postinst", id] UTF8String]);
5852 [broken_ removeAllObjects];
5859 else if ([context isEqualToString:@"role"]) {
5861 case 1: Role_ = @"User"; break;
5862 case 2: Role_ = @"Hacker"; break;
5863 case 3: Role_ = @"Developer"; break;
5870 bool reset = Settings_ != nil;
5872 Settings_ = [NSMutableDictionary dictionaryWithObjectsAndKeys:
5876 [Metadata_ setObject:Settings_ forKey:@"Settings"];
5884 } else if ([context isEqualToString:@"upgrade"])
5887 @synchronized (self) {
5888 for (int i = 0, e = [essential_ count]; i != e; ++i) {
5889 Package *essential = [essential_ objectAtIndex:i];
5890 [essential install];
5909 - (void) reorganize {
5910 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5911 system("/usr/libexec/cydia/free.sh");
5912 [self performSelectorOnMainThread:@selector(finish) withObject:nil waitUntilDone:NO];
5916 - (void) applicationSuspend:(__GSEvent *)event {
5917 if (hud_ == nil && ![progress_ isRunning])
5918 [super applicationSuspend:event];
5921 - (void) _animateSuspension:(BOOL)arg0 duration:(double)arg1 startTime:(double)arg2 scale:(float)arg3 {
5923 [super _animateSuspension:arg0 duration:arg1 startTime:arg2 scale:arg3];
5926 - (void) _setSuspended:(BOOL)value {
5928 [super _setSuspended:value];
5931 - (UIProgressHUD *) addProgressHUD {
5932 UIProgressHUD *hud = [[UIProgressHUD alloc] initWithWindow:window_];
5934 [underlay_ addSubview:hud];
5938 - (void) applicationDidFinishLaunching:(id)unused {
5939 Font12_ = [[UIFont systemFontOfSize:12] retain];
5940 Font12Bold_ = [[UIFont boldSystemFontOfSize:12] retain];
5941 Font14_ = [[UIFont systemFontOfSize:14] retain];
5942 Font18Bold_ = [[UIFont boldSystemFontOfSize:18] retain];
5943 Font22Bold_ = [[UIFont boldSystemFontOfSize:22] retain];
5945 _assert(pkgInitConfig(*_config));
5946 _assert(pkgInitSystem(*_config, _system));
5951 essential_ = [[NSMutableArray alloc] initWithCapacity:4];
5952 broken_ = [[NSMutableArray alloc] initWithCapacity:4];
5954 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
5955 window_ = [[UIWindow alloc] initWithContentRect:screenrect];
5957 [window_ orderFront:self];
5958 [window_ makeKey:self];
5959 [window_ _setHidden:NO];
5961 database_ = [[Database alloc] init];
5962 progress_ = [[ProgressView alloc] initWithFrame:[window_ bounds] database:database_ delegate:self];
5963 [database_ setDelegate:progress_];
5964 [window_ setContentView:progress_];
5966 underlay_ = [[UIView alloc] initWithFrame:[progress_ bounds]];
5967 [progress_ setContentView:underlay_];
5969 [progress_ resetView];
5972 readlink("/Applications", NULL, 0) == -1 && errno == EINVAL ||
5973 readlink("/Library/Ringtones", NULL, 0) == -1 && errno == EINVAL ||
5974 readlink("/Library/Wallpaper", NULL, 0) == -1 && errno == EINVAL ||
5975 readlink("/usr/include", NULL, 0) == -1 && errno == EINVAL ||
5976 readlink("/usr/libexec", NULL, 0) == -1 && errno == EINVAL ||
5977 readlink("/usr/share", NULL, 0) == -1 && errno == EINVAL
5979 [self setIdleTimerDisabled:YES];
5981 hud_ = [self addProgressHUD];
5982 [hud_ setText:@"Reorganizing\n\nWill Automatically\nRestart When Done"];
5984 [self setStatusBarShowsProgress:YES];
5987 detachNewThreadSelector:@selector(reorganize)
5995 - (void) showKeyboard:(BOOL)show {
5996 CGSize keysize = [UIKeyboard defaultSize];
5997 CGRect keydown = {{0, [overlay_ bounds].size.height}, keysize};
5998 CGRect keyup = keydown;
5999 keyup.origin.y -= keysize.height;
6001 UIFrameAnimation *animation = [[[UIFrameAnimation alloc] initWithTarget:keyboard_] autorelease];
6002 [animation setSignificantRectFields:2];
6005 [animation setStartFrame:keydown];
6006 [animation setEndFrame:keyup];
6007 [keyboard_ activate];
6009 [animation setStartFrame:keyup];
6010 [animation setEndFrame:keydown];
6011 [keyboard_ deactivate];
6014 [[UIAnimator sharedAnimator]
6015 addAnimations:[NSArray arrayWithObjects:animation, nil]
6016 withDuration:KeyboardTime_
6021 - (void) slideUp:(UIAlertSheet *)alert {
6023 [alert presentSheetFromButtonBar:buttonbar_];
6025 [alert presentSheetInView:overlay_];
6030 void AddPreferences(NSString *plist) {
6031 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
6033 NSMutableDictionary *settings = [[[NSMutableDictionary alloc] initWithContentsOfFile:plist] autorelease];
6034 _assert(settings != NULL);
6035 NSMutableArray *items = [settings objectForKey:@"items"];
6039 for (size_t i(0); i != [items count]; ++i) {
6040 NSMutableDictionary *item([items objectAtIndex:i]);
6041 NSString *label = [item objectForKey:@"label"];
6042 if (label != nil && [label isEqualToString:@"Cydia"]) {
6049 for (size_t i(0); i != [items count]; ++i) {
6050 NSDictionary *item([items objectAtIndex:i]);
6051 NSString *label = [item objectForKey:@"label"];
6052 if (label != nil && [label isEqualToString:@"General"]) {
6053 [items insertObject:[NSDictionary dictionaryWithObjectsAndKeys:
6054 @"CydiaSettings", @"bundle",
6055 @"PSLinkCell", @"cell",
6056 [NSNumber numberWithBool:YES], @"hasIcon",
6057 [NSNumber numberWithBool:YES], @"isController",
6059 nil] atIndex:(i + 1)];
6065 _assert([settings writeToFile:plist atomically:YES] == YES);
6072 id Alloc_(id self, SEL selector) {
6073 id object = alloc_(self, selector);
6074 fprintf(stderr, "[%s]A-%p\n", self->isa->name, object);
6079 id Dealloc_(id self, SEL selector) {
6080 id object = dealloc_(self, selector);
6081 fprintf(stderr, "[%s]D-%p\n", self->isa->name, object);
6085 int main(int argc, char *argv[]) {
6086 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
6088 bootstrap_ = argc > 1 && strcmp(argv[1], "--bootstrap") == 0;
6090 Home_ = NSHomeDirectory();
6093 NSString *plist = [Home_ stringByAppendingString:@"/Library/Preferences/com.apple.preferences.sounds.plist"];
6094 if (NSDictionary *sounds = [NSDictionary dictionaryWithContentsOfFile:plist])
6095 if (NSNumber *keyboard = [sounds objectForKey:@"keyboard"])
6096 Sounds_Keyboard_ = [keyboard boolValue];
6102 if (unlink("/var/cache/apt/pkgcache.bin") == -1)
6103 _assert(errno == ENOENT);
6104 if (unlink("/var/cache/apt/srcpkgcache.bin") == -1)
6105 _assert(errno == ENOENT);
6107 /*Method alloc = class_getClassMethod([NSObject class], @selector(alloc));
6108 alloc_ = alloc->method_imp;
6109 alloc->method_imp = (IMP) &Alloc_;*/
6111 /*Method dealloc = class_getClassMethod([NSObject class], @selector(dealloc));
6112 dealloc_ = dealloc->method_imp;
6113 dealloc->method_imp = (IMP) &Dealloc_;*/
6115 if (NSDictionary *sysver = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]) {
6116 if (NSString *prover = [sysver valueForKey:@"ProductVersion"]) {
6117 Firmware_ = strdup([prover UTF8String]);
6118 NSArray *versions = [prover componentsSeparatedByString:@"."];
6119 int count = [versions count];
6120 Major_ = count > 0 ? [[versions objectAtIndex:0] intValue] : 0;
6121 Minor_ = count > 1 ? [[versions objectAtIndex:1] intValue] : 0;
6122 BugFix_ = count > 2 ? [[versions objectAtIndex:2] intValue] : 0;
6127 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
6128 char *machine = new char[size];
6129 sysctlbyname("hw.machine", machine, &size, NULL, 0);
6132 if (CFMutableDictionaryRef dict = IOServiceMatching("IOPlatformExpertDevice"))
6133 if (io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, dict)) {
6134 if (CFTypeRef serial = IORegistryEntryCreateCFProperty(service, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0)) {
6135 SerialNumber_ = strdup(CFStringGetCStringPtr((CFStringRef) serial, CFStringGetSystemEncoding()));
6139 IOObjectRelease(service);
6142 /*AddPreferences(@"/Applications/Preferences.app/Settings-iPhone.plist");
6143 AddPreferences(@"/Applications/Preferences.app/Settings-iPod.plist");*/
6145 if ((Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"]) == NULL)
6146 Metadata_ = [[NSMutableDictionary alloc] initWithCapacity:2];
6148 Settings_ = [Metadata_ objectForKey:@"Settings"];
6150 Packages_ = [Metadata_ objectForKey:@"Packages"];
6151 Sections_ = [Metadata_ objectForKey:@"Sections"];
6152 Sources_ = [Metadata_ objectForKey:@"Sources"];
6155 if (Settings_ != nil)
6156 Role_ = [Settings_ objectForKey:@"Role"];
6158 if (Packages_ == nil) {
6159 Packages_ = [[[NSMutableDictionary alloc] initWithCapacity:128] autorelease];
6160 [Metadata_ setObject:Packages_ forKey:@"Packages"];
6163 if (Sections_ == nil) {
6164 Sections_ = [[[NSMutableDictionary alloc] initWithCapacity:32] autorelease];
6165 [Metadata_ setObject:Sections_ forKey:@"Sections"];
6168 if (Sources_ == nil) {
6169 Sources_ = [[[NSMutableDictionary alloc] initWithCapacity:0] autorelease];
6170 [Metadata_ setObject:Sources_ forKey:@"Sources"];
6173 if (access("/Library/MobileSubstrate/MobileSubstrate.dylib", F_OK) == 0)
6174 dlopen("/Library/MobileSubstrate/MobileSubstrate.dylib", RTLD_LAZY | RTLD_GLOBAL);
6176 if (access("/User", F_OK) != 0)
6177 system("/usr/libexec/cydia/firmware.sh");
6179 Locale_ = CFLocaleCopyCurrent();
6180 space_ = CGColorSpaceCreateDeviceRGB();
6182 Blue_.Set(space_, 0.2, 0.2, 1.0, 1.0);
6183 Blueish_.Set(space_, 0x19/255.f, 0x32/255.f, 0x50/255.f, 1.0);
6184 Black_.Set(space_, 0.0, 0.0, 0.0, 1.0);
6185 Clear_.Set(space_, 0.0, 0.0, 0.0, 0.0);
6186 Red_.Set(space_, 1.0, 0.0, 0.0, 1.0);
6187 White_.Set(space_, 1.0, 1.0, 1.0, 1.0);
6188 Gray_.Set(space_, 0.4, 0.4, 0.4, 1.0);
6190 Finishes_ = [NSArray arrayWithObjects:@"return", @"reopen", @"restart", @"reload", @"reboot", nil];
6192 SectionMap_ = [[[NSDictionary alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Sections" ofType:@"plist"]] autorelease];
6194 int value = UIApplicationMain(argc, argv, [Cydia class]);
6196 CGColorSpaceRelease(space_);