This is an automated email from the ASF dual-hosted git repository.

hansva pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/hop.git


The following commit(s) were added to refs/heads/main by this push:
     new bd4726d5f9 Fix #5518, Fix #6168, Fix #6475 (#6412)
bd4726d5f9 is described below

commit bd4726d5f915242403b7dd3c72c5b791d3d36b7c
Author: Sergio Ramazzina <[email protected]>
AuthorDate: Mon Feb 2 13:39:31 2026 +0100

    Fix #5518, Fix #6168, Fix #6475 (#6412)
    
    * WIP
    
    * Fix #5518 - Get a file with SFTP - modification timestamp is altered with 
current time
    
    * Fix #6168 - "FTP delete" action disables use of key+passphrase when using 
SFTP
    
    * Fixed Unit Tests
    
    * Documentation update
    
    * Fix #6168 - "FTP delete" action disables use of key+passphrase when using 
SFTP
    
    * Fix #6475 - Put a file with SFTP - modification timestamp is altered with 
current timestamp
    
    * Fix #6475 - Fixed failed unit test
    
    * Added integration tests for both #6475 and #5518
---
 .../integration-tests/integration-tests-sftp.yaml  |  30 +
 .../modules/ROOT/pages/workflow/actions/sftp.adoc  |   1 +
 .../ROOT/pages/workflow/actions/sftpput.adoc       |   3 +-
 .../sftp/001-get-final-lastmodified-value.hpl      | 155 ++++
 .../sftp/001-get-initial-lastmodified-value.hpl    | 163 ++++
 integration-tests/sftp/dev-env-config.json         |  24 +
 integration-tests/sftp/files/test.txt              |   1 +
 integration-tests/sftp/hop-config.json             | 290 +++++++
 ...main-001-sftp-get-preserve-lasmodified-date.hwf | 268 +++++++
 .../metadata/pipeline-run-configuration/local.json |  22 +
 .../metadata/workflow-run-configuration/local.json |  11 +
 integration-tests/sftp/project-config.json         |  13 +
 lib/pom.xml                                        |   2 +-
 .../actions/ftpdelete/ActionFtpDelete.java         |  11 +-
 .../actions/ftpdelete/ActionFtpDeleteDialog.java   |  11 +-
 .../hop/workflow/actions/sftp/ActionSftp.java      | 367 ++-------
 .../workflow/actions/sftp/ActionSftpDialog.java    | 887 +++++++++++----------
 .../apache/hop/workflow/actions/sftp/FileItem.java |  39 +
 .../hop/workflow/actions/sftp/SftpClient.java      |  47 +-
 .../workflow/actions/sftpput/ActionSftpPut.java    | 313 +-------
 .../actions/sftpput/ActionSftpPutDialog.java       |  79 +-
 .../sftp/messages/messages_en_US.properties        |   2 +
 .../sftp/messages/messages_it_IT.properties        |   2 +
 .../sftpput/messages/messages_en_US.properties     |   2 +
 .../sftpput/messages/messages_it_IT.properties     |   2 +
 .../sftp/WorkflowActionSftpLoadSaveTest.java       |   7 +-
 .../sftpput/WorkflowActionSftpPutLoadSaveTest.java |  11 +-
 27 files changed, 1705 insertions(+), 1058 deletions(-)

diff --git a/docker/integration-tests/integration-tests-sftp.yaml 
b/docker/integration-tests/integration-tests-sftp.yaml
new file mode 100644
index 0000000000..6b9d3cba7a
--- /dev/null
+++ b/docker/integration-tests/integration-tests-sftp.yaml
@@ -0,0 +1,30 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+services:
+  integration_test_sftp:
+    extends:
+      file: integration-tests-base.yaml
+      service: integration_test
+    links:
+      - sftp-server
+
+  sftp-server:
+    image: atmoz/sftp:latest
+    ports:
+      - 2222:22
+    command: foo:pass:::upload
diff --git a/docs/hop-user-manual/modules/ROOT/pages/workflow/actions/sftp.adoc 
b/docs/hop-user-manual/modules/ROOT/pages/workflow/actions/sftp.adoc
index 536a78a347..124dfbfaf9 100644
--- a/docs/hop-user-manual/modules/ROOT/pages/workflow/actions/sftp.adoc
+++ b/docs/hop-user-manual/modules/ROOT/pages/workflow/actions/sftp.adoc
@@ -89,6 +89,7 @@ A.*[ENG:0-9].txt  : files tarting with A, ending with a 
number and .txt
 2+|*Target files*
 |Target Directory|The directory on the machine on which Hop runs in which you 
want to place the transferred files
 |Create target folder|Check this option if the destination folder does not 
exist and should be created.
+|Preserve timestamp|If checked the last modified timestamp of the source file 
is preserved in the downloaded file. If not checked, the downloaded file will 
have the last modified timestamp updated to the instant when the file's 
download happens.
 |Add filenames to result|If checked the information about downloaded files is 
added to the result files stream.
 |===
 
diff --git 
a/docs/hop-user-manual/modules/ROOT/pages/workflow/actions/sftpput.adoc 
b/docs/hop-user-manual/modules/ROOT/pages/workflow/actions/sftpput.adoc
index 8eddb288d3..157525098f 100644
--- a/docs/hop-user-manual/modules/ROOT/pages/workflow/actions/sftpput.adoc
+++ b/docs/hop-user-manual/modules/ROOT/pages/workflow/actions/sftpput.adoc
@@ -97,7 +97,8 @@ The destination on the source file for the move is specified 
here.
 Use to browse button to browse to destination folder.
 |Create destination folder|Enabled if `After SFTP Put` is set to `Move file 
to`.
 If the `Destination folder` does not exists check this option to create it.
-|Add filename to to result|Enabled if `After SFTP Put` is seet to `Do nothing`.
+|Preserve timestamp|If checked the last modified timestamp of the source file 
is preserved in the uploaded file. If not checked, the uploaded file will have 
the last modified timestamp updated to the instant when the file's upload 
happens.
+|Add filename to result|Enabled if `After SFTP Put` is set to `Do nothing`.
 If checked the name of the file is added to the result stream.
 2+|*Target (remote) folder*
 |Remote directory|The remote directory on the SFTP server in which the files 
will be uploaded.
diff --git a/integration-tests/sftp/001-get-final-lastmodified-value.hpl 
b/integration-tests/sftp/001-get-final-lastmodified-value.hpl
new file mode 100644
index 0000000000..4bc363d743
--- /dev/null
+++ b/integration-tests/sftp/001-get-final-lastmodified-value.hpl
@@ -0,0 +1,155 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-->
+<pipeline>
+  <info>
+    <name>001-get-final-lastmodified-value</name>
+    <name_sync_with_filename>Y</name_sync_with_filename>
+    <description/>
+    <extended_description/>
+    <pipeline_version/>
+    <pipeline_type>Normal</pipeline_type>
+    <parameters>
+    </parameters>
+    <capture_transform_performance>N</capture_transform_performance>
+    
<transform_performance_capturing_delay>1000</transform_performance_capturing_delay>
+    
<transform_performance_capturing_size_limit>100</transform_performance_capturing_size_limit>
+    <created_user>-</created_user>
+    <created_date>2026/01/30 11:24:35.986</created_date>
+    <modified_user>-</modified_user>
+    <modified_date>2026/01/30 11:24:35.986</modified_date>
+  </info>
+  <notepads>
+  </notepads>
+  <order>
+    <hop>
+      <from>Get file names</from>
+      <to>Get initial lastmodified value</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>Get initial lastmodified value</from>
+      <to>Set variables</to>
+      <enabled>Y</enabled>
+    </hop>
+  </order>
+  <transform>
+    <name>Get file names</name>
+    <type>GetFileNames</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <doNotFailIfNoFile>N</doNotFailIfNoFile>
+    <dynamic_include_subfolders>N</dynamic_include_subfolders>
+    <exclude_wildcard_Field/>
+    <file>
+      <exclude_filemask/>
+      <file_required>N</file_required>
+      <filemask>.*.txt</filemask>
+      <include_subfolders>N</include_subfolders>
+      <name>/tmp</name>
+    </file>
+    <filefield>N</filefield>
+    <filename_Field/>
+    <filter>
+      <filterfiletype>all_files</filterfiletype>
+    </filter>
+    <isaddresult>Y</isaddresult>
+    <limit>0</limit>
+    <raiseAnExceptionIfNoFile>N</raiseAnExceptionIfNoFile>
+    <rownum>N</rownum>
+    <rownum_field/>
+    <wildcard_Field/>
+    <attributes/>
+    <GUI>
+      <xloc>240</xloc>
+      <yloc>80</yloc>
+    </GUI>
+  </transform>
+  <transform>
+    <name>Get initial lastmodified value</name>
+    <type>SelectValues</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <fields>
+      <field>
+        <length>-2</length>
+        <name>lastmodifiedtime</name>
+        <precision>-2</precision>
+      </field>
+      <meta>
+        <conversion_mask>yyyyMMddHHmmss</conversion_mask>
+        <date_format_lenient>N</date_format_lenient>
+        <length>-2</length>
+        <lenient_string_to_number>N</lenient_string_to_number>
+        <name>lastmodifiedtime</name>
+        <precision>-2</precision>
+        <rename>lastmodifiedtime</rename>
+        <roundingType>half_even</roundingType>
+        <storage_type/>
+        <type>String</type>
+      </meta>
+      <select_unspecified>N</select_unspecified>
+    </fields>
+    <attributes/>
+    <GUI>
+      <xloc>480</xloc>
+      <yloc>80</yloc>
+    </GUI>
+  </transform>
+  <transform>
+    <name>Set variables</name>
+    <type>SetVariable</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <fields>
+      <field>
+        <field_name>lastmodifiedtime</field_name>
+        <variable_name>v_final_lastmodified_value</variable_name>
+        <variable_type>ROOT_WORKFLOW</variable_type>
+      </field>
+    </fields>
+    <use_formatting>Y</use_formatting>
+    <attributes/>
+    <GUI>
+      <xloc>688</xloc>
+      <yloc>80</yloc>
+    </GUI>
+  </transform>
+  <transform_error_handling>
+  </transform_error_handling>
+  <attributes/>
+</pipeline>
diff --git a/integration-tests/sftp/001-get-initial-lastmodified-value.hpl 
b/integration-tests/sftp/001-get-initial-lastmodified-value.hpl
new file mode 100644
index 0000000000..f176ee9007
--- /dev/null
+++ b/integration-tests/sftp/001-get-initial-lastmodified-value.hpl
@@ -0,0 +1,163 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-->
+<pipeline>
+  <info>
+    <name>001-get-initial-lastmodified-value</name>
+    <name_sync_with_filename>Y</name_sync_with_filename>
+    <description/>
+    <extended_description/>
+    <pipeline_version/>
+    <pipeline_type>Normal</pipeline_type>
+    <parameters>
+    </parameters>
+    <capture_transform_performance>N</capture_transform_performance>
+    
<transform_performance_capturing_delay>1000</transform_performance_capturing_delay>
+    
<transform_performance_capturing_size_limit>100</transform_performance_capturing_size_limit>
+    <created_user>-</created_user>
+    <created_date>2026/01/30 11:24:35.986</created_date>
+    <modified_user>-</modified_user>
+    <modified_date>2026/01/30 11:24:35.986</modified_date>
+  </info>
+  <notepads>
+  </notepads>
+  <order>
+    <hop>
+      <from>Get file names</from>
+      <to>Get initial lastmodified value</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>Get initial lastmodified value</from>
+      <to>Set variables</to>
+      <enabled>Y</enabled>
+    </hop>
+  </order>
+  <transform>
+    <name>Get file names</name>
+    <type>GetFileNames</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <doNotFailIfNoFile>N</doNotFailIfNoFile>
+    <dynamic_include_subfolders>N</dynamic_include_subfolders>
+    <exclude_wildcard_Field/>
+    <file>
+      <exclude_filemask/>
+      <file_required>N</file_required>
+      <filemask>.*.txt</filemask>
+      <include_subfolders>N</include_subfolders>
+      <name>${PROJECT_HOME}/files</name>
+    </file>
+    <filefield>N</filefield>
+    <filename_Field/>
+    <filter>
+      <filterfiletype>all_files</filterfiletype>
+    </filter>
+    <isaddresult>Y</isaddresult>
+    <limit>0</limit>
+    <raiseAnExceptionIfNoFile>N</raiseAnExceptionIfNoFile>
+    <rownum>N</rownum>
+    <rownum_field/>
+    <wildcard_Field/>
+    <attributes/>
+    <GUI>
+      <xloc>240</xloc>
+      <yloc>80</yloc>
+    </GUI>
+  </transform>
+  <transform>
+    <name>Get initial lastmodified value</name>
+    <type>SelectValues</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <fields>
+      <field>
+        <length>-2</length>
+        <name>lastmodifiedtime</name>
+        <precision>-2</precision>
+        <rename/>
+      </field>
+      <meta>
+        <conversion_mask>yyyyMMddHHmmss</conversion_mask>
+        <currency_symbol/>
+        <date_format_lenient>N</date_format_lenient>
+        <date_format_locale/>
+        <date_format_timezone/>
+        <decimal_symbol/>
+        <encoding/>
+        <grouping_symbol/>
+        <length>-2</length>
+        <lenient_string_to_number>N</lenient_string_to_number>
+        <name>lastmodifiedtime</name>
+        <precision>-2</precision>
+        <rename>lastmodifiedtime</rename>
+        <roundingType>half_even</roundingType>
+        <storage_type/>
+        <type>String</type>
+      </meta>
+      <select_unspecified>N</select_unspecified>
+    </fields>
+    <attributes/>
+    <GUI>
+      <xloc>480</xloc>
+      <yloc>80</yloc>
+    </GUI>
+  </transform>
+  <transform>
+    <name>Set variables</name>
+    <type>SetVariable</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <fields>
+      <field>
+        <default_value/>
+        <field_name>lastmodifiedtime</field_name>
+        <variable_name>v_initial_lastmodified_value</variable_name>
+        <variable_type>ROOT_WORKFLOW</variable_type>
+      </field>
+    </fields>
+    <use_formatting>Y</use_formatting>
+    <attributes/>
+    <GUI>
+      <xloc>688</xloc>
+      <yloc>80</yloc>
+    </GUI>
+  </transform>
+  <transform_error_handling>
+  </transform_error_handling>
+  <attributes/>
+</pipeline>
diff --git a/integration-tests/sftp/dev-env-config.json 
b/integration-tests/sftp/dev-env-config.json
new file mode 100644
index 0000000000..e533f24624
--- /dev/null
+++ b/integration-tests/sftp/dev-env-config.json
@@ -0,0 +1,24 @@
+{
+  "variables" : [
+    {
+      "name" : "SFTP_HOSTNAME",
+      "value" : "sftp-server",
+      "description" : ""
+    },
+    {
+      "name" : "SFTP_USER",
+      "value" : "foo",
+      "description" : ""
+    },
+    {
+      "name" : "SFTP_PASSWORD",
+      "value" : "pass",
+      "description" : ""
+    },
+    {
+      "name" : "SFTP_PORT",
+      "value" : "22",
+      "description" : ""
+    }
+  ]
+}
\ No newline at end of file
diff --git a/integration-tests/sftp/files/test.txt 
b/integration-tests/sftp/files/test.txt
new file mode 100644
index 0000000000..9f4b6d8bfe
--- /dev/null
+++ b/integration-tests/sftp/files/test.txt
@@ -0,0 +1 @@
+This is a test file
diff --git a/integration-tests/sftp/hop-config.json 
b/integration-tests/sftp/hop-config.json
new file mode 100644
index 0000000000..102ac981d5
--- /dev/null
+++ b/integration-tests/sftp/hop-config.json
@@ -0,0 +1,290 @@
+{
+  "variables": [
+    {
+      "name": "HOP_LENIENT_STRING_TO_NUMBER_CONVERSION",
+      "value": "N",
+      "description": "System wide flag to allow lenient string to number 
conversion for backward compatibility. If this setting is set to \"Y\", an 
string starting with digits will be converted successfully into a number. 
(example: 192.168.1.1 will be converted into 192 or 192.168 or 192168 depending 
on the decimal and grouping symbol). The default (N) will be to throw an error 
if non-numeric symbols are found in the string."
+    },
+    {
+      "name": "HOP_COMPATIBILITY_DB_IGNORE_TIMEZONE",
+      "value": "N",
+      "description": "System wide flag to ignore timezone while writing 
date/timestamp value to the database."
+    },
+    {
+      "name": "HOP_LOG_SIZE_LIMIT",
+      "value": "0",
+      "description": "The log size limit for all pipelines and workflows that 
don't have the \"log size limit\" property set in their respective properties."
+    },
+    {
+      "name": "HOP_EMPTY_STRING_DIFFERS_FROM_NULL",
+      "value": "N",
+      "description": "NULL vs Empty String. If this setting is set to Y, an 
empty string and null are different. Otherwise they are not."
+    },
+    {
+      "name": "HOP_MAX_LOG_SIZE_IN_LINES",
+      "value": "0",
+      "description": "The maximum number of log lines that are kept internally 
by Hop. Set to 0 to keep all rows (default)"
+    },
+    {
+      "name": "HOP_MAX_LOG_TIMEOUT_IN_MINUTES",
+      "value": "1440",
+      "description": "The maximum age (in minutes) of a log line while being 
kept internally by Hop. Set to 0 to keep all rows indefinitely (default)"
+    },
+    {
+      "name": "HOP_MAX_WORKFLOW_TRACKER_SIZE",
+      "value": "5000",
+      "description": "The maximum number of workflow trackers kept in memory"
+    },
+    {
+      "name": "HOP_MAX_ACTIONS_LOGGED",
+      "value": "5000",
+      "description": "The maximum number of action results kept in memory for 
logging purposes."
+    },
+    {
+      "name": "HOP_MAX_LOGGING_REGISTRY_SIZE",
+      "value": "10000",
+      "description": "The maximum number of logging registry entries kept in 
memory for logging purposes."
+    },
+    {
+      "name": "HOP_LOG_TAB_REFRESH_DELAY",
+      "value": "1000",
+      "description": "The hop log tab refresh delay."
+    },
+    {
+      "name": "HOP_LOG_TAB_REFRESH_PERIOD",
+      "value": "1000",
+      "description": "The hop log tab refresh period."
+    },
+    {
+      "name": "HOP_PLUGIN_CLASSES",
+      "value": null,
+      "description": "A comma delimited list of classes to scan for plugin 
annotations"
+    },
+    {
+      "name": "HOP_PLUGIN_PACKAGES",
+      "value": null,
+      "description": "A comma delimited list of packages to scan for plugin 
annotations (warning: slow!!)"
+    },
+    {
+      "name": "HOP_TRANSFORM_PERFORMANCE_SNAPSHOT_LIMIT",
+      "value": "0",
+      "description": "The maximum number of transform performance snapshots to 
keep in memory. Set to 0 to keep all snapshots indefinitely (default)"
+    },
+    {
+      "name": "HOP_ROWSET_GET_TIMEOUT",
+      "value": "50",
+      "description": "The name of the variable that optionally contains an 
alternative rowset get timeout (in ms). This only makes a difference for 
extremely short lived pipelines."
+    },
+    {
+      "name": "HOP_ROWSET_PUT_TIMEOUT",
+      "value": "50",
+      "description": "The name of the variable that optionally contains an 
alternative rowset put timeout (in ms). This only makes a difference for 
extremely short lived pipelines."
+    },
+    {
+      "name": "HOP_CORE_TRANSFORMS_FILE",
+      "value": null,
+      "description": "The name of the project variable that will contain the 
alternative location of the hop-transforms.xml file. You can use this to 
customize the list of available internal transforms outside of the codebase."
+    },
+    {
+      "name": "HOP_CORE_WORKFLOW_ACTIONS_FILE",
+      "value": null,
+      "description": "The name of the project variable that will contain the 
alternative location of the hop-workflow-actions.xml file."
+    },
+    {
+      "name": "HOP_SERVER_OBJECT_TIMEOUT_MINUTES",
+      "value": "1440",
+      "description": "This project variable will set a time-out after which 
waiting, completed or stopped pipelines and workflows will be automatically 
cleaned up. The default value is 1440 (one day)."
+    },
+    {
+      "name": "HOP_PIPELINE_PAN_JVM_EXIT_CODE",
+      "value": null,
+      "description": "Set this variable to an integer that will be returned as 
the Pan JVM exit code."
+    },
+    {
+      "name": "HOP_DISABLE_CONSOLE_LOGGING",
+      "value": "N",
+      "description": "Set this variable to Y to disable standard Hop logging 
to the console. (stdout)"
+    },
+    {
+      "name": "HOP_REDIRECT_STDERR",
+      "value": "N",
+      "description": "Set this variable to Y to redirect stderr to Hop 
logging."
+    },
+    {
+      "name": "HOP_REDIRECT_STDOUT",
+      "value": "N",
+      "description": "Set this variable to Y to redirect stdout to Hop 
logging."
+    },
+    {
+      "name": "HOP_DEFAULT_NUMBER_FORMAT",
+      "value": null,
+      "description": "The name of the variable containing an alternative 
default number format"
+    },
+    {
+      "name": "HOP_DEFAULT_BIGNUMBER_FORMAT",
+      "value": null,
+      "description": "The name of the variable containing an alternative 
default bignumber format"
+    },
+    {
+      "name": "HOP_DEFAULT_INTEGER_FORMAT",
+      "value": null,
+      "description": "The name of the variable containing an alternative 
default integer format"
+    },
+    {
+      "name": "HOP_DEFAULT_DATE_FORMAT",
+      "value": null,
+      "description": "The name of the variable containing an alternative 
default date format"
+    },
+    {
+      "name": "HOP_DEFAULT_TIMESTAMP_FORMAT",
+      "value": null,
+      "description": "The name of the variable containing an alternative 
default timestamp format"
+    },
+    {
+      "name": "HOP_DEFAULT_SERVLET_ENCODING",
+      "value": null,
+      "description": "Defines the default encoding for servlets, leave it 
empty to use Java default encoding"
+    },
+    {
+      "name": "HOP_FAIL_ON_LOGGING_ERROR",
+      "value": "N",
+      "description": "Set this variable to Y when you want the 
workflow/pipeline fail with an error when the related logging process (e.g. to 
a database) fails."
+    },
+    {
+      "name": "HOP_AGGREGATION_MIN_NULL_IS_VALUED",
+      "value": "N",
+      "description": "Set this variable to Y to set the minimum to NULL if 
NULL is within an aggregate. Otherwise by default NULL is ignored by the MIN 
aggregate and MIN is set to the minimum value that is not NULL. See also the 
variable HOP_AGGREGATION_ALL_NULLS_ARE_ZERO."
+    },
+    {
+      "name": "HOP_AGGREGATION_ALL_NULLS_ARE_ZERO",
+      "value": "N",
+      "description": "Set this variable to Y to return 0 when all values 
within an aggregate are NULL. Otherwise by default a NULL is returned when all 
values are NULL."
+    },
+    {
+      "name": "HOP_COMPATIBILITY_TEXT_FILE_OUTPUT_APPEND_NO_HEADER",
+      "value": "N",
+      "description": "Set this variable to Y for backward compatibility for 
the Text File Output transform. Setting this to Ywill add no header row at all 
when the append option is enabled, regardless if the file is existing or not."
+    },
+    {
+      "name": "HOP_PASSWORD_ENCODER_PLUGIN",
+      "value": "Hop",
+      "description": "Specifies the password encoder plugin to use by ID (Hop 
is the default)."
+    },
+    {
+      "name": "HOP_SYSTEM_HOSTNAME",
+      "value": null,
+      "description": "You can use this variable to speed up hostname lookup. 
Hostname lookup is performed by Hop so that it is capable of logging the server 
on which a workflow or pipeline is executed."
+    },
+    {
+      "name": "HOP_SERVER_JETTY_ACCEPTORS",
+      "value": null,
+      "description": "A variable to configure jetty option: acceptors for 
Carte"
+    },
+    {
+      "name": "HOP_SERVER_JETTY_ACCEPT_QUEUE_SIZE",
+      "value": null,
+      "description": "A variable to configure jetty option: acceptQueueSize 
for Carte"
+    },
+    {
+      "name": "HOP_SERVER_JETTY_RES_MAX_IDLE_TIME",
+      "value": null,
+      "description": "A variable to configure jetty option: 
lowResourcesMaxIdleTime for Carte"
+    },
+    {
+      "name": 
"HOP_COMPATIBILITY_MERGE_ROWS_USE_REFERENCE_STREAM_WHEN_IDENTICAL",
+      "value": "N",
+      "description": "Set this variable to Y for backward compatibility for 
the Merge Rows (diff) transform. Setting this to Y will use the data from the 
reference stream (instead of the comparison stream) in case the compared rows 
are identical."
+    },
+    {
+      "name": "HOP_SPLIT_FIELDS_REMOVE_ENCLOSURE",
+      "value": "false",
+      "description": "Set this variable to false to preserve enclosure symbol 
after splitting the string in the Split fields transform. Changing it to true 
will remove first and last enclosure symbol from the resulting string chunks."
+    },
+    {
+      "name": "HOP_ALLOW_EMPTY_FIELD_NAMES_AND_TYPES",
+      "value": "false",
+      "description": "Set this variable to TRUE to allow your pipeline to pass 
'null' fields and/or empty types."
+    },
+    {
+      "name": "HOP_GLOBAL_LOG_VARIABLES_CLEAR_ON_EXPORT",
+      "value": "false",
+      "description": "Set this variable to false to preserve global log 
variables defined in pipeline / workflow Properties -> Log panel. Changing it 
to true will clear it when export pipeline / workflow."
+    },
+    {
+      "name": "HOP_FILE_OUTPUT_MAX_STREAM_COUNT",
+      "value": "1024",
+      "description": "This project variable is used by the Text File Output 
transform. It defines the max number of simultaneously open files within the 
transform. The transform will close/reopen files as necessary to insure the max 
is not exceeded"
+    },
+    {
+      "name": "HOP_FILE_OUTPUT_MAX_STREAM_LIFE",
+      "value": "0",
+      "description": "This project variable is used by the Text File Output 
transform. It defines the max number of milliseconds between flushes of files 
opened by the transform."
+    },
+    {
+      "name": "HOP_USE_NATIVE_FILE_DIALOG",
+      "value": "N",
+      "description": "Set this value to Y if you want to use the system file 
open/save dialog when browsing files"
+    },
+    {
+      "name": "HOP_AUTO_CREATE_CONFIG",
+      "value": "Y",
+      "description": "Set this value to N if you don't want to automatically 
create a hop configuration file (hop-config.json) when it's missing"
+    }
+  ],
+  "LocaleDefault": "en_BE",
+  "guiProperties": {
+    "FontFixedSize": "13",
+    "MaxUndo": "100",
+    "DarkMode": "Y",
+    "FontNoteSize": "13",
+    "ShowOSLook": "Y",
+    "FontFixedStyle": "0",
+    "FontNoteName": ".AppleSystemUIFont",
+    "FontFixedName": "Monospaced",
+    "FontGraphStyle": "0",
+    "FontDefaultSize": "13",
+    "GraphColorR": "255",
+    "FontGraphSize": "13",
+    "IconSize": "32",
+    "BackgroundColorB": "255",
+    "FontNoteStyle": "0",
+    "FontGraphName": ".AppleSystemUIFont",
+    "FontDefaultName": ".AppleSystemUIFont",
+    "GraphColorG": "255",
+    "UseGlobalFileBookmarks": "Y",
+    "FontDefaultStyle": "0",
+    "GraphColorB": "255",
+    "BackgroundColorR": "255",
+    "BackgroundColorG": "255",
+    "WorkflowDialogStyle": "RESIZE,MAX,MIN",
+    "LineWidth": "1",
+    "ContextDialogShowCategories": "Y"
+  },
+  "projectsConfig": {
+    "enabled": true,
+    "projectMandatory": true,
+    "environmentMandatory": true,
+    "defaultProject": "default",
+    "defaultEnvironment": null,
+    "standardParentProject": "default",
+    "standardProjectsFolder": null,
+    "projectConfigurations": [
+      {
+        "projectName": "default",
+        "projectHome": "${HOP_CONFIG_FOLDER}",
+        "configFilename": "project-config.json"
+      }
+    ],
+    "lifecycleEnvironments": [
+      {
+        "name": "dev",
+        "purpose": "Testing",
+        "projectName": "default",
+        "configurationFiles": [
+          "${PROJECT_HOME}/dev-env-config.json"
+        ]
+      }
+    ],
+    "projectLifecycles": []
+  }
+}
\ No newline at end of file
diff --git 
a/integration-tests/sftp/main-001-sftp-get-preserve-lasmodified-date.hwf 
b/integration-tests/sftp/main-001-sftp-get-preserve-lasmodified-date.hwf
new file mode 100644
index 0000000000..4fbcc3fce5
--- /dev/null
+++ b/integration-tests/sftp/main-001-sftp-get-preserve-lasmodified-date.hwf
@@ -0,0 +1,268 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-->
+<workflow>
+  <name>main-001-sftp-get-preserve-lasmodified-date</name>
+  <name_sync_with_filename>Y</name_sync_with_filename>
+  <description/>
+  <extended_description/>
+  <workflow_version/>
+  <created_user>-</created_user>
+  <created_date>2025/11/17 12:35:16.622</created_date>
+  <modified_user>-</modified_user>
+  <modified_date>2025/11/17 12:35:16.622</modified_date>
+  <parameters>
+    </parameters>
+  <actions>
+    <action>
+      <name>Start</name>
+      <description/>
+      <type>SPECIAL</type>
+      <attributes/>
+      <DayOfMonth>1</DayOfMonth>
+      <doNotWaitOnFirstExecution>N</doNotWaitOnFirstExecution>
+      <hour>12</hour>
+      <intervalMinutes>60</intervalMinutes>
+      <intervalSeconds>0</intervalSeconds>
+      <minutes>0</minutes>
+      <repeat>N</repeat>
+      <schedulerType>0</schedulerType>
+      <weekDay>1</weekDay>
+      <parallel>N</parallel>
+      <xloc>50</xloc>
+      <yloc>50</yloc>
+      <attributes_hac/>
+    </action>
+    <action>
+      <name>Put a file with SFTP</name>
+      <description/>
+      <type>SFTPPUT</type>
+      <attributes/>
+      <servername>${SFTP_HOSTNAME}</servername>
+      <serverport>${SFTP_PORT}</serverport>
+      <username>${SFTP_USER}</username>
+      <password>${SFTP_PASSWORD}</password>
+      <sftpdirectory>/upload</sftpdirectory>
+      <localdirectory>${PROJECT_HOME}/files</localdirectory>
+      <wildcard>.*.txt</wildcard>
+      <copyprevious>N</copyprevious>
+      <copypreviousfiles>N</copypreviousfiles>
+      <addFilenameResut>N</addFilenameResut>
+      <usekeyfilename>N</usekeyfilename>
+      <keyfilename/>
+      <keyfilepass>Encrypted </keyfilepass>
+      <compression>none</compression>
+      <proxyType/>
+      <proxyHost/>
+      <proxyPort/>
+      <proxyUsername/>
+      <proxyPassword>Encrypted </proxyPassword>
+      <createRemoteFolder>N</createRemoteFolder>
+      <aftersftpput>nothing</aftersftpput>
+      <destinationfolder/>
+      <createdestinationfolder>N</createdestinationfolder>
+      <preserveTargetFileTimestamp>Y</preserveTargetFileTimestamp>
+      <successWhenNoFile>N</successWhenNoFile>
+      <parallel>N</parallel>
+      <xloc>432</xloc>
+      <yloc>48</yloc>
+      <attributes_hac/>
+    </action>
+    <action>
+      <name>001-get-initial-lastmodified-value.hpl</name>
+      <description/>
+      <type>PIPELINE</type>
+      <attributes/>
+      <add_date>N</add_date>
+      <add_time>N</add_time>
+      <clear_files>N</clear_files>
+      <clear_rows>N</clear_rows>
+      <create_parent_folder>N</create_parent_folder>
+      <exec_per_row>N</exec_per_row>
+      
<filename>${PROJECT_HOME}/001-get-initial-lastmodified-value.hpl</filename>
+      <loglevel>Basic</loglevel>
+      <parameters>
+        <pass_all_parameters>Y</pass_all_parameters>
+      </parameters>
+      <params_from_previous>N</params_from_previous>
+      <run_configuration>local</run_configuration>
+      <set_append_logfile>N</set_append_logfile>
+      <set_logfile>N</set_logfile>
+      <wait_until_finished>Y</wait_until_finished>
+      <parallel>N</parallel>
+      <xloc>208</xloc>
+      <yloc>48</yloc>
+      <attributes_hac/>
+    </action>
+    <action>
+      <name>Get a file with SFTP</name>
+      <description/>
+      <type>SFTP</type>
+      <attributes/>
+      <servername>${SFTP_HOSTNAME}</servername>
+      <serverport>${SFTP_PORT}</serverport>
+      <username>${SFTP_USER}</username>
+      <password>${SFTP_PASSWORD}</password>
+      <sftpdirectory>/upload</sftpdirectory>
+      <targetdirectory>/tmp</targetdirectory>
+      <wildcard>.*.txt</wildcard>
+      <remove>N</remove>
+      <isaddresult>Y</isaddresult>
+      <preserveTargetFileTimestamp>Y</preserveTargetFileTimestamp>
+      <createtargetfolder>N</createtargetfolder>
+      <copyprevious>N</copyprevious>
+      <usekeyfilename>N</usekeyfilename>
+      <keyfilename/>
+      <keyfilepass>Encrypted </keyfilepass>
+      <compression>none</compression>
+      <proxyType/>
+      <proxyHost/>
+      <proxyPort/>
+      <proxyUsername/>
+      <proxyPassword>Encrypted </proxyPassword>
+      <parallel>N</parallel>
+      <xloc>624</xloc>
+      <yloc>48</yloc>
+      <attributes_hac/>
+    </action>
+    <action>
+      <name>001-get-final-lastmodified-value.hpl</name>
+      <description/>
+      <type>PIPELINE</type>
+      <attributes/>
+      <add_date>N</add_date>
+      <add_time>N</add_time>
+      <clear_files>N</clear_files>
+      <clear_rows>N</clear_rows>
+      <create_parent_folder>N</create_parent_folder>
+      <exec_per_row>N</exec_per_row>
+      <filename>${PROJECT_HOME}/001-get-final-lastmodified-value.hpl</filename>
+      <logext/>
+      <logfile/>
+      <loglevel>Basic</loglevel>
+      <parameters>
+        <pass_all_parameters>Y</pass_all_parameters>
+      </parameters>
+      <params_from_previous>N</params_from_previous>
+      <run_configuration>local</run_configuration>
+      <set_append_logfile>N</set_append_logfile>
+      <set_logfile>N</set_logfile>
+      <wait_until_finished>Y</wait_until_finished>
+      <parallel>N</parallel>
+      <xloc>864</xloc>
+      <yloc>48</yloc>
+      <attributes_hac/>
+    </action>
+    <action>
+      <name>Check if lastmodifed is preserved</name>
+      <description/>
+      <type>SIMPLE_EVAL</type>
+      <attributes/>
+      <comparevalue>${v_initial_lastmodified_value}</comparevalue>
+      <fieldname>lastmodified</fieldname>
+      <fieldtype>string</fieldtype>
+      <successbooleancondition>true</successbooleancondition>
+      <successcondition>equal</successcondition>
+      <successnumbercondition>equal</successnumbercondition>
+      <successwhenvarset>N</successwhenvarset>
+      <valuetype>variable</valuetype>
+      <variablename>${v_final_lastmodified_value}</variablename>
+      <parallel>N</parallel>
+      <xloc>1200</xloc>
+      <yloc>48</yloc>
+      <attributes_hac/>
+    </action>
+    <action>
+      <name>Success</name>
+      <description/>
+      <type>SUCCESS</type>
+      <attributes/>
+      <parallel>N</parallel>
+      <xloc>1424</xloc>
+      <yloc>48</yloc>
+      <attributes_hac/>
+    </action>
+    <action>
+      <name>Abort - Last modified date is not preserved</name>
+      <description/>
+      <type>ABORT</type>
+      <attributes/>
+      <always_log_rows>Y</always_log_rows>
+      <message>Last modified date is not preserved</message>
+      <parallel>N</parallel>
+      <xloc>1200</xloc>
+      <yloc>240</yloc>
+      <attributes_hac/>
+    </action>
+  </actions>
+  <hops>
+    <hop>
+      <from>Start</from>
+      <to>001-get-initial-lastmodified-value.hpl</to>
+      <enabled>Y</enabled>
+      <evaluation>Y</evaluation>
+      <unconditional>Y</unconditional>
+    </hop>
+    <hop>
+      <from>001-get-initial-lastmodified-value.hpl</from>
+      <to>Put a file with SFTP</to>
+      <enabled>Y</enabled>
+      <evaluation>Y</evaluation>
+      <unconditional>N</unconditional>
+    </hop>
+    <hop>
+      <from>Put a file with SFTP</from>
+      <to>Get a file with SFTP</to>
+      <enabled>Y</enabled>
+      <evaluation>Y</evaluation>
+      <unconditional>N</unconditional>
+    </hop>
+    <hop>
+      <from>Get a file with SFTP</from>
+      <to>001-get-final-lastmodified-value.hpl</to>
+      <enabled>Y</enabled>
+      <evaluation>Y</evaluation>
+      <unconditional>N</unconditional>
+    </hop>
+    <hop>
+      <from>Check if lastmodifed is preserved</from>
+      <to>Success</to>
+      <enabled>Y</enabled>
+      <evaluation>Y</evaluation>
+      <unconditional>N</unconditional>
+    </hop>
+    <hop>
+      <from>Check if lastmodifed is preserved</from>
+      <to>Abort - Last modified date is not preserved</to>
+      <enabled>Y</enabled>
+      <evaluation>N</evaluation>
+      <unconditional>N</unconditional>
+    </hop>
+    <hop>
+      <from>001-get-final-lastmodified-value.hpl</from>
+      <to>Check if lastmodifed is preserved</to>
+      <enabled>Y</enabled>
+      <evaluation>Y</evaluation>
+      <unconditional>N</unconditional>
+    </hop>
+  </hops>
+  <notepads>
+  </notepads>
+  <attributes/>
+</workflow>
diff --git 
a/integration-tests/sftp/metadata/pipeline-run-configuration/local.json 
b/integration-tests/sftp/metadata/pipeline-run-configuration/local.json
new file mode 100644
index 0000000000..0c0d87c84d
--- /dev/null
+++ b/integration-tests/sftp/metadata/pipeline-run-configuration/local.json
@@ -0,0 +1,22 @@
+{
+  "engineRunConfiguration": {
+    "Local": {
+      "feedback_size": "50000",
+      "sample_size": "100",
+      "sample_type_in_gui": "Last",
+      "wait_time": "20",
+      "rowset_size": "10000",
+      "safe_mode": false,
+      "show_feedback": false,
+      "topo_sort": false,
+      "gather_metrics": false,
+      "transactional": false
+    }
+  },
+  "defaultSelection": true,
+  "configurationVariables": [],
+  "name": "local",
+  "description": "",
+  "dataProfile": "",
+  "executionInfoLocationName": ""
+}
\ No newline at end of file
diff --git 
a/integration-tests/sftp/metadata/workflow-run-configuration/local.json 
b/integration-tests/sftp/metadata/workflow-run-configuration/local.json
new file mode 100644
index 0000000000..1d0cf74bae
--- /dev/null
+++ b/integration-tests/sftp/metadata/workflow-run-configuration/local.json
@@ -0,0 +1,11 @@
+{
+  "engineRunConfiguration": {
+    "Local": {
+      "safe_mode": false,
+      "transactional": false
+    }
+  },
+  "defaultSelection": true,
+  "name": "local",
+  "description": "Runs your workflows locally with the standard local Hop 
workflow engine"
+}
\ No newline at end of file
diff --git a/integration-tests/sftp/project-config.json 
b/integration-tests/sftp/project-config.json
new file mode 100644
index 0000000000..6a91171e1c
--- /dev/null
+++ b/integration-tests/sftp/project-config.json
@@ -0,0 +1,13 @@
+{
+  "metadataBaseFolder" : "${PROJECT_HOME}/metadata",
+  "unitTestsBasePath" : "${PROJECT_HOME}",
+  "dataSetsCsvFolder" : "${PROJECT_HOME}/datasets",
+  "enforcingExecutionInHome" : true,
+  "config" : {
+    "variables" : [ {
+      "name" : "HOP_LICENSE_HEADER_FILE",
+      "value" : "${PROJECT_HOME}/../asf-header.txt",
+      "description" : "This will automatically serialize the ASF license 
header into pipelines and workflows in the integration test projects"
+    } ]
+  }
+}
\ No newline at end of file
diff --git a/lib/pom.xml b/lib/pom.xml
index 203364f1e4..3e55756d0a 100644
--- a/lib/pom.xml
+++ b/lib/pom.xml
@@ -99,7 +99,7 @@
         <jetty.version>12.1.2</jetty.version>
         <jna.version>5.13.0</jna.version>
         <joda-time.version>2.12.1</joda-time.version>
-        <jsch.version>0.2.18</jsch.version>
+        <jsch.version>2.27.7</jsch.version>
         <json-simple.version>1.1.1</json-simple.version>
         <json-simple.version>1.1.1</json-simple.version>
         <json-smart.version>2.5.2</json-smart.version>
diff --git 
a/plugins/actions/ftp/src/main/java/org/apache/hop/workflow/actions/ftpdelete/ActionFtpDelete.java
 
b/plugins/actions/ftp/src/main/java/org/apache/hop/workflow/actions/ftpdelete/ActionFtpDelete.java
index 0bf5c971c6..2ce6c0bac5 100644
--- 
a/plugins/actions/ftp/src/main/java/org/apache/hop/workflow/actions/ftpdelete/ActionFtpDelete.java
+++ 
b/plugins/actions/ftp/src/main/java/org/apache/hop/workflow/actions/ftpdelete/ActionFtpDelete.java
@@ -18,6 +18,7 @@
 package org.apache.hop.workflow.actions.ftpdelete;
 
 import java.net.InetAddress;
+import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
 import java.util.regex.Matcher;
@@ -44,6 +45,7 @@ import org.apache.hop.workflow.action.ActionBase;
 import org.apache.hop.workflow.action.IAction;
 import org.apache.hop.workflow.action.validator.ActionValidatorUtils;
 import org.apache.hop.workflow.action.validator.AndValidator;
+import org.apache.hop.workflow.actions.sftp.FileItem;
 import org.apache.hop.workflow.actions.sftp.SftpClient;
 import org.apache.hop.workflow.actions.util.FtpClientUtil;
 import org.apache.hop.workflow.actions.util.IFtpConnection;
@@ -572,7 +574,14 @@ public class ActionFtpDelete extends ActionBase implements 
Cloneable, IAction, I
         sftpConnect(realServerName, realUsername, realServerPort, 
realPassword, realFtpDirectory);
 
         // Get all the files in the current directory...
-        filelist = sftpclient.dir();
+        ArrayList<FileItem> dirlist = sftpclient.dir();
+
+        if (!dirlist.isEmpty()) {
+          filelist =
+              dirlist.stream()
+                  .map(FileItem::getFileName) // adapt getter if it's named 
differently
+                  .toArray(String[]::new);
+        }
       }
 
       if (isDetailed()) {
diff --git 
a/plugins/actions/ftp/src/main/java/org/apache/hop/workflow/actions/ftpdelete/ActionFtpDeleteDialog.java
 
b/plugins/actions/ftp/src/main/java/org/apache/hop/workflow/actions/ftpdelete/ActionFtpDeleteDialog.java
index 599dab3b1c..a3a3883926 100644
--- 
a/plugins/actions/ftp/src/main/java/org/apache/hop/workflow/actions/ftpdelete/ActionFtpDeleteDialog.java
+++ 
b/plugins/actions/ftp/src/main/java/org/apache/hop/workflow/actions/ftpdelete/ActionFtpDeleteDialog.java
@@ -564,11 +564,11 @@ public class ActionFtpDeleteDialog extends ActionDialog {
     wAdvancedSettings.setText(
         BaseMessages.getString(PKG, 
"ActionFtpDelete.AdvancedSettings.Group.Label"));
 
-    FormLayout advancedSettingsgroupLayout = new FormLayout();
-    advancedSettingsgroupLayout.marginWidth = 10;
-    advancedSettingsgroupLayout.marginHeight = 10;
+    FormLayout advancedSettingsGroupLayout = new FormLayout();
+    advancedSettingsGroupLayout.marginWidth = 10;
+    advancedSettingsGroupLayout.marginHeight = 10;
 
-    wAdvancedSettings.setLayout(advancedSettingsgroupLayout);
+    wAdvancedSettings.setLayout(advancedSettingsGroupLayout);
 
     // Timeout line
     wTimeout =
@@ -975,10 +975,7 @@ public class ActionFtpDeleteDialog extends ActionDialog {
     if (wProtocol.getText().equals(ActionFtpDelete.PROTOCOL_FTP)) {
       wSocksProxy.setEnabled(true);
     } else {
-      wUsePublicKey.setSelection(false);
       activeUsePublicKey();
-      wlUsePublicKey.setEnabled(false);
-      wUsePublicKey.setEnabled(false);
       wSocksProxy.setEnabled(false);
     }
   }
diff --git 
a/plugins/actions/ftp/src/main/java/org/apache/hop/workflow/actions/sftp/ActionSftp.java
 
b/plugins/actions/ftp/src/main/java/org/apache/hop/workflow/actions/sftp/ActionSftp.java
index 8bde107ecd..2e0e26d45b 100644
--- 
a/plugins/actions/ftp/src/main/java/org/apache/hop/workflow/actions/sftp/ActionSftp.java
+++ 
b/plugins/actions/ftp/src/main/java/org/apache/hop/workflow/actions/sftp/ActionSftp.java
@@ -18,10 +18,13 @@
 package org.apache.hop.workflow.actions.sftp;
 
 import java.net.InetAddress;
+import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+import lombok.Getter;
+import lombok.Setter;
 import org.apache.commons.vfs2.FileObject;
 import org.apache.hop.core.Const;
 import org.apache.hop.core.ICheckResult;
@@ -64,38 +67,40 @@ public class ActionSftp extends ActionBase implements 
Cloneable, IAction {
   private static final String CONST_PASSWORD = "password";
 
   private static final int DEFAULT_PORT = 22;
-  private String serverName;
-  private String serverPort;
-  private String userName;
-  private String password;
-  private String sftpDirectory;
-  private String targetDirectory;
-  private String wildcard;
-  private boolean remove;
-  private boolean isaddresult;
-  private boolean createtargetfolder;
-  private boolean copyprevious;
-  private boolean usekeyfilename;
-  private String keyfilename;
-  private String keyfilepass;
-  private String compression;
+  @Getter @Setter private String serverName;
+  @Getter @Setter private String serverPort;
+  @Getter @Setter private String userName;
+  @Getter @Setter private String password;
+  @Getter @Setter private String sftpDirectory;
+  @Getter @Setter private String targetDirectory;
+  @Getter @Setter private String wildcard;
+  @Getter @Setter private boolean remove;
+  @Getter @Setter private boolean addFilenameToResult;
+  @Getter @Setter private boolean createTargetFolder;
+  @Getter @Setter private boolean copyPrevious;
+  @Getter @Setter private boolean useKeyFilename;
+  @Getter @Setter private boolean preserveTargetFileTimestamp;
+  @Getter @Setter private String keyFilename;
+  @Getter @Setter private String keyPassPhrase;
+  @Getter @Setter private String compression;
   // proxy
-  private String proxyType;
-  private String proxyHost;
-  private String proxyPort;
-  private String proxyUsername;
-  private String proxyPassword;
+  @Getter @Setter private String proxyType;
+  @Getter @Setter private String proxyHost;
+  @Getter @Setter private String proxyPort;
+  @Getter @Setter private String proxyUsername;
+  @Getter @Setter private String proxyPassword;
 
   public ActionSftp(String n) {
     super(n, "");
     serverName = null;
     serverPort = "22";
-    isaddresult = true;
-    createtargetfolder = false;
-    copyprevious = false;
-    usekeyfilename = false;
-    keyfilename = null;
-    keyfilepass = null;
+    addFilenameToResult = true;
+    preserveTargetFileTimestamp = true;
+    createTargetFolder = false;
+    copyPrevious = false;
+    useKeyFilename = false;
+    keyFilename = null;
+    keyPassPhrase = null;
     compression = "none";
     proxyType = null;
     proxyHost = null;
@@ -134,21 +139,26 @@ public class ActionSftp extends ActionBase implements 
Cloneable, IAction {
         .append(XmlHandler.addTagValue("targetdirectory", targetDirectory));
     retval.append(CONST_SPACE_SHORT).append(XmlHandler.addTagValue("wildcard", 
wildcard));
     retval.append(CONST_SPACE_SHORT).append(XmlHandler.addTagValue("remove", 
remove));
-    
retval.append(CONST_SPACE_SHORT).append(XmlHandler.addTagValue("isaddresult", 
isaddresult));
     retval
         .append(CONST_SPACE_SHORT)
-        .append(XmlHandler.addTagValue("createtargetfolder", 
createtargetfolder));
-    
retval.append(CONST_SPACE_SHORT).append(XmlHandler.addTagValue("copyprevious", 
copyprevious));
+        .append(XmlHandler.addTagValue("isaddresult", addFilenameToResult));
+    retval
+        .append(CONST_SPACE_SHORT)
+        .append(XmlHandler.addTagValue("preserveTargetFileTimestamp", 
preserveTargetFileTimestamp));
+    retval
+        .append(CONST_SPACE_SHORT)
+        .append(XmlHandler.addTagValue("createtargetfolder", 
createTargetFolder));
+    
retval.append(CONST_SPACE_SHORT).append(XmlHandler.addTagValue("copyprevious", 
copyPrevious));
 
     retval
         .append(CONST_SPACE_SHORT)
-        .append(XmlHandler.addTagValue("usekeyfilename", usekeyfilename));
-    
retval.append(CONST_SPACE_SHORT).append(XmlHandler.addTagValue("keyfilename", 
keyfilename));
+        .append(XmlHandler.addTagValue("usekeyfilename", useKeyFilename));
+    
retval.append(CONST_SPACE_SHORT).append(XmlHandler.addTagValue("keyfilename", 
keyFilename));
     retval
         .append(CONST_SPACE_SHORT)
         .append(
             XmlHandler.addTagValue(
-                "keyfilepass", 
Encr.encryptPasswordIfNotUsingVariables(keyfilepass)));
+                "keyfilepass", 
Encr.encryptPasswordIfNotUsingVariables(keyPassPhrase)));
     
retval.append(CONST_SPACE_SHORT).append(XmlHandler.addTagValue("compression", 
compression));
 
     
retval.append(CONST_SPACE_SHORT).append(XmlHandler.addTagValue("proxyType", 
proxyType));
@@ -180,21 +190,20 @@ public class ActionSftp extends ActionBase implements 
Cloneable, IAction {
       wildcard = XmlHandler.getTagValue(entrynode, "wildcard");
       remove = "Y".equalsIgnoreCase(XmlHandler.getTagValue(entrynode, 
"remove"));
 
-      String addresult = XmlHandler.getTagValue(entrynode, "isaddresult");
+      String addResult = XmlHandler.getTagValue(entrynode, "isaddresult");
+      String preserveTimestamp = XmlHandler.getTagValue(entrynode, 
"preserveTargetFileTimestamp");
 
-      if (Utils.isEmpty(addresult)) {
-        isaddresult = true;
-      } else {
-        isaddresult = "Y".equalsIgnoreCase(addresult);
-      }
+      addFilenameToResult = Utils.isEmpty(addResult) || 
"Y".equalsIgnoreCase(addResult);
+      preserveTargetFileTimestamp =
+          Utils.isEmpty(preserveTimestamp) || 
"Y".equalsIgnoreCase(preserveTimestamp);
 
-      createtargetfolder =
+      createTargetFolder =
           "Y".equalsIgnoreCase(XmlHandler.getTagValue(entrynode, 
"createtargetfolder"));
-      copyprevious = "Y".equalsIgnoreCase(XmlHandler.getTagValue(entrynode, 
"copyprevious"));
+      copyPrevious = "Y".equalsIgnoreCase(XmlHandler.getTagValue(entrynode, 
"copyprevious"));
 
-      usekeyfilename = "Y".equalsIgnoreCase(XmlHandler.getTagValue(entrynode, 
"usekeyfilename"));
-      keyfilename = XmlHandler.getTagValue(entrynode, "keyfilename");
-      keyfilepass =
+      useKeyFilename = "Y".equalsIgnoreCase(XmlHandler.getTagValue(entrynode, 
"usekeyfilename"));
+      keyFilename = XmlHandler.getTagValue(entrynode, "keyfilename");
+      keyPassPhrase =
           
Encr.decryptPasswordOptionallyEncrypted(XmlHandler.getTagValue(entrynode, 
"keyfilepass"));
       compression = XmlHandler.getTagValue(entrynode, "compression");
 
@@ -210,214 +219,6 @@ public class ActionSftp extends ActionBase implements 
Cloneable, IAction {
     }
   }
 
-  /**
-   * @return Returns the directory.
-   */
-  public String getScpDirectory() {
-    return sftpDirectory;
-  }
-
-  /**
-   * @param directory The directory to set.
-   */
-  public void setScpDirectory(String directory) {
-    this.sftpDirectory = directory;
-  }
-
-  /**
-   * @return Returns the password.
-   */
-  public String getPassword() {
-    return password;
-  }
-
-  /**
-   * @param password The password to set.
-   */
-  public void setPassword(String password) {
-    this.password = password;
-  }
-
-  /**
-   * @return Returns the compression.
-   */
-  public String getCompression() {
-    return compression;
-  }
-
-  /**
-   * @param compression The compression to set.
-   */
-  public void setCompression(String compression) {
-    this.compression = compression;
-  }
-
-  /**
-   * @return Returns the serverName.
-   */
-  public String getServerName() {
-    return serverName;
-  }
-
-  /**
-   * @param serverName The serverName to set.
-   */
-  public void setServerName(String serverName) {
-    this.serverName = serverName;
-  }
-
-  /**
-   * @return Returns the userName.
-   */
-  public String getUserName() {
-    return userName;
-  }
-
-  /**
-   * @param userName The userName to set.
-   */
-  public void setUserName(String userName) {
-    this.userName = userName;
-  }
-
-  /**
-   * @return Returns the wildcard.
-   */
-  public String getWildcard() {
-    return wildcard;
-  }
-
-  /**
-   * @param wildcard The wildcard to set.
-   */
-  public void setWildcard(String wildcard) {
-    this.wildcard = wildcard;
-  }
-
-  public void setAddToResult(boolean isaddresultin) {
-    this.isaddresult = isaddresultin;
-  }
-
-  public boolean isAddToResult() {
-    return isaddresult;
-  }
-
-  /**
-   * @return Returns the targetDirectory.
-   */
-  public String getTargetDirectory() {
-    return targetDirectory;
-  }
-
-  public boolean isCreateTargetFolder() {
-    return createtargetfolder;
-  }
-
-  public void setCreateTargetFolder(boolean createtargetfolder) {
-    this.createtargetfolder = createtargetfolder;
-  }
-
-  public boolean isCopyPrevious() {
-    return copyprevious;
-  }
-
-  public void setCopyPrevious(boolean copyprevious) {
-    this.copyprevious = copyprevious;
-  }
-
-  /**
-   * @param targetDirectory The targetDirectory to set.
-   */
-  public void setTargetDirectory(String targetDirectory) {
-    this.targetDirectory = targetDirectory;
-  }
-
-  /**
-   * @param remove The remove to set.
-   */
-  public void setRemove(boolean remove) {
-    this.remove = remove;
-  }
-
-  /**
-   * @return Returns the remove.
-   */
-  public boolean getRemove() {
-    return remove;
-  }
-
-  public String getServerPort() {
-    return serverPort;
-  }
-
-  public void setServerPort(String serverPort) {
-    this.serverPort = serverPort;
-  }
-
-  public boolean isUseKeyFile() {
-    return usekeyfilename;
-  }
-
-  public void setUseKeyFile(boolean value) {
-    this.usekeyfilename = value;
-  }
-
-  public String getKeyFilename() {
-    return keyfilename;
-  }
-
-  public void setKeyFilename(String value) {
-    this.keyfilename = value;
-  }
-
-  public String getKeyPassPhrase() {
-    return keyfilepass;
-  }
-
-  public void setKeyPassPhrase(String value) {
-    this.keyfilepass = value;
-  }
-
-  public String getProxyType() {
-    return proxyType;
-  }
-
-  public void setProxyType(String value) {
-    this.proxyType = value;
-  }
-
-  public String getProxyHost() {
-    return proxyHost;
-  }
-
-  public void setProxyHost(String value) {
-    this.proxyHost = value;
-  }
-
-  public String getProxyPort() {
-    return proxyPort;
-  }
-
-  public void setProxyPort(String value) {
-    this.proxyPort = value;
-  }
-
-  public String getProxyUsername() {
-    return proxyUsername;
-  }
-
-  public void setProxyUsername(String value) {
-    this.proxyUsername = value;
-  }
-
-  public String getProxyPassword() {
-    return proxyPassword;
-  }
-
-  public void setProxyPassword(String value) {
-    this.proxyPassword = value;
-  }
-
   @Override
   public Result execute(Result previousResult, int nr) {
     Result result = previousResult;
@@ -432,7 +233,7 @@ public class ActionSftp extends ActionBase implements 
Cloneable, IAction {
     }
     HashSet<String> listPreviousFilenames = new HashSet<>();
 
-    if (copyprevious) {
+    if (copyPrevious) {
       if (rows.isEmpty()) {
         if (isDetailed()) {
           logDetailed(BaseMessages.getString(PKG, 
"ActionSftp.ArgsFromPreviousNothing"));
@@ -463,7 +264,7 @@ public class ActionSftp extends ActionBase implements 
Cloneable, IAction {
       }
     }
 
-    SftpClient sftpclient = null;
+    SftpClient sftpClient = null;
 
     // String substitution..
     String realServerName = resolve(serverName);
@@ -479,8 +280,8 @@ public class ActionSftp extends ActionBase implements 
Cloneable, IAction {
 
     try {
       // Let's perform some checks before starting
-      if (isUseKeyFile()) {
-        // We must have here a private keyfilename
+      if (isUseKeyFilename()) {
+        // We must have here a private keyFilename
         realKeyFilename = resolve(getKeyFilename());
         if (Utils.isEmpty(realKeyFilename)) {
           // Error..Missing keyfile
@@ -508,7 +309,7 @@ public class ActionSftp extends ActionBase implements 
Cloneable, IAction {
                     PKG, "ActionSftp.Log.TargetFolderExists", 
realTargetDirectory));
           }
         } else {
-          if (!createtargetfolder) {
+          if (!createTargetFolder) {
             // Error..Target folder can not be found !
             logError(
                 BaseMessages.getString(
@@ -533,7 +334,7 @@ public class ActionSftp extends ActionBase implements 
Cloneable, IAction {
       }
 
       // Create sftp client to host ...
-      sftpclient =
+      sftpClient =
           new SftpClient(
               InetAddress.getByName(realServerName),
               Const.toInt(realServerPort, DEFAULT_PORT),
@@ -551,14 +352,14 @@ public class ActionSftp extends ActionBase implements 
Cloneable, IAction {
       }
 
       // Set compression
-      sftpclient.setCompression(getCompression());
+      sftpClient.setCompression(getCompression());
 
       // Set proxy?
       String realProxyHost = resolve(getProxyHost());
       if (!Utils.isEmpty(realProxyHost)) {
         // Set proxy
         String password = getRealPassword(getProxyPassword());
-        sftpclient.setProxy(
+        sftpClient.setProxy(
             realProxyHost,
             resolve(getProxyPort()),
             resolve(getProxyUsername()),
@@ -567,7 +368,7 @@ public class ActionSftp extends ActionBase implements 
Cloneable, IAction {
       }
 
       // login to ftp host ...
-      sftpclient.login(realPassword);
+      sftpClient.login(realPassword);
       // Passwords should not appear in log files.
       // logDetailed("logged in using password "+realPassword); // Logging 
this seems a bad idea! Oh
       // well.
@@ -575,7 +376,7 @@ public class ActionSftp extends ActionBase implements 
Cloneable, IAction {
       // move to spool dir ...
       if (!Utils.isEmpty(realSftpDirString)) {
         try {
-          sftpclient.chdir(realSftpDirString);
+          sftpClient.chdir(realSftpDirString);
         } catch (Exception e) {
           logError(
               BaseMessages.getString(
@@ -589,8 +390,8 @@ public class ActionSftp extends ActionBase implements 
Cloneable, IAction {
       }
       Pattern pattern = null;
       // Get all the files in the current directory...
-      String[] filelist = sftpclient.dir();
-      if (filelist == null) {
+      ArrayList<FileItem> filelist = sftpClient.dir();
+      if (filelist.isEmpty()) {
         // Nothing was found !!! exit
         result.setResult(true);
         if (isDetailed()) {
@@ -599,26 +400,26 @@ public class ActionSftp extends ActionBase implements 
Cloneable, IAction {
         return result;
       }
       if (isDetailed()) {
-        logDetailed(BaseMessages.getString(PKG, "ActionSftp.Log.Found", "" + 
filelist.length));
+        logDetailed(BaseMessages.getString(PKG, "ActionSftp.Log.Found", "" + 
filelist.size()));
       }
 
-      if (!copyprevious && !Utils.isEmpty(realWildcard)) {
+      if (!copyPrevious && !Utils.isEmpty(realWildcard)) {
         pattern = Pattern.compile(realWildcard);
       }
 
       // Get the files in the list...
-      for (int i = 0; i < filelist.length && !parentWorkflow.isStopped(); i++) 
{
+      for (int i = 0; i < filelist.size() && !parentWorkflow.isStopped(); i++) 
{
         boolean getIt = true;
-
-        if (copyprevious) {
+        String sourceFilename = filelist.get(i).getFileName();
+        if (copyPrevious) {
           // filenames list is send by previous action
           // download if the current file is in this list
-          getIt = listPreviousFilenames.contains(filelist[i]);
+          getIt = listPreviousFilenames.contains(sourceFilename);
         } else {
           // download files
           // but before see if the file matches the regular expression!
           if (pattern != null) {
-            Matcher matcher = pattern.matcher(filelist[i]);
+            Matcher matcher = pattern.matcher(sourceFilename);
             getIt = matcher.matches();
           }
         }
@@ -627,15 +428,19 @@ public class ActionSftp extends ActionBase implements 
Cloneable, IAction {
           if (isDebug()) {
             logDebug(
                 BaseMessages.getString(
-                    PKG, "ActionSftp.Log.GettingFiles", filelist[i], 
realTargetDirectory));
+                    PKG, "ActionSftp.Log.GettingFiles", sourceFilename, 
realTargetDirectory));
           }
 
           FileObject targetFile =
-              HopVfs.getFileObject(realTargetDirectory + Const.FILE_SEPARATOR 
+ filelist[i]);
-          sftpclient.get(targetFile, filelist[i]);
+              HopVfs.getFileObject(realTargetDirectory + Const.FILE_SEPARATOR 
+ sourceFilename);
+          sftpClient.get(targetFile, filelist.get(i));
+          if (preserveTargetFileTimestamp) {
+            
targetFile.getContent().setLastModifiedTime(filelist.get(i).getLastModified());
+          }
+
           filesRetrieved++;
 
-          if (isaddresult) {
+          if (addFilenameToResult) {
             // Add to the result files...
             ResultFile resultFile =
                 new ResultFile(
@@ -647,18 +452,20 @@ public class ActionSftp extends ActionBase implements 
Cloneable, IAction {
             if (isDetailed()) {
               logDetailed(
                   BaseMessages.getString(
-                      PKG, "ActionSftp.Log.FilenameAddedToResultFilenames", 
filelist[i]));
+                      PKG, "ActionSftp.Log.FilenameAddedToResultFilenames", 
sourceFilename));
             }
           }
           if (isDetailed()) {
-            logDetailed(BaseMessages.getString(PKG, 
"ActionSftp.Log.TransferedFile", filelist[i]));
+            logDetailed(
+                BaseMessages.getString(PKG, "ActionSftp.Log.TransferedFile", 
sourceFilename));
           }
 
           // Delete the file if this is needed!
           if (remove) {
-            sftpclient.delete(filelist[i]);
+            sftpClient.delete(sourceFilename);
             if (isDetailed()) {
-              logDetailed(BaseMessages.getString(PKG, 
"ActionSftp.Log.DeletedFile", filelist[i]));
+              logDetailed(
+                  BaseMessages.getString(PKG, "ActionSftp.Log.DeletedFile", 
sourceFilename));
             }
           }
         }
@@ -673,8 +480,8 @@ public class ActionSftp extends ActionBase implements 
Cloneable, IAction {
     } finally {
       // close connection, if possible
       try {
-        if (sftpclient != null) {
-          sftpclient.disconnect();
+        if (sftpClient != null) {
+          sftpClient.disconnect();
         }
       } catch (Exception e) {
         // just ignore this, makes no big difference
diff --git 
a/plugins/actions/ftp/src/main/java/org/apache/hop/workflow/actions/sftp/ActionSftpDialog.java
 
b/plugins/actions/ftp/src/main/java/org/apache/hop/workflow/actions/sftp/ActionSftpDialog.java
index 80ffd3d017..f892f6b347 100644
--- 
a/plugins/actions/ftp/src/main/java/org/apache/hop/workflow/actions/sftp/ActionSftpDialog.java
+++ 
b/plugins/actions/ftp/src/main/java/org/apache/hop/workflow/actions/sftp/ActionSftpDialog.java
@@ -27,6 +27,7 @@ import org.apache.hop.ui.core.PropsUi;
 import org.apache.hop.ui.core.dialog.BaseDialog;
 import org.apache.hop.ui.core.dialog.MessageBox;
 import org.apache.hop.ui.core.gui.GuiResource;
+import org.apache.hop.ui.core.widget.CheckBoxVar;
 import org.apache.hop.ui.core.widget.LabelTextVar;
 import org.apache.hop.ui.core.widget.PasswordTextVar;
 import org.apache.hop.ui.core.widget.TextVar;
@@ -66,7 +67,7 @@ public class ActionSftpDialog extends ActionDialog {
   private TextVar wServerPort;
   private TextVar wUserName;
   private TextVar wPassword;
-  private TextVar wScpDirectory;
+  private TextVar wSftpDirectory;
   private TextVar wTargetDirectory;
   private Label wlWildcard;
   private TextVar wWildcard;
@@ -88,6 +89,7 @@ public class ActionSftpDialog extends ActionDialog {
   private LabelTextVar wProxyPort;
   private LabelTextVar wProxyUsername;
   private LabelTextVar wProxyPassword;
+  private CheckBoxVar wPreserveTimestamp;
 
   public ActionSftpDialog(
       Shell parent, ActionSftp action, WorkflowMeta workflowMeta, IVariables 
variables) {
@@ -155,426 +157,115 @@ public class ActionSftpDialog extends ActionDialog {
     CTabFolder wTabFolder = new CTabFolder(shell, SWT.BORDER);
     PropsUi.setLook(wTabFolder, Props.WIDGET_STYLE_TAB);
 
-    // ////////////////////////
-    // START OF GENERAL TAB ///
-    // ////////////////////////
+    addGeneralTab(wTabFolder, margin, middle, lsMod);
+    addFilesTab(wTabFolder, margin, middle, lsMod);
 
-    CTabItem wGeneralTab = new CTabItem(wTabFolder, SWT.NONE);
-    wGeneralTab.setFont(GuiResource.getInstance().getFontDefault());
-    wGeneralTab.setText(BaseMessages.getString(PKG, 
"ActionSftp.Tab.General.Label"));
+    // ///////////////////////////////////////////////////////////
+    // / END OF Files TAB
+    // ///////////////////////////////////////////////////////////
 
-    Composite wGeneralComp = new Composite(wTabFolder, SWT.NONE);
-    PropsUi.setLook(wGeneralComp);
+    FormData fdTabFolder = new FormData();
+    fdTabFolder.left = new FormAttachment(0, 0);
+    fdTabFolder.top = new FormAttachment(wName, margin);
+    fdTabFolder.right = new FormAttachment(100, 0);
+    fdTabFolder.bottom = new FormAttachment(wOk, -2 * margin);
+    wTabFolder.setLayoutData(fdTabFolder);
 
-    FormLayout generalLayout = new FormLayout();
-    generalLayout.marginWidth = 3;
-    generalLayout.marginHeight = 3;
-    wGeneralComp.setLayout(generalLayout);
+    getData();
+    activeCopyFromPrevious();
+    activeUseKey();
 
-    // ////////////////////////
-    // START OF SERVER SETTINGS GROUP///
-    // /
-    Group wServerSettings = new Group(wGeneralComp, SWT.SHADOW_NONE);
-    PropsUi.setLook(wServerSettings);
-    wServerSettings.setText(BaseMessages.getString(PKG, 
"ActionSftp.ServerSettings.Group.Label"));
-    FormLayout serverSettingsgroupLayout = new FormLayout();
-    serverSettingsgroupLayout.marginWidth = 10;
-    serverSettingsgroupLayout.marginHeight = 10;
-    wServerSettings.setLayout(serverSettingsgroupLayout);
+    wTabFolder.setSelection(0);
 
-    // ServerName line
-    Label wlServerName = new Label(wServerSettings, SWT.RIGHT);
-    wlServerName.setText(BaseMessages.getString(PKG, 
"ActionSftp.Server.Label"));
-    PropsUi.setLook(wlServerName);
-    FormData fdlServerName = new FormData();
-    fdlServerName.left = new FormAttachment(0, 0);
-    fdlServerName.top = new FormAttachment(wName, margin);
-    fdlServerName.right = new FormAttachment(middle, -margin);
-    wlServerName.setLayoutData(fdlServerName);
-    wServerName = new TextVar(variables, wServerSettings, SWT.SINGLE | 
SWT.LEFT | SWT.BORDER);
-    PropsUi.setLook(wServerName);
-    wServerName.addModifyListener(lsMod);
-    FormData fdServerName = new FormData();
-    fdServerName.left = new FormAttachment(middle, 0);
-    fdServerName.top = new FormAttachment(wName, margin);
-    fdServerName.right = new FormAttachment(100, 0);
-    wServerName.setLayoutData(fdServerName);
+    BaseDialog.defaultShellHandling(shell, c -> ok(), c -> cancel());
 
-    // ServerPort line
-    Label wlServerPort = new Label(wServerSettings, SWT.RIGHT);
-    wlServerPort.setText(BaseMessages.getString(PKG, "ActionSftp.Port.Label"));
-    PropsUi.setLook(wlServerPort);
-    FormData fdlServerPort = new FormData();
-    fdlServerPort.left = new FormAttachment(0, 0);
-    fdlServerPort.top = new FormAttachment(wServerName, margin);
-    fdlServerPort.right = new FormAttachment(middle, -margin);
-    wlServerPort.setLayoutData(fdlServerPort);
-    wServerPort = new TextVar(variables, wServerSettings, SWT.SINGLE | 
SWT.LEFT | SWT.BORDER);
-    PropsUi.setLook(wServerPort);
-    wServerPort.setToolTipText(BaseMessages.getString(PKG, 
"ActionSftp.Port.Tooltip"));
-    wServerPort.addModifyListener(lsMod);
-    FormData fdServerPort = new FormData();
-    fdServerPort.left = new FormAttachment(middle, 0);
-    fdServerPort.top = new FormAttachment(wServerName, margin);
-    fdServerPort.right = new FormAttachment(100, 0);
-    wServerPort.setLayoutData(fdServerPort);
+    return action;
+  }
 
-    // UserName line
-    Label wlUserName = new Label(wServerSettings, SWT.RIGHT);
-    wlUserName.setText(BaseMessages.getString(PKG, 
"ActionSftp.Username.Label"));
-    PropsUi.setLook(wlUserName);
-    FormData fdlUserName = new FormData();
-    fdlUserName.left = new FormAttachment(0, 0);
-    fdlUserName.top = new FormAttachment(wServerPort, margin);
-    fdlUserName.right = new FormAttachment(middle, -margin);
-    wlUserName.setLayoutData(fdlUserName);
-    wUserName = new TextVar(variables, wServerSettings, SWT.SINGLE | SWT.LEFT 
| SWT.BORDER);
-    PropsUi.setLook(wUserName);
-    wUserName.addModifyListener(lsMod);
-    FormData fdUserName = new FormData();
-    fdUserName.left = new FormAttachment(middle, 0);
-    fdUserName.top = new FormAttachment(wServerPort, margin);
-    fdUserName.right = new FormAttachment(100, 0);
-    wUserName.setLayoutData(fdUserName);
+  private void addFilesTab(CTabFolder wTabFolder, int margin, int middle, 
ModifyListener lsMod) {
+    CTabItem wFilesTab = new CTabItem(wTabFolder, SWT.NONE);
+    wFilesTab.setFont(GuiResource.getInstance().getFontDefault());
+    wFilesTab.setText(BaseMessages.getString(PKG, 
"ActionSftp.Tab.Files.Label"));
 
-    // Password line
-    Label wlPassword = new Label(wServerSettings, SWT.RIGHT);
-    wlPassword.setText(BaseMessages.getString(PKG, 
"ActionSftp.Password.Label"));
-    PropsUi.setLook(wlPassword);
-    FormData fdlPassword = new FormData();
-    fdlPassword.left = new FormAttachment(0, 0);
-    fdlPassword.top = new FormAttachment(wUserName, margin);
-    fdlPassword.right = new FormAttachment(middle, -margin);
-    wlPassword.setLayoutData(fdlPassword);
-    wPassword = new PasswordTextVar(variables, wServerSettings, SWT.SINGLE | 
SWT.LEFT | SWT.BORDER);
-    PropsUi.setLook(wPassword);
-    wPassword.addModifyListener(lsMod);
-    FormData fdPassword = new FormData();
-    fdPassword.left = new FormAttachment(middle, 0);
-    fdPassword.top = new FormAttachment(wUserName, margin);
-    fdPassword.right = new FormAttachment(100, 0);
-    wPassword.setLayoutData(fdPassword);
+    Composite wFilesComp = new Composite(wTabFolder, SWT.NONE);
+    PropsUi.setLook(wFilesComp);
 
-    // usePublicKey
-    Label wlUsePublicKey = new Label(wServerSettings, SWT.RIGHT);
-    wlUsePublicKey.setText(BaseMessages.getString(PKG, 
"ActionSftp.useKeyFile.Label"));
-    PropsUi.setLook(wlUsePublicKey);
-    FormData fdlUsePublicKey = new FormData();
-    fdlUsePublicKey.left = new FormAttachment(0, 0);
-    fdlUsePublicKey.top = new FormAttachment(wPassword, margin);
-    fdlUsePublicKey.right = new FormAttachment(middle, -margin);
-    wlUsePublicKey.setLayoutData(fdlUsePublicKey);
-    wUsePublicKey = new Button(wServerSettings, SWT.CHECK);
-    wUsePublicKey.setToolTipText(BaseMessages.getString(PKG, 
"ActionSftp.useKeyFile.Tooltip"));
-    PropsUi.setLook(wUsePublicKey);
-    FormData fdUsePublicKey = new FormData();
-    fdUsePublicKey.left = new FormAttachment(middle, 0);
-    fdUsePublicKey.top = new FormAttachment(wlUsePublicKey, 0, SWT.CENTER);
-    fdUsePublicKey.right = new FormAttachment(100, 0);
-    wUsePublicKey.setLayoutData(fdUsePublicKey);
-    wUsePublicKey.addSelectionListener(
+    FormLayout filesLayout = new FormLayout();
+    filesLayout.marginWidth = 3;
+    filesLayout.marginHeight = 3;
+    wFilesComp.setLayout(filesLayout);
+
+    // ////////////////////////
+    // START OF Source files GROUP///
+    // /
+    Group wSourceFiles = new Group(wFilesComp, SWT.SHADOW_NONE);
+    PropsUi.setLook(wSourceFiles);
+    wSourceFiles.setText(BaseMessages.getString(PKG, 
"ActionSftp.SourceFiles.Group.Label"));
+    FormLayout sourceFilesgroupLayout = new FormLayout();
+    sourceFilesgroupLayout.marginWidth = 10;
+    sourceFilesgroupLayout.marginHeight = 10;
+    wSourceFiles.setLayout(sourceFilesgroupLayout);
+
+    // Get arguments from previous result...
+    Label wlGetPrevious = new Label(wSourceFiles, SWT.RIGHT);
+    wlGetPrevious.setText(BaseMessages.getString(PKG, 
"ActionSftp.getPrevious.Label"));
+    PropsUi.setLook(wlGetPrevious);
+    FormData fdlGetPrevious = new FormData();
+    fdlGetPrevious.left = new FormAttachment(0, 0);
+    fdlGetPrevious.top = new FormAttachment(wSourceFiles, 2 * margin);
+    fdlGetPrevious.right = new FormAttachment(middle, -margin);
+    wlGetPrevious.setLayoutData(fdlGetPrevious);
+    wGetPrevious = new Button(wSourceFiles, SWT.CHECK);
+    PropsUi.setLook(wGetPrevious);
+    wGetPrevious.setToolTipText(BaseMessages.getString(PKG, 
"ActionSftp.getPrevious.Tooltip"));
+    FormData fdGetPrevious = new FormData();
+    fdGetPrevious.left = new FormAttachment(middle, 0);
+    fdGetPrevious.top = new FormAttachment(wlGetPrevious, 0, SWT.CENTER);
+    fdGetPrevious.right = new FormAttachment(100, 0);
+    wGetPrevious.setLayoutData(fdGetPrevious);
+    wGetPrevious.addSelectionListener(
         new SelectionAdapter() {
           @Override
           public void widgetSelected(SelectionEvent e) {
-            activeUseKey();
+            activeCopyFromPrevious();
             action.setChanged();
           }
         });
 
-    // Key File
-    wlKeyFilename = new Label(wServerSettings, SWT.RIGHT);
-    wlKeyFilename.setText(BaseMessages.getString(PKG, 
"ActionSftp.KeyFilename.Label"));
-    PropsUi.setLook(wlKeyFilename);
-    FormData fdlKeyFilename = new FormData();
-    fdlKeyFilename.left = new FormAttachment(0, 0);
-    fdlKeyFilename.top = new FormAttachment(wlUsePublicKey, 2 * margin);
-    fdlKeyFilename.right = new FormAttachment(middle, -margin);
-    wlKeyFilename.setLayoutData(fdlKeyFilename);
-
-    wbKeyFilename = new Button(wServerSettings, SWT.PUSH | SWT.CENTER);
-    PropsUi.setLook(wbKeyFilename);
-    wbKeyFilename.setText(BaseMessages.getString(PKG, "System.Button.Browse"));
-    FormData fdbKeyFilename = new FormData();
-    fdbKeyFilename.right = new FormAttachment(100, 0);
-    fdbKeyFilename.top = new FormAttachment(wUsePublicKey, 0);
-    wbKeyFilename.setLayoutData(fdbKeyFilename);
-
-    wKeyFilename = new TextVar(variables, wServerSettings, SWT.SINGLE | 
SWT.LEFT | SWT.BORDER);
-    wKeyFilename.setToolTipText(BaseMessages.getString(PKG, 
"ActionSftp.KeyFilename.Tooltip"));
-    PropsUi.setLook(wKeyFilename);
-    wKeyFilename.addModifyListener(lsMod);
-    FormData fdKeyFilename = new FormData();
-    fdKeyFilename.left = new FormAttachment(middle, 0);
-    fdKeyFilename.top = new FormAttachment(wUsePublicKey, margin);
-    fdKeyFilename.right = new FormAttachment(wbKeyFilename, -margin);
-    wKeyFilename.setLayoutData(fdKeyFilename);
+    // FtpDirectory line
+    Label wlScpDirectory = new Label(wSourceFiles, SWT.RIGHT);
+    wlScpDirectory.setText(BaseMessages.getString(PKG, 
"ActionSftp.RemoteDir.Label"));
+    PropsUi.setLook(wlScpDirectory);
+    FormData fdlScpDirectory = new FormData();
+    fdlScpDirectory.left = new FormAttachment(0, 0);
+    fdlScpDirectory.top = new FormAttachment(wlGetPrevious, 2 * margin);
+    fdlScpDirectory.right = new FormAttachment(middle, -margin);
+    wlScpDirectory.setLayoutData(fdlScpDirectory);
 
-    wbKeyFilename.addListener(
-        SWT.Selection,
-        e ->
-            BaseDialog.presentFileDialog(
-                shell, wKeyFilename, variables, new String[] {"*.pem", "*"}, 
FILETYPES, true));
+    // Test remote folder button ...
+    Button wbTestChangeFolderExists = new Button(wSourceFiles, SWT.PUSH | 
SWT.CENTER);
+    PropsUi.setLook(wbTestChangeFolderExists);
+    wbTestChangeFolderExists.setText(
+        BaseMessages.getString(PKG, "ActionSftp.TestFolderExists.Label"));
+    FormData fdbTestChangeFolderExists = new FormData();
+    fdbTestChangeFolderExists.right = new FormAttachment(100, 0);
+    fdbTestChangeFolderExists.top = new FormAttachment(wGetPrevious, 2 * 
margin);
+    wbTestChangeFolderExists.setLayoutData(fdbTestChangeFolderExists);
+    wbTestChangeFolderExists.addListener(SWT.Selection, e -> 
checkRemoteFolder());
 
-    // keyfilePass line
-    wKeyfilePass =
-        new LabelTextVar(
+    wSftpDirectory =
+        new TextVar(
             variables,
-            wServerSettings,
-            SWT.NONE,
-            BaseMessages.getString(PKG, "ActionSftp.keyfilePass.Label"),
-            BaseMessages.getString(PKG, "ActionSftp.keyfilePass.Tooltip"),
-            true,
-            false);
-    PropsUi.setLook(wKeyfilePass);
-    wKeyfilePass.addModifyListener(lsMod);
-    FormData fdkeyfilePass = new FormData();
-    fdkeyfilePass.left = new FormAttachment(0, 0);
-    fdkeyfilePass.top = new FormAttachment(wKeyFilename, margin);
-    fdkeyfilePass.right = new FormAttachment(100, 0);
-    wKeyfilePass.setLayoutData(fdkeyfilePass);
-
-    Label wlProxyType = new Label(wServerSettings, SWT.RIGHT);
-    wlProxyType.setText(BaseMessages.getString(PKG, 
"ActionSftp.ProxyType.Label"));
-    PropsUi.setLook(wlProxyType);
-    FormData fdlProxyType = new FormData();
-    fdlProxyType.left = new FormAttachment(0, 0);
-    fdlProxyType.right = new FormAttachment(middle, -margin);
-    fdlProxyType.top = new FormAttachment(wKeyfilePass, 2 * margin);
-    wlProxyType.setLayoutData(fdlProxyType);
-
-    wProxyType = new CCombo(wServerSettings, SWT.SINGLE | SWT.READ_ONLY | 
SWT.BORDER);
-    wProxyType.add(SftpClient.PROXY_TYPE_HTTP);
-    wProxyType.add(SftpClient.PROXY_TYPE_SOCKS5);
-    wProxyType.select(0); // +1: starts at -1
-    PropsUi.setLook(wProxyType);
-    FormData fdProxyType = new FormData();
-    fdProxyType.left = new FormAttachment(middle, 0);
-    fdProxyType.top = new FormAttachment(wKeyfilePass, 2 * margin);
-    fdProxyType.right = new FormAttachment(100, 0);
-    wProxyType.setLayoutData(fdProxyType);
-    wProxyType.addSelectionListener(
-        new SelectionAdapter() {
-          @Override
-          public void widgetSelected(SelectionEvent e) {
-            setDefaultProxyPort();
-          }
-        });
-
-    // Proxy host line
-    wProxyHost =
-        new LabelTextVar(
-            variables,
-            wServerSettings,
-            SWT.NONE,
-            BaseMessages.getString(PKG, "ActionSftp.ProxyHost.Label"),
-            BaseMessages.getString(PKG, "ActionSftp.ProxyHost.Tooltip"),
-            false,
-            false);
-    PropsUi.setLook(wProxyHost);
-    wProxyHost.addModifyListener(lsMod);
-    FormData fdProxyHost = new FormData();
-    fdProxyHost.left = new FormAttachment(0, 0);
-    fdProxyHost.top = new FormAttachment(wProxyType, margin);
-    fdProxyHost.right = new FormAttachment(100, 0);
-    wProxyHost.setLayoutData(fdProxyHost);
-
-    // Proxy port line
-    wProxyPort =
-        new LabelTextVar(
-            variables,
-            wServerSettings,
-            SWT.NONE,
-            BaseMessages.getString(PKG, "ActionSftp.ProxyPort.Label"),
-            BaseMessages.getString(PKG, "ActionSftp.ProxyPort.Tooltip"),
-            false,
-            false);
-    PropsUi.setLook(wProxyPort);
-    wProxyPort.addModifyListener(lsMod);
-    FormData fdProxyPort = new FormData();
-    fdProxyPort.left = new FormAttachment(0, 0);
-    fdProxyPort.top = new FormAttachment(wProxyHost, margin);
-    fdProxyPort.right = new FormAttachment(100, 0);
-    wProxyPort.setLayoutData(fdProxyPort);
-
-    // Proxy username line
-    wProxyUsername =
-        new LabelTextVar(
-            variables,
-            wServerSettings,
-            SWT.NONE,
-            BaseMessages.getString(PKG, "ActionSftp.ProxyUsername.Label"),
-            BaseMessages.getString(PKG, "ActionSftp.ProxyUsername.Tooltip"),
-            false,
-            false);
-    PropsUi.setLook(wProxyUsername);
-    wProxyUsername.addModifyListener(lsMod);
-    FormData fdProxyUsername = new FormData();
-    fdProxyUsername.left = new FormAttachment(0, 0);
-    fdProxyUsername.top = new FormAttachment(wProxyPort, margin);
-    fdProxyUsername.right = new FormAttachment(100, 0);
-    wProxyUsername.setLayoutData(fdProxyUsername);
-
-    // Proxy password line
-    wProxyPassword =
-        new LabelTextVar(
-            variables,
-            wServerSettings,
-            SWT.NONE,
-            BaseMessages.getString(PKG, "ActionSftp.ProxyPassword.Label"),
-            BaseMessages.getString(PKG, "ActionSftp.ProxyPassword.Tooltip"),
-            true,
-            false);
-    PropsUi.setLook(wProxyPassword);
-    wProxyPassword.addModifyListener(lsMod);
-    FormData fdProxyPasswd = new FormData();
-    fdProxyPasswd.left = new FormAttachment(0, 0);
-    fdProxyPasswd.top = new FormAttachment(wProxyUsername, margin);
-    fdProxyPasswd.right = new FormAttachment(100, 0);
-    wProxyPassword.setLayoutData(fdProxyPasswd);
-
-    // Test connection button
-    Button wTest = new Button(wServerSettings, SWT.PUSH);
-    wTest.setText(BaseMessages.getString(PKG, 
"ActionSftp.TestConnection.Label"));
-    PropsUi.setLook(wTest);
-    FormData fdTest = new FormData();
-    wTest.setToolTipText(BaseMessages.getString(PKG, 
"ActionSftp.TestConnection.Tooltip"));
-    fdTest.top = new FormAttachment(wProxyPassword, margin);
-    fdTest.right = new FormAttachment(100, 0);
-    wTest.setLayoutData(fdTest);
-    wTest.addListener(SWT.Selection, e -> test());
-
-    FormData fdServerSettings = new FormData();
-    fdServerSettings.left = new FormAttachment(0, margin);
-    fdServerSettings.top = new FormAttachment(wName, margin);
-    fdServerSettings.right = new FormAttachment(100, -margin);
-    wServerSettings.setLayoutData(fdServerSettings);
-    // ///////////////////////////////////////////////////////////
-    // / END OF SERVER SETTINGS GROUP
-    // ///////////////////////////////////////////////////////////
-
-    Label wlCompression = new Label(wGeneralComp, SWT.RIGHT);
-    wlCompression.setText(BaseMessages.getString(PKG, 
"ActionSftp.Compression.Label"));
-    PropsUi.setLook(wlCompression);
-    FormData fdlCompression = new FormData();
-    fdlCompression.left = new FormAttachment(0, -margin);
-    fdlCompression.right = new FormAttachment(middle, 0);
-    fdlCompression.top = new FormAttachment(wServerSettings, margin);
-    wlCompression.setLayoutData(fdlCompression);
-
-    wCompression = new CCombo(wGeneralComp, SWT.SINGLE | SWT.READ_ONLY | 
SWT.BORDER);
-    wCompression.add("none");
-    wCompression.add("zlib");
-    wCompression.select(0); // +1: starts at -1
-
-    PropsUi.setLook(wCompression);
-    FormData fdCompression = new FormData();
-    fdCompression.left = new FormAttachment(middle, margin);
-    fdCompression.top = new FormAttachment(wServerSettings, margin);
-    fdCompression.right = new FormAttachment(100, 0);
-    wCompression.setLayoutData(fdCompression);
-
-    FormData fdGeneralComp = new FormData();
-    fdGeneralComp.left = new FormAttachment(0, 0);
-    fdGeneralComp.top = new FormAttachment(0, 0);
-    fdGeneralComp.right = new FormAttachment(100, 0);
-    fdGeneralComp.bottom = new FormAttachment(100, 0);
-    wGeneralComp.setLayoutData(fdGeneralComp);
-
-    wGeneralComp.layout();
-    wGeneralTab.setControl(wGeneralComp);
-    PropsUi.setLook(wGeneralComp);
-
-    // ///////////////////////////////////////////////////////////
-    // / END OF GENERAL TAB
-    // ///////////////////////////////////////////////////////////
-
-    // ////////////////////////
-    // START OF Files TAB ///
-    // ////////////////////////
-
-    CTabItem wFilesTab = new CTabItem(wTabFolder, SWT.NONE);
-    wFilesTab.setFont(GuiResource.getInstance().getFontDefault());
-    wFilesTab.setText(BaseMessages.getString(PKG, 
"ActionSftp.Tab.Files.Label"));
-
-    Composite wFilesComp = new Composite(wTabFolder, SWT.NONE);
-    PropsUi.setLook(wFilesComp);
-
-    FormLayout filesLayout = new FormLayout();
-    filesLayout.marginWidth = 3;
-    filesLayout.marginHeight = 3;
-    wFilesComp.setLayout(filesLayout);
-
-    // ////////////////////////
-    // START OF Source files GROUP///
-    // /
-    Group wSourceFiles = new Group(wFilesComp, SWT.SHADOW_NONE);
-    PropsUi.setLook(wSourceFiles);
-    wSourceFiles.setText(BaseMessages.getString(PKG, 
"ActionSftp.SourceFiles.Group.Label"));
-    FormLayout sourceFilesgroupLayout = new FormLayout();
-    sourceFilesgroupLayout.marginWidth = 10;
-    sourceFilesgroupLayout.marginHeight = 10;
-    wSourceFiles.setLayout(sourceFilesgroupLayout);
-
-    // Get arguments from previous result...
-    Label wlGetPrevious = new Label(wSourceFiles, SWT.RIGHT);
-    wlGetPrevious.setText(BaseMessages.getString(PKG, 
"ActionSftp.getPrevious.Label"));
-    PropsUi.setLook(wlGetPrevious);
-    FormData fdlGetPrevious = new FormData();
-    fdlGetPrevious.left = new FormAttachment(0, 0);
-    fdlGetPrevious.top = new FormAttachment(wServerSettings, 2 * margin);
-    fdlGetPrevious.right = new FormAttachment(middle, -margin);
-    wlGetPrevious.setLayoutData(fdlGetPrevious);
-    wGetPrevious = new Button(wSourceFiles, SWT.CHECK);
-    PropsUi.setLook(wGetPrevious);
-    wGetPrevious.setToolTipText(BaseMessages.getString(PKG, 
"ActionSftp.getPrevious.Tooltip"));
-    FormData fdGetPrevious = new FormData();
-    fdGetPrevious.left = new FormAttachment(middle, 0);
-    fdGetPrevious.top = new FormAttachment(wlGetPrevious, 0, SWT.CENTER);
-    fdGetPrevious.right = new FormAttachment(100, 0);
-    wGetPrevious.setLayoutData(fdGetPrevious);
-    wGetPrevious.addSelectionListener(
-        new SelectionAdapter() {
-          @Override
-          public void widgetSelected(SelectionEvent e) {
-            activeCopyFromPrevious();
-            action.setChanged();
-          }
-        });
-
-    // FtpDirectory line
-    Label wlScpDirectory = new Label(wSourceFiles, SWT.RIGHT);
-    wlScpDirectory.setText(BaseMessages.getString(PKG, 
"ActionSftp.RemoteDir.Label"));
-    PropsUi.setLook(wlScpDirectory);
-    FormData fdlScpDirectory = new FormData();
-    fdlScpDirectory.left = new FormAttachment(0, 0);
-    fdlScpDirectory.top = new FormAttachment(wlGetPrevious, 2 * margin);
-    fdlScpDirectory.right = new FormAttachment(middle, -margin);
-    wlScpDirectory.setLayoutData(fdlScpDirectory);
-
-    // Test remote folder button ...
-    Button wbTestChangeFolderExists = new Button(wSourceFiles, SWT.PUSH | 
SWT.CENTER);
-    PropsUi.setLook(wbTestChangeFolderExists);
-    wbTestChangeFolderExists.setText(
-        BaseMessages.getString(PKG, "ActionSftp.TestFolderExists.Label"));
-    FormData fdbTestChangeFolderExists = new FormData();
-    fdbTestChangeFolderExists.right = new FormAttachment(100, 0);
-    fdbTestChangeFolderExists.top = new FormAttachment(wGetPrevious, 2 * 
margin);
-    wbTestChangeFolderExists.setLayoutData(fdbTestChangeFolderExists);
-    wbTestChangeFolderExists.addListener(SWT.Selection, e -> 
checkRemoteFolder());
-
-    wScpDirectory =
-        new TextVar(
-            variables,
-            wSourceFiles,
-            SWT.SINGLE | SWT.LEFT | SWT.BORDER,
-            BaseMessages.getString(PKG, "ActionSftp.RemoteDir.Tooltip"));
-    PropsUi.setLook(wScpDirectory);
-    wScpDirectory.addModifyListener(lsMod);
-    FormData fdScpDirectory = new FormData();
-    fdScpDirectory.left = new FormAttachment(middle, 0);
-    fdScpDirectory.top = new FormAttachment(wGetPrevious, 2 * margin);
-    fdScpDirectory.right = new FormAttachment(wbTestChangeFolderExists, 
-margin);
-    wScpDirectory.setLayoutData(fdScpDirectory);
+            wSourceFiles,
+            SWT.SINGLE | SWT.LEFT | SWT.BORDER,
+            BaseMessages.getString(PKG, "ActionSftp.RemoteDir.Tooltip"));
+    PropsUi.setLook(wSftpDirectory);
+    wSftpDirectory.addModifyListener(lsMod);
+    FormData fdScpDirectory = new FormData();
+    fdScpDirectory.left = new FormAttachment(middle, 0);
+    fdScpDirectory.top = new FormAttachment(wGetPrevious, 2 * margin);
+    fdScpDirectory.right = new FormAttachment(wbTestChangeFolderExists, 
-margin);
+    wSftpDirectory.setLayoutData(fdScpDirectory);
 
     // Wildcard line
     wlWildcard = new Label(wSourceFiles, SWT.RIGHT);
@@ -582,7 +273,7 @@ public class ActionSftpDialog extends ActionDialog {
     PropsUi.setLook(wlWildcard);
     FormData fdlWildcard = new FormData();
     fdlWildcard.left = new FormAttachment(0, 0);
-    fdlWildcard.top = new FormAttachment(wScpDirectory, margin);
+    fdlWildcard.top = new FormAttachment(wSftpDirectory, margin);
     fdlWildcard.right = new FormAttachment(middle, -margin);
     wlWildcard.setLayoutData(fdlWildcard);
     wWildcard =
@@ -595,7 +286,7 @@ public class ActionSftpDialog extends ActionDialog {
     wWildcard.addModifyListener(lsMod);
     FormData fdWildcard = new FormData();
     fdWildcard.left = new FormAttachment(middle, 0);
-    fdWildcard.top = new FormAttachment(wScpDirectory, margin);
+    fdWildcard.top = new FormAttachment(wSftpDirectory, margin);
     fdWildcard.right = new FormAttachment(100, 0);
     wWildcard.setLayoutData(fdWildcard);
 
@@ -619,7 +310,7 @@ public class ActionSftpDialog extends ActionDialog {
 
     FormData fdSourceFiles = new FormData();
     fdSourceFiles.left = new FormAttachment(0, margin);
-    fdSourceFiles.top = new FormAttachment(wServerSettings, 2 * margin);
+    fdSourceFiles.top = new FormAttachment(0, 2 * margin);
     fdSourceFiles.right = new FormAttachment(100, -margin);
     wSourceFiles.setLayoutData(fdSourceFiles);
     // ///////////////////////////////////////////////////////////
@@ -692,6 +383,32 @@ public class ActionSftpDialog extends ActionDialog {
     fdCreateTargetFolder.right = new FormAttachment(100, 0);
     wCreateTargetFolder.setLayoutData(fdCreateTargetFolder);
 
+    // Preserve timestamp
+    Label wlPreserveTimestamp = new Label(wTargetFiles, SWT.RIGHT);
+    wlPreserveTimestamp.setText(BaseMessages.getString(PKG, 
"ActionSftp.PreserveTimestamp.Label"));
+    PropsUi.setLook(wlPreserveTimestamp);
+    FormData fdlPreserveTimestamp = new FormData();
+    fdlPreserveTimestamp.left = new FormAttachment(0, 0);
+    fdlPreserveTimestamp.right = new FormAttachment(middle, -margin);
+    fdlPreserveTimestamp.top = new FormAttachment(wCreateTargetFolder, margin 
* 2);
+    wlPreserveTimestamp.setLayoutData(fdlPreserveTimestamp);
+    wPreserveTimestamp = new CheckBoxVar(variables, wTargetFiles, SWT.CHECK, 
"");
+    wPreserveTimestamp.setToolTipText(
+        BaseMessages.getString(PKG, "ActionSftp.PreserveTimestamp.Tooltip"));
+    PropsUi.setLook(wPreserveTimestamp);
+    FormData fdCompress = new FormData();
+    fdCompress.left = new FormAttachment(middle, 0);
+    fdCompress.top = new FormAttachment(wlPreserveTimestamp, 0, SWT.CENTER);
+    fdCompress.right = new FormAttachment(100, 0);
+    wPreserveTimestamp.setLayoutData(fdCompress);
+    wPreserveTimestamp.addSelectionListener(
+        new SelectionAdapter() {
+          @Override
+          public void widgetSelected(SelectionEvent e) {
+            action.setChanged();
+          }
+        });
+
     // Add filenames to result filenames...
     Label wlAddFilenameToResult = new Label(wTargetFiles, SWT.RIGHT);
     wlAddFilenameToResult.setText(
@@ -699,7 +416,7 @@ public class ActionSftpDialog extends ActionDialog {
     PropsUi.setLook(wlAddFilenameToResult);
     FormData fdlAddFilenameToResult = new FormData();
     fdlAddFilenameToResult.left = new FormAttachment(0, 0);
-    fdlAddFilenameToResult.top = new FormAttachment(wCreateTargetFolder, 
margin);
+    fdlAddFilenameToResult.top = new FormAttachment(wPreserveTimestamp, 
margin);
     fdlAddFilenameToResult.right = new FormAttachment(middle, -margin);
     wlAddFilenameToResult.setLayoutData(fdlAddFilenameToResult);
     wAddFilenameToResult = new Button(wTargetFiles, SWT.CHECK);
@@ -731,27 +448,335 @@ public class ActionSftpDialog extends ActionDialog {
     wFilesComp.layout();
     wFilesTab.setControl(wFilesComp);
     PropsUi.setLook(wFilesComp);
+  }
 
-    // ///////////////////////////////////////////////////////////
-    // / END OF Files TAB
-    // ///////////////////////////////////////////////////////////
-
-    FormData fdTabFolder = new FormData();
-    fdTabFolder.left = new FormAttachment(0, 0);
-    fdTabFolder.top = new FormAttachment(wName, margin);
-    fdTabFolder.right = new FormAttachment(100, 0);
-    fdTabFolder.bottom = new FormAttachment(wOk, -2 * margin);
-    wTabFolder.setLayoutData(fdTabFolder);
+  private void addGeneralTab(CTabFolder wTabFolder, int margin, int middle, 
ModifyListener lsMod) {
 
-    getData();
-    activeCopyFromPrevious();
-    activeUseKey();
+    CTabItem wGeneralTab = new CTabItem(wTabFolder, SWT.NONE);
+    wGeneralTab.setFont(GuiResource.getInstance().getFontDefault());
+    wGeneralTab.setText(BaseMessages.getString(PKG, 
"ActionSftp.Tab.General.Label"));
 
-    wTabFolder.setSelection(0);
+    Composite wGeneralComp = new Composite(wTabFolder, SWT.NONE);
+    PropsUi.setLook(wGeneralComp);
 
-    BaseDialog.defaultShellHandling(shell, c -> ok(), c -> cancel());
+    FormLayout generalLayout = new FormLayout();
+    generalLayout.marginWidth = 3;
+    generalLayout.marginHeight = 3;
+    wGeneralComp.setLayout(generalLayout);
 
-    return action;
+    // ////////////////////////
+    // START OF SERVER SETTINGS GROUP///
+    // /
+    Group wServerSettings = new Group(wGeneralComp, SWT.SHADOW_NONE);
+    PropsUi.setLook(wServerSettings);
+    wServerSettings.setText(BaseMessages.getString(PKG, 
"ActionSftp.ServerSettings.Group.Label"));
+    FormLayout serverSettingsgroupLayout = new FormLayout();
+    serverSettingsgroupLayout.marginWidth = 10;
+    serverSettingsgroupLayout.marginHeight = 10;
+    wServerSettings.setLayout(serverSettingsgroupLayout);
+
+    // ServerName line
+    Label wlServerName = new Label(wServerSettings, SWT.RIGHT);
+    wlServerName.setText(BaseMessages.getString(PKG, 
"ActionSftp.Server.Label"));
+    PropsUi.setLook(wlServerName);
+    FormData fdlServerName = new FormData();
+    fdlServerName.left = new FormAttachment(0, 0);
+    fdlServerName.top = new FormAttachment(wName, margin);
+    fdlServerName.right = new FormAttachment(middle, -margin);
+    wlServerName.setLayoutData(fdlServerName);
+    wServerName = new TextVar(variables, wServerSettings, SWT.SINGLE | 
SWT.LEFT | SWT.BORDER);
+    PropsUi.setLook(wServerName);
+    wServerName.addModifyListener(lsMod);
+    FormData fdServerName = new FormData();
+    fdServerName.left = new FormAttachment(middle, 0);
+    fdServerName.top = new FormAttachment(wName, margin);
+    fdServerName.right = new FormAttachment(100, 0);
+    wServerName.setLayoutData(fdServerName);
+
+    // ServerPort line
+    Label wlServerPort = new Label(wServerSettings, SWT.RIGHT);
+    wlServerPort.setText(BaseMessages.getString(PKG, "ActionSftp.Port.Label"));
+    PropsUi.setLook(wlServerPort);
+    FormData fdlServerPort = new FormData();
+    fdlServerPort.left = new FormAttachment(0, 0);
+    fdlServerPort.top = new FormAttachment(wServerName, margin);
+    fdlServerPort.right = new FormAttachment(middle, -margin);
+    wlServerPort.setLayoutData(fdlServerPort);
+    wServerPort = new TextVar(variables, wServerSettings, SWT.SINGLE | 
SWT.LEFT | SWT.BORDER);
+    PropsUi.setLook(wServerPort);
+    wServerPort.setToolTipText(BaseMessages.getString(PKG, 
"ActionSftp.Port.Tooltip"));
+    wServerPort.addModifyListener(lsMod);
+    FormData fdServerPort = new FormData();
+    fdServerPort.left = new FormAttachment(middle, 0);
+    fdServerPort.top = new FormAttachment(wServerName, margin);
+    fdServerPort.right = new FormAttachment(100, 0);
+    wServerPort.setLayoutData(fdServerPort);
+
+    // UserName line
+    Label wlUserName = new Label(wServerSettings, SWT.RIGHT);
+    wlUserName.setText(BaseMessages.getString(PKG, 
"ActionSftp.Username.Label"));
+    PropsUi.setLook(wlUserName);
+    FormData fdlUserName = new FormData();
+    fdlUserName.left = new FormAttachment(0, 0);
+    fdlUserName.top = new FormAttachment(wServerPort, margin);
+    fdlUserName.right = new FormAttachment(middle, -margin);
+    wlUserName.setLayoutData(fdlUserName);
+    wUserName = new TextVar(variables, wServerSettings, SWT.SINGLE | SWT.LEFT 
| SWT.BORDER);
+    PropsUi.setLook(wUserName);
+    wUserName.addModifyListener(lsMod);
+    FormData fdUserName = new FormData();
+    fdUserName.left = new FormAttachment(middle, 0);
+    fdUserName.top = new FormAttachment(wServerPort, margin);
+    fdUserName.right = new FormAttachment(100, 0);
+    wUserName.setLayoutData(fdUserName);
+
+    // Password line
+    Label wlPassword = new Label(wServerSettings, SWT.RIGHT);
+    wlPassword.setText(BaseMessages.getString(PKG, 
"ActionSftp.Password.Label"));
+    PropsUi.setLook(wlPassword);
+    FormData fdlPassword = new FormData();
+    fdlPassword.left = new FormAttachment(0, 0);
+    fdlPassword.top = new FormAttachment(wUserName, margin);
+    fdlPassword.right = new FormAttachment(middle, -margin);
+    wlPassword.setLayoutData(fdlPassword);
+    wPassword = new PasswordTextVar(variables, wServerSettings, SWT.SINGLE | 
SWT.LEFT | SWT.BORDER);
+    PropsUi.setLook(wPassword);
+    wPassword.addModifyListener(lsMod);
+    FormData fdPassword = new FormData();
+    fdPassword.left = new FormAttachment(middle, 0);
+    fdPassword.top = new FormAttachment(wUserName, margin);
+    fdPassword.right = new FormAttachment(100, 0);
+    wPassword.setLayoutData(fdPassword);
+
+    // usePublicKey
+    Label wlUsePublicKey = new Label(wServerSettings, SWT.RIGHT);
+    wlUsePublicKey.setText(BaseMessages.getString(PKG, 
"ActionSftp.useKeyFile.Label"));
+    PropsUi.setLook(wlUsePublicKey);
+    FormData fdlUsePublicKey = new FormData();
+    fdlUsePublicKey.left = new FormAttachment(0, 0);
+    fdlUsePublicKey.top = new FormAttachment(wPassword, margin);
+    fdlUsePublicKey.right = new FormAttachment(middle, -margin);
+    wlUsePublicKey.setLayoutData(fdlUsePublicKey);
+    wUsePublicKey = new Button(wServerSettings, SWT.CHECK);
+    wUsePublicKey.setToolTipText(BaseMessages.getString(PKG, 
"ActionSftp.useKeyFile.Tooltip"));
+    PropsUi.setLook(wUsePublicKey);
+    FormData fdUsePublicKey = new FormData();
+    fdUsePublicKey.left = new FormAttachment(middle, 0);
+    fdUsePublicKey.top = new FormAttachment(wlUsePublicKey, 0, SWT.CENTER);
+    fdUsePublicKey.right = new FormAttachment(100, 0);
+    wUsePublicKey.setLayoutData(fdUsePublicKey);
+    wUsePublicKey.addSelectionListener(
+        new SelectionAdapter() {
+          @Override
+          public void widgetSelected(SelectionEvent e) {
+            activeUseKey();
+            action.setChanged();
+          }
+        });
+
+    // Key File
+    wlKeyFilename = new Label(wServerSettings, SWT.RIGHT);
+    wlKeyFilename.setText(BaseMessages.getString(PKG, 
"ActionSftp.KeyFilename.Label"));
+    PropsUi.setLook(wlKeyFilename);
+    FormData fdlKeyFilename = new FormData();
+    fdlKeyFilename.left = new FormAttachment(0, 0);
+    fdlKeyFilename.top = new FormAttachment(wlUsePublicKey, 2 * margin);
+    fdlKeyFilename.right = new FormAttachment(middle, -margin);
+    wlKeyFilename.setLayoutData(fdlKeyFilename);
+
+    wbKeyFilename = new Button(wServerSettings, SWT.PUSH | SWT.CENTER);
+    PropsUi.setLook(wbKeyFilename);
+    wbKeyFilename.setText(BaseMessages.getString(PKG, "System.Button.Browse"));
+    FormData fdbKeyFilename = new FormData();
+    fdbKeyFilename.right = new FormAttachment(100, 0);
+    fdbKeyFilename.top = new FormAttachment(wUsePublicKey, 0);
+    wbKeyFilename.setLayoutData(fdbKeyFilename);
+
+    wKeyFilename = new TextVar(variables, wServerSettings, SWT.SINGLE | 
SWT.LEFT | SWT.BORDER);
+    wKeyFilename.setToolTipText(BaseMessages.getString(PKG, 
"ActionSftp.KeyFilename.Tooltip"));
+    PropsUi.setLook(wKeyFilename);
+    wKeyFilename.addModifyListener(lsMod);
+    FormData fdKeyFilename = new FormData();
+    fdKeyFilename.left = new FormAttachment(middle, 0);
+    fdKeyFilename.top = new FormAttachment(wUsePublicKey, margin);
+    fdKeyFilename.right = new FormAttachment(wbKeyFilename, -margin);
+    wKeyFilename.setLayoutData(fdKeyFilename);
+
+    wbKeyFilename.addListener(
+        SWT.Selection,
+        e ->
+            BaseDialog.presentFileDialog(
+                shell, wKeyFilename, variables, new String[] {"*.pem", "*"}, 
FILETYPES, true));
+
+    // keyfilePass line
+    wKeyfilePass =
+        new LabelTextVar(
+            variables,
+            wServerSettings,
+            SWT.NONE,
+            BaseMessages.getString(PKG, "ActionSftp.keyfilePass.Label"),
+            BaseMessages.getString(PKG, "ActionSftp.keyfilePass.Tooltip"),
+            true,
+            false);
+    PropsUi.setLook(wKeyfilePass);
+    wKeyfilePass.addModifyListener(lsMod);
+    FormData fdkeyfilePass = new FormData();
+    fdkeyfilePass.left = new FormAttachment(0, 0);
+    fdkeyfilePass.top = new FormAttachment(wKeyFilename, margin);
+    fdkeyfilePass.right = new FormAttachment(100, 0);
+    wKeyfilePass.setLayoutData(fdkeyfilePass);
+
+    Label wlProxyType = new Label(wServerSettings, SWT.RIGHT);
+    wlProxyType.setText(BaseMessages.getString(PKG, 
"ActionSftp.ProxyType.Label"));
+    PropsUi.setLook(wlProxyType);
+    FormData fdlProxyType = new FormData();
+    fdlProxyType.left = new FormAttachment(0, 0);
+    fdlProxyType.right = new FormAttachment(middle, -margin);
+    fdlProxyType.top = new FormAttachment(wKeyfilePass, 2 * margin);
+    wlProxyType.setLayoutData(fdlProxyType);
+
+    wProxyType = new CCombo(wServerSettings, SWT.SINGLE | SWT.READ_ONLY | 
SWT.BORDER);
+    wProxyType.add(SftpClient.PROXY_TYPE_HTTP);
+    wProxyType.add(SftpClient.PROXY_TYPE_SOCKS5);
+    wProxyType.select(0); // +1: starts at -1
+    PropsUi.setLook(wProxyType);
+    FormData fdProxyType = new FormData();
+    fdProxyType.left = new FormAttachment(middle, 0);
+    fdProxyType.top = new FormAttachment(wKeyfilePass, 2 * margin);
+    fdProxyType.right = new FormAttachment(100, 0);
+    wProxyType.setLayoutData(fdProxyType);
+    wProxyType.addSelectionListener(
+        new SelectionAdapter() {
+          @Override
+          public void widgetSelected(SelectionEvent e) {
+            setDefaultProxyPort();
+          }
+        });
+
+    // Proxy host line
+    wProxyHost =
+        new LabelTextVar(
+            variables,
+            wServerSettings,
+            SWT.NONE,
+            BaseMessages.getString(PKG, "ActionSftp.ProxyHost.Label"),
+            BaseMessages.getString(PKG, "ActionSftp.ProxyHost.Tooltip"),
+            false,
+            false);
+    PropsUi.setLook(wProxyHost);
+    wProxyHost.addModifyListener(lsMod);
+    FormData fdProxyHost = new FormData();
+    fdProxyHost.left = new FormAttachment(0, 0);
+    fdProxyHost.top = new FormAttachment(wProxyType, margin);
+    fdProxyHost.right = new FormAttachment(100, 0);
+    wProxyHost.setLayoutData(fdProxyHost);
+
+    // Proxy port line
+    wProxyPort =
+        new LabelTextVar(
+            variables,
+            wServerSettings,
+            SWT.NONE,
+            BaseMessages.getString(PKG, "ActionSftp.ProxyPort.Label"),
+            BaseMessages.getString(PKG, "ActionSftp.ProxyPort.Tooltip"),
+            false,
+            false);
+    PropsUi.setLook(wProxyPort);
+    wProxyPort.addModifyListener(lsMod);
+    FormData fdProxyPort = new FormData();
+    fdProxyPort.left = new FormAttachment(0, 0);
+    fdProxyPort.top = new FormAttachment(wProxyHost, margin);
+    fdProxyPort.right = new FormAttachment(100, 0);
+    wProxyPort.setLayoutData(fdProxyPort);
+
+    // Proxy username line
+    wProxyUsername =
+        new LabelTextVar(
+            variables,
+            wServerSettings,
+            SWT.NONE,
+            BaseMessages.getString(PKG, "ActionSftp.ProxyUsername.Label"),
+            BaseMessages.getString(PKG, "ActionSftp.ProxyUsername.Tooltip"),
+            false,
+            false);
+    PropsUi.setLook(wProxyUsername);
+    wProxyUsername.addModifyListener(lsMod);
+    FormData fdProxyUsername = new FormData();
+    fdProxyUsername.left = new FormAttachment(0, 0);
+    fdProxyUsername.top = new FormAttachment(wProxyPort, margin);
+    fdProxyUsername.right = new FormAttachment(100, 0);
+    wProxyUsername.setLayoutData(fdProxyUsername);
+
+    // Proxy password line
+    wProxyPassword =
+        new LabelTextVar(
+            variables,
+            wServerSettings,
+            SWT.NONE,
+            BaseMessages.getString(PKG, "ActionSftp.ProxyPassword.Label"),
+            BaseMessages.getString(PKG, "ActionSftp.ProxyPassword.Tooltip"),
+            true,
+            false);
+    PropsUi.setLook(wProxyPassword);
+    wProxyPassword.addModifyListener(lsMod);
+    FormData fdProxyPasswd = new FormData();
+    fdProxyPasswd.left = new FormAttachment(0, 0);
+    fdProxyPasswd.top = new FormAttachment(wProxyUsername, margin);
+    fdProxyPasswd.right = new FormAttachment(100, 0);
+    wProxyPassword.setLayoutData(fdProxyPasswd);
+
+    // Test connection button
+    Button wTest = new Button(wServerSettings, SWT.PUSH);
+    wTest.setText(BaseMessages.getString(PKG, 
"ActionSftp.TestConnection.Label"));
+    PropsUi.setLook(wTest);
+    FormData fdTest = new FormData();
+    wTest.setToolTipText(BaseMessages.getString(PKG, 
"ActionSftp.TestConnection.Tooltip"));
+    fdTest.top = new FormAttachment(wProxyPassword, margin);
+    fdTest.right = new FormAttachment(100, 0);
+    wTest.setLayoutData(fdTest);
+    wTest.addListener(SWT.Selection, e -> test());
+
+    FormData fdServerSettings = new FormData();
+    fdServerSettings.left = new FormAttachment(0, margin);
+    fdServerSettings.top = new FormAttachment(wName, margin);
+    fdServerSettings.right = new FormAttachment(100, -margin);
+    wServerSettings.setLayoutData(fdServerSettings);
+
+    // ///////////////////////////////////////////////////////////
+    // / END OF SERVER SETTINGS GROUP
+    // ///////////////////////////////////////////////////////////
+
+    Label wlCompression = new Label(wGeneralComp, SWT.RIGHT);
+    wlCompression.setText(BaseMessages.getString(PKG, 
"ActionSftp.Compression.Label"));
+    PropsUi.setLook(wlCompression);
+    FormData fdlCompression = new FormData();
+    fdlCompression.left = new FormAttachment(0, -margin);
+    fdlCompression.top = new FormAttachment(wServerSettings, margin);
+    fdlCompression.right = new FormAttachment(middle, 0);
+    wlCompression.setLayoutData(fdlCompression);
+
+    wCompression = new CCombo(wGeneralComp, SWT.SINGLE | SWT.READ_ONLY | 
SWT.BORDER);
+    wCompression.add("none");
+    wCompression.add("zlib");
+    wCompression.select(0); // +1: starts at -1
+
+    PropsUi.setLook(wCompression);
+    FormData fdCompression = new FormData();
+    fdCompression.left = new FormAttachment(middle, margin);
+    fdCompression.top = new FormAttachment(wServerSettings, margin);
+    fdCompression.right = new FormAttachment(100, 0);
+    wCompression.setLayoutData(fdCompression);
+
+    FormData fdGeneralComp = new FormData();
+    fdGeneralComp.left = new FormAttachment(0, 0);
+    fdGeneralComp.top = new FormAttachment(0, 0);
+    fdGeneralComp.right = new FormAttachment(100, 0);
+    fdGeneralComp.bottom = new FormAttachment(100, 0);
+    wGeneralComp.setLayoutData(fdGeneralComp);
+
+    wGeneralComp.layout();
+    wGeneralTab.setControl(wGeneralComp);
+    PropsUi.setLook(wGeneralComp);
   }
 
   private void test() {
@@ -836,7 +861,7 @@ public class ActionSftpDialog extends ActionDialog {
   }
 
   private void checkRemoteFolder() {
-    String changeFtpFolder = variables.resolve(wScpDirectory.getText());
+    String changeFtpFolder = variables.resolve(wSftpDirectory.getText());
     if (!Utils.isEmpty(changeFtpFolder) && connectToSftp(true, 
changeFtpFolder)) {
       MessageBox mb = new MessageBox(shell, SWT.OK | SWT.ICON_INFORMATION);
       mb.setMessage(
@@ -860,14 +885,15 @@ public class ActionSftpDialog extends ActionDialog {
     wServerPort.setText(action.getServerPort());
     wUserName.setText(Const.NVL(action.getUserName(), ""));
     wPassword.setText(Const.NVL(action.getPassword(), ""));
-    wScpDirectory.setText(Const.NVL(action.getScpDirectory(), ""));
+    wSftpDirectory.setText(Const.NVL(action.getSftpDirectory(), ""));
     wTargetDirectory.setText(Const.NVL(action.getTargetDirectory(), ""));
     wWildcard.setText(Const.NVL(action.getWildcard(), ""));
-    wRemove.setSelection(action.getRemove());
-    wAddFilenameToResult.setSelection(action.isAddToResult());
+    wRemove.setSelection(action.isRemove());
+    wAddFilenameToResult.setSelection(action.isAddFilenameToResult());
+    wPreserveTimestamp.setSelection(action.isPreserveTargetFileTimestamp());
     wCreateTargetFolder.setSelection(action.isCreateTargetFolder());
     wGetPrevious.setSelection(action.isCopyPrevious());
-    wUsePublicKey.setSelection(action.isUseKeyFile());
+    wUsePublicKey.setSelection(action.isUseKeyFilename());
     wKeyFilename.setText(Const.NVL(action.getKeyFilename(), ""));
     wKeyfilePass.setText(Const.NVL(action.getKeyPassPhrase(), ""));
     wCompression.setText(Const.NVL(action.getCompression(), "none"));
@@ -901,14 +927,15 @@ public class ActionSftpDialog extends ActionDialog {
     action.setServerPort(wServerPort.getText());
     action.setUserName(wUserName.getText());
     action.setPassword(wPassword.getText());
-    action.setScpDirectory(wScpDirectory.getText());
+    action.setSftpDirectory(wSftpDirectory.getText());
     action.setTargetDirectory(wTargetDirectory.getText());
     action.setWildcard(wWildcard.getText());
     action.setRemove(wRemove.getSelection());
-    action.setAddToResult(wAddFilenameToResult.getSelection());
+    action.setAddFilenameToResult(wAddFilenameToResult.getSelection());
+    action.setPreserveTargetFileTimestamp(wPreserveTimestamp.getSelection());
     action.setCreateTargetFolder(wCreateTargetFolder.getSelection());
     action.setCopyPrevious(wGetPrevious.getSelection());
-    action.setUseKeyFile(wUsePublicKey.getSelection());
+    action.setUseKeyFilename(wUsePublicKey.getSelection());
     action.setKeyFilename(wKeyFilename.getText());
     action.setKeyPassPhrase(wKeyfilePass.getText());
     action.setCompression(wCompression.getText());
diff --git 
a/plugins/actions/ftp/src/main/java/org/apache/hop/workflow/actions/sftp/FileItem.java
 
b/plugins/actions/ftp/src/main/java/org/apache/hop/workflow/actions/sftp/FileItem.java
new file mode 100644
index 0000000000..26dd855509
--- /dev/null
+++ 
b/plugins/actions/ftp/src/main/java/org/apache/hop/workflow/actions/sftp/FileItem.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hop.workflow.actions.sftp;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class FileItem {
+
+  private String fileName;
+  private long lastModified;
+
+  public FileItem(String fileName, long lastModified) {
+    this.fileName = fileName;
+    this.lastModified = lastModified;
+  }
+
+  @Override
+  public String toString() {
+    return "RemoteFile{" + "fileName='" + fileName + '\'' + ", lastModified=" 
+ lastModified + '}';
+  }
+}
diff --git 
a/plugins/actions/ftp/src/main/java/org/apache/hop/workflow/actions/sftp/SftpClient.java
 
b/plugins/actions/ftp/src/main/java/org/apache/hop/workflow/actions/sftp/SftpClient.java
index 24c3b05b22..99c8d62250 100644
--- 
a/plugins/actions/ftp/src/main/java/org/apache/hop/workflow/actions/sftp/SftpClient.java
+++ 
b/plugins/actions/ftp/src/main/java/org/apache/hop/workflow/actions/sftp/SftpClient.java
@@ -32,6 +32,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.InetAddress;
+import java.util.ArrayList;
 import org.apache.commons.vfs2.FileObject;
 import org.apache.commons.vfs2.FileType;
 import org.apache.commons.vfs2.FileUtil;
@@ -183,38 +184,35 @@ public class SftpClient {
     }
   }
 
-  public String[] dir() throws HopWorkflowException {
-    String[] fileList = null;
+  public ArrayList<FileItem> dir() throws HopWorkflowException {
+    // String[] fileList = null;
+    ArrayList<FileItem> remoteFiles = new ArrayList<>();
 
     try {
       java.util.Vector<?> v = c.ls(".");
-      java.util.Vector<String> o = new java.util.Vector<>();
+      //      java.util.Vector<String> o = new java.util.Vector<>();
       if (v != null) {
         for (int i = 0; i < v.size(); i++) {
           Object obj = v.elementAt(i);
           if (obj != null
               && obj instanceof com.jcraft.jsch.ChannelSftp.LsEntry lse
               && !lse.getAttrs().isDir()) {
-            o.add(lse.getFilename());
+            remoteFiles.add(new FileItem(lse.getFilename(), 
lse.getAttrs().getMTime() * 1000L));
           }
         }
       }
-      if (!o.isEmpty()) {
-        fileList = new String[o.size()];
-        o.copyInto(fileList);
-      }
     } catch (SftpException e) {
       throw new HopWorkflowException(e);
     }
 
-    return fileList;
+    return remoteFiles;
   }
 
-  public void get(FileObject localFile, String remoteFile) throws 
HopWorkflowException {
+  public void get(FileObject localFile, FileItem remoteFile) throws 
HopWorkflowException {
     OutputStream localStream = null;
     try {
       localStream = HopVfs.getOutputStream(localFile, false);
-      c.get(remoteFile, localStream);
+      c.get(remoteFile.getFileName(), localStream);
     } catch (SftpException | IOException e) {
       throw new HopWorkflowException(e);
     } finally {
@@ -236,30 +234,19 @@ public class SftpClient {
     }
   }
 
-  public void put(FileObject fileObject, String remoteFile) throws 
HopWorkflowException {
-    int mode = ChannelSftp.OVERWRITE;
-    InputStream inputStream = null;
-    try {
-      inputStream = HopVfs.getInputStream(fileObject);
-      c.put(inputStream, remoteFile, null, mode);
-    } catch (Exception e) {
-      throw new HopWorkflowException(e);
-    } finally {
-      if (inputStream != null) {
-        try {
-          inputStream.close();
-        } catch (IOException e) {
-          throw new HopWorkflowException(e);
-        }
-      }
-    }
-  }
+  public void put(FileObject fileObject, String remoteFile, boolean 
preserveTimestamp)
+      throws HopWorkflowException {
 
-  public void put(InputStream inputStream, String remoteFile) throws 
HopWorkflowException {
+    InputStream inputStream = null;
     int mode = ChannelSftp.OVERWRITE;
 
     try {
+      inputStream = HopVfs.getInputStream(fileObject);
       c.put(inputStream, remoteFile, null, mode);
+      if (preserveTimestamp) {
+        long localLastMod = fileObject.getContent().getLastModifiedTime();
+        c.setMtime(remoteFile, (int) (localLastMod / 1000L));
+      }
     } catch (Exception e) {
       throw new HopWorkflowException(e);
     } finally {
diff --git 
a/plugins/actions/ftp/src/main/java/org/apache/hop/workflow/actions/sftpput/ActionSftpPut.java
 
b/plugins/actions/ftp/src/main/java/org/apache/hop/workflow/actions/sftpput/ActionSftpPut.java
index d7089a335e..348efbbca2 100644
--- 
a/plugins/actions/ftp/src/main/java/org/apache/hop/workflow/actions/sftpput/ActionSftpPut.java
+++ 
b/plugins/actions/ftp/src/main/java/org/apache/hop/workflow/actions/sftpput/ActionSftpPut.java
@@ -23,6 +23,8 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+import lombok.Getter;
+import lombok.Setter;
 import org.apache.commons.vfs2.FileObject;
 import org.apache.commons.vfs2.FileType;
 import org.apache.hop.core.Const;
@@ -65,7 +67,7 @@ public class ActionSftpPut extends ActionBase implements 
Cloneable, IAction {
   private static final String CONST_SPACE_SHORT = "      ";
   private static final String CONST_PASSWORD = "password";
 
-  private int afterFtps;
+  @Getter @Setter private int afterFtps;
 
   public static final String[] afterFtpsDesc =
       new String[] {
@@ -79,32 +81,32 @@ public class ActionSftpPut extends ActionBase implements 
Cloneable, IAction {
   public static final int AFTER_FTPSPUT_DELETE = 1;
   public static final int AFTER_FTPSPUT_MOVE = 2;
 
-  private String serverName;
-  private String serverPort;
-  private String userName;
-  private String password;
-  private String remoteDirectory;
-  private String localDirectory;
-  private String wildcard;
-  private boolean copyingPrevious;
-  private boolean copyingPreviousFiles;
-  private boolean addFilenameResut;
-  private boolean useKeyFilename;
-  private String keyFilename;
-  private String keyFilePassword;
-  private String compression;
-  private boolean createRemoteFolder;
+  @Getter @Setter private String serverName;
+  @Getter @Setter private String serverPort;
+  @Getter @Setter private String userName;
+  @Getter @Setter private String password;
+  @Getter @Setter private String remoteDirectory;
+  @Getter @Setter private String localDirectory;
+  @Getter @Setter private String wildcard;
+  @Getter @Setter private boolean copyingPrevious;
+  @Getter @Setter private boolean copyingPreviousFiles;
+  @Getter @Setter private boolean addFilenameResut;
+  @Getter @Setter private boolean useKeyFilename;
+  @Getter @Setter private String keyFilename;
+  @Getter @Setter private String keyFilePassword;
+  @Getter @Setter private String compression;
+  @Getter @Setter private boolean createRemoteFolder;
+  @Getter @Setter private boolean preserveTargetFileTimestamp;
   // proxy
-  private String proxyType;
-  private String proxyHost;
-  private String proxyPort;
-  private String proxyUsername;
-  private String proxyPassword;
+  @Getter @Setter private String proxyType;
+  @Getter @Setter private String proxyHost;
+  @Getter @Setter private String proxyPort;
+  @Getter @Setter private String proxyUsername;
+  @Getter @Setter private String proxyPassword;
 
-  private String destinationFolder;
-  private boolean createDestinationFolder;
-
-  private boolean successWhenNoFile;
+  @Getter @Setter private String destinationFolder;
+  @Getter @Setter private boolean createDestinationFolder;
+  @Getter @Setter private boolean successWhenNoFile;
 
   public ActionSftpPut(String n) {
     super(n, "");
@@ -126,6 +128,7 @@ public class ActionSftpPut extends ActionBase implements 
Cloneable, IAction {
     afterFtps = AFTER_FTPSPUT_NOTHING;
     destinationFolder = null;
     createDestinationFolder = false;
+    preserveTargetFileTimestamp = true;
     successWhenNoFile = false;
   }
 
@@ -200,6 +203,9 @@ public class ActionSftpPut extends ActionBase implements 
Cloneable, IAction {
     retval
         .append(CONST_SPACE_SHORT)
         .append(XmlHandler.addTagValue("createdestinationfolder", 
createDestinationFolder));
+    retval
+        .append(CONST_SPACE_SHORT)
+        .append(XmlHandler.addTagValue("preserveTargetFileTimestamp", 
preserveTargetFileTimestamp));
 
     retval
         .append(CONST_SPACE_SHORT)
@@ -251,6 +257,9 @@ public class ActionSftpPut extends ActionBase implements 
Cloneable, IAction {
       createRemoteFolder =
           "Y".equalsIgnoreCase(XmlHandler.getTagValue(entrynode, 
"createRemoteFolder"));
 
+      preserveTargetFileTimestamp =
+          "Y".equalsIgnoreCase(XmlHandler.getTagValue(entrynode, 
"preserveTargetFileTimestamp"));
+
       boolean remove = "Y".equalsIgnoreCase(XmlHandler.getTagValue(entrynode, 
"remove"));
       setAfterFtps(
           getAfterSftpPutByCode(Const.NVL(XmlHandler.getTagValue(entrynode, 
"aftersftpput"), "")));
@@ -303,258 +312,10 @@ public class ActionSftpPut extends ActionBase implements 
Cloneable, IAction {
     return getAfterSftpPutByCode(tt);
   }
 
-  /**
-   * @param createDestinationFolder The create destination folder flag to set.
-   */
-  public void setCreateDestinationFolder(boolean createDestinationFolder) {
-    this.createDestinationFolder = createDestinationFolder;
-  }
-
-  /**
-   * @return Returns the create destination folder flag
-   */
-  public boolean isCreateDestinationFolder() {
-    return createDestinationFolder;
-  }
-
-  /**
-   * @param successWhenNoFile The successWhenNoFile flag to set.
-   */
-  public void setSuccessWhenNoFile(boolean successWhenNoFile) {
-    this.successWhenNoFile = successWhenNoFile;
-  }
-
-  /**
-   * @return Returns the create successWhenNoFile folder flag
-   */
-  public boolean isSuccessWhenNoFile() {
-    return successWhenNoFile;
-  }
-
-  public void setDestinationFolder(String destinationfolderin) {
-    this.destinationFolder = destinationfolderin;
-  }
-
-  public String getDestinationFolder() {
-    return destinationFolder;
-  }
-
-  /**
-   * @return Returns the afterFTPS.
-   */
-  public int getAfterFtps() {
-    return afterFtps;
-  }
-
-  /**
-   * @param value The afterFTPS to set.
-   */
-  public void setAfterFtps(int value) {
-    this.afterFtps = value;
-  }
-
-  /**
-   * @return Returns the directory.
-   */
-  public String getScpDirectory() {
-    return remoteDirectory;
-  }
-
-  /**
-   * @param directory The directory to set.
-   */
-  public void setScpDirectory(String directory) {
-    this.remoteDirectory = directory;
-  }
-
-  /**
-   * @return Returns the password.
-   */
-  public String getPassword() {
-    return password;
-  }
-
-  /**
-   * @param password The password to set.
-   */
-  public void setPassword(String password) {
-    this.password = password;
-  }
-
-  /**
-   * @return Returns the serverName.
-   */
-  public String getServerName() {
-    return serverName;
-  }
-
-  /**
-   * @param serverName The serverName to set.
-   */
-  public void setServerName(String serverName) {
-    this.serverName = serverName;
-  }
-
-  /**
-   * @return Returns the userName.
-   */
-  public String getUserName() {
-    return userName;
-  }
-
-  /**
-   * @param userName The userName to set.
-   */
-  public void setUserName(String userName) {
-    this.userName = userName;
-  }
-
-  /**
-   * @return Returns the wildcard.
-   */
-  public String getWildcard() {
-    return wildcard;
-  }
-
-  /**
-   * @param wildcard The wildcard to set.
-   */
-  public void setWildcard(String wildcard) {
-    this.wildcard = wildcard;
-  }
-
-  /**
-   * @return Returns the localdirectory.
-   */
-  public String getLocalDirectory() {
-    return localDirectory;
-  }
-
-  /**
-   * @param localDirectory The localDirectory to set.
-   */
-  public void setLocalDirectory(String localDirectory) {
-    this.localDirectory = localDirectory;
-  }
-
   public boolean isCopyPrevious() {
     return copyingPrevious;
   }
 
-  public void setCopyPrevious(boolean copyprevious) {
-    this.copyingPrevious = copyprevious;
-  }
-
-  public boolean isCopyPreviousFiles() {
-    return copyingPreviousFiles;
-  }
-
-  public void setCopyPreviousFiles(boolean copypreviousfiles) {
-    this.copyingPreviousFiles = copypreviousfiles;
-  }
-
-  public boolean isAddFilenameResut() {
-    return addFilenameResut;
-  }
-
-  public boolean isUseKeyFile() {
-    return useKeyFilename;
-  }
-
-  public void setUseKeyFile(boolean value) {
-    this.useKeyFilename = value;
-  }
-
-  public String getKeyFilename() {
-    return keyFilename;
-  }
-
-  public void setKeyFilename(String value) {
-    this.keyFilename = value;
-  }
-
-  public String getKeyPassPhrase() {
-    return keyFilePassword;
-  }
-
-  public void setKeyPassPhrase(String value) {
-    this.keyFilePassword = value;
-  }
-
-  public void setAddFilenameResut(boolean addFilenameResut) {
-    this.addFilenameResut = addFilenameResut;
-  }
-
-  /**
-   * @return Returns the compression.
-   */
-  public String getCompression() {
-    return compression;
-  }
-
-  /**
-   * @param compression The compression to set.
-   */
-  public void setCompression(String compression) {
-    this.compression = compression;
-  }
-
-  public String getServerPort() {
-    return serverPort;
-  }
-
-  public void setServerPort(String serverPort) {
-    this.serverPort = serverPort;
-  }
-
-  public String getProxyType() {
-    return proxyType;
-  }
-
-  public void setProxyType(String value) {
-    this.proxyType = value;
-  }
-
-  public String getProxyHost() {
-    return proxyHost;
-  }
-
-  public void setProxyHost(String value) {
-    this.proxyHost = value;
-  }
-
-  public String getProxyPort() {
-    return proxyPort;
-  }
-
-  public void setProxyPort(String value) {
-    this.proxyPort = value;
-  }
-
-  public String getProxyUsername() {
-    return proxyUsername;
-  }
-
-  public void setProxyUsername(String value) {
-    this.proxyUsername = value;
-  }
-
-  public String getProxyPassword() {
-    return proxyPassword;
-  }
-
-  public void setProxyPassword(String value) {
-    this.proxyPassword = value;
-  }
-
-  public boolean isCreateRemoteFolder() {
-    return this.createRemoteFolder;
-  }
-
-  public void setCreateRemoteFolder(boolean value) {
-    this.createRemoteFolder = value;
-  }
-
   @Override
   public Result execute(Result previousResult, int nr) throws HopException {
     Result result = previousResult;
@@ -702,7 +463,7 @@ public class ActionSftpPut extends ActionBase implements 
Cloneable, IAction {
         }
       }
 
-      if (isUseKeyFile()) {
+      if (isUseKeyFilename()) {
         // We must have here a private keyfilename
         realKeyFilename = resolve(getKeyFilename());
         if (Utils.isEmpty(realKeyFilename)) {
@@ -717,7 +478,7 @@ public class ActionSftpPut extends ActionBase implements 
Cloneable, IAction {
           result.setNrErrors(1);
           return result;
         }
-        realPassPhrase = resolve(getKeyPassPhrase());
+        realPassPhrase = resolve(getKeyFilePassword());
       }
 
       // Create sftp client to host ...
@@ -843,7 +604,7 @@ public class ActionSftpPut extends ActionBase implements 
Cloneable, IAction {
                       PKG, "ActionSftpPut.Log.PuttingFile", localFilename, 
realSftpDirString));
             }
 
-            sftpclient.put(myFile, destinationFilename);
+            sftpclient.put(myFile, destinationFilename, 
preserveTargetFileTimestamp);
             nrFilesSent++;
 
             if (isDetailed()) {
diff --git 
a/plugins/actions/ftp/src/main/java/org/apache/hop/workflow/actions/sftpput/ActionSftpPutDialog.java
 
b/plugins/actions/ftp/src/main/java/org/apache/hop/workflow/actions/sftpput/ActionSftpPutDialog.java
index 3666552986..efa56c9af4 100644
--- 
a/plugins/actions/ftp/src/main/java/org/apache/hop/workflow/actions/sftpput/ActionSftpPutDialog.java
+++ 
b/plugins/actions/ftp/src/main/java/org/apache/hop/workflow/actions/sftpput/ActionSftpPutDialog.java
@@ -27,6 +27,7 @@ import org.apache.hop.ui.core.PropsUi;
 import org.apache.hop.ui.core.dialog.BaseDialog;
 import org.apache.hop.ui.core.dialog.MessageBox;
 import org.apache.hop.ui.core.gui.GuiResource;
+import org.apache.hop.ui.core.widget.CheckBoxVar;
 import org.apache.hop.ui.core.widget.LabelTextVar;
 import org.apache.hop.ui.core.widget.PasswordTextVar;
 import org.apache.hop.ui.core.widget.TextVar;
@@ -99,7 +100,8 @@ public class ActionSftpPutDialog extends ActionDialog {
   private Label wlDestinationFolder;
   private TextVar wDestinationFolder;
   private Button wbMovetoDirectory;
-  private SftpClient sftpclient = null;
+  private SftpClient sftpClient = null;
+  private CheckBoxVar wPreserveTimestamp;
 
   public ActionSftpPutDialog(
       Shell parent, ActionSftpPut action, WorkflowMeta workflowMeta, 
IVariables variables) {
@@ -119,7 +121,7 @@ public class ActionSftpPutDialog extends ActionDialog {
 
     ModifyListener lsMod =
         e -> {
-          sftpclient = null;
+          sftpClient = null;
           action.setChanged();
         };
     changed = action.hasChanged();
@@ -854,6 +856,33 @@ public class ActionSftpPutDialog extends ActionDialog {
           }
         });
 
+    // Preserve timestamp
+    Label wlPreserveTimestamp = new Label(wTargetFiles, SWT.RIGHT);
+    wlPreserveTimestamp.setText(
+        BaseMessages.getString(PKG, "ActionSftpPut.PreserveTimestamp.Label"));
+    PropsUi.setLook(wlPreserveTimestamp);
+    FormData fdlPreserveTimestamp = new FormData();
+    fdlPreserveTimestamp.left = new FormAttachment(0, 0);
+    fdlPreserveTimestamp.right = new FormAttachment(middle, -margin);
+    fdlPreserveTimestamp.top = new FormAttachment(wCreateRemoteFolder, margin 
* 2);
+    wlPreserveTimestamp.setLayoutData(fdlPreserveTimestamp);
+    wPreserveTimestamp = new CheckBoxVar(variables, wTargetFiles, SWT.CHECK, 
"");
+    wPreserveTimestamp.setToolTipText(
+        BaseMessages.getString(PKG, 
"ActionSftpPut.PreserveTimestamp.Tooltip"));
+    PropsUi.setLook(wPreserveTimestamp);
+    FormData fdCompress = new FormData();
+    fdCompress.left = new FormAttachment(middle, 0);
+    fdCompress.top = new FormAttachment(wlPreserveTimestamp, 0, SWT.CENTER);
+    fdCompress.right = new FormAttachment(100, 0);
+    wPreserveTimestamp.setLayoutData(fdCompress);
+    wPreserveTimestamp.addSelectionListener(
+        new SelectionAdapter() {
+          @Override
+          public void widgetSelected(SelectionEvent e) {
+            action.setChanged();
+          }
+        });
+
     FormData fdTargetFiles = new FormData();
     fdTargetFiles.left = new FormAttachment(0, margin);
     fdTargetFiles.top = new FormAttachment(wgSourceFiles, margin);
@@ -921,9 +950,9 @@ public class ActionSftpPutDialog extends ActionDialog {
   }
 
   private void quitSftp() {
-    if (sftpclient != null) {
+    if (sftpClient != null) {
       try {
-        sftpclient.disconnect();
+        sftpClient.disconnect();
       } catch (Exception e) {
         // Ignore
       }
@@ -932,10 +961,10 @@ public class ActionSftpPutDialog extends ActionDialog {
 
   private void closeFtpConnections() {
     // Close SecureFTP connection if necessary
-    if (sftpclient != null) {
+    if (sftpClient != null) {
       try {
-        sftpclient.disconnect();
-        sftpclient = null;
+        sftpClient.disconnect();
+        sftpClient = null;
       } catch (Exception e) {
         // Ignore errors
       }
@@ -946,9 +975,9 @@ public class ActionSftpPutDialog extends ActionDialog {
     boolean retval = false;
     try {
 
-      if (sftpclient == null) {
+      if (sftpClient == null) {
         // Create sftp client to host ...
-        sftpclient =
+        sftpClient =
             new SftpClient(
                 
InetAddress.getByName(variables.resolve(wServerName.getText())),
                 Const.toInt(variables.resolve(wServerPort.getText()), 22),
@@ -959,7 +988,7 @@ public class ActionSftpPutDialog extends ActionDialog {
         String realProxyHost = variables.resolve(wProxyHost.getText());
         if (!Utils.isEmpty(realProxyHost)) {
           // Set proxy
-          sftpclient.setProxy(
+          sftpClient.setProxy(
               realProxyHost,
               variables.resolve(wProxyPort.getText()),
               variables.resolve(wProxyUsername.getText()),
@@ -967,23 +996,23 @@ public class ActionSftpPutDialog extends ActionDialog {
               wProxyType.getText());
         }
         // login to ftp host ...
-        sftpclient.login(Utils.resolvePassword(variables, 
wPassword.getText()));
+        sftpClient.login(Utils.resolvePassword(variables, 
wPassword.getText()));
 
         retval = true;
       }
       if (checkFolder) {
-        retval = sftpclient.folderExists(remotefoldername);
+        retval = sftpClient.folderExists(remotefoldername);
       }
 
     } catch (Exception e) {
-      if (sftpclient != null) {
+      if (sftpClient != null) {
         try {
-          sftpclient.disconnect();
+          sftpClient.disconnect();
         } catch (Exception ignored) {
           // We've tried quitting the SFTP Client exception
           // nothing else to be done if the SFTP Client was already 
disconnected
         }
-        sftpclient = null;
+        sftpClient = null;
       }
       MessageBox mb = new MessageBox(shell, SWT.OK | SWT.ICON_ERROR);
       mb.setMessage(
@@ -1021,15 +1050,15 @@ public class ActionSftpPutDialog extends ActionDialog {
     wServerPort.setText(action.getServerPort());
     wUserName.setText(Const.NVL(action.getUserName(), ""));
     wPassword.setText(Const.NVL(action.getPassword(), ""));
-    wScpDirectory.setText(Const.NVL(action.getScpDirectory(), ""));
+    wScpDirectory.setText(Const.NVL(action.getRemoteDirectory(), ""));
     wLocalDirectory.setText(Const.NVL(action.getLocalDirectory(), ""));
     wWildcard.setText(Const.NVL(action.getWildcard(), ""));
     wGetPrevious.setSelection(action.isCopyPrevious());
-    wGetPreviousFiles.setSelection(action.isCopyPreviousFiles());
+    wGetPreviousFiles.setSelection(action.isCopyingPreviousFiles());
     wAddFilenameToResult.setSelection(action.isAddFilenameResut());
-    wUsePublicKey.setSelection(action.isUseKeyFile());
+    wUsePublicKey.setSelection(action.isUseKeyFilename());
     wKeyFilename.setText(Const.NVL(action.getKeyFilename(), ""));
-    wKeyFilePass.setText(Const.NVL(action.getKeyPassPhrase(), ""));
+    wKeyFilePass.setText(Const.NVL(action.getKeyFilePassword(), ""));
     wCompression.setText(Const.NVL(action.getCompression(), "none"));
 
     wProxyType.setText(Const.NVL(action.getProxyType(), ""));
@@ -1042,6 +1071,7 @@ public class ActionSftpPutDialog extends ActionDialog {
     
wAfterFtpPut.setText(ActionSftpPut.getAfterSftpPutDesc(action.getAfterFtps()));
     wDestinationFolder.setText(Const.NVL(action.getDestinationFolder(), ""));
     wCreateDestinationFolder.setSelection(action.isCreateDestinationFolder());
+    wPreserveTimestamp.setSelection(action.isPreserveTargetFileTimestamp());
     wSuccessWhenNoFile.setSelection(action.isSuccessWhenNoFile());
 
     wName.selectAll();
@@ -1067,15 +1097,15 @@ public class ActionSftpPutDialog extends ActionDialog {
     action.setServerPort(wServerPort.getText());
     action.setUserName(wUserName.getText());
     action.setPassword(wPassword.getText());
-    action.setScpDirectory(wScpDirectory.getText());
+    action.setRemoteDirectory(wScpDirectory.getText());
     action.setLocalDirectory(wLocalDirectory.getText());
     action.setWildcard(wWildcard.getText());
-    action.setCopyPrevious(wGetPrevious.getSelection());
-    action.setCopyPreviousFiles(wGetPreviousFiles.getSelection());
+    action.setCopyingPrevious(wGetPrevious.getSelection());
+    action.setCopyingPreviousFiles(wGetPreviousFiles.getSelection());
     action.setAddFilenameResut(wAddFilenameToResult.getSelection());
-    action.setUseKeyFile(wUsePublicKey.getSelection());
+    action.setUseKeyFilename(wUsePublicKey.getSelection());
     action.setKeyFilename(wKeyFilename.getText());
-    action.setKeyPassPhrase(wKeyFilePass.getText());
+    action.setKeyFilePassword(wKeyFilePass.getText());
     action.setCompression(wCompression.getText());
 
     action.setProxyType(wProxyType.getText());
@@ -1084,6 +1114,7 @@ public class ActionSftpPutDialog extends ActionDialog {
     action.setProxyUsername(wProxyUsername.getText());
     action.setProxyPassword(wProxyPassword.getText());
     action.setCreateRemoteFolder(wCreateRemoteFolder.getSelection());
+    action.setPreserveTargetFileTimestamp(wPreserveTimestamp.getSelection());
     
action.setAfterFtps(ActionSftpPut.getAfterSftpPutByDesc(wAfterFtpPut.getText()));
     action.setCreateDestinationFolder(wCreateDestinationFolder.getSelection());
     action.setDestinationFolder(wDestinationFolder.getText());
diff --git 
a/plugins/actions/ftp/src/main/resources/org/apache/hop/workflow/actions/sftp/messages/messages_en_US.properties
 
b/plugins/actions/ftp/src/main/resources/org/apache/hop/workflow/actions/sftp/messages/messages_en_US.properties
index 835b8fab96..706c1e4494 100644
--- 
a/plugins/actions/ftp/src/main/resources/org/apache/hop/workflow/actions/sftp/messages/messages_en_US.properties
+++ 
b/plugins/actions/ftp/src/main/resources/org/apache/hop/workflow/actions/sftp/messages/messages_en_US.properties
@@ -63,6 +63,8 @@ ActionSftp.Name.Label=Action name
 ActionSftp.Password.Label=Password
 ActionSftp.Port.Label=Port
 ActionSftp.Port.Tooltip=The port of the SFTP server. The default is 22 - this 
value is used if nothing is entered or "0".
+ActionSftp.PreserveTimestamp.Label=Preserve timestamp
+ActionSftp.PreserveTimestamp.Tooltip=Preserve timestamp of source file
 ActionSftp.ProxyHost.Label=Proxy host
 ActionSftp.ProxyHost.Tooltip=Proxy host
 ActionSftp.ProxyPassword.Label=Proxy password
diff --git 
a/plugins/actions/ftp/src/main/resources/org/apache/hop/workflow/actions/sftp/messages/messages_it_IT.properties
 
b/plugins/actions/ftp/src/main/resources/org/apache/hop/workflow/actions/sftp/messages/messages_it_IT.properties
index 3da88aa619..e1634af886 100644
--- 
a/plugins/actions/ftp/src/main/resources/org/apache/hop/workflow/actions/sftp/messages/messages_it_IT.properties
+++ 
b/plugins/actions/ftp/src/main/resources/org/apache/hop/workflow/actions/sftp/messages/messages_it_IT.properties
@@ -61,6 +61,8 @@ ActionSftp.Name.Label=Nome action:
 ActionSftp.Password.Label=Password: 
 ActionSftp.Port.Label=Porta
 ActionSftp.Port.Tooltip=La porta del server SFTP. Default\: 22. Questo valore 
\u00E8 utilizzato se non \u00E8 presente alcun valore oppure "0".
+ActionSftp.PreserveTimestamp.Label=Mantieni timestamp
+ActionSftp.PreserveTimestamp.Tooltip=Preserve timestamp of source file
 ActionSftp.ProxyHost.Label=Host proxy
 ActionSftp.ProxyHost.Tooltip=Host proxy
 ActionSftp.ProxyPassword.Label=Password proxy
diff --git 
a/plugins/actions/ftp/src/main/resources/org/apache/hop/workflow/actions/sftpput/messages/messages_en_US.properties
 
b/plugins/actions/ftp/src/main/resources/org/apache/hop/workflow/actions/sftpput/messages/messages_en_US.properties
index 5a507c1925..c1c2e3db7e 100644
--- 
a/plugins/actions/ftp/src/main/resources/org/apache/hop/workflow/actions/sftpput/messages/messages_en_US.properties
+++ 
b/plugins/actions/ftp/src/main/resources/org/apache/hop/workflow/actions/sftpput/messages/messages_en_US.properties
@@ -74,6 +74,8 @@ ActionSftpPut.Name.Label=Action name
 ActionSftpPut.Password.Label=Password
 ActionSftpPut.Port.Label=Port
 ActionSftpPut.Port.Tooltip=The port of the SFTP server. The default is 22 - 
this value is used if nothing is entered or "0".
+ActionSftpPut.PreserveTimestamp.Label=Preserve timestamp
+ActionSftpPut.PreserveTimestamp.Tooltip=Preserve timestamp of source file
 ActionSftpPut.ProxyHost.Label=Proxy host
 ActionSftpPut.ProxyHost.Tooltip=Proxy host
 ActionSftpPut.ProxyPassword.Label=Proxy password
diff --git 
a/plugins/actions/ftp/src/main/resources/org/apache/hop/workflow/actions/sftpput/messages/messages_it_IT.properties
 
b/plugins/actions/ftp/src/main/resources/org/apache/hop/workflow/actions/sftpput/messages/messages_it_IT.properties
index e379faef32..7621684fb3 100644
--- 
a/plugins/actions/ftp/src/main/resources/org/apache/hop/workflow/actions/sftpput/messages/messages_it_IT.properties
+++ 
b/plugins/actions/ftp/src/main/resources/org/apache/hop/workflow/actions/sftpput/messages/messages_it_IT.properties
@@ -74,6 +74,8 @@ ActionSftpPut.Name.Label=Nome action:
 ActionSftpPut.Password.Label=Password: 
 ActionSftpPut.Port.Label=Porta
 ActionSftpPut.Port.Tooltip=La porta sul server SFTP. Default 22; questo valore 
viene utilizzato se non \u00E8 specificato niente oppure "0".
+ActionSftpPut.PreserveTimestamp.Label=Non modificare timestamp
+ActionSftpPut.PreserveTimestamp.Tooltip=Mantiene il timestamp del file origine
 ActionSftpPut.ProxyHost.Label=Host proxy
 ActionSftpPut.ProxyHost.Tooltip=Host proxy
 ActionSftpPut.ProxyPassword.Label=Password proxy
diff --git 
a/plugins/actions/ftp/src/test/java/org/apache/hop/workflow/actions/sftp/WorkflowActionSftpLoadSaveTest.java
 
b/plugins/actions/ftp/src/test/java/org/apache/hop/workflow/actions/sftp/WorkflowActionSftpLoadSaveTest.java
index 40fe787502..72ae5cc388 100644
--- 
a/plugins/actions/ftp/src/test/java/org/apache/hop/workflow/actions/sftp/WorkflowActionSftpLoadSaveTest.java
+++ 
b/plugins/actions/ftp/src/test/java/org/apache/hop/workflow/actions/sftp/WorkflowActionSftpLoadSaveTest.java
@@ -39,14 +39,15 @@ class WorkflowActionSftpLoadSaveTest extends 
WorkflowActionLoadSaveTestSupport<A
         "serverPort",
         "userName",
         "password",
-        "scpDirectory",
+        "sftpDirectory",
         "targetDirectory",
         "wildcard",
         "remove",
-        "addToResult",
+        "addFilenameToResult",
+        "preserveTargetFileTimestamp",
         "createTargetFolder",
         "copyPrevious",
-        "useKeyFile",
+        "useKeyFilename",
         "keyFilename",
         "keyPassPhrase",
         "compression",
diff --git 
a/plugins/actions/ftp/src/test/java/org/apache/hop/workflow/actions/sftpput/WorkflowActionSftpPutLoadSaveTest.java
 
b/plugins/actions/ftp/src/test/java/org/apache/hop/workflow/actions/sftpput/WorkflowActionSftpPutLoadSaveTest.java
index 29545bfcf8..7972309db2 100644
--- 
a/plugins/actions/ftp/src/test/java/org/apache/hop/workflow/actions/sftpput/WorkflowActionSftpPutLoadSaveTest.java
+++ 
b/plugins/actions/ftp/src/test/java/org/apache/hop/workflow/actions/sftpput/WorkflowActionSftpPutLoadSaveTest.java
@@ -43,15 +43,16 @@ class WorkflowActionSftpPutLoadSaveTest extends 
WorkflowActionLoadSaveTestSuppor
         "serverPort",
         "userName",
         "password",
-        "scpDirectory",
+        "remoteDirectory",
         "localDirectory",
         "wildcard",
-        "copyPrevious",
-        "copyPreviousFiles",
+        "copyingPrevious",
+        "copyingPreviousFiles",
+        "preserveTargetFileTimestamp",
         "addFilenameResut",
-        "useKeyFile",
+        "useKeyFilename",
         "keyFilename",
-        "keyPassPhrase",
+        "keyFilePassword",
         "compression",
         "proxyType",
         "proxyHost",


Reply via email to