retrieveFile method
Implementation
Future<void> retrieveFile(String filename) async {
if (filename.isEmpty) {
sendResponse('501 Syntax error in parameters');
return;
}
// Check file existence before opening data connection to avoid
// sending 550 after 150 (RFC 959: validate before preliminary reply)
if (!fileOperations.exists(filename)) {
sendResponse('550 File not found');
return;
}
String fullPath = fileOperations.resolvePath(filename);
File file = File(fullPath);
if (!await file.exists()) {
sendResponse('550 File not found');
return;
}
if (!checkDataProtection()) return;
if (!await openDataConnection()) {
return;
}
try {
transferInProgress = true;
if (await file.exists()) {
Stream<List<int>> fileStream = file.openRead();
StreamSubscription<List<int>>? subscription;
subscription = fileStream.listen(
(data) {
if (transferInProgress && dataSocket != null) {
try {
dataSocket!.add(data);
} catch (e) {
logger.generalLog('Error writing to data socket: $e');
transferInProgress = false;
subscription?.cancel();
_closeDataSocket();
}
}
},
onDone: () async {
if (transferInProgress) {
transferInProgress = false;
await _closeDataSocket();
sendResponse('226 Transfer complete');
}
},
onError: (error) async {
logger.generalLog('Error reading from file: $error');
if (transferInProgress) {
sendResponse('426 Connection closed; transfer aborted');
transferInProgress = false;
await _closeDataSocket();
}
},
cancelOnError: true,
);
}
} catch (e) {
logger.generalLog('Exception in retrieveFile: $e');
sendResponse('550 File transfer failed');
transferInProgress = false;
await _closeDataSocket();
}
}