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