/* #include Directives {{{ */
#import "UICaboodle.h"
+#include <objc/message.h>
#include <objc/objc.h>
#include <objc/runtime.h>
// XXX: remove
#import <MessageUI/MailComposeController.h>
+#include <iomanip>
#include <sstream>
#include <string>
exit(0); \
} while (false)
-static uint64_t profile_;
-
#define _timestamp ({ \
struct timeval tv; \
gettimeofday(&tv, NULL); \
tv.tv_sec * 1000000 + tv.tv_usec; \
})
+typedef std::vector<class ProfileTime *> TimeList;
+TimeList times_;
+
+class ProfileTime {
+ private:
+ const char *name_;
+ uint64_t total_;
+ uint64_t count_;
+
+ public:
+ ProfileTime(const char *name) :
+ name_(name),
+ total_(0)
+ {
+ times_.push_back(this);
+ }
+
+ void AddTime(uint64_t time) {
+ total_ += time;
+ ++count_;
+ }
+
+ void Print() {
+ if (total_ != 0)
+ std::cerr << std::setw(5) << count_ << ", " << std::setw(7) << total_ << " : " << name_ << std::endl;
+ total_ = 0;
+ count_ = 0;
+ }
+};
+
+class ProfileTimer {
+ private:
+ ProfileTime &time_;
+ uint64_t start_;
+
+ public:
+ ProfileTimer(ProfileTime &time) :
+ time_(time),
+ start_(_timestamp)
+ {
+ }
+
+ ~ProfileTimer() {
+ time_.AddTime(_timestamp - start_);
+ }
+};
+
+void PrintTimes() {
+ for (TimeList::const_iterator i(times_.begin()); i != times_.end(); ++i)
+ (*i)->Print();
+ std::cerr << "========" << std::endl;
+}
+
+#define _profile(name) { \
+ static ProfileTime name(#name); \
+ ProfileTimer _ ## name(name);
+
+#define _end }
+
/* Objective-C Handle<> {{{ */
template <typename Type_>
class _H {
NSLog(@"%s(%g,%g)+(%g,%g)", fix, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
}
+@interface NSObject (Cydia)
+- (id) yieldToSelector:(SEL)selector withObject:(id)object;
+- (id) yieldToSelector:(SEL)selector;
+@end
+
+@implementation NSObject (Cydia)
+
+- (void) doNothing {
+}
+
+- (void) _yieldToContext:(NSMutableArray *)context { _pooled
+ SEL selector(reinterpret_cast<SEL>([[context objectAtIndex:0] pointerValue]));
+ id object([[context objectAtIndex:1] nonretainedObjectValue]);
+ volatile bool &stopped(*reinterpret_cast<bool *>([[context objectAtIndex:2] pointerValue]));
+
+ /* XXX: deal with exceptions */
+ id value([self performSelector:selector withObject:object]);
+
+ [context removeAllObjects];
+ if (value != nil)
+ [context addObject:value];
+
+ stopped = true;
+
+ [self
+ performSelectorOnMainThread:@selector(doNothing)
+ withObject:nil
+ waitUntilDone:NO
+ ];
+}
+
+- (id) yieldToSelector:(SEL)selector withObject:(id)object {
+ /*return [self performSelector:selector withObject:object];*/
+
+ volatile bool stopped(false);
+
+ NSMutableArray *context([NSMutableArray arrayWithObjects:
+ [NSValue valueWithPointer:selector],
+ [NSValue valueWithNonretainedObject:object],
+ [NSValue valueWithPointer:const_cast<bool *>(&stopped)],
+ nil]);
+
+ NSThread *thread([[[NSThread alloc]
+ initWithTarget:self
+ selector:@selector(_yieldToContext:)
+ object:context
+ ] autorelease]);
+
+ [thread start];
+
+ NSRunLoop *loop([NSRunLoop currentRunLoop]);
+ NSDate *future([NSDate distantFuture]);
+
+ while (!stopped && [loop runMode:NSDefaultRunLoopMode beforeDate:future]);
+
+ return [context count] == 0 ? nil : [context objectAtIndex:0];
+}
+
+- (id) yieldToSelector:(SEL)selector {
+ return [self yieldToSelector:selector withObject:nil];
+}
+
+@end
+
/* NSForcedOrderingSearch doesn't work on the iPhone */
+static const NSStringCompareOptions MatchCompareOptions_ = NSLiteralSearch | NSCaseInsensitiveSearch;
static const NSStringCompareOptions BaseCompareOptions_ = NSNumericSearch | NSDiacriticInsensitiveSearch | NSWidthInsensitiveSearch;
static const NSStringCompareOptions ForcedCompareOptions_ = BaseCompareOptions_;
static const NSStringCompareOptions LaxCompareOptions_ = BaseCompareOptions_ | NSCaseInsensitiveSearch;
@implementation PopTransitionView
-- (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
+- (void) transitionViewDidComplete:(UITransitionView *)view fromView:(UIView *)from toView:(UIView *)to {
if (from != nil && to == nil)
[self removeFromSuperview];
}
@end
-@interface UIView (PopUpView)
-- (void) popFromSuperviewAnimated:(BOOL)animated;
-- (void) popSubview:(UIView *)view;
-@end
-
@implementation UIView (PopUpView)
- (void) popFromSuperviewAnimated:(BOOL)animated {
#define lprintf(args...) fprintf(stderr, args)
-#define ForRelease 0
-#define ForSaurik (1 && !ForRelease)
+#define ForRelease 1
+#define ForSaurik (0 && !ForRelease)
+#define LogBrowser (1 && !ForRelease)
+#define ManualRefresh (1 && !ForRelease)
+#define ShowInternals (1 && !ForRelease)
#define IgnoreInstall (0 && !ForRelease)
#define RecycleWebViews 0
-#define AlwaysReload (1 && !ForRelease)
+#define AlwaysReload (0 && !ForRelease)
+
+#if ForRelease
+#undef _trace
+#define _trace(args...)
+#undef _profile
+#define _profile(name) {
+#undef _end
+#define _end }
+#define PrintTimes() do {} while (false)
+#endif
/* Radix Sort {{{ */
@interface NSMutableArray (Radix)
@end
@interface NSString (Cydia)
++ (NSString *) stringWithUTF8BytesNoCopy:(const char *)bytes length:(int)length;
+ (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length;
- (NSComparisonResult) compareByPath:(NSString *)other;
+- (NSString *) stringByCachingURLWithCurrentCDN;
+- (NSString *) stringByAddingPercentEscapesIncludingReserved;
@end
@implementation NSString (Cydia)
++ (NSString *) stringWithUTF8BytesNoCopy:(const char *)bytes length:(int)length {
+ return [[[NSString alloc] initWithBytesNoCopy:const_cast<char *>(bytes) length:length encoding:NSUTF8StringEncoding freeWhenDone:NO] autorelease];
+}
+
+ (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length {
return [[[NSString alloc] initWithBytes:bytes length:length encoding:NSUTF8StringEncoding] autorelease];
}
return result == NSOrderedSame ? value : result;
}
+- (NSString *) stringByCachingURLWithCurrentCDN {
+ return [self
+ stringByReplacingOccurrencesOfString:@"://"
+ withString:@"://ne.edgecastcdn.net/8003A4/"
+ options:0
+ /* XXX: this is somewhat inaccurate */
+ range:NSMakeRange(0, 10)
+ ];
+}
+
+- (NSString *) stringByAddingPercentEscapesIncludingReserved {
+ return [(id)CFURLCreateStringByAddingPercentEscapes(
+ kCFAllocatorDefault,
+ (CFStringRef) self,
+ NULL,
+ CFSTR(";/?:@&=+$,"),
+ kCFStringEncodingUTF8
+ ) autorelease];
+}
+
@end
/* Perl-Compatible RegEx {{{ */
- (NSString *) name;
- (NSString *) address;
+- (void) setAddress:(NSString *)address;
+
+ (Address *) addressWithString:(NSString *)string;
- (Address *) initWithString:(NSString *)string;
@end
return address_;
}
+- (void) setAddress:(NSString *)address {
+ if (address_ != nil)
+ [address_ autorelease];
+ if (address == nil)
+ address_ = nil;
+ else
+ address_ = [address retain];
+}
+
+ (Address *) addressWithString:(NSString *)string {
return [[[Address alloc] initWithString:string] autorelease];
}
#define SandboxTemplate_ "/usr/share/sandbox/SandboxTemplate.sb"
#define NotifyConfig_ "/etc/notify.conf"
+static bool Queuing_;
+
static CGColor Blue_;
static CGColor Blueish_;
static CGColor Black_;
static CGColor Off_;
static CGColor White_;
static CGColor Gray_;
+static CGColor Green_;
+static CGColor Purple_;
+static CGColor Purplish_;
+
+static UIColor *InstallingColor_;
+static UIColor *RemovingColor_;
static NSString *App_;
static NSString *Home_;
static BOOL Sounds_Keyboard_;
static BOOL Advanced_;
-#if !ForSaurik
static BOOL Loaded_;
-#endif
static BOOL Ignored_;
static UIFont *Font12_;
static const char *Machine_ = NULL;
static const NSString *UniqueID_ = nil;
static const NSString *Build_ = nil;
+static const NSString *Product_ = nil;
+static const NSString *Safari_ = nil;
CFLocaleRef Locale_;
CGColorSpaceRef space_;
static NSDictionary *SectionMap_;
static NSMutableDictionary *Metadata_;
-static NSMutableDictionary *Indices_;
static _transient NSMutableDictionary *Settings_;
static _transient NSString *Role_;
static _transient NSMutableDictionary *Packages_;
@end
@protocol CydiaDelegate
+- (void) clearPackage:(Package *)package;
- (void) installPackage:(Package *)package;
- (void) removePackage:(Package *)package;
- (void) slideUp:(UIActionSheet *)alert;
- (void) syncData;
- (void) askForSettings;
- (UIProgressHUD *) addProgressHUD;
+- (void) removeProgressHUD:(UIProgressHUD *)hud;
- (RVPage *) pageForURL:(NSURL *)url hasTag:(int *)tag;
- (RVPage *) pageForPackage:(NSString *)name;
- (void) openMailToURL:(NSURL *)url;
protected:
virtual void Update() {
- [delegate_ setProgressTitle:[NSString stringWithUTF8String:Op.c_str()]];
- [delegate_ setProgressPercent:(Percent / 100)];
+ /*[delegate_ setProgressTitle:[NSString stringWithUTF8String:Op.c_str()]];
+ [delegate_ setProgressPercent:(Percent / 100)];*/
}
public:
}
virtual void Done() {
- [delegate_ setProgressPercent:1];
+ //[delegate_ setProgressPercent:1];
}
};
/* }}} */
/* Database Interface {{{ */
@interface Database : NSObject {
+ unsigned era_;
+
pkgCacheFile cache_;
pkgDepCache::Policy *policy_;
pkgRecords *records_;
}
+ (Database *) sharedInstance;
+- (unsigned) era;
- (void) _readCydia:(NSNumber *)fd;
- (void) _readStatus:(NSNumber *)fd;
- (pkgRecords *) records;
- (pkgProblemResolver *) resolver;
- (pkgAcquire &) fetcher;
+- (pkgSourceList &) list;
- (NSArray *) packages;
- (NSArray *) sources;
- (void) reloadData;
NSString *description_;
NSString *label_;
NSString *origin_;
+ NSString *support_;
NSString *uri_;
NSString *distribution_;
- (NSComparisonResult) compareByNameAndType:(Source *)source;
+- (NSString *) supportForPackage:(NSString *)package;
+
- (NSDictionary *) record;
- (BOOL) trusted;
@implementation Source
-- (void) dealloc {
- [uri_ release];
- [distribution_ release];
- [type_ release];
+#define _clear(field) \
+ if (field != nil) \
+ [field release]; \
+ field = nil;
- if (description_ != nil)
- [description_ release];
- if (label_ != nil)
- [label_ release];
- if (origin_ != nil)
- [origin_ release];
- if (version_ != nil)
- [version_ release];
- if (defaultIcon_ != nil)
- [defaultIcon_ release];
- if (record_ != nil)
- [record_ release];
+- (void) _clear {
+ _clear(uri_)
+ _clear(distribution_)
+ _clear(type_)
+
+ _clear(description_)
+ _clear(label_)
+ _clear(origin_)
+ _clear(support_)
+ _clear(version_)
+ _clear(defaultIcon_)
+ _clear(record_)
+}
+- (void) dealloc {
+ [self _clear];
[super dealloc];
}
return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name];
}
-- (Source *) initWithMetaIndex:(metaIndex *)index {
- if ((self = [super init]) != nil) {
- trusted_ = index->IsTrusted();
-
- uri_ = [[NSString stringWithUTF8String:index->GetURI().c_str()] retain];
- distribution_ = [[NSString stringWithUTF8String:index->GetDist().c_str()] retain];
- type_ = [[NSString stringWithUTF8String:index->GetType()] retain];
-
- debReleaseIndex *dindex(dynamic_cast<debReleaseIndex *>(index));
- if (dindex != NULL) {
- std::ifstream release(dindex->MetaIndexFile("Release").c_str());
- std::string line;
- while (std::getline(release, line)) {
- std::string::size_type colon(line.find(':'));
- if (colon == std::string::npos)
- continue;
+- (void) setMetaIndex:(metaIndex *)index {
+ [self _clear];
- std::string name(line.substr(0, colon));
- std::string value(line.substr(colon + 1));
- while (!value.empty() && value[0] == ' ')
- value = value.substr(1);
-
- if (name == "Default-Icon")
- defaultIcon_ = [[NSString stringWithUTF8String:value.c_str()] retain];
- else if (name == "Description")
- description_ = [[NSString stringWithUTF8String:value.c_str()] retain];
- else if (name == "Label")
- label_ = [[NSString stringWithUTF8String:value.c_str()] retain];
- else if (name == "Origin")
- origin_ = [[NSString stringWithUTF8String:value.c_str()] retain];
- else if (name == "Version")
- version_ = [[NSString stringWithUTF8String:value.c_str()] retain];
- }
+ trusted_ = index->IsTrusted();
+
+ uri_ = [[NSString stringWithUTF8String:index->GetURI().c_str()] retain];
+ distribution_ = [[NSString stringWithUTF8String:index->GetDist().c_str()] retain];
+ type_ = [[NSString stringWithUTF8String:index->GetType()] retain];
+
+ debReleaseIndex *dindex(dynamic_cast<debReleaseIndex *>(index));
+ if (dindex != NULL) {
+ std::ifstream release(dindex->MetaIndexFile("Release").c_str());
+ std::string line;
+ while (std::getline(release, line)) {
+ std::string::size_type colon(line.find(':'));
+ if (colon == std::string::npos)
+ continue;
+
+ std::string name(line.substr(0, colon));
+ std::string value(line.substr(colon + 1));
+ while (!value.empty() && value[0] == ' ')
+ value = value.substr(1);
+
+ if (name == "Default-Icon")
+ defaultIcon_ = [[NSString stringWithUTF8String:value.c_str()] retain];
+ else if (name == "Description")
+ description_ = [[NSString stringWithUTF8String:value.c_str()] retain];
+ else if (name == "Label")
+ label_ = [[NSString stringWithUTF8String:value.c_str()] retain];
+ else if (name == "Origin")
+ origin_ = [[NSString stringWithUTF8String:value.c_str()] retain];
+ else if (name == "Support")
+ support_ = [[NSString stringWithUTF8String:value.c_str()] retain];
+ else if (name == "Version")
+ version_ = [[NSString stringWithUTF8String:value.c_str()] retain];
}
+ }
- record_ = [Sources_ objectForKey:[self key]];
- if (record_ != nil)
- record_ = [record_ retain];
+ record_ = [Sources_ objectForKey:[self key]];
+ if (record_ != nil)
+ record_ = [record_ retain];
+}
+
+- (Source *) initWithMetaIndex:(metaIndex *)index {
+ if ((self = [super init]) != nil) {
+ [self setMetaIndex:index];
} return self;
}
return [lhs compare:rhs options:LaxCompareOptions_];
}
+- (NSString *) supportForPackage:(NSString *)package {
+ return support_ == nil ? nil : [support_ stringByReplacingOccurrencesOfString:@"*" withString:package];
+}
+
- (NSDictionary *) record {
return record_;
}
/* }}} */
/* Package Class {{{ */
@interface Package : NSObject {
+ unsigned era_;
+
pkgCache::PkgIterator iterator_;
_transient Database *database_;
pkgCache::VerIterator version_;
bool cached_;
NSString *section_;
+ bool essential_;
NSString *latest_;
NSString *installed_;
NSString *homepage_;
Address *sponsor_;
Address *author_;
+ NSString *support_;
NSArray *tags_;
NSString *role_;
- (NSString *) section;
- (NSString *) simpleSection;
+- (NSString *) uri;
+
- (Address *) maintainer;
- (size_t) size;
- (NSString *) description;
-- (NSString *) index;
+- (unichar) index;
- (NSMutableDictionary *) metadata;
- (NSDate *) seen;
- (NSString *) depiction;
- (Address *) author;
+- (NSString *) support;
+
- (NSArray *) files;
- (NSArray *) relationships;
- (NSArray *) warnings;
- (Source *) source;
- (NSString *) role;
-- (NSString *) rating;
- (BOOL) matches:(NSString *)text;
- (BOOL) hasTag:(NSString *)tag;
- (NSString *) primaryPurpose;
- (NSArray *) purposes;
+- (bool) isCommercial;
- (NSComparisonResult) compareByName:(Package *)package;
- (NSComparisonResult) compareBySection:(Package *)package;
- (void) install;
- (void) remove;
-- (NSNumber *) isUnfilteredAndSearchedForBy:(NSString *)search;
-- (NSNumber *) isInstalledAndVisible:(NSNumber *)number;
-- (NSNumber *) isVisiblyUninstalledInSection:(NSString *)section;
-- (NSNumber *) isVisibleInSource:(Source *)source;
+- (bool) isUnfilteredAndSearchedForBy:(NSString *)search;
+- (bool) isInstalledAndVisible:(NSNumber *)number;
+- (bool) isVisiblyUninstalledInSection:(NSString *)section;
+- (bool) isVisibleInSource:(Source *)source;
@end
- (void) dealloc {
if (source_ != nil)
[source_ release];
-
if (section_ != nil)
[section_ release];
[sponsor_ release];
if (author_ != nil)
[author_ release];
+ if (support_ != nil)
+ [support_ release];
if (tags_ != nil)
[tags_ release];
if (role_ != nil)
[super dealloc];
}
++ (NSString *) webScriptNameForSelector:(SEL)selector {
+ if (selector == @selector(hasTag:))
+ return @"hasTag";
+ else
+ return nil;
+}
+
++ (BOOL) isSelectorExcludedFromWebScript:(SEL)selector {
+ return [self webScriptNameForSelector:selector] == nil;
+}
+
+ (NSArray *) _attributeKeys {
- return [NSArray arrayWithObjects:@"applications", @"author", @"depiction", @"description", @"essential", @"homepage", @"icon", @"id", @"installed", @"latest", @"maintainer", @"name", @"purposes", @"rating", @"section", @"size", @"source", @"sponsor", @"tagline", @"warnings", nil];
+ return [NSArray arrayWithObjects:@"applications", @"author", @"depiction", @"description", @"essential", @"homepage", @"icon", @"id", @"installed", @"latest", @"maintainer", @"mode", @"name", @"purposes", @"section", @"size", @"source", @"sponsor", @"support", @"tagline", @"warnings", nil];
}
- (NSArray *) attributeKeys {
- (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
if ((self = [super init]) != nil) {
+ _profile(Package$initWithIterator)
+ @synchronized (database) {
+ era_ = [database era];
+
iterator_ = iterator;
database_ = database;
- version_ = [database_ policy]->GetCandidateVer(iterator_);
+ _profile(Package$initWithIterator$Control)
+ _end
+
+ _profile(Package$initWithIterator$Version)
+ version_ = [database_ policy]->GetCandidateVer(iterator_);
+ _end
+
NSString *latest = version_.end() ? nil : [NSString stringWithUTF8String:version_.VerStr()];
- latest_ = latest == nil ? nil : [StripVersion(latest) retain];
- pkgCache::VerIterator current = iterator_.CurrentVer();
- NSString *installed = current.end() ? nil : [NSString stringWithUTF8String:current.VerStr()];
- installed_ = [StripVersion(installed) retain];
+ _profile(Package$initWithIterator$Latest)
+ latest_ = latest == nil ? nil : [StripVersion(latest) retain];
+ _end
- if (!version_.end())
- file_ = version_.FileList();
- else {
- pkgCache &cache([database_ cache]);
- file_ = pkgCache::VerFileIterator(cache, cache.VerFileP);
- }
+ pkgCache::VerIterator current;
+ NSString *installed;
- id_ = [[NSString stringWithUTF8String:iterator_.Name()] retain];
-
- if (!file_.end()) {
- pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
-
- const char *begin, *end;
- parser->GetRec(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;
- }
- }
+ _profile(Package$initWithIterator$Current)
+ current = iterator_.CurrentVer();
+ installed = current.end() ? nil : [NSString stringWithUTF8String:current.VerStr()];
+ _end
- if (begin == NULL)
- break;
- ++begin;
- } else goto next;
-
- if (name_ != nil)
- name_ = [name_ retain];
- tagline_ = [[NSString stringWithUTF8String:parser->ShortDesc().c_str()] retain];
- if (icon_ != nil)
- icon_ = [icon_ retain];
- if (depiction_ != nil)
- depiction_ = [depiction_ retain];
- if (homepage_ == nil)
- homepage_ = website;
- if ([homepage_ isEqualToString:depiction_])
- homepage_ = nil;
- if (homepage_ != nil)
- homepage_ = [homepage_ retain];
- if (sponsor != nil)
- sponsor_ = [[Address addressWithString:sponsor] retain];
- if (author != nil)
- author_ = [[Address addressWithString:author] retain];
- if (tag != nil)
- tags_ = [[tag componentsSeparatedByString:@", "] retain];
- }
+ _profile(Package$initWithIterator$Installed)
+ installed_ = [StripVersion(installed) retain];
+ _end
- if (tags_ != nil)
- for (int i(0), e([tags_ count]); i != e; ++i) {
- NSString *tag = [tags_ objectAtIndex:i];
- if ([tag hasPrefix:@"role::"]) {
- role_ = [[tag substringFromIndex:6] retain];
- break;
- }
+ _profile(Package$initWithIterator$File)
+ if (!version_.end())
+ file_ = version_.FileList();
+ else {
+ pkgCache &cache([database_ cache]);
+ file_ = pkgCache::VerFileIterator(cache, cache.VerFileP);
}
+ _end
+
+ _profile(Package$initWithIterator$Name)
+ id_ = [[NSString stringWithUTF8String:iterator_.Name()] retain];
+ _end
+
+ if (!file_.end())
+ _profile(Package$initWithIterator$Parse)
+ pkgRecords::Parser *parser;
+
+ _profile(Package$initWithIterator$Parse$Lookup)
+ parser = &[database_ records]->Lookup(file_);
+ _end
+
+ const char *begin, *end;
+ parser->GetRec(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},
+ {"support", &support_},
+ {"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;
+
+ _profile(Package$initWithIterator$Parse$Value)
+ value = [NSString stringWithUTF8Bytes:colon length:(stop - colon)];
+ _end
+
+ *names[i].value_ = value;
+ break;
+ }
+ }
+
+ if (begin == NULL)
+ break;
+ ++begin;
+ } else goto next;
+
+ _profile(Package$initWithIterator$Parse$Retain)
+ if (name_ != nil)
+ name_ = [name_ retain];
+ _profile(Package$initWithIterator$Parse$Tagline)
+ tagline_ = [[NSString stringWithUTF8String:parser->ShortDesc().c_str()] retain];
+ _end
+ if (icon_ != nil)
+ icon_ = [icon_ retain];
+ if (depiction_ != nil)
+ depiction_ = [depiction_ retain];
+ if (homepage_ == nil)
+ homepage_ = website;
+ if ([homepage_ isEqualToString:depiction_])
+ homepage_ = nil;
+ if (homepage_ != nil)
+ homepage_ = [homepage_ retain];
+ if (sponsor != nil)
+ sponsor_ = [[Address addressWithString:sponsor] retain];
+ if (author != nil)
+ author_ = [[Address addressWithString:author] retain];
+ if (tag != nil)
+ tags_ = [[tag componentsSeparatedByString:@", "] retain];
+ _end
+ _end
+
+ _profile(Package$initWithIterator$Tags)
+ if (tags_ != nil)
+ for (NSString *tag in tags_)
+ if ([tag hasPrefix:@"role::"]) {
+ role_ = [[tag substringFromIndex:6] retain];
+ break;
+ }
+ _end
NSString *solid(latest == nil ? installed : latest);
bool changed(false);
NSString *key([id_ lowercaseString]);
- NSMutableDictionary *metadata = [Packages_ objectForKey:key];
- if (metadata == nil) {
- metadata = [[NSMutableDictionary dictionaryWithObjectsAndKeys:
- now_, @"FirstSeen",
- nil] mutableCopy];
-
- if (solid != nil)
- [metadata setObject:solid forKey:@"LastVersion"];
- changed = true;
- } else {
- NSDate *first([metadata objectForKey:@"FirstSeen"]);
- NSDate *last([metadata objectForKey:@"LastSeen"]);
- NSString *version([metadata objectForKey:@"LastVersion"]);
+ _profile(Package$initWithIterator$Metadata)
+ NSMutableDictionary *metadata = [Packages_ objectForKey:key];
+ if (metadata == nil) {
+ metadata = [[NSMutableDictionary dictionaryWithObjectsAndKeys:
+ now_, @"FirstSeen",
+ nil] mutableCopy];
- if (first == nil) {
- first = last == nil ? now_ : last;
- [metadata setObject:first forKey:@"FirstSeen"];
+ if (solid != nil)
+ [metadata setObject:solid forKey:@"LastVersion"];
changed = true;
+ } else {
+ NSDate *first([metadata objectForKey:@"FirstSeen"]);
+ NSDate *last([metadata objectForKey:@"LastSeen"]);
+ NSString *version([metadata objectForKey:@"LastVersion"]);
+
+ if (first == nil) {
+ first = last == nil ? now_ : last;
+ [metadata setObject:first forKey:@"FirstSeen"];
+ changed = true;
+ }
+
+ if (solid != nil)
+ if (version == nil) {
+ [metadata setObject:solid forKey:@"LastVersion"];
+ changed = true;
+ } else if (![version isEqualToString:solid]) {
+ [metadata setObject:solid forKey:@"LastVersion"];
+ last = now_;
+ [metadata setObject:last forKey:@"LastSeen"];
+ changed = true;
+ }
}
- if (solid != nil)
- if (version == nil) {
- [metadata setObject:solid forKey:@"LastVersion"];
- changed = true;
- } else if (![version isEqualToString:solid]) {
- [metadata setObject:solid forKey:@"LastVersion"];
- last = now_;
- [metadata setObject:last forKey:@"LastSeen"];
- changed = true;
+ if (changed) {
+ [Packages_ setObject:metadata forKey:key];
+ Changed_ = true;
+ }
+ _end
+
+ const char *section(iterator_.Section());
+ if (section == NULL)
+ section_ = nil;
+ else {
+ NSString *name([[NSString stringWithUTF8String:section] stringByReplacingCharacter:' ' withCharacter:'_']);
+
+ lookup:
+ if (NSDictionary *value = [SectionMap_ objectForKey:name])
+ if (NSString *rename = [value objectForKey:@"Rename"]) {
+ name = rename;
+ goto lookup;
}
- }
- if (changed) {
- [Packages_ setObject:metadata forKey:key];
- Changed_ = true;
+ section_ = [[name stringByReplacingCharacter:'_' withCharacter:' '] retain];
}
- } return self;
+
+ essential_ = (iterator_->Flags & pkgCache::Flag::Essential) == 0 ? NO : YES;
+ } _end } return self;
}
+ (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
}
- (NSString *) section {
- if (section_ != nil)
- return section_;
-
- const char *section = iterator_.Section();
- if (section == NULL)
- return nil;
-
- NSString *name = [[NSString stringWithUTF8String:section] stringByReplacingCharacter:' ' withCharacter:'_'];
-
- lookup:
- if (NSDictionary *value = [SectionMap_ objectForKey:name])
- if (NSString *rename = [value objectForKey:@"Rename"]) {
- name = rename;
- goto lookup;
- }
-
- section_ = [[name stringByReplacingCharacter:'_' withCharacter:' '] retain];
return section_;
}
return Simplify(section);
else
return nil;
+}
+- (NSString *) uri {
+ return nil;
+#if 0
+ pkgIndexFile *index;
+ pkgCache::PkgFileIterator file(file_.File());
+ if (![database_ list].FindIndex(file, index))
+ return nil;
+ return [NSString stringWithUTF8String:iterator_->Path];
+ //return [NSString stringWithUTF8String:file.Site()];
+ //return [NSString stringWithUTF8String:index->ArchiveURI(file.FileName()).c_str()];
+#endif
}
- (Address *) maintainer {
if (file_.end())
return nil;
pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
- return [Address addressWithString:[NSString stringWithUTF8String:parser->Maintainer().c_str()]];
+ const std::string &maintainer(parser->Maintainer());
+ return maintainer.empty() ? nil : [Address addressWithString:[NSString stringWithUTF8String:maintainer.c_str()]];
}
- (size_t) size {
return nil;
NSCharacterSet *whitespace = [NSCharacterSet whitespaceCharacterSet];
- for (size_t i(1); i != [lines count]; ++i) {
+ for (size_t i(1), e([lines count]); i != e; ++i) {
NSString *trim = [[lines objectAtIndex:i] stringByTrimmingCharactersInSet:whitespace];
[trimmed addObject:trim];
}
return [trimmed componentsJoinedByString:@"\n"];
}
-- (NSString *) index {
- NSString *index = [[[self name] substringToIndex:1] uppercaseString];
- return [index length] != 0 && isalpha([index characterAtIndex:0]) ? index : @"123";
+- (unichar) index {
+ _profile(Package$index)
+ NSString *name([self name]);
+ if ([name length] == 0)
+ return '#';
+ unichar character([name characterAtIndex:0]);
+ if (!isalpha(character))
+ return '#';
+ return toupper(character);
+ _end
}
- (NSMutableDictionary *) metadata {
- (BOOL) upgradableAndEssential:(BOOL)essential {
pkgCache::VerIterator current = iterator_.CurrentVer();
+ bool value;
if (current.end())
- return essential && [self essential];
+ value = essential && [self essential] && [self visible];
else
- return !version_.end() && version_ != current;
+ value = !version_.end() && version_ != current;// && (!essential || ![database_ cache][iterator_].Keep());
+ return value;
}
- (BOOL) essential {
- return (iterator_->Flags & pkgCache::Flag::Essential) == 0 ? NO : YES;
+ return essential_;
}
- (BOOL) broken {
else
return @"Remove";
case pkgDepCache::ModeKeep:
- if ((state.iFlags & pkgDepCache::AutoKept) != 0)
- return nil;
+ if ((state.iFlags & pkgDepCache::ReInstall) != 0)
+ return @"Reinstall";
+ /*else if ((state.iFlags & pkgDepCache::AutoKept) != 0)
+ return nil;*/
else
return nil;
case pkgDepCache::ModeInstall:
- if ((state.iFlags & pkgDepCache::ReInstall) != 0)
+ /*if ((state.iFlags & pkgDepCache::ReInstall) != 0)
return @"Reinstall";
- else switch (state.Status) {
+ else*/ switch (state.Status) {
case -1:
return @"Downgrade";
case 0:
NSString *section = [self simpleSection];
UIImage *icon(nil);
- if (NSString *icon = icon_)
- icon = [UIImage imageAtPath:[icon_ substringFromIndex:6]];
+ if (icon_ != nil)
+ if ([icon_ hasPrefix:@"file:///"])
+ icon = [UIImage imageAtPath:[icon_ substringFromIndex:7]];
if (icon == nil) if (section != nil)
icon = [UIImage imageAtPath:[NSString stringWithFormat:@"%@/Sections/%@.png", App_, section]];
- if (icon == nil) if (source_ != nil) if (NSString *icon = [source_ defaultIcon])
- icon = [UIImage imageAtPath:[icon substringFromIndex:6]];
+ if (icon == nil) if (source_ != nil) if (NSString *dicon = [source_ defaultIcon])
+ if ([dicon hasPrefix:@"file:///"])
+ icon = [UIImage imageAtPath:[dicon substringFromIndex:7]];
if (icon == nil)
icon = [UIImage applicationImageNamed:@"unknown.png"];
return icon;
return author_;
}
+- (NSString *) support {
+ return support_ != nil ? support_ : [[self source] supportForPackage:id_];
+}
+
- (NSArray *) files {
NSString *path = [NSString stringWithFormat:@"/var/lib/dpkg/info/%@.list", id_];
NSMutableArray *files = [NSMutableArray arrayWithCapacity:128];
[warnings addObject:@"illegal package identifier"];
else for (size_t i(0); i != length; ++i)
if (
+ /* XXX: technically this is not allowed */
+ (name[i] < 'A' || name[i] > 'Z') &&
(name[i] < 'a' || name[i] > 'z') &&
(name[i] < '0' || name[i] > '9') &&
(i == 0 || name[i] != '+' && name[i] != '-' && name[i] != '.')
if (strcmp(name, "cydia") != 0) {
bool cydia = false;
+ bool _private = false;
bool stash = false;
+ bool repository = [[self section] isEqualToString:@"Repositories"];
+
if (NSArray *files = [self files])
for (NSString *file in files)
if (!cydia && [file isEqualToString:@"/Applications/Cydia.app"])
cydia = true;
+ else if (!_private && [file isEqualToString:@"/private"])
+ _private = true;
else if (!stash && [file isEqualToString:@"/var/stash"])
stash = true;
- if (cydia)
+ /* XXX: this is not sensitive enough. only some folders are valid. */
+ if (cydia && !repository)
[warnings addObject:@"files installed into Cydia.app"];
+ if (_private)
+ [warnings addObject:@"files installed with /private/*"];
if (stash)
[warnings addObject:@"files installed to /var/stash"];
}
- (Source *) source {
if (!cached_) {
- source_ = file_.end() ? nil : [[database_ getSource:file_.File()] retain];
- cached_ = true;
+ @synchronized (database_) {
+ if ([database_ era] != era_ || file_.end())
+ source_ = nil;
+ else {
+ source_ = [database_ getSource:file_.File()];
+ if (source_ != nil)
+ [source_ retain];
+ }
+
+ cached_ = true;
+ }
}
return source_;
return role_;
}
-- (NSString *) rating {
- if (NSString *rating = [Indices_ objectForKey:@"Rating"])
- return [rating stringByReplacingOccurrencesOfString:@"@P" withString:[id_ stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
- else
- return nil;
-}
-
- (BOOL) matches:(NSString *)text {
if (text == nil)
return NO;
NSRange range;
- range = [[self id] rangeOfString:text options:NSCaseInsensitiveSearch];
+ range = [[self id] rangeOfString:text options:MatchCompareOptions_];
if (range.location != NSNotFound)
return YES;
- range = [[self name] rangeOfString:text options:NSCaseInsensitiveSearch];
+ range = [[self name] rangeOfString:text options:MatchCompareOptions_];
if (range.location != NSNotFound)
return YES;
- range = [[self tagline] rangeOfString:text options:NSCaseInsensitiveSearch];
+ range = [[self tagline] rangeOfString:text options:MatchCompareOptions_];
if (range.location != NSNotFound)
return YES;
return [purposes count] == 0 ? nil : purposes;
}
+- (bool) isCommercial {
+ return [self hasTag:@"cydia::commercial"];
+}
+
- (NSComparisonResult) compareByName:(Package *)package {
NSString *lhs = [self name];
NSString *rhs = [package name];
} bits;
} value;
- value.bits.upgradable = [self upgradableAndEssential:YES] ? 1 : 0;
+ bool upgradable([self upgradableAndEssential:YES]);
+ value.bits.upgradable = upgradable ? 1 : 0;
- if ([self upgradableAndEssential:YES]) {
+ if (upgradable) {
value.bits.timestamp = 0;
value.bits.ignored = [self ignored] ? 0 : 1;
value.bits.upgradable = 1;
return _not(uint32_t) - value.key;
}
+- (void) clear {
+ pkgProblemResolver *resolver = [database_ resolver];
+ resolver->Clear(iterator_);
+ resolver->Protect(iterator_);
+}
+
- (void) install {
pkgProblemResolver *resolver = [database_ resolver];
resolver->Clear(iterator_);
[database_ cache]->MarkDelete(iterator_, true);
}
-- (NSNumber *) isUnfilteredAndSearchedForBy:(NSString *)search {
- return [NSNumber numberWithBool:(
- [self unfiltered] && [self matches:search]
- )];
+- (bool) isUnfilteredAndSearchedForBy:(NSString *)search {
+ _profile(Package$isUnfilteredAndSearchedForBy)
+ bool value(true);
+
+ _profile(Package$isUnfilteredAndSearchedForBy$Unfiltered)
+ value &= [self unfiltered];
+ _end
+
+ _profile(Package$isUnfilteredAndSearchedForBy$Match)
+ value &= [self matches:search];
+ _end
+
+ return value;
+ _end
}
-- (NSNumber *) isInstalledAndVisible:(NSNumber *)number {
- return [NSNumber numberWithBool:(
- (![number boolValue] || [self visible]) && [self installed] != nil
- )];
+- (bool) isInstalledAndVisible:(NSNumber *)number {
+ return (![number boolValue] || [self visible]) && [self installed] != nil;
}
-- (NSNumber *) isVisiblyUninstalledInSection:(NSString *)name {
+- (bool) isVisiblyUninstalledInSection:(NSString *)name {
NSString *section = [self section];
- return [NSNumber numberWithBool:(
+ return
[self visible] &&
[self installed] == nil && (
name == nil ||
section == nil && [name length] == 0 ||
[name isEqualToString:section]
- )
- )];
+ );
}
-- (NSNumber *) isVisibleInSource:(Source *)source {
- return [NSNumber numberWithBool:([self source] == source && [self visible])];
+- (bool) isVisibleInSource:(Source *)source {
+ return [self source] == source && [self visible];
}
@end
/* Section Class {{{ */
@interface Section : NSObject {
NSString *name_;
+ unichar index_;
size_t row_;
size_t count_;
}
- (NSComparisonResult) compareByName:(Section *)section;
- (Section *) initWithName:(NSString *)name;
- (Section *) initWithName:(NSString *)name row:(size_t)row;
+- (Section *) initWithIndex:(unichar)index row:(size_t)row;
- (NSString *) name;
+- (unichar) index;
- (size_t) row;
- (size_t) count;
- (void) addToCount;
- (Section *) initWithName:(NSString *)name row:(size_t)row {
if ((self = [super init]) != nil) {
name_ = [name retain];
+ index_ = '\0';
+ row_ = row;
+ } return self;
+}
+
+- (Section *) initWithIndex:(unichar)index row:(size_t)row {
+ if ((self = [super init]) != nil) {
+ name_ = [(index == '#' ? @"123" : [NSString stringWithCharacters:&index length:1]) retain];
+ index_ = index;
row_ = row;
} return self;
}
return name_;
}
+- (unichar) index {
+ return index_;
+}
+
- (size_t) row {
return row_;
}
return instance;
}
+- (unsigned) era {
+ return era_;
+}
+
- (void) dealloc {
_assert(false);
[super dealloc];
return *fetcher_;
}
+- (pkgSourceList &) list {
+ return *list_;
+}
+
- (NSArray *) packages {
return packages_;
}
return issues;
}
-- (void) reloadData {
+- (void) reloadData { _pooled
+ @synchronized (self) {
+ ++era_;
+ }
+
_error->Discard();
delete list_;
[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();
+
+ _config->Set("Acquire::http::Timeout", 15);
+ _config->Set("Acquire::http::MaxParallel", 4);
}
- (void) configure {
failed = true;
[delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
- withObject:[NSArray arrayWithObjects:[NSString stringWithUTF8String:error.c_str()], nil]
+ withObject:[NSArray arrayWithObjects:
+ [NSString stringWithUTF8String:error.c_str()],
+ nil]
waitUntilDone:YES
];
}
@protocol ConfirmationViewDelegate
- (void) cancel;
- (void) confirm;
+- (void) queue;
@end
@interface ConfirmationView : BrowserView {
pkgCacheFile &cache([database_ cache]);
NSArray *packages = [database_ packages];
- for (size_t i(0), e = [packages count]; i != e; ++i) {
- Package *package = [packages objectAtIndex:i];
+ for (Package *package in packages) {
pkgCache::PkgIterator iterator = [package iterator];
pkgDepCache::StateCache &state(cache[iterator]);
return @"Cancel";
}
+- (id) rightButtonTitle {
+ return issues_ != nil ? nil : [super rightButtonTitle];
+}
+
- (id) _rightButtonTitle {
#if AlwaysReload || IgnoreInstall
- return @"Reload";
+ return [super _rightButtonTitle];
#else
- return issues_ == nil ? @"Confirm" : nil;
+ return @"Confirm";
#endif
}
SHA1SumValue springlist_;
SHA1SumValue notifyconf_;
SHA1SumValue sandplate_;
- size_t received_;
- NSTimeInterval last_;
}
- (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
[status_ setCentersHorizontally:YES];
//[status_ setFont:font];
+ _trace();
output_ = [[UITextView alloc] initWithFrame:CGRectMake(
10,
bounds.size.width - 20,
bounds.size.height - navsize.height - 62 - navrect.size.height
)];
+ _trace();
//[output_ setTextFont:@"Courier New"];
[output_ setTextSize:12];
- (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
NSString *context([sheet context]);
- if ([context isEqualToString:@"conffile"]) {
+ if ([context isEqualToString:@"error"])
+ [sheet dismiss];
+ else if ([context isEqualToString:@"conffile"]) {
FILE *input = [database_ input];
switch (button) {
[output_ setText:@""];
[progress_ setProgress:0];
- received_ = 0;
- last_ = 0;//[NSDate timeIntervalSinceReferenceDate];
-
[close_ removeFromSuperview];
[overlay_ addSubview:progress_];
[overlay_ addSubview:status_];
}
- (void) startProgress {
- last_ = [NSDate timeIntervalSinceReferenceDate];
}
- (void) addProgressOutput:(NSString *)output {
}
- (bool) isCancelling:(size_t)received {
- if (last_ != 0) {
- NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate];
- if (received_ != received) {
- received_ = received;
- last_ = now;
- } else if (now - last_ > 30)
- return true;
- }
-
return false;
}
/* }}} */
/* Package Cell {{{ */
-@interface PackageCell : UISimpleTableCell {
+@interface PackageCell : UITableCell {
UIImage *icon_;
NSString *name_;
NSString *description_;
+ bool commercial_;
NSString *source_;
UIImage *badge_;
+ bool cached_;
+ Package *package_;
#ifdef USE_BADGES
UITextLabel *status_;
#endif
[badge_ release];
badge_ = nil;
}
+
+ [package_ release];
+ package_ = nil;
}
- (void) dealloc {
name_ = [[package name] retain];
description_ = [[package tagline] retain];
+ commercial_ = [package isCommercial];
+
+ package_ = [package retain];
NSString *label = nil;
bool trusted = false;
[status_ setText:nil];
}
#endif
+
+ cached_ = false;
+}
+
+- (void) drawRect:(CGRect)rect {
+ if (!cached_) {
+ UIColor *color;
+
+ if (NSString *mode = [package_ mode]) {
+ bool remove([mode isEqualToString:@"Remove"] || [mode isEqualToString:@"Purge"]);
+ color = remove ? RemovingColor_ : InstallingColor_;
+ } else
+ color = [UIColor whiteColor];
+
+ [self setBackgroundColor:color];
+ cached_ = true;
+ }
+
+ [super drawRect:rect];
+}
+
+- (void) drawBackgroundInRect:(CGRect)rect withFade:(float)fade {
+ if (fade == 0) {
+ CGContextRef context(UIGraphicsGetCurrentContext());
+ [[self backgroundColor] set];
+ CGRect back(rect);
+ back.size.height -= 1;
+ CGContextFillRect(context, back);
+ }
+
+ [super drawBackgroundInRect:rect withFade:fade];
}
- (void) drawContentInRect:(CGRect)rect selected:(BOOL)selected {
UISetColor(White_);
if (!selected)
- UISetColor(Black_);
+ UISetColor(commercial_ ? Purple_ : Black_);
[name_ drawAtPoint:CGPointMake(48, 8) forWidth:240 withFont:Font18Bold_ ellipsis:2];
[source_ drawAtPoint:CGPointMake(58, 29) forWidth:225 withFont:Font12_ ellipsis:2];
if (!selected)
- UISetColor(Gray_);
+ UISetColor(commercial_ ? Purplish_ : Gray_);
[description_ drawAtPoint:CGPointMake(12, 46) forWidth:280 withFont:Font14_ ellipsis:2];
[super drawContentInRect:rect selected:selected];
}
+- (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
+ cached_ = false;
+ [super setSelected:selected withFade:fade];
+}
+
+ (int) heightForPackage:(Package *)package {
NSString *tagline([package tagline]);
int height = tagline == nil || [tagline length] == 0 ? -17 : 0;
_transient Database *database_;
Package *package_;
NSString *name_;
+ bool commercial_;
NSMutableArray *buttons_;
}
}
- (void) _clickButtonWithName:(NSString *)name {
- if ([name isEqualToString:@"Install"])
+ if ([name isEqualToString:@"Clear"])
+ [delegate_ clearPackage:package_];
+ else if ([name isEqualToString:@"Install"])
[delegate_ installPackage:package_];
else if ([name isEqualToString:@"Reinstall"])
[delegate_ installPackage:package_];
[super webView:sender didClearWindowObject:window forFrame:frame];
}
-#if !AlwaysReload
-- (void) _rightButtonClicked {
- /*[super _rightButtonClicked];
- return;*/
+- (bool) _allowJavaScriptPanel {
+ return commercial_;
+}
+#if !AlwaysReload
+- (void) __rightButtonClicked {
int count = [buttons_ count];
_assert(count != 0);
[delegate_ slideUp:[[[UIActionSheet alloc]
initWithTitle:nil
buttons:buttons
- defaultButtonIndex:2
+ defaultButtonIndex:([buttons count] - 1)
delegate:self
context:@"modify"
] autorelease]];
}
}
+
+- (void) _rightButtonClicked {
+ if (commercial_)
+ [super _rightButtonClicked];
+ else
+ [self __rightButtonClicked];
+}
#endif
- (id) _rightButtonTitle {
if (package != nil) {
package_ = [package retain];
name_ = [[package id] retain];
+ commercial_ = [package isCommercial];
[self loadURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"package" ofType:@"html"]]];
+ if ([package_ mode] != nil)
+ [buttons_ addObject:@"Clear"];
if ([package_ source] == nil);
else if ([package_ upgradableAndEssential:NO])
[buttons_ addObject:@"Upgrade"];
}
}
-- (bool) _loading {
- return false;
+- (bool) isLoading {
+ return commercial_ ? [super isLoading] : false;
}
- (void) reloadData {
@interface PackageTable : RVPage {
_transient Database *database_;
NSString *title_;
- SEL filter_;
- id object_;
NSMutableArray *packages_;
NSMutableArray *sections_;
UISectionList *list_;
}
-- (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object;
+- (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title;
- (void) setDelegate:(id)delegate;
-- (void) setObject:(id)object;
- (void) reloadData;
- (void) resetCursor;
[list_ setDataSource:nil];
[title_ release];
- if (object_ != nil)
- [object_ release];
[packages_ release];
[sections_ release];
[list_ release];
return;
Package *package = [packages_ objectAtIndex:row];
+ package = [database_ packageWithName:[package id]];
PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
- [view setDelegate:delegate_];
[view setPackage:package];
+ [view setDelegate:delegate_];
[book_ pushPage:view];
}
-- (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object {
+- (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title {
if ((self = [super initWithBook:book]) != nil) {
database_ = database;
title_ = [title retain];
- filter_ = filter;
- object_ = object == nil ? nil : [object retain];
packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
[table setReusesTableCells:YES];
[self addSubview:list_];
- [self reloadData];
[self setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
[list_ setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
delegate_ = delegate;
}
-- (void) setObject:(id)object {
- if (object_ != nil)
- [object_ release];
- if (object == nil)
- object_ = nil;
- else
- object_ = [object retain];
+- (bool) hasPackage:(Package *)package {
+ return true;
}
- (void) reloadData {
[packages_ removeAllObjects];
[sections_ removeAllObjects];
- for (size_t i(0); i != [packages count]; ++i) {
- Package *package([packages objectAtIndex:i]);
- if ([package valid] && [[package performSelector:filter_ withObject:object_] boolValue])
- [packages_ addObject:package];
- }
+ _profile(PackageTable$reloadData$Filter)
+ for (Package *package in packages)
+ if ([self hasPackage:package])
+ [packages_ addObject:package];
+ _end
Section *section = nil;
- for (size_t offset(0); offset != [packages_ count]; ++offset) {
- Package *package = [packages_ objectAtIndex:offset];
- NSString *name = [package index];
+ _profile(PackageTable$reloadData$Section)
+ for (size_t offset(0), end([packages_ count]); offset != end; ++offset) {
+ Package *package;
+ unichar index;
- if (section == nil || ![[section name] isEqualToString:name]) {
- section = [[[Section alloc] initWithName:name row:offset] autorelease];
- [sections_ addObject:section];
- }
+ _profile(PackageTable$reloadData$Section$Package)
+ package = [packages_ objectAtIndex:offset];
+ index = [package index];
+ _end
- [section addToCount];
- }
+ if (section == nil || [section index] != index) {
+ _profile(PackageTable$reloadData$Section$Allocate)
+ section = [[[Section alloc] initWithIndex:index row:offset] autorelease];
+ _end
- [list_ reloadData];
+ _profile(PackageTable$reloadData$Section$Add)
+ [sections_ addObject:section];
+ _end
+ }
+
+ [section addToCount];
+ }
+ _end
+
+ _profile(PackageTable$reloadData$List)
+ [list_ reloadData];
+ _end
}
- (NSString *) title {
[list_ setShouldHideHeaderInShortLists:hide];
}
+@end
+/* }}} */
+/* Filtered Package Table {{{ */
+@interface FilteredPackageTable : PackageTable {
+ SEL filter_;
+ IMP imp_;
+ id object_;
+}
+
+- (void) setObject:(id)object;
+
+- (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object;
+
+@end
+
+@implementation FilteredPackageTable
+
+- (void) dealloc {
+ if (object_ != nil)
+ [object_ release];
+ [super dealloc];
+}
+
+- (void) setObject:(id)object {
+ if (object_ != nil)
+ [object_ release];
+ if (object == nil)
+ object_ = nil;
+ else
+ object_ = [object retain];
+}
+
+- (bool) hasPackage:(Package *)package {
+ _profile(FilteredPackageTable$hasPackage)
+ return [package valid] && (*reinterpret_cast<bool (*)(id, SEL, id)>(imp_))(package, filter_, object_);
+ _end
+}
+
+- (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object {
+ if ((self = [super initWithBook:book database:database title:title]) != nil) {
+ filter_ = filter;
+ object_ = object == nil ? nil : [object retain];
+
+ /* XXX: this is an unsafe optimization of doomy hell */
+ Method method = class_getInstanceMethod([Package class], filter);
+ imp_ = method_getImplementation(method);
+ _assert(imp_ != NULL);
+
+ [self reloadData];
+ } return self;
+}
+
@end
/* }}} */
Source *source = [sources_ objectAtIndex:row];
- PackageTable *packages = [[[PackageTable alloc]
+ PackageTable *packages = [[[FilteredPackageTable alloc]
initWithBook:book_
database:database_
title:[source label]
[delegate_ syncData];
}
+- (void) complete {
+ [Sources_ setObject:[NSDictionary dictionaryWithObjectsAndKeys:
+ @"deb", @"Type",
+ href_, @"URI",
+ @"./", @"Distribution",
+ nil] forKey:[NSString stringWithFormat:@"deb:%@:./", href_]];
+
+ [delegate_ syncData];
+}
+
+- (NSString *) getWarning {
+ NSString *href(href_);
+ NSRange colon([href rangeOfString:@"://"]);
+ if (colon.location != NSNotFound)
+ href = [href substringFromIndex:(colon.location + 3)];
+ href = [href stringByAddingPercentEscapes];
+ href = [@"http://cydia.saurik.com/api/repotag/" stringByAppendingString:href];
+ href = [href stringByCachingURLWithCurrentCDN];
+
+ NSURL *url([NSURL URLWithString:href]);
+
+ NSStringEncoding encoding;
+ NSError *error(nil);
+
+ if (NSString *warning = [NSString stringWithContentsOfURL:url usedEncoding:&encoding error:&error])
+ return [warning length] == 0 ? nil : warning;
+ return nil;
+}
+
- (void) _endConnection:(NSURLConnection *)connection {
NSURLConnection **field = NULL;
if (connection == trivial_bz2_)
trivial_bz2_ == nil &&
trivial_gz_ == nil
) {
- [delegate_ setStatusBarShowsProgress:NO];
-
- [hud_ show:NO];
- [hud_ removeFromSuperview];
- [hud_ autorelease];
- hud_ = nil;
+ bool defer(false);
if (trivial_) {
- [Sources_ setObject:[NSDictionary dictionaryWithObjectsAndKeys:
- @"deb", @"Type",
- href_, @"URI",
- @"./", @"Distribution",
- nil] forKey:[NSString stringWithFormat:@"deb:%@:./", href_]];
-
- [delegate_ syncData];
+ if (NSString *warning = [self yieldToSelector:@selector(getWarning)]) {
+ defer = true;
+
+ UIActionSheet *sheet = [[[UIActionSheet alloc]
+ initWithTitle:@"Source Warning"
+ buttons:[NSArray arrayWithObjects:@"Add Anyway", @"Cancel", nil]
+ defaultButtonIndex:0
+ delegate:self
+ context:@"warning"
+ ] autorelease];
+
+ [sheet setNumberOfRows:1];
+
+ [sheet setBodyText:warning];
+ [sheet popupAlertAnimated:YES];
+ } else
+ [self complete];
} else if (error_ != nil) {
UIActionSheet *sheet = [[[UIActionSheet alloc]
initWithTitle:@"Verification Error"
[sheet popupAlertAnimated:YES];
}
- [href_ release];
- href_ = nil;
+ [delegate_ setStatusBarShowsProgress:NO];
+ [delegate_ removeProgressHUD:hud_];
+
+ [hud_ autorelease];
+ hud_ = nil;
+
+ if (!defer) {
+ [href_ release];
+ href_ = nil;
+ }
if (error_ != nil) {
[error_ release];
trivial_ = false;
- hud_ = [delegate_ addProgressHUD];
+ hud_ = [[delegate_ addProgressHUD] retain];
[hud_ setText:@"Verifying URL"];
} break;
[sheet dismiss];
else if ([context isEqualToString:@"urlerror"])
[sheet dismiss];
+ else if ([context isEqualToString:@"warning"]) {
+ switch (button) {
+ case 1:
+ [self complete];
+ break;
+
+ case 2:
+ break;
+
+ default:
+ _assert(false);
+ }
+
+ [href_ release];
+ href_ = nil;
+
+ [sheet dismiss];
+ }
}
- (id) initWithBook:(RVBook *)book database:(Database *)database {
/* Installed View {{{ */
@interface InstalledView : RVPage {
_transient Database *database_;
- PackageTable *packages_;
+ FilteredPackageTable *packages_;
BOOL expert_;
}
if ((self = [super initWithBook:book]) != nil) {
database_ = database;
- packages_ = [[PackageTable alloc]
+ packages_ = [[FilteredPackageTable alloc]
initWithBook:book
database:database
title:nil
] autorelease];
[sheet setBodyText:
- @"Copyright (C) 2008\n"
+ @"Copyright (C) 2008-2009\n"
"Jay Freeman (saurik)\n"
"saurik@saurik.com\n"
"http://www.saurik.com/\n"
#if !AlwaysReload
- (id) _rightButtonTitle {
- return nil;
-}
-#endif
-
-- (bool) _loading {
- return false;
-}
-
-@end
-/* }}} */
-
-/* Indirect Delegate {{{ */
-@interface IndirectDelegate : NSProxy {
- _transient volatile id delegate_;
-}
-
-- (void) setDelegate:(id)delegate;
-- (id) initWithDelegate:(id)delegate;
-@end
-
-@implementation IndirectDelegate
-
-- (void) setDelegate:(id)delegate {
- delegate_ = delegate;
+ return Queuing_ ? @"Queue" : nil;
}
-- (id) initWithDelegate:(id)delegate {
- delegate_ = delegate;
- return self;
+- (UINavigationButtonStyle) rightButtonStyle {
+ return Queuing_ ? UINavigationButtonStyleHighlighted : UINavigationButtonStyleNormal;
}
-- (NSMethodSignature*) methodSignatureForSelector:(SEL)sel {
- if (delegate_ != nil)
- if (NSMethodSignature *sig = [delegate_ methodSignatureForSelector:sel])
- return sig;
- // XXX: I fucking hate Apple so very very bad
- return [NSMethodSignature signatureWithObjCTypes:"v@:"];
+- (void) _rightButtonClicked {
+ [delegate_ queue];
}
+#endif
-- (void) forwardInvocation:(NSInvocation *)inv {
- SEL sel = [inv selector];
- if (delegate_ != nil && [delegate_ respondsToSelector:sel])
- [inv invokeWithTarget:delegate_];
+- (bool) isLoading {
+ return false;
}
@end
UIProgressBar *progress_;
UINavigationButton *cancel_;
bool updating_;
- size_t received_;
- NSTimeInterval last_;
}
- (id) initWithFrame:(CGRect)frame database:(Database *)database;
[prompt_ setText:@"Updating Database"];
[progress_ setProgress:0];
- received_ = 0;
- last_ = [NSDate timeIntervalSinceReferenceDate];
updating_ = true;
[overlay_ addSubview:cancel_];
}
- (bool) isCancelling:(size_t)received {
- NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate];
- if (received_ != received) {
- received_ = received;
- last_ = now;
- } else if (now - last_ > 15)
- return true;
return !updating_;
}
- (void) _returnPNGWithImage:(UIImage *)icon forRequest:(NSURLRequest *)request {
id<NSURLProtocolClient> client([self client]);
- NSData *data(UIImagePNGRepresentation(icon));
+ if (icon == nil)
+ [client URLProtocol:self didFailWithError:[NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorFileDoesNotExist userInfo:nil]];
+ else {
+ NSData *data(UIImagePNGRepresentation(icon));
- NSURLResponse *response([[[NSURLResponse alloc] initWithURL:[request URL] MIMEType:@"image/png" expectedContentLength:-1 textEncodingName:nil] autorelease]);
- [client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
- [client URLProtocol:self didLoadData:data];
- [client URLProtocolDidFinishLoading:self];
+ NSURLResponse *response([[[NSURLResponse alloc] initWithURL:[request URL] MIMEType:@"image/png" expectedContentLength:-1 textEncodingName:nil] autorelease]);
+ [client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
+ [client URLProtocol:self didLoadData:data];
+ [client URLProtocolDidFinishLoading:self];
+ }
}
- (void) startLoading {
@end
/* }}} */
-/* Install View {{{ */
-@interface InstallView : RVPage {
+/* Sections View {{{ */
+@interface SectionsView : RVPage {
_transient Database *database_;
NSMutableArray *sections_;
NSMutableArray *filtered_;
@end
-@implementation InstallView
+@implementation SectionsView
- (void) dealloc {
[list_ setDataSource:nil];
}
}
- PackageTable *table = [[[PackageTable alloc]
+ PackageTable *table = [[[FilteredPackageTable alloc]
initWithBook:book_
database:database_
title:title
NSMutableDictionary *sections = [NSMutableDictionary dictionaryWithCapacity:32];
_trace();
- for (size_t i(0); i != [packages count]; ++i) {
- Package *package([packages objectAtIndex:i]);
+ for (Package *package in packages) {
NSString *name([package section]);
if (name != nil) {
_trace();
Section *section = nil;
- for (size_t offset = 0, count = [filtered count]; offset != count; ++offset) {
- Package *package = [filtered objectAtIndex:offset];
+ for (Package *package in filtered) {
NSString *name = [package section];
if (section == nil || name != nil && ![[section name] isEqualToString:name]) {
[sections_ removeAllObjects];
_trace();
- for (size_t i(0); i != [packages count]; ++i) {
- Package *package([packages objectAtIndex:i]);
-
+ for (Package *package in packages)
if (
[package installed] == nil && [package valid] && [package visible] ||
- [package upgradableAndEssential:NO]
+ [package upgradableAndEssential:YES]
)
[packages_ addObject:package];
- }
_trace();
[packages_ radixSortUsingSelector:@selector(compareForChanges) withObject:nil];
if (section == nil || last != seen && (seen == nil || [seen compare:last] != NSOrderedSame)) {
last = seen;
- NSString *name(seen == nil ? [@"n/a ?" retain] : (NSString *) CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen));
+ NSString *name;
+ if (seen == nil)
+ name = @"unknown?";
+ else {
+ name = (NSString *) CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen);
+ [name autorelease];
+ }
+
+ name = [@"New at " stringByAppendingString:name];
section = [[[Section alloc] initWithName:name row:offset] autorelease];
[sections_ addObject:section];
- [name release];
}
[section addToCount];
UIView *accessory_;
UISearchField *field_;
UITransitionView *transition_;
- PackageTable *table_;
+ FilteredPackageTable *table_;
UIPreferencesTable *advanced_;
UIView *dimmed_;
bool flipped_;
CGColor dimmed(space_, 0, 0, 0, 0.5);
[dimmed_ setBackgroundColor:[UIColor colorWithCGColor:dimmed]];
- table_ = [[PackageTable alloc]
+ table_ = [[FilteredPackageTable alloc]
initWithBook:book
database:database
title:nil
if (flipped_)
[self flipPage];
[table_ setObject:[field_ text]];
- [table_ reloadData];
+ _profile(SearchView$reloadData)
+ [table_ reloadData];
+ _end
+ PrintTimes();
[table_ resetCursor];
}
UIKeyboard *keyboard_;
UIProgressHUD *hud_;
- InstallView *install_;
+ SectionsView *sections_;
ChangesView *changes_;
ManageView *manage_;
SearchView *search_;
}
- (void) _reloadData {
- /*UIProgressHUD *hud = [[UIProgressHUD alloc] initWithWindow:window_];
- [hud setText:@"Reloading Data"];
- [overlay_ addSubview:hud];
- [hud show:YES];*/
+ UIView *block();
- [database_ reloadData];
+ static bool loaded(false);
+ UIProgressHUD *hud([self addProgressHUD]);
+ [hud setText:(loaded ? @"Reloading Data" : @"Loading Data")];
+ loaded = true;
+
+ [database_ yieldToSelector:@selector(reloadData) withObject:nil];
+ _trace();
+
+ [self removeProgressHUD:hud];
size_t changes(0);
NSString *badge([[NSNumber numberWithInt:changes] stringValue]);
[buttonbar_ setBadgeValue:badge forButton:3];
if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
- [buttonbar_ setBadgeAnimated:YES forButton:3];
+ [buttonbar_ setBadgeAnimated:([essential_ count] != 0) forButton:3];
[self setApplicationBadge:badge];
} else {
[buttonbar_ setBadgeValue:nil forButton:3];
[self removeApplicationBadge];
}
+ Queuing_ = false;
+ [buttonbar_ setBadgeValue:nil forButton:4];
+
[self updateData];
-#if !ForSaurik
+ // XXX: what is this line of code for?
if ([packages count] == 0);
- else if (Loaded_)
-#endif
+ else if (Loaded_ || ManualRefresh) loaded:
[self _loaded];
-#if !ForSaurik
else {
Loaded_ = YES;
+
+ if (NSDate *update = [Metadata_ objectForKey:@"LastUpdate"]) {
+ NSTimeInterval interval([update timeIntervalSinceNow]);
+ if (interval <= 0 && interval > -600)
+ goto loaded;
+ }
+
[book_ update];
}
-#endif
-
- /*[hud show:NO];
- [hud removeFromSuperview];*/
}
- (void) _saveConfig {
[self _saveConfig];
/* XXX: this is just stupid */
- if (tag_ != 2 && install_ != nil)
- [install_ reloadData];
+ if (tag_ != 2 && sections_ != nil)
+ [sections_ reloadData];
if (tag_ != 3 && changes_ != nil)
[changes_ reloadData];
if (tag_ != 5 && search_ != nil)
NSArray *keys = [Sources_ allKeys];
- for (int i(0), e([keys count]); i != e; ++i) {
- NSString *key = [keys objectAtIndex:i];
+ for (NSString *key in keys) {
NSDictionary *source = [Sources_ objectForKey:key];
fprintf(file, "%s %s %s\n",
_error->Discard();
}
+- (void) popUpBook:(RVBook *)book {
+ [underlay_ popSubview:book];
+}
+
+- (CGRect) popUpBounds {
+ return [underlay_ bounds];
+}
+
- (void) perform {
[database_ prepare];
- confirm_ = [[RVBook alloc] initWithFrame:[underlay_ bounds]];
+ confirm_ = [[RVBook alloc] initWithFrame:[self popUpBounds]];
[confirm_ setDelegate:self];
ConfirmationView *page([[[ConfirmationView alloc] initWithBook:confirm_ database:database_] autorelease]);
[page setDelegate:self];
[confirm_ setPage:page];
- [underlay_ popSubview:confirm_];
+ [self popUpBook:confirm_];
+}
+
+- (void) queue {
+ @synchronized (self) {
+ [self perform];
+ }
+}
+
+- (void) clearPackage:(Package *)package {
+ @synchronized (self) {
+ [package clear];
+ [self resolve];
+ [self perform];
+ }
}
- (void) installPackage:(Package *)package {
}
- (void) cancel {
+ [self slideUp:[[[UIActionSheet alloc]
+ initWithTitle:nil
+ buttons:[NSArray arrayWithObjects:@"Continue Queuing", @"Cancel and Clear", nil]
+ defaultButtonIndex:1
+ delegate:self
+ context:@"cancel"
+ ] autorelease]];
+}
+
+- (void) complete {
@synchronized (self) {
[self _reloadData];
+
if (confirm_ != nil) {
[confirm_ release];
confirm_ = nil;
[confirm_ popFromSuperviewAnimated:NO];
}
- [self cancel];
+ [self complete];
}
- (void) setPage:(RVPage *)page {
[book_ resetViewAnimated:YES];
return;
} else if (tag_ == 2 && tag != 2)
- [install_ resetView];
+ [sections_ resetView];
switch (tag) {
case 1: [self _setHomePage]; break;
- case 2: [self setPage:install_]; break;
+ case 2: [self setPage:sections_]; break;
case 3: [self setPage:changes_]; break;
case 4: [self setPage:manage_]; break;
case 5: [self setPage:search_]; break;
- (void) finish {
if (hud_ != nil) {
[self setStatusBarShowsProgress:NO];
+ [self removeProgressHUD:hud_];
- [hud_ show:NO];
- [hud_ removeFromSuperview];
[hud_ autorelease];
hud_ = nil;
return;
}
+ _trace();
overlay_ = [[UIView alloc] initWithFrame:[underlay_ bounds]];
CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
[self reloadData];
- install_ = [[InstallView alloc] initWithBook:book_ database:database_];
+ sections_ = [[SectionsView alloc] initWithBook:book_ database:database_];
changes_ = [[ChangesView alloc] initWithBook:book_ database:database_];
search_ = [[SearchView alloc] initWithBook:book_ database:database_];
withClass:[ManageView class]
] retain];
+ PrintTimes();
+
if (bootstrap_)
[self bootstrap];
else
- (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
NSString *context([sheet context]);
- if ([context isEqualToString:@"fixhalf"]) {
+ if ([context isEqualToString:@"missing"])
+ [sheet dismiss];
+ else if ([context isEqualToString:@"cancel"]) {
+ bool clear;
+
+ switch (button) {
+ case 1:
+ clear = false;
+ break;
+
+ case 2:
+ clear = true;
+ break;
+
+ default:
+ _assert(false);
+ }
+
+ [sheet dismiss];
+
+ @synchronized (self) {
+ if (clear)
+ [self _reloadData];
+ else {
+ Queuing_ = true;
+ [buttonbar_ setBadgeValue:@"Q'd" forButton:4];
+ [book_ reloadData];
+ }
+
+ if (confirm_ != nil) {
+ [confirm_ release];
+ confirm_ = nil;
+ }
+ }
+ } else if ([context isEqualToString:@"fixhalf"]) {
switch (button) {
case 1:
@synchronized (self) {
- for (int i = 0, e = [broken_ count]; i != e; ++i) {
- Package *broken = [broken_ objectAtIndex:i];
+ for (Package *broken in broken_) {
[broken remove];
NSString *id = [broken id];
switch (button) {
case 1:
@synchronized (self) {
- for (int i = 0, e = [essential_ count]; i != e; ++i) {
- Package *essential = [essential_ objectAtIndex:i];
+ for (Package *essential in essential_)
[essential install];
- }
[self resolve];
[self perform];
}
- (UIProgressHUD *) addProgressHUD {
- UIProgressHUD *hud = [[UIProgressHUD alloc] initWithWindow:window_];
+ UIProgressHUD *hud([[[UIProgressHUD alloc] initWithWindow:window_] autorelease]);
+ [window_ setUserInteractionEnabled:NO];
[hud show:YES];
- [underlay_ addSubview:hud];
+ [progress_ addSubview:hud];
return hud;
}
+- (void) removeProgressHUD:(UIProgressHUD *)hud {
+ [hud show:NO];
+ [hud removeFromSuperview];
+ [window_ setUserInteractionEnabled:YES];
+}
+
- (void) openMailToURL:(NSURL *)url {
// XXX: this makes me sad
#if 0
}
- (RVPage *) pageForURL:(NSURL *)url hasTag:(int *)tag {
- NSString *href = [url absoluteString];
-
if (tag != NULL)
tag = 0;
- if ([href isEqualToString:@"cydia://add-source"])
+ NSString *scheme([[url scheme] lowercaseString]);
+ if (![scheme isEqualToString:@"cydia"])
+ return nil;
+ NSString *path([url absoluteString]);
+ if ([path length] < 8)
+ return nil;
+ path = [path substringFromIndex:8];
+ if (![path hasPrefix:@"/"])
+ path = [@"/" stringByAppendingString:path];
+
+ if ([path isEqualToString:@"/add-source"])
return [[[AddSourceView alloc] initWithBook:book_ database:database_] autorelease];
- else if ([href isEqualToString:@"cydia://storage"])
+ else if ([path isEqualToString:@"/storage"])
return [self _pageForURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"storage" ofType:@"html"]] withClass:[BrowserView class]];
- else if ([href isEqualToString:@"cydia://sources"])
+ else if ([path isEqualToString:@"/sources"])
return [[[SourceTable alloc] initWithBook:book_ database:database_] autorelease];
- else if ([href isEqualToString:@"cydia://packages"])
+ else if ([path isEqualToString:@"/packages"])
return [[[InstalledView alloc] initWithBook:book_ database:database_] autorelease];
- else if ([href hasPrefix:@"cydia://url/"])
- return [self _pageForURL:[NSURL URLWithString:[href substringFromIndex:12]] withClass:[BrowserView class]];
- else if ([href hasPrefix:@"cydia://launch/"])
- [self launchApplicationWithIdentifier:[href substringFromIndex:15] suspended:NO];
- else if ([href hasPrefix:@"cydia://package-settings/"])
- return [[[SettingsView alloc] initWithBook:book_ database:database_ package:[href substringFromIndex:25]] autorelease];
- else if ([href hasPrefix:@"cydia://package-signature/"])
- return [[[SignatureView alloc] initWithBook:book_ database:database_ package:[href substringFromIndex:26]] autorelease];
- else if ([href hasPrefix:@"cydia://package/"])
- return [self pageForPackage:[href substringFromIndex:16]];
- else if ([href hasPrefix:@"cydia://files/"]) {
- NSString *name = [href substringFromIndex:14];
+ else if ([path hasPrefix:@"/url/"])
+ return [self _pageForURL:[NSURL URLWithString:[path substringFromIndex:5]] withClass:[BrowserView class]];
+ else if ([path hasPrefix:@"/launch/"])
+ [self launchApplicationWithIdentifier:[path substringFromIndex:8] suspended:NO];
+ else if ([path hasPrefix:@"/package-settings/"])
+ return [[[SettingsView alloc] initWithBook:book_ database:database_ package:[path substringFromIndex:18]] autorelease];
+ else if ([path hasPrefix:@"/package-signature/"])
+ return [[[SignatureView alloc] initWithBook:book_ database:database_ package:[path substringFromIndex:19]] autorelease];
+ else if ([path hasPrefix:@"/package/"])
+ return [self pageForPackage:[path substringFromIndex:9]];
+ else if ([path hasPrefix:@"/files/"]) {
+ NSString *name = [path substringFromIndex:7];
if (Package *package = [database_ packageWithName:name]) {
FileTable *files = [[[FileTable alloc] initWithBook:book_ database:database_] autorelease];
}
- (void) applicationDidFinishLaunching:(id)unused {
+ _trace();
Font12_ = [[UIFont systemFontOfSize:12] retain];
Font12Bold_ = [[UIFont boldSystemFontOfSize:12] retain];
Font14_ = [[UIFont systemFontOfSize:14] retain];
) {
[self setIdleTimerDisabled:YES];
- hud_ = [self addProgressHUD];
+ hud_ = [[self addProgressHUD] retain];
[hud_ setText:@"Reorganizing\n\nWill Automatically\nClose When Done"];
[self setStatusBarShowsProgress:YES];
bool cydia(false);
- for (size_t i(0); i != [items count]; ++i) {
- NSMutableDictionary *item([items objectAtIndex:i]);
+ for (NSMutableDictionary *item in items) {
NSString *label = [item objectForKey:@"label"];
if (label != nil && [label isEqualToString:@"Cydia"]) {
cydia = true;
}*/
int main(int argc, char *argv[]) { _pooled
+ _trace();
class_addMethod(objc_getClass("DOMNodeList"), @selector(countByEnumeratingWithState:objects:count:), (IMP) &DOMNodeList$countByEnumeratingWithState$objects$count$, "I20@0:4^{NSFastEnumerationState}8^@12I16");
bool substrate(false);
if (NSDictionary *system = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"])
Build_ = [system objectForKey:@"ProductBuildVersion"];
+ if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:@"/Applications/MobileSafari.app/Info.plist"]) {
+ Product_ = [info objectForKey:@"SafariProductVersion"];
+ Safari_ = [info objectForKey:@"CFBundleVersion"];
+ }
/*AddPreferences(@"/Applications/Preferences.app/Settings-iPhone.plist");
AddPreferences(@"/Applications/Preferences.app/Settings-iPod.plist");*/
- /*if ((Indices_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/indices.plist"]) == NULL)
- Indices_ = [[NSMutableDictionary alloc] init];*/
-
- Indices_ = [NSMutableDictionary dictionaryWithObjectsAndKeys:
- //@"http://"/*"cache.saurik.com/"*/"cydia.saurik.com/server/rating/@", @"Rating",
- @"http://"/*"cache.saurik.com/"*/"cydia.saurik.com/repotag/@", @"RepoTag",
- nil];
+ _trace();
+ Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"];
+ _trace();
- if ((Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"]) == NULL)
+ if (Metadata_ == NULL)
Metadata_ = [[NSMutableDictionary alloc] initWithCapacity:2];
else {
Settings_ = [Metadata_ objectForKey:@"Settings"];
Documents_ = [[[NSMutableArray alloc] initWithCapacity:4] autorelease];
#endif
- if (substrate && access("/Library/MobileSubstrate/MobileSubstrate.dylib", F_OK) == 0)
- dlopen("/Library/MobileSubstrate/MobileSubstrate.dylib", RTLD_LAZY | RTLD_GLOBAL);
+ if (substrate && access("/Applications/WinterBoard.app/WinterBoard.dylib", F_OK) == 0)
+ dlopen("/Applications/WinterBoard.app/WinterBoard.dylib", RTLD_LAZY | RTLD_GLOBAL);
+ /*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)
+ if (access("/User", F_OK) != 0) {
+ _trace();
system("/usr/libexec/cydia/firmware.sh");
+ _trace();
+ }
_assert([[NSFileManager defaultManager]
createDirectoryAtPath:@"/var/cache/apt/archives/partial"
Off_.Set(space_, 0.9, 0.9, 0.9, 1.0);
White_.Set(space_, 1.0, 1.0, 1.0, 1.0);
Gray_.Set(space_, 0.4, 0.4, 0.4, 1.0);
+ Green_.Set(space_, 0.0, 0.5, 0.0, 1.0);
+ Purple_.Set(space_, 0.0, 0.0, 0.7, 1.0);
+ Purplish_.Set(space_, 0.4, 0.4, 0.8, 1.0);
+ /*Purple_.Set(space_, 1.0, 0.3, 0.0, 1.0);
+ Purplish_.Set(space_, 1.0, 0.6, 0.4, 1.0); ORANGE */
+ /*Purple_.Set(space_, 1.0, 0.5, 0.0, 1.0);
+ Purplish_.Set(space_, 1.0, 0.7, 0.2, 1.0); ORANGISH */
+ /*Purple_.Set(space_, 0.5, 0.0, 0.7, 1.0);
+ Purplish_.Set(space_, 0.7, 0.4, 0.8, 1.0); PURPLE */
+
+//.93
+ InstallingColor_ = [UIColor colorWithRed:0.88f green:1.00f blue:0.88f alpha:1.00f];
+ RemovingColor_ = [UIColor colorWithRed:1.00f green:0.88f blue:0.88f alpha:1.00f];
Finishes_ = [NSArray arrayWithObjects:@"return", @"reopen", @"restart", @"reload", @"reboot", nil];
UIApplicationUseLegacyEvents(YES);
UIKeyboardDisableAutomaticAppearance();
+ _trace();
int value = UIApplicationMain(argc, argv, @"Cydia", @"Cydia");
CGColorSpaceRelease(space_);