UPDATE:
since release 2012 R3 there is better support for setting a custom upload command.
The SendCommand method is not a command-line-like interface to Rebex FTP API. All it does is sending the supplied commands to the server as-is, without any further processing. This is fine for simple commands, but won't work for commands that need other actions to be done at the client. In case of STOR command, the client has to connect to the IP/port returned by the server in response to the PASV command. The PutFile method does that, but SendCommand alone does not - that's why the log doesn't contain anything useful except the 425 error response.
To make the code work, you would have to handle the data transfer yourself. This is not recommended, but it can be done:
Ftp ftp = new Ftp();
ftp.CommandSent += FtpCommandSentEventHandler;
ftp.LogWriter = new Rebex.FileLogWriter(@"F:\REBEXLog.txt", Rebex.LogLevel.Verbose);
ftp.Connect("localhost", 990, new TlsParameters { CertificateVerifier = CertificateVerifier.AcceptAll, AllowedSuites = TlsCipherSuite.Secure, Version = TlsVersion.SSL30 | TlsVersion.TLS10, CommonName = "localhost" }, FtpSecurity.Implicit);
ftp.Login("user", "1234");
// after each ftp.ReadResponse, the Group property of the
// resulting FtpResponse object should be checked
ftp.SendCommand("PBSZ 0");
ftp.ReadResponse();
ftp.SendCommand("PROT P");
ftp.ReadResponse();
ftp.SendCommand("TYPE I");
ftp.ReadResponse();
ftp.SendCommand("PASV");
string rawEP = ftp.ReadResponse().Description;
// parse the IP address and port from the PASV response
// (this sample code doesn't check for any unusual or unparsable values)
int epStart = rawEP.LastIndexOf('(') + 1;
int epEnd = rawEP.IndexOf(')', epStart);
rawEP = rawEP.Substring(epStart, epEnd - epStart);
string[] epPart = rawEP.Split(',');
string ip = string.Join(".", epPart, 0, 4);
int port = int.Parse(epPart[4], CultureInfo.InvariantCulture) * 256;
port += int.Parse(epPart[5], CultureInfo.InvariantCulture);
// initialize the transfer at the server side
ftp.SendCommand("STOR " + "d.zip");
// open data connection
TlsSocket dataSocket = new TlsSocket();
dataSocket.Connect(ip, port);
// upgrade the data connection to SSL
dataSocket.Negotiate();
// read and check the STOR command response
FtpResponse response = ftp.ReadResponse();
if (response.Group != 1)
throw new ApplicationException("FTP error " + response.Description);
// send data in 4K blocks (can be enlarged for better throughput)
byte[] buffer = new byte[4096];
using (Stream input = File.OpenRead(@"F:\d.zip"))
{
for (;;)
{
int count = input.Read(buffer, 0, buffer.Length);
if (count == 0)
break;
dataSocket.Send(buffer, 0, count, SocketFlags.None);
}
}
// close the data connection (=end of upload)
dataSocket.Close();
// read and check the server response
response = ftp.ReadResponse();
if (response.Group != 2)
throw new ApplicationException("FTP error " + response.Description);
By the way, please let us know which FTP server requires a PUT
command instead of STOR
- we have never seen anything like that. Are you sure it's really the case? PUT command is used by some command-line FTP clients, but they actually send STOR to the server during the process.