Parsing authentication credentials from String to char not working

Hi, I am trying to use preferences to store authentication credentials for an FTP server.
When credentials are hard coded it works but when credentials come from storage it does not.
Authentication fails.

The format of the hard coded credentials that work are commented out.
All variables are stored as Strings in the preferences flash memory and converted as necessary.
It works everywhere, with WiFi and SMTP but fails with this ftp.

The library used is:
// FTP Client Lib
#include "ESP32_FTPClient.h"

The portion of the code with the problem is as follows:

void FTP_upload(String pic_name){
      
  //FTP parameters
  preferences.begin("AppParms", false);
  String Server = preferences.getString("ftpServer", "");      //toCharArray(ftpServer,sizeof(ftpServer));                        
  String User   = preferences.getString("ftpUser", "");          //toCharArray(ftpUser,sizeof(ftpUser));                        
  String Pass   = preferences.getString("ftpPass", "");          //toCharArray(ftpPass,sizeof(ftpPass)); 
  preferences.end();
  
  Server.trim();
  User.trim();
  Pass.trim();    

  Serial.print(" Strings:  #");
  Serial.print(Server);
  Serial.print("#");
  Serial.print(User);
  Serial.print("#");
  Serial.print(Pass);
  Serial.println("#");

  char ftp_server[Server.length()+1];
  char ftp_user[User.length()+1];
  char ftp_pass[Pass.length()+1];

  Server.toCharArray(ftp_server,Server.length()+1);
  User.toCharArray(ftp_user,User.length()+1);
  Pass.toCharArray(ftp_pass,Pass.length()+1);

  Serial.print(" FTP Parms:  #");
  Serial.print(ftp_server);
  Serial.print("#");
  Serial.print(ftp_user);
  Serial.print("#");
  Serial.print(ftp_pass);
  Serial.println("#");

  //ESP32_FTPClient ftp("host.ftpserver.com", "ftpuser", "ftppass");   //WORKS OK
  ESP32_FTPClient ftp(ftp_server, ftp_user, ftp_pass);                 //Compile but fails
  
  Serial.println("Transferindo imagem para  FTP Server...");
  ftp.OpenConnection();
  
  //Create a file and write the image data to it;
  ftp.InitFile("Type I");
  //ftp.ChangeWorkDir("/public_html/zyro/gallery_gen/"); // change it to reflect your directory
  const char *f_name = pic_name.c_str();
  ftp.NewFile( f_name );
  ftp.WriteData(fb->buf, fb->len);
  ftp.CloseFile();

  // Breath, withouth delay URL failed to update.
  Serial.println("Concluido...");
  delay(100);
}

Assistance welcome.

Thanks
Paulo

"Not working" does not provide any useful information.

Server.toCharArray(ftp_server,Server.length()+1);

Is this the correct usage of .toCharArray(buf, len)?

I don't know if the null terminator character is dealt with by the function or if you include it in your length. Someone else might know how .toCHarArray() works or you could look at the source. It just stuck out to me as wrong because String wrappers usually deal with the null terminator for you.

It's at least a quick test on your part to remove the +1's from .toCharArray().

arduino_new, thanks for your contribution but if I present the whole story at once it is going to be tedious and confusing.
May be the best is to drill down presenting what is asked from the original, and somewhat generalized problem is my original post. The plan was not to scare people away with hart to understand long explanations.

Hi Thee_Captain, if I remove the +1 the last char at the right is lost.

I also believe the problem may well be related with the null terminator but I lack the knowledge to sort the problem out.

May be it is being lost in some stage from the html form where it originates to the point it is used.
I am not handling it, I do not know how.

The process I am using, somehow, works everywhere else as in the fragment below although the method to present the data varies from function to function as on the fragment below:

  //Preferences preferences;
  preferences.begin("AppParms", false);
  String ssid = preferences.getString("wifissid", "");
  String pass = preferences.getString("wifiPass", "");      
  preferences.end();  
  
  WiFi.begin(ssid.c_str(), pass.c_str());

On another part of the program I had to use another method. Here I did not even have to convert using .c_str():

if(!smtpParmsLoaded){
    //smtp parameters
    preferences.begin("AppParms", false);                 
    smtpServer   = preferences.getString("smtpServer", "");                      
    smtpUser     = preferences.getString("smtpUser", "");                       
    smtpPass     = preferences.getString("smtpPass", "");                        
    emailto      = preferences.getString("emailto", "");                       
    emailTitle   = preferences.getString("emailTitle", "");                      
    emailMessage = preferences.getString("emailMessage", "");
    preferences.end(); 
    smtpParmsLoaded = true;
  }

  //Set the Email host, port, account and password
  smtpData.setLogin(smtpServer, 465, smtpUser, smtpPass);

The full code where the data is collected from html and stored in Preferences is below:

See attached text for complete post + code, code text too long...

Thanks
Paulo

htmlfunction.txt (24.9 KB)

pcborges:
...if I remove the +1 the last char at the right is lost.

I also believe the problem may well be related with the null terminator but I lack the knowledge to sort the problem out.

May be it is being lost in some stage from the html form where it originates to the point it is used.
I am not handling it, I do not know how.

The process I am using, somehow, works everywhere else as in the fragment below although the method to present the data varies from function to function as on the fragment below:

...

Try appending the '\0' character to the char array. You may need to make the array one byte larger to do this. While I am guessing that this could be the solution, I am less inclined to think that the string function would not append that character for you when copying it to a char buffer. It is worth a try though to test.

If at all possible I try not to use C++ String objects and just use the lower case C string (char array null terminated).

HI, the fact that I have to add +1 at that point also makes me feel strange...

I decided to go back to the roots, where the preferences are defined.
So I typed all the variable as below:

  while(1){
    WiFiClient client = server.available(); // Listen for incoming clients
    if (client) {                           // If a new client connects,  
      Serial.println("New Client.");          // print a message out in the serial port
      String currentLine = "";                // make a String to hold incoming data from the client
      while (client.connected()) {            // loop while the client's connected
        if (client.available()) {             // if there's bytes to read from the client,
          char c = client.read();             // read a byte, then
          Serial.write(c);                    // print it out the serial monitor
          header += c;
       
          if (c == '\n') {                    // if the byte is a newline character
            // if the current line is blank, you got two newline characters in a row.
            // that's the end of the client HTTP request, so send a response:
            if (currentLine.length() == 0) {
              // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
              // and a content-type so the client knows what's coming, then a blank line:
              client.println("HTTP/1.1 200 OK");
              client.println("Content-type:text/html");
              client.println("Connection: close");
              client.println();
  
              clientPayload = header.substring(header.indexOf("GET /?")+6,header.indexOf("HTTP/1.1"));
              Serial.print("Payload: ");
              Serial.println(clientPayload);
             
              if(clientPayload.length()>0){                
                preferences.begin("AppParms", false);              
                int getPosition = 0;
                for(int i=0;i<=clientPayload.length();i++){
                  if(clientPayload.charAt(i)=='='){
                    varName = clientPayload.substring(getPosition,i);
                    DBG(varName);
                    DBG(" = ");
                    getPosition = i+1;
                  }
                  if(clientPayload.charAt(i)=='&'){
                    varValue = urldecode(clientPayload.substring(getPosition,i));
                    DBGln(varValue);
                    getPosition = i+1;  

                    if(varName == "wifissid"){ preferences.putChar("wifissid", varValue.c_str());}
                    if(varName == "wifiPass"){ preferences.putChar("wifiPass", varValue.c_str());}
                    if(varName == "delayPrimFoto"){ preferences.putBytes("delayPrimFoto", varValue.int());}
                    if(varName == "delayEntreFotos"){ preferences.putBytes("delayEntreFotos", varValue.int());}
                    if(varName == "fireFlash"){ preferences.putBool("fireFlash", varValue.bool());}  
                    if(varName == "totFotos"){ preferences.putBytes("totFotos", varValue.int());}                                       
                    if(varName == "timeGMT"){ preferences.putBytes("timeGMT", varValue.int());}                      
                    if(varName == "sendtoemail"){ preferences.putBool("sendtoemail", varValue.bool());}                     
                    if(varName == "smtpServer"){ preferences.putChar("smtpServer", varValue.c_str());}                      
                    if(varName == "smtpUser"){ preferences.putChar("smtpUser", varValue.c_str());}                       
                    if(varName == "smtpPass"){ preferences.putChar("smtpPass", varValue.c_str());}                        
                    if(varName == "emailto"){ preferences.putChar("emailto", varValue.c_str());}                       
                    if(varName == "emailTitle"){ preferences.putChar("emailTitle", varValue.c_str());}                      
                    if(varName == "emailMessage"){ preferences.putChar("emailMessage", varValue.c_str());}                       
                    if(varName == "sendtoftp"){ preferences.putBool("sendtoftp", varValue.bool());}                      
                    if(varName == "ftpServer"){ preferences.putChar("ftpServer", varValue.c_str());}                        
                    if(varName == "ftpUser"){ preferences.putChar("ftpUser", varValue.c_str());}                        
--error-->     if(varName == "ftpPass"){ preferences.putChar("ftpPass", varValue.c_str());}                  
                  
                  }

But when I compile it produces an error message as below (highlighting the line marked above):

exit status 1
invalid conversion from 'const char*' to 'int8_t {aka signed char}' [-fpermissive]

Thanks
Paulo