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