#include <algorithm>
#include <iomanip>
+#include <set>
#include <sstream>
#include <string>
@class CYPackageController;
+@protocol SourceDelegate
+- (void) setFetch:(NSNumber *)fetch;
+@end
+
+@protocol FetchDelegate
+- (bool) isSourceCancelled;
+- (void) startSourceFetch:(NSString *)uri;
+- (void) stopSourceFetch:(NSString *)uri;
+@end
+
@protocol CydiaDelegate
- (void) returnToCydia;
- (void) saveState;
@end
/* }}} */
-/* Status Delegation {{{ */
-class Status :
+/* CancelStatus {{{ */
+class CancelStatus :
public pkgAcquireStatus
{
private:
- _transient NSObject<ProgressDelegate> *delegate_;
bool cancelled_;
public:
- Status() :
- delegate_(nil),
+ CancelStatus() :
cancelled_(false)
{
}
- void setDelegate(NSObject<ProgressDelegate> *delegate) {
- delegate_ = delegate;
- }
-
- NSObject<ProgressDelegate> *getDelegate() const {
- return delegate_;
- }
-
virtual bool MediaChange(std::string media, std::string drive) {
return false;
}
Done(item);
}
+ virtual bool Pulse_(pkgAcquire *Owner) = 0;
+
+ virtual bool Pulse(pkgAcquire *Owner) {
+ if (pkgAcquireStatus::Pulse(Owner) && Pulse_(Owner))
+ return true;
+ else {
+ cancelled_ = true;
+ return false;
+ }
+ }
+
+ _finline bool WasCancelled() const {
+ return cancelled_;
+ }
+};
+/* }}} */
+/* DelegateStatus {{{ */
+class CydiaStatus :
+ public CancelStatus
+{
+ private:
+ _transient NSObject<ProgressDelegate> *delegate_;
+
+ public:
+ CydiaStatus() :
+ delegate_(nil)
+ {
+ }
+
+ void setDelegate(NSObject<ProgressDelegate> *delegate) {
+ delegate_ = delegate;
+ }
+
virtual void Fetch(pkgAcquire::ItemDesc &item) {
NSString *name([NSString stringWithUTF8String:item.ShortDesc.c_str()]);
CydiaProgressEvent *event([CydiaProgressEvent eventWithMessage:[NSString stringWithFormat:UCLocalize("DOWNLOADING_"), name] ofType:kCydiaProgressEventTypeStatus forItem:item]);
[delegate_ performSelectorOnMainThread:@selector(addProgressEvent:) withObject:event waitUntilDone:YES];
}
- virtual bool Pulse(pkgAcquire *Owner) {
- bool value = pkgAcquireStatus::Pulse(Owner);
-
+ virtual bool Pulse_(pkgAcquire *Owner) {
double percent(
double(CurrentBytes + CurrentItems) /
double(TotalBytes + TotalItems)
[NSNumber numberWithDouble:CurrentCPS], @"Speed",
nil] waitUntilDone:YES];
- if (value && ![delegate_ isProgressCancelled])
- return true;
- else {
- cancelled_ = true;
- return false;
- }
- }
-
- _finline bool WasCancelled() const {
- return cancelled_;
+ return ![delegate_ isProgressCancelled];
}
virtual void Start() {
_transient NSObject<DatabaseDelegate> *delegate_;
_transient NSObject<ProgressDelegate> *progress_;
- Status status_;
+ CydiaStatus status_;
int cydiafd_;
int statusfd_;
- (bool) upgrade;
- (void) update;
-- (void) updateWithStatus:(Status &)status;
+- (void) updateWithStatus:(CancelStatus &)status;
- (void) setDelegate:(NSObject<DatabaseDelegate> *)delegate;
- (NSObject<ProgressDelegate> *) progressDelegate;
- (Source *) getSource:(pkgCache::PkgFileIterator)file;
+- (void) setFetch:(bool)fetch forURI:(const char *)uri;
+- (void) resetFetch;
- (NSString *) mappedSectionForPointer:(const char *)pointer;
@end
/* }}} */
+/* SourceStatus {{{ */
+class SourceStatus :
+ public CancelStatus
+{
+ private:
+ _transient NSObject<FetchDelegate> *delegate_;
+ _transient Database *database_;
+
+ public:
+ SourceStatus(NSObject<FetchDelegate> *delegate, Database *database) :
+ delegate_(delegate),
+ database_(database)
+ {
+ }
+
+ void Set(bool fetch, pkgAcquire::ItemDesc &desc) {
+ desc.Owner->ID = 0;
+ [database_ setFetch:fetch forURI:desc.Owner->DescURI().c_str()];
+ }
+
+ virtual void Fetch(pkgAcquire::ItemDesc &desc) {
+ Set(true, desc);
+ }
+
+ virtual void Done(pkgAcquire::ItemDesc &desc) {
+ Set(false, desc);
+ }
+
+ virtual void Fail(pkgAcquire::ItemDesc &desc) {
+ Set(false, desc);
+ }
+
+ virtual bool Pulse_(pkgAcquire *Owner) {
+ for (pkgAcquire::ItemCIterator item = Owner->ItemsBegin(); item != Owner->ItemsEnd(); ++item)
+ if ((*item)->ID != 0);
+ else if ((*item)->Status == pkgAcquire::Item::StatIdle) {
+ (*item)->ID = 1;
+ [database_ setFetch:true forURI:(*item)->DescURI().c_str()];
+ } else (*item)->ID = 0;
+ return ![delegate_ isSourceCancelled];
+ }
+
+ virtual void Stop() {
+ pkgAcquireStatus::Stop();
+ [database_ resetFetch];
+ }
+};
+/* }}} */
/* ProgressEvent Implementation {{{ */
@implementation CydiaProgressEvent
_H<NSMutableDictionary> record_;
BOOL trusted_;
+
+ std::set<std::string> fetches_;
+ std::set<std::string> files_;
+ _transient NSObject<SourceDelegate> *delegate_;
}
- (Source *) initWithMetaIndex:(metaIndex *)index forDatabase:(Database *)database inPool:(apr_pool_t *)pool;
- (NSString *) defaultIcon;
- (NSURL *) iconURL;
+- (void) setFetch:(bool)fetch forURI:(const char *)uri;
+- (void) resetFetch;
+
@end
@implementation Source
debReleaseIndex *dindex(dynamic_cast<debReleaseIndex *>(index));
if (dindex != NULL) {
- base_.set(pool, dindex->MetaIndexURI(""));
+ std::string file(dindex->MetaIndexURI(""));
+ files_.insert(file + "Release.gpg");
+ files_.insert(file + "Release");
+ base_.set(pool, file);
+
+ std::vector<IndexTarget *> *targets(dindex->ComputeIndexTargets());
+ for (std::vector<IndexTarget *>::const_iterator target(targets->begin()); target != targets->end(); ++target) {
+ std::string file((*target)->URI);
+ files_.insert(file);
+ files_.insert(file + ".gz");
+ files_.insert(file + ".bz2");
+ files_.insert(file + "Index");
+ } delete targets;
FileFd fd;
if (!fd.Open(dindex->MetaIndexFile("Release"), FileFd::ReadOnly))
return defaultIcon_;
}
+- (void) setDelegate:(NSObject<SourceDelegate> *)delegate {
+ delegate_ = delegate;
+}
+
+- (bool) fetch {
+ return !fetches_.empty();
+}
+
+- (void) setFetch:(bool)fetch forURI:(const char *)uri {
+ if (!fetch) {
+ if (fetches_.erase(uri) == 0)
+ return;
+ } else if (files_.find(uri) == files_.end())
+ return;
+ else if (!fetches_.insert(uri).second)
+ return;
+
+ [delegate_ performSelectorOnMainThread:@selector(setFetch:) withObject:[NSNumber numberWithBool:[self fetch]] waitUntilDone:NO];
+}
+
+- (void) resetFetch {
+ fetches_.clear();
+ [delegate_ performSelectorOnMainThread:@selector(setFetch:) withObject:[NSNumber numberWithBool:NO] waitUntilDone:NO];
+}
+
@end
/* }}} */
/* CydiaOperation Class {{{ */
[self updateWithStatus:status_];
}
-- (void) updateWithStatus:(Status &)status {
+- (void) updateWithStatus:(CancelStatus &)status {
NSString *title(UCLocalize("REFRESHING_DATA"));
pkgSourceList list;
return i == sourceMap_.end() ? nil : i->second;
}
+- (void) setFetch:(bool)fetch forURI:(const char *)uri {
+ for (Source *source in (id) sourceList_)
+ [source setFetch:fetch forURI:uri];
+}
+
+- (void) resetFetch {
+ for (Source *source in (id) sourceList_)
+ [source resetFetch];
+}
+
- (NSString *) mappedSectionForPointer:(const char *)section {
_H<NSString> *mapped;
/* Cydia Tab Bar Controller {{{ */
@interface CydiaTabBarController : CyteTabBarController <
UITabBarControllerDelegate,
- ProgressDelegate
+ FetchDelegate
> {
_transient Database *database_;
- (void) performUpdate {
NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
- Status status;
- status.setDelegate(self);
+ SourceStatus status(self, database_);
[database_ updateWithStatus:status];
[self
return updating_;
}
-- (void) addProgressEvent:(CydiaProgressEvent *)event {
-}
-
-- (bool) isProgressCancelled {
+- (bool) isSourceCancelled {
return !updating_;
}
-- (void) setProgressCancellable:(NSNumber *)cancellable {
-}
-
-- (void) setProgressPercent:(NSNumber *)percent {
+- (void) startSourceFetch:(NSString *)uri {
}
-- (void) setProgressStatus:(NSDictionary *)status {
- if (status != nil)
- [self setProgressPercent:[status objectForKey:@"Percent"]];
+- (void) stopSourceFetch:(NSString *)uri {
}
- (void) setUpdateDelegate:(id)delegate {
/* Source Cell {{{ */
@interface SourceCell : CyteTableViewCell <
- CyteTableViewCellDelegate
+ CyteTableViewCellDelegate,
+ SourceDelegate
> {
+ _H<Source, 1> source_;
_H<NSURL> url_;
_H<UIImage> icon_;
_H<NSString> origin_;
_H<NSString> label_;
+ _H<UIActivityIndicatorView> indicator_;
}
- (void) setSource:(Source *)source;
+- (void) setFetch:(NSNumber *)fetch;
@end
}
- (void) setSource:(Source *)source {
+ source_ = source;
+ [source_ setDelegate:self];
+
+ [self setFetch:[NSNumber numberWithBool:[source_ fetch]]];
+
icon_ = [UIImage applicationImageNamed:@"unknown.png"];
origin_ = [source name];
}
- (void) setAllSource {
+ source_ = nil;
+ [indicator_ stopAnimating];
+
icon_ = [UIImage applicationImageNamed:@"folder.png"];
origin_ = UCLocalize("ALL_SOURCES");
label_ = UCLocalize("ALL_SOURCES_EX");
[content_ setDelegate:self];
[content_ setOpaque:YES];
+ indicator_ = [[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGraySmall] autorelease];
+ [indicator_ setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin];// | UIViewAutoresizingFlexibleBottomMargin];
+ [content addSubview:indicator_];
+
[[content_ layer] setContentsGravity:kCAGravityTopLeft];
} return self;
}
+- (void) layoutSubviews {
+ [super layoutSubviews];
+
+ UIView *content([self contentView]);
+ CGRect bounds([content bounds]);
+
+ CGRect frame([indicator_ frame]);
+ frame.origin.x = bounds.size.width - frame.size.width;
+ frame.origin.y = (bounds.size.height - frame.size.height) / 2;
+
+ if (kCFCoreFoundationVersionNumber < 800)
+ frame.origin.x -= 8;
+ [indicator_ setFrame:frame];
+}
+
- (NSString *) accessibilityLabel {
return origin_;
}
[label_ drawAtPoint:CGPointMake(52, 29) forWidth:(width - 61) withFont:Font12_ lineBreakMode:UILineBreakModeTailTruncation];
}
+- (void) setFetch:(NSNumber *)fetch {
+ if ([fetch boolValue])
+ [indicator_ startAnimating];
+ else
+ [indicator_ stopAnimating];
+}
+
@end
/* }}} */
/* Sources Controller {{{ */
_H<UIProgressHUD> hud_;
_H<NSError> error_;
- //NSURLConnection *installer_;
NSURLConnection *trivial_bz2_;
NSURLConnection *trivial_gz_;
- //NSURLConnection *automatic_;
BOOL cydia_;
}
}
- (void) dealloc {
- //[self _releaseConnection:installer_];
[self _releaseConnection:trivial_gz_];
[self _releaseConnection:trivial_bz2_];
- //[self _releaseConnection:automatic_];
[super dealloc];
}
}
}
+- (void) tableView:(UITableView *)tableView didEndEditingRowAtIndexPath:(NSIndexPath *)indexPath {
+ [self updateButtonsForEditingStatusAnimated:YES];
+}
+
- (void) complete {
[delegate_ addTrivialSource:href_];
href_ = nil;
case 1: {
NSString *href = [[alert textField] text];
- //installer_ = [[self _requestHRef:href method:@"GET"] retain];
+ static Pcre href_r("^http(s?)://[^# ]*$");
+ if (!href_r(href)) {
+ UIAlertView *alert = [[[UIAlertView alloc]
+ initWithTitle:Error_
+ message:UCLocalize("INVALID_URL")
+ delegate:self
+ cancelButtonTitle:UCLocalize("OK")
+ otherButtonTitles:nil
+ ] autorelease];
+
+ [alert setContext:@"badurl"];
+ [alert show];
+
+ break;
+ }
if (![href hasSuffix:@"/"])
href_ = [href stringByAppendingString:@"/"];
trivial_bz2_ = [[self _requestHRef:[href_ stringByAppendingString:@"Packages.bz2"] method:@"HEAD"] retain];
trivial_gz_ = [[self _requestHRef:[href_ stringByAppendingString:@"Packages.gz"] method:@"HEAD"] retain];
- //trivial_bz2_ = [[self _requestHRef:[href stringByAppendingString:@"dists/Release"] method:@"HEAD"] retain];
cydia_ = false;
Changed_ = true;
}
+
+ _H<NSMutableArray> broken([NSMutableArray array]);
+ for (NSString *key in (id) Sources_)
+ if ([key rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@"# "]].location != NSNotFound)
+ [broken addObject:key];
+ if ([broken count] != 0) {
+ for (NSString *key in (id) broken)
+ [Sources_ removeObjectForKey:key];
+ Changed_ = true;
+ } broken = nil;
/* }}} */
CydiaWriteSources();