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