]> git.saurik.com Git - cydia.git/blob - Cydia.mm
Finally got all these transitions right.
[cydia.git] / Cydia.mm
1 /* #include Directives {{{ */
2 #include <Foundation/NSURL.h>
3 #include <UIKit/UIKit.h>
4 #import <GraphicsServices/GraphicsServices.h>
5
6 #include <sstream>
7 #include <ext/stdio_filebuf.h>
8
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>
20
21 #include <sys/sysctl.h>
22
23 #include <errno.h>
24 #include <pcre.h>
25 #include <string.h>
26 /* }}} */
27 /* Extension Keywords {{{ */
28 #define _trace() fprintf(stderr, "_trace()@%s:%u[%s]\n", __FILE__, __LINE__, __FUNCTION__)
29
30 #define _assert(test) do \
31 if (!(test)) { \
32 fprintf(stderr, "_assert(%d:%s)@%s:%u[%s]\n", errno, #test, __FILE__, __LINE__, __FUNCTION__); \
33 exit(-1); \
34 } \
35 while (false)
36 /* }}} */
37
38 @interface WebView
39 - (void) setApplicationNameForUserAgent:(NSString *)applicationName;
40 @end
41
42 static const int PulseInterval_ = 50000;
43 const char *Machine_ = NULL;
44 const char *SerialNumber_ = NULL;
45
46 @interface NSString (CydiaBypass)
47 - (NSString *) stringByAddingPercentEscapes;
48 @end
49
50 @protocol ProgressDelegate
51 - (void) setError:(NSString *)error;
52 - (void) setTitle:(NSString *)title;
53 - (void) setPercent:(float)percent;
54 - (void) addOutput:(NSString *)output;
55 @end
56
57 /* Status Delegation {{{ */
58 class Status :
59 public pkgAcquireStatus
60 {
61 private:
62 id delegate_;
63
64 public:
65 Status() :
66 delegate_(nil)
67 {
68 }
69
70 void setDelegate(id delegate) {
71 delegate_ = delegate;
72 }
73
74 virtual bool MediaChange(std::string media, std::string drive) {
75 return false;
76 }
77
78 virtual void IMSHit(pkgAcquire::ItemDesc &item) {
79 }
80
81 virtual void Fetch(pkgAcquire::ItemDesc &item) {
82 [delegate_ setTitle:[NSString stringWithCString:("Downloading " + item.ShortDesc).c_str()]];
83 }
84
85 virtual void Done(pkgAcquire::ItemDesc &item) {
86 }
87
88 virtual void Fail(pkgAcquire::ItemDesc &item) {
89 [delegate_ performSelectorOnMainThread:@selector(setStatusFail) withObject:nil waitUntilDone:YES];
90 }
91
92 virtual bool Pulse(pkgAcquire *Owner) {
93 bool value = pkgAcquireStatus::Pulse(Owner);
94
95 float percent(
96 double(CurrentBytes + CurrentItems) /
97 double(TotalBytes + TotalItems)
98 );
99
100 [delegate_ setPercent:percent];
101 return value;
102 }
103
104 virtual void Start() {
105 }
106
107 virtual void Stop() {
108 }
109 };
110 /* }}} */
111 /* Progress Delegation {{{ */
112 class Progress :
113 public OpProgress
114 {
115 private:
116 id delegate_;
117
118 protected:
119 virtual void Update() {
120 [delegate_ setTitle:[NSString stringWithCString:Op.c_str()]];
121 [delegate_ setPercent:(Percent / 100)];
122 }
123
124 public:
125 Progress() :
126 delegate_(nil)
127 {
128 }
129
130 void setDelegate(id delegate) {
131 delegate_ = delegate;
132 }
133
134 virtual void Done() {
135 [delegate_ setPercent:1];
136 }
137 };
138 /* }}} */
139
140 /* External Constants {{{ */
141 extern NSString *kUIButtonBarButtonAction;
142 extern NSString *kUIButtonBarButtonInfo;
143 extern NSString *kUIButtonBarButtonInfoOffset;
144 extern NSString *kUIButtonBarButtonSelectedInfo;
145 extern NSString *kUIButtonBarButtonStyle;
146 extern NSString *kUIButtonBarButtonTag;
147 extern NSString *kUIButtonBarButtonTarget;
148 extern NSString *kUIButtonBarButtonTitle;
149 extern NSString *kUIButtonBarButtonTitleVerticalHeight;
150 extern NSString *kUIButtonBarButtonTitleWidth;
151 extern NSString *kUIButtonBarButtonType;
152 /* }}} */
153 /* Mime Addresses {{{ */
154 @interface Address : NSObject {
155 NSString *name_;
156 NSString *email_;
157 }
158
159 - (void) dealloc;
160
161 - (NSString *) name;
162 - (NSString *) email;
163
164 + (Address *) addressWithString:(NSString *)string;
165 - (Address *) initWithString:(NSString *)string;
166 @end
167
168 @implementation Address
169
170 - (void) dealloc {
171 [name_ release];
172 if (email_ != nil)
173 [email_ release];
174 [super dealloc];
175 }
176
177 - (NSString *) name {
178 return name_;
179 }
180
181 - (NSString *) email {
182 return email_;
183 }
184
185 + (Address *) addressWithString:(NSString *)string {
186 return [[[Address alloc] initWithString:string] autorelease];
187 }
188
189 - (Address *) initWithString:(NSString *)string {
190 if ((self = [super init]) != nil) {
191 const char *error;
192 int offset;
193 pcre *code = pcre_compile("^\"?(.*)\"? <([^>]*)>$", 0, &error, &offset, NULL);
194
195 if (code == NULL) {
196 fprintf(stderr, "%d:%s\n", offset, error);
197 _assert(false);
198 }
199
200 pcre_extra *study = NULL;
201 int capture;
202 pcre_fullinfo(code, study, PCRE_INFO_CAPTURECOUNT, &capture);
203 int matches[(capture + 1) * 3];
204
205 size_t size = [string length];
206 const char *data = [string UTF8String];
207
208 if (pcre_exec(code, study, data, size, 0, 0, matches, sizeof(matches) / sizeof(matches[0])) >= 0) {
209 name_ = [[NSString stringWithCString:(data + matches[2]) length:(matches[3] - matches[2])] retain];
210 email_ = [[NSString stringWithCString:(data + matches[4]) length:(matches[5] - matches[4])] retain];
211 } else {
212 name_ = [[NSString stringWithCString:data length:size] retain];
213 email_ = nil;
214 }
215 } return self;
216 }
217
218 @end
219 /* }}} */
220
221 /* Right Alignment {{{ */
222 @interface UIRightTextLabel : UITextLabel {
223 float _savedRightEdgeX;
224 BOOL _sizedtofit_flag;
225 }
226
227 - (void) setFrame:(CGRect)frame;
228 - (void) setText:(NSString *)text;
229 - (void) realignText;
230 @end
231
232 @implementation UIRightTextLabel
233
234 - (void) setFrame:(CGRect)frame {
235 [super setFrame:frame];
236 if (_sizedtofit_flag == NO) {
237 _savedRightEdgeX = frame.origin.x;
238 [self realignText];
239 }
240 }
241
242 - (void) setText:(NSString *)text {
243 [super setText:text];
244 [self realignText];
245 }
246
247 - (void) realignText {
248 CGRect oldFrame = [self frame];
249
250 _sizedtofit_flag = YES;
251 [self sizeToFit]; // shrink down size so I can right align it
252
253 CGRect newFrame = [self frame];
254
255 oldFrame.origin.x = _savedRightEdgeX - newFrame.size.width;
256 oldFrame.size.width = newFrame.size.width;
257 [super setFrame:oldFrame];
258 _sizedtofit_flag = NO;
259 }
260
261 @end
262 /* }}} */
263 /* Linear Algebra {{{ */
264 inline float interpolate(float begin, float end, float fraction) {
265 return (end - begin) * fraction + begin;
266 }
267 /* }}} */
268
269 /* Reset View {{{ */
270 @interface ResetView : UIView {
271 UINavigationBar *navbar_;
272 bool resetting_;
273 }
274
275 - (void) navigationBar:(UINavigationBar *)navbar poppedItem:(UINavigationItem *)item;
276
277 - (void) dealloc;
278 - (void) resetView;
279 - (void) _resetView;
280 - (NSString *) leftTitle;
281 - (NSString *) rightTitle;
282 @end
283
284 @implementation ResetView
285
286 - (void) navigationBar:(UINavigationBar *)navbar poppedItem:(UINavigationItem *)item {
287 if ([[navbar_ navigationItems] count] == 1)
288 [self _resetView];
289 }
290
291 - (void) dealloc {
292 [navbar_ release];
293 [super dealloc];
294 }
295
296 - (void) resetView {
297 resetting_ = true;
298 if ([[navbar_ navigationItems] count] == 1)
299 [self _resetView];
300 else while ([[navbar_ navigationItems] count] != 1)
301 [navbar_ popNavigationItem];
302 resetting_ = false;
303 }
304
305 - (void) _resetView {
306 [navbar_ showButtonsWithLeftTitle:[self leftTitle] rightTitle:[self rightTitle]];
307 }
308
309 - (NSString *) leftTitle {
310 return nil;
311 }
312
313 - (NSString *) rightTitle {
314 return nil;
315 }
316
317 @end
318 /* }}} */
319
320 @class Package;
321
322 @interface Database : NSObject {
323 pkgCacheFile cache_;
324 pkgRecords *records_;
325 pkgProblemResolver *resolver_;
326
327 id delegate_;
328 Status status_;
329 Progress progress_;
330 int statusfd_;
331 }
332
333 - (void) _readStatus:(NSNumber *)fd;
334 - (void) _readOutput:(NSNumber *)fd;
335
336 - (Package *) packageWithName:(NSString *)name;
337
338 - (Database *) init;
339 - (pkgCacheFile &) cache;
340 - (pkgRecords *) records;
341 - (pkgProblemResolver *) resolver;
342 - (void) reloadData;
343
344 - (void) perform;
345 - (void) update;
346 - (void) upgrade;
347
348 - (void) setDelegate:(id)delegate;
349 @end
350
351 /* Package Class {{{ */
352 @interface Package : NSObject {
353 pkgCache::PkgIterator iterator_;
354 Database *database_;
355 pkgRecords::Parser *parser_;
356 pkgCache::VerIterator version_;
357 pkgCache::VerFileIterator file_;
358 }
359
360 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database version:(pkgCache::VerIterator)version file:(pkgCache::VerFileIterator)file;
361 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
362
363 - (NSString *) name;
364 - (NSString *) section;
365 - (NSString *) latest;
366 - (NSString *) installed;
367 - (Address *) maintainer;
368 - (size_t) size;
369 - (NSString *) tagline;
370 - (NSString *) description;
371 - (NSComparisonResult) compareBySectionAndName:(Package *)package;
372
373 - (void) install;
374 - (void) remove;
375 @end
376
377 @implementation Package
378
379 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database version:(pkgCache::VerIterator)version file:(pkgCache::VerFileIterator)file {
380 if ((self = [super init]) != nil) {
381 iterator_ = iterator;
382 database_ = database;
383
384 version_ = version;
385 file_ = file;
386 parser_ = &[database_ records]->Lookup(file);
387 } return self;
388 }
389
390 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
391 for (pkgCache::VerIterator version = iterator.VersionList(); !version.end(); ++version)
392 for (pkgCache::VerFileIterator file = version.FileList(); !file.end(); ++file)
393 return [[[Package alloc]
394 initWithIterator:iterator
395 database:database
396 version:version
397 file:file]
398 autorelease];
399 return nil;
400 }
401
402 - (NSString *) name {
403 return [[NSString stringWithCString:iterator_.Name()] lowercaseString];
404 }
405
406 - (NSString *) section {
407 return [NSString stringWithCString:iterator_.Section()];
408 }
409
410 - (NSString *) latest {
411 return [NSString stringWithCString:version_.VerStr()];
412 }
413
414 - (NSString *) installed {
415 return iterator_.CurrentVer().end() ? nil : [NSString stringWithCString:iterator_.CurrentVer().VerStr()];
416 }
417
418 - (Address *) maintainer {
419 return [Address addressWithString:[NSString stringWithCString:parser_->Maintainer().c_str()]];
420 }
421
422 - (size_t) size {
423 return version_->InstalledSize;
424 }
425
426 - (NSString *) tagline {
427 return [NSString stringWithCString:parser_->ShortDesc().c_str()];
428 }
429
430 - (NSString *) description {
431 return [NSString stringWithCString:parser_->LongDesc().c_str()];
432 }
433
434 - (NSComparisonResult) compareBySectionAndName:(Package *)package {
435 NSComparisonResult result = [[self section] compare:[package section]];
436 if (result != NSOrderedSame)
437 return result;
438 return [[self name] compare:[package name]];
439 }
440
441 - (void) install {
442 pkgProblemResolver *resolver = [database_ resolver];
443 resolver->Clear(iterator_);
444 resolver->Protect(iterator_);
445 [database_ cache]->MarkInstall(iterator_, false);
446 }
447
448 - (void) remove {
449 pkgProblemResolver *resolver = [database_ resolver];
450 resolver->Clear(iterator_);
451 resolver->Protect(iterator_);
452 resolver->Remove(iterator_);
453 [database_ cache]->MarkDelete(iterator_, true);
454 }
455
456 @end
457 /* }}} */
458 /* Section Class {{{ */
459 @interface Section : NSObject {
460 NSString *name_;
461 size_t row_;
462 NSMutableArray *packages_;
463 }
464
465 - (void) dealloc;
466
467 - (Section *) initWithName:(NSString *)name row:(size_t)row;
468 - (NSString *) name;
469 - (size_t) row;
470 - (void) addPackage:(Package *)package;
471 @end
472
473 @implementation Section
474
475 - (void) dealloc {
476 [name_ release];
477 [packages_ release];
478 [super dealloc];
479 }
480
481 - (Section *) initWithName:(NSString *)name row:(size_t)row {
482 if ((self = [super init]) != nil) {
483 name_ = [name retain];
484 row_ = row;
485 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
486 } return self;
487 }
488
489 - (NSString *) name {
490 return name_;
491 }
492
493 - (size_t) row {
494 return row_;
495 }
496
497 - (void) addPackage:(Package *)package {
498 [packages_ addObject:package];
499 }
500
501 @end
502 /* }}} */
503
504 /* Confirmation View {{{ */
505 @protocol ConfirmationViewDelegate
506 - (void) cancel;
507 - (void) confirm;
508 @end
509
510 @interface ConfirmationView : UIView {
511 Database *database_;
512 id delegate_;
513 UITransitionView *transition_;
514 UIView *overlay_;
515 UINavigationBar *navbar_;
516 UIPreferencesTable *table_;
517 }
518
519 - (void) dealloc;
520
521 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
522 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
523
524 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate;
525
526 @end
527
528 @implementation ConfirmationView
529
530 - (void) dealloc {
531 [transition_ release];
532 [overlay_ release];
533 [navbar_ release];
534 [table_ release];
535 [super dealloc];
536 }
537
538 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
539 if (from != nil && to == nil)
540 [self removeFromSuperview];
541 }
542
543 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
544 switch (button) {
545 case 0:
546 [delegate_ confirm];
547 break;
548
549 case 1:
550 [transition_ transition:7 toView:nil];
551 [delegate_ cancel];
552 break;
553 }
554 }
555
556 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate {
557 if ((self = [super initWithFrame:[view bounds]]) != nil) {
558 database_ = database;
559 delegate_ = delegate;
560
561 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
562 [self addSubview:transition_];
563
564 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
565
566 CGSize navsize = [UINavigationBar defaultSize];
567 CGRect navrect = {{0, 0}, navsize};
568 CGRect bounds = [overlay_ bounds];
569
570 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
571 [navbar_ setBarStyle:1];
572 [navbar_ setDelegate:self];
573
574 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Confirm"] autorelease];
575 [navbar_ pushNavigationItem:navitem];
576 [navbar_ showButtonsWithLeftTitle:@"Cancel" rightTitle:@"Confirm"];
577
578 table_ = [[UIPreferencesTable alloc] initWithFrame:CGRectMake(
579 0, navsize.height, bounds.size.width, bounds.size.height - navsize.height
580 )];
581
582 [table_ setDataSource:self];
583
584 [overlay_ addSubview:navbar_];
585 [overlay_ addSubview:table_];
586
587 [view addSubview:self];
588
589 [transition_ setDelegate:self];
590
591 UIView *blank = [[[UIView alloc] initWithFrame:[transition_ bounds]] autorelease];
592 [transition_ transition:0 toView:blank];
593 [transition_ transition:3 toView:overlay_];
594 } return self;
595 }
596
597 @end
598 /* }}} */
599 /* Package View {{{ */
600 @interface PackageView : UIView {
601 UIPreferencesTable *table_;
602 Package *package_;
603 Database *database_;
604 NSMutableArray *cells_;
605 id delegate_;
606 }
607
608 - (void) dealloc;
609
610 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table;
611 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group;
612 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group;
613
614 - (BOOL) canSelectRow:(int)row;
615 - (void) tableRowSelected:(NSNotification *)notification;
616
617 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database;
618 - (void) setPackage:(Package *)package;
619 - (void) setDelegate:(id)delegate;
620 @end
621
622 @implementation PackageView
623
624 - (void) dealloc {
625 if (package_ != nil)
626 [package_ release];
627 [table_ release];
628 [database_ release];
629 [cells_ release];
630 [super dealloc];
631 }
632
633 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
634 return 2;
635 }
636
637 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
638 switch (group) {
639 case 0:
640 return @"Specifics";
641 break;
642
643 case 1:
644 return @"Description";
645 break;
646
647 default: _assert(false);
648 }
649 }
650
651 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
652 switch (group) {
653 case 0:
654 return 6;
655 break;
656
657 case 1:
658 return 1;
659 break;
660
661 default: _assert(false);
662 }
663 }
664
665 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
666 UIPreferencesTableCell *cell;
667
668 switch (group) {
669 case 0: switch (row) {
670 case 0:
671 cell = [cells_ objectAtIndex:0];
672 [cell setTitle:@"Name"];
673 [cell setValue:[package_ name]];
674 break;
675
676 case 1: {
677 cell = [cells_ objectAtIndex:1];
678 [cell setTitle:@"Installed"];
679 NSString *installed([package_ installed]);
680 [cell setValue:(installed == nil ? @"n/a" : installed)];
681 } break;
682
683 case 2:
684 cell = [cells_ objectAtIndex:2];
685 [cell setTitle:@"Latest"];
686 [cell setValue:[package_ latest]];
687 break;
688
689 case 3:
690 cell = [cells_ objectAtIndex:3];
691 [cell setTitle:@"Section"];
692 [cell setValue:[package_ section]];
693 break;
694
695 case 4: {
696 double size = [package_ size];
697 unsigned power = 0;
698 while (size > 1024) {
699 size /= 1024;
700 ++power;
701 }
702
703 cell = [cells_ objectAtIndex:4];
704 [cell setTitle:@"Size"];
705 [cell setValue:[NSString stringWithFormat:@"%.1f%c", size, "bkMG"[power]]];
706 } break;
707
708 case 5:
709 cell = [cells_ objectAtIndex:5];
710 [cell setTitle:@"Maintainer"];
711 [cell setValue:[[package_ maintainer] name]];
712 [cell setShowDisclosure:YES];
713 [cell setShowSelection:YES];
714 break;
715
716 default: _assert(false);
717 } break;
718
719 case 1: switch (row) {
720 case 0:
721 cell = [cells_ objectAtIndex:6];
722 [cell setTitle:nil];
723 [cell setValue:[package_ tagline]];
724 break;
725
726 case 1:
727 cell = [cells_ objectAtIndex:7];
728 [cell setTitle:@"Description"];
729 [cell setValue:[package_ description]];
730 break;
731 } break;
732
733 default: _assert(false);
734 }
735
736 return cell;
737 }
738
739 - (BOOL) canSelectRow:(int)row {
740 return YES;
741 }
742
743 - (void) tableRowSelected:(NSNotification *)notification {
744 switch ([table_ selectedRow]) {
745 case 5:
746 [delegate_ openURL:[NSURL URLWithString:[NSString stringWithFormat:@"mailto:%@?subject=%@",
747 [[package_ maintainer] email],
748 [[NSString stringWithFormat:@"regarding apt package \"%@\"", [package_ name]] stringByAddingPercentEscapes]
749 ]]];
750 break;
751 }
752 }
753
754 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database {
755 if ((self = [super initWithFrame:frame]) != nil) {
756 database_ = [database retain];
757
758 table_ = [[UIPreferencesTable alloc] initWithFrame:[self bounds]];
759 [self addSubview:table_];
760
761 [table_ setDataSource:self];
762 [table_ setDelegate:self];
763
764 cells_ = [[NSMutableArray arrayWithCapacity:16] retain];
765
766 for (unsigned i = 0; i != 8; ++i) {
767 struct CGRect frame = [table_ frameOfPreferencesCellAtRow:0 inGroup:0];
768 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
769 [cell setShowSelection:NO];
770 [cells_ addObject:cell];
771 }
772 } return self;
773 }
774
775 - (void) setPackage:(Package *)package {
776 package_ = [package retain];
777 [table_ reloadData];
778 }
779
780 - (void) setDelegate:(id)delegate {
781 delegate_ = delegate;
782 }
783
784 @end
785 /* }}} */
786 /* Package Cell {{{ */
787 @interface PackageCell : UITableCell {
788 UITextLabel *name_;
789 UIRightTextLabel *version_;
790 UITextLabel *description_;
791 }
792
793 - (void) dealloc;
794
795 - (PackageCell *) initWithPackage:(Package *)package;
796
797 - (void) _setSelected:(float)fraction;
798 - (void) setSelected:(BOOL)selected;
799 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
800 - (void) _setSelectionFadeFraction:(float)fraction;
801
802 @end
803
804 @implementation PackageCell
805
806 - (void) dealloc {
807 [name_ release];
808 [version_ release];
809 [description_ release];
810 [super dealloc];
811 }
812
813 - (PackageCell *) initWithPackage:(Package *)package {
814 if ((self = [super init]) != nil) {
815 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22);
816 GSFontRef large = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
817 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 14);
818
819 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
820 float clear[] = {0, 0, 0, 0};
821
822 name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(12, 7, 250, 25)];
823 [name_ setText:[package name]];
824 [name_ setBackgroundColor:CGColorCreate(space, clear)];
825 [name_ setFont:bold];
826
827 version_ = [[UIRightTextLabel alloc] initWithFrame:CGRectMake(290, 7, 70, 25)];
828 [version_ setText:[package latest]];
829 [version_ setBackgroundColor:CGColorCreate(space, clear)];
830 [version_ setFont:large];
831
832 description_ = [[UITextLabel alloc] initWithFrame:CGRectMake(13, 35, 315, 20)];
833 [description_ setText:[package tagline]];
834 [description_ setBackgroundColor:CGColorCreate(space, clear)];
835 [description_ setFont:small];
836
837 [self addSubview:name_];
838 [self addSubview:version_];
839 [self addSubview:description_];
840
841 CFRelease(small);
842 CFRelease(large);
843 CFRelease(bold);
844 } return self;
845 }
846
847 - (void) _setSelected:(float)fraction {
848 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
849
850 float black[] = {
851 interpolate(0.0, 1.0, fraction),
852 interpolate(0.0, 1.0, fraction),
853 interpolate(0.0, 1.0, fraction),
854 1.0};
855
856 float blue[] = {
857 interpolate(0.2, 1.0, fraction),
858 interpolate(0.2, 1.0, fraction),
859 interpolate(1.0, 1.0, fraction),
860 1.0};
861
862 float gray[] = {
863 interpolate(0.4, 1.0, fraction),
864 interpolate(0.4, 1.0, fraction),
865 interpolate(0.4, 1.0, fraction),
866 1.0};
867
868 [name_ setColor:CGColorCreate(space, black)];
869 [version_ setColor:CGColorCreate(space, blue)];
870 [description_ setColor:CGColorCreate(space, gray)];
871 }
872
873 - (void) setSelected:(BOOL)selected {
874 [self _setSelected:(selected ? 1.0 : 0.0)];
875 [super setSelected:selected];
876 }
877
878 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
879 if (!fade)
880 [self _setSelected:(selected ? 1.0 : 0.0)];
881 [super setSelected:selected withFade:fade];
882 }
883
884 - (void) _setSelectionFadeFraction:(float)fraction {
885 [self _setSelected:fraction];
886 [super _setSelectionFadeFraction:fraction];
887 }
888
889 @end
890 /* }}} */
891 /* Sources View {{{ */
892 @interface SourcesView : ResetView {
893 UISectionList *list_;
894 Database *database_;
895 id delegate_;
896 NSMutableArray *sources_;
897 }
898
899 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
900 - (void) dealloc;
901 - (id) initWithFrame:(CGRect)frame database:(Database *)database;
902 - (void) setDelegate:(id)delegate;
903 - (void) reloadData;
904 - (NSString *) leftTitle;
905 - (NSString *) rightTitle;
906 @end
907
908 @implementation SourcesView
909
910 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
911 switch (button) {
912 case 0:
913 break;
914
915 case 1:
916 [delegate_ update];
917 break;
918 }
919 }
920
921 - (void) dealloc {
922 if (sources_ != nil)
923 [sources_ release];
924 [list_ release];
925 [super dealloc];
926 }
927
928 - (id) initWithFrame:(CGRect)frame database:(Database *)database {
929 if ((self = [super initWithFrame:frame]) != nil) {
930 database_ = database;
931 sources_ = nil;
932
933 CGSize navsize = [UINavigationBar defaultSize];
934 CGRect navrect = {{0, 0}, navsize};
935 CGRect bounds = [self bounds];
936
937 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
938 [self addSubview:navbar_];
939
940 [navbar_ setBarStyle:1];
941 [navbar_ setDelegate:self];
942
943 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Sources"] autorelease];
944 [navbar_ pushNavigationItem:navitem];
945
946 list_ = [[UISectionList alloc] initWithFrame:CGRectMake(
947 0, navsize.height, bounds.size.width, bounds.size.height - navsize.height
948 )];
949
950 [list_ setDataSource:self];
951 //[list_ setShouldHideHeaderInShortLists:NO];
952 } return self;
953 }
954
955 - (void) setDelegate:(id)delegate {
956 delegate_ = delegate;
957 }
958
959 - (void) reloadData {
960 pkgSourceList list;
961 _assert(list.ReadMainList());
962
963 sources_ = [[NSMutableArray arrayWithCapacity:16] retain];
964
965 for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source) {
966 metaIndex *index(*source);
967 fprintf(stderr, "\"%s\" \"%s\" \"%s\" \"%s\"\n", index->GetURI().c_str(), index->GetDist().c_str(), index->GetType(), index->IsTrusted() ? "true" : "false");
968
969 debReleaseIndex *dindex(dynamic_cast<debReleaseIndex *>(index));
970 if (dindex == NULL)
971 continue;
972
973 fprintf(stderr, " \"%s\"\n", dindex->MetaIndexFile("Release").c_str());
974
975 std::ifstream release(dindex->MetaIndexFile("Release").c_str());
976 std::string line;
977 while (std::getline(release, line)) {
978 std::string::size_type colon(line.find(':'));
979 if (colon == std::string::npos)
980 continue;
981 std::string name(line.substr(0, colon));
982 std::string value(line.substr(colon + 1));
983 while (!value.empty() && value[0] == ' ')
984 value = value.substr(1);
985 std::cerr << "[" << name << "|" << value << "]" << std::endl;
986 }
987 }
988
989 [self resetView];
990 }
991
992 - (NSString *) leftTitle {
993 return @"Refresh All";
994 }
995
996 - (NSString *) rightTitle {
997 return @"Edit";
998 }
999
1000 @end
1001 /* }}} */
1002
1003 @implementation Database
1004
1005 - (void) _readStatus:(NSNumber *)fd {
1006 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1007
1008 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1009 std::istream is(&ib);
1010 std::string line;
1011
1012 const char *error;
1013 int offset;
1014 pcre *code = pcre_compile("^([^:]*):([^:]*):([^:]*):(.*)$", 0, &error, &offset, NULL);
1015
1016 pcre_extra *study = NULL;
1017 int capture;
1018 pcre_fullinfo(code, study, PCRE_INFO_CAPTURECOUNT, &capture);
1019 int matches[(capture + 1) * 3];
1020
1021 while (std::getline(is, line)) {
1022 const char *data(line.c_str());
1023
1024 _assert(pcre_exec(code, study, data, line.size(), 0, 0, matches, sizeof(matches) / sizeof(matches[0])) >= 0);
1025
1026 std::istringstream buffer(line.substr(matches[6], matches[7] - matches[6]));
1027 float percent;
1028 buffer >> percent;
1029 [delegate_ setPercent:(percent / 100)];
1030
1031 NSString *string = [NSString stringWithCString:(data + matches[8]) length:(matches[9] - matches[8])];
1032 std::string type(line.substr(matches[2], matches[3] - matches[2]));
1033
1034 if (type == "pmerror")
1035 [delegate_ setError:string];
1036 else if (type == "pmstatus")
1037 [delegate_ setTitle:string];
1038 else if (type == "pmconffile")
1039 ;
1040 else _assert(false);
1041 }
1042
1043 [pool release];
1044 }
1045
1046 - (void) _readOutput:(NSNumber *)fd {
1047 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1048
1049 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1050 std::istream is(&ib);
1051 std::string line;
1052
1053 while (std::getline(is, line))
1054 [delegate_ addOutput:[NSString stringWithCString:line.c_str()]];
1055
1056 [pool release];
1057 }
1058
1059 - (Package *) packageWithName:(NSString *)name {
1060 pkgCache::PkgIterator iterator(cache_->FindPkg([name cString]));
1061 return iterator.end() ? nil : [Package packageWithIterator:iterator database:self];
1062 }
1063
1064 - (Database *) init {
1065 if ((self = [super init]) != nil) {
1066 records_ = NULL;
1067 resolver_ = NULL;
1068
1069 int fds[2];
1070
1071 _assert(pipe(fds) != -1);
1072 statusfd_ = fds[1];
1073
1074 [NSThread
1075 detachNewThreadSelector:@selector(_readStatus:)
1076 toTarget:self
1077 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1078 ];
1079
1080 _assert(pipe(fds) != -1);
1081 _assert(dup2(fds[1], 1) != -1);
1082 _assert(close(fds[1]) != -1);
1083
1084 [NSThread
1085 detachNewThreadSelector:@selector(_readOutput:)
1086 toTarget:self
1087 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1088 ];
1089 } return self;
1090 }
1091
1092 - (pkgCacheFile &) cache {
1093 return cache_;
1094 }
1095
1096 - (pkgRecords *) records {
1097 return records_;
1098 }
1099
1100 - (pkgProblemResolver *) resolver {
1101 return resolver_;
1102 }
1103
1104 - (void) reloadData {
1105 _error->Discard();
1106 delete resolver_;
1107 delete records_;
1108 cache_.Close();
1109 cache_.Open(progress_, true);
1110 records_ = new pkgRecords(cache_);
1111 resolver_ = new pkgProblemResolver(cache_);
1112 }
1113
1114 - (void) perform {
1115 pkgRecords records(cache_);
1116
1117 FileFd lock;
1118 lock.Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1119 _assert(!_error->PendingError());
1120
1121 pkgAcquire fetcher(&status_);
1122 pkgSourceList list;
1123 _assert(list.ReadMainList());
1124
1125 SPtr<pkgPackageManager> manager(_system->CreatePM(cache_));
1126 _assert(manager->GetArchives(&fetcher, &list, &records));
1127 _assert(!_error->PendingError());
1128 _assert(fetcher.Run(PulseInterval_) != pkgAcquire::Failed);
1129
1130 _system->UnLock();
1131 pkgPackageManager::OrderResult result = manager->DoInstall(statusfd_);
1132
1133 if (result == pkgPackageManager::Failed)
1134 return;
1135 if (_error->PendingError())
1136 return;
1137 if (result != pkgPackageManager::Completed)
1138 return;
1139 }
1140
1141 - (void) update {
1142 pkgSourceList list;
1143 _assert(list.ReadMainList());
1144
1145 FileFd lock;
1146 lock.Fd(GetLock(_config->FindDir("Dir::State::Lists") + "lock"));
1147 _assert(!_error->PendingError());
1148
1149 pkgAcquire fetcher(&status_);
1150 _assert(list.GetIndexes(&fetcher));
1151 _assert(fetcher.Run(PulseInterval_) != pkgAcquire::Failed);
1152
1153 bool failed = false;
1154 for (pkgAcquire::ItemIterator item = fetcher.ItemsBegin(); item != fetcher.ItemsEnd(); item++)
1155 if ((*item)->Status != pkgAcquire::Item::StatDone) {
1156 (*item)->Finished();
1157 failed = true;
1158 }
1159
1160 if (!failed && _config->FindB("APT::Get::List-Cleanup", true) == true) {
1161 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists")));
1162 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/"));
1163 }
1164 }
1165
1166 - (void) upgrade {
1167 _assert(cache_->DelCount() == 0 && cache_->InstCount() == 0);
1168 _assert(pkgApplyStatus(cache_));
1169
1170 if (cache_->BrokenCount() != 0) {
1171 _assert(pkgFixBroken(cache_));
1172 _assert(cache_->BrokenCount() == 0);
1173 _assert(pkgMinimizeUpgrade(cache_));
1174 }
1175
1176 _assert(pkgDistUpgrade(cache_));
1177
1178 //InstallPackages(cache_, true);
1179 }
1180
1181 - (void) setDelegate:(id)delegate {
1182 delegate_ = delegate;
1183 status_.setDelegate(delegate);
1184 progress_.setDelegate(delegate);
1185 }
1186
1187 @end
1188
1189 /* Progress Data {{{ */
1190 @interface ProgressData : NSObject {
1191 SEL selector_;
1192 id target_;
1193 id object_;
1194 }
1195
1196 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object;
1197
1198 - (SEL) selector;
1199 - (id) target;
1200 - (id) object;
1201 @end
1202
1203 @implementation ProgressData
1204
1205 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object {
1206 if ((self = [super init]) != nil) {
1207 selector_ = selector;
1208 target_ = target;
1209 object_ = object;
1210 } return self;
1211 }
1212
1213 - (SEL) selector {
1214 return selector_;
1215 }
1216
1217 - (id) target {
1218 return target_;
1219 }
1220
1221 - (id) object {
1222 return object_;
1223 }
1224
1225 @end
1226 /* }}} */
1227 /* Progress View {{{ */
1228 @interface ProgressView : UIView <
1229 ProgressDelegate
1230 > {
1231 UIView *view_;
1232 UIView *background_;
1233 UITransitionView *transition_;
1234 UIView *overlay_;
1235 UINavigationBar *navbar_;
1236 UIProgressBar *progress_;
1237 UITextView *output_;
1238 UITextLabel *status_;
1239 id delegate_;
1240 UIAlertSheet *alert_;
1241 }
1242
1243 - (void) dealloc;
1244
1245 - (ProgressView *) initWithFrame:(struct CGRect)frame delegate:(id)delegate;
1246 - (void) setContentView:(UIView *)view;
1247 - (void) resetView;
1248
1249 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
1250
1251 - (void) _retachThread;
1252 - (void) _detachNewThreadData:(ProgressData *)data;
1253 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object;
1254
1255 - (void) setError:(NSString *)error;
1256 - (void) _setError:(NSString *)error;
1257
1258 - (void) setTitle:(NSString *)title;
1259 - (void) _setTitle:(NSString *)title;
1260
1261 - (void) setPercent:(float)percent;
1262 - (void) _setPercent:(NSNumber *)percent;
1263
1264 - (void) addOutput:(NSString *)output;
1265 - (void) _addOutput:(NSString *)output;
1266
1267 - (void) setStatusFail;
1268 @end
1269
1270 @protocol ProgressViewDelegate
1271 - (void) progressViewIsComplete:(ProgressView *)sender;
1272 @end
1273
1274 @implementation ProgressView
1275
1276 - (void) dealloc {
1277 [view_ release];
1278 [background_ release];
1279 [transition_ release];
1280 [overlay_ release];
1281 [navbar_ release];
1282 [progress_ release];
1283 [output_ release];
1284 [status_ release];
1285 [super dealloc];
1286 }
1287
1288 - (ProgressView *) initWithFrame:(struct CGRect)frame delegate:(id)delegate {
1289 if ((self = [super initWithFrame:frame]) != nil) {
1290 delegate_ = delegate;
1291 alert_ = nil;
1292
1293 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1294 float black[] = {0.0, 0.0, 0.0, 1.0};
1295 float white[] = {1.0, 1.0, 1.0, 1.0};
1296 float clear[] = {0.0, 0.0, 0.0, 0.0};
1297
1298 background_ = [[UIView alloc] initWithFrame:[self bounds]];
1299 [background_ setBackgroundColor:CGColorCreate(space, black)];
1300 [self addSubview:background_];
1301
1302 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
1303 [self addSubview:transition_];
1304
1305 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
1306
1307 CGSize navsize = [UINavigationBar defaultSize];
1308 CGRect navrect = {{0, 0}, navsize};
1309
1310 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
1311 [overlay_ addSubview:navbar_];
1312
1313 [navbar_ setBarStyle:1];
1314 [navbar_ setDelegate:self];
1315
1316 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Running..."] autorelease];
1317 [navbar_ pushNavigationItem:navitem];
1318
1319 CGRect bounds = [overlay_ bounds];
1320 CGSize prgsize = [UIProgressBar defaultSize];
1321
1322 CGRect prgrect = {{
1323 (bounds.size.width - prgsize.width) / 2,
1324 bounds.size.height - prgsize.height - 20
1325 }, prgsize};
1326
1327 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
1328 [overlay_ addSubview:progress_];
1329
1330 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(
1331 10,
1332 bounds.size.height - prgsize.height - 50,
1333 bounds.size.width - 20,
1334 24
1335 )];
1336
1337 [status_ setColor:CGColorCreate(space, white)];
1338 [status_ setBackgroundColor:CGColorCreate(space, clear)];
1339
1340 [status_ setCentersHorizontally:YES];
1341 //[status_ setFont:font];
1342
1343 output_ = [[UITextView alloc] initWithFrame:CGRectMake(
1344 10,
1345 navrect.size.height + 20,
1346 bounds.size.width - 20,
1347 bounds.size.height - navsize.height - 62 - navrect.size.height
1348 )];
1349
1350 //[output_ setTextFont:@"Courier New"];
1351 [output_ setTextSize:12];
1352
1353 [output_ setTextColor:CGColorCreate(space, white)];
1354 [output_ setBackgroundColor:CGColorCreate(space, clear)];
1355
1356 [output_ setMarginTop:0];
1357 [output_ setAllowsRubberBanding:YES];
1358
1359 [overlay_ addSubview:output_];
1360 [overlay_ addSubview:status_];
1361
1362 [progress_ setStyle:0];
1363 } return self;
1364 }
1365
1366 - (void) setContentView:(UIView *)view {
1367 view_ = view;
1368 }
1369
1370 - (void) resetView {
1371 [transition_ transition:6 toView:view_];
1372 }
1373
1374 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
1375 [alert_ dismiss];
1376 [alert_ release];
1377 alert_ = nil;
1378 }
1379
1380 - (void) _retachThread {
1381 [delegate_ progressViewIsComplete:self];
1382 [self resetView];
1383 }
1384
1385 - (void) _detachNewThreadData:(ProgressData *)data {
1386 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1387
1388 [[data target] performSelector:[data selector] withObject:[data object]];
1389 [self performSelectorOnMainThread:@selector(_retachThread) withObject:nil waitUntilDone:YES];
1390
1391 [data release];
1392 [pool release];
1393 }
1394
1395 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object {
1396 [status_ setText:nil];
1397 [output_ setText:@""];
1398 [progress_ setProgress:0];
1399
1400 [transition_ transition:6 toView:overlay_];
1401
1402 [NSThread
1403 detachNewThreadSelector:@selector(_detachNewThreadData:)
1404 toTarget:self
1405 withObject:[[ProgressData alloc]
1406 initWithSelector:selector
1407 target:target
1408 object:object
1409 ]
1410 ];
1411 }
1412
1413 - (void) setStatusFail {
1414 }
1415
1416 - (void) setError:(NSString *)error {
1417 [self
1418 performSelectorOnMainThread:@selector(_setError:)
1419 withObject:error
1420 waitUntilDone:YES
1421 ];
1422 }
1423
1424 - (void) _setError:(NSString *)error {
1425 _assert(alert_ == nil);
1426
1427 alert_ = [[UIAlertSheet alloc]
1428 initWithTitle:@"Package Error"
1429 buttons:[NSArray arrayWithObjects:@"Okay", nil]
1430 defaultButtonIndex:0
1431 delegate:self
1432 context:self
1433 ];
1434
1435 [alert_ setBodyText:error];
1436 [alert_ popupAlertAnimated:YES];
1437 }
1438
1439 - (void) setTitle:(NSString *)title {
1440 [self
1441 performSelectorOnMainThread:@selector(_setTitle:)
1442 withObject:title
1443 waitUntilDone:YES
1444 ];
1445 }
1446
1447 - (void) _setTitle:(NSString *)title {
1448 [status_ setText:[title stringByAppendingString:@"..."]];
1449 }
1450
1451 - (void) setPercent:(float)percent {
1452 [self
1453 performSelectorOnMainThread:@selector(_setPercent:)
1454 withObject:[NSNumber numberWithFloat:percent]
1455 waitUntilDone:YES
1456 ];
1457 }
1458
1459 - (void) _setPercent:(NSNumber *)percent {
1460 [progress_ setProgress:[percent floatValue]];
1461 }
1462
1463 - (void) addOutput:(NSString *)output {
1464 [self
1465 performSelectorOnMainThread:@selector(_addOutput:)
1466 withObject:output
1467 waitUntilDone:YES
1468 ];
1469 }
1470
1471 - (void) _addOutput:(NSString *)output {
1472 [output_ setText:[NSString stringWithFormat:@"%@\n%@", [output_ text], output]];
1473 CGSize size = [output_ contentSize];
1474 CGRect rect = {{0, size.height}, {size.width, 0}};
1475 [output_ scrollRectToVisible:rect animated:YES];
1476 }
1477
1478 @end
1479 /* }}} */
1480
1481 @protocol PackagesViewDelegate
1482 - (void) perform;
1483 - (void) update;
1484 - (void) openURL:(NSString *)url;
1485 @end
1486
1487 /* PackagesView {{{ */
1488 @interface PackagesView : ResetView {
1489 Database *database_;
1490 NSMutableArray *packages_;
1491 NSMutableArray *sections_;
1492 id delegate_;
1493 UISectionList *list_;
1494 UITransitionView *transition_;
1495 Package *package_;
1496 PackageView *pkgview_;
1497 }
1498
1499 - (int) numberOfSectionsInSectionList:(UISectionList *)list;
1500 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section;
1501 - (int) sectionList:(UISectionList *)list rowForSection:(int)section;
1502
1503 - (int) numberOfRowsInTable:(UITable *)table;
1504 - (float) table:(UITable *)table heightForRow:(int)row;
1505 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col;
1506 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row;
1507 - (void) tableRowSelected:(NSNotification*)notification;
1508
1509 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
1510 - (void) navigationBar:(UINavigationBar *)navbar poppedItem:(UINavigationItem *)item;
1511
1512 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database;
1513 - (void) setDelegate:(id)delegate;
1514 - (void) deselect;
1515 - (void) reloadData;
1516
1517 - (NSString *) title;
1518 - (void) perform:(Package *)package;
1519 - (void) addPackage:(Package *)package;
1520 @end
1521
1522 @implementation PackagesView
1523
1524 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
1525 return [sections_ count];
1526 }
1527
1528 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
1529 return [[sections_ objectAtIndex:section] name];
1530 }
1531
1532 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
1533 return [[sections_ objectAtIndex:section] row];
1534 }
1535
1536 - (int) numberOfRowsInTable:(UITable *)table {
1537 return [packages_ count];
1538 }
1539
1540 - (float) table:(UITable *)table heightForRow:(int)row {
1541 return 64;
1542 }
1543
1544 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col {
1545 Package *package = [packages_ objectAtIndex:row];
1546 PackageCell *cell = [[[PackageCell alloc] initWithPackage:package] autorelease];
1547 return cell;
1548 }
1549
1550 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
1551 return YES;
1552 }
1553
1554 - (void) tableRowSelected:(NSNotification*)notification {
1555 int row = [[list_ table] selectedRow];
1556 if (row == INT_MAX)
1557 return;
1558
1559 package_ = [packages_ objectAtIndex:row];
1560
1561 UINavigationItem *navitem = [[UINavigationItem alloc] initWithTitle:[package_ name]];
1562 [navbar_ pushNavigationItem:navitem];
1563
1564 [navbar_ showButtonsWithLeftTitle:nil rightTitle:[self title]];
1565
1566 [pkgview_ setPackage:package_];
1567 [transition_ transition:1 toView:pkgview_];
1568 }
1569
1570 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
1571 if (button == 0) {
1572 [self perform:package_];
1573
1574 pkgProblemResolver *resolver = [database_ resolver];
1575
1576 resolver->InstallProtect();
1577 if (!resolver->Resolve(true))
1578 _error->Discard();
1579
1580 [delegate_ perform];
1581 }
1582 }
1583
1584 - (void) navigationBar:(UINavigationBar *)navbar poppedItem:(UINavigationItem *)item {
1585 [self deselect];
1586 [super navigationBar:navbar poppedItem:item];
1587 }
1588
1589 - (id) initWithFrame:(struct CGRect)frame database:(Database *)database {
1590 if ((self = [super initWithFrame:frame]) != nil) {
1591 database_ = [database retain];
1592
1593 struct CGRect bounds = [self bounds];
1594 CGSize navsize = [UINavigationBar defaultSize];
1595 CGRect navrect = {{0, 0}, navsize};
1596
1597 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
1598 [self addSubview:navbar_];
1599
1600 [navbar_ setBarStyle:1];
1601 [navbar_ setDelegate:self];
1602
1603 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:[self title]] autorelease];
1604 [navbar_ pushNavigationItem:navitem];
1605 [navitem setBackButtonTitle:@"Packages"];
1606
1607 transition_ = [[UITransitionView alloc] initWithFrame:CGRectMake(
1608 bounds.origin.x, bounds.origin.y + navsize.height, bounds.size.width, bounds.size.height - navsize.height
1609 )];
1610
1611 [self addSubview:transition_];
1612
1613 list_ = [[UISectionList alloc] initWithFrame:[transition_ bounds] showSectionIndex:NO];
1614 [list_ setDataSource:self];
1615 [list_ setShouldHideHeaderInShortLists:NO];
1616
1617 [transition_ transition:0 toView:list_];
1618
1619 UITableColumn *column = [[UITableColumn alloc]
1620 initWithTitle:@"Name"
1621 identifier:@"name"
1622 width:frame.size.width
1623 ];
1624
1625 UITable *table = [list_ table];
1626 [table setSeparatorStyle:1];
1627 [table addTableColumn:column];
1628 [table setDelegate:self];
1629
1630 pkgview_ = [[PackageView alloc] initWithFrame:[transition_ bounds] database:database_];
1631 } return self;
1632 }
1633
1634 - (void) setDelegate:(id)delegate {
1635 delegate_ = delegate;
1636 [pkgview_ setDelegate:delegate];
1637 }
1638
1639 - (void) deselect {
1640 [transition_ transition:(resetting_ ? 0 : 2) toView:list_];
1641 UITable *table = [list_ table];
1642 [table selectRow:-1 byExtendingSelection:NO withFade:(resetting_ ? NO : YES)];
1643 package_ = nil;
1644 }
1645
1646 - (void) reloadData {
1647 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
1648
1649 if (sections_ != nil) {
1650 [sections_ release];
1651 sections_ = nil;
1652 }
1653
1654 for (pkgCache::PkgIterator iterator = [database_ cache]->PkgBegin(); !iterator.end(); ++iterator)
1655 if (Package *package = [Package packageWithIterator:iterator database:database_])
1656 [self addPackage:package];
1657
1658 [packages_ sortUsingSelector:@selector(compareBySectionAndName:)];
1659 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
1660
1661 Section *section = nil;
1662 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
1663 Package *package = [packages_ objectAtIndex:offset];
1664 NSString *name = [package section];
1665
1666 if (section == nil || ![[section name] isEqual:name]) {
1667 section = [[Section alloc] initWithName:name row:offset];
1668 [sections_ addObject:section];
1669 }
1670
1671 [section addPackage:package];
1672 }
1673
1674 [list_ reloadData];
1675 [self resetView];
1676 }
1677
1678 - (NSString *) title {
1679 return nil;
1680 }
1681
1682 - (void) perform:(Package *)package {
1683 }
1684
1685 - (void) addPackage:(Package *)package {
1686 [packages_ addObject:package];
1687 }
1688
1689 @end
1690 /* }}} */
1691
1692 /* InstallView {{{ */
1693 @interface InstallView : PackagesView {
1694 }
1695
1696 - (NSString *) title;
1697 - (void) addPackage:(Package *)package;
1698 - (void) perform:(Package *)package;
1699 @end
1700
1701 @implementation InstallView
1702
1703 - (NSString *) title {
1704 return @"Install";
1705 }
1706
1707 - (void) addPackage:(Package *)package {
1708 if ([package installed] == nil)
1709 [super addPackage:package];
1710 }
1711
1712 - (void) perform:(Package *)package {
1713 [package install];
1714 }
1715
1716 @end
1717 /* }}} */
1718 /* UpgradeView {{{ */
1719 @interface UpgradeView : PackagesView {
1720 }
1721
1722 - (NSString *) title;
1723 - (NSString *) leftTitle;
1724 - (void) addPackage:(Package *)package;
1725 - (void) perform:(Package *)package;
1726 @end
1727
1728 @implementation UpgradeView
1729
1730 - (NSString *) title {
1731 return @"Upgrade";
1732 }
1733
1734 - (NSString *) leftTitle {
1735 return @"Upgrade All";
1736 }
1737
1738 - (void) addPackage:(Package *)package {
1739 NSString *installed = [package installed];
1740 if (installed != nil && [[package latest] compare:installed] != NSOrderedSame)
1741 [super addPackage:package];
1742 }
1743
1744 - (void) perform:(Package *)package {
1745 [package install];
1746 }
1747
1748 @end
1749 /* }}} */
1750 /* UninstallView {{{ */
1751 @interface UninstallView : PackagesView {
1752 }
1753
1754 - (NSString *) title;
1755 - (void) addPackage:(Package *)package;
1756 - (void) perform:(Package *)package;
1757 @end
1758
1759 @implementation UninstallView
1760
1761 - (NSString *) title {
1762 return @"Uninstall";
1763 }
1764
1765 - (void) addPackage:(Package *)package {
1766 if ([package installed] != nil)
1767 [super addPackage:package];
1768 }
1769
1770 - (void) perform:(Package *)package {
1771 [package remove];
1772 }
1773
1774 @end
1775 /* }}} */
1776
1777 @interface Cydia : UIApplication <
1778 ConfirmationViewDelegate,
1779 PackagesViewDelegate,
1780 ProgressViewDelegate
1781 > {
1782 UIWindow *window_;
1783 UIView *underlay_;
1784 UIView *overlay_;
1785 UITransitionView *transition_;
1786 UIButtonBar *buttonbar_;
1787
1788 UIAlertSheet *alert_;
1789 ConfirmationView *confirm_;
1790
1791 Database *database_;
1792 ProgressView *progress_;
1793
1794 UIView *featured_;
1795 UINavigationBar *navbar_;
1796 UIScroller *scroller_;
1797 UIWebView *webview_;
1798 NSURL *url_;
1799
1800 InstallView *install_;
1801 UpgradeView *upgrade_;
1802 UninstallView *uninstall_;
1803 SourcesView *sources_;
1804 }
1805
1806 - (void) loadNews;
1807 - (void) reloadData;
1808 - (void) perform;
1809 - (void) cancel;
1810 - (void) confirm;
1811 - (void) update;
1812
1813 - (void) progressViewIsComplete:(ProgressView *)progress;
1814
1815 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
1816 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
1817 - (void) buttonBarItemTapped:(id)sender;
1818
1819 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame;
1820 - (void) view:(UIView *)view didDrawInRect:(CGRect)rect duration:(float)duration;
1821
1822 - (void) applicationDidFinishLaunching:(id)unused;
1823 @end
1824
1825 #include <objc/objc-class.h>
1826
1827 @implementation Cydia
1828
1829 - (void) loadNews {
1830 NSMutableURLRequest *request = [NSMutableURLRequest
1831 requestWithURL:url_
1832 cachePolicy:NSURLRequestReloadIgnoringCacheData
1833 timeoutInterval:30.0
1834 ];
1835
1836 [request addValue:[NSString stringWithCString:Machine_] forHTTPHeaderField:@"X-Machine"];
1837 [request addValue:[NSString stringWithCString:SerialNumber_] forHTTPHeaderField:@"X-Serial-Number"];
1838
1839 [webview_ loadRequest:request];
1840 }
1841
1842 - (void) reloadData {
1843 [database_ reloadData];
1844 [install_ reloadData];
1845 [upgrade_ reloadData];
1846 [uninstall_ reloadData];
1847 [sources_ reloadData];
1848 }
1849
1850 - (void) perform {
1851 confirm_ = [[ConfirmationView alloc] initWithView:underlay_ database:database_ delegate:self];
1852 }
1853
1854 - (void) cancel {
1855 [confirm_ release];
1856 confirm_ = nil;
1857 }
1858
1859 - (void) confirm {
1860 [overlay_ removeFromSuperview];
1861
1862 [progress_
1863 detachNewThreadSelector:@selector(perform)
1864 toTarget:database_
1865 withObject:nil
1866 ];
1867 }
1868
1869 - (void) update {
1870 [progress_
1871 detachNewThreadSelector:@selector(update)
1872 toTarget:database_
1873 withObject:nil
1874 ];
1875 }
1876
1877 - (void) progressViewIsComplete:(ProgressView *)progress {
1878 [self reloadData];
1879
1880 if (confirm_ != nil) {
1881 [underlay_ addSubview:overlay_];
1882 [confirm_ removeFromSuperview];
1883 [confirm_ release];
1884 confirm_ = nil;
1885 }
1886 }
1887
1888 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
1889 switch (button) {
1890 case 0:
1891 [self loadNews];
1892 break;
1893
1894 case 1:
1895 _assert(alert_ == nil);
1896
1897 alert_ = [[UIAlertSheet alloc]
1898 initWithTitle:@"About Cydia Packager"
1899 buttons:[NSArray arrayWithObjects:@"Close", nil]
1900 defaultButtonIndex:0
1901 delegate:self
1902 context:self
1903 ];
1904
1905 [alert_ setBodyText:
1906 @"Copyright (C) 2007\n"
1907 "Jay Freeman (saurik)\n"
1908 "saurik@saurik.com\n"
1909 "http://www.saurik.com/\n"
1910 "\n"
1911 "The Okori Group\n"
1912 "http://www.theokorigroup.com/\n"
1913 "\n"
1914 "College of Creative Studies,\n"
1915 "University of California,\n"
1916 "Santa Barbara\n"
1917 "http://www.ccs.ucsb.edu/\n"
1918 "\n"
1919 "Special Thanks:\n"
1920 "bad_, BHSPitMonkey, Cobra, core,\n"
1921 "Corona, cromas, Darken, dtzWill,\n"
1922 "francis, Godores, jerry, Kingstone,\n"
1923 "lounger, rockabilly, tman, Wbiggs"
1924 ];
1925
1926 [alert_ presentSheetFromButtonBar:buttonbar_];
1927 break;
1928 }
1929 }
1930
1931 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
1932 [alert_ dismiss];
1933 [alert_ release];
1934 alert_ = nil;
1935 }
1936
1937 - (void) buttonBarItemTapped:(id)sender {
1938 UIView *view;
1939
1940 switch ([sender tag]) {
1941 case 1: view = featured_; break;
1942 case 2: view = install_; break;
1943 case 3: view = upgrade_; break;
1944 case 4: view = uninstall_; break;
1945 case 5: view = sources_; break;
1946
1947 default:
1948 _assert(false);
1949 }
1950
1951 if ([view respondsToSelector:@selector(resetView)])
1952 [(id) view resetView];
1953 [transition_ transition:0 toView:view];
1954 }
1955
1956 - (void) view:(UIView *)view didSetFrame:(CGRect)frame {
1957 [scroller_ setContentSize:frame.size];
1958 }
1959
1960 - (void) view:(UIView *)view didDrawInRect:(CGRect)rect duration:(float)duration {
1961 [scroller_ setContentSize:[webview_ bounds].size];
1962 }
1963
1964 - (void) applicationDidFinishLaunching:(id)unused {
1965 _assert(pkgInitConfig(*_config));
1966 _assert(pkgInitSystem(*_config, _system));
1967
1968 alert_ = nil;
1969 confirm_ = nil;
1970
1971 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
1972 window_ = [[UIWindow alloc] initWithContentRect:screenrect];
1973
1974 [window_ orderFront: self];
1975 [window_ makeKey: self];
1976 [window_ _setHidden: NO];
1977
1978 progress_ = [[ProgressView alloc] initWithFrame:[window_ bounds] delegate:self];
1979 [window_ setContentView:progress_];
1980
1981 underlay_ = [[UIView alloc] initWithFrame:[progress_ bounds]];
1982 [progress_ setContentView:underlay_];
1983
1984 overlay_ = [[UIView alloc] initWithFrame:[underlay_ bounds]];
1985 [underlay_ addSubview:overlay_];
1986
1987 transition_ = [[UITransitionView alloc] initWithFrame:CGRectMake(
1988 0, 0, screenrect.size.width, screenrect.size.height - 48
1989 )];
1990
1991 [overlay_ addSubview:transition_];
1992
1993 featured_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
1994
1995 CGSize navsize = [UINavigationBar defaultSize];
1996 CGRect navrect = {{0, 0}, navsize};
1997
1998 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
1999 [featured_ addSubview:navbar_];
2000
2001 [navbar_ setBarStyle:1];
2002 [navbar_ setDelegate:self];
2003
2004 [navbar_ showButtonsWithLeftTitle:@"About" rightTitle:@"Reload"];
2005
2006 UINavigationItem *navitem = [[UINavigationItem alloc] initWithTitle:@"Featured"];
2007 [navbar_ pushNavigationItem:navitem];
2008
2009 struct CGRect subbounds = [featured_ bounds];
2010 subbounds.origin.y += navsize.height;
2011 subbounds.size.height -= navsize.height;
2012
2013 UIImageView *pinstripe = [[UIImageView alloc] initWithFrame:subbounds];
2014 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
2015 [featured_ addSubview:pinstripe];
2016
2017 scroller_ = [[UIScroller alloc] initWithFrame:subbounds];
2018 [featured_ addSubview:scroller_];
2019
2020 [scroller_ setScrollingEnabled:YES];
2021 [scroller_ setAdjustForContentSizeChange:YES];
2022 [scroller_ setClipsSubviews:YES];
2023 [scroller_ setAllowsRubberBanding:YES];
2024 [scroller_ setScrollDecelerationFactor:0.99];
2025 [scroller_ setDelegate:self];
2026
2027 webview_ = [[UIWebView alloc] initWithFrame:[scroller_ bounds]];
2028 [scroller_ addSubview:webview_];
2029
2030 [webview_ setTilingEnabled:YES];
2031 [webview_ setTileSize:CGSizeMake(screenrect.size.width, 500)];
2032 [webview_ setAutoresizes:YES];
2033 [webview_ setDelegate:self];
2034
2035 NSArray *buttonitems = [NSArray arrayWithObjects:
2036 [NSDictionary dictionaryWithObjectsAndKeys:
2037 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
2038 @"featured-up.png", kUIButtonBarButtonInfo,
2039 @"featured-dn.png", kUIButtonBarButtonSelectedInfo,
2040 [NSNumber numberWithInt:1], kUIButtonBarButtonTag,
2041 self, kUIButtonBarButtonTarget,
2042 @"Featured", kUIButtonBarButtonTitle,
2043 @"0", kUIButtonBarButtonType,
2044 nil],
2045
2046 [NSDictionary dictionaryWithObjectsAndKeys:
2047 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
2048 @"install-up.png", kUIButtonBarButtonInfo,
2049 @"install-dn.png", kUIButtonBarButtonSelectedInfo,
2050 [NSNumber numberWithInt:2], kUIButtonBarButtonTag,
2051 self, kUIButtonBarButtonTarget,
2052 @"Install", kUIButtonBarButtonTitle,
2053 @"0", kUIButtonBarButtonType,
2054 nil],
2055
2056 [NSDictionary dictionaryWithObjectsAndKeys:
2057 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
2058 @"upgrade-up.png", kUIButtonBarButtonInfo,
2059 @"upgrade-dn.png", kUIButtonBarButtonSelectedInfo,
2060 [NSNumber numberWithInt:3], kUIButtonBarButtonTag,
2061 self, kUIButtonBarButtonTarget,
2062 @"Upgrade", kUIButtonBarButtonTitle,
2063 @"0", kUIButtonBarButtonType,
2064 nil],
2065
2066 [NSDictionary dictionaryWithObjectsAndKeys:
2067 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
2068 @"uninstall-up.png", kUIButtonBarButtonInfo,
2069 @"uninstall-dn.png", kUIButtonBarButtonSelectedInfo,
2070 [NSNumber numberWithInt:4], kUIButtonBarButtonTag,
2071 self, kUIButtonBarButtonTarget,
2072 @"Uninstall", kUIButtonBarButtonTitle,
2073 @"0", kUIButtonBarButtonType,
2074 nil],
2075
2076 [NSDictionary dictionaryWithObjectsAndKeys:
2077 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
2078 @"sources-up.png", kUIButtonBarButtonInfo,
2079 @"sources-dn.png", kUIButtonBarButtonSelectedInfo,
2080 [NSNumber numberWithInt:5], kUIButtonBarButtonTag,
2081 self, kUIButtonBarButtonTarget,
2082 @"Sources", kUIButtonBarButtonTitle,
2083 @"0", kUIButtonBarButtonType,
2084 nil],
2085 nil];
2086
2087 buttonbar_ = [[UIButtonBar alloc]
2088 initInView:overlay_
2089 withFrame:CGRectMake(
2090 0, screenrect.size.height - 48,
2091 screenrect.size.width, 48
2092 )
2093 withItemList:buttonitems
2094 ];
2095
2096 [buttonbar_ setDelegate:self];
2097 [buttonbar_ setBarStyle:1];
2098 [buttonbar_ setButtonBarTrackingMode:2];
2099
2100 int buttons[5] = {1, 2, 3, 4, 5};
2101 [buttonbar_ registerButtonGroup:0 withButtons:buttons withCount:5];
2102 [buttonbar_ showButtonGroup:0 withDuration:0];
2103
2104 for (int i = 0; i != 5; ++i)
2105 [[buttonbar_ viewWithTag:(i + 1)] setFrame:CGRectMake(
2106 i * 64 + 2, 1, 60, 48
2107 )];
2108
2109 [buttonbar_ showSelectionForButton:1];
2110 [transition_ transition:0 toView:featured_];
2111
2112 [overlay_ addSubview:buttonbar_];
2113
2114 database_ = [[Database alloc] init];
2115 [database_ setDelegate:progress_];
2116
2117 install_ = [[InstallView alloc] initWithFrame:[transition_ bounds] database:database_];
2118 [install_ setDelegate:self];
2119
2120 upgrade_ = [[UpgradeView alloc] initWithFrame:[transition_ bounds] database:database_];
2121 [upgrade_ setDelegate:self];
2122
2123 uninstall_ = [[UninstallView alloc] initWithFrame:[transition_ bounds] database:database_];
2124 [uninstall_ setDelegate:self];
2125
2126 sources_ = [[SourcesView alloc] initWithFrame:[transition_ bounds] database:database_];
2127 [sources_ setDelegate:self];
2128
2129 #if 0
2130
2131 UIAlertSheet *alert = [[UIAlertSheet alloc]
2132 initWithTitle:@"Alert Title"
2133 buttons:[NSArray arrayWithObjects:@"Yes", nil]
2134 defaultButtonIndex:0
2135 delegate:self
2136 context:self
2137 ];
2138
2139 NSLog(@"%p\n", [alert table]);
2140 [[alert table] setDelegate:self];
2141 [[alert table] reloadData];
2142
2143 [alert addTextFieldWithValue:@"Title" label:@"Label"];
2144 [alert setShowsOverSpringBoardAlerts:YES];
2145 [alert setBodyText:@"This is an alert."];
2146 [alert presentSheetFromButtonBar:buttonbar_];
2147 //[alert popupAlertAnimated:YES];
2148
2149 #endif
2150
2151 [self reloadData];
2152 [progress_ resetView];
2153
2154 Package *package([database_ packageWithName:@"cydia"]);
2155 NSString *application = package == nil ? @"Cydia" : [NSString stringWithFormat:@"Cydia/%@", [package installed]];
2156 WebView *webview = [webview_ webView];
2157 [webview setApplicationNameForUserAgent:application];
2158
2159 url_ = [NSURL URLWithString:@"http://cydia.saurik.com/"];
2160 [self loadNews];
2161 }
2162
2163 @end
2164
2165 int main(int argc, char *argv[]) {
2166 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
2167
2168 size_t size;
2169 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
2170 char *machine = new char[size];
2171 sysctlbyname("hw.machine", machine, &size, NULL, 0);
2172 Machine_ = machine;
2173
2174 if (CFMutableDictionaryRef dict = IOServiceMatching("IOPlatformExpertDevice"))
2175 if (io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, dict)) {
2176 if (CFTypeRef serial = IORegistryEntryCreateCFProperty(service, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0)) {
2177 SerialNumber_ = strdup(CFStringGetCStringPtr((CFStringRef) serial, CFStringGetSystemEncoding()));
2178 CFRelease(serial);
2179 }
2180
2181 IOObjectRelease(service);
2182 }
2183
2184 UIApplicationMain(argc, argv, [Cydia class]);
2185 [pool release];
2186 }