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>
27 /* Extension Keywords {{{ */
28 #define _trace() fprintf(stderr, "_trace()@%s:%u[%s]\n", __FILE__, __LINE__, __FUNCTION__)
30 #define _assert(test) do \
32 fprintf(stderr, "_assert(%d:%s)@%s:%u[%s]\n", errno, #test, __FILE__, __LINE__, __FUNCTION__); \
39 - (void) setApplicationNameForUserAgent:(NSString *)applicationName;
42 static const int PulseInterval_ = 50000;
43 const char *Machine_ = NULL;
44 const char *SerialNumber_ = NULL;
46 @interface NSString (CydiaBypass)
47 - (NSString *) stringByAddingPercentEscapes;
50 @protocol ProgressDelegate
51 - (void) setError:(NSString *)error;
52 - (void) setTitle:(NSString *)title;
53 - (void) setPercent:(float)percent;
54 - (void) addOutput:(NSString *)output;
57 NSString *SizeString(double size) {
64 static const char *powers_[] = {"B", "kB", "MB", "GB"};
66 return [NSString stringWithFormat:@"%.1f%s", size, powers_[power]];
69 /* Status Delegation {{{ */
71 public pkgAcquireStatus
82 void setDelegate(id delegate) {
86 virtual bool MediaChange(std::string media, std::string drive) {
90 virtual void IMSHit(pkgAcquire::ItemDesc &item) {
93 virtual void Fetch(pkgAcquire::ItemDesc &item) {
94 [delegate_ setTitle:[NSString stringWithCString:("Downloading " + item.ShortDesc).c_str()]];
97 virtual void Done(pkgAcquire::ItemDesc &item) {
100 virtual void Fail(pkgAcquire::ItemDesc &item) {
101 [delegate_ performSelectorOnMainThread:@selector(setStatusFail) withObject:nil waitUntilDone:YES];
104 virtual bool Pulse(pkgAcquire *Owner) {
105 bool value = pkgAcquireStatus::Pulse(Owner);
108 double(CurrentBytes + CurrentItems) /
109 double(TotalBytes + TotalItems)
112 [delegate_ setPercent:percent];
116 virtual void Start() {
119 virtual void Stop() {
123 /* Progress Delegation {{{ */
131 virtual void Update() {
132 [delegate_ setTitle:[NSString stringWithCString:Op.c_str()]];
133 [delegate_ setPercent:(Percent / 100)];
142 void setDelegate(id delegate) {
143 delegate_ = delegate;
146 virtual void Done() {
147 [delegate_ setPercent:1];
152 /* External Constants {{{ */
153 extern NSString *kUIButtonBarButtonAction;
154 extern NSString *kUIButtonBarButtonInfo;
155 extern NSString *kUIButtonBarButtonInfoOffset;
156 extern NSString *kUIButtonBarButtonSelectedInfo;
157 extern NSString *kUIButtonBarButtonStyle;
158 extern NSString *kUIButtonBarButtonTag;
159 extern NSString *kUIButtonBarButtonTarget;
160 extern NSString *kUIButtonBarButtonTitle;
161 extern NSString *kUIButtonBarButtonTitleVerticalHeight;
162 extern NSString *kUIButtonBarButtonTitleWidth;
163 extern NSString *kUIButtonBarButtonType;
165 /* Mime Addresses {{{ */
166 @interface Address : NSObject {
174 - (NSString *) email;
176 + (Address *) addressWithString:(NSString *)string;
177 - (Address *) initWithString:(NSString *)string;
180 @implementation Address
189 - (NSString *) name {
193 - (NSString *) email {
197 + (Address *) addressWithString:(NSString *)string {
198 return [[[Address alloc] initWithString:string] autorelease];
201 - (Address *) initWithString:(NSString *)string {
202 if ((self = [super init]) != nil) {
205 pcre *code = pcre_compile("^\"?(.*)\"? <([^>]*)>$", 0, &error, &offset, NULL);
208 fprintf(stderr, "%d:%s\n", offset, error);
212 pcre_extra *study = NULL;
214 pcre_fullinfo(code, study, PCRE_INFO_CAPTURECOUNT, &capture);
215 int matches[(capture + 1) * 3];
217 size_t size = [string length];
218 const char *data = [string UTF8String];
220 if (pcre_exec(code, study, data, size, 0, 0, matches, sizeof(matches) / sizeof(matches[0])) >= 0) {
221 name_ = [[NSString stringWithCString:(data + matches[2]) length:(matches[3] - matches[2])] retain];
222 email_ = [[NSString stringWithCString:(data + matches[4]) length:(matches[5] - matches[4])] retain];
224 name_ = [[NSString stringWithCString:data length:size] retain];
233 /* Right Alignment {{{ */
234 @interface UIRightTextLabel : UITextLabel {
235 float _savedRightEdgeX;
236 BOOL _sizedtofit_flag;
239 - (void) setFrame:(CGRect)frame;
240 - (void) setText:(NSString *)text;
241 - (void) realignText;
244 @implementation UIRightTextLabel
246 - (void) setFrame:(CGRect)frame {
247 [super setFrame:frame];
248 if (_sizedtofit_flag == NO) {
249 _savedRightEdgeX = frame.origin.x;
254 - (void) setText:(NSString *)text {
255 [super setText:text];
259 - (void) realignText {
260 CGRect oldFrame = [self frame];
262 _sizedtofit_flag = YES;
263 [self sizeToFit]; // shrink down size so I can right align it
265 CGRect newFrame = [self frame];
267 oldFrame.origin.x = _savedRightEdgeX - newFrame.size.width;
268 oldFrame.size.width = newFrame.size.width;
269 [super setFrame:oldFrame];
270 _sizedtofit_flag = NO;
275 /* Linear Algebra {{{ */
276 inline float interpolate(float begin, float end, float fraction) {
277 return (end - begin) * fraction + begin;
283 @interface Database : NSObject {
285 pkgRecords *records_;
286 pkgProblemResolver *resolver_;
287 pkgAcquire *fetcher_;
289 SPtr<pkgPackageManager> manager_;
297 - (void) _readStatus:(NSNumber *)fd;
298 - (void) _readOutput:(NSNumber *)fd;
300 - (Package *) packageWithName:(NSString *)name;
303 - (pkgCacheFile &) cache;
304 - (pkgRecords *) records;
305 - (pkgProblemResolver *) resolver;
306 - (pkgAcquire &) fetcher;
314 - (void) setDelegate:(id)delegate;
318 @interface ResetView : UIView {
319 UINavigationBar *navbar_;
323 - (void) navigationBar:(UINavigationBar *)navbar poppedItem:(UINavigationItem *)item;
328 - (NSString *) leftTitle;
329 - (NSString *) rightTitle;
332 @implementation ResetView
334 - (void) navigationBar:(UINavigationBar *)navbar poppedItem:(UINavigationItem *)item {
335 if ([[navbar_ navigationItems] count] == 1)
346 if ([[navbar_ navigationItems] count] == 1)
348 else while ([[navbar_ navigationItems] count] != 1)
349 [navbar_ popNavigationItem];
353 - (void) _resetView {
354 [navbar_ showButtonsWithLeftTitle:[self leftTitle] rightTitle:[self rightTitle]];
357 - (NSString *) leftTitle {
361 - (NSString *) rightTitle {
367 /* Confirmation View {{{ */
368 void AddTextView(NSMutableDictionary *fields, NSMutableArray *packages, NSString *key) {
369 if ([packages count] == 0)
372 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
373 float clear[] = {0, 0, 0, 0};
374 float blue[] = {0, 0, 0.4, 1};
376 UITextView *text([[[UITextView alloc] initWithFrame: CGRectMake(110, 3, 200, 60)] autorelease]);
377 [text setEditable:NO];
378 [text setTextSize:16];
379 [text setBackgroundColor:CGColorCreate(space, clear)];
380 [text setTextColor:CGColorCreate(space, blue)];
381 [text setText:([packages count] == 0 ? @"n/a" : [packages componentsJoinedByString:@", "])];
382 [text setEnabled:NO];
384 CGRect frame([text frame]);
385 CGSize size([text contentSize]);
386 frame.size.height = size.height;
387 [text setFrame:frame];
389 [fields setObject:text forKey:key];
392 @protocol ConfirmationViewDelegate
397 @interface ConfirmationView : UIView {
400 UITransitionView *transition_;
402 UINavigationBar *navbar_;
403 UIPreferencesTable *table_;
404 NSMutableDictionary *fields_;
405 UIAlertSheet *essential_;
411 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
412 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
413 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
415 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table;
416 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group;
417 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed;
418 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group;
419 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group;
421 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate;
425 @implementation ConfirmationView
428 [transition_ release];
433 if (essential_ != nil)
434 [essential_ release];
439 [transition_ transition:7 toView:nil];
443 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
444 if (from != nil && to == nil)
445 [self removeFromSuperview];
448 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
451 if (essential_ != nil)
452 [essential_ popupAlertAnimated:YES];
463 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
464 [essential_ dismiss];
468 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
472 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
474 case 0: return @"Statistics";
475 case 1: return @"Modifications";
477 default: _assert(false);
481 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
484 case 1: return [fields_ count];
486 default: _assert(false);
490 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
491 if (group != 1 || row == -1)
494 _assert(size_t(row) < [fields_ count]);
495 return [[[fields_ allValues] objectAtIndex:row] contentSize].height;
499 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
500 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
501 [cell setShowSelection:NO];
504 case 0: switch (row) {
506 [cell setTitle:@"Downloading"];
507 [cell setValue:SizeString([database_ fetcher].FetchNeeded())];
511 [cell setTitle:@"Resuming At"];
512 [cell setValue:SizeString([database_ fetcher].PartialPresent())];
516 double size([database_ cache]->UsrSize());
519 [cell setTitle:@"Disk Freeing"];
520 [cell setValue:SizeString(-size)];
522 [cell setTitle:@"Disk Using"];
523 [cell setValue:SizeString(size)];
527 default: _assert(false);
531 _assert(size_t(row) < [fields_ count]);
532 [cell setTitle:[[fields_ allKeys] objectAtIndex:row]];
533 [cell addSubview:[[fields_ allValues] objectAtIndex:row]];
536 default: _assert(false);
542 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate {
543 if ((self = [super initWithFrame:[view bounds]]) != nil) {
544 database_ = database;
545 delegate_ = delegate;
547 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
548 [self addSubview:transition_];
550 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
552 CGSize navsize = [UINavigationBar defaultSize];
553 CGRect navrect = {{0, 0}, navsize};
554 CGRect bounds = [overlay_ bounds];
556 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
557 [navbar_ setBarStyle:1];
558 [navbar_ setDelegate:self];
560 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Confirm"] autorelease];
561 [navbar_ pushNavigationItem:navitem];
562 [navbar_ showButtonsWithLeftTitle:@"Cancel" rightTitle:@"Confirm"];
564 fields_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
566 NSMutableArray *installing = [NSMutableArray arrayWithCapacity:16];
567 NSMutableArray *upgrading = [NSMutableArray arrayWithCapacity:16];
568 NSMutableArray *removing = [NSMutableArray arrayWithCapacity:16];
570 bool essential(false);
572 pkgCacheFile &cache([database_ cache]);
573 for (pkgCache::PkgIterator iterator = cache->PkgBegin(); !iterator.end(); ++iterator) {
574 NSString *name([NSString stringWithCString:iterator.Name()]);
575 if (cache[iterator].NewInstall())
576 [installing addObject:name];
577 else if (cache[iterator].Upgrade())
578 [upgrading addObject:name];
579 else if (cache[iterator].Delete()) {
580 [removing addObject:name];
581 if ((iterator->Flags & pkgCache::Flag::Essential) != 0)
589 essential_ = [[UIAlertSheet alloc]
590 initWithTitle:@"Unable to Comply"
591 buttons:[NSArray arrayWithObjects:@"Okay", nil]
597 [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."];
600 AddTextView(fields_, installing, @"Installing");
601 AddTextView(fields_, upgrading, @"Upgrading");
602 AddTextView(fields_, removing, @"Removing");
604 table_ = [[UIPreferencesTable alloc] initWithFrame:CGRectMake(
605 0, navsize.height, bounds.size.width, bounds.size.height - navsize.height
608 [table_ setReusesTableCells:YES];
609 [table_ setDataSource:self];
612 [overlay_ addSubview:navbar_];
613 [overlay_ addSubview:table_];
615 [view addSubview:self];
617 [transition_ setDelegate:self];
619 UIView *blank = [[[UIView alloc] initWithFrame:[transition_ bounds]] autorelease];
620 [transition_ transition:0 toView:blank];
621 [transition_ transition:3 toView:overlay_];
628 /* Package Class {{{ */
629 @interface Package : NSObject {
630 pkgCache::PkgIterator iterator_;
632 pkgRecords::Parser *parser_;
633 pkgCache::VerIterator version_;
634 pkgCache::VerFileIterator file_;
637 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database version:(pkgCache::VerIterator)version file:(pkgCache::VerFileIterator)file;
638 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
641 - (NSString *) section;
642 - (NSString *) latest;
643 - (NSString *) installed;
644 - (Address *) maintainer;
646 - (NSString *) tagline;
647 - (NSString *) description;
648 - (NSComparisonResult) compareBySectionAndName:(Package *)package;
654 @implementation Package
656 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database version:(pkgCache::VerIterator)version file:(pkgCache::VerFileIterator)file {
657 if ((self = [super init]) != nil) {
658 iterator_ = iterator;
659 database_ = database;
663 parser_ = &[database_ records]->Lookup(file);
667 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
668 for (pkgCache::VerIterator version = iterator.VersionList(); !version.end(); ++version)
669 for (pkgCache::VerFileIterator file = version.FileList(); !file.end(); ++file)
670 return [[[Package alloc]
671 initWithIterator:iterator
679 - (NSString *) name {
680 return [[NSString stringWithCString:iterator_.Name()] lowercaseString];
683 - (NSString *) section {
684 return [NSString stringWithCString:iterator_.Section()];
687 - (NSString *) latest {
688 return [NSString stringWithCString:version_.VerStr()];
691 - (NSString *) installed {
692 return iterator_.CurrentVer().end() ? nil : [NSString stringWithCString:iterator_.CurrentVer().VerStr()];
695 - (Address *) maintainer {
696 return [Address addressWithString:[NSString stringWithCString:parser_->Maintainer().c_str()]];
700 return version_->InstalledSize;
703 - (NSString *) tagline {
704 return [NSString stringWithCString:parser_->ShortDesc().c_str()];
707 - (NSString *) description {
708 return [NSString stringWithCString:parser_->LongDesc().c_str()];
711 - (NSComparisonResult) compareBySectionAndName:(Package *)package {
712 NSComparisonResult result = [[self section] compare:[package section]];
713 if (result != NSOrderedSame)
715 return [[self name] compare:[package name]];
719 pkgProblemResolver *resolver = [database_ resolver];
720 resolver->Clear(iterator_);
721 resolver->Protect(iterator_);
722 [database_ cache]->MarkInstall(iterator_, false);
726 pkgProblemResolver *resolver = [database_ resolver];
727 resolver->Clear(iterator_);
728 resolver->Protect(iterator_);
729 resolver->Remove(iterator_);
730 [database_ cache]->MarkDelete(iterator_, true);
735 /* Section Class {{{ */
736 @interface Section : NSObject {
739 NSMutableArray *packages_;
744 - (Section *) initWithName:(NSString *)name row:(size_t)row;
747 - (void) addPackage:(Package *)package;
750 @implementation Section
758 - (Section *) initWithName:(NSString *)name row:(size_t)row {
759 if ((self = [super init]) != nil) {
760 name_ = [name retain];
762 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
766 - (NSString *) name {
774 - (void) addPackage:(Package *)package {
775 [packages_ addObject:package];
781 /* Package View {{{ */
782 @interface PackageView : UIView {
783 UIPreferencesTable *table_;
786 NSMutableArray *cells_;
792 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table;
793 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group;
794 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group;
795 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group;
797 - (BOOL) canSelectRow:(int)row;
798 - (void) tableRowSelected:(NSNotification *)notification;
800 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database;
801 - (void) setPackage:(Package *)package;
802 - (void) setDelegate:(id)delegate;
805 @implementation PackageView
816 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
820 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
822 case 0: return @"Specifics";
823 case 1: return @"Description";
825 default: _assert(false);
829 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
834 default: _assert(false);
838 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
839 UIPreferencesTableCell *cell;
842 case 0: switch (row) {
844 cell = [cells_ objectAtIndex:0];
845 [cell setTitle:@"Name"];
846 [cell setValue:[package_ name]];
850 cell = [cells_ objectAtIndex:1];
851 [cell setTitle:@"Installed"];
852 NSString *installed([package_ installed]);
853 [cell setValue:(installed == nil ? @"n/a" : installed)];
857 cell = [cells_ objectAtIndex:2];
858 [cell setTitle:@"Latest"];
859 [cell setValue:[package_ latest]];
863 cell = [cells_ objectAtIndex:3];
864 [cell setTitle:@"Section"];
865 [cell setValue:[package_ section]];
869 cell = [cells_ objectAtIndex:4];
870 [cell setTitle:@"Size"];
871 [cell setValue:SizeString([package_ size])];
875 cell = [cells_ objectAtIndex:5];
876 [cell setTitle:@"Maintainer"];
877 [cell setValue:[[package_ maintainer] name]];
878 [cell setShowDisclosure:YES];
879 [cell setShowSelection:YES];
882 default: _assert(false);
885 case 1: switch (row) {
887 cell = [cells_ objectAtIndex:6];
889 [cell setValue:[package_ tagline]];
893 cell = [cells_ objectAtIndex:7];
894 [cell setTitle:@"Description"];
895 [cell setValue:[package_ description]];
899 default: _assert(false);
905 - (BOOL) canSelectRow:(int)row {
909 - (void) tableRowSelected:(NSNotification *)notification {
910 switch ([table_ selectedRow]) {
912 [delegate_ openURL:[NSURL URLWithString:[NSString stringWithFormat:@"mailto:%@?subject=%@",
913 [[package_ maintainer] email],
914 [[NSString stringWithFormat:@"regarding apt package \"%@\"", [package_ name]] stringByAddingPercentEscapes]
920 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database {
921 if ((self = [super initWithFrame:frame]) != nil) {
922 database_ = [database retain];
924 table_ = [[UIPreferencesTable alloc] initWithFrame:[self bounds]];
925 [self addSubview:table_];
927 [table_ setDataSource:self];
928 [table_ setDelegate:self];
930 cells_ = [[NSMutableArray arrayWithCapacity:16] retain];
932 for (unsigned i = 0; i != 8; ++i) {
933 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
934 [cell setShowSelection:NO];
935 [cells_ addObject:cell];
940 - (void) setPackage:(Package *)package {
941 package_ = [package retain];
945 - (void) setDelegate:(id)delegate {
946 delegate_ = delegate;
951 /* Package Cell {{{ */
952 @protocol PackageCellDelegate
953 - (NSString *) versionWithPackage:(Package *)package;
956 @interface PackageCell : UITableCell {
958 UIRightTextLabel *version_;
959 UITextLabel *description_;
964 - (PackageCell *) initWithPackage:(Package *)package delegate:(id)delegate;
966 - (void) _setSelected:(float)fraction;
967 - (void) setSelected:(BOOL)selected;
968 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
969 - (void) _setSelectionFadeFraction:(float)fraction;
973 @implementation PackageCell
978 [description_ release];
982 - (PackageCell *) initWithPackage:(Package *)package delegate:(id)delegate {
983 if ((self = [super init]) != nil) {
984 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22);
985 GSFontRef large = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
986 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 14);
988 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
989 float clear[] = {0, 0, 0, 0};
991 name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(12, 7, 250, 25)];
992 [name_ setBackgroundColor:CGColorCreate(space, clear)];
993 [name_ setFont:bold];
994 [name_ setText:[package name]];
996 version_ = [[UIRightTextLabel alloc] initWithFrame:CGRectMake(290, 7, 70, 25)];
997 [version_ setBackgroundColor:CGColorCreate(space, clear)];
998 [version_ setFont:large];
999 [version_ setText:[delegate versionWithPackage:package]];
1001 description_ = [[UITextLabel alloc] initWithFrame:CGRectMake(13, 35, 315, 20)];
1002 [description_ setBackgroundColor:CGColorCreate(space, clear)];
1003 [description_ setFont:small];
1004 [description_ setText:[package tagline]];
1006 [self addSubview:name_];
1007 [self addSubview:version_];
1008 [self addSubview:description_];
1016 - (void) _setSelected:(float)fraction {
1017 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1020 interpolate(0.0, 1.0, fraction),
1021 interpolate(0.0, 1.0, fraction),
1022 interpolate(0.0, 1.0, fraction),
1026 interpolate(0.2, 1.0, fraction),
1027 interpolate(0.2, 1.0, fraction),
1028 interpolate(1.0, 1.0, fraction),
1032 interpolate(0.4, 1.0, fraction),
1033 interpolate(0.4, 1.0, fraction),
1034 interpolate(0.4, 1.0, fraction),
1037 [name_ setColor:CGColorCreate(space, black)];
1038 [version_ setColor:CGColorCreate(space, blue)];
1039 [description_ setColor:CGColorCreate(space, gray)];
1042 - (void) setSelected:(BOOL)selected {
1043 [self _setSelected:(selected ? 1.0 : 0.0)];
1044 [super setSelected:selected];
1047 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
1049 [self _setSelected:(selected ? 1.0 : 0.0)];
1050 [super setSelected:selected withFade:fade];
1053 - (void) _setSelectionFadeFraction:(float)fraction {
1054 [self _setSelected:fraction];
1055 [super _setSelectionFadeFraction:fraction];
1062 @interface Source : NSObject {
1063 NSString *description_;
1068 NSString *distribution_;
1076 - (Source *) initWithMetaIndex:(metaIndex *)index;
1081 - (NSString *) distribution;
1082 - (NSString *) type;
1084 - (NSString *) description;
1085 - (NSString *) label;
1086 - (NSString *) origin;
1089 @implementation Source
1093 [distribution_ release];
1096 if (description_ != nil)
1097 [description_ release];
1106 - (Source *) initWithMetaIndex:(metaIndex *)index {
1107 if ((self = [super init]) != nil) {
1108 trusted_ = index->IsTrusted();
1110 uri_ = [[NSString stringWithCString:index->GetURI().c_str()] retain];
1111 distribution_ = [[NSString stringWithCString:index->GetDist().c_str()] retain];
1112 type_ = [[NSString stringWithCString:index->GetType()] retain];
1118 debReleaseIndex *dindex(dynamic_cast<debReleaseIndex *>(index));
1119 if (dindex != NULL) {
1120 std::ifstream release(dindex->MetaIndexFile("Release").c_str());
1122 while (std::getline(release, line)) {
1123 std::string::size_type colon(line.find(':'));
1124 if (colon == std::string::npos)
1127 std::string name(line.substr(0, colon));
1128 std::string value(line.substr(colon + 1));
1129 while (!value.empty() && value[0] == ' ')
1130 value = value.substr(1);
1132 if (name == "Description")
1133 description_ = [[NSString stringWithCString:value.c_str()] retain];
1134 else if (name == "Label")
1135 label_ = [[NSString stringWithCString:value.c_str()] retain];
1136 else if (name == "Origin")
1137 origin_ = [[NSString stringWithCString:value.c_str()] retain];
1147 - (NSString *) uri {
1151 - (NSString *) distribution {
1152 return distribution_;
1155 - (NSString *) type {
1159 - (NSString *) description {
1160 return description_;
1163 - (NSString *) label {
1167 - (NSString *) origin {
1173 /* Source Cell {{{ */
1174 @interface SourceCell : UITableCell {
1175 UITextLabel *description_;
1176 UIRightTextLabel *label_;
1177 UITextLabel *origin_;
1182 - (SourceCell *) initWithSource:(Source *)source;
1184 - (void) _setSelected:(float)fraction;
1185 - (void) setSelected:(BOOL)selected;
1186 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
1187 - (void) _setSelectionFadeFraction:(float)fraction;
1191 @implementation SourceCell
1194 [description_ release];
1200 - (SourceCell *) initWithSource:(Source *)source {
1201 if ((self = [super init]) != nil) {
1202 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 20);
1203 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 14);
1205 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1206 float clear[] = {0, 0, 0, 0};
1208 NSString *description = [source description];
1209 if (description == nil)
1210 description = [source uri];
1212 description_ = [[UITextLabel alloc] initWithFrame:CGRectMake(12, 7, 270, 25)];
1213 [description_ setBackgroundColor:CGColorCreate(space, clear)];
1214 [description_ setFont:bold];
1215 [description_ setText:description];
1217 NSString *label = [source label];
1219 label = [source type];
1221 label_ = [[UIRightTextLabel alloc] initWithFrame:CGRectMake(290, 32, 90, 25)];
1222 [label_ setBackgroundColor:CGColorCreate(space, clear)];
1223 [label_ setFont:small];
1224 [label_ setText:label];
1226 NSString *origin = [source origin];
1228 origin = [source distribution];
1230 origin_ = [[UITextLabel alloc] initWithFrame:CGRectMake(13, 35, 315, 20)];
1231 [origin_ setBackgroundColor:CGColorCreate(space, clear)];
1232 [origin_ setFont:small];
1233 [origin_ setText:origin];
1235 [self addSubview:description_];
1236 [self addSubview:label_];
1237 [self addSubview:origin_];
1244 - (void) _setSelected:(float)fraction {
1245 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1248 interpolate(0.0, 1.0, fraction),
1249 interpolate(0.0, 1.0, fraction),
1250 interpolate(0.0, 1.0, fraction),
1254 interpolate(0.2, 1.0, fraction),
1255 interpolate(0.2, 1.0, fraction),
1256 interpolate(1.0, 1.0, fraction),
1260 interpolate(0.4, 1.0, fraction),
1261 interpolate(0.4, 1.0, fraction),
1262 interpolate(0.4, 1.0, fraction),
1265 [description_ setColor:CGColorCreate(space, black)];
1266 [label_ setColor:CGColorCreate(space, blue)];
1267 [origin_ setColor:CGColorCreate(space, gray)];
1270 - (void) setSelected:(BOOL)selected {
1271 [self _setSelected:(selected ? 1.0 : 0.0)];
1272 [super setSelected:selected];
1275 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
1277 [self _setSelected:(selected ? 1.0 : 0.0)];
1278 [super setSelected:selected withFade:fade];
1281 - (void) _setSelectionFadeFraction:(float)fraction {
1282 [self _setSelected:fraction];
1283 [super _setSelectionFadeFraction:fraction];
1288 /* Sources View {{{ */
1289 @interface SourcesView : ResetView {
1290 UISectionList *list_;
1291 Database *database_;
1293 NSMutableArray *sources_;
1294 UIAlertSheet *alert_;
1297 - (int) numberOfSectionsInSectionList:(UISectionList *)list;
1298 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section;
1299 - (int) sectionList:(UISectionList *)list rowForSection:(int)section;
1301 - (int) numberOfRowsInTable:(UITable *)table;
1302 - (float) table:(UITable *)table heightForRow:(int)row;
1303 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col;
1304 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row;
1305 - (void) tableRowSelected:(NSNotification*)notification;
1307 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
1310 - (id) initWithFrame:(CGRect)frame database:(Database *)database;
1311 - (void) setDelegate:(id)delegate;
1312 - (void) reloadData;
1313 - (NSString *) leftTitle;
1314 - (NSString *) rightTitle;
1317 @implementation SourcesView
1319 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
1323 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
1327 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
1331 - (int) numberOfRowsInTable:(UITable *)table {
1332 return [sources_ count];
1335 - (float) table:(UITable *)table heightForRow:(int)row {
1339 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col {
1340 return [[[SourceCell alloc] initWithSource:[sources_ objectAtIndex:row]] autorelease];
1343 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
1347 - (void) tableRowSelected:(NSNotification*)notification {
1348 UITable *table([list_ table]);
1349 int row([table selectedRow]);
1353 [table selectRow:-1 byExtendingSelection:NO withFade:YES];
1356 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
1362 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
1365 alert_ = [[UIAlertSheet alloc]
1366 initWithTitle:@"Unimplemented"
1367 buttons:[NSArray arrayWithObjects:@"Okay", nil]
1368 defaultButtonIndex:0
1373 [alert_ 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'. If you'd like to be in the default list, please contact the author of Packager."];
1374 [alert_ popupAlertAnimated:YES];
1384 if (sources_ != nil)
1390 - (id) initWithFrame:(CGRect)frame database:(Database *)database {
1391 if ((self = [super initWithFrame:frame]) != nil) {
1392 database_ = database;
1395 CGSize navsize = [UINavigationBar defaultSize];
1396 CGRect navrect = {{0, 0}, navsize};
1397 CGRect bounds = [self bounds];
1399 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
1400 [self addSubview:navbar_];
1402 [navbar_ setBarStyle:1];
1403 [navbar_ setDelegate:self];
1405 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Sources"] autorelease];
1406 [navbar_ pushNavigationItem:navitem];
1408 list_ = [[UISectionList alloc] initWithFrame:CGRectMake(
1409 0, navsize.height, bounds.size.width, bounds.size.height - navsize.height
1412 [self addSubview:list_];
1414 [list_ setDataSource:self];
1415 [list_ setShouldHideHeaderInShortLists:NO];
1417 UITableColumn *column = [[UITableColumn alloc]
1418 initWithTitle:@"Name"
1420 width:frame.size.width
1423 UITable *table = [list_ table];
1424 [table setSeparatorStyle:1];
1425 [table addTableColumn:column];
1426 [table setDelegate:self];
1430 - (void) setDelegate:(id)delegate {
1431 delegate_ = delegate;
1434 - (void) reloadData {
1436 _assert(list.ReadMainList());
1438 if (sources_ != nil)
1441 sources_ = [[NSMutableArray arrayWithCapacity:16] retain];
1442 for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source)
1443 [sources_ addObject:[[[Source alloc] initWithMetaIndex:*source] autorelease]];
1449 - (NSString *) leftTitle {
1450 return @"Refresh All";
1453 - (NSString *) rightTitle {
1460 @implementation Database
1462 - (void) _readStatus:(NSNumber *)fd {
1463 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1465 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1466 std::istream is(&ib);
1471 pcre *code = pcre_compile("^([^:]*):([^:]*):([^:]*):(.*)$", 0, &error, &offset, NULL);
1473 pcre_extra *study = NULL;
1475 pcre_fullinfo(code, study, PCRE_INFO_CAPTURECOUNT, &capture);
1476 int matches[(capture + 1) * 3];
1478 while (std::getline(is, line)) {
1479 const char *data(line.c_str());
1481 _assert(pcre_exec(code, study, data, line.size(), 0, 0, matches, sizeof(matches) / sizeof(matches[0])) >= 0);
1483 std::istringstream buffer(line.substr(matches[6], matches[7] - matches[6]));
1486 [delegate_ setPercent:(percent / 100)];
1488 NSString *string = [NSString stringWithCString:(data + matches[8]) length:(matches[9] - matches[8])];
1489 std::string type(line.substr(matches[2], matches[3] - matches[2]));
1491 if (type == "pmerror")
1492 [delegate_ setError:string];
1493 else if (type == "pmstatus")
1494 [delegate_ setTitle:string];
1495 else if (type == "pmconffile")
1497 else _assert(false);
1503 - (void) _readOutput:(NSNumber *)fd {
1504 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1506 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1507 std::istream is(&ib);
1510 while (std::getline(is, line))
1511 [delegate_ addOutput:[NSString stringWithCString:line.c_str()]];
1516 - (Package *) packageWithName:(NSString *)name {
1517 pkgCache::PkgIterator iterator(cache_->FindPkg([name cString]));
1518 return iterator.end() ? nil : [Package packageWithIterator:iterator database:self];
1521 - (Database *) init {
1522 if ((self = [super init]) != nil) {
1530 _assert(pipe(fds) != -1);
1534 detachNewThreadSelector:@selector(_readStatus:)
1536 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1539 _assert(pipe(fds) != -1);
1540 _assert(dup2(fds[1], 1) != -1);
1541 _assert(close(fds[1]) != -1);
1544 detachNewThreadSelector:@selector(_readOutput:)
1546 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1551 - (pkgCacheFile &) cache {
1555 - (pkgRecords *) records {
1559 - (pkgProblemResolver *) resolver {
1563 - (pkgAcquire &) fetcher {
1567 - (void) reloadData {
1575 cache_.Open(progress_, true);
1576 records_ = new pkgRecords(cache_);
1577 resolver_ = new pkgProblemResolver(cache_);
1578 fetcher_ = new pkgAcquire(&status_);
1583 pkgRecords records(cache_);
1585 lock_ = new FileFd();
1586 lock_->Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1587 _assert(!_error->PendingError());
1590 _assert(list.ReadMainList());
1592 manager_ = (_system->CreatePM(cache_));
1593 _assert(manager_->GetArchives(fetcher_, &list, &records));
1594 _assert(!_error->PendingError());
1598 if (fetcher_->Run(PulseInterval_) != pkgAcquire::Continue)
1602 pkgPackageManager::OrderResult result = manager_->DoInstall(statusfd_);
1604 if (result == pkgPackageManager::Failed)
1606 if (_error->PendingError())
1608 if (result != pkgPackageManager::Completed)
1614 _assert(list.ReadMainList());
1617 lock.Fd(GetLock(_config->FindDir("Dir::State::Lists") + "lock"));
1618 _assert(!_error->PendingError());
1620 pkgAcquire fetcher(&status_);
1621 _assert(list.GetIndexes(&fetcher));
1622 _assert(fetcher.Run(PulseInterval_) != pkgAcquire::Failed);
1624 bool failed = false;
1625 for (pkgAcquire::ItemIterator item = fetcher.ItemsBegin(); item != fetcher.ItemsEnd(); item++)
1626 if ((*item)->Status != pkgAcquire::Item::StatDone) {
1627 (*item)->Finished();
1631 if (!failed && _config->FindB("APT::Get::List-Cleanup", true) == true) {
1632 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists")));
1633 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/"));
1638 _assert(cache_->DelCount() == 0 && cache_->InstCount() == 0);
1639 _assert(pkgApplyStatus(cache_));
1641 if (cache_->BrokenCount() != 0) {
1642 _assert(pkgFixBroken(cache_));
1643 _assert(cache_->BrokenCount() == 0);
1644 _assert(pkgMinimizeUpgrade(cache_));
1647 _assert(pkgDistUpgrade(cache_));
1650 - (void) setDelegate:(id)delegate {
1651 delegate_ = delegate;
1652 status_.setDelegate(delegate);
1653 progress_.setDelegate(delegate);
1658 /* Progress Data {{{ */
1659 @interface ProgressData : NSObject {
1665 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object;
1672 @implementation ProgressData
1674 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object {
1675 if ((self = [super init]) != nil) {
1676 selector_ = selector;
1696 /* Progress View {{{ */
1697 @interface ProgressView : UIView <
1701 UIView *background_;
1702 UITransitionView *transition_;
1704 UINavigationBar *navbar_;
1705 UIProgressBar *progress_;
1706 UITextView *output_;
1707 UITextLabel *status_;
1709 UIAlertSheet *alert_;
1714 - (ProgressView *) initWithFrame:(struct CGRect)frame delegate:(id)delegate;
1715 - (void) setContentView:(UIView *)view;
1718 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
1720 - (void) _retachThread;
1721 - (void) _detachNewThreadData:(ProgressData *)data;
1722 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object;
1724 - (void) setError:(NSString *)error;
1725 - (void) _setError:(NSString *)error;
1727 - (void) setTitle:(NSString *)title;
1728 - (void) _setTitle:(NSString *)title;
1730 - (void) setPercent:(float)percent;
1731 - (void) _setPercent:(NSNumber *)percent;
1733 - (void) addOutput:(NSString *)output;
1734 - (void) _addOutput:(NSString *)output;
1736 - (void) setStatusFail;
1739 @protocol ProgressViewDelegate
1740 - (void) progressViewIsComplete:(ProgressView *)sender;
1743 @implementation ProgressView
1747 [background_ release];
1748 [transition_ release];
1751 [progress_ release];
1757 - (ProgressView *) initWithFrame:(struct CGRect)frame delegate:(id)delegate {
1758 if ((self = [super initWithFrame:frame]) != nil) {
1759 delegate_ = delegate;
1762 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1763 float black[] = {0.0, 0.0, 0.0, 1.0};
1764 float white[] = {1.0, 1.0, 1.0, 1.0};
1765 float clear[] = {0.0, 0.0, 0.0, 0.0};
1767 background_ = [[UIView alloc] initWithFrame:[self bounds]];
1768 [background_ setBackgroundColor:CGColorCreate(space, black)];
1769 [self addSubview:background_];
1771 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
1772 [self addSubview:transition_];
1774 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
1776 CGSize navsize = [UINavigationBar defaultSize];
1777 CGRect navrect = {{0, 0}, navsize};
1779 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
1780 [overlay_ addSubview:navbar_];
1782 [navbar_ setBarStyle:1];
1783 [navbar_ setDelegate:self];
1785 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Running..."] autorelease];
1786 [navbar_ pushNavigationItem:navitem];
1788 CGRect bounds = [overlay_ bounds];
1789 CGSize prgsize = [UIProgressBar defaultSize];
1792 (bounds.size.width - prgsize.width) / 2,
1793 bounds.size.height - prgsize.height - 20
1796 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
1797 [overlay_ addSubview:progress_];
1799 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(
1801 bounds.size.height - prgsize.height - 50,
1802 bounds.size.width - 20,
1806 [status_ setColor:CGColorCreate(space, white)];
1807 [status_ setBackgroundColor:CGColorCreate(space, clear)];
1809 [status_ setCentersHorizontally:YES];
1810 //[status_ setFont:font];
1812 output_ = [[UITextView alloc] initWithFrame:CGRectMake(
1814 navrect.size.height + 20,
1815 bounds.size.width - 20,
1816 bounds.size.height - navsize.height - 62 - navrect.size.height
1819 //[output_ setTextFont:@"Courier New"];
1820 [output_ setTextSize:12];
1822 [output_ setTextColor:CGColorCreate(space, white)];
1823 [output_ setBackgroundColor:CGColorCreate(space, clear)];
1825 [output_ setMarginTop:0];
1826 [output_ setAllowsRubberBanding:YES];
1828 [overlay_ addSubview:output_];
1829 [overlay_ addSubview:status_];
1831 [progress_ setStyle:0];
1835 - (void) setContentView:(UIView *)view {
1839 - (void) resetView {
1840 [transition_ transition:6 toView:view_];
1843 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
1849 - (void) _retachThread {
1850 [delegate_ progressViewIsComplete:self];
1854 - (void) _detachNewThreadData:(ProgressData *)data {
1855 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1857 [[data target] performSelector:[data selector] withObject:[data object]];
1858 [self performSelectorOnMainThread:@selector(_retachThread) withObject:nil waitUntilDone:YES];
1864 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object {
1865 [status_ setText:nil];
1866 [output_ setText:@""];
1867 [progress_ setProgress:0];
1869 [transition_ transition:6 toView:overlay_];
1872 detachNewThreadSelector:@selector(_detachNewThreadData:)
1874 withObject:[[ProgressData alloc]
1875 initWithSelector:selector
1882 - (void) setStatusFail {
1885 - (void) setError:(NSString *)error {
1887 performSelectorOnMainThread:@selector(_setError:)
1893 - (void) _setError:(NSString *)error {
1894 _assert(alert_ == nil);
1896 alert_ = [[UIAlertSheet alloc]
1897 initWithTitle:@"Package Error"
1898 buttons:[NSArray arrayWithObjects:@"Okay", nil]
1899 defaultButtonIndex:0
1904 [alert_ setBodyText:error];
1905 [alert_ popupAlertAnimated:YES];
1908 - (void) setTitle:(NSString *)title {
1910 performSelectorOnMainThread:@selector(_setTitle:)
1916 - (void) _setTitle:(NSString *)title {
1917 [status_ setText:[title stringByAppendingString:@"..."]];
1920 - (void) setPercent:(float)percent {
1922 performSelectorOnMainThread:@selector(_setPercent:)
1923 withObject:[NSNumber numberWithFloat:percent]
1928 - (void) _setPercent:(NSNumber *)percent {
1929 [progress_ setProgress:[percent floatValue]];
1932 - (void) addOutput:(NSString *)output {
1934 performSelectorOnMainThread:@selector(_addOutput:)
1940 - (void) _addOutput:(NSString *)output {
1941 [output_ setText:[NSString stringWithFormat:@"%@\n%@", [output_ text], output]];
1942 CGSize size = [output_ contentSize];
1943 CGRect rect = {{0, size.height}, {size.width, 0}};
1944 [output_ scrollRectToVisible:rect animated:YES];
1950 @protocol PackagesViewDelegate
1953 - (void) openURL:(NSString *)url;
1956 /* PackagesView {{{ */
1957 @interface PackagesView : ResetView <
1960 Database *database_;
1961 NSMutableArray *packages_;
1962 NSMutableArray *sections_;
1964 UISectionList *list_;
1965 UITransitionView *transition_;
1968 PackageView *pkgview_;
1971 - (int) numberOfSectionsInSectionList:(UISectionList *)list;
1972 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section;
1973 - (int) sectionList:(UISectionList *)list rowForSection:(int)section;
1975 - (int) numberOfRowsInTable:(UITable *)table;
1976 - (float) table:(UITable *)table heightForRow:(int)row;
1977 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col;
1978 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row;
1979 - (void) tableRowSelected:(NSNotification*)notification;
1981 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
1982 - (void) navigationBar:(UINavigationBar *)navbar poppedItem:(UINavigationItem *)item;
1984 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database;
1985 - (void) setDelegate:(id)delegate;
1987 - (void) reloadData:(BOOL)reset;
1989 - (NSMutableArray *) packages;
1990 - (NSString *) title;
1991 - (void) perform:(Package *)package;
1992 - (void) addPackage:(Package *)package;
1993 - (NSString *) versionWithPackage:(Package *)package;
1996 @implementation PackagesView
1998 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
1999 return [sections_ count];
2002 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
2003 return [[sections_ objectAtIndex:section] name];
2006 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
2007 return [[sections_ objectAtIndex:section] row];
2010 - (int) numberOfRowsInTable:(UITable *)table {
2011 return [packages_ count];
2014 - (float) table:(UITable *)table heightForRow:(int)row {
2018 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col {
2019 return [[[PackageCell alloc] initWithPackage:[packages_ objectAtIndex:row] delegate:self] autorelease];
2022 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
2026 - (void) tableRowSelected:(NSNotification*)notification {
2027 int row = [[list_ table] selectedRow];
2031 package_ = [packages_ objectAtIndex:row];
2032 pkgname_ = [[package_ name] retain];
2034 UINavigationItem *navitem = [[UINavigationItem alloc] initWithTitle:[package_ name]];
2035 [navbar_ pushNavigationItem:navitem];
2037 [navbar_ showButtonsWithLeftTitle:nil rightTitle:[self title]];
2039 [pkgview_ setPackage:package_];
2040 [transition_ transition:1 toView:pkgview_];
2043 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2045 [self perform:package_];
2047 pkgProblemResolver *resolver = [database_ resolver];
2049 resolver->InstallProtect();
2050 if (!resolver->Resolve(true))
2053 [delegate_ perform];
2057 - (void) navigationBar:(UINavigationBar *)navbar poppedItem:(UINavigationItem *)item {
2059 [super navigationBar:navbar poppedItem:item];
2062 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database {
2063 if ((self = [super initWithFrame:frame]) != nil) {
2064 database_ = [database retain];
2066 struct CGRect bounds = [self bounds];
2067 CGSize navsize = [UINavigationBar defaultSize];
2068 CGRect navrect = {{0, 0}, navsize};
2070 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
2071 [self addSubview:navbar_];
2073 [navbar_ setBarStyle:1];
2074 [navbar_ setDelegate:self];
2076 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:[self title]] autorelease];
2077 [navbar_ pushNavigationItem:navitem];
2078 [navitem setBackButtonTitle:@"Packages"];
2080 transition_ = [[UITransitionView alloc] initWithFrame:CGRectMake(
2081 bounds.origin.x, bounds.origin.y + navsize.height, bounds.size.width, bounds.size.height - navsize.height
2084 [self addSubview:transition_];
2086 list_ = [[UISectionList alloc] initWithFrame:[transition_ bounds] showSectionIndex:NO];
2087 [list_ setDataSource:self];
2088 [list_ setShouldHideHeaderInShortLists:NO];
2090 [transition_ transition:0 toView:list_];
2092 UITableColumn *column = [[UITableColumn alloc]
2093 initWithTitle:@"Name"
2095 width:frame.size.width
2098 UITable *table = [list_ table];
2099 [table setSeparatorStyle:1];
2100 [table addTableColumn:column];
2101 [table setDelegate:self];
2103 pkgview_ = [[PackageView alloc] initWithFrame:[transition_ bounds] database:database_];
2107 - (void) setDelegate:(id)delegate {
2108 delegate_ = delegate;
2109 [pkgview_ setDelegate:delegate];
2113 [transition_ transition:(resetting_ ? 0 : 2) toView:list_];
2114 UITable *table = [list_ table];
2115 [table selectRow:-1 byExtendingSelection:NO withFade:(resetting_ ? NO : YES)];
2119 - (void) reloadData:(BOOL)reset {
2120 if (sections_ != nil)
2121 [sections_ release];
2122 if (packages_ != nil)
2123 [packages_ release];
2125 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
2127 for (pkgCache::PkgIterator iterator = [database_ cache]->PkgBegin(); !iterator.end(); ++iterator)
2128 if (Package *package = [Package packageWithIterator:iterator database:database_])
2129 [self addPackage:package];
2131 [packages_ sortUsingSelector:@selector(compareBySectionAndName:)];
2132 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
2134 Section *section = nil;
2135 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
2136 Package *package = [packages_ objectAtIndex:offset];
2137 NSString *name = [package section];
2139 if (section == nil || ![[section name] isEqual:name]) {
2140 section = [[Section alloc] initWithName:name row:offset];
2141 [sections_ addObject:section];
2144 [section addPackage:package];
2150 else if (package_ != nil) {
2151 package_ = [database_ packageWithName:pkgname_];
2152 [pkgview_ setPackage:package_];
2156 - (NSMutableArray *) packages {
2160 - (NSString *) title {
2164 - (void) perform:(Package *)package {
2167 - (void) addPackage:(Package *)package {
2168 [packages_ addObject:package];
2171 - (NSString *) versionWithPackage:(Package *)package {
2178 /* InstallView {{{ */
2179 @interface InstallView : PackagesView {
2182 - (NSString *) title;
2183 - (void) addPackage:(Package *)package;
2184 - (void) perform:(Package *)package;
2185 - (NSString *) versionWithPackage:(Package *)package;
2188 @implementation InstallView
2190 - (NSString *) title {
2194 - (void) addPackage:(Package *)package {
2195 if ([package installed] == nil)
2196 [super addPackage:package];
2199 - (void) perform:(Package *)package {
2203 - (NSString *) versionWithPackage:(Package *)package {
2204 return [package latest];
2209 /* UpgradeView {{{ */
2210 @interface UpgradeView : PackagesView {
2213 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
2215 - (NSString *) title;
2216 - (NSString *) leftTitle;
2217 - (void) addPackage:(Package *)package;
2218 - (void) perform:(Package *)package;
2219 - (NSString *) versionWithPackage:(Package *)package;
2222 @implementation UpgradeView
2224 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2226 [super navigationBar:navbar buttonClicked:button];
2228 [database_ upgrade];
2229 [delegate_ perform];
2233 - (NSString *) title {
2237 - (NSString *) leftTitle {
2238 return [packages_ count] == 0 ? nil : @"Upgrade All";
2241 - (void) addPackage:(Package *)package {
2242 NSString *installed = [package installed];
2243 if (installed != nil && [[package latest] compare:installed] != NSOrderedSame)
2244 [super addPackage:package];
2247 - (void) perform:(Package *)package {
2251 - (NSString *) versionWithPackage:(Package *)package {
2252 return [package latest];
2257 /* UninstallView {{{ */
2258 @interface UninstallView : PackagesView {
2261 - (NSString *) title;
2262 - (void) addPackage:(Package *)package;
2263 - (void) perform:(Package *)package;
2264 - (NSString *) versionWithPackage:(Package *)package;
2267 @implementation UninstallView
2269 - (NSString *) title {
2270 return @"Uninstall";
2273 - (void) addPackage:(Package *)package {
2274 if ([package installed] != nil)
2275 [super addPackage:package];
2278 - (void) perform:(Package *)package {
2282 - (NSString *) versionWithPackage:(Package *)package {
2283 return [package installed];
2289 @interface Cydia : UIApplication <
2290 ConfirmationViewDelegate,
2291 PackagesViewDelegate,
2292 ProgressViewDelegate
2297 UITransitionView *transition_;
2298 UIButtonBar *buttonbar_;
2300 UIAlertSheet *alert_;
2301 ConfirmationView *confirm_;
2303 Database *database_;
2304 ProgressView *progress_;
2307 UINavigationBar *navbar_;
2308 UIScroller *scroller_;
2309 UIWebView *webview_;
2311 UIProgressIndicator *indicator_;
2313 InstallView *install_;
2314 UpgradeView *upgrade_;
2315 UninstallView *uninstall_;
2316 SourcesView *sources_;
2320 - (void) reloadData:(BOOL)reset;
2326 - (void) progressViewIsComplete:(ProgressView *)progress;
2328 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
2329 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
2330 - (void) buttonBarItemTapped:(id)sender;
2332 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old;
2334 - (void) applicationDidFinishLaunching:(id)unused;
2337 #include <objc/objc-class.h>
2339 @implementation Cydia
2342 NSMutableURLRequest *request = [NSMutableURLRequest
2344 cachePolicy:NSURLRequestReloadIgnoringCacheData
2345 timeoutInterval:30.0
2348 [request addValue:[NSString stringWithCString:Machine_] forHTTPHeaderField:@"X-Machine"];
2349 [request addValue:[NSString stringWithCString:SerialNumber_] forHTTPHeaderField:@"X-Serial-Number"];
2351 [webview_ loadRequest:request];
2352 [indicator_ startAnimation];
2355 - (void) reloadData:(BOOL)reset {
2356 [database_ reloadData];
2357 [install_ reloadData:reset];
2358 [upgrade_ reloadData:reset];
2359 [uninstall_ reloadData:reset];
2360 [sources_ reloadData];
2362 if (size_t count = [[upgrade_ packages] count]) {
2363 NSString *badge([[NSNumber numberWithInt:count] stringValue]);
2364 [buttonbar_ setBadgeValue:badge forButton:3];
2365 [buttonbar_ setBadgeAnimated:YES forButton:3];
2366 [self setApplicationBadge:badge];
2368 [buttonbar_ setBadgeValue:nil forButton:3];
2369 [buttonbar_ setBadgeAnimated:NO forButton:3];
2370 [self removeApplicationBadge];
2375 [database_ prepare];
2376 confirm_ = [[ConfirmationView alloc] initWithView:underlay_ database:database_ delegate:self];
2380 [self reloadData:NO];
2386 [overlay_ removeFromSuperview];
2389 detachNewThreadSelector:@selector(perform)
2397 detachNewThreadSelector:@selector(update)
2403 - (void) progressViewIsComplete:(ProgressView *)progress {
2404 [self reloadData:YES];
2406 if (confirm_ != nil) {
2407 [underlay_ addSubview:overlay_];
2408 [confirm_ removeFromSuperview];
2414 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2421 _assert(alert_ == nil);
2423 alert_ = [[UIAlertSheet alloc]
2424 initWithTitle:@"About Cydia Packager"
2425 buttons:[NSArray arrayWithObjects:@"Close", nil]
2426 defaultButtonIndex:0
2431 [alert_ setBodyText:
2432 @"Copyright (C) 2007\n"
2433 "Jay Freeman (saurik)\n"
2434 "saurik@saurik.com\n"
2435 "http://www.saurik.com/\n"
2438 "http://www.theokorigroup.com/\n"
2440 "College of Creative Studies,\n"
2441 "University of California,\n"
2443 "http://www.ccs.ucsb.edu/\n"
2446 "bad_, BHSPitMonkey, Cobra, core,\n"
2447 "Corona, cromas, Darken, dtzWill,\n"
2448 "francis, Godores, jerry, Kingstone,\n"
2449 "lounger, rockabilly, tman, Wbiggs"
2452 [alert_ presentSheetFromButtonBar:buttonbar_];
2457 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
2463 - (void) buttonBarItemTapped:(id)sender {
2466 switch ([sender tag]) {
2467 case 1: view = featured_; break;
2468 case 2: view = install_; break;
2469 case 3: view = upgrade_; break;
2470 case 4: view = uninstall_; break;
2471 case 5: view = sources_; break;
2477 if ([view respondsToSelector:@selector(resetView)])
2478 [(id) view resetView];
2479 [transition_ transition:0 toView:view];
2482 - (void) view:(UIView *)view didSetFrame:(CGRect)frame oldFrame:(CGRect)old {
2483 [scroller_ setContentSize:frame.size];
2484 [indicator_ stopAnimation];
2487 - (void) applicationDidFinishLaunching:(id)unused {
2488 _assert(pkgInitConfig(*_config));
2489 _assert(pkgInitSystem(*_config, _system));
2494 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
2495 window_ = [[UIWindow alloc] initWithContentRect:screenrect];
2497 [window_ orderFront: self];
2498 [window_ makeKey: self];
2499 [window_ _setHidden: NO];
2501 progress_ = [[ProgressView alloc] initWithFrame:[window_ bounds] delegate:self];
2502 [window_ setContentView:progress_];
2504 underlay_ = [[UIView alloc] initWithFrame:[progress_ bounds]];
2505 [progress_ setContentView:underlay_];
2507 overlay_ = [[UIView alloc] initWithFrame:[underlay_ bounds]];
2508 [underlay_ addSubview:overlay_];
2510 transition_ = [[UITransitionView alloc] initWithFrame:CGRectMake(
2511 0, 0, screenrect.size.width, screenrect.size.height - 48
2514 [overlay_ addSubview:transition_];
2516 featured_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
2518 CGSize navsize = [UINavigationBar defaultSize];
2519 CGRect navrect = {{0, 0}, navsize};
2521 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
2522 [featured_ addSubview:navbar_];
2524 [navbar_ setBarStyle:1];
2525 [navbar_ setDelegate:self];
2527 [navbar_ showButtonsWithLeftTitle:@"About" rightTitle:@"Reload"];
2529 UINavigationItem *navitem = [[UINavigationItem alloc] initWithTitle:@"Featured"];
2530 [navbar_ pushNavigationItem:navitem];
2532 struct CGRect subbounds = [featured_ bounds];
2533 subbounds.origin.y += navsize.height;
2534 subbounds.size.height -= navsize.height;
2536 UIImageView *pinstripe = [[UIImageView alloc] initWithFrame:subbounds];
2537 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
2538 [featured_ addSubview:pinstripe];
2540 scroller_ = [[UIScroller alloc] initWithFrame:subbounds];
2541 [featured_ addSubview:scroller_];
2543 [scroller_ setScrollingEnabled:YES];
2544 [scroller_ setAdjustForContentSizeChange:YES];
2545 [scroller_ setClipsSubviews:YES];
2546 [scroller_ setAllowsRubberBanding:YES];
2547 [scroller_ setScrollDecelerationFactor:0.99];
2548 [scroller_ setDelegate:self];
2550 webview_ = [[UIWebView alloc] initWithFrame:[scroller_ bounds]];
2551 [scroller_ addSubview:webview_];
2553 [webview_ setTilingEnabled:YES];
2554 [webview_ setTileSize:CGSizeMake(screenrect.size.width, 500)];
2555 [webview_ setAutoresizes:YES];
2556 [webview_ setDelegate:self];
2558 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:2];
2559 indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(87, 15, indsize.width, indsize.height)];
2560 [indicator_ setStyle:2];
2561 [featured_ addSubview:indicator_];
2563 NSArray *buttonitems = [NSArray arrayWithObjects:
2564 [NSDictionary dictionaryWithObjectsAndKeys:
2565 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
2566 @"featured-up.png", kUIButtonBarButtonInfo,
2567 @"featured-dn.png", kUIButtonBarButtonSelectedInfo,
2568 [NSNumber numberWithInt:1], kUIButtonBarButtonTag,
2569 self, kUIButtonBarButtonTarget,
2570 @"Featured", kUIButtonBarButtonTitle,
2571 @"0", kUIButtonBarButtonType,
2574 [NSDictionary dictionaryWithObjectsAndKeys:
2575 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
2576 @"install-up.png", kUIButtonBarButtonInfo,
2577 @"install-dn.png", kUIButtonBarButtonSelectedInfo,
2578 [NSNumber numberWithInt:2], kUIButtonBarButtonTag,
2579 self, kUIButtonBarButtonTarget,
2580 @"Install", kUIButtonBarButtonTitle,
2581 @"0", kUIButtonBarButtonType,
2584 [NSDictionary dictionaryWithObjectsAndKeys:
2585 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
2586 @"upgrade-up.png", kUIButtonBarButtonInfo,
2587 @"upgrade-dn.png", kUIButtonBarButtonSelectedInfo,
2588 [NSNumber numberWithInt:3], kUIButtonBarButtonTag,
2589 self, kUIButtonBarButtonTarget,
2590 @"Upgrade", kUIButtonBarButtonTitle,
2591 @"0", kUIButtonBarButtonType,
2594 [NSDictionary dictionaryWithObjectsAndKeys:
2595 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
2596 @"uninstall-up.png", kUIButtonBarButtonInfo,
2597 @"uninstall-dn.png", kUIButtonBarButtonSelectedInfo,
2598 [NSNumber numberWithInt:4], kUIButtonBarButtonTag,
2599 self, kUIButtonBarButtonTarget,
2600 @"Uninstall", kUIButtonBarButtonTitle,
2601 @"0", kUIButtonBarButtonType,
2604 [NSDictionary dictionaryWithObjectsAndKeys:
2605 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
2606 @"sources-up.png", kUIButtonBarButtonInfo,
2607 @"sources-dn.png", kUIButtonBarButtonSelectedInfo,
2608 [NSNumber numberWithInt:5], kUIButtonBarButtonTag,
2609 self, kUIButtonBarButtonTarget,
2610 @"Sources", kUIButtonBarButtonTitle,
2611 @"0", kUIButtonBarButtonType,
2615 buttonbar_ = [[UIButtonBar alloc]
2617 withFrame:CGRectMake(
2618 0, screenrect.size.height - 48,
2619 screenrect.size.width, 48
2621 withItemList:buttonitems
2624 [buttonbar_ setDelegate:self];
2625 [buttonbar_ setBarStyle:1];
2626 [buttonbar_ setButtonBarTrackingMode:2];
2628 int buttons[5] = {1, 2, 3, 4, 5};
2629 [buttonbar_ registerButtonGroup:0 withButtons:buttons withCount:5];
2630 [buttonbar_ showButtonGroup:0 withDuration:0];
2632 for (int i = 0; i != 5; ++i)
2633 [[buttonbar_ viewWithTag:(i + 1)] setFrame:CGRectMake(
2634 i * 64 + 2, 1, 60, 48
2637 [buttonbar_ showSelectionForButton:1];
2638 [transition_ transition:0 toView:featured_];
2640 [overlay_ addSubview:buttonbar_];
2642 database_ = [[Database alloc] init];
2643 [database_ setDelegate:progress_];
2645 install_ = [[InstallView alloc] initWithFrame:[transition_ bounds] database:database_];
2646 [install_ setDelegate:self];
2648 upgrade_ = [[UpgradeView alloc] initWithFrame:[transition_ bounds] database:database_];
2649 [upgrade_ setDelegate:self];
2651 uninstall_ = [[UninstallView alloc] initWithFrame:[transition_ bounds] database:database_];
2652 [uninstall_ setDelegate:self];
2654 sources_ = [[SourcesView alloc] initWithFrame:[transition_ bounds] database:database_];
2655 [sources_ setDelegate:self];
2657 [self reloadData:NO];
2658 [progress_ resetView];
2660 Package *package([database_ packageWithName:@"cydia"]);
2661 NSString *application = package == nil ? @"Cydia" : [NSString stringWithFormat:@"Cydia/%@", [package installed]];
2662 WebView *webview = [webview_ webView];
2663 [webview setApplicationNameForUserAgent:application];
2665 url_ = [NSURL URLWithString:@"http://cydia.saurik.com/"];
2671 int main(int argc, char *argv[]) {
2672 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
2675 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
2676 char *machine = new char[size];
2677 sysctlbyname("hw.machine", machine, &size, NULL, 0);
2680 if (CFMutableDictionaryRef dict = IOServiceMatching("IOPlatformExpertDevice"))
2681 if (io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, dict)) {
2682 if (CFTypeRef serial = IORegistryEntryCreateCFProperty(service, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0)) {
2683 SerialNumber_ = strdup(CFStringGetCStringPtr((CFStringRef) serial, CFStringGetSystemEncoding()));
2687 IOObjectRelease(service);
2690 UIApplicationMain(argc, argv, [Cydia class]);