B4A Library [lib] NetExtras

Here's a library i want to share with other members, original developed for forum member Biometrics.

NetExtras contains a new object FTPResume:

In order to use NetExtras you have to also include the official b4a Net library in you project.
NetExtras is based on version 1.52 of the b4a Net library.

NetExtras
Comment: NetExtras is a modified version of the official B4A Net library.
FTPResume is a modified version of the FTP Object.
It's DownloadFileResume replaces DownloadFile and it's UploadFileResume replaces UploadFile.
Both of these two new methods support resume of incomplete file download and upload.
SMTPExtras is a modified version of the SMTP object.
It has been modified to allow additional (custom) header fields to be added to the outgoing email,
and control over the connection timeout periods.
NetExtras is based on version 1.52 of the B4A Net library.
Author: B4A Net library modified by Martin Pearman
Version: 1.52
  • CustomTrustManager
    Methods:
    • Initialize (Dir As String, FileName As String)
      Initializes the trust manager based on the given cert file.
    • InitializeAcceptAll
      Initializes an "accept all" trust manager. This option should only be used in safe networks as it offers no real protection.
    • IsInitialized As Boolean
  • FTPEntry
    Methods:
    • IsInitialized As Boolean
    Properties:
    • Name As String [read only]
    • Size As Long [read only]
    • Timestamp As Long [read only]
  • FTPResume
    Events:
    • CommandCompleted (Command As String, Success As Boolean, ReplyCode As Int, ReplyString As String)
    • DeleteCompleted (ServerPath As String, Success As Boolean)
    • DownloadCompleted (ServerPath As String, Success As Boolean)
    • DownloadProgress (ServerPath As String, TotalDownloaded As Long, Total As Long)
    • ListCompleted (ServerPath As String, Success As Boolean, Folders() As FTPEntry, Files() As FTPEntry)
    • UploadCompleted (ServerPath As String, Success As Boolean)
    • UploadProgress (ServerPath As String, TotalUploaded As Long, Total As Long)
    Methods:
    • Close
      Closes the connection after all submitted tasks finish. Note that this method does not block.
    • CloseNow
      Closes the connection immediately without waiting for current tasks to finish.
      The data connection will only be closed when UploadProgress or DownloadProgress events fire.
    • DeleteFile (ServerPath As String)
      Deletes a file from the server.
      The DeleteCompleted event will be raised when this task completes.
    • DownloadFileResume (ServerFilePath As String, AsciiFile As Boolean, DeviceFolder As String, DeviceFile As String, RestartOffset As Long)
      Downloads or resumes down of a file from the server.
      The DownloadCompleted event will be raised when download completes.
      DownloadProgress events will be raised during download.
      ServerFilePath - Full path to the remote file.
      AsciiFile - If True then end of line characters will be converted as needed. Note that Android end of line character is the same as Unix / Linux.
      DeviceFolder - Folder that the file will be saved to.
      DeviceFile - The name of the local file that will be created.
      RestartOffset - The first byte to request if resuming an incomplete download. Pass 0 if you wish to download the entire file.
    • Initialize (EventName As String, Host As String, Port As Int, User As String, Password As String)
      Initializes the object and sets the subs that will handle the events
    • IsInitialized As Boolean
      Tests whether the object was initialized.
    • List (ServerPath As String)
      Fetches the list of folders and files in the specified path.
      The ListCompleted event will be raised when the data is available.
    • SendCommand (Command As String, Parameters As String)
      Sends an FTP command. The CommandCompleted event will be raised with the server reply.
      Should only be used with commands that return the reply in the command channel (not the data channel).
      It is possible that Success will be false and LastException will not be initialized.
      Common commands:
      MKD - Creates a new folder.
      RMD - Deletes an empty folder.
      Example:<code>
      FTP.SendCommand("MKD", "/somefolder/newfolder")</code>
    • SetCustomSSLTrustManager (TrustManager As Object)
    • UploadFileResume (DeviceFolder As String, DeviceFile As String, AsciiFile As Boolean, ServerFilePath As String, RestartOffset As Long)
      Uploads a file to the server.
      The UploadCompleted event will be raised when upload completes.
      UploadProgress events will be raised during the upload.
      DeviceFolder - Local folder.
      DeviceFile - Local file name.
      AsciiFile - If True then end of line characters will be converted as needed. Note that Android end of line character is the same as Unix / Linux.
      ServerFilePath - Full path to file that will be created on the server.
      RestartOffset - The first byte to send if resuming an incomplete upload. Pass 0 if you wish to upload the entire file.
    Permissions:
    • android.permission.INTERNET
    Properties:
    • PassiveMode As Boolean
      Gets or sets whether FTP is in passive mode. The default mode is active mode.
    • UseSSL As Boolean
      Gets or sets whether the connection should be done with SSL sockets (FTPS Implicit).
    • UseSSLExplicit As Boolean
      Gets or sets whether the connection should be done with SSL sockets (FTPS Explicit).
  • SMTPExtras
    Events:
    • MessageSent (Success As Boolean)
    • MessageSent2 (Success As Boolean, Tag As Object)
    Fields:
    • AUTH_CRAM_MD5 As AUTH_METHOD
    • AUTH_LOGIN As AUTH_METHOD
    • AUTH_PLAIN As AUTH_METHOD
    • Sender As String
      Gets or sets the Sender field. By default it is the same as the Username.
    Methods:
    • AddAttachment (Dir As String, FileName As String)
      Adds a file attachment.
    • AddHeader (HeaderField As String, HeaderValue As String)
      Adds a header field and header value.
    • Initialize (Server As String, Port As Int, Username As String, Password As String, EventName As String)
      Initializes the object.
      Server - Server address. Host name or Ip.
      Port - Mail server port.
      Username - Account user name.
      Password - Account password.
      EventName - The name of the sub that will handle the MessageSent event.
    • Send
      Sends the message. The MessageSent event will be raised after the message was sent.
      Note that the message fields are cleared after this method to allow you to send new messages with the same object.
    Permissions:
    • android.permission.INTERNET
    Properties:
    • AuthMethod As AUTH_METHOD
      Gets or sets the SMTP AUTH method. Default value is PLAIN.
    • BCC As List
      Gets or sets the list of "BCC" recipients.
    • Body As String
      Gets or sets the message body.
    • CC As List
      Gets or sets the list of "CC" recipients.
    • DefaultTimeout As Int [write only]
      Set the default timeout in milliseconds to use when opening a socket.
      Default value is 60000.
    • HtmlBody As Boolean
      Gets or sets whether this message body is Html text.
    • SoTimeout As Int [write only]
      Set the timeout in milliseconds of a currently open socket connection.
      Default value is 60000.
    • StartTLSMode As Boolean
      Gets or sets whether the connection should be done in StartTLS mode.
    • Subject As String
      Gets or sets the message subject.
    • Tag As Object
      Gets or Sets a Tag object for the email task to be sent.
      If a Tag object is set then the Send method will raise the event MessageSent2(Success As Boolean, Tag As Object) instead of the event MessageSent(Success As Boolean).
      A unique Tag object can therefore be used to identify which email has been sent.
    • To As List
      Gets or sets the list of "To" recipients.
      Example:<code>SMTP.To.Add("email@example.com")</code>
    • UseSSL As Boolean
      Gets or sets whether the connection should be done with SSL sockets.

So FTPResume is nearly a drop in replacement for the existing FTP object.
The differences are in the DownloadFileResume and UploadFileResume methods where a RestartOffset parameter is required.
If you pass zero as the RestartOffset parameter then the FTPResume methods will function exactly as the equivalent FTP object methods.
Otherwise the methods will begin an upload or download from the byte specified by ResumeOffset.

It is likely that the FTP server you are connecting to must support resume - if you have problems with resume check that the FTP server supports it.

I have made the version of NetExtras 1.20 to match the verison of the Net library that it modifies - there are no versions prior to 1.20.

Martin.
 

Attachments

  • NetExtras_library_files_v1.52.zip
    30.3 KB · Views: 818
Last edited:

biometrics

Active Member
Licensed User
Longtime User
This solves critical missing functionality in the FTP component. Without it our project was crippled when transferring large files over wireless networks, especially when signals were weak.

Thanks Martin, it was a pleasure working with you.

I can highly recommend Martin for your library development needs.

:sign0098:
 

enrico

Active Member
Licensed User
Longtime User
Just trying to move from Net to NetExtras an I get :
java.lang.NoClassDefFoundError: org.apache.commons.net.ftp.FTPClient

(Java is version 6)
 

warwound

Expert
Licensed User
Longtime User
Just trying to move from Net to NetExtras an I get :
java.lang.NoClassDefFoundError: org.apache.commons.net.ftp.FTPClient

(Java is version 6)

I'd guess that you have included NetExtras but not the standard B4A Net library in your project.

Both are required - NetExtras offers the FTPResume object as an alternative to the FTP object.
But the standard B4A Net library must also be included as it contains other objects required by FTPResume.

Martin.
 

enrico

Active Member
Licensed User
Longtime User
I'd guess that you have included NetExtras but not the standard B4A Net library in your project.

Both are required - NetExtras offers the FTPResume object as an alternative to the FTP object.
But the standard B4A Net library must also be included as it contains other objects required by FTPResume.

Martin.

ok
 

warwound

Expert
Licensed User
Longtime User
NetExtras updated to version 1.201

This update adds a new object to the library, the SMTPExtras object.
SMTPExtras adds two new features to the original SMTP object:
  • You can use the new AddHeader (HeaderField As String, HeaderValue As String) method to set header fields in the email.
  • You can set the SMTPExtras Tag property, SMTPExtras will now raise the event MessageSent2(Success As Boolean, Tag As Object) instead of raising the event MessageSent(Success As Boolean).
    Setting a unique Tag value for each sent email therefore enables you to identify which email has been (successfully or unsuccessfully) sent.

In order to use NetExtras you must also use (check in the IDE) the default B4A Net library.

SMTPExtras is a drop in replacement for the default SMTP object - change all instances of SMTP object to instances of SMTPExtras object and your code will function the same, you can now use the AddHeader method if required.
If you set the new SMTPExtras Tag property you will need a Sub that listens for the MessageSent2(Success As Boolean, Tag As Object) event instead of the MessageSent(Success As Boolean) event.

Here's a simple example:

B4X:
Sub Process_Globals
   Dim SMTPExtras1 As SMTPExtras
End Sub

Sub Globals
   Dim Button1 As Button
   Dim Button2 As Button
End Sub

Sub Activity_Create(FirstTime As Boolean)
  If FirstTime Then
  SMTPExtras1.Initialize("smtp.gmail.com", 465, "example@gmail.com", "mypassword", "SMTPExtras1")
  SMTPExtras1.UseSSL = True   '   Gmail requires SSL.
  End If
  
   Button1.Initialize("Button1")
   Button1.Text="Send an email"
   Activity.AddView(Button1, 0, 0, 100%x, 64dip)
  
   Button2.Initialize("Button2")
   Button2.Text="Bulk send emails"
   Activity.AddView(Button2, 0, 64dip, 100%x, 64dip)
  
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Sub Button1_Click
   '   this Sub demonstrates use of the new AddHeader method
   '   SMTPExtras raises the event MessageSent(Success As Boolean) once the message has been (successfully or unsuccessfully) sent.
   Button1.Enabled=False
  SMTPExtras1.To.Add("othermail@example.com")
  SMTPExtras1.Subject = "SMTPExtras is go!"
  SMTPExtras1.Body = "This is the message body."
  
   SMTPExtras1.AddHeader("MyField", "MyValue:"&DateTime.Now)
  
  SMTPExtras1.Send
End Sub

Sub Button2_Click
   '   this Sub demonstrates the new Tag property
   '   it sends 4 emails one after the other
   '   SMTPExtras raises the event MessageSent2(Success As Boolean, Tag As Object) once each message has been (successfully or unsuccessfully) sent.
   '   the unique integer Tag value i'm setting allows me to identify which email sending has raised the MessageSent2 event.
   Dim i As Int
   For i=0 To 3
    SMTPExtras1.To.Add("othermail@example.com")
    SMTPExtras1.Subject = "SMTPExtras bulk email #"&i
    SMTPExtras1.Body = "This is the message body of bulk email #"&i
    
     SMTPExtras1.AddHeader("MyField", "MyValue "&i&" :"&DateTime.Now)
    
     SMTPExtras1.AddHeader("AnotherHeaderField", "Value: "&i)
    
     SMTPExtras1.Tag=i
    
     '   if you uncomment the next line then you'll see that the MessageSent(Success As Boolean) event is raised instead of the MessageSent2(Success As Boolean, Tag As Object) event
     '   SMTPExtras1.Tag=Null
    
    SMTPExtras1.Send
   Next
End Sub

Sub SMTPExtras1_MessageSent(Success As Boolean)
   '   the event MessageSent(Success As Boolean) is identical to the same event in the default SMTP object
  Log("SMTPExtras1_MessageSent "&Success)
  If Success Then
  ToastMessageShow("Message sent successfully", True)
  Else
  ToastMessageShow("Error sending message", True)
  Log(LastException.Message)
  End If
   Button1.Enabled=True
End Sub

Sub SMTPExtras1_MessageSent2(Success As Boolean, Tag As Object)
   '   MessageSent2(Success As Boolean, Tag As Object) is a new event introduced in SMTPExtras
  
   '   if you set the SMTPExtras Tag property to a value then SMTPEXtras will raise the event MessageSent2(Success As Boolean, Tag As Object)
   '   if you do not set the SMTPExtras Tag property, or you set it to Null, then SMTPExtras will instead raise the event MessageSent(Success As Boolean)
  
   Log("SMTPExtras1_MessageSent2 "&Success&", "&Tag)
  If Success Then
  ToastMessageShow("Message "&Tag&" sent successfully", True)
  Else
  ToastMessageShow("Error sending message "&Tag, True)
  Log(LastException.Message)
  End If
End Sub

The example displays two Buttons.
Click one Button to send a single email, click the other Button to send 4 emails one after the other.

I think the code comments explain all you need to know.

Version 1.201 of NetExtras is attached to the first post in this thread.

Note that in the B4A IDE version 1.201 will show as version 1.20, seems the IDE only displays the first 2 decimal places of the version.
The included HTML reference document shows version 1.201 though.
As this version of NetExtras is based on version 1.20 of the Net library i decided to make it version 1.201 anyway and hope the IDE doesn't cause any confusion.

Martin.
 

Attachments

  • SMTPExtrasExample.zip
    6.6 KB · Views: 482

markoates

New Member
Licensed User
Longtime User
Thanks Martin, the new SMTP Header is just what we needed to move forward on the project we are working at the moment. Very much appreciated.
 

warwound

Expert
Licensed User
Longtime User
NetExtras updated to version 1.202

This update adds 2 new properties to the SMTPExtras object:
  • DefaultTimeout As Int [write only]
    Set the default timeout in milliseconds to use when opening a socket.
    Default value is 60000.
  • SoTimeout As Int [write only]
    Set the timeout in milliseconds of a currently open socket connection.
    Default value is 60000.
Version 1.202 is attached to the first post in this thread.
Martin.
 

warwound

Expert
Licensed User
Longtime User
@biometrics

I swapped the old version 1.20 Net library source for the new version 1.51 (kindly provided by Erel so thanks to Erel there).
The project compiled without a single modification.

Can you test the attached new version and report your findings?

Thanks.

Martin.
 

warwound

Expert
Licensed User
Longtime User
NetExtras updated to version 1.52

This update simply recompiles the library using version 1.52 of the b4a Net library - version 1.52 of the Net library is currently the latest version.

Version 1.52 of NetExtras is attached to the first post in this thread.

Martin.
 

warwound

Expert
Licensed User
Longtime User
NetExtras version 1.52 error

The version 1.52 of NetExtras i uploaded earlier was missing some methods.
Only 3 forum members have so far downloaded that version 1.52 of NetExtras with the missing methods.
Post #1 now contains the correct and updated NetExtras with all methods.

Can i ask those three members to download the updated version 1.52 which contains the new methods?

Thanks.

Martin.
 

schimanski

Well-Known Member
Licensed User
Longtime User
Sorry for this question, but how do i know the last up- or dowloaded byte to set it in ResumeOffset? With file.size?
 

MMORETTI964

Member
Licensed User
Longtime User
I'm founding some misterious problem for some user in FTPResume using B4A 4.xx, could be due to net 1.53 and netextras 1.52?
It needs a new compilation?
@warwound, could you help? Many Thanks.
Maurizio
 

Tommaso

Member
Licensed User
Longtime User
I'm founding some misterious problem for some user in FTPResume using B4A 4.xx, could be due to net 1.53 and netextras 1.52?
It needs a new compilation?
@warwound, could you help? Many Thanks.
Maurizio

After a long debug with my colleague we've found that NetExtras has a problem in CloseNow function during SSL in a Data Connection.
The problem should be near the old 1.52 problem solved in last Erel version net lib.
Here the details:

android.os.NetworkOnMainThreadException

at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1156)
at com.android.org.conscrypt.OpenSSLSocketImpl.close(OpenSSLSocketImpl.java:1009)
at org.apache.commons.net.SocketClient.closeQuietly(SocketClient.java:309)
at org.apache.commons.net.SocketClient.disconnect(SocketClient.java:298)
at org.apache.commons.net.ftp.FTP.disconnect(FTP.java:434)
at org.apache.commons.net.ftp.FTPClient.disconnect(FTPClient.java:843)
at uk.co.martinpearman.b4a.netextras.FTPResume.CloseNow(FTPResume.java:471)
at com.palmosoft.primaprova.main._effetipi_uploadprogress(main.java:464)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:187)
at anywheresoftware.b4a.BA$3.run(BA.java:332)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:157)
at android.app.ActivityThread.main(ActivityThread.java:5356)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1265)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1081)
at dalvik.system.NativeStart.main(Native Method)

Attached a sample project to reproduce the issue.
If you haven't time to solve the problem, if you can share the java source we can try to solve ourselves (and reshare the library with you).

@Erel: do you think is possible (should possible) to use a self-signed certificate with implicit ftp using net lib?

Thanks in advance.
 

Attachments

  • Test.zip
    13.4 KB · Views: 296
Top