]> git.saurik.com Git - cydia.git/blobdiff - Cydia.mm
Fixed _blank behavior for cydia:// due to prophylactic swapping.
[cydia.git] / Cydia.mm
index 7e4f33fef4ca7466bd7eed9aade6d1b2296c34c2..d898ef3a775fe902a18b1f438b464603ad53e597 100644 (file)
--- a/Cydia.mm
+++ b/Cydia.mm
@@ -232,7 +232,8 @@ void NSLogRect(const char *fix, const CGRect &rect) {
 }
 
 @interface NSObject (Cydia)
-- (void) yieldToSelector:(SEL)selector withObject:(id)object;
+- (id) yieldToSelector:(SEL)selector withObject:(id)object;
+- (id) yieldToSelector:(SEL)selector;
 @end
 
 @implementation NSObject (Cydia)
@@ -240,12 +241,17 @@ void NSLogRect(const char *fix, const CGRect &rect) {
 - (void) doNothing {
 }
 
-- (void) _yieldToContext:(NSArray *)context { _pooled
+- (void) _yieldToContext:(NSMutableArray *)context { _pooled
     SEL selector(reinterpret_cast<SEL>([[context objectAtIndex:0] pointerValue]));
     id object([[context objectAtIndex:1] nonretainedObjectValue]);
     volatile bool &stopped(*reinterpret_cast<bool *>([[context objectAtIndex:2] pointerValue]));
 
-    [self performSelector:selector withObject:object];
+    /* XXX: deal with exceptions */
+    id value([self performSelector:selector withObject:object]);
+
+    [context removeAllObjects];
+    if (value != nil)
+        [context addObject:value];
 
     stopped = true;
 
@@ -256,13 +262,12 @@ void NSLogRect(const char *fix, const CGRect &rect) {
     ];
 }
 
-- (void) yieldToSelector:(SEL)selector withObject:(id)object {
-    [self performSelector:selector withObject:object];
-    return;
+- (id) yieldToSelector:(SEL)selector withObject:(id)object {
+    /*return [self performSelector:selector withObject:object];*/
 
     volatile bool stopped(false);
 
-    NSArray *context([NSArray arrayWithObjects:
+    NSMutableArray *context([NSMutableArray arrayWithObjects:
         [NSValue valueWithPointer:selector],
         [NSValue valueWithNonretainedObject:object],
         [NSValue valueWithPointer:const_cast<bool *>(&stopped)],
@@ -280,6 +285,12 @@ void NSLogRect(const char *fix, const CGRect &rect) {
     NSDate *future([NSDate distantFuture]);
 
     while (!stopped && [loop runMode:NSDefaultRunLoopMode beforeDate:future]);
+
+    return [context count] == 0 ? nil : [context objectAtIndex:0];
+}
+
+- (id) yieldToSelector:(SEL)selector {
+    return [self yieldToSelector:selector withObject:nil];
 }
 
 @end
@@ -370,9 +381,9 @@ extern NSString * const kCAFilterNearest;
 
 #define lprintf(args...) fprintf(stderr, args)
 
-#define ForRelease 0
+#define ForRelease 1
 #define ForSaurik (1 && !ForRelease)
-#define ShowInternals (0 && !ForRelease)
+#define ShowInternals (1 && !ForRelease)
 #define IgnoreInstall (0 && !ForRelease)
 #define RecycleWebViews 0
 #define AlwaysReload (1 && !ForRelease)
@@ -381,9 +392,10 @@ extern NSString * const kCAFilterNearest;
 #undef _trace
 #define _trace(args...)
 #undef _profile
-#define _profile(name)
+#define _profile(name) {
 #undef _end
-#define _end
+#define _end }
+#define PrintTimes() do {} while (false)
 #endif
 
 /* Radix Sort {{{ */
@@ -524,6 +536,8 @@ NSUInteger DOMNodeList$countByEnumeratingWithState$objects$count$(DOMNodeList *s
 + (NSString *) stringWithUTF8BytesNoCopy:(const char *)bytes length:(int)length;
 + (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length;
 - (NSComparisonResult) compareByPath:(NSString *)other;
+- (NSString *) stringByCachingURLWithCurrentCDN;
+- (NSString *) stringByAddingPercentEscapesIncludingReserved;
 @end
 
 @implementation NSString (Cydia)
@@ -566,6 +580,26 @@ NSUInteger DOMNodeList$countByEnumeratingWithState$objects$count$(DOMNodeList *s
     return result == NSOrderedSame ? value : result;
 }
 
+- (NSString *) stringByCachingURLWithCurrentCDN {
+    return [self
+        stringByReplacingOccurrencesOfString:@"://"
+        withString:@"://ne.edgecastcdn.net/8003A4/"
+        options:0
+        /* XXX: this is somewhat inaccurate */
+        range:NSMakeRange(0, 10)
+    ];
+}
+
+- (NSString *) stringByAddingPercentEscapesIncludingReserved {
+    return [(id)CFURLCreateStringByAddingPercentEscapes(
+        kCFAllocatorDefault, 
+        (CFStringRef) self,
+        NULL,
+        CFSTR(";/?:@&=+$,"),
+        kCFStringEncodingUTF8
+    ) autorelease];
+}
+
 @end
 
 /* Perl-Compatible RegEx {{{ */
@@ -752,6 +786,8 @@ static UIFont *Font22Bold_;
 static const char *Machine_ = NULL;
 static const NSString *UniqueID_ = nil;
 static const NSString *Build_ = nil;
+static const NSString *Product_ = nil;
+static const NSString *Safari_ = nil;
 
 CFLocaleRef Locale_;
 CGColorSpaceRef space_;
@@ -997,6 +1033,8 @@ class Progress :
 
 /* Database Interface {{{ */
 @interface Database : NSObject {
+    unsigned era_;
+
     pkgCacheFile cache_;
     pkgDepCache::Policy *policy_;
     pkgRecords *records_;
@@ -1019,6 +1057,7 @@ class Progress :
 }
 
 + (Database *) sharedInstance;
+- (unsigned) era;
 
 - (void) _readCydia:(NSNumber *)fd;
 - (void) _readStatus:(NSNumber *)fd;
@@ -1289,6 +1328,8 @@ class Progress :
 /* }}} */
 /* Package Class {{{ */
 @interface Package : NSObject {
+    unsigned era_;
+
     pkgCache::PkgIterator iterator_;
     _transient Database *database_;
     pkgCache::VerIterator version_;
@@ -1298,6 +1339,7 @@ class Progress :
     bool cached_;
 
     NSString *section_;
+    bool essential_;
 
     NSString *latest_;
     NSString *installed_;
@@ -1395,7 +1437,6 @@ class Progress :
 - (void) dealloc {
     if (source_ != nil)
         [source_ release];
-
     if (section_ != nil)
         [section_ release];
 
@@ -1441,7 +1482,11 @@ class Progress :
 }
 
 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
-    if ((self = [super init]) != nil) { _profile(Package$initWithIterator)
+    if ((self = [super init]) != nil) {
+    _profile(Package$initWithIterator)
+    @synchronized (database) {
+        era_ = [database era];
+
         iterator_ = iterator;
         database_ = database;
 
@@ -1628,7 +1673,25 @@ class Progress :
                 Changed_ = true;
             }
         _end
-    _end } return self;
+
+        const char *section(iterator_.Section());
+        if (section == NULL)
+            section_ = nil;
+        else {
+            NSString *name([[NSString stringWithUTF8String:section] stringByReplacingCharacter:' ' withCharacter:'_']);
+
+          lookup:
+            if (NSDictionary *value = [SectionMap_ objectForKey:name])
+                if (NSString *rename = [value objectForKey:@"Rename"]) {
+                    name = rename;
+                    goto lookup;
+                }
+
+            section_ = [[name stringByReplacingCharacter:'_' withCharacter:' '] retain];
+        }
+
+        essential_ = (iterator_->Flags & pkgCache::Flag::Essential) == 0 ? NO : YES;
+    } _end } return self;
 }
 
 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
@@ -1643,23 +1706,6 @@ class Progress :
 }
 
 - (NSString *) section {
-    if (section_ != nil)
-        return section_;
-
-    const char *section = iterator_.Section();
-    if (section == NULL)
-        return nil;
-
-    NSString *name = [[NSString stringWithUTF8String:section] stringByReplacingCharacter:' ' withCharacter:'_'];
-
-  lookup:
-    if (NSDictionary *value = [SectionMap_ objectForKey:name])
-        if (NSString *rename = [value objectForKey:@"Rename"]) {
-            name = rename;
-            goto lookup;
-        }
-
-    section_ = [[name stringByReplacingCharacter:'_' withCharacter:' '] retain];
     return section_;
 }
 
@@ -1723,7 +1769,7 @@ class Progress :
         unichar character([name characterAtIndex:0]);
         if (!isalpha(character))
             return '#';
-        return character;
+        return toupper(character);
     _end
 }
 
@@ -1779,7 +1825,7 @@ class Progress :
 }
 
 - (BOOL) essential {
-    return (iterator_->Flags & pkgCache::Flag::Essential) == 0 ? NO : YES;
+    return essential_;
 }
 
 - (BOOL) broken {
@@ -1993,8 +2039,17 @@ class Progress :
 
 - (Source *) source {
     if (!cached_) {
-        source_ = file_.end() ? nil : [[database_ getSource:file_.File()] retain];
-        cached_ = true;
+        @synchronized (database_) {
+            if ([database_ era] != era_ || file_.end())
+                source_ = nil;
+            else {
+                source_ = [database_ getSource:file_.File()];
+                if (source_ != nil)
+                    [source_ retain];
+            }
+
+            cached_ = true;
+        }
     }
 
     return source_;
@@ -2237,7 +2292,7 @@ class Progress :
 
 - (Section *) initWithIndex:(unichar)index row:(size_t)row {
     if ((self = [super init]) != nil) {
-        name_ = [[NSString stringWithCharacters:&index length:1] retain];
+        name_ = [(index == '#' ? @"123" : [NSString stringWithCharacters:&index length:1]) retain];
         index_ = index;
         row_ = row;
     } return self;
@@ -2279,6 +2334,10 @@ static NSArray *Finishes_;
     return instance;
 }
 
+- (unsigned) era {
+    return era_;
+}
+
 - (void) dealloc {
     _assert(false);
     [super dealloc];
@@ -2523,6 +2582,10 @@ static NSArray *Finishes_;
 }
 
 - (void) reloadData { _pooled
+    @synchronized (self) {
+        ++era_;
+    }
+
     _error->Discard();
 
     delete list_;
@@ -3074,11 +3137,15 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     return @"Cancel";
 }
 
+- (id) rightButtonTitle {
+    return issues_ != nil ? nil : [super rightButtonTitle];
+}
+
 - (id) _rightButtonTitle {
 #if AlwaysReload || IgnoreInstall
-    return @"Reload";
+    return [super _rightButtonTitle];
 #else
-    return issues_ == nil ? @"Confirm" : nil;
+    return @"Confirm";
 #endif
 }
 
@@ -4110,6 +4177,10 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     [super webView:sender didClearWindowObject:window forFrame:frame];
 }
 
+- (bool) _allowJavaScriptPanel {
+    return false;
+}
+
 #if !AlwaysReload
 - (void) _rightButtonClicked {
     /*[super _rightButtonClicked];
@@ -4649,6 +4720,35 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     [delegate_ syncData];
 }
 
+- (void) complete {
+    [Sources_ setObject:[NSDictionary dictionaryWithObjectsAndKeys:
+        @"deb", @"Type",
+        href_, @"URI",
+        @"./", @"Distribution",
+    nil] forKey:[NSString stringWithFormat:@"deb:%@:./", href_]];
+
+    [delegate_ syncData];
+}
+
+- (NSString *) getWarning {
+    NSString *href(href_);
+    NSRange colon([href rangeOfString:@"://"]);
+    if (colon.location != NSNotFound)
+        href = [href substringFromIndex:(colon.location + 3)];
+    href = [href stringByAddingPercentEscapes];
+    href = [@"http://cydia.saurik.com/api/repotag/" stringByAppendingString:href];
+    href = [href stringByCachingURLWithCurrentCDN];
+
+    NSURL *url([NSURL URLWithString:href]);
+
+    NSStringEncoding encoding;
+    NSError *error(nil);
+
+    if (NSString *warning = [NSString stringWithContentsOfURL:url usedEncoding:&encoding error:&error])
+        return [warning length] == 0 ? nil : warning;
+    return nil;
+}
+
 - (void) _endConnection:(NSURLConnection *)connection {
     NSURLConnection **field = NULL;
     if (connection == trivial_bz2_)
@@ -4663,20 +4763,26 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         trivial_bz2_ == nil &&
         trivial_gz_ == nil
     ) {
-        [delegate_ setStatusBarShowsProgress:NO];
-        [delegate_ removeProgressHUD:hud_];
-
-        [hud_ autorelease];
-        hud_ = nil;
+        bool defer(false);
 
         if (trivial_) {
-            [Sources_ setObject:[NSDictionary dictionaryWithObjectsAndKeys:
-                @"deb", @"Type",
-                href_, @"URI",
-                @"./", @"Distribution",
-            nil] forKey:[NSString stringWithFormat:@"deb:%@:./", href_]];
-
-            [delegate_ syncData];
+            if (NSString *warning = [self yieldToSelector:@selector(getWarning)]) {
+                defer = true;
+
+                UIActionSheet *sheet = [[[UIActionSheet alloc]
+                    initWithTitle:@"Source Warning"
+                    buttons:[NSArray arrayWithObjects:@"Add Anyway", @"Cancel", nil]
+                    defaultButtonIndex:0
+                    delegate:self
+                    context:@"warning"
+                ] autorelease];
+
+                [sheet setNumberOfRows:1];
+
+                [sheet setBodyText:warning];
+                [sheet popupAlertAnimated:YES];
+            } else
+                [self complete];
         } else if (error_ != nil) {
             UIActionSheet *sheet = [[[UIActionSheet alloc]
                 initWithTitle:@"Verification Error"
@@ -4701,8 +4807,16 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
             [sheet popupAlertAnimated:YES];
         }
 
-        [href_ release];
-        href_ = nil;
+        [delegate_ setStatusBarShowsProgress:NO];
+        [delegate_ removeProgressHUD:hud_];
+
+        [hud_ autorelease];
+        hud_ = nil;
+
+        if (!defer) {
+            [href_ release];
+            href_ = nil;
+        }
 
         if (error_ != nil) {
             [error_ release];
@@ -4779,6 +4893,24 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         [sheet dismiss];
     else if ([context isEqualToString:@"urlerror"])
         [sheet dismiss];
+    else if ([context isEqualToString:@"warning"]) {
+        switch (button) {
+            case 1:
+                [self complete];
+            break;
+
+            case 2:
+            break;
+
+            default:
+                _assert(false);
+        }
+
+        [href_ release];
+        href_ = nil;
+
+        [sheet dismiss];
+    }
 }
 
 - (id) initWithBook:(RVBook *)book database:(Database *)database {
@@ -4992,7 +5124,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     ] autorelease];
 
     [sheet setBodyText:
-        @"Copyright (C) 2008\n"
+        @"Copyright (C) 2008-2009\n"
         "Jay Freeman (saurik)\n"
         "saurik@saurik.com\n"
         "http://www.saurik.com/\n"
@@ -6383,8 +6515,10 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 - (void) _reloadData {
     UIView *block();
 
+    static bool loaded(false);
     UIProgressHUD *hud([self addProgressHUD]);
-    [hud setText:@"Reloading Data"];
+    [hud setText:(loaded ? @"Reloading Data" : @"Loading Data")];
+    loaded = true;
 
     [database_ yieldToSelector:@selector(reloadData) withObject:nil];
     _trace();
@@ -6424,7 +6558,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
     // XXX: what is this line of code for?
     if ([packages count] == 0);
-    else if (Loaded_) loaded:
+    else if (Loaded_ || ForSaurik) loaded:
         [self _loaded];
     else {
         Loaded_ = YES;
@@ -7202,7 +7336,7 @@ int main(int argc, char *argv[]) { _pooled
     setuid(0);
     setgid(0);
 
-#if 0 /* XXX: this costs 1.4s of startup performance */
+#if 1 /* XXX: this costs 1.4s of startup performance */
     if (unlink("/var/cache/apt/pkgcache.bin") == -1)
         _assert(errno == ENOENT);
     if (unlink("/var/cache/apt/srcpkgcache.bin") == -1)
@@ -7240,6 +7374,10 @@ int main(int argc, char *argv[]) { _pooled
 
     if (NSDictionary *system = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"])
         Build_ = [system objectForKey:@"ProductBuildVersion"];
+    if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:@"/Applications/MobileSafari.app/Info.plist"]) {
+        Product_ = [info objectForKey:@"SafariProductVersion"];
+        Safari_ = [info objectForKey:@"CFBundleVersion"];
+    }
 
     /*AddPreferences(@"/Applications/Preferences.app/Settings-iPhone.plist");
     AddPreferences(@"/Applications/Preferences.app/Settings-iPod.plist");*/