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