]> git.saurik.com Git - cydia.git/blob - Cydia.mm
Added nifty graphics and Source support.
[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 #include <notify.h>
23
24 extern "C" {
25 #include <mach-o/nlist.h>
26 }
27
28 #include <objc/objc-class.h>
29
30 #include <errno.h>
31 #include <pcre.h>
32 #include <string.h>
33 /* }}} */
34 /* Extension Keywords {{{ */
35 #define _trace() fprintf(stderr, "_trace()@%s:%u[%s]\n", __FILE__, __LINE__, __FUNCTION__)
36
37 #define _assert(test) do \
38 if (!(test)) { \
39 fprintf(stderr, "_assert(%d:%s)@%s:%u[%s]\n", errno, #test, __FILE__, __LINE__, __FUNCTION__); \
40 exit(-1); \
41 } \
42 while (false)
43
44 #define _not(type) ((type) ~ (type) 0)
45 /* }}} */
46 /* Miscellaneous Messages {{{ */
47 @interface WebView
48 - (void) setApplicationNameForUserAgent:(NSString *)applicationName;
49 - (id) frameLoadDelegate;
50 - (void) setFrameLoadDelegate:(id)delegate;
51 @end
52
53 @interface NSString (Cydia)
54 - (NSString *) stringByAddingPercentEscapes;
55 - (NSString *) stringByReplacingCharacter:(unsigned short)arg0 withCharacter:(unsigned short)arg1;
56 @end
57 /* }}} */
58
59 /* Reset View (UIView) {{{ */
60 @interface UIView (CYResetView)
61 - (void) resetViewAnimated:(BOOL)animated;
62 @end
63
64 @implementation UIView (CYResetView)
65
66 - (void) resetViewAnimated:(BOOL)animated {
67 fprintf(stderr, "%s\n", self->isa->name);
68 _assert(false);
69 }
70
71 @end
72 /* }}} */
73 /* Reset View (UITable) {{{ */
74 @interface UITable (CYResetView)
75 - (void) resetViewAnimated:(BOOL)animated;
76 @end
77
78 @implementation UITable (CYResetView)
79
80 - (void) resetViewAnimated:(BOOL)animated {
81 [self selectRow:-1 byExtendingSelection:NO withFade:animated];
82 }
83
84 @end
85 /* }}} */
86 /* Reset View (UISectionList) {{{ */
87 @interface UISectionList (CYResetView)
88 - (void) resetViewAnimated:(BOOL)animated;
89 @end
90
91 @implementation UISectionList (CYResetView)
92
93 - (void) resetViewAnimated:(BOOL)animated {
94 [[self table] resetViewAnimated:animated];
95 }
96
97 @end
98 /* }}} */
99
100 /* Perl-Compatible RegEx {{{ */
101 class Pcre {
102 private:
103 pcre *code_;
104 pcre_extra *study_;
105 int capture_;
106 int *matches_;
107 const char *data_;
108
109 public:
110 Pcre(const char *regex) :
111 study_(NULL)
112 {
113 const char *error;
114 int offset;
115 code_ = pcre_compile(regex, 0, &error, &offset, NULL);
116
117 if (code_ == NULL) {
118 fprintf(stderr, "%d:%s\n", offset, error);
119 _assert(false);
120 }
121
122 pcre_fullinfo(code_, study_, PCRE_INFO_CAPTURECOUNT, &capture_);
123 matches_ = new int[(capture_ + 1) * 3];
124 }
125
126 ~Pcre() {
127 pcre_free(code_);
128 delete matches_;
129 }
130
131 NSString *operator [](size_t match) {
132 return [NSString
133 stringWithCString:(data_ + matches_[match * 2])
134 length:(matches_[match * 2 + 1] - matches_[match * 2])
135 ];
136 }
137
138 bool operator ()(const char *data, size_t size) {
139 data_ = data;
140 return pcre_exec(code_, study_, data, size, 0, 0, matches_, (capture_ + 1) * 3) >= 0;
141 }
142 };
143 /* }}} */
144 /* CoreGraphicsServices Primitives {{{ */
145 class CGColor {
146 private:
147 CGColorRef color_;
148
149 public:
150 CGColor(CGColorSpaceRef space, float red, float green, float blue, float alpha) {
151 float color[] = {red, green, blue, alpha};
152 color_ = CGColorCreate(space, color);
153 }
154
155 ~CGColor() {
156 CGColorRelease(color_);
157 }
158
159 operator CGColorRef() {
160 return color_;
161 }
162 };
163
164 class GSFont {
165 private:
166 GSFontRef font_;
167
168 public:
169 ~GSFont() {
170 /* XXX: no GSFontRelease()? */
171 CFRelease(font_);
172 }
173 };
174 /* }}} */
175
176 static const int PulseInterval_ = 50000;
177
178 const char *Firmware_ = NULL;
179 const char *Machine_ = NULL;
180 const char *SerialNumber_ = NULL;
181
182 unsigned Major_;
183 unsigned Minor_;
184 unsigned BugFix_;
185
186 #define FW_LEAST(major, minor, bugfix) \
187 (major < Major_ || major == Major_ && \
188 (minor < Minor_ || minor == Minor_ && \
189 bugfix <= BugFix_))
190
191 bool bootstrap_ = false;
192
193 static NSMutableDictionary *Metadata_;
194 static NSMutableDictionary *Packages_;
195 static NSDate *now_;
196
197 NSString *GetLastUpdate() {
198 NSDate *update = [Metadata_ objectForKey:@"LastUpdate"];
199
200 if (update == nil)
201 return @"Never or Unknown";
202
203 CFLocaleRef locale = CFLocaleCopyCurrent();
204 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
205 CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) update);
206
207 CFRelease(formatter);
208 CFRelease(locale);
209
210 return [(NSString *) formatted autorelease];
211 }
212
213 @protocol ProgressDelegate
214 - (void) setError:(NSString *)error;
215 - (void) setTitle:(NSString *)title;
216 - (void) setPercent:(float)percent;
217 - (void) addOutput:(NSString *)output;
218 @end
219
220 NSString *SizeString(double size) {
221 unsigned power = 0;
222 while (size > 1024) {
223 size /= 1024;
224 ++power;
225 }
226
227 static const char *powers_[] = {"B", "kB", "MB", "GB"};
228
229 return [NSString stringWithFormat:@"%.1f%s", size, powers_[power]];
230 }
231
232 static const float TextViewOffset_ = 22;
233
234 UITextView *GetTextView(NSString *value, float left, bool html) {
235 UITextView *text([[[UITextView alloc] initWithFrame:CGRectMake(left, 3, 310 - left, 1000)] autorelease]);
236 [text setEditable:NO];
237 [text setTextSize:16];
238 if (html)
239 [text setHTML:value];
240 else
241 [text setText:value];
242 [text setEnabled:NO];
243
244 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
245 CGColor clear(space, 0, 0, 0, 0);
246 [text setBackgroundColor:clear];
247 CGColorSpaceRelease(space);
248
249 CGRect frame = [text frame];
250 [text setFrame:frame];
251 CGRect rect = [text visibleTextRect];
252 frame.size.height = rect.size.height;
253 [text setFrame:frame];
254
255 return text;
256 }
257
258 /* Status Delegation {{{ */
259 class Status :
260 public pkgAcquireStatus
261 {
262 private:
263 id delegate_;
264
265 public:
266 Status() :
267 delegate_(nil)
268 {
269 }
270
271 void setDelegate(id delegate) {
272 delegate_ = delegate;
273 }
274
275 virtual bool MediaChange(std::string media, std::string drive) {
276 return false;
277 }
278
279 virtual void IMSHit(pkgAcquire::ItemDesc &item) {
280 }
281
282 virtual void Fetch(pkgAcquire::ItemDesc &item) {
283 [delegate_ setTitle:[NSString stringWithCString:("Downloading " + item.ShortDesc).c_str()]];
284 }
285
286 virtual void Done(pkgAcquire::ItemDesc &item) {
287 }
288
289 virtual void Fail(pkgAcquire::ItemDesc &item) {
290 if (
291 item.Owner->Status == pkgAcquire::Item::StatIdle ||
292 item.Owner->Status == pkgAcquire::Item::StatDone
293 )
294 return;
295
296 [delegate_ setError:[NSString stringWithCString:item.Owner->ErrorText.c_str()]];
297 }
298
299 virtual bool Pulse(pkgAcquire *Owner) {
300 bool value = pkgAcquireStatus::Pulse(Owner);
301
302 float percent(
303 double(CurrentBytes + CurrentItems) /
304 double(TotalBytes + TotalItems)
305 );
306
307 [delegate_ setPercent:percent];
308 return value;
309 }
310
311 virtual void Start() {
312 }
313
314 virtual void Stop() {
315 }
316 };
317 /* }}} */
318 /* Progress Delegation {{{ */
319 class Progress :
320 public OpProgress
321 {
322 private:
323 id delegate_;
324
325 protected:
326 virtual void Update() {
327 [delegate_ setTitle:[NSString stringWithCString:Op.c_str()]];
328 [delegate_ setPercent:(Percent / 100)];
329 }
330
331 public:
332 Progress() :
333 delegate_(nil)
334 {
335 }
336
337 void setDelegate(id delegate) {
338 delegate_ = delegate;
339 }
340
341 virtual void Done() {
342 [delegate_ setPercent:1];
343 }
344 };
345 /* }}} */
346
347 /* External Constants {{{ */
348 extern NSString *kUIButtonBarButtonAction;
349 extern NSString *kUIButtonBarButtonInfo;
350 extern NSString *kUIButtonBarButtonInfoOffset;
351 extern NSString *kUIButtonBarButtonSelectedInfo;
352 extern NSString *kUIButtonBarButtonStyle;
353 extern NSString *kUIButtonBarButtonTag;
354 extern NSString *kUIButtonBarButtonTarget;
355 extern NSString *kUIButtonBarButtonTitle;
356 extern NSString *kUIButtonBarButtonTitleVerticalHeight;
357 extern NSString *kUIButtonBarButtonTitleWidth;
358 extern NSString *kUIButtonBarButtonType;
359 /* }}} */
360 /* Mime Addresses {{{ */
361 Pcre email_r("^\"?(.*)\"? <([^>]*)>$");
362
363 @interface Address : NSObject {
364 NSString *name_;
365 NSString *email_;
366 }
367
368 - (void) dealloc;
369
370 - (NSString *) name;
371 - (NSString *) email;
372
373 + (Address *) addressWithString:(NSString *)string;
374 - (Address *) initWithString:(NSString *)string;
375 @end
376
377 @implementation Address
378
379 - (void) dealloc {
380 [name_ release];
381 if (email_ != nil)
382 [email_ release];
383 [super dealloc];
384 }
385
386 - (NSString *) name {
387 return name_;
388 }
389
390 - (NSString *) email {
391 return email_;
392 }
393
394 + (Address *) addressWithString:(NSString *)string {
395 return [[[Address alloc] initWithString:string] autorelease];
396 }
397
398 - (Address *) initWithString:(NSString *)string {
399 if ((self = [super init]) != nil) {
400 const char *data = [string UTF8String];
401 size_t size = [string length];
402
403 if (email_r(data, size)) {
404 name_ = [email_r[1] retain];
405 email_ = [email_r[2] retain];
406 } else {
407 name_ = [[NSString stringWithCString:data length:size] retain];
408 email_ = nil;
409 }
410 } return self;
411 }
412
413 @end
414 /* }}} */
415
416 /* Right Alignment {{{ */
417 @interface UIRightTextLabel : UITextLabel {
418 float _savedRightEdgeX;
419 BOOL _sizedtofit_flag;
420 }
421
422 - (void) setFrame:(CGRect)frame;
423 - (void) setText:(NSString *)text;
424 - (void) realignText;
425 @end
426
427 @implementation UIRightTextLabel
428
429 - (void) setFrame:(CGRect)frame {
430 [super setFrame:frame];
431 if (_sizedtofit_flag == NO) {
432 _savedRightEdgeX = frame.origin.x;
433 [self realignText];
434 }
435 }
436
437 - (void) setText:(NSString *)text {
438 [super setText:text];
439 [self realignText];
440 }
441
442 - (void) realignText {
443 CGRect oldFrame = [self frame];
444
445 _sizedtofit_flag = YES;
446 [self sizeToFit]; // shrink down size so I can right align it
447
448 CGRect newFrame = [self frame];
449
450 oldFrame.origin.x = _savedRightEdgeX - newFrame.size.width;
451 oldFrame.size.width = newFrame.size.width;
452 [super setFrame:oldFrame];
453 _sizedtofit_flag = NO;
454 }
455
456 @end
457 /* }}} */
458 /* Linear Algebra {{{ */
459 inline float interpolate(float begin, float end, float fraction) {
460 return (end - begin) * fraction + begin;
461 }
462 /* }}} */
463
464 @class Package;
465 @class Source;
466
467 /* Database Interface {{{ */
468 @interface Database : NSObject {
469 pkgCacheFile cache_;
470 pkgRecords *records_;
471 pkgProblemResolver *resolver_;
472 pkgAcquire *fetcher_;
473 FileFd *lock_;
474 SPtr<pkgPackageManager> manager_;
475 pkgSourceList *list_;
476
477 NSMutableDictionary *sources_;
478
479 id delegate_;
480 Status status_;
481 Progress progress_;
482 int statusfd_;
483 }
484
485 - (void) dealloc;
486
487 - (void) _readStatus:(NSNumber *)fd;
488 - (void) _readOutput:(NSNumber *)fd;
489
490 - (Package *) packageWithName:(NSString *)name;
491
492 - (Database *) init;
493 - (pkgCacheFile &) cache;
494 - (pkgRecords *) records;
495 - (pkgProblemResolver *) resolver;
496 - (pkgAcquire &) fetcher;
497 - (void) reloadData;
498
499 - (void) prepare;
500 - (void) perform;
501 - (void) update;
502 - (void) upgrade;
503
504 - (void) setDelegate:(id)delegate;
505 - (Source *) getSource:(const pkgCache::PkgFileIterator &)file;
506 @end
507 /* }}} */
508
509 /* Reset View {{{ */
510 @interface ResetView : UIView {
511 UIPushButton *configure_;
512 UIPushButton *reload_;
513 NSMutableArray *views_;
514 UINavigationBar *navbar_;
515 UITransitionView *transition_;
516 bool resetting_;
517 id delegate_;
518 }
519
520 - (void) dealloc;
521
522 - (void) navigationBar:(UINavigationBar *)navbar poppedItem:(UINavigationItem *)item;
523 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
524
525 - (id) initWithFrame:(CGRect)frame;
526 - (void) setDelegate:(id)delegate;
527
528 - (void) configurePushed;
529 - (void) reloadPushed;
530
531 - (void) pushView:(UIView *)view withTitle:(NSString *)title backButtonTitle:(NSString *)back rightButton:(NSString *)right;
532 - (void) popViews:(unsigned)views;
533 - (void) resetView:(BOOL)clear;
534 - (void) _resetView;
535 - (void) setPrompt;
536 @end
537
538 @implementation ResetView
539
540 - (void) dealloc {
541 [configure_ release];
542 [reload_ release];
543 [transition_ release];
544 [navbar_ release];
545 [views_ release];
546 [super dealloc];
547 }
548
549 - (void) navigationBar:(UINavigationBar *)navbar poppedItem:(UINavigationItem *)item {
550 [views_ removeLastObject];
551 UIView *view([views_ lastObject]);
552 [view resetViewAnimated:!resetting_];
553
554 if (!resetting_) {
555 [transition_ transition:2 toView:view];
556 [self _resetView];
557 }
558 }
559
560 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
561 [sheet dismiss];
562 }
563
564 - (id) initWithFrame:(CGRect)frame {
565 if ((self = [super initWithFrame:frame]) != nil) {
566 views_ = [[NSMutableArray arrayWithCapacity:4] retain];
567
568 struct CGRect bounds = [self bounds];
569 CGSize navsize = [UINavigationBar defaultSizeWithPrompt];
570 CGRect navrect = {{0, 0}, navsize};
571
572 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
573 [self addSubview:navbar_];
574
575 [navbar_ setBarStyle:1];
576 [navbar_ setDelegate:self];
577
578 transition_ = [[UITransitionView alloc] initWithFrame:CGRectMake(
579 bounds.origin.x, bounds.origin.y + navsize.height, bounds.size.width, bounds.size.height - navsize.height
580 )];
581
582 //configure_ = [[UIPushButton alloc] initWithFrame:CGRectMake(15, 9, 17, 18)];
583 configure_ = [[UIPushButton alloc] initWithFrame:CGRectMake(10, 9, 17, 18)];
584 [configure_ setShowPressFeedback:YES];
585 [configure_ setImage:[UIImage applicationImageNamed:@"configure.png"]];
586 [configure_ addTarget:self action:@selector(configurePushed) forEvents:1];
587
588 //reload_ = [[UIPushButton alloc] initWithFrame:CGRectMake(288, 5, 18, 22)];
589 reload_ = [[UIPushButton alloc] initWithFrame:CGRectMake(293, 5, 18, 22)];
590 [reload_ setShowPressFeedback:YES];
591 [reload_ setImage:[UIImage applicationImageNamed:@"reload.png"]];
592 [reload_ addTarget:self action:@selector(reloadPushed) forEvents:1];
593
594 [navbar_ addSubview:configure_];
595 [navbar_ addSubview:reload_];
596
597 [self addSubview:transition_];
598 } return self;
599 }
600
601 - (void) setDelegate:(id)delegate {
602 delegate_ = delegate;
603 }
604
605 - (void) configurePushed {
606 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
607 initWithTitle:@"Sources Unimplemented"
608 buttons:[NSArray arrayWithObjects:@"Okay", nil]
609 defaultButtonIndex:0
610 delegate:self
611 context:self
612 ] autorelease];
613
614 [sheet setBodyText:@"This feature will be implemented soon. In the mean time, you may add sources by adding .list files to '/etc/apt/sources.list.d' or modifying '/etc/apt/sources.list'."];
615 [sheet popupAlertAnimated:YES];
616 }
617
618 - (void) reloadPushed {
619 [delegate_ update];
620 }
621
622 - (void) pushView:(UIView *)view withTitle:(NSString *)title backButtonTitle:(NSString *)back rightButton:(NSString *)right {
623 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:title] autorelease];
624 [navbar_ pushNavigationItem:navitem];
625 [navitem setBackButtonTitle:back];
626
627 [navbar_ showButtonsWithLeftTitle:nil rightTitle:right];
628
629 [transition_ transition:([views_ count] == 0 ? 0 : 1) toView:view];
630 [views_ addObject:view];
631 }
632
633 - (void) popViews:(unsigned)views {
634 resetting_ = true;
635 for (unsigned i(0); i != views; ++i)
636 [navbar_ popNavigationItem];
637 resetting_ = false;
638
639 [self _resetView];
640 [transition_ transition:2 toView:[views_ lastObject]];
641 }
642
643 - (void) resetView:(BOOL)clear {
644 resetting_ = true;
645
646 if ([views_ count] > 1) {
647 [navbar_ disableAnimation];
648 while ([views_ count] != (clear ? 1 : 2))
649 [navbar_ popNavigationItem];
650 [navbar_ enableAnimation];
651 if (!clear)
652 [navbar_ popNavigationItem];
653 }
654
655 resetting_ = false;
656
657 [self _resetView];
658 [transition_ transition:(clear ? 0 : 2) toView:[views_ lastObject]];
659 }
660
661 - (void) _resetView {
662 [navbar_ showButtonsWithLeftTitle:nil rightTitle:nil];
663 }
664
665 - (void) setPrompt {
666 [navbar_ setPrompt:[NSString stringWithFormat:@"Last Updated: %@", GetLastUpdate()]];
667 }
668
669 @end
670 /* }}} */
671 /* Confirmation View {{{ */
672 void AddTextView(NSMutableDictionary *fields, NSMutableArray *packages, NSString *key) {
673 if ([packages count] == 0)
674 return;
675
676 UITextView *text = GetTextView([packages count] == 0 ? @"n/a" : [packages componentsJoinedByString:@", "], 110, false);
677 [fields setObject:text forKey:key];
678
679 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
680 CGColor blue(space, 0, 0, 0.4, 1);
681 [text setTextColor:blue];
682 CGColorSpaceRelease(space);
683 }
684
685 @protocol ConfirmationViewDelegate
686 - (void) cancel;
687 - (void) confirm;
688 @end
689
690 @interface ConfirmationView : UIView {
691 Database *database_;
692 id delegate_;
693 UITransitionView *transition_;
694 UIView *overlay_;
695 UINavigationBar *navbar_;
696 UIPreferencesTable *table_;
697 NSMutableDictionary *fields_;
698 UIAlertSheet *essential_;
699 }
700
701 - (void) dealloc;
702 - (void) cancel;
703
704 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
705 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
706 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
707
708 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table;
709 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group;
710 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed;
711 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group;
712 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group;
713
714 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate;
715
716 @end
717
718 @implementation ConfirmationView
719
720 - (void) dealloc {
721 [transition_ release];
722 [overlay_ release];
723 [navbar_ release];
724 [table_ release];
725 [fields_ release];
726 if (essential_ != nil)
727 [essential_ release];
728 [super dealloc];
729 }
730
731 - (void) cancel {
732 [transition_ transition:7 toView:nil];
733 [delegate_ cancel];
734 }
735
736 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
737 if (from != nil && to == nil)
738 [self removeFromSuperview];
739 }
740
741 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
742 switch (button) {
743 case 0:
744 if (essential_ != nil)
745 [essential_ popupAlertAnimated:YES];
746 else
747 [delegate_ confirm];
748 break;
749
750 case 1:
751 [self cancel];
752 break;
753 }
754 }
755
756 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
757 [essential_ dismiss];
758 [self cancel];
759 }
760
761 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
762 return 2;
763 }
764
765 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
766 switch (group) {
767 case 0: return @"Statistics";
768 case 1: return @"Modifications";
769
770 default: _assert(false);
771 }
772 }
773
774 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
775 switch (group) {
776 case 0: return 3;
777 case 1: return [fields_ count];
778
779 default: _assert(false);
780 }
781 }
782
783 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
784 if (group != 1 || row == -1)
785 return proposed;
786 else {
787 _assert(size_t(row) < [fields_ count]);
788 return [[[fields_ allValues] objectAtIndex:row] visibleTextRect].size.height + TextViewOffset_;
789 }
790 }
791
792 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
793 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
794 [cell setShowSelection:NO];
795
796 switch (group) {
797 case 0: switch (row) {
798 case 0: {
799 [cell setTitle:@"Downloading"];
800 [cell setValue:SizeString([database_ fetcher].FetchNeeded())];
801 } break;
802
803 case 1: {
804 [cell setTitle:@"Resuming At"];
805 [cell setValue:SizeString([database_ fetcher].PartialPresent())];
806 } break;
807
808 case 2: {
809 double size([database_ cache]->UsrSize());
810
811 if (size < 0) {
812 [cell setTitle:@"Disk Freeing"];
813 [cell setValue:SizeString(-size)];
814 } else {
815 [cell setTitle:@"Disk Using"];
816 [cell setValue:SizeString(size)];
817 }
818 } break;
819
820 default: _assert(false);
821 } break;
822
823 case 1:
824 _assert(size_t(row) < [fields_ count]);
825 [cell setTitle:[[fields_ allKeys] objectAtIndex:row]];
826 [cell addSubview:[[fields_ allValues] objectAtIndex:row]];
827 break;
828
829 default: _assert(false);
830 }
831
832 return cell;
833 }
834
835 - (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate {
836 if ((self = [super initWithFrame:[view bounds]]) != nil) {
837 database_ = database;
838 delegate_ = delegate;
839
840 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
841 [self addSubview:transition_];
842
843 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
844
845 CGSize navsize = [UINavigationBar defaultSize];
846 CGRect navrect = {{0, 0}, navsize};
847 CGRect bounds = [overlay_ bounds];
848
849 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
850 [navbar_ setBarStyle:1];
851 [navbar_ setDelegate:self];
852
853 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Confirm"] autorelease];
854 [navbar_ pushNavigationItem:navitem];
855 [navbar_ showButtonsWithLeftTitle:@"Cancel" rightTitle:@"Confirm"];
856
857 fields_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
858
859 NSMutableArray *installing = [NSMutableArray arrayWithCapacity:16];
860 NSMutableArray *upgrading = [NSMutableArray arrayWithCapacity:16];
861 NSMutableArray *removing = [NSMutableArray arrayWithCapacity:16];
862
863 bool install(false);
864 bool upgrade(false);
865 bool remove(false);
866
867 pkgCacheFile &cache([database_ cache]);
868 for (pkgCache::PkgIterator iterator = cache->PkgBegin(); !iterator.end(); ++iterator) {
869 NSString *name([NSString stringWithCString:iterator.Name()]);
870 bool essential((iterator->Flags & pkgCache::Flag::Essential) != 0);
871
872 if (cache[iterator].NewInstall()) {
873 if (essential)
874 install = true;
875 [installing addObject:name];
876 } else if (cache[iterator].Upgrade()) {
877 if (essential)
878 upgrade = true;
879 [upgrading addObject:name];
880 } else if (cache[iterator].Delete()) {
881 if (essential)
882 remove = true;
883 [removing addObject:name];
884 }
885 }
886
887 if (!remove)
888 essential_ = nil;
889 else {
890 essential_ = [[UIAlertSheet alloc]
891 initWithTitle:@"Unable to Comply"
892 buttons:[NSArray arrayWithObjects:@"Okay", nil]
893 defaultButtonIndex:0
894 delegate:self
895 context:self
896 ];
897
898 [essential_ setBodyText:@"One or more of the packages you are about to remove are marked 'Essential' and cannot be removed by Cydia. Please use apt-get."];
899 }
900
901 AddTextView(fields_, installing, @"Installing");
902 AddTextView(fields_, upgrading, @"Upgrading");
903 AddTextView(fields_, removing, @"Removing");
904
905 table_ = [[UIPreferencesTable alloc] initWithFrame:CGRectMake(
906 0, navsize.height, bounds.size.width, bounds.size.height - navsize.height
907 )];
908
909 [table_ setReusesTableCells:YES];
910 [table_ setDataSource:self];
911 [table_ reloadData];
912
913 [overlay_ addSubview:navbar_];
914 [overlay_ addSubview:table_];
915
916 [view addSubview:self];
917
918 [transition_ setDelegate:self];
919
920 UIView *blank = [[[UIView alloc] initWithFrame:[transition_ bounds]] autorelease];
921 [transition_ transition:0 toView:blank];
922 [transition_ transition:3 toView:overlay_];
923 } return self;
924 }
925
926 @end
927 /* }}} */
928
929 /* Source Class {{{ */
930 @interface Source : NSObject {
931 NSString *description_;
932 NSString *label_;
933 NSString *origin_;
934
935 NSString *uri_;
936 NSString *distribution_;
937 NSString *type_;
938 NSString *version_;
939
940 BOOL trusted_;
941 }
942
943 - (void) dealloc;
944
945 - (Source *) initWithMetaIndex:(metaIndex *)index;
946
947 - (BOOL) trusted;
948
949 - (NSString *) uri;
950 - (NSString *) distribution;
951 - (NSString *) type;
952
953 - (NSString *) description;
954 - (NSString *) label;
955 - (NSString *) origin;
956 - (NSString *) version;
957 @end
958
959 @implementation Source
960
961 - (void) dealloc {
962 [uri_ release];
963 [distribution_ release];
964 [type_ release];
965
966 if (description_ != nil)
967 [description_ release];
968 if (label_ != nil)
969 [label_ release];
970 if (origin_ != nil)
971 [origin_ release];
972 if (version_ != nil)
973 [version_ release];
974
975 [super dealloc];
976 }
977
978 - (Source *) initWithMetaIndex:(metaIndex *)index {
979 if ((self = [super init]) != nil) {
980 trusted_ = index->IsTrusted();
981
982 uri_ = [[NSString stringWithCString:index->GetURI().c_str()] retain];
983 distribution_ = [[NSString stringWithCString:index->GetDist().c_str()] retain];
984 type_ = [[NSString stringWithCString:index->GetType()] retain];
985
986 description_ = nil;
987 label_ = nil;
988 origin_ = nil;
989
990 debReleaseIndex *dindex(dynamic_cast<debReleaseIndex *>(index));
991 if (dindex != NULL) {
992 std::ifstream release(dindex->MetaIndexFile("Release").c_str());
993 std::string line;
994 while (std::getline(release, line)) {
995 std::string::size_type colon(line.find(':'));
996 if (colon == std::string::npos)
997 continue;
998
999 std::string name(line.substr(0, colon));
1000 std::string value(line.substr(colon + 1));
1001 while (!value.empty() && value[0] == ' ')
1002 value = value.substr(1);
1003
1004 if (name == "Description")
1005 description_ = [[NSString stringWithCString:value.c_str()] retain];
1006 else if (name == "Label")
1007 label_ = [[NSString stringWithCString:value.c_str()] retain];
1008 else if (name == "Origin")
1009 origin_ = [[NSString stringWithCString:value.c_str()] retain];
1010 else if (name == "Version")
1011 version_ = [[NSString stringWithCString:value.c_str()] retain];
1012 }
1013 }
1014 } return self;
1015 }
1016
1017 - (BOOL) trusted {
1018 return trusted_;
1019 }
1020
1021 - (NSString *) uri {
1022 return uri_;
1023 }
1024
1025 - (NSString *) distribution {
1026 return distribution_;
1027 }
1028
1029 - (NSString *) type {
1030 return type_;
1031 }
1032
1033 - (NSString *) description {
1034 return description_;
1035 }
1036
1037 - (NSString *) label {
1038 return label_;
1039 }
1040
1041 - (NSString *) origin {
1042 return origin_;
1043 }
1044
1045 - (NSString *) version {
1046 return version_;
1047 }
1048
1049 @end
1050 /* }}} */
1051 /* Package Class {{{ */
1052 NSString *Scour(const char *field, const char *begin, const char *end) {
1053 size_t i(0), l(strlen(field));
1054
1055 for (;;) {
1056 const char *name = begin + i;
1057 const char *colon = name + l;
1058 const char *value = colon + 1;
1059
1060 if (
1061 value < end &&
1062 *colon == ':' &&
1063 memcmp(name, field, l) == 0
1064 ) {
1065 while (value != end && value[0] == ' ')
1066 ++value;
1067 const char *line = std::find(value, end, '\n');
1068 while (line != value && line[-1] == ' ')
1069 --line;
1070 return [NSString stringWithCString:value length:(line - value)];
1071 } else {
1072 begin = std::find(begin, end, '\n');
1073 if (begin == end)
1074 return nil;
1075 ++begin;
1076 }
1077 }
1078 }
1079
1080 @interface Package : NSObject {
1081 pkgCache::PkgIterator iterator_;
1082 Database *database_;
1083 pkgCache::VerIterator version_;
1084 pkgCache::VerFileIterator file_;
1085 Source *source_;
1086
1087 NSString *latest_;
1088 NSString *installed_;
1089
1090 NSString *id_;
1091 NSString *name_;
1092 NSString *tagline_;
1093 NSString *icon_;
1094 NSString *website_;
1095 }
1096
1097 - (void) dealloc;
1098
1099 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database version:(pkgCache::VerIterator)version file:(pkgCache::VerFileIterator)file;
1100 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
1101
1102 - (NSString *) section;
1103 - (Address *) maintainer;
1104 - (size_t) size;
1105 - (NSString *) description;
1106 - (NSString *) index;
1107
1108 - (NSDate *) seen;
1109
1110 - (NSString *) latest;
1111 - (NSString *) installed;
1112 - (BOOL) upgradable;
1113
1114 - (NSString *) id;
1115 - (NSString *) name;
1116 - (NSString *) tagline;
1117 - (NSString *) icon;
1118 - (NSString *) website;
1119
1120 - (Source *) source;
1121
1122 - (BOOL) matches:(NSString *)text;
1123
1124 - (NSComparisonResult) compareByName:(Package *)package;
1125 - (NSComparisonResult) compareBySectionAndName:(Package *)package;
1126 - (NSComparisonResult) compareForChanges:(Package *)package;
1127
1128 - (void) install;
1129 - (void) remove;
1130 @end
1131
1132 @implementation Package
1133
1134 - (void) dealloc {
1135 [latest_ release];
1136 if (installed_ != nil)
1137 [installed_ release];
1138
1139 [id_ release];
1140 if (name_ != nil)
1141 [name_ release];
1142 [tagline_ release];
1143 if (icon_ != nil)
1144 [icon_ release];
1145 if (website_ != nil)
1146 [website_ release];
1147
1148 if (source_ != nil)
1149 [source_ release];
1150
1151 [super dealloc];
1152 }
1153
1154 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database version:(pkgCache::VerIterator)version file:(pkgCache::VerFileIterator)file {
1155 if ((self = [super init]) != nil) {
1156 iterator_ = iterator;
1157 database_ = database;
1158
1159 version_ = version;
1160 file_ = file;
1161
1162 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1163
1164 const char *begin, *end;
1165 parser->GetRec(begin, end);
1166
1167 latest_ = [[NSString stringWithCString:version_.VerStr()] retain];
1168 installed_ = iterator_.CurrentVer().end() ? nil : [[NSString stringWithCString:iterator_.CurrentVer().VerStr()] retain];
1169
1170 id_ = [[[NSString stringWithCString:iterator_.Name()] lowercaseString] retain];
1171 name_ = Scour("Name", begin, end);
1172 if (name_ != nil)
1173 name_ = [name_ retain];
1174 tagline_ = [[NSString stringWithCString:parser->ShortDesc().c_str()] retain];
1175 icon_ = Scour("Icon", begin, end);
1176 if (icon_ != nil)
1177 icon_ = [icon_ retain];
1178 website_ = Scour("Website", begin, end);
1179 if (website_ != nil)
1180 website_ = [website_ retain];
1181
1182 source_ = [[database_ getSource:file_.File()] retain];
1183
1184 NSMutableDictionary *metadata = [Packages_ objectForKey:id_];
1185 if (metadata == nil) {
1186 metadata = [NSMutableDictionary dictionaryWithObjectsAndKeys:
1187 now_, @"FirstSeen",
1188 nil];
1189
1190 [Packages_ setObject:metadata forKey:id_];
1191 }
1192 } return self;
1193 }
1194
1195 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
1196 for (pkgCache::VerIterator version = iterator.VersionList(); !version.end(); ++version)
1197 for (pkgCache::VerFileIterator file = version.FileList(); !file.end(); ++file)
1198 return [[[Package alloc]
1199 initWithIterator:iterator
1200 database:database
1201 version:version
1202 file:file]
1203 autorelease];
1204 return nil;
1205 }
1206
1207 - (NSString *) section {
1208 const char *section = iterator_.Section();
1209 return section == NULL ? nil : [[NSString stringWithCString:section] stringByReplacingCharacter:'_' withCharacter:' '];
1210 }
1211
1212 - (Address *) maintainer {
1213 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1214 return [Address addressWithString:[NSString stringWithCString:parser->Maintainer().c_str()]];
1215 }
1216
1217 - (size_t) size {
1218 return version_->InstalledSize;
1219 }
1220
1221 - (NSString *) description {
1222 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1223 NSString *description([NSString stringWithCString:parser->LongDesc().c_str()]);
1224
1225 NSArray *lines = [description componentsSeparatedByString:@"\n"];
1226 NSMutableArray *trimmed = [NSMutableArray arrayWithCapacity:([lines count] - 1)];
1227 if ([lines count] < 2)
1228 return nil;
1229
1230 NSCharacterSet *whitespace = [NSCharacterSet whitespaceCharacterSet];
1231 for (size_t i(1); i != [lines count]; ++i) {
1232 NSString *trim = [[lines objectAtIndex:i] stringByTrimmingCharactersInSet:whitespace];
1233 [trimmed addObject:trim];
1234 }
1235
1236 return [trimmed componentsJoinedByString:@"\n"];
1237 }
1238
1239 - (NSString *) index {
1240 NSString *index = [[[self name] substringToIndex:1] uppercaseString];
1241 return [index length] != 0 && isalpha([index characterAtIndex:0]) ? index : @"123";
1242 }
1243
1244 - (NSDate *) seen {
1245 return [[Packages_ objectForKey:id_] objectForKey:@"FirstSeen"];
1246 }
1247
1248 - (NSString *) latest {
1249 return latest_;
1250 }
1251
1252 - (NSString *) installed {
1253 return installed_;
1254 }
1255
1256 - (BOOL) upgradable {
1257 NSString *installed = [self installed];
1258 return installed != nil && [[self latest] compare:installed] != NSOrderedSame ? YES : NO;
1259 }
1260
1261 - (NSString *) id {
1262 return id_;
1263 }
1264
1265 - (NSString *) name {
1266 return name_ == nil ? id_ : name_;
1267 }
1268
1269 - (NSString *) tagline {
1270 return tagline_;
1271 }
1272
1273 - (NSString *) icon {
1274 return icon_;
1275 }
1276
1277 - (NSString *) website {
1278 return website_;
1279 }
1280
1281 - (Source *) source {
1282 return source_;
1283 }
1284
1285 - (BOOL) matches:(NSString *)text {
1286 if (text == nil)
1287 return NO;
1288
1289 NSRange range;
1290
1291 range = [[self id] rangeOfString:text options:NSCaseInsensitiveSearch];
1292 if (range.location != NSNotFound)
1293 return YES;
1294
1295 range = [[self name] rangeOfString:text options:NSCaseInsensitiveSearch];
1296 if (range.location != NSNotFound)
1297 return YES;
1298
1299 range = [[self tagline] rangeOfString:text options:NSCaseInsensitiveSearch];
1300 if (range.location != NSNotFound)
1301 return YES;
1302
1303 return NO;
1304 }
1305
1306 - (NSComparisonResult) compareByName:(Package *)package {
1307 NSString *lhs = [self name];
1308 NSString *rhs = [package name];
1309
1310 if ([lhs length] != 0 && [rhs length] != 0) {
1311 unichar lhc = [lhs characterAtIndex:0];
1312 unichar rhc = [rhs characterAtIndex:0];
1313
1314 if (isalpha(lhc) && !isalpha(rhc))
1315 return NSOrderedAscending;
1316 else if (!isalpha(lhc) && isalpha(rhc))
1317 return NSOrderedDescending;
1318 }
1319
1320 return [lhs caseInsensitiveCompare:rhs];
1321 }
1322
1323 - (NSComparisonResult) compareBySectionAndName:(Package *)package {
1324 NSString *lhs = [self section];
1325 NSString *rhs = [package section];
1326
1327 if (lhs == NULL && rhs != NULL)
1328 return NSOrderedAscending;
1329 else if (lhs != NULL && rhs == NULL)
1330 return NSOrderedDescending;
1331 else if (lhs != NULL && rhs != NULL) {
1332 NSComparisonResult result = [lhs compare:rhs];
1333 if (result != NSOrderedSame)
1334 return result;
1335 }
1336
1337 return [self compareByName:package];
1338 }
1339
1340 - (NSComparisonResult) compareForChanges:(Package *)package {
1341 BOOL lhs = [self upgradable];
1342 BOOL rhs = [package upgradable];
1343
1344 if (lhs != rhs)
1345 return lhs ? NSOrderedAscending : NSOrderedDescending;
1346 else if (!lhs) {
1347 switch ([[self seen] compare:[package seen]]) {
1348 case NSOrderedAscending:
1349 return NSOrderedDescending;
1350 case NSOrderedSame:
1351 break;
1352 case NSOrderedDescending:
1353 return NSOrderedAscending;
1354 default:
1355 _assert(false);
1356 }
1357 }
1358
1359 return [self compareByName:package];
1360 }
1361
1362 - (void) install {
1363 pkgProblemResolver *resolver = [database_ resolver];
1364 resolver->Clear(iterator_);
1365 resolver->Protect(iterator_);
1366 [database_ cache]->MarkInstall(iterator_, false);
1367 }
1368
1369 - (void) remove {
1370 pkgProblemResolver *resolver = [database_ resolver];
1371 resolver->Clear(iterator_);
1372 resolver->Protect(iterator_);
1373 resolver->Remove(iterator_);
1374 [database_ cache]->MarkDelete(iterator_, true);
1375 }
1376
1377 @end
1378 /* }}} */
1379 /* Section Class {{{ */
1380 @interface Section : NSObject {
1381 NSString *name_;
1382 size_t row_;
1383 NSMutableArray *packages_;
1384 }
1385
1386 - (void) dealloc;
1387
1388 - (Section *) initWithName:(NSString *)name row:(size_t)row;
1389 - (NSString *) name;
1390 - (size_t) row;
1391 - (NSArray *) packages;
1392 - (size_t) count;
1393 - (void) addPackage:(Package *)package;
1394 @end
1395
1396 @implementation Section
1397
1398 - (void) dealloc {
1399 [name_ release];
1400 [packages_ release];
1401 [super dealloc];
1402 }
1403
1404 - (Section *) initWithName:(NSString *)name row:(size_t)row {
1405 if ((self = [super init]) != nil) {
1406 name_ = [name retain];
1407 row_ = row;
1408 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
1409 } return self;
1410 }
1411
1412 - (NSString *) name {
1413 return name_;
1414 }
1415
1416 - (size_t) row {
1417 return row_;
1418 }
1419
1420 - (NSArray *) packages {
1421 return packages_;
1422 }
1423
1424 - (size_t) count {
1425 return [packages_ count];
1426 }
1427
1428 - (void) addPackage:(Package *)package {
1429 [packages_ addObject:package];
1430 }
1431
1432 @end
1433 /* }}} */
1434
1435 /* Package View {{{ */
1436 @protocol PackageViewDelegate
1437 - (void) performPackage:(Package *)package;
1438 @end
1439
1440 @interface PackageView : UIView {
1441 UIPreferencesTable *table_;
1442 Package *package_;
1443 UITextView *description_;
1444 id delegate_;
1445 }
1446
1447 - (void) dealloc;
1448
1449 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table;
1450 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group;
1451 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed;
1452 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group;
1453 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group;
1454
1455 - (BOOL) canSelectRow:(int)row;
1456 - (void) tableRowSelected:(NSNotification *)notification;
1457
1458 - (Package *) package;
1459
1460 - (id) initWithFrame:(struct CGRect)frame;
1461 - (void) setPackage:(Package *)package;
1462 - (void) setDelegate:(id)delegate;
1463 @end
1464
1465 @implementation PackageView
1466
1467 - (void) dealloc {
1468 if (package_ != nil)
1469 [package_ release];
1470 if (description_ != nil)
1471 [description_ release];
1472 [table_ release];
1473 [super dealloc];
1474 }
1475
1476 - (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
1477 return 3;
1478 }
1479
1480 - (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
1481 switch (group) {
1482 case 0: return nil;
1483 case 1: return @"Package Details";
1484 case 2: return @"Source Information";
1485
1486 default: _assert(false);
1487 }
1488 }
1489
1490 - (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
1491 if (group != 0 || row != 1)
1492 return proposed;
1493 else
1494 return [description_ visibleTextRect].size.height + TextViewOffset_;
1495 }
1496
1497 - (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
1498 switch (group) {
1499 case 0: return [package_ website] == nil ? 2 : 3;
1500 case 1: return 5;
1501 case 2: return 3;
1502
1503 default: _assert(false);
1504 }
1505 }
1506
1507 - (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
1508 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
1509 [cell setShowSelection:NO];
1510
1511 switch (group) {
1512 case 0: switch (row) {
1513 case 0:
1514 [cell setTitle:[package_ name]];
1515 [cell setValue:[package_ latest]];
1516 break;
1517
1518 case 1:
1519 [cell addSubview:description_];
1520 break;
1521
1522 case 2:
1523 [cell setTitle:@"More Information"];
1524 [cell setShowDisclosure:YES];
1525 [cell setShowSelection:YES];
1526 break;
1527
1528 default: _assert(false);
1529 } break;
1530
1531 case 1: switch (row) {
1532 case 0:
1533 [cell setTitle:@"Identifier"];
1534 [cell setValue:[package_ id]];
1535 break;
1536
1537 case 1: {
1538 [cell setTitle:@"Installed Version"];
1539 NSString *installed([package_ installed]);
1540 [cell setValue:(installed == nil ? @"n/a" : installed)];
1541 } break;
1542
1543 case 2: {
1544 [cell setTitle:@"Section"];
1545 NSString *section([package_ section]);
1546 [cell setValue:(section == nil ? @"n/a" : section)];
1547 } break;
1548
1549 case 3:
1550 [cell setTitle:@"Expanded Size"];
1551 [cell setValue:SizeString([package_ size])];
1552 break;
1553
1554 case 4:
1555 [cell setTitle:@"Maintainer"];
1556 [cell setValue:[[package_ maintainer] name]];
1557 [cell setShowDisclosure:YES];
1558 [cell setShowSelection:YES];
1559 break;
1560
1561 default: _assert(false);
1562 } break;
1563
1564 case 2: switch (row) {
1565 case 0:
1566 [cell setTitle:[[package_ source] label]];
1567 [cell setValue:[[package_ source] version]];
1568 break;
1569
1570 case 1:
1571 [cell setValue:[[package_ source] description]];
1572 break;
1573
1574 case 2:
1575 [cell setTitle:@"Origin"];
1576 [cell setValue:[[package_ source] origin]];
1577 break;
1578
1579 default: _assert(false);
1580 } break;
1581
1582 default: _assert(false);
1583 }
1584
1585 return cell;
1586 }
1587
1588 - (BOOL) canSelectRow:(int)row {
1589 return YES;
1590 }
1591
1592 - (void) tableRowSelected:(NSNotification *)notification {
1593 int row = [table_ selectedRow];
1594 NSString *website = [package_ website];
1595
1596 if (row == (website == nil ? 8 : 9))
1597 [delegate_ openURL:[NSURL URLWithString:[NSString stringWithFormat:@"mailto:%@?subject=%@",
1598 [[package_ maintainer] email],
1599 [[NSString stringWithFormat:@"regarding apt package \"%@\"", [package_ name]] stringByAddingPercentEscapes]
1600 ]]];
1601 else if (website != nil && row == 3)
1602 [delegate_ openURL:[NSURL URLWithString:website]];
1603 }
1604
1605 - (Package *) package {
1606 return package_;
1607 }
1608
1609 - (id) initWithFrame:(struct CGRect)frame {
1610 if ((self = [super initWithFrame:frame]) != nil) {
1611 table_ = [[UIPreferencesTable alloc] initWithFrame:[self bounds]];
1612 [self addSubview:table_];
1613
1614 [table_ setDataSource:self];
1615 [table_ setDelegate:self];
1616 } return self;
1617 }
1618
1619 - (void) setPackage:(Package *)package {
1620 if (package_ != nil) {
1621 [package_ autorelease];
1622 package_ = nil;
1623 }
1624
1625 if (description_ != nil) {
1626 [description_ release];
1627 description_ = nil;
1628 }
1629
1630 if (package != nil) {
1631 package_ = [package retain];
1632
1633 NSString *description([package description]);
1634 if (description == nil)
1635 description = [package tagline];
1636 description_ = [GetTextView(description, 12, true) retain];
1637
1638 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1639 CGColor black(space, 0, 0, 0, 1);
1640 [description_ setTextColor:black];
1641 CGColorSpaceRelease(space);
1642
1643 [table_ reloadData];
1644 }
1645 }
1646
1647 - (void) setDelegate:(id)delegate {
1648 delegate_ = delegate;
1649 }
1650
1651 @end
1652 /* }}} */
1653 /* Package Cell {{{ */
1654 @interface PackageCell : UITableCell {
1655 UIImageView *icon_;
1656 UITextLabel *name_;
1657 UITextLabel *description_;
1658 UITextLabel *source_;
1659 UITextLabel *version_;
1660 UIImageView *trusted_;
1661 SEL versioner_;
1662 }
1663
1664 - (void) dealloc;
1665
1666 - (PackageCell *) initWithVersioner:(SEL)versioner;
1667 - (void) setPackage:(Package *)package;
1668
1669 - (void) _setSelected:(float)fraction;
1670 - (void) setSelected:(BOOL)selected;
1671 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
1672 - (void) _setSelectionFadeFraction:(float)fraction;
1673
1674 @end
1675
1676 @implementation PackageCell
1677
1678 - (void) dealloc {
1679 [icon_ release];
1680 [name_ release];
1681 [description_ release];
1682 [source_ release];
1683 [version_ release];
1684 [trusted_ release];
1685 [super dealloc];
1686 }
1687
1688 - (PackageCell *) initWithVersioner:(SEL)versioner {
1689 if ((self = [super init]) != nil) {
1690 versioner_ = versioner;
1691
1692 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22);
1693 GSFontRef large = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
1694 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 14);
1695
1696 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1697
1698 CGColor clear(space, 0, 0, 0, 0);
1699
1700 icon_ = [[UIImageView alloc] initWithFrame:CGRectMake(10, 10, 30, 30)];
1701
1702 name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 12, 240, 25)];
1703 [name_ setBackgroundColor:clear];
1704 [name_ setFont:bold];
1705
1706 description_ = [[UITextLabel alloc] initWithFrame:CGRectMake(12, 46, 280, 20)];
1707 [description_ setBackgroundColor:clear];
1708 [description_ setFont:small];
1709
1710 source_ = [[UITextLabel alloc] initWithFrame:CGRectMake(12, 72, 150, 20)];
1711 [source_ setBackgroundColor:clear];
1712 [source_ setFont:large];
1713
1714 version_ = [[UIRightTextLabel alloc] initWithFrame:CGRectMake(286, 69, 70, 25)];
1715 [version_ setBackgroundColor:clear];
1716 [version_ setFont:large];
1717
1718 //trusted_ = [[UIImageView alloc] initWithFrame:CGRectMake(278, 7, 16, 16)];
1719 trusted_ = [[UIImageView alloc] initWithFrame:CGRectMake(30, 30, 16, 16)];
1720 [trusted_ setImage:[UIImage applicationImageNamed:@"trusted.png"]];
1721
1722 [self addSubview:icon_];
1723 [self addSubview:name_];
1724 [self addSubview:description_];
1725 [self addSubview:source_];
1726 [self addSubview:version_];
1727
1728 CGColorSpaceRelease(space);
1729
1730 CFRelease(small);
1731 CFRelease(large);
1732 CFRelease(bold);
1733 } return self;
1734 }
1735
1736 - (void) setPackage:(Package *)package {
1737 UIImage *image = nil;
1738 if (NSString *icon = [package icon])
1739 image = [UIImage imageAtPath:[icon substringFromIndex:6]];
1740 if (image == nil)
1741 image = [UIImage applicationImageNamed:@"unknown.png"];
1742
1743 [icon_ setImage:image];
1744 [icon_ zoomToScale:0.5f];
1745 [icon_ setFrame:CGRectMake(10, 10, 30, 30)];
1746
1747 [name_ setText:[package name]];
1748 [version_ setText:[package latest]];
1749 [description_ setText:[package tagline]];
1750
1751 Source *source = [package source];
1752 NSString *label;
1753 bool trusted;
1754
1755 if (source == nil) {
1756 label = @"Apple";
1757 trusted = false;
1758 } else {
1759 label = [source label];
1760 trusted = [source trusted];
1761 }
1762
1763 [source_ setText:[NSString stringWithFormat:@"from %@", label]];
1764
1765 [trusted_ removeFromSuperview];
1766 if (trusted)
1767 [self addSubview:trusted_];
1768 }
1769
1770 - (void) _setSelected:(float)fraction {
1771 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
1772
1773 CGColor black(space,
1774 interpolate(0.0, 1.0, fraction),
1775 interpolate(0.0, 1.0, fraction),
1776 interpolate(0.0, 1.0, fraction),
1777 1.0);
1778
1779 CGColor blue(space,
1780 interpolate(0.2, 1.0, fraction),
1781 interpolate(0.2, 1.0, fraction),
1782 interpolate(1.0, 1.0, fraction),
1783 1.0);
1784
1785 CGColor gray(space,
1786 interpolate(0.4, 1.0, fraction),
1787 interpolate(0.4, 1.0, fraction),
1788 interpolate(0.4, 1.0, fraction),
1789 1.0);
1790
1791 [name_ setColor:black];
1792 [description_ setColor:gray];
1793 [source_ setColor:black];
1794 [version_ setColor:blue];
1795
1796 CGColorSpaceRelease(space);
1797 }
1798
1799 - (void) setSelected:(BOOL)selected {
1800 [self _setSelected:(selected ? 1.0 : 0.0)];
1801 [super setSelected:selected];
1802 }
1803
1804 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
1805 if (!fade)
1806 [self _setSelected:(selected ? 1.0 : 0.0)];
1807 [super setSelected:selected withFade:fade];
1808 }
1809
1810 - (void) _setSelectionFadeFraction:(float)fraction {
1811 [self _setSelected:fraction];
1812 [super _setSelectionFadeFraction:fraction];
1813 }
1814
1815 @end
1816 /* }}} */
1817
1818 /* Database Implementation {{{ */
1819 @implementation Database
1820
1821 - (void) dealloc {
1822 _assert(false);
1823 [super dealloc];
1824 }
1825
1826 - (void) _readStatus:(NSNumber *)fd {
1827 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1828
1829 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1830 std::istream is(&ib);
1831 std::string line;
1832
1833 const char *error;
1834 int offset;
1835 pcre *code = pcre_compile("^([^:]*):([^:]*):([^:]*):(.*)$", 0, &error, &offset, NULL);
1836
1837 pcre_extra *study = NULL;
1838 int capture;
1839 pcre_fullinfo(code, study, PCRE_INFO_CAPTURECOUNT, &capture);
1840 int matches[(capture + 1) * 3];
1841
1842 while (std::getline(is, line)) {
1843 const char *data(line.c_str());
1844
1845 _assert(pcre_exec(code, study, data, line.size(), 0, 0, matches, sizeof(matches) / sizeof(matches[0])) >= 0);
1846
1847 std::istringstream buffer(line.substr(matches[6], matches[7] - matches[6]));
1848 float percent;
1849 buffer >> percent;
1850 [delegate_ setPercent:(percent / 100)];
1851
1852 NSString *string = [NSString stringWithCString:(data + matches[8]) length:(matches[9] - matches[8])];
1853 std::string type(line.substr(matches[2], matches[3] - matches[2]));
1854
1855 if (type == "pmerror")
1856 [delegate_ setError:string];
1857 else if (type == "pmstatus")
1858 [delegate_ setTitle:string];
1859 else if (type == "pmconffile")
1860 ;
1861 else _assert(false);
1862 }
1863
1864 [pool release];
1865 _assert(false);
1866 }
1867
1868 - (void) _readOutput:(NSNumber *)fd {
1869 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1870
1871 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1872 std::istream is(&ib);
1873 std::string line;
1874
1875 while (std::getline(is, line))
1876 [delegate_ addOutput:[NSString stringWithCString:line.c_str()]];
1877
1878 [pool release];
1879 _assert(false);
1880 }
1881
1882 - (Package *) packageWithName:(NSString *)name {
1883 pkgCache::PkgIterator iterator(cache_->FindPkg([name cString]));
1884 return iterator.end() ? nil : [Package packageWithIterator:iterator database:self];
1885 }
1886
1887 - (Database *) init {
1888 if ((self = [super init]) != nil) {
1889 records_ = NULL;
1890 resolver_ = NULL;
1891 fetcher_ = NULL;
1892 lock_ = NULL;
1893
1894 sources_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1895
1896 int fds[2];
1897
1898 _assert(pipe(fds) != -1);
1899 statusfd_ = fds[1];
1900
1901 [NSThread
1902 detachNewThreadSelector:@selector(_readStatus:)
1903 toTarget:self
1904 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1905 ];
1906
1907 _assert(pipe(fds) != -1);
1908 _assert(dup2(fds[1], 1) != -1);
1909 _assert(close(fds[1]) != -1);
1910
1911 [NSThread
1912 detachNewThreadSelector:@selector(_readOutput:)
1913 toTarget:self
1914 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1915 ];
1916 } return self;
1917 }
1918
1919 - (pkgCacheFile &) cache {
1920 return cache_;
1921 }
1922
1923 - (pkgRecords *) records {
1924 return records_;
1925 }
1926
1927 - (pkgProblemResolver *) resolver {
1928 return resolver_;
1929 }
1930
1931 - (pkgAcquire &) fetcher {
1932 return *fetcher_;
1933 }
1934
1935 - (void) reloadData {
1936 _error->Discard();
1937 delete list_;
1938 manager_ = NULL;
1939 delete lock_;
1940 delete fetcher_;
1941 delete resolver_;
1942 delete records_;
1943 cache_.Close();
1944
1945 if (!cache_.Open(progress_, true)) {
1946 fprintf(stderr, "repairing corrupted database...\n");
1947 _error->Discard();
1948 [self update];
1949 _assert(cache_.Open(progress_, true));
1950 }
1951
1952 records_ = new pkgRecords(cache_);
1953 resolver_ = new pkgProblemResolver(cache_);
1954 fetcher_ = new pkgAcquire(&status_);
1955 lock_ = NULL;
1956
1957 list_ = new pkgSourceList();
1958 _assert(list_->ReadMainList());
1959
1960 [sources_ removeAllObjects];
1961 for (pkgSourceList::const_iterator source = list_->begin(); source != list_->end(); ++source) {
1962 std::vector<pkgIndexFile *> *indices = (*source)->GetIndexFiles();
1963 for (std::vector<pkgIndexFile *>::const_iterator index = indices->begin(); index != indices->end(); ++index)
1964 [sources_
1965 setObject:[[[Source alloc] initWithMetaIndex:*source] autorelease]
1966 forKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(*index)]
1967 ];
1968 }
1969 }
1970
1971 - (void) prepare {
1972 pkgRecords records(cache_);
1973
1974 lock_ = new FileFd();
1975 lock_->Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1976 _assert(!_error->PendingError());
1977
1978 pkgSourceList list;
1979 _assert(list.ReadMainList());
1980
1981 manager_ = (_system->CreatePM(cache_));
1982 _assert(manager_->GetArchives(fetcher_, &list, &records));
1983 _assert(!_error->PendingError());
1984 }
1985
1986 - (void) perform {
1987 if (fetcher_->Run(PulseInterval_) != pkgAcquire::Continue)
1988 return;
1989
1990 _system->UnLock();
1991 pkgPackageManager::OrderResult result = manager_->DoInstall(statusfd_);
1992
1993 if (result == pkgPackageManager::Failed)
1994 return;
1995 if (_error->PendingError())
1996 return;
1997 if (result != pkgPackageManager::Completed)
1998 return;
1999 }
2000
2001 - (void) update {
2002 pkgSourceList list;
2003 _assert(list.ReadMainList());
2004
2005 FileFd lock;
2006 lock.Fd(GetLock(_config->FindDir("Dir::State::Lists") + "lock"));
2007 _assert(!_error->PendingError());
2008
2009 pkgAcquire fetcher(&status_);
2010 _assert(list.GetIndexes(&fetcher));
2011 _assert(fetcher.Run(PulseInterval_) != pkgAcquire::Failed);
2012
2013 bool failed = false;
2014 for (pkgAcquire::ItemIterator item = fetcher.ItemsBegin(); item != fetcher.ItemsEnd(); item++)
2015 if ((*item)->Status != pkgAcquire::Item::StatDone) {
2016 (*item)->Finished();
2017 failed = true;
2018 }
2019
2020 if (!failed && _config->FindB("APT::Get::List-Cleanup", true) == true) {
2021 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists")));
2022 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/"));
2023 }
2024
2025 [Metadata_ setObject:[NSDate date] forKey:@"LastUpdate"];
2026 }
2027
2028 - (void) upgrade {
2029 _assert(cache_->DelCount() == 0 && cache_->InstCount() == 0);
2030 _assert(pkgApplyStatus(cache_));
2031
2032 if (cache_->BrokenCount() != 0) {
2033 _assert(pkgFixBroken(cache_));
2034 _assert(cache_->BrokenCount() == 0);
2035 _assert(pkgMinimizeUpgrade(cache_));
2036 }
2037
2038 _assert(pkgDistUpgrade(cache_));
2039 }
2040
2041 - (void) setDelegate:(id)delegate {
2042 delegate_ = delegate;
2043 status_.setDelegate(delegate);
2044 progress_.setDelegate(delegate);
2045 }
2046
2047 - (Source *) getSource:(const pkgCache::PkgFileIterator &)file {
2048 pkgIndexFile *index(NULL);
2049 list_->FindIndex(file, index);
2050 return [sources_ objectForKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(index)]];
2051 }
2052
2053 @end
2054 /* }}} */
2055
2056 /* Progress Data {{{ */
2057 @interface ProgressData : NSObject {
2058 SEL selector_;
2059 id target_;
2060 id object_;
2061 }
2062
2063 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object;
2064
2065 - (SEL) selector;
2066 - (id) target;
2067 - (id) object;
2068 @end
2069
2070 @implementation ProgressData
2071
2072 - (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object {
2073 if ((self = [super init]) != nil) {
2074 selector_ = selector;
2075 target_ = target;
2076 object_ = object;
2077 } return self;
2078 }
2079
2080 - (SEL) selector {
2081 return selector_;
2082 }
2083
2084 - (id) target {
2085 return target_;
2086 }
2087
2088 - (id) object {
2089 return object_;
2090 }
2091
2092 @end
2093 /* }}} */
2094 /* Progress View {{{ */
2095 @interface ProgressView : UIView <
2096 ProgressDelegate
2097 > {
2098 UIView *view_;
2099 UIView *background_;
2100 UITransitionView *transition_;
2101 UIView *overlay_;
2102 UINavigationBar *navbar_;
2103 UIProgressBar *progress_;
2104 UITextView *output_;
2105 UITextLabel *status_;
2106 id delegate_;
2107 }
2108
2109 - (void) dealloc;
2110
2111 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
2112
2113 - (ProgressView *) initWithFrame:(struct CGRect)frame delegate:(id)delegate;
2114 - (void) setContentView:(UIView *)view;
2115 - (void) resetView;
2116
2117 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
2118
2119 - (void) _retachThread;
2120 - (void) _detachNewThreadData:(ProgressData *)data;
2121 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title;
2122
2123 - (void) setError:(NSString *)error;
2124 - (void) _setError:(NSString *)error;
2125
2126 - (void) setTitle:(NSString *)title;
2127 - (void) _setTitle:(NSString *)title;
2128
2129 - (void) setPercent:(float)percent;
2130 - (void) _setPercent:(NSNumber *)percent;
2131
2132 - (void) addOutput:(NSString *)output;
2133 - (void) _addOutput:(NSString *)output;
2134 @end
2135
2136 @protocol ProgressViewDelegate
2137 - (void) progressViewIsComplete:(ProgressView *)sender;
2138 @end
2139
2140 @implementation ProgressView
2141
2142 - (void) dealloc {
2143 [view_ release];
2144 if (background_ != nil)
2145 [background_ release];
2146 [transition_ release];
2147 [overlay_ release];
2148 [navbar_ release];
2149 [progress_ release];
2150 [output_ release];
2151 [status_ release];
2152 [super dealloc];
2153 }
2154
2155 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
2156 if (bootstrap_ && from == overlay_ && to == view_)
2157 exit(0);
2158 }
2159
2160 - (ProgressView *) initWithFrame:(struct CGRect)frame delegate:(id)delegate {
2161 if ((self = [super initWithFrame:frame]) != nil) {
2162 delegate_ = delegate;
2163
2164 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
2165
2166 CGColor black(space, 0.0, 0.0, 0.0, 1.0);
2167 CGColor white(space, 1.0, 1.0, 1.0, 1.0);
2168 CGColor clear(space, 0.0, 0.0, 0.0, 0.0);
2169
2170 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
2171 [transition_ setDelegate:self];
2172
2173 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
2174
2175 if (bootstrap_)
2176 [overlay_ setBackgroundColor:black];
2177 else {
2178 background_ = [[UIView alloc] initWithFrame:[self bounds]];
2179 [background_ setBackgroundColor:black];
2180 [self addSubview:background_];
2181 }
2182
2183 [self addSubview:transition_];
2184
2185 CGSize navsize = [UINavigationBar defaultSize];
2186 CGRect navrect = {{0, 0}, navsize};
2187
2188 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
2189 [overlay_ addSubview:navbar_];
2190
2191 [navbar_ setBarStyle:1];
2192 [navbar_ setDelegate:self];
2193
2194 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:nil] autorelease];
2195 [navbar_ pushNavigationItem:navitem];
2196
2197 CGRect bounds = [overlay_ bounds];
2198 CGSize prgsize = [UIProgressBar defaultSize];
2199
2200 CGRect prgrect = {{
2201 (bounds.size.width - prgsize.width) / 2,
2202 bounds.size.height - prgsize.height - 20
2203 }, prgsize};
2204
2205 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
2206 [overlay_ addSubview:progress_];
2207
2208 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(
2209 10,
2210 bounds.size.height - prgsize.height - 50,
2211 bounds.size.width - 20,
2212 24
2213 )];
2214
2215 [status_ setColor:white];
2216 [status_ setBackgroundColor:clear];
2217
2218 [status_ setCentersHorizontally:YES];
2219 //[status_ setFont:font];
2220
2221 output_ = [[UITextView alloc] initWithFrame:CGRectMake(
2222 10,
2223 navrect.size.height + 20,
2224 bounds.size.width - 20,
2225 bounds.size.height - navsize.height - 62 - navrect.size.height
2226 )];
2227
2228 //[output_ setTextFont:@"Courier New"];
2229 [output_ setTextSize:12];
2230
2231 [output_ setTextColor:white];
2232 [output_ setBackgroundColor:clear];
2233
2234 [output_ setMarginTop:0];
2235 [output_ setAllowsRubberBanding:YES];
2236
2237 [overlay_ addSubview:output_];
2238 [overlay_ addSubview:status_];
2239
2240 [progress_ setStyle:0];
2241
2242 CGColorSpaceRelease(space);
2243 } return self;
2244 }
2245
2246 - (void) setContentView:(UIView *)view {
2247 view_ = [view retain];
2248 }
2249
2250 - (void) resetView {
2251 [transition_ transition:6 toView:view_];
2252 }
2253
2254 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
2255 [sheet dismiss];
2256 }
2257
2258 - (void) _retachThread {
2259 [delegate_ progressViewIsComplete:self];
2260 [self resetView];
2261 }
2262
2263 - (void) _detachNewThreadData:(ProgressData *)data {
2264 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
2265
2266 [[data target] performSelector:[data selector] withObject:[data object]];
2267 [data release];
2268
2269 [self performSelectorOnMainThread:@selector(_retachThread) withObject:nil waitUntilDone:YES];
2270
2271 [pool release];
2272 }
2273
2274 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title {
2275 [navbar_ popNavigationItem];
2276 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:title] autorelease];
2277 [navbar_ pushNavigationItem:navitem];
2278
2279 [status_ setText:nil];
2280 [output_ setText:@""];
2281 [progress_ setProgress:0];
2282
2283 [transition_ transition:6 toView:overlay_];
2284
2285 [NSThread
2286 detachNewThreadSelector:@selector(_detachNewThreadData:)
2287 toTarget:self
2288 withObject:[[ProgressData alloc]
2289 initWithSelector:selector
2290 target:target
2291 object:object
2292 ]
2293 ];
2294 }
2295
2296 - (void) setError:(NSString *)error {
2297 [self
2298 performSelectorOnMainThread:@selector(_setError:)
2299 withObject:error
2300 waitUntilDone:YES
2301 ];
2302 }
2303
2304 - (void) _setError:(NSString *)error {
2305 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
2306 initWithTitle:@"Package Error"
2307 buttons:[NSArray arrayWithObjects:@"Okay", nil]
2308 defaultButtonIndex:0
2309 delegate:self
2310 context:self
2311 ] autorelease];
2312
2313 [sheet setBodyText:error];
2314 [sheet popupAlertAnimated:YES];
2315 }
2316
2317 - (void) setTitle:(NSString *)title {
2318 [self
2319 performSelectorOnMainThread:@selector(_setTitle:)
2320 withObject:title
2321 waitUntilDone:YES
2322 ];
2323 }
2324
2325 - (void) _setTitle:(NSString *)title {
2326 [status_ setText:[title stringByAppendingString:@"..."]];
2327 }
2328
2329 - (void) setPercent:(float)percent {
2330 [self
2331 performSelectorOnMainThread:@selector(_setPercent:)
2332 withObject:[NSNumber numberWithFloat:percent]
2333 waitUntilDone:YES
2334 ];
2335 }
2336
2337 - (void) _setPercent:(NSNumber *)percent {
2338 [progress_ setProgress:[percent floatValue]];
2339 }
2340
2341 - (void) addOutput:(NSString *)output {
2342 [self
2343 performSelectorOnMainThread:@selector(_addOutput:)
2344 withObject:output
2345 waitUntilDone:YES
2346 ];
2347 }
2348
2349 - (void) _addOutput:(NSString *)output {
2350 [output_ setText:[NSString stringWithFormat:@"%@\n%@", [output_ text], output]];
2351 CGSize size = [output_ contentSize];
2352 CGRect rect = {{0, size.height}, {size.width, 0}};
2353 [output_ scrollRectToVisible:rect animated:YES];
2354 }
2355
2356 @end
2357 /* }}} */
2358
2359 /* Package Table {{{ */
2360 @protocol PackageTableDelegate
2361 - (void) packageTable:(id)table packageSelected:(Package *)package;
2362 @end
2363
2364 @interface PackageTable : UIView {
2365 SEL versioner_;
2366 UISectionList *list_;
2367
2368 id delegate_;
2369 NSArray *packages_;
2370 NSMutableArray *sections_;
2371 }
2372
2373 - (void) dealloc;
2374
2375 - (int) numberOfSectionsInSectionList:(UISectionList *)list;
2376 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section;
2377 - (int) sectionList:(UISectionList *)list rowForSection:(int)section;
2378
2379 - (int) numberOfRowsInTable:(UITable *)table;
2380 - (float) table:(UITable *)table heightForRow:(int)row;
2381 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing;
2382 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row;
2383 - (void) tableRowSelected:(NSNotification *)notification;
2384
2385 - (id) initWithFrame:(CGRect)frame versioner:(SEL)versioner;
2386
2387 - (void) setDelegate:(id)delegate;
2388 - (void) setPackages:(NSArray *)packages;
2389
2390 - (void) resetViewAnimated:(BOOL)animated;
2391 - (UITable *) table;
2392 @end
2393
2394 @implementation PackageTable
2395
2396 - (void) dealloc {
2397 [list_ release];
2398 [sections_ release];
2399 if (packages_ != nil)
2400 [packages_ release];
2401 [super dealloc];
2402 }
2403
2404 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
2405 return [sections_ count];
2406 }
2407
2408 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
2409 return [[sections_ objectAtIndex:section] name];
2410 }
2411
2412 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
2413 return [[sections_ objectAtIndex:section] row];
2414 }
2415
2416 - (int) numberOfRowsInTable:(UITable *)table {
2417 return [packages_ count];
2418 }
2419
2420 - (float) table:(UITable *)table heightForRow:(int)row {
2421 return 100;
2422 }
2423
2424 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2425 if (reusing == nil)
2426 reusing = [[[PackageCell alloc] initWithVersioner:versioner_] autorelease];
2427 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
2428 return reusing;
2429 }
2430
2431 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
2432 return NO;
2433 }
2434
2435 - (void) tableRowSelected:(NSNotification *)notification {
2436 int row = [[notification object] selectedRow];
2437 [delegate_ packageTable:self packageSelected:(row == INT_MAX ? nil : [packages_ objectAtIndex:row])];
2438 }
2439
2440 - (id) initWithFrame:(CGRect)frame versioner:(SEL)versioner {
2441 if ((self = [super initWithFrame:frame]) != nil) {
2442 versioner_ = versioner;
2443 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
2444
2445 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:YES];
2446 [list_ setDataSource:self];
2447
2448 UITableColumn *column = [[[UITableColumn alloc]
2449 initWithTitle:@"Name"
2450 identifier:@"name"
2451 width:frame.size.width
2452 ] autorelease];
2453
2454 UITable *table = [list_ table];
2455 [table setSeparatorStyle:1];
2456 [table addTableColumn:column];
2457 [table setDelegate:self];
2458 [table setReusesTableCells:YES];
2459
2460 [self addSubview:list_];
2461 } return self;
2462 }
2463
2464 - (void) setDelegate:(id)delegate {
2465 delegate_ = delegate;
2466 }
2467
2468 - (void) setPackages:(NSArray *)packages {
2469 if (packages_ != nil)
2470 [packages_ autorelease];
2471 _assert(packages != nil);
2472 packages_ = [packages retain];
2473
2474 [sections_ removeAllObjects];
2475
2476 Section *section = nil;
2477
2478 for (size_t offset(0); offset != [packages_ count]; ++offset) {
2479 Package *package = [packages_ objectAtIndex:offset];
2480 NSString *name = [package index];
2481
2482 if (section == nil || ![[section name] isEqual:name]) {
2483 section = [[[Section alloc] initWithName:name row:offset] autorelease];
2484 [sections_ addObject:section];
2485 }
2486
2487 [section addPackage:package];
2488 }
2489
2490 [list_ reloadData];
2491 }
2492
2493 - (void) resetViewAnimated:(BOOL)animated {
2494 [[list_ table] selectRow:-1 byExtendingSelection:NO withFade:animated];
2495 }
2496
2497 - (UITable *) table {
2498 return [list_ table];
2499 }
2500
2501 @end
2502 /* }}} */
2503
2504 /* Section Cell {{{ */
2505 @interface SectionCell : UITableCell {
2506 UITextLabel *name_;
2507 UITextLabel *count_;
2508 }
2509
2510 - (void) dealloc;
2511
2512 - (id) init;
2513 - (void) setSection:(Section *)section;
2514
2515 - (void) _setSelected:(float)fraction;
2516 - (void) setSelected:(BOOL)selected;
2517 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade;
2518 - (void) _setSelectionFadeFraction:(float)fraction;
2519
2520 @end
2521
2522 @implementation SectionCell
2523
2524 - (void) dealloc {
2525 [name_ release];
2526 [count_ release];
2527 [super dealloc];
2528 }
2529
2530 - (id) init {
2531 if ((self = [super init]) != nil) {
2532 GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22);
2533 GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 12);
2534
2535 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
2536 CGColor clear(space, 0, 0, 0, 0);
2537 CGColor white(space, 1, 1, 1, 1);
2538
2539 name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 9, 250, 25)];
2540 [name_ setBackgroundColor:clear];
2541 [name_ setFont:bold];
2542
2543 count_ = [[UITextLabel alloc] initWithFrame:CGRectMake(11, 7, 29, 32)];
2544 [count_ setCentersHorizontally:YES];
2545 [count_ setBackgroundColor:clear];
2546 [count_ setFont:small];
2547 [count_ setColor:white];
2548
2549 UIImageView *folder = [[[UIImageView alloc] initWithFrame:CGRectMake(8, 7, 32, 32)] autorelease];
2550 [folder setImage:[UIImage applicationImageNamed:@"folder.png"]];
2551
2552 [self addSubview:folder];
2553 [self addSubview:name_];
2554 [self addSubview:count_];
2555
2556 [self _setSelected:0];
2557
2558 CGColorSpaceRelease(space);
2559
2560 CFRelease(small);
2561 CFRelease(bold);
2562 } return self;
2563 }
2564
2565 - (void) setSection:(Section *)section {
2566 if (section == nil) {
2567 [name_ setText:@"All Packages"];
2568 [count_ setText:nil];
2569 } else {
2570 NSString *name = [section name];
2571 [name_ setText:(name == nil ? @"(No Section)" : name)];
2572 [count_ setText:[NSString stringWithFormat:@"%d", [section count]]];
2573 }
2574 }
2575
2576 - (void) _setSelected:(float)fraction {
2577 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
2578
2579 CGColor black(space,
2580 interpolate(0.0, 1.0, fraction),
2581 interpolate(0.0, 1.0, fraction),
2582 interpolate(0.0, 1.0, fraction),
2583 1.0);
2584
2585 [name_ setColor:black];
2586
2587 CGColorSpaceRelease(space);
2588 }
2589
2590 - (void) setSelected:(BOOL)selected {
2591 [self _setSelected:(selected ? 1.0 : 0.0)];
2592 [super setSelected:selected];
2593 }
2594
2595 - (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
2596 if (!fade)
2597 [self _setSelected:(selected ? 1.0 : 0.0)];
2598 [super setSelected:selected withFade:fade];
2599 }
2600
2601 - (void) _setSelectionFadeFraction:(float)fraction {
2602 [self _setSelected:fraction];
2603 [super _setSelectionFadeFraction:fraction];
2604 }
2605
2606 @end
2607 /* }}} */
2608 /* Install View {{{ */
2609 @interface InstallView : ResetView <
2610 PackageTableDelegate
2611 > {
2612 NSArray *sections_;
2613 UITable *list_;
2614 PackageTable *table_;
2615 PackageView *view_;
2616 NSString *section_;
2617 NSString *package_;
2618 NSMutableArray *packages_;
2619 }
2620
2621 - (void) dealloc;
2622
2623 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
2624
2625 - (int) numberOfRowsInTable:(UITable *)table;
2626 - (float) table:(UITable *)table heightForRow:(int)row;
2627 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing;
2628 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row;
2629 - (void) tableRowSelected:(NSNotification *)notification;
2630
2631 - (void) packageTable:(id)table packageSelected:(Package *)package;
2632
2633 - (id) initWithFrame:(CGRect)frame;
2634 - (void) setPackages:(NSArray *)packages;
2635 - (void) setDelegate:(id)delegate;
2636 @end
2637
2638 @implementation InstallView
2639
2640 - (void) dealloc {
2641 [packages_ release];
2642 if (sections_ != nil)
2643 [sections_ release];
2644 if (list_ != nil)
2645 [list_ release];
2646 if (table_ != nil)
2647 [table_ release];
2648 if (view_ != nil)
2649 [view_ release];
2650 if (section_ != nil)
2651 [section_ release];
2652 if (package_ != nil)
2653 [package_ release];
2654 [super dealloc];
2655 }
2656
2657 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2658 if (button == 0) {
2659 [[view_ package] install];
2660 [delegate_ resolve];
2661 [delegate_ perform];
2662 }
2663 }
2664
2665 - (int) numberOfRowsInTable:(UITable *)table {
2666 return [sections_ count] + 1;
2667 }
2668
2669 - (float) table:(UITable *)table heightForRow:(int)row {
2670 return 45;
2671 }
2672
2673 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2674 if (reusing == nil)
2675 reusing = [[[SectionCell alloc] init] autorelease];
2676 if (row == 0)
2677 [(SectionCell *)reusing setSection:nil];
2678 else
2679 [(SectionCell *)reusing setSection:[sections_ objectAtIndex:(row - 1)]];
2680 return reusing;
2681 }
2682
2683 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
2684 return YES;
2685 }
2686
2687 - (void) tableRowSelected:(NSNotification *)notification {
2688 int row = [[notification object] selectedRow];
2689
2690 if (row == INT_MAX) {
2691 [section_ release];
2692 section_ = nil;
2693
2694 [table_ release];
2695 table_ = nil;
2696 } else {
2697 _assert(section_ == nil);
2698 _assert(table_ == nil);
2699
2700 Section *section;
2701 NSString *name;
2702
2703 if (row == 0) {
2704 section = nil;
2705 section_ = nil;
2706 name = @"All Packages";
2707 } else {
2708 section = [sections_ objectAtIndex:(row - 1)];
2709 name = [section name];
2710 section_ = [name retain];
2711 }
2712
2713 table_ = [[PackageTable alloc] initWithFrame:[transition_ bounds] versioner:@selector(latest)];
2714 [table_ setDelegate:self];
2715 [table_ setPackages:(section == nil ? packages_ : [section packages])];
2716
2717 [self pushView:table_ withTitle:name backButtonTitle:@"Packages" rightButton:nil];
2718 }
2719 }
2720
2721 - (void) packageTable:(id)table packageSelected:(Package *)package {
2722 if (package == nil) {
2723 [package_ release];
2724 package_ = nil;
2725
2726 [view_ release];
2727 view_ = nil;
2728 } else {
2729 _assert(package_ == nil);
2730 _assert(view_ == nil);
2731
2732 package_ = [[package name] retain];
2733
2734 view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]];
2735 [view_ setDelegate:delegate_];
2736
2737 [view_ setPackage:package];
2738
2739 [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:@"Install"];
2740 }
2741 }
2742
2743 - (id) initWithFrame:(CGRect)frame {
2744 if ((self = [super initWithFrame:frame]) != nil) {
2745 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
2746
2747 list_ = [[UITable alloc] initWithFrame:[transition_ bounds]];
2748 [self pushView:list_ withTitle:@"Install" backButtonTitle:@"Sections" rightButton:nil];
2749
2750 UITableColumn *column = [[[UITableColumn alloc]
2751 initWithTitle:@"Name"
2752 identifier:@"name"
2753 width:frame.size.width
2754 ] autorelease];
2755
2756 [list_ setDataSource:self];
2757 [list_ setSeparatorStyle:1];
2758 [list_ addTableColumn:column];
2759 [list_ setDelegate:self];
2760 [list_ setReusesTableCells:YES];
2761
2762 [transition_ transition:0 toView:list_];
2763 } return self;
2764 }
2765
2766 - (void) setPackages:(NSArray *)packages {
2767 [packages_ removeAllObjects];
2768
2769 for (size_t i(0); i != [packages count]; ++i) {
2770 Package *package([packages objectAtIndex:i]);
2771 if ([package installed] == nil)
2772 [packages_ addObject:package];
2773 }
2774
2775 [packages_ sortUsingSelector:@selector(compareBySectionAndName:)];
2776 NSMutableArray *sections = [NSMutableArray arrayWithCapacity:16];
2777
2778 Section *nsection = nil;
2779 Package *npackage = nil;
2780
2781 Section *section = nil;
2782 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
2783 Package *package = [packages_ objectAtIndex:offset];
2784 NSString *name = [package section];
2785
2786 if (section == nil || name != nil && ![[section name] isEqual:name]) {
2787 section = [[[Section alloc] initWithName:name row:offset] autorelease];
2788
2789 if (name == nil || [name isEqualToString:section_])
2790 nsection = section;
2791 [sections addObject:section];
2792 }
2793
2794 if ([[package name] isEqualToString:package_])
2795 npackage = package;
2796 [section addPackage:package];
2797 }
2798
2799 if (sections_ != nil)
2800 [sections_ release];
2801 sections_ = [sections retain];
2802
2803 [packages_ sortUsingSelector:@selector(compareByName:)];
2804
2805 [list_ reloadData];
2806
2807 unsigned views(0);
2808
2809 if (npackage != nil)
2810 [view_ setPackage:npackage];
2811 else if (package_ != nil)
2812 ++views;
2813
2814 if (table_ != nil && section_ == nil)
2815 [table_ setPackages:packages_];
2816 else if (nsection != nil)
2817 [table_ setPackages:[nsection packages]];
2818 else if (section_ != nil)
2819 ++views;
2820
2821 if (views != 0)
2822 [self popViews:views];
2823 [self setPrompt];
2824 }
2825
2826 - (void) setDelegate:(id)delegate {
2827 if (view_ != nil)
2828 [view_ setDelegate:delegate];
2829 [super setDelegate:delegate];
2830 }
2831
2832 @end
2833 /* }}} */
2834 /* Changes View {{{ */
2835 @interface ChangesView : ResetView <
2836 PackageTableDelegate
2837 > {
2838 UISectionList *list_;
2839 NSMutableArray *packages_;
2840 NSMutableArray *sections_;
2841 PackageView *view_;
2842 NSString *package_;
2843 size_t count_;
2844 }
2845
2846 - (void) dealloc;
2847
2848 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
2849
2850 - (int) numberOfSectionsInSectionList:(UISectionList *)list;
2851 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section;
2852 - (int) sectionList:(UISectionList *)list rowForSection:(int)section;
2853
2854 - (int) numberOfRowsInTable:(UITable *)table;
2855 - (float) table:(UITable *)table heightForRow:(int)row;
2856 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing;
2857 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row;
2858 - (void) tableRowSelected:(NSNotification *)notification;
2859
2860 - (id) initWithFrame:(CGRect)frame;
2861 - (void) setPackages:(NSArray *)packages;
2862 - (void) _resetView;
2863 - (size_t) count;
2864
2865 - (void) setDelegate:(id)delegate;
2866 @end
2867
2868 @implementation ChangesView
2869
2870 - (void) dealloc {
2871 [list_ release];
2872 [packages_ release];
2873 [sections_ release];
2874 if (view_ != nil)
2875 [view_ release];
2876 if (package_ != nil)
2877 [package_ release];
2878 [super dealloc];
2879 }
2880
2881 - (int) numberOfSectionsInSectionList:(UISectionList *)list {
2882 return [sections_ count];
2883 }
2884
2885 - (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
2886 return [[sections_ objectAtIndex:section] name];
2887 }
2888
2889 - (int) sectionList:(UISectionList *)list rowForSection:(int)section {
2890 return [[sections_ objectAtIndex:section] row];
2891 }
2892
2893 - (int) numberOfRowsInTable:(UITable *)table {
2894 return [packages_ count];
2895 }
2896
2897 - (float) table:(UITable *)table heightForRow:(int)row {
2898 return 100;
2899 }
2900
2901 - (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
2902 if (reusing == nil)
2903 reusing = [[[PackageCell alloc] initWithVersioner:NULL] autorelease];
2904 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
2905 return reusing;
2906 }
2907
2908 - (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
2909 return NO;
2910 }
2911
2912 - (void) tableRowSelected:(NSNotification *)notification {
2913 int row = [[notification object] selectedRow];
2914 [self packageTable:self packageSelected:(row == INT_MAX ? nil : [packages_ objectAtIndex:row])];
2915 }
2916
2917 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2918 switch (button) {
2919 case 0:
2920 [[view_ package] install];
2921 [delegate_ resolve];
2922 [delegate_ perform];
2923 break;
2924
2925 case 1:
2926 [delegate_ upgrade];
2927 break;
2928 }
2929 }
2930
2931 - (void) packageTable:(id)table packageSelected:(Package *)package {
2932 if (package == nil) {
2933 [package_ release];
2934 package_ = nil;
2935
2936 [view_ release];
2937 view_ = nil;
2938 } else {
2939 _assert(package_ == nil);
2940 _assert(view_ == nil);
2941
2942 package_ = [[package name] retain];
2943
2944 view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]];
2945 [view_ setDelegate:delegate_];
2946
2947 [view_ setPackage:package];
2948
2949 [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:(
2950 [package upgradable] ? @"Upgrade" : @"Install"
2951 )];
2952 }
2953 }
2954
2955 - (id) initWithFrame:(CGRect)frame {
2956 if ((self = [super initWithFrame:frame]) != nil) {
2957 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
2958 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
2959
2960 list_ = [[UISectionList alloc] initWithFrame:[transition_ bounds] showSectionIndex:NO];
2961 [list_ setShouldHideHeaderInShortLists:NO];
2962 [list_ setDataSource:self];
2963 //[list_ setSectionListStyle:1];
2964
2965 UITableColumn *column = [[[UITableColumn alloc]
2966 initWithTitle:@"Name"
2967 identifier:@"name"
2968 width:frame.size.width
2969 ] autorelease];
2970
2971 UITable *table = [list_ table];
2972 [table setSeparatorStyle:1];
2973 [table addTableColumn:column];
2974 [table setDelegate:self];
2975 [table setReusesTableCells:YES];
2976
2977 [self pushView:list_ withTitle:@"Changes" backButtonTitle:nil rightButton:nil];
2978 } return self;
2979 }
2980
2981 - (void) setPackages:(NSArray *)packages {
2982 [packages_ removeAllObjects];
2983 for (size_t i(0); i != [packages count]; ++i) {
2984 Package *package([packages objectAtIndex:i]);
2985 if ([package installed] == nil || [package upgradable])
2986 [packages_ addObject:package];
2987 }
2988
2989 [packages_ sortUsingSelector:@selector(compareForChanges:)];
2990
2991 [sections_ removeAllObjects];
2992
2993 Section *upgradable = [[[Section alloc] initWithName:@"Available Upgrades" row:0] autorelease];
2994 Section *section = nil;
2995
2996 count_ = 0;
2997 Package *npackage = nil;
2998 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
2999 Package *package = [packages_ objectAtIndex:offset];
3000 if ([[package name] isEqualToString:package_])
3001 npackage = package;
3002
3003 if ([package upgradable])
3004 [upgradable addPackage:package];
3005 else {
3006 NSDate *seen = [package seen];
3007
3008 CFLocaleRef locale = CFLocaleCopyCurrent();
3009 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
3010 CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen);
3011
3012 NSString *name = (NSString *) formatted;
3013
3014 if (section == nil || ![[section name] isEqual:name]) {
3015 section = [[[Section alloc] initWithName:name row:offset] autorelease];
3016 [sections_ addObject:section];
3017 }
3018
3019 [section addPackage:package];
3020
3021 CFRelease(formatter);
3022 CFRelease(formatted);
3023 CFRelease(locale);
3024 }
3025 }
3026
3027 count_ = [[upgradable packages] count];
3028 if (count_ != 0)
3029 [sections_ insertObject:upgradable atIndex:0];
3030
3031 [list_ reloadData];
3032
3033 if (npackage != nil)
3034 [view_ setPackage:npackage];
3035 else if (package_ != nil)
3036 [self popViews:1];
3037
3038 [self _resetView];
3039 [self setPrompt];
3040 }
3041
3042 - (void) _resetView {
3043 if ([views_ count] == 1)
3044 [navbar_ showButtonsWithLeftTitle:(count_ == 0 ? nil : @"Upgrade All") rightTitle:nil];
3045 }
3046
3047 - (size_t) count {
3048 return count_;
3049 }
3050
3051 - (void) setDelegate:(id)delegate {
3052 if (view_ != nil)
3053 [view_ setDelegate:delegate];
3054 [super setDelegate:delegate];
3055 }
3056
3057 @end
3058 /* }}} */
3059 /* Manage View {{{ */
3060 @interface ManageView : ResetView <
3061 PackageTableDelegate
3062 > {
3063 PackageTable *table_;
3064 PackageView *view_;
3065 NSString *package_;
3066 }
3067
3068 - (void) dealloc;
3069
3070 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
3071
3072 - (void) packageTable:(id)table packageSelected:(Package *)package;
3073
3074 - (id) initWithFrame:(CGRect)frame;
3075 - (void) setPackages:(NSArray *)packages;
3076
3077 - (void) setDelegate:(id)delegate;
3078 @end
3079
3080 @implementation ManageView
3081
3082 - (void) dealloc {
3083 [table_ release];
3084 if (view_ != nil)
3085 [view_ release];
3086 if (package_ != nil)
3087 [package_ release];
3088 [super dealloc];
3089 }
3090
3091 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
3092 if (button == 0) {
3093 [[view_ package] remove];
3094 [delegate_ resolve];
3095 [delegate_ perform];
3096 }
3097 }
3098
3099 - (void) packageTable:(id)table packageSelected:(Package *)package {
3100 if (package == nil) {
3101 [package_ release];
3102 package_ = nil;
3103
3104 [view_ release];
3105 view_ = nil;
3106 } else {
3107 _assert(package_ == nil);
3108 _assert(view_ == nil);
3109
3110 package_ = [[package name] retain];
3111
3112 view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]];
3113 [view_ setDelegate:delegate_];
3114
3115 [view_ setPackage:package];
3116
3117 [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:@"Uninstall"];
3118 }
3119 }
3120
3121 - (id) initWithFrame:(CGRect)frame {
3122 if ((self = [super initWithFrame:frame]) != nil) {
3123 table_ = [[PackageTable alloc] initWithFrame:[transition_ bounds] versioner:@selector(latest)];
3124 [table_ setDelegate:self];
3125
3126 [self pushView:table_ withTitle:@"Uninstall" backButtonTitle:@"Packages" rightButton:nil];
3127 } return self;
3128 }
3129
3130 - (void) setPackages:(NSArray *)packages {
3131 NSMutableArray *local = [NSMutableArray arrayWithCapacity:16];
3132 for (size_t i(0); i != [packages count]; ++i) {
3133 Package *package([packages objectAtIndex:i]);
3134 if ([package installed] != nil)
3135 [local addObject:package];
3136 }
3137
3138 [local sortUsingSelector:@selector(compareByName:)];
3139
3140 Package *npackage = nil;
3141 for (size_t offset = 0, count = [local count]; offset != count; ++offset) {
3142 Package *package = [local objectAtIndex:offset];
3143 if ([[package name] isEqualToString:package_])
3144 npackage = package;
3145 }
3146
3147 [table_ setPackages:local];
3148
3149 if (npackage != nil)
3150 [view_ setPackage:npackage];
3151 else if (package_ != nil)
3152 [self popViews:1];
3153
3154 [self setPrompt];
3155 }
3156
3157 - (void) setDelegate:(id)delegate {
3158 if (view_ != nil)
3159 [view_ setDelegate:delegate];
3160 [super setDelegate:delegate];
3161 }
3162
3163 @end
3164 /* }}} */
3165 /* Search View {{{ */
3166 @protocol SearchViewDelegate
3167 - (void) showKeyboard:(BOOL)show;
3168 @end
3169
3170 @interface SearchView : ResetView <
3171 PackageTableDelegate
3172 > {
3173 NSMutableArray *packages_;
3174 UIView *accessory_;
3175 UISearchField *field_;
3176 PackageTable *table_;
3177 PackageView *view_;
3178 NSString *package_;
3179 }
3180
3181 - (void) dealloc;
3182
3183 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
3184 - (void) packageTable:(id)table packageSelected:(Package *)package;
3185
3186 - (void) textFieldDidBecomeFirstResponder:(UITextField *)field;
3187 - (void) textFieldDidResignFirstResponder:(UITextField *)field;
3188
3189 - (void) keyboardInputChanged:(UIFieldEditor *)editor;
3190 - (BOOL) keyboardInput:(id)input shouldInsertText:(NSString *)text isMarkedText:(int)marked;
3191
3192 - (id) initWithFrame:(CGRect)frame;
3193 - (void) setPackages:(NSArray *)packages;
3194
3195 - (void) setDelegate:(id)delegate;
3196 - (void) resetPackage:(Package *)package;
3197 - (void) searchPackages;
3198
3199 @end
3200
3201 @implementation SearchView
3202
3203 - (void) dealloc {
3204 [packages_ release];
3205 [accessory_ release];
3206 [field_ release];
3207 [table_ release];
3208 if (view_ != nil)
3209 [view_ release];
3210 if (package_ != nil)
3211 [package_ release];
3212 [super dealloc];
3213 }
3214
3215 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
3216 if (button == 0) {
3217 Package *package = [view_ package];
3218 if ([package installed] == nil)
3219 [package install];
3220 else
3221 [package remove];
3222 [delegate_ resolve];
3223 [delegate_ perform];
3224 }
3225 }
3226
3227 - (void) packageTable:(id)table packageSelected:(Package *)package {
3228 if (package == nil) {
3229 [navbar_ setAccessoryView:accessory_ animate:(resetting_ ? NO : YES) goingBack:YES];
3230
3231 [package_ release];
3232 package_ = nil;
3233
3234 [view_ release];
3235 view_ = nil;
3236 } else {
3237 [navbar_ setAccessoryView:nil animate:YES goingBack:NO];
3238
3239 _assert(package_ == nil);
3240 _assert(view_ == nil);
3241
3242 package_ = [[package name] retain];
3243
3244 view_ = [[PackageView alloc] initWithFrame:[transition_ bounds]];
3245 [view_ setDelegate:delegate_];
3246
3247 [self pushView:view_ withTitle:[package name] backButtonTitle:nil rightButton:nil];
3248 [self resetPackage:package];
3249 }
3250 }
3251
3252 - (void) textFieldDidBecomeFirstResponder:(UITextField *)field {
3253 [delegate_ showKeyboard:YES];
3254 [table_ setEnabled:NO];
3255
3256 /*CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
3257 CGColor dimmed(alpha, 0, 0, 0, 0.5);
3258 [editor_ setBackgroundColor:dimmed];
3259 CGColorSpaceRelease(space);*/
3260 }
3261
3262 - (void) textFieldDidResignFirstResponder:(UITextField *)field {
3263 [table_ setEnabled:YES];
3264 [delegate_ showKeyboard:NO];
3265 }
3266
3267 - (void) keyboardInputChanged:(UIFieldEditor *)editor {
3268 NSString *text([field_ text]);
3269 [field_ setClearButtonStyle:(text == nil || [text length] == 0 ? 0 : 2)];
3270 }
3271
3272 - (BOOL) keyboardInput:(id)input shouldInsertText:(NSString *)text isMarkedText:(int)marked {
3273 if ([text length] != 1 || [text characterAtIndex:0] != '\n')
3274 return YES;
3275
3276 [self searchPackages];
3277 [field_ resignFirstResponder];
3278 return NO;
3279 }
3280
3281 - (id) initWithFrame:(CGRect)frame {
3282 if ((self = [super initWithFrame:frame]) != nil) {
3283 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
3284
3285 table_ = [[PackageTable alloc] initWithFrame:[transition_ bounds] versioner:@selector(latest)];
3286 [table_ setDelegate:self];
3287
3288 CGRect area = [self bounds];
3289 area.origin.y = 30;
3290 area.origin.x = 0;
3291 area.size.width -= 12;
3292 area.size.height = [UISearchField defaultHeight];
3293
3294 field_ = [[UISearchField alloc] initWithFrame:area];
3295
3296 GSFontRef font = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16);
3297 [field_ setFont:font];
3298 CFRelease(font);
3299
3300 [field_ setPlaceholder:@"Package Names & Descriptions"];
3301 [field_ setPaddingTop:5];
3302 [field_ setDelegate:self];
3303
3304 UITextTraits *traits = [field_ textTraits];
3305 [traits setEditingDelegate:self];
3306 [traits setReturnKeyType:6];
3307
3308 accessory_ = [[UIView alloc] initWithFrame:CGRectMake(6, 6, area.size.width, area.size.height + 30)];
3309 [accessory_ addSubview:field_];
3310
3311 [navbar_ setAccessoryView:accessory_];
3312 [self pushView:table_ withTitle:nil backButtonTitle:@"Search" rightButton:nil];
3313
3314 /* XXX: for the love of god just fix this */
3315 [navbar_ removeFromSuperview];
3316 [reload_ removeFromSuperview];
3317 [configure_ removeFromSuperview];
3318 [self addSubview:navbar_];
3319 [self addSubview:reload_];
3320 [self addSubview:configure_];
3321 } return self;
3322 }
3323
3324 - (void) setPackages:(NSArray *)packages {
3325 [packages_ removeAllObjects];
3326 [packages_ addObjectsFromArray:packages];
3327 [packages_ sortUsingSelector:@selector(compareByName:)];
3328
3329 Package *npackage = nil;
3330 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
3331 Package *package = [packages_ objectAtIndex:offset];
3332 if ([[package name] isEqualToString:package_])
3333 npackage = package;
3334 }
3335
3336 [self searchPackages];
3337
3338 if (npackage != nil)
3339 [self resetPackage:npackage];
3340 else if (package_ != nil)
3341 [self popViews:1];
3342
3343 [self setPrompt];
3344 }
3345
3346 - (void) setDelegate:(id)delegate {
3347 if (view_ != nil)
3348 [view_ setDelegate:delegate];
3349 [super setDelegate:delegate];
3350 }
3351
3352 - (void) resetPackage:(Package *)package {
3353 [view_ setPackage:package];
3354 NSString *right = [package installed] == nil ? @"Install" : @"Uninstall";
3355 [navbar_ showButtonsWithLeftTitle:nil rightTitle:right];
3356 }
3357
3358 - (void) searchPackages {
3359 NSString *text([field_ text]);
3360
3361 NSMutableArray *packages([NSMutableArray arrayWithCapacity:16]);
3362
3363 for (size_t offset(0), count([packages_ count]); offset != count; ++offset) {
3364 Package *package = [packages_ objectAtIndex:offset];
3365 if ([package matches:text])
3366 [packages addObject:package];
3367 }
3368
3369 [table_ setPackages:packages];
3370 [[table_ table] scrollPointVisibleAtTopLeft:CGPointMake(0, 0) animated:NO];
3371 }
3372
3373 @end
3374 /* }}} */
3375
3376 @interface Cydia : UIApplication <
3377 ConfirmationViewDelegate,
3378 ProgressViewDelegate,
3379 SearchViewDelegate
3380 > {
3381 UIWindow *window_;
3382 UIView *underlay_;
3383 UIView *overlay_;
3384 UITransitionView *transition_;
3385 UIButtonBar *buttonbar_;
3386
3387 ConfirmationView *confirm_;
3388
3389 Database *database_;
3390 ProgressView *progress_;
3391
3392 UIView *featured_;
3393 UINavigationBar *navbar_;
3394 UIScroller *scroller_;
3395 UIWebView *webview_;
3396 NSURL *url_;
3397 UIProgressIndicator *indicator_;
3398
3399 InstallView *install_;
3400 ChangesView *changes_;
3401 ManageView *manage_;
3402 SearchView *search_;
3403
3404 bool restart_;
3405 unsigned tag_;
3406
3407 UIKeyboard *keyboard_;
3408 }
3409
3410 - (void) loadNews;
3411 - (void) reloadData:(BOOL)reset;
3412 - (void) setPrompt;
3413
3414 - (void) resolve;
3415 - (void) perform;
3416 - (void) upgrade;
3417 - (void) update;
3418
3419 - (void) cancel;
3420 - (void) confirm;
3421
3422 - (void) progressViewIsComplete:(ProgressView *)progress;
3423
3424 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button;
3425 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
3426 - (void) buttonBarItemTapped:(id)sender;
3427
3428 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old;
3429
3430 - (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame;
3431
3432 - (void) applicationWillSuspend;
3433 - (void) applicationDidFinishLaunching:(id)unused;
3434 @end
3435
3436 @implementation Cydia
3437
3438 - (void) loadNews {
3439 NSMutableURLRequest *request = [NSMutableURLRequest
3440 requestWithURL:url_
3441 cachePolicy:NSURLRequestReloadIgnoringCacheData
3442 timeoutInterval:30.0
3443 ];
3444
3445 [request addValue:[NSString stringWithCString:Firmware_] forHTTPHeaderField:@"X-Firmware"];
3446 [request addValue:[NSString stringWithCString:Machine_] forHTTPHeaderField:@"X-Machine"];
3447 [request addValue:[NSString stringWithCString:SerialNumber_] forHTTPHeaderField:@"X-Serial-Number"];
3448
3449 [webview_ loadRequest:request];
3450 }
3451
3452 - (void) reloadData:(BOOL)reset {
3453 [database_ reloadData];
3454
3455 size_t count = 16;
3456
3457 if (Packages_ == nil) {
3458 Packages_ = [[NSMutableDictionary alloc] initWithCapacity:count];
3459 [Metadata_ setObject:Packages_ forKey:@"Packages"];
3460 }
3461
3462 now_ = [NSDate date];
3463
3464 NSMutableArray *packages = [NSMutableArray arrayWithCapacity:count];
3465 for (pkgCache::PkgIterator iterator = [database_ cache]->PkgBegin(); !iterator.end(); ++iterator)
3466 if (Package *package = [Package packageWithIterator:iterator database:database_])
3467 [packages addObject:package];
3468
3469 [install_ setPackages:packages];
3470 [changes_ setPackages:packages];
3471 [manage_ setPackages:packages];
3472 [search_ setPackages:packages];
3473
3474 if (size_t count = [changes_ count]) {
3475 NSString *badge([[NSNumber numberWithInt:count] stringValue]);
3476 [buttonbar_ setBadgeValue:badge forButton:3];
3477 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
3478 [buttonbar_ setBadgeAnimated:YES forButton:3];
3479 [self setApplicationBadge:badge];
3480 } else {
3481 [buttonbar_ setBadgeValue:nil forButton:3];
3482 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
3483 [buttonbar_ setBadgeAnimated:NO forButton:3];
3484 [self removeApplicationBadge];
3485 }
3486
3487 _assert([Metadata_ writeToFile:@"/var/lib/cydia/metadata.plist" atomically:YES] == YES);
3488 }
3489
3490 - (void) setPrompt {
3491 [navbar_ setPrompt:[NSString stringWithFormat:@"Last Updated: %@", GetLastUpdate()]];
3492 }
3493
3494 - (void) resolve {
3495 pkgProblemResolver *resolver = [database_ resolver];
3496
3497 resolver->InstallProtect();
3498 if (!resolver->Resolve(true))
3499 _error->Discard();
3500 }
3501
3502 - (void) perform {
3503 [database_ prepare];
3504 confirm_ = [[ConfirmationView alloc] initWithView:underlay_ database:database_ delegate:self];
3505 }
3506
3507 - (void) upgrade {
3508 [database_ upgrade];
3509 [self perform];
3510 }
3511
3512 - (void) cancel {
3513 [self reloadData:NO];
3514 [confirm_ release];
3515 confirm_ = nil;
3516 }
3517
3518 - (void) confirm {
3519 [overlay_ removeFromSuperview];
3520 restart_ = true;
3521
3522 [progress_
3523 detachNewThreadSelector:@selector(perform)
3524 toTarget:database_
3525 withObject:nil
3526 title:@"Running..."
3527 ];
3528 }
3529
3530 - (void) bootstrap_ {
3531 [database_ update];
3532 [database_ upgrade];
3533 [database_ prepare];
3534 [database_ perform];
3535 }
3536
3537 - (void) bootstrap {
3538 [progress_
3539 detachNewThreadSelector:@selector(bootstrap_)
3540 toTarget:self
3541 withObject:nil
3542 title:@"Bootstrap Install..."
3543 ];
3544 }
3545
3546 - (void) update {
3547 [progress_
3548 detachNewThreadSelector:@selector(update)
3549 toTarget:database_
3550 withObject:nil
3551 title:@"Refreshing Sources..."
3552 ];
3553 }
3554
3555 - (void) progressViewIsComplete:(ProgressView *)progress {
3556 [self reloadData:YES];
3557
3558 if (confirm_ != nil) {
3559 [underlay_ addSubview:overlay_];
3560 [confirm_ removeFromSuperview];
3561 [confirm_ release];
3562 confirm_ = nil;
3563 }
3564 }
3565
3566 - (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
3567 switch (button) {
3568 case 0:
3569 [self loadNews];
3570 break;
3571
3572 case 1:
3573 UIAlertSheet *sheet = [[[UIAlertSheet alloc]
3574 initWithTitle:@"About Cydia Packager"
3575 buttons:[NSArray arrayWithObjects:@"Close", nil]
3576 defaultButtonIndex:0
3577 delegate:self
3578 context:self
3579 ] autorelease];
3580
3581 [sheet setBodyText:
3582 @"Copyright (C) 2008\n"
3583 "Jay Freeman (saurik)\n"
3584 "saurik@saurik.com\n"
3585 "http://www.saurik.com/\n"
3586 "\n"
3587 "The Okori Group\n"
3588 "http://www.theokorigroup.com/\n"
3589 "\n"
3590 "College of Creative Studies,\n"
3591 "University of California,\n"
3592 "Santa Barbara\n"
3593 "http://www.ccs.ucsb.edu/\n"
3594 "\n"
3595 "Special Thanks:\n"
3596 "bad_, BHSPitMonkey, cash, Cobra,\n"
3597 "core, Corona, crashx, cromas,\n"
3598 "Darken, dtzWill, Erica, francis,\n"
3599 "Godores, jerry, Kingstone, lounger,\n"
3600 "mbranes, rockabilly, tman, Wbiggs"
3601 ];
3602
3603 [sheet presentSheetFromButtonBar:buttonbar_];
3604 break;
3605 }
3606 }
3607
3608 - (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
3609 [sheet dismiss];
3610 }
3611
3612 - (void) buttonBarItemTapped:(id)sender {
3613 UIView *view;
3614 unsigned tag = [sender tag];
3615
3616 switch (tag) {
3617 case 1: view = featured_; break;
3618 case 2: view = install_; break;
3619 case 3: view = changes_; break;
3620 case 4: view = manage_; break;
3621 case 5: view = search_; break;
3622
3623 default:
3624 _assert(false);
3625 }
3626
3627 if ([view respondsToSelector:@selector(resetView:)])
3628 [(id) view resetView:(tag == tag_ ? NO : YES)];
3629 tag_ = tag;
3630 [transition_ transition:0 toView:view];
3631 }
3632
3633 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old {
3634 [scroller_ setContentSize:frame.size];
3635 [indicator_ stopAnimation];
3636 }
3637
3638 - (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame {
3639 [navbar_ setPrompt:title];
3640 }
3641
3642 - (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame {
3643 [navbar_ setPrompt:@"Loading..."];
3644 [indicator_ startAnimation];
3645 }
3646
3647 - (void) applicationWillSuspend {
3648 if (restart_)
3649 if (FW_LEAST(1,1,3))
3650 notify_post("com.apple.language.changed");
3651 else
3652 system("launchctl stop com.apple.SpringBoard");
3653
3654 [super applicationWillSuspend];
3655 }
3656
3657 - (void) applicationDidFinishLaunching:(id)unused {
3658 _assert(pkgInitConfig(*_config));
3659 _assert(pkgInitSystem(*_config, _system));
3660
3661 confirm_ = nil;
3662 restart_ = false;
3663 tag_ = 1;
3664
3665 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
3666 window_ = [[UIWindow alloc] initWithContentRect:screenrect];
3667
3668 [window_ orderFront: self];
3669 [window_ makeKey: self];
3670 [window_ _setHidden: NO];
3671
3672 progress_ = [[ProgressView alloc] initWithFrame:[window_ bounds] delegate:self];
3673 [window_ setContentView:progress_];
3674
3675 underlay_ = [[UIView alloc] initWithFrame:[progress_ bounds]];
3676 [progress_ setContentView:underlay_];
3677
3678 overlay_ = [[UIView alloc] initWithFrame:[underlay_ bounds]];
3679
3680 if (!bootstrap_)
3681 [underlay_ addSubview:overlay_];
3682
3683 transition_ = [[UITransitionView alloc] initWithFrame:CGRectMake(
3684 0, 0, screenrect.size.width, screenrect.size.height - 48
3685 )];
3686
3687 [overlay_ addSubview:transition_];
3688
3689 featured_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
3690
3691 CGSize navsize = [UINavigationBar defaultSizeWithPrompt];
3692 CGRect navrect = {{0, 0}, navsize};
3693
3694 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
3695 [featured_ addSubview:navbar_];
3696
3697 [navbar_ setBarStyle:1];
3698 [navbar_ setDelegate:self];
3699
3700 [navbar_ showButtonsWithLeftTitle:@"About" rightTitle:@"Reload"];
3701
3702 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Featured"] autorelease];
3703 [navbar_ pushNavigationItem:navitem];
3704
3705 struct CGRect subbounds = [featured_ bounds];
3706 subbounds.origin.y += navsize.height;
3707 subbounds.size.height -= navsize.height;
3708
3709 UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:subbounds] autorelease];
3710 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
3711 [featured_ addSubview:pinstripe];
3712
3713 scroller_ = [[UIScroller alloc] initWithFrame:subbounds];
3714 [featured_ addSubview:scroller_];
3715
3716 [scroller_ setScrollingEnabled:YES];
3717 [scroller_ setAdjustForContentSizeChange:YES];
3718 [scroller_ setClipsSubviews:YES];
3719 [scroller_ setAllowsRubberBanding:YES];
3720 [scroller_ setScrollDecelerationFactor:0.99];
3721 [scroller_ setDelegate:self];
3722
3723 CGRect webrect = [scroller_ bounds];
3724 webrect.size.height = 0;
3725
3726 webview_ = [[UIWebView alloc] initWithFrame:webrect];
3727 [scroller_ addSubview:webview_];
3728
3729 [webview_ setTilingEnabled:YES];
3730 [webview_ setTileSize:CGSizeMake(screenrect.size.width, 500)];
3731 [webview_ setAutoresizes:YES];
3732 [webview_ setDelegate:self];
3733
3734 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:2];
3735 indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(87, 45, indsize.width, indsize.height)];
3736 [indicator_ setStyle:2];
3737 [featured_ addSubview:indicator_];
3738
3739 NSArray *buttonitems = [NSArray arrayWithObjects:
3740 [NSDictionary dictionaryWithObjectsAndKeys:
3741 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3742 @"featured-up.png", kUIButtonBarButtonInfo,
3743 @"featured-dn.png", kUIButtonBarButtonSelectedInfo,
3744 [NSNumber numberWithInt:1], kUIButtonBarButtonTag,
3745 self, kUIButtonBarButtonTarget,
3746 @"Featured", kUIButtonBarButtonTitle,
3747 @"0", kUIButtonBarButtonType,
3748 nil],
3749
3750 [NSDictionary dictionaryWithObjectsAndKeys:
3751 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3752 @"install-up.png", kUIButtonBarButtonInfo,
3753 @"install-dn.png", kUIButtonBarButtonSelectedInfo,
3754 [NSNumber numberWithInt:2], kUIButtonBarButtonTag,
3755 self, kUIButtonBarButtonTarget,
3756 @"Install", kUIButtonBarButtonTitle,
3757 @"0", kUIButtonBarButtonType,
3758 nil],
3759
3760 [NSDictionary dictionaryWithObjectsAndKeys:
3761 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3762 @"changes-up.png", kUIButtonBarButtonInfo,
3763 @"changes-dn.png", kUIButtonBarButtonSelectedInfo,
3764 [NSNumber numberWithInt:3], kUIButtonBarButtonTag,
3765 self, kUIButtonBarButtonTarget,
3766 @"Changes", kUIButtonBarButtonTitle,
3767 @"0", kUIButtonBarButtonType,
3768 nil],
3769
3770 [NSDictionary dictionaryWithObjectsAndKeys:
3771 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3772 @"manage-up.png", kUIButtonBarButtonInfo,
3773 @"manage-dn.png", kUIButtonBarButtonSelectedInfo,
3774 [NSNumber numberWithInt:4], kUIButtonBarButtonTag,
3775 self, kUIButtonBarButtonTarget,
3776 @"Uninstall", kUIButtonBarButtonTitle,
3777 @"0", kUIButtonBarButtonType,
3778 nil],
3779
3780 [NSDictionary dictionaryWithObjectsAndKeys:
3781 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
3782 @"search-up.png", kUIButtonBarButtonInfo,
3783 @"search-dn.png", kUIButtonBarButtonSelectedInfo,
3784 [NSNumber numberWithInt:5], kUIButtonBarButtonTag,
3785 self, kUIButtonBarButtonTarget,
3786 @"Search", kUIButtonBarButtonTitle,
3787 @"0", kUIButtonBarButtonType,
3788 nil],
3789 nil];
3790
3791 buttonbar_ = [[UIButtonBar alloc]
3792 initInView:overlay_
3793 withFrame:CGRectMake(
3794 0, screenrect.size.height - 48,
3795 screenrect.size.width, 48
3796 )
3797 withItemList:buttonitems
3798 ];
3799
3800 [buttonbar_ setDelegate:self];
3801 [buttonbar_ setBarStyle:1];
3802 [buttonbar_ setButtonBarTrackingMode:2];
3803
3804 int buttons[5] = {1, 2, 3, 4, 5};
3805 [buttonbar_ registerButtonGroup:0 withButtons:buttons withCount:5];
3806 [buttonbar_ showButtonGroup:0 withDuration:0];
3807
3808 for (int i = 0; i != 5; ++i)
3809 [[buttonbar_ viewWithTag:(i + 1)] setFrame:CGRectMake(
3810 i * 64 + 2, 1, 60, 48
3811 )];
3812
3813 [buttonbar_ showSelectionForButton:1];
3814 [transition_ transition:0 toView:featured_];
3815
3816 [overlay_ addSubview:buttonbar_];
3817
3818 [UIKeyboard initImplementationNow];
3819
3820 CGRect edtrect = [overlay_ bounds];
3821 edtrect.origin.y += navsize.height;
3822 edtrect.size.height -= navsize.height;
3823
3824 CGSize keysize = [UIKeyboard defaultSize];
3825 CGRect keyrect = {{0, [overlay_ bounds].size.height - keysize.height}, keysize};
3826 keyboard_ = [[UIKeyboard alloc] initWithFrame:keyrect];
3827
3828 database_ = [[Database alloc] init];
3829 [database_ setDelegate:progress_];
3830
3831 install_ = [[InstallView alloc] initWithFrame:[transition_ bounds]];
3832 [install_ setDelegate:self];
3833
3834 changes_ = [[ChangesView alloc] initWithFrame:[transition_ bounds]];
3835 [changes_ setDelegate:self];
3836
3837 manage_ = [[ManageView alloc] initWithFrame:[transition_ bounds]];
3838 [manage_ setDelegate:self];
3839
3840 search_ = [[SearchView alloc] initWithFrame:[transition_ bounds]];
3841 [search_ setDelegate:self];
3842
3843 [self reloadData:NO];
3844
3845 Package *package([database_ packageWithName:@"cydia"]);
3846 NSString *application = package == nil ? @"Cydia" : [NSString
3847 stringWithFormat:@"Cydia/%@",
3848 [package installed]
3849 ];
3850
3851 WebView *webview = [webview_ webView];
3852 [webview setApplicationNameForUserAgent:application];
3853 [webview setFrameLoadDelegate:self];
3854
3855 url_ = [NSURL URLWithString:@"http://cydia.saurik.com/"];
3856 [self loadNews];
3857
3858 [progress_ resetView];
3859
3860 if (bootstrap_)
3861 [self bootstrap];
3862 }
3863
3864 - (void) showKeyboard:(BOOL)show {
3865 if (show)
3866 [overlay_ addSubview:keyboard_];
3867 else
3868 [keyboard_ removeFromSuperview];
3869 }
3870
3871 @end
3872
3873 void AddPreferences(NSString *plist) {
3874 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
3875
3876 NSMutableDictionary *settings = [[[NSMutableDictionary alloc] initWithContentsOfFile:plist] autorelease];
3877 _assert(settings != NULL);
3878 NSMutableArray *items = [settings objectForKey:@"items"];
3879
3880 bool cydia(false);
3881
3882 for (size_t i(0); i != [items count]; ++i) {
3883 NSMutableDictionary *item([items objectAtIndex:i]);
3884 NSString *label = [item objectForKey:@"label"];
3885 if (label != nil && [label isEqualToString:@"Cydia"]) {
3886 cydia = true;
3887 break;
3888 }
3889 }
3890
3891 if (!cydia) {
3892 for (size_t i(0); i != [items count]; ++i) {
3893 NSDictionary *item([items objectAtIndex:i]);
3894 NSString *label = [item objectForKey:@"label"];
3895 if (label != nil && [label isEqualToString:@"General"]) {
3896 [items insertObject:[NSDictionary dictionaryWithObjectsAndKeys:
3897 @"CydiaSettings", @"bundle",
3898 @"PSLinkCell", @"cell",
3899 [NSNumber numberWithBool:YES], @"hasIcon",
3900 [NSNumber numberWithBool:YES], @"isController",
3901 @"Cydia", @"label",
3902 nil] atIndex:(i + 1)];
3903
3904 break;
3905 }
3906 }
3907
3908 _assert([settings writeToFile:plist atomically:YES] == YES);
3909 }
3910
3911 [pool release];
3912 }
3913
3914 /*IMP alloc_;
3915 id Alloc_(id self, SEL selector) {
3916 id object = alloc_(self, selector);
3917 fprintf(stderr, "[%s]A-%p\n", self->isa->name, object);
3918 return object;
3919 }*/
3920
3921 int main(int argc, char *argv[]) {
3922 struct nlist nl[2];
3923 memset(nl, 0, sizeof(nl));
3924 nl[0].n_un.n_name = "_useMDNSResponder";
3925 nlist("/usr/lib/libc.dylib", nl);
3926 if (nl[0].n_type != N_UNDF)
3927 *(int *) nl[0].n_value = 0;
3928
3929 bootstrap_ = argc > 1 && strcmp(argv[1], "--bootstrap") == 0;
3930
3931 setuid(0);
3932 setgid(0);
3933
3934 /*Method alloc = class_getClassMethod([NSObject class], @selector(alloc));
3935 alloc_ = alloc->method_imp;
3936 alloc->method_imp = (IMP) &Alloc_;*/
3937
3938 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
3939
3940 if (NSDictionary *sysver = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]) {
3941 if (NSString *prover = [sysver valueForKey:@"ProductVersion"]) {
3942 Firmware_ = strdup([prover cString]);
3943 NSArray *versions = [prover componentsSeparatedByString:@"."];
3944 int count = [versions count];
3945 Major_ = count > 0 ? [[versions objectAtIndex:0] intValue] : 0;
3946 Minor_ = count > 1 ? [[versions objectAtIndex:1] intValue] : 0;
3947 BugFix_ = count > 2 ? [[versions objectAtIndex:2] intValue] : 0;
3948 }
3949 }
3950
3951 size_t size;
3952 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
3953 char *machine = new char[size];
3954 sysctlbyname("hw.machine", machine, &size, NULL, 0);
3955 Machine_ = machine;
3956
3957 if (CFMutableDictionaryRef dict = IOServiceMatching("IOPlatformExpertDevice"))
3958 if (io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, dict)) {
3959 if (CFTypeRef serial = IORegistryEntryCreateCFProperty(service, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0)) {
3960 SerialNumber_ = strdup(CFStringGetCStringPtr((CFStringRef) serial, CFStringGetSystemEncoding()));
3961 CFRelease(serial);
3962 }
3963
3964 IOObjectRelease(service);
3965 }
3966
3967 /*AddPreferences(@"/Applications/Preferences.app/Settings-iPhone.plist");
3968 AddPreferences(@"/Applications/Preferences.app/Settings-iPod.plist");*/
3969
3970 if ((Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"]) == NULL)
3971 Metadata_ = [[NSMutableDictionary alloc] initWithCapacity:2];
3972 else
3973 Packages_ = [Metadata_ objectForKey:@"Packages"];
3974
3975 setenv("CYDIA", "", _not(int));
3976 if (access("/User", F_OK) != 0)
3977 system("/usr/libexec/cydia/firmware.sh");
3978 system("dpkg --configure -a");
3979
3980 UIApplicationMain(argc, argv, [Cydia class]);
3981 [pool release];
3982 return 0;
3983 }