]> git.basschouten.com Git - openhab-addons.git/blob
2a493628f4aad8fa16cd2af217ee134bde08c5a6
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.ftpupload.internal.ftp;
14
15 import java.io.IOException;
16 import java.util.ArrayList;
17 import java.util.Iterator;
18 import java.util.LinkedHashMap;
19 import java.util.List;
20 import java.util.Map;
21
22 import org.apache.ftpserver.DataConnectionConfiguration;
23 import org.apache.ftpserver.FtpServerConfigurationException;
24 import org.apache.ftpserver.FtpServerFactory;
25 import org.apache.ftpserver.ftplet.DefaultFtplet;
26 import org.apache.ftpserver.ftplet.FileSystemFactory;
27 import org.apache.ftpserver.ftplet.FileSystemView;
28 import org.apache.ftpserver.ftplet.FtpException;
29 import org.apache.ftpserver.ftplet.FtpRequest;
30 import org.apache.ftpserver.ftplet.FtpSession;
31 import org.apache.ftpserver.ftplet.FtpStatistics;
32 import org.apache.ftpserver.ftplet.Ftplet;
33 import org.apache.ftpserver.ftplet.FtpletContext;
34 import org.apache.ftpserver.ftplet.FtpletResult;
35 import org.apache.ftpserver.ftplet.User;
36 import org.apache.ftpserver.listener.Listener;
37 import org.apache.ftpserver.listener.ListenerFactory;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40
41 /**
42  * Simple FTP server implementation to receive files via FTP.
43  *
44  *
45  * @author Pauli Anttila - Initial contribution
46  */
47 public class FtpServer {
48
49     private final Logger logger = LoggerFactory.getLogger(FtpServer.class);
50
51     private int port;
52     private DataConnectionConfiguration dataConnectionConfiguration;
53     int idleTimeout;
54
55     private org.apache.ftpserver.FtpServer server;
56     private List<FtpServerEventListener> listeners;
57     private MyFTPLet myFTPLet;
58     private FTPUserManager FTPUserManager;
59     private String ftpStartUpErrorReason;
60
61     public FtpServer() {
62         listeners = new ArrayList<>();
63         FTPUserManager = new FTPUserManager();
64     }
65
66     public void startServer(int port, int idleTimeout, DataConnectionConfiguration dataConnectionConfiguration)
67             throws FtpException {
68         stopServer();
69         this.port = port;
70         this.idleTimeout = idleTimeout;
71         this.dataConnectionConfiguration = dataConnectionConfiguration;
72         FTPUserManager.setIdleTimeout(idleTimeout);
73         initServer();
74     }
75
76     public void stopServer() {
77         if (server != null) {
78             server.stop();
79         }
80     }
81
82     public String getStartUpErrorReason() {
83         return ftpStartUpErrorReason;
84     }
85
86     public synchronized void addEventListener(FtpServerEventListener listener) {
87         if (!listeners.contains(listener)) {
88             listeners.add(listener);
89         }
90     }
91
92     public synchronized void addAuthenticationCredentials(String username, String password)
93             throws IllegalArgumentException {
94         FTPUserManager.addAuthenticationCredentials(username, password);
95     }
96
97     public synchronized void removeAuthenticationCredentials(String username) {
98         FTPUserManager.removeAuthenticationCredentials(username);
99     }
100
101     public synchronized void removeEventListener(FtpServerEventListener listener) {
102         listeners.remove(listener);
103     }
104
105     private void sendMsgToListeners(String userName, String filename, byte[] data) {
106         Iterator<FtpServerEventListener> iterator = listeners.iterator();
107
108         while (iterator.hasNext()) {
109             try {
110                 iterator.next().fileReceived(userName, filename, data);
111             } catch (Exception e) {
112                 // catch all exceptions give all handlers a fair chance of handling the messages
113                 logger.debug("Event listener invoking error: {}", e.getMessage());
114             }
115         }
116     }
117
118     public void printStats() {
119         FtpStatistics ftpStats = myFTPLet.getStats();
120
121         logger.debug("TotalConnectionNumber: {}", ftpStats.getTotalConnectionNumber());
122         logger.debug("TotalLoginNumber: {}", ftpStats.getTotalLoginNumber());
123         logger.debug("TotalFailedLoginNumber: {}", ftpStats.getTotalFailedLoginNumber());
124         logger.debug("TotalUploadNumber: {}", ftpStats.getTotalUploadNumber());
125         logger.debug("TotalUploadSize: {}", ftpStats.getTotalUploadSize());
126
127         logger.debug("CurrentConnectionNumber: {}", ftpStats.getCurrentConnectionNumber());
128         logger.debug("CurrentLoginNumber: {}", ftpStats.getCurrentLoginNumber());
129     }
130
131     private void initServer() throws FtpException {
132         FtpServerFactory serverFactory = new FtpServerFactory();
133         ListenerFactory listenerFactory = new ListenerFactory();
134
135         listenerFactory.setPort(port);
136         listenerFactory.setIdleTimeout(idleTimeout);
137         listenerFactory.setDataConnectionConfiguration(dataConnectionConfiguration);
138
139         Listener listener = listenerFactory.createListener();
140
141         serverFactory.addListener("default", listener);
142
143         Map<String, Ftplet> ftplets = new LinkedHashMap<>();
144         myFTPLet = new MyFTPLet();
145
146         ftplets.put("ftplet", myFTPLet);
147
148         serverFactory.setFtplets(ftplets);
149         serverFactory.setFileSystem(new FileSystemFactory() {
150             @Override
151             public FileSystemView createFileSystemView(User user) throws FtpException {
152                 logger.debug("createFileSystemView: {}", user.getName());
153                 return new SimpleFileSystemView();
154             }
155         });
156
157         // set the user manager
158         serverFactory.setUserManager(FTPUserManager);
159         server = serverFactory.createServer();
160
161         try {
162             server.start();
163             ftpStartUpErrorReason = null;
164         } catch (FtpException | FtpServerConfigurationException e) {
165             ftpStartUpErrorReason = "Failed to start FTP server";
166             if (!e.getMessage().isEmpty()) {
167                 ftpStartUpErrorReason += ": " + e.getMessage();
168             }
169             throw e;
170         }
171     }
172
173     private class MyFTPLet extends DefaultFtplet {
174         FtpletContext ftpletContext;
175
176         public FtpStatistics getStats() {
177             return ftpletContext.getFtpStatistics();
178         }
179
180         @Override
181         public void init(FtpletContext ftpletContext) throws FtpException {
182             this.ftpletContext = ftpletContext;
183         }
184
185         @Override
186         public void destroy() {
187             logger.trace("destroy");
188         }
189
190         @Override
191         public FtpletResult onConnect(FtpSession session) throws FtpException, IOException {
192             logger.debug("User connected to FtpServer");
193             return super.onConnect(session);
194         }
195
196         @Override
197         public FtpletResult onUploadEnd(final FtpSession session, final FtpRequest request)
198                 throws FtpException, IOException {
199             String userRoot = session.getUser().getHomeDirectory();
200             String currDir = session.getFileSystemView().getWorkingDirectory().getAbsolutePath();
201             String fileName = request.getArgument();
202
203             logger.debug("File {} upload to FTP server", userRoot + currDir + "/" + fileName);
204
205             SimpleFtpFile file = (SimpleFtpFile) session.getFileSystemView().getFile(fileName);
206             byte[] data = file.getData();
207
208             sendMsgToListeners(session.getUser().getName(), fileName, data);
209             return FtpletResult.SKIP;
210         }
211     }
212 }