Web Connection
FTP Changes in Web Connection and Client Tools
Gravatar is a globally recognized avatar based on your email address. FTP Changes in Web Connection and Client Tools
  Rick Strahl
  All
  May 27, 2024 @ 07:18am

Hi all,

I've been doing some work over the last few days adding improved FTP support to Web Conenction and the Client Tools. This brings more features and consistency across FTP protocols to FTP processing.

There are two new classes:

  • wwFtpClient - Replaces wwFtp and provides support for FTP and SFTP
  • wwSftpClient - Replaces wwSftp and provides support for SFTP

Both classes now have the same exact interface (except for a few SFTP specific connection features). Both classes are now simpler in that they provide just the Connect(), Ftp Operations, Close() model of operation. In essence the new interface dumps all the funky legacy that was based around the old Win32 APIs that were used with the old WinInet based libraries.

All the same features are still available:

  • Download
  • Upload
  • ListFiles
  • DeleteFile
  • MoveFile
  • CreateDirectory
  • DeleteDirectory
  • ChangeDirectory

An Example

The following code is an example that demonstrates most of the functionality in a single short program that uploads, downloads, lists and deletes files on an FTP server using FTPS:

loFtp  = CREATEOBJECT("wwFtpClient")
loFtp.lUseTls = .T.
loFtp.cLogFile = "c:\temp\ftp.log" && verbose log - leave empty
oFtp.lIgnoreCertificateErrors = .T.   && self-signed cert not installed

SET PROCEDURE TO wwutils ADDITIVE  && for UI helpers

*** yourserver.com or yourserver.com:28
lcServer = INPUTBOX("Server Domain/IP")
IF EMPTY(lcServer)
   RETURN
ENDIF

lcUsername = InputBox("User name")
IF EMPTY(lcUsername)
   RETURN
ENDIF

lcPassword = GetPassword("Password")
IF EMPTY(lcPassword)
	RETURN
ENDIF

loFtp.oProgressEventObject = CREATEOBJECT("FtpClientProgressEvents")

loFtp.cServer = lcServer
loFtp.cUsername = lcUsername
loFtp.cPassword = lcPassword
*loFtp.nPort = 21 && only needed if custom port is required

IF !loFtp.Connect()
	? loFtp.cErrorMsg
	RETURN
ENDIF
? "Connected to " + lcServer	

IF !loFtp.DownloadFile("Tools/jsMinifier.zip", "c:\temp\jsMinifier.zip")
	? loFtp.cErrorMsg
	RETURN
ENDIF	
? "Downloaded " + "Tools/jsMinifier.zip"

lcUploadFile = "Tools/jsMinifier" + SYS(2015) + ".zip"
IF !loFtp.UploadFile("c:\temp\jsMinifier.zip", lcUploadFile)
	? loFtp.cErrorMsg
	RETURN
ENDIF
? "Uploaded " + lcuploadFile

*** provide a folder name (no wildcards)
loCol = loFtp.ListFiles("/Tools")
? TRANSFORM(loCol.Count ) + " matching file(s)"
? loFtp.cErrorMsg
FOR EACH loFile IN loCol FOXOBJECT
   IF ( AT("jsMinifier_",loFile.Name) = 1)
	   ? loFtp.oBridge.ToJson(loFile)  && for kicks print out as json
	   IF loFtp.DeleteFile(loFile.FullName)
	      ? "Deleted " + loFile.FullName
	   ENDIF
	   
   ENDIF
ENDFOR

RETURN


DEFINE class FtpClientProgressEvents as Custom

FUNCTION OnFtpBufferUpdate(lnPercent, lnDownloadedBytes, lcRemotePath, lcMode)
  lcMsg = lcMode + ": " + TRANSFORM(lnPercent) + "% complete. " + lcRemotePath + " - " + TRANSFORM(lnDownloadedBytes) + " bytes"
  ? "*** " + lcMsg
ENDFUNC

ENDDEFINE 

Under the Covers

The FTP and SFTP classes now use a .NET component (Fluent FTP) for handling the FTP interaction. The main reason for the change is support for FTPS (FTP over TLS) which seems to be very common since many OSS servers like FileZilla use it and unsecured FTP is no longer a viable option for anything but internal solutions.

The SFTP class continues to use the same .NET component it's been using (SSH.net) but the functionality has been simplified to match the FTP/SFTP class. The .NET component also has been updated to the latest 2024 release.

Breaking Changes, but old versions continue to work

These new libraries are a breaking change obviously, but the old libraries will continue to ship in the OldFiles folder. The only breaking change for the old version is the OnFtpBufferUpdate() functionality which has been changed at the API interface level.

+++ Rick ---

© 1996-2024