FTP for all PB OS's

Share your advanced PureBasic knowledge/code with the community.
TerryHough
Enthusiast
Enthusiast
Posts: 781
Joined: Fri Apr 25, 2003 6:51 pm
Location: NC, USA
Contact:

Post by TerryHough »

@Num3
Num3 wrote:It works with many servers i've tested with, but i can assume it will fail on some :(
:lol: Yes, even the FTP specifications (RFC-959) mentions that the server
environment has a lot to do with successful transfers.

Thanks for posting the source code for your library so it was available to
use as an include file. That made it possible to resolve my issues and
that could have never happened with just a library.

I believe that I have "touched" all of your Procedures (except one) in some
manner while resolving my failures. Now I can use these procedures to
work successfully with the two major FTP servers I frequently use.

Most of my changes were to recognize responses from these servers
that weren't already handled in your Procedures. Without handling for
those responses, my uploads and downloads were timing out without
notice, failing completely, or just returning without a response code.

So, now I can happily re-write a FTP program and replace the embedded
WinAPI calls and add some more functionality at the same time. :D

Thanks again,
Terry
naw
Enthusiast
Enthusiast
Posts: 573
Joined: Fri Apr 25, 2003 4:57 pm

Post by naw »

@TerryHough

Any chance of you posting those updates back onto the forum, I have some probs too...
Ta - N
TerryHough
Enthusiast
Enthusiast
Posts: 781
Joined: Fri Apr 25, 2003 6:51 pm
Location: NC, USA
Contact:

Post by TerryHough »

naw wrote:@TerryHough

Any chance of you posting those updates back onto the forum, I have some probs too...
Sorry to be so long replying. I have been away on vacation.

I have sent all of my changes, suggestions and tests to Num3 earlier
and some more today.

I don't know if he will make updates to his libary based on my stuff or
not. My tests were all on Windows and I know he wanted to keep this
working for all platforms. It may take a bit of time for him to review
it all.

Feel free to PM me with specific questions on this. Maybe I can help.

Terry
OmeCloak
User
User
Posts: 13
Joined: Sat May 15, 2004 6:27 pm

Post by OmeCloak »

@TerryHough:

Any progress? I have also some errors, getting timeout when i want to actually transfer files.

Thnx.
User avatar
NoahPhense
Addict
Addict
Posts: 1999
Joined: Thu Oct 16, 2003 8:30 pm
Location: North Florida

Re: FTP for all PB OS's

Post by NoahPhense »

hell yeah... keep this project going.. and open source.. ;)

VERY NICE.. this will make nice stuff for my servers ..

- np
Num3
PureBasic Expert
PureBasic Expert
Posts: 2812
Joined: Fri Apr 25, 2003 4:51 pm
Location: Portugal, Lisbon
Contact:

Post by Num3 »

Hum... Didn't receive squat !!!

I guess it's better if we keep this thread alive, by posting the code here!
TerryHough
Enthusiast
Enthusiast
Posts: 781
Joined: Fri Apr 25, 2003 6:51 pm
Location: NC, USA
Contact:

Post by TerryHough »

Num3 wrote:Hum... Didn't receive squat !!!

I guess it's better if we keep this thread alive, by posting the code here!
@Num3
If that was meant for me...
I sent my changes to you via PM on Oct 18, 2004. Added a function on Oct 20th, and another on Nov 08, and sent them via PM on those dates.

I can resend them or post here if you want me to.

Terry

PS. Third time I have replied on this. Guess the forum relocation lost it twice before.
User avatar
NoahPhense
Addict
Addict
Posts: 1999
Joined: Thu Oct 16, 2003 8:30 pm
Location: North Florida

Post by NoahPhense »

I use Pauls routine, found here:

viewtopic.php?t=8971&highlight=ftp

I don't need the ftp server stuff.. Just the automated client stuff.. so that
I can have the app send stuff to my server.. or any server for that
matter.


- np
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Post by Psychophanta »

Num3 wrote:Work in progress...
I'll try to fine tune the code a little more, and i'll include a nice help on the next release ;)
Great! :)
Could you modify it in your first post of this thread?
http://www.zeitgeistmovie.com

while (world==business) world+=mafia;
TerryHough
Enthusiast
Enthusiast
Posts: 781
Joined: Fri Apr 25, 2003 6:51 pm
Location: NC, USA
Contact:

Post by TerryHough »

I have finally had time to spend with this FTP code again.

My current version is available at
http://elfecc.no-ip.info/purebasic#FTP_Library
last updated May 27, 2005

It includes the source code for the library procedures, an example of a
FTP conversation program, and a supporting procedure.

Image

I have utilized Num3's FTP procedures and extended them to work with
several different FTP servers. Yet, I still have problems with other
server pieces. Version 7b works successfully with the
FREE zFTPServer from
http://zftpserver.serveftp.com/
and the rather expensive Broker server from
http://www.transsoft.com/view_content.asp?ID=7

7b also works with FileZilla from
http://filezilla.sourceforge.net/
but sometimes has problems with FileZilla opening ports. I haven't
located that intermittent problem as yet

Reminder, the FTP procedures use the PASV mode for transfering info.
If you are running behind a router or firewall, make sure that the ports
assigned by the server are open on the router or firewall. If you have
trouble opening a port, that would be the first thing to check.

Thanks to Num3 for his code and contributions to the forum.

Terry
Last edited by TerryHough on Fri May 27, 2005 2:45 pm, edited 1 time in total.
DarkDragon
Addict
Addict
Posts: 2344
Joined: Mon Jun 02, 2003 9:16 am
Location: Germany
Contact:

Post by DarkDragon »

I have also made some functions:

Code: Select all

Global EOL.s
EOL.s = Chr(13)+Chr(10)

Procedure.s PassiveIP(Text.s)
  s = FindString(Text, "(", 1)+1
  l = FindString(Text, ")", s)-s
  Host.s = Mid(Text, s, l)
  IP.s = StringField(Host, 1, ",")+"."+StringField(Host, 2, ",")+"."+StringField(Host, 3, ",")+"."+StringField(Host, 4, ",")
  ProcedureReturn IP.s
EndProcedure

Procedure.l PassivePort(Text.s)
  s = FindString(Text, "(", 1)+1
  l = FindString(Text, ")", s)-s
  Host.s = Mid(Text, s, l)
  Port = Val(StringField(Host, 5, ","))*256+Val(StringField(Host, 6, ","))
  ProcedureReturn Port
EndProcedure

Procedure.s Wait(ConnectionID, Timeout)
  Delay(10)
  *Buffer = AllocateMemory(60000)
  t = ElapsedMilliseconds()
  While NetworkClientEvent(ConnectionID) <> 2 And ElapsedMilliseconds()-t < Timeout : Delay(1) : Wend
  If ElapsedMilliseconds()-t < Timeout
    Size = ReceiveNetworkData(ConnectionID, *Buffer, 60000)
    Text.s = PeekS(*Buffer)
    FreeMemory(*Buffer)
    ProcedureReturn Text
  EndIf
EndProcedure

Procedure Wait2(ConnectionID, *Buffer, Size, Timeout)
  Delay(50)
  t = ElapsedMilliseconds()
  While NetworkClientEvent(ConnectionID) = 0 And ElapsedMilliseconds()-t < Timeout : Delay(1) : Wend
  If ElapsedMilliseconds()-t < Timeout
    CurSize = ReceiveNetworkData(ConnectionID, *Buffer, Size)
    While CurSize < Size
      If NetworkClientEvent(ConnectionID) = 2
        CurSize + ReceiveNetworkData(ConnectionID, *Buffer+CurSize, Size-CurSize)
      EndIf
    Wend
    ProcedureReturn CurSize-1
  EndIf
EndProcedure

Procedure SendNetworkString2(ConnectionID, String.s)
  SendNetworkString(ConnectionID, String.s)
EndProcedure

Procedure FTP_Connect(Server.s, Port, Name.s, Pass.s)
  ConnectionID = OpenNetworkConnection(Server, Port)
  If ConnectionID
    Text.s = Wait(ConnectionID, 5000)
    If Left(Text, 3) = "220"
      SendNetworkString2(ConnectionID, "USER "+Name.s+EOL)
      Text.s = Wait(ConnectionID, 5000)
      If Left(Text, 3) = "331"
        SendNetworkString2(ConnectionID, "PASS "+Pass.s+EOL)
        Text.s = Wait(ConnectionID, 5000)
        If Left(Text, 3) = "230"
          SendNetworkString2(ConnectionID, "TYPE A"+EOL)
          Wait(ConnectionID, 5000)
          ProcedureReturn ConnectionID
        EndIf
      EndIf
    EndIf
    CloseNetworkConnection(ConnectionID)
  EndIf
EndProcedure

Procedure FTP_SetCurrentDirectory(ConnectionID, Path.s)
  If ConnectionID
    SendNetworkString2(ConnectionID, "CWD "+Path.s+EOL)
    Text.s = Wait(ConnectionID, 5000)
    If Left(Text, 3) = "250"
      SendNetworkString2(ConnectionID, "PWD"+EOL)
      Text.s = Wait(ConnectionID, 5000)
      If Left(Text, 3) = "257"
        ProcedureReturn 1
      EndIf
    EndIf
  EndIf
EndProcedure

Procedure.s FTP_List(ConnectionID)
  If ConnectionID
    SendNetworkString2(ConnectionID, "TYPE A"+EOL)
    Text.s = Wait(ConnectionID, 5000)
    If Left(Text, 3) = "200"
      SendNetworkString2(ConnectionID, "PASV"+EOL)
      Text.s = Wait(ConnectionID, 5000)
      If Left(Text, 3) = "227"
        Passive = OpenNetworkConnection(PassiveIP(Text.s), PassivePort(Text.s))
        If Passive
          SendNetworkString2(ConnectionID, "LIST"+EOL)
          Text.s = Wait(ConnectionID, 5000)
          If Left(Text, 3) = "150"
            Text.s = Wait(ConnectionID, 5000)
            Delay(10)
            Result.s = Wait(Passive, 5000)
            CloseNetworkConnection(Passive)
            Text.s = Wait(ConnectionID, 5000)
            ProcedureReturn Result
          EndIf
          CloseNetworkConnection(Passive)
        Else
        EndIf
      EndIf
    EndIf
  EndIf
EndProcedure

Procedure.s FTP_NameList(ConnectionID)
  If ConnectionID
    SendNetworkString2(ConnectionID, "TYPE A"+EOL)
    Text.s = Wait(ConnectionID, 5000)
    If Left(Text, 3) = "200"
      SendNetworkString2(ConnectionID, "PASV"+EOL)
      Text.s = Wait(ConnectionID, 5000)
      If Left(Text, 3) = "227"
        Passive = OpenNetworkConnection(PassiveIP(Text.s), PassivePort(Text.s))
        If Passive
          SendNetworkString2(ConnectionID, "NLST"+EOL)
          Delay(100)
          Text.s = Wait(ConnectionID, 5000)
          If Left(Text, 3) = "150"
            Text.s = Wait(ConnectionID, 5000)
            Delay(100)
            Result.s = Wait(Passive, 5000)
            CloseNetworkConnection(Passive)
            Text.s = Wait(ConnectionID, 5000)
            ProcedureReturn Result
          EndIf
          CloseNetworkConnection(Passive)
        EndIf
      EndIf
    EndIf
  EndIf
EndProcedure

Procedure.l FTP_DownloadFile(ConnectionID, SFile.s, DFile.s)
  If ConnectionID
    SendNetworkString2(ConnectionID, "TYPE I"+EOL)
    Text.s = Wait(ConnectionID, 5000)
    If Left(Text, 3) = "200"
      SendNetworkString2(ConnectionID, "PASV"+EOL)
      Text.s = Wait(ConnectionID, 5000)
      If Left(Text, 3) = "227"
        Passive = OpenNetworkConnection(PassiveIP(Text.s), PassivePort(Text.s))
        If Passive
          SendNetworkString2(ConnectionID, "RETR "+SFile+EOL)
          Delay(100)
          Text.s = Wait(ConnectionID, 5000)
          s = FindString(Text, "(", 1)+1
          l = FindString(Text, " ", s)-s
          Size = Val(Mid(Text, s, l))
          If Left(Text, 3) = "150"
            *Buffer = AllocateMemory(1024)
            Text = ""
            s = 0
            File = CreateFile(#PB_Any, DFile)
            If File
              While s < Size
                Size2 = ReceiveNetworkData(Passive, *Buffer, 1024)
                If Size2 > 0
                  s + Size2
                  WriteData(File, *Buffer, Size2)
                EndIf
              Wend
              CloseFile(File)
            EndIf
            FreeMemory(*Buffer)
            CloseNetworkConnection(Passive)
            Text.s = Wait(ConnectionID, 5000)

            ProcedureReturn 1
          EndIf
          CloseNetworkConnection(Passive)
        EndIf
      EndIf
    EndIf
  EndIf
EndProcedure

Procedure.l FTP_UploadFile(ConnectionID, SFile.s, DFile.s)
  If ConnectionID
    SendNetworkString2(ConnectionID, "TYPE I"+EOL)
    Text.s = Wait(ConnectionID, 5000)
    If Left(Text, 3) = "200"
      SendNetworkString2(ConnectionID, "PASV"+EOL)
      Text.s = Wait(ConnectionID, 5000)
      If Left(Text, 3) = "227"
        Passive = OpenNetworkConnection(PassiveIP(Text.s), PassivePort(Text.s))
        If Passive
          SendNetworkString2(ConnectionID, "STOR "+DFile+EOL)
          Delay(100)
          Text.s = Wait(ConnectionID, 5000)
          If Left(Text, 3) = "150"
            *Buffer = AllocateMemory(FileSize(SFile))
            File = ReadFile(#PB_Any, SFile)
            If File
              ReadData(File, *Buffer, FileSize(SFile))
              CloseFile(File)
            EndIf
            SendNetworkData(Passive, *Buffer, FileSize(SFile))
            FreeMemory(*Buffer)
            CloseNetworkConnection(Passive)
            Text.s = Wait(ConnectionID, 5000)
            ProcedureReturn 1
          EndIf
          CloseNetworkConnection(Passive)
        EndIf
      EndIf
    EndIf
  EndIf
EndProcedure

Procedure FTP_DeleteDirectory(ConnectionID, Dir.s)
  If ConnectionID
    SendNetworkString2(ConnectionID, "RMD "+Dir+EOL)
    Text.s = Wait(ConnectionID, 5000)
    If Left(Text, 3) = "250"
      ProcedureReturn 1
    EndIf
  EndIf
EndProcedure

Procedure FTP_RenameFile(ConnectionID, FromName.s, ToName.s)
  If ConnectionID
    SendNetworkString2(ConnectionID, "RNFR "+FromName+EOL)
    Text.s = Wait(ConnectionID, 5000)
    If Left(Text, 3) = "350"
      SendNetworkString2(ConnectionID, "RNTO "+ToName+EOL)
      Text.s = Wait(ConnectionID, 5000)
      If Left(Text, 3) = "250"
        ProcedureReturn 1
      EndIf
    EndIf
  EndIf
EndProcedure

Procedure FTP_DeleteFile(ConnectionID, File.s)
  If ConnectionID
    SendNetworkString2(ConnectionID, "DELE "+File+EOL)
    Text.s = Wait(ConnectionID, 5000)
    If Left(Text, 3) = "250"
      ProcedureReturn 1
    EndIf
  EndIf
EndProcedure

Procedure FTP_CreateDirectory(ConnectionID, Dir.s)
  If ConnectionID
    SendNetworkString2(ConnectionID, "MKD "+Dir+EOL)
    Text.s = Wait(ConnectionID, 5000)
    If Left(Text, 3) = "257"
      ProcedureReturn 1
    EndIf
  EndIf
EndProcedure

Procedure FTP_DirectoryUp(ConnectionID)
  If ConnectionID
    SendNetworkString2(ConnectionID, "CDUP"+EOL)
    Text.s = Wait(ConnectionID, 5000)
    If Left(Text, 3) = "250"
      ProcedureReturn 1
    EndIf
  EndIf
EndProcedure

Procedure FTP_NoEvent(ConnectionID)
  If ConnectionID
    SendNetworkString2(ConnectionID, "NOOP"+EOL)
    Text.s = Wait(ConnectionID, 5000)
  EndIf
EndProcedure

Procedure FTP_Quit(ConnectionID)
  If ConnectionID
    SendNetworkString2(ConnectionID, "QUIT"+EOL)
    Text.s = Wait(ConnectionID, 5000)
    If Left(Text, 3) = "221"
      ProcedureReturn 1
    EndIf
  EndIf
EndProcedure
[EDIT]
PB4.0
Last edited by DarkDragon on Wed Aug 29, 2007 9:26 am, edited 2 times in total.
bye,
Daniel
Num3
PureBasic Expert
PureBasic Expert
Posts: 2812
Joined: Fri Apr 25, 2003 4:51 pm
Location: Portugal, Lisbon
Contact:

Post by Num3 »

Gentleman...

Awesome!

You guys are getting better and better with the simple code i built!

Maybe it's time for the PB team to consider including this and other cool code has standard library commands or pbi files!
TerryHough
Enthusiast
Enthusiast
Posts: 781
Joined: Fri Apr 25, 2003 6:51 pm
Location: NC, USA
Contact:

Post by TerryHough »

Updated my source code as of today, May 26, 2005.

Found an additional response by a different FTP server to the LIST
command. Added handling to the FTP_List procedure in the Library
include file to recognize/handle that response and avoid a timeout failure.

My current version is available at
http://elfecc.no-ip.info/purebasic#FTP_Library
last updated May 27, 2005
Num3
PureBasic Expert
PureBasic Expert
Posts: 2812
Joined: Fri Apr 25, 2003 4:51 pm
Location: Portugal, Lisbon
Contact:

Post by Num3 »

Cool man!
User avatar
NoahPhense
Addict
Addict
Posts: 1999
Joined: Thu Oct 16, 2003 8:30 pm
Location: North Florida

..

Post by NoahPhense »

Sweet..


- np
Post Reply