/* #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 1
-#define ForSaurik (1 && !ForRelease)
+#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 {{{ */
@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;
NSString *description_;
NSString *label_;
NSString *origin_;
+ NSString *support_;
NSString *uri_;
NSString *distribution_;
- (NSComparisonResult) compareByNameAndType:(Source *)source;
+- (NSString *) supportForPackage:(NSString *)package;
+
- (NSDictionary *) record;
- (BOOL) trusted;
_clear(description_)
_clear(label_)
_clear(origin_)
+ _clear(support_)
_clear(version_)
_clear(defaultIcon_)
_clear(record_)
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];
}
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_;
- (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];
+ _profile(Package$initWithIterator$Metadata)
+ 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"]);
-
- 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_;
}
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 value;
if (current.end())
- value = essential && [self essential];
+ value = essential && [self essential] && [self visible];
else
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:
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];
- (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];
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 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 {
@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];
[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 {
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];
}
[packages_ removeAllObjects];
[sections_ removeAllObjects];
- for (size_t i(0); i != [packages count]; ++i) {
- Package *package([packages objectAtIndex:i]);
- if ([self hasPackage:package])
- [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 {
/* Filtered Package Table {{{ */
@interface FilteredPackageTable : PackageTable {
SEL filter_;
+ IMP imp_;
id object_;
}
}
- (bool) hasPackage:(Package *)package {
- return [package valid] && [[package performSelector:filter_ withObject:object_] boolValue];
+ _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 {
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;
}
[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 {
] 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;
+ return Queuing_ ? @"Queue" : 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;
-}
-
-- (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_;
}
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: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];
if (flipped_)
[self flipPage];
[table_ setObject:[field_ text]];
- [table_ reloadData];
+ _profile(SearchView$reloadData)
+ [table_ reloadData];
+ _end
+ PrintTimes();
[table_ resetCursor];
}
}
- (void) _reloadData {
- /*UIProgressHUD *hud = [[UIProgressHUD alloc] initWithWindow:window_];
- [hud setText:@"Reloading Data"];
- [overlay_ addSubview:hud];
- [hud show:YES];*/
+ UIView *block();
+
+ static bool loaded(false);
+ UIProgressHUD *hud([self addProgressHUD]);
+ [hud setText:(loaded ? @"Reloading Data" : @"Loading Data")];
+ loaded = true;
+
+ [database_ yieldToSelector:@selector(reloadData) withObject:nil];
+ _trace();
- [database_ reloadData];
+ [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 {
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 {
- (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];
withClass:[ManageView class]
] retain];
+ PrintTimes();
+
if (bootstrap_)
[self bootstrap];
else
if ([context isEqualToString:@"missing"])
[sheet dismiss];
- else if ([context isEqualToString:@"fixhalf"]) {
+ 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
}
- (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"];
/*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_);