/*******************************************************************************
* This file is part of OpenNMS(R).
*
* Copyright (C) 2008-2011 The OpenNMS Group, Inc.
* OpenNMS(R) is Copyright (C) 1999-2011 The OpenNMS Group, Inc.
*
* OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc.
*
* OpenNMS(R) is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* OpenNMS(R) is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenNMS(R). If not, see:
* http://www.gnu.org/licenses/
*
* For more information contact:
* OpenNMS(R) Licensing <license@opennms.org>
* http://www.opennms.org/
* http://www.opennms.com/
*******************************************************************************/
package org.opennms.netmgt.capsd.plugins;
import java.io.BufferedReader;
import java.io.IOException;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import org.springframework.util.StringUtils;
/**
* Represents an FTP command response.
*
* @author <a href="mailto:dj@opennms.org">DJ Gregor</a>
* @version $Id: $
*/
public class FtpResponse {
private int m_code;
private String m_response[];
/**
* Creates an empty FTP response.
*/
public FtpResponse() {}
/**
* Creates an FTP response with given status code and response string.
*
* @param code numeric status code
* @param response response detail message (one line per array element)
*/
public FtpResponse(int code, String[] response) {
m_code = code;
m_response = response;
}
/**
* Gets the numeric response code.
*
* @return numeric status code
*/
public int getCode() {
return m_code;
}
/**
* Sets the numeric response code.
*
* @param code numeric status code
*/
public void setCode(int code) {
m_code = code;
}
/**
* Gets the response string array.
*
* @return response detail message (one line per array element)
*/
public String[] getResponse() {
return m_response;
}
/**
* Sets the response string array.
*
* @param response response detail message (one line per array element)
*/
public void setResponse(String[] response) {
m_response = response;
}
/**
* Search for a text string in each line of the response result.
* Note that each line is tested individually.
*
* @param contain text to search for (using String.contains(contain))
* @return true if the search string is found, false otherwise
*/
public boolean responseContains(String contain) {
for (String line : m_response) {
if (line.contains(contain)) {
return true;
}
}
return false;
}
/**
* Converts FTP response to string.
*
* @return FTP response as would be sent over FTP
*/
public String toString() {
StringBuffer sb = new StringBuffer();
int i;
sb.append(m_code);
if (m_response.length > 1) {
sb.append("-");
}
if (m_response.length > 0) {
sb.append(" " + m_response[0]);
}
for (i = 1; i < m_response.length; i++) {
sb.append("\n");
if (i == (m_response.length - 1)) {
sb.append(m_code);
sb.append(" ");
sb.append(m_response[i]);
} else if (m_response[i].startsWith(m_code + " ")) {
sb.append(" ");
sb.append(m_response[i]);
} else {
sb.append(m_response[i]);
}
}
return sb.toString();
}
/**
* Does this response have a valid code?
*
* @return True if the response code is between 100 and 599,
* false otherwise.
*/
public boolean isCodeValid() {
return getCode() >= 100 && getCode() < 600;
}
/**
* Is this response a successful message?
*
* @return True if the response code is between 200 and 299,
* false otherwise.
*/
public boolean isSuccess() {
return (m_code >= 200 && m_code < 300);
}
/**
* Is this response an intermediate message?
*
* @return True if the response code is between 300 and 399,
* false otherwise.
*/
public boolean isIntermediate() {
return (m_code >= 300 && m_code < 400);
}
/**
* Helper method to send commands to the remote server.
*
* @param socket connection to the server
* @param command command to send, without trailing EOL (CRLF, \r\n).
* @throws java.io.IOException if we can't write() to the OutputStream for the Socket
*/
public static void sendCommand(Socket socket, String command) throws IOException {
socket.getOutputStream().write((command + "\r\n").getBytes());
}
/**
* Reads a server response.
*
* @param in input reader
* @return response from server
* @throws java.io.IOException if any.
*/
public static FtpResponse readResponse(BufferedReader in) throws IOException {
int code;
List<String> response = new ArrayList<String>();
String firstResponseLine = in.readLine();
if (firstResponseLine == null) {
throw new IOException("End of stream was reached before a response could be read");
}
// XXX this could use better error checking!
String codeString = firstResponseLine.substring(0, 3);
response.add(firstResponseLine.substring(4));
try {
code = Integer.parseInt(codeString);
} catch (NumberFormatException e) {
IOException newE = new IOException("First response line returned a non-numeric result code \"" + codeString + "\": " + firstResponseLine);
newE.initCause(e);
throw newE;
}
// Is the fourth character a hyphen (if so, it's a continuation)?
if ("-".equals(firstResponseLine.substring(3, 4))) {
// The multi-line response ends with a line that begins with this:
String endMultiLine = code + " ";
while (true) {
String subsequentResponse = in.readLine();
if (subsequentResponse == null) {
throw new IOException("End of stream was reached before the complete multi-line response could be read. What was read: " + StringUtils.collectionToDelimitedString(response, "\n"));
}
if (subsequentResponse.startsWith(endMultiLine)) {
response.add(subsequentResponse.substring(4));
break;
}
response.add(subsequentResponse);
}
}
return new FtpResponse(code, response.toArray(new String[response.size()]));
}
}