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