/*
Copyright 2009 David Revell
This file is part of SwiFTP.
SwiFTP 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.
SwiFTP 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 SwiFTP. If not, see <http://www.gnu.org/licenses/>.
*/
package org.swiftp;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import android.util.Log;
public class CmdRETR extends FtpCmd implements Runnable {
//public static final String message = "TEMPLATE!!";
protected String input;
public CmdRETR(SessionThread sessionThread, String input) {
super(sessionThread, CmdRETR.class.toString());
this.input = input;
}
public void run() {
myLog.l(Log.DEBUG, "RETR executing");
String param = getParameter(input);
File fileToRetr;
String errString = null;
mainblock: {
fileToRetr = inputPathToChrootedFile(sessionThread.getWorkingDir(), param);
if(violatesChroot(fileToRetr)) {
errString = "550 Invalid name or chroot violation\r\n";
break mainblock;
} else if(fileToRetr.isDirectory()) {
myLog.l(Log.DEBUG, "Ignoring RETR for directory");
errString = "550 Can't RETR a directory\r\n";
break mainblock;
} else if(!fileToRetr.exists()) {
myLog.l(Log.INFO, "Can't RETR nonexistent file: " +
fileToRetr.getAbsolutePath());
errString = "550 File does not exist\r\n";
break mainblock;
} else if(!fileToRetr.canRead()) {
myLog.l(Log.INFO, "Failed RETR permission (canRead() is false)");
errString = "550 No read permissions\r\n";
break mainblock;
} /*else if(!sessionThread.isBinaryMode()) {
myLog.l(Log.INFO, "Failed RETR in text mode");
errString = "550 Text mode RETR not supported\r\n";
break mainblock;
}*/
try {
FileInputStream in = new FileInputStream(fileToRetr);
byte[] buffer = new byte[Defaults.getDataChunkSize()];
int bytesRead;
if(sessionThread.startUsingDataSocket()) {
myLog.l(Log.DEBUG, "RETR opened data socket");
} else {
errString = "425 Error opening socket\r\n";
myLog.l(Log.INFO, "Error in initDataSocket()");
break mainblock;
}
sessionThread.writeString("150 Sending file\r\n");
if(sessionThread.isBinaryMode()) {
myLog.l(Log.DEBUG, "Transferring in binary mode");
while((bytesRead = in.read(buffer)) != -1) {
//myLog.l(Log.DEBUG,
// String.format("CmdRETR sending %d bytes", bytesRead));
if(sessionThread
.sendViaDataSocket(buffer, bytesRead) == false)
{
errString = "426 Data socket error\r\n";
myLog.l(Log.INFO, "Data socket error");
break mainblock;
}
}
} else { // We're in ASCII mode
myLog.l(Log.DEBUG, "Transferring in ASCII mode");
// We have to convert all solitary \n to \r\n
boolean lastBufEndedWithCR = false;
while((bytesRead = in.read(buffer)) != -1) {
int startPos = 0, endPos = 0;
byte[] crnBuf = {'\r','\n'};
for(endPos = 0; endPos<bytesRead; endPos++) {
if(buffer[endPos] == '\n') {
// Send bytes up to but not including the newline
sessionThread.sendViaDataSocket(buffer,
startPos, endPos-startPos);
if(endPos == 0) {
// handle special case where newline occurs at
// the beginning of a buffer
if(!lastBufEndedWithCR) {
// Send an \r only if the the previous
// buffer didn't end with an \r
sessionThread.sendViaDataSocket(crnBuf, 1);
}
} else if(buffer[endPos-1] != '\r') {
// The file did not have \r before \n, add it
sessionThread.sendViaDataSocket(crnBuf, 1);
} else {
// The file did have \r before \n, don't change
}
startPos = endPos;
}
}
// Now endPos has finished traversing the array, send remaining
// data as-is
sessionThread.sendViaDataSocket(buffer, startPos,
endPos-startPos);
if(buffer[bytesRead-1] == '\r') {
lastBufEndedWithCR = true;
} else {
lastBufEndedWithCR = false;
}
}
}
} catch (FileNotFoundException e) {
errString = "550 File not found\r\n";
break mainblock;
} catch(IOException e) {
errString = "425 Network error\r\n";
break mainblock;
}
}
sessionThread.closeDataSocket();
if(errString != null) {
sessionThread.writeString(errString);
} else {
sessionThread.writeString("226 Transmission finished\r\n");
}
myLog.l(Log.DEBUG, "RETR done");
}
}