/* #include Directives {{{ */
#include <Foundation/NSURL.h>
#include <UIKit/UIKit.h>
-#import <GraphicsServices/GraphicsServices.h>
+#include <GraphicsServices/GraphicsServices.h>
+
+#include <objc/objc.h>
#include <sstream>
#include <ext/stdio_filebuf.h>
#include <apt-pkg/sptr.h>
#include <sys/sysctl.h>
+#include <notify.h>
extern "C" {
#include <mach-o/nlist.h>
}
-#include <objc/objc-class.h>
+#include <stdio.h>
+#include <stdlib.h>
#include <errno.h>
#include <pcre.h>
exit(-1); \
} \
while (false)
+
+#define _not(type) ((type) ~ (type) 0)
/* }}} */
/* Miscellaneous Messages {{{ */
@interface WebView
- (void) setApplicationNameForUserAgent:(NSString *)applicationName;
+- (id) frameLoadDelegate;
+- (void) setFrameLoadDelegate:(id)delegate;
@end
@interface NSString (Cydia)
@end
/* }}} */
+#ifdef SRK_ASPEN
+#define UITable UITableView
+#endif
+
+OBJC_EXPORT const char *class_getName(Class cls);
+
/* Reset View (UIView) {{{ */
@interface UIView (CYResetView)
- (void) resetViewAnimated:(BOOL)animated;
@implementation UIView (CYResetView)
- (void) resetViewAnimated:(BOOL)animated {
- fprintf(stderr, "%s\n", self->isa->name);
+ fprintf(stderr, "%s\n", class_getName(self->isa));
_assert(false);
}
/* }}} */
static const int PulseInterval_ = 50000;
+
+const char *Firmware_ = NULL;
const char *Machine_ = NULL;
const char *SerialNumber_ = NULL;
+unsigned Major_;
+unsigned Minor_;
+unsigned BugFix_;
+
+#define FW_LEAST(major, minor, bugfix) \
+ (major < Major_ || major == Major_ && \
+ (minor < Minor_ || minor == Minor_ && \
+ bugfix <= BugFix_))
+
+bool bootstrap_ = false;
+
static NSMutableDictionary *Metadata_;
static NSMutableDictionary *Packages_;
static NSDate *now_;
+NSString *GetLastUpdate() {
+ NSDate *update = [Metadata_ objectForKey:@"LastUpdate"];
+
+ if (update == nil)
+ return @"Never or Unknown";
+
+ CFLocaleRef locale = CFLocaleCopyCurrent();
+ CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
+ CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) update);
+
+ CFRelease(formatter);
+ CFRelease(locale);
+
+ return [(NSString *) formatted autorelease];
+}
+
@protocol ProgressDelegate
- (void) setError:(NSString *)error;
- (void) setTitle:(NSString *)title;
/* }}} */
@class Package;
+@class Source;
/* Database Interface {{{ */
@interface Database : NSObject {
pkgAcquire *fetcher_;
FileFd *lock_;
SPtr<pkgPackageManager> manager_;
+ pkgSourceList *list_;
+
+ NSMutableDictionary *sources_;
+ NSMutableArray *packages_;
id delegate_;
Status status_;
- (pkgRecords *) records;
- (pkgProblemResolver *) resolver;
- (pkgAcquire &) fetcher;
+- (NSArray *) packages;
- (void) reloadData;
- (void) prepare;
- (void) upgrade;
- (void) setDelegate:(id)delegate;
+- (Source *) getSource:(const pkgCache::PkgFileIterator &)file;
@end
/* }}} */
/* Reset View {{{ */
@interface ResetView : UIView {
+ UIPushButton *configure_;
UIPushButton *reload_;
NSMutableArray *views_;
UINavigationBar *navbar_;
- (void) dealloc;
- (void) navigationBar:(UINavigationBar *)navbar poppedItem:(UINavigationItem *)item;
+- (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button;
- (id) initWithFrame:(CGRect)frame;
- (void) setDelegate:(id)delegate;
+
+- (void) configurePushed;
- (void) reloadPushed;
- (void) pushView:(UIView *)view withTitle:(NSString *)title backButtonTitle:(NSString *)back rightButton:(NSString *)right;
- (void) popViews:(unsigned)views;
-- (void) resetView;
+- (void) resetView:(BOOL)clear;
- (void) _resetView;
- (void) setPrompt;
@end
@implementation ResetView
- (void) dealloc {
+ [configure_ release];
[reload_ release];
[transition_ release];
[navbar_ release];
[views_ removeLastObject];
UIView *view([views_ lastObject]);
[view resetViewAnimated:!resetting_];
- if (!resetting_)
- [transition_ transition:2 toView:view];
- if ([views_ count] == 1)
+ if (!resetting_) {
+ [transition_ transition:2 toView:view];
[self _resetView];
+ }
+}
+
+- (void) alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button {
+ [sheet dismiss];
}
- (id) initWithFrame:(CGRect)frame {
bounds.origin.x, bounds.origin.y + navsize.height, bounds.size.width, bounds.size.height - navsize.height
)];
- //reload_ = [[UIPushButton alloc] initWithFrame:CGRectMake(284, 8, 29, 23)];
- reload_ = [[UIPushButton alloc] initWithFrame:CGRectMake(282, 5, 29, 23)];
+ //configure_ = [[UIPushButton alloc] initWithFrame:CGRectMake(15, 9, 17, 18)];
+ configure_ = [[UIPushButton alloc] initWithFrame:CGRectMake(10, 9, 17, 18)];
+ [configure_ setShowPressFeedback:YES];
+ [configure_ setImage:[UIImage applicationImageNamed:@"configure.png"]];
+ [configure_ addTarget:self action:@selector(configurePushed) forEvents:1];
+
+ //reload_ = [[UIPushButton alloc] initWithFrame:CGRectMake(288, 5, 18, 22)];
+ reload_ = [[UIPushButton alloc] initWithFrame:CGRectMake(293, 5, 18, 22)];
[reload_ setShowPressFeedback:YES];
[reload_ setImage:[UIImage applicationImageNamed:@"reload.png"]];
[reload_ addTarget:self action:@selector(reloadPushed) forEvents:1];
+ [navbar_ addSubview:configure_];
[navbar_ addSubview:reload_];
[self addSubview:transition_];
delegate_ = delegate;
}
+- (void) configurePushed {
+ UIAlertSheet *sheet = [[[UIAlertSheet alloc]
+ initWithTitle:@"Sources Unimplemented"
+ buttons:[NSArray arrayWithObjects:@"Okay", nil]
+ defaultButtonIndex:0
+ delegate:self
+ context:self
+ ] autorelease];
+
+ [sheet setBodyText:@"This feature will be implemented soon. In the mean time, you may add sources by adding .list files to '/etc/apt/sources.list.d' or modifying '/etc/apt/sources.list'."];
+ [sheet popupAlertAnimated:YES];
+}
+
- (void) reloadPushed {
[delegate_ update];
}
[navbar_ popNavigationItem];
resetting_ = false;
+ [self _resetView];
[transition_ transition:2 toView:[views_ lastObject]];
}
-- (void) resetView {
+- (void) resetView:(BOOL)clear {
resetting_ = true;
- if ([[navbar_ navigationItems] count] == 1)
- [self _resetView];
- else do
- [navbar_ popNavigationItem];
- while ([[navbar_ navigationItems] count] != 1);
+
+ if ([views_ count] > 1) {
+ [navbar_ disableAnimation];
+ while ([views_ count] != (clear ? 1 : 2))
+ [navbar_ popNavigationItem];
+ [navbar_ enableAnimation];
+ if (!clear)
+ [navbar_ popNavigationItem];
+ }
+
resetting_ = false;
- [transition_ transition:0 toView:[views_ lastObject]];
+ [self _resetView];
+ [transition_ transition:(clear ? 0 : 2) toView:[views_ lastObject]];
}
- (void) _resetView {
+ [navbar_ showButtonsWithLeftTitle:nil rightTitle:nil];
}
- (void) setPrompt {
- NSDate *update = [Metadata_ objectForKey:@"LastUpdate"];
-
- CFLocaleRef locale = CFLocaleCopyCurrent();
- CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
- CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) update);
-
- [navbar_ setPrompt:[NSString stringWithFormat:@"Last Updated: %@", (NSString *) formatted]];
-
- CFRelease(formatter);
- CFRelease(formatted);
- CFRelease(locale);
+ [navbar_ setPrompt:[NSString stringWithFormat:@"Last Updated: %@", GetLastUpdate()]];
}
@end
NSMutableArray *upgrading = [NSMutableArray arrayWithCapacity:16];
NSMutableArray *removing = [NSMutableArray arrayWithCapacity:16];
- bool essential(false);
+ bool install(false);
+ bool upgrade(false);
+ bool remove(false);
pkgCacheFile &cache([database_ cache]);
for (pkgCache::PkgIterator iterator = cache->PkgBegin(); !iterator.end(); ++iterator) {
NSString *name([NSString stringWithCString:iterator.Name()]);
- if (cache[iterator].NewInstall())
+ bool essential((iterator->Flags & pkgCache::Flag::Essential) != 0);
+
+ if (cache[iterator].NewInstall()) {
+ if (essential)
+ install = true;
[installing addObject:name];
- else if (cache[iterator].Upgrade())
+ } else if (cache[iterator].Upgrade()) {
+ if (essential)
+ upgrade = true;
[upgrading addObject:name];
- else if (cache[iterator].Delete()) {
+ } else if (cache[iterator].Delete()) {
+ if (essential)
+ remove = true;
[removing addObject:name];
- if ((iterator->Flags & pkgCache::Flag::Essential) != 0)
- essential = true;
}
}
- if (!essential)
+ if (!remove)
essential_ = nil;
else {
essential_ = [[UIAlertSheet alloc]
@end
/* }}} */
+/* Source Class {{{ */
+@interface Source : NSObject {
+ NSString *description_;
+ NSString *label_;
+ NSString *origin_;
+
+ NSString *uri_;
+ NSString *distribution_;
+ NSString *type_;
+ NSString *version_;
+
+ NSString *defaultIcon_;
+
+ BOOL trusted_;
+}
+
+- (void) dealloc;
+
+- (Source *) initWithMetaIndex:(metaIndex *)index;
+
+- (BOOL) trusted;
+
+- (NSString *) uri;
+- (NSString *) distribution;
+- (NSString *) type;
+
+- (NSString *) description;
+- (NSString *) label;
+- (NSString *) origin;
+- (NSString *) version;
+
+- (NSString *) defaultIcon;
+@end
+
+@implementation Source
+
+- (void) dealloc {
+ [uri_ release];
+ [distribution_ release];
+ [type_ release];
+
+ if (description_ != nil)
+ [description_ release];
+ if (label_ != nil)
+ [label_ release];
+ if (origin_ != nil)
+ [origin_ release];
+ if (version_ != nil)
+ [version_ release];
+
+ [super dealloc];
+}
+
+- (Source *) initWithMetaIndex:(metaIndex *)index {
+ if ((self = [super init]) != nil) {
+ trusted_ = index->IsTrusted();
+
+ uri_ = [[NSString stringWithCString:index->GetURI().c_str()] retain];
+ distribution_ = [[NSString stringWithCString:index->GetDist().c_str()] retain];
+ type_ = [[NSString stringWithCString:index->GetType()] retain];
+
+ description_ = nil;
+ label_ = nil;
+ origin_ = nil;
+
+ 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 stringWithCString:value.c_str()] retain];
+ else if (name == "Description")
+ description_ = [[NSString stringWithCString:value.c_str()] retain];
+ else if (name == "Label")
+ label_ = [[NSString stringWithCString:value.c_str()] retain];
+ else if (name == "Origin")
+ origin_ = [[NSString stringWithCString:value.c_str()] retain];
+ else if (name == "Version")
+ version_ = [[NSString stringWithCString:value.c_str()] retain];
+ }
+ }
+ } return self;
+}
+
+- (BOOL) trusted {
+ return trusted_;
+}
+
+- (NSString *) uri {
+ return uri_;
+}
+
+- (NSString *) distribution {
+ return distribution_;
+}
+
+- (NSString *) type {
+ return type_;
+}
+
+- (NSString *) description {
+ return description_;
+}
+
+- (NSString *) label {
+ return label_;
+}
+
+- (NSString *) origin {
+ return origin_;
+}
+
+- (NSString *) version {
+ return version_;
+}
+
+- (NSString *) defaultIcon {
+ return defaultIcon_;
+}
+
+@end
+/* }}} */
/* Package Class {{{ */
NSString *Scour(const char *field, const char *begin, const char *end) {
size_t i(0), l(strlen(field));
Database *database_;
pkgCache::VerIterator version_;
pkgCache::VerFileIterator file_;
+ Source *source_;
NSString *latest_;
NSString *installed_;
NSString *name_;
NSString *tagline_;
NSString *icon_;
- NSString *bundle_;
+ NSString *website_;
}
- (void) dealloc;
- (NSString *) latest;
- (NSString *) installed;
- (BOOL) upgradable;
+- (BOOL) essential;
+- (BOOL) broken;
- (NSString *) id;
- (NSString *) name;
- (NSString *) tagline;
- (NSString *) icon;
-- (NSString *) bundle;
+- (NSString *) website;
+
+- (Source *) source;
- (BOOL) matches:(NSString *)text;
[tagline_ release];
if (icon_ != nil)
[icon_ release];
- if (bundle_ != nil)
- [bundle_ release];
+ if (website_ != nil)
+ [website_ release];
+
+ if (source_ != nil)
+ [source_ release];
+
[super dealloc];
}
icon_ = Scour("Icon", begin, end);
if (icon_ != nil)
icon_ = [icon_ retain];
- bundle_ = Scour("Bundle", begin, end);
- if (bundle_ != nil)
- bundle_ = [bundle_ retain];
+ website_ = Scour("Website", begin, end);
+ if (website_ != nil)
+ website_ = [website_ retain];
+
+ source_ = [[database_ getSource:file_.File()] retain];
NSMutableDictionary *metadata = [Packages_ objectForKey:id_];
- if (metadata == nil) {
+ if (metadata == nil || [metadata count] == 0) {
metadata = [NSMutableDictionary dictionaryWithObjectsAndKeys:
now_, @"FirstSeen",
nil];
}
- (NSString *) section {
- return [[NSString stringWithCString:iterator_.Section()] stringByReplacingCharacter:'_' withCharacter:' '];
+ const char *section = iterator_.Section();
+ return section == NULL ? nil : [[NSString stringWithCString:section] stringByReplacingCharacter:'_' withCharacter:' '];
}
- (Address *) maintainer {
}
- (NSString *) index {
- return [[[self name] substringToIndex:1] uppercaseString];
+ NSString *index = [[[self name] substringToIndex:1] uppercaseString];
+ return [index length] != 0 && isalpha([index characterAtIndex:0]) ? index : @"123";
}
- (NSDate *) seen {
}
- (BOOL) upgradable {
- NSString *installed = [self installed];
- return installed != nil && [[self latest] compare:installed] != NSOrderedSame ? YES : NO;
+ if (NSString *installed = [self installed])
+ return [[self latest] compare:installed] != NSOrderedSame ? YES : NO;
+ else
+ return [self essential];
+}
+
+- (BOOL) essential {
+ return (iterator_->Flags & pkgCache::Flag::Essential) == 0 ? NO : YES;
+}
+
+- (BOOL) broken {
+ return (*[database_ cache])[iterator_].InstBroken();
}
- (NSString *) id {
return icon_;
}
-- (NSString *) bundle {
- return bundle_;
+- (NSString *) website {
+ return website_;
+}
+
+- (Source *) source {
+ return source_;
}
- (BOOL) matches:(NSString *)text {
NSRange range;
+ range = [[self id] rangeOfString:text options:NSCaseInsensitiveSearch];
+ if (range.location != NSNotFound)
+ return YES;
+
range = [[self name] rangeOfString:text options:NSCaseInsensitiveSearch];
if (range.location != NSNotFound)
return YES;
}
- (NSComparisonResult) compareByName:(Package *)package {
- return [[self name] caseInsensitiveCompare:[package name]];
+ NSString *lhs = [self name];
+ NSString *rhs = [package name];
+
+ if ([lhs length] != 0 && [rhs length] != 0) {
+ unichar lhc = [lhs characterAtIndex:0];
+ unichar rhc = [rhs characterAtIndex:0];
+
+ if (isalpha(lhc) && !isalpha(rhc))
+ return NSOrderedAscending;
+ else if (!isalpha(lhc) && isalpha(rhc))
+ return NSOrderedDescending;
+ }
+
+ return [lhs caseInsensitiveCompare:rhs];
}
- (NSComparisonResult) compareBySectionAndName:(Package *)package {
- NSComparisonResult result = [[self section] caseInsensitiveCompare:[package section]];
- if (result != NSOrderedSame)
- return result;
+ NSString *lhs = [self section];
+ NSString *rhs = [package section];
+
+ if (lhs == NULL && rhs != NULL)
+ return NSOrderedAscending;
+ else if (lhs != NULL && rhs == NULL)
+ return NSOrderedDescending;
+ else if (lhs != NULL && rhs != NULL) {
+ NSComparisonResult result = [lhs compare:rhs];
+ if (result != NSOrderedSame)
+ return result;
+ }
+
return [self compareByName:package];
}
}
- (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table {
- return 2;
+ return 3;
}
- (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group {
switch (group) {
case 0: return nil;
- case 1: return @"Details";
- case 2: return @"Source";
+ case 1: return @"Package Details";
+ case 2: return @"Source Information";
default: _assert(false);
}
- (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group {
switch (group) {
- case 0: return 2;
+ case 0: return [package_ website] == nil ? 2 : 3;
case 1: return 5;
- case 2: return 0;
+ case 2: return 3;
default: _assert(false);
}
[cell addSubview:description_];
break;
+ case 2:
+ [cell setTitle:@"More Information"];
+ [cell setShowDisclosure:YES];
+ [cell setShowSelection:YES];
+ break;
+
default: _assert(false);
} break;
[cell setValue:(installed == nil ? @"n/a" : installed)];
} break;
- case 2:
+ case 2: {
[cell setTitle:@"Section"];
- [cell setValue:[package_ section]];
- break;
+ NSString *section([package_ section]);
+ [cell setValue:(section == nil ? @"n/a" : section)];
+ } break;
case 3:
[cell setTitle:@"Expanded Size"];
} break;
case 2: switch (row) {
+ case 0:
+ [cell setTitle:[[package_ source] label]];
+ [cell setValue:[[package_ source] version]];
+ break;
+
+ case 1:
+ [cell setValue:[[package_ source] description]];
+ break;
+
+ case 2:
+ [cell setTitle:@"Origin"];
+ [cell setValue:[[package_ source] origin]];
+ break;
+
+ default: _assert(false);
} break;
default: _assert(false);
}
- (void) tableRowSelected:(NSNotification *)notification {
- printf("%d\n", [table_ selectedRow]);
- switch ([table_ selectedRow]) {
- case 8:
- [delegate_ openURL:[NSURL URLWithString:[NSString stringWithFormat:@"mailto:%@?subject=%@",
- [[package_ maintainer] email],
- [[NSString stringWithFormat:@"regarding apt package \"%@\"", [package_ name]] stringByAddingPercentEscapes]
- ]]];
- break;
- }
+ int row = [table_ selectedRow];
+ NSString *website = [package_ website];
+
+ if (row == (website == nil ? 8 : 9))
+ [delegate_ openURL:[NSURL URLWithString:[NSString stringWithFormat:@"mailto:%@?subject=%@",
+ [[package_ maintainer] email],
+ [[NSString stringWithFormat:@"regarding apt package \"%@\"", [package_ name]] stringByAddingPercentEscapes]
+ ]]];
+ else if (website != nil && row == 3)
+ [delegate_ openURL:[NSURL URLWithString:website]];
}
- (Package *) package {
/* }}} */
/* Package Cell {{{ */
@interface PackageCell : UITableCell {
+ UIImageView *icon_;
UITextLabel *name_;
- UITextLabel *version_;
UITextLabel *description_;
+ UITextLabel *source_;
+ UITextLabel *version_;
+ UIImageView *trusted_;
SEL versioner_;
}
@implementation PackageCell
- (void) dealloc {
+ [icon_ release];
[name_ release];
- [version_ release];
[description_ release];
+ [source_ release];
+ [version_ release];
+ [trusted_ release];
[super dealloc];
}
CGColor clear(space, 0, 0, 0, 0);
- name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(12, 7, 250, 25)];
+ icon_ = [[UIImageView alloc] initWithFrame:CGRectMake(10, 10, 30, 30)];
+
+ name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 12, 240, 25)];
[name_ setBackgroundColor:clear];
[name_ setFont:bold];
- version_ = [[UIRightTextLabel alloc] initWithFrame:CGRectMake(286, 7, 70, 25)];
+ description_ = [[UITextLabel alloc] initWithFrame:CGRectMake(12, 46, 280, 20)];
+ [description_ setBackgroundColor:clear];
+ [description_ setFont:small];
+
+ source_ = [[UITextLabel alloc] initWithFrame:CGRectMake(12, 72, 225, 20)];
+ [source_ setBackgroundColor:clear];
+ [source_ setFont:large];
+
+ version_ = [[UIRightTextLabel alloc] initWithFrame:CGRectMake(286, 69, 70, 25)];
[version_ setBackgroundColor:clear];
[version_ setFont:large];
- description_ = [[UITextLabel alloc] initWithFrame:CGRectMake(13, 35, 315, 20)];
- [description_ setBackgroundColor:clear];
- [description_ setFont:small];
+ //trusted_ = [[UIImageView alloc] initWithFrame:CGRectMake(278, 7, 16, 16)];
+ trusted_ = [[UIImageView alloc] initWithFrame:CGRectMake(30, 30, 16, 16)];
+ [trusted_ setImage:[UIImage applicationImageNamed:@"trusted.png"]];
+ [self addSubview:icon_];
[self addSubview:name_];
- [self addSubview:version_];
[self addSubview:description_];
+ [self addSubview:source_];
+ [self addSubview:version_];
CGColorSpaceRelease(space);
}
- (void) setPackage:(Package *)package {
+ Source *source = [package source];
+
+ UIImage *image = nil;
+ if (NSString *icon = [package icon])
+ image = [UIImage imageAtPath:[icon substringFromIndex:6]];
+ if (image == nil) if (NSString *icon = [source defaultIcon])
+ image = [UIImage imageAtPath:[icon substringFromIndex:6]];
+ if (image == nil)
+ image = [UIImage applicationImageNamed:@"unknown.png"];
+
+ [icon_ setImage:image];
+ [icon_ zoomToScale:0.5f];
+ [icon_ setFrame:CGRectMake(10, 10, 30, 30)];
+
[name_ setText:[package name]];
[version_ setText:[package latest]];
[description_ setText:[package tagline]];
+
+ NSString *label;
+ bool trusted;
+
+ if (source != nil) {
+ label = [source label];
+ trusted = [source trusted];
+ } else if ([[package id] isEqualToString:@"firmware"]) {
+ label = @"Apple";
+ trusted = false;
+ } else {
+ label = @"Unknown/Local";
+ trusted = false;
+ }
+
+ [source_ setText:[NSString stringWithFormat:@"from %@", label]];
+
+ [trusted_ removeFromSuperview];
+ if (trusted)
+ [self addSubview:trusted_];
}
- (void) _setSelected:(float)fraction {
1.0);
[name_ setColor:black];
- [version_ setColor:blue];
[description_ setColor:gray];
+ [source_ setColor:black];
+ [version_ setColor:blue];
CGColorSpaceRelease(space);
}
fetcher_ = NULL;
lock_ = NULL;
+ sources_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
+ packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
+
int fds[2];
_assert(pipe(fds) != -1);
return *fetcher_;
}
+- (NSArray *) packages {
+ return packages_;
+}
+
- (void) reloadData {
_error->Discard();
+ delete list_;
manager_ = NULL;
delete lock_;
delete fetcher_;
delete resolver_;
delete records_;
cache_.Close();
- _assert(cache_.Open(progress_, true));
+
+ if (!cache_.Open(progress_, true)) {
+ fprintf(stderr, "repairing corrupted database...\n");
+ _error->Discard();
+ [self update];
+ _assert(cache_.Open(progress_, true));
+ }
+
+ now_ = [NSDate date];
+
records_ = new pkgRecords(cache_);
resolver_ = new pkgProblemResolver(cache_);
fetcher_ = new pkgAcquire(&status_);
lock_ = NULL;
+
+ list_ = new pkgSourceList();
+ _assert(list_->ReadMainList());
+
+ [sources_ removeAllObjects];
+ for (pkgSourceList::const_iterator source = list_->begin(); source != list_->end(); ++source) {
+ std::vector<pkgIndexFile *> *indices = (*source)->GetIndexFiles();
+ for (std::vector<pkgIndexFile *>::const_iterator index = indices->begin(); index != indices->end(); ++index)
+ [sources_
+ setObject:[[[Source alloc] initWithMetaIndex:*source] autorelease]
+ forKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(*index)]
+ ];
+ }
+
+ [packages_ removeAllObjects];
+ for (pkgCache::PkgIterator iterator = cache_->PkgBegin(); !iterator.end(); ++iterator)
+ if (Package *package = [Package packageWithIterator:iterator database:self])
+ if ([package source] != nil || [package installed] != nil)
+ [packages_ addObject:package];
}
- (void) prepare {
progress_.setDelegate(delegate);
}
+- (Source *) getSource:(const pkgCache::PkgFileIterator &)file {
+ pkgIndexFile *index(NULL);
+ list_->FindIndex(file, index);
+ return [sources_ objectForKey:[NSNumber numberWithLong:reinterpret_cast<uintptr_t>(index)]];
+}
+
@end
/* }}} */
- (void) dealloc;
+- (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
+
- (ProgressView *) initWithFrame:(struct CGRect)frame delegate:(id)delegate;
- (void) setContentView:(UIView *)view;
- (void) resetView;
- (void) dealloc {
[view_ release];
- [background_ release];
+ if (background_ != nil)
+ [background_ release];
[transition_ release];
[overlay_ release];
[navbar_ release];
[super dealloc];
}
+- (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
+ if (bootstrap_ && from == overlay_ && to == view_)
+ exit(0);
+}
+
- (ProgressView *) initWithFrame:(struct CGRect)frame delegate:(id)delegate {
if ((self = [super initWithFrame:frame]) != nil) {
delegate_ = delegate;
CGColor white(space, 1.0, 1.0, 1.0, 1.0);
CGColor clear(space, 0.0, 0.0, 0.0, 0.0);
- background_ = [[UIView alloc] initWithFrame:[self bounds]];
- [background_ setBackgroundColor:black];
- [self addSubview:background_];
-
transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]];
- [self addSubview:transition_];
+ [transition_ setDelegate:self];
overlay_ = [[UIView alloc] initWithFrame:[transition_ bounds]];
+ if (bootstrap_)
+ [overlay_ setBackgroundColor:black];
+ else {
+ background_ = [[UIView alloc] initWithFrame:[self bounds]];
+ [background_ setBackgroundColor:black];
+ [self addSubview:background_];
+ }
+
+ [self addSubview:transition_];
+
CGSize navsize = [UINavigationBar defaultSize];
CGRect navrect = {{0, 0}, navsize};
}
- (float) table:(UITable *)table heightForRow:(int)row {
- return 64;
+ return 100;
}
- (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
CGColor clear(space, 0, 0, 0, 0);
CGColor white(space, 1, 1, 1, 1);
- name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(47, 9, 250, 25)];
+ name_ = [[UITextLabel alloc] initWithFrame:CGRectMake(48, 9, 250, 25)];
[name_ setBackgroundColor:clear];
[name_ setFont:bold];
[name_ setText:@"All Packages"];
[count_ setText:nil];
} else {
- [name_ setText:[section name]];
+ NSString *name = [section name];
+ [name_ setText:(name == nil ? @"(No Section)" : name)];
[count_ setText:[NSString stringWithFormat:@"%d", [section count]]];
}
}
Package *package = [packages_ objectAtIndex:offset];
NSString *name = [package section];
- if (section == nil || ![[section name] isEqual:name]) {
+ if (section == nil || name != nil && ![[section name] isEqual:name]) {
section = [[[Section alloc] initWithName:name row:offset] autorelease];
- if ([name isEqualToString:section_])
+ if (name == nil || [name isEqualToString:section_])
nsection = section;
[sections addObject:section];
}
else if (package_ != nil)
++views;
- if (nsection != nil)
+ if (table_ != nil && section_ == nil)
+ [table_ setPackages:packages_];
+ else if (nsection != nil)
[table_ setPackages:[nsection packages]];
else if (section_ != nil)
++views;
- [self popViews:views];
+ if (views != 0)
+ [self popViews:views];
[self setPrompt];
}
}
- (float) table:(UITable *)table heightForRow:(int)row {
- return 64;
+ return 100;
}
- (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col reusing:(UITableCell *)reusing {
}
- (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button {
- if (button == 1)
- [delegate_ upgrade];
+ switch (button) {
+ case 0:
+ [[view_ package] install];
+ [delegate_ resolve];
+ [delegate_ perform];
+ break;
+
+ case 1:
+ [delegate_ upgrade];
+ break;
+ }
}
- (void) packageTable:(id)table packageSelected:(Package *)package {
else {
NSDate *seen = [package seen];
- CFLocaleRef locale = CFLocaleCopyCurrent();
- CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
- CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen);
-
- NSString *name = (NSString *) formatted;
+ NSString *name;
+ CFStringRef formatted = NULL;
+
+ if (seen == nil)
+ name = @"n/a ?";
+ else {
+ CFLocaleRef locale = CFLocaleCopyCurrent();
+ CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
+ formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen);
+ name = (NSString *) formatted;
+ CFRelease(formatter);
+ CFRelease(locale);
+ }
if (section == nil || ![[section name] isEqual:name]) {
section = [[[Section alloc] initWithName:name row:offset] autorelease];
[section addPackage:package];
- CFRelease(formatter);
- CFRelease(formatted);
- CFRelease(locale);
+ if (formatted != NULL)
+ CFRelease(formatted);
}
}
[view_ setPackage:npackage];
else if (package_ != nil)
[self popViews:1];
- if ([views_ count] == 1)
- [self _resetView];
+ [self _resetView];
[self setPrompt];
}
- (void) _resetView {
- [navbar_ showButtonsWithLeftTitle:(count_ == 0 ? nil : @"Upgrade All") rightTitle:nil];
- [super _resetView];
+ if ([views_ count] == 1)
+ [navbar_ showButtonsWithLeftTitle:(count_ == 0 ? nil : @"Upgrade All") rightTitle:nil];
}
- (size_t) count {
/* XXX: for the love of god just fix this */
[navbar_ removeFromSuperview];
+ [reload_ removeFromSuperview];
+ [configure_ removeFromSuperview];
[self addSubview:navbar_];
+ [self addSubview:reload_];
+ [self addSubview:configure_];
} return self;
}
SearchView *search_;
bool restart_;
+ unsigned tag_;
UIKeyboard *keyboard_;
}
- (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old;
+- (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame;
+
- (void) applicationWillSuspend;
- (void) applicationDidFinishLaunching:(id)unused;
@end
timeoutInterval:30.0
];
+ [request addValue:[NSString stringWithCString:Firmware_] forHTTPHeaderField:@"X-Firmware"];
[request addValue:[NSString stringWithCString:Machine_] forHTTPHeaderField:@"X-Machine"];
[request addValue:[NSString stringWithCString:SerialNumber_] forHTTPHeaderField:@"X-Serial-Number"];
[webview_ loadRequest:request];
- [indicator_ startAnimation];
}
- (void) reloadData:(BOOL)reset {
[Metadata_ setObject:Packages_ forKey:@"Packages"];
}
- now_ = [NSDate date];
-
- NSMutableArray *packages = [NSMutableArray arrayWithCapacity:count];
- for (pkgCache::PkgIterator iterator = [database_ cache]->PkgBegin(); !iterator.end(); ++iterator)
- if (Package *package = [Package packageWithIterator:iterator database:database_])
- [packages addObject:package];
+ NSArray *packages = [database_ packages];
[install_ setPackages:packages];
[changes_ setPackages:packages];
[manage_ setPackages:packages];
[search_ setPackages:packages];
- //[self setPrompt];
if (size_t count = [changes_ count]) {
NSString *badge([[NSNumber numberWithInt:count] stringValue]);
[buttonbar_ setBadgeValue:badge forButton:3];
- [buttonbar_ setBadgeAnimated:YES forButton:3];
+ if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
+ [buttonbar_ setBadgeAnimated:YES forButton:3];
[self setApplicationBadge:badge];
} else {
[buttonbar_ setBadgeValue:nil forButton:3];
- [buttonbar_ setBadgeAnimated:NO forButton:3];
+ if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
+ [buttonbar_ setBadgeAnimated:NO forButton:3];
[self removeApplicationBadge];
}
}
- (void) setPrompt {
- NSDate *update = [Metadata_ objectForKey:@"LastUpdate"];
-
- CFLocaleRef locale = CFLocaleCopyCurrent();
- CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, locale, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
- CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) update);
-
- [navbar_ setPrompt:[NSString stringWithFormat:@"Last Updated: %@", (NSString *) formatted]];
-
- CFRelease(formatter);
- CFRelease(formatted);
- CFRelease(locale);
+ [navbar_ setPrompt:[NSString stringWithFormat:@"Last Updated: %@", GetLastUpdate()]];
}
- (void) resolve {
- (void) perform {
[database_ prepare];
- confirm_ = [[ConfirmationView alloc] initWithView:underlay_ database:database_ delegate:self];
+
+ if ([database_ cache]->BrokenCount() == 0)
+ confirm_ = [[ConfirmationView alloc] initWithView:underlay_ database:database_ delegate:self];
+ else {
+ NSMutableArray *broken = [NSMutableArray arrayWithCapacity:16];
+ NSArray *packages = [database_ packages];
+
+ for (size_t i(0); i != [packages count]; ++i) {
+ Package *package = [packages objectAtIndex:i];
+ if ([package broken])
+ [broken addObject:[package name]];
+ }
+
+ UIAlertSheet *sheet = [[[UIAlertSheet alloc]
+ initWithTitle:[NSString stringWithFormat:@"%d Broken Packages", [database_ cache]->BrokenCount()]
+ buttons:[NSArray arrayWithObjects:@"Okay", nil]
+ defaultButtonIndex:0
+ delegate:self
+ context:self
+ ] autorelease];
+
+ [sheet setBodyText:[NSString stringWithFormat:@"The following packages have unmet dependencies:\n\n%@", [broken componentsJoinedByString:@"\n"]]];
+ [sheet popupAlertAnimated:YES];
+
+ [self reloadData:NO];
+ }
}
- (void) upgrade {
];
}
+- (void) bootstrap_ {
+ [database_ update];
+ [database_ upgrade];
+ [database_ prepare];
+ [database_ perform];
+}
+
+- (void) bootstrap {
+ [progress_
+ detachNewThreadSelector:@selector(bootstrap_)
+ toTarget:self
+ withObject:nil
+ title:@"Bootstrap Install..."
+ ];
+}
+
- (void) update {
[progress_
detachNewThreadSelector:@selector(update)
- (void) buttonBarItemTapped:(id)sender {
UIView *view;
+ unsigned tag = [sender tag];
- switch ([sender tag]) {
+ switch (tag) {
case 1: view = featured_; break;
case 2: view = install_; break;
case 3: view = changes_; break;
_assert(false);
}
- if ([view respondsToSelector:@selector(resetView)])
- [(id) view resetView];
+ if ([view respondsToSelector:@selector(resetView:)])
+ [(id) view resetView:(tag == tag_ ? NO : YES)];
+ tag_ = tag;
[transition_ transition:0 toView:view];
}
-- (void) view:(UIView *)view didSetFrame:(CGRect)frame oldFrame:(CGRect)old {
+- (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old {
[scroller_ setContentSize:frame.size];
[indicator_ stopAnimation];
}
+- (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame {
+ [navbar_ setPrompt:title];
+}
+
+- (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame {
+ [navbar_ setPrompt:@"Loading..."];
+ [indicator_ startAnimation];
+}
+
- (void) applicationWillSuspend {
if (restart_)
- system("launchctl stop com.apple.SpringBoard");
+ if (FW_LEAST(1,1,3))
+ notify_post("com.apple.language.changed");
+ else
+ system("launchctl stop com.apple.SpringBoard");
+
+ [super applicationWillSuspend];
}
- (void) applicationDidFinishLaunching:(id)unused {
confirm_ = nil;
restart_ = false;
+ tag_ = 1;
- _trace();
CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
window_ = [[UIWindow alloc] initWithContentRect:screenrect];
[progress_ setContentView:underlay_];
overlay_ = [[UIView alloc] initWithFrame:[underlay_ bounds]];
- [underlay_ addSubview:overlay_];
+
+ if (!bootstrap_)
+ [underlay_ addSubview:overlay_];
transition_ = [[UITransitionView alloc] initWithFrame:CGRectMake(
0, 0, screenrect.size.width, screenrect.size.height - 48
[navbar_ setBarStyle:1];
[navbar_ setDelegate:self];
- [navbar_ setPrompt:@"Welcome to Cydia Packager"];
[navbar_ showButtonsWithLeftTitle:@"About" rightTitle:@"Reload"];
[scroller_ setScrollDecelerationFactor:0.99];
[scroller_ setDelegate:self];
- webview_ = [[UIWebView alloc] initWithFrame:[scroller_ bounds]];
+ CGRect webrect = [scroller_ bounds];
+ webrect.size.height = 0;
+
+ webview_ = [[UIWebView alloc] initWithFrame:webrect];
[scroller_ addSubview:webview_];
[webview_ setTilingEnabled:YES];
[buttonbar_ showSelectionForButton:1];
[transition_ transition:0 toView:featured_];
- _trace();
[overlay_ addSubview:buttonbar_];
- _trace();
[UIKeyboard initImplementationNow];
- _trace();
CGRect edtrect = [overlay_ bounds];
edtrect.origin.y += navsize.height;
edtrect.size.height -= navsize.height;
- _trace();
CGSize keysize = [UIKeyboard defaultSize];
CGRect keyrect = {{0, [overlay_ bounds].size.height - keysize.height}, keysize};
keyboard_ = [[UIKeyboard alloc] initWithFrame:keyrect];
- _trace();
database_ = [[Database alloc] init];
[database_ setDelegate:progress_];
- _trace();
install_ = [[InstallView alloc] initWithFrame:[transition_ bounds]];
[install_ setDelegate:self];
- _trace();
changes_ = [[ChangesView alloc] initWithFrame:[transition_ bounds]];
[changes_ setDelegate:self];
- _trace();
manage_ = [[ManageView alloc] initWithFrame:[transition_ bounds]];
[manage_ setDelegate:self];
- _trace();
search_ = [[SearchView alloc] initWithFrame:[transition_ bounds]];
[search_ setDelegate:self];
- _trace();
[self reloadData:NO];
- _trace();
- [progress_ resetView];
- _trace();
Package *package([database_ packageWithName:@"cydia"]);
- NSString *application = package == nil ? @"Cydia" : [NSString stringWithFormat:@"Cydia/%@", [package installed]];
+ NSString *application = package == nil ? @"Cydia" : [NSString
+ stringWithFormat:@"Cydia/%@",
+ [package installed]
+ ];
+
WebView *webview = [webview_ webView];
[webview setApplicationNameForUserAgent:application];
+ [webview setFrameLoadDelegate:self];
- _trace();
url_ = [NSURL URLWithString:@"http://cydia.saurik.com/"];
[self loadNews];
- _trace();
+
+ [progress_ resetView];
+
+ if (bootstrap_)
+ [self bootstrap];
}
- (void) showKeyboard:(BOOL)show {
if (nl[0].n_type != N_UNDF)
*(int *) nl[0].n_value = 0;
+ bootstrap_ = argc > 1 && strcmp(argv[1], "--bootstrap") == 0;
+
setuid(0);
setgid(0);
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ if (NSDictionary *sysver = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]) {
+ if (NSString *prover = [sysver valueForKey:@"ProductVersion"]) {
+ Firmware_ = strdup([prover cString]);
+ NSArray *versions = [prover componentsSeparatedByString:@"."];
+ int count = [versions count];
+ Major_ = count > 0 ? [[versions objectAtIndex:0] intValue] : 0;
+ Minor_ = count > 1 ? [[versions objectAtIndex:1] intValue] : 0;
+ BugFix_ = count > 2 ? [[versions objectAtIndex:2] intValue] : 0;
+ }
+ }
+
size_t size;
sysctlbyname("hw.machine", NULL, &size, NULL, 0);
char *machine = new char[size];
IOObjectRelease(service);
}
- AddPreferences(@"/Applications/Preferences.app/Settings-iPhone.plist");
- AddPreferences(@"/Applications/Preferences.app/Settings-iPod.plist");
+ /*AddPreferences(@"/Applications/Preferences.app/Settings-iPhone.plist");
+ AddPreferences(@"/Applications/Preferences.app/Settings-iPod.plist");*/
if ((Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"]) == NULL)
Metadata_ = [[NSMutableDictionary alloc] initWithCapacity:2];
else
Packages_ = [Metadata_ objectForKey:@"Packages"];
+ setenv("CYDIA", "", _not(int));
+ if (access("/User", F_OK) != 0)
+ system("/usr/libexec/cydia/firmware.sh");
+ system("dpkg --configure -a");
+
UIApplicationMain(argc, argv, [Cydia class]);
[pool release];
return 0;