diff --git a/esp3d/configuration.h b/esp3d/configuration.h index 06dcc21f..1c7727c3 100644 --- a/esp3d/configuration.h +++ b/esp3d/configuration.h @@ -42,9 +42,6 @@ //TELNET_FEATURE : enable Telnet function #define TELNET_FEATURE -//FTP_FEATURE : enable FTP function -//#define FTP_FEATURE - //WS_DATA_FEATURE: allow to connect serial from Websocket #define WS_DATA_FEATURE @@ -112,9 +109,6 @@ //ESP_SDFAT 3 //esp8266 (same as native) / esp32 #define SD_DEVICE ESP_SDFAT -//FILESYSTEM_TIMESTAMP_FEATURE: allow to get last write time from FILESYSTEM files -//#define SD_TIMESTAMP_FEATURE - //pin if reader has insert detection feature //let -1 or comment if none #define ESP_SD_DETECT_PIN -1 @@ -128,7 +122,14 @@ #define FILESYSTEM_FEATURE ESP_SPIFFS_FILESYSTEM //Allows to mount /FS and /SD under / for FTP server -#define GLOBAL_FILESYSTEM +#define GLOBAL_FILESYSTEM_FEATURE + +//FTP_FEATURE : enable FTP feature +//FS_ROOT mount all FS +//FS_FLASH mount Flash FS +//FS_SD mount SD FS +//FS_USBDISK mount USB disk FS +#define FTP_FEATURE FS_ROOT //DIRECT_PIN_FEATURE: allow to access pin using ESP201 command #define DIRECT_PIN_FEATURE @@ -136,9 +137,12 @@ //TIMESTAMP_FEATURE: set time system //#define TIMESTAMP_FEATURE -//FILESYSTEM_TIMESTAMP_FEATURE: allow to get last write time from FILESYSTEM files +//FILESYSTEM_TIMESTAMP_FEATURE: display last write time from Flash files //#define FILESYSTEM_TIMESTAMP_FEATURE +//FILESYSTEM_TIMESTAMP_FEATURE:display last write time from SD files +//#define SD_TIMESTAMP_FEATURE + //MDNS_FEATURE: this feature allow type the name defined //in web browser by default: http:\\esp8266.local and connect //need `bonjour` protocol on windows diff --git a/esp3d/src/core/commands.cpp b/esp3d/src/core/commands.cpp index 49295f0d..27dbf2be 100644 --- a/esp3d/src/core/commands.cpp +++ b/esp3d/src/core/commands.cpp @@ -564,7 +564,7 @@ bool Commands::execute_internal_command (int cmd, const char* cmd_params, level_ response = ESP750(cmd_params, auth_type, output); break; #endif //SD_DEVICE -#if defined (GLOBAL_FILESYSTEM) +#if defined (GLOBAL_FILESYSTEM_FEATURE) //List Global Filesystem //[ESP780] pwd= case 780: @@ -576,7 +576,7 @@ bool Commands::execute_internal_command (int cmd, const char* cmd_params, level_ case 790: response = ESP790(cmd_params, auth_type, output); break; -#endif //GLOBAL_FILESYSTEM +#endif //GLOBAL_FILESYSTEM_FEATURE //Get fw version firmare target and fw version //eventually set time with pc time //output is JSON or plain text according parameter diff --git a/esp3d/src/core/commands.h b/esp3d/src/core/commands.h index 0a9e56ea..3103d719 100644 --- a/esp3d/src/core/commands.h +++ b/esp3d/src/core/commands.h @@ -132,10 +132,10 @@ public: bool ESP750(const char* cmd_params, level_authenticate_type auth_level, ESP3DOutput * output); bool ESP740(const char* cmd_params, level_authenticate_type auth_level, ESP3DOutput * output); #endif //SD_DEVICE -#if defined (GLOBAL_FILESYSTEM) +#if defined (GLOBAL_FILESYSTEM_FEATURE) bool ESP780(const char* cmd_params, level_authenticate_type auth_level, ESP3DOutput * output); bool ESP790(const char* cmd_params, level_authenticate_type auth_level, ESP3DOutput * output); -#endif //GLOBAL_FILESYSTEM +#endif //GLOBAL_FILESYSTEM_FEATURE bool ESP800(const char* cmd_params, level_authenticate_type auth_level, ESP3DOutput * output); bool ESP900(const char* cmd_params, level_authenticate_type auth_level, ESP3DOutput * output); #ifdef BUZZER_DEVICE diff --git a/esp3d/src/core/espcmd/ESP180.cpp b/esp3d/src/core/espcmd/ESP180.cpp index 51712e35..5a1d1878 100644 --- a/esp3d/src/core/espcmd/ESP180.cpp +++ b/esp3d/src/core/espcmd/ESP180.cpp @@ -23,7 +23,7 @@ #include "../esp3doutput.h" #include "../settings_esp3d.h" #include "../../modules/authentication/authentication_service.h" -#include "../../modules/ftp/ftp_server.h" +#include "../../modules/ftp/FtpServer.h" //Set ftp state which can be ON, OFF, CLOSE //[ESP180]pwd= bool Commands::ESP180(const char* cmd_params, level_authenticate_type auth_type, ESP3DOutput * output) diff --git a/esp3d/src/core/espcmd/ESP420.cpp b/esp3d/src/core/espcmd/ESP420.cpp index d9a2f243..b5441566 100644 --- a/esp3d/src/core/espcmd/ESP420.cpp +++ b/esp3d/src/core/espcmd/ESP420.cpp @@ -45,7 +45,7 @@ #include "../../modules/telnet/telnet_server.h" #endif //TELNET_FEATURE #ifdef FTP_FEATURE -#include "../../modules/ftp/ftp_server.h" +#include "../../modules/ftp/FtpServer.h" #endif //FTP_FEATURE #ifdef WS_DATA_FEATURE #include "../../modules/websocket/websocket_server.h" diff --git a/esp3d/src/core/espcmd/ESP780.cpp b/esp3d/src/core/espcmd/ESP780.cpp index bc496733..502ddc07 100644 --- a/esp3d/src/core/espcmd/ESP780.cpp +++ b/esp3d/src/core/espcmd/ESP780.cpp @@ -18,7 +18,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "../../include/esp3d_config.h" -#if defined (GLOBAL_FILESYSTEM) +#if defined (GLOBAL_FILESYSTEM_FEATURE) #include "../commands.h" #include "../esp3doutput.h" #include "../settings_esp3d.h" @@ -107,4 +107,4 @@ bool Commands::ESP780(const char* cmd_params, level_authenticate_type auth_type, return response; } -#endif //GLOBAL_FILESYSTEM +#endif //GLOBAL_FILESYSTEM_FEATURE diff --git a/esp3d/src/core/espcmd/ESP790.cpp b/esp3d/src/core/espcmd/ESP790.cpp index 1fb23ea0..11ac9d42 100644 --- a/esp3d/src/core/espcmd/ESP790.cpp +++ b/esp3d/src/core/espcmd/ESP790.cpp @@ -18,7 +18,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "../../include/esp3d_config.h" -#if defined (GLOBAL_FILESYSTEM) +#if defined (GLOBAL_FILESYSTEM_FEATURE) #include "../commands.h" #include "../esp3doutput.h" #include "../settings_esp3d.h" @@ -95,4 +95,4 @@ bool Commands::ESP790(const char* cmd_params, level_authenticate_type auth_type, return false; } -#endif //GLOBAL_FILESYSTEM +#endif //GLOBAL_FILESYSTEM_FEATURE diff --git a/esp3d/src/include/sanity_esp3d.h b/esp3d/src/include/sanity_esp3d.h index 649fe013..2e35d7a5 100644 --- a/esp3d/src/include/sanity_esp3d.h +++ b/esp3d/src/include/sanity_esp3d.h @@ -78,8 +78,8 @@ /************************** * Time * ***********************/ -#if defined(FILESYSTEM_TIMESTAMP_FEATURE) && defined( ARDUINO_ARCH_ESP8266) -#error Filesystem time is not available in ESP8266 yet +#if defined(FILESYSTEM_TIMESTAMP_FEATURE) && defined( ARDUINO_ARCH_ESP8266) && FILESYSTEM_FEATURE == ESP_SPIFFS_FILESYSTEM +#warning Filesystem time is not available in SPIFFS ESP8266 yet #endif /************************** diff --git a/esp3d/src/include/version.h b/esp3d/src/include/version.h index 73918d28..c5960401 100644 --- a/esp3d/src/include/version.h +++ b/esp3d/src/include/version.h @@ -22,7 +22,7 @@ #define _VERSION_ESP3D_H //version and sources location -#define FW_VERSION "3.0.0.a25" +#define FW_VERSION "3.0.0.a26" #define REPOSITORY "https://github.com/luc-github/ESP3D" #endif //_VERSION_ESP3D_H diff --git a/esp3d/src/modules/filesystem/esp_filesystem.cpp b/esp3d/src/modules/filesystem/esp_filesystem.cpp index 3d5c43ca..dff85859 100644 --- a/esp3d/src/modules/filesystem/esp_filesystem.cpp +++ b/esp3d/src/modules/filesystem/esp_filesystem.cpp @@ -20,9 +20,7 @@ #include "../../include/esp3d_config.h" #ifdef FILESYSTEM_FEATURE #include "esp_filesystem.h" -#ifdef FILESYSTEM_TIMESTAMP_FEATURE #include -#endif //FILESYSTEM_TIMESTAMP_FEATURE #include #ifdef ARDUINO_ARCH_ESP32 #include @@ -97,9 +95,7 @@ ESP_File::ESP_File(const char * name, const char * filename, bool isdir, size_t _index = -1; _filename = filename; _name = name; -#ifdef FILESYSTEM_TIMESTAMP_FEATURE _lastwrite = 0; -#endif //FILESYSTEM_TIMESTAMP_FEATURE _iswritemode = false; _size = size; } @@ -144,12 +140,10 @@ size_t ESP_File::size() return _size; } -#ifdef FILESYSTEM_TIMESTAMP_FEATURE time_t ESP_File::getLastWrite() { return _lastwrite; } -#endif //FILESYSTEM_TIMESTAMP_FEATURE int ESP_File::available() { @@ -210,9 +204,7 @@ ESP_File& ESP_File::operator=(const ESP_File & other) _size = other._size; _iswritemode = other._iswritemode; _dirlist = other._dirlist; -#ifdef FILESYSTEM_TIMESTAMP_FEATURE _lastwrite = other._lastwrite; -#endif //FILESYSTEM_TIMESTAMP_FEATURE return *this; } diff --git a/esp3d/src/modules/filesystem/esp_filesystem.h b/esp3d/src/modules/filesystem/esp_filesystem.h index 5fbe7cad..0ef4fed3 100644 --- a/esp3d/src/modules/filesystem/esp_filesystem.h +++ b/esp3d/src/modules/filesystem/esp_filesystem.h @@ -21,9 +21,7 @@ #ifndef _ESP_FILESYSTEM_H #define _ESP_FILESYSTEM_H #include "../../include/esp3d_config.h" -#ifdef FILESYSTEM_TIMESTAMP_FEATURE #include -#endif //FILESYSTEM_TIMESTAMP_FEATURE #define ESP_FLASH_FS_HEADER "/FS" @@ -43,9 +41,7 @@ public: bool isOpen(); ESP_File & operator=(const ESP_File & other); size_t size(); -#ifdef FILESYSTEM_TIMESTAMP_FEATURE time_t getLastWrite(); -#endif //FILESYSTEM_TIMESTAMP_FEATURE int available(); size_t write(uint8_t i); size_t write(const uint8_t *buf, size_t size); @@ -62,9 +58,7 @@ private: String _filename; String _name; size_t _size; -#ifdef FILESYSTEM_TIMESTAMP_FEATURE time_t _lastwrite; -#endif //FILESYSTEM_TIMESTAMP_FEATURE }; class ESP_FileSystem @@ -86,6 +80,7 @@ public: static bool remove(const char *path); static bool mkdir(const char *path); static bool rmdir(const char *path); + static bool rename(const char *oldpath, const char *newpath); static void closeAll(); static bool started() { diff --git a/esp3d/src/modules/filesystem/esp_globalFS.cpp b/esp3d/src/modules/filesystem/esp_globalFS.cpp index 1b0cf0f5..9991922d 100644 --- a/esp3d/src/modules/filesystem/esp_globalFS.cpp +++ b/esp3d/src/modules/filesystem/esp_globalFS.cpp @@ -19,9 +19,9 @@ */ #include "../../include/esp3d_config.h" -#if defined(GLOBAL_FILESYSTEM) +#if defined(GLOBAL_FILESYSTEM_FEATURE) #include "esp_globalFS.h" -#include "../../core/genLinkedList.h" +//#include "../../core/genLinkedList.h" //to verify FS is accessible @@ -227,6 +227,27 @@ bool ESP_GBFS::remove(const char *path) return false; } +bool ESP_GBFS::rename(const char *oldpath, const char *newpath) +{ +#if defined (FILESYSTEM_FEATURE) || defined(SD_DEVICE) + uint8_t t = getFSType(oldpath); + if (t == FS_ROOT) { + return false; + } +#if defined (FILESYSTEM_FEATURE) + if (t == FS_FLASH) { + return ESP_FileSystem::rename(getRealPath(oldpath), getRealPath(newpath)); + } +#endif //FILESYSTEM_FEATURE +#if defined (SD_DEVICE) + if (t == FS_SD) { + return ESP_SD::rename(getRealPath(oldpath), getRealPath(newpath)); + } +#endif //SD_DEVICE +#endif // FILESYSTEM_FEATURE || SD_DEVICE + return false; +} + bool ESP_GBFS::mkdir(const char *path) { #if defined (FILESYSTEM_FEATURE) || defined(SD_DEVICE) @@ -501,22 +522,16 @@ size_t ESP_GBFile::size() return 0; } -#if defined (SD_TIMESTAMP_FEATURE) || defined(FILESYSTEM_TIMESTAMP_FEATURE) time_t ESP_GBFile::getLastWrite() { -#if defined(FILESYSTEM_FEATURE) && defined(FILESYSTEM_TIMESTAMP_FEATURE) if (_type == FS_FLASH) { return _flashFile.getLastWrite(); } -#endif //FILESYSTEM_FEATURE && FILESYSTEM_TIMESTAMP_FEATURE -#if defined(SD_DEVICE) && defined(SD_TIMESTAMP_FEATURE) if (_type == FS_SD) { return _sdFile.getLastWrite(); } -#endif //SD_DEVICE && SD_TIMESTAMP_FEATURE return 0; } -#endif //SD_TIMESTAMP_FEATURE || FILESYSTEM_TIMESTAMP_FEATURE int ESP_GBFile::available() { @@ -716,4 +731,4 @@ ESP_GBFile ESP_GBFile::openNextFile() return f; } -#endif //GLOBAL_FILESYSTEM +#endif //GLOBAL_FILESYSTEM_FEATURE diff --git a/esp3d/src/modules/filesystem/esp_globalFS.h b/esp3d/src/modules/filesystem/esp_globalFS.h index 2c83b547..5608214b 100644 --- a/esp3d/src/modules/filesystem/esp_globalFS.h +++ b/esp3d/src/modules/filesystem/esp_globalFS.h @@ -22,9 +22,7 @@ #define _ESP_GLOBAL_FS_H #include "../../include/esp3d_config.h" #include "../../core/esp3doutput.h" -#if defined(SD_TIMESTAMP_FEATURE) || defined(FILESYSTEM_TIMESTAMP_FEATURE) #include -#endif //SD_TIMESTAMP_FEATURE || FILESYSTEM_TIMESTAMP_FEATURE #ifdef FILESYSTEM_FEATURE #include "esp_filesystem.h" #endif //FILESYSTEM_FEATURE @@ -60,9 +58,7 @@ public: ESP_GBFile & operator=(const ESP_SDFile & other); #endif //SD_DEVICE size_t size(); -#if defined (SD_TIMESTAMP_FEATURE) || defined(FILESYSTEM_TIMESTAMP_FEATURE) time_t getLastWrite(); -#endif //SD_TIMESTAMP_FEATURE || FILESYSTEM_TIMESTAMP_FEATURE int available(); size_t write(uint8_t i); size_t write(const uint8_t *buf, size_t size); @@ -96,6 +92,7 @@ public: static bool remove(const char *path); static bool mkdir(const char *path); static bool rmdir(const char *path); + static bool rename(const char *oldpath, const char *newpath); static void closeAll(); static String & formatBytes (uint64_t bytes); static const char * getNextFS(bool reset = false); diff --git a/esp3d/src/modules/filesystem/esp_sd.cpp b/esp3d/src/modules/filesystem/esp_sd.cpp index f752cd03..75349c90 100644 --- a/esp3d/src/modules/filesystem/esp_sd.cpp +++ b/esp3d/src/modules/filesystem/esp_sd.cpp @@ -22,9 +22,7 @@ #ifdef SD_DEVICE #include "esp_sd.h" #include "../../core/genLinkedList.h" -#ifdef SD_TIMESTAMP_FEATURE #include -#endif //SD_TIMESTAMP_FEATURE #define ESP_MAX_SD_OPENHANDLE 4 #if ((SD_DEVICE == ESP_SD_NATIVE) || (SD_DEVICE == ESP_SDFAT)) && defined (ARDUINO_ARCH_ESP8266) @@ -89,9 +87,7 @@ ESP_SDFile::ESP_SDFile(const char * name, const char * filename, bool isdir, siz _index = -1; _filename = filename; _name = name; -#ifdef SD_TIMESTAMP_FEATURE _lastwrite = 0; -#endif //SD_TIMESTAMP_FEATURE _iswritemode = false; _size = size; } @@ -136,12 +132,10 @@ size_t ESP_SDFile::size() return _size; } -#ifdef SD_TIMESTAMP_FEATURE time_t ESP_SDFile::getLastWrite() { return _lastwrite; } -#endif //SD_TIMESTAMP_FEATURE int ESP_SDFile::available() { @@ -201,9 +195,7 @@ ESP_SDFile& ESP_SDFile::operator=(const ESP_SDFile & other) _size = other._size; _iswritemode = other._iswritemode; _dirlist = other._dirlist; -#ifdef SD_TIMESTAMP_FEATURE _lastwrite = other._lastwrite; -#endif //SD_TIMESTAMP_FEATURE return *this; } diff --git a/esp3d/src/modules/filesystem/esp_sd.h b/esp3d/src/modules/filesystem/esp_sd.h index 67ab3c15..6843d45f 100644 --- a/esp3d/src/modules/filesystem/esp_sd.h +++ b/esp3d/src/modules/filesystem/esp_sd.h @@ -22,9 +22,7 @@ #define _ESP_SD_H #include "../../include/esp3d_config.h" #include "../../core/esp3doutput.h" -#ifdef SD_TIMESTAMP_FEATURE #include -#endif //SD_TIMESTAMP_FEATURE #define ESP_SD_FS_HEADER "/SD" @@ -45,9 +43,7 @@ public: bool isOpen(); ESP_SDFile & operator=(const ESP_SDFile & other); size_t size(); -#ifdef SD_TIMESTAMP_FEATURE time_t getLastWrite(); -#endif //SD_TIMESTAMP_FEATURE int available(); size_t write(uint8_t i); size_t write(const uint8_t *buf, size_t size); @@ -63,9 +59,7 @@ private: String _filename; String _name; size_t _size; -#ifdef SD_TIMESTAMP_FEATURE time_t _lastwrite; -#endif //SD_TIMESTAMP_FEATURE }; class ESP_SD @@ -89,6 +83,7 @@ public: static bool remove(const char *path); static bool mkdir(const char *path); static bool rmdir(const char *path); + static bool rename(const char *oldpath, const char *newpath); static void closeAll(); static uint8_t getSPISpeedDivider() { diff --git a/esp3d/src/modules/filesystem/flash/fat_esp32_filesystem.cpp b/esp3d/src/modules/filesystem/flash/fat_esp32_filesystem.cpp index 3db4502b..b7b79a45 100644 --- a/esp3d/src/modules/filesystem/flash/fat_esp32_filesystem.cpp +++ b/esp3d/src/modules/filesystem/flash/fat_esp32_filesystem.cpp @@ -53,6 +53,10 @@ size_t ESP_FileSystem::usedBytes() return (FFat.totalBytes() - FFat.freeBytes()); } +bool ESP_FileSystem::rename(const char *oldpath, const char *newpath) +{ + return FFat.rename(oldpath,newpath); +} const char * ESP_FileSystem::FilesystemName() { @@ -170,9 +174,7 @@ ESP_File::ESP_File(void* handle, bool isdir, bool iswritemode, const char * path _index = -1; _filename = ""; _name = ""; -#ifdef FILESYSTEM_TIMESTAMP_FEATURE - memset (&_lastwrite,0,sizeof(time_t)); -#endif //FILESYSTEM_TIMESTAMP_FEATURE + _lastwrite = 0; _iswritemode = iswritemode; _size = 0; if (!handle) { @@ -218,9 +220,7 @@ ESP_File::ESP_File(void* handle, bool isdir, bool iswritemode, const char * path //size _size = tFile_handle[i].size(); //time -#ifdef FILESYSTEM_TIMESTAMP_FEATURE _lastwrite = tFile_handle[i].getLastWrite(); -#endif //FILESYSTEM_TIMESTAMP_FEATURE _index = i; //log_esp3d("Opening File at index %d",_index); set = true; @@ -239,9 +239,7 @@ void ESP_File::close() File ftmp = FFat.open(_filename.c_str()); if (ftmp) { _size = ftmp.size(); -#ifdef FILESYSTEM_TIMESTAMP_FEATURE _lastwrite = ftmp.getLastWrite(); -#endif //FILESYSTEM_TIMESTAMP_FEATURE ftmp.close(); } } diff --git a/esp3d/src/modules/filesystem/flash/littlefs_esp8266_filesystem .cpp b/esp3d/src/modules/filesystem/flash/littlefs_esp8266_filesystem .cpp index ee0ceb31..9a997e90 100644 --- a/esp3d/src/modules/filesystem/flash/littlefs_esp8266_filesystem .cpp +++ b/esp3d/src/modules/filesystem/flash/littlefs_esp8266_filesystem .cpp @@ -57,6 +57,10 @@ size_t ESP_FileSystem::usedBytes() return info.usedBytes; } +bool ESP_FileSystem::rename(const char *oldpath, const char *newpath) +{ + return LittleFS.rename(oldpath,newpath); +} const char * ESP_FileSystem::FilesystemName() { @@ -197,9 +201,7 @@ ESP_File::ESP_File(void* handle, bool isdir, bool iswritemode, const char * path _index = -1; _filename = ""; _name = ""; -#ifdef FILESYSTEM_TIMESTAMP_FEATURE - memset (&_lastwrite,0,sizeof(time_t)); -#endif //FILESYSTEM_TIMESTAMP_FEATURE + _lastwrite = 0; _iswritemode = iswritemode; _size = 0; if (!handle) { @@ -259,9 +261,9 @@ ESP_File::ESP_File(void* handle, bool isdir, bool iswritemode, const char * path //size _size = tFile_handle[i].size(); //time -#ifdef FILESYSTEM_TIMESTAMP_FEATURE - _lastwrite = tFile_handle[i].getLastWrite(); -#endif //FILESYSTEM_TIMESTAMP_FEATURE + //TODO - not yet implemented in esp core + //_lastwrite = tFile_handle[i].getLastWrite(); + _lastwrite = 0; _index = i; //log_esp3d("Opening File at index %d",_index); set = true; @@ -286,9 +288,9 @@ void ESP_File::close() File ftmp = LittleFS.open(_filename.c_str(), "r"); if (ftmp) { _size = ftmp.size(); -#ifdef FILESYSTEM_TIMESTAMP_FEATURE - _lastwrite = ftmp.getLastWrite(); -#endif //FILESYSTEM_TIMESTAMP_FEATURE + //TODO - not yet implemented in esp core + //_lastwrite = ftmp.getLastWrite(); + _lastwrite = 0; ftmp.close(); } } diff --git a/esp3d/src/modules/filesystem/flash/spiffs_esp32_filesystem.cpp b/esp3d/src/modules/filesystem/flash/spiffs_esp32_filesystem.cpp index 31ce0110..e74bd2c0 100644 --- a/esp3d/src/modules/filesystem/flash/spiffs_esp32_filesystem.cpp +++ b/esp3d/src/modules/filesystem/flash/spiffs_esp32_filesystem.cpp @@ -51,6 +51,10 @@ size_t ESP_FileSystem::usedBytes() return SPIFFS.usedBytes(); } +bool ESP_FileSystem::rename(const char *oldpath, const char *newpath) +{ + return SPIFFS.rename(oldpath,newpath); +} const char * ESP_FileSystem::FilesystemName() { @@ -185,9 +189,7 @@ ESP_File::ESP_File(void* handle, bool isdir, bool iswritemode, const char * path _index = -1; _filename = ""; _name = ""; -#ifdef FILESYSTEM_TIMESTAMP_FEATURE - memset (&_lastwrite,0,sizeof(time_t)); -#endif //FILESYSTEM_TIMESTAMP_FEATURE + _lastwrite = 0; _iswritemode = iswritemode; _size = 0; if (!handle) { @@ -233,9 +235,7 @@ ESP_File::ESP_File(void* handle, bool isdir, bool iswritemode, const char * path //size _size = tFile_handle[i].size(); //time -#ifdef FILESYSTEM_TIMESTAMP_FEATURE _lastwrite = tFile_handle[i].getLastWrite(); -#endif //FILESYSTEM_TIMESTAMP_FEATURE _index = i; //log_esp3d("Opening File at index %d",_index); set = true; @@ -254,9 +254,7 @@ void ESP_File::close() File ftmp = SPIFFS.open(_filename.c_str()); if (ftmp) { _size = ftmp.size(); -#ifdef FILESYSTEM_TIMESTAMP_FEATURE _lastwrite = ftmp.getLastWrite(); -#endif //FILESYSTEM_TIMESTAMP_FEATURE ftmp.close(); } } diff --git a/esp3d/src/modules/filesystem/flash/spiffs_esp8266_filesystem.cpp b/esp3d/src/modules/filesystem/flash/spiffs_esp8266_filesystem.cpp index 41a9b4e4..04d890e9 100644 --- a/esp3d/src/modules/filesystem/flash/spiffs_esp8266_filesystem.cpp +++ b/esp3d/src/modules/filesystem/flash/spiffs_esp8266_filesystem.cpp @@ -55,6 +55,10 @@ size_t ESP_FileSystem::usedBytes() return info.usedBytes; } +bool ESP_FileSystem::rename(const char *oldpath, const char *newpath) +{ + return SPIFFS.rename(oldpath,newpath); +} const char * ESP_FileSystem::FilesystemName() { @@ -178,9 +182,7 @@ ESP_File::ESP_File(void* handle, bool isdir, bool iswritemode, const char * path _index = -1; _filename = ""; _name = ""; -#ifdef FILESYSTEM_TIMESTAMP_FEATURE - memset (&_lastwrite,0,sizeof(time_t)); -#endif //FILESYSTEM_TIMESTAMP_FEATURE + _lastwrite = 0; _iswritemode = iswritemode; _size = 0; if (!handle) { @@ -263,9 +265,9 @@ ESP_File::ESP_File(void* handle, bool isdir, bool iswritemode, const char * path //size _size = tFile_handle[i].size(); //time -#ifdef FILESYSTEM_TIMESTAMP_FEATURE - _lastwrite = tFile_handle[i].getLastWrite(); -#endif //FILESYSTEM_TIMESTAMP_FEATURE + //TODO - not yet implemented in esp core + //_lastwrite = tFile_handle[i].getLastWrite(); + _lastwrite = 0; _index = i; //log_esp3d("Opening File at index %d",_index); set = true; @@ -290,9 +292,9 @@ void ESP_File::close() File ftmp = SPIFFS.open(_filename.c_str(), "r"); if (ftmp) { _size = ftmp.size(); -#ifdef FILESYSTEM_TIMESTAMP_FEATURE - _lastwrite = ftmp.getLastWrite(); -#endif //FILESYSTEM_TIMESTAMP_FEATURE + //TODO - Not yet available in esp core + //_lastwrite = ftmp.getLastWrite(); + _lastwrite = 0; ftmp.close(); } } diff --git a/esp3d/src/modules/filesystem/sd/sd_native_esp32.cpp b/esp3d/src/modules/filesystem/sd/sd_native_esp32.cpp index 521d4039..3fbc0c29 100644 --- a/esp3d/src/modules/filesystem/sd/sd_native_esp32.cpp +++ b/esp3d/src/modules/filesystem/sd/sd_native_esp32.cpp @@ -97,7 +97,12 @@ uint64_t ESP_SD::usedBytes() uint64_t ESP_SD::freeBytes() { return (SD.totalBytes() - SD.usedBytes()); -}; +} + +bool ESP_SD::rename(const char *oldpath, const char *newpath) +{ + return SD.rename(oldpath,newpath); +} bool ESP_SD::format(ESP3DOutput * output) { @@ -213,9 +218,7 @@ ESP_SDFile::ESP_SDFile(void* handle, bool isdir, bool iswritemode, const char * _index = -1; _filename = ""; _name = ""; -#ifdef SD_TIMESTAMP_FEATURE - memset (&_lastwrite,0,sizeof(time_t)); -#endif //SD_TIMESTAMP_FEATURE + _lastwrite = 0; _iswritemode = iswritemode; _size = 0; if (!handle) { @@ -245,9 +248,7 @@ ESP_SDFile::ESP_SDFile(void* handle, bool isdir, bool iswritemode, const char * //size _size = tSDFile_handle[i].size(); //time -#ifdef SD_TIMESTAMP_FEATURE _lastwrite = tSDFile_handle[i].getLastWrite(); -#endif //SD_TIMESTAMP_FEATURE _index = i; //log_esp3d("Opening File at index %d",_index); set = true; @@ -266,9 +267,7 @@ void ESP_SDFile::close() File ftmp = SD.open(_filename.c_str()); if (ftmp) { _size = ftmp.size(); -#ifdef SD_TIMESTAMP_FEATURE _lastwrite = ftmp.getLastWrite(); -#endif //SD_TIMESTAMP_FEATURE ftmp.close(); } } diff --git a/esp3d/src/modules/filesystem/sd/sd_native_esp8266.cpp b/esp3d/src/modules/filesystem/sd/sd_native_esp8266.cpp index 3a20d284..a55d65fa 100644 --- a/esp3d/src/modules/filesystem/sd/sd_native_esp8266.cpp +++ b/esp3d/src/modules/filesystem/sd/sd_native_esp8266.cpp @@ -31,7 +31,6 @@ using namespace sdfat; SdFat SD; -#ifdef SD_TIMESTAMP_FEATURE void dateTime (uint16_t* date, uint16_t* dtime) { struct tm tmstruct; @@ -42,34 +41,33 @@ void dateTime (uint16_t* date, uint16_t* dtime) *dtime = FAT_TIME (tmstruct.tm_hour, tmstruct.tm_min, tmstruct.tm_sec); } -time_t getDateTimeFile(sdfat::File & filehandle) +time_t getDateTimeFile(File & filehandle) { - time_t dt = 0; + static time_t dt = 0; struct tm timefile; - memset((void *)&timefile, 0, sizeof(tm)); dir_t d; - if (filehandle.dirEntry(&d)) { - timefile.tm_year = FAT_YEAR(d.lastWriteDate) - 1900; - timefile.tm_mon = FAT_MONTH(d.lastWriteDate) - 1; - timefile.tm_mday = FAT_DAY(d.lastWriteDate); - timefile.tm_hour = FAT_HOUR(d.lastWriteTime); - timefile.tm_min = FAT_MINUTE(d.lastWriteTime); - timefile.tm_sec = FAT_SECOND(d.lastWriteTime); - timefile.tm_isdst = -1; - if (mktime(&timefile) != -1) { + if(filehandle) { + if (filehandle.dirEntry(&d)) { + timefile.tm_year = FAT_YEAR(d.lastWriteDate) - 1900; + timefile.tm_mon = FAT_MONTH(d.lastWriteDate) - 1; + timefile.tm_mday = FAT_DAY(d.lastWriteDate); + timefile.tm_hour = FAT_HOUR(d.lastWriteTime); + timefile.tm_min = FAT_MINUTE(d.lastWriteTime); + timefile.tm_sec = FAT_SECOND(d.lastWriteTime); + timefile.tm_isdst = -1; dt = mktime(&timefile); + if (dt == -1) { + log_esp3d("mktime failed"); + } } else { - log_esp3d("mktime failed"); + log_esp3d("stat file failed"); } } else { - log_esp3d("stat file failed"); + log_esp3d("check file for stat failed"); } return dt; } - -#endif //SD_TIMESTAMP_FEATURE - uint8_t ESP_SD::getState(bool refresh) { #if defined(ESP_SD_DETECT_PIN) && ESP_SD_DETECT_PIN != -1 @@ -143,7 +141,12 @@ uint64_t ESP_SD::freeBytes() } uint8_t blocks = SD.vol()->blocksPerCluster(); return volFree * blocks * 512; -}; +} + +bool ESP_SD::rename(const char *oldpath, const char *newpath) +{ + return SD.rename(oldpath,newpath); +} // strings needed in file system structures #define noName "NO NAME " @@ -697,9 +700,7 @@ ESP_SDFile::ESP_SDFile(void* handle, bool isdir, bool iswritemode, const char * _index = -1; _filename = ""; _name = ""; -#ifdef SD_TIMESTAMP_FEATURE - memset (&_lastwrite,0,sizeof(time_t)); -#endif //SD_TIMESTAMP_FEATURE + _lastwrite = 0; _iswritemode = iswritemode; _size = 0; if (!handle) { @@ -732,7 +733,6 @@ ESP_SDFile::ESP_SDFile(void* handle, bool isdir, bool iswritemode, const char * //size _size = tSDFile_handle[i].size(); //time -#ifdef SD_TIMESTAMP_FEATURE if (!_isdir) { _lastwrite = getDateTimeFile(tSDFile_handle[i]); @@ -740,7 +740,6 @@ ESP_SDFile::ESP_SDFile(void* handle, bool isdir, bool iswritemode, const char * //no need date time for directory _lastwrite = 0; } -#endif //SD_TIMESTAMP_FEATURE _index = i; //log_esp3d("Opening File at index %d",_index); set = true; @@ -772,9 +771,7 @@ void ESP_SDFile::close() sdfat::File ftmp = SD.open(_filename.c_str()); if (ftmp) { _size = ftmp.size(); -#ifdef SD_TIMESTAMP_FEATURE _lastwrite = getDateTimeFile(ftmp); -#endif //SD_TIMESTAMP_FEATURE ftmp.close(); } } diff --git a/esp3d/src/modules/filesystem/sd/sd_sdfat_esp32.cpp b/esp3d/src/modules/filesystem/sd/sd_sdfat_esp32.cpp index b8b8ad84..83b5c1b8 100644 --- a/esp3d/src/modules/filesystem/sd/sd_sdfat_esp32.cpp +++ b/esp3d/src/modules/filesystem/sd/sd_sdfat_esp32.cpp @@ -30,7 +30,6 @@ extern File tSDFile_handle[ESP_MAX_SD_OPENHANDLE]; #define FREQMZ 40 SdFat SD; -#ifdef SD_TIMESTAMP_FEATURE void dateTime (uint16_t* date, uint16_t* dtime) { struct tm tmstruct; @@ -43,32 +42,32 @@ void dateTime (uint16_t* date, uint16_t* dtime) time_t getDateTimeFile(File & filehandle) { - time_t dt = 0; + static time_t dt = 0; struct tm timefile; - memset((void *)&timefile, 0, sizeof(tm)); dir_t d; - if (filehandle.dirEntry(&d)) { - timefile.tm_year = FAT_YEAR(d.lastWriteDate) - 1900; - timefile.tm_mon = FAT_MONTH(d.lastWriteDate) - 1; - timefile.tm_mday = FAT_DAY(d.lastWriteDate); - timefile.tm_hour = FAT_HOUR(d.lastWriteTime); - timefile.tm_min = FAT_MINUTE(d.lastWriteTime); - timefile.tm_sec = FAT_SECOND(d.lastWriteTime); - timefile.tm_isdst = -1; - if (mktime(&timefile) != -1) { + if(filehandle) { + if (filehandle.dirEntry(&d)) { + timefile.tm_year = FAT_YEAR(d.lastWriteDate) - 1900; + timefile.tm_mon = FAT_MONTH(d.lastWriteDate) - 1; + timefile.tm_mday = FAT_DAY(d.lastWriteDate); + timefile.tm_hour = FAT_HOUR(d.lastWriteTime); + timefile.tm_min = FAT_MINUTE(d.lastWriteTime); + timefile.tm_sec = FAT_SECOND(d.lastWriteTime); + timefile.tm_isdst = -1; dt = mktime(&timefile); + if (dt == -1) { + log_esp3d("mktime failed"); + } } else { - log_esp3d("mktime failed"); + log_esp3d("stat file failed"); } } else { - log_esp3d("stat file failed"); + log_esp3d("check stat file failed"); } return dt; } -#endif //SD_TIMESTAMP_FEATURE - uint8_t ESP_SD::getState(bool refresh) { #if defined(ESP_SD_DETECT_PIN) && ESP_SD_DETECT_PIN != -1 @@ -142,7 +141,12 @@ uint64_t ESP_SD::freeBytes() } uint8_t blocks = SD.vol()->blocksPerCluster(); return volFree * blocks * 512; -}; +} + +bool ESP_SD::rename(const char *oldpath, const char *newpath) +{ + return SD.rename(oldpath,newpath); +} // strings needed in file system structures #define noName "NO NAME " @@ -696,9 +700,7 @@ ESP_SDFile::ESP_SDFile(void* handle, bool isdir, bool iswritemode, const char * _index = -1; _filename = ""; _name = ""; -#ifdef SD_TIMESTAMP_FEATURE _lastwrite = 0 ; -#endif //SD_TIMESTAMP_FEATURE _iswritemode = iswritemode; _size = 0; if (!handle) { @@ -731,15 +733,13 @@ ESP_SDFile::ESP_SDFile(void* handle, bool isdir, bool iswritemode, const char * //size _size = tSDFile_handle[i].size(); //time -#ifdef SD_TIMESTAMP_FEATURE - if (!_isdir) { + if (!_isdir && !iswritemode) { _lastwrite = getDateTimeFile(tSDFile_handle[i]); } else { //no need date time for directory _lastwrite = 0; } -#endif //SD_TIMESTAMP_FEATURE _index = i; //log_esp3d("Opening File at index %d",_index); set = true; @@ -771,9 +771,7 @@ void ESP_SDFile::close() File ftmp = SD.open(_filename.c_str()); if (ftmp) { _size = ftmp.size(); -#ifdef SD_TIMESTAMP_FEATURE _lastwrite = getDateTimeFile(ftmp); -#endif //SD_TIMESTAMP_FEATURE ftmp.close(); } } diff --git a/esp3d/src/modules/filesystem/sd/sdio_esp32.cpp b/esp3d/src/modules/filesystem/sd/sdio_esp32.cpp index 699bda0f..f390f00a 100644 --- a/esp3d/src/modules/filesystem/sd/sdio_esp32.cpp +++ b/esp3d/src/modules/filesystem/sd/sdio_esp32.cpp @@ -86,7 +86,12 @@ uint64_t ESP_SD::usedBytes() uint64_t ESP_SD::freeBytes() { return (SD_MMC.totalBytes() - SD_MMC.usedBytes()); -}; +} + +bool ESP_SD::rename(const char *oldpath, const char *newpath) +{ + return SD_MMC.rename(oldpath,newpath); +} bool ESP_SD::format(ESP3DOutput * output) { @@ -202,9 +207,7 @@ ESP_SDFile::ESP_SDFile(void* handle, bool isdir, bool iswritemode, const char * _index = -1; _filename = ""; _name = ""; -#ifdef SD_TIMESTAMP_FEATURE - memset (&_lastwrite,0,sizeof(time_t)); -#endif //SD_TIMESTAMP_FEATURE + _lastwrite = 0; _iswritemode = iswritemode; _size = 0; if (!handle) { @@ -234,9 +237,7 @@ ESP_SDFile::ESP_SDFile(void* handle, bool isdir, bool iswritemode, const char * //size _size = tSDFile_handle[i].size(); //time -#ifdef SD_TIMESTAMP_FEATURE _lastwrite = tSDFile_handle[i].getLastWrite(); -#endif //SD_TIMESTAMP_FEATURE _index = i; //log_esp3d("Opening File at index %d",_index); set = true; @@ -255,9 +256,7 @@ void ESP_SDFile::close() File ftmp = SD_MMC.open(_filename.c_str()); if (ftmp) { _size = ftmp.size(); -#ifdef SD_TIMESTAMP_FEATURE _lastwrite = ftmp.getLastWrite(); -#endif //SD_TIMESTAMP_FEATURE ftmp.close(); } } diff --git a/esp3d/src/modules/ftp/ExtStreaming.h b/esp3d/src/modules/ftp/ExtStreaming.h new file mode 100644 index 00000000..c1798fb0 --- /dev/null +++ b/esp3d/src/modules/ftp/ExtStreaming.h @@ -0,0 +1,127 @@ +/* +Streaming.h - Arduino library for supporting the << streaming operator +Copyright (c) 2010-2012 Mikal Hart. All rights reserved. + +ExtStreaming.h by Jean-Michel Gallego is a copy of Streaming.h. +endl had been removed and replaced by eol for compatibility with SdFat. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef EXT_STREAMING_H +#define EXT_STREAMING_H + +#if defined(ARDUINO) && ARDUINO >= 100 +#include "Arduino.h" +#else +#include "WProgram.h" +#endif + +#define STREAMING_LIBRARY_VERSION 5 + +// Generic template +template +inline Print &operator <<(Print &stream, T arg) +{ + stream.print(arg); + return stream; +} + +struct _BASED { + long val; + int base; + _BASED(long v, int b): val(v), base(b) + {} +}; + +#if ARDUINO >= 100 + +struct _BYTE_CODE { + byte val; + _BYTE_CODE(byte v) : val(v) + {} +}; +#define _BYTE(a) _BYTE_CODE(a) + +inline Print &operator <<(Print &obj, const _BYTE_CODE &arg) +{ + obj.write(arg.val); + return obj; +} + +#else + +#define _BYTE(a) _BASED(a, BYTE) + +#endif + +#define _HEX(a) _BASED(a, HEX) +#define _DEC(a) _BASED(a, DEC) +#define _OCT(a) _BASED(a, OCT) +#define _BIN(a) _BASED(a, BIN) + +// Specialization for class _BASED +// Thanks to Arduino forum user Ben Combee who suggested this +// clever technique to allow for expressions like +// Serial << _HEX(a); + +inline Print &operator <<(Print &obj, const _BASED &arg) +{ + obj.print(arg.val, arg.base); + return obj; +} + +#if ARDUINO >= 18 +// Specialization for class _FLOAT +// Thanks to Michael Margolis for suggesting a way +// to accommodate Arduino 0018's floating point precision +// feature like this: +// Serial << _FLOAT(gps_latitude, 6); // 6 digits of precision + +struct _FLOAT { + float val; + int digits; + _FLOAT(double v, int d): val(v), digits(d) + {} +}; + +inline Print &operator <<(Print &obj, const _FLOAT &arg) +{ + obj.print(arg.val, arg.digits); + return obj; +} +#endif + +// Specialization for enum _EndLineCode +// Thanks to Arduino forum user Paul V. who suggested this +// clever technique to allow for expressions like +// Serial << "Hello!" << endl; + +/* +enum _EndLineCode { endl }; + +inline Print &operator <<(Print &obj, _EndLineCode arg) +{ obj.println(); return obj; } +*/ + +enum _EndLineCode { eol }; + +inline Print &operator <<(Print &obj, _EndLineCode arg) +{ + obj.print( "\r\n" ); + return obj; +} + +#endif // EXT_STREAMING_H diff --git a/esp3d/src/modules/ftp/FtpServer.cpp b/esp3d/src/modules/ftp/FtpServer.cpp new file mode 100644 index 00000000..6bf00f7a --- /dev/null +++ b/esp3d/src/modules/ftp/FtpServer.cpp @@ -0,0 +1,1311 @@ +/* + * FTP Serveur for Arduino Due or Mega 2580 + * and Ethernet shield W5100, W5200 or W5500 + * or for Esp8266 with external SD card or SpiFfs + * Copyright (c) 2014-2018 by Jean-Michel Gallego + * + * Please read file ReadMe.txt for instructions + * + * Use ExtStreaming based on Streaming from Mial Hart + * + * Use FatLib library to easily switch between + * libraries SdFat, FatFs or SpiFfs + * + * Use Ethernet library (version 2.0.0) or + * ESP8266WiFi library + * + * Commands implemented: + * USER, PASS, AUTH (AUTH only return 'not implemented' code) + * CDUP, CWD, PWD, QUIT, NOOP + * MODE, PASV, PORT, STRU, TYPE + * ABOR, DELE, LIST, NLST, MLST, MLSD + * APPE, RETR, STOR + * MKD, RMD + * RNTO, RNFR + * MDTM, MFMT + * FEAT, SIZE + * SITE FREE + * + * Tested with those clients: + * under Windows: + * FTP Rush + * Filezilla + * WinSCP + * NcFTP, ncftpget, ncftpput + * Firefox + * command line ftp.exe + * under Ubuntu: + * gFTP + * Filezilla + * NcFTP, ncftpget, ncftpput + * lftp + * ftp + * Firefox + * under Android: + * AndFTP + * FTP Express + * Firefox + * with a second Arduino and sketch of SurferTim at + * http://playground.arduino.cc/Code/FTP + * + * This program 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. + * + * This program 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 this program. If not, see . + */ +/* + * 2019-10-27 Modified version for ESP3D by Luc LEBOSSE @luc-github + * support for ESP8266 and ESP32 in ESP3D project + */ + +#include "../../include/esp3d_config.h" +#if defined (FTP_FEATURE) +#include +#include +#include "FtpServer.h" +#include "ExtStreaming.h" +#include "../network/netconfig.h" +#include "../authentication/authentication_service.h" +#include "../../core/settings_esp3d.h" +#include "../../core/esp3doutput.h" +#if FTP_FEATURE == FS_ROOT +#include "../filesystem/esp_globalFS.h" +typedef ESP_GBFile FTPFile; +typedef ESP_GBFS FTPFS; +#endif //FTP_FEATURE == FS_ROOT + +#if FTP_FEATURE == FS_FLASH +#include "../filesystem/esp_filesystem.h" +typedef ESP_File FTPFile; +typedef ESP_FileSystem FTPFS; +#endif //FTP_FEATURE == FS_FLASH + +#if FTP_FEATURE == FS_SD +#include "../filesystem/esp_sd.h" +typedef ESP_SDFile FTPFile; +typedef ESP_SD FTPFS; +#endif //FTP_FEATURE == FS_SD + +// Uncomment to print additional info for log_esp3d +//#define FTP_DEBUG + +//width in char of file size output in listing +#define SIZELISTPADING 15 + +FTPFile dir; +FTPFile file; + +FtpServer ftp_server; + +bool legalChar( char c ) +{ + if( c == '"' || c == '*' || c == '?' || c == ':' || + c == '<' || c == '>' || c == '|' ) { + return false; + } + return 0x1f < c && c < 0x7f; +} + + +void FtpServer::closeClient() +{ + client.stop(); +} + +bool FtpServer::isConnected() +{ + return client.connected(); +} + +FtpServer::FtpServer() +{ + ftpServer = nullptr; + dataServer = nullptr; + ctrlPort = 0; + activePort = 0; + passivePort = 0; + _root = FS_ROOT; +} + +FtpServer::~FtpServer() +{ + end(); +} + +void FtpServer::end() +{ + if(ftpServer) { + delete(ftpServer); + ftpServer = nullptr; + } + if(dataServer) { + delete(dataServer); + dataServer = nullptr; + } + ctrlPort = 0; + activePort = 0; + passivePort = 0; + _started = false; + _root = FS_ROOT; +} + +const char* FtpServer::clientIPAddress() +{ + static String res; + res = "0.0.0.0"; + if (client && client.connected()) { + res = client.remoteIP().toString(); + } + return res.c_str(); +} + +bool FtpServer::started() +{ + return _started; +} + +bool FtpServer::begin() +{ + end(); + if (Settings_ESP3D::read_byte(ESP_FTP_ON) !=1) { + return true; + } + ctrlPort = Settings_ESP3D::read_uint32(ESP_FTP_CTRL_PORT); + activePort = Settings_ESP3D::read_uint32(ESP_FTP_DATA_ACTIVE_PORT); + passivePort = Settings_ESP3D::read_uint32(ESP_FTP_DATA_PASSIVE_PORT); + ftpServer = new WiFiServer(ctrlPort); + if (!ftpServer) { + return false; + } + dataServer = new WiFiServer(passivePort); + if (!dataServer) { + return false; + } + // Tells the ftp server to begin listening for incoming connection + ftpServer->begin(); + ftpServer->setNoDelay( true ); + dataServer->begin(); + millisDelay = 0; + cmdStage = FTP_Stop; + iniVariables(); + _started = true; + return _started; +} + +void FtpServer::iniVariables() +{ + // Default for data port + dataPort = activePort; + + // Default Data connection is Active + dataConn = FTP_NoConn; + + // Set the root directory + strcpy( cwdName, "/" ); + + rnfrCmd = false; + transferStage = FTP_Close; +} + + +void FtpServer::handle() +{ + if (!_started) { + return; + } +#ifdef FTP_DEBUG + int8_t data0 = data.status(); + ftpTransfer transferStage0 = transferStage; + ftpCmd cmdStage0 = cmdStage; +#endif + + if((int32_t) ( millisDelay - millis() ) > 0 ) { + return; + } + + if( cmdStage == FTP_Stop ) { + log_esp3d("FTP_STOP"); + if( client.connected()) { + disconnectClient(); + } + cmdStage = FTP_Init; + } else if( cmdStage == FTP_Init ) { // Ftp server waiting for connection + abortTransfer(); + iniVariables(); + log_esp3d(" Ftp server waiting for connection on port %d", ctrlPort); + cmdStage = FTP_Client; + } else if( cmdStage == FTP_Client ) { // Ftp server idle + if( ftpServer->hasClient()) { + client.stop(); + client = ftpServer->available(); + } + if( client.connected()) { // A client connected + clientConnected(); + millisEndConnection = millis() + 1000L * FTP_AUTH_TIME_OUT; // wait client id for 10 s. + cmdStage = FTP_User; + } + } else if( readChar() > 0 ) { // got response + processCommand(); + if( cmdStage == FTP_Stop ) { + millisEndConnection = millis() + 1000L * FTP_AUTH_TIME_OUT; // wait authentication for 10 s. + } else if( cmdStage < FTP_Cmd ) { + millisDelay = millis() + 200; // delay of 100 ms + } else { + millisEndConnection = millis() + 1000L * FTP_TIME_OUT; + } + } else if( ! client.connected() ) { + cmdStage = FTP_Init; + } + + if( transferStage == FTP_Retrieve ) { // Retrieve data + if( ! doRetrieve()) { + transferStage = FTP_Close; + } + } else if( transferStage == FTP_Store ) { // Store data + if( ! doStore()) { + transferStage = FTP_Close; + } + } else if( transferStage == FTP_List || + transferStage == FTP_Nlst) { // LIST or NLST + if( ! doList()) { + transferStage = FTP_Close; + } + } else if( transferStage == FTP_Mlsd ) { // MLSD listing + if( ! doMlsd()) { + transferStage = FTP_Close; + } + } else if( cmdStage > FTP_Client && + ! ((int32_t) ( millisEndConnection - millis() ) > 0 )) { + client << F("530 Timeout") << eol; + millisDelay = millis() + 200; // delay of 200 ms + cmdStage = FTP_Stop; + } + +#ifdef FTP_DEBUG + uint8_t dstat = data.status(); + if( cmdStage != cmdStage0 || transferStage != transferStage0 || + dstat != data0 ) { + log_esp3d (" Command: %d Transfer: %d Data: %d", cmdStage, transferStage, _HEX( dstat )); + } +#endif +} + +void FtpServer::clientConnected() +{ + log_esp3d(" Client connected!"); + client << F("220--- Welcome to FTP for ESP3D ---") << eol; + client << F("220 -- Version ") << FW_VERSION << F(" --") << eol; + iCL = 0; +} + +bool FtpServer::isUser(const char * user) +{ + log_esp3d("Check User"); + _currentUser = ""; +#ifdef AUTHENTICATION_FEATURE + if ((user != nullptr) && ((strcmp(user, DEFAULT_ADMIN_LOGIN) == 0) || (strcmp(user, DEFAULT_USER_LOGIN) == 0)) { + _currentUser = user; + return true; +} +return false; +#endif //AUTHENTICATION_FEATURE + (void)user; + _currentUser = DEFAULT_ADMIN_LOGIN; + log_esp3d("User is %s",_currentUser.c_str()); + return true; + +} +bool FtpServer::isPassword(const char * password) +{ + log_esp3d("Check Password"); +#ifdef AUTHENTICATION_FEATURE + if(((_currentUser == DEFAULT_ADMIN_LOGIN) && AuthenticationService::isadmin(password)) || + ((_currentUser == DEFAULT_USER_LOGIN) && AuthenticationService::isuser(password))) { + log_esp3d("Password ok"); + return true; + } + return false; +#endif //AUTHENTICATION_FEATURE + (void)password; + log_esp3d("Password ok"); + return true; +} + +void FtpServer::disconnectClient() +{ + log_esp3d(" Disconnecting client"); + abortTransfer(); + client << F("221 Goodbye") << eol; + client.stop(); + _currentUser = ""; +} + +bool FtpServer::processCommand() +{ + /////////////////////////////////////// + // // + // AUTHENTICATION COMMANDS // + // // + /////////////////////////////////////// + + // + // USER - User Identity + // + if( CommandIs( "USER" )) { + log_esp3d("USER : Command: %s Param: %s", command, (parameter == nullptr)?"":parameter); + if( isUser(parameter)) { + client << F("331 Ok. Password required") << eol; + strcpy( cwdName, "/" ); + cmdStage = FTP_Pass; + } else { + log_esp3d("Error USER"); + client << F("530 ") << eol; + cmdStage = FTP_Stop; + } + } + // + // PASS - Password + // + else if( CommandIs( "PASS" )) { + log_esp3d("PASS : Command: %s Param: %s", command, (parameter == nullptr)?"":parameter); + if( cmdStage != FTP_Pass ) { + log_esp3d("Error PASS"); + client << F("503 ") << eol; + cmdStage = FTP_Stop; + } + if( isPassword(parameter)) { + log_esp3d(" Authentication Ok. Waiting for commands."); + client << F("230 Ok") << eol; + cmdStage = FTP_Cmd; + } else { + log_esp3d("Wrong PASS"); + client << F("530 ") << eol; + cmdStage = FTP_Stop; + } + } + // + // FEAT - New Features + // + else if( CommandIs( "FEAT" )) { + client << F("211-Extensions suported:") << eol; + client << F(" MLST type*;modify*;size*;") << eol; + client << F(" MLSD") << eol; + client << F(" MDTM") << eol; + client << F(" MFMT") << eol; + client << F(" SIZE") << eol; + client << F(" SITE FREE") << eol; + client << F("211 End.") << eol; + } + // + // AUTH - Not implemented + // + else if( CommandIs( "AUTH" )) { + client << F("502 ") << eol; + } + // + // OPTS / SYST - Not implemented + // + else if((cmdStage < FTP_Cmd) && ( CommandIs( "OPTS" ) || CommandIs( "SYST" ) || CommandIs( "TYPE" ))) { + log_esp3d("Unsupported Command: %s Param: %s stage %d", command, (parameter == nullptr)?"":parameter, cmdStage); + client << F("500 ") << eol; + cmdStage = FTP_User; + } + // + // Unrecognized commands at stage of authentication + // + else if(cmdStage < FTP_Cmd) { + log_esp3d("Unknow Command: %s Param: %s stage %d", command, (parameter == nullptr)?"":parameter, cmdStage); + client << F("200 ") << eol; + cmdStage = FTP_Stop; + } + + /////////////////////////////////////// + // // + // ACCESS CONTROL COMMANDS // + // // + /////////////////////////////////////// + + // + // PWD - Print Directory + // + else if( CommandIs( "PWD" ) || + ( CommandIs( "CWD" ) && ParameterIs( "." ))) { + client << F("257 \"") << cwdName << F("\"") << F(" is your current directory") << eol; + } + // + // CDUP - Change to Parent Directory + // + else if( CommandIs( "CDUP" ) || + ( CommandIs( "CWD" ) && ParameterIs( ".." ))) { + bool ok = false; + + if( strlen( cwdName ) > 1 ) { // do nothing if cwdName is root + // if cwdName ends with '/', remove it (must not append) + if( cwdName[ strlen( cwdName ) - 1 ] == '/' ) { + cwdName[ strlen( cwdName ) - 1 ] = 0; + } + // search last '/' + char * pSep = strrchr( cwdName, '/' ); + ok = pSep > cwdName; + // if found, ends the string on its position + if( ok ) { + * pSep = 0; + ok = FTPFS::exists( cwdName ); + } + } + // if an error appends, move to root + if( ! ok ) { + strcpy( cwdName, "/" ); + } + client << F("250 Ok. Current directory is ") << cwdName << eol; + } + // + // CWD - Change Working Directory + // + else if( CommandIs( "CWD" )) { + char path[ FTP_CWD_SIZE ]; + if( haveParameter() && makeExistsPath( path )) { + strcpy( cwdName, path ); + client << F("250 Directory changed to ") << cwdName << eol; + } + } + // + // QUIT + // + else if( CommandIs( "QUIT" )) { + log_esp3d("QUIT"); + client << F("221 Goodbye") << eol; + disconnectClient(); + cmdStage = FTP_Stop; + } + + /////////////////////////////////////// + // // + // TRANSFER PARAMETER COMMANDS // + // // + /////////////////////////////////////// + + // + // MODE - Transfer Mode + // + else if( CommandIs( "MODE" )) { + if( ParameterIs( "S" )) { + client << F("200 S Ok") << eol; + } else { + client << F("504 Only S(tream) is suported") << eol; + } + } + // + // PASV - Passive Connection management + // + else if( CommandIs( "PASV" )) { + data.stop(); + dataServer->begin(); + dataIp.fromString(NetConfig::localIP()); + dataPort = passivePort; + log_esp3d(" Connection management set to passive"); + log_esp3d(" Data port set to %d", dataPort); + client << F("227 Entering Passive Mode") << F(" (") + << dataIp[0] << F(",") << dataIp[1] << F(",") + << dataIp[2] << F(",") << dataIp[3] << F(",") + << ( dataPort >> 8 ) << F(",") << ( dataPort & 255 ) << F(")") << eol; + dataConn = FTP_Pasive; + } + // + // PORT - Data Port + // + else if( CommandIs( "PORT" )) { + data.stop(); + // get IP of data client + dataIp[ 0 ] = atoi( parameter ); + char * p = strchr( parameter, ',' ); + for( uint8_t i = 1; i < 4; i ++ ) { + dataIp[ i ] = atoi( ++ p ); + p = strchr( p, ',' ); + } + // get port of data client + dataPort = 256 * atoi( ++ p ); + p = strchr( p, ',' ); + dataPort += atoi( ++ p ); + if( p == NULL ) { + client << F("501 Can't interpret parameters") << eol; + } else { + log_esp3d(" Data IP set to %s", dataIp.toString().c_str()); + log_esp3d(" Data port set to %d", dataPort); + client << F("200 PORT command successful") << eol; + dataConn = FTP_Active; + } + } + // + // STRU - File Structure + // + else if( CommandIs( "STRU" )) { + if( ParameterIs( "F" )) { + client << F("200 F Ok") << eol; + } + // else if( ParameterIs( "R" )) + // client << F("200 B Ok") << eol; + else { + client << F("504 Only F(ile) is suported") << eol; + } + } + // + // TYPE - Data Type + // + else if( CommandIs( "TYPE" )) { + if( ParameterIs( "A" )) { + client << F("200 TYPE is now ASCII") << eol; + } else if( ParameterIs( "I" )) { + client << F("200 TYPE is now 8-bit binary") << eol; + } else { + client << F("504 Unknow TYPE") << eol; + } + } + + /////////////////////////////////////// + // // + // FTP SERVICE COMMANDS // + // // + /////////////////////////////////////// + + // + // ABOR - Abort + // + else if( CommandIs( "ABOR" )) { + abortTransfer(); + client << F("226 Data connection closed") << eol; + } + // + // DELE - Delete a File + // + else if( CommandIs( "DELE" )) { + char path[ FTP_CWD_SIZE ]; + if(haveParameter() && makeExistsPath( path )) { + if( FTPFS::remove( path )) { + client << F("250 Deleted ") << parameter << eol; + } else { + client << F("450 Can't delete ") << parameter << eol; + } + } + } + // + // LIST - List + // NLST - Name List + // MLSD - Listing for Machine Processing (see RFC 3659) + // + else if( CommandIs( "LIST" ) || CommandIs( "NLST" ) || CommandIs( "MLSD" )) { + if( dataConnect()) { + dir = FTPFS::open(cwdName); + } + if (dir) { + nbMatch = 0; + if( CommandIs( "LIST" )) { + transferStage = FTP_List; + } else if( CommandIs( "NLST" )) { + transferStage = FTP_Nlst; + } else { + transferStage = FTP_Mlsd; + } + } else { + client << F("550 Can't open directory ") << cwdName << eol; + data.stop(); + } + } + // + // MLST - Listing for Machine Processing (see RFC 3659) + // + else if( CommandIs( "MLST" )) { + char path[ FTP_CWD_SIZE ]; + time_t t = 0; + char dtStr[ 15 ]; + bool isdir = false; + if( haveParameter() && makeExistsPath( path )) { + if( ! getFileModTime( path, t )) { + client << F("550 Unable to retrieve time for ") << parameter << eol; + } else { + if( file = FTPFS::open(path)) { + isdir = file.isDirectory(); + t = file.getLastWrite(); + file.close(); + } + client << F("250-Begin") << eol + << F(" Type=") << ( isdir ? F("dir") : F("file")) + << F(";Modify=") << makeDateTimeStr( dtStr, t ); + if( ! isdir ) { + client << F(";Size=") << file.size(); + } + client << F("; ") << path << eol + << F("250 End.") << eol; + } + } + } + // + // NOOP + // + else if( CommandIs( "NOOP" )) { + client << F("200 Zzz...") << eol; + } + // + // RETR - Retrieve + // + else if( CommandIs( "RETR" )) { + char path[ FTP_CWD_SIZE ]; + if( haveParameter() && makeExistsPath( path )) { + file = FTPFS::open(path); + if( ! file.isOpen()) { + client << F("450 Can't open ") << parameter << eol; + } else if( dataConnect( false )) { + log_esp3d(" Sending %s", parameter); + client << F("150-Connected to port ") << dataPort << eol; + client << F("150 ") << file.size() << F(" bytes to download") << eol; + millisBeginTrans = millis(); + bytesTransfered = 0; + transferStage = FTP_Retrieve; + } + } + } + // + // STOR - Store + // APPE - Append + // + else if( CommandIs( "STOR" ) || CommandIs( "APPE" )) { + char path[ FTP_CWD_SIZE ]; + if( haveParameter() && makePath( path )) { + if( FTPFS::exists( path )) { + file = FTPFS::open( path, ESP_FILE_WRITE | ( CommandIs( "APPE" ) ? ESP_FILE_APPEND : ESP_FILE_WRITE )); + } else { + file = FTPFS::open( path, ESP_FILE_WRITE ); + } + if( ! file.isOpen() ) { + client << F("451 Can't open/create ") << parameter << eol; + } else if( ! dataConnect()) { + file.close(); + } else { + log_esp3d(" Receiving %s", parameter); + millisBeginTrans = millis(); + bytesTransfered = 0; + transferStage = FTP_Store; + } + } + } + // + // MKD - Make Directory + // + else if( CommandIs( "MKD" ) || CommandIs( "XMKD" )) { + char path[ FTP_CWD_SIZE ]; + if( haveParameter() && makePath( path )) { + if( FTPFS::exists( path )) { + client << F("521 \"") << parameter << F("\" directory already exists") << eol; + } else { + log_esp3d(" Creating directory %s", parameter); + if( FTPFS::mkdir( path )) { + client << F("257 \"") << parameter << F("\"") << F(" created") << eol; + } else { + client << F("550 Can't create \"") << parameter << F("\"") << eol; + } + } + } + } + // + // RMD - Remove a Directory + // + else if( CommandIs( "RMD" ) || CommandIs( "XRMD" )) { + char path[ FTP_CWD_SIZE ]; + if( haveParameter() && makeExistsPath( path )) { + if( FTPFS::rmdir( path )) { + log_esp3d(" Deleting %s", path); + client << F("250 \"") << parameter << F("\" deleted") << eol; + } else { + client << F("550 Can't remove \"") << parameter << F("\". Directory not empty?") << eol; + } + } + } + // + // RNFR - Rename From + // + else if( CommandIs( "RNFR" )) { + rnfrName[ 0 ] = 0; + if( haveParameter() && makeExistsPath( rnfrName )) { + log_esp3d(" Ready for renaming %s", rnfrName); + client << F("350 RNFR accepted - file exists, ready for destination") << eol; + rnfrCmd = true; + } + } + // + // RNTO - Rename To + // + else if( CommandIs( "RNTO" )) { + char path[ FTP_CWD_SIZE ]; + char dirp[ FTP_FIL_SIZE ]; + if( strlen( rnfrName ) == 0 || ! rnfrCmd ) { + client << F("503 Need RNFR before RNTO") << eol; + } else if( haveParameter() && makePath( path )) { + if( FTPFS::exists( path )) { + client << F("553 ") << parameter << F(" already exists") << eol; + } else { + strcpy( dirp, path ); + char * psep = strrchr( dirp, '/' ); + bool fail = psep == NULL; + if( ! fail ) { + if( psep == dirp ) { + psep ++; + } + * psep = 0; + FTPFile f = FTPFS::open( dirp ); + f.close(); + fail = ! f.isDirectory(); + if( fail ) { + client << F("550 \"") << dirp << F("\" is not directory") << eol; + } else { + log_esp3d(" Renaming %s to %s", rnfrName, path); + if( FTPFS::rename( rnfrName, path )) { + client << F("250 File successfully renamed or moved") << eol; + } else { + fail = true; + } + } + } + if( fail ) { + client << F("451 Rename/move failure") << eol; + } + } + } + rnfrCmd = false; + } + + // + // SYST - System + // + else if( CommandIs( "SYST" )) { + client << F("215 ESP3D") << eol; + } + + + /////////////////////////////////////// + // // + // EXTENSIONS COMMANDS (RFC 3659) // + // // + /////////////////////////////////////// + + // + // MDTM && MFMT - File Modification Time (see RFC 3659) + // + else if( CommandIs( "MDTM" ) || CommandIs( "MFMT" )) { + if( haveParameter()) { + char path[ FTP_CWD_SIZE ]; + char * fname = parameter; + uint16_t year; + uint8_t month, day, hour, minute, second, setTime; + char dt[ 15 ]; + bool mdtm = CommandIs( "MDTM" ); + + setTime = getDateTime( dt, & year, & month, & day, & hour, & minute, & second ); + // fname point to file name + fname += setTime; + if( strlen( fname ) <= 0 ) { + client << "501 No file name" << eol; + } else if( makeExistsPath( path, fname )) { + if( setTime ) { // set file modification time + if( timeStamp( path, year, month, day, hour, minute, second )) { + client << "213 " << dt << eol; + } else { + client << "550 Unable to modify time" << eol; + } + } else if( mdtm ) { // get file modification time + time_t t = 0; + char dtStr[ 15 ]; + //TODO: add date time support + if( getFileModTime( path, t)) { + client << "213 " << makeDateTimeStr( dtStr, t ) << eol; + } else { + client << "550 Unable to retrieve time" << eol; + } + } + } + } + } + // + // SIZE - Size of the file + // + else if( CommandIs( "SIZE" )) { + char path[ FTP_CWD_SIZE ]; + if( haveParameter() && makeExistsPath( path )) { + file = FTPFS::open( path ); + } + if( ! file.isOpen()) { + client << F("450 Can't open ") << parameter << eol; + } else { + client << F("213 ") << file.size() << eol; + file.close(); + } + } + // + // SITE - System command + // + else if( CommandIs( "SITE" )) { + if( ParameterIs( "FREE" )) { +#if FTP_FEATURE == FS_ROOT + uint8_t fs = FTPFS::getFSType(cwdName); + uint64_t capacity = FTPFS::totalBytes(fs); + uint64_t free = FTPFS::freeBytes(fs); +#else +#if FTP_FEATURE == FS_FLASH + size_t capacity; + size_t free; +#endif +#if FTP_FEATURE == FS_SD + uint64_t capacity; + uint64_t free; +#endif + + capacity = FTPFS::totalBytes(); + free = FTPFS::freeBytes(); +#endif + client << F("200 ") << FTPFS::formatBytes(free) << F(" free of ") + << FTPFS::formatBytes(capacity) << F(" capacity") << eol; + } else { + client << F("500 Unknow SITE command ") << parameter << eol; + } + } + // + // Unrecognized commands ... + // + else { + client << F("500 Unknow command") << eol; + } + return true; +} + +int FtpServer::dataConnect( bool out150 ) +{ + if( ! data.connected()) { + if( dataConn == FTP_Pasive ) { + uint16_t count = 1000; // wait up to a second + while( ! data.connected() && count -- > 0 ) { + if( dataServer->hasClient()) { + data.stop(); + data = dataServer->available(); + } + delay( 1 ); + } + } else if( dataConn == FTP_Active ) { + data.connect( dataIp, dataPort ); + } + } + if( ! data.connected()) { + client << F("425 No data connection") << eol; + } else if( out150 ) { + client << F("150 Accepted data connection to port ") << dataPort << eol; + } + + return data.connected(); +} + +bool FtpServer::dataConnected() +{ + if( data.connected()) { + return true; + } + data.stop(); + client << F("426 Data connection closed. Transfer aborted") << eol; + transferStage = FTP_Close; + return false; +} + +bool FtpServer::doRetrieve() +{ + if( ! dataConnected()) { + file.close(); + return false; + } + int16_t nb = file.read( buf, FTP_BUF_SIZE ); + if( nb > 0 ) { + data.write( buf, nb ); + bytesTransfered += nb; + return true; + } + closeTransfer(); + return false; +} + +bool FtpServer::doStore() +{ + int16_t na = data.available(); + if( na == 0 ) { + if( data.connected()) { + return true; + } else { + closeTransfer(); + return false; + } + } + if( na > FTP_BUF_SIZE ) { + na = FTP_BUF_SIZE; + } + int16_t nb = data.read((uint8_t *) buf, na ); + int16_t rc = 0; + if( nb > 0 ) { + rc = file.write( buf, nb ); + bytesTransfered += nb; + } + if( nb < 0 || rc == nb ) { + return true; + } + client << F("552 Probably insufficient storage space") << eol; + file.close(); + data.stop(); + return false; +} + +bool FtpServer::doList() +{ + if( ! dataConnected()) { + dir.close(); + return false; + } + if (dir) { + if (file) { + file.close(); + } + file = dir.openNextFile(); + if (file) { + time_t t = file.getLastWrite(); + char dtStr[ 15 ]; + data << (file.isDirectory()?"d":"-") << "rwxrwxrwx 1 " << _currentUser.c_str() << " " << _currentUser.c_str(); + String s = String(file.size()); + for(uint i = 0; i < SIZELISTPADING - s.length(); i++) { + data << " "; + } + data << file.size() << " " << makeDateTimeString(dtStr,t) << " " << file.name() << eol; + nbMatch ++; + file.close(); + return true; + } + } + client << F("226 ") << nbMatch << F(" matches total") << eol; + dir.close(); + data.stop(); + return false; +} + +bool FtpServer::doMlsd() +{ + if( ! dataConnected()) { + dir.close(); + return false; + } + if (dir) { + if(file) { + file.close(); + } + file = dir.openNextFile(); + if (file) { + char dtStr[ 15 ]; + time_t t = file.getLastWrite(); + data << "Type=" << ( file.isDirectory() ? F("dir") : F("file")) << ";Size=" << file.size() << ";Modify=" << makeDateTimeStr( dtStr, t) << "; " << file.name() << eol; + log_esp3d("%s %u %s %s", file.isDirectory() ? "dir" : "file", file.size(), makeDateTimeStr( dtStr, t), file.name()); + file.close(); + nbMatch ++; + return true; + } + } + client << F("226-options: -a -l") << eol; + client << F("226 ") << nbMatch << F(" matches total") << eol; + dir.close(); + data.stop(); + return false; +} + +void FtpServer::closeTransfer() +{ + uint32_t deltaT = (int32_t) ( millis() - millisBeginTrans ); + if( deltaT > 0 && bytesTransfered > 0 ) { + log_esp3d(" Transfer completed in %d ms, %f kbytes/s", deltaT, 1.0*bytesTransfered / deltaT); + client << F("226-File successfully transferred") << eol; + client << F("226 ") << deltaT << F(" ms, ") + << bytesTransfered / deltaT << F(" kbytes/s") << eol; + } else { + client << F("226 File successfully transferred") << eol; + } + + file.close(); + data.stop(); +} + +void FtpServer::abortTransfer() +{ + if( transferStage != FTP_Close ) { + file.close(); + dir.close(); + client << F("426 Transfer aborted") << eol; + log_esp3d(" Transfer aborted!"); + transferStage = FTP_Close; + } +// if( data.connected()) + data.stop(); +} + +// Read a char from client connected to ftp server +// +// update cmdLine and command buffers, iCL and parameter pointers +// +// return: +// -2 if buffer cmdLine is full +// -1 if line not completed +// 0 if empty line received +// length of cmdLine (positive) if no empty line received + +int8_t FtpServer::readChar() +{ + int8_t rc = -1; + + if( client.available()) { + char c = client.read(); + log_esp3d("read %c", c); + if( c == '\\' ) { + c = '/'; + } + if( c != '\r' ) { + if( c != '\n' ) { + if( iCL < FTP_CMD_SIZE ) { + cmdLine[ iCL ++ ] = c; + } else { + rc = -2; // Line too long + } + } else { + cmdLine[ iCL ] = 0; + command[ 0 ] = 0; + parameter = NULL; + // empty line? + if( iCL == 0 ) { + rc = 0; + } else { + rc = iCL; + // search for space between command and parameter + parameter = strchr( cmdLine, ' ' ); + if( parameter != NULL ) { + if( parameter - cmdLine > 4 ) { + rc = -2; // Syntax error + } else { + strncpy( command, cmdLine, parameter - cmdLine ); + command[ parameter - cmdLine ] = 0; + while( * ( ++ parameter ) == ' ' ) + ; + } + } else if( strlen( cmdLine ) > 4 ) { + rc = -2; // Syntax error. + } else { + strcpy( command, cmdLine ); + } + iCL = 0; + } + } + } + if( rc > 0 ) + for( uint8_t i = 0 ; i < strlen( command ); i ++ ) { + command[ i ] = toupper( command[ i ] ); + } + if( rc == -2 ) { + iCL = 0; + client << F("500 Syntax error") << eol; + } + } + return rc; +} + +bool FtpServer::haveParameter() +{ + if( parameter != NULL && strlen( parameter ) > 0 ) { + return true; + } + client << "501 No file name" << eol; + return false; +} + +// Make complete path/name from cwdName and param +// +// 3 possible cases: parameter can be absolute path, relative path or only the name +// +// parameter: +// fullName : where to store the path/name +// +// return: +// true, if done + +bool FtpServer::makePath( char * fullName, char * param ) +{ + if( param == NULL ) { + param = parameter; + } + + // Root or empty? + if( strcmp( param, "/" ) == 0 || strlen( param ) == 0 ) { + strcpy( fullName, "/" ); + return true; + } + // If relative path, concatenate with current dir + if( param[0] != '/' ) { + strcpy( fullName, cwdName ); + if( fullName[ strlen( fullName ) - 1 ] != '/' ) { + strncat( fullName, "/", FTP_CWD_SIZE ); + } + strncat( fullName, param, FTP_CWD_SIZE ); + } else { + strcpy( fullName, param ); + } + // If ends with '/', remove it + uint16_t strl = strlen( fullName ) - 1; + if( fullName[ strl ] == '/' && strl > 1 ) { + fullName[ strl ] = 0; + } + if( strlen( fullName ) >= FTP_CWD_SIZE ) { + client << F("500 Command line too long") << eol; + return false; + } + for( uint8_t i = 0; i < strlen( fullName ); i ++ ) + if( ! legalChar( fullName[i])) { + client << F("553 File name not allowed") << eol; + return false; + } + return true; +} + +bool FtpServer::makeExistsPath( char * path, char * param ) +{ + if( ! makePath( path, param )) { + return false; + } + if( FTPFS::exists( path )) { + return true; + } + client << F("550 ") << path << F(" not found.") << eol; + return false; +} + +// Calculate year, month, day, hour, minute and second +// from first parameter sent by MDTM command (YYYYMMDDHHMMSS) +// Accept longer parameter YYYYMMDDHHMMSSmmm where mmm are milliseconds +// but don't take in account additional digits +// +// parameters: +// dt: 15 length string for 14 digits and terminator +// pyear, pmonth, pday, phour, pminute and psecond: pointer of +// variables where to store data +// +// return: +// 0 if parameter is not YYYYMMDDHHMMSS +// length of parameter + space +// +// Date/time are expressed as a 14 digits long string +// terminated by a space and followed by name of file + +uint8_t FtpServer::getDateTime( char * dt, uint16_t * pyear, uint8_t * pmonth, uint8_t * pday, + uint8_t * phour, uint8_t * pminute, uint8_t * psecond ) +{ + uint8_t i; + dt[ 0 ] = 0; + if( strlen( parameter ) < 15 ) { //|| parameter[ 14 ] != ' ' ) + return 0; + } + for( i = 0; i < 14; i ++ ) + if( ! isdigit( parameter[ i ])) { + return 0; + } + for( i = 14; i < 18; i ++ ) + if( parameter[ i ] == ' ' ) { + break; + } else if( ! isdigit( parameter[ i ])) { + return 0; + } + if( i == 18 ) { + return 0; + } + i ++ ; + + strncpy( dt, parameter, 14 ); + dt[ 14 ] = 0; + * psecond = atoi( dt + 12 ); + dt[ 12 ] = 0; + * pminute = atoi( dt + 10 ); + dt[ 10 ] = 0; + * phour = atoi( dt + 8 ); + dt[ 8 ] = 0; + * pday = atoi( dt + 6 ); + dt[ 6 ] = 0 ; + * pmonth = atoi( dt + 4 ); + dt[ 4 ] = 0 ; + * pyear = atoi( dt ); + strncpy( dt, parameter, 14 ); + log_esp3d(" Modification time: %d/%d/%d %d:%d:%d of file: %s", * pyear, * pmonth, * pday, * phour, * pminute, * psecond, (char *) ( parameter + i )); + return i; +} + +// Create string YYYYMMDDHHMMSS from time_t +// +// parameters: +// time_t +// tstr: where to store the string. Must be at least 15 characters long +// +// return: +// pointer to tstr + +char * FtpServer::makeDateTimeStr( char * tstr, time_t timefile ) +{ + struct tm * tmstruct = localtime(&timefile); + sprintf( tstr, "%04u%02u%02u%02u%02u%02u",(tmstruct->tm_year)+1900,(tmstruct->tm_mon)+1, tmstruct->tm_mday, tmstruct->tm_hour, tmstruct->tm_min, tmstruct->tm_sec); + return tstr; +} + +// Create string MMM DD YYYY or MMM DD HH:MM from time_t +// +// parameters: +// time_t +// tstr: where to store the string. Must be at least 13 characters long +// +// return: +// pointer to tstr + +char * FtpServer::makeDateTimeString( char * tstr, time_t timefile ) +{ + struct tm * tmstruct = localtime(&timefile); + time_t now; + time(&now); + struct tm tmstructnow; + localtime_r(&now, &tmstructnow); + if ((tmstruct->tm_year == tmstructnow.tm_year) && (timefile != 0)) { + strftime (tstr, 13, "%b %d %R", tmstruct); + } else { + strftime (tstr, 13, "%b %d %Y", tmstruct); + } + return tstr; +} + + +bool FtpServer::getFileModTime(const char * path, time_t & t) +{ + FTPFile f = FTPFS::open(path); + if (f) { + t = f.getLastWrite(); + f.close(); + return true; + } + log_esp3d("Cannot get getLastWrite"); + t = 0; + return false; +} +//TODO +bool FtpServer::timeStamp( const char * path, uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second ) +{ + //Not available yet + return false; +} + +#endif //FTP_FEATURE diff --git a/esp3d/src/modules/ftp/FtpServer.h b/esp3d/src/modules/ftp/FtpServer.h new file mode 100644 index 00000000..adde04d6 --- /dev/null +++ b/esp3d/src/modules/ftp/FtpServer.h @@ -0,0 +1,160 @@ +/* + * FTP Serveur for Arduino Due or Mega 2580 + * and Ethernet shield W5100, W5200 or W5500 + * or for Esp8266 with external SD card or SpiFfs + * Copyright (c) 2014-2018 by Jean-Michel Gallego + * + * This program 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. + * + * This program 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 this program. If not, see . + */ +/* +* 2019-10-27 Modified version for ESP3D by Luc LEBOSSE @luc-github +* support for ESP8266 and ESP32 in ESP3D project +*/ + +/******************************************************************************* + ** ** + ** DEFINITIONS FOR FTP SERVER ** + ** ** + *******************************************************************************/ + +#ifndef FTP_SERVER_H +#define FTP_SERVER_H + +class WiFiServer; +class WiFiClient; +#ifndef FF_MAX_LFN +#define FF_MAX_LFN 255 +#endif +#define FTP_TIME_OUT 5 * 60 // Disconnect client after 5 minutes of inactivity +#define FTP_AUTH_TIME_OUT 10 // Wait for authentication for 10 seconds +#define FTP_CMD_SIZE FF_MAX_LFN+8 // max size of a command +#define FTP_CWD_SIZE FF_MAX_LFN+8 // max size of a directory name +#define FTP_FIL_SIZE FF_MAX_LFN // max size of a file name +#define FTP_BUF_SIZE 1024 // 512 // size of file buffer for read/write + +#define FTP_SERVER WiFiServer +#define FTP_CLIENT WiFiClient +#define CommandIs( a ) (command != NULL && ! strcmp_P( command, PSTR( a ))) +#define ParameterIs( a ) ( parameter != NULL && ! strcmp_P( parameter, PSTR( a ))) +#include + +enum ftpCmd { FTP_Stop = 0, // In this stage, stop any connection + FTP_Init, // initialize some variables + FTP_Client, // wait for client connection + FTP_User, // wait for user name + FTP_Pass, // wait for user password + FTP_Cmd + }; // answers to commands + +enum ftpTransfer { FTP_Close = 0, // In this stage, close data channel + FTP_Retrieve, // retrieve file + FTP_Store, // store file + FTP_List, // list of files + FTP_Nlst, // list of name of files + FTP_Mlsd + }; // listing for machine processing + +enum ftpDataConn { FTP_NoConn = 0,// No data connexion + FTP_Pasive, // Pasive type + FTP_Active + }; // Active type + +class FtpServer +{ +public: + FtpServer(); + ~FtpServer(); + bool begin(); + void handle(); + void end(); + bool started(); + uint16_t ctrlport() + { + return ctrlPort; + } + uint16_t datapassiveport() + { + return passivePort; + } + uint16_t dataactiveport() + { + return activePort; + } + void closeClient(); + bool isConnected(); + const char* clientIPAddress(); + bool isUser(const char * user); + bool isPassword(const char * password); +private: + void iniVariables(); + void clientConnected(); + void disconnectClient(); + bool processCommand(); + bool haveParameter(); + int dataConnect( bool out150 = true ); + bool dataConnected(); + bool doRetrieve(); + bool doStore(); + bool doList(); + bool doMlsd(); + void closeTransfer(); + void abortTransfer(); + bool makePath( char * fullName, char * param = NULL ); + bool makeExistsPath( char * path, char * param = NULL ); + char * makeDateTimeStr( char * tstr, time_t timefile ); + char * makeDateTimeString( char * tstr, time_t timefile ); + uint8_t getDateTime( char * dt, uint16_t * pyear, uint8_t * pmonth, uint8_t * pday, + uint8_t * phour, uint8_t * pminute, uint8_t * second ); + + bool getFileModTime(const char * path,time_t & time); + bool timeStamp( const char * path, uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second ); + int8_t readChar(); + + FTP_SERVER * ftpServer; + FTP_SERVER * dataServer; + uint16_t ctrlPort; // Command port on wich server is listening + uint16_t activePort; // Default data port in active mode + uint16_t passivePort; // Data port in passive mode + bool _started; + uint8_t _root; + IPAddress dataIp; // IP address of client for data + FTP_CLIENT client; + FTP_CLIENT data; + + ftpCmd cmdStage; // stage of ftp command connexion + ftpTransfer transferStage; // stage of data connexion + ftpDataConn dataConn; // type of data connexion + + // uint8_t __attribute__((packed, aligned(4))) // need to be aligned to 32bit for Esp8266 SPIClass::transferBytes() + uint8_t buf[ FTP_BUF_SIZE ]; // data buffer for transfers + char cmdLine[ FTP_CMD_SIZE ]; // where to store incoming char from client + char cwdName[ FTP_CWD_SIZE ]; // name of current directory + char rnfrName[ FTP_CWD_SIZE ]; // name of file for RNFR command + char command[ 5 ]; // command sent by client + bool rnfrCmd; // previous command was RNFR + char * parameter; // point to begin of parameters sent by client + uint16_t dataPort; + uint16_t iCL; // pointer to cmdLine next incoming char + uint16_t nbMatch; + + uint32_t millisDelay, // + millisEndConnection, // + millisBeginTrans, // store time of beginning of a transaction + bytesTransfered; // + String _currentUser; +}; + +extern FtpServer ftp_server; + +#endif // FTP_SERVER_H diff --git a/esp3d/src/modules/ftp/ftp_server.cpp b/esp3d/src/modules/ftp/ftp_server.cpp deleted file mode 100644 index c4e0e2ba..00000000 --- a/esp3d/src/modules/ftp/ftp_server.cpp +++ /dev/null @@ -1,142 +0,0 @@ -/* - ftp_server.cpp - ftp server functions class - - Copyright (c) 2014 Luc Lebosse. All rights reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include "../../include/esp3d_config.h" - -#if defined (FTP_FEATURE) -#include "ftp_server.h" -#include "../../core/settings_esp3d.h" -#include "../../core/esp3doutput.h" - -Ftp_Server ftp_server; - - -void Ftp_Server::closeClient() -{ - /*if(_telnetClients) { - _telnetClients.stop(); - }*/ -} - -bool Ftp_Server::isConnected() -{ - return false; - /* - if ( !_started || _telnetserver == NULL) { - return false; - } - //check if there are any new clients - if (_telnetserver->hasClient()) { - //find free/disconnected spot - if (!_telnetClients || !_telnetClients.connected()) { - if(_telnetClients) { - _telnetClients.stop(); - } - _telnetClients = _telnetserver->available(); - //new client - } - } - if (_telnetserver->hasClient()) { - //no free/disconnected spot so reject - _telnetserver->available().stop(); - } - return _telnetClients.connected();*/ -} - -const char* Ftp_Server::clientIPAddress() -{ - static String res; - /*res = "0.0.0.0"; - if (_telnetClients && _telnetClients.connected()) { - res = _telnetClients.remoteIP().toString(); - }*/ - return res.c_str(); -} - - -Ftp_Server::Ftp_Server() -{ - _started = false; - _ctrlport = 0; - _dataactiveport = 0; - _datapassiveport = 0; -} -Ftp_Server::~Ftp_Server() -{ - end(); -} - -/** - * begin Telnet setup - */ -bool Ftp_Server::begin() -{ - end(); - if (Settings_ESP3D::read_byte(ESP_TELNET_ON) !=1) { - return true; - } - _ctrlport = Settings_ESP3D::read_uint32(ESP_FTP_CTRL_PORT); - _dataactiveport = Settings_ESP3D::read_uint32(ESP_FTP_DATA_ACTIVE_PORT); - _datapassiveport = Settings_ESP3D::read_uint32(ESP_FTP_DATA_PASSIVE_PORT); - _started = true; - //create instance - /* _telnetserver= new WiFiServer(_port); - if (!_telnetserver) { - return false; - } - _telnetserver->setNoDelay(true); - //start telnet server - _telnetserver->begin(); - _started = true; - _lastflush = millis();*/ - return _started; -} -/** - * End Telnet - */ -void Ftp_Server::end() -{ - _started = false; - _ctrlport = 0; - _dataactiveport = 0; - _datapassiveport = 0; -} - -/** - * Reset Telnet - */ -bool Ftp_Server::reset() -{ - //nothing to reset - return true; -} - -bool Ftp_Server::started() -{ - return _started; -} - -void Ftp_Server::handle() -{ - Hal::wait(0); - //TODO -} - -#endif //FTP_FEATURE diff --git a/esp3d/src/modules/ftp/ftp_server.h b/esp3d/src/modules/ftp/ftp_server.h deleted file mode 100644 index bdd2bdb3..00000000 --- a/esp3d/src/modules/ftp/ftp_server.h +++ /dev/null @@ -1,60 +0,0 @@ - -/* - ftp_server.h - ftp service functions class - - Copyright (c) 2014 Luc Lebosse. All rights reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _FTP_SERVER_H -#define _FTP_SERVER_H - -class Ftp_Server -{ -public: - Ftp_Server(); - ~Ftp_Server(); - bool begin(); - void end(); - void handle(); - bool reset(); - bool started(); - bool isConnected(); - const char* clientIPAddress(); - uint16_t ctrlport() - { - return _ctrlport; - } - uint16_t datapassiveport() - { - return _datapassiveport; - } - uint16_t dataactiveport() - { - return _dataactiveport; - } - void closeClient(); -private: - bool _started; - uint16_t _ctrlport; - uint16_t _dataactiveport; - uint16_t _datapassiveport; -}; - -extern Ftp_Server ftp_server; - -#endif - diff --git a/esp3d/src/modules/gcode_host/gcode_host.cpp b/esp3d/src/modules/gcode_host/gcode_host.cpp index 5c8ae251..f67a789c 100644 --- a/esp3d/src/modules/gcode_host/gcode_host.cpp +++ b/esp3d/src/modules/gcode_host/gcode_host.cpp @@ -270,7 +270,7 @@ uint32_t GcodeHost::Get_commandNumber(String & response) } int pos = response.indexOf(sresend); if (pos == -1 ) { - log_esp3d("Cannot find label", _error); + log_esp3d("Cannot find label %d", _error); return -1; } pos+=sresend.length(); diff --git a/esp3d/src/modules/network/netservices.cpp b/esp3d/src/modules/network/netservices.cpp index d3ece578..a1382d89 100644 --- a/esp3d/src/modules/network/netservices.cpp +++ b/esp3d/src/modules/network/netservices.cpp @@ -50,7 +50,7 @@ #include "../telnet/telnet_server.h" #endif //TELNET_FEATURE #ifdef FTP_FEATURE -#include "../ftp/ftp_server.h" +#include "../ftp/FtpServer.h" #endif //FP_FEATURE #ifdef HTTP_FEATURE #include "../http/http_server.h"