1 /* #include Directives {{{ */
2 #include <Foundation/NSURL.h>
3 #include <UIKit/UIKit.h>
4 #import <GraphicsServices/GraphicsServices.h>
7 #include <ext/stdio_filebuf.h>
9 #include <apt-pkg/acquire.h>
10 #include <apt-pkg/acquire-item.h>
11 #include <apt-pkg/algorithms.h>
12 #include <apt-pkg/cachefile.h>
13 #include <apt-pkg/configuration.h>
14 #include <apt-pkg/debmetaindex.h>
15 #include <apt-pkg/error.h>
16 #include <apt-pkg/init.h>
17 #include <apt-pkg/pkgrecords.h>
18 #include <apt-pkg/sourcelist.h>
19 #include <apt-pkg/sptr.h>
21 #include <sys/sysctl.h>
25 #include <mach-o/nlist.h>
28 #include <objc/objc-class.h>
34 /* Extension Keywords {{{ */
35 #define _trace() fprintf(stderr, "_trace()@%s:%u[%s]\n", __FILE__, __LINE__, __FUNCTION__)
37 #define _assert(test) do \
39 fprintf(stderr, "_assert(%d:%s)@%s:%u[%s]\n", errno, #test, __FILE__, __LINE__, __FUNCTION__); \
44 #define _not(type) ((type) ~ (type) 0)
46 /* Miscellaneous Messages {{{ */
48 - (void) setApplicationNameForUserAgent:(NSString *)applicationName;
49 - (id) frameLoadDelegate;
50 - (void) setFrameLoadDelegate:(id)delegate;
53 @interface NSString (Cydia)
54 - (NSString *) stringByAddingPercentEscapes;
55 - (NSString *) stringByReplacingCharacter:(unsigned short)arg0 withCharacter:(unsigned short)arg1;
59 /* Reset View (UIView) {{{ */
60 @interface UIView (CYResetView)
61 - (void) resetViewAnimated:(BOOL)animated;
64 @implementation UIView (CYResetView)
66 - (void) resetViewAnimated:(BOOL)animated {
67 fprintf(stderr, "%s\n", self->isa->name);
73 /* Reset View (UITable) {{{ */
74 @interface UITable (CYResetView)
75 - (void) resetViewAnimated:(BOOL)animated;
78 @implementation UITable (CYResetView)
80 - (void) resetViewAnimated:(BOOL)animated {
81 [self selectRow:-1 byExtendingSelection:NO withFade:animated];
86 /* Reset View (UISectionList) {{{ */
87 @interface UISectionList (CYResetView)
88 - (void) resetViewAnimated:(BOOL)animated;
91 @implementation UISectionList (CYResetView)
93 - (void) resetViewAnimated:(BOOL)animated {
94 [[self table] resetViewAnimated:animated];
100 /* Perl-Compatible RegEx {{{ */
110 Pcre(const char *regex) :
115 code_ = pcre_compile(regex, 0, &error, &offset, NULL);
118 fprintf(stderr, "%d:%s\n", offset, error);
122 pcre_fullinfo(code_, study_, PCRE_INFO_CAPTURECOUNT, &capture_);
123 matches_ = new int[(capture_ + 1) * 3];
131 NSString *operator [](size_t match) {
133 stringWithCString:(data_ + matches_[match * 2])
134 length:(matches_[match * 2 + 1] - matches_[match * 2])
138 bool operator ()(const char *data, size_t size) {
140 return pcre_exec(code_, study_, data, size, 0, 0, matches_, (capture_ + 1) * 3) >= 0;
144 /* CoreGraphicsServices Primitives {{{ */
150 CGColor(CGColorSpaceRef space, float red, float green, float blue, float alpha) {
151 float color[] = {red, green, blue, alpha};
152 color_ = CGColorCreate(space, color);
156 CGColorRelease(color_);
159 operator CGColorRef() {
170 /* XXX: no GSFontRelease()? */
176 static const int PulseInterval_ = 50000;
178 const char *Firmware_ = NULL;
179 const char *Machine_ = NULL;
180 const char *SerialNumber_ = NULL;
186 #define FW_LEAST(major, minor, bugfix) \
187 (major < Major_ || major == Major_ && \
188 (minor < Minor_ || minor == Minor_ && \
191 bool bootstrap_ = false;
193 static NSMutableDictionary *Metadata_;
194 static NSMutableDictionary *Packages_;
197 NSString *GetLastUpdate() {
198 NSDate *update = [Metadata_ objectForKey:@"LastUpdate"];
201 return @"Never or Unknown";
203 CFLocaleRef locale = CFLocaleCopyCurrent();
204 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
205 CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) update);
207 CFRelease(formatter);
210 return [(NSString *) formatted autorelease];
213 @protocol ProgressDelegate
214 - (void) setError:(NSString *)error;
215 - (void) setTitle:(NSString *)title;
216 - (void) setPercent:(float)percent;
217 - (void) addOutput:(NSString *)output;
220 NSString *SizeString(double size) {
222 while (size > 1024) {
227 static const char *powers_[] = {"B", "kB", "MB", "GB"};
229 return [NSString stringWithFormat:@"%.1f%s", size, powers_[power]];
232 static const float TextViewOffset_ = 22;
234 UITextView *GetTextView(NSString *value, float left, bool html) {
235 UITextView *text([[[UITextView alloc] initWithFrame:CGRectMake(left, 3, 310 - left, 1000)] autorelease]);
236 [text setEditable:NO];
237 [text setTextSize:16];
239 [text setHTML:value];
241 [text setText:value];
242 [text setEnabled:NO];
244 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
245 CGColor clear(space, 0, 0, 0, 0);
246 [text setBackgroundColor:clear];
247 CGColorSpaceRelease(space);
249 CGRect frame = [text frame];
250 [text setFrame:frame];
251 CGRect rect = [text visibleTextRect];
252 frame.size.height = rect.size.height;
253 [text setFrame:frame];
258 /* Status Delegation {{{ */
260 public pkgAcquireStatus
271 void setDelegate(id delegate) {
272 delegate_ = delegate;
275 virtual bool MediaChange(std::string media, std::string drive) {
279 virtual void IMSHit(pkgAcquire::ItemDesc &item) {
282 virtual void Fetch(pkgAcquire::ItemDesc &item) {
283 [delegate_ setTitle:[NSString stringWithCString:("Downloading " + item.ShortDesc).c_str()]];
286 virtual void Done(pkgAcquire::ItemDesc &item) {
289 virtual void Fail(pkgAcquire::ItemDesc &item) {
291 item.Owner->Status == pkgAcquire::Item::StatIdle ||
292 item.Owner->Status == pkgAcquire::Item::StatDone
296 [delegate_ setError:[NSString stringWithCString:item.Owner->ErrorText.c_str()]];
299 virtual bool Pulse(pkgAcquire *Owner) {
300 bool value = pkgAcquireStatus::Pulse(Owner);
303 double(CurrentBytes + CurrentItems) /
304 double(TotalBytes + TotalItems)
307 [delegate_ setPercent:percent];
311 virtual void Start() {
314 virtual void Stop() {
318 /* Progress Delegation {{{ */
326 virtual void Update() {
327 [delegate_ setTitle:[NSString stringWithCString:Op.c_str()]];
328 [delegate_ setPercent:(Percent / 100)];
337 void setDelegate(id delegate) {
338 delegate_ = delegate;
341 virtual void Done() {
342 [delegate_ setPercent:1];
347 /* External Constants {{{ */
348 extern NSString *kUIButtonBarButtonAction;
349 extern NSString *kUIButtonBarButtonInfo;
350 extern NSString *kUIButtonBarButtonInfoOffset;
351 extern NSString *kUIButtonBarButtonSelectedInfo;
352 extern NSString *kUIButtonBarButtonStyle;
353 extern NSString *kUIButtonBarButtonTag;
354 extern NSString *kUIButtonBarButtonTarget;
355 extern NSString *kUIButtonBarButtonTitle;
356 extern NSString *kUIButtonBarButtonTitleVerticalHeight;
357 extern NSString *kUIButtonBarButtonTitleWidth;
358 extern NSString *kUIButtonBarButtonType;
360 /* Mime Addresses {{{ */
361 Pcre email_r("^\"?(.*)\"? <([^>]*)>$");
363 @interface Address : NSObject {
371 - (NSString *) email;
373 + (Address *) addressWithString:(NSString *)string;
374 - (Address *) initWithString:(NSString *)string;
377 @implementation Address
386 - (NSString *) name {
390 - (NSString *) email {
394 + (Address *) addressWithString:(NSString *)string {
395 return [[[Address alloc] initWithString:string] autorelease];
398 - (Address *) initWithString:(NSString *)string {
399 if ((self = [super init]) != nil) {
400 const char *data = [string UTF8String];
401 size_t size = [string length];
403 if (email_r(data, size)) {
404 name_ = [email_r[1] retain];
405 email_ = [email_r[2] retain];
407 name_ = [[NSString stringWithCString:data length:size] retain];
416 /* Right Alignment {{{ */
417 @interface UIRightTextLabel : UITextLabel {
418 float _savedRightEdgeX;
419 BOOL _sizedtofit_flag;
422 - (void) setFrame:(CGRect)frame;
423 - (void) setText:(NSString *)text;
424 - (void) realignText;
427 @implementation UIRightTextLabel
429 - (void) setFrame:(CGRect)frame {
430 [super setFrame:frame];
431 if (_sizedtofit_flag == NO) {
432 _savedRightEdgeX = frame.origin.x;
437 - (void) setText:(NSString *)text {
438 [super setText:text];
442 - (void) realignText {
443 CGRect oldFrame = [self frame];
445 _sizedtofit_flag = YES;
446 [self sizeToFit]; // shrink down size so I can right align it
448 CGRect newFrame = [self frame];
450 oldFrame.origin.x = _savedRightEdgeX - newFrame.size.width;
451 oldFrame.size.width = newFrame.size.width;
452 [super setFrame:oldFrame];
453 _sizedtofit_flag = NO;
458 /* Linear Algebra {{{ */
459 inline float interpolate(float begin, float end, float fraction) {
460 return (end - begin) * fraction + begin;
467 /* Database Interface {{{ */
468 @interface Database : NSObject {
470 pkgRecords *records_;
471 pkgProblemResolver *resolver_;
472 pkgAcquire *fetcher_;
474 SPtr<pkgPackageManager> manager_;
475 pkgSourceList *list_;
477 NSMutableDictionary *sources_;
487 - (void) _readStatus:(NSNumber *)fd;
488 - (void) _readOutput:(NSNumber *)fd;
490 - (Package *) packageWithName:(NSString *)name;
493 - (pkgCacheFile &) cache;
494 - (pkgRecords *) records;
495 - (pkgProblemResolver *) resolver;
496 - (pkgAcquire &) fetcher;
504 - (void) setDelegate:(id)delegate;
505 - (Source *) getSource:(const pkgCache::PkgFileIterator &)file;
510 @interface ResetView : UIView {
511 UIPushButton *configure_;
512 UIPushButton *reload_;
513 NSMutableArray *views_;
514 UINavigationBar *navbar_;
515 UITransitionView *transition_;
522 - (void) navigationBar:(UINavigationBar *)navbar poppedItem:(UINavigationItem *)item;
523 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
525 - (id) initWithFrame:(CGRect)frame;
526 - (void) setDelegate:(id)delegate;
528 - (void) configurePushed;
529 - (void) reloadPushed;
531 - (void) pushView:(UIView *)view withTitle:(NSString *)title backButtonTitle:(NSString *)back rightButton:(NSString *)right;
532 - (void) popViews:(unsigned)views;
533 - (void) resetView:(BOOL)clear;
538 @implementation ResetView
541 [configure_ release];
543 [transition_ release];
549 - (void) navigationBar:(UINavigationBar *)navbar poppedItem:(UINavigationItem *)item {
550 [views_ removeLastObject];
551 UIView *view([views_ lastObject]);
552 [view resetViewAnimated:!resetting_];
555 [transition_ transition:2 toView:view];
560 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
564 - (id) initWithFrame:(CGRect)frame {
565 if ((self = [super initWithFrame:frame]) != nil) {
566 views_ = [[NSMutableArray arrayWithCapacity:4] retain];
568 struct CGRect bounds = [self bounds];
569 CGSize navsize = [UINavigationBar defaultSizeWithPrompt];
570 CGRect navrect = {{0, 0}, navsize};
572 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
573 [self addSubview:navbar_];
575 [navbar_ setBarStyle:1];
576 [navbar_ setDelegate:self];
578 transition_ = [[UITransitionView alloc] initWithFrame:CGRectMake(
579 bounds.origin.x, bounds.origin.y + navsize.height, bounds.size.width, bounds.size.height - navsize.height
582 //configure_ = [[UIPushButton alloc] initWithFrame:CGRectMake(15, 9, 17, 18)];
583 configure_ = [[UIPushButton alloc] initWithFrame:CGRectMake(10, 9, 17, 18)];
584 [configure_ setShowPressFeedback:YES];
585 [configure_ setImage:[UIImage applicationImageNamed:@"configure.png"]];
586 [configure_ addTarget:self action:@selector(configurePushed) forEvents:1];
588 //reload_ = [[UIPushButton alloc] initWithFrame:CGRectMake(288, 5, 18, 22)];
589 reload_ = [[UIPushButton alloc] initWithFrame:CGRectMake(293, 5, 18, 22)];
590 [reload_ setShowPressFeedback:YES];
591 [reload_ setImage:[UIImage applicationImageNamed:@"reload.png"]];
592 [reload_ addTarget:self action:@selector(reloadPushed) forEvents:1];
594 [navbar_ addSubview:configure_];
595 [navbar_ addSubview:reload_];
597 [self addSubview:transition_];
601 - (void) setDelegate:(id)delegate {
602 delegate_ = delegate;
605 - (void) configurePushed {
606 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
607 initWithTitle:@"Sources Unimplemented"
608 buttons:[NSArray arrayWithObjects:@"Okay", nil]
614 [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'."];
615 [sheet popupAlertAnimated:YES];
618 - (void) reloadPushed {
622 - (void) pushView:(UIView *)view withTitle:(NSString *)title backButtonTitle:(NSString *)back rightButton:(NSString *)right {
623 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:title] autorelease];
624 [navbar_ pushNavigationItem:navitem];
625 [navitem setBackButtonTitle:back];
627 [navbar_ showButtonsWithLeftTitle:nil rightTitle:right];
629 [transition_ transition:([views_ count] == 0 ? 0 : 1) toView:view];
630 [views_ addObject:view];
633 - (void) popViews:(unsigned)views {
635 for (unsigned i(0); i != views; ++i)
636 [navbar_ popNavigationItem];
640 [transition_ transition:2 toView:[views_ lastObject]];
643 - (void) resetView:(BOOL)clear {
646 if ([views_ count] > 1) {
647 [navbar_ disableAnimation];
648 while ([views_ count] != (clear ? 1 : 2))
649 [navbar_ popNavigationItem];
650 [navbar_ enableAnimation];
652 [navbar_ popNavigationItem];
658 [transition_ transition:(clear ? 0 : 2) toView:[views_ lastObject]];
661 - (void) _resetView {
662 [navbar_ showButtonsWithLeftTitle:nil rightTitle:nil];
666 [navbar_ setPrompt:[NSString stringWithFormat:@"Last Updated: %@", GetLastUpdate()]];
671 /* Confirmation View {{{ */
672 void AddTextView(NSMutableDictionary *fields, NSMutableArray *packages, NSString *key) {
673 if ([packages count] == 0)
676 UITextView *text = GetTextView([packages count] == 0 ? @"n/a" : [packages componentsJoinedByString:@", "], 110, false);
677 [fields setObject:text forKey:key];
679 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
680 CGColor blue(space, 0, 0, 0.4, 1);
681 [text setTextColor:blue];
682 CGColorSpaceRelease(space);
685 @protocol ConfirmationViewDelegate
690 @interface ConfirmationView : UIView {
693 UITransitionView *transition_;
695 UINavigationBar *navbar_;
696 UIPreferencesTable *table_;
697 NSMutableDictionary *fields_;
698 UIAlertSheet *essential_;
704 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
705 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
706 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
708 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table;
709 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group;
710 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed;
711 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group;
712 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group;
714 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate;
718 @implementation ConfirmationView
721 [transition_ release];
726 if (essential_ != nil)
727 [essential_ release];
732 [transition_ transition:7 toView:nil];
736 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
737 if (from != nil && to == nil)
738 [self removeFromSuperview];
741 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
744 if (essential_ != nil)
745 [essential_ popupAlertAnimated:YES];
756 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
757 [essential_ dismiss];
761 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
765 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
767 case 0: return @"Statistics";
768 case 1: return @"Modifications";
770 default: _assert(false);
774 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
777 case 1: return [fields_ count];
779 default: _assert(false);
783 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
784 if (group != 1 || row == -1)
787 _assert(size_t(row) < [fields_ count]);
788 return [[[fields_ allValues] objectAtIndex:row] visibleTextRect].size.height + TextViewOffset_;
792 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
793 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
794 [cell setShowSelection:NO];
797 case 0: switch (row) {
799 [cell setTitle:@"Downloading"];
800 [cell setValue:SizeString([database_ fetcher].FetchNeeded())];
804 [cell setTitle:@"Resuming At"];
805 [cell setValue:SizeString([database_ fetcher].PartialPresent())];
809 double size([database_ cache]->UsrSize());
812 [cell setTitle:@"Disk Freeing"];
813 [cell setValue:SizeString(-size)];
815 [cell setTitle:@"Disk Using"];
816 [cell setValue:SizeString(size)];
820 default: _assert(false);
824 _assert(size_t(row) < [fields_ count]);
825 [cell setTitle:[[fields_ allKeys] objectAtIndex:row]];
826 [cell addSubview:[[fields_ allValues] objectAtIndex:row]];
829 default: _assert(false);
835 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate {
836 if ((self = [super initWithFrame:[view bounds]]) != nil) {
837 database_ = database;
838 delegate_ = delegate;
840 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
841 [self addSubview:transition_];
843 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
845 CGSize navsize = [UINavigationBar defaultSize];
846 CGRect navrect = {{0, 0}, navsize};
847 CGRect bounds = [overlay_ bounds];
849 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
850 [navbar_ setBarStyle:1];
851 [navbar_ setDelegate:self];
853 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Confirm"] autorelease];
854 [navbar_ pushNavigationItem:navitem];
855 [navbar_ showButtonsWithLeftTitle:@"Cancel" rightTitle:@"Confirm"];
857 fields_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
859 NSMutableArray *installing = [NSMutableArray arrayWithCapacity:16];
860 NSMutableArray *upgrading = [NSMutableArray arrayWithCapacity:16];
861 NSMutableArray *removing = [NSMutableArray arrayWithCapacity:16];
867 pkgCacheFile &cache([database_ cache]);
868 for (pkgCache::PkgIterator iterator = cache->PkgBegin(); !iterator.end(); ++iterator) {
869 NSString *name([NSString stringWithCString:iterator.Name()]);
870 bool essential((iterator->Flags & pkgCache::Flag::Essential) != 0);
872 if (cache[iterator].NewInstall()) {
875 [installing addObject:name];
876 } else if (cache[iterator].Upgrade()) {
879 [upgrading addObject:name];
880 } else if (cache[iterator].Delete()) {
883 [removing addObject:name];
890 essential_ = [[UIAlertSheet alloc]
891 initWithTitle:@"Unable to Comply"
892 buttons:[NSArray arrayWithObjects:@"Okay", nil]
898 [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."];
901 AddTextView(fields_, installing, @"Installing");
902 AddTextView(fields_, upgrading, @"Upgrading");
903 AddTextView(fields_, removing, @"Removing");
905 table_ = [[UIPreferencesTable alloc] initWithFrame:CGRectMake(
906 0, navsize.height, bounds.size.width, bounds.size.height - navsize.height
909 [table_ setReusesTableCells:YES];
910 [table_ setDataSource:self];
913 [overlay_ addSubview:navbar_];
914 [overlay_ addSubview:table_];
916 [view addSubview:self];
918 [transition_ setDelegate:self];
920 UIView *blank = [[[UIView alloc] initWithFrame:[transition_ bounds]] autorelease];
921 [transition_ transition:0 toView:blank];
922 [transition_ transition:3 toView:overlay_];
929 /* Source Class {{{ */
930 @interface Source : NSObject {
931 NSString *description_;
936 NSString *distribution_;
940 NSString *defaultIcon_;
947 - (Source *) initWithMetaIndex:(metaIndex *)index;
952 - (NSString *) distribution;
955 - (NSString *) description;
956 - (NSString *) label;
957 - (NSString *) origin;
958 - (NSString *) version;
960 - (NSString *) defaultIcon;
963 @implementation Source
967 [distribution_ release];
970 if (description_ != nil)
971 [description_ release];
982 - (Source *) initWithMetaIndex:(metaIndex *)index {
983 if ((self = [super init]) != nil) {
984 trusted_ = index->IsTrusted();
986 uri_ = [[NSString stringWithCString:index->GetURI().c_str()] retain];
987 distribution_ = [[NSString stringWithCString:index->GetDist().c_str()] retain];
988 type_ = [[NSString stringWithCString:index->GetType()] retain];
994 debReleaseIndex *dindex(dynamic_cast<debReleaseIndex *>(index));
995 if (dindex != NULL) {
996 std::ifstream release(dindex->MetaIndexFile("Release").c_str());
998 while (std::getline(release, line)) {
999 std::string::size_type colon(line.find(':'));
1000 if (colon == std::string::npos)
1003 std::string name(line.substr(0, colon));
1004 std::string value(line.substr(colon + 1));
1005 while (!value.empty() && value[0] == ' ')
1006 value = value.substr(1);
1008 if (name == "Default-Icon")
1009 defaultIcon_ = [[NSString stringWithCString:value.c_str()] retain];
1010 else if (name == "Description")
1011 description_ = [[NSString stringWithCString:value.c_str()] retain];
1012 else if (name == "Label")
1013 label_ = [[NSString stringWithCString:value.c_str()] retain];
1014 else if (name == "Origin")
1015 origin_ = [[NSString stringWithCString:value.c_str()] retain];
1016 else if (name == "Version")
1017 version_ = [[NSString stringWithCString:value.c_str()] retain];
1027 - (NSString *) uri {
1031 - (NSString *) distribution {
1032 return distribution_;
1035 - (NSString *) type {
1039 - (NSString *) description {
1040 return description_;
1043 - (NSString *) label {
1047 - (NSString *) origin {
1051 - (NSString *) version {
1055 - (NSString *) defaultIcon {
1056 return defaultIcon_;
1061 /* Package Class {{{ */
1062 NSString *Scour(const char *field, const char *begin, const char *end) {
1063 size_t i(0), l(strlen(field));
1066 const char *name = begin + i;
1067 const char *colon = name + l;
1068 const char *value = colon + 1;
1073 memcmp(name, field, l) == 0
1075 while (value != end && value[0] == ' ')
1077 const char *line = std::find(value, end, '\n');
1078 while (line != value && line[-1] == ' ')
1080 return [NSString stringWithCString:value length:(line - value)];
1082 begin = std::find(begin, end, '\n');
1090 @interface Package : NSObject {
1091 pkgCache::PkgIterator iterator_;
1092 Database *database_;
1093 pkgCache::VerIterator version_;
1094 pkgCache::VerFileIterator file_;
1098 NSString *installed_;
1109 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database version:(pkgCache::VerIterator)version file:(pkgCache::VerFileIterator)file;
1110 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
1112 - (NSString *) section;
1113 - (Address *) maintainer;
1115 - (NSString *) description;
1116 - (NSString *) index;
1120 - (NSString *) latest;
1121 - (NSString *) installed;
1122 - (BOOL) upgradable;
1125 - (NSString *) name;
1126 - (NSString *) tagline;
1127 - (NSString *) icon;
1128 - (NSString *) website;
1130 - (Source *) source;
1132 - (BOOL) matches:(NSString *)text;
1134 - (NSComparisonResult) compareByName:(Package *)package;
1135 - (NSComparisonResult) compareBySectionAndName:(Package *)package;
1136 - (NSComparisonResult) compareForChanges:(Package *)package;
1142 @implementation Package
1146 if (installed_ != nil)
1147 [installed_ release];
1155 if (website_ != nil)
1164 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database version:(pkgCache::VerIterator)version file:(pkgCache::VerFileIterator)file {
1165 if ((self = [super init]) != nil) {
1166 iterator_ = iterator;
1167 database_ = database;
1172 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1174 const char *begin, *end;
1175 parser->GetRec(begin, end);
1177 latest_ = [[NSString stringWithCString:version_.VerStr()] retain];
1178 installed_ = iterator_.CurrentVer().end() ? nil : [[NSString stringWithCString:iterator_.CurrentVer().VerStr()] retain];
1180 id_ = [[[NSString stringWithCString:iterator_.Name()] lowercaseString] retain];
1181 name_ = Scour("Name", begin, end);
1183 name_ = [name_ retain];
1184 tagline_ = [[NSString stringWithCString:parser->ShortDesc().c_str()] retain];
1185 icon_ = Scour("Icon", begin, end);
1187 icon_ = [icon_ retain];
1188 website_ = Scour("Website", begin, end);
1189 if (website_ != nil)
1190 website_ = [website_ retain];
1192 source_ = [[database_ getSource:file_.File()] retain];
1194 NSMutableDictionary *metadata = [Packages_ objectForKey:id_];
1195 if (metadata == nil) {
1196 metadata = [NSMutableDictionary dictionaryWithObjectsAndKeys:
1200 [Packages_ setObject:metadata forKey:id_];
1205 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
1206 for (pkgCache::VerIterator version = iterator.VersionList(); !version.end(); ++version)
1207 for (pkgCache::VerFileIterator file = version.FileList(); !file.end(); ++file)
1208 return [[[Package alloc]
1209 initWithIterator:iterator
1217 - (NSString *) section {
1218 const char *section = iterator_.Section();
1219 return section == NULL ? nil : [[NSString stringWithCString:section] stringByReplacingCharacter:'_' withCharacter:' '];
1222 - (Address *) maintainer {
1223 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1224 return [Address addressWithString:[NSString stringWithCString:parser->Maintainer().c_str()]];
1228 return version_->InstalledSize;
1231 - (NSString *) description {
1232 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1233 NSString *description([NSString stringWithCString:parser->LongDesc().c_str()]);
1235 NSArray *lines = [description componentsSeparatedByString:@"\n"];
1236 NSMutableArray *trimmed = [NSMutableArray arrayWithCapacity:([lines count] - 1)];
1237 if ([lines count] < 2)
1240 NSCharacterSet *whitespace = [NSCharacterSet whitespaceCharacterSet];
1241 for (size_t i(1); i != [lines count]; ++i) {
1242 NSString *trim = [[lines objectAtIndex:i] stringByTrimmingCharactersInSet:whitespace];
1243 [trimmed addObject:trim];
1246 return [trimmed componentsJoinedByString:@"\n"];
1249 - (NSString *) index {
1250 NSString *index = [[[self name] substringToIndex:1] uppercaseString];
1251 return [index length] != 0 && isalpha([index characterAtIndex:0]) ? index : @"123";
1255 return [[Packages_ objectForKey:id_] objectForKey:@"FirstSeen"];
1258 - (NSString *) latest {
1262 - (NSString *) installed {
1266 - (BOOL) upgradable {
1267 NSString *installed = [self installed];
1268 return installed != nil && [[self latest] compare:installed] != NSOrderedSame ? YES : NO;
1275 - (NSString *) name {
1276 return name_ == nil ? id_ : name_;
1279 - (NSString *) tagline {
1283 - (NSString *) icon {
1287 - (NSString *) website {
1291 - (Source *) source {
1295 - (BOOL) matches:(NSString *)text {
1301 range = [[self id] rangeOfString:text options:NSCaseInsensitiveSearch];
1302 if (range.location != NSNotFound)
1305 range = [[self name] rangeOfString:text options:NSCaseInsensitiveSearch];
1306 if (range.location != NSNotFound)
1309 range = [[self tagline] rangeOfString:text options:NSCaseInsensitiveSearch];
1310 if (range.location != NSNotFound)
1316 - (NSComparisonResult) compareByName:(Package *)package {
1317 NSString *lhs = [self name];
1318 NSString *rhs = [package name];
1320 if ([lhs length] != 0 && [rhs length] != 0) {
1321 unichar lhc = [lhs characterAtIndex:0];
1322 unichar rhc = [rhs characterAtIndex:0];
1324 if (isalpha(lhc) && !isalpha(rhc))
1325 return NSOrderedAscending;
1326 else if (!isalpha(lhc) && isalpha(rhc))
1327 return NSOrderedDescending;
1330 return [lhs caseInsensitiveCompare:rhs];
1333 - (NSComparisonResult) compareBySectionAndName:(Package *)package {
1334 NSString *lhs = [self section];
1335 NSString *rhs = [package section];
1337 if (lhs == NULL && rhs != NULL)
1338 return NSOrderedAscending;
1339 else if (lhs != NULL && rhs == NULL)
1340 return NSOrderedDescending;
1341 else if (lhs != NULL && rhs != NULL) {
1342 NSComparisonResult result = [lhs compare:rhs];
1343 if (result != NSOrderedSame)
1347 return [self compareByName:package];
1350 - (NSComparisonResult) compareForChanges:(Package *)package {
1351 BOOL lhs = [self upgradable];
1352 BOOL rhs = [package upgradable];
1355 return lhs ? NSOrderedAscending : NSOrderedDescending;
1357 switch ([[self seen] compare:[package seen]]) {
1358 case NSOrderedAscending:
1359 return NSOrderedDescending;
1362 case NSOrderedDescending:
1363 return NSOrderedAscending;
1369 return [self compareByName:package];
1373 pkgProblemResolver *resolver = [database_ resolver];
1374 resolver->Clear(iterator_);
1375 resolver->Protect(iterator_);
1376 [database_ cache]->MarkInstall(iterator_, false);
1380 pkgProblemResolver *resolver = [database_ resolver];
1381 resolver->Clear(iterator_);
1382 resolver->Protect(iterator_);
1383 resolver->Remove(iterator_);
1384 [database_ cache]->MarkDelete(iterator_, true);
1389 /* Section Class {{{ */
1390 @interface Section : NSObject {
1393 NSMutableArray *packages_;
1398 - (Section *) initWithName:(NSString *)name row:(size_t)row;
1399 - (NSString *) name;
1401 - (NSArray *) packages;
1403 - (void) addPackage:(Package *)package;
1406 @implementation Section
1410 [packages_ release];
1414 - (Section *) initWithName:(NSString *)name row:(size_t)row {
1415 if ((self = [super init]) != nil) {
1416 name_ = [name retain];
1418 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
1422 - (NSString *) name {
1430 - (NSArray *) packages {
1435 return [packages_ count];
1438 - (void) addPackage:(Package *)package {
1439 [packages_ addObject:package];
1445 /* Package View {{{ */
1446 @protocol PackageViewDelegate
1447 - (void) performPackage:(Package *)package;
1450 @interface PackageView : UIView {
1451 UIPreferencesTable *table_;
1453 UITextView *description_;
1459 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table;
1460 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group;
1461 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed;
1462 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group;
1463 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group;
1465 - (BOOL) canSelectRow:(int)row;
1466 - (void) tableRowSelected:(NSNotification *)notification;
1468 - (Package *) package;
1470 - (id) initWithFrame:(struct CGRect)frame;
1471 - (void) setPackage:(Package *)package;
1472 - (void) setDelegate:(id)delegate;
1475 @implementation PackageView
1478 if (package_ != nil)
1480 if (description_ != nil)
1481 [description_ release];
1486 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
1490 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
1493 case 1: return @"Package Details";
1494 case 2: return @"Source Information";
1496 default: _assert(false);
1500 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
1501 if (group != 0 || row != 1)
1504 return [description_ visibleTextRect].size.height + TextViewOffset_;
1507 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
1509 case 0: return [package_ website] == nil ? 2 : 3;
1513 default: _assert(false);
1517 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
1518 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
1519 [cell setShowSelection:NO];
1522 case 0: switch (row) {
1524 [cell setTitle:[package_ name]];
1525 [cell setValue:[package_ latest]];
1529 [cell addSubview:description_];
1533 [cell setTitle:@"More Information"];
1534 [cell setShowDisclosure:YES];
1535 [cell setShowSelection:YES];
1538 default: _assert(false);
1541 case 1: switch (row) {
1543 [cell setTitle:@"Identifier"];
1544 [cell setValue:[package_ id]];
1548 [cell setTitle:@"Installed Version"];
1549 NSString *installed([package_ installed]);
1550 [cell setValue:(installed == nil ? @"n/a" : installed)];
1554 [cell setTitle:@"Section"];
1555 NSString *section([package_ section]);
1556 [cell setValue:(section == nil ? @"n/a" : section)];
1560 [cell setTitle:@"Expanded Size"];
1561 [cell setValue:SizeString([package_ size])];
1565 [cell setTitle:@"Maintainer"];
1566 [cell setValue:[[package_ maintainer] name]];
1567 [cell setShowDisclosure:YES];
1568 [cell setShowSelection:YES];
1571 default: _assert(false);
1574 case 2: switch (row) {
1576 [cell setTitle:[[package_ source] label]];
1577 [cell setValue:[[package_ source] version]];
1581 [cell setValue:[[package_ source] description]];
1585 [cell setTitle:@"Origin"];
1586 [cell setValue:[[package_ source] origin]];
1589 default: _assert(false);
1592 default: _assert(false);
1598 - (BOOL) canSelectRow:(int)row {
1602 - (void) tableRowSelected:(NSNotification *)notification {
1603 int row = [table_ selectedRow];
1604 NSString *website = [package_ website];
1606 if (row == (website == nil ? 8 : 9))
1607 [delegate_ openURL:[NSURL URLWithString:[NSString stringWithFormat:@"mailto:%@?subject=%@",
1608 [[package_ maintainer] email],
1609 [[NSString stringWithFormat:@"regarding apt package \"%@\"", [package_ name]] stringByAddingPercentEscapes]
1611 else if (website != nil && row == 3)
1612 [delegate_ openURL:[NSURL URLWithString:website]];
1615 - (Package *) package {
1619 - (id) initWithFrame:(struct CGRect)frame {
1620 if ((self = [super initWithFrame:frame]) != nil) {
1621 table_ = [[UIPreferencesTable alloc] initWithFrame:[self bounds]];
1622 [self addSubview:table_];
1624 [table_ setDataSource:self];
1625 [table_ setDelegate:self];
1629 - (void) setPackage:(Package *)package {
1630 if (package_ != nil) {
1631 [package_ autorelease];
1635 if (description_ != nil) {
1636 [description_ release];
1640 if (package != nil) {
1641 package_ = [package retain];
1643 NSString *description([package description]);
1644 if (description == nil)
1645 description = [package tagline];
1646 description_ = [GetTextView(description, 12, true) retain];
1648 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1649 CGColor black(space, 0, 0, 0, 1);
1650 [description_ setTextColor:black];
1651 CGColorSpaceRelease(space);
1653 [table_ reloadData];
1657 - (void) setDelegate:(id)delegate {
1658 delegate_ = delegate;
1663 /* Package Cell {{{ */
1664 @interface PackageCell : UITableCell {
1667 UITextLabel *description_;
1668 UITextLabel *source_;
1669 UITextLabel *version_;
1670 UIImageView *trusted_;
1676 - (PackageCell *) initWithVersioner:(SEL)versioner;
1677 - (void) setPackage:(Package *)package;
1679 - (void) _setSelected:(float)fraction;
1680 - (void) setSelected:(BOOL)selected;
1681 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
1682 - (void) _setSelectionFadeFraction:(float)fraction;
1686 @implementation PackageCell
1691 [description_ release];
1698 - (PackageCell *) initWithVersioner:(SEL)versioner {
1699 if ((self = [super init]) != nil) {
1700 versioner_ = versioner;
1702 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22);
1703 GSFontRef large = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
1704 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 14);
1706 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1708 CGColor clear(space, 0, 0, 0, 0);
1710 icon_ = [[UIImageView alloc] initWithFrame:CGRectMake(10, 10, 30, 30)];
1712 name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 12, 240, 25)];
1713 [name_ setBackgroundColor:clear];
1714 [name_ setFont:bold];
1716 description_ = [[UITextLabel alloc] initWithFrame:CGRectMake(12, 46, 280, 20)];
1717 [description_ setBackgroundColor:clear];
1718 [description_ setFont:small];
1720 source_ = [[UITextLabel alloc] initWithFrame:CGRectMake(12, 72, 225, 20)];
1721 [source_ setBackgroundColor:clear];
1722 [source_ setFont:large];
1724 version_ = [[UIRightTextLabel alloc] initWithFrame:CGRectMake(286, 69, 70, 25)];
1725 [version_ setBackgroundColor:clear];
1726 [version_ setFont:large];
1728 //trusted_ = [[UIImageView alloc] initWithFrame:CGRectMake(278, 7, 16, 16)];
1729 trusted_ = [[UIImageView alloc] initWithFrame:CGRectMake(30, 30, 16, 16)];
1730 [trusted_ setImage:[UIImage applicationImageNamed:@"trusted.png"]];
1732 [self addSubview:icon_];
1733 [self addSubview:name_];
1734 [self addSubview:description_];
1735 [self addSubview:source_];
1736 [self addSubview:version_];
1738 CGColorSpaceRelease(space);
1746 - (void) setPackage:(Package *)package {
1747 Source *source = [package source];
1749 UIImage *image = nil;
1750 if (NSString *icon = [package icon])
1751 image = [UIImage imageAtPath:[icon substringFromIndex:6]];
1752 if (image == nil) if (NSString *icon = [source defaultIcon])
1753 image = [UIImage imageAtPath:[icon substringFromIndex:6]];
1755 image = [UIImage applicationImageNamed:@"unknown.png"];
1757 [icon_ setImage:image];
1758 [icon_ zoomToScale:0.5f];
1759 [icon_ setFrame:CGRectMake(10, 10, 30, 30)];
1761 [name_ setText:[package name]];
1762 [version_ setText:[package latest]];
1763 [description_ setText:[package tagline]];
1768 if (source != nil) {
1769 label = [source label];
1770 trusted = [source trusted];
1771 } else if ([[package id] isEqualToString:@"firmware"]) {
1775 label = @"Unknown/Local";
1779 [source_ setText:[NSString stringWithFormat:@"from %@", label]];
1781 [trusted_ removeFromSuperview];
1783 [self addSubview:trusted_];
1786 - (void) _setSelected:(float)fraction {
1787 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1789 CGColor black(space,
1790 interpolate(0.0, 1.0, fraction),
1791 interpolate(0.0, 1.0, fraction),
1792 interpolate(0.0, 1.0, fraction),
1796 interpolate(0.2, 1.0, fraction),
1797 interpolate(0.2, 1.0, fraction),
1798 interpolate(1.0, 1.0, fraction),
1802 interpolate(0.4, 1.0, fraction),
1803 interpolate(0.4, 1.0, fraction),
1804 interpolate(0.4, 1.0, fraction),
1807 [name_ setColor:black];
1808 [description_ setColor:gray];
1809 [source_ setColor:black];
1810 [version_ setColor:blue];
1812 CGColorSpaceRelease(space);
1815 - (void) setSelected:(BOOL)selected {
1816 [self _setSelected:(selected ? 1.0 : 0.0)];
1817 [super setSelected:selected];
1820 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
1822 [self _setSelected:(selected ? 1.0 : 0.0)];
1823 [super setSelected:selected withFade:fade];
1826 - (void) _setSelectionFadeFraction:(float)fraction {
1827 [self _setSelected:fraction];
1828 [super _setSelectionFadeFraction:fraction];
1834 /* Database Implementation {{{ */
1835 @implementation Database
1842 - (void) _readStatus:(NSNumber *)fd {
1843 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1845 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1846 std::istream is(&ib);
1851 pcre *code = pcre_compile("^([^:]*):([^:]*):([^:]*):(.*)$", 0, &error, &offset, NULL);
1853 pcre_extra *study = NULL;
1855 pcre_fullinfo(code, study, PCRE_INFO_CAPTURECOUNT, &capture);
1856 int matches[(capture + 1) * 3];
1858 while (std::getline(is, line)) {
1859 const char *data(line.c_str());
1861 _assert(pcre_exec(code, study, data, line.size(), 0, 0, matches, sizeof(matches) / sizeof(matches[0])) >= 0);
1863 std::istringstream buffer(line.substr(matches[6], matches[7] - matches[6]));
1866 [delegate_ setPercent:(percent / 100)];
1868 NSString *string = [NSString stringWithCString:(data + matches[8]) length:(matches[9] - matches[8])];
1869 std::string type(line.substr(matches[2], matches[3] - matches[2]));
1871 if (type == "pmerror")
1872 [delegate_ setError:string];
1873 else if (type == "pmstatus")
1874 [delegate_ setTitle:string];
1875 else if (type == "pmconffile")
1877 else _assert(false);
1884 - (void) _readOutput:(NSNumber *)fd {
1885 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1887 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1888 std::istream is(&ib);
1891 while (std::getline(is, line))
1892 [delegate_ addOutput:[NSString stringWithCString:line.c_str()]];
1898 - (Package *) packageWithName:(NSString *)name {
1899 pkgCache::PkgIterator iterator(cache_->FindPkg([name cString]));
1900 return iterator.end() ? nil : [Package packageWithIterator:iterator database:self];
1903 - (Database *) init {
1904 if ((self = [super init]) != nil) {
1910 sources_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1914 _assert(pipe(fds) != -1);
1918 detachNewThreadSelector:@selector(_readStatus:)
1920 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1923 _assert(pipe(fds) != -1);
1924 _assert(dup2(fds[1], 1) != -1);
1925 _assert(close(fds[1]) != -1);
1928 detachNewThreadSelector:@selector(_readOutput:)
1930 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1935 - (pkgCacheFile &) cache {
1939 - (pkgRecords *) records {
1943 - (pkgProblemResolver *) resolver {
1947 - (pkgAcquire &) fetcher {
1951 - (void) reloadData {
1961 if (!cache_.Open(progress_, true)) {
1962 fprintf(stderr, "repairing corrupted database...\n");
1965 _assert(cache_.Open(progress_, true));
1968 records_ = new pkgRecords(cache_);
1969 resolver_ = new pkgProblemResolver(cache_);
1970 fetcher_ = new pkgAcquire(&status_);
1973 list_ = new pkgSourceList();
1974 _assert(list_->ReadMainList());
1976 [sources_ removeAllObjects];
1977 for (pkgSourceList::const_iterator source = list_->begin(); source != list_->end(); ++source) {
1978 std::vector<pkgIndexFile *> *indices = (*source)->GetIndexFiles();
1979 for (std::vector<pkgIndexFile *>::const_iterator index = indices->begin(); index != indices->end(); ++index)
1981 setObject:[[[Source alloc] initWithMetaIndex:*source] autorelease]
1982 forKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(*index)]
1988 pkgRecords records(cache_);
1990 lock_ = new FileFd();
1991 lock_->Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1992 _assert(!_error->PendingError());
1995 _assert(list.ReadMainList());
1997 manager_ = (_system->CreatePM(cache_));
1998 _assert(manager_->GetArchives(fetcher_, &list, &records));
1999 _assert(!_error->PendingError());
2003 if (fetcher_->Run(PulseInterval_) != pkgAcquire::Continue)
2007 pkgPackageManager::OrderResult result = manager_->DoInstall(statusfd_);
2009 if (result == pkgPackageManager::Failed)
2011 if (_error->PendingError())
2013 if (result != pkgPackageManager::Completed)
2019 _assert(list.ReadMainList());
2022 lock.Fd(GetLock(_config->FindDir("Dir::State::Lists") + "lock"));
2023 _assert(!_error->PendingError());
2025 pkgAcquire fetcher(&status_);
2026 _assert(list.GetIndexes(&fetcher));
2027 _assert(fetcher.Run(PulseInterval_) != pkgAcquire::Failed);
2029 bool failed = false;
2030 for (pkgAcquire::ItemIterator item = fetcher.ItemsBegin(); item != fetcher.ItemsEnd(); item++)
2031 if ((*item)->Status != pkgAcquire::Item::StatDone) {
2032 (*item)->Finished();
2036 if (!failed && _config->FindB("APT::Get::List-Cleanup", true) == true) {
2037 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists")));
2038 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/"));
2041 [Metadata_ setObject:[NSDate date] forKey:@"LastUpdate"];
2045 _assert(cache_->DelCount() == 0 && cache_->InstCount() == 0);
2046 _assert(pkgApplyStatus(cache_));
2048 if (cache_->BrokenCount() != 0) {
2049 _assert(pkgFixBroken(cache_));
2050 _assert(cache_->BrokenCount() == 0);
2051 _assert(pkgMinimizeUpgrade(cache_));
2054 _assert(pkgDistUpgrade(cache_));
2057 - (void) setDelegate:(id)delegate {
2058 delegate_ = delegate;
2059 status_.setDelegate(delegate);
2060 progress_.setDelegate(delegate);
2063 - (Source *) getSource:(const pkgCache::PkgFileIterator &)file {
2064 pkgIndexFile *index(NULL);
2065 list_->FindIndex(file, index);
2066 return [sources_ objectForKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(index)]];
2072 /* Progress Data {{{ */
2073 @interface ProgressData : NSObject {
2079 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object;
2086 @implementation ProgressData
2088 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object {
2089 if ((self = [super init]) != nil) {
2090 selector_ = selector;
2110 /* Progress View {{{ */
2111 @interface ProgressView : UIView <
2115 UIView *background_;
2116 UITransitionView *transition_;
2118 UINavigationBar *navbar_;
2119 UIProgressBar *progress_;
2120 UITextView *output_;
2121 UITextLabel *status_;
2127 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
2129 - (ProgressView *) initWithFrame:(struct CGRect)frame delegate:(id)delegate;
2130 - (void) setContentView:(UIView *)view;
2133 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
2135 - (void) _retachThread;
2136 - (void) _detachNewThreadData:(ProgressData *)data;
2137 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title;
2139 - (void) setError:(NSString *)error;
2140 - (void) _setError:(NSString *)error;
2142 - (void) setTitle:(NSString *)title;
2143 - (void) _setTitle:(NSString *)title;
2145 - (void) setPercent:(float)percent;
2146 - (void) _setPercent:(NSNumber *)percent;
2148 - (void) addOutput:(NSString *)output;
2149 - (void) _addOutput:(NSString *)output;
2152 @protocol ProgressViewDelegate
2153 - (void) progressViewIsComplete:(ProgressView *)sender;
2156 @implementation ProgressView
2160 if (background_ != nil)
2161 [background_ release];
2162 [transition_ release];
2165 [progress_ release];
2171 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
2172 if (bootstrap_ && from == overlay_ && to == view_)
2176 - (ProgressView *) initWithFrame:(struct CGRect)frame delegate:(id)delegate {
2177 if ((self = [super initWithFrame:frame]) != nil) {
2178 delegate_ = delegate;
2180 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
2182 CGColor black(space, 0.0, 0.0, 0.0, 1.0);
2183 CGColor white(space, 1.0, 1.0, 1.0, 1.0);
2184 CGColor clear(space, 0.0, 0.0, 0.0, 0.0);
2186 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
2187 [transition_ setDelegate:self];
2189 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
2192 [overlay_ setBackgroundColor:black];
2194 background_ = [[UIView alloc] initWithFrame:[self bounds]];
2195 [background_ setBackgroundColor:black];
2196 [self addSubview:background_];
2199 [self addSubview:transition_];
2201 CGSize navsize = [UINavigationBar defaultSize];
2202 CGRect navrect = {{0, 0}, navsize};
2204 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
2205 [overlay_ addSubview:navbar_];
2207 [navbar_ setBarStyle:1];
2208 [navbar_ setDelegate:self];
2210 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:nil] autorelease];
2211 [navbar_ pushNavigationItem:navitem];
2213 CGRect bounds = [overlay_ bounds];
2214 CGSize prgsize = [UIProgressBar defaultSize];
2217 (bounds.size.width - prgsize.width) / 2,
2218 bounds.size.height - prgsize.height - 20
2221 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
2222 [overlay_ addSubview:progress_];
2224 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(
2226 bounds.size.height - prgsize.height - 50,
2227 bounds.size.width - 20,
2231 [status_ setColor:white];
2232 [status_ setBackgroundColor:clear];
2234 [status_ setCentersHorizontally:YES];
2235 //[status_ setFont:font];
2237 output_ = [[UITextView alloc] initWithFrame:CGRectMake(
2239 navrect.size.height + 20,
2240 bounds.size.width - 20,
2241 bounds.size.height - navsize.height - 62 - navrect.size.height
2244 //[output_ setTextFont:@"Courier New"];
2245 [output_ setTextSize:12];
2247 [output_ setTextColor:white];
2248 [output_ setBackgroundColor:clear];
2250 [output_ setMarginTop:0];
2251 [output_ setAllowsRubberBanding:YES];
2253 [overlay_ addSubview:output_];
2254 [overlay_ addSubview:status_];
2256 [progress_ setStyle:0];
2258 CGColorSpaceRelease(space);
2262 - (void) setContentView:(UIView *)view {
2263 view_ = [view retain];
2266 - (void) resetView {
2267 [transition_ transition:6 toView:view_];
2270 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
2274 - (void) _retachThread {
2275 [delegate_ progressViewIsComplete:self];
2279 - (void) _detachNewThreadData:(ProgressData *)data {
2280 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
2282 [[data target] performSelector:[data selector] withObject:[data object]];
2285 [self performSelectorOnMainThread:@selector(_retachThread) withObject:nil waitUntilDone:YES];
2290 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title {
2291 [navbar_ popNavigationItem];
2292 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:title] autorelease];
2293 [navbar_ pushNavigationItem:navitem];
2295 [status_ setText:nil];
2296 [output_ setText:@""];
2297 [progress_ setProgress:0];
2299 [transition_ transition:6 toView:overlay_];
2302 detachNewThreadSelector:@selector(_detachNewThreadData:)
2304 withObject:[[ProgressData alloc]
2305 initWithSelector:selector
2312 - (void) setError:(NSString *)error {
2314 performSelectorOnMainThread:@selector(_setError:)
2320 - (void) _setError:(NSString *)error {
2321 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
2322 initWithTitle:@"Package Error"
2323 buttons:[NSArray arrayWithObjects:@"Okay", nil]
2324 defaultButtonIndex:0
2329 [sheet setBodyText:error];
2330 [sheet popupAlertAnimated:YES];
2333 - (void) setTitle:(NSString *)title {
2335 performSelectorOnMainThread:@selector(_setTitle:)
2341 - (void) _setTitle:(NSString *)title {
2342 [status_ setText:[title stringByAppendingString:@"..."]];
2345 - (void) setPercent:(float)percent {
2347 performSelectorOnMainThread:@selector(_setPercent:)
2348 withObject:[NSNumber numberWithFloat:percent]
2353 - (void) _setPercent:(NSNumber *)percent {
2354 [progress_ setProgress:[percent floatValue]];
2357 - (void) addOutput:(NSString *)output {
2359 performSelectorOnMainThread:@selector(_addOutput:)
2365 - (void) _addOutput:(NSString *)output {
2366 [output_ setText:[NSString stringWithFormat:@"%@\n%@", [output_ text], output]];
2367 CGSize size = [output_ contentSize];
2368 CGRect rect = {{0, size.height}, {size.width, 0}};
2369 [output_ scrollRectToVisible:rect animated:YES];
2375 /* Package Table {{{ */
2376 @protocol PackageTableDelegate
2377 - (void) packageTable:(id)table packageSelected:(Package *)package;
2380 @interface PackageTable : UIView {
2382 UISectionList *list_;
2386 NSMutableArray *sections_;
2391 - (int) numberOfSectionsInSectionList:(UISectionList *)list;
2392 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section;
2393 - (int) sectionList:(UISectionList *)list rowForSection:(int)section;
2395 - (int) numberOfRowsInTable:(UITable *)table;
2396 - (float) table:(UITable *)table heightForRow:(int)row;
2397 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing;
2398 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row;
2399 - (void) tableRowSelected:(NSNotification *)notification;
2401 - (id) initWithFrame:(CGRect)frame versioner:(SEL)versioner;
2403 - (void) setDelegate:(id)delegate;
2404 - (void) setPackages:(NSArray *)packages;
2406 - (void) resetViewAnimated:(BOOL)animated;
2407 - (UITable *) table;
2410 @implementation PackageTable
2414 [sections_ release];
2415 if (packages_ != nil)
2416 [packages_ release];
2420 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
2421 return [sections_ count];
2424 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
2425 return [[sections_ objectAtIndex:section] name];
2428 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
2429 return [[sections_ objectAtIndex:section] row];
2432 - (int) numberOfRowsInTable:(UITable *)table {
2433 return [packages_ count];
2436 - (float) table:(UITable *)table heightForRow:(int)row {
2440 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2442 reusing = [[[PackageCell alloc] initWithVersioner:versioner_] autorelease];
2443 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
2447 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
2451 - (void) tableRowSelected:(NSNotification *)notification {
2452 int row = [[notification object] selectedRow];
2453 [delegate_ packageTable:self packageSelected:(row == INT_MAX ? nil : [packages_ objectAtIndex:row])];
2456 - (id) initWithFrame:(CGRect)frame versioner:(SEL)versioner {
2457 if ((self = [super initWithFrame:frame]) != nil) {
2458 versioner_ = versioner;
2459 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
2461 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:YES];
2462 [list_ setDataSource:self];
2464 UITableColumn *column = [[[UITableColumn alloc]
2465 initWithTitle:@"Name"
2467 width:frame.size.width
2470 UITable *table = [list_ table];
2471 [table setSeparatorStyle:1];
2472 [table addTableColumn:column];
2473 [table setDelegate:self];
2474 [table setReusesTableCells:YES];
2476 [self addSubview:list_];
2480 - (void) setDelegate:(id)delegate {
2481 delegate_ = delegate;
2484 - (void) setPackages:(NSArray *)packages {
2485 if (packages_ != nil)
2486 [packages_ autorelease];
2487 _assert(packages != nil);
2488 packages_ = [packages retain];
2490 [sections_ removeAllObjects];
2492 Section *section = nil;
2494 for (size_t offset(0); offset != [packages_ count]; ++offset) {
2495 Package *package = [packages_ objectAtIndex:offset];
2496 NSString *name = [package index];
2498 if (section == nil || ![[section name] isEqual:name]) {
2499 section = [[[Section alloc] initWithName:name row:offset] autorelease];
2500 [sections_ addObject:section];
2503 [section addPackage:package];
2509 - (void) resetViewAnimated:(BOOL)animated {
2510 [[list_ table] selectRow:-1 byExtendingSelection:NO withFade:animated];
2513 - (UITable *) table {
2514 return [list_ table];
2520 /* Section Cell {{{ */
2521 @interface SectionCell : UITableCell {
2523 UITextLabel *count_;
2529 - (void) setSection:(Section *)section;
2531 - (void) _setSelected:(float)fraction;
2532 - (void) setSelected:(BOOL)selected;
2533 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
2534 - (void) _setSelectionFadeFraction:(float)fraction;
2538 @implementation SectionCell
2547 if ((self = [super init]) != nil) {
2548 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22);
2549 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 12);
2551 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
2552 CGColor clear(space, 0, 0, 0, 0);
2553 CGColor white(space, 1, 1, 1, 1);
2555 name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 9, 250, 25)];
2556 [name_ setBackgroundColor:clear];
2557 [name_ setFont:bold];
2559 count_ = [[UITextLabel alloc] initWithFrame:CGRectMake(11, 7, 29, 32)];
2560 [count_ setCentersHorizontally:YES];
2561 [count_ setBackgroundColor:clear];
2562 [count_ setFont:small];
2563 [count_ setColor:white];
2565 UIImageView *folder = [[[UIImageView alloc] initWithFrame:CGRectMake(8, 7, 32, 32)] autorelease];
2566 [folder setImage:[UIImage applicationImageNamed:@"folder.png"]];
2568 [self addSubview:folder];
2569 [self addSubview:name_];
2570 [self addSubview:count_];
2572 [self _setSelected:0];
2574 CGColorSpaceRelease(space);
2581 - (void) setSection:(Section *)section {
2582 if (section == nil) {
2583 [name_ setText:@"All Packages"];
2584 [count_ setText:nil];
2586 NSString *name = [section name];
2587 [name_ setText:(name == nil ? @"(No Section)" : name)];
2588 [count_ setText:[NSString stringWithFormat:@"%d", [section count]]];
2592 - (void) _setSelected:(float)fraction {
2593 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
2595 CGColor black(space,
2596 interpolate(0.0, 1.0, fraction),
2597 interpolate(0.0, 1.0, fraction),
2598 interpolate(0.0, 1.0, fraction),
2601 [name_ setColor:black];
2603 CGColorSpaceRelease(space);
2606 - (void) setSelected:(BOOL)selected {
2607 [self _setSelected:(selected ? 1.0 : 0.0)];
2608 [super setSelected:selected];
2611 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
2613 [self _setSelected:(selected ? 1.0 : 0.0)];
2614 [super setSelected:selected withFade:fade];
2617 - (void) _setSelectionFadeFraction:(float)fraction {
2618 [self _setSelected:fraction];
2619 [super _setSelectionFadeFraction:fraction];
2624 /* Install View {{{ */
2625 @interface InstallView : ResetView <
2626 PackageTableDelegate
2630 PackageTable *table_;
2634 NSMutableArray *packages_;
2639 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
2641 - (int) numberOfRowsInTable:(UITable *)table;
2642 - (float) table:(UITable *)table heightForRow:(int)row;
2643 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing;
2644 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row;
2645 - (void) tableRowSelected:(NSNotification *)notification;
2647 - (void) packageTable:(id)table packageSelected:(Package *)package;
2649 - (id) initWithFrame:(CGRect)frame;
2650 - (void) setPackages:(NSArray *)packages;
2651 - (void) setDelegate:(id)delegate;
2654 @implementation InstallView
2657 [packages_ release];
2658 if (sections_ != nil)
2659 [sections_ release];
2666 if (section_ != nil)
2668 if (package_ != nil)
2673 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2675 [[view_ package] install];
2676 [delegate_ resolve];
2677 [delegate_ perform];
2681 - (int) numberOfRowsInTable:(UITable *)table {
2682 return [sections_ count] + 1;
2685 - (float) table:(UITable *)table heightForRow:(int)row {
2689 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2691 reusing = [[[SectionCell alloc] init] autorelease];
2693 [(SectionCell *)reusing setSection:nil];
2695 [(SectionCell *)reusing setSection:[sections_ objectAtIndex:(row - 1)]];
2699 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
2703 - (void) tableRowSelected:(NSNotification *)notification {
2704 int row = [[notification object] selectedRow];
2706 if (row == INT_MAX) {
2713 _assert(section_ == nil);
2714 _assert(table_ == nil);
2722 name = @"All Packages";
2724 section = [sections_ objectAtIndex:(row - 1)];
2725 name = [section name];
2726 section_ = [name retain];
2729 table_ = [[PackageTable alloc] initWithFrame:[transition_ bounds] versioner:@selector(latest)];
2730 [table_ setDelegate:self];
2731 [table_ setPackages:(section == nil ? packages_ : [section packages])];
2733 [self pushView:table_ withTitle:name backButtonTitle:@"Packages" rightButton:nil];
2737 - (void) packageTable:(id)table packageSelected:(Package *)package {
2738 if (package == nil) {
2745 _assert(package_ == nil);
2746 _assert(view_ == nil);
2748 package_ = [[package name] retain];
2750 view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]];
2751 [view_ setDelegate:delegate_];
2753 [view_ setPackage:package];
2755 [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:@"Install"];
2759 - (id) initWithFrame:(CGRect)frame {
2760 if ((self = [super initWithFrame:frame]) != nil) {
2761 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
2763 list_ = [[UITable alloc] initWithFrame:[transition_ bounds]];
2764 [self pushView:list_ withTitle:@"Install" backButtonTitle:@"Sections" rightButton:nil];
2766 UITableColumn *column = [[[UITableColumn alloc]
2767 initWithTitle:@"Name"
2769 width:frame.size.width
2772 [list_ setDataSource:self];
2773 [list_ setSeparatorStyle:1];
2774 [list_ addTableColumn:column];
2775 [list_ setDelegate:self];
2776 [list_ setReusesTableCells:YES];
2778 [transition_ transition:0 toView:list_];
2782 - (void) setPackages:(NSArray *)packages {
2783 [packages_ removeAllObjects];
2785 for (size_t i(0); i != [packages count]; ++i) {
2786 Package *package([packages objectAtIndex:i]);
2787 if ([package installed] == nil)
2788 [packages_ addObject:package];
2791 [packages_ sortUsingSelector:@selector(compareBySectionAndName:)];
2792 NSMutableArray *sections = [NSMutableArray arrayWithCapacity:16];
2794 Section *nsection = nil;
2795 Package *npackage = nil;
2797 Section *section = nil;
2798 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
2799 Package *package = [packages_ objectAtIndex:offset];
2800 NSString *name = [package section];
2802 if (section == nil || name != nil && ![[section name] isEqual:name]) {
2803 section = [[[Section alloc] initWithName:name row:offset] autorelease];
2805 if (name == nil || [name isEqualToString:section_])
2807 [sections addObject:section];
2810 if ([[package name] isEqualToString:package_])
2812 [section addPackage:package];
2815 if (sections_ != nil)
2816 [sections_ release];
2817 sections_ = [sections retain];
2819 [packages_ sortUsingSelector:@selector(compareByName:)];
2825 if (npackage != nil)
2826 [view_ setPackage:npackage];
2827 else if (package_ != nil)
2830 if (table_ != nil && section_ == nil)
2831 [table_ setPackages:packages_];
2832 else if (nsection != nil)
2833 [table_ setPackages:[nsection packages]];
2834 else if (section_ != nil)
2838 [self popViews:views];
2842 - (void) setDelegate:(id)delegate {
2844 [view_ setDelegate:delegate];
2845 [super setDelegate:delegate];
2850 /* Changes View {{{ */
2851 @interface ChangesView : ResetView <
2852 PackageTableDelegate
2854 UISectionList *list_;
2855 NSMutableArray *packages_;
2856 NSMutableArray *sections_;
2864 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
2866 - (int) numberOfSectionsInSectionList:(UISectionList *)list;
2867 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section;
2868 - (int) sectionList:(UISectionList *)list rowForSection:(int)section;
2870 - (int) numberOfRowsInTable:(UITable *)table;
2871 - (float) table:(UITable *)table heightForRow:(int)row;
2872 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing;
2873 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row;
2874 - (void) tableRowSelected:(NSNotification *)notification;
2876 - (id) initWithFrame:(CGRect)frame;
2877 - (void) setPackages:(NSArray *)packages;
2878 - (void) _resetView;
2881 - (void) setDelegate:(id)delegate;
2884 @implementation ChangesView
2888 [packages_ release];
2889 [sections_ release];
2892 if (package_ != nil)
2897 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
2898 return [sections_ count];
2901 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
2902 return [[sections_ objectAtIndex:section] name];
2905 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
2906 return [[sections_ objectAtIndex:section] row];
2909 - (int) numberOfRowsInTable:(UITable *)table {
2910 return [packages_ count];
2913 - (float) table:(UITable *)table heightForRow:(int)row {
2917 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2919 reusing = [[[PackageCell alloc] initWithVersioner:NULL] autorelease];
2920 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
2924 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
2928 - (void) tableRowSelected:(NSNotification *)notification {
2929 int row = [[notification object] selectedRow];
2930 [self packageTable:self packageSelected:(row == INT_MAX ? nil : [packages_ objectAtIndex:row])];
2933 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2936 [[view_ package] install];
2937 [delegate_ resolve];
2938 [delegate_ perform];
2942 [delegate_ upgrade];
2947 - (void) packageTable:(id)table packageSelected:(Package *)package {
2948 if (package == nil) {
2955 _assert(package_ == nil);
2956 _assert(view_ == nil);
2958 package_ = [[package name] retain];
2960 view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]];
2961 [view_ setDelegate:delegate_];
2963 [view_ setPackage:package];
2965 [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:(
2966 [package upgradable] ? @"Upgrade" : @"Install"
2971 - (id) initWithFrame:(CGRect)frame {
2972 if ((self = [super initWithFrame:frame]) != nil) {
2973 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
2974 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
2976 list_ = [[UISectionList alloc] initWithFrame:[transition_ bounds] showSectionIndex:NO];
2977 [list_ setShouldHideHeaderInShortLists:NO];
2978 [list_ setDataSource:self];
2979 //[list_ setSectionListStyle:1];
2981 UITableColumn *column = [[[UITableColumn alloc]
2982 initWithTitle:@"Name"
2984 width:frame.size.width
2987 UITable *table = [list_ table];
2988 [table setSeparatorStyle:1];
2989 [table addTableColumn:column];
2990 [table setDelegate:self];
2991 [table setReusesTableCells:YES];
2993 [self pushView:list_ withTitle:@"Changes" backButtonTitle:nil rightButton:nil];
2997 - (void) setPackages:(NSArray *)packages {
2998 [packages_ removeAllObjects];
2999 for (size_t i(0); i != [packages count]; ++i) {
3000 Package *package([packages objectAtIndex:i]);
3001 if ([package installed] == nil || [package upgradable])
3002 [packages_ addObject:package];
3005 [packages_ sortUsingSelector:@selector(compareForChanges:)];
3007 [sections_ removeAllObjects];
3009 Section *upgradable = [[[Section alloc] initWithName:@"Available Upgrades" row:0] autorelease];
3010 Section *section = nil;
3013 Package *npackage = nil;
3014 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
3015 Package *package = [packages_ objectAtIndex:offset];
3016 if ([[package name] isEqualToString:package_])
3019 if ([package upgradable])
3020 [upgradable addPackage:package];
3022 NSDate *seen = [package seen];
3024 CFLocaleRef locale = CFLocaleCopyCurrent();
3025 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
3026 CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen);
3028 NSString *name = (NSString *) formatted;
3030 if (section == nil || ![[section name] isEqual:name]) {
3031 section = [[[Section alloc] initWithName:name row:offset] autorelease];
3032 [sections_ addObject:section];
3035 [section addPackage:package];
3037 CFRelease(formatter);
3038 CFRelease(formatted);
3043 count_ = [[upgradable packages] count];
3045 [sections_ insertObject:upgradable atIndex:0];
3049 if (npackage != nil)
3050 [view_ setPackage:npackage];
3051 else if (package_ != nil)
3058 - (void) _resetView {
3059 if ([views_ count] == 1)
3060 [navbar_ showButtonsWithLeftTitle:(count_ == 0 ? nil : @"Upgrade All") rightTitle:nil];
3067 - (void) setDelegate:(id)delegate {
3069 [view_ setDelegate:delegate];
3070 [super setDelegate:delegate];
3075 /* Manage View {{{ */
3076 @interface ManageView : ResetView <
3077 PackageTableDelegate
3079 PackageTable *table_;
3086 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
3088 - (void) packageTable:(id)table packageSelected:(Package *)package;
3090 - (id) initWithFrame:(CGRect)frame;
3091 - (void) setPackages:(NSArray *)packages;
3093 - (void) setDelegate:(id)delegate;
3096 @implementation ManageView
3102 if (package_ != nil)
3107 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
3109 [[view_ package] remove];
3110 [delegate_ resolve];
3111 [delegate_ perform];
3115 - (void) packageTable:(id)table packageSelected:(Package *)package {
3116 if (package == nil) {
3123 _assert(package_ == nil);
3124 _assert(view_ == nil);
3126 package_ = [[package name] retain];
3128 view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]];
3129 [view_ setDelegate:delegate_];
3131 [view_ setPackage:package];
3133 [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:@"Uninstall"];
3137 - (id) initWithFrame:(CGRect)frame {
3138 if ((self = [super initWithFrame:frame]) != nil) {
3139 table_ = [[PackageTable alloc] initWithFrame:[transition_ bounds] versioner:@selector(latest)];
3140 [table_ setDelegate:self];
3142 [self pushView:table_ withTitle:@"Uninstall" backButtonTitle:@"Packages" rightButton:nil];
3146 - (void) setPackages:(NSArray *)packages {
3147 NSMutableArray *local = [NSMutableArray arrayWithCapacity:16];
3148 for (size_t i(0); i != [packages count]; ++i) {
3149 Package *package([packages objectAtIndex:i]);
3150 if ([package installed] != nil)
3151 [local addObject:package];
3154 [local sortUsingSelector:@selector(compareByName:)];
3156 Package *npackage = nil;
3157 for (size_t offset = 0, count = [local count]; offset != count; ++offset) {
3158 Package *package = [local objectAtIndex:offset];
3159 if ([[package name] isEqualToString:package_])
3163 [table_ setPackages:local];
3165 if (npackage != nil)
3166 [view_ setPackage:npackage];
3167 else if (package_ != nil)
3173 - (void) setDelegate:(id)delegate {
3175 [view_ setDelegate:delegate];
3176 [super setDelegate:delegate];
3181 /* Search View {{{ */
3182 @protocol SearchViewDelegate
3183 - (void) showKeyboard:(BOOL)show;
3186 @interface SearchView : ResetView <
3187 PackageTableDelegate
3189 NSMutableArray *packages_;
3191 UISearchField *field_;
3192 PackageTable *table_;
3199 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
3200 - (void) packageTable:(id)table packageSelected:(Package *)package;
3202 - (void) textFieldDidBecomeFirstResponder:(UITextField *)field;
3203 - (void) textFieldDidResignFirstResponder:(UITextField *)field;
3205 - (void) keyboardInputChanged:(UIFieldEditor *)editor;
3206 - (BOOL) keyboardInput:(id)input shouldInsertText:(NSString *)text isMarkedText:(int)marked;
3208 - (id) initWithFrame:(CGRect)frame;
3209 - (void) setPackages:(NSArray *)packages;
3211 - (void) setDelegate:(id)delegate;
3212 - (void) resetPackage:(Package *)package;
3213 - (void) searchPackages;
3217 @implementation SearchView
3220 [packages_ release];
3221 [accessory_ release];
3226 if (package_ != nil)
3231 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
3233 Package *package = [view_ package];
3234 if ([package installed] == nil)
3238 [delegate_ resolve];
3239 [delegate_ perform];
3243 - (void) packageTable:(id)table packageSelected:(Package *)package {
3244 if (package == nil) {
3245 [navbar_ setAccessoryView:accessory_ animate:(resetting_ ? NO : YES) goingBack:YES];
3253 [navbar_ setAccessoryView:nil animate:YES goingBack:NO];
3255 _assert(package_ == nil);
3256 _assert(view_ == nil);
3258 package_ = [[package name] retain];
3260 view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]];
3261 [view_ setDelegate:delegate_];
3263 [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:nil];
3264 [self resetPackage:package];
3268 - (void) textFieldDidBecomeFirstResponder:(UITextField *)field {
3269 [delegate_ showKeyboard:YES];
3270 [table_ setEnabled:NO];
3272 /*CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
3273 CGColor dimmed(alpha, 0, 0, 0, 0.5);
3274 [editor_ setBackgroundColor:dimmed];
3275 CGColorSpaceRelease(space);*/
3278 - (void) textFieldDidResignFirstResponder:(UITextField *)field {
3279 [table_ setEnabled:YES];
3280 [delegate_ showKeyboard:NO];
3283 - (void) keyboardInputChanged:(UIFieldEditor *)editor {
3284 NSString *text([field_ text]);
3285 [field_ setClearButtonStyle:(text == nil || [text length] == 0 ? 0 : 2)];
3288 - (BOOL) keyboardInput:(id)input shouldInsertText:(NSString *)text isMarkedText:(int)marked {
3289 if ([text length] != 1 || [text characterAtIndex:0] != '\n')
3292 [self searchPackages];
3293 [field_ resignFirstResponder];
3297 - (id) initWithFrame:(CGRect)frame {
3298 if ((self = [super initWithFrame:frame]) != nil) {
3299 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
3301 table_ = [[PackageTable alloc] initWithFrame:[transition_ bounds] versioner:@selector(latest)];
3302 [table_ setDelegate:self];
3304 CGRect area = [self bounds];
3307 area.size.width -= 12;
3308 area.size.height = [UISearchField defaultHeight];
3310 field_ = [[UISearchField alloc] initWithFrame:area];
3312 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
3313 [field_ setFont:font];
3316 [field_ setPlaceholder:@"Package Names & Descriptions"];
3317 [field_ setPaddingTop:5];
3318 [field_ setDelegate:self];
3320 UITextTraits *traits = [field_ textTraits];
3321 [traits setEditingDelegate:self];
3322 [traits setReturnKeyType:6];
3324 accessory_ = [[UIView alloc] initWithFrame:CGRectMake(6, 6, area.size.width, area.size.height + 30)];
3325 [accessory_ addSubview:field_];
3327 [navbar_ setAccessoryView:accessory_];
3328 [self pushView:table_ withTitle:nil backButtonTitle:@"Search" rightButton:nil];
3330 /* XXX: for the love of god just fix this */
3331 [navbar_ removeFromSuperview];
3332 [reload_ removeFromSuperview];
3333 [configure_ removeFromSuperview];
3334 [self addSubview:navbar_];
3335 [self addSubview:reload_];
3336 [self addSubview:configure_];
3340 - (void) setPackages:(NSArray *)packages {
3341 [packages_ removeAllObjects];
3342 [packages_ addObjectsFromArray:packages];
3343 [packages_ sortUsingSelector:@selector(compareByName:)];
3345 Package *npackage = nil;
3346 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
3347 Package *package = [packages_ objectAtIndex:offset];
3348 if ([[package name] isEqualToString:package_])
3352 [self searchPackages];
3354 if (npackage != nil)
3355 [self resetPackage:npackage];
3356 else if (package_ != nil)
3362 - (void) setDelegate:(id)delegate {
3364 [view_ setDelegate:delegate];
3365 [super setDelegate:delegate];
3368 - (void) resetPackage:(Package *)package {
3369 [view_ setPackage:package];
3370 NSString *right = [package installed] == nil ? @"Install" : @"Uninstall";
3371 [navbar_ showButtonsWithLeftTitle:nil rightTitle:right];
3374 - (void) searchPackages {
3375 NSString *text([field_ text]);
3377 NSMutableArray *packages([NSMutableArray arrayWithCapacity:16]);
3379 for (size_t offset(0), count([packages_ count]); offset != count; ++offset) {
3380 Package *package = [packages_ objectAtIndex:offset];
3381 if ([package matches:text])
3382 [packages addObject:package];
3385 [table_ setPackages:packages];
3386 [[table_ table] scrollPointVisibleAtTopLeft:CGPointMake(0, 0) animated:NO];
3392 @interface Cydia : UIApplication <
3393 ConfirmationViewDelegate,
3394 ProgressViewDelegate,
3400 UITransitionView *transition_;
3401 UIButtonBar *buttonbar_;
3403 ConfirmationView *confirm_;
3405 Database *database_;
3406 ProgressView *progress_;
3409 UINavigationBar *navbar_;
3410 UIScroller *scroller_;
3411 UIWebView *webview_;
3413 UIProgressIndicator *indicator_;
3415 InstallView *install_;
3416 ChangesView *changes_;
3417 ManageView *manage_;
3418 SearchView *search_;
3423 UIKeyboard *keyboard_;
3427 - (void) reloadData:(BOOL)reset;
3438 - (void) progressViewIsComplete:(ProgressView *)progress;
3440 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
3441 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
3442 - (void) buttonBarItemTapped:(id)sender;
3444 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old;
3446 - (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame;
3448 - (void) applicationWillSuspend;
3449 - (void) applicationDidFinishLaunching:(id)unused;
3452 @implementation Cydia
3455 NSMutableURLRequest *request = [NSMutableURLRequest
3457 cachePolicy:NSURLRequestReloadIgnoringCacheData
3458 timeoutInterval:30.0
3461 [request addValue:[NSString stringWithCString:Firmware_] forHTTPHeaderField:@"X-Firmware"];
3462 [request addValue:[NSString stringWithCString:Machine_] forHTTPHeaderField:@"X-Machine"];
3463 [request addValue:[NSString stringWithCString:SerialNumber_] forHTTPHeaderField:@"X-Serial-Number"];
3465 [webview_ loadRequest:request];
3468 - (void) reloadData:(BOOL)reset {
3469 [database_ reloadData];
3473 if (Packages_ == nil) {
3474 Packages_ = [[NSMutableDictionary alloc] initWithCapacity:count];
3475 [Metadata_ setObject:Packages_ forKey:@"Packages"];
3478 now_ = [NSDate date];
3480 NSMutableArray *packages = [NSMutableArray arrayWithCapacity:count];
3481 for (pkgCache::PkgIterator iterator = [database_ cache]->PkgBegin(); !iterator.end(); ++iterator)
3482 if (Package *package = [Package packageWithIterator:iterator database:database_])
3483 [packages addObject:package];
3485 [install_ setPackages:packages];
3486 [changes_ setPackages:packages];
3487 [manage_ setPackages:packages];
3488 [search_ setPackages:packages];
3490 if (size_t count = [changes_ count]) {
3491 NSString *badge([[NSNumber numberWithInt:count] stringValue]);
3492 [buttonbar_ setBadgeValue:badge forButton:3];
3493 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
3494 [buttonbar_ setBadgeAnimated:YES forButton:3];
3495 [self setApplicationBadge:badge];
3497 [buttonbar_ setBadgeValue:nil forButton:3];
3498 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
3499 [buttonbar_ setBadgeAnimated:NO forButton:3];
3500 [self removeApplicationBadge];
3503 _assert([Metadata_ writeToFile:@"/var/lib/cydia/metadata.plist" atomically:YES] == YES);
3506 - (void) setPrompt {
3507 [navbar_ setPrompt:[NSString stringWithFormat:@"Last Updated: %@", GetLastUpdate()]];
3511 pkgProblemResolver *resolver = [database_ resolver];
3513 resolver->InstallProtect();
3514 if (!resolver->Resolve(true))
3519 [database_ prepare];
3520 confirm_ = [[ConfirmationView alloc] initWithView:underlay_ database:database_ delegate:self];
3524 [database_ upgrade];
3529 [self reloadData:NO];
3535 [overlay_ removeFromSuperview];
3539 detachNewThreadSelector:@selector(perform)
3546 - (void) bootstrap_ {
3548 [database_ upgrade];
3549 [database_ prepare];
3550 [database_ perform];
3553 - (void) bootstrap {
3555 detachNewThreadSelector:@selector(bootstrap_)
3558 title:@"Bootstrap Install..."
3564 detachNewThreadSelector:@selector(update)
3567 title:@"Refreshing Sources..."
3571 - (void) progressViewIsComplete:(ProgressView *)progress {
3572 [self reloadData:YES];
3574 if (confirm_ != nil) {
3575 [underlay_ addSubview:overlay_];
3576 [confirm_ removeFromSuperview];
3582 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
3589 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
3590 initWithTitle:@"About Cydia Packager"
3591 buttons:[NSArray arrayWithObjects:@"Close", nil]
3592 defaultButtonIndex:0
3598 @"Copyright (C) 2008\n"
3599 "Jay Freeman (saurik)\n"
3600 "saurik@saurik.com\n"
3601 "http://www.saurik.com/\n"
3604 "http://www.theokorigroup.com/\n"
3606 "College of Creative Studies,\n"
3607 "University of California,\n"
3609 "http://www.ccs.ucsb.edu/\n"
3612 "bad_, BHSPitMonkey, cash, Cobra,\n"
3613 "core, Corona, crashx, cromas,\n"
3614 "Darken, dtzWill, Erica, francis,\n"
3615 "Godores, jerry, Kingstone, lounger,\n"
3616 "mbranes, rockabilly, tman, Wbiggs"
3619 [sheet presentSheetFromButtonBar:buttonbar_];
3624 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
3628 - (void) buttonBarItemTapped:(id)sender {
3630 unsigned tag = [sender tag];
3633 case 1: view = featured_; break;
3634 case 2: view = install_; break;
3635 case 3: view = changes_; break;
3636 case 4: view = manage_; break;
3637 case 5: view = search_; break;
3643 if ([view respondsToSelector:@selector(resetView:)])
3644 [(id) view resetView:(tag == tag_ ? NO : YES)];
3646 [transition_ transition:0 toView:view];
3649 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old {
3650 [scroller_ setContentSize:frame.size];
3651 [indicator_ stopAnimation];
3654 - (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame {
3655 [navbar_ setPrompt:title];
3658 - (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame {
3659 [navbar_ setPrompt:@"Loading..."];
3660 [indicator_ startAnimation];
3663 - (void) applicationWillSuspend {
3665 if (FW_LEAST(1,1,3))
3666 notify_post("com.apple.language.changed");
3668 system("launchctl stop com.apple.SpringBoard");
3670 [super applicationWillSuspend];
3673 - (void) applicationDidFinishLaunching:(id)unused {
3674 _assert(pkgInitConfig(*_config));
3675 _assert(pkgInitSystem(*_config, _system));
3681 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
3682 window_ = [[UIWindow alloc] initWithContentRect:screenrect];
3684 [window_ orderFront: self];
3685 [window_ makeKey: self];
3686 [window_ _setHidden: NO];
3688 progress_ = [[ProgressView alloc] initWithFrame:[window_ bounds] delegate:self];
3689 [window_ setContentView:progress_];
3691 underlay_ = [[UIView alloc] initWithFrame:[progress_ bounds]];
3692 [progress_ setContentView:underlay_];
3694 overlay_ = [[UIView alloc] initWithFrame:[underlay_ bounds]];
3697 [underlay_ addSubview:overlay_];
3699 transition_ = [[UITransitionView alloc] initWithFrame:CGRectMake(
3700 0, 0, screenrect.size.width, screenrect.size.height - 48
3703 [overlay_ addSubview:transition_];
3705 featured_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
3707 CGSize navsize = [UINavigationBar defaultSizeWithPrompt];
3708 CGRect navrect = {{0, 0}, navsize};
3710 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
3711 [featured_ addSubview:navbar_];
3713 [navbar_ setBarStyle:1];
3714 [navbar_ setDelegate:self];
3716 [navbar_ showButtonsWithLeftTitle:@"About" rightTitle:@"Reload"];
3718 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Featured"] autorelease];
3719 [navbar_ pushNavigationItem:navitem];
3721 struct CGRect subbounds = [featured_ bounds];
3722 subbounds.origin.y += navsize.height;
3723 subbounds.size.height -= navsize.height;
3725 UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:subbounds] autorelease];
3726 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
3727 [featured_ addSubview:pinstripe];
3729 scroller_ = [[UIScroller alloc] initWithFrame:subbounds];
3730 [featured_ addSubview:scroller_];
3732 [scroller_ setScrollingEnabled:YES];
3733 [scroller_ setAdjustForContentSizeChange:YES];
3734 [scroller_ setClipsSubviews:YES];
3735 [scroller_ setAllowsRubberBanding:YES];
3736 [scroller_ setScrollDecelerationFactor:0.99];
3737 [scroller_ setDelegate:self];
3739 CGRect webrect = [scroller_ bounds];
3740 webrect.size.height = 0;
3742 webview_ = [[UIWebView alloc] initWithFrame:webrect];
3743 [scroller_ addSubview:webview_];
3745 [webview_ setTilingEnabled:YES];
3746 [webview_ setTileSize:CGSizeMake(screenrect.size.width, 500)];
3747 [webview_ setAutoresizes:YES];
3748 [webview_ setDelegate:self];
3750 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:2];
3751 indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(87, 45, indsize.width, indsize.height)];
3752 [indicator_ setStyle:2];
3753 [featured_ addSubview:indicator_];
3755 NSArray *buttonitems = [NSArray arrayWithObjects:
3756 [NSDictionary dictionaryWithObjectsAndKeys:
3757 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3758 @"featured-up.png", kUIButtonBarButtonInfo,
3759 @"featured-dn.png", kUIButtonBarButtonSelectedInfo,
3760 [NSNumber numberWithInt:1], kUIButtonBarButtonTag,
3761 self, kUIButtonBarButtonTarget,
3762 @"Featured", kUIButtonBarButtonTitle,
3763 @"0", kUIButtonBarButtonType,
3766 [NSDictionary dictionaryWithObjectsAndKeys:
3767 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3768 @"install-up.png", kUIButtonBarButtonInfo,
3769 @"install-dn.png", kUIButtonBarButtonSelectedInfo,
3770 [NSNumber numberWithInt:2], kUIButtonBarButtonTag,
3771 self, kUIButtonBarButtonTarget,
3772 @"Install", kUIButtonBarButtonTitle,
3773 @"0", kUIButtonBarButtonType,
3776 [NSDictionary dictionaryWithObjectsAndKeys:
3777 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3778 @"changes-up.png", kUIButtonBarButtonInfo,
3779 @"changes-dn.png", kUIButtonBarButtonSelectedInfo,
3780 [NSNumber numberWithInt:3], kUIButtonBarButtonTag,
3781 self, kUIButtonBarButtonTarget,
3782 @"Changes", kUIButtonBarButtonTitle,
3783 @"0", kUIButtonBarButtonType,
3786 [NSDictionary dictionaryWithObjectsAndKeys:
3787 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3788 @"manage-up.png", kUIButtonBarButtonInfo,
3789 @"manage-dn.png", kUIButtonBarButtonSelectedInfo,
3790 [NSNumber numberWithInt:4], kUIButtonBarButtonTag,
3791 self, kUIButtonBarButtonTarget,
3792 @"Uninstall", kUIButtonBarButtonTitle,
3793 @"0", kUIButtonBarButtonType,
3796 [NSDictionary dictionaryWithObjectsAndKeys:
3797 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3798 @"search-up.png", kUIButtonBarButtonInfo,
3799 @"search-dn.png", kUIButtonBarButtonSelectedInfo,
3800 [NSNumber numberWithInt:5], kUIButtonBarButtonTag,
3801 self, kUIButtonBarButtonTarget,
3802 @"Search", kUIButtonBarButtonTitle,
3803 @"0", kUIButtonBarButtonType,
3807 buttonbar_ = [[UIButtonBar alloc]
3809 withFrame:CGRectMake(
3810 0, screenrect.size.height - 48,
3811 screenrect.size.width, 48
3813 withItemList:buttonitems
3816 [buttonbar_ setDelegate:self];
3817 [buttonbar_ setBarStyle:1];
3818 [buttonbar_ setButtonBarTrackingMode:2];
3820 int buttons[5] = {1, 2, 3, 4, 5};
3821 [buttonbar_ registerButtonGroup:0 withButtons:buttons withCount:5];
3822 [buttonbar_ showButtonGroup:0 withDuration:0];
3824 for (int i = 0; i != 5; ++i)
3825 [[buttonbar_ viewWithTag:(i + 1)] setFrame:CGRectMake(
3826 i * 64 + 2, 1, 60, 48
3829 [buttonbar_ showSelectionForButton:1];
3830 [transition_ transition:0 toView:featured_];
3832 [overlay_ addSubview:buttonbar_];
3834 [UIKeyboard initImplementationNow];
3836 CGRect edtrect = [overlay_ bounds];
3837 edtrect.origin.y += navsize.height;
3838 edtrect.size.height -= navsize.height;
3840 CGSize keysize = [UIKeyboard defaultSize];
3841 CGRect keyrect = {{0, [overlay_ bounds].size.height - keysize.height}, keysize};
3842 keyboard_ = [[UIKeyboard alloc] initWithFrame:keyrect];
3844 database_ = [[Database alloc] init];
3845 [database_ setDelegate:progress_];
3847 install_ = [[InstallView alloc] initWithFrame:[transition_ bounds]];
3848 [install_ setDelegate:self];
3850 changes_ = [[ChangesView alloc] initWithFrame:[transition_ bounds]];
3851 [changes_ setDelegate:self];
3853 manage_ = [[ManageView alloc] initWithFrame:[transition_ bounds]];
3854 [manage_ setDelegate:self];
3856 search_ = [[SearchView alloc] initWithFrame:[transition_ bounds]];
3857 [search_ setDelegate:self];
3859 [self reloadData:NO];
3861 Package *package([database_ packageWithName:@"cydia"]);
3862 NSString *application = package == nil ? @"Cydia" : [NSString
3863 stringWithFormat:@"Cydia/%@",
3867 WebView *webview = [webview_ webView];
3868 [webview setApplicationNameForUserAgent:application];
3869 [webview setFrameLoadDelegate:self];
3871 url_ = [NSURL URLWithString:@"http://cydia.saurik.com/"];
3874 [progress_ resetView];
3880 - (void) showKeyboard:(BOOL)show {
3882 [overlay_ addSubview:keyboard_];
3884 [keyboard_ removeFromSuperview];
3889 void AddPreferences(NSString *plist) {
3890 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
3892 NSMutableDictionary *settings = [[[NSMutableDictionary alloc] initWithContentsOfFile:plist] autorelease];
3893 _assert(settings != NULL);
3894 NSMutableArray *items = [settings objectForKey:@"items"];
3898 for (size_t i(0); i != [items count]; ++i) {
3899 NSMutableDictionary *item([items objectAtIndex:i]);
3900 NSString *label = [item objectForKey:@"label"];
3901 if (label != nil && [label isEqualToString:@"Cydia"]) {
3908 for (size_t i(0); i != [items count]; ++i) {
3909 NSDictionary *item([items objectAtIndex:i]);
3910 NSString *label = [item objectForKey:@"label"];
3911 if (label != nil && [label isEqualToString:@"General"]) {
3912 [items insertObject:[NSDictionary dictionaryWithObjectsAndKeys:
3913 @"CydiaSettings", @"bundle",
3914 @"PSLinkCell", @"cell",
3915 [NSNumber numberWithBool:YES], @"hasIcon",
3916 [NSNumber numberWithBool:YES], @"isController",
3918 nil] atIndex:(i + 1)];
3924 _assert([settings writeToFile:plist atomically:YES] == YES);
3931 id Alloc_(id self, SEL selector) {
3932 id object = alloc_(self, selector);
3933 fprintf(stderr, "[%s]A-%p\n", self->isa->name, object);
3937 int main(int argc, char *argv[]) {
3939 memset(nl, 0, sizeof(nl));
3940 nl[0].n_un.n_name = "_useMDNSResponder";
3941 nlist("/usr/lib/libc.dylib", nl);
3942 if (nl[0].n_type != N_UNDF)
3943 *(int *) nl[0].n_value = 0;
3945 bootstrap_ = argc > 1 && strcmp(argv[1], "--bootstrap") == 0;
3950 /*Method alloc = class_getClassMethod([NSObject class], @selector(alloc));
3951 alloc_ = alloc->method_imp;
3952 alloc->method_imp = (IMP) &Alloc_;*/
3954 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
3956 if (NSDictionary *sysver = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]) {
3957 if (NSString *prover = [sysver valueForKey:@"ProductVersion"]) {
3958 Firmware_ = strdup([prover cString]);
3959 NSArray *versions = [prover componentsSeparatedByString:@"."];
3960 int count = [versions count];
3961 Major_ = count > 0 ? [[versions objectAtIndex:0] intValue] : 0;
3962 Minor_ = count > 1 ? [[versions objectAtIndex:1] intValue] : 0;
3963 BugFix_ = count > 2 ? [[versions objectAtIndex:2] intValue] : 0;
3968 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
3969 char *machine = new char[size];
3970 sysctlbyname("hw.machine", machine, &size, NULL, 0);
3973 if (CFMutableDictionaryRef dict = IOServiceMatching("IOPlatformExpertDevice"))
3974 if (io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, dict)) {
3975 if (CFTypeRef serial = IORegistryEntryCreateCFProperty(service, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0)) {
3976 SerialNumber_ = strdup(CFStringGetCStringPtr((CFStringRef) serial, CFStringGetSystemEncoding()));
3980 IOObjectRelease(service);
3983 /*AddPreferences(@"/Applications/Preferences.app/Settings-iPhone.plist");
3984 AddPreferences(@"/Applications/Preferences.app/Settings-iPod.plist");*/
3986 if ((Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"]) == NULL)
3987 Metadata_ = [[NSMutableDictionary alloc] initWithCapacity:2];
3989 Packages_ = [Metadata_ objectForKey:@"Packages"];
3991 setenv("CYDIA", "", _not(int));
3992 if (access("/User", F_OK) != 0)
3993 system("/usr/libexec/cydia/firmware.sh");
3994 system("dpkg --configure -a");
3996 UIApplicationMain(argc, argv, [Cydia class]);