KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > h2 > server > ftp > FtpControl


1 /*
2  * Copyright 2004-2006 H2 Group. Licensed under the H2 License, Version 1.0 (http://h2database.com/html/license.html).
3  * Initial Developer: H2 Group
4  */

5 package org.h2.server.ftp;
6
7 import java.io.BufferedReader JavaDoc;
8 import java.io.IOException JavaDoc;
9 import java.io.InputStreamReader JavaDoc;
10 import java.io.OutputStreamWriter JavaDoc;
11 import java.io.PrintWriter JavaDoc;
12 import java.net.ServerSocket JavaDoc;
13 import java.net.Socket JavaDoc;
14
15 import org.h2.engine.Constants;
16 import org.h2.util.StringUtils;
17
18 public class FtpControl extends Thread JavaDoc {
19     
20     private static final String JavaDoc SERVER_NAME = "Small FTP Server";
21     
22     private FtpServer server;
23     private Socket JavaDoc control;
24     private FtpData data;
25     private PrintWriter JavaDoc output;
26     private String JavaDoc userName;
27     private boolean connected, readonly;
28     private String JavaDoc currentDir = "/";
29     private String JavaDoc serverIpAddress;
30     private boolean stop;
31     private String JavaDoc renameFrom;
32     private boolean replied;
33     private long restart;
34     
35     public FtpControl(Socket JavaDoc control, FtpServer server, boolean stop) {
36         this.server = server;
37         this.control = control;
38         this.stop = stop;
39     }
40     
41     public void run() {
42         try {
43             output = new PrintWriter JavaDoc(new OutputStreamWriter JavaDoc(control.getOutputStream(), Constants.UTF8));
44             if(stop) {
45                 reply(421, "Too many users");
46             } else {
47                 reply(220, SERVER_NAME);
48                 // TODO need option to configure the serverIpAddress
49
serverIpAddress = control.getLocalAddress().getHostAddress().replace('.', ',');
50                 BufferedReader JavaDoc input = new BufferedReader JavaDoc(new InputStreamReader JavaDoc(control.getInputStream()));
51                 while(!stop) {
52                     String JavaDoc command = null;
53                     try {
54                         command = input.readLine();
55                     } catch(IOException JavaDoc e) {
56                         // ignore
57
}
58                     if(command == null) {
59                         break;
60                     }
61                     process(command);
62                 }
63                 if(data != null) {
64                     data.close();
65                 }
66             }
67         } catch(Throwable JavaDoc t) {
68             server.logError(t);
69         }
70         server.closeConnection();
71     }
72
73     private void process(String JavaDoc command) throws IOException JavaDoc {
74         int idx = command.indexOf(' ');
75         String JavaDoc param = "";
76         if(idx >= 0) {
77             param = command.substring(idx).trim();
78             command = command.substring(0, idx);
79         }
80         command = StringUtils.toUpperEnglish(command);
81         if(command.length() == 0) {
82             reply(506, "No command");
83             return;
84         }
85         server.log(">" + command);
86         replied = false;
87         if(connected) {
88             processConnected(command, param);
89         }
90         if(!replied) {
91             if("USER".equals(command)) {
92                 userName = param;
93                 reply(331, "Need password");
94             } else if("QUIT".equals(command)) {
95                 reply(221, "Bye");
96                 stop = true;
97             } else if("PASS".equals(command)) {
98                 if(userName == null) {
99                     reply(332, "Need username");
100                 } else if(server.checkUserPassword(userName, param)) {
101                     reply(230, "Ok");
102                     readonly = false;
103                     connected = true;
104                 } else if(server.checkUserPasswordReadOnly(userName, param)) {
105                     reply(230, "Ok, readonly");
106                     readonly = true;
107                     connected = true;
108                 } else {
109                     reply(431, "Wrong user/password");
110                 }
111             } else if("REIN".equals(command)) {
112                 userName = null;
113                 connected = false;
114                 currentDir = "/";
115                 reply(200, "Ok");
116             } else if("HELP".equals(command)) {
117                 reply(214, SERVER_NAME);
118             }
119         }
120         if(!replied) {
121             reply(506, "Invalid command");
122         }
123     }
124     
125     private void processConnected(String JavaDoc command, String JavaDoc param) throws IOException JavaDoc {
126         switch(command.charAt(0)) {
127         case 'C':
128             if("CWD".equals(command)) {
129                 param = getFileName(param);
130                 FileObject file = server.getFile(param);
131                 if(file.exists() && file.isDirectory()) {
132                     if(!param.endsWith("/")) {
133                         param += "/";
134                     }
135                     currentDir = param;
136                     reply(250, "Ok");
137                 } else {
138                     reply(550, "Failed");
139                 }
140             } else if("CDUP".equals(command)) {
141                 if(currentDir.length()>1) {
142                     int idx = currentDir.lastIndexOf("/", currentDir.length()-2);
143                     currentDir = currentDir.substring(0, idx+1);
144                     reply(250, "Ok");
145                 } else {
146                     reply(550, "Failed");
147                 }
148             }
149             break;
150         case 'D':
151             if("DELE".equals(command)) {
152                 FileObject file = server.getFile(getFileName(param));
153                 if(!readonly && file.exists() && file.isFile() && file.delete()) {
154                     if(server.getAllowTask() && param.endsWith(FtpServer.TASK_SUFFIX)) {
155                         server.stopTask(file);
156                     }
157                     reply(250, "Ok");
158                 } else {
159                     reply(500, "Delete failed");
160                 }
161             }
162             break;
163         case 'L':
164             if("LIST".equals(command)) {
165                 processList(param, true);
166             }
167             break;
168         case 'M':
169             if("MKD".equals(command)) {
170                 param = getFileName(param);
171                 FileObject file = server.getFile(param);
172                 if(!readonly && file.mkdirs()) {
173                     reply(257, "\"" + param + "\" directory"); // TODO quote (" > "")
174
} else {
175                     reply(500, "Failed");
176                 }
177             } else if("MODE".equals(command)) {
178                 if("S".equals(StringUtils.toUpperEnglish(param))) {
179                     reply(200, "Ok");
180                 } else {
181                     reply(504, "Invalid");
182                 }
183             } else if("MDTM".equals(command)) {
184                 FileObject file = server.getFile(getFileName(param));
185                 if(file.exists() && file.isFile()) {
186                     reply(213, server.formatLastModified(file));
187                 } else {
188                     reply(550, "Failed");
189                 }
190             }
191             break;
192         case 'N':
193             if("NLST".equals(command)) {
194                 processList(param, false);
195             } else if("NOOP".equals(command)) {
196                 reply(200, "Ok");
197             }
198             break;
199         case 'P':
200             if("PWD".equals(command)) {
201                 reply(257, "\"" + currentDir + "\" directory"); // TODO quote (" > "")
202
} else if("PASV".equals(command)) {
203                 ServerSocket JavaDoc dataSocket = server.createDataSocket();
204                 data = new FtpData(server, control.getInetAddress(), dataSocket);
205                 data.start();
206                 int port = dataSocket.getLocalPort();
207                 reply(227, "Passive Mode (" + serverIpAddress + "," + (port >> 8) + "," + (port & 255) + ")");
208                 // reply(501, ne.getMessage());
209
}
210             break;
211         case 'R':
212             if("RNFR".equals(command)) {
213                 param = getFileName(param);
214                 FileObject file = server.getFile(param);
215                 if(file.exists()) {
216                     renameFrom = param;
217                     reply(350, "Ok");
218                 } else {
219                     reply(450, "Not found");
220                 }
221             } else if("RNTO".equals(command)) {
222                 if (renameFrom == null) {
223                     reply(503, "RNFR required");
224                 } else {
225                     FileObject fileOld = server.getFile(renameFrom);
226                     FileObject fileNew = server.getFile(getFileName(param));
227                     if(!readonly && fileOld.renameTo(fileNew)) {
228                         reply(250, "Ok");
229                     } else {
230                         reply(550, "Failed");
231                     }
232                 }
233             } else if("RETR".equals(command)) {
234                 FileObject file = server.getFile(getFileName(param));
235                 if(file.exists() && file.isFile()) {
236                     reply(150, "Starting transfer");
237                     try {
238                         data.send(file, restart);
239                         reply(226, "Ok");
240                     } catch(IOException JavaDoc e) {
241                         reply(426, "Failed");
242                     }
243                     restart = 0;
244                 } else {
245                     processList(param, true); // Firefox compatibility (still not good)
246
// reply(426, "Not a file");
247
}
248             } else if("RMD".equals(command)) {
249                 FileObject file = server.getFile(getFileName(param));
250                 if(!readonly && file.exists() && file.isDirectory() && file.delete()) {
251                     reply(250, "Ok");
252                 } else {
253                     reply(500, "Failed");
254                 }
255             } else if("REST".equals(command)) {
256                 try {
257                     restart = Integer.parseInt(param);
258                     reply(350, "Ok");
259                 } catch(NumberFormatException JavaDoc e) {
260                     reply(500, "Invalid");
261                 }
262             }
263             break;
264         case 'S':
265             if("SYST".equals(command)) {
266                 reply(215, "UNIX Type: L8");
267             } else if("SITE".equals(command)) {
268                 reply(500, "Not understood");
269             } else if("SIZE".equals(command)) {
270                 FileObject file = server.getFile(getFileName(param));
271                 if(file.exists() && file.isFile()) {
272                     reply(250, String.valueOf(file.length()));
273                 } else {
274                     reply(500, "Failed");
275                 }
276             } else if("STOR".equals(command)) {
277                 FileObject file = server.getFile(getFileName(param));
278                 if(!readonly && !file.exists() || file.isFile()) {
279                     reply(150, "Starting transfer");
280                     try {
281                         data.receive(file);
282                         if(server.getAllowTask() && param.endsWith(FtpServer.TASK_SUFFIX)) {
283                             server.startTask(file);
284                         }
285                         reply(226, "Ok");
286                     } catch(IOException JavaDoc e) {
287                         reply(426, "Failed");
288                     }
289                 } else {
290                     reply(550, "Failed");
291                 }
292             } else if("STRU".equals(command)) {
293                 if("F".equals(StringUtils.toUpperEnglish(param))) {
294                     reply(200, "Ok");
295                 } else {
296                     reply(504, "Invalid");
297                 }
298             }
299             break;
300         case 'T':
301             if("TYPE".equals(command)) {
302                 param = StringUtils.toUpperEnglish(param);
303                 if("A".equals(param) || "A N".equals(param)) {
304                     reply(200, "Ok");
305                 } else if("I".equals(param) || "L 8".equals(param)) {
306                     reply(200, "Ok");
307                 } else {
308                     reply(500, "Invalid");
309                 }
310             }
311             break;
312         }
313     }
314     
315     private String JavaDoc getFileName(String JavaDoc file) {
316         return file.startsWith("/") ? file : currentDir + file;
317     }
318     
319     private void processList(String JavaDoc param, boolean directories) throws IOException JavaDoc {
320         FileObject directory = server.getFile(getFileName(param));
321         if(!directory.exists()) {
322             reply(450, "Directory does not exist");
323             return;
324         } else if(!directory.isDirectory()) {
325             reply(450, "Not a directory");
326             return;
327         }
328         String JavaDoc list = server.getDirectoryListing(directory, directories);
329         reply(150, "Starting transfer");
330         server.log(list);
331         // need to use the current locale (UTF-8 would be wrong for the Windows Explorer)
332
data.send(list.getBytes());
333         reply(226, "Done");
334     }
335     
336     private void reply(int code, String JavaDoc message) throws IOException JavaDoc {
337         server.log(code + " " + message);
338         output.print(code + " " + message + "\r\n");
339         output.flush();
340         replied = true;
341     }
342     
343 }
344
Popular Tags