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