/* Cydia - iPhone UIKit Front-End for Debian APT
- * Copyright (C) 2008-2014 Jay Freeman (saurik)
+ * Copyright (C) 2008-2015 Jay Freeman (saurik)
*/
/* GNU General Public License, Version 3 {{{ */
#include <sys/mount.h>
#include <sys/reboot.h>
+#include <dirent.h>
#include <fcntl.h>
#include <notify.h>
#include <dlfcn.h>
};
// }}}
-static void setreugid(uid_t uid, gid_t gid) {
- _assert(setreuid(uid, uid) != -1);
- _assert(setregid(gid, gid) != -1);
-}
-
-static void setreguid(gid_t gid, uid_t uid) {
- _assert(setregid(gid, gid) != -1);
- _assert(setreuid(uid, uid) != -1);
-}
-
-struct Root {
- Root() {
- _trace();
- setreugid(0, 0);
- _assert(pthread_setugid_np(0, 0) != -1);
- setreguid(501, 501);
- }
-
- ~Root() {
- _trace();
- setreugid(0, 0);
- _assert(pthread_setugid_np(KAUTH_UID_NONE, KAUTH_GID_NONE) != -1);
- setreguid(501, 501);
- }
-};
-
-#define _root(code) \
- ({ Root _root; code; })
-
static NSString *Colon_;
NSString *Elision_;
static NSString *Error_;
return [[NSString stringWithUTF8String:page] stringByAppendingString:path];
}
-static void ReapZombie(pid_t pid) {
- int status;
- wait:
- if (waitpid(pid, &status, 0) == -1)
- if (errno == EINTR)
- goto wait;
- else _assert(false);
+static NSString *ShellEscape(NSString *value) {
+ return [NSString stringWithFormat:@"'%@'", [value stringByReplacingOccurrencesOfString:@"'" withString:@"'\\''"]];
}
static _finline void UpdateExternalStatus(uint64_t newStatus) {
static int Finish_;
static bool RestartSubstrate_;
-static bool UpgradeCydia_;
static NSArray *Finishes_;
#define SpringBoard_ "/System/Library/LaunchDaemons/com.apple.SpringBoard.plist"
static NSString *SerialNumber_ = nil;
static NSString *ChipID_ = nil;
static NSString *BBSNum_ = nil;
-static _H<NSString> Token_;
static _H<NSString> UniqueID_;
static _H<NSString> UserAgent_;
static _H<NSString> Product_;
static NSArray *Languages_;
static CGColorSpaceRef space_;
+#define CacheState_ "/var/mobile/Library/Caches/com.saurik.Cydia/CacheState.plist"
+#define SavedState_ "/var/mobile/Library/Caches/com.saurik.Cydia/SavedState.plist"
+
static NSDictionary *SectionMap_;
-static NSMutableDictionary *Metadata_;
-static _transient NSMutableDictionary *Settings_;
-static _transient NSMutableDictionary *Packages_;
+static _H<NSDate> Backgrounded_;
static _transient NSMutableDictionary *Values_;
static _transient NSMutableDictionary *Sections_;
_H<NSMutableDictionary> Sources_;
static _transient NSNumber *Version_;
-bool Changed_;
static time_t now_;
bool IsWildcat_;
static _H<NSMutableDictionary> SessionData_;
static _H<NSObject> HostConfig_;
static _H<NSMutableSet> BridgedHosts_;
-static _H<NSMutableSet> TokenHosts_;
static _H<NSMutableSet> InsecureHosts_;
static _H<NSMutableSet> PipelinedHosts_;
static _H<NSMutableSet> CachedURLs_;
}
/* }}} */
-NSString *GetLastUpdate() {
- NSDate *update = [Metadata_ objectForKey:@"LastUpdate"];
-
- if (update == nil)
- return UCLocalize("NEVER_OR_UNKNOWN");
-
- CFDateFormatterRef formatter = CFDateFormatterCreate(NULL, Locale_, kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
- CFStringRef formatted = CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) update);
-
- CFRelease(formatter);
-
- return [(NSString *) formatted autorelease];
-}
-
bool isSectionVisible(NSString *section) {
NSDictionary *metadata([Sections_ objectForKey:(section ?: @"")]);
NSNumber *hidden(metadata == nil ? nil : [metadata objectForKey:@"Hidden"]);
return [NSString stringWithUTF8String:string];
}
+static NSString *VerifySource(NSString *href) {
+ static RegEx href_r("(http(s?)://|file:///)[^# ]*");
+ if (!href_r(href)) {
+ [[[[UIAlertView alloc]
+ initWithTitle:[NSString stringWithFormat:Colon_, Error_, UCLocalize("INVALID_URL")]
+ message:UCLocalize("INVALID_URL_EX")
+ delegate:nil
+ cancelButtonTitle:UCLocalize("OK")
+ otherButtonTitles:nil
+ ] autorelease] show];
+
+ return nil;
+ }
+
+ if (![href hasSuffix:@"/"])
+ href = [href stringByAppendingString:@"/"];
+ return href;
+}
+
@class Cydia;
/* Delegate Prototypes {{{ */
- (void) _saveConfig;
- (void) syncData;
- (void) addSource:(NSDictionary *)source;
-- (void) addTrivialSource:(NSString *)href;
+- (BOOL) addTrivialSource:(NSString *)href;
- (UIProgressHUD *) addProgressHUD;
- (void) removeProgressHUD:(UIProgressHUD *)hud;
- (void) showActionSheet:(UIActionSheet *)sheet fromItem:(UIBarButtonItem *)item;
CYPool pool_;
unsigned era_;
+ _H<NSDate> delock_;
pkgCacheFile cache_;
pkgDepCache::Policy *policy_;
}
// }}}
+static NSDate *GetStatusDate() {
+ return [[[NSFileManager defaultManager] attributesOfItemAtPath:@"/var/lib/dpkg/status" error:NULL] fileModificationDate];
+}
+
+static void SaveConfig(NSObject *lock) {
+ @synchronized (lock) {
+ _trace();
+ MetaFile_.Sync();
+ _trace();
+ }
+
+ CFPreferencesSetMultiple((CFDictionaryRef) [NSDictionary dictionaryWithObjectsAndKeys:
+ Values_, @"CydiaValues",
+ Sections_, @"CydiaSections",
+ (id) Sources_, @"CydiaSources",
+ Version_, @"CydiaVersion",
+ nil], NULL, CFSTR("com.saurik.Cydia"), kCFPreferencesCurrentUser, kCFPreferencesCurrentHost);
+
+ if (!CFPreferencesAppSynchronize(CFSTR("com.saurik.Cydia")))
+ NSLog(@"CFPreferencesAppSynchronize(com.saurik.Cydia) == false");
+
+ CydiaWriteSources();
+}
+
/* Source Class {{{ */
@interface Source : NSObject {
unsigned era_;
if (record_ == nil)
return;
else if (NSMutableArray *sections = [record_ objectForKey:@"Sections"]) {
- if (![sections containsObject:section]) {
+ if (![sections containsObject:section])
[sections addObject:section];
- Changed_ = true;
- }
- } else {
+ } else
[record_ setObject:[NSMutableArray arrayWithObject:section] forKey:@"Sections"];
- Changed_ = true;
- }
}
- (bool) addSection:(NSString *)section {
return;
if (NSMutableArray *sections = [record_ objectForKey:@"Sections"])
- if ([sections containsObject:section]) {
+ if ([sections containsObject:section])
[sections removeObject:section];
- Changed_ = true;
- }
}
- (bool) removeSection:(NSString *)section {
- (void) _remove {
[Sources_ removeObjectForKey:[self key]];
- Changed_ = true;
}
- (bool) remove {
for (NSString *file in files)
if (application_r(file)) {
NSDictionary *info([NSDictionary dictionaryWithContentsOfFile:file]);
+ if (info == nil)
+ continue;
NSString *id([info objectForKey:@"CFBundleIdentifier"]);
- if ([id isEqualToString:me])
+ if (id == nil || [id isEqualToString:me])
continue;
NSString *display([info objectForKey:@"CFBundleDisplayName"]);
if ([self popErrorWithTitle:title forOperation:list.ReadMainList()])
return true;
return false;
+
+ list.Reset();
+
+ bool error(false);
+
+ if (access("/etc/apt/sources.list", F_OK) == 0)
+ error |= [self popErrorWithTitle:title forOperation:list.ReadAppend("/etc/apt/sources.list")];
+
+ std::string base("/etc/apt/sources.list.d");
+ if (DIR *sources = opendir(base.c_str())) {
+ while (dirent *source = readdir(sources))
+ if (source->d_name[0] != '.' && source->d_namlen > 5 && strcmp(source->d_name + source->d_namlen - 5, ".list") == 0 && strcmp(source->d_name, "cydia.list") != 0)
+ error |= [self popErrorWithTitle:title forOperation:list.ReadAppend((base + "/" + source->d_name).c_str())];
+ closedir(sources);
+ }
+
+ error |= [self popErrorWithTitle:title forOperation:list.ReadAppend(SOURCES_LIST)];
+
+ return error;
}
- (void) reloadDataWithInvocation:(NSInvocation *)invocation {
}
_end
- _root(_system->Lock());
-
_trace();
OpProgress progress;
bool opened;
open:
+ delock_ = GetStatusDate();
_profile(reloadDataWithInvocation$pkgCacheFile)
opened = cache_.Open(progress, false);
_end
}
}
- _system->UnLock();
return;
}
_trace();
if (substrate)
RestartSubstrate_ = true;
- _system->UnLock();
+ if (![delock_ isEqual:GetStatusDate()]) {
+ [delegate_ addProgressEventOnMainThread:[CydiaProgressEvent eventWithMessage:UCLocalize("DPKG_LOCKED") ofType:kCydiaProgressEventTypeError] forTask:title];
+ return;
+ }
+
+ delock_ = nil;
+
pkgPackageManager::OrderResult result(manager_->DoInstall(statusfd_));
+
+ NSString *oextended(@"/var/lib/apt/extended_states");
+ NSString *nextended(Cache("extended_states"));
+
+ struct stat info;
+ if (stat([nextended UTF8String], &info) != -1 && (info.st_mode & S_IFMT) == S_IFREG) {
+ system([[NSString stringWithFormat:@"/usr/libexec/cydia/cydo /bin/mv -f %@ %@", ShellEscape(nextended), ShellEscape(oextended)] UTF8String]);
+ system([[NSString stringWithFormat:@"/usr/libexec/cydia/cydo /bin/chown 0:0 %@", ShellEscape(oextended)] UTF8String]);
+ }
+
+ unlink([nextended UTF8String]);
+ symlink([oextended UTF8String], [nextended UTF8String]);
+
if ([self popErrorWithTitle:title])
return;
[self update];
}
+- (bool) delocked {
+ return ![delock_ isEqual:GetStatusDate()];
+}
+
- (bool) upgrade {
NSString *title(UCLocalize("UPGRADE"));
if ([self popErrorWithTitle:title forOperation:pkgDistUpgrade(cache_)])
_error->Discard();
else {
[self popErrorWithTitle:title forOperation:success];
- [Metadata_ setObject:[NSDate date] forKey:@"LastUpdate"];
- Changed_ = true;
+
+ [[NSDictionary dictionaryWithObjectsAndKeys:
+ [NSDate date], @"LastUpdate",
+ nil] writeToFile:@ CacheState_ atomically:YES];
}
[delegate_ performSelectorOnMainThread:@selector(releaseNetworkActivityIndicator) withObject:nil waitUntilDone:YES];
@"operator",
@"role",
@"serial",
- @"token",
@"version",
nil];
}
return [NSString stringWithUTF8String:Machine_];
}
-- (NSString *) token {
- return (id) Token_ ?: [NSNull null];
-}
-
+ (NSString *) webScriptNameForSelector:(SEL)selector {
if (false);
else if (selector == @selector(addBridgedHost:))
return @"addPipelinedHost";
else if (selector == @selector(addSource:::))
return @"addSource";
- else if (selector == @selector(addTokenHost:))
- return @"addTokenHost";
else if (selector == @selector(addTrivialSource:))
return @"addTrivialSource";
else if (selector == @selector(close))
[Values_ removeObjectForKey:key];
else
[Values_ setObject:value forKey:key];
-
- [delegate_ performSelectorOnMainThread:@selector(updateValues) withObject:nil waitUntilDone:YES];
} }
- (id) getSessionValue:(NSString *)key {
[InsecureHosts_ addObject:host];
} }
-- (void) addTokenHost:(NSString *)host {
-@synchronized (HostConfig_) {
- [TokenHosts_ addObject:host];
-} }
-
- (void) addPipelinedHost:(NSString *)host scheme:(NSString *)scheme {
@synchronized (HostConfig_) {
if (scheme != (id) [WebUndefined undefined])
nil] waitUntilDone:NO];
}
-- (void) addTrivialSource:(NSString *)href {
+- (BOOL) addTrivialSource:(NSString *)href {
+ href = VerifySource(href);
+ if (href == nil)
+ return NO;
[delegate_ performSelectorOnMainThread:@selector(addTrivialSource:) withObject:href waitUntilDone:NO];
+ return YES;
}
- (void) refreshSources {
nil];
}
-ssize_t DiskUsage(const char *path);
-
- (NSNumber *) du:(NSString *)path {
- ssize_t usage(DiskUsage([path UTF8String]));
- if (usage != -1)
- usage /= 1024;
- return [NSNumber numberWithUnsignedLong:usage];
+ NSNumber *value(nil);
+
+ FILE *du(popen([[NSString stringWithFormat:@"/usr/libexec/cydia/cydo /usr/libexec/cydia/du -ks %@", ShellEscape(path)] UTF8String], "r"));
+ if (du != NULL) {
+ char line[1024];
+ while (fgets(line, sizeof(line), du) != NULL) {
+ size_t length(strlen(line));
+ while (length != 0 && line[length - 1] == '\n')
+ line[--length] = '\0';
+ if (char *tab = strchr(line, '\t')) {
+ *tab = '\0';
+ value = [NSNumber numberWithUnsignedLong:strtoul(line, NULL, 0)];
+ }
+ }
+ pclose(du);
+ }
+
+ return value;
}
- (void) close {
[[objc_getClass("UIPasteboard") generalPasteboard] setURL:[NSURL URLWithString:value]];
}
-- (void) _setToken:(NSString *)token {
- Token_ = token;
-
- if (token == nil)
- [Metadata_ removeObjectForKey:@"Token"];
- else
- [Metadata_ setObject:Token_ forKey:@"Token"];
-
- Changed_ = true;
-}
-
- (void) setToken:(NSString *)token {
- [self performSelectorOnMainThread:@selector(_setToken:) withObject:token waitUntilDone:NO];
+ // XXX: the website expects this :/
}
- (void) scrollToBottom:(NSNumber *)animated {
if (Machine_ != NULL && [copy valueForHTTPHeaderField:@"X-Machine"] == nil)
[copy setValue:[NSString stringWithUTF8String:Machine_] forHTTPHeaderField:@"X-Machine"];
- bool bridged;
- bool token;
-
- @synchronized (HostConfig_) {
+ bool bridged; @synchronized (HostConfig_) {
bridged = [BridgedHosts_ containsObject:host];
- token = [TokenHosts_ containsObject:host];
}
- if ([url isCydiaSecure]) {
- if (bridged) {
- if (UniqueID_ != nil && [copy valueForHTTPHeaderField:@"X-Cydia-Id"] == nil)
- [copy setValue:UniqueID_ forHTTPHeaderField:@"X-Cydia-Id"];
- } else if (token) {
- if (Token_ != nil && [copy valueForHTTPHeaderField:@"X-Cydia-Token"] == nil)
- [copy setValue:Token_ forHTTPHeaderField:@"X-Cydia-Token"];
- }
- }
+ if ([url isCydiaSecure] && bridged && UniqueID_ != nil && [copy valueForHTTPHeaderField:@"X-Cydia-Id"] == nil)
+ [copy setValue:UniqueID_ forHTTPHeaderField:@"X-Cydia-Id"];
return copy;
}
issues_ = [NSMutableArray arrayWithCapacity:4];
- UpgradeCydia_ = false;
-
for (Package *package in packages) {
pkgCache::PkgIterator iterator([package iterator]);
NSString *name([package id]);
[removes addObject:name];
}
- if ([name isEqualToString:@"cydia"])
- UpgradeCydia_ = true;
-
substrate_ |= DepSubstrate(policy->GetCandidateVer(iterator));
substrate_ |= DepSubstrate(iterator.CurrentVer());
}
[super viewWillAppear:animated];
}
-- (void) reloadSpringBoard {
- if (kCFCoreFoundationVersionNumber > 700) { // XXX: iOS 6.x
- system("/bin/launchctl stop com.apple.backboardd");
- sleep(15);
- system("/usr/bin/killall backboardd SpringBoard sbreload");
- return;
- }
-
- pid_t pid(ExecFork());
- if (pid == 0) {
- if (setsid() == -1)
- perror("setsid");
-
- pid_t pid(ExecFork());
- if (pid == 0) {
- execl("/usr/libexec/cydia/cydo", "cydo", "/usr/bin/sbreload", NULL);
- perror("sbreload");
-
- exit(0);
- } ReapZombie(pid);
-
- exit(0);
- } ReapZombie(pid);
-
- sleep(15);
- system("/usr/bin/killall backboardd SpringBoard sbreload");
-}
-
- (void) close {
UpdateExternalStatus(0);
reload: {
UIProgressHUD *hud([delegate_ addProgressHUD]);
[hud setText:UCLocalize("LOADING")];
- [self performSelector:@selector(reloadSpringBoard) withObject:nil afterDelay:0.5];
+ [delegate_ performSelector:@selector(reloadSpringBoard) withObject:nil afterDelay:0.5];
return;
}
}
[metadata setObject:[NSNumber numberWithBool:([switch_ isOn] == NO)] forKey:@"Hidden"];
- Changed_ = true;
}
- (void) setSection:(Section *)section editing:(BOOL)editing {
[alert setCancelButtonIndex:0];
[alert setMessage:
- @"Copyright \u00a9 2008-2014\n"
+ @"Copyright \u00a9 2008-2015\n"
"SaurikIT, LLC\n"
"\n"
"Jay Freeman (saurik)\n"
} return self;
}
-- (void) setUpdate:(NSDate *)date {
- [self beginUpdate];
-}
-
- (void) beginUpdate {
if (updating_)
return;
const char *package([name_ UTF8String]);
bool on([ignoredSwitch_ isOn]);
- pid_t pid(ExecFork());
- if (pid == 0) {
- FILE *dpkg(popen("/usr/libexec/cydo --set-selections", "w"));
- fwrite(package, strlen(package), 1, dpkg);
-
- if (on)
- fwrite(" hold\n", 6, 1, dpkg);
- else
- fwrite(" install\n", 9, 1, dpkg);
+ FILE *dpkg(popen("/usr/libexec/cydia/cydo --set-selections", "w"));
+ fwrite(package, strlen(package), 1, dpkg);
- pclose(dpkg);
+ if (on)
+ fwrite(" hold\n", 6, 1, dpkg);
+ else
+ fwrite(" install\n", 9, 1, dpkg);
- exit(0);
- } ReapZombie(pid);
+ pclose(dpkg);
}
- (void) onIgnored:(id)control {
if (source == nil) return;
[Sources_ removeObjectForKey:[source key]];
- Changed_ = true;
[delegate_ _saveConfig];
[delegate_ reloadDataWithInvocation:nil];
switch (button) {
case 1: {
NSString *href = [[alert textField] text];
-
- static RegEx href_r("(http(s?)://|file:///)[^# ]*");
- if (!href_r(href)) {
- UIAlertView *alert = [[[UIAlertView alloc]
- initWithTitle:[NSString stringWithFormat:Colon_, Error_, UCLocalize("INVALID_URL")]
- message:UCLocalize("INVALID_URL_EX")
- delegate:self
- cancelButtonTitle:UCLocalize("OK")
- otherButtonTitles:nil
- ] autorelease];
-
- [alert setContext:@"badurl"];
- [alert show];
-
+ href = VerifySource(href);
+ if (href == nil)
break;
- }
-
- if (![href hasSuffix:@"/"])
- href_ = [href stringByAppendingString:@"/"];
- else
- href_ = href;
+ href_ = href;
trivial_bz2_ = [[self _requestHRef:[href_ stringByAppendingString:@"Packages.bz2"] method:@"HEAD"] retain];
trivial_gz_ = [[self _requestHRef:[href_ stringByAppendingString:@"Packages.gz"] method:@"HEAD"] retain];
[self _loaded];
}
-- (void) _saveConfig {
- @synchronized (database_) {
- _trace();
- MetaFile_.Sync();
- _trace();
- }
-
- if (Changed_) {
- NSString *error(nil);
-
- if (NSData *data = [NSPropertyListSerialization dataFromPropertyList:Metadata_ format:NSPropertyListBinaryFormat_v1_0 errorDescription:&error]) {
- _trace();
- NSError *error(nil);
- if (!_root([data writeToFile:@"/var/lib/cydia/metadata.plist" options:NSAtomicWrite error:&error]))
- NSLog(@"failure to save metadata data: %@", error);
- _trace();
-
- Changed_ = false;
- } else {
- NSLog(@"failure to serialize metadata: %@", error);
- }
- }
+- (void) reloadSpringBoard {
+ if (kCFCoreFoundationVersionNumber >= 700) // XXX: iOS 6.x
+ system("/bin/launchctl stop com.apple.backboardd");
+ else
+ system("/bin/launchctl stop com.apple.SpringBoard");
+ sleep(15);
+ system("/usr/bin/killall backboardd SpringBoard");
+}
- _root(CydiaWriteSources());
+- (void) _saveConfig {
+ SaveConfig(database_);
}
// Navigation controller for the queuing badge.
[[navigation tabBarItem] setBadgeValue:(Queuing_ ? UCLocalize("Q_D") : nil)];
}
-- (void) _refreshIfPossible:(NSDate *)update {
+- (void) _refreshIfPossible {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ NSDate *update([[NSDictionary dictionaryWithContentsOfFile:@ CacheState_] objectForKey:@"LastUpdate"]);
+
bool recently = false;
if (update != nil) {
NSTimeInterval interval([update timeIntervalSinceNow]);
// We are going to load, so remember that.
loaded_ = true;
- [tabbar_ performSelectorOnMainThread:@selector(setUpdate:) withObject:update waitUntilDone:NO];
+ [tabbar_ performSelectorOnMainThread:@selector(beginUpdate) withObject:nil waitUntilDone:NO];
}
[pool release];
}
- (void) refreshIfPossible {
- [NSThread detachNewThreadSelector:@selector(_refreshIfPossible:) toTarget:self withObject:[Metadata_ objectForKey:@"LastUpdate"]];
+ [NSThread detachNewThreadSelector:@selector(_refreshIfPossible) toTarget:self withObject:nil];
}
- (void) reloadDataWithInvocation:(NSInvocation *)invocation {
CydiaAddSource(href, distribution, sections);
}
-- (void) addTrivialSource:(NSString *)href {
+// XXX: this method should not return anything
+- (BOOL) addTrivialSource:(NSString *)href {
CydiaAddSource(href, @"./");
-}
-
-- (void) updateValues {
- Changed_ = true;
+ return YES;
}
- (void) resolve {
- (void) _uicache {
_trace();
-
- if (UpgradeCydia_ && Finish_ > 0) {
- setreugid(0, 0);
- system("su -c /usr/bin/uicache mobile");
- } else {
- system("/usr/bin/uicache");
- }
-
+ system("/usr/bin/uicache");
_trace();
}
@synchronized (self) {
for (Package *broken in (id) broken_) {
[broken remove];
- NSString *id = [broken id];
-
- _root({
- unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.prerm", id] UTF8String]);
- unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.postrm", id] UTF8String]);
- unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.preinst", id] UTF8String]);
- unlink([[NSString stringWithFormat:@"/var/lib/dpkg/info/%@.postinst", id] UTF8String]);
- });
+ NSString *id(ShellEscape([broken id]));
+ system([[NSString stringWithFormat:@"/usr/libexec/cydia/cydo /bin/rm -f"
+ " /var/lib/dpkg/info/%@.prerm"
+ " /var/lib/dpkg/info/%@.postrm"
+ " /var/lib/dpkg/info/%@.preinst"
+ " /var/lib/dpkg/info/%@.postinst"
+ " /var/lib/dpkg/info/%@.extrainst_"
+ "", id, id, id, id, id] UTF8String]);
}
[self resolve];
controller = [[[SectionController alloc] initWithDatabase:database_ source:nil section:argument] autorelease];
}
- if (!external && [base isEqualToString:@"sources"]) {
+ if ([base isEqualToString:@"sources"]) {
if ([argument isEqualToString:@"add"]) {
controller = [[[SourcesController alloc] initWithDatabase:database_] autorelease];
[(SourcesController *)controller showAddSourcePrompt];
}
- (void) saveState {
- [Metadata_ setObject:[tabbar_ navigationURLCollection] forKey:@"InterfaceState"];
- [Metadata_ setObject:[NSDate date] forKey:@"LastClosed"];
- [Metadata_ setObject:[NSNumber numberWithInt:[tabbar_ selectedIndex]] forKey:@"InterfaceIndex"];
- Changed_ = true;
+ [[NSDictionary dictionaryWithObjectsAndKeys:
+ @"InterfaceState", [tabbar_ navigationURLCollection],
+ @"LastClosed", [NSDate date],
+ @"InterfaceIndex", [NSNumber numberWithInt:[tabbar_ selectedIndex]],
+ nil] writeToFile:@ SavedState_ atomically:YES];
[self _saveConfig];
}
- (void) applicationDidEnterBackground:(UIApplication *)application {
if (kCFCoreFoundationVersionNumber < 1000 && [self isSafeToSuspend])
return [self terminateWithSuccess];
+ Backgrounded_ = [NSDate date];
[self saveState];
}
- (void) applicationWillEnterForeground:(UIApplication *)application {
- NSDate *closed = [Metadata_ objectForKey:@"LastClosed"];
- if (closed == nil)
+ if (Backgrounded_ == nil)
return;
- NSTimeInterval interval([closed timeIntervalSinceNow]);
+ NSTimeInterval interval([Backgrounded_ timeIntervalSinceNow]);
if (interval <= -(30*60)) {
[tabbar_ setSelectedIndex:0];
[appcache_ reloadURLWithCache:YES];
}
}
+
+ if ([database_ delocked])
+ [self reloadData];
}
- (void) setConfigurationData:(NSString *)data {
UpdateExternalStatus(0);
[self removeStashController];
-
- pid_t pid(ExecFork());
- if (pid == 0) {
- execlp("launchctl", "launchctl", "stop", "com.apple.SpringBoard", NULL);
- perror("launchctl stop");
-
- exit(0);
- } ReapZombie(pid);
+ [self reloadSpringBoard];
}
- (void) setupViewControllers {
[self refreshIfPossible];
[self disemulate];
- int savedIndex = [[Metadata_ objectForKey:@"InterfaceIndex"] intValue];
- NSArray *saved = [[[Metadata_ objectForKey:@"InterfaceState"] mutableCopy] autorelease];
+ NSDictionary *state([NSDictionary dictionaryWithContentsOfFile:@ SavedState_]);
+
+ int savedIndex = [[state objectForKey:@"InterfaceIndex"] intValue];
+ NSArray *saved = [[[state objectForKey:@"InterfaceState"] mutableCopy] autorelease];
int standardIndex = 0;
NSArray *standard = [self defaultStartPages];
if (saved == nil)
valid = NO;
- NSDate *closed = [Metadata_ objectForKey:@"LastClosed"];
+ NSDate *closed = [state objectForKey:@"LastClosed"];
if (valid && closed != nil) {
NSTimeInterval interval([closed timeIntervalSinceNow]);
if (interval <= -(30*60))
return _NSUserDefaults$objectForKey$(self, _cmd, key);
}
+static NSMutableDictionary *AutoreleaseDeepMutableCopyOfDictionary(CFTypeRef type) {
+ if (type == NULL)
+ return nil;
+ if (CFGetTypeID(type) != CFDictionaryGetTypeID())
+ return nil;
+ CFTypeRef copy(CFPropertyListCreateDeepCopy(kCFAllocatorDefault, type, kCFPropertyListMutableContainers));
+ CFRelease(type);
+ return [(NSMutableDictionary *) copy autorelease];
+}
+
int main(int argc, char *argv[]) {
- setreugid(501, 501);
+ int fd(open("/tmp/cydia.log", O_WRONLY | O_APPEND | O_CREAT, 0644));
+ dup2(fd, 2);
+ close(fd);
NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
HostConfig_ = [[[NSObject alloc] init] autorelease];
@synchronized (HostConfig_) {
BridgedHosts_ = [NSMutableSet setWithCapacity:4];
- TokenHosts_ = [NSMutableSet setWithCapacity:4];
InsecureHosts_ = [NSMutableSet setWithCapacity:4];
PipelinedHosts_ = [NSMutableSet setWithCapacity:4];
CachedURLs_ = [NSMutableSet setWithCapacity:32];
UserAgent_ = agent;
/* }}} */
/* Load Database {{{ */
- _trace();
- Metadata_ = [[[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"] autorelease];
- _trace();
SectionMap_ = [[[NSDictionary alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Sections" ofType:@"plist"]] autorelease];
- if (Metadata_ == NULL)
- Metadata_ = [NSMutableDictionary dictionaryWithCapacity:2];
- else {
- Settings_ = [Metadata_ objectForKey:@"Settings"];
-
- Packages_ = [Metadata_ objectForKey:@"Packages"];
-
- Values_ = [Metadata_ objectForKey:@"Values"];
- Sections_ = [Metadata_ objectForKey:@"Sections"];
- Sources_ = [Metadata_ objectForKey:@"Sources"];
+ _trace();
+ mkdir("/var/mobile/Library/Cydia", 0755);
+ MetaFile_.Open("/var/mobile/Library/Cydia/metadata.cb0");
+ _trace();
- Token_ = [Metadata_ objectForKey:@"Token"];
+ Values_ = AutoreleaseDeepMutableCopyOfDictionary(CFPreferencesCopyAppValue(CFSTR("CydiaValues"), CFSTR("com.saurik.Cydia")));
+ Sections_ = AutoreleaseDeepMutableCopyOfDictionary(CFPreferencesCopyAppValue(CFSTR("CydiaSections"), CFSTR("com.saurik.Cydia")));
+ Sources_ = AutoreleaseDeepMutableCopyOfDictionary(CFPreferencesCopyAppValue(CFSTR("CydiaSources"), CFSTR("com.saurik.Cydia")));
+ Version_ = [(NSNumber *) CFPreferencesCopyAppValue(CFSTR("CydiaVersion"), CFSTR("com.saurik.Cydia")) autorelease];
- Version_ = [Metadata_ objectForKey:@"Version"];
- }
+ _trace();
+ NSDictionary *metadata([[[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"] autorelease]);
- if (Values_ == nil) {
+ if (Values_ == nil)
+ Values_ = [metadata objectForKey:@"Values"];
+ if (Values_ == nil)
Values_ = [[[NSMutableDictionary alloc] initWithCapacity:4] autorelease];
- [Metadata_ setObject:Values_ forKey:@"Values"];
- }
- if (Sections_ == nil) {
+ if (Sections_ == nil)
+ Sections_ = [metadata objectForKey:@"Sections"];
+ if (Sections_ == nil)
Sections_ = [[[NSMutableDictionary alloc] initWithCapacity:32] autorelease];
- [Metadata_ setObject:Sections_ forKey:@"Sections"];
- }
- if (Sources_ == nil) {
+ if (Sources_ == nil)
+ Sources_ = [metadata objectForKey:@"Sources"];
+ if (Sources_ == nil)
Sources_ = [[[NSMutableDictionary alloc] initWithCapacity:0] autorelease];
- [Metadata_ setObject:Sources_ forKey:@"Sources"];
- }
- if (Version_ == nil) {
+ // XXX: this wrong, but in a way that doesn't matter :/
+ if (Version_ == nil)
+ Version_ = [metadata objectForKey:@"Version"];
+ if (Version_ == nil)
Version_ = [NSNumber numberWithUnsignedInt:0];
- [Metadata_ setObject:Version_ forKey:@"Version"];
+
+ if (NSDictionary *packages = [metadata objectForKey:@"Packages"]) {
+ bool fail(false);
+ CFDictionaryApplyFunction((CFDictionaryRef) packages, &PackageImport, &fail);
+ _trace();
+ if (fail)
+ NSLog(@"unable to import package preferences... from 2010? oh well :/");
}
if ([Version_ unsignedIntValue] == 0) {
CydiaAddSource(@"http://repo666.ultrasn0w.com/", @"./");
Version_ = [NSNumber numberWithUnsignedInt:1];
- [Metadata_ setObject:Version_ forKey:@"Version"];
-
- [Metadata_ removeObjectForKey:@"LastUpdate"];
- Changed_ = true;
+ if (NSMutableDictionary *cache = [NSMutableDictionary dictionaryWithContentsOfFile:@ CacheState_]) {
+ [cache removeObjectForKey:@"LastUpdate"];
+ [cache writeToFile:@ CacheState_ atomically:YES];
+ }
}
_H<NSMutableArray> broken([NSMutableArray array]);
for (NSString *key in (id) Sources_)
- if ([key rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@"# "]].location != NSNotFound)
+ if ([key rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@"# "]].location != NSNotFound || ![([[Sources_ objectForKey:key] objectForKey:@"URI"] ?: @"/") hasSuffix:@"/"])
[broken addObject:key];
- if ([broken count] != 0) {
+ if ([broken count] != 0)
for (NSString *key in (id) broken)
[Sources_ removeObjectForKey:key];
- Changed_ = true;
- } broken = nil;
- /* }}} */
-
- _root(CydiaWriteSources());
+ broken = nil;
- _trace();
- mkdir("/var/mobile/Library/Cydia", 0755);
- MetaFile_.Open("/var/mobile/Library/Cydia/metadata.cb0");
- _trace();
-
- if (Packages_ != nil) {
- bool fail(false);
- CFDictionaryApplyFunction((CFDictionaryRef) Packages_, &PackageImport, &fail);
- _trace();
-
- if (!fail) {
- [Metadata_ removeObjectForKey:@"Packages"];
- Packages_ = nil;
- Changed_ = true;
- }
- }
+ SaveConfig(nil);
+ system("/usr/libexec/cydia/cydo /bin/rm -f /var/lib/cydia/metadata.plist");
+ /* }}} */
Finishes_ = [NSArray arrayWithObjects:@"return", @"reopen", @"restart", @"reload", @"reboot", nil];
-#define MobileSubstrate_(name) \
- if (substrate && access("/Library/MobileSubstrate/DynamicLibraries/" #name ".dylib", F_OK) == 0) { \
- void *handle(dlopen("/Library/MobileSubstrate/DynamicLibraries/" #name ".dylib", RTLD_LAZY | RTLD_GLOBAL)); \
- if (handle == NULL) \
- NSLog(@"%s", dlerror()); \
- }
-
- MobileSubstrate_(Activator)
- MobileSubstrate_(libstatusbar)
- MobileSubstrate_(SimulatedKeyEvents)
- MobileSubstrate_(WinterBoard)
-
- /*if (substrate && access("/Library/MobileSubstrate/MobileSubstrate.dylib", F_OK) == 0)
- dlopen("/Library/MobileSubstrate/MobileSubstrate.dylib", RTLD_LAZY | RTLD_GLOBAL);*/
-
if (kCFCoreFoundationVersionNumber > 1000)
system("/usr/libexec/cydia/cydo /usr/libexec/cydia/setnsfpn /var/lib");
_assert(errno == ENOENT);
}
+ system("/usr/libexec/cydia/cydo /bin/ln -sf /var/mobile/Library/Caches/com.saurik.Cydia/sources.list /etc/apt/sources.list.d/cydia.list");
+
/* APT Initialization {{{ */
_assert(pkgInitConfig(*_config));
_assert(pkgInitSystem(*_config, _system));
mkdir([Cache("archives/partial") UTF8String], 0755);
_config->Set("Dir::Cache", [Cache_ UTF8String]);
+ symlink("/var/lib/apt/extended_states", [Cache("extended_states") UTF8String]);
+ _config->Set("Dir::State", [Cache_ UTF8String]);
+
mkdir([Cache("lists") UTF8String], 0755);
mkdir([Cache("lists/partial") UTF8String], 0755);
mkdir([Cache("periodic") UTF8String], 0755);