001: /*
002: * This file is part of the QuickServer library
003: * Copyright (C) 2003-2005 QuickServer.org
004: *
005: * Use, modification, copying and distribution of this software is subject to
006: * the terms and conditions of the GNU Lesser General Public License.
007: * You should have received a copy of the GNU LGP License along with this
008: * library; if not, you can download a copy from <http://www.quickserver.org/>.
009: *
010: * For questions, suggestions, bug-reports, enhancement-requests etc.
011: * visit http://www.quickserver.org
012: *
013: */
014:
015: package ftpserver;
016:
017: import org.quickserver.net.server.ClientCommandHandler;
018: import org.quickserver.net.server.ClientHandler;
019:
020: import java.net.*;
021: import java.io.*;
022: import java.util.StringTokenizer;
023: import org.quickserver.util.*;
024: import java.text.*;
025: import java.util.Date;
026: import java.util.logging.*;
027:
028: /**
029: * IMPORTANT NOTE: This example just demonstrates how to use some
030: * of the QuickServer features. This example not built keeping
031: * security in mind.
032: */
033: public class CommandHandler implements ClientCommandHandler {
034: private static Logger logger = Logger
035: .getLogger(CommandHandler.class.getName());
036:
037: public void gotConnected(ClientHandler handler)
038: throws SocketTimeoutException, IOException {
039: handler.sendSystemMsg("Connection opened : "
040: + handler.getSocket().getInetAddress(), Level.FINE);
041:
042: handler.sendClientMsg("220- QuickFTPServer v 0.1 ");
043: handler.sendClientMsg("220- Developed using QuickServer");
044: handler.sendClientMsg("220 ");
045: //send feature supported msg
046: //handler.sendClientMsg("220 Features: a p .");
047: }
048:
049: public void lostConnection(ClientHandler handler)
050: throws IOException {
051: logger.fine("Connection lost : "
052: + handler.getSocket().getInetAddress());
053: }
054:
055: public void closingConnection(ClientHandler handler)
056: throws IOException {
057: logger.fine("Connection closed: "
058: + handler.getSocket().getInetAddress());
059: }
060:
061: public void handleCommand(ClientHandler handler, String command)
062: throws SocketTimeoutException, IOException {
063: Data data = (Data) handler.getClientData();
064: command = command.trim();
065: String ucCommand = command.toUpperCase();
066: String args = null;
067: String temp = null;
068:
069: logger.fine("Got command : " + command);
070:
071: if (ucCommand.equals("QUIT")) {
072: //LOGOUT
073: data.wasQuit = true;
074: handler.sendClientMsg("221 Logged out.");
075: handler.closeConnection();
076: return;
077: } else if (ucCommand.endsWith("ABOR")) {
078: //ABORT
079: data.isStop = true;
080: //close data connection
081: //handler.sendClientMsg("502 Command not implemented.");
082: handler.sendClientMsg("220 OK");
083: return;
084: } else if (ucCommand.startsWith("STAT")) {
085: //STATUS
086: handler.sendClientMsg("211- QuickFTPServer");
087: handler.sendClientMsg(" Version 0.1 ");
088: handler.sendClientMsg(" Connected to "
089: + handler.getSocket().getInetAddress());
090: handler.sendClientMsg(" Logged in as " + data.username);
091: handler.sendClientMsg(" Cur Dir : " + data.wDir);
092: handler.sendClientMsg(" Data connection : "
093: + data.isTransferring);
094: handler.sendClientMsg("211 End of status");
095: return;
096: }
097:
098: ///////////// now check if only not processing ///////
099: if (data.isProcessing == true) {
100: handler
101: .sendClientMsg("503 Bad sequence of commands; another command is being processed.");
102: return;
103: }
104: /////////// ACCESS CONTROL COMMANDS /////////
105: if (ucCommand.equals("REIN")) {
106: //REINITIALIZE
107: handler.sendClientMsg("502 Command not implemented.");
108: } else if (ucCommand.startsWith("ACCT")) {
109: //ACCOUNT
110: args = command.substring("ACCT".length()).trim();
111: data.account = args;
112: handler.sendClientMsg("230 Account OK.");
113: } else if (ucCommand.equals("CDUP")) {
114: //CHANGE TO PARENT DIRECTORY
115: int i = data.wDir.lastIndexOf("/");
116: String temp_wDir = null;
117: if (i != -1) {
118: temp_wDir = data.wDir.substring(0, i);
119: if (temp_wDir.equals(""))
120: temp_wDir = "/";
121: else
122: temp_wDir += "/"; //end
123: temp = MyString.replaceAll(data.root + temp_wDir, "/",
124: "\\");
125: temp = MyString.replaceAll(temp, "\\\\", "\\");
126: File file = new File(temp);
127: if (file.canRead()) {
128: data.wDir = temp_wDir;
129: handler.sendClientMsg("250 Okay");
130: } else {
131: handler.sendClientMsg("550 No parent dir");
132: }
133: } else {
134: handler.sendClientMsg("550 No parent dir");
135: }
136: } else if (ucCommand.startsWith("SMNT")) {
137: //STRUCTURE MOUNT
138: handler.sendClientMsg("502 Command not implemented.");
139: }
140: ///////// TRANSFER PARAMETER COMMANDS ////////
141: else if (ucCommand.startsWith("PORT")) {
142: /*
143: PORT h1,h2,h3,h4,p1,p2
144: */
145: args = command.substring("PORT".length()).trim();
146: String ipAddr = "";
147: int port = 0;
148: StringTokenizer st = new StringTokenizer(args, ",");
149: int p1 = 0;
150: int p2 = 0;
151: try {
152: ipAddr += st.nextToken() + ".";
153: ipAddr += st.nextToken() + ".";
154: ipAddr += st.nextToken() + ".";
155: ipAddr += st.nextToken();
156: p1 = Integer.parseInt(st.nextToken());
157: p2 = Integer.parseInt(st.nextToken());
158: port = p1 * 256 + p2;
159: data.ip = ipAddr;
160: data.socketPort = port;
161: handler.sendClientMsg("200 Command okay.");
162: } catch (Exception e) {
163: handler
164: .sendClientMsg("501 Syntax error in parameters or arguments. : PORT "
165: + e);
166: }
167: } else if (ucCommand.startsWith("PASV")) {
168: /*
169: PASSIVE
170: This command requests the server-DTP to "listen" on a data
171: port (which is not its default data port) and to wait for a
172: connection rather than initiate one upon receipt of a
173: transfer command. The response to this command includes the
174: host and port address this server is listening on.
175: PORT = p1*256+p2
176: p1 = PORT / 256
177: p2 = PORT - p1*256
178: */
179: //227 =127,0,0,1,10,5
180: //reset for PORT
181: data.ip = null;
182:
183: try {
184: InetAddress ipAddr = handler.getSocket()
185: .getLocalAddress();
186: String ip_port = "";
187: StringTokenizer st = new StringTokenizer(ipAddr
188: .getHostAddress(), ".");
189: while (st.hasMoreTokens()) {
190: ip_port += st.nextToken() + ",";
191: }
192: data.server = new ServerSocket(0, 1, ipAddr);
193: data.serverPort = data.server.getLocalPort();
194: int p1 = data.serverPort / 256;
195: int p2 = data.serverPort - p1 * 256;
196: ip_port += p1 + "," + p2;
197: data.startDataServer(data.server, data); //start server
198: handler.sendClientMsg("227 =" + ip_port);
199: } catch (Exception e) {
200: handler
201: .sendClientMsg("425 Can't open data port; Error : "
202: + e);
203: }
204: } else if (ucCommand.startsWith("TYPE")) {
205: /*
206: REPRESENTATION TYPE
207: \ /
208: A - ASCII | | N - Non-print
209: |-><-| T - Telnet format effectors
210: E - EBCDIC| | C - Carriage Control (ASA)
211: / \
212: I - Image
213:
214: L <byte size> - Local byte Byte size
215: */
216: args = command.substring("TYPE".length()).trim();
217: if (args.equals("A")) {
218: data.binary = false;
219: data.type = 'A';
220: data.typeSub = 'Z';
221: } else if (args.equals("A N")) {
222: data.binary = false;
223: data.type = 'A';
224: data.typeSub = 'N';
225: } else if (args.equals("I")) {
226: data.binary = true;
227: data.type = 'I';
228: data.typeSub = 'Z';
229: } else if (args.equals("L 8")) {
230: data.binary = true;
231: //data.type = 'A';
232: //data.typeSub = 'N';
233: } else {
234: handler
235: .sendClientMsg("501 Syntax error in parameters.");
236: return;
237: }
238: handler.sendClientMsg("200 Command OK.");
239: } else if (ucCommand.startsWith("STRU")) {
240: /*
241: FILE STRUCTURE
242: F - File (no record structure) - default
243: R - Record structure
244: P - Page structure
245: */
246: if (ucCommand.equals("STRU F")) {
247: handler.sendClientMsg("200 Command OK.");
248: } else {
249: //obsolete
250: handler
251: .sendClientMsg("504 Command not implemented for that parameter.");
252: }
253: } else if (ucCommand.startsWith("MODE")) {
254: /*
255: TRANSFER MODE
256: S - Stream - Default
257: B - Block
258: C - Compressed
259: */
260: if (ucCommand.equals("MODE S")) {
261: handler.sendClientMsg("200 Command OK.");
262: } else {
263: //obsolete
264: handler
265: .sendClientMsg("504 Command not implemented for that parameter.");
266: }
267: }
268: /////// FTP SERVICE COMMANDS ///////
269: else if (ucCommand.startsWith("RETR")) {
270: data.isTransferring = true;
271: //RETRIEVE
272: args = command.substring("RETR".length()).trim();
273: String sfile = "";
274: //check if NOT PASSIVE, i.e PORT was set
275: if (data.ip != null) {
276: try {
277: data.socket = new Socket(InetAddress
278: .getByName(data.ip), data.socketPort);
279: } catch (Exception e) {
280: handler
281: .sendClientMsg("425 Can't open data connection.");
282: data.isTransferring = false;
283: return;
284: }
285: }
286: if (data.socket != null) {
287: if (args.charAt(0) == '/') {
288: sfile = data.root + args;
289: } else {
290: sfile = data.root + data.wDir + "/" + args;
291: }
292: temp = MyString.replaceAll(sfile, "/", "\\");
293: temp = MyString.replaceAll(temp, "\\\\", "\\");
294: File file = new File(temp);
295: if (file.canRead() && file.isFile()) {
296: handler.sendClientMsg("150 I see that file.");
297: //send file
298: try {
299: data.sendFile(temp);
300: //close data connection when done
301: if (data.ip != null)
302: data.socket.close();
303: data.closeDataServer = true;
304: if (data.isStop == false)
305: handler
306: .sendClientMsg("226 File transferred successfully.");
307: else
308: handler
309: .sendClientMsg("551 Error sending file : User Aborted");
310: } catch (Exception e) {
311: data.closeDataServer = true;
312: handler
313: .sendClientMsg("551 Error sending file : "
314: + e);
315: }
316: } else {
317: handler
318: .sendClientMsg("451 Sorry, that isn't a data file");
319: }
320: } else {
321: handler
322: .sendClientMsg("425 Sorry no TCP connection was established.");
323: }
324: data.isTransferring = false;
325: } else if (ucCommand.startsWith("STOR")) {
326: //STORE
327: args = command.substring("STOR".length()).trim();
328: handler.sendClientMsg("502 Command not implemented.");
329: } else if (ucCommand.startsWith("STOU")) {
330: //STORE UNIQUE - The 250 Transfer Started response
331: //must include the name generated.
332: args = command.substring("STOU".length()).trim();
333: handler.sendClientMsg("502 Command not implemented.");
334: } else if (ucCommand.startsWith("APPE")) {
335: //APPEND (with create)
336: handler.sendClientMsg("502 Command not implemented.");
337: } else if (ucCommand.startsWith("ALLO")) {
338: //ALLOCATE - obsolete
339: handler
340: .sendClientMsg("502 Command not implemented - obsolete.");
341: } else if (ucCommand.startsWith("REST")) {
342: //RESTART transfer
343: //350 ok
344: handler.sendClientMsg("502 Command not implemented.");
345: } else if (ucCommand.startsWith("RNFR")) {
346: //RENAME FROM
347: data.isRenameFrom = true;
348: handler.sendClientMsg("502 Command not implemented.");
349: } else if (ucCommand.startsWith("RNTO")) {
350: //RENAME TO
351: if (!data.isRenameFrom) {
352: //error should not happen
353: }
354: data.isRenameFrom = false;
355: handler.sendClientMsg("502 Command not implemented.");
356: } else if (ucCommand.startsWith("DELE")) {
357: //DELETE
358: handler.sendClientMsg("502 Command not implemented.");
359: } else if (ucCommand.startsWith("RMD")) {
360: //REMOVE DIRECTORY
361: handler.sendClientMsg("502 Command not implemented.");
362: } else if (ucCommand.startsWith("MKD")) {
363: //MAKE DIRECTORY
364: args = command.substring("MKD".length()).trim();
365: temp = MyString.replaceAll(data.root + data.wDir + args,
366: "/", "\\");
367: temp = MyString.replaceAll(temp, "\\\\", "\\");
368: File file = new File(temp);
369: try {
370: file.mkdir();
371: file.canRead();
372: temp = file.getAbsolutePath();
373: temp = "/" + MyString.replaceAll(temp, data.root, "");
374: temp = MyString.replaceAll(temp, "\\", "/");
375: temp = MyString.replaceAll(temp, "//", "/");
376: handler.sendClientMsg("257 \"" + temp
377: + "\" directory created");
378: } catch (Exception e) {
379: handler.sendClientMsg("521-Could not create dir \""
380: + args + "\"");
381: handler.sendClientMsg("521 Error : " + e);
382: }
383: } else if (ucCommand.startsWith("CWD")) {
384: //CHANGE DIRECTORY
385: temp = data.wDir;
386: args = command.substring("CWD".length()).trim();
387: if (data.wDir.charAt(data.wDir.length() - 1) != '/')
388: data.wDir += "/";
389: if (args.charAt(args.length() - 1) != '/')
390: args += "/";
391:
392: if (args.charAt(0) != '/')
393: data.wDir += args;
394: else
395: data.wDir = args;
396:
397: temp = MyString
398: .replaceAll(data.root + data.wDir, "/", "\\");
399: temp = MyString.replaceAll(temp, "\\\\", "\\");
400: File file = new File(temp);
401: if (file.canRead() && file.isDirectory()) {
402: handler.sendClientMsg("250 Directory changed to "
403: + data.wDir);
404: } else {
405: if (file.canRead())
406: handler.sendClientMsg("550 " + data.wDir
407: + ": The directory name is invalid.");
408: else
409: handler
410: .sendClientMsg("550 "
411: + data.wDir
412: + ": The system cannot find the file specified .");
413: data.wDir = temp;
414: logger.logp(Level.FINER, "CommandHandler",
415: "handleCommand",
416: "Command=CWD; ERROR : 550 No such directory "
417: + file);
418: }
419: } else if (ucCommand.startsWith("PWD")) {
420: //PRINT WORKING DIRECTORY
421: temp = MyString.replaceAll(data.wDir, "\"", "\"\"");
422: handler.sendClientMsg("257 \"" + data.wDir + "\"");
423: } else if (ucCommand.startsWith("LIST")) {
424: data.isTransferring = true;
425: if (ucCommand.equals("LIST")) {
426: args = "";
427: } else {
428: args = command.substring("LIST".length()).trim();
429: if (args.equals("-latr")) //not known
430: args = "";
431: }
432: temp = MyString.replaceAll(data.root + data.wDir + args,
433: "/", "\\");
434: temp = MyString.replaceAll(temp, "\\\\", "\\");
435: File file = new File(temp);
436:
437: if (file.canRead()) {
438: handler
439: .sendClientMsg("150 Opening data connection for LIST "
440: + data.wDir + args);
441: if (data.ip != null) {
442: try {
443: data.socket = new Socket(InetAddress
444: .getByName(data.ip), data.socketPort);
445: } catch (Exception e) {
446: handler
447: .sendClientMsg("425 Can't open data connection.");
448: data.isTransferring = false;
449: return;
450: }
451: }
452: String result = winDirList(temp);
453: try {
454: data.sendData(result);
455: //close data connection when done
456: if (data.ip != null) {
457: data.socket.close();
458: }
459: data.closeDataServer = true;
460: if (data.isStop == false)
461: handler
462: .sendClientMsg("226 File transferred successfully.");
463: else
464: handler
465: .sendClientMsg("551 Error sending file : User Aborted");
466: } catch (Exception e) {
467: if (data.ip != null && data.socket != null)
468: data.socket.close();
469: data.closeDataServer = true;
470: handler.sendClientMsg("551 Error sending LIST : "
471: + e);
472: }
473: } else {
474: handler.sendClientMsg("550 No such directory : "
475: + data.wDir + args);
476: logger.logp(Level.FINER, "CommandHandler",
477: "handleCommand",
478: "Command=LIST; ERROR : 550 No such directory "
479: + file);
480: }
481: data.isTransferring = false;
482: } else if (ucCommand.startsWith("NLST")) {
483: //NAME LIST of directory only
484: data.isTransferring = true;
485: if (ucCommand.equals("NLST")) {
486: args = "";
487: } else {
488: args = command.substring("NLST".length()).trim();
489: }
490: temp = MyString.replaceAll(data.root + data.wDir + args,
491: "/", "\\");
492: temp = MyString.replaceAll(temp, "\\\\", "\\");
493: File file = new File(temp);
494: String result = "";
495: if (file.canRead() && file.isDirectory()) {
496: handler
497: .sendClientMsg("150 Opening data connection for LIST "
498: + data.wDir + args);
499: if (data.ip != null) {
500: try {
501: data.socket = new Socket(InetAddress
502: .getByName(data.ip), data.socketPort);
503: } catch (Exception e) {
504: handler
505: .sendClientMsg("425 Can't open data connection.");
506: data.isTransferring = false;
507: return;
508: }
509: }
510: String list[] = file.list();
511: for (int i = 0; i < list.length; i++) {
512: if (!list[i].equals(".") && !list[i].equals(".."))
513: result += list[i] + "\r\n";
514: }
515: try {
516: data.sendData(result);
517: //close data connection when done
518: if (data.ip != null)
519: data.socket.close();
520: data.closeDataServer = true;
521: if (data.isStop == false)
522: handler
523: .sendClientMsg("226 File transferred successfully.");
524: else
525: handler
526: .sendClientMsg("551 Error sending file : User Aborted");
527: } catch (Exception e) {
528: if (data.ip != null && data.socket != null)
529: data.socket.close();
530: data.closeDataServer = true;
531: handler.sendClientMsg("551 Error sending NLST : "
532: + e);
533: }
534: } else {
535: handler.sendClientMsg("550 No such directory : "
536: + data.wDir + args);
537: logger.logp(Level.FINER, "CommandHandler",
538: "handleCommand",
539: "Command=NLST; ERROR : 550 No such directory "
540: + file);
541: }
542: data.isTransferring = false;
543: } else if (ucCommand.startsWith("SITE")) {
544: //SITE PARAMETERS
545: handler.sendClientMsg("502 Command not implemented.");
546: } else if (ucCommand.startsWith("SYST")) {
547: //SYSTEM - Assigned Numbers document [4]
548: // UNIX Type: L8
549: handler.sendClientMsg("215 " + "Windows_NT version 5.0");
550: } else if (ucCommand.startsWith("HELP")) {
551: //HELP
552: //The reply is type 211 or 214.
553: handler.sendClientMsg("502 Command not implemented.");
554: } else if (ucCommand.startsWith("NOOP")) {
555: //NOOP - OK reply
556: handler.sendClientMsg("200 OK");
557: } else if (ucCommand.startsWith("SIZE")) {
558: //SIZE OF FILE
559: args = command.substring("SIZE".length()).trim();
560: temp = MyString.replaceAll(data.root + data.wDir + args,
561: "/", "\\");
562: temp = MyString.replaceAll(temp, "\\\\", "\\");
563: File file = new File(temp);
564: if (file.canRead()) {
565: handler.sendClientMsg("213 " + file.length());
566: } else {
567: handler.sendClientMsg("550 No such file.");
568: }
569: } else {
570: //ERROR
571: handler
572: .sendClientMsg("500 Syntax error, command unrecognized.");
573: }
574: }
575:
576: // helper meethods
577: private String dirList(String dir) {
578: //+FACTS1,FACTS@..,FACTN\tfile_name\r\n
579: /*
580: FACE = xy
581: >X<
582: r -> File
583: / -> Dir
584: s ->Size, y=size in bytes
585: m ->Modified since 1970
586: i ->This file has identifier y.
587: up->Chmode is allowed
588: */
589: File file = new File(dir);
590: File subFile = null;
591: String result = "";
592: if (file.canRead()) {
593: String list[] = file.list();
594: for (int i = 0; i < list.length; i++) {
595: //if(list[i].equals(".") || list[i].equals("..") )
596: // continue;
597: subFile = new File(dir + File.separator + list[i]);
598: result += "+";
599: result += "i" + subFile.hashCode() + ",";
600: result += "s" + subFile.length() + ",";
601: result += "m" + subFile.lastModified() + ",";
602: if (subFile.isFile()) {
603: result += "r,";
604: } else {
605: result += "/,";
606: }
607: result += "\t" + list[i] + "\r\n";
608: }
609: }
610: return result;
611: }
612:
613: private String winDirList(String dir) {
614: File file = new File(dir);
615: File subFile = null;
616: String result = "";
617: if (file.canRead()) {
618: String list[] = file.list();
619: for (int i = 0; i < list.length; i++) {
620: subFile = new File(dir + File.separator + list[i]);
621: SimpleDateFormat dformat = new SimpleDateFormat(
622: "MM-dd-yy HH:mm:a ");
623: result += dformat.format(new Date(subFile
624: .lastModified()));
625: if (subFile.isFile()) {
626: //20 field length
627: StringBuffer size = new StringBuffer(20);
628: size.append(subFile.length());
629: while (size.length() < 20) {
630: size.insert(0, " ");
631: }
632: result += size.toString();
633: } else {
634: result += " <DIR> ";
635: }
636: result += " " + list[i] + "\r\n";
637: }
638: }
639: return result;
640: }
641: }
|