diff --git a/lib/SimpleFTPServer/FtpServer.cpp b/lib/SimpleFTPServer/FtpServer.cpp index 678197d9..7107c82b 100644 --- a/lib/SimpleFTPServer/FtpServer.cpp +++ b/lib/SimpleFTPServer/FtpServer.cpp @@ -8,8 +8,8 @@ * * * Use Ethernet library - * - * Commands implemented: + * + * Commands implemented: * USER, PASS, AUTH (AUTH only return 'not implemented' code) * CDUP, CWD, PWD, QUIT, NOOP * MODE, PASV, PORT, STRU, TYPE @@ -20,6 +20,7 @@ * MDTM, MFMT * FEAT, SIZE * SITE FREE + * HELP * * Tested with those clients: * under Windows: @@ -42,1583 +43,1724 @@ * Firefox * with a second Arduino and sketch of SurferTim at * http://playground.arduino.cc/Code/FTP - * + * */ #include -FtpServer::FtpServer(uint16_t _cmdPort, uint16_t _pasvPort) : ftpServer(_cmdPort), dataServer(_pasvPort) +FtpServer::FtpServer( uint16_t _cmdPort, uint16_t _pasvPort ) + : ftpServer( _cmdPort ), dataServer( _pasvPort ) { - cmdPort = _cmdPort; - pasvPort = _pasvPort; + cmdPort = _cmdPort; + pasvPort = _pasvPort; - millisDelay = 0; - nbMatch = 0; - iCL = 0; + millisDelay = 0; + nbMatch = 0; + iCL = 0; - iniVariables(); + iniVariables(); +} + +void FtpServer::begin( const char * _user, const char * _pass, const char * _welcomeMessage ) +{ + if ( strcmp( _user, "anonymous" ) != 0) { + DEBUG_PRINTLN(F("NOT ANONYMOUS")); + DEBUG_PRINTLN(_user); + this->anonymousConnection = false; // needed to reset after end of anonymnous and begin of not anonymous + } else { + this->anonymousConnection = true; + } + // Tells the ftp server to begin listening for incoming connection + ftpServer.begin(); + #if defined(ESP8266) || defined(ARDUINO_ARCH_RP2040) || FTP_SERVER_NETWORK_TYPE_SELECTED == NETWORK_SEEED_RTL8720DN + ftpServer.setNoDelay( true ); + #endif +// localIp = _localIP == FTP_NULLIP() || (uint32_t) _localIP == 0 ? NET_CLASS.localIP() : _localIP ; + localIp = NET_CLASS.localIP(); //_localIP == FTP_NULLIP() || (uint32_t) _localIP == 0 ? NET_CLASS.localIP() : _localIP ; +// strcpy( user, FTP_USER ); +// strcpy( pass, FTP_PASS ); + if( strlen( _user ) > 0 && strlen( _user ) < FTP_CRED_SIZE ) { + //strcpy( user, _user ); + this->user = _user; + } + if( strlen( _pass ) > 0 && strlen( _pass ) < FTP_CRED_SIZE ) { +// strcpy( pass, _pass ); + this->pass = _pass; + } +// strcpy(_welcomeMessage, welcomeMessage); + + this->welcomeMessage = _welcomeMessage; + + dataServer.begin(); +#if defined(ESP8266) || defined(ARDUINO_ARCH_RP2040) || FTP_SERVER_NETWORK_TYPE_SELECTED == NETWORK_SEEED_RTL8720DN + dataServer.setNoDelay( true ); +#endif + + millisDelay = 0; + cmdStage = FTP_Stop; + iniVariables(); +} + +void FtpServer::begin( const char * _welcomeMessage ) { + this->anonymousConnection = true; + this->begin( "anonymous", "anonymous", _welcomeMessage); } void FtpServer::end() { - DEBUG_PRINTLN(F("Stop server!")); - if(client.connected()) { - DEBUG_PRINTLN(F("Disconnect client!")); disconnectClient(); } +#if FTP_SERVER_NETWORK_TYPE == NETWORK_ESP32 && !defined(ARDUINO_ARCH_RP2040) ftpServer.end(); dataServer.end(); +#endif - cmdStage = FTP_Stop; + DEBUG_PRINTLN(F("Stop server!")); + + if (FtpServer::_callback) { + FtpServer::_callback(FTP_DISCONNECT, free(), capacity()); + } + + cmdStage = FTP_Init; transferStage = FTP_Close; - dataConn = FTP_NoConn; + dataConn = FTP_NoConn; } - -void FtpServer::begin(const char* _user, const char* _pass, const char* _welcomeMessage) +void FtpServer::setLocalIp(IPAddress localIp) { - // Tells the ftp server to begin listening for incoming connection - ftpServer.begin(); -#if defined(ESP8266) || FTP_SERVER_NETWORK_TYPE_SELECTED == NETWORK_SEEED_RTL8720DN - ftpServer.setNoDelay(true); -#endif - // localIp = _localIP == FTP_NULLIP() || (uint32_t) _localIP == 0 ? NET_CLASS.localIP() : _localIP ; - localIp = - NET_CLASS.localIP(); //_localIP == FTP_NULLIP() || (uint32_t) _localIP == 0 ? NET_CLASS.localIP() : _localIP ; - // strcpy( user, FTP_USER ); - // strcpy( pass, FTP_PASS ); - if(strlen(_user) > 0 && strlen(_user) < FTP_CRED_SIZE) { - // strcpy( user, _user ); - this->user = _user; - } else { - // strcpy( user, FTP_USER ); - this->user = FTP_USER; - } - if(strlen(_pass) > 0 && strlen(_pass) < FTP_CRED_SIZE) { - // strcpy( pass, _pass ); - this->pass = _pass; - } else { - // strcpy( pass, FTP_PASS ); - this->pass = FTP_PASS; - } - - // strcpy(_welcomeMessage, welcomeMessage); - - this->welcomeMessage = _welcomeMessage; - - dataServer.begin(); -#if defined(ESP8266) || FTP_SERVER_NETWORK_TYPE_SELECTED == NETWORK_SEEED_RTL8720DN - dataServer.setNoDelay(true); -#endif - - millisDelay = 0; - cmdStage = FTP_Stop; - iniVariables(); + this->localIp = localIp; } - -void FtpServer::credentials(const char* _user, const char* _pass) +void FtpServer::credentials( const char * _user, const char * _pass ) { - this->user = user; - this->pass = _pass; - - /* - if(strlen(_user) > 0 && strlen(_user) < FTP_CRED_SIZE) - // strcpy( user, _user ); - this->user = user; - if(strlen(_pass) > 0 && strlen(_pass) < FTP_CRED_SIZE) - // strcpy( pass, _pass ); - this->pass = _pass; */ + if( strlen( _user ) > 0 && strlen( _user ) < FTP_CRED_SIZE ) +// strcpy( user, _user ); + this->user = user; + if( strlen( _pass ) > 0 && strlen( _pass ) < FTP_CRED_SIZE ) +// strcpy( pass, _pass ); + this->pass = _pass; } void FtpServer::iniVariables() { - // Default for data port - dataPort = FTP_DATA_PORT_DFLT; + // Default for data port + dataPort = FTP_DATA_PORT_DFLT; + + // Default Data connection is Active + dataConn = FTP_NoConn; + + // Set the root directory + strcpy( cwdName, "/" ); - // Default Data connection is Active - dataConn = FTP_NoConn; - - // Set the root directory - strcpy(cwdName, "/"); - - rnfrCmd = false; - transferStage = FTP_Close; + rnfrCmd = false; + transferStage = FTP_Close; } -uint8_t FtpServer::handleFTP() -{ +uint8_t FtpServer::handleFTP() { #ifdef FTP_ADDITIONAL_DEBUG - // int8_t data0 = data.status(); - ftpTransfer transferStage0 = transferStage; - ftpCmd cmdStage0 = cmdStage; - ftpDataConn dataConn0 = dataConn; +// int8_t data0 = data.status(); + ftpTransfer transferStage0 = transferStage; + ftpCmd cmdStage0 = cmdStage; + ftpDataConn dataConn0 = dataConn; #endif - if((int32_t)(millisDelay - millis()) <= 0) { - if(cmdStage == FTP_Stop) { - if(client.connected()) { - DEBUG_PRINTLN(F("Disconnect client!")); - disconnectClient(); - } - cmdStage = FTP_Init; - } else if(cmdStage == FTP_Init) { // Ftp server waiting for connection - abortTransfer(); - iniVariables(); - DEBUG_PRINT(F(" Ftp server waiting for connection on port ")); - DEBUG_PRINTLN(cmdPort); + if ((int32_t) (millisDelay - millis()) <= 0) { + if (cmdStage == FTP_Stop) { + if (client.connected()) { + // DEBUG_PRINTLN(F("Disconnect client!")); + disconnectClient(); + } + cmdStage = FTP_Init; + } else if (cmdStage == FTP_Init) { // Ftp server waiting for connection + abortTransfer(); + iniVariables(); + DEBUG_PRINT(F("Server waiting for connection on port %d"),cmdPort); + // DEBUG_PRINTLN(cmdPort); - cmdStage = FTP_Client; - } else if(cmdStage == FTP_Client) { // Ftp server idle -#ifdef ESP8266 - if(ftpServer.hasClient()) { - client.stop(); - client = ftpServer.available(); - } + cmdStage = FTP_Client; + } else if (cmdStage == FTP_Client) { // Ftp server idle +#if (FTP_SERVER_NETWORK_TYPE == NETWORK_WiFiNINA) +// if (client && !client.connected()) { +// client.stop(); +// DEBUG_PRINTLN(F("CLIENT STOP!!")); +// } + byte status; + client = ftpServer.available(&status); + /* + * CLOSED = 0, + LISTEN = 1, + SYN_SENT = 2, + SYN_RCVD = 3, + ESTABLISHED = 4, + FIN_WAIT_1 = 5, + FIN_WAIT_2 = 6, + CLOSE_WAIT = 7, + CLOSING = 8, + LAST_ACK = 9, + TIME_WAIT = 10 + * + */ +// DEBUG_PRINTLN(status); +#elif defined(ESP8266) // || defined(ARDUINO_ARCH_RP2040) + if( ftpServer.hasClient()) + { + client.stop(); + client = ftpServer.available(); + } #else - if(client && !client.connected()) { - client.stop(); - DEBUG_PRINTLN(F("CLIENT STOP!!")); - } - client = ftpServer.accept(); + if (client && !client.connected()) { + client.stop(); + DEBUG_PRINTLN(F("CLIENT STOP!!")); + } + client = ftpServer.accept(); #endif - 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()) { - if(FtpServer::_callback) { - FtpServer::_callback(FTP_FREE_SPACE_CHANGE, free(), capacity()); - } + 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()) { + if (FtpServer::_callback) { + FtpServer::_callback(FTP_DISCONNECT, free(), capacity()); + } - 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()) { + cmdStage = FTP_Init; + } + if (transferStage == FTP_Retrieve) // Retrieve data + { + if (!doRetrieve()) { + transferStage = FTP_Close; + } + } else if (transferStage == FTP_Store) // Store data + { + if (!doStore()) { + if (FtpServer::_callback) { + FtpServer::_callback(FTP_FREE_SPACE_CHANGE, free(), capacity()); + } - transferStage = FTP_Close; - } - } else if(cmdStage > FTP_Client && !((int32_t)(millisEndConnection - millis()) > 0)) { - client.println(F("530 Timeout")); - millisDelay = millis() + 200; // delay of 200 ms - cmdStage = FTP_Stop; - } + 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.println(F("530 Timeout")); + millisDelay = millis() + 200; // delay of 200 ms + cmdStage = FTP_Stop; + } #ifdef FTP_ADDITIONAL_DEBUG - if(cmdStage != cmdStage0 || transferStage != transferStage0 || dataConn != dataConn0) { - DEBUG_PRINT(F(" Command Old: ")); - DEBUG_PRINT(cmdStage0); - DEBUG_PRINT(F(" Transfer Old: ")); - DEBUG_PRINT(transferStage0); - DEBUG_PRINT(F(" Data Old: ")); - DEBUG_PRINTLN(dataConn0); + if (cmdStage != cmdStage0 || transferStage != transferStage0 + || dataConn != dataConn0) { + DEBUG_PRINT(F(" Command Old: ")); + DEBUG_PRINT(cmdStage0); + DEBUG_PRINT(F(" Transfer Old: ")); + DEBUG_PRINT(transferStage0); + DEBUG_PRINT(F(" Data Old: ")); + DEBUG_PRINTLN(dataConn0); - DEBUG_PRINT(F(" Command : ")); - DEBUG_PRINT(cmdStage); - DEBUG_PRINT(F(" Transfer : ")); - DEBUG_PRINT(transferStage); - DEBUG_PRINT(F(" Data : ")); - DEBUG_PRINTLN(dataConn); - } + DEBUG_PRINT(F(" Command : ")); + DEBUG_PRINT(cmdStage); + DEBUG_PRINT(F(" Transfer : ")); + DEBUG_PRINT(transferStage); + DEBUG_PRINT(F(" Data : ")); + DEBUG_PRINTLN(dataConn); + } #endif - } - return cmdStage | (transferStage << 3) | (dataConn << 6); + } + return cmdStage | (transferStage << 3) | (dataConn << 6); } void FtpServer::clientConnected() { - DEBUG_PRINTLN(F(" Client connected!")); - client.print(F("220---")); - client.print(welcomeMessage); - client.println(F(" ---")); - client.println(F("220--- By Renzo Mischianti ---")); - client.print(F("220 -- Version ")); - client.print(FTP_SERVER_VERSION); - client.println(F(" --")); - iCL = 0; - if(FtpServer::_callback) { - FtpServer::_callback(FTP_CONNECT, free(), capacity()); - } + // DEBUG_PRINTLN( F(" Client connected!") ); + client.print(F("220 ---")); client.print(welcomeMessage); client.println(F(" ---")); + // client.print(F("220---")); client.print(welcomeMessage); client.println(F(" ---")); + // client.println(F("220--- By Renzo Mischianti ---")); + // client.print(F("220 -- Version ")); client.print(FTP_SERVER_VERSION); client.println(F(" --")); + iCL = 0; + if (FtpServer::_callback) { + FtpServer::_callback(FTP_CONNECT, free(), capacity()); + } + } void FtpServer::disconnectClient() { - DEBUG_PRINTLN(F(" Disconnecting client")); + // DEBUG_PRINTLN( F(" Disconnecting client") ); - abortTransfer(); - client.println(F("221 Goodbye")); + abortTransfer(); + client.println(F("221 Goodbye") ); - if(FtpServer::_callback) { - FtpServer::_callback(FTP_DISCONNECT, free(), capacity()); - } + if (FtpServer::_callback) { + FtpServer::_callback(FTP_DISCONNECT, free(), capacity()); + } - if(client) { - } - if(data) { - data.stop(); - } + if( client ) { + } + if( data ) { + data.stop(); + } } bool FtpServer::processCommand() { - /////////////////////////////////////// - // // - // AUTHENTICATION COMMANDS // - // // - /////////////////////////////////////// + /////////////////////////////////////// + // // + // AUTHENTICATION COMMANDS // + // // + /////////////////////////////////////// - // RoSchmi added the next two lines - DEBUG_PRINT("Command is: "); - DEBUG_PRINTLN(command); + // RoSchmi added the next two lines + // DEBUG_PRINT("Command is: "); + //DEBUG_PRINTLN(command); - // - // USER - User Identity - // - if(CommandIs("USER")) { - if(!strcmp(parameter, user)) { - client.println(F("331 Ok. Password required")); - strcpy(cwdName, "/"); - cmdStage = FTP_Pass; - } else { - client.println(F("530 ")); - cmdStage = FTP_Stop; - } + // + // USER - User Identity + // + if( CommandIs( "USER" )) + { + DEBUG_PRINT(F("USER: %s"),parameter); + // DEBUG_PRINT(parameter); + // DEBUG_PRINT(F(" ")); + // DEBUG_PRINTLN(user) + + if (this->anonymousConnection && ! strcmp( parameter, user )) { + DEBUG_PRINTLN( F("Anonymous authentication Ok. Waiting for commands.") ); + + client.println(F("230 Ok") ); + cmdStage = FTP_Cmd; + } else if( ! strcmp( parameter, user )) + { + client.println(F("331 Ok. Password required") ); + strcpy( cwdName, "/" ); + cmdStage = FTP_Pass; } - // - // PASS - Password - // - else if(CommandIs("PASS")) { - if(cmdStage != FTP_Pass) { - client.println(F("503 ")); - cmdStage = FTP_Stop; - } else if(!strcmp(parameter, pass)) { - DEBUG_PRINTLN(F(" Authentication Ok. Waiting for commands.")); - - client.println(F("230 Ok")); - cmdStage = FTP_Cmd; - } else if(!strcmp("anonymous", user)) { - DEBUG_PRINTLN(F(" Anonymous login. Waiting for commands.")); - - client.println(F("230 Ok")); - cmdStage = FTP_Cmd; - } else { - client.println(F("530 ")); - cmdStage = FTP_Stop; - } - } - // - // FEAT - New Features - // - else if(CommandIs("FEAT")) { - client.println(F("211-Extensions suported:")); - client.println(F(" MLST type*;modify*;size*;")); - client.println(F(" MLSD")); - client.println(F(" MDTM")); - client.println(F(" MFMT")); - client.println(F(" SIZE")); - client.println(F(" SITE FREE")); - client.println(F("211 End.")); - } - // - // AUTH - Not implemented - // - else if(CommandIs("AUTH")) - client.println(F("502 ")); - // - // Unrecognized commands at stage of authentication - // - else if(cmdStage < FTP_Cmd) { - client.println(F("530 ")); - cmdStage = FTP_Stop; - } - - /////////////////////////////////////// - // // - // ACCESS CONTROL COMMANDS // - // // - /////////////////////////////////////// - - // - // PWD - Print Directory - // - else if(CommandIs("PWD") || (CommandIs("CWD") && ParameterIs("."))) { - client.print(F("257 \"")); - client.print(cwdName); - client.print(F("\"")); - client.println(F(" is your current directory")); - // - // 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 = exists(cwdName); - } - } - // if an error appends, move to root - if(!ok) { - strcpy(cwdName, "/"); - } - client.print(F("250 Ok. Current directory is ")); - client.println(cwdName); - } - // - // CWD - Change Working Directory - // - else if(CommandIs("CWD")) { - char path[FTP_CWD_SIZE]; - if(haveParameter() && makeExistsPath(path)) { - strcpy(cwdName, path); - client.print(F("250 Directory changed to ")); - client.print(cwdName); - client.println(); - } - } - // - // QUIT - // - else if(CommandIs("QUIT")) { - client.println(F("221 Goodbye")); - disconnectClient(); - cmdStage = FTP_Stop; - } - - /////////////////////////////////////// - // // - // TRANSFER PARAMETER COMMANDS // - // // - /////////////////////////////////////// - - // - // MODE - Transfer Mode - // - else if(CommandIs("MODE")) { - if(ParameterIs("S")) { - client.println(F("200 S Ok")); - } else { - client.println(F("504 Only S(tream) is suported")); - } - } - // - // PASV - Passive Connection management - // - else if(CommandIs("PASV")) { - data.stop(); - dataServer.begin(); - if((((uint32_t)NET_CLASS.localIP()) & ((uint32_t)NET_CLASS.subnetMask())) == - (((uint32_t)client.remoteIP()) & ((uint32_t)NET_CLASS.subnetMask()))) { - if((uint32_t)localIp > 0) { - dataIp = localIp; // same subnet with manual IP set - } else { - dataIp = NET_CLASS.localIP(); // same subnet without manual IP set - } - } else { - dataIp = NET_CLASS.localIP(); // other subnet, no NAT - } - dataPort = pasvPort; - DEBUG_PRINTLN(F(" Connection management set to passive")); - DEBUG_PRINT(F(" Listening at ")); - DEBUG_PRINT(int(dataIp[0])); - DEBUG_PRINT(F(".")); - DEBUG_PRINT(int(dataIp[1])); - DEBUG_PRINT(F(".")); - DEBUG_PRINT(int(dataIp[2])); - DEBUG_PRINT(F(".")); - DEBUG_PRINT(int(dataIp[3])); - DEBUG_PRINT(F(":")); - DEBUG_PRINTLN(dataPort); - - client.print(F("227 Entering Passive Mode")); - client.print(F(" (")); - client.print(int(dataIp[0])); - client.print(F(",")); - client.print(int(dataIp[1])); - client.print(F(",")); - client.print(int(dataIp[2])); - client.print(F(",")); - client.print(int(dataIp[3])); - client.print(F(",")); - client.print((dataPort >> 8)); - client.print(F(",")); - client.print((dataPort & 255)); - client.println(F(")")); - 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.println(F("501 Can't interpret parameters")); - } else { - DEBUG_PRINT(F(" Data IP set to ")); - DEBUG_PRINT(int(dataIp[0])); - DEBUG_PRINT(F(".")); - DEBUG_PRINT(int(dataIp[1])); - DEBUG_PRINT(F(".")); - DEBUG_PRINT(int(dataIp[2])); - DEBUG_PRINT(F(".")); - DEBUG_PRINTLN(int(dataIp[3])); - DEBUG_PRINT(F(" Data port set to ")); - DEBUG_PRINTLN(dataPort); - - client.println(F("200 PORT command successful")); - dataConn = FTP_Active; - } - } - // - // STRU - File Structure - // - else if(CommandIs("STRU")) { - if(ParameterIs("F")) { - client.println(F("200 F Ok")); - // else if( ParameterIs( "R" )) - // client.println(F("200 B Ok") ); - } else { - client.println(F("504 Only F(ile) is suported")); - } - } - // - // TYPE - Data Type - // - else if(CommandIs("TYPE")) { - if(ParameterIs("A")) { - client.println(F("200 TYPE is now ASCII")); - } else if(ParameterIs("I")) { - client.println(F("200 TYPE is now 8-bit binary")); - } else { - client.println(F("504 Unknow TYPE")); - } - } - - /////////////////////////////////////// - // // - // FTP SERVICE COMMANDS // - // // - /////////////////////////////////////// - - // - // ABOR - Abort - // - else if(CommandIs("ABOR")) { - abortTransfer(); - client.println(F("226 Data connection closed")); - } - // - // DELE - Delete a File - // - else if(CommandIs("DELE")) { - char path[FTP_CWD_SIZE]; - if(haveParameter() && makeExistsPath(path)) { - if(remove(path)) { - if(FtpServer::_callback) { - FtpServer::_callback(FTP_FREE_SPACE_CHANGE, free(), capacity()); - } - - client.print(F("250 Deleted ")); - client.println(parameter); - } else { - client.print(F("450 Can't delete ")); - client.println(parameter); - } - } - } - // - // LIST - List - // NLST - Name List - // MLSD - Listing for Machine Processing (see RFC 3659) - // - else if(CommandIs("LIST") || CommandIs("NLST") || CommandIs("MLSD")) { - DEBUG_PRINT("List of file!!"); - - if(dataConnect()) { - if(openDir(&dir)) { - DEBUG_PRINT("Dir opened!!"); - - nbMatch = 0; - if(CommandIs("LIST")) - transferStage = FTP_List; - else if(CommandIs("NLST")) - transferStage = FTP_Nlst; - else - transferStage = FTP_Mlsd; - } else { - DEBUG_PRINT("List Data stop!!"); - data.stop(); - } - } - } - // - // MLST - Listing for Machine Processing (see RFC 3659) - // - else if(CommandIs("MLST")) { - char path[FTP_CWD_SIZE]; - uint16_t dat, tim; - char dtStr[15]; - bool isdir; - if(haveParameter() && makeExistsPath(path)) { - if(!getFileModTime(path, &dat, &tim)) { - client.print(F("550 Unable to retrieve time for ")); - client.println(parameter); - } else { - isdir = isDir(path); - client.println(F("250-Begin")); - client.print(F(" Type=")); - client.print((isdir ? F("dir") : F("file"))); - client.print(F(";Modify=")); - client.print(makeDateTimeStr(dtStr, dat, tim)); - if(!isdir) { - if(openFile(path, FTP_FILE_READ)) { - client.print(F(";Size=")); - client.print(long(fileSize(file))); - file.close(); - } - } - client.print(F("; ")); - client.println(path); - client.println(F("250 End.")); - } - } - } - // - // NOOP - // - else if(CommandIs("NOOP")) { - client.println(F("200 Zzz...")); - } - // - // RETR - Retrieve - // - else if(CommandIs("RETR")) { - char path[FTP_CWD_SIZE]; - if(haveParameter() && makeExistsPath(path)) { - if(!openFile(path, FTP_FILE_READ)) { - client.print(F("450 Can't open ")); - client.print(parameter); - } else if(dataConnect(false)) { - DEBUG_PRINT(F(" Sending ")); - DEBUG_PRINT(parameter); - DEBUG_PRINT(F(" size ")); - DEBUG_PRINTLN(long(fileSize(file))); - - if(FtpServer::_transferCallback) { - FtpServer::_transferCallback(FTP_DOWNLOAD_START, path, long(fileSize(file))); - } - - client.print(F("150-Connected to port ")); - client.println(dataPort); - client.print(F("150 ")); - client.print(long(fileSize(file))); - client.println(F(" bytes to download")); - 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)) { - bool open; - if(exists(path)) { - DEBUG_PRINTLN(F("APPEND FILE!!")); - open = openFile(path, (CommandIs("APPE") ? FTP_FILE_WRITE_APPEND : FTP_FILE_WRITE_CREATE)); - } else { - DEBUG_PRINTLN(F("CREATE FILE!!")); - open = openFile(path, FTP_FILE_WRITE_CREATE); - } - - data.stop(); - data.flush(); - - DEBUG_PRINT(F("open/create ")); - DEBUG_PRINTLN(open); - if(!open) { - client.print(F("451 Can't open/create ")); - client.println(parameter); - } else if(!dataConnect()) // && !data.available()) - file.close(); - else { - DEBUG_PRINT(F(" Receiving ")); - DEBUG_PRINTLN(parameter); - - millisBeginTrans = millis(); - bytesTransfered = 0; - transferStage = FTP_Store; - - if(FtpServer::_transferCallback) { - - // FtpServer::_transferCallback(FTP_UPLOAD_START, parameter, bytesTransfered); - FtpServer::_transferCallback(FTP_UPLOAD_START, path, bytesTransfered); - } - } - } - } - // - // MKD - Make Directory - // - else if(CommandIs("MKD")) { - char path[FTP_CWD_SIZE]; - if(haveParameter() && makePath(path)) { - if(exists(path)) { - client.print(F("521 \"")); - client.print(parameter); - client.println(F("\" directory already exists")); - } else { - DEBUG_PRINT(F(" Creating directory ")); - DEBUG_PRINTLN(parameter); - -#if STORAGE_TYPE != STORAGE_SPIFFS - if(makeDir(path)) { - client.print(F("257 \"")); - client.print(parameter); - client.print(F("\"")); - client.println(F(" created")); - } else { -#endif - client.print(F("550 Can't create \"")); - client.print(parameter); - client.println(F("\"")); -#if STORAGE_TYPE != STORAGE_SPIFFS - } -#endif - } - } - } - // - // RMD - Remove a Directory - // - else if(CommandIs("RMD")) { - char path[FTP_CWD_SIZE]; - if(haveParameter() && makeExistsPath(path)) { - if(removeDir(path)) { - DEBUG_PRINT(F(" Deleting ")); - DEBUG_PRINTLN(path); - - client.print(F("250 \"")); - client.print(parameter); - client.println(F("\" deleted")); - } else { - client.print(F("550 Can't remove \"")); - client.print(parameter); - client.println(F("\". Directory not empty?")); - } - } - } - // - // RNFR - Rename From - // - else if(CommandIs("RNFR")) { - rnfrName[0] = 0; - if(haveParameter() && makeExistsPath(rnfrName)) { - DEBUG_PRINT(F(" Ready for renaming ")); - DEBUG_PRINTLN(rnfrName); - - client.println(F("350 RNFR accepted - file exists, ready for destination")); - 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.println(F("503 Need RNFR before RNTO")); - } else if(haveParameter() && makePath(path)) { - if(exists(path)) { - client.print(F("553 ")); - client.print(parameter); - client.println(F(" already exists")); - } else { - strcpy(dirp, path); - char* psep = strrchr(dirp, '/'); - bool fail = psep == NULL; - if(!fail) { - if(psep == dirp) psep++; - *psep = 0; - // fail = ! isDir( dirp ); - // if( fail ) { - // client.print( F("550 \"") ); client.print( dirp ); client.println( F("\" is not - // directory") ); - // } else - // { - DEBUG_PRINT(F(" Renaming ")); - DEBUG_PRINT(rnfrName); - DEBUG_PRINT(F(" to ")); - DEBUG_PRINTLN(path); - - if(rename(rnfrName, path)) - client.println(F("250 File successfully renamed or moved")); - else - fail = true; - // } - } - if(fail) client.println(F("451 Rename/move failure")); - } - } - rnfrCmd = false; - } - /* - // - // SYST - System - // - else if( CommandIs( "SYST" )) - FtpOutCli << F("215 MSDOS") << endl; - */ - - /////////////////////////////////////// - // // - // 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.println(F("501 No file name")); - } else if(makeExistsPath(path, fname)) { - if(setTime) // set file modification time - { - if(timeStamp(path, year, month, day, hour, minute, second)) { - client.print(F("213 ")); - client.println(dt); - } else { - client.println(F("550 Unable to modify time")); - } - } else if(mdtm) // get file modification time - { - uint16_t dat, tim; - char dtStr[15]; - if(getFileModTime(path, &dat, &tim)) { - client.print(F("213 ")); - client.println(makeDateTimeStr(dtStr, dat, tim)); - } else { - client.println("550 Unable to retrieve time"); - } - } - } - } - } - // - // SIZE - Size of the file - // - else if(CommandIs("SIZE")) { - char path[FTP_CWD_SIZE]; - if(haveParameter() && makeExistsPath(path)) { - if(!openFile(path, FTP_FILE_READ)) { - client.print(F("450 Can't open ")); - client.println(parameter); - } else { - client.print(F("213 ")); - client.println(long(fileSize(file))); - file.close(); - } - } - } - // - // SITE - System command - // - else if(CommandIs("SITE")) { - if(ParameterIs("FREE")) { - uint32_t capa = capacity(); - if((capa >> 10) < 1000) { // less than 1 Giga - client.print(F("200 ")); - client.print(free()); - client.print(F(" kB free of ")); - client.print(capa); - client.println(F(" kB capacity")); - } else { - client.print(F("200 ")); - client.print((free() >> 10)); - client.print(F(" MB free of ")); - client.print((capa >> 10)); - client.println(F(" MB capacity")); - } - } else { - client.print(F("500 Unknow SITE command ")); - client.println(parameter); - } - } - // - // Unrecognized commands ... - // else - client.println(F("500 Unknow command")); - return true; + { + client.println(F("530 ") ); + cmdStage = FTP_Stop; + } + } + // + // PASS - Password + // + else if( CommandIs( "PASS" )) + { + if( cmdStage != FTP_Pass ) + { + client.println(F("503 ") ); + cmdStage = FTP_Stop; + } + if( ! strcmp( parameter, pass )) + { + DEBUG_PRINTLN( F("Authentication Ok. Waiting for commands.") ); + + client.println(F("230 Ok") ); + cmdStage = FTP_Cmd; + } + else + { + client.println( F("530 ") ); + cmdStage = FTP_Stop; + } + } + // + // FEAT - New Features + // + else if( CommandIs( "FEAT" )) + { + client.println(F("211-Extensions suported:")); + client.println(F(" MLST type*;modify*;size*;") ); + client.println(F(" MLSD") ); + client.println(F(" MDTM") ); + client.println(F(" MFMT") ); +#ifdef UTF8_SUPPORT + client.println(F(" UTF8") ); +#endif + client.println(F(" SIZE") ); + client.println(F(" SITE FREE") ); + client.println(F("211 End.") ); + } + // + // AUTH - Not implemented + // + else if( CommandIs( "AUTH" )) + client.println(F("502 ") ); + // + // Unrecognized commands at stage of authentication + // + else if( cmdStage < FTP_Cmd ) + { + client.println(F("530 ") ); + cmdStage = FTP_Stop; + } + + /////////////////////////////////////// + // // + // ACCESS CONTROL COMMANDS // + // // + /////////////////////////////////////// + + // + // PWD - Print Directory + // + else if( CommandIs( "PWD" ) || + ( CommandIs( "CWD" ) && ParameterIs( "." ))) { + client.print( F("257 \"")); client.print( cwdName ); client.print( F("\"") ); client.println( F(" is your current directory") ); + // + // 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 = exists( cwdName ); + } + } + // if an error appends, move to root + if( ! ok ) { + strcpy( cwdName, "/" ); + } + client.print( F("250 Ok. Current directory is ") ); client.println( cwdName ); + } + // + // CWD - Change Working Directory + // + else if( CommandIs( "CWD" )) + { + char path[ FTP_CWD_SIZE ]; + if( haveParameter() && makeExistsPath( path )) + { + strcpy( cwdName, path ); + client.print( F("250 Directory changed to ") ); client.print(cwdName); client.println(); + } + } + // + // QUIT + // + else if( CommandIs( "QUIT" )) + { + client.println(F("221 Goodbye") ); + disconnectClient(); + cmdStage = FTP_Stop; + } + + /////////////////////////////////////// + // // + // TRANSFER PARAMETER COMMANDS // + // // + /////////////////////////////////////// + + // + // MODE - Transfer Mode + // + else if( CommandIs( "MODE" )) + { + if( ParameterIs( "S" )) { + client.println(F("200 S Ok") ); + } else { + client.println(F("504 Only S(tream) is suported") ); + } + } + // + // PASV - Passive Connection management + // + else if( CommandIs( "PASV" )) + { + data.stop(); + dataServer.begin(); + if (((((uint32_t) NET_CLASS.localIP()) & ((uint32_t) NET_CLASS.subnetMask())) == + (((uint32_t) client.remoteIP()) & ((uint32_t) NET_CLASS.subnetMask()))) && (uint32_t)localIp <= 0) { + dataIp = NET_CLASS.localIP(); + } else { + dataIp = localIp; + } + // DEBUG_PRINT( F(" IP: %s"), dataIp.toString().c_str() ); + // DEBUG_PRINT( int( dataIp[0]) ); DEBUG_PRINT( F(".") ); DEBUG_PRINT( int( dataIp[1]) ); DEBUG_PRINT( F(".") ); + // DEBUG_PRINT( int( dataIp[2]) ); DEBUG_PRINT( F(".") ); DEBUG_PRINTLN( int( dataIp[3]) ); + +#if !defined(ARDUINO_ARCH_RP2040) && ((FTP_SERVER_NETWORK_TYPE_SELECTED == NETWORK_ESP8266_ASYNC) || (FTP_SERVER_NETWORK_TYPE_SELECTED == NETWORK_ESP8266) || (FTP_SERVER_NETWORK_TYPE_SELECTED == NETWORK_ESP8266) || (FTP_SERVER_NETWORK_TYPE_SELECTED == NETWORK_ESP32)) // || (FTP_SERVER_NETWORK_TYPE_SELECTED == NETWORK_WiFiNINA) || (FTP_SERVER_NETWORK_TYPE_SELECTED == NETWORK_SEEED_RTL8720DN)) + if (dataIp.toString() == F("0.0.0.0")) { + dataIp = NET_CLASS.softAPIP(); + } +#endif + // DEBUG_PRINT( F(" Soft IP: %s"), dataIp.toString().c_str()); + // DEBUG_PRINT( int( dataIp[0]) ); DEBUG_PRINT( F(".") ); DEBUG_PRINT( int( dataIp[1]) ); DEBUG_PRINT( F(".") ); + // DEBUG_PRINT( int( dataIp[2]) ); DEBUG_PRINT( F(".") ); DEBUG_PRINTLN( int( dataIp[3]) ); + + dataPort = pasvPort; + // DEBUG_PRINTLN( F(" Connection management set to passive") ); + DEBUG_PRINT( F("Listening at %s:%d"),dataIp.toString().c_str(),dataPort ); + // DEBUG_PRINT( int( dataIp[0]) ); DEBUG_PRINT( F(".") ); DEBUG_PRINT( int( dataIp[1]) ); DEBUG_PRINT( F(".") ); + // DEBUG_PRINT( int( dataIp[2]) ); DEBUG_PRINT( F(".") ); DEBUG_PRINT( int( dataIp[3]) ); + // DEBUG_PRINT( F(":") ); DEBUG_PRINTLN( dataPort ); + + client.print( F("227 Entering Passive Mode") ); client.print( F(" (") ); + client.print( int( dataIp[0]) ); client.print( F(",") ); client.print( int( dataIp[1]) ); client.print( F(",") ); + client.print( int( dataIp[2]) ); client.print( F(",") ); client.print( int( dataIp[3]) ); client.print( F(",") ); + client.print( ( dataPort >> 8 ) ); client.print( F(",") ); client.print( ( dataPort & 255 ) ); client.println( F(")") ); + 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.println(F("501 Can't interpret parameters") ); + } else + { + // DEBUG_PRINT( F(" Data IP set to ") ); DEBUG_PRINT( int( dataIp[0]) ); DEBUG_PRINT( F(".") ); DEBUG_PRINT( int( dataIp[1]) ); + // DEBUG_PRINT( F(".") ); DEBUG_PRINT( int( dataIp[2]) ); DEBUG_PRINT( F(".") ); DEBUG_PRINTLN( int( dataIp[3]) ); + // DEBUG_PRINT( F(" Data port set to ") ); DEBUG_PRINTLN( dataPort ); + + DEBUG_PRINT( F("Remote endpoint %s:%d"), dataIp.toString().c_str(), dataPort ); + + + client.println(F("200 PORT command successful") ); + dataConn = FTP_Active; + } + } + // + // STRU - File Structure + // + else if( CommandIs( "STRU" )) + { + if( ParameterIs( "F" )) { + client.println(F("200 F Ok") ); + // else if( ParameterIs( "R" )) + // client.println(F("200 B Ok") ); + }else{ + client.println(F("504 Only F(ile) is suported") ); + } + } + // + // TYPE - Data Type + // + else if( CommandIs( "TYPE" )) + { + if( ParameterIs( "A" )) { + client.println(F("200 TYPE is now ASCII")); + } else if( ParameterIs( "I" )) { + client.println(F("200 TYPE is now 8-bit binary") ); + } else { + client.println(F("504 Unknow TYPE") ); + } + } + + /////////////////////////////////////// + // // + // FTP SERVICE COMMANDS // + // // + /////////////////////////////////////// + + // + // ABOR - Abort + // + else if( CommandIs( "ABOR" )) + { + abortTransfer(); + client.println(F("226 Data connection closed")); + } + // + // DELE - Delete a File + // + else if( CommandIs( "DELE" )) + { + char path[ FTP_CWD_SIZE ]; + if( haveParameter() && makeExistsPath( path )) { + if( remove( path )) { + if (FtpServer::_callback) { + FtpServer::_callback(FTP_FREE_SPACE_CHANGE, free(), capacity()); + } + + client.print( F("250 Deleted ") ); client.println( parameter ); + } else { + client.print( F("450 Can't delete ") ); client.println( parameter ); + } + } + } + // + // LIST - List + // NLST - Name List + // MLSD - Listing for Machine Processing (see RFC 3659) + // + else if( CommandIs( "LIST" ) || CommandIs( "NLST" ) || CommandIs( "MLSD" )) + { + //DEBUG_PRINT("List of file!!"); + + if( dataConnect()){ + if( openDir( & dir )) + { + // DEBUG_PRINT("Dir opened!!"); + + nbMatch = 0; + if( CommandIs( "LIST" )) + transferStage = FTP_List; + else if( CommandIs( "NLST" )) + transferStage = FTP_Nlst; + else + transferStage = FTP_Mlsd; + } + else { + DEBUG_PRINT("List Data stop!!"); + data.stop(); + } + } + } + // + // MLST - Listing for Machine Processing (see RFC 3659) + // + else if( CommandIs( "MLST" )) + { + char path[ FTP_CWD_SIZE ]; + uint16_t dat=0, tim=0; + char dtStr[ 15 ]; + bool isdir; + if( haveParameter() && makeExistsPath( path )){ + if( ! getFileModTime( path, &dat, &tim )) { + client.print( F("550 Unable to retrieve time for ") ); client.println( parameter ); + } else + { + isdir = isDir( path ); + client.println( F("250-Begin") ); + client.print( F(" Type=") ); client.print( ( isdir ? F("dir") : F("file")) ); + client.print( F(";Modify=") ); client.print( makeDateTimeStr( dtStr, dat, tim ) ); + if( ! isdir ) + { + if( openFile( path, FTP_FILE_READ )) + { + client.print( F(";Size=") ); client.print( long( fileSize( file )) ); + file.close(); + } + } + client.print( F("; ") ); client.println( path ); + client.println( F("250 End.") ); + } + } + } + // + // NOOP + // + else if( CommandIs( "NOOP" )) { + client.println(F("200 Zzz...") ); + } + // +#ifdef UTF8_SUPPORT + // OPTS + // + else if( CommandIs( "OPTS" )) { + if( ParameterIs( "UTF8 ON" ) || ParameterIs( "utf8 on" )) { + client.println(F("200 OK, UTF8 ON") ); + // DEBUG_PRINTLN(F("200 OK, UTF8 ON") ); + } else { + client.println(F("504 Unknow OPTS") ); + DEBUG_PRINTLN(F("504 Unknow OPTS") ); + } + } + // +#endif + // HELP + // + else if( CommandIs( "HELP" )) { + client.println(F("200 Commands implemented:") ); + client.println(F(" USER, PASS, AUTH (AUTH only return 'not implemented' code)") ); + client.println(F(" CDUP, CWD, PWD, QUIT, NOOP") ); + client.println(F(" MODE, PASV, PORT, STRU, TYPE") ); + client.println(F(" ABOR, DELE, LIST, NLST, MLST, MLSD") ); + client.println(F(" APPE, RETR, STOR") ); + client.println(F(" MKD, RMD") ); + client.println(F(" RNTO, RNFR") ); + client.println(F(" MDTM, MFMT") ); + client.println(F(" FEAT, SIZE") ); + client.println(F(" SITE FREE") ); + client.println(F(" HELP") ); + } + // + // RETR - Retrieve + // + else if( CommandIs( "RETR" )) + { + char path[ FTP_CWD_SIZE ]; + if( haveParameter() && makeExistsPath( path )) { + if( ! openFile( path, FTP_FILE_READ )) { + client.print( F("450 Can't open ") ); client.print( parameter ); + } else if( dataConnect( false )) + { + // DEBUG_PRINT( F(" Sending ") ); DEBUG_PRINT( parameter ); DEBUG_PRINT( F(" size ") ); DEBUG_PRINTLN( long( fileSize( file )) ); + // DEBUG_PRINT( F(" Sending %s size %d"), parameter, long( fileSize( file )) ); + + if (FtpServer::_transferCallback) { + FtpServer::_transferCallback(FTP_DOWNLOAD_START, parameter, long( fileSize( file ))); + } + + + client.print( F("150-Connected to port ") ); client.println( dataPort ); + client.print( F("150 ") ); client.print( long( fileSize( file )) ); client.println( F(" bytes to download") ); + 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 )) + { + bool open; + if( exists( path )) { + DEBUG_PRINTLN(F("APPEND FILE!!")); + open = openFile( path, ( CommandIs( "APPE" ) ? FTP_FILE_WRITE_APPEND : FTP_FILE_WRITE_CREATE )); + } else { + DEBUG_PRINTLN(F("CREATE FILE!!")); + open = openFile( path, FTP_FILE_WRITE_CREATE ); + } + + data.stop(); + data.flush(); + + // DEBUG_PRINT(F("open/create ")); + // DEBUG_PRINTLN(open); + if( ! open ){ + client.print( F("451 Can't open/create ") ); client.println( parameter ); + }else if( ! dataConnect()) // && !data.available()) + file.close(); + else + { + // DEBUG_PRINT( F(" Receiving %s") , parameter ); + + millisBeginTrans = millis(); + bytesTransfered = 0; + transferStage = FTP_Store; + + if (FtpServer::_transferCallback) { + + FtpServer::_transferCallback(FTP_UPLOAD_START, parameter, bytesTransfered); + } + + } + } + } + // + // MKD - Make Directory + // + else if( CommandIs( "MKD" )) + { + char path[ FTP_CWD_SIZE ]; + if( haveParameter() && makePath( path )) + { + if( exists( path )) { + client.print( F("521 \"") ); client.print( parameter ); client.println( F("\" directory already exists") ); + } else + { + DEBUG_PRINT( F(" Creating directory %s"), parameter ); + +#if STORAGE_TYPE != STORAGE_SPIFFS + if( makeDir( path )) { + client.print( F("257 \"") ); client.print( parameter ); client.print( F("\"") ); client.println( F(" created") ); + } else { +#endif + client.print( F("550 Can't create \"") ); client.print( parameter ); client.println( F("\"") ); +#if STORAGE_TYPE != STORAGE_SPIFFS + } +#endif + } + } + } + // + // RMD - Remove a Directory + // + else if( CommandIs( "RMD" )) + { + char path[ FTP_CWD_SIZE ]; + if( haveParameter() && makeExistsPath( path )) { + if( removeDir( path )) + { + DEBUG_PRINT( F(" Deleting %s"), path ); + + client.print( F("250 \"") ); client.print( parameter ); client.println( F("\" deleted") ); + } + else { + client.print( F("550 Can't remove \"") ); client.print( parameter ); client.println( F("\". Directory not empty?") ); + } + } + } + // + // RNFR - Rename From + // + else if( CommandIs( "RNFR" )) + { + rnfrName[ 0 ] = 0; + if( haveParameter() && makeExistsPath( rnfrName )) + { + DEBUG_PRINT( F(" Ready for renaming ") ); DEBUG_PRINTLN( rnfrName ); + + client.println(F("350 RNFR accepted - file exists, ready for destination") ); + 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.println(F("503 Need RNFR before RNTO") ); + } else if( haveParameter() && makePath( path )) + { + if( exists( path )) { + client.print( F("553 ") ); client.print( parameter ); client.println( F(" already exists") ); + } else + { + strcpy( dirp, path ); + char * psep = strrchr( dirp, '/' ); + bool fail = psep == NULL; + if( ! fail ) + { + if( psep == dirp ) + psep ++; + * psep = 0; +// fail = ! isDir( dirp ); +// if( fail ) { +// client.print( F("550 \"") ); client.print( dirp ); client.println( F("\" is not directory") ); +// } else +// { + DEBUG_PRINT( F(" Renaming ") ); DEBUG_PRINT( rnfrName ); DEBUG_PRINT( F(" to ") ); DEBUG_PRINTLN( path ); + + if( rename( rnfrName, path )) + client.println(F("250 File successfully renamed or moved") ); + else + fail = true; +// } + } + if( fail ) + client.println(F("451 Rename/move failure") ); + } + } + rnfrCmd = false; + } + /* + // + // SYST - System + // + else if( CommandIs( "SYST" )) + FtpOutCli << F("215 MSDOS") << endl; + */ + + /////////////////////////////////////// + // // + // 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.println(F("501 No file name") ); + } else if( makeExistsPath( path, fname )) { + if( setTime ) // set file modification time + { + if( timeStamp( path, year, month, day, hour, minute, second )) { + client.print( F("213 ") ); client.println( dt ); + } else { + client.println(F("550 Unable to modify time" )); + } + } + else if( mdtm ) // get file modification time + { + uint16_t dat=0, tim=0; + char dtStr[ 15 ]; + if( getFileModTime( path, &dat, &tim )) { + client.print( F("213 ") ); client.println( makeDateTimeStr( dtStr, dat, tim ) ); + } else { + client.println("550 Unable to retrieve time" ); + } + } + } + } + } + // + // SIZE - Size of the file + // + else if( CommandIs( "SIZE" )) + { + char path[ FTP_CWD_SIZE ]; + if( haveParameter() && makeExistsPath( path )) { + if( ! openFile( path, FTP_FILE_READ )) { + client.print( F("450 Can't open ") ); client.println( parameter ); + } else + { + client.print( F("213 ") ); client.println( long( fileSize( file )) ); + file.close(); + } + } + } + // + // SITE - System command + // + else if( CommandIs( "SITE" )) + { + if( ParameterIs( "FREE" )) + { + uint32_t capa = capacity(); + if(( capa >> 10 ) < 1000 ) { // less than 1 Giga + client.print( F("200 ") ); client.print( free() ); client.print( F(" kB free of ") ); + client.print( capa ); client.println( F(" kB capacity") ); + }else { + client.print( F("200 ") ); client.print( ( free() >> 10 ) ); client.print( F(" MB free of ") ); + client.print( ( capa >> 10 ) ); client.println( F(" MB capacity") ); + } + } + else { + client.print( F("500 Unknow SITE command ") ); client.println( parameter ); + } + } + // + // Unrecognized commands ... + // + else + client.println(F("500 Unknow command") ); + return true; } -int FtpServer::dataConnect(bool out150) +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) { -#ifdef ESP8266 - if(dataServer.hasClient()) { - data.stop(); - data = dataServer.available(); - } -#else - data = dataServer.accept(); -#endif - delay(1); - } - } else if(dataConn == FTP_Active) - data.connect(dataIp, dataPort); + if( ! data.connected()) { + if( dataConn == FTP_Pasive ) + { + uint16_t count = 1000; // wait up to a second + while( ! data.connected() && count -- > 0 ) + { + #if (FTP_SERVER_NETWORK_TYPE == NETWORK_WiFiNINA) + data = dataServer.available(); + #elif defined(ESP8266) // || defined(ARDUINO_ARCH_RP2040) + if( dataServer.hasClient()) + { + data.stop(); + data = dataServer.available(); + } + #else + data = dataServer.accept(); + #endif + delay( 1 ); + } } + else if( dataConn == FTP_Active ) + data.connect( dataIp, dataPort ); + } + +//#ifdef ESP8266 + if( ! ( data.connected() || data.available())) { +//#else +// if( ! ( data.connected() )) { +//#endif + client.println(F("425 No data connection")); + } else if( out150 ) { + client.print( F("150 Accepted data connection to port ") ); client.println( dataPort ); + } +//#ifdef ESP8266 + return data.connected() || data.available(); +//#else +// return data.connected(); +//#endif - //#ifdef ESP8266 - if(!(data.connected() || data.available())) { - //#else - // if( ! ( data.connected() )) { - //#endif - client.println(F("425 No data connection")); - } else if(out150) { - client.print(F("150 Accepted data connection to port ")); - client.println(dataPort); - } - //#ifdef ESP8266 - return data.connected() || data.available(); - //#else - // return data.connected(); - //#endif } bool FtpServer::dataConnected() { - if(data.connected()) return true; - data.stop(); - client.println(F("426 Data connection closed. Transfer aborted")); - transferStage = FTP_Close; - return false; + if( data.connected()) + return true; + data.stop(); + client.println(F("426 Data connection closed. Transfer aborted") ); + transferStage = FTP_Close; + return false; } - -bool FtpServer::openDir(FTP_DIR* pdir) + +bool FtpServer::openDir( FTP_DIR * pdir ) { - bool openD; -#if(STORAGE_TYPE == STORAGE_LITTLEFS && defined(ESP8266)) - if(cwdName == 0) { - dir = STORAGE_MANAGER.openDir("/"); - } else { - dir = STORAGE_MANAGER.openDir(cwdName); - } - openD = dir.rewind(); + bool openD; +#if (STORAGE_TYPE == STORAGE_LITTLEFS && (defined(ESP8266) || defined(ARDUINO_ARCH_RP2040))) + if( cwdName == 0 ) { + dir = STORAGE_MANAGER.openDir( "/" ); + } else { + dir = STORAGE_MANAGER.openDir( cwdName ); + } + openD = dir.rewind(); - if(!openD) { - client.print(F("550 Can't open directory ")); - client.println(cwdName); - } -#elif STORAGE_TYPE == STORAGE_SD - if(cwdName == 0) { - dir = STORAGE_MANAGER.open("/"); - } else { - dir = STORAGE_MANAGER.open(cwdName); - } - openD = true; - if(!openD) { - client.print(F("550 Can't open directory ")); - client.println(cwdName); - } + if( ! openD ) { + client.print( F("550 Can't open directory ") ); client.println( cwdName ); + } +#elif STORAGE_TYPE == STORAGE_SD || STORAGE_TYPE == STORAGE_SD_MMC + if( cwdName == 0 ) { + dir = STORAGE_MANAGER.open( "/" ); + } else { + dir = STORAGE_MANAGER.open( cwdName ); + } + openD = true; + if( ! openD ) { + client.print( F("550 Can't open directory ") ); client.println( cwdName ); + } #elif STORAGE_TYPE == STORAGE_FFAT || (STORAGE_TYPE == STORAGE_LITTLEFS && defined(ESP32)) - if(cwdName == 0) { - dir = STORAGE_MANAGER.open("/"); - } else { - dir = STORAGE_MANAGER.open(cwdName); - } - openD = true; - if(!openD) { - client.print(F("550 Can't open directory ")); - client.println(cwdName); - } + if( cwdName == 0 ) { + dir = STORAGE_MANAGER.open( "/" ); + } else { + dir = STORAGE_MANAGER.open( cwdName ); + } + openD = true; + if( ! openD ) { + client.print( F("550 Can't open directory ") ); client.println( cwdName ); + } #elif STORAGE_TYPE == STORAGE_SEEED_SD - if(cwdName == 0) { - DEBUG_PRINT("cwdName forced -> "); - DEBUG_PRINTLN(cwdName); + if( cwdName == 0 ) { + DEBUG_PRINT("cwdName forced -> "); + DEBUG_PRINTLN(cwdName ); - FTP_DIR d = STORAGE_MANAGER.open("/"); - dir = d; - } else { - DEBUG_PRINT("cwdName -> "); - DEBUG_PRINTLN(cwdName); + FTP_DIR d = STORAGE_MANAGER.open( "/" ); + dir=d; + } else { + DEBUG_PRINT("cwdName -> "); + DEBUG_PRINTLN(cwdName ); - FTP_DIR d = STORAGE_MANAGER.open(cwdName); - dir = d; - } + FTP_DIR d = STORAGE_MANAGER.open( cwdName ); + dir=d; + } - openD = dir.isDirectory(); + openD = dir.isDirectory(); - //#ifdef FTP_ADDITIONAL_DEBUG - // DEBUG_PRINT("Listing directory: "); - // DEBUG_PRINTLN(cwdName); - // - // if (!dir) { - // DEBUG_PRINTLN("Failed to open directory"); - // } - // if (!dir.isDirectory()) { - // DEBUG_PRINTLN("Not a directory"); - // } - // - // File file = dir.openNextFile(); - // while (file) { - // if (file.isDirectory()) { - // DEBUG_PRINT(" DIR : "); - // DEBUG_PRINTLN(file.name()); - // } else { - // DEBUG_PRINT(" FILE: "); - // DEBUG_PRINT(file.name()); - // DEBUG_PRINT(" SIZE: "); - // DEBUG_PRINTLN(file.size()); - // } - // file = dir.openNextFile(); - // } - // - // dir.rewindDirectory(); - // - //#endif - - if(!openD) { - client.print(F("550 Can't open directory ")); - client.println(cwdName); - } + if( ! openD ) { + client.print( F("550 Can't open directory ") ); client.println( cwdName ); + } #elif STORAGE_TYPE == STORAGE_SPIFFS - if(cwdName == 0 || strcmp(cwdName, "/") == 0) { - DEBUG_PRINT("DIRECTORY / EXIST "); + if( cwdName == 0 || strcmp(cwdName, "/") == 0 ) { + DEBUG_PRINT("DIRECTORY / EXIST "); #if ESP8266 - dir = STORAGE_MANAGER.openDir("/"); + dir = STORAGE_MANAGER.openDir( "/" ); #else - dir = STORAGE_MANAGER.open("/"); + dir = STORAGE_MANAGER.open( "/" ); #endif - openD = true; + openD = true; } else { - openD = false; + openD = false; } - if(!openD) { - client.print(F("550 Can't open directory ")); - client.println(cwdName); + if( ! openD ) { + client.print( F("550 Can't open directory ") ); client.println( cwdName ); } #else - if(cwdName == 0) { - openD = pdir->open("/"); - } else { - openD = pdir->open(cwdName); - } - if(!openD) { - client.print(F("550 Can't open directory ")); - client.println(cwdName); - } + if( cwdName == 0 ) { + openD = pdir->open( "/" ); + } else { + openD = pdir->open( cwdName ); + } + if( ! openD ) { + client.print( F("550 Can't open directory ") ); client.println( cwdName ); + } #endif - return openD; + return openD; } 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); - DEBUG_PRINT(F("NB --> ")); - DEBUG_PRINTLN(nb); - bytesTransfered += nb; + if( ! dataConnected()) + { + file.close(); + return false; + } + int16_t nb = file.read( buf, FTP_BUF_SIZE ); + if( nb > 0 ) + { + data.write( buf, nb ); + // DEBUG_PRINT(F("NB --> ")); + // DEBUG_PRINTLN(nb); + bytesTransfered += nb; - if(FtpServer::_transferCallback) { - FtpServer::_transferCallback(FTP_DOWNLOAD, getFileName(&file), bytesTransfered); - } + if (FtpServer::_transferCallback) { + FtpServer::_transferCallback(FTP_DOWNLOAD, getFileName(&file), bytesTransfered); + } // RoSchmi #if STORAGE_TYPE != STORAGE_SEEED_SD - return true; + return true; #endif - } - closeTransfer(); - return false; + } + closeTransfer(); + return false; } bool FtpServer::doStore() { - int16_t na = data.available(); - if(na == 0) { - DEBUG_PRINTLN("NO DATA AVAILABLE!"); + int16_t na = data.available(); + if( na == 0 ) { + // DEBUG_PRINTLN("NO DATA AVAILABLE!"); #if FTP_SERVER_NETWORK_TYPE_SELECTED == NETWORK_SEEED_RTL8720DN - data.stop(); + data.stop(); #endif - if(data.connected()) { - return true; - } else { - closeTransfer(); - return false; - } + 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) { - DEBUG_PRINT("NB -> "); - DEBUG_PRINTLN(nb); + 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 ) + { + // DEBUG_PRINT("NB -> "); + // DEBUG_PRINTLN(nb); - rc = file.write(buf, nb); - DEBUG_PRINT("RC -> "); - DEBUG_PRINTLN(rc); - bytesTransfered += nb; + rc = file.write( buf, nb ); + // DEBUG_PRINT("RC -> "); + // DEBUG_PRINTLN(rc); + bytesTransfered += nb; - if(FtpServer::_transferCallback) { + if (FtpServer::_transferCallback) { - FtpServer::_transferCallback(FTP_UPLOAD, getFileName(&file), bytesTransfered); - } - } - if(nb < 0 || rc == nb) { - return true; - } - client.println(F("552 Probably insufficient storage space")); - file.close(); - data.stop(); - return false; + FtpServer::_transferCallback(FTP_UPLOAD, getFileName(&file), bytesTransfered); + } + } + if( nb < 0 || rc == nb ) { + return true; + } + client.println(F("552 Probably insufficient storage space") ); + file.close(); + data.stop(); + return false; } +void generateFileLine(FTP_CLIENT_NETWORK_CLASS* data, bool isDirectory, const char* fn, long fz, const char* time, const char* user, bool writeFilename = true) { + if( isDirectory ) { + // data.print( F("+/,\t") ); + // DEBUG_PRINT(F("+/,\t")); + + data->print( F("drwxrwsr-x\t2\t")); + data->print( user ); + data->print( F("\t") ); + data->print( long( 4096 ) ); + data->print( F("\t") ); + + DEBUG_PRINT( F("drwxrwsr-x\t2\t") ); + DEBUG_PRINT( user ); + DEBUG_PRINT( F("\t") ); + + // DEBUG_PRINT( long( 4096 ) ); + DEBUG_PRINT( F("\t") ); + + data->print(time); + DEBUG_PRINT(time); + + data->print( F("\t") ); + if (writeFilename) data->println( fn ); + + DEBUG_PRINT( F("\t") ); + if (writeFilename) DEBUG_PRINTLN( fn ); + + } else { +// data.print( F("+r,s") ); +// DEBUG_PRINT(F("+r,s")); + + data->print( F("-rw-rw-r--\t1\t") ); + data->print( user ); + data->print( F("\t") ); + data->print( fz ); + data->print( F("\t") ); + + DEBUG_PRINT( F("-rw-rw-r--\t1\t") ); + DEBUG_PRINT( user ); + DEBUG_PRINT( F("\t") ); + // DEBUG_PRINT( fz ); + DEBUG_PRINT( F("\t") ); + + data->print(time); + DEBUG_PRINT(time); + + data->print( F("\t") ); + if (writeFilename) data->println( fn ); + + DEBUG_PRINT( F("\t") ); + if (writeFilename) DEBUG_PRINTLN( fn ); + } + +} + +#if defined(ESP32) || defined(ESP8266) || defined(ARDUINO_ARCH_RP2040) +// +// Formats printable String from a time_t timestamp +// +String makeDateTimeStrList(time_t ft, bool dateContracted = false) +{ + String tmp; + // a buffer with enough space for the formats + char buf[25]; + char *b = buf; + + // break down the provided file time + struct tm _tm; + gmtime_r(&ft, &_tm); + + if (dateContracted) + { + // "%Y%m%d%H%M%S", e.g. "20200517123400" + strftime(b, sizeof(buf), "%Y%m%d%H%M%S", &_tm); + } + else + { + // "%h %d %H:%M", e.g. "May 17 12:34" for file dates of the current year + // "%h %d %Y" , e.g. "May 17 2019" for file dates of any other years + + // just convert both ways, select later what's to be shown + // buf becomes "May 17 2019May 17 12:34" + strftime(b, sizeof(buf), "%h %d %H:%M%h %d %Y", &_tm); + + // check for a year != year from now + int fileYear = _tm.tm_year; + time_t nowTime = time(NULL); + gmtime_r(&nowTime, &_tm); + if (fileYear == _tm.tm_year) + { + // cut off 2nd half - year variant + b[12] = '\0'; + } + else + { + // skip 1st half - time variant + b += 12; + } + } + tmp = b; + return tmp; +} + +// https://files.stairways.com/other/ftp-list-specs-info.txt +void generateFileLine(FTP_CLIENT_NETWORK_CLASS* data, bool isDirectory, const char* fn, long fz, time_t time, const char* user, bool writeFilename = true) { + generateFileLine(data, isDirectory, fn, fz, makeDateTimeStrList(time).c_str(), user, writeFilename); +} +#endif + bool FtpServer::doList() { - if(!dataConnected()) { -#if STORAGE_TYPE != STORAGE_SPIFFS && STORAGE_TYPE != STORAGE_LITTLEFS && STORAGE_TYPE != STORAGE_SEEED_SD - dir.close(); -#endif - return false; - } -#if STORAGE_TYPE == STORAGE_SPIFFS -#if ESP8266 - if(dir.next()) -#else - FTP_FILE fileDir = dir.openNextFile(); - if(fileDir) -#endif - { - - data.print(F("+r,s")); -#if ESP8266 - data.print(long(dir.fileSize())); - data.print(F(",\t")); - data.println(dir.fileName()); -#else - data.print(long(fileDir.size())); - data.print(F(",\t")); - data.println(fileDir.name()); -#endif - nbMatch++; - return true; - } -#elif STORAGE_TYPE == STORAGE_LITTLEFS || STORAGE_TYPE == STORAGE_SEEED_SD || STORAGE_TYPE == STORAGE_FFAT -#if ESP8266 - if(dir.next()) -#else -#if STORAGE_TYPE == STORAGE_SEEED_SD - FTP_FILE fileDir = STORAGE_MANAGER.open(dir.name()); - fileDir = dir.openNextFile(); -#else - FTP_FILE fileDir = dir.openNextFile(); -#endif - if(fileDir) -#endif - { - - if(fileDir.isDirectory()) { - data.print(F("drw-rw-rw- 1 hasp hasp ")); - DEBUG_PRINT(F("drw-rw-rw- ")); - } else { - data.print(F("-rw-rw-rw- 1 hasp hasp ")); - DEBUG_PRINT(F("-rw-rw-rw- ")); - } -#if ESP8266 - data.print(long(dir.fileSize())); - data.print(F(",\t")); - data.println(dir.fileName()); -#elif STORAGE_TYPE == STORAGE_SEEED_SD - String fn = fileDir.name(); - fn.remove(0, strlen(dir.name())); - if(fn[0] == '/') { - fn.remove(0, fn.lastIndexOf("/") + 1); - } - long fz = fileDir.size(); -#else - data.print(long(fileDir.size())); - data.print(F(" ")); - data.print(long(fileDir.getLastWrite())); - data.print(F(" ")); - data.println(fileDir.name()); - - DEBUG_PRINT(long(fileDir.size())); - DEBUG_PRINT(F(" ")); - DEBUG_PRINTLN(fileDir.name()); - -#endif - - nbMatch++; - return true; - } -#elif STORAGE_TYPE == STORAGE_SD - FTP_FILE fileDir = dir.openNextFile(); - if(fileDir) { - - data.print(F("+r,s")); - data.print(long(fileDir.size())); - data.print(F(",\t")); - data.println(fileDir.name()); - - nbMatch++; - return true; - } - // - //#elif STORAGE_TYPE == STORAGE_SPIFFS || STORAGE_TYPE == STORAGE_LITTLEFS || STORAGE_TYPE == STORAGE_SD - // #if ESP8266 && STORAGE_TYPE != STORAGE_SD - // if( dir.next()) - // #else - // File fileDir = dir.openNextFile(); - // if( fileDir ) - // #endif - // { - // - // #if (STORAGE_TYPE == STORAGE_LITTLEFS) - // if( dir.isDirectory()) { - // data.print( F("+/,\t") ); - // } else { - // #endif - // data.print( F("+r,s") ); - // #if ESP8266 && STORAGE_TYPE != STORAGE_SD - // data.print( long( dir.fileSize()) ); - // data.print( F(",\t") ); - // data.println( dir.fileName() ); - // #else - // data.print( long( fileDir.size()) ); - // data.print( F(",\t") ); - // data.println( fileDir.name() ); - // #endif - // #if (STORAGE_TYPE == STORAGE_LITTLEFS) - // } - // #endif - // - // nbMatch ++; - // return true; - // } - // - -#elif STORAGE_TYPE == STORAGE_FATFS - if(dir.nextFile()) { - if(dir.isDir()) { - data.print(F("+/,\t")); - } else { - data.print(F("+r,s")); - data.print(long(dir.fileSize())); - data.print(F(",\t")); - } - data.println(dir.fileName()); - nbMatch++; - return true; - } -#else - if(file.openNext(&dir, FTP_FILE_READ_ONLY)) { - if(file.isDir()) { - data.print(F("+/,\t")); - } else { - data.print(F("+r,s")); - data.print(long(fileSize(file))); - data.print(F(",\t")); - } - file.printName(&data); - data.println(); - file.close(); - nbMatch++; - return true; - } -#endif - client.print(F("226 ")); - client.print(nbMatch); - client.println(F(" matches total")); + if( ! dataConnected()) + { #if STORAGE_TYPE != STORAGE_SPIFFS && STORAGE_TYPE != STORAGE_LITTLEFS && STORAGE_TYPE != STORAGE_SEEED_SD dir.close(); #endif - data.stop(); return false; + } +#if STORAGE_TYPE == STORAGE_SPIFFS + #if ESP8266 + if( dir.next()) + #else + FTP_FILE fileDir = dir.openNextFile(); + if( fileDir ) + #endif + { + +// data.print( F("+r,s") ); +// #if ESP8266 +// data.print( long( dir.fileSize()) ); +// data.print( F(",\t") ); +// data.println( dir.fileName() ); +// #else +// data.print( long( fileDir.size()) ); +// data.print( F(",\t") ); +// data.println( fileDir.name() ); +// #endif + + + +#ifdef ESP8266 + String fn = dir.fileName(); + long fz = long( dir.fileSize()); + if (fn[0]=='/') { fn.remove(0, fn.lastIndexOf("/")+1); } + time_t time = dir.fileTime(); + generateFileLine(&data, false, fn.c_str(), fz, time, this->user); +#else + long fz = long( fileDir.size()); + const char* fnC = fileDir.name(); + const char* fn; + if ( fnC[0] == '/' ) { + fn = &fnC[1]; + }else{ + fn = fnC; + } + + time_t time = fileDir.getLastWrite(); + generateFileLine(&data, false, fn, fz, time, this->user); + +#endif + + nbMatch ++; + return true; + } +#elif STORAGE_TYPE == STORAGE_LITTLEFS || STORAGE_TYPE == STORAGE_SEEED_SD || STORAGE_TYPE == STORAGE_FFAT + #if defined(ESP8266) || defined(ARDUINO_ARCH_RP2040) + if( dir.next()) + #else +#if STORAGE_TYPE == STORAGE_SEEED_SD + FTP_FILE fileDir = STORAGE_MANAGER.open(dir.name()); + fileDir = dir.openNextFile(); +#else + FTP_FILE fileDir = dir.openNextFile(); +#endif + if( fileDir ) +#endif + { + + #if defined(ESP8266) || defined(ARDUINO_ARCH_RP2040) + long fz = long( dir.fileSize()); +// const char* fn = dir.fileName().c_str(); + String aza = dir.fileName(); + const char* fn = aza.c_str(); //Serial.printf("test %s ", fn); + +// data.print( long( dir.fileSize()) ); +// data.print( F(",\t") ); +// data.println( dir.fileName() ); + #elif STORAGE_TYPE == STORAGE_SEEED_SD + const char* fnC = fileDir.name(); + const char* fn; + if ( fnC[0] == '/' ) { + fn = &fnC[1]; + }else{ + fn = fnC; + } + long fz = fileDir.size(); + #else + long fz = long( fileDir.size()); + const char* fn = fileDir.name(); + +// data.print( long( fileDir.size()) ); +// data.print( F("\t") ); +// data.println( fileDir.name() ); + +// DEBUG_PRINT( long( fileDir.size())); +// DEBUG_PRINT( F("\t") ); +// DEBUG_PRINTLN( fileDir.name() ); + #endif + #if defined(ESP8266) || defined(ARDUINO_ARCH_RP2040) + time_t time = dir.fileTime(); + generateFileLine(&data, dir.isDirectory(), fn, fz, time, this->user); + #elif ESP32 + time_t time = fileDir.getLastWrite(); + generateFileLine(&data, fileDir.isDirectory(), fn, fz, time, this->user); + #else + generateFileLine(&data, fileDir.isDirectory(), fn, fz, "Jan 01 00:00", this->user); + #endif + nbMatch ++; + return true; + } +#elif STORAGE_TYPE == STORAGE_SD || STORAGE_TYPE == STORAGE_SD_MMC + FTP_FILE fileDir = dir.openNextFile(); + if( fileDir ) + { + +// data.print( F("+r,s") ); +// data.print( long( fileDir.size()) ); +// data.print( F(",\t") ); +// data.println( fileDir.name() ); + + String fn = fileDir.name(); + if (fn[0]=='/') { fn.remove(0, fn.lastIndexOf("/")+1); } + + generateFileLine(&data, fileDir.isDirectory(), fn.c_str(), long( fileDir.size()), "Jan 01 00:00", this->user); + + nbMatch ++; + return true; + } + +#elif STORAGE_TYPE == STORAGE_FATFS + if( dir.nextFile()) + { +// if( dir.isDir()) { +// data.print( F("+/,\t") ); +// } else { +// data.print( F("+r,s") ); data.print( long( dir.fileSize()) ); data.print( F(",\t") ); +// } +// data.println( dir.fileName() ); + + String fn = dir.fileName(); + if (fn[0]=='/') { fn.remove(0, fn.lastIndexOf("/")+1); } + + generateFileLine(&data, dir.isDir(), fn.c_str(), long( dir.fileSize()), "Jan 01 00:00", this->user); + + nbMatch ++; + return true; + } +#else + if( file.openNext( &dir, FTP_FILE_READ_ONLY )) + { +// if( file.isDir()) { +// data.print( F("+/,\t") ); +// } else { +// data.print( F("+r,s") ); data.print( long( fileSize( file )) ); data.print( F(",\t") ); +// } + + generateFileLine(&data, file.isDir(), "", long( fileSize( file )), "Jan 01 00:00", this->user, false); + + file.printName( & data ); + data.println(); + file.close(); + nbMatch ++; + return true; + } +#endif + client.print( F("226 ") ); client.print( nbMatch ); client.println( F(" matches total") ); +#if STORAGE_TYPE != STORAGE_SPIFFS && STORAGE_TYPE != STORAGE_LITTLEFS && STORAGE_TYPE != STORAGE_SEEED_SD + dir.close(); +#endif + data.stop(); + return false; } bool FtpServer::doMlsd() { - if(!dataConnected()) { + if( ! dataConnected()) + { #if STORAGE_TYPE != STORAGE_SPIFFS && STORAGE_TYPE != STORAGE_LITTLEFS && STORAGE_TYPE != STORAGE_SEEED_SD - dir.close(); + dir.close(); #endif - DEBUG_PRINTLN(F("Not connected!!")); - return false; - } - DEBUG_PRINTLN(F("Connected!!")); + DEBUG_PRINTLN(F("Not connected!!")); + return false; + } + // DEBUG_PRINTLN(F("Connected!!")); #if STORAGE_TYPE == STORAGE_SPIFFS - DEBUG_PRINTLN("DIR MLSD "); -#if ESP8266 - if(dir.next()) -#else - File fileDir = dir.openNextFile(); - if(fileDir) -#endif - { - DEBUG_PRINTLN("DIR NEXT "); - char dtStr[15]; + DEBUG_PRINTLN("DIR MLSD "); + #if ESP8266 + if( dir.next()) + #else + File fileDir = dir.openNextFile(); + if( fileDir ) + #endif + { + DEBUG_PRINTLN("DIR NEXT "); + char dtStr[ 15 ]; - struct tm* timeinfo; + struct tm * timeinfo; -#if ESP8266 - time_t time = dir.fileTime(); -#else - time_t time = fileDir.getLastWrite(); -#endif + #if ESP8266 + time_t time = dir.fileTime(); + #else + time_t time = fileDir.getLastWrite(); + #endif - timeinfo = localtime(&time); + timeinfo = localtime ( &time ); - // 2000 01 01 16 06 56 + // 2000 01 01 16 06 56 - strftime(dtStr, 15, "%Y%m%d%H%M%S", timeinfo); + strftime (dtStr,15,"%Y%m%d%H%M%S",timeinfo); -#if ESP8266 - String fn = dir.fileName(); - fn.remove(0, fn.lastIndexOf("/") + 1); - long fz = dir.fileSize(); -#else - String fn = fileDir.name(); - fn.remove(0, fn.lastIndexOf("/") + 1); - long fz = fileDir.size(); -#endif - data.print(F("Type=")); + #if ESP8266 + String fn = dir.fileName(); + fn.remove(0, fn.lastIndexOf("/")+1); + long fz = dir.fileSize(); + #else + String fn = fileDir.name(); + fn.remove(0, fn.lastIndexOf("/")+1); + long fz = fileDir.size(); + #endif - data.print(F("file")); - data.print(F(";Modify=")); - data.print(dtStr); // data.print( makeDateTimeStr( dtStr, time, time) ); - data.print(F(";Size=")); - data.print(fz); - data.print(F("; ")); - data.println(fn); + data.print( F("Type=") ); - DEBUG_PRINT(F("Type=")); - DEBUG_PRINT(F("file")); + data.print( F("file") ); + data.print( F(";Modify=") ); data.print(dtStr);// data.print( makeDateTimeStr( dtStr, time, time) ); + data.print( F(";Size=") ); data.print( fz ); + data.print( F("; ") ); data.println( fn ); - DEBUG_PRINT(F(";Modify=")); - DEBUG_PRINT(dtStr); // DEBUG_PRINT( makeDateTimeStr( dtStr, time, time) ); - DEBUG_PRINT(F(";Size=")); - DEBUG_PRINT(fz); - DEBUG_PRINT(F("; ")); - DEBUG_PRINTLN(fn); + // DEBUG_PRINT( F("Type=") ); + // DEBUG_PRINT( F("file") ); - nbMatch++; - return true; - } + // DEBUG_PRINT( F(";Modify=") ); DEBUG_PRINT(dtStr); //DEBUG_PRINT( makeDateTimeStr( dtStr, time, time) ); + // DEBUG_PRINT( F(";Size=") ); DEBUG_PRINT( fz ); + // DEBUG_PRINT( F("; ") ); DEBUG_PRINTLN( fn ); + + DEBUG_PRINT( F("Type=file;Modify=%s;Size=%d;%s"),dtStr,fz,fn.c_str()); + + nbMatch ++; + return true; + } #elif STORAGE_TYPE == STORAGE_LITTLEFS || STORAGE_TYPE == STORAGE_SEEED_SD || STORAGE_TYPE == STORAGE_FFAT - DEBUG_PRINTLN("DIR MLSD "); -#if ESP8266 - if(dir.next()) -#else + // DEBUG_PRINTLN("DIR MLSD "); + #if defined(ESP8266) || defined(ARDUINO_ARCH_RP2040) + if( dir.next()) + #else #if STORAGE_TYPE == STORAGE_SEEED_SD - File fileDir = STORAGE_MANAGER.open(dir.name()); - fileDir = dir.openNextFile(); + File fileDir = STORAGE_MANAGER.open(dir.name()); + fileDir = dir.openNextFile(); #else - File fileDir = dir.openNextFile(); + File fileDir = dir.openNextFile(); #endif - DEBUG_PRINTLN(dir); - DEBUG_PRINTLN(fileDir); - if(fileDir) -#endif - { - DEBUG_PRINTLN("DIR NEXT "); - char dtStr[15]; + // DEBUG_PRINTLN(dir); + // DEBUG_PRINTLN(fileDir); + if( fileDir ) + #endif + { + // DEBUG_PRINTLN("DIR NEXT "); + char dtStr[ 15 ]; -#if STORAGE_TYPE == STORAGE_SEEED_SD - struct tm* timeinfo; - strcpy(dtStr, "19700101000000"); -#else - struct tm* timeinfo; + #if STORAGE_TYPE == STORAGE_SEEED_SD + struct tm * timeinfo; -#if ESP8266 - time_t time = dir.fileTime(); -#else - time_t time = fileDir.getLastWrite(); -#endif + strcpy(dtStr, "19700101000000"); + #else + struct tm * timeinfo; - timeinfo = localtime(&time); + #if defined(ESP8266) || defined(ARDUINO_ARCH_RP2040) + time_t time = dir.fileTime(); + #else + time_t time = fileDir.getLastWrite(); + #endif - // 2000 01 01 16 06 56 + timeinfo = localtime ( &time ); - strftime(dtStr, 15, "%Y%m%d%H%M%S", timeinfo); -#endif + // 2000 01 01 16 06 56 -#if ESP8266 - String fn = dir.fileName(); - long fz = dir.fileSize(); - FTP_DIR fileDir = dir; -#elif STORAGE_TYPE == STORAGE_SEEED_SD - String fn = fileDir.name(); - fn.remove(0, strlen(dir.name())); - if(fn[0] == '/') { - fn.remove(0, fn.lastIndexOf("/") + 1); - } - long fz = fileDir.size(); -#else - String fn = fileDir.name(); - fn.remove(0, fn.lastIndexOf("/") + 1); - long fz = fileDir.size(); -#endif + strftime (dtStr,15,"%Y%m%d%H%M%S",timeinfo); + #endif - data.print(F("Type=")); + #if defined(ESP8266) || defined(ARDUINO_ARCH_RP2040) + String fn = dir.fileName(); + long fz = dir.fileSize(); + FTP_DIR fileDir = dir; + #elif STORAGE_TYPE == STORAGE_SEEED_SD + String fn = fileDir.name(); + fn.remove(0, strlen(dir.name())); + if (fn[0]=='/') { fn.remove(0, fn.lastIndexOf("/")+1); } + long fz = fileDir.size(); + #else + String fn = fileDir.name(); + fn.remove(0, fn.lastIndexOf("/")+1); + long fz = fileDir.size(); + #endif - data.print((fileDir.isDirectory() ? F("dir") : F("file"))); - data.print(F(";Modify=")); - data.print(dtStr); // data.print( makeDateTimeStr( dtStr, time, time) ); - data.print(F(";Size=")); - data.print(fz); - data.print(F("; ")); - data.println(fn); + data.print( F("Type=") ); - DEBUG_PRINT(F("Type=")); - DEBUG_PRINT((fileDir.isDirectory() ? F("dir") : F("file"))); + data.print( ( fileDir.isDirectory() ? F("dir") : F("file")) ); + data.print( F(";Modify=") ); data.print(dtStr);// data.print( makeDateTimeStr( dtStr, time, time) ); + data.print( F(";Size=") ); data.print( fz ); + data.print( F("; ") ); data.println( fn ); - DEBUG_PRINT(F(";Modify=")); - DEBUG_PRINT(dtStr); // DEBUG_PRINT( makeDateTimeStr( dtStr, time, time) ); - DEBUG_PRINT(F(";Size=")); - DEBUG_PRINT(fz); - DEBUG_PRINT(F("; ")); - DEBUG_PRINTLN(fn); + DEBUG_PRINT( F("Type=%s;Modify=%s;Size=%d;%s"),fileDir.isDirectory() ? "dir" : "file",dtStr,fz,fn.c_str()); - nbMatch++; + nbMatch ++; // RoSchmi: next line was commented #if STORAGE_TYPE == STORAGE_SEEED_SD - fileDir.close(); + fileDir.close(); #endif - return true; - } + return true; + } -#elif STORAGE_TYPE == STORAGE_SD - DEBUG_PRINTLN("DIR MLSD "); - File fileDir = dir.openNextFile(); - if(fileDir) { - DEBUG_PRINTLN("DIR NEXT "); - char dtStr[15]; +#elif STORAGE_TYPE == STORAGE_SD || STORAGE_TYPE == STORAGE_SD_MMC + DEBUG_PRINTLN("DIR MLSD "); + File fileDir = dir.openNextFile(); + if( fileDir ) + { + DEBUG_PRINTLN("DIR NEXT "); + char dtStr[ 15 ]; - struct tm* timeinfo; + struct tm * timeinfo; - strcpy(dtStr, "19700101000000"); + strcpy(dtStr, "19700101000000"); - // long fz = dir.fileSize(); - String fn = fileDir.name(); - //#ifdef ESP32 - fn.remove(0, fn.lastIndexOf("/") + 1); - //#else if !defined(ESP8266) - // fn.remove(0, 1); - //#endif +// long fz = dir.fileSize(); + String fn = fileDir.name(); - long fz = fileDir.size(); +//#ifdef ESP32 + fn.remove(0, fn.lastIndexOf("/")+1); +//#else if !defined(ESP8266) +// fn.remove(0, 1); +//#endif - data.print(F("Type=")); - data.print((fileDir.isDirectory() ? F("dir") : F("file"))); - data.print(F(";Modify=")); - data.print(dtStr); // data.print( makeDateTimeStr( dtStr, time, time) ); - data.print(F(";Size=")); - data.print(fz); - data.print(F("; ")); - data.println(fn); + long fz = fileDir.size(); - DEBUG_PRINT(F("Type=")); - DEBUG_PRINT((fileDir.isDirectory() ? F("dir") : F("file"))); + data.print( F("Type=") ); - DEBUG_PRINT(F(";Modify=")); - DEBUG_PRINT(dtStr); // DEBUG_PRINT( makeDateTimeStr( dtStr, time, time) ); - DEBUG_PRINT(F(";Size=")); - DEBUG_PRINT(fz); - DEBUG_PRINT(F("; ")); - DEBUG_PRINTLN(fn); + data.print( ( fileDir.isDirectory() ? F("dir") : F("file")) ); + data.print( F(";Modify=") ); data.print(dtStr);// data.print( makeDateTimeStr( dtStr, time, time) ); + data.print( F(";Size=") ); data.print( fz ); + data.print( F("; ") ); data.println( fn ); - nbMatch++; - return true; - } + DEBUG_PRINT( F("Type=") ); + DEBUG_PRINT( ( fileDir.isDirectory() ? F("dir") : F("file")) ); + + DEBUG_PRINT( F(";Modify=") ); DEBUG_PRINT(dtStr); //DEBUG_PRINT( makeDateTimeStr( dtStr, time, time) ); + DEBUG_PRINT( F(";Size=") ); DEBUG_PRINT( fz ); + DEBUG_PRINT( F("; ") ); DEBUG_PRINTLN( fn ); + + nbMatch ++; + return true; + } #elif STORAGE_TYPE == STORAGE_FATFS - if(dir.nextFile()) { - char dtStr[15]; - data.print(F("Type=")); - data.print((dir.isDir() ? F("dir") : F("file"))); - data.print(F(";Modify=")); - data.print(makeDateTimeStr(dtStr, dir.fileModDate(), dir.fileModTime())); - data.print(F(";Size=")); - data.print(long(dir.fileSize())); - data.print(F("; ")); - data.println(dir.fileName()); - nbMatch++; - return true; - } + if( dir.nextFile()) + { + char dtStr[ 15 ]; + data.print( F("Type=") ); data.print( ( dir.isDir() ? F("dir") : F("file")) ); + data.print( F(";Modify=") ); data.print( makeDateTimeStr( dtStr, dir.fileModDate(), dir.fileModTime()) ); + data.print( F(";Size=") ); data.print( long( dir.fileSize()) ); + data.print( F("; ") ); data.println( dir.fileName() ); + nbMatch ++; + return true; + } #else - if(file.openNext(&dir, FTP_FILE_READ_ONLY)) { - char dtStr[15]; - uint16_t filelwd, filelwt; - bool gfmt = getFileModTime(&filelwd, &filelwt); - DEBUG_PRINT("gfmt --> "); - DEBUG_PRINTLN(gfmt); - if(gfmt) { - data.print(F("Type=")); - data.print((file.isDir() ? F("dir") : F("file"))); - data.print(F(";Modify=")); - data.print(makeDateTimeStr(dtStr, filelwd, filelwt)); - data.print(F(";Size=")); - data.print(long(fileSize(file))); - data.print(F("; ")); - file.printName(&data); - data.println(); + if( file.openNext( &dir, FTP_FILE_READ_ONLY )) + { + char dtStr[ 15 ]; + uint16_t filelwd, filelwt; + bool gfmt = getFileModTime( & filelwd, & filelwt ); + DEBUG_PRINT("gfmt --> "); + DEBUG_PRINTLN(gfmt); + if( gfmt ) + { + data.print( F("Type=") ); data.print( ( file.isDir() ? F("dir") : F("file")) ); + data.print( F(";Modify=") ); data.print( makeDateTimeStr( dtStr, filelwd, filelwt ) ); + data.print( F(";Size=") ); data.print( long( fileSize( file )) ); data.print( F("; ") ); + file.printName( & data ); + data.println(); - DEBUG_PRINT(F("Type=")); - DEBUG_PRINT((file.isDir() ? F("dir") : F("file"))); - DEBUG_PRINT(F(";Modify=")); - DEBUG_PRINT(makeDateTimeStr(dtStr, filelwd, filelwt)); - DEBUG_PRINT(F(";Size=")); - DEBUG_PRINT(long(fileSize(file))); - DEBUG_PRINT(F("; ")); - // DEBUG_PRINT(file.name()); - DEBUG_PRINTLN(); - nbMatch++; - } - file.close(); - return gfmt; + DEBUG_PRINT( F("Type=") ); DEBUG_PRINT( ( file.isDir() ? F("dir") : F("file")) ); + DEBUG_PRINT( F(";Modify=") ); DEBUG_PRINT( makeDateTimeStr( dtStr, filelwd, filelwt ) ); + DEBUG_PRINT( F(";Size=") ); DEBUG_PRINT( long( fileSize( file )) ); DEBUG_PRINT( F("; ") ); +// DEBUG_PRINT(file.name()); + DEBUG_PRINTLN(); + nbMatch ++; } + file.close(); + return gfmt; + } #endif - client.println(F("226-options: -a -l")); - client.print(F("226 ")); - client.print(nbMatch); - client.println(F(" matches total")); -#if STORAGE_TYPE != STORAGE_SPIFFS && STORAGE_TYPE != STORAGE_LITTLEFS && STORAGE_TYPE != STORAGE_SEEED_SD && \ - STORAGE_TYPE != STORAGE_SEEED_SD + client.println(F("226-options: -a -l") ); + client.print( F("226 ") ); client.print( nbMatch ); client.println( F(" matches total") ); +#if STORAGE_TYPE != STORAGE_SPIFFS && STORAGE_TYPE != STORAGE_LITTLEFS && STORAGE_TYPE != STORAGE_SEEED_SD && STORAGE_TYPE != STORAGE_SEEED_SD dir.close(); #endif - data.stop(); - DEBUG_PRINTLN(F("All file readed!!")); - return false; + data.stop(); + // DEBUG_PRINTLN(F("All file readed!!")); + return false; } void FtpServer::closeTransfer() { - uint32_t deltaT = (int32_t)(millis() - millisBeginTrans); - if(deltaT > 0 && bytesTransfered > 0) { - DEBUG_PRINT(F(" Transfer completed in ")); - DEBUG_PRINT(deltaT); - DEBUG_PRINTLN(F(" ms, ")); - DEBUG_PRINT(bytesTransfered / deltaT); - DEBUG_PRINTLN(F(" kbytes/s")); + uint32_t deltaT = (int32_t) ( millis() - millisBeginTrans ); + if( deltaT > 0 && bytesTransfered > 0 ) + { + // DEBUG_PRINT( F(" Transfer completed in ") ); DEBUG_PRINT( deltaT ); DEBUG_PRINTLN( F(" ms, ") ); + // DEBUG_PRINT( bytesTransfered / deltaT ); DEBUG_PRINTLN( F(" kbytes/s") ); - if(FtpServer::_transferCallback) { - FtpServer::_transferCallback(FTP_TRANSFER_STOP, getFileName(&file), bytesTransfered); - } + // DEBUG_PRINT( F(" Transfer completed in %d ms, %d kbytes/s"), deltaT, bytesTransfered / deltaT ); - client.println(F("226-File successfully transferred")); - client.print(F("226 ")); - client.print(deltaT); - client.print(F(" ms, ")); - client.print(bytesTransfered / deltaT); - client.println(F(" kbytes/s")); - } else - client.println(F("226 File successfully transferred")); + if (FtpServer::_transferCallback) { + FtpServer::_transferCallback(FTP_TRANSFER_STOP, getFileName(&file), bytesTransfered); + } - file.close(); - data.stop(); + + client.println(F("226-File successfully transferred") ); + client.print( F("226 ") ); client.print( deltaT ); client.print( F(" ms, ") ); + client.print( bytesTransfered / deltaT ); client.println( F(" kbytes/s") ); + } + else + client.println(F("226 File successfully transferred") ); + + file.close(); + data.stop(); } void FtpServer::abortTransfer() { - if(transferStage != FTP_Close) { - if(FtpServer::_transferCallback) { - FtpServer::_transferCallback(FTP_TRANSFER_ERROR, getFileName(&file), bytesTransfered); - } + if( transferStage != FTP_Close ) + { + if (FtpServer::_transferCallback) { + FtpServer::_transferCallback(FTP_TRANSFER_ERROR, getFileName(&file), bytesTransfered); + } - file.close(); + file.close(); #if STORAGE_TYPE != STORAGE_SPIFFS && STORAGE_TYPE != STORAGE_LITTLEFS && STORAGE_TYPE != STORAGE_SEEED_SD - dir.close(); + dir.close(); #endif - client.println(F("426 Transfer aborted")); - DEBUG_PRINTLN(F(" Transfer aborted!")); + client.println(F("426 Transfer aborted") ); + DEBUG_PRINTLN( F(" Transfer aborted!") ); - transferStage = FTP_Close; - } - // if( data.connected()) - data.stop(); + transferStage = FTP_Close; + } +// if( data.connected()) + data.stop(); } // Read a char from client connected to ftp server @@ -1629,69 +1771,154 @@ void FtpServer::abortTransfer() // -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 +// length of cmdLine (positive) if no empty line received int8_t FtpServer::readChar() { - int8_t rc = -1; + int8_t rc = -1; - if(client.available()) { - char c = client.read(); - DEBUG_PRINT("-"); - DEBUG_PRINT(c); + if( client.available()) + { + char c = client.read(); + // DEBUG_PRINT("-"); + // DEBUG_PRINT( 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( 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.println(F("500 Syntax error")); - } + } } - return rc; + if( rc > 0 ) + for( uint8_t i = 0 ; i < strlen( command ); i ++ ) + command[ i ] = toupper( command[ i ] ); + if( rc == -2 ) + { + iCL = 0; + client.println(F("500 Syntax error")); + } + } + return rc; } bool FtpServer::haveParameter() { - if(parameter != NULL && strlen(parameter) > 0) return true; - client.println("501 No file name"); - return false; + if( parameter != NULL && strlen( parameter ) > 0 ) + return true; + client.println("501 No file name" ); + return false; } +int utf8_strlen(const String& str) +{ + int c,i,ix,q; + for (q=0, i=0, ix=str.length(); i < ix; i++, q++) + { + c = (unsigned char) str[i]; + if (c>=0 && c<=127) i+=0; + else if ((c & 0xE0) == 0xC0) i+=1; + else if ((c & 0xF0) == 0xE0) i+=2; + else if ((c & 0xF8) == 0xF0) i+=3; + //else if (($c & 0xFC) == 0xF8) i+=4; // 111110bb //byte 5, unnecessary in 4 byte UTF-8 + //else if (($c & 0xFE) == 0xFC) i+=5; // 1111110b //byte 6, unnecessary in 4 byte UTF-8 + else return 0;//invalid utf8 + } + return q; +} + +//// ****** UTF8-Decoder: convert UTF8-string to extended ASCII ******* +//static byte c1; // Last character buffer +// +//// Convert a single Character from UTF8 to Extended ASCII +//// Return "0" if a byte has to be ignored +//byte utf8ascii(byte ascii) { +// if ( ascii<128 ) // Standard ASCII-set 0..0x7F handling +// { c1=0; +// return( ascii ); +// } +// +// // get previous input +// byte last = c1; // get last char +// c1=ascii; // remember actual character +// +// switch (last) // conversion depending on first UTF8-character +// { case 0xC2: return (ascii); break; +// case 0xC3: return (ascii | 0xC0); break; +// case 0x82: if(ascii==0xAC) return(0x80); // special case Euro-symbol +// } +// +// return (0); // otherwise: return zero, if character has to be ignored +//} +// +//// convert String object from UTF8 String to Extended ASCII +//String utf8ascii(String s) +//{ +// String r=""; +// char c; +// for (int i=0; i 1) fullName[strl] = 0; - if(strlen(fullName) >= FTP_CWD_SIZE) { - client.println(F("500 Command line too long")); - return false; - } - for(uint8_t i = 0; i < strlen(fullName); i++) - if(!legalChar(fullName[i])) { - client.println(F("553 File name not allowed")); - return false; - } + 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.println(F("500 Command line too long")); + return false; + } +#ifdef UTF8_SUPPORT +// for( uint8_t i = 0; i < utf8_strlen( fullName ); i ++ ) { +// +// } + + +// DEBUG_PRINT(F("utf8_strlen2")); +// DEBUG_PRINTLN(utf8_strlen2(fullName)); + + if (utf8_strlen(fullName)>=FILENAME_LENGTH) { + DEBUG_PRINT(F("utf8_strlen %d"),utf8_strlen(fullName)); + client.println(F("553 File name not allowed. Too long.") ); + return false; + } +#else + for( uint8_t i = 0; i < strlen( fullName ); i ++ ) { + if( ! legalChar( fullName[i])) + { + client.println(F("553 File name not allowed") ); + return false; + } + } + if (strlen(fullName)>=FILENAME_LENGTH) { + client.println(F("553 File name not allowed. Too long.") ); + return false; + } +#endif + return true; } -bool FtpServer::makeExistsPath(char* path, char* param) +bool FtpServer::makeExistsPath( char * path, char * param ) { - if(!makePath(path, param)) return false; - // RoSchmi - //#if STORAGE_TYPE == STORAGE_SPIFFS || STORAGE_TYPE == STORAGE_SD -#if(STORAGE_TYPE == STORAGE_SPIFFS || STORAGE_TYPE == STORAGE_SD || STORAGE_TYPE == STORAGE_SEEED_SD) - if(strcmp(path, "/") == 0) return true; -#endif - DEBUG_PRINT("PATH --> ") - DEBUG_PRINT(path) - if(exists(path)) { - DEBUG_PRINTLN(" ...EXIST!") - return true; - } - DEBUG_PRINTLN(" ...NOT EXIST!") - client.print(F("550 ")); - client.print(path); - client.println(F(" not found.")); + if( ! makePath( path, param )) return false; + // RoSchmi + //#if STORAGE_TYPE == STORAGE_SPIFFS || STORAGE_TYPE == STORAGE_SD +#if (STORAGE_TYPE == STORAGE_SPIFFS || STORAGE_TYPE == STORAGE_SD || STORAGE_TYPE == STORAGE_SD_MMC || STORAGE_TYPE == STORAGE_SEEED_SD) + if (strcmp(path, "/") == 0) return true; +#endif + DEBUG_PRINT("PATH %s %s",path,exists( path )?"found":"not found"); + // DEBUG_PRINT(path) + if( exists( path )) { + // DEBUG_PRINTLN(" ...EXIST!") + return true; + } + // DEBUG_PRINTLN(" ...NOT EXIST!") + client.print(F("550 ")); client.print( path ); client.println( F(" not found.") ); + return false; } // Calculate year, month, day, hour, minute and second @@ -1771,352 +2026,334 @@ bool FtpServer::makeExistsPath(char* path, char* param) // 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 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++; + 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 ); + // DEBUG_PRINT( F(" Modification time: ") ); DEBUG_PRINT( * pyear ); DEBUG_PRINT( F("/") ); DEBUG_PRINT( int(* pmonth) ); DEBUG_PRINT( F("/") ); DEBUG_PRINT( int(* pday) ); + // DEBUG_PRINT( F(" ") ); DEBUG_PRINT( int(* phour) ); DEBUG_PRINT( F(":") ); DEBUG_PRINT( int(* pminute) ); DEBUG_PRINT( F(":") ); DEBUG_PRINT( int(* psecond) ); + // DEBUG_PRINT( F(" of file: ") ); DEBUG_PRINTLN( (char *) ( parameter + 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); - DEBUG_PRINT(F(" Modification time: ")); - DEBUG_PRINT(*pyear); - DEBUG_PRINT(F("/")); - DEBUG_PRINT(int(*pmonth)); - DEBUG_PRINT(F("/")); - DEBUG_PRINT(int(*pday)); - DEBUG_PRINT(F(" ")); - DEBUG_PRINT(int(*phour)); - DEBUG_PRINT(F(":")); - DEBUG_PRINT(int(*pminute)); - DEBUG_PRINT(F(":")); - DEBUG_PRINT(int(*psecond)); - DEBUG_PRINT(F(" of file: ")); - DEBUG_PRINTLN((char*)(parameter + i)); - - return i; + return i; } // Create string YYYYMMDDHHMMSS from date and time // // parameters: -// date, time +// date, time // tstr: where to store the string. Must be at least 15 characters long // // return: // pointer to tstr -char* FtpServer::makeDateTimeStr(char* tstr, uint16_t date, uint16_t time) +char * FtpServer::makeDateTimeStr( char * tstr, uint16_t date, uint16_t time ) { - sprintf(tstr, "%04u%02u%02u%02u%02u%02u", ((date & 0xFE00) >> 9) + 1980, (date & 0x01E0) >> 5, date & 0x001F, - (time & 0xF800) >> 11, (time & 0x07E0) >> 5, (time & 0x001F) << 1); - return tstr; + sprintf( tstr, "%04u%02u%02u%02u%02u%02u", + (( date & 0xFE00 ) >> 9 ) + 1980, ( date & 0x01E0 ) >> 5, date & 0x001F, + ( time & 0xF800 ) >> 11, ( time & 0x07E0 ) >> 5, ( time & 0x001F ) << 1 ); + return tstr; } -uint16_t FtpServer::fileSize(FTP_FILE file) -{ -#if(STORAGE_TYPE == STORAGE_SPIFFS || STORAGE_TYPE == STORAGE_LITTLEFS || STORAGE_TYPE == STORAGE_FFAT || \ - STORAGE_TYPE == STORAGE_SD || STORAGE_TYPE == STORAGE_SEEED_SD) - return file.size(); + +uint32_t FtpServer::fileSize( FTP_FILE file ) { +#if (STORAGE_TYPE == STORAGE_SPIFFS || STORAGE_TYPE == STORAGE_LITTLEFS || STORAGE_TYPE == STORAGE_FFAT || STORAGE_TYPE == STORAGE_SD || STORAGE_TYPE == STORAGE_SD_MMC || STORAGE_TYPE == STORAGE_SEEED_SD) + return file.size(); #else - return file.fileSize(); + return file.fileSize(); #endif } -#if(STORAGE_TYPE == STORAGE_SEEED_SD) -bool FtpServer::openFile(char path[FTP_CWD_SIZE], int readTypeInt) -{ - DEBUG_PRINT(F("File to open ")); - DEBUG_PRINT(path); - DEBUG_PRINT(F(" readType ")); - DEBUG_PRINTLN(readTypeInt); +#if (STORAGE_TYPE == STORAGE_SEEED_SD) + bool FtpServer::openFile( char path[ FTP_CWD_SIZE ], int readTypeInt ){ + DEBUG_PRINT(F("File to open ") ); + DEBUG_PRINT( path ); + DEBUG_PRINT(F(" readType ") ); + DEBUG_PRINTLN(readTypeInt); - if(readTypeInt == 0X01) { - readTypeInt = FILE_READ; - } else { - readTypeInt = FILE_WRITE; - } + if (readTypeInt == 0X01) { + readTypeInt = FILE_READ; + }else { + readTypeInt = FILE_WRITE; + } - file = STORAGE_MANAGER.open(path, readTypeInt); - if(!file) { // && readTypeInt[0]==FILE_READ) { - return false; - } else { - DEBUG_PRINTLN("TRUE"); + file = STORAGE_MANAGER.open( path, readTypeInt ); + if (!file) { // && readTypeInt[0]==FILE_READ) { + return false; + }else{ + // DEBUG_PRINTLN("TRUE"); - return true; - } + return true; + } } -#elif(STORAGE_TYPE == STORAGE_SD && defined(ESP8266)) // FTP_SERVER_NETWORK_TYPE_SELECTED == NETWORK_ESP8266_242) -bool FtpServer::openFile(char path[FTP_CWD_SIZE], int readTypeInt) -{ - DEBUG_PRINT(F("File to open ")); - DEBUG_PRINT(path); - DEBUG_PRINT(F(" readType ")); - DEBUG_PRINTLN(readTypeInt); +#elif ((STORAGE_TYPE == STORAGE_SD || STORAGE_TYPE == STORAGE_SD_MMC) && defined(ESP8266))// FTP_SERVER_NETWORK_TYPE_SELECTED == NETWORK_ESP8266_242) + bool FtpServer::openFile( char path[ FTP_CWD_SIZE ], int readTypeInt ){ + DEBUG_PRINT(F("File to open ") ); + DEBUG_PRINT( path ); + DEBUG_PRINT(F(" readType ") ); + DEBUG_PRINTLN(readTypeInt); - if(readTypeInt == 0X01) { - readTypeInt = FILE_READ; - } else { - readTypeInt = FILE_WRITE; - } + if (readTypeInt == 0X01) { + readTypeInt = FILE_READ; + }else { + readTypeInt = FILE_WRITE; + } - file = STORAGE_MANAGER.open(path, readTypeInt); - if(!file) { // && readTypeInt[0]==FILE_READ) { - return false; - } else { - DEBUG_PRINTLN("TRUE"); + file = STORAGE_MANAGER.open( path, readTypeInt ); + if (!file) { // && readTypeInt[0]==FILE_READ) { + return false; + }else{ + DEBUG_PRINTLN("TRUE"); - return true; - } + return true; + } } -#elif(STORAGE_TYPE == STORAGE_SPIFFS || STORAGE_TYPE == STORAGE_LITTLEFS || STORAGE_TYPE == STORAGE_FFAT) -bool FtpServer::openFile(const char* path, const char* readType) -{ - DEBUG_PRINT(F("File to open ")); - DEBUG_PRINT(path); - DEBUG_PRINT(F(" readType ")); - DEBUG_PRINTLN(readType); - file = STORAGE_MANAGER.open(path, readType); - if(!file && readType[0] == 'r') { - return false; - } else { - DEBUG_PRINTLN("TRUE"); +#elif (STORAGE_TYPE == STORAGE_SPIFFS || STORAGE_TYPE == STORAGE_LITTLEFS || STORAGE_TYPE == STORAGE_FFAT ) + bool FtpServer::openFile( const char * path, const char * readType ) { + DEBUG_PRINT(F("File to open %s"), path ); + // DEBUG_PRINT( path ); + // DEBUG_PRINT(F(" readType ") ); + // DEBUG_PRINTLN(readType); + file = STORAGE_MANAGER.open( path, readType ); + if (!file && readType[0]=='r') { + return false; + }else{ + // DEBUG_PRINTLN("TRUE"); - return true; - } -} -#elif STORAGE_TYPE <= STORAGE_SDFAT2 -bool FtpServer::openFile(char path[FTP_CWD_SIZE], int readTypeInt) -{ - DEBUG_PRINT(F("File to open ")); - DEBUG_PRINT(path); - DEBUG_PRINT(F(" readType ")); - DEBUG_PRINTLN(readTypeInt); + return true; + } + } +#elif STORAGE_TYPE <= STORAGE_SDFAT2 || STORAGE_TYPE == STORAGE_SPIFM || ((STORAGE_TYPE == STORAGE_SD || STORAGE_TYPE == STORAGE_SD_MMC) && ARDUINO_ARCH_SAMD) + bool FtpServer::openFile( char path[ FTP_CWD_SIZE ], int readTypeInt ){ + DEBUG_PRINT(F("File to open ") ); + DEBUG_PRINT( path ); + DEBUG_PRINT(F(" readType ") ); + DEBUG_PRINTLN(readTypeInt); - file = STORAGE_MANAGER.open(path, readTypeInt); - if(!file) { - return false; - } else { - DEBUG_PRINTLN("TRUE"); + file = STORAGE_MANAGER.open( path, readTypeInt ); + if (!file) { + return false; + }else{ + DEBUG_PRINTLN("TRUE"); - return true; - } + return true; + } } #else -bool FtpServer::openFile(char path[FTP_CWD_SIZE], const char* readType) -{ - return openFile((const char*)path, readType); -} -bool FtpServer::openFile(const char* path, const char* readType) -{ - DEBUG_PRINT(F("File to open ")); - DEBUG_PRINT(path); - DEBUG_PRINT(F(" readType ")); - DEBUG_PRINTLN(readType); -#if(STORAGE_TYPE == STORAGE_SD && !defined(ESP32)) - if(readType == 0X01) { - readType = FILE_READ; - } else { - readType = FILE_WRITE; - } -#endif - file = STORAGE_MANAGER.open(path, readType); - if(!file && readType[0] == 'r') { - return false; - } else { - DEBUG_PRINTLN("TRUE"); + bool FtpServer::openFile( char path[ FTP_CWD_SIZE ], const char * readType ) { + return openFile( (const char*) path, readType ); + } + bool FtpServer::openFile( const char * path, const char * readType ) { + DEBUG_PRINT(F("File to open ") ); + DEBUG_PRINT( path ); + DEBUG_PRINT(F(" readType ") ); + DEBUG_PRINTLN(readType); + #if ((STORAGE_TYPE == STORAGE_SD || STORAGE_TYPE == STORAGE_SD_MMC) && !defined(ESP32)) + if (readType == 0X01) { + readType = FILE_READ; + }else { + readType = FILE_WRITE; + } + #endif + file = STORAGE_MANAGER.open( path, readType ); + if (!file && readType[0]=='r') { + return false; + }else{ + DEBUG_PRINTLN("TRUE"); - return true; - } -} + return true; + } + } #endif // Return true if path points to a directory -bool FtpServer::isDir(char* path) +bool FtpServer::isDir( char * path ) { -#if(STORAGE_TYPE == STORAGE_LITTLEFS && defined(ESP8266)) - FTP_DIR dir; - bool res; - dir = STORAGE_MANAGER.openDir(path); +#if (STORAGE_TYPE == STORAGE_LITTLEFS && (defined(ESP8266) || defined(ARDUINO_ARCH_RP2040))) + FTP_DIR dir; + bool res; + dir = STORAGE_MANAGER.openDir( path ); - return true; - // res = dir.isDirectory(); - // return res; + res = true; + return res; -#elif STORAGE_TYPE == STORAGE_SPIFFS - if(strcmp(path, "/") == 0) { - return true; - } - return false; // no directory support -#elif STORAGE_TYPE == STORAGE_SEEED_SD || STORAGE_TYPE == STORAGE_FFAT || \ - (STORAGE_TYPE == STORAGE_LITTLEFS && defined(ESP32)) - FTP_DIR dir; - bool res; - dir = STORAGE_MANAGER.open(path); + #elif STORAGE_TYPE == STORAGE_SPIFFS + if (strcmp(path, "/") == 0) { return true; } + return false; // no directory support +#elif STORAGE_TYPE == STORAGE_SEEED_SD || STORAGE_TYPE == STORAGE_FFAT || (STORAGE_TYPE == STORAGE_LITTLEFS && defined(ESP32)) + FTP_DIR dir; + bool res; + dir = STORAGE_MANAGER.open( path ); - // return true; - res = dir.isDirectory(); - return res; +// return true; + res = dir.isDirectory(); + return res; #elif STORAGE_TYPE == STORAGE_FATFS - return STORAGE_MANAGER.isDir(path); + return STORAGE_MANAGER.isDir( path ); #elif STORAGE_TYPE == STORAGE_SDFAT1 || STORAGE_TYPE == STORAGE_SDFAT2 - // bool res = (!dir.open(path, FTP_FILE_READ) || !dir.isDir()); - // dir.close(); - // return res; - if(strcmp(path, "/") == 0) { - return true; +// bool res = (!dir.open(path, FTP_FILE_READ) || !dir.isDir()); +// dir.close(); +// return res; + if (strcmp(path, "/") == 0) { return true; } + if( ! openFile( path, FTP_FILE_READ )) { + return false; } - if(!openFile(path, FTP_FILE_READ)) { - return false; - } - return true; + return true; #else - FTP_FILE file; - bool res; - - if(!openFile(path, FTP_FILE_READ)) { - return false; - } -#if STORAGE_TYPE == STORAGE_SD - // if (strcmp(path, "/") == 0) return true; - // res = file.isDirectory(); - // DEBUG_PRINT(path); - // DEBUG_PRINT(" IS DIRECOTORY --> "); - // DEBUG_PRINTLN(res); - return true; + FTP_FILE file; + bool res; + + if( ! openFile( path, FTP_FILE_READ )) { + return false; + } +#if STORAGE_TYPE == STORAGE_SD || STORAGE_TYPE == STORAGE_SD_MMC +// if (strcmp(path, "/") == 0) return true; +// res = file.isDirectory(); +// DEBUG_PRINT(path); +// DEBUG_PRINT(" IS DIRECOTORY --> "); +// DEBUG_PRINTLN(res); + return true; #else // res = file.isDir(); // DEBUG_PRINT("IS DIRECTORY --> " ); // DEBUG_PRINTLN(res); #endif - file.close(); - return res; + file.close(); + return res; #endif } -bool FtpServer::timeStamp(char* path, uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, - uint8_t second) +bool FtpServer::timeStamp( char * path, uint16_t year, uint8_t month, uint8_t day, + uint8_t hour, uint8_t minute, uint8_t second ) { -#if STORAGE_TYPE == STORAGE_SPIFFS || STORAGE_TYPE == STORAGE_LITTLEFS || STORAGE_TYPE == STORAGE_FFAT || \ - STORAGE_TYPE == STORAGE_SD || STORAGE_TYPE == STORAGE_SEEED_SD - // struct tm tmDate = { second, minute, hour, day, month, year }; - // time_t rawtime = mktime(&tmDate); +#if STORAGE_TYPE == STORAGE_SPIFFS || STORAGE_TYPE == STORAGE_LITTLEFS || STORAGE_TYPE == STORAGE_FFAT || STORAGE_TYPE == STORAGE_SD || STORAGE_TYPE == STORAGE_SD_MMC || STORAGE_TYPE == STORAGE_SEEED_SD +// struct tm tmDate = { second, minute, hour, day, month, year }; +// time_t rawtime = mktime(&tmDate); return true; - // setTime(rawtime); - // SPIFFS USE time() call + // setTime(rawtime); + // SPIFFS USE time() call // return STORAGE_MANAGER.timeStamp( path, year, month, day, hour, minute, second ); #elif STORAGE_TYPE == STORAGE_FATFS - return STORAGE_MANAGER.timeStamp(path, year, month, day, hour, minute, second); + return STORAGE_MANAGER.timeStamp( path, year, month, day, hour, minute, second ); #else - FTP_FILE file; - bool res; + FTP_FILE file; + bool res; - if(!openFile(path, FTP_FILE_READ_WRITE)) return false; - res = file.timestamp(T_WRITE, year, month, day, hour, minute, second); - file.close(); - return res; + if( ! openFile( path, FTP_FILE_READ_WRITE )) + return false; + res = file.timestamp( T_WRITE, year, month, day, hour, minute, second ); + file.close(); + return res; #endif } - -bool FtpServer::getFileModTime(char* path, uint16_t* pdate, uint16_t* ptime) + +bool FtpServer::getFileModTime( char * path, uint16_t * pdate, uint16_t * ptime ) { #if STORAGE_TYPE == STORAGE_FATFS - return STORAGE_MANAGER.getFileModTime(path, pdate, ptime); + return STORAGE_MANAGER.getFileModTime( path, pdate, ptime ); #else - // FTP_FILE file; - bool res; +// FTP_FILE file; + bool res; - if(!openFile(path, FTP_FILE_READ)) { - return false; - } - res = getFileModTime(pdate, ptime); - file.close(); - return res; + if( ! openFile( path, FTP_FILE_READ )) { + return false; + } + res = getFileModTime( pdate, ptime ); + file.close(); + return res; #endif } // Assume SD library is SdFat (or family) and file is open - + #if STORAGE_TYPE != STORAGE_FATFS -bool FtpServer::getFileModTime(uint16_t* pdate, uint16_t* ptime) +bool FtpServer::getFileModTime( uint16_t * pdate, uint16_t * ptime ) { #if STORAGE_TYPE == STORAGE_SPIFFS || STORAGE_TYPE == STORAGE_LITTLEFS || STORAGE_TYPE == STORAGE_FFAT -#if ESP8266 - return dir.fileTime(); -#else - return dir.getLastWrite(); -#endif -#elif STORAGE_TYPE == STORAGE_SDFAT1 || STORAGE_TYPE == STORAGE_SPIFM - dir_t d; + #if defined(ESP8266) || defined(ARDUINO_ARCH_RP2040) + return dir.fileTime(); + #else + return dir.getLastWrite(); + #endif +#elif STORAGE_TYPE == STORAGE_SDFAT1 + dir_t d; - if(!file.dirEntry(&d)) return false; - *pdate = d.lastWriteDate; - *ptime = d.lastWriteTime; - return true; -#elif STORAGE_TYPE == STORAGE_SDFAT2 - return file.getModifyDateTime(pdate, ptime); -#endif + if( ! file.dirEntry( & d )) return false; + * pdate = d.lastWriteDate; + * ptime = d.lastWriteTime; + return true; +#elif STORAGE_TYPE == STORAGE_SDFAT2 || STORAGE_TYPE == STORAGE_SPIFM + return file.getModifyDateTime( pdate, ptime ); +#endif + return false; } #endif -#if STORAGE_TYPE == STORAGE_SD -bool FtpServer::rename(const char* path, const char* newpath) -{ +#if STORAGE_TYPE == STORAGE_SD || STORAGE_TYPE == STORAGE_SD_MMC + bool FtpServer::rename( const char * path, const char * newpath ){ - FTP_FILE myFileIn = STORAGE_MANAGER.open(path, FILE_READ); - FTP_FILE myFileOut = STORAGE_MANAGER.open(newpath, FILE_WRITE); + FTP_FILE myFileIn = STORAGE_MANAGER.open(path, FILE_READ); + FTP_FILE myFileOut = STORAGE_MANAGER.open(newpath, FILE_WRITE); - if(myFileOut) { - while(myFileIn.available() > 0) { - int i = myFileIn.readBytes((char*)buf, FTP_BUF_SIZE); - myFileOut.write(buf, i); - } - // done, close the destination file - myFileOut.close(); - myFileOut = STORAGE_MANAGER.open(newpath, FILE_READ); - } - bool operation = false; + if(myFileOut) { + while (myFileIn.available() > 0) + { + int i = myFileIn.readBytes((char*)buf, FTP_BUF_SIZE); + myFileOut.write(buf, i); + } + // done, close the destination file + myFileOut.close(); + myFileOut = STORAGE_MANAGER.open(newpath, FILE_READ); - DEBUG_PRINT(F("RENAME --> ")); - DEBUG_PRINT(myFileIn.size()); - DEBUG_PRINT(" size "); - DEBUG_PRINTLN(myFileOut.size()); + } + bool operation = false; - if(myFileIn.size() == myFileOut.size()) { - operation = true; - } + DEBUG_PRINT(F("RENAME --> ")); + DEBUG_PRINT(myFileIn.size()); + DEBUG_PRINT(" size "); + DEBUG_PRINTLN(myFileOut.size()); - if(!operation) return operation; + if (myFileIn.size() == myFileOut.size()) { + operation = true; + } - myFileIn.close(); - myFileOut.close(); - return remove(path); -}; + if (!operation) return operation; + + myFileIn.close(); + myFileOut.close(); + + return remove( path ); + }; #endif diff --git a/lib/SimpleFTPServer/FtpServer.h b/lib/SimpleFTPServer/FtpServer.h index ff6300eb..bd1c7b92 100644 --- a/lib/SimpleFTPServer/FtpServer.h +++ b/lib/SimpleFTPServer/FtpServer.h @@ -15,12 +15,15 @@ ** ** *******************************************************************************/ +#include + #ifndef FTP_SERVER_H #define FTP_SERVER_H -#define FTP_SERVER_VERSION "2021-11-09" +#define FTP_SERVER_VERSION "2.1.5 (2023-01-13)" + +#include "ArduinoLog.h" -#include #if ARDUINO >= 100 #include "Arduino.h" #else @@ -50,6 +53,12 @@ #elif defined(ESP32) #define FTP_SERVER_NETWORK_TYPE DEFAULT_FTP_SERVER_NETWORK_TYPE_ESP32 #define STORAGE_TYPE DEFAULT_STORAGE_TYPE_ESP32 + #elif defined(ARDUINO_ARCH_STM32) + #define FTP_SERVER_NETWORK_TYPE DEFAULT_FTP_SERVER_NETWORK_TYPE_STM32 + #define STORAGE_TYPE DEFAULT_STORAGE_TYPE_STM32 + #elif defined(ARDUINO_ARCH_RP2040) + #define FTP_SERVER_NETWORK_TYPE DEFAULT_FTP_SERVER_NETWORK_TYPE_RP2040 + #define STORAGE_TYPE DEFAULT_STORAGE_TYPE_RP2040 #elif defined(ARDUINO_ARCH_SAMD) #define FTP_SERVER_NETWORK_TYPE DEFAULT_FTP_SERVER_NETWORK_TYPE_SAMD #define STORAGE_TYPE DEFAULT_STORAGE_TYPE_SAMD @@ -89,72 +98,96 @@ // Includes and defined based on Network Type #if(FTP_SERVER_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) -// Note: -// No SSL/WSS support for client in Async mode -// TLS lib need a sync interface! + // Note: + // No SSL/WSS support for client in Async mode + // TLS lib need a sync interface! -#if defined(ESP8266) -#include -//#include -#elif defined(ESP32) -#include -//#include + #if defined(ESP8266) + #include + //#include + #define FTP_CLIENT_NETWORK_CLASS WiFiClient + //#define FTP_CLIENT_NETWORK_SSL_CLASS WiFiClientSecure + #define FTP_SERVER_NETWORK_SERVER_CLASS WiFiServer -#define FTP_CLIENT_NETWORK_CLASS WiFiClient -//#define FTP_CLIENT_NETWORK_SSL_CLASS WiFiClientSecure -#define FTP_SERVER_NETWORK_SERVER_CLASS WiFiServer + #elif defined(ESP32) + #include + //#include -#elif defined(ESP31B) -#include -#else -#error "network type ESP8266 ASYNC only possible on the ESP mcu!" -#endif + #define FTP_CLIENT_NETWORK_CLASS WiFiClient + //#define FTP_CLIENT_NETWORK_SSL_CLASS WiFiClientSecure + #define FTP_SERVER_NETWORK_SERVER_CLASS WiFiServer + #elif defined(ESP31B) + #include + + #define FTP_CLIENT_NETWORK_CLASS WiFiClient + //#define FTP_CLIENT_NETWORK_SSL_CLASS WiFiClientSecure + #define FTP_SERVER_NETWORK_SERVER_CLASS WiFiServer + #else + #error "network type ESP8266 ASYNC only possible on the ESP mcu!" + #endif #elif(FTP_SERVER_NETWORK_TYPE == NETWORK_ESP8266 || FTP_SERVER_NETWORK_TYPE == NETWORK_ESP8266_242) - #if !defined(ESP8266) && !defined(ESP31B) - #error "network type ESP8266 only possible on the ESP mcu!" + #if !defined(ESP8266) && !defined(ESP31B) + #error "network type ESP8266 only possible on the ESP mcu!" #endif #ifdef ESP8266 - #include + #include #else - #include + #include #endif #define FTP_CLIENT_NETWORK_CLASS WiFiClient //#define FTP_CLIENT_NETWORK_SSL_CLASS WiFiClientSecure #define FTP_SERVER_NETWORK_SERVER_CLASS WiFiServer #define NET_CLASS WiFi - #define CommandIs( a ) (command != NULL && ! strcmp_P( command, PSTR( a ))) - #define ParameterIs( a ) ( parameter != NULL && ! strcmp_P( parameter, PSTR( a ))) - #elif(FTP_SERVER_NETWORK_TYPE == NETWORK_W5100) +// #define CommandIs( a ) (command != NULL && ! strcmp_P( command, PSTR( a ))) +// #define ParameterIs( a ) ( parameter != NULL && ! strcmp_P( parameter, PSTR( a ))) +#elif(FTP_SERVER_NETWORK_TYPE == NETWORK_W5100 || FTP_SERVER_NETWORK_TYPE == NETWORK_ETHERNET_ENC) - #ifdef STM32_DEVICE - #define FTP_CLIENT_NETWORK_CLASS TCPClient - #define FTP_SERVER_NETWORK_SERVER_CLASS TCPServer - #define CommandIs( a ) ( ! strcmp_PF( command, PSTR( a ))) - #define ParameterIs( a ) ( ! strcmp_PF( parameter, PSTR( a ))) - #define NET_CLASS Ethernet - #else #include #include #define FTP_CLIENT_NETWORK_CLASS EthernetClient #define FTP_SERVER_NETWORK_SERVER_CLASS EthernetServer #define NET_CLASS Ethernet - #define CommandIs( a ) ( ! strcmp_PF( command, PSTR( a ))) - #define ParameterIs( a ) ( ! strcmp_PF( parameter, PSTR( a ))) - #endif -#elif(FTP_SERVER_NETWORK_TYPE == NETWORK_ENC28J60) +// #if defined(ESP8266) || defined(ESP32) +// #define CommandIs( a ) (command != NULL && ! strcmp_P( command, PSTR( a ))) +// #define ParameterIs( a ) ( parameter != NULL && ! strcmp_P( parameter, PSTR( a ))) +// #else +// #define CommandIs( a ) ( ! strcmp_PF( command, PSTR( a ))) +// #define ParameterIs( a ) ( ! strcmp_PF( parameter, PSTR( a ))) +// #endif +#elif(FTP_SERVER_NETWORK_TYPE == NETWORK_ENC28J60 || FTP_SERVER_NETWORK_TYPE == NETWORK_UIPETHERNET) #include #define FTP_CLIENT_NETWORK_CLASS UIPClient #define FTP_SERVER_NETWORK_SERVER_CLASS UIPServer #define NET_CLASS Ethernet - #define CommandIs( a ) ( ! strcmp_PF( command, PSTR( a ))) - #define ParameterIs( a ) ( ! strcmp_PF( parameter, PSTR( a ))) - //SSLClient client(base_client, TAs, (size_t)TAs_NUM, A5); +// #if define(ESP8266) || define(ESP32) +// #define CommandIs( a ) (command != NULL && ! strcmp_P( command, PSTR( a ))) +// #define ParameterIs( a ) ( parameter != NULL && ! strcmp_P( parameter, PSTR( a ))) +// #else +// #define CommandIs( a ) ( ! strcmp_PF( command, PSTR( a ))) +// #define ParameterIs( a ) ( ! strcmp_PF( parameter, PSTR( a ))) +// #endif +#elif(EMAIL_NETWORK_TYPE == NETWORK_ETHERNET_LARGE) + + #include + #include + #define FTP_CLIENT_NETWORK_CLASS EthernetClient + #define FTP_SERVER_NETWORK_SERVER_CLASS EthernetServer + #define NET_CLASS Ethernet + +#elif(EMAIL_NETWORK_TYPE == NETWORK_ETHERNET_STM) + + #include + #include + #define FTP_CLIENT_NETWORK_CLASS EthernetClient + #define FTP_SERVER_NETWORK_SERVER_CLASS EthernetServer + #define NET_CLASS Ethernet + #elif(FTP_SERVER_NETWORK_TYPE == NETWORK_ESP32) #include @@ -163,16 +196,16 @@ //#define FTP_CLIENT_NETWORK_SSL_CLASS WiFiClientSecure #define FTP_SERVER_NETWORK_SERVER_CLASS WiFiServer #define NET_CLASS WiFi - #define CommandIs( a ) (command != NULL && ! strcmp_P( command, PSTR( a ))) - #define ParameterIs( a ) ( parameter != NULL && ! strcmp_P( parameter, PSTR( a ))) +// #define CommandIs( a ) (command != NULL && ! strcmp_P( command, PSTR( a ))) +// #define ParameterIs( a ) ( parameter != NULL && ! strcmp_P( parameter, PSTR( a ))) #elif(FTP_SERVER_NETWORK_TYPE == NETWORK_ESP32_ETH) #include #define FTP_CLIENT_NETWORK_CLASS WiFiClient #define FTP_SERVER_NETWORK_SERVER_CLASS WiFiServer #define NET_CLASS Ethernet - #define CommandIs( a ) ( ! strcmp_PF( command, PSTR( a ))) - #define ParameterIs( a ) ( ! strcmp_PF( parameter, PSTR( a ))) +// #define CommandIs( a ) ( ! strcmp_PF( command, PSTR( a ))) +// #define ParameterIs( a ) ( ! strcmp_PF( parameter, PSTR( a ))) #elif(FTP_SERVER_NETWORK_TYPE == NETWORK_WiFiNINA) #include @@ -180,8 +213,8 @@ //#define FTP_CLIENT_NETWORK_SSL_CLASS WiFiSSLClient #define FTP_SERVER_NETWORK_SERVER_CLASS WiFiServer #define NET_CLASS WiFi - #define CommandIs( a ) ( ! strcmp_PF( command, PSTR( a ))) - #define ParameterIs( a ) ( ! strcmp_PF( parameter, PSTR( a ))) +// #define CommandIs( a ) ( ! strcmp_PF( command, PSTR( a ))) +// #define ParameterIs( a ) ( ! strcmp_PF( parameter, PSTR( a ))) #elif(FTP_SERVER_NETWORK_TYPE == NETWORK_SEEED_RTL8720DN) #include @@ -189,12 +222,20 @@ //#define FTP_CLIENT_NETWORK_SSL_CLASS WiFiSSLClient #define FTP_SERVER_NETWORK_SERVER_CLASS WiFiServer #define NET_CLASS WiFi - #define CommandIs( a ) ( ! strcmp_PF( command, PSTR( a ))) - #define ParameterIs( a ) ( ! strcmp_PF( parameter, PSTR( a ))) +// #define CommandIs( a ) ( ! strcmp_PF( command, PSTR( a ))) +// #define ParameterIs( a ) ( ! strcmp_PF( parameter, PSTR( a ))) #else #error "no network type selected!" #endif +#if defined(ESP8266) || defined(ESP32) || defined(ARDUINO_ARCH_RP2040) + #define CommandIs( a ) (command != NULL && ! strcmp_P( command, PSTR( a ))) + #define ParameterIs( a ) ( parameter != NULL && ! strcmp_P( parameter, PSTR( a ))) +#else + #define CommandIs( a ) ( ! strcmp_PF( command, PSTR( a ))) + #define ParameterIs( a ) ( ! strcmp_PF( parameter, PSTR( a ))) +#endif + #if(STORAGE_TYPE == STORAGE_SPIFFS) #if defined(ESP32) // #define FS_NO_GLOBALS @@ -216,7 +257,6 @@ #endif - #if ESP8266 #define FTP_FILE_READ "r" #define FTP_FILE_READ_ONLY "r" @@ -231,7 +271,9 @@ #define FTP_FILE_WRITE_CREATE "w" #endif - #define STORAGE_MANAGER SPIFFS + #define STORAGE_MANAGER SPIFFS + + #define FILENAME_LENGTH 32 #elif(STORAGE_TYPE == STORAGE_FFAT) #include "FS.h" #include "FFat.h" @@ -247,8 +289,9 @@ #define FTP_FILE_WRITE_APPEND "a" #define FTP_FILE_WRITE_CREATE "w" + #define FILENAME_LENGTH 255 #elif(STORAGE_TYPE == STORAGE_LITTLEFS) - #if ESP8266 + #if ESP8266 || ARDUINO_ARCH_RP2040 #include "LittleFS.h" #define STORAGE_MANAGER LittleFS #define FTP_FILE File @@ -260,13 +303,18 @@ #define FTP_FILE_WRITE_APPEND "a+" #define FTP_FILE_WRITE_CREATE "w+" #else -#if ESP_ARDUINO_VERSION_MAJOR >= 2 - #include "FS.h" - #include "LittleFS.h" - #define STORAGE_MANAGER LittleFS +#ifdef ESP32 + #if ESP_ARDUINO_VERSION_MAJOR >= 2 + #include "FS.h" + #include "LittleFS.h" + #define STORAGE_MANAGER LittleFS + #else + #include "LITTLEFS.h" + #define STORAGE_MANAGER LITTLEFS + #endif #else - #include "LITTLEFS.h" - #define STORAGE_MANAGER LITTLEFS + #include "LittleFS.h" + #define STORAGE_MANAGER LittleFS #endif #define FTP_FILE File #define FTP_DIR File @@ -277,6 +325,7 @@ #define FTP_FILE_WRITE_APPEND "a" #define FTP_FILE_WRITE_CREATE "w" #endif + #define FILENAME_LENGTH 32 #elif(STORAGE_TYPE == STORAGE_SD) #include #include @@ -287,16 +336,37 @@ #define FTP_FILE_READ FILE_READ #define FTP_FILE_READ_ONLY FILE_READ - #define FTP_FILE_READ_WRITE FILE_WRITE -#ifdef ESP8266 - #define FTP_FILE_READ_WRITE FILE_WRITE - #define FTP_FILE_WRITE_APPEND FILE_WRITE -#else +#ifdef ESP32 #define FTP_FILE_READ_WRITE FILE_WRITE #define FTP_FILE_WRITE_APPEND FILE_APPEND +#else + #define FTP_FILE_READ_WRITE FILE_WRITE + #define FTP_FILE_WRITE_APPEND FILE_WRITE #endif #define FTP_FILE_WRITE_CREATE FILE_WRITE + #define FILENAME_LENGTH 255 +#elif(STORAGE_TYPE == STORAGE_SD_MMC) + #include + #include + + #define STORAGE_MANAGER SD_MMC + #define FTP_FILE File + #define FTP_DIR File + + #define FTP_FILE_READ FILE_READ + #define FTP_FILE_READ_ONLY FILE_READ + #define FTP_FILE_READ_WRITE FILE_WRITE +#ifdef ESP32 + #define FTP_FILE_READ_WRITE FILE_WRITE + #define FTP_FILE_WRITE_APPEND FILE_APPEND +#else + #define FTP_FILE_READ_WRITE FILE_WRITE + #define FTP_FILE_WRITE_APPEND FILE_WRITE +#endif + #define FTP_FILE_WRITE_CREATE FILE_WRITE + + #define FILENAME_LENGTH 255 #elif(STORAGE_TYPE == STORAGE_SEEED_SD) #include #define STORAGE_MANAGER SD @@ -317,6 +387,8 @@ #define FTP_FILE_WRITE_APPEND FILE_APPEND #define FTP_FILE_WRITE_CREATE FILE_WRITE + #define FILENAME_LENGTH 255 + #elif (STORAGE_TYPE == STORAGE_SDFAT1) #include #include @@ -331,6 +403,8 @@ #define FTP_FILE_READ_WRITE O_RDWR #define FTP_FILE_WRITE_APPEND O_WRITE | O_APPEND #define FTP_FILE_WRITE_CREATE O_WRITE | O_CREAT + #define FILENAME_LENGTH 255 + #elif (STORAGE_TYPE == STORAGE_SDFAT2) #include #include @@ -345,6 +419,7 @@ #define FTP_FILE_READ_WRITE O_RDWR #define FTP_FILE_WRITE_APPEND O_WRITE | O_APPEND #define FTP_FILE_WRITE_CREATE O_WRITE | O_CREAT + #define FILENAME_LENGTH 255 #elif (STORAGE_TYPE == STORAGE_SPIFM) #include #include @@ -355,12 +430,12 @@ #define FTP_DIR File extern FatFileSystem STORAGE_MANAGER; extern Adafruit_SPIFlash flash; - #define FTP_FILE_READ O_READ - #define FTP_FILE_READ_ONLY O_RDONLY - #define FTP_FILE_READ_WRITE O_RDWR - #define FTP_FILE_WRITE_APPEND O_WRITE | O_APPEND - #define FTP_FILE_WRITE_CREATE O_WRITE | O_CREAT - + #define FTP_FILE_READ FILE_READ + #define FTP_FILE_READ_ONLY FILE_READ + #define FTP_FILE_READ_WRITE FILE_WRITE + #define FTP_FILE_WRITE_APPEND FILE_WRITE + #define FTP_FILE_WRITE_CREATE FILE_WRITE + #define FILENAME_LENGTH 255 #elif (STORAGE_TYPE == STORAGE_FATFS) #include #include @@ -380,6 +455,7 @@ #define FTP_FILE_READ_WRITE O_RDWR #define FTP_FILE_WRITE_APPEND O_WRITE | O_APPEND #define FTP_FILE_WRITE_CREATE O_WRITE | O_CREAT + #define FILENAME_LENGTH 255 #endif //#ifdef FTP_CLIENT_NETWORK_SSL_CLASS @@ -391,25 +467,24 @@ // Setup debug printing macros. #ifdef FTP_SERVER_DEBUG - #define DEBUG_PRINT(...) { DEBUG_PRINTER.print(__VA_ARGS__); } - #define DEBUG_PRINTLN(...) { DEBUG_PRINTER.println(__VA_ARGS__); } + // #define DEBUG_PRINT(...) { DEBUG_PRINTER.print(__VA_ARGS__); } + // #define DEBUG_PRINTLN(...) { DEBUG_PRINTER.println(__VA_ARGS__); } + #define DEBUG_PRINT(...) { Log.verbose(68 /* FTP_TAG */, __VA_ARGS__); } + #define DEBUG_PRINTLN(...) { Log.verbose(68 /* FTP_TAG */, __VA_ARGS__); } #else #define DEBUG_PRINT(...) {} #define DEBUG_PRINTLN(...) {} #endif -#define FTP_USER "arduino" // Default user'name -#define FTP_PASS "test" // Default password - #define FTP_CMD_PORT 21 // Command port on wich server is listening #define FTP_DATA_PORT_DFLT 20 // Default data port in active mode #define FTP_DATA_PORT_PASV 50009 // Data port in passive mode -#define FF_MAX_LFN 255 // max size of a long file name +#define FF_MAX_LFN 255 // max size of a long file name #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_CRED_SIZE 16 // max size of username and password +#define FTP_FIL_SIZE FF_MAX_LFN // max size of a file name +#define FTP_CRED_SIZE 255 // max size of username and password #define FTP_NULLIP() IPAddress(0,0,0,0) enum ftpCmd { FTP_Stop = 0, // In this stage, stop any connection @@ -458,8 +533,11 @@ class FtpServer public: FtpServer( uint16_t _cmdPort = FTP_CMD_PORT, uint16_t _pasvPort = FTP_DATA_PORT_PASV ); - void begin( const char * _user = FTP_USER, const char * _pass = FTP_PASS, const char * welcomeMessage = "Welcome to Simply FTP server" ); - void end(); + void begin( const char * _user, const char * _pass, const char * welcomeMessage = "Welcome to Simply FTP server" ); + void begin( const char * welcomeMessage = "Welcome to Simply FTP server" ); + + void end(); + void setLocalIp(IPAddress localIp); void credentials( const char * _user, const char * _pass ); uint8_t handleFTP(); @@ -515,11 +593,7 @@ private: #elif STORAGE_TYPE == STORAGE_FATFS return file->fileName(); #else - #if ESP_ARDUINO_VERSION_MAJOR >= 2 - return file->path(); - #else - return file->name(); - #endif + return file->name(); #endif } bool exists( const char * path ) { @@ -542,7 +616,7 @@ private: bool removeDir( const char * path ) { return STORAGE_MANAGER.rmdir( path ); }; #endif -#if STORAGE_TYPE == STORAGE_SD +#if STORAGE_TYPE == STORAGE_SD || STORAGE_TYPE == STORAGE_SD_MMC bool rename( const char * path, const char * newpath ); #else bool rename( const char * path, const char * newpath ) { return STORAGE_MANAGER.rename( path, newpath ); }; @@ -554,7 +628,7 @@ private: #elif (STORAGE_TYPE == STORAGE_SPIFFS || STORAGE_TYPE == STORAGE_LITTLEFS || STORAGE_TYPE == STORAGE_FFAT ) bool openFile( const char * path, const char * readType ); // bool openFile( char path[ FTP_CWD_SIZE ], int readTypeInt ); -#elif STORAGE_TYPE <= STORAGE_SDFAT2 +#elif STORAGE_TYPE <= STORAGE_SDFAT2 || STORAGE_TYPE == STORAGE_SPIFM || (STORAGE_TYPE == STORAGE_SD && ARDUINO_ARCH_SAMD) bool openFile( char path[ FTP_CWD_SIZE ], int readTypeInt ); #else bool openFile( char path[ FTP_CWD_SIZE ], const char * readType ); @@ -563,10 +637,10 @@ private: #endif // bool openFile( char path[ FTP_CWD_SIZE ], const char * readType ); // bool openFile( const char * path, const char * readType ); - uint16_t fileSize( FTP_FILE file ); + uint32_t fileSize( FTP_FILE file ); #if STORAGE_TYPE == STORAGE_SPIFFS || STORAGE_TYPE == STORAGE_LITTLEFS -#if ESP8266 +#if ESP8266 || ARDUINO_ARCH_RP2040 uint32_t capacity() { FSInfo fi; STORAGE_MANAGER.info(fi); @@ -577,8 +651,7 @@ private: FSInfo fi; STORAGE_MANAGER.info(fi); - return fi.totalBytes - - fi.usedBytes >> 1; + return (fi.totalBytes - fi.usedBytes) >> 1; }; #else uint32_t capacity() { @@ -589,7 +662,7 @@ private: STORAGE_MANAGER.usedBytes()) >> 1; }; #endif -#elif STORAGE_TYPE == STORAGE_SD +#elif STORAGE_TYPE == STORAGE_SD || STORAGE_TYPE == STORAGE_SD_MMC uint32_t capacity() { return true; }; uint32_t free() { return true; }; #elif STORAGE_TYPE == STORAGE_SEEED_SD @@ -620,7 +693,7 @@ private: #endif bool legalChar( char c ) // Return true if char c is allowed in a long file name { - if( c == '"' || c == '*' || c == '?' || c == ':' || + if( c == '"' || c == '*' || c == '?' || c == ':' || c == '<' || c == '>' || c == '|' ) return false; #if STORAGE_TYPE == STORAGE_FATFS @@ -629,7 +702,7 @@ private: return 0x1f < c && c < 0x7f; #endif } - + IPAddress localIp; // IP address of server as seen by clients IPAddress dataIp; // IP address of client for data FTP_SERVER_NETWORK_SERVER_CLASS ftpServer; @@ -638,15 +711,17 @@ private: FTP_CLIENT_NETWORK_CLASS client; FTP_CLIENT_NETWORK_CLASS data; - + FTP_FILE file; FTP_DIR dir; - + 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() + bool anonymousConnection = false; + + uint8_t __attribute__((aligned(4))) // need to be aligned to 32bit for Esp8266 SPIClass::transferBytes() 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 @@ -664,7 +739,7 @@ private: uint16_t nbMatch; uint32_t millisDelay, // - millisEndConnection, // + millisEndConnection, // millisBeginTrans, // store time of beginning of a transaction bytesTransfered; // }; diff --git a/lib/SimpleFTPServer/FtpServerKey.h b/lib/SimpleFTPServer/FtpServerKey.h index fef50767..d9c5ed5d 100644 --- a/lib/SimpleFTPServer/FtpServerKey.h +++ b/lib/SimpleFTPServer/FtpServerKey.h @@ -18,52 +18,76 @@ #define FTP_SERVER_CONFIG_H // Uncomment to enable printing out nice debug messages. -//#define FTP_SERVER_DEBUG +// #define FTP_SERVER_DEBUG // Define where debug output will be printed. #define DEBUG_PRINTER Serial -#define STORAGE_SDFAT1 0 // Library SdFat version 1.4.x -#define STORAGE_SDFAT2 1 // Library SdFat version >= 2.0.2 -#define STORAGE_SPIFM 2 // Libraries Adafruit_SPIFlash and SdFat-Adafruit-Fork -#define STORAGE_FATFS 3 // Library FatFs -#define STORAGE_SD 4 // Standard SD library (suitable for Arduino esp8266 and esp32 -#define STORAGE_SPIFFS 5 // SPIFFS -#define STORAGE_LITTLEFS 6 // LITTLEFS -#define STORAGE_SEEED_SD 7 // Seeed_SD library -#define STORAGE_FFAT 8 // ESP32 FFAT +#define STORAGE_SDFAT1 1 // Library SdFat version 1.4.x +#define STORAGE_SDFAT2 2 // Library SdFat version >= 2.0.2 +#define STORAGE_SPIFM 3 // Libraries Adafruit_SPIFlash and SdFat-Adafruit-Fork +#define STORAGE_FATFS 4 // Library FatFs +#define STORAGE_SD 5 // Standard SD library (suitable for Arduino esp8266 and esp32 +#define STORAGE_SPIFFS 6 // SPIFFS +#define STORAGE_LITTLEFS 7 // LITTLEFS +#define STORAGE_SEEED_SD 8 // Seeed_SD library +#define STORAGE_FFAT 9 // ESP32 FFAT +#define STORAGE_SD_MMC 10 // SD_MMC library -#define NETWORK_ESP8266_ASYNC (0) -#define NETWORK_ESP8266 (1) -#define NETWORK_ESP8266_242 (6) -#define NETWORK_W5100 (2) -#define NETWORK_ENC28J60 (3) -#define NETWORK_ESP32 (4) -#define NETWORK_ESP32_ETH (5) -#define NETWORK_WiFiNINA (7) -#define NETWORK_SEEED_RTL8720DN (8) +#define NETWORK_ESP8266_ASYNC (1) +#define NETWORK_ESP8266 (2) // Standard ESP8266WiFi +#define NETWORK_ESP8266_242 (3) // ESP8266WiFi before 2.4.2 core +#define NETWORK_W5100 (4) // Standard Arduino Ethernet library +#define NETWORK_ENC28J60 (5) // UIPEthernet library +#define NETWORK_ESP32 (6) // Standard WiFi library +#define NETWORK_RP2040_WIFI (6) // Raspberry Pi Pico W standard WiFi library +#define NETWORK_ESP32_ETH (7) // Standard ETH library +#define NETWORK_WiFiNINA (8) // Standard WiFiNINA library +#define NETWORK_SEEED_RTL8720DN (9) // Standard SEED WiFi library +#define NETWORK_ETHERNET_LARGE (10) +#define NETWORK_ETHERNET_ENC (11) // EthernetENC library (evolution of UIPEthernet +#define NETWORK_ETHERNET_STM (12) +#define NETWORK_UIPETHERNET (13) // UIPEthernet library same of NETWORK_ENC28J60 +// esp8266 configuration #ifndef DEFAULT_FTP_SERVER_NETWORK_TYPE_ESP8266 #define DEFAULT_FTP_SERVER_NETWORK_TYPE_ESP8266 NETWORK_ESP8266 - #define DEFAULT_STORAGE_TYPE_ESP8266 STORAGE_LITTLEFS + #define DEFAULT_STORAGE_TYPE_ESP8266 STORAGE_LITTLEFS #endif +// esp32 configuration #ifndef DEFAULT_FTP_SERVER_NETWORK_TYPE_ESP32 - #define DEFAULT_FTP_SERVER_NETWORK_TYPE_ESP32 NETWORK_ESP32 - #define DEFAULT_STORAGE_TYPE_ESP32 STORAGE_SPIFFS + #define DEFAULT_FTP_SERVER_NETWORK_TYPE_ESP32 NETWORK_ESP32 + #define DEFAULT_STORAGE_TYPE_ESP32 STORAGE_FFAT #endif +// Standard AVR Arduino configuration #ifndef DEFAULT_FTP_SERVER_NETWORK_TYPE_ARDUINO #define DEFAULT_FTP_SERVER_NETWORK_TYPE_ARDUINO NETWORK_W5100 - #define DEFAULT_STORAGE_TYPE_ARDUINO STORAGE_SDFAT2 + #define DEFAULT_STORAGE_TYPE_ARDUINO STORAGE_SD #endif +// STM32 configuration +#ifndef DEFAULT_FTP_SERVER_NETWORK_TYPE_STM32 + #define DEFAULT_FTP_SERVER_NETWORK_TYPE_STM32 NETWORK_W5100 + #define DEFAULT_STORAGE_TYPE_STM32 STORAGE_SDFAT2 +#endif +// Raspberry Pi Pico (rp2040) configuration +#ifndef DEFAULT_FTP_SERVER_NETWORK_TYPE_RP2040 + #define DEFAULT_FTP_SERVER_NETWORK_TYPE_RP2040 NETWORK_RP2040_WIFI + #define DEFAULT_STORAGE_TYPE_RP2040 STORAGE_LITTLEFS +#endif + +// Arduino SAMD21 like Arduino MKR Nano 33 IoT or Wio Terminal #ifndef DEFAULT_FTP_SERVER_NETWORK_TYPE_ARDUINO_SAMD // Wio Terminal // #define DEFAULT_FTP_SERVER_NETWORK_TYPE_SAMD NETWORK_SEEED_RTL8720DN // #define DEFAULT_STORAGE_TYPE_SAMD STORAGE_SEEED_SD + // Arduino SAMD - #define DEFAULT_FTP_SERVER_NETWORK_TYPE_SAMD NETWORK_WiFiNINA // NETWORK_SEEED_RTL8720DN // NETWORK_WiFiNINA - #define DEFAULT_STORAGE_TYPE_SAMD STORAGE_SD // STORAGE_SDFAT2 // STORAGE_SD + #define DEFAULT_FTP_SERVER_NETWORK_TYPE_SAMD NETWORK_WiFiNINA + #define DEFAULT_STORAGE_TYPE_SAMD STORAGE_SD #endif +#define UTF8_SUPPORT + //#define SD_CS_PIN 4 // Disconnect client after 5 minutes of inactivity (expressed in seconds) #define FTP_TIME_OUT 5 * 60 @@ -77,6 +101,6 @@ // Transfer speed depends of this value // Best value depends on many factors: SD card, client side OS, ... // But it can be reduced to 512 if memory usage is critical. -#define FTP_BUF_SIZE 2048 //1024 // 512 +#define FTP_BUF_SIZE 1024 //2048 //1024 // 512 #endif // FTP_SERVER_CONFIG_H diff --git a/lib/SimpleFTPServer/README.md b/lib/SimpleFTPServer/README.md index 1a8130cd..53ce548b 100644 --- a/lib/SimpleFTPServer/README.md +++ b/lib/SimpleFTPServer/README.md @@ -3,11 +3,26 @@ [Instruction on FTP server on esp8266 and esp32](https://www.mischianti.org/2020/02/08/ftp-server-on-esp8266-and-esp32) [Simple FTP Server library now with support for Wio Terminal and SD](https://www.mischianti.org/2021/07/01/simple-ftp-server-library-now-with-support-for-wio-terminal-and-sd/) -Simple FTP Server for +#### Simple FTP Server for + - Raspberry Pi Pico W (Flash: LittleFS) (To test SD and SdFat) - esp8266 (Flash: SPIFFs, LittleFS. SD: SD, SdFat 2) - - esp32 (SPIFFS, LITTLEFS, FFAT, SdFat) - - Arduino (SD with 8.3 file format, SdFat 2) - - Wio Terminal (SdFat 2, and native FAT) + - esp32 (SPIFFS, LITTLEFS, FFAT, SD: SD, SdFat) + - stm32 (SdFat, SPI flash) + - Arduino (SD with 8.3 file format, SD: SD, SdFat 2) + - Wio Terminal (SdFat 2, Seed SD, and native FAT) + +#### Changelog +- 2022-01-13 2.1.5 Fix SPIFM external SPI Flash date management (add SPIFM esp32 example) +- 2022-09-21 2.1.4 Add support for Raspberry Pi Pico W and rp2040 boards, Fix SD card config +- 2022-09-20 2.1.3 Soft AP IP management, more disconnect event and SD_MCC +- 2022-05-21 2.1.2 Fix SD path (#19) +- 2022-05-21 2.1.1 Minor fix +- 2022-03-30 2.1.0 Add UTF8 support and enabled It by default (Thanks to @plaber) +- 2022-03-30 2.0.0 Complete support for STM32 with SD and SPI Flash minor bux fix and HELP command support +- 2022-03-17 1.3.0 Fix enc28j60 and w5500 support and restructuring for local settings +- 2022-02-25 1.2.1 Fix anonymous user begin and fix SPIFFS wrong display +- 2022-02-22 1.2.0 Add anonymous user and implement correct RFC (#9 now work correctly with File Explorer) +- 2022-02-01 1.1.1 Add workaround to start FTP server before connection, add end and setLocalIP method.

When I develop a new solution I'd like to divide the application in layer, and so I'd like focus my attention in only one aspect at time.

@@ -87,4 +102,6 @@ void loop(void){ // server.handleClient(); //example if running a webserver you still need to call .handleClient(); } -``` \ No newline at end of file +``` + +https://downloads.arduino.cc/libraries/logs/github.com/xreef/SimpleFTPServer/ \ No newline at end of file diff --git a/lib/SimpleFTPServer/SimpleFTPServer.h b/lib/SimpleFTPServer/SimpleFTPServer.h index 894c359c..dc92d46b 100644 --- a/lib/SimpleFTPServer/SimpleFTPServer.h +++ b/lib/SimpleFTPServer/SimpleFTPServer.h @@ -11,7 +11,7 @@ #ifndef SIMPLE_FTP_SERVER_H #define SIMPLE_FTP_SERVER_H -#include "FtpServer.h" +#include #endif diff --git a/lib/SimpleFTPServer/examples/FTPServer_Arduino_Ethernet/FTPServer_Arduino_Ethernet.ino b/lib/SimpleFTPServer/examples/FTPServer_Arduino_Ethernet/FTPServer_Arduino_Ethernet.ino deleted file mode 100644 index af178521..00000000 --- a/lib/SimpleFTPServer/examples/FTPServer_Arduino_Ethernet/FTPServer_Arduino_Ethernet.ino +++ /dev/null @@ -1,62 +0,0 @@ -/* - * FtpServer Arduino with Ethernet library and w5100 shield - * - * AUTHOR: Renzo Mischianti - * - * https://www.mischianti.org/2020/02/08/ftp-server-on-esp8266-and-esp32 - * - */ - -#include -#include -#include "SD.h" - -#include - -// Enter a MAC address for your controller below. -// Newer Ethernet shields have a MAC address printed on a sticker on the shield -byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xE1 }; - -// Set the static IP address to use if the DHCP fails to assign -byte macAddr[] = {0x5e, 0xa4, 0x18, 0xf0, 0x8a, 0xf2}; -IPAddress arduinoIP(192, 168, 1, 177); -IPAddress dnsIP(192, 168, 1, 1); -IPAddress gatewayIP(192, 168, 1, 1); -IPAddress subnetIP(255, 255, 255, 0); - -FtpServer ftpSrv; - -void setup(void){ - Serial.begin(115200); - delay(2000); - // If other chips are connected to SPI bus, set to high the pin connected - // to their CS before initializing Flash memory - pinMode( 4, OUTPUT ); - digitalWrite( 4, HIGH ); - pinMode( 10, OUTPUT ); - digitalWrite( 10, HIGH ); - - Serial.print("Starting SD."); - while (!SD.begin(4)) { - Serial.print("."); - } - Serial.println("finish!"); - - // start the Ethernet connection: - Serial.print("Starting ethernet."); - if (Ethernet.begin(mac) == 0) { - Serial.println("Failed to configure Ethernet using DHCP"); - Ethernet.begin(macAddr, arduinoIP, dnsIP, gatewayIP, subnetIP); - }else{ - Serial.println("ok to configure Ethernet using DHCP"); - } - - Serial.print("IP address "); - Serial.println(Ethernet.localIP()); - - Serial.println("SPIFFS opened!"); - ftpSrv.begin("esp8266","esp8266"); //username, password for ftp. -} -void loop(void){ - ftpSrv.handleFTP(); //make sure in loop you call handleFTP()!! -} diff --git a/lib/SimpleFTPServer/examples/FTPServer_Arduino_esp32_SD/FTPServer_Arduino_esp32_SD.ino b/lib/SimpleFTPServer/examples/FTPServer_Arduino_esp32_SD/FTPServer_Arduino_esp32_SD.ino deleted file mode 100644 index c28dcf0b..00000000 --- a/lib/SimpleFTPServer/examples/FTPServer_Arduino_esp32_SD/FTPServer_Arduino_esp32_SD.ino +++ /dev/null @@ -1,96 +0,0 @@ -/* - * FtpServer esp8266 and esp32 with SD - * - * AUTHOR: Renzo Mischianti - * - * https://www.mischianti.org/2020/02/08/ftp-server-on-esp8266-and-esp32 - * - */ - -#include -#include "SD.h" - -#include - -const char* ssid = ""; -const char* password = ""; - - -FtpServer ftpSrv; //set #define FTP_DEBUG in ESP8266FtpServer.h to see ftp verbose on serial - -void _callback(FtpOperation ftpOperation, unsigned int freeSpace, unsigned int totalSpace){ - Serial.print(">>>>>>>>>>>>>>> _callback " ); - Serial.print(ftpOperation); - /* FTP_CONNECT, - * FTP_DISCONNECT, - * FTP_FREE_SPACE_CHANGE - */ - Serial.print(" "); - Serial.print(freeSpace); - Serial.print(" "); - Serial.println(totalSpace); - - // freeSpace : totalSpace = x : 360 - - if (ftpOperation == FTP_CONNECT) Serial.println(F("CONNECTED")); - if (ftpOperation == FTP_DISCONNECT) Serial.println(F("DISCONNECTED")); -}; -void _transferCallback(FtpTransferOperation ftpOperation, const char* name, unsigned int transferredSize){ - Serial.print(">>>>>>>>>>>>>>> _transferCallback " ); - Serial.print(ftpOperation); - /* FTP_UPLOAD_START = 0, - * FTP_UPLOAD = 1, - * - * FTP_DOWNLOAD_START = 2, - * FTP_DOWNLOAD = 3, - * - * FTP_TRANSFER_STOP = 4, - * FTP_DOWNLOAD_STOP = 4, - * FTP_UPLOAD_STOP = 4, - * - * FTP_TRANSFER_ERROR = 5, - * FTP_DOWNLOAD_ERROR = 5, - * FTP_UPLOAD_ERROR = 5 - */ - Serial.print(" "); - Serial.print(name); - Serial.print(" "); - Serial.println(transferredSize); -}; - -void setup(void){ - Serial.begin(115200); - WiFi.begin(ssid, password); - Serial.println(""); - - // Wait for connection - while (WiFi.status() != WL_CONNECTED) { - delay(500); - Serial.print("."); - } - Serial.println(""); - Serial.print("Connected to "); - Serial.println(ssid); - Serial.print("IP address: "); - Serial.println(WiFi.localIP()); - - - /////FTP Setup, ensure SPIFFS is started before ftp; ///////// - - /////FTP Setup, ensure SPIFFS is started before ftp; ///////// - SPI.begin(14, 2, 15, 13); //SCK, MISO, MOSI,SS - - if (SD.begin(13, SPI)) { - Serial.println("SD opened!"); - - ftpSrv.setCallback(_callback); - ftpSrv.setTransferCallback(_transferCallback); - - ftpSrv.begin("esp8266","esp8266"); //username, password for ftp. (default 21, 50009 for PASV) - } -} -void loop(void){ - ftpSrv.handleFTP(); //make sure in loop you call handleFTP()!! - // server.handleClient(); //example if running a webserver you still need to call .handleClient(); - -} diff --git a/lib/SimpleFTPServer/examples/FTPServer_esp8266_esp32/FTPServer_esp8266_esp32.ino b/lib/SimpleFTPServer/examples/FTPServer_esp8266_esp32/FTPServer_esp8266_esp32.ino deleted file mode 100644 index c67a1ade..00000000 --- a/lib/SimpleFTPServer/examples/FTPServer_esp8266_esp32/FTPServer_esp8266_esp32.ino +++ /dev/null @@ -1,110 +0,0 @@ -/* - * FtpServer esp8266 and esp32 with SPIFFS - * - * AUTHOR: Renzo Mischianti - * - * https://www.mischianti.org/2020/02/08/ftp-server-on-esp8266-and-esp32 - * - */ - -#ifdef ESP8266 -#include -#elif defined ESP32 -#include -#include "SPIFFS.h" -#endif - -#include - -const char* ssid = "YOUR_SSID"; -const char* password = "YOUR_PASS"; - - -FtpServer ftpSrv; //set #define FTP_DEBUG in ESP8266FtpServer.h to see ftp verbose on serial - -void _callback(FtpOperation ftpOperation, unsigned int freeSpace, unsigned int totalSpace){ - switch (ftpOperation) { - case FTP_CONNECT: - Serial.println(F("FTP: Connected!")); - break; - case FTP_DISCONNECT: - Serial.println(F("FTP: Disconnected!")); - break; - case FTP_FREE_SPACE_CHANGE: - Serial.printf("FTP: Free space change, free %u of %u!\n", freeSpace, totalSpace); - break; - default: - break; - } -}; -void _transferCallback(FtpTransferOperation ftpOperation, const char* name, unsigned int transferredSize){ - switch (ftpOperation) { - case FTP_UPLOAD_START: - Serial.println(F("FTP: Upload start!")); - break; - case FTP_UPLOAD: - Serial.printf("FTP: Upload of file %s byte %u\n", name, transferredSize); - break; - case FTP_TRANSFER_STOP: - Serial.println(F("FTP: Finish transfer!")); - break; - case FTP_TRANSFER_ERROR: - Serial.println(F("FTP: Transfer error!")); - break; - default: - break; - } - - /* FTP_UPLOAD_START = 0, - * FTP_UPLOAD = 1, - * - * FTP_DOWNLOAD_START = 2, - * FTP_DOWNLOAD = 3, - * - * FTP_TRANSFER_STOP = 4, - * FTP_DOWNLOAD_STOP = 4, - * FTP_UPLOAD_STOP = 4, - * - * FTP_TRANSFER_ERROR = 5, - * FTP_DOWNLOAD_ERROR = 5, - * FTP_UPLOAD_ERROR = 5 - */ -}; - -void setup(void){ - Serial.begin(115200); - WiFi.begin(ssid, password); - Serial.println(""); - - // Wait for connection - while (WiFi.status() != WL_CONNECTED) { - delay(500); - Serial.print("."); - } - Serial.println(""); - Serial.print("Connected to "); - Serial.println(ssid); - Serial.print("IP address: "); - Serial.println(WiFi.localIP()); - - - /////FTP Setup, ensure SPIFFS is started before ftp; ///////// - - /////FTP Setup, ensure SPIFFS is started before ftp; ///////// -#ifdef ESP32 //esp32 we send true to format spiffs if cannot mount - if (SPIFFS.begin(true)) { -#elif defined ESP8266 - if (SPIFFS.begin()) { -#endif - ftpSrv.setCallback(_callback); - ftpSrv.setTransferCallback(_transferCallback); - - Serial.println("SPIFFS opened!"); - ftpSrv.begin("esp8266","esp8266"); //username, password for ftp. (default 21, 50009 for PASV) - } -} -void loop(void){ - ftpSrv.handleFTP(); //make sure in loop you call handleFTP()!! - // server.handleClient(); //example if running a webserver you still need to call .handleClient(); - -} diff --git a/lib/SimpleFTPServer/examples/FTPServer_wio_terminal/FTPServer_wio_terminal.ino b/lib/SimpleFTPServer/examples/FTPServer_wio_terminal/FTPServer_wio_terminal.ino deleted file mode 100644 index c6620c64..00000000 --- a/lib/SimpleFTPServer/examples/FTPServer_wio_terminal/FTPServer_wio_terminal.ino +++ /dev/null @@ -1,102 +0,0 @@ -/* - * This sketch sends data via HTTP GET requests to examle.com service. - */ - -#include -#include "SD/Seeed_SD.h" - -// #define DEFAULT_FTP_SERVER_NETWORK_TYPE_SAMD NETWORK_SEEED_RTL8720DN -// #define DEFAULT_STORAGE_TYPE_SAMD STORAGE_SEEED_SD - -#include - -#include - -FtpServer ftpSrv; - -const char *ssid = ""; -const char *password = ""; - -void listDir(const char* dirname, uint8_t levels) { - Serial.print("Listing directory: "); - Serial.println(dirname); - - File root = SD.open(dirname); - if (!root) { - Serial.println("Failed to open directory"); - return; - } - if (!root.isDirectory()) { - Serial.println("Not a directory"); - return; - } - - File file = root.openNextFile(); - while (file) { - if (file.isDirectory()) { - Serial.print(" DIR : "); - Serial.println(file.name()); - if (levels) { - listDir(file.name(), levels - 1); - } - } else { - Serial.print(" FILE: "); - Serial.print(file.name()); - Serial.print(" SIZE: "); - Serial.println(file.size()); - } - file = root.openNextFile(); - } -} - - -void setup() -{ - Serial.begin(115200); - delay(1000); - - pinMode(5, OUTPUT); - digitalWrite(5, HIGH); - - while (!SD.begin(SDCARD_SS_PIN,SDCARD_SPI,4000000UL)) { - Serial.println("Card Mount Failed"); - return; - } - - // We start by connecting to a WiFi network - Serial.println(); - Serial.println(); - Serial.print("Connecting to "); - Serial.print(ssid); - - WiFi.mode(WIFI_STA); - - WiFi.begin(ssid, password); - - while (WiFi.status() != WL_CONNECTED) - { - Serial.print("Connecting to "); - Serial.println(ssid); - WiFi.begin(ssid, password); - Serial.print("."); - delay(500); - } - - Serial.println(""); - Serial.println("WiFi connected"); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); - delay(1000); - - Serial.print("Starting SD."); - - Serial.println("finish!"); - - listDir("/", 0); - - ftpSrv.begin("esp8266","esp8266"); //username, password for ftp. - } - - void loop(void) { - ftpSrv.handleFTP(); //make sure in loop you call handleFTP()!! - } diff --git a/lib/SimpleFTPServer/examples/FTPServer_wio_terminal_SdFat/FTPServer_wio_terminal_SdFat.ino b/lib/SimpleFTPServer/examples/FTPServer_wio_terminal_SdFat/FTPServer_wio_terminal_SdFat.ino deleted file mode 100644 index 155f84de..00000000 --- a/lib/SimpleFTPServer/examples/FTPServer_wio_terminal_SdFat/FTPServer_wio_terminal_SdFat.ino +++ /dev/null @@ -1,98 +0,0 @@ -/* - * This sketch sends data via HTTP GET requests to examle.com service. - */ - -#include "SdFat.h" - -#include - -#include - -// #define DEFAULT_FTP_SERVER_NETWORK_TYPE_SAMD NETWORK_SEEED_RTL8720DN -// #define DEFAULT_STORAGE_TYPE_SAMD STORAGE_SDFAT2 - -#define SD_CONFIG SdSpiConfig(SDCARD_SS_PIN, 2) -SdFs sd; - -FtpServer ftpSrv; - -const char *ssid = ""; -const char *password = ""; - -void setup() -{ - Serial.begin(115200); - delay(1000); - - pinMode(5, OUTPUT); - digitalWrite(5, HIGH); - - // Initialize the SD. - if (!sd.begin(SD_CONFIG)) { - sd.initErrorHalt(&Serial); - } - FsFile dir; - FsFile file; - - // Open root directory - if (!dir.open("/")){ - Serial.println("dir.open failed"); - } - - // We start by connecting to a WiFi network - - Serial.println(); - Serial.println(); - Serial.print("Connecting to "); - Serial.print(ssid); - - WiFi.mode(WIFI_STA); - - - WiFi.begin(ssid, password); - - while (WiFi.status() != WL_CONNECTED) - { - Serial.print("Connecting to "); - Serial.println(ssid); - WiFi.begin(ssid, password); - Serial.print("."); - delay(500); - } - - Serial.println(""); - Serial.println("WiFi connected"); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); - delay(1000); - - Serial.print("Starting SD."); - - Serial.println("finish!"); - - while (file.openNext(&dir, O_RDONLY)) { - file.printFileSize(&Serial); - Serial.write(' '); - file.printModifyDateTime(&Serial); - Serial.write(' '); - file.printName(&Serial); - if (file.isDir()) { - // Indicate a directory. - Serial.write('/'); - } - Serial.println(); - file.close(); - } - if (dir.getError()) { - Serial.println("openNext failed"); - } else { - Serial.println("Done!"); - } - - - ftpSrv.begin("esp8266","esp8266"); //username, password for ftp. - } - - void loop(void) { - ftpSrv.handleFTP(); //make sure in loop you call handleFTP()!! - } diff --git a/lib/SimpleFTPServer/examples/FTPServer_wio_terminal_SdFat_TFT_monitor/FTPServer_wio_terminal_SdFat_TFT_monitor.ino b/lib/SimpleFTPServer/examples/FTPServer_wio_terminal_SdFat_TFT_monitor/FTPServer_wio_terminal_SdFat_TFT_monitor.ino deleted file mode 100644 index 86d18b19..00000000 --- a/lib/SimpleFTPServer/examples/FTPServer_wio_terminal_SdFat_TFT_monitor/FTPServer_wio_terminal_SdFat_TFT_monitor.ino +++ /dev/null @@ -1,367 +0,0 @@ -/* - * FtpServer Wio Terminal with SdFat library - * and with callbacks to the main actions of FTP server - * and a monitor on TFT - * - * AUTHOR: Renzo Mischianti - * - * https://www.mischianti.org/ - * - */ - -#include "SdFat.h" - -#include - - -#include // Hardware-specific library -#include - -#include - -TFT_eSPI tft = TFT_eSPI(); // Invoke custom library - -#define DEG2RAD 0.0174532925 - -byte inc = 0; -unsigned int col = 0; - -#define SD_CONFIG SdSpiConfig(SDCARD_SS_PIN, 2) -SdFs sd; - -FtpServer ftpSrv; - -const char *ssid = "reef-casa-sopra"; -const char *password = "aabbccdd77"; - -#define MAIN_TOP 110 - -#define FREE_SPACE_PIE_X 80 -#define FREE_SPACE_PIE_Y MAIN_TOP+40 -#define FREE_SPACE_PIE_RADIUS 50 - -void freeSpacePieData(unsigned int freeSpace, unsigned int totalSpace) { - int pieFree = 360 - (freeSpace * 360 / totalSpace); - - fillSegment(FREE_SPACE_PIE_X, FREE_SPACE_PIE_Y, 0, pieFree, FREE_SPACE_PIE_RADIUS, TFT_RED); - fillSegment(FREE_SPACE_PIE_X, FREE_SPACE_PIE_Y, pieFree, 360 - pieFree, FREE_SPACE_PIE_RADIUS, TFT_BLUE); - - // Set "cursor" at top left corner of display (0,0) and select font 2 - // (cursor will move to next line automatically during printing with 'tft.println' - // or stay on the line is there is room for the text with tft.print) - tft.setCursor(FREE_SPACE_PIE_X + 80, MAIN_TOP, 2); - // Set the font colour to be white with a black background, set text size multiplier to 1 - tft.setTextColor(TFT_WHITE, TFT_BLACK); tft.setTextSize(1); - // We can now plot text on screen using the "print" class - Serial.print(freeSpace/1000);Serial.print("Mb/");Serial.print(String(totalSpace/1000));Serial.println("Mb"); - tft.print(freeSpace/1000);tft.print("Mb/");tft.print(String(totalSpace/1000));tft.println("Mb"); -} - -void connectedDisconnected(bool connected) { - tft.fillCircle(FREE_SPACE_PIE_X + 80 + 10, MAIN_TOP+25+7, 10, (connected)?TFT_GREEN:TFT_RED); - - tft.setCursor(FREE_SPACE_PIE_X + 80 + 25, MAIN_TOP+25, 2); - tft.println(" "); - - tft.setCursor(FREE_SPACE_PIE_X + 80 + 25, MAIN_TOP+25, 2); - (connected)?tft.println("Connected!"):tft.println("Disconnected!"); -} - -void transfer(bool transfer, bool upload) { - tft.fillCircle(FREE_SPACE_PIE_X + 80 + 10, MAIN_TOP+25+25+7, 10, (transfer)?(upload)?TFT_GREEN:TFT_BLUE:TFT_RED); - - tft.setCursor(FREE_SPACE_PIE_X + 80 + 25, MAIN_TOP+25+25, 2); - tft.println(" "); - - tft.setCursor(FREE_SPACE_PIE_X + 80 + 25, MAIN_TOP+25+25, 2); - (transfer)?tft.println((upload)?"Upload!":"Download!"):tft.println("Idle!"); -} - -//index - starting at, n- how many chars -char* subString(const char *s, int index, int n){ - char* b = (char*) malloc((strlen(s) + 1) * sizeof(char)); - strcpy(b,s); - - Serial.println("--------------------------------------"); - Serial.println(s); - Serial.println(index); - Serial.println(n); - char *res = new char[n + 1]; - Serial.println(res); - sprintf(res, "%.*s", n, b + index); - Serial.println(res); - free(b); - return res; -} - - -void fileTransfer(FtpTransferOperation ftpOperation, const char* filename, unsigned int transferredSize) { - int yoffset = 2; - - tft.setCursor(20, MAIN_TOP+(FREE_SPACE_PIE_RADIUS*2)+yoffset, 2); - tft.println(F(" ")); - - tft.setCursor(20, MAIN_TOP+(FREE_SPACE_PIE_RADIUS*2)+yoffset, 2); - int lenfile = strlen(filename); - Serial.println(lenfile); - if (lenfile>22) { - - tft.print(subString(filename, 0, 16));tft.print(F("~")); - tft.print( subString(filename, (lenfile-4), 4) ); - } else { - tft.print(filename); - } - tft.setCursor(20+160, MAIN_TOP+(FREE_SPACE_PIE_RADIUS*2)+yoffset, 2); - tft.print(F(" ")); - tft.setCursor(20+160, MAIN_TOP+(FREE_SPACE_PIE_RADIUS*2)+yoffset, 2); - tft.print(transferredSize);tft.print("Kb"); - - tft.setCursor(320-55, MAIN_TOP+(FREE_SPACE_PIE_RADIUS*2)+yoffset, 2); - switch (ftpOperation) { - case FTP_UPLOAD: - tft.setTextColor(TFT_GREEN, TFT_BLACK); - tft.print(F("Upload")); - tft.setTextColor(TFT_WHITE, TFT_BLACK); - break; - case FTP_DOWNLOAD: - tft.setTextColor(TFT_BLUE, TFT_BLACK); - tft.print(F("Down")); - tft.setTextColor(TFT_WHITE, TFT_BLACK); - - break; - case FTP_TRANSFER_STOP: - tft.setTextColor(TFT_GREEN, TFT_BLACK); - tft.print(F("OK")); - tft.setTextColor(TFT_WHITE, TFT_BLACK); - - break; - case FTP_TRANSFER_ERROR: - tft.setTextColor(TFT_RED, TFT_BLACK); - tft.print(F("Error")); - tft.setTextColor(TFT_WHITE, TFT_BLACK); - - break; - - default: - break; - } - -} - -void wifiStrenght (int8_t RSSI, bool connection = false) { - Serial.print("RSSI --> ");Serial.println(RSSI); - int marginX = 30; - - int startX = 90; - int widthW = 320-(startX+marginX); - - int startY = 60; - int heightY = 10; - - tft.setCursor(marginX, startY - 5, 2); - tft.print(F(" ")); - tft.setCursor(marginX, startY - 5, 2); - - if (connection) { - tft.print(F("Connectint to: ")); - tft.print(ssid); - }else{ - tft.println("WiFi str: "); - - // 120 : 120-RSSI = 300 : x - - tft.drawRoundRect(startX, startY, widthW, heightY, 5, TFT_WHITE); - - uint32_t colorRSSI = TFT_GREEN; - if (abs(RSSI)<55) { - colorRSSI = TFT_GREEN; - } else if (abs(RSSI)<75) { - colorRSSI = TFT_YELLOW; - } else if (abs(RSSI)<75) { - colorRSSI = TFT_RED; - } - - tft.fillRoundRect(startX+1, startY+1, (120+RSSI)*widthW/120, heightY-2, 5, colorRSSI); - - tft.setCursor(marginX, startY + 15, 2); - - tft.print("IP: "); - tft.println(WiFi.localIP()); - } -} - -void _callback(FtpOperation ftpOperation, unsigned int freeSpace, unsigned int totalSpace){ - Serial.print(">>>>>>>>>>>>>>> _callback " ); - Serial.print(ftpOperation); - /* FTP_CONNECT, - * FTP_DISCONNECT, - * FTP_FREE_SPACE_CHANGE - */ - Serial.print(" "); - Serial.print(freeSpace); - Serial.print(" "); - Serial.println(totalSpace); - - // freeSpace : totalSpace = x : 360 - - freeSpacePieData(freeSpace, totalSpace); - - if (ftpOperation == FTP_CONNECT) connectedDisconnected(true); - if (ftpOperation == FTP_DISCONNECT) connectedDisconnected(false); -}; -void _transferCallback(FtpTransferOperation ftpOperation, const char* name, unsigned int transferredSize){ - Serial.print(">>>>>>>>>>>>>>> _transferCallback " ); - Serial.print(ftpOperation); - /* FTP_UPLOAD_START = 0, - * FTP_UPLOAD = 1, - * - * FTP_DOWNLOAD_START = 2, - * FTP_DOWNLOAD = 3, - * - * FTP_TRANSFER_STOP = 4, - * FTP_DOWNLOAD_STOP = 4, - * FTP_UPLOAD_STOP = 4, - * - * FTP_TRANSFER_ERROR = 5, - * FTP_DOWNLOAD_ERROR = 5, - * FTP_UPLOAD_ERROR = 5 - */ - Serial.print(" "); - Serial.print(name); - Serial.print(" "); - Serial.println(transferredSize); - - (ftpOperation==FTP_UPLOAD || ftpOperation==FTP_DOWNLOAD)?transfer(true, ftpOperation==FTP_UPLOAD):transfer(false, false); - - fileTransfer(ftpOperation, name, transferredSize); -}; - - -void setup() -{ - ftpSrv.setCallback(_callback); - ftpSrv.setTransferCallback(_transferCallback); - - Serial.begin(115200); - delay(1000); - - tft.init(); - - tft.begin(); - - tft.setRotation(3); - - tft.fillScreen(TFT_BLACK); - - tft.setCursor(0, 0); - - tft.setTextColor(TFT_BLACK, TFT_WHITE); tft.setTextSize(2); - - tft.fillRoundRect(3, 3, 320-6, 40, 5, TFT_WHITE); - - tft.drawCentreString("www.mischianti.org", 160, 14,1); - tft.setTextColor(TFT_WHITE, TFT_BLACK); - - - freeSpacePieData(0, 0); - connectedDisconnected(false); - transfer(false, false); - - wifiStrenght(0, true); - - Serial.println(); - Serial.println(); - Serial.print("Connecting to "); - Serial.print(ssid); - - WiFi.mode(WIFI_STA); - - - WiFi.begin(ssid, password); - - while (WiFi.status() != WL_CONNECTED) - { - Serial.print("."); - WiFi.begin(ssid, password); - Serial.print("."); - tft.print(F(".")); - delay(500); - } - - Serial.println(""); - Serial.println("WiFi connected"); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); - - wifiStrenght(WiFi.RSSI()); - - delay(1000); - - if (!sd.begin(SD_CONFIG)) { - sd.initErrorHalt(&Serial); - } - FsFile dir; - FsFile file; - - // Open root directory - if (!dir.open("/")){ - Serial.println("dir.open failed"); - } - - ftpSrv.begin("wioterminal","wioterminal"); //username, password for ftp. - -} - -void loop() { - ftpSrv.handleFTP(); //make sure in loop you call handleFTP()!! -} - - -// ######################################################################### -// Draw circle segments -// ######################################################################### - -// x,y == coords of centre of circle -// start_angle = 0 - 359 -// sub_angle = 0 - 360 = subtended angle -// r = radius -// colour = 16 bit colour value - -int fillSegment(int x, int y, int start_angle, int sub_angle, int r, unsigned int colour) { - // Calculate first pair of coordinates for segment start - float sx = cos((start_angle - 90) * DEG2RAD); - float sy = sin((start_angle - 90) * DEG2RAD); - uint16_t x1 = sx * r + x; - uint16_t y1 = sy * r + y; - - // Draw colour blocks every inc degrees - for (int i = start_angle; i < start_angle + sub_angle; i++) { - - // Calculate pair of coordinates for segment end - int x2 = cos((i + 1 - 90) * DEG2RAD) * r + x; - int y2 = sin((i + 1 - 90) * DEG2RAD) * r + y; - - tft.fillTriangle(x1, y1, x2, y2, x, y, colour); - - // Copy segment end to sgement start for next segment - x1 = x2; - y1 = y2; - } -} - - -// ######################################################################### -// Return the 16 bit colour with brightness 0-100% -// ######################################################################### -unsigned int brightness(unsigned int colour, int brightness) { - byte red = colour >> 11; - byte green = (colour & 0x7E0) >> 5; - byte blue = colour & 0x1F; - - blue = (blue * brightness) / 100; - green = (green * brightness) / 100; - red = (red * brightness) / 100; - - return (red << 11) + (green << 5) + blue; -} - diff --git a/lib/SimpleFTPServer/keywords.txt b/lib/SimpleFTPServer/keywords.txt index e759b081..5cc521ad 100644 --- a/lib/SimpleFTPServer/keywords.txt +++ b/lib/SimpleFTPServer/keywords.txt @@ -9,6 +9,8 @@ SimpleFtpServer KEYWORD1 ####################################### begin KEYWORD2 +end KEYWORD2 +setLocalIp KEYWORD2 credentials KEYWORD2 setCallback KEYWORD2 setTransferCallback KEYWORD2 diff --git a/lib/SimpleFTPServer/library.json b/lib/SimpleFTPServer/library.json index f73a296b..6840dc38 100644 --- a/lib/SimpleFTPServer/library.json +++ b/lib/SimpleFTPServer/library.json @@ -1,7 +1,8 @@ { "name": "SimpleFTPServer", - "description": "Simple FTP Server for using esp8266 and esp32 SPIFFs", - "keywords": "esp8266, ftp, spiffs", + "description": "Simple FTP Server for using esp8266, esp32, STM32, Arduino", + "keywords": "arduino, esp8266, esp32, stm32, rp2040, Raspberry Pi, ftp, FtpServer, spiffs, Fat, LittleFS, Ethernet, WiFi, WiFiNINA", + "homepage": "https://www.mischianti.org/category/my-libraries/simple-ftp-server/", "authors": { "name": "Renzo Mischianti", @@ -15,5 +16,6 @@ }, "url": "https://www.mischianti.org", "frameworks": "Arduino", + "version": "2.1.5", "platforms": "*" } diff --git a/lib/SimpleFTPServer/library.properties b/lib/SimpleFTPServer/library.properties index 44030841..42ec8ba6 100644 --- a/lib/SimpleFTPServer/library.properties +++ b/lib/SimpleFTPServer/library.properties @@ -1,9 +1,9 @@ name=SimpleFTPServer -version=1.0.1 +version=2.1.5 author=Renzo Mischianti maintainer=Renzo Mischianti -sentence=Simple FTP server for esp8266, esp32 and Arduino -paragraph=Simple FTP server for esp8266 (SPIFFS and LittleFS), esp32 (SPIFFS, LittleFS ans FFAT) and Arduino (SD basic lib with 8.3 file format), Wio Terminal (SdFat 2), Arduino MKR (SdFat 2). With internal callback to chck the phase of communication. +sentence=Simple FTP server for esp8266, esp32, STM32, Raspberry Pi Pico and Arduino +paragraph=Simple FTP server for Raspberry Pi Pico W (LittleFS), esp8266 (SPIFFS and LittleFS or SD, SdFat 2.x), esp32 (SPIFFS, LittleFS and FFAT or SD, SdFat 2.x) and Arduino (SdFat, SD basic lib with 8.3 file format), Wio Terminal (Seed_SD, SdFat 2.x), Arduino MKR (SdFat 2), STM32 (Flash >64K SdFat 2.x and SPI Flash). Support w5500, w5100 and enc28j60. With internal callback to chck the phase of communication. category=Communication url=https://www.mischianti.org/category/my-libraries/simple-ftp-server/ repository=https://github.com/xreef/SimpleFTPServer.git diff --git a/src/hasp/hasp_dispatch.cpp b/src/hasp/hasp_dispatch.cpp index dff7b204..291d743c 100644 --- a/src/hasp/hasp_dispatch.cpp +++ b/src/hasp/hasp_dispatch.cpp @@ -502,7 +502,7 @@ void dispatch_config(const char* topic, const char* payload, uint8_t source) timeGetConfig(settings); } #if HASP_USE_MQTT > 0 - else if(strcasecmp_P(topic, PSTR("mqtt")) == 0) { + else if(strcasecmp_P(topic, PSTR(FP_MQTT)) == 0) { if(update) mqttSetConfig(settings); else @@ -522,15 +522,23 @@ void dispatch_config(const char* topic, const char* payload, uint8_t source) } #endif #if HASP_USE_HTTP > 0 || HASP_USE_HTTP_ASYNC > 0 - else if(strcasecmp_P(topic, PSTR("http")) == 0) { + else if(strcasecmp_P(topic, PSTR(FP_HTTP)) == 0) { if(update) httpSetConfig(settings); else httpGetConfig(settings); } #endif +#if HASP_USE_FTP > 0 + else if(strcasecmp_P(topic, PSTR(FP_FTP)) == 0) { + if(update) + ftpSetConfig(settings); + else + ftpGetConfig(settings); + } +#endif #if HASP_USE_ARDUINOOTA > 0 || HASP_USE_HTTP_UPDATE > 0 - else if(strcasecmp_P(topic, PSTR("ota")) == 0) { + else if(strcasecmp_P(topic, PSTR(FP_OTA)) == 0) { if(update) otaSetConfig(settings); else @@ -542,7 +550,7 @@ void dispatch_config(const char* topic, const char* payload, uint8_t source) // Send output if(!update) { char subtopic[8]; - settings.remove(F("pass")); // hide password in output + settings.remove(FP_CONFIG_PASS); // hide password in output /* size_t size = */ serializeJson(doc, buffer, sizeof(buffer)); memcpy_P(subtopic, PSTR("config"), 7); diff --git a/src/hasp/hasp_nvs.cpp b/src/hasp/hasp_nvs.cpp index 6177bfb9..88039415 100644 --- a/src/hasp/hasp_nvs.cpp +++ b/src/hasp/hasp_nvs.cpp @@ -22,12 +22,12 @@ bool nvs_user_begin(Preferences& preferences, const char* key, bool readonly) bool nvs_clear_user_config() { - const char* name[8] = {"time", "ota", "http", "mqtt", "wifi"}; + const char* name[8] = {FP_TIME, FP_OTA, FP_HTTP, FP_FTP, FP_MQTT, FP_WIFI}; Preferences preferences; - for(int i = 0; i < 5; i++) { - preferences.begin(name[i], false); - preferences.clear(); + for(int i = 0; i < 6; i++) { + if(!preferences.begin(name[i], false)) return false; + if(!preferences.clear()) return false; preferences.end(); } @@ -72,6 +72,25 @@ bool nvsUpdateUInt(Preferences& preferences, const char* key, JsonVariant value) return changed; } +bool nvsUpdateUShort(Preferences& preferences, const char* key, JsonVariant value) +{ + bool changed = false; + uint32_t val = value.as(); + + if(!value.isNull()) { // Json key exists + if(preferences.isKey(key)) { // Nvs key exists + changed = preferences.getUShort(key, 0) != val; // Value changed + } else + changed = true; // Nvs key doesnot exist, create it + if(changed) { + size_t len = preferences.putUShort(key, val); + LOG_DEBUG(TAG_TIME, F(D_BULLET "Wrote %s => %d"), key, val); + } + } + + return changed; +} + // Show_nvs_keys.ino // Read all the keys from nvs partition and dump this information. // 04-dec-2017, Ed Smallenburg. @@ -202,10 +221,10 @@ void nvs_setup() nvs_stats.free_entries, nvs_stats.total_entries); { // TODO: remove migratrion of keys from default NVS partition to CONFIG partition - const char* name[8] = {"time", "ota", "http", "mqtt", "wifi"}; + const char* name[8] = {FP_TIME, FP_OTA, FP_HTTP, FP_FTP, FP_MQTT, FP_WIFI}; Preferences oldPrefs, newPrefs; - for(int i = 0; i < 5; i++) { + for(int i = 0; i < 6; i++) { if(oldPrefs.begin(name[i], false) && newPrefs.begin(name[i], false, "config")) { LOG_INFO(TAG_NVS, "opened %s", name[i]); String password = oldPrefs.getString(FP_CONFIG_PASS, D_PASSWORD_MASK); @@ -253,7 +272,7 @@ void nvs_setup2() dbgprint("Partition %s not found!", partname); return; } - namespace_ID = FindNsID(nvs, "mqtt"); // Find ID of our namespace in NVS + namespace_ID = FindNsID(nvs, FP_MQTT); // Find ID of our namespace in NVS dbgprint("Namespace ID of ESP32Radio is %d", namespace_ID); while(offset < nvs->size) { result = esp_partition_read(nvs, offset, // Read 1 page in nvs partition diff --git a/src/hasp/hasp_nvs.h b/src/hasp/hasp_nvs.h index 178ed0a5..809f65ca 100644 --- a/src/hasp/hasp_nvs.h +++ b/src/hasp/hasp_nvs.h @@ -14,6 +14,7 @@ bool nvs_user_begin(Preferences& preferences, const char* key, bool readonly); bool nvs_clear_user_config(); bool nvsUpdateString(Preferences& preferences, const char* key, JsonVariant value); bool nvsUpdateUInt(Preferences& preferences, const char* key, JsonVariant value); +bool nvsUpdateUShort(Preferences& preferences, const char* key, JsonVariant value); #endif // ESP32 diff --git a/src/hasp_config.h b/src/hasp_config.h index b2144bc2..5b4e0d72 100644 --- a/src/hasp_config.h +++ b/src/hasp_config.h @@ -7,7 +7,6 @@ #define HASP_CONFIG_H #include "hasplib.h" -#include "hasp_debug.h" // for TAG_CONF /* ===== Default Event Processors ===== */ void configSetup(void); @@ -20,7 +19,7 @@ void configStop(void); DeserializationError configParseFile(String& configFile, JsonDocument& settings); DeserializationError configRead(JsonDocument& settings, bool setupdebug); void configWrite(void); -void configOutput(const JsonObject& settings, uint8_t tag = TAG_CONF); +void configOutput(const JsonObject& settings, uint8_t tag); bool configClearEeprom(void); /* ===== Getter and Setter Functions ===== */ @@ -48,6 +47,7 @@ const char FP_CONFIG_COLOR2[] PROGMEM = "color2"; const char FP_CONFIG_ENABLE[] PROGMEM = "enable"; const char FP_CONFIG_HOST[] PROGMEM = "host"; const char FP_CONFIG_PORT[] PROGMEM = "port"; +const char FP_CONFIG_PASV[] PROGMEM = "pasv"; const char FP_CONFIG_NAME[] PROGMEM = "name"; const char FP_CONFIG_USER[] PROGMEM = "user"; const char FP_CONFIG_PASS[] PROGMEM = "pass"; @@ -76,6 +76,7 @@ const char FP_HASP_CONFIG_FILE[] PROGMEM = "/config.json"; const char FP_WIFI[] PROGMEM = "wifi"; const char FP_MQTT[] PROGMEM = "mqtt"; const char FP_HTTP[] PROGMEM = "http"; +const char FP_FTP[] PROGMEM = "ftp"; const char FP_GPIO[] PROGMEM = "gpio"; const char FP_MDNS[] PROGMEM = "mdns"; const char FP_HASP[] PROGMEM = "hasp"; diff --git a/src/lang/en_US.h b/src/lang/en_US.h index 2a971d96..37558021 100644 --- a/src/lang/en_US.h +++ b/src/lang/en_US.h @@ -122,6 +122,7 @@ #define D_HTTP_HASP_DESIGN "HASP Design" #define D_HTTP_INFORMATION "Information" #define D_HTTP_HTTP_SETTINGS "HTTP Settings" +#define D_HTTP_FTP_SETTINGS "FTP Settings" #define D_HTTP_WIFI_SETTINGS "Wifi Settings" #define D_HTTP_MQTT_SETTINGS "MQTT Settings" #define D_HTTP_GPIO_SETTINGS "GPIO Settings" diff --git a/src/lang/es_ES.h b/src/lang/es_ES.h index 081a769d..1892ee9f 100644 --- a/src/lang/es_ES.h +++ b/src/lang/es_ES.h @@ -122,6 +122,7 @@ #define D_HTTP_HASP_DESIGN "Diseño de HASP" #define D_HTTP_INFORMATION "Información" #define D_HTTP_HTTP_SETTINGS "Ajustes HTTP" +#define D_HTTP_HTTP_SETTINGS "Ajustes FTP" #define D_HTTP_WIFI_SETTINGS "Ajustes Wifi" #define D_HTTP_MQTT_SETTINGS "Ajustes MQTT" #define D_HTTP_GPIO_SETTINGS "Ajustes GPIO" diff --git a/src/lang/fr_FR.h b/src/lang/fr_FR.h index 90c7b4fa..a29d520b 100644 --- a/src/lang/fr_FR.h +++ b/src/lang/fr_FR.h @@ -122,6 +122,7 @@ #define D_HTTP_HASP_DESIGN "Conception HASP" #define D_HTTP_INFORMATION "Information" #define D_HTTP_HTTP_SETTINGS "Paramètres HTTP" +#define D_HTTP_FTP_SETTINGS "Paramètres FTP" #define D_HTTP_WIFI_SETTINGS "Paramètres Wifi" #define D_HTTP_MQTT_SETTINGS "Paramètres MQTT" #define D_HTTP_GPIO_SETTINGS "Paramètres GPIO" diff --git a/src/lang/hu_HU.h b/src/lang/hu_HU.h index 8fd3679f..b617a64c 100644 --- a/src/lang/hu_HU.h +++ b/src/lang/hu_HU.h @@ -122,6 +122,7 @@ #define D_HTTP_HASP_DESIGN "Képernyő dizájn" #define D_HTTP_INFORMATION "Információk" #define D_HTTP_HTTP_SETTINGS "HTTP beállítások" +#define D_HTTP_FTP_SETTINGS "FTP beállítások" #define D_HTTP_WIFI_SETTINGS "WiFi beállítások" #define D_HTTP_MQTT_SETTINGS "MQTT beállítások" #define D_HTTP_GPIO_SETTINGS "GPIO beállítások" diff --git a/src/lang/nl_NL.h b/src/lang/nl_NL.h index ab0940f9..33b1f0a9 100644 --- a/src/lang/nl_NL.h +++ b/src/lang/nl_NL.h @@ -122,6 +122,7 @@ #define D_HTTP_HASP_DESIGN "HASP Ontwerp" #define D_HTTP_INFORMATION "Informatie" #define D_HTTP_HTTP_SETTINGS "HTTP Instellingen" +#define D_HTTP_FTP_SETTINGS "FTP Instellingen" #define D_HTTP_WIFI_SETTINGS "Wifi Instellingen" #define D_HTTP_MQTT_SETTINGS "MQTT Instellingen" #define D_HTTP_GPIO_SETTINGS "GPIO Instellingen" diff --git a/src/lang/pt_PT.h b/src/lang/pt_PT.h index 8bdb073a..82c273db 100644 --- a/src/lang/pt_PT.h +++ b/src/lang/pt_PT.h @@ -123,6 +123,7 @@ #define D_HTTP_HASP_DESIGN "Design do HASP" #define D_HTTP_INFORMATION "Informação" #define D_HTTP_HTTP_SETTINGS "Configurar HTTP" +#define D_HTTP_FTP_SETTINGS "Configurar FTP" #define D_HTTP_WIFI_SETTINGS "Configurar Wifi" #define D_HTTP_MQTT_SETTINGS "Configurar MQTT" #define D_HTTP_GPIO_SETTINGS "Configurar GPIO" diff --git a/src/lang/ro_RO.h b/src/lang/ro_RO.h index 53f12e8e..03125f6d 100644 --- a/src/lang/ro_RO.h +++ b/src/lang/ro_RO.h @@ -122,6 +122,7 @@ #define D_HTTP_HASP_DESIGN "Desenul ecranului" #define D_HTTP_INFORMATION "Informații" #define D_HTTP_HTTP_SETTINGS "Setări HTTP" +#define D_HTTP_FTP_SETTINGS "Setări FTP" #define D_HTTP_WIFI_SETTINGS "Setări WiFi" #define D_HTTP_MQTT_SETTINGS "Setări MQTT" #define D_HTTP_GPIO_SETTINGS "Setări GPIO" diff --git a/src/sys/svc/hasp_ftp.cpp b/src/sys/svc/hasp_ftp.cpp index d4288f9b..712cda7b 100644 --- a/src/sys/svc/hasp_ftp.cpp +++ b/src/sys/svc/hasp_ftp.cpp @@ -7,7 +7,6 @@ #include "hasp_debug.h" #include "hasp_ftp.h" -#include "hasp_http.h" #include "hasp_filesystem.h" #include "../../hasp/hasp_dispatch.h" @@ -15,12 +14,10 @@ #include "FtpServerKey.h" #include "SimpleFTPServer.h" -#if HASP_USE_HTTP > 0 || HASP_USE_HTTP_ASYNC > 0 -extern hasp_http_config_t http_config; -#endif - FtpServer* ftpSrv; // set #define FTP_DEBUG in ESP8266FtpServer.h to see ftp verbose on serial +String ftpUsername = ""; +String ftpPassword = ""; uint16_t ftpCtrlPort = 21; uint16_t ftpDataPort = 50009; uint8_t ftpEnabled = true; @@ -52,13 +49,13 @@ void ftp_transfer_callback(FtpTransferOperation ftpOperation, const char* name, case FTP_UPLOAD_START: { char size[16]; Parser::format_bytes(transferredSize, size, sizeof(size)); - LOG_VERBOSE(TAG_FTP, "Start upload of file %s (%s)", name, size); + LOG_VERBOSE(TAG_FTP, "Receiving file %s (%s)", name, size); return; } case FTP_DOWNLOAD_START: { char size[16]; Parser::format_bytes(transferredSize, size, sizeof(size)); - LOG_VERBOSE(TAG_FTP, "Start download of file %s (%s)", name, size); + LOG_VERBOSE(TAG_FTP, "Sending file %s (%s)", name, size); return; } case FTP_UPLOAD: @@ -67,11 +64,11 @@ void ftp_transfer_callback(FtpTransferOperation ftpOperation, const char* name, case FTP_TRANSFER_STOP: { char size[16]; Parser::format_bytes(transferredSize, size, sizeof(size)); - LOG_VERBOSE(TAG_FTP, "Completed transfer of file %s (%s)", name, size); + LOG_VERBOSE(TAG_FTP, "Completed file %s (%s)", name, size); break; } case FTP_TRANSFER_ERROR: - LOG_VERBOSE(TAG_FTP, ("Transfer error!")); + LOG_ERROR(TAG_FTP, ("Transfer error!")); break; default: break; @@ -79,23 +76,18 @@ void ftp_transfer_callback(FtpTransferOperation ftpOperation, const char* name, transferName = NULL; transferSize = 0; - - /* FTP_UPLOAD_START = 0, - * FTP_UPLOAD = 1, - * - * FTP_DOWNLOAD_START = 2, - * FTP_DOWNLOAD = 3, - * - * FTP_TRANSFER_STOP = 4, - * FTP_DOWNLOAD_STOP = 4, - * FTP_UPLOAD_STOP = 4, - * - * FTP_TRANSFER_ERROR = 5, - * FTP_DOWNLOAD_ERROR = 5, - * FTP_UPLOAD_ERROR = 5 - */ }; +static void ftpInitializePorts() +{ + Preferences preferences; + + nvs_user_begin(preferences, FP_FTP, true); + ftpCtrlPort = preferences.getUShort(FP_CONFIG_PORT, ftpCtrlPort); // Read from NVS if it exists + ftpDataPort = preferences.getUShort(FP_CONFIG_PASV, ftpDataPort); // Read from NVS if it exists + preferences.end(); +} + void ftpStop(void) { if(ftpSrv) { @@ -106,35 +98,47 @@ void ftpStop(void) transferSize = 0; transferName = NULL; + ftpInitializePorts(); LOG_INFO(TAG_FTP, F(D_SERVICE_STOPPED)); } void ftpStart() { - LOG_TRACE(TAG_FTP, F(D_SERVICE_STARTING)); - - ftpSrv = new FtpServer(ftpCtrlPort, ftpDataPort); if(!ftpSrv) { - LOG_INFO(TAG_FTP, F(D_SERVICE_START_FAILED)); - return; + LOG_TRACE(TAG_FTP, F(D_SERVICE_STARTING)); + Preferences preferences; + + nvs_user_begin(preferences, FP_FTP, true); + ftpUsername = preferences.getString(FP_CONFIG_USER, ftpUsername); // Read from NVS if it exists + ftpPassword = preferences.getString(FP_CONFIG_PASS, ftpPassword); // Read from NVS if it exists + preferences.end(); + + if(!ftpEnabled || ftpUsername == "" || ftpUsername == "anonymous" || ftpCtrlPort == 0) { + LOG_INFO(TAG_FTP, F(D_SERVICE_DISABLED)); + return; + } + + ftpSrv = new FtpServer(ftpCtrlPort, ftpDataPort); + if(!ftpSrv) { + LOG_INFO(TAG_FTP, F(D_SERVICE_START_FAILED)); + return; + } + + ftpSrv->setCallback(ftp_callback); + ftpSrv->setTransferCallback(ftp_transfer_callback); + ftpSrv->begin(ftpUsername.c_str(), ftpPassword.c_str(), D_MANUFACTURER); // Password must be non-empty + + LOG_VERBOSE(TAG_FTP, F(FTP_SERVER_VERSION)); } - ftpSrv->setCallback(ftp_callback); - ftpSrv->setTransferCallback(ftp_transfer_callback); - -#if HASP_USE_HTTP > 0 || HASP_USE_HTTP_ASYNC > 0 - ftpSrv->begin(http_config.username, http_config.password, D_MANUFACTURER); // Password must be non-empty -#else - ftpSrv->begin("ftpuser", "haspadmin"); // username, password for ftp. (default 21, 50009 for PASV) -#endif - - LOG_VERBOSE(TAG_FTP, F(FTP_SERVER_VERSION)); LOG_INFO(TAG_FTP, F(D_SERVICE_STARTED)); } void ftpSetup() { + ftpInitializePorts(); + #if HASP_START_FTP ftpStart(); #endif @@ -154,10 +158,33 @@ void ftpEverySecond(void) LOG_VERBOSE(TAG_FTP, D_BULLET "%s (%s)", transferName, size); } +//////////////////////////////////////////////////////////////////////////////////////////////////// #if HASP_USE_CONFIG > 0 bool ftpGetConfig(const JsonObject& settings) { bool changed = false; + Preferences preferences; + + nvs_user_begin(preferences, FP_FTP, true); + String nvsUsername = preferences.getString(FP_CONFIG_USER, ftpUsername); // Read from NVS if it exists + String nvsPassword = preferences.getString(FP_CONFIG_PASS, ftpPassword); // Read from NVS if it exists + uint16_t nvsPort = preferences.getUShort(FP_CONFIG_PORT, ftpCtrlPort); // Read from NVS if it exists + uint16_t nvsData = preferences.getUShort(FP_CONFIG_PASV, ftpDataPort); // Read from NVS if it exists + preferences.end(); + + settings[FPSTR(FP_CONFIG_ENABLE)] = ftpEnabled; + + if(nvsPort != settings[FPSTR(FP_CONFIG_PORT)].as()) changed = true; + settings[FPSTR(FP_CONFIG_PORT)] = nvsPort; + + if(nvsData != settings[FPSTR(FP_CONFIG_PASV)].as()) changed = true; + settings[FPSTR(FP_CONFIG_PASV)] = nvsData; + + if(strcmp(nvsUsername.c_str(), settings[FP_CONFIG_USER].as().c_str()) != 0) changed = true; + settings[FP_CONFIG_USER] = nvsUsername; + + if(strcmp(D_PASSWORD_MASK, settings[FP_CONFIG_PASS].as().c_str()) != 0) changed = true; + settings[FP_CONFIG_PASS] = D_PASSWORD_MASK; if(changed) configOutput(settings, TAG_FTP); return changed; @@ -167,15 +194,31 @@ bool ftpGetConfig(const JsonObject& settings) * * Read the settings from json and sets the application variables. * - * @note: read config.json into memory + * @note: data pixel should be formated to uint32_t RGBA. Imagemagick requirements. * * @param[in] settings JsonObject with the config settings. **/ bool ftpSetConfig(const JsonObject& settings) { + Preferences preferences; + nvs_user_begin(preferences, FP_FTP, false); + configOutput(settings, TAG_FTP); bool changed = false; + changed |= nvsUpdateUShort(preferences, FP_CONFIG_PORT, settings[FPSTR(FP_CONFIG_PORT)]); + changed |= nvsUpdateUShort(preferences, FP_CONFIG_PASV, settings[FPSTR(FP_CONFIG_PASV)]); + + if(!settings[FPSTR(FP_CONFIG_USER)].isNull()) { + changed |= nvsUpdateString(preferences, FP_CONFIG_USER, settings[FPSTR(FP_CONFIG_USER)]); + } + + if(!settings[FPSTR(FP_CONFIG_PASS)].isNull() && + settings[FPSTR(FP_CONFIG_PASS)].as() != String(FPSTR(D_PASSWORD_MASK))) { + changed |= nvsUpdateString(preferences, FP_CONFIG_PASS, settings[FPSTR(FP_CONFIG_PASS)]); + } + + preferences.end(); return changed; } #endif // HASP_USE_CONFIG diff --git a/src/sys/svc/hasp_http.cpp b/src/sys/svc/hasp_http.cpp index 4bd3213d..6f44023e 100644 --- a/src/sys/svc/hasp_http.cpp +++ b/src/sys/svc/hasp_http.cpp @@ -72,12 +72,12 @@ ESP8266WebServer webServer(80); WebServer webServer(80); #if defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) -extern const uint8_t EDIT_HTM_GZ_START[] asm("_binary_data_edit_htm_gz_start"); -extern const uint8_t EDIT_HTM_GZ_END[] asm("_binary_data_edit_htm_gz_end"); -extern const uint8_t STYLE_CSS_GZ_START[] asm("_binary_data_style_css_gz_start"); -extern const uint8_t STYLE_CSS_GZ_END[] asm("_binary_data_style_css_gz_end"); -extern const uint8_t SCRIPT_JS_GZ_START[] asm("_binary_data_script_js_gz_start"); -extern const uint8_t SCRIPT_JS_GZ_END[] asm("_binary_data_script_js_gz_end"); +extern const uint8_t EDIT_HTM_GZ_START[] asm("_binary_data_static_edit_htm_gz_start"); +extern const uint8_t EDIT_HTM_GZ_END[] asm("_binary_data_static_edit_htm_gz_end"); +extern const uint8_t STYLE_CSS_GZ_START[] asm("_binary_data_static_style_css_gz_start"); +extern const uint8_t STYLE_CSS_GZ_END[] asm("_binary_data_static_style_css_gz_end"); +extern const uint8_t SCRIPT_JS_GZ_START[] asm("_binary_data_static_script_js_gz_start"); +extern const uint8_t SCRIPT_JS_GZ_END[] asm("_binary_data_static_script_js_gz_end"); extern const uint8_t LOGO_SVG_GZ_START[] asm("_binary_data_static_logo_svg_gz_start"); extern const uint8_t LOGO_SVG_GZ_END[] asm("_binary_data_static_logo_svg_gz_end"); extern const uint8_t ACE_JS_GZ_START[] asm("_binary_data_static_ace_1_9_6_min_js_gz_start"); @@ -331,9 +331,13 @@ bool http_save_config() updated = haspSetConfig(settings.as()); #if HASP_USE_MQTT > 0 - } else if(save == String(PSTR("mqtt"))) { + } else if(save == String(PSTR(FP_MQTT))) { updated = mqttSetConfig(settings.as()); #endif +#if HASP_USE_FTP > 0 + } else if(save == String(PSTR(FP_FTP))) { + updated = ftpSetConfig(settings.as()); +#endif } else if(save == String(PSTR("gui"))) { settings[FPSTR(FP_GUI_POINTER)] = webServer.hasArg(PSTR("cursor")); @@ -345,7 +349,7 @@ bool http_save_config() settings[FPSTR(FP_DEBUG_ANSI)] = webServer.hasArg(PSTR("ansi")); updated = debugSetConfig(settings.as()); - } else if(save == String(PSTR("http"))) { + } else if(save == String(PSTR(FP_HTTP))) { updated = httpSetConfig(settings.as()); // Password might have changed @@ -659,6 +663,11 @@ static void webHandleApi() settings.createNestedObject(module); mqttGetConfig(settings[module]); #endif +#if HASP_USE_FTP > 0 + module = FPSTR(FP_FTP); + settings.createNestedObject(module); + ftpGetConfig(settings[module]); +#endif #if HASP_USE_HTTP > 0 module = FPSTR(FP_HTTP); settings.createNestedObject(module); @@ -752,12 +761,17 @@ static void webHandleApiConfig() } else #endif #if HASP_USE_MQTT > 0 - if(!strcasecmp_P(endpoint_key, PSTR("mqtt"))) { + if(!strcasecmp_P(endpoint_key, PSTR(FP_MQTT))) { mqttSetConfig(settings); } else #endif +#if HASP_USE_FTP > 0 + if(!strcasecmp_P(endpoint_key, PSTR(FP_FTP))) { + ftpSetConfig(settings); + } else +#endif #if HASP_USE_HTTP > 0 - if(!strcasecmp_P(endpoint_key, PSTR("http"))) { + if(!strcasecmp_P(endpoint_key, PSTR(FP_HTTP))) { httpSetConfig(settings); } else #endif @@ -788,12 +802,17 @@ static void webHandleApiConfig() } else #endif #if HASP_USE_MQTT > 0 - if(!strcasecmp_P(endpoint_key, PSTR("mqtt"))) { + if(!strcasecmp_P(endpoint_key, PSTR(FP_MQTT))) { mqttGetConfig(settings); } else #endif +#if HASP_USE_FTP > 0 + if(!strcasecmp_P(endpoint_key, PSTR(FP_FTP))) { + ftpGetConfig(settings); + } else +#endif #if HASP_USE_HTTP > 0 - if(!strcasecmp_P(endpoint_key, PSTR("http"))) { + if(!strcasecmp_P(endpoint_key, PSTR(FP_HTTP))) { httpGetConfig(settings); } else #endif @@ -1324,6 +1343,9 @@ static void webHandleConfig() httpMessage += F("" D_HTTP_MQTT_SETTINGS ""); #endif httpMessage += F("" D_HTTP_HTTP_SETTINGS ""); +#if HASP_USE_FTP > 0 + httpMessage += F("" D_HTTP_FTP_SETTINGS ""); +#endif httpMessage += F("" D_HTTP_GUI_SETTINGS ""); #if HASP_USE_GPIO > 0 @@ -1552,6 +1574,57 @@ static void webHandleHttpConfig() webSendFooter(); } +//////////////////////////////////////////////////////////////////////////////////////////////////// +static void webHandleFtpConfig() +{ // http://plate01/config/http + if(!http_is_authenticated(F("config/ftp"))) return; + + { // Send Content + String httpMessage((char*)0); + httpMessage.reserve(HTTP_PAGE_SIZE); + httpMessage += F("

"); + httpMessage += haspDevice.get_hostname(); + httpMessage += F("


"); + httpMessage += F("

" D_HTTP_FTP_SETTINGS "

"); + + // Form + httpMessage += F("
"); + + // Username + httpMessage += F("
"); + httpMessage += F("
"); + + // Password + httpMessage += F("
"); + httpMessage += F("
"); + + // Ftp Port + httpMessage += F("
"); + httpMessage += F("
"); + + // Passiv Port + httpMessage += F("
"); + httpMessage += F("
"); + + // Submit & End Form + httpMessage += F(""); + httpMessage += F("
"); + + httpMessage += F("" D_HTTP_CONFIGURATION ""); + + webSendHtmlHeader(haspDevice.get_hostname(), httpMessage.length(), 0); + webServer.sendContent(httpMessage); + } + webSendFooter(); +} + + //////////////////////////////////////////////////////////////////////////////////////////////////// #if HASP_USE_GPIO > 0 static void webHandleGpioConfig() @@ -2505,7 +2578,7 @@ static inline void webStartConfigPortal() void httpSetup() { Preferences preferences; - nvs_user_begin(preferences,"http", true); + nvs_user_begin(preferences, FP_HTTP, true); String password = preferences.getString(FP_CONFIG_PASS, HTTP_PASSWORD); strncpy(http_config.password, password.c_str(), sizeof(http_config.password)); LOG_DEBUG(TAG_HTTP, F(D_BULLET "Read %s => %s (%d bytes)"), FP_CONFIG_PASS, password.c_str(), password.length()); @@ -2593,6 +2666,9 @@ void httpSetup() #if HASP_USE_MQTT > 0 webServer.on(F("/config/mqtt"), webHandleMqttConfig); #endif +#if HASP_USE_FTP > 0 + webServer.on(F("/config/ftp"), webHandleFtpConfig); +#endif #if HASP_USE_WIFI > 0 webServer.on(F("/config/wifi"), webHandleWifiConfig); #endif @@ -2653,7 +2729,7 @@ bool httpGetConfig(const JsonObject& settings) bool httpSetConfig(const JsonObject& settings) { Preferences preferences; - nvs_user_begin(preferences,"http", false); + nvs_user_begin(preferences, FP_HTTP, false); configOutput(settings, TAG_HTTP); bool changed = false;