diff options
-rw-r--r-- | Cydia.mm | 1316 | ||||
-rw-r--r-- | makefile | 10 |
2 files changed, 1326 insertions, 0 deletions
diff --git a/Cydia.mm b/Cydia.mm new file mode 100644 index 0000000..7b7820b --- /dev/null +++ b/Cydia.mm @@ -0,0 +1,1316 @@ +/* #include Directives {{{ */ +#include <UIKit/UIKit.h> +#import <GraphicsServices/GraphicsServices.h> + +#include <apt-pkg/acquire.h> +#include <apt-pkg/acquire-item.h> +#include <apt-pkg/algorithms.h> +#include <apt-pkg/cachefile.h> +#include <apt-pkg/configuration.h> +#include <apt-pkg/error.h> +#include <apt-pkg/init.h> +#include <apt-pkg/pkgrecords.h> +#include <apt-pkg/sourcelist.h> + +#include <pcre.h> +#include <string.h> +/* }}} */ +/* Extension Keywords {{{ */ +#define _trace() printf("_trace()@%s:%u[%s]\n", __FILE__, __LINE__, __FUNCTION__) + +#define _assert(test) do \ + if (!(test)) { \ + printf("_assert(%s)@%s:%u[%s]\n", #test, __FILE__, __LINE__, __FUNCTION__); \ + exit(-1); \ + } \ +while (false) +/* }}} */ + +/* Status Delegation {{{ */ +class Status : + public pkgAcquireStatus +{ + private: + id delegate_; + + public: + Status() : + delegate_(nil) + { + } + + void setDelegate(id delegate) { + delegate_ = delegate; + } + + virtual bool MediaChange(std::string media, std::string drive) { + return false; + } + + virtual void IMSHit(pkgAcquire::ItemDesc &item) { + [delegate_ performSelectorOnMainThread:@selector(setStatusIMSHit) withObject:nil waitUntilDone:YES]; + } + + virtual void Fetch(pkgAcquire::ItemDesc &item) { + [delegate_ performSelectorOnMainThread:@selector(setStatusFetch) withObject:nil waitUntilDone:YES]; + } + + virtual void Done(pkgAcquire::ItemDesc &item) { + [delegate_ performSelectorOnMainThread:@selector(setStatusDone) withObject:nil waitUntilDone:YES]; + } + + virtual void Fail(pkgAcquire::ItemDesc &item) { + [delegate_ performSelectorOnMainThread:@selector(setStatusFail) withObject:nil waitUntilDone:YES]; + } + + virtual bool Pulse(pkgAcquire *Owner) { + [delegate_ performSelectorOnMainThread:@selector(setStatusPulse) withObject:nil waitUntilDone:YES]; + return true; + } + + virtual void Start() { + [delegate_ performSelectorOnMainThread:@selector(setStatusStart) withObject:nil waitUntilDone:YES]; + } + + virtual void Stop() { + [delegate_ performSelectorOnMainThread:@selector(setStatusStop) withObject:nil waitUntilDone:YES]; + } +}; +/* }}} */ +/* Progress Delegation {{{ */ +class Progress : + public OpProgress +{ + private: + id delegate_; + + protected: + virtual void Update() { + printf("Update(): %f (%s)\n", Percent, Op.c_str()); + } + + public: + Progress() : + delegate_(nil) + { + } + + void setDelegate(id delegate) { + delegate_ = delegate; + } + + virtual void Done() { + printf("Done()\n"); + } +}; +/* }}} */ + +/* External Constants {{{ */ +extern NSString *kUIButtonBarButtonAction; +extern NSString *kUIButtonBarButtonInfo; +extern NSString *kUIButtonBarButtonInfoOffset; +extern NSString *kUIButtonBarButtonSelectedInfo; +extern NSString *kUIButtonBarButtonStyle; +extern NSString *kUIButtonBarButtonTag; +extern NSString *kUIButtonBarButtonTarget; +extern NSString *kUIButtonBarButtonTitle; +extern NSString *kUIButtonBarButtonTitleVerticalHeight; +extern NSString *kUIButtonBarButtonTitleWidth; +extern NSString *kUIButtonBarButtonType; +/* }}} */ +/* Mime Addresses {{{ */ +@interface Address : NSObject { + NSString *name_; + NSString *email_; +} + +- (NSString *) name; +- (NSString *) email; + ++ (Address *) addressWithString:(NSString *)string; +- (Address *) initWithString:(NSString *)string; +@end + +@implementation Address + +- (NSString *) name { + return name_; +} + +- (NSString *) email { + return email_; +} + ++ (Address *) addressWithString:(NSString *)string { + return [[[Address alloc] initWithString:string] retain]; +} + +- (Address *) initWithString:(NSString *)string { + if ((self = [super init]) != nil) { + const char *error; + int offset; + + pcre *code = pcre_compile("^\"?(.*)\"? <([^>]*)>$", 0, &error, &offset, NULL); + + if (code == NULL) { + printf("%d:%s\n", offset, error); + _assert(false); + } + + pcre_extra *study = NULL; + int capture; + pcre_fullinfo(code, study, PCRE_INFO_CAPTURECOUNT, &capture); + + size_t size = [string length]; + const char *data = [string UTF8String]; + + int matches[(capture + 1) * 3]; + pcre_exec(code, study, data, size, 0, 0, matches, sizeof(matches) / sizeof(matches[0])); + + name_ = [[NSString stringWithCString:(data + matches[2]) length:(matches[3] - matches[2])] retain]; + email_ = [[NSString stringWithCString:(data + matches[4]) length:(matches[5] - matches[4])] retain]; + } return self; +} + +@end +/* }}} */ + +/* Right Alignment {{{ */ +@interface UIRightTextLabel : UITextLabel { + float _savedRightEdgeX; + BOOL _sizedtofit_flag; +} + +- (void) setFrame:(CGRect)frame; +- (void) setText:(NSString *)text; +- (void) realignText; +@end + +@implementation UIRightTextLabel + +- (void) setFrame:(CGRect)frame { + [super setFrame:frame]; + if (_sizedtofit_flag == NO) { + _savedRightEdgeX = frame.origin.x; + [self realignText]; + } +} + +- (void) setText:(NSString *)text { + [super setText:text]; + [self realignText]; +} + +- (void) realignText { + CGRect oldFrame = [self frame]; + + _sizedtofit_flag = YES; + [self sizeToFit]; // shrink down size so I can right align it + + CGRect newFrame = [self frame]; + + oldFrame.origin.x = _savedRightEdgeX - newFrame.size.width; + oldFrame.size.width = newFrame.size.width; + [super setFrame:oldFrame]; + _sizedtofit_flag = NO; +} + +@end +/* }}} */ + +@interface Database : NSObject { + pkgCacheFile cache_; + pkgRecords *records_; + pkgProblemResolver *resolver_; + + Status status_; + Progress progress_; +} + +- (Database *) init; +- (pkgCacheFile &) cache; +- (pkgRecords *) records; +- (pkgProblemResolver *) resolver; +- (void) reloadData; +- (void) update; +- (void) upgrade; +- (void) setDelegate:(id)delegate; +@end + +/* Package Class {{{ */ +@interface Package : NSObject { + pkgCache::PkgIterator iterator_; + Database *database_; + UITableCell *cell_; + pkgRecords::Parser *parser_; + pkgCache::VerIterator version_; + pkgCache::VerFileIterator file_; +} + +- (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database version:(pkgCache::VerIterator)version file:(pkgCache::VerFileIterator)file; ++ (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database; + +- (NSString *) name; +- (NSString *) section; +- (BOOL) installed; +- (NSString *) version; +- (Address *) maintainer; +- (size_t) size; +- (NSString *) tagline; +- (NSString *) description; +- (UITableCell *) cell; +- (void) setCell:(UITableCell *)cell; +- (NSComparisonResult) compareBySectionAndName:(Package *)package; + +- (void) install; +- (void) remove; +@end + +@implementation Package + +- (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database version:(pkgCache::VerIterator)version file:(pkgCache::VerFileIterator)file { + if ((self = [super init]) != nil) { + iterator_ = iterator; + database_ = database; + cell_ = nil; + + version_ = version; + file_ = file; + parser_ = &[database_ records]->Lookup(file); + } return self; +} + ++ (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database { + for (pkgCache::VerIterator version = iterator.VersionList(); !version.end(); ++version) + for (pkgCache::VerFileIterator file = version.FileList(); !file.end(); ++file) + return [[Package alloc] initWithIterator:iterator database:database version:version file:file]; + return nil; +} + +- (NSString *) name { + return [NSString stringWithCString:iterator_.Name()]; +} + +- (NSString *) section { + return [NSString stringWithCString:iterator_.Section()]; +} + +- (BOOL) installed { + return iterator_->CurrentState != pkgCache::State::NotInstalled; +} + +- (NSString *) version { + return [NSString stringWithCString:version_.VerStr()]; +} + +- (Address *) maintainer { + return [Address addressWithString:[NSString stringWithCString:parser_->Maintainer().c_str()]]; +} + +- (size_t) size { + return version_->InstalledSize; +} + +- (NSString *) tagline { + return [NSString stringWithCString:parser_->ShortDesc().c_str()]; +} + +- (NSString *) description { + return [NSString stringWithCString:parser_->LongDesc().c_str()]; +} + +- (UITableCell *) cell { + return cell_; +} + +- (void) setCell:(UITableCell *)cell { + cell_ = cell; +} + +- (NSComparisonResult) compareBySectionAndName:(Package *)package { + NSComparisonResult result = [[self section] compare:[package section]]; + if (result != NSOrderedSame) + return result; + return [[self name] compare:[package name]]; +} + +- (void) install { + pkgProblemResolver *resolver = [database_ resolver]; + resolver->Clear(iterator_); + resolver->Protect(iterator_); + [database_ cache]->MarkInstall(iterator_, false); +} + +- (void) remove { + pkgProblemResolver *resolver = [database_ resolver]; + resolver->Clear(iterator_); + resolver->Protect(iterator_); + resolver->Remove(iterator_); + [database_ cache]->MarkDelete(iterator_, false); +} + +@end +/* }}} */ +/* Section Class {{{ */ +@interface Section : NSObject { + NSString *name_; + size_t row_; + NSMutableArray *packages_; +} + +- (Section *) initWithName:(NSString *)name row:(size_t)row; +- (NSString *) name; +- (size_t) row; +- (void) addPackage:(Package *)package; +@end + +@implementation Section + +- (Section *) initWithName:(NSString *)name row:(size_t)row { + if ((self = [super init]) != nil) { + name_ = [name retain]; + row_ = row; + packages_ = [[NSMutableArray arrayWithCapacity:16] retain]; + } return self; +} + +- (NSString *) name { + return name_; +} + +- (size_t) row { + return row_; +} + +- (void) addPackage:(Package *)package { + [packages_ addObject:package]; +} + +@end +/* }}} */ + +/* Confirmation View {{{ */ +@interface ConfirmationView : UIView { +} + +@end + +@implementation ConfirmationView +@end +/* }}} */ +/* Package View {{{ */ +@interface PackageView : UIPreferencesTable { + Package *package_; + Database *database_; + NSMutableArray *cells_; +} + +- (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table; +- (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group; +- (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group; + +- (PackageView *) initWithFrame:(struct CGRect)frame database:(Database *)database; +- (void) setPackage:(Package *)package; +@end + +@implementation PackageView + +- (int) numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table { + return 2; +} + +- (NSString *) preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group { + switch (group) { + case 0: + return @"Specifics"; + break; + + case 1: + return @"Description"; + break; + + default: _assert(false); + } +} + +- (int) preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group { + switch (group) { + case 0: + return 5; + break; + + case 1: + return 1; + break; + + default: _assert(false); + } +} + +- (UIPreferencesTableCell *) preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group { + UIPreferencesTableCell *cell; + + switch (group) { + case 0: switch (row) { + case 0: + cell = [cells_ objectAtIndex:0]; + [cell setTitle:@"Name"]; + [cell setValue:[package_ name]]; + break; + + case 1: + cell = [cells_ objectAtIndex:1]; + [cell setTitle:@"Version"]; + [cell setValue:[package_ version]]; + break; + + case 2: + cell = [cells_ objectAtIndex:2]; + [cell setTitle:@"Section"]; + [cell setValue:[package_ section]]; + break; + + case 3: { + double size = [package_ size]; + unsigned power = 0; + while (size > 1024) { + size /= 1024; + ++power; + } + + cell = [cells_ objectAtIndex:3]; + [cell setTitle:@"Size"]; + [cell setValue:[NSString stringWithFormat:@"%.1f%c", size, "bkMG"[power]]]; + } break; + + case 4: + cell = [cells_ objectAtIndex:4]; + [cell setTitle:@"Maintainer"]; + [cell setValue:[[package_ maintainer] name]]; + [cell setShowDisclosure:YES]; + [cell setShowSelection:YES]; + break; + + default: _assert(false); + } break; + + case 1: switch (row) { + case 0: + cell = [cells_ objectAtIndex:5]; + [cell setTitle:@"Tagline"]; + [cell setValue:[package_ tagline]]; + break; + + case 1: + cell = [cells_ objectAtIndex:6]; + [cell setTitle:@"Description"]; + [cell setValue:[package_ description]]; + break; + } break; + + default: _assert(false); + } + + return cell; +} + +- (PackageView *) initWithFrame:(struct CGRect)frame database:(Database *)database { + if ((self = [super initWithFrame:frame]) != nil) { + database_ = database; + [self setDataSource:self]; + + cells_ = [[NSMutableArray arrayWithCapacity:16] retain]; + + for (unsigned i = 0; i != 6; ++i) { + struct CGRect frame = [self frameOfPreferencesCellAtRow:0 inGroup:0]; + UIPreferencesTableCell *cell = [[UIPreferencesTableCell alloc] init]; + [cell setShowSelection:NO]; + [cells_ addObject:cell]; + } + } return self; +} + +- (void) setPackage:(Package *)package { + package_ = package; + [self reloadData]; +} + +@end +/* }}} */ + +@implementation Database + +- (Database *) init { + if ((self = [super init]) != nil) { + records_ = NULL; + resolver_ = NULL; + } return self; +} + +- (pkgCacheFile &) cache { + return cache_; +} + +- (pkgRecords *) records { + return records_; +} + +- (pkgProblemResolver *) resolver { + return resolver_; +} + +- (void) reloadData { + delete resolver_; + delete records_; + cache_.Close(); + cache_.Open(progress_, true); + records_ = new pkgRecords(cache_); + resolver_ = new pkgProblemResolver(cache_); +} + +- (void) update { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + pkgSourceList list; + _assert(list.ReadMainList()); + + FileFd lock; + lock.Fd(GetLock(_config->FindDir("Dir::State::Lists") + "lock")); + _assert(!_error->PendingError()); + + pkgAcquire fetcher(&status_); + _assert(list.GetIndexes(&fetcher)); + _assert(fetcher.Run() != pkgAcquire::Failed); + + bool failed = false; + for (pkgAcquire::ItemIterator item = fetcher.ItemsBegin(); item != fetcher.ItemsEnd(); item++) + if ((*item)->Status != pkgAcquire::Item::StatDone) { + (*item)->Finished(); + failed = true; + } + + if (!failed && _config->FindB("APT::Get::List-Cleanup", true) == true) { + _assert(fetcher.Clean(_config->FindDir("Dir::State::lists"))); + _assert(fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/")); + } + + [pool release]; +} + +- (void) upgrade { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + _assert(cache_->DelCount() == 0 && cache_->InstCount() == 0); + _assert(pkgApplyStatus(cache_)); + + if (cache_->BrokenCount() != 0) { + _assert(pkgFixBroken(cache_)); + _assert(cache_->BrokenCount() == 0); + _assert(pkgMinimizeUpgrade(cache_)); + } + + _assert(pkgDistUpgrade(cache_)); + + //InstallPackages(cache_, true); + + [pool release]; +} + +- (void) setDelegate:(id)delegate { + status_.setDelegate(delegate); + progress_.setDelegate(delegate); +} + +@end + +/* Progress Data {{{ */ +@interface ProgressData : NSObject { + SEL selector_; + id target_; + id object_; +} + +- (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object; + +- (SEL) selector; +- (id) target; +- (id) object; +@end + +@implementation ProgressData + +- (ProgressData *) initWithSelector:(SEL)selector target:(id)target object:(id)object { + if ((self = [super init]) != nil) { + selector_ = selector; + target_ = target; + object_ = object; + } return self; +} + +- (SEL) selector { + return selector_; +} + +- (id) target { + return target_; +} + +- (id) object { + return object_; +} + +@end +/* }}} */ + +@interface ProgressView : UIView { + UIView *view_; + UITransitionView *transition_; + UIView *progress_; + UINavigationBar *navbar_; +} + +- (ProgressView *) initWithFrame:(struct CGRect)frame; +- (void) setContentView:(UIView *)view; +- (void) resetView; + +- (void) _detachNewThreadData:(ProgressData *)data; +- (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object; + +- (void) setStatusIMSHit; +- (void) setStatusFetch; +- (void) setStatusDone; +- (void) setStatusFail; +- (void) setStatusPulse; + +- (void) setStatusStart; +- (void) setStatusStop; +@end + +@implementation ProgressView + +- (ProgressView *) initWithFrame:(struct CGRect)frame { + if ((self = [super initWithFrame:frame]) != nil) { + transition_ = [[UITransitionView alloc] initWithFrame:[self bounds]]; + [self addSubview:transition_]; + + progress_ = [[UIView alloc] initWithFrame:[transition_ bounds]]; + + CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); + float black[] = {0.0, 0.0, 0.0, 1.0}; + [progress_ setBackgroundColor:CGColorCreate(space, black)]; + + CGSize navsize = [UINavigationBar defaultSize]; + CGRect navrect = {{0, 0}, navsize}; + + navbar_ = [[UINavigationBar alloc] initWithFrame:navrect]; + [progress_ addSubview:navbar_]; + + [navbar_ setBarStyle:1]; + [navbar_ setDelegate:self]; + + UINavigationItem *navitem = [[UINavigationItem alloc] initWithTitle:nil]; + [navbar_ pushNavigationItem:navitem]; + } return self; +} + +- (void) setContentView:(UIView *)view { + view_ = view; +} + +- (void) resetView { + [transition_ transition:6 toView:view_]; +} + +- (void) _detachNewThreadData:(ProgressData *)data { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + [[data target] performSelector:[data selector] withObject:[data object]]; + [self performSelectorOnMainThread:@selector(resetView) withObject:nil waitUntilDone:YES]; + + [pool release]; +} + +- (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object { + [transition_ transition:6 toView:progress_]; + + [NSThread + detachNewThreadSelector:@selector(_detachNewThreadData:) + toTarget:self + withObject:[[ProgressData alloc] + initWithSelector:selector + target:target + object:object + ] + ]; +} + +- (void) setStatusIMSHit { + _trace(); +} + +- (void) setStatusFetch { + _trace(); +} + +- (void) setStatusDone { + _trace(); +} + +- (void) setStatusFail { + _trace(); +} + +- (void) setStatusPulse { + _trace(); +} + +- (void) setStatusStart { + _trace(); +} + +- (void) setStatusStop { + _trace(); +} + +@end + +@protocol PackagesDelegate + +- (void) viewPackage:(Package *)package; + +@end + +@interface Packages : UIView { + NSString *title_; + Database *database_; + bool (*filter_)(Package *package); + NSMutableArray *packages_; + NSMutableArray *sections_; + id delegate_; + UISectionList *list_; + UINavigationBar *navbar_; + UITransitionView *transition_; + Package *package_; + PackageView *pkgview_; + SEL selector_; +} + +- (int) numberOfSectionsInSectionList:(UISectionList *)list; +- (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section; +- (int) sectionList:(UISectionList *)list rowForSection:(int)section; + +- (int) numberOfRowsInTable:(UITable *)table; +- (float) table:(UITable *)table heightForRow:(int)row; +- (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col; +- (BOOL) table:(UITable *)table showDisclosureForRow:(int)row; +- (void) tableRowSelected:(NSNotification*)notification; + +- (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button; +- (void) navigationBar:(UINavigationBar *)navbar poppedItem:(UINavigationItem *)item; + +- (Packages *) initWithFrame:(struct CGRect)frame title:(NSString *)title database:(Database *)database filter:(bool (*)(Package *))filter selector:(SEL)selector; +- (void) setDelegate:(id)delegate; +- (void) addPackage:(Package *)package; +- (NSMutableArray *) packages; +- (void) reloadData; +@end + +@implementation Packages + +- (int) numberOfSectionsInSectionList:(UISectionList *)list { + return [sections_ count]; +} + +- (NSString *) sectionList:(UISectionList *)list titleForSection:(int)section { + return [[sections_ objectAtIndex:section] name]; +} + +- (int) sectionList:(UISectionList *)list rowForSection:(int)section { + return [[sections_ objectAtIndex:section] row]; +} + +- (int) numberOfRowsInTable:(UITable *)table { + return [packages_ count]; +} + +- (float) table:(UITable *)table heightForRow:(int)row { + return 64; +} + +- (UITableCell *) table:(UITable *)table cellForRow:(int)row column:(UITableColumn *)col { + Package *package = [packages_ objectAtIndex:row]; { + UITableCell *cell = [package cell]; + if (cell != nil) + return cell; + } + +#if 0 + UIImageAndTextTableCell *cell_ = [[UIImageAndTextTableCell alloc] init]; + [package setCell:cell_]; + + [cell_ setTitle:[package name]]; + return cell_; +#endif + + UITableCell *cell = [[UITableCell alloc] init]; + [package setCell:cell]; + + GSFontRef bold = GSFontCreateWithName("Helvetica", kGSFontTraitBold, 22); + GSFontRef large = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 16); + GSFontRef small = GSFontCreateWithName("Helvetica", kGSFontTraitNone, 14); + + CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); + float blue[] = {0.2, 0.2, 1.0, 1.0}; + float gray[] = {0.4, 0.4, 0.4, 1.0}; + float clear[] = {0, 0, 0, 0}; + + UITextLabel *name = [[UITextLabel alloc] initWithFrame:CGRectMake(12, 7, 250, 25)]; + [name setText:[package name]]; + [name setBackgroundColor:CGColorCreate(space, clear)]; + [name setFont:bold]; + + UIRightTextLabel *version = [[UIRightTextLabel alloc] initWithFrame:CGRectMake(290, 7, 70, 25)]; + [version setText:[package version]]; + [version setColor:CGColorCreate(space, blue)]; + [version setBackgroundColor:CGColorCreate(space, clear)]; + [version setFont:large]; + + UITextLabel *description = [[UITextLabel alloc] initWithFrame:CGRectMake(13, 35, 315, 20)]; + [description setText:[package tagline]]; + [description setColor:CGColorCreate(space, gray)]; + [description setBackgroundColor:CGColorCreate(space, clear)]; + [description setFont:small]; + + [cell addSubview:name]; + [cell addSubview:version]; + [cell addSubview:description]; + + CFRelease(small); + CFRelease(large); + CFRelease(bold); + + return cell; +} + +- (BOOL) table:(UITable *)table showDisclosureForRow:(int)row { + return YES; +} + +- (void) tableRowSelected:(NSNotification*)notification { + int row = [[list_ table] selectedRow]; + if (row == INT_MAX) + return; + + package_ = [packages_ objectAtIndex:row]; + + UINavigationItem *navitem = [[UINavigationItem alloc] initWithTitle:[package_ name]]; + [navbar_ pushNavigationItem:navitem]; + + [navbar_ showButtonsWithLeftTitle:nil rightTitle:title_]; + + [pkgview_ setPackage:package_]; + [transition_ transition:1 toView:pkgview_]; + +} + +- (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button { + if (button == 0) { + printf("bef:%ld\n", [database_ cache]->InstCount()); + [package_ performSelector:selector_]; + + pkgProblemResolver *resolver = [database_ resolver]; + + resolver->InstallProtect(); + if (!resolver->Resolve(true)) + _error->Discard(); + + printf("aft:%ld\n", [database_ cache]->InstCount()); + _assert(false); + } +} + +- (void) navigationBar:(UINavigationBar *)navbar poppedItem:(UINavigationItem *)item { + [transition_ transition:2 toView:list_]; + [navbar_ showButtonsWithLeftTitle:nil rightTitle:nil]; + UITable *table = [list_ table]; + [table selectRow:-1 byExtendingSelection:NO withFade:YES]; + //UITableCell *cell = [table cellAtRow:[table selectedRow] column:0]; + //[table selectCell:nil inRow:-1 column:-1 withFade:YES]; + //[table highlightRow:-1]; + //[cell setSelected:NO withFade:YES]; + package_ = nil; +} + +- (Packages *) initWithFrame:(struct CGRect)frame title:(NSString *)title database:(Database *)database filter:(bool (*)(Package *))filter selector:(SEL)selector { + if ((self = [super initWithFrame:frame]) != nil) { + title_ = title; + database_ = database; + filter_ = filter; + selector_ = selector; + + packages_ = [[NSMutableArray arrayWithCapacity:16] retain]; + + struct CGRect bounds = [self bounds]; + CGSize navsize = [UINavigationBar defaultSize]; + CGRect navrect = {{0, 0}, navsize}; + + navbar_ = [[UINavigationBar alloc] initWithFrame:navrect]; + [self addSubview:navbar_]; + + [navbar_ setBarStyle:1]; + [navbar_ setDelegate:self]; + + UINavigationItem *navitem = [[UINavigationItem alloc] initWithTitle:title]; + [navbar_ pushNavigationItem:navitem]; + [navitem setBackButtonTitle:@"Packages"]; + + transition_ = [[UITransitionView alloc] initWithFrame:CGRectMake( + bounds.origin.x, bounds.origin.y + navsize.height, bounds.size.width, bounds.size.height - navsize.height + )]; + + [self addSubview:transition_]; + + list_ = [[UISectionList alloc] initWithFrame:[transition_ bounds] showSectionIndex:NO]; + [list_ setDataSource:self]; + + [transition_ transition:0 toView:list_]; + + UITableColumn *column = [[UITableColumn alloc] + initWithTitle:@"Name" + identifier:@"name" + width:frame.size.width + ]; + + UITable *table = [list_ table]; + [table setSeparatorStyle:1]; + [table addTableColumn:column]; + [table setDelegate:self]; + + pkgview_ = [[PackageView alloc] initWithFrame:[transition_ bounds] database:database_]; + } return self; +} + +- (void) setDelegate:(id)delegate { + delegate_ = delegate; +} + +- (void) addPackage:(Package *)package { + _assert(sections_ == nil); + [packages_ addObject:package]; +} + +- (NSMutableArray *) packages { + return packages_; +} + +- (void) reloadData { + for (pkgCache::PkgIterator iterator = [database_ cache]->PkgBegin(); !iterator.end(); ++iterator) { + Package *package = [Package packageWithIterator:iterator database:database_]; + if (package == nil) + continue; + if (filter_(package)) + [self addPackage:package]; + } + + [packages_ sortUsingSelector:@selector(compareBySectionAndName:)]; + sections_ = [[NSMutableArray arrayWithCapacity:16] retain]; + + Section *section = nil; + for (size_t offset = 0, count = [packages_ count]; offset != count; ++offset) { + Package *package = [packages_ objectAtIndex:offset]; + NSString *name = [package section]; + + if (section == nil || ![[section name] isEqual:name]) { + section = [[Section alloc] initWithName:name row:offset]; + [sections_ addObject:section]; + } + + [section addPackage:package]; + } + + [list_ reloadData]; +} + +@end + +bool IsInstalled(Package *package) { + return [package installed]; +} + +bool IsNotInstalled(Package *package) { + return ![package installed]; +} + +@interface Cydia : UIApplication <PackagesDelegate> { + UIWindow *window_; + UITransitionView *transition_; + + Database *database_; + ProgressView *progress_; + + UIView *featured_; + UINavigationBar *navbar_; + UIScroller *scroller_; + UIWebView *webview_; + NSURL *url_; + + Packages *install_; + Packages *uninstall_; +} + +- (void) loadNews; +- (void) reloadData; + +- (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button; +- (void) buttonBarItemTapped:(id)sender; + +- (void) view:(UIView *)sender didSetFrame:(CGRect)frame; +- (void) view:(UIView *)view didDrawInRect:(CGRect)rect duration:(float)duration; + +- (void) viewPackage:(Package *)package; + +- (void) applicationDidFinishLaunching:(id)unused; +@end + +@implementation Cydia + +- (void) loadNews { + [webview_ loadRequest:[NSURLRequest + requestWithURL:url_ + cachePolicy:NSURLRequestReloadIgnoringCacheData + timeoutInterval:30.0 + ]]; +} + +- (void) reloadData { + [database_ reloadData]; + [install_ reloadData]; + [uninstall_ reloadData]; +} + +- (void) navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button { + switch (button) { + case 0: + [self loadNews]; + break; + + case 1: + break; + } +} + +- (void) buttonBarItemTapped:(id)sender { + UIView *view; + + switch ([sender tag]) { + case 1: view = featured_; break; + case 2: view = install_; break; + case 4: view = uninstall_; break; + + default: + _assert(false); + } + + [transition_ transition:0 toView:view]; +} + +- (void) view:(UIView *)view didSetFrame:(CGRect)frame { + [scroller_ setContentSize:frame.size]; +} + +- (void) view:(UIView *)view didDrawInRect:(CGRect)rect duration:(float)duration { + [scroller_ setContentSize:[webview_ bounds].size]; +} + +- (void) viewPackage:(Package *)package { + _assert(false); +} + +- (void) applicationDidFinishLaunching:(id)unused { + _assert(pkgInitConfig(*_config)); + _assert(pkgInitSystem(*_config, _system)); + + CGRect screenrect = [UIHardware fullScreenApplicationContentRect]; + window_ = [[UIWindow alloc] initWithContentRect:screenrect]; + + [window_ orderFront: self]; + [window_ makeKey: self]; + [window_ _setHidden: NO]; + + progress_ = [[ProgressView alloc] initWithFrame:[window_ bounds]]; + [database_ setDelegate:progress_]; + [window_ setContentView:progress_]; + + UIView *view = [[UIView alloc] initWithFrame:[progress_ bounds]]; + [progress_ setContentView:view]; + + transition_ = [[UITransitionView alloc] initWithFrame:CGRectMake( + 0, 0, screenrect.size.width, screenrect.size.height - 48 + )]; + + [view addSubview:transition_]; + + featured_ = [[UIView alloc] initWithFrame:[transition_ bounds]]; + + CGSize navsize = [UINavigationBar defaultSize]; + CGRect navrect = {{0, 0}, navsize}; + + navbar_ = [[UINavigationBar alloc] initWithFrame:navrect]; + [featured_ addSubview:navbar_]; + + [navbar_ setBarStyle:1]; + [navbar_ setDelegate:self]; + + [navbar_ showButtonsWithLeftTitle:@"About" rightTitle:@"Reload"]; + + UINavigationItem *navitem = [[UINavigationItem alloc] initWithTitle:@"Featured"]; + [navbar_ pushNavigationItem:navitem]; + + struct CGRect subbounds = [featured_ bounds]; + subbounds.origin.y += navsize.height; + subbounds.size.height -= navsize.height; + + UIImageView *pinstripe = [[UIImageView alloc] initWithFrame:subbounds]; + [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]]; + [featured_ addSubview:pinstripe]; + + scroller_ = [[UIScroller alloc] initWithFrame:subbounds]; + [featured_ addSubview:scroller_]; + + [scroller_ setScrollingEnabled:YES]; + [scroller_ setAdjustForContentSizeChange:YES]; + [scroller_ setClipsSubviews:YES]; + [scroller_ setAllowsRubberBanding:YES]; + [scroller_ setScrollDecelerationFactor:0.99]; + [scroller_ setDelegate:self]; + + webview_ = [[UIWebView alloc] initWithFrame:[scroller_ bounds]]; + [scroller_ addSubview:webview_]; + + [webview_ setTilingEnabled:YES]; + [webview_ setTileSize:CGSizeMake(screenrect.size.width, 500)]; + [webview_ setAutoresizes:YES]; + [webview_ setDelegate:self]; + + url_ = [NSURL URLWithString:@"http://cydia.saurik.com/"]; + [self loadNews]; + + NSArray *buttonitems = [NSArray arrayWithObjects: + [NSDictionary dictionaryWithObjectsAndKeys: + @"buttonBarItemTapped:", kUIButtonBarButtonAction, + @"featured-up.png", kUIButtonBarButtonInfo, + @"featured-dn.png", kUIButtonBarButtonSelectedInfo, + [NSNumber numberWithInt:1], kUIButtonBarButtonTag, + self, kUIButtonBarButtonTarget, + @"Featured", kUIButtonBarButtonTitle, + @"0", kUIButtonBarButtonType, + nil], + + [NSDictionary dictionaryWithObjectsAndKeys: + @"buttonBarItemTapped:", kUIButtonBarButtonAction, + @"install-up.png", kUIButtonBarButtonInfo, + @"install-dn.png", kUIButtonBarButtonSelectedInfo, + [NSNumber numberWithInt:2], kUIButtonBarButtonTag, + self, kUIButtonBarButtonTarget, + @"Install", kUIButtonBarButtonTitle, + @"0", kUIButtonBarButtonType, + nil], + + [NSDictionary dictionaryWithObjectsAndKeys: + @"buttonBarItemTapped:", kUIButtonBarButtonAction, + @"upgrade-up.png", kUIButtonBarButtonInfo, + @"upgrade-dn.png", kUIButtonBarButtonSelectedInfo, + [NSNumber numberWithInt:3], kUIButtonBarButtonTag, + self, kUIButtonBarButtonTarget, + @"Upgrade", kUIButtonBarButtonTitle, + @"0", kUIButtonBarButtonType, + nil], + + [NSDictionary dictionaryWithObjectsAndKeys: + @"buttonBarItemTapped:", kUIButtonBarButtonAction, + @"uninstall-up.png", kUIButtonBarButtonInfo, + @"uninstall-dn.png", kUIButtonBarButtonSelectedInfo, + [NSNumber numberWithInt:4], kUIButtonBarButtonTag, + self, kUIButtonBarButtonTarget, + @"Uninstall", kUIButtonBarButtonTitle, + @"0", kUIButtonBarButtonType, + nil], + + [NSDictionary dictionaryWithObjectsAndKeys: + @"buttonBarItemTapped:", kUIButtonBarButtonAction, + @"sources-up.png", kUIButtonBarButtonInfo, + @"sources-dn.png", kUIButtonBarButtonSelectedInfo, + [NSNumber numberWithInt:5], kUIButtonBarButtonTag, + self, kUIButtonBarButtonTarget, + @"Sources", kUIButtonBarButtonTitle, + @"0", kUIButtonBarButtonType, + nil], + nil]; + + UIButtonBar *buttonbar = [[UIButtonBar alloc] + initInView:view + withFrame:CGRectMake( + 0, screenrect.size.height - 48, + screenrect.size.width, 48 + ) + withItemList:buttonitems + ]; + + [buttonbar setDelegate:self]; + [buttonbar setBarStyle:1]; + [buttonbar setButtonBarTrackingMode:2]; + + int buttons[5] = {1, 2, 3, 4, 5}; + [buttonbar registerButtonGroup:0 withButtons:buttons withCount:5]; + [buttonbar showButtonGroup:0 withDuration:0]; + + for (int i = 0; i != 5; ++i) + [[buttonbar viewWithTag:(i + 1)] setFrame:CGRectMake( + i * 64 + 2, 1, 60, 48 + )]; + + [buttonbar showSelectionForButton:1]; + [transition_ transition:0 toView:featured_]; + + [view addSubview:buttonbar]; + + database_ = [[Database alloc] init]; + + install_ = [[Packages alloc] initWithFrame:[transition_ bounds] title:@"Install" database:database_ filter:&IsNotInstalled selector:@selector(install)]; + [install_ setDelegate:self]; + + uninstall_ = [[Packages alloc] initWithFrame:[transition_ bounds] title:@"Uninstall" database:database_ filter:&IsInstalled selector:@selector(remove)]; + [uninstall_ setDelegate:self]; + +#if 0 + UIAlertSheet *alert = [[UIAlertSheet alloc] + initWithTitle:@"Alert Title" + buttons:[NSArray arrayWithObjects:@"Yes", nil] + defaultButtonIndex:0 + delegate:self + context:self + ]; + + NSLog(@"%p\n", [alert table]); + [[alert table] setDelegate:self]; + [[alert table] reloadData]; + + [alert addTextFieldWithValue:@"Title" label:@"Label"]; + [alert setShowsOverSpringBoardAlerts:YES]; + [alert setBodyText:@"This is an alert."]; + [alert presentSheetFromButtonBar:buttonbar]; + //[alert popupAlertAnimated:YES]; +#endif + + [self reloadData]; + [progress_ resetView]; + //[progress_ detachNewThreadSelector:@selector(reloadData) toTarget:self withObject:nil]; +} + +@end + +int main(int argc, char *argv[]) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + UIApplicationMain(argc, argv, [Cydia class]); + [pool release]; +} diff --git a/makefile b/makefile new file mode 100644 index 0000000..9ffa5e9 --- /dev/null +++ b/makefile @@ -0,0 +1,10 @@ +iPhone := 192.168.1.100 + +all: Cydia + +test: all + scp -p Cydia saurik@$(iPhone):/dat + ssh saurik@$(iPhone) /dat/Cydia + +Cydia: *.mm makefile + arm-apple-darwin-g++ -fobjc-call-cxx-cdtors -g3 -O2 -Wall -Werror -o $@ $< -framework UIKit -framework Foundation -framework CoreFoundation -framework CoreGraphics -framework GraphicsServices -lobjc -lapt-pkg -lpcre -fobjc-exceptions |