exit(0); \
} while (false)
+static uint64_t profile_;
+
+#define _timestamp ({ \
+ struct timeval tv; \
+ gettimeofday(&tv, NULL); \
+ tv.tv_sec * 1000000 + tv.tv_usec; \
+})
+
/* Objective-C Handle<> {{{ */
template <typename Type_>
class _H {
#define _pooled _H<NSAutoreleasePool> _pool([[NSAutoreleasePool alloc] init], true);
+void NSLogPoint(const char *fix, const CGPoint &point) {
+ NSLog(@"%s(%g,%g)", fix, point.x, point.y);
+}
+
void NSLogRect(const char *fix, const CGRect &rect) {
NSLog(@"%s(%g,%g)+(%g,%g)", fix, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
}
#define lprintf(args...) fprintf(stderr, args)
-#define ForSaurik 1
+#define ForRelease 0
+#define ForSaurik 1 && !ForRelease
#define RecycleWebViews 0
+#define AlwaysReload 0 && !ForRelease
/* Radix Sort {{{ */
@interface NSMutableArray (Radix)
-- (void) radixUsingSelector:(SEL)selector withObject:(id)object;
+- (void) radixSortUsingSelector:(SEL)selector withObject:(id)object;
@end
@implementation NSMutableArray (Radix)
-- (void) radixUsingSelector:(SEL)selector withObject:(id)object {
+- (void) radixSortUsingSelector:(SEL)selector withObject:(id)object {
NSInvocation *invocation([NSInvocation invocationWithMethodSignature:[NSMethodSignature signatureWithObjCTypes:"L12@0:4@8"]]);
[invocation setSelector:selector];
[invocation setArgument:&object atIndex:2];
@end
/* }}} */
+/* Apple Bug Fixes {{{ */
+@implementation UIWebDocumentView (Cydia)
+
+- (void) _setScrollerOffset:(CGPoint)offset {
+ UIScroller *scroller([self _scroller]);
+
+ CGSize size([scroller contentSize]);
+ CGSize bounds([scroller bounds].size);
+
+ CGPoint max;
+ max.x = size.width - bounds.width;
+ max.y = size.height - bounds.height;
+
+ // wtf Apple?!
+ if (max.x < 0)
+ max.x = 0;
+ if (max.y < 0)
+ max.y = 0;
+
+ offset.x = offset.x < 0 ? 0 : offset.x > max.x ? max.x : offset.x;
+ offset.y = offset.y < 0 ? 0 : offset.y > max.y ? max.y : offset.y;
+
+ [scroller setOffset:offset];
+}
+
+@end
+/* }}} */
+
typedef enum {
kUIControlEventMouseDown = 1 << 0,
kUIControlEventMouseMovedInside = 1 << 2, // mouse moved inside control target
@implementation NSString (Cydia)
+ (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length {
- char data[length + 1];
- memcpy(data, bytes, length);
- data[length] = '\0';
- return [NSString stringWithUTF8String:data];
+ return [[[NSString alloc] initWithBytes:bytes length:length encoding:NSUTF8StringEncoding] autorelease];
}
- (NSComparisonResult) compareByPath:(NSString *)other {
}
virtual void Fetch(pkgAcquire::ItemDesc &item) {
+ //NSString *name([NSString stringWithUTF8String:item.ShortDesc.c_str()]);
[delegate_ setProgressTitle:[NSString stringWithUTF8String:("Downloading " + item.ShortDesc).c_str()]];
}
@end
/* }}} */
/* Package Class {{{ */
-NSString *Scour(const char *field, const char *begin, const char *end) {
- size_t i(0), l(strlen(field));
-
- for (;;) {
- const char *name = begin + i;
- const char *colon = name + l;
- const char *value = colon + 1;
-
- if (
- value < end &&
- *colon == ':' &&
- strncasecmp(name, field, l) == 0
- ) {
- while (value != end && value[0] == ' ')
- ++value;
- const char *line = std::find(value, end, '\n');
- while (line != value && line[-1] == ' ')
- --line;
-
- return [NSString stringWithUTF8Bytes:value length:(line - value)];
- } else {
- begin = std::find(begin, end, '\n');
- if (begin == end)
- return nil;
- ++begin;
- }
- }
-}
-
@interface Package : NSObject {
pkgCache::PkgIterator iterator_;
_transient Database *database_;
version_ = [database_ policy]->GetCandidateVer(iterator_);
NSString *latest = version_.end() ? nil : [NSString stringWithUTF8String:version_.VerStr()];
- latest_ = [StripVersion(latest) retain];
+ latest_ = latest == nil ? nil : [StripVersion(latest) retain];
pkgCache::VerIterator current = iterator_.CurrentVer();
NSString *installed = current.end() ? nil : [NSString stringWithUTF8String:current.VerStr()];
const char *begin, *end;
parser->GetRec(begin, end);
- name_ = Scour("name", begin, end);
+ NSString *website(nil);
+ NSString *sponsor(nil);
+ NSString *author(nil);
+ NSString *tag(nil);
+
+ struct {
+ const char *name_;
+ NSString **value_;
+ } names[] = {
+ {"name", &name_},
+ {"icon", &icon_},
+ {"depiction", &depiction_},
+ {"homepage", &homepage_},
+ {"website", &website},
+ {"sponsor", &sponsor},
+ {"author", &author},
+ {"tag", &tag},
+ };
+
+ while (begin != end)
+ if (*begin == '\n') {
+ ++begin;
+ continue;
+ } else if (isblank(*begin)) next: {
+ begin = static_cast<char *>(memchr(begin + 1, '\n', end - begin - 1));
+ if (begin == NULL)
+ break;
+ } else if (const char *colon = static_cast<char *>(memchr(begin, ':', end - begin))) {
+ const char *name(begin);
+ size_t size(colon - begin);
+
+ begin = static_cast<char *>(memchr(begin, '\n', end - begin));
+
+ {
+ const char *stop(begin == NULL ? end : begin);
+ while (stop[-1] == '\r')
+ --stop;
+ while (++colon != stop && isblank(*colon));
+
+ for (size_t i(0); i != sizeof(names) / sizeof(names[0]); ++i)
+ if (strncasecmp(names[i].name_, name, size) == 0) {
+ NSString *value([NSString stringWithUTF8Bytes:colon length:(stop - colon)]);
+ *names[i].value_ = value;
+ break;
+ }
+ }
+
+ if (begin == NULL)
+ break;
+ ++begin;
+ } else goto next;
+
if (name_ != nil)
name_ = [name_ retain];
tagline_ = [[NSString stringWithUTF8String:parser->ShortDesc().c_str()] retain];
- icon_ = Scour("icon", begin, end);
if (icon_ != nil)
icon_ = [icon_ retain];
- depiction_ = Scour("depiction", begin, end);
if (depiction_ != nil)
depiction_ = [depiction_ retain];
- homepage_ = Scour("homepage", begin, end);
if (homepage_ == nil)
- homepage_ = Scour("website", begin, end);
+ homepage_ = website;
if ([homepage_ isEqualToString:depiction_])
homepage_ = nil;
if (homepage_ != nil)
homepage_ = [homepage_ retain];
- NSString *sponsor = Scour("sponsor", begin, end);
if (sponsor != nil)
sponsor_ = [[Address addressWithString:sponsor] retain];
- NSString *author = Scour("author", begin, end);
if (author != nil)
author_ = [[Address addressWithString:author] retain];
- NSString *tags = Scour("tag", begin, end);
- if (tags != nil)
- tags_ = [[tags componentsSeparatedByString:@", "] retain];
+ if (tag != nil)
+ tags_ = [[tag componentsSeparatedByString:@", "] retain];
}
if (tags_ != nil)
if (current.end())
return essential && [self essential];
- else {
- pkgCache::VerIterator candidate = [database_ policy]->GetCandidateVer(iterator_);
- return !candidate.end() && candidate != current;
- }
+ else
+ return !version_.end() && version_ != current;
}
- (BOOL) essential {
withObject:[NSArray arrayWithObjects:string, id, nil]
waitUntilDone:YES
];
- else if (type == "pmstatus")
+ else if (type == "pmstatus") {
[delegate_ setProgressTitle:string];
- else if (type == "pmconffile")
+ } else if (type == "pmconffile")
[delegate_ setConfigurationData:string];
else _assert(false);
} else _assert(false);
cache_.Close();
+ _trace();
if (!cache_.Open(progress_, true)) {
std::string error;
if (!_error->PopMessage(error))
return;
}
+ _trace();
now_ = [[NSDate date] retain];
}
[packages_ removeAllObjects];
+ _trace();
+ profile_ = 0;
for (pkgCache::PkgIterator iterator = cache_->PkgBegin(); !iterator.end(); ++iterator)
if (Package *package = [Package packageWithIterator:iterator database:self])
[packages_ addObject:package];
-
+ _trace();
[packages_ sortUsingSelector:@selector(compareByName:)];
+ _trace();
}
- (void) configure {
}
- (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
- NSString *context = [sheet context];
+ NSString *context([sheet context]);
- if ([context isEqualToString:@"remove"])
+ if ([context isEqualToString:@"remove"]) {
switch (button) {
case 1:
[self cancel];
default:
_assert(false);
}
- else if ([context isEqualToString:@"unable"])
- [self cancel];
- [sheet dismiss];
+ [sheet dismiss];
+ } else if ([context isEqualToString:@"unable"]) {
+ [self cancel];
+ [sheet dismiss];
+ } else
+ [super alertSheet:sheet buttonClicked:button];
}
- (void) webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame {
[self cancel];
}
+#if !AlwaysReload
- (void) _rightButtonClicked {
if (essential_ != nil)
[essential_ popupAlertAnimated:YES];
[delegate_ confirm];
}
}
+#endif
@end
/* }}} */
}
- (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
- NSString *context = [sheet context];
+ NSString *context([sheet context]);
+
if ([context isEqualToString:@"conffile"]) {
FILE *input = [database_ input];
default:
_assert(false);
}
- }
- [sheet dismiss];
+ [sheet dismiss];
+ }
}
- (void) closeButtonPushed {
NSString *plist = [path stringByAppendingPathComponent:@"Info.plist"];
if (NSMutableDictionary *info = [[NSMutableDictionary alloc] initWithContentsOfFile:plist]) {
[info autorelease];
- [info setObject:path forKey:@"Path"];
- [info setObject:@"System" forKey:@"ApplicationType"];
- [system addInfoDictionary:info];
+ if ([info objectForKey:@"CFBundleIdentifier"] != nil) {
+ [info setObject:path forKey:@"Path"];
+ [info setObject:@"System" forKey:@"ApplicationType"];
+ [system addInfoDictionary:info];
+ }
}
}
} else goto error;
}
- (void) _setProgressTitle:(NSString *)title {
- [status_ setText:title];
+ NSMutableArray *words([[title componentsSeparatedByString:@" "] mutableCopy]);
+ for (size_t i(0), e([words count]); i != e; ++i) {
+ NSString *word([words objectAtIndex:i]);
+ if (Package *package = [database_ packageWithName:word])
+ [words replaceObjectAtIndex:i withObject:[package name]];
+ }
+
+ [status_ setText:[words componentsJoinedByString:@" "]];
}
- (void) _setProgressPercent:(NSNumber *)percent {
}
- (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
- int count = [buttons_ count];
- _assert(count != 0);
- _assert(button <= count + 1);
+ NSString *context([sheet context]);
- if (count != button - 1)
- [self _clickButtonWithName:[buttons_ objectAtIndex:(button - 1)]];
+ if ([context isEqualToString:@"modify"]) {
+ int count = [buttons_ count];
+ _assert(count != 0);
+ _assert(button <= count + 1);
- [sheet dismiss];
+ if (count != button - 1)
+ [self _clickButtonWithName:[buttons_ objectAtIndex:(button - 1)]];
+
+ [sheet dismiss];
+ } else
+ [super alertSheet:sheet buttonClicked:button];
}
- (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
[super webView:sender didClearWindowObject:window forFrame:frame];
}
+#if !AlwaysReload
- (void) _rightButtonClicked {
/*[super _rightButtonClicked];
return;*/
buttons:buttons
defaultButtonIndex:2
delegate:self
- context:@"manage"
+ context:@"modify"
] autorelease]];
}
}
+#endif
- (NSString *) _rightButtonTitle {
int count = [buttons_ count];
}
- (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
- NSString *context = [sheet context];
- if ([context isEqualToString:@"source"])
+ NSString *context([sheet context]);
+
+ if ([context isEqualToString:@"source"]) {
switch (button) {
case 1: {
NSString *href = [[sheet textField] text];
_assert(false);
}
- [sheet dismiss];
+ [sheet dismiss];
+ }
}
- (id) initWithBook:(RVBook *)book database:(Database *)database {
context:@"source"
] autorelease];
+ [sheet setNumberOfRows:1];
+
[sheet addTextFieldWithValue:@"http://" label:@""];
UITextInputTraits *traits = [[sheet textField] textInputTraits];
[traits setAutocapitalizationType:0];
- [traits setKeyboardType:3];
+ [traits setKeyboardType:UIKeyboardTypeURL];
[traits setAutocorrectionType:1];
[sheet popupAlertAnimated:YES];
@implementation HomeView
- (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
- [sheet dismiss];
+ NSString *context([sheet context]);
+
+ if ([context isEqualToString:@"about"])
+ [sheet dismiss];
+ else
+ [super alertSheet:sheet buttonClicked:button];
}
- (void) _leftButtonClicked {
return @"Settings";
}
+#if !AlwaysReload
- (NSString *) _rightButtonTitle {
return nil;
}
+#endif
@end
/* }}} */
@implementation BrowserView
- (void) dealloc {
+ if (challenge_ != nil)
+ [challenge_ release];
+
WebView *webview = [webview_ webView];
[webview setFrameLoadDelegate:nil];
[webview setResourceLoadDelegate:nil];
[book_ pushPage:self];
}
-- (NSURLRequest *) webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource {
+- (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
+ NSString *context([sheet context]);
+
+ if ([context isEqualToString:@"challenge"]) {
+ id<NSURLAuthenticationChallengeSender> sender([challenge_ sender]);
+
+ switch (button) {
+ case 1: {
+ NSString *username([[sheet textFieldAtIndex:0] text]);
+ NSString *password([[sheet textFieldAtIndex:1] text]);
+
+ NSURLCredential *credential([NSURLCredential credentialWithUser:username password:password persistence:NSURLCredentialPersistenceForSession]);
+
+ [sender useCredential:credential forAuthenticationChallenge:challenge_];
+ } break;
+
+ case 2:
+ [sender cancelAuthenticationChallenge:challenge_];
+ break;
+
+ default:
+ _assert(false);
+ }
+
+ [challenge_ release];
+ challenge_ = nil;
+
+ [sheet dismiss];
+ }
+}
+
+- (void) webView:(WebView *)sender resource:(id)identifier didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge fromDataSource:(WebDataSource *)source {
+ challenge_ = [challenge retain];
+
+ NSURLProtectionSpace *space([challenge protectionSpace]);
+ NSString *realm([space realm]);
+ if (realm == nil)
+ realm = @"";
+
+ UIActionSheet *sheet = [[[UIActionSheet alloc]
+ initWithTitle:realm
+ buttons:[NSArray arrayWithObjects:@"Login", @"Cancel", nil]
+ defaultButtonIndex:0
+ delegate:self
+ context:@"challenge"
+ ] autorelease];
+
+ [sheet setNumberOfRows:1];
+
+ [sheet addTextFieldWithValue:@"" label:@"username"];
+ [sheet addTextFieldWithValue:@"" label:@"password"];
+
+ UITextField *username([sheet textFieldAtIndex:0]); {
+ UITextInputTraits *traits([username textInputTraits]);
+ [traits setAutocapitalizationType:0];
+ [traits setAutocorrectionType:1];
+ }
+
+ UITextField *password([sheet textFieldAtIndex:1]); {
+ UITextInputTraits *traits([password textInputTraits]);
+ [traits setAutocapitalizationType:0];
+ [traits setAutocorrectionType:1];
+ }
+
+ [sheet popupAlertAnimated:YES];
+}
+
+- (NSURLRequest *) webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)source {
NSURL *url = [request URL];
if ([self getSpecial:url])
return nil;
[webview_ setZoomsFocusedFormControl:YES];
[webview_ setContentsPosition:7];
[webview_ setEnabledGestures:0xa];
- [webview_ setValue:[NSNumber numberWithBool:YES] forGestureAttribute:0x4];
- [webview_ setValue:[NSNumber numberWithBool:YES] forGestureAttribute:0x7];
+ [webview_ setValue:[NSNumber numberWithBool:YES] forGestureAttribute:UIGestureAttributeIsZoomRubberBandEnabled];
+ [webview_ setValue:[NSNumber numberWithBool:YES] forGestureAttribute:UIGestureAttributeUpdatesScroller];
[webview_ setSmoothsFonts:YES];
}
_trace();
- [packages_ radixUsingSelector:@selector(compareForChanges) withObject:nil];
+ [packages_ radixSortUsingSelector:@selector(compareForChanges) withObject:nil];
_trace();
Section *upgradable = [[[Section alloc] initWithName:@"Available Upgrades"] autorelease];
case 1: switch (row) {
case 0: {
UIPreferencesControlTableCell *cell([[[UIPreferencesControlTableCell alloc] init] autorelease]);
- [cell setTitle:@"Changes only shows upgrades to installed packages. This minimizes spam from packagers. Activate this to see upgrades to this package even when it is not installed."];
+ [cell setShowSelection:NO];
+ [cell setTitle:@"Changes only shows upgrades to installed packages so as to minimize spam from packagers. Activate this to see upgrades to this package even when it is not installed."];
return cell;
}
[ignoredSwitch_ addTarget:self action:@selector(onIgnored:) forEvents:kUIControlEventMouseUpInside];
subscribedCell_ = [[UIPreferencesControlTableCell alloc] init];
+ [subscribedCell_ setShowSelection:NO];
[subscribedCell_ setTitle:@"Show All Changes"];
[subscribedCell_ setControl:subscribedSwitch_];
ignoredCell_ = [[UIPreferencesControlTableCell alloc] init];
+ [ignoredCell_ setShowSelection:NO];
[ignoredCell_ setTitle:@"Ignore Upgrades"];
[ignoredCell_ setControl:ignoredSwitch_];
initWithTitle:[NSString stringWithFormat:@"%d Essential Upgrade%@", count, (count == 1 ? @"" : @"s")]
buttons:[NSArray arrayWithObjects:
@"Upgrade Essential",
- @"Upgrade Everything",
+ @"Complete Upgrade",
@"Ignore (Temporary)",
nil]
defaultButtonIndex:0
[overlay_ addSubview:hud];
[hud show:YES];*/
- _trace();
[database_ reloadData];
- _trace();
size_t changes(0);
CGSize keysize = [UIKeyboard defaultSize];
CGRect keyrect = {{0, [overlay_ bounds].size.height}, keysize};
keyboard_ = [[UIKeyboard alloc] initWithFrame:keyrect];
- [[UIKeyboardImpl sharedInstance] setSoundsEnabled:(Sounds_Keyboard_ ? YES : NO)];
+ //[[UIKeyboardImpl sharedInstance] setSoundsEnabled:(Sounds_Keyboard_ ? YES : NO)];
[overlay_ addSubview:keyboard_];
if (!bootstrap_)
}
- (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
- NSString *context = [sheet context];
- if ([context isEqualToString:@"fixhalf"])
+ NSString *context([sheet context]);
+
+ if ([context isEqualToString:@"fixhalf"]) {
switch (button) {
case 1:
@synchronized (self) {
default:
_assert(false);
}
- else if ([context isEqualToString:@"role"]) {
+
+ [sheet dismiss];
+ } else if ([context isEqualToString:@"role"]) {
switch (button) {
case 1: Role_ = @"User"; break;
case 2: Role_ = @"Hacker"; break;
[self updateData];
else
[self finish];
- } else if ([context isEqualToString:@"upgrade"])
+
+ [sheet dismiss];
+ } else if ([context isEqualToString:@"upgrade"]) {
switch (button) {
case 1:
@synchronized (self) {
_assert(false);
}
- [sheet dismiss];
+ [sheet dismiss];
+ }
}
- (void) reorganize { _pooled
[self setIdleTimerDisabled:YES];
hud_ = [self addProgressHUD];
- [hud_ setText:@"Reorganizing\n\nWill Automatically\nRestart When Done"];
+ [hud_ setText:@"Reorganizing\n\nWill Automatically\nClose When Done"];
[self setStatusBarShowsProgress:YES];
}*/
int main(int argc, char *argv[]) { _pooled
- bootstrap_ = argc > 1 && strcmp(argv[1], "--bootstrap") == 0;
+ bool substrate(false);
+
+ if (argc != 0) {
+ char **args(argv);
+ int arge(1);
+
+ for (int argi(1); argi != argc; ++argi)
+ if (strcmp(argv[argi], "--") == 0) {
+ arge = argi;
+ argv[argi] = argv[0];
+ argv += argi;
+ argc -= argi;
+ break;
+ }
+
+ for (int argi(1); argi != arge; ++argi)
+ if (strcmp(args[argi], "--bootstrap") == 0)
+ bootstrap_ = true;
+ else if (strcmp(args[argi], "--substrate") == 0)
+ substrate = true;
+ else
+ fprintf(stderr, "unknown argument: %s\n", args[argi]);
+ }
App_ = [[NSBundle mainBundle] bundlePath];
Home_ = NSHomeDirectory();
setuid(0);
setgid(0);
+#if 1 /* XXX: this costs 1.4s of startup performance */
if (unlink("/var/cache/apt/pkgcache.bin") == -1)
_assert(errno == ENOENT);
if (unlink("/var/cache/apt/srcpkgcache.bin") == -1)
_assert(errno == ENOENT);
+#endif
/*Method alloc = class_getClassMethod([NSObject class], @selector(alloc));
alloc_ = alloc->method_imp;
Documents_ = [[[NSMutableArray alloc] initWithCapacity:4] autorelease];
#endif
- if (access("/Library/MobileSubstrate/MobileSubstrate.dylib", F_OK) == 0)
+ if (substrate && access("/Library/MobileSubstrate/MobileSubstrate.dylib", F_OK) == 0)
dlopen("/Library/MobileSubstrate/MobileSubstrate.dylib", RTLD_LAZY | RTLD_GLOBAL);
if (access("/User", F_OK) != 0)