1 /* #include Directives {{{ */
2 #include <Foundation/NSURL.h>
3 #include <UIKit/UIKit.h>
4 #import <GraphicsServices/GraphicsServices.h>
7 #include <ext/stdio_filebuf.h>
9 #include <apt-pkg/acquire.h>
10 #include <apt-pkg/acquire-item.h>
11 #include <apt-pkg/algorithms.h>
12 #include <apt-pkg/cachefile.h>
13 #include <apt-pkg/configuration.h>
14 #include <apt-pkg/debmetaindex.h>
15 #include <apt-pkg/error.h>
16 #include <apt-pkg/init.h>
17 #include <apt-pkg/pkgrecords.h>
18 #include <apt-pkg/sourcelist.h>
19 #include <apt-pkg/sptr.h>
21 #include <sys/sysctl.h>
25 #include <mach-o/nlist.h>
28 #include <objc/objc-class.h>
34 /* Extension Keywords {{{ */
35 #define _trace() fprintf(stderr, "_trace()@%s:%u[%s]\n", __FILE__, __LINE__, __FUNCTION__)
37 #define _assert(test) do \
39 fprintf(stderr, "_assert(%d:%s)@%s:%u[%s]\n", errno, #test, __FILE__, __LINE__, __FUNCTION__); \
44 /* Miscellaneous Messages {{{ */
46 - (void) setApplicationNameForUserAgent:(NSString *)applicationName;
47 - (id) frameLoadDelegate;
48 - (void) setFrameLoadDelegate:(id)delegate;
51 @interface NSString (Cydia)
52 - (NSString *) stringByAddingPercentEscapes;
53 - (NSString *) stringByReplacingCharacter:(unsigned short)arg0 withCharacter:(unsigned short)arg1;
57 /* Reset View (UIView) {{{ */
58 @interface UIView (CYResetView)
59 - (void) resetViewAnimated:(BOOL)animated;
62 @implementation UIView (CYResetView)
64 - (void) resetViewAnimated:(BOOL)animated {
65 fprintf(stderr, "%s\n", self->isa->name);
71 /* Reset View (UITable) {{{ */
72 @interface UITable (CYResetView)
73 - (void) resetViewAnimated:(BOOL)animated;
76 @implementation UITable (CYResetView)
78 - (void) resetViewAnimated:(BOOL)animated {
79 [self selectRow:-1 byExtendingSelection:NO withFade:animated];
84 /* Reset View (UISectionList) {{{ */
85 @interface UISectionList (CYResetView)
86 - (void) resetViewAnimated:(BOOL)animated;
89 @implementation UISectionList (CYResetView)
91 - (void) resetViewAnimated:(BOOL)animated {
92 [[self table] resetViewAnimated:animated];
98 /* Perl-Compatible RegEx {{{ */
108 Pcre(const char *regex) :
113 code_ = pcre_compile(regex, 0, &error, &offset, NULL);
116 fprintf(stderr, "%d:%s\n", offset, error);
120 pcre_fullinfo(code_, study_, PCRE_INFO_CAPTURECOUNT, &capture_);
121 matches_ = new int[(capture_ + 1) * 3];
129 NSString *operator [](size_t match) {
131 stringWithCString:(data_ + matches_[match * 2])
132 length:(matches_[match * 2 + 1] - matches_[match * 2])
136 bool operator ()(const char *data, size_t size) {
138 return pcre_exec(code_, study_, data, size, 0, 0, matches_, (capture_ + 1) * 3) >= 0;
142 /* CoreGraphicsServices Primitives {{{ */
148 CGColor(CGColorSpaceRef space, float red, float green, float blue, float alpha) {
149 float color[] = {red, green, blue, alpha};
150 color_ = CGColorCreate(space, color);
154 CGColorRelease(color_);
157 operator CGColorRef() {
168 /* XXX: no GSFontRelease()? */
174 static const int PulseInterval_ = 50000;
176 const char *Firmware_ = NULL;
177 const char *Machine_ = NULL;
178 const char *SerialNumber_ = NULL;
184 #define FW_LEAST(major, minor, bugfix) \
185 (major > Major_ || major == Major_ && \
186 (minor > Minor_ || minor == Minor_ && \
189 bool bootstrap_ = false;
191 static NSMutableDictionary *Metadata_;
192 static NSMutableDictionary *Packages_;
195 NSString *GetLastUpdate() {
196 NSDate *update = [Metadata_ objectForKey:@"LastUpdate"];
199 return @"Never or Unknown";
201 CFLocaleRef locale = CFLocaleCopyCurrent();
202 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
203 CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) update);
205 CFRelease(formatter);
208 return [(NSString *) formatted autorelease];
211 @protocol ProgressDelegate
212 - (void) setError:(NSString *)error;
213 - (void) setTitle:(NSString *)title;
214 - (void) setPercent:(float)percent;
215 - (void) addOutput:(NSString *)output;
218 NSString *SizeString(double size) {
220 while (size > 1024) {
225 static const char *powers_[] = {"B", "kB", "MB", "GB"};
227 return [NSString stringWithFormat:@"%.1f%s", size, powers_[power]];
230 static const float TextViewOffset_ = 22;
232 UITextView *GetTextView(NSString *value, float left, bool html) {
233 UITextView *text([[[UITextView alloc] initWithFrame:CGRectMake(left, 3, 310 - left, 1000)] autorelease]);
234 [text setEditable:NO];
235 [text setTextSize:16];
237 [text setHTML:value];
239 [text setText:value];
240 [text setEnabled:NO];
242 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
243 CGColor clear(space, 0, 0, 0, 0);
244 [text setBackgroundColor:clear];
245 CGColorSpaceRelease(space);
247 CGRect frame = [text frame];
248 [text setFrame:frame];
249 CGRect rect = [text visibleTextRect];
250 frame.size.height = rect.size.height;
251 [text setFrame:frame];
256 /* Status Delegation {{{ */
258 public pkgAcquireStatus
269 void setDelegate(id delegate) {
270 delegate_ = delegate;
273 virtual bool MediaChange(std::string media, std::string drive) {
277 virtual void IMSHit(pkgAcquire::ItemDesc &item) {
280 virtual void Fetch(pkgAcquire::ItemDesc &item) {
281 [delegate_ setTitle:[NSString stringWithCString:("Downloading " + item.ShortDesc).c_str()]];
284 virtual void Done(pkgAcquire::ItemDesc &item) {
287 virtual void Fail(pkgAcquire::ItemDesc &item) {
289 item.Owner->Status == pkgAcquire::Item::StatIdle ||
290 item.Owner->Status == pkgAcquire::Item::StatDone
294 [delegate_ setError:[NSString stringWithCString:item.Owner->ErrorText.c_str()]];
297 virtual bool Pulse(pkgAcquire *Owner) {
298 bool value = pkgAcquireStatus::Pulse(Owner);
301 double(CurrentBytes + CurrentItems) /
302 double(TotalBytes + TotalItems)
305 [delegate_ setPercent:percent];
309 virtual void Start() {
312 virtual void Stop() {
316 /* Progress Delegation {{{ */
324 virtual void Update() {
325 [delegate_ setTitle:[NSString stringWithCString:Op.c_str()]];
326 [delegate_ setPercent:(Percent / 100)];
335 void setDelegate(id delegate) {
336 delegate_ = delegate;
339 virtual void Done() {
340 [delegate_ setPercent:1];
345 /* External Constants {{{ */
346 extern NSString *kUIButtonBarButtonAction;
347 extern NSString *kUIButtonBarButtonInfo;
348 extern NSString *kUIButtonBarButtonInfoOffset;
349 extern NSString *kUIButtonBarButtonSelectedInfo;
350 extern NSString *kUIButtonBarButtonStyle;
351 extern NSString *kUIButtonBarButtonTag;
352 extern NSString *kUIButtonBarButtonTarget;
353 extern NSString *kUIButtonBarButtonTitle;
354 extern NSString *kUIButtonBarButtonTitleVerticalHeight;
355 extern NSString *kUIButtonBarButtonTitleWidth;
356 extern NSString *kUIButtonBarButtonType;
358 /* Mime Addresses {{{ */
359 Pcre email_r("^\"?(.*)\"? <([^>]*)>$");
361 @interface Address : NSObject {
369 - (NSString *) email;
371 + (Address *) addressWithString:(NSString *)string;
372 - (Address *) initWithString:(NSString *)string;
375 @implementation Address
384 - (NSString *) name {
388 - (NSString *) email {
392 + (Address *) addressWithString:(NSString *)string {
393 return [[[Address alloc] initWithString:string] autorelease];
396 - (Address *) initWithString:(NSString *)string {
397 if ((self = [super init]) != nil) {
398 const char *data = [string UTF8String];
399 size_t size = [string length];
401 if (email_r(data, size)) {
402 name_ = [email_r[1] retain];
403 email_ = [email_r[2] retain];
405 name_ = [[NSString stringWithCString:data length:size] retain];
414 /* Right Alignment {{{ */
415 @interface UIRightTextLabel : UITextLabel {
416 float _savedRightEdgeX;
417 BOOL _sizedtofit_flag;
420 - (void) setFrame:(CGRect)frame;
421 - (void) setText:(NSString *)text;
422 - (void) realignText;
425 @implementation UIRightTextLabel
427 - (void) setFrame:(CGRect)frame {
428 [super setFrame:frame];
429 if (_sizedtofit_flag == NO) {
430 _savedRightEdgeX = frame.origin.x;
435 - (void) setText:(NSString *)text {
436 [super setText:text];
440 - (void) realignText {
441 CGRect oldFrame = [self frame];
443 _sizedtofit_flag = YES;
444 [self sizeToFit]; // shrink down size so I can right align it
446 CGRect newFrame = [self frame];
448 oldFrame.origin.x = _savedRightEdgeX - newFrame.size.width;
449 oldFrame.size.width = newFrame.size.width;
450 [super setFrame:oldFrame];
451 _sizedtofit_flag = NO;
456 /* Linear Algebra {{{ */
457 inline float interpolate(float begin, float end, float fraction) {
458 return (end - begin) * fraction + begin;
464 /* Database Interface {{{ */
465 @interface Database : NSObject {
467 pkgRecords *records_;
468 pkgProblemResolver *resolver_;
469 pkgAcquire *fetcher_;
471 SPtr<pkgPackageManager> manager_;
481 - (void) _readStatus:(NSNumber *)fd;
482 - (void) _readOutput:(NSNumber *)fd;
484 - (Package *) packageWithName:(NSString *)name;
487 - (pkgCacheFile &) cache;
488 - (pkgRecords *) records;
489 - (pkgProblemResolver *) resolver;
490 - (pkgAcquire &) fetcher;
498 - (void) setDelegate:(id)delegate;
503 @interface ResetView : UIView {
504 UIPushButton *configure_;
505 UIPushButton *reload_;
506 NSMutableArray *views_;
507 UINavigationBar *navbar_;
508 UITransitionView *transition_;
515 - (void) navigationBar:(UINavigationBar *)navbar poppedItem:(UINavigationItem *)item;
516 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
518 - (id) initWithFrame:(CGRect)frame;
519 - (void) setDelegate:(id)delegate;
521 - (void) configurePushed;
522 - (void) reloadPushed;
524 - (void) pushView:(UIView *)view withTitle:(NSString *)title backButtonTitle:(NSString *)back rightButton:(NSString *)right;
525 - (void) popViews:(unsigned)views;
526 - (void) resetView:(BOOL)clear;
531 @implementation ResetView
534 [configure_ release];
536 [transition_ release];
542 - (void) navigationBar:(UINavigationBar *)navbar poppedItem:(UINavigationItem *)item {
543 [views_ removeLastObject];
544 UIView *view([views_ lastObject]);
545 [view resetViewAnimated:!resetting_];
548 [transition_ transition:2 toView:view];
553 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
557 - (id) initWithFrame:(CGRect)frame {
558 if ((self = [super initWithFrame:frame]) != nil) {
559 views_ = [[NSMutableArray arrayWithCapacity:4] retain];
561 struct CGRect bounds = [self bounds];
562 CGSize navsize = [UINavigationBar defaultSizeWithPrompt];
563 CGRect navrect = {{0, 0}, navsize};
565 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
566 [self addSubview:navbar_];
568 [navbar_ setBarStyle:1];
569 [navbar_ setDelegate:self];
571 transition_ = [[UITransitionView alloc] initWithFrame:CGRectMake(
572 bounds.origin.x, bounds.origin.y + navsize.height, bounds.size.width, bounds.size.height - navsize.height
575 //configure_ = [[UIPushButton alloc] initWithFrame:CGRectMake(15, 9, 17, 18)];
576 configure_ = [[UIPushButton alloc] initWithFrame:CGRectMake(10, 9, 17, 18)];
577 [configure_ setShowPressFeedback:YES];
578 [configure_ setImage:[UIImage applicationImageNamed:@"configure.png"]];
579 [configure_ addTarget:self action:@selector(configurePushed) forEvents:1];
581 //reload_ = [[UIPushButton alloc] initWithFrame:CGRectMake(288, 5, 18, 22)];
582 reload_ = [[UIPushButton alloc] initWithFrame:CGRectMake(293, 5, 18, 22)];
583 [reload_ setShowPressFeedback:YES];
584 [reload_ setImage:[UIImage applicationImageNamed:@"reload.png"]];
585 [reload_ addTarget:self action:@selector(reloadPushed) forEvents:1];
587 [navbar_ addSubview:configure_];
588 [navbar_ addSubview:reload_];
590 [self addSubview:transition_];
594 - (void) setDelegate:(id)delegate {
595 delegate_ = delegate;
598 - (void) configurePushed {
599 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
600 initWithTitle:@"Sources Unimplemented"
601 buttons:[NSArray arrayWithObjects:@"Okay", nil]
607 [sheet setBodyText:@"This feature will be implemented soon. In the mean time, you may add sources by adding .list files to '/etc/apt/sources.list.d' or modifying '/etc/apt/sources.list'."];
608 [sheet popupAlertAnimated:YES];
611 - (void) reloadPushed {
615 - (void) pushView:(UIView *)view withTitle:(NSString *)title backButtonTitle:(NSString *)back rightButton:(NSString *)right {
616 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:title] autorelease];
617 [navbar_ pushNavigationItem:navitem];
618 [navitem setBackButtonTitle:back];
620 [navbar_ showButtonsWithLeftTitle:nil rightTitle:right];
622 [transition_ transition:([views_ count] == 0 ? 0 : 1) toView:view];
623 [views_ addObject:view];
626 - (void) popViews:(unsigned)views {
628 for (unsigned i(0); i != views; ++i)
629 [navbar_ popNavigationItem];
633 [transition_ transition:2 toView:[views_ lastObject]];
636 - (void) resetView:(BOOL)clear {
639 if ([views_ count] > 1) {
640 [navbar_ disableAnimation];
641 while ([views_ count] != (clear ? 1 : 2))
642 [navbar_ popNavigationItem];
643 [navbar_ enableAnimation];
645 [navbar_ popNavigationItem];
651 [transition_ transition:(clear ? 0 : 2) toView:[views_ lastObject]];
654 - (void) _resetView {
655 [navbar_ showButtonsWithLeftTitle:nil rightTitle:nil];
659 [navbar_ setPrompt:[NSString stringWithFormat:@"Last Updated: %@", GetLastUpdate()]];
664 /* Confirmation View {{{ */
665 void AddTextView(NSMutableDictionary *fields, NSMutableArray *packages, NSString *key) {
666 if ([packages count] == 0)
669 UITextView *text = GetTextView([packages count] == 0 ? @"n/a" : [packages componentsJoinedByString:@", "], 110, false);
670 [fields setObject:text forKey:key];
672 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
673 CGColor blue(space, 0, 0, 0.4, 1);
674 [text setTextColor:blue];
675 CGColorSpaceRelease(space);
678 @protocol ConfirmationViewDelegate
683 @interface ConfirmationView : UIView {
686 UITransitionView *transition_;
688 UINavigationBar *navbar_;
689 UIPreferencesTable *table_;
690 NSMutableDictionary *fields_;
691 UIAlertSheet *essential_;
697 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
698 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
699 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
701 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table;
702 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group;
703 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed;
704 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group;
705 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group;
707 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate;
711 @implementation ConfirmationView
714 [transition_ release];
719 if (essential_ != nil)
720 [essential_ release];
725 [transition_ transition:7 toView:nil];
729 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
730 if (from != nil && to == nil)
731 [self removeFromSuperview];
734 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
737 if (essential_ != nil)
738 [essential_ popupAlertAnimated:YES];
749 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
750 [essential_ dismiss];
754 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
758 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
760 case 0: return @"Statistics";
761 case 1: return @"Modifications";
763 default: _assert(false);
767 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
770 case 1: return [fields_ count];
772 default: _assert(false);
776 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
777 if (group != 1 || row == -1)
780 _assert(size_t(row) < [fields_ count]);
781 return [[[fields_ allValues] objectAtIndex:row] visibleTextRect].size.height + TextViewOffset_;
785 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
786 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
787 [cell setShowSelection:NO];
790 case 0: switch (row) {
792 [cell setTitle:@"Downloading"];
793 [cell setValue:SizeString([database_ fetcher].FetchNeeded())];
797 [cell setTitle:@"Resuming At"];
798 [cell setValue:SizeString([database_ fetcher].PartialPresent())];
802 double size([database_ cache]->UsrSize());
805 [cell setTitle:@"Disk Freeing"];
806 [cell setValue:SizeString(-size)];
808 [cell setTitle:@"Disk Using"];
809 [cell setValue:SizeString(size)];
813 default: _assert(false);
817 _assert(size_t(row) < [fields_ count]);
818 [cell setTitle:[[fields_ allKeys] objectAtIndex:row]];
819 [cell addSubview:[[fields_ allValues] objectAtIndex:row]];
822 default: _assert(false);
828 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate {
829 if ((self = [super initWithFrame:[view bounds]]) != nil) {
830 database_ = database;
831 delegate_ = delegate;
833 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
834 [self addSubview:transition_];
836 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
838 CGSize navsize = [UINavigationBar defaultSize];
839 CGRect navrect = {{0, 0}, navsize};
840 CGRect bounds = [overlay_ bounds];
842 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
843 [navbar_ setBarStyle:1];
844 [navbar_ setDelegate:self];
846 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Confirm"] autorelease];
847 [navbar_ pushNavigationItem:navitem];
848 [navbar_ showButtonsWithLeftTitle:@"Cancel" rightTitle:@"Confirm"];
850 fields_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
852 NSMutableArray *installing = [NSMutableArray arrayWithCapacity:16];
853 NSMutableArray *upgrading = [NSMutableArray arrayWithCapacity:16];
854 NSMutableArray *removing = [NSMutableArray arrayWithCapacity:16];
856 bool essential(false);
858 pkgCacheFile &cache([database_ cache]);
859 for (pkgCache::PkgIterator iterator = cache->PkgBegin(); !iterator.end(); ++iterator) {
860 NSString *name([NSString stringWithCString:iterator.Name()]);
861 if (cache[iterator].NewInstall())
862 [installing addObject:name];
863 else if (cache[iterator].Upgrade())
864 [upgrading addObject:name];
865 else if (cache[iterator].Delete()) {
866 [removing addObject:name];
867 if ((iterator->Flags & pkgCache::Flag::Essential) != 0)
875 essential_ = [[UIAlertSheet alloc]
876 initWithTitle:@"Unable to Comply"
877 buttons:[NSArray arrayWithObjects:@"Okay", nil]
883 [essential_ setBodyText:@"One or more of the packages you are about to remove are marked 'Essential' and cannot be removed by Cydia. Please use apt-get."];
886 AddTextView(fields_, installing, @"Installing");
887 AddTextView(fields_, upgrading, @"Upgrading");
888 AddTextView(fields_, removing, @"Removing");
890 table_ = [[UIPreferencesTable alloc] initWithFrame:CGRectMake(
891 0, navsize.height, bounds.size.width, bounds.size.height - navsize.height
894 [table_ setReusesTableCells:YES];
895 [table_ setDataSource:self];
898 [overlay_ addSubview:navbar_];
899 [overlay_ addSubview:table_];
901 [view addSubview:self];
903 [transition_ setDelegate:self];
905 UIView *blank = [[[UIView alloc] initWithFrame:[transition_ bounds]] autorelease];
906 [transition_ transition:0 toView:blank];
907 [transition_ transition:3 toView:overlay_];
914 /* Package Class {{{ */
915 NSString *Scour(const char *field, const char *begin, const char *end) {
916 size_t i(0), l(strlen(field));
919 const char *name = begin + i;
920 const char *colon = name + l;
921 const char *value = colon + 1;
926 memcmp(name, field, l) == 0
928 while (value != end && value[0] == ' ')
930 const char *line = std::find(value, end, '\n');
931 while (line != value && line[-1] == ' ')
933 return [NSString stringWithCString:value length:(line - value)];
935 begin = std::find(begin, end, '\n');
943 @interface Package : NSObject {
944 pkgCache::PkgIterator iterator_;
946 pkgCache::VerIterator version_;
947 pkgCache::VerFileIterator file_;
950 NSString *installed_;
961 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database version:(pkgCache::VerIterator)version file:(pkgCache::VerFileIterator)file;
962 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
964 - (NSString *) section;
965 - (Address *) maintainer;
967 - (NSString *) description;
968 - (NSString *) index;
972 - (NSString *) latest;
973 - (NSString *) installed;
978 - (NSString *) tagline;
980 - (NSString *) website;
982 - (BOOL) matches:(NSString *)text;
984 - (NSComparisonResult) compareByName:(Package *)package;
985 - (NSComparisonResult) compareBySectionAndName:(Package *)package;
986 - (NSComparisonResult) compareForChanges:(Package *)package;
992 @implementation Package
996 if (installed_ != nil)
997 [installed_ release];
1008 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database version:(pkgCache::VerIterator)version file:(pkgCache::VerFileIterator)file {
1009 if ((self = [super init]) != nil) {
1010 iterator_ = iterator;
1011 database_ = database;
1016 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1018 const char *begin, *end;
1019 parser->GetRec(begin, end);
1021 latest_ = [[NSString stringWithCString:version_.VerStr()] retain];
1022 installed_ = iterator_.CurrentVer().end() ? nil : [[NSString stringWithCString:iterator_.CurrentVer().VerStr()] retain];
1024 id_ = [[[NSString stringWithCString:iterator_.Name()] lowercaseString] retain];
1025 name_ = Scour("Name", begin, end);
1027 name_ = [name_ retain];
1028 tagline_ = [[NSString stringWithCString:parser->ShortDesc().c_str()] retain];
1029 icon_ = Scour("Icon", begin, end);
1031 icon_ = [icon_ retain];
1032 website_ = Scour("Website", begin, end);
1033 if (website_ != nil)
1034 website_ = [website_ retain];
1036 NSMutableDictionary *metadata = [Packages_ objectForKey:id_];
1037 if (metadata == nil) {
1038 metadata = [NSMutableDictionary dictionaryWithObjectsAndKeys:
1042 [Packages_ setObject:metadata forKey:id_];
1047 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
1048 for (pkgCache::VerIterator version = iterator.VersionList(); !version.end(); ++version)
1049 for (pkgCache::VerFileIterator file = version.FileList(); !file.end(); ++file)
1050 return [[[Package alloc]
1051 initWithIterator:iterator
1059 - (NSString *) section {
1060 return [[NSString stringWithCString:iterator_.Section()] stringByReplacingCharacter:'_' withCharacter:' '];
1063 - (Address *) maintainer {
1064 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1065 return [Address addressWithString:[NSString stringWithCString:parser->Maintainer().c_str()]];
1069 return version_->InstalledSize;
1072 - (NSString *) description {
1073 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1074 NSString *description([NSString stringWithCString:parser->LongDesc().c_str()]);
1076 NSArray *lines = [description componentsSeparatedByString:@"\n"];
1077 NSMutableArray *trimmed = [NSMutableArray arrayWithCapacity:([lines count] - 1)];
1078 if ([lines count] < 2)
1081 NSCharacterSet *whitespace = [NSCharacterSet whitespaceCharacterSet];
1082 for (size_t i(1); i != [lines count]; ++i) {
1083 NSString *trim = [[lines objectAtIndex:i] stringByTrimmingCharactersInSet:whitespace];
1084 [trimmed addObject:trim];
1087 return [trimmed componentsJoinedByString:@"\n"];
1090 - (NSString *) index {
1091 NSString *index = [[[self name] substringToIndex:1] uppercaseString];
1092 return [index length] != 0 && isalpha([index characterAtIndex:0]) ? index : @"123";
1096 return [[Packages_ objectForKey:id_] objectForKey:@"FirstSeen"];
1099 - (NSString *) latest {
1103 - (NSString *) installed {
1107 - (BOOL) upgradable {
1108 NSString *installed = [self installed];
1109 return installed != nil && [[self latest] compare:installed] != NSOrderedSame ? YES : NO;
1116 - (NSString *) name {
1117 return name_ == nil ? id_ : name_;
1120 - (NSString *) tagline {
1124 - (NSString *) icon {
1128 - (NSString *) website {
1132 - (BOOL) matches:(NSString *)text {
1138 range = [[self id] rangeOfString:text options:NSCaseInsensitiveSearch];
1139 if (range.location != NSNotFound)
1142 range = [[self name] rangeOfString:text options:NSCaseInsensitiveSearch];
1143 if (range.location != NSNotFound)
1146 range = [[self tagline] rangeOfString:text options:NSCaseInsensitiveSearch];
1147 if (range.location != NSNotFound)
1153 - (NSComparisonResult) compareByName:(Package *)package {
1154 NSString *lhs = [self name];
1155 NSString *rhs = [package name];
1157 if ([lhs length] != 0 && [rhs length] != 0) {
1158 unichar lhc = [lhs characterAtIndex:0];
1159 unichar rhc = [rhs characterAtIndex:0];
1161 if (isalpha(lhc) && !isalpha(rhc))
1162 return NSOrderedAscending;
1163 else if (!isalpha(lhc) && isalpha(rhc))
1164 return NSOrderedDescending;
1167 return [lhs caseInsensitiveCompare:rhs];
1170 - (NSComparisonResult) compareBySectionAndName:(Package *)package {
1171 NSComparisonResult result = [[self section] compare:[package section]];
1172 if (result != NSOrderedSame)
1174 return [self compareByName:package];
1177 - (NSComparisonResult) compareForChanges:(Package *)package {
1178 BOOL lhs = [self upgradable];
1179 BOOL rhs = [package upgradable];
1182 return lhs ? NSOrderedAscending : NSOrderedDescending;
1184 switch ([[self seen] compare:[package seen]]) {
1185 case NSOrderedAscending:
1186 return NSOrderedDescending;
1189 case NSOrderedDescending:
1190 return NSOrderedAscending;
1196 return [self compareByName:package];
1200 pkgProblemResolver *resolver = [database_ resolver];
1201 resolver->Clear(iterator_);
1202 resolver->Protect(iterator_);
1203 [database_ cache]->MarkInstall(iterator_, false);
1207 pkgProblemResolver *resolver = [database_ resolver];
1208 resolver->Clear(iterator_);
1209 resolver->Protect(iterator_);
1210 resolver->Remove(iterator_);
1211 [database_ cache]->MarkDelete(iterator_, true);
1216 /* Section Class {{{ */
1217 @interface Section : NSObject {
1220 NSMutableArray *packages_;
1225 - (Section *) initWithName:(NSString *)name row:(size_t)row;
1226 - (NSString *) name;
1228 - (NSArray *) packages;
1230 - (void) addPackage:(Package *)package;
1233 @implementation Section
1237 [packages_ release];
1241 - (Section *) initWithName:(NSString *)name row:(size_t)row {
1242 if ((self = [super init]) != nil) {
1243 name_ = [name retain];
1245 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
1249 - (NSString *) name {
1257 - (NSArray *) packages {
1262 return [packages_ count];
1265 - (void) addPackage:(Package *)package {
1266 [packages_ addObject:package];
1272 /* Package View {{{ */
1273 @protocol PackageViewDelegate
1274 - (void) performPackage:(Package *)package;
1277 @interface PackageView : UIView {
1278 UIPreferencesTable *table_;
1280 UITextView *description_;
1286 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table;
1287 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group;
1288 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed;
1289 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group;
1290 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group;
1292 - (BOOL) canSelectRow:(int)row;
1293 - (void) tableRowSelected:(NSNotification *)notification;
1295 - (Package *) package;
1297 - (id) initWithFrame:(struct CGRect)frame;
1298 - (void) setPackage:(Package *)package;
1299 - (void) setDelegate:(id)delegate;
1302 @implementation PackageView
1305 if (package_ != nil)
1307 if (description_ != nil)
1308 [description_ release];
1313 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
1317 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
1320 case 1: return @"Details";
1321 case 2: return @"Source";
1323 default: _assert(false);
1327 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
1328 if (group != 0 || row != 1)
1331 return [description_ visibleTextRect].size.height + TextViewOffset_;
1334 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
1336 case 0: return [package_ website] == nil ? 2 : 3;
1340 default: _assert(false);
1344 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
1345 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
1346 [cell setShowSelection:NO];
1349 case 0: switch (row) {
1351 [cell setTitle:[package_ name]];
1352 [cell setValue:[package_ latest]];
1356 [cell addSubview:description_];
1360 [cell setTitle:@"More Information"];
1361 [cell setShowDisclosure:YES];
1362 [cell setShowSelection:YES];
1365 default: _assert(false);
1368 case 1: switch (row) {
1370 [cell setTitle:@"Identifier"];
1371 [cell setValue:[package_ id]];
1375 [cell setTitle:@"Installed Version"];
1376 NSString *installed([package_ installed]);
1377 [cell setValue:(installed == nil ? @"n/a" : installed)];
1381 [cell setTitle:@"Section"];
1382 [cell setValue:[package_ section]];
1386 [cell setTitle:@"Expanded Size"];
1387 [cell setValue:SizeString([package_ size])];
1391 [cell setTitle:@"Maintainer"];
1392 [cell setValue:[[package_ maintainer] name]];
1393 [cell setShowDisclosure:YES];
1394 [cell setShowSelection:YES];
1397 default: _assert(false);
1400 case 2: switch (row) {
1403 default: _assert(false);
1409 - (BOOL) canSelectRow:(int)row {
1413 - (void) tableRowSelected:(NSNotification *)notification {
1414 int row = [table_ selectedRow];
1415 NSString *website = [package_ website];
1417 if (row == (website == nil ? 8 : 9))
1418 [delegate_ openURL:[NSURL URLWithString:[NSString stringWithFormat:@"mailto:%@?subject=%@",
1419 [[package_ maintainer] email],
1420 [[NSString stringWithFormat:@"regarding apt package \"%@\"", [package_ name]] stringByAddingPercentEscapes]
1422 else if (website != nil && row == 3)
1423 [delegate_ openURL:[NSURL URLWithString:website]];
1426 - (Package *) package {
1430 - (id) initWithFrame:(struct CGRect)frame {
1431 if ((self = [super initWithFrame:frame]) != nil) {
1432 table_ = [[UIPreferencesTable alloc] initWithFrame:[self bounds]];
1433 [self addSubview:table_];
1435 [table_ setDataSource:self];
1436 [table_ setDelegate:self];
1440 - (void) setPackage:(Package *)package {
1441 if (package_ != nil) {
1442 [package_ autorelease];
1446 if (description_ != nil) {
1447 [description_ release];
1451 if (package != nil) {
1452 package_ = [package retain];
1454 NSString *description([package description]);
1455 if (description == nil)
1456 description = [package tagline];
1457 description_ = [GetTextView(description, 12, true) retain];
1459 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1460 CGColor black(space, 0, 0, 0, 1);
1461 [description_ setTextColor:black];
1462 CGColorSpaceRelease(space);
1464 [table_ reloadData];
1468 - (void) setDelegate:(id)delegate {
1469 delegate_ = delegate;
1474 /* Package Cell {{{ */
1475 @interface PackageCell : UITableCell {
1477 UITextLabel *version_;
1478 UITextLabel *description_;
1484 - (PackageCell *) initWithVersioner:(SEL)versioner;
1485 - (void) setPackage:(Package *)package;
1487 - (void) _setSelected:(float)fraction;
1488 - (void) setSelected:(BOOL)selected;
1489 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
1490 - (void) _setSelectionFadeFraction:(float)fraction;
1494 @implementation PackageCell
1499 [description_ release];
1503 - (PackageCell *) initWithVersioner:(SEL)versioner {
1504 if ((self = [super init]) != nil) {
1505 versioner_ = versioner;
1507 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22);
1508 GSFontRef large = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
1509 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 14);
1511 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1513 CGColor clear(space, 0, 0, 0, 0);
1515 name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(12, 7, 250, 25)];
1516 [name_ setBackgroundColor:clear];
1517 [name_ setFont:bold];
1519 version_ = [[UIRightTextLabel alloc] initWithFrame:CGRectMake(286, 7, 70, 25)];
1520 [version_ setBackgroundColor:clear];
1521 [version_ setFont:large];
1523 description_ = [[UITextLabel alloc] initWithFrame:CGRectMake(13, 35, 280, 20)];
1524 [description_ setBackgroundColor:clear];
1525 [description_ setFont:small];
1527 [self addSubview:name_];
1528 [self addSubview:version_];
1529 [self addSubview:description_];
1531 CGColorSpaceRelease(space);
1539 - (void) setPackage:(Package *)package {
1540 [name_ setText:[package name]];
1541 [version_ setText:[package latest]];
1542 [description_ setText:[package tagline]];
1545 - (void) _setSelected:(float)fraction {
1546 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1548 CGColor black(space,
1549 interpolate(0.0, 1.0, fraction),
1550 interpolate(0.0, 1.0, fraction),
1551 interpolate(0.0, 1.0, fraction),
1555 interpolate(0.2, 1.0, fraction),
1556 interpolate(0.2, 1.0, fraction),
1557 interpolate(1.0, 1.0, fraction),
1561 interpolate(0.4, 1.0, fraction),
1562 interpolate(0.4, 1.0, fraction),
1563 interpolate(0.4, 1.0, fraction),
1566 [name_ setColor:black];
1567 [version_ setColor:blue];
1568 [description_ setColor:gray];
1570 CGColorSpaceRelease(space);
1573 - (void) setSelected:(BOOL)selected {
1574 [self _setSelected:(selected ? 1.0 : 0.0)];
1575 [super setSelected:selected];
1578 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
1580 [self _setSelected:(selected ? 1.0 : 0.0)];
1581 [super setSelected:selected withFade:fade];
1584 - (void) _setSelectionFadeFraction:(float)fraction {
1585 [self _setSelected:fraction];
1586 [super _setSelectionFadeFraction:fraction];
1592 /* Database Implementation {{{ */
1593 @implementation Database
1600 - (void) _readStatus:(NSNumber *)fd {
1601 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1603 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1604 std::istream is(&ib);
1609 pcre *code = pcre_compile("^([^:]*):([^:]*):([^:]*):(.*)$", 0, &error, &offset, NULL);
1611 pcre_extra *study = NULL;
1613 pcre_fullinfo(code, study, PCRE_INFO_CAPTURECOUNT, &capture);
1614 int matches[(capture + 1) * 3];
1616 while (std::getline(is, line)) {
1617 const char *data(line.c_str());
1619 _assert(pcre_exec(code, study, data, line.size(), 0, 0, matches, sizeof(matches) / sizeof(matches[0])) >= 0);
1621 std::istringstream buffer(line.substr(matches[6], matches[7] - matches[6]));
1624 [delegate_ setPercent:(percent / 100)];
1626 NSString *string = [NSString stringWithCString:(data + matches[8]) length:(matches[9] - matches[8])];
1627 std::string type(line.substr(matches[2], matches[3] - matches[2]));
1629 if (type == "pmerror")
1630 [delegate_ setError:string];
1631 else if (type == "pmstatus")
1632 [delegate_ setTitle:string];
1633 else if (type == "pmconffile")
1635 else _assert(false);
1642 - (void) _readOutput:(NSNumber *)fd {
1643 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1645 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1646 std::istream is(&ib);
1649 while (std::getline(is, line))
1650 [delegate_ addOutput:[NSString stringWithCString:line.c_str()]];
1656 - (Package *) packageWithName:(NSString *)name {
1657 pkgCache::PkgIterator iterator(cache_->FindPkg([name cString]));
1658 return iterator.end() ? nil : [Package packageWithIterator:iterator database:self];
1661 - (Database *) init {
1662 if ((self = [super init]) != nil) {
1670 _assert(pipe(fds) != -1);
1674 detachNewThreadSelector:@selector(_readStatus:)
1676 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1679 _assert(pipe(fds) != -1);
1680 _assert(dup2(fds[1], 1) != -1);
1681 _assert(close(fds[1]) != -1);
1684 detachNewThreadSelector:@selector(_readOutput:)
1686 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1691 - (pkgCacheFile &) cache {
1695 - (pkgRecords *) records {
1699 - (pkgProblemResolver *) resolver {
1703 - (pkgAcquire &) fetcher {
1707 - (void) reloadData {
1715 _assert(cache_.Open(progress_, true));
1716 records_ = new pkgRecords(cache_);
1717 resolver_ = new pkgProblemResolver(cache_);
1718 fetcher_ = new pkgAcquire(&status_);
1723 pkgRecords records(cache_);
1725 lock_ = new FileFd();
1726 lock_->Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1727 _assert(!_error->PendingError());
1730 _assert(list.ReadMainList());
1732 manager_ = (_system->CreatePM(cache_));
1733 _assert(manager_->GetArchives(fetcher_, &list, &records));
1734 _assert(!_error->PendingError());
1738 if (fetcher_->Run(PulseInterval_) != pkgAcquire::Continue)
1742 pkgPackageManager::OrderResult result = manager_->DoInstall(statusfd_);
1744 if (result == pkgPackageManager::Failed)
1746 if (_error->PendingError())
1748 if (result != pkgPackageManager::Completed)
1754 _assert(list.ReadMainList());
1757 lock.Fd(GetLock(_config->FindDir("Dir::State::Lists") + "lock"));
1758 _assert(!_error->PendingError());
1760 pkgAcquire fetcher(&status_);
1761 _assert(list.GetIndexes(&fetcher));
1762 _assert(fetcher.Run(PulseInterval_) != pkgAcquire::Failed);
1764 bool failed = false;
1765 for (pkgAcquire::ItemIterator item = fetcher.ItemsBegin(); item != fetcher.ItemsEnd(); item++)
1766 if ((*item)->Status != pkgAcquire::Item::StatDone) {
1767 (*item)->Finished();
1771 if (!failed && _config->FindB("APT::Get::List-Cleanup", true) == true) {
1772 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists")));
1773 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/"));
1776 [Metadata_ setObject:[NSDate date] forKey:@"LastUpdate"];
1780 _assert(cache_->DelCount() == 0 && cache_->InstCount() == 0);
1781 _assert(pkgApplyStatus(cache_));
1783 if (cache_->BrokenCount() != 0) {
1784 _assert(pkgFixBroken(cache_));
1785 _assert(cache_->BrokenCount() == 0);
1786 _assert(pkgMinimizeUpgrade(cache_));
1789 _assert(pkgDistUpgrade(cache_));
1792 - (void) setDelegate:(id)delegate {
1793 delegate_ = delegate;
1794 status_.setDelegate(delegate);
1795 progress_.setDelegate(delegate);
1801 /* Progress Data {{{ */
1802 @interface ProgressData : NSObject {
1808 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object;
1815 @implementation ProgressData
1817 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object {
1818 if ((self = [super init]) != nil) {
1819 selector_ = selector;
1839 /* Progress View {{{ */
1840 @interface ProgressView : UIView <
1844 UIView *background_;
1845 UITransitionView *transition_;
1847 UINavigationBar *navbar_;
1848 UIProgressBar *progress_;
1849 UITextView *output_;
1850 UITextLabel *status_;
1856 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
1858 - (ProgressView *) initWithFrame:(struct CGRect)frame delegate:(id)delegate;
1859 - (void) setContentView:(UIView *)view;
1862 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
1864 - (void) _retachThread;
1865 - (void) _detachNewThreadData:(ProgressData *)data;
1866 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title;
1868 - (void) setError:(NSString *)error;
1869 - (void) _setError:(NSString *)error;
1871 - (void) setTitle:(NSString *)title;
1872 - (void) _setTitle:(NSString *)title;
1874 - (void) setPercent:(float)percent;
1875 - (void) _setPercent:(NSNumber *)percent;
1877 - (void) addOutput:(NSString *)output;
1878 - (void) _addOutput:(NSString *)output;
1881 @protocol ProgressViewDelegate
1882 - (void) progressViewIsComplete:(ProgressView *)sender;
1885 @implementation ProgressView
1889 if (background_ != nil)
1890 [background_ release];
1891 [transition_ release];
1894 [progress_ release];
1900 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
1901 if (bootstrap_ && from == overlay_ && to == view_)
1905 - (ProgressView *) initWithFrame:(struct CGRect)frame delegate:(id)delegate {
1906 if ((self = [super initWithFrame:frame]) != nil) {
1907 delegate_ = delegate;
1909 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1911 CGColor black(space, 0.0, 0.0, 0.0, 1.0);
1912 CGColor white(space, 1.0, 1.0, 1.0, 1.0);
1913 CGColor clear(space, 0.0, 0.0, 0.0, 0.0);
1915 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
1916 [transition_ setDelegate:self];
1918 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
1921 [overlay_ setBackgroundColor:black];
1923 background_ = [[UIView alloc] initWithFrame:[self bounds]];
1924 [background_ setBackgroundColor:black];
1925 [self addSubview:background_];
1928 [self addSubview:transition_];
1930 CGSize navsize = [UINavigationBar defaultSize];
1931 CGRect navrect = {{0, 0}, navsize};
1933 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
1934 [overlay_ addSubview:navbar_];
1936 [navbar_ setBarStyle:1];
1937 [navbar_ setDelegate:self];
1939 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:nil] autorelease];
1940 [navbar_ pushNavigationItem:navitem];
1942 CGRect bounds = [overlay_ bounds];
1943 CGSize prgsize = [UIProgressBar defaultSize];
1946 (bounds.size.width - prgsize.width) / 2,
1947 bounds.size.height - prgsize.height - 20
1950 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
1951 [overlay_ addSubview:progress_];
1953 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(
1955 bounds.size.height - prgsize.height - 50,
1956 bounds.size.width - 20,
1960 [status_ setColor:white];
1961 [status_ setBackgroundColor:clear];
1963 [status_ setCentersHorizontally:YES];
1964 //[status_ setFont:font];
1966 output_ = [[UITextView alloc] initWithFrame:CGRectMake(
1968 navrect.size.height + 20,
1969 bounds.size.width - 20,
1970 bounds.size.height - navsize.height - 62 - navrect.size.height
1973 //[output_ setTextFont:@"Courier New"];
1974 [output_ setTextSize:12];
1976 [output_ setTextColor:white];
1977 [output_ setBackgroundColor:clear];
1979 [output_ setMarginTop:0];
1980 [output_ setAllowsRubberBanding:YES];
1982 [overlay_ addSubview:output_];
1983 [overlay_ addSubview:status_];
1985 [progress_ setStyle:0];
1987 CGColorSpaceRelease(space);
1991 - (void) setContentView:(UIView *)view {
1992 view_ = [view retain];
1995 - (void) resetView {
1996 [transition_ transition:6 toView:view_];
1999 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
2003 - (void) _retachThread {
2004 [delegate_ progressViewIsComplete:self];
2008 - (void) _detachNewThreadData:(ProgressData *)data {
2009 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
2011 [[data target] performSelector:[data selector] withObject:[data object]];
2014 [self performSelectorOnMainThread:@selector(_retachThread) withObject:nil waitUntilDone:YES];
2019 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title {
2020 [navbar_ popNavigationItem];
2021 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:title] autorelease];
2022 [navbar_ pushNavigationItem:navitem];
2024 [status_ setText:nil];
2025 [output_ setText:@""];
2026 [progress_ setProgress:0];
2028 [transition_ transition:6 toView:overlay_];
2031 detachNewThreadSelector:@selector(_detachNewThreadData:)
2033 withObject:[[ProgressData alloc]
2034 initWithSelector:selector
2041 - (void) setError:(NSString *)error {
2043 performSelectorOnMainThread:@selector(_setError:)
2049 - (void) _setError:(NSString *)error {
2050 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
2051 initWithTitle:@"Package Error"
2052 buttons:[NSArray arrayWithObjects:@"Okay", nil]
2053 defaultButtonIndex:0
2058 [sheet setBodyText:error];
2059 [sheet popupAlertAnimated:YES];
2062 - (void) setTitle:(NSString *)title {
2064 performSelectorOnMainThread:@selector(_setTitle:)
2070 - (void) _setTitle:(NSString *)title {
2071 [status_ setText:[title stringByAppendingString:@"..."]];
2074 - (void) setPercent:(float)percent {
2076 performSelectorOnMainThread:@selector(_setPercent:)
2077 withObject:[NSNumber numberWithFloat:percent]
2082 - (void) _setPercent:(NSNumber *)percent {
2083 [progress_ setProgress:[percent floatValue]];
2086 - (void) addOutput:(NSString *)output {
2088 performSelectorOnMainThread:@selector(_addOutput:)
2094 - (void) _addOutput:(NSString *)output {
2095 [output_ setText:[NSString stringWithFormat:@"%@\n%@", [output_ text], output]];
2096 CGSize size = [output_ contentSize];
2097 CGRect rect = {{0, size.height}, {size.width, 0}};
2098 [output_ scrollRectToVisible:rect animated:YES];
2104 /* Package Table {{{ */
2105 @protocol PackageTableDelegate
2106 - (void) packageTable:(id)table packageSelected:(Package *)package;
2109 @interface PackageTable : UIView {
2111 UISectionList *list_;
2115 NSMutableArray *sections_;
2120 - (int) numberOfSectionsInSectionList:(UISectionList *)list;
2121 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section;
2122 - (int) sectionList:(UISectionList *)list rowForSection:(int)section;
2124 - (int) numberOfRowsInTable:(UITable *)table;
2125 - (float) table:(UITable *)table heightForRow:(int)row;
2126 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing;
2127 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row;
2128 - (void) tableRowSelected:(NSNotification *)notification;
2130 - (id) initWithFrame:(CGRect)frame versioner:(SEL)versioner;
2132 - (void) setDelegate:(id)delegate;
2133 - (void) setPackages:(NSArray *)packages;
2135 - (void) resetViewAnimated:(BOOL)animated;
2136 - (UITable *) table;
2139 @implementation PackageTable
2143 [sections_ release];
2144 if (packages_ != nil)
2145 [packages_ release];
2149 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
2150 return [sections_ count];
2153 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
2154 return [[sections_ objectAtIndex:section] name];
2157 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
2158 return [[sections_ objectAtIndex:section] row];
2161 - (int) numberOfRowsInTable:(UITable *)table {
2162 return [packages_ count];
2165 - (float) table:(UITable *)table heightForRow:(int)row {
2169 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2171 reusing = [[[PackageCell alloc] initWithVersioner:versioner_] autorelease];
2172 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
2176 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
2180 - (void) tableRowSelected:(NSNotification *)notification {
2181 int row = [[notification object] selectedRow];
2182 [delegate_ packageTable:self packageSelected:(row == INT_MAX ? nil : [packages_ objectAtIndex:row])];
2185 - (id) initWithFrame:(CGRect)frame versioner:(SEL)versioner {
2186 if ((self = [super initWithFrame:frame]) != nil) {
2187 versioner_ = versioner;
2188 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
2190 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:YES];
2191 [list_ setDataSource:self];
2193 UITableColumn *column = [[[UITableColumn alloc]
2194 initWithTitle:@"Name"
2196 width:frame.size.width
2199 UITable *table = [list_ table];
2200 [table setSeparatorStyle:1];
2201 [table addTableColumn:column];
2202 [table setDelegate:self];
2203 [table setReusesTableCells:YES];
2205 [self addSubview:list_];
2209 - (void) setDelegate:(id)delegate {
2210 delegate_ = delegate;
2213 - (void) setPackages:(NSArray *)packages {
2214 if (packages_ != nil)
2215 [packages_ autorelease];
2216 _assert(packages != nil);
2217 packages_ = [packages retain];
2219 [sections_ removeAllObjects];
2221 Section *section = nil;
2223 for (size_t offset(0); offset != [packages_ count]; ++offset) {
2224 Package *package = [packages_ objectAtIndex:offset];
2225 NSString *name = [package index];
2227 if (section == nil || ![[section name] isEqual:name]) {
2228 section = [[[Section alloc] initWithName:name row:offset] autorelease];
2229 [sections_ addObject:section];
2232 [section addPackage:package];
2238 - (void) resetViewAnimated:(BOOL)animated {
2239 [[list_ table] selectRow:-1 byExtendingSelection:NO withFade:animated];
2242 - (UITable *) table {
2243 return [list_ table];
2249 /* Section Cell {{{ */
2250 @interface SectionCell : UITableCell {
2252 UITextLabel *count_;
2258 - (void) setSection:(Section *)section;
2260 - (void) _setSelected:(float)fraction;
2261 - (void) setSelected:(BOOL)selected;
2262 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
2263 - (void) _setSelectionFadeFraction:(float)fraction;
2267 @implementation SectionCell
2276 if ((self = [super init]) != nil) {
2277 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22);
2278 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 12);
2280 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
2281 CGColor clear(space, 0, 0, 0, 0);
2282 CGColor white(space, 1, 1, 1, 1);
2284 name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(47, 9, 250, 25)];
2285 [name_ setBackgroundColor:clear];
2286 [name_ setFont:bold];
2288 count_ = [[UITextLabel alloc] initWithFrame:CGRectMake(11, 7, 29, 32)];
2289 [count_ setCentersHorizontally:YES];
2290 [count_ setBackgroundColor:clear];
2291 [count_ setFont:small];
2292 [count_ setColor:white];
2294 UIImageView *folder = [[[UIImageView alloc] initWithFrame:CGRectMake(8, 7, 32, 32)] autorelease];
2295 [folder setImage:[UIImage applicationImageNamed:@"folder.png"]];
2297 [self addSubview:folder];
2298 [self addSubview:name_];
2299 [self addSubview:count_];
2301 [self _setSelected:0];
2303 CGColorSpaceRelease(space);
2310 - (void) setSection:(Section *)section {
2311 if (section == nil) {
2312 [name_ setText:@"All Packages"];
2313 [count_ setText:nil];
2315 [name_ setText:[section name]];
2316 [count_ setText:[NSString stringWithFormat:@"%d", [section count]]];
2320 - (void) _setSelected:(float)fraction {
2321 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
2323 CGColor black(space,
2324 interpolate(0.0, 1.0, fraction),
2325 interpolate(0.0, 1.0, fraction),
2326 interpolate(0.0, 1.0, fraction),
2329 [name_ setColor:black];
2331 CGColorSpaceRelease(space);
2334 - (void) setSelected:(BOOL)selected {
2335 [self _setSelected:(selected ? 1.0 : 0.0)];
2336 [super setSelected:selected];
2339 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
2341 [self _setSelected:(selected ? 1.0 : 0.0)];
2342 [super setSelected:selected withFade:fade];
2345 - (void) _setSelectionFadeFraction:(float)fraction {
2346 [self _setSelected:fraction];
2347 [super _setSelectionFadeFraction:fraction];
2352 /* Install View {{{ */
2353 @interface InstallView : ResetView <
2354 PackageTableDelegate
2358 PackageTable *table_;
2362 NSMutableArray *packages_;
2367 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
2369 - (int) numberOfRowsInTable:(UITable *)table;
2370 - (float) table:(UITable *)table heightForRow:(int)row;
2371 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing;
2372 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row;
2373 - (void) tableRowSelected:(NSNotification *)notification;
2375 - (void) packageTable:(id)table packageSelected:(Package *)package;
2377 - (id) initWithFrame:(CGRect)frame;
2378 - (void) setPackages:(NSArray *)packages;
2379 - (void) setDelegate:(id)delegate;
2382 @implementation InstallView
2385 [packages_ release];
2386 if (sections_ != nil)
2387 [sections_ release];
2394 if (section_ != nil)
2396 if (package_ != nil)
2401 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2403 [[view_ package] install];
2404 [delegate_ resolve];
2405 [delegate_ perform];
2409 - (int) numberOfRowsInTable:(UITable *)table {
2410 return [sections_ count] + 1;
2413 - (float) table:(UITable *)table heightForRow:(int)row {
2417 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2419 reusing = [[[SectionCell alloc] init] autorelease];
2421 [(SectionCell *)reusing setSection:nil];
2423 [(SectionCell *)reusing setSection:[sections_ objectAtIndex:(row - 1)]];
2427 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
2431 - (void) tableRowSelected:(NSNotification *)notification {
2432 int row = [[notification object] selectedRow];
2434 if (row == INT_MAX) {
2441 _assert(section_ == nil);
2442 _assert(table_ == nil);
2450 name = @"All Packages";
2452 section = [sections_ objectAtIndex:(row - 1)];
2453 name = [section name];
2454 section_ = [name retain];
2457 table_ = [[PackageTable alloc] initWithFrame:[transition_ bounds] versioner:@selector(latest)];
2458 [table_ setDelegate:self];
2459 [table_ setPackages:(section == nil ? packages_ : [section packages])];
2461 [self pushView:table_ withTitle:name backButtonTitle:@"Packages" rightButton:nil];
2465 - (void) packageTable:(id)table packageSelected:(Package *)package {
2466 if (package == nil) {
2473 _assert(package_ == nil);
2474 _assert(view_ == nil);
2476 package_ = [[package name] retain];
2478 view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]];
2479 [view_ setDelegate:delegate_];
2481 [view_ setPackage:package];
2483 [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:@"Install"];
2487 - (id) initWithFrame:(CGRect)frame {
2488 if ((self = [super initWithFrame:frame]) != nil) {
2489 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
2491 list_ = [[UITable alloc] initWithFrame:[transition_ bounds]];
2492 [self pushView:list_ withTitle:@"Install" backButtonTitle:@"Sections" rightButton:nil];
2494 UITableColumn *column = [[[UITableColumn alloc]
2495 initWithTitle:@"Name"
2497 width:frame.size.width
2500 [list_ setDataSource:self];
2501 [list_ setSeparatorStyle:1];
2502 [list_ addTableColumn:column];
2503 [list_ setDelegate:self];
2504 [list_ setReusesTableCells:YES];
2506 [transition_ transition:0 toView:list_];
2510 - (void) setPackages:(NSArray *)packages {
2511 [packages_ removeAllObjects];
2513 for (size_t i(0); i != [packages count]; ++i) {
2514 Package *package([packages objectAtIndex:i]);
2515 if ([package installed] == nil)
2516 [packages_ addObject:package];
2519 [packages_ sortUsingSelector:@selector(compareBySectionAndName:)];
2520 NSMutableArray *sections = [NSMutableArray arrayWithCapacity:16];
2522 Section *nsection = nil;
2523 Package *npackage = nil;
2525 Section *section = nil;
2526 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
2527 Package *package = [packages_ objectAtIndex:offset];
2528 NSString *name = [package section];
2530 if (section == nil || ![[section name] isEqual:name]) {
2531 section = [[[Section alloc] initWithName:name row:offset] autorelease];
2533 if ([name isEqualToString:section_])
2535 [sections addObject:section];
2538 if ([[package name] isEqualToString:package_])
2540 [section addPackage:package];
2543 if (sections_ != nil)
2544 [sections_ release];
2545 sections_ = [sections retain];
2547 [packages_ sortUsingSelector:@selector(compareByName:)];
2553 if (npackage != nil)
2554 [view_ setPackage:npackage];
2555 else if (package_ != nil)
2558 if (table_ != nil && section_ == nil)
2559 [table_ setPackages:packages_];
2560 else if (nsection != nil)
2561 [table_ setPackages:[nsection packages]];
2562 else if (section_ != nil)
2565 [self popViews:views];
2569 - (void) setDelegate:(id)delegate {
2571 [view_ setDelegate:delegate];
2572 [super setDelegate:delegate];
2577 /* Changes View {{{ */
2578 @interface ChangesView : ResetView <
2579 PackageTableDelegate
2581 UISectionList *list_;
2582 NSMutableArray *packages_;
2583 NSMutableArray *sections_;
2591 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
2593 - (int) numberOfSectionsInSectionList:(UISectionList *)list;
2594 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section;
2595 - (int) sectionList:(UISectionList *)list rowForSection:(int)section;
2597 - (int) numberOfRowsInTable:(UITable *)table;
2598 - (float) table:(UITable *)table heightForRow:(int)row;
2599 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing;
2600 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row;
2601 - (void) tableRowSelected:(NSNotification *)notification;
2603 - (id) initWithFrame:(CGRect)frame;
2604 - (void) setPackages:(NSArray *)packages;
2605 - (void) _resetView;
2608 - (void) setDelegate:(id)delegate;
2611 @implementation ChangesView
2615 [packages_ release];
2616 [sections_ release];
2619 if (package_ != nil)
2624 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
2625 return [sections_ count];
2628 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
2629 return [[sections_ objectAtIndex:section] name];
2632 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
2633 return [[sections_ objectAtIndex:section] row];
2636 - (int) numberOfRowsInTable:(UITable *)table {
2637 return [packages_ count];
2640 - (float) table:(UITable *)table heightForRow:(int)row {
2644 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2646 reusing = [[[PackageCell alloc] initWithVersioner:NULL] autorelease];
2647 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
2651 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
2655 - (void) tableRowSelected:(NSNotification *)notification {
2656 int row = [[notification object] selectedRow];
2657 [self packageTable:self packageSelected:(row == INT_MAX ? nil : [packages_ objectAtIndex:row])];
2660 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2663 [[view_ package] install];
2664 [delegate_ resolve];
2665 [delegate_ perform];
2669 [delegate_ upgrade];
2674 - (void) packageTable:(id)table packageSelected:(Package *)package {
2675 if (package == nil) {
2682 _assert(package_ == nil);
2683 _assert(view_ == nil);
2685 package_ = [[package name] retain];
2687 view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]];
2688 [view_ setDelegate:delegate_];
2690 [view_ setPackage:package];
2692 [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:(
2693 [package upgradable] ? @"Upgrade" : @"Install"
2698 - (id) initWithFrame:(CGRect)frame {
2699 if ((self = [super initWithFrame:frame]) != nil) {
2700 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
2701 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
2703 list_ = [[UISectionList alloc] initWithFrame:[transition_ bounds] showSectionIndex:NO];
2704 [list_ setShouldHideHeaderInShortLists:NO];
2705 [list_ setDataSource:self];
2706 //[list_ setSectionListStyle:1];
2708 UITableColumn *column = [[[UITableColumn alloc]
2709 initWithTitle:@"Name"
2711 width:frame.size.width
2714 UITable *table = [list_ table];
2715 [table setSeparatorStyle:1];
2716 [table addTableColumn:column];
2717 [table setDelegate:self];
2718 [table setReusesTableCells:YES];
2720 [self pushView:list_ withTitle:@"Changes" backButtonTitle:nil rightButton:nil];
2724 - (void) setPackages:(NSArray *)packages {
2725 [packages_ removeAllObjects];
2726 for (size_t i(0); i != [packages count]; ++i) {
2727 Package *package([packages objectAtIndex:i]);
2728 if ([package installed] == nil || [package upgradable])
2729 [packages_ addObject:package];
2732 [packages_ sortUsingSelector:@selector(compareForChanges:)];
2734 [sections_ removeAllObjects];
2736 Section *upgradable = [[[Section alloc] initWithName:@"Available Upgrades" row:0] autorelease];
2737 Section *section = nil;
2740 Package *npackage = nil;
2741 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
2742 Package *package = [packages_ objectAtIndex:offset];
2743 if ([[package name] isEqualToString:package_])
2746 if ([package upgradable])
2747 [upgradable addPackage:package];
2749 NSDate *seen = [package seen];
2751 CFLocaleRef locale = CFLocaleCopyCurrent();
2752 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
2753 CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen);
2755 NSString *name = (NSString *) formatted;
2757 if (section == nil || ![[section name] isEqual:name]) {
2758 section = [[[Section alloc] initWithName:name row:offset] autorelease];
2759 [sections_ addObject:section];
2762 [section addPackage:package];
2764 CFRelease(formatter);
2765 CFRelease(formatted);
2770 count_ = [[upgradable packages] count];
2772 [sections_ insertObject:upgradable atIndex:0];
2776 if (npackage != nil)
2777 [view_ setPackage:npackage];
2778 else if (package_ != nil)
2785 - (void) _resetView {
2786 if ([views_ count] == 1)
2787 [navbar_ showButtonsWithLeftTitle:(count_ == 0 ? nil : @"Upgrade All") rightTitle:nil];
2794 - (void) setDelegate:(id)delegate {
2796 [view_ setDelegate:delegate];
2797 [super setDelegate:delegate];
2802 /* Manage View {{{ */
2803 @interface ManageView : ResetView <
2804 PackageTableDelegate
2806 PackageTable *table_;
2813 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
2815 - (void) packageTable:(id)table packageSelected:(Package *)package;
2817 - (id) initWithFrame:(CGRect)frame;
2818 - (void) setPackages:(NSArray *)packages;
2820 - (void) setDelegate:(id)delegate;
2823 @implementation ManageView
2829 if (package_ != nil)
2834 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2836 [[view_ package] remove];
2837 [delegate_ resolve];
2838 [delegate_ perform];
2842 - (void) packageTable:(id)table packageSelected:(Package *)package {
2843 if (package == nil) {
2850 _assert(package_ == nil);
2851 _assert(view_ == nil);
2853 package_ = [[package name] retain];
2855 view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]];
2856 [view_ setDelegate:delegate_];
2858 [view_ setPackage:package];
2860 [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:@"Uninstall"];
2864 - (id) initWithFrame:(CGRect)frame {
2865 if ((self = [super initWithFrame:frame]) != nil) {
2866 table_ = [[PackageTable alloc] initWithFrame:[transition_ bounds] versioner:@selector(latest)];
2867 [table_ setDelegate:self];
2869 [self pushView:table_ withTitle:@"Uninstall" backButtonTitle:@"Packages" rightButton:nil];
2873 - (void) setPackages:(NSArray *)packages {
2874 NSMutableArray *local = [NSMutableArray arrayWithCapacity:16];
2875 for (size_t i(0); i != [packages count]; ++i) {
2876 Package *package([packages objectAtIndex:i]);
2877 if ([package installed] != nil)
2878 [local addObject:package];
2881 [local sortUsingSelector:@selector(compareByName:)];
2883 Package *npackage = nil;
2884 for (size_t offset = 0, count = [local count]; offset != count; ++offset) {
2885 Package *package = [local objectAtIndex:offset];
2886 if ([[package name] isEqualToString:package_])
2890 [table_ setPackages:local];
2892 if (npackage != nil)
2893 [view_ setPackage:npackage];
2894 else if (package_ != nil)
2900 - (void) setDelegate:(id)delegate {
2902 [view_ setDelegate:delegate];
2903 [super setDelegate:delegate];
2908 /* Search View {{{ */
2909 @protocol SearchViewDelegate
2910 - (void) showKeyboard:(BOOL)show;
2913 @interface SearchView : ResetView <
2914 PackageTableDelegate
2916 NSMutableArray *packages_;
2918 UISearchField *field_;
2919 PackageTable *table_;
2926 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
2927 - (void) packageTable:(id)table packageSelected:(Package *)package;
2929 - (void) textFieldDidBecomeFirstResponder:(UITextField *)field;
2930 - (void) textFieldDidResignFirstResponder:(UITextField *)field;
2932 - (void) keyboardInputChanged:(UIFieldEditor *)editor;
2933 - (BOOL) keyboardInput:(id)input shouldInsertText:(NSString *)text isMarkedText:(int)marked;
2935 - (id) initWithFrame:(CGRect)frame;
2936 - (void) setPackages:(NSArray *)packages;
2938 - (void) setDelegate:(id)delegate;
2939 - (void) resetPackage:(Package *)package;
2940 - (void) searchPackages;
2944 @implementation SearchView
2947 [packages_ release];
2948 [accessory_ release];
2953 if (package_ != nil)
2958 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2960 Package *package = [view_ package];
2961 if ([package installed] == nil)
2965 [delegate_ resolve];
2966 [delegate_ perform];
2970 - (void) packageTable:(id)table packageSelected:(Package *)package {
2971 if (package == nil) {
2972 [navbar_ setAccessoryView:accessory_ animate:(resetting_ ? NO : YES) goingBack:YES];
2980 [navbar_ setAccessoryView:nil animate:YES goingBack:NO];
2982 _assert(package_ == nil);
2983 _assert(view_ == nil);
2985 package_ = [[package name] retain];
2987 view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]];
2988 [view_ setDelegate:delegate_];
2990 [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:nil];
2991 [self resetPackage:package];
2995 - (void) textFieldDidBecomeFirstResponder:(UITextField *)field {
2996 [delegate_ showKeyboard:YES];
2997 [table_ setEnabled:NO];
2999 /*CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
3000 CGColor dimmed(alpha, 0, 0, 0, 0.5);
3001 [editor_ setBackgroundColor:dimmed];
3002 CGColorSpaceRelease(space);*/
3005 - (void) textFieldDidResignFirstResponder:(UITextField *)field {
3006 [table_ setEnabled:YES];
3007 [delegate_ showKeyboard:NO];
3010 - (void) keyboardInputChanged:(UIFieldEditor *)editor {
3011 NSString *text([field_ text]);
3012 [field_ setClearButtonStyle:(text == nil || [text length] == 0 ? 0 : 2)];
3015 - (BOOL) keyboardInput:(id)input shouldInsertText:(NSString *)text isMarkedText:(int)marked {
3016 if ([text length] != 1 || [text characterAtIndex:0] != '\n')
3019 [self searchPackages];
3020 [field_ resignFirstResponder];
3024 - (id) initWithFrame:(CGRect)frame {
3025 if ((self = [super initWithFrame:frame]) != nil) {
3026 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
3028 table_ = [[PackageTable alloc] initWithFrame:[transition_ bounds] versioner:@selector(latest)];
3029 [table_ setDelegate:self];
3031 CGRect area = [self bounds];
3034 area.size.width -= 12;
3035 area.size.height = [UISearchField defaultHeight];
3037 field_ = [[UISearchField alloc] initWithFrame:area];
3039 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
3040 [field_ setFont:font];
3043 [field_ setPlaceholder:@"Package Names & Descriptions"];
3044 [field_ setPaddingTop:5];
3045 [field_ setDelegate:self];
3047 UITextTraits *traits = [field_ textTraits];
3048 [traits setEditingDelegate:self];
3049 [traits setReturnKeyType:6];
3051 accessory_ = [[UIView alloc] initWithFrame:CGRectMake(6, 6, area.size.width, area.size.height + 30)];
3052 [accessory_ addSubview:field_];
3054 [navbar_ setAccessoryView:accessory_];
3055 [self pushView:table_ withTitle:nil backButtonTitle:@"Search" rightButton:nil];
3057 /* XXX: for the love of god just fix this */
3058 [navbar_ removeFromSuperview];
3059 [reload_ removeFromSuperview];
3060 [configure_ removeFromSuperview];
3061 [self addSubview:navbar_];
3062 [self addSubview:reload_];
3063 [self addSubview:configure_];
3067 - (void) setPackages:(NSArray *)packages {
3068 [packages_ removeAllObjects];
3069 [packages_ addObjectsFromArray:packages];
3070 [packages_ sortUsingSelector:@selector(compareByName:)];
3072 Package *npackage = nil;
3073 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
3074 Package *package = [packages_ objectAtIndex:offset];
3075 if ([[package name] isEqualToString:package_])
3079 [self searchPackages];
3081 if (npackage != nil)
3082 [self resetPackage:npackage];
3083 else if (package_ != nil)
3089 - (void) setDelegate:(id)delegate {
3091 [view_ setDelegate:delegate];
3092 [super setDelegate:delegate];
3095 - (void) resetPackage:(Package *)package {
3096 [view_ setPackage:package];
3097 NSString *right = [package installed] == nil ? @"Install" : @"Uninstall";
3098 [navbar_ showButtonsWithLeftTitle:nil rightTitle:right];
3101 - (void) searchPackages {
3102 NSString *text([field_ text]);
3104 NSMutableArray *packages([NSMutableArray arrayWithCapacity:16]);
3106 for (size_t offset(0), count([packages_ count]); offset != count; ++offset) {
3107 Package *package = [packages_ objectAtIndex:offset];
3108 if ([package matches:text])
3109 [packages addObject:package];
3112 [table_ setPackages:packages];
3113 [[table_ table] scrollPointVisibleAtTopLeft:CGPointMake(0, 0) animated:NO];
3119 @interface Cydia : UIApplication <
3120 ConfirmationViewDelegate,
3121 ProgressViewDelegate,
3127 UITransitionView *transition_;
3128 UIButtonBar *buttonbar_;
3130 ConfirmationView *confirm_;
3132 Database *database_;
3133 ProgressView *progress_;
3136 UINavigationBar *navbar_;
3137 UIScroller *scroller_;
3138 UIWebView *webview_;
3140 UIProgressIndicator *indicator_;
3142 InstallView *install_;
3143 ChangesView *changes_;
3144 ManageView *manage_;
3145 SearchView *search_;
3150 UIKeyboard *keyboard_;
3154 - (void) reloadData:(BOOL)reset;
3165 - (void) progressViewIsComplete:(ProgressView *)progress;
3167 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
3168 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
3169 - (void) buttonBarItemTapped:(id)sender;
3171 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old;
3173 - (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame;
3175 - (void) applicationWillSuspend;
3176 - (void) applicationDidFinishLaunching:(id)unused;
3179 @implementation Cydia
3182 NSMutableURLRequest *request = [NSMutableURLRequest
3184 cachePolicy:NSURLRequestReloadIgnoringCacheData
3185 timeoutInterval:30.0
3188 [request addValue:[NSString stringWithCString:Firmware_] forHTTPHeaderField:@"X-Firmware"];
3189 [request addValue:[NSString stringWithCString:Machine_] forHTTPHeaderField:@"X-Machine"];
3190 [request addValue:[NSString stringWithCString:SerialNumber_] forHTTPHeaderField:@"X-Serial-Number"];
3192 [webview_ loadRequest:request];
3195 - (void) reloadData:(BOOL)reset {
3196 [database_ reloadData];
3200 if (Packages_ == nil) {
3201 Packages_ = [[NSMutableDictionary alloc] initWithCapacity:count];
3202 [Metadata_ setObject:Packages_ forKey:@"Packages"];
3205 now_ = [NSDate date];
3207 NSMutableArray *packages = [NSMutableArray arrayWithCapacity:count];
3208 for (pkgCache::PkgIterator iterator = [database_ cache]->PkgBegin(); !iterator.end(); ++iterator)
3209 if (Package *package = [Package packageWithIterator:iterator database:database_])
3210 [packages addObject:package];
3212 [install_ setPackages:packages];
3213 [changes_ setPackages:packages];
3214 [manage_ setPackages:packages];
3215 [search_ setPackages:packages];
3217 if (size_t count = [changes_ count]) {
3218 NSString *badge([[NSNumber numberWithInt:count] stringValue]);
3219 [buttonbar_ setBadgeValue:badge forButton:3];
3220 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
3221 [buttonbar_ setBadgeAnimated:YES forButton:3];
3222 [self setApplicationBadge:badge];
3224 [buttonbar_ setBadgeValue:nil forButton:3];
3225 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
3226 [buttonbar_ setBadgeAnimated:NO forButton:3];
3227 [self removeApplicationBadge];
3230 _assert([Metadata_ writeToFile:@"/var/lib/cydia/metadata.plist" atomically:YES] == YES);
3233 - (void) setPrompt {
3234 [navbar_ setPrompt:[NSString stringWithFormat:@"Last Updated: %@", GetLastUpdate()]];
3238 pkgProblemResolver *resolver = [database_ resolver];
3240 resolver->InstallProtect();
3241 if (!resolver->Resolve(true))
3246 [database_ prepare];
3247 confirm_ = [[ConfirmationView alloc] initWithView:underlay_ database:database_ delegate:self];
3251 [database_ upgrade];
3256 [self reloadData:NO];
3262 [overlay_ removeFromSuperview];
3266 detachNewThreadSelector:@selector(perform)
3273 - (void) bootstrap_ {
3275 [database_ upgrade];
3276 [database_ prepare];
3277 [database_ perform];
3280 - (void) bootstrap {
3282 detachNewThreadSelector:@selector(bootstrap_)
3285 title:@"Bootstrap Install..."
3291 detachNewThreadSelector:@selector(update)
3294 title:@"Refreshing Sources..."
3298 - (void) progressViewIsComplete:(ProgressView *)progress {
3299 [self reloadData:YES];
3301 if (confirm_ != nil) {
3302 [underlay_ addSubview:overlay_];
3303 [confirm_ removeFromSuperview];
3309 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
3316 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
3317 initWithTitle:@"About Cydia Packager"
3318 buttons:[NSArray arrayWithObjects:@"Close", nil]
3319 defaultButtonIndex:0
3325 @"Copyright (C) 2008\n"
3326 "Jay Freeman (saurik)\n"
3327 "saurik@saurik.com\n"
3328 "http://www.saurik.com/\n"
3331 "http://www.theokorigroup.com/\n"
3333 "College of Creative Studies,\n"
3334 "University of California,\n"
3336 "http://www.ccs.ucsb.edu/\n"
3339 "bad_, BHSPitMonkey, cash, Cobra,\n"
3340 "core, Corona, crashx, cromas,\n"
3341 "Darken, dtzWill, Erica, francis,\n"
3342 "Godores, jerry, Kingstone, lounger,\n"
3343 "mbranes, rockabilly, tman, Wbiggs"
3346 [sheet presentSheetFromButtonBar:buttonbar_];
3351 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
3355 - (void) buttonBarItemTapped:(id)sender {
3357 unsigned tag = [sender tag];
3360 case 1: view = featured_; break;
3361 case 2: view = install_; break;
3362 case 3: view = changes_; break;
3363 case 4: view = manage_; break;
3364 case 5: view = search_; break;
3370 if ([view respondsToSelector:@selector(resetView:)])
3371 [(id) view resetView:(tag == tag_ ? NO : YES)];
3373 [transition_ transition:0 toView:view];
3376 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old {
3377 [scroller_ setContentSize:frame.size];
3378 [indicator_ stopAnimation];
3381 - (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame {
3382 [navbar_ setPrompt:title];
3385 - (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame {
3386 [navbar_ setPrompt:@"Loading..."];
3387 [indicator_ startAnimation];
3390 - (void) applicationWillSuspend {
3392 system("launchctl stop com.apple.SpringBoard");
3394 [super applicationWillSuspend];
3397 - (void) applicationDidFinishLaunching:(id)unused {
3398 _assert(pkgInitConfig(*_config));
3399 _assert(pkgInitSystem(*_config, _system));
3405 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
3406 window_ = [[UIWindow alloc] initWithContentRect:screenrect];
3408 [window_ orderFront: self];
3409 [window_ makeKey: self];
3410 [window_ _setHidden: NO];
3412 progress_ = [[ProgressView alloc] initWithFrame:[window_ bounds] delegate:self];
3413 [window_ setContentView:progress_];
3415 underlay_ = [[UIView alloc] initWithFrame:[progress_ bounds]];
3416 [progress_ setContentView:underlay_];
3418 overlay_ = [[UIView alloc] initWithFrame:[underlay_ bounds]];
3421 [underlay_ addSubview:overlay_];
3423 transition_ = [[UITransitionView alloc] initWithFrame:CGRectMake(
3424 0, 0, screenrect.size.width, screenrect.size.height - 48
3427 [overlay_ addSubview:transition_];
3429 featured_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
3431 CGSize navsize = [UINavigationBar defaultSizeWithPrompt];
3432 CGRect navrect = {{0, 0}, navsize};
3434 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
3435 [featured_ addSubview:navbar_];
3437 [navbar_ setBarStyle:1];
3438 [navbar_ setDelegate:self];
3440 [navbar_ showButtonsWithLeftTitle:@"About" rightTitle:@"Reload"];
3442 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Featured"] autorelease];
3443 [navbar_ pushNavigationItem:navitem];
3445 struct CGRect subbounds = [featured_ bounds];
3446 subbounds.origin.y += navsize.height;
3447 subbounds.size.height -= navsize.height;
3449 UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:subbounds] autorelease];
3450 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
3451 [featured_ addSubview:pinstripe];
3453 scroller_ = [[UIScroller alloc] initWithFrame:subbounds];
3454 [featured_ addSubview:scroller_];
3456 [scroller_ setScrollingEnabled:YES];
3457 [scroller_ setAdjustForContentSizeChange:YES];
3458 [scroller_ setClipsSubviews:YES];
3459 [scroller_ setAllowsRubberBanding:YES];
3460 [scroller_ setScrollDecelerationFactor:0.99];
3461 [scroller_ setDelegate:self];
3463 CGRect webrect = [scroller_ bounds];
3464 webrect.size.height = 0;
3466 webview_ = [[UIWebView alloc] initWithFrame:webrect];
3467 [scroller_ addSubview:webview_];
3469 [webview_ setTilingEnabled:YES];
3470 [webview_ setTileSize:CGSizeMake(screenrect.size.width, 500)];
3471 [webview_ setAutoresizes:YES];
3472 [webview_ setDelegate:self];
3474 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:2];
3475 indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(87, 45, indsize.width, indsize.height)];
3476 [indicator_ setStyle:2];
3477 [featured_ addSubview:indicator_];
3479 NSArray *buttonitems = [NSArray arrayWithObjects:
3480 [NSDictionary dictionaryWithObjectsAndKeys:
3481 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3482 @"featured-up.png", kUIButtonBarButtonInfo,
3483 @"featured-dn.png", kUIButtonBarButtonSelectedInfo,
3484 [NSNumber numberWithInt:1], kUIButtonBarButtonTag,
3485 self, kUIButtonBarButtonTarget,
3486 @"Featured", kUIButtonBarButtonTitle,
3487 @"0", kUIButtonBarButtonType,
3490 [NSDictionary dictionaryWithObjectsAndKeys:
3491 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3492 @"install-up.png", kUIButtonBarButtonInfo,
3493 @"install-dn.png", kUIButtonBarButtonSelectedInfo,
3494 [NSNumber numberWithInt:2], kUIButtonBarButtonTag,
3495 self, kUIButtonBarButtonTarget,
3496 @"Install", kUIButtonBarButtonTitle,
3497 @"0", kUIButtonBarButtonType,
3500 [NSDictionary dictionaryWithObjectsAndKeys:
3501 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3502 @"changes-up.png", kUIButtonBarButtonInfo,
3503 @"changes-dn.png", kUIButtonBarButtonSelectedInfo,
3504 [NSNumber numberWithInt:3], kUIButtonBarButtonTag,
3505 self, kUIButtonBarButtonTarget,
3506 @"Changes", kUIButtonBarButtonTitle,
3507 @"0", kUIButtonBarButtonType,
3510 [NSDictionary dictionaryWithObjectsAndKeys:
3511 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3512 @"manage-up.png", kUIButtonBarButtonInfo,
3513 @"manage-dn.png", kUIButtonBarButtonSelectedInfo,
3514 [NSNumber numberWithInt:4], kUIButtonBarButtonTag,
3515 self, kUIButtonBarButtonTarget,
3516 @"Uninstall", kUIButtonBarButtonTitle,
3517 @"0", kUIButtonBarButtonType,
3520 [NSDictionary dictionaryWithObjectsAndKeys:
3521 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3522 @"search-up.png", kUIButtonBarButtonInfo,
3523 @"search-dn.png", kUIButtonBarButtonSelectedInfo,
3524 [NSNumber numberWithInt:5], kUIButtonBarButtonTag,
3525 self, kUIButtonBarButtonTarget,
3526 @"Search", kUIButtonBarButtonTitle,
3527 @"0", kUIButtonBarButtonType,
3531 buttonbar_ = [[UIButtonBar alloc]
3533 withFrame:CGRectMake(
3534 0, screenrect.size.height - 48,
3535 screenrect.size.width, 48
3537 withItemList:buttonitems
3540 [buttonbar_ setDelegate:self];
3541 [buttonbar_ setBarStyle:1];
3542 [buttonbar_ setButtonBarTrackingMode:2];
3544 int buttons[5] = {1, 2, 3, 4, 5};
3545 [buttonbar_ registerButtonGroup:0 withButtons:buttons withCount:5];
3546 [buttonbar_ showButtonGroup:0 withDuration:0];
3548 for (int i = 0; i != 5; ++i)
3549 [[buttonbar_ viewWithTag:(i + 1)] setFrame:CGRectMake(
3550 i * 64 + 2, 1, 60, 48
3553 [buttonbar_ showSelectionForButton:1];
3554 [transition_ transition:0 toView:featured_];
3556 [overlay_ addSubview:buttonbar_];
3558 [UIKeyboard initImplementationNow];
3560 CGRect edtrect = [overlay_ bounds];
3561 edtrect.origin.y += navsize.height;
3562 edtrect.size.height -= navsize.height;
3564 CGSize keysize = [UIKeyboard defaultSize];
3565 CGRect keyrect = {{0, [overlay_ bounds].size.height - keysize.height}, keysize};
3566 keyboard_ = [[UIKeyboard alloc] initWithFrame:keyrect];
3568 database_ = [[Database alloc] init];
3569 [database_ setDelegate:progress_];
3571 install_ = [[InstallView alloc] initWithFrame:[transition_ bounds]];
3572 [install_ setDelegate:self];
3574 changes_ = [[ChangesView alloc] initWithFrame:[transition_ bounds]];
3575 [changes_ setDelegate:self];
3577 manage_ = [[ManageView alloc] initWithFrame:[transition_ bounds]];
3578 [manage_ setDelegate:self];
3580 search_ = [[SearchView alloc] initWithFrame:[transition_ bounds]];
3581 [search_ setDelegate:self];
3583 [self reloadData:NO];
3585 Package *package([database_ packageWithName:@"cydia"]);
3586 NSString *application = package == nil ? @"Cydia" : [NSString
3587 stringWithFormat:@"Cydia/%@",
3591 WebView *webview = [webview_ webView];
3592 [webview setApplicationNameForUserAgent:application];
3593 [webview setFrameLoadDelegate:self];
3595 url_ = [NSURL URLWithString:@"http://cydia.saurik.com/"];
3598 [progress_ resetView];
3604 - (void) showKeyboard:(BOOL)show {
3606 [overlay_ addSubview:keyboard_];
3608 [keyboard_ removeFromSuperview];
3613 void AddPreferences(NSString *plist) {
3614 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
3616 NSMutableDictionary *settings = [[[NSMutableDictionary alloc] initWithContentsOfFile:plist] autorelease];
3617 _assert(settings != NULL);
3618 NSMutableArray *items = [settings objectForKey:@"items"];
3622 for (size_t i(0); i != [items count]; ++i) {
3623 NSMutableDictionary *item([items objectAtIndex:i]);
3624 NSString *label = [item objectForKey:@"label"];
3625 if (label != nil && [label isEqualToString:@"Cydia"]) {
3632 for (size_t i(0); i != [items count]; ++i) {
3633 NSDictionary *item([items objectAtIndex:i]);
3634 NSString *label = [item objectForKey:@"label"];
3635 if (label != nil && [label isEqualToString:@"General"]) {
3636 [items insertObject:[NSDictionary dictionaryWithObjectsAndKeys:
3637 @"CydiaSettings", @"bundle",
3638 @"PSLinkCell", @"cell",
3639 [NSNumber numberWithBool:YES], @"hasIcon",
3640 [NSNumber numberWithBool:YES], @"isController",
3642 nil] atIndex:(i + 1)];
3648 _assert([settings writeToFile:plist atomically:YES] == YES);
3655 id Alloc_(id self, SEL selector) {
3656 id object = alloc_(self, selector);
3657 fprintf(stderr, "[%s]A-%p\n", self->isa->name, object);
3661 int main(int argc, char *argv[]) {
3663 memset(nl, 0, sizeof(nl));
3664 nl[0].n_un.n_name = "_useMDNSResponder";
3665 nlist("/usr/lib/libc.dylib", nl);
3666 if (nl[0].n_type != N_UNDF)
3667 *(int *) nl[0].n_value = 0;
3669 bootstrap_ = argc > 1 && strcmp(argv[1], "--bootstrap") == 0;
3674 /*Method alloc = class_getClassMethod([NSObject class], @selector(alloc));
3675 alloc_ = alloc->method_imp;
3676 alloc->method_imp = (IMP) &Alloc_;*/
3678 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
3680 if (NSDictionary *sysver = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]) {
3681 if (NSString *prover = [sysver valueForKey:@"ProductVersion"]) {
3682 Firmware_ = strdup([prover cString]);
3683 NSArray *versions = [prover componentsSeparatedByString:@"."];
3684 int count = [versions count];
3685 Major_ = count > 0 ? [[versions objectAtIndex:0] intValue] : 0;
3686 Minor_ = count > 1 ? [[versions objectAtIndex:0] intValue] : 0;
3687 BugFix_ = count > 2 ? [[versions objectAtIndex:0] intValue] : 0;
3692 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
3693 char *machine = new char[size];
3694 sysctlbyname("hw.machine", machine, &size, NULL, 0);
3697 if (CFMutableDictionaryRef dict = IOServiceMatching("IOPlatformExpertDevice"))
3698 if (io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, dict)) {
3699 if (CFTypeRef serial = IORegistryEntryCreateCFProperty(service, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0)) {
3700 SerialNumber_ = strdup(CFStringGetCStringPtr((CFStringRef) serial, CFStringGetSystemEncoding()));
3704 IOObjectRelease(service);
3707 /*AddPreferences(@"/Applications/Preferences.app/Settings-iPhone.plist");
3708 AddPreferences(@"/Applications/Preferences.app/Settings-iPod.plist");*/
3710 if ((Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"]) == NULL)
3711 Metadata_ = [[NSMutableDictionary alloc] initWithCapacity:2];
3713 Packages_ = [Metadata_ objectForKey:@"Packages"];
3715 system("dpkg --configure -a");
3717 UIApplicationMain(argc, argv, [Cydia class]);