Skip to content
Snippets Groups Projects
Commit 30698c2c authored by George Nachman's avatar George Nachman
Browse files

Implement successors to allow multiple uploads via drag-drop with a single session

parent 2041d0ee
No related branches found
No related tags found
No related merge requests found
Loading
Loading
@@ -4250,6 +4250,7 @@ static long long timeInTenthsOfSeconds(struct timeval t)
 
- (void)uploadFiles:(NSArray *)localFilenames toPath:(SCPPath *)destinationPath
{
SCPFile *previous = nil;
for (NSString *file in localFilenames) {
SCPFile *scpFile = [[[SCPFile alloc] init] autorelease];
scpFile.path = [[[SCPPath alloc] init] autorelease];
Loading
Loading
@@ -4258,7 +4259,11 @@ static long long timeInTenthsOfSeconds(struct timeval t)
NSString *filename = [file lastPathComponent];
scpFile.path.path = [destinationPath.path stringByAppendingPathComponent:filename];
scpFile.localPath = file;
if (previous) {
previous.successor = scpFile;
}
previous = scpFile;
[scpFile upload];
}
}
Loading
Loading
Loading
Loading
@@ -27,12 +27,13 @@ static NSError *SCPFileError(NSString *description) {
@property(atomic, assign) BOOL stopped;
@property(atomic, copy) NSString *error;
@property(atomic, copy) NSString *destination;
@property(nonatomic, assign) dispatch_queue_t queue;
@end
 
@implementation SCPFile {
dispatch_queue_t _queue;
BOOL _okToAdd;
BOOL _downloading;
dispatch_queue_t _queue;
}
 
- (id)init {
Loading
Loading
@@ -46,9 +47,28 @@ static NSError *SCPFileError(NSString *description) {
- (void)dealloc {
[_error release];
[_destination release];
dispatch_release(_queue);
[super dealloc];
}
 
- (void)setQueue:(dispatch_queue_t)queue {
@synchronized(self) {
if (queue != _queue) {
dispatch_release(_queue);
_queue = queue;
if (queue) {
dispatch_retain(queue);
}
}
}
}
- (dispatch_queue_t)queue {
@synchronized(self) {
return _queue;
}
}
- (NSString *)displayName {
return [NSString stringWithFormat:@"scp %@@%@:%@", _path.username, _path.hostname, _path.path];
}
Loading
Loading
@@ -94,6 +114,15 @@ static NSError *SCPFileError(NSString *description) {
return finalDestination;
}
 
// This runs in a thread.
- (void)performTransferWrapper:(BOOL)isDownload {
[self performTransfer:isDownload];
if (self.session && self.session.isConnected) {
[self.session disconnect];
}
self.session = nil;
}
// This runs in a thread.
- (void)performTransfer:(BOOL)isDownload {
NSString *baseName = [[self class] fileNameForPath:self.path.path];
Loading
Loading
@@ -106,18 +135,21 @@ static NSError *SCPFileError(NSString *description) {
return;
}
_okToAdd = NO;
self.session = [[[NMSSHSession alloc] initWithHost:self.path.hostname
andUsername:self.path.username] autorelease];
self.session.delegate = self;
[self.session connect];
if (self.stopped) {
NSLog(@"Stop after connect");
dispatch_sync(dispatch_get_main_queue(), ^() {
[[FileTransferManager sharedInstance] transferrableFileDidStopTransfer:self];
});
return;
if (self.session) {
self.session.delegate = self;
} else {
self.session = [[[NMSSHSession alloc] initWithHost:self.path.hostname
andUsername:self.path.username] autorelease];
self.session.delegate = self;
[self.session connect];
if (self.stopped) {
NSLog(@"Stop after connect");
dispatch_sync(dispatch_get_main_queue(), ^() {
[[FileTransferManager sharedInstance] transferrableFileDidStopTransfer:self];
});
return;
}
}
if (!self.session.isConnected) {
NSError *theError = self.session.lastError;
self.error = [NSString stringWithFormat:@"Connection failed: %@", theError.localizedDescription];
Loading
Loading
@@ -128,60 +160,61 @@ static NSError *SCPFileError(NSString *description) {
return;
}
NSArray *authTypes = [self.session supportedAuthenticationMethods];
if (!authTypes) {
authTypes = @[ @"password" ];
}
for (NSString *authType in authTypes) {
if (self.stopped) {
NSLog(@"Break out of auth loop because stopped");
break;
if (!self.session.isAuthorized) {
NSArray *authTypes = [self.session supportedAuthenticationMethods];
if (!authTypes) {
authTypes = @[ @"password" ];
}
if ([authType isEqualToString:@"password"]) {
__block NSString *password;
dispatch_sync(dispatch_get_main_queue(), ^() {
password = [[FileTransferManager sharedInstance] transferrableFile:self
keyboardInteractivePrompt:@"Password:"];
});
if (self.stopped || !password) {
break;
}
[self.session authenticateByPassword:password];
if (self.session.isAuthorized) {
for (NSString *authType in authTypes) {
if (self.stopped) {
NSLog(@"Break out of auth loop because stopped");
break;
}
} else if ([authType isEqualToString:@"keyboard-interactive"]) {
[self.session authenticateByKeyboardInteractiveUsingBlock:^NSString *(NSString *request) {
__block NSString *response;
if ([authType isEqualToString:@"password"]) {
__block NSString *password;
dispatch_sync(dispatch_get_main_queue(), ^() {
response = [[FileTransferManager sharedInstance] transferrableFile:self
keyboardInteractivePrompt:request];
password = [[FileTransferManager sharedInstance] transferrableFile:self
keyboardInteractivePrompt:@"Password:"];
});
return response;
}];
if (self.stopped || self.session.isAuthorized) {
break;
}
} else if ([authType isEqualToString:@"publickey"] && [self havePrivateKey]) {
if (self.stopped) {
break;
}
[self.session authenticateByPublicKey:[kPublicKeyPath stringByExpandingTildeInPath]
privateKey:[kPrivateKeyPath stringByExpandingTildeInPath]
optionalPasswordBlock:^NSString *() {
__block NSString *password;
dispatch_sync(dispatch_get_main_queue(), ^() {
password = [[FileTransferManager sharedInstance] transferrableFile:self
keyboardInteractivePrompt:@"Passphrase for private key:"];
});
return password;
}];
if (self.session.isAuthorized) {
break;
if (self.stopped || !password) {
break;
}
[self.session authenticateByPassword:password];
if (self.session.isAuthorized) {
break;
}
} else if ([authType isEqualToString:@"keyboard-interactive"]) {
[self.session authenticateByKeyboardInteractiveUsingBlock:^NSString *(NSString *request) {
__block NSString *response;
dispatch_sync(dispatch_get_main_queue(), ^() {
response = [[FileTransferManager sharedInstance] transferrableFile:self
keyboardInteractivePrompt:request];
});
return response;
}];
if (self.stopped || self.session.isAuthorized) {
break;
}
} else if ([authType isEqualToString:@"publickey"] && [self havePrivateKey]) {
if (self.stopped) {
break;
}
[self.session authenticateByPublicKey:[kPublicKeyPath stringByExpandingTildeInPath]
privateKey:[kPrivateKeyPath stringByExpandingTildeInPath]
optionalPasswordBlock:^NSString *() {
__block NSString *password;
dispatch_sync(dispatch_get_main_queue(), ^() {
password = [[FileTransferManager sharedInstance] transferrableFile:self
keyboardInteractivePrompt:@"Passphrase for private key:"];
});
return password;
}];
if (self.session.isAuthorized) {
break;
}
}
}
}
if (self.stopped) {
NSLog(@"Stop after auth");
dispatch_sync(dispatch_get_main_queue(), ^() {
Loading
Loading
@@ -291,6 +324,14 @@ static NSError *SCPFileError(NSString *description) {
[[FileTransferManager sharedInstance] transferrableFile:self
didFinishTransmissionWithError:error];
});
if (!error && self.successor) {
SCPFile *scpSuccessor = (SCPFile *)self.successor;
scpSuccessor.session = self.session;
scpSuccessor.queue = _queue;
self.session = nil;
self.queue = nil;
[scpSuccessor performTransferWrapper:isDownload];
}
} else {
self.status = kTransferrableFileStatusTransferring;
BOOL ok = [self.session.channel uploadFile:[self localPath]
Loading
Loading
@@ -327,6 +368,14 @@ static NSError *SCPFileError(NSString *description) {
[[FileTransferManager sharedInstance] transferrableFile:self
didFinishTransmissionWithError:error];
});
if (!error && self.successor) {
SCPFile *scpSuccessor = (SCPFile *)self.successor;
scpSuccessor.session = self.session;
scpSuccessor.queue = _queue;
self.session = nil;
self.queue = nil;
[scpSuccessor performTransferWrapper:isDownload];
}
}
}
 
Loading
Loading
@@ -351,9 +400,11 @@ static NSError *SCPFileError(NSString *description) {
[[[FileTransferManager sharedInstance] files] addObject:self];
[[FileTransferManager sharedInstance] transferrableFileDidStartTransfer:self];
 
dispatch_async(_queue, ^() {
[self performTransfer:YES];
});
if (!self.hasPredecessor) {
dispatch_async(_queue, ^() {
[self performTransferWrapper:YES];
});
}
}
 
- (void)upload {
Loading
Loading
@@ -363,9 +414,11 @@ static NSError *SCPFileError(NSString *description) {
[[[FileTransferManager sharedInstance] files] addObject:self];
[[FileTransferManager sharedInstance] transferrableFileDidStartTransfer:self];
dispatch_async(_queue, ^() {
[self performTransfer:NO];
});
if (!self.hasPredecessor) {
dispatch_async(_queue, ^() {
[self performTransferWrapper:NO];
});
}
}
 
- (BOOL)isDownloading {
Loading
Loading
Loading
Loading
@@ -26,6 +26,8 @@ typedef enum {
@property(atomic, assign) TransferrableFileStatus status;
@property(atomic, assign) NSUInteger bytesTransferred;
@property(atomic, assign) int fileSize; // -1 if unknown
@property(atomic, retain) TransferrableFile *successor;
@property(atomic, assign) BOOL hasPredecessor;
 
- (NSString *)displayName;
- (NSString *)shortName;
Loading
Loading
Loading
Loading
@@ -11,6 +11,7 @@
@implementation TransferrableFile {
NSTimeInterval _timeOfLastStatusChange;
TransferrableFileStatus _status;
TransferrableFile *_successor;
}
 
- (id)init {
Loading
Loading
@@ -62,6 +63,20 @@
assert(false);
}
 
- (void)setSuccessor:(TransferrableFile *)successor {
@synchronized(self) {
[_successor autorelease];
_successor = [successor retain];
successor.hasPredecessor = YES;
}
}
- (TransferrableFile *)successor {
@synchronized(self) {
return _successor;
}
}
- (void)setStatus:(TransferrableFileStatus)status {
@synchronized(self) {
_status = status;
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment