View Javadoc
1   /*
2    * This file is part of Waarp Project (named also Waarp or GG).
3    *
4    *  Copyright (c) 2019, Waarp SAS, and individual contributors by the @author
5    *  tags. See the COPYRIGHT.txt in the distribution for a full listing of
6    * individual contributors.
7    *
8    *  All Waarp Project is free software: you can redistribute it and/or
9    * modify it under the terms of the GNU General Public License as published by
10   * the Free Software Foundation, either version 3 of the License, or (at your
11   * option) any later version.
12   *
13   * Waarp is distributed in the hope that it will be useful, but WITHOUT ANY
14   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15   * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16   *
17   *  You should have received a copy of the GNU General Public License along with
18   * Waarp . If not, see <http://www.gnu.org/licenses/>.
19   */
20  package org.waarp.ftp.core.control;
21  
22  import io.netty.channel.Channel;
23  import org.waarp.common.command.exception.CommandAbstractException;
24  import org.waarp.common.file.Restart;
25  import org.waarp.common.file.filesystembased.FilesystemBasedOptsMLSxImpl;
26  import org.waarp.ftp.core.command.AbstractCommand;
27  import org.waarp.ftp.core.command.FtpCommandCode;
28  import org.waarp.ftp.core.data.FtpTransfer;
29  import org.waarp.ftp.core.file.FtpAuth;
30  import org.waarp.ftp.core.file.FtpDir;
31  import org.waarp.ftp.core.session.FtpSession;
32  
33  /**
34   * This class is to be implemented in order to allow Business actions according
35   * to FTP service
36   */
37  public abstract class BusinessHandler {
38    private static final String FILENAME = " \"filename\"";
39    private static final String[] PROPERTIES_0_LENGTH = new String[0];
40    /**
41     * NettyHandler that holds this BusinessHandler
42     */
43    private NetworkHandler networkHandler;
44  
45    /**
46     * FtpSession
47     */
48    private FtpSession session;
49  
50    /**
51     * Constructor with no argument (mandatory)
52     */
53    protected BusinessHandler() {
54      // nothing to do
55    }
56  
57    /**
58     * Called when the NetworkHandler is created
59     *
60     * @param networkHandler the networkHandler to set
61     */
62    public final void setNetworkHandler(final NetworkHandler networkHandler) {
63      this.networkHandler = networkHandler;
64      session = this.networkHandler.getFtpSession();
65    }
66  
67    /**
68     * @return the networkHandler
69     */
70    public final NetworkHandler getNetworkHandler() {
71      return networkHandler;
72    }
73  
74    // Some helpful functions
75  
76    /**
77     * @return the ftpSession
78     */
79    public final FtpSession getFtpSession() {
80      return session;
81    }
82  
83    /**
84     * Create a new AuthInterface according to business choice
85     *
86     * @return the new FtpAuth
87     */
88    public abstract FtpAuth getBusinessNewAuth();
89  
90    /**
91     * Create a new FtpDir according to business choice
92     *
93     * @return the new FtpDir
94     */
95    public abstract FtpDir getBusinessNewDir();
96  
97    /**
98     * Create a new Restart according to business choice
99     *
100    * @return the new Restart
101    */
102   public abstract Restart getBusinessNewRestart();
103 
104   /**
105    * @param arg the argument from HELP command
106    *
107    * @return the string to return to the client for the HELP command
108    */
109   public abstract String getHelpMessage(String arg);
110 
111   /**
112    * @return the string to return to the client for the FEAT command
113    */
114   public abstract String getFeatMessage();
115 
116   protected final String getSslFeatMessage() {
117     return "AUTH TLS\nAUTH SSL\nCCC\nPROT P\nPROT C";
118   }
119 
120   /**
121    * @return the string to return to the client for the FEAT command without
122    *     surrounding by "Extensions
123    *     supported:\n" and "\nEnd"
124    */
125   protected final String getDefaultFeatMessage() {
126     final StringBuilder builder = new StringBuilder();
127     builder.append(FtpCommandCode.MODE.name()).append(" Z\n")
128            .append(FtpCommandCode.MDTM.name()).append('\n')
129            .append(FtpCommandCode.MLSD.name())
130            .append(getFtpSession().getDir().getOptsMLSx().getFeat())
131            .append('\n').append(FtpCommandCode.MLST.name())
132            .append(getFtpSession().getDir().getOptsMLSx().getFeat())
133            .append('\n').append(FtpCommandCode.SIZE.name()).append('\n')
134            .append(FtpCommandCode.XCUP.name()).append('\n')
135            .append(FtpCommandCode.XCWD.name()).append('\n')
136            .append(FtpCommandCode.XMKD.name()).append('\n')
137            .append(FtpCommandCode.XPWD.name()).append('\n')
138            .append(FtpCommandCode.XRMD.name()).append('\n')
139            .append(FtpCommandCode.PASV.name()).append('\n')
140            .append(FtpCommandCode.ALLO.name()).append('\n')
141            .append(FtpCommandCode.EPRT.name()).append('\n')
142            .append(FtpCommandCode.EPSV.name()).append('\n')
143            .append(FtpCommandCode.XCRC.name()).append(' ').append(FILENAME)
144            .append('\n').append(FtpCommandCode.XMD5.name()).append(' ')
145            .append(FILENAME).append('\n').append(FtpCommandCode.XSHA1.name())
146            .append(' ').append(FILENAME).append('\n')
147            .append(FtpCommandCode.XDIGEST.name()).append(' ').append(
148                "Digest_algo_among(CRC32,ADLER32,MD5,MD2,SHA-1,SHA-256,SHA-384,SHA-512)")
149            .append(' ').append(FILENAME).append('\n')
150            .append(FtpCommandCode.SITE.name()).append(' ')
151            .append(FtpCommandCode.XCRC.name())
152            // .append(" \"filename\"")
153            .append('\n').append(FtpCommandCode.SITE.name()).append(' ')
154            .append(FtpCommandCode.XMD5.name())
155            // .append(" \"filename\"")
156            .append('\n').append(FtpCommandCode.SITE.name()).append(' ')
157            .append(FtpCommandCode.XSHA1.name())
158            // .append(" \"filename\"")
159            .append('\n').append(FtpCommandCode.SITE.name()).append(' ')
160            .append(FtpCommandCode.XDIGEST.name()).append(' ').append(
161                "Digest_algo_among(CRC32,ADLER32,MD5,MD2,SHA-1,SHA-256,SHA-384,SHA-512)")
162            // .append(" \"filename\"")
163            .append('\n').append("LAN EN*").append('\n')
164            .append(FtpCommandCode.REST.name()).append(" STREAM\n");
165     return builder.toString();
166   }
167 
168   /**
169    * @param args
170    *
171    * @return the string to return to the client for the FEAT command
172    *
173    * @throws CommandAbstractException
174    */
175   public abstract String getOptsMessage(String[] args)
176       throws CommandAbstractException;
177 
178   /**
179    * Check if a command pass to SITE command is legal
180    *
181    * @param session
182    * @param line
183    *
184    * @return the AbstractCommand to execute if it is a Specialized Command,
185    *     else
186    *     Null
187    */
188   public abstract AbstractCommand getSpecializedSiteCommand(FtpSession session,
189                                                             String line);
190 
191   /**
192    * @param args
193    *
194    * @return the string to return to the client for the FEAT command for the
195    *     MLSx argument
196    */
197   protected final String getMLSxOptsMessage(final String[] args) {
198     String[] properties = PROPERTIES_0_LENGTH;
199     if (args.length >= 2) {
200       properties = args[1].split(";");
201     }
202 
203     final FilesystemBasedOptsMLSxImpl optsMLSx =
204         (FilesystemBasedOptsMLSxImpl) getFtpSession().getDir().getOptsMLSx();
205     optsMLSx.setOptsModify((byte) 0);
206     optsMLSx.setOptsPerm((byte) 0);
207     optsMLSx.setOptsSize((byte) 0);
208     optsMLSx.setOptsType((byte) 0);
209     for (final String propertie : properties) {
210       if ("modify".equalsIgnoreCase(propertie)) {
211         optsMLSx.setOptsModify((byte) 1);
212       } else if ("perm".equalsIgnoreCase(propertie)) {
213         optsMLSx.setOptsPerm((byte) 1);
214       } else if ("size".equalsIgnoreCase(propertie)) {
215         optsMLSx.setOptsSize((byte) 1);
216       } else if ("type".equalsIgnoreCase(propertie)) {
217         optsMLSx.setOptsType((byte) 1);
218       }
219     }
220     return args[0] + ' ' + FtpCommandCode.OPTS.name() + optsMLSx.getFeat();
221   }
222 
223   /**
224    * Is executed when the channel is closed, just before cleaning and just
225    * after.<br>
226    * <I>Note: In some circumstances, it could be a good idea to call the clean
227    * operation on FtpAuth in order to
228    * relax constraints on user authentication. It will be called however at
229    * least when the session will be clean
230    * just after this call.</I>
231    */
232   public abstract void executeChannelClosed();
233 
234   /**
235    * To Clean the session attached objects
236    */
237   protected abstract void cleanSession();
238 
239   /**
240    * Clean the BusinessHandler.
241    */
242   public final void clear() {
243     cleanSession();
244   }
245 
246   /**
247    * Is executed when the channel is connected after the handler is on, before
248    * answering OK or not on
249    * connection, except if the global service is going to shutdown.
250    *
251    * @param channel
252    */
253   public abstract void executeChannelConnected(Channel channel);
254 
255   /**
256    * Run when an exception is get before the channel is closed. This must set
257    * a
258    * correct answer.
259    *
260    * @param e
261    */
262   public abstract void exceptionLocalCaught(Throwable e);
263 
264   /**
265    * This method is called for every received message before the execution of
266    * the command. If an exception is
267    * raised, the reply is immediate and no action taken.
268    *
269    * @throws CommandAbstractException
270    */
271   public abstract void beforeRunCommand() throws CommandAbstractException;
272 
273   /**
274    * This method is called for every received message after the execution of
275    * the
276    * command but before the final
277    * reply to the client. If an exception is raised, the reply is immediate.
278    * This is the last call before
279    * finishing the command.
280    *
281    * @throws CommandAbstractException
282    */
283   public abstract void afterRunCommandOk() throws CommandAbstractException;
284 
285   /**
286    * Run when a FTP exception is catch (the channel is not necessary closed
287    * after). This must set a correct
288    * answer and a correct code of reply. If the code of reply is 421, then the
289    * channel will be closed after this
290    * call. This is the last call before finishing the command.
291    *
292    * @param e
293    */
294   public abstract void afterRunCommandKo(CommandAbstractException e);
295 
296   /**
297    * Run when a transfer is finished (eventually in error) but before
298    * answering.
299    * Note that this is called only
300    * for a Transfer Request (or LIST) but called before afterRunCommandXX is
301    * called (Ok or Ko).
302    *
303    * @param transfer
304    *
305    * @throws CommandAbstractException
306    */
307   public abstract void afterTransferDoneBeforeAnswer(FtpTransfer transfer)
308       throws CommandAbstractException;
309 }