1 /* #include Directives {{{ */
2 #include <CoreGraphics/CoreGraphics.h>
3 #include <GraphicsServices/GraphicsServices.h>
4 #include <Foundation/Foundation.h>
5 #include <UIKit/UIKit.h>
10 #include <ext/stdio_filebuf.h>
12 #include <apt-pkg/acquire.h>
13 #include <apt-pkg/acquire-item.h>
14 #include <apt-pkg/algorithms.h>
15 #include <apt-pkg/cachefile.h>
16 #include <apt-pkg/configuration.h>
17 #include <apt-pkg/debmetaindex.h>
18 #include <apt-pkg/error.h>
19 #include <apt-pkg/init.h>
20 #include <apt-pkg/pkgrecords.h>
21 #include <apt-pkg/sourcelist.h>
22 #include <apt-pkg/sptr.h>
24 #include <sys/sysctl.h>
28 #include <mach-o/nlist.h>
38 /* Extension Keywords {{{ */
39 #define _trace() fprintf(stderr, "_trace()@%s:%u[%s]\n", __FILE__, __LINE__, __FUNCTION__)
41 #define _assert(test) do \
43 fprintf(stderr, "_assert(%d:%s)@%s:%u[%s]\n", errno, #test, __FILE__, __LINE__, __FUNCTION__); \
48 #define _not(type) ((type) ~ (type) 0)
50 /* Miscellaneous Messages {{{ */
52 - (void) setApplicationNameForUserAgent:(NSString *)applicationName;
53 - (id) frameLoadDelegate;
54 - (void) setFrameLoadDelegate:(id)delegate;
57 @interface NSString (Cydia)
58 - (NSString *) stringByAddingPercentEscapes;
59 - (NSString *) stringByReplacingCharacter:(unsigned short)arg0 withCharacter:(unsigned short)arg1;
64 #define UITable UITableView
67 OBJC_EXPORT const char *class_getName(Class cls);
69 /* Reset View (UIView) {{{ */
70 @interface UIView (CYResetView)
71 - (void) resetViewAnimated:(BOOL)animated;
74 @implementation UIView (CYResetView)
76 - (void) resetViewAnimated:(BOOL)animated {
77 fprintf(stderr, "%s\n", class_getName(self->isa));
83 /* Reset View (UITable) {{{ */
84 @interface UITable (CYResetView)
85 - (void) resetViewAnimated:(BOOL)animated;
88 @implementation UITable (CYResetView)
90 - (void) resetViewAnimated:(BOOL)animated {
91 [self selectRow:-1 byExtendingSelection:NO withFade:animated];
96 /* Reset View (UISectionList) {{{ */
97 @interface UISectionList (CYResetView)
98 - (void) resetViewAnimated:(BOOL)animated;
101 @implementation UISectionList (CYResetView)
103 - (void) resetViewAnimated:(BOOL)animated {
104 [[self table] resetViewAnimated:animated];
110 /* Perl-Compatible RegEx {{{ */
120 Pcre(const char *regex) :
125 code_ = pcre_compile(regex, 0, &error, &offset, NULL);
128 fprintf(stderr, "%d:%s\n", offset, error);
132 pcre_fullinfo(code_, study_, PCRE_INFO_CAPTURECOUNT, &capture_);
133 matches_ = new int[(capture_ + 1) * 3];
141 NSString *operator [](size_t match) {
143 stringWithCString:(data_ + matches_[match * 2])
144 length:(matches_[match * 2 + 1] - matches_[match * 2])
148 bool operator ()(const char *data, size_t size) {
150 return pcre_exec(code_, study_, data, size, 0, 0, matches_, (capture_ + 1) * 3) >= 0;
154 /* CoreGraphics Primitives {{{ */
160 CGColor(CGColorSpaceRef space, float red, float green, float blue, float alpha) {
161 float color[] = {red, green, blue, alpha};
162 color_ = CGColorCreate(space, color);
166 CGColorRelease(color_);
169 operator CGColorRef() {
185 static const int PulseInterval_ = 50000;
187 const char *Firmware_ = NULL;
188 const char *Machine_ = NULL;
189 const char *SerialNumber_ = NULL;
195 #define FW_LEAST(major, minor, bugfix) \
196 (major < Major_ || major == Major_ && \
197 (minor < Minor_ || minor == Minor_ && \
200 bool bootstrap_ = false;
202 static NSMutableDictionary *Metadata_;
203 static NSMutableDictionary *Packages_;
206 NSString *GetLastUpdate() {
207 NSDate *update = [Metadata_ objectForKey:@"LastUpdate"];
210 return @"Never or Unknown";
212 CFLocaleRef locale = CFLocaleCopyCurrent();
213 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
214 CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) update);
216 CFRelease(formatter);
219 return [(NSString *) formatted autorelease];
222 @protocol ProgressDelegate
223 - (void) setError:(NSString *)error;
224 - (void) setTitle:(NSString *)title;
225 - (void) setPercent:(float)percent;
226 - (void) addOutput:(NSString *)output;
229 NSString *SizeString(double size) {
231 while (size > 1024) {
236 static const char *powers_[] = {"B", "kB", "MB", "GB"};
238 return [NSString stringWithFormat:@"%.1f%s", size, powers_[power]];
241 static const float TextViewOffset_ = 22;
243 UITextView *GetTextView(NSString *value, float left, bool html) {
244 UITextView *text([[[UITextView alloc] initWithFrame:CGRectMake(left, 3, 310 - left, 1000)] autorelease]);
245 [text setEditable:NO];
246 [text setTextSize:16];
248 [text setHTML:value];
250 [text setText:value];
251 [text setEnabled:NO];
253 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
254 CGColor clear(space, 0, 0, 0, 0);
255 [text setBackgroundColor:clear];
256 CGColorSpaceRelease(space);
258 CGRect frame = [text frame];
259 [text setFrame:frame];
260 CGRect rect = [text visibleTextRect];
261 frame.size.height = rect.size.height;
262 [text setFrame:frame];
267 /* Status Delegation {{{ */
269 public pkgAcquireStatus
280 void setDelegate(id delegate) {
281 delegate_ = delegate;
284 virtual bool MediaChange(std::string media, std::string drive) {
288 virtual void IMSHit(pkgAcquire::ItemDesc &item) {
291 virtual void Fetch(pkgAcquire::ItemDesc &item) {
292 [delegate_ setTitle:[NSString stringWithCString:("Downloading " + item.ShortDesc).c_str()]];
295 virtual void Done(pkgAcquire::ItemDesc &item) {
298 virtual void Fail(pkgAcquire::ItemDesc &item) {
300 item.Owner->Status == pkgAcquire::Item::StatIdle ||
301 item.Owner->Status == pkgAcquire::Item::StatDone
305 [delegate_ setError:[NSString stringWithCString:item.Owner->ErrorText.c_str()]];
308 virtual bool Pulse(pkgAcquire *Owner) {
309 bool value = pkgAcquireStatus::Pulse(Owner);
312 double(CurrentBytes + CurrentItems) /
313 double(TotalBytes + TotalItems)
316 [delegate_ setPercent:percent];
320 virtual void Start() {
323 virtual void Stop() {
327 /* Progress Delegation {{{ */
335 virtual void Update() {
336 [delegate_ setTitle:[NSString stringWithCString:Op.c_str()]];
337 [delegate_ setPercent:(Percent / 100)];
346 void setDelegate(id delegate) {
347 delegate_ = delegate;
350 virtual void Done() {
351 [delegate_ setPercent:1];
356 @protocol CydiaDelegate
363 /* External Constants {{{ */
364 extern NSString *kUIButtonBarButtonAction;
365 extern NSString *kUIButtonBarButtonInfo;
366 extern NSString *kUIButtonBarButtonInfoOffset;
367 extern NSString *kUIButtonBarButtonSelectedInfo;
368 extern NSString *kUIButtonBarButtonStyle;
369 extern NSString *kUIButtonBarButtonTag;
370 extern NSString *kUIButtonBarButtonTarget;
371 extern NSString *kUIButtonBarButtonTitle;
372 extern NSString *kUIButtonBarButtonTitleVerticalHeight;
373 extern NSString *kUIButtonBarButtonTitleWidth;
374 extern NSString *kUIButtonBarButtonType;
376 /* Mime Addresses {{{ */
377 Pcre email_r("^\"?(.*)\"? <([^>]*)>$");
379 @interface Address : NSObject {
387 - (NSString *) email;
389 + (Address *) addressWithString:(NSString *)string;
390 - (Address *) initWithString:(NSString *)string;
393 @implementation Address
402 - (NSString *) name {
406 - (NSString *) email {
410 + (Address *) addressWithString:(NSString *)string {
411 return [[[Address alloc] initWithString:string] autorelease];
414 - (Address *) initWithString:(NSString *)string {
415 if ((self = [super init]) != nil) {
416 const char *data = [string UTF8String];
417 size_t size = [string length];
419 if (email_r(data, size)) {
420 name_ = [email_r[1] retain];
421 email_ = [email_r[2] retain];
423 name_ = [[NSString stringWithCString:data length:size] retain];
432 /* Right Alignment {{{ */
433 @interface UIRightTextLabel : UITextLabel {
434 float _savedRightEdgeX;
435 BOOL _sizedtofit_flag;
438 - (void) setFrame:(CGRect)frame;
439 - (void) setText:(NSString *)text;
440 - (void) realignText;
443 @implementation UIRightTextLabel
445 - (void) setFrame:(CGRect)frame {
446 [super setFrame:frame];
447 if (_sizedtofit_flag == NO) {
448 _savedRightEdgeX = frame.origin.x;
453 - (void) setText:(NSString *)text {
454 [super setText:text];
458 - (void) realignText {
459 CGRect oldFrame = [self frame];
461 _sizedtofit_flag = YES;
462 [self sizeToFit]; // shrink down size so I can right align it
464 CGRect newFrame = [self frame];
466 oldFrame.origin.x = _savedRightEdgeX - newFrame.size.width;
467 oldFrame.size.width = newFrame.size.width;
468 [super setFrame:oldFrame];
469 _sizedtofit_flag = NO;
474 /* Linear Algebra {{{ */
475 inline float interpolate(float begin, float end, float fraction) {
476 return (end - begin) * fraction + begin;
483 /* Database Interface {{{ */
484 @interface Database : NSObject {
486 pkgRecords *records_;
487 pkgProblemResolver *resolver_;
488 pkgAcquire *fetcher_;
490 SPtr<pkgPackageManager> manager_;
491 pkgSourceList *list_;
493 NSMutableDictionary *sources_;
494 NSMutableArray *packages_;
504 - (void) _readStatus:(NSNumber *)fd;
505 - (void) _readOutput:(NSNumber *)fd;
507 - (Package *) packageWithName:(NSString *)name;
510 - (pkgCacheFile &) cache;
511 - (pkgRecords *) records;
512 - (pkgProblemResolver *) resolver;
513 - (pkgAcquire &) fetcher;
514 - (NSArray *) packages;
522 - (void) setDelegate:(id)delegate;
523 - (Source *) getSource:(const pkgCache::PkgFileIterator &)file;
528 @interface ResetView : UIView {
529 UIPushButton *configure_;
530 UIPushButton *reload_;
531 NSMutableArray *views_;
532 UINavigationBar *navbar_;
533 UITransitionView *transition_;
540 - (void) navigationBar:(UINavigationBar *)navbar poppedItem:(UINavigationItem *)item;
541 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
543 - (id) initWithFrame:(CGRect)frame;
544 - (void) setDelegate:(id)delegate;
546 - (void) configurePushed;
547 - (void) reloadPushed;
549 - (void) pushView:(UIView *)view withTitle:(NSString *)title backButtonTitle:(NSString *)back rightButton:(NSString *)right;
550 - (void) popViews:(unsigned)views;
551 - (void) resetView:(BOOL)clear;
556 @implementation ResetView
559 [configure_ release];
561 [transition_ release];
567 - (void) navigationBar:(UINavigationBar *)navbar poppedItem:(UINavigationItem *)item {
568 [views_ removeLastObject];
569 UIView *view([views_ lastObject]);
570 [view resetViewAnimated:!resetting_];
573 [transition_ transition:2 toView:view];
578 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
582 - (id) initWithFrame:(CGRect)frame {
583 if ((self = [super initWithFrame:frame]) != nil) {
584 views_ = [[NSMutableArray arrayWithCapacity:4] retain];
586 struct CGRect bounds = [self bounds];
587 CGSize navsize = [UINavigationBar defaultSizeWithPrompt];
588 CGRect navrect = {{0, 0}, navsize};
590 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
591 [self addSubview:navbar_];
593 [navbar_ setBarStyle:1];
594 [navbar_ setDelegate:self];
596 transition_ = [[UITransitionView alloc] initWithFrame:CGRectMake(
597 bounds.origin.x, bounds.origin.y + navsize.height, bounds.size.width, bounds.size.height - navsize.height
600 //configure_ = [[UIPushButton alloc] initWithFrame:CGRectMake(15, 9, 17, 18)];
601 configure_ = [[UIPushButton alloc] initWithFrame:CGRectMake(10, 9, 17, 18)];
602 [configure_ setShowPressFeedback:YES];
603 [configure_ setImage:[UIImage applicationImageNamed:@"configure.png"]];
604 [configure_ addTarget:self action:@selector(configurePushed) forEvents:1];
606 //reload_ = [[UIPushButton alloc] initWithFrame:CGRectMake(288, 5, 18, 22)];
607 reload_ = [[UIPushButton alloc] initWithFrame:CGRectMake(293, 5, 18, 22)];
608 [reload_ setShowPressFeedback:YES];
609 [reload_ setImage:[UIImage applicationImageNamed:@"reload.png"]];
610 [reload_ addTarget:self action:@selector(reloadPushed) forEvents:1];
612 [navbar_ addSubview:configure_];
613 [navbar_ addSubview:reload_];
615 [self addSubview:transition_];
619 - (void) setDelegate:(id)delegate {
620 delegate_ = delegate;
623 - (void) configurePushed {
624 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
625 initWithTitle:@"Sources Unimplemented"
626 buttons:[NSArray arrayWithObjects:@"Okay", nil]
632 [sheet setBodyText:@"This feature will be implemented soon. In the mean time, you may add sources by adding .list files to '/etc/apt/sources.list.d' or modifying '/etc/apt/sources.list'."];
633 [sheet popupAlertAnimated:YES];
636 - (void) reloadPushed {
640 - (void) pushView:(UIView *)view withTitle:(NSString *)title backButtonTitle:(NSString *)back rightButton:(NSString *)right {
641 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:title] autorelease];
642 [navbar_ pushNavigationItem:navitem];
643 [navitem setBackButtonTitle:back];
645 [navbar_ showButtonsWithLeftTitle:nil rightTitle:right];
647 [transition_ transition:([views_ count] == 0 ? 0 : 1) toView:view];
648 [views_ addObject:view];
651 - (void) popViews:(unsigned)views {
653 for (unsigned i(0); i != views; ++i)
654 [navbar_ popNavigationItem];
658 [transition_ transition:2 toView:[views_ lastObject]];
661 - (void) resetView:(BOOL)clear {
664 if ([views_ count] > 1) {
665 [navbar_ disableAnimation];
666 while ([views_ count] != (clear ? 1 : 2))
667 [navbar_ popNavigationItem];
668 [navbar_ enableAnimation];
670 [navbar_ popNavigationItem];
676 [transition_ transition:(clear ? 0 : 2) toView:[views_ lastObject]];
679 - (void) _resetView {
680 [navbar_ showButtonsWithLeftTitle:nil rightTitle:nil];
684 [navbar_ setPrompt:[NSString stringWithFormat:@"Last Updated: %@", GetLastUpdate()]];
689 /* Confirmation View {{{ */
690 void AddTextView(NSMutableDictionary *fields, NSMutableArray *packages, NSString *key) {
691 if ([packages count] == 0)
694 UITextView *text = GetTextView([packages count] == 0 ? @"n/a" : [packages componentsJoinedByString:@", "], 110, false);
695 [fields setObject:text forKey:key];
697 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
698 CGColor blue(space, 0, 0, 0.4, 1);
699 [text setTextColor:blue];
700 CGColorSpaceRelease(space);
703 @protocol ConfirmationViewDelegate
708 @interface ConfirmationView : UIView {
711 UITransitionView *transition_;
713 UINavigationBar *navbar_;
714 UIPreferencesTable *table_;
715 NSMutableDictionary *fields_;
716 UIAlertSheet *essential_;
722 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
723 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
724 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
726 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table;
727 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group;
728 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed;
729 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group;
730 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group;
732 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate;
736 @implementation ConfirmationView
739 [transition_ release];
744 if (essential_ != nil)
745 [essential_ release];
750 [transition_ transition:7 toView:nil];
754 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
755 if (from != nil && to == nil)
756 [self removeFromSuperview];
759 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
762 if (essential_ != nil)
763 [essential_ popupAlertAnimated:YES];
774 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
775 [essential_ dismiss];
779 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
783 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
785 case 0: return @"Statistics";
786 case 1: return @"Modifications";
788 default: _assert(false);
792 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
795 case 1: return [fields_ count];
797 default: _assert(false);
801 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
802 if (group != 1 || row == -1)
805 _assert(size_t(row) < [fields_ count]);
806 return [[[fields_ allValues] objectAtIndex:row] visibleTextRect].size.height + TextViewOffset_;
810 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
811 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
812 [cell setShowSelection:NO];
815 case 0: switch (row) {
817 [cell setTitle:@"Downloading"];
818 [cell setValue:SizeString([database_ fetcher].FetchNeeded())];
822 [cell setTitle:@"Resuming At"];
823 [cell setValue:SizeString([database_ fetcher].PartialPresent())];
827 double size([database_ cache]->UsrSize());
830 [cell setTitle:@"Disk Freeing"];
831 [cell setValue:SizeString(-size)];
833 [cell setTitle:@"Disk Using"];
834 [cell setValue:SizeString(size)];
838 default: _assert(false);
842 _assert(size_t(row) < [fields_ count]);
843 [cell setTitle:[[fields_ allKeys] objectAtIndex:row]];
844 [cell addSubview:[[fields_ allValues] objectAtIndex:row]];
847 default: _assert(false);
853 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate {
854 if ((self = [super initWithFrame:[view bounds]]) != nil) {
855 database_ = database;
856 delegate_ = delegate;
858 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
859 [self addSubview:transition_];
861 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
863 CGSize navsize = [UINavigationBar defaultSize];
864 CGRect navrect = {{0, 0}, navsize};
865 CGRect bounds = [overlay_ bounds];
867 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
868 [navbar_ setBarStyle:1];
869 [navbar_ setDelegate:self];
871 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Confirm"] autorelease];
872 [navbar_ pushNavigationItem:navitem];
873 [navbar_ showButtonsWithLeftTitle:@"Cancel" rightTitle:@"Confirm"];
875 fields_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
877 NSMutableArray *installing = [NSMutableArray arrayWithCapacity:16];
878 NSMutableArray *upgrading = [NSMutableArray arrayWithCapacity:16];
879 NSMutableArray *removing = [NSMutableArray arrayWithCapacity:16];
885 pkgCacheFile &cache([database_ cache]);
886 for (pkgCache::PkgIterator iterator = cache->PkgBegin(); !iterator.end(); ++iterator) {
887 NSString *name([NSString stringWithCString:iterator.Name()]);
888 bool essential((iterator->Flags & pkgCache::Flag::Essential) != 0);
890 if (cache[iterator].NewInstall()) {
893 [installing addObject:name];
894 } else if (cache[iterator].Upgrade()) {
897 [upgrading addObject:name];
898 } else if (cache[iterator].Delete()) {
901 [removing addObject:name];
908 essential_ = [[UIAlertSheet alloc]
909 initWithTitle:@"Unable to Comply"
910 buttons:[NSArray arrayWithObjects:@"Okay", nil]
916 [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."];
919 AddTextView(fields_, installing, @"Installing");
920 AddTextView(fields_, upgrading, @"Upgrading");
921 AddTextView(fields_, removing, @"Removing");
923 table_ = [[UIPreferencesTable alloc] initWithFrame:CGRectMake(
924 0, navsize.height, bounds.size.width, bounds.size.height - navsize.height
927 [table_ setReusesTableCells:YES];
928 [table_ setDataSource:self];
931 [overlay_ addSubview:navbar_];
932 [overlay_ addSubview:table_];
934 [view addSubview:self];
936 [transition_ setDelegate:self];
938 UIView *blank = [[[UIView alloc] initWithFrame:[transition_ bounds]] autorelease];
939 [transition_ transition:0 toView:blank];
940 [transition_ transition:3 toView:overlay_];
947 /* Source Class {{{ */
948 @interface Source : NSObject {
949 NSString *description_;
954 NSString *distribution_;
958 NSString *defaultIcon_;
965 - (Source *) initWithMetaIndex:(metaIndex *)index;
970 - (NSString *) distribution;
973 - (NSString *) description;
974 - (NSString *) label;
975 - (NSString *) origin;
976 - (NSString *) version;
978 - (NSString *) defaultIcon;
981 @implementation Source
985 [distribution_ release];
988 if (description_ != nil)
989 [description_ release];
1000 - (Source *) initWithMetaIndex:(metaIndex *)index {
1001 if ((self = [super init]) != nil) {
1002 trusted_ = index->IsTrusted();
1004 uri_ = [[NSString stringWithCString:index->GetURI().c_str()] retain];
1005 distribution_ = [[NSString stringWithCString:index->GetDist().c_str()] retain];
1006 type_ = [[NSString stringWithCString:index->GetType()] retain];
1012 debReleaseIndex *dindex(dynamic_cast<debReleaseIndex *>(index));
1013 if (dindex != NULL) {
1014 std::ifstream release(dindex->MetaIndexFile("Release").c_str());
1016 while (std::getline(release, line)) {
1017 std::string::size_type colon(line.find(':'));
1018 if (colon == std::string::npos)
1021 std::string name(line.substr(0, colon));
1022 std::string value(line.substr(colon + 1));
1023 while (!value.empty() && value[0] == ' ')
1024 value = value.substr(1);
1026 if (name == "Default-Icon")
1027 defaultIcon_ = [[NSString stringWithCString:value.c_str()] retain];
1028 else if (name == "Description")
1029 description_ = [[NSString stringWithCString:value.c_str()] retain];
1030 else if (name == "Label")
1031 label_ = [[NSString stringWithCString:value.c_str()] retain];
1032 else if (name == "Origin")
1033 origin_ = [[NSString stringWithCString:value.c_str()] retain];
1034 else if (name == "Version")
1035 version_ = [[NSString stringWithCString:value.c_str()] retain];
1045 - (NSString *) uri {
1049 - (NSString *) distribution {
1050 return distribution_;
1053 - (NSString *) type {
1057 - (NSString *) description {
1058 return description_;
1061 - (NSString *) label {
1065 - (NSString *) origin {
1069 - (NSString *) version {
1073 - (NSString *) defaultIcon {
1074 return defaultIcon_;
1079 /* Package Class {{{ */
1080 NSString *Scour(const char *field, const char *begin, const char *end) {
1081 size_t i(0), l(strlen(field));
1084 const char *name = begin + i;
1085 const char *colon = name + l;
1086 const char *value = colon + 1;
1091 memcmp(name, field, l) == 0
1093 while (value != end && value[0] == ' ')
1095 const char *line = std::find(value, end, '\n');
1096 while (line != value && line[-1] == ' ')
1098 return [NSString stringWithCString:value length:(line - value)];
1100 begin = std::find(begin, end, '\n');
1108 @interface Package : NSObject {
1109 pkgCache::PkgIterator iterator_;
1110 Database *database_;
1111 pkgCache::VerIterator version_;
1112 pkgCache::VerFileIterator file_;
1116 NSString *installed_;
1127 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database version:(pkgCache::VerIterator)version file:(pkgCache::VerFileIterator)file;
1128 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
1130 - (NSString *) section;
1131 - (Address *) maintainer;
1133 - (NSString *) description;
1134 - (NSString *) index;
1138 - (NSString *) latest;
1139 - (NSString *) installed;
1140 - (BOOL) upgradable;
1145 - (NSString *) name;
1146 - (NSString *) tagline;
1147 - (NSString *) icon;
1148 - (NSString *) website;
1150 - (Source *) source;
1152 - (BOOL) matches:(NSString *)text;
1154 - (NSComparisonResult) compareByName:(Package *)package;
1155 - (NSComparisonResult) compareBySectionAndName:(Package *)package;
1156 - (NSComparisonResult) compareForChanges:(Package *)package;
1162 @implementation Package
1166 if (installed_ != nil)
1167 [installed_ release];
1175 if (website_ != nil)
1184 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database version:(pkgCache::VerIterator)version file:(pkgCache::VerFileIterator)file {
1185 if ((self = [super init]) != nil) {
1186 iterator_ = iterator;
1187 database_ = database;
1192 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1194 const char *begin, *end;
1195 parser->GetRec(begin, end);
1197 latest_ = [[NSString stringWithCString:version_.VerStr()] retain];
1198 installed_ = iterator_.CurrentVer().end() ? nil : [[NSString stringWithCString:iterator_.CurrentVer().VerStr()] retain];
1200 id_ = [[[NSString stringWithCString:iterator_.Name()] lowercaseString] retain];
1201 name_ = Scour("Name", begin, end);
1203 name_ = [name_ retain];
1204 tagline_ = [[NSString stringWithCString:parser->ShortDesc().c_str()] retain];
1205 icon_ = Scour("Icon", begin, end);
1207 icon_ = [icon_ retain];
1208 website_ = Scour("Website", begin, end);
1209 if (website_ != nil)
1210 website_ = [website_ retain];
1212 source_ = [[database_ getSource:file_.File()] retain];
1214 NSMutableDictionary *metadata = [Packages_ objectForKey:id_];
1215 if (metadata == nil || [metadata count] == 0) {
1216 metadata = [NSMutableDictionary dictionaryWithObjectsAndKeys:
1220 [Packages_ setObject:metadata forKey:id_];
1225 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
1226 for (pkgCache::VerIterator version = iterator.VersionList(); !version.end(); ++version)
1227 for (pkgCache::VerFileIterator file = version.FileList(); !file.end(); ++file)
1228 return [[[Package alloc]
1229 initWithIterator:iterator
1237 - (NSString *) section {
1238 const char *section = iterator_.Section();
1239 return section == NULL ? nil : [[NSString stringWithCString:section] stringByReplacingCharacter:'_' withCharacter:' '];
1242 - (Address *) maintainer {
1243 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1244 return [Address addressWithString:[NSString stringWithCString:parser->Maintainer().c_str()]];
1248 return version_->InstalledSize;
1251 - (NSString *) description {
1252 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1253 NSString *description([NSString stringWithCString:parser->LongDesc().c_str()]);
1255 NSArray *lines = [description componentsSeparatedByString:@"\n"];
1256 NSMutableArray *trimmed = [NSMutableArray arrayWithCapacity:([lines count] - 1)];
1257 if ([lines count] < 2)
1260 NSCharacterSet *whitespace = [NSCharacterSet whitespaceCharacterSet];
1261 for (size_t i(1); i != [lines count]; ++i) {
1262 NSString *trim = [[lines objectAtIndex:i] stringByTrimmingCharactersInSet:whitespace];
1263 [trimmed addObject:trim];
1266 return [trimmed componentsJoinedByString:@"\n"];
1269 - (NSString *) index {
1270 NSString *index = [[[self name] substringToIndex:1] uppercaseString];
1271 return [index length] != 0 && isalpha([index characterAtIndex:0]) ? index : @"123";
1275 return [[Packages_ objectForKey:id_] objectForKey:@"FirstSeen"];
1278 - (NSString *) latest {
1282 - (NSString *) installed {
1286 - (BOOL) upgradable {
1287 if (NSString *installed = [self installed])
1288 return [[self latest] compare:installed] != NSOrderedSame ? YES : NO;
1290 return [self essential];
1293 - (BOOL) essential {
1294 return (iterator_->Flags & pkgCache::Flag::Essential) == 0 ? NO : YES;
1298 return (*[database_ cache])[iterator_].InstBroken();
1305 - (NSString *) name {
1306 return name_ == nil ? id_ : name_;
1309 - (NSString *) tagline {
1313 - (NSString *) icon {
1317 - (NSString *) website {
1321 - (Source *) source {
1325 - (BOOL) matches:(NSString *)text {
1331 range = [[self id] rangeOfString:text options:NSCaseInsensitiveSearch];
1332 if (range.location != NSNotFound)
1335 range = [[self name] rangeOfString:text options:NSCaseInsensitiveSearch];
1336 if (range.location != NSNotFound)
1339 range = [[self tagline] rangeOfString:text options:NSCaseInsensitiveSearch];
1340 if (range.location != NSNotFound)
1346 - (NSComparisonResult) compareByName:(Package *)package {
1347 NSString *lhs = [self name];
1348 NSString *rhs = [package name];
1350 if ([lhs length] != 0 && [rhs length] != 0) {
1351 unichar lhc = [lhs characterAtIndex:0];
1352 unichar rhc = [rhs characterAtIndex:0];
1354 if (isalpha(lhc) && !isalpha(rhc))
1355 return NSOrderedAscending;
1356 else if (!isalpha(lhc) && isalpha(rhc))
1357 return NSOrderedDescending;
1360 return [lhs caseInsensitiveCompare:rhs];
1363 - (NSComparisonResult) compareBySectionAndName:(Package *)package {
1364 NSString *lhs = [self section];
1365 NSString *rhs = [package section];
1367 if (lhs == NULL && rhs != NULL)
1368 return NSOrderedAscending;
1369 else if (lhs != NULL && rhs == NULL)
1370 return NSOrderedDescending;
1371 else if (lhs != NULL && rhs != NULL) {
1372 NSComparisonResult result = [lhs compare:rhs];
1373 if (result != NSOrderedSame)
1377 return [self compareByName:package];
1380 - (NSComparisonResult) compareForChanges:(Package *)package {
1381 BOOL lhs = [self upgradable];
1382 BOOL rhs = [package upgradable];
1385 return lhs ? NSOrderedAscending : NSOrderedDescending;
1387 switch ([[self seen] compare:[package seen]]) {
1388 case NSOrderedAscending:
1389 return NSOrderedDescending;
1392 case NSOrderedDescending:
1393 return NSOrderedAscending;
1399 return [self compareByName:package];
1403 pkgProblemResolver *resolver = [database_ resolver];
1404 resolver->Clear(iterator_);
1405 resolver->Protect(iterator_);
1406 [database_ cache]->MarkInstall(iterator_, false);
1410 pkgProblemResolver *resolver = [database_ resolver];
1411 resolver->Clear(iterator_);
1412 resolver->Protect(iterator_);
1413 resolver->Remove(iterator_);
1414 [database_ cache]->MarkDelete(iterator_, true);
1419 /* Section Class {{{ */
1420 @interface Section : NSObject {
1423 NSMutableArray *packages_;
1428 - (Section *) initWithName:(NSString *)name row:(size_t)row;
1429 - (NSString *) name;
1431 - (NSArray *) packages;
1433 - (void) addPackage:(Package *)package;
1436 @implementation Section
1440 [packages_ release];
1444 - (Section *) initWithName:(NSString *)name row:(size_t)row {
1445 if ((self = [super init]) != nil) {
1446 name_ = [name retain];
1448 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
1452 - (NSString *) name {
1460 - (NSArray *) packages {
1465 return [packages_ count];
1468 - (void) addPackage:(Package *)package {
1469 [packages_ addObject:package];
1475 /* Package View {{{ */
1476 @protocol PackageViewDelegate
1477 - (void) performPackage:(Package *)package;
1480 @interface PackageView : UIView {
1481 UIPreferencesTable *table_;
1483 UITextView *description_;
1489 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table;
1490 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group;
1491 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed;
1492 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group;
1493 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group;
1495 - (BOOL) canSelectRow:(int)row;
1496 - (void) tableRowSelected:(NSNotification *)notification;
1498 - (Package *) package;
1500 - (id) initWithFrame:(struct CGRect)frame;
1501 - (void) setPackage:(Package *)package;
1502 - (void) setDelegate:(id)delegate;
1505 @implementation PackageView
1508 if (package_ != nil)
1510 if (description_ != nil)
1511 [description_ release];
1516 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
1520 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
1523 case 1: return @"Package Details";
1524 case 2: return @"Source Information";
1526 default: _assert(false);
1530 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
1531 if (group != 0 || row != 1)
1534 return [description_ visibleTextRect].size.height + TextViewOffset_;
1537 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
1539 case 0: return [package_ website] == nil ? 2 : 3;
1543 default: _assert(false);
1547 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
1548 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
1549 [cell setShowSelection:NO];
1552 case 0: switch (row) {
1554 [cell setTitle:[package_ name]];
1555 [cell setValue:[package_ latest]];
1559 [cell addSubview:description_];
1563 [cell setTitle:@"More Information"];
1564 [cell setShowDisclosure:YES];
1565 [cell setShowSelection:YES];
1568 default: _assert(false);
1571 case 1: switch (row) {
1573 [cell setTitle:@"Identifier"];
1574 [cell setValue:[package_ id]];
1578 [cell setTitle:@"Installed Version"];
1579 NSString *installed([package_ installed]);
1580 [cell setValue:(installed == nil ? @"n/a" : installed)];
1584 [cell setTitle:@"Section"];
1585 NSString *section([package_ section]);
1586 [cell setValue:(section == nil ? @"n/a" : section)];
1590 [cell setTitle:@"Expanded Size"];
1591 [cell setValue:SizeString([package_ size])];
1595 [cell setTitle:@"Maintainer"];
1596 [cell setValue:[[package_ maintainer] name]];
1597 [cell setShowDisclosure:YES];
1598 [cell setShowSelection:YES];
1601 default: _assert(false);
1604 case 2: switch (row) {
1606 [cell setTitle:[[package_ source] label]];
1607 [cell setValue:[[package_ source] version]];
1611 [cell setValue:[[package_ source] description]];
1615 [cell setTitle:@"Origin"];
1616 [cell setValue:[[package_ source] origin]];
1619 default: _assert(false);
1622 default: _assert(false);
1628 - (BOOL) canSelectRow:(int)row {
1632 - (void) tableRowSelected:(NSNotification *)notification {
1633 int row = [table_ selectedRow];
1634 NSString *website = [package_ website];
1636 if (row == (website == nil ? 8 : 9))
1637 [delegate_ openURL:[NSURL URLWithString:[NSString stringWithFormat:@"mailto:%@?subject=%@",
1638 [[package_ maintainer] email],
1639 [[NSString stringWithFormat:@"regarding apt package \"%@\"", [package_ name]] stringByAddingPercentEscapes]
1641 else if (website != nil && row == 3)
1642 [delegate_ openURL:[NSURL URLWithString:website]];
1645 - (Package *) package {
1649 - (id) initWithFrame:(struct CGRect)frame {
1650 if ((self = [super initWithFrame:frame]) != nil) {
1651 table_ = [[UIPreferencesTable alloc] initWithFrame:[self bounds]];
1652 [self addSubview:table_];
1654 [table_ setDataSource:self];
1655 [table_ setDelegate:self];
1659 - (void) setPackage:(Package *)package {
1660 if (package_ != nil) {
1661 [package_ autorelease];
1665 if (description_ != nil) {
1666 [description_ release];
1670 if (package != nil) {
1671 package_ = [package retain];
1673 NSString *description([package description]);
1674 if (description == nil)
1675 description = [package tagline];
1676 description_ = [GetTextView(description, 12, true) retain];
1678 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1679 CGColor black(space, 0, 0, 0, 1);
1680 [description_ setTextColor:black];
1681 CGColorSpaceRelease(space);
1683 [table_ reloadData];
1687 - (void) setDelegate:(id)delegate {
1688 delegate_ = delegate;
1693 /* Package Cell {{{ */
1694 @interface PackageCell : UITableCell {
1697 UITextLabel *description_;
1698 UITextLabel *source_;
1699 UIImageView *trusted_;
1705 - (PackageCell *) initWithVersioner:(SEL)versioner;
1706 - (void) setPackage:(Package *)package;
1708 - (void) _setSelected:(float)fraction;
1709 - (void) setSelected:(BOOL)selected;
1710 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
1711 - (void) _setSelectionFadeFraction:(float)fraction;
1715 @implementation PackageCell
1720 [description_ release];
1726 - (PackageCell *) initWithVersioner:(SEL)versioner {
1727 if ((self = [super init]) != nil) {
1728 versioner_ = versioner;
1730 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22);
1731 GSFontRef large = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
1732 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 14);
1734 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1736 CGColor clear(space, 0, 0, 0, 0);
1738 icon_ = [[UIImageView alloc] initWithFrame:CGRectMake(10, 10, 30, 30)];
1740 name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 12, 240, 25)];
1741 [name_ setBackgroundColor:clear];
1742 [name_ setFont:bold];
1744 description_ = [[UITextLabel alloc] initWithFrame:CGRectMake(12, 46, 280, 20)];
1745 [description_ setBackgroundColor:clear];
1746 [description_ setFont:small];
1748 source_ = [[UITextLabel alloc] initWithFrame:CGRectMake(12, 72, 225, 20)];
1749 [source_ setBackgroundColor:clear];
1750 [source_ setFont:large];
1752 //trusted_ = [[UIImageView alloc] initWithFrame:CGRectMake(278, 7, 16, 16)];
1753 trusted_ = [[UIImageView alloc] initWithFrame:CGRectMake(30, 30, 16, 16)];
1754 [trusted_ setImage:[UIImage applicationImageNamed:@"trusted.png"]];
1756 [self addSubview:icon_];
1757 [self addSubview:name_];
1758 [self addSubview:description_];
1759 [self addSubview:source_];
1761 CGColorSpaceRelease(space);
1769 - (void) setPackage:(Package *)package {
1770 Source *source = [package source];
1772 UIImage *image = nil;
1773 if (NSString *icon = [package icon])
1774 image = [UIImage imageAtPath:[icon substringFromIndex:6]];
1775 if (image == nil) if (NSString *icon = [source defaultIcon])
1776 image = [UIImage imageAtPath:[icon substringFromIndex:6]];
1778 image = [UIImage applicationImageNamed:@"unknown.png"];
1780 [icon_ setImage:image];
1781 [icon_ zoomToScale:0.5f];
1782 [icon_ setFrame:CGRectMake(10, 10, 30, 30)];
1784 [name_ setText:[package name]];
1785 [description_ setText:[package tagline]];
1790 if (source != nil) {
1791 label = [source label];
1792 trusted = [source trusted];
1793 } else if ([[package id] isEqualToString:@"firmware"]) {
1797 label = @"Unknown/Local";
1801 [source_ setText:[NSString stringWithFormat:@"from %@", label]];
1803 [trusted_ removeFromSuperview];
1805 [self addSubview:trusted_];
1808 - (void) _setSelected:(float)fraction {
1809 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1811 CGColor black(space,
1812 interpolate(0.0, 1.0, fraction),
1813 interpolate(0.0, 1.0, fraction),
1814 interpolate(0.0, 1.0, fraction),
1818 interpolate(0.4, 1.0, fraction),
1819 interpolate(0.4, 1.0, fraction),
1820 interpolate(0.4, 1.0, fraction),
1823 [name_ setColor:black];
1824 [description_ setColor:gray];
1825 [source_ setColor:black];
1827 CGColorSpaceRelease(space);
1830 - (void) setSelected:(BOOL)selected {
1831 [self _setSelected:(selected ? 1.0 : 0.0)];
1832 [super setSelected:selected];
1835 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
1837 [self _setSelected:(selected ? 1.0 : 0.0)];
1838 [super setSelected:selected withFade:fade];
1841 - (void) _setSelectionFadeFraction:(float)fraction {
1842 [self _setSelected:fraction];
1843 [super _setSelectionFadeFraction:fraction];
1849 /* Database Implementation {{{ */
1850 @implementation Database
1857 - (void) _readStatus:(NSNumber *)fd {
1858 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1860 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1861 std::istream is(&ib);
1866 pcre *code = pcre_compile("^([^:]*):([^:]*):([^:]*):(.*)$", 0, &error, &offset, NULL);
1868 pcre_extra *study = NULL;
1870 pcre_fullinfo(code, study, PCRE_INFO_CAPTURECOUNT, &capture);
1871 int matches[(capture + 1) * 3];
1873 while (std::getline(is, line)) {
1874 const char *data(line.c_str());
1876 _assert(pcre_exec(code, study, data, line.size(), 0, 0, matches, sizeof(matches) / sizeof(matches[0])) >= 0);
1878 std::istringstream buffer(line.substr(matches[6], matches[7] - matches[6]));
1881 [delegate_ setPercent:(percent / 100)];
1883 NSString *string = [NSString stringWithCString:(data + matches[8]) length:(matches[9] - matches[8])];
1884 std::string type(line.substr(matches[2], matches[3] - matches[2]));
1886 if (type == "pmerror")
1887 [delegate_ setError:string];
1888 else if (type == "pmstatus")
1889 [delegate_ setTitle:string];
1890 else if (type == "pmconffile")
1892 else _assert(false);
1899 - (void) _readOutput:(NSNumber *)fd {
1900 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1902 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1903 std::istream is(&ib);
1906 while (std::getline(is, line))
1907 [delegate_ addOutput:[NSString stringWithCString:line.c_str()]];
1913 - (Package *) packageWithName:(NSString *)name {
1914 pkgCache::PkgIterator iterator(cache_->FindPkg([name UTF8String]));
1915 return iterator.end() ? nil : [Package packageWithIterator:iterator database:self];
1918 - (Database *) init {
1919 if ((self = [super init]) != nil) {
1925 sources_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1926 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
1930 _assert(pipe(fds) != -1);
1934 detachNewThreadSelector:@selector(_readStatus:)
1936 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1939 _assert(pipe(fds) != -1);
1940 _assert(dup2(fds[1], 1) != -1);
1941 _assert(close(fds[1]) != -1);
1944 detachNewThreadSelector:@selector(_readOutput:)
1946 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1951 - (pkgCacheFile &) cache {
1955 - (pkgRecords *) records {
1959 - (pkgProblemResolver *) resolver {
1963 - (pkgAcquire &) fetcher {
1967 - (NSArray *) packages {
1971 - (void) reloadData {
1981 if (!cache_.Open(progress_, true)) {
1982 fprintf(stderr, "repairing corrupted database...\n");
1985 _assert(cache_.Open(progress_, true));
1988 now_ = [NSDate date];
1990 records_ = new pkgRecords(cache_);
1991 resolver_ = new pkgProblemResolver(cache_);
1992 fetcher_ = new pkgAcquire(&status_);
1995 list_ = new pkgSourceList();
1996 _assert(list_->ReadMainList());
1998 [sources_ removeAllObjects];
1999 for (pkgSourceList::const_iterator source = list_->begin(); source != list_->end(); ++source) {
2000 std::vector<pkgIndexFile *> *indices = (*source)->GetIndexFiles();
2001 for (std::vector<pkgIndexFile *>::const_iterator index = indices->begin(); index != indices->end(); ++index)
2003 setObject:[[[Source alloc] initWithMetaIndex:*source] autorelease]
2004 forKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(*index)]
2008 [packages_ removeAllObjects];
2009 for (pkgCache::PkgIterator iterator = cache_->PkgBegin(); !iterator.end(); ++iterator)
2010 if (Package *package = [Package packageWithIterator:iterator database:self])
2011 if ([package source] != nil || [package installed] != nil)
2012 [packages_ addObject:package];
2016 pkgRecords records(cache_);
2018 lock_ = new FileFd();
2019 lock_->Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
2020 _assert(!_error->PendingError());
2023 _assert(list.ReadMainList());
2025 manager_ = (_system->CreatePM(cache_));
2026 _assert(manager_->GetArchives(fetcher_, &list, &records));
2027 _assert(!_error->PendingError());
2031 if (fetcher_->Run(PulseInterval_) != pkgAcquire::Continue)
2035 pkgPackageManager::OrderResult result = manager_->DoInstall(statusfd_);
2037 if (result == pkgPackageManager::Failed)
2039 if (_error->PendingError())
2041 if (result != pkgPackageManager::Completed)
2047 _assert(list.ReadMainList());
2050 lock.Fd(GetLock(_config->FindDir("Dir::State::Lists") + "lock"));
2051 _assert(!_error->PendingError());
2053 pkgAcquire fetcher(&status_);
2054 _assert(list.GetIndexes(&fetcher));
2055 _assert(fetcher.Run(PulseInterval_) != pkgAcquire::Failed);
2057 bool failed = false;
2058 for (pkgAcquire::ItemIterator item = fetcher.ItemsBegin(); item != fetcher.ItemsEnd(); item++)
2059 if ((*item)->Status != pkgAcquire::Item::StatDone) {
2060 (*item)->Finished();
2064 if (!failed && _config->FindB("APT::Get::List-Cleanup", true) == true) {
2065 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists")));
2066 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/"));
2069 [Metadata_ setObject:[NSDate date] forKey:@"LastUpdate"];
2073 _assert(cache_->DelCount() == 0 && cache_->InstCount() == 0);
2074 _assert(pkgApplyStatus(cache_));
2076 if (cache_->BrokenCount() != 0) {
2077 _assert(pkgFixBroken(cache_));
2078 _assert(cache_->BrokenCount() == 0);
2079 _assert(pkgMinimizeUpgrade(cache_));
2082 _assert(pkgDistUpgrade(cache_));
2085 - (void) setDelegate:(id)delegate {
2086 delegate_ = delegate;
2087 status_.setDelegate(delegate);
2088 progress_.setDelegate(delegate);
2091 - (Source *) getSource:(const pkgCache::PkgFileIterator &)file {
2092 pkgIndexFile *index(NULL);
2093 list_->FindIndex(file, index);
2094 return [sources_ objectForKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(index)]];
2100 /* Progress Data {{{ */
2101 @interface ProgressData : NSObject {
2107 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object;
2114 @implementation ProgressData
2116 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object {
2117 if ((self = [super init]) != nil) {
2118 selector_ = selector;
2138 /* Progress View {{{ */
2139 @interface ProgressView : UIView <
2143 UIView *background_;
2144 UITransitionView *transition_;
2146 UINavigationBar *navbar_;
2147 UIProgressBar *progress_;
2148 UITextView *output_;
2149 UITextLabel *status_;
2155 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
2157 - (ProgressView *) initWithFrame:(struct CGRect)frame delegate:(id)delegate;
2158 - (void) setContentView:(UIView *)view;
2161 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
2163 - (void) _retachThread;
2164 - (void) _detachNewThreadData:(ProgressData *)data;
2165 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title;
2167 - (void) setError:(NSString *)error;
2168 - (void) _setError:(NSString *)error;
2170 - (void) setTitle:(NSString *)title;
2171 - (void) _setTitle:(NSString *)title;
2173 - (void) setPercent:(float)percent;
2174 - (void) _setPercent:(NSNumber *)percent;
2176 - (void) addOutput:(NSString *)output;
2177 - (void) _addOutput:(NSString *)output;
2180 @protocol ProgressViewDelegate
2181 - (void) progressViewIsComplete:(ProgressView *)sender;
2184 @implementation ProgressView
2188 if (background_ != nil)
2189 [background_ release];
2190 [transition_ release];
2193 [progress_ release];
2199 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
2200 if (bootstrap_ && from == overlay_ && to == view_)
2204 - (ProgressView *) initWithFrame:(struct CGRect)frame delegate:(id)delegate {
2205 if ((self = [super initWithFrame:frame]) != nil) {
2206 delegate_ = delegate;
2208 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
2210 CGColor black(space, 0.0, 0.0, 0.0, 1.0);
2211 CGColor white(space, 1.0, 1.0, 1.0, 1.0);
2212 CGColor clear(space, 0.0, 0.0, 0.0, 0.0);
2214 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
2215 [transition_ setDelegate:self];
2217 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
2220 [overlay_ setBackgroundColor:black];
2222 background_ = [[UIView alloc] initWithFrame:[self bounds]];
2223 [background_ setBackgroundColor:black];
2224 [self addSubview:background_];
2227 [self addSubview:transition_];
2229 CGSize navsize = [UINavigationBar defaultSize];
2230 CGRect navrect = {{0, 0}, navsize};
2232 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
2233 [overlay_ addSubview:navbar_];
2235 [navbar_ setBarStyle:1];
2236 [navbar_ setDelegate:self];
2238 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:nil] autorelease];
2239 [navbar_ pushNavigationItem:navitem];
2241 CGRect bounds = [overlay_ bounds];
2242 CGSize prgsize = [UIProgressBar defaultSize];
2245 (bounds.size.width - prgsize.width) / 2,
2246 bounds.size.height - prgsize.height - 20
2249 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
2250 [overlay_ addSubview:progress_];
2252 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(
2254 bounds.size.height - prgsize.height - 50,
2255 bounds.size.width - 20,
2259 [status_ setColor:white];
2260 [status_ setBackgroundColor:clear];
2262 [status_ setCentersHorizontally:YES];
2263 //[status_ setFont:font];
2265 output_ = [[UITextView alloc] initWithFrame:CGRectMake(
2267 navrect.size.height + 20,
2268 bounds.size.width - 20,
2269 bounds.size.height - navsize.height - 62 - navrect.size.height
2272 //[output_ setTextFont:@"Courier New"];
2273 [output_ setTextSize:12];
2275 [output_ setTextColor:white];
2276 [output_ setBackgroundColor:clear];
2278 [output_ setMarginTop:0];
2279 [output_ setAllowsRubberBanding:YES];
2281 [overlay_ addSubview:output_];
2282 [overlay_ addSubview:status_];
2284 [progress_ setStyle:0];
2286 CGColorSpaceRelease(space);
2290 - (void) setContentView:(UIView *)view {
2291 view_ = [view retain];
2294 - (void) resetView {
2295 [transition_ transition:6 toView:view_];
2298 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
2302 - (void) _retachThread {
2303 [delegate_ progressViewIsComplete:self];
2307 - (void) _detachNewThreadData:(ProgressData *)data {
2308 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
2310 [[data target] performSelector:[data selector] withObject:[data object]];
2313 [self performSelectorOnMainThread:@selector(_retachThread) withObject:nil waitUntilDone:YES];
2318 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title {
2319 [navbar_ popNavigationItem];
2320 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:title] autorelease];
2321 [navbar_ pushNavigationItem:navitem];
2323 [status_ setText:nil];
2324 [output_ setText:@""];
2325 [progress_ setProgress:0];
2327 [transition_ transition:6 toView:overlay_];
2330 detachNewThreadSelector:@selector(_detachNewThreadData:)
2332 withObject:[[ProgressData alloc]
2333 initWithSelector:selector
2340 - (void) setError:(NSString *)error {
2342 performSelectorOnMainThread:@selector(_setError:)
2348 - (void) _setError:(NSString *)error {
2349 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
2350 initWithTitle:@"Package Error"
2351 buttons:[NSArray arrayWithObjects:@"Okay", nil]
2352 defaultButtonIndex:0
2357 [sheet setBodyText:error];
2358 [sheet popupAlertAnimated:YES];
2361 - (void) setTitle:(NSString *)title {
2363 performSelectorOnMainThread:@selector(_setTitle:)
2369 - (void) _setTitle:(NSString *)title {
2370 [status_ setText:[title stringByAppendingString:@"..."]];
2373 - (void) setPercent:(float)percent {
2375 performSelectorOnMainThread:@selector(_setPercent:)
2376 withObject:[NSNumber numberWithFloat:percent]
2381 - (void) _setPercent:(NSNumber *)percent {
2382 [progress_ setProgress:[percent floatValue]];
2385 - (void) addOutput:(NSString *)output {
2387 performSelectorOnMainThread:@selector(_addOutput:)
2393 - (void) _addOutput:(NSString *)output {
2394 [output_ setText:[NSString stringWithFormat:@"%@\n%@", [output_ text], output]];
2395 CGSize size = [output_ contentSize];
2396 CGRect rect = {{0, size.height}, {size.width, 0}};
2397 [output_ scrollRectToVisible:rect animated:YES];
2403 /* Package Table {{{ */
2404 @protocol PackageTableDelegate
2405 - (void) packageTable:(id)table packageSelected:(Package *)package;
2408 @interface PackageTable : UIView {
2410 UISectionList *list_;
2414 NSMutableArray *sections_;
2419 - (int) numberOfSectionsInSectionList:(UISectionList *)list;
2420 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section;
2421 - (int) sectionList:(UISectionList *)list rowForSection:(int)section;
2423 - (int) numberOfRowsInTable:(UITable *)table;
2424 - (float) table:(UITable *)table heightForRow:(int)row;
2425 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing;
2426 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row;
2427 - (void) tableRowSelected:(NSNotification *)notification;
2429 - (id) initWithFrame:(CGRect)frame versioner:(SEL)versioner;
2431 - (void) setDelegate:(id)delegate;
2432 - (void) setPackages:(NSArray *)packages;
2434 - (void) resetViewAnimated:(BOOL)animated;
2435 - (UITable *) table;
2438 @implementation PackageTable
2442 [sections_ release];
2443 if (packages_ != nil)
2444 [packages_ release];
2448 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
2449 return [sections_ count];
2452 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
2453 return [[sections_ objectAtIndex:section] name];
2456 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
2457 return [[sections_ objectAtIndex:section] row];
2460 - (int) numberOfRowsInTable:(UITable *)table {
2461 return [packages_ count];
2464 - (float) table:(UITable *)table heightForRow:(int)row {
2468 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2470 reusing = [[[PackageCell alloc] initWithVersioner:versioner_] autorelease];
2471 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
2475 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
2479 - (void) tableRowSelected:(NSNotification *)notification {
2480 int row = [[notification object] selectedRow];
2481 [delegate_ packageTable:self packageSelected:(row == INT_MAX ? nil : [packages_ objectAtIndex:row])];
2484 - (id) initWithFrame:(CGRect)frame versioner:(SEL)versioner {
2485 if ((self = [super initWithFrame:frame]) != nil) {
2486 versioner_ = versioner;
2487 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
2489 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:YES];
2490 [list_ setDataSource:self];
2492 UITableColumn *column = [[[UITableColumn alloc]
2493 initWithTitle:@"Name"
2495 width:frame.size.width
2498 UITable *table = [list_ table];
2499 [table setSeparatorStyle:1];
2500 [table addTableColumn:column];
2501 [table setDelegate:self];
2502 [table setReusesTableCells:YES];
2504 [self addSubview:list_];
2508 - (void) setDelegate:(id)delegate {
2509 delegate_ = delegate;
2512 - (void) setPackages:(NSArray *)packages {
2513 if (packages_ != nil)
2514 [packages_ autorelease];
2515 _assert(packages != nil);
2516 packages_ = [packages retain];
2518 [sections_ removeAllObjects];
2520 Section *section = nil;
2522 for (size_t offset(0); offset != [packages_ count]; ++offset) {
2523 Package *package = [packages_ objectAtIndex:offset];
2524 NSString *name = [package index];
2526 if (section == nil || ![[section name] isEqual:name]) {
2527 section = [[[Section alloc] initWithName:name row:offset] autorelease];
2528 [sections_ addObject:section];
2531 [section addPackage:package];
2537 - (void) resetViewAnimated:(BOOL)animated {
2538 [[list_ table] selectRow:-1 byExtendingSelection:NO withFade:animated];
2541 - (UITable *) table {
2542 return [list_ table];
2548 /* Section Cell {{{ */
2549 @interface SectionCell : UITableCell {
2551 UITextLabel *count_;
2557 - (void) setSection:(Section *)section;
2559 - (void) _setSelected:(float)fraction;
2560 - (void) setSelected:(BOOL)selected;
2561 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
2562 - (void) _setSelectionFadeFraction:(float)fraction;
2566 @implementation SectionCell
2575 if ((self = [super init]) != nil) {
2576 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22);
2577 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 12);
2579 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
2580 CGColor clear(space, 0, 0, 0, 0);
2581 CGColor white(space, 1, 1, 1, 1);
2583 name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 9, 250, 25)];
2584 [name_ setBackgroundColor:clear];
2585 [name_ setFont:bold];
2587 count_ = [[UITextLabel alloc] initWithFrame:CGRectMake(11, 7, 29, 32)];
2588 [count_ setCentersHorizontally:YES];
2589 [count_ setBackgroundColor:clear];
2590 [count_ setFont:small];
2591 [count_ setColor:white];
2593 UIImageView *folder = [[[UIImageView alloc] initWithFrame:CGRectMake(8, 7, 32, 32)] autorelease];
2594 [folder setImage:[UIImage applicationImageNamed:@"folder.png"]];
2596 [self addSubview:folder];
2597 [self addSubview:name_];
2598 [self addSubview:count_];
2600 [self _setSelected:0];
2602 CGColorSpaceRelease(space);
2609 - (void) setSection:(Section *)section {
2610 if (section == nil) {
2611 [name_ setText:@"All Packages"];
2612 [count_ setText:nil];
2614 NSString *name = [section name];
2615 [name_ setText:(name == nil ? @"(No Section)" : name)];
2616 [count_ setText:[NSString stringWithFormat:@"%d", [section count]]];
2620 - (void) _setSelected:(float)fraction {
2621 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
2623 CGColor black(space,
2624 interpolate(0.0, 1.0, fraction),
2625 interpolate(0.0, 1.0, fraction),
2626 interpolate(0.0, 1.0, fraction),
2629 [name_ setColor:black];
2631 CGColorSpaceRelease(space);
2634 - (void) setSelected:(BOOL)selected {
2635 [self _setSelected:(selected ? 1.0 : 0.0)];
2636 [super setSelected:selected];
2639 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
2641 [self _setSelected:(selected ? 1.0 : 0.0)];
2642 [super setSelected:selected withFade:fade];
2645 - (void) _setSelectionFadeFraction:(float)fraction {
2646 [self _setSelected:fraction];
2647 [super _setSelectionFadeFraction:fraction];
2652 /* Install View {{{ */
2653 @interface InstallView : ResetView <
2654 PackageTableDelegate
2658 PackageTable *table_;
2662 NSMutableArray *packages_;
2667 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
2669 - (int) numberOfRowsInTable:(UITable *)table;
2670 - (float) table:(UITable *)table heightForRow:(int)row;
2671 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing;
2672 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row;
2673 - (void) tableRowSelected:(NSNotification *)notification;
2675 - (void) packageTable:(id)table packageSelected:(Package *)package;
2677 - (id) initWithFrame:(CGRect)frame;
2678 - (void) setPackages:(NSArray *)packages;
2679 - (void) setDelegate:(id)delegate;
2682 @implementation InstallView
2685 [packages_ release];
2686 if (sections_ != nil)
2687 [sections_ release];
2694 if (section_ != nil)
2696 if (package_ != nil)
2701 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2703 [[view_ package] install];
2704 [delegate_ resolve];
2705 [delegate_ perform];
2709 - (int) numberOfRowsInTable:(UITable *)table {
2710 return [sections_ count] + 1;
2713 - (float) table:(UITable *)table heightForRow:(int)row {
2717 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2719 reusing = [[[SectionCell alloc] init] autorelease];
2721 [(SectionCell *)reusing setSection:nil];
2723 [(SectionCell *)reusing setSection:[sections_ objectAtIndex:(row - 1)]];
2727 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
2731 - (void) tableRowSelected:(NSNotification *)notification {
2732 int row = [[notification object] selectedRow];
2734 if (row == INT_MAX) {
2741 _assert(section_ == nil);
2742 _assert(table_ == nil);
2750 name = @"All Packages";
2752 section = [sections_ objectAtIndex:(row - 1)];
2753 name = [section name];
2754 section_ = [name retain];
2757 table_ = [[PackageTable alloc] initWithFrame:[transition_ bounds] versioner:@selector(latest)];
2758 [table_ setDelegate:self];
2759 [table_ setPackages:(section == nil ? packages_ : [section packages])];
2761 [self pushView:table_ withTitle:name backButtonTitle:@"Packages" rightButton:nil];
2765 - (void) packageTable:(id)table packageSelected:(Package *)package {
2766 if (package == nil) {
2773 _assert(package_ == nil);
2774 _assert(view_ == nil);
2776 package_ = [[package name] retain];
2778 view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]];
2779 [view_ setDelegate:delegate_];
2781 [view_ setPackage:package];
2783 [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:@"Install"];
2787 - (id) initWithFrame:(CGRect)frame {
2788 if ((self = [super initWithFrame:frame]) != nil) {
2789 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
2791 list_ = [[UITable alloc] initWithFrame:[transition_ bounds]];
2792 [self pushView:list_ withTitle:@"Install" backButtonTitle:@"Sections" rightButton:nil];
2794 UITableColumn *column = [[[UITableColumn alloc]
2795 initWithTitle:@"Name"
2797 width:frame.size.width
2800 [list_ setDataSource:self];
2801 [list_ setSeparatorStyle:1];
2802 [list_ addTableColumn:column];
2803 [list_ setDelegate:self];
2804 [list_ setReusesTableCells:YES];
2806 [transition_ transition:0 toView:list_];
2810 - (void) setPackages:(NSArray *)packages {
2811 [packages_ removeAllObjects];
2813 for (size_t i(0); i != [packages count]; ++i) {
2814 Package *package([packages objectAtIndex:i]);
2815 if ([package installed] == nil)
2816 [packages_ addObject:package];
2819 [packages_ sortUsingSelector:@selector(compareBySectionAndName:)];
2820 NSMutableArray *sections = [NSMutableArray arrayWithCapacity:16];
2822 Section *nsection = nil;
2823 Package *npackage = nil;
2825 Section *section = nil;
2826 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
2827 Package *package = [packages_ objectAtIndex:offset];
2828 NSString *name = [package section];
2830 if (section == nil || name != nil && ![[section name] isEqual:name]) {
2831 section = [[[Section alloc] initWithName:name row:offset] autorelease];
2833 if (name == nil || [name isEqualToString:section_])
2835 [sections addObject:section];
2838 if ([[package name] isEqualToString:package_])
2840 [section addPackage:package];
2843 if (sections_ != nil)
2844 [sections_ release];
2845 sections_ = [sections retain];
2847 [packages_ sortUsingSelector:@selector(compareByName:)];
2853 if (npackage != nil)
2854 [view_ setPackage:npackage];
2855 else if (package_ != nil)
2858 if (table_ != nil && section_ == nil)
2859 [table_ setPackages:packages_];
2860 else if (nsection != nil)
2861 [table_ setPackages:[nsection packages]];
2862 else if (section_ != nil)
2866 [self popViews:views];
2870 - (void) setDelegate:(id)delegate {
2872 [view_ setDelegate:delegate];
2873 [super setDelegate:delegate];
2878 /* Changes View {{{ */
2879 @interface ChangesView : ResetView <
2880 PackageTableDelegate
2882 UISectionList *list_;
2883 NSMutableArray *packages_;
2884 NSMutableArray *sections_;
2892 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
2894 - (int) numberOfSectionsInSectionList:(UISectionList *)list;
2895 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section;
2896 - (int) sectionList:(UISectionList *)list rowForSection:(int)section;
2898 - (int) numberOfRowsInTable:(UITable *)table;
2899 - (float) table:(UITable *)table heightForRow:(int)row;
2900 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing;
2901 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row;
2902 - (void) tableRowSelected:(NSNotification *)notification;
2904 - (id) initWithFrame:(CGRect)frame;
2905 - (void) setPackages:(NSArray *)packages;
2906 - (void) _resetView;
2909 - (void) setDelegate:(id)delegate;
2912 @implementation ChangesView
2916 [packages_ release];
2917 [sections_ release];
2920 if (package_ != nil)
2925 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
2926 return [sections_ count];
2929 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
2930 return [[sections_ objectAtIndex:section] name];
2933 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
2934 return [[sections_ objectAtIndex:section] row];
2937 - (int) numberOfRowsInTable:(UITable *)table {
2938 return [packages_ count];
2941 - (float) table:(UITable *)table heightForRow:(int)row {
2945 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2947 reusing = [[[PackageCell alloc] initWithVersioner:NULL] autorelease];
2948 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
2952 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
2956 - (void) tableRowSelected:(NSNotification *)notification {
2957 int row = [[notification object] selectedRow];
2958 [self packageTable:self packageSelected:(row == INT_MAX ? nil : [packages_ objectAtIndex:row])];
2961 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2964 [[view_ package] install];
2965 [delegate_ resolve];
2966 [delegate_ perform];
2970 [delegate_ upgrade];
2975 - (void) packageTable:(id)table packageSelected:(Package *)package {
2976 if (package == nil) {
2983 _assert(package_ == nil);
2984 _assert(view_ == nil);
2986 package_ = [[package name] retain];
2988 view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]];
2989 [view_ setDelegate:delegate_];
2991 [view_ setPackage:package];
2993 [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:(
2994 [package upgradable] ? @"Upgrade" : @"Install"
2999 - (id) initWithFrame:(CGRect)frame {
3000 if ((self = [super initWithFrame:frame]) != nil) {
3001 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
3002 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
3004 list_ = [[UISectionList alloc] initWithFrame:[transition_ bounds] showSectionIndex:NO];
3005 [list_ setShouldHideHeaderInShortLists:NO];
3006 [list_ setDataSource:self];
3007 //[list_ setSectionListStyle:1];
3009 UITableColumn *column = [[[UITableColumn alloc]
3010 initWithTitle:@"Name"
3012 width:frame.size.width
3015 UITable *table = [list_ table];
3016 [table setSeparatorStyle:1];
3017 [table addTableColumn:column];
3018 [table setDelegate:self];
3019 [table setReusesTableCells:YES];
3021 [self pushView:list_ withTitle:@"Changes" backButtonTitle:nil rightButton:nil];
3025 - (void) setPackages:(NSArray *)packages {
3026 [packages_ removeAllObjects];
3027 for (size_t i(0); i != [packages count]; ++i) {
3028 Package *package([packages objectAtIndex:i]);
3029 if ([package installed] == nil || [package upgradable])
3030 [packages_ addObject:package];
3033 [packages_ sortUsingSelector:@selector(compareForChanges:)];
3035 [sections_ removeAllObjects];
3037 Section *upgradable = [[[Section alloc] initWithName:@"Available Upgrades" row:0] autorelease];
3038 Section *section = nil;
3041 Package *npackage = nil;
3042 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
3043 Package *package = [packages_ objectAtIndex:offset];
3044 if ([[package name] isEqualToString:package_])
3047 if ([package upgradable])
3048 [upgradable addPackage:package];
3050 NSDate *seen = [package seen];
3053 CFStringRef formatted = NULL;
3058 CFLocaleRef locale = CFLocaleCopyCurrent();
3059 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
3060 formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen);
3061 name = (NSString *) formatted;
3062 CFRelease(formatter);
3066 if (section == nil || ![[section name] isEqual:name]) {
3067 section = [[[Section alloc] initWithName:name row:offset] autorelease];
3068 [sections_ addObject:section];
3071 [section addPackage:package];
3073 if (formatted != NULL)
3074 CFRelease(formatted);
3078 count_ = [[upgradable packages] count];
3080 [sections_ insertObject:upgradable atIndex:0];
3084 if (npackage != nil)
3085 [view_ setPackage:npackage];
3086 else if (package_ != nil)
3093 - (void) _resetView {
3094 if ([views_ count] == 1)
3095 [navbar_ showButtonsWithLeftTitle:(count_ == 0 ? nil : @"Upgrade All") rightTitle:nil];
3102 - (void) setDelegate:(id)delegate {
3104 [view_ setDelegate:delegate];
3105 [super setDelegate:delegate];
3110 /* Manage View {{{ */
3111 @interface ManageView : ResetView <
3112 PackageTableDelegate
3114 PackageTable *table_;
3121 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
3123 - (void) packageTable:(id)table packageSelected:(Package *)package;
3125 - (id) initWithFrame:(CGRect)frame;
3126 - (void) setPackages:(NSArray *)packages;
3128 - (void) setDelegate:(id)delegate;
3131 @implementation ManageView
3137 if (package_ != nil)
3142 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
3144 [[view_ package] remove];
3145 [delegate_ resolve];
3146 [delegate_ perform];
3150 - (void) packageTable:(id)table packageSelected:(Package *)package {
3151 if (package == nil) {
3158 _assert(package_ == nil);
3159 _assert(view_ == nil);
3161 package_ = [[package name] retain];
3163 view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]];
3164 [view_ setDelegate:delegate_];
3166 [view_ setPackage:package];
3168 [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:@"Uninstall"];
3172 - (id) initWithFrame:(CGRect)frame {
3173 if ((self = [super initWithFrame:frame]) != nil) {
3174 table_ = [[PackageTable alloc] initWithFrame:[transition_ bounds] versioner:@selector(latest)];
3175 [table_ setDelegate:self];
3177 [self pushView:table_ withTitle:@"Uninstall" backButtonTitle:@"Packages" rightButton:nil];
3181 - (void) setPackages:(NSArray *)packages {
3182 NSMutableArray *local = [NSMutableArray arrayWithCapacity:16];
3183 for (size_t i(0); i != [packages count]; ++i) {
3184 Package *package([packages objectAtIndex:i]);
3185 if ([package installed] != nil)
3186 [local addObject:package];
3189 [local sortUsingSelector:@selector(compareByName:)];
3191 Package *npackage = nil;
3192 for (size_t offset = 0, count = [local count]; offset != count; ++offset) {
3193 Package *package = [local objectAtIndex:offset];
3194 if ([[package name] isEqualToString:package_])
3198 [table_ setPackages:local];
3200 if (npackage != nil)
3201 [view_ setPackage:npackage];
3202 else if (package_ != nil)
3208 - (void) setDelegate:(id)delegate {
3210 [view_ setDelegate:delegate];
3211 [super setDelegate:delegate];
3216 /* Search View {{{ */
3217 @protocol SearchViewDelegate
3218 - (void) showKeyboard:(BOOL)show;
3221 @interface SearchView : ResetView <
3222 PackageTableDelegate
3224 NSMutableArray *packages_;
3226 UISearchField *field_;
3227 PackageTable *table_;
3234 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
3235 - (void) packageTable:(id)table packageSelected:(Package *)package;
3237 - (void) textFieldDidBecomeFirstResponder:(UITextField *)field;
3238 - (void) textFieldDidResignFirstResponder:(UITextField *)field;
3240 - (void) keyboardInputChanged:(UIFieldEditor *)editor;
3241 - (BOOL) keyboardInput:(id)input shouldInsertText:(NSString *)text isMarkedText:(int)marked;
3243 - (id) initWithFrame:(CGRect)frame;
3244 - (void) setPackages:(NSArray *)packages;
3246 - (void) setDelegate:(id)delegate;
3247 - (void) resetPackage:(Package *)package;
3248 - (void) searchPackages;
3252 @implementation SearchView
3255 [packages_ release];
3256 [accessory_ release];
3261 if (package_ != nil)
3266 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
3268 Package *package = [view_ package];
3269 if ([package installed] == nil)
3273 [delegate_ resolve];
3274 [delegate_ perform];
3278 - (void) packageTable:(id)table packageSelected:(Package *)package {
3279 if (package == nil) {
3280 [navbar_ setAccessoryView:accessory_ animate:(resetting_ ? NO : YES) goingBack:YES];
3288 [navbar_ setAccessoryView:nil animate:YES goingBack:NO];
3290 _assert(package_ == nil);
3291 _assert(view_ == nil);
3293 package_ = [[package name] retain];
3295 view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]];
3296 [view_ setDelegate:delegate_];
3298 [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:nil];
3299 [self resetPackage:package];
3303 - (void) textFieldDidBecomeFirstResponder:(UITextField *)field {
3304 [delegate_ showKeyboard:YES];
3305 [table_ setEnabled:NO];
3307 /*CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
3308 CGColor dimmed(alpha, 0, 0, 0, 0.5);
3309 [editor_ setBackgroundColor:dimmed];
3310 CGColorSpaceRelease(space);*/
3313 - (void) textFieldDidResignFirstResponder:(UITextField *)field {
3314 [table_ setEnabled:YES];
3315 [delegate_ showKeyboard:NO];
3318 - (void) keyboardInputChanged:(UIFieldEditor *)editor {
3319 NSString *text([field_ text]);
3320 [field_ setClearButtonStyle:(text == nil || [text length] == 0 ? 0 : 2)];
3323 - (BOOL) keyboardInput:(id)input shouldInsertText:(NSString *)text isMarkedText:(int)marked {
3324 if ([text length] != 1 || [text characterAtIndex:0] != '\n')
3327 [self searchPackages];
3328 [field_ resignFirstResponder];
3332 - (id) initWithFrame:(CGRect)frame {
3333 if ((self = [super initWithFrame:frame]) != nil) {
3334 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
3336 table_ = [[PackageTable alloc] initWithFrame:[transition_ bounds] versioner:@selector(latest)];
3337 [table_ setDelegate:self];
3339 CGRect area = [self bounds];
3342 area.size.width -= 12;
3343 area.size.height = [UISearchField defaultHeight];
3345 field_ = [[UISearchField alloc] initWithFrame:area];
3347 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
3348 [field_ setFont:font];
3351 [field_ setPlaceholder:@"Package Names & Descriptions"];
3352 [field_ setPaddingTop:5];
3353 [field_ setDelegate:self];
3355 UITextTraits *traits = [field_ textTraits];
3356 [traits setEditingDelegate:self];
3357 [traits setReturnKeyType:6];
3359 accessory_ = [[UIView alloc] initWithFrame:CGRectMake(6, 6, area.size.width, area.size.height + 30)];
3360 [accessory_ addSubview:field_];
3362 [navbar_ setAccessoryView:accessory_];
3363 [self pushView:table_ withTitle:nil backButtonTitle:@"Search" rightButton:nil];
3365 /* XXX: for the love of god just fix this */
3366 [navbar_ removeFromSuperview];
3367 [reload_ removeFromSuperview];
3368 [configure_ removeFromSuperview];
3369 [self addSubview:navbar_];
3370 [self addSubview:reload_];
3371 [self addSubview:configure_];
3375 - (void) setPackages:(NSArray *)packages {
3376 [packages_ removeAllObjects];
3377 [packages_ addObjectsFromArray:packages];
3378 [packages_ sortUsingSelector:@selector(compareByName:)];
3380 Package *npackage = nil;
3381 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
3382 Package *package = [packages_ objectAtIndex:offset];
3383 if ([[package name] isEqualToString:package_])
3387 [self searchPackages];
3389 if (npackage != nil)
3390 [self resetPackage:npackage];
3391 else if (package_ != nil)
3397 - (void) setDelegate:(id)delegate {
3399 [view_ setDelegate:delegate];
3400 [super setDelegate:delegate];
3403 - (void) resetPackage:(Package *)package {
3404 [view_ setPackage:package];
3405 NSString *right = [package installed] == nil ? @"Install" : @"Uninstall";
3406 [navbar_ showButtonsWithLeftTitle:nil rightTitle:right];
3409 - (void) searchPackages {
3410 NSString *text([field_ text]);
3412 NSMutableArray *packages([NSMutableArray arrayWithCapacity:16]);
3414 for (size_t offset(0), count([packages_ count]); offset != count; ++offset) {
3415 Package *package = [packages_ objectAtIndex:offset];
3416 if ([package matches:text])
3417 [packages addObject:package];
3420 [table_ setPackages:packages];
3421 [[table_ table] scrollPointVisibleAtTopLeft:CGPointMake(0, 0) animated:NO];
3427 @interface Cydia : UIApplication <
3428 ConfirmationViewDelegate,
3429 ProgressViewDelegate,
3436 UITransitionView *transition_;
3437 UIButtonBar *buttonbar_;
3439 ConfirmationView *confirm_;
3441 Database *database_;
3442 ProgressView *progress_;
3445 UINavigationBar *navbar_;
3446 UIScroller *scroller_;
3447 UIWebView *webview_;
3449 UIProgressIndicator *indicator_;
3451 InstallView *install_;
3452 ChangesView *changes_;
3453 ManageView *manage_;
3454 SearchView *search_;
3459 UIKeyboard *keyboard_;
3463 - (void) reloadData:(BOOL)reset;
3474 - (void) progressViewIsComplete:(ProgressView *)progress;
3476 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
3477 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
3478 - (void) buttonBarItemTapped:(id)sender;
3480 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old;
3482 - (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame;
3484 - (void) applicationWillSuspend;
3485 - (void) applicationDidFinishLaunching:(id)unused;
3488 @implementation Cydia
3491 NSMutableURLRequest *request = [NSMutableURLRequest
3493 cachePolicy:NSURLRequestReloadIgnoringCacheData
3494 timeoutInterval:30.0
3497 [request addValue:[NSString stringWithCString:Firmware_] forHTTPHeaderField:@"X-Firmware"];
3498 [request addValue:[NSString stringWithCString:Machine_] forHTTPHeaderField:@"X-Machine"];
3499 [request addValue:[NSString stringWithCString:SerialNumber_] forHTTPHeaderField:@"X-Serial-Number"];
3501 [webview_ loadRequest:request];
3504 - (void) reloadData:(BOOL)reset {
3505 [database_ reloadData];
3509 if (Packages_ == nil) {
3510 Packages_ = [[NSMutableDictionary alloc] initWithCapacity:count];
3511 [Metadata_ setObject:Packages_ forKey:@"Packages"];
3514 NSArray *packages = [database_ packages];
3516 [install_ setPackages:packages];
3517 [changes_ setPackages:packages];
3518 [manage_ setPackages:packages];
3519 [search_ setPackages:packages];
3521 if (size_t count = [changes_ count]) {
3522 NSString *badge([[NSNumber numberWithInt:count] stringValue]);
3523 [buttonbar_ setBadgeValue:badge forButton:3];
3524 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
3525 [buttonbar_ setBadgeAnimated:YES forButton:3];
3526 [self setApplicationBadge:badge];
3528 [buttonbar_ setBadgeValue:nil forButton:3];
3529 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
3530 [buttonbar_ setBadgeAnimated:NO forButton:3];
3531 [self removeApplicationBadge];
3534 _assert([Metadata_ writeToFile:@"/var/lib/cydia/metadata.plist" atomically:YES] == YES);
3537 - (void) setPrompt {
3538 [navbar_ setPrompt:[NSString stringWithFormat:@"Last Updated: %@", GetLastUpdate()]];
3542 pkgProblemResolver *resolver = [database_ resolver];
3544 resolver->InstallProtect();
3545 if (!resolver->Resolve(true))
3550 [database_ prepare];
3552 if ([database_ cache]->BrokenCount() == 0)
3553 confirm_ = [[ConfirmationView alloc] initWithView:underlay_ database:database_ delegate:self];
3555 NSMutableArray *broken = [NSMutableArray arrayWithCapacity:16];
3556 NSArray *packages = [database_ packages];
3558 for (size_t i(0); i != [packages count]; ++i) {
3559 Package *package = [packages objectAtIndex:i];
3560 if ([package broken])
3561 [broken addObject:[package name]];
3564 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
3565 initWithTitle:[NSString stringWithFormat:@"%d Broken Packages", [database_ cache]->BrokenCount()]
3566 buttons:[NSArray arrayWithObjects:@"Okay", nil]
3567 defaultButtonIndex:0
3572 [sheet setBodyText:[NSString stringWithFormat:@"The following packages have unmet dependencies:\n\n%@", [broken componentsJoinedByString:@"\n"]]];
3573 [sheet popupAlertAnimated:YES];
3575 [self reloadData:NO];
3580 [database_ upgrade];
3585 [self reloadData:NO];
3591 [overlay_ removeFromSuperview];
3595 detachNewThreadSelector:@selector(perform)
3602 - (void) bootstrap_ {
3604 [database_ upgrade];
3605 [database_ prepare];
3606 [database_ perform];
3609 - (void) bootstrap {
3611 detachNewThreadSelector:@selector(bootstrap_)
3614 title:@"Bootstrap Install..."
3620 detachNewThreadSelector:@selector(update)
3623 title:@"Refreshing Sources..."
3627 - (void) progressViewIsComplete:(ProgressView *)progress {
3628 [self reloadData:YES];
3630 if (confirm_ != nil) {
3631 [underlay_ addSubview:overlay_];
3632 [confirm_ removeFromSuperview];
3638 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
3645 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
3646 initWithTitle:@"About Cydia Packager"
3647 buttons:[NSArray arrayWithObjects:@"Close", nil]
3648 defaultButtonIndex:0
3654 @"Copyright (C) 2008\n"
3655 "Jay Freeman (saurik)\n"
3656 "saurik@saurik.com\n"
3657 "http://www.saurik.com/\n"
3660 "http://www.theokorigroup.com/\n"
3662 "College of Creative Studies,\n"
3663 "University of California,\n"
3665 "http://www.ccs.ucsb.edu/\n"
3668 "bad_, BHSPitMonkey, cash, Cobra,\n"
3669 "core, Corona, crashx, cromas,\n"
3670 "Darken, dtzWill, Erica, francis,\n"
3671 "Godores, jerry, Kingstone, lounger,\n"
3672 "mbranes, rockabilly, tman, Wbiggs"
3675 [sheet presentSheetFromButtonBar:buttonbar_];
3680 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
3684 - (void) buttonBarItemTapped:(id)sender {
3686 unsigned tag = [sender tag];
3689 case 1: view = featured_; break;
3690 case 2: view = install_; break;
3691 case 3: view = changes_; break;
3692 case 4: view = manage_; break;
3693 case 5: view = search_; break;
3699 if ([view respondsToSelector:@selector(resetView:)])
3700 [(id) view resetView:(tag == tag_ ? NO : YES)];
3702 [transition_ transition:0 toView:view];
3705 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old {
3706 [scroller_ setContentSize:frame.size];
3707 [indicator_ stopAnimation];
3710 - (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame {
3711 [navbar_ setPrompt:title];
3714 - (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame {
3715 [navbar_ setPrompt:@"Loading..."];
3716 [indicator_ startAnimation];
3719 - (void) applicationWillSuspend {
3721 if (FW_LEAST(1,1,3))
3722 notify_post("com.apple.language.changed");
3724 system("launchctl stop com.apple.SpringBoard");
3726 [super applicationWillSuspend];
3729 - (void) applicationDidFinishLaunching:(id)unused {
3730 _assert(pkgInitConfig(*_config));
3731 _assert(pkgInitSystem(*_config, _system));
3737 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
3738 window_ = [[UIWindow alloc] initWithContentRect:screenrect];
3740 [window_ orderFront: self];
3741 [window_ makeKey: self];
3742 [window_ _setHidden: NO];
3744 progress_ = [[ProgressView alloc] initWithFrame:[window_ bounds] delegate:self];
3745 [window_ setContentView:progress_];
3747 underlay_ = [[UIView alloc] initWithFrame:[progress_ bounds]];
3748 [progress_ setContentView:underlay_];
3750 overlay_ = [[UIView alloc] initWithFrame:[underlay_ bounds]];
3753 [underlay_ addSubview:overlay_];
3755 transition_ = [[UITransitionView alloc] initWithFrame:CGRectMake(
3756 0, 0, screenrect.size.width, screenrect.size.height - 48
3759 [overlay_ addSubview:transition_];
3761 featured_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
3763 CGSize navsize = [UINavigationBar defaultSizeWithPrompt];
3764 CGRect navrect = {{0, 0}, navsize};
3766 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
3767 [featured_ addSubview:navbar_];
3769 [navbar_ setBarStyle:1];
3770 [navbar_ setDelegate:self];
3772 [navbar_ showButtonsWithLeftTitle:@"About" rightTitle:@"Reload"];
3774 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Featured"] autorelease];
3775 [navbar_ pushNavigationItem:navitem];
3777 struct CGRect subbounds = [featured_ bounds];
3778 subbounds.origin.y += navsize.height;
3779 subbounds.size.height -= navsize.height;
3781 UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:subbounds] autorelease];
3782 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
3783 [featured_ addSubview:pinstripe];
3785 scroller_ = [[UIScroller alloc] initWithFrame:subbounds];
3786 [featured_ addSubview:scroller_];
3788 [scroller_ setScrollingEnabled:YES];
3789 [scroller_ setAdjustForContentSizeChange:YES];
3790 [scroller_ setClipsSubviews:YES];
3791 [scroller_ setAllowsRubberBanding:YES];
3792 [scroller_ setScrollDecelerationFactor:0.99];
3793 [scroller_ setDelegate:self];
3795 CGRect webrect = [scroller_ bounds];
3796 webrect.size.height = 0;
3798 webview_ = [[UIWebView alloc] initWithFrame:webrect];
3799 [scroller_ addSubview:webview_];
3801 [webview_ setTilingEnabled:YES];
3802 [webview_ setTileSize:CGSizeMake(screenrect.size.width, 500)];
3803 [webview_ setAutoresizes:YES];
3804 [webview_ setDelegate:self];
3806 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:2];
3807 indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(87, 45, indsize.width, indsize.height)];
3808 [indicator_ setStyle:2];
3809 [featured_ addSubview:indicator_];
3811 NSArray *buttonitems = [NSArray arrayWithObjects:
3812 [NSDictionary dictionaryWithObjectsAndKeys:
3813 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3814 @"featured-up.png", kUIButtonBarButtonInfo,
3815 @"featured-dn.png", kUIButtonBarButtonSelectedInfo,
3816 [NSNumber numberWithInt:1], kUIButtonBarButtonTag,
3817 self, kUIButtonBarButtonTarget,
3818 @"Featured", kUIButtonBarButtonTitle,
3819 @"0", kUIButtonBarButtonType,
3822 [NSDictionary dictionaryWithObjectsAndKeys:
3823 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3824 @"install-up.png", kUIButtonBarButtonInfo,
3825 @"install-dn.png", kUIButtonBarButtonSelectedInfo,
3826 [NSNumber numberWithInt:2], kUIButtonBarButtonTag,
3827 self, kUIButtonBarButtonTarget,
3828 @"Install", kUIButtonBarButtonTitle,
3829 @"0", kUIButtonBarButtonType,
3832 [NSDictionary dictionaryWithObjectsAndKeys:
3833 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3834 @"changes-up.png", kUIButtonBarButtonInfo,
3835 @"changes-dn.png", kUIButtonBarButtonSelectedInfo,
3836 [NSNumber numberWithInt:3], kUIButtonBarButtonTag,
3837 self, kUIButtonBarButtonTarget,
3838 @"Changes", kUIButtonBarButtonTitle,
3839 @"0", kUIButtonBarButtonType,
3842 [NSDictionary dictionaryWithObjectsAndKeys:
3843 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3844 @"manage-up.png", kUIButtonBarButtonInfo,
3845 @"manage-dn.png", kUIButtonBarButtonSelectedInfo,
3846 [NSNumber numberWithInt:4], kUIButtonBarButtonTag,
3847 self, kUIButtonBarButtonTarget,
3848 @"Uninstall", kUIButtonBarButtonTitle,
3849 @"0", kUIButtonBarButtonType,
3852 [NSDictionary dictionaryWithObjectsAndKeys:
3853 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3854 @"search-up.png", kUIButtonBarButtonInfo,
3855 @"search-dn.png", kUIButtonBarButtonSelectedInfo,
3856 [NSNumber numberWithInt:5], kUIButtonBarButtonTag,
3857 self, kUIButtonBarButtonTarget,
3858 @"Search", kUIButtonBarButtonTitle,
3859 @"0", kUIButtonBarButtonType,
3863 buttonbar_ = [[UIButtonBar alloc]
3865 withFrame:CGRectMake(
3866 0, screenrect.size.height - 48,
3867 screenrect.size.width, 48
3869 withItemList:buttonitems
3872 [buttonbar_ setDelegate:self];
3873 [buttonbar_ setBarStyle:1];
3874 [buttonbar_ setButtonBarTrackingMode:2];
3876 int buttons[5] = {1, 2, 3, 4, 5};
3877 [buttonbar_ registerButtonGroup:0 withButtons:buttons withCount:5];
3878 [buttonbar_ showButtonGroup:0 withDuration:0];
3880 for (int i = 0; i != 5; ++i)
3881 [[buttonbar_ viewWithTag:(i + 1)] setFrame:CGRectMake(
3882 i * 64 + 2, 1, 60, 48
3885 [buttonbar_ showSelectionForButton:1];
3886 [transition_ transition:0 toView:featured_];
3888 [overlay_ addSubview:buttonbar_];
3890 [UIKeyboard initImplementationNow];
3892 CGRect edtrect = [overlay_ bounds];
3893 edtrect.origin.y += navsize.height;
3894 edtrect.size.height -= navsize.height;
3896 CGSize keysize = [UIKeyboard defaultSize];
3897 CGRect keyrect = {{0, [overlay_ bounds].size.height - keysize.height}, keysize};
3898 keyboard_ = [[UIKeyboard alloc] initWithFrame:keyrect];
3900 database_ = [[Database alloc] init];
3901 [database_ setDelegate:progress_];
3903 install_ = [[InstallView alloc] initWithFrame:[transition_ bounds]];
3904 [install_ setDelegate:self];
3906 changes_ = [[ChangesView alloc] initWithFrame:[transition_ bounds]];
3907 [changes_ setDelegate:self];
3909 manage_ = [[ManageView alloc] initWithFrame:[transition_ bounds]];
3910 [manage_ setDelegate:self];
3912 search_ = [[SearchView alloc] initWithFrame:[transition_ bounds]];
3913 [search_ setDelegate:self];
3915 [self reloadData:NO];
3917 Package *package([database_ packageWithName:@"cydia"]);
3918 NSString *application = package == nil ? @"Cydia" : [NSString
3919 stringWithFormat:@"Cydia/%@",
3923 WebView *webview = [webview_ webView];
3924 [webview setApplicationNameForUserAgent:application];
3925 [webview setFrameLoadDelegate:self];
3927 url_ = [NSURL URLWithString:@"http://cydia.saurik.com/"];
3930 [progress_ resetView];
3936 - (void) showKeyboard:(BOOL)show {
3938 [overlay_ addSubview:keyboard_];
3940 [keyboard_ removeFromSuperview];
3945 void AddPreferences(NSString *plist) {
3946 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
3948 NSMutableDictionary *settings = [[[NSMutableDictionary alloc] initWithContentsOfFile:plist] autorelease];
3949 _assert(settings != NULL);
3950 NSMutableArray *items = [settings objectForKey:@"items"];
3954 for (size_t i(0); i != [items count]; ++i) {
3955 NSMutableDictionary *item([items objectAtIndex:i]);
3956 NSString *label = [item objectForKey:@"label"];
3957 if (label != nil && [label isEqualToString:@"Cydia"]) {
3964 for (size_t i(0); i != [items count]; ++i) {
3965 NSDictionary *item([items objectAtIndex:i]);
3966 NSString *label = [item objectForKey:@"label"];
3967 if (label != nil && [label isEqualToString:@"General"]) {
3968 [items insertObject:[NSDictionary dictionaryWithObjectsAndKeys:
3969 @"CydiaSettings", @"bundle",
3970 @"PSLinkCell", @"cell",
3971 [NSNumber numberWithBool:YES], @"hasIcon",
3972 [NSNumber numberWithBool:YES], @"isController",
3974 nil] atIndex:(i + 1)];
3980 _assert([settings writeToFile:plist atomically:YES] == YES);
3987 id Alloc_(id self, SEL selector) {
3988 id object = alloc_(self, selector);
3989 fprintf(stderr, "[%s]A-%p\n", self->isa->name, object);
3993 int main(int argc, char *argv[]) {
3995 memset(nl, 0, sizeof(nl));
3996 nl[0].n_un.n_name = (char *) "_useMDNSResponder";
3997 nlist("/usr/lib/libc.dylib", nl);
3998 if (nl[0].n_type != N_UNDF)
3999 *(int *) nl[0].n_value = 0;
4001 bootstrap_ = argc > 1 && strcmp(argv[1], "--bootstrap") == 0;
4006 /*Method alloc = class_getClassMethod([NSObject class], @selector(alloc));
4007 alloc_ = alloc->method_imp;
4008 alloc->method_imp = (IMP) &Alloc_;*/
4010 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
4012 if (NSDictionary *sysver = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]) {
4013 if (NSString *prover = [sysver valueForKey:@"ProductVersion"]) {
4014 Firmware_ = strdup([prover UTF8String]);
4015 NSArray *versions = [prover componentsSeparatedByString:@"."];
4016 int count = [versions count];
4017 Major_ = count > 0 ? [[versions objectAtIndex:0] intValue] : 0;
4018 Minor_ = count > 1 ? [[versions objectAtIndex:1] intValue] : 0;
4019 BugFix_ = count > 2 ? [[versions objectAtIndex:2] intValue] : 0;
4024 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
4025 char *machine = new char[size];
4026 sysctlbyname("hw.machine", machine, &size, NULL, 0);
4029 if (CFMutableDictionaryRef dict = IOServiceMatching("IOPlatformExpertDevice"))
4030 if (io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, dict)) {
4031 if (CFTypeRef serial = IORegistryEntryCreateCFProperty(service, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0)) {
4032 SerialNumber_ = strdup(CFStringGetCStringPtr((CFStringRef) serial, CFStringGetSystemEncoding()));
4036 IOObjectRelease(service);
4039 /*AddPreferences(@"/Applications/Preferences.app/Settings-iPhone.plist");
4040 AddPreferences(@"/Applications/Preferences.app/Settings-iPod.plist");*/
4042 if ((Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"]) == NULL)
4043 Metadata_ = [[NSMutableDictionary alloc] initWithCapacity:2];
4045 Packages_ = [Metadata_ objectForKey:@"Packages"];
4047 setenv("CYDIA", "", _not(int));
4048 if (access("/User", F_OK) != 0)
4049 system("/usr/libexec/cydia/firmware.sh");
4050 system("dpkg --configure -a");
4052 UIApplicationMain(argc, argv, [Cydia class]);