Спасибо Мартину Прикрилу и Штеффену Ульриху за вашу помощь. Я добавлю здесь рабочий код с комментариями. Может быть, это будет кому-то полезно. Возможно, необходимо добавить команды сна, потому что код работает быстрее, чем сервер отвечает.
# Open control channel
sHandle := SocketOpen('ftp.stackoverflow.net', 21);
SocketReadString(sHandle, answer);
SocketWriteString(sHandle, 'USER user1673665' & CHR(13) & CHR(10));
SocketReadString(sHandle, answer);
SocketWriteString(sHandle, 'PASS !@#$%^&*' & CHR(13) & CHR(10));
SocketReadString(sHandle, answer);
SocketWriteString(sHandle, 'CWD update' & CHR(13) & CHR(10));
SocketReadString(sHandle, answer);
# Enter passive mode and receive data channel adress and port
SocketWriteString(sHandle, 'PASV' & CHR(13) & CHR(10));
SocketReadString(sHandle, answer);
# Create adress for data channel
IF answer <> NOVALUE THEN
# Split answer on character , and ( and ) and whitespace
retPASV[] := StrSplit(answer, ',() ');
ENDIF;
CASE retPASV[1]
# Passive mode is 227
IS = 227 DO
connect := retPASV[6] & '.' & retPASV[7] & '.' & retPASV[8] & '.' & retPASV[9];
IS DO
ENDCASE;
# Create port for data channel
# Port is secondlast number * 256 + last number from PASV reply
port := String2Num(retPASV[10]) * 256 + String2Num(retPASV[11]);
# Open data channel on sHandle2
sHandle2 := SocketOpen(connect, port);
SocketReadString(sHandle2, answer2);
# Download file on control channel
SocketWriteString(sHandle, 'RETR update.txt' & CHR(13) & CHR(10));
SocketReadString(sHandle, Antwort);
# Read file on data channel - result of textfile in string answer2
SocketReadString(sHandle2, answer2);
SocketClose(sHandle);