Code archives/Networking/FTP Client
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
Unfortunately far from complete or clean, but it's working on both Mac and win32. It shouldn't be hard to extend this to all possible FTP commands, but these were basically the one that I needed. Everything happens in main, remember to change the credentials before using. | |||||
Strict ' http://tools.ietf.org/html/rfc959 Global Server_Host:String Global Server_IP:Int Global Server_Port:Int Global Server_User:String Global Server_pwd:String Global Server_Socket:TSocket Global Server_SocketStream:TSocketStream Global Server_Stream:TStream Global isConnected:Int = False Global isAborting:Int = False Global pasvPort:Int Global currentLine:String Function message(s:String) Print s EndFunction Function messageOut(s:String) message "OUT: " + s EndFunction Function messageIn(s:String) message "IN: " + s EndFunction Function messageSys(s:String) message "SYS: " + s EndFunction Function messageDebug(s:String) message "DBG: " + s EndFunction Function writeToServer(line:String) If Server_Stream And SocketConnected(Server_Socket) messageOut line WriteLine(Server_Stream, line) Else message "You are not connected yet" EndIf EndFunction Function receiveLineFromServer:String() ' time in milliseconds until timeout Local threshold:Int = 3000 Local start:Int = MilliSecs() Local now:Int = 0 Local data:String If Server_Stream And SocketConnected(Server_Socket) While Not SocketReadAvail(Server_Socket) And ( (now - start) < threshold ) now = MilliSecs() Wend If (now - start) < threshold If SocketReadAvail(Server_Socket)>0 data = ReadLine(Server_Stream) EndIf If(data<>"") messageIn data currentLine = data Return ""+data EndIf Else messageSys "TIMEOUT in receiveLineFromServer" isAborting = True EndIf EndIf EndFunction Function send:String(s:String) writeToServer(s) Return receiveLineFromServer() EndFunction Function getDataAsText(p:Int) Local dataSocket:TSocket = CreateTCPSocket() Local dataSocketStream:TSocketStream Local dataStream:TStream messageDebug "trying to transfer some text on port " + String(p) If ConnectSocket( dataSocket, Server_IP, p) dataSocketStream = CreateSocketStream(dataSocket, True) dataStream = OpenStream(dataSocketStream) If dataStream While Not Eof(dataStream) messageSys ReadLine(dataStream) Wend messageDebug "transferring some text" CloseStream(dataStream) Else messageSys "stream failed" EndIf CloseSocket(dataSocket) Else messageSys "socket failed" EndIf EndFunction Function getDataAsFile(p:Int, filename:String) Local dataSocket:TSocket = CreateTCPSocket() Local dataSocketStream:TSocketStream Local dataStream:TStream Local fileStream:TStream messageSys "trying to receive some data on port " + String(p) If ConnectSocket( dataSocket, Server_IP, p) dataSocketStream = CreateSocketStream(dataSocket, True) dataStream = OpenStream(dataSocketStream) If dataStream fileStream=WriteStream(filename) CopyStream(dataSocketStream,fileStream) messageSys "succesfully received file "+filename Else messageSys "stream failed" EndIf Else messageSys "socket failed" EndIf EndFunction Function sendDataAsFile(p:Int, filename:String) Local dataSocket:TSocket = CreateTCPSocket() Local dataSocketStream:TSocketStream Local dataStream:TStream Local fileStream:TStream messageSys "trying to send some data on port " + String(p) If ConnectSocket( dataSocket, Server_IP, p) dataSocketStream = CreateSocketStream(dataSocket, True) dataStream = OpenStream(dataSocketStream) If dataStream fileStream=ReadStream(filename) CopyStream(fileStream, dataSocketStream) messageSys "succesfully transfered file "+filename Else messageSys "stream failed" EndIf Else messageSys "socket failed" EndIf EndFunction Function _stringSplit:String[](text:String, separator:String) Local splitArray:String[] Local fieldCount:Int = 1 ' how many elements ? Local loc:Int = text.find(separator) While loc >= 0 loc = text.find(separator, loc + 1) fieldCount:+1 Wend ' set the array with the calculated size splitArray = New String[fieldCount] fieldcount = 0 While True loc = text.find(separator) If loc >= 0 Then splitArray[fieldCount] = text[..loc] text = text[loc+1..] Else splitArray[fieldCount] = text Exit End If fieldCount:+1 Wend Return splitArray End Function Function getPort(tempStr:String) Local tempArray:String[] tempArray = _stringSplit(tempStr, "(" ) tempStr = tempArray[Len(tempArray) - 1] tempStr= tempStr[0..Len(tempStr)-1] tempArray= _stringSplit(tempStr, "," ) Return Int(tempArray[Len(tempArray) - 2])*256 + Int(tempArray[Len(tempArray) - 1]) EndFunction Function checkResult(s:String) If s = "331" And currentLine[0..Len(s)] = "220" ' if we dont look for 220, get the rest of them While currentLine[0..Len(s)] = "220" messageDebug "receiving more to get rid of the 220's" receiveLineFromServer() Wend EndIf If currentLine[0..Len(s)] <> s messageDebug "check ("+s+") is wrong, got "+currentLine[0..Len(s)]+" ...aborting" isAborting = True Else messageDebug "check is ok ("+s+")." isAborting = False EndIf EndFunction Function sendQuit() send("quit") EndFunction Function sendCwd(foldername:String) If Not isAborting send("cwd "+foldername) checkResult("250") Else messageDebug "... aborting sendCwd "+foldername EndIf EndFunction Function sendRename(oldFilename:String, newFilename:String) If Not isAborting send("rnfr "+oldFilename) checkResult("350") Else messageDebug "... aborting sendRename "+oldFilename EndIf If Not isAborting send("rnto "+newFilename) checkResult("250") Else messageDebug "... aborting sendRename "+newFilename EndIf EndFunction Function sendCredentials() If Not isAborting send("user " + Server_User) checkResult("331") send("pass " + Server_pwd) checkResult("230") send("type i") checkResult("200") Else messageDebug "... aborting sendCredentials" EndIf EndFunction Function sendList() If Not isAborting pasvPort = getPort(send("pasv")) checkResult("227") writeToServer("list") getDataAsText(pasvPort) receiveLineFromServer() checkResult("150") receiveLineFromServer checkResult("226") Else messageDebug "... aborting sendlist" EndIf EndFunction Function sendGetData(filename:String) If Not isAborting pasvPort = getPort(send("pasv")) checkResult("227") writeToServer("retr "+filename) getDataAsFile(pasvPort, filename) receiveLineFromServer() checkResult("150") receiveLineFromServer checkResult("226") Else messageDebug "... aborting sendgetdata" EndIf EndFunction Function sendStoreData(filename:String) If Not isAborting pasvPort = getPort(send("pasv")) checkResult("227") writeToServer("stor "+filename) sendDataAsFile(pasvPort, filename) receiveLineFromServer() checkResult("150") receiveLineFromServer checkResult("226") Else messageDebug "... aborting sendstoredata" EndIf EndFunction Function main() ' CHANGE THIS! Server_Host = "localhost" Server_IP = HostIp(Server_Host) Server_Port = 21 Server_User = "user" Server_pwd = "password" If Server_IP = 0 messageSys "could not resolve servername ... are you online??" EndIf If Server_Stream CloseStream(Server_SocketStream) If Server_Socket CloseSocket(Server_Socket) Server_Socket = CreateTCPSocket() If ConnectSocket( Server_Socket, Server_IP, Server_Port) Server_SocketStream = CreateSocketStream(Server_Socket, True) Server_Stream = OpenStream(Server_SocketStream) messageSys "connect ok" isConnected = True receiveLineFromServer() checkResult("220") Else message "couldnt connect to " + Server_Host isConnected = False EndIf If isConnected sendCredentials() sendList() sendCwd("files") sendRename("ddd.mp3", "ccc.mp3") sendRename("ccc.mp3", "ddd.mp3") sendList() sendGetData("ddd.mp3") sendStoreData("test.mp3") sendQuit() EndIf EndFunction main |
Comments
| ||
Thanks for this, very handy. There were some differences on my server that meant I had to change sendList() to this:Function sendList%() If Not isAborting pasvPort = getPort(send("pasv")) checkResult("227") writeToServer("list") getDataAsText(pasvPort) receiveLineFromServer() checkResult("150") receiveLineFromServer checkResult("226") receiveLineFromServer checkResult("226") Return 1 Else messageDebug "... aborting sendlist" Return 0 EndIf EndFunction Basically it has to receive TWO lots of 226. Also sendStoreData() was failing for two reasons: 1) It calls sendDataAsFile which was not closing the socket, and so my server never sent the 226 success messages. So I changed it to this: Local dataSocket:TSocket = CreateTCPSocket() Local dataSocketStream:TSocketStream Local dataStream:TStream Local fileStream:TStream messageSys "trying to send some data on port " + String(p) If ConnectSocket( dataSocket, Server_IP, p) dataSocketStream = CreateSocketStream(dataSocket, True) dataStream = OpenStream(dataSocketStream) If dataStream fileStream=ReadStream(filename) CopyStream(fileStream, dataSocketStream) messageSys "succesfully transfered file "+filename Else messageSys "stream failed" EndIf CloseSocket(dataSocket) Else messageSys "socket failed" EndIf 2) It needs to receive TWO lots 226 as follows: Function sendStoreData(filename:String) If Not isAborting pasvPort = getPort(send("pasv")) checkResult("227") writeToServer("stor "+filename) sendDataAsFile(pasvPort, filename) receiveLineFromServer() checkResult("150") receiveLineFromServer checkResult("226") receiveLineFromServer checkResult("226") Else messageDebug "... aborting sendstoredata" EndIf EndFunction Possibly other things are broken on my server too but I didn't test sendRename() or GetData() (which uses getDataAsFile() and that doesn't have a CloseSocket either, but I think maybe it's supposed to). |
| ||
A real newby question here. Will these functions do Uploading and Downloading of files like the FTP functions for BB did? If this is the case then I am a lot nearer rewriting my game in BMax. |
Code Archives Forum