#include "CyteKit/WebViewController.h"
#include "CyteKit/stringWithUTF8Bytes.h"
+#include "Cydia/MIMEAddress.h"
+#include "Cydia/LoadingViewController.h"
#include "Cydia/ProgressEvent.h"
#include "SDURLCache/SDURLCache.h"
#define _end }
/* }}} */
+#include "Version.h"
#define Cydia_ CYDIA_VERSION
#define lprintf(args...) fprintf(stderr, args)
notify_post("com.saurik.Cydia.status");
}
+static CGFloat CYStatusBarHeight(UIInterfaceOrientation orientation) {
+ CGSize size([[UIApplication sharedApplication] statusBarFrame].size);
+ return UIInterfaceOrientationIsPortrait(orientation) ? size.height : size.width;
+}
+
/* NSForcedOrderingSearch doesn't work on the iPhone */
static const NSStringCompareOptions MatchCompareOptions_ = NSLiteralSearch | NSCaseInsensitiveSearch;
static const NSStringCompareOptions LaxCompareOptions_ = NSNumericSearch | NSDiacriticInsensitiveSearch | NSWidthInsensitiveSearch | NSCaseInsensitiveSearch;
};
/* }}} */
-/* Mime Addresses {{{ */
-@interface Address : NSObject {
- _H<NSString> name_;
- _H<NSString> address_;
-}
-
-- (NSString *) name;
-- (NSString *) address;
-
-- (void) setAddress:(NSString *)address;
-
-+ (Address *) addressWithString:(NSString *)string;
-- (Address *) initWithString:(NSString *)string;
-
-@end
-
-@implementation Address
-
-- (NSString *) name {
- return name_;
-}
-
-- (NSString *) address {
- return address_;
-}
-
-- (void) setAddress:(NSString *)address {
- address_ = address;
-}
-
-+ (Address *) addressWithString:(NSString *)string {
- return [[[Address alloc] initWithString:string] autorelease];
-}
-
-+ (NSArray *) _attributeKeys {
- return [NSArray arrayWithObjects:
- @"address",
- @"name",
- nil];
-}
-
-- (NSArray *) attributeKeys {
- return [[self class] _attributeKeys];
-}
-
-+ (BOOL) isKeyExcludedFromWebScript:(const char *)name {
- return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name];
-}
-
-- (Address *) initWithString:(NSString *)string {
- if ((self = [super init]) != nil) {
- const char *data = [string UTF8String];
- size_t size = [string length];
-
- static Pcre address_r("^\"?(.*)\"? <([^>]*)>$");
-
- if (address_r(data, size)) {
- name_ = address_r[1];
- address_ = address_r[2];
- } else {
- name_ = string;
- address_ = nil;
- }
- } return self;
-}
-
-@end
-/* }}} */
/* CoreGraphics Primitives {{{ */
class CYColor {
private:
static _H<NSMutableDictionary> SessionData_;
static _H<NSObject> HostConfig_;
static _H<NSMutableSet> BridgedHosts_;
+static _H<NSMutableSet> TokenHosts_;
+static _H<NSMutableSet> InsecureHosts_;
static _H<NSMutableSet> PipelinedHosts_;
+static _H<NSMutableSet> CachedURLs_;
static NSString *kCydiaProgressEventTypeError = @"Error";
static NSString *kCydiaProgressEventTypeInformation = @"Information";
CYString uri_;
CYString distribution_;
CYString type_;
+ CYString base_;
CYString version_;
_H<NSString> host_;
- (NSString *) uri;
- (NSString *) distribution;
- (NSString *) type;
+
+- (NSString *) base;
+
- (NSString *) key;
- (NSString *) host;
distribution_.clear();
type_.clear();
+ base_.clear();
+
description_.clear();
label_.clear();
origin_.clear();
debReleaseIndex *dindex(dynamic_cast<debReleaseIndex *>(index));
if (dindex != NULL) {
+ base_.set(pool, dindex->MetaIndexURI(""));
+
FileFd fd;
if (!fd.Open(dindex->MetaIndexFile("Release"), FileFd::ReadOnly))
_error->Discard();
return type_;
}
+- (NSString *) base {
+ return base_;
+}
+
- (NSString *) key {
return [NSString stringWithFormat:@"%@:%@:%@", (NSString *) type_, (NSString *) uri_, (NSString *) distribution_];
}
apr_pool_t *pool_;
+ uint32_t rank_;
+
_transient Database *database_;
pkgCache::VerIterator version_;
- (NSString *) uri;
-- (Address *) maintainer;
+- (MIMEAddress *) maintainer;
- (size_t) size;
- (NSString *) longDescription;
- (NSString *) shortDescription;
- (UIImage *) icon;
- (NSString *) homepage;
- (NSString *) depiction;
-- (Address *) author;
+- (MIMEAddress *) author;
- (NSString *) support;
- (Source *) source;
-- (BOOL) matches:(NSString *)text;
+- (uint32_t) rank;
+- (BOOL) matches:(NSArray *)query;
- (bool) hasSupportingRole;
- (BOOL) hasTag:(NSString *)tag;
- (void) install;
- (void) remove;
-- (bool) isUnfilteredAndSearchedForBy:(NSString *)search;
+- (bool) isUnfilteredAndSearchedForBy:(NSArray *)query;
- (bool) isUnfilteredAndSelectedForBy:(NSString *)search;
- (bool) isInstalledAndUnfiltered:(NSNumber *)number;
- (bool) isVisibleInSection:(NSString *)section;
#endif
}
-- (Address *) maintainer {
+- (MIMEAddress *) maintainer {
@synchronized (database_) {
if ([database_ era] != era_ || file_.end())
return nil;
pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
const std::string &maintainer(parser->Maintainer());
- return maintainer.empty() ? nil : [Address addressWithString:[NSString stringWithUTF8String:maintainer.c_str()]];
+ return maintainer.empty() ? nil : [MIMEAddress addressWithString:[NSString stringWithUTF8String:maintainer.c_str()]];
} }
- (size_t) size {
return parsed_ != NULL && !parsed_->depiction_.empty() ? parsed_->depiction_ : [[self source] depictionForPackage:id_];
}
-- (Address *) sponsor {
- return parsed_ == NULL || parsed_->sponsor_.empty() ? nil : [Address addressWithString:parsed_->sponsor_];
+- (MIMEAddress *) sponsor {
+ return parsed_ == NULL || parsed_->sponsor_.empty() ? nil : [MIMEAddress addressWithString:parsed_->sponsor_];
}
-- (Address *) author {
- return parsed_ == NULL || parsed_->author_.empty() ? nil : [Address addressWithString:parsed_->author_];
+- (MIMEAddress *) author {
+ return parsed_ == NULL || parsed_->author_.empty() ? nil : [MIMEAddress addressWithString:parsed_->author_];
}
- (NSString *) support {
return source_ == (Source *) [NSNull null] ? nil : source_;
}
-- (BOOL) matches:(NSString *)text {
- if (text == nil)
+- (uint32_t) rank {
+ return rank_;
+}
+
+- (BOOL) matches:(NSArray *)query {
+ if (query == nil || [query count] == 0)
return NO;
+ rank_ = 0;
+
+ NSString *string;
NSRange range;
+ NSUInteger length;
- range = [[self id] rangeOfString:text options:MatchCompareOptions_];
- if (range.location != NSNotFound)
- return YES;
+ [self parse];
- range = [[self name] rangeOfString:text options:MatchCompareOptions_];
- if (range.location != NSNotFound)
- return YES;
+ string = [self id];
+ length = [string length];
- [self parse];
+ for (NSString *term in query) {
+ range = [string rangeOfString:term options:MatchCompareOptions_];
+ if (range.location != NSNotFound)
+ rank_ -= 10 * 100000 / length;
+ }
- NSString *description([self shortDescription]);
- NSUInteger length([description length]);
+ string = [self name];
- range = [[self shortDescription] rangeOfString:text options:MatchCompareOptions_ range:NSMakeRange(0, std::min<NSUInteger>(length, 100))];
- if (range.location != NSNotFound)
- return YES;
+ for (NSString *term in query) {
+ range = [string rangeOfString:term options:MatchCompareOptions_];
+ if (range.location != NSNotFound)
+ rank_ -= 6 * 100000 / length;
+ }
- return NO;
+ string = [self shortDescription];
+ length = [string length];
+ NSUInteger stop(std::min<NSUInteger>(length, 100));
+
+ for (NSString *term in query) {
+ range = [string rangeOfString:term options:MatchCompareOptions_ range:NSMakeRange(0, stop)];
+ if (range.location != NSNotFound)
+ rank_ -= 2 * 100000 / length;
+ }
+
+ return rank_ != 0;
}
- (bool) hasSupportingRole {
cache->MarkDelete(iterator_, true);
} }
-- (bool) isUnfilteredAndSearchedForBy:(NSString *)search {
+- (bool) isUnfilteredAndSearchedForBy:(NSArray *)query {
_profile(Package$isUnfilteredAndSearchedForBy)
bool value(true);
_end
_profile(Package$isUnfilteredAndSearchedForBy$Match)
- value &= [self matches:search];
+ value &= [self matches:query];
_end
return value;
/* }}} */
static NSString *Colon_;
-static NSString *Elision_;
+NSString *Elision_;
static NSString *Error_;
static NSString *Warning_;
if (false);
else if (selector == @selector(addBridgedHost:))
return @"addBridgedHost";
+ else if (selector == @selector(addInsecureHost:))
+ return @"addInsecureHost";
else if (selector == @selector(addInternalRedirect::))
return @"addInternalRedirect";
else if (selector == @selector(addPipelinedHost:scheme:))
return @"addPipelinedHost";
+ else if (selector == @selector(addTokenHost:))
+ return @"addTokenHost";
else if (selector == @selector(addTrivialSource:))
return @"addTrivialSource";
else if (selector == @selector(close))
return @"statfs";
else if (selector == @selector(supports:))
return @"supports";
+ else if (selector == @selector(unload))
+ return @"unload";
else
return nil;
}
return [feature isEqualToString:@"window.open"];
}
+- (void) unload {
+ [delegate_ performSelectorOnMainThread:@selector(unloadData) withObject:nil waitUntilDone:NO];
+}
+
- (void) addInternalRedirect:(NSString *)from :(NSString *)to {
[CydiaWebViewController performSelectorOnMainThread:@selector(addDiversion:) withObject:[[[Diversion alloc] initWithFrom:from to:to] autorelease] waitUntilDone:NO];
}
[BridgedHosts_ addObject:host];
} }
+- (void) addInsecureHost:(NSString *)host {
+@synchronized (HostConfig_) {
+ [InsecureHosts_ addObject:host];
+} }
+
+- (void) addTokenHost:(NSString *)host {
+@synchronized (HostConfig_) {
+ [TokenHosts_ addObject:host];
+} }
+
- (void) addPipelinedHost:(NSString *)host scheme:(NSString *)scheme {
@synchronized (HostConfig_) {
if (scheme != (id) [WebUndefined undefined])
@end
/* }}} */
-/* @ Loading... Indicator {{{ */
-@interface CYLoadingIndicator : UIView {
- _H<UIActivityIndicatorView> spinner_;
- _H<UILabel> label_;
- _H<UIView> container_;
-}
-
-@property (readonly, nonatomic) UILabel *label;
-@property (readonly, nonatomic) UIActivityIndicatorView *activityIndicatorView;
-
-@end
-
-@implementation CYLoadingIndicator
-
-- (id) initWithFrame:(CGRect)frame {
- if ((self = [super initWithFrame:frame]) != nil) {
- container_ = [[[UIView alloc] init] autorelease];
- [container_ setAutoresizingMask:UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin];
-
- spinner_ = [[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray] autorelease];
- [spinner_ startAnimating];
- [container_ addSubview:spinner_];
-
- label_ = [[[UILabel alloc] init] autorelease];
- [label_ setFont:[UIFont boldSystemFontOfSize:15.0f]];
- [label_ setBackgroundColor:[UIColor clearColor]];
- [label_ setTextColor:[UIColor blackColor]];
- [label_ setShadowColor:[UIColor whiteColor]];
- [label_ setShadowOffset:CGSizeMake(0, 1)];
- [label_ setText:[NSString stringWithFormat:Elision_, UCLocalize("LOADING"), nil]];
- [container_ addSubview:label_];
-
- CGSize viewsize = frame.size;
- CGSize spinnersize = [spinner_ bounds].size;
- CGSize textsize = [[label_ text] sizeWithFont:[label_ font]];
- float bothwidth = spinnersize.width + textsize.width + 5.0f;
-
- CGRect containrect = {
- CGPointMake(floorf((viewsize.width / 2) - (bothwidth / 2)), floorf((viewsize.height / 2) - (spinnersize.height / 2))),
- CGSizeMake(bothwidth, spinnersize.height)
- };
- CGRect textrect = {
- CGPointMake(spinnersize.width + 5.0f, floorf((spinnersize.height / 2) - (textsize.height / 2))),
- textsize
- };
- CGRect spinrect = {
- CGPointZero,
- spinnersize
- };
-
- [container_ setFrame:containrect];
- [spinner_ setFrame:spinrect];
- [label_ setFrame:textrect];
- [self addSubview:container_];
- } return self;
-}
-
-- (UILabel *) label {
- return label_;
-}
-
-- (UIActivityIndicatorView *) activityIndicatorView {
- return spinner_;
-}
-
-@end
-/* }}} */
-/* Emulated Loading Controller {{{ */
-@interface CYEmulatedLoadingController : CyteViewController {
- _transient Database *database_;
- _H<CYLoadingIndicator> indicator_;
- _H<UITabBar> tabbar_;
- _H<UINavigationBar> navbar_;
-}
-
+@interface NSURL (CydiaSecure)
@end
-@implementation CYEmulatedLoadingController
-
-- (id) initWithDatabase:(Database *)database {
- if ((self = [super init]) != nil) {
- database_ = database;
- } return self;
-}
+@implementation NSURL (CydiaSecure)
-- (void) loadView {
- [self setView:[[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease]];
-
- UITableView *table([[[UITableView alloc] initWithFrame:[[self view] bounds] style:UITableViewStyleGrouped] autorelease]);
- [table setAutoresizingMask:UIViewAutoresizingFlexibleBoth];
- [[self view] addSubview:table];
-
- indicator_ = [[[CYLoadingIndicator alloc] initWithFrame:[[self view] bounds]] autorelease];
- [indicator_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth];
- [[self view] addSubview:indicator_];
-
- tabbar_ = [[[UITabBar alloc] initWithFrame:CGRectMake(0, 0, 0, 49.0f)] autorelease];
- [tabbar_ setFrame:CGRectMake(0.0f, [[self view] bounds].size.height - [tabbar_ bounds].size.height, [[self view] bounds].size.width, [tabbar_ bounds].size.height)];
- [tabbar_ setAutoresizingMask:UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth];
- [[self view] addSubview:tabbar_];
+- (bool) isCydiaSecure {
+ if ([[[self scheme] lowercaseString] isEqualToString:@"https"])
+ return true;
- navbar_ = [[[UINavigationBar alloc] initWithFrame:CGRectMake(0, 0, 0, 44.0f)] autorelease];
- [navbar_ setFrame:CGRectMake(0.0f, 0.0f, [[self view] bounds].size.width, [navbar_ bounds].size.height)];
- [navbar_ setAutoresizingMask:UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleWidth];
- [[self view] addSubview:navbar_];
-}
+ @synchronized (HostConfig_) {
+ if ([InsecureHosts_ containsObject:[self host]])
+ return true;
+ }
-- (void) releaseSubviews {
- indicator_ = nil;
- tabbar_ = nil;
- navbar_ = nil;
+ return false;
}
@end
-/* }}} */
/* Cydia Browser Controller {{{ */
@implementation CydiaWebViewController
[window setValue:cydia_ forKey:@"cydia"];
}
+- (void) _setupMail:(MFMailComposeViewController *)controller {
+ [controller addAttachmentData:[NSData dataWithContentsOfFile:@"/tmp/cydia.log"] mimeType:@"text/plain" fileName:@"cydia.log"];
+
+ system("/usr/bin/dpkg -l >/tmp/dpkgl.log");
+ [controller addAttachmentData:[NSData dataWithContentsOfFile:@"/tmp/dpkgl.log"] mimeType:@"text/plain" fileName:@"dpkgl.log"];
+}
+
- (NSURL *) URLWithURL:(NSURL *)url {
return [Diversion divertURL:url];
}
- (NSURLRequest *) webView:(WebView *)view resource:(id)resource willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response fromDataSource:(WebDataSource *)source {
+ NSURL *url([request URL]);
+ NSString *host([url host]);
+
NSMutableURLRequest *copy([[super webView:view resource:resource willSendRequest:request redirectResponse:response fromDataSource:source] mutableCopy]);
- if (System_ != NULL)
+ if (System_ != NULL && [copy valueForHTTPHeaderField:@"X-System"] == nil)
[copy setValue:System_ forHTTPHeaderField:@"X-System"];
- if (Machine_ != NULL)
+ if (Machine_ != NULL && [copy valueForHTTPHeaderField:@"X-Machine"] == nil)
[copy setValue:[NSString stringWithUTF8String:Machine_] forHTTPHeaderField:@"X-Machine"];
- if (Token_ != nil)
- [copy setValue:Token_ forHTTPHeaderField:@"X-Cydia-Token"];
+
+ bool token;
+ @synchronized (HostConfig_) {
+ token = [TokenHosts_ containsObject:host] || [BridgedHosts_ containsObject:host];
+ }
+
+ if ([url isCydiaSecure] && token) {
+ if (Token_ != nil && [copy valueForHTTPHeaderField:@"X-Cydia-Token"] == nil)
+ [copy setValue:Token_ forHTTPHeaderField:@"X-Cydia-Token"];
+ }
return copy;
}
[cydia_ setDelegate:delegate];
}
-- (id) init {
- if ((self = [super initWithWidth:0 ofClass:[CydiaWebViewController class]]) != nil) {
- cydia_ = [[[CydiaObject alloc] initWithDelegate:indirect_] autorelease];
-
- WebView *webview([[webview_ _documentView] webView]);
+- (NSString *) applicationNameForUserAgent {
+ NSString *application([NSString stringWithFormat:@"Cydia/%@", @ Cydia_]);
- NSString *application([NSString stringWithFormat:@"Cydia/%@", @ Cydia_]);
+ if (Safari_ != nil)
+ application = [NSString stringWithFormat:@"Safari/%@ %@", Safari_, application];
+ if (Build_ != nil)
+ application = [NSString stringWithFormat:@"Mobile/%@ %@", Build_, application];
+ if (Product_ != nil)
+ application = [NSString stringWithFormat:@"Version/%@ %@", Product_, application];
- if (Safari_ != nil)
- application = [NSString stringWithFormat:@"Safari/%@ %@", Safari_, application];
- if (Build_ != nil)
- application = [NSString stringWithFormat:@"Mobile/%@ %@", Build_, application];
- if (Product_ != nil)
- application = [NSString stringWithFormat:@"Version/%@ %@", Product_, application];
+ return application;
+}
- [webview setApplicationNameForUserAgent:application];
+- (id) init {
+ if ((self = [super initWithWidth:0 ofClass:[CydiaWebViewController class]]) != nil) {
+ cydia_ = [[[CydiaObject alloc] initWithDelegate:indirect_] autorelease];
} return self;
}
/* }}} */
/* Package Cell {{{ */
-@interface PackageCell : CYTableViewCell <
+@interface PackageCell : CyteTableViewCell <
CyteTableViewCellDelegate
> {
_H<UIImage> icon_;
Source *source = [package source];
icon_ = [package icon];
- name_ = [package name];
- if (IsWildcat_)
- description_ = [package longDescription];
- if (description_ == nil)
- description_ = [package shortDescription];
+ if (NSString *name = [package name])
+ name_ = [NSString stringWithString:name];
+
+ NSString *description(nil);
+
+ if (description == nil && IsWildcat_)
+ description = [package longDescription];
+ if (description == nil)
+ description = [package shortDescription];
+
+ if (description != nil)
+ description_ = [NSString stringWithString:description];
commercial_ = [package isCommercial];
@end
/* }}} */
/* Section Cell {{{ */
-@interface SectionCell : CYTableViewCell <
+@interface SectionCell : CyteTableViewCell <
CyteTableViewCellDelegate
> {
_H<NSString> basic_;
- (void) releaseSubviews {
list_ = nil;
+
+ [super releaseSubviews];
}
- (id) initWithDatabase:(Database *)database {
return false;
}
+- (bool) showsSections {
+ return true;
+}
+
- (void) deselectWithAnimation:(BOOL)animated {
[list_ deselectRowAtIndexPath:[list_ indexPathForSelectedRow] animated:animated];
}
[self resizeForKeyboardBounds:bounds duration:0];
}
+- (void) getKeyboardCurve:(UIViewAnimationCurve *)curve duration:(NSTimeInterval *)duration forNotification:(NSNotification *)notification {
+ if (&UIKeyboardAnimationCurveUserInfoKey == NULL)
+ *curve = UIViewAnimationCurveEaseInOut;
+ else
+ [[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:curve];
+
+ if (&UIKeyboardAnimationDurationUserInfoKey == NULL)
+ *duration = 0.3;
+ else
+ [[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:duration];
+}
+
- (void) keyboardWillShow:(NSNotification *)notification {
CGRect bounds;
CGPoint center;
- NSTimeInterval duration;
- UIViewAnimationCurve curve;
[[[notification userInfo] objectForKey:UIKeyboardBoundsUserInfoKey] getValue:&bounds];
[[[notification userInfo] objectForKey:UIKeyboardCenterEndUserInfoKey] getValue:¢er];
- [[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&curve];
- [[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&duration];
+
+ NSTimeInterval duration;
+ UIViewAnimationCurve curve;
+ [self getKeyboardCurve:&curve duration:&duration forNotification:notification];
CGRect kbframe = CGRectMake(round(center.x - bounds.size.width / 2.0), round(center.y - bounds.size.height / 2.0), bounds.size.width, bounds.size.height);
UIViewController *base = self;
CGRect viewframe = [[base view] convertRect:[list_ frame] fromView:[list_ superview]];
CGRect intersection = CGRectIntersection(viewframe, kbframe);
+ if (kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber_iPhoneOS_3_0) // XXX: _UIApplicationLinkedOnOrAfter(4)
+ intersection.size.height += CYStatusBarHeight([self interfaceOrientation]);
+
[self resizeForKeyboardBounds:intersection duration:duration curve:curve];
}
- (void) keyboardWillHide:(NSNotification *)notification {
NSTimeInterval duration;
UIViewAnimationCurve curve;
- [[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&curve];
- [[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&duration];
+ [self getKeyboardCurve:&curve duration:&duration forNotification:notification];
[self resizeForKeyboardBounds:CGRectZero duration:duration curve:curve];
}
}
- (NSArray *) sectionIndexTitlesForTableView:(UITableView *)tableView {
- if ([self isSummarized])
+ if ([self showsSections])
return nil;
return index_;
packages_ = [NSArray array];
sections_ = [NSMutableArray arrayWithCapacity:16];
+ } return self;
+}
- list_ = [[[UITableView alloc] initWithFrame:[[self view] bounds] style:UITableViewStylePlain] autorelease];
- [list_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth];
- [[self view] addSubview:list_];
+- (void) loadView {
+ [self setView:[[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease]];
- // XXX: is 20 the most optimal number here?
- [list_ setSectionIndexMinimumDisplayRowCount:20];
+ list_ = [[[UITableView alloc] initWithFrame:[[self view] bounds] style:UITableViewStylePlain] autorelease];
+ [list_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth];
+ [[self view] addSubview:list_];
- [(UITableView *) list_ setDataSource:self];
- [list_ setDelegate:self];
+ // XXX: is 20 the most optimal number here?
+ [list_ setSectionIndexMinimumDisplayRowCount:20];
- [self updateHeight];
- } return self;
+ [(UITableView *) list_ setDataSource:self];
+ [list_ setDelegate:self];
+
+ [self updateHeight];
}
-- (void) setDelegate:(id)delegate {
- delegate_ = delegate;
+- (void) releaseSubviews {
+ list_ = nil;
+
+ [super releaseSubviews];
}
-- (bool) hasPackage:(Package *)package {
- return true;
+- (void) setDelegate:(id)delegate {
+ delegate_ = delegate;
}
- (bool) shouldYield {
return false;
}
-- (NSArray *) _reloadPackages:(NSArray *)packages {
- NSMutableArray *filtered([NSMutableArray arrayWithCapacity:[packages count]]);
-
- _profile(PackageTable$reloadData$Filter)
- for (Package *package in packages)
- if ([self hasPackage:package])
- [filtered addObject:package];
- _end
+- (NSMutableArray *) _reloadPackages {
+@synchronized (database_) {
+ era_ = [database_ era];
+ NSArray *packages([database_ packages]);
- return filtered;
-}
+ return [NSMutableArray arrayWithArray:packages];
+} }
- (void) _reloadData {
if (reloading_ != 0) {
return;
}
- era_ = [database_ era];
- NSArray *packages = [database_ packages];
+ NSArray *packages;
if ([self shouldYield]) {
- UIProgressHUD *hud;
+ do {
+ UIProgressHUD *hud;
- if (![self shouldBlock])
- hud = nil;
- else {
- hud = [delegate_ addProgressHUD];
- [hud setText:UCLocalize("LOADING")];
- }
+ if (![self shouldBlock])
+ hud = nil;
+ else {
+ hud = [delegate_ addProgressHUD];
+ [hud setText:UCLocalize("LOADING")];
+ }
- do {
reloading_ = 1;
- packages_ = [self yieldToSelector:@selector(_reloadPackages:) withObject:packages];
+ packages = [self yieldToSelector:@selector(_reloadPackages)];
+
+ if (hud != nil)
+ [delegate_ removeProgressHUD:hud];
} while (reloading_ == 2);
reloading_ = 0;
-
- if (hud != nil)
- [delegate_ removeProgressHUD:hud];
} else {
- packages_ = [self _reloadPackages:packages];
+ packages = [self _reloadPackages];
}
+ packages_ = packages;
+
[indices_ removeAllObjects];
[sections_ removeAllObjects];
{
[index_ removeAllObjects];
- bool summary([self isSummarized]);
- if (summary) {
+ bool sectioned([self showsSections]);
+ if (!sectioned) {
section = [[[Section alloc] initWithName:nil localize:false] autorelease];
[sections_ addObject:section];
}
index = [package index];
_end
- if (!summary && (section == nil || [section index] != index)) {
+ if (sectioned && (section == nil || [section index] != index)) {
_profile(PackageTable$reloadData$Section$Allocate)
section = [[[Section alloc] initWithIndex:index row:offset] autorelease];
_end
}
- (void) setFilter:(SEL)filter {
+@synchronized (self) {
filter_ = filter;
/* XXX: this is an unsafe optimization of doomy hell */
_assert(method != NULL);
imp_ = method_getImplementation(method);
_assert(imp_ != NULL);
-}
+} }
- (void) setObject:(id)object {
+@synchronized (self) {
object_ = object;
-}
+} }
- (void) setObject:(id)object forFilter:(SEL)filter {
+@synchronized (self) {
[self setFilter:filter];
[self setObject:object];
-}
+} }
+
+- (NSMutableArray *) _reloadPackages {
+@synchronized (database_) {
+ era_ = [database_ era];
+ NSArray *packages([database_ packages]);
+
+ NSMutableArray *filtered([NSMutableArray arrayWithCapacity:[packages count]]);
+
+ IMP imp;
+ SEL filter;
+ _H<NSObject> object;
-- (bool) hasPackage:(Package *)package {
- _profile(FilteredPackageTable$hasPackage)
- return [package valid] && (*reinterpret_cast<bool (*)(id, SEL, id)>(imp_))(package, filter_, object_);
+ @synchronized (self) {
+ imp = imp_;
+ filter = filter_;
+ object = object_;
+ }
+
+ _profile(PackageTable$reloadData$Filter)
+ for (Package *package in packages)
+ if ([package valid] && (*reinterpret_cast<bool (*)(id, SEL, id)>(imp))(package, filter, object))
+ [filtered addObject:package];
_end
-}
+
+ return filtered;
+} }
- (id) initWithDatabase:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object {
if ((self = [super initWithDatabase:database title:title]) != nil) {
] autorelease];
}
-- (void) unloadData {
- [super unloadData];
- [self reloadData];
-}
-
@end
/* }}} */
/* Manage Controller {{{ */
}
- (void) unloadData {
- UIViewController *selected([self selectedViewController]);
+ [super unloadData];
+
for (UINavigationController *controller in [self viewControllers])
[controller unloadData];
- [selected reloadData];
+ if (UIViewController *selected = [self selectedViewController])
+ [selected reloadData];
- if (UIViewController *unselected = [self unselectedViewController])
+ if (UIViewController *unselected = [self unselectedViewController]) {
+ [unselected unloadData];
[unselected reloadData];
-
- [super unloadData];
+ }
}
- (void) dealloc {
updatedelegate_ = delegate;
}
-- (CGFloat) statusBarHeight {
- if (UIInterfaceOrientationIsPortrait([self interfaceOrientation])) {
- return [[UIApplication sharedApplication] statusBarFrame].size.height;
- } else {
- return [[UIApplication sharedApplication] statusBarFrame].size.width;
- }
-}
-
- (UIView *) transitionView {
if ([self respondsToSelector:@selector(_transitionView)])
return [self _transitionView];
CGRect barframe([refreshbar_ frame]);
if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iPhoneOS_3_0) // XXX: _UIApplicationLinkedOnOrAfter(4)
- barframe.origin.y = [self statusBarHeight];
+ barframe.origin.y = CYStatusBarHeight([self interfaceOrientation]);
else
barframe.origin.y = 0;
- (void) releaseSubviews {
list_ = nil;
+
+ [super releaseSubviews];
}
- (id) initWithDatabase:(Database *)database {
- (void) releaseSubviews {
list_ = nil;
+
+ [super releaseSubviews];
}
- (id) initWithDatabase:(Database *)database {
} return self;
}
-- (NSArray *) _reloadPackages:(NSArray *)packages {
+- (NSMutableArray *) _reloadPackages {
+@synchronized (database_) {
+ era_ = [database_ era];
+ NSArray *packages([database_ packages]);
+
NSMutableArray *filtered([NSMutableArray arrayWithCapacity:[packages count]]);
_trace();
_trace();
return filtered;
-}
+} }
- (void) _reloadData {
-@synchronized (database_) {
- era_ = [database_ era];
- NSArray *packages = [database_ packages];
+ NSArray *packages;
+
+ reload:
+ if (true) {
+ UIProgressHUD *hud([delegate_ addProgressHUD]);
+ [hud setText:UCLocalize("LOADING")];
+ //NSLog(@"HUD:%@::%@", delegate_, hud);
+ packages = [self yieldToSelector:@selector(_reloadPackages)];
+ [delegate_ removeProgressHUD:hud];
+ } else {
+ packages = [self _reloadPackages];
+ }
-#if 1
- UIProgressHUD *hud([delegate_ addProgressHUD]);
- [hud setText:UCLocalize("LOADING")];
- //NSLog(@"HUD:%@::%@", delegate_, hud);
- packages_ = [self yieldToSelector:@selector(_reloadPackages:) withObject:packages];
- [delegate_ removeProgressHUD:hud];
-#else
- packages_ = [self _reloadPackages:packages];
-#endif
+@synchronized (database_) {
+ if (era_ != [database_ era])
+ goto reload;
+ packages_ = packages;
[sections_ removeAllObjects];
Section *upgradable = [[[Section alloc] initWithName:UCLocalize("AVAILABLE_UPGRADES") localize:NO] autorelease];
}
- (void) useSearch {
- [self setObject:[search_ text] forFilter:@selector(isUnfilteredAndSearchedForBy:)];
+ [self setObject:[[search_ text] componentsSeparatedByString:@" "] forFilter:@selector(isUnfilteredAndSearchedForBy:)];
[self clearData];
[self reloadData];
}
return [self filter] == @selector(isUnfilteredAndSelectedForBy:);
}
+- (bool) showsSections {
+ return false;
+}
+
+- (NSMutableArray *) _reloadPackages {
+ NSMutableArray *packages([super _reloadPackages]);
+ if ([self filter] == @selector(isUnfilteredAndSearchedForBy:))
+ [packages radixSortUsingSelector:@selector(rank)];
+ return packages;
+}
+
- (id) initWithDatabase:(Database *)database query:(NSString *)query {
- if ((self = [super initWithDatabase:database title:UCLocalize("SEARCH") filter:@selector(isUnfilteredAndSearchedForBy:) with:query])) {
+ if ((self = [super initWithDatabase:database title:UCLocalize("SEARCH") filter:@selector(isUnfilteredAndSearchedForBy:) with:[query componentsSeparatedByString:@" "]])) {
search_ = [[[UISearchBar alloc] init] autorelease];
[search_ setDelegate:self];
}
- (void) reloadData {
- [self setObject:[search_ text]];
+ id object([search_ text]);
+ if ([self filter] == @selector(isUnfilteredAndSearchedForBy:))
+ object = [object componentsSeparatedByString:@" "];
+
+ [self setObject:object];
[self resetCursor];
[super reloadData];
table_ = nil;
ignoredSwitch_ = nil;
subscribedSwitch_ = nil;
+
+ [super releaseSubviews];
}
- (id) initWithDatabase:(Database *)database package:(NSString *)package {
/* }}} */
/* Source Cell {{{ */
-@interface SourceCell : CYTableViewCell <
+@interface SourceCell : CyteTableViewCell <
CyteTableViewCellDelegate
> {
_H<UIImage> icon_;
@implementation SourceCell
+- (void) _setImage:(UIImage *)image {
+ icon_ = image;
+ [content_ setNeedsDisplay];
+}
+
+- (void) _setSource:(Source *)source {
+ NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
+
+ if (NSString *base = [source base])
+ if ([base length] != 0) {
+ NSURL *url([NSURL URLWithString:[base stringByAppendingString:@"CydiaIcon.png"]]);
+
+ if (NSData *data = [NSURLConnection
+ sendSynchronousRequest:[NSURLRequest
+ requestWithURL:url
+ //cachePolicy:NSURLRequestUseProtocolCachePolicy
+ //timeoutInterval:5
+ ]
+
+ returningResponse:NULL
+ error:NULL
+ ])
+ if (UIImage *image = [UIImage imageWithData:data])
+ [self performSelectorOnMainThread:@selector(_setImage:) withObject:image waitUntilDone:NO];
+ }
+
+ [pool release];
+}
+
- (void) setSource:(Source *)source {
- icon_ = nil;
- if (icon_ == nil)
- icon_ = [UIImage applicationImageNamed:[NSString stringWithFormat:@"Sources/%@.png", [source host]]];
- if (icon_ == nil)
- icon_ = [UIImage applicationImageNamed:@"unknown.png"];
+ icon_ = [UIImage applicationImageNamed:@"unknown.png"];
origin_ = [source name];
label_ = [source uri];
[content_ setNeedsDisplay];
+
+ [NSThread detachNewThreadSelector:@selector(_setSource:) toTarget:self withObject:source];
}
- (SourceCell *) initWithFrame:(CGRect)frame reuseIdentifier:(NSString *)reuseIdentifier {
}
- (NSURLConnection *) _requestHRef:(NSString *)href method:(NSString *)method {
+ NSURL *url([NSURL URLWithString:href]);
+
NSMutableURLRequest *request = [NSMutableURLRequest
- requestWithURL:[NSURL URLWithString:href]
+ requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:120.0
];
if (Machine_ != NULL)
[request setValue:[NSString stringWithUTF8String:Machine_] forHTTPHeaderField:@"X-Machine"];
- if (UniqueID_ != nil)
- [request setValue:UniqueID_ forHTTPHeaderField:@"X-Unique-ID"];
+
+ if ([url isCydiaSecure]) {
+ if (UniqueID_ != nil)
+ [request setValue:UniqueID_ forHTTPHeaderField:@"X-Unique-ID"];
+ }
return [[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease];
}
- (void) releaseSubviews {
list_ = nil;
+
+ [super releaseSubviews];
}
- (id) initWithDatabase:(Database *)database {
table_ = nil;
segment_ = nil;
container_ = nil;
+
+ [super releaseSubviews];
}
- (id) initWithDatabase:(Database *)database delegate:(id)delegate {
[[self view] addSubview:status_];
}
+- (void) releaseSubviews {
+ spinner_ = nil;
+ status_ = nil;
+ caption_ = nil;
+
+ [super releaseSubviews];
+}
+
@end
/* }}} */
#endif
}
+- (void) storeCachedResponse:(NSCachedURLResponse *)cached forRequest:(NSURLRequest *)request {
+ if (NSURLResponse *response = [cached response])
+ if (NSString *mime = [response MIMEType])
+ if ([mime isEqualToString:@"text/cache-manifest"]) {
+ NSURL *url([response URL]);
+
+#if !ForRelease
+ NSLog(@"###: %@", [url absoluteString]);
+#endif
+
+ @synchronized (HostConfig_) {
+ [CachedURLs_ addObject:url];
+ }
+ }
+
+ [super storeCachedResponse:cached forRequest:request];
+}
+
@end
@interface Cydia : UIApplication <
> {
_H<UIWindow> window_;
_H<CYTabBarController> tabbar_;
- _H<CYEmulatedLoadingController> emulated_;
+ _H<CydiaLoadingViewController> emulated_;
_H<NSMutableArray> essential_;
_H<NSMutableArray> broken_;
[NSThread detachNewThreadSelector:@selector(_refreshIfPossible:) toTarget:self withObject:[Metadata_ objectForKey:@"LastUpdate"]];
}
-- (void) _reloadDataWithInvocation:(NSInvocation *)invocation {
+- (void) reloadDataWithInvocation:(NSInvocation *)invocation {
+@synchronized (self) {
UIProgressHUD *hud(loaded_ ? [self addProgressHUD] : nil);
[hud setText:UCLocalize("RELOADING_DATA")];
}
}
- NSLog(@"changes:#%u", changes);
-
UITabBarItem *changesItem = [[[tabbar_ viewControllers] objectAtIndex:2] tabBarItem];
if (changes != 0) {
_trace();
[self _updateData];
[self refreshIfPossible];
-}
+} }
- (void) updateData {
[self _updateData];
- (void) update_ {
[database_ update];
-}
-
-- (void) complete {
- @synchronized (self) {
- [self _reloadDataWithInvocation:nil];
- }
+ [self performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:YES];
}
- (void) disemulate {
[self performSelectorOnMainThread:@selector(repairWithInvocation:) withObject:[NSInvocation invocationWithSelector:selector forTarget:database_] waitUntilDone:YES];
}
+- (void) reloadData {
+ [self reloadDataWithInvocation:nil];
+}
+
- (void) syncData {
[self _saveConfig];
fclose(file);
[self detachNewProgressSelector:@selector(update_) toTarget:self forController:nil title:@"UPDATING_SOURCES"];
-
- [self complete];
}
- (void) addTrivialSource:(NSString *)href {
Changed_ = true;
}
-- (void) reloadDataWithInvocation:(NSInvocation *)invocation {
- @synchronized (self) {
- [self _reloadDataWithInvocation:invocation];
- }
-}
-
-- (void) reloadData {
- [self reloadDataWithInvocation:nil];
-}
-
- (void) resolve {
pkgProblemResolver *resolver = [database_ resolver];
}
}
+- (void) perform_ {
+ [database_ perform];
+ [self performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:YES];
+}
+
- (void) confirmWithNavigationController:(UINavigationController *)navigation {
Queuing_ = false;
++locked_;
- [self detachNewProgressSelector:@selector(perform) toTarget:database_ forController:navigation title:@"RUNNING"];
+ [self detachNewProgressSelector:@selector(perform_) toTarget:self forController:navigation title:@"RUNNING"];
--locked_;
- [self complete];
}
- (void) showSettings {
[window_ setUserInteractionEnabled:NO];
[self setupViewControllers];
- emulated_ = [[[CYEmulatedLoadingController alloc] initWithDatabase:database_] autorelease];
+ emulated_ = [[[CydiaLoadingViewController alloc] init] autorelease];
[window_ addSubview:[emulated_ view]];
[self performSelector:@selector(loadData) withObject:nil afterDelay:0];
NSMutableURLRequest *copy([request mutableCopy]);
NSURL *url([copy URL]);
+
+ NSString *href([url absoluteString]);
NSString *host([url host]);
NSString *scheme([[url scheme] lowercaseString]);
if ([copy respondsToSelector:@selector(setHTTPShouldUsePipelining:)])
if ([PipelinedHosts_ containsObject:host] || [PipelinedHosts_ containsObject:compound])
[copy setHTTPShouldUsePipelining:YES];
+
+ if (NSString *control = [copy valueForHTTPHeaderField:@"Cache-Control"])
+ if ([control isEqualToString:@"max-age=0"])
+ if ([CachedURLs_ containsObject:href]) {
+#if !ForRelease
+ NSLog(@"~~~: %@", href);
+#endif
+
+ [copy setCachePolicy:NSURLRequestReturnCacheDataDontLoad];
+
+ [copy setValue:nil forHTTPHeaderField:@"Cache-Control"];
+ [copy setValue:nil forHTTPHeaderField:@"If-Modified-Since"];
+ [copy setValue:nil forHTTPHeaderField:@"If-None-Match"];
+ }
}
if ((self = _NSURLConnection$init$(self, _cmd, copy, delegate, usesCache, maxContentLength, startImmediately, connectionProperties)) != nil) {
HostConfig_ = [[[NSObject alloc] init] autorelease];
@synchronized (HostConfig_) {
BridgedHosts_ = [NSMutableSet setWithCapacity:4];
+ TokenHosts_ = [NSMutableSet setWithCapacity:4];
+ InsecureHosts_ = [NSMutableSet setWithCapacity:4];
PipelinedHosts_ = [NSMutableSet setWithCapacity:4];
+ CachedURLs_ = [NSMutableSet setWithCapacity:32];
}
UI_ = CydiaURL([NSString stringWithFormat:@"ui/ios~%@", Idiom_]);