Q&A

  • 답변이나 의견 부탁드립니다.
아래화일은 화일전송프로그램입니다.

아래것은 서버에 있는것을 가지고 올수만있더군요..

이것을 어떤방법을 서버로 전송도 가능하게 만들수 있을까요.

참고로 이 소스는 인터넷 서핑해서 찾은겁니다...아마 한델인것 같은데.

도움 바랍니다.



unit FTPGetFile;



interface



uses

SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,

Forms, StdCtrls, Dialogs, Buttons, ComCtrls, ExtCtrls, Winsock;



type

// FTP control에서 사용될 상수

// 비동기적으로 호출되는 Command_Proc에서 현재 작업의 상태를 알기위해

TCommand = (PUT_USER, PUT_PASS, PUT_CWD, PUT_QUIT, PUT_TYPE, PUT_RETR,

PUT_STOR, PUT_DELE, PUT_RMD, PUT_MKD, PUT_LIST, PUT_NLST,

PUT_HELP, PUT_PORT, PUT_PWD, PUT_SYST, PUT_ACCT, GET_MESSAGE,

CHK_REST, PRX_OPEN1, PRX_SITE1, PRX_SITE2, PRX_SITE3);



const

// 함수에서 사용할 네트워크 메시지

WM_CONNECT_MSG = WM_USER + 100; // 호스트의 포트에 연결시 발생되는 원도우즈 메시지

// (주의) 이 프로그램의 비동기 통신방법

// 1. connect() : WSAAsyncSelect() 함수 사용

// 2. accept(), recv(), send() : select() 함수 사용

// 3. 호스트 이름 resolve : WSAAsyncGetHostByName(), WSAAsyncGetHostByAddr() 함수 사용



type

TFTPGetForm = class(TForm)

BB_Stop: TBitBtn;

Label2: TLabel;

L_Rfile: TLabel;

Label5: TLabel;

L_Rsize: TLabel;

Label3: TLabel;

ProgressBar1: TProgressBar;

CB_Message: TComboBox;

Panel1: TPanel;

Timer1: TTimer;

L_Speed: TLabel;

Image_update: TImage;

Image_new: TImage;

procedure FormActivate(Sender: TObject);

procedure BB_StopClick(Sender: TObject);

procedure Timer1Timer(Sender: TObject);

procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);

private

{ Private declarations }



{Message Handler}

procedure ConnectMessage(var Msg: TMessage); message WM_CONNECT_MSG;



{FTP부분에 사용되는 기본 method}

function Send_Command(cStr: String): Boolean;

procedure AllCloseSocket;

function GetFTPListenSocket: Tsocket;

procedure DOclosesocket(var socket_id: Tsocket);

procedure DOAddLine(str: String);

function GetReply: Boolean;

procedure Process_ReplyMessage;

procedure asyncselect(synsocket: Tsocket; readsock: Boolean);

procedure asyncconnect(synsocket: Tsocket; synsocket_in: TSockAddrIn; trytimes: Integer);

function AbortCom: Boolean;

function Get_Value(Str, cSpr:String; nPos: Integer): String;

public

{ Public declarations }

HOST_IP : String; {호스트 IP}

USER_ID : String; {사용자 ID}

PASSWORD : String; {비밀번호}

PASSIVE_MODE : Boolean; {passive mode}

SEND_FILENAME, RECV_FILENAME, TRAN_MODE: String;



FTPTransfered : Boolean; {전송완료 여부}



{WSAGetLastError함수에 의해 리턴된 에러번호에 해당하는 메시지를 구한다}

// function GetWinsockError(error: Integer):String;



function FTP_connect: Boolean;

function Send_HostFile(SendFile, RecvFile: String; BinFile: Boolean): Boolean;

end;



const

SEND_BYTE = (4096 - 1); {전송 버퍼의 크기}

RECV_BYTE = (4096 - 1); {수신 버퍼의 크기}

SERVER_PORT = 21; {FTP port}

ASYNC_TIMEOUT_SEC = 60; {default timeout}

TRANS_STEPBY = 5; {transfer step}



{ Macro = 'Indicate code' (FTP 서버의 respond message) }

C150 = '150'; {Opening data connection for xxxxxxxx.xxxx}

C200 = '200'; {일반명령어의 실행 성공}

C213 = '213'; {Fise Size}

C220 = '220'; {Service ready}

C226 = '226'; {Transfer complete}

C227 = '227'; {Entering Passive Mode (130,33,2,28,4,62)}

C250 = '250'; {DELE or RMD or CWD command successful}

C331 = '331'; {Password required for xxxx} {331 Anonymous access allowed, send identity (e-mail name) as password}

C230 = '230'; {User xxxx logged in}

C257 = '257'; {"xxxxxx" is current directory} {MKD command successful}

C350 = '350'; {File exists,ready for destination name}

C500 = '500'; {command not understood.}

C502 = '502'; {REST command not implemented.}

C530 = '530'; {Login incorrect}

C550 = '550'; {"xxxxxx": Permission denied.}

C553 = '553'; {"xxxxxx": Permission denied or Cannot rename to /c:/insa/bin/aaa/WHATSNEW.TXT}



var

FTPGetForm: TFTPGetForm;

ctrl_skt, Listen_skt, Data_skt: Tsocket;

Server_in, Local_In, Listen_in, Data_in: TSockAddrIn;

ReplyMsg : String; {reply message}

SendBuff : array[0..SEND_BYTE] of Char; {명령어 전송용 버퍼}

RecvBuff : array[0..RECV_BYTE] of Char; {메시지(응답) 수신용 버퍼}

Comd : TCommand;

RecvFileSize: LongInt;

trans_time, trans_bps: Real;



// select() 함수에서 사용하는 변수

Start_Time: Longint;

readfds, writefds: TFDSet;

readycomm: Integer;

timeval: TTimeVal;



implementation

{$R *.DFM}



function TFTPGetForm.FTP_connect: Boolean;

var

Address: DWord; // 이진의 네트워크 IP주소(4 bytes)

i: Integer;

begin

Result := False;

DOAddLine('Connecting to '+HOST_IP+' port '+IntToStr(SERVER_PORT));



// 인터넷의 IP주소를 의미하는 문자열은 네 개의 숫자와 그들을 구분하는 도트(".')

// 로 구성된다. 그래서 inet_addr은 그 문자열에 해당하는 네트워크 바이트 순서로

// 된 이진의 IP주소를 리턴한다(4 bytes).

Address := inet_addr(PChar(HOST_IP));

// inet_addr은 인자로 전달된 도트 표현의 IP주소에서 4개의 숫자 가운데

// 255를 넘는 값이 있다거나 기타 이유로 이진 IP주소로 변환될 수 없는

// 문제가 있는 문자열인 경우 INADDR_NONE 값을 리턴한다.

if Address = INADDR_NONE then

begin

DOAddLine('Connection failed '+HOST_IP);

DOAddLine('호스트를 알 수 없습니다. 호스트 주소를 확인하세요.');

System.Exit;

end;



// 서버연결을 위한 상대방의 주소 지정

with Server_in do

begin

FillChar(Server_in, SizeOf(Server_in), #0);

sin_family := PF_INET; // 주소 영역은 현재 PF_INET 뿐이다

sin_addr.s_addr := Address; // 이진의 IP주소(네트워크 바이트 순서의 4 bytes)

sin_port := htons(SERVER_PORT); // 네트워크 바이트 순서의 FTP port 번호(well-known port numer)

end;



{Control Connection port 21(ftpd)}

ctrl_skt := INVALID_SOCKET;

ctrl_skt := socket(PF_INET, SOCK_STREAM, 0); // PF_INET 주소 영역의 TCP 프로토콜을 사용

if ctrl_skt = INVALID_SOCKET then

begin

DOAddLine('Connection failed '+HOST_IP);

DOAddLine('통신오류: 소켓핸들을 얻을 수 없습니다.');

System.Exit;

end;



// 비동기 접속

asyncconnect(ctrl_skt, Server_in, ASYNC_TIMEOUT_SEC);



if BB_Stop.Tag = 1 then // 중지비튼을 눌렀다

begin

DOAddLine('Connection failed '+HOST_IP);

DOAddLine('중지버튼을 눌렀습니다.');

DOclosesocket(ctrl_skt);

System.Exit;

end

else if BB_Stop.Tag = 2 then // 연결시도중 에러발생

begin

DOAddLine('Connection failed '+HOST_IP);

DOAddLine('FTP서버에 연결을 못했습니다.');

DOclosesocket(ctrl_skt);

System.Exit;

end

else if BB_Stop.Tag <> 5 then

begin

DOAddLine('Connection failed '+HOST_IP);

DOAddLine('FTP서버에 연결을 못했습니다. (시간제한 초과)');

DOclosesocket(ctrl_skt);

System.Exit;

end;



BB_Stop.Tag := 0;

if GetReply then // Get banner

begin

// Intermediate 검사 (예, welcome banner)

// 응답의 4번째에 '-'문자를 넣어 comment 를 보내온다

// Intermediate인 경우는 다시 메시지를 받아야 한다

if Copy(ReplyMsg,4,1) = '-' then

GetReply;



if CompareStr(C220, Copy(ReplyMsg,1,3)) <> 0 then

begin

DOAddLine('Connection failed '+HOST_IP);

DOAddLine('FTP서버에 연결을 못했습니다.');

DOclosesocket(ctrl_skt);

System.Exit;

end;

end;

if BB_Stop.Tag <> 0 then

begin

DOAddLine('Connection failed '+HOST_IP);

DOclosesocket(ctrl_skt);

System.Exit;

end;



DOAddLine('Connected to '+HOST_IP+' port '+IntToStr(SERVER_PORT));



if ReplyMsg <> '' then

DOAddLine(ReplyMsg);



Comd := PUT_USER;

if not Send_Command('USER ' + USER_ID) then

begin

DOAddLine('Connection failed '+HOST_IP);

DOclosesocket(ctrl_skt);

System.Exit;

end;



if not Send_Command('TYPE '+TRAN_MODE) then

begin

DOAddLine('전송실패: TYPE 명령어를 실행할 수 없습니다');

DOclosesocket(ctrl_skt);

System.Exit;

end;



i := SizeOf(Local_in);

// GetSockname() 함수는 현재 소켓에 할당된 내쪽 주소(IP주소+포트번호)를 얻어내는 함수이다

// 이 함수는 bind()로 내쪽 주소를 지정하지 않고 connect()를 이용하여 연결이 이루어진 후

// TCP/IP 커널에 의해 할당된 내쪽 주소를 알아낼때 사용한다

// 만약 연결(connect)이 이루어지지 않은 상태에서 이 함수를 호출하면 내쪽 IP 주소가 할당되지

// 않기 때문에 INADDR_ANY에 해당하는 값의 주소가 리턴된다.

if GetSockname(ctrl_skt, Local_in, i) = SOCKET_ERROR then // Local_in 은 여기서 한번만 setting된다

begin

DOAddLine('통신오류: Packet Driver 에러로 로컬주소를 얻지못했습니다.');

DOclosesocket(ctrl_skt);

System.Exit;

end;



Send_HostFile(SEND_FILENAME, RECV_FILENAME, True);

if CompareStr(C226, Copy(ReplyMsg,1,3)) = 0 then // 226 = Transfer complete

Result := True;

end;



// 하나의 host file을 Local로 전송(SendFile, RecvFile은 full path로 지정되있다)

function TFTPGetForm.Send_HostFile(SendFile, RecvFile: String; BinFile: Boolean): Boolean;

var

OutF: file;

i, iNumRead, iNumWrite: Integer;

cnt, accum: Integer;

MsgBuf: array[0..RECV_BYTE] of Char; {전송 버퍼}

begin

Result := False; // 전송실패



{$I-}

FileMode := 1; {write Only}

AssignFile(OutF, RecvFile); // full path

ReWrite(OutF, 1); {Record Size 1(byte단위)}

{$I+}

if IOResult <> 0 then

begin

DOAddLine('로컬에 파일 '''+RecvFile+''' 를 만들 수 없습니다.');

System.CloseFile(OutF);

System.Exit;

end;



if GetFTPListenSocket = INVALID_SOCKET then {listen socket을 얻은후 "PORT"명령을 보내는 함수호출후 비교}

begin

System.CloseFile(OutF);

System.Exit;

end;



if PASSIVE_MODE then // passive mode

begin

// PASV 명령에의해 서버로 부터 할당받은 IP와 port번호로 직접 접속하여

// 자료를 가져온다(data_skt은 GetFTPListenSocket 에서 생성시켰음)



// 비동기 접속

asyncconnect(data_skt, Data_in, ASYNC_TIMEOUT_SEC);



if BB_Stop.Tag = 1 then // 중지비튼을 눌렀다

begin

System.CloseFile(OutF);

DOclosesocket(data_skt);

System.Exit;

end

else if BB_Stop.Tag = 2 then // 연결시도중 에러발생

begin

System.CloseFile(OutF);

DOAddLine('통신오류: 데이타를 수신할 수 없는 상태입니다.');

System.Exit;

end

else if BB_Stop.Tag = 3 then // Timeout

begin

System.CloseFile(OutF);

DOclosesocket(data_skt);

DOAddLine('통신오류: 데이타 수신이 지연됩니다.');

System.Exit;

end;



Comd := PUT_RETR; {파일size를 구한다}

if not Send_Command('RETR '+SendFile) then // full path

begin

System.CloseFile(OutF);

DoCloseSocket(data_skt);

if (BB_Stop.Tag = 1) and (CompareStr(C226, Copy(ReplyMsg,1,3)) <> 0) then // 226 = Transfer complete

begin

AbortCom;

end;

System.Exit;

end;



if Copy(ReplyMsg,1,1) = '5' then

begin

System.CloseFile(OutF);

DoCloseSocket(data_skt);

MessageDlg('서버에 실행파일이 없거나 사용할 수 없습니다',

mtInformation, [mbOk], 0);

Timer1.Enabled := True; // 약간 지연시킨후 종료

System.Exit;

end;



if RecvFileSize < 0 then

begin

System.CloseFile(OutF);

DoCloseSocket(data_skt);

System.Exit;

end;

end

else

begin

Comd := PUT_RETR; {파일size를 구한다}

if not Send_Command('RETR '+SendFile) then // full path

begin

DoCloseSocket(listen_skt);

System.CloseFile(OutF);

if (BB_Stop.Tag = 1) and (CompareStr(C226, Copy(ReplyMsg,1,3)) <> 0) then // 226 = Transfer complete

begin

AbortCom;

end;

System.Exit;

end;



if Copy(ReplyMsg,1,1) = '5' then

begin

System.CloseFile(OutF);

DoCloseSocket(data_skt);

MessageDlg('서버에 실행파일이 없거나 사용할 수 없습니다',

mtInformation, [mbOk], 0);

Timer1.Enabled := True; // 약간 지연시킨후 종료

System.Exit;

end;



if RecvFileSize < 0 then

begin

DoCloseSocket(listen_skt);

System.CloseFile(OutF);

System.Exit;

end;



asyncselect(listen_skt, True); // 두번째가 True인것은 지정한 소켓이 recv용 소켓임을 표시

if BB_Stop.Tag <> 0 then

begin

DoCloseSocket(listen_skt);

System.CloseFile(OutF);

if (BB_Stop.Tag = 1) and (CompareStr(C226, Copy(ReplyMsg,1,3)) <> 0) then // 226 = Transfer complete

begin

AbortCom;

end;

System.Exit;

end;



accum := SizeOf(Data_in);

Data_skt := accept(listen_skt, @Data_in, @accum); {listen socket에서 대기}

if Data_skt = INVALID_SOCKET then

begin

DoCloseSocket(listen_skt);

DoCloseSocket(Data_skt);

System.CloseFile(OutF);

System.Exit;

end;

DoCloseSocket(listen_skt); {data송수신시 Listen socket은 필요없으므로 닫는다}

end;



L_Rsize.Caption := '0/'+IntToStr(RecvFileSize div 1024)+' KB';



iNumRead := 0;

iNumWrite := 0;

accum := 0;

cnt := TRANS_STEPBY - 1;

trans_bps := 0;



while True do

begin

trans_time := GetTickCount; // 시작 TimeOut



asyncselect(Data_skt, True); // 두번째가 True인것은 지정한 소켓이 recv용 소켓임을 표시

if BB_Stop.Tag <> 0 then

begin

Break;

end;

iNumRead := recv(Data_skt, MsgBuf, SizeOf(MsgBuf), 0);



if iNumRead = SOCKET_ERROR then

begin

System.CloseFile(OutF);

DOAddLine('통신오류: 데이터를 받을 수 없습니다.');

System.Exit;

end;

if iNumRead <= 0 then

Break;

BlockWrite(OutF, MsgBuf, iNumRead, iNumWrite);

Inc(accum, iNumWrite);



trans_time := (GetTickCount - trans_time) / 1000; // 종료 TimeOut



if RecvFileSize > 0 then

begin

ProgressBar1.Position := (accum * 100) div RecvFileSize;

L_Rsize.Caption := IntToStr(accum div 1024)+'/'+IntToStr(RecvFileSize div 1024)+' KB';



if trans_time > 0 then

begin

Inc(cnt);

trans_bps := trans_bps + (iNumRead / trans_time);

if (cnt mod TRANS_STEPBY) = 0 then

begin

trans_bps := trans_bps / TRANS_STEPBY; // 평균을 구한다

if trans_bps > 1024 then

L_Speed.Caption := Format('at %.1f Kbps',[trans_bps / 1024])

else if trans_bps > 0 then

L_Speed.Caption := Format('at %.0f bps',[trans_bps]);

end;

end;

end;

Application.ProcessMessages;

if BB_Stop.Tag <> 0 then {Cancel이 click되면}

Break;

end; {while}



System.CloseFile(OutF);



if BB_Stop.Tag = 1 then // 중지이면 Abort 메시지를 보내서 data connection을 취소

begin

DoCloseSocket(Data_skt); {data control 소켓을 닫는다}

if CompareStr(C226, Copy(ReplyMsg,1,3)) <> 0 then // 226 = Transfer complete

begin

AbortCom;

end;

System.Exit;

end

else if BB_Stop.Tag = 2 then // 에러

begin

DOAddLine('통신오류: 데이타를 수신할 수 없는 상태입니다.');

system.Exit;

end;



ProgressBar1.Position := 100;

DoCloseSocket(Data_skt); {data control 소켓을 닫는다}



if CompareStr(C226, Copy(ReplyMsg,1,3)) <> 0 then // 226 = Transfer complete

if GetReply then

begin

if Copy(ReplyMsg,4,1) = '-' then

GetReply;

if ReplyMsg <> '' then

DOAddLine(ReplyMsg);

end;



Result := True;

end;



{Data Connection(listen socket을 얻는다)}

function TFTPGetForm.GetFTPListenSocket: TSocket;

var

i: Integer;

a, p: PChar; {a:address, p:port}



passiveIP: String;

PasvAddress: DWord; // 이진의 IP주소(4 bytes)

PasvPort: Word;

begin

// GetFTPListenSocket() 의 리턴값은 PASV 모드인 경우는 data_skt 을

// 그렇지 않으면 listen_skt 을 리턴한다



DOclosesocket(Listen_skt); {이전 소켓이 열려있을 수 있으므로 닫는다}

DOclosesocket(Data_skt);



Result := INVALID_SOCKET;



// Use PASV Mode

// PASV mode is supported as a firewall option.

// This feature simply reverses the connection between host and server,

// thus allowing many users that reside behind firewalls to use this program.

// PASV mode ftp is what most of the browsers like Netscape,

// and Microsoft use to initiate ftp transfers.

if PASSIVE_MODE then // PASV 모드

begin

Comd := GET_MESSAGE;

if not Send_Command('PASV') then {Use PASV Mode}

System.Exit;



if CompareStr(C227, Copy(ReplyMsg,1,3)) <> 0 then {C227 = "Entering Passive Mode (130,33,2,28,4,62)"}

begin

if ReplyMsg <> '' then

DOAddLine(ReplyMsg);

Result := INVALID_SOCKET;

end

else

begin

passiveIP := copy(ReplyMsg, pos('(', ReplyMsg) + 1, length(ReplyMsg));

passiveIP := copy(passiveIP, 1, pos(')', passiveIP) - 1); // passiveIP = "130,33,2,28,4,62"

// 인터넷의 IP주소를 의미하는 문자열은 네 개의 숫자와 그들을 구분하는 도트(".')

// 로 구성된다. 그래서 inet_addr은 그 문자열에 해당하는 네트워크 바이트 순서로

// 된 이진의 IP주소를 리턴한다(4 bytes).

PasvAddress := inet_addr(PChar(Get_Value(passiveIP,',',1)+'.'+

Get_Value(passiveIP,',',2)+'.'+

Get_Value(passiveIP,',',3)+'.'+

Get_Value(passiveIP,',',4)));

PasvPort := StrToIntDef(Get_Value(passiveIP,',',5),0) shl 8 +

StrToIntDef(Get_Value(passiveIP,',',6),0); // 네트워크 바이트 순서의 port 번호



Data_skt := socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

if Data_skt = INVALID_SOCKET then

begin

DOAddLine('통신오류: 데이터 소켓핸들을 얻을 수 없습니다.');

Result := INVALID_SOCKET;

System.Exit;

end;

Result := Data_skt;



// passive mode 에서는 data socket의 IP와 port 번호를 서버가 임의로

// 할당하므로 이를 이용하여 listen, accept하지 않고 바로 data socket으로

// connect하여 자료를 가져온다

with Data_in do

begin

FillChar(Data_in, SizeOf(Data_in), #0);

sin_family := PF_INET;

sin_addr.s_addr := PasvAddress; // 서버가 할당한 IP

sin_port := htons(PasvPort); // 서버가 할당한 port number (data port)

end;

end;

end

else // PORT 모드

begin

Listen_skt := socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

if Listen_skt = INVALID_SOCKET then

begin

DOAddLine('통신오류: 데이터 소켓핸들을 얻을 수 없습니다.');

Result := INVALID_SOCKET;

System.Exit;

end;



// 만일 IP주소가 INADDR_ANY 이면 실제 이 소켓이 사용될 때는 내 호스트가 연결된

// 여러 개의 네트워크 가운데 상대방 호스트에 따라 적합한 네트워크를 선택하고

// 그에 해당하는 주소로 바뀐다

with Listen_in do

begin

FillChar(Listen_in, SizeOf(Listen_in), #0);

sin_family := PF_INET;

sin_addr.s_addr := htonl(INADDR_ANY);

sin_port := htons(0);

end;



// bind()함수는 스트림 소켓과 데이터그램 소켓 등 양쪽 형태의 아직 연결이 되지 않은

// 소켓에 대해 connect()나 listen() 함수를 호출하기 이전에 내쪽의 주소(IP, port)

// 를 구체적으로 지정하기 위해 사용

if bind(Listen_skt, Listen_in, SizeOf(Listen_in)) = SOCKET_ERROR then

begin

DOAddLine('통신오류: 데이터 바인딩을 못했습니다.');

Result := INVALID_SOCKET;

System.Exit;

end;



i := SizeOf(Listen_in);

if getsockname(Listen_skt, Listen_in, i) < 0 then {내쪽의 주소(IP + port)를 알아낸다}

begin

DOAddLine('통신오류: 데이터 포트번호를 얻지 못했습니다.(data control)');

Result := INVALID_SOCKET;

System.Exit;

end;



// listen() 함수는 스트림 소켓의 TCP 상태를 LISTEN 상태, 즉 연결을 기다리는 상태로 만든다

// 따라서 listen()은 연결을 지원하는 스트림 소켓에만 적용되는 함수이다

if Listen(Listen_skt, 1) = SOCKET_ERROR then

begin

DOAddLine('통신오류: 데이터를 받을 수 없습니다.');

Result := INVALID_SOCKET;

System.Exit;

end;



{port번호를 생성하여 "PORT"명령을 송신하여 클라이언트의 receive 포트를 서버에 알린다}

a := PChar(@(Local_in.sin_addr)); {local IP address, login 시 구해놨음}

p := PChar(@(Listen_in.sin_port)); {listen socket(htons(0)에 의해 생성된 port}



Comd := PUT_PORT;

if not Send_Command(

Format('PORT %d,%d,%d,%d,%d,%d',[Byte(a[0]) and $00ff

,Byte(a[1]) and $00ff

,Byte(a[2]) and $00ff

,Byte(a[3]) and $00ff

,Byte(p[0]) and $00ff

,Byte(p[1]) and $00ff])) then

begin

DOclosesocket(Listen_skt);

DOclosesocket(Data_skt);

if BB_Stop.Tag = 1 then

begin

AbortCom;

end;

System.Exit;

end;



if CompareStr(C200, Copy(ReplyMsg,1,3)) <> 0 then {C200 = "200 PORT command successful."}

Result := INVALID_SOCKET

else

Result := Listen_skt;

end;

end;



function TFTPGetForm.AbortCom: Boolean;

begin

Result := False;

BB_Stop.Tag := 0;

Comd := GET_MESSAGE;

if not Send_Command('ABOR') then

begin

DOAddLine('transfer failed');

DOAddLine('전송이 취소되었습니다');

System.Exit;

end;

if GetReply then

begin

if Copy(ReplyMsg,4,1) = '-' then

GetReply;

if ReplyMsg <> '' then

DOAddLine(ReplyMsg);

end;

Result := True;

end;



{Command전송후 reply message를 처리

multiline 메시지수신(첫번째 message만 ReplyMsg변수에 받고 나머지는 삭제}

procedure TFTPGetForm.Process_ReplyMessage;

var

i, j: integer;

SubStr: String;

begin

if (ctrl_skt = SOCKET_ERROR) then

begin

BB_Stop.Tag := 2;

System.Exit;

end;



case Comd of {Comd 전역변수에는 현재 FTP명령어의 종류를 저장하고 있음}

PUT_USER:

begin

if ReplyMsg = '' then // 응답이 없었다면(가끔 proxy서버에서 발생) 다시 받는다

begin

if GetReply then // Get banner

begin

if Copy(ReplyMsg,4,1) = '-' then

GetReply;

end;

end;



if Copy(ReplyMsg,1,1) = '2' then {"230 User 사용자ID logged in."}

begin

DOAddLine(ReplyMsg);

end

else if Copy(ReplyMsg,1,1) = '3' then {"331 Password required for 사용자ID"}

begin

DOAddLine(ReplyMsg);

Comd := PUT_PASS;

if not Send_Command('PASS ' + PASSWORD) then {password전송}

begin

BB_Stop.Tag := 2;

System.Exit;

end;

end

else // 530 User ... Unknown

begin

if ReplyMsg <> '' then

DOAddLine(ReplyMsg);

DOAddLine('사용자ID가 틀립니다.');

BB_Stop.Tag := 2;

end;

end;

PUT_PASS:

begin

if Copy(ReplyMsg,1,1) = '2' then {"230 User 사용자ID logged in."}

begin

DOAddLine(ReplyMsg);

end

else if Copy(ReplyMsg,1,1) = '3' then {계정필요}

begin

DOAddLine(ReplyMsg);

Comd := PUT_ACCT;

if not Send_Command('ACCT '+USER_ID) then

begin

BB_Stop.Tag := 2;

System.Exit;

end;

end

else // 530 Login incorrect

begin

if ReplyMsg <> '' then

DOAddLine(ReplyMsg);

DOAddLine('사용자ID의 비밀번호가 틀립니다.');

BB_Stop.Tag := 2;

end;

end;

PUT_ACCT:

begin

if Copy(ReplyMsg,1,1) = '2' then {"230 User 사용자ID logged in."}

begin

DOAddLine(ReplyMsg);

end

else // 530 Login incorrect

begin

if ReplyMsg <> '' then

DOAddLine(ReplyMsg);

DOAddLine('사용자ID의 계정(Account)이 틀립니다.');

BB_Stop.Tag := 2;

end;

end;

PUT_PORT:

begin

if CompareStr(C200, Copy(ReplyMsg,1,3)) <> 0 then {C200 = "일반명령어의 실행 성공"}

DOclosesocket(Listen_skt);

if ReplyMsg <> '' then

DOAddLine(ReplyMsg);

end;

PUT_RETR:

begin

RecvFileSize := -1; // -1은 에러, 0은 파일 크기가 0인것을 의미

if ReplyMsg <> '' then

DOAddLine(ReplyMsg);

if CompareStr(C150, Copy(ReplyMsg,1,3)) = 0 then {C150 = "Opening data connection for xxxxxxxx.xxxx"}

begin

for i := Length(ReplyMsg) downto 1 do

if ReplyMsg[i] = '(' then

begin

ReplyMsg := Copy(ReplyMsg, i, MAX_PATH); // (99999) 만 뽑아낸다

Break;

end;



i := Pos('(', ReplyMsg); {메시지에서 Retrieve할 파일의 size를 추출}

if i > 0 then

begin

SubStr := '';

for j := i+1 to System.Length(ReplyMsg) do

if ReplyMsg[j] in ['0','1','2','3','4','5','6','7','8','9'] then

AppendStr(SubStr,ReplyMsg[j]);

RecvFileSize := StrToIntDef(SubStr, 0);

end

else

begin

// "150 Opening data connection for xxxx" 에 파일 사이즈를 안주는 서버가 있음

// 이때는 RecvFileSize 의 최대 크기를 주어 파일은 받게한다

RecvFileSize := High(RecvFileSize);

end;

end

else if CompareStr(C226, Copy(ReplyMsg,1,3)) = 0 then // 226 = Transfer complete

begin

// RETR 하자마자 "226 = Transfer complete" 이 오는것은 파일의 크기가 너무 작을때 발생한다

RecvFileSize := RECV_BYTE; // -1은 에러, 0은 파일 크기가 0인것을 의미

end;

end;

GET_MESSAGE:

begin

if ReplyMsg <> '' then

DOAddLine(ReplyMsg);

end;

PUT_QUIT: {program end}

begin

if ReplyMsg <> '' then

DOAddLine(ReplyMsg);

end;

end; {case}

end;



{FTP서버에 명령어 전송 프로시져}

function TFTPGetForm.Send_Command(cStr: String): Boolean;

begin

Result := False;

if ctrl_skt = INVALID_SOCKET then

begin

System.Exit;

end;



asyncselect(ctrl_skt, False); // 두번째가 False인것은 지정한 소켓이 send용 소켓임을 표시



if BB_Stop.Tag <> 0 then

begin

System.Exit;

end;



if Copy(cStr,1,4) = 'PASS' then

DOAddLine('PASS (hidden)') // password를 보여주지 않고 감춘다

else

DOAddLine(cStr);



FillChar(SendBuff, SizeOf(SendBuff), #0);

AppendStr(cStr, #13#10); {CR/LF문자 추가}

StrPcopy(SendBuff, cStr);



if Send(ctrl_skt, SendBuff, StrLen(SendBuff), 0) = SOCKET_ERROR then

begin

System.Exit;

end;



if GetReply then

begin

// Intermediate 검사 (예, welcome banner)

// 응답의 4번째에 '-'문자를 넣어 comment 를 보내온다

// Intermediate인 경우는 다시 메시지를 받아야 한다

if Copy(ReplyMsg,4,1) = '-' then

GetReply;

Process_ReplyMessage;

end;



if BB_Stop.Tag <> 0 then

begin

System.Exit;

end;



Result := True;

end;



{reply message를 메시지 listbox에 출력}

procedure TFTPGetForm.DOAddLine(str: String);

begin

CB_Message.ItemIndex := CB_Message.Items.Add(str);

Application.ProcessMessages;

end;



{FTP서버로 부터의 메시지를 받는 함수}

function TFTPGetForm.GetReply: Boolean;

var

i, iNumByte: Integer;

begin

// 복수 메시지일 경우 마지막 메시지를 응답으로 처리한다

ReplyMsg := '';



Result := False;

if ctrl_skt = INVALID_SOCKET then

begin

BB_Stop.Tag := 2;

System.Exit;

end;

if BB_Stop.Tag <> 0 then

begin

System.Exit;

end;



asyncselect(ctrl_skt, True); // 두번째가 True인것은 지정한 소켓이 recv용 소켓임을 표시

if BB_Stop.Tag <> 0 then

begin

System.Exit;

end;



FillChar(RecvBuff, SizeOf(RecvBuff), #0);

iNumByte := recv(ctrl_skt, RecvBuff, SizeOf(RecvBuff), 0);

if iNumByte = SOCKET_ERROR then

begin

BB_Stop.Tag := 2;

System.Exit;

end;



for i := 0 to iNumByte - 1 do

if (RecvBuff[i] = #0) or (RecvBuff[i] = #10) then {각 message의 구분문자}

begin

if i = (iNumByte - 1) then // 하나의 메시지만 있는경우

begin

Break;

end;



// * 마지막 메시지가 아닌것은 그냥 화면에 보여준다 *

// Intermediate 검사 (예, welcome banner)

// 응답의 4번째에 '-'문자를 넣어 comment 를 보내온다

// Intermediate인 경우는 다시 메시지를 받아야 한다

if Trim(ReplyMsg) <> '' then

DOAddLine(Trim(ReplyMsg));

ReplyMsg := '';

end

else

ReplyMsg := ReplyMsg + RecvBuff[i];



ReplyMsg := Trim(ReplyMsg); // 문자열에 #13(CR)이 포함될 수 있으므로 제거하는 의미에서 Trim 시킴

Result := True;

end;



{열려있는 모든 소켓을 닫는다}

procedure TFTPGetForm.AllCloseSocket;

begin

if ctrl_skt <> INVALID_SOCKET then

DOclosesocket(ctrl_skt);

if listen_skt <> INVALID_SOCKET then

DOclosesocket(listen_skt);

if Data_skt <> INVALID_SOCKET then

DOclosesocket(Data_skt);

end;



procedure TFTPGetForm.asyncselect(synsocket: Tsocket; readsock: Boolean);

// 이 함수는 원래 WSAAsyncSelect() 함수를 사용하여 비동기 원속 메시지를

// 처리하여야 하지만 이 프로그램에서는 BSD 계열의 소켓 함수인 select()

// 함수를 사용하여 비동기 처리를 하였습니다

begin

if readsock = True then // recv

FD_ZERO(readfds)

else

FD_ZERO(writefds);



// select() 함수는 BSD 계열의 소켓 함수(소켓함수는 크게 3가지로 분류하는데

// BSD 계열의 함수, 데이터베이스 함수, 원도우즈 지원함수로 분류) 로

// 지정된 하나 또는 여러 개의 소켓에 대해 수신된 데이터가 있는지,

// 송신이 가능한지, OOB(대역외 데이터) 가 수신되었는지를 체크하기 의한

// 폴링(polling)함수이다

// 함수의 리턴값은 select()가 성공적으로 이루어지면 리턴된 readfds,

// writefds, exceptfds 중에 어느 하나라도 지정된 동작이 가능한 소켓의

// 총 수가 리턴된다. 지정된 시간동안 어떤 소켓에 대해서도 지정한 동작의

// 가능성이 없었다면 select()는 0으로 곧바로 리턴한다. 만일 select()에 체크

// 하라고 지정한 스트림(stream) 소켓 중 하나라도 연결이 끊어진 상태라면

// select()는 SOCKET_ERROR 를 리턴하며 에러 코드가 설정된다



TimeVal.tv_sec := 0; // 대기시간 없음

TimeVal.tv_usec := 0;

readycomm := 0;



while True do

begin

Application.ProcessMessages; // 대기상태인동안 원도우즈의 메세지처리

if readsock = True then // recv

begin

FD_SET(synsocket, readfds);

readycomm := select(synsocket+1, @readfds, nil, nil, @TimeVal) // 0..synsocket까지의 socket 검사

end

else

begin

FD_SET(synsocket, writefds);

readycomm := select(synsocket+1, nil, @writefds, nil, @TimeVal);

end;



if BB_stop.Tag = 1 then {중지버튼 클릭}

System.Exit;



if (readycomm > 0) then // 지정된 동작을 할 수 있는 소켓의 갯수

begin

if (readsock = True) and (FD_ISSET(synsocket, readfds) = True) then

begin

BB_Stop.Tag := 0;

System.Exit;

end

else if (readsock = False) and (FD_ISSET(synsocket, writefds) = True) then

begin

BB_Stop.Tag := 0;

System.Exit;

end

end;

end;

end;



procedure TFTPGetForm.asyncconnect(synsocket: Tsocket; synsocket_in: TSockAddrIn; trytimes: Integer);

var

argp: Longint;

begin

// WSAAsyncSelect()은 네트워크 이벤트(FD_ACCEPT, FD_READ, FD_WRITE, FD_CLOSE...)중 하나라도 소켓에 발생했을때

// 지정된 원도우에 메시지를 보낸다. 이 함수를 호출하면 소켓은 자동적으로 Non-Blocking 모드로 바뀐다.

// 이 메시지의 wParam에는 소켓이, lParam의 하위 16비트에는 발생한 이벤트, 상위 16비트에는 에러코드가

// 저장된다.

// 여러개의 네트워크 이벤트가 동시에 발생했다면, 원도우는 각 이벤트에 대하여 각각의 메시지를 받게 된다

WSAAsyncSelect(synsocket, Self.Handle, WM_CONNECT_MSG, FD_CONNECT);



Start_Time := GetTickCount; // 시작 TimeOut

if Connect(synsocket, synsocket_in, sizeof(synsocket_in)) = SOCKET_ERROR then

if WSAGetLastError <> WSAEWOULDBLOCK then

begin

BB_Stop.Tag := 2;

System.Exit;

end;



repeat

Application.ProcessMessages; {allowing access to other controls, etc.}

if BB_Stop.Tag <> 0 then // 중지비튼을 눌렀거나 연결되거나 에러발생(BB_Stop.Tag의 값은 AppMessage에서 바꿈)

Break;

until ((GetTickCount-Start_Time) >= Longint(trytimes * 1000)); // TimeOut 검사



if (BB_Stop.Tag <> 1) and (BB_Stop.Tag <> 2) and (BB_Stop.Tag <> 5) then // 에러나 연결이 아니면 시간초과

begin

BB_Stop.Tag := 3;

System.Exit;

end;



// WSAAsyncSelect()함수를 호출하면 소켓은 자동적으로 Non-Blocking 모드로 바뀌는데

// 이를 Blocking모드로 다시 변경한다

// 소켓을 Blocking 모드로 다시 전환하기 위해서는 먼저 WSAAsyncSelect()의 lEvent 인자를 0으로

// 하여 호출하고 ioctlsocket() 함수를 호출해야 한다

WSAAsyncSelect(synsocket, Self.Handle, 0, 0);

argp := 0; // Non-Blocking 모드 해제

ioctlsocket(synsocket, FIONBIO, argp);

end;



procedure TFTPGetForm.ConnectMessage(var Msg: TMessage);

begin

if (WSAGetSelectEvent(Msg.lParam) = FD_CONNECT) and // 이전에 요청한 연결이 이루어짐

(WSAGetSelectError(Msg.lParam) = 0) // 상위 16비트에는 에러코드가 있음

then

BB_Stop.Tag := 5 // 0:초기/정상, 1:중지, 2:에러, 5:연결

else

BB_Stop.Tag := 2;

end;



{parameter로 지정한 소켓을 강제로 즉시 닫는다(블록킹 해제됨)}

procedure TFTPGetForm.DOclosesocket(var socket_id: TSocket);

begin

// 블록킹(blocking)된 소켓함수가 있다면 이를 취소시킨다

// 어느 경우에나 WSACancelBlockingCall() 이 호출되면 Block이 진행 중이던

// 원래의 함수는 에러로 리턴하고, 이 때 에러 코드는 WSAEINTR이 된다

// 이식성이 높은 응용 프로그램을 개발하기 위하여 WSACancelBlockingCall() 후에

// closesocket() 이외의 다른 소켓 함수 호출은 하지 않는 것이 좋다.

if socket_id <> INVALID_SOCKET then

if WSAISBlocking then // 어떤 소켓 함수가 Block 상태에 있는 가를 검사

begin

WSACancelBlockingCall;

DOAddLine('Cancelled blocking call');

end;



CloseSocket(socket_id);

socket_id := INVALID_SOCKET;

end;



{cSpr 문자로 분리된 문자열에서 nPos번째 문자열을 return}

function TFTPGetForm.Get_Value(Str, cSpr:String; nPos: Integer): String;

var

i, j, cnt: Integer;

begin

if Pos(cSpr, Str) = 0 then

begin

Result := Str;

System.Exit;

end;



i := 1;

j := 1;

cnt := 1; {cSpr 문자 갯수}

while i <= Length(Str) do

begin

if Str[i] = cSpr then

begin

if cnt = nPos then

begin

Result := Copy(Str, j, i - j);

System.Exit;

end;

Inc(cnt);

j := i + 1;

end;

Inc(i);

end;



if nPos = cnt then {맨 마지막 문자열을 원했을때}

Result := Copy(Str, j, i - j + 1)

else

Result := ''; {해당값 없음}

end;



procedure TFTPGetForm.FormActivate(Sender: TObject);

var

ImsiFile: String;

begin

ImsiFile := ExtractFilePath(RECV_FILENAME)+

Copy(ExtractFileName(RECV_FILENAME),1,Pos('.',ExtractFileName(RECV_FILENAME))-1)+'.bak';

if FileExists(RECV_FILENAME) or FileExists(ImsiFile) then // 해당파일이나 backup파일이 있다면 Update!

Image_update.Visible := True

else

Image_new.Visible := True;



Application.ProcessMessages;

BB_Stop.Tag := 0;

BB_Stop.Caption := '중지(&C)';



ProgressBar1.Position := 0;

L_Rsize.Caption := '';

CB_Message.Items.Clear;

Application.ProcessMessages;



FTPTransfered := FTP_connect;

Application.ProcessMessages;

AllCloseSocket;

BB_Stop.caption := '닫기(&C)';



if FTPTransfered then // 전송완료

begin

Timer1.Enabled := True; // 약간 지연시킨후 종료

end;

end;



procedure TFTPGetForm.BB_StopClick(Sender: TObject);

begin

BB_Stop.Tag := 1;

Application.ProcessMessages;

Close;

end;



procedure TFTPGetForm.Timer1Timer(Sender: TObject);

begin

Timer1.Enabled := False;

Close;

end;



procedure TFTPGetForm.FormCloseQuery(Sender: TObject;

var CanClose: Boolean);

begin

Image_update.Visible := False;

Image_new.Visible := False;

CanClose := True;

end;



end.

1  COMMENTS
  • Profile
    오태양 2000.12.20 16:57
    안냐세염.. 델초보에영. ㅜ.ㅜ

    이거 ftp관련댄게 데모에 이뜨라구여. 그래서 일케 쓰는데 분석은 못하구여--;;

    여기 업로드 기능 이뜨라구여. 그거 보시구 하믄 대겐네여 ^^;



    아공 위치는 C:Program FilesBolandDelphi5DemosFastNetFtp 네요.



    구럼 도움이 되시길 간절히 바라면서 ㅜ.ㅜ 초보는 물러갑니당...



    ///////////////////////////////////////////////////////////////////////////

    // //

    // Copyright ?1997-1998, NetMasters, L.L.C //

    // - All rights reserved worldwide. - //

    // Portions may be Copyright ?Inprise. //

    // //

    // FTP Demo Unit 1 : (UNIT1.PAS) //

    // //

    // DESCRIPTION: //

    // //

    // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY //

    // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE //

    // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR //

    // PURPOSE. //

    // //

    ///////////////////////////////////////////////////////////////////////////

    //

    // Revision History

    //

    // //

    ///////////////////////////////////////////////////////////////////////////

    unit FTPDem;



    interface



    uses

    Windows, Messages, SysUtils, Classes, Graphics, Forms, Dialogs,

    ComCtrls, StdCtrls, Psock, NMFtp, Controls;



    type

    TForm1 = class(TForm)

    PageControl1: TPageControl;

    TabSheet1: TTabSheet;

    TabSheet2: TTabSheet;

    TabSheet3: TTabSheet;

    TabSheet4: TTabSheet;

    HostTxt: TEdit;

    PortTxt: TEdit;

    Label1: TLabel;

    Label2: TLabel;

    Button1: TButton;

    Button2: TButton;

    StatusBar1: TStatusBar;

    Memo1: TMemo;

    Button3: TButton;

    Button4: TButton;

    NMFTP1: TNMFTP;

    UserTxt: TEdit;

    Label3: TLabel;

    PassTxt: TEdit;

    Label4: TLabel;

    DirTxt: TEdit;

    Label5: TLabel;

    Label6: TLabel;

    Button5: TButton;

    RemoteTxt: TEdit;

    Label7: TLabel;

    LocalTxt: TEdit;

    Label8: TLabel;

    Button6: TButton;

    Button7: TButton;

    TabSheet6: TTabSheet;

    Edit3: TEdit;

    Label11: TLabel;

    Label12: TLabel;

    Edit4: TEdit;

    Button10: TButton;

    Button11: TButton;

    Button8: TButton;

    Button9: TButton;

    Button12: TButton;

    Button13: TButton;

    PosTxt: TEdit;

    Label9: TLabel;

    TabSheet5: TTabSheet;

    Edit1: TEdit;

    Label10: TLabel;

    Edit2: TEdit;

    Label13: TLabel;

    Button14: TButton;

    Button15: TButton;

    TabSheet7: TTabSheet;

    Edit5: TEdit;

    Label14: TLabel;

    Button16: TButton;

    TabSheet8: TTabSheet;

    Button17: TButton;

    Label15: TLabel;

    CheckBox1: TCheckBox;

    Edit6: TEdit;

    Edit7: TEdit;

    Label16: TLabel;

    Label17: TLabel;

    TabSheet9: TTabSheet;

    Edit8: TEdit;

    Edit9: TEdit;

    Label18: TLabel;

    Label19: TLabel;

    Button18: TButton;

    procedure NMFTP1Success(Trans_Type: TCmdType);

    procedure Button1Click(Sender: TObject);

    procedure Button2Click(Sender: TObject);

    procedure Button3Click(Sender: TObject);

    procedure Button4Click(Sender: TObject);

    procedure NMFTP1ListItem(Listing: String);

    procedure TabSheet3MouseMove(Sender: TObject; Shift: TShiftState; X,

    Y: Integer);

    procedure Button5Click(Sender: TObject);

    procedure Button8Click(Sender: TObject);

    procedure NMFTP1PacketRecvd(Sender: TObject);

    procedure Button7Click(Sender: TObject);

    procedure Button10Click(Sender: TObject);

    procedure Button11Click(Sender: TObject);

    procedure Button12Click(Sender: TObject);

    procedure Button13Click(Sender: TObject);

    procedure Button6Click(Sender: TObject);

    procedure Button14Click(Sender: TObject);

    procedure Button15Click(Sender: TObject);

    procedure Button16Click(Sender: TObject);

    procedure Button17Click(Sender: TObject);

    procedure NMFTP1Connect(Sender: TObject);

    procedure NMFTP1Failure(var handled: Boolean; Trans_Type: TCmdType);

    procedure NMFTP1TransactionStop(Sender: TObject);

    procedure NMFTP1HostResolved(Sender: TComponent);

    procedure NMFTP1InvalidHost(var handled: Boolean);

    procedure NMFTP1PacketSent(Sender: TObject);

    procedure NMFTP1TransactionStart(Sender: TObject);

    procedure NMFTP1Disconnect(Sender: TObject);

    procedure NMFTP1Error(Sender: TComponent; Errno: Word; Errmsg: String);

    procedure NMFTP1Status(Sender: TComponent; Status: String);

    procedure Button18Click(Sender: TObject);

    procedure NMFTP1UnSupportedFunction(Trans_Type: TCmdType);

    procedure NMFTP1ConnectionFailed(Sender: TObject);

    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);

    private

    { Private declarations }

    public

    { Public declarations }

    end;



    var

    Form1: TForm1;



    implementation



    {$R *.DFM}



    var

    Q: Integer;



    procedure TForm1.NMFTP1Success(Trans_Type: TCmdType);

    begin

    Case Trans_Type of

    cmdChangeDir: StatusBar1.SimpleText := 'ChangeDir success';

    cmdMakeDir: StatusBar1.SimpleText := 'MakeDir success';

    cmdDelete: StatusBar1.SimpleText := 'Delete success';

    cmdRemoveDir: StatusBar1.SimpleText := 'RemoveDir success';

    cmdList: StatusBar1.SimpleText := 'List success';

    cmdRename: StatusBar1.SimpleText := 'Rename success';

    cmdUpRestore: StatusBar1.SimpleText := 'UploadRestore success';

    cmdDownRestore: StatusBar1.SimpleText := 'DownloadRestore success';

    cmdDownload: StatusBar1.SimpleText := 'Download success';

    cmdUpload: StatusBar1.SimpleText := 'Upload success';

    cmdAppend: StatusBar1.SimpleText := 'UploadAppend success';

    cmdReInit: StatusBar1.SimpleText := 'ReInit success';

    cmdAllocate: StatusBar1.SimpleText := 'Allocate success';

    cmdNList: StatusBar1.SimpleText := 'NList success';

    cmdDoCommand: StatusBar1.SimpleText := 'DoCommand success';

    end;

    end;



    procedure TForm1.Button1Click(Sender: TObject);

    begin

    If CheckBox1.Checked then

    Begin

    NMFTP1.Proxy := Edit6.Text;

    NMFTP1.ProxyPort := StrToInt(Edit7.Text);

    End;

    NMFTP1.Host := HostTxt.Text;

    NMFTP1.Port := StrToInt(PortTxt.Text);

    NMFTP1.Timeout := 5000;

    NMFTP1.UserID := UserTxt.Text;

    NMFTP1.Password := PassTxt.Text;

    try

    NMFTP1.Connect;

    except

    On E:Exception do

    writeln(E.message);

    end

    end;



    procedure TForm1.Button2Click(Sender: TObject);

    begin

    NMFTP1.Disconnect;

    end;



    procedure TForm1.Button3Click(Sender: TObject);

    begin

    Q := 1;

    try NMFTP1.Nlist; except end;

    end;



    procedure TForm1.Button4Click(Sender: TObject);

    begin

    Q := 1;

    try NMFTP1.List; except end;

    end;



    procedure TForm1.NMFTP1ListItem(Listing: String);

    begin

    Memo1.Lines.Add(IntToStr(Q)+': '+Listing);

    Inc(Q);

    end;



    procedure TForm1.TabSheet3MouseMove(Sender: TObject; Shift: TShiftState; X,

    Y: Integer);

    begin

    Label5.Caption := 'Current Dir: ';

    end;



    procedure TForm1.Button5Click(Sender: TObject);

    begin

    NMFTP1.ChangeDir(DirTxt.Text);

    end;



    procedure TForm1.Button8Click(Sender: TObject);

    begin

    NMFTP1.DownloadRestore(RemoteTxt.Text, LocalTxt.Text);

    end;



    procedure TForm1.NMFTP1PacketRecvd(Sender: TObject);

    begin

    StatusBar1.SimpleText := IntToStr(NMFTP1.BytesRecvd)+' of '+IntToStr(NMFTP1.BytesTotal);

    end;



    procedure TForm1.Button7Click(Sender: TObject);

    begin

    NMFTP1.Abort;

    end;





    procedure TForm1.Button10Click(Sender: TObject);

    begin

    try NMFTP1.Upload(Edit3.Text, Edit4.Text); except end;

    end;





    procedure TForm1.Button11Click(Sender: TObject);

    begin

    try NMFTP1.UploadAppend(Edit3.Text, Edit4.Text); except end;

    end;



    procedure TForm1.Button12Click(Sender: TObject);

    begin

    try NMFTP1.UploadUnique(Edit3.Text); except end;

    end;



    procedure TForm1.Button13Click(Sender: TObject);

    begin

    try NMFTP1.UploadRestore(Edit3.Text,Edit4.Text,StrToInt(PosTxt.Text)); except end;

    end;



    procedure TForm1.Button6Click(Sender: TObject);

    begin

    try NMFTP1.Download(RemoteTxt.Text, LocalTxt.Text); except end;

    end;



    procedure TForm1.Button14Click(Sender: TObject);

    begin

    NMFTP1.MakeDirectory(Edit1.Text);

    end;



    procedure TForm1.Button15Click(Sender: TObject);

    begin

    NMFTP1.RemoveDir(Edit2.Text);

    end;



    procedure TForm1.Button16Click(Sender: TObject);

    begin

    NMFTP1.Delete(Edit5.Text);

    end;



    procedure TForm1.Button17Click(Sender: TObject);

    begin

    NMFTP1.Reinitialize;

    PageControl1.ActivePage := TabSheet2;

    end;



    procedure TForm1.NMFTP1Connect(Sender: TObject);

    begin

    StatusBar1.SimpleText := 'Connected';

    end;



    procedure TForm1.NMFTP1Failure(var handled: Boolean; Trans_Type: TCmdType);

    begin

    Case Trans_Type of

    cmdChangeDir: StatusBar1.SimpleText := 'ChangeDir failure';

    cmdMakeDir: StatusBar1.SimpleText := 'MakeDir failure';

    cmdDelete: StatusBar1.SimpleText := 'Delete failure';

    cmdRemoveDir: StatusBar1.SimpleText := 'RemoveDir failure';

    cmdList: StatusBar1.SimpleText := 'List failure';

    cmdRename: StatusBar1.SimpleText := 'Rename failure';

    cmdUpRestore: StatusBar1.SimpleText := 'UploadRestore failure';

    cmdDownRestore: StatusBar1.SimpleText := 'DownloadRestore failure';

    cmdDownload: StatusBar1.SimpleText := 'Download failure';

    cmdUpload: StatusBar1.SimpleText := 'Upload failure';

    cmdAppend: StatusBar1.SimpleText := 'UploadAppend failure';

    cmdReInit: StatusBar1.SimpleText := 'ReInit failure';

    cmdAllocate: StatusBar1.SimpleText := 'Allocate failure';

    cmdNList: StatusBar1.SimpleText := 'NList failure';

    cmdDoCommand: StatusBar1.SimpleText := 'DoCommand failure';

    end;

    end;



    procedure TForm1.NMFTP1TransactionStop(Sender: TObject);

    begin

    StatusBar1.SimpleText := 'Data Transfer Complete';

    end;



    procedure TForm1.NMFTP1HostResolved(Sender: TComponent);

    begin

    StatusBar1.SimpleText := 'Host resolved';

    end;



    procedure TForm1.NMFTP1InvalidHost(var handled: Boolean);

    begin

    ShowMessage('Invalid Host');

    end;



    procedure TForm1.NMFTP1PacketSent(Sender: TObject);

    begin

    StatusBar1.SimpleText := IntToStr(NMFTP1.BytesSent)+' of '+IntToStr(NMFTP1.BytesTotal);

    end;



    procedure TForm1.NMFTP1TransactionStart(Sender: TObject);

    begin

    StatusBar1.SimpleText := 'Beginning Data Transfer';

    end;



    procedure TForm1.NMFTP1Disconnect(Sender: TObject);

    begin

    If StatusBar1 <> nil then

    StatusBar1.SimpleText := 'Disconnected';

    end;



    procedure TForm1.NMFTP1Error(Sender: TComponent; Errno: Word;

    Errmsg: String);

    begin

    ShowMessage('Error '+IntToStr(Errno)+': '+Errmsg);

    end;



    procedure TForm1.NMFTP1Status(Sender: TComponent; Status: String);

    begin

    // If StatusBar1 <> nil then

    // StatusBar1.SimpleText := status;

    end;



    procedure TForm1.Button18Click(Sender: TObject);

    begin

    NMFTP1.Rename(Edit8.Text,Edit9.Text);

    end;



    procedure TForm1.NMFTP1UnSupportedFunction(Trans_Type: TCmdType);

    begin

    Case Trans_Type of

    cmdChangeDir: ShowMessage('ChangeDir unsupported');

    cmdMakeDir: ShowMessage('MakeDir unsupported');

    cmdDelete: ShowMessage('Delete unsupported');

    cmdRemoveDir: ShowMessage('RemoveDir unsupported');

    cmdList: ShowMessage('List unsupported');

    cmdRename: ShowMessage('Rename unsupported');

    cmdUpRestore: ShowMessage('UploadRestore unsupported');

    cmdDownRestore: ShowMessage('DownloadRestore unsupported');

    cmdDownload: ShowMessage('Download unsupported');

    cmdUpload: ShowMessage('Upload unsupported');

    cmdAppend: ShowMessage('UploadAppend unsupported');

    cmdReInit: ShowMessage('ReInit unsupported');

    cmdAllocate: ShowMessage('Allocate unsupported');

    cmdNList: ShowMessage('NList unsupported');

    cmdDoCommand: ShowMessage('DoCommand unsupported');

    end;

    end;



    procedure TForm1.NMFTP1ConnectionFailed(Sender: TObject);

    begin

    ShowMessage('Connection Failed');

    end;



    procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);

    begin

    NMFTP1.Abort;

    end;



    end.