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) {
102 item.Owner->Status == pkgAcquire::Item::StatIdle ||
103 item.Owner->Status == pkgAcquire::Item::StatDone
107 [delegate_ setError:[NSString stringWithCString:item.Owner->ErrorText.c_str()]];
110 virtual bool Pulse(pkgAcquire *Owner) {
111 bool value = pkgAcquireStatus::Pulse(Owner);
114 double(CurrentBytes + CurrentItems) /
115 double(TotalBytes + TotalItems)
118 [delegate_ setPercent:percent];
122 virtual void Start() {
125 virtual void Stop() {
129 /* Progress Delegation {{{ */
137 virtual void Update() {
138 [delegate_ setTitle:[NSString stringWithCString:Op.c_str()]];
139 [delegate_ setPercent:(Percent / 100)];
148 void setDelegate(id delegate) {
149 delegate_ = delegate;
152 virtual void Done() {
153 [delegate_ setPercent:1];
158 /* External Constants {{{ */
159 extern NSString *kUIButtonBarButtonAction;
160 extern NSString *kUIButtonBarButtonInfo;
161 extern NSString *kUIButtonBarButtonInfoOffset;
162 extern NSString *kUIButtonBarButtonSelectedInfo;
163 extern NSString *kUIButtonBarButtonStyle;
164 extern NSString *kUIButtonBarButtonTag;
165 extern NSString *kUIButtonBarButtonTarget;
166 extern NSString *kUIButtonBarButtonTitle;
167 extern NSString *kUIButtonBarButtonTitleVerticalHeight;
168 extern NSString *kUIButtonBarButtonTitleWidth;
169 extern NSString *kUIButtonBarButtonType;
171 /* Mime Addresses {{{ */
172 @interface Address : NSObject {
180 - (NSString *) email;
182 + (Address *) addressWithString:(NSString *)string;
183 - (Address *) initWithString:(NSString *)string;
186 @implementation Address
195 - (NSString *) name {
199 - (NSString *) email {
203 + (Address *) addressWithString:(NSString *)string {
204 return [[[Address alloc] initWithString:string] autorelease];
207 - (Address *) initWithString:(NSString *)string {
208 if ((self = [super init]) != nil) {
211 pcre *code = pcre_compile("^\"?(.*)\"? <([^>]*)>$", 0, &error, &offset, NULL);
214 fprintf(stderr, "%d:%s\n", offset, error);
218 pcre_extra *study = NULL;
220 pcre_fullinfo(code, study, PCRE_INFO_CAPTURECOUNT, &capture);
221 int matches[(capture + 1) * 3];
223 size_t size = [string length];
224 const char *data = [string UTF8String];
226 if (pcre_exec(code, study, data, size, 0, 0, matches, sizeof(matches) / sizeof(matches[0])) >= 0) {
227 name_ = [[NSString stringWithCString:(data + matches[2]) length:(matches[3] - matches[2])] retain];
228 email_ = [[NSString stringWithCString:(data + matches[4]) length:(matches[5] - matches[4])] retain];
230 name_ = [[NSString stringWithCString:data length:size] retain];
239 /* Right Alignment {{{ */
240 @interface UIRightTextLabel : UITextLabel {
241 float _savedRightEdgeX;
242 BOOL _sizedtofit_flag;
245 - (void) setFrame:(CGRect)frame;
246 - (void) setText:(NSString *)text;
247 - (void) realignText;
250 @implementation UIRightTextLabel
252 - (void) setFrame:(CGRect)frame {
253 [super setFrame:frame];
254 if (_sizedtofit_flag == NO) {
255 _savedRightEdgeX = frame.origin.x;
260 - (void) setText:(NSString *)text {
261 [super setText:text];
265 - (void) realignText {
266 CGRect oldFrame = [self frame];
268 _sizedtofit_flag = YES;
269 [self sizeToFit]; // shrink down size so I can right align it
271 CGRect newFrame = [self frame];
273 oldFrame.origin.x = _savedRightEdgeX - newFrame.size.width;
274 oldFrame.size.width = newFrame.size.width;
275 [super setFrame:oldFrame];
276 _sizedtofit_flag = NO;
281 /* Linear Algebra {{{ */
282 inline float interpolate(float begin, float end, float fraction) {
283 return (end - begin) * fraction + begin;
289 @interface Database : NSObject {
291 pkgRecords *records_;
292 pkgProblemResolver *resolver_;
293 pkgAcquire *fetcher_;
295 SPtr<pkgPackageManager> manager_;
303 - (void) _readStatus:(NSNumber *)fd;
304 - (void) _readOutput:(NSNumber *)fd;
306 - (Package *) packageWithName:(NSString *)name;
309 - (pkgCacheFile &) cache;
310 - (pkgRecords *) records;
311 - (pkgProblemResolver *) resolver;
312 - (pkgAcquire &) fetcher;
320 - (void) setDelegate:(id)delegate;
324 @interface ResetView : UIView {
325 UINavigationBar *navbar_;
329 - (void) navigationBar:(UINavigationBar *)navbar poppedItem:(UINavigationItem *)item;
334 - (NSString *) leftTitle;
335 - (NSString *) rightTitle;
338 @implementation ResetView
340 - (void) navigationBar:(UINavigationBar *)navbar poppedItem:(UINavigationItem *)item {
341 if ([[navbar_ navigationItems] count] == 1)
352 if ([[navbar_ navigationItems] count] == 1)
354 else while ([[navbar_ navigationItems] count] != 1)
355 [navbar_ popNavigationItem];
359 - (void) _resetView {
360 [navbar_ showButtonsWithLeftTitle:[self leftTitle] rightTitle:[self rightTitle]];
363 - (NSString *) leftTitle {
367 - (NSString *) rightTitle {
373 /* Confirmation View {{{ */
374 void AddTextView(NSMutableDictionary *fields, NSMutableArray *packages, NSString *key) {
375 if ([packages count] == 0)
378 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
379 float clear[] = {0, 0, 0, 0};
380 float blue[] = {0, 0, 0.4, 1};
382 UITextView *text([[[UITextView alloc] initWithFrame: CGRectMake(110, 3, 200, 60)] autorelease]);
383 [text setEditable:NO];
384 [text setTextSize:16];
385 [text setBackgroundColor:CGColorCreate(space, clear)];
386 [text setTextColor:CGColorCreate(space, blue)];
387 [text setText:([packages count] == 0 ? @"n/a" : [packages componentsJoinedByString:@", "])];
388 [text setEnabled:NO];
390 CGRect frame([text frame]);
391 CGSize size([text contentSize]);
392 frame.size.height = size.height;
393 [text setFrame:frame];
395 [fields setObject:text forKey:key];
398 @protocol ConfirmationViewDelegate
403 @interface ConfirmationView : UIView {
406 UITransitionView *transition_;
408 UINavigationBar *navbar_;
409 UIPreferencesTable *table_;
410 NSMutableDictionary *fields_;
411 UIAlertSheet *essential_;
417 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
418 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
419 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
421 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table;
422 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group;
423 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed;
424 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group;
425 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group;
427 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate;
431 @implementation ConfirmationView
434 [transition_ release];
439 if (essential_ != nil)
440 [essential_ release];
445 [transition_ transition:7 toView:nil];
449 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
450 if (from != nil && to == nil)
451 [self removeFromSuperview];
454 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
457 if (essential_ != nil)
458 [essential_ popupAlertAnimated:YES];
469 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
470 [essential_ dismiss];
474 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
478 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
480 case 0: return @"Statistics";
481 case 1: return @"Modifications";
483 default: _assert(false);
487 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
490 case 1: return [fields_ count];
492 default: _assert(false);
496 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
497 if (group != 1 || row == -1)
500 _assert(size_t(row) < [fields_ count]);
501 return [[[fields_ allValues] objectAtIndex:row] contentSize].height;
505 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
506 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
507 [cell setShowSelection:NO];
510 case 0: switch (row) {
512 [cell setTitle:@"Downloading"];
513 [cell setValue:SizeString([database_ fetcher].FetchNeeded())];
517 [cell setTitle:@"Resuming At"];
518 [cell setValue:SizeString([database_ fetcher].PartialPresent())];
522 double size([database_ cache]->UsrSize());
525 [cell setTitle:@"Disk Freeing"];
526 [cell setValue:SizeString(-size)];
528 [cell setTitle:@"Disk Using"];
529 [cell setValue:SizeString(size)];
533 default: _assert(false);
537 _assert(size_t(row) < [fields_ count]);
538 [cell setTitle:[[fields_ allKeys] objectAtIndex:row]];
539 [cell addSubview:[[fields_ allValues] objectAtIndex:row]];
542 default: _assert(false);
548 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate {
549 if ((self = [super initWithFrame:[view bounds]]) != nil) {
550 database_ = database;
551 delegate_ = delegate;
553 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
554 [self addSubview:transition_];
556 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
558 CGSize navsize = [UINavigationBar defaultSize];
559 CGRect navrect = {{0, 0}, navsize};
560 CGRect bounds = [overlay_ bounds];
562 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
563 [navbar_ setBarStyle:1];
564 [navbar_ setDelegate:self];
566 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Confirm"] autorelease];
567 [navbar_ pushNavigationItem:navitem];
568 [navbar_ showButtonsWithLeftTitle:@"Cancel" rightTitle:@"Confirm"];
570 fields_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
572 NSMutableArray *installing = [NSMutableArray arrayWithCapacity:16];
573 NSMutableArray *upgrading = [NSMutableArray arrayWithCapacity:16];
574 NSMutableArray *removing = [NSMutableArray arrayWithCapacity:16];
576 bool essential(false);
578 pkgCacheFile &cache([database_ cache]);
579 for (pkgCache::PkgIterator iterator = cache->PkgBegin(); !iterator.end(); ++iterator) {
580 NSString *name([NSString stringWithCString:iterator.Name()]);
581 if (cache[iterator].NewInstall())
582 [installing addObject:name];
583 else if (cache[iterator].Upgrade())
584 [upgrading addObject:name];
585 else if (cache[iterator].Delete()) {
586 [removing addObject:name];
587 if ((iterator->Flags & pkgCache::Flag::Essential) != 0)
595 essential_ = [[UIAlertSheet alloc]
596 initWithTitle:@"Unable to Comply"
597 buttons:[NSArray arrayWithObjects:@"Okay", nil]
603 [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."];
606 AddTextView(fields_, installing, @"Installing");
607 AddTextView(fields_, upgrading, @"Upgrading");
608 AddTextView(fields_, removing, @"Removing");
610 table_ = [[UIPreferencesTable alloc] initWithFrame:CGRectMake(
611 0, navsize.height, bounds.size.width, bounds.size.height - navsize.height
614 [table_ setReusesTableCells:YES];
615 [table_ setDataSource:self];
618 [overlay_ addSubview:navbar_];
619 [overlay_ addSubview:table_];
621 [view addSubview:self];
623 [transition_ setDelegate:self];
625 UIView *blank = [[[UIView alloc] initWithFrame:[transition_ bounds]] autorelease];
626 [transition_ transition:0 toView:blank];
627 [transition_ transition:3 toView:overlay_];
634 /* Package Class {{{ */
635 @interface Package : NSObject {
636 pkgCache::PkgIterator iterator_;
638 pkgRecords::Parser *parser_;
639 pkgCache::VerIterator version_;
640 pkgCache::VerFileIterator file_;
643 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database version:(pkgCache::VerIterator)version file:(pkgCache::VerFileIterator)file;
644 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
647 - (NSString *) section;
648 - (NSString *) latest;
649 - (NSString *) installed;
650 - (Address *) maintainer;
652 - (NSString *) tagline;
653 - (NSString *) description;
654 - (NSComparisonResult) compareBySectionAndName:(Package *)package;
660 @implementation Package
662 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database version:(pkgCache::VerIterator)version file:(pkgCache::VerFileIterator)file {
663 if ((self = [super init]) != nil) {
664 iterator_ = iterator;
665 database_ = database;
669 parser_ = &[database_ records]->Lookup(file);
673 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
674 for (pkgCache::VerIterator version = iterator.VersionList(); !version.end(); ++version)
675 for (pkgCache::VerFileIterator file = version.FileList(); !file.end(); ++file)
676 return [[[Package alloc]
677 initWithIterator:iterator
685 - (NSString *) name {
686 return [[NSString stringWithCString:iterator_.Name()] lowercaseString];
689 - (NSString *) section {
690 return [NSString stringWithCString:iterator_.Section()];
693 - (NSString *) latest {
694 return [NSString stringWithCString:version_.VerStr()];
697 - (NSString *) installed {
698 return iterator_.CurrentVer().end() ? nil : [NSString stringWithCString:iterator_.CurrentVer().VerStr()];
701 - (Address *) maintainer {
702 return [Address addressWithString:[NSString stringWithCString:parser_->Maintainer().c_str()]];
706 return version_->InstalledSize;
709 - (NSString *) tagline {
710 return [NSString stringWithCString:parser_->ShortDesc().c_str()];
713 - (NSString *) description {
714 return [NSString stringWithCString:parser_->LongDesc().c_str()];
717 - (NSComparisonResult) compareBySectionAndName:(Package *)package {
718 NSComparisonResult result = [[self section] compare:[package section]];
719 if (result != NSOrderedSame)
721 return [[self name] compare:[package name]];
725 pkgProblemResolver *resolver = [database_ resolver];
726 resolver->Clear(iterator_);
727 resolver->Protect(iterator_);
728 [database_ cache]->MarkInstall(iterator_, false);
732 pkgProblemResolver *resolver = [database_ resolver];
733 resolver->Clear(iterator_);
734 resolver->Protect(iterator_);
735 resolver->Remove(iterator_);
736 [database_ cache]->MarkDelete(iterator_, true);
741 /* Section Class {{{ */
742 @interface Section : NSObject {
745 NSMutableArray *packages_;
750 - (Section *) initWithName:(NSString *)name row:(size_t)row;
753 - (void) addPackage:(Package *)package;
756 @implementation Section
764 - (Section *) initWithName:(NSString *)name row:(size_t)row {
765 if ((self = [super init]) != nil) {
766 name_ = [name retain];
768 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
772 - (NSString *) name {
780 - (void) addPackage:(Package *)package {
781 [packages_ addObject:package];
787 /* Package View {{{ */
788 @interface PackageView : UIView {
789 UIPreferencesTable *table_;
792 NSMutableArray *cells_;
798 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table;
799 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group;
800 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group;
801 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group;
803 - (BOOL) canSelectRow:(int)row;
804 - (void) tableRowSelected:(NSNotification *)notification;
806 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database;
807 - (void) setPackage:(Package *)package;
808 - (void) setDelegate:(id)delegate;
811 @implementation PackageView
822 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
826 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
828 case 0: return @"Specifics";
829 case 1: return @"Description";
831 default: _assert(false);
835 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
840 default: _assert(false);
844 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
845 UIPreferencesTableCell *cell;
848 case 0: switch (row) {
850 cell = [cells_ objectAtIndex:0];
851 [cell setTitle:@"Name"];
852 [cell setValue:[package_ name]];
856 cell = [cells_ objectAtIndex:1];
857 [cell setTitle:@"Installed"];
858 NSString *installed([package_ installed]);
859 [cell setValue:(installed == nil ? @"n/a" : installed)];
863 cell = [cells_ objectAtIndex:2];
864 [cell setTitle:@"Latest"];
865 [cell setValue:[package_ latest]];
869 cell = [cells_ objectAtIndex:3];
870 [cell setTitle:@"Section"];
871 [cell setValue:[package_ section]];
875 cell = [cells_ objectAtIndex:4];
876 [cell setTitle:@"Size"];
877 [cell setValue:SizeString([package_ size])];
881 cell = [cells_ objectAtIndex:5];
882 [cell setTitle:@"Maintainer"];
883 [cell setValue:[[package_ maintainer] name]];
884 [cell setShowDisclosure:YES];
885 [cell setShowSelection:YES];
888 default: _assert(false);
891 case 1: switch (row) {
893 cell = [cells_ objectAtIndex:6];
895 [cell setValue:[package_ tagline]];
899 cell = [cells_ objectAtIndex:7];
900 [cell setTitle:@"Description"];
901 [cell setValue:[package_ description]];
905 default: _assert(false);
911 - (BOOL) canSelectRow:(int)row {
915 - (void) tableRowSelected:(NSNotification *)notification {
916 switch ([table_ selectedRow]) {
918 [delegate_ openURL:[NSURL URLWithString:[NSString stringWithFormat:@"mailto:%@?subject=%@",
919 [[package_ maintainer] email],
920 [[NSString stringWithFormat:@"regarding apt package \"%@\"", [package_ name]] stringByAddingPercentEscapes]
926 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database {
927 if ((self = [super initWithFrame:frame]) != nil) {
928 database_ = [database retain];
930 table_ = [[UIPreferencesTable alloc] initWithFrame:[self bounds]];
931 [self addSubview:table_];
933 [table_ setDataSource:self];
934 [table_ setDelegate:self];
936 cells_ = [[NSMutableArray arrayWithCapacity:16] retain];
938 for (unsigned i = 0; i != 8; ++i) {
939 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
940 [cell setShowSelection:NO];
941 [cells_ addObject:cell];
946 - (void) setPackage:(Package *)package {
947 package_ = [package retain];
951 - (void) setDelegate:(id)delegate {
952 delegate_ = delegate;
957 /* Package Cell {{{ */
958 @protocol PackageCellDelegate
959 - (NSString *) versionWithPackage:(Package *)package;
962 @interface PackageCell : UITableCell {
964 UIRightTextLabel *version_;
965 UITextLabel *description_;
971 - (PackageCell *) initWithDelegate:(id)delegate;
972 - (void) setPackage:(Package *)package;
974 - (void) _setSelected:(float)fraction;
975 - (void) setSelected:(BOOL)selected;
976 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
977 - (void) _setSelectionFadeFraction:(float)fraction;
981 @implementation PackageCell
986 [description_ release];
990 - (PackageCell *) initWithDelegate:(id)delegate {
991 if ((self = [super init]) != nil) {
992 delegate_ = delegate;
994 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22);
995 GSFontRef large = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
996 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 14);
998 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
999 float clear[] = {0, 0, 0, 0};
1001 name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(12, 7, 250, 25)];
1002 [name_ setBackgroundColor:CGColorCreate(space, clear)];
1003 [name_ setFont:bold];
1005 version_ = [[UIRightTextLabel alloc] initWithFrame:CGRectMake(290, 7, 70, 25)];
1006 [version_ setBackgroundColor:CGColorCreate(space, clear)];
1007 [version_ setFont:large];
1009 description_ = [[UITextLabel alloc] initWithFrame:CGRectMake(13, 35, 315, 20)];
1010 [description_ setBackgroundColor:CGColorCreate(space, clear)];
1011 [description_ setFont:small];
1013 [self addSubview:name_];
1014 [self addSubview:version_];
1015 [self addSubview:description_];
1023 - (void) setPackage:(Package *)package {
1024 [name_ setText:[package name]];
1025 [version_ setText:[delegate_ versionWithPackage:package]];
1026 [description_ setText:[package tagline]];
1029 - (void) _setSelected:(float)fraction {
1030 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1033 interpolate(0.0, 1.0, fraction),
1034 interpolate(0.0, 1.0, fraction),
1035 interpolate(0.0, 1.0, fraction),
1039 interpolate(0.2, 1.0, fraction),
1040 interpolate(0.2, 1.0, fraction),
1041 interpolate(1.0, 1.0, fraction),
1045 interpolate(0.4, 1.0, fraction),
1046 interpolate(0.4, 1.0, fraction),
1047 interpolate(0.4, 1.0, fraction),
1050 [name_ setColor:CGColorCreate(space, black)];
1051 [version_ setColor:CGColorCreate(space, blue)];
1052 [description_ setColor:CGColorCreate(space, gray)];
1055 - (void) setSelected:(BOOL)selected {
1056 [self _setSelected:(selected ? 1.0 : 0.0)];
1057 [super setSelected:selected];
1060 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
1062 [self _setSelected:(selected ? 1.0 : 0.0)];
1063 [super setSelected:selected withFade:fade];
1066 - (void) _setSelectionFadeFraction:(float)fraction {
1067 [self _setSelected:fraction];
1068 [super _setSelectionFadeFraction:fraction];
1075 @interface Source : NSObject {
1076 NSString *description_;
1081 NSString *distribution_;
1089 - (Source *) initWithMetaIndex:(metaIndex *)index;
1094 - (NSString *) distribution;
1095 - (NSString *) type;
1097 - (NSString *) description;
1098 - (NSString *) label;
1099 - (NSString *) origin;
1102 @implementation Source
1106 [distribution_ release];
1109 if (description_ != nil)
1110 [description_ release];
1119 - (Source *) initWithMetaIndex:(metaIndex *)index {
1120 if ((self = [super init]) != nil) {
1121 trusted_ = index->IsTrusted();
1123 uri_ = [[NSString stringWithCString:index->GetURI().c_str()] retain];
1124 distribution_ = [[NSString stringWithCString:index->GetDist().c_str()] retain];
1125 type_ = [[NSString stringWithCString:index->GetType()] retain];
1131 debReleaseIndex *dindex(dynamic_cast<debReleaseIndex *>(index));
1132 if (dindex != NULL) {
1133 std::ifstream release(dindex->MetaIndexFile("Release").c_str());
1135 while (std::getline(release, line)) {
1136 std::string::size_type colon(line.find(':'));
1137 if (colon == std::string::npos)
1140 std::string name(line.substr(0, colon));
1141 std::string value(line.substr(colon + 1));
1142 while (!value.empty() && value[0] == ' ')
1143 value = value.substr(1);
1145 if (name == "Description")
1146 description_ = [[NSString stringWithCString:value.c_str()] retain];
1147 else if (name == "Label")
1148 label_ = [[NSString stringWithCString:value.c_str()] retain];
1149 else if (name == "Origin")
1150 origin_ = [[NSString stringWithCString:value.c_str()] retain];
1160 - (NSString *) uri {
1164 - (NSString *) distribution {
1165 return distribution_;
1168 - (NSString *) type {
1172 - (NSString *) description {
1173 return description_;
1176 - (NSString *) label {
1180 - (NSString *) origin {
1186 /* Source Cell {{{ */
1187 @interface SourceCell : UITableCell {
1188 UITextLabel *description_;
1189 UIRightTextLabel *label_;
1190 UITextLabel *origin_;
1195 - (SourceCell *) initWithSource:(Source *)source;
1197 - (void) _setSelected:(float)fraction;
1198 - (void) setSelected:(BOOL)selected;
1199 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
1200 - (void) _setSelectionFadeFraction:(float)fraction;
1204 @implementation SourceCell
1207 [description_ release];
1213 - (SourceCell *) initWithSource:(Source *)source {
1214 if ((self = [super init]) != nil) {
1215 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 20);
1216 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 14);
1218 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1219 float clear[] = {0, 0, 0, 0};
1221 NSString *description = [source description];
1222 if (description == nil)
1223 description = [source uri];
1225 description_ = [[UITextLabel alloc] initWithFrame:CGRectMake(12, 7, 270, 25)];
1226 [description_ setBackgroundColor:CGColorCreate(space, clear)];
1227 [description_ setFont:bold];
1228 [description_ setText:description];
1230 NSString *label = [source label];
1232 label = [source type];
1234 label_ = [[UIRightTextLabel alloc] initWithFrame:CGRectMake(290, 32, 90, 25)];
1235 [label_ setBackgroundColor:CGColorCreate(space, clear)];
1236 [label_ setFont:small];
1237 [label_ setText:label];
1239 NSString *origin = [source origin];
1241 origin = [source distribution];
1243 origin_ = [[UITextLabel alloc] initWithFrame:CGRectMake(13, 35, 315, 20)];
1244 [origin_ setBackgroundColor:CGColorCreate(space, clear)];
1245 [origin_ setFont:small];
1246 [origin_ setText:origin];
1248 [self addSubview:description_];
1249 [self addSubview:label_];
1250 [self addSubview:origin_];
1257 - (void) _setSelected:(float)fraction {
1258 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1261 interpolate(0.0, 1.0, fraction),
1262 interpolate(0.0, 1.0, fraction),
1263 interpolate(0.0, 1.0, fraction),
1267 interpolate(0.2, 1.0, fraction),
1268 interpolate(0.2, 1.0, fraction),
1269 interpolate(1.0, 1.0, fraction),
1273 interpolate(0.4, 1.0, fraction),
1274 interpolate(0.4, 1.0, fraction),
1275 interpolate(0.4, 1.0, fraction),
1278 [description_ setColor:CGColorCreate(space, black)];
1279 [label_ setColor:CGColorCreate(space, blue)];
1280 [origin_ setColor:CGColorCreate(space, gray)];
1283 - (void) setSelected:(BOOL)selected {
1284 [self _setSelected:(selected ? 1.0 : 0.0)];
1285 [super setSelected:selected];
1288 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
1290 [self _setSelected:(selected ? 1.0 : 0.0)];
1291 [super setSelected:selected withFade:fade];
1294 - (void) _setSelectionFadeFraction:(float)fraction {
1295 [self _setSelected:fraction];
1296 [super _setSelectionFadeFraction:fraction];
1301 /* Sources View {{{ */
1302 @interface SourcesView : ResetView {
1303 UISectionList *list_;
1304 Database *database_;
1306 NSMutableArray *sources_;
1307 UIAlertSheet *alert_;
1310 - (int) numberOfSectionsInSectionList:(UISectionList *)list;
1311 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section;
1312 - (int) sectionList:(UISectionList *)list rowForSection:(int)section;
1314 - (int) numberOfRowsInTable:(UITable *)table;
1315 - (float) table:(UITable *)table heightForRow:(int)row;
1316 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col;
1317 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row;
1318 - (void) tableRowSelected:(NSNotification*)notification;
1320 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
1323 - (id) initWithFrame:(CGRect)frame database:(Database *)database;
1324 - (void) setDelegate:(id)delegate;
1325 - (void) reloadData;
1326 - (NSString *) leftTitle;
1327 - (NSString *) rightTitle;
1330 @implementation SourcesView
1332 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
1336 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
1340 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
1344 - (int) numberOfRowsInTable:(UITable *)table {
1345 return [sources_ count];
1348 - (float) table:(UITable *)table heightForRow:(int)row {
1352 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col {
1353 return [[[SourceCell alloc] initWithSource:[sources_ objectAtIndex:row]] autorelease];
1356 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
1360 - (void) tableRowSelected:(NSNotification*)notification {
1361 UITable *table([list_ table]);
1362 int row([table selectedRow]);
1366 [table selectRow:-1 byExtendingSelection:NO withFade:YES];
1369 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
1375 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
1378 alert_ = [[UIAlertSheet alloc]
1379 initWithTitle:@"Unimplemented"
1380 buttons:[NSArray arrayWithObjects:@"Okay", nil]
1381 defaultButtonIndex:0
1386 [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."];
1387 [alert_ popupAlertAnimated:YES];
1397 if (sources_ != nil)
1403 - (id) initWithFrame:(CGRect)frame database:(Database *)database {
1404 if ((self = [super initWithFrame:frame]) != nil) {
1405 database_ = database;
1408 CGSize navsize = [UINavigationBar defaultSize];
1409 CGRect navrect = {{0, 0}, navsize};
1410 CGRect bounds = [self bounds];
1412 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
1413 [self addSubview:navbar_];
1415 [navbar_ setBarStyle:1];
1416 [navbar_ setDelegate:self];
1418 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Sources"] autorelease];
1419 [navbar_ pushNavigationItem:navitem];
1421 list_ = [[UISectionList alloc] initWithFrame:CGRectMake(
1422 0, navsize.height, bounds.size.width, bounds.size.height - navsize.height
1425 [self addSubview:list_];
1427 [list_ setDataSource:self];
1428 [list_ setShouldHideHeaderInShortLists:NO];
1430 UITableColumn *column = [[UITableColumn alloc]
1431 initWithTitle:@"Name"
1433 width:frame.size.width
1436 UITable *table = [list_ table];
1437 [table setSeparatorStyle:1];
1438 [table addTableColumn:column];
1439 [table setDelegate:self];
1443 - (void) setDelegate:(id)delegate {
1444 delegate_ = delegate;
1447 - (void) reloadData {
1449 _assert(list.ReadMainList());
1451 if (sources_ != nil)
1454 sources_ = [[NSMutableArray arrayWithCapacity:16] retain];
1455 for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source)
1456 [sources_ addObject:[[[Source alloc] initWithMetaIndex:*source] autorelease]];
1462 - (NSString *) leftTitle {
1463 return @"Refresh All";
1466 - (NSString *) rightTitle {
1473 @implementation Database
1475 - (void) _readStatus:(NSNumber *)fd {
1476 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1478 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1479 std::istream is(&ib);
1484 pcre *code = pcre_compile("^([^:]*):([^:]*):([^:]*):(.*)$", 0, &error, &offset, NULL);
1486 pcre_extra *study = NULL;
1488 pcre_fullinfo(code, study, PCRE_INFO_CAPTURECOUNT, &capture);
1489 int matches[(capture + 1) * 3];
1491 while (std::getline(is, line)) {
1492 const char *data(line.c_str());
1494 _assert(pcre_exec(code, study, data, line.size(), 0, 0, matches, sizeof(matches) / sizeof(matches[0])) >= 0);
1496 std::istringstream buffer(line.substr(matches[6], matches[7] - matches[6]));
1499 [delegate_ setPercent:(percent / 100)];
1501 NSString *string = [NSString stringWithCString:(data + matches[8]) length:(matches[9] - matches[8])];
1502 std::string type(line.substr(matches[2], matches[3] - matches[2]));
1504 if (type == "pmerror")
1505 [delegate_ setError:string];
1506 else if (type == "pmstatus")
1507 [delegate_ setTitle:string];
1508 else if (type == "pmconffile")
1510 else _assert(false);
1516 - (void) _readOutput:(NSNumber *)fd {
1517 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1519 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1520 std::istream is(&ib);
1523 while (std::getline(is, line))
1524 [delegate_ addOutput:[NSString stringWithCString:line.c_str()]];
1529 - (Package *) packageWithName:(NSString *)name {
1530 pkgCache::PkgIterator iterator(cache_->FindPkg([name cString]));
1531 return iterator.end() ? nil : [Package packageWithIterator:iterator database:self];
1534 - (Database *) init {
1535 if ((self = [super init]) != nil) {
1543 _assert(pipe(fds) != -1);
1547 detachNewThreadSelector:@selector(_readStatus:)
1549 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1552 _assert(pipe(fds) != -1);
1553 _assert(dup2(fds[1], 1) != -1);
1554 _assert(close(fds[1]) != -1);
1557 detachNewThreadSelector:@selector(_readOutput:)
1559 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1564 - (pkgCacheFile &) cache {
1568 - (pkgRecords *) records {
1572 - (pkgProblemResolver *) resolver {
1576 - (pkgAcquire &) fetcher {
1580 - (void) reloadData {
1588 cache_.Open(progress_, true);
1589 records_ = new pkgRecords(cache_);
1590 resolver_ = new pkgProblemResolver(cache_);
1591 fetcher_ = new pkgAcquire(&status_);
1596 pkgRecords records(cache_);
1598 lock_ = new FileFd();
1599 lock_->Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1600 _assert(!_error->PendingError());
1603 _assert(list.ReadMainList());
1605 manager_ = (_system->CreatePM(cache_));
1606 _assert(manager_->GetArchives(fetcher_, &list, &records));
1607 _assert(!_error->PendingError());
1611 if (fetcher_->Run(PulseInterval_) != pkgAcquire::Continue)
1615 pkgPackageManager::OrderResult result = manager_->DoInstall(statusfd_);
1617 if (result == pkgPackageManager::Failed)
1619 if (_error->PendingError())
1621 if (result != pkgPackageManager::Completed)
1627 _assert(list.ReadMainList());
1630 lock.Fd(GetLock(_config->FindDir("Dir::State::Lists") + "lock"));
1631 _assert(!_error->PendingError());
1633 pkgAcquire fetcher(&status_);
1634 _assert(list.GetIndexes(&fetcher));
1635 _assert(fetcher.Run(PulseInterval_) != pkgAcquire::Failed);
1637 bool failed = false;
1638 for (pkgAcquire::ItemIterator item = fetcher.ItemsBegin(); item != fetcher.ItemsEnd(); item++)
1639 if ((*item)->Status != pkgAcquire::Item::StatDone) {
1640 (*item)->Finished();
1644 if (!failed && _config->FindB("APT::Get::List-Cleanup", true) == true) {
1645 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists")));
1646 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/"));
1651 _assert(cache_->DelCount() == 0 && cache_->InstCount() == 0);
1652 _assert(pkgApplyStatus(cache_));
1654 if (cache_->BrokenCount() != 0) {
1655 _assert(pkgFixBroken(cache_));
1656 _assert(cache_->BrokenCount() == 0);
1657 _assert(pkgMinimizeUpgrade(cache_));
1660 _assert(pkgDistUpgrade(cache_));
1663 - (void) setDelegate:(id)delegate {
1664 delegate_ = delegate;
1665 status_.setDelegate(delegate);
1666 progress_.setDelegate(delegate);
1671 /* Progress Data {{{ */
1672 @interface ProgressData : NSObject {
1678 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object;
1685 @implementation ProgressData
1687 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object {
1688 if ((self = [super init]) != nil) {
1689 selector_ = selector;
1709 /* Progress View {{{ */
1710 @interface ProgressView : UIView <
1714 UIView *background_;
1715 UITransitionView *transition_;
1717 UINavigationBar *navbar_;
1718 UIProgressBar *progress_;
1719 UITextView *output_;
1720 UITextLabel *status_;
1726 - (ProgressView *) initWithFrame:(struct CGRect)frame delegate:(id)delegate;
1727 - (void) setContentView:(UIView *)view;
1730 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
1732 - (void) _retachThread;
1733 - (void) _detachNewThreadData:(ProgressData *)data;
1734 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object;
1736 - (void) setError:(NSString *)error;
1737 - (void) _setError:(NSString *)error;
1739 - (void) setTitle:(NSString *)title;
1740 - (void) _setTitle:(NSString *)title;
1742 - (void) setPercent:(float)percent;
1743 - (void) _setPercent:(NSNumber *)percent;
1745 - (void) addOutput:(NSString *)output;
1746 - (void) _addOutput:(NSString *)output;
1749 @protocol ProgressViewDelegate
1750 - (void) progressViewIsComplete:(ProgressView *)sender;
1753 @implementation ProgressView
1757 [background_ release];
1758 [transition_ release];
1761 [progress_ release];
1767 - (ProgressView *) initWithFrame:(struct CGRect)frame delegate:(id)delegate {
1768 if ((self = [super initWithFrame:frame]) != nil) {
1769 delegate_ = delegate;
1771 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1772 float black[] = {0.0, 0.0, 0.0, 1.0};
1773 float white[] = {1.0, 1.0, 1.0, 1.0};
1774 float clear[] = {0.0, 0.0, 0.0, 0.0};
1776 background_ = [[UIView alloc] initWithFrame:[self bounds]];
1777 [background_ setBackgroundColor:CGColorCreate(space, black)];
1778 [self addSubview:background_];
1780 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
1781 [self addSubview:transition_];
1783 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
1785 CGSize navsize = [UINavigationBar defaultSize];
1786 CGRect navrect = {{0, 0}, navsize};
1788 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
1789 [overlay_ addSubview:navbar_];
1791 [navbar_ setBarStyle:1];
1792 [navbar_ setDelegate:self];
1794 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Running..."] autorelease];
1795 [navbar_ pushNavigationItem:navitem];
1797 CGRect bounds = [overlay_ bounds];
1798 CGSize prgsize = [UIProgressBar defaultSize];
1801 (bounds.size.width - prgsize.width) / 2,
1802 bounds.size.height - prgsize.height - 20
1805 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
1806 [overlay_ addSubview:progress_];
1808 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(
1810 bounds.size.height - prgsize.height - 50,
1811 bounds.size.width - 20,
1815 [status_ setColor:CGColorCreate(space, white)];
1816 [status_ setBackgroundColor:CGColorCreate(space, clear)];
1818 [status_ setCentersHorizontally:YES];
1819 //[status_ setFont:font];
1821 output_ = [[UITextView alloc] initWithFrame:CGRectMake(
1823 navrect.size.height + 20,
1824 bounds.size.width - 20,
1825 bounds.size.height - navsize.height - 62 - navrect.size.height
1828 //[output_ setTextFont:@"Courier New"];
1829 [output_ setTextSize:12];
1831 [output_ setTextColor:CGColorCreate(space, white)];
1832 [output_ setBackgroundColor:CGColorCreate(space, clear)];
1834 [output_ setMarginTop:0];
1835 [output_ setAllowsRubberBanding:YES];
1837 [overlay_ addSubview:output_];
1838 [overlay_ addSubview:status_];
1840 [progress_ setStyle:0];
1844 - (void) setContentView:(UIView *)view {
1848 - (void) resetView {
1849 [transition_ transition:6 toView:view_];
1852 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
1856 - (void) _retachThread {
1857 [delegate_ progressViewIsComplete:self];
1861 - (void) _detachNewThreadData:(ProgressData *)data {
1862 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1864 [[data target] performSelector:[data selector] withObject:[data object]];
1865 [self performSelectorOnMainThread:@selector(_retachThread) withObject:nil waitUntilDone:YES];
1871 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object {
1872 [status_ setText:nil];
1873 [output_ setText:@""];
1874 [progress_ setProgress:0];
1876 [transition_ transition:6 toView:overlay_];
1879 detachNewThreadSelector:@selector(_detachNewThreadData:)
1881 withObject:[[ProgressData alloc]
1882 initWithSelector:selector
1889 - (void) setError:(NSString *)error {
1891 performSelectorOnMainThread:@selector(_setError:)
1897 - (void) _setError:(NSString *)error {
1898 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
1899 initWithTitle:@"Package Error"
1900 buttons:[NSArray arrayWithObjects:@"Okay", nil]
1901 defaultButtonIndex:0
1906 [sheet setBodyText:error];
1907 [sheet popupAlertAnimated:YES];
1910 - (void) setTitle:(NSString *)title {
1912 performSelectorOnMainThread:@selector(_setTitle:)
1918 - (void) _setTitle:(NSString *)title {
1919 [status_ setText:[title stringByAppendingString:@"..."]];
1922 - (void) setPercent:(float)percent {
1924 performSelectorOnMainThread:@selector(_setPercent:)
1925 withObject:[NSNumber numberWithFloat:percent]
1930 - (void) _setPercent:(NSNumber *)percent {
1931 [progress_ setProgress:[percent floatValue]];
1934 - (void) addOutput:(NSString *)output {
1936 performSelectorOnMainThread:@selector(_addOutput:)
1942 - (void) _addOutput:(NSString *)output {
1943 [output_ setText:[NSString stringWithFormat:@"%@\n%@", [output_ text], output]];
1944 CGSize size = [output_ contentSize];
1945 CGRect rect = {{0, size.height}, {size.width, 0}};
1946 [output_ scrollRectToVisible:rect animated:YES];
1952 @protocol PackagesViewDelegate
1955 - (void) openURL:(NSString *)url;
1958 /* PackagesView {{{ */
1959 @interface PackagesView : ResetView <
1962 Database *database_;
1963 NSMutableArray *packages_;
1964 NSMutableArray *sections_;
1966 UISectionList *list_;
1967 UITransitionView *transition_;
1970 PackageView *pkgview_;
1973 - (int) numberOfSectionsInSectionList:(UISectionList *)list;
1974 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section;
1975 - (int) sectionList:(UISectionList *)list rowForSection:(int)section;
1977 - (int) numberOfRowsInTable:(UITable *)table;
1978 - (float) table:(UITable *)table heightForRow:(int)row;
1979 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing;
1980 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row;
1981 - (void) tableRowSelected:(NSNotification*)notification;
1983 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
1984 - (void) navigationBar:(UINavigationBar *)navbar poppedItem:(UINavigationItem *)item;
1986 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database;
1987 - (void) setDelegate:(id)delegate;
1989 - (void) reloadData:(BOOL)reset;
1991 - (NSMutableArray *) packages;
1992 - (NSString *) title;
1993 - (void) perform:(Package *)package;
1994 - (void) addPackage:(Package *)package;
1995 - (NSString *) versionWithPackage:(Package *)package;
1998 @implementation PackagesView
2000 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
2001 return [sections_ count];
2004 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
2005 return [[sections_ objectAtIndex:section] name];
2008 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
2009 return [[sections_ objectAtIndex:section] row];
2012 - (int) numberOfRowsInTable:(UITable *)table {
2013 return [packages_ count];
2016 - (float) table:(UITable *)table heightForRow:(int)row {
2020 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2022 reusing = [[PackageCell alloc] initWithDelegate:self];
2023 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
2027 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
2031 - (void) tableRowSelected:(NSNotification*)notification {
2032 int row = [[list_ table] selectedRow];
2036 package_ = [packages_ objectAtIndex:row];
2037 pkgname_ = [[package_ name] retain];
2039 UINavigationItem *navitem = [[UINavigationItem alloc] initWithTitle:[package_ name]];
2040 [navbar_ pushNavigationItem:navitem];
2042 [navbar_ showButtonsWithLeftTitle:nil rightTitle:[self title]];
2044 [pkgview_ setPackage:package_];
2045 [transition_ transition:1 toView:pkgview_];
2048 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2050 [self perform:package_];
2052 pkgProblemResolver *resolver = [database_ resolver];
2054 resolver->InstallProtect();
2055 if (!resolver->Resolve(true))
2058 [delegate_ perform];
2062 - (void) navigationBar:(UINavigationBar *)navbar poppedItem:(UINavigationItem *)item {
2064 [super navigationBar:navbar poppedItem:item];
2067 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database {
2068 if ((self = [super initWithFrame:frame]) != nil) {
2069 database_ = [database retain];
2071 struct CGRect bounds = [self bounds];
2072 CGSize navsize = [UINavigationBar defaultSize];
2073 CGRect navrect = {{0, 0}, navsize};
2075 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
2076 [self addSubview:navbar_];
2078 [navbar_ setBarStyle:1];
2079 [navbar_ setDelegate:self];
2081 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:[self title]] autorelease];
2082 [navbar_ pushNavigationItem:navitem];
2083 [navitem setBackButtonTitle:@"Packages"];
2085 transition_ = [[UITransitionView alloc] initWithFrame:CGRectMake(
2086 bounds.origin.x, bounds.origin.y + navsize.height, bounds.size.width, bounds.size.height - navsize.height
2089 [self addSubview:transition_];
2091 list_ = [[UISectionList alloc] initWithFrame:[transition_ bounds] showSectionIndex:NO];
2092 [list_ setDataSource:self];
2093 [list_ setShouldHideHeaderInShortLists:NO];
2095 [transition_ transition:0 toView:list_];
2097 UITableColumn *column = [[UITableColumn alloc]
2098 initWithTitle:@"Name"
2100 width:frame.size.width
2103 UITable *table = [list_ table];
2104 [table setSeparatorStyle:1];
2105 [table addTableColumn:column];
2106 [table setDelegate:self];
2107 [table setReusesTableCells:YES];
2109 pkgview_ = [[PackageView alloc] initWithFrame:[transition_ bounds] database:database_];
2113 - (void) setDelegate:(id)delegate {
2114 delegate_ = delegate;
2115 [pkgview_ setDelegate:delegate];
2119 [transition_ transition:(resetting_ ? 0 : 2) toView:list_];
2120 UITable *table = [list_ table];
2121 [table selectRow:-1 byExtendingSelection:NO withFade:(resetting_ ? NO : YES)];
2125 - (void) reloadData:(BOOL)reset {
2126 if (sections_ != nil)
2127 [sections_ release];
2128 if (packages_ != nil)
2129 [packages_ release];
2131 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
2133 for (pkgCache::PkgIterator iterator = [database_ cache]->PkgBegin(); !iterator.end(); ++iterator)
2134 if (Package *package = [Package packageWithIterator:iterator database:database_])
2135 [self addPackage:package];
2137 [packages_ sortUsingSelector:@selector(compareBySectionAndName:)];
2138 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
2140 Section *section = nil;
2141 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
2142 Package *package = [packages_ objectAtIndex:offset];
2143 NSString *name = [package section];
2145 if (section == nil || ![[section name] isEqual:name]) {
2146 section = [[Section alloc] initWithName:name row:offset];
2147 [sections_ addObject:section];
2150 [section addPackage:package];
2156 else if (package_ != nil) {
2157 package_ = [database_ packageWithName:pkgname_];
2158 [pkgview_ setPackage:package_];
2162 - (NSMutableArray *) packages {
2166 - (NSString *) title {
2170 - (void) perform:(Package *)package {
2173 - (void) addPackage:(Package *)package {
2174 [packages_ addObject:package];
2177 - (NSString *) versionWithPackage:(Package *)package {
2184 /* InstallView {{{ */
2185 @interface InstallView : PackagesView {
2188 - (NSString *) title;
2189 - (void) addPackage:(Package *)package;
2190 - (void) perform:(Package *)package;
2191 - (NSString *) versionWithPackage:(Package *)package;
2194 @implementation InstallView
2196 - (NSString *) title {
2200 - (void) addPackage:(Package *)package {
2201 if ([package installed] == nil)
2202 [super addPackage:package];
2205 - (void) perform:(Package *)package {
2209 - (NSString *) versionWithPackage:(Package *)package {
2210 return [package latest];
2215 /* UpgradeView {{{ */
2216 @interface UpgradeView : PackagesView {
2219 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
2221 - (NSString *) title;
2222 - (NSString *) leftTitle;
2223 - (void) addPackage:(Package *)package;
2224 - (void) perform:(Package *)package;
2225 - (NSString *) versionWithPackage:(Package *)package;
2228 @implementation UpgradeView
2230 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2232 [super navigationBar:navbar buttonClicked:button];
2234 [database_ upgrade];
2235 [delegate_ perform];
2239 - (NSString *) title {
2243 - (NSString *) leftTitle {
2244 return [packages_ count] == 0 ? nil : @"Upgrade All";
2247 - (void) addPackage:(Package *)package {
2248 NSString *installed = [package installed];
2249 if (installed != nil && [[package latest] compare:installed] != NSOrderedSame)
2250 [super addPackage:package];
2253 - (void) perform:(Package *)package {
2257 - (NSString *) versionWithPackage:(Package *)package {
2258 return [package latest];
2263 /* UninstallView {{{ */
2264 @interface UninstallView : PackagesView {
2267 - (NSString *) title;
2268 - (void) addPackage:(Package *)package;
2269 - (void) perform:(Package *)package;
2270 - (NSString *) versionWithPackage:(Package *)package;
2273 @implementation UninstallView
2275 - (NSString *) title {
2276 return @"Uninstall";
2279 - (void) addPackage:(Package *)package {
2280 if ([package installed] != nil)
2281 [super addPackage:package];
2284 - (void) perform:(Package *)package {
2288 - (NSString *) versionWithPackage:(Package *)package {
2289 return [package installed];
2295 @interface Cydia : UIApplication <
2296 ConfirmationViewDelegate,
2297 PackagesViewDelegate,
2298 ProgressViewDelegate
2303 UITransitionView *transition_;
2304 UIButtonBar *buttonbar_;
2306 ConfirmationView *confirm_;
2308 Database *database_;
2309 ProgressView *progress_;
2312 UINavigationBar *navbar_;
2313 UIScroller *scroller_;
2314 UIWebView *webview_;
2316 UIProgressIndicator *indicator_;
2318 InstallView *install_;
2319 UpgradeView *upgrade_;
2320 UninstallView *uninstall_;
2321 SourcesView *sources_;
2325 - (void) reloadData:(BOOL)reset;
2331 - (void) progressViewIsComplete:(ProgressView *)progress;
2333 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
2334 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
2335 - (void) buttonBarItemTapped:(id)sender;
2337 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old;
2339 - (void) applicationDidFinishLaunching:(id)unused;
2342 #include <objc/objc-class.h>
2344 @implementation Cydia
2347 NSMutableURLRequest *request = [NSMutableURLRequest
2349 cachePolicy:NSURLRequestReloadIgnoringCacheData
2350 timeoutInterval:30.0
2353 [request addValue:[NSString stringWithCString:Machine_] forHTTPHeaderField:@"X-Machine"];
2354 [request addValue:[NSString stringWithCString:SerialNumber_] forHTTPHeaderField:@"X-Serial-Number"];
2356 [webview_ loadRequest:request];
2357 [indicator_ startAnimation];
2360 - (void) reloadData:(BOOL)reset {
2361 [database_ reloadData];
2362 [install_ reloadData:reset];
2363 [upgrade_ reloadData:reset];
2364 [uninstall_ reloadData:reset];
2365 [sources_ reloadData];
2367 if (size_t count = [[upgrade_ packages] count]) {
2368 NSString *badge([[NSNumber numberWithInt:count] stringValue]);
2369 [buttonbar_ setBadgeValue:badge forButton:3];
2370 [buttonbar_ setBadgeAnimated:YES forButton:3];
2371 [self setApplicationBadge:badge];
2373 [buttonbar_ setBadgeValue:nil forButton:3];
2374 [buttonbar_ setBadgeAnimated:NO forButton:3];
2375 [self removeApplicationBadge];
2380 [database_ prepare];
2381 confirm_ = [[ConfirmationView alloc] initWithView:underlay_ database:database_ delegate:self];
2385 [self reloadData:NO];
2391 [overlay_ removeFromSuperview];
2394 detachNewThreadSelector:@selector(perform)
2402 detachNewThreadSelector:@selector(update)
2408 - (void) progressViewIsComplete:(ProgressView *)progress {
2409 [self reloadData:YES];
2411 if (confirm_ != nil) {
2412 [underlay_ addSubview:overlay_];
2413 [confirm_ removeFromSuperview];
2419 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2426 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
2427 initWithTitle:@"About Cydia Packager"
2428 buttons:[NSArray arrayWithObjects:@"Close", nil]
2429 defaultButtonIndex:0
2435 @"Copyright (C) 2007\n"
2436 "Jay Freeman (saurik)\n"
2437 "saurik@saurik.com\n"
2438 "http://www.saurik.com/\n"
2441 "http://www.theokorigroup.com/\n"
2443 "College of Creative Studies,\n"
2444 "University of California,\n"
2446 "http://www.ccs.ucsb.edu/\n"
2449 "bad_, BHSPitMonkey, Cobra, core,\n"
2450 "Corona, cromas, Darken, dtzWill,\n"
2451 "francis, Godores, jerry, Kingstone,\n"
2452 "lounger, rockabilly, tman, Wbiggs"
2455 [sheet presentSheetFromButtonBar:buttonbar_];
2460 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
2464 - (void) buttonBarItemTapped:(id)sender {
2467 switch ([sender tag]) {
2468 case 1: view = featured_; break;
2469 case 2: view = install_; break;
2470 case 3: view = upgrade_; break;
2471 case 4: view = uninstall_; break;
2472 case 5: view = sources_; break;
2478 if ([view respondsToSelector:@selector(resetView)])
2479 [(id) view resetView];
2480 [transition_ transition:0 toView:view];
2483 - (void) view:(UIView *)view didSetFrame:(CGRect)frame oldFrame:(CGRect)old {
2484 [scroller_ setContentSize:frame.size];
2485 [indicator_ stopAnimation];
2488 - (void) applicationDidFinishLaunching:(id)unused {
2489 _assert(pkgInitConfig(*_config));
2490 _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]);