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 <UIKit/UIActionSheet-Private.h>
53 #import <UIKit/UIControl-UIControlPrivate.h>
54 #import <UIKit/UIImage-UIImageDeprecated.h>
55 #import <UIKit/UIImage-UIImagePrivate.h>
56 #import <UIKit/UINavigationBar-Static.h>
57 #import <UIKit/UIProgressHUD-Deprecated.h>
58 #import <UIKit/UIToolbar-UIButtonBarPrivate.h>
59 #import <UIKit/UIView-Deprecated.h>
60 #import <UIKit/UIWindow-Static.h>
63 #import <UIKit/NSString-UIStringDrawingDeprecated.h>
65 #include <WebKit/WebFrame.h>
66 #include <WebKit/WebView.h>
71 #include <ext/stdio_filebuf.h>
73 #include <apt-pkg/acquire.h>
74 #include <apt-pkg/acquire-item.h>
75 #include <apt-pkg/algorithms.h>
76 #include <apt-pkg/cachefile.h>
77 #include <apt-pkg/clean.h>
78 #include <apt-pkg/configuration.h>
79 #include <apt-pkg/debmetaindex.h>
80 #include <apt-pkg/error.h>
81 #include <apt-pkg/init.h>
82 #include <apt-pkg/mmap.h>
83 #include <apt-pkg/pkgrecords.h>
84 #include <apt-pkg/sha1.h>
85 #include <apt-pkg/sourcelist.h>
86 #include <apt-pkg/sptr.h>
88 #include <sys/types.h>
90 #include <sys/sysctl.h>
96 #include <mach-o/nlist.h>
106 #import "BrowserView.h"
107 #import "ResetView.h"
108 #import "UICaboodle.h"
111 static const NSStringCompareOptions CompareOptions_ = NSCaseInsensitiveSearch | NSNumericSearch | NSDiacriticInsensitiveSearch | NSWidthInsensitiveSearch | NSForcedOrderingSearch;
113 @interface WebView (Cydia)
114 - (void) _setLayoutInterval:(float)interval;
117 /* iPhoneOS 2.0 Compatibility {{{ */
119 @interface UICGColor : NSObject {
122 - (id) initWithCGColor:(CGColorRef)color;
125 @interface NSObject (iPhoneOS)
126 - (CGColorRef) cgColor;
127 - (CGColorRef) CGColor;
131 @implementation NSObject (iPhoneOS)
133 - (CGColorRef) cgColor {
134 return [self CGColor];
137 - (CGColorRef) CGColor {
138 return (CGColorRef) self;
142 [[[[objc_getClass("UICGColor") alloc] initWithCGColor:[self CGColor]] autorelease] set];
147 @interface UITextView (iPhoneOS)
148 - (void) setTextSize:(float)size;
151 @implementation UITextView (iPhoneOS)
153 - (void) setTextSize:(float)size {
154 [self setFont:[[self font] fontWithSize:size]];
161 @interface UIApplication (IdleTimer)
162 - (void) setIdleTimerDisabled:(char)arg0;
165 extern "C" int UIApplicationMain(int argc, char *argv[], NSString *principalClassName, NSString *delegateClassName);
167 extern NSString *kUIButtonBarButtonAction;
168 extern NSString *kUIButtonBarButtonInfo;
169 extern NSString *kUIButtonBarButtonInfoOffset;
170 extern NSString *kUIButtonBarButtonSelectedInfo;
171 extern NSString *kUIButtonBarButtonStyle;
172 extern NSString *kUIButtonBarButtonTag;
173 extern NSString *kUIButtonBarButtonTarget;
174 extern NSString *kUIButtonBarButtonTitle;
175 extern NSString *kUIButtonBarButtonTitleVerticalHeight;
176 extern NSString *kUIButtonBarButtonTitleWidth;
177 extern NSString *kUIButtonBarButtonType;
180 kUIProgressIndicatorStyleLargeWhite = 0,
181 kUIProgressIndicatorStyleMediumWhite = 1,
182 kUIProgressIndicatorStyleMediumBrown = 2,
183 kUIProgressIndicatorStyleSmallWhite = 3,
184 kUIProgressIndicatorStyleSmallBlack = 4,
185 kUIProgressIndicatorStyleTinyWhite = 5,
186 } UIProgressIndicatorStyle;
189 kUIControlEventMouseDown = 1 << 0,
190 kUIControlEventMouseMovedInside = 1 << 2, // mouse moved inside control target
191 kUIControlEventMouseMovedOutside = 1 << 3, // mouse moved outside control target
192 kUIControlEventMouseUpInside = 1 << 6, // mouse up inside control target
193 kUIControlEventMouseUpOutside = 1 << 7, // mouse up outside control target
194 kUIControlAllEvents = (kUIControlEventMouseDown | kUIControlEventMouseMovedInside | kUIControlEventMouseMovedOutside | kUIControlEventMouseUpInside | kUIControlEventMouseUpOutside)
195 } UIControlEventMasks;
197 @interface NSString (UIKit)
198 - (NSString *) stringByAddingPercentEscapes;
199 - (NSString *) stringByReplacingCharacter:(unsigned short)arg0 withCharacter:(unsigned short)arg1;
202 @interface NSString (Cydia)
203 + (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length;
204 - (NSComparisonResult) compareByPath:(NSString *)other;
207 @implementation NSString (Cydia)
209 + (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length {
210 char data[length + 1];
211 memcpy(data, bytes, length);
213 return [NSString stringWithUTF8String:data];
216 - (NSComparisonResult) compareByPath:(NSString *)other {
217 NSString *prefix = [self commonPrefixWithString:other options:0];
218 size_t length = [prefix length];
220 NSRange lrange = NSMakeRange(length, [self length] - length);
221 NSRange rrange = NSMakeRange(length, [other length] - length);
223 lrange = [self rangeOfString:@"/" options:0 range:lrange];
224 rrange = [other rangeOfString:@"/" options:0 range:rrange];
226 NSComparisonResult value;
228 if (lrange.location == NSNotFound && rrange.location == NSNotFound)
229 value = NSOrderedSame;
230 else if (lrange.location == NSNotFound)
231 value = NSOrderedAscending;
232 else if (rrange.location == NSNotFound)
233 value = NSOrderedDescending;
235 value = NSOrderedSame;
237 NSString *lpath = lrange.location == NSNotFound ? [self substringFromIndex:length] :
238 [self substringWithRange:NSMakeRange(length, lrange.location - length)];
239 NSString *rpath = rrange.location == NSNotFound ? [other substringFromIndex:length] :
240 [other substringWithRange:NSMakeRange(length, rrange.location - length)];
242 NSComparisonResult result = [lpath compare:rpath];
243 return result == NSOrderedSame ? value : result;
248 /* Perl-Compatible RegEx {{{ */
258 Pcre(const char *regex) :
263 code_ = pcre_compile(regex, 0, &error, &offset, NULL);
266 fprintf(stderr, "%d:%s\n", offset, error);
270 pcre_fullinfo(code_, study_, PCRE_INFO_CAPTURECOUNT, &capture_);
271 matches_ = new int[(capture_ + 1) * 3];
279 NSString *operator [](size_t match) {
280 return [NSString stringWithUTF8Bytes:(data_ + matches_[match * 2]) length:(matches_[match * 2 + 1] - matches_[match * 2])];
283 bool operator ()(NSString *data) {
284 // XXX: length is for characters, not for bytes
285 return operator ()([data UTF8String], [data length]);
288 bool operator ()(const char *data, size_t size) {
290 return pcre_exec(code_, study_, data, size, 0, 0, matches_, (capture_ + 1) * 3) >= 0;
294 /* Mime Addresses {{{ */
295 @interface Address : NSObject {
301 - (NSString *) address;
303 + (Address *) addressWithString:(NSString *)string;
304 - (Address *) initWithString:(NSString *)string;
307 @implementation Address
316 - (NSString *) name {
320 - (NSString *) address {
324 + (Address *) addressWithString:(NSString *)string {
325 return [[[Address alloc] initWithString:string] autorelease];
328 + (NSArray *) _attributeKeys {
329 return [NSArray arrayWithObjects:@"address", @"name", nil];
332 - (NSArray *) attributeKeys {
333 return [[self class] _attributeKeys];
336 + (BOOL) isKeyExcludedFromWebScript:(const char *)name {
337 return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name];
340 - (Address *) initWithString:(NSString *)string {
341 if ((self = [super init]) != nil) {
342 const char *data = [string UTF8String];
343 size_t size = [string length];
345 static Pcre address_r("^\"?(.*)\"? <([^>]*)>$");
347 if (address_r(data, size)) {
348 name_ = [address_r[1] retain];
349 address_ = [address_r[2] retain];
351 name_ = [[NSString alloc]
354 encoding:kCFStringEncodingUTF8
364 /* CoreGraphics Primitives {{{ */
375 CGColor(CGColorSpaceRef space, float red, float green, float blue, float alpha) :
378 Set(space, red, green, blue, alpha);
383 CGColorRelease(color_);
390 void Set(CGColorSpaceRef space, float red, float green, float blue, float alpha) {
392 float color[] = {red, green, blue, alpha};
393 color_ = CGColorCreate(space, color);
396 operator CGColorRef() {
402 extern "C" void UISetColor(CGColorRef color);
404 /* Random Global Variables {{{ */
405 static const int PulseInterval_ = 50000;
406 static const int ButtonBarHeight_ = 48;
407 static const float KeyboardTime_ = 0.3f;
408 static const char * const SpringBoard_ = "/System/Library/LaunchDaemons/com.apple.SpringBoard.plist";
410 static CGColor Blue_;
411 static CGColor Blueish_;
412 static CGColor Black_;
415 static CGColor White_;
416 static CGColor Gray_;
418 static NSString *App_;
419 static NSString *Home_;
420 static BOOL Sounds_Keyboard_;
422 static BOOL Advanced_;
424 static BOOL Ignored_;
426 static UIFont *Font12_;
427 static UIFont *Font12Bold_;
428 static UIFont *Font14_;
429 static UIFont *Font18Bold_;
430 static UIFont *Font22Bold_;
432 static const char *Firmware_ = NULL;
433 static const char *Machine_ = NULL;
434 static const NSString *UniqueID_ = NULL;
441 CGColorSpaceRef space_;
443 #define FW_LEAST(major, minor, bugfix) \
444 (major < Major_ || major == Major_ && \
445 (minor < Minor_ || minor == Minor_ && \
451 static NSDictionary *SectionMap_;
452 static NSMutableDictionary *Metadata_;
453 static _transient NSMutableDictionary *Settings_;
454 static _transient NSString *Role_;
455 static _transient NSMutableDictionary *Packages_;
456 static _transient NSMutableDictionary *Sections_;
457 static _transient NSMutableDictionary *Sources_;
458 static _transient NSMutableArray *Documents_;
459 static bool Changed_;
462 NSString *GetLastUpdate() {
463 NSDate *update = [Metadata_ objectForKey:@"LastUpdate"];
466 return @"Never or Unknown";
468 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, Locale_, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
469 CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) update);
471 CFRelease(formatter);
473 return [(NSString *) formatted autorelease];
476 /* Display Helpers {{{ */
477 inline float Interpolate(float begin, float end, float fraction) {
478 return (end - begin) * fraction + begin;
481 NSString *SizeString(double size) {
483 while (size > 1024) {
488 static const char *powers_[] = {"B", "kB", "MB", "GB"};
490 return [NSString stringWithFormat:@"%.1f%s", size, powers_[power]];
493 NSString *StripVersion(NSString *version) {
494 NSRange colon = [version rangeOfString:@":"];
495 if (colon.location != NSNotFound)
496 version = [version substringFromIndex:(colon.location + 1)];
500 static const float TextViewOffset_ = 22;
502 UITextView *GetTextView(NSString *value, float left, bool html) {
503 UITextView *text([[[UITextView alloc] initWithFrame:CGRectMake(left, 3, 310 - left, 1000)] autorelease]);
504 [text setEditable:NO];
505 [text setTextSize:16];
507 [text setHTML:value];
509 [text setText:value];
510 [text setEnabled:NO];
512 [text setBackgroundColor:[UIColor clearColor]];
514 CGRect frame = [text frame];
515 [text setFrame:frame];
516 CGRect rect = [text visibleTextRect];
517 frame.size.height = rect.size.height;
518 [text setFrame:frame];
523 NSString *Simplify(NSString *title) {
524 const char *data = [title UTF8String];
525 size_t size = [title length];
527 static Pcre square_r("^\\[(.*)\\]$");
528 if (square_r(data, size))
529 return Simplify(square_r[1]);
531 static Pcre paren_r("^\\((.*)\\)$");
532 if (paren_r(data, size))
533 return Simplify(paren_r[1]);
535 static Pcre title_r("^(.*?) \\(.*\\)$");
536 if (title_r(data, size))
537 return Simplify(title_r[1]);
543 bool isSectionVisible(NSString *section) {
544 NSDictionary *metadata = [Sections_ objectForKey:section];
545 NSNumber *hidden = metadata == nil ? nil : [metadata objectForKey:@"Hidden"];
546 return hidden == nil || ![hidden boolValue];
549 /* Delegate Prototypes {{{ */
553 @interface NSObject (ProgressDelegate)
556 @implementation NSObject(ProgressDelegate)
558 - (void) _setProgressError:(NSArray *)args {
559 [self performSelector:@selector(setProgressError:forPackage:)
560 withObject:[args objectAtIndex:0]
561 withObject:([args count] == 1 ? nil : [args objectAtIndex:1])
567 @protocol ProgressDelegate
568 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id;
569 - (void) setProgressTitle:(NSString *)title;
570 - (void) setProgressPercent:(float)percent;
571 - (void) startProgress;
572 - (void) addProgressOutput:(NSString *)output;
573 - (bool) isCancelling:(size_t)received;
576 @protocol ConfigurationDelegate
577 - (void) repairWithSelector:(SEL)selector;
578 - (void) setConfigurationData:(NSString *)data;
581 @protocol CydiaDelegate
582 - (void) installPackage:(Package *)package;
583 - (void) removePackage:(Package *)package;
584 - (void) slideUp:(UIActionSheet *)alert;
585 - (void) distUpgrade;
588 - (void) askForSettings;
589 - (UIProgressHUD *) addProgressHUD;
593 /* Status Delegation {{{ */
595 public pkgAcquireStatus
598 _transient NSObject<ProgressDelegate> *delegate_;
606 void setDelegate(id delegate) {
607 delegate_ = delegate;
610 virtual bool MediaChange(std::string media, std::string drive) {
614 virtual void IMSHit(pkgAcquire::ItemDesc &item) {
617 virtual void Fetch(pkgAcquire::ItemDesc &item) {
618 [delegate_ setProgressTitle:[NSString stringWithUTF8String:("Downloading " + item.ShortDesc).c_str()]];
621 virtual void Done(pkgAcquire::ItemDesc &item) {
624 virtual void Fail(pkgAcquire::ItemDesc &item) {
626 item.Owner->Status == pkgAcquire::Item::StatIdle ||
627 item.Owner->Status == pkgAcquire::Item::StatDone
631 [delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
632 withObject:[NSArray arrayWithObjects:[NSString stringWithUTF8String:item.Owner->ErrorText.c_str()], nil]
637 virtual bool Pulse(pkgAcquire *Owner) {
638 bool value = pkgAcquireStatus::Pulse(Owner);
641 double(CurrentBytes + CurrentItems) /
642 double(TotalBytes + TotalItems)
645 [delegate_ setProgressPercent:percent];
646 return [delegate_ isCancelling:CurrentBytes] ? false : value;
649 virtual void Start() {
650 [delegate_ startProgress];
653 virtual void Stop() {
657 /* Progress Delegation {{{ */
662 _transient id<ProgressDelegate> delegate_;
665 virtual void Update() {
666 [delegate_ setProgressTitle:[NSString stringWithUTF8String:Op.c_str()]];
667 [delegate_ setProgressPercent:(Percent / 100)];
676 void setDelegate(id delegate) {
677 delegate_ = delegate;
680 virtual void Done() {
681 [delegate_ setProgressPercent:1];
686 /* Database Interface {{{ */
687 @interface Database : NSObject {
689 pkgDepCache::Policy *policy_;
690 pkgRecords *records_;
691 pkgProblemResolver *resolver_;
692 pkgAcquire *fetcher_;
694 SPtr<pkgPackageManager> manager_;
695 pkgSourceList *list_;
697 NSMutableDictionary *sources_;
698 NSMutableArray *packages_;
700 _transient NSObject<ConfigurationDelegate, ProgressDelegate> *delegate_;
709 - (void) _readCydia:(NSNumber *)fd;
710 - (void) _readStatus:(NSNumber *)fd;
711 - (void) _readOutput:(NSNumber *)fd;
715 - (Package *) packageWithName:(NSString *)name;
718 - (pkgCacheFile &) cache;
719 - (pkgDepCache::Policy *) policy;
720 - (pkgRecords *) records;
721 - (pkgProblemResolver *) resolver;
722 - (pkgAcquire &) fetcher;
723 - (NSArray *) packages;
724 - (NSArray *) sources;
733 - (void) updateWithStatus:(Status &)status;
735 - (void) setDelegate:(id)delegate;
736 - (Source *) getSource:(const pkgCache::PkgFileIterator &)file;
740 /* Source Class {{{ */
741 @interface Source : NSObject {
742 NSString *description_;
747 NSString *distribution_;
751 NSString *defaultIcon_;
753 NSDictionary *record_;
757 - (Source *) initWithMetaIndex:(metaIndex *)index;
759 - (NSComparisonResult) compareByNameAndType:(Source *)source;
761 - (NSDictionary *) record;
765 - (NSString *) distribution;
771 - (NSString *) description;
772 - (NSString *) label;
773 - (NSString *) origin;
774 - (NSString *) version;
776 - (NSString *) defaultIcon;
780 @implementation Source
784 [distribution_ release];
787 if (description_ != nil)
788 [description_ release];
795 if (defaultIcon_ != nil)
796 [defaultIcon_ release];
803 + (NSArray *) _attributeKeys {
804 return [NSArray arrayWithObjects:@"description", @"distribution", @"host", @"key", @"label", @"name", @"origin", @"trusted", @"type", @"uri", @"version", nil];
807 - (NSArray *) attributeKeys {
808 return [[self class] _attributeKeys];
811 + (BOOL) isKeyExcludedFromWebScript:(const char *)name {
812 return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name];
815 - (Source *) initWithMetaIndex:(metaIndex *)index {
816 if ((self = [super init]) != nil) {
817 trusted_ = index->IsTrusted();
819 uri_ = [[NSString stringWithUTF8String:index->GetURI().c_str()] retain];
820 distribution_ = [[NSString stringWithUTF8String:index->GetDist().c_str()] retain];
821 type_ = [[NSString stringWithUTF8String:index->GetType()] retain];
823 debReleaseIndex *dindex(dynamic_cast<debReleaseIndex *>(index));
824 if (dindex != NULL) {
825 std::ifstream release(dindex->MetaIndexFile("Release").c_str());
827 while (std::getline(release, line)) {
828 std::string::size_type colon(line.find(':'));
829 if (colon == std::string::npos)
832 std::string name(line.substr(0, colon));
833 std::string value(line.substr(colon + 1));
834 while (!value.empty() && value[0] == ' ')
835 value = value.substr(1);
837 if (name == "Default-Icon")
838 defaultIcon_ = [[NSString stringWithUTF8String:value.c_str()] retain];
839 else if (name == "Description")
840 description_ = [[NSString stringWithUTF8String:value.c_str()] retain];
841 else if (name == "Label")
842 label_ = [[NSString stringWithUTF8String:value.c_str()] retain];
843 else if (name == "Origin")
844 origin_ = [[NSString stringWithUTF8String:value.c_str()] retain];
845 else if (name == "Version")
846 version_ = [[NSString stringWithUTF8String:value.c_str()] retain];
850 record_ = [Sources_ objectForKey:[self key]];
852 record_ = [record_ retain];
856 - (NSComparisonResult) compareByNameAndType:(Source *)source {
857 NSDictionary *lhr = [self record];
858 NSDictionary *rhr = [source record];
861 return lhr == nil ? NSOrderedDescending : NSOrderedAscending;
863 NSString *lhs = [self name];
864 NSString *rhs = [source name];
866 if ([lhs length] != 0 && [rhs length] != 0) {
867 unichar lhc = [lhs characterAtIndex:0];
868 unichar rhc = [rhs characterAtIndex:0];
870 if (isalpha(lhc) && !isalpha(rhc))
871 return NSOrderedAscending;
872 else if (!isalpha(lhc) && isalpha(rhc))
873 return NSOrderedDescending;
876 return [lhs compare:rhs options:CompareOptions_];
879 - (NSDictionary *) record {
891 - (NSString *) distribution {
892 return distribution_;
895 - (NSString *) type {
900 return [NSString stringWithFormat:@"%@:%@:%@", type_, uri_, distribution_];
903 - (NSString *) host {
904 return [[[NSURL URLWithString:[self uri]] host] lowercaseString];
907 - (NSString *) name {
908 return origin_ == nil ? [self host] : origin_;
911 - (NSString *) description {
915 - (NSString *) label {
916 return label_ == nil ? [self host] : label_;
919 - (NSString *) origin {
923 - (NSString *) version {
927 - (NSString *) defaultIcon {
933 /* Relationship Class {{{ */
934 @interface Relationship : NSObject {
945 @implementation Relationship
953 - (NSString *) type {
961 - (NSString *) name {
968 /* Package Class {{{ */
969 NSString *Scour(const char *field, const char *begin, const char *end) {
970 size_t i(0), l(strlen(field));
973 const char *name = begin + i;
974 const char *colon = name + l;
975 const char *value = colon + 1;
980 memcmp(name, field, l) == 0
982 while (value != end && value[0] == ' ')
984 const char *line = std::find(value, end, '\n');
985 while (line != value && line[-1] == ' ')
988 return [NSString stringWithUTF8Bytes:value length:(line - value)];
990 begin = std::find(begin, end, '\n');
998 @interface Package : NSObject {
999 pkgCache::PkgIterator iterator_;
1000 _transient Database *database_;
1001 pkgCache::VerIterator version_;
1002 pkgCache::VerFileIterator file_;
1008 NSString *installed_;
1014 NSString *depiction_;
1015 NSString *homepage_;
1021 NSArray *relationships_;
1024 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
1025 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
1027 - (pkgCache::PkgIterator) iterator;
1029 - (NSString *) section;
1030 - (Address *) maintainer;
1032 - (NSString *) description;
1033 - (NSString *) index;
1037 - (NSString *) latest;
1038 - (NSString *) installed;
1041 - (BOOL) upgradableAndEssential:(BOOL)essential;
1044 - (BOOL) unfiltered;
1048 - (BOOL) halfConfigured;
1049 - (BOOL) halfInstalled;
1051 - (NSString *) mode;
1054 - (NSString *) name;
1055 - (NSString *) tagline;
1056 - (NSString *) icon;
1057 - (NSString *) homepage;
1058 - (NSString *) depiction;
1059 - (Address *) author;
1061 - (NSArray *) relationships;
1063 - (Source *) source;
1064 - (NSString *) role;
1066 - (BOOL) matches:(NSString *)text;
1068 - (bool) hasSupportingRole;
1069 - (BOOL) hasTag:(NSString *)tag;
1071 - (NSComparisonResult) compareByName:(Package *)package;
1072 - (NSComparisonResult) compareBySection:(Package *)package;
1073 - (NSComparisonResult) compareBySectionAndName:(Package *)package;
1074 - (NSComparisonResult) compareForChanges:(Package *)package;
1079 - (NSNumber *) isUnfilteredAndSearchedForBy:(NSString *)search;
1080 - (NSNumber *) isInstalledAndVisible:(NSNumber *)number;
1081 - (NSNumber *) isVisiblyUninstalledInSection:(NSString *)section;
1082 - (NSNumber *) isVisibleInSource:(Source *)source;
1086 @implementation Package
1093 if (installed_ != nil)
1094 [installed_ release];
1102 if (depiction_ != nil)
1103 [depiction_ release];
1104 if (homepage_ != nil)
1105 [homepage_ release];
1106 if (sponsor_ != nil)
1115 if (relationships_ != nil)
1116 [relationships_ release];
1121 + (NSArray *) _attributeKeys {
1122 return [NSArray arrayWithObjects:@"author", @"depiction", @"description", @"essential", @"homepage", @"icon", @"id", @"installed", @"latest", @"maintainer", @"name", @"section", @"size", @"source", @"sponsor", @"tagline", nil];
1125 - (NSArray *) attributeKeys {
1126 return [[self class] _attributeKeys];
1129 + (BOOL) isKeyExcludedFromWebScript:(const char *)name {
1130 return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name];
1133 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
1134 if ((self = [super init]) != nil) {
1135 iterator_ = iterator;
1136 database_ = database;
1138 version_ = [database_ policy]->GetCandidateVer(iterator_);
1139 latest_ = version_.end() ? nil : [StripVersion([NSString stringWithUTF8String:version_.VerStr()]) retain];
1141 if (!version_.end())
1142 file_ = version_.FileList();
1144 pkgCache &cache([database_ cache]);
1145 file_ = pkgCache::VerFileIterator(cache, cache.VerFileP);
1148 pkgCache::VerIterator current = iterator_.CurrentVer();
1149 installed_ = current.end() ? nil : [StripVersion([NSString stringWithUTF8String:current.VerStr()]) retain];
1151 id_ = [[[NSString stringWithUTF8String:iterator_.Name()] lowercaseString] retain];
1154 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1156 const char *begin, *end;
1157 parser->GetRec(begin, end);
1159 name_ = Scour("Name", begin, end);
1161 name_ = [name_ retain];
1162 tagline_ = [[NSString stringWithUTF8String:parser->ShortDesc().c_str()] retain];
1163 icon_ = Scour("Icon", begin, end);
1165 icon_ = [icon_ retain];
1166 depiction_ = Scour("Depiction", begin, end);
1167 if (depiction_ != nil)
1168 depiction_ = [depiction_ retain];
1169 homepage_ = Scour("Homepage", begin, end);
1170 if (homepage_ == nil)
1171 homepage_ = Scour("Website", begin, end);
1172 if ([homepage_ isEqualToString:depiction_])
1174 if (homepage_ != nil)
1175 homepage_ = [homepage_ retain];
1176 NSString *sponsor = Scour("Sponsor", begin, end);
1178 sponsor_ = [[Address addressWithString:sponsor] retain];
1179 NSString *author = Scour("Author", begin, end);
1181 author_ = [[Address addressWithString:author] retain];
1182 NSString *tags = Scour("Tag", begin, end);
1184 tags_ = [[tags componentsSeparatedByString:@", "] retain];
1188 for (int i(0), e([tags_ count]); i != e; ++i) {
1189 NSString *tag = [tags_ objectAtIndex:i];
1190 if ([tag hasPrefix:@"role::"]) {
1191 role_ = [[tag substringFromIndex:6] retain];
1196 NSMutableDictionary *metadata = [Packages_ objectForKey:id_];
1197 if (metadata == nil || [metadata count] == 0) {
1198 metadata = [NSMutableDictionary dictionaryWithObjectsAndKeys:
1202 [Packages_ setObject:metadata forKey:id_];
1208 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
1209 return [[[Package alloc]
1210 initWithIterator:iterator
1215 - (pkgCache::PkgIterator) iterator {
1219 - (NSString *) section {
1220 const char *section = iterator_.Section();
1221 if (section == NULL)
1224 NSString *name = [[NSString stringWithUTF8String:section] stringByReplacingCharacter:' ' withCharacter:'_'];
1227 if (NSDictionary *value = [SectionMap_ objectForKey:name])
1228 if (NSString *rename = [value objectForKey:@"Rename"]) {
1233 return [name stringByReplacingCharacter:'_' withCharacter:' '];
1236 - (Address *) maintainer {
1239 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1240 return [Address addressWithString:[NSString stringWithUTF8String:parser->Maintainer().c_str()]];
1244 return version_.end() ? 0 : version_->InstalledSize;
1247 - (NSString *) description {
1250 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1251 NSString *description([NSString stringWithUTF8String:parser->LongDesc().c_str()]);
1253 NSArray *lines = [description componentsSeparatedByString:@"\n"];
1254 NSMutableArray *trimmed = [NSMutableArray arrayWithCapacity:([lines count] - 1)];
1255 if ([lines count] < 2)
1258 NSCharacterSet *whitespace = [NSCharacterSet whitespaceCharacterSet];
1259 for (size_t i(1); i != [lines count]; ++i) {
1260 NSString *trim = [[lines objectAtIndex:i] stringByTrimmingCharactersInSet:whitespace];
1261 [trimmed addObject:trim];
1264 return [trimmed componentsJoinedByString:@"\n"];
1267 - (NSString *) index {
1268 NSString *index = [[[self name] substringToIndex:1] uppercaseString];
1269 return [index length] != 0 && isalpha([index characterAtIndex:0]) ? index : @"123";
1273 return [[Packages_ objectForKey:id_] objectForKey:@"FirstSeen"];
1276 - (NSString *) latest {
1280 - (NSString *) installed {
1285 return !version_.end();
1288 - (BOOL) upgradableAndEssential:(BOOL)essential {
1289 pkgCache::VerIterator current = iterator_.CurrentVer();
1292 return essential && [self essential];
1294 pkgCache::VerIterator candidate = [database_ policy]->GetCandidateVer(iterator_);
1295 return !candidate.end() && candidate != current;
1299 - (BOOL) essential {
1300 return (iterator_->Flags & pkgCache::Flag::Essential) == 0 ? NO : YES;
1304 return [database_ cache][iterator_].InstBroken();
1307 - (BOOL) unfiltered {
1308 NSString *section = [self section];
1309 return section == nil || isSectionVisible(section);
1313 return [self hasSupportingRole] && [self unfiltered];
1317 unsigned char current = iterator_->CurrentState;
1318 return current == pkgCache::State::HalfConfigured || current == pkgCache::State::HalfInstalled;
1321 - (BOOL) halfConfigured {
1322 return iterator_->CurrentState == pkgCache::State::HalfConfigured;
1325 - (BOOL) halfInstalled {
1326 return iterator_->CurrentState == pkgCache::State::HalfInstalled;
1330 pkgDepCache::StateCache &state([database_ cache][iterator_]);
1331 return state.Mode != pkgDepCache::ModeKeep;
1334 - (NSString *) mode {
1335 pkgDepCache::StateCache &state([database_ cache][iterator_]);
1337 switch (state.Mode) {
1338 case pkgDepCache::ModeDelete:
1339 if ((state.iFlags & pkgDepCache::Purge) != 0)
1344 case pkgDepCache::ModeKeep:
1345 if ((state.iFlags & pkgDepCache::AutoKept) != 0)
1350 case pkgDepCache::ModeInstall:
1351 if ((state.iFlags & pkgDepCache::ReInstall) != 0)
1352 return @"Reinstall";
1353 else switch (state.Status) {
1355 return @"Downgrade";
1361 return @"New Install";
1374 - (NSString *) name {
1375 return name_ == nil ? id_ : name_;
1378 - (NSString *) tagline {
1382 - (NSString *) icon {
1386 - (NSString *) homepage {
1390 - (NSString *) depiction {
1394 - (Address *) sponsor {
1398 - (Address *) author {
1402 - (NSArray *) relationships {
1403 return relationships_;
1406 - (Source *) source {
1408 source_ = file_.end() ? nil : [[database_ getSource:file_.File()] retain];
1415 - (NSString *) role {
1419 - (BOOL) matches:(NSString *)text {
1425 range = [[self id] rangeOfString:text options:NSCaseInsensitiveSearch];
1426 if (range.location != NSNotFound)
1429 range = [[self name] rangeOfString:text options:NSCaseInsensitiveSearch];
1430 if (range.location != NSNotFound)
1433 range = [[self tagline] rangeOfString:text options:NSCaseInsensitiveSearch];
1434 if (range.location != NSNotFound)
1440 - (bool) hasSupportingRole {
1443 if ([role_ isEqualToString:@"enduser"])
1445 if ([Role_ isEqualToString:@"User"])
1447 if ([role_ isEqualToString:@"hacker"])
1449 if ([Role_ isEqualToString:@"Hacker"])
1451 if ([role_ isEqualToString:@"developer"])
1453 if ([Role_ isEqualToString:@"Developer"])
1458 - (BOOL) hasTag:(NSString *)tag {
1459 return tags_ == nil ? NO : [tags_ containsObject:tag];
1462 - (NSComparisonResult) compareByName:(Package *)package {
1463 NSString *lhs = [self name];
1464 NSString *rhs = [package name];
1466 if ([lhs length] != 0 && [rhs length] != 0) {
1467 unichar lhc = [lhs characterAtIndex:0];
1468 unichar rhc = [rhs characterAtIndex:0];
1470 if (isalpha(lhc) && !isalpha(rhc))
1471 return NSOrderedAscending;
1472 else if (!isalpha(lhc) && isalpha(rhc))
1473 return NSOrderedDescending;
1476 return [lhs compare:rhs options:CompareOptions_];
1479 - (NSComparisonResult) compareBySection:(Package *)package {
1480 NSString *lhs = [self section];
1481 NSString *rhs = [package section];
1483 if (lhs == NULL && rhs != NULL)
1484 return NSOrderedAscending;
1485 else if (lhs != NULL && rhs == NULL)
1486 return NSOrderedDescending;
1487 else if (lhs != NULL && rhs != NULL) {
1488 NSComparisonResult result = [lhs compare:rhs options:CompareOptions_];
1489 if (result != NSOrderedSame)
1493 return NSOrderedSame;
1496 - (NSComparisonResult) compareBySectionAndName:(Package *)package {
1497 NSString *lhs = [self section];
1498 NSString *rhs = [package section];
1500 if (lhs == NULL && rhs != NULL)
1501 return NSOrderedAscending;
1502 else if (lhs != NULL && rhs == NULL)
1503 return NSOrderedDescending;
1504 else if (lhs != NULL && rhs != NULL) {
1505 NSComparisonResult result = [lhs compare:rhs];
1506 if (result != NSOrderedSame)
1510 return [self compareByName:package];
1513 - (NSComparisonResult) compareForChanges:(Package *)package {
1514 BOOL lhs = [self upgradableAndEssential:YES];
1515 BOOL rhs = [package upgradableAndEssential:YES];
1518 return lhs ? NSOrderedAscending : NSOrderedDescending;
1520 switch ([[self seen] compare:[package seen]]) {
1521 case NSOrderedAscending:
1522 return NSOrderedDescending;
1525 case NSOrderedDescending:
1526 return NSOrderedAscending;
1532 return [self compareByName:package];
1536 pkgProblemResolver *resolver = [database_ resolver];
1537 resolver->Clear(iterator_);
1538 resolver->Protect(iterator_);
1539 pkgCacheFile &cache([database_ cache]);
1540 cache->MarkInstall(iterator_, false);
1541 pkgDepCache::StateCache &state((*cache)[iterator_]);
1542 if (!state.Install())
1543 cache->SetReInstall(iterator_, true);
1547 pkgProblemResolver *resolver = [database_ resolver];
1548 resolver->Clear(iterator_);
1549 resolver->Protect(iterator_);
1550 resolver->Remove(iterator_);
1551 [database_ cache]->MarkDelete(iterator_, true);
1554 - (NSNumber *) isUnfilteredAndSearchedForBy:(NSString *)search {
1555 return [NSNumber numberWithBool:(
1556 [self unfiltered] && [self matches:search]
1560 - (NSNumber *) isInstalledAndVisible:(NSNumber *)number {
1561 return [NSNumber numberWithBool:(
1562 (![number boolValue] || [self visible]) && [self installed] != nil
1566 - (NSNumber *) isVisiblyUninstalledInSection:(NSString *)name {
1567 NSString *section = [self section];
1569 return [NSNumber numberWithBool:(
1571 [self installed] == nil && (
1573 section == nil && [name length] == 0 ||
1574 [name isEqualToString:section]
1579 - (NSNumber *) isVisibleInSource:(Source *)source {
1580 return [NSNumber numberWithBool:([self source] == source && [self visible])];
1585 /* Section Class {{{ */
1586 @interface Section : NSObject {
1592 - (NSComparisonResult) compareByName:(Section *)section;
1593 - (Section *) initWithName:(NSString *)name;
1594 - (Section *) initWithName:(NSString *)name row:(size_t)row;
1595 - (NSString *) name;
1598 - (void) addToCount;
1602 @implementation Section
1609 - (NSComparisonResult) compareByName:(Section *)section {
1610 NSString *lhs = [self name];
1611 NSString *rhs = [section name];
1613 if ([lhs length] != 0 && [rhs length] != 0) {
1614 unichar lhc = [lhs characterAtIndex:0];
1615 unichar rhc = [rhs characterAtIndex:0];
1617 if (isalpha(lhc) && !isalpha(rhc))
1618 return NSOrderedAscending;
1619 else if (!isalpha(lhc) && isalpha(rhc))
1620 return NSOrderedDescending;
1623 return [lhs compare:rhs options:CompareOptions_];
1626 - (Section *) initWithName:(NSString *)name {
1627 return [self initWithName:name row:0];
1630 - (Section *) initWithName:(NSString *)name row:(size_t)row {
1631 if ((self = [super init]) != nil) {
1632 name_ = [name retain];
1637 - (NSString *) name {
1649 - (void) addToCount {
1659 /* Database Implementation {{{ */
1660 @implementation Database
1667 - (void) _readCydia:(NSNumber *)fd {
1668 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1670 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1671 std::istream is(&ib);
1674 static Pcre finish_r("^finish:([^:]*)$");
1676 while (std::getline(is, line)) {
1677 const char *data(line.c_str());
1678 size_t size = line.size();
1679 fprintf(stderr, "C:%s\n", data);
1681 if (finish_r(data, size)) {
1682 NSString *finish = finish_r[1];
1683 int index = [Finishes_ indexOfObject:finish];
1684 if (index != INT_MAX && index > Finish_)
1693 - (void) _readStatus:(NSNumber *)fd {
1694 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1696 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1697 std::istream is(&ib);
1700 static Pcre conffile_r("^status: [^ ]* : conffile-prompt : (.*?) *$");
1701 static Pcre pmstatus_r("^([^:]*):([^:]*):([^:]*):(.*)$");
1703 while (std::getline(is, line)) {
1704 const char *data(line.c_str());
1705 size_t size = line.size();
1706 fprintf(stderr, "S:%s\n", data);
1708 if (conffile_r(data, size)) {
1709 [delegate_ setConfigurationData:conffile_r[1]];
1710 } else if (strncmp(data, "status: ", 8) == 0) {
1711 NSString *string = [NSString stringWithUTF8String:(data + 8)];
1712 [delegate_ setProgressTitle:string];
1713 } else if (pmstatus_r(data, size)) {
1714 std::string type([pmstatus_r[1] UTF8String]);
1715 NSString *id = pmstatus_r[2];
1717 float percent([pmstatus_r[3] floatValue]);
1718 [delegate_ setProgressPercent:(percent / 100)];
1720 NSString *string = pmstatus_r[4];
1722 if (type == "pmerror")
1723 [delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
1724 withObject:[NSArray arrayWithObjects:string, id, nil]
1727 else if (type == "pmstatus")
1728 [delegate_ setProgressTitle:string];
1729 else if (type == "pmconffile")
1730 [delegate_ setConfigurationData:string];
1731 else _assert(false);
1732 } else _assert(false);
1739 - (void) _readOutput:(NSNumber *)fd {
1740 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1742 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1743 std::istream is(&ib);
1746 while (std::getline(is, line)) {
1747 fprintf(stderr, "O:%s\n", line.c_str());
1748 [delegate_ addProgressOutput:[NSString stringWithUTF8String:line.c_str()]];
1759 - (Package *) packageWithName:(NSString *)name {
1760 if (static_cast<pkgDepCache *>(cache_) == NULL)
1762 pkgCache::PkgIterator iterator(cache_->FindPkg([name UTF8String]));
1763 return iterator.end() ? nil : [Package packageWithIterator:iterator database:self];
1766 - (Database *) init {
1767 if ((self = [super init]) != nil) {
1774 sources_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1775 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
1779 _assert(pipe(fds) != -1);
1782 _config->Set("APT::Keep-Fds::", cydiafd_);
1783 setenv("CYDIA", [[[[NSNumber numberWithInt:cydiafd_] stringValue] stringByAppendingString:@" 1"] UTF8String], _not(int));
1786 detachNewThreadSelector:@selector(_readCydia:)
1788 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1791 _assert(pipe(fds) != -1);
1795 detachNewThreadSelector:@selector(_readStatus:)
1797 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1800 _assert(pipe(fds) != -1);
1801 _assert(dup2(fds[0], 0) != -1);
1802 _assert(close(fds[0]) != -1);
1804 input_ = fdopen(fds[1], "a");
1806 _assert(pipe(fds) != -1);
1807 _assert(dup2(fds[1], 1) != -1);
1808 _assert(close(fds[1]) != -1);
1811 detachNewThreadSelector:@selector(_readOutput:)
1813 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1818 - (pkgCacheFile &) cache {
1822 - (pkgDepCache::Policy *) policy {
1826 - (pkgRecords *) records {
1830 - (pkgProblemResolver *) resolver {
1834 - (pkgAcquire &) fetcher {
1838 - (NSArray *) packages {
1842 - (NSArray *) sources {
1843 return [sources_ allValues];
1846 - (void) reloadData {
1865 if (!cache_.Open(progress_, true)) {
1867 if (!_error->PopMessage(error))
1870 fprintf(stderr, "cache_.Open():[%s]\n", error.c_str());
1872 if (error == "dpkg was interrupted, you must manually run 'dpkg --configure -a' to correct the problem. ")
1873 [delegate_ repairWithSelector:@selector(configure)];
1874 else if (error == "The package lists or status file could not be parsed or opened.")
1875 [delegate_ repairWithSelector:@selector(update)];
1876 // else if (error == "Could not open lock file /var/lib/dpkg/lock - open (13 Permission denied)")
1877 // else if (error == "Could not get lock /var/lib/dpkg/lock - open (35 Resource temporarily unavailable)")
1878 // else if (error == "The list of sources could not be read.")
1879 else _assert(false);
1884 now_ = [[NSDate date] retain];
1886 policy_ = new pkgDepCache::Policy();
1887 records_ = new pkgRecords(cache_);
1888 resolver_ = new pkgProblemResolver(cache_);
1889 fetcher_ = new pkgAcquire(&status_);
1892 list_ = new pkgSourceList();
1893 _assert(list_->ReadMainList());
1895 _assert(cache_->DelCount() == 0 && cache_->InstCount() == 0);
1896 _assert(pkgApplyStatus(cache_));
1898 if (cache_->BrokenCount() != 0) {
1899 _assert(pkgFixBroken(cache_));
1900 _assert(cache_->BrokenCount() == 0);
1901 _assert(pkgMinimizeUpgrade(cache_));
1904 [sources_ removeAllObjects];
1905 for (pkgSourceList::const_iterator source = list_->begin(); source != list_->end(); ++source) {
1906 std::vector<pkgIndexFile *> *indices = (*source)->GetIndexFiles();
1907 for (std::vector<pkgIndexFile *>::const_iterator index = indices->begin(); index != indices->end(); ++index)
1909 setObject:[[[Source alloc] initWithMetaIndex:*source] autorelease]
1910 forKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(*index)]
1914 [packages_ removeAllObjects];
1915 for (pkgCache::PkgIterator iterator = cache_->PkgBegin(); !iterator.end(); ++iterator)
1916 if (Package *package = [Package packageWithIterator:iterator database:self])
1917 [packages_ addObject:package];
1919 [packages_ sortUsingSelector:@selector(compareByName:)];
1922 - (void) configure {
1923 NSString *dpkg = [NSString stringWithFormat:@"dpkg --configure -a --status-fd %u", statusfd_];
1924 system([dpkg UTF8String]);
1932 Lock.Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1933 _assert(!_error->PendingError());
1936 fetcher.Clean(_config->FindDir("Dir::Cache::Archives"));
1939 public pkgArchiveCleaner
1942 virtual void Erase(const char *File, std::string Pkg, std::string Ver, struct stat &St) {
1947 if (!cleaner.Go(_config->FindDir("Dir::Cache::Archives") + "partial/", cache_)) {
1949 while (_error->PopMessage(error))
1950 fprintf(stderr, "ArchiveCleaner: %s\n", error.c_str());
1955 pkgRecords records(cache_);
1957 lock_ = new FileFd();
1958 lock_->Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1959 _assert(!_error->PendingError());
1962 // XXX: explain this with an error message
1963 _assert(list.ReadMainList());
1965 manager_ = (_system->CreatePM(cache_));
1966 _assert(manager_->GetArchives(fetcher_, &list, &records));
1967 _assert(!_error->PendingError());
1971 NSMutableArray *before = [NSMutableArray arrayWithCapacity:16]; {
1973 _assert(list.ReadMainList());
1974 for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source)
1975 [before addObject:[NSString stringWithUTF8String:(*source)->GetURI().c_str()]];
1978 if (fetcher_->Run(PulseInterval_) != pkgAcquire::Continue) {
1983 bool failed = false;
1984 for (pkgAcquire::ItemIterator item = fetcher_->ItemsBegin(); item != fetcher_->ItemsEnd(); item++) {
1985 if ((*item)->Status == pkgAcquire::Item::StatDone && (*item)->Complete)
1988 std::string uri = (*item)->DescURI();
1989 std::string error = (*item)->ErrorText;
1991 fprintf(stderr, "pAf:%s:%s\n", uri.c_str(), error.c_str());
1994 [delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
1995 withObject:[NSArray arrayWithObjects:[NSString stringWithUTF8String:error.c_str()], nil]
2006 pkgPackageManager::OrderResult result = manager_->DoInstall(statusfd_);
2008 if (_error->PendingError()) {
2013 if (result == pkgPackageManager::Failed) {
2018 if (result != pkgPackageManager::Completed) {
2023 NSMutableArray *after = [NSMutableArray arrayWithCapacity:16]; {
2025 _assert(list.ReadMainList());
2026 for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source)
2027 [after addObject:[NSString stringWithUTF8String:(*source)->GetURI().c_str()]];
2030 if (![before isEqualToArray:after])
2035 _assert(pkgDistUpgrade(cache_));
2039 [self updateWithStatus:status_];
2042 - (void) updateWithStatus:(Status &)status {
2044 _assert(list.ReadMainList());
2047 lock.Fd(GetLock(_config->FindDir("Dir::State::Lists") + "lock"));
2048 _assert(!_error->PendingError());
2050 pkgAcquire fetcher(&status);
2051 _assert(list.GetIndexes(&fetcher));
2053 if (fetcher.Run(PulseInterval_) != pkgAcquire::Failed) {
2054 bool failed = false;
2055 for (pkgAcquire::ItemIterator item = fetcher.ItemsBegin(); item != fetcher.ItemsEnd(); item++)
2056 if ((*item)->Status != pkgAcquire::Item::StatDone) {
2057 (*item)->Finished();
2061 if (!failed && _config->FindB("APT::Get::List-Cleanup", true) == true) {
2062 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists")));
2063 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/"));
2066 [Metadata_ setObject:[NSDate date] forKey:@"LastUpdate"];
2071 - (void) setDelegate:(id)delegate {
2072 delegate_ = delegate;
2073 status_.setDelegate(delegate);
2074 progress_.setDelegate(delegate);
2077 - (Source *) getSource:(const pkgCache::PkgFileIterator &)file {
2078 pkgIndexFile *index(NULL);
2079 list_->FindIndex(file, index);
2080 return [sources_ objectForKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(index)]];
2086 /* Confirmation View {{{ */
2087 void AddTextView(NSMutableDictionary *fields, NSMutableArray *packages, NSString *key) {
2088 if ([packages count] == 0)
2091 UITextView *text = GetTextView([packages count] == 0 ? @"n/a" : [packages componentsJoinedByString:@", "], 120, false);
2092 [fields setObject:text forKey:key];
2094 CGColor blue(space_, 0, 0, 0.4, 1);
2095 [text setTextColor:[UIColor colorWithCGColor:blue]];
2098 bool DepSubstrate(const pkgCache::VerIterator &iterator) {
2099 if (!iterator.end())
2100 for (pkgCache::DepIterator dep(iterator.DependsList()); !dep.end(); ++dep) {
2101 if (dep->Type != pkgCache::Dep::Depends && dep->Type != pkgCache::Dep::PreDepends)
2103 pkgCache::PkgIterator package(dep.TargetPkg());
2106 if (strcmp(package.Name(), "mobilesubstrate") == 0)
2113 @protocol ConfirmationViewDelegate
2118 @interface ConfirmationView : UIView {
2119 Database *database_;
2121 UITransitionView *transition_;
2123 UINavigationBar *navbar_;
2124 UIPreferencesTable *table_;
2125 NSMutableDictionary *fields_;
2126 UIActionSheet *essential_;
2132 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate;
2136 @implementation ConfirmationView
2139 [navbar_ setDelegate:nil];
2140 [transition_ setDelegate:nil];
2141 [table_ setDataSource:nil];
2143 [transition_ release];
2148 if (essential_ != nil)
2149 [essential_ release];
2154 [transition_ transition:7 toView:nil];
2158 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
2159 if (from != nil && to == nil)
2160 [self removeFromSuperview];
2163 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2166 if (essential_ != nil)
2167 [essential_ popupAlertAnimated:YES];
2171 [delegate_ confirm];
2181 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
2182 NSString *context = [sheet context];
2184 if ([context isEqualToString:@"remove"])
2192 [delegate_ confirm];
2197 else if ([context isEqualToString:@"unable"])
2203 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
2207 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
2209 case 0: return @"Statistics";
2210 case 1: return @"Modifications";
2212 default: _assert(false);
2216 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
2219 case 1: return [fields_ count];
2221 default: _assert(false);
2225 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
2226 if (group != 1 || row == -1)
2229 _assert(size_t(row) < [fields_ count]);
2230 return [[[fields_ allValues] objectAtIndex:row] visibleTextRect].size.height + TextViewOffset_;
2234 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
2235 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
2236 [cell setShowSelection:NO];
2239 case 0: switch (row) {
2241 [cell setTitle:@"Downloading"];
2242 [cell setValue:SizeString([database_ fetcher].FetchNeeded())];
2246 [cell setTitle:@"Resuming At"];
2247 [cell setValue:SizeString([database_ fetcher].PartialPresent())];
2251 double size([database_ cache]->UsrSize());
2254 [cell setTitle:@"Disk Freeing"];
2255 [cell setValue:SizeString(-size)];
2257 [cell setTitle:@"Disk Using"];
2258 [cell setValue:SizeString(size)];
2262 default: _assert(false);
2266 _assert(size_t(row) < [fields_ count]);
2267 [cell setTitle:[[fields_ allKeys] objectAtIndex:row]];
2268 [cell addSubview:[[fields_ allValues] objectAtIndex:row]];
2271 default: _assert(false);
2277 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate {
2278 if ((self = [super initWithFrame:[view bounds]]) != nil) {
2279 database_ = database;
2280 delegate_ = delegate;
2282 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
2283 [self addSubview:transition_];
2285 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
2287 CGSize navsize = [UINavigationBar defaultSize];
2288 CGRect navrect = {{0, 0}, navsize};
2289 CGRect bounds = [overlay_ bounds];
2291 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
2292 [navbar_ setDelegate:self];
2294 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Confirm"] autorelease];
2295 [navbar_ pushNavigationItem:navitem];
2296 [navbar_ showButtonsWithLeftTitle:@"Cancel" rightTitle:@"Confirm"];
2298 fields_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
2300 NSMutableArray *installing = [NSMutableArray arrayWithCapacity:16];
2301 NSMutableArray *reinstalling = [NSMutableArray arrayWithCapacity:16];
2302 NSMutableArray *upgrading = [NSMutableArray arrayWithCapacity:16];
2303 NSMutableArray *downgrading = [NSMutableArray arrayWithCapacity:16];
2304 NSMutableArray *removing = [NSMutableArray arrayWithCapacity:16];
2308 pkgDepCache::Policy *policy([database_ policy]);
2310 pkgCacheFile &cache([database_ cache]);
2311 NSArray *packages = [database_ packages];
2312 for (size_t i(0), e = [packages count]; i != e; ++i) {
2313 Package *package = [packages objectAtIndex:i];
2314 pkgCache::PkgIterator iterator = [package iterator];
2315 pkgDepCache::StateCache &state(cache[iterator]);
2317 NSString *name([package name]);
2319 if (state.NewInstall())
2320 [installing addObject:name];
2321 else if (!state.Delete() && (state.iFlags & pkgDepCache::ReInstall) == pkgDepCache::ReInstall)
2322 [reinstalling addObject:name];
2323 else if (state.Upgrade())
2324 [upgrading addObject:name];
2325 else if (state.Downgrade())
2326 [downgrading addObject:name];
2327 else if (state.Delete()) {
2328 if ([package essential])
2330 [removing addObject:name];
2333 substrate_ |= DepSubstrate(policy->GetCandidateVer(iterator));
2334 substrate_ |= DepSubstrate(iterator.CurrentVer());
2339 else if (Advanced_ || true) {
2340 essential_ = [[UIActionSheet alloc]
2341 initWithTitle:@"Removing Essentials"
2342 buttons:[NSArray arrayWithObjects:
2343 @"Cancel Operation (Safe)",
2344 @"Force Removal (Unsafe)",
2346 defaultButtonIndex:0
2352 [essential_ setDestructiveButton:[[essential_ buttons] objectAtIndex:0]];
2354 [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."];
2356 essential_ = [[UIActionSheet alloc]
2357 initWithTitle:@"Unable to Comply"
2358 buttons:[NSArray arrayWithObjects:@"Okay", nil]
2359 defaultButtonIndex:0
2364 [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."];
2367 AddTextView(fields_, installing, @"Installing");
2368 AddTextView(fields_, reinstalling, @"Reinstalling");
2369 AddTextView(fields_, upgrading, @"Upgrading");
2370 AddTextView(fields_, downgrading, @"Downgrading");
2371 AddTextView(fields_, removing, @"Removing");
2373 table_ = [[UIPreferencesTable alloc] initWithFrame:CGRectMake(
2374 0, navsize.height, bounds.size.width, bounds.size.height - navsize.height
2377 [table_ setDataSource:self];
2378 [table_ reloadData];
2380 [overlay_ addSubview:navbar_];
2381 [overlay_ addSubview:table_];
2383 [view addSubview:self];
2385 [transition_ setDelegate:self];
2387 UIView *blank = [[[UIView alloc] initWithFrame:[transition_ bounds]] autorelease];
2388 [transition_ transition:0 toView:blank];
2389 [transition_ transition:3 toView:overlay_];
2396 /* Progress Data {{{ */
2397 @interface ProgressData : NSObject {
2403 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object;
2410 @implementation ProgressData
2412 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object {
2413 if ((self = [super init]) != nil) {
2414 selector_ = selector;
2434 /* Progress View {{{ */
2435 @interface ProgressView : UIView <
2436 ConfigurationDelegate,
2439 _transient Database *database_;
2441 UIView *background_;
2442 UITransitionView *transition_;
2444 UINavigationBar *navbar_;
2445 UIProgressBar *progress_;
2446 UITextView *output_;
2447 UITextLabel *status_;
2448 UIPushButton *close_;
2451 SHA1SumValue springlist_;
2453 NSTimeInterval last_;
2456 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
2458 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database delegate:(id)delegate;
2459 - (void) setContentView:(UIView *)view;
2462 - (void) _retachThread;
2463 - (void) _detachNewThreadData:(ProgressData *)data;
2464 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title;
2470 @protocol ProgressViewDelegate
2471 - (void) progressViewIsComplete:(ProgressView *)sender;
2474 @implementation ProgressView
2477 [transition_ setDelegate:nil];
2478 [navbar_ setDelegate:nil];
2481 if (background_ != nil)
2482 [background_ release];
2483 [transition_ release];
2486 [progress_ release];
2493 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
2494 if (bootstrap_ && from == overlay_ && to == view_)
2498 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database delegate:(id)delegate {
2499 if ((self = [super initWithFrame:frame]) != nil) {
2500 database_ = database;
2501 delegate_ = delegate;
2503 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
2504 [transition_ setDelegate:self];
2506 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
2509 [overlay_ setBackgroundColor:[UIColor blackColor]];
2511 background_ = [[UIView alloc] initWithFrame:[self bounds]];
2512 [background_ setBackgroundColor:[UIColor blackColor]];
2513 [self addSubview:background_];
2516 [self addSubview:transition_];
2518 CGSize navsize = [UINavigationBar defaultSize];
2519 CGRect navrect = {{0, 0}, navsize};
2521 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
2522 [overlay_ addSubview:navbar_];
2524 [navbar_ setBarStyle:1];
2525 [navbar_ setDelegate:self];
2527 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:nil] autorelease];
2528 [navbar_ pushNavigationItem:navitem];
2530 CGRect bounds = [overlay_ bounds];
2531 CGSize prgsize = [UIProgressBar defaultSize];
2534 (bounds.size.width - prgsize.width) / 2,
2535 bounds.size.height - prgsize.height - 20
2538 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
2539 [progress_ setStyle:0];
2541 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(
2543 bounds.size.height - prgsize.height - 50,
2544 bounds.size.width - 20,
2548 [status_ setColor:[UIColor whiteColor]];
2549 [status_ setBackgroundColor:[UIColor clearColor]];
2551 [status_ setCentersHorizontally:YES];
2552 //[status_ setFont:font];
2554 output_ = [[UITextView alloc] initWithFrame:CGRectMake(
2556 navrect.size.height + 20,
2557 bounds.size.width - 20,
2558 bounds.size.height - navsize.height - 62 - navrect.size.height
2561 //[output_ setTextFont:@"Courier New"];
2562 [output_ setTextSize:12];
2564 [output_ setTextColor:[UIColor whiteColor]];
2565 [output_ setBackgroundColor:[UIColor clearColor]];
2567 [output_ setMarginTop:0];
2568 [output_ setAllowsRubberBanding:YES];
2569 [output_ setEditable:NO];
2571 [overlay_ addSubview:output_];
2573 close_ = [[UIPushButton alloc] initWithFrame:CGRectMake(
2575 bounds.size.height - prgsize.height - 50,
2576 bounds.size.width - 20,
2580 [close_ setAutosizesToFit:NO];
2581 [close_ setDrawsShadow:YES];
2582 [close_ setStretchBackground:YES];
2583 [close_ setEnabled:YES];
2585 UIFont *bold = [UIFont boldSystemFontOfSize:22];
2586 [close_ setTitleFont:bold];
2588 [close_ addTarget:self action:@selector(closeButtonPushed) forEvents:kUIControlEventMouseUpInside];
2589 [close_ setBackground:[UIImage applicationImageNamed:@"green-up.png"] forState:0];
2590 [close_ setBackground:[UIImage applicationImageNamed:@"green-dn.png"] forState:1];
2594 - (void) setContentView:(UIView *)view {
2595 view_ = [view retain];
2598 - (void) resetView {
2599 [transition_ transition:6 toView:view_];
2602 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
2603 NSString *context = [sheet context];
2604 if ([context isEqualToString:@"conffile"]) {
2605 FILE *input = [database_ input];
2609 fprintf(input, "N\n");
2613 fprintf(input, "Y\n");
2624 - (void) closeButtonPushed {
2627 [delegate_ progressViewIsComplete:self];
2632 [delegate_ suspendWithAnimation:YES];
2636 system("launchctl stop com.apple.SpringBoard");
2640 system("launchctl unload /System/Library/LaunchDaemons/com.apple.SpringBoard.plist; launchctl load /System/Library/LaunchDaemons/com.apple.SpringBoard.plist");
2649 - (void) _retachThread {
2650 UINavigationItem *item = [navbar_ topItem];
2651 [item setTitle:@"Complete"];
2653 [overlay_ addSubview:close_];
2654 [progress_ removeFromSuperview];
2655 [status_ removeFromSuperview];
2658 FileFd file("/System/Library/LaunchDaemons/com.apple.SpringBoard.plist", FileFd::ReadOnly);
2659 MMap mmap(file, MMap::ReadOnly);
2661 sha1.Add(reinterpret_cast<uint8_t *>(mmap.Data()), mmap.Size());
2662 if (!(springlist_ == sha1.Result()))
2667 case 0: [close_ setTitle:@"Return to Cydia"]; break;
2668 case 1: [close_ setTitle:@"Close Cydia (Restart)"]; break;
2669 case 2: [close_ setTitle:@"Restart SpringBoard"]; break;
2670 case 3: [close_ setTitle:@"Reload SpringBoard"]; break;
2671 case 4: [close_ setTitle:@"Reboot Device"]; break;
2674 #define Cache_ "/User/Library/Caches/com.apple.mobile.installation.plist"
2676 if (NSMutableDictionary *cache = [[NSDictionary alloc] initWithContentsOfFile:@ Cache_]) {
2677 [cache autorelease];
2679 NSFileManager *manager = [NSFileManager defaultManager];
2682 NSMutableDictionary *system = [cache objectForKey:@"System"];
2687 if (stat(Cache_, &info) == -1)
2690 [system removeAllObjects];
2692 if (NSArray *apps = [manager contentsOfDirectoryAtPath:@"/Applications" error:&error])
2693 for (NSString *app in apps)
2694 if ([app hasSuffix:@".app"]) {
2695 NSString *path = [@"/Applications" stringByAppendingPathComponent:app];
2696 NSString *plist = [path stringByAppendingPathComponent:@"Info.plist"];
2697 if (NSMutableDictionary *info = [[NSMutableDictionary alloc] initWithContentsOfFile:plist]) {
2699 [info setObject:path forKey:@"Path"];
2700 [info setObject:@"System" forKey:@"ApplicationType"];
2701 NSString *bundle = [info objectForKey:@"CFBundleIdentifier"];
2702 [system setObject:info forKey:bundle];
2707 [cache writeToFile:@Cache_ atomically:YES];
2709 if (chown(Cache_, info.st_uid, info.st_gid) == -1)
2711 if (chmod(Cache_, info.st_mode) == -1)
2715 fprintf(stderr, "%s\n", error == nil ? strerror(errno) : [[error localizedDescription] UTF8String]);
2718 notify_post("com.apple.mobile.application_installed");
2720 [delegate_ setStatusBarShowsProgress:NO];
2725 - (void) _detachNewThreadData:(ProgressData *)data {
2726 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
2728 [[data target] performSelector:[data selector] withObject:[data object]];
2731 [self performSelectorOnMainThread:@selector(_retachThread) withObject:nil waitUntilDone:YES];
2736 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title {
2737 UINavigationItem *item = [navbar_ topItem];
2738 [item setTitle:title];
2740 [status_ setText:nil];
2741 [output_ setText:@""];
2742 [progress_ setProgress:0];
2745 last_ = 0;//[NSDate timeIntervalSinceReferenceDate];
2747 [close_ removeFromSuperview];
2748 [overlay_ addSubview:progress_];
2749 [overlay_ addSubview:status_];
2751 [delegate_ setStatusBarShowsProgress:YES];
2755 FileFd file("/System/Library/LaunchDaemons/com.apple.SpringBoard.plist", FileFd::ReadOnly);
2756 MMap mmap(file, MMap::ReadOnly);
2758 sha1.Add(reinterpret_cast<uint8_t *>(mmap.Data()), mmap.Size());
2759 springlist_ = sha1.Result();
2762 [transition_ transition:6 toView:overlay_];
2765 detachNewThreadSelector:@selector(_detachNewThreadData:)
2767 withObject:[[ProgressData alloc]
2768 initWithSelector:selector
2775 - (void) repairWithSelector:(SEL)selector {
2777 detachNewThreadSelector:selector
2784 - (void) setConfigurationData:(NSString *)data {
2786 performSelectorOnMainThread:@selector(_setConfigurationData:)
2792 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id {
2793 Package *package = id == nil ? nil : [database_ packageWithName:id];
2795 UIActionSheet *sheet = [[[UIActionSheet alloc]
2796 initWithTitle:(package == nil ? @"Source Error" : [package name])
2797 buttons:[NSArray arrayWithObjects:@"Okay", nil]
2798 defaultButtonIndex:0
2803 [sheet setBodyText:error];
2804 [sheet popupAlertAnimated:YES];
2807 - (void) setProgressTitle:(NSString *)title {
2809 performSelectorOnMainThread:@selector(_setProgressTitle:)
2815 - (void) setProgressPercent:(float)percent {
2817 performSelectorOnMainThread:@selector(_setProgressPercent:)
2818 withObject:[NSNumber numberWithFloat:percent]
2823 - (void) startProgress {
2824 last_ = [NSDate timeIntervalSinceReferenceDate];
2827 - (void) addProgressOutput:(NSString *)output {
2829 performSelectorOnMainThread:@selector(_addProgressOutput:)
2835 - (bool) isCancelling:(size_t)received {
2837 NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate];
2838 if (received_ != received) {
2839 received_ = received;
2841 } else if (now - last_ > 30)
2848 - (void) _setConfigurationData:(NSString *)data {
2849 static Pcre conffile_r("^'(.*)' '(.*)' ([01]) ([01])$");
2851 _assert(conffile_r(data));
2853 NSString *ofile = conffile_r[1];
2854 //NSString *nfile = conffile_r[2];
2856 UIActionSheet *sheet = [[[UIActionSheet alloc]
2857 initWithTitle:@"Configuration Upgrade"
2858 buttons:[NSArray arrayWithObjects:
2859 @"Keep My Old Copy",
2860 @"Accept The New Copy",
2861 // XXX: @"See What Changed",
2863 defaultButtonIndex:0
2868 [sheet setBodyText:[NSString stringWithFormat:
2869 @"The following file has been changed by both the package maintainer and by you (or for you by a script).\n\n%@"
2872 [sheet popupAlertAnimated:YES];
2875 - (void) _setProgressTitle:(NSString *)title {
2876 [status_ setText:title];
2879 - (void) _setProgressPercent:(NSNumber *)percent {
2880 [progress_ setProgress:[percent floatValue]];
2883 - (void) _addProgressOutput:(NSString *)output {
2884 [output_ setText:[NSString stringWithFormat:@"%@\n%@", [output_ text], output]];
2885 CGSize size = [output_ contentSize];
2886 CGRect rect = {{0, size.height}, {size.width, 0}};
2887 [output_ scrollRectToVisible:rect animated:YES];
2890 - (BOOL) isRunning {
2897 /* Package Cell {{{ */
2898 @interface PackageCell : UISimpleTableCell {
2901 NSString *description_;
2903 //UIImageView *trusted_;
2905 UIImageView *badge_;
2906 UITextLabel *status_;
2910 - (PackageCell *) init;
2911 - (void) setPackage:(Package *)package;
2913 + (int) heightForPackage:(Package *)package;
2917 @implementation PackageCell
2919 - (void) clearPackage {
2930 if (description_ != nil) {
2931 [description_ release];
2935 if (source_ != nil) {
2942 [self clearPackage];
2947 //[trusted_ release];
2951 - (PackageCell *) init {
2952 if ((self = [super init]) != nil) {
2954 badge_ = [[UIImageView alloc] initWithFrame:CGRectMake(17, 70, 16, 16)];
2956 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 68, 280, 20)];
2957 [status_ setBackgroundColor:[UIColor clearColor]];
2958 [status_ setFont:small];
2963 - (void) setPackage:(Package *)package {
2964 [self clearPackage];
2966 Source *source = [package source];
2969 if (NSString *icon = [package icon])
2970 icon_ = [UIImage imageAtPath:[icon substringFromIndex:6]];
2971 if (icon_ == nil) if (NSString *section = [package section])
2972 icon_ = [UIImage imageAtPath:[NSString stringWithFormat:@"%@/Sections/%@.png", App_, Simplify(section)]];
2973 /*if (icon_ == nil) if (NSString *icon = [source defaultIcon])
2974 icon_ = [UIImage imageAtPath:[icon substringFromIndex:6]];*/
2976 icon_ = [UIImage applicationImageNamed:@"unknown.png"];
2978 icon_ = [icon_ retain];
2980 name_ = [[package name] retain];
2981 description_ = [[package tagline] retain];
2983 NSString *label = nil;
2984 bool trusted = false;
2986 if (source != nil) {
2987 label = [source label];
2988 trusted = [source trusted];
2989 } else if ([[package id] isEqualToString:@"firmware"])
2992 label = @"Unknown/Local";
2994 NSString *from = [NSString stringWithFormat:@"from %@", label];
2996 NSString *section = Simplify([package section]);
2997 if (section != nil && ![section isEqualToString:label])
2998 from = [from stringByAppendingString:[NSString stringWithFormat:@" (%@)", section]];
3000 source_ = [from retain];
3003 [badge_ removeFromSuperview];
3004 [status_ removeFromSuperview];
3006 if (NSString *mode = [package mode]) {
3007 [badge_ setImage:[UIImage applicationImageNamed:
3008 [mode isEqualToString:@"Remove"] || [mode isEqualToString:@"Purge"] ? @"removing.png" : @"installing.png"
3011 [status_ setText:[NSString stringWithFormat:@"Queued for %@", mode]];
3012 [status_ setColor:Blueish_];
3013 } else if ([package half]) {
3014 [badge_ setImage:[UIImage applicationImageNamed:@"damaged.png"]];
3015 [status_ setText:@"Package Damaged"];
3016 [status_ setColor:[UIColor redColor]];
3018 [badge_ setImage:nil];
3019 [status_ setText:nil];
3023 [self addSubview:badge_];
3024 [self addSubview:status_];
3029 - (void) drawContentInRect:(CGRect)rect selected:(BOOL)selected {
3032 rect.size = [icon_ size];
3034 rect.size.width /= 2;
3035 rect.size.height /= 2;
3037 rect.origin.x = 25 - rect.size.width / 2;
3038 rect.origin.y = 25 - rect.size.height / 2;
3040 [icon_ drawInRect:rect];
3048 [name_ drawAtPoint:CGPointMake(48, 8) forWidth:240 withFont:Font18Bold_ ellipsis:2];
3049 [source_ drawAtPoint:CGPointMake(58, 29) forWidth:225 withFont:Font12_ ellipsis:2];
3053 [description_ drawAtPoint:CGPointMake(12, 46) forWidth:280 withFont:Font14_ ellipsis:2];
3055 [super drawContentInRect:rect selected:selected];
3058 + (int) heightForPackage:(Package *)package {
3059 NSString *tagline([package tagline]);
3060 int height = tagline == nil || [tagline length] == 0 ? -17 : 0;
3062 if ([package hasMode] || [package half])
3071 /* Section Cell {{{ */
3072 @interface SectionCell : UISimpleTableCell {
3077 _UISwitchSlider *switch_;
3082 - (void) setSection:(Section *)section editing:(BOOL)editing;
3086 @implementation SectionCell
3088 - (void) clearSection {
3089 if (section_ != nil) {
3099 if (count_ != nil) {
3106 [self clearSection];
3113 if ((self = [super init]) != nil) {
3114 icon_ = [[UIImage applicationImageNamed:@"folder.png"] retain];
3116 switch_ = [[_UISwitchSlider alloc] initWithFrame:CGRectMake(218, 9, 60, 25)];
3117 [switch_ addTarget:self action:@selector(onSwitch:) forEvents:kUIControlEventMouseUpInside];
3121 - (void) onSwitch:(id)sender {
3122 NSMutableDictionary *metadata = [Sections_ objectForKey:section_];
3123 if (metadata == nil) {
3124 metadata = [NSMutableDictionary dictionaryWithCapacity:2];
3125 [Sections_ setObject:metadata forKey:section_];
3129 [metadata setObject:[NSNumber numberWithBool:([switch_ value] == 0)] forKey:@"Hidden"];
3132 - (void) setSection:(Section *)section editing:(BOOL)editing {
3133 if (editing != editing_) {
3135 [switch_ removeFromSuperview];
3137 [self addSubview:switch_];
3141 [self clearSection];
3143 if (section == nil) {
3144 name_ = [@"All Packages" retain];
3147 section_ = [section name];
3148 if (section_ != nil)
3149 section_ = [section_ retain];
3150 name_ = [(section_ == nil ? @"(No Section)" : section_) retain];
3151 count_ = [[NSString stringWithFormat:@"%d", [section count]] retain];
3154 [switch_ setValue:isSectionVisible(section_) animated:NO];
3158 - (void) drawContentInRect:(CGRect)rect selected:(BOOL)selected {
3159 [icon_ drawInRect:CGRectMake(8, 7, 32, 32)];
3166 [name_ drawAtPoint:CGPointMake(48, 9) forWidth:(editing_ ? 164 : 250) withFont:Font22Bold_ ellipsis:2];
3168 CGSize size = [count_ sizeWithFont:Font14_];
3172 [count_ drawAtPoint:CGPointMake(12 + (29 - size.width) / 2, 15) withFont:Font12Bold_];
3174 [super drawContentInRect:rect selected:selected];
3180 /* File Table {{{ */
3181 @interface FileTable : RVPage {
3182 _transient Database *database_;
3185 NSMutableArray *files_;
3189 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3190 - (void) setPackage:(Package *)package;
3194 @implementation FileTable
3197 if (package_ != nil)
3206 - (int) numberOfRowsInTable:(UITable *)table {
3207 return files_ == nil ? 0 : [files_ count];
3210 - (float) table:(UITable *)table heightForRow:(int)row {
3214 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
3215 if (reusing == nil) {
3216 reusing = [[[UIImageAndTextTableCell alloc] init] autorelease];
3217 UIFont *font = [UIFont systemFontOfSize:16];
3218 [[(UIImageAndTextTableCell *)reusing titleTextLabel] setFont:font];
3220 [(UIImageAndTextTableCell *)reusing setTitle:[files_ objectAtIndex:row]];
3224 - (BOOL) table:(UITable *)table canSelectRow:(int)row {
3228 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3229 if ((self = [super initWithBook:book]) != nil) {
3230 database_ = database;
3232 files_ = [[NSMutableArray arrayWithCapacity:32] retain];
3234 list_ = [[UITable alloc] initWithFrame:[self bounds]];
3235 [self addSubview:list_];
3237 UITableColumn *column = [[[UITableColumn alloc]
3238 initWithTitle:@"Name"
3240 width:[self frame].size.width
3243 [list_ setDataSource:self];
3244 [list_ setSeparatorStyle:1];
3245 [list_ addTableColumn:column];
3246 [list_ setDelegate:self];
3247 [list_ setReusesTableCells:YES];
3251 - (void) setPackage:(Package *)package {
3252 if (package_ != nil) {
3253 [package_ autorelease];
3262 [files_ removeAllObjects];
3264 if (package != nil) {
3265 package_ = [package retain];
3266 name_ = [[package id] retain];
3268 NSString *path = [NSString stringWithFormat:@"/var/lib/dpkg/info/%@.list", name_];
3271 std::ifstream fin([path UTF8String]);
3273 while (std::getline(fin, line))
3274 [files_ addObject:[NSString stringWithUTF8String:line.c_str()]];
3277 if ([files_ count] != 0) {
3278 if ([[files_ objectAtIndex:0] isEqualToString:@"/."])
3279 [files_ removeObjectAtIndex:0];
3280 [files_ sortUsingSelector:@selector(compareByPath:)];
3282 NSMutableArray *stack = [NSMutableArray arrayWithCapacity:8];
3283 [stack addObject:@"/"];
3285 for (int i(0), e([files_ count]); i != e; ++i) {
3286 NSString *file = [files_ objectAtIndex:i];
3287 while (![file hasPrefix:[stack lastObject]])
3288 [stack removeLastObject];
3289 NSString *directory = [stack lastObject];
3290 [stack addObject:[file stringByAppendingString:@"/"]];
3291 [files_ replaceObjectAtIndex:i withObject:[NSString stringWithFormat:@"%*s%@",
3292 ([stack count] - 2) * 3, "",
3293 [file substringFromIndex:[directory length]]
3302 - (void) resetViewAnimated:(BOOL)animated {
3303 [list_ resetViewAnimated:animated];
3306 - (void) reloadData {
3307 [self setPackage:[database_ packageWithName:name_]];
3308 [self reloadButtons];
3311 - (NSString *) title {
3312 return @"Installed Files";
3315 - (NSString *) backButtonTitle {
3321 /* Package View {{{ */
3322 @interface PackageView : BrowserView {
3325 NSMutableArray *buttons_;
3328 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3329 - (void) setPackage:(Package *)package;
3333 @implementation PackageView
3336 if (package_ != nil)
3344 - (void) _clickButtonWithName:(NSString *)name {
3345 if ([name isEqualToString:@"Install"])
3346 [delegate_ installPackage:package_];
3347 else if ([name isEqualToString:@"Reinstall"])
3348 [delegate_ installPackage:package_];
3349 else if ([name isEqualToString:@"Remove"])
3350 [delegate_ removePackage:package_];
3351 else if ([name isEqualToString:@"Upgrade"])
3352 [delegate_ installPackage:package_];
3353 else _assert(false);
3356 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
3357 int count = [buttons_ count];
3358 _assert(count != 0);
3359 _assert(button <= count + 1);
3361 if (count != button - 1)
3362 [self _clickButtonWithName:[buttons_ objectAtIndex:(button - 1)]];
3367 - (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
3368 [[frame windowObject] evaluateWebScript:@"document.base.target = '_top'"];
3369 return [super webView:sender didFinishLoadForFrame:frame];
3372 - (void) webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame {
3373 [window setValue:package_ forKey:@"package"];
3376 - (void) _rightButtonClicked {
3377 /*[super _rightButtonClicked];
3380 int count = [buttons_ count];
3381 _assert(count != 0);
3384 [self _clickButtonWithName:[buttons_ objectAtIndex:0]];
3386 NSMutableArray *buttons = [NSMutableArray arrayWithCapacity:(count + 1)];
3387 [buttons addObjectsFromArray:buttons_];
3388 [buttons addObject:@"Cancel"];
3390 [delegate_ slideUp:[[[UIActionSheet alloc]
3393 defaultButtonIndex:2
3400 - (NSString *) _rightButtonTitle {
3401 int count = [buttons_ count];
3402 return count == 0 ? nil : count != 1 ? @"Modify" : [buttons_ objectAtIndex:0];
3405 - (NSString *) title {
3409 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3410 if ((self = [super initWithBook:book database:database]) != nil) {
3411 database_ = database;
3412 buttons_ = [[NSMutableArray alloc] initWithCapacity:4];
3416 - (void) setPackage:(Package *)package {
3417 if (package_ != nil) {
3418 [package_ autorelease];
3427 [buttons_ removeAllObjects];
3429 if (package != nil) {
3430 package_ = [package retain];
3431 name_ = [[package id] retain];
3433 [self loadURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"package" ofType:@"html"]]];
3435 if ([package_ source] == nil);
3436 else if ([package_ upgradableAndEssential:NO])
3437 [buttons_ addObject:@"Upgrade"];
3438 else if ([package_ installed] == nil)
3439 [buttons_ addObject:@"Install"];
3441 [buttons_ addObject:@"Reinstall"];
3442 if ([package_ installed] != nil)
3443 [buttons_ addObject:@"Remove"];
3447 - (void) reloadData {
3448 [self setPackage:[database_ packageWithName:name_]];
3449 [self reloadButtons];
3454 /* Package Table {{{ */
3455 @interface PackageTable : RVPage {
3456 _transient Database *database_;
3460 NSMutableArray *packages_;
3461 NSMutableArray *sections_;
3462 UISectionList *list_;
3465 - (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object;
3467 - (void) setDelegate:(id)delegate;
3468 - (void) setObject:(id)object;
3470 - (void) reloadData;
3471 - (void) resetCursor;
3473 - (UISectionList *) list;
3475 - (void) setShouldHideHeaderInShortLists:(BOOL)hide;
3479 @implementation PackageTable
3482 [list_ setDataSource:nil];
3487 [packages_ release];
3488 [sections_ release];
3493 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
3494 return [sections_ count];
3497 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
3498 return [[sections_ objectAtIndex:section] name];
3501 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
3502 return [[sections_ objectAtIndex:section] row];
3505 - (int) numberOfRowsInTable:(UITable *)table {
3506 return [packages_ count];
3509 - (float) table:(UITable *)table heightForRow:(int)row {
3510 return [PackageCell heightForPackage:[packages_ objectAtIndex:row]];
3513 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
3515 reusing = [[[PackageCell alloc] init] autorelease];
3516 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
3520 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
3524 - (void) tableRowSelected:(NSNotification *)notification {
3525 int row = [[notification object] selectedRow];
3529 Package *package = [packages_ objectAtIndex:row];
3530 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
3531 [view setDelegate:delegate_];
3532 [view setPackage:package];
3533 [book_ pushPage:view];
3536 - (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object {
3537 if ((self = [super initWithBook:book]) != nil) {
3538 database_ = database;
3539 title_ = [title retain];
3541 object_ = object == nil ? nil : [object retain];
3543 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
3544 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
3546 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:YES];
3547 [list_ setDataSource:self];
3549 UITableColumn *column = [[[UITableColumn alloc]
3550 initWithTitle:@"Name"
3552 width:[self frame].size.width
3555 UITable *table = [list_ table];
3556 [table setSeparatorStyle:1];
3557 [table addTableColumn:column];
3558 [table setDelegate:self];
3559 [table setReusesTableCells:YES];
3561 [self addSubview:list_];
3564 [self setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
3565 [list_ setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
3569 - (void) setDelegate:(id)delegate {
3570 delegate_ = delegate;
3573 - (void) setObject:(id)object {
3579 object_ = [object retain];
3582 - (void) reloadData {
3583 NSArray *packages = [database_ packages];
3585 [packages_ removeAllObjects];
3586 [sections_ removeAllObjects];
3588 for (size_t i(0); i != [packages count]; ++i) {
3589 Package *package([packages objectAtIndex:i]);
3590 if ([package valid] && [[package performSelector:filter_ withObject:object_] boolValue])
3591 [packages_ addObject:package];
3594 Section *section = nil;
3596 for (size_t offset(0); offset != [packages_ count]; ++offset) {
3597 Package *package = [packages_ objectAtIndex:offset];
3598 NSString *name = [package index];
3600 if (section == nil || ![[section name] isEqualToString:name]) {
3601 section = [[[Section alloc] initWithName:name row:offset] autorelease];
3602 [sections_ addObject:section];
3605 [section addToCount];
3611 - (NSString *) title {
3615 - (void) resetViewAnimated:(BOOL)animated {
3616 [list_ resetViewAnimated:animated];
3619 - (void) resetCursor {
3620 [[list_ table] scrollPointVisibleAtTopLeft:CGPointMake(0, 0) animated:NO];
3623 - (UISectionList *) list {
3627 - (void) setShouldHideHeaderInShortLists:(BOOL)hide {
3628 [list_ setShouldHideHeaderInShortLists:hide];
3634 /* Add Source View {{{ */
3635 @interface AddSourceView : RVPage {
3636 _transient Database *database_;
3639 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3643 @implementation AddSourceView
3645 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3646 if ((self = [super initWithBook:book]) != nil) {
3647 database_ = database;
3653 /* Source Cell {{{ */
3654 @interface SourceCell : UITableCell {
3657 NSString *description_;
3663 - (SourceCell *) initWithSource:(Source *)source;
3667 @implementation SourceCell
3672 [description_ release];
3677 - (SourceCell *) initWithSource:(Source *)source {
3678 if ((self = [super init]) != nil) {
3680 icon_ = [UIImage applicationImageNamed:[NSString stringWithFormat:@"Sources/%@.png", [source host]]];
3682 icon_ = [UIImage applicationImageNamed:@"unknown.png"];
3683 icon_ = [icon_ retain];
3685 origin_ = [[source name] retain];
3686 label_ = [[source uri] retain];
3687 description_ = [[source description] retain];
3691 - (void) drawContentInRect:(CGRect)rect selected:(BOOL)selected {
3693 [icon_ drawInRect:CGRectMake(10, 10, 30, 30)];
3700 [origin_ drawAtPoint:CGPointMake(48, 8) forWidth:240 withFont:Font18Bold_ ellipsis:2];
3704 [label_ drawAtPoint:CGPointMake(58, 29) forWidth:225 withFont:Font12_ ellipsis:2];
3708 [description_ drawAtPoint:CGPointMake(12, 46) forWidth:280 withFont:Font14_ ellipsis:2];
3710 [super drawContentInRect:rect selected:selected];
3715 /* Source Table {{{ */
3716 @interface SourceTable : RVPage {
3717 _transient Database *database_;
3718 UISectionList *list_;
3719 NSMutableArray *sources_;
3720 UIActionSheet *alert_;
3724 UIProgressHUD *hud_;
3727 //NSURLConnection *installer_;
3728 NSURLConnection *trivial_bz2_;
3729 NSURLConnection *trivial_gz_;
3730 //NSURLConnection *automatic_;
3735 - (id) initWithBook:(RVBook *)book database:(Database *)database;
3739 @implementation SourceTable
3741 - (void) _deallocConnection:(NSURLConnection *)connection {
3742 if (connection != nil) {
3743 [connection cancel];
3744 //[connection setDelegate:nil];
3745 [connection release];
3750 [[list_ table] setDelegate:nil];
3751 [list_ setDataSource:nil];
3760 //[self _deallocConnection:installer_];
3761 [self _deallocConnection:trivial_gz_];
3762 [self _deallocConnection:trivial_bz2_];
3763 //[self _deallocConnection:automatic_];
3770 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
3771 return offset_ == 0 ? 1 : 2;
3774 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
3775 switch (section + (offset_ == 0 ? 1 : 0)) {
3776 case 0: return @"Entered by User";
3777 case 1: return @"Installed by Packages";
3785 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
3786 switch (section + (offset_ == 0 ? 1 : 0)) {
3788 case 1: return offset_;
3796 - (int) numberOfRowsInTable:(UITable *)table {
3797 return [sources_ count];
3800 - (float) table:(UITable *)table heightForRow:(int)row {
3801 Source *source = [sources_ objectAtIndex:row];
3802 return [source description] == nil ? 56 : 73;
3805 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col {
3806 Source *source = [sources_ objectAtIndex:row];
3807 // XXX: weird warning, stupid selectors ;P
3808 return [[[SourceCell alloc] initWithSource:(id)source] autorelease];
3811 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
3815 - (BOOL) table:(UITable *)table canSelectRow:(int)row {
3819 - (void) tableRowSelected:(NSNotification*)notification {
3820 UITable *table([list_ table]);
3821 int row([table selectedRow]);
3825 Source *source = [sources_ objectAtIndex:row];
3827 PackageTable *packages = [[[PackageTable alloc]
3830 title:[source label]
3831 filter:@selector(isVisibleInSource:)
3835 [packages setDelegate:delegate_];
3837 [book_ pushPage:packages];
3840 - (BOOL) table:(UITable *)table canDeleteRow:(int)row {
3841 Source *source = [sources_ objectAtIndex:row];
3842 return [source record] != nil;
3845 - (void) table:(UITable *)table willSwipeToDeleteRow:(int)row {
3846 [[list_ table] setDeleteConfirmationRow:row];
3849 - (void) table:(UITable *)table deleteRow:(int)row {
3850 Source *source = [sources_ objectAtIndex:row];
3851 [Sources_ removeObjectForKey:[source key]];
3852 [delegate_ syncData];
3855 - (void) _endConnection:(NSURLConnection *)connection {
3856 NSURLConnection **field = NULL;
3857 if (connection == trivial_bz2_)
3858 field = &trivial_bz2_;
3859 else if (connection == trivial_gz_)
3860 field = &trivial_gz_;
3861 _assert(field != NULL);
3862 [connection release];
3866 trivial_bz2_ == nil &&
3869 [delegate_ setStatusBarShowsProgress:NO];
3872 [hud_ removeFromSuperview];
3877 [Sources_ setObject:[NSDictionary dictionaryWithObjectsAndKeys:
3880 @"./", @"Distribution",
3881 nil] forKey:[NSString stringWithFormat:@"deb:%@:./", href_]];
3883 [delegate_ syncData];
3884 } else if (error_ != nil) {
3885 UIActionSheet *sheet = [[[UIActionSheet alloc]
3886 initWithTitle:@"Verification Error"
3887 buttons:[NSArray arrayWithObjects:@"OK", nil]
3888 defaultButtonIndex:0
3893 [sheet setBodyText:[error_ localizedDescription]];
3894 [sheet popupAlertAnimated:YES];
3896 UIActionSheet *sheet = [[[UIActionSheet alloc]
3897 initWithTitle:@"Did not Find Repository"
3898 buttons:[NSArray arrayWithObjects:@"OK", nil]
3899 defaultButtonIndex:0
3904 [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."];
3905 [sheet popupAlertAnimated:YES];
3911 if (error_ != nil) {
3918 - (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response {
3919 switch ([response statusCode]) {
3925 - (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
3926 fprintf(stderr, "connection:\"%s\" didFailWithError:\"%s\"", [href_ UTF8String], [[error localizedDescription] UTF8String]);
3928 error_ = [error retain];
3929 [self _endConnection:connection];
3932 - (void) connectionDidFinishLoading:(NSURLConnection *)connection {
3933 [self _endConnection:connection];
3936 - (NSURLConnection *) _requestHRef:(NSString *)href method:(NSString *)method {
3937 NSMutableURLRequest *request = [NSMutableURLRequest
3938 requestWithURL:[NSURL URLWithString:href]
3939 cachePolicy:NSURLRequestUseProtocolCachePolicy
3940 timeoutInterval:20.0
3943 [request setHTTPMethod:method];
3945 return [[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease];
3948 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
3949 NSString *context = [sheet context];
3950 if ([context isEqualToString:@"source"])
3953 NSString *href = [[sheet textField] text];
3955 //installer_ = [[self _requestHRef:href method:@"GET"] retain];
3957 if (![href hasSuffix:@"/"])
3958 href_ = [href stringByAppendingString:@"/"];
3961 href_ = [href_ retain];
3963 trivial_bz2_ = [[self _requestHRef:[href_ stringByAppendingString:@"Packages.bz2"] method:@"HEAD"] retain];
3964 trivial_gz_ = [[self _requestHRef:[href_ stringByAppendingString:@"Packages.gz"] method:@"HEAD"] retain];
3965 //trivial_bz2_ = [[self _requestHRef:[href stringByAppendingString:@"dists/Release"] method:@"HEAD"] retain];
3969 hud_ = [delegate_ addProgressHUD];
3970 [hud_ setText:@"Verifying URL"];
3983 - (id) initWithBook:(RVBook *)book database:(Database *)database {
3984 if ((self = [super initWithBook:book]) != nil) {
3985 database_ = database;
3986 sources_ = [[NSMutableArray arrayWithCapacity:16] retain];
3988 //list_ = [[UITable alloc] initWithFrame:[self bounds]];
3989 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:NO];
3990 [list_ setShouldHideHeaderInShortLists:NO];
3992 [self addSubview:list_];
3993 [list_ setDataSource:self];
3995 UITableColumn *column = [[UITableColumn alloc]
3996 initWithTitle:@"Name"
3998 width:[self frame].size.width
4001 UITable *table = [list_ table];
4002 [table setSeparatorStyle:1];
4003 [table addTableColumn:column];
4004 [table setDelegate:self];
4008 [self setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
4009 [list_ setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
4013 - (void) reloadData {
4015 _assert(list.ReadMainList());
4017 [sources_ removeAllObjects];
4018 [sources_ addObjectsFromArray:[database_ sources]];
4019 [sources_ sortUsingSelector:@selector(compareByNameAndType:)];
4021 int count = [sources_ count];
4022 for (offset_ = 0; offset_ != count; ++offset_) {
4023 Source *source = [sources_ objectAtIndex:offset_];
4024 if ([source record] == nil)
4031 - (void) resetViewAnimated:(BOOL)animated {
4032 [list_ resetViewAnimated:animated];
4035 - (void) _leftButtonClicked {
4036 /*[book_ pushPage:[[[AddSourceView alloc]
4041 UIActionSheet *sheet = [[[UIActionSheet alloc]
4042 initWithTitle:@"Enter Cydia/APT URL"
4043 buttons:[NSArray arrayWithObjects:@"Add Source", @"Cancel", nil]
4044 defaultButtonIndex:0
4049 [sheet addTextFieldWithValue:@"http://" label:@""];
4051 UITextInputTraits *traits = [[sheet textField] textInputTraits];
4052 [traits setAutocapitalizationType:0];
4053 [traits setKeyboardType:3];
4054 [traits setAutocorrectionType:1];
4056 [sheet popupAlertAnimated:YES];
4059 - (void) _rightButtonClicked {
4060 UITable *table = [list_ table];
4061 BOOL editing = [table isRowDeletionEnabled];
4062 [table enableRowDeletion:!editing animated:YES];
4063 [book_ reloadButtonsForPage:self];
4066 - (NSString *) title {
4070 - (NSString *) backButtonTitle {
4074 - (NSString *) leftButtonTitle {
4075 return [[list_ table] isRowDeletionEnabled] ? @"Add" : nil;
4078 - (NSString *) rightButtonTitle {
4079 return [[list_ table] isRowDeletionEnabled] ? @"Done" : @"Edit";
4082 - (UINavigationButtonStyle) rightButtonStyle {
4083 return [[list_ table] isRowDeletionEnabled] ? UINavigationButtonStyleHighlighted : UINavigationButtonStyleNormal;
4089 /* Installed View {{{ */
4090 @interface InstalledView : RVPage {
4091 _transient Database *database_;
4092 PackageTable *packages_;
4096 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4100 @implementation InstalledView
4103 [packages_ release];
4107 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4108 if ((self = [super initWithBook:book]) != nil) {
4109 database_ = database;
4111 packages_ = [[PackageTable alloc]
4115 filter:@selector(isInstalledAndVisible:)
4116 with:[NSNumber numberWithBool:YES]
4119 [self addSubview:packages_];
4121 [self setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
4122 [packages_ setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
4126 - (void) resetViewAnimated:(BOOL)animated {
4127 [packages_ resetViewAnimated:animated];
4130 - (void) reloadData {
4131 [packages_ reloadData];
4134 - (void) _rightButtonClicked {
4135 [packages_ setObject:[NSNumber numberWithBool:expert_]];
4136 [packages_ reloadData];
4138 [book_ reloadButtonsForPage:self];
4141 - (NSString *) title {
4142 return @"Installed";
4145 - (NSString *) backButtonTitle {
4149 - (NSString *) rightButtonTitle {
4150 return Role_ != nil && [Role_ isEqualToString:@"Developer"] ? nil : expert_ ? @"Expert" : @"Simple";
4153 - (UINavigationButtonStyle) rightButtonStyle {
4154 return expert_ ? UINavigationButtonStyleHighlighted : UINavigationButtonStyleNormal;
4157 - (void) setDelegate:(id)delegate {
4158 [super setDelegate:delegate];
4159 [packages_ setDelegate:delegate];
4166 @interface HomeView : BrowserView {
4171 @implementation HomeView
4173 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
4177 - (void) _leftButtonClicked {
4178 UIActionSheet *sheet = [[[UIActionSheet alloc]
4179 initWithTitle:@"About Cydia Installer"
4180 buttons:[NSArray arrayWithObjects:@"Close", nil]
4181 defaultButtonIndex:0
4187 @"Copyright (C) 2008\n"
4188 "Jay Freeman (saurik)\n"
4189 "saurik@saurik.com\n"
4190 "http://www.saurik.com/\n"
4193 "http://www.theokorigroup.com/\n"
4195 "College of Creative Studies,\n"
4196 "University of California,\n"
4198 "http://www.ccs.ucsb.edu/"
4201 [sheet popupAlertAnimated:YES];
4204 - (NSString *) leftButtonTitle {
4210 /* Manage View {{{ */
4211 @interface ManageView : BrowserView {
4216 @implementation ManageView
4218 - (NSString *) title {
4222 - (void) _leftButtonClicked {
4223 [delegate_ askForSettings];
4226 - (NSString *) leftButtonTitle {
4230 - (NSString *) _rightButtonTitle {
4237 /* Indirect Delegate {{{ */
4238 @interface IndirectDelegate : NSProxy {
4239 _transient id delegate_;
4242 - (void) setDelegate:(id)delegate;
4243 - (id) initWithDelegate:(id)delegate;
4246 @implementation IndirectDelegate
4248 - (void) setDelegate:(id)delegate {
4249 delegate_ = delegate;
4252 - (id) initWithDelegate:(id)delegate {
4253 delegate_ = delegate;
4257 - (void) doesNotRecognizeSelector:(SEL)sel {
4258 fprintf(stderr, "doesNotRecognizeSelector:@selector(%s)", sel_getName(sel));
4261 - (NSMethodSignature*) methodSignatureForSelector:(SEL)sel {
4262 if (delegate_ != nil)
4263 if (NSMethodSignature *sig = [delegate_ methodSignatureForSelector:sel])
4268 - (void) forwardInvocation:(NSInvocation*)inv {
4269 SEL sel = [inv selector];
4270 if (delegate_ != nil && [delegate_ respondsToSelector:sel])
4271 [inv invokeWithTarget:delegate_];
4276 /* Browser Implementation {{{ */
4277 @implementation BrowserView
4280 WebView *webview = [webview_ webView];
4281 [webview setFrameLoadDelegate:nil];
4282 [webview setResourceLoadDelegate:nil];
4283 [webview setUIDelegate:nil];
4285 [webview_ setDelegate:nil];
4286 [webview_ setGestureDelegate:nil];
4288 /*WebFrame *frame = [webview mainFrame];
4289 [frame loadHTMLString:@"" baseURL:[NSURL URLWithString:@"http://cydia.saurik.com/"]];*/
4291 //[webview_ removeFromSuperview];
4292 //[Documents_ addObject:[webview_ autorelease]];
4295 [indirect_ setDelegate:nil];
4296 [indirect_ release];
4298 [scroller_ setDelegate:nil];
4300 [scroller_ release];
4302 [indicator_ release];
4308 - (void) loadURL:(NSURL *)url cachePolicy:(NSURLRequestCachePolicy)policy {
4309 [self loadRequest:[NSURLRequest
4312 timeoutInterval:30.0
4316 - (void) loadURL:(NSURL *)url {
4317 [self loadURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy];
4320 - (NSURLRequest *) _addHeadersToRequest:(NSURLRequest *)request {
4321 NSMutableURLRequest *copy = [request mutableCopy];
4323 [copy addValue:[NSString stringWithUTF8String:Firmware_] forHTTPHeaderField:@"X-Firmware"];
4324 [copy addValue:[NSString stringWithUTF8String:Machine_] forHTTPHeaderField:@"X-Machine"];
4325 [copy addValue:UniqueID_ forHTTPHeaderField:@"X-Unique-ID"];
4328 [copy addValue:Role_ forHTTPHeaderField:@"X-Role"];
4333 - (void) loadRequest:(NSURLRequest *)request {
4335 [webview_ loadRequest:request];
4338 - (void) reloadURL {
4339 if ([urls_ count] == 0)
4341 NSURL *url = [[[urls_ lastObject] retain] autorelease];
4342 [urls_ removeLastObject];
4343 [self loadURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData];
4346 - (WebView *) webView {
4347 return [webview_ webView];
4350 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame {
4351 [scroller_ setContentSize:frame.size];
4354 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old {
4355 [self view:sender didSetFrame:frame];
4358 - (void) pushPage:(RVPage *)page {
4359 [self setBackButtonTitle:title_];
4360 [page setDelegate:delegate_];
4361 [book_ pushPage:page];
4364 - (RVPage *) _pageForPackage:(NSString *)name {
4365 if (Package *package = [database_ packageWithName:name]) {
4366 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
4367 [view setPackage:package];
4370 UIActionSheet *sheet = [[[UIActionSheet alloc]
4371 initWithTitle:@"Cannot Locate Package"
4372 buttons:[NSArray arrayWithObjects:@"Close", nil]
4373 defaultButtonIndex:0
4378 [sheet setBodyText:[NSString stringWithFormat:
4379 @"The package %@ cannot be found in your current sources. I might recommend installing more sources."
4382 [sheet popupAlertAnimated:YES];
4387 - (BOOL) getSpecial:(NSString *)href {
4391 [href hasPrefix:@"http://ax.phobos.apple.com/"] ||
4392 [href hasPrefix:@"http://phobos.apple.com/"] ||
4393 [href hasPrefix:@"http://www.youtube.com/watch?"] ||
4394 [href hasPrefix:@"tel:"]
4396 [delegate_ openURL:[NSURL URLWithString:href]];
4397 else if ([href hasPrefix:@"mailto:"]) {
4398 [delegate_ openURL:[NSURL URLWithString:href]];
4399 } else if ([href isEqualToString:@"cydia://add-source"])
4400 page = [[[AddSourceView alloc] initWithBook:book_ database:database_] autorelease];
4401 else if ([href isEqualToString:@"cydia://sources"])
4402 page = [[[SourceTable alloc] initWithBook:book_ database:database_] autorelease];
4403 else if ([href isEqualToString:@"cydia://packages"])
4404 page = [[[InstalledView alloc] initWithBook:book_ database:database_] autorelease];
4405 else if ([href hasPrefix:@"cydia://files/"]) {
4406 NSString *name = [href substringFromIndex:14];
4408 if (Package *package = [database_ packageWithName:name]) {
4409 FileTable *files = [[[FileTable alloc] initWithBook:book_ database:database_] autorelease];
4410 [files setPackage:package];
4413 } else if ([href hasPrefix:@"apptapp://package/"])
4414 page = [self _pageForPackage:[href substringFromIndex:18]];
4415 else if ([href hasPrefix:@"cydia://package/"])
4416 page = [self _pageForPackage:[href substringFromIndex:16]];
4417 else if (![href hasPrefix:@"apptapp:"] && ![href hasPrefix:@"cydia:"])
4421 [self pushPage:page];
4425 - (void) webView:(WebView *)sender willClickElement:(id)element {
4426 if ([[element localName] isEqualToString:@"img"])
4427 do if ((element = [element parentNode]) == nil)
4429 while (![[element localName] isEqualToString:@"a"]);
4430 if (![element respondsToSelector:@selector(href)])
4432 NSString *href = [element href];
4435 [self getSpecial:href];
4438 - (NSURLRequest *) webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource {
4439 NSURL *url = [request URL];
4440 if ([self getSpecial:[url absoluteString]])
4445 [book_ pushPage:self];
4448 return [self _addHeadersToRequest:request];
4451 - (BOOL) isSpecialScheme:(NSString *)scheme {
4453 [scheme isEqualToString:@"apptapp"] ||
4454 [scheme isEqualToString:@"cydia"] ||
4455 [scheme isEqualToString:@"mailto"] ||
4456 [scheme isEqualToString:@"tel"];
4459 - (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request {
4460 if (request != nil) {
4461 NSURL *url = [request URL];
4462 NSString *scheme = [url scheme];
4463 NSString *absolute = [url absoluteString];
4465 [self isSpecialScheme:scheme] ||
4466 [absolute hasPrefix:@"http://ax.phobos.apple.com/"] ||
4467 [absolute hasPrefix:@"http://phobos.apple.com/"] ||
4468 [absolute hasPrefix:@"http://www.yahoo.com/watch?"]
4473 [self setBackButtonTitle:title_];
4475 BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease];
4476 [browser setDelegate:delegate_];
4478 if (request != nil) {
4479 [browser loadRequest:[self _addHeadersToRequest:request]];
4480 [book_ pushPage:browser];
4483 return [browser webView];
4486 - (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame {
4487 if ([frame parentFrame] != nil)
4490 title_ = [title retain];
4491 [self setTitle:title];
4494 - (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame {
4495 if ([frame parentFrame] != nil)
4500 [indicator_ startAnimation];
4501 [self reloadButtons];
4503 if (title_ != nil) {
4508 [self setTitle:@"Loading"];
4510 WebView *webview = [webview_ webView];
4511 NSString *href = [webview mainFrameURL];
4512 [urls_ addObject:[NSURL URLWithString:href]];
4514 CGRect webrect = [scroller_ bounds];
4515 webrect.size.height = 0;
4516 [webview_ setFrame:webrect];
4518 [scroller_ scrollPointVisibleAtTopLeft:CGPointZero];
4521 - (void) _finishLoading {
4524 [indicator_ stopAnimation];
4525 [self reloadButtons];
4529 - (BOOL) webView:(WebView *)sender shouldScrollToPoint:(struct CGPoint)point forFrame:(WebFrame *)frame {
4531 return [webview_ webView:sender shouldScrollToPoint:point forFrame:frame];
4534 - (void) webView:(WebView *)sender didReceiveViewportArguments:(id)arguments forFrame:(WebFrame *)frame {
4535 return [webview_ webView:sender didReceiveViewportArguments:arguments forFrame:frame];
4538 - (void) webView:(WebView *)sender needsScrollNotifications:(id)notifications forFrame:(WebFrame *)frame {
4539 return [webview_ webView:sender needsScrollNotifications:notifications forFrame:frame];
4542 - (void) webView:(WebView *)sender didCommitLoadForFrame:(WebFrame *)frame {
4543 return [webview_ webView:sender didCommitLoadForFrame:frame];
4546 - (void) webView:(WebView *)sender didReceiveDocTypeForFrame:(WebFrame *)frame {
4547 return [webview_ webView:sender didReceiveDocTypeForFrame:frame];
4550 - (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
4551 if ([frame parentFrame] == nil)
4552 [self _finishLoading];
4553 return [webview_ webView:sender didFinishLoadForFrame:frame];
4556 - (void) webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
4557 if ([frame parentFrame] != nil)
4559 [self _finishLoading];
4561 [self loadURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@?%@",
4562 [[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"error" ofType:@"html"]] absoluteString],
4563 [[error localizedDescription] stringByAddingPercentEscapes]
4567 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4568 if ((self = [super initWithBook:book]) != nil) {
4569 database_ = database;
4572 struct CGRect bounds = [self bounds];
4574 UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:bounds] autorelease];
4575 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
4576 [self addSubview:pinstripe];
4578 scroller_ = [[UIScroller alloc] initWithFrame:bounds];
4579 [self addSubview:scroller_];
4581 [scroller_ setScrollingEnabled:YES];
4582 [scroller_ setAdjustForContentSizeChange:YES];
4583 [scroller_ setClipsSubviews:YES];
4584 [scroller_ setAllowsRubberBanding:YES];
4585 [scroller_ setScrollDecelerationFactor:0.99];
4586 [scroller_ setDelegate:self];
4588 CGRect webrect = [scroller_ bounds];
4589 webrect.size.height = 0;
4591 webview_ = [Documents_ lastObject];
4592 if (webview_ != nil) {
4593 webview_ = [webview_ retain];
4594 [Documents_ removeLastObject];
4595 [webview_ setFrame:webrect];
4597 webview_ = [[UIWebDocumentView alloc] initWithFrame:webrect];
4599 [webview_ setTileSize:CGSizeMake(webrect.size.width, 500)];
4601 [webview_ setTilingEnabled:YES];
4602 [webview_ setTileMinificationFilter:kCAFilterNearest];
4603 [webview_ setAutoresizes:YES];
4605 [webview_ setViewportSize:CGSizeMake(980, -1) forDocumentTypes:0x10];
4606 [webview_ setViewportSize:CGSizeMake(320, -1) forDocumentTypes:0x2];
4607 [webview_ setViewportSize:CGSizeMake(320, -1) forDocumentTypes:0x8];
4609 [webview_ _setDocumentType:0x4];
4611 [webview_ setZoomsFocusedFormControl:YES];
4612 [webview_ setContentsPosition:7];
4613 [webview_ setEnabledGestures:0xa];
4614 [webview_ setValue:[NSNumber numberWithBool:YES] forGestureAttribute:0x4];
4615 [webview_ setValue:[NSNumber numberWithBool:YES] forGestureAttribute:0x7];
4616 [webview_ setSmoothsFonts:YES];
4619 [webview_ setDelegate:self];
4620 [webview_ setGestureDelegate:self];
4621 [scroller_ addSubview:webview_];
4623 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:kUIProgressIndicatorStyleMediumWhite];
4624 indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(281, 12, indsize.width, indsize.height)];
4625 [indicator_ setStyle:kUIProgressIndicatorStyleMediumWhite];
4627 Package *package([database_ packageWithName:@"cydia"]);
4628 NSString *application = package == nil ? @"Cydia" : [NSString
4629 stringWithFormat:@"Cydia/%@",
4633 indirect_ = [[IndirectDelegate alloc] initWithDelegate:self];
4635 WebView *webview = [webview_ webView];
4636 [webview setApplicationNameForUserAgent:application];
4637 [webview setFrameLoadDelegate:self];
4638 [webview setResourceLoadDelegate:indirect_];
4639 [webview setUIDelegate:self];
4641 //[webview _setLayoutInterval:0.5];
4643 urls_ = [[NSMutableArray alloc] initWithCapacity:16];
4645 [self setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
4646 [scroller_ setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
4647 [pinstripe setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
4651 - (void) didFinishGesturesInView:(UIView *)view forEvent:(id)event {
4652 [webview_ redrawScaledDocument];
4655 - (void) _rightButtonClicked {
4660 - (NSString *) _rightButtonTitle {
4664 - (NSString *) rightButtonTitle {
4665 return loading_ ? @"" : [self _rightButtonTitle];
4668 - (NSString *) title {
4672 - (NSString *) backButtonTitle {
4676 - (void) setPageActive:(BOOL)active {
4678 [indicator_ removeFromSuperview];
4680 [[book_ navigationBar] addSubview:indicator_];
4683 - (void) resetViewAnimated:(BOOL)animated {
4686 - (void) setPushed:(bool)pushed {
4693 @interface CYBook : RVBook <
4696 _transient Database *database_;
4697 UINavigationBar *overlay_;
4698 UIProgressIndicator *indicator_;
4699 UITextLabel *prompt_;
4700 UIProgressBar *progress_;
4701 UINavigationButton *cancel_;
4704 NSTimeInterval last_;
4707 - (id) initWithFrame:(CGRect)frame database:(Database *)database;
4713 /* Install View {{{ */
4714 @interface InstallView : RVPage {
4715 _transient Database *database_;
4716 NSMutableArray *sections_;
4717 NSMutableArray *filtered_;
4718 UITransitionView *transition_;
4724 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4725 - (void) reloadData;
4730 @implementation InstallView
4733 [list_ setDataSource:nil];
4734 [list_ setDelegate:nil];
4736 [sections_ release];
4737 [filtered_ release];
4738 [transition_ release];
4740 [accessory_ release];
4744 - (int) numberOfRowsInTable:(UITable *)table {
4745 return editing_ ? [sections_ count] : [filtered_ count] + 1;
4748 - (float) table:(UITable *)table heightForRow:(int)row {
4752 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
4754 reusing = [[[SectionCell alloc] init] autorelease];
4755 [(SectionCell *)reusing setSection:(editing_ ?
4756 [sections_ objectAtIndex:row] :
4757 (row == 0 ? nil : [filtered_ objectAtIndex:(row - 1)])
4758 ) editing:editing_];
4762 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
4766 - (BOOL) table:(UITable *)table canSelectRow:(int)row {
4770 - (void) tableRowSelected:(NSNotification *)notification {
4771 int row = [[notification object] selectedRow];
4782 title = @"All Packages";
4784 section = [filtered_ objectAtIndex:(row - 1)];
4785 name = [section name];
4791 title = @"(No Section)";
4795 PackageTable *table = [[[PackageTable alloc]
4799 filter:@selector(isVisiblyUninstalledInSection:)
4803 [table setDelegate:delegate_];
4805 [book_ pushPage:table];
4808 - (id) initWithBook:(RVBook *)book database:(Database *)database {
4809 if ((self = [super initWithBook:book]) != nil) {
4810 database_ = database;
4812 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
4813 filtered_ = [[NSMutableArray arrayWithCapacity:16] retain];
4815 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
4816 [self addSubview:transition_];
4818 list_ = [[UITable alloc] initWithFrame:[transition_ bounds]];
4819 [transition_ transition:0 toView:list_];
4821 UITableColumn *column = [[[UITableColumn alloc]
4822 initWithTitle:@"Name"
4824 width:[self frame].size.width
4827 [list_ setDataSource:self];
4828 [list_ setSeparatorStyle:1];
4829 [list_ addTableColumn:column];
4830 [list_ setDelegate:self];
4831 [list_ setReusesTableCells:YES];
4835 [self setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
4836 [list_ setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
4840 - (void) reloadData {
4841 NSArray *packages = [database_ packages];
4843 [sections_ removeAllObjects];
4844 [filtered_ removeAllObjects];
4846 NSMutableArray *filtered = [NSMutableArray arrayWithCapacity:[packages count]];
4847 NSMutableDictionary *sections = [NSMutableDictionary dictionaryWithCapacity:32];
4849 for (size_t i(0); i != [packages count]; ++i) {
4850 Package *package([packages objectAtIndex:i]);
4851 NSString *name([package section]);
4854 Section *section([sections objectForKey:name]);
4855 if (section == nil) {
4856 section = [[[Section alloc] initWithName:name] autorelease];
4857 [sections setObject:section forKey:name];
4861 if ([package valid] && [package installed] == nil && [package visible])
4862 [filtered addObject:package];
4865 [sections_ addObjectsFromArray:[sections allValues]];
4866 [sections_ sortUsingSelector:@selector(compareByName:)];
4868 [filtered sortUsingSelector:@selector(compareBySection:)];
4870 Section *section = nil;
4871 for (size_t offset = 0, count = [filtered count]; offset != count; ++offset) {
4872 Package *package = [filtered objectAtIndex:offset];
4873 NSString *name = [package section];
4875 if (section == nil || name != nil && ![[section name] isEqualToString:name]) {
4876 section = name == nil ?
4877 [[[Section alloc] initWithName:nil] autorelease] :
4878 [sections objectForKey:name];
4879 [filtered_ addObject:section];
4882 [section addToCount];
4888 - (void) resetView {
4890 [self _rightButtonClicked];
4893 - (void) resetViewAnimated:(BOOL)animated {
4894 [list_ resetViewAnimated:animated];
4897 - (void) _rightButtonClicked {
4898 if ((editing_ = !editing_))
4901 [delegate_ updateData];
4904 [book_ setTitle:[self title] forPage:self];
4905 [book_ reloadButtonsForPage:self];
4908 - (NSString *) title {
4909 return editing_ ? @"Section Visibility" : @"Install by Section";
4912 - (NSString *) backButtonTitle {
4916 - (NSString *) rightButtonTitle {
4917 return [sections_ count] == 0 ? nil : editing_ ? @"Done" : @"Edit";
4920 - (UINavigationButtonStyle) rightButtonStyle {
4921 return editing_ ? UINavigationButtonStyleHighlighted : UINavigationButtonStyleNormal;
4924 - (UIView *) accessoryView {
4930 /* Changes View {{{ */
4931 @interface ChangesView : RVPage {
4932 _transient Database *database_;
4933 NSMutableArray *packages_;
4934 NSMutableArray *sections_;
4935 UISectionList *list_;
4939 - (id) initWithBook:(RVBook *)book database:(Database *)database;
4940 - (void) reloadData;
4944 @implementation ChangesView
4947 [[list_ table] setDelegate:nil];
4948 [list_ setDataSource:nil];
4950 [packages_ release];
4951 [sections_ release];
4956 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
4957 return [sections_ count];
4960 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
4961 return [[sections_ objectAtIndex:section] name];
4964 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
4965 return [[sections_ objectAtIndex:section] row];
4968 - (int) numberOfRowsInTable:(UITable *)table {
4969 return [packages_ count];
4972 - (float) table:(UITable *)table heightForRow:(int)row {
4973 return [PackageCell heightForPackage:[packages_ objectAtIndex:row]];
4976 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
4978 reusing = [[[PackageCell alloc] init] autorelease];
4979 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
4983 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
4987 - (void) tableRowSelected:(NSNotification *)notification {
4988 int row = [[notification object] selectedRow];
4991 Package *package = [packages_ objectAtIndex:row];
4992 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
4993 [view setDelegate:delegate_];
4994 [view setPackage:package];
4995 [book_ pushPage:view];
4998 - (void) _leftButtonClicked {
4999 [(CYBook *)book_ update];
5000 [self reloadButtons];
5003 - (void) _rightButtonClicked {
5004 [delegate_ distUpgrade];
5007 - (id) initWithBook:(RVBook *)book database:(Database *)database {
5008 if ((self = [super initWithBook:book]) != nil) {
5009 database_ = database;
5011 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
5012 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
5014 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:NO];
5015 [self addSubview:list_];
5017 [list_ setShouldHideHeaderInShortLists:NO];
5018 [list_ setDataSource:self];
5019 //[list_ setSectionListStyle:1];
5021 UITableColumn *column = [[[UITableColumn alloc]
5022 initWithTitle:@"Name"
5024 width:[self frame].size.width
5027 UITable *table = [list_ table];
5028 [table setSeparatorStyle:1];
5029 [table addTableColumn:column];
5030 [table setDelegate:self];
5031 [table setReusesTableCells:YES];
5035 [self setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
5036 [list_ setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
5040 - (void) reloadData {
5041 NSArray *packages = [database_ packages];
5043 [packages_ removeAllObjects];
5044 [sections_ removeAllObjects];
5046 for (size_t i(0); i != [packages count]; ++i) {
5047 Package *package([packages objectAtIndex:i]);
5050 [package installed] == nil && [package valid] && [package visible] ||
5051 [package upgradableAndEssential:NO]
5053 [packages_ addObject:package];
5056 [packages_ sortUsingSelector:@selector(compareForChanges:)];
5058 Section *upgradable = [[[Section alloc] initWithName:@"Available Upgrades"] autorelease];
5059 Section *section = nil;
5062 bool unseens = false;
5064 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, Locale_, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
5066 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
5067 Package *package = [packages_ objectAtIndex:offset];
5069 if ([package upgradableAndEssential:YES]) {
5071 [upgradable addToCount];
5074 NSDate *seen = [package seen];
5079 name = [@"n/a ?" retain];
5081 name = (NSString *) CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen);
5084 if (section == nil || ![[section name] isEqualToString:name]) {
5085 section = [[[Section alloc] initWithName:name row:offset] autorelease];
5086 [sections_ addObject:section];
5090 [section addToCount];
5094 CFRelease(formatter);
5097 Section *last = [sections_ lastObject];
5098 size_t count = [last count];
5099 [packages_ removeObjectsInRange:NSMakeRange([packages_ count] - count, count)];
5100 [sections_ removeLastObject];
5104 [sections_ insertObject:upgradable atIndex:0];
5107 [self reloadButtons];
5110 - (void) resetViewAnimated:(BOOL)animated {
5111 [list_ resetViewAnimated:animated];
5114 - (NSString *) leftButtonTitle {
5115 return [(CYBook *)book_ updating] ? nil : @"Refresh";
5118 - (NSString *) rightButtonTitle {
5119 return upgrades_ == 0 ? nil : [NSString stringWithFormat:@"Upgrade (%u)", upgrades_];
5122 - (NSString *) title {
5128 /* Search View {{{ */
5129 @protocol SearchViewDelegate
5130 - (void) showKeyboard:(BOOL)show;
5133 @interface SearchView : RVPage {
5135 UISearchField *field_;
5136 UITransitionView *transition_;
5137 PackageTable *table_;
5138 UIPreferencesTable *advanced_;
5144 - (id) initWithBook:(RVBook *)book database:(Database *)database;
5145 - (void) reloadData;
5149 @implementation SearchView
5152 [field_ setDelegate:nil];
5154 [accessory_ release];
5156 [transition_ release];
5158 [advanced_ release];
5163 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
5167 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
5169 case 0: return @"Advanced Search (Coming Soon!)";
5171 default: _assert(false);
5175 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
5179 default: _assert(false);
5183 - (void) _showKeyboard:(BOOL)show {
5184 CGSize keysize = [UIKeyboard defaultSize];
5185 CGRect keydown = [book_ pageBounds];
5186 CGRect keyup = keydown;
5187 keyup.size.height -= keysize.height - ButtonBarHeight_;
5189 float delay = KeyboardTime_ * ButtonBarHeight_ / keysize.height;
5191 UIFrameAnimation *animation = [[[UIFrameAnimation alloc] initWithTarget:[table_ list]] autorelease];
5192 [animation setSignificantRectFields:8];
5195 [animation setStartFrame:keydown];
5196 [animation setEndFrame:keyup];
5198 [animation setStartFrame:keyup];
5199 [animation setEndFrame:keydown];
5202 UIAnimator *animator = [UIAnimator sharedAnimator];
5205 addAnimations:[NSArray arrayWithObjects:animation, nil]
5206 withDuration:(KeyboardTime_ - delay)
5211 [animator performSelector:@selector(startAnimation:) withObject:animation afterDelay:delay];
5213 [delegate_ showKeyboard:show];
5216 - (void) textFieldDidBecomeFirstResponder:(UITextField *)field {
5217 [self _showKeyboard:YES];
5220 - (void) textFieldDidResignFirstResponder:(UITextField *)field {
5221 [self _showKeyboard:NO];
5224 - (void) keyboardInputChanged:(UIFieldEditor *)editor {
5226 NSString *text([field_ text]);
5227 [field_ setClearButtonStyle:(text == nil || [text length] == 0 ? 0 : 2)];
5233 - (void) textFieldClearButtonPressed:(UITextField *)field {
5237 - (void) keyboardInputShouldDelete:(id)input {
5241 - (BOOL) keyboardInput:(id)input shouldInsertText:(NSString *)text isMarkedText:(int)marked {
5242 if ([text length] != 1 || [text characterAtIndex:0] != '\n') {
5246 [field_ resignFirstResponder];
5251 - (id) initWithBook:(RVBook *)book database:(Database *)database {
5252 if ((self = [super initWithBook:book]) != nil) {
5253 CGRect pageBounds = [book_ pageBounds];
5255 /*UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:pageBounds] autorelease];
5256 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
5257 [self addSubview:pinstripe];*/
5259 transition_ = [[UITransitionView alloc] initWithFrame:pageBounds];
5260 [self addSubview:transition_];
5262 advanced_ = [[UIPreferencesTable alloc] initWithFrame:pageBounds];
5264 [advanced_ setReusesTableCells:YES];
5265 [advanced_ setDataSource:self];
5266 [advanced_ reloadData];
5268 dimmed_ = [[UIView alloc] initWithFrame:pageBounds];
5269 CGColor dimmed(space_, 0, 0, 0, 0.5);
5270 [dimmed_ setBackgroundColor:[UIColor colorWithCGColor:dimmed]];
5272 table_ = [[PackageTable alloc]
5276 filter:@selector(isUnfilteredAndSearchedForBy:)
5280 [table_ setShouldHideHeaderInShortLists:NO];
5281 [transition_ transition:0 toView:table_];
5290 area.origin.x = /*cnfrect.origin.x + cnfrect.size.width + 4 +*/ 10;
5297 [self bounds].size.width - area.origin.x - 18;
5299 area.size.height = [UISearchField defaultHeight];
5301 field_ = [[UISearchField alloc] initWithFrame:area];
5303 UIFont *font = [UIFont systemFontOfSize:16];
5304 [field_ setFont:font];
5306 [field_ setPlaceholder:@"Package Names & Descriptions"];
5307 [field_ setDelegate:self];
5309 [field_ setPaddingTop:5];
5311 UITextInputTraits *traits = [field_ textInputTraits];
5312 [traits setAutocapitalizationType:0];
5313 [traits setAutocorrectionType:1];
5314 [traits setReturnKeyType:6];
5316 CGRect accrect = {{0, 6}, {6 + cnfrect.size.width + 6 + area.size.width + 6, area.size.height}};
5318 accessory_ = [[UIView alloc] initWithFrame:accrect];
5319 [accessory_ addSubview:field_];
5321 /*UIPushButton *configure = [[[UIPushButton alloc] initWithFrame:cnfrect] autorelease];
5322 [configure setShowPressFeedback:YES];
5323 [configure setImage:[UIImage applicationImageNamed:@"advanced.png"]];
5324 [configure addTarget:self action:@selector(configurePushed) forEvents:1];
5325 [accessory_ addSubview:configure];*/
5327 [self setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
5328 [table_ setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
5334 LKAnimation *animation = [LKTransition animation];
5335 [animation setType:@"oglFlip"];
5336 [animation setTimingFunction:[LKTimingFunction functionWithName:@"easeInEaseOut"]];
5337 [animation setFillMode:@"extended"];
5338 [animation setTransitionFlags:3];
5339 [animation setDuration:10];
5340 [animation setSpeed:0.35];
5341 [animation setSubtype:(flipped_ ? @"fromLeft" : @"fromRight")];
5342 [[transition_ _layer] addAnimation:animation forKey:0];
5343 [transition_ transition:0 toView:(flipped_ ? (UIView *) table_ : (UIView *) advanced_)];
5344 flipped_ = !flipped_;
5348 - (void) configurePushed {
5349 [field_ resignFirstResponder];
5353 - (void) resetViewAnimated:(BOOL)animated {
5356 [table_ resetViewAnimated:animated];
5359 - (void) reloadData {
5362 [table_ setObject:[field_ text]];
5363 [table_ reloadData];
5364 [table_ resetCursor];
5367 - (UIView *) accessoryView {
5371 - (NSString *) title {
5375 - (NSString *) backButtonTitle {
5379 - (void) setDelegate:(id)delegate {
5380 [table_ setDelegate:delegate];
5381 [super setDelegate:delegate];
5387 @implementation CYBook
5391 [indicator_ release];
5393 [progress_ release];
5398 - (NSString *) getTitleForPage:(RVPage *)page {
5399 return Simplify([super getTitleForPage:page]);
5407 [UIView beginAnimations:nil context:NULL];
5409 CGRect ovrframe = [overlay_ frame];
5410 ovrframe.origin.y = 0;
5411 [overlay_ setFrame:ovrframe];
5413 CGRect barframe = [navbar_ frame];
5414 barframe.origin.y += ovrframe.size.height;
5415 [navbar_ setFrame:barframe];
5417 CGRect trnframe = [transition_ frame];
5418 trnframe.origin.y += ovrframe.size.height;
5419 trnframe.size.height -= ovrframe.size.height;
5420 [transition_ setFrame:trnframe];
5422 [UIView endAnimations];
5424 [indicator_ startAnimation];
5425 [prompt_ setText:@"Updating Database"];
5426 [progress_ setProgress:0];
5429 last_ = [NSDate timeIntervalSinceReferenceDate];
5431 [overlay_ addSubview:cancel_];
5434 detachNewThreadSelector:@selector(_update)
5443 [indicator_ stopAnimation];
5445 [UIView beginAnimations:nil context:NULL];
5447 CGRect ovrframe = [overlay_ frame];
5448 ovrframe.origin.y = -ovrframe.size.height;
5449 [overlay_ setFrame:ovrframe];
5451 CGRect barframe = [navbar_ frame];
5452 barframe.origin.y -= ovrframe.size.height;
5453 [navbar_ setFrame:barframe];
5455 CGRect trnframe = [transition_ frame];
5456 trnframe.origin.y -= ovrframe.size.height;
5457 trnframe.size.height += ovrframe.size.height;
5458 [transition_ setFrame:trnframe];
5460 [UIView commitAnimations];
5462 [delegate_ performSelector:@selector(reloadData) withObject:nil afterDelay:0];
5465 - (id) initWithFrame:(CGRect)frame database:(Database *)database {
5466 if ((self = [super initWithFrame:frame]) != nil) {
5467 database_ = database;
5469 CGRect ovrrect = [navbar_ bounds];
5470 ovrrect.size.height = [UINavigationBar defaultSize].height;
5471 ovrrect.origin.y = -ovrrect.size.height;
5473 overlay_ = [[UINavigationBar alloc] initWithFrame:ovrrect];
5474 [self addSubview:overlay_];
5476 [overlay_ setBarStyle:1];
5477 int barstyle = [overlay_ _barStyle:NO];
5478 bool ugly = barstyle == 0;
5480 UIProgressIndicatorStyle style = ugly ?
5481 kUIProgressIndicatorStyleMediumBrown :
5482 kUIProgressIndicatorStyleMediumWhite;
5484 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:style];
5485 unsigned indoffset = (ovrrect.size.height - indsize.height) / 2;
5486 CGRect indrect = {{indoffset, indoffset}, indsize};
5488 indicator_ = [[UIProgressIndicator alloc] initWithFrame:indrect];
5489 [indicator_ setStyle:style];
5490 [overlay_ addSubview:indicator_];
5492 CGSize prmsize = {215, indsize.height + 4};
5495 indoffset * 2 + indsize.width,
5499 unsigned(ovrrect.size.height - prmsize.height) / 2
5502 UIFont *font = [UIFont systemFontOfSize:15];
5504 prompt_ = [[UITextLabel alloc] initWithFrame:prmrect];
5506 [prompt_ setColor:[UIColor colorWithCGColor:(ugly ? Blueish_ : Off_)]];
5507 [prompt_ setBackgroundColor:[UIColor clearColor]];
5508 [prompt_ setFont:font];
5510 [overlay_ addSubview:prompt_];
5512 CGSize prgsize = {75, 100};
5515 ovrrect.size.width - prgsize.width - 10,
5516 (ovrrect.size.height - prgsize.height) / 2
5519 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
5520 [progress_ setStyle:0];
5521 [overlay_ addSubview:progress_];
5523 cancel_ = [[UINavigationButton alloc] initWithTitle:@"Cancel" style:UINavigationButtonStyleHighlighted];
5524 [cancel_ addTarget:self action:@selector(_onCancel) forControlEvents:UIControlEventTouchUpInside];
5526 CGRect frame = [cancel_ frame];
5527 frame.size.width = 65;
5528 frame.origin.x = ovrrect.size.width - frame.size.width - 5;
5529 frame.origin.y = (ovrrect.size.height - frame.size.height) / 2;
5530 [cancel_ setFrame:frame];
5532 [cancel_ setBarStyle:barstyle];
5536 - (void) _onCancel {
5538 [cancel_ removeFromSuperview];
5542 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5545 status.setDelegate(self);
5547 [database_ updateWithStatus:status];
5550 performSelectorOnMainThread:@selector(_update_)
5558 - (void) setProgressError:(NSString *)error forPackage:(NSString *)id {
5559 [prompt_ setText:[NSString stringWithFormat:@"Error: %@", error]];
5562 - (void) setProgressTitle:(NSString *)title {
5564 performSelectorOnMainThread:@selector(_setProgressTitle:)
5570 - (void) setProgressPercent:(float)percent {
5572 performSelectorOnMainThread:@selector(_setProgressPercent:)
5573 withObject:[NSNumber numberWithFloat:percent]
5578 - (void) startProgress {
5581 - (void) addProgressOutput:(NSString *)output {
5583 performSelectorOnMainThread:@selector(_addProgressOutput:)
5589 - (bool) isCancelling:(size_t)received {
5590 NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate];
5591 if (received_ != received) {
5592 received_ = received;
5594 } else if (now - last_ > 15)
5599 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
5603 - (void) _setProgressTitle:(NSString *)title {
5604 [prompt_ setText:title];
5607 - (void) _setProgressPercent:(NSNumber *)percent {
5608 [progress_ setProgress:[percent floatValue]];
5611 - (void) _addProgressOutput:(NSString *)output {
5616 @interface Cydia : UIApplication <
5617 ConfirmationViewDelegate,
5618 ProgressViewDelegate,
5627 UIToolbar *buttonbar_;
5629 ConfirmationView *confirm_;
5631 NSMutableArray *essential_;
5632 NSMutableArray *broken_;
5634 Database *database_;
5635 ProgressView *progress_;
5639 UIKeyboard *keyboard_;
5640 UIProgressHUD *hud_;
5642 InstallView *install_;
5643 ChangesView *changes_;
5644 ManageView *manage_;
5645 SearchView *search_;
5650 @implementation Cydia
5653 if ([broken_ count] != 0) {
5654 int count = [broken_ count];
5656 UIActionSheet *sheet = [[[UIActionSheet alloc]
5657 initWithTitle:[NSString stringWithFormat:@"%d Half-Installed Package%@", count, (count == 1 ? @"" : @"s")]
5658 buttons:[NSArray arrayWithObjects:
5660 @"Ignore (Temporary)",
5662 defaultButtonIndex:0
5667 [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."];
5668 [sheet popupAlertAnimated:YES];
5669 } else if (!Ignored_ && [essential_ count] != 0) {
5670 int count = [essential_ count];
5672 UIActionSheet *sheet = [[[UIActionSheet alloc]
5673 initWithTitle:[NSString stringWithFormat:@"%d Essential Upgrade%@", count, (count == 1 ? @"" : @"s")]
5674 buttons:[NSArray arrayWithObjects:@"Upgrade Essential", @"Ignore (Temporary)", nil]
5675 defaultButtonIndex:0
5680 [sheet setBodyText:@"One or more essential packages are currently out of date. If these upgrades are not performed you are likely to encounter errors."];
5681 [sheet popupAlertAnimated:YES];
5685 - (void) _reloadData {
5686 /*UIProgressHUD *hud = [[UIProgressHUD alloc] initWithWindow:window_];
5687 [hud setText:@"Reloading Data"];
5688 [overlay_ addSubview:hud];
5691 [database_ reloadData];
5695 [essential_ removeAllObjects];
5696 [broken_ removeAllObjects];
5698 NSArray *packages = [database_ packages];
5699 for (int i(0), e([packages count]); i != e; ++i) {
5700 Package *package = [packages objectAtIndex:i];
5702 [broken_ addObject:package];
5703 if ([package upgradableAndEssential:NO]) {
5704 if ([package essential])
5705 [essential_ addObject:package];
5711 NSString *badge([[NSNumber numberWithInt:changes] stringValue]);
5712 [buttonbar_ setBadgeValue:badge forButton:3];
5713 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
5714 [buttonbar_ setBadgeAnimated:YES forButton:3];
5715 [self setApplicationBadge:badge];
5717 [buttonbar_ setBadgeValue:nil forButton:3];
5718 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
5719 [buttonbar_ setBadgeAnimated:NO forButton:3];
5720 [self removeApplicationBadge];
5725 if ([packages count] == 0);
5734 [hud removeFromSuperview];*/
5737 - (void) _saveConfig {
5739 _assert([Metadata_ writeToFile:@"/var/lib/cydia/metadata.plist" atomically:YES] == YES);
5744 - (void) updateData {
5747 /* XXX: this is just stupid */
5749 [install_ reloadData];
5751 [changes_ reloadData];
5753 [search_ reloadData];
5763 FILE *file = fopen("/etc/apt/sources.list.d/cydia.list", "w");
5764 _assert(file != NULL);
5766 NSArray *keys = [Sources_ allKeys];
5768 for (int i(0), e([keys count]); i != e; ++i) {
5769 NSString *key = [keys objectAtIndex:i];
5770 NSDictionary *source = [Sources_ objectForKey:key];
5772 fprintf(file, "%s %s %s\n",
5773 [[source objectForKey:@"Type"] UTF8String],
5774 [[source objectForKey:@"URI"] UTF8String],
5775 [[source objectForKey:@"Distribution"] UTF8String]
5784 detachNewThreadSelector:@selector(update_)
5787 title:@"Updating Sources"
5791 - (void) reloadData {
5792 @synchronized (self) {
5793 if (confirm_ == nil)
5799 pkgProblemResolver *resolver = [database_ resolver];
5801 resolver->InstallProtect();
5802 if (!resolver->Resolve(true))
5807 [database_ prepare];
5809 if ([database_ cache]->BrokenCount() == 0)
5810 confirm_ = [[ConfirmationView alloc] initWithView:underlay_ database:database_ delegate:self];
5812 NSMutableArray *broken = [NSMutableArray arrayWithCapacity:16];
5813 NSArray *packages = [database_ packages];
5815 for (size_t i(0); i != [packages count]; ++i) {
5816 Package *package = [packages objectAtIndex:i];
5817 if ([package broken])
5818 [broken addObject:[package name]];
5821 UIActionSheet *sheet = [[[UIActionSheet alloc]
5822 initWithTitle:[NSString stringWithFormat:@"%d Broken Packages", [database_ cache]->BrokenCount()]
5823 buttons:[NSArray arrayWithObjects:@"Okay", nil]
5824 defaultButtonIndex:0
5829 [sheet setBodyText:[NSString stringWithFormat:@"The following packages have unmet dependencies:\n\n%@", [broken componentsJoinedByString:@"\n"]]];
5830 [sheet popupAlertAnimated:YES];
5836 - (void) installPackage:(Package *)package {
5837 @synchronized (self) {
5844 - (void) removePackage:(Package *)package {
5845 @synchronized (self) {
5852 - (void) distUpgrade {
5853 @synchronized (self) {
5854 [database_ upgrade];
5860 @synchronized (self) {
5868 [overlay_ removeFromSuperview];
5872 detachNewThreadSelector:@selector(perform)
5879 - (void) bootstrap_ {
5881 [database_ upgrade];
5882 [database_ prepare];
5883 [database_ perform];
5886 - (void) bootstrap {
5888 detachNewThreadSelector:@selector(bootstrap_)
5891 title:@"Bootstrap Install"
5895 - (void) progressViewIsComplete:(ProgressView *)progress {
5896 @synchronized (self) {
5899 if (confirm_ != nil) {
5900 [underlay_ addSubview:overlay_];
5901 [confirm_ removeFromSuperview];
5908 - (void) setPage:(RVPage *)page {
5909 [page resetViewAnimated:NO];
5910 [page setDelegate:self];
5911 [book_ setPage:page];
5914 - (RVPage *) _pageForURL:(NSURL *)url withClass:(Class)_class {
5915 BrowserView *browser = [[[_class alloc] initWithBook:book_ database:database_] autorelease];
5916 [browser loadURL:url];
5920 - (void) _setHomePage {
5921 [self setPage:[self _pageForURL:[NSURL URLWithString:@"http://cydia.saurik.com/"] withClass:[HomeView class]]];
5924 - (void) buttonBarItemTapped:(id)sender {
5925 unsigned tag = [sender tag];
5927 [book_ resetViewAnimated:YES];
5929 } else if (tag_ == 2 && tag != 2)
5930 [install_ resetView];
5933 case 1: [self _setHomePage]; break;
5935 case 2: [self setPage:install_]; break;
5936 case 3: [self setPage:changes_]; break;
5937 case 4: [self setPage:manage_]; break;
5938 case 5: [self setPage:search_]; break;
5940 default: _assert(false);
5946 - (void) applicationWillSuspend {
5948 [super applicationWillSuspend];
5951 - (void) askForSettings {
5952 UIActionSheet *role = [[[UIActionSheet alloc]
5953 initWithTitle:@"Who Are You?"
5954 buttons:[NSArray arrayWithObjects:
5955 @"User (Graphical Only)",
5956 @"Hacker (+ Command Line)",
5957 @"Developer (No Filters)",
5959 defaultButtonIndex:-1
5964 [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."];
5965 [role popupAlertAnimated:YES];
5970 [self setStatusBarShowsProgress:NO];
5973 [hud_ removeFromSuperview];
5977 pid_t pid = ExecFork();
5979 execlp("launchctl", "launchctl", "stop", "com.apple.SpringBoard", NULL);
5980 perror("launchctl stop");
5987 [self askForSettings];
5991 overlay_ = [[UIView alloc] initWithFrame:[underlay_ bounds]];
5993 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
5994 book_ = [[CYBook alloc] initWithFrame:CGRectMake(
5995 0, 0, screenrect.size.width, screenrect.size.height - 48
5996 ) database:database_];
5998 [book_ setDelegate:self];
6000 [overlay_ addSubview:book_];
6002 NSArray *buttonitems = [NSArray arrayWithObjects:
6003 [NSDictionary dictionaryWithObjectsAndKeys:
6004 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
6005 @"home-up.png", kUIButtonBarButtonInfo,
6006 @"home-dn.png", kUIButtonBarButtonSelectedInfo,
6007 [NSNumber numberWithInt:1], kUIButtonBarButtonTag,
6008 self, kUIButtonBarButtonTarget,
6009 @"Home", kUIButtonBarButtonTitle,
6010 @"0", kUIButtonBarButtonType,
6013 [NSDictionary dictionaryWithObjectsAndKeys:
6014 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
6015 @"install-up.png", kUIButtonBarButtonInfo,
6016 @"install-dn.png", kUIButtonBarButtonSelectedInfo,
6017 [NSNumber numberWithInt:2], kUIButtonBarButtonTag,
6018 self, kUIButtonBarButtonTarget,
6019 @"Sections", kUIButtonBarButtonTitle,
6020 @"0", kUIButtonBarButtonType,
6023 [NSDictionary dictionaryWithObjectsAndKeys:
6024 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
6025 @"changes-up.png", kUIButtonBarButtonInfo,
6026 @"changes-dn.png", kUIButtonBarButtonSelectedInfo,
6027 [NSNumber numberWithInt:3], kUIButtonBarButtonTag,
6028 self, kUIButtonBarButtonTarget,
6029 @"Changes", kUIButtonBarButtonTitle,
6030 @"0", kUIButtonBarButtonType,
6033 [NSDictionary dictionaryWithObjectsAndKeys:
6034 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
6035 @"manage-up.png", kUIButtonBarButtonInfo,
6036 @"manage-dn.png", kUIButtonBarButtonSelectedInfo,
6037 [NSNumber numberWithInt:4], kUIButtonBarButtonTag,
6038 self, kUIButtonBarButtonTarget,
6039 @"Manage", kUIButtonBarButtonTitle,
6040 @"0", kUIButtonBarButtonType,
6043 [NSDictionary dictionaryWithObjectsAndKeys:
6044 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
6045 @"search-up.png", kUIButtonBarButtonInfo,
6046 @"search-dn.png", kUIButtonBarButtonSelectedInfo,
6047 [NSNumber numberWithInt:5], kUIButtonBarButtonTag,
6048 self, kUIButtonBarButtonTarget,
6049 @"Search", kUIButtonBarButtonTitle,
6050 @"0", kUIButtonBarButtonType,
6054 buttonbar_ = [[UIToolbar alloc]
6056 withFrame:CGRectMake(
6057 0, screenrect.size.height - ButtonBarHeight_,
6058 screenrect.size.width, ButtonBarHeight_
6060 withItemList:buttonitems
6063 [buttonbar_ setDelegate:self];
6064 [buttonbar_ setBarStyle:1];
6065 [buttonbar_ setButtonBarTrackingMode:2];
6067 int buttons[5] = {1, 2, 3, 4, 5};
6068 [buttonbar_ registerButtonGroup:0 withButtons:buttons withCount:5];
6069 [buttonbar_ showButtonGroup:0 withDuration:0];
6071 for (int i = 0; i != 5; ++i)
6072 [[buttonbar_ viewWithTag:(i + 1)] setFrame:CGRectMake(
6073 i * 64 + 2, 1, 60, ButtonBarHeight_
6076 [buttonbar_ showSelectionForButton:1];
6077 [overlay_ addSubview:buttonbar_];
6079 [UIKeyboard initImplementationNow];
6080 CGSize keysize = [UIKeyboard defaultSize];
6081 CGRect keyrect = {{0, [overlay_ bounds].size.height}, keysize};
6082 keyboard_ = [[UIKeyboard alloc] initWithFrame:keyrect];
6083 [[UIKeyboardImpl sharedInstance] setSoundsEnabled:(Sounds_Keyboard_ ? YES : NO)];
6084 [overlay_ addSubview:keyboard_];
6086 install_ = [[InstallView alloc] initWithBook:book_ database:database_];
6087 changes_ = [[ChangesView alloc] initWithBook:book_ database:database_];
6088 search_ = [[SearchView alloc] initWithBook:book_ database:database_];
6090 manage_ = (ManageView *) [[self
6091 _pageForURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"manage" ofType:@"html"]]
6092 withClass:[ManageView class]
6096 [underlay_ addSubview:overlay_];
6103 [self _setHomePage];
6106 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
6107 NSString *context = [sheet context];
6108 if ([context isEqualToString:@"fixhalf"])
6111 @synchronized (self) {
6112 for (int i = 0, e = [broken_ count]; i != e; ++i) {
6113 Package *broken = [broken_ objectAtIndex:i];
6116 NSString *id = [broken id];
6117 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.prerm", id] UTF8String]);
6118 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.postrm", id] UTF8String]);
6119 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.preinst", id] UTF8String]);
6120 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.postinst", id] UTF8String]);
6129 [broken_ removeAllObjects];
6136 else if ([context isEqualToString:@"role"]) {
6138 case 1: Role_ = @"User"; break;
6139 case 2: Role_ = @"Hacker"; break;
6140 case 3: Role_ = @"Developer"; break;
6147 bool reset = Settings_ != nil;
6149 Settings_ = [NSMutableDictionary dictionaryWithObjectsAndKeys:
6153 [Metadata_ setObject:Settings_ forKey:@"Settings"];
6161 } else if ([context isEqualToString:@"upgrade"])
6164 @synchronized (self) {
6165 for (int i = 0, e = [essential_ count]; i != e; ++i) {
6166 Package *essential = [essential_ objectAtIndex:i];
6167 [essential install];
6186 - (void) reorganize {
6187 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
6188 system("/usr/libexec/cydia/free.sh");
6189 [self performSelectorOnMainThread:@selector(finish) withObject:nil waitUntilDone:NO];
6193 - (void) applicationSuspend:(__GSEvent *)event {
6194 if (hud_ == nil && ![progress_ isRunning])
6195 [super applicationSuspend:event];
6198 - (void) _animateSuspension:(BOOL)arg0 duration:(double)arg1 startTime:(double)arg2 scale:(float)arg3 {
6200 [super _animateSuspension:arg0 duration:arg1 startTime:arg2 scale:arg3];
6203 - (void) _setSuspended:(BOOL)value {
6205 [super _setSuspended:value];
6208 - (UIProgressHUD *) addProgressHUD {
6209 UIProgressHUD *hud = [[UIProgressHUD alloc] initWithWindow:window_];
6211 [underlay_ addSubview:hud];
6215 - (void) applicationDidFinishLaunching:(id)unused {
6216 Font12_ = [[UIFont systemFontOfSize:12] retain];
6217 Font12Bold_ = [[UIFont boldSystemFontOfSize:12] retain];
6218 Font14_ = [[UIFont systemFontOfSize:14] retain];
6219 Font18Bold_ = [[UIFont boldSystemFontOfSize:18] retain];
6220 Font22Bold_ = [[UIFont boldSystemFontOfSize:22] retain];
6222 _assert(pkgInitConfig(*_config));
6223 _assert(pkgInitSystem(*_config, _system));
6228 essential_ = [[NSMutableArray alloc] initWithCapacity:4];
6229 broken_ = [[NSMutableArray alloc] initWithCapacity:4];
6231 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
6232 window_ = [[UIWindow alloc] initWithContentRect:screenrect];
6234 [window_ orderFront:self];
6235 [window_ makeKey:self];
6236 [window_ _setHidden:NO];
6238 database_ = [[Database alloc] init];
6239 progress_ = [[ProgressView alloc] initWithFrame:[window_ bounds] database:database_ delegate:self];
6240 [database_ setDelegate:progress_];
6241 [window_ setContentView:progress_];
6243 underlay_ = [[UIView alloc] initWithFrame:[progress_ bounds]];
6244 [progress_ setContentView:underlay_];
6246 [progress_ resetView];
6249 readlink("/Applications", NULL, 0) == -1 && errno == EINVAL ||
6250 readlink("/Library/Ringtones", NULL, 0) == -1 && errno == EINVAL ||
6251 readlink("/Library/Wallpaper", NULL, 0) == -1 && errno == EINVAL ||
6252 readlink("/usr/include", NULL, 0) == -1 && errno == EINVAL ||
6253 readlink("/usr/libexec", NULL, 0) == -1 && errno == EINVAL ||
6254 readlink("/usr/share", NULL, 0) == -1 && errno == EINVAL /*||
6255 readlink("/var/lib", NULL, 0) == -1 && errno == EINVAL*/
6257 [self setIdleTimerDisabled:YES];
6259 hud_ = [self addProgressHUD];
6260 [hud_ setText:@"Reorganizing\n\nWill Automatically\nRestart When Done"];
6262 [self setStatusBarShowsProgress:YES];
6265 detachNewThreadSelector:@selector(reorganize)
6273 - (void) showKeyboard:(BOOL)show {
6274 CGSize keysize = [UIKeyboard defaultSize];
6275 CGRect keydown = {{0, [overlay_ bounds].size.height}, keysize};
6276 CGRect keyup = keydown;
6277 keyup.origin.y -= keysize.height;
6279 UIFrameAnimation *animation = [[[UIFrameAnimation alloc] initWithTarget:keyboard_] autorelease];
6280 [animation setSignificantRectFields:2];
6283 [animation setStartFrame:keydown];
6284 [animation setEndFrame:keyup];
6285 [keyboard_ activate];
6287 [animation setStartFrame:keyup];
6288 [animation setEndFrame:keydown];
6289 [keyboard_ deactivate];
6292 [[UIAnimator sharedAnimator]
6293 addAnimations:[NSArray arrayWithObjects:animation, nil]
6294 withDuration:KeyboardTime_
6299 - (void) slideUp:(UIActionSheet *)alert {
6301 [alert presentSheetFromButtonBar:buttonbar_];
6303 [alert presentSheetInView:overlay_];
6308 void AddPreferences(NSString *plist) {
6309 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
6311 NSMutableDictionary *settings = [[[NSMutableDictionary alloc] initWithContentsOfFile:plist] autorelease];
6312 _assert(settings != NULL);
6313 NSMutableArray *items = [settings objectForKey:@"items"];
6317 for (size_t i(0); i != [items count]; ++i) {
6318 NSMutableDictionary *item([items objectAtIndex:i]);
6319 NSString *label = [item objectForKey:@"label"];
6320 if (label != nil && [label isEqualToString:@"Cydia"]) {
6327 for (size_t i(0); i != [items count]; ++i) {
6328 NSDictionary *item([items objectAtIndex:i]);
6329 NSString *label = [item objectForKey:@"label"];
6330 if (label != nil && [label isEqualToString:@"General"]) {
6331 [items insertObject:[NSDictionary dictionaryWithObjectsAndKeys:
6332 @"CydiaSettings", @"bundle",
6333 @"PSLinkCell", @"cell",
6334 [NSNumber numberWithBool:YES], @"hasIcon",
6335 [NSNumber numberWithBool:YES], @"isController",
6337 nil] atIndex:(i + 1)];
6343 _assert([settings writeToFile:plist atomically:YES] == YES);
6350 id Alloc_(id self, SEL selector) {
6351 id object = alloc_(self, selector);
6352 fprintf(stderr, "[%s]A-%p\n", self->isa->name, object);
6357 id Dealloc_(id self, SEL selector) {
6358 id object = dealloc_(self, selector);
6359 fprintf(stderr, "[%s]D-%p\n", self->isa->name, object);
6363 int main(int argc, char *argv[]) {
6364 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
6366 bootstrap_ = argc > 1 && strcmp(argv[1], "--bootstrap") == 0;
6368 App_ = [[NSBundle mainBundle] bundlePath];
6369 Home_ = NSHomeDirectory();
6370 Locale_ = CFLocaleCopyCurrent();
6373 NSString *plist = [Home_ stringByAppendingString:@"/Library/Preferences/com.apple.preferences.sounds.plist"];
6374 if (NSDictionary *sounds = [NSDictionary dictionaryWithContentsOfFile:plist])
6375 if (NSNumber *keyboard = [sounds objectForKey:@"keyboard"])
6376 Sounds_Keyboard_ = [keyboard boolValue];
6382 if (unlink("/var/cache/apt/pkgcache.bin") == -1)
6383 _assert(errno == ENOENT);
6384 if (unlink("/var/cache/apt/srcpkgcache.bin") == -1)
6385 _assert(errno == ENOENT);
6387 /*Method alloc = class_getClassMethod([NSObject class], @selector(alloc));
6388 alloc_ = alloc->method_imp;
6389 alloc->method_imp = (IMP) &Alloc_;*/
6391 /*Method dealloc = class_getClassMethod([NSObject class], @selector(dealloc));
6392 dealloc_ = dealloc->method_imp;
6393 dealloc->method_imp = (IMP) &Dealloc_;*/
6395 if (NSDictionary *sysver = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]) {
6396 if (NSString *prover = [sysver valueForKey:@"ProductVersion"]) {
6397 Firmware_ = strdup([prover UTF8String]);
6398 NSArray *versions = [prover componentsSeparatedByString:@"."];
6399 int count = [versions count];
6400 Major_ = count > 0 ? [[versions objectAtIndex:0] intValue] : 0;
6401 Minor_ = count > 1 ? [[versions objectAtIndex:1] intValue] : 0;
6402 BugFix_ = count > 2 ? [[versions objectAtIndex:2] intValue] : 0;
6407 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
6408 char *machine = new char[size];
6409 sysctlbyname("hw.machine", machine, &size, NULL, 0);
6412 UniqueID_ = [[UIDevice currentDevice] uniqueIdentifier];
6414 /*AddPreferences(@"/Applications/Preferences.app/Settings-iPhone.plist");
6415 AddPreferences(@"/Applications/Preferences.app/Settings-iPod.plist");*/
6417 if ((Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"]) == NULL)
6418 Metadata_ = [[NSMutableDictionary alloc] initWithCapacity:2];
6420 Settings_ = [Metadata_ objectForKey:@"Settings"];
6422 Packages_ = [Metadata_ objectForKey:@"Packages"];
6423 Sections_ = [Metadata_ objectForKey:@"Sections"];
6424 Sources_ = [Metadata_ objectForKey:@"Sources"];
6427 if (Settings_ != nil)
6428 Role_ = [Settings_ objectForKey:@"Role"];
6430 if (Packages_ == nil) {
6431 Packages_ = [[[NSMutableDictionary alloc] initWithCapacity:128] autorelease];
6432 [Metadata_ setObject:Packages_ forKey:@"Packages"];
6435 if (Sections_ == nil) {
6436 Sections_ = [[[NSMutableDictionary alloc] initWithCapacity:32] autorelease];
6437 [Metadata_ setObject:Sections_ forKey:@"Sections"];
6440 if (Sources_ == nil) {
6441 Sources_ = [[[NSMutableDictionary alloc] initWithCapacity:0] autorelease];
6442 [Metadata_ setObject:Sources_ forKey:@"Sources"];
6445 Documents_ = [[[NSMutableArray alloc] initWithCapacity:4] autorelease];
6447 if (access("/Library/MobileSubstrate/MobileSubstrate.dylib", F_OK) == 0)
6448 dlopen("/Library/MobileSubstrate/MobileSubstrate.dylib", RTLD_LAZY | RTLD_GLOBAL);
6450 if (access("/User", F_OK) != 0)
6451 system("/usr/libexec/cydia/firmware.sh");
6453 _assert([[NSFileManager defaultManager]
6454 createDirectoryAtPath:@"/var/cache/apt/archives/partial"
6455 withIntermediateDirectories:YES
6460 space_ = CGColorSpaceCreateDeviceRGB();
6462 Blue_.Set(space_, 0.2, 0.2, 1.0, 1.0);
6463 Blueish_.Set(space_, 0x19/255.f, 0x32/255.f, 0x50/255.f, 1.0);
6464 Black_.Set(space_, 0.0, 0.0, 0.0, 1.0);
6465 Off_.Set(space_, 0.9, 0.9, 0.9, 1.0);
6466 Red_.Set(space_, 1.0, 0.0, 0.0, 1.0);
6467 White_.Set(space_, 1.0, 1.0, 1.0, 1.0);
6468 Gray_.Set(space_, 0.4, 0.4, 0.4, 1.0);
6470 Finishes_ = [NSArray arrayWithObjects:@"return", @"reopen", @"restart", @"reload", @"reboot", nil];
6472 SectionMap_ = [[[NSDictionary alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Sections" ofType:@"plist"]] autorelease];
6474 UIApplicationUseLegacyEvents(YES);
6475 UIKeyboardDisableAutomaticAppearance();
6477 int value = UIApplicationMain(argc, argv, @"Cydia", @"Cydia");
6479 CGColorSpaceRelease(space_);