Improving FTPserver again and again, added the rename function, code refactoring, what is missing is verifying if the client is logged in before commands - will be added soon
This commit is contained in:
parent
49b16c1b17
commit
34ffc920a1
@ -11,6 +11,7 @@ _fileSentBytes(0),
|
||||
_fileRecvBytes(0),
|
||||
_waitingForDataConnection(false),
|
||||
_fileIsBeeingReceived(false),
|
||||
_actionTimeout(0),
|
||||
_ftpClientState(FTPServer<FTPClient>::FTPClientState::INIT),
|
||||
_binaryFlag(FTPServer<FTPClient>::BinaryFlag::OFF),
|
||||
_dataTransferPending(FTPServer<FTPClient>::FTPClientDataTransfer::NONE)
|
||||
@ -35,7 +36,19 @@ void FTPClient::setDataClient(WiFiClient dataClient)
|
||||
boolean FTPClient::parseCommandAndParameters()
|
||||
{
|
||||
//We remove the cr lf at the end
|
||||
char *cr = strchr((char *)_data,'\r'); *cr = '\0';
|
||||
char *cr = strchr((char *)_data,'\r');
|
||||
|
||||
if(cr != NULL)
|
||||
{
|
||||
*cr = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
cr = strchr((char *)_data,'\n');
|
||||
if(cr != NULL)
|
||||
*cr = '\0';
|
||||
}
|
||||
|
||||
char *cmdDelimiter = strchr((char *)_data,' ');
|
||||
|
||||
if(cmdDelimiter == NULL) //It means that we do not have any parameters
|
||||
@ -56,6 +69,8 @@ boolean FTPClient::parseCommandAndParameters()
|
||||
|
||||
//At the end, we flush the buffer:
|
||||
freeDataBuffer(_dataSize);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FTPClient::setUsername(const char *username)
|
||||
@ -87,3 +102,8 @@ void FTPClient::setCurrentFile(const char *file)
|
||||
strcpy(_currentFile, file);
|
||||
}
|
||||
}
|
||||
|
||||
void FTPClient::startTimeout()
|
||||
{
|
||||
_actionTimeout = millis();
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ class FTPClient : public TCPClient
|
||||
void setUsername(const char *username);
|
||||
void setCurrentDirectory(const char *dir);
|
||||
void setCurrentFile(const char *file);
|
||||
void startTimeout();
|
||||
|
||||
char _ftpCommand[5];
|
||||
Dictionary<DictionaryHelper::StringEntity> *_cmdParameters;
|
||||
@ -31,6 +32,7 @@ class FTPClient : public TCPClient
|
||||
uint64_t _fileRecvBytes;
|
||||
boolean _waitingForDataConnection;
|
||||
boolean _fileIsBeeingReceived;
|
||||
uint64_t _actionTimeout;
|
||||
|
||||
FTPServer<FTPClient>::FTPClientState _ftpClientState;
|
||||
FTPServer<FTPClient>::BinaryFlag _binaryFlag;
|
||||
|
@ -4,8 +4,9 @@
|
||||
#include "TCPServer.h"
|
||||
#include "SDCardManager.h"
|
||||
#include "definition.h"
|
||||
#include "Dictionary.h"
|
||||
#define DEBUG_FTPS
|
||||
#define READ_WRITE_BUFFER_SIZE 2500
|
||||
#define READ_BUFFER_SIZE 2500 //2500 is max to read sd card, more will crash
|
||||
|
||||
template <typename T>
|
||||
class FTPServer : public TCPServer<T>
|
||||
@ -262,6 +263,7 @@ class FTPServer : public TCPServer<T>
|
||||
}
|
||||
else //The ftp access is open
|
||||
{
|
||||
client->_loggedIn = true;
|
||||
client->_client.println("230 User logged in, proceed.");
|
||||
}
|
||||
}
|
||||
@ -358,43 +360,24 @@ class FTPServer : public TCPServer<T>
|
||||
{
|
||||
client->setCurrentDirectory("/");
|
||||
}
|
||||
else
|
||||
else //If the client already nows the path, he will send it with a /
|
||||
{
|
||||
if(client->_cmdParameters->getAt(0)->getString()[0] == '/')//Then this is a name prefix
|
||||
{
|
||||
client->setCurrentDirectory(client->_cmdParameters->getAt(0)->getString());
|
||||
char *fullDirPath = constructFileNameWithPath("",client->_cmdParameters);
|
||||
client->setCurrentDirectory(fullDirPath);
|
||||
free(fullDirPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Directories with spaces are now working:
|
||||
uint16_t dirNameSize(0), paramCount(client->_cmdParameters->count());
|
||||
for(int i(0); i < paramCount; i++)
|
||||
{
|
||||
dirNameSize += strlen(client->_cmdParameters->getAt(i)->getString()) + 1;
|
||||
}
|
||||
|
||||
dirNameSize += strlen(client->_currentDirectory) + 1;
|
||||
char *directoryFullpath = constructFileNameWithPath(client->_currentDirectory,client->_cmdParameters);
|
||||
|
||||
#ifdef DEBUG_FTPS
|
||||
Serial.printf("Param size : %d\n", dirNameSize);
|
||||
Serial.printf("Final dir : %s\n", directoryFullpath);
|
||||
#endif
|
||||
|
||||
char *temp = (char *)malloc(sizeof(char) * dirNameSize + 1);// /!\ test for malloc fail
|
||||
strcpy(temp,client->_currentDirectory);
|
||||
if(strcmp(temp, "/") != 0)strcat(temp,"/");
|
||||
|
||||
for(int i(0); i < paramCount; i++)
|
||||
{
|
||||
strcat(temp,client->_cmdParameters->getAt(i)->getString());
|
||||
if(i != paramCount-1)
|
||||
strcat(temp," ");
|
||||
}
|
||||
|
||||
#ifdef DEBUG_FTPS
|
||||
Serial.printf("Final dir : %s, size : %d --> %d\n",temp, dirNameSize, strlen(temp));
|
||||
#endif
|
||||
client->setCurrentDirectory(temp);
|
||||
free(temp);
|
||||
client->setCurrentDirectory(directoryFullpath);
|
||||
free(directoryFullpath);
|
||||
}
|
||||
}
|
||||
|
||||
@ -409,37 +392,17 @@ class FTPServer : public TCPServer<T>
|
||||
if (client->_cmdParameters->count() > 0)
|
||||
{
|
||||
//We save the file path to be sent
|
||||
uint16_t filePathSize(0), paramCount(client->_cmdParameters->count());
|
||||
for(int i(0); i < paramCount; i++)
|
||||
{
|
||||
filePathSize += strlen(client->_cmdParameters->getAt(i)->getString()) + 1;
|
||||
}
|
||||
|
||||
filePathSize += strlen(client->_currentDirectory) + 1;
|
||||
char *file2store(NULL);
|
||||
if(client->_cmdParameters->getAt(0)->getString()[0] == '/')
|
||||
file2store = constructFileNameWithPath("", client->_cmdParameters);
|
||||
else
|
||||
file2store = constructFileNameWithPath(client->_currentDirectory, client->_cmdParameters);
|
||||
|
||||
#ifdef DEBUG_FTPS
|
||||
Serial.printf("filePathSize : %d\n", filePathSize);
|
||||
Serial.printf("Final file path : %s\n",file2store);
|
||||
#endif
|
||||
|
||||
char *temp = (char *)malloc(sizeof(char) * filePathSize + 1);// /!\ test for malloc fail
|
||||
strcpy(temp,client->_currentDirectory);
|
||||
if(strcmp(temp, "/") != 0)strcat(temp,"/");
|
||||
|
||||
for(int i(0); i < paramCount; i++)
|
||||
{
|
||||
strcat(temp,client->_cmdParameters->getAt(i)->getString());
|
||||
if(i != paramCount-1)
|
||||
strcat(temp," ");
|
||||
}
|
||||
|
||||
#ifdef DEBUG_FTPS
|
||||
Serial.printf("Final file path : %s, size : %d --> %d\n",temp, filePathSize, strlen(temp));
|
||||
#endif
|
||||
client->setCurrentFile(temp);
|
||||
#ifdef DEBUG_FTPS
|
||||
Serial.printf("File to donwload : %s\n", temp);
|
||||
#endif
|
||||
free(temp);
|
||||
client->setCurrentFile(file2store);
|
||||
free(file2store);
|
||||
client->_dataTransferPending = RETR_DF;
|
||||
}
|
||||
}
|
||||
@ -447,32 +410,12 @@ class FTPServer : public TCPServer<T>
|
||||
{
|
||||
if (client->_cmdParameters->count() > 0)
|
||||
{
|
||||
uint16_t dirPathSize(0) /*dir path plus dirname*/, paramCount(client->_cmdParameters->count());
|
||||
char *dirNameWithPath(NULL);
|
||||
for(int i(0); i < paramCount; i++)
|
||||
{
|
||||
dirPathSize += strlen(client->_cmdParameters->getAt(i)->getString()) + 1;
|
||||
}
|
||||
|
||||
dirPathSize += strlen(client->_currentDirectory) + 1;
|
||||
|
||||
dirNameWithPath = (char *)malloc( sizeof(char) * dirPathSize );
|
||||
char *dirNameWithPath = constructFileNameWithPath(client->_currentDirectory, client->_cmdParameters);
|
||||
|
||||
if(dirNameWithPath != NULL)
|
||||
{
|
||||
strcpy(dirNameWithPath,client->_currentDirectory);
|
||||
if(strcmp(dirNameWithPath, "/") != 0)strcat(dirNameWithPath,"/");
|
||||
|
||||
for(int i(0); i < paramCount; i++)
|
||||
{
|
||||
strcat(dirNameWithPath,client->_cmdParameters->getAt(i)->getString());
|
||||
|
||||
if(i != paramCount-1)
|
||||
strcat(dirNameWithPath," ");
|
||||
}
|
||||
|
||||
#ifdef DEBUG_FTPS
|
||||
Serial.printf("Final dirName : #%s#, size : %d\n",dirNameWithPath, dirPathSize);
|
||||
Serial.printf("Final dirName : #%s#\n",dirNameWithPath);
|
||||
#endif
|
||||
|
||||
if(_sdCardManager->mkdir(dirNameWithPath))
|
||||
@ -499,30 +442,10 @@ class FTPServer : public TCPServer<T>
|
||||
if (client->_cmdParameters->count() > 0)
|
||||
{
|
||||
//We have the dir name, we need to append the current directory...
|
||||
uint16_t dirPathSize(0) /*dir path plus dirname*/, paramCount(client->_cmdParameters->count());
|
||||
char *dirNameWithPath(NULL);
|
||||
for(int i(0); i < paramCount; i++)
|
||||
{
|
||||
dirPathSize += strlen(client->_cmdParameters->getAt(i)->getString()) + 1;
|
||||
}
|
||||
|
||||
dirPathSize += strlen(client->_currentDirectory) + 1;
|
||||
|
||||
dirNameWithPath = (char *)malloc( sizeof(char) * dirPathSize );
|
||||
|
||||
strcpy(dirNameWithPath,client->_currentDirectory);
|
||||
if(strcmp(dirNameWithPath, "/") != 0)strcat(dirNameWithPath,"/");
|
||||
|
||||
for(int i(0); i < paramCount; i++)
|
||||
{
|
||||
strcat(dirNameWithPath,client->_cmdParameters->getAt(i)->getString());
|
||||
|
||||
if(i != paramCount-1)
|
||||
strcat(dirNameWithPath," ");
|
||||
}
|
||||
char *dirNameWithPath = constructFileNameWithPath(client->_currentDirectory, client->_cmdParameters);
|
||||
|
||||
#ifdef DEBUG_FTPS
|
||||
Serial.printf("pathDirName to delete : #%s#, size : %d\n",dirNameWithPath, dirPathSize);
|
||||
Serial.printf("pathDirName to delete : #%s#\n",dirNameWithPath);
|
||||
#endif
|
||||
|
||||
if(_sdCardManager->rmdir(dirNameWithPath))
|
||||
@ -546,36 +469,18 @@ class FTPServer : public TCPServer<T>
|
||||
if (client->_cmdParameters->count() > 0)
|
||||
{
|
||||
//We save the file path to be sent
|
||||
uint16_t filePathSize(0) /*dir path plus dirname*/, paramCount(client->_cmdParameters->count());
|
||||
char *fileNameWithPath(NULL);
|
||||
for(int i(0); i < paramCount; i++)
|
||||
{
|
||||
filePathSize += strlen(client->_cmdParameters->getAt(i)->getString()) + 1;
|
||||
}
|
||||
char *fileNameWithPath = constructFileNameWithPath(client->_currentDirectory, client->_cmdParameters);
|
||||
|
||||
filePathSize += strlen(client->_currentDirectory) + 1;
|
||||
|
||||
fileNameWithPath = (char *)malloc( sizeof(char) * filePathSize );
|
||||
|
||||
strcpy(fileNameWithPath,client->_currentDirectory);
|
||||
if(strcmp(fileNameWithPath, "/") != 0)strcat(fileNameWithPath,"/");
|
||||
|
||||
for(int i(0); i < paramCount; i++)
|
||||
{
|
||||
strcat(fileNameWithPath,client->_cmdParameters->getAt(i)->getString());
|
||||
|
||||
if(i != paramCount-1)
|
||||
strcat(fileNameWithPath," ");
|
||||
}
|
||||
client->_client.println("150 File status okay; about to open data connection.");
|
||||
|
||||
client->setCurrentFile(fileNameWithPath);
|
||||
|
||||
#ifdef DEBUG_FTPS
|
||||
Serial.printf("File to store : #%s#, size : %d\n", client->_currentFile, filePathSize);
|
||||
Serial.printf("File to store : #%s#\n", client->_currentFile);
|
||||
#endif
|
||||
free(fileNameWithPath);
|
||||
client->_dataTransferPending = STOR_DF;
|
||||
client->startTimeout();
|
||||
}
|
||||
}
|
||||
else if(strcmp(client->_ftpCommand, "SYST") == 0)
|
||||
@ -587,33 +492,13 @@ class FTPServer : public TCPServer<T>
|
||||
if (client->_cmdParameters->count() > 0)
|
||||
{
|
||||
//We have the file name, we need to append the current directory...
|
||||
uint16_t filePathSize(0) /*dir path plus dirname*/, paramCount(client->_cmdParameters->count());
|
||||
char *fileNameWithPath(NULL);
|
||||
for(int i(0); i < paramCount; i++)
|
||||
{
|
||||
filePathSize += strlen(client->_cmdParameters->getAt(i)->getString()) + 1;
|
||||
}
|
||||
|
||||
filePathSize += strlen(client->_currentDirectory) + 1;
|
||||
|
||||
fileNameWithPath = (char *)malloc( sizeof(char) * filePathSize );
|
||||
|
||||
strcpy(fileNameWithPath,client->_currentDirectory);
|
||||
if(strcmp(fileNameWithPath, "/") != 0)strcat(fileNameWithPath,"/");
|
||||
|
||||
for(int i(0); i < paramCount; i++)
|
||||
{
|
||||
strcat(fileNameWithPath,client->_cmdParameters->getAt(i)->getString());
|
||||
|
||||
if(i != paramCount-1)
|
||||
strcat(fileNameWithPath," ");
|
||||
}
|
||||
char *file2deleteNameWithPath = constructFileNameWithPath(client->_currentDirectory, client->_cmdParameters);
|
||||
|
||||
#ifdef DEBUG_FTPS
|
||||
Serial.printf("file to delete : #%s#, size : %d\n",fileNameWithPath,filePathSize);
|
||||
Serial.printf("file to delete : #%s#\n",file2deleteNameWithPath);
|
||||
#endif
|
||||
|
||||
if(_sdCardManager->remove(fileNameWithPath))
|
||||
if(_sdCardManager->remove(file2deleteNameWithPath))
|
||||
{
|
||||
client->_client.println("250 Requested file action okay.");
|
||||
}
|
||||
@ -622,13 +507,54 @@ class FTPServer : public TCPServer<T>
|
||||
client->_client.println("550 Requested action not taken.");
|
||||
}
|
||||
|
||||
free(fileNameWithPath);
|
||||
free(file2deleteNameWithPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
client->_client.println("550 Requested action not taken.");
|
||||
}
|
||||
}
|
||||
else if(strcmp(client->_ftpCommand, "RNFR") == 0)
|
||||
{
|
||||
if (client->_cmdParameters->count() > 0)
|
||||
{
|
||||
//We have the file name, we need to append the current directory...
|
||||
char *fileNameWithPath = constructFileNameWithPath(client->_currentDirectory, client->_cmdParameters);
|
||||
|
||||
#ifdef DEBUG_FTPS
|
||||
Serial.printf("file to rename : #%s#\n",fileNameWithPath);
|
||||
#endif
|
||||
|
||||
client->setCurrentFile(fileNameWithPath);
|
||||
free(fileNameWithPath);
|
||||
|
||||
client->_client.println("350 Requested file action pending further information.");
|
||||
}
|
||||
else
|
||||
{
|
||||
client->_client.println("550 Requested action not taken.");
|
||||
}
|
||||
}
|
||||
else if(strcmp(client->_ftpCommand, "RNTO") == 0)
|
||||
{
|
||||
if (client->_cmdParameters->count() > 0)
|
||||
{
|
||||
//Here we rename the file
|
||||
char *file2RenameNameWithPath = constructFileNameWithPath(client->_currentDirectory, client->_cmdParameters);
|
||||
#ifdef DEBUG_FTPS
|
||||
Serial.printf("file to rename to : #%s#\n",file2RenameNameWithPath);
|
||||
Serial.printf("Old name : %s --> %s\n",client->_currentFile,file2RenameNameWithPath);
|
||||
#endif
|
||||
|
||||
if(_sdCardManager->rename(client->_currentFile,file2RenameNameWithPath))
|
||||
{
|
||||
client->_client.println("250 Requested file action okay.");
|
||||
}else
|
||||
client->_client.println("550 Requested action not taken.");
|
||||
|
||||
free(file2RenameNameWithPath);
|
||||
}
|
||||
}
|
||||
else
|
||||
client->_client.println("502 Command not implemented.");
|
||||
}
|
||||
@ -645,17 +571,17 @@ class FTPServer : public TCPServer<T>
|
||||
|
||||
if(fileBeeingReceived)
|
||||
{
|
||||
char recvBuffer[1024];
|
||||
uint8_t recvBuffer[2048];
|
||||
|
||||
/*fileBeeingReceived.seek(client->_fileRecvBytes);*/
|
||||
uint16_t size = client->_dataClient.read((uint8_t *)recvBuffer, 1024);
|
||||
uint16_t size = client->_dataClient.read(recvBuffer, 2048);
|
||||
|
||||
fileBeeingReceived.write(recvBuffer, size);
|
||||
|
||||
client->_fileRecvBytes += size;
|
||||
fileBeeingReceived.close();
|
||||
#ifdef DEBUG_FTPS
|
||||
Serial.println("File beeing written");
|
||||
Serial.printf("Writting : %d bytes to file\n", size);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
@ -720,7 +646,7 @@ class FTPServer : public TCPServer<T>
|
||||
{
|
||||
if (client->_currentFile != NULL)
|
||||
{
|
||||
uint8_t sendBuffer[READ_WRITE_BUFFER_SIZE];
|
||||
uint8_t sendBuffer[READ_BUFFER_SIZE];
|
||||
File fileToSend = _sdCardManager->open(client->_currentFile);
|
||||
|
||||
if (fileToSend)
|
||||
@ -731,7 +657,7 @@ class FTPServer : public TCPServer<T>
|
||||
|
||||
if(fileToSend.available())
|
||||
{
|
||||
readBytes = fileToSend.read(sendBuffer, READ_WRITE_BUFFER_SIZE);
|
||||
readBytes = fileToSend.read(sendBuffer, READ_BUFFER_SIZE);
|
||||
client->_dataClient.write(sendBuffer, readBytes);
|
||||
|
||||
client->_fileSentBytes += readBytes;
|
||||
@ -765,7 +691,7 @@ class FTPServer : public TCPServer<T>
|
||||
return false;
|
||||
}
|
||||
|
||||
char *_83FileNameFormat(char *filename)
|
||||
static char *_83FileNameFormat(char *filename)
|
||||
{
|
||||
char *buffer = (char *)malloc((sizeof(char) * strlen(filename)) + 1);
|
||||
strcpy(buffer, filename);
|
||||
@ -797,6 +723,46 @@ class FTPServer : public TCPServer<T>
|
||||
return filename;
|
||||
}
|
||||
|
||||
//This functions construct the full file path.
|
||||
//ie : if the current directory is : "/somedir/subdir" and the received file name is : "my file .txt"
|
||||
//then it will return : "/somedir/subdir/my file .txt"
|
||||
//Note that the file name is contained in a parameter list : "my" in the first element, then "file" in the second and finally ".txt" in the third.
|
||||
//Return NULL if malloc fails
|
||||
// DO NOT FORGET TO FREE THE ALLOCATED STRING AFTER USING IT....
|
||||
static char *constructFileNameWithPath(const char *dir, Dictionary<DictionaryHelper::StringEntity> *parameters)
|
||||
{
|
||||
uint16_t fileWithPathSize(strlen(dir) + 1) /*dir path plus filename*/, paramCount(parameters->count());
|
||||
char *fileNameWithPath(NULL);
|
||||
|
||||
for(int i(0); i < paramCount; i++)
|
||||
{
|
||||
fileWithPathSize += strlen(parameters->getAt(i)->getString()) + 1;
|
||||
}
|
||||
|
||||
fileNameWithPath = (char *)malloc( sizeof(char) * fileWithPathSize );
|
||||
|
||||
#ifdef DEBUG_FTPS
|
||||
Serial.printf("Allocated string size : %d\n",fileWithPathSize);
|
||||
#endif
|
||||
|
||||
if(fileNameWithPath == NULL)//Malloc fails
|
||||
return NULL;
|
||||
|
||||
strcpy(fileNameWithPath, dir);
|
||||
if(strcmp(fileNameWithPath, "/") != 0 && strlen(dir) != 0)
|
||||
strcat(fileNameWithPath,"/");
|
||||
|
||||
for(int i(0); i < paramCount; i++)
|
||||
{
|
||||
strcat(fileNameWithPath, parameters->getAt(i)->getString());
|
||||
|
||||
if(i != paramCount-1)
|
||||
strcat(fileNameWithPath," ");
|
||||
}
|
||||
|
||||
return fileNameWithPath;
|
||||
}
|
||||
|
||||
char *_login;
|
||||
char *_password;
|
||||
unsigned int _dataPort;
|
||||
|
@ -19,5 +19,6 @@
|
||||
#define SOFT_VERSION "1.3.1" //Fixed sdCardUnmount api call
|
||||
#define SOFT_VERSION "1.3.2" //Modified TCPServer and WEBServer core logic
|
||||
#define SOFT_VERSION "1.4.0" //Added the new FTPServer
|
||||
#define SOFT_VERSION "1.4.1" //Updated FTP server to use the new SD library for the ESP8266
|
||||
|
||||
#endif //VERSIONS_H
|
||||
|
Loading…
Reference in New Issue
Block a user