FTPException = class(Exception); {FTP Exceptions}
TFailureEvent = procedure(var Handled: Boolean; Trans_Type: TCmdType) of object;
TSuccessEvent = procedure(Trans_Type: TCmdType) of object;
TUnsupportedEvent = procedure(Trans_Type: TCmdType) of object;
TNMListItem = procedure(Listing: string) of object;
{*******************************************************************************************
FTP Class Definition
********************************************************************************************}
TNMFTP = class(TPowersock)
private
ProcessLock: TRTLCriticalSection;
FUserID, FPassword: string; {Password and User ID strings}
FPassive: boolean;
DataSocket: TPowersock; {Socket for Data Transfers}
FTransactionStart, FTransactionStop: TNotifyEvent; {Handler after each packet received for progress reports etc}
FOnSuccess: TSuccessEvent;
FOnFailure: TFailureEvent;
FOnAuthenticationNeeded: THandlerEvent;
FOnAuthenticationFailed: THandlerEvent;
FOnListItem: TNMListItem;
FOnConnect: TNotifyEvent;
FOnUnSupportedFunction: TUnsupportedEvent;
FVendor: integer;
FFTPDirectoryList: TFTPDirectoryList;
FParseList: boolean;
FFirewallType: TFirewallType;
// Added these 2 property containers to support user ID and password
// with firewalls
FFWUserID, FFWPassword: string;
// Added FFWAuth property container for optional firewall authentication
{*******************************************************************************************
Register the TNMFTP Component in the internet pallette
********************************************************************************************}
procedure Register;
begin
RegisterComponents(Cons_Palette_Inet, [TNMFTP]);
end; {_ procedure register; _}
procedure TFTPDirectoryList.ParseLine(Line: string);
var
i, j: integer;
procedure skipblanks;
begin
repeat
inc(j)
until (line[j] <> ' ') or (j > length(line));
end; {_ repeat _}
begin
for i := 1 to 25 do tokens := ''; //clear tokens;
i := 1;
j := 1;
tokens[1] := '';
repeat
if line[j] <> ' ' then
begin
tokens := tokens + line[j];
inc(j)
end {_ if line <> ' ' then _}
else {_ NOT if line <> ' ' then _}
begin
inc(i);
tokens := '';
skipblanks;
end; {_ NOT if line <> ' ' then _}
procedure TFTPUnixList.ParseLine(Line: string);
begin
inherited ParseLine(Line);
if NoTokens > 7 then
begin
FName.add(tokens[NoTokens]);
FSize.add(tokens[NoTokens - 4]);
FModifDate.add(tokens[NoTokens - 3] + ' ' + tokens[NoTokens - 2] + ' ' + tokens[NoTokens - 1]);
FAttribute.add(tokens[1]);
end; {_ if NoTokens > 7 then _}
end; {_ procedure TFTPUnixList.ParseLine(Line: string); _}
procedure TFTPNETWAREList.ParseLine(Line: string);
begin
inherited ParseLine(Line);
if NoTokens > 7 then
begin
FName.add(tokens[NoTokens - 1]);
FSize.add(tokens[NoTokens - 5]);
FModifDate.add(tokens[NoTokens - 4] + ' ' + tokens[NoTokens - 3] + ' ' + tokens[NoTokens - 2]);
FAttribute.add(tokens[1]);
end; {_ if NoTokens > 7 then _}
end; {_ procedure TFTPNETWAREList.ParseLine(Line: string); _}
procedure TFTPDOSList.ParseLine(Line: string);
begin
inherited ParseLine(Line);
if NoTokens > 7 then
begin
FName.add(tokens[NoTokens - 1]);
FSize.add(tokens[NoTokens - 5]);
FModifDate.add(tokens[NoTokens - 4] + ' ' + tokens[NoTokens - 3] + ' ' + tokens[NoTokens - 2]);
FAttribute.add(tokens[1]);
end; {_ if NoTokens > 7 then _}
end; {_ procedure TFTPDOSList.ParseLine(Line: string); _}
procedure TFTPVMSList.ParseLine(Line: string);
begin
inherited ParseLine(Line);
if NoTokens > 7 then
begin
FName.add(tokens[NoTokens - 1]);
FSize.add(tokens[NoTokens - 5]);
FModifDate.add(tokens[NoTokens - 4] + ' ' + tokens[NoTokens - 3] + ' ' + tokens[NoTokens - 2]);
FAttribute.add(tokens[1]);
end; {_ if NoTokens > 7 then _}
end; {_ procedure TFTPVMSList.ParseLine(Line: string); _}
procedure TFTPMVSList.ParseLine(Line: string);
begin
inherited ParseLine(Line);
if NoTokens > 7 then
begin
FName.add(tokens[NoTokens - 1]);
FSize.add(tokens[NoTokens - 5]);
FModifDate.add(tokens[NoTokens - 4] + ' ' + tokens[NoTokens - 3] + ' ' + tokens[NoTokens - 2]);
FAttribute.add(tokens[1]);
end; {_ if NoTokens > 7 then _}
end; {_ procedure TFTPMVSList.ParseLine(Line: string); _}
procedure TFTPVMList.ParseLine(Line: string);
begin
inherited ParseLine(Line);
if NoTokens > 7 then
begin
FName.add(tokens[NoTokens - 1]);
FSize.add(tokens[NoTokens - 5]);
FModifDate.add(tokens[NoTokens - 4] + ' ' + tokens[NoTokens - 3] + ' ' + tokens[NoTokens - 2]);
FAttribute.add(tokens[1]);
end; {_ if NoTokens > 7 then _}
end; {_ procedure TFTPVMList.ParseLine(Line: string); _}
procedure TFTPMACOSList.ParseLine(Line: string);
begin
inherited ParseLine(Line);
if NoTokens > 7 then
begin
FName.add(tokens[NoTokens - 1]);
FSize.add(tokens[NoTokens - 5]);
FModifDate.add(tokens[NoTokens - 4] + ' ' + tokens[NoTokens - 3] + ' ' + tokens[NoTokens - 2]);
FAttribute.add(tokens[1]);
end; {_ if NoTokens > 7 then _}
end; {_ procedure TFTPMACOSList.ParseLine(Line: string); _}
procedure TFTPAS400List.ParseLine(Line: string);
begin
inherited ParseLine(Line);
if NoTokens > 3 then
begin
if tokens[NoTokens][1] = '*' then
FName.add(tokens[NoTokens])
else FName.add(tokens[NoTokens - 1]);
FAttribute.add(tokens[1]);
end; {_ if NoTokens > 7 then _}
end; {_ procedure TFTPAS400List.ParseLine(Line: string); _}
procedure TFTPOTHERList.ParseLine(Line: string);
begin
inherited ParseLine(Line);
if NoTokens > 7 then
begin
FName.add(tokens[NoTokens]);
FSize.add(tokens[NoTokens - 4]);
FModifDate.add(tokens[NoTokens - 3] + ' ' + tokens[NoTokens - 2] + ' ' + tokens[NoTokens - 1]);
FAttribute.add(tokens[1]);
end; {_ if NoTokens > 7 then _}
end; {_ procedure TFTPOTHERList.ParseLine(Line: string); _}
{*******************************************************************************************
Initialize the TNMFTP Component
********************************************************************************************}
destructor TNMFTP.Destroy;
begin
Cancel;
DeleteCriticalSection(ProcessLock);
// if Connected then Disconnect;
if FFTPDirectoryList <> nil then
FFTPDirectoryList.free;
inherited Destroy;
end; {_ destructor TNMFTP.Destroy; _}
{*******************************************************************************************
Disconnect from server
********************************************************************************************}
procedure TNMFTP.Disconnect;
var
Replymess: string;
begin
BeenCanceled := False; {Reset Cancelled flag}
if Connected then
{If Connected}
begin
StatusMessage(Status_Informational, Cont_Quit); {Inform Status}
try
FFTPDirectoryList.free;
FFTPDirectoryList := nil;
FVendor := NMOS_AUTO;
if DataAvailable then read(0);
Replymess := Transaction(Cont_Quit); {Do a Quit transaction}
if ((ReplyNumber > 300) and (ReplyNumber < 600))
then raise FTPException.Create(Replymess); {If Error raise exception}
CloseImmediate;
finally
inherited Disconnect; {Finally Disconnect}
end {_ try _}
end; {_ if Connected then _}
end; {_ procedure TNMFTP.Disconnect; _}
{*******************************************************************************************
Initialize a FTP connection
********************************************************************************************}
procedure TNMFTP.Connect;
var
Replymess: string;
Handled: boolean;
begin
BeenCanceled := False; {Reset Cancelled flag}
if not Connected then
{If not already connected}
begin
ClearInput;
inherited Connect; {Do the inherited connect}
try
Replymess := ' ';
ReadExtraLines(Replymess);
if ReplyNumber > 400 then
begin
if assigned(OnConnectionFailed) then OnConnectionFailed(self);
raise FTPException.Create(Replymess); {If Error show exception}
end;
// Below this line added by Edward T. Smith 11/18/1998
// FFWUserID is the firewall user ID
if FFWAuth then
begin
Replymess := Transaction(Cont_User + FFWUserID); {Send User Name and check result}
if (ReplyNumber > 400) and (ReplyNumber < 600) then
begin
if assigned(OnConnectionFailed) then OnConnectionFailed(self);
raise FTPException.Create(Replymess); {If Error show exception}
end;
if ReplyNumber = 331 then
{If Password Needed}
begin
StatusMessage(Status_Informational, Cont_Pass); {Show outgoing Message} {Show Outgoing Message}
Replymess := Transaction(Cont_Pass + FFWPassword); {Send Password and check result}
// FFWPassword is the firewall password
if (ReplyNumber > 400) and (ReplyNumber < 600) then
begin
if assigned(OnConnectionFailed) then OnConnectionFailed(self);
raise FTPException.Create(Replymess); {If Error show exception}
end;
end; {_ if ReplyNumber = 331 then _}
end; // FIrewall Authentication
// Above this line added by Edward T. Smith 11/18/1998
if (FUserID = '') or (Password = '') then
if assigned(FOnAuthenticationNeeded) then FOnAuthenticationNeeded(Handled);
if Proxy <> '' then
begin
case FFirewallType of
ftUser: Replymess := Transaction('USER ' + USERID + '@' + Host);
ftOpen: Replymess := Transaction('OPEN ' + Host);
ftSite: Replymess := Transaction('SITE ' + Host);
end;
end;
if (Proxy = '') or (FFirewallType <> ftUser) then
begin
StatusMessage(Status_Informational, Cont_User + UserID); {Show Outgoing message}
Replymess := Transaction(Cont_User + UserID); {Send User Name and check result}
if (ReplyNumber > 400) and (ReplyNumber < 600) then
begin
if assigned(OnConnectionFailed) then OnConnectionFailed(self);
raise FTPException.Create(Replymess); {If Error show exception}
end;
end;
if ReplyNumber = 331 then
{If Password Needed}
begin
StatusMessage(Status_Informational, Cont_Pass); {Show outgoing Message} {Show Outgoing Message}
Replymess := Transaction(Cont_Pass + Password); {Send Password and check result}
if (ReplyNumber > 400) and (ReplyNumber < 600) then
begin
if assigned(OnConnectionFailed) then OnConnectionFailed(self);
raise FTPException.Create(Replymess); {If Error show exception}
end;
end; {_ if ReplyNumber = 331 then _}
if assigned(FOnConnect) then FOnConnect(self);
except {If fault}
if Connected then Disconnect; {Disconnect}
StatusMessage(Status_Informational, sFTP_Msg_Disconnect); {Show Status}
raise; {Show disconnected status}
end; {_ try _}
end; {_ if not Connected then _}
end; {_ procedure TNMFTP.Connect; _}
{*******************************************************************************************
Do a generic FTP Command
********************************************************************************************}
procedure TNMFTP.DoCommand(CommandStr: string);
var Replymess: string;
Handled: Boolean;
ThisCmd: TCmdType;
begin
if NthWord(CommandStr, ' ', 1) + ' ' = Cont_Cwd then ThisCmd := cmdChangeDir
else if NthWord(CommandStr, ' ', 1) + ' ' = Cont_Dele then ThisCmd := cmdDelete
else if NthWord(CommandStr, ' ', 1) + ' ' = Cont_Mkd then ThisCmd := cmdMakeDir
else if NthWord(CommandStr, ' ', 1) + ' ' = Cont_Rmd then ThisCmd := cmdRemoveDir
else if CommandStr = Cont_Pwd then ThisCmd := cmdCurrentDir
else {_ NOT if CommandStr = Cont_Pwd then ThisCmd := cmdCurrentDir _} ThisCmd := cmdDoCommand;
BeenCanceled := False; {Reset Cancelled flag}
CertifyConnect;
if Connected then
{If connected}
begin
StatusMessage(Status_Informational, CommandStr); {Show Outgoing Message}
if DataAvailable then read(0);
Replymess := Transaction(CommandStr); {Send command and chectk result}
if (ReplyNumber > 399) and (ReplyNumber < 600) then
begin
if assigned(FOnUnSupportedFunction) and (ReplyNumber >= 500) and (ReplyNumber <= 502) then FOnUnSupportedFunction(ThisCmd);
if not assigned(FOnFailure) then raise FTPException.Create(Replymess)
{Raise exception on errors}
else {_ NOT if not assigned(FOnFailure) then raise FTPException.Create(Replymess) _}
begin
Handled := False;
FOnFailure(Handled, ThisCmd);
if not Handled then raise FTPException.Create(Replymess);
{Raise exception on errors}
end {_ NOT if not assigned(FOnFailure) then raise FTPException.Create(Replymess) _}
end {_ if (ReplyNumber > 399) and (ReplyNumber < 600) then _}
else if assigned(FOnSuccess) then FOnSuccess(ThisCmd);
end; {_ if Connected then _}
end; {_ procedure TNMFTP.DoCommand(CommandStr: string); _}
{*******************************************************************************************
Change the Dirctory at remote host
********************************************************************************************}
{*******************************************************************************************
Rename File in Remote Server
********************************************************************************************}
procedure TNMFTP.Rename(Filename, FileName2: string);
var
Replymess: string;
Handled: Boolean;
begin
BeenCanceled := False; {Reset Cancelled flag}
CertifyConnect;
if Connected then
{If connected}
begin
if DataAvailable then read(0);
StatusMessage(Status_Informational, Cont_Rnfr + Filename); {Show Outgoing Message}
Replymess := Transaction(Cont_Rnfr + Filename); {Send Rename from and check result}
if (ReplyNumber > 351) and (ReplyNumber < 600) then
if not assigned(FOnFailure) then raise FTPException.Create(Replymess)
{Raise exception on errors}
else {_ NOT if not assigned(FOnFailure) then raise FTPException.Create(Replymess) _}
begin
Handled := False;
FOnFailure(Handled, cmdRename);
if not Handled then raise FTPException.Create(Replymess);
{Raise exception on errors}
end; {_ NOT if not assigned(FOnFailure) then raise FTPException.Create(Replymess) _}
StatusMessage(Status_Informational, Cont_Rnto + FileName2); {Show Outgoing Message}
Replymess := Transaction(Cont_Rnto + FileName2); {Send Rename to and check result}
if (ReplyNumber > 300) and (ReplyNumber < 600) then
begin
if assigned(FOnUnSupportedFunction) and (ReplyNumber >= 500) and (ReplyNumber <= 502) then FOnUnSupportedFunction(cmdRename);
if not assigned(FOnFailure) then
raise FTPException.Create(Replymess)
{Raise exception on errors}
else {_ NOT if not assigned(FOnFailure) then _}
begin
Handled := False;
FOnFailure(Handled, cmdRename);
if not Handled then
raise FTPException.Create(Replymess);
{Raise exception on errors}
end {_ NOT if not assigned(FOnFailure) then _}
end {_ if (ReplyNumber > 300) and (ReplyNumber < 600) then _}
else if assigned(FOnSuccess) then FOnSuccess(cmdRename);
end; {_ if Connected then _} {Resume Asynchronous Processing}
end; {_ procedure TNMFTP.Rename(Filename, FileName2: string); _}
{*******************************************************************************************
Delete file in remote server
********************************************************************************************}
procedure TNMFTP.Delete(Filename: string);
begin
DoCommand(Cont_Dele + Filename); {Send Delete command and check result}
end; {_ procedure TNMFTP.Delete(Filename: string); _}
{*******************************************************************************************
Delete file in remote server
********************************************************************************************}
begin
DoCommand(Cont_Mkd + DirectoryName); {Send Delete command and check result}
end; {_ procedure TNMFTP.MakeDirectory(DirectoryName: string); _}
{*******************************************************************************************
Delete file in remote server
********************************************************************************************}
procedure TNMFTP.RemoveDir(DirectoryName: string);
begin
DoCommand(Cont_Rmd + DirectoryName); {Send Delete command and check result}
end; {_ procedure TNMFTP.RemoveDir(DirectoryName: string); _}
{*******************************************************************************************
Upload file to Remote Server with unique name
********************************************************************************************}
procedure TNMFTP.UploadUnique(LocalFile: string);
var
Replymess: string;
strm: TFileStream;
Done, Handled: Boolean;
Tsck: TSocket;
label CleanUp;
begin
Done := False;
BeenCanceled := False; {Reset Cancelled flag}
CertifyConnect;
if Connected then
{If connected}
begin
DataSocket := TPowersock.Create(self); {Create a Data socket}
DataSocket.TimeOut := TimeOut;
try
if DataAvailable then read(0);
DataSocket.Timeout := Timeout;
DataSocket.Port := 0; {Set Port to Zero}
DataSocket.Listen(True); {Listen in the datasocket}
strm := TFileStream.Create(LocalFile, fmOpenRead);
try
FBytesTotal := strm.Size;
finally
strm.Destroy;
end; {_ try _}
StatusMessage(Status_Informational, Cont_Port + GetLocalAddress + DataSocket.GetPortString); {Show Outgoing Message}
Replymess := Transaction(Cont_Port + GetLocalAddress + DataSocket.GetPortString); {Send Port for data socket}
if (ReplyNumber > 300) and (ReplyNumber < 600) then
if not assigned(FOnFailure) then raise FTPException.Create(Replymess)
{Raise exception on errors}
else {_ NOT if not assigned(FOnFailure) then raise FTPException.Create(Replymess) _}
begin
Handled := False;
FOnFailure(Handled, cmdUpload);
if not Handled then raise FTPException.Create(Replymess)
else goto Cleanup;
{Raise exception on errors}
end; {_ NOT if not assigned(FOnFailure) then raise FTPException.Create(Replymess) _}
if assigned(FPacketSent) then
DataSocket.OnPacketSent := FPacketSent; {Set function to handle data socket status}
StatusMessage(Status_Informational, Cont_Stou); {Show Outgoing Message}
Replymess := Transaction(Cont_Stou); {Give store unique cmmand}
if (ReplyNumber > 300) and (ReplyNumber < 600) then
begin
if assigned(FOnUnSupportedFunction) and (ReplyNumber >= 500) and (ReplyNumber <= 502) then FOnUnSupportedFunction(cmdUpload);
if not assigned(FOnFailure) then
raise FTPException.Create(Replymess)
{Raise exception on errors}
else {_ NOT if not assigned(FOnFailure) then _}
begin
Handled := False;
FOnFailure(Handled, cmdUpload);
if not Handled then
raise FTPException.Create(Replymess)
else goto Cleanup;
{Raise exception on errors}
end; {_ NOT if not assigned(FOnFailure) then _}
end; {_ if (ReplyNumber > 300) and (ReplyNumber < 600) then _}
Tsck := DataSocket.handle;
DataSocket.ThisSocket := DataSocket.Accept; {Accept the datasocket}
WinSock.CloseSocket(Tsck);
if assigned(FTransactionStart) then FTransactionStart(self);
if not (BeenCanceled or BeenTimedOut) then DataSocket.SendFile(LocalFile);
{If no Local filename specified save file same as remote}
if assigned(FTransactionStop) then FTransactionStop(self);
DataSocket.RequestCloseSocket;
if not (BeenCanceled or BeenTimedOut) then
if DataAvailable then readln
else {_ NOT if DataAvailable > 0 then read (0); _} Replymess := sFTP_Cont_Msg_UpldS;
StatusMessage(Status_Informational, Replymess);
if not (BeenCanceled or BeenTimedOut) then ReadExtraLines(Replymess); {Read Extra Lines}
Done := True;
Cleanup:
finally
DataSocket.Destroy; {Destroy datasocket}
DataSocket := nil;
if Done then if assigned(FOnSuccess) then FOnSuccess(cmdUpload);
end; {_ try _}
end; {_ if Connected then _}
end; {_ procedure TNMFTP.UploadUnique(LocalFile: string); _}
{*******************************************************************************************
List Current Directory in Remote Server
********************************************************************************************}
procedure TNMFTP.List;
var
Replymess: string;
Success, Handled: Boolean;
Tsck: TSocket;
label CleanUp;
begin
EnterCriticalSection(ProcessLock);
Success := False;
BeenCanceled := False; {If there is a cancelled process reset it}
//if Fabort then
// begin
// ReplyMess:= transaction('ABOR');
// Fabort := False;
// end;
CertifyConnect; {Make sure Connection exists}
if Connected then
begin
if DataAvailable then read(0);
DataSocket := TPowersock.Create(self); {Create a Data socket}
DataSocket.TimeOut := TimeOut;
if assigned(FPacketRecvd) then
DataSocket.OnPacketRecvd := FPacketRecvd; {Set function to handle data socket status}
if FParseList then
begin
if FFTPDirectoryList = nil then
begin
if Vendor = NMOS_AUTO then
begin
try DoCommand('SYST')except end;
if (Pos('UNIX', TransactionReply) > 0) then
FVendor := NMOS_UNIX
else if (Pos('NETWARE', TransactionReply) > 0) then
FVendor := NMOS_NETWARE
else if (Pos('DOS', TransactionReply) > 0) then
FVendor := NMOS_WINDOWS
else if (Pos('VMS', TransactionReply) > 0) then
FVendor := NMOS_VMS
else if (Pos('MVS', TransactionReply) > 0) then
FVendor := NMOS_MVS_IBM
else if (Pos('VM', TransactionReply) > 0) then
FVendor := NMOS_VM
else if (Pos('MACOS', TransactionReply) > 0) then
FVendor := NMOS_MAC
else if (Pos('OS/400', TransactionReply) > 0) then
FVendor := NMOS_AS400
else {_ NOT if (Pos('OS/400', TransactionReply) > 0) then _}
FVendor := NMOS_OTHER;
end; {_ if Vendor = NMOS_AUTO then _}
case FVendor of
NMOS_UNIX: FFTPDirectoryList := TFTPUnixList.create;
NMOS_NETWARE: FFTPDirectoryList := TFTPUnixList.create;
NMOS_WINDOWS: FFTPDirectoryList := TFTPUnixList.create;
NMOS_VMS: FFTPDirectoryList := TFTPUnixList.create;
NMOS_MVS_IBM: FFTPDirectoryList := TFTPUnixList.create;
NMOS_VM: FFTPDirectoryList := TFTPUnixList.create;
NMOS_MAC: FFTPDirectoryList := TFTPUnixList.create;
NMOS_AS400: FFTPDirectoryList := TFTPUnixList.create;
NMOS_OTHER: FFTPDirectoryList := TFTPUnixList.create;
end; {_ case FVendor of _}
end; {_ if FFTPDirectoryList <> nil then _}
FFTPDirectoryList.clear;
end; {_ if FParseList then _}
DataSocket.TimeOut := TimeOut;
try
if FPassive then
begin
ReplyMess := Transaction('PASV');
if (ReplyNumber > 499) then
if not assigned(FOnFailure) then
raise FTPException.Create(Replymess)
else
begin
Handled := False;
FOnFailure(Handled, cmdList);
if not Handled then
raise FTPException.Create(Replymess)
else goto CleanUp;
{Raise exception on errors}
end; {_ NOT if not assigned(FOnFailure) then _}
DataSocket.Port := StrToInt(Copy(NthWord(replyMess, ',', 6), 1, Pos(')', NthWord(replyMess, ',', 6)) - 1)) + (256 * StrToInt(NthWord(replyMess, ',', 5)));
DataSocket.Host := Host;
DataSocket.connect;
end
else { _FPassive_ }
begin
DataSocket.Port := 0; {Set Port to Zero}
DataSocket.Listen(True); {Listen in the datasocket}
Replymess := Transaction(Cont_Port + GetLocalAddress + DataSocket.GetPortString); {Send Port for data socket}
if (ReplyNumber > 300) and (ReplyNumber < 600) then
if not assigned(FOnFailure) then
raise FTPException.Create(Replymess)
{Raise exception on errors}
else {_ NOT if not assigned(FOnFailure) then _}
begin
Handled := False;
FOnFailure(Handled, cmdList);
if not Handled then
raise FTPException.Create(Replymess)
else goto CleanUp;
{Raise exception on errors}
end; {_ NOT if not assigned(FOnFailure) then _}
end { not _FPassive_ };
StatusMessage(Status_Informational, Cont_List); {Show Outgoing Message}
if FListMask = '' then Replymess := Transaction(Cont_List)
else Replymess := Transaction(Cont_List + ' ' + FListMask); {Send List command}
if (ReplyNumber > 300) and (ReplyNumber < 600) then
begin
if assigned(FOnUnSupportedFunction) and (ReplyNumber >= 500) and (ReplyNumber <= 502) then FOnUnSupportedFunction(cmdList);
if not assigned(FOnFailure) then
raise FTPException.Create(Replymess)
{Raise exception on errors}
else {_ NOT if not assigned(FOnFailure) then _}
begin
Handled := False;
FOnFailure(Handled, cmdList);
if not Handled then
raise FTPException.Create(Replymess)
else goto CleanUp;
{Raise exception on errors}
end; {_ NOT if not assigned(FOnFailure) then _}
end; {_ if (ReplyNumber > 300) and (ReplyNumber < 600) then _}
if not FPassive then
begin
Tsck := DataSocket.handle;
DataSocket.ThisSocket := DataSocket.Accept; {Accept the datasocket}
WinSock.CloseSocket(Tsck);
end;
if assigned(FTransactionStart) then FTransactionStart(self);
while not (BeenCanceled or BeenTimedOut or DataSocket.DataAvailable) and DataSocket.Connected do
DataSocket.wait;
if not (BeenCanceled or BeenTimedOut) then
repeat
if DataSocket.DataAvailable then
begin
Replymess := DataSocket.readln;
if (Replymess = '') then break;
if Length(Replymess) > 2 then
if Replymess[Length(Replymess) - 1] = #13 then
SetLength(Replymess, Length(Replymess) - 2)
else
SetLength(Replymess, Length(Replymess) - 1);
if FParseList then
FFTPdirectoryList.ParseLine(Replymess);
if assigned(FOnListItem) then FOnListItem(Replymess);
end
else
DataSocket.Wait; //Application.ProcessMessages;
until (((not DataSocket.Connected) or DataAvailable) and (not DataSocket.DataAvailable)) or BeenTimedOut or BeenCanceled;
if assigned(FTransactionStop) then FTransactionStop(self);
if DataSocket.Connected then DataSocket.RequestCloseSocket;
if not (BeenCanceled or BeenTimedOut) then
Replymess := readln;
if ReplyMess = '' then ReplyMess := '226 Data Transfer successful';
StatusMessage(Status_Informational, Replymess);
if not (BeenCanceled or BeenTimedOut) then ReadExtraLines(Replymess); {Read Extra Lines}
Success := True;
CleanUp:
finally
DataSocket.Destroy; { _Destroy datasocket_ }
DataSocket := nil;
if BeenCanceled then
begin
BeenCanceled := False;
ReplyMess := Transaction('ABOR');
end;
LeaveCriticalSection(ProcessLock);
if Success then if assigned(FOnSuccess) then FOnSuccess(cmdList);
end {_ try _}
end; { _Connected_ }
end;
{*******************************************************************************************
Upload a file to a Remote Server
********************************************************************************************}
procedure TNMFTP.Upload(LocalFile, RemoteFile: string);
var
Replymess: string;
strm: TFileStream;
Success, Handled: Boolean;
Tsck: TSocket;
label CleanUp;
begin
try
Success := False;
BeenCanceled := False; {If there is a cancelled process reset it}
CertifyConnect; {Make sure Connection exists}
if Connected then
begin
EnterCriticalSection(ProcessLock);
if DataAvailable then read(0);
DataSocket := TPowersock.Create(self); {Create a Data socket}
DataSocket.TimeOut := TimeOut;
strm := TFileStream.Create(LocalFile, fmOpenRead);
DataSocket.TimeOut := TimeOut;
if assigned(FPacketSent) then
DataSocket.OnPacketSent := FPacketSent; {Set function to handle data socket status}
try
FBytesTotal := strm.Size;
finally
strm.Destroy;
end; {_ try _}
try
if FPassive then
begin
ReplyMess := Transaction('PASV');
if (ReplyNumber > 499) then
if not assigned(FOnFailure) then
raise FTPException.Create(Replymess)
else
begin
Handled := False;
FOnFailure(Handled, cmdUpload);
if not Handled then
raise FTPException.Create(Replymess)
else goto CleanUp;
{Raise exception on errors}
end; {_ NOT if not assigned(FOnFailure) then _}
DataSocket.Port := StrToInt(Copy(NthWord(replyMess, ',', 6), 1, Pos(')', NthWord(replyMess, ',', 6)) - 1)) + (256 * StrToInt(NthWord(replyMess, ',', 5)));
DataSocket.Host := Host;
DataSocket.connect;
end
else { _FPassive_ }
begin
DataSocket.Port := 0; {Set Port to Zero}
DataSocket.Listen(True); {Listen in the datasocket}
Replymess := Transaction(Cont_Port + GetLocalAddress + DataSocket.GetPortString); {Send Port for data socket}
if (ReplyNumber > 300) and (ReplyNumber < 600) then
if not assigned(FOnFailure) then
raise FTPException.Create(Replymess)
{Raise exception on errors}
else {_ NOT if not assigned(FOnFailure) then _}
begin
Handled := False;
FOnFailure(Handled, cmdUpload);
if not Handled then
raise FTPException.Create(Replymess)
else goto CleanUp;
{Raise exception on errors}
end; {_ NOT if not assigned(FOnFailure) then _}
end { not _FPassive_ };
if RemoteFile = '' then
begin
StatusMessage(Status_Informational, Cont_Stor + LocalFile); {Show Outgoing Message}
Replymess := Transaction(Cont_Stor + ExtractFileName(LocalFile)) {Give store unique cmmand}
end {_ if RemoteFile = '' then _}
else {_ NOT if RemoteFile = '' then _}
begin
StatusMessage(Status_Informational, Cont_Stor + RemoteFile); {Show Outgoing Message}
Replymess := Transaction(Cont_Stor + RemoteFile); {Give store unique cmmand}
end; {_ NOT if RemoteFile = '' then _}
if (ReplyNumber > 300) and (ReplyNumber < 600) then
begin
if assigned(FOnUnSupportedFunction) and (ReplyNumber >= 500) and (ReplyNumber <= 502) then FOnUnSupportedFunction(cmdUpload);
if not assigned(FOnFailure) then
raise FTPException.Create(Replymess)
{Raise exception on errors}
else {_ NOT if not assigned(FOnFailure) then _}
begin
Handled := False;
FOnFailure(Handled, cmdUpload);
if not Handled then
raise FTPException.Create(Replymess)
else goto CleanUp;
{Raise exception on errors}
end; {_ NOT if not assigned(FOnFailure) then _}
end; {_ if (ReplyNumber > 300) and (ReplyNumber < 600) then _}
if not FPassive then
begin
Tsck := DataSocket.handle;
DataSocket.ThisSocket := DataSocket.Accept; {Accept the datasocket}
WinSock.CloseSocket(Tsck);
end;
if assigned(FTransactionStart) then FTransactionStart(self);
DataSocket.CloseAfterData;
if not (BeenCanceled or BeenTimedOut) then DataSocket.SendFile(LocalFile);
{If no Local filename specified save file same as remote}
if assigned(FTransactionStop) then FTransactionStop(self);
WinSock.CloseSocket(DataSocket.ThisSocket);
Replymess := readln;
if ReplyMess = '' then ReplyMess := '226 Data Transfer successful';
StatusMessage(Status_Informational, Replymess);
if not (BeenCanceled or BeenTimedOut) then ReadExtraLines(Replymess); {Read Extra Lines}
Success := True;
CleanUp:
finally
DataSocket.Destroy; { _Destroy datasocket_ }
DataSocket := nil;
LeaveCriticalSection(ProcessLock);
if Success then if assigned(FOnSuccess) then FOnSuccess(cmdUpload);
end {_ try _}
end; { _Connected_ }
except
Handled := False;
FOnFailure(Handled, cmdUpload);
if not Handled then
raise;
end;
end;
{*******************************************************************************************
Upload a file to a Remote Server
********************************************************************************************}
begin
Success := False;
BeenCanceled := False; {If there is a cancelled process reset it}
CertifyConnect; {Make sure Connection exists}
if Connected then
begin
if DataAvailable then read(0);
DataSocket := TPowersock.Create(self); {Create a Data socket}
DataSocket.TimeOut := TimeOut;
strm := TFileStream.Create(LocalFile, fmOpenRead);
DataSocket.TimeOut := TimeOut;
if assigned(FPacketSent) then
DataSocket.OnPacketSent := FPacketSent; {Set function to handle data socket status}
try
FBytesTotal := strm.Size;
finally
strm.Destroy;
end; {_ try _}
try
if FPassive then
begin
ReplyMess := Transaction('PASV');
if (ReplyNumber > 499) then
if not assigned(FOnFailure) then
raise FTPException.Create(Replymess)
else
begin
Handled := False;
FOnFailure(Handled, cmdUpload);
if not Handled then
raise FTPException.Create(Replymess)
else goto CleanUp;
{Raise exception on errors}
end; {_ NOT if not assigned(FOnFailure) then _}
DataSocket.Port := StrToInt(Copy(NthWord(replyMess, ',', 6), 1, Pos(')', NthWord(replyMess, ',', 6)) - 1)) + (256 * StrToInt(NthWord(replyMess, ',', 5)));
DataSocket.Host := Host;
DataSocket.connect;
end
else { _FPassive_ }
begin
DataSocket.Port := 0; {Set Port to Zero}
DataSocket.Listen(True); {Listen in the datasocket}
Replymess := Transaction(Cont_Port + GetLocalAddress + DataSocket.GetPortString); {Send Port for data socket}
if (ReplyNumber > 300) and (ReplyNumber < 600) then
if not assigned(FOnFailure) then
raise FTPException.Create(Replymess)
{Raise exception on errors}
else {_ NOT if not assigned(FOnFailure) then _}
begin
Handled := False;
FOnFailure(Handled, cmdUpload);
if not Handled then
raise FTPException.Create(Replymess)
else goto CleanUp;
{Raise exception on errors}
end; {_ NOT if not assigned(FOnFailure) then _}
end { not _FPassive_ };
if RemoteFile = '' then
begin
StatusMessage(Status_Informational, Cont_Rest + IntToStr(Position) + '' + Cont_stor); {Show Outgoing Message}
Replymess := Transaction(Cont_Rest + IntToStr(Position));
Replymess := Transaction(Cont_stor + ExtractFileName(LocalFile)); {Give store unique cmmand}
end {_ if RemoteFile = '' then _}
else {_ NOT if RemoteFile = '' then _}
begin
StatusMessage(Status_Informational, Cont_Rest + IntToStr(Position) + '' + Cont_stor); {Show Outgoing Message}
Replymess := Transaction(Cont_Rest + IntToStr(Position));
Replymess := Transaction(Cont_stor + RemoteFile); {Give store unique cmmand}
end; {_ NOT if RemoteFile = '' then _}
if (ReplyNumber > 399) and (ReplyNumber < 600) then
begin
if assigned(FOnUnSupportedFunction) and (ReplyNumber >= 500) and (ReplyNumber <= 502) then FOnUnSupportedFunction(cmdUpload);
if not assigned(FOnFailure) then
raise FTPException.Create(Replymess)
{Raise exception on errors}
else {_ NOT if not assigned(FOnFailure) then _}
begin
Handled := False;
FOnFailure(Handled, cmdUpload);
if not Handled then
raise FTPException.Create(Replymess)
else goto CleanUp;
{Raise exception on errors}
end; {_ NOT if not assigned(FOnFailure) then _}
end; {_ if (ReplyNumber > 300) and (ReplyNumber < 600) then _}
if not FPassive then
begin
Tsck := DataSocket.handle;
DataSocket.ThisSocket := DataSocket.Accept; {Accept the datasocket}
WinSock.CloseSocket(Tsck);
end;
if assigned(FTransactionStart) then FTransactionStart(self);
Strm := TFileStream.Create(LocalFile, fmOpenRead);
Strm.Position := Position;
try
if not (BeenCanceled or BeenTimedOut)
then DataSocket.SendRestStream(Strm);
finally
Strm.free;
end;
{If no Local filename specified save file same as remote}
if assigned(FTransactionStop) then FTransactionStop(self);
gudtLinger.l_onoff := 0;
gudtLinger.l_linger := 0;
setsockopt(DataSocket.ThisSocket, SOL_SOCKET, SO_LINGER, @gudtLinger, 4);
DataSocket.RequestCloseSocket;
if not (BeenCanceled or BeenTimedOut) then
Replymess := read(0);
if ReplyMess = '' then ReplyMess := '226 Data Transfer successful';
StatusMessage(Status_Informational, Replymess);
if not (BeenCanceled or BeenTimedOut) then ReadExtraLines(Replymess); {Read Extra Lines}
Success := True;
CleanUp:
finally
DataSocket.Destroy; { _Destroy datasocket_ }
DataSocket := nil;
if Success then if assigned(FOnSuccess) then FOnSuccess(cmdUpload);
end {_ try _}
end; { _Connected_ }
end;
{*******************************************************************************************
Download a file from a Remote Server
********************************************************************************************}
procedure TNMFTP.Download(RemoteFile, LocalFile: string);
var
Replymess: string;
Success, Handled: Boolean;
Tsck: TSocket;
label CleanUp;
begin
try
Success := False;
BeenCanceled := False; {If there is a cancelled process reset it}
CertifyConnect; {Make sure Connection exists}
if Connected then
begin
EnterCriticalSection(ProcessLock);
if DataAvailable then read(0);
DataSocket := TPowersock.Create(self); {Create a Data socket}
DataSocket.TimeOut := TimeOut;
if assigned(FPacketRecvd) then
DataSocket.OnPacketRecvd := FPacketRecvd; {Set function to handle data socket status}
try
if FPassive then
begin
ReplyMess := Transaction('PASV');
if (ReplyNumber > 499) then
if not assigned(FOnFailure) then
raise FTPException.Create(Replymess)
else
begin
Handled := False;
FOnFailure(Handled, cmdDownLoad);
if not Handled then
raise FTPException.Create(Replymess)
else goto CleanUp;
{Raise exception on errors}
end; {_ NOT if not assigned(FOnFailure) then _}
DataSocket.Port := StrToInt(Copy(NthWord(replyMess, ',', 6), 1, Pos(')', NthWord(replyMess, ',', 6)) - 1)) + (256 * StrToInt(NthWord(replyMess, ',', 5)));
DataSocket.Host := Host;
DataSocket.connect;
end
else { _FPassive_ }
begin
DataSocket.Port := 0; {Set Port to Zero}
DataSocket.Listen(True); {Listen in the datasocket}
Replymess := Transaction(Cont_Port + GetLocalAddress + DataSocket.GetPortString); {Send Port for data socket}
if (ReplyNumber > 300) and (ReplyNumber < 600) then
if not assigned(FOnFailure) then
raise FTPException.Create(Replymess)
{Raise exception on errors}
else {_ NOT if not assigned(FOnFailure) then _}
begin
Handled := False;
FOnFailure(Handled, cmdDownload);
if not Handled then
raise FTPException.Create(Replymess)
else goto CleanUp;
{Raise exception on errors}
end; {_ NOT if not assigned(FOnFailure) then _}
end { not _FPassive_ };
StatusMessage(Status_Informational, Cont_Retr + RemoteFile); {Show Outgoing Message}
FBytesTotal := 0;
Replymess := inherited Transaction(Cont_Retr + RemoteFile);
if (ReplyNumber > 300) and (ReplyNumber < 600) then
if not assigned(FOnFailure) then raise FTPException.Create(Replymess)
{Raise exception on errors}
else {_ NOT if not assigned(FOnFailure) then raise FTPException.Create(Replymess) _}
begin
Handled := False;
FOnFailure(Handled, cmdDownload);
if not Handled then raise FTPException.Create(Replymess)
else goto CleanUp;
{Raise exception on errors}
end; {_ NOT if not assigned(FOnFailure) then raise FTPException.Create(Replymess) _}
FBytesTotal := GetBytesTotal(Replymess);
while (Replymess[1] = ' ') or (Replymess[4] = '-') do
begin
Replymess := readln; {Handle Extra Lines}
StatusMessage(Status_Informational, Replymess); {Show Received Lines}
if FBytesTotal = 0 then FBytesTotal := GetBytesTotal(Replymess);
if (ReplyNumber > 300) and (ReplyNumber < 600) then
begin
if assigned(FOnUnSupportedFunction) and (ReplyNumber >= 500) and (ReplyNumber <= 502) then FOnUnSupportedFunction(cmdDownload);
if not assigned(FOnFailure) then
raise FTPException.Create(Replymess)
{Raise exception on errors}
else {_ NOT if not assigned(FOnFailure) then _}
begin
Handled := False;
FOnFailure(Handled, cmdDownload);
if not Handled then
raise FTPException.Create(Replymess);
{Raise exception on errors}
end; {_ NOT if not assigned(FOnFailure) then _}
end; {_ if (ReplyNumber > 300) and (ReplyNumber < 600) then _}
end; {_ while (Replymess[1] = ' ') or (Replymess[4] = '-') do _}
if not FPassive then
begin
Tsck := DataSocket.handle;
DataSocket.ThisSocket := DataSocket.Accept; {Accept the datasocket}
WinSock.CloseSocket(Tsck);
end;
FBytesTotal := GetBytesTotal(Replymess);
if assigned(FTransactionStart) then FTransactionStart(self);
if not (BeenCanceled or BeenTimedOut) then
if LocalFile = '' then DataSocket.CaptureFile(RemoteFile)
{If no Local filename specified save file same as remote}
else {_ NOT if LocalFile = '' then DataSocket.CaptureFile(RemoteFile) _} DataSocket.CaptureFile(LocalFile); {If Local filename specified save file under it}
if assigned(FTransactionStop) then FTransactionStop(self);
DataSocket.RequestCloseSocket;
FBytesTotal := DataSocket.BytesRecvd;
StatusMessage(Status_Informational, (sFTP_Msg_Recvd + IntToStr(BytesTotal) + sFTP_No_Bytes));
if not (BeenCanceled or BeenTimedOut) then Replymess := readln;
//if ReplyMess='' then ReplyMess:='226 Data Transfer successful';
StatusMessage(Status_Informational, Replymess);
if not (BeenCanceled or BeenTimedOut) then ReadExtraLines(Replymess);
{Read Extra Lines}
{If no Local filename specified save file same as remote}
if assigned(FTransactionStop) then FTransactionStop(self);
Success := True;
CleanUp:
finally
DataSocket.Destroy; { _Destroy datasocket_ }
DataSocket := nil;
if BeenCanceled then
begin
BeenCanceled := False;
ReplyMess := Transaction('ABOR');
end;
if Success then if assigned(FOnSuccess) then FOnSuccess(cmdDownload);
end {_ try _}
end; { _Connected_ }
except
Handled := False;
FOnFailure(Handled, cmdDownload);
if not Handled then
raise;
end;
end;
{*******************************************************************************************
Download a file from a Remote Server
********************************************************************************************}
procedure TNMFTP.DownloadRestore(RemoteFile, LocalFile: string);
var
Replymess: string;
Success, Handled: Boolean;
AFileStream: TFileStream;
Posn: Integer;
Tsck: TSocket;
label CleanUp;
begin
Success := False;
BeenCanceled := False; {If there is a cancelled process reset it}
CertifyConnect; {Make sure Connection exists}
if Connected then
begin
if DataAvailable then read(0);
DataSocket := TPowersock.Create(self); {Create a Data socket}
DataSocket.TimeOut := TimeOut;
if Localfile = '' then LocalFile := RemoteFile;
if assigned(FPacketRecvd) then
DataSocket.OnPacketRecvd := FPacketRecvd; {Set function to handle data socket status}
try
if FPassive then
begin
ReplyMess := Transaction('PASV');
if (ReplyNumber > 499) then
if not assigned(FOnFailure) then
raise FTPException.Create(Replymess)
else
begin
Handled := False;
FOnFailure(Handled, cmdDownLoad);
if not Handled then
raise FTPException.Create(Replymess)
else goto CleanUp;
{Raise exception on errors}
end; {_ NOT if not assigned(FOnFailure) then _}
DataSocket.Port := StrToInt(Copy(NthWord(replyMess, ',', 6), 1, Pos(')', NthWord(replyMess, ',', 6)) - 1)) + (256 * StrToInt(NthWord(replyMess, ',', 5)));
DataSocket.Host := Host;
DataSocket.connect;
end
else { _FPassive_ }
begin
DataSocket.Port := 0; {Set Port to Zero}
DataSocket.Listen(True); {Listen in the datasocket}
Replymess := Transaction(Cont_Port + GetLocalAddress + DataSocket.GetPortString); {Send Port for data socket}
if (ReplyNumber > 300) and (ReplyNumber < 600) then
if not assigned(FOnFailure) then
raise FTPException.Create(Replymess)
{Raise exception on errors}
else {_ NOT if not assigned(FOnFailure) then _}
begin
Handled := False;
FOnFailure(Handled, cmdDownload);
if not Handled then
raise FTPException.Create(Replymess)
else goto CleanUp;
{Raise exception on errors}
end; {_ NOT if not assigned(FOnFailure) then _}
end { not _FPassive_ };
try
AFileStream := TFileStream.Create(LocalFile, fmOpenRead); {If Local filename specified save file under it}
Posn := AFileStream.Size;
AFileStream.Free;
except
Posn := 0;
end;
StatusMessage(Status_Informational, Cont_Rest + Cont_Retr + RemoteFile); {Show Outgoing Message}
FBytesTotal := 0;
Replymess := inherited Transaction(Cont_Rest + IntToStr(Posn));
Replymess := inherited Transaction(Cont_Retr + RemoteFile);
if (ReplyNumber > 300) and (ReplyNumber < 600) then
if not assigned(FOnFailure) then raise FTPException.Create(Replymess)
{Raise exception on errors}
else {_ NOT if not assigned(FOnFailure) then raise FTPException.Create(Replymess) _}
begin
Handled := False;
FOnFailure(Handled, cmdDownload);
if not Handled then raise FTPException.Create(Replymess);
{Raise exception on errors}
end; {_ NOT if not assigned(FOnFailure) then raise FTPException.Create(Replymess) _}
FBytesTotal := GetBytesTotal(Replymess);
while (Replymess[1] = ' ') or (Replymess[4] = '-') do
begin
Replymess := readln; {Handle Extra Lines}
StatusMessage(Status_Informational, Replymess); {Show Received Lines}
if FBytesTotal = 0 then FBytesTotal := GetBytesTotal(Replymess);
if (ReplyNumber > 300) and (ReplyNumber < 600) then
begin
if assigned(FOnUnSupportedFunction) and (ReplyNumber >= 500) and (ReplyNumber <= 502) then FOnUnSupportedFunction(cmdDownload);
if not assigned(FOnFailure) then
raise FTPException.Create(Replymess)
{Raise exception on errors}
else {_ NOT if not assigned(FOnFailure) then _}
begin
Handled := False;
FOnFailure(Handled, cmdDownload);
if not Handled then
raise FTPException.Create(Replymess);
{Raise exception on errors}
end; {_ NOT if not assigned(FOnFailure) then _}
end; {_ if (ReplyNumber > 300) and (ReplyNumber < 600) then _}
end; {_ while (Replymess[1] = ' ') or (Replymess[4] = '-') do _}
if not FPassive then
begin
Tsck := DataSocket.handle;
DataSocket.ThisSocket := DataSocket.Accept; {Accept the datasocket}
WinSock.CloseSocket(Tsck);
end;
FBytesTotal := GetBytesTotal(Replymess);
if assigned(FTransactionStart) then FTransactionStart(self);
if not (BeenCanceled or BeenTimedOut) then
if LocalFile = '' then DataSocket.AppendFile(RemoteFile)
{If no Local filename specified save file same as remote}
else {_ NOT if LocalFile = '' then DataSocket.CaptureFile(RemoteFile) _} DataSocket.AppendFile(LocalFile); {If Local filename specified save file under it}
if assigned(FTransactionStop) then FTransactionStop(self);
DataSocket.RequestCloseSocket;
FBytesTotal := DataSocket.BytesRecvd;
StatusMessage(Status_Informational, (sFTP_Msg_Recvd + IntToStr(BytesTotal) + sFTP_No_Bytes));
if not (BeenCanceled or BeenTimedOut) then Replymess := read(0);
if ReplyMess = '' then ReplyMess := '226 Data Transfer successful';
StatusMessage(Status_Informational, Replymess);
if not (BeenCanceled or BeenTimedOut) then ReadExtraLines(Replymess);
{Read Extra Lines}
{If no Local filename specified save file same as remote}
if assigned(FTransactionStop) then FTransactionStop(self);
Success := True;
CleanUp:
finally
DataSocket.Destroy; { _Destroy datasocket_ }
DataSocket := nil;
if BeenCanceled then
begin
BeenCanceled := False;
ReplyMess := Transaction('ABOR');
end;
if Success then if assigned(FOnSuccess) then FOnSuccess(cmdDownload);
end {_ try _}
end; { _Connected_ }
end;
{*******************************************************************************************
Upload a file to a Remote Server and append to existing file
********************************************************************************************}
procedure TNMFTP.UploadAppend(LocalFile, RemoteFile: string);
var
Replymess: string;
strm: TFileStream;
Success, Handled: Boolean;
Tsck: TSocket;
label CleanUp;
begin
Success := False;
BeenCanceled := False; {If there is a cancelled process reset it}
CertifyConnect; {Make sure Connection exists}
if Connected then
begin
if DataAvailable then read(0);
DataSocket := TPowersock.Create(self); {Create a Data socket}
DataSocket.TimeOut := TimeOut;
strm := TFileStream.Create(LocalFile, fmOpenRead);
DataSocket.TimeOut := TimeOut;
if assigned(FPacketSent) then
DataSocket.OnPacketSent := FPacketSent; {Set function to handle data socket status}
try
FBytesTotal := strm.Size;
finally
strm.Destroy;
end; {_ try _}
try
if FPassive then
begin
ReplyMess := Transaction('PASV');
if (ReplyNumber > 499) then
if not assigned(FOnFailure) then
raise FTPException.Create(Replymess)
else
begin
Handled := False;
FOnFailure(Handled, cmdAppend);
if not Handled then
raise FTPException.Create(Replymess)
else goto CleanUp;
{Raise exception on errors}
end; {_ NOT if not assigned(FOnFailure) then _}
DataSocket.Port := StrToInt(Copy(NthWord(replyMess, ',', 6), 1, Pos(')', NthWord(replyMess, ',', 6)) - 1)) + (256 * StrToInt(NthWord(replyMess, ',', 5)));
DataSocket.Host := Host;
DataSocket.connect;
end
else { _FPassive_ }
begin
DataSocket.Port := 0; {Set Port to Zero}
DataSocket.Listen(True); {Listen in the datasocket}
Replymess := Transaction(Cont_Port + GetLocalAddress + DataSocket.GetPortString); {Send Port for data socket}
if (ReplyNumber > 300) and (ReplyNumber < 600) then
if not assigned(FOnFailure) then
raise FTPException.Create(Replymess)
{Raise exception on errors}
else {_ NOT if not assigned(FOnFailure) then _}
begin
Handled := False;
FOnFailure(Handled, cmdAppend);
if not Handled then
raise FTPException.Create(Replymess)
else goto CleanUp;
{Raise exception on errors}
end; {_ NOT if not assigned(FOnFailure) then _}
end { not _FPassive_ };
if RemoteFile = '' then
begin
StatusMessage(Status_Informational, Cont_Appe + LocalFile); {Show Outgoing Message}
Replymess := Transaction(Cont_Appe + ExtractFileName(LocalFile)) {Give store unique cmmand}
end {_ if RemoteFile = '' then _}
else {_ NOT if RemoteFile = '' then _}
begin
StatusMessage(Status_Informational, Cont_Appe + RemoteFile); {Show Outgoing Message}
Replymess := Transaction(Cont_Appe + RemoteFile); {Give store unique cmmand}
end; {_ NOT if RemoteFile = '' then _}
if (ReplyNumber > 300) and (ReplyNumber < 600) then
begin
if assigned(FOnUnSupportedFunction) and (ReplyNumber >= 500) and (ReplyNumber <= 502) then FOnUnSupportedFunction(cmdAppend);
if not assigned(FOnFailure) then
raise FTPException.Create(Replymess)
{Raise exception on errors}
else {_ NOT if not assigned(FOnFailure) then _}
begin
Handled := False;
FOnFailure(Handled, cmdAppend);
if not Handled then
raise FTPException.Create(Replymess)
else goto CleanUp;
{Raise exception on errors}
end; {_ NOT if not assigned(FOnFailure) then _}
end; {_ if (ReplyNumber > 300) and (ReplyNumber < 600) then _}
if not FPassive then
begin
Tsck := DataSocket.handle;
DataSocket.ThisSocket := DataSocket.Accept; {Accept the datasocket}
WinSock.CloseSocket(Tsck);
end;
if assigned(FTransactionStart) then FTransactionStart(self);
if not (BeenCanceled or BeenTimedOut) then DataSocket.SendFile(LocalFile);
{If no Local filename specified save file same as remote}
if assigned(FTransactionStop) then FTransactionStop(self);
CloseAfterData;
DataSocket.RequestCloseSocket;
if not (BeenCanceled or BeenTimedOut) then
Replymess := readln;
if ReplyMess = '' then ReplyMess := '226 Data Transfer successful';
StatusMessage(Status_Informational, Replymess);
if not (BeenCanceled or BeenTimedOut) then ReadExtraLines(Replymess); {Read Extra Lines}
Success := True;
CleanUp:
finally
DataSocket.Destroy; { _Destroy datasocket_ }
DataSocket := nil;
if Success then if assigned(FOnSuccess) then FOnSuccess(cmdAppend);
end {_ try _}
end; { _Connected_ }
end;
{*******************************************************************************************
Get Current Directory in Remote Server
********************************************************************************************}
function TNMFTP.GetCurrentDir;
begin
DoCommand(Cont_Pwd); {Send get Current directory Command}
Result := NthWord(TransactionReply, '"', 2);
end; {_ function TNMFTP.GetCurrentDir; _}
{*******************************************************************************************
Change the mode for file transactions
********************************************************************************************}
procedure TNMFTP.Mode(TheMode: Integer);
begin
case TheMode of
MODE_ASCII: DoCommand(Cont_Typ + 'A'); {Send AsCII Command}
MODE_IMAGE: DoCommand(Cont_Typ + 'I'); {Send Image Command}
MODE_BYTE: DoCommand(Cont_Typ + 'L 8'); {Send Byte Command}
end; {_ case TheMode of _}
end; {_ procedure TNMFTP.Mode(TheMode: Integer); _}
{*******************************************************************************************
Get the value of BytesReceived property
********************************************************************************************}
function TNMFTP.GetBytesRcvd;
begin Result := DataSocket.BytesRecvd end;
{*******************************************************************************************
Get the value of BytesReceived property
********************************************************************************************}
function TNMFTP.GetBytesSent;
begin Result := DataSocket.BytesSent end;
{*******************************************************************************************
Get the value of BytesTotal property
********************************************************************************************}
function TNMFTP.GetBytesTotal;
var
ReplyP: string[255];
I: Integer;
begin
I := Pos(No_Byte, UpperCase(Replymess));
if I > 0 then
begin
ReplyP := '';
while (Replymess < '0') or (Replymess > '9') do
I := I - 1;
while (Replymess >= '0') and (Replymess <= '9') do
I := I - 1;
I := I + 1;
while (Replymess >= '0') and (Replymess <= '9') do
begin
ReplyP := ReplyP + Replymess;
I := I + 1;
end; {_ while (Replymess >= '0') and (Replymess <= '9') do _}
Result := StrToIntDef(ReplyP, 0);
end {_ if I > 0 then _}
else {_ NOT if I > 0 then _} Result := 0;
end; {_ function TNMFTP.GetBytesTotal; _}
{*******************************************************************************************
Abort a FTP file transaction
********************************************************************************************}
procedure TNMFTP.Abort;
begin
// ReplyMess:= transaction('ABOR');
if DataSocket <> nil then
begin
//DataSocket.FOStream.size := 0;
DataSocket.Cancel; {Cancel Read or write}
end; {_ if DataSocket <> nil then _}
Cancel;
//FAbort := True;
end; {_ procedure TNMFTP.Abort; _}
{*******************************************************************************************
Process Extra Lines in Transaction
********************************************************************************************}
function TNMFTP.Transaction(const CommandString: string): string;
var Replymess: string;
begin
Replymess := inherited Transaction(CommandString);
ReadExtraLines(Replymess);
Result := Replymess;
end; {_ function TNMFTP.Transaction(const CommandString: string): string; _}
procedure TNMFTP.ReadExtraLines;
begin
while (Replymess[1] = ' ') or (Replymess[4] = '-') do
{If extra Lines}
begin
Replymess := readln; {Handle Extra Lines}
StatusMessage(Status_Informational, Replymess); {Show Received Lines}
end; {_ while (Replymess[1] = ' ') or (Replymess[4] = '-') do _}
end; {_ procedure TNMFTP.ReadExtraLines; _}
{*******************************************************************************************
List Files in Current Directory in Remote Server
********************************************************************************************}
procedure TNMFTP.Nlist;
var
Replymess: string;
Done: Boolean;
Sck1: Integer;
begin {Stop Asynchronous Processing}
Done := False;
BeenCanceled := False; {Reset Cancelled flag}
CertifyConnect;
if Connected then
{If connected}
begin
DataSocket := TPowersock.Create(self); {Create a Data socket}
DataSocket.TimeOut := TimeOut;
try
if DataAvailable then read(0);
DataSocket.Timeout := Timeout;
DataSocket.Port := 0; {Set Port to Zero}
DataSocket.Listen(True); {Listen in the datasocket}
StatusMessage(Status_Informational, Cont_Port + GetLocalAddress + DataSocket.GetPortString); {Show Outgoing Message}
Replymess := Transaction(Cont_Port + GetLocalAddress + DataSocket.GetPortString); {Send Port for data socket}
if (ReplyNumber > 300) and (ReplyNumber < 600)
then raise FTPException.Create(Replymess);
{Raise exception on errors}
StatusMessage(Status_Informational, Cont_Nlst); {Show Outgoing Message}
if FListMask = '' then Replymess := Transaction(Cont_Nlst)
else Replymess := Transaction(Cont_Nlst + ' ' + FListMask); {Send List command}
if (ReplyNumber > 300) and (ReplyNumber < 600)
then raise FTPException.Create(Replymess);
{Raise exception on errors}
FBytesTotal := GetBytesTotal(Replymess);
Sck1 := DataSocket.ThisSocket;
DataSocket.ThisSocket := DataSocket.Accept; {Accept the datasocket}
Winsock.Closesocket(Sck1); {Accept the datasocket}
if assigned(FTransactionStart) then FTransactionStart(self);
while not (BeenCanceled or BeenTimedOut or DataSocket.DataAvailable) do
Datasocket.wait;
if not (BeenCanceled or BeenTimedOut) then
repeat
if DataSocket.DataAvailable then
begin
Replymess := DataSocket.readln;
if Length(Replymess) > 2 then
if Replymess[Length(Replymess) - 1] = #13 then
SetLength(Replymess, Length(Replymess) - 2)
else {_ NOT if Replymess[Length(Replymess) - 1] = #13 then _} SetLength(Replymess, Length(Replymess) - 1);
if assigned(FOnListItem) then FOnListItem(Replymess);
end {_ if DataAvailable > 0 then read (0); _}
else {_ NOT if DataAvailable > 0 then read (0); _}
Datasocket.Wait; //Application.ProcessMessages;
until (((not DataSocket.Connected) or DataAvailable) and (not DataSocket.DataAvailable)) or BeenTimedOut or BeenCanceled; {Capture incoming data}
{Capture incoming data}
if assigned(FTransactionStop) then FTransactionStop(self);
DataSocket.RequestCloseSocket;
FBytesTotal := DataSocket.BytesRecvd;
StatusMessage(Status_Informational, (sFTP_Msg_Recvd + IntToStr(BytesTotal) + sFTP_No_Bytes));
if not (BeenCanceled or BeenTimedOut) then Replymess := read(0);
if ReplyMess = '' then ReplyMess := '226 Data Transfer successful';
StatusMessage(Status_Informational, Replymess);
if not (BeenCanceled or BeenTimedOut) then ReadExtraLines(Replymess); {Read Extra Lines}
Done := True;
finally
DataSocket.Destroy; {Destroy datasocket}
DataSocket := nil;
if Done then if assigned(FOnSuccess) then FOnSuccess(cmdNList);
if BeenCanceled then Flush;
end; {_ try _}
end; {_ if Connected then _}
end; {_ procedure TNMFTP.Nlist; _}
procedure TNMFTP.Reinitialize;
begin
DoCommand(Cont_Rein);
end; {_ procedure TNMFTP.Reinitialize; _}
procedure TNMFTP.CheckRead(Sender: TObject);
begin
(*if DataAvailable then
begin
{ AStr := TMemoryStream(FIstream).Memory;
if Astr[0] ='4' then
if AStr[1] = '2' then
if (AStr[2] ='1') or (AStr[2] ='6') then
Cancel; }
end; *)
end;
procedure TNMFTP.Flush;
var STime: TDateTime;
var Replymess: string;
begin
BeenCanceled := False;
STime := Now;
repeat
Replymess := read(0);
Application.ProcessMessages;
until (Replymess <> '') or (Now - STime > 1.1E-5);
StatusMessage(Status_Informational, Replymess);
end; {_ procedure TNMFTP.Flush; _}
NetMaster Fast Net VcL V5.6.3 /with source/Delphi345/BCB
www.net-wing.net/kangwei/newvcl/netfast/f-fnvcl1.zip
www.net-wing.net/kangwei/newvcl/netfast/f-fnvcl2.zip
www.net-wing.net/kangwei/newvcl/netfast/f-fnvcl3.zip