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