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