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/UIKit.h>
52 #import <MessageUI/MailComposeController.h>
54 #include <WebKit/WebFrame.h>
55 #include <WebKit/WebView.h>
60 #include <ext/stdio_filebuf.h>
62 #include <apt-pkg/acquire.h>
63 #include <apt-pkg/acquire-item.h>
64 #include <apt-pkg/algorithms.h>
65 #include <apt-pkg/cachefile.h>
66 #include <apt-pkg/clean.h>
67 #include <apt-pkg/configuration.h>
68 #include <apt-pkg/debmetaindex.h>
69 #include <apt-pkg/error.h>
70 #include <apt-pkg/init.h>
71 #include <apt-pkg/mmap.h>
72 #include <apt-pkg/pkgrecords.h>
73 #include <apt-pkg/sha1.h>
74 #include <apt-pkg/sourcelist.h>
75 #include <apt-pkg/sptr.h>
77 #include <sys/types.h>
79 #include <sys/sysctl.h>
85 #include <mach-o/nlist.h>
95 #import "BrowserView.h"
97 #import "UICaboodle.h"
100 static const NSStringCompareOptions CompareOptions_ = NSCaseInsensitiveSearch | NSNumericSearch | NSDiacriticInsensitiveSearch | NSWidthInsensitiveSearch | NSForcedOrderingSearch;
102 /* iPhoneOS 2.0 Compatibility {{{ */
104 @interface UICGColor : NSObject {
107 - (id) initWithCGColor:(CGColorRef)color;
110 @interface NSObject (iPhoneOS)
111 - (CGColorRef) cgColor;
112 - (CGColorRef) CGColor;
116 @implementation NSObject (iPhoneOS)
118 - (CGColorRef) cgColor {
119 return [self CGColor];
122 - (CGColorRef) CGColor {
123 return (CGColorRef) self;
127 [[[[objc_getClass("UICGColor") alloc] initWithCGColor:[self CGColor]] autorelease] set];
132 @interface UITextView (iPhoneOS)
133 - (void) setTextSize:(float)size;
136 @implementation UITextView (iPhoneOS)
138 - (void) setTextSize:(float)size {
139 [self setFont:[[self font] fontWithSize:size]];
146 extern NSString * const kCAFilterNearest;
148 @interface UIApplication (IdleTimer)
149 - (void) setIdleTimerDisabled:(char)arg0;
152 /* Information Dictionaries {{{ */
153 @interface NSMutableArray (Cydia)
154 - (void) addInfoDictionary:(NSDictionary *)info;
157 @implementation NSMutableArray (Cydia)
159 - (void) addInfoDictionary:(NSDictionary *)info {
160 [self addObject:info];
165 @interface NSMutableDictionary (Cydia)
166 - (void) addInfoDictionary:(NSDictionary *)info;
169 @implementation NSMutableDictionary (Cydia)
171 - (void) addInfoDictionary:(NSDictionary *)info {
172 NSString *bundle = [info objectForKey:@"CFBundleIdentifier"];
173 [self setObject:info forKey:bundle];
179 #define lprintf(args...) fprintf(stderr, args)
182 extern "C" int UIApplicationMain(int argc, char *argv[], NSString *principalClassName, NSString *delegateClassName);
184 extern NSString *kUIButtonBarButtonAction;
185 extern NSString *kUIButtonBarButtonInfo;
186 extern NSString *kUIButtonBarButtonInfoOffset;
187 extern NSString *kUIButtonBarButtonSelectedInfo;
188 extern NSString *kUIButtonBarButtonStyle;
189 extern NSString *kUIButtonBarButtonTag;
190 extern NSString *kUIButtonBarButtonTarget;
191 extern NSString *kUIButtonBarButtonTitle;
192 extern NSString *kUIButtonBarButtonTitleVerticalHeight;
193 extern NSString *kUIButtonBarButtonTitleWidth;
194 extern NSString *kUIButtonBarButtonType;
197 kUIProgressIndicatorStyleLargeWhite = 0,
198 kUIProgressIndicatorStyleMediumWhite = 1,
199 kUIProgressIndicatorStyleMediumBrown = 2,
200 kUIProgressIndicatorStyleSmallWhite = 3,
201 kUIProgressIndicatorStyleSmallBlack = 4,
202 kUIProgressIndicatorStyleTinyWhite = 5,
203 } UIProgressIndicatorStyle;
206 kUIControlEventMouseDown = 1 << 0,
207 kUIControlEventMouseMovedInside = 1 << 2, // mouse moved inside control target
208 kUIControlEventMouseMovedOutside = 1 << 3, // mouse moved outside control target
209 kUIControlEventMouseUpInside = 1 << 6, // mouse up inside control target
210 kUIControlEventMouseUpOutside = 1 << 7, // mouse up outside control target
211 kUIControlAllEvents = (kUIControlEventMouseDown | kUIControlEventMouseMovedInside | kUIControlEventMouseMovedOutside | kUIControlEventMouseUpInside | kUIControlEventMouseUpOutside)
212 } UIControlEventMasks;
214 @interface NSString (UIKit)
215 - (NSString *) stringByAddingPercentEscapes;
216 - (NSString *) stringByReplacingCharacter:(unsigned short)arg0 withCharacter:(unsigned short)arg1;
219 @interface NSString (Cydia)
220 + (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length;
221 - (NSComparisonResult) compareByPath:(NSString *)other;
224 @implementation NSString (Cydia)
226 + (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length {
227 char data[length + 1];
228 memcpy(data, bytes, length);
230 return [NSString stringWithUTF8String:data];
233 - (NSComparisonResult) compareByPath:(NSString *)other {
234 NSString *prefix = [self commonPrefixWithString:other options:0];
235 size_t length = [prefix length];
237 NSRange lrange = NSMakeRange(length, [self length] - length);
238 NSRange rrange = NSMakeRange(length, [other length] - length);
240 lrange = [self rangeOfString:@"/" options:0 range:lrange];
241 rrange = [other rangeOfString:@"/" options:0 range:rrange];
243 NSComparisonResult value;
245 if (lrange.location == NSNotFound && rrange.location == NSNotFound)
246 value = NSOrderedSame;
247 else if (lrange.location == NSNotFound)
248 value = NSOrderedAscending;
249 else if (rrange.location == NSNotFound)
250 value = NSOrderedDescending;
252 value = NSOrderedSame;
254 NSString *lpath = lrange.location == NSNotFound ? [self substringFromIndex:length] :
255 [self substringWithRange:NSMakeRange(length, lrange.location - length)];
256 NSString *rpath = rrange.location == NSNotFound ? [other substringFromIndex:length] :
257 [other substringWithRange:NSMakeRange(length, rrange.location - length)];
259 NSComparisonResult result = [lpath compare:rpath];
260 return result == NSOrderedSame ? value : result;
265 /* Perl-Compatible RegEx {{{ */
275 Pcre(const char *regex) :
280 code_ = pcre_compile(regex, 0, &error, &offset, NULL);
283 lprintf("%d:%s\n", offset, error);
287 pcre_fullinfo(code_, study_, PCRE_INFO_CAPTURECOUNT, &capture_);
288 matches_ = new int[(capture_ + 1) * 3];
296 NSString *operator [](size_t match) {
297 return [NSString stringWithUTF8Bytes:(data_ + matches_[match * 2]) length:(matches_[match * 2 + 1] - matches_[match * 2])];
300 bool operator ()(NSString *data) {
301 // XXX: length is for characters, not for bytes
302 return operator ()([data UTF8String], [data length]);
305 bool operator ()(const char *data, size_t size) {
307 return pcre_exec(code_, study_, data, size, 0, 0, matches_, (capture_ + 1) * 3) >= 0;
311 /* Mime Addresses {{{ */
312 @interface Address : NSObject {
318 - (NSString *) address;
320 + (Address *) addressWithString:(NSString *)string;
321 - (Address *) initWithString:(NSString *)string;
324 @implementation Address
333 - (NSString *) name {
337 - (NSString *) address {
341 + (Address *) addressWithString:(NSString *)string {
342 return [[[Address alloc] initWithString:string] autorelease];
345 + (NSArray *) _attributeKeys {
346 return [NSArray arrayWithObjects:@"address", @"name", nil];
349 - (NSArray *) attributeKeys {
350 return [[self class] _attributeKeys];
353 + (BOOL) isKeyExcludedFromWebScript:(const char *)name {
354 return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name];
357 - (Address *) initWithString:(NSString *)string {
358 if ((self = [super init]) != nil) {
359 const char *data = [string UTF8String];
360 size_t size = [string length];
362 static Pcre address_r("^\"?(.*)\"? <([^>]*)>$");
364 if (address_r(data, size)) {
365 name_ = [address_r[1] retain];
366 address_ = [address_r[2] retain];
368 name_ = [[NSString alloc]
371 encoding:kCFStringEncodingUTF8
381 /* CoreGraphics Primitives {{{ */
392 CGColor(CGColorSpaceRef space, float red, float green, float blue, float alpha) :
395 Set(space, red, green, blue, alpha);
400 CGColorRelease(color_);
407 void Set(CGColorSpaceRef space, float red, float green, float blue, float alpha) {
409 float color[] = {red, green, blue, alpha};
410 color_ = CGColorCreate(space, color);
413 operator CGColorRef() {
419 extern "C" void UISetColor(CGColorRef color);
421 /* Random Global Variables {{{ */
422 static const int PulseInterval_ = 50000;
423 static const int ButtonBarHeight_ = 48;
424 static const float KeyboardTime_ = 0.3f;
425 static const char * const SpringBoard_ = "/System/Library/LaunchDaemons/com.apple.SpringBoard.plist";
427 static CGColor Blue_;
428 static CGColor Blueish_;
429 static CGColor Black_;
432 static CGColor White_;
433 static CGColor Gray_;
435 static NSString *App_;
436 static NSString *Home_;
437 static BOOL Sounds_Keyboard_;
439 static BOOL Advanced_;
443 static BOOL Ignored_;
445 static UIFont *Font12_;
446 static UIFont *Font12Bold_;
447 static UIFont *Font14_;
448 static UIFont *Font18Bold_;
449 static UIFont *Font22Bold_;
451 static const char *Firmware_ = NULL;
452 static const char *Machine_ = NULL;
453 static const NSString *UniqueID_ = NULL;
460 CGColorSpaceRef space_;
462 #define FW_LEAST(major, minor, bugfix) \
463 (major < Major_ || major == Major_ && \
464 (minor < Minor_ || minor == Minor_ && \
470 static NSDictionary *SectionMap_;
471 static NSMutableDictionary *Metadata_;
472 static _transient NSMutableDictionary *Settings_;
473 static _transient NSString *Role_;
474 static _transient NSMutableDictionary *Packages_;
475 static _transient NSMutableDictionary *Sections_;
476 static _transient NSMutableDictionary *Sources_;
477 static _transient NSMutableArray *Documents_;
478 static bool Changed_;
481 NSString *GetLastUpdate() {
482 NSDate *update = [Metadata_ objectForKey:@"LastUpdate"];
485 return @"Never or Unknown";
487 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, Locale_, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
488 CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) update);
490 CFRelease(formatter);
492 return [(NSString *) formatted autorelease];
495 /* Display Helpers {{{ */
496 inline float Interpolate(float begin, float end, float fraction) {
497 return (end - begin) * fraction + begin;
500 NSString *SizeString(double size) {
502 while (size > 1024) {
507 static const char *powers_[] = {"B", "kB", "MB", "GB"};
509 return [NSString stringWithFormat:@"%.1f%s", size, powers_[power]];
512 NSString *StripVersion(NSString *version) {
513 NSRange colon = [version rangeOfString:@":"];
514 if (colon.location != NSNotFound)
515 version = [version substringFromIndex:(colon.location + 1)];
519 static const float TextViewOffset_ = 22;
521 UITextView *GetTextView(NSString *value, float left, bool html) {
522 UITextView *text([[[UITextView alloc] initWithFrame:CGRectMake(left, 3, 310 - left, 1000)] autorelease]);
523 [text setEditable:NO];
524 [text setTextSize:16];
526 [text setHTML:value];
528 [text setText:value];
529 [text setEnabled:NO];
531 [text setBackgroundColor:[UIColor clearColor]];
533 CGRect frame = [text frame];
534 [text setFrame:frame];
535 CGRect rect = [text visibleTextRect];
536 frame.size.height = rect.size.height;
537 [text setFrame:frame];
542 NSString *Simplify(NSString *title) {
543 const char *data = [title UTF8String];
544 size_t size = [title length];
546 static Pcre square_r("^\\[(.*)\\]$");
547 if (square_r(data, size))
548 return Simplify(square_r[1]);
550 static Pcre paren_r("^\\((.*)\\)$");
551 if (paren_r(data, size))
552 return Simplify(paren_r[1]);
554 static Pcre title_r("^(.*?) \\(.*\\)$");
555 if (title_r(data, size))
556 return Simplify(title_r[1]);
562 bool isSectionVisible(NSString *section) {
563 NSDictionary *metadata = [Sections_ objectForKey:section];
564 NSNumber *hidden = metadata == nil ? nil : [metadata objectForKey:@"Hidden"];
565 return hidden == nil || ![hidden boolValue];
568 /* Delegate Prototypes {{{ */
572 @interface NSObject (ProgressDelegate)
575 @implementation NSObject(ProgressDelegate)
577 - (void) _setProgressError:(NSArray *)args {
578 [self performSelector:@selector(setProgressError:forPackage:)
579 withObject:[args objectAtIndex:0]
580 withObject:([args count] == 1 ? nil : [args objectAtIndex:1])
586 @protocol ProgressDelegate
587 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id;
588 - (void) setProgressTitle:(NSString *)title;
589 - (void) setProgressPercent:(float)percent;
590 - (void) startProgress;
591 - (void) addProgressOutput:(NSString *)output;
592 - (bool) isCancelling:(size_t)received;
595 @protocol ConfigurationDelegate
596 - (void) repairWithSelector:(SEL)selector;
597 - (void) setConfigurationData:(NSString *)data;
600 @protocol CydiaDelegate
601 - (void) installPackage:(Package *)package;
602 - (void) removePackage:(Package *)package;
603 - (void) slideUp:(UIActionSheet *)alert;
604 - (void) distUpgrade;
607 - (void) askForSettings;
608 - (UIProgressHUD *) addProgressHUD;
609 - (RVPage *) pageForURL:(NSURL *)url hasTag:(int *)tag;
610 - (RVPage *) pageForPackage:(NSString *)name;
611 - (void) openMailToURL:(NSURL *)url;
615 /* Status Delegation {{{ */
617 public pkgAcquireStatus
620 _transient NSObject<ProgressDelegate> *delegate_;
628 void setDelegate(id delegate) {
629 delegate_ = delegate;
632 virtual bool MediaChange(std::string media, std::string drive) {
636 virtual void IMSHit(pkgAcquire::ItemDesc &item) {
639 virtual void Fetch(pkgAcquire::ItemDesc &item) {
640 [delegate_ setProgressTitle:[NSString stringWithUTF8String:("Downloading " + item.ShortDesc).c_str()]];
643 virtual void Done(pkgAcquire::ItemDesc &item) {
646 virtual void Fail(pkgAcquire::ItemDesc &item) {
648 item.Owner->Status == pkgAcquire::Item::StatIdle ||
649 item.Owner->Status == pkgAcquire::Item::StatDone
653 [delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
654 withObject:[NSArray arrayWithObjects:[NSString stringWithUTF8String:item.Owner->ErrorText.c_str()], nil]
659 virtual bool Pulse(pkgAcquire *Owner) {
660 bool value = pkgAcquireStatus::Pulse(Owner);
663 double(CurrentBytes + CurrentItems) /
664 double(TotalBytes + TotalItems)
667 [delegate_ setProgressPercent:percent];
668 return [delegate_ isCancelling:CurrentBytes] ? false : value;
671 virtual void Start() {
672 [delegate_ startProgress];
675 virtual void Stop() {
679 /* Progress Delegation {{{ */
684 _transient id<ProgressDelegate> delegate_;
687 virtual void Update() {
688 [delegate_ setProgressTitle:[NSString stringWithUTF8String:Op.c_str()]];
689 [delegate_ setProgressPercent:(Percent / 100)];
698 void setDelegate(id delegate) {
699 delegate_ = delegate;
702 virtual void Done() {
703 [delegate_ setProgressPercent:1];
708 /* Database Interface {{{ */
709 @interface Database : NSObject {
711 pkgDepCache::Policy *policy_;
712 pkgRecords *records_;
713 pkgProblemResolver *resolver_;
714 pkgAcquire *fetcher_;
716 SPtr<pkgPackageManager> manager_;
717 pkgSourceList *list_;
719 NSMutableDictionary *sources_;
720 NSMutableArray *packages_;
722 _transient NSObject<ConfigurationDelegate, ProgressDelegate> *delegate_;
731 - (void) _readCydia:(NSNumber *)fd;
732 - (void) _readStatus:(NSNumber *)fd;
733 - (void) _readOutput:(NSNumber *)fd;
737 - (Package *) packageWithName:(NSString *)name;
740 - (pkgCacheFile &) cache;
741 - (pkgDepCache::Policy *) policy;
742 - (pkgRecords *) records;
743 - (pkgProblemResolver *) resolver;
744 - (pkgAcquire &) fetcher;
745 - (NSArray *) packages;
746 - (NSArray *) sources;
755 - (void) updateWithStatus:(Status &)status;
757 - (void) setDelegate:(id)delegate;
758 - (Source *) getSource:(const pkgCache::PkgFileIterator &)file;
762 /* Source Class {{{ */
763 @interface Source : NSObject {
764 NSString *description_;
769 NSString *distribution_;
773 NSString *defaultIcon_;
775 NSDictionary *record_;
779 - (Source *) initWithMetaIndex:(metaIndex *)index;
781 - (NSComparisonResult) compareByNameAndType:(Source *)source;
783 - (NSDictionary *) record;
787 - (NSString *) distribution;
793 - (NSString *) description;
794 - (NSString *) label;
795 - (NSString *) origin;
796 - (NSString *) version;
798 - (NSString *) defaultIcon;
802 @implementation Source
806 [distribution_ release];
809 if (description_ != nil)
810 [description_ release];
817 if (defaultIcon_ != nil)
818 [defaultIcon_ release];
825 + (NSArray *) _attributeKeys {
826 return [NSArray arrayWithObjects:@"description", @"distribution", @"host", @"key", @"label", @"name", @"origin", @"trusted", @"type", @"uri", @"version", nil];
829 - (NSArray *) attributeKeys {
830 return [[self class] _attributeKeys];
833 + (BOOL) isKeyExcludedFromWebScript:(const char *)name {
834 return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name];
837 - (Source *) initWithMetaIndex:(metaIndex *)index {
838 if ((self = [super init]) != nil) {
839 trusted_ = index->IsTrusted();
841 uri_ = [[NSString stringWithUTF8String:index->GetURI().c_str()] retain];
842 distribution_ = [[NSString stringWithUTF8String:index->GetDist().c_str()] retain];
843 type_ = [[NSString stringWithUTF8String:index->GetType()] retain];
845 debReleaseIndex *dindex(dynamic_cast<debReleaseIndex *>(index));
846 if (dindex != NULL) {
847 std::ifstream release(dindex->MetaIndexFile("Release").c_str());
849 while (std::getline(release, line)) {
850 std::string::size_type colon(line.find(':'));
851 if (colon == std::string::npos)
854 std::string name(line.substr(0, colon));
855 std::string value(line.substr(colon + 1));
856 while (!value.empty() && value[0] == ' ')
857 value = value.substr(1);
859 if (name == "Default-Icon")
860 defaultIcon_ = [[NSString stringWithUTF8String:value.c_str()] retain];
861 else if (name == "Description")
862 description_ = [[NSString stringWithUTF8String:value.c_str()] retain];
863 else if (name == "Label")
864 label_ = [[NSString stringWithUTF8String:value.c_str()] retain];
865 else if (name == "Origin")
866 origin_ = [[NSString stringWithUTF8String:value.c_str()] retain];
867 else if (name == "Version")
868 version_ = [[NSString stringWithUTF8String:value.c_str()] retain];
872 record_ = [Sources_ objectForKey:[self key]];
874 record_ = [record_ retain];
878 - (NSComparisonResult) compareByNameAndType:(Source *)source {
879 NSDictionary *lhr = [self record];
880 NSDictionary *rhr = [source record];
883 return lhr == nil ? NSOrderedDescending : NSOrderedAscending;
885 NSString *lhs = [self name];
886 NSString *rhs = [source name];
888 if ([lhs length] != 0 && [rhs length] != 0) {
889 unichar lhc = [lhs characterAtIndex:0];
890 unichar rhc = [rhs characterAtIndex:0];
892 if (isalpha(lhc) && !isalpha(rhc))
893 return NSOrderedAscending;
894 else if (!isalpha(lhc) && isalpha(rhc))
895 return NSOrderedDescending;
898 return [lhs compare:rhs options:CompareOptions_];
901 - (NSDictionary *) record {
913 - (NSString *) distribution {
914 return distribution_;
917 - (NSString *) type {
922 return [NSString stringWithFormat:@"%@:%@:%@", type_, uri_, distribution_];
925 - (NSString *) host {
926 return [[[NSURL URLWithString:[self uri]] host] lowercaseString];
929 - (NSString *) name {
930 return origin_ == nil ? [self host] : origin_;
933 - (NSString *) description {
937 - (NSString *) label {
938 return label_ == nil ? [self host] : label_;
941 - (NSString *) origin {
945 - (NSString *) version {
949 - (NSString *) defaultIcon {
955 /* Relationship Class {{{ */
956 @interface Relationship : NSObject {
967 @implementation Relationship
975 - (NSString *) type {
983 - (NSString *) name {
990 /* Package Class {{{ */
991 NSString *Scour(const char *field, const char *begin, const char *end) {
992 size_t i(0), l(strlen(field));
995 const char *name = begin + i;
996 const char *colon = name + l;
997 const char *value = colon + 1;
1002 memcmp(name, field, l) == 0
1004 while (value != end && value[0] == ' ')
1006 const char *line = std::find(value, end, '\n');
1007 while (line != value && line[-1] == ' ')
1010 return [NSString stringWithUTF8Bytes:value length:(line - value)];
1012 begin = std::find(begin, end, '\n');
1020 @interface Package : NSObject {
1021 pkgCache::PkgIterator iterator_;
1022 _transient Database *database_;
1023 pkgCache::VerIterator version_;
1024 pkgCache::VerFileIterator file_;
1030 NSString *installed_;
1036 NSString *depiction_;
1037 NSString *homepage_;
1043 NSArray *relationships_;
1046 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
1047 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
1049 - (pkgCache::PkgIterator) iterator;
1051 - (NSString *) section;
1052 - (Address *) maintainer;
1054 - (NSString *) description;
1055 - (NSString *) index;
1059 - (NSString *) latest;
1060 - (NSString *) installed;
1063 - (BOOL) upgradableAndEssential:(BOOL)essential;
1066 - (BOOL) unfiltered;
1070 - (BOOL) halfConfigured;
1071 - (BOOL) halfInstalled;
1073 - (NSString *) mode;
1076 - (NSString *) name;
1077 - (NSString *) tagline;
1078 - (NSString *) icon;
1079 - (NSString *) homepage;
1080 - (NSString *) depiction;
1081 - (Address *) author;
1083 - (NSArray *) relationships;
1085 - (Source *) source;
1086 - (NSString *) role;
1088 - (BOOL) matches:(NSString *)text;
1090 - (bool) hasSupportingRole;
1091 - (BOOL) hasTag:(NSString *)tag;
1092 - (NSString *) primaryPurpose;
1094 - (NSComparisonResult) compareByName:(Package *)package;
1095 - (NSComparisonResult) compareBySection:(Package *)package;
1096 - (NSComparisonResult) compareBySectionAndName:(Package *)package;
1097 - (NSComparisonResult) compareForChanges:(Package *)package;
1102 - (NSNumber *) isUnfilteredAndSearchedForBy:(NSString *)search;
1103 - (NSNumber *) isInstalledAndVisible:(NSNumber *)number;
1104 - (NSNumber *) isVisiblyUninstalledInSection:(NSString *)section;
1105 - (NSNumber *) isVisibleInSource:(Source *)source;
1109 @implementation Package
1116 if (installed_ != nil)
1117 [installed_ release];
1125 if (depiction_ != nil)
1126 [depiction_ release];
1127 if (homepage_ != nil)
1128 [homepage_ release];
1129 if (sponsor_ != nil)
1138 if (relationships_ != nil)
1139 [relationships_ release];
1144 + (NSArray *) _attributeKeys {
1145 return [NSArray arrayWithObjects:@"author", @"depiction", @"description", @"essential", @"homepage", @"icon", @"id", @"installed", @"latest", @"maintainer", @"name", @"section", @"size", @"source", @"sponsor", @"tagline", nil];
1148 - (NSArray *) attributeKeys {
1149 return [[self class] _attributeKeys];
1152 + (BOOL) isKeyExcludedFromWebScript:(const char *)name {
1153 return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name];
1156 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
1157 if ((self = [super init]) != nil) {
1158 iterator_ = iterator;
1159 database_ = database;
1161 version_ = [database_ policy]->GetCandidateVer(iterator_);
1162 latest_ = version_.end() ? nil : [StripVersion([NSString stringWithUTF8String:version_.VerStr()]) retain];
1164 if (!version_.end())
1165 file_ = version_.FileList();
1167 pkgCache &cache([database_ cache]);
1168 file_ = pkgCache::VerFileIterator(cache, cache.VerFileP);
1171 pkgCache::VerIterator current = iterator_.CurrentVer();
1172 installed_ = current.end() ? nil : [StripVersion([NSString stringWithUTF8String:current.VerStr()]) retain];
1174 id_ = [[[NSString stringWithUTF8String:iterator_.Name()] lowercaseString] retain];
1177 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1179 const char *begin, *end;
1180 parser->GetRec(begin, end);
1182 name_ = Scour("Name", begin, end);
1184 name_ = [name_ retain];
1185 tagline_ = [[NSString stringWithUTF8String:parser->ShortDesc().c_str()] retain];
1186 icon_ = Scour("Icon", begin, end);
1188 icon_ = [icon_ retain];
1189 depiction_ = Scour("Depiction", begin, end);
1190 if (depiction_ != nil)
1191 depiction_ = [depiction_ retain];
1192 homepage_ = Scour("Homepage", begin, end);
1193 if (homepage_ == nil)
1194 homepage_ = Scour("Website", begin, end);
1195 if ([homepage_ isEqualToString:depiction_])
1197 if (homepage_ != nil)
1198 homepage_ = [homepage_ retain];
1199 NSString *sponsor = Scour("Sponsor", begin, end);
1201 sponsor_ = [[Address addressWithString:sponsor] retain];
1202 NSString *author = Scour("Author", begin, end);
1204 author_ = [[Address addressWithString:author] retain];
1205 NSString *tags = Scour("Tag", begin, end);
1207 tags_ = [[tags componentsSeparatedByString:@", "] retain];
1211 for (int i(0), e([tags_ count]); i != e; ++i) {
1212 NSString *tag = [tags_ objectAtIndex:i];
1213 if ([tag hasPrefix:@"role::"]) {
1214 role_ = [[tag substringFromIndex:6] retain];
1219 NSMutableDictionary *metadata = [Packages_ objectForKey:id_];
1220 if (metadata == nil || [metadata count] == 0) {
1221 metadata = [NSMutableDictionary dictionaryWithObjectsAndKeys:
1225 [Packages_ setObject:metadata forKey:id_];
1231 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
1232 return [[[Package alloc]
1233 initWithIterator:iterator
1238 - (pkgCache::PkgIterator) iterator {
1242 - (NSString *) section {
1243 const char *section = iterator_.Section();
1244 if (section == NULL)
1247 NSString *name = [[NSString stringWithUTF8String:section] stringByReplacingCharacter:' ' withCharacter:'_'];
1250 if (NSDictionary *value = [SectionMap_ objectForKey:name])
1251 if (NSString *rename = [value objectForKey:@"Rename"]) {
1256 return [name stringByReplacingCharacter:'_' withCharacter:' '];
1259 - (Address *) maintainer {
1262 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1263 return [Address addressWithString:[NSString stringWithUTF8String:parser->Maintainer().c_str()]];
1267 return version_.end() ? 0 : version_->InstalledSize;
1270 - (NSString *) description {
1273 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1274 NSString *description([NSString stringWithUTF8String:parser->LongDesc().c_str()]);
1276 NSArray *lines = [description componentsSeparatedByString:@"\n"];
1277 NSMutableArray *trimmed = [NSMutableArray arrayWithCapacity:([lines count] - 1)];
1278 if ([lines count] < 2)
1281 NSCharacterSet *whitespace = [NSCharacterSet whitespaceCharacterSet];
1282 for (size_t i(1); i != [lines count]; ++i) {
1283 NSString *trim = [[lines objectAtIndex:i] stringByTrimmingCharactersInSet:whitespace];
1284 [trimmed addObject:trim];
1287 return [trimmed componentsJoinedByString:@"\n"];
1290 - (NSString *) index {
1291 NSString *index = [[[self name] substringToIndex:1] uppercaseString];
1292 return [index length] != 0 && isalpha([index characterAtIndex:0]) ? index : @"123";
1296 return [[Packages_ objectForKey:id_] objectForKey:@"FirstSeen"];
1299 - (NSString *) latest {
1303 - (NSString *) installed {
1308 return !version_.end();
1311 - (BOOL) upgradableAndEssential:(BOOL)essential {
1312 pkgCache::VerIterator current = iterator_.CurrentVer();
1315 return essential && [self essential];
1317 pkgCache::VerIterator candidate = [database_ policy]->GetCandidateVer(iterator_);
1318 return !candidate.end() && candidate != current;
1322 - (BOOL) essential {
1323 return (iterator_->Flags & pkgCache::Flag::Essential) == 0 ? NO : YES;
1327 return [database_ cache][iterator_].InstBroken();
1330 - (BOOL) unfiltered {
1331 NSString *section = [self section];
1332 return section == nil || isSectionVisible(section);
1336 return [self hasSupportingRole] && [self unfiltered];
1340 unsigned char current = iterator_->CurrentState;
1341 return current == pkgCache::State::HalfConfigured || current == pkgCache::State::HalfInstalled;
1344 - (BOOL) halfConfigured {
1345 return iterator_->CurrentState == pkgCache::State::HalfConfigured;
1348 - (BOOL) halfInstalled {
1349 return iterator_->CurrentState == pkgCache::State::HalfInstalled;
1353 pkgDepCache::StateCache &state([database_ cache][iterator_]);
1354 return state.Mode != pkgDepCache::ModeKeep;
1357 - (NSString *) mode {
1358 pkgDepCache::StateCache &state([database_ cache][iterator_]);
1360 switch (state.Mode) {
1361 case pkgDepCache::ModeDelete:
1362 if ((state.iFlags & pkgDepCache::Purge) != 0)
1367 case pkgDepCache::ModeKeep:
1368 if ((state.iFlags & pkgDepCache::AutoKept) != 0)
1373 case pkgDepCache::ModeInstall:
1374 if ((state.iFlags & pkgDepCache::ReInstall) != 0)
1375 return @"Reinstall";
1376 else switch (state.Status) {
1378 return @"Downgrade";
1384 return @"New Install";
1397 - (NSString *) name {
1398 return name_ == nil ? id_ : name_;
1401 - (NSString *) tagline {
1405 - (NSString *) icon {
1409 - (NSString *) homepage {
1413 - (NSString *) depiction {
1417 - (Address *) sponsor {
1421 - (Address *) author {
1425 - (NSArray *) relationships {
1426 return relationships_;
1429 - (Source *) source {
1431 source_ = file_.end() ? nil : [[database_ getSource:file_.File()] retain];
1438 - (NSString *) role {
1442 - (BOOL) matches:(NSString *)text {
1448 range = [[self id] rangeOfString:text options:NSCaseInsensitiveSearch];
1449 if (range.location != NSNotFound)
1452 range = [[self name] rangeOfString:text options:NSCaseInsensitiveSearch];
1453 if (range.location != NSNotFound)
1456 range = [[self tagline] rangeOfString:text options:NSCaseInsensitiveSearch];
1457 if (range.location != NSNotFound)
1463 - (bool) hasSupportingRole {
1466 if ([role_ isEqualToString:@"enduser"])
1468 if ([Role_ isEqualToString:@"User"])
1470 if ([role_ isEqualToString:@"hacker"])
1472 if ([Role_ isEqualToString:@"Hacker"])
1474 if ([role_ isEqualToString:@"developer"])
1476 if ([Role_ isEqualToString:@"Developer"])
1481 - (BOOL) hasTag:(NSString *)tag {
1482 return tags_ == nil ? NO : [tags_ containsObject:tag];
1485 - (NSString *) primaryPurpose {
1486 for (NSString *tag in tags_)
1487 if ([tag hasPrefix:@"purpose::"])
1488 return [tag substringFromIndex:9];
1492 - (NSComparisonResult) compareByName:(Package *)package {
1493 NSString *lhs = [self name];
1494 NSString *rhs = [package name];
1496 if ([lhs length] != 0 && [rhs length] != 0) {
1497 unichar lhc = [lhs characterAtIndex:0];
1498 unichar rhc = [rhs characterAtIndex:0];
1500 if (isalpha(lhc) && !isalpha(rhc))
1501 return NSOrderedAscending;
1502 else if (!isalpha(lhc) && isalpha(rhc))
1503 return NSOrderedDescending;
1506 return [lhs compare:rhs options:CompareOptions_];
1509 - (NSComparisonResult) compareBySection:(Package *)package {
1510 NSString *lhs = [self section];
1511 NSString *rhs = [package section];
1513 if (lhs == NULL && rhs != NULL)
1514 return NSOrderedAscending;
1515 else if (lhs != NULL && rhs == NULL)
1516 return NSOrderedDescending;
1517 else if (lhs != NULL && rhs != NULL) {
1518 NSComparisonResult result = [lhs compare:rhs options:CompareOptions_];
1519 if (result != NSOrderedSame)
1523 return NSOrderedSame;
1526 - (NSComparisonResult) compareBySectionAndName:(Package *)package {
1527 NSString *lhs = [self section];
1528 NSString *rhs = [package section];
1530 if (lhs == NULL && rhs != NULL)
1531 return NSOrderedAscending;
1532 else if (lhs != NULL && rhs == NULL)
1533 return NSOrderedDescending;
1534 else if (lhs != NULL && rhs != NULL) {
1535 NSComparisonResult result = [lhs compare:rhs];
1536 if (result != NSOrderedSame)
1540 return [self compareByName:package];
1543 - (NSComparisonResult) compareForChanges:(Package *)package {
1544 BOOL lhs = [self upgradableAndEssential:YES];
1545 BOOL rhs = [package upgradableAndEssential:YES];
1548 return lhs ? NSOrderedAscending : NSOrderedDescending;
1550 switch ([[self seen] compare:[package seen]]) {
1551 case NSOrderedAscending:
1552 return NSOrderedDescending;
1555 case NSOrderedDescending:
1556 return NSOrderedAscending;
1562 return [self compareByName:package];
1566 pkgProblemResolver *resolver = [database_ resolver];
1567 resolver->Clear(iterator_);
1568 resolver->Protect(iterator_);
1569 pkgCacheFile &cache([database_ cache]);
1570 cache->MarkInstall(iterator_, false);
1571 pkgDepCache::StateCache &state((*cache)[iterator_]);
1572 if (!state.Install())
1573 cache->SetReInstall(iterator_, true);
1577 pkgProblemResolver *resolver = [database_ resolver];
1578 resolver->Clear(iterator_);
1579 resolver->Protect(iterator_);
1580 resolver->Remove(iterator_);
1581 [database_ cache]->MarkDelete(iterator_, true);
1584 - (NSNumber *) isUnfilteredAndSearchedForBy:(NSString *)search {
1585 return [NSNumber numberWithBool:(
1586 [self unfiltered] && [self matches:search]
1590 - (NSNumber *) isInstalledAndVisible:(NSNumber *)number {
1591 return [NSNumber numberWithBool:(
1592 (![number boolValue] || [self visible]) && [self installed] != nil
1596 - (NSNumber *) isVisiblyUninstalledInSection:(NSString *)name {
1597 NSString *section = [self section];
1599 return [NSNumber numberWithBool:(
1601 [self installed] == nil && (
1603 section == nil && [name length] == 0 ||
1604 [name isEqualToString:section]
1609 - (NSNumber *) isVisibleInSource:(Source *)source {
1610 return [NSNumber numberWithBool:([self source] == source && [self visible])];
1615 /* Section Class {{{ */
1616 @interface Section : NSObject {
1622 - (NSComparisonResult) compareByName:(Section *)section;
1623 - (Section *) initWithName:(NSString *)name;
1624 - (Section *) initWithName:(NSString *)name row:(size_t)row;
1625 - (NSString *) name;
1628 - (void) addToCount;
1632 @implementation Section
1639 - (NSComparisonResult) compareByName:(Section *)section {
1640 NSString *lhs = [self name];
1641 NSString *rhs = [section name];
1643 if ([lhs length] != 0 && [rhs length] != 0) {
1644 unichar lhc = [lhs characterAtIndex:0];
1645 unichar rhc = [rhs characterAtIndex:0];
1647 if (isalpha(lhc) && !isalpha(rhc))
1648 return NSOrderedAscending;
1649 else if (!isalpha(lhc) && isalpha(rhc))
1650 return NSOrderedDescending;
1653 return [lhs compare:rhs options:CompareOptions_];
1656 - (Section *) initWithName:(NSString *)name {
1657 return [self initWithName:name row:0];
1660 - (Section *) initWithName:(NSString *)name row:(size_t)row {
1661 if ((self = [super init]) != nil) {
1662 name_ = [name retain];
1667 - (NSString *) name {
1679 - (void) addToCount {
1689 /* Database Implementation {{{ */
1690 @implementation Database
1697 - (void) _readCydia:(NSNumber *)fd {
1698 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1700 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1701 std::istream is(&ib);
1704 static Pcre finish_r("^finish:([^:]*)$");
1706 while (std::getline(is, line)) {
1707 const char *data(line.c_str());
1708 size_t size = line.size();
1709 lprintf("C:%s\n", data);
1711 if (finish_r(data, size)) {
1712 NSString *finish = finish_r[1];
1713 int index = [Finishes_ indexOfObject:finish];
1714 if (index != INT_MAX && index > Finish_)
1723 - (void) _readStatus:(NSNumber *)fd {
1724 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1726 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1727 std::istream is(&ib);
1730 static Pcre conffile_r("^status: [^ ]* : conffile-prompt : (.*?) *$");
1731 static Pcre pmstatus_r("^([^:]*):([^:]*):([^:]*):(.*)$");
1733 while (std::getline(is, line)) {
1734 const char *data(line.c_str());
1735 size_t size = line.size();
1736 lprintf("S:%s\n", data);
1738 if (conffile_r(data, size)) {
1739 [delegate_ setConfigurationData:conffile_r[1]];
1740 } else if (strncmp(data, "status: ", 8) == 0) {
1741 NSString *string = [NSString stringWithUTF8String:(data + 8)];
1742 [delegate_ setProgressTitle:string];
1743 } else if (pmstatus_r(data, size)) {
1744 std::string type([pmstatus_r[1] UTF8String]);
1745 NSString *id = pmstatus_r[2];
1747 float percent([pmstatus_r[3] floatValue]);
1748 [delegate_ setProgressPercent:(percent / 100)];
1750 NSString *string = pmstatus_r[4];
1752 if (type == "pmerror")
1753 [delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
1754 withObject:[NSArray arrayWithObjects:string, id, nil]
1757 else if (type == "pmstatus")
1758 [delegate_ setProgressTitle:string];
1759 else if (type == "pmconffile")
1760 [delegate_ setConfigurationData:string];
1761 else _assert(false);
1762 } else _assert(false);
1769 - (void) _readOutput:(NSNumber *)fd {
1770 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1772 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1773 std::istream is(&ib);
1776 while (std::getline(is, line)) {
1777 lprintf("O:%s\n", line.c_str());
1778 [delegate_ addProgressOutput:[NSString stringWithUTF8String:line.c_str()]];
1789 - (Package *) packageWithName:(NSString *)name {
1790 if (static_cast<pkgDepCache *>(cache_) == NULL)
1792 pkgCache::PkgIterator iterator(cache_->FindPkg([name UTF8String]));
1793 return iterator.end() ? nil : [Package packageWithIterator:iterator database:self];
1796 - (Database *) init {
1797 if ((self = [super init]) != nil) {
1804 sources_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1805 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
1809 _assert(pipe(fds) != -1);
1812 _config->Set("APT::Keep-Fds::", cydiafd_);
1813 setenv("CYDIA", [[[[NSNumber numberWithInt:cydiafd_] stringValue] stringByAppendingString:@" 1"] UTF8String], _not(int));
1816 detachNewThreadSelector:@selector(_readCydia:)
1818 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1821 _assert(pipe(fds) != -1);
1825 detachNewThreadSelector:@selector(_readStatus:)
1827 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1830 _assert(pipe(fds) != -1);
1831 _assert(dup2(fds[0], 0) != -1);
1832 _assert(close(fds[0]) != -1);
1834 input_ = fdopen(fds[1], "a");
1836 _assert(pipe(fds) != -1);
1837 _assert(dup2(fds[1], 1) != -1);
1838 _assert(close(fds[1]) != -1);
1841 detachNewThreadSelector:@selector(_readOutput:)
1843 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1848 - (pkgCacheFile &) cache {
1852 - (pkgDepCache::Policy *) policy {
1856 - (pkgRecords *) records {
1860 - (pkgProblemResolver *) resolver {
1864 - (pkgAcquire &) fetcher {
1868 - (NSArray *) packages {
1872 - (NSArray *) sources {
1873 return [sources_ allValues];
1876 - (void) reloadData {
1895 if (!cache_.Open(progress_, true)) {
1897 if (!_error->PopMessage(error))
1900 lprintf("cache_.Open():[%s]\n", error.c_str());
1902 if (error == "dpkg was interrupted, you must manually run 'dpkg --configure -a' to correct the problem. ")
1903 [delegate_ repairWithSelector:@selector(configure)];
1904 else if (error == "The package lists or status file could not be parsed or opened.")
1905 [delegate_ repairWithSelector:@selector(update)];
1906 // else if (error == "Could not open lock file /var/lib/dpkg/lock - open (13 Permission denied)")
1907 // else if (error == "Could not get lock /var/lib/dpkg/lock - open (35 Resource temporarily unavailable)")
1908 // else if (error == "The list of sources could not be read.")
1909 else _assert(false);
1914 now_ = [[NSDate date] retain];
1916 policy_ = new pkgDepCache::Policy();
1917 records_ = new pkgRecords(cache_);
1918 resolver_ = new pkgProblemResolver(cache_);
1919 fetcher_ = new pkgAcquire(&status_);
1922 list_ = new pkgSourceList();
1923 _assert(list_->ReadMainList());
1925 _assert(cache_->DelCount() == 0 && cache_->InstCount() == 0);
1926 _assert(pkgApplyStatus(cache_));
1928 if (cache_->BrokenCount() != 0) {
1929 _assert(pkgFixBroken(cache_));
1930 _assert(cache_->BrokenCount() == 0);
1931 _assert(pkgMinimizeUpgrade(cache_));
1934 [sources_ removeAllObjects];
1935 for (pkgSourceList::const_iterator source = list_->begin(); source != list_->end(); ++source) {
1936 std::vector<pkgIndexFile *> *indices = (*source)->GetIndexFiles();
1937 for (std::vector<pkgIndexFile *>::const_iterator index = indices->begin(); index != indices->end(); ++index)
1939 setObject:[[[Source alloc] initWithMetaIndex:*source] autorelease]
1940 forKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(*index)]
1944 [packages_ removeAllObjects];
1945 for (pkgCache::PkgIterator iterator = cache_->PkgBegin(); !iterator.end(); ++iterator)
1946 if (Package *package = [Package packageWithIterator:iterator database:self])
1947 [packages_ addObject:package];
1949 [packages_ sortUsingSelector:@selector(compareByName:)];
1952 - (void) configure {
1953 NSString *dpkg = [NSString stringWithFormat:@"dpkg --configure -a --status-fd %u", statusfd_];
1954 system([dpkg UTF8String]);
1962 Lock.Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1963 _assert(!_error->PendingError());
1966 fetcher.Clean(_config->FindDir("Dir::Cache::Archives"));
1969 public pkgArchiveCleaner
1972 virtual void Erase(const char *File, std::string Pkg, std::string Ver, struct stat &St) {
1977 if (!cleaner.Go(_config->FindDir("Dir::Cache::Archives") + "partial/", cache_)) {
1979 while (_error->PopMessage(error))
1980 lprintf("ArchiveCleaner: %s\n", error.c_str());
1985 pkgRecords records(cache_);
1987 lock_ = new FileFd();
1988 lock_->Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1989 _assert(!_error->PendingError());
1992 // XXX: explain this with an error message
1993 _assert(list.ReadMainList());
1995 manager_ = (_system->CreatePM(cache_));
1996 _assert(manager_->GetArchives(fetcher_, &list, &records));
1997 _assert(!_error->PendingError());
2001 NSMutableArray *before = [NSMutableArray arrayWithCapacity:16]; {
2003 _assert(list.ReadMainList());
2004 for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source)
2005 [before addObject:[NSString stringWithUTF8String:(*source)->GetURI().c_str()]];
2008 if (fetcher_->Run(PulseInterval_) != pkgAcquire::Continue) {
2013 bool failed = false;
2014 for (pkgAcquire::ItemIterator item = fetcher_->ItemsBegin(); item != fetcher_->ItemsEnd(); item++) {
2015 if ((*item)->Status == pkgAcquire::Item::StatDone && (*item)->Complete)
2018 std::string uri = (*item)->DescURI();
2019 std::string error = (*item)->ErrorText;
2021 lprintf("pAf:%s:%s\n", uri.c_str(), error.c_str());
2024 [delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
2025 withObject:[NSArray arrayWithObjects:[NSString stringWithUTF8String:error.c_str()], nil]
2036 pkgPackageManager::OrderResult result = manager_->DoInstall(statusfd_);
2038 if (_error->PendingError()) {
2043 if (result == pkgPackageManager::Failed) {
2048 if (result != pkgPackageManager::Completed) {
2053 NSMutableArray *after = [NSMutableArray arrayWithCapacity:16]; {
2055 _assert(list.ReadMainList());
2056 for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source)
2057 [after addObject:[NSString stringWithUTF8String:(*source)->GetURI().c_str()]];
2060 if (![before isEqualToArray:after])
2065 _assert(pkgDistUpgrade(cache_));
2069 [self updateWithStatus:status_];
2072 - (void) updateWithStatus:(Status &)status {
2074 _assert(list.ReadMainList());
2077 lock.Fd(GetLock(_config->FindDir("Dir::State::Lists") + "lock"));
2078 _assert(!_error->PendingError());
2080 pkgAcquire fetcher(&status);
2081 _assert(list.GetIndexes(&fetcher));
2083 if (fetcher.Run(PulseInterval_) != pkgAcquire::Failed) {
2084 bool failed = false;
2085 for (pkgAcquire::ItemIterator item = fetcher.ItemsBegin(); item != fetcher.ItemsEnd(); item++)
2086 if ((*item)->Status != pkgAcquire::Item::StatDone) {
2087 (*item)->Finished();
2091 if (!failed && _config->FindB("APT::Get::List-Cleanup", true) == true) {
2092 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists")));
2093 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/"));
2096 [Metadata_ setObject:[NSDate date] forKey:@"LastUpdate"];
2101 - (void) setDelegate:(id)delegate {
2102 delegate_ = delegate;
2103 status_.setDelegate(delegate);
2104 progress_.setDelegate(delegate);
2107 - (Source *) getSource:(const pkgCache::PkgFileIterator &)file {
2108 pkgIndexFile *index(NULL);
2109 list_->FindIndex(file, index);
2110 return [sources_ objectForKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(index)]];
2116 /* Pop Up Windows {{{ */
2117 @interface PopUpView : UIView {
2118 _transient id delegate_;
2119 UITransitionView *transition_;
2124 - (id) initWithView:(UIView *)view delegate:(id)delegate;
2128 @implementation PopUpView
2131 [transition_ setDelegate:nil];
2132 [transition_ release];
2138 [transition_ transition:UITransitionPushFromTop toView:nil];
2141 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
2142 if (from != nil && to == nil)
2143 [self removeFromSuperview];
2146 - (id) initWithView:(UIView *)view delegate:(id)delegate {
2147 if ((self = [super initWithFrame:[view bounds]]) != nil) {
2148 delegate_ = delegate;
2150 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
2151 [self addSubview:transition_];
2153 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
2155 [view addSubview:self];
2157 [transition_ setDelegate:self];
2159 UIView *blank = [[[UIView alloc] initWithFrame:[transition_ bounds]] autorelease];
2160 [transition_ transition:UITransitionNone toView:blank];
2161 [transition_ transition:UITransitionPushFromBottom toView:overlay_];
2168 /* Mail Composition {{{ */
2169 @interface MailToView : PopUpView {
2170 MailComposeController *controller_;
2173 - (id) initWithView:(UIView *)view delegate:(id)delegate url:(NSURL *)url;
2177 @implementation MailToView
2180 [controller_ release];
2184 #include "internals.h"
2186 - (void) mailComposeControllerWillAttemptToSend:(MailComposeController *)controller {
2190 - (void) mailComposeControllerDidAttemptToSend:(MailComposeController *)controller mailDelivery:(id)delivery {
2191 NSLog(@"did:%@", delivery);
2192 // [UIApp setStatusBarShowsProgress:NO];
2193 if ([controller error]){
2194 NSArray *buttons = [NSArray arrayWithObjects:@"OK", nil];
2195 UIActionSheet *mailAlertSheet = [[UIActionSheet alloc] initWithTitle:@"Error" buttons:buttons defaultButtonIndex:0 delegate:self context:self];
2196 [mailAlertSheet setBodyText:[controller error]];
2197 [mailAlertSheet popupAlertAnimated:YES];
2201 - (void) mailComposeControllerCompositionFinished:(MailComposeController *)controller {
2202 if ([controller needsDelivery])
2203 [controller deliverMessage];
2208 - (id) initWithView:(UIView *)view delegate:(id)delegate url:(NSURL *)url {
2209 if ((self = [super initWithView:view delegate:delegate]) != nil) {
2210 controller_ = [[MailComposeController alloc] initForContentSize:[overlay_ bounds].size];
2211 [controller_ setDelegate:self];
2212 [controller_ initializeUI];
2213 [controller_ setupForURL:url];
2215 UIView *view([controller_ view]);
2216 [overlay_ addSubview:view];
2222 /* Confirmation View {{{ */
2223 void AddTextView(NSMutableDictionary *fields, NSMutableArray *packages, NSString *key) {
2224 if ([packages count] == 0)
2227 UITextView *text = GetTextView([packages count] == 0 ? @"n/a" : [packages componentsJoinedByString:@", "], 120, false);
2228 [fields setObject:text forKey:key];
2230 CGColor blue(space_, 0, 0, 0.4, 1);
2231 [text setTextColor:[UIColor colorWithCGColor:blue]];
2234 bool DepSubstrate(const pkgCache::VerIterator &iterator) {
2235 if (!iterator.end())
2236 for (pkgCache::DepIterator dep(iterator.DependsList()); !dep.end(); ++dep) {
2237 if (dep->Type != pkgCache::Dep::Depends && dep->Type != pkgCache::Dep::PreDepends)
2239 pkgCache::PkgIterator package(dep.TargetPkg());
2242 if (strcmp(package.Name(), "mobilesubstrate") == 0)
2249 @protocol ConfirmationViewDelegate
2254 @interface ConfirmationView : PopUpView {
2255 Database *database_;
2256 UINavigationBar *navbar_;
2257 UIPreferencesTable *table_;
2258 NSMutableDictionary *fields_;
2259 UIActionSheet *essential_;
2265 - (id) initWithView:(UIView *)view delegate:(id)delegate database:(Database *)database;
2269 @implementation ConfirmationView
2272 [navbar_ setDelegate:nil];
2273 [table_ setDataSource:nil];
2278 if (essential_ != nil)
2279 [essential_ release];
2288 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2291 if (essential_ != nil)
2292 [essential_ popupAlertAnimated:YES];
2296 [delegate_ confirm];
2306 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
2307 NSString *context = [sheet context];
2309 if ([context isEqualToString:@"remove"])
2317 [delegate_ confirm];
2322 else if ([context isEqualToString:@"unable"])
2328 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
2332 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
2334 case 0: return @"Statistics";
2335 case 1: return @"Modifications";
2337 default: _assert(false);
2341 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
2344 case 1: return [fields_ count];
2346 default: _assert(false);
2350 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
2351 if (group != 1 || row == -1)
2354 _assert(size_t(row) < [fields_ count]);
2355 return [[[fields_ allValues] objectAtIndex:row] visibleTextRect].size.height + TextViewOffset_;
2359 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
2360 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
2361 [cell setShowSelection:NO];
2364 case 0: switch (row) {
2366 [cell setTitle:@"Downloading"];
2367 [cell setValue:SizeString([database_ fetcher].FetchNeeded())];
2371 [cell setTitle:@"Resuming At"];
2372 [cell setValue:SizeString([database_ fetcher].PartialPresent())];
2376 double size([database_ cache]->UsrSize());
2379 [cell setTitle:@"Disk Freeing"];
2380 [cell setValue:SizeString(-size)];
2382 [cell setTitle:@"Disk Using"];
2383 [cell setValue:SizeString(size)];
2387 default: _assert(false);
2391 _assert(size_t(row) < [fields_ count]);
2392 [cell setTitle:[[fields_ allKeys] objectAtIndex:row]];
2393 [cell addSubview:[[fields_ allValues] objectAtIndex:row]];
2396 default: _assert(false);
2402 - (id) initWithView:(UIView *)view delegate:(id)delegate database:(Database *)database {
2403 if ((self = [super initWithView:view delegate:delegate]) != nil) {
2404 database_ = database;
2406 CGSize navsize = [UINavigationBar defaultSize];
2407 CGRect navrect = {{0, 0}, navsize};
2408 CGRect bounds = [overlay_ bounds];
2410 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
2411 [navbar_ setDelegate:self];
2413 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Confirm"] autorelease];
2414 [navbar_ pushNavigationItem:navitem];
2415 [navbar_ showButtonsWithLeftTitle:@"Cancel" rightTitle:@"Confirm"];
2417 fields_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
2419 NSMutableArray *installing = [NSMutableArray arrayWithCapacity:16];
2420 NSMutableArray *reinstalling = [NSMutableArray arrayWithCapacity:16];
2421 NSMutableArray *upgrading = [NSMutableArray arrayWithCapacity:16];
2422 NSMutableArray *downgrading = [NSMutableArray arrayWithCapacity:16];
2423 NSMutableArray *removing = [NSMutableArray arrayWithCapacity:16];
2427 pkgDepCache::Policy *policy([database_ policy]);
2429 pkgCacheFile &cache([database_ cache]);
2430 NSArray *packages = [database_ packages];
2431 for (size_t i(0), e = [packages count]; i != e; ++i) {
2432 Package *package = [packages objectAtIndex:i];
2433 pkgCache::PkgIterator iterator = [package iterator];
2434 pkgDepCache::StateCache &state(cache[iterator]);
2436 NSString *name([package name]);
2438 if (state.NewInstall())
2439 [installing addObject:name];
2440 else if (!state.Delete() && (state.iFlags & pkgDepCache::ReInstall) == pkgDepCache::ReInstall)
2441 [reinstalling addObject:name];
2442 else if (state.Upgrade())
2443 [upgrading addObject:name];
2444 else if (state.Downgrade())
2445 [downgrading addObject:name];
2446 else if (state.Delete()) {
2447 if ([package essential])
2449 [removing addObject:name];
2452 substrate_ |= DepSubstrate(policy->GetCandidateVer(iterator));
2453 substrate_ |= DepSubstrate(iterator.CurrentVer());
2458 else if (Advanced_ || true) {
2459 essential_ = [[UIActionSheet alloc]
2460 initWithTitle:@"Removing Essentials"
2461 buttons:[NSArray arrayWithObjects:
2462 @"Cancel Operation (Safe)",
2463 @"Force Removal (Unsafe)",
2465 defaultButtonIndex:0
2471 [essential_ setDestructiveButton:[[essential_ buttons] objectAtIndex:0]];
2473 [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."];
2475 essential_ = [[UIActionSheet alloc]
2476 initWithTitle:@"Unable to Comply"
2477 buttons:[NSArray arrayWithObjects:@"Okay", nil]
2478 defaultButtonIndex:0
2483 [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."];
2486 AddTextView(fields_, installing, @"Installing");
2487 AddTextView(fields_, reinstalling, @"Reinstalling");
2488 AddTextView(fields_, upgrading, @"Upgrading");
2489 AddTextView(fields_, downgrading, @"Downgrading");
2490 AddTextView(fields_, removing, @"Removing");
2492 table_ = [[UIPreferencesTable alloc] initWithFrame:CGRectMake(
2493 0, navsize.height, bounds.size.width, bounds.size.height - navsize.height
2496 [table_ setDataSource:self];
2497 [table_ reloadData];
2499 [overlay_ addSubview:navbar_];
2500 [overlay_ addSubview:table_];
2507 /* Progress Data {{{ */
2508 @interface ProgressData : NSObject {
2514 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object;
2521 @implementation ProgressData
2523 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object {
2524 if ((self = [super init]) != nil) {
2525 selector_ = selector;
2545 /* Progress View {{{ */
2546 @interface ProgressView : UIView <
2547 ConfigurationDelegate,
2550 _transient Database *database_;
2552 UIView *background_;
2553 UITransitionView *transition_;
2555 UINavigationBar *navbar_;
2556 UIProgressBar *progress_;
2557 UITextView *output_;
2558 UITextLabel *status_;
2559 UIPushButton *close_;
2562 SHA1SumValue springlist_;
2564 NSTimeInterval last_;
2567 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
2569 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database delegate:(id)delegate;
2570 - (void) setContentView:(UIView *)view;
2573 - (void) _retachThread;
2574 - (void) _detachNewThreadData:(ProgressData *)data;
2575 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title;
2581 @protocol ProgressViewDelegate
2582 - (void) progressViewIsComplete:(ProgressView *)sender;
2585 @implementation ProgressView
2588 [transition_ setDelegate:nil];
2589 [navbar_ setDelegate:nil];
2592 if (background_ != nil)
2593 [background_ release];
2594 [transition_ release];
2597 [progress_ release];
2604 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
2605 if (bootstrap_ && from == overlay_ && to == view_)
2609 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database delegate:(id)delegate {
2610 if ((self = [super initWithFrame:frame]) != nil) {
2611 database_ = database;
2612 delegate_ = delegate;
2614 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
2615 [transition_ setDelegate:self];
2617 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
2620 [overlay_ setBackgroundColor:[UIColor blackColor]];
2622 background_ = [[UIView alloc] initWithFrame:[self bounds]];
2623 [background_ setBackgroundColor:[UIColor blackColor]];
2624 [self addSubview:background_];
2627 [self addSubview:transition_];
2629 CGSize navsize = [UINavigationBar defaultSize];
2630 CGRect navrect = {{0, 0}, navsize};
2632 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
2633 [overlay_ addSubview:navbar_];
2635 [navbar_ setBarStyle:1];
2636 [navbar_ setDelegate:self];
2638 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:nil] autorelease];
2639 [navbar_ pushNavigationItem:navitem];
2641 CGRect bounds = [overlay_ bounds];
2642 CGSize prgsize = [UIProgressBar defaultSize];
2645 (bounds.size.width - prgsize.width) / 2,
2646 bounds.size.height - prgsize.height - 20
2649 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
2650 [progress_ setStyle:0];
2652 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(
2654 bounds.size.height - prgsize.height - 50,
2655 bounds.size.width - 20,
2659 [status_ setColor:[UIColor whiteColor]];
2660 [status_ setBackgroundColor:[UIColor clearColor]];
2662 [status_ setCentersHorizontally:YES];
2663 //[status_ setFont:font];
2665 output_ = [[UITextView alloc] initWithFrame:CGRectMake(
2667 navrect.size.height + 20,
2668 bounds.size.width - 20,
2669 bounds.size.height - navsize.height - 62 - navrect.size.height
2672 //[output_ setTextFont:@"Courier New"];
2673 [output_ setTextSize:12];
2675 [output_ setTextColor:[UIColor whiteColor]];
2676 [output_ setBackgroundColor:[UIColor clearColor]];
2678 [output_ setMarginTop:0];
2679 [output_ setAllowsRubberBanding:YES];
2680 [output_ setEditable:NO];
2682 [overlay_ addSubview:output_];
2684 close_ = [[UIPushButton alloc] initWithFrame:CGRectMake(
2686 bounds.size.height - prgsize.height - 50,
2687 bounds.size.width - 20,
2691 [close_ setAutosizesToFit:NO];
2692 [close_ setDrawsShadow:YES];
2693 [close_ setStretchBackground:YES];
2694 [close_ setEnabled:YES];
2696 UIFont *bold = [UIFont boldSystemFontOfSize:22];
2697 [close_ setTitleFont:bold];
2699 [close_ addTarget:self action:@selector(closeButtonPushed) forEvents:kUIControlEventMouseUpInside];
2700 [close_ setBackground:[UIImage applicationImageNamed:@"green-up.png"] forState:0];
2701 [close_ setBackground:[UIImage applicationImageNamed:@"green-dn.png"] forState:1];
2705 - (void) setContentView:(UIView *)view {
2706 view_ = [view retain];
2709 - (void) resetView {
2710 [transition_ transition:6 toView:view_];
2713 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
2714 NSString *context = [sheet context];
2715 if ([context isEqualToString:@"conffile"]) {
2716 FILE *input = [database_ input];
2720 fprintf(input, "N\n");
2724 fprintf(input, "Y\n");
2735 - (void) closeButtonPushed {
2742 [delegate_ suspendWithAnimation:YES];
2746 system("launchctl stop com.apple.SpringBoard");
2750 system("launchctl unload /System/Library/LaunchDaemons/com.apple.SpringBoard.plist; launchctl load /System/Library/LaunchDaemons/com.apple.SpringBoard.plist");
2759 - (void) _retachThread {
2760 UINavigationItem *item = [navbar_ topItem];
2761 [item setTitle:@"Complete"];
2763 [overlay_ addSubview:close_];
2764 [progress_ removeFromSuperview];
2765 [status_ removeFromSuperview];
2767 [delegate_ progressViewIsComplete:self];
2770 FileFd file("/System/Library/LaunchDaemons/com.apple.SpringBoard.plist", FileFd::ReadOnly);
2771 MMap mmap(file, MMap::ReadOnly);
2773 sha1.Add(reinterpret_cast<uint8_t *>(mmap.Data()), mmap.Size());
2774 if (!(springlist_ == sha1.Result()))
2779 case 0: [close_ setTitle:@"Return to Cydia"]; break;
2780 case 1: [close_ setTitle:@"Close Cydia (Restart)"]; break;
2781 case 2: [close_ setTitle:@"Restart SpringBoard"]; break;
2782 case 3: [close_ setTitle:@"Reload SpringBoard"]; break;
2783 case 4: [close_ setTitle:@"Reboot Device"]; break;
2786 #define Cache_ "/User/Library/Caches/com.apple.mobile.installation.plist"
2788 if (NSMutableDictionary *cache = [[NSMutableDictionary alloc] initWithContentsOfFile:@ Cache_]) {
2789 [cache autorelease];
2791 NSFileManager *manager = [NSFileManager defaultManager];
2792 NSError *error = nil;
2794 id system = [cache objectForKey:@"System"];
2799 if (stat(Cache_, &info) == -1)
2802 [system removeAllObjects];
2804 if (NSArray *apps = [manager contentsOfDirectoryAtPath:@"/Applications" error:&error]) {
2805 for (NSString *app in apps)
2806 if ([app hasSuffix:@".app"]) {
2807 NSString *path = [@"/Applications" stringByAppendingPathComponent:app];
2808 NSString *plist = [path stringByAppendingPathComponent:@"Info.plist"];
2809 if (NSMutableDictionary *info = [[NSMutableDictionary alloc] initWithContentsOfFile:plist]) {
2811 [info setObject:path forKey:@"Path"];
2812 [info setObject:@"System" forKey:@"ApplicationType"];
2813 [system addInfoDictionary:info];
2818 [cache writeToFile:@Cache_ atomically:YES];
2820 if (chown(Cache_, info.st_uid, info.st_gid) == -1)
2822 if (chmod(Cache_, info.st_mode) == -1)
2826 lprintf("%s\n", error == nil ? strerror(errno) : [[error localizedDescription] UTF8String]);
2829 notify_post("com.apple.mobile.application_installed");
2831 [delegate_ setStatusBarShowsProgress:NO];
2836 - (void) _detachNewThreadData:(ProgressData *)data {
2837 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
2839 [[data target] performSelector:[data selector] withObject:[data object]];
2842 [self performSelectorOnMainThread:@selector(_retachThread) withObject:nil waitUntilDone:YES];
2847 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title {
2848 UINavigationItem *item = [navbar_ topItem];
2849 [item setTitle:title];
2851 [status_ setText:nil];
2852 [output_ setText:@""];
2853 [progress_ setProgress:0];
2856 last_ = 0;//[NSDate timeIntervalSinceReferenceDate];
2858 [close_ removeFromSuperview];
2859 [overlay_ addSubview:progress_];
2860 [overlay_ addSubview:status_];
2862 [delegate_ setStatusBarShowsProgress:YES];
2866 FileFd file("/System/Library/LaunchDaemons/com.apple.SpringBoard.plist", FileFd::ReadOnly);
2867 MMap mmap(file, MMap::ReadOnly);
2869 sha1.Add(reinterpret_cast<uint8_t *>(mmap.Data()), mmap.Size());
2870 springlist_ = sha1.Result();
2873 [transition_ transition:6 toView:overlay_];
2876 detachNewThreadSelector:@selector(_detachNewThreadData:)
2878 withObject:[[ProgressData alloc]
2879 initWithSelector:selector
2886 - (void) repairWithSelector:(SEL)selector {
2888 detachNewThreadSelector:selector
2895 - (void) setConfigurationData:(NSString *)data {
2897 performSelectorOnMainThread:@selector(_setConfigurationData:)
2903 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id {
2904 Package *package = id == nil ? nil : [database_ packageWithName:id];
2906 UIActionSheet *sheet = [[[UIActionSheet alloc]
2907 initWithTitle:(package == nil ? @"Source Error" : [package name])
2908 buttons:[NSArray arrayWithObjects:@"Okay", nil]
2909 defaultButtonIndex:0
2914 [sheet setBodyText:error];
2915 [sheet popupAlertAnimated:YES];
2918 - (void) setProgressTitle:(NSString *)title {
2920 performSelectorOnMainThread:@selector(_setProgressTitle:)
2926 - (void) setProgressPercent:(float)percent {
2928 performSelectorOnMainThread:@selector(_setProgressPercent:)
2929 withObject:[NSNumber numberWithFloat:percent]
2934 - (void) startProgress {
2935 last_ = [NSDate timeIntervalSinceReferenceDate];
2938 - (void) addProgressOutput:(NSString *)output {
2940 performSelectorOnMainThread:@selector(_addProgressOutput:)
2946 - (bool) isCancelling:(size_t)received {
2948 NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate];
2949 if (received_ != received) {
2950 received_ = received;
2952 } else if (now - last_ > 30)
2959 - (void) _setConfigurationData:(NSString *)data {
2960 static Pcre conffile_r("^'(.*)' '(.*)' ([01]) ([01])$");
2962 _assert(conffile_r(data));
2964 NSString *ofile = conffile_r[1];
2965 //NSString *nfile = conffile_r[2];
2967 UIActionSheet *sheet = [[[UIActionSheet alloc]
2968 initWithTitle:@"Configuration Upgrade"
2969 buttons:[NSArray arrayWithObjects:
2970 @"Keep My Old Copy",
2971 @"Accept The New Copy",
2972 // XXX: @"See What Changed",
2974 defaultButtonIndex:0
2979 [sheet setBodyText:[NSString stringWithFormat:
2980 @"The following file has been changed by both the package maintainer and by you (or for you by a script).\n\n%@"
2983 [sheet popupAlertAnimated:YES];
2986 - (void) _setProgressTitle:(NSString *)title {
2987 [status_ setText:title];
2990 - (void) _setProgressPercent:(NSNumber *)percent {
2991 [progress_ setProgress:[percent floatValue]];
2994 - (void) _addProgressOutput:(NSString *)output {
2995 [output_ setText:[NSString stringWithFormat:@"%@\n%@", [output_ text], output]];
2996 CGSize size = [output_ contentSize];
2997 CGRect rect = {{0, size.height}, {size.width, 0}};
2998 [output_ scrollRectToVisible:rect animated:YES];
3001 - (BOOL) isRunning {
3008 /* Package Cell {{{ */
3009 @interface PackageCell : UISimpleTableCell {
3012 NSString *description_;
3014 //UIImageView *trusted_;
3017 UITextLabel *status_;
3021 - (PackageCell *) init;
3022 - (void) setPackage:(Package *)package;
3024 + (int) heightForPackage:(Package *)package;
3028 @implementation PackageCell
3030 - (void) clearPackage {
3041 if (description_ != nil) {
3042 [description_ release];
3046 if (source_ != nil) {
3051 if (badge_ != nil) {
3058 [self clearPackage];
3062 //[trusted_ release];
3066 - (PackageCell *) init {
3067 if ((self = [super init]) != nil) {
3069 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 68, 280, 20)];
3070 [status_ setBackgroundColor:[UIColor clearColor]];
3071 [status_ setFont:small];
3076 - (void) setPackage:(Package *)package {
3077 [self clearPackage];
3079 Source *source = [package source];
3080 NSString *section = [package section];
3082 section = Simplify(section);
3085 if (NSString *icon = [package icon])
3086 icon_ = [UIImage imageAtPath:[icon substringFromIndex:6]];
3087 if (icon_ == nil) if (section != nil)
3088 icon_ = [UIImage imageAtPath:[NSString stringWithFormat:@"%@/Sections/%@.png", App_, section]];
3089 if (icon_ == nil) if (NSString *icon = [source defaultIcon])
3090 icon_ = [UIImage imageAtPath:[icon substringFromIndex:6]];
3092 icon_ = [UIImage applicationImageNamed:@"unknown.png"];
3094 icon_ = [icon_ retain];
3096 name_ = [[package name] retain];
3097 description_ = [[package tagline] retain];
3099 NSString *label = nil;
3100 bool trusted = false;
3102 if (source != nil) {
3103 label = [source label];
3104 trusted = [source trusted];
3105 } else if ([[package id] isEqualToString:@"firmware"])
3108 label = @"Unknown/Local";
3110 NSString *from = [NSString stringWithFormat:@"from %@", label];
3112 if (section != nil && ![section isEqualToString:label])
3113 from = [from stringByAppendingString:[NSString stringWithFormat:@" (%@)", section]];
3115 source_ = [from retain];
3117 if (NSString *purpose = [package primaryPurpose])
3118 if ((badge_ = [UIImage imageAtPath:[NSString stringWithFormat:@"%@/Purposes/%@.png", App_, purpose]]) != nil)
3119 badge_ = [badge_ retain];
3122 [badge_ removeFromSuperview];
3123 [status_ removeFromSuperview];
3125 if (NSString *mode = [package mode]) {
3126 [badge_ setImage:[UIImage applicationImageNamed:
3127 [mode isEqualToString:@"Remove"] || [mode isEqualToString:@"Purge"] ? @"removing.png" : @"installing.png"
3130 [status_ setText:[NSString stringWithFormat:@"Queued for %@", mode]];
3131 [status_ setColor:Blueish_];
3132 } else if ([package half]) {
3133 [badge_ setImage:[UIImage applicationImageNamed:@"damaged.png"]];
3134 [status_ setText:@"Package Damaged"];
3135 [status_ setColor:[UIColor redColor]];
3137 [badge_ setImage:nil];
3138 [status_ setText:nil];
3142 [self addSubview:badge_];
3143 [self addSubview:status_];
3148 - (void) drawContentInRect:(CGRect)rect selected:(BOOL)selected {
3151 rect.size = [icon_ size];
3153 rect.size.width /= 2;
3154 rect.size.height /= 2;
3156 rect.origin.x = 25 - rect.size.width / 2;
3157 rect.origin.y = 25 - rect.size.height / 2;
3159 [icon_ drawInRect:rect];
3162 if (badge_ != nil) {
3163 CGSize size = [badge_ size];
3165 [badge_ drawAtPoint:CGPointMake(
3166 36 - size.width / 2,
3167 36 - size.height / 2
3176 [name_ drawAtPoint:CGPointMake(48, 8) forWidth:240 withFont:Font18Bold_ ellipsis:2];
3177 [source_ drawAtPoint:CGPointMake(58, 29) forWidth:225 withFont:Font12_ ellipsis:2];
3181 [description_ drawAtPoint:CGPointMake(12, 46) forWidth:280 withFont:Font14_ ellipsis:2];
3183 [super drawContentInRect:rect selected:selected];
3186 + (int) heightForPackage:(Package *)package {
3187 NSString *tagline([package tagline]);
3188 int height = tagline == nil || [tagline length] == 0 ? -17 : 0;
3190 if ([package hasMode] || [package half])
3199 /* Section Cell {{{ */
3200 @interface SectionCell : UISimpleTableCell {
3205 _UISwitchSlider *switch_;
3210 - (void) setSection:(Section *)section editing:(BOOL)editing;
3214 @implementation SectionCell
3216 - (void) clearSection {
3217 if (section_ != nil) {
3227 if (count_ != nil) {
3234 [self clearSection];
3241 if ((self = [super init]) != nil) {
3242 icon_ = [[UIImage applicationImageNamed:@"folder.png"] retain];
3244 switch_ = [[_UISwitchSlider alloc] initWithFrame:CGRectMake(218, 9, 60, 25)];
3245 [switch_ addTarget:self action:@selector(onSwitch:) forEvents:kUIControlEventMouseUpInside];
3249 - (void) onSwitch:(id)sender {
3250 NSMutableDictionary *metadata = [Sections_ objectForKey:section_];
3251 if (metadata == nil) {
3252 metadata = [NSMutableDictionary dictionaryWithCapacity:2];
3253 [Sections_ setObject:metadata forKey:section_];
3257 [metadata setObject:[NSNumber numberWithBool:([switch_ value] == 0)] forKey:@"Hidden"];
3260 - (void) setSection:(Section *)section editing:(BOOL)editing {
3261 if (editing != editing_) {
3263 [switch_ removeFromSuperview];
3265 [self addSubview:switch_];
3269 [self clearSection];
3271 if (section == nil) {
3272 name_ = [@"All Packages" retain];
3275 section_ = [section name];
3276 if (section_ != nil)
3277 section_ = [section_ retain];
3278 name_ = [(section_ == nil ? @"(No Section)" : section_) retain];
3279 count_ = [[NSString stringWithFormat:@"%d", [section count]] retain];
3282 [switch_ setValue:isSectionVisible(section_) animated:NO];
3286 - (void) drawContentInRect:(CGRect)rect selected:(BOOL)selected {
3287 [icon_ drawInRect:CGRectMake(8, 7, 32, 32)];
3294 [name_ drawAtPoint:CGPointMake(48, 9) forWidth:(editing_ ? 164 : 250) withFont:Font22Bold_ ellipsis:2];
3296 CGSize size = [count_ sizeWithFont:Font14_];
3300 [count_ drawAtPoint:CGPointMake(13 + (29 - size.width) / 2, 16) withFont:Font12Bold_];
3302 [super drawContentInRect:rect selected:selected];
3308 /* File Table {{{ */
3309 @interface FileTable : RVPage {
3310 _transient Database *database_;
3313 NSMutableArray *files_;
3317 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3318 - (void) setPackage:(Package *)package;
3322 @implementation FileTable
3325 if (package_ != nil)
3334 - (int) numberOfRowsInTable:(UITable *)table {
3335 return files_ == nil ? 0 : [files_ count];
3338 - (float) table:(UITable *)table heightForRow:(int)row {
3342 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
3343 if (reusing == nil) {
3344 reusing = [[[UIImageAndTextTableCell alloc] init] autorelease];
3345 UIFont *font = [UIFont systemFontOfSize:16];
3346 [[(UIImageAndTextTableCell *)reusing titleTextLabel] setFont:font];
3348 [(UIImageAndTextTableCell *)reusing setTitle:[files_ objectAtIndex:row]];
3352 - (BOOL) table:(UITable *)table canSelectRow:(int)row {
3356 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3357 if ((self = [super initWithBook:book]) != nil) {
3358 database_ = database;
3360 files_ = [[NSMutableArray arrayWithCapacity:32] retain];
3362 list_ = [[UITable alloc] initWithFrame:[self bounds]];
3363 [self addSubview:list_];
3365 UITableColumn *column = [[[UITableColumn alloc]
3366 initWithTitle:@"Name"
3368 width:[self frame].size.width
3371 [list_ setDataSource:self];
3372 [list_ setSeparatorStyle:1];
3373 [list_ addTableColumn:column];
3374 [list_ setDelegate:self];
3375 [list_ setReusesTableCells:YES];
3379 - (void) setPackage:(Package *)package {
3380 if (package_ != nil) {
3381 [package_ autorelease];
3390 [files_ removeAllObjects];
3392 if (package != nil) {
3393 package_ = [package retain];
3394 name_ = [[package id] retain];
3396 NSString *path = [NSString stringWithFormat:@"/var/lib/dpkg/info/%@.list", name_];
3399 std::ifstream fin([path UTF8String]);
3401 while (std::getline(fin, line))
3402 [files_ addObject:[NSString stringWithUTF8String:line.c_str()]];
3405 if ([files_ count] != 0) {
3406 if ([[files_ objectAtIndex:0] isEqualToString:@"/."])
3407 [files_ removeObjectAtIndex:0];
3408 [files_ sortUsingSelector:@selector(compareByPath:)];
3410 NSMutableArray *stack = [NSMutableArray arrayWithCapacity:8];
3411 [stack addObject:@"/"];
3413 for (int i(0), e([files_ count]); i != e; ++i) {
3414 NSString *file = [files_ objectAtIndex:i];
3415 while (![file hasPrefix:[stack lastObject]])
3416 [stack removeLastObject];
3417 NSString *directory = [stack lastObject];
3418 [stack addObject:[file stringByAppendingString:@"/"]];
3419 [files_ replaceObjectAtIndex:i withObject:[NSString stringWithFormat:@"%*s%@",
3420 ([stack count] - 2) * 3, "",
3421 [file substringFromIndex:[directory length]]
3430 - (void) resetViewAnimated:(BOOL)animated {
3431 [list_ resetViewAnimated:animated];
3434 - (void) reloadData {
3435 [self setPackage:[database_ packageWithName:name_]];
3436 [self reloadButtons];
3439 - (NSString *) title {
3440 return @"Installed Files";
3443 - (NSString *) backButtonTitle {
3449 /* Package View {{{ */
3450 @interface PackageView : BrowserView {
3453 NSMutableArray *buttons_;
3456 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3457 - (void) setPackage:(Package *)package;
3461 @implementation PackageView
3464 if (package_ != nil)
3472 - (void) _clickButtonWithName:(NSString *)name {
3473 if ([name isEqualToString:@"Install"])
3474 [delegate_ installPackage:package_];
3475 else if ([name isEqualToString:@"Reinstall"])
3476 [delegate_ installPackage:package_];
3477 else if ([name isEqualToString:@"Remove"])
3478 [delegate_ removePackage:package_];
3479 else if ([name isEqualToString:@"Upgrade"])
3480 [delegate_ installPackage:package_];
3481 else _assert(false);
3484 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
3485 int count = [buttons_ count];
3486 _assert(count != 0);
3487 _assert(button <= count + 1);
3489 if (count != button - 1)
3490 [self _clickButtonWithName:[buttons_ objectAtIndex:(button - 1)]];
3495 - (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
3496 [[frame windowObject] evaluateWebScript:@"document.base.target = '_top'"];
3497 return [super webView:sender didFinishLoadForFrame:frame];
3500 - (void) webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame {
3501 [window setValue:package_ forKey:@"package"];
3502 [super webView:sender didClearWindowObject:window forFrame:frame];
3505 - (void) _rightButtonClicked {
3506 /*[super _rightButtonClicked];
3509 int count = [buttons_ count];
3510 _assert(count != 0);
3513 [self _clickButtonWithName:[buttons_ objectAtIndex:0]];
3515 NSMutableArray *buttons = [NSMutableArray arrayWithCapacity:(count + 1)];
3516 [buttons addObjectsFromArray:buttons_];
3517 [buttons addObject:@"Cancel"];
3519 [delegate_ slideUp:[[[UIActionSheet alloc]
3522 defaultButtonIndex:2
3529 - (NSString *) _rightButtonTitle {
3530 int count = [buttons_ count];
3531 return count == 0 ? nil : count != 1 ? @"Modify" : [buttons_ objectAtIndex:0];
3534 - (NSString *) title {
3538 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3539 if ((self = [super initWithBook:book database:database]) != nil) {
3540 database_ = database;
3541 buttons_ = [[NSMutableArray alloc] initWithCapacity:4];
3545 - (void) setPackage:(Package *)package {
3546 if (package_ != nil) {
3547 [package_ autorelease];
3556 [buttons_ removeAllObjects];
3558 if (package != nil) {
3559 package_ = [package retain];
3560 name_ = [[package id] retain];
3562 [self loadURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"package" ofType:@"html"]]];
3564 if ([package_ source] == nil);
3565 else if ([package_ upgradableAndEssential:NO])
3566 [buttons_ addObject:@"Upgrade"];
3567 else if ([package_ installed] == nil)
3568 [buttons_ addObject:@"Install"];
3570 [buttons_ addObject:@"Reinstall"];
3571 if ([package_ installed] != nil)
3572 [buttons_ addObject:@"Remove"];
3576 - (void) reloadData {
3577 [self setPackage:[database_ packageWithName:name_]];
3578 [self reloadButtons];
3583 /* Package Table {{{ */
3584 @interface PackageTable : RVPage {
3585 _transient Database *database_;
3589 NSMutableArray *packages_;
3590 NSMutableArray *sections_;
3591 UISectionList *list_;
3594 - (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object;
3596 - (void) setDelegate:(id)delegate;
3597 - (void) setObject:(id)object;
3599 - (void) reloadData;
3600 - (void) resetCursor;
3602 - (UISectionList *) list;
3604 - (void) setShouldHideHeaderInShortLists:(BOOL)hide;
3608 @implementation PackageTable
3611 [list_ setDataSource:nil];
3616 [packages_ release];
3617 [sections_ release];
3622 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
3623 return [sections_ count];
3626 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
3627 return [[sections_ objectAtIndex:section] name];
3630 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
3631 return [[sections_ objectAtIndex:section] row];
3634 - (int) numberOfRowsInTable:(UITable *)table {
3635 return [packages_ count];
3638 - (float) table:(UITable *)table heightForRow:(int)row {
3639 return [PackageCell heightForPackage:[packages_ objectAtIndex:row]];
3642 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
3644 reusing = [[[PackageCell alloc] init] autorelease];
3645 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
3649 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
3653 - (void) tableRowSelected:(NSNotification *)notification {
3654 int row = [[notification object] selectedRow];
3658 Package *package = [packages_ objectAtIndex:row];
3659 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
3660 [view setDelegate:delegate_];
3661 [view setPackage:package];
3662 [book_ pushPage:view];
3665 - (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object {
3666 if ((self = [super initWithBook:book]) != nil) {
3667 database_ = database;
3668 title_ = [title retain];
3670 object_ = object == nil ? nil : [object retain];
3672 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
3673 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
3675 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:YES];
3676 [list_ setDataSource:self];
3678 UITableColumn *column = [[[UITableColumn alloc]
3679 initWithTitle:@"Name"
3681 width:[self frame].size.width
3684 UITable *table = [list_ table];
3685 [table setSeparatorStyle:1];
3686 [table addTableColumn:column];
3687 [table setDelegate:self];
3688 [table setReusesTableCells:YES];
3690 [self addSubview:list_];
3693 [self setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
3694 [list_ setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
3698 - (void) setDelegate:(id)delegate {
3699 delegate_ = delegate;
3702 - (void) setObject:(id)object {
3708 object_ = [object retain];
3711 - (void) reloadData {
3712 NSArray *packages = [database_ packages];
3714 [packages_ removeAllObjects];
3715 [sections_ removeAllObjects];
3717 for (size_t i(0); i != [packages count]; ++i) {
3718 Package *package([packages objectAtIndex:i]);
3719 if ([package valid] && [[package performSelector:filter_ withObject:object_] boolValue])
3720 [packages_ addObject:package];
3723 Section *section = nil;
3725 for (size_t offset(0); offset != [packages_ count]; ++offset) {
3726 Package *package = [packages_ objectAtIndex:offset];
3727 NSString *name = [package index];
3729 if (section == nil || ![[section name] isEqualToString:name]) {
3730 section = [[[Section alloc] initWithName:name row:offset] autorelease];
3731 [sections_ addObject:section];
3734 [section addToCount];
3740 - (NSString *) title {
3744 - (void) resetViewAnimated:(BOOL)animated {
3745 [list_ resetViewAnimated:animated];
3748 - (void) resetCursor {
3749 [[list_ table] scrollPointVisibleAtTopLeft:CGPointMake(0, 0) animated:NO];
3752 - (UISectionList *) list {
3756 - (void) setShouldHideHeaderInShortLists:(BOOL)hide {
3757 [list_ setShouldHideHeaderInShortLists:hide];
3763 /* Add Source View {{{ */
3764 @interface AddSourceView : RVPage {
3765 _transient Database *database_;
3768 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3772 @implementation AddSourceView
3774 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3775 if ((self = [super initWithBook:book]) != nil) {
3776 database_ = database;
3782 /* Source Cell {{{ */
3783 @interface SourceCell : UITableCell {
3786 NSString *description_;
3792 - (SourceCell *) initWithSource:(Source *)source;
3796 @implementation SourceCell
3801 [description_ release];
3806 - (SourceCell *) initWithSource:(Source *)source {
3807 if ((self = [super init]) != nil) {
3809 icon_ = [UIImage applicationImageNamed:[NSString stringWithFormat:@"Sources/%@.png", [source host]]];
3811 icon_ = [UIImage applicationImageNamed:@"unknown.png"];
3812 icon_ = [icon_ retain];
3814 origin_ = [[source name] retain];
3815 label_ = [[source uri] retain];
3816 description_ = [[source description] retain];
3820 - (void) drawContentInRect:(CGRect)rect selected:(BOOL)selected {
3822 [icon_ drawInRect:CGRectMake(10, 10, 30, 30)];
3829 [origin_ drawAtPoint:CGPointMake(48, 8) forWidth:240 withFont:Font18Bold_ ellipsis:2];
3833 [label_ drawAtPoint:CGPointMake(58, 29) forWidth:225 withFont:Font12_ ellipsis:2];
3837 [description_ drawAtPoint:CGPointMake(12, 46) forWidth:280 withFont:Font14_ ellipsis:2];
3839 [super drawContentInRect:rect selected:selected];
3844 /* Source Table {{{ */
3845 @interface SourceTable : RVPage {
3846 _transient Database *database_;
3847 UISectionList *list_;
3848 NSMutableArray *sources_;
3849 UIActionSheet *alert_;
3853 UIProgressHUD *hud_;
3856 //NSURLConnection *installer_;
3857 NSURLConnection *trivial_bz2_;
3858 NSURLConnection *trivial_gz_;
3859 //NSURLConnection *automatic_;
3864 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3868 @implementation SourceTable
3870 - (void) _deallocConnection:(NSURLConnection *)connection {
3871 if (connection != nil) {
3872 [connection cancel];
3873 //[connection setDelegate:nil];
3874 [connection release];
3879 [[list_ table] setDelegate:nil];
3880 [list_ setDataSource:nil];
3889 //[self _deallocConnection:installer_];
3890 [self _deallocConnection:trivial_gz_];
3891 [self _deallocConnection:trivial_bz2_];
3892 //[self _deallocConnection:automatic_];
3899 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
3900 return offset_ == 0 ? 1 : 2;
3903 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
3904 switch (section + (offset_ == 0 ? 1 : 0)) {
3905 case 0: return @"Entered by User";
3906 case 1: return @"Installed by Packages";
3914 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
3915 switch (section + (offset_ == 0 ? 1 : 0)) {
3917 case 1: return offset_;
3925 - (int) numberOfRowsInTable:(UITable *)table {
3926 return [sources_ count];
3929 - (float) table:(UITable *)table heightForRow:(int)row {
3930 Source *source = [sources_ objectAtIndex:row];
3931 return [source description] == nil ? 56 : 73;
3934 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col {
3935 Source *source = [sources_ objectAtIndex:row];
3936 // XXX: weird warning, stupid selectors ;P
3937 return [[[SourceCell alloc] initWithSource:(id)source] autorelease];
3940 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
3944 - (BOOL) table:(UITable *)table canSelectRow:(int)row {
3948 - (void) tableRowSelected:(NSNotification*)notification {
3949 UITable *table([list_ table]);
3950 int row([table selectedRow]);
3954 Source *source = [sources_ objectAtIndex:row];
3956 PackageTable *packages = [[[PackageTable alloc]
3959 title:[source label]
3960 filter:@selector(isVisibleInSource:)
3964 [packages setDelegate:delegate_];
3966 [book_ pushPage:packages];
3969 - (BOOL) table:(UITable *)table canDeleteRow:(int)row {
3970 Source *source = [sources_ objectAtIndex:row];
3971 return [source record] != nil;
3974 - (void) table:(UITable *)table willSwipeToDeleteRow:(int)row {
3975 [[list_ table] setDeleteConfirmationRow:row];
3978 - (void) table:(UITable *)table deleteRow:(int)row {
3979 Source *source = [sources_ objectAtIndex:row];
3980 [Sources_ removeObjectForKey:[source key]];
3981 [delegate_ syncData];
3984 - (void) _endConnection:(NSURLConnection *)connection {
3985 NSURLConnection **field = NULL;
3986 if (connection == trivial_bz2_)
3987 field = &trivial_bz2_;
3988 else if (connection == trivial_gz_)
3989 field = &trivial_gz_;
3990 _assert(field != NULL);
3991 [connection release];
3995 trivial_bz2_ == nil &&
3998 [delegate_ setStatusBarShowsProgress:NO];
4001 [hud_ removeFromSuperview];
4006 [Sources_ setObject:[NSDictionary dictionaryWithObjectsAndKeys:
4009 @"./", @"Distribution",
4010 nil] forKey:[NSString stringWithFormat:@"deb:%@:./", href_]];
4012 [delegate_ syncData];
4013 } else if (error_ != nil) {
4014 UIActionSheet *sheet = [[[UIActionSheet alloc]
4015 initWithTitle:@"Verification Error"
4016 buttons:[NSArray arrayWithObjects:@"OK", nil]
4017 defaultButtonIndex:0
4022 [sheet setBodyText:[error_ localizedDescription]];
4023 [sheet popupAlertAnimated:YES];
4025 UIActionSheet *sheet = [[[UIActionSheet alloc]
4026 initWithTitle:@"Did not Find Repository"
4027 buttons:[NSArray arrayWithObjects:@"OK", nil]
4028 defaultButtonIndex:0
4033 [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."];
4034 [sheet popupAlertAnimated:YES];
4040 if (error_ != nil) {
4047 - (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response {
4048 switch ([response statusCode]) {
4054 - (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
4055 lprintf("connection:\"%s\" didFailWithError:\"%s\"", [href_ UTF8String], [[error localizedDescription] UTF8String]);
4057 error_ = [error retain];
4058 [self _endConnection:connection];
4061 - (void) connectionDidFinishLoading:(NSURLConnection *)connection {
4062 [self _endConnection:connection];
4065 - (NSURLConnection *) _requestHRef:(NSString *)href method:(NSString *)method {
4066 NSMutableURLRequest *request = [NSMutableURLRequest
4067 requestWithURL:[NSURL URLWithString:href]
4068 cachePolicy:NSURLRequestUseProtocolCachePolicy
4069 timeoutInterval:20.0
4072 [request setHTTPMethod:method];
4074 return [[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease];
4077 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
4078 NSString *context = [sheet context];
4079 if ([context isEqualToString:@"source"])
4082 NSString *href = [[sheet textField] text];
4084 //installer_ = [[self _requestHRef:href method:@"GET"] retain];
4086 if (![href hasSuffix:@"/"])
4087 href_ = [href stringByAppendingString:@"/"];
4090 href_ = [href_ retain];
4092 trivial_bz2_ = [[self _requestHRef:[href_ stringByAppendingString:@"Packages.bz2"] method:@"HEAD"] retain];
4093 trivial_gz_ = [[self _requestHRef:[href_ stringByAppendingString:@"Packages.gz"] method:@"HEAD"] retain];
4094 //trivial_bz2_ = [[self _requestHRef:[href stringByAppendingString:@"dists/Release"] method:@"HEAD"] retain];
4098 hud_ = [delegate_ addProgressHUD];
4099 [hud_ setText:@"Verifying URL"];
4112 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4113 if ((self = [super initWithBook:book]) != nil) {
4114 database_ = database;
4115 sources_ = [[NSMutableArray arrayWithCapacity:16] retain];
4117 //list_ = [[UITable alloc] initWithFrame:[self bounds]];
4118 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:NO];
4119 [list_ setShouldHideHeaderInShortLists:NO];
4121 [self addSubview:list_];
4122 [list_ setDataSource:self];
4124 UITableColumn *column = [[UITableColumn alloc]
4125 initWithTitle:@"Name"
4127 width:[self frame].size.width
4130 UITable *table = [list_ table];
4131 [table setSeparatorStyle:1];
4132 [table addTableColumn:column];
4133 [table setDelegate:self];
4137 [self setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
4138 [list_ setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
4142 - (void) reloadData {
4144 _assert(list.ReadMainList());
4146 [sources_ removeAllObjects];
4147 [sources_ addObjectsFromArray:[database_ sources]];
4148 [sources_ sortUsingSelector:@selector(compareByNameAndType:)];
4150 int count = [sources_ count];
4151 for (offset_ = 0; offset_ != count; ++offset_) {
4152 Source *source = [sources_ objectAtIndex:offset_];
4153 if ([source record] == nil)
4160 - (void) resetViewAnimated:(BOOL)animated {
4161 [list_ resetViewAnimated:animated];
4164 - (void) _leftButtonClicked {
4165 /*[book_ pushPage:[[[AddSourceView alloc]
4170 UIActionSheet *sheet = [[[UIActionSheet alloc]
4171 initWithTitle:@"Enter Cydia/APT URL"
4172 buttons:[NSArray arrayWithObjects:@"Add Source", @"Cancel", nil]
4173 defaultButtonIndex:0
4178 [sheet addTextFieldWithValue:@"http://" label:@""];
4180 UITextInputTraits *traits = [[sheet textField] textInputTraits];
4181 [traits setAutocapitalizationType:0];
4182 [traits setKeyboardType:3];
4183 [traits setAutocorrectionType:1];
4185 [sheet popupAlertAnimated:YES];
4188 - (void) _rightButtonClicked {
4189 UITable *table = [list_ table];
4190 BOOL editing = [table isRowDeletionEnabled];
4191 [table enableRowDeletion:!editing animated:YES];
4192 [book_ reloadButtonsForPage:self];
4195 - (NSString *) title {
4199 - (NSString *) backButtonTitle {
4203 - (NSString *) leftButtonTitle {
4204 return [[list_ table] isRowDeletionEnabled] ? @"Add" : nil;
4207 - (NSString *) rightButtonTitle {
4208 return [[list_ table] isRowDeletionEnabled] ? @"Done" : @"Edit";
4211 - (UINavigationButtonStyle) rightButtonStyle {
4212 return [[list_ table] isRowDeletionEnabled] ? UINavigationButtonStyleHighlighted : UINavigationButtonStyleNormal;
4218 /* Installed View {{{ */
4219 @interface InstalledView : RVPage {
4220 _transient Database *database_;
4221 PackageTable *packages_;
4225 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4229 @implementation InstalledView
4232 [packages_ release];
4236 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4237 if ((self = [super initWithBook:book]) != nil) {
4238 database_ = database;
4240 packages_ = [[PackageTable alloc]
4244 filter:@selector(isInstalledAndVisible:)
4245 with:[NSNumber numberWithBool:YES]
4248 [self addSubview:packages_];
4250 [self setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
4251 [packages_ setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
4255 - (void) resetViewAnimated:(BOOL)animated {
4256 [packages_ resetViewAnimated:animated];
4259 - (void) reloadData {
4260 [packages_ reloadData];
4263 - (void) _rightButtonClicked {
4264 [packages_ setObject:[NSNumber numberWithBool:expert_]];
4265 [packages_ reloadData];
4267 [book_ reloadButtonsForPage:self];
4270 - (NSString *) title {
4271 return @"Installed";
4274 - (NSString *) backButtonTitle {
4278 - (NSString *) rightButtonTitle {
4279 return Role_ != nil && [Role_ isEqualToString:@"Developer"] ? nil : expert_ ? @"Expert" : @"Simple";
4282 - (UINavigationButtonStyle) rightButtonStyle {
4283 return expert_ ? UINavigationButtonStyleHighlighted : UINavigationButtonStyleNormal;
4286 - (void) setDelegate:(id)delegate {
4287 [super setDelegate:delegate];
4288 [packages_ setDelegate:delegate];
4295 @interface HomeView : BrowserView {
4300 @implementation HomeView
4302 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
4306 - (void) _leftButtonClicked {
4307 UIActionSheet *sheet = [[[UIActionSheet alloc]
4308 initWithTitle:@"About Cydia Installer"
4309 buttons:[NSArray arrayWithObjects:@"Close", nil]
4310 defaultButtonIndex:0
4316 @"Copyright (C) 2008\n"
4317 "Jay Freeman (saurik)\n"
4318 "saurik@saurik.com\n"
4319 "http://www.saurik.com/\n"
4322 "http://www.theokorigroup.com/\n"
4324 "College of Creative Studies,\n"
4325 "University of California,\n"
4327 "http://www.ccs.ucsb.edu/"
4330 [sheet popupAlertAnimated:YES];
4333 - (NSString *) leftButtonTitle {
4339 /* Manage View {{{ */
4340 @interface ManageView : BrowserView {
4345 @implementation ManageView
4347 - (NSString *) title {
4351 - (void) _leftButtonClicked {
4352 [delegate_ askForSettings];
4355 - (NSString *) leftButtonTitle {
4359 - (NSString *) _rightButtonTitle {
4366 @interface WebView (Cydia)
4367 - (void) setScriptDebugDelegate:(id)delegate;
4368 - (void) _setFormDelegate:(id)delegate;
4369 - (void) _setUIKitDelegate:(id)delegate;
4370 - (void) setWebMailDelegate:(id)delegate;
4371 - (void) _setLayoutInterval:(float)interval;
4374 /* Indirect Delegate {{{ */
4375 @interface IndirectDelegate : NSProxy {
4376 _transient volatile id delegate_;
4379 - (void) setDelegate:(id)delegate;
4380 - (id) initWithDelegate:(id)delegate;
4383 @implementation IndirectDelegate
4385 - (void) setDelegate:(id)delegate {
4386 delegate_ = delegate;
4389 - (id) initWithDelegate:(id)delegate {
4390 delegate_ = delegate;
4394 - (NSMethodSignature*) methodSignatureForSelector:(SEL)sel {
4395 if (delegate_ != nil)
4396 if (NSMethodSignature *sig = [delegate_ methodSignatureForSelector:sel])
4398 // XXX: I fucking hate Apple so very very bad
4399 return [NSMethodSignature signatureWithObjCTypes:"v@:"];
4402 - (void) forwardInvocation:(NSInvocation *)inv {
4403 SEL sel = [inv selector];
4404 if (delegate_ != nil && [delegate_ respondsToSelector:sel])
4405 [inv invokeWithTarget:delegate_];
4410 /* Browser Implementation {{{ */
4411 @implementation BrowserView
4414 WebView *webview = [webview_ webView];
4415 [webview setFrameLoadDelegate:nil];
4416 [webview setResourceLoadDelegate:nil];
4417 [webview setUIDelegate:nil];
4418 [webview setScriptDebugDelegate:nil];
4419 [webview setPolicyDelegate:nil];
4421 [webview setDownloadDelegate:nil];
4423 [webview _setFormDelegate:nil];
4424 [webview _setUIKitDelegate:nil];
4425 [webview setWebMailDelegate:nil];
4426 [webview setEditingDelegate:nil];
4428 [webview_ setDelegate:nil];
4429 [webview_ setGestureDelegate:nil];
4431 //NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
4433 /*WebFrame *frame = [webview mainFrame];
4434 [frame loadHTMLString:@"" baseURL:[NSURL URLWithString:@"http://cydia.saurik.com/"]];*/
4438 //[webview_ removeFromSuperview];
4439 //[Documents_ addObject:[webview_ autorelease]];
4442 [indirect_ setDelegate:nil];
4443 [indirect_ release];
4445 [scroller_ setDelegate:nil];
4447 [scroller_ release];
4449 [indicator_ release];
4455 - (void) loadURL:(NSURL *)url cachePolicy:(NSURLRequestCachePolicy)policy {
4456 [self loadRequest:[NSURLRequest
4459 timeoutInterval:30.0
4463 - (void) loadURL:(NSURL *)url {
4464 [self loadURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy];
4467 - (NSURLRequest *) _addHeadersToRequest:(NSURLRequest *)request {
4468 NSMutableURLRequest *copy = [request mutableCopy];
4470 [copy addValue:[NSString stringWithUTF8String:Firmware_] forHTTPHeaderField:@"X-Firmware"];
4471 if (Machine_ != NULL)
4472 [copy addValue:[NSString stringWithUTF8String:Machine_] forHTTPHeaderField:@"X-Machine"];
4473 if (UniqueID_ != nil)
4474 [copy addValue:UniqueID_ forHTTPHeaderField:@"X-Unique-ID"];
4477 [copy addValue:Role_ forHTTPHeaderField:@"X-Role"];
4482 - (void) loadRequest:(NSURLRequest *)request {
4484 [webview_ loadRequest:request];
4487 - (void) reloadURL {
4488 if ([urls_ count] == 0)
4490 NSURL *url = [[[urls_ lastObject] retain] autorelease];
4491 [urls_ removeLastObject];
4492 [self loadURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData];
4495 - (WebView *) webView {
4496 return [webview_ webView];
4499 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame {
4500 [scroller_ setContentSize:frame.size];
4503 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old {
4504 [self view:sender didSetFrame:frame];
4507 - (void) pushPage:(RVPage *)page {
4508 [self setBackButtonTitle:title_];
4509 [page setDelegate:delegate_];
4510 [book_ pushPage:page];
4513 - (BOOL) getSpecial:(NSString *)href {
4517 [href hasPrefix:@"http://ax.phobos.apple.com/"] ||
4518 [href hasPrefix:@"http://phobos.apple.com/"] ||
4519 [href hasPrefix:@"http://www.youtube.com/watch?"] ||
4520 [href hasPrefix:@"tel:"]
4522 [delegate_ openURL:[NSURL URLWithString:href]];
4523 else if ([href hasPrefix:@"mailto:"])
4524 [delegate_ openURL:[NSURL URLWithString:href]];
4525 else if ([href hasPrefix:@"apptapp://package/"])
4526 page = [delegate_ pageForPackage:[href substringFromIndex:18]];
4527 else if ([href hasPrefix:@"cydia://"])
4528 page = [delegate_ pageForURL:[NSURL URLWithString:href] hasTag:NULL];
4529 else if (![href hasPrefix:@"apptapp:"])
4533 [self pushPage:page];
4537 - (void) webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame {
4538 [window setValue:delegate_ forKey:@"cydia"];
4541 - (void) webView:(WebView *)sender willClickElement:(id)element {
4542 if ([[element localName] isEqualToString:@"img"])
4543 do if ((element = [element parentNode]) == nil)
4545 while (![[element localName] isEqualToString:@"a"]);
4546 if (![element respondsToSelector:@selector(href)])
4548 NSString *href = [element href];
4551 [self getSpecial:href];
4554 - (void) webView:(WebView *)sender setStatusText:(NSString *)text {
4555 //lprintf("Status:%s\n", [text UTF8String]);
4558 - (void) _pushPage {
4562 [book_ pushPage:self];
4565 - (NSURLRequest *) webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource {
4566 NSURL *url = [request URL];
4567 if ([self getSpecial:[url absoluteString]])
4570 return [self _addHeadersToRequest:request];
4573 - (BOOL) isSpecialScheme:(NSString *)scheme {
4575 [scheme isEqualToString:@"apptapp"] ||
4576 [scheme isEqualToString:@"cydia"] ||
4577 [scheme isEqualToString:@"mailto"] ||
4578 [scheme isEqualToString:@"tel"];
4581 - (WebView *) _createWebViewWithRequest:(NSURLRequest *)request pushed:(BOOL)pushed {
4582 if (request != nil) {
4583 NSURL *url = [request URL];
4584 NSString *scheme = [url scheme];
4585 NSString *absolute = [url absoluteString];
4587 [self isSpecialScheme:scheme] ||
4588 [absolute hasPrefix:@"http://ax.phobos.apple.com/"] ||
4589 [absolute hasPrefix:@"http://phobos.apple.com/"] ||
4590 [absolute hasPrefix:@"http://www.yahoo.com/watch?"]
4595 [self setBackButtonTitle:title_];
4597 BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease];
4598 [browser setDelegate:delegate_];
4601 [browser loadRequest:[self _addHeadersToRequest:request]];
4602 [book_ pushPage:browser];
4605 return [browser webView];
4608 - (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request {
4609 return [self _createWebViewWithRequest:request pushed:(request != nil)];
4612 - (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request windowFeatures:(NSDictionary *)features {
4613 return [self _createWebViewWithRequest:request pushed:YES];
4616 - (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame {
4617 if ([frame parentFrame] != nil)
4620 title_ = [title retain];
4621 [self setTitle:title];
4624 - (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame {
4625 if ([frame parentFrame] != nil)
4630 [indicator_ startAnimation];
4631 [self reloadButtons];
4633 if (title_ != nil) {
4638 [self setTitle:@"Loading"];
4640 WebView *webview = [webview_ webView];
4641 NSString *href = [webview mainFrameURL];
4642 [urls_ addObject:[NSURL URLWithString:href]];
4644 [scroller_ scrollPointVisibleAtTopLeft:CGPointZero];
4646 CGRect webrect = [scroller_ bounds];
4647 webrect.size.height = 0;
4648 [webview_ setFrame:webrect];
4651 - (void) _finishLoading {
4654 [indicator_ stopAnimation];
4655 [self reloadButtons];
4659 - (BOOL) webView:(WebView *)sender shouldScrollToPoint:(struct CGPoint)point forFrame:(WebFrame *)frame {
4660 return [webview_ webView:sender shouldScrollToPoint:point forFrame:frame];
4663 - (void) webView:(WebView *)sender didReceiveViewportArguments:(id)arguments forFrame:(WebFrame *)frame {
4664 return [webview_ webView:sender didReceiveViewportArguments:arguments forFrame:frame];
4667 - (void) webView:(WebView *)sender needsScrollNotifications:(id)notifications forFrame:(WebFrame *)frame {
4668 return [webview_ webView:sender needsScrollNotifications:notifications forFrame:frame];
4671 - (void) webView:(WebView *)sender didCommitLoadForFrame:(WebFrame *)frame {
4672 return [webview_ webView:sender didCommitLoadForFrame:frame];
4675 - (void) webView:(WebView *)sender didReceiveDocTypeForFrame:(WebFrame *)frame {
4676 return [webview_ webView:sender didReceiveDocTypeForFrame:frame];
4679 - (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
4680 if ([frame parentFrame] == nil)
4681 [self _finishLoading];
4682 return [webview_ webView:sender didFinishLoadForFrame:frame];
4685 - (void) webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
4686 if ([frame parentFrame] != nil)
4688 [self _finishLoading];
4690 [self loadURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@?%@",
4691 [[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"error" ofType:@"html"]] absoluteString],
4692 [[error localizedDescription] stringByAddingPercentEscapes]
4696 - (void) webView:(WebView *)sender addMessageToConsole:(NSDictionary *)dictionary {
4698 lprintf("Console:%s\n", [[dictionary description] UTF8String]);
4702 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4703 if ((self = [super initWithBook:book]) != nil) {
4704 database_ = database;
4707 struct CGRect bounds = [self bounds];
4709 UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:bounds] autorelease];
4710 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
4711 [self addSubview:pinstripe];
4713 scroller_ = [[UIScroller alloc] initWithFrame:bounds];
4714 [self addSubview:scroller_];
4716 [scroller_ setScrollingEnabled:YES];
4717 [scroller_ setAdjustForContentSizeChange:YES];
4718 [scroller_ setClipsSubviews:YES];
4719 [scroller_ setAllowsRubberBanding:YES];
4720 [scroller_ setScrollDecelerationFactor:0.99];
4721 [scroller_ setDelegate:self];
4723 CGRect webrect = [scroller_ bounds];
4724 webrect.size.height = 0;
4726 webview_ = [Documents_ lastObject];
4727 if (webview_ != nil) {
4728 webview_ = [webview_ retain];
4729 [Documents_ removeLastObject];
4730 [webview_ setFrame:webrect];
4732 webview_ = [[UIWebDocumentView alloc] initWithFrame:webrect];
4734 [webview_ setTileSize:CGSizeMake(webrect.size.width, 500)];
4736 [webview_ setTilingEnabled:YES];
4737 [webview_ setTileMinificationFilter:kCAFilterNearest];
4738 [webview_ setAutoresizes:YES];
4740 [webview_ setViewportSize:CGSizeMake(980, -1) forDocumentTypes:0x10];
4741 [webview_ setViewportSize:CGSizeMake(320, -1) forDocumentTypes:0x2];
4742 [webview_ setViewportSize:CGSizeMake(320, -1) forDocumentTypes:0x8];
4744 [webview_ _setDocumentType:0x4];
4746 [webview_ setZoomsFocusedFormControl:YES];
4747 [webview_ setContentsPosition:7];
4748 [webview_ setEnabledGestures:0xa];
4749 [webview_ setValue:[NSNumber numberWithBool:YES] forGestureAttribute:0x4];
4750 [webview_ setValue:[NSNumber numberWithBool:YES] forGestureAttribute:0x7];
4751 [webview_ setSmoothsFonts:YES];
4753 [webview_ setAllowsMessaging:YES];
4756 [webview_ setDelegate:self];
4757 [webview_ setGestureDelegate:self];
4758 [scroller_ addSubview:webview_];
4760 //NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
4762 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:kUIProgressIndicatorStyleMediumWhite];
4763 indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(281, 12, indsize.width, indsize.height)];
4764 [indicator_ setStyle:kUIProgressIndicatorStyleMediumWhite];
4766 Package *package([database_ packageWithName:@"cydia"]);
4767 NSString *application = package == nil ? @"Cydia" : [NSString
4768 stringWithFormat:@"Cydia/%@",
4772 indirect_ = [[IndirectDelegate alloc] initWithDelegate:self];
4774 WebView *webview = [webview_ webView];
4775 [webview setApplicationNameForUserAgent:application];
4776 [webview setFrameLoadDelegate:self];
4777 [webview setResourceLoadDelegate:indirect_];
4778 [webview setUIDelegate:self];
4779 [webview setScriptDebugDelegate:self];
4780 [webview setPolicyDelegate:self];
4782 //[webview _setLayoutInterval:0.5];
4784 urls_ = [[NSMutableArray alloc] initWithCapacity:16];
4786 [self setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
4787 [scroller_ setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
4788 [pinstripe setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
4792 - (void) didFinishGesturesInView:(UIView *)view forEvent:(id)event {
4793 [webview_ redrawScaledDocument];
4796 - (void) _rightButtonClicked {
4801 - (NSString *) _rightButtonTitle {
4805 - (NSString *) rightButtonTitle {
4806 return loading_ ? @"" : [self _rightButtonTitle];
4809 - (NSString *) title {
4813 - (NSString *) backButtonTitle {
4817 - (void) setPageActive:(BOOL)active {
4819 [indicator_ removeFromSuperview];
4821 [[book_ navigationBar] addSubview:indicator_];
4824 - (void) resetViewAnimated:(BOOL)animated {
4827 - (void) setPushed:(bool)pushed {
4834 @interface CYBook : RVBook <
4837 _transient Database *database_;
4838 UINavigationBar *overlay_;
4839 UIProgressIndicator *indicator_;
4840 UITextLabel *prompt_;
4841 UIProgressBar *progress_;
4842 UINavigationButton *cancel_;
4845 NSTimeInterval last_;
4848 - (id) initWithFrame:(CGRect)frame database:(Database *)database;
4854 /* Install View {{{ */
4855 @interface InstallView : RVPage {
4856 _transient Database *database_;
4857 NSMutableArray *sections_;
4858 NSMutableArray *filtered_;
4859 UITransitionView *transition_;
4865 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4866 - (void) reloadData;
4871 @implementation InstallView
4874 [list_ setDataSource:nil];
4875 [list_ setDelegate:nil];
4877 [sections_ release];
4878 [filtered_ release];
4879 [transition_ release];
4881 [accessory_ release];
4885 - (int) numberOfRowsInTable:(UITable *)table {
4886 return editing_ ? [sections_ count] : [filtered_ count] + 1;
4889 - (float) table:(UITable *)table heightForRow:(int)row {
4893 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
4895 reusing = [[[SectionCell alloc] init] autorelease];
4896 [(SectionCell *)reusing setSection:(editing_ ?
4897 [sections_ objectAtIndex:row] :
4898 (row == 0 ? nil : [filtered_ objectAtIndex:(row - 1)])
4899 ) editing:editing_];
4903 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
4907 - (BOOL) table:(UITable *)table canSelectRow:(int)row {
4911 - (void) tableRowSelected:(NSNotification *)notification {
4912 int row = [[notification object] selectedRow];
4923 title = @"All Packages";
4925 section = [filtered_ objectAtIndex:(row - 1)];
4926 name = [section name];
4932 title = @"(No Section)";
4936 PackageTable *table = [[[PackageTable alloc]
4940 filter:@selector(isVisiblyUninstalledInSection:)
4944 [table setDelegate:delegate_];
4946 [book_ pushPage:table];
4949 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4950 if ((self = [super initWithBook:book]) != nil) {
4951 database_ = database;
4953 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
4954 filtered_ = [[NSMutableArray arrayWithCapacity:16] retain];
4956 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
4957 [self addSubview:transition_];
4959 list_ = [[UITable alloc] initWithFrame:[transition_ bounds]];
4960 [transition_ transition:0 toView:list_];
4962 UITableColumn *column = [[[UITableColumn alloc]
4963 initWithTitle:@"Name"
4965 width:[self frame].size.width
4968 [list_ setDataSource:self];
4969 [list_ setSeparatorStyle:1];
4970 [list_ addTableColumn:column];
4971 [list_ setDelegate:self];
4972 [list_ setReusesTableCells:YES];
4976 [self setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
4977 [list_ setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
4981 - (void) reloadData {
4982 NSArray *packages = [database_ packages];
4984 [sections_ removeAllObjects];
4985 [filtered_ removeAllObjects];
4987 NSMutableArray *filtered = [NSMutableArray arrayWithCapacity:[packages count]];
4988 NSMutableDictionary *sections = [NSMutableDictionary dictionaryWithCapacity:32];
4990 for (size_t i(0); i != [packages count]; ++i) {
4991 Package *package([packages objectAtIndex:i]);
4992 NSString *name([package section]);
4995 Section *section([sections objectForKey:name]);
4996 if (section == nil) {
4997 section = [[[Section alloc] initWithName:name] autorelease];
4998 [sections setObject:section forKey:name];
5002 if ([package valid] && [package installed] == nil && [package visible])
5003 [filtered addObject:package];
5006 [sections_ addObjectsFromArray:[sections allValues]];
5007 [sections_ sortUsingSelector:@selector(compareByName:)];
5009 [filtered sortUsingSelector:@selector(compareBySection:)];
5011 Section *section = nil;
5012 for (size_t offset = 0, count = [filtered count]; offset != count; ++offset) {
5013 Package *package = [filtered objectAtIndex:offset];
5014 NSString *name = [package section];
5016 if (section == nil || name != nil && ![[section name] isEqualToString:name]) {
5017 section = name == nil ?
5018 [[[Section alloc] initWithName:nil] autorelease] :
5019 [sections objectForKey:name];
5020 [filtered_ addObject:section];
5023 [section addToCount];
5029 - (void) resetView {
5031 [self _rightButtonClicked];
5034 - (void) resetViewAnimated:(BOOL)animated {
5035 [list_ resetViewAnimated:animated];
5038 - (void) _rightButtonClicked {
5039 if ((editing_ = !editing_))
5042 [delegate_ updateData];
5045 [book_ setTitle:[self title] forPage:self];
5046 [book_ reloadButtonsForPage:self];
5049 - (NSString *) title {
5050 return editing_ ? @"Section Visibility" : @"Install by Section";
5053 - (NSString *) backButtonTitle {
5057 - (NSString *) rightButtonTitle {
5058 return [sections_ count] == 0 ? nil : editing_ ? @"Done" : @"Edit";
5061 - (UINavigationButtonStyle) rightButtonStyle {
5062 return editing_ ? UINavigationButtonStyleHighlighted : UINavigationButtonStyleNormal;
5065 - (UIView *) accessoryView {
5071 /* Changes View {{{ */
5072 @interface ChangesView : RVPage {
5073 _transient Database *database_;
5074 NSMutableArray *packages_;
5075 NSMutableArray *sections_;
5076 UISectionList *list_;
5080 - (id) initWithBook:(RVBook *)book database:(Database *)database;
5081 - (void) reloadData;
5085 @implementation ChangesView
5088 [[list_ table] setDelegate:nil];
5089 [list_ setDataSource:nil];
5091 [packages_ release];
5092 [sections_ release];
5097 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
5098 return [sections_ count];
5101 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
5102 return [[sections_ objectAtIndex:section] name];
5105 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
5106 return [[sections_ objectAtIndex:section] row];
5109 - (int) numberOfRowsInTable:(UITable *)table {
5110 return [packages_ count];
5113 - (float) table:(UITable *)table heightForRow:(int)row {
5114 return [PackageCell heightForPackage:[packages_ objectAtIndex:row]];
5117 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
5119 reusing = [[[PackageCell alloc] init] autorelease];
5120 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
5124 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
5128 - (void) tableRowSelected:(NSNotification *)notification {
5129 int row = [[notification object] selectedRow];
5132 Package *package = [packages_ objectAtIndex:row];
5133 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
5134 [view setDelegate:delegate_];
5135 [view setPackage:package];
5136 [book_ pushPage:view];
5139 - (void) _leftButtonClicked {
5140 [(CYBook *)book_ update];
5141 [self reloadButtons];
5144 - (void) _rightButtonClicked {
5145 [delegate_ distUpgrade];
5148 - (id) initWithBook:(RVBook *)book database:(Database *)database {
5149 if ((self = [super initWithBook:book]) != nil) {
5150 database_ = database;
5152 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
5153 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
5155 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:NO];
5156 [self addSubview:list_];
5158 [list_ setShouldHideHeaderInShortLists:NO];
5159 [list_ setDataSource:self];
5160 //[list_ setSectionListStyle:1];
5162 UITableColumn *column = [[[UITableColumn alloc]
5163 initWithTitle:@"Name"
5165 width:[self frame].size.width
5168 UITable *table = [list_ table];
5169 [table setSeparatorStyle:1];
5170 [table addTableColumn:column];
5171 [table setDelegate:self];
5172 [table setReusesTableCells:YES];
5176 [self setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
5177 [list_ setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
5181 - (void) reloadData {
5182 NSArray *packages = [database_ packages];
5184 [packages_ removeAllObjects];
5185 [sections_ removeAllObjects];
5187 for (size_t i(0); i != [packages count]; ++i) {
5188 Package *package([packages objectAtIndex:i]);
5191 [package installed] == nil && [package valid] && [package visible] ||
5192 [package upgradableAndEssential:NO]
5194 [packages_ addObject:package];
5197 [packages_ sortUsingSelector:@selector(compareForChanges:)];
5199 Section *upgradable = [[[Section alloc] initWithName:@"Available Upgrades"] autorelease];
5200 Section *section = nil;
5203 bool unseens = false;
5205 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, Locale_, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
5207 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
5208 Package *package = [packages_ objectAtIndex:offset];
5210 if ([package upgradableAndEssential:YES]) {
5212 [upgradable addToCount];
5215 NSDate *seen = [package seen];
5220 name = [@"n/a ?" retain];
5222 name = (NSString *) CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen);
5225 if (section == nil || ![[section name] isEqualToString:name]) {
5226 section = [[[Section alloc] initWithName:name row:offset] autorelease];
5227 [sections_ addObject:section];
5231 [section addToCount];
5235 CFRelease(formatter);
5238 Section *last = [sections_ lastObject];
5239 size_t count = [last count];
5240 [packages_ removeObjectsInRange:NSMakeRange([packages_ count] - count, count)];
5241 [sections_ removeLastObject];
5245 [sections_ insertObject:upgradable atIndex:0];
5248 [self reloadButtons];
5251 - (void) resetViewAnimated:(BOOL)animated {
5252 [list_ resetViewAnimated:animated];
5255 - (NSString *) leftButtonTitle {
5256 return [(CYBook *)book_ updating] ? nil : @"Refresh";
5259 - (NSString *) rightButtonTitle {
5260 return upgrades_ == 0 ? nil : [NSString stringWithFormat:@"Upgrade (%u)", upgrades_];
5263 - (NSString *) title {
5269 /* Search View {{{ */
5270 @protocol SearchViewDelegate
5271 - (void) showKeyboard:(BOOL)show;
5274 @interface SearchView : RVPage {
5276 UISearchField *field_;
5277 UITransitionView *transition_;
5278 PackageTable *table_;
5279 UIPreferencesTable *advanced_;
5285 - (id) initWithBook:(RVBook *)book database:(Database *)database;
5286 - (void) reloadData;
5290 @implementation SearchView
5293 [field_ setDelegate:nil];
5295 [accessory_ release];
5297 [transition_ release];
5299 [advanced_ release];
5304 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
5308 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
5310 case 0: return @"Advanced Search (Coming Soon!)";
5312 default: _assert(false);
5316 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
5320 default: _assert(false);
5324 - (void) _showKeyboard:(BOOL)show {
5325 CGSize keysize = [UIKeyboard defaultSize];
5326 CGRect keydown = [book_ pageBounds];
5327 CGRect keyup = keydown;
5328 keyup.size.height -= keysize.height - ButtonBarHeight_;
5330 float delay = KeyboardTime_ * ButtonBarHeight_ / keysize.height;
5332 UIFrameAnimation *animation = [[[UIFrameAnimation alloc] initWithTarget:[table_ list]] autorelease];
5333 [animation setSignificantRectFields:8];
5336 [animation setStartFrame:keydown];
5337 [animation setEndFrame:keyup];
5339 [animation setStartFrame:keyup];
5340 [animation setEndFrame:keydown];
5343 UIAnimator *animator = [UIAnimator sharedAnimator];
5346 addAnimations:[NSArray arrayWithObjects:animation, nil]
5347 withDuration:(KeyboardTime_ - delay)
5352 [animator performSelector:@selector(startAnimation:) withObject:animation afterDelay:delay];
5354 [delegate_ showKeyboard:show];
5357 - (void) textFieldDidBecomeFirstResponder:(UITextField *)field {
5358 [self _showKeyboard:YES];
5361 - (void) textFieldDidResignFirstResponder:(UITextField *)field {
5362 [self _showKeyboard:NO];
5365 - (void) keyboardInputChanged:(UIFieldEditor *)editor {
5367 NSString *text([field_ text]);
5368 [field_ setClearButtonStyle:(text == nil || [text length] == 0 ? 0 : 2)];
5374 - (void) textFieldClearButtonPressed:(UITextField *)field {
5378 - (void) keyboardInputShouldDelete:(id)input {
5382 - (BOOL) keyboardInput:(id)input shouldInsertText:(NSString *)text isMarkedText:(int)marked {
5383 if ([text length] != 1 || [text characterAtIndex:0] != '\n') {
5387 [field_ resignFirstResponder];
5392 - (id) initWithBook:(RVBook *)book database:(Database *)database {
5393 if ((self = [super initWithBook:book]) != nil) {
5394 CGRect pageBounds = [book_ pageBounds];
5396 /*UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:pageBounds] autorelease];
5397 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
5398 [self addSubview:pinstripe];*/
5400 transition_ = [[UITransitionView alloc] initWithFrame:pageBounds];
5401 [self addSubview:transition_];
5403 advanced_ = [[UIPreferencesTable alloc] initWithFrame:pageBounds];
5405 [advanced_ setReusesTableCells:YES];
5406 [advanced_ setDataSource:self];
5407 [advanced_ reloadData];
5409 dimmed_ = [[UIView alloc] initWithFrame:pageBounds];
5410 CGColor dimmed(space_, 0, 0, 0, 0.5);
5411 [dimmed_ setBackgroundColor:[UIColor colorWithCGColor:dimmed]];
5413 table_ = [[PackageTable alloc]
5417 filter:@selector(isUnfilteredAndSearchedForBy:)
5421 [table_ setShouldHideHeaderInShortLists:NO];
5422 [transition_ transition:0 toView:table_];
5431 area.origin.x = /*cnfrect.origin.x + cnfrect.size.width + 4 +*/ 10;
5438 [self bounds].size.width - area.origin.x - 18;
5440 area.size.height = [UISearchField defaultHeight];
5442 field_ = [[UISearchField alloc] initWithFrame:area];
5444 UIFont *font = [UIFont systemFontOfSize:16];
5445 [field_ setFont:font];
5447 [field_ setPlaceholder:@"Package Names & Descriptions"];
5448 [field_ setDelegate:self];
5450 [field_ setPaddingTop:5];
5452 UITextInputTraits *traits = [field_ textInputTraits];
5453 [traits setAutocapitalizationType:0];
5454 [traits setAutocorrectionType:1];
5455 [traits setReturnKeyType:6];
5457 CGRect accrect = {{0, 6}, {6 + cnfrect.size.width + 6 + area.size.width + 6, area.size.height}};
5459 accessory_ = [[UIView alloc] initWithFrame:accrect];
5460 [accessory_ addSubview:field_];
5462 /*UIPushButton *configure = [[[UIPushButton alloc] initWithFrame:cnfrect] autorelease];
5463 [configure setShowPressFeedback:YES];
5464 [configure setImage:[UIImage applicationImageNamed:@"advanced.png"]];
5465 [configure addTarget:self action:@selector(configurePushed) forEvents:1];
5466 [accessory_ addSubview:configure];*/
5468 [self setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
5469 [table_ setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
5475 LKAnimation *animation = [LKTransition animation];
5476 [animation setType:@"oglFlip"];
5477 [animation setTimingFunction:[LKTimingFunction functionWithName:@"easeInEaseOut"]];
5478 [animation setFillMode:@"extended"];
5479 [animation setTransitionFlags:3];
5480 [animation setDuration:10];
5481 [animation setSpeed:0.35];
5482 [animation setSubtype:(flipped_ ? @"fromLeft" : @"fromRight")];
5483 [[transition_ _layer] addAnimation:animation forKey:0];
5484 [transition_ transition:0 toView:(flipped_ ? (UIView *) table_ : (UIView *) advanced_)];
5485 flipped_ = !flipped_;
5489 - (void) configurePushed {
5490 [field_ resignFirstResponder];
5494 - (void) resetViewAnimated:(BOOL)animated {
5497 [table_ resetViewAnimated:animated];
5500 - (void) reloadData {
5503 [table_ setObject:[field_ text]];
5504 [table_ reloadData];
5505 [table_ resetCursor];
5508 - (UIView *) accessoryView {
5512 - (NSString *) title {
5516 - (NSString *) backButtonTitle {
5520 - (void) setDelegate:(id)delegate {
5521 [table_ setDelegate:delegate];
5522 [super setDelegate:delegate];
5528 @implementation CYBook
5532 [indicator_ release];
5534 [progress_ release];
5539 - (NSString *) getTitleForPage:(RVPage *)page {
5540 return Simplify([super getTitleForPage:page]);
5548 [UIView beginAnimations:nil context:NULL];
5550 CGRect ovrframe = [overlay_ frame];
5551 ovrframe.origin.y = 0;
5552 [overlay_ setFrame:ovrframe];
5554 CGRect barframe = [navbar_ frame];
5555 barframe.origin.y += ovrframe.size.height;
5556 [navbar_ setFrame:barframe];
5558 CGRect trnframe = [transition_ frame];
5559 trnframe.origin.y += ovrframe.size.height;
5560 trnframe.size.height -= ovrframe.size.height;
5561 [transition_ setFrame:trnframe];
5563 [UIView endAnimations];
5565 [indicator_ startAnimation];
5566 [prompt_ setText:@"Updating Database"];
5567 [progress_ setProgress:0];
5570 last_ = [NSDate timeIntervalSinceReferenceDate];
5572 [overlay_ addSubview:cancel_];
5575 detachNewThreadSelector:@selector(_update)
5584 [indicator_ stopAnimation];
5586 [UIView beginAnimations:nil context:NULL];
5588 CGRect ovrframe = [overlay_ frame];
5589 ovrframe.origin.y = -ovrframe.size.height;
5590 [overlay_ setFrame:ovrframe];
5592 CGRect barframe = [navbar_ frame];
5593 barframe.origin.y -= ovrframe.size.height;
5594 [navbar_ setFrame:barframe];
5596 CGRect trnframe = [transition_ frame];
5597 trnframe.origin.y -= ovrframe.size.height;
5598 trnframe.size.height += ovrframe.size.height;
5599 [transition_ setFrame:trnframe];
5601 [UIView commitAnimations];
5603 [delegate_ performSelector:@selector(reloadData) withObject:nil afterDelay:0];
5606 - (id) initWithFrame:(CGRect)frame database:(Database *)database {
5607 if ((self = [super initWithFrame:frame]) != nil) {
5608 database_ = database;
5610 CGRect ovrrect = [navbar_ bounds];
5611 ovrrect.size.height = [UINavigationBar defaultSize].height;
5612 ovrrect.origin.y = -ovrrect.size.height;
5614 overlay_ = [[UINavigationBar alloc] initWithFrame:ovrrect];
5615 [self addSubview:overlay_];
5617 [overlay_ setBarStyle:1];
5618 int barstyle = [overlay_ _barStyle:NO];
5619 bool ugly = barstyle == 0;
5621 UIProgressIndicatorStyle style = ugly ?
5622 kUIProgressIndicatorStyleMediumBrown :
5623 kUIProgressIndicatorStyleMediumWhite;
5625 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:style];
5626 unsigned indoffset = (ovrrect.size.height - indsize.height) / 2;
5627 CGRect indrect = {{indoffset, indoffset}, indsize};
5629 indicator_ = [[UIProgressIndicator alloc] initWithFrame:indrect];
5630 [indicator_ setStyle:style];
5631 [overlay_ addSubview:indicator_];
5633 CGSize prmsize = {215, indsize.height + 4};
5636 indoffset * 2 + indsize.width,
5640 unsigned(ovrrect.size.height - prmsize.height) / 2
5643 UIFont *font = [UIFont systemFontOfSize:15];
5645 prompt_ = [[UITextLabel alloc] initWithFrame:prmrect];
5647 [prompt_ setColor:[UIColor colorWithCGColor:(ugly ? Blueish_ : Off_)]];
5648 [prompt_ setBackgroundColor:[UIColor clearColor]];
5649 [prompt_ setFont:font];
5651 [overlay_ addSubview:prompt_];
5653 CGSize prgsize = {75, 100};
5656 ovrrect.size.width - prgsize.width - 10,
5657 (ovrrect.size.height - prgsize.height) / 2
5660 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
5661 [progress_ setStyle:0];
5662 [overlay_ addSubview:progress_];
5664 cancel_ = [[UINavigationButton alloc] initWithTitle:@"Cancel" style:UINavigationButtonStyleHighlighted];
5665 [cancel_ addTarget:self action:@selector(_onCancel) forControlEvents:UIControlEventTouchUpInside];
5667 CGRect frame = [cancel_ frame];
5668 frame.size.width = 65;
5669 frame.origin.x = ovrrect.size.width - frame.size.width - 5;
5670 frame.origin.y = (ovrrect.size.height - frame.size.height) / 2;
5671 [cancel_ setFrame:frame];
5673 [cancel_ setBarStyle:barstyle];
5677 - (void) _onCancel {
5679 [cancel_ removeFromSuperview];
5683 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5686 status.setDelegate(self);
5688 [database_ updateWithStatus:status];
5691 performSelectorOnMainThread:@selector(_update_)
5699 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id {
5700 [prompt_ setText:[NSString stringWithFormat:@"Error: %@", error]];
5703 - (void) setProgressTitle:(NSString *)title {
5705 performSelectorOnMainThread:@selector(_setProgressTitle:)
5711 - (void) setProgressPercent:(float)percent {
5713 performSelectorOnMainThread:@selector(_setProgressPercent:)
5714 withObject:[NSNumber numberWithFloat:percent]
5719 - (void) startProgress {
5722 - (void) addProgressOutput:(NSString *)output {
5724 performSelectorOnMainThread:@selector(_addProgressOutput:)
5730 - (bool) isCancelling:(size_t)received {
5731 NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate];
5732 if (received_ != received) {
5733 received_ = received;
5735 } else if (now - last_ > 15)
5740 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
5744 - (void) _setProgressTitle:(NSString *)title {
5745 [prompt_ setText:title];
5748 - (void) _setProgressPercent:(NSNumber *)percent {
5749 [progress_ setProgress:[percent floatValue]];
5752 - (void) _addProgressOutput:(NSString *)output {
5757 @interface Cydia : UIApplication <
5758 ConfirmationViewDelegate,
5759 ProgressViewDelegate,
5768 UIToolbar *buttonbar_;
5770 ConfirmationView *confirm_;
5772 NSMutableArray *essential_;
5773 NSMutableArray *broken_;
5775 Database *database_;
5776 ProgressView *progress_;
5780 UIKeyboard *keyboard_;
5781 UIProgressHUD *hud_;
5783 InstallView *install_;
5784 ChangesView *changes_;
5785 ManageView *manage_;
5786 SearchView *search_;
5791 @implementation Cydia
5794 if ([broken_ count] != 0) {
5795 int count = [broken_ count];
5797 UIActionSheet *sheet = [[[UIActionSheet alloc]
5798 initWithTitle:[NSString stringWithFormat:@"%d Half-Installed Package%@", count, (count == 1 ? @"" : @"s")]
5799 buttons:[NSArray arrayWithObjects:
5801 @"Ignore (Temporary)",
5803 defaultButtonIndex:0
5808 [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."];
5809 [sheet popupAlertAnimated:YES];
5810 } else if (!Ignored_ && [essential_ count] != 0) {
5811 int count = [essential_ count];
5813 UIActionSheet *sheet = [[[UIActionSheet alloc]
5814 initWithTitle:[NSString stringWithFormat:@"%d Essential Upgrade%@", count, (count == 1 ? @"" : @"s")]
5815 buttons:[NSArray arrayWithObjects:@"Upgrade Essential", @"Ignore (Temporary)", nil]
5816 defaultButtonIndex:0
5821 [sheet setBodyText:@"One or more essential packages are currently out of date. If these upgrades are not performed you are likely to encounter errors."];
5822 [sheet popupAlertAnimated:YES];
5826 - (void) _reloadData {
5827 /*UIProgressHUD *hud = [[UIProgressHUD alloc] initWithWindow:window_];
5828 [hud setText:@"Reloading Data"];
5829 [overlay_ addSubview:hud];
5832 [database_ reloadData];
5836 [essential_ removeAllObjects];
5837 [broken_ removeAllObjects];
5839 NSArray *packages = [database_ packages];
5840 for (int i(0), e([packages count]); i != e; ++i) {
5841 Package *package = [packages objectAtIndex:i];
5843 [broken_ addObject:package];
5844 if ([package upgradableAndEssential:NO]) {
5845 if ([package essential])
5846 [essential_ addObject:package];
5852 NSString *badge([[NSNumber numberWithInt:changes] stringValue]);
5853 [buttonbar_ setBadgeValue:badge forButton:3];
5854 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
5855 [buttonbar_ setBadgeAnimated:YES forButton:3];
5856 [self setApplicationBadge:badge];
5858 [buttonbar_ setBadgeValue:nil forButton:3];
5859 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
5860 [buttonbar_ setBadgeAnimated:NO forButton:3];
5861 [self removeApplicationBadge];
5867 if ([packages count] == 0);
5879 [hud removeFromSuperview];*/
5882 - (void) _saveConfig {
5884 _assert([Metadata_ writeToFile:@"/var/lib/cydia/metadata.plist" atomically:YES] == YES);
5889 - (void) updateData {
5892 /* XXX: this is just stupid */
5894 [install_ reloadData];
5896 [changes_ reloadData];
5898 [search_ reloadData];
5908 FILE *file = fopen("/etc/apt/sources.list.d/cydia.list", "w");
5909 _assert(file != NULL);
5911 NSArray *keys = [Sources_ allKeys];
5913 for (int i(0), e([keys count]); i != e; ++i) {
5914 NSString *key = [keys objectAtIndex:i];
5915 NSDictionary *source = [Sources_ objectForKey:key];
5917 fprintf(file, "%s %s %s\n",
5918 [[source objectForKey:@"Type"] UTF8String],
5919 [[source objectForKey:@"URI"] UTF8String],
5920 [[source objectForKey:@"Distribution"] UTF8String]
5929 detachNewThreadSelector:@selector(update_)
5932 title:@"Updating Sources"
5936 - (void) reloadData {
5937 @synchronized (self) {
5938 if (confirm_ == nil)
5944 pkgProblemResolver *resolver = [database_ resolver];
5946 resolver->InstallProtect();
5947 if (!resolver->Resolve(true))
5952 [database_ prepare];
5954 if ([database_ cache]->BrokenCount() == 0)
5955 confirm_ = [[ConfirmationView alloc] initWithView:underlay_ delegate:self database:database_];
5957 NSMutableArray *broken = [NSMutableArray arrayWithCapacity:16];
5958 NSArray *packages = [database_ packages];
5960 for (size_t i(0); i != [packages count]; ++i) {
5961 Package *package = [packages objectAtIndex:i];
5962 if ([package broken])
5963 [broken addObject:[package name]];
5966 UIActionSheet *sheet = [[[UIActionSheet alloc]
5967 initWithTitle:[NSString stringWithFormat:@"%d Broken Packages", [database_ cache]->BrokenCount()]
5968 buttons:[NSArray arrayWithObjects:@"Okay", nil]
5969 defaultButtonIndex:0
5974 [sheet setBodyText:[NSString stringWithFormat:@"The following packages have unmet dependencies:\n\n%@", [broken componentsJoinedByString:@"\n"]]];
5975 [sheet popupAlertAnimated:YES];
5981 - (void) installPackage:(Package *)package {
5982 @synchronized (self) {
5989 - (void) removePackage:(Package *)package {
5990 @synchronized (self) {
5997 - (void) distUpgrade {
5998 @synchronized (self) {
5999 [database_ upgrade];
6005 @synchronized (self) {
6007 if (confirm_ != nil) {
6015 [overlay_ removeFromSuperview];
6019 detachNewThreadSelector:@selector(perform)
6026 - (void) bootstrap_ {
6028 [database_ upgrade];
6029 [database_ prepare];
6030 [database_ perform];
6033 - (void) bootstrap {
6035 detachNewThreadSelector:@selector(bootstrap_)
6038 title:@"Bootstrap Install"
6042 - (void) progressViewIsComplete:(ProgressView *)progress {
6043 if (confirm_ != nil) {
6044 [underlay_ addSubview:overlay_];
6045 [confirm_ removeFromSuperview];
6051 - (void) setPage:(RVPage *)page {
6052 [page resetViewAnimated:NO];
6053 [page setDelegate:self];
6054 [book_ setPage:page];
6057 - (RVPage *) _pageForURL:(NSURL *)url withClass:(Class)_class {
6058 BrowserView *browser = [[[_class alloc] initWithBook:book_ database:database_] autorelease];
6059 [browser loadURL:url];
6063 - (void) _setHomePage {
6064 [self setPage:[self _pageForURL:[NSURL URLWithString:@"http://cydia.saurik.com/"] withClass:[HomeView class]]];
6067 - (void) buttonBarItemTapped:(id)sender {
6068 unsigned tag = [sender tag];
6070 [book_ resetViewAnimated:YES];
6072 } else if (tag_ == 2 && tag != 2)
6073 [install_ resetView];
6076 case 1: [self _setHomePage]; break;
6078 case 2: [self setPage:install_]; break;
6079 case 3: [self setPage:changes_]; break;
6080 case 4: [self setPage:manage_]; break;
6081 case 5: [self setPage:search_]; break;
6083 default: _assert(false);
6089 - (void) applicationWillSuspend {
6091 [super applicationWillSuspend];
6094 - (void) askForSettings {
6095 UIActionSheet *role = [[[UIActionSheet alloc]
6096 initWithTitle:@"Who Are You?"
6097 buttons:[NSArray arrayWithObjects:
6098 @"User (Graphical Only)",
6099 @"Hacker (+ Command Line)",
6100 @"Developer (No Filters)",
6102 defaultButtonIndex:-1
6107 [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."];
6108 [role popupAlertAnimated:YES];
6113 [self setStatusBarShowsProgress:NO];
6116 [hud_ removeFromSuperview];
6120 pid_t pid = ExecFork();
6122 execlp("launchctl", "launchctl", "stop", "com.apple.SpringBoard", NULL);
6123 perror("launchctl stop");
6130 [self askForSettings];
6134 overlay_ = [[UIView alloc] initWithFrame:[underlay_ bounds]];
6136 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
6137 book_ = [[CYBook alloc] initWithFrame:CGRectMake(
6138 0, 0, screenrect.size.width, screenrect.size.height - 48
6139 ) database:database_];
6141 [book_ setDelegate:self];
6143 [overlay_ addSubview:book_];
6145 NSArray *buttonitems = [NSArray arrayWithObjects:
6146 [NSDictionary dictionaryWithObjectsAndKeys:
6147 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
6148 @"home-up.png", kUIButtonBarButtonInfo,
6149 @"home-dn.png", kUIButtonBarButtonSelectedInfo,
6150 [NSNumber numberWithInt:1], kUIButtonBarButtonTag,
6151 self, kUIButtonBarButtonTarget,
6152 @"Home", kUIButtonBarButtonTitle,
6153 @"0", kUIButtonBarButtonType,
6156 [NSDictionary dictionaryWithObjectsAndKeys:
6157 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
6158 @"install-up.png", kUIButtonBarButtonInfo,
6159 @"install-dn.png", kUIButtonBarButtonSelectedInfo,
6160 [NSNumber numberWithInt:2], kUIButtonBarButtonTag,
6161 self, kUIButtonBarButtonTarget,
6162 @"Sections", kUIButtonBarButtonTitle,
6163 @"0", kUIButtonBarButtonType,
6166 [NSDictionary dictionaryWithObjectsAndKeys:
6167 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
6168 @"changes-up.png", kUIButtonBarButtonInfo,
6169 @"changes-dn.png", kUIButtonBarButtonSelectedInfo,
6170 [NSNumber numberWithInt:3], kUIButtonBarButtonTag,
6171 self, kUIButtonBarButtonTarget,
6172 @"Changes", kUIButtonBarButtonTitle,
6173 @"0", kUIButtonBarButtonType,
6176 [NSDictionary dictionaryWithObjectsAndKeys:
6177 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
6178 @"manage-up.png", kUIButtonBarButtonInfo,
6179 @"manage-dn.png", kUIButtonBarButtonSelectedInfo,
6180 [NSNumber numberWithInt:4], kUIButtonBarButtonTag,
6181 self, kUIButtonBarButtonTarget,
6182 @"Manage", kUIButtonBarButtonTitle,
6183 @"0", kUIButtonBarButtonType,
6186 [NSDictionary dictionaryWithObjectsAndKeys:
6187 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
6188 @"search-up.png", kUIButtonBarButtonInfo,
6189 @"search-dn.png", kUIButtonBarButtonSelectedInfo,
6190 [NSNumber numberWithInt:5], kUIButtonBarButtonTag,
6191 self, kUIButtonBarButtonTarget,
6192 @"Search", kUIButtonBarButtonTitle,
6193 @"0", kUIButtonBarButtonType,
6197 buttonbar_ = [[UIToolbar alloc]
6199 withFrame:CGRectMake(
6200 0, screenrect.size.height - ButtonBarHeight_,
6201 screenrect.size.width, ButtonBarHeight_
6203 withItemList:buttonitems
6206 [buttonbar_ setDelegate:self];
6207 [buttonbar_ setBarStyle:1];
6208 [buttonbar_ setButtonBarTrackingMode:2];
6210 int buttons[5] = {1, 2, 3, 4, 5};
6211 [buttonbar_ registerButtonGroup:0 withButtons:buttons withCount:5];
6212 [buttonbar_ showButtonGroup:0 withDuration:0];
6214 for (int i = 0; i != 5; ++i)
6215 [[buttonbar_ viewWithTag:(i + 1)] setFrame:CGRectMake(
6216 i * 64 + 2, 1, 60, ButtonBarHeight_
6219 [buttonbar_ showSelectionForButton:1];
6220 [overlay_ addSubview:buttonbar_];
6222 [UIKeyboard initImplementationNow];
6223 CGSize keysize = [UIKeyboard defaultSize];
6224 CGRect keyrect = {{0, [overlay_ bounds].size.height}, keysize};
6225 keyboard_ = [[UIKeyboard alloc] initWithFrame:keyrect];
6226 [[UIKeyboardImpl sharedInstance] setSoundsEnabled:(Sounds_Keyboard_ ? YES : NO)];
6227 [overlay_ addSubview:keyboard_];
6229 install_ = [[InstallView alloc] initWithBook:book_ database:database_];
6230 changes_ = [[ChangesView alloc] initWithBook:book_ database:database_];
6231 search_ = [[SearchView alloc] initWithBook:book_ database:database_];
6233 manage_ = (ManageView *) [[self
6234 _pageForURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"manage" ofType:@"html"]]
6235 withClass:[ManageView class]
6239 [underlay_ addSubview:overlay_];
6246 [self _setHomePage];
6249 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
6250 NSString *context = [sheet context];
6251 if ([context isEqualToString:@"fixhalf"])
6254 @synchronized (self) {
6255 for (int i = 0, e = [broken_ count]; i != e; ++i) {
6256 Package *broken = [broken_ objectAtIndex:i];
6259 NSString *id = [broken id];
6260 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.prerm", id] UTF8String]);
6261 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.postrm", id] UTF8String]);
6262 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.preinst", id] UTF8String]);
6263 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.postinst", id] UTF8String]);
6272 [broken_ removeAllObjects];
6279 else if ([context isEqualToString:@"role"]) {
6281 case 1: Role_ = @"User"; break;
6282 case 2: Role_ = @"Hacker"; break;
6283 case 3: Role_ = @"Developer"; break;
6290 bool reset = Settings_ != nil;
6292 Settings_ = [NSMutableDictionary dictionaryWithObjectsAndKeys:
6296 [Metadata_ setObject:Settings_ forKey:@"Settings"];
6304 } else if ([context isEqualToString:@"upgrade"])
6307 @synchronized (self) {
6308 for (int i = 0, e = [essential_ count]; i != e; ++i) {
6309 Package *essential = [essential_ objectAtIndex:i];
6310 [essential install];
6329 - (void) reorganize {
6330 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
6331 system("/usr/libexec/cydia/free.sh");
6332 [self performSelectorOnMainThread:@selector(finish) withObject:nil waitUntilDone:NO];
6336 - (void) applicationSuspend:(__GSEvent *)event {
6337 if (hud_ == nil && ![progress_ isRunning])
6338 [super applicationSuspend:event];
6341 - (void) _animateSuspension:(BOOL)arg0 duration:(double)arg1 startTime:(double)arg2 scale:(float)arg3 {
6343 [super _animateSuspension:arg0 duration:arg1 startTime:arg2 scale:arg3];
6346 - (void) _setSuspended:(BOOL)value {
6348 [super _setSuspended:value];
6351 - (UIProgressHUD *) addProgressHUD {
6352 UIProgressHUD *hud = [[UIProgressHUD alloc] initWithWindow:window_];
6354 [underlay_ addSubview:hud];
6358 - (void) openMailToURL:(NSURL *)url {
6359 [[[MailToView alloc] initWithView:underlay_ delegate:self url:url] autorelease];
6362 - (RVPage *) pageForPackage:(NSString *)name {
6363 if (Package *package = [database_ packageWithName:name]) {
6364 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
6365 [view setPackage:package];
6368 UIActionSheet *sheet = [[[UIActionSheet alloc]
6369 initWithTitle:@"Cannot Locate Package"
6370 buttons:[NSArray arrayWithObjects:@"Close", nil]
6371 defaultButtonIndex:0
6376 [sheet setBodyText:[NSString stringWithFormat:
6377 @"The package %@ cannot be found in your current sources. I might recommend installing more sources."
6380 [sheet popupAlertAnimated:YES];
6385 - (RVPage *) pageForURL:(NSURL *)url hasTag:(int *)tag {
6386 NSString *href = [url absoluteString];
6391 if ([href isEqualToString:@"cydia://add-source"])
6392 return [[[AddSourceView alloc] initWithBook:book_ database:database_] autorelease];
6393 else if ([href isEqualToString:@"cydia://sources"])
6394 return [[[SourceTable alloc] initWithBook:book_ database:database_] autorelease];
6395 else if ([href isEqualToString:@"cydia://packages"])
6396 return [[[InstalledView alloc] initWithBook:book_ database:database_] autorelease];
6397 else if ([href hasPrefix:@"cydia://url/"])
6398 return [self _pageForURL:[NSURL URLWithString:[href substringFromIndex:12]] withClass:[BrowserView class]];
6399 else if ([href hasPrefix:@"cydia://package/"])
6400 return [self pageForPackage:[href substringFromIndex:16]];
6401 else if ([href hasPrefix:@"cydia://files/"]) {
6402 NSString *name = [href substringFromIndex:14];
6404 if (Package *package = [database_ packageWithName:name]) {
6405 FileTable *files = [[[FileTable alloc] initWithBook:book_ database:database_] autorelease];
6406 [files setPackage:package];
6414 - (void) applicationOpenURL:(NSURL *)url {
6415 [super applicationOpenURL:url];
6417 if (RVPage *page = [self pageForURL:url hasTag:&tag]) {
6418 [self setPage:page];
6419 [buttonbar_ showSelectionForButton:tag];
6424 - (void) applicationDidFinishLaunching:(id)unused {
6425 Font12_ = [[UIFont systemFontOfSize:12] retain];
6426 Font12Bold_ = [[UIFont boldSystemFontOfSize:12] retain];
6427 Font14_ = [[UIFont systemFontOfSize:14] retain];
6428 Font18Bold_ = [[UIFont boldSystemFontOfSize:18] retain];
6429 Font22Bold_ = [[UIFont boldSystemFontOfSize:22] retain];
6431 _assert(pkgInitConfig(*_config));
6432 _assert(pkgInitSystem(*_config, _system));
6436 essential_ = [[NSMutableArray alloc] initWithCapacity:4];
6437 broken_ = [[NSMutableArray alloc] initWithCapacity:4];
6439 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
6440 window_ = [[UIWindow alloc] initWithContentRect:screenrect];
6442 [window_ orderFront:self];
6443 [window_ makeKey:self];
6444 [window_ setHidden:NO];
6446 database_ = [[Database alloc] init];
6447 progress_ = [[ProgressView alloc] initWithFrame:[window_ bounds] database:database_ delegate:self];
6448 [database_ setDelegate:progress_];
6449 [window_ setContentView:progress_];
6451 underlay_ = [[UIView alloc] initWithFrame:[progress_ bounds]];
6452 [progress_ setContentView:underlay_];
6454 [progress_ resetView];
6457 readlink("/Applications", NULL, 0) == -1 && errno == EINVAL ||
6458 readlink("/Library/Ringtones", NULL, 0) == -1 && errno == EINVAL ||
6459 readlink("/Library/Wallpaper", NULL, 0) == -1 && errno == EINVAL ||
6460 readlink("/usr/include", NULL, 0) == -1 && errno == EINVAL ||
6461 readlink("/usr/libexec", NULL, 0) == -1 && errno == EINVAL ||
6462 readlink("/usr/share", NULL, 0) == -1 && errno == EINVAL /*||
6463 readlink("/var/lib", NULL, 0) == -1 && errno == EINVAL*/
6465 [self setIdleTimerDisabled:YES];
6467 hud_ = [self addProgressHUD];
6468 [hud_ setText:@"Reorganizing\n\nWill Automatically\nRestart When Done"];
6470 [self setStatusBarShowsProgress:YES];
6473 detachNewThreadSelector:@selector(reorganize)
6481 + (NSString *) webScriptNameForSelector:(SEL)selector {
6482 if (selector == @selector(supports:))
6487 - (BOOL) supports:(NSString *)feature {
6488 return [feature isEqualToString:@"window.open"];
6491 + (BOOL) isSelectorExcludedFromWebScript:(SEL)selector {
6492 NSLog(@"exc:%s", sel_getName(selector));
6493 return selector != @selector(supports:);
6496 - (void) showKeyboard:(BOOL)show {
6497 CGSize keysize = [UIKeyboard defaultSize];
6498 CGRect keydown = {{0, [overlay_ bounds].size.height}, keysize};
6499 CGRect keyup = keydown;
6500 keyup.origin.y -= keysize.height;
6502 UIFrameAnimation *animation = [[[UIFrameAnimation alloc] initWithTarget:keyboard_] autorelease];
6503 [animation setSignificantRectFields:2];
6506 [animation setStartFrame:keydown];
6507 [animation setEndFrame:keyup];
6508 [keyboard_ activate];
6510 [animation setStartFrame:keyup];
6511 [animation setEndFrame:keydown];
6512 [keyboard_ deactivate];
6515 [[UIAnimator sharedAnimator]
6516 addAnimations:[NSArray arrayWithObjects:animation, nil]
6517 withDuration:KeyboardTime_
6522 - (void) slideUp:(UIActionSheet *)alert {
6524 [alert presentSheetFromButtonBar:buttonbar_];
6526 [alert presentSheetInView:overlay_];
6531 void AddPreferences(NSString *plist) {
6532 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
6534 NSMutableDictionary *settings = [[[NSMutableDictionary alloc] initWithContentsOfFile:plist] autorelease];
6535 _assert(settings != NULL);
6536 NSMutableArray *items = [settings objectForKey:@"items"];
6540 for (size_t i(0); i != [items count]; ++i) {
6541 NSMutableDictionary *item([items objectAtIndex:i]);
6542 NSString *label = [item objectForKey:@"label"];
6543 if (label != nil && [label isEqualToString:@"Cydia"]) {
6550 for (size_t i(0); i != [items count]; ++i) {
6551 NSDictionary *item([items objectAtIndex:i]);
6552 NSString *label = [item objectForKey:@"label"];
6553 if (label != nil && [label isEqualToString:@"General"]) {
6554 [items insertObject:[NSDictionary dictionaryWithObjectsAndKeys:
6555 @"CydiaSettings", @"bundle",
6556 @"PSLinkCell", @"cell",
6557 [NSNumber numberWithBool:YES], @"hasIcon",
6558 [NSNumber numberWithBool:YES], @"isController",
6560 nil] atIndex:(i + 1)];
6566 _assert([settings writeToFile:plist atomically:YES] == YES);
6573 id Alloc_(id self, SEL selector) {
6574 id object = alloc_(self, selector);
6575 lprintf("[%s]A-%p\n", self->isa->name, object);
6580 id Dealloc_(id self, SEL selector) {
6581 id object = dealloc_(self, selector);
6582 lprintf("[%s]D-%p\n", self->isa->name, object);
6586 int main(int argc, char *argv[]) {
6587 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
6589 bootstrap_ = argc > 1 && strcmp(argv[1], "--bootstrap") == 0;
6591 App_ = [[NSBundle mainBundle] bundlePath];
6592 Home_ = NSHomeDirectory();
6593 Locale_ = CFLocaleCopyCurrent();
6596 NSString *plist = [Home_ stringByAppendingString:@"/Library/Preferences/com.apple.preferences.sounds.plist"];
6597 if (NSDictionary *sounds = [NSDictionary dictionaryWithContentsOfFile:plist])
6598 if (NSNumber *keyboard = [sounds objectForKey:@"keyboard"])
6599 Sounds_Keyboard_ = [keyboard boolValue];
6605 if (unlink("/var/cache/apt/pkgcache.bin") == -1)
6606 _assert(errno == ENOENT);
6607 if (unlink("/var/cache/apt/srcpkgcache.bin") == -1)
6608 _assert(errno == ENOENT);
6610 /*Method alloc = class_getClassMethod([NSObject class], @selector(alloc));
6611 alloc_ = alloc->method_imp;
6612 alloc->method_imp = (IMP) &Alloc_;*/
6614 /*Method dealloc = class_getClassMethod([NSObject class], @selector(dealloc));
6615 dealloc_ = dealloc->method_imp;
6616 dealloc->method_imp = (IMP) &Dealloc_;*/
6618 if (NSDictionary *sysver = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]) {
6619 if (NSString *prover = [sysver valueForKey:@"ProductVersion"]) {
6620 Firmware_ = strdup([prover UTF8String]);
6621 NSArray *versions = [prover componentsSeparatedByString:@"."];
6622 int count = [versions count];
6623 Major_ = count > 0 ? [[versions objectAtIndex:0] intValue] : 0;
6624 Minor_ = count > 1 ? [[versions objectAtIndex:1] intValue] : 0;
6625 BugFix_ = count > 2 ? [[versions objectAtIndex:2] intValue] : 0;
6632 size = sizeof(maxproc);
6633 if (sysctlbyname("kern.maxproc", &maxproc, &size, NULL, 0) == -1)
6634 perror("sysctlbyname(\"kern.maxproc\", ?)");
6635 else if (maxproc < 64) {
6637 if (sysctlbyname("kern.maxproc", NULL, NULL, &maxproc, sizeof(maxproc)) == -1)
6638 perror("sysctlbyname(\"kern.maxproc\", #)");
6641 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
6642 char *machine = new char[size];
6643 if (sysctlbyname("hw.machine", machine, &size, NULL, 0) == -1)
6644 perror("sysctlbyname(\"hw.machine\", ?)");
6648 UniqueID_ = [[UIDevice currentDevice] uniqueIdentifier];
6650 /*AddPreferences(@"/Applications/Preferences.app/Settings-iPhone.plist");
6651 AddPreferences(@"/Applications/Preferences.app/Settings-iPod.plist");*/
6653 if ((Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"]) == NULL)
6654 Metadata_ = [[NSMutableDictionary alloc] initWithCapacity:2];
6656 Settings_ = [Metadata_ objectForKey:@"Settings"];
6658 Packages_ = [Metadata_ objectForKey:@"Packages"];
6659 Sections_ = [Metadata_ objectForKey:@"Sections"];
6660 Sources_ = [Metadata_ objectForKey:@"Sources"];
6663 if (Settings_ != nil)
6664 Role_ = [Settings_ objectForKey:@"Role"];
6666 if (Packages_ == nil) {
6667 Packages_ = [[[NSMutableDictionary alloc] initWithCapacity:128] autorelease];
6668 [Metadata_ setObject:Packages_ forKey:@"Packages"];
6671 if (Sections_ == nil) {
6672 Sections_ = [[[NSMutableDictionary alloc] initWithCapacity:32] autorelease];
6673 [Metadata_ setObject:Sections_ forKey:@"Sections"];
6676 if (Sources_ == nil) {
6677 Sources_ = [[[NSMutableDictionary alloc] initWithCapacity:0] autorelease];
6678 [Metadata_ setObject:Sources_ forKey:@"Sources"];
6681 Documents_ = [[[NSMutableArray alloc] initWithCapacity:4] autorelease];
6683 if (access("/Library/MobileSubstrate/MobileSubstrate.dylib", F_OK) == 0)
6684 dlopen("/Library/MobileSubstrate/MobileSubstrate.dylib", RTLD_LAZY | RTLD_GLOBAL);
6686 if (access("/User", F_OK) != 0)
6687 system("/usr/libexec/cydia/firmware.sh");
6689 _assert([[NSFileManager defaultManager]
6690 createDirectoryAtPath:@"/var/cache/apt/archives/partial"
6691 withIntermediateDirectories:YES
6696 space_ = CGColorSpaceCreateDeviceRGB();
6698 Blue_.Set(space_, 0.2, 0.2, 1.0, 1.0);
6699 Blueish_.Set(space_, 0x19/255.f, 0x32/255.f, 0x50/255.f, 1.0);
6700 Black_.Set(space_, 0.0, 0.0, 0.0, 1.0);
6701 Off_.Set(space_, 0.9, 0.9, 0.9, 1.0);
6702 Red_.Set(space_, 1.0, 0.0, 0.0, 1.0);
6703 White_.Set(space_, 1.0, 1.0, 1.0, 1.0);
6704 Gray_.Set(space_, 0.4, 0.4, 0.4, 1.0);
6706 Finishes_ = [NSArray arrayWithObjects:@"return", @"reopen", @"restart", @"reload", @"reboot", nil];
6708 SectionMap_ = [[[NSDictionary alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Sections" ofType:@"plist"]] autorelease];
6710 UIApplicationUseLegacyEvents(YES);
6711 UIKeyboardDisableAutomaticAppearance();
6713 int value = UIApplicationMain(argc, argv, @"Cydia", @"Cydia");
6715 CGColorSpaceRelease(space_);