1/* 2 * Copyright 2008 the original author or authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16package org.mockftpserver.fake.command 17 18import org.mockftpserver.fake.command.AbstractFakeCommandHandler 19import org.mockftpserver.core.command.Command 20import org.mockftpserver.core.session.Session 21import org.mockftpserver.core.session.SessionKeys 22import org.mockftpserver.core.command.ReplyCodes 23import org.mockftpserver.fake.filesystem.FileInfo 24import java.text.SimpleDateFormat 25/** 26 * CommandHandler for the LIST command. Handler logic: 27 * <ol> 28 * <li>If the user has not logged in, then reply with 530 and terminate</li> 29 * <li>Send an initial reply of 150</li> 30 * <li>If the optional pathname parameter is missing, then send a directory listing for 31 * the current directory across the data connection</li> 32 * <li>Otherwise, if the optional pathname parameter specifies a directory or group of files, 33 * then send a directory listing for the specified directory across the data connection</li> 34 * <li>Otherwise, if the optional pathname parameter specifies a filename, then send information 35 * for the specified file across the data connection</li> 36 * <li>Send a final reply with 226</li> 37 * </ol> 38 * 39 * @version $Revision: $ - $Date: $ 40 * 41 * @author Chris Mair 42 */ 43class ListCommandHandler extends AbstractFakeCommandHandler { 44 45 static final DATE_FORMAT = "MM/dd/yyyy hh:mm aa" 46 static final SIZE_WIDTH = 15 47 48 protected void handle(Command command, Session session) { 49 verifyLoggedIn(session) 50 sendReply(session, ReplyCodes.SEND_DATA_INITIAL_OK) 51 52 def path = getRealPath(session, command.getParameter(0)) 53 def fileEntries = this.fileSystem.listFiles(path) 54 def lines = fileEntries.collect { directoryListing(it) } 55 def result = lines.join(endOfLine()) 56 session.sendData(result.toString().getBytes(), result.length()) 57 58 sendReply(session, ReplyCodes.SEND_DATA_FINAL_OK) 59 } 60 61 /** 62 * Format and return a directory listing String for a single file/directory 63 * entry represented by the specified FileInfo. 64 * TODO Consider making this filesystem-dependent 65 */ 66 protected String directoryListing(FileInfo fileInfo) { 67 def dateFormat = new SimpleDateFormat(DATE_FORMAT) 68 def dateStr = dateFormat.format(fileInfo.lastModified) 69 def dirOrSize = fileInfo.directory ? "<DIR>".padRight(SIZE_WIDTH) : fileInfo.size.toString().padLeft(SIZE_WIDTH) 70 return "$dateStr $dirOrSize ${fileInfo.name}" 71 } 72 73}