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