B4J Question Help needed - ftp.list only listing top level directory. Client in B4J, Server in B4A

This is a simple file transfer app. (that will be part of a much bigger beehive inspection application - already written but now growing).
This part copies the database from the logging device (an Android phone Samsung SM-J700F running Android 6.0.1) to a
PC running the latest version of Windows 10.

The client app. (win10) copies the "HiveInspections.db" file from the phone (the server) without a problem.
I would then like to copy any files in two other directories (reports & pictures). But so far all I can get ftp.List("/Android/data/b4a.hives/files/pictures")
to do is list files and directories in "/" and even then it doesn't do this recursively.

The two attached .zip files should be both the client and server parts of this little app. (Please Note: I intend using the file list derived from ftp.List to retrieve
the files from the server/phone - this has not yet been implemented. Also the IP, Port and File path data entry labels on the UI do nothing yet).

Filezilla can access all of the directories I need ie running the phone based server part and accessing from the PC using Filezilla.

The two parts of the app have been based on/lifted from code posted on the B4X forums, without which I wouldn't have made it this far - so thank you all.

So any ideas? What am I missing/doing wrong?

Many Thanks,
Al

This is the first part of the logged output.
'/Android/data/b4a.hives/files/pictures' should contain just one .jpg file
but is actually the listing of all dirs. and files in the top level.

Waiting for debugger to connect...
Program started.
Server Path = /Android/data/b4a.hives/files/pictures
Samsung
Android <-- Dir 1, but nothing below this directory
.mobvista
tbs
OLYMPUS
.KRSDK
.SDKDownloads
Playlists
data <-- Not the 'data' I need.
Download
DCIM
tencent
.here-maps
Pictures
com.android.calendar.subscription.a
Books
360
LD-Log_FREE
rdtmp
Documents
ShareMemo
Media
etc etc

Followed by the top level files;
Contacts.vcf, 3037, 11/03/2015
driveinfo.calibre, 262, 11/08/2015
metadata.calibre, 876, 11/08/2015
qs.pid, 6, 01/09/2016
ota, 398726, 09/14/2020
userconfig.dat, 697, 10/15/2017

B4J Client
B4X:
#Region Project Attributes
    #MainFormWidth: 600
    #MainFormHeight: 600
#End Region

Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private xui As XUI
    Private Button1 As B4XView
    Private Label1 As Label
    Private ftfClientPath As B4XFloatTextField
    Private ftfServerPath As B4XFloatTextField
    Private ftfIP As B4XFloatTextField
    Private ftfPort As B4XFloatTextField
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Layout1")
    MainForm.Show
    ftfClientPath.Text = "D:\Data\Temp09"
    ftfServerPath.Text = "/Android/data/b4a.hives/files/database/HiveInspections.db"
    ftfIP.Text = "192.168.1.65"
    ftfPort.Text = 51041
End Sub

Sub Button1_Click
    DownloadFile("HiveInspections.db")
    ListFiles("/Android/data/b4a.hives/files/pictures")
End Sub

Private Sub DownloadFile(filename As String)
    Dim ftp As FTP
    'ftp.Initialize("ftp","[server IP or url]",21,"[user]","[password]")
    ftp.Initialize("ftp","192.168.1.65",51041,"Test","test") '
    ftp.PassiveMode=True
    ftp.TimeoutMs=60000
   
    Dim sf As Object = ftp.DownloadFile("/Android/data/b4a.hives/files/database/"& filename,False,"D:\Data\Temp09",filename)
    Wait For (sf) ftp_DownloadCompleted (ServerPath As String, Success As Boolean)
    If Success Then
        Label1.Text = filename & " file was downloaded successfully"
    Else
        Label1.Text = "Error downloading file " & filename
    End If
    ftp.Close
End Sub

Private Sub ListFiles(path As String)
    Dim ftp As FTP
    'ftp.Initialize("ftp","[server IP or url]",21,"[user]","[password]")
    ftp.Initialize("ftp","192.168.1.65",51041,"Test","test") '
    ftp.PassiveMode=True
    ftp.TimeoutMs=60000
   
    ' Now get pictures and reports
    ftp.List(path) '<-- Regardless of 'path' value this just returns two directories below '/'
    ftp.Close
End Sub

'Return true to allow the default exceptions handler to handle the uncaught exception.
Sub Application_Error (Error As Exception, StackTrace As String) As Boolean
    Return True
End Sub

Sub ftp_ListCompleted (ServerPath As String, Success As Boolean, Folders() As FTPEntry, Files() As FTPEntry)
    Log("Server Path = " & ServerPath)
    If Success = False Then
        Log(LastException)
    Else
        For i = 0 To Folders.Length - 1
            Log(Folders(i).Name)
        Next
        For i = 0 To Files.Length - 1
            Log(Files(i).Name & ", " & Files(i).Size & ", " & DateTime.Date(Files(i).Timestamp))
        Next
    End If
End Sub

B4A Server
B4X:
#Region  Project Attributes
    #ApplicationLabel: B4A Example
    #VersionCode: 1
    #VersionName:
    'SupportedOrientations possible values: unspecified, landscape or portrait.
    #SupportedOrientations: unspecified
    #CanInstallToExternalStorage: False
#End Region

#Region  Activity Attributes
    #FullScreen: False
    #IncludeTitle: True
#End Region

Sub Process_Globals
    Private rp As RuntimePermissions
End Sub

Sub Globals

    Private lblState As Label
    Private lblServer As Label
End Sub

Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("1")
    rp.CheckAndRequest(rp.PERMISSION_WRITE_EXTERNAL_STORAGE)
    Wait For Activity_PermissionResult (Permission As String, Result As Boolean)
    If Result Then
        Starter.server.Start
    Else
        lblServer.Text = "No permission!"
    End If
End Sub

Sub Activity_Resume
    FTPServer_StateChanged
End Sub

Public Sub FTPServer_StateChanged
    lblServer.Text = $"Server address: ${Starter.server.ssocket.GetMyWifiIP}
Port: ${Starter.server.Port}"$
    lblState.Text = $"Number of clients: ${Starter.server.NumberOfClients}"$
End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub
 

Attachments

  • FTP_Client_B4J.zip
    3.2 KB · Views: 153
  • FTP_Server_B4A.zip
    7.9 KB · Views: 163
Hi Erel,
Thanks for the prompt reply. It looks like it doesn't matter what I use as the server path, I always get the listing provided above in my first post.
Below is a list of some of the paths I have tried (there were a lot more);
B4X:
Sub Button1_Click
    DownloadFile("HiveInspections.db")
    'ListFiles("/Android/data/b4a.hives/files/pictures")
    'ListFiles("/")
    'ListFiles("/storage/emulated/0/Android/data/b4a.hives/files/pictures")
    'ListFiles("/data/b4a.hives/files/pictures")
    'ListFiles("/b4a.hives/files/pictures")
    'ListFiles("/files/pictures")
    'ListFiles("/storage/emulated/0/data/b4a.hives/files/pictures")
    'ListFiles("storage")
    'ListFiles("/storage")
    'ListFiles("/storage/emulated/0/")
    'ListFiles("reghrthdtyjjy")
    'ListFiles("")
    'ListFiles(".")
End Sub

What is confusing me is the fact that the ftp.DownloadFile works using the 'odd' server path;
B4X:
Private Sub DownloadFile(filename As String)
    Dim ftp As FTP
    'ftp.Initialize("ftp","[server IP or url]",21,"[user]","[password]")
    ftp.Initialize("ftp","192.168.1.65",51041,"Test","test") '
    ftp.PassiveMode=True
    ftp.TimeoutMs=60000
    
    Dim sf As Object = ftp.DownloadFile("/Android/data/b4a.hives/files/database/"& filename,False,"D:\Data\Temp09",filename)
    Wait For (sf) ftp_DownloadCompleted (ServerPath As String, Success As Boolean)
    If Success Then
        Label1.Text = filename & " file was downloaded successfully"
    Else
        Label1.Text = "Error downloading file " & filename
    End If
    ftp.Close
End Sub

Thanks,
Al
 
Upvote 0
This is the full listing for "/";

Waiting for debugger to connect...
Program started.
*****************************************************************************
(FTPFile) drwxr-xr-x 1 owner group 4096 Dec 31 2013 Samsung
(FTPFile) drwxr-xr-x 1 owner group 4096 Dec 15 2015 Android
(FTPFile) drwxr-xr-x 1 owner group 4096 Jan 9 2016 .mobvista
(FTPFile) drwxr-xr-x 1 owner group 4096 Mar 7 2016 tbs
(FTPFile) drwxr-xr-x 1 owner group 4096 Sep 17 2016 OLYMPUS
(FTPFile) drwxr-xr-x 1 owner group 4096 Jan 11 2016 .KRSDK
(FTPFile) drwxr-xr-x 1 owner group 4096 Jan 12 2016 .SDKDownloads
(FTPFile) drwxr-xr-x 1 owner group 4096 Jan 15 2016 Playlists
(FTPFile) drwxr-xr-x 1 owner group 4096 Jun 10 15:15 data
(FTPFile) drwxr-xr-x 1 owner group 4096 Mar 29 20:20 Download
(FTPFile) drwxr-xr-x 1 owner group 4096 Jul 18 11:11 DCIM
(FTPFile) drwxr-xr-x 1 owner group 4096 Mar 7 2016 tencent
(FTPFile) drwxr-xr-x 1 owner group 4096 Oct 27 2015 .here-maps
(FTPFile) drwxr-xr-x 1 owner group 4096 May 6 2019 Pictures
(FTPFile) drwxr-xr-x 1 owner group 4096 Jan 16 2016 com.android.calendar.subscription.a
(FTPFile) drwxr-xr-x 1 owner group 4096 Jan 23 2020 Books
(FTPFile) drwxr-xr-x 1 owner group 4096 Jan 9 2016 360
(FTPFile) drwxr-xr-x 1 owner group 4096 Dec 15 2015 LD-Log_FREE
(FTPFile) drwxr-xr-x 1 owner group 4096 Jul 13 2016 rdtmp
(FTPFile) drwxr-xr-x 1 owner group 4096 Aug 2 2016 Documents
(FTPFile) drwxr-xr-x 1 owner group 4096 Aug 18 2016 ShareMemo
(FTPFile) drwxr-xr-x 1 owner group 4096 Aug 22 2016 Media
(FTPFile) drwxr-xr-x 1 owner group 4096 Dec 15 2018 com.grppl.android.shell.CMBlloydsTSB73
(FTPFile) drwxr-xr-x 1 owner group 4096 Jan 8 2019 .EmailTempImage
(FTPFile) drwxr-xr-x 1 owner group 4096 Feb 10 2018 duapps
(FTPFile) drwxr-xr-x 1 owner group 4096 Feb 1 2017 MyHeart
(FTPFile) drwxr-xr-x 1 owner group 4096 Feb 1 2017 Blood Pressure
(FTPFile) drwxr-xr-x 1 owner group 4096 Oct 13 2019 SuperCam
(FTPFile) drwxr-xr-x 1 owner group 4096 Oct 13 2019 XMEye
(FTPFile) drwxr-xr-x 1 owner group 4096 Oct 17 2019 homesafeview
(FTPFile) drwxr-xr-x 1 owner group 4096 Feb 23 2020 baidu
(FTPFile) drwxr-xr-x 1 owner group 4096 Sep 8 2017 videorecord
(FTPFile) drwxr-xr-x 1 owner group 4096 Sep 8 2017 HB
(FTPFile) drwxr-xr-x 1 owner group 4096 Sep 8 2017 snapshot
(FTPFile) drwxr-xr-x 1 owner group 4096 Sep 8 2017 .LocalXml
(FTPFile) drwxr-xr-x 1 owner group 4096 Oct 25 2019 Voice Recorder
(FTPFile) drwxr-xr-x 1 owner group 4096 Sep 9 2017 Mob
(FTPFile) drwxr-xr-x 1 owner group 4096 Sep 9 2017 ViewerAuth_com.ichano.athome.camera
(FTPFile) drwxr-xr-x 1 owner group 4096 Sep 9 2017 AtHome
(FTPFile) drwxr-xr-x 1 owner group 4096 Nov 26 2019 swannsecurity
(FTPFile) drwxr-xr-x 1 owner group 4096 Sep 9 2017 Ivideon
(FTPFile) drwxr-xr-x 1 owner group 4096 Sep 9 2017 temp
(FTPFile) drwxr-xr-x 1 owner group 4096 Feb 25 2020 WhatsApp
(FTPFile) drwxr-xr-x 1 owner group 4096 Jun 2 15:15 Smart AudioBook Player Backup
(FTPFile) -rw-r--r-- 1 owner group 3037 Nov 3 2015 Contacts.vcf
(FTPFile) -rw-r--r-- 1 owner group 262 Nov 8 2015 driveinfo.calibre
(FTPFile) -rw-r--r-- 1 owner group 876 Nov 8 2015 metadata.calibre
(FTPFile) -rw-r--r-- 1 owner group 6 Jan 9 2016 qs.pid
(FTPFile) -rw-r--r-- 1 owner group 400615 Sep 15 12:12 ota
(FTPFile) -rw-r--r-- 1 owner group 697 Oct 15 2017 userconfig.dat

Also attached a new test version of the code;

B4X:
Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    
    Public timeout = 60000 As Int
    Public usr = "Test" As String
    Public pwd = "test" As String
    Private ftfIP = "192.168.1.65" As String
    Private ftfPort = 51041 As Int
    
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.Show
    Dim PagesManager As B4XPagesManager
    PagesManager.Initialize(MainForm)
    
    
    Dim Ftp As FTP
    Ftp.Initialize("ftp",ftfIP,ftfPort,usr,pwd) '
    Ftp.PassiveMode=True
    Ftp.TimeoutMs=timeout
    
    Dim sf As Object = Ftp.List("/")
    Wait For (sf) ftp_ListCompleted (ServerPath As String, Success As Boolean, Folders() As FTPEntry, Files() As FTPEntry)
    Log(ServerPath)
    If Success Then
        For Each f As FTPEntry In Folders
            Log(f)
        Next
 
        For Each f As FTPEntry In Files
            Log(f)
        Next
    End If
    Ftp.Close
    
End Sub



Have also tried;
ftp.List("/Android")
ftp.List("/Android/")
ftp.List("")
Ftp.List("/storage/emulated/0/data")
Ftp.List("/storage/emulated/0")

All give exactly the same file list.

Thanks,
Al
 
Upvote 0
This is the log from the B4A (Server) side of things;

client: USER Test
client: PASS test
User logged in: Test
client: SYST
client: PASV
client: LIST /Android
Data connection terminated: /
DataConnection_Close
terminated
DataConnection_Close

Thanks,
Al
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
YOU ARE CORRECT!!!

The B4X ftp server ignores the path set with FTP.List. Apparently most clients doesn't use it so we never encountered this issue.
Workaround is to do what other clients do and change the folder with CWD command:
B4X:
ftp.SendCommand("CWD", "/Android")
Wait For ftp_CommandCompleted (Command As String, Success As Boolean, ReplyCode As Int, ReplyString As String)
If Success Then
 ftp.List("")
 Wait For ftp_ListCompleted (ServerPath As String, Success As Boolean, Folders() As FTPEntry, Files() As FTPEntry)
 Log(Folders.Length)
 Log(Files.Length)
 For Each f As FTPEntry In Folders
    Log(f)
 Next
 For Each f As FTPEntry In Files
    Log(f)
 Next
End If
 
Upvote 0
Hi Erel,
Thanks for that.
I did try SendCommand but was trying to use it to LIST, hadn't thought of simply changing directory.

I have posted my final code snippet just incase it helps someone else or someone would like to improve on it.

Thanks again for all your help,
Al

B4X:
#Region Project Attributes
    #MainFormWidth: 600
    #MainFormHeight: 600
#End Region

Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private xui As XUI
    Private Button1 As B4XView
    Private Label1 As Label
    Private ftfClientPath As B4XFloatTextField
    Private ftfServerPath As B4XFloatTextField
    Private ftfIP As B4XFloatTextField
    Private ftfPort As B4XFloatTextField
    Public timeout = 60000 As Int
    Public usr = "Test" As String
    Public pwd = "test" As String
    Private cbPictures As B4XView
    Private cbReports As B4XView
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Layout")
    MainForm.Show
    ftfClientPath.Text = "D:\Data\Temp09"
    ftfServerPath.Text = "/Android/data/b4a.hives/files/"
    ftfIP.Text = "192.168.1.65"
    ftfPort.Text = 51041
End Sub

Sub Button1_Click
    DownloadFile(ftfServerPath.Text & "database/", "HiveInspections.db", ftfClientPath.Text)
    
    If cbPictures.Checked Then
        Wait For (GetFiles(ftfServerPath.Text & "pictures/")) Complete (Complete As Object)
    End If
    '
    If cbReports.Checked Then
        Wait For (GetFiles(ftfServerPath.Text & "reports/")) Complete (Complete As Object)
    End If
    Log("*****************************************************************************")
End Sub

'DownloadFile (serverpath = Android path, filename = used both sides, clientpath = PC path)
Private Sub DownloadFile(serverpath As String, filename As String, clientpath As String)
    Dim Ftp As FTP
    'ftp.Initialize("ftp","[server IP or url]",21,"[user]","[password]")
    Ftp.Initialize("ftp",ftfIP.Text,ftfPort.Text,usr,pwd) '
    Ftp.PassiveMode=True
    Ftp.TimeoutMs=timeout
    Dim sf As Object = Ftp.DownloadFile(serverpath & filename,False,clientpath,filename)
    Wait For (sf) ftp_DownloadCompleted (serverpath As String, Success As Boolean)
    If Success Then
        Label1.Text = filename & " file was downloaded successfully"
    Else
        Label1.Text = "Error downloading file " & filename
    End If
    Ftp.Close
End Sub

'GetFiles (path = Android/Server path)
Sub GetFiles(path As String) As ResumableSub
    Dim Ftp As FTP
    'ftp.Initialize("ftp","[server IP or url]",21,"[user]","[password]")
    Ftp.Initialize("ftp",ftfIP.Text,ftfPort.Text,usr,pwd) '
    Ftp.PassiveMode=True
    Ftp.TimeoutMs=timeout
    Ftp.SendCommand("CWD", path)
    Wait For FTP_CommandCompleted(Command As String, Success As Boolean, ReplyCode As Int, ReplyString As String)
    If Success = False Then
        Log(LastException)
    Else
        Ftp.List("")
        Wait For ftp_ListCompleted(ServerPath As String, Success As Boolean, Folders() As FTPEntry, Files() As FTPEntry)
        If Success = False Then
            Log(LastException)
        Else
            For i = 0 To Files.Length - 1
                Log(Files(i).Name)
                DownloadFile(path, Files(i).Name, ftfClientPath.Text)
            Next
        End If
    End If
    Ftp.Close
Return Null
End Sub

'Return true to allow the default exceptions handler to handle the uncaught exception.
Sub Application_Error (Error As Exception, StackTrace As String) As Boolean
    Return True
End Sub
 

Attachments

  • FTP_Client.zip
    3.5 KB · Views: 180
  • Like
Reactions: udg
Upvote 0
Top