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>
24 #include <mach-o/nlist.h>
27 #include <objc/objc-class.h>
33 /* Extension Keywords {{{ */
34 #define _trace() fprintf(stderr, "_trace()@%s:%u[%s]\n", __FILE__, __LINE__, __FUNCTION__)
36 #define _assert(test) do \
38 fprintf(stderr, "_assert(%d:%s)@%s:%u[%s]\n", errno, #test, __FILE__, __LINE__, __FUNCTION__); \
43 /* Miscellaneous Messages {{{ */
45 - (void) setApplicationNameForUserAgent:(NSString *)applicationName;
46 - (id) frameLoadDelegate;
47 - (void) setFrameLoadDelegate:(id)delegate;
50 @interface NSString (Cydia)
51 - (NSString *) stringByAddingPercentEscapes;
52 - (NSString *) stringByReplacingCharacter:(unsigned short)arg0 withCharacter:(unsigned short)arg1;
56 /* Reset View (UIView) {{{ */
57 @interface UIView (CYResetView)
58 - (void) resetViewAnimated:(BOOL)animated;
61 @implementation UIView (CYResetView)
63 - (void) resetViewAnimated:(BOOL)animated {
64 fprintf(stderr, "%s\n", self->isa->name);
70 /* Reset View (UITable) {{{ */
71 @interface UITable (CYResetView)
72 - (void) resetViewAnimated:(BOOL)animated;
75 @implementation UITable (CYResetView)
77 - (void) resetViewAnimated:(BOOL)animated {
78 [self selectRow:-1 byExtendingSelection:NO withFade:animated];
83 /* Reset View (UISectionList) {{{ */
84 @interface UISectionList (CYResetView)
85 - (void) resetViewAnimated:(BOOL)animated;
88 @implementation UISectionList (CYResetView)
90 - (void) resetViewAnimated:(BOOL)animated {
91 [[self table] resetViewAnimated:animated];
97 /* Perl-Compatible RegEx {{{ */
107 Pcre(const char *regex) :
112 code_ = pcre_compile(regex, 0, &error, &offset, NULL);
115 fprintf(stderr, "%d:%s\n", offset, error);
119 pcre_fullinfo(code_, study_, PCRE_INFO_CAPTURECOUNT, &capture_);
120 matches_ = new int[(capture_ + 1) * 3];
128 NSString *operator [](size_t match) {
130 stringWithCString:(data_ + matches_[match * 2])
131 length:(matches_[match * 2 + 1] - matches_[match * 2])
135 bool operator ()(const char *data, size_t size) {
137 return pcre_exec(code_, study_, data, size, 0, 0, matches_, (capture_ + 1) * 3) >= 0;
141 /* CoreGraphicsServices Primitives {{{ */
147 CGColor(CGColorSpaceRef space, float red, float green, float blue, float alpha) {
148 float color[] = {red, green, blue, alpha};
149 color_ = CGColorCreate(space, color);
153 CGColorRelease(color_);
156 operator CGColorRef() {
167 /* XXX: no GSFontRelease()? */
173 static const int PulseInterval_ = 50000;
174 const char *Machine_ = NULL;
175 const char *SerialNumber_ = NULL;
177 bool bootstrap_ = false;
179 static NSMutableDictionary *Metadata_;
180 static NSMutableDictionary *Packages_;
183 NSString *GetLastUpdate() {
184 NSDate *update = [Metadata_ objectForKey:@"LastUpdate"];
187 return @"Never or Unknown";
189 CFLocaleRef locale = CFLocaleCopyCurrent();
190 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
191 CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) update);
193 CFRelease(formatter);
196 return [(NSString *) formatted autorelease];
199 @protocol ProgressDelegate
200 - (void) setError:(NSString *)error;
201 - (void) setTitle:(NSString *)title;
202 - (void) setPercent:(float)percent;
203 - (void) addOutput:(NSString *)output;
206 NSString *SizeString(double size) {
208 while (size > 1024) {
213 static const char *powers_[] = {"B", "kB", "MB", "GB"};
215 return [NSString stringWithFormat:@"%.1f%s", size, powers_[power]];
218 static const float TextViewOffset_ = 22;
220 UITextView *GetTextView(NSString *value, float left, bool html) {
221 UITextView *text([[[UITextView alloc] initWithFrame:CGRectMake(left, 3, 310 - left, 1000)] autorelease]);
222 [text setEditable:NO];
223 [text setTextSize:16];
225 [text setHTML:value];
227 [text setText:value];
228 [text setEnabled:NO];
230 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
231 CGColor clear(space, 0, 0, 0, 0);
232 [text setBackgroundColor:clear];
233 CGColorSpaceRelease(space);
235 CGRect frame = [text frame];
236 [text setFrame:frame];
237 CGRect rect = [text visibleTextRect];
238 frame.size.height = rect.size.height;
239 [text setFrame:frame];
244 /* Status Delegation {{{ */
246 public pkgAcquireStatus
257 void setDelegate(id delegate) {
258 delegate_ = delegate;
261 virtual bool MediaChange(std::string media, std::string drive) {
265 virtual void IMSHit(pkgAcquire::ItemDesc &item) {
268 virtual void Fetch(pkgAcquire::ItemDesc &item) {
269 [delegate_ setTitle:[NSString stringWithCString:("Downloading " + item.ShortDesc).c_str()]];
272 virtual void Done(pkgAcquire::ItemDesc &item) {
275 virtual void Fail(pkgAcquire::ItemDesc &item) {
277 item.Owner->Status == pkgAcquire::Item::StatIdle ||
278 item.Owner->Status == pkgAcquire::Item::StatDone
282 [delegate_ setError:[NSString stringWithCString:item.Owner->ErrorText.c_str()]];
285 virtual bool Pulse(pkgAcquire *Owner) {
286 bool value = pkgAcquireStatus::Pulse(Owner);
289 double(CurrentBytes + CurrentItems) /
290 double(TotalBytes + TotalItems)
293 [delegate_ setPercent:percent];
297 virtual void Start() {
300 virtual void Stop() {
304 /* Progress Delegation {{{ */
312 virtual void Update() {
313 [delegate_ setTitle:[NSString stringWithCString:Op.c_str()]];
314 [delegate_ setPercent:(Percent / 100)];
323 void setDelegate(id delegate) {
324 delegate_ = delegate;
327 virtual void Done() {
328 [delegate_ setPercent:1];
333 /* External Constants {{{ */
334 extern NSString *kUIButtonBarButtonAction;
335 extern NSString *kUIButtonBarButtonInfo;
336 extern NSString *kUIButtonBarButtonInfoOffset;
337 extern NSString *kUIButtonBarButtonSelectedInfo;
338 extern NSString *kUIButtonBarButtonStyle;
339 extern NSString *kUIButtonBarButtonTag;
340 extern NSString *kUIButtonBarButtonTarget;
341 extern NSString *kUIButtonBarButtonTitle;
342 extern NSString *kUIButtonBarButtonTitleVerticalHeight;
343 extern NSString *kUIButtonBarButtonTitleWidth;
344 extern NSString *kUIButtonBarButtonType;
346 /* Mime Addresses {{{ */
347 Pcre email_r("^\"?(.*)\"? <([^>]*)>$");
349 @interface Address : NSObject {
357 - (NSString *) email;
359 + (Address *) addressWithString:(NSString *)string;
360 - (Address *) initWithString:(NSString *)string;
363 @implementation Address
372 - (NSString *) name {
376 - (NSString *) email {
380 + (Address *) addressWithString:(NSString *)string {
381 return [[[Address alloc] initWithString:string] autorelease];
384 - (Address *) initWithString:(NSString *)string {
385 if ((self = [super init]) != nil) {
386 const char *data = [string UTF8String];
387 size_t size = [string length];
389 if (email_r(data, size)) {
390 name_ = [email_r[1] retain];
391 email_ = [email_r[2] retain];
393 name_ = [[NSString stringWithCString:data length:size] retain];
402 /* Right Alignment {{{ */
403 @interface UIRightTextLabel : UITextLabel {
404 float _savedRightEdgeX;
405 BOOL _sizedtofit_flag;
408 - (void) setFrame:(CGRect)frame;
409 - (void) setText:(NSString *)text;
410 - (void) realignText;
413 @implementation UIRightTextLabel
415 - (void) setFrame:(CGRect)frame {
416 [super setFrame:frame];
417 if (_sizedtofit_flag == NO) {
418 _savedRightEdgeX = frame.origin.x;
423 - (void) setText:(NSString *)text {
424 [super setText:text];
428 - (void) realignText {
429 CGRect oldFrame = [self frame];
431 _sizedtofit_flag = YES;
432 [self sizeToFit]; // shrink down size so I can right align it
434 CGRect newFrame = [self frame];
436 oldFrame.origin.x = _savedRightEdgeX - newFrame.size.width;
437 oldFrame.size.width = newFrame.size.width;
438 [super setFrame:oldFrame];
439 _sizedtofit_flag = NO;
444 /* Linear Algebra {{{ */
445 inline float interpolate(float begin, float end, float fraction) {
446 return (end - begin) * fraction + begin;
452 /* Database Interface {{{ */
453 @interface Database : NSObject {
455 pkgRecords *records_;
456 pkgProblemResolver *resolver_;
457 pkgAcquire *fetcher_;
459 SPtr<pkgPackageManager> manager_;
469 - (void) _readStatus:(NSNumber *)fd;
470 - (void) _readOutput:(NSNumber *)fd;
472 - (Package *) packageWithName:(NSString *)name;
475 - (pkgCacheFile &) cache;
476 - (pkgRecords *) records;
477 - (pkgProblemResolver *) resolver;
478 - (pkgAcquire &) fetcher;
486 - (void) setDelegate:(id)delegate;
491 @interface ResetView : UIView {
492 UIPushButton *configure_;
493 UIPushButton *reload_;
494 NSMutableArray *views_;
495 UINavigationBar *navbar_;
496 UITransitionView *transition_;
503 - (void) navigationBar:(UINavigationBar *)navbar poppedItem:(UINavigationItem *)item;
504 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
506 - (id) initWithFrame:(CGRect)frame;
507 - (void) setDelegate:(id)delegate;
509 - (void) configurePushed;
510 - (void) reloadPushed;
512 - (void) pushView:(UIView *)view withTitle:(NSString *)title backButtonTitle:(NSString *)back rightButton:(NSString *)right;
513 - (void) popViews:(unsigned)views;
514 - (void) resetView:(BOOL)clear;
519 @implementation ResetView
522 [configure_ release];
524 [transition_ release];
530 - (void) navigationBar:(UINavigationBar *)navbar poppedItem:(UINavigationItem *)item {
531 [views_ removeLastObject];
532 UIView *view([views_ lastObject]);
533 [view resetViewAnimated:!resetting_];
536 [transition_ transition:2 toView:view];
541 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
545 - (id) initWithFrame:(CGRect)frame {
546 if ((self = [super initWithFrame:frame]) != nil) {
547 views_ = [[NSMutableArray arrayWithCapacity:4] retain];
549 struct CGRect bounds = [self bounds];
550 CGSize navsize = [UINavigationBar defaultSizeWithPrompt];
551 CGRect navrect = {{0, 0}, navsize};
553 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
554 [self addSubview:navbar_];
556 [navbar_ setBarStyle:1];
557 [navbar_ setDelegate:self];
559 transition_ = [[UITransitionView alloc] initWithFrame:CGRectMake(
560 bounds.origin.x, bounds.origin.y + navsize.height, bounds.size.width, bounds.size.height - navsize.height
563 //configure_ = [[UIPushButton alloc] initWithFrame:CGRectMake(15, 9, 17, 18)];
564 configure_ = [[UIPushButton alloc] initWithFrame:CGRectMake(10, 9, 17, 18)];
565 [configure_ setShowPressFeedback:YES];
566 [configure_ setImage:[UIImage applicationImageNamed:@"configure.png"]];
567 [configure_ addTarget:self action:@selector(configurePushed) forEvents:1];
569 //reload_ = [[UIPushButton alloc] initWithFrame:CGRectMake(288, 5, 18, 22)];
570 reload_ = [[UIPushButton alloc] initWithFrame:CGRectMake(293, 5, 18, 22)];
571 [reload_ setShowPressFeedback:YES];
572 [reload_ setImage:[UIImage applicationImageNamed:@"reload.png"]];
573 [reload_ addTarget:self action:@selector(reloadPushed) forEvents:1];
575 [navbar_ addSubview:configure_];
576 [navbar_ addSubview:reload_];
578 [self addSubview:transition_];
582 - (void) setDelegate:(id)delegate {
583 delegate_ = delegate;
586 - (void) configurePushed {
587 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
588 initWithTitle:@"Sources Unimplemented"
589 buttons:[NSArray arrayWithObjects:@"Okay", nil]
595 [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'."];
596 [sheet popupAlertAnimated:YES];
599 - (void) reloadPushed {
603 - (void) pushView:(UIView *)view withTitle:(NSString *)title backButtonTitle:(NSString *)back rightButton:(NSString *)right {
604 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:title] autorelease];
605 [navbar_ pushNavigationItem:navitem];
606 [navitem setBackButtonTitle:back];
608 [navbar_ showButtonsWithLeftTitle:nil rightTitle:right];
610 [transition_ transition:([views_ count] == 0 ? 0 : 1) toView:view];
611 [views_ addObject:view];
614 - (void) popViews:(unsigned)views {
616 for (unsigned i(0); i != views; ++i)
617 [navbar_ popNavigationItem];
621 [transition_ transition:2 toView:[views_ lastObject]];
624 - (void) resetView:(BOOL)clear {
627 if ([views_ count] > 1) {
628 [navbar_ disableAnimation];
629 while ([views_ count] != (clear ? 1 : 2))
630 [navbar_ popNavigationItem];
631 [navbar_ enableAnimation];
633 [navbar_ popNavigationItem];
639 [transition_ transition:(clear ? 0 : 2) toView:[views_ lastObject]];
642 - (void) _resetView {
643 [navbar_ showButtonsWithLeftTitle:nil rightTitle:nil];
647 [navbar_ setPrompt:[NSString stringWithFormat:@"Last Updated: %@", GetLastUpdate()]];
652 /* Confirmation View {{{ */
653 void AddTextView(NSMutableDictionary *fields, NSMutableArray *packages, NSString *key) {
654 if ([packages count] == 0)
657 UITextView *text = GetTextView([packages count] == 0 ? @"n/a" : [packages componentsJoinedByString:@", "], 110, false);
658 [fields setObject:text forKey:key];
660 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
661 CGColor blue(space, 0, 0, 0.4, 1);
662 [text setTextColor:blue];
663 CGColorSpaceRelease(space);
666 @protocol ConfirmationViewDelegate
671 @interface ConfirmationView : UIView {
674 UITransitionView *transition_;
676 UINavigationBar *navbar_;
677 UIPreferencesTable *table_;
678 NSMutableDictionary *fields_;
679 UIAlertSheet *essential_;
685 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
686 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
687 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
689 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table;
690 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group;
691 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed;
692 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group;
693 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group;
695 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate;
699 @implementation ConfirmationView
702 [transition_ release];
707 if (essential_ != nil)
708 [essential_ release];
713 [transition_ transition:7 toView:nil];
717 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
718 if (from != nil && to == nil)
719 [self removeFromSuperview];
722 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
725 if (essential_ != nil)
726 [essential_ popupAlertAnimated:YES];
737 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
738 [essential_ dismiss];
742 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
746 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
748 case 0: return @"Statistics";
749 case 1: return @"Modifications";
751 default: _assert(false);
755 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
758 case 1: return [fields_ count];
760 default: _assert(false);
764 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
765 if (group != 1 || row == -1)
768 _assert(size_t(row) < [fields_ count]);
769 return [[[fields_ allValues] objectAtIndex:row] visibleTextRect].size.height + TextViewOffset_;
773 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
774 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
775 [cell setShowSelection:NO];
778 case 0: switch (row) {
780 [cell setTitle:@"Downloading"];
781 [cell setValue:SizeString([database_ fetcher].FetchNeeded())];
785 [cell setTitle:@"Resuming At"];
786 [cell setValue:SizeString([database_ fetcher].PartialPresent())];
790 double size([database_ cache]->UsrSize());
793 [cell setTitle:@"Disk Freeing"];
794 [cell setValue:SizeString(-size)];
796 [cell setTitle:@"Disk Using"];
797 [cell setValue:SizeString(size)];
801 default: _assert(false);
805 _assert(size_t(row) < [fields_ count]);
806 [cell setTitle:[[fields_ allKeys] objectAtIndex:row]];
807 [cell addSubview:[[fields_ allValues] objectAtIndex:row]];
810 default: _assert(false);
816 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate {
817 if ((self = [super initWithFrame:[view bounds]]) != nil) {
818 database_ = database;
819 delegate_ = delegate;
821 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
822 [self addSubview:transition_];
824 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
826 CGSize navsize = [UINavigationBar defaultSize];
827 CGRect navrect = {{0, 0}, navsize};
828 CGRect bounds = [overlay_ bounds];
830 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
831 [navbar_ setBarStyle:1];
832 [navbar_ setDelegate:self];
834 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Confirm"] autorelease];
835 [navbar_ pushNavigationItem:navitem];
836 [navbar_ showButtonsWithLeftTitle:@"Cancel" rightTitle:@"Confirm"];
838 fields_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
840 NSMutableArray *installing = [NSMutableArray arrayWithCapacity:16];
841 NSMutableArray *upgrading = [NSMutableArray arrayWithCapacity:16];
842 NSMutableArray *removing = [NSMutableArray arrayWithCapacity:16];
844 bool essential(false);
846 pkgCacheFile &cache([database_ cache]);
847 for (pkgCache::PkgIterator iterator = cache->PkgBegin(); !iterator.end(); ++iterator) {
848 NSString *name([NSString stringWithCString:iterator.Name()]);
849 if (cache[iterator].NewInstall())
850 [installing addObject:name];
851 else if (cache[iterator].Upgrade())
852 [upgrading addObject:name];
853 else if (cache[iterator].Delete()) {
854 [removing addObject:name];
855 if ((iterator->Flags & pkgCache::Flag::Essential) != 0)
863 essential_ = [[UIAlertSheet alloc]
864 initWithTitle:@"Unable to Comply"
865 buttons:[NSArray arrayWithObjects:@"Okay", nil]
871 [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."];
874 AddTextView(fields_, installing, @"Installing");
875 AddTextView(fields_, upgrading, @"Upgrading");
876 AddTextView(fields_, removing, @"Removing");
878 table_ = [[UIPreferencesTable alloc] initWithFrame:CGRectMake(
879 0, navsize.height, bounds.size.width, bounds.size.height - navsize.height
882 [table_ setReusesTableCells:YES];
883 [table_ setDataSource:self];
886 [overlay_ addSubview:navbar_];
887 [overlay_ addSubview:table_];
889 [view addSubview:self];
891 [transition_ setDelegate:self];
893 UIView *blank = [[[UIView alloc] initWithFrame:[transition_ bounds]] autorelease];
894 [transition_ transition:0 toView:blank];
895 [transition_ transition:3 toView:overlay_];
902 /* Package Class {{{ */
903 NSString *Scour(const char *field, const char *begin, const char *end) {
904 size_t i(0), l(strlen(field));
907 const char *name = begin + i;
908 const char *colon = name + l;
909 const char *value = colon + 1;
914 memcmp(name, field, l) == 0
916 while (value != end && value[0] == ' ')
918 const char *line = std::find(value, end, '\n');
919 while (line != value && line[-1] == ' ')
921 return [NSString stringWithCString:value length:(line - value)];
923 begin = std::find(begin, end, '\n');
931 @interface Package : NSObject {
932 pkgCache::PkgIterator iterator_;
934 pkgCache::VerIterator version_;
935 pkgCache::VerFileIterator file_;
938 NSString *installed_;
950 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database version:(pkgCache::VerIterator)version file:(pkgCache::VerFileIterator)file;
951 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
953 - (NSString *) section;
954 - (Address *) maintainer;
956 - (NSString *) description;
957 - (NSString *) index;
961 - (NSString *) latest;
962 - (NSString *) installed;
967 - (NSString *) tagline;
969 - (NSString *) bundle;
970 - (NSString *) website;
972 - (BOOL) matches:(NSString *)text;
974 - (NSComparisonResult) compareByName:(Package *)package;
975 - (NSComparisonResult) compareBySectionAndName:(Package *)package;
976 - (NSComparisonResult) compareForChanges:(Package *)package;
982 @implementation Package
986 if (installed_ != nil)
987 [installed_ release];
1000 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database version:(pkgCache::VerIterator)version file:(pkgCache::VerFileIterator)file {
1001 if ((self = [super init]) != nil) {
1002 iterator_ = iterator;
1003 database_ = database;
1008 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1010 const char *begin, *end;
1011 parser->GetRec(begin, end);
1013 latest_ = [[NSString stringWithCString:version_.VerStr()] retain];
1014 installed_ = iterator_.CurrentVer().end() ? nil : [[NSString stringWithCString:iterator_.CurrentVer().VerStr()] retain];
1016 id_ = [[[NSString stringWithCString:iterator_.Name()] lowercaseString] retain];
1017 name_ = Scour("Name", begin, end);
1019 name_ = [name_ retain];
1020 tagline_ = [[NSString stringWithCString:parser->ShortDesc().c_str()] retain];
1021 icon_ = Scour("Icon", begin, end);
1023 icon_ = [icon_ retain];
1024 bundle_ = Scour("Bundle", begin, end);
1026 bundle_ = [bundle_ retain];
1027 website_ = Scour("Website", begin, end);
1028 if (website_ != nil)
1029 website_ = [website_ retain];
1031 NSMutableDictionary *metadata = [Packages_ objectForKey:id_];
1032 if (metadata == nil) {
1033 metadata = [NSMutableDictionary dictionaryWithObjectsAndKeys:
1037 [Packages_ setObject:metadata forKey:id_];
1042 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
1043 for (pkgCache::VerIterator version = iterator.VersionList(); !version.end(); ++version)
1044 for (pkgCache::VerFileIterator file = version.FileList(); !file.end(); ++file)
1045 return [[[Package alloc]
1046 initWithIterator:iterator
1054 - (NSString *) section {
1055 return [[NSString stringWithCString:iterator_.Section()] stringByReplacingCharacter:'_' withCharacter:' '];
1058 - (Address *) maintainer {
1059 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1060 return [Address addressWithString:[NSString stringWithCString:parser->Maintainer().c_str()]];
1064 return version_->InstalledSize;
1067 - (NSString *) description {
1068 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1069 NSString *description([NSString stringWithCString:parser->LongDesc().c_str()]);
1071 NSArray *lines = [description componentsSeparatedByString:@"\n"];
1072 NSMutableArray *trimmed = [NSMutableArray arrayWithCapacity:([lines count] - 1)];
1073 if ([lines count] < 2)
1076 NSCharacterSet *whitespace = [NSCharacterSet whitespaceCharacterSet];
1077 for (size_t i(1); i != [lines count]; ++i) {
1078 NSString *trim = [[lines objectAtIndex:i] stringByTrimmingCharactersInSet:whitespace];
1079 [trimmed addObject:trim];
1082 return [trimmed componentsJoinedByString:@"\n"];
1085 - (NSString *) index {
1086 return [[[self name] substringToIndex:1] uppercaseString];
1090 return [[Packages_ objectForKey:id_] objectForKey:@"FirstSeen"];
1093 - (NSString *) latest {
1097 - (NSString *) installed {
1101 - (BOOL) upgradable {
1102 NSString *installed = [self installed];
1103 return installed != nil && [[self latest] compare:installed] != NSOrderedSame ? YES : NO;
1110 - (NSString *) name {
1111 return name_ == nil ? id_ : name_;
1114 - (NSString *) tagline {
1118 - (NSString *) icon {
1122 - (NSString *) bundle {
1126 - (NSString *) website {
1130 - (BOOL) matches:(NSString *)text {
1136 range = [[self name] rangeOfString:text options:NSCaseInsensitiveSearch];
1137 if (range.location != NSNotFound)
1140 range = [[self tagline] rangeOfString:text options:NSCaseInsensitiveSearch];
1141 if (range.location != NSNotFound)
1147 - (NSComparisonResult) compareByName:(Package *)package {
1148 return [[self name] caseInsensitiveCompare:[package name]];
1151 - (NSComparisonResult) compareBySectionAndName:(Package *)package {
1152 NSComparisonResult result = [[self section] compare:[package section]];
1153 if (result != NSOrderedSame)
1155 return [self compareByName:package];
1158 - (NSComparisonResult) compareForChanges:(Package *)package {
1159 BOOL lhs = [self upgradable];
1160 BOOL rhs = [package upgradable];
1163 return lhs ? NSOrderedAscending : NSOrderedDescending;
1165 switch ([[self seen] compare:[package seen]]) {
1166 case NSOrderedAscending:
1167 return NSOrderedDescending;
1170 case NSOrderedDescending:
1171 return NSOrderedAscending;
1177 return [self compareByName:package];
1181 pkgProblemResolver *resolver = [database_ resolver];
1182 resolver->Clear(iterator_);
1183 resolver->Protect(iterator_);
1184 [database_ cache]->MarkInstall(iterator_, false);
1188 pkgProblemResolver *resolver = [database_ resolver];
1189 resolver->Clear(iterator_);
1190 resolver->Protect(iterator_);
1191 resolver->Remove(iterator_);
1192 [database_ cache]->MarkDelete(iterator_, true);
1197 /* Section Class {{{ */
1198 @interface Section : NSObject {
1201 NSMutableArray *packages_;
1206 - (Section *) initWithName:(NSString *)name row:(size_t)row;
1207 - (NSString *) name;
1209 - (NSArray *) packages;
1211 - (void) addPackage:(Package *)package;
1214 @implementation Section
1218 [packages_ release];
1222 - (Section *) initWithName:(NSString *)name row:(size_t)row {
1223 if ((self = [super init]) != nil) {
1224 name_ = [name retain];
1226 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
1230 - (NSString *) name {
1238 - (NSArray *) packages {
1243 return [packages_ count];
1246 - (void) addPackage:(Package *)package {
1247 [packages_ addObject:package];
1253 /* Package View {{{ */
1254 @protocol PackageViewDelegate
1255 - (void) performPackage:(Package *)package;
1258 @interface PackageView : UIView {
1259 UIPreferencesTable *table_;
1261 UITextView *description_;
1267 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table;
1268 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group;
1269 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed;
1270 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group;
1271 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group;
1273 - (BOOL) canSelectRow:(int)row;
1274 - (void) tableRowSelected:(NSNotification *)notification;
1276 - (Package *) package;
1278 - (id) initWithFrame:(struct CGRect)frame;
1279 - (void) setPackage:(Package *)package;
1280 - (void) setDelegate:(id)delegate;
1283 @implementation PackageView
1286 if (package_ != nil)
1288 if (description_ != nil)
1289 [description_ release];
1294 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
1298 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
1301 case 1: return @"Details";
1302 case 2: return @"Source";
1304 default: _assert(false);
1308 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
1309 if (group != 0 || row != 1)
1312 return [description_ visibleTextRect].size.height + TextViewOffset_;
1315 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
1317 case 0: return [package_ website] == nil ? 2 : 3;
1321 default: _assert(false);
1325 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
1326 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
1327 [cell setShowSelection:NO];
1330 case 0: switch (row) {
1332 [cell setTitle:[package_ name]];
1333 [cell setValue:[package_ latest]];
1337 [cell addSubview:description_];
1341 [cell setTitle:@"More Information"];
1342 [cell setShowDisclosure:YES];
1343 [cell setShowSelection:YES];
1346 default: _assert(false);
1349 case 1: switch (row) {
1351 [cell setTitle:@"Identifier"];
1352 [cell setValue:[package_ id]];
1356 [cell setTitle:@"Installed Version"];
1357 NSString *installed([package_ installed]);
1358 [cell setValue:(installed == nil ? @"n/a" : installed)];
1362 [cell setTitle:@"Section"];
1363 [cell setValue:[package_ section]];
1367 [cell setTitle:@"Expanded Size"];
1368 [cell setValue:SizeString([package_ size])];
1372 [cell setTitle:@"Maintainer"];
1373 [cell setValue:[[package_ maintainer] name]];
1374 [cell setShowDisclosure:YES];
1375 [cell setShowSelection:YES];
1378 default: _assert(false);
1381 case 2: switch (row) {
1384 default: _assert(false);
1390 - (BOOL) canSelectRow:(int)row {
1394 - (void) tableRowSelected:(NSNotification *)notification {
1395 int row = [table_ selectedRow];
1397 if (row == ([package_ website] == nil ? 8 : 9)) {
1398 [delegate_ openURL:[NSURL URLWithString:[NSString stringWithFormat:@"mailto:%@?subject=%@",
1399 [[package_ maintainer] email],
1400 [[NSString stringWithFormat:@"regarding apt package \"%@\"", [package_ name]] stringByAddingPercentEscapes]
1405 - (Package *) package {
1409 - (id) initWithFrame:(struct CGRect)frame {
1410 if ((self = [super initWithFrame:frame]) != nil) {
1411 table_ = [[UIPreferencesTable alloc] initWithFrame:[self bounds]];
1412 [self addSubview:table_];
1414 [table_ setDataSource:self];
1415 [table_ setDelegate:self];
1419 - (void) setPackage:(Package *)package {
1420 if (package_ != nil) {
1421 [package_ autorelease];
1425 if (description_ != nil) {
1426 [description_ release];
1430 if (package != nil) {
1431 package_ = [package retain];
1433 NSString *description([package description]);
1434 if (description == nil)
1435 description = [package tagline];
1436 description_ = [GetTextView(description, 12, true) retain];
1438 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1439 CGColor black(space, 0, 0, 0, 1);
1440 [description_ setTextColor:black];
1441 CGColorSpaceRelease(space);
1443 [table_ reloadData];
1447 - (void) setDelegate:(id)delegate {
1448 delegate_ = delegate;
1453 /* Package Cell {{{ */
1454 @interface PackageCell : UITableCell {
1456 UITextLabel *version_;
1457 UITextLabel *description_;
1463 - (PackageCell *) initWithVersioner:(SEL)versioner;
1464 - (void) setPackage:(Package *)package;
1466 - (void) _setSelected:(float)fraction;
1467 - (void) setSelected:(BOOL)selected;
1468 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
1469 - (void) _setSelectionFadeFraction:(float)fraction;
1473 @implementation PackageCell
1478 [description_ release];
1482 - (PackageCell *) initWithVersioner:(SEL)versioner {
1483 if ((self = [super init]) != nil) {
1484 versioner_ = versioner;
1486 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22);
1487 GSFontRef large = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
1488 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 14);
1490 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1492 CGColor clear(space, 0, 0, 0, 0);
1494 name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(12, 7, 250, 25)];
1495 [name_ setBackgroundColor:clear];
1496 [name_ setFont:bold];
1498 version_ = [[UIRightTextLabel alloc] initWithFrame:CGRectMake(286, 7, 70, 25)];
1499 [version_ setBackgroundColor:clear];
1500 [version_ setFont:large];
1502 description_ = [[UITextLabel alloc] initWithFrame:CGRectMake(13, 35, 315, 20)];
1503 [description_ setBackgroundColor:clear];
1504 [description_ setFont:small];
1506 [self addSubview:name_];
1507 [self addSubview:version_];
1508 [self addSubview:description_];
1510 CGColorSpaceRelease(space);
1518 - (void) setPackage:(Package *)package {
1519 [name_ setText:[package name]];
1520 [version_ setText:[package latest]];
1521 [description_ setText:[package tagline]];
1524 - (void) _setSelected:(float)fraction {
1525 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1527 CGColor black(space,
1528 interpolate(0.0, 1.0, fraction),
1529 interpolate(0.0, 1.0, fraction),
1530 interpolate(0.0, 1.0, fraction),
1534 interpolate(0.2, 1.0, fraction),
1535 interpolate(0.2, 1.0, fraction),
1536 interpolate(1.0, 1.0, fraction),
1540 interpolate(0.4, 1.0, fraction),
1541 interpolate(0.4, 1.0, fraction),
1542 interpolate(0.4, 1.0, fraction),
1545 [name_ setColor:black];
1546 [version_ setColor:blue];
1547 [description_ setColor:gray];
1549 CGColorSpaceRelease(space);
1552 - (void) setSelected:(BOOL)selected {
1553 [self _setSelected:(selected ? 1.0 : 0.0)];
1554 [super setSelected:selected];
1557 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
1559 [self _setSelected:(selected ? 1.0 : 0.0)];
1560 [super setSelected:selected withFade:fade];
1563 - (void) _setSelectionFadeFraction:(float)fraction {
1564 [self _setSelected:fraction];
1565 [super _setSelectionFadeFraction:fraction];
1571 /* Database Implementation {{{ */
1572 @implementation Database
1579 - (void) _readStatus:(NSNumber *)fd {
1580 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1582 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1583 std::istream is(&ib);
1588 pcre *code = pcre_compile("^([^:]*):([^:]*):([^:]*):(.*)$", 0, &error, &offset, NULL);
1590 pcre_extra *study = NULL;
1592 pcre_fullinfo(code, study, PCRE_INFO_CAPTURECOUNT, &capture);
1593 int matches[(capture + 1) * 3];
1595 while (std::getline(is, line)) {
1596 const char *data(line.c_str());
1598 _assert(pcre_exec(code, study, data, line.size(), 0, 0, matches, sizeof(matches) / sizeof(matches[0])) >= 0);
1600 std::istringstream buffer(line.substr(matches[6], matches[7] - matches[6]));
1603 [delegate_ setPercent:(percent / 100)];
1605 NSString *string = [NSString stringWithCString:(data + matches[8]) length:(matches[9] - matches[8])];
1606 std::string type(line.substr(matches[2], matches[3] - matches[2]));
1608 if (type == "pmerror")
1609 [delegate_ setError:string];
1610 else if (type == "pmstatus")
1611 [delegate_ setTitle:string];
1612 else if (type == "pmconffile")
1614 else _assert(false);
1621 - (void) _readOutput:(NSNumber *)fd {
1622 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1624 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1625 std::istream is(&ib);
1628 while (std::getline(is, line))
1629 [delegate_ addOutput:[NSString stringWithCString:line.c_str()]];
1635 - (Package *) packageWithName:(NSString *)name {
1636 pkgCache::PkgIterator iterator(cache_->FindPkg([name cString]));
1637 return iterator.end() ? nil : [Package packageWithIterator:iterator database:self];
1640 - (Database *) init {
1641 if ((self = [super init]) != nil) {
1649 _assert(pipe(fds) != -1);
1653 detachNewThreadSelector:@selector(_readStatus:)
1655 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1658 _assert(pipe(fds) != -1);
1659 _assert(dup2(fds[1], 1) != -1);
1660 _assert(close(fds[1]) != -1);
1663 detachNewThreadSelector:@selector(_readOutput:)
1665 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1670 - (pkgCacheFile &) cache {
1674 - (pkgRecords *) records {
1678 - (pkgProblemResolver *) resolver {
1682 - (pkgAcquire &) fetcher {
1686 - (void) reloadData {
1694 _assert(cache_.Open(progress_, true));
1695 records_ = new pkgRecords(cache_);
1696 resolver_ = new pkgProblemResolver(cache_);
1697 fetcher_ = new pkgAcquire(&status_);
1702 pkgRecords records(cache_);
1704 lock_ = new FileFd();
1705 lock_->Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1706 _assert(!_error->PendingError());
1709 _assert(list.ReadMainList());
1711 manager_ = (_system->CreatePM(cache_));
1712 _assert(manager_->GetArchives(fetcher_, &list, &records));
1713 _assert(!_error->PendingError());
1717 if (fetcher_->Run(PulseInterval_) != pkgAcquire::Continue)
1721 pkgPackageManager::OrderResult result = manager_->DoInstall(statusfd_);
1723 if (result == pkgPackageManager::Failed)
1725 if (_error->PendingError())
1727 if (result != pkgPackageManager::Completed)
1733 _assert(list.ReadMainList());
1736 lock.Fd(GetLock(_config->FindDir("Dir::State::Lists") + "lock"));
1737 _assert(!_error->PendingError());
1739 pkgAcquire fetcher(&status_);
1740 _assert(list.GetIndexes(&fetcher));
1741 _assert(fetcher.Run(PulseInterval_) != pkgAcquire::Failed);
1743 bool failed = false;
1744 for (pkgAcquire::ItemIterator item = fetcher.ItemsBegin(); item != fetcher.ItemsEnd(); item++)
1745 if ((*item)->Status != pkgAcquire::Item::StatDone) {
1746 (*item)->Finished();
1750 if (!failed && _config->FindB("APT::Get::List-Cleanup", true) == true) {
1751 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists")));
1752 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/"));
1755 [Metadata_ setObject:[NSDate date] forKey:@"LastUpdate"];
1759 _assert(cache_->DelCount() == 0 && cache_->InstCount() == 0);
1760 _assert(pkgApplyStatus(cache_));
1762 if (cache_->BrokenCount() != 0) {
1763 _assert(pkgFixBroken(cache_));
1764 _assert(cache_->BrokenCount() == 0);
1765 _assert(pkgMinimizeUpgrade(cache_));
1768 _assert(pkgDistUpgrade(cache_));
1771 - (void) setDelegate:(id)delegate {
1772 delegate_ = delegate;
1773 status_.setDelegate(delegate);
1774 progress_.setDelegate(delegate);
1780 /* Progress Data {{{ */
1781 @interface ProgressData : NSObject {
1787 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object;
1794 @implementation ProgressData
1796 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object {
1797 if ((self = [super init]) != nil) {
1798 selector_ = selector;
1818 /* Progress View {{{ */
1819 @interface ProgressView : UIView <
1823 UIView *background_;
1824 UITransitionView *transition_;
1826 UINavigationBar *navbar_;
1827 UIProgressBar *progress_;
1828 UITextView *output_;
1829 UITextLabel *status_;
1835 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
1837 - (ProgressView *) initWithFrame:(struct CGRect)frame delegate:(id)delegate;
1838 - (void) setContentView:(UIView *)view;
1841 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
1843 - (void) _retachThread;
1844 - (void) _detachNewThreadData:(ProgressData *)data;
1845 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title;
1847 - (void) setError:(NSString *)error;
1848 - (void) _setError:(NSString *)error;
1850 - (void) setTitle:(NSString *)title;
1851 - (void) _setTitle:(NSString *)title;
1853 - (void) setPercent:(float)percent;
1854 - (void) _setPercent:(NSNumber *)percent;
1856 - (void) addOutput:(NSString *)output;
1857 - (void) _addOutput:(NSString *)output;
1860 @protocol ProgressViewDelegate
1861 - (void) progressViewIsComplete:(ProgressView *)sender;
1864 @implementation ProgressView
1868 if (background_ != nil)
1869 [background_ release];
1870 [transition_ release];
1873 [progress_ release];
1879 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
1880 if (bootstrap_ && from == overlay_ && to == view_)
1884 - (ProgressView *) initWithFrame:(struct CGRect)frame delegate:(id)delegate {
1885 if ((self = [super initWithFrame:frame]) != nil) {
1886 delegate_ = delegate;
1888 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1890 CGColor black(space, 0.0, 0.0, 0.0, 1.0);
1891 CGColor white(space, 1.0, 1.0, 1.0, 1.0);
1892 CGColor clear(space, 0.0, 0.0, 0.0, 0.0);
1894 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
1895 [transition_ setDelegate:self];
1897 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
1900 [overlay_ setBackgroundColor:black];
1902 background_ = [[UIView alloc] initWithFrame:[self bounds]];
1903 [background_ setBackgroundColor:black];
1904 [self addSubview:background_];
1907 [self addSubview:transition_];
1909 CGSize navsize = [UINavigationBar defaultSize];
1910 CGRect navrect = {{0, 0}, navsize};
1912 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
1913 [overlay_ addSubview:navbar_];
1915 [navbar_ setBarStyle:1];
1916 [navbar_ setDelegate:self];
1918 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:nil] autorelease];
1919 [navbar_ pushNavigationItem:navitem];
1921 CGRect bounds = [overlay_ bounds];
1922 CGSize prgsize = [UIProgressBar defaultSize];
1925 (bounds.size.width - prgsize.width) / 2,
1926 bounds.size.height - prgsize.height - 20
1929 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
1930 [overlay_ addSubview:progress_];
1932 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(
1934 bounds.size.height - prgsize.height - 50,
1935 bounds.size.width - 20,
1939 [status_ setColor:white];
1940 [status_ setBackgroundColor:clear];
1942 [status_ setCentersHorizontally:YES];
1943 //[status_ setFont:font];
1945 output_ = [[UITextView alloc] initWithFrame:CGRectMake(
1947 navrect.size.height + 20,
1948 bounds.size.width - 20,
1949 bounds.size.height - navsize.height - 62 - navrect.size.height
1952 //[output_ setTextFont:@"Courier New"];
1953 [output_ setTextSize:12];
1955 [output_ setTextColor:white];
1956 [output_ setBackgroundColor:clear];
1958 [output_ setMarginTop:0];
1959 [output_ setAllowsRubberBanding:YES];
1961 [overlay_ addSubview:output_];
1962 [overlay_ addSubview:status_];
1964 [progress_ setStyle:0];
1966 CGColorSpaceRelease(space);
1970 - (void) setContentView:(UIView *)view {
1971 view_ = [view retain];
1974 - (void) resetView {
1975 [transition_ transition:6 toView:view_];
1978 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
1982 - (void) _retachThread {
1983 [delegate_ progressViewIsComplete:self];
1987 - (void) _detachNewThreadData:(ProgressData *)data {
1988 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1990 [[data target] performSelector:[data selector] withObject:[data object]];
1993 [self performSelectorOnMainThread:@selector(_retachThread) withObject:nil waitUntilDone:YES];
1998 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title {
1999 [navbar_ popNavigationItem];
2000 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:title] autorelease];
2001 [navbar_ pushNavigationItem:navitem];
2003 [status_ setText:nil];
2004 [output_ setText:@""];
2005 [progress_ setProgress:0];
2007 [transition_ transition:6 toView:overlay_];
2010 detachNewThreadSelector:@selector(_detachNewThreadData:)
2012 withObject:[[ProgressData alloc]
2013 initWithSelector:selector
2020 - (void) setError:(NSString *)error {
2022 performSelectorOnMainThread:@selector(_setError:)
2028 - (void) _setError:(NSString *)error {
2029 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
2030 initWithTitle:@"Package Error"
2031 buttons:[NSArray arrayWithObjects:@"Okay", nil]
2032 defaultButtonIndex:0
2037 [sheet setBodyText:error];
2038 [sheet popupAlertAnimated:YES];
2041 - (void) setTitle:(NSString *)title {
2043 performSelectorOnMainThread:@selector(_setTitle:)
2049 - (void) _setTitle:(NSString *)title {
2050 [status_ setText:[title stringByAppendingString:@"..."]];
2053 - (void) setPercent:(float)percent {
2055 performSelectorOnMainThread:@selector(_setPercent:)
2056 withObject:[NSNumber numberWithFloat:percent]
2061 - (void) _setPercent:(NSNumber *)percent {
2062 [progress_ setProgress:[percent floatValue]];
2065 - (void) addOutput:(NSString *)output {
2067 performSelectorOnMainThread:@selector(_addOutput:)
2073 - (void) _addOutput:(NSString *)output {
2074 [output_ setText:[NSString stringWithFormat:@"%@\n%@", [output_ text], output]];
2075 CGSize size = [output_ contentSize];
2076 CGRect rect = {{0, size.height}, {size.width, 0}};
2077 [output_ scrollRectToVisible:rect animated:YES];
2083 /* Package Table {{{ */
2084 @protocol PackageTableDelegate
2085 - (void) packageTable:(id)table packageSelected:(Package *)package;
2088 @interface PackageTable : UIView {
2090 UISectionList *list_;
2094 NSMutableArray *sections_;
2099 - (int) numberOfSectionsInSectionList:(UISectionList *)list;
2100 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section;
2101 - (int) sectionList:(UISectionList *)list rowForSection:(int)section;
2103 - (int) numberOfRowsInTable:(UITable *)table;
2104 - (float) table:(UITable *)table heightForRow:(int)row;
2105 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing;
2106 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row;
2107 - (void) tableRowSelected:(NSNotification *)notification;
2109 - (id) initWithFrame:(CGRect)frame versioner:(SEL)versioner;
2111 - (void) setDelegate:(id)delegate;
2112 - (void) setPackages:(NSArray *)packages;
2114 - (void) resetViewAnimated:(BOOL)animated;
2115 - (UITable *) table;
2118 @implementation PackageTable
2122 [sections_ release];
2123 if (packages_ != nil)
2124 [packages_ release];
2128 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
2129 return [sections_ count];
2132 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
2133 return [[sections_ objectAtIndex:section] name];
2136 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
2137 return [[sections_ objectAtIndex:section] row];
2140 - (int) numberOfRowsInTable:(UITable *)table {
2141 return [packages_ count];
2144 - (float) table:(UITable *)table heightForRow:(int)row {
2148 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2150 reusing = [[[PackageCell alloc] initWithVersioner:versioner_] autorelease];
2151 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
2155 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
2159 - (void) tableRowSelected:(NSNotification *)notification {
2160 int row = [[notification object] selectedRow];
2161 [delegate_ packageTable:self packageSelected:(row == INT_MAX ? nil : [packages_ objectAtIndex:row])];
2164 - (id) initWithFrame:(CGRect)frame versioner:(SEL)versioner {
2165 if ((self = [super initWithFrame:frame]) != nil) {
2166 versioner_ = versioner;
2167 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
2169 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:YES];
2170 [list_ setDataSource:self];
2172 UITableColumn *column = [[[UITableColumn alloc]
2173 initWithTitle:@"Name"
2175 width:frame.size.width
2178 UITable *table = [list_ table];
2179 [table setSeparatorStyle:1];
2180 [table addTableColumn:column];
2181 [table setDelegate:self];
2182 [table setReusesTableCells:YES];
2184 [self addSubview:list_];
2188 - (void) setDelegate:(id)delegate {
2189 delegate_ = delegate;
2192 - (void) setPackages:(NSArray *)packages {
2193 if (packages_ != nil)
2194 [packages_ autorelease];
2195 _assert(packages != nil);
2196 packages_ = [packages retain];
2198 [sections_ removeAllObjects];
2200 Section *section = nil;
2202 for (size_t offset(0); offset != [packages_ count]; ++offset) {
2203 Package *package = [packages_ objectAtIndex:offset];
2204 NSString *name = [package index];
2206 if (section == nil || ![[section name] isEqual:name]) {
2207 section = [[[Section alloc] initWithName:name row:offset] autorelease];
2208 [sections_ addObject:section];
2211 [section addPackage:package];
2217 - (void) resetViewAnimated:(BOOL)animated {
2218 [[list_ table] selectRow:-1 byExtendingSelection:NO withFade:animated];
2221 - (UITable *) table {
2222 return [list_ table];
2228 /* Section Cell {{{ */
2229 @interface SectionCell : UITableCell {
2231 UITextLabel *count_;
2237 - (void) setSection:(Section *)section;
2239 - (void) _setSelected:(float)fraction;
2240 - (void) setSelected:(BOOL)selected;
2241 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
2242 - (void) _setSelectionFadeFraction:(float)fraction;
2246 @implementation SectionCell
2255 if ((self = [super init]) != nil) {
2256 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22);
2257 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 12);
2259 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
2260 CGColor clear(space, 0, 0, 0, 0);
2261 CGColor white(space, 1, 1, 1, 1);
2263 name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(47, 9, 250, 25)];
2264 [name_ setBackgroundColor:clear];
2265 [name_ setFont:bold];
2267 count_ = [[UITextLabel alloc] initWithFrame:CGRectMake(11, 7, 29, 32)];
2268 [count_ setCentersHorizontally:YES];
2269 [count_ setBackgroundColor:clear];
2270 [count_ setFont:small];
2271 [count_ setColor:white];
2273 UIImageView *folder = [[[UIImageView alloc] initWithFrame:CGRectMake(8, 7, 32, 32)] autorelease];
2274 [folder setImage:[UIImage applicationImageNamed:@"folder.png"]];
2276 [self addSubview:folder];
2277 [self addSubview:name_];
2278 [self addSubview:count_];
2280 [self _setSelected:0];
2282 CGColorSpaceRelease(space);
2289 - (void) setSection:(Section *)section {
2290 if (section == nil) {
2291 [name_ setText:@"All Packages"];
2292 [count_ setText:nil];
2294 [name_ setText:[section name]];
2295 [count_ setText:[NSString stringWithFormat:@"%d", [section count]]];
2299 - (void) _setSelected:(float)fraction {
2300 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
2302 CGColor black(space,
2303 interpolate(0.0, 1.0, fraction),
2304 interpolate(0.0, 1.0, fraction),
2305 interpolate(0.0, 1.0, fraction),
2308 [name_ setColor:black];
2310 CGColorSpaceRelease(space);
2313 - (void) setSelected:(BOOL)selected {
2314 [self _setSelected:(selected ? 1.0 : 0.0)];
2315 [super setSelected:selected];
2318 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
2320 [self _setSelected:(selected ? 1.0 : 0.0)];
2321 [super setSelected:selected withFade:fade];
2324 - (void) _setSelectionFadeFraction:(float)fraction {
2325 [self _setSelected:fraction];
2326 [super _setSelectionFadeFraction:fraction];
2331 /* Install View {{{ */
2332 @interface InstallView : ResetView <
2333 PackageTableDelegate
2337 PackageTable *table_;
2341 NSMutableArray *packages_;
2346 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
2348 - (int) numberOfRowsInTable:(UITable *)table;
2349 - (float) table:(UITable *)table heightForRow:(int)row;
2350 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing;
2351 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row;
2352 - (void) tableRowSelected:(NSNotification *)notification;
2354 - (void) packageTable:(id)table packageSelected:(Package *)package;
2356 - (id) initWithFrame:(CGRect)frame;
2357 - (void) setPackages:(NSArray *)packages;
2358 - (void) setDelegate:(id)delegate;
2361 @implementation InstallView
2364 [packages_ release];
2365 if (sections_ != nil)
2366 [sections_ release];
2373 if (section_ != nil)
2375 if (package_ != nil)
2380 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2382 [[view_ package] install];
2383 [delegate_ resolve];
2384 [delegate_ perform];
2388 - (int) numberOfRowsInTable:(UITable *)table {
2389 return [sections_ count] + 1;
2392 - (float) table:(UITable *)table heightForRow:(int)row {
2396 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2398 reusing = [[[SectionCell alloc] init] autorelease];
2400 [(SectionCell *)reusing setSection:nil];
2402 [(SectionCell *)reusing setSection:[sections_ objectAtIndex:(row - 1)]];
2406 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
2410 - (void) tableRowSelected:(NSNotification *)notification {
2411 int row = [[notification object] selectedRow];
2413 if (row == INT_MAX) {
2420 _assert(section_ == nil);
2421 _assert(table_ == nil);
2429 name = @"All Packages";
2431 section = [sections_ objectAtIndex:(row - 1)];
2432 name = [section name];
2433 section_ = [name retain];
2436 table_ = [[PackageTable alloc] initWithFrame:[transition_ bounds] versioner:@selector(latest)];
2437 [table_ setDelegate:self];
2438 [table_ setPackages:(section == nil ? packages_ : [section packages])];
2440 [self pushView:table_ withTitle:name backButtonTitle:@"Packages" rightButton:nil];
2444 - (void) packageTable:(id)table packageSelected:(Package *)package {
2445 if (package == nil) {
2452 _assert(package_ == nil);
2453 _assert(view_ == nil);
2455 package_ = [[package name] retain];
2457 view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]];
2458 [view_ setDelegate:delegate_];
2460 [view_ setPackage:package];
2462 [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:@"Install"];
2466 - (id) initWithFrame:(CGRect)frame {
2467 if ((self = [super initWithFrame:frame]) != nil) {
2468 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
2470 list_ = [[UITable alloc] initWithFrame:[transition_ bounds]];
2471 [self pushView:list_ withTitle:@"Install" backButtonTitle:@"Sections" rightButton:nil];
2473 UITableColumn *column = [[[UITableColumn alloc]
2474 initWithTitle:@"Name"
2476 width:frame.size.width
2479 [list_ setDataSource:self];
2480 [list_ setSeparatorStyle:1];
2481 [list_ addTableColumn:column];
2482 [list_ setDelegate:self];
2483 [list_ setReusesTableCells:YES];
2485 [transition_ transition:0 toView:list_];
2489 - (void) setPackages:(NSArray *)packages {
2490 [packages_ removeAllObjects];
2492 for (size_t i(0); i != [packages count]; ++i) {
2493 Package *package([packages objectAtIndex:i]);
2494 if ([package installed] == nil)
2495 [packages_ addObject:package];
2498 [packages_ sortUsingSelector:@selector(compareBySectionAndName:)];
2499 NSMutableArray *sections = [NSMutableArray arrayWithCapacity:16];
2501 Section *nsection = nil;
2502 Package *npackage = nil;
2504 Section *section = nil;
2505 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
2506 Package *package = [packages_ objectAtIndex:offset];
2507 NSString *name = [package section];
2509 if (section == nil || ![[section name] isEqual:name]) {
2510 section = [[[Section alloc] initWithName:name row:offset] autorelease];
2512 if ([name isEqualToString:section_])
2514 [sections addObject:section];
2517 if ([[package name] isEqualToString:package_])
2519 [section addPackage:package];
2522 if (sections_ != nil)
2523 [sections_ release];
2524 sections_ = [sections retain];
2526 [packages_ sortUsingSelector:@selector(compareByName:)];
2532 if (npackage != nil)
2533 [view_ setPackage:npackage];
2534 else if (package_ != nil)
2537 if (nsection != nil)
2538 [table_ setPackages:[nsection packages]];
2539 else if (section_ != nil)
2542 [self popViews:views];
2546 - (void) setDelegate:(id)delegate {
2548 [view_ setDelegate:delegate];
2549 [super setDelegate:delegate];
2554 /* Changes View {{{ */
2555 @interface ChangesView : ResetView <
2556 PackageTableDelegate
2558 UISectionList *list_;
2559 NSMutableArray *packages_;
2560 NSMutableArray *sections_;
2568 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
2570 - (int) numberOfSectionsInSectionList:(UISectionList *)list;
2571 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section;
2572 - (int) sectionList:(UISectionList *)list rowForSection:(int)section;
2574 - (int) numberOfRowsInTable:(UITable *)table;
2575 - (float) table:(UITable *)table heightForRow:(int)row;
2576 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing;
2577 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row;
2578 - (void) tableRowSelected:(NSNotification *)notification;
2580 - (id) initWithFrame:(CGRect)frame;
2581 - (void) setPackages:(NSArray *)packages;
2582 - (void) _resetView;
2585 - (void) setDelegate:(id)delegate;
2588 @implementation ChangesView
2592 [packages_ release];
2593 [sections_ release];
2596 if (package_ != nil)
2601 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
2602 return [sections_ count];
2605 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
2606 return [[sections_ objectAtIndex:section] name];
2609 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
2610 return [[sections_ objectAtIndex:section] row];
2613 - (int) numberOfRowsInTable:(UITable *)table {
2614 return [packages_ count];
2617 - (float) table:(UITable *)table heightForRow:(int)row {
2621 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2623 reusing = [[[PackageCell alloc] initWithVersioner:NULL] autorelease];
2624 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
2628 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
2632 - (void) tableRowSelected:(NSNotification *)notification {
2633 int row = [[notification object] selectedRow];
2634 [self packageTable:self packageSelected:(row == INT_MAX ? nil : [packages_ objectAtIndex:row])];
2637 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2640 [[view_ package] install];
2641 [delegate_ resolve];
2642 [delegate_ perform];
2646 [delegate_ upgrade];
2651 - (void) packageTable:(id)table packageSelected:(Package *)package {
2652 if (package == nil) {
2659 _assert(package_ == nil);
2660 _assert(view_ == nil);
2662 package_ = [[package name] retain];
2664 view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]];
2665 [view_ setDelegate:delegate_];
2667 [view_ setPackage:package];
2669 [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:(
2670 [package upgradable] ? @"Upgrade" : @"Install"
2675 - (id) initWithFrame:(CGRect)frame {
2676 if ((self = [super initWithFrame:frame]) != nil) {
2677 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
2678 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
2680 list_ = [[UISectionList alloc] initWithFrame:[transition_ bounds] showSectionIndex:NO];
2681 [list_ setShouldHideHeaderInShortLists:NO];
2682 [list_ setDataSource:self];
2683 //[list_ setSectionListStyle:1];
2685 UITableColumn *column = [[[UITableColumn alloc]
2686 initWithTitle:@"Name"
2688 width:frame.size.width
2691 UITable *table = [list_ table];
2692 [table setSeparatorStyle:1];
2693 [table addTableColumn:column];
2694 [table setDelegate:self];
2695 [table setReusesTableCells:YES];
2697 [self pushView:list_ withTitle:@"Changes" backButtonTitle:nil rightButton:nil];
2701 - (void) setPackages:(NSArray *)packages {
2702 [packages_ removeAllObjects];
2703 for (size_t i(0); i != [packages count]; ++i) {
2704 Package *package([packages objectAtIndex:i]);
2705 if ([package installed] == nil || [package upgradable])
2706 [packages_ addObject:package];
2709 [packages_ sortUsingSelector:@selector(compareForChanges:)];
2711 [sections_ removeAllObjects];
2713 Section *upgradable = [[[Section alloc] initWithName:@"Available Upgrades" row:0] autorelease];
2714 Section *section = nil;
2717 Package *npackage = nil;
2718 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
2719 Package *package = [packages_ objectAtIndex:offset];
2720 if ([[package name] isEqualToString:package_])
2723 if ([package upgradable])
2724 [upgradable addPackage:package];
2726 NSDate *seen = [package seen];
2728 CFLocaleRef locale = CFLocaleCopyCurrent();
2729 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
2730 CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen);
2732 NSString *name = (NSString *) formatted;
2734 if (section == nil || ![[section name] isEqual:name]) {
2735 section = [[[Section alloc] initWithName:name row:offset] autorelease];
2736 [sections_ addObject:section];
2739 [section addPackage:package];
2741 CFRelease(formatter);
2742 CFRelease(formatted);
2747 count_ = [[upgradable packages] count];
2749 [sections_ insertObject:upgradable atIndex:0];
2753 if (npackage != nil)
2754 [view_ setPackage:npackage];
2755 else if (package_ != nil)
2762 - (void) _resetView {
2763 if ([views_ count] == 1)
2764 [navbar_ showButtonsWithLeftTitle:(count_ == 0 ? nil : @"Upgrade All") rightTitle:nil];
2771 - (void) setDelegate:(id)delegate {
2773 [view_ setDelegate:delegate];
2774 [super setDelegate:delegate];
2779 /* Manage View {{{ */
2780 @interface ManageView : ResetView <
2781 PackageTableDelegate
2783 PackageTable *table_;
2790 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
2792 - (void) packageTable:(id)table packageSelected:(Package *)package;
2794 - (id) initWithFrame:(CGRect)frame;
2795 - (void) setPackages:(NSArray *)packages;
2797 - (void) setDelegate:(id)delegate;
2800 @implementation ManageView
2806 if (package_ != nil)
2811 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2813 [[view_ package] remove];
2814 [delegate_ resolve];
2815 [delegate_ perform];
2819 - (void) packageTable:(id)table packageSelected:(Package *)package {
2820 if (package == nil) {
2827 _assert(package_ == nil);
2828 _assert(view_ == nil);
2830 package_ = [[package name] retain];
2832 view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]];
2833 [view_ setDelegate:delegate_];
2835 [view_ setPackage:package];
2837 [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:@"Uninstall"];
2841 - (id) initWithFrame:(CGRect)frame {
2842 if ((self = [super initWithFrame:frame]) != nil) {
2843 table_ = [[PackageTable alloc] initWithFrame:[transition_ bounds] versioner:@selector(latest)];
2844 [table_ setDelegate:self];
2846 [self pushView:table_ withTitle:@"Uninstall" backButtonTitle:@"Packages" rightButton:nil];
2850 - (void) setPackages:(NSArray *)packages {
2851 NSMutableArray *local = [NSMutableArray arrayWithCapacity:16];
2852 for (size_t i(0); i != [packages count]; ++i) {
2853 Package *package([packages objectAtIndex:i]);
2854 if ([package installed] != nil)
2855 [local addObject:package];
2858 [local sortUsingSelector:@selector(compareByName:)];
2860 Package *npackage = nil;
2861 for (size_t offset = 0, count = [local count]; offset != count; ++offset) {
2862 Package *package = [local objectAtIndex:offset];
2863 if ([[package name] isEqualToString:package_])
2867 [table_ setPackages:local];
2869 if (npackage != nil)
2870 [view_ setPackage:npackage];
2871 else if (package_ != nil)
2877 - (void) setDelegate:(id)delegate {
2879 [view_ setDelegate:delegate];
2880 [super setDelegate:delegate];
2885 /* Search View {{{ */
2886 @protocol SearchViewDelegate
2887 - (void) showKeyboard:(BOOL)show;
2890 @interface SearchView : ResetView <
2891 PackageTableDelegate
2893 NSMutableArray *packages_;
2895 UISearchField *field_;
2896 PackageTable *table_;
2903 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
2904 - (void) packageTable:(id)table packageSelected:(Package *)package;
2906 - (void) textFieldDidBecomeFirstResponder:(UITextField *)field;
2907 - (void) textFieldDidResignFirstResponder:(UITextField *)field;
2909 - (void) keyboardInputChanged:(UIFieldEditor *)editor;
2910 - (BOOL) keyboardInput:(id)input shouldInsertText:(NSString *)text isMarkedText:(int)marked;
2912 - (id) initWithFrame:(CGRect)frame;
2913 - (void) setPackages:(NSArray *)packages;
2915 - (void) setDelegate:(id)delegate;
2916 - (void) resetPackage:(Package *)package;
2917 - (void) searchPackages;
2921 @implementation SearchView
2924 [packages_ release];
2925 [accessory_ release];
2930 if (package_ != nil)
2935 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2937 Package *package = [view_ package];
2938 if ([package installed] == nil)
2942 [delegate_ resolve];
2943 [delegate_ perform];
2947 - (void) packageTable:(id)table packageSelected:(Package *)package {
2948 if (package == nil) {
2949 [navbar_ setAccessoryView:accessory_ animate:(resetting_ ? NO : YES) goingBack:YES];
2957 [navbar_ setAccessoryView:nil animate:YES goingBack:NO];
2959 _assert(package_ == nil);
2960 _assert(view_ == nil);
2962 package_ = [[package name] retain];
2964 view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]];
2965 [view_ setDelegate:delegate_];
2967 [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:nil];
2968 [self resetPackage:package];
2972 - (void) textFieldDidBecomeFirstResponder:(UITextField *)field {
2973 [delegate_ showKeyboard:YES];
2974 [table_ setEnabled:NO];
2976 /*CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
2977 CGColor dimmed(alpha, 0, 0, 0, 0.5);
2978 [editor_ setBackgroundColor:dimmed];
2979 CGColorSpaceRelease(space);*/
2982 - (void) textFieldDidResignFirstResponder:(UITextField *)field {
2983 [table_ setEnabled:YES];
2984 [delegate_ showKeyboard:NO];
2987 - (void) keyboardInputChanged:(UIFieldEditor *)editor {
2988 NSString *text([field_ text]);
2989 [field_ setClearButtonStyle:(text == nil || [text length] == 0 ? 0 : 2)];
2992 - (BOOL) keyboardInput:(id)input shouldInsertText:(NSString *)text isMarkedText:(int)marked {
2993 if ([text length] != 1 || [text characterAtIndex:0] != '\n')
2996 [self searchPackages];
2997 [field_ resignFirstResponder];
3001 - (id) initWithFrame:(CGRect)frame {
3002 if ((self = [super initWithFrame:frame]) != nil) {
3003 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
3005 table_ = [[PackageTable alloc] initWithFrame:[transition_ bounds] versioner:@selector(latest)];
3006 [table_ setDelegate:self];
3008 CGRect area = [self bounds];
3011 area.size.width -= 12;
3012 area.size.height = [UISearchField defaultHeight];
3014 field_ = [[UISearchField alloc] initWithFrame:area];
3016 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
3017 [field_ setFont:font];
3020 [field_ setPlaceholder:@"Package Names & Descriptions"];
3021 [field_ setPaddingTop:5];
3022 [field_ setDelegate:self];
3024 UITextTraits *traits = [field_ textTraits];
3025 [traits setEditingDelegate:self];
3026 [traits setReturnKeyType:6];
3028 accessory_ = [[UIView alloc] initWithFrame:CGRectMake(6, 6, area.size.width, area.size.height + 30)];
3029 [accessory_ addSubview:field_];
3031 [navbar_ setAccessoryView:accessory_];
3032 [self pushView:table_ withTitle:nil backButtonTitle:@"Search" rightButton:nil];
3034 /* XXX: for the love of god just fix this */
3035 [navbar_ removeFromSuperview];
3036 [reload_ removeFromSuperview];
3037 [configure_ removeFromSuperview];
3038 [self addSubview:navbar_];
3039 [self addSubview:reload_];
3040 [self addSubview:configure_];
3044 - (void) setPackages:(NSArray *)packages {
3045 [packages_ removeAllObjects];
3046 [packages_ addObjectsFromArray:packages];
3047 [packages_ sortUsingSelector:@selector(compareByName:)];
3049 Package *npackage = nil;
3050 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
3051 Package *package = [packages_ objectAtIndex:offset];
3052 if ([[package name] isEqualToString:package_])
3056 [self searchPackages];
3058 if (npackage != nil)
3059 [self resetPackage:npackage];
3060 else if (package_ != nil)
3066 - (void) setDelegate:(id)delegate {
3068 [view_ setDelegate:delegate];
3069 [super setDelegate:delegate];
3072 - (void) resetPackage:(Package *)package {
3073 [view_ setPackage:package];
3074 NSString *right = [package installed] == nil ? @"Install" : @"Uninstall";
3075 [navbar_ showButtonsWithLeftTitle:nil rightTitle:right];
3078 - (void) searchPackages {
3079 NSString *text([field_ text]);
3081 NSMutableArray *packages([NSMutableArray arrayWithCapacity:16]);
3083 for (size_t offset(0), count([packages_ count]); offset != count; ++offset) {
3084 Package *package = [packages_ objectAtIndex:offset];
3085 if ([package matches:text])
3086 [packages addObject:package];
3089 [table_ setPackages:packages];
3090 [[table_ table] scrollPointVisibleAtTopLeft:CGPointMake(0, 0) animated:NO];
3096 @interface Cydia : UIApplication <
3097 ConfirmationViewDelegate,
3098 ProgressViewDelegate,
3104 UITransitionView *transition_;
3105 UIButtonBar *buttonbar_;
3107 ConfirmationView *confirm_;
3109 Database *database_;
3110 ProgressView *progress_;
3113 UINavigationBar *navbar_;
3114 UIScroller *scroller_;
3115 UIWebView *webview_;
3117 UIProgressIndicator *indicator_;
3119 InstallView *install_;
3120 ChangesView *changes_;
3121 ManageView *manage_;
3122 SearchView *search_;
3127 UIKeyboard *keyboard_;
3131 - (void) reloadData:(BOOL)reset;
3142 - (void) progressViewIsComplete:(ProgressView *)progress;
3144 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
3145 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
3146 - (void) buttonBarItemTapped:(id)sender;
3148 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old;
3150 - (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame;
3152 - (void) applicationWillSuspend;
3153 - (void) applicationDidFinishLaunching:(id)unused;
3156 @implementation Cydia
3159 NSMutableURLRequest *request = [NSMutableURLRequest
3161 cachePolicy:NSURLRequestReloadIgnoringCacheData
3162 timeoutInterval:30.0
3165 [request addValue:[NSString stringWithCString:Machine_] forHTTPHeaderField:@"X-Machine"];
3166 [request addValue:[NSString stringWithCString:SerialNumber_] forHTTPHeaderField:@"X-Serial-Number"];
3168 [webview_ loadRequest:request];
3171 - (void) reloadData:(BOOL)reset {
3172 [database_ reloadData];
3176 if (Packages_ == nil) {
3177 Packages_ = [[NSMutableDictionary alloc] initWithCapacity:count];
3178 [Metadata_ setObject:Packages_ forKey:@"Packages"];
3181 now_ = [NSDate date];
3183 NSMutableArray *packages = [NSMutableArray arrayWithCapacity:count];
3184 for (pkgCache::PkgIterator iterator = [database_ cache]->PkgBegin(); !iterator.end(); ++iterator)
3185 if (Package *package = [Package packageWithIterator:iterator database:database_])
3186 [packages addObject:package];
3188 [install_ setPackages:packages];
3189 [changes_ setPackages:packages];
3190 [manage_ setPackages:packages];
3191 [search_ setPackages:packages];
3193 if (size_t count = [changes_ count]) {
3194 NSString *badge([[NSNumber numberWithInt:count] stringValue]);
3195 [buttonbar_ setBadgeValue:badge forButton:3];
3196 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
3197 [buttonbar_ setBadgeAnimated:YES forButton:3];
3198 [self setApplicationBadge:badge];
3200 [buttonbar_ setBadgeValue:nil forButton:3];
3201 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
3202 [buttonbar_ setBadgeAnimated:NO forButton:3];
3203 [self removeApplicationBadge];
3206 _assert([Metadata_ writeToFile:@"/var/lib/cydia/metadata.plist" atomically:YES] == YES);
3209 - (void) setPrompt {
3210 [navbar_ setPrompt:[NSString stringWithFormat:@"Last Updated: %@", GetLastUpdate()]];
3214 pkgProblemResolver *resolver = [database_ resolver];
3216 resolver->InstallProtect();
3217 if (!resolver->Resolve(true))
3222 [database_ prepare];
3223 confirm_ = [[ConfirmationView alloc] initWithView:underlay_ database:database_ delegate:self];
3227 [database_ upgrade];
3232 [self reloadData:NO];
3238 [overlay_ removeFromSuperview];
3242 detachNewThreadSelector:@selector(perform)
3249 - (void) bootstrap_ {
3251 [database_ upgrade];
3252 [database_ prepare];
3253 [database_ perform];
3256 - (void) bootstrap {
3258 detachNewThreadSelector:@selector(bootstrap_)
3261 title:@"Bootstrap Install..."
3267 detachNewThreadSelector:@selector(update)
3270 title:@"Refreshing Sources..."
3274 - (void) progressViewIsComplete:(ProgressView *)progress {
3275 [self reloadData:YES];
3277 if (confirm_ != nil) {
3278 [underlay_ addSubview:overlay_];
3279 [confirm_ removeFromSuperview];
3285 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
3292 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
3293 initWithTitle:@"About Cydia Packager"
3294 buttons:[NSArray arrayWithObjects:@"Close", nil]
3295 defaultButtonIndex:0
3301 @"Copyright (C) 2008\n"
3302 "Jay Freeman (saurik)\n"
3303 "saurik@saurik.com\n"
3304 "http://www.saurik.com/\n"
3307 "http://www.theokorigroup.com/\n"
3309 "College of Creative Studies,\n"
3310 "University of California,\n"
3312 "http://www.ccs.ucsb.edu/\n"
3315 "bad_, BHSPitMonkey, cash, Cobra,\n"
3316 "core, Corona, crashx, cromas,\n"
3317 "Darken, dtzWill, Erica, francis,\n"
3318 "Godores, jerry, Kingstone, lounger,\n"
3319 "mbranes, rockabilly, tman, Wbiggs"
3322 [sheet presentSheetFromButtonBar:buttonbar_];
3327 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
3331 - (void) buttonBarItemTapped:(id)sender {
3333 unsigned tag = [sender tag];
3336 case 1: view = featured_; break;
3337 case 2: view = install_; break;
3338 case 3: view = changes_; break;
3339 case 4: view = manage_; break;
3340 case 5: view = search_; break;
3346 if ([view respondsToSelector:@selector(resetView:)])
3347 [(id) view resetView:(tag == tag_ ? NO : YES)];
3349 [transition_ transition:0 toView:view];
3352 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old {
3353 [scroller_ setContentSize:frame.size];
3354 [indicator_ stopAnimation];
3357 - (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame {
3358 [navbar_ setPrompt:title];
3361 - (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame {
3362 [navbar_ setPrompt:@"Loading..."];
3363 [indicator_ startAnimation];
3366 - (void) applicationWillSuspend {
3368 system("launchctl stop com.apple.SpringBoard");
3369 [super applicationWillSuspend];
3372 - (void) applicationDidFinishLaunching:(id)unused {
3373 _assert(pkgInitConfig(*_config));
3374 _assert(pkgInitSystem(*_config, _system));
3380 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
3381 window_ = [[UIWindow alloc] initWithContentRect:screenrect];
3383 [window_ orderFront: self];
3384 [window_ makeKey: self];
3385 [window_ _setHidden: NO];
3387 progress_ = [[ProgressView alloc] initWithFrame:[window_ bounds] delegate:self];
3388 [window_ setContentView:progress_];
3390 underlay_ = [[UIView alloc] initWithFrame:[progress_ bounds]];
3391 [progress_ setContentView:underlay_];
3393 overlay_ = [[UIView alloc] initWithFrame:[underlay_ bounds]];
3396 [underlay_ addSubview:overlay_];
3398 transition_ = [[UITransitionView alloc] initWithFrame:CGRectMake(
3399 0, 0, screenrect.size.width, screenrect.size.height - 48
3402 [overlay_ addSubview:transition_];
3404 featured_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
3406 CGSize navsize = [UINavigationBar defaultSizeWithPrompt];
3407 CGRect navrect = {{0, 0}, navsize};
3409 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
3410 [featured_ addSubview:navbar_];
3412 [navbar_ setBarStyle:1];
3413 [navbar_ setDelegate:self];
3415 [navbar_ showButtonsWithLeftTitle:@"About" rightTitle:@"Reload"];
3417 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Featured"] autorelease];
3418 [navbar_ pushNavigationItem:navitem];
3420 struct CGRect subbounds = [featured_ bounds];
3421 subbounds.origin.y += navsize.height;
3422 subbounds.size.height -= navsize.height;
3424 UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:subbounds] autorelease];
3425 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
3426 [featured_ addSubview:pinstripe];
3428 scroller_ = [[UIScroller alloc] initWithFrame:subbounds];
3429 [featured_ addSubview:scroller_];
3431 [scroller_ setScrollingEnabled:YES];
3432 [scroller_ setAdjustForContentSizeChange:YES];
3433 [scroller_ setClipsSubviews:YES];
3434 [scroller_ setAllowsRubberBanding:YES];
3435 [scroller_ setScrollDecelerationFactor:0.99];
3436 [scroller_ setDelegate:self];
3438 CGRect webrect = [scroller_ bounds];
3439 webrect.size.height = 0;
3441 webview_ = [[UIWebView alloc] initWithFrame:webrect];
3442 [scroller_ addSubview:webview_];
3444 [webview_ setTilingEnabled:YES];
3445 [webview_ setTileSize:CGSizeMake(screenrect.size.width, 500)];
3446 [webview_ setAutoresizes:YES];
3447 [webview_ setDelegate:self];
3449 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:2];
3450 indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(87, 45, indsize.width, indsize.height)];
3451 [indicator_ setStyle:2];
3452 [featured_ addSubview:indicator_];
3454 NSArray *buttonitems = [NSArray arrayWithObjects:
3455 [NSDictionary dictionaryWithObjectsAndKeys:
3456 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3457 @"featured-up.png", kUIButtonBarButtonInfo,
3458 @"featured-dn.png", kUIButtonBarButtonSelectedInfo,
3459 [NSNumber numberWithInt:1], kUIButtonBarButtonTag,
3460 self, kUIButtonBarButtonTarget,
3461 @"Featured", kUIButtonBarButtonTitle,
3462 @"0", kUIButtonBarButtonType,
3465 [NSDictionary dictionaryWithObjectsAndKeys:
3466 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3467 @"install-up.png", kUIButtonBarButtonInfo,
3468 @"install-dn.png", kUIButtonBarButtonSelectedInfo,
3469 [NSNumber numberWithInt:2], kUIButtonBarButtonTag,
3470 self, kUIButtonBarButtonTarget,
3471 @"Install", kUIButtonBarButtonTitle,
3472 @"0", kUIButtonBarButtonType,
3475 [NSDictionary dictionaryWithObjectsAndKeys:
3476 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3477 @"changes-up.png", kUIButtonBarButtonInfo,
3478 @"changes-dn.png", kUIButtonBarButtonSelectedInfo,
3479 [NSNumber numberWithInt:3], kUIButtonBarButtonTag,
3480 self, kUIButtonBarButtonTarget,
3481 @"Changes", kUIButtonBarButtonTitle,
3482 @"0", kUIButtonBarButtonType,
3485 [NSDictionary dictionaryWithObjectsAndKeys:
3486 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3487 @"manage-up.png", kUIButtonBarButtonInfo,
3488 @"manage-dn.png", kUIButtonBarButtonSelectedInfo,
3489 [NSNumber numberWithInt:4], kUIButtonBarButtonTag,
3490 self, kUIButtonBarButtonTarget,
3491 @"Uninstall", kUIButtonBarButtonTitle,
3492 @"0", kUIButtonBarButtonType,
3495 [NSDictionary dictionaryWithObjectsAndKeys:
3496 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3497 @"search-up.png", kUIButtonBarButtonInfo,
3498 @"search-dn.png", kUIButtonBarButtonSelectedInfo,
3499 [NSNumber numberWithInt:5], kUIButtonBarButtonTag,
3500 self, kUIButtonBarButtonTarget,
3501 @"Search", kUIButtonBarButtonTitle,
3502 @"0", kUIButtonBarButtonType,
3506 buttonbar_ = [[UIButtonBar alloc]
3508 withFrame:CGRectMake(
3509 0, screenrect.size.height - 48,
3510 screenrect.size.width, 48
3512 withItemList:buttonitems
3515 [buttonbar_ setDelegate:self];
3516 [buttonbar_ setBarStyle:1];
3517 [buttonbar_ setButtonBarTrackingMode:2];
3519 int buttons[5] = {1, 2, 3, 4, 5};
3520 [buttonbar_ registerButtonGroup:0 withButtons:buttons withCount:5];
3521 [buttonbar_ showButtonGroup:0 withDuration:0];
3523 for (int i = 0; i != 5; ++i)
3524 [[buttonbar_ viewWithTag:(i + 1)] setFrame:CGRectMake(
3525 i * 64 + 2, 1, 60, 48
3528 [buttonbar_ showSelectionForButton:1];
3529 [transition_ transition:0 toView:featured_];
3531 [overlay_ addSubview:buttonbar_];
3533 [UIKeyboard initImplementationNow];
3535 CGRect edtrect = [overlay_ bounds];
3536 edtrect.origin.y += navsize.height;
3537 edtrect.size.height -= navsize.height;
3539 CGSize keysize = [UIKeyboard defaultSize];
3540 CGRect keyrect = {{0, [overlay_ bounds].size.height - keysize.height}, keysize};
3541 keyboard_ = [[UIKeyboard alloc] initWithFrame:keyrect];
3543 database_ = [[Database alloc] init];
3544 [database_ setDelegate:progress_];
3546 install_ = [[InstallView alloc] initWithFrame:[transition_ bounds]];
3547 [install_ setDelegate:self];
3549 changes_ = [[ChangesView alloc] initWithFrame:[transition_ bounds]];
3550 [changes_ setDelegate:self];
3552 manage_ = [[ManageView alloc] initWithFrame:[transition_ bounds]];
3553 [manage_ setDelegate:self];
3555 search_ = [[SearchView alloc] initWithFrame:[transition_ bounds]];
3556 [search_ setDelegate:self];
3558 [self reloadData:NO];
3560 Package *package([database_ packageWithName:@"cydia"]);
3561 NSString *application = package == nil ? @"Cydia" : [NSString stringWithFormat:@"Cydia/%@", [package installed]];
3563 WebView *webview = [webview_ webView];
3564 [webview setApplicationNameForUserAgent:application];
3565 [webview setFrameLoadDelegate:self];
3567 url_ = [NSURL URLWithString:@"http://cydia.saurik.com/"];
3570 [progress_ resetView];
3576 - (void) showKeyboard:(BOOL)show {
3578 [overlay_ addSubview:keyboard_];
3580 [keyboard_ removeFromSuperview];
3585 void AddPreferences(NSString *plist) {
3586 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
3588 NSMutableDictionary *settings = [[[NSMutableDictionary alloc] initWithContentsOfFile:plist] autorelease];
3589 _assert(settings != NULL);
3590 NSMutableArray *items = [settings objectForKey:@"items"];
3594 for (size_t i(0); i != [items count]; ++i) {
3595 NSMutableDictionary *item([items objectAtIndex:i]);
3596 NSString *label = [item objectForKey:@"label"];
3597 if (label != nil && [label isEqualToString:@"Cydia"]) {
3604 for (size_t i(0); i != [items count]; ++i) {
3605 NSDictionary *item([items objectAtIndex:i]);
3606 NSString *label = [item objectForKey:@"label"];
3607 if (label != nil && [label isEqualToString:@"General"]) {
3608 [items insertObject:[NSDictionary dictionaryWithObjectsAndKeys:
3609 @"CydiaSettings", @"bundle",
3610 @"PSLinkCell", @"cell",
3611 [NSNumber numberWithBool:YES], @"hasIcon",
3612 [NSNumber numberWithBool:YES], @"isController",
3614 nil] atIndex:(i + 1)];
3620 _assert([settings writeToFile:plist atomically:YES] == YES);
3627 id Alloc_(id self, SEL selector) {
3628 id object = alloc_(self, selector);
3629 fprintf(stderr, "[%s]A-%p\n", self->isa->name, object);
3633 int main(int argc, char *argv[]) {
3635 memset(nl, 0, sizeof(nl));
3636 nl[0].n_un.n_name = "_useMDNSResponder";
3637 nlist("/usr/lib/libc.dylib", nl);
3638 if (nl[0].n_type != N_UNDF)
3639 *(int *) nl[0].n_value = 0;
3641 bootstrap_ = argc > 1 && strcmp(argv[1], "--bootstrap") == 0;
3646 /*Method alloc = class_getClassMethod([NSObject class], @selector(alloc));
3647 alloc_ = alloc->method_imp;
3648 alloc->method_imp = (IMP) &Alloc_;*/
3650 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
3653 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
3654 char *machine = new char[size];
3655 sysctlbyname("hw.machine", machine, &size, NULL, 0);
3658 if (CFMutableDictionaryRef dict = IOServiceMatching("IOPlatformExpertDevice"))
3659 if (io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, dict)) {
3660 if (CFTypeRef serial = IORegistryEntryCreateCFProperty(service, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0)) {
3661 SerialNumber_ = strdup(CFStringGetCStringPtr((CFStringRef) serial, CFStringGetSystemEncoding()));
3665 IOObjectRelease(service);
3668 /*AddPreferences(@"/Applications/Preferences.app/Settings-iPhone.plist");
3669 AddPreferences(@"/Applications/Preferences.app/Settings-iPod.plist");*/
3671 if ((Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"]) == NULL)
3672 Metadata_ = [[NSMutableDictionary alloc] initWithCapacity:2];
3674 Packages_ = [Metadata_ objectForKey:@"Packages"];
3676 system("dpkg --configure -a");
3678 UIApplicationMain(argc, argv, [Cydia class]);