1 /* Cydia - iPhone UIKit Front-End for Debian APT
2 * Copyright (C) 2008 Jay Freeman (saurik)
6 * Redistribution and use in source and binary
7 * forms, with or without modification, are permitted
8 * provided that the following conditions are met:
10 * 1. Redistributions of source code must retain the
11 * above copyright notice, this list of conditions
12 * and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the
14 * above copyright notice, this list of conditions
15 * and the following disclaimer in the documentation
16 * and/or other materials provided with the
18 * 3. The name of the author may not be used to endorse
19 * or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS''
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
24 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
33 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
35 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 /* #include Directives {{{ */
39 #include <objc/objc.h>
40 #include <objc/runtime.h>
42 #include <CoreGraphics/CoreGraphics.h>
43 #include <GraphicsServices/GraphicsServices.h>
44 #include <Foundation/Foundation.h>
46 #include <WebCore/DOMHTML.h>
47 #import <QuartzCore/CALayer.h>
49 #import <UIKit/UIActionSheet.h>
50 #import <UIKit/UIAnimator.h>
51 #import <UIKit/UIApplication.h>
52 #import <UIKit/UIColor.h>
53 #import <UIKit/UIFieldEditor.h>
54 #import <UIKit/UIFrameAnimation.h>
55 #import <UIKit/UIHardware.h>
56 #import <UIKit/UIImage.h>
57 #import <UIKit/UIImageAndTextTableCell.h>
58 #import <UIKit/UIImageView.h>
59 #import <UIKit/UIKeyboard.h>
60 #import <UIKit/UIKeyboardImpl.h>
61 #import <UIKit/UINavigationBar.h>
62 #import <UIKit/UINavigationItem.h>
63 #import <UIKit/UIPreferencesTable.h>
64 #import <UIKit/UIPreferencesTableCell.h>
65 #import <UIKit/UIProgressBar.h>
66 #import <UIKit/UIProgressHUD.h>
67 #import <UIKit/UIProgressIndicator.h>
68 #import <UIKit/UIPushButton.h>
69 #import <UIKit/UISearchField.h>
70 #import <UIKit/UISimpleTableCell.h>
71 #import <UIKit/_UISwitchSlider.h>
72 #import <UIKit/UITableCell.h>
73 #import <UIKit/UITableColumn.h>
74 #import <UIKit/UITextField.h>
75 #import <UIKit/UITextInputTraits.h>
76 #import <UIKit/UITextLabel.h>
77 #import <UIKit/UITextView.h>
78 #import <UIKit/UIToolbar.h>
79 #import <UIKit/UITransitionView.h>
80 #import <UIKit/UIWebDocumentView.h>
81 #import <UIKit/UIWebView.h>
82 #import <UIKit/UIWindow.h>
84 #import <UIKit/UIView-Geometry.h>
85 #import <UIKit/UIView-Gestures.h>
86 #import <UIKit/UIView-Hierarchy.h>
87 #import <UIKit/UIView-Rendering.h>
89 #import <UIKit/UIWebDocumentView-Forms.h>
91 #import <UIKit/NSString-UIStringDrawing.h>
94 #import <UIKit/UIActionSheet-Private.h>
95 #import <UIKit/UIControl-UIControlPrivate.h>
96 #import <UIKit/UIImage-UIImageDeprecated.h>
97 #import <UIKit/UIImage-UIImagePrivate.h>
98 #import <UIKit/UINavigationBar-Static.h>
99 #import <UIKit/UIProgressHUD-Deprecated.h>
100 #import <UIKit/UIToolbar-UIButtonBarPrivate.h>
101 #import <UIKit/UIView-Deprecated.h>
102 #import <UIKit/UIWindow-Static.h>
105 #import <UIKit/NSString-UIStringDrawingDeprecated.h>
107 #include <WebKit/WebFrame.h>
108 #include <WebKit/WebView.h>
113 #include <ext/stdio_filebuf.h>
115 #include <apt-pkg/acquire.h>
116 #include <apt-pkg/acquire-item.h>
117 #include <apt-pkg/algorithms.h>
118 #include <apt-pkg/cachefile.h>
119 #include <apt-pkg/clean.h>
120 #include <apt-pkg/configuration.h>
121 #include <apt-pkg/debmetaindex.h>
122 #include <apt-pkg/error.h>
123 #include <apt-pkg/init.h>
124 #include <apt-pkg/mmap.h>
125 #include <apt-pkg/pkgrecords.h>
126 #include <apt-pkg/sha1.h>
127 #include <apt-pkg/sourcelist.h>
128 #include <apt-pkg/sptr.h>
130 #include <sys/sysctl.h>
135 #include <mach-o/nlist.h>
145 #define UIWebView UIWebDocumentView
147 #import "BrowserView.h"
148 #import "ResetView.h"
149 #import "UICaboodle.h"
152 @interface WebView (Cydia)
153 - (void) _setLayoutInterval:(float)interval;
156 /* iPhoneOS 2.0 Compatibility {{{ */
158 @interface UICGColor : NSObject {
161 - (id) initWithCGColor:(CGColorRef)color;
167 + (id)systemFontOfSize:(float)fp8;
168 + (id)boldSystemFontOfSize:(float)fp8;
169 - (UIFont *) fontWithSize:(CGFloat)size;
172 @interface NSObject (iPhoneOS)
173 - (CGColorRef) cgColor;
174 - (CGColorRef) CGColor;
178 @implementation NSObject (iPhoneOS)
180 - (CGColorRef) cgColor {
181 return [self CGColor];
184 - (CGColorRef) CGColor {
185 return (CGColorRef) self;
189 [[[[objc_getClass("UICGColor") alloc] initWithCGColor:[self CGColor]] autorelease] set];
194 @interface UITextView (iPhoneOS)
195 - (void) setTextSize:(float)size;
198 @implementation UITextView (iPhoneOS)
200 - (void) setTextSize:(float)size {
201 [self setFont:[[self font] fontWithSize:size]];
208 @interface UIApplication (IdleTimer)
209 - (void) setIdleTimerDisabled:(char)arg0;
212 extern "C" int UIApplicationMain(int argc, char *argv[], NSString *principalClassName, NSString *delegateClassName);
214 extern NSString *kUIButtonBarButtonAction;
215 extern NSString *kUIButtonBarButtonInfo;
216 extern NSString *kUIButtonBarButtonInfoOffset;
217 extern NSString *kUIButtonBarButtonSelectedInfo;
218 extern NSString *kUIButtonBarButtonStyle;
219 extern NSString *kUIButtonBarButtonTag;
220 extern NSString *kUIButtonBarButtonTarget;
221 extern NSString *kUIButtonBarButtonTitle;
222 extern NSString *kUIButtonBarButtonTitleVerticalHeight;
223 extern NSString *kUIButtonBarButtonTitleWidth;
224 extern NSString *kUIButtonBarButtonType;
227 kUIProgressIndicatorStyleLargeWhite = 0,
228 kUIProgressIndicatorStyleMediumWhite = 1,
229 kUIProgressIndicatorStyleSmallWhite = 3,
230 kUIProgressIndicatorStyleSmallBlack = 4
231 } UIProgressIndicatorStyle;
234 kUIControlEventMouseDown = 1 << 0,
235 kUIControlEventMouseMovedInside = 1 << 2, // mouse moved inside control target
236 kUIControlEventMouseMovedOutside = 1 << 3, // mouse moved outside control target
237 kUIControlEventMouseUpInside = 1 << 6, // mouse up inside control target
238 kUIControlEventMouseUpOutside = 1 << 7, // mouse up outside control target
239 kUIControlAllEvents = (kUIControlEventMouseDown | kUIControlEventMouseMovedInside | kUIControlEventMouseMovedOutside | kUIControlEventMouseUpInside | kUIControlEventMouseUpOutside)
240 } UIControlEventMasks;
242 @interface NSString (UIKit)
243 - (NSString *) stringByAddingPercentEscapes;
244 - (NSString *) stringByReplacingCharacter:(unsigned short)arg0 withCharacter:(unsigned short)arg1;
247 @interface NSString (Cydia)
248 + (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length;
249 - (NSComparisonResult) compareByPath:(NSString *)other;
252 @implementation NSString (Cydia)
254 + (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length {
255 char data[length + 1];
256 memcpy(data, bytes, length);
258 return [NSString stringWithUTF8String:data];
261 - (NSComparisonResult) compareByPath:(NSString *)other {
262 NSString *prefix = [self commonPrefixWithString:other options:0];
263 size_t length = [prefix length];
265 NSRange lrange = NSMakeRange(length, [self length] - length);
266 NSRange rrange = NSMakeRange(length, [other length] - length);
268 lrange = [self rangeOfString:@"/" options:0 range:lrange];
269 rrange = [other rangeOfString:@"/" options:0 range:rrange];
271 NSComparisonResult value;
273 if (lrange.location == NSNotFound && rrange.location == NSNotFound)
274 value = NSOrderedSame;
275 else if (lrange.location == NSNotFound)
276 value = NSOrderedAscending;
277 else if (rrange.location == NSNotFound)
278 value = NSOrderedDescending;
280 value = NSOrderedSame;
282 NSString *lpath = lrange.location == NSNotFound ? [self substringFromIndex:length] :
283 [self substringWithRange:NSMakeRange(length, lrange.location - length)];
284 NSString *rpath = rrange.location == NSNotFound ? [other substringFromIndex:length] :
285 [other substringWithRange:NSMakeRange(length, rrange.location - length)];
287 NSComparisonResult result = [lpath compare:rpath];
288 return result == NSOrderedSame ? value : result;
293 /* Perl-Compatible RegEx {{{ */
303 Pcre(const char *regex) :
308 code_ = pcre_compile(regex, 0, &error, &offset, NULL);
311 fprintf(stderr, "%d:%s\n", offset, error);
315 pcre_fullinfo(code_, study_, PCRE_INFO_CAPTURECOUNT, &capture_);
316 matches_ = new int[(capture_ + 1) * 3];
324 NSString *operator [](size_t match) {
325 return [NSString stringWithUTF8Bytes:(data_ + matches_[match * 2]) length:(matches_[match * 2 + 1] - matches_[match * 2])];
328 bool operator ()(NSString *data) {
329 // XXX: length is for characters, not for bytes
330 return operator ()([data UTF8String], [data length]);
333 bool operator ()(const char *data, size_t size) {
335 return pcre_exec(code_, study_, data, size, 0, 0, matches_, (capture_ + 1) * 3) >= 0;
339 /* Mime Addresses {{{ */
340 @interface Address : NSObject {
346 - (NSString *) address;
348 + (Address *) addressWithString:(NSString *)string;
349 - (Address *) initWithString:(NSString *)string;
352 @implementation Address
361 - (NSString *) name {
365 - (NSString *) address {
369 + (Address *) addressWithString:(NSString *)string {
370 return [[[Address alloc] initWithString:string] autorelease];
373 + (NSArray *) _attributeKeys {
374 return [NSArray arrayWithObjects:@"address", @"name", nil];
377 - (NSArray *) attributeKeys {
378 return [[self class] _attributeKeys];
381 + (BOOL) isKeyExcludedFromWebScript:(const char *)name {
382 return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name];
385 - (Address *) initWithString:(NSString *)string {
386 if ((self = [super init]) != nil) {
387 const char *data = [string UTF8String];
388 size_t size = [string length];
390 static Pcre address_r("^\"?(.*)\"? <([^>]*)>$");
392 if (address_r(data, size)) {
393 name_ = [address_r[1] retain];
394 address_ = [address_r[2] retain];
396 name_ = [[NSString alloc]
399 encoding:kCFStringEncodingUTF8
409 /* CoreGraphics Primitives {{{ */
420 CGColor(CGColorSpaceRef space, float red, float green, float blue, float alpha) :
423 Set(space, red, green, blue, alpha);
428 CGColorRelease(color_);
435 void Set(CGColorSpaceRef space, float red, float green, float blue, float alpha) {
437 float color[] = {red, green, blue, alpha};
438 color_ = CGColorCreate(space, color);
441 operator CGColorRef() {
457 extern "C" void UISetColor(CGColorRef color);
459 /* Random Global Variables {{{ */
460 static const int PulseInterval_ = 50000;
461 static const int ButtonBarHeight_ = 48;
462 static const float KeyboardTime_ = 0.3f;
463 static const char * const SpringBoard_ = "/System/Library/LaunchDaemons/com.apple.SpringBoard.plist";
465 static CGColor Blue_;
466 static CGColor Blueish_;
467 static CGColor Black_;
468 static CGColor Clear_;
470 static CGColor White_;
471 static CGColor Gray_;
473 static NSString *App_;
474 static NSString *Home_;
475 static BOOL Sounds_Keyboard_;
477 static BOOL Advanced_;
479 static BOOL Ignored_;
481 static UIFont *Font12_;
482 static UIFont *Font12Bold_;
483 static UIFont *Font14_;
484 static UIFont *Font18Bold_;
485 static UIFont *Font22Bold_;
487 const char *Firmware_ = NULL;
488 const char *Machine_ = NULL;
489 const char *SerialNumber_ = NULL;
496 CGColorSpaceRef space_;
498 #define FW_LEAST(major, minor, bugfix) \
499 (major < Major_ || major == Major_ && \
500 (minor < Minor_ || minor == Minor_ && \
506 static NSDictionary *SectionMap_;
507 static NSMutableDictionary *Metadata_;
508 static _transient NSMutableDictionary *Settings_;
509 static _transient NSString *Role_;
510 static _transient NSMutableDictionary *Packages_;
511 static _transient NSMutableDictionary *Sections_;
512 static _transient NSMutableDictionary *Sources_;
513 static bool Changed_;
516 NSString *GetLastUpdate() {
517 NSDate *update = [Metadata_ objectForKey:@"LastUpdate"];
520 return @"Never or Unknown";
522 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, Locale_, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
523 CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) update);
525 CFRelease(formatter);
527 return [(NSString *) formatted autorelease];
530 /* Display Helpers {{{ */
531 inline float Interpolate(float begin, float end, float fraction) {
532 return (end - begin) * fraction + begin;
535 NSString *SizeString(double size) {
537 while (size > 1024) {
542 static const char *powers_[] = {"B", "kB", "MB", "GB"};
544 return [NSString stringWithFormat:@"%.1f%s", size, powers_[power]];
547 NSString *StripVersion(NSString *version) {
548 NSRange colon = [version rangeOfString:@":"];
549 if (colon.location != NSNotFound)
550 version = [version substringFromIndex:(colon.location + 1)];
554 static const float TextViewOffset_ = 22;
556 UITextView *GetTextView(NSString *value, float left, bool html) {
557 UITextView *text([[[UITextView alloc] initWithFrame:CGRectMake(left, 3, 310 - left, 1000)] autorelease]);
558 [text setEditable:NO];
559 [text setTextSize:16];
561 [text setHTML:value];
563 [text setText:value];
564 [text setEnabled:NO];
566 [text setBackgroundColor:[UIColor colorWithCGColor:Clear_]];
568 CGRect frame = [text frame];
569 [text setFrame:frame];
570 CGRect rect = [text visibleTextRect];
571 frame.size.height = rect.size.height;
572 [text setFrame:frame];
577 NSString *Simplify(NSString *title) {
578 const char *data = [title UTF8String];
579 size_t size = [title length];
581 static Pcre square_r("^\\[(.*)\\]$");
582 if (square_r(data, size))
583 return Simplify(square_r[1]);
585 static Pcre paren_r("^\\((.*)\\)$");
586 if (paren_r(data, size))
587 return Simplify(paren_r[1]);
589 static Pcre title_r("^(.*?) \\(.*\\)$");
590 if (title_r(data, size))
591 return Simplify(title_r[1]);
597 bool isSectionVisible(NSString *section) {
598 NSDictionary *metadata = [Sections_ objectForKey:section];
599 NSNumber *hidden = metadata == nil ? nil : [metadata objectForKey:@"Hidden"];
600 return hidden == nil || ![hidden boolValue];
603 /* Delegate Prototypes {{{ */
607 @interface NSObject (ProgressDelegate)
610 @implementation NSObject(ProgressDelegate)
612 - (void) _setProgressError:(NSArray *)args {
613 [self performSelector:@selector(setProgressError:forPackage:)
614 withObject:[args objectAtIndex:0]
615 withObject:([args count] == 1 ? nil : [args objectAtIndex:1])
621 @protocol ProgressDelegate
622 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id;
623 - (void) setProgressTitle:(NSString *)title;
624 - (void) setProgressPercent:(float)percent;
625 - (void) addProgressOutput:(NSString *)output;
628 @protocol ConfigurationDelegate
629 - (void) repairWithSelector:(SEL)selector;
630 - (void) setConfigurationData:(NSString *)data;
633 @protocol CydiaDelegate
634 - (void) installPackage:(Package *)package;
635 - (void) removePackage:(Package *)package;
636 - (void) slideUp:(UIActionSheet *)alert;
637 - (void) distUpgrade;
640 - (void) askForSettings;
641 - (UIProgressHUD *) addProgressHUD;
645 /* Status Delegation {{{ */
647 public pkgAcquireStatus
650 _transient NSObject<ProgressDelegate> *delegate_;
658 void setDelegate(id delegate) {
659 delegate_ = delegate;
662 virtual bool MediaChange(std::string media, std::string drive) {
666 virtual void IMSHit(pkgAcquire::ItemDesc &item) {
669 virtual void Fetch(pkgAcquire::ItemDesc &item) {
670 [delegate_ setProgressTitle:[NSString stringWithUTF8String:("Downloading " + item.ShortDesc).c_str()]];
673 virtual void Done(pkgAcquire::ItemDesc &item) {
676 virtual void Fail(pkgAcquire::ItemDesc &item) {
678 item.Owner->Status == pkgAcquire::Item::StatIdle ||
679 item.Owner->Status == pkgAcquire::Item::StatDone
683 [delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
684 withObject:[NSArray arrayWithObjects:[NSString stringWithUTF8String:item.Owner->ErrorText.c_str()], nil]
689 virtual bool Pulse(pkgAcquire *Owner) {
690 bool value = pkgAcquireStatus::Pulse(Owner);
693 double(CurrentBytes + CurrentItems) /
694 double(TotalBytes + TotalItems)
697 [delegate_ setProgressPercent:percent];
701 virtual void Start() {
704 virtual void Stop() {
708 /* Progress Delegation {{{ */
713 _transient id<ProgressDelegate> delegate_;
716 virtual void Update() {
717 [delegate_ setProgressTitle:[NSString stringWithUTF8String:Op.c_str()]];
718 [delegate_ setProgressPercent:(Percent / 100)];
727 void setDelegate(id delegate) {
728 delegate_ = delegate;
731 virtual void Done() {
732 [delegate_ setProgressPercent:1];
737 /* Database Interface {{{ */
738 @interface Database : NSObject {
740 pkgDepCache::Policy *policy_;
741 pkgRecords *records_;
742 pkgProblemResolver *resolver_;
743 pkgAcquire *fetcher_;
745 SPtr<pkgPackageManager> manager_;
746 pkgSourceList *list_;
748 NSMutableDictionary *sources_;
749 NSMutableArray *packages_;
751 _transient NSObject<ConfigurationDelegate, ProgressDelegate> *delegate_;
760 - (void) _readCydia:(NSNumber *)fd;
761 - (void) _readStatus:(NSNumber *)fd;
762 - (void) _readOutput:(NSNumber *)fd;
766 - (Package *) packageWithName:(NSString *)name;
769 - (pkgCacheFile &) cache;
770 - (pkgDepCache::Policy *) policy;
771 - (pkgRecords *) records;
772 - (pkgProblemResolver *) resolver;
773 - (pkgAcquire &) fetcher;
774 - (NSArray *) packages;
775 - (NSArray *) sources;
784 - (void) updateWithStatus:(Status &)status;
786 - (void) setDelegate:(id)delegate;
787 - (Source *) getSource:(const pkgCache::PkgFileIterator &)file;
791 /* Source Class {{{ */
792 @interface Source : NSObject {
793 NSString *description_;
798 NSString *distribution_;
802 NSString *defaultIcon_;
804 NSDictionary *record_;
808 - (Source *) initWithMetaIndex:(metaIndex *)index;
810 - (NSComparisonResult) compareByNameAndType:(Source *)source;
812 - (NSDictionary *) record;
816 - (NSString *) distribution;
822 - (NSString *) description;
823 - (NSString *) label;
824 - (NSString *) origin;
825 - (NSString *) version;
827 - (NSString *) defaultIcon;
831 @implementation Source
835 [distribution_ release];
838 if (description_ != nil)
839 [description_ release];
846 if (defaultIcon_ != nil)
847 [defaultIcon_ release];
854 + (NSArray *) _attributeKeys {
855 return [NSArray arrayWithObjects:@"description", @"distribution", @"host", @"key", @"label", @"name", @"origin", @"trusted", @"type", @"uri", @"version", nil];
858 - (NSArray *) attributeKeys {
859 return [[self class] _attributeKeys];
862 + (BOOL) isKeyExcludedFromWebScript:(const char *)name {
863 return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name];
866 - (Source *) initWithMetaIndex:(metaIndex *)index {
867 if ((self = [super init]) != nil) {
868 trusted_ = index->IsTrusted();
870 uri_ = [[NSString stringWithUTF8String:index->GetURI().c_str()] retain];
871 distribution_ = [[NSString stringWithUTF8String:index->GetDist().c_str()] retain];
872 type_ = [[NSString stringWithUTF8String:index->GetType()] retain];
874 debReleaseIndex *dindex(dynamic_cast<debReleaseIndex *>(index));
875 if (dindex != NULL) {
876 std::ifstream release(dindex->MetaIndexFile("Release").c_str());
878 while (std::getline(release, line)) {
879 std::string::size_type colon(line.find(':'));
880 if (colon == std::string::npos)
883 std::string name(line.substr(0, colon));
884 std::string value(line.substr(colon + 1));
885 while (!value.empty() && value[0] == ' ')
886 value = value.substr(1);
888 if (name == "Default-Icon")
889 defaultIcon_ = [[NSString stringWithUTF8String:value.c_str()] retain];
890 else if (name == "Description")
891 description_ = [[NSString stringWithUTF8String:value.c_str()] retain];
892 else if (name == "Label")
893 label_ = [[NSString stringWithUTF8String:value.c_str()] retain];
894 else if (name == "Origin")
895 origin_ = [[NSString stringWithUTF8String:value.c_str()] retain];
896 else if (name == "Version")
897 version_ = [[NSString stringWithUTF8String:value.c_str()] retain];
901 record_ = [Sources_ objectForKey:[self key]];
903 record_ = [record_ retain];
907 - (NSComparisonResult) compareByNameAndType:(Source *)source {
908 NSDictionary *lhr = [self record];
909 NSDictionary *rhr = [source record];
912 return lhr == nil ? NSOrderedDescending : NSOrderedAscending;
914 NSString *lhs = [self name];
915 NSString *rhs = [source name];
917 if ([lhs length] != 0 && [rhs length] != 0) {
918 unichar lhc = [lhs characterAtIndex:0];
919 unichar rhc = [rhs characterAtIndex:0];
921 if (isalpha(lhc) && !isalpha(rhc))
922 return NSOrderedAscending;
923 else if (!isalpha(lhc) && isalpha(rhc))
924 return NSOrderedDescending;
927 return [lhs caseInsensitiveCompare:rhs];
930 - (NSDictionary *) record {
942 - (NSString *) distribution {
943 return distribution_;
946 - (NSString *) type {
951 return [NSString stringWithFormat:@"%@:%@:%@", type_, uri_, distribution_];
954 - (NSString *) host {
955 return [[[NSURL URLWithString:[self uri]] host] lowercaseString];
958 - (NSString *) name {
959 return origin_ == nil ? [self host] : origin_;
962 - (NSString *) description {
966 - (NSString *) label {
967 return label_ == nil ? [self host] : label_;
970 - (NSString *) origin {
974 - (NSString *) version {
978 - (NSString *) defaultIcon {
984 /* Relationship Class {{{ */
985 @interface Relationship : NSObject {
996 @implementation Relationship
1004 - (NSString *) type {
1012 - (NSString *) name {
1019 /* Package Class {{{ */
1020 NSString *Scour(const char *field, const char *begin, const char *end) {
1021 size_t i(0), l(strlen(field));
1024 const char *name = begin + i;
1025 const char *colon = name + l;
1026 const char *value = colon + 1;
1031 memcmp(name, field, l) == 0
1033 while (value != end && value[0] == ' ')
1035 const char *line = std::find(value, end, '\n');
1036 while (line != value && line[-1] == ' ')
1039 return [NSString stringWithUTF8Bytes:value length:(line - value)];
1041 begin = std::find(begin, end, '\n');
1049 @interface Package : NSObject {
1050 pkgCache::PkgIterator iterator_;
1051 _transient Database *database_;
1052 pkgCache::VerIterator version_;
1053 pkgCache::VerFileIterator file_;
1059 NSString *installed_;
1065 NSString *homepage_;
1066 NSString *depiction_;
1072 NSArray *relationships_;
1075 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
1076 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
1078 - (pkgCache::PkgIterator) iterator;
1080 - (NSString *) section;
1081 - (Address *) maintainer;
1083 - (NSString *) description;
1084 - (NSString *) index;
1088 - (NSString *) latest;
1089 - (NSString *) installed;
1092 - (BOOL) upgradableAndEssential:(BOOL)essential;
1095 - (BOOL) unfiltered;
1099 - (BOOL) halfConfigured;
1100 - (BOOL) halfInstalled;
1102 - (NSString *) mode;
1105 - (NSString *) name;
1106 - (NSString *) tagline;
1107 - (NSString *) icon;
1108 - (NSString *) homepage;
1109 - (NSString *) depiction;
1110 - (Address *) author;
1112 - (NSArray *) relationships;
1114 - (Source *) source;
1115 - (NSString *) role;
1117 - (BOOL) matches:(NSString *)text;
1119 - (bool) hasSupportingRole;
1120 - (BOOL) hasTag:(NSString *)tag;
1122 - (NSComparisonResult) compareByName:(Package *)package;
1123 - (NSComparisonResult) compareBySection:(Package *)package;
1124 - (NSComparisonResult) compareBySectionAndName:(Package *)package;
1125 - (NSComparisonResult) compareForChanges:(Package *)package;
1130 - (NSNumber *) isUnfilteredAndSearchedForBy:(NSString *)search;
1131 - (NSNumber *) isInstalledAndUnfiltered:(NSNumber *)number;
1132 - (NSNumber *) isVisiblyUninstalledInSection:(NSString *)section;
1133 - (NSNumber *) isVisibleInSource:(Source *)source;
1137 @implementation Package
1144 if (installed_ != nil)
1145 [installed_ release];
1153 if (homepage_ != nil)
1154 [homepage_ release];
1155 if (depiction_ != nil)
1156 [depiction_ release];
1157 if (sponsor_ != nil)
1166 if (relationships_ != nil)
1167 [relationships_ release];
1172 + (NSArray *) _attributeKeys {
1173 return [NSArray arrayWithObjects:@"author", @"depiction", @"description", @"essential", @"homepage", @"icon", @"id", @"installed", @"latest", @"maintainer", @"name", @"section", @"size", @"source", @"sponsor", @"tagline", nil];
1176 - (NSArray *) attributeKeys {
1177 return [[self class] _attributeKeys];
1180 + (BOOL) isKeyExcludedFromWebScript:(const char *)name {
1181 return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name];
1184 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
1185 if ((self = [super init]) != nil) {
1186 iterator_ = iterator;
1187 database_ = database;
1189 version_ = [database_ policy]->GetCandidateVer(iterator_);
1190 latest_ = version_.end() ? nil : [StripVersion([NSString stringWithUTF8String:version_.VerStr()]) retain];
1192 if (!version_.end())
1193 file_ = version_.FileList();
1195 pkgCache &cache([database_ cache]);
1196 file_ = pkgCache::VerFileIterator(cache, cache.VerFileP);
1199 pkgCache::VerIterator current = iterator_.CurrentVer();
1200 installed_ = current.end() ? nil : [StripVersion([NSString stringWithUTF8String:current.VerStr()]) retain];
1202 id_ = [[[NSString stringWithUTF8String:iterator_.Name()] lowercaseString] retain];
1205 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1207 const char *begin, *end;
1208 parser->GetRec(begin, end);
1210 name_ = Scour("Name", begin, end);
1212 name_ = [name_ retain];
1213 tagline_ = [[NSString stringWithUTF8String:parser->ShortDesc().c_str()] retain];
1214 icon_ = Scour("Icon", begin, end);
1216 icon_ = [icon_ retain];
1217 homepage_ = Scour("Homepage", begin, end);
1218 if (homepage_ == nil)
1219 homepage_ = Scour("Website", begin, end);
1220 if (homepage_ != nil)
1221 homepage_ = [homepage_ retain];
1222 depiction_ = Scour("Depiction", begin, end);
1223 if (depiction_ != nil)
1224 depiction_ = [depiction_ retain];
1225 NSString *sponsor = Scour("Sponsor", begin, end);
1227 sponsor_ = [[Address addressWithString:sponsor] retain];
1228 NSString *author = Scour("Author", begin, end);
1230 author_ = [[Address addressWithString:author] retain];
1231 NSString *tags = Scour("Tag", begin, end);
1233 tags_ = [[tags componentsSeparatedByString:@", "] retain];
1237 for (int i(0), e([tags_ count]); i != e; ++i) {
1238 NSString *tag = [tags_ objectAtIndex:i];
1239 if ([tag hasPrefix:@"role::"]) {
1240 role_ = [[tag substringFromIndex:6] retain];
1245 NSMutableDictionary *metadata = [Packages_ objectForKey:id_];
1246 if (metadata == nil || [metadata count] == 0) {
1247 metadata = [NSMutableDictionary dictionaryWithObjectsAndKeys:
1251 [Packages_ setObject:metadata forKey:id_];
1257 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
1258 return [[[Package alloc]
1259 initWithIterator:iterator
1264 - (pkgCache::PkgIterator) iterator {
1268 - (NSString *) section {
1269 const char *section = iterator_.Section();
1270 if (section == NULL)
1273 NSString *name = [[NSString stringWithUTF8String:section] stringByReplacingCharacter:' ' withCharacter:'_'];
1276 if (NSDictionary *value = [SectionMap_ objectForKey:name])
1277 if (NSString *rename = [value objectForKey:@"Rename"]) {
1282 return [name stringByReplacingCharacter:'_' withCharacter:' '];
1285 - (Address *) maintainer {
1288 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1289 return [Address addressWithString:[NSString stringWithUTF8String:parser->Maintainer().c_str()]];
1293 return version_.end() ? 0 : version_->InstalledSize;
1296 - (NSString *) description {
1299 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1300 NSString *description([NSString stringWithUTF8String:parser->LongDesc().c_str()]);
1302 NSArray *lines = [description componentsSeparatedByString:@"\n"];
1303 NSMutableArray *trimmed = [NSMutableArray arrayWithCapacity:([lines count] - 1)];
1304 if ([lines count] < 2)
1307 NSCharacterSet *whitespace = [NSCharacterSet whitespaceCharacterSet];
1308 for (size_t i(1); i != [lines count]; ++i) {
1309 NSString *trim = [[lines objectAtIndex:i] stringByTrimmingCharactersInSet:whitespace];
1310 [trimmed addObject:trim];
1313 return [trimmed componentsJoinedByString:@"\n"];
1316 - (NSString *) index {
1317 NSString *index = [[[self name] substringToIndex:1] uppercaseString];
1318 return [index length] != 0 && isalpha([index characterAtIndex:0]) ? index : @"123";
1322 return [[Packages_ objectForKey:id_] objectForKey:@"FirstSeen"];
1325 - (NSString *) latest {
1329 - (NSString *) installed {
1334 return !version_.end();
1337 - (BOOL) upgradableAndEssential:(BOOL)essential {
1338 pkgCache::VerIterator current = iterator_.CurrentVer();
1341 return essential && [self essential];
1343 pkgCache::VerIterator candidate = [database_ policy]->GetCandidateVer(iterator_);
1344 return !candidate.end() && candidate != current;
1348 - (BOOL) essential {
1349 return (iterator_->Flags & pkgCache::Flag::Essential) == 0 ? NO : YES;
1353 return [database_ cache][iterator_].InstBroken();
1356 - (BOOL) unfiltered {
1357 NSString *section = [self section];
1358 return section == nil || isSectionVisible(section);
1362 return [self hasSupportingRole] && [self unfiltered];
1366 unsigned char current = iterator_->CurrentState;
1367 return current == pkgCache::State::HalfConfigured || current == pkgCache::State::HalfInstalled;
1370 - (BOOL) halfConfigured {
1371 return iterator_->CurrentState == pkgCache::State::HalfConfigured;
1374 - (BOOL) halfInstalled {
1375 return iterator_->CurrentState == pkgCache::State::HalfInstalled;
1379 pkgDepCache::StateCache &state([database_ cache][iterator_]);
1380 return state.Mode != pkgDepCache::ModeKeep;
1383 - (NSString *) mode {
1384 pkgDepCache::StateCache &state([database_ cache][iterator_]);
1386 switch (state.Mode) {
1387 case pkgDepCache::ModeDelete:
1388 if ((state.iFlags & pkgDepCache::Purge) != 0)
1393 case pkgDepCache::ModeKeep:
1394 if ((state.iFlags & pkgDepCache::AutoKept) != 0)
1399 case pkgDepCache::ModeInstall:
1400 if ((state.iFlags & pkgDepCache::ReInstall) != 0)
1401 return @"Reinstall";
1402 else switch (state.Status) {
1404 return @"Downgrade";
1410 return @"New Install";
1423 - (NSString *) name {
1424 return name_ == nil ? id_ : name_;
1427 - (NSString *) tagline {
1431 - (NSString *) icon {
1435 - (NSString *) homepage {
1436 return homepage_ == nil ? depiction_ : homepage_;
1439 - (NSString *) depiction {
1443 - (Address *) sponsor {
1447 - (Address *) author {
1451 - (NSArray *) relationships {
1452 return relationships_;
1455 - (Source *) source {
1457 source_ = file_.end() ? nil : [[database_ getSource:file_.File()] retain];
1464 - (NSString *) role {
1468 - (BOOL) matches:(NSString *)text {
1474 range = [[self id] rangeOfString:text options:NSCaseInsensitiveSearch];
1475 if (range.location != NSNotFound)
1478 range = [[self name] rangeOfString:text options:NSCaseInsensitiveSearch];
1479 if (range.location != NSNotFound)
1482 range = [[self tagline] rangeOfString:text options:NSCaseInsensitiveSearch];
1483 if (range.location != NSNotFound)
1489 - (bool) hasSupportingRole {
1492 if ([role_ isEqualToString:@"enduser"])
1494 if ([Role_ isEqualToString:@"User"])
1496 if ([role_ isEqualToString:@"hacker"])
1498 if ([Role_ isEqualToString:@"Hacker"])
1500 if ([role_ isEqualToString:@"developer"])
1502 if ([Role_ isEqualToString:@"Developer"])
1507 - (BOOL) hasTag:(NSString *)tag {
1508 return tags_ == nil ? NO : [tags_ containsObject:tag];
1511 - (NSComparisonResult) compareByName:(Package *)package {
1512 NSString *lhs = [self name];
1513 NSString *rhs = [package name];
1515 if ([lhs length] != 0 && [rhs length] != 0) {
1516 unichar lhc = [lhs characterAtIndex:0];
1517 unichar rhc = [rhs characterAtIndex:0];
1519 if (isalpha(lhc) && !isalpha(rhc))
1520 return NSOrderedAscending;
1521 else if (!isalpha(lhc) && isalpha(rhc))
1522 return NSOrderedDescending;
1525 return [lhs caseInsensitiveCompare:rhs];
1528 - (NSComparisonResult) compareBySection:(Package *)package {
1529 NSString *lhs = [self section];
1530 NSString *rhs = [package section];
1532 if (lhs == NULL && rhs != NULL)
1533 return NSOrderedAscending;
1534 else if (lhs != NULL && rhs == NULL)
1535 return NSOrderedDescending;
1536 else if (lhs != NULL && rhs != NULL) {
1537 NSComparisonResult result = [lhs caseInsensitiveCompare:rhs];
1538 if (result != NSOrderedSame)
1542 return NSOrderedSame;
1545 - (NSComparisonResult) compareBySectionAndName:(Package *)package {
1546 NSString *lhs = [self section];
1547 NSString *rhs = [package section];
1549 if (lhs == NULL && rhs != NULL)
1550 return NSOrderedAscending;
1551 else if (lhs != NULL && rhs == NULL)
1552 return NSOrderedDescending;
1553 else if (lhs != NULL && rhs != NULL) {
1554 NSComparisonResult result = [lhs compare:rhs];
1555 if (result != NSOrderedSame)
1559 return [self compareByName:package];
1562 - (NSComparisonResult) compareForChanges:(Package *)package {
1563 BOOL lhs = [self upgradableAndEssential:YES];
1564 BOOL rhs = [package upgradableAndEssential:YES];
1567 return lhs ? NSOrderedAscending : NSOrderedDescending;
1569 switch ([[self seen] compare:[package seen]]) {
1570 case NSOrderedAscending:
1571 return NSOrderedDescending;
1574 case NSOrderedDescending:
1575 return NSOrderedAscending;
1581 return [self compareByName:package];
1585 pkgProblemResolver *resolver = [database_ resolver];
1586 resolver->Clear(iterator_);
1587 resolver->Protect(iterator_);
1588 pkgCacheFile &cache([database_ cache]);
1589 cache->MarkInstall(iterator_, false);
1590 pkgDepCache::StateCache &state((*cache)[iterator_]);
1591 if (!state.Install())
1592 cache->SetReInstall(iterator_, true);
1596 pkgProblemResolver *resolver = [database_ resolver];
1597 resolver->Clear(iterator_);
1598 resolver->Protect(iterator_);
1599 resolver->Remove(iterator_);
1600 [database_ cache]->MarkDelete(iterator_, true);
1603 - (NSNumber *) isUnfilteredAndSearchedForBy:(NSString *)search {
1604 return [NSNumber numberWithBool:(
1605 [self unfiltered] && [self matches:search]
1609 - (NSNumber *) isInstalledAndUnfiltered:(NSNumber *)number {
1610 return [NSNumber numberWithBool:(
1611 (![number boolValue] || [self unfiltered]) && [self installed] != nil
1615 - (NSNumber *) isVisiblyUninstalledInSection:(NSString *)name {
1616 NSString *section = [self section];
1618 return [NSNumber numberWithBool:(
1620 [self installed] == nil && (
1622 section == nil && [name length] == 0 ||
1623 [name isEqualToString:section]
1628 - (NSNumber *) isVisibleInSource:(Source *)source {
1629 return [NSNumber numberWithBool:([self source] == source && [self visible])];
1634 /* Section Class {{{ */
1635 @interface Section : NSObject {
1641 - (NSComparisonResult) compareByName:(Section *)section;
1642 - (Section *) initWithName:(NSString *)name;
1643 - (Section *) initWithName:(NSString *)name row:(size_t)row;
1644 - (NSString *) name;
1647 - (void) addToCount;
1651 @implementation Section
1658 - (NSComparisonResult) compareByName:(Section *)section {
1659 NSString *lhs = [self name];
1660 NSString *rhs = [section name];
1662 if ([lhs length] != 0 && [rhs length] != 0) {
1663 unichar lhc = [lhs characterAtIndex:0];
1664 unichar rhc = [rhs characterAtIndex:0];
1666 if (isalpha(lhc) && !isalpha(rhc))
1667 return NSOrderedAscending;
1668 else if (!isalpha(lhc) && isalpha(rhc))
1669 return NSOrderedDescending;
1672 return [lhs caseInsensitiveCompare:rhs];
1675 - (Section *) initWithName:(NSString *)name {
1676 return [self initWithName:name row:0];
1679 - (Section *) initWithName:(NSString *)name row:(size_t)row {
1680 if ((self = [super init]) != nil) {
1681 name_ = [name retain];
1686 - (NSString *) name {
1698 - (void) addToCount {
1708 /* Database Implementation {{{ */
1709 @implementation Database
1716 - (void) _readCydia:(NSNumber *)fd {
1717 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1719 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1720 std::istream is(&ib);
1723 static Pcre finish_r("^finish:([^:]*)$");
1725 while (std::getline(is, line)) {
1726 const char *data(line.c_str());
1727 size_t size = line.size();
1728 fprintf(stderr, "C:%s\n", data);
1730 if (finish_r(data, size)) {
1731 NSString *finish = finish_r[1];
1732 int index = [Finishes_ indexOfObject:finish];
1733 if (index != INT_MAX && index > Finish_)
1742 - (void) _readStatus:(NSNumber *)fd {
1743 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1745 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1746 std::istream is(&ib);
1749 static Pcre conffile_r("^status: [^ ]* : conffile-prompt : (.*?) *$");
1750 static Pcre pmstatus_r("^([^:]*):([^:]*):([^:]*):(.*)$");
1752 while (std::getline(is, line)) {
1753 const char *data(line.c_str());
1754 size_t size = line.size();
1755 fprintf(stderr, "S:%s\n", data);
1757 if (conffile_r(data, size)) {
1758 [delegate_ setConfigurationData:conffile_r[1]];
1759 } else if (strncmp(data, "status: ", 8) == 0) {
1760 NSString *string = [NSString stringWithUTF8String:(data + 8)];
1761 [delegate_ setProgressTitle:string];
1762 } else if (pmstatus_r(data, size)) {
1763 std::string type([pmstatus_r[1] UTF8String]);
1764 NSString *id = pmstatus_r[2];
1766 float percent([pmstatus_r[3] floatValue]);
1767 [delegate_ setProgressPercent:(percent / 100)];
1769 NSString *string = pmstatus_r[4];
1771 if (type == "pmerror")
1772 [delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
1773 withObject:[NSArray arrayWithObjects:string, id, nil]
1776 else if (type == "pmstatus")
1777 [delegate_ setProgressTitle:string];
1778 else if (type == "pmconffile")
1779 [delegate_ setConfigurationData:string];
1780 else _assert(false);
1781 } else _assert(false);
1788 - (void) _readOutput:(NSNumber *)fd {
1789 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1791 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1792 std::istream is(&ib);
1795 while (std::getline(is, line)) {
1796 fprintf(stderr, "O:%s\n", line.c_str());
1797 [delegate_ addProgressOutput:[NSString stringWithUTF8String:line.c_str()]];
1808 - (Package *) packageWithName:(NSString *)name {
1809 if (static_cast<pkgDepCache *>(cache_) == NULL)
1811 pkgCache::PkgIterator iterator(cache_->FindPkg([name UTF8String]));
1812 return iterator.end() ? nil : [Package packageWithIterator:iterator database:self];
1815 - (Database *) init {
1816 if ((self = [super init]) != nil) {
1823 sources_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1824 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
1828 _assert(pipe(fds) != -1);
1831 _config->Set("APT::Keep-Fds::", cydiafd_);
1832 setenv("CYDIA", [[[[NSNumber numberWithInt:cydiafd_] stringValue] stringByAppendingString:@" 1"] UTF8String], _not(int));
1835 detachNewThreadSelector:@selector(_readCydia:)
1837 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1840 _assert(pipe(fds) != -1);
1844 detachNewThreadSelector:@selector(_readStatus:)
1846 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1849 _assert(pipe(fds) != -1);
1850 _assert(dup2(fds[0], 0) != -1);
1851 _assert(close(fds[0]) != -1);
1853 input_ = fdopen(fds[1], "a");
1855 _assert(pipe(fds) != -1);
1856 _assert(dup2(fds[1], 1) != -1);
1857 _assert(close(fds[1]) != -1);
1860 detachNewThreadSelector:@selector(_readOutput:)
1862 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1867 - (pkgCacheFile &) cache {
1871 - (pkgDepCache::Policy *) policy {
1875 - (pkgRecords *) records {
1879 - (pkgProblemResolver *) resolver {
1883 - (pkgAcquire &) fetcher {
1887 - (NSArray *) packages {
1891 - (NSArray *) sources {
1892 return [sources_ allValues];
1895 - (void) reloadData {
1914 if (!cache_.Open(progress_, true)) {
1916 if (!_error->PopMessage(error))
1919 fprintf(stderr, "cache_.Open():[%s]\n", error.c_str());
1921 if (error == "dpkg was interrupted, you must manually run 'dpkg --configure -a' to correct the problem. ")
1922 [delegate_ repairWithSelector:@selector(configure)];
1923 else if (error == "The package lists or status file could not be parsed or opened.")
1924 [delegate_ repairWithSelector:@selector(update)];
1925 // else if (error == "Could not open lock file /var/lib/dpkg/lock - open (13 Permission denied)")
1926 // else if (error == "Could not get lock /var/lib/dpkg/lock - open (35 Resource temporarily unavailable)")
1927 // else if (error == "The list of sources could not be read.")
1928 else _assert(false);
1933 now_ = [[NSDate date] retain];
1935 policy_ = new pkgDepCache::Policy();
1936 records_ = new pkgRecords(cache_);
1937 resolver_ = new pkgProblemResolver(cache_);
1938 fetcher_ = new pkgAcquire(&status_);
1941 list_ = new pkgSourceList();
1942 _assert(list_->ReadMainList());
1944 _assert(cache_->DelCount() == 0 && cache_->InstCount() == 0);
1945 _assert(pkgApplyStatus(cache_));
1947 if (cache_->BrokenCount() != 0) {
1948 _assert(pkgFixBroken(cache_));
1949 _assert(cache_->BrokenCount() == 0);
1950 _assert(pkgMinimizeUpgrade(cache_));
1953 [sources_ removeAllObjects];
1954 for (pkgSourceList::const_iterator source = list_->begin(); source != list_->end(); ++source) {
1955 std::vector<pkgIndexFile *> *indices = (*source)->GetIndexFiles();
1956 for (std::vector<pkgIndexFile *>::const_iterator index = indices->begin(); index != indices->end(); ++index)
1958 setObject:[[[Source alloc] initWithMetaIndex:*source] autorelease]
1959 forKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(*index)]
1963 [packages_ removeAllObjects];
1964 for (pkgCache::PkgIterator iterator = cache_->PkgBegin(); !iterator.end(); ++iterator)
1965 if (Package *package = [Package packageWithIterator:iterator database:self])
1966 [packages_ addObject:package];
1968 [packages_ sortUsingSelector:@selector(compareByName:)];
1971 - (void) configure {
1972 NSString *dpkg = [NSString stringWithFormat:@"dpkg --configure -a --status-fd %u", statusfd_];
1973 system([dpkg UTF8String]);
1981 Lock.Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1982 _assert(!_error->PendingError());
1985 fetcher.Clean(_config->FindDir("Dir::Cache::Archives"));
1988 public pkgArchiveCleaner
1991 virtual void Erase(const char *File, std::string Pkg, std::string Ver, struct stat &St) {
1996 if (!cleaner.Go(_config->FindDir("Dir::Cache::Archives") + "partial/", cache_)) {
1998 while (_error->PopMessage(error))
1999 fprintf(stderr, "ArchiveCleaner: %s\n", error.c_str());
2004 pkgRecords records(cache_);
2006 lock_ = new FileFd();
2007 lock_->Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
2008 _assert(!_error->PendingError());
2011 // XXX: explain this with an error message
2012 _assert(list.ReadMainList());
2014 manager_ = (_system->CreatePM(cache_));
2015 _assert(manager_->GetArchives(fetcher_, &list, &records));
2016 _assert(!_error->PendingError());
2020 NSMutableArray *before = [NSMutableArray arrayWithCapacity:16]; {
2022 _assert(list.ReadMainList());
2023 for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source)
2024 [before addObject:[NSString stringWithUTF8String:(*source)->GetURI().c_str()]];
2027 if (fetcher_->Run(PulseInterval_) != pkgAcquire::Continue) {
2032 bool failed = false;
2033 for (pkgAcquire::ItemIterator item = fetcher_->ItemsBegin(); item != fetcher_->ItemsEnd(); item++) {
2034 if ((*item)->Status == pkgAcquire::Item::StatDone && (*item)->Complete)
2037 std::string uri = (*item)->DescURI();
2038 std::string error = (*item)->ErrorText;
2040 fprintf(stderr, "pAf:%s:%s\n", uri.c_str(), error.c_str());
2043 [delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
2044 withObject:[NSArray arrayWithObjects:[NSString stringWithUTF8String:error.c_str()], nil]
2055 pkgPackageManager::OrderResult result = manager_->DoInstall(statusfd_);
2057 if (_error->PendingError()) {
2062 if (result == pkgPackageManager::Failed) {
2067 if (result != pkgPackageManager::Completed) {
2072 NSMutableArray *after = [NSMutableArray arrayWithCapacity:16]; {
2074 _assert(list.ReadMainList());
2075 for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source)
2076 [after addObject:[NSString stringWithUTF8String:(*source)->GetURI().c_str()]];
2079 if (![before isEqualToArray:after])
2084 _assert(pkgDistUpgrade(cache_));
2088 [self updateWithStatus:status_];
2091 - (void) updateWithStatus:(Status &)status {
2093 _assert(list.ReadMainList());
2096 lock.Fd(GetLock(_config->FindDir("Dir::State::Lists") + "lock"));
2097 _assert(!_error->PendingError());
2099 pkgAcquire fetcher(&status);
2100 _assert(list.GetIndexes(&fetcher));
2102 if (fetcher.Run(PulseInterval_) != pkgAcquire::Failed) {
2103 bool failed = false;
2104 for (pkgAcquire::ItemIterator item = fetcher.ItemsBegin(); item != fetcher.ItemsEnd(); item++)
2105 if ((*item)->Status != pkgAcquire::Item::StatDone) {
2106 (*item)->Finished();
2110 if (!failed && _config->FindB("APT::Get::List-Cleanup", true) == true) {
2111 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists")));
2112 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/"));
2115 [Metadata_ setObject:[NSDate date] forKey:@"LastUpdate"];
2120 - (void) setDelegate:(id)delegate {
2121 delegate_ = delegate;
2122 status_.setDelegate(delegate);
2123 progress_.setDelegate(delegate);
2126 - (Source *) getSource:(const pkgCache::PkgFileIterator &)file {
2127 pkgIndexFile *index(NULL);
2128 list_->FindIndex(file, index);
2129 return [sources_ objectForKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(index)]];
2135 /* Confirmation View {{{ */
2136 void AddTextView(NSMutableDictionary *fields, NSMutableArray *packages, NSString *key) {
2137 if ([packages count] == 0)
2140 UITextView *text = GetTextView([packages count] == 0 ? @"n/a" : [packages componentsJoinedByString:@", "], 120, false);
2141 [fields setObject:text forKey:key];
2143 CGColor blue(space_, 0, 0, 0.4, 1);
2144 [text setTextColor:[UIColor colorWithCGColor:blue]];
2147 @protocol ConfirmationViewDelegate
2152 @interface ConfirmationView : UIView {
2153 Database *database_;
2155 UITransitionView *transition_;
2157 UINavigationBar *navbar_;
2158 UIPreferencesTable *table_;
2159 NSMutableDictionary *fields_;
2160 UIActionSheet *essential_;
2165 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate;
2169 @implementation ConfirmationView
2172 [navbar_ setDelegate:nil];
2173 [transition_ setDelegate:nil];
2174 [table_ setDataSource:nil];
2176 [transition_ release];
2181 if (essential_ != nil)
2182 [essential_ release];
2187 [transition_ transition:7 toView:nil];
2191 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
2192 if (from != nil && to == nil)
2193 [self removeFromSuperview];
2196 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2199 if (essential_ != nil)
2200 [essential_ popupAlertAnimated:YES];
2202 [delegate_ confirm];
2211 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
2212 NSString *context = [sheet context];
2214 if ([context isEqualToString:@"remove"])
2220 [delegate_ confirm];
2225 else if ([context isEqualToString:@"unable"])
2231 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
2235 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
2237 case 0: return @"Statistics";
2238 case 1: return @"Modifications";
2240 default: _assert(false);
2244 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
2247 case 1: return [fields_ count];
2249 default: _assert(false);
2253 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
2254 if (group != 1 || row == -1)
2257 _assert(size_t(row) < [fields_ count]);
2258 return [[[fields_ allValues] objectAtIndex:row] visibleTextRect].size.height + TextViewOffset_;
2262 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
2263 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
2264 [cell setShowSelection:NO];
2267 case 0: switch (row) {
2269 [cell setTitle:@"Downloading"];
2270 [cell setValue:SizeString([database_ fetcher].FetchNeeded())];
2274 [cell setTitle:@"Resuming At"];
2275 [cell setValue:SizeString([database_ fetcher].PartialPresent())];
2279 double size([database_ cache]->UsrSize());
2282 [cell setTitle:@"Disk Freeing"];
2283 [cell setValue:SizeString(-size)];
2285 [cell setTitle:@"Disk Using"];
2286 [cell setValue:SizeString(size)];
2290 default: _assert(false);
2294 _assert(size_t(row) < [fields_ count]);
2295 [cell setTitle:[[fields_ allKeys] objectAtIndex:row]];
2296 [cell addSubview:[[fields_ allValues] objectAtIndex:row]];
2299 default: _assert(false);
2305 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate {
2306 if ((self = [super initWithFrame:[view bounds]]) != nil) {
2307 database_ = database;
2308 delegate_ = delegate;
2310 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
2311 [self addSubview:transition_];
2313 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
2315 CGSize navsize = [UINavigationBar defaultSize];
2316 CGRect navrect = {{0, 0}, navsize};
2317 CGRect bounds = [overlay_ bounds];
2319 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
2320 [navbar_ setDelegate:self];
2322 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Confirm"] autorelease];
2323 [navbar_ pushNavigationItem:navitem];
2324 [navbar_ showButtonsWithLeftTitle:@"Cancel" rightTitle:@"Confirm"];
2326 fields_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
2328 NSMutableArray *installing = [NSMutableArray arrayWithCapacity:16];
2329 NSMutableArray *reinstalling = [NSMutableArray arrayWithCapacity:16];
2330 NSMutableArray *upgrading = [NSMutableArray arrayWithCapacity:16];
2331 NSMutableArray *downgrading = [NSMutableArray arrayWithCapacity:16];
2332 NSMutableArray *removing = [NSMutableArray arrayWithCapacity:16];
2336 pkgCacheFile &cache([database_ cache]);
2337 NSArray *packages = [database_ packages];
2338 for (size_t i(0), e = [packages count]; i != e; ++i) {
2339 Package *package = [packages objectAtIndex:i];
2340 pkgCache::PkgIterator iterator = [package iterator];
2341 pkgDepCache::StateCache &state(cache[iterator]);
2343 NSString *name([package name]);
2345 if (state.NewInstall())
2346 [installing addObject:name];
2347 else if (!state.Delete() && (state.iFlags & pkgDepCache::ReInstall) == pkgDepCache::ReInstall)
2348 [reinstalling addObject:name];
2349 else if (state.Upgrade())
2350 [upgrading addObject:name];
2351 else if (state.Downgrade())
2352 [downgrading addObject:name];
2353 else if (state.Delete()) {
2354 if ([package essential])
2356 [removing addObject:name];
2362 else if (Advanced_ || true) {
2363 essential_ = [[UIActionSheet alloc]
2364 initWithTitle:@"Removing Essentials"
2365 buttons:[NSArray arrayWithObjects:
2366 @"Cancel Operation (Safe)",
2367 @"Force Removal (Unsafe)",
2369 defaultButtonIndex:0
2375 [essential_ setDestructiveButton:[[essential_ buttons] objectAtIndex:0]];
2377 [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."];
2379 essential_ = [[UIActionSheet alloc]
2380 initWithTitle:@"Unable to Comply"
2381 buttons:[NSArray arrayWithObjects:@"Okay", nil]
2382 defaultButtonIndex:0
2387 [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."];
2390 AddTextView(fields_, installing, @"Installing");
2391 AddTextView(fields_, reinstalling, @"Reinstalling");
2392 AddTextView(fields_, upgrading, @"Upgrading");
2393 AddTextView(fields_, downgrading, @"Downgrading");
2394 AddTextView(fields_, removing, @"Removing");
2396 table_ = [[UIPreferencesTable alloc] initWithFrame:CGRectMake(
2397 0, navsize.height, bounds.size.width, bounds.size.height - navsize.height
2400 [table_ setReusesTableCells:YES];
2401 [table_ setDataSource:self];
2402 [table_ reloadData];
2404 [overlay_ addSubview:navbar_];
2405 [overlay_ addSubview:table_];
2407 [view addSubview:self];
2409 [transition_ setDelegate:self];
2411 UIView *blank = [[[UIView alloc] initWithFrame:[transition_ bounds]] autorelease];
2412 [transition_ transition:0 toView:blank];
2413 [transition_ transition:3 toView:overlay_];
2420 /* Progress Data {{{ */
2421 @interface ProgressData : NSObject {
2427 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object;
2434 @implementation ProgressData
2436 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object {
2437 if ((self = [super init]) != nil) {
2438 selector_ = selector;
2458 /* Progress View {{{ */
2459 @interface ProgressView : UIView <
2460 ConfigurationDelegate,
2463 _transient Database *database_;
2465 UIView *background_;
2466 UITransitionView *transition_;
2468 UINavigationBar *navbar_;
2469 UIProgressBar *progress_;
2470 UITextView *output_;
2471 UITextLabel *status_;
2472 UIPushButton *close_;
2475 SHA1SumValue springlist_;
2478 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
2480 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database delegate:(id)delegate;
2481 - (void) setContentView:(UIView *)view;
2484 - (void) _retachThread;
2485 - (void) _detachNewThreadData:(ProgressData *)data;
2486 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title;
2492 @protocol ProgressViewDelegate
2493 - (void) progressViewIsComplete:(ProgressView *)sender;
2496 @implementation ProgressView
2499 [transition_ setDelegate:nil];
2500 [navbar_ setDelegate:nil];
2503 if (background_ != nil)
2504 [background_ release];
2505 [transition_ release];
2508 [progress_ release];
2515 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
2516 if (bootstrap_ && from == overlay_ && to == view_)
2520 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database delegate:(id)delegate {
2521 if ((self = [super initWithFrame:frame]) != nil) {
2522 database_ = database;
2523 delegate_ = delegate;
2525 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
2526 [transition_ setDelegate:self];
2528 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
2531 [overlay_ setBackgroundColor:[UIColor colorWithCGColor:Black_]];
2533 background_ = [[UIView alloc] initWithFrame:[self bounds]];
2534 [background_ setBackgroundColor:[UIColor colorWithCGColor:Black_]];
2535 [self addSubview:background_];
2538 [self addSubview:transition_];
2540 CGSize navsize = [UINavigationBar defaultSize];
2541 CGRect navrect = {{0, 0}, navsize};
2543 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
2544 [overlay_ addSubview:navbar_];
2546 [navbar_ setBarStyle:1];
2547 [navbar_ setDelegate:self];
2549 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:nil] autorelease];
2550 [navbar_ pushNavigationItem:navitem];
2552 CGRect bounds = [overlay_ bounds];
2553 CGSize prgsize = [UIProgressBar defaultSize];
2556 (bounds.size.width - prgsize.width) / 2,
2557 bounds.size.height - prgsize.height - 20
2560 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
2561 [progress_ setStyle:0];
2563 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(
2565 bounds.size.height - prgsize.height - 50,
2566 bounds.size.width - 20,
2570 [status_ setColor:[UIColor colorWithCGColor:White_]];
2571 [status_ setBackgroundColor:[UIColor colorWithCGColor:Clear_]];
2573 [status_ setCentersHorizontally:YES];
2574 //[status_ setFont:font];
2576 output_ = [[UITextView alloc] initWithFrame:CGRectMake(
2578 navrect.size.height + 20,
2579 bounds.size.width - 20,
2580 bounds.size.height - navsize.height - 62 - navrect.size.height
2583 //[output_ setTextFont:@"Courier New"];
2584 [output_ setTextSize:12];
2586 [output_ setTextColor:[UIColor colorWithCGColor:White_]];
2587 [output_ setBackgroundColor:[UIColor colorWithCGColor:Clear_]];
2589 [output_ setMarginTop:0];
2590 [output_ setAllowsRubberBanding:YES];
2591 [output_ setEditable:NO];
2593 [overlay_ addSubview:output_];
2595 close_ = [[UIPushButton alloc] initWithFrame:CGRectMake(
2597 bounds.size.height - prgsize.height - 50,
2598 bounds.size.width - 20,
2602 [close_ setAutosizesToFit:NO];
2603 [close_ setDrawsShadow:YES];
2604 [close_ setStretchBackground:YES];
2605 [close_ setEnabled:YES];
2607 UIFont *bold = [UIFont boldSystemFontOfSize:22];
2608 [close_ setTitleFont:bold];
2610 [close_ addTarget:self action:@selector(closeButtonPushed) forEvents:kUIControlEventMouseUpInside];
2611 [close_ setBackground:[UIImage applicationImageNamed:@"green-up.png"] forState:0];
2612 [close_ setBackground:[UIImage applicationImageNamed:@"green-dn.png"] forState:1];
2616 - (void) setContentView:(UIView *)view {
2617 view_ = [view retain];
2620 - (void) resetView {
2621 [transition_ transition:6 toView:view_];
2624 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
2625 NSString *context = [sheet context];
2626 if ([context isEqualToString:@"conffile"]) {
2627 FILE *input = [database_ input];
2631 fprintf(input, "N\n");
2635 fprintf(input, "Y\n");
2646 - (void) closeButtonPushed {
2649 [delegate_ progressViewIsComplete:self];
2654 [delegate_ suspendWithAnimation:YES];
2658 system("killall SpringBoard");
2662 system("launchctl unload /System/Library/LaunchDaemons/com.apple.SpringBoard.plist; launchctl load /System/Library/LaunchDaemons/com.apple.SpringBoard.plist");
2671 - (void) _retachThread {
2672 UINavigationItem *item = [navbar_ topItem];
2673 [item setTitle:@"Complete"];
2675 [overlay_ addSubview:close_];
2676 [progress_ removeFromSuperview];
2677 [status_ removeFromSuperview];
2680 FileFd file("/System/Library/LaunchDaemons/com.apple.SpringBoard.plist", FileFd::ReadOnly);
2681 MMap mmap(file, MMap::ReadOnly);
2683 sha1.Add(reinterpret_cast<uint8_t *>(mmap.Data()), mmap.Size());
2684 if (!(springlist_ == sha1.Result()))
2689 case 0: [close_ setTitle:@"Return to Cydia"]; break;
2690 case 1: [close_ setTitle:@"Close Cydia (Restart)"]; break;
2691 case 2: [close_ setTitle:@"Restart SpringBoard"]; break;
2692 case 3: [close_ setTitle:@"Reload SpringBoard"]; break;
2693 case 4: [close_ setTitle:@"Reboot Device"]; break;
2697 notify_post("com.apple.mobile.application_installed");
2700 [delegate_ setStatusBarShowsProgress:NO];
2705 - (void) _detachNewThreadData:(ProgressData *)data {
2706 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
2708 [[data target] performSelector:[data selector] withObject:[data object]];
2711 [self performSelectorOnMainThread:@selector(_retachThread) withObject:nil waitUntilDone:YES];
2716 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title {
2717 UINavigationItem *item = [navbar_ topItem];
2718 [item setTitle:title];
2720 [status_ setText:nil];
2721 [output_ setText:@""];
2722 [progress_ setProgress:0];
2724 [close_ removeFromSuperview];
2725 [overlay_ addSubview:progress_];
2726 [overlay_ addSubview:status_];
2728 [delegate_ setStatusBarShowsProgress:YES];
2732 FileFd file("/System/Library/LaunchDaemons/com.apple.SpringBoard.plist", FileFd::ReadOnly);
2733 MMap mmap(file, MMap::ReadOnly);
2735 sha1.Add(reinterpret_cast<uint8_t *>(mmap.Data()), mmap.Size());
2736 springlist_ = sha1.Result();
2739 [transition_ transition:6 toView:overlay_];
2742 detachNewThreadSelector:@selector(_detachNewThreadData:)
2744 withObject:[[ProgressData alloc]
2745 initWithSelector:selector
2752 - (void) repairWithSelector:(SEL)selector {
2754 detachNewThreadSelector:selector
2757 title:@"Repairing..."
2761 - (void) setConfigurationData:(NSString *)data {
2763 performSelectorOnMainThread:@selector(_setConfigurationData:)
2769 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id {
2770 Package *package = id == nil ? nil : [database_ packageWithName:id];
2772 UIActionSheet *sheet = [[[UIActionSheet alloc]
2773 initWithTitle:(package == nil ? @"Source Error" : [package name])
2774 buttons:[NSArray arrayWithObjects:@"Okay", nil]
2775 defaultButtonIndex:0
2780 [sheet setBodyText:error];
2781 [sheet popupAlertAnimated:YES];
2784 - (void) setProgressTitle:(NSString *)title {
2786 performSelectorOnMainThread:@selector(_setProgressTitle:)
2792 - (void) setProgressPercent:(float)percent {
2794 performSelectorOnMainThread:@selector(_setProgressPercent:)
2795 withObject:[NSNumber numberWithFloat:percent]
2800 - (void) addProgressOutput:(NSString *)output {
2802 performSelectorOnMainThread:@selector(_addProgressOutput:)
2808 - (void) _setConfigurationData:(NSString *)data {
2809 static Pcre conffile_r("^'(.*)' '(.*)' ([01]) ([01])$");
2811 _assert(conffile_r(data));
2813 NSString *ofile = conffile_r[1];
2814 //NSString *nfile = conffile_r[2];
2816 UIActionSheet *sheet = [[[UIActionSheet alloc]
2817 initWithTitle:@"Configuration Upgrade"
2818 buttons:[NSArray arrayWithObjects:
2819 @"Keep My Old Copy",
2820 @"Accept The New Copy",
2821 // XXX: @"See What Changed",
2823 defaultButtonIndex:0
2828 [sheet setBodyText:[NSString stringWithFormat:
2829 @"The following file has been changed by both the package maintainer and by you (or for you by a script).\n\n%@"
2832 [sheet popupAlertAnimated:YES];
2835 - (void) _setProgressTitle:(NSString *)title {
2836 [status_ setText:[title stringByAppendingString:@"..."]];
2839 - (void) _setProgressPercent:(NSNumber *)percent {
2840 [progress_ setProgress:[percent floatValue]];
2843 - (void) _addProgressOutput:(NSString *)output {
2844 [output_ setText:[NSString stringWithFormat:@"%@\n%@", [output_ text], output]];
2845 CGSize size = [output_ contentSize];
2846 CGRect rect = {{0, size.height}, {size.width, 0}};
2847 [output_ scrollRectToVisible:rect animated:YES];
2850 - (BOOL) isRunning {
2857 /* Package Cell {{{ */
2858 @interface PackageCell : UISimpleTableCell {
2861 NSString *description_;
2863 //UIImageView *trusted_;
2865 UIImageView *badge_;
2866 UITextLabel *status_;
2870 - (PackageCell *) init;
2871 - (void) setPackage:(Package *)package;
2873 + (int) heightForPackage:(Package *)package;
2877 @implementation PackageCell
2879 - (void) clearPackage {
2890 if (description_ != nil) {
2891 [description_ release];
2895 if (source_ != nil) {
2902 [self clearPackage];
2907 //[trusted_ release];
2911 - (PackageCell *) init {
2912 if ((self = [super init]) != nil) {
2914 badge_ = [[UIImageView alloc] initWithFrame:CGRectMake(17, 70, 16, 16)];
2916 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 68, 280, 20)];
2917 [status_ setBackgroundColor:Clear_];
2918 [status_ setFont:small];
2923 - (void) setPackage:(Package *)package {
2924 [self clearPackage];
2926 Source *source = [package source];
2929 if (NSString *icon = [package icon])
2930 icon_ = [UIImage imageAtPath:[icon substringFromIndex:6]];
2931 if (icon_ == nil) if (NSString *section = [package section])
2932 icon_ = [UIImage imageAtPath:[NSString stringWithFormat:@"%@/Sections/%@.png", App_, Simplify(section)]];
2933 /*if (icon_ == nil) if (NSString *icon = [source defaultIcon])
2934 icon_ = [UIImage imageAtPath:[icon substringFromIndex:6]];*/
2936 icon_ = [UIImage applicationImageNamed:@"unknown.png"];
2938 icon_ = [icon_ retain];
2940 name_ = [[package name] retain];
2941 description_ = [[package tagline] retain];
2943 NSString *label = nil;
2944 bool trusted = false;
2946 if (source != nil) {
2947 label = [source label];
2948 trusted = [source trusted];
2949 } else if ([[package id] isEqualToString:@"firmware"])
2952 label = @"Unknown/Local";
2954 NSString *from = [NSString stringWithFormat:@"from %@", label];
2956 NSString *section = Simplify([package section]);
2957 if (section != nil && ![section isEqualToString:label])
2958 from = [from stringByAppendingString:[NSString stringWithFormat:@" (%@)", section]];
2960 source_ = [from retain];
2963 [badge_ removeFromSuperview];
2964 [status_ removeFromSuperview];
2966 if (NSString *mode = [package mode]) {
2967 [badge_ setImage:[UIImage applicationImageNamed:
2968 [mode isEqualToString:@"Remove"] || [mode isEqualToString:@"Purge"] ? @"removing.png" : @"installing.png"
2971 [status_ setText:[NSString stringWithFormat:@"Queued for %@", mode]];
2972 [status_ setColor:Blueish_];
2973 } else if ([package half]) {
2974 [badge_ setImage:[UIImage applicationImageNamed:@"damaged.png"]];
2975 [status_ setText:@"Package Damaged"];
2976 [status_ setColor:Red_];
2978 [badge_ setImage:nil];
2979 [status_ setText:nil];
2983 [self addSubview:badge_];
2984 [self addSubview:status_];
2989 - (void) drawContentInRect:(CGRect)rect selected:(BOOL)selected {
2991 [icon_ drawInRect:CGRectMake(10, 10, 30, 30)];
2998 [name_ drawAtPoint:CGPointMake(48, 8) forWidth:240 withFont:Font18Bold_ ellipsis:2];
2999 [source_ drawAtPoint:CGPointMake(58, 29) forWidth:225 withFont:Font12_ ellipsis:2];
3003 [description_ drawAtPoint:CGPointMake(12, 46) forWidth:280 withFont:Font14_ ellipsis:2];
3005 [super drawContentInRect:rect selected:selected];
3008 + (int) heightForPackage:(Package *)package {
3009 NSString *tagline([package tagline]);
3010 int height = tagline == nil || [tagline length] == 0 ? -17 : 0;
3012 if ([package hasMode] || [package half])
3021 /* Section Cell {{{ */
3022 @interface SectionCell : UISimpleTableCell {
3027 _UISwitchSlider *switch_;
3032 - (void) setSection:(Section *)section editing:(BOOL)editing;
3036 @implementation SectionCell
3038 - (void) clearSection {
3039 if (section_ != nil) {
3049 if (count_ != nil) {
3056 [self clearSection];
3063 if ((self = [super init]) != nil) {
3064 icon_ = [[UIImage applicationImageNamed:@"folder.png"] retain];
3066 switch_ = [[_UISwitchSlider alloc] initWithFrame:CGRectMake(218, 9, 60, 25)];
3067 [switch_ addTarget:self action:@selector(onSwitch:) forEvents:kUIControlEventMouseUpInside];
3071 - (void) onSwitch:(id)sender {
3072 NSMutableDictionary *metadata = [Sections_ objectForKey:section_];
3073 if (metadata == nil) {
3074 metadata = [NSMutableDictionary dictionaryWithCapacity:2];
3075 [Sections_ setObject:metadata forKey:section_];
3079 [metadata setObject:[NSNumber numberWithBool:([switch_ value] == 0)] forKey:@"Hidden"];
3082 - (void) setSection:(Section *)section editing:(BOOL)editing {
3083 if (editing != editing_) {
3085 [switch_ removeFromSuperview];
3087 [self addSubview:switch_];
3091 [self clearSection];
3093 if (section == nil) {
3094 name_ = [@"All Packages" retain];
3097 section_ = [section name];
3098 if (section_ != nil)
3099 section_ = [section_ retain];
3100 name_ = [(section_ == nil ? @"(No Section)" : section_) retain];
3101 count_ = [[NSString stringWithFormat:@"%d", [section count]] retain];
3104 [switch_ setValue:isSectionVisible(section_) animated:NO];
3108 - (void) drawContentInRect:(CGRect)rect selected:(BOOL)selected {
3109 [icon_ drawInRect:CGRectMake(8, 7, 32, 32)];
3116 [name_ drawAtPoint:CGPointMake(48, 9) forWidth:(editing_ ? 164 : 250) withFont:Font22Bold_ ellipsis:2];
3118 CGSize size = [count_ sizeWithFont:Font14_];
3122 [count_ drawAtPoint:CGPointMake(12 + (29 - size.width) / 2, 15) withFont:Font12Bold_];
3124 [super drawContentInRect:rect selected:selected];
3130 /* File Table {{{ */
3131 @interface FileTable : RVPage {
3132 _transient Database *database_;
3135 NSMutableArray *files_;
3139 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3140 - (void) setPackage:(Package *)package;
3144 @implementation FileTable
3147 if (package_ != nil)
3156 - (int) numberOfRowsInTable:(UITable *)table {
3157 return files_ == nil ? 0 : [files_ count];
3160 - (float) table:(UITable *)table heightForRow:(int)row {
3164 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
3165 if (reusing == nil) {
3166 reusing = [[[UIImageAndTextTableCell alloc] init] autorelease];
3167 UIFont *font = [UIFont systemFontOfSize:16];
3168 [[(UIImageAndTextTableCell *)reusing titleTextLabel] setFont:font];
3170 [(UIImageAndTextTableCell *)reusing setTitle:[files_ objectAtIndex:row]];
3174 - (BOOL) table:(UITable *)table canSelectRow:(int)row {
3178 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3179 if ((self = [super initWithBook:book]) != nil) {
3180 database_ = database;
3182 files_ = [[NSMutableArray arrayWithCapacity:32] retain];
3184 list_ = [[UITable alloc] initWithFrame:[self bounds]];
3185 [self addSubview:list_];
3187 UITableColumn *column = [[[UITableColumn alloc]
3188 initWithTitle:@"Name"
3190 width:[self frame].size.width
3193 [list_ setDataSource:self];
3194 [list_ setSeparatorStyle:1];
3195 [list_ addTableColumn:column];
3196 [list_ setDelegate:self];
3197 [list_ setReusesTableCells:YES];
3201 - (void) setPackage:(Package *)package {
3202 if (package_ != nil) {
3203 [package_ autorelease];
3212 [files_ removeAllObjects];
3214 if (package != nil) {
3215 package_ = [package retain];
3216 name_ = [[package id] retain];
3218 NSString *path = [NSString stringWithFormat:@"/var/lib/dpkg/info/%@.list", name_];
3221 std::ifstream fin([path UTF8String]);
3223 while (std::getline(fin, line))
3224 [files_ addObject:[NSString stringWithUTF8String:line.c_str()]];
3227 if ([files_ count] != 0) {
3228 if ([[files_ objectAtIndex:0] isEqualToString:@"/."])
3229 [files_ removeObjectAtIndex:0];
3230 [files_ sortUsingSelector:@selector(compareByPath:)];
3232 NSMutableArray *stack = [NSMutableArray arrayWithCapacity:8];
3233 [stack addObject:@"/"];
3235 for (int i(0), e([files_ count]); i != e; ++i) {
3236 NSString *file = [files_ objectAtIndex:i];
3237 while (![file hasPrefix:[stack lastObject]])
3238 [stack removeLastObject];
3239 NSString *directory = [stack lastObject];
3240 [stack addObject:[file stringByAppendingString:@"/"]];
3241 [files_ replaceObjectAtIndex:i withObject:[NSString stringWithFormat:@"%*s%@",
3242 ([stack count] - 2) * 3, "",
3243 [file substringFromIndex:[directory length]]
3252 - (void) resetViewAnimated:(BOOL)animated {
3253 [list_ resetViewAnimated:animated];
3256 - (void) reloadData {
3257 [self setPackage:[database_ packageWithName:name_]];
3258 [self reloadButtons];
3261 - (NSString *) title {
3262 return @"Installed Files";
3265 - (NSString *) backButtonTitle {
3271 /* Package View {{{ */
3272 @interface PackageView : BrowserView {
3275 NSMutableArray *buttons_;
3278 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3279 - (void) setPackage:(Package *)package;
3283 @implementation PackageView
3286 if (package_ != nil)
3294 - (void) _clickButtonWithName:(NSString *)name {
3295 if ([name isEqualToString:@"Install"])
3296 [delegate_ installPackage:package_];
3297 else if ([name isEqualToString:@"Reinstall"])
3298 [delegate_ installPackage:package_];
3299 else if ([name isEqualToString:@"Remove"])
3300 [delegate_ removePackage:package_];
3301 else if ([name isEqualToString:@"Upgrade"])
3302 [delegate_ installPackage:package_];
3303 else _assert(false);
3306 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
3307 int count = [buttons_ count];
3308 _assert(count != 0);
3309 _assert(button <= count + 1);
3311 if (count != button - 1)
3312 [self _clickButtonWithName:[buttons_ objectAtIndex:(button - 1)]];
3317 #include "internals.h"
3319 - (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
3320 [[frame windowObject] evaluateWebScript:@"document.base.target = '_top'"];
3321 return [super webView:sender didFinishLoadForFrame:frame];
3324 - (void) webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame {
3325 [window setValue:package_ forKey:@"package"];
3328 - (void) _rightButtonClicked {
3329 /*[super _rightButtonClicked];
3332 int count = [buttons_ count];
3333 _assert(count != 0);
3336 [self _clickButtonWithName:[buttons_ objectAtIndex:0]];
3338 NSMutableArray *buttons = [NSMutableArray arrayWithCapacity:(count + 1)];
3339 [buttons addObjectsFromArray:buttons_];
3340 [buttons addObject:@"Cancel"];
3342 [delegate_ slideUp:[[[UIActionSheet alloc]
3345 defaultButtonIndex:2
3352 - (NSString *) _rightButtonTitle {
3353 int count = [buttons_ count];
3354 return count == 0 ? nil : count != 1 ? @"Modify" : [buttons_ objectAtIndex:0];
3357 - (NSString *) title {
3361 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3362 if ((self = [super initWithBook:book database:database]) != nil) {
3363 database_ = database;
3364 buttons_ = [[NSMutableArray alloc] initWithCapacity:4];
3368 - (void) setPackage:(Package *)package {
3369 if (package_ != nil) {
3370 [package_ autorelease];
3379 [buttons_ removeAllObjects];
3381 if (package != nil) {
3382 package_ = [package retain];
3383 name_ = [[package id] retain];
3385 [self loadURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"package" ofType:@"html"]]];
3387 if ([package_ source] == nil);
3388 else if ([package_ upgradableAndEssential:NO])
3389 [buttons_ addObject:@"Upgrade"];
3390 else if ([package_ installed] == nil)
3391 [buttons_ addObject:@"Install"];
3393 [buttons_ addObject:@"Reinstall"];
3394 if ([package_ installed] != nil)
3395 [buttons_ addObject:@"Remove"];
3399 - (void) reloadData {
3400 [self setPackage:[database_ packageWithName:name_]];
3401 [self reloadButtons];
3406 /* Package Table {{{ */
3407 @interface PackageTable : RVPage {
3408 _transient Database *database_;
3412 NSMutableArray *packages_;
3413 NSMutableArray *sections_;
3414 UISectionList *list_;
3417 - (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object;
3419 - (void) setDelegate:(id)delegate;
3420 - (void) setObject:(id)object;
3422 - (void) reloadData;
3423 - (void) resetCursor;
3425 - (UISectionList *) list;
3427 - (void) setShouldHideHeaderInShortLists:(BOOL)hide;
3431 @implementation PackageTable
3434 [list_ setDataSource:nil];
3439 [packages_ release];
3440 [sections_ release];
3445 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
3446 return [sections_ count];
3449 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
3450 return [[sections_ objectAtIndex:section] name];
3453 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
3454 return [[sections_ objectAtIndex:section] row];
3457 - (int) numberOfRowsInTable:(UITable *)table {
3458 return [packages_ count];
3461 - (float) table:(UITable *)table heightForRow:(int)row {
3462 return [PackageCell heightForPackage:[packages_ objectAtIndex:row]];
3465 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
3467 reusing = [[[PackageCell alloc] init] autorelease];
3468 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
3472 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
3476 - (void) tableRowSelected:(NSNotification *)notification {
3477 int row = [[notification object] selectedRow];
3481 Package *package = [packages_ objectAtIndex:row];
3482 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
3483 [view setDelegate:delegate_];
3484 [view setPackage:package];
3485 [book_ pushPage:view];
3488 - (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object {
3489 if ((self = [super initWithBook:book]) != nil) {
3490 database_ = database;
3491 title_ = [title retain];
3493 object_ = object == nil ? nil : [object retain];
3495 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
3496 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
3498 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:YES];
3499 [list_ setDataSource:self];
3501 UITableColumn *column = [[[UITableColumn alloc]
3502 initWithTitle:@"Name"
3504 width:[self frame].size.width
3507 UITable *table = [list_ table];
3508 [table setSeparatorStyle:1];
3509 [table addTableColumn:column];
3510 [table setDelegate:self];
3511 [table setReusesTableCells:YES];
3513 [self addSubview:list_];
3518 - (void) setDelegate:(id)delegate {
3519 delegate_ = delegate;
3522 - (void) setObject:(id)object {
3528 object_ = [object retain];
3531 - (void) reloadData {
3532 NSArray *packages = [database_ packages];
3534 [packages_ removeAllObjects];
3535 [sections_ removeAllObjects];
3537 for (size_t i(0); i != [packages count]; ++i) {
3538 Package *package([packages objectAtIndex:i]);
3539 if ([package valid] && [[package performSelector:filter_ withObject:object_] boolValue])
3540 [packages_ addObject:package];
3543 Section *section = nil;
3545 for (size_t offset(0); offset != [packages_ count]; ++offset) {
3546 Package *package = [packages_ objectAtIndex:offset];
3547 NSString *name = [package index];
3549 if (section == nil || ![[section name] isEqualToString:name]) {
3550 section = [[[Section alloc] initWithName:name row:offset] autorelease];
3551 [sections_ addObject:section];
3554 [section addToCount];
3560 - (NSString *) title {
3564 - (void) resetViewAnimated:(BOOL)animated {
3565 [list_ resetViewAnimated:animated];
3568 - (void) resetCursor {
3569 [[list_ table] scrollPointVisibleAtTopLeft:CGPointMake(0, 0) animated:NO];
3572 - (UISectionList *) list {
3576 - (void) setShouldHideHeaderInShortLists:(BOOL)hide {
3577 [list_ setShouldHideHeaderInShortLists:hide];
3583 /* Add Source View {{{ */
3584 @interface AddSourceView : RVPage {
3585 _transient Database *database_;
3588 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3592 @implementation AddSourceView
3594 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3595 if ((self = [super initWithBook:book]) != nil) {
3596 database_ = database;
3602 /* Source Cell {{{ */
3603 @interface SourceCell : UITableCell {
3606 NSString *description_;
3612 - (SourceCell *) initWithSource:(Source *)source;
3616 @implementation SourceCell
3621 [description_ release];
3626 - (SourceCell *) initWithSource:(Source *)source {
3627 if ((self = [super init]) != nil) {
3629 icon_ = [UIImage applicationImageNamed:[NSString stringWithFormat:@"Sources/%@.png", [source host]]];
3631 icon_ = [UIImage applicationImageNamed:@"unknown.png"];
3632 icon_ = [icon_ retain];
3634 origin_ = [[source name] retain];
3635 label_ = [[source uri] retain];
3636 description_ = [[source description] retain];
3640 - (void) drawContentInRect:(CGRect)rect selected:(BOOL)selected {
3642 [icon_ drawInRect:CGRectMake(10, 10, 30, 30)];
3649 [origin_ drawAtPoint:CGPointMake(48, 8) forWidth:240 withFont:Font18Bold_ ellipsis:2];
3653 [label_ drawAtPoint:CGPointMake(58, 29) forWidth:225 withFont:Font12_ ellipsis:2];
3657 [description_ drawAtPoint:CGPointMake(12, 46) forWidth:280 withFont:Font14_ ellipsis:2];
3659 [super drawContentInRect:rect selected:selected];
3664 /* Source Table {{{ */
3665 @interface SourceTable : RVPage {
3666 _transient Database *database_;
3667 UISectionList *list_;
3668 NSMutableArray *sources_;
3669 UIActionSheet *alert_;
3673 UIProgressHUD *hud_;
3676 //NSURLConnection *installer_;
3677 NSURLConnection *trivial_bz2_;
3678 NSURLConnection *trivial_gz_;
3679 //NSURLConnection *automatic_;
3684 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3688 @implementation SourceTable
3690 - (void) _deallocConnection:(NSURLConnection *)connection {
3691 if (connection != nil) {
3692 [connection cancel];
3693 //[connection setDelegate:nil];
3694 [connection release];
3699 [[list_ table] setDelegate:nil];
3700 [list_ setDataSource:nil];
3709 //[self _deallocConnection:installer_];
3710 [self _deallocConnection:trivial_gz_];
3711 [self _deallocConnection:trivial_bz2_];
3712 //[self _deallocConnection:automatic_];
3719 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
3720 return offset_ == 0 ? 1 : 2;
3723 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
3724 switch (section + (offset_ == 0 ? 1 : 0)) {
3725 case 0: return @"Entered by User";
3726 case 1: return @"Installed by Packages";
3734 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
3735 switch (section + (offset_ == 0 ? 1 : 0)) {
3737 case 1: return offset_;
3745 - (int) numberOfRowsInTable:(UITable *)table {
3746 return [sources_ count];
3749 - (float) table:(UITable *)table heightForRow:(int)row {
3750 Source *source = [sources_ objectAtIndex:row];
3751 return [source description] == nil ? 56 : 73;
3754 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col {
3755 Source *source = [sources_ objectAtIndex:row];
3756 // XXX: weird warning, stupid selectors ;P
3757 return [[[SourceCell alloc] initWithSource:(id)source] autorelease];
3760 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
3764 - (BOOL) table:(UITable *)table canSelectRow:(int)row {
3768 - (void) tableRowSelected:(NSNotification*)notification {
3769 UITable *table([list_ table]);
3770 int row([table selectedRow]);
3774 Source *source = [sources_ objectAtIndex:row];
3776 PackageTable *packages = [[[PackageTable alloc]
3779 title:[source label]
3780 filter:@selector(isVisibleInSource:)
3784 [packages setDelegate:delegate_];
3786 [book_ pushPage:packages];
3789 - (BOOL) table:(UITable *)table canDeleteRow:(int)row {
3790 Source *source = [sources_ objectAtIndex:row];
3791 return [source record] != nil;
3794 - (void) table:(UITable *)table willSwipeToDeleteRow:(int)row {
3795 [[list_ table] setDeleteConfirmationRow:row];
3798 - (void) table:(UITable *)table deleteRow:(int)row {
3799 Source *source = [sources_ objectAtIndex:row];
3800 [Sources_ removeObjectForKey:[source key]];
3801 [delegate_ syncData];
3804 - (void) _endConnection:(NSURLConnection *)connection {
3805 NSURLConnection **field = NULL;
3806 if (connection == trivial_bz2_)
3807 field = &trivial_bz2_;
3808 else if (connection == trivial_gz_)
3809 field = &trivial_gz_;
3810 _assert(field != NULL);
3811 [connection release];
3815 trivial_bz2_ == nil &&
3818 [delegate_ setStatusBarShowsProgress:NO];
3821 [hud_ removeFromSuperview];
3826 [Sources_ setObject:[NSDictionary dictionaryWithObjectsAndKeys:
3829 @"./", @"Distribution",
3830 nil] forKey:[NSString stringWithFormat:@"deb:%@:./", href_]];
3832 [delegate_ syncData];
3833 } else if (error_ != nil) {
3834 UIActionSheet *sheet = [[[UIActionSheet alloc]
3835 initWithTitle:@"Verification Error"
3836 buttons:[NSArray arrayWithObjects:@"OK", nil]
3837 defaultButtonIndex:0
3842 [sheet setBodyText:[error_ localizedDescription]];
3843 [sheet popupAlertAnimated:YES];
3845 UIActionSheet *sheet = [[[UIActionSheet alloc]
3846 initWithTitle:@"Did not Find Repository"
3847 buttons:[NSArray arrayWithObjects:@"OK", nil]
3848 defaultButtonIndex:0
3853 [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."];
3854 [sheet popupAlertAnimated:YES];
3860 if (error_ != nil) {
3867 - (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response {
3868 switch ([response statusCode]) {
3874 - (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
3875 fprintf(stderr, "connection:\"%s\" didFailWithError:\"%s\"", [href_ UTF8String], [[error localizedDescription] UTF8String]);
3877 error_ = [error retain];
3878 [self _endConnection:connection];
3881 - (void) connectionDidFinishLoading:(NSURLConnection *)connection {
3882 [self _endConnection:connection];
3885 - (NSURLConnection *) _requestHRef:(NSString *)href method:(NSString *)method {
3886 NSMutableURLRequest *request = [NSMutableURLRequest
3887 requestWithURL:[NSURL URLWithString:href]
3888 cachePolicy:NSURLRequestUseProtocolCachePolicy
3889 timeoutInterval:20.0
3892 [request setHTTPMethod:method];
3894 return [[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease];
3897 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
3898 NSString *context = [sheet context];
3899 if ([context isEqualToString:@"source"])
3902 NSString *href = [[sheet textField] text];
3904 //installer_ = [[self _requestHRef:href method:@"GET"] retain];
3906 if (![href hasSuffix:@"/"])
3907 href_ = [href stringByAppendingString:@"/"];
3910 href_ = [href_ retain];
3912 trivial_bz2_ = [[self _requestHRef:[href_ stringByAppendingString:@"Packages.bz2"] method:@"HEAD"] retain];
3913 trivial_gz_ = [[self _requestHRef:[href_ stringByAppendingString:@"Packages.gz"] method:@"HEAD"] retain];
3914 //trivial_bz2_ = [[self _requestHRef:[href stringByAppendingString:@"dists/Release"] method:@"HEAD"] retain];
3918 hud_ = [delegate_ addProgressHUD];
3919 [hud_ setText:@"Verifying URL"];
3932 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3933 if ((self = [super initWithBook:book]) != nil) {
3934 database_ = database;
3935 sources_ = [[NSMutableArray arrayWithCapacity:16] retain];
3937 //list_ = [[UITable alloc] initWithFrame:[self bounds]];
3938 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:NO];
3939 [list_ setShouldHideHeaderInShortLists:NO];
3941 [self addSubview:list_];
3942 [list_ setDataSource:self];
3944 UITableColumn *column = [[UITableColumn alloc]
3945 initWithTitle:@"Name"
3947 width:[self frame].size.width
3950 UITable *table = [list_ table];
3951 [table setSeparatorStyle:1];
3952 [table addTableColumn:column];
3953 [table setDelegate:self];
3959 - (void) reloadData {
3961 _assert(list.ReadMainList());
3963 [sources_ removeAllObjects];
3964 [sources_ addObjectsFromArray:[database_ sources]];
3965 [sources_ sortUsingSelector:@selector(compareByNameAndType:)];
3967 int count = [sources_ count];
3968 for (offset_ = 0; offset_ != count; ++offset_) {
3969 Source *source = [sources_ objectAtIndex:offset_];
3970 if ([source record] == nil)
3977 - (void) resetViewAnimated:(BOOL)animated {
3978 [list_ resetViewAnimated:animated];
3981 - (void) _leftButtonClicked {
3982 /*[book_ pushPage:[[[AddSourceView alloc]
3987 UIActionSheet *sheet = [[[UIActionSheet alloc]
3988 initWithTitle:@"Enter Cydia/APT URL"
3989 buttons:[NSArray arrayWithObjects:@"Add Source", @"Cancel", nil]
3990 defaultButtonIndex:0
3995 [sheet addTextFieldWithValue:@"http://" label:@""];
3997 UITextInputTraits *traits = [[sheet textField] textInputTraits];
3998 [traits setAutocapitalizationType:0];
3999 [traits setKeyboardType:3];
4000 [traits setAutocorrectionType:1];
4002 [sheet popupAlertAnimated:YES];
4005 - (void) _rightButtonClicked {
4006 UITable *table = [list_ table];
4007 BOOL editing = [table isRowDeletionEnabled];
4008 [table enableRowDeletion:!editing animated:YES];
4009 [book_ reloadButtonsForPage:self];
4012 - (NSString *) title {
4016 - (NSString *) backButtonTitle {
4020 - (NSString *) leftButtonTitle {
4021 return [[list_ table] isRowDeletionEnabled] ? @"Add" : nil;
4024 - (NSString *) rightButtonTitle {
4025 return [[list_ table] isRowDeletionEnabled] ? @"Done" : @"Edit";
4028 - (RVUINavBarButtonStyle) rightButtonStyle {
4029 return [[list_ table] isRowDeletionEnabled] ? RVUINavBarButtonStyleHighlighted : RVUINavBarButtonStyleNormal;
4035 /* Installed View {{{ */
4036 @interface InstalledView : RVPage {
4037 _transient Database *database_;
4038 PackageTable *packages_;
4042 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4046 @implementation InstalledView
4049 [packages_ release];
4053 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4054 if ((self = [super initWithBook:book]) != nil) {
4055 database_ = database;
4057 packages_ = [[PackageTable alloc]
4061 filter:@selector(isInstalledAndUnfiltered:)
4062 with:[NSNumber numberWithBool:YES]
4065 [self addSubview:packages_];
4069 - (void) resetViewAnimated:(BOOL)animated {
4070 [packages_ resetViewAnimated:animated];
4073 - (void) reloadData {
4074 [packages_ reloadData];
4077 - (void) _rightButtonClicked {
4078 [packages_ setObject:[NSNumber numberWithBool:expert_]];
4079 [packages_ reloadData];
4081 [book_ reloadButtonsForPage:self];
4084 - (NSString *) title {
4085 return @"Installed";
4088 - (NSString *) backButtonTitle {
4092 - (NSString *) rightButtonTitle {
4093 return Role_ != nil && [Role_ isEqualToString:@"Developer"] ? nil : expert_ ? @"Expert" : @"Simple";
4096 - (RVUINavBarButtonStyle) rightButtonStyle {
4097 return expert_ ? RVUINavBarButtonStyleHighlighted : RVUINavBarButtonStyleNormal;
4100 - (void) setDelegate:(id)delegate {
4101 [super setDelegate:delegate];
4102 [packages_ setDelegate:delegate];
4109 @interface HomeView : BrowserView {
4114 @implementation HomeView
4116 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
4120 - (void) _leftButtonClicked {
4121 UIActionSheet *sheet = [[[UIActionSheet alloc]
4122 initWithTitle:@"About Cydia Installer"
4123 buttons:[NSArray arrayWithObjects:@"Close", nil]
4124 defaultButtonIndex:0
4130 @"Copyright (C) 2008\n"
4131 "Jay Freeman (saurik)\n"
4132 "saurik@saurik.com\n"
4133 "http://www.saurik.com/\n"
4136 "http://www.theokorigroup.com/\n"
4138 "College of Creative Studies,\n"
4139 "University of California,\n"
4141 "http://www.ccs.ucsb.edu/"
4144 [sheet popupAlertAnimated:YES];
4147 - (NSString *) leftButtonTitle {
4153 /* Manage View {{{ */
4154 @interface ManageView : BrowserView {
4159 @implementation ManageView
4161 - (NSString *) title {
4165 - (void) _leftButtonClicked {
4166 [delegate_ askForSettings];
4169 - (NSString *) leftButtonTitle {
4173 - (NSString *) _rightButtonTitle {
4180 /* Browser Implementation {{{ */
4181 @implementation BrowserView
4184 WebView *webview = [webview_ webView];
4185 [webview setFrameLoadDelegate:nil];
4186 [webview setResourceLoadDelegate:nil];
4187 [webview setUIDelegate:nil];
4189 [scroller_ setDelegate:nil];
4190 [webview_ setDelegate:nil];
4192 [scroller_ release];
4195 [indicator_ release];
4201 - (void) loadURL:(NSURL *)url cachePolicy:(NSURLRequestCachePolicy)policy {
4202 [self loadRequest:[NSURLRequest
4205 timeoutInterval:30.0
4209 - (void) loadURL:(NSURL *)url {
4210 [self loadURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy];
4213 - (NSURLRequest *) _addHeadersToRequest:(NSURLRequest *)request {
4214 NSMutableURLRequest *copy = [request mutableCopy];
4216 [copy addValue:[NSString stringWithUTF8String:Firmware_] forHTTPHeaderField:@"X-Firmware"];
4217 [copy addValue:[NSString stringWithUTF8String:Machine_] forHTTPHeaderField:@"X-Machine"];
4218 [copy addValue:[NSString stringWithUTF8String:SerialNumber_] forHTTPHeaderField:@"X-Serial-Number"];
4221 [copy addValue:Role_ forHTTPHeaderField:@"X-Role"];
4226 - (void) loadRequest:(NSURLRequest *)request {
4228 [webview_ loadRequest:request];
4231 - (void) reloadURL {
4232 NSURL *url = [[[urls_ lastObject] retain] autorelease];
4233 [urls_ removeLastObject];
4234 [self loadURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData];
4237 - (WebView *) webView {
4238 return [webview_ webView];
4241 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame {
4242 [scroller_ setContentSize:frame.size];
4245 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old {
4246 [self view:sender didSetFrame:frame];
4249 - (void) pushPage:(RVPage *)page {
4250 [self setBackButtonTitle:title_];
4251 [page setDelegate:delegate_];
4252 [book_ pushPage:page];
4255 - (void) getSpecial:(NSString *)href {
4258 if ([href hasPrefix:@"mailto:"])
4259 [delegate_ openURL:[NSURL URLWithString:href]];
4260 else if ([href isEqualToString:@"cydia://add-source"])
4261 page = [[[AddSourceView alloc] initWithBook:book_ database:database_] autorelease];
4262 else if ([href isEqualToString:@"cydia://sources"])
4263 page = [[[SourceTable alloc] initWithBook:book_ database:database_] autorelease];
4264 else if ([href isEqualToString:@"cydia://packages"])
4265 page = [[[InstalledView alloc] initWithBook:book_ database:database_] autorelease];
4266 else if ([href hasPrefix:@"cydia://files/"]) {
4267 NSString *name = [href substringFromIndex:14];
4269 if (Package *package = [database_ packageWithName:name]) {
4270 FileTable *files = [[[FileTable alloc] initWithBook:book_ database:database_] autorelease];
4271 [files setPackage:package];
4274 } else if ([href hasPrefix:@"apptapp://package/"]) {
4275 NSString *name = [href substringFromIndex:18];
4277 if (Package *package = [database_ packageWithName:name]) {
4278 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
4279 [view setPackage:package];
4282 UIActionSheet *sheet = [[[UIActionSheet alloc]
4283 initWithTitle:@"Cannot Locate Package"
4284 buttons:[NSArray arrayWithObjects:@"Close", nil]
4285 defaultButtonIndex:0
4290 [sheet setBodyText:[NSString stringWithFormat:
4291 @"The package %@ cannot be found in your current sources. I might recommend installing more sources."
4294 [sheet popupAlertAnimated:YES];
4299 [self pushPage:page];
4302 - (void) webView:(WebView *)sender willClickElement:(id)element {
4303 if ([[element localName] isEqualToString:@"img"])
4304 do if ((element = [element parentNode]) == nil)
4306 while (![[element localName] isEqualToString:@"a"]);
4307 if (![element respondsToSelector:@selector(href)])
4309 NSString *href = [element href];
4312 [self getSpecial:href];
4315 - (BOOL) isSpecialScheme:(NSString *)scheme {
4317 [scheme isEqualToString:@"apptapp"] ||
4318 [scheme isEqualToString:@"cydia"] ||
4319 [scheme isEqualToString:@"mailto"];
4322 - (NSURLRequest *) webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource {
4323 NSURL *url = [request URL];
4324 if ([self isSpecialScheme:[url scheme]]) {
4325 [self getSpecial:[url absoluteString]];
4331 [book_ pushPage:self];
4334 return [self _addHeadersToRequest:request];
4337 - (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request {
4338 if (request != nil) {
4339 NSString *scheme = [[request URL] scheme];
4340 if ([self isSpecialScheme:scheme])
4344 [self setBackButtonTitle:title_];
4346 BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease];
4347 [browser setDelegate:delegate_];
4349 if (request != nil) {
4350 [browser loadRequest:[self _addHeadersToRequest:request]];
4351 [book_ pushPage:browser];
4354 return [browser webView];
4357 - (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame {
4358 if ([frame parentFrame] != nil)
4361 title_ = [title retain];
4362 [self setTitle:title];
4365 - (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame {
4366 if ([frame parentFrame] != nil)
4371 [indicator_ startAnimation];
4372 [self reloadButtons];
4374 if (title_ != nil) {
4379 [self setTitle:@"Loading..."];
4381 WebView *webview = [webview_ webView];
4382 NSString *href = [webview mainFrameURL];
4383 [urls_ addObject:[NSURL URLWithString:href]];
4385 CGRect webrect = [scroller_ bounds];
4386 webrect.size.height = 0;
4387 [webview_ setFrame:webrect];
4390 - (void) _finishLoading {
4393 [indicator_ stopAnimation];
4394 [self reloadButtons];
4398 - (BOOL) webView:(WebView *)sender shouldScrollToPoint:(struct CGPoint)point forFrame:(WebFrame *)frame {
4400 return [webview_ webView:sender shouldScrollToPoint:point forFrame:frame];
4403 - (void) webView:(WebView *)sender didReceiveViewportArguments:(id)arguments forFrame:(WebFrame *)frame {
4404 return [webview_ webView:sender didReceiveViewportArguments:arguments forFrame:frame];
4407 - (void) webView:(WebView *)sender needsScrollNotifications:(id)notifications forFrame:(WebFrame *)frame {
4408 return [webview_ webView:sender needsScrollNotifications:notifications forFrame:frame];
4411 - (void) webView:(WebView *)sender didCommitLoadForFrame:(WebFrame *)frame {
4412 return [webview_ webView:sender didCommitLoadForFrame:frame];
4415 - (void) webView:(WebView *)sender didReceiveDocTypeForFrame:(WebFrame *)frame {
4416 return [webview_ webView:sender didReceiveDocTypeForFrame:frame];
4419 - (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
4420 if ([frame parentFrame] == nil)
4421 [self _finishLoading];
4422 return [webview_ webView:sender didFinishLoadForFrame:frame];
4425 - (void) webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
4426 if ([frame parentFrame] != nil)
4428 [self _finishLoading];
4430 [self loadURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@?%@",
4431 [[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"error" ofType:@"html"]] absoluteString],
4432 [[error localizedDescription] stringByAddingPercentEscapes]
4436 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4437 if ((self = [super initWithBook:book]) != nil) {
4438 database_ = database;
4441 struct CGRect bounds = [self bounds];
4443 UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:bounds] autorelease];
4444 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
4445 [self addSubview:pinstripe];
4447 scroller_ = [[UIScroller alloc] initWithFrame:bounds];
4448 [self addSubview:scroller_];
4450 [scroller_ setScrollingEnabled:YES];
4451 [scroller_ setAdjustForContentSizeChange:YES];
4452 [scroller_ setClipsSubviews:YES];
4453 [scroller_ setAllowsRubberBanding:YES];
4454 [scroller_ setScrollDecelerationFactor:0.99];
4455 [scroller_ setDelegate:self];
4457 CGRect webrect = [scroller_ bounds];
4458 webrect.size.height = 0;
4460 webview_ = [[UIWebView alloc] initWithFrame:webrect];
4461 [scroller_ addSubview:webview_];
4463 [webview_ setTileSize:CGSizeMake(webrect.size.width, 500)];
4465 [webview_ setTilingEnabled:YES];
4466 [webview_ setTileMinificationFilter:kCAFilterNearest];
4467 [webview_ setAutoresizes:YES];
4469 [webview_ setViewportSize:CGSizeMake(980, -1) forDocumentTypes:0x10];
4470 [webview_ setViewportSize:CGSizeMake(320, -1) forDocumentTypes:0x2];
4471 [webview_ setViewportSize:CGSizeMake(320, -1) forDocumentTypes:0x8];
4473 [webview_ _setDocumentType:0x4];
4475 [webview_ setZoomsFocusedFormControl:YES];
4476 [webview_ setContentsPosition:7];
4477 [webview_ setEnabledGestures:0xa];
4478 [webview_ setValue:[NSNumber numberWithBool:YES] forGestureAttribute:0x4];
4479 [webview_ setValue:[NSNumber numberWithBool:YES] forGestureAttribute:0x7];
4480 [webview_ setDelegate:self];
4481 [webview_ setGestureDelegate:self];
4482 [webview_ setSmoothsFonts:YES];
4484 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:kUIProgressIndicatorStyleMediumWhite];
4485 indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(281, 42, indsize.width, indsize.height)];
4486 [indicator_ setStyle:kUIProgressIndicatorStyleMediumWhite];
4488 Package *package([database_ packageWithName:@"cydia"]);
4489 NSString *application = package == nil ? @"Cydia" : [NSString
4490 stringWithFormat:@"Cydia/%@",
4494 WebView *webview = [webview_ webView];
4495 [webview setApplicationNameForUserAgent:application];
4496 [webview setFrameLoadDelegate:self];
4497 [webview setResourceLoadDelegate:self];
4498 [webview setUIDelegate:self];
4500 //[webview _setLayoutInterval:0.5];
4502 urls_ = [[NSMutableArray alloc] initWithCapacity:16];
4506 - (void) didFinishGesturesInView:(UIView *)view forEvent:(id)event {
4507 [webview_ redrawScaledDocument];
4510 - (void) _rightButtonClicked {
4515 - (NSString *) _rightButtonTitle {
4519 - (NSString *) rightButtonTitle {
4520 return loading_ ? @"" : [self _rightButtonTitle];
4523 - (NSString *) title {
4527 - (NSString *) backButtonTitle {
4531 - (void) setPageActive:(BOOL)active {
4533 [book_ addSubview:indicator_];
4535 [indicator_ removeFromSuperview];
4538 - (void) resetViewAnimated:(BOOL)animated {
4541 - (void) setPushed:(bool)pushed {
4548 @interface CYBook : RVBook <
4551 _transient Database *database_;
4553 UIProgressIndicator *indicator_;
4554 UITextLabel *prompt_;
4555 UIProgressBar *progress_;
4559 - (id) initWithFrame:(CGRect)frame database:(Database *)database;
4565 /* Install View {{{ */
4566 @interface InstallView : RVPage {
4567 _transient Database *database_;
4568 NSMutableArray *sections_;
4569 NSMutableArray *filtered_;
4570 UITransitionView *transition_;
4576 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4577 - (void) reloadData;
4582 @implementation InstallView
4585 [list_ setDataSource:nil];
4586 [list_ setDelegate:nil];
4588 [sections_ release];
4589 [filtered_ release];
4590 [transition_ release];
4592 [accessory_ release];
4596 - (int) numberOfRowsInTable:(UITable *)table {
4597 return editing_ ? [sections_ count] : [filtered_ count] + 1;
4600 - (float) table:(UITable *)table heightForRow:(int)row {
4604 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
4606 reusing = [[[SectionCell alloc] init] autorelease];
4607 [(SectionCell *)reusing setSection:(editing_ ?
4608 [sections_ objectAtIndex:row] :
4609 (row == 0 ? nil : [filtered_ objectAtIndex:(row - 1)])
4610 ) editing:editing_];
4614 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
4618 - (BOOL) table:(UITable *)table canSelectRow:(int)row {
4622 - (void) tableRowSelected:(NSNotification *)notification {
4623 int row = [[notification object] selectedRow];
4634 title = @"All Packages";
4636 section = [filtered_ objectAtIndex:(row - 1)];
4637 name = [section name];
4643 title = @"(No Section)";
4647 PackageTable *table = [[[PackageTable alloc]
4651 filter:@selector(isVisiblyUninstalledInSection:)
4655 [table setDelegate:delegate_];
4657 [book_ pushPage:table];
4660 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4661 if ((self = [super initWithBook:book]) != nil) {
4662 database_ = database;
4664 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
4665 filtered_ = [[NSMutableArray arrayWithCapacity:16] retain];
4667 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
4668 [self addSubview:transition_];
4670 list_ = [[UITable alloc] initWithFrame:[transition_ bounds]];
4671 [transition_ transition:0 toView:list_];
4673 UITableColumn *column = [[[UITableColumn alloc]
4674 initWithTitle:@"Name"
4676 width:[self frame].size.width
4679 [list_ setDataSource:self];
4680 [list_ setSeparatorStyle:1];
4681 [list_ addTableColumn:column];
4682 [list_ setDelegate:self];
4683 [list_ setReusesTableCells:YES];
4689 - (void) reloadData {
4690 NSArray *packages = [database_ packages];
4692 [sections_ removeAllObjects];
4693 [filtered_ removeAllObjects];
4695 NSMutableArray *filtered = [NSMutableArray arrayWithCapacity:[packages count]];
4696 NSMutableDictionary *sections = [NSMutableDictionary dictionaryWithCapacity:32];
4698 for (size_t i(0); i != [packages count]; ++i) {
4699 Package *package([packages objectAtIndex:i]);
4700 NSString *name([package section]);
4703 Section *section([sections objectForKey:name]);
4704 if (section == nil) {
4705 section = [[[Section alloc] initWithName:name] autorelease];
4706 [sections setObject:section forKey:name];
4710 if ([package valid] && [package installed] == nil && [package visible])
4711 [filtered addObject:package];
4714 [sections_ addObjectsFromArray:[sections allValues]];
4715 [sections_ sortUsingSelector:@selector(compareByName:)];
4717 [filtered sortUsingSelector:@selector(compareBySection:)];
4719 Section *section = nil;
4720 for (size_t offset = 0, count = [filtered count]; offset != count; ++offset) {
4721 Package *package = [filtered objectAtIndex:offset];
4722 NSString *name = [package section];
4724 if (section == nil || name != nil && ![[section name] isEqualToString:name]) {
4725 section = name == nil ?
4726 [[[Section alloc] initWithName:nil] autorelease] :
4727 [sections objectForKey:name];
4728 [filtered_ addObject:section];
4731 [section addToCount];
4737 - (void) resetView {
4739 [self _rightButtonClicked];
4742 - (void) resetViewAnimated:(BOOL)animated {
4743 [list_ resetViewAnimated:animated];
4746 - (void) _rightButtonClicked {
4747 if ((editing_ = !editing_))
4750 [delegate_ updateData];
4753 [book_ setTitle:[self title] forPage:self];
4754 [book_ reloadButtonsForPage:self];
4757 - (NSString *) title {
4758 return editing_ ? @"Section Visibility" : @"Install by Section";
4761 - (NSString *) backButtonTitle {
4765 - (NSString *) rightButtonTitle {
4766 return [sections_ count] == 0 ? nil : editing_ ? @"Done" : @"Edit";
4769 - (UIView *) accessoryView {
4775 /* Changes View {{{ */
4776 @interface ChangesView : RVPage {
4777 _transient Database *database_;
4778 NSMutableArray *packages_;
4779 NSMutableArray *sections_;
4780 UISectionList *list_;
4784 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4785 - (void) reloadData;
4789 @implementation ChangesView
4792 [[list_ table] setDelegate:nil];
4793 [list_ setDataSource:nil];
4795 [packages_ release];
4796 [sections_ release];
4801 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
4802 return [sections_ count];
4805 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
4806 return [[sections_ objectAtIndex:section] name];
4809 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
4810 return [[sections_ objectAtIndex:section] row];
4813 - (int) numberOfRowsInTable:(UITable *)table {
4814 return [packages_ count];
4817 - (float) table:(UITable *)table heightForRow:(int)row {
4818 return [PackageCell heightForPackage:[packages_ objectAtIndex:row]];
4821 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
4823 reusing = [[[PackageCell alloc] init] autorelease];
4824 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
4828 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
4832 - (void) tableRowSelected:(NSNotification *)notification {
4833 int row = [[notification object] selectedRow];
4836 Package *package = [packages_ objectAtIndex:row];
4837 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
4838 [view setDelegate:delegate_];
4839 [view setPackage:package];
4840 [book_ pushPage:view];
4843 - (void) _leftButtonClicked {
4844 [(CYBook *)book_ update];
4845 [self reloadButtons];
4848 - (void) _rightButtonClicked {
4849 [delegate_ distUpgrade];
4852 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4853 if ((self = [super initWithBook:book]) != nil) {
4854 database_ = database;
4856 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
4857 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
4859 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:NO];
4860 [self addSubview:list_];
4862 [list_ setShouldHideHeaderInShortLists:NO];
4863 [list_ setDataSource:self];
4864 //[list_ setSectionListStyle:1];
4866 UITableColumn *column = [[[UITableColumn alloc]
4867 initWithTitle:@"Name"
4869 width:[self frame].size.width
4872 UITable *table = [list_ table];
4873 [table setSeparatorStyle:1];
4874 [table addTableColumn:column];
4875 [table setDelegate:self];
4876 [table setReusesTableCells:YES];
4882 - (void) reloadData {
4883 NSArray *packages = [database_ packages];
4885 [packages_ removeAllObjects];
4886 [sections_ removeAllObjects];
4888 for (size_t i(0); i != [packages count]; ++i) {
4889 Package *package([packages objectAtIndex:i]);
4892 [package installed] == nil && [package valid] && [package visible] ||
4893 [package upgradableAndEssential:NO]
4895 [packages_ addObject:package];
4898 [packages_ sortUsingSelector:@selector(compareForChanges:)];
4900 Section *upgradable = [[[Section alloc] initWithName:@"Available Upgrades"] autorelease];
4901 Section *section = nil;
4904 bool unseens = false;
4906 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, Locale_, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
4908 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
4909 Package *package = [packages_ objectAtIndex:offset];
4911 if ([package upgradableAndEssential:YES]) {
4913 [upgradable addToCount];
4916 NSDate *seen = [package seen];
4921 name = [@"n/a ?" retain];
4923 name = (NSString *) CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen);
4926 if (section == nil || ![[section name] isEqualToString:name]) {
4927 section = [[[Section alloc] initWithName:name row:offset] autorelease];
4928 [sections_ addObject:section];
4932 [section addToCount];
4936 CFRelease(formatter);
4939 Section *last = [sections_ lastObject];
4940 size_t count = [last count];
4941 [packages_ removeObjectsInRange:NSMakeRange([packages_ count] - count, count)];
4942 [sections_ removeLastObject];
4946 [sections_ insertObject:upgradable atIndex:0];
4949 [self reloadButtons];
4952 - (void) resetViewAnimated:(BOOL)animated {
4953 [list_ resetViewAnimated:animated];
4956 - (NSString *) leftButtonTitle {
4957 return [(CYBook *)book_ updating] ? nil : @"Refresh";
4960 - (NSString *) rightButtonTitle {
4961 return upgrades_ == 0 ? nil : [NSString stringWithFormat:@"Upgrade (%u)", upgrades_];
4964 - (NSString *) title {
4970 /* Search View {{{ */
4971 @protocol SearchViewDelegate
4972 - (void) showKeyboard:(BOOL)show;
4975 @interface SearchView : RVPage {
4977 UISearchField *field_;
4978 UITransitionView *transition_;
4979 PackageTable *table_;
4980 UIPreferencesTable *advanced_;
4986 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4987 - (void) reloadData;
4991 @implementation SearchView
4995 [[field_ textTraits] setEditingDelegate:nil];
4997 [field_ setDelegate:nil];
4999 [accessory_ release];
5001 [transition_ release];
5003 [advanced_ release];
5008 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
5012 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
5014 case 0: return @"Advanced Search (Coming Soon!)";
5016 default: _assert(false);
5020 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
5024 default: _assert(false);
5028 - (void) _showKeyboard:(BOOL)show {
5029 CGSize keysize = [UIKeyboard defaultSize];
5030 CGRect keydown = [book_ pageBounds];
5031 CGRect keyup = keydown;
5032 keyup.size.height -= keysize.height - ButtonBarHeight_;
5034 float delay = KeyboardTime_ * ButtonBarHeight_ / keysize.height;
5036 UIFrameAnimation *animation = [[[UIFrameAnimation alloc] initWithTarget:[table_ list]] autorelease];
5037 [animation setSignificantRectFields:8];
5040 [animation setStartFrame:keydown];
5041 [animation setEndFrame:keyup];
5043 [animation setStartFrame:keyup];
5044 [animation setEndFrame:keydown];
5047 UIAnimator *animator = [UIAnimator sharedAnimator];
5050 addAnimations:[NSArray arrayWithObjects:animation, nil]
5051 withDuration:(KeyboardTime_ - delay)
5056 [animator performSelector:@selector(startAnimation:) withObject:animation afterDelay:delay];
5059 [delegate_ showKeyboard:show];
5063 - (void) textFieldDidBecomeFirstResponder:(UITextField *)field {
5064 [self _showKeyboard:YES];
5067 - (void) textFieldDidResignFirstResponder:(UITextField *)field {
5068 [self _showKeyboard:NO];
5071 - (void) keyboardInputChanged:(UIFieldEditor *)editor {
5073 NSString *text([field_ text]);
5074 [field_ setClearButtonStyle:(text == nil || [text length] == 0 ? 0 : 2)];
5080 - (void) textFieldClearButtonPressed:(UITextField *)field {
5084 - (void) keyboardInputShouldDelete:(id)input {
5088 - (BOOL) keyboardInput:(id)input shouldInsertText:(NSString *)text isMarkedText:(int)marked {
5089 if ([text length] != 1 || [text characterAtIndex:0] != '\n') {
5093 [field_ resignFirstResponder];
5098 - (id) initWithBook:(RVBook *)book database:(Database *)database {
5099 if ((self = [super initWithBook:book]) != nil) {
5100 CGRect pageBounds = [book_ pageBounds];
5102 /*UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:pageBounds] autorelease];
5103 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
5104 [self addSubview:pinstripe];*/
5106 transition_ = [[UITransitionView alloc] initWithFrame:pageBounds];
5107 [self addSubview:transition_];
5109 advanced_ = [[UIPreferencesTable alloc] initWithFrame:pageBounds];
5111 [advanced_ setReusesTableCells:YES];
5112 [advanced_ setDataSource:self];
5113 [advanced_ reloadData];
5115 dimmed_ = [[UIView alloc] initWithFrame:pageBounds];
5116 CGColor dimmed(space_, 0, 0, 0, 0.5);
5117 [dimmed_ setBackgroundColor:[UIColor colorWithCGColor:dimmed]];
5119 table_ = [[PackageTable alloc]
5123 filter:@selector(isUnfilteredAndSearchedForBy:)
5127 [table_ setShouldHideHeaderInShortLists:NO];
5128 [transition_ transition:0 toView:table_];
5137 area.origin.x = /*cnfrect.origin.x + cnfrect.size.width + 4 +*/ 10;
5144 [self bounds].size.width - area.origin.x - 18;
5146 area.size.height = [UISearchField defaultHeight];
5148 field_ = [[UISearchField alloc] initWithFrame:area];
5150 UIFont *font = [UIFont systemFontOfSize:16];
5151 [field_ setFont:font];
5153 [field_ setPlaceholder:@"Package Names & Descriptions"];
5154 [field_ setDelegate:self];
5156 [field_ setPaddingTop:3];
5158 UITextInputTraits *traits = [field_ textInputTraits];
5159 [traits setAutocapitalizationType:0];
5160 [traits setAutocorrectionType:1];
5161 [traits setReturnKeyType:6];
5163 CGRect accrect = {{0, 6}, {6 + cnfrect.size.width + 6 + area.size.width + 6, area.size.height + 30}};
5165 accessory_ = [[UIView alloc] initWithFrame:accrect];
5166 [accessory_ addSubview:field_];
5168 /*UIPushButton *configure = [[[UIPushButton alloc] initWithFrame:cnfrect] autorelease];
5169 [configure setShowPressFeedback:YES];
5170 [configure setImage:[UIImage applicationImageNamed:@"advanced.png"]];
5171 [configure addTarget:self action:@selector(configurePushed) forEvents:1];
5172 [accessory_ addSubview:configure];*/
5178 LKAnimation *animation = [LKTransition animation];
5179 [animation setType:@"oglFlip"];
5180 [animation setTimingFunction:[LKTimingFunction functionWithName:@"easeInEaseOut"]];
5181 [animation setFillMode:@"extended"];
5182 [animation setTransitionFlags:3];
5183 [animation setDuration:10];
5184 [animation setSpeed:0.35];
5185 [animation setSubtype:(flipped_ ? @"fromLeft" : @"fromRight")];
5186 [[transition_ _layer] addAnimation:animation forKey:0];
5187 [transition_ transition:0 toView:(flipped_ ? (UIView *) table_ : (UIView *) advanced_)];
5188 flipped_ = !flipped_;
5192 - (void) configurePushed {
5193 [field_ resignFirstResponder];
5197 - (void) resetViewAnimated:(BOOL)animated {
5200 [table_ resetViewAnimated:animated];
5203 - (void) reloadData {
5206 [table_ setObject:[field_ text]];
5207 [table_ reloadData];
5208 [table_ resetCursor];
5211 - (UIView *) accessoryView {
5215 - (NSString *) title {
5219 - (NSString *) backButtonTitle {
5223 - (void) setDelegate:(id)delegate {
5224 [table_ setDelegate:delegate];
5225 [super setDelegate:delegate];
5231 @implementation CYBook
5235 [indicator_ release];
5237 [progress_ release];
5241 - (NSString *) getTitleForPage:(RVPage *)page {
5242 return Simplify([super getTitleForPage:page]);
5250 [navbar_ setPrompt:@""];
5251 [navbar_ addSubview:overlay_];
5252 [indicator_ startAnimation];
5253 [prompt_ setText:@"Updating Database..."];
5254 [progress_ setProgress:0];
5259 detachNewThreadSelector:@selector(_update)
5268 [overlay_ removeFromSuperview];
5269 [indicator_ stopAnimation];
5270 [delegate_ reloadData];
5272 [self setPrompt:[NSString stringWithFormat:@"Last Updated: %@", GetLastUpdate()]];
5275 - (id) initWithFrame:(CGRect)frame database:(Database *)database {
5276 if ((self = [super initWithFrame:frame]) != nil) {
5277 database_ = database;
5279 CGRect ovrrect = [navbar_ bounds];
5280 ovrrect.size.height = ([UINavigationBar defaultSizeWithPrompt].height - [UINavigationBar defaultSize].height);
5282 overlay_ = [[UIView alloc] initWithFrame:ovrrect];
5284 bool ugly = [navbar_ _barStyle:NO] == 0;
5286 UIProgressIndicatorStyle style = ugly ?
5287 kUIProgressIndicatorStyleSmallBlack :
5288 kUIProgressIndicatorStyleSmallWhite;
5290 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:style];
5291 unsigned indoffset = (ovrrect.size.height - indsize.height) / 2;
5292 CGRect indrect = {{indoffset, indoffset}, indsize};
5294 indicator_ = [[UIProgressIndicator alloc] initWithFrame:indrect];
5295 [indicator_ setStyle:style];
5296 [overlay_ addSubview:indicator_];
5298 CGSize prmsize = {200, indsize.width + 4};
5301 indoffset * 2 + indsize.width,
5305 (ovrrect.size.height - prmsize.height) / 2
5308 UIFont *font = [UIFont systemFontOfSize:12];
5310 prompt_ = [[UITextLabel alloc] initWithFrame:prmrect];
5312 [prompt_ setColor:[UIColor colorWithCGColor:(ugly ? Blueish_ : White_)]];
5313 [prompt_ setBackgroundColor:[UIColor colorWithCGColor:Clear_]];
5314 [prompt_ setFont:font];
5316 [overlay_ addSubview:prompt_];
5318 CGSize prgsize = {75, 100};
5321 ovrrect.size.width - prgsize.width - 10,
5322 (ovrrect.size.height - prgsize.height) / 2
5325 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
5326 [progress_ setStyle:0];
5327 [overlay_ addSubview:progress_];
5332 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5335 status.setDelegate(self);
5337 [database_ updateWithStatus:status];
5340 performSelectorOnMainThread:@selector(_update_)
5348 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id {
5349 [prompt_ setText:[NSString stringWithFormat:@"Error: %@", error]];
5352 - (void) setProgressTitle:(NSString *)title {
5354 performSelectorOnMainThread:@selector(_setProgressTitle:)
5360 - (void) setProgressPercent:(float)percent {
5363 - (void) addProgressOutput:(NSString *)output {
5365 performSelectorOnMainThread:@selector(_addProgressOutput:)
5371 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
5375 - (void) _setProgressTitle:(NSString *)title {
5376 [prompt_ setText:[title stringByAppendingString:@"..."]];
5379 - (void) _addProgressOutput:(NSString *)output {
5384 @interface Cydia : UIApplication <
5385 ConfirmationViewDelegate,
5386 ProgressViewDelegate,
5395 UIToolbar *buttonbar_;
5397 ConfirmationView *confirm_;
5399 NSMutableArray *essential_;
5400 NSMutableArray *broken_;
5402 Database *database_;
5403 ProgressView *progress_;
5407 UIKeyboard *keyboard_;
5408 UIProgressHUD *hud_;
5410 InstallView *install_;
5411 ChangesView *changes_;
5412 ManageView *manage_;
5413 SearchView *search_;
5418 @implementation Cydia
5421 if ([broken_ count] != 0) {
5422 int count = [broken_ count];
5424 UIActionSheet *sheet = [[[UIActionSheet alloc]
5425 initWithTitle:[NSString stringWithFormat:@"%d Half-Installed Package%@", count, (count == 1 ? @"" : @"s")]
5426 buttons:[NSArray arrayWithObjects:
5428 @"Ignore (Temporary)",
5430 defaultButtonIndex:0
5435 [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."];
5436 [sheet popupAlertAnimated:YES];
5437 } else if (!Ignored_ && [essential_ count] != 0) {
5438 int count = [essential_ count];
5440 UIActionSheet *sheet = [[[UIActionSheet alloc]
5441 initWithTitle:[NSString stringWithFormat:@"%d Essential Upgrade%@", count, (count == 1 ? @"" : @"s")]
5442 buttons:[NSArray arrayWithObjects:@"Upgrade Essential", @"Ignore (Temporary)", nil]
5443 defaultButtonIndex:0
5448 [sheet setBodyText:@"One or more essential packages are currently out of date. If these upgrades are not performed you are likely to encounter errors."];
5449 [sheet popupAlertAnimated:YES];
5453 - (void) _reloadData {
5454 /*UIProgressHUD *hud = [[UIProgressHUD alloc] initWithWindow:window_];
5455 [hud setText:@"Reloading Data"];
5456 [overlay_ addSubview:hud];
5459 [database_ reloadData];
5463 [essential_ removeAllObjects];
5464 [broken_ removeAllObjects];
5466 NSArray *packages = [database_ packages];
5467 for (int i(0), e([packages count]); i != e; ++i) {
5468 Package *package = [packages objectAtIndex:i];
5470 [broken_ addObject:package];
5471 if ([package upgradableAndEssential:NO]) {
5472 if ([package essential])
5473 [essential_ addObject:package];
5479 NSString *badge([[NSNumber numberWithInt:changes] stringValue]);
5480 [buttonbar_ setBadgeValue:badge forButton:3];
5481 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
5482 [buttonbar_ setBadgeAnimated:YES forButton:3];
5483 [self setApplicationBadge:badge];
5485 [buttonbar_ setBadgeValue:nil forButton:3];
5486 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
5487 [buttonbar_ setBadgeAnimated:NO forButton:3];
5488 [self removeApplicationBadge];
5493 if ([packages count] == 0);
5502 [hud removeFromSuperview];*/
5505 - (void) _saveConfig {
5507 _assert([Metadata_ writeToFile:@"/var/lib/cydia/metadata.plist" atomically:YES] == YES);
5512 - (void) updateData {
5515 /* XXX: this is just stupid */
5517 [install_ reloadData];
5519 [changes_ reloadData];
5521 [search_ reloadData];
5531 FILE *file = fopen("/etc/apt/sources.list.d/cydia.list", "w");
5532 _assert(file != NULL);
5534 NSArray *keys = [Sources_ allKeys];
5536 for (int i(0), e([keys count]); i != e; ++i) {
5537 NSString *key = [keys objectAtIndex:i];
5538 NSDictionary *source = [Sources_ objectForKey:key];
5540 fprintf(file, "%s %s %s\n",
5541 [[source objectForKey:@"Type"] UTF8String],
5542 [[source objectForKey:@"URI"] UTF8String],
5543 [[source objectForKey:@"Distribution"] UTF8String]
5552 detachNewThreadSelector:@selector(update_)
5555 title:@"Updating Sources..."
5559 - (void) reloadData {
5560 @synchronized (self) {
5561 if (confirm_ == nil)
5567 pkgProblemResolver *resolver = [database_ resolver];
5569 resolver->InstallProtect();
5570 if (!resolver->Resolve(true))
5575 [database_ prepare];
5577 if ([database_ cache]->BrokenCount() == 0)
5578 confirm_ = [[ConfirmationView alloc] initWithView:underlay_ database:database_ delegate:self];
5580 NSMutableArray *broken = [NSMutableArray arrayWithCapacity:16];
5581 NSArray *packages = [database_ packages];
5583 for (size_t i(0); i != [packages count]; ++i) {
5584 Package *package = [packages objectAtIndex:i];
5585 if ([package broken])
5586 [broken addObject:[package name]];
5589 UIActionSheet *sheet = [[[UIActionSheet alloc]
5590 initWithTitle:[NSString stringWithFormat:@"%d Broken Packages", [database_ cache]->BrokenCount()]
5591 buttons:[NSArray arrayWithObjects:@"Okay", nil]
5592 defaultButtonIndex:0
5597 [sheet setBodyText:[NSString stringWithFormat:@"The following packages have unmet dependencies:\n\n%@", [broken componentsJoinedByString:@"\n"]]];
5598 [sheet popupAlertAnimated:YES];
5604 - (void) installPackage:(Package *)package {
5605 @synchronized (self) {
5612 - (void) removePackage:(Package *)package {
5613 @synchronized (self) {
5620 - (void) distUpgrade {
5621 @synchronized (self) {
5622 [database_ upgrade];
5628 @synchronized (self) {
5636 [overlay_ removeFromSuperview];
5640 detachNewThreadSelector:@selector(perform)
5647 - (void) bootstrap_ {
5649 [database_ upgrade];
5650 [database_ prepare];
5651 [database_ perform];
5654 - (void) bootstrap {
5656 detachNewThreadSelector:@selector(bootstrap_)
5659 title:@"Bootstrap Install..."
5663 - (void) progressViewIsComplete:(ProgressView *)progress {
5664 @synchronized (self) {
5667 if (confirm_ != nil) {
5668 [underlay_ addSubview:overlay_];
5669 [confirm_ removeFromSuperview];
5676 - (void) setPage:(RVPage *)page {
5677 [page resetViewAnimated:NO];
5678 [page setDelegate:self];
5679 [book_ setPage:page];
5682 - (RVPage *) _pageForURL:(NSURL *)url withClass:(Class)_class {
5683 BrowserView *browser = [[[_class alloc] initWithBook:book_ database:database_] autorelease];
5684 [browser loadURL:url];
5688 - (void) _setHomePage {
5689 [self setPage:[self _pageForURL:[NSURL URLWithString:@"http://cydia.saurik.com/"] withClass:[HomeView class]]];
5692 - (void) buttonBarItemTapped:(id)sender {
5693 unsigned tag = [sender tag];
5695 [book_ resetViewAnimated:YES];
5697 } else if (tag_ == 2 && tag != 2)
5698 [install_ resetView];
5701 case 1: [self _setHomePage]; break;
5703 case 2: [self setPage:install_]; break;
5704 case 3: [self setPage:changes_]; break;
5705 case 4: [self setPage:manage_]; break;
5706 case 5: [self setPage:search_]; break;
5708 default: _assert(false);
5714 - (void) fixSpringBoard {
5715 pid_t pid = ExecFork();
5719 if (pid_t child = fork()) {
5720 waitpid(child, NULL, 0);
5722 execlp("launchctl", "launchctl", "unload", SpringBoard_, NULL);
5723 perror("launchctl unload");
5727 execlp("launchctl", "launchctl", "load", SpringBoard_, NULL);
5728 perror("launchctl load");
5733 - (void) applicationWillSuspend {
5738 [self fixSpringBoard];
5742 [super applicationWillSuspend];
5745 - (void) askForSettings {
5746 UIActionSheet *role = [[[UIActionSheet alloc]
5747 initWithTitle:@"Who Are You?"
5748 buttons:[NSArray arrayWithObjects:
5749 @"User (Graphical Only)",
5750 @"Hacker (+ Command Line)",
5751 @"Developer (No Filters)",
5753 defaultButtonIndex:-1
5758 [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."];
5759 [role popupAlertAnimated:YES];
5764 [self setStatusBarShowsProgress:NO];
5767 [hud_ removeFromSuperview];
5771 pid_t pid = ExecFork();
5773 execlp("launchctl", "launchctl", "stop", "com.apple.SpringBoard", NULL);
5774 perror("launchctl stop");
5781 [self askForSettings];
5785 overlay_ = [[UIView alloc] initWithFrame:[underlay_ bounds]];
5787 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
5788 book_ = [[CYBook alloc] initWithFrame:CGRectMake(
5789 0, 0, screenrect.size.width, screenrect.size.height - 48
5790 ) database:database_];
5792 [book_ setDelegate:self];
5794 [overlay_ addSubview:book_];
5796 NSArray *buttonitems = [NSArray arrayWithObjects:
5797 [NSDictionary dictionaryWithObjectsAndKeys:
5798 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5799 @"home-up.png", kUIButtonBarButtonInfo,
5800 @"home-dn.png", kUIButtonBarButtonSelectedInfo,
5801 [NSNumber numberWithInt:1], kUIButtonBarButtonTag,
5802 self, kUIButtonBarButtonTarget,
5803 @"Home", kUIButtonBarButtonTitle,
5804 @"0", kUIButtonBarButtonType,
5807 [NSDictionary dictionaryWithObjectsAndKeys:
5808 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5809 @"install-up.png", kUIButtonBarButtonInfo,
5810 @"install-dn.png", kUIButtonBarButtonSelectedInfo,
5811 [NSNumber numberWithInt:2], kUIButtonBarButtonTag,
5812 self, kUIButtonBarButtonTarget,
5813 @"Sections", kUIButtonBarButtonTitle,
5814 @"0", kUIButtonBarButtonType,
5817 [NSDictionary dictionaryWithObjectsAndKeys:
5818 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5819 @"changes-up.png", kUIButtonBarButtonInfo,
5820 @"changes-dn.png", kUIButtonBarButtonSelectedInfo,
5821 [NSNumber numberWithInt:3], kUIButtonBarButtonTag,
5822 self, kUIButtonBarButtonTarget,
5823 @"Changes", kUIButtonBarButtonTitle,
5824 @"0", kUIButtonBarButtonType,
5827 [NSDictionary dictionaryWithObjectsAndKeys:
5828 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5829 @"manage-up.png", kUIButtonBarButtonInfo,
5830 @"manage-dn.png", kUIButtonBarButtonSelectedInfo,
5831 [NSNumber numberWithInt:4], kUIButtonBarButtonTag,
5832 self, kUIButtonBarButtonTarget,
5833 @"Manage", kUIButtonBarButtonTitle,
5834 @"0", kUIButtonBarButtonType,
5837 [NSDictionary dictionaryWithObjectsAndKeys:
5838 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5839 @"search-up.png", kUIButtonBarButtonInfo,
5840 @"search-dn.png", kUIButtonBarButtonSelectedInfo,
5841 [NSNumber numberWithInt:5], kUIButtonBarButtonTag,
5842 self, kUIButtonBarButtonTarget,
5843 @"Search", kUIButtonBarButtonTitle,
5844 @"0", kUIButtonBarButtonType,
5848 buttonbar_ = [[UIToolbar alloc]
5850 withFrame:CGRectMake(
5851 0, screenrect.size.height - ButtonBarHeight_,
5852 screenrect.size.width, ButtonBarHeight_
5854 withItemList:buttonitems
5857 [buttonbar_ setDelegate:self];
5858 [buttonbar_ setBarStyle:1];
5859 [buttonbar_ setButtonBarTrackingMode:2];
5861 int buttons[5] = {1, 2, 3, 4, 5};
5862 [buttonbar_ registerButtonGroup:0 withButtons:buttons withCount:5];
5863 [buttonbar_ showButtonGroup:0 withDuration:0];
5865 for (int i = 0; i != 5; ++i)
5866 [[buttonbar_ viewWithTag:(i + 1)] setFrame:CGRectMake(
5867 i * 64 + 2, 1, 60, ButtonBarHeight_
5870 [buttonbar_ showSelectionForButton:1];
5871 [overlay_ addSubview:buttonbar_];
5873 [UIKeyboard initImplementationNow];
5874 CGSize keysize = [UIKeyboard defaultSize];
5875 CGRect keyrect = {{0, [overlay_ bounds].size.height}, keysize};
5876 keyboard_ = [[UIKeyboard alloc] initWithFrame:keyrect];
5877 [[UIKeyboardImpl sharedInstance] setSoundsEnabled:(Sounds_Keyboard_ ? YES : NO)];
5878 [overlay_ addSubview:keyboard_];
5880 install_ = [[InstallView alloc] initWithBook:book_ database:database_];
5881 changes_ = [[ChangesView alloc] initWithBook:book_ database:database_];
5882 search_ = [[SearchView alloc] initWithBook:book_ database:database_];
5884 manage_ = (ManageView *) [[self
5885 _pageForURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"manage" ofType:@"html"]]
5886 withClass:[ManageView class]
5890 [underlay_ addSubview:overlay_];
5897 [self _setHomePage];
5900 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
5901 NSString *context = [sheet context];
5902 if ([context isEqualToString:@"fixhalf"])
5905 @synchronized (self) {
5906 for (int i = 0, e = [broken_ count]; i != e; ++i) {
5907 Package *broken = [broken_ objectAtIndex:i];
5910 NSString *id = [broken id];
5911 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.prerm", id] UTF8String]);
5912 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.postrm", id] UTF8String]);
5913 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.preinst", id] UTF8String]);
5914 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.postinst", id] UTF8String]);
5923 [broken_ removeAllObjects];
5930 else if ([context isEqualToString:@"role"]) {
5932 case 1: Role_ = @"User"; break;
5933 case 2: Role_ = @"Hacker"; break;
5934 case 3: Role_ = @"Developer"; break;
5941 bool reset = Settings_ != nil;
5943 Settings_ = [NSMutableDictionary dictionaryWithObjectsAndKeys:
5947 [Metadata_ setObject:Settings_ forKey:@"Settings"];
5955 } else if ([context isEqualToString:@"upgrade"])
5958 @synchronized (self) {
5959 for (int i = 0, e = [essential_ count]; i != e; ++i) {
5960 Package *essential = [essential_ objectAtIndex:i];
5961 [essential install];
5980 - (void) reorganize {
5981 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5982 system("/usr/libexec/cydia/free.sh");
5983 [self performSelectorOnMainThread:@selector(finish) withObject:nil waitUntilDone:NO];
5987 - (void) applicationSuspend:(__GSEvent *)event {
5988 if (hud_ == nil && ![progress_ isRunning])
5989 [super applicationSuspend:event];
5992 - (void) _animateSuspension:(BOOL)arg0 duration:(double)arg1 startTime:(double)arg2 scale:(float)arg3 {
5994 [super _animateSuspension:arg0 duration:arg1 startTime:arg2 scale:arg3];
5997 - (void) _setSuspended:(BOOL)value {
5999 [super _setSuspended:value];
6002 - (UIProgressHUD *) addProgressHUD {
6003 UIProgressHUD *hud = [[UIProgressHUD alloc] initWithWindow:window_];
6005 [underlay_ addSubview:hud];
6009 - (void) applicationDidFinishLaunching:(id)unused {
6010 Font12_ = [[UIFont systemFontOfSize:12] retain];
6011 Font12Bold_ = [[UIFont boldSystemFontOfSize:12] retain];
6012 Font14_ = [[UIFont systemFontOfSize:14] retain];
6013 Font18Bold_ = [[UIFont boldSystemFontOfSize:18] retain];
6014 Font22Bold_ = [[UIFont boldSystemFontOfSize:22] retain];
6016 _assert(pkgInitConfig(*_config));
6017 _assert(pkgInitSystem(*_config, _system));
6022 essential_ = [[NSMutableArray alloc] initWithCapacity:4];
6023 broken_ = [[NSMutableArray alloc] initWithCapacity:4];
6025 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
6026 window_ = [[UIWindow alloc] initWithContentRect:screenrect];
6028 [window_ orderFront:self];
6029 [window_ makeKey:self];
6030 [window_ _setHidden:NO];
6032 database_ = [[Database alloc] init];
6033 progress_ = [[ProgressView alloc] initWithFrame:[window_ bounds] database:database_ delegate:self];
6034 [database_ setDelegate:progress_];
6035 [window_ setContentView:progress_];
6037 underlay_ = [[UIView alloc] initWithFrame:[progress_ bounds]];
6038 [progress_ setContentView:underlay_];
6040 [progress_ resetView];
6043 readlink("/Applications", NULL, 0) == -1 && errno == EINVAL ||
6044 readlink("/Library/Ringtones", NULL, 0) == -1 && errno == EINVAL ||
6045 readlink("/Library/Wallpaper", NULL, 0) == -1 && errno == EINVAL ||
6046 readlink("/usr/include", NULL, 0) == -1 && errno == EINVAL ||
6047 readlink("/usr/libexec", NULL, 0) == -1 && errno == EINVAL ||
6048 readlink("/usr/share", NULL, 0) == -1 && errno == EINVAL
6050 [self setIdleTimerDisabled:YES];
6052 hud_ = [self addProgressHUD];
6053 [hud_ setText:@"Reorganizing\n\nWill Automatically\nRestart When Done"];
6055 [self setStatusBarShowsProgress:YES];
6058 detachNewThreadSelector:@selector(reorganize)
6066 - (void) showKeyboard:(BOOL)show {
6067 CGSize keysize = [UIKeyboard defaultSize];
6068 CGRect keydown = {{0, [overlay_ bounds].size.height}, keysize};
6069 CGRect keyup = keydown;
6070 keyup.origin.y -= keysize.height;
6072 UIFrameAnimation *animation = [[[UIFrameAnimation alloc] initWithTarget:keyboard_] autorelease];
6073 [animation setSignificantRectFields:2];
6076 [animation setStartFrame:keydown];
6077 [animation setEndFrame:keyup];
6078 [keyboard_ activate];
6080 [animation setStartFrame:keyup];
6081 [animation setEndFrame:keydown];
6082 [keyboard_ deactivate];
6085 [[UIAnimator sharedAnimator]
6086 addAnimations:[NSArray arrayWithObjects:animation, nil]
6087 withDuration:KeyboardTime_
6092 - (void) slideUp:(UIActionSheet *)alert {
6094 [alert presentSheetFromButtonBar:buttonbar_];
6096 [alert presentSheetInView:overlay_];
6101 void AddPreferences(NSString *plist) {
6102 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
6104 NSMutableDictionary *settings = [[[NSMutableDictionary alloc] initWithContentsOfFile:plist] autorelease];
6105 _assert(settings != NULL);
6106 NSMutableArray *items = [settings objectForKey:@"items"];
6110 for (size_t i(0); i != [items count]; ++i) {
6111 NSMutableDictionary *item([items objectAtIndex:i]);
6112 NSString *label = [item objectForKey:@"label"];
6113 if (label != nil && [label isEqualToString:@"Cydia"]) {
6120 for (size_t i(0); i != [items count]; ++i) {
6121 NSDictionary *item([items objectAtIndex:i]);
6122 NSString *label = [item objectForKey:@"label"];
6123 if (label != nil && [label isEqualToString:@"General"]) {
6124 [items insertObject:[NSDictionary dictionaryWithObjectsAndKeys:
6125 @"CydiaSettings", @"bundle",
6126 @"PSLinkCell", @"cell",
6127 [NSNumber numberWithBool:YES], @"hasIcon",
6128 [NSNumber numberWithBool:YES], @"isController",
6130 nil] atIndex:(i + 1)];
6136 _assert([settings writeToFile:plist atomically:YES] == YES);
6143 id Alloc_(id self, SEL selector) {
6144 id object = alloc_(self, selector);
6145 fprintf(stderr, "[%s]A-%p\n", self->isa->name, object);
6150 id Dealloc_(id self, SEL selector) {
6151 id object = dealloc_(self, selector);
6152 fprintf(stderr, "[%s]D-%p\n", self->isa->name, object);
6156 int main(int argc, char *argv[]) {
6157 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
6159 bootstrap_ = argc > 1 && strcmp(argv[1], "--bootstrap") == 0;
6161 App_ = [[NSBundle mainBundle] bundlePath];
6162 Home_ = NSHomeDirectory();
6165 NSString *plist = [Home_ stringByAppendingString:@"/Library/Preferences/com.apple.preferences.sounds.plist"];
6166 if (NSDictionary *sounds = [NSDictionary dictionaryWithContentsOfFile:plist])
6167 if (NSNumber *keyboard = [sounds objectForKey:@"keyboard"])
6168 Sounds_Keyboard_ = [keyboard boolValue];
6174 if (unlink("/var/cache/apt/pkgcache.bin") == -1)
6175 _assert(errno == ENOENT);
6176 if (unlink("/var/cache/apt/srcpkgcache.bin") == -1)
6177 _assert(errno == ENOENT);
6179 /*Method alloc = class_getClassMethod([NSObject class], @selector(alloc));
6180 alloc_ = alloc->method_imp;
6181 alloc->method_imp = (IMP) &Alloc_;*/
6183 /*Method dealloc = class_getClassMethod([NSObject class], @selector(dealloc));
6184 dealloc_ = dealloc->method_imp;
6185 dealloc->method_imp = (IMP) &Dealloc_;*/
6187 if (NSDictionary *sysver = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]) {
6188 if (NSString *prover = [sysver valueForKey:@"ProductVersion"]) {
6189 Firmware_ = strdup([prover UTF8String]);
6190 NSArray *versions = [prover componentsSeparatedByString:@"."];
6191 int count = [versions count];
6192 Major_ = count > 0 ? [[versions objectAtIndex:0] intValue] : 0;
6193 Minor_ = count > 1 ? [[versions objectAtIndex:1] intValue] : 0;
6194 BugFix_ = count > 2 ? [[versions objectAtIndex:2] intValue] : 0;
6199 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
6200 char *machine = new char[size];
6201 sysctlbyname("hw.machine", machine, &size, NULL, 0);
6204 if (CFMutableDictionaryRef dict = IOServiceMatching("IOPlatformExpertDevice"))
6205 if (io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, dict)) {
6206 if (CFTypeRef serial = IORegistryEntryCreateCFProperty(service, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0)) {
6207 SerialNumber_ = strdup(CFStringGetCStringPtr((CFStringRef) serial, CFStringGetSystemEncoding()));
6211 IOObjectRelease(service);
6214 /*AddPreferences(@"/Applications/Preferences.app/Settings-iPhone.plist");
6215 AddPreferences(@"/Applications/Preferences.app/Settings-iPod.plist");*/
6217 if ((Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"]) == NULL)
6218 Metadata_ = [[NSMutableDictionary alloc] initWithCapacity:2];
6220 Settings_ = [Metadata_ objectForKey:@"Settings"];
6222 Packages_ = [Metadata_ objectForKey:@"Packages"];
6223 Sections_ = [Metadata_ objectForKey:@"Sections"];
6224 Sources_ = [Metadata_ objectForKey:@"Sources"];
6227 if (Settings_ != nil)
6228 Role_ = [Settings_ objectForKey:@"Role"];
6230 if (Packages_ == nil) {
6231 Packages_ = [[[NSMutableDictionary alloc] initWithCapacity:128] autorelease];
6232 [Metadata_ setObject:Packages_ forKey:@"Packages"];
6235 if (Sections_ == nil) {
6236 Sections_ = [[[NSMutableDictionary alloc] initWithCapacity:32] autorelease];
6237 [Metadata_ setObject:Sections_ forKey:@"Sections"];
6240 if (Sources_ == nil) {
6241 Sources_ = [[[NSMutableDictionary alloc] initWithCapacity:0] autorelease];
6242 [Metadata_ setObject:Sources_ forKey:@"Sources"];
6245 if (access("/Library/MobileSubstrate/MobileSubstrate.dylib", F_OK) == 0)
6246 dlopen("/Library/MobileSubstrate/MobileSubstrate.dylib", RTLD_LAZY | RTLD_GLOBAL);
6248 if (access("/User", F_OK) != 0)
6249 system("/usr/libexec/cydia/firmware.sh");
6251 Locale_ = CFLocaleCopyCurrent();
6252 space_ = CGColorSpaceCreateDeviceRGB();
6254 Blue_.Set(space_, 0.2, 0.2, 1.0, 1.0);
6255 Blueish_.Set(space_, 0x19/255.f, 0x32/255.f, 0x50/255.f, 1.0);
6256 Black_.Set(space_, 0.0, 0.0, 0.0, 1.0);
6257 Clear_.Set(space_, 0.0, 0.0, 0.0, 0.0);
6258 Red_.Set(space_, 1.0, 0.0, 0.0, 1.0);
6259 White_.Set(space_, 1.0, 1.0, 1.0, 1.0);
6260 Gray_.Set(space_, 0.4, 0.4, 0.4, 1.0);
6262 Finishes_ = [NSArray arrayWithObjects:@"return", @"reopen", @"restart", @"reload", @"reboot", nil];
6264 SectionMap_ = [[[NSDictionary alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Sections" ofType:@"plist"]] autorelease];
6266 int value = UIApplicationMain(argc, argv, @"Cydia", @"Cydia");
6268 CGColorSpaceRelease(space_);