The FTPClient (gb.net.curl) class provides an FTP client that allows downloading files from an FTP server, uploading files to an FTP server and sending FTP commands to an FTP server. This functionality should be demonstrated in the project. The programme interface represents on the one hand the view of a local directory and the files contained therein and on the other hand, among other things, of a remote directory and its files. A DirView and a FileView are used as controls for the local view. The remote directories on the FTP server are mapped to a TreeView. A GridView is used to display the file names (with matching icon) and selected file properties in a selected remote directory:
Figure 24.2.3.1.1: GUI - FTP Client Program1
The functionality of the FTP client can be described in a simplified way as follows:
PC: You can
FTP server: You can
For testing the programme, the FTP server vsFTPd was installed locally and configured appropriately. At https://gambas-buch.de/doku.php?id=k24:k24.15:start you will find a detailed description of the installation and configuration of the secure FTP server in a digression in chapter 24.15.
The idea for this Gambas project comes from Jorge Carrión (2013). However, he has further developed his programme on the basis of the class FTPClient with a different approach (GUI) and new emphases. You can now find Jorge's final project at https://gitlab.com/shordi/gbftp.
The class FTPClient (gb.net.curl) currently (23/03/2022) provides only unencrypted FTP and is therefore insecure! * Please switch to FTP over TLS (FTPS).
The FTP connection details dialogue captures the URL of the FTP server, the FTP user name, its FTP password and the base path on the FTP server:
The dialogue for reading the FTP connection data is called up in the main programme and is pleasantly short:
' Gambas class file ' ● Unverschlüsseltes FTP ist unsicher. Bitte wechseln Sie zu FTP über TLS. ' ● Unencrypted FTP is insecure. Please switch to FTP over TLS. Private cFTPAccountData As Collection Public Sub _call(sTitel As String) As Collection Me.Text = sTitel '-- Returns if one of the two buttons was clicked! '-- The return value is set in the Me.Close() call and indicates whether the dialog was aborted or not. If Me.ShowModal() = 0 Then Return Null Else If txbFTPServerURL.Text And If txbFTPUserName.Text And If txbFTPUserPassword.Text And \ If txbFTPServerInitialPath.Text Then cFTPAccountData = New Collection cFTPAccountData["FTPServerURL"] = txbFTPServerURL.Text cFTPAccountData["FTPUsername"] = txbFTPUserName.Text cFTPAccountData["FTPPassword"] = txbFTPUserPassword.Text If txbFTPServerInitialPath.Text Not Ends "/" Then txbFTPServerInitialPath.Text &= "/" cFTPAccountData["FTPServerInitialPath"] = txbFTPServerInitialPath.Text Return cFTPAccountData Else Message.Error(("The FTP account data are not complete!")) Return Null Endif Endif End Public Sub Form_Open() txbFTPServerURL.Text = MSettings.AppSettings["FTP/ServerURL"] txbFTPUserName.Text = MSettings.AppSettings["FTP/Username"] txbFTPUserPassword.Text = MSettings.AppSettings["FTP/Password"] txbFTPServerInitialPath.Text = MSettings.AppSettings["FTP/InitialPath"] End Public Sub bConnect_Click() Me.Close(1) End Public Sub bCancel_Click() Me.Close(0) End Public Sub Form_Close() If rbtnRemember.Value = True Then MSettings.AppSettings["FTP/ServerURL"] = txbFTPServerURL.Text MSettings.AppSettings["FTP/Username"] = txbFTPUserName.Text MSettings.AppSettings["FTP/Password"] = txbFTPUserPassword.Text If txbFTPServerInitialPath.Text Not Ends "/" Then txbFTPServerInitialPath.Text &= "/" MSettings.AppSettings["FTP/InitialPath"] = txbFTPServerInitialPath.Text Else MSettings.AppSettings["FTP/ServerURL"] = "" MSettings.AppSettings["FTP/Username"] = "" MSettings.AppSettings["FTP/Password"] = "" MSettings.AppSettings["FTP/InitialPath"] = "" Endif MSettings.AppSettings.Save() End
The programme source code is given only in selected sections and is sufficiently commented there. The complete project archive can be found in the download area.
It has proved very helpful during programme development to use the debug property
'-- OPTION hFTPClient.Debug = True
to the value True.
The following three procedures realise the display of relevant directories and file names (with matching symbol) as well as selected file properties (→ Figure 24.2.3.1.1):
Public Sub GetServerDirectories() Dim n As Integer Dim sLine, sSize, sDate, sFileName As String Dim asDirRawData As New String[] Dim asDirData As New String[] asServerDirData = New String[] avServerFileData = New Variant[] aoFileIcon = New Object[] Inc Application.Busy hFTPClient.Async = False hFTPClient.URL = sFTPServerURL &/ sFTPServerInitialPath &/ txbServerDir.Text &/ "/" '-- Reads the contents of the specified server directory and stores it in a temporary file hFTPClient.Get(sTempFileName) If hFTPClient.ErrorText Then Message.Error(("The server reports the error") & ":\n" & hFTPClient.ErrorText) '-- The main program is terminated without comment! FMain.Close() Endif asDirRawData = Split(File.Load(sTempFileName), gb.NewLine, "\\", True) For Each sLine In asDirRawData '-- Several contiguous spaces in the string are reduced to 1 space character While InStr(sLine, " ") sLine = Replace(sLine, " ", " ") Wend '-- Last parameter avoid empty items on asDirData asDirData = Split(sline, " ", "", True) '-- . and .. are the convention names of actual and parent Directory we avoid them if exist If asDirData[8] = "." Or If asDirData[8] = ".." Then Continue sFilename = "" '-- Element 8 is only the *first* word of the name. There can also be more ... For n = 8 To asDirData.Max sFileName &= asDirData[n] & " " Next '-- Delete the last space added in the last for-next loop. sFileName = Left(sFileName, -1) If asDirData[0] Begins "d" Then ' ◀—— The rights string for a directory begins with `d` '-- Add-Option: asDirData[8], we use the local variable `sFilename` instead asServerDirData.Add(sFilename) Else sSize = GetFileSize(CLong(asDirData[4])) ' ◀—— File-Size sDate = asDirData[6] & " " & asDirData[5] & " " & asDirData[7] ' ◀—— Day - Month - Time '-- Filename, Filesize and Date of last change avServerFileData.Add([sFileName, sSize, sDate]) '-- Returns the icon associated with a specific file. (DesktopMime class) File.Save("/tmp" &/ "t." & File.Ext(sFileName), "") aoFileIcon.Add(Desktop.GetFileIcon("/tmp" &/ "t." & File.Ext(sFileName), 16)) ' ◀—— File-Icon Endif Next Dec Application.Busy End
Public Sub ShowServerDirectories() Dim sServerDirName As String For Each sServerDirName In asServerDirData '-- sServerDirName = Conv$(sServerDirName, "ISO-8859-15", "UTF-8") ' —▶ After a tip from Claus D. If trvServerDirectories.MoveTo(txbServerDir.Text &/ sServerDirName) Then trvServerDirectories.Add(txbServerDir.Text &/ sServerDirName, sServerDirName, \ Stock["directory"], txbServerDir.Text, Null).EnsureVisible Endif Next End
Public Sub ShowServerFiles() Dim iRow, iColumn As Integer Dim avLines As New Variant[] grvServerFiles.Rows.Count = avServerFileData.Count For iRow = 0 To avServerFileData.Max avLines = avServerFileData[iRow] grvServerFiles[iRow, 0].Picture = aoFileIcon[iRow] For iColumn = 0 To avLines.Max '-- grvServerFiles[iRow, iColumn].Text = Conv$(avLines[iColumn], "ISO-8859-15", "UTF-8") grvServerFiles[iRow, iColumn].Text = avLines[iColumn] Next Next End Public Sub trvServerDirectories_Click() txbServerDir.Text = trvServerDirectories.Key trvServerDirectories[trvServerDirectories.Key].Expanded = IIf(trvServerDirectories.Key = "/", \ True, Not trvServerDirectories[trvServerDirectories.Key].Expanded) txbServerDir_Activate() End
Note:\ For sorting the files on the FTP server, the following applies: first numbers, then upper case letters and then lower case letters (→ Figure 24.2.3.1.1).
Whether you want to download only one file or several marked files from the FTP server to a marked local directory or you realise the download with Drog&Drop - you always use the following procedure RunDownload():
Private Sub RunDownload() Dim sServerFileName, sServerFilePath As String Dim aiRows As New Integer[] Dim n, iIndex As Integer If grvServerFiles.Rows.Selection.Count = 0 Then Message.Info(("No file was selected!")) Return Endif pbarDownload.Visible = True pbarDownload.Value = 0 Inc Application.Busy aiRows = grvServerFiles.Rows.Selection For n = 0 To aiRows.Max pbarDownload.Value = 0 iIndex = aiRows[n] sServerFileName = grvServerFiles[iIndex, 0].Text lblDownloadFilename.Text = " —▶ " & sServerFileName hFTPClient.Async = True hFTPClient.URL = sFTPServerURL &/ sFTPServerInitialPath &/ txbServerDir.Text &/ sServerFileName sServerFilePath = txbLocalDir.Text &/ sServerFileName hFTPClient.Get(sServerFilePath) ' ◀—— File-Download While hFTPClient.Status > 0 If hFTPClient.TotalDownloaded > 0 Then pbarDownload.Value = hFTPClient.Downloaded / hFTPClient.TotalDownloaded Endif Wait 0.01 Wend If hFTPClient.ErrorText Then Message(("The server reports the error") & ":\n" & hFTPClient.ErrorText) Else pbarDownload.Value = 1 Wait 0.5 dirvLocalDirectories.Reload() Endif Next Dec Application.Busy End
Whether you want to upload only one file or several marked files from a local directory to a marked directory on the FTP server or implement the upload with Drog&Drop - you always use the following procedure RunUpload():
Private Sub RunUpload() Dim sLocalFileName, sLocalFilePath As String If filevLocalFiles.Selection.Count = 0 Then Message.Info(("No file was selected!")) Return Endif pbarUpload.Visible = True pbarUpload.Value = 0 Inc Application.Busy For Each sLocalFileName In filevLocalFiles.Selection pbarUpload.Value = 0 lblUploadFilename.Text = " —▶ " & sLocalFileName '-- Here it is possible to give the file to be uploaded a different name. '-- This is unnecessary, however, as files can be renamed on the server. hFTPClient.Async = True '-- Currently the file name is kept when uploading to the server hFTPClient.URL = sFTPServerURL &/ sFTPServerInitialPath &/ txbServerDir.Text &/ sLocalFileName sLocalFilePath = filevLocalFiles.Dir &/ sLocalFileName hFTPClient.Put(sLocalFilePath) ' ◀—— File-Upload While hFTPClient.Status > 0 If hFTPClient.TotalUploaded > 0 Then pbarUpload.Value = hFTPClient.Uploaded / hFTPClient.TotalUploaded Endif Wait 0.01 Wend If hFTPClient.ErrorText Then Message(("The server reports the error") & ":\n" & hFTPClient.ErrorText) Else pbarUpload.Value = 1 Wait 0.5 RefreshServerView() Endif Next Dec Application.Busy End
Project