Author: pgil
Date: Fri May 18 15:53:35 2018
New Revision: 1831867

URL: http://svn.apache.org/viewvc?rev=1831867&view=rev
Log:
Implemented : File transfer management with communicationEvent and new 
contactMech FTP_ADDRESS
(OFBIZ-10245)

This commit introduce a new way to manage file transfer in OFBiz.
Inspired by mailing communication event management, a new 
communicationEventTypeId is created ('FILE_TRANSFER_COMM').

Such commEvent with classics : partyIdFrom/partyIdTo/contactMechIdTo/entryDate 
etc. are analysed by a job (like sendEmailDated), to send associated contents 
to a configured FTP/SFTP/FTPS server. If failure happens, it is catched and 
stored in communicationEvent, waiting for a new try.

For this purpose :

A new contactMechTypeId is introduced (FtpAddress), with its corresponding 
table. This contactMech store needed information for basic user/password 
authentication (server url and protocol, port, username, password, etc.)
A new service sendFileTransferDated that will look for pending file transfer 
and call following service.
A new service sendCommEventAsFtp that take a selected commEvent, check its 
structure and manage its status after trying the associated content file 
transfers.
A new service sendContentToFtp, that take a content and transfer it to a given 
FtpAddress.
A seca createCommEventFromFtpTransfer on sendContentToFtp to manage plural 
content file transfer, creating children communicationEvent to follow each 
content transfer separately (only for several content transfers).
A new Interface FtpClientInterface, with the 3 implementations of FTP, FTPS (To 
Implement), SFTP clients to manage Ftp connection and transfer.
A new property file to enable and manage redirection for testing purpose.

With this implementation, creating a communicationEvent, with a FtpAddress 
contactMechIdTo, and sendFileTransferDated job planned, the file is transfered 
to the ftp : communication event status set to COM_COMPLETE, if error occured 
the communication event status is set to COM_BOUNCED with error message on 
communicationEvent note.

Thanks Rishi for your feedbacks

Added:
    
ofbiz/ofbiz-framework/trunk/applications/content/servicedef/services_ftp.xml   
(with props)
    
ofbiz/ofbiz-framework/trunk/applications/content/src/main/java/org/apache/ofbiz/content/ftp/
    
ofbiz/ofbiz-framework/trunk/applications/content/src/main/java/org/apache/ofbiz/content/ftp/FtpClientInterface.java
   (with props)
    
ofbiz/ofbiz-framework/trunk/applications/content/src/main/java/org/apache/ofbiz/content/ftp/FtpServices.java
   (with props)
    
ofbiz/ofbiz-framework/trunk/applications/content/src/main/java/org/apache/ofbiz/content/ftp/SecureFtpClient.java
   (with props)
    
ofbiz/ofbiz-framework/trunk/applications/content/src/main/java/org/apache/ofbiz/content/ftp/SimpleFtpClient.java
   (with props)
    
ofbiz/ofbiz-framework/trunk/applications/content/src/main/java/org/apache/ofbiz/content/ftp/SshFtpClient.java
   (with props)
    
ofbiz/ofbiz-framework/trunk/applications/party/groovyScripts/party/ContactMechServices.groovy
   (with props)
    ofbiz/ofbiz-framework/trunk/framework/common/config/ftp.properties   (with 
props)
Modified:
    
ofbiz/ofbiz-framework/trunk/applications/content/config/ContentErrorUiLabels.xml
    ofbiz/ofbiz-framework/trunk/applications/content/ofbiz-component.xml
    
ofbiz/ofbiz-framework/trunk/applications/datamodel/data/seed/PartySeedData.xml
    
ofbiz/ofbiz-framework/trunk/applications/datamodel/entitydef/party-entitymodel.xml
    ofbiz/ofbiz-framework/trunk/applications/party/config/PartyEntityLabels.xml
    ofbiz/ofbiz-framework/trunk/applications/party/config/PartyErrorUiLabels.xml
    ofbiz/ofbiz-framework/trunk/applications/party/config/PartyUiLabels.xml
    ofbiz/ofbiz-framework/trunk/applications/party/servicedef/secas.xml
    ofbiz/ofbiz-framework/trunk/applications/party/servicedef/services.xml
    
ofbiz/ofbiz-framework/trunk/applications/party/src/main/java/org/apache/ofbiz/party/communication/CommunicationEventServices.java
    
ofbiz/ofbiz-framework/trunk/applications/party/src/main/java/org/apache/ofbiz/party/contact/ContactMechWorker.java
    
ofbiz/ofbiz-framework/trunk/applications/party/template/party/EditContactMech.ftl
    
ofbiz/ofbiz-framework/trunk/applications/party/template/party/profileblocks/Contact.ftl
    
ofbiz/ofbiz-framework/trunk/applications/party/webapp/partymgr/WEB-INF/controller.xml
    ofbiz/ofbiz-framework/trunk/build.gradle

Modified: 
ofbiz/ofbiz-framework/trunk/applications/content/config/ContentErrorUiLabels.xml
URL: 
http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/applications/content/config/ContentErrorUiLabels.xml?rev=1831867&r1=1831866&r2=1831867&view=diff
==============================================================================
--- 
ofbiz/ofbiz-framework/trunk/applications/content/config/ContentErrorUiLabels.xml
 (original)
+++ 
ofbiz/ofbiz-framework/trunk/applications/content/config/ContentErrorUiLabels.xml
 Fri May 18 15:53:35 2018
@@ -303,6 +303,10 @@
         <value xml:lang="zh">没有上传文件</value>
         <value xml:lang="zh-TW">沒有上傳檔案</value>
     </property>
+    <property key="ftpservices.contact_mech_must_be_ftp">
+        <value xml:lang="en">ERROR: Contact mech must be an ftp server</value>
+        <value xml:lang="fr">ERREUR: La coordonnée destinataire doit être un 
serveur ftp</value>
+    </property>
     <property key="layoutEvents.content_empty">
         <value xml:lang="da">indhold er tomt</value>
         <value xml:lang="de">Inhalt ist leer</value>

Modified: ofbiz/ofbiz-framework/trunk/applications/content/ofbiz-component.xml
URL: 
http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/applications/content/ofbiz-component.xml?rev=1831867&r1=1831866&r2=1831867&view=diff
==============================================================================
--- ofbiz/ofbiz-framework/trunk/applications/content/ofbiz-component.xml 
(original)
+++ ofbiz/ofbiz-framework/trunk/applications/content/ofbiz-component.xml Fri 
May 18 15:53:35 2018
@@ -37,6 +37,7 @@ under the License.
     <service-resource type="model" loader="main" 
location="servicedef/services_contenttypes.xml"/>
     <service-resource type="model" loader="main" 
location="servicedef/services_data.xml"/>
     <service-resource type="model" loader="main" 
location="servicedef/services_document.xml"/>
+    <service-resource type="model" loader="main" 
location="servicedef/services_ftp.xml"/>
     <service-resource type="model" loader="main" 
location="servicedef/services_output.xml"/>
     <service-resource type="model" loader="main" 
location="servicedef/services_survey.xml"/>
     <service-resource type="model" loader="main" 
location="servicedef/services_commevent.xml"/>

Added: 
ofbiz/ofbiz-framework/trunk/applications/content/servicedef/services_ftp.xml
URL: 
http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/applications/content/servicedef/services_ftp.xml?rev=1831867&view=auto
==============================================================================
--- 
ofbiz/ofbiz-framework/trunk/applications/content/servicedef/services_ftp.xml 
(added)
+++ 
ofbiz/ofbiz-framework/trunk/applications/content/servicedef/services_ftp.xml 
Fri May 18 15:53:35 2018
@@ -0,0 +1,35 @@
+<!--
+  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 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+        
xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/services.xsd";>
+    <description>Content Component Ftp Services</description>
+    <vendor>OFBiz</vendor>
+
+    <!-- DataResource services -->
+    <service name="sendContentToFtp" engine="java"
+            location="org.apache.ofbiz.content.ftp.FtpServices" 
invoke="sendContentToFtp" auth="true">
+        <description>Send content to FtpAddress</description>
+        <attribute name="contentId" type="String" mode="IN"/>
+        <attribute name="contactMechId" type="String" mode="IN"/>
+        <!--  used for parsing and ECAs -->
+        <attribute name="partyId" type="String" mode="IN" optional="true"/>
+        <attribute name="communicationEventId" type="String" mode="INOUT" 
optional="true"/>
+    </service>
+</services>

Propchange: 
ofbiz/ofbiz-framework/trunk/applications/content/servicedef/services_ftp.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
ofbiz/ofbiz-framework/trunk/applications/content/servicedef/services_ftp.xml
------------------------------------------------------------------------------
    svn:keywords = Date Rev Author URL Id

Propchange: 
ofbiz/ofbiz-framework/trunk/applications/content/servicedef/services_ftp.xml
------------------------------------------------------------------------------
    svn:mime-type = text/xml

Added: 
ofbiz/ofbiz-framework/trunk/applications/content/src/main/java/org/apache/ofbiz/content/ftp/FtpClientInterface.java
URL: 
http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/applications/content/src/main/java/org/apache/ofbiz/content/ftp/FtpClientInterface.java?rev=1831867&view=auto
==============================================================================
--- 
ofbiz/ofbiz-framework/trunk/applications/content/src/main/java/org/apache/ofbiz/content/ftp/FtpClientInterface.java
 (added)
+++ 
ofbiz/ofbiz-framework/trunk/applications/content/src/main/java/org/apache/ofbiz/content/ftp/FtpClientInterface.java
 Fri May 18 15:53:35 2018
@@ -0,0 +1,43 @@
+package org.apache.ofbiz.content.ftp;
+
+import org.apache.ofbiz.base.util.GeneralException;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+
+public interface FtpClientInterface {
+
+    /**
+     * Initialization of a file transfer client, and connection to the given 
server
+     *
+     * @param hostname hostname to connect to
+     * @param username username to login with
+     * @param password password to login with
+     * @param port     port to connect to the server, optional
+     * @param timeout  timeout for connection process, optional
+     * @throws IOException
+     */
+    void connect(String hostname, String username, String password, Long port, 
Long timeout) throws IOException, GeneralException;
+
+    /**
+     * Copy of the give file to the connected server into the path.
+     *
+     * @param path     path to copy the file to
+     * @param fileName name of the copied file
+     * @param file     data to copy
+     * @throws IOException
+     */
+    void copy(String path, String fileName, InputStream file) throws 
IOException;
+
+    List<String> list(String path) throws IOException;
+
+    void setBinaryTransfer(boolean isBinary) throws IOException;
+
+    void setPassiveMode(boolean isPassive) throws IOException;
+
+    /**
+     * Close opened connection
+     */
+    void closeConnection() throws IOException;
+}

Propchange: 
ofbiz/ofbiz-framework/trunk/applications/content/src/main/java/org/apache/ofbiz/content/ftp/FtpClientInterface.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
ofbiz/ofbiz-framework/trunk/applications/content/src/main/java/org/apache/ofbiz/content/ftp/FtpClientInterface.java
------------------------------------------------------------------------------
    svn:keywords = Date Rev Author URL Id

Propchange: 
ofbiz/ofbiz-framework/trunk/applications/content/src/main/java/org/apache/ofbiz/content/ftp/FtpClientInterface.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
ofbiz/ofbiz-framework/trunk/applications/content/src/main/java/org/apache/ofbiz/content/ftp/FtpServices.java
URL: 
http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/applications/content/src/main/java/org/apache/ofbiz/content/ftp/FtpServices.java?rev=1831867&view=auto
==============================================================================
--- 
ofbiz/ofbiz-framework/trunk/applications/content/src/main/java/org/apache/ofbiz/content/ftp/FtpServices.java
 (added)
+++ 
ofbiz/ofbiz-framework/trunk/applications/content/src/main/java/org/apache/ofbiz/content/ftp/FtpServices.java
 Fri May 18 15:53:35 2018
@@ -0,0 +1,204 @@
+/*******************************************************************************
+ * 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.ofbiz.content.ftp;
+
+import org.apache.ofbiz.base.util.Debug;
+import org.apache.ofbiz.base.util.FileUtil;
+import org.apache.ofbiz.base.util.GeneralException;
+import org.apache.ofbiz.base.util.UtilMisc;
+import org.apache.ofbiz.base.util.UtilProperties;
+import org.apache.ofbiz.base.util.UtilValidate;
+import org.apache.ofbiz.content.data.DataResourceWorker;
+import org.apache.ofbiz.entity.Delegator;
+import org.apache.ofbiz.entity.GenericValue;
+import org.apache.ofbiz.entity.util.EntityQuery;
+import org.apache.ofbiz.entity.util.EntityUtilProperties;
+import org.apache.ofbiz.service.DispatchContext;
+import org.apache.ofbiz.service.ServiceUtil;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+
+/**
+ * FtpServices class
+ * This class provide Ftp transfer services for content
+ */
+public class FtpServices {
+
+    public static final String module = FtpServices.class.getName();
+    public static final String resource = "ContentUiLabels";
+
+    private static FtpClientInterface createFtpClient(String serverType)
+            throws GeneralException {
+        FtpClientInterface ftpClient = null;
+        switch (serverType) {
+            case "ftp":
+                ftpClient = new SimpleFtpClient();
+                break;
+            case "ftps":
+                //TODO : to implements
+                throw new GeneralException("Ftp secured transfer protocol not 
yet implemented");
+            case "sftp":
+                ftpClient = new SshFtpClient();
+                break;
+        }
+        return ftpClient;
+    }
+
+    public static Map<String, Object> sendContentToFtp(DispatchContext dctx, 
Map<String, Object> context) {
+        Delegator delegator = dctx.getDelegator();
+        Locale locale = (Locale) context.get("locale");
+        String contactMechId = (String) context.get("contactMechId");
+        String contentId = (String) context.get("contentId");
+        String communicationEventId = (String) 
context.get("communicationEventId");
+        boolean forceTransferControlSuccess = 
EntityUtilProperties.propertyValueEqualsIgnoreCase("ftp", 
"ftp.force.transfer.control", "Y", delegator);
+        boolean ftpNotificationEnabled = 
EntityUtilProperties.propertyValueEqualsIgnoreCase("ftp", 
"ftp.notifications.enabled", "Y", delegator);
+
+        if (ftpNotificationEnabled) return ServiceUtil.returnSuccess();
+
+        // for ECA communicationEvent process
+        Map<String, Object> resultMap = ServiceUtil.returnSuccess();
+        resultMap.put("communicationEventId", communicationEventId);
+
+        FtpClientInterface ftpClient = null;
+
+        try {
+            //Retrieve and check contactMechType
+            GenericValue contactMech = 
EntityQuery.use(delegator).from("ContactMech").where("contactMechId", 
contactMechId).cache().queryOne();
+            GenericValue ftpAddress = 
EntityQuery.use(delegator).from("FtpAddress").where("contactMechId", 
contactMechId).cache().queryOne();
+            if (null == contactMech || null == ftpAddress || 
!"FTP_ADDRESS".equals(contactMech.getString("contactMechTypeId"))) {
+                String errMsg = 
UtilProperties.getMessage("ContentErrorUiLabels", 
"ftpservices.contact_mech_must_be_ftp", locale);
+                return ServiceUtil.returnError(errMsg + " " + contactMechId);
+            }
+
+            //Validate content
+            GenericValue content = 
EntityQuery.use(delegator).from("Content").where("contentId", 
contentId).cache().queryOne();
+            if (null == content) {
+                return 
ServiceUtil.returnError(UtilProperties.getMessage(resource, 
"ContentNoContentFound", UtilMisc.toMap("contentId", contentId), locale));
+            }
+
+            //ftp redirection
+            if ("Y".equalsIgnoreCase(UtilProperties.getPropertyValue("ftp", 
"ftp.notifications.redirectTo.enabled"))) {
+                ftpAddress = delegator.makeValue("FtpAddress");
+                ftpAddress.put("defaultTimeout", 
UtilProperties.getPropertyAsLong("ftp", 
"ftp.notifications.redirectTo.defaultTimeout", 30000));
+                ftpAddress.put("hostname", 
UtilProperties.getPropertyValue("ftp", 
"ftp.notifications.redirectTo.hostname"));
+                ftpAddress.put("path", UtilProperties.getPropertyValue("ftp", 
"ftp.notifications.redirectTo.path"));
+                ftpAddress.put("port", UtilProperties.getPropertyAsLong("ftp", 
"ftp.notifications.redirectTo.port", 65535));
+                ftpAddress.put("username", 
UtilProperties.getPropertyValue("ftp", 
"ftp.notifications.redirectTo.username"));
+                ftpAddress.put("password", 
UtilProperties.getPropertyValue("ftp", 
"ftp.notifications.redirectTo.password"));
+                ftpAddress.put("binaryTransfer", 
UtilProperties.getPropertyValue("ftp", 
"ftp.notifications.redirectTo.binaryTransfer"));
+                ftpAddress.put("passiveMode", 
UtilProperties.getPropertyValue("ftp", 
"ftp.notifications.redirectTo.passiveMode"));
+                ftpAddress.put("zipFile", 
UtilProperties.getPropertyValue("ftp", "ftp.notifications.redirectTo.zipFile"));
+            }
+
+            String hostname = ftpAddress.getString("hostname");
+            if (UtilValidate.isEmpty(hostname))
+                return ServiceUtil.returnError("Ftp destination server is 
null");
+            else if (hostname.indexOf("://") == -1) {
+                return ServiceUtil.returnError("No protocol defined in ftp 
destination address");
+            }
+
+            String serverType = hostname.split("://")[0];
+            hostname = hostname.split("://")[1];
+
+            ftpClient = createFtpClient(serverType);
+            if (null == ftpClient) {
+                return ServiceUtil.returnError("Server type : " + serverType + 
", not supported for hostname " + hostname);
+            }
+
+            Long defaultTimeout = ftpAddress.getLong("defaultTimeout");
+            Long port = ftpAddress.getLong("port");
+            String username = ftpAddress.getString("username");
+            String password = ftpAddress.getString("password");
+
+            if (Debug.infoOn())
+                Debug.logInfo("connecting to: " + username + "@" + 
ftpAddress.getString("hostname") + ":" + port, module);
+            ftpClient.connect(hostname, username, password, port, 
defaultTimeout);
+            boolean binary = 
"Y".equalsIgnoreCase(ftpAddress.getString("binaryTransfer"));
+            ftpClient.setBinaryTransfer(binary);
+            boolean passive = 
"Y".equalsIgnoreCase(ftpAddress.getString("passiveMode"));
+            ftpClient.setPassiveMode(passive);
+
+            GenericValue dataResource = delegator.findOne("DataResource", 
true, "dataResourceId", content.getString("dataResourceId"));
+            Map<String, Object> resultStream = 
DataResourceWorker.getDataResourceStream(dataResource, null, null, locale, 
null, true);
+            InputStream contentStream = (InputStream) 
resultStream.get("stream");
+            if (contentStream == null) {
+                return ServiceUtil.returnError("DataResource " + 
content.getString("dataResourceId") + " return an empty stream");
+            }
+
+            String path = ftpAddress.getString("path");
+            if (Debug.infoOn())
+                Debug.logInfo("storing local file remotely as: " + 
(UtilValidate.isNotEmpty(path) ? path + "/" : "") + 
content.getString("contentName"), module);
+
+            String fileName = content.getString("contentName");
+            String remoteFileName = fileName;
+            boolean zipFile = 
"Y".equalsIgnoreCase(ftpAddress.getString("zipFile"));
+            if (zipFile) {
+                //Create zip file from content input stream
+                ByteArrayInputStream zipStream = 
FileUtil.zipFileStream(contentStream, fileName);
+                remoteFileName = fileName + 
(fileName.endsWith("zip")?"":".zip");
+                ftpClient.copy(path, remoteFileName, zipStream);
+
+                zipStream.close();
+            } else {
+                ftpClient.copy(path, remoteFileName, contentStream);
+            }
+            contentStream.close();
+
+            //test if the file is correctly sent
+            if (forceTransferControlSuccess) {
+                if (Debug.infoOn()) Debug.logInfo(" Control if service really 
success the transfer", module);
+
+                //recreate the connection
+                ftpClient.closeConnection();
+                ftpClient = createFtpClient(serverType);
+                ftpClient.connect(hostname, username, password, port, 
defaultTimeout);
+                ftpClient.setBinaryTransfer(binary);
+                ftpClient.setPassiveMode(passive);
+
+                //check the file name previously copy
+                List<String> fileNames = ftpClient.list(path);
+                if (Debug.infoOn()) Debug.logInfo(" For the path " + path + " 
we found " + fileNames, module);
+
+                if (fileNames == null || !fileNames.contains(remoteFileName)) {
+                    return ServiceUtil.returnError("DataResource " + 
content.getString("dataResourceId") + " return an empty stream");
+                }
+                if (Debug.infoOn())
+                    Debug.logInfo(" Ok the file " + 
content.getString("contentName") + " is present", module);
+            }
+        } catch (GeneralException | IOException e) {
+            return ServiceUtil.returnError(e.getMessage());
+        } finally {
+            try {
+                if (ftpClient != null) {
+                    ftpClient.closeConnection();
+                }
+            } catch (Exception e) {
+                Debug.logWarning(e, "[getFile] Problem with FTP disconnect: ", 
module);
+            }
+        }
+        return resultMap;
+    }
+
+}

Propchange: 
ofbiz/ofbiz-framework/trunk/applications/content/src/main/java/org/apache/ofbiz/content/ftp/FtpServices.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
ofbiz/ofbiz-framework/trunk/applications/content/src/main/java/org/apache/ofbiz/content/ftp/FtpServices.java
------------------------------------------------------------------------------
    svn:keywords = Date Rev Author URL Id

Propchange: 
ofbiz/ofbiz-framework/trunk/applications/content/src/main/java/org/apache/ofbiz/content/ftp/FtpServices.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
ofbiz/ofbiz-framework/trunk/applications/content/src/main/java/org/apache/ofbiz/content/ftp/SecureFtpClient.java
URL: 
http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/applications/content/src/main/java/org/apache/ofbiz/content/ftp/SecureFtpClient.java?rev=1831867&view=auto
==============================================================================
--- 
ofbiz/ofbiz-framework/trunk/applications/content/src/main/java/org/apache/ofbiz/content/ftp/SecureFtpClient.java
 (added)
+++ 
ofbiz/ofbiz-framework/trunk/applications/content/src/main/java/org/apache/ofbiz/content/ftp/SecureFtpClient.java
 Fri May 18 15:53:35 2018
@@ -0,0 +1,43 @@
+package org.apache.ofbiz.content.ftp;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+
+public class SecureFtpClient implements FtpClientInterface {
+
+    public static final String module = SecureFtpClient.class.getName();
+
+    /**
+     * TODO : to implements
+     */
+    @Override
+    public void connect(String hostname, String username, String password, 
Long port, Long timeout) throws IOException {
+
+    }
+
+    @Override
+    public void copy(String path, String fileName, InputStream file) throws 
IOException {
+
+    }
+
+    @Override
+    public List<String> list(String path) throws IOException {
+        return null;
+    }
+
+    @Override
+    public void setBinaryTransfer(boolean isBinary) throws IOException {
+
+    }
+
+    @Override
+    public void setPassiveMode(boolean isPassive) throws IOException {
+
+    }
+
+    @Override
+    public void closeConnection() {
+
+    }
+}

Propchange: 
ofbiz/ofbiz-framework/trunk/applications/content/src/main/java/org/apache/ofbiz/content/ftp/SecureFtpClient.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
ofbiz/ofbiz-framework/trunk/applications/content/src/main/java/org/apache/ofbiz/content/ftp/SecureFtpClient.java
------------------------------------------------------------------------------
    svn:keywords = Date Rev Author URL Id

Propchange: 
ofbiz/ofbiz-framework/trunk/applications/content/src/main/java/org/apache/ofbiz/content/ftp/SecureFtpClient.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
ofbiz/ofbiz-framework/trunk/applications/content/src/main/java/org/apache/ofbiz/content/ftp/SimpleFtpClient.java
URL: 
http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/applications/content/src/main/java/org/apache/ofbiz/content/ftp/SimpleFtpClient.java?rev=1831867&view=auto
==============================================================================
--- 
ofbiz/ofbiz-framework/trunk/applications/content/src/main/java/org/apache/ofbiz/content/ftp/SimpleFtpClient.java
 (added)
+++ 
ofbiz/ofbiz-framework/trunk/applications/content/src/main/java/org/apache/ofbiz/content/ftp/SimpleFtpClient.java
 Fri May 18 15:53:35 2018
@@ -0,0 +1,85 @@
+package org.apache.ofbiz.content.ftp;
+
+import org.apache.commons.net.ftp.FTP;
+import org.apache.commons.net.ftp.FTPClient;
+import org.apache.commons.net.ftp.FTPFile;
+import org.apache.commons.net.ftp.FTPReply;
+import org.apache.ofbiz.base.util.Debug;
+import org.apache.ofbiz.base.util.GeneralException;
+import org.apache.ofbiz.base.util.UtilProperties;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+public class SimpleFtpClient implements FtpClientInterface {
+
+    public static final String module = SimpleFtpClient.class.getName();
+    private FTPClient client;
+
+    public SimpleFtpClient() {
+        client = new FTPClient();
+    }
+
+    @Override
+    public void connect(String hostname, String username, String password, 
Long port, Long timeout) throws IOException, GeneralException {
+        if (client == null) return;
+        if (client.isConnected()) return;
+        if (port != null) {
+            client.connect(hostname, port.intValue());
+        } else {
+            client.connect(hostname);
+        }
+        if (timeout != null) client.setDefaultTimeout(timeout.intValue());
+
+        if (!FTPReply.isPositiveCompletion(client.getReplyCode())) {
+            Debug.logError("Server refused connection", module);
+            throw new 
GeneralException(UtilProperties.getMessage("CommonUiLabels", 
"CommonFtpConnectionRefused", Locale.getDefault()));
+        }
+        if (!client.login(username, password)) {
+            Debug.logError("login failed", module);
+            throw new 
GeneralException(UtilProperties.getMessage("CommonUiLabels", 
"CommonFtpLoginFailure", Locale.getDefault()));
+        }
+    }
+
+    @Override
+    public List<String> list(String path) throws IOException {
+        FTPFile[] files = client.listFiles(path);
+        List<String> fileNames = new ArrayList<>();
+        for (FTPFile file : files) {
+            fileNames.add(file.getName());
+        }
+        return fileNames;
+    }
+
+    public void setBinaryTransfer(boolean isBinary) throws IOException {
+        if (isBinary) {
+            client.setFileType(FTP.BINARY_FILE_TYPE);
+        } else {
+            client.setFileType(FTP.ASCII_FILE_TYPE);
+        }
+    }
+
+    public void setPassiveMode(boolean isPassive) {
+        if (isPassive) {
+            client.enterLocalPassiveMode();
+        } else {
+            client.enterLocalActiveMode();
+        }
+    }
+
+    @Override
+    public void copy(String path, String fileName, InputStream file) throws 
IOException {
+        client.changeWorkingDirectory(path);
+        client.storeFile(fileName, file);
+    }
+
+    @Override
+    public void closeConnection() throws IOException {
+        if (client != null && client.isConnected()) {
+            client.logout();
+        }
+    }
+}

Propchange: 
ofbiz/ofbiz-framework/trunk/applications/content/src/main/java/org/apache/ofbiz/content/ftp/SimpleFtpClient.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
ofbiz/ofbiz-framework/trunk/applications/content/src/main/java/org/apache/ofbiz/content/ftp/SimpleFtpClient.java
------------------------------------------------------------------------------
    svn:keywords = Date Rev Author URL Id

Propchange: 
ofbiz/ofbiz-framework/trunk/applications/content/src/main/java/org/apache/ofbiz/content/ftp/SimpleFtpClient.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
ofbiz/ofbiz-framework/trunk/applications/content/src/main/java/org/apache/ofbiz/content/ftp/SshFtpClient.java
URL: 
http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/applications/content/src/main/java/org/apache/ofbiz/content/ftp/SshFtpClient.java?rev=1831867&view=auto
==============================================================================
--- 
ofbiz/ofbiz-framework/trunk/applications/content/src/main/java/org/apache/ofbiz/content/ftp/SshFtpClient.java
 (added)
+++ 
ofbiz/ofbiz-framework/trunk/applications/content/src/main/java/org/apache/ofbiz/content/ftp/SshFtpClient.java
 Fri May 18 15:53:35 2018
@@ -0,0 +1,74 @@
+package org.apache.ofbiz.content.ftp;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.sshd.client.SshClient;
+import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.client.subsystem.sftp.SftpClient;
+import org.apache.ofbiz.base.util.UtilValidate;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Basic client to copy files to an ssh ftp server
+ */
+public class SshFtpClient implements FtpClientInterface {
+
+    public static final String module = SshFtpClient.class.getName();
+
+    private SshClient client;
+    private SftpClient sftp;
+
+    public SshFtpClient() {
+        client = SshClient.setUpDefaultClient();
+        client.start();
+    }
+
+    @Override
+    public void connect(String hostname, String username, String password, 
Long port, Long timeout) throws IOException {
+        if (port == null) port = 22l;
+        if (timeout == null) timeout = 10000l;
+
+        if (sftp != null) return;
+        ClientSession session = client.connect(username, hostname, 
port.intValue()).verify(timeout.intValue()).getSession();
+        session.addPasswordIdentity(password);
+        session.auth().verify(timeout.intValue());
+        sftp = session.createSftpClient();
+    }
+
+    @Override
+    public void copy(String path, String fileName, InputStream file) throws 
IOException {
+        OutputStream os = sftp.write((UtilValidate.isNotEmpty(path) ? path + 
"/" : "") + fileName);
+        IOUtils.copy(file, os);
+        os.close();
+    }
+
+    @Override
+    public List<String> list(String path) throws IOException {
+        SftpClient.CloseableHandle handle = 
sftp.openDir((UtilValidate.isNotEmpty(path) ? path + "/" : ""));
+        List<String> fileNames = new ArrayList<>();
+        for (SftpClient.DirEntry dirEntry : sftp.listDir(handle)) {
+            fileNames.add(dirEntry.getFilename());
+        }
+        return fileNames;
+    }
+
+    @Override
+    public void setBinaryTransfer(boolean isBinary) throws IOException {
+    }
+
+    @Override
+    public void setPassiveMode(boolean isPassive) throws IOException {
+    }
+
+    @Override
+    public void closeConnection() {
+        if (sftp != null) {
+            client.stop();
+            sftp = null;
+        }
+    }
+}

Propchange: 
ofbiz/ofbiz-framework/trunk/applications/content/src/main/java/org/apache/ofbiz/content/ftp/SshFtpClient.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
ofbiz/ofbiz-framework/trunk/applications/content/src/main/java/org/apache/ofbiz/content/ftp/SshFtpClient.java
------------------------------------------------------------------------------
    svn:keywords = Date Rev Author URL Id

Propchange: 
ofbiz/ofbiz-framework/trunk/applications/content/src/main/java/org/apache/ofbiz/content/ftp/SshFtpClient.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: 
ofbiz/ofbiz-framework/trunk/applications/datamodel/data/seed/PartySeedData.xml
URL: 
http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/applications/datamodel/data/seed/PartySeedData.xml?rev=1831867&r1=1831866&r2=1831867&view=diff
==============================================================================
--- 
ofbiz/ofbiz-framework/trunk/applications/datamodel/data/seed/PartySeedData.xml 
(original)
+++ 
ofbiz/ofbiz-framework/trunk/applications/datamodel/data/seed/PartySeedData.xml 
Fri May 18 15:53:35 2018
@@ -63,6 +63,7 @@ under the License.
     <ContactMechType contactMechTypeId="DOMAIN_NAME" description="Internet 
Domain Name" hasTable="N" parentTypeId="ELECTRONIC_ADDRESS"/>
     <ContactMechType contactMechTypeId="WEB_ADDRESS" description="Web 
URL/Address" hasTable="N" parentTypeId="ELECTRONIC_ADDRESS"/>
     <ContactMechType contactMechTypeId="INTERNAL_PARTYID" 
description="Internal Note via partyId" hasTable="N" 
parentTypeId="ELECTRONIC_ADDRESS"/>
+    <ContactMechType contactMechTypeId="FTP_ADDRESS" description="Ftp server 
connection" hasTable="Y" parentTypeId="ELECTRONIC_ADDRESS"/>
 
     <ContactMechTypePurpose contactMechPurposeTypeId="BILLING_EMAIL" 
contactMechTypeId="EMAIL_ADDRESS"/>
     <ContactMechTypePurpose contactMechPurposeTypeId="MARKETING_EMAIL" 
contactMechTypeId="EMAIL_ADDRESS"/>
@@ -117,7 +118,8 @@ under the License.
     <CommunicationEventType communicationEventTypeId="WEB_SITE_COMMUNICATI" 
description="Web Site" hasTable="N" contactMechTypeId="WEB_ADDRESS"/>
     <CommunicationEventType communicationEventTypeId="COMMENT_NOTE" 
description="Comment/Note" hasTable="N" contactMechTypeId="INTERNAL_PARTYID"/>
     <CommunicationEventType communicationEventTypeId="AUTO_EMAIL_COMM" 
description="Auto Email" hasTable="N" contactMechTypeId="EMAIL_ADDRESS"/>
-    
+    <CommunicationEventType communicationEventTypeId="FILE_TRANSFER_COMM" 
description="File transfer" hasTable="N" parentTypeId="" 
contactMechTypeId="FTP_ADDRESS"/>
+
     <!-- party content types -->
     <PartyContentType description="Internal Content" 
partyContentTypeId="INTERNAL"/>
     <PartyContentType description="User Defined Content"  
partyContentTypeId="USERDEF"/>

Modified: 
ofbiz/ofbiz-framework/trunk/applications/datamodel/entitydef/party-entitymodel.xml
URL: 
http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/applications/datamodel/entitydef/party-entitymodel.xml?rev=1831867&r1=1831866&r2=1831867&view=diff
==============================================================================
--- 
ofbiz/ofbiz-framework/trunk/applications/datamodel/entitydef/party-entitymodel.xml
 (original)
+++ 
ofbiz/ofbiz-framework/trunk/applications/datamodel/entitydef/party-entitymodel.xml
 Fri May 18 15:53:35 2018
@@ -1304,6 +1304,24 @@ under the License.
         <index-field name="contactNumber"/>
       </index>
     </entity>
+    <entity entity-name="FtpAddress"
+            package-name="org.ofbiz.party.contact"
+            title="Ftp server Entity">
+      <field name="contactMechId" type="id"/>
+      <field name="hostname" type="long-varchar"/>
+      <field name="port" type="numeric"/>
+      <field name="username" type="long-varchar"/>
+      <field name="password" type="long-varchar" encrypt="true"/>
+      <field name="binaryTransfer" type="indicator"/>
+      <field name="path" type="long-varchar"/>
+      <field name="zipFile" type="indicator"/>
+      <field name="passiveMode" type="indicator"/>
+      <field name="defaultTimeout" type="numeric"/>
+      <prim-key field="contactMechId"/>
+      <relation type="one" fk-name="FTP_SRV_CMECH" 
rel-entity-name="ContactMech">
+        <key-map field-name="contactMechId"/>
+      </relation>
+    </entity>
     <entity entity-name="ValidContactMechRole"
             package-name="org.apache.ofbiz.party.contact"
             title="Valid Contact Mechanism Role Entity">

Modified: 
ofbiz/ofbiz-framework/trunk/applications/party/config/PartyEntityLabels.xml
URL: 
http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/applications/party/config/PartyEntityLabels.xml?rev=1831867&r1=1831866&r2=1831867&view=diff
==============================================================================
--- ofbiz/ofbiz-framework/trunk/applications/party/config/PartyEntityLabels.xml 
(original)
+++ ofbiz/ofbiz-framework/trunk/applications/party/config/PartyEntityLabels.xml 
Fri May 18 15:53:35 2018
@@ -1078,6 +1078,11 @@
         <value xml:lang="zh">电子邮件地址</value>
         <value xml:lang="zh-TW">電子郵件位址</value>
     </property>
+    <property key="ContactMechType.description.FTP_ADDRESS">
+        <value xml:lang="de">Fileserver</value>
+        <value xml:lang="en">File server</value>
+        <value xml:lang="fr">Serveur de fichier</value>
+    </property>
     <property key="ContactMechType.description.INTERNAL_PARTYID">
         <value xml:lang="ar">ملاحظة طرف داخلية</value>
         <value xml:lang="cs">Interní poznámka</value>

Modified: 
ofbiz/ofbiz-framework/trunk/applications/party/config/PartyErrorUiLabels.xml
URL: 
http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/applications/party/config/PartyErrorUiLabels.xml?rev=1831867&r1=1831866&r2=1831867&view=diff
==============================================================================
--- 
ofbiz/ofbiz-framework/trunk/applications/party/config/PartyErrorUiLabels.xml 
(original)
+++ 
ofbiz/ofbiz-framework/trunk/applications/party/config/PartyErrorUiLabels.xml 
Fri May 18 15:53:35 2018
@@ -52,6 +52,18 @@
         <value 
xml:lang="zh">错误:沟通事件不是电子邮件沟通,所以不能发邮件,沟通事件æ
 ‡è¯† </value>
         <value 
xml:lang="zh-TW">錯誤:通訊事件不是電子郵件通訊,所以不能發郵件,通訊事件識別
 </value>
     </property>
+    <property 
key="commeventservices.communication_event_from_contact_mech_must_be_ftp">
+        <value xml:lang="de">FEHLER: Kommunikationsereignis muss ein 
"Kontaktmechanismus von" besitzen das ein ftp server als Kommunikationereignis 
ID ist</value>
+        <value xml:lang="en">ERROR: Communication event must have a from 
contact mech that is an ftp server for communication event Id</value>
+        <value xml:lang="es">Error: Los eventos de comunicación deben tener 
un servidor ftp asociado</value>
+        <value xml:lang="fr">ERREUR: la réf. d'évènement de communication 
doit avoir une coordonnée qui soit un serveur ftp pour évènement de 
communication</value>
+    </property>
+    <property key="commeventservices.communication_event_must_be_ftp_for_ftp">
+        <value xml:lang="de">FEHLER: Kommunikationsereignis ist keine Ftp 
Kommunikation und kann nicht als Ftp versendet werden für 
Kommunikationsereignis ID</value>
+        <value xml:lang="en">ERROR: Communication event is not an Ftp 
communication and cannot be transfered for communication event Id </value>
+        <value xml:lang="es">ERROR: La comunicación no es un transferencia 
ftp y no puede se enviado</value>
+        <value xml:lang="fr">ERREUR: l'évènement de communication n'est pas 
un transfert ftp et ne peut être envoyé comme réf. d'évènement de 
communication </value>
+    </property>
     <property key="commeventservices.communication_event_not_found_failure">
         <value xml:lang="de">FEHLER: Kommunikationsereignis nicht gefunden mit 
der Kommunikationsereignis ID</value>
         <value xml:lang="en">ERROR: Communication Event not found for 
communication event ID</value>

Modified: 
ofbiz/ofbiz-framework/trunk/applications/party/config/PartyUiLabels.xml
URL: 
http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/applications/party/config/PartyUiLabels.xml?rev=1831867&r1=1831866&r2=1831867&view=diff
==============================================================================
--- ofbiz/ofbiz-framework/trunk/applications/party/config/PartyUiLabels.xml 
(original)
+++ ofbiz/ofbiz-framework/trunk/applications/party/config/PartyUiLabels.xml Fri 
May 18 15:53:35 2018
@@ -34,6 +34,11 @@
         <value xml:lang="zh">年收入</value>
         <value xml:lang="zh-TW">年收入</value>
     </property>
+    <property key="FormFieldTitle_binaryTransfer">
+        <value xml:lang="de">Binären transfer</value>
+        <value xml:lang="en">Binary transfer</value>
+        <value xml:lang="fr">Transfert binaire</value>
+    </property>
     <property key="FormFieldTitle_birthDate">
         <value xml:lang="ar">تاريخ الميلاد</value>
         <value xml:lang="cs">Datum narození</value>
@@ -339,6 +344,11 @@
         <value xml:lang="zh">默认费率</value>
         <value xml:lang="zh-TW">預設費率</value>
     </property>
+    <property key="FormFieldTitle_defaultTimeout">
+        <value xml:lang="de">Voreinstellung timeout</value>
+        <value xml:lang="en">Default timeout</value>
+        <value xml:lang="fr">Expiration par défaut</value>
+    </property>
     <property key="FormFieldTitle_deleteEmail">
         <value xml:lang="ar">حذف البريد الالكتروني</value>
         <value xml:lang="cs">Smazat e-mail</value>
@@ -605,6 +615,11 @@
         <value xml:lang="zh">高度</value>
         <value xml:lang="zh-TW">身高</value>
     </property>
+    <property key="FormFieldTitle_hostname">
+        <value xml:lang="de">Hostname</value>
+        <value xml:lang="en">Host name</value>
+        <value xml:lang="fr">Nom d'hôte</value>
+    </property>
     <property key="FormFieldTitle_infoString">
         <value xml:lang="ar">سلسلة المعلومات</value>
         <value xml:lang="de">Info String</value>
@@ -1392,6 +1407,11 @@
         <value xml:lang="zh">会员类型标识</value>
         <value xml:lang="zh-TW">團體類型識別</value>
     </property>
+    <property key="FormFieldTitle_passiveMode">
+        <value xml:lang="de">Passiv modus</value>
+        <value xml:lang="en">Passive mode</value>
+        <value xml:lang="fr">Mode passif</value>
+    </property>
     <property key="FormFieldTitle_passportExpireDate">
         <value xml:lang="ar">تاريخ إنتهاء صلاحية جواز 
السفر</value>
         <value xml:lang="de">Ablaufdatum Pass</value>
@@ -1447,6 +1467,18 @@
         <value xml:lang="zh">密码提示</value>
         <value xml:lang="zh-TW">密碼提示</value>
     </property>
+    <property key="FormFieldTitle_path">
+        <value xml:lang="de">Pfad</value>
+        <value xml:lang="en">Path</value>
+        <value xml:lang="fr">Chemin</value>
+        <value xml:lang="it">Percorso</value>
+        <value xml:lang="ja">パス</value>
+        <value xml:lang="pt">Caminho</value>
+        <value xml:lang="th">Path</value>
+        <value xml:lang="vi">Đường dẫn</value>
+        <value xml:lang="zh">路径</value>
+        <value xml:lang="zh-TW">路徑</value>
+    </property>
     <property key="FormFieldTitle_percentComplete">
         <value xml:lang="ar">نسبة الإتمام</value>
         <value xml:lang="de">Prozent abgeschlossen</value>
@@ -1507,6 +1539,11 @@
         <value xml:lang="zh">个人图片</value>
         <value xml:lang="zh-TW">個人圖片</value>
     </property>
+    <property key="FormFieldTitle_port">
+        <value xml:lang="de">Port</value>
+        <value xml:lang="en">Port</value>
+        <value xml:lang="fr">Port</value>
+    </property>
     <property key="FormFieldTitle_preferredContactMechId">
         <value xml:lang="ar">دليل وسيلة الإتصال الم
فضلة</value>
         <value xml:lang="cs">Preferovaný způsob kontaktu</value>
@@ -1995,6 +2032,11 @@
         <value xml:lang="zh">年为雇主</value>
         <value xml:lang="zh-TW">受雇年數</value>
     </property>
+    <property key="FormFieldTitle_zipFile">
+        <value xml:lang="de">Zipdatei</value>
+        <value xml:lang="en">File compression</value>
+        <value xml:lang="fr">Compression de fichier</value>
+    </property>
     <property key="NewProspect">
         <value xml:lang="ar">تم إنشاء بروسبكت جديد 
بنجاح.</value>
         <value xml:lang="de">Neuer Prospect wurde erfolgreich erstellt.</value>
@@ -7379,6 +7421,11 @@
         <value xml:lang="zh">找不到家庭电话号码。</value>
         <value xml:lang="zh-TW">沒有家裡電話號碼.</value>
     </property>
+    <property key="PartyHostnameMustContainProtocol">
+        <value xml:lang="de">Der Hostname muss das Protokoll enthalten</value>
+        <value xml:lang="en">Hostname must contain the protocol</value>
+        <value xml:lang="fr">Le nom d'hôte doit contenir le protocole</value>
+    </property>
     <property key="PartyImportInvalidCsvFile">
         <value xml:lang="ar">نمط ملف الCSV غير صالح (الم
فتاح, القيمة, التسلسل)</value>
         <value xml:lang="de">Ungültiges CSV Format (Schlüssel, Wert, 
Sequenz)</value>

Added: 
ofbiz/ofbiz-framework/trunk/applications/party/groovyScripts/party/ContactMechServices.groovy
URL: 
http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/applications/party/groovyScripts/party/ContactMechServices.groovy?rev=1831867&view=auto
==============================================================================
--- 
ofbiz/ofbiz-framework/trunk/applications/party/groovyScripts/party/ContactMechServices.groovy
 (added)
+++ 
ofbiz/ofbiz-framework/trunk/applications/party/groovyScripts/party/ContactMechServices.groovy
 Fri May 18 15:53:35 2018
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+import org.apache.ofbiz.entity.GenericValue
+import org.apache.ofbiz.service.ModelService
+import org.apache.ofbiz.service.ServiceUtil
+
+/**
+ * Create FtpAddress contact Mech
+ */
+def createFtpAddress() {
+    Map contactMech = run service: 'createContactMech', with: 
[contactMechTypeId: 'FTP_ADDRESS']
+    String contactMechId = contactMech.contactMechId
+    if (contactMechId) {
+        GenericValue ftpAddress = makeValue('FtpAddress', parameters)
+        ftpAddress.contactMechId = contactMechId
+        ftpAddress.create()
+    } else return error('Error creating contactMech')
+
+    Map resultMap = success()
+    resultMap.contactMechId = contactMechId
+    return resultMap
+}
+
+/**
+ * Update FtpAddress contact Mech
+ */
+def updateFtpAddressWithHistory() {
+    Map resultMap = success()
+    resultMap.oldContactMechId = parameters.contactMechId
+    resultMap.contactMechId = parameters.contactMechId
+    Map newContactMechResult
+    if (resultMap.oldContactMechId) {
+        newValue = makeValue('FtpAddress', parameters)
+        if (newValue != from('FtpAddress').where(parameters).queryOne()) {  // 
if there is some modifications in FtpAddress data
+            newContactMechResult = run service: 'createFtpAddress', with: 
parameters
+        } else { //update only contactMech
+            Map updateContactMechMap = 
dispatcher.getDispatchContext().makeValidContext('updateContactMech', 
ModelService.IN_PARAM, parameters)
+            updateContactMechMap.contactMechTypeId = 'FTP_ADDRESS'
+            newContactMechResult = run service: 'updateContactMech', with: 
updateContactMechMap
+        }
+
+        if 
(!resultMap.oldContactMechId.equals(newContactMechResult.contactMechId)) {
+            resultMap.put('contactMechId', newContactMechResult.contactMechId)
+        }
+    }
+    return resultMap
+}
+
+/**
+ * Create FtpAddress contact Mech and link it with given partyId
+ * @return
+ */
+def createPartyFtpAddress() {
+    Map contactMech = run service: 'createFtpAddress', with: parameters
+    if (ServiceUtil.isError(contactMech)) return contactMech
+    String contactMechId = contactMech.contactMechId
+
+    Map createPartyContactMechMap = parameters
+    createPartyContactMechMap.put('contactMechId', contactMechId)
+    Map serviceResult = run service: 'createPartyContactMech', with: 
createPartyContactMechMap
+    if (ServiceUtil.isError(serviceResult)) return serviceResult
+
+    //TODO: manage purpose
+
+    Map resultMap = success()
+    resultMap.contactMechId = contactMechId
+    return resultMap
+}
+
+def updatePartyFtpAddress() {
+    Map updateFtpResult = run service: 'updateFtpAddressWithHistory', with: 
parameters
+    Map result = success()
+    result.contactMechId = parameters.contactMechId
+    if (parameters.contactMechId != updateFtpResult.contactMechId) {
+        Map updatePartyContactMechMap = 
dispatcher.getDispatchContext().makeValidContext('updatePartyContactMech', 
ModelService.IN_PARAM, parameters)
+        updatePartyContactMechMap.newContactMechId = 
updateFtpResult.contactMechId
+        updatePartyContactMechMap.contactMechTypeId = 'FTP_ADDRESS'
+        run service: 'updatePartyContactMech', with: updatePartyContactMechMap
+        result.contactMechId = updateFtpResult.contactMechId
+    }
+    return result
+}

Propchange: 
ofbiz/ofbiz-framework/trunk/applications/party/groovyScripts/party/ContactMechServices.groovy
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
ofbiz/ofbiz-framework/trunk/applications/party/groovyScripts/party/ContactMechServices.groovy
------------------------------------------------------------------------------
    svn:keywords = Date Rev Author URL Id

Propchange: 
ofbiz/ofbiz-framework/trunk/applications/party/groovyScripts/party/ContactMechServices.groovy
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: ofbiz/ofbiz-framework/trunk/applications/party/servicedef/secas.xml
URL: 
http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/applications/party/servicedef/secas.xml?rev=1831867&r1=1831866&r2=1831867&view=diff
==============================================================================
--- ofbiz/ofbiz-framework/trunk/applications/party/servicedef/secas.xml 
(original)
+++ ofbiz/ofbiz-framework/trunk/applications/party/servicedef/secas.xml Fri May 
18 15:53:35 2018
@@ -92,7 +92,16 @@ under the License.
         <condition field-name="communicationEventId" operator="is-not-empty"/>
         <action service="updateCommEventAfterEmail" mode="sync" 
run-as-user="system"/>
     </eca>
-    
+
+    <eca service="sendContentToFtp" event="in-validate">
+        <condition field-name="communicationEventId" operator="is-empty"/>
+        <action service="createCommEventFromFtpTransfer" mode="sync" 
run-as-user="system"/>
+    </eca>
+    <eca service="sendContentToFtp" event="commit">
+        <condition field-name="communicationEventId" operator="is-not-empty"/>
+        <action service="setCommEventComplete" mode="sync" 
run-as-user="system"/>
+    </eca>
+
     <!-- all these secas are now replaced by a sheduled job (sendEmailDated) 
which runs every 5 minutes -->
 
     <!-- After all the emails have been sent to a contact list, mark it as 
complete. -->

Modified: ofbiz/ofbiz-framework/trunk/applications/party/servicedef/services.xml
URL: 
http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/applications/party/servicedef/services.xml?rev=1831867&r1=1831866&r2=1831867&view=diff
==============================================================================
--- ofbiz/ofbiz-framework/trunk/applications/party/servicedef/services.xml 
(original)
+++ ofbiz/ofbiz-framework/trunk/applications/party/servicedef/services.xml Fri 
May 18 15:53:35 2018
@@ -564,7 +564,40 @@ under the License.
         <attribute name="partyIdFrom" type="String" mode="IN" 
optional="false"/>
         <attribute name="partyIdTo" type="String" mode="IN" optional="false"/>
     </service>
-
+    <service name="createPartyFtpAddress" engine="groovy"
+             
location="component://party/groovyScripts/party/ContactMechServices.groovy" 
invoke="createPartyFtpAddress" auth="true">
+        <description>Create an Ftp Address associated to a party</description>
+        <permission-service service-name="partyContactMechPermissionCheck" 
main-action="CREATE"/>
+        <auto-attributes entity-name="ContactMech" include="nonpk" mode="IN" 
optional="true"/>
+        <auto-attributes entity-name="PartyContactMech" mode="IN" 
optional="true"/>
+        <auto-attributes entity-name="FtpAddress" mode="IN" optional="true"/>
+        <attribute name="contactMechPurposeTypeId" type="String" mode="IN" 
optional="true"/>
+        <attribute name="contactMechId" type="String" mode="INOUT" 
optional="true"/>
+    </service>
+    <service name="updatePartyFtpAddress" engine="groovy"
+             
location="component://party/groovyScripts/party/ContactMechServices.groovy" 
invoke="updatePartyFtpAddress" auth="true">
+        <description>Update an Ftp Address associated to a party</description>
+        <permission-service service-name="partyContactMechPermissionCheck" 
main-action="UPDATE"/>
+        <auto-attributes entity-name="PartyContactMech" mode="IN" 
optional="true"/>
+        <auto-attributes entity-name="FtpAddress" mode="IN" optional="true"/>
+        <attribute name="contactMechId" type="String" mode="INOUT"/>
+    </service>
+    <service name="createFtpAddress" default-entity-name="FtpAddress" 
engine="groovy" invoke="createFtpAddress"
+             
location="component://party/groovyScripts/party/ContactMechServices.groovy">
+        <description>create FtpAddress</description>
+        <permission-service service-name="partyBasePermissionCheck" 
main-action="CREATE"/>
+        <auto-attributes mode="OUT" include="pk"/>
+        <auto-attributes mode="IN" include="nonpk" optional="true"/>
+    </service>
+    <service name="updateFtpAddressWithHistory" 
default-entity-name="FtpAddress" engine="groovy" 
invoke="updateFtpAddressWithHistory"
+        
location="component://party/groovyScripts/party/ContactMechServices.groovy">
+        <description>update FtpAddress</description>
+        <permission-service service-name="partyBasePermissionCheck" 
main-action="UPDATE"/>
+        <auto-attributes mode="IN" include="pk"/>
+        <auto-attributes mode="IN" include="nonpk" optional="true"/>
+        <attribute name="contactMechId" type="String" mode="INOUT"/> <!-- the 
out paramater is the id of the new address -->
+        <attribute name="oldContactMechId" type="String" mode="OUT"/> <!-- 
this is the id of the old address -->
+    </service>
     <!-- contact mech attribute services -->
     <service name="createContactMechAttribute" engine="entity-auto" 
default-entity-name="ContactMechAttribute" invoke="create" auth="true">
         <description>create a contact mech attribute record</description>
@@ -886,6 +919,25 @@ under the License.
             be of type EMAIL_COMMUNICATION. Will look for a contactMechIdTo to 
send the emails</description>
         <attribute name="communicationEventId" type="String" mode="IN" 
optional="false"/>
     </service>
+    <!-- ftp communicationEvent services -->
+    <service name="sendCommEventAsFtp" engine="java"
+             
location="org.apache.ofbiz.party.communication.CommunicationEventServices" 
invoke="sendCommEventAsFtp" auth="true"
+             transaction-timeout="7200">  <!-- set transaction time out for 2 
hours, since this sometimes may last long during big file transfer -->
+        <description>Sends communication event associated contents to a ftp 
server. All parameters come from CommunicationEvent, which must
+            be of type FILE_TRANSFER_COMM. Will look for a contactMechIdTo to 
connect to Ftp</description>
+        <attribute name="communicationEventId" type="String" mode="IN"/>
+    </service>
+    <service name="createCommEventFromFtpTransfer" engine="java"
+             
location="org.apache.ofbiz.party.communication.CommunicationEventServices" 
invoke="createCommEventFromFtpTransfer" auth="true">
+        <description>Creates a CommunicationEvent record based on information 
before
+            running a sendContentToFtp service (to be used via ECA)
+        </description>
+        <attribute name="partyId" type="String" mode="IN" optional="true"/>
+        <attribute name="contentId" type="String" mode="IN"/>
+        <attribute name="contactMechId" type="String" mode="IN"/>
+        <attribute name="communicationEventId" type="String" mode="OUT"/>
+    </service>
+
 
     <!--  email to communication event ECA services -->
     <service name="createCommEventFromEmail" engine="java"

Modified: 
ofbiz/ofbiz-framework/trunk/applications/party/src/main/java/org/apache/ofbiz/party/communication/CommunicationEventServices.java
URL: 
http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/applications/party/src/main/java/org/apache/ofbiz/party/communication/CommunicationEventServices.java?rev=1831867&r1=1831866&r2=1831867&view=diff
==============================================================================
--- 
ofbiz/ofbiz-framework/trunk/applications/party/src/main/java/org/apache/ofbiz/party/communication/CommunicationEventServices.java
 (original)
+++ 
ofbiz/ofbiz-framework/trunk/applications/party/src/main/java/org/apache/ofbiz/party/communication/CommunicationEventServices.java
 Fri May 18 15:53:35 2018
@@ -270,6 +270,139 @@ public class CommunicationEventServices
         return result;
     }
 
+    /**
+     * Service to send all content associated to a FILE_TRANSFER_COMM 
CommunicationEvent,
+     * with contactMechIdTo as a FtpAdress contactMech
+     *
+     * @param ctx
+     * @param context
+     * @return
+     */
+    public static Map<String, Object> sendCommEventAsFtp(DispatchContext ctx, 
Map<String, ?> context) {
+        Delegator delegator = ctx.getDelegator();
+        LocalDispatcher dispatcher = ctx.getDispatcher();
+        Locale locale = (Locale) context.get("locale");
+        GenericValue userLogin = (GenericValue) context.get("userLogin");
+
+        String communicationEventId = (String) 
context.get("communicationEventId");
+        List<String> errorMessages = new ArrayList<>();
+        try {
+            GenericValue communicationEvent = 
EntityQuery.use(delegator).from("CommunicationEvent").where("communicationEventId",
 communicationEventId).queryOne();
+            if (communicationEvent == null) {
+                String errMsg = UtilProperties.getMessage(resource, 
"commeventservices.communication_event_not_found_failure", locale);
+                return ServiceUtil.returnError(errMsg + " " + 
communicationEventId);
+            }
+
+            if 
("COM_COMPLETE".equals(communicationEvent.getString("statusId"))) return 
ServiceUtil.returnSuccess();
+
+            String communicationEventType = 
communicationEvent.getString("communicationEventTypeId");
+            if (communicationEventType == null || 
!"FILE_TRANSFER_COMM".equals(communicationEventType)) {
+                String errMsg = UtilProperties.getMessage(resource, 
"commeventservices.communication_event_must_be_ftp_for_ftp", locale);
+                return ServiceUtil.returnError(errMsg + " " + 
communicationEventId);
+            }
+
+            String contactMechId = 
communicationEvent.getString("contactMechIdTo");
+
+            // Check contactMech type to FTP_ADDRESS
+            GenericValue contactMech = 
EntityQuery.use(delegator).from("ContactMech").cache().where("contactMechId",contactMechId).queryOne();
+            GenericValue ftpAddress = 
EntityQuery.use(delegator).from("FtpAddress").cache().where("contactMechId",contactMechId).queryOne();
+            if (null == contactMech || null == ftpAddress || 
!"FTP_ADDRESS".equals(contactMech.getString("contactMechTypeId"))) {
+                String errMsg = UtilProperties.getMessage(resource, 
"commeventservices.communication_event_to_contact_mech_must_be_ftp", locale);
+                return ServiceUtil.returnError(errMsg + " " + 
communicationEventId);
+            }
+
+            // Get list of children communication events, to avoid same 
content multi-send
+            List<GenericValue> childrenCommunicationEvent = 
EntityQuery.use(delegator).select("communicationEventId", "statusId")
+                    .from("CommunicationEvent").where("parentCommEventId", 
communicationEventId).cache().queryList();
+            List<String> childrenCommunicationEventIds = 
EntityUtil.getFieldListFromEntityList(childrenCommunicationEvent, 
"communicationEventId", true);
+            // Retrieve all contents to send
+            List<GenericValue> contents = 
EntityQuery.use(delegator).from("CommEventContentDataResource").where("communicationEventId",
 communicationEventId).cache().queryList();
+
+            if (UtilValidate.isNotEmpty(contents)) {
+                if 
(UtilValidate.isEmpty(communicationEvent.getTimestamp("datetimeStarted"))) {
+                    //store the startDate into the communication
+                    Map<String, Object> updateCommEventResult = 
dispatcher.runSync("updateCommunicationEvent",
+                            UtilMisc.toMap("communicationEventId", 
communicationEventId, "datetimeStarted", UtilDateTime.nowTimestamp(), 
"userLogin", userLogin), 600, true);
+                    if (ServiceUtil.isError(updateCommEventResult)) {
+                        
errorMessages.add(ServiceUtil.getErrorMessage(updateCommEventResult));
+                    }
+                }
+
+                for (GenericValue content : contents) {
+                    Map<String, Object> ftpServiceMap = new HashMap<>();
+                    //store the child Communication Event, to keep track of 
errorMessages in note field
+                    String childCommunicationEventId = "";
+                    ftpServiceMap.put("userLogin", userLogin);
+                    ftpServiceMap.put("contentId", 
content.getString("contentId"));
+                    ftpServiceMap.put("partyId", 
communicationEvent.getString("partyIdTo"));
+                    ftpServiceMap.put("contactMechId", contactMechId);
+                    // no need to create a child CommEvent if it is a single 
content transfer
+                    if (contents.size() == 1)
+                        ftpServiceMap.put("communicationEventId", 
communicationEvent.get("communicationEventId"));
+                    else {
+                        // check if currentContent is already sent by an 
existing children communicationEvent
+                        EntityCondition sentCond = 
EntityCondition.makeCondition(UtilMisc.toList(
+                                
EntityCondition.makeCondition("communicationEventId", EntityOperator.IN, 
childrenCommunicationEventIds),
+                                EntityCondition.makeCondition("contentId", 
content.getString("contentId"))));
+                        GenericValue alreadySent = 
EntityQuery.use(delegator).from("CommEventContentAssoc").where(sentCond).cache().queryFirst();
+
+                        if (null != alreadySent) {
+                            GenericValue childCommEvent = 
EntityUtil.getFirst(EntityUtil.filterByCondition(childrenCommunicationEvent,
+                                    
EntityCondition.makeCondition("communicationEventId", 
alreadySent.getString("communicationEventId"))));
+                            // if completely sent, continue to next content
+                            if 
("COM_COMPLETE".equals(childCommEvent.getString("statusId"))) continue;
+                            ftpServiceMap.put("communicationEventId", 
childCommEvent.getString("communicationEventId"));
+                        }
+                    }
+
+                    Map<String, Object> resultTmp = 
dispatcher.runSync("sendContentToFtp", ftpServiceMap, 600, true);
+                    if (ServiceUtil.isError(resultTmp)) {
+                        
errorMessages.add(ServiceUtil.getErrorMessage(resultTmp));
+                    }
+
+                    // attach the parent communication event to the new event 
created when sending the content, and store error if needed
+                    if 
(UtilValidate.isNotEmpty(resultTmp.get("communicationEventId"))) 
childCommunicationEventId = (String) resultTmp.get("communicationEventId");
+                    if (UtilValidate.isNotEmpty(childCommunicationEventId) && 
!childCommunicationEventId.equals(communicationEventId)) {
+                        GenericValue childCommunicationEvent = 
EntityQuery.use(delegator).from("CommunicationEvent").where("communicationEventId",
 childCommunicationEventId).queryOne();
+                        childCommunicationEvent.set("parentCommEventId", 
communicationEventId);
+                        if (ServiceUtil.isError(resultTmp)) {
+                            childCommunicationEvent.set("statusId", 
"COM_BOUNCED");
+                            childCommunicationEvent.set("note", 
ServiceUtil.getErrorMessage(resultTmp));
+                        }
+                        childCommunicationEvent.store();
+                    }
+                }
+            } else {
+                errorMessages.add(UtilProperties.getMessage(resource, 
"commeventservices.communication_event_not_without_content", locale));
+            }
+
+            if (errorMessages.size() > 0) {
+                communicationEvent.set("statusId", "COM_BOUNCED");
+                communicationEvent.set("note", errorMessages.toString());
+                communicationEvent.store();
+            } else {
+                //Update content status
+                for (GenericValue content : contents) {
+                    Map<String, Object> updateContentResult = 
dispatcher.runSync("setContentStatus", UtilMisc.<String, 
Object>toMap("contentId", content.getString("contentId"), "statusId", 
"CTNT_PUBLISHED", "userLogin", userLogin));
+                    if (ServiceUtil.isError(updateContentResult)) {
+                        
errorMessages.add(ServiceUtil.getErrorMessage(updateContentResult));
+                    }
+                }
+
+                Map<String, Object> completeResult = 
dispatcher.runSync("setCommEventComplete", UtilMisc.<String, 
Object>toMap("communicationEventId", communicationEventId, "userLogin", 
userLogin));
+                if (ServiceUtil.isError(completeResult)) {
+                    
errorMessages.add(ServiceUtil.getErrorMessage(completeResult));
+                }
+            }
+        } catch (GenericEntityException | GenericServiceException e) {
+            return ServiceUtil.returnError(e.getMessage());
+        }
+        if (errorMessages.size() > 0) {
+            return ServiceUtil.returnFailure(errorMessages);
+        }
+        return ServiceUtil.returnSuccess();
+    }
+
     public static Map<String, Object> sendEmailToContactList(DispatchContext 
ctx, Map<String, ? extends Object> context) {
         Delegator delegator = ctx.getDelegator();
         LocalDispatcher dispatcher = ctx.getDispatcher();
@@ -514,7 +647,7 @@ public class CommunicationEventServices
         String partyIdFrom = (String) context.get("partyIdFrom");
 
         try {
-            GenericValue communicationEvent = 
delegator.findOne("CommunicationEvent", true, "communicationEventId", 
communicationEventId);
+            GenericValue communicationEvent = 
EntityQuery.use(delegator).from("CommunicationEvent").where("communicationEventId",
 communicationEventId).cache().queryOne();
             if (communicationEvent == null) {
                 return 
ServiceUtil.returnError(UtilProperties.getMessage("PartyUiLabels", 
"PartyCommunicationEventNotFound",
                         UtilMisc.toMap("communicationEventId", 
communicationEventId), (Locale) context.get("locale")));
@@ -536,6 +669,60 @@ public class CommunicationEventServices
     }
 
     /*
+     * Store an outgoing file transfer as a communication event;
+     * runs as a pre-invoke ECA on sendContentToFtp service
+     * - service should run as the 'system' user
+     */
+    public static Map<String, Object> 
createCommEventFromFtpTransfer(DispatchContext dctx, Map<String, ? extends 
Object> context) {
+        LocalDispatcher dispatcher = dctx.getDispatcher();
+
+        GenericValue userLogin = (GenericValue) context.get("userLogin");
+        String contentId = (String) context.get("contentId");
+        String contactMechId = (String) context.get("contactMechId");
+        String partyId = (String) context.get("partyId");
+        String communicationEventId;
+
+        Timestamp now = UtilDateTime.nowTimestamp();
+
+        Map<String, Object> commEventMap = new HashMap<>();
+        commEventMap.put("communicationEventTypeId", "FILE_TRANSFER_COMM");
+        commEventMap.put("contactMechTypeId", "FTP_ADDRESS");
+        commEventMap.put("contactMechIdTo", contactMechId);
+        commEventMap.put("statusId", "COM_PENDING");
+        commEventMap.put("datetimeStarted", now);
+        commEventMap.put("entryDate", now);
+        commEventMap.put("userLogin", userLogin);
+        if (UtilValidate.isNotEmpty(partyId)) {
+            commEventMap.put("partyIdTo", partyId);
+        }
+
+        Map<String, Object> createResult;
+        try {
+            createResult = dispatcher.runSync("createCommunicationEvent", 
commEventMap);
+            if (ServiceUtil.isError(createResult)) {
+                return createResult;
+            }
+            communicationEventId = (String) 
createResult.get("communicationEventId");
+
+            //add content to newly created commEvent
+            Map createCommEventContentMap = new HashMap<>();
+            createCommEventContentMap.put("userLogin", userLogin);
+            createCommEventContentMap.put("contentId", contentId);
+            createCommEventContentMap.put("communicationEventId", 
communicationEventId);
+            createResult = dispatcher.runSync("createCommEventContentAssoc", 
createCommEventContentMap);
+            if (ServiceUtil.isError(createResult)) {
+                return createResult;
+            }
+        } catch (GenericServiceException e) {
+            Debug.logError(e, module);
+            return ServiceUtil.returnError(e.getMessage());
+        }
+        Map<String, Object> result = ServiceUtil.returnSuccess();
+        result.put("communicationEventId", communicationEventId);
+        return result;
+    }
+
+    /*
      * Store an outgoing email as a communication event;
      * runs as a pre-invoke ECA on sendMail and sendMultipartMail services
      * - service should run as the 'system' user

Modified: 
ofbiz/ofbiz-framework/trunk/applications/party/src/main/java/org/apache/ofbiz/party/contact/ContactMechWorker.java
URL: 
http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/applications/party/src/main/java/org/apache/ofbiz/party/contact/ContactMechWorker.java?rev=1831867&r1=1831866&r2=1831867&view=diff
==============================================================================
--- 
ofbiz/ofbiz-framework/trunk/applications/party/src/main/java/org/apache/ofbiz/party/contact/ContactMechWorker.java
 (original)
+++ 
ofbiz/ofbiz-framework/trunk/applications/party/src/main/java/org/apache/ofbiz/party/contact/ContactMechWorker.java
 Fri May 18 15:53:35 2018
@@ -123,6 +123,8 @@ public class ContactMechWorker {
                         partyContactMechValueMap.put("postalAddress", 
contactMech.getRelatedOne("PostalAddress", false));
                     } else if 
("TELECOM_NUMBER".equals(contactMech.getString("contactMechTypeId"))) {
                         partyContactMechValueMap.put("telecomNumber", 
contactMech.getRelatedOne("TelecomNumber", false));
+                    } else if 
("FTP_ADDRESS".equals(contactMech.getString("contactMechTypeId"))) {
+                        partyContactMechValueMap.put("ftpAddress", 
contactMech.getRelatedOne("FtpAddress", false));
                     }
                 } catch (GenericEntityException e) {
                     Debug.logWarning(e, module);
@@ -463,6 +465,8 @@ public class ContactMechWorker {
                 requestName = "createTelecomNumber";
             } else if ("EMAIL_ADDRESS".equals(contactMechTypeId)) {
                 requestName = "createEmailAddress";
+            } else if ("FTP_ADDRESS".equals(contactMechTypeId)) {
+                requestName = "createFtpAddress";
             } else {
                 requestName = "createContactMech";
             }
@@ -474,6 +478,8 @@ public class ContactMechWorker {
                 requestName = "updateTelecomNumber";
             } else if ("EMAIL_ADDRESS".equals(contactMechTypeId)) {
                 requestName = "updateEmailAddress";
+            } else if ("FTP_ADDRESS".equals(contactMechTypeId)) {
+                requestName = "updateFtpAddress";
             } else {
                 requestName = "updateContactMech";
             }
@@ -506,6 +512,19 @@ public class ContactMechWorker {
             if (telecomNumber != null) {
                 target.put("telecomNumber", telecomNumber);
             }
+        } else if ("FTP_ADDRESS".equals(contactMechTypeId)) {
+            GenericValue ftpAddress = null;
+
+            try {
+                if (contactMech != null) {
+                    ftpAddress = contactMech.getRelatedOne("FtpAddress", 
false);
+                }
+            } catch (GenericEntityException e) {
+                Debug.logWarning(e, module);
+            }
+            if (ftpAddress != null) {
+                target.put("ftpAddress", ftpAddress);
+            }
         }
 
         if ("true".equals(request.getParameter("useValues"))) {

Modified: 
ofbiz/ofbiz-framework/trunk/applications/party/template/party/EditContactMech.ftl
URL: 
http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/applications/party/template/party/EditContactMech.ftl?rev=1831867&r1=1831866&r2=1831867&view=diff
==============================================================================
--- 
ofbiz/ofbiz-framework/trunk/applications/party/template/party/EditContactMech.ftl
 (original)
+++ 
ofbiz/ofbiz-framework/trunk/applications/party/template/party/EditContactMech.ftl
 Fri May 18 15:53:35 2018
@@ -200,12 +200,86 @@ under the License.
       <td>[${uiLabelMap.CommonCountryCode}] [${uiLabelMap.PartyAreaCode}] 
[${uiLabelMap.PartyContactNumber}] [${uiLabelMap.PartyContactExt}]</td>
     </tr>
   <#elseif "EMAIL_ADDRESS" = mechMap.contactMechTypeId!>
-    <tr>
-      <td 
class="label">${mechMap.contactMechType.get("description",locale)}</td>
-      <td>
-        <input type="text" size="60" maxlength="255" name="emailAddress" 
value="${(mechMap.contactMech.infoString)?default(request.getParameter('emailAddress')!)}"
 />
-      </td>
-    </tr>
+      <tr>
+          <td 
class="label">${mechMap.contactMechType.get("description",locale)}</td>
+          <td>
+              <input type="text" size="60" maxlength="255" name="emailAddress" 
value="${(mechMap.contactMech.infoString)?default(request.getParameter('emailAddress')!)}"
 />
+          </td>
+      </tr>
+  <#elseif "FTP_ADDRESS" = mechMap.contactMechTypeId!>
+      <tr>
+          <td class="label">${uiLabelMap.FormFieldTitle_hostname}</td>
+          <td>
+              <input type="text" size="60" maxlength="255" name="hostname" 
value="${(mechMap.ftpAddress.hostname)!request.getParameter('hostname')!}" />
+              <span 
class="tooltip">${uiLabelMap.PartyHostnameMustContainProtocol} (ftp://, 
sftp://, ftps://...)</span>
+          </td>
+      </tr>
+      <tr>
+          <td class="label">${uiLabelMap.FormFieldTitle_port}</td>
+          <td>
+              <input type="text" size="6" maxlength="6" name="port" 
value="${(mechMap.ftpAddress.port)!request.getParameter('port')!}" />
+          </td>
+      </tr>
+      <tr>
+          <td class="label">${uiLabelMap.CommonUsername}</td>
+          <td>
+              <input type="text" size="60" maxlength="255" name="username" 
value="${(mechMap.ftpAddress.username)!request.getParameter('username')!''}" />
+          </td>
+      </tr>
+      <tr>
+          <td class="label">${uiLabelMap.CommonPassword}</td>
+          <td>
+              <input type="text" size="60" maxlength="255" name="password" 
value="${(mechMap.ftpAddress.password)!request.getParameter('password')!''}" />
+          </td>
+      </tr>
+      <tr>
+          <td class="label">${uiLabelMap.FormFieldTitle_binaryTransfer}</td>
+          <td>
+              <select name="binaryTransfer">
+                  <#if "Y" == (mechMap.ftpAddress.binaryTransfer)!""><option 
value="Y">${uiLabelMap.CommonY}</option></#if>
+                  <#if "N" == (mechMap.ftpAddress.binaryTransfer)!""><option 
value="N">${uiLabelMap.CommonN}</option></#if>
+                  <option></option>
+                  <option value="Y">${uiLabelMap.CommonY}</option>
+                  <option value="N">${uiLabelMap.CommonN}</option>
+              </select>
+          </td>
+      </tr>
+      <tr>
+          <td class="label">${uiLabelMap.FormFieldTitle_path}</td>
+          <td>
+              <input type="text" size="60" maxlength="255" name="path" 
value="${(mechMap.ftpAddress.path)!request.getParameter('path')!''}" />
+          </td>
+      </tr>
+      <tr>
+          <td class="label">${uiLabelMap.FormFieldTitle_zipFile}</td>
+          <td>
+              <select name="zipFile">
+                  <#if "Y" == (mechMap.ftpAddress.zipFile)!""><option 
value="Y">${uiLabelMap.CommonY}</option></#if>
+                  <#if "N" == (mechMap.ftpAddress.zipFile)!""><option 
value="N">${uiLabelMap.CommonN}</option></#if>
+                  <option></option>
+                  <option value="Y">${uiLabelMap.CommonY}</option>
+                  <option value="N">${uiLabelMap.CommonN}</option>
+              </select>
+          </td>
+      </tr>
+      <tr>
+          <td class="label">${uiLabelMap.FormFieldTitle_passiveMode}</td>
+          <td>
+              <select name="passiveMode">
+                  <#if "Y" == (mechMap.ftpAddress.passiveMode)!""><option 
value="Y">${uiLabelMap.CommonY}</option></#if>
+                  <#if "N" == (mechMap.ftpAddress.passiveMode)!""><option 
value="N">${uiLabelMap.CommonN}</option></#if>
+                  <option></option>
+                  <option value="Y">${uiLabelMap.CommonY}</option>
+                  <option value="N">${uiLabelMap.CommonN}</option>
+              </select>
+          </td>
+      </tr>
+      <tr>
+          <td class="label">${uiLabelMap.FormFieldTitle_defaultTimeout}</td>
+          <td>
+              <input type="text" size="10" maxlength="10" 
name="defaultTimeout" 
value="${(mechMap.ftpAddress.defaultTimeout)!request.getParameter('defaultTimeout')!''}"
 />
+          </td>
+      </tr>
   <#else>
     <tr>
       <td 
class="label">${mechMap.contactMechType.get("description",locale)}</td>

Modified: 
ofbiz/ofbiz-framework/trunk/applications/party/template/party/profileblocks/Contact.ftl
URL: 
http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/applications/party/template/party/profileblocks/Contact.ftl?rev=1831867&r1=1831866&r2=1831867&view=diff
==============================================================================
--- 
ofbiz/ofbiz-framework/trunk/applications/party/template/party/profileblocks/Contact.ftl
 (original)
+++ 
ofbiz/ofbiz-framework/trunk/applications/party/template/party/profileblocks/Contact.ftl
 Fri May 18 15:53:35 2018
@@ -95,6 +95,19 @@ under the License.
                       <input name="communicationEventTypeId" 
value="EMAIL_COMMUNICATION" type="hidden"/>
                     </form><a class="buttontext" 
href="javascript:document.createEmail${contactMech.infoString?replace('&#64;','')?replace('&#x40;','')?replace('.','')}.submit()">${uiLabelMap.CommonSendEmail}</a>
                   </div>
+                <#elseif "FTP_ADDRESS" = contactMech.contactMechTypeId>
+                    <#if contactMechMap.ftpAddress?has_content>
+                    <#assign ftpAddress = contactMechMap.ftpAddress>
+                    <div>
+                        <b><#if 
ftpAddress.hostname?has_content>${ftpAddress.hostname!}</#if><#if 
ftpAddress.port?has_content>:${ftpAddress.port!}</#if><#if 
ftpAddress.path?has_content>:${ftpAddress.path!}</#if></b>
+                        <br/>${uiLabelMap.CommonUsername} : 
${ftpAddress.username!}
+                        <br/>${uiLabelMap.CommonPassword} : 
${ftpAddress.password!}
+                        <br/>${uiLabelMap.FormFieldTitle_binaryTransfer} : 
${ftpAddress.binaryTransfer!}
+                        <br/>${uiLabelMap.FormFieldTitle_zipFile} : 
${ftpAddress.zipFile!}
+                        <br/>${uiLabelMap.FormFieldTitle_passiveMode} : 
${ftpAddress.passiveMode!}
+                        <br/>${uiLabelMap.FormFieldTitle_defaultTimeout} : 
${ftpAddress.defaultTimeout!}
+                    </div>
+                    </#if>
                 <#elseif "WEB_ADDRESS" = contactMech.contactMechTypeId>
                   <div>
                     ${contactMech.infoString!}

Modified: 
ofbiz/ofbiz-framework/trunk/applications/party/webapp/partymgr/WEB-INF/controller.xml
URL: 
http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/applications/party/webapp/partymgr/WEB-INF/controller.xml?rev=1831867&r1=1831866&r2=1831867&view=diff
==============================================================================
--- 
ofbiz/ofbiz-framework/trunk/applications/party/webapp/partymgr/WEB-INF/controller.xml
 (original)
+++ 
ofbiz/ofbiz-framework/trunk/applications/party/webapp/partymgr/WEB-INF/controller.xml
 Fri May 18 15:53:35 2018
@@ -191,6 +191,19 @@ under the License.
         <response name="error" type="view" value="editcontactmech"/>
     </request-map>
 
+    <request-map uri="createFtpAddress">
+        <security https="true" auth="true"/>
+        <event type="service" invoke="createPartyFtpAddress"/>
+        <response name="success" type="view" value="editcontactmech"/>
+        <response name="error" type="view" value="editcontactmech"/>
+    </request-map>
+    <request-map uri="updateFtpAddress">
+        <security https="true" auth="true"/>
+        <event type="service" invoke="updatePartyFtpAddress"/>
+        <response name="success" type="view" value="editcontactmech"/>
+        <response name="error" type="view" value="editcontactmech"/>
+    </request-map>
+
     <request-map uri="createPartyContactMechPurpose">
         <security https="true" auth="true"/>
         <event type="service" invoke="createPartyContactMechPurpose"/>

Modified: ofbiz/ofbiz-framework/trunk/build.gradle
URL: 
http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/build.gradle?rev=1831867&r1=1831866&r2=1831867&view=diff
==============================================================================
--- ofbiz/ofbiz-framework/trunk/build.gradle (original)
+++ ofbiz/ofbiz-framework/trunk/build.gradle Fri May 18 15:53:35 2018
@@ -131,6 +131,7 @@ dependencies {
     compile 'org.apache.logging.log4j:log4j-api:2.10.0' // the API of log4j 2
     compile 'org.apache.poi:poi:3.17'
     compile 'org.apache.shiro:shiro-core:1.4.0'
+    compile 'org.apache.sshd:sshd-core:1.7.0'
     compile 'org.apache.tika:tika-core:1.16'
     compile 'org.apache.tika:tika-parsers:1.16'
     compile 'org.apache.tomcat:tomcat-catalina-ha:9.0.7'

Added: ofbiz/ofbiz-framework/trunk/framework/common/config/ftp.properties
URL: 
http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/framework/common/config/ftp.properties?rev=1831867&view=auto
==============================================================================
--- ofbiz/ofbiz-framework/trunk/framework/common/config/ftp.properties (added)
+++ ofbiz/ofbiz-framework/trunk/framework/common/config/ftp.properties Fri May 
18 15:53:35 2018
@@ -0,0 +1,35 @@
+###############################################################################
+# 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.
+###############################################################################
+
+# -- ftp notifications enabled (Y|N)
+ftp.notifications.enabled=N
+
+# -- redirect all ftp notifications to this server for testing
+ftp.notifications.redirectTo.enabled=Y
+ftp.notifications.redirectTo.hostname=localhost
+ftp.notifications.redirectTo.port=65535
+ftp.notifications.redirectTo.username=admin
+ftp.notifications.redirectTo.password=ofbiz
+ftp.notifications.redirectTo.binaryTransfer=Y
+ftp.notifications.redirectTo.path=
+ftp.notifications.redirectTo.passiveMode=Y
+ftp.notifications.redirectTo.defaultTimeout=
+
+# -- if you have some pb with a ftp server, set it to Y to force OFBiz to 
control the file copy
+ftp.force.transfer.control=N
\ No newline at end of file


Reply via email to