]> git.saurik.com Git - cydia.git/blame - Cydia.mm
Added custom depictions and better webview support.
[cydia.git] / Cydia.mm
CommitLineData
e057ec05
JF
1/* Cydia - iPhone UIKit Front-End for Debian APT
2 * Copyright (C) 2008 Jay Freeman (saurik)
3*/
4
5/*
6 * Redistribution and use in source and binary
7 * forms, with or without modification, are permitted
8 * provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the
11 * above copyright notice, this list of conditions
12 * and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the
14 * above copyright notice, this list of conditions
15 * and the following disclaimer in the documentation
16 * and/or other materials provided with the
17 * distribution.
18 * 3. The name of the author may not be used to endorse
19 * or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS''
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
24 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
33 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
35 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36*/
37
a75f53e7 38/* #include Directives {{{ */
59efd93a
JF
39#include <objc/objc.h>
40#include <objc/runtime.h>
41
b0d03ade 42#include <CoreGraphics/CoreGraphics.h>
9856894f 43#include <GraphicsServices/GraphicsServices.h>
b0d03ade 44#include <Foundation/Foundation.h>
853d14d3 45
e057ec05 46#include <WebCore/DOMHTML.h>
853d14d3 47#import <QuartzCore/CALayer.h>
e057ec05 48
d210b85d
JF
49#import <UIKit/UIActionSheet.h>
50#import <UIKit/UIAnimator.h>
51#import <UIKit/UIApplication.h>
52#import <UIKit/UIColor.h>
53#import <UIKit/UIFieldEditor.h>
54#import <UIKit/UIFrameAnimation.h>
55#import <UIKit/UIHardware.h>
56#import <UIKit/UIImage.h>
57#import <UIKit/UIImageAndTextTableCell.h>
58#import <UIKit/UIImageView.h>
59#import <UIKit/UIKeyboard.h>
60#import <UIKit/UIKeyboardImpl.h>
61#import <UIKit/UINavigationBar.h>
62#import <UIKit/UINavigationItem.h>
63#import <UIKit/UIPreferencesTable.h>
64#import <UIKit/UIPreferencesTableCell.h>
65#import <UIKit/UIProgressBar.h>
66#import <UIKit/UIProgressHUD.h>
67#import <UIKit/UIProgressIndicator.h>
68#import <UIKit/UIPushButton.h>
69#import <UIKit/UISearchField.h>
70#import <UIKit/UISimpleTableCell.h>
71#import <UIKit/_UISwitchSlider.h>
72#import <UIKit/UITableCell.h>
73#import <UIKit/UITableColumn.h>
74#import <UIKit/UITextField.h>
75#import <UIKit/UITextInputTraits.h>
76#import <UIKit/UITextLabel.h>
77#import <UIKit/UITextView.h>
78#import <UIKit/UIToolbar.h>
79#import <UIKit/UITransitionView.h>
80#import <UIKit/UIWebDocumentView.h>
81#import <UIKit/UIWebView.h>
82#import <UIKit/UIWindow.h>
83
84#import <UIKit/UIView-Geometry.h>
853d14d3 85#import <UIKit/UIView-Gestures.h>
d210b85d
JF
86#import <UIKit/UIView-Hierarchy.h>
87#import <UIKit/UIView-Rendering.h>
88
853d14d3
JF
89#import <UIKit/UIWebDocumentView-Forms.h>
90
d210b85d
JF
91#import <UIKit/NSString-UIStringDrawing.h>
92
93// XXX: remove
94#import <UIKit/UIActionSheet-Private.h>
95#import <UIKit/UIControl-UIControlPrivate.h>
96#import <UIKit/UIImage-UIImageDeprecated.h>
97#import <UIKit/UIImage-UIImagePrivate.h>
98#import <UIKit/UINavigationBar-Static.h>
99#import <UIKit/UIProgressHUD-Deprecated.h>
100#import <UIKit/UIToolbar-UIButtonBarPrivate.h>
101#import <UIKit/UIView-Deprecated.h>
102#import <UIKit/UIWindow-Static.h>
103
104// XXX: remove
105#import <UIKit/NSString-UIStringDrawingDeprecated.h>
77f175ac 106
e057ec05
JF
107#include <WebKit/WebFrame.h>
108#include <WebKit/WebView.h>
9856894f 109
4941f41d 110#include <sstream>
8993ad57
JF
111#include <string>
112
4941f41d
JF
113#include <ext/stdio_filebuf.h>
114
a75f53e7
JF
115#include <apt-pkg/acquire.h>
116#include <apt-pkg/acquire-item.h>
117#include <apt-pkg/algorithms.h>
118#include <apt-pkg/cachefile.h>
d72d91aa 119#include <apt-pkg/clean.h>
a75f53e7 120#include <apt-pkg/configuration.h>
2d28b35a 121#include <apt-pkg/debmetaindex.h>
a75f53e7
JF
122#include <apt-pkg/error.h>
123#include <apt-pkg/init.h>
1eb0c554 124#include <apt-pkg/mmap.h>
a75f53e7 125#include <apt-pkg/pkgrecords.h>
1eb0c554 126#include <apt-pkg/sha1.h>
a75f53e7 127#include <apt-pkg/sourcelist.h>
4941f41d 128#include <apt-pkg/sptr.h>
a75f53e7 129
2d28b35a 130#include <sys/sysctl.h>
fc675b93 131#include <notify.h>
1eb0c554 132#include <dlfcn.h>
2d28b35a 133
686e302f
JF
134extern "C" {
135#include <mach-o/nlist.h>
136}
137
8993ad57
JF
138#include <cstdio>
139#include <cstdlib>
140#include <cstring>
686e302f 141
4941f41d 142#include <errno.h>
a75f53e7 143#include <pcre.h>
d210b85d
JF
144
145#define UIWebView UIWebDocumentView
146
147#import "BrowserView.h"
148#import "ResetView.h"
149#import "UICaboodle.h"
a75f53e7 150/* }}} */
2d28b35a 151
853d14d3
JF
152@interface WebView (Cydia)
153- (void) _setLayoutInterval:(float)interval;
154@end
155
c045fc11
JF
156/* iPhoneOS 2.0 Compatibility {{{ */
157#ifdef __OBJC2__
158@interface UICGColor : NSObject {
159}
160
161- (id) initWithCGColor:(CGColorRef)color;
162@end
163
164@interface UIFont {
165}
166
5e563e79
JF
167+ (id)systemFontOfSize:(float)fp8;
168+ (id)boldSystemFontOfSize:(float)fp8;
c045fc11
JF
169- (UIFont *) fontWithSize:(CGFloat)size;
170@end
171
172@interface NSObject (iPhoneOS)
173- (CGColorRef) cgColor;
171bba0e 174- (CGColorRef) CGColor;
c045fc11
JF
175- (void) set;
176@end
177
178@implementation NSObject (iPhoneOS)
179
180- (CGColorRef) cgColor {
171bba0e
JF
181 return [self CGColor];
182}
183
184- (CGColorRef) CGColor {
c045fc11
JF
185 return (CGColorRef) self;
186}
187
188- (void) set {
171bba0e 189 [[[[objc_getClass("UICGColor") alloc] initWithCGColor:[self CGColor]] autorelease] set];
c045fc11
JF
190}
191
192@end
193
194@interface UITextView (iPhoneOS)
195- (void) setTextSize:(float)size;
196@end
197
198@implementation UITextView (iPhoneOS)
199
200- (void) setTextSize:(float)size {
201 [self setFont:[[self font] fontWithSize:size]];
202}
203
204@end
242bcc6d 205#endif
c045fc11 206/* }}} */
242bcc6d 207
03a2893d
JF
208@interface UIApplication (IdleTimer)
209- (void) setIdleTimerDisabled:(char)arg0;
210@end
211
d210b85d
JF
212extern "C" int UIApplicationMain(int argc, char *argv[], NSString *principalClassName, NSString *delegateClassName);
213
214extern NSString *kUIButtonBarButtonAction;
215extern NSString *kUIButtonBarButtonInfo;
216extern NSString *kUIButtonBarButtonInfoOffset;
217extern NSString *kUIButtonBarButtonSelectedInfo;
218extern NSString *kUIButtonBarButtonStyle;
219extern NSString *kUIButtonBarButtonTag;
220extern NSString *kUIButtonBarButtonTarget;
221extern NSString *kUIButtonBarButtonTitle;
222extern NSString *kUIButtonBarButtonTitleVerticalHeight;
223extern NSString *kUIButtonBarButtonTitleWidth;
224extern NSString *kUIButtonBarButtonType;
225
81ab76dc 226typedef enum {
1eb0c554 227 kUIProgressIndicatorStyleLargeWhite = 0,
81ab76dc 228 kUIProgressIndicatorStyleMediumWhite = 1,
1eb0c554 229 kUIProgressIndicatorStyleSmallWhite = 3,
81ab76dc
JF
230 kUIProgressIndicatorStyleSmallBlack = 4
231} UIProgressIndicatorStyle;
81ab76dc 232
238b07ce
JF
233typedef enum {
234 kUIControlEventMouseDown = 1 << 0,
235 kUIControlEventMouseMovedInside = 1 << 2, // mouse moved inside control target
236 kUIControlEventMouseMovedOutside = 1 << 3, // mouse moved outside control target
237 kUIControlEventMouseUpInside = 1 << 6, // mouse up inside control target
238 kUIControlEventMouseUpOutside = 1 << 7, // mouse up outside control target
239 kUIControlAllEvents = (kUIControlEventMouseDown | kUIControlEventMouseMovedInside | kUIControlEventMouseMovedOutside | kUIControlEventMouseUpInside | kUIControlEventMouseUpOutside)
240} UIControlEventMasks;
241
2a987aa5
JF
242@interface NSString (UIKit)
243- (NSString *) stringByAddingPercentEscapes;
244- (NSString *) stringByReplacingCharacter:(unsigned short)arg0 withCharacter:(unsigned short)arg1;
245@end
246
247@interface NSString (Cydia)
248+ (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length;
9e07091a 249- (NSComparisonResult) compareByPath:(NSString *)other;
2a987aa5
JF
250@end
251
252@implementation NSString (Cydia)
253
254+ (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length {
255 char data[length + 1];
256 memcpy(data, bytes, length);
257 data[length] = '\0';
258 return [NSString stringWithUTF8String:data];
259}
260
9e07091a
JF
261- (NSComparisonResult) compareByPath:(NSString *)other {
262 NSString *prefix = [self commonPrefixWithString:other options:0];
263 size_t length = [prefix length];
264
265 NSRange lrange = NSMakeRange(length, [self length] - length);
266 NSRange rrange = NSMakeRange(length, [other length] - length);
267
268 lrange = [self rangeOfString:@"/" options:0 range:lrange];
269 rrange = [other rangeOfString:@"/" options:0 range:rrange];
270
271 NSComparisonResult value;
272
273 if (lrange.location == NSNotFound && rrange.location == NSNotFound)
274 value = NSOrderedSame;
275 else if (lrange.location == NSNotFound)
276 value = NSOrderedAscending;
277 else if (rrange.location == NSNotFound)
278 value = NSOrderedDescending;
279 else
280 value = NSOrderedSame;
281
282 NSString *lpath = lrange.location == NSNotFound ? [self substringFromIndex:length] :
283 [self substringWithRange:NSMakeRange(length, lrange.location - length)];
284 NSString *rpath = rrange.location == NSNotFound ? [other substringFromIndex:length] :
285 [other substringWithRange:NSMakeRange(length, rrange.location - length)];
286
287 NSComparisonResult result = [lpath compare:rpath];
288 return result == NSOrderedSame ? value : result;
289}
290
2a987aa5
JF
291@end
292
686e302f
JF
293/* Perl-Compatible RegEx {{{ */
294class Pcre {
295 private:
296 pcre *code_;
297 pcre_extra *study_;
298 int capture_;
299 int *matches_;
300 const char *data_;
301
302 public:
303 Pcre(const char *regex) :
304 study_(NULL)
305 {
306 const char *error;
307 int offset;
308 code_ = pcre_compile(regex, 0, &error, &offset, NULL);
309
310 if (code_ == NULL) {
311 fprintf(stderr, "%d:%s\n", offset, error);
312 _assert(false);
313 }
314
315 pcre_fullinfo(code_, study_, PCRE_INFO_CAPTURECOUNT, &capture_);
316 matches_ = new int[(capture_ + 1) * 3];
317 }
318
319 ~Pcre() {
320 pcre_free(code_);
321 delete matches_;
322 }
323
324 NSString *operator [](size_t match) {
2a987aa5 325 return [NSString stringWithUTF8Bytes:(data_ + matches_[match * 2]) length:(matches_[match * 2 + 1] - matches_[match * 2])];
686e302f
JF
326 }
327
7600bd69
JF
328 bool operator ()(NSString *data) {
329 // XXX: length is for characters, not for bytes
330 return operator ()([data UTF8String], [data length]);
331 }
332
686e302f
JF
333 bool operator ()(const char *data, size_t size) {
334 data_ = data;
335 return pcre_exec(code_, study_, data, size, 0, 0, matches_, (capture_ + 1) * 3) >= 0;
336 }
337};
338/* }}} */
e057ec05 339/* Mime Addresses {{{ */
e057ec05
JF
340@interface Address : NSObject {
341 NSString *name_;
ad554f10 342 NSString *address_;
e057ec05
JF
343}
344
345- (NSString *) name;
ad554f10 346- (NSString *) address;
e057ec05
JF
347
348+ (Address *) addressWithString:(NSString *)string;
349- (Address *) initWithString:(NSString *)string;
350@end
351
352@implementation Address
353
354- (void) dealloc {
355 [name_ release];
ad554f10
JF
356 if (address_ != nil)
357 [address_ release];
e057ec05
JF
358 [super dealloc];
359}
360
361- (NSString *) name {
362 return name_;
363}
364
ad554f10
JF
365- (NSString *) address {
366 return address_;
e057ec05
JF
367}
368
369+ (Address *) addressWithString:(NSString *)string {
370 return [[[Address alloc] initWithString:string] autorelease];
371}
372
ad554f10
JF
373+ (NSArray *) _attributeKeys {
374 return [NSArray arrayWithObjects:@"address", @"name", nil];
375}
376
377- (NSArray *) attributeKeys {
378 return [[self class] _attributeKeys];
379}
380
381+ (BOOL) isKeyExcludedFromWebScript:(const char *)name {
382 return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name];
383}
384
e057ec05
JF
385- (Address *) initWithString:(NSString *)string {
386 if ((self = [super init]) != nil) {
387 const char *data = [string UTF8String];
388 size_t size = [string length];
389
ad554f10 390 static Pcre address_r("^\"?(.*)\"? <([^>]*)>$");
faf4eb4f 391
ad554f10
JF
392 if (address_r(data, size)) {
393 name_ = [address_r[1] retain];
394 address_ = [address_r[2] retain];
e057ec05 395 } else {
2a987aa5
JF
396 name_ = [[NSString alloc]
397 initWithBytes:data
398 length:size
399 encoding:kCFStringEncodingUTF8
400 ];
401
ad554f10 402 address_ = nil;
e057ec05
JF
403 }
404 } return self;
405}
406
407@end
408/* }}} */
b0d03ade 409/* CoreGraphics Primitives {{{ */
686e302f
JF
410class CGColor {
411 private:
412 CGColorRef color_;
413
414 public:
e057ec05
JF
415 CGColor() :
416 color_(NULL)
417 {
418 }
419
420 CGColor(CGColorSpaceRef space, float red, float green, float blue, float alpha) :
421 color_(NULL)
422 {
423 Set(space, red, green, blue, alpha);
424 }
425
426 void Clear() {
427 if (color_ != NULL)
428 CGColorRelease(color_);
686e302f
JF
429 }
430
431 ~CGColor() {
e057ec05
JF
432 Clear();
433 }
434
435 void Set(CGColorSpaceRef space, float red, float green, float blue, float alpha) {
436 Clear();
437 float color[] = {red, green, blue, alpha};
438 color_ = CGColorCreate(space, color);
686e302f
JF
439 }
440
441 operator CGColorRef() {
442 return color_;
443 }
444};
445
446class GSFont {
447 private:
448 GSFontRef font_;
449
450 public:
451 ~GSFont() {
686e302f
JF
452 CFRelease(font_);
453 }
454};
455/* }}} */
456
5e563e79
JF
457extern "C" void UISetColor(CGColorRef color);
458
e057ec05 459/* Random Global Variables {{{ */
2d28b35a 460static const int PulseInterval_ = 50000;
2a987aa5 461static const int ButtonBarHeight_ = 48;
fa7bb92f 462static const float KeyboardTime_ = 0.3f;
238b07ce 463static const char * const SpringBoard_ = "/System/Library/LaunchDaemons/com.apple.SpringBoard.plist";
fc675b93 464
5e563e79 465static CGColor Blue_;
d72d91aa 466static CGColor Blueish_;
e057ec05
JF
467static CGColor Black_;
468static CGColor Clear_;
469static CGColor Red_;
470static CGColor White_;
faf4eb4f 471static CGColor Gray_;
e057ec05 472
853d14d3 473static NSString *App_;
0039464f
JF
474static NSString *Home_;
475static BOOL Sounds_Keyboard_;
476
2a987aa5 477static BOOL Advanced_;
ad554f10 478static BOOL Loaded_;
9e07091a 479static BOOL Ignored_;
2a987aa5 480
5e563e79
JF
481static UIFont *Font12_;
482static UIFont *Font12Bold_;
483static UIFont *Font14_;
484static UIFont *Font18Bold_;
485static UIFont *Font22Bold_;
486
fc675b93 487const char *Firmware_ = NULL;
2d28b35a
JF
488const char *Machine_ = NULL;
489const char *SerialNumber_ = NULL;
490
fc675b93
JF
491unsigned Major_;
492unsigned Minor_;
493unsigned BugFix_;
494
b27f0a94 495CFLocaleRef Locale_;
e057ec05
JF
496CGColorSpaceRef space_;
497
fc675b93 498#define FW_LEAST(major, minor, bugfix) \
584f58f8
JF
499 (major < Major_ || major == Major_ && \
500 (minor < Minor_ || minor == Minor_ && \
501 bugfix <= BugFix_))
fc675b93 502
e057ec05 503bool bootstrap_;
d72d91aa 504bool reload_;
df5a7529 505
d1494d2c 506static NSDictionary *SectionMap_;
686e302f 507static NSMutableDictionary *Metadata_;
faf4eb4f
JF
508static _transient NSMutableDictionary *Settings_;
509static _transient NSString *Role_;
510static _transient NSMutableDictionary *Packages_;
511static _transient NSMutableDictionary *Sections_;
512static _transient NSMutableDictionary *Sources_;
3d37fc0d 513static bool Changed_;
686e302f 514static NSDate *now_;
20dd7407 515
3a83ebf7
JF
516NSString *GetLastUpdate() {
517 NSDate *update = [Metadata_ objectForKey:@"LastUpdate"];
518
519 if (update == nil)
520 return @"Never or Unknown";
521
b27f0a94 522 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, Locale_, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
3a83ebf7
JF
523 CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) update);
524
525 CFRelease(formatter);
3a83ebf7
JF
526
527 return [(NSString *) formatted autorelease];
528}
e057ec05
JF
529/* }}} */
530/* Display Helpers {{{ */
531inline float Interpolate(float begin, float end, float fraction) {
532 return (end - begin) * fraction + begin;
533}
4941f41d 534
b6ffa083
JF
535NSString *SizeString(double size) {
536 unsigned power = 0;
537 while (size > 1024) {
538 size /= 1024;
539 ++power;
540 }
541
542 static const char *powers_[] = {"B", "kB", "MB", "GB"};
543
544 return [NSString stringWithFormat:@"%.1f%s", size, powers_[power]];
545}
546
238b07ce
JF
547NSString *StripVersion(NSString *version) {
548 NSRange colon = [version rangeOfString:@":"];
549 if (colon.location != NSNotFound)
550 version = [version substringFromIndex:(colon.location + 1)];
551 return version;
552}
553
686e302f
JF
554static const float TextViewOffset_ = 22;
555
556UITextView *GetTextView(NSString *value, float left, bool html) {
557 UITextView *text([[[UITextView alloc] initWithFrame:CGRectMake(left, 3, 310 - left, 1000)] autorelease]);
558 [text setEditable:NO];
559 [text setTextSize:16];
c045fc11 560 /*if (html)
686e302f 561 [text setHTML:value];
c045fc11 562 else*/
686e302f
JF
563 [text setText:value];
564 [text setEnabled:NO];
565
d210b85d 566 [text setBackgroundColor:[UIColor colorWithCGColor:Clear_]];
686e302f
JF
567
568 CGRect frame = [text frame];
569 [text setFrame:frame];
570 CGRect rect = [text visibleTextRect];
571 frame.size.height = rect.size.height;
572 [text setFrame:frame];
573
574 return text;
575}
49525fb2
JF
576
577NSString *Simplify(NSString *title) {
578 const char *data = [title UTF8String];
579 size_t size = [title length];
580
faf4eb4f
JF
581 static Pcre square_r("^\\[(.*)\\]$");
582 if (square_r(data, size))
583 return Simplify(square_r[1]);
584
585 static Pcre paren_r("^\\((.*)\\)$");
586 if (paren_r(data, size))
587 return Simplify(paren_r[1]);
588
589 static Pcre title_r("^(.*?) \\(.*\\)$");
49525fb2 590 if (title_r(data, size))
faf4eb4f
JF
591 return Simplify(title_r[1]);
592
593 return title;
49525fb2 594}
e057ec05
JF
595/* }}} */
596
fa7bb92f
JF
597bool isSectionVisible(NSString *section) {
598 NSDictionary *metadata = [Sections_ objectForKey:section];
599 NSNumber *hidden = metadata == nil ? nil : [metadata objectForKey:@"Hidden"];
600 return hidden == nil || ![hidden boolValue];
601}
602
a0e1b888 603/* Delegate Prototypes {{{ */
e057ec05
JF
604@class Package;
605@class Source;
606
238b07ce
JF
607@interface NSObject (ProgressDelegate)
608@end
609
610@implementation NSObject(ProgressDelegate)
611
612- (void) _setProgressError:(NSArray *)args {
613 [self performSelector:@selector(setProgressError:forPackage:)
614 withObject:[args objectAtIndex:0]
615 withObject:([args count] == 1 ? nil : [args objectAtIndex:1])
616 ];
617}
618
619@end
620
e057ec05 621@protocol ProgressDelegate
238b07ce 622- (void) setProgressError:(NSString *)error forPackage:(NSString *)id;
e057ec05
JF
623- (void) setProgressTitle:(NSString *)title;
624- (void) setProgressPercent:(float)percent;
625- (void) addProgressOutput:(NSString *)output;
626@end
627
7600bd69 628@protocol ConfigurationDelegate
965edd52 629- (void) repairWithSelector:(SEL)selector;
7600bd69
JF
630- (void) setConfigurationData:(NSString *)data;
631@end
632
e057ec05
JF
633@protocol CydiaDelegate
634- (void) installPackage:(Package *)package;
635- (void) removePackage:(Package *)package;
d210b85d 636- (void) slideUp:(UIActionSheet *)alert;
e057ec05 637- (void) distUpgrade;
fa7bb92f 638- (void) updateData;
faf4eb4f
JF
639- (void) syncData;
640- (void) askForSettings;
641- (UIProgressHUD *) addProgressHUD;
e057ec05 642@end
a0e1b888 643/* }}} */
686e302f 644
a75f53e7
JF
645/* Status Delegation {{{ */
646class Status :
647 public pkgAcquireStatus
648{
649 private:
238b07ce 650 _transient NSObject<ProgressDelegate> *delegate_;
a75f53e7
JF
651
652 public:
653 Status() :
654 delegate_(nil)
655 {
656 }
657
658 void setDelegate(id delegate) {
659 delegate_ = delegate;
660 }
661
662 virtual bool MediaChange(std::string media, std::string drive) {
663 return false;
664 }
665
666 virtual void IMSHit(pkgAcquire::ItemDesc &item) {
a75f53e7
JF
667 }
668
669 virtual void Fetch(pkgAcquire::ItemDesc &item) {
2a987aa5 670 [delegate_ setProgressTitle:[NSString stringWithUTF8String:("Downloading " + item.ShortDesc).c_str()]];
a75f53e7
JF
671 }
672
673 virtual void Done(pkgAcquire::ItemDesc &item) {
a75f53e7
JF
674 }
675
676 virtual void Fail(pkgAcquire::ItemDesc &item) {
3325a005
JF
677 if (
678 item.Owner->Status == pkgAcquire::Item::StatIdle ||
679 item.Owner->Status == pkgAcquire::Item::StatDone
680 )
681 return;
682
238b07ce
JF
683 [delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
684 withObject:[NSArray arrayWithObjects:[NSString stringWithUTF8String:item.Owner->ErrorText.c_str()], nil]
685 waitUntilDone:YES
686 ];
a75f53e7
JF
687 }
688
689 virtual bool Pulse(pkgAcquire *Owner) {
4941f41d
JF
690 bool value = pkgAcquireStatus::Pulse(Owner);
691
692 float percent(
693 double(CurrentBytes + CurrentItems) /
694 double(TotalBytes + TotalItems)
695 );
696
e057ec05 697 [delegate_ setProgressPercent:percent];
4941f41d 698 return value;
a75f53e7
JF
699 }
700
701 virtual void Start() {
a75f53e7
JF
702 }
703
704 virtual void Stop() {
a75f53e7
JF
705 }
706};
707/* }}} */
708/* Progress Delegation {{{ */
709class Progress :
710 public OpProgress
711{
712 private:
e057ec05 713 _transient id<ProgressDelegate> delegate_;
a75f53e7
JF
714
715 protected:
716 virtual void Update() {
2a987aa5 717 [delegate_ setProgressTitle:[NSString stringWithUTF8String:Op.c_str()]];
e057ec05 718 [delegate_ setProgressPercent:(Percent / 100)];
a75f53e7
JF
719 }
720
721 public:
722 Progress() :
723 delegate_(nil)
724 {
725 }
726
727 void setDelegate(id delegate) {
728 delegate_ = delegate;
729 }
730
731 virtual void Done() {
e057ec05 732 [delegate_ setProgressPercent:1];
a75f53e7
JF
733 }
734};
735/* }}} */
736
e057ec05
JF
737/* Database Interface {{{ */
738@interface Database : NSObject {
739 pkgCacheFile cache_;
965edd52 740 pkgDepCache::Policy *policy_;
e057ec05
JF
741 pkgRecords *records_;
742 pkgProblemResolver *resolver_;
743 pkgAcquire *fetcher_;
744 FileFd *lock_;
745 SPtr<pkgPackageManager> manager_;
746 pkgSourceList *list_;
b0d03ade 747
e057ec05
JF
748 NSMutableDictionary *sources_;
749 NSMutableArray *packages_;
686e302f 750
238b07ce 751 _transient NSObject<ConfigurationDelegate, ProgressDelegate> *delegate_;
e057ec05
JF
752 Status status_;
753 Progress progress_;
7600bd69 754
d72d91aa 755 int cydiafd_;
e057ec05 756 int statusfd_;
7600bd69 757 FILE *input_;
a75f53e7
JF
758}
759
d72d91aa 760- (void) _readCydia:(NSNumber *)fd;
e057ec05
JF
761- (void) _readStatus:(NSNumber *)fd;
762- (void) _readOutput:(NSNumber *)fd;
4941f41d 763
7600bd69
JF
764- (FILE *) input;
765
e057ec05 766- (Package *) packageWithName:(NSString *)name;
a75f53e7 767
e057ec05
JF
768- (Database *) init;
769- (pkgCacheFile &) cache;
965edd52 770- (pkgDepCache::Policy *) policy;
e057ec05
JF
771- (pkgRecords *) records;
772- (pkgProblemResolver *) resolver;
773- (pkgAcquire &) fetcher;
774- (NSArray *) packages;
faf4eb4f 775- (NSArray *) sources;
e057ec05
JF
776- (void) reloadData;
777
965edd52 778- (void) configure;
e057ec05
JF
779- (void) prepare;
780- (void) perform;
781- (void) upgrade;
782- (void) update;
783
784- (void) updateWithStatus:(Status &)status;
785
786- (void) setDelegate:(id)delegate;
787- (Source *) getSource:(const pkgCache::PkgFileIterator &)file;
a75f53e7 788@end
e057ec05 789/* }}} */
a75f53e7 790
e057ec05
JF
791/* Source Class {{{ */
792@interface Source : NSObject {
793 NSString *description_;
794 NSString *label_;
795 NSString *origin_;
a75f53e7 796
e057ec05
JF
797 NSString *uri_;
798 NSString *distribution_;
799 NSString *type_;
800 NSString *version_;
4941f41d 801
e057ec05 802 NSString *defaultIcon_;
a75f53e7 803
faf4eb4f 804 NSDictionary *record_;
e057ec05 805 BOOL trusted_;
a75f53e7
JF
806}
807
e057ec05 808- (Source *) initWithMetaIndex:(metaIndex *)index;
a75f53e7 809
faf4eb4f
JF
810- (NSComparisonResult) compareByNameAndType:(Source *)source;
811
812- (NSDictionary *) record;
e057ec05 813- (BOOL) trusted;
a75f53e7 814
e057ec05
JF
815- (NSString *) uri;
816- (NSString *) distribution;
817- (NSString *) type;
faf4eb4f
JF
818- (NSString *) key;
819- (NSString *) host;
e057ec05 820
faf4eb4f 821- (NSString *) name;
e057ec05
JF
822- (NSString *) description;
823- (NSString *) label;
824- (NSString *) origin;
825- (NSString *) version;
a75f53e7 826
e057ec05 827- (NSString *) defaultIcon;
faf4eb4f 828
a75f53e7 829@end
a75f53e7 830
e057ec05 831@implementation Source
a75f53e7 832
e057ec05
JF
833- (void) dealloc {
834 [uri_ release];
835 [distribution_ release];
836 [type_ release];
a75f53e7 837
e057ec05
JF
838 if (description_ != nil)
839 [description_ release];
840 if (label_ != nil)
841 [label_ release];
842 if (origin_ != nil)
843 [origin_ release];
844 if (version_ != nil)
845 [version_ release];
846 if (defaultIcon_ != nil)
847 [defaultIcon_ release];
faf4eb4f
JF
848 if (record_ != nil)
849 [record_ release];
a75f53e7 850
e057ec05 851 [super dealloc];
a75f53e7
JF
852}
853
ad554f10
JF
854+ (NSArray *) _attributeKeys {
855 return [NSArray arrayWithObjects:@"description", @"distribution", @"host", @"key", @"label", @"name", @"origin", @"trusted", @"type", @"uri", @"version", nil];
856}
857
858- (NSArray *) attributeKeys {
859 return [[self class] _attributeKeys];
860}
861
862+ (BOOL) isKeyExcludedFromWebScript:(const char *)name {
863 return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name];
864}
865
e057ec05
JF
866- (Source *) initWithMetaIndex:(metaIndex *)index {
867 if ((self = [super init]) != nil) {
868 trusted_ = index->IsTrusted();
a75f53e7 869
2a987aa5
JF
870 uri_ = [[NSString stringWithUTF8String:index->GetURI().c_str()] retain];
871 distribution_ = [[NSString stringWithUTF8String:index->GetDist().c_str()] retain];
872 type_ = [[NSString stringWithUTF8String:index->GetType()] retain];
a75f53e7 873
e057ec05
JF
874 debReleaseIndex *dindex(dynamic_cast<debReleaseIndex *>(index));
875 if (dindex != NULL) {
876 std::ifstream release(dindex->MetaIndexFile("Release").c_str());
877 std::string line;
878 while (std::getline(release, line)) {
879 std::string::size_type colon(line.find(':'));
880 if (colon == std::string::npos)
881 continue;
a75f53e7 882
e057ec05
JF
883 std::string name(line.substr(0, colon));
884 std::string value(line.substr(colon + 1));
885 while (!value.empty() && value[0] == ' ')
886 value = value.substr(1);
a75f53e7 887
e057ec05 888 if (name == "Default-Icon")
2a987aa5 889 defaultIcon_ = [[NSString stringWithUTF8String:value.c_str()] retain];
e057ec05 890 else if (name == "Description")
2a987aa5 891 description_ = [[NSString stringWithUTF8String:value.c_str()] retain];
e057ec05 892 else if (name == "Label")
2a987aa5 893 label_ = [[NSString stringWithUTF8String:value.c_str()] retain];
e057ec05 894 else if (name == "Origin")
2a987aa5 895 origin_ = [[NSString stringWithUTF8String:value.c_str()] retain];
e057ec05 896 else if (name == "Version")
2a987aa5 897 version_ = [[NSString stringWithUTF8String:value.c_str()] retain];
e057ec05
JF
898 }
899 }
faf4eb4f
JF
900
901 record_ = [Sources_ objectForKey:[self key]];
902 if (record_ != nil)
903 record_ = [record_ retain];
e057ec05 904 } return self;
4941f41d 905}
a75f53e7 906
faf4eb4f
JF
907- (NSComparisonResult) compareByNameAndType:(Source *)source {
908 NSDictionary *lhr = [self record];
909 NSDictionary *rhr = [source record];
910
911 if (lhr != rhr)
912 return lhr == nil ? NSOrderedDescending : NSOrderedAscending;
913
914 NSString *lhs = [self name];
915 NSString *rhs = [source name];
916
917 if ([lhs length] != 0 && [rhs length] != 0) {
918 unichar lhc = [lhs characterAtIndex:0];
919 unichar rhc = [rhs characterAtIndex:0];
920
921 if (isalpha(lhc) && !isalpha(rhc))
922 return NSOrderedAscending;
923 else if (!isalpha(lhc) && isalpha(rhc))
924 return NSOrderedDescending;
925 }
926
927 return [lhs caseInsensitiveCompare:rhs];
928}
929
930- (NSDictionary *) record {
931 return record_;
932}
933
e057ec05
JF
934- (BOOL) trusted {
935 return trusted_;
936}
2d28b35a 937
e057ec05
JF
938- (NSString *) uri {
939 return uri_;
940}
1cb11c5f 941
e057ec05
JF
942- (NSString *) distribution {
943 return distribution_;
944}
a75f53e7 945
e057ec05
JF
946- (NSString *) type {
947 return type_;
a75f53e7
JF
948}
949
faf4eb4f
JF
950- (NSString *) key {
951 return [NSString stringWithFormat:@"%@:%@:%@", type_, uri_, distribution_];
952}
953
954- (NSString *) host {
955 return [[[NSURL URLWithString:[self uri]] host] lowercaseString];
956}
957
958- (NSString *) name {
959 return origin_ == nil ? [self host] : origin_;
960}
961
e057ec05
JF
962- (NSString *) description {
963 return description_;
964}
686e302f 965
e057ec05 966- (NSString *) label {
faf4eb4f 967 return label_ == nil ? [self host] : label_;
e057ec05 968}
2d28b35a 969
e057ec05
JF
970- (NSString *) origin {
971 return origin_;
972}
2d28b35a 973
e057ec05
JF
974- (NSString *) version {
975 return version_;
976}
4941f41d 977
e057ec05
JF
978- (NSString *) defaultIcon {
979 return defaultIcon_;
980}
4941f41d 981
2a987aa5
JF
982@end
983/* }}} */
984/* Relationship Class {{{ */
985@interface Relationship : NSObject {
986 NSString *type_;
987 NSString *id_;
988}
989
990- (NSString *) type;
991- (NSString *) id;
992- (NSString *) name;
993
994@end
995
996@implementation Relationship
997
998- (void) dealloc {
999 [type_ release];
1000 [id_ release];
1001 [super dealloc];
1002}
1003
1004- (NSString *) type {
1005 return type_;
1006}
1007
1008- (NSString *) id {
1009 return id_;
1010}
1011
1012- (NSString *) name {
1013 _assert(false);
1014 return nil;
1015}
1016
a75f53e7 1017@end
686e302f 1018/* }}} */
e057ec05
JF
1019/* Package Class {{{ */
1020NSString *Scour(const char *field, const char *begin, const char *end) {
1021 size_t i(0), l(strlen(field));
a75f53e7 1022
e057ec05
JF
1023 for (;;) {
1024 const char *name = begin + i;
1025 const char *colon = name + l;
1026 const char *value = colon + 1;
7e986211 1027
e057ec05
JF
1028 if (
1029 value < end &&
1030 *colon == ':' &&
1031 memcmp(name, field, l) == 0
1032 ) {
1033 while (value != end && value[0] == ' ')
1034 ++value;
1035 const char *line = std::find(value, end, '\n');
1036 while (line != value && line[-1] == ' ')
1037 --line;
2a987aa5
JF
1038
1039 return [NSString stringWithUTF8Bytes:value length:(line - value)];
e057ec05
JF
1040 } else {
1041 begin = std::find(begin, end, '\n');
1042 if (begin == end)
1043 return nil;
1044 ++begin;
1045 }
1046 }
1047}
686e302f 1048
e057ec05
JF
1049@interface Package : NSObject {
1050 pkgCache::PkgIterator iterator_;
1051 _transient Database *database_;
1052 pkgCache::VerIterator version_;
1053 pkgCache::VerFileIterator file_;
3d37fc0d 1054
e057ec05 1055 Source *source_;
3d37fc0d 1056 bool cached_;
a75f53e7 1057
e057ec05
JF
1058 NSString *latest_;
1059 NSString *installed_;
a75f53e7 1060
e057ec05
JF
1061 NSString *id_;
1062 NSString *name_;
1063 NSString *tagline_;
1064 NSString *icon_;
ad554f10 1065 NSString *homepage_;
0235116c 1066 NSString *depiction_;
81ab76dc 1067 Address *sponsor_;
d72d91aa 1068 Address *author_;
fa7bb92f 1069 NSArray *tags_;
faf4eb4f 1070 NSString *role_;
2a987aa5
JF
1071
1072 NSArray *relationships_;
686e302f
JF
1073}
1074
965edd52 1075- (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
e057ec05 1076+ (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database;
686e302f 1077
2a987aa5
JF
1078- (pkgCache::PkgIterator) iterator;
1079
e057ec05
JF
1080- (NSString *) section;
1081- (Address *) maintainer;
1082- (size_t) size;
1083- (NSString *) description;
1084- (NSString *) index;
a75f53e7 1085
e057ec05 1086- (NSDate *) seen;
63a1e4b8 1087
e057ec05
JF
1088- (NSString *) latest;
1089- (NSString *) installed;
965edd52
JF
1090
1091- (BOOL) valid;
238b07ce 1092- (BOOL) upgradableAndEssential:(BOOL)essential;
e057ec05
JF
1093- (BOOL) essential;
1094- (BOOL) broken;
853d14d3 1095- (BOOL) unfiltered;
fa7bb92f 1096- (BOOL) visible;
686e302f 1097
3319715b
JF
1098- (BOOL) half;
1099- (BOOL) halfConfigured;
1100- (BOOL) halfInstalled;
1101- (BOOL) hasMode;
1102- (NSString *) mode;
1103
e057ec05
JF
1104- (NSString *) id;
1105- (NSString *) name;
1106- (NSString *) tagline;
1107- (NSString *) icon;
ad554f10 1108- (NSString *) homepage;
0235116c 1109- (NSString *) depiction;
d72d91aa 1110- (Address *) author;
686e302f 1111
2a987aa5
JF
1112- (NSArray *) relationships;
1113
e057ec05 1114- (Source *) source;
faf4eb4f 1115- (NSString *) role;
686e302f 1116
e057ec05 1117- (BOOL) matches:(NSString *)text;
686e302f 1118
faf4eb4f 1119- (bool) hasSupportingRole;
fa7bb92f
JF
1120- (BOOL) hasTag:(NSString *)tag;
1121
e057ec05
JF
1122- (NSComparisonResult) compareByName:(Package *)package;
1123- (NSComparisonResult) compareBySection:(Package *)package;
1124- (NSComparisonResult) compareBySectionAndName:(Package *)package;
1125- (NSComparisonResult) compareForChanges:(Package *)package;
686e302f 1126
e057ec05
JF
1127- (void) install;
1128- (void) remove;
7e986211 1129
853d14d3
JF
1130- (NSNumber *) isUnfilteredAndSearchedForBy:(NSString *)search;
1131- (NSNumber *) isInstalledAndUnfiltered:(NSNumber *)number;
faf4eb4f
JF
1132- (NSNumber *) isVisiblyUninstalledInSection:(NSString *)section;
1133- (NSNumber *) isVisibleInSource:(Source *)source;
686e302f 1134
e057ec05 1135@end
686e302f 1136
e057ec05 1137@implementation Package
686e302f 1138
e057ec05 1139- (void) dealloc {
3d37fc0d
JF
1140 if (source_ != nil)
1141 [source_ release];
1142
e057ec05
JF
1143 [latest_ release];
1144 if (installed_ != nil)
1145 [installed_ release];
686e302f 1146
e057ec05
JF
1147 [id_ release];
1148 if (name_ != nil)
1149 [name_ release];
1150 [tagline_ release];
1151 if (icon_ != nil)
1152 [icon_ release];
ad554f10
JF
1153 if (homepage_ != nil)
1154 [homepage_ release];
0235116c
JF
1155 if (depiction_ != nil)
1156 [depiction_ release];
81ab76dc
JF
1157 if (sponsor_ != nil)
1158 [sponsor_ release];
d72d91aa
JF
1159 if (author_ != nil)
1160 [author_ release];
fa7bb92f
JF
1161 if (tags_ != nil)
1162 [tags_ release];
faf4eb4f
JF
1163 if (role_ != nil)
1164 [role_ release];
63a1e4b8 1165
2a987aa5
JF
1166 if (relationships_ != nil)
1167 [relationships_ release];
1168
e057ec05 1169 [super dealloc];
686e302f
JF
1170}
1171
ad554f10 1172+ (NSArray *) _attributeKeys {
0235116c 1173 return [NSArray arrayWithObjects:@"author", @"depiction", @"description", @"essential", @"homepage", @"icon", @"id", @"installed", @"latest", @"maintainer", @"name", @"section", @"size", @"source", @"sponsor", @"tagline", nil];
ad554f10
JF
1174}
1175
1176- (NSArray *) attributeKeys {
1177 return [[self class] _attributeKeys];
1178}
1179
1180+ (BOOL) isKeyExcludedFromWebScript:(const char *)name {
1181 return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name];
1182}
1183
965edd52 1184- (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
e057ec05
JF
1185 if ((self = [super init]) != nil) {
1186 iterator_ = iterator;
1187 database_ = database;
686e302f 1188
965edd52 1189 version_ = [database_ policy]->GetCandidateVer(iterator_);
238b07ce 1190 latest_ = version_.end() ? nil : [StripVersion([NSString stringWithUTF8String:version_.VerStr()]) retain];
3d37fc0d 1191
965edd52
JF
1192 if (!version_.end())
1193 file_ = version_.FileList();
1194 else {
1195 pkgCache &cache([database_ cache]);
1196 file_ = pkgCache::VerFileIterator(cache, cache.VerFileP);
1197 }
686e302f 1198
965edd52 1199 pkgCache::VerIterator current = iterator_.CurrentVer();
238b07ce 1200 installed_ = current.end() ? nil : [StripVersion([NSString stringWithUTF8String:current.VerStr()]) retain];
686e302f 1201
2a987aa5 1202 id_ = [[[NSString stringWithUTF8String:iterator_.Name()] lowercaseString] retain];
965edd52
JF
1203
1204 if (!file_.end()) {
1205 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
1206
1207 const char *begin, *end;
1208 parser->GetRec(begin, end);
1209
1210 name_ = Scour("Name", begin, end);
1211 if (name_ != nil)
1212 name_ = [name_ retain];
1213 tagline_ = [[NSString stringWithUTF8String:parser->ShortDesc().c_str()] retain];
1214 icon_ = Scour("Icon", begin, end);
1215 if (icon_ != nil)
1216 icon_ = [icon_ retain];
ad554f10
JF
1217 homepage_ = Scour("Homepage", begin, end);
1218 if (homepage_ == nil)
1219 homepage_ = Scour("Website", begin, end);
1220 if (homepage_ != nil)
1221 homepage_ = [homepage_ retain];
0235116c
JF
1222 depiction_ = Scour("Depiction", begin, end);
1223 if (depiction_ != nil)
1224 depiction_ = [depiction_ retain];
81ab76dc
JF
1225 NSString *sponsor = Scour("Sponsor", begin, end);
1226 if (sponsor != nil)
1227 sponsor_ = [[Address addressWithString:sponsor] retain];
d72d91aa
JF
1228 NSString *author = Scour("Author", begin, end);
1229 if (author != nil)
81ab76dc 1230 author_ = [[Address addressWithString:author] retain];
fa7bb92f
JF
1231 NSString *tags = Scour("Tag", begin, end);
1232 if (tags != nil)
1233 tags_ = [[tags componentsSeparatedByString:@", "] retain];
965edd52 1234 }
7e986211 1235
faf4eb4f
JF
1236 if (tags_ != nil)
1237 for (int i(0), e([tags_ count]); i != e; ++i) {
1238 NSString *tag = [tags_ objectAtIndex:i];
1239 if ([tag hasPrefix:@"role::"]) {
1240 role_ = [[tag substringFromIndex:6] retain];
1241 break;
1242 }
1243 }
1244
e057ec05
JF
1245 NSMutableDictionary *metadata = [Packages_ objectForKey:id_];
1246 if (metadata == nil || [metadata count] == 0) {
1247 metadata = [NSMutableDictionary dictionaryWithObjectsAndKeys:
1248 now_, @"FirstSeen",
1249 nil];
686e302f 1250
e057ec05 1251 [Packages_ setObject:metadata forKey:id_];
3d37fc0d 1252 Changed_ = true;
e057ec05
JF
1253 }
1254 } return self;
a75f53e7
JF
1255}
1256
e057ec05 1257+ (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
965edd52
JF
1258 return [[[Package alloc]
1259 initWithIterator:iterator
1260 database:database
1261 ] autorelease];
a75f53e7
JF
1262}
1263
2a987aa5
JF
1264- (pkgCache::PkgIterator) iterator {
1265 return iterator_;
1266}
1267
e057ec05
JF
1268- (NSString *) section {
1269 const char *section = iterator_.Section();
faf4eb4f
JF
1270 if (section == NULL)
1271 return nil;
d1494d2c
JF
1272
1273 NSString *name = [[NSString stringWithUTF8String:section] stringByReplacingCharacter:' ' withCharacter:'_'];
1274
1275 lookup:
1276 if (NSDictionary *value = [SectionMap_ objectForKey:name])
1277 if (NSString *rename = [value objectForKey:@"Rename"]) {
1278 name = rename;
1279 goto lookup;
1280 }
1281
1282 return [name stringByReplacingCharacter:'_' withCharacter:' '];
a75f53e7
JF
1283}
1284
e057ec05 1285- (Address *) maintainer {
965edd52
JF
1286 if (file_.end())
1287 return nil;
e057ec05 1288 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
2a987aa5 1289 return [Address addressWithString:[NSString stringWithUTF8String:parser->Maintainer().c_str()]];
b6ffa083
JF
1290}
1291
e057ec05 1292- (size_t) size {
965edd52 1293 return version_.end() ? 0 : version_->InstalledSize;
a75f53e7
JF
1294}
1295
e057ec05 1296- (NSString *) description {
965edd52
JF
1297 if (file_.end())
1298 return nil;
e057ec05 1299 pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
2a987aa5 1300 NSString *description([NSString stringWithUTF8String:parser->LongDesc().c_str()]);
b6ffa083 1301
e057ec05
JF
1302 NSArray *lines = [description componentsSeparatedByString:@"\n"];
1303 NSMutableArray *trimmed = [NSMutableArray arrayWithCapacity:([lines count] - 1)];
1304 if ([lines count] < 2)
1305 return nil;
2d28b35a 1306
e057ec05
JF
1307 NSCharacterSet *whitespace = [NSCharacterSet whitespaceCharacterSet];
1308 for (size_t i(1); i != [lines count]; ++i) {
1309 NSString *trim = [[lines objectAtIndex:i] stringByTrimmingCharactersInSet:whitespace];
1310 [trimmed addObject:trim];
1311 }
2d28b35a 1312
e057ec05
JF
1313 return [trimmed componentsJoinedByString:@"\n"];
1314}
a75f53e7 1315
e057ec05
JF
1316- (NSString *) index {
1317 NSString *index = [[[self name] substringToIndex:1] uppercaseString];
1318 return [index length] != 0 && isalpha([index characterAtIndex:0]) ? index : @"123";
1319}
2d28b35a 1320
e057ec05
JF
1321- (NSDate *) seen {
1322 return [[Packages_ objectForKey:id_] objectForKey:@"FirstSeen"];
2d28b35a
JF
1323}
1324
e057ec05
JF
1325- (NSString *) latest {
1326 return latest_;
b6ffa083
JF
1327}
1328
e057ec05
JF
1329- (NSString *) installed {
1330 return installed_;
2d28b35a
JF
1331}
1332
965edd52
JF
1333- (BOOL) valid {
1334 return !version_.end();
1335}
1336
238b07ce 1337- (BOOL) upgradableAndEssential:(BOOL)essential {
9e07091a
JF
1338 pkgCache::VerIterator current = iterator_.CurrentVer();
1339
1340 if (current.end())
238b07ce 1341 return essential && [self essential];
9e07091a 1342 else {
965edd52 1343 pkgCache::VerIterator candidate = [database_ policy]->GetCandidateVer(iterator_);
9e07091a
JF
1344 return !candidate.end() && candidate != current;
1345 }
e057ec05 1346}
2d28b35a 1347
e057ec05
JF
1348- (BOOL) essential {
1349 return (iterator_->Flags & pkgCache::Flag::Essential) == 0 ? NO : YES;
2d28b35a
JF
1350}
1351
e057ec05 1352- (BOOL) broken {
3319715b
JF
1353 return [database_ cache][iterator_].InstBroken();
1354}
1355
853d14d3 1356- (BOOL) unfiltered {
fa7bb92f 1357 NSString *section = [self section];
853d14d3
JF
1358 return section == nil || isSectionVisible(section);
1359}
1360
1361- (BOOL) visible {
1362 return [self hasSupportingRole] && [self unfiltered];
fa7bb92f
JF
1363}
1364
3319715b
JF
1365- (BOOL) half {
1366 unsigned char current = iterator_->CurrentState;
1367 return current == pkgCache::State::HalfConfigured || current == pkgCache::State::HalfInstalled;
1368}
1369
1370- (BOOL) halfConfigured {
1371 return iterator_->CurrentState == pkgCache::State::HalfConfigured;
1372}
1373
1374- (BOOL) halfInstalled {
1375 return iterator_->CurrentState == pkgCache::State::HalfInstalled;
1376}
1377
1378- (BOOL) hasMode {
1379 pkgDepCache::StateCache &state([database_ cache][iterator_]);
1380 return state.Mode != pkgDepCache::ModeKeep;
1381}
1382
1383- (NSString *) mode {
1384 pkgDepCache::StateCache &state([database_ cache][iterator_]);
1385
1386 switch (state.Mode) {
1387 case pkgDepCache::ModeDelete:
1388 if ((state.iFlags & pkgDepCache::Purge) != 0)
1389 return @"Purge";
1390 else
1391 return @"Remove";
1392 _assert(false);
1393 case pkgDepCache::ModeKeep:
1394 if ((state.iFlags & pkgDepCache::AutoKept) != 0)
1395 return nil;
1396 else
1397 return nil;
1398 _assert(false);
1399 case pkgDepCache::ModeInstall:
1400 if ((state.iFlags & pkgDepCache::ReInstall) != 0)
1401 return @"Reinstall";
1402 else switch (state.Status) {
1403 case -1:
1404 return @"Downgrade";
1405 case 0:
1406 return @"Install";
1407 case 1:
1408 return @"Upgrade";
1409 case 2:
1410 return @"New Install";
1411 default:
1412 _assert(false);
1413 }
1414 default:
1415 _assert(false);
1416 }
b6ffa083
JF
1417}
1418
e057ec05
JF
1419- (NSString *) id {
1420 return id_;
b6ffa083
JF
1421}
1422
e057ec05
JF
1423- (NSString *) name {
1424 return name_ == nil ? id_ : name_;
1425}
b6ffa083 1426
e057ec05
JF
1427- (NSString *) tagline {
1428 return tagline_;
b6ffa083
JF
1429}
1430
e057ec05
JF
1431- (NSString *) icon {
1432 return icon_;
1433}
b6ffa083 1434
ad554f10
JF
1435- (NSString *) homepage {
1436 return homepage_;
b6ffa083
JF
1437}
1438
0235116c
JF
1439- (NSString *) depiction {
1440 return depiction_;
1441}
1442
81ab76dc
JF
1443- (Address *) sponsor {
1444 return sponsor_;
1445}
1446
d72d91aa
JF
1447- (Address *) author {
1448 return author_;
1449}
1450
2a987aa5
JF
1451- (NSArray *) relationships {
1452 return relationships_;
1453}
1454
e057ec05 1455- (Source *) source {
3d37fc0d 1456 if (!cached_) {
965edd52 1457 source_ = file_.end() ? nil : [[database_ getSource:file_.File()] retain];
3d37fc0d
JF
1458 cached_ = true;
1459 }
1460
e057ec05 1461 return source_;
b6ffa083
JF
1462}
1463
faf4eb4f
JF
1464- (NSString *) role {
1465 return role_;
1466}
1467
e057ec05
JF
1468- (BOOL) matches:(NSString *)text {
1469 if (text == nil)
1470 return NO;
b6ffa083 1471
e057ec05 1472 NSRange range;
b6ffa083 1473
e057ec05
JF
1474 range = [[self id] rangeOfString:text options:NSCaseInsensitiveSearch];
1475 if (range.location != NSNotFound)
1476 return YES;
b6ffa083 1477
e057ec05
JF
1478 range = [[self name] rangeOfString:text options:NSCaseInsensitiveSearch];
1479 if (range.location != NSNotFound)
1480 return YES;
b6ffa083 1481
e057ec05
JF
1482 range = [[self tagline] rangeOfString:text options:NSCaseInsensitiveSearch];
1483 if (range.location != NSNotFound)
1484 return YES;
b6ffa083 1485
e057ec05
JF
1486 return NO;
1487}
b6ffa083 1488
faf4eb4f
JF
1489- (bool) hasSupportingRole {
1490 if (role_ == nil)
fa7bb92f 1491 return true;
faf4eb4f
JF
1492 if ([role_ isEqualToString:@"enduser"])
1493 return true;
1494 if ([Role_ isEqualToString:@"User"])
1495 return false;
1496 if ([role_ isEqualToString:@"hacker"])
1497 return true;
1498 if ([Role_ isEqualToString:@"Hacker"])
1499 return false;
1500 if ([role_ isEqualToString:@"developer"])
1501 return true;
1502 if ([Role_ isEqualToString:@"Developer"])
1503 return false;
1504 _assert(false);
fa7bb92f
JF
1505}
1506
1507- (BOOL) hasTag:(NSString *)tag {
1508 return tags_ == nil ? NO : [tags_ containsObject:tag];
1509}
1510
e057ec05
JF
1511- (NSComparisonResult) compareByName:(Package *)package {
1512 NSString *lhs = [self name];
1513 NSString *rhs = [package name];
b6ffa083 1514
e057ec05
JF
1515 if ([lhs length] != 0 && [rhs length] != 0) {
1516 unichar lhc = [lhs characterAtIndex:0];
1517 unichar rhc = [rhs characterAtIndex:0];
1518
1519 if (isalpha(lhc) && !isalpha(rhc))
1520 return NSOrderedAscending;
1521 else if (!isalpha(lhc) && isalpha(rhc))
1522 return NSOrderedDescending;
b6ffa083
JF
1523 }
1524
e057ec05 1525 return [lhs caseInsensitiveCompare:rhs];
b6ffa083
JF
1526}
1527
e057ec05
JF
1528- (NSComparisonResult) compareBySection:(Package *)package {
1529 NSString *lhs = [self section];
1530 NSString *rhs = [package section];
2d28b35a 1531
e057ec05
JF
1532 if (lhs == NULL && rhs != NULL)
1533 return NSOrderedAscending;
1534 else if (lhs != NULL && rhs == NULL)
1535 return NSOrderedDescending;
1536 else if (lhs != NULL && rhs != NULL) {
113c9b62 1537 NSComparisonResult result = [lhs caseInsensitiveCompare:rhs];
e057ec05
JF
1538 if (result != NSOrderedSame)
1539 return result;
1540 }
2d28b35a 1541
e057ec05
JF
1542 return NSOrderedSame;
1543}
2d28b35a 1544
e057ec05
JF
1545- (NSComparisonResult) compareBySectionAndName:(Package *)package {
1546 NSString *lhs = [self section];
1547 NSString *rhs = [package section];
2d28b35a 1548
e057ec05
JF
1549 if (lhs == NULL && rhs != NULL)
1550 return NSOrderedAscending;
1551 else if (lhs != NULL && rhs == NULL)
1552 return NSOrderedDescending;
1553 else if (lhs != NULL && rhs != NULL) {
1554 NSComparisonResult result = [lhs compare:rhs];
1555 if (result != NSOrderedSame)
1556 return result;
1557 }
2d28b35a 1558
e057ec05
JF
1559 return [self compareByName:package];
1560}
2d28b35a 1561
e057ec05 1562- (NSComparisonResult) compareForChanges:(Package *)package {
238b07ce
JF
1563 BOOL lhs = [self upgradableAndEssential:YES];
1564 BOOL rhs = [package upgradableAndEssential:YES];
b6ffa083 1565
e057ec05
JF
1566 if (lhs != rhs)
1567 return lhs ? NSOrderedAscending : NSOrderedDescending;
1568 else if (!lhs) {
1569 switch ([[self seen] compare:[package seen]]) {
1570 case NSOrderedAscending:
1571 return NSOrderedDescending;
1572 case NSOrderedSame:
1573 break;
1574 case NSOrderedDescending:
1575 return NSOrderedAscending;
1576 default:
1577 _assert(false);
1578 }
1579 }
b6ffa083 1580
e057ec05
JF
1581 return [self compareByName:package];
1582}
b6ffa083 1583
e057ec05
JF
1584- (void) install {
1585 pkgProblemResolver *resolver = [database_ resolver];
1586 resolver->Clear(iterator_);
1587 resolver->Protect(iterator_);
1588 pkgCacheFile &cache([database_ cache]);
1589 cache->MarkInstall(iterator_, false);
1590 pkgDepCache::StateCache &state((*cache)[iterator_]);
1591 if (!state.Install())
1592 cache->SetReInstall(iterator_, true);
1593}
0f25fa58 1594
e057ec05
JF
1595- (void) remove {
1596 pkgProblemResolver *resolver = [database_ resolver];
1597 resolver->Clear(iterator_);
1598 resolver->Protect(iterator_);
1599 resolver->Remove(iterator_);
1600 [database_ cache]->MarkDelete(iterator_, true);
1601}
b6ffa083 1602
853d14d3 1603- (NSNumber *) isUnfilteredAndSearchedForBy:(NSString *)search {
5e563e79 1604 return [NSNumber numberWithBool:(
853d14d3 1605 [self unfiltered] && [self matches:search]
5e563e79 1606 )];
e057ec05 1607}
b6ffa083 1608
853d14d3 1609- (NSNumber *) isInstalledAndUnfiltered:(NSNumber *)number {
5e563e79 1610 return [NSNumber numberWithBool:(
853d14d3 1611 (![number boolValue] || [self unfiltered]) && [self installed] != nil
5e563e79 1612 )];
e057ec05 1613}
b6ffa083 1614
faf4eb4f 1615- (NSNumber *) isVisiblyUninstalledInSection:(NSString *)name {
965edd52
JF
1616 NSString *section = [self section];
1617
faf4eb4f 1618 return [NSNumber numberWithBool:(
853d14d3 1619 [self visible] &&
faf4eb4f
JF
1620 [self installed] == nil && (
1621 name == nil ||
1622 section == nil && [name length] == 0 ||
1623 [name isEqualToString:section]
1624 )
1625 )];
1626}
1627
1628- (NSNumber *) isVisibleInSource:(Source *)source {
1629 return [NSNumber numberWithBool:([self source] == source && [self visible])];
e057ec05 1630}
b6ffa083 1631
e057ec05
JF
1632@end
1633/* }}} */
1634/* Section Class {{{ */
1635@interface Section : NSObject {
1636 NSString *name_;
1637 size_t row_;
1638 size_t count_;
1639}
2d28b35a 1640
fa7bb92f
JF
1641- (NSComparisonResult) compareByName:(Section *)section;
1642- (Section *) initWithName:(NSString *)name;
e057ec05
JF
1643- (Section *) initWithName:(NSString *)name row:(size_t)row;
1644- (NSString *) name;
1645- (size_t) row;
1646- (size_t) count;
1647- (void) addToCount;
a933cee2 1648
e057ec05 1649@end
a933cee2 1650
e057ec05 1651@implementation Section
a933cee2 1652
e057ec05
JF
1653- (void) dealloc {
1654 [name_ release];
1655 [super dealloc];
1656}
a933cee2 1657
fa7bb92f
JF
1658- (NSComparisonResult) compareByName:(Section *)section {
1659 NSString *lhs = [self name];
1660 NSString *rhs = [section name];
1661
1662 if ([lhs length] != 0 && [rhs length] != 0) {
1663 unichar lhc = [lhs characterAtIndex:0];
1664 unichar rhc = [rhs characterAtIndex:0];
1665
1666 if (isalpha(lhc) && !isalpha(rhc))
1667 return NSOrderedAscending;
1668 else if (!isalpha(lhc) && isalpha(rhc))
1669 return NSOrderedDescending;
1670 }
1671
1672 return [lhs caseInsensitiveCompare:rhs];
1673}
1674
1675- (Section *) initWithName:(NSString *)name {
1676 return [self initWithName:name row:0];
1677}
1678
e057ec05
JF
1679- (Section *) initWithName:(NSString *)name row:(size_t)row {
1680 if ((self = [super init]) != nil) {
1681 name_ = [name retain];
1682 row_ = row;
a933cee2
JF
1683 } return self;
1684}
1685
e057ec05
JF
1686- (NSString *) name {
1687 return name_;
1688}
1689
1690- (size_t) row {
1691 return row_;
1692}
1693
1694- (size_t) count {
1695 return count_;
1696}
1697
1698- (void) addToCount {
1699 ++count_;
1700}
1701
a933cee2
JF
1702@end
1703/* }}} */
1704
03d01f0e
JF
1705int Finish_;
1706NSArray *Finishes_;
1707
e057ec05
JF
1708/* Database Implementation {{{ */
1709@implementation Database
1cb11c5f 1710
e057ec05
JF
1711- (void) dealloc {
1712 _assert(false);
1713 [super dealloc];
1714}
1cb11c5f 1715
d72d91aa
JF
1716- (void) _readCydia:(NSNumber *)fd {
1717 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1718
1719 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1720 std::istream is(&ib);
1721 std::string line;
1722
03d01f0e
JF
1723 static Pcre finish_r("^finish:([^:]*)$");
1724
d72d91aa
JF
1725 while (std::getline(is, line)) {
1726 const char *data(line.c_str());
03d01f0e 1727 size_t size = line.size();
d72d91aa 1728 fprintf(stderr, "C:%s\n", data);
03d01f0e
JF
1729
1730 if (finish_r(data, size)) {
1731 NSString *finish = finish_r[1];
1732 int index = [Finishes_ indexOfObject:finish];
1733 if (index != INT_MAX && index > Finish_)
1734 Finish_ = index;
1735 }
d72d91aa
JF
1736 }
1737
1738 [pool release];
1739 _assert(false);
1740}
1741
e057ec05
JF
1742- (void) _readStatus:(NSNumber *)fd {
1743 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1951a333 1744
e057ec05
JF
1745 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1746 std::istream is(&ib);
1747 std::string line;
1cb11c5f 1748
faf4eb4f
JF
1749 static Pcre conffile_r("^status: [^ ]* : conffile-prompt : (.*?) *$");
1750 static Pcre pmstatus_r("^([^:]*):([^:]*):([^:]*):(.*)$");
1cb11c5f 1751
e057ec05
JF
1752 while (std::getline(is, line)) {
1753 const char *data(line.c_str());
965edd52 1754 size_t size = line.size();
d72d91aa 1755 fprintf(stderr, "S:%s\n", data);
1cb11c5f 1756
965edd52
JF
1757 if (conffile_r(data, size)) {
1758 [delegate_ setConfigurationData:conffile_r[1]];
1759 } else if (strncmp(data, "status: ", 8) == 0) {
1760 NSString *string = [NSString stringWithUTF8String:(data + 8)];
e057ec05 1761 [delegate_ setProgressTitle:string];
965edd52 1762 } else if (pmstatus_r(data, size)) {
238b07ce
JF
1763 std::string type([pmstatus_r[1] UTF8String]);
1764 NSString *id = pmstatus_r[2];
1765
965edd52
JF
1766 float percent([pmstatus_r[3] floatValue]);
1767 [delegate_ setProgressPercent:(percent / 100)];
1768
1769 NSString *string = pmstatus_r[4];
965edd52
JF
1770
1771 if (type == "pmerror")
238b07ce
JF
1772 [delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
1773 withObject:[NSArray arrayWithObjects:string, id, nil]
1774 waitUntilDone:YES
1775 ];
965edd52
JF
1776 else if (type == "pmstatus")
1777 [delegate_ setProgressTitle:string];
1778 else if (type == "pmconffile")
1779 [delegate_ setConfigurationData:string];
1780 else _assert(false);
1781 } else _assert(false);
e057ec05 1782 }
1cb11c5f 1783
e057ec05
JF
1784 [pool release];
1785 _assert(false);
1786}
1cb11c5f 1787
e057ec05
JF
1788- (void) _readOutput:(NSNumber *)fd {
1789 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1cb11c5f 1790
e057ec05
JF
1791 __gnu_cxx::stdio_filebuf<char> ib([fd intValue], std::ios::in);
1792 std::istream is(&ib);
1793 std::string line;
1794
965edd52 1795 while (std::getline(is, line)) {
d72d91aa 1796 fprintf(stderr, "O:%s\n", line.c_str());
2a987aa5 1797 [delegate_ addProgressOutput:[NSString stringWithUTF8String:line.c_str()]];
965edd52 1798 }
e057ec05
JF
1799
1800 [pool release];
1801 _assert(false);
1cb11c5f
JF
1802}
1803
7600bd69
JF
1804- (FILE *) input {
1805 return input_;
1806}
1807
e057ec05 1808- (Package *) packageWithName:(NSString *)name {
965edd52
JF
1809 if (static_cast<pkgDepCache *>(cache_) == NULL)
1810 return nil;
e057ec05
JF
1811 pkgCache::PkgIterator iterator(cache_->FindPkg([name UTF8String]));
1812 return iterator.end() ? nil : [Package packageWithIterator:iterator database:self];
1813}
1814
1815- (Database *) init {
1cb11c5f 1816 if ((self = [super init]) != nil) {
965edd52 1817 policy_ = NULL;
e057ec05
JF
1818 records_ = NULL;
1819 resolver_ = NULL;
1820 fetcher_ = NULL;
1821 lock_ = NULL;
1cb11c5f 1822
e057ec05
JF
1823 sources_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1824 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
1cb11c5f 1825
e057ec05 1826 int fds[2];
1cb11c5f 1827
d72d91aa
JF
1828 _assert(pipe(fds) != -1);
1829 cydiafd_ = fds[1];
1830
1831 _config->Set("APT::Keep-Fds::", cydiafd_);
03d01f0e 1832 setenv("CYDIA", [[[[NSNumber numberWithInt:cydiafd_] stringValue] stringByAppendingString:@" 1"] UTF8String], _not(int));
d72d91aa
JF
1833
1834 [NSThread
1835 detachNewThreadSelector:@selector(_readCydia:)
1836 toTarget:self
1837 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1838 ];
1839
e057ec05
JF
1840 _assert(pipe(fds) != -1);
1841 statusfd_ = fds[1];
1cb11c5f 1842
e057ec05
JF
1843 [NSThread
1844 detachNewThreadSelector:@selector(_readStatus:)
1845 toTarget:self
1846 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1847 ];
1cb11c5f 1848
7600bd69
JF
1849 _assert(pipe(fds) != -1);
1850 _assert(dup2(fds[0], 0) != -1);
1851 _assert(close(fds[0]) != -1);
1852
1853 input_ = fdopen(fds[1], "a");
1854
e057ec05
JF
1855 _assert(pipe(fds) != -1);
1856 _assert(dup2(fds[1], 1) != -1);
1857 _assert(close(fds[1]) != -1);
1858
1859 [NSThread
1860 detachNewThreadSelector:@selector(_readOutput:)
1861 toTarget:self
1862 withObject:[[NSNumber numberWithInt:fds[0]] retain]
1863 ];
1cb11c5f
JF
1864 } return self;
1865}
1866
e057ec05
JF
1867- (pkgCacheFile &) cache {
1868 return cache_;
1cb11c5f
JF
1869}
1870
965edd52
JF
1871- (pkgDepCache::Policy *) policy {
1872 return policy_;
1873}
1874
e057ec05
JF
1875- (pkgRecords *) records {
1876 return records_;
1cb11c5f
JF
1877}
1878
e057ec05
JF
1879- (pkgProblemResolver *) resolver {
1880 return resolver_;
1cb11c5f
JF
1881}
1882
e057ec05
JF
1883- (pkgAcquire &) fetcher {
1884 return *fetcher_;
1cb11c5f
JF
1885}
1886
e057ec05
JF
1887- (NSArray *) packages {
1888 return packages_;
1cb11c5f
JF
1889}
1890
faf4eb4f
JF
1891- (NSArray *) sources {
1892 return [sources_ allValues];
1893}
1894
e057ec05
JF
1895- (void) reloadData {
1896 _error->Discard();
965edd52 1897
e057ec05 1898 delete list_;
965edd52 1899 list_ = NULL;
e057ec05
JF
1900 manager_ = NULL;
1901 delete lock_;
965edd52 1902 lock_ = NULL;
e057ec05 1903 delete fetcher_;
965edd52 1904 fetcher_ = NULL;
e057ec05 1905 delete resolver_;
965edd52 1906 resolver_ = NULL;
e057ec05 1907 delete records_;
965edd52
JF
1908 records_ = NULL;
1909 delete policy_;
1910 policy_ = NULL;
e057ec05 1911
965edd52 1912 cache_.Close();
7600bd69 1913
965edd52 1914 if (!cache_.Open(progress_, true)) {
7600bd69
JF
1915 std::string error;
1916 if (!_error->PopMessage(error))
1917 _assert(false);
965edd52
JF
1918 _error->Discard();
1919 fprintf(stderr, "cache_.Open():[%s]\n", error.c_str());
1920
1921 if (error == "dpkg was interrupted, you must manually run 'dpkg --configure -a' to correct the problem. ")
1922 [delegate_ repairWithSelector:@selector(configure)];
1923 else if (error == "The package lists or status file could not be parsed or opened.")
1924 [delegate_ repairWithSelector:@selector(update)];
fc19e583
JF
1925 // else if (error == "Could not open lock file /var/lib/dpkg/lock - open (13 Permission denied)")
1926 // else if (error == "Could not get lock /var/lib/dpkg/lock - open (35 Resource temporarily unavailable)")
1927 // else if (error == "The list of sources could not be read.")
965edd52
JF
1928 else _assert(false);
1929
1930 return;
e057ec05
JF
1931 }
1932
1933 now_ = [[NSDate date] retain];
1934
965edd52 1935 policy_ = new pkgDepCache::Policy();
e057ec05
JF
1936 records_ = new pkgRecords(cache_);
1937 resolver_ = new pkgProblemResolver(cache_);
1938 fetcher_ = new pkgAcquire(&status_);
1939 lock_ = NULL;
1940
1941 list_ = new pkgSourceList();
1942 _assert(list_->ReadMainList());
1943
3319715b
JF
1944 _assert(cache_->DelCount() == 0 && cache_->InstCount() == 0);
1945 _assert(pkgApplyStatus(cache_));
1946
1947 if (cache_->BrokenCount() != 0) {
1948 _assert(pkgFixBroken(cache_));
1949 _assert(cache_->BrokenCount() == 0);
1950 _assert(pkgMinimizeUpgrade(cache_));
1951 }
1952
e057ec05
JF
1953 [sources_ removeAllObjects];
1954 for (pkgSourceList::const_iterator source = list_->begin(); source != list_->end(); ++source) {
1955 std::vector<pkgIndexFile *> *indices = (*source)->GetIndexFiles();
1956 for (std::vector<pkgIndexFile *>::const_iterator index = indices->begin(); index != indices->end(); ++index)
1957 [sources_
1958 setObject:[[[Source alloc] initWithMetaIndex:*source] autorelease]
1959 forKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(*index)]
1960 ];
1961 }
1962
1963 [packages_ removeAllObjects];
1964 for (pkgCache::PkgIterator iterator = cache_->PkgBegin(); !iterator.end(); ++iterator)
965edd52
JF
1965 if (Package *package = [Package packageWithIterator:iterator database:self])
1966 [packages_ addObject:package];
59efd93a
JF
1967
1968 [packages_ sortUsingSelector:@selector(compareByName:)];
1cb11c5f
JF
1969}
1970
965edd52
JF
1971- (void) configure {
1972 NSString *dpkg = [NSString stringWithFormat:@"dpkg --configure -a --status-fd %u", statusfd_];
1973 system([dpkg UTF8String]);
1974}
1975
d72d91aa
JF
1976- (void) clean {
1977 if (lock_ != NULL)
1978 return;
1979
1980 FileFd Lock;
1981 Lock.Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
1982 _assert(!_error->PendingError());
1983
1984 pkgAcquire fetcher;
1985 fetcher.Clean(_config->FindDir("Dir::Cache::Archives"));
1986
3319715b
JF
1987 class LogCleaner :
1988 public pkgArchiveCleaner
1989 {
d72d91aa
JF
1990 protected:
1991 virtual void Erase(const char *File, std::string Pkg, std::string Ver, struct stat &St) {
3319715b 1992 unlink(File);
d72d91aa
JF
1993 }
1994 } cleaner;
1995
1996 if (!cleaner.Go(_config->FindDir("Dir::Cache::Archives") + "partial/", cache_)) {
1997 std::string error;
1998 while (_error->PopMessage(error))
1999 fprintf(stderr, "ArchiveCleaner: %s\n", error.c_str());
2000 }
2001}
2002
e057ec05
JF
2003- (void) prepare {
2004 pkgRecords records(cache_);
2005
2006 lock_ = new FileFd();
2007 lock_->Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
2008 _assert(!_error->PendingError());
2009
2010 pkgSourceList list;
2011 // XXX: explain this with an error message
2012 _assert(list.ReadMainList());
2013
2014 manager_ = (_system->CreatePM(cache_));
2015 _assert(manager_->GetArchives(fetcher_, &list, &records));
2016 _assert(!_error->PendingError());
1cb11c5f
JF
2017}
2018
e057ec05 2019- (void) perform {
113c9b62
JF
2020 NSMutableArray *before = [NSMutableArray arrayWithCapacity:16]; {
2021 pkgSourceList list;
2022 _assert(list.ReadMainList());
2023 for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source)
2024 [before addObject:[NSString stringWithUTF8String:(*source)->GetURI().c_str()]];
2025 }
8993ad57 2026
2d7f7dea
JF
2027 if (fetcher_->Run(PulseInterval_) != pkgAcquire::Continue) {
2028 _trace();
e057ec05 2029 return;
2d7f7dea
JF
2030 }
2031
2032 bool failed = false;
2033 for (pkgAcquire::ItemIterator item = fetcher_->ItemsBegin(); item != fetcher_->ItemsEnd(); item++) {
2034 if ((*item)->Status == pkgAcquire::Item::StatDone && (*item)->Complete)
2035 continue;
2036
2037 std::string uri = (*item)->DescURI();
2038 std::string error = (*item)->ErrorText;
2039
2040 fprintf(stderr, "pAf:%s:%s\n", uri.c_str(), error.c_str());
2041 failed = true;
2042
2043 [delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
2044 withObject:[NSArray arrayWithObjects:[NSString stringWithUTF8String:error.c_str()], nil]
2045 waitUntilDone:YES
2046 ];
2047 }
2048
2049 if (failed) {
2050 _trace();
2051 return;
2052 }
e057ec05
JF
2053
2054 _system->UnLock();
2055 pkgPackageManager::OrderResult result = manager_->DoInstall(statusfd_);
2056
2d7f7dea
JF
2057 if (_error->PendingError()) {
2058 _trace();
e057ec05 2059 return;
2d7f7dea
JF
2060 }
2061
2062 if (result == pkgPackageManager::Failed) {
2063 _trace();
e057ec05 2064 return;
2d7f7dea
JF
2065 }
2066
2067 if (result != pkgPackageManager::Completed) {
2068 _trace();
e057ec05 2069 return;
2d7f7dea 2070 }
8993ad57 2071
113c9b62
JF
2072 NSMutableArray *after = [NSMutableArray arrayWithCapacity:16]; {
2073 pkgSourceList list;
2074 _assert(list.ReadMainList());
2075 for (pkgSourceList::const_iterator source = list.begin(); source != list.end(); ++source)
2076 [after addObject:[NSString stringWithUTF8String:(*source)->GetURI().c_str()]];
2077 }
2078
2079 if (![before isEqualToArray:after])
2080 [self update];
1cb11c5f
JF
2081}
2082
e057ec05 2083- (void) upgrade {
e057ec05 2084 _assert(pkgDistUpgrade(cache_));
1951a333
JF
2085}
2086
e057ec05
JF
2087- (void) update {
2088 [self updateWithStatus:status_];
2089}
686e302f 2090
e057ec05
JF
2091- (void) updateWithStatus:(Status &)status {
2092 pkgSourceList list;
2093 _assert(list.ReadMainList());
686e302f 2094
e057ec05
JF
2095 FileFd lock;
2096 lock.Fd(GetLock(_config->FindDir("Dir::State::Lists") + "lock"));
2097 _assert(!_error->PendingError());
2098
2099 pkgAcquire fetcher(&status);
2100 _assert(list.GetIndexes(&fetcher));
2101
2102 if (fetcher.Run(PulseInterval_) != pkgAcquire::Failed) {
2103 bool failed = false;
2104 for (pkgAcquire::ItemIterator item = fetcher.ItemsBegin(); item != fetcher.ItemsEnd(); item++)
2105 if ((*item)->Status != pkgAcquire::Item::StatDone) {
2106 (*item)->Finished();
2107 failed = true;
2108 }
2109
2110 if (!failed && _config->FindB("APT::Get::List-Cleanup", true) == true) {
2111 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists")));
2112 _assert(fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/"));
686e302f 2113 }
e057ec05
JF
2114
2115 [Metadata_ setObject:[NSDate date] forKey:@"LastUpdate"];
3d37fc0d 2116 Changed_ = true;
686e302f
JF
2117 }
2118}
2119
e057ec05
JF
2120- (void) setDelegate:(id)delegate {
2121 delegate_ = delegate;
2122 status_.setDelegate(delegate);
2123 progress_.setDelegate(delegate);
2124}
686e302f 2125
e057ec05
JF
2126- (Source *) getSource:(const pkgCache::PkgFileIterator &)file {
2127 pkgIndexFile *index(NULL);
2128 list_->FindIndex(file, index);
2129 return [sources_ objectForKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(index)]];
a933cee2
JF
2130}
2131
e057ec05
JF
2132@end
2133/* }}} */
686e302f 2134
e057ec05
JF
2135/* Confirmation View {{{ */
2136void AddTextView(NSMutableDictionary *fields, NSMutableArray *packages, NSString *key) {
2137 if ([packages count] == 0)
2138 return;
686e302f 2139
e057ec05
JF
2140 UITextView *text = GetTextView([packages count] == 0 ? @"n/a" : [packages componentsJoinedByString:@", "], 120, false);
2141 [fields setObject:text forKey:key];
2142
2143 CGColor blue(space_, 0, 0, 0.4, 1);
d210b85d 2144 [text setTextColor:[UIColor colorWithCGColor:blue]];
a75f53e7
JF
2145}
2146
e057ec05
JF
2147@protocol ConfirmationViewDelegate
2148- (void) cancel;
2149- (void) confirm;
2150@end
4941f41d 2151
e057ec05
JF
2152@interface ConfirmationView : UIView {
2153 Database *database_;
2154 id delegate_;
2155 UITransitionView *transition_;
2156 UIView *overlay_;
2157 UINavigationBar *navbar_;
2158 UIPreferencesTable *table_;
2159 NSMutableDictionary *fields_;
d210b85d 2160 UIActionSheet *essential_;
e057ec05 2161}
a75f53e7 2162
e057ec05 2163- (void) cancel;
20dd7407 2164
e057ec05 2165- (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate;
686e302f 2166
a75f53e7
JF
2167@end
2168
e057ec05 2169@implementation ConfirmationView
a75f53e7 2170
4941f41d 2171- (void) dealloc {
e057ec05
JF
2172 [navbar_ setDelegate:nil];
2173 [transition_ setDelegate:nil];
2174 [table_ setDataSource:nil];
2175
2176 [transition_ release];
2177 [overlay_ release];
2178 [navbar_ release];
20dd7407 2179 [table_ release];
e057ec05
JF
2180 [fields_ release];
2181 if (essential_ != nil)
2182 [essential_ release];
4941f41d
JF
2183 [super dealloc];
2184}
2185
e057ec05
JF
2186- (void) cancel {
2187 [transition_ transition:7 toView:nil];
2188 [delegate_ cancel];
2189}
2190
2191- (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
2192 if (from != nil && to == nil)
2193 [self removeFromSuperview];
2194}
2195
2196- (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
2197 switch (button) {
2198 case 0:
2199 if (essential_ != nil)
2200 [essential_ popupAlertAnimated:YES];
2201 else
2202 [delegate_ confirm];
2203 break;
2204
2205 case 1:
2206 [self cancel];
2207 break;
2208 }
2209}
2210
d210b85d 2211- (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
3319715b
JF
2212 NSString *context = [sheet context];
2213
2214 if ([context isEqualToString:@"remove"])
2215 switch (button) {
2216 case 1:
238b07ce 2217 [self cancel];
3319715b
JF
2218 break;
2219 case 2:
238b07ce 2220 [delegate_ confirm];
3319715b
JF
2221 break;
2222 default:
2223 _assert(false);
2224 }
2225 else if ([context isEqualToString:@"unable"])
2226 [self cancel];
2227
2228 [sheet dismiss];
e057ec05
JF
2229}
2230
a75f53e7 2231- (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
e057ec05 2232 return 2;
a75f53e7
JF
2233}
2234
2235- (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
2236 switch (group) {
e057ec05
JF
2237 case 0: return @"Statistics";
2238 case 1: return @"Modifications";
a75f53e7
JF
2239
2240 default: _assert(false);
2241 }
2242}
2243
2244- (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
2245 switch (group) {
e057ec05
JF
2246 case 0: return 3;
2247 case 1: return [fields_ count];
a75f53e7
JF
2248
2249 default: _assert(false);
2250 }
2251}
2252
e057ec05
JF
2253- (float) preferencesTable:(UIPreferencesTable *)table heightForRow:(int)row inGroup:(int)group withProposedHeight:(float)proposed {
2254 if (group != 1 || row == -1)
2255 return proposed;
2256 else {
2257 _assert(size_t(row) < [fields_ count]);
2258 return [[[fields_ allValues] objectAtIndex:row] visibleTextRect].size.height + TextViewOffset_;
2259 }
2260}
2261
a75f53e7 2262- (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group {
686e302f
JF
2263 UIPreferencesTableCell *cell = [[[UIPreferencesTableCell alloc] init] autorelease];
2264 [cell setShowSelection:NO];
a75f53e7
JF
2265
2266 switch (group) {
2267 case 0: switch (row) {
e057ec05
JF
2268 case 0: {
2269 [cell setTitle:@"Downloading"];
2270 [cell setValue:SizeString([database_ fetcher].FetchNeeded())];
2271 } break;
2272
2273 case 1: {
2274 [cell setTitle:@"Resuming At"];
2275 [cell setValue:SizeString([database_ fetcher].PartialPresent())];
2276 } break;
2277
2278 case 2: {
2279 double size([database_ cache]->UsrSize());
2280
2281 if (size < 0) {
2282 [cell setTitle:@"Disk Freeing"];
2283 [cell setValue:SizeString(-size)];
2284 } else {
2285 [cell setTitle:@"Disk Using"];
2286 [cell setValue:SizeString(size)];
2287 }
2288 } break;
2289
2290 default: _assert(false);
2291 } break;
2292
2293 case 1:
2294 _assert(size_t(row) < [fields_ count]);
2295 [cell setTitle:[[fields_ allKeys] objectAtIndex:row]];
2296 [cell addSubview:[[fields_ allValues] objectAtIndex:row]];
2297 break;
2298
2299 default: _assert(false);
2300 }
2301
2302 return cell;
2303}
2304
2305- (id) initWithView:(UIView *)view database:(Database *)database delegate:(id)delegate {
2306 if ((self = [super initWithFrame:[view bounds]]) != nil) {
2307 database_ = database;
2308 delegate_ = delegate;
686e302f 2309
e057ec05
JF
2310 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
2311 [self addSubview:transition_];
686e302f 2312
e057ec05 2313 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
7e986211 2314
e057ec05
JF
2315 CGSize navsize = [UINavigationBar defaultSize];
2316 CGRect navrect = {{0, 0}, navsize};
2317 CGRect bounds = [overlay_ bounds];
686e302f 2318
e057ec05 2319 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
e057ec05 2320 [navbar_ setDelegate:self];
a75f53e7 2321
e057ec05
JF
2322 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:@"Confirm"] autorelease];
2323 [navbar_ pushNavigationItem:navitem];
2324 [navbar_ showButtonsWithLeftTitle:@"Cancel" rightTitle:@"Confirm"];
a75f53e7 2325
e057ec05 2326 fields_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
a75f53e7 2327
e057ec05
JF
2328 NSMutableArray *installing = [NSMutableArray arrayWithCapacity:16];
2329 NSMutableArray *reinstalling = [NSMutableArray arrayWithCapacity:16];
2330 NSMutableArray *upgrading = [NSMutableArray arrayWithCapacity:16];
2331 NSMutableArray *downgrading = [NSMutableArray arrayWithCapacity:16];
2332 NSMutableArray *removing = [NSMutableArray arrayWithCapacity:16];
a75f53e7 2333
e057ec05 2334 bool remove(false);
a75f53e7 2335
e057ec05 2336 pkgCacheFile &cache([database_ cache]);
2a987aa5
JF
2337 NSArray *packages = [database_ packages];
2338 for (size_t i(0), e = [packages count]; i != e; ++i) {
2339 Package *package = [packages objectAtIndex:i];
2340 pkgCache::PkgIterator iterator = [package iterator];
e057ec05 2341 pkgDepCache::StateCache &state(cache[iterator]);
a75f53e7 2342
2a987aa5
JF
2343 NSString *name([package name]);
2344
e057ec05
JF
2345 if (state.NewInstall())
2346 [installing addObject:name];
2347 else if (!state.Delete() && (state.iFlags & pkgDepCache::ReInstall) == pkgDepCache::ReInstall)
2348 [reinstalling addObject:name];
2349 else if (state.Upgrade())
2350 [upgrading addObject:name];
2351 else if (state.Downgrade())
2352 [downgrading addObject:name];
2353 else if (state.Delete()) {
2a987aa5 2354 if ([package essential])
e057ec05
JF
2355 remove = true;
2356 [removing addObject:name];
2357 }
2358 }
1cb11c5f 2359
e057ec05
JF
2360 if (!remove)
2361 essential_ = nil;
3319715b 2362 else if (Advanced_ || true) {
d210b85d 2363 essential_ = [[UIActionSheet alloc]
238b07ce 2364 initWithTitle:@"Removing Essentials"
3319715b 2365 buttons:[NSArray arrayWithObjects:
238b07ce
JF
2366 @"Cancel Operation (Safe)",
2367 @"Force Removal (Unsafe)",
3319715b 2368 nil]
238b07ce 2369 defaultButtonIndex:0
3319715b
JF
2370 delegate:self
2371 context:@"remove"
2372 ];
2373
b27f0a94 2374#ifndef __OBJC2__
3319715b 2375 [essential_ setDestructiveButton:[[essential_ buttons] objectAtIndex:0]];
b27f0a94 2376#endif
238b07ce 2377 [essential_ setBodyText:@"This operation involves the removal of one or more packages that are required for the continued operation of either Cydia or iPhoneOS. If you continue, you may not be able to use Cydia to repair any damage."];
3319715b 2378 } else {
d210b85d 2379 essential_ = [[UIActionSheet alloc]
e057ec05
JF
2380 initWithTitle:@"Unable to Comply"
2381 buttons:[NSArray arrayWithObjects:@"Okay", nil]
2382 defaultButtonIndex:0
2383 delegate:self
3319715b 2384 context:@"unable"
e057ec05 2385 ];
1cb11c5f 2386
238b07ce 2387 [essential_ setBodyText:@"This operation requires the removal of one or more packages that are required for the continued operation of either Cydia or iPhoneOS. In order to continue and force this operation you will need to be activate the Advanced mode under to continue and force this operation you will need to be activate the Advanced mode under Settings."];
e057ec05 2388 }
1cb11c5f 2389
e057ec05
JF
2390 AddTextView(fields_, installing, @"Installing");
2391 AddTextView(fields_, reinstalling, @"Reinstalling");
2392 AddTextView(fields_, upgrading, @"Upgrading");
2393 AddTextView(fields_, downgrading, @"Downgrading");
2394 AddTextView(fields_, removing, @"Removing");
a75f53e7 2395
e057ec05
JF
2396 table_ = [[UIPreferencesTable alloc] initWithFrame:CGRectMake(
2397 0, navsize.height, bounds.size.width, bounds.size.height - navsize.height
2398 )];
a75f53e7 2399
e057ec05
JF
2400 [table_ setReusesTableCells:YES];
2401 [table_ setDataSource:self];
2402 [table_ reloadData];
a75f53e7 2403
e057ec05
JF
2404 [overlay_ addSubview:navbar_];
2405 [overlay_ addSubview:table_];
20dd7407 2406
e057ec05 2407 [view addSubview:self];
ec5624fe 2408
e057ec05 2409 [transition_ setDelegate:self];
20dd7407 2410
e057ec05
JF
2411 UIView *blank = [[[UIView alloc] initWithFrame:[transition_ bounds]] autorelease];
2412 [transition_ transition:0 toView:blank];
2413 [transition_ transition:3 toView:overlay_];
2414 } return self;
686e302f 2415}
20dd7407 2416
e057ec05
JF
2417@end
2418/* }}} */
20dd7407 2419
e057ec05
JF
2420/* Progress Data {{{ */
2421@interface ProgressData : NSObject {
2422 SEL selector_;
2423 id target_;
2424 id object_;
a75f53e7
JF
2425}
2426
e057ec05 2427- (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object;
686e302f 2428
e057ec05
JF
2429- (SEL) selector;
2430- (id) target;
2431- (id) object;
2432@end
686e302f 2433
e057ec05 2434@implementation ProgressData
686e302f 2435
e057ec05
JF
2436- (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object {
2437 if ((self = [super init]) != nil) {
2438 selector_ = selector;
2439 target_ = target;
2440 object_ = object;
2441 } return self;
2442}
686e302f 2443
e057ec05
JF
2444- (SEL) selector {
2445 return selector_;
2446}
686e302f 2447
e057ec05
JF
2448- (id) target {
2449 return target_;
20dd7407
JF
2450}
2451
e057ec05
JF
2452- (id) object {
2453 return object_;
a75f53e7
JF
2454}
2455
4941f41d
JF
2456@end
2457/* }}} */
e057ec05
JF
2458/* Progress View {{{ */
2459@interface ProgressView : UIView <
7600bd69 2460 ConfigurationDelegate,
e057ec05
JF
2461 ProgressDelegate
2462> {
7600bd69 2463 _transient Database *database_;
e057ec05
JF
2464 UIView *view_;
2465 UIView *background_;
2466 UITransitionView *transition_;
2467 UIView *overlay_;
2468 UINavigationBar *navbar_;
2469 UIProgressBar *progress_;
2470 UITextView *output_;
2471 UITextLabel *status_;
238b07ce 2472 UIPushButton *close_;
e057ec05 2473 id delegate_;
b26eb97d 2474 BOOL running_;
1eb0c554 2475 SHA1SumValue springlist_;
4941f41d
JF
2476}
2477
e057ec05 2478- (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
4941f41d 2479
7600bd69 2480- (id) initWithFrame:(struct CGRect)frame database:(Database *)database delegate:(id)delegate;
e057ec05
JF
2481- (void) setContentView:(UIView *)view;
2482- (void) resetView;
4941f41d 2483
e057ec05
JF
2484- (void) _retachThread;
2485- (void) _detachNewThreadData:(ProgressData *)data;
2486- (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title;
4941f41d 2487
b26eb97d
JF
2488- (BOOL) isRunning;
2489
4941f41d
JF
2490@end
2491
e057ec05
JF
2492@protocol ProgressViewDelegate
2493- (void) progressViewIsComplete:(ProgressView *)sender;
2494@end
2495
2496@implementation ProgressView
4941f41d
JF
2497
2498- (void) dealloc {
e057ec05
JF
2499 [transition_ setDelegate:nil];
2500 [navbar_ setDelegate:nil];
2501
2502 [view_ release];
2503 if (background_ != nil)
2504 [background_ release];
2505 [transition_ release];
2506 [overlay_ release];
2507 [navbar_ release];
2508 [progress_ release];
2509 [output_ release];
2510 [status_ release];
238b07ce 2511 [close_ release];
4941f41d
JF
2512 [super dealloc];
2513}
2514
e057ec05
JF
2515- (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
2516 if (bootstrap_ && from == overlay_ && to == view_)
2517 exit(0);
2518}
4941f41d 2519
7600bd69 2520- (id) initWithFrame:(struct CGRect)frame database:(Database *)database delegate:(id)delegate {
e057ec05 2521 if ((self = [super initWithFrame:frame]) != nil) {
7600bd69 2522 database_ = database;
e057ec05 2523 delegate_ = delegate;
1cb11c5f 2524
e057ec05
JF
2525 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
2526 [transition_ setDelegate:self];
4941f41d 2527
e057ec05 2528 overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
1cb11c5f 2529
e057ec05 2530 if (bootstrap_)
d210b85d 2531 [overlay_ setBackgroundColor:[UIColor colorWithCGColor:Black_]];
e057ec05
JF
2532 else {
2533 background_ = [[UIView alloc] initWithFrame:[self bounds]];
d210b85d 2534 [background_ setBackgroundColor:[UIColor colorWithCGColor:Black_]];
e057ec05
JF
2535 [self addSubview:background_];
2536 }
1cb11c5f 2537
e057ec05 2538 [self addSubview:transition_];
4941f41d 2539
e057ec05
JF
2540 CGSize navsize = [UINavigationBar defaultSize];
2541 CGRect navrect = {{0, 0}, navsize};
4941f41d 2542
e057ec05
JF
2543 navbar_ = [[UINavigationBar alloc] initWithFrame:navrect];
2544 [overlay_ addSubview:navbar_];
686e302f 2545
e057ec05
JF
2546 [navbar_ setBarStyle:1];
2547 [navbar_ setDelegate:self];
4941f41d 2548
e057ec05
JF
2549 UINavigationItem *navitem = [[[UINavigationItem alloc] initWithTitle:nil] autorelease];
2550 [navbar_ pushNavigationItem:navitem];
1951a333 2551
e057ec05
JF
2552 CGRect bounds = [overlay_ bounds];
2553 CGSize prgsize = [UIProgressBar defaultSize];
1cb11c5f 2554
e057ec05
JF
2555 CGRect prgrect = {{
2556 (bounds.size.width - prgsize.width) / 2,
2557 bounds.size.height - prgsize.height - 20
2558 }, prgsize};
1cb11c5f 2559
e057ec05 2560 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
238b07ce 2561 [progress_ setStyle:0];
1cb11c5f 2562
e057ec05
JF
2563 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(
2564 10,
2565 bounds.size.height - prgsize.height - 50,
2566 bounds.size.width - 20,
2567 24
2568 )];
1cb11c5f 2569
d210b85d
JF
2570 [status_ setColor:[UIColor colorWithCGColor:White_]];
2571 [status_ setBackgroundColor:[UIColor colorWithCGColor:Clear_]];
1cb11c5f 2572
e057ec05
JF
2573 [status_ setCentersHorizontally:YES];
2574 //[status_ setFont:font];
1cb11c5f 2575
e057ec05
JF
2576 output_ = [[UITextView alloc] initWithFrame:CGRectMake(
2577 10,
2578 navrect.size.height + 20,
2579 bounds.size.width - 20,
2580 bounds.size.height - navsize.height - 62 - navrect.size.height
2581 )];
3325a005 2582
e057ec05
JF
2583 //[output_ setTextFont:@"Courier New"];
2584 [output_ setTextSize:12];
4941f41d 2585
d210b85d
JF
2586 [output_ setTextColor:[UIColor colorWithCGColor:White_]];
2587 [output_ setBackgroundColor:[UIColor colorWithCGColor:Clear_]];
4941f41d 2588
e057ec05
JF
2589 [output_ setMarginTop:0];
2590 [output_ setAllowsRubberBanding:YES];
81ab76dc 2591 [output_ setEditable:NO];
686e302f 2592
e057ec05 2593 [overlay_ addSubview:output_];
4941f41d 2594
238b07ce
JF
2595 close_ = [[UIPushButton alloc] initWithFrame:CGRectMake(
2596 10,
2597 bounds.size.height - prgsize.height - 50,
2598 bounds.size.width - 20,
81ab76dc 2599 32 + prgsize.height
238b07ce
JF
2600 )];
2601
2602 [close_ setAutosizesToFit:NO];
2603 [close_ setDrawsShadow:YES];
2604 [close_ setStretchBackground:YES];
238b07ce
JF
2605 [close_ setEnabled:YES];
2606
d210b85d 2607 UIFont *bold = [UIFont boldSystemFontOfSize:22];
238b07ce 2608 [close_ setTitleFont:bold];
238b07ce
JF
2609
2610 [close_ addTarget:self action:@selector(closeButtonPushed) forEvents:kUIControlEventMouseUpInside];
2611 [close_ setBackground:[UIImage applicationImageNamed:@"green-up.png"] forState:0];
2612 [close_ setBackground:[UIImage applicationImageNamed:@"green-dn.png"] forState:1];
e057ec05 2613 } return self;
4941f41d
JF
2614}
2615
e057ec05
JF
2616- (void) setContentView:(UIView *)view {
2617 view_ = [view retain];
4941f41d
JF
2618}
2619
e057ec05
JF
2620- (void) resetView {
2621 [transition_ transition:6 toView:view_];
4941f41d
JF
2622}
2623
d210b85d 2624- (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
7600bd69
JF
2625 NSString *context = [sheet context];
2626 if ([context isEqualToString:@"conffile"]) {
2627 FILE *input = [database_ input];
2628
2629 switch (button) {
2630 case 1:
2631 fprintf(input, "N\n");
2632 fflush(input);
3319715b 2633 break;
7600bd69
JF
2634 case 2:
2635 fprintf(input, "Y\n");
2636 fflush(input);
3319715b
JF
2637 break;
2638 default:
2639 _assert(false);
7600bd69
JF
2640 }
2641 }
2642
e057ec05 2643 [sheet dismiss];
4941f41d
JF
2644}
2645
238b07ce 2646- (void) closeButtonPushed {
03d01f0e
JF
2647 switch (Finish_) {
2648 case 0:
2649 [delegate_ progressViewIsComplete:self];
2650 [self resetView];
2651 break;
2652
2653 case 1:
2654 [delegate_ suspendWithAnimation:YES];
2655 break;
2656
2657 case 2:
2658 system("killall SpringBoard");
2659 break;
2660
2661 case 3:
2662 system("launchctl unload /System/Library/LaunchDaemons/com.apple.SpringBoard.plist; launchctl load /System/Library/LaunchDaemons/com.apple.SpringBoard.plist");
2663 break;
2664
2665 case 4:
2666 system("reboot");
2667 break;
2668 }
a933cee2
JF
2669}
2670
238b07ce 2671- (void) _retachThread {
81ab76dc
JF
2672 UINavigationItem *item = [navbar_ topItem];
2673 [item setTitle:@"Complete"];
2674
238b07ce
JF
2675 [overlay_ addSubview:close_];
2676 [progress_ removeFromSuperview];
2677 [status_ removeFromSuperview];
b26eb97d 2678
1eb0c554
JF
2679 {
2680 FileFd file("/System/Library/LaunchDaemons/com.apple.SpringBoard.plist", FileFd::ReadOnly);
2681 MMap mmap(file, MMap::ReadOnly);
2682 SHA1Summation sha1;
2683 sha1.Add(reinterpret_cast<uint8_t *>(mmap.Data()), mmap.Size());
2684 if (!(springlist_ == sha1.Result()))
2685 Finish_ = 3;
2686 }
2687
03d01f0e
JF
2688 switch (Finish_) {
2689 case 0: [close_ setTitle:@"Return to Cydia"]; break;
2690 case 1: [close_ setTitle:@"Close Cydia (Restart)"]; break;
2691 case 2: [close_ setTitle:@"Restart SpringBoard"]; break;
2692 case 3: [close_ setTitle:@"Reload SpringBoard"]; break;
2693 case 4: [close_ setTitle:@"Reboot Device"]; break;
2694 }
2695
5f54c108
JF
2696#ifdef __OBJC2__
2697 notify_post("com.apple.mobile.application_installed");
2698#endif
2699
b26eb97d 2700 [delegate_ setStatusBarShowsProgress:NO];
2d7f7dea 2701
b26eb97d 2702 running_ = NO;
238b07ce
JF
2703}
2704
e057ec05 2705- (void) _detachNewThreadData:(ProgressData *)data {
686e302f
JF
2706 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
2707
e057ec05
JF
2708 [[data target] performSelector:[data selector] withObject:[data object]];
2709 [data release];
a933cee2 2710
e057ec05 2711 [self performSelectorOnMainThread:@selector(_retachThread) withObject:nil waitUntilDone:YES];
a933cee2 2712
686e302f 2713 [pool release];
a933cee2
JF
2714}
2715
e057ec05 2716- (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title {
965edd52
JF
2717 UINavigationItem *item = [navbar_ topItem];
2718 [item setTitle:title];
686e302f 2719
e057ec05
JF
2720 [status_ setText:nil];
2721 [output_ setText:@""];
2722 [progress_ setProgress:0];
a933cee2 2723
238b07ce
JF
2724 [close_ removeFromSuperview];
2725 [overlay_ addSubview:progress_];
2726 [overlay_ addSubview:status_];
2727
b26eb97d
JF
2728 [delegate_ setStatusBarShowsProgress:YES];
2729 running_ = YES;
2730
1eb0c554
JF
2731 {
2732 FileFd file("/System/Library/LaunchDaemons/com.apple.SpringBoard.plist", FileFd::ReadOnly);
2733 MMap mmap(file, MMap::ReadOnly);
2734 SHA1Summation sha1;
2735 sha1.Add(reinterpret_cast<uint8_t *>(mmap.Data()), mmap.Size());
2736 springlist_ = sha1.Result();
2737 }
2738
e057ec05 2739 [transition_ transition:6 toView:overlay_];
a933cee2 2740
e057ec05
JF
2741 [NSThread
2742 detachNewThreadSelector:@selector(_detachNewThreadData:)
2743 toTarget:self
2744 withObject:[[ProgressData alloc]
2745 initWithSelector:selector
2746 target:target
2747 object:object
2748 ]
2749 ];
a933cee2
JF
2750}
2751
965edd52
JF
2752- (void) repairWithSelector:(SEL)selector {
2753 [self
2754 detachNewThreadSelector:selector
2755 toTarget:database_
2756 withObject:nil
2757 title:@"Repairing..."
2758 ];
2759}
2760
7600bd69
JF
2761- (void) setConfigurationData:(NSString *)data {
2762 [self
2763 performSelectorOnMainThread:@selector(_setConfigurationData:)
2764 withObject:data
2765 waitUntilDone:YES
2766 ];
2767}
2768
238b07ce
JF
2769- (void) setProgressError:(NSString *)error forPackage:(NSString *)id {
2770 Package *package = id == nil ? nil : [database_ packageWithName:id];
2771
d210b85d 2772 UIActionSheet *sheet = [[[UIActionSheet alloc]
238b07ce
JF
2773 initWithTitle:(package == nil ? @"Source Error" : [package name])
2774 buttons:[NSArray arrayWithObjects:@"Okay", nil]
2775 defaultButtonIndex:0
2776 delegate:self
2777 context:@"error"
2778 ] autorelease];
2779
2780 [sheet setBodyText:error];
2781 [sheet popupAlertAnimated:YES];
a933cee2
JF
2782}
2783
e057ec05
JF
2784- (void) setProgressTitle:(NSString *)title {
2785 [self
2786 performSelectorOnMainThread:@selector(_setProgressTitle:)
2787 withObject:title
2788 waitUntilDone:YES
2789 ];
a933cee2
JF
2790}
2791
e057ec05
JF
2792- (void) setProgressPercent:(float)percent {
2793 [self
2794 performSelectorOnMainThread:@selector(_setProgressPercent:)
2795 withObject:[NSNumber numberWithFloat:percent]
2796 waitUntilDone:YES
2797 ];
a933cee2
JF
2798}
2799
e057ec05
JF
2800- (void) addProgressOutput:(NSString *)output {
2801 [self
2802 performSelectorOnMainThread:@selector(_addProgressOutput:)
2803 withObject:output
2804 waitUntilDone:YES
2805 ];
a933cee2
JF
2806}
2807
7600bd69 2808- (void) _setConfigurationData:(NSString *)data {
faf4eb4f
JF
2809 static Pcre conffile_r("^'(.*)' '(.*)' ([01]) ([01])$");
2810
7600bd69
JF
2811 _assert(conffile_r(data));
2812
2813 NSString *ofile = conffile_r[1];
2814 //NSString *nfile = conffile_r[2];
2815
d210b85d 2816 UIActionSheet *sheet = [[[UIActionSheet alloc]
7600bd69
JF
2817 initWithTitle:@"Configuration Upgrade"
2818 buttons:[NSArray arrayWithObjects:
2819 @"Keep My Old Copy",
2820 @"Accept The New Copy",
2821 // XXX: @"See What Changed",
2822 nil]
2823 defaultButtonIndex:0
2824 delegate:self
2825 context:@"conffile"
2826 ] autorelease];
2827
2828 [sheet setBodyText:[NSString stringWithFormat:
2829 @"The following file has been changed by both the package maintainer and by you (or for you by a script).\n\n%@"
2830 , ofile]];
2831
2832 [sheet popupAlertAnimated:YES];
2833}
2834
e057ec05
JF
2835- (void) _setProgressTitle:(NSString *)title {
2836 [status_ setText:[title stringByAppendingString:@"..."]];
686e302f 2837}
a933cee2 2838
e057ec05
JF
2839- (void) _setProgressPercent:(NSNumber *)percent {
2840 [progress_ setProgress:[percent floatValue]];
242bcc6d
JF
2841}
2842
e057ec05
JF
2843- (void) _addProgressOutput:(NSString *)output {
2844 [output_ setText:[NSString stringWithFormat:@"%@\n%@", [output_ text], output]];
2845 CGSize size = [output_ contentSize];
2846 CGRect rect = {{0, size.height}, {size.width, 0}};
2847 [output_ scrollRectToVisible:rect animated:YES];
2848}
3957dd75 2849
b26eb97d 2850- (BOOL) isRunning {
5f54c108 2851 return running_;
b26eb97d
JF
2852}
2853
e057ec05
JF
2854@end
2855/* }}} */
3957dd75 2856
e057ec05 2857/* Package Cell {{{ */
5e563e79
JF
2858@interface PackageCell : UISimpleTableCell {
2859 UIImage *icon_;
2860 NSString *name_;
2861 NSString *description_;
2862 NSString *source_;
3319715b 2863 //UIImageView *trusted_;
238b07ce 2864#ifdef USE_BADGES
3319715b
JF
2865 UIImageView *badge_;
2866 UITextLabel *status_;
238b07ce 2867#endif
e057ec05 2868}
138ae18d 2869
e057ec05
JF
2870- (PackageCell *) init;
2871- (void) setPackage:(Package *)package;
1cb11c5f 2872
3319715b
JF
2873+ (int) heightForPackage:(Package *)package;
2874
e057ec05 2875@end
242bcc6d 2876
e057ec05
JF
2877@implementation PackageCell
2878
5e563e79
JF
2879- (void) clearPackage {
2880 if (icon_ != nil) {
2881 [icon_ release];
2882 icon_ = nil;
2883 }
2884
2885 if (name_ != nil) {
2886 [name_ release];
2887 name_ = nil;
2888 }
2889
2890 if (description_ != nil) {
2891 [description_ release];
2892 description_ = nil;
2893 }
2894
2895 if (source_ != nil) {
2896 [source_ release];
2897 source_ = nil;
2898 }
2899}
2900
e057ec05 2901- (void) dealloc {
5e563e79 2902 [self clearPackage];
238b07ce 2903#ifdef USE_BADGES
3319715b
JF
2904 [badge_ release];
2905 [status_ release];
238b07ce 2906#endif
3319715b 2907 //[trusted_ release];
e057ec05 2908 [super dealloc];
686e302f 2909}
a933cee2 2910
e057ec05
JF
2911- (PackageCell *) init {
2912 if ((self = [super init]) != nil) {
238b07ce 2913#ifdef USE_BADGES
3319715b
JF
2914 badge_ = [[UIImageView alloc] initWithFrame:CGRectMake(17, 70, 16, 16)];
2915
2916 status_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 68, 280, 20)];
2917 [status_ setBackgroundColor:Clear_];
2918 [status_ setFont:small];
238b07ce 2919#endif
e057ec05 2920 } return self;
686e302f 2921}
a933cee2 2922
e057ec05 2923- (void) setPackage:(Package *)package {
d1494d2c 2924 [self clearPackage];
238b07ce 2925
e057ec05 2926 Source *source = [package source];
a933cee2 2927
5e563e79 2928 icon_ = nil;
e057ec05 2929 if (NSString *icon = [package icon])
5e563e79
JF
2930 icon_ = [UIImage imageAtPath:[icon substringFromIndex:6]];
2931 if (icon_ == nil) if (NSString *section = [package section])
853d14d3 2932 icon_ = [UIImage imageAtPath:[NSString stringWithFormat:@"%@/Sections/%@.png", App_, Simplify(section)]];
5e563e79
JF
2933 /*if (icon_ == nil) if (NSString *icon = [source defaultIcon])
2934 icon_ = [UIImage imageAtPath:[icon substringFromIndex:6]];*/
2935 if (icon_ == nil)
2936 icon_ = [UIImage applicationImageNamed:@"unknown.png"];
8993ad57 2937
5e563e79 2938 icon_ = [icon_ retain];
a933cee2 2939
5e563e79
JF
2940 name_ = [[package name] retain];
2941 description_ = [[package tagline] retain];
e057ec05 2942
9e07091a
JF
2943 NSString *label = nil;
2944 bool trusted = false;
a933cee2 2945
e057ec05
JF
2946 if (source != nil) {
2947 label = [source label];
2948 trusted = [source trusted];
9e07091a 2949 } else if ([[package id] isEqualToString:@"firmware"])
e057ec05 2950 label = @"Apple";
faf4eb4f 2951 else
e057ec05 2952 label = @"Unknown/Local";
a933cee2 2953
9e07091a
JF
2954 NSString *from = [NSString stringWithFormat:@"from %@", label];
2955
2956 NSString *section = Simplify([package section]);
2957 if (section != nil && ![section isEqualToString:label])
2958 from = [from stringByAppendingString:[NSString stringWithFormat:@" (%@)", section]];
2959
5e563e79 2960 source_ = [from retain];
e057ec05 2961
238b07ce
JF
2962#ifdef USE_BADGES
2963 [badge_ removeFromSuperview];
2964 [status_ removeFromSuperview];
2965
3319715b
JF
2966 if (NSString *mode = [package mode]) {
2967 [badge_ setImage:[UIImage applicationImageNamed:
2968 [mode isEqualToString:@"Remove"] || [mode isEqualToString:@"Purge"] ? @"removing.png" : @"installing.png"
2969 ]];
2970
2971 [status_ setText:[NSString stringWithFormat:@"Queued for %@", mode]];
2972 [status_ setColor:Blueish_];
2973 } else if ([package half]) {
2974 [badge_ setImage:[UIImage applicationImageNamed:@"damaged.png"]];
2975 [status_ setText:@"Package Damaged"];
2976 [status_ setColor:Red_];
2977 } else {
2978 [badge_ setImage:nil];
2979 [status_ setText:nil];
238b07ce 2980 goto done;
3319715b 2981 }
238b07ce
JF
2982
2983 [self addSubview:badge_];
2984 [self addSubview:status_];
2985 done:;
2986#endif
a933cee2
JF
2987}
2988
5e563e79
JF
2989- (void) drawContentInRect:(CGRect)rect selected:(BOOL)selected {
2990 if (icon_ != nil)
2991 [icon_ drawInRect:CGRectMake(10, 10, 30, 30)];
a933cee2 2992
5e563e79
JF
2993 if (selected)
2994 UISetColor(White_);
a933cee2 2995
5e563e79
JF
2996 if (!selected)
2997 UISetColor(Black_);
2998 [name_ drawAtPoint:CGPointMake(48, 8) forWidth:240 withFont:Font18Bold_ ellipsis:2];
2999 [source_ drawAtPoint:CGPointMake(58, 29) forWidth:225 withFont:Font12_ ellipsis:2];
a933cee2 3000
5e563e79
JF
3001 if (!selected)
3002 UISetColor(Gray_);
3003 [description_ drawAtPoint:CGPointMake(12, 46) forWidth:280 withFont:Font14_ ellipsis:2];
a933cee2 3004
5e563e79 3005 [super drawContentInRect:rect selected:selected];
1cb11c5f
JF
3006}
3007
3319715b 3008+ (int) heightForPackage:(Package *)package {
fa7bb92f 3009 NSString *tagline([package tagline]);
5e563e79 3010 int height = tagline == nil || [tagline length] == 0 ? -17 : 0;
238b07ce 3011#ifdef USE_BADGES
3319715b 3012 if ([package hasMode] || [package half])
fa7bb92f 3013 return height + 96;
3319715b 3014 else
238b07ce 3015#endif
fa7bb92f 3016 return height + 73;
3319715b
JF
3017}
3018
20dd7407
JF
3019@end
3020/* }}} */
e057ec05 3021/* Section Cell {{{ */
5e563e79 3022@interface SectionCell : UISimpleTableCell {
fa7bb92f 3023 NSString *section_;
5e563e79
JF
3024 NSString *name_;
3025 NSString *count_;
3026 UIImage *icon_;
d210b85d 3027 _UISwitchSlider *switch_;
fa7bb92f 3028 BOOL editing_;
686e302f 3029}
a933cee2 3030
e057ec05 3031- (id) init;
fa7bb92f 3032- (void) setSection:(Section *)section editing:(BOOL)editing;
e057ec05 3033
20dd7407
JF
3034@end
3035
e057ec05 3036@implementation SectionCell
20dd7407 3037
5e563e79
JF
3038- (void) clearSection {
3039 if (section_ != nil) {
fa7bb92f 3040 [section_ release];
5e563e79
JF
3041 section_ = nil;
3042 }
faf4eb4f 3043
5e563e79
JF
3044 if (name_ != nil) {
3045 [name_ release];
3046 name_ = nil;
3047 }
faf4eb4f 3048
5e563e79
JF
3049 if (count_ != nil) {
3050 [count_ release];
3051 count_ = nil;
3052 }
faf4eb4f
JF
3053}
3054
5e563e79
JF
3055- (void) dealloc {
3056 [self clearSection];
3057 [icon_ release];
3058 [switch_ release];
3059 [super dealloc];
faf4eb4f
JF
3060}
3061
e057ec05 3062- (id) init {
686e302f 3063 if ((self = [super init]) != nil) {
5e563e79 3064 icon_ = [[UIImage applicationImageNamed:@"folder.png"] retain];
e057ec05 3065
d210b85d 3066 switch_ = [[_UISwitchSlider alloc] initWithFrame:CGRectMake(218, 9, 60, 25)];
fa7bb92f 3067 [switch_ addTarget:self action:@selector(onSwitch:) forEvents:kUIControlEventMouseUpInside];
686e302f 3068 } return self;
a933cee2
JF
3069}
3070
fa7bb92f
JF
3071- (void) onSwitch:(id)sender {
3072 NSMutableDictionary *metadata = [Sections_ objectForKey:section_];
3073 if (metadata == nil) {
3074 metadata = [NSMutableDictionary dictionaryWithCapacity:2];
3075 [Sections_ setObject:metadata forKey:section_];
3076 }
3077
3078 Changed_ = true;
3079 [metadata setObject:[NSNumber numberWithBool:([switch_ value] == 0)] forKey:@"Hidden"];
3080}
3081
3082- (void) setSection:(Section *)section editing:(BOOL)editing {
3083 if (editing != editing_) {
3084 if (editing_)
3085 [switch_ removeFromSuperview];
3086 else
3087 [self addSubview:switch_];
3088 editing_ = editing;
3089 }
3090
5e563e79 3091 [self clearSection];
fa7bb92f 3092
e057ec05 3093 if (section == nil) {
5e563e79
JF
3094 name_ = [@"All Packages" retain];
3095 count_ = nil;
e057ec05 3096 } else {
fa7bb92f
JF
3097 section_ = [section name];
3098 if (section_ != nil)
3099 section_ = [section_ retain];
5e563e79
JF
3100 name_ = [(section_ == nil ? @"(No Section)" : section_) retain];
3101 count_ = [[NSString stringWithFormat:@"%d", [section count]] retain];
fa7bb92f
JF
3102
3103 if (editing_)
3104 [switch_ setValue:isSectionVisible(section_) animated:NO];
e057ec05 3105 }
5e563e79
JF
3106}
3107
3108- (void) drawContentInRect:(CGRect)rect selected:(BOOL)selected {
3109 [icon_ drawInRect:CGRectMake(8, 7, 32, 32)];
3110
3111 if (selected)
3112 UISetColor(White_);
3113
3114 if (!selected)
3115 UISetColor(Black_);
3116 [name_ drawAtPoint:CGPointMake(48, 9) forWidth:(editing_ ? 164 : 250) withFont:Font22Bold_ ellipsis:2];
fa7bb92f 3117
5e563e79
JF
3118 CGSize size = [count_ sizeWithFont:Font14_];
3119
3120 UISetColor(White_);
3121 if (count_ != nil)
3122 [count_ drawAtPoint:CGPointMake(12 + (29 - size.width) / 2, 15) withFont:Font12Bold_];
3123
3124 [super drawContentInRect:rect selected:selected];
a933cee2
JF
3125}
3126
e057ec05
JF
3127@end
3128/* }}} */
a933cee2 3129
59efd93a
JF
3130/* File Table {{{ */
3131@interface FileTable : RVPage {
e057ec05 3132 _transient Database *database_;
59efd93a
JF
3133 Package *package_;
3134 NSString *name_;
3135 NSMutableArray *files_;
3136 UITable *list_;
3137}
a933cee2 3138
59efd93a
JF
3139- (id) initWithBook:(RVBook *)book database:(Database *)database;
3140- (void) setPackage:(Package *)package;
3141
3142@end
3143
3144@implementation FileTable
3145
3146- (void) dealloc {
3147 if (package_ != nil)
3148 [package_ release];
3149 if (name_ != nil)
3150 [name_ release];
3151 [files_ release];
3152 [list_ release];
3153 [super dealloc];
3154}
3155
3156- (int) numberOfRowsInTable:(UITable *)table {
3157 return files_ == nil ? 0 : [files_ count];
3158}
3159
3160- (float) table:(UITable *)table heightForRow:(int)row {
3161 return 24;
3162}
3163
3164- (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
3165 if (reusing == nil) {
3166 reusing = [[[UIImageAndTextTableCell alloc] init] autorelease];
d210b85d 3167 UIFont *font = [UIFont systemFontOfSize:16];
59efd93a 3168 [[(UIImageAndTextTableCell *)reusing titleTextLabel] setFont:font];
59efd93a
JF
3169 }
3170 [(UIImageAndTextTableCell *)reusing setTitle:[files_ objectAtIndex:row]];
3171 return reusing;
e057ec05 3172}
a933cee2 3173
30edf48c 3174- (BOOL) table:(UITable *)table canSelectRow:(int)row {
59efd93a
JF
3175 return NO;
3176}
a933cee2 3177
59efd93a
JF
3178- (id) initWithBook:(RVBook *)book database:(Database *)database {
3179 if ((self = [super initWithBook:book]) != nil) {
3180 database_ = database;
a933cee2 3181
59efd93a 3182 files_ = [[NSMutableArray arrayWithCapacity:32] retain];
20dd7407 3183
59efd93a
JF
3184 list_ = [[UITable alloc] initWithFrame:[self bounds]];
3185 [self addSubview:list_];
3186
3187 UITableColumn *column = [[[UITableColumn alloc]
3188 initWithTitle:@"Name"
3189 identifier:@"name"
3190 width:[self frame].size.width
3191 ] autorelease];
3192
3193 [list_ setDataSource:self];
3194 [list_ setSeparatorStyle:1];
3195 [list_ addTableColumn:column];
3196 [list_ setDelegate:self];
3197 [list_ setReusesTableCells:YES];
3198 } return self;
3199}
3200
3201- (void) setPackage:(Package *)package {
3202 if (package_ != nil) {
3203 [package_ autorelease];
3204 package_ = nil;
3205 }
3206
3207 if (name_ != nil) {
3208 [name_ release];
3209 name_ = nil;
3210 }
3211
3212 [files_ removeAllObjects];
3213
3214 if (package != nil) {
3215 package_ = [package retain];
3216 name_ = [[package id] retain];
3217
fc19e583
JF
3218 NSString *path = [NSString stringWithFormat:@"/var/lib/dpkg/info/%@.list", name_];
3219
3220 {
3221 std::ifstream fin([path UTF8String]);
3222 std::string line;
3223 while (std::getline(fin, line))
3224 [files_ addObject:[NSString stringWithUTF8String:line.c_str()]];
3225 }
59efd93a 3226
fc19e583
JF
3227 if ([files_ count] != 0) {
3228 if ([[files_ objectAtIndex:0] isEqualToString:@"/."])
3229 [files_ removeObjectAtIndex:0];
9e07091a 3230 [files_ sortUsingSelector:@selector(compareByPath:)];
2a987aa5
JF
3231
3232 NSMutableArray *stack = [NSMutableArray arrayWithCapacity:8];
3233 [stack addObject:@"/"];
3234
3235 for (int i(0), e([files_ count]); i != e; ++i) {
3236 NSString *file = [files_ objectAtIndex:i];
3237 while (![file hasPrefix:[stack lastObject]])
3238 [stack removeLastObject];
3239 NSString *directory = [stack lastObject];
3240 [stack addObject:[file stringByAppendingString:@"/"]];
3241 [files_ replaceObjectAtIndex:i withObject:[NSString stringWithFormat:@"%*s%@",
9e07091a 3242 ([stack count] - 2) * 3, "",
2a987aa5
JF
3243 [file substringFromIndex:[directory length]]
3244 ]];
3245 }
59efd93a
JF
3246 }
3247 }
3248
3249 [list_ reloadData];
3250}
3251
3252- (void) resetViewAnimated:(BOOL)animated {
3253 [list_ resetViewAnimated:animated];
3254}
3255
3256- (void) reloadData {
3257 [self setPackage:[database_ packageWithName:name_]];
3258 [self reloadButtons];
3259}
3260
3261- (NSString *) title {
2a987aa5
JF
3262 return @"Installed Files";
3263}
3264
3265- (NSString *) backButtonTitle {
3266 return @"Files";
59efd93a 3267}
686e302f 3268
686e302f 3269@end
e057ec05 3270/* }}} */
e057ec05 3271/* Package View {{{ */
ad554f10 3272@interface PackageView : BrowserView {
e057ec05
JF
3273 Package *package_;
3274 NSString *name_;
965edd52 3275 NSMutableArray *buttons_;
df5a7529
JF
3276}
3277
e057ec05
JF
3278- (id) initWithBook:(RVBook *)book database:(Database *)database;
3279- (void) setPackage:(Package *)package;
686e302f 3280
e057ec05 3281@end
686e302f 3282
e057ec05 3283@implementation PackageView
686e302f 3284
e057ec05 3285- (void) dealloc {
e057ec05
JF
3286 if (package_ != nil)
3287 [package_ release];
3288 if (name_ != nil)
3289 [name_ release];
965edd52 3290 [buttons_ release];
e057ec05
JF
3291 [super dealloc];
3292}
20dd7407 3293
965edd52
JF
3294- (void) _clickButtonWithName:(NSString *)name {
3295 if ([name isEqualToString:@"Install"])
3296 [delegate_ installPackage:package_];
3297 else if ([name isEqualToString:@"Reinstall"])
3298 [delegate_ installPackage:package_];
3299 else if ([name isEqualToString:@"Remove"])
3300 [delegate_ removePackage:package_];
3301 else if ([name isEqualToString:@"Upgrade"])
3302 [delegate_ installPackage:package_];
3303 else _assert(false);
3304}
3305
d210b85d 3306- (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
965edd52
JF
3307 int count = [buttons_ count];
3308 _assert(count != 0);
3309 _assert(button <= count + 1);
3310
3311 if (count != button - 1)
3312 [self _clickButtonWithName:[buttons_ objectAtIndex:(button - 1)]];
e057ec05
JF
3313
3314 [sheet dismiss];
686e302f 3315}
4941f41d 3316
853d14d3
JF
3317#include "internals.h"
3318
3319- (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
3320 [[frame windowObject] evaluateWebScript:@"document.base.target = '_top'"];
3321 return [super webView:sender didFinishLoadForFrame:frame];
3322}
3323
ad554f10 3324- (void) webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame {
ad554f10
JF
3325 [window setValue:package_ forKey:@"package"];
3326}
3327
e057ec05 3328- (void) _rightButtonClicked {
ad554f10
JF
3329 /*[super _rightButtonClicked];
3330 return;*/
3331
965edd52
JF
3332 int count = [buttons_ count];
3333 _assert(count != 0);
4941f41d 3334
965edd52
JF
3335 if (count == 1)
3336 [self _clickButtonWithName:[buttons_ objectAtIndex:0]];
3337 else {
3338 NSMutableArray *buttons = [NSMutableArray arrayWithCapacity:(count + 1)];
3339 [buttons addObjectsFromArray:buttons_];
e057ec05
JF
3340 [buttons addObject:@"Cancel"];
3341
d210b85d 3342 [delegate_ slideUp:[[[UIActionSheet alloc]
fc19e583 3343 initWithTitle:nil
e057ec05
JF
3344 buttons:buttons
3345 defaultButtonIndex:2
3346 delegate:self
9e07091a 3347 context:@"manage"
e057ec05
JF
3348 ] autorelease]];
3349 }
686e302f 3350}
4941f41d 3351
ad554f10 3352- (NSString *) _rightButtonTitle {
965edd52
JF
3353 int count = [buttons_ count];
3354 return count == 0 ? nil : count != 1 ? @"Modify" : [buttons_ objectAtIndex:0];
686e302f 3355}
4941f41d 3356
e057ec05
JF
3357- (NSString *) title {
3358 return @"Details";
a75f53e7
JF
3359}
3360
e057ec05 3361- (id) initWithBook:(RVBook *)book database:(Database *)database {
ad554f10 3362 if ((self = [super initWithBook:book database:database]) != nil) {
e057ec05 3363 database_ = database;
965edd52 3364 buttons_ = [[NSMutableArray alloc] initWithCapacity:4];
e057ec05 3365 } return self;
a75f53e7
JF
3366}
3367
e057ec05
JF
3368- (void) setPackage:(Package *)package {
3369 if (package_ != nil) {
3370 [package_ autorelease];
3371 package_ = nil;
3372 }
3373
3374 if (name_ != nil) {
3375 [name_ release];
3376 name_ = nil;
3377 }
3378
965edd52
JF
3379 [buttons_ removeAllObjects];
3380
e057ec05
JF
3381 if (package != nil) {
3382 package_ = [package retain];
3383 name_ = [[package id] retain];
3384
ad554f10 3385 [self loadURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"package" ofType:@"html"]]];
965edd52
JF
3386
3387 if ([package_ source] == nil);
238b07ce
JF
3388 else if ([package_ upgradableAndEssential:NO])
3389 [buttons_ addObject:@"Upgrade"];
965edd52
JF
3390 else if ([package_ installed] == nil)
3391 [buttons_ addObject:@"Install"];
965edd52
JF
3392 else
3393 [buttons_ addObject:@"Reinstall"];
3394 if ([package_ installed] != nil)
3395 [buttons_ addObject:@"Remove"];
e057ec05 3396 }
a75f53e7
JF
3397}
3398
e057ec05
JF
3399- (void) reloadData {
3400 [self setPackage:[database_ packageWithName:name_]];
3401 [self reloadButtons];
b6ffa083
JF
3402}
3403
686e302f
JF
3404@end
3405/* }}} */
686e302f 3406/* Package Table {{{ */
e057ec05
JF
3407@interface PackageTable : RVPage {
3408 _transient Database *database_;
3409 NSString *title_;
3410 SEL filter_;
3411 id object_;
3412 NSMutableArray *packages_;
686e302f 3413 NSMutableArray *sections_;
e057ec05 3414 UISectionList *list_;
a75f53e7
JF
3415}
3416
e057ec05 3417- (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object;
686e302f
JF
3418
3419- (void) setDelegate:(id)delegate;
8993ad57
JF
3420- (void) setObject:(id)object;
3421
e057ec05 3422- (void) reloadData;
8993ad57 3423- (void) resetCursor;
686e302f 3424
2a987aa5
JF
3425- (UISectionList *) list;
3426
59efd93a
JF
3427- (void) setShouldHideHeaderInShortLists:(BOOL)hide;
3428
686e302f
JF
3429@end
3430
3431@implementation PackageTable
3432
3433- (void) dealloc {
e057ec05
JF
3434 [list_ setDataSource:nil];
3435
3436 [title_ release];
3437 if (object_ != nil)
3438 [object_ release];
3439 [packages_ release];
686e302f 3440 [sections_ release];
e057ec05 3441 [list_ release];
686e302f 3442 [super dealloc];
b6ffa083
JF
3443}
3444
686e302f
JF
3445- (int) numberOfSectionsInSectionList:(UISectionList *)list {
3446 return [sections_ count];
3447}
4941f41d 3448
686e302f
JF
3449- (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
3450 return [[sections_ objectAtIndex:section] name];
3451}
a75f53e7 3452
686e302f
JF
3453- (int) sectionList:(UISectionList *)list rowForSection:(int)section {
3454 return [[sections_ objectAtIndex:section] row];
4941f41d
JF
3455}
3456
686e302f
JF
3457- (int) numberOfRowsInTable:(UITable *)table {
3458 return [packages_ count];
3459}
a75f53e7 3460
686e302f 3461- (float) table:(UITable *)table heightForRow:(int)row {
3319715b 3462 return [PackageCell heightForPackage:[packages_ objectAtIndex:row]];
686e302f 3463}
a75f53e7 3464
686e302f
JF
3465- (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
3466 if (reusing == nil)
e057ec05 3467 reusing = [[[PackageCell alloc] init] autorelease];
686e302f
JF
3468 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
3469 return reusing;
3470}
a75f53e7 3471
686e302f
JF
3472- (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
3473 return NO;
3474}
a75f53e7 3475
686e302f
JF
3476- (void) tableRowSelected:(NSNotification *)notification {
3477 int row = [[notification object] selectedRow];
e057ec05
JF
3478 if (row == INT_MAX)
3479 return;
3480
3481 Package *package = [packages_ objectAtIndex:row];
3482 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
3483 [view setDelegate:delegate_];
3484 [view setPackage:package];
3485 [book_ pushPage:view];
a75f53e7
JF
3486}
3487
e057ec05
JF
3488- (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object {
3489 if ((self = [super initWithBook:book]) != nil) {
3490 database_ = database;
3491 title_ = [title retain];
3492 filter_ = filter;
3493 object_ = object == nil ? nil : [object retain];
3494
3495 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
686e302f 3496 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
a75f53e7 3497
686e302f
JF
3498 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:YES];
3499 [list_ setDataSource:self];
a75f53e7 3500
686e302f
JF
3501 UITableColumn *column = [[[UITableColumn alloc]
3502 initWithTitle:@"Name"
3503 identifier:@"name"
e057ec05 3504 width:[self frame].size.width
686e302f
JF
3505 ] autorelease];
3506
3507 UITable *table = [list_ table];
3508 [table setSeparatorStyle:1];
3509 [table addTableColumn:column];
3510 [table setDelegate:self];
3511 [table setReusesTableCells:YES];
3512
3513 [self addSubview:list_];
e057ec05 3514 [self reloadData];
686e302f 3515 } return self;
a75f53e7
JF
3516}
3517
3518- (void) setDelegate:(id)delegate {
4941f41d 3519 delegate_ = delegate;
686e302f
JF
3520}
3521
8993ad57
JF
3522- (void) setObject:(id)object {
3523 if (object_ != nil)
3524 [object_ release];
3525 if (object == nil)
3526 object_ = nil;
3527 else
3528 object_ = [object retain];
3529}
3530
e057ec05
JF
3531- (void) reloadData {
3532 NSArray *packages = [database_ packages];
686e302f 3533
e057ec05 3534 [packages_ removeAllObjects];
686e302f
JF
3535 [sections_ removeAllObjects];
3536
e057ec05
JF
3537 for (size_t i(0); i != [packages count]; ++i) {
3538 Package *package([packages objectAtIndex:i]);
853d14d3 3539 if ([package valid] && [[package performSelector:filter_ withObject:object_] boolValue])
e057ec05
JF
3540 [packages_ addObject:package];
3541 }
3542
686e302f
JF
3543 Section *section = nil;
3544
3545 for (size_t offset(0); offset != [packages_ count]; ++offset) {
3546 Package *package = [packages_ objectAtIndex:offset];
3547 NSString *name = [package index];
3548
e057ec05 3549 if (section == nil || ![[section name] isEqualToString:name]) {
686e302f
JF
3550 section = [[[Section alloc] initWithName:name row:offset] autorelease];
3551 [sections_ addObject:section];
3552 }
3553
e057ec05 3554 [section addToCount];
686e302f
JF
3555 }
3556
3557 [list_ reloadData];
3558}
3559
e057ec05
JF
3560- (NSString *) title {
3561 return title_;
686e302f
JF
3562}
3563
e057ec05
JF
3564- (void) resetViewAnimated:(BOOL)animated {
3565 [list_ resetViewAnimated:animated];
a75f53e7
JF
3566}
3567
8993ad57
JF
3568- (void) resetCursor {
3569 [[list_ table] scrollPointVisibleAtTopLeft:CGPointMake(0, 0) animated:NO];
3570}
3571
2a987aa5
JF
3572- (UISectionList *) list {
3573 return list_;
3574}
3575
59efd93a
JF
3576- (void) setShouldHideHeaderInShortLists:(BOOL)hide {
3577 [list_ setShouldHideHeaderInShortLists:hide];
3578}
3579
a75f53e7 3580@end
686e302f 3581/* }}} */
a75f53e7 3582
faf4eb4f
JF
3583/* Add Source View {{{ */
3584@interface AddSourceView : RVPage {
3585 _transient Database *database_;
a75f53e7
JF
3586}
3587
faf4eb4f 3588- (id) initWithBook:(RVBook *)book database:(Database *)database;
686e302f 3589
faf4eb4f 3590@end
a75f53e7 3591
faf4eb4f 3592@implementation AddSourceView
a75f53e7 3593
faf4eb4f
JF
3594- (id) initWithBook:(RVBook *)book database:(Database *)database {
3595 if ((self = [super initWithBook:book]) != nil) {
3596 database_ = database;
3597 } return self;
e057ec05 3598}
a75f53e7 3599
faf4eb4f
JF
3600@end
3601/* }}} */
3602/* Source Cell {{{ */
3603@interface SourceCell : UITableCell {
5e563e79
JF
3604 UIImage *icon_;
3605 NSString *origin_;
3606 NSString *description_;
3607 NSString *label_;
686e302f
JF
3608}
3609
faf4eb4f 3610- (void) dealloc;
686e302f 3611
faf4eb4f 3612- (SourceCell *) initWithSource:(Source *)source;
686e302f 3613
faf4eb4f 3614@end
686e302f 3615
faf4eb4f 3616@implementation SourceCell
686e302f 3617
faf4eb4f 3618- (void) dealloc {
5e563e79 3619 [icon_ release];
faf4eb4f
JF
3620 [origin_ release];
3621 [description_ release];
3622 [label_ release];
3623 [super dealloc];
e057ec05 3624}
686e302f 3625
faf4eb4f
JF
3626- (SourceCell *) initWithSource:(Source *)source {
3627 if ((self = [super init]) != nil) {
5e563e79
JF
3628 if (icon_ == nil)
3629 icon_ = [UIImage applicationImageNamed:[NSString stringWithFormat:@"Sources/%@.png", [source host]]];
3630 if (icon_ == nil)
3631 icon_ = [UIImage applicationImageNamed:@"unknown.png"];
3632 icon_ = [icon_ retain];
3633
3634 origin_ = [[source name] retain];
3635 label_ = [[source uri] retain];
3636 description_ = [[source description] retain];
faf4eb4f 3637 } return self;
48c0461e
JF
3638}
3639
5e563e79
JF
3640- (void) drawContentInRect:(CGRect)rect selected:(BOOL)selected {
3641 if (icon_ != nil)
3642 [icon_ drawInRect:CGRectMake(10, 10, 30, 30)];
faf4eb4f 3643
5e563e79
JF
3644 if (selected)
3645 UISetColor(White_);
faf4eb4f 3646
5e563e79
JF
3647 if (!selected)
3648 UISetColor(Black_);
3649 [origin_ drawAtPoint:CGPointMake(48, 8) forWidth:240 withFont:Font18Bold_ ellipsis:2];
faf4eb4f 3650
5e563e79
JF
3651 if (!selected)
3652 UISetColor(Blue_);
3653 [label_ drawAtPoint:CGPointMake(58, 29) forWidth:225 withFont:Font12_ ellipsis:2];
faf4eb4f 3654
5e563e79
JF
3655 if (!selected)
3656 UISetColor(Gray_);
3657 [description_ drawAtPoint:CGPointMake(12, 46) forWidth:280 withFont:Font14_ ellipsis:2];
faf4eb4f 3658
5e563e79 3659 [super drawContentInRect:rect selected:selected];
faf4eb4f
JF
3660}
3661
3662@end
3663/* }}} */
3664/* Source Table {{{ */
3665@interface SourceTable : RVPage {
3666 _transient Database *database_;
3667 UISectionList *list_;
3668 NSMutableArray *sources_;
d210b85d 3669 UIActionSheet *alert_;
faf4eb4f
JF
3670 int offset_;
3671
3672 NSString *href_;
3673 UIProgressHUD *hud_;
3674 NSError *error_;
3675
3676 //NSURLConnection *installer_;
3677 NSURLConnection *trivial_bz2_;
3678 NSURLConnection *trivial_gz_;
3679 //NSURLConnection *automatic_;
3680
3681 BOOL trivial_;
3682}
3683
3684- (id) initWithBook:(RVBook *)book database:(Database *)database;
3685
3686@end
3687
3688@implementation SourceTable
3689
3690- (void) _deallocConnection:(NSURLConnection *)connection {
3691 if (connection != nil) {
3692 [connection cancel];
3693 //[connection setDelegate:nil];
3694 [connection release];
3695 }
3696}
3697
3698- (void) dealloc {
3699 [[list_ table] setDelegate:nil];
3700 [list_ setDataSource:nil];
3701
3702 if (href_ != nil)
3703 [href_ release];
3704 if (hud_ != nil)
3705 [hud_ release];
3706 if (error_ != nil)
3707 [error_ release];
3708
3709 //[self _deallocConnection:installer_];
3710 [self _deallocConnection:trivial_gz_];
3711 [self _deallocConnection:trivial_bz2_];
3712 //[self _deallocConnection:automatic_];
3713
3714 [sources_ release];
3715 [list_ release];
3716 [super dealloc];
3717}
3718
3719- (int) numberOfSectionsInSectionList:(UISectionList *)list {
3720 return offset_ == 0 ? 1 : 2;
3721}
3722
3723- (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
3724 switch (section + (offset_ == 0 ? 1 : 0)) {
3725 case 0: return @"Entered by User";
3726 case 1: return @"Installed by Packages";
3727
3728 default:
3729 _assert(false);
3730 return nil;
3731 }
3732}
3733
3734- (int) sectionList:(UISectionList *)list rowForSection:(int)section {
3735 switch (section + (offset_ == 0 ? 1 : 0)) {
3736 case 0: return 0;
3737 case 1: return offset_;
3738
3739 default:
3740 _assert(false);
3741 return -1;
3742 }
3743}
3744
3745- (int) numberOfRowsInTable:(UITable *)table {
3746 return [sources_ count];
3747}
3748
3749- (float) table:(UITable *)table heightForRow:(int)row {
3750 Source *source = [sources_ objectAtIndex:row];
5e563e79 3751 return [source description] == nil ? 56 : 73;
faf4eb4f
JF
3752}
3753
3754- (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col {
3755 Source *source = [sources_ objectAtIndex:row];
3756 // XXX: weird warning, stupid selectors ;P
3757 return [[[SourceCell alloc] initWithSource:(id)source] autorelease];
3758}
3759
3760- (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
3761 return YES;
3762}
3763
3764- (BOOL) table:(UITable *)table canSelectRow:(int)row {
3765 return YES;
3766}
3767
3768- (void) tableRowSelected:(NSNotification*)notification {
3769 UITable *table([list_ table]);
3770 int row([table selectedRow]);
3771 if (row == INT_MAX)
3772 return;
3773
3774 Source *source = [sources_ objectAtIndex:row];
3775
3776 PackageTable *packages = [[[PackageTable alloc]
3777 initWithBook:book_
3778 database:database_
3779 title:[source label]
3780 filter:@selector(isVisibleInSource:)
3781 with:source
3782 ] autorelease];
3783
3784 [packages setDelegate:delegate_];
3785
3786 [book_ pushPage:packages];
3787}
3788
3789- (BOOL) table:(UITable *)table canDeleteRow:(int)row {
3790 Source *source = [sources_ objectAtIndex:row];
3791 return [source record] != nil;
3792}
3793
3794- (void) table:(UITable *)table willSwipeToDeleteRow:(int)row {
3795 [[list_ table] setDeleteConfirmationRow:row];
3796}
3797
3798- (void) table:(UITable *)table deleteRow:(int)row {
3799 Source *source = [sources_ objectAtIndex:row];
3800 [Sources_ removeObjectForKey:[source key]];
3801 [delegate_ syncData];
3802}
3803
3804- (void) _endConnection:(NSURLConnection *)connection {
3805 NSURLConnection **field = NULL;
3806 if (connection == trivial_bz2_)
3807 field = &trivial_bz2_;
3808 else if (connection == trivial_gz_)
3809 field = &trivial_gz_;
3810 _assert(field != NULL);
3811 [connection release];
3812 *field = nil;
3813
3814 if (
3815 trivial_bz2_ == nil &&
3816 trivial_gz_ == nil
3817 ) {
3818 [delegate_ setStatusBarShowsProgress:NO];
3819
3820 [hud_ show:NO];
3821 [hud_ removeFromSuperview];
3822 [hud_ autorelease];
3823 hud_ = nil;
3824
3825 if (trivial_) {
3826 [Sources_ setObject:[NSDictionary dictionaryWithObjectsAndKeys:
3827 @"deb", @"Type",
3828 href_, @"URI",
3829 @"./", @"Distribution",
3830 nil] forKey:[NSString stringWithFormat:@"deb:%@:./", href_]];
3831
3832 [delegate_ syncData];
3833 } else if (error_ != nil) {
d210b85d 3834 UIActionSheet *sheet = [[[UIActionSheet alloc]
faf4eb4f
JF
3835 initWithTitle:@"Verification Error"
3836 buttons:[NSArray arrayWithObjects:@"OK", nil]
3837 defaultButtonIndex:0
3838 delegate:self
3839 context:@"urlerror"
3840 ] autorelease];
3841
3842 [sheet setBodyText:[error_ localizedDescription]];
3843 [sheet popupAlertAnimated:YES];
3844 } else {
d210b85d 3845 UIActionSheet *sheet = [[[UIActionSheet alloc]
faf4eb4f
JF
3846 initWithTitle:@"Did not Find Repository"
3847 buttons:[NSArray arrayWithObjects:@"OK", nil]
3848 defaultButtonIndex:0
3849 delegate:self
3850 context:@"trivial"
3851 ] autorelease];
3852
3853 [sheet setBodyText:@"The indicated repository could not be found. This could be because you are trying to add a legacy Installer repository (these are not supported). Also, this interface is only capable of working with exact repository URLs. If you host a repository and are having issues please contact the author of Cydia with any questions you have."];
3854 [sheet popupAlertAnimated:YES];
3855 }
3856
3857 [href_ release];
3858 href_ = nil;
3859
3860 if (error_ != nil) {
3861 [error_ release];
3862 error_ = nil;
3863 }
3864 }
3865}
3866
3867- (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response {
3868 switch ([response statusCode]) {
3869 case 200:
3870 trivial_ = YES;
3871 }
3872}
3873
3874- (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
3875 fprintf(stderr, "connection:\"%s\" didFailWithError:\"%s\"", [href_ UTF8String], [[error localizedDescription] UTF8String]);
3876 if (error_ != nil)
3877 error_ = [error retain];
3878 [self _endConnection:connection];
3879}
3880
3881- (void) connectionDidFinishLoading:(NSURLConnection *)connection {
3882 [self _endConnection:connection];
3883}
3884
3885- (NSURLConnection *) _requestHRef:(NSString *)href method:(NSString *)method {
3886 NSMutableURLRequest *request = [NSMutableURLRequest
3887 requestWithURL:[NSURL URLWithString:href]
3888 cachePolicy:NSURLRequestUseProtocolCachePolicy
3889 timeoutInterval:20.0
3890 ];
3891
3892 [request setHTTPMethod:method];
3893
3894 return [[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease];
3895}
3896
d210b85d 3897- (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
faf4eb4f
JF
3898 NSString *context = [sheet context];
3899 if ([context isEqualToString:@"source"])
3900 switch (button) {
3901 case 1: {
3902 NSString *href = [[sheet textField] text];
3903
3904 //installer_ = [[self _requestHRef:href method:@"GET"] retain];
3905
3906 if (![href hasSuffix:@"/"])
3907 href_ = [href stringByAppendingString:@"/"];
3908 else
3909 href_ = href;
3910 href_ = [href_ retain];
3911
3912 trivial_bz2_ = [[self _requestHRef:[href_ stringByAppendingString:@"Packages.bz2"] method:@"HEAD"] retain];
3913 trivial_gz_ = [[self _requestHRef:[href_ stringByAppendingString:@"Packages.gz"] method:@"HEAD"] retain];
3914 //trivial_bz2_ = [[self _requestHRef:[href stringByAppendingString:@"dists/Release"] method:@"HEAD"] retain];
3915
3916 trivial_ = false;
3917
3918 hud_ = [delegate_ addProgressHUD];
3919 [hud_ setText:@"Verifying URL"];
3920 } break;
3921
3922 case 2:
3923 break;
3924
3925 default:
3926 _assert(false);
3927 }
3928
3929 [sheet dismiss];
3930}
3931
3932- (id) initWithBook:(RVBook *)book database:(Database *)database {
3933 if ((self = [super initWithBook:book]) != nil) {
3934 database_ = database;
3935 sources_ = [[NSMutableArray arrayWithCapacity:16] retain];
3936
3937 //list_ = [[UITable alloc] initWithFrame:[self bounds]];
3938 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:NO];
3939 [list_ setShouldHideHeaderInShortLists:NO];
3940
3941 [self addSubview:list_];
3942 [list_ setDataSource:self];
3943
3944 UITableColumn *column = [[UITableColumn alloc]
3945 initWithTitle:@"Name"
3946 identifier:@"name"
3947 width:[self frame].size.width
3948 ];
3949
3950 UITable *table = [list_ table];
3951 [table setSeparatorStyle:1];
3952 [table addTableColumn:column];
3953 [table setDelegate:self];
3954
3955 [self reloadData];
3956 } return self;
3957}
3958
3959- (void) reloadData {
3960 pkgSourceList list;
3961 _assert(list.ReadMainList());
3962
3963 [sources_ removeAllObjects];
3964 [sources_ addObjectsFromArray:[database_ sources]];
3965 [sources_ sortUsingSelector:@selector(compareByNameAndType:)];
3966
3967 int count = [sources_ count];
3968 for (offset_ = 0; offset_ != count; ++offset_) {
3969 Source *source = [sources_ objectAtIndex:offset_];
3970 if ([source record] == nil)
3971 break;
3972 }
3973
3974 [list_ reloadData];
3975}
3976
3977- (void) resetViewAnimated:(BOOL)animated {
3978 [list_ resetViewAnimated:animated];
3979}
3980
3981- (void) _leftButtonClicked {
3982 /*[book_ pushPage:[[[AddSourceView alloc]
3983 initWithBook:book_
3984 database:database_
3985 ] autorelease]];*/
3986
d210b85d 3987 UIActionSheet *sheet = [[[UIActionSheet alloc]
faf4eb4f
JF
3988 initWithTitle:@"Enter Cydia/APT URL"
3989 buttons:[NSArray arrayWithObjects:@"Add Source", @"Cancel", nil]
3990 defaultButtonIndex:0
3991 delegate:self
3992 context:@"source"
3993 ] autorelease];
3994
3995 [sheet addTextFieldWithValue:@"http://" label:@""];
3996
d210b85d
JF
3997 UITextInputTraits *traits = [[sheet textField] textInputTraits];
3998 [traits setAutocapitalizationType:0];
3999 [traits setKeyboardType:3];
4000 [traits setAutocorrectionType:1];
faf4eb4f
JF
4001
4002 [sheet popupAlertAnimated:YES];
4003}
4004
4005- (void) _rightButtonClicked {
4006 UITable *table = [list_ table];
4007 BOOL editing = [table isRowDeletionEnabled];
4008 [table enableRowDeletion:!editing animated:YES];
4009 [book_ reloadButtonsForPage:self];
4010}
4011
4012- (NSString *) title {
4013 return @"Sources";
4014}
4015
4016- (NSString *) backButtonTitle {
4017 return @"Sources";
4018}
4019
4020- (NSString *) leftButtonTitle {
4021 return [[list_ table] isRowDeletionEnabled] ? @"Add" : nil;
4022}
4023
4024- (NSString *) rightButtonTitle {
4025 return [[list_ table] isRowDeletionEnabled] ? @"Done" : @"Edit";
4026}
4027
4028- (RVUINavBarButtonStyle) rightButtonStyle {
4029 return [[list_ table] isRowDeletionEnabled] ? RVUINavBarButtonStyleHighlighted : RVUINavBarButtonStyleNormal;
4030}
4031
4032@end
4033/* }}} */
4034
4035/* Installed View {{{ */
4036@interface InstalledView : RVPage {
4037 _transient Database *database_;
4038 PackageTable *packages_;
5e563e79 4039 BOOL expert_;
faf4eb4f
JF
4040}
4041
4042- (id) initWithBook:(RVBook *)book database:(Database *)database;
4043
4044@end
4045
4046@implementation InstalledView
4047
4048- (void) dealloc {
4049 [packages_ release];
4050 [super dealloc];
4051}
4052
4053- (id) initWithBook:(RVBook *)book database:(Database *)database {
4054 if ((self = [super initWithBook:book]) != nil) {
4055 database_ = database;
4056
4057 packages_ = [[PackageTable alloc]
4058 initWithBook:book
4059 database:database
4060 title:nil
853d14d3 4061 filter:@selector(isInstalledAndUnfiltered:)
5e563e79 4062 with:[NSNumber numberWithBool:YES]
faf4eb4f
JF
4063 ];
4064
4065 [self addSubview:packages_];
4066 } return self;
4067}
4068
4069- (void) resetViewAnimated:(BOOL)animated {
4070 [packages_ resetViewAnimated:animated];
4071}
4072
4073- (void) reloadData {
4074 [packages_ reloadData];
4075}
4076
5e563e79
JF
4077- (void) _rightButtonClicked {
4078 [packages_ setObject:[NSNumber numberWithBool:expert_]];
4079 [packages_ reloadData];
4080 expert_ = !expert_;
4081 [book_ reloadButtonsForPage:self];
4082}
4083
faf4eb4f 4084- (NSString *) title {
5e563e79 4085 return @"Installed";
faf4eb4f
JF
4086}
4087
4088- (NSString *) backButtonTitle {
4089 return @"Packages";
4090}
4091
5e563e79
JF
4092- (NSString *) rightButtonTitle {
4093 return Role_ != nil && [Role_ isEqualToString:@"Developer"] ? nil : expert_ ? @"Expert" : @"Simple";
4094}
4095
4096- (RVUINavBarButtonStyle) rightButtonStyle {
4097 return expert_ ? RVUINavBarButtonStyleHighlighted : RVUINavBarButtonStyleNormal;
4098}
4099
faf4eb4f
JF
4100- (void) setDelegate:(id)delegate {
4101 [super setDelegate:delegate];
4102 [packages_ setDelegate:delegate];
4103}
4104
4105@end
4106/* }}} */
4107
1bb0d66c 4108/* Home View {{{ */
faf4eb4f
JF
4109@interface HomeView : BrowserView {
4110}
4111
4112@end
4113
4114@implementation HomeView
4115
d210b85d 4116- (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
faf4eb4f
JF
4117 [sheet dismiss];
4118}
4119
4120- (void) _leftButtonClicked {
d210b85d 4121 UIActionSheet *sheet = [[[UIActionSheet alloc]
faf4eb4f
JF
4122 initWithTitle:@"About Cydia Installer"
4123 buttons:[NSArray arrayWithObjects:@"Close", nil]
4124 defaultButtonIndex:0
4125 delegate:self
4126 context:@"about"
4127 ] autorelease];
4128
4129 [sheet setBodyText:
4130 @"Copyright (C) 2008\n"
4131 "Jay Freeman (saurik)\n"
4132 "saurik@saurik.com\n"
4133 "http://www.saurik.com/\n"
4134 "\n"
4135 "The Okori Group\n"
4136 "http://www.theokorigroup.com/\n"
4137 "\n"
4138 "College of Creative Studies,\n"
4139 "University of California,\n"
4140 "Santa Barbara\n"
4141 "http://www.ccs.ucsb.edu/"
4142 ];
4143
4144 [sheet popupAlertAnimated:YES];
4145}
4146
4147- (NSString *) leftButtonTitle {
4148 return @"About";
4149}
4150
4151@end
1bb0d66c
JF
4152/* }}} */
4153/* Manage View {{{ */
faf4eb4f
JF
4154@interface ManageView : BrowserView {
4155}
4156
4157@end
4158
4159@implementation ManageView
4160
4161- (NSString *) title {
4162 return @"Manage";
4163}
4164
4165- (void) _leftButtonClicked {
4166 [delegate_ askForSettings];
4167}
4168
4169- (NSString *) leftButtonTitle {
4170 return @"Settings";
4171}
4172
ad554f10 4173- (NSString *) _rightButtonTitle {
faf4eb4f
JF
4174 return nil;
4175}
4176
4177@end
1bb0d66c 4178/* }}} */
faf4eb4f
JF
4179
4180/* Browser Implementation {{{ */
4181@implementation BrowserView
4182
4183- (void) dealloc {
4184 WebView *webview = [webview_ webView];
4185 [webview setFrameLoadDelegate:nil];
4186 [webview setResourceLoadDelegate:nil];
4187 [webview setUIDelegate:nil];
4188
4189 [scroller_ setDelegate:nil];
4190 [webview_ setDelegate:nil];
4191
4192 [scroller_ release];
4193 [webview_ release];
4194 [urls_ release];
4195 [indicator_ release];
4196 if (title_ != nil)
4197 [title_ release];
4198 [super dealloc];
4199}
4200
4201- (void) loadURL:(NSURL *)url cachePolicy:(NSURLRequestCachePolicy)policy {
4202 [self loadRequest:[NSURLRequest
4203 requestWithURL:url
4204 cachePolicy:policy
4205 timeoutInterval:30.0
4206 ]];
4207}
4208
4209- (void) loadURL:(NSURL *)url {
4210 [self loadURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy];
4211}
4212
4213- (NSURLRequest *) _addHeadersToRequest:(NSURLRequest *)request {
4214 NSMutableURLRequest *copy = [request mutableCopy];
4215
4216 [copy addValue:[NSString stringWithUTF8String:Firmware_] forHTTPHeaderField:@"X-Firmware"];
4217 [copy addValue:[NSString stringWithUTF8String:Machine_] forHTTPHeaderField:@"X-Machine"];
4218 [copy addValue:[NSString stringWithUTF8String:SerialNumber_] forHTTPHeaderField:@"X-Serial-Number"];
4219
4220 if (Role_ != nil)
4221 [copy addValue:Role_ forHTTPHeaderField:@"X-Role"];
4222
4223 return copy;
4224}
4225
4226- (void) loadRequest:(NSURLRequest *)request {
4227 pushed_ = true;
4228 [webview_ loadRequest:request];
4229}
4230
4231- (void) reloadURL {
4232 NSURL *url = [[[urls_ lastObject] retain] autorelease];
4233 [urls_ removeLastObject];
4234 [self loadURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData];
4235}
4236
4237- (WebView *) webView {
4238 return [webview_ webView];
4239}
4240
4241- (void) view:(UIView *)sender didSetFrame:(CGRect)frame {
4242 [scroller_ setContentSize:frame.size];
4243}
4244
4245- (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old {
4246 [self view:sender didSetFrame:frame];
4247}
4248
4249- (void) pushPage:(RVPage *)page {
4250 [self setBackButtonTitle:title_];
4251 [page setDelegate:delegate_];
4252 [book_ pushPage:page];
4253}
4254
5e563e79 4255- (void) getSpecial:(NSString *)href {
faf4eb4f
JF
4256 RVPage *page = nil;
4257
5e563e79
JF
4258 if ([href hasPrefix:@"mailto:"])
4259 [delegate_ openURL:[NSURL URLWithString:href]];
4260 else if ([href isEqualToString:@"cydia://add-source"])
faf4eb4f
JF
4261 page = [[[AddSourceView alloc] initWithBook:book_ database:database_] autorelease];
4262 else if ([href isEqualToString:@"cydia://sources"])
4263 page = [[[SourceTable alloc] initWithBook:book_ database:database_] autorelease];
4264 else if ([href isEqualToString:@"cydia://packages"])
4265 page = [[[InstalledView alloc] initWithBook:book_ database:database_] autorelease];
ad554f10
JF
4266 else if ([href hasPrefix:@"cydia://files/"]) {
4267 NSString *name = [href substringFromIndex:14];
4268
4269 if (Package *package = [database_ packageWithName:name]) {
4270 FileTable *files = [[[FileTable alloc] initWithBook:book_ database:database_] autorelease];
4271 [files setPackage:package];
4272 page = files;
4273 }
4274 } else if ([href hasPrefix:@"apptapp://package/"]) {
faf4eb4f 4275 NSString *name = [href substringFromIndex:18];
5e563e79
JF
4276
4277 if (Package *package = [database_ packageWithName:name]) {
4278 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
4279 [view setPackage:package];
4280 page = view;
4281 } else {
d210b85d 4282 UIActionSheet *sheet = [[[UIActionSheet alloc]
faf4eb4f
JF
4283 initWithTitle:@"Cannot Locate Package"
4284 buttons:[NSArray arrayWithObjects:@"Close", nil]
4285 defaultButtonIndex:0
4286 delegate:self
4287 context:@"missing"
4288 ] autorelease];
4289
4290 [sheet setBodyText:[NSString stringWithFormat:
4291 @"The package %@ cannot be found in your current sources. I might recommend installing more sources."
4292 , name]];
4293
4294 [sheet popupAlertAnimated:YES];
faf4eb4f
JF
4295 }
4296 }
5e563e79
JF
4297
4298 if (page != nil)
4299 [self pushPage:page];
faf4eb4f
JF
4300}
4301
4302- (void) webView:(WebView *)sender willClickElement:(id)element {
4303 if ([[element localName] isEqualToString:@"img"])
4304 do if ((element = [element parentNode]) == nil)
4305 return;
4306 while (![[element localName] isEqualToString:@"a"]);
4307 if (![element respondsToSelector:@selector(href)])
4308 return;
4309 NSString *href = [element href];
4310 if (href == nil)
4311 return;
5e563e79 4312 [self getSpecial:href];
faf4eb4f
JF
4313}
4314
5e563e79
JF
4315- (BOOL) isSpecialScheme:(NSString *)scheme {
4316 return
4317 [scheme isEqualToString:@"apptapp"] ||
4318 [scheme isEqualToString:@"cydia"] ||
4319 [scheme isEqualToString:@"mailto"];
4320}
faf4eb4f 4321
5e563e79
JF
4322- (NSURLRequest *) webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource {
4323 NSURL *url = [request URL];
4324 if ([self isSpecialScheme:[url scheme]]) {
4325 [self getSpecial:[url absoluteString]];
faf4eb4f
JF
4326 return nil;
4327 }
4328
4329 if (!pushed_) {
4330 pushed_ = true;
4331 [book_ pushPage:self];
4332 }
4333
4334 return [self _addHeadersToRequest:request];
4335}
4336
4337- (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request {
4338 if (request != nil) {
4339 NSString *scheme = [[request URL] scheme];
5e563e79 4340 if ([self isSpecialScheme:scheme])
faf4eb4f
JF
4341 return nil;
4342 }
4343
4344 [self setBackButtonTitle:title_];
4345
4346 BrowserView *browser = [[[BrowserView alloc] initWithBook:book_ database:database_] autorelease];
4347 [browser setDelegate:delegate_];
4348
4349 if (request != nil) {
4350 [browser loadRequest:[self _addHeadersToRequest:request]];
4351 [book_ pushPage:browser];
4352 }
4353
4354 return [browser webView];
4355}
4356
4357- (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame {
0235116c
JF
4358 if ([frame parentFrame] != nil)
4359 return;
4360
faf4eb4f
JF
4361 title_ = [title retain];
4362 [self setTitle:title];
4363}
e057ec05
JF
4364
4365- (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame {
4366 if ([frame parentFrame] != nil)
4367 return;
4368
7e649dc8 4369 reloading_ = false;
e057ec05
JF
4370 loading_ = true;
4371 [indicator_ startAnimation];
4372 [self reloadButtons];
4373
4374 if (title_ != nil) {
4375 [title_ release];
4376 title_ = nil;
686e302f 4377 }
e057ec05
JF
4378
4379 [self setTitle:@"Loading..."];
4380
4381 WebView *webview = [webview_ webView];
4382 NSString *href = [webview mainFrameURL];
4383 [urls_ addObject:[NSURL URLWithString:href]];
4384
853d14d3 4385 CGRect webrect = [scroller_ bounds];
e057ec05
JF
4386 webrect.size.height = 0;
4387 [webview_ setFrame:webrect];
a75f53e7
JF
4388}
4389
e057ec05 4390- (void) _finishLoading {
7e649dc8
JF
4391 if (!reloading_) {
4392 loading_ = false;
4393 [indicator_ stopAnimation];
4394 [self reloadButtons];
4395 }
e057ec05 4396}
686e302f 4397
853d14d3
JF
4398- (BOOL) webView:(WebView *)sender shouldScrollToPoint:(struct CGPoint)point forFrame:(WebFrame *)frame {
4399 _trace();
4400 return [webview_ webView:sender shouldScrollToPoint:point forFrame:frame];
4401}
4402
4403- (void) webView:(WebView *)sender didReceiveViewportArguments:(id)arguments forFrame:(WebFrame *)frame {
4404 return [webview_ webView:sender didReceiveViewportArguments:arguments forFrame:frame];
4405}
4406
4407- (void) webView:(WebView *)sender needsScrollNotifications:(id)notifications forFrame:(WebFrame *)frame {
4408 return [webview_ webView:sender needsScrollNotifications:notifications forFrame:frame];
4409}
4410
4411- (void) webView:(WebView *)sender didCommitLoadForFrame:(WebFrame *)frame {
4412 return [webview_ webView:sender didCommitLoadForFrame:frame];
4413}
4414
4415- (void) webView:(WebView *)sender didReceiveDocTypeForFrame:(WebFrame *)frame {
4416 return [webview_ webView:sender didReceiveDocTypeForFrame:frame];
4417}
4418
e057ec05 4419- (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
853d14d3
JF
4420 if ([frame parentFrame] == nil)
4421 [self _finishLoading];
4422 return [webview_ webView:sender didFinishLoadForFrame:frame];
e057ec05 4423}
686e302f 4424
e057ec05
JF
4425- (void) webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
4426 if ([frame parentFrame] != nil)
4427 return;
e057ec05 4428 [self _finishLoading];
faf4eb4f 4429
fa7bb92f 4430 [self loadURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@?%@",
faf4eb4f 4431 [[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"error" ofType:@"html"]] absoluteString],
fa7bb92f
JF
4432 [[error localizedDescription] stringByAddingPercentEscapes]
4433 ]]];
e057ec05
JF
4434}
4435
4436- (id) initWithBook:(RVBook *)book database:(Database *)database {
4437 if ((self = [super initWithBook:book]) != nil) {
4438 database_ = database;
4439 loading_ = false;
4440
4441 struct CGRect bounds = [self bounds];
4442
4443 UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:bounds] autorelease];
4444 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
4445 [self addSubview:pinstripe];
4446
4447 scroller_ = [[UIScroller alloc] initWithFrame:bounds];
4448 [self addSubview:scroller_];
4449
4450 [scroller_ setScrollingEnabled:YES];
4451 [scroller_ setAdjustForContentSizeChange:YES];
4452 [scroller_ setClipsSubviews:YES];
4453 [scroller_ setAllowsRubberBanding:YES];
4454 [scroller_ setScrollDecelerationFactor:0.99];
4455 [scroller_ setDelegate:self];
4456
4457 CGRect webrect = [scroller_ bounds];
4458 webrect.size.height = 0;
4459
4460 webview_ = [[UIWebView alloc] initWithFrame:webrect];
4461 [scroller_ addSubview:webview_];
4462
e057ec05 4463 [webview_ setTileSize:CGSizeMake(webrect.size.width, 500)];
853d14d3
JF
4464
4465 [webview_ setTilingEnabled:YES];
4466 [webview_ setTileMinificationFilter:kCAFilterNearest];
e057ec05 4467 [webview_ setAutoresizes:YES];
853d14d3
JF
4468
4469 [webview_ setViewportSize:CGSizeMake(980, -1) forDocumentTypes:0x10];
4470 [webview_ setViewportSize:CGSizeMake(320, -1) forDocumentTypes:0x2];
4471 [webview_ setViewportSize:CGSizeMake(320, -1) forDocumentTypes:0x8];
4472
4473 [webview_ _setDocumentType:0x4];
4474
4475 [webview_ setZoomsFocusedFormControl:YES];
4476 [webview_ setContentsPosition:7];
4477 [webview_ setEnabledGestures:0xa];
4478 [webview_ setValue:[NSNumber numberWithBool:YES] forGestureAttribute:0x4];
4479 [webview_ setValue:[NSNumber numberWithBool:YES] forGestureAttribute:0x7];
e057ec05 4480 [webview_ setDelegate:self];
853d14d3
JF
4481 [webview_ setGestureDelegate:self];
4482 [webview_ setSmoothsFonts:YES];
686e302f 4483
81ab76dc 4484 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:kUIProgressIndicatorStyleMediumWhite];
9e07091a 4485 indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(281, 42, indsize.width, indsize.height)];
81ab76dc 4486 [indicator_ setStyle:kUIProgressIndicatorStyleMediumWhite];
e057ec05
JF
4487
4488 Package *package([database_ packageWithName:@"cydia"]);
4489 NSString *application = package == nil ? @"Cydia" : [NSString
4490 stringWithFormat:@"Cydia/%@",
4491 [package installed]
4492 ];
4493
4494 WebView *webview = [webview_ webView];
4495 [webview setApplicationNameForUserAgent:application];
4496 [webview setFrameLoadDelegate:self];
4497 [webview setResourceLoadDelegate:self];
4498 [webview setUIDelegate:self];
4499
853d14d3
JF
4500 //[webview _setLayoutInterval:0.5];
4501
e057ec05
JF
4502 urls_ = [[NSMutableArray alloc] initWithCapacity:16];
4503 } return self;
a75f53e7
JF
4504}
4505
853d14d3
JF
4506- (void) didFinishGesturesInView:(UIView *)view forEvent:(id)event {
4507 [webview_ redrawScaledDocument];
4508}
4509
e057ec05 4510- (void) _rightButtonClicked {
7e649dc8 4511 reloading_ = true;
e057ec05
JF
4512 [self reloadURL];
4513}
4514
ad554f10
JF
4515- (NSString *) _rightButtonTitle {
4516 return @"Reload";
4517}
4518
e057ec05 4519- (NSString *) rightButtonTitle {
ad554f10 4520 return loading_ ? @"" : [self _rightButtonTitle];
e057ec05
JF
4521}
4522
4523- (NSString *) title {
4524 return nil;
4525}
4526
4527- (NSString *) backButtonTitle {
4528 return @"Browser";
a75f53e7
JF
4529}
4530
e057ec05
JF
4531- (void) setPageActive:(BOOL)active {
4532 if (active)
4533 [book_ addSubview:indicator_];
4534 else
4535 [indicator_ removeFromSuperview];
a75f53e7
JF
4536}
4537
e057ec05 4538- (void) resetViewAnimated:(BOOL)animated {
686e302f 4539}
4941f41d 4540
48c0461e
JF
4541- (void) setPushed:(bool)pushed {
4542 pushed_ = pushed;
4543}
4544
faf4eb4f
JF
4545@end
4546/* }}} */
30d83bfe 4547
faf4eb4f
JF
4548@interface CYBook : RVBook <
4549 ProgressDelegate
4550> {
4551 _transient Database *database_;
4552 UIView *overlay_;
4553 UIProgressIndicator *indicator_;
4554 UITextLabel *prompt_;
4555 UIProgressBar *progress_;
4556 bool updating_;
30d83bfe
JF
4557}
4558
faf4eb4f
JF
4559- (id) initWithFrame:(CGRect)frame database:(Database *)database;
4560- (void) update;
4561- (BOOL) updating;
30d83bfe
JF
4562
4563@end
30d83bfe 4564
686e302f 4565/* Install View {{{ */
e057ec05
JF
4566@interface InstallView : RVPage {
4567 _transient Database *database_;
e057ec05 4568 NSMutableArray *sections_;
fa7bb92f
JF
4569 NSMutableArray *filtered_;
4570 UITransitionView *transition_;
e057ec05 4571 UITable *list_;
9e07091a 4572 UIView *accessory_;
fa7bb92f 4573 BOOL editing_;
686e302f 4574}
a75f53e7 4575
e057ec05
JF
4576- (id) initWithBook:(RVBook *)book database:(Database *)database;
4577- (void) reloadData;
fa7bb92f 4578- (void) resetView;
a75f53e7 4579
4941f41d
JF
4580@end
4581
686e302f 4582@implementation InstallView
a75f53e7 4583
4941f41d 4584- (void) dealloc {
e057ec05
JF
4585 [list_ setDataSource:nil];
4586 [list_ setDelegate:nil];
4587
e057ec05 4588 [sections_ release];
fa7bb92f
JF
4589 [filtered_ release];
4590 [transition_ release];
e057ec05 4591 [list_ release];
9e07091a 4592 [accessory_ release];
4941f41d
JF
4593 [super dealloc];
4594}
4595
686e302f 4596- (int) numberOfRowsInTable:(UITable *)table {
fa7bb92f 4597 return editing_ ? [sections_ count] : [filtered_ count] + 1;
686e302f 4598}
20dd7407 4599
686e302f
JF
4600- (float) table:(UITable *)table heightForRow:(int)row {
4601 return 45;
4602}
20dd7407 4603
686e302f
JF
4604- (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
4605 if (reusing == nil)
4606 reusing = [[[SectionCell alloc] init] autorelease];
fa7bb92f
JF
4607 [(SectionCell *)reusing setSection:(editing_ ?
4608 [sections_ objectAtIndex:row] :
4609 (row == 0 ? nil : [filtered_ objectAtIndex:(row - 1)])
4610 ) editing:editing_];
686e302f
JF
4611 return reusing;
4612}
a75f53e7 4613
686e302f 4614- (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
fa7bb92f
JF
4615 return !editing_;
4616}
4617
4618- (BOOL) table:(UITable *)table canSelectRow:(int)row {
4619 return !editing_;
686e302f 4620}
a75f53e7 4621
686e302f
JF
4622- (void) tableRowSelected:(NSNotification *)notification {
4623 int row = [[notification object] selectedRow];
e057ec05
JF
4624 if (row == INT_MAX)
4625 return;
a75f53e7 4626
e057ec05 4627 Section *section;
965edd52 4628 NSString *name;
e057ec05 4629 NSString *title;
a75f53e7 4630
e057ec05
JF
4631 if (row == 0) {
4632 section = nil;
965edd52 4633 name = nil;
e057ec05 4634 title = @"All Packages";
686e302f 4635 } else {
fa7bb92f 4636 section = [filtered_ objectAtIndex:(row - 1)];
965edd52
JF
4637 name = [section name];
4638
4639 if (name != nil)
4640 title = name;
4641 else {
4642 name = @"";
4643 title = @"(No Section)";
4644 }
686e302f 4645 }
4941f41d 4646
e057ec05
JF
4647 PackageTable *table = [[[PackageTable alloc]
4648 initWithBook:book_
4649 database:database_
4650 title:title
faf4eb4f 4651 filter:@selector(isVisiblyUninstalledInSection:)
965edd52 4652 with:name
e057ec05 4653 ] autorelease];
4941f41d 4654
e057ec05 4655 [table setDelegate:delegate_];
4941f41d 4656
e057ec05 4657 [book_ pushPage:table];
686e302f 4658}
4941f41d 4659
e057ec05
JF
4660- (id) initWithBook:(RVBook *)book database:(Database *)database {
4661 if ((self = [super initWithBook:book]) != nil) {
4662 database_ = database;
4663
e057ec05 4664 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
fa7bb92f 4665 filtered_ = [[NSMutableArray arrayWithCapacity:16] retain];
4941f41d 4666
fa7bb92f
JF
4667 transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
4668 [self addSubview:transition_];
4669
4670 list_ = [[UITable alloc] initWithFrame:[transition_ bounds]];
4671 [transition_ transition:0 toView:list_];
a75f53e7 4672
686e302f
JF
4673 UITableColumn *column = [[[UITableColumn alloc]
4674 initWithTitle:@"Name"
4675 identifier:@"name"
e057ec05 4676 width:[self frame].size.width
686e302f 4677 ] autorelease];
a75f53e7 4678
686e302f
JF
4679 [list_ setDataSource:self];
4680 [list_ setSeparatorStyle:1];
4681 [list_ addTableColumn:column];
4682 [list_ setDelegate:self];
4683 [list_ setReusesTableCells:YES];
4941f41d 4684
e057ec05 4685 [self reloadData];
686e302f 4686 } return self;
4941f41d
JF
4687}
4688
e057ec05
JF
4689- (void) reloadData {
4690 NSArray *packages = [database_ packages];
4691
e057ec05 4692 [sections_ removeAllObjects];
fa7bb92f
JF
4693 [filtered_ removeAllObjects];
4694
4695 NSMutableArray *filtered = [NSMutableArray arrayWithCapacity:[packages count]];
4696 NSMutableDictionary *sections = [NSMutableDictionary dictionaryWithCapacity:32];
a75f53e7 4697
686e302f
JF
4698 for (size_t i(0); i != [packages count]; ++i) {
4699 Package *package([packages objectAtIndex:i]);
fa7bb92f
JF
4700 NSString *name([package section]);
4701
4702 if (name != nil) {
4703 Section *section([sections objectForKey:name]);
4704 if (section == nil) {
4705 section = [[[Section alloc] initWithName:name] autorelease];
4706 [sections setObject:section forKey:name];
4707 }
4708 }
4709
4710 if ([package valid] && [package installed] == nil && [package visible])
4711 [filtered addObject:package];
686e302f 4712 }
a75f53e7 4713
fa7bb92f
JF
4714 [sections_ addObjectsFromArray:[sections allValues]];
4715 [sections_ sortUsingSelector:@selector(compareByName:)];
4716
4717 [filtered sortUsingSelector:@selector(compareBySection:)];
a75f53e7 4718
686e302f 4719 Section *section = nil;
fa7bb92f
JF
4720 for (size_t offset = 0, count = [filtered count]; offset != count; ++offset) {
4721 Package *package = [filtered objectAtIndex:offset];
686e302f 4722 NSString *name = [package section];
4941f41d 4723
e057ec05 4724 if (section == nil || name != nil && ![[section name] isEqualToString:name]) {
fa7bb92f
JF
4725 section = name == nil ?
4726 [[[Section alloc] initWithName:nil] autorelease] :
4727 [sections objectForKey:name];
4728 [filtered_ addObject:section];
686e302f 4729 }
a75f53e7 4730
e057ec05 4731 [section addToCount];
686e302f 4732 }
4941f41d 4733
686e302f 4734 [list_ reloadData];
e057ec05 4735}
4941f41d 4736
fa7bb92f
JF
4737- (void) resetView {
4738 if (editing_)
4739 [self _rightButtonClicked];
4740}
4741
e057ec05
JF
4742- (void) resetViewAnimated:(BOOL)animated {
4743 [list_ resetViewAnimated:animated];
4744}
4941f41d 4745
fa7bb92f
JF
4746- (void) _rightButtonClicked {
4747 if ((editing_ = !editing_))
4748 [list_ reloadData];
4749 else {
4750 [delegate_ updateData];
4751 }
4752
4753 [book_ setTitle:[self title] forPage:self];
4754 [book_ reloadButtonsForPage:self];
4755}
4756
e057ec05 4757- (NSString *) title {
fa7bb92f 4758 return editing_ ? @"Section Visibility" : @"Install by Section";
4941f41d
JF
4759}
4760
e057ec05
JF
4761- (NSString *) backButtonTitle {
4762 return @"Sections";
a75f53e7
JF
4763}
4764
fa7bb92f
JF
4765- (NSString *) rightButtonTitle {
4766 return [sections_ count] == 0 ? nil : editing_ ? @"Done" : @"Edit";
4767}
4768
9e07091a
JF
4769- (UIView *) accessoryView {
4770 return accessory_;
4771}
4772
a75f53e7 4773@end
4941f41d 4774/* }}} */
686e302f 4775/* Changes View {{{ */
e057ec05
JF
4776@interface ChangesView : RVPage {
4777 _transient Database *database_;
a75f53e7
JF
4778 NSMutableArray *packages_;
4779 NSMutableArray *sections_;
e057ec05
JF
4780 UISectionList *list_;
4781 unsigned upgrades_;
a75f53e7
JF
4782}
4783
e057ec05
JF
4784- (id) initWithBook:(RVBook *)book database:(Database *)database;
4785- (void) reloadData;
a75f53e7 4786
a75f53e7
JF
4787@end
4788
686e302f
JF
4789@implementation ChangesView
4790
4791- (void) dealloc {
e057ec05
JF
4792 [[list_ table] setDelegate:nil];
4793 [list_ setDataSource:nil];
4794
686e302f
JF
4795 [packages_ release];
4796 [sections_ release];
e057ec05 4797 [list_ release];
686e302f
JF
4798 [super dealloc];
4799}
a75f53e7
JF
4800
4801- (int) numberOfSectionsInSectionList:(UISectionList *)list {
4802 return [sections_ count];
4803}
4804
4805- (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section {
4806 return [[sections_ objectAtIndex:section] name];
4807}
4808
4809- (int) sectionList:(UISectionList *)list rowForSection:(int)section {
4810 return [[sections_ objectAtIndex:section] row];
4811}
4812
4813- (int) numberOfRowsInTable:(UITable *)table {
4814 return [packages_ count];
4815}
4816
4817- (float) table:(UITable *)table heightForRow:(int)row {
3319715b 4818 return [PackageCell heightForPackage:[packages_ objectAtIndex:row]];
a75f53e7
JF
4819}
4820
3325a005
JF
4821- (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
4822 if (reusing == nil)
e057ec05 4823 reusing = [[[PackageCell alloc] init] autorelease];
3325a005
JF
4824 [(PackageCell *)reusing setPackage:[packages_ objectAtIndex:row]];
4825 return reusing;
a75f53e7
JF
4826}
4827
4828- (BOOL) table:(UITable *)table showDisclosureForRow:(int)row {
686e302f 4829 return NO;
a75f53e7
JF
4830}
4831
686e302f
JF
4832- (void) tableRowSelected:(NSNotification *)notification {
4833 int row = [[notification object] selectedRow];
e057ec05
JF
4834 if (row == INT_MAX)
4835 return;
4836 Package *package = [packages_ objectAtIndex:row];
4837 PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
4838 [view setDelegate:delegate_];
4839 [view setPackage:package];
4840 [book_ pushPage:view];
a75f53e7
JF
4841}
4842
b7eb9e84
JF
4843- (void) _leftButtonClicked {
4844 [(CYBook *)book_ update];
4845 [self reloadButtons];
4846}
4847
e057ec05
JF
4848- (void) _rightButtonClicked {
4849 [delegate_ distUpgrade];
a75f53e7
JF
4850}
4851
e057ec05
JF
4852- (id) initWithBook:(RVBook *)book database:(Database *)database {
4853 if ((self = [super initWithBook:book]) != nil) {
4854 database_ = database;
a75f53e7 4855
686e302f
JF
4856 packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
4857 sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
a75f53e7 4858
e057ec05
JF
4859 list_ = [[UISectionList alloc] initWithFrame:[self bounds] showSectionIndex:NO];
4860 [self addSubview:list_];
4861
2d28b35a 4862 [list_ setShouldHideHeaderInShortLists:NO];
686e302f
JF
4863 [list_ setDataSource:self];
4864 //[list_ setSectionListStyle:1];
a75f53e7 4865
686e302f 4866 UITableColumn *column = [[[UITableColumn alloc]
a75f53e7
JF
4867 initWithTitle:@"Name"
4868 identifier:@"name"
e057ec05 4869 width:[self frame].size.width
686e302f 4870 ] autorelease];
a75f53e7
JF
4871
4872 UITable *table = [list_ table];
4873 [table setSeparatorStyle:1];
4874 [table addTableColumn:column];
4875 [table setDelegate:self];
3325a005 4876 [table setReusesTableCells:YES];
a75f53e7 4877
e057ec05 4878 [self reloadData];
a75f53e7
JF
4879 } return self;
4880}
4881
e057ec05
JF
4882- (void) reloadData {
4883 NSArray *packages = [database_ packages];
4884
686e302f 4885 [packages_ removeAllObjects];
e057ec05
JF
4886 [sections_ removeAllObjects];
4887
686e302f
JF
4888 for (size_t i(0); i != [packages count]; ++i) {
4889 Package *package([packages objectAtIndex:i]);
fa7bb92f
JF
4890
4891 if (
4892 [package installed] == nil && [package valid] && [package visible] ||
4893 [package upgradableAndEssential:NO]
4894 )
686e302f
JF
4895 [packages_ addObject:package];
4896 }
4941f41d 4897
686e302f 4898 [packages_ sortUsingSelector:@selector(compareForChanges:)];
a75f53e7 4899
fa7bb92f 4900 Section *upgradable = [[[Section alloc] initWithName:@"Available Upgrades"] autorelease];
a75f53e7 4901 Section *section = nil;
686e302f 4902
e057ec05
JF
4903 upgrades_ = 0;
4904 bool unseens = false;
4905
b27f0a94 4906 CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, Locale_, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
e057ec05 4907
a75f53e7
JF
4908 for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) {
4909 Package *package = [packages_ objectAtIndex:offset];
a75f53e7 4910
238b07ce 4911 if ([package upgradableAndEssential:YES]) {
e057ec05
JF
4912 ++upgrades_;
4913 [upgradable addToCount];
4914 } else {
4915 unseens = true;
686e302f 4916 NSDate *seen = [package seen];
a75f53e7 4917
138ae18d 4918 NSString *name;
138ae18d
JF
4919
4920 if (seen == nil)
e057ec05 4921 name = [@"n/a ?" retain];
138ae18d 4922 else {
e057ec05 4923 name = (NSString *) CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen);
138ae18d 4924 }
686e302f 4925
e057ec05 4926 if (section == nil || ![[section name] isEqualToString:name]) {
686e302f
JF
4927 section = [[[Section alloc] initWithName:name row:offset] autorelease];
4928 [sections_ addObject:section];
4929 }
4930
e057ec05
JF
4931 [name release];
4932 [section addToCount];
686e302f 4933 }
a75f53e7
JF
4934 }
4935
e057ec05 4936 CFRelease(formatter);
686e302f 4937
e057ec05
JF
4938 if (unseens) {
4939 Section *last = [sections_ lastObject];
4940 size_t count = [last count];
4941 [packages_ removeObjectsInRange:NSMakeRange([packages_ count] - count, count)];
4942 [sections_ removeLastObject];
4943 }
a75f53e7 4944
e057ec05
JF
4945 if (upgrades_ != 0)
4946 [sections_ insertObject:upgradable atIndex:0];
d12c6e70 4947
e057ec05
JF
4948 [list_ reloadData];
4949 [self reloadButtons];
2d28b35a
JF
4950}
4951
e057ec05
JF
4952- (void) resetViewAnimated:(BOOL)animated {
4953 [list_ resetViewAnimated:animated];
2d28b35a
JF
4954}
4955
b7eb9e84
JF
4956- (NSString *) leftButtonTitle {
4957 return [(CYBook *)book_ updating] ? nil : @"Refresh";
4958}
4959
e057ec05 4960- (NSString *) rightButtonTitle {
5e563e79 4961 return upgrades_ == 0 ? nil : [NSString stringWithFormat:@"Upgrade (%u)", upgrades_];
2d28b35a
JF
4962}
4963
e057ec05
JF
4964- (NSString *) title {
4965 return @"Changes";
b6ffa083
JF
4966}
4967
2d28b35a
JF
4968@end
4969/* }}} */
e057ec05
JF
4970/* Search View {{{ */
4971@protocol SearchViewDelegate
4972- (void) showKeyboard:(BOOL)show;
4973@end
686e302f 4974
8993ad57 4975@interface SearchView : RVPage {
e057ec05
JF
4976 UIView *accessory_;
4977 UISearchField *field_;
8993ad57
JF
4978 UITransitionView *transition_;
4979 PackageTable *table_;
4980 UIPreferencesTable *advanced_;
e25e221f 4981 UIView *dimmed_;
8993ad57 4982 bool flipped_;
59efd93a 4983 bool reload_;
e057ec05 4984}
686e302f 4985
e057ec05
JF
4986- (id) initWithBook:(RVBook *)book database:(Database *)database;
4987- (void) reloadData;
686e302f 4988
2d28b35a
JF
4989@end
4990
e057ec05 4991@implementation SearchView
2d28b35a 4992
686e302f 4993- (void) dealloc {
e057ec05
JF
4994#ifndef __OBJC2__
4995 [[field_ textTraits] setEditingDelegate:nil];
4996#endif
4997 [field_ setDelegate:nil];
2d28b35a 4998
e057ec05
JF
4999 [accessory_ release];
5000 [field_ release];
8993ad57
JF
5001 [transition_ release];
5002 [table_ release];
5003 [advanced_ release];
e25e221f 5004 [dimmed_ release];
e057ec05 5005 [super dealloc];
686e302f
JF
5006}
5007
59efd93a
JF
5008- (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
5009 return 1;
5010}
5011
5012- (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
5013 switch (group) {
5014 case 0: return @"Advanced Search (Coming Soon!)";
5015
5016 default: _assert(false);
5017 }
5018}
5019
5020- (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
5021 switch (group) {
5022 case 0: return 0;
5023
5024 default: _assert(false);
5025 }
5026}
5027
2a987aa5
JF
5028- (void) _showKeyboard:(BOOL)show {
5029 CGSize keysize = [UIKeyboard defaultSize];
5030 CGRect keydown = [book_ pageBounds];
5031 CGRect keyup = keydown;
5032 keyup.size.height -= keysize.height - ButtonBarHeight_;
5033
5034 float delay = KeyboardTime_ * ButtonBarHeight_ / keysize.height;
5035
5036 UIFrameAnimation *animation = [[[UIFrameAnimation alloc] initWithTarget:[table_ list]] autorelease];
5037 [animation setSignificantRectFields:8];
5038
5039 if (show) {
5040 [animation setStartFrame:keydown];
5041 [animation setEndFrame:keyup];
5042 } else {
5043 [animation setStartFrame:keyup];
5044 [animation setEndFrame:keydown];
5045 }
5046
5047 UIAnimator *animator = [UIAnimator sharedAnimator];
5048
5049 [animator
5050 addAnimations:[NSArray arrayWithObjects:animation, nil]
5051 withDuration:(KeyboardTime_ - delay)
5052 start:!show
5053 ];
5054
5055 if (show)
5056 [animator performSelector:@selector(startAnimation:) withObject:animation afterDelay:delay];
5057
23bcd525 5058#ifndef __OBJC2__
2a987aa5 5059 [delegate_ showKeyboard:show];
23bcd525 5060#endif
2a987aa5
JF
5061}
5062
e057ec05 5063- (void) textFieldDidBecomeFirstResponder:(UITextField *)field {
2a987aa5 5064 [self _showKeyboard:YES];
e057ec05 5065}
686e302f 5066
e057ec05 5067- (void) textFieldDidResignFirstResponder:(UITextField *)field {
2a987aa5 5068 [self _showKeyboard:NO];
e057ec05 5069}
686e302f 5070
e057ec05 5071- (void) keyboardInputChanged:(UIFieldEditor *)editor {
59efd93a
JF
5072 if (reload_) {
5073 NSString *text([field_ text]);
5074 [field_ setClearButtonStyle:(text == nil || [text length] == 0 ? 0 : 2)];
5075 [self reloadData];
5076 reload_ = false;
5077 }
5078}
5079
5080- (void) textFieldClearButtonPressed:(UITextField *)field {
5081 reload_ = true;
5082}
5083
5084- (void) keyboardInputShouldDelete:(id)input {
5085 reload_ = true;
e057ec05 5086}
686e302f 5087
e057ec05 5088- (BOOL) keyboardInput:(id)input shouldInsertText:(NSString *)text isMarkedText:(int)marked {
59efd93a
JF
5089 if ([text length] != 1 || [text characterAtIndex:0] != '\n') {
5090 reload_ = true;
e057ec05 5091 return YES;
59efd93a
JF
5092 } else {
5093 [field_ resignFirstResponder];
5094 return NO;
5095 }
686e302f
JF
5096}
5097
e057ec05 5098- (id) initWithBook:(RVBook *)book database:(Database *)database {
8993ad57
JF
5099 if ((self = [super initWithBook:book]) != nil) {
5100 CGRect pageBounds = [book_ pageBounds];
5101
ecabc2b3 5102 /*UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:pageBounds] autorelease];
8993ad57 5103 [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
ecabc2b3 5104 [self addSubview:pinstripe];*/
8993ad57 5105
8993ad57
JF
5106 transition_ = [[UITransitionView alloc] initWithFrame:pageBounds];
5107 [self addSubview:transition_];
5108
5109 advanced_ = [[UIPreferencesTable alloc] initWithFrame:pageBounds];
5110
59efd93a
JF
5111 [advanced_ setReusesTableCells:YES];
5112 [advanced_ setDataSource:self];
5113 [advanced_ reloadData];
5114
e25e221f
JF
5115 dimmed_ = [[UIView alloc] initWithFrame:pageBounds];
5116 CGColor dimmed(space_, 0, 0, 0, 0.5);
d210b85d 5117 [dimmed_ setBackgroundColor:[UIColor colorWithCGColor:dimmed]];
e25e221f 5118
8993ad57
JF
5119 table_ = [[PackageTable alloc]
5120 initWithBook:book
5121 database:database
5122 title:nil
853d14d3 5123 filter:@selector(isUnfilteredAndSearchedForBy:)
8993ad57
JF
5124 with:nil
5125 ];
5126
59efd93a 5127 [table_ setShouldHideHeaderInShortLists:NO];
8993ad57
JF
5128 [transition_ transition:0 toView:table_];
5129
23bcd525
JF
5130 CGRect cnfrect = {{
5131#ifdef __OBJC2__
5132 6 +
5133#endif
5134 1, 38}, {17, 18}};
686e302f 5135
e057ec05 5136 CGRect area;
fa7bb92f 5137 area.origin.x = /*cnfrect.origin.x + cnfrect.size.width + 4 +*/ 10;
e057ec05 5138 area.origin.y = 30;
23bcd525
JF
5139
5140 area.size.width =
5141#ifdef __OBJC2__
5142 8 +
5143#endif
5144 [self bounds].size.width - area.origin.x - 18;
5145
e057ec05 5146 area.size.height = [UISearchField defaultHeight];
2d28b35a 5147
e057ec05 5148 field_ = [[UISearchField alloc] initWithFrame:area];
686e302f 5149
d210b85d 5150 UIFont *font = [UIFont systemFontOfSize:16];
e057ec05 5151 [field_ setFont:font];
686e302f 5152
e057ec05 5153 [field_ setPlaceholder:@"Package Names & Descriptions"];
e057ec05 5154 [field_ setDelegate:self];
686e302f 5155
23bcd525 5156 [field_ setPaddingTop:3];
23bcd525 5157
d210b85d
JF
5158 UITextInputTraits *traits = [field_ textInputTraits];
5159 [traits setAutocapitalizationType:0];
5160 [traits setAutocorrectionType:1];
fa7bb92f
JF
5161 [traits setReturnKeyType:6];
5162
23bcd525
JF
5163 CGRect accrect = {{0, 6}, {6 + cnfrect.size.width + 6 + area.size.width + 6, area.size.height + 30}};
5164
5165 accessory_ = [[UIView alloc] initWithFrame:accrect];
81ab76dc
JF
5166 [accessory_ addSubview:field_];
5167
fa7bb92f 5168 /*UIPushButton *configure = [[[UIPushButton alloc] initWithFrame:cnfrect] autorelease];
e057ec05 5169 [configure setShowPressFeedback:YES];
97959670 5170 [configure setImage:[UIImage applicationImageNamed:@"advanced.png"]];
e057ec05 5171 [configure addTarget:self action:@selector(configurePushed) forEvents:1];
fa7bb92f 5172 [accessory_ addSubview:configure];*/
e057ec05 5173 } return self;
2d28b35a
JF
5174}
5175
8993ad57 5176- (void) flipPage {
b27f0a94 5177#ifndef __OBJC2__
8993ad57
JF
5178 LKAnimation *animation = [LKTransition animation];
5179 [animation setType:@"oglFlip"];
5180 [animation setTimingFunction:[LKTimingFunction functionWithName:@"easeInEaseOut"]];
5181 [animation setFillMode:@"extended"];
5182 [animation setTransitionFlags:3];
5183 [animation setDuration:10];
5184 [animation setSpeed:0.35];
ecabc2b3
JF
5185 [animation setSubtype:(flipped_ ? @"fromLeft" : @"fromRight")];
5186 [[transition_ _layer] addAnimation:animation forKey:0];
8993ad57
JF
5187 [transition_ transition:0 toView:(flipped_ ? (UIView *) table_ : (UIView *) advanced_)];
5188 flipped_ = !flipped_;
b27f0a94 5189#endif
8993ad57
JF
5190}
5191
e057ec05 5192- (void) configurePushed {
8993ad57
JF
5193 [field_ resignFirstResponder];
5194 [self flipPage];
5195}
5196
5197- (void) resetViewAnimated:(BOOL)animated {
5198 if (flipped_)
5199 [self flipPage];
5200 [table_ resetViewAnimated:animated];
b6ffa083
JF
5201}
5202
e057ec05 5203- (void) reloadData {
8993ad57
JF
5204 if (flipped_)
5205 [self flipPage];
5206 [table_ setObject:[field_ text]];
5207 [table_ reloadData];
5208 [table_ resetCursor];
2d28b35a
JF
5209}
5210
e057ec05
JF
5211- (UIView *) accessoryView {
5212 return accessory_;
5213}
686e302f 5214
8993ad57
JF
5215- (NSString *) title {
5216 return nil;
5217}
5218
e057ec05
JF
5219- (NSString *) backButtonTitle {
5220 return @"Search";
5221}
e38b51c5 5222
74bfe814
JF
5223- (void) setDelegate:(id)delegate {
5224 [table_ setDelegate:delegate];
5225 [super setDelegate:delegate];
5226}
5227
2d28b35a 5228@end
e057ec05 5229/* }}} */
2d28b35a 5230
e057ec05 5231@implementation CYBook
686e302f 5232
e057ec05
JF
5233- (void) dealloc {
5234 [overlay_ release];
5235 [indicator_ release];
5236 [prompt_ release];
5237 [progress_ release];
5238 [super dealloc];
5239}
686e302f 5240
77f175ac
JF
5241- (NSString *) getTitleForPage:(RVPage *)page {
5242 return Simplify([super getTitleForPage:page]);
5243}
5244
b7eb9e84
JF
5245- (BOOL) updating {
5246 return updating_;
5247}
5248
e057ec05 5249- (void) update {
b7eb9e84 5250 [navbar_ setPrompt:@""];
e057ec05
JF
5251 [navbar_ addSubview:overlay_];
5252 [indicator_ startAnimation];
5253 [prompt_ setText:@"Updating Database..."];
5254 [progress_ setProgress:0];
686e302f 5255
b7eb9e84
JF
5256 updating_ = true;
5257
e057ec05
JF
5258 [NSThread
5259 detachNewThreadSelector:@selector(_update)
5260 toTarget:self
5261 withObject:nil
5262 ];
2d28b35a
JF
5263}
5264
e057ec05 5265- (void) _update_ {
b7eb9e84
JF
5266 updating_ = false;
5267
e057ec05
JF
5268 [overlay_ removeFromSuperview];
5269 [indicator_ stopAnimation];
5270 [delegate_ reloadData];
686e302f 5271
e057ec05 5272 [self setPrompt:[NSString stringWithFormat:@"Last Updated: %@", GetLastUpdate()]];
2d28b35a
JF
5273}
5274
e057ec05
JF
5275- (id) initWithFrame:(CGRect)frame database:(Database *)database {
5276 if ((self = [super initWithFrame:frame]) != nil) {
5277 database_ = database;
2d28b35a 5278
e057ec05 5279 CGRect ovrrect = [navbar_ bounds];
23bcd525 5280 ovrrect.size.height = ([UINavigationBar defaultSizeWithPrompt].height - [UINavigationBar defaultSize].height);
2d28b35a 5281
e057ec05 5282 overlay_ = [[UIView alloc] initWithFrame:ovrrect];
686e302f 5283
1eb0c554
JF
5284 bool ugly = [navbar_ _barStyle:NO] == 0;
5285
5286 UIProgressIndicatorStyle style = ugly ?
5287 kUIProgressIndicatorStyleSmallBlack :
5288 kUIProgressIndicatorStyleSmallWhite;
81ab76dc
JF
5289
5290 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:style];
e057ec05
JF
5291 unsigned indoffset = (ovrrect.size.height - indsize.height) / 2;
5292 CGRect indrect = {{indoffset, indoffset}, indsize};
b6ffa083 5293
e057ec05 5294 indicator_ = [[UIProgressIndicator alloc] initWithFrame:indrect];
81ab76dc 5295 [indicator_ setStyle:style];
e057ec05 5296 [overlay_ addSubview:indicator_];
686e302f 5297
23bcd525 5298 CGSize prmsize = {200, indsize.width + 4};
686e302f 5299
e057ec05
JF
5300 CGRect prmrect = {{
5301 indoffset * 2 + indsize.width,
23bcd525
JF
5302#ifdef __OBJC2__
5303 -1 +
5304#endif
e057ec05
JF
5305 (ovrrect.size.height - prmsize.height) / 2
5306 }, prmsize};
686e302f 5307
d210b85d 5308 UIFont *font = [UIFont systemFontOfSize:12];
686e302f 5309
e057ec05 5310 prompt_ = [[UITextLabel alloc] initWithFrame:prmrect];
686e302f 5311
d210b85d
JF
5312 [prompt_ setColor:[UIColor colorWithCGColor:(ugly ? Blueish_ : White_)]];
5313 [prompt_ setBackgroundColor:[UIColor colorWithCGColor:Clear_]];
e057ec05 5314 [prompt_ setFont:font];
686e302f 5315
e057ec05 5316 [overlay_ addSubview:prompt_];
686e302f 5317
e057ec05 5318 CGSize prgsize = {75, 100};
686e302f 5319
e057ec05
JF
5320 CGRect prgrect = {{
5321 ovrrect.size.width - prgsize.width - 10,
5322 (ovrrect.size.height - prgsize.height) / 2
5323 } , prgsize};
5324
5325 progress_ = [[UIProgressBar alloc] initWithFrame:prgrect];
5326 [progress_ setStyle:0];
5327 [overlay_ addSubview:progress_];
686e302f 5328 } return self;
2d28b35a
JF
5329}
5330
e057ec05
JF
5331- (void) _update {
5332 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
a75f53e7 5333
e057ec05
JF
5334 Status status;
5335 status.setDelegate(self);
686e302f 5336
e057ec05 5337 [database_ updateWithStatus:status];
2d28b35a 5338
e057ec05
JF
5339 [self
5340 performSelectorOnMainThread:@selector(_update_)
5341 withObject:nil
5342 waitUntilDone:NO
5343 ];
686e302f 5344
e057ec05 5345 [pool release];
a75f53e7
JF
5346}
5347
238b07ce
JF
5348- (void) setProgressError:(NSString *)error forPackage:(NSString *)id {
5349 [prompt_ setText:[NSString stringWithFormat:@"Error: %@", error]];
a75f53e7
JF
5350}
5351
e057ec05
JF
5352- (void) setProgressTitle:(NSString *)title {
5353 [self
5354 performSelectorOnMainThread:@selector(_setProgressTitle:)
5355 withObject:title
5356 waitUntilDone:YES
5357 ];
2d28b35a
JF
5358}
5359
e057ec05
JF
5360- (void) setProgressPercent:(float)percent {
5361}
686e302f 5362
e057ec05
JF
5363- (void) addProgressOutput:(NSString *)output {
5364 [self
5365 performSelectorOnMainThread:@selector(_addProgressOutput:)
5366 withObject:output
5367 waitUntilDone:YES
5368 ];
5369}
686e302f 5370
d210b85d 5371- (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
e057ec05
JF
5372 [sheet dismiss];
5373}
5374
e057ec05
JF
5375- (void) _setProgressTitle:(NSString *)title {
5376 [prompt_ setText:[title stringByAppendingString:@"..."]];
5377}
686e302f 5378
e057ec05 5379- (void) _addProgressOutput:(NSString *)output {
b6ffa083
JF
5380}
5381
2d28b35a 5382@end
2d28b35a 5383
4941f41d 5384@interface Cydia : UIApplication <
2d28b35a 5385 ConfirmationViewDelegate,
686e302f 5386 ProgressViewDelegate,
b0d03ade
JF
5387 SearchViewDelegate,
5388 CydiaDelegate
4941f41d 5389> {
a75f53e7 5390 UIWindow *window_;
e057ec05 5391
2d28b35a
JF
5392 UIView *underlay_;
5393 UIView *overlay_;
e057ec05 5394 CYBook *book_;
d210b85d 5395 UIToolbar *buttonbar_;
2d28b35a 5396
2d28b35a 5397 ConfirmationView *confirm_;
3319715b 5398
9e07091a 5399 NSMutableArray *essential_;
3319715b 5400 NSMutableArray *broken_;
a75f53e7
JF
5401
5402 Database *database_;
5403 ProgressView *progress_;
5404
7e986211 5405 unsigned tag_;
686e302f
JF
5406
5407 UIKeyboard *keyboard_;
b26eb97d 5408 UIProgressHUD *hud_;
e25e221f
JF
5409
5410 InstallView *install_;
5411 ChangesView *changes_;
5412 ManageView *manage_;
5413 SearchView *search_;
a75f53e7
JF
5414}
5415
a75f53e7
JF
5416@end
5417
5418@implementation Cydia
5419
3319715b
JF
5420- (void) _loaded {
5421 if ([broken_ count] != 0) {
5422 int count = [broken_ count];
5423
d210b85d 5424 UIActionSheet *sheet = [[[UIActionSheet alloc]
3319715b
JF
5425 initWithTitle:[NSString stringWithFormat:@"%d Half-Installed Package%@", count, (count == 1 ? @"" : @"s")]
5426 buttons:[NSArray arrayWithObjects:
5427 @"Forcibly Clear",
5428 @"Ignore (Temporary)",
5429 nil]
5430 defaultButtonIndex:0
5431 delegate:self
5432 context:@"fixhalf"
5433 ] autorelease];
5434
238b07ce 5435 [sheet setBodyText:@"When the shell scripts associated with packages fail, they are left in a bad state known as either half-configured or half-installed. These errors don't go away and instead continue to cause issues. These scripts can be deleted and the packages forcibly removed."];
3319715b
JF
5436 [sheet popupAlertAnimated:YES];
5437 } else if (!Ignored_ && [essential_ count] != 0) {
5438 int count = [essential_ count];
5439
d210b85d 5440 UIActionSheet *sheet = [[[UIActionSheet alloc]
3319715b
JF
5441 initWithTitle:[NSString stringWithFormat:@"%d Essential Upgrade%@", count, (count == 1 ? @"" : @"s")]
5442 buttons:[NSArray arrayWithObjects:@"Upgrade Essential", @"Ignore (Temporary)", nil]
5443 defaultButtonIndex:0
5444 delegate:self
5445 context:@"upgrade"
5446 ] autorelease];
5447
238b07ce 5448 [sheet setBodyText:@"One or more essential packages are currently out of date. If these upgrades are not performed you are likely to encounter errors."];
3319715b
JF
5449 [sheet popupAlertAnimated:YES];
5450 }
5451}
5452
e057ec05
JF
5453- (void) _reloadData {
5454 /*UIProgressHUD *hud = [[UIProgressHUD alloc] initWithWindow:window_];
5455 [hud setText:@"Reloading Data"];
5456 [overlay_ addSubview:hud];
5457 [hud show:YES];*/
a75f53e7 5458
a75f53e7 5459 [database_ reloadData];
d12c6e70 5460
e057ec05 5461 size_t changes(0);
3319715b 5462
9e07091a 5463 [essential_ removeAllObjects];
3319715b 5464 [broken_ removeAllObjects];
686e302f 5465
e057ec05
JF
5466 NSArray *packages = [database_ packages];
5467 for (int i(0), e([packages count]); i != e; ++i) {
5468 Package *package = [packages objectAtIndex:i];
3319715b
JF
5469 if ([package half])
5470 [broken_ addObject:package];
238b07ce 5471 if ([package upgradableAndEssential:NO]) {
9e07091a
JF
5472 if ([package essential])
5473 [essential_ addObject:package];
e057ec05 5474 ++changes;
9e07091a 5475 }
e057ec05 5476 }
686e302f 5477
e057ec05
JF
5478 if (changes != 0) {
5479 NSString *badge([[NSNumber numberWithInt:changes] stringValue]);
d12c6e70 5480 [buttonbar_ setBadgeValue:badge forButton:3];
63a1e4b8
JF
5481 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
5482 [buttonbar_ setBadgeAnimated:YES forButton:3];
d12c6e70
JF
5483 [self setApplicationBadge:badge];
5484 } else {
5485 [buttonbar_ setBadgeValue:nil forButton:3];
63a1e4b8
JF
5486 if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
5487 [buttonbar_ setBadgeAnimated:NO forButton:3];
d12c6e70
JF
5488 [self removeApplicationBadge];
5489 }
686e302f 5490
fa7bb92f
JF
5491 [self updateData];
5492
ad554f10
JF
5493 if ([packages count] == 0);
5494 else if (Loaded_)
fa7bb92f 5495 [self _loaded];
ad554f10 5496 else {
fa7bb92f
JF
5497 Loaded_ = YES;
5498 [book_ update];
ad554f10 5499 }
fa7bb92f
JF
5500
5501 /*[hud show:NO];
5502 [hud removeFromSuperview];*/
5503}
5504
faf4eb4f 5505- (void) _saveConfig {
3d37fc0d
JF
5506 if (Changed_) {
5507 _assert([Metadata_ writeToFile:@"/var/lib/cydia/metadata.plist" atomically:YES] == YES);
5508 Changed_ = false;
5509 }
faf4eb4f
JF
5510}
5511
5512- (void) updateData {
5513 [self _saveConfig];
e057ec05 5514
e25e221f
JF
5515 /* XXX: this is just stupid */
5516 if (tag_ != 2)
5517 [install_ reloadData];
5518 if (tag_ != 3)
5519 [changes_ reloadData];
e25e221f
JF
5520 if (tag_ != 5)
5521 [search_ reloadData];
5522
e057ec05 5523 [book_ reloadData];
686e302f
JF
5524}
5525
faf4eb4f
JF
5526- (void) update_ {
5527 [database_ update];
5528}
5529
5530- (void) syncData {
5531 FILE *file = fopen("/etc/apt/sources.list.d/cydia.list", "w");
5532 _assert(file != NULL);
5533
5534 NSArray *keys = [Sources_ allKeys];
5535
5536 for (int i(0), e([keys count]); i != e; ++i) {
5537 NSString *key = [keys objectAtIndex:i];
5538 NSDictionary *source = [Sources_ objectForKey:key];
5539
5540 fprintf(file, "%s %s %s\n",
5541 [[source objectForKey:@"Type"] UTF8String],
5542 [[source objectForKey:@"URI"] UTF8String],
5543 [[source objectForKey:@"Distribution"] UTF8String]
5544 );
5545 }
5546
5547 fclose(file);
5548
5549 [self _saveConfig];
5550
5551 [progress_
5552 detachNewThreadSelector:@selector(update_)
5553 toTarget:self
5554 withObject:nil
5555 title:@"Updating Sources..."
5556 ];
5557}
5558
e057ec05
JF
5559- (void) reloadData {
5560 @synchronized (self) {
5561 if (confirm_ == nil)
5562 [self _reloadData];
5563 }
686e302f
JF
5564}
5565
5566- (void) resolve {
5567 pkgProblemResolver *resolver = [database_ resolver];
5568
5569 resolver->InstallProtect();
5570 if (!resolver->Resolve(true))
5571 _error->Discard();
4941f41d
JF
5572}
5573
5574- (void) perform {
b6ffa083 5575 [database_ prepare];
242bcc6d
JF
5576
5577 if ([database_ cache]->BrokenCount() == 0)
5578 confirm_ = [[ConfirmationView alloc] initWithView:underlay_ database:database_ delegate:self];
5579 else {
5580 NSMutableArray *broken = [NSMutableArray arrayWithCapacity:16];
5581 NSArray *packages = [database_ packages];
5582
5583 for (size_t i(0); i != [packages count]; ++i) {
5584 Package *package = [packages objectAtIndex:i];
5585 if ([package broken])
5586 [broken addObject:[package name]];
5587 }
5588
d210b85d 5589 UIActionSheet *sheet = [[[UIActionSheet alloc]
242bcc6d
JF
5590 initWithTitle:[NSString stringWithFormat:@"%d Broken Packages", [database_ cache]->BrokenCount()]
5591 buttons:[NSArray arrayWithObjects:@"Okay", nil]
5592 defaultButtonIndex:0
5593 delegate:self
9e07091a 5594 context:@"broken"
242bcc6d
JF
5595 ] autorelease];
5596
5597 [sheet setBodyText:[NSString stringWithFormat:@"The following packages have unmet dependencies:\n\n%@", [broken componentsJoinedByString:@"\n"]]];
5598 [sheet popupAlertAnimated:YES];
5599
e057ec05 5600 [self _reloadData];
242bcc6d 5601 }
2d28b35a
JF
5602}
5603
e057ec05
JF
5604- (void) installPackage:(Package *)package {
5605 @synchronized (self) {
5606 [package install];
5607 [self resolve];
5608 [self perform];
5609 }
5610}
5611
5612- (void) removePackage:(Package *)package {
5613 @synchronized (self) {
5614 [package remove];
5615 [self resolve];
5616 [self perform];
5617 }
5618}
5619
5620- (void) distUpgrade {
5621 @synchronized (self) {
5622 [database_ upgrade];
5623 [self perform];
5624 }
686e302f
JF
5625}
5626
2d28b35a 5627- (void) cancel {
e057ec05
JF
5628 @synchronized (self) {
5629 [confirm_ release];
5630 confirm_ = nil;
5631 [self _reloadData];
5632 }
2d28b35a
JF
5633}
5634
5635- (void) confirm {
5636 [overlay_ removeFromSuperview];
d72d91aa 5637 reload_ = true;
2d28b35a 5638
4941f41d
JF
5639 [progress_
5640 detachNewThreadSelector:@selector(perform)
5641 toTarget:database_
5642 withObject:nil
686e302f 5643 title:@"Running..."
4941f41d
JF
5644 ];
5645}
5646
df5a7529
JF
5647- (void) bootstrap_ {
5648 [database_ update];
5649 [database_ upgrade];
5650 [database_ prepare];
5651 [database_ perform];
5652}
5653
5654- (void) bootstrap {
5655 [progress_
5656 detachNewThreadSelector:@selector(bootstrap_)
5657 toTarget:self
5658 withObject:nil
5659 title:@"Bootstrap Install..."
5660 ];
5661}
5662
4941f41d 5663- (void) progressViewIsComplete:(ProgressView *)progress {
e057ec05
JF
5664 @synchronized (self) {
5665 [self _reloadData];
5666
5667 if (confirm_ != nil) {
5668 [underlay_ addSubview:overlay_];
5669 [confirm_ removeFromSuperview];
5670 [confirm_ release];
5671 confirm_ = nil;
5672 }
2d28b35a 5673 }
a75f53e7
JF
5674}
5675
e057ec05 5676- (void) setPage:(RVPage *)page {
e25e221f 5677 [page resetViewAnimated:NO];
e057ec05
JF
5678 [page setDelegate:self];
5679 [book_ setPage:page];
a75f53e7
JF
5680}
5681
faf4eb4f
JF
5682- (RVPage *) _pageForURL:(NSURL *)url withClass:(Class)_class {
5683 BrowserView *browser = [[[_class alloc] initWithBook:book_ database:database_] autorelease];
5684 [browser loadURL:url];
e057ec05 5685 return browser;
4941f41d
JF
5686}
5687
faf4eb4f
JF
5688- (void) _setHomePage {
5689 [self setPage:[self _pageForURL:[NSURL URLWithString:@"http://cydia.saurik.com/"] withClass:[HomeView class]]];
5690}
5691
a75f53e7 5692- (void) buttonBarItemTapped:(id)sender {
7e986211 5693 unsigned tag = [sender tag];
97959670
JF
5694 if (tag == tag_) {
5695 [book_ resetViewAnimated:YES];
5696 return;
fa7bb92f
JF
5697 } else if (tag_ == 2 && tag != 2)
5698 [install_ resetView];
a75f53e7 5699
7e986211 5700 switch (tag) {
7d07c4ff 5701 case 1: [self _setHomePage]; break;
e057ec05 5702
7d07c4ff
JF
5703 case 2: [self setPage:install_]; break;
5704 case 3: [self setPage:changes_]; break;
5705 case 4: [self setPage:manage_]; break;
5706 case 5: [self setPage:search_]; break;
e057ec05 5707
7d07c4ff 5708 default: _assert(false);
a75f53e7
JF
5709 }
5710
7e986211 5711 tag_ = tag;
7e986211
JF
5712}
5713
5f54c108
JF
5714- (void) fixSpringBoard {
5715 pid_t pid = ExecFork();
5716 if (pid == 0) {
5717 sleep(1);
5718
5719 if (pid_t child = fork()) {
5720 waitpid(child, NULL, 0);
5721 } else {
5722 execlp("launchctl", "launchctl", "unload", SpringBoard_, NULL);
5723 perror("launchctl unload");
5724 exit(0);
5725 }
5726
5727 execlp("launchctl", "launchctl", "load", SpringBoard_, NULL);
5728 perror("launchctl load");
5729 exit(0);
5730 }
5731}
5732
686e302f 5733- (void) applicationWillSuspend {
d72d91aa
JF
5734 [database_ clean];
5735
3042366d 5736 if (reload_) {
68fd5800 5737#ifndef __OBJC2__
5f54c108 5738 [self fixSpringBoard];
68fd5800 5739#endif
5f54c108 5740}
2d7f7dea
JF
5741
5742 [super applicationWillSuspend];
686e302f
JF
5743}
5744
faf4eb4f 5745- (void) askForSettings {
d210b85d 5746 UIActionSheet *role = [[[UIActionSheet alloc]
faf4eb4f
JF
5747 initWithTitle:@"Who Are You?"
5748 buttons:[NSArray arrayWithObjects:
5749 @"User (Graphical Only)",
5e563e79 5750 @"Hacker (+ Command Line)",
faf4eb4f
JF
5751 @"Developer (No Filters)",
5752 nil]
5753 defaultButtonIndex:-1
5754 delegate:self
5755 context:@"role"
5756 ] autorelease];
5757
5758 [role setBodyText:@"Not all of the packages available via Cydia are designed to be used by all users. Please categorize yourself so that Cydia can apply helpful filters.\n\nThis choice can be changed from \"Settings\" under the \"Manage\" tab."];
5759 [role popupAlertAnimated:YES];
5760}
5761
b26eb97d
JF
5762- (void) finish {
5763 if (hud_ != nil) {
5764 [self setStatusBarShowsProgress:NO];
9e07091a 5765
b26eb97d
JF
5766 [hud_ show:NO];
5767 [hud_ removeFromSuperview];
5768 [hud_ autorelease];
5769 hud_ = nil;
a2ef756d 5770
81a66bfc
JF
5771 pid_t pid = ExecFork();
5772 if (pid == 0) {
5773 execlp("launchctl", "launchctl", "stop", "com.apple.SpringBoard", NULL);
5774 perror("launchctl stop");
5775 }
5776
a2ef756d 5777 return;
b26eb97d 5778 }
2d28b35a 5779
faf4eb4f
JF
5780 if (Role_ == nil) {
5781 [self askForSettings];
5782 return;
5783 }
5784
2d28b35a 5785 overlay_ = [[UIView alloc] initWithFrame:[underlay_ bounds]];
df5a7529 5786
b26eb97d 5787 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
e057ec05
JF
5788 book_ = [[CYBook alloc] initWithFrame:CGRectMake(
5789 0, 0, screenrect.size.width, screenrect.size.height - 48
5790 ) database:database_];
a75f53e7 5791
e057ec05 5792 [book_ setDelegate:self];
a75f53e7 5793
e057ec05 5794 [overlay_ addSubview:book_];
a933cee2 5795
a75f53e7
JF
5796 NSArray *buttonitems = [NSArray arrayWithObjects:
5797 [NSDictionary dictionaryWithObjectsAndKeys:
5798 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
e25e221f
JF
5799 @"home-up.png", kUIButtonBarButtonInfo,
5800 @"home-dn.png", kUIButtonBarButtonSelectedInfo,
a75f53e7
JF
5801 [NSNumber numberWithInt:1], kUIButtonBarButtonTag,
5802 self, kUIButtonBarButtonTarget,
e25e221f 5803 @"Home", kUIButtonBarButtonTitle,
a75f53e7
JF
5804 @"0", kUIButtonBarButtonType,
5805 nil],
5806
5807 [NSDictionary dictionaryWithObjectsAndKeys:
5808 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
5809 @"install-up.png", kUIButtonBarButtonInfo,
5810 @"install-dn.png", kUIButtonBarButtonSelectedInfo,
5811 [NSNumber numberWithInt:2], kUIButtonBarButtonTag,
5812 self, kUIButtonBarButtonTarget,
fa7bb92f 5813 @"Sections", kUIButtonBarButtonTitle,
a75f53e7
JF
5814 @"0", kUIButtonBarButtonType,
5815 nil],
5816
5817 [NSDictionary dictionaryWithObjectsAndKeys:
5818 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
686e302f
JF
5819 @"changes-up.png", kUIButtonBarButtonInfo,
5820 @"changes-dn.png", kUIButtonBarButtonSelectedInfo,
a75f53e7
JF
5821 [NSNumber numberWithInt:3], kUIButtonBarButtonTag,
5822 self, kUIButtonBarButtonTarget,
686e302f 5823 @"Changes", kUIButtonBarButtonTitle,
a75f53e7
JF
5824 @"0", kUIButtonBarButtonType,
5825 nil],
5826
5827 [NSDictionary dictionaryWithObjectsAndKeys:
5828 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
686e302f
JF
5829 @"manage-up.png", kUIButtonBarButtonInfo,
5830 @"manage-dn.png", kUIButtonBarButtonSelectedInfo,
a75f53e7
JF
5831 [NSNumber numberWithInt:4], kUIButtonBarButtonTag,
5832 self, kUIButtonBarButtonTarget,
e057ec05 5833 @"Manage", kUIButtonBarButtonTitle,
a75f53e7
JF
5834 @"0", kUIButtonBarButtonType,
5835 nil],
5836
5837 [NSDictionary dictionaryWithObjectsAndKeys:
5838 @"buttonBarItemTapped:", kUIButtonBarButtonAction,
686e302f
JF
5839 @"search-up.png", kUIButtonBarButtonInfo,
5840 @"search-dn.png", kUIButtonBarButtonSelectedInfo,
a75f53e7
JF
5841 [NSNumber numberWithInt:5], kUIButtonBarButtonTag,
5842 self, kUIButtonBarButtonTarget,
686e302f 5843 @"Search", kUIButtonBarButtonTitle,
a75f53e7
JF
5844 @"0", kUIButtonBarButtonType,
5845 nil],
5846 nil];
5847
d210b85d 5848 buttonbar_ = [[UIToolbar alloc]
2d28b35a 5849 initInView:overlay_
a75f53e7 5850 withFrame:CGRectMake(
2a987aa5
JF
5851 0, screenrect.size.height - ButtonBarHeight_,
5852 screenrect.size.width, ButtonBarHeight_
a75f53e7
JF
5853 )
5854 withItemList:buttonitems
5855 ];
5856
4941f41d
JF
5857 [buttonbar_ setDelegate:self];
5858 [buttonbar_ setBarStyle:1];
5859 [buttonbar_ setButtonBarTrackingMode:2];
a75f53e7
JF
5860
5861 int buttons[5] = {1, 2, 3, 4, 5};
4941f41d
JF
5862 [buttonbar_ registerButtonGroup:0 withButtons:buttons withCount:5];
5863 [buttonbar_ showButtonGroup:0 withDuration:0];
a75f53e7
JF
5864
5865 for (int i = 0; i != 5; ++i)
4941f41d 5866 [[buttonbar_ viewWithTag:(i + 1)] setFrame:CGRectMake(
2a987aa5 5867 i * 64 + 2, 1, 60, ButtonBarHeight_
a75f53e7
JF
5868 )];
5869
4941f41d 5870 [buttonbar_ showSelectionForButton:1];
2d28b35a 5871 [overlay_ addSubview:buttonbar_];
a75f53e7 5872
686e302f 5873 [UIKeyboard initImplementationNow];
686e302f 5874 CGSize keysize = [UIKeyboard defaultSize];
59efd93a 5875 CGRect keyrect = {{0, [overlay_ bounds].size.height}, keysize};
686e302f 5876 keyboard_ = [[UIKeyboard alloc] initWithFrame:keyrect];
0039464f 5877 [[UIKeyboardImpl sharedInstance] setSoundsEnabled:(Sounds_Keyboard_ ? YES : NO)];
59efd93a 5878 [overlay_ addSubview:keyboard_];
686e302f 5879
e25e221f
JF
5880 install_ = [[InstallView alloc] initWithBook:book_ database:database_];
5881 changes_ = [[ChangesView alloc] initWithBook:book_ database:database_];
e25e221f
JF
5882 search_ = [[SearchView alloc] initWithBook:book_ database:database_];
5883
faf4eb4f
JF
5884 manage_ = (ManageView *) [[self
5885 _pageForURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"manage" ofType:@"html"]]
5886 withClass:[ManageView class]
5887 ] retain];
5888
b26eb97d
JF
5889 if (!bootstrap_)
5890 [underlay_ addSubview:overlay_];
5891
965edd52 5892 [self reloadData];
df5a7529
JF
5893
5894 if (bootstrap_)
5895 [self bootstrap];
e057ec05 5896 else
e25e221f 5897 [self _setHomePage];
686e302f
JF
5898}
5899
d210b85d 5900- (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
faf4eb4f
JF
5901 NSString *context = [sheet context];
5902 if ([context isEqualToString:@"fixhalf"])
5903 switch (button) {
5904 case 1:
5905 @synchronized (self) {
5906 for (int i = 0, e = [broken_ count]; i != e; ++i) {
5907 Package *broken = [broken_ objectAtIndex:i];
5908 [broken remove];
5909
5910 NSString *id = [broken id];
5911 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.prerm", id] UTF8String]);
5912 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.postrm", id] UTF8String]);
5913 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.preinst", id] UTF8String]);
5914 unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.postinst", id] UTF8String]);
5915 }
5916
5917 [self resolve];
5918 [self perform];
5919 }
5920 break;
5921
5922 case 2:
5923 [broken_ removeAllObjects];
5924 [self _loaded];
5925 break;
5926
5927 default:
5928 _assert(false);
5929 }
5930 else if ([context isEqualToString:@"role"]) {
5931 switch (button) {
5932 case 1: Role_ = @"User"; break;
5933 case 2: Role_ = @"Hacker"; break;
5934 case 3: Role_ = @"Developer"; break;
5935
5936 default:
5937 Role_ = nil;
5938 _assert(false);
5939 }
5940
5941 bool reset = Settings_ != nil;
5942
5943 Settings_ = [NSMutableDictionary dictionaryWithObjectsAndKeys:
5944 Role_, @"Role",
5945 nil];
5946
5947 [Metadata_ setObject:Settings_ forKey:@"Settings"];
5948
5949 Changed_ = true;
5950
5951 if (reset)
5952 [self updateData];
5953 else
5954 [self finish];
5955 } else if ([context isEqualToString:@"upgrade"])
5956 switch (button) {
5957 case 1:
5958 @synchronized (self) {
5959 for (int i = 0, e = [essential_ count]; i != e; ++i) {
5960 Package *essential = [essential_ objectAtIndex:i];
5961 [essential install];
5962 }
5963
5964 [self resolve];
5965 [self perform];
5966 }
5967 break;
5968
5969 case 2:
5970 Ignored_ = YES;
5971 break;
5972
5973 default:
5974 _assert(false);
5975 }
5976
5977 [sheet dismiss];
5978}
5979
b26eb97d
JF
5980- (void) reorganize {
5981 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
56fd24ea
JF
5982 system("/usr/libexec/cydia/free.sh");
5983 [self performSelectorOnMainThread:@selector(finish) withObject:nil waitUntilDone:NO];
b26eb97d
JF
5984 [pool release];
5985}
5986
5987- (void) applicationSuspend:(__GSEvent *)event {
5988 if (hud_ == nil && ![progress_ isRunning])
5989 [super applicationSuspend:event];
b26eb97d
JF
5990}
5991
fa7bb92f
JF
5992- (void) _animateSuspension:(BOOL)arg0 duration:(double)arg1 startTime:(double)arg2 scale:(float)arg3 {
5993 if (hud_ == nil)
5994 [super _animateSuspension:arg0 duration:arg1 startTime:arg2 scale:arg3];
5995}
5996
5997- (void) _setSuspended:(BOOL)value {
5998 if (hud_ == nil)
5999 [super _setSuspended:value];
6000}
6001
faf4eb4f
JF
6002- (UIProgressHUD *) addProgressHUD {
6003 UIProgressHUD *hud = [[UIProgressHUD alloc] initWithWindow:window_];
6004 [hud show:YES];
6005 [underlay_ addSubview:hud];
6006 return hud;
6007}
6008
b26eb97d 6009- (void) applicationDidFinishLaunching:(id)unused {
5e563e79
JF
6010 Font12_ = [[UIFont systemFontOfSize:12] retain];
6011 Font12Bold_ = [[UIFont boldSystemFontOfSize:12] retain];
6012 Font14_ = [[UIFont systemFontOfSize:14] retain];
6013 Font18Bold_ = [[UIFont boldSystemFontOfSize:18] retain];
6014 Font22Bold_ = [[UIFont boldSystemFontOfSize:22] retain];
6015
b26eb97d
JF
6016 _assert(pkgInitConfig(*_config));
6017 _assert(pkgInitSystem(*_config, _system));
6018
6019 confirm_ = nil;
6020 tag_ = 1;
6021
6022 essential_ = [[NSMutableArray alloc] initWithCapacity:4];
6023 broken_ = [[NSMutableArray alloc] initWithCapacity:4];
6024
6025 CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
6026 window_ = [[UIWindow alloc] initWithContentRect:screenrect];
6027
5e563e79
JF
6028 [window_ orderFront:self];
6029 [window_ makeKey:self];
6030 [window_ _setHidden:NO];
b26eb97d
JF
6031
6032 database_ = [[Database alloc] init];
6033 progress_ = [[ProgressView alloc] initWithFrame:[window_ bounds] database:database_ delegate:self];
6034 [database_ setDelegate:progress_];
6035 [window_ setContentView:progress_];
6036
6037 underlay_ = [[UIView alloc] initWithFrame:[progress_ bounds]];
6038 [progress_ setContentView:underlay_];
6039
6040 [progress_ resetView];
6041
fa7bb92f 6042 if (
b26eb97d 6043 readlink("/Applications", NULL, 0) == -1 && errno == EINVAL ||
b26eb97d 6044 readlink("/Library/Ringtones", NULL, 0) == -1 && errno == EINVAL ||
fa7bb92f
JF
6045 readlink("/Library/Wallpaper", NULL, 0) == -1 && errno == EINVAL ||
6046 readlink("/usr/include", NULL, 0) == -1 && errno == EINVAL ||
6047 readlink("/usr/libexec", NULL, 0) == -1 && errno == EINVAL ||
6048 readlink("/usr/share", NULL, 0) == -1 && errno == EINVAL
b26eb97d 6049 ) {
03a2893d
JF
6050 [self setIdleTimerDisabled:YES];
6051
faf4eb4f 6052 hud_ = [self addProgressHUD];
81a66bfc 6053 [hud_ setText:@"Reorganizing\n\nWill Automatically\nRestart When Done"];
b26eb97d
JF
6054
6055 [self setStatusBarShowsProgress:YES];
6056
6057 [NSThread
6058 detachNewThreadSelector:@selector(reorganize)
6059 toTarget:self
6060 withObject:nil
6061 ];
fa7bb92f 6062 } else
b26eb97d
JF
6063 [self finish];
6064}
6065
686e302f 6066- (void) showKeyboard:(BOOL)show {
59efd93a
JF
6067 CGSize keysize = [UIKeyboard defaultSize];
6068 CGRect keydown = {{0, [overlay_ bounds].size.height}, keysize};
6069 CGRect keyup = keydown;
6070 keyup.origin.y -= keysize.height;
6071
6072 UIFrameAnimation *animation = [[[UIFrameAnimation alloc] initWithTarget:keyboard_] autorelease];
6073 [animation setSignificantRectFields:2];
6074
6075 if (show) {
6076 [animation setStartFrame:keydown];
6077 [animation setEndFrame:keyup];
6078 [keyboard_ activate];
6079 } else {
6080 [animation setStartFrame:keyup];
6081 [animation setEndFrame:keydown];
6082 [keyboard_ deactivate];
6083 }
6084
6085 [[UIAnimator sharedAnimator]
6086 addAnimations:[NSArray arrayWithObjects:animation, nil]
2a987aa5 6087 withDuration:KeyboardTime_
59efd93a
JF
6088 start:YES
6089 ];
a75f53e7
JF
6090}
6091
d210b85d 6092- (void) slideUp:(UIActionSheet *)alert {
d72d91aa
JF
6093 if (Advanced_)
6094 [alert presentSheetFromButtonBar:buttonbar_];
6095 else
6096 [alert presentSheetInView:overlay_];
e057ec05
JF
6097}
6098
a75f53e7
JF
6099@end
6100
686e302f
JF
6101void AddPreferences(NSString *plist) {
6102 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
6103
6104 NSMutableDictionary *settings = [[[NSMutableDictionary alloc] initWithContentsOfFile:plist] autorelease];
6105 _assert(settings != NULL);
6106 NSMutableArray *items = [settings objectForKey:@"items"];
6107
6108 bool cydia(false);
6109
6110 for (size_t i(0); i != [items count]; ++i) {
6111 NSMutableDictionary *item([items objectAtIndex:i]);
6112 NSString *label = [item objectForKey:@"label"];
6113 if (label != nil && [label isEqualToString:@"Cydia"]) {
6114 cydia = true;
6115 break;
6116 }
6117 }
6118
6119 if (!cydia) {
6120 for (size_t i(0); i != [items count]; ++i) {
6121 NSDictionary *item([items objectAtIndex:i]);
6122 NSString *label = [item objectForKey:@"label"];
6123 if (label != nil && [label isEqualToString:@"General"]) {
6124 [items insertObject:[NSDictionary dictionaryWithObjectsAndKeys:
6125 @"CydiaSettings", @"bundle",
6126 @"PSLinkCell", @"cell",
6127 [NSNumber numberWithBool:YES], @"hasIcon",
6128 [NSNumber numberWithBool:YES], @"isController",
6129 @"Cydia", @"label",
6130 nil] atIndex:(i + 1)];
6131
6132 break;
6133 }
6134 }
6135
6136 _assert([settings writeToFile:plist atomically:YES] == YES);
6137 }
6138
6139 [pool release];
6140}
6141
6142/*IMP alloc_;
6143id Alloc_(id self, SEL selector) {
6144 id object = alloc_(self, selector);
6145 fprintf(stderr, "[%s]A-%p\n", self->isa->name, object);
6146 return object;
6147}*/
6148
e057ec05
JF
6149/*IMP dealloc_;
6150id Dealloc_(id self, SEL selector) {
6151 id object = dealloc_(self, selector);
6152 fprintf(stderr, "[%s]D-%p\n", self->isa->name, object);
6153 return object;
6154}*/
686e302f 6155
e057ec05 6156int main(int argc, char *argv[]) {
0039464f
JF
6157 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
6158
df5a7529
JF
6159 bootstrap_ = argc > 1 && strcmp(argv[1], "--bootstrap") == 0;
6160
853d14d3 6161 App_ = [[NSBundle mainBundle] bundlePath];
0039464f
JF
6162 Home_ = NSHomeDirectory();
6163
6164 {
6165 NSString *plist = [Home_ stringByAppendingString:@"/Library/Preferences/com.apple.preferences.sounds.plist"];
6166 if (NSDictionary *sounds = [NSDictionary dictionaryWithContentsOfFile:plist])
6167 if (NSNumber *keyboard = [sounds objectForKey:@"keyboard"])
6168 Sounds_Keyboard_ = [keyboard boolValue];
6169 }
6170
686e302f
JF
6171 setuid(0);
6172 setgid(0);
6173
84af45a1
JF
6174 if (unlink("/var/cache/apt/pkgcache.bin") == -1)
6175 _assert(errno == ENOENT);
6176 if (unlink("/var/cache/apt/srcpkgcache.bin") == -1)
6177 _assert(errno == ENOENT);
30d83bfe 6178
686e302f
JF
6179 /*Method alloc = class_getClassMethod([NSObject class], @selector(alloc));
6180 alloc_ = alloc->method_imp;
6181 alloc->method_imp = (IMP) &Alloc_;*/
6182
e057ec05
JF
6183 /*Method dealloc = class_getClassMethod([NSObject class], @selector(dealloc));
6184 dealloc_ = dealloc->method_imp;
6185 dealloc->method_imp = (IMP) &Dealloc_;*/
6186
fc675b93
JF
6187 if (NSDictionary *sysver = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]) {
6188 if (NSString *prover = [sysver valueForKey:@"ProductVersion"]) {
b0d03ade 6189 Firmware_ = strdup([prover UTF8String]);
fc675b93
JF
6190 NSArray *versions = [prover componentsSeparatedByString:@"."];
6191 int count = [versions count];
6192 Major_ = count > 0 ? [[versions objectAtIndex:0] intValue] : 0;
584f58f8
JF
6193 Minor_ = count > 1 ? [[versions objectAtIndex:1] intValue] : 0;
6194 BugFix_ = count > 2 ? [[versions objectAtIndex:2] intValue] : 0;
fc675b93
JF
6195 }
6196 }
6197
2d28b35a
JF
6198 size_t size;
6199 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
6200 char *machine = new char[size];
6201 sysctlbyname("hw.machine", machine, &size, NULL, 0);
6202 Machine_ = machine;
6203
6204 if (CFMutableDictionaryRef dict = IOServiceMatching("IOPlatformExpertDevice"))
6205 if (io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, dict)) {
6206 if (CFTypeRef serial = IORegistryEntryCreateCFProperty(service, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0)) {
6207 SerialNumber_ = strdup(CFStringGetCStringPtr((CFStringRef) serial, CFStringGetSystemEncoding()));
6208 CFRelease(serial);
6209 }
6210
6211 IOObjectRelease(service);
6212 }
6213
ec5624fe
JF
6214 /*AddPreferences(@"/Applications/Preferences.app/Settings-iPhone.plist");
6215 AddPreferences(@"/Applications/Preferences.app/Settings-iPod.plist");*/
686e302f
JF
6216
6217 if ((Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"]) == NULL)
6218 Metadata_ = [[NSMutableDictionary alloc] initWithCapacity:2];
fa7bb92f 6219 else {
faf4eb4f
JF
6220 Settings_ = [Metadata_ objectForKey:@"Settings"];
6221
686e302f 6222 Packages_ = [Metadata_ objectForKey:@"Packages"];
fa7bb92f 6223 Sections_ = [Metadata_ objectForKey:@"Sections"];
faf4eb4f
JF
6224 Sources_ = [Metadata_ objectForKey:@"Sources"];
6225 }
6226
6227 if (Settings_ != nil)
6228 Role_ = [Settings_ objectForKey:@"Role"];
6229
6230 if (Packages_ == nil) {
6231 Packages_ = [[[NSMutableDictionary alloc] initWithCapacity:128] autorelease];
6232 [Metadata_ setObject:Packages_ forKey:@"Packages"];
6233 }
6234
6235 if (Sections_ == nil) {
6236 Sections_ = [[[NSMutableDictionary alloc] initWithCapacity:32] autorelease];
6237 [Metadata_ setObject:Sections_ forKey:@"Sections"];
6238 }
6239
6240 if (Sources_ == nil) {
6241 Sources_ = [[[NSMutableDictionary alloc] initWithCapacity:0] autorelease];
6242 [Metadata_ setObject:Sources_ forKey:@"Sources"];
fa7bb92f 6243 }
686e302f 6244
1eb0c554
JF
6245 if (access("/Library/MobileSubstrate/MobileSubstrate.dylib", F_OK) == 0)
6246 dlopen("/Library/MobileSubstrate/MobileSubstrate.dylib", RTLD_LAZY | RTLD_GLOBAL);
6247
6a0db335
JF
6248 if (access("/User", F_OK) != 0)
6249 system("/usr/libexec/cydia/firmware.sh");
63a1e4b8 6250
b27f0a94 6251 Locale_ = CFLocaleCopyCurrent();
e057ec05
JF
6252 space_ = CGColorSpaceCreateDeviceRGB();
6253
5e563e79 6254 Blue_.Set(space_, 0.2, 0.2, 1.0, 1.0);
d72d91aa 6255 Blueish_.Set(space_, 0x19/255.f, 0x32/255.f, 0x50/255.f, 1.0);
e057ec05
JF
6256 Black_.Set(space_, 0.0, 0.0, 0.0, 1.0);
6257 Clear_.Set(space_, 0.0, 0.0, 0.0, 0.0);
6258 Red_.Set(space_, 1.0, 0.0, 0.0, 1.0);
6259 White_.Set(space_, 1.0, 1.0, 1.0, 1.0);
faf4eb4f
JF
6260 Gray_.Set(space_, 0.4, 0.4, 0.4, 1.0);
6261
03d01f0e
JF
6262 Finishes_ = [NSArray arrayWithObjects:@"return", @"reopen", @"restart", @"reload", @"reboot", nil];
6263
d1494d2c 6264 SectionMap_ = [[[NSDictionary alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Sections" ofType:@"plist"]] autorelease];
faf4eb4f 6265
d210b85d 6266 int value = UIApplicationMain(argc, argv, @"Cydia", @"Cydia");
e057ec05
JF
6267
6268 CGColorSpaceRelease(space_);
b27f0a94 6269 CFRelease(Locale_);
e057ec05 6270
a75f53e7 6271 [pool release];
e057ec05 6272 return value;
a75f53e7 6273}