ESP3D Lib  1.0
3D Printer WiFi Library
web_server.cpp
Go to the documentation of this file.
1 /*
2  web_server.cpp - web server functions class
3 
4  Copyright (c) 2014 Luc Lebosse. All rights reserved.
5 
6  This library is free software; you can redistribute it and/or
7  modify it under the terms of the GNU Lesser General Public
8  License as published by the Free Software Foundation; either
9  version 2.1 of the License, or (at your option) any later version.
10 
11  This library is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  Lesser General Public License for more details.
15 
16  You should have received a copy of the GNU Lesser General Public
17  License along with this library; if not, write to the Free Software
18  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20 
21 #ifdef ARDUINO_ARCH_ESP32
22 
23 #include "esplibconfig.h"
24 
25 
26 #if ENABLED(ESP3D_WIFISUPPORT)
27 
28 #include "wificonfig.h"
29 
30 #if defined (ENABLE_HTTP)
31 #include MARLIN_PATH(gcode/queue.h)
32 #include MARLIN_PATH(inc/Version.h)
33 #undef DISABLED
34 #undef _BV
35 #include "wifiservices.h"
36 #include "serial2socket.h"
37 #include "web_server.h"
38 #include <WebSocketsServer.h>
39 #include <WiFi.h>
40 #include <FS.h>
41 #include <SPIFFS.h>
42 #if ENABLED(SDSUPPORT)
43 #include "sd_ESP32.h"
44 #endif
45 #include <Preferences.h>
46 #include <WebServer.h>
47 #include <ESP32SSDP.h>
48 #include <StreamString.h>
49 #include <Update.h>
50 #include <esp_wifi.h>
51 #include <esp_wifi_types.h>
52 #ifdef ENABLE_MDNS
53 #include <ESPmDNS.h>
54 #endif
55 #ifdef ENABLE_SSDP
56 #include <ESP32SSDP.h>
57 #endif
58 #ifdef ENABLE_CAPTIVE_PORTAL
59 #include <DNSServer.h>
60 const byte DNS_PORT = 53;
61 DNSServer dnsServer;
62 #endif
63 
64 //embedded response file if no files on SPIFFS
65 #include "nofile.h"
66 
67 //Upload status
68 typedef enum {
69  UPLOAD_STATUS_NONE = 0,
70  UPLOAD_STATUS_FAILED = 1,
71  UPLOAD_STATUS_CANCELLED = 2,
72  UPLOAD_STATUS_SUCCESSFUL = 3,
73  UPLOAD_STATUS_ONGOING = 4
74 } upload_status_type;
75 
76 #ifdef ENABLE_AUTHENTICATION
77 #define DEFAULT_ADMIN_PWD "admin"
78 #define DEFAULT_USER_PWD "user";
79 #define DEFAULT_ADMIN_LOGIN "admin"
80 #define DEFAULT_USER_LOGIN "user"
81 #define ADMIN_PWD_ENTRY "ADMIN_PWD"
82 #define USER_PWD_ENTRY "USER_PWD"
83 #define AUTH_ENTRY_NB 20
84 #define MAX_LOCAL_PASSWORD_LENGTH 16
85 #define MIN_LOCAL_PASSWORD_LENGTH 1
86 #endif
87 
88 //Default 404
89 const char PAGE_404 [] = "<HTML>\n<HEAD>\n<title>Redirecting...</title> \n</HEAD>\n<BODY>\n<CENTER>Unknown page : $QUERY$- you will be redirected...\n<BR><BR>\nif not redirected, <a href='http://$WEB_ADDRESS$'>click here</a>\n<BR><BR>\n<PROGRESS name='prg' id='prg'></PROGRESS>\n\n<script>\nvar i = 0; \nvar x = document.getElementById(\"prg\"); \nx.max=5; \nvar interval=setInterval(function(){\ni=i+1; \nvar x = document.getElementById(\"prg\"); \nx.value=i; \nif (i>5) \n{\nclearInterval(interval);\nwindow.location.href='/';\n}\n},1000);\n</script>\n</CENTER>\n</BODY>\n</HTML>\n\n";
90 const char PAGE_CAPTIVE [] = "<HTML>\n<HEAD>\n<title>Captive Portal</title> \n</HEAD>\n<BODY>\n<CENTER>Captive Portal page : $QUERY$- you will be redirected...\n<BR><BR>\nif not redirected, <a href='http://$WEB_ADDRESS$'>click here</a>\n<BR><BR>\n<PROGRESS name='prg' id='prg'></PROGRESS>\n\n<script>\nvar i = 0; \nvar x = document.getElementById(\"prg\"); \nx.max=5; \nvar interval=setInterval(function(){\ni=i+1; \nvar x = document.getElementById(\"prg\"); \nx.value=i; \nif (i>5) \n{\nclearInterval(interval);\nwindow.location.href='/';\n}\n},1000);\n</script>\n</CENTER>\n</BODY>\n</HTML>\n\n";
91 
92 
94 bool Web_Server::_setupdone = false;
95 uint16_t Web_Server::_port = 0;
96 String Web_Server::_hostname = "";
97 uint16_t Web_Server::_data_port = 0;
98 long Web_Server::_id_connection = 0;
99 uint8_t Web_Server::_upload_status = UPLOAD_STATUS_NONE;
100 WebServer * Web_Server::_webserver = NULL;
101 WebSocketsServer * Web_Server::_socket_server = NULL;
102 #ifdef ENABLE_AUTHENTICATION
103 auth_ip * Web_Server::_head = NULL;
104 uint8_t Web_Server::_nb_ip = 0;
105 #define MAX_AUTH_IP 10
106 #endif
108 
109 }
111  end();
112 }
113 
115  return _id_connection;
116 }
117 
118 bool Web_Server::begin(){
119 
120  bool no_error = true;
121  _setupdone = false;
122  Preferences prefs;
123  prefs.begin(NAMESPACE, true);
124  int8_t penabled = prefs.getChar(HTTP_ENABLE_ENTRY, DEFAULT_HTTP_STATE);
125  //Get http port
126  _port = prefs.getUShort(HTTP_PORT_ENTRY, DEFAULT_WEBSERVER_PORT);
127  //Get hostname
128  String defV = DEFAULT_HOSTNAME;
129  _hostname = prefs.getString(HOSTNAME_ENTRY, defV);
130  prefs.end();
131  if (penabled == 0) return false;
132  //create instance
133  _webserver= new WebServer(_port);
134 #ifdef ENABLE_AUTHENTICATION
135  //here the list of headers to be recorded
136  const char * headerkeys[] = {"Cookie"} ;
137  size_t headerkeyssize = sizeof (headerkeys) / sizeof (char*);
138  //ask server to track these headers
139  _webserver->collectHeaders (headerkeys, headerkeyssize );
140 #endif
141  _socket_server = new WebSocketsServer(_port + 1);
142  _socket_server->begin();
143  _socket_server->onEvent(handle_Websocket_Event);
144 
145 
146  //Websocket output
147  Serial2Socket.attachWS(_socket_server);
148 
149  //Web server handlers
150  //trick to catch command line on "/" before file being processed
151  _webserver->on("/",HTTP_ANY, handle_root);
152 
153  //Page not found handler
154  _webserver->onNotFound (handle_not_found);
155 
156  //need to be there even no authentication to say to UI no authentication
157  _webserver->on("/login", HTTP_ANY, handle_login);
158 
159  //web commands
160  _webserver->on ("/command", HTTP_ANY, handle_web_command);
161  _webserver->on ("/command_silent", HTTP_ANY, handle_web_command_silent);
162 
163  //SPIFFS
164  _webserver->on ("/files", HTTP_ANY, handleFileList, SPIFFSFileupload);
165 
166  //web update
167  _webserver->on ("/updatefw", HTTP_ANY, handleUpdate, WebUpdateUpload);
168 
169 #if ENABLED(SDSUPPORT)
170  //Direct SD management
171  _webserver->on("/upload", HTTP_ANY, handle_direct_SDFileList,SDFile_direct_upload);
172 #endif
173 
174 #ifdef ENABLE_CAPTIVE_PORTAL
175  if(WiFi.getMode() == WIFI_AP){
176  // if DNSServer is started with "*" for domain name, it will reply with
177  // provided IP to all DNS request
178  dnsServer.start(DNS_PORT, "*", WiFi.softAPIP());
179  _webserver->on ("/generate_204", HTTP_ANY, handle_root);
180  _webserver->on ("/gconnectivitycheck.gstatic.com", HTTP_ANY, handle_root);
181  //do not forget the / at the end
182  _webserver->on ("/fwlink/", HTTP_ANY, handle_root);
183  }
184 #endif
185 
186 #ifdef ENABLE_SSDP
187  //SSDP service presentation
188  if(WiFi.getMode() == WIFI_STA){
189  _webserver->on ("/description.xml", HTTP_GET, handle_SSDP);
190  //Add specific for SSDP
191  SSDP.setSchemaURL ("description.xml");
192  SSDP.setHTTPPort (_port);
193  SSDP.setName (_hostname);
194  SSDP.setURL ("/");
195  SSDP.setDeviceType ("upnp:rootdevice");
196  /*Any customization could be here
197  SSDP.setModelName (ESP32_MODEL_NAME);
198  SSDP.setModelURL (ESP32_MODEL_URL);
199  SSDP.setModelNumber (ESP_MODEL_NUMBER);
200  SSDP.setManufacturer (ESP_MANUFACTURER_NAME);
201  SSDP.setManufacturerURL (ESP_MANUFACTURER_URL);
202  */
203 
204  //Start SSDP
205  MYSERIAL0.println("SSDP Started");
206  SSDP.begin();
207  }
208 #endif
209  MYSERIAL0.println("HTTP Started");
210  //start webserver
211  _webserver->begin();
212 #ifdef ENABLE_MDNS
213  //add mDNS
214  if(WiFi.getMode() == WIFI_STA){
215  MDNS.addService("http","tcp",_port);
216  }
217 #endif
218  _setupdone = true;
219  return no_error;
220 }
221 
222 void Web_Server::end(){
223  _setupdone = false;
224 #ifdef ENABLE_SSDP
225  SSDP.end();
226 #endif
227 #ifdef ENABLE_MDNS
228  //remove mDNS
229  mdns_service_remove("_http", "_tcp");
230 #endif
231  if (_socket_server) {
232  delete _socket_server;
233  _socket_server = NULL;
234  }
235  if (_webserver) {
236  delete _webserver;
237  _webserver = NULL;
238  }
239 #ifdef ENABLE_AUTHENTICATION
240  while (_head) {
241  auth_ip * current = _head;
242  _head = _head->_next;
243  delete current;
244  }
245  _nb_ip = 0;
246 #endif
247 }
248 
249 //Root of Webserver/////////////////////////////////////////////////////
250 
251 void Web_Server::handle_root()
252 {
253  String path = "/index.html";
254  String contentType = getContentType(path);
255  String pathWithGz = path + ".gz";
256  //if have a index.html or gzip version this is default root page
257  if((SPIFFS.exists(pathWithGz) || SPIFFS.exists(path)) && !_webserver->hasArg("forcefallback") && _webserver->arg("forcefallback")!="yes") {
258  if(SPIFFS.exists(pathWithGz)) {
259  path = pathWithGz;
260  }
261  File file = SPIFFS.open(path, FILE_READ);
262  _webserver->streamFile(file, contentType);
263  file.close();
264  return;
265  }
266  //if no lets launch the default content
267  _webserver->sendHeader("Content-Encoding", "gzip");
268  _webserver->send_P(200,"text/html",PAGE_NOFILES,PAGE_NOFILES_SIZE);
269 }
270 
271 //Handle not registred path on SPIFFS neither SD ///////////////////////
272 void Web_Server:: handle_not_found()
273 {
274  if (is_authenticated() == LEVEL_GUEST) {
275  _webserver->sendContent_P("HTTP/1.1 301 OK\r\nLocation: /\r\nCache-Control: no-cache\r\n\r\n");
276  //_webserver->client().stop();
277  return;
278  }
279  bool page_not_found = false;
280  String path = _webserver->urlDecode(_webserver->uri());
281  String contentType = getContentType(path);
282  String pathWithGz = path + ".gz";
283 
284 #if ENABLED(SDSUPPORT)
285  if ((path.substring(0,4) == "/SD/")) {
286  //remove /SD
287  path = path.substring(3);
288  ESP_SD SD_card;
289  if (SD_card.card_status() == 1) {
290  if (SD_card.exists(pathWithGz.c_str()) || SD_card.exists(path.c_str())) {
291  if (!SD_card.exists(path.c_str())) path = pathWithGz;
292  if(SD_card.open(path.c_str())) {
293  uint8_t buf[1200];
294  _webserver->setContentLength(SD_card.size());
295  _webserver->sendHeader("Cache-Control","no-cache");
296  _webserver->send(200, "application/octet-stream", "");
297 
298  WiFiClient c = _webserver->client();
299  int16_t len = SD_card.read( buf, 1200);
300  while(len > 0) {
301  c.write(buf, len);
302  len = SD_card.read( buf, 1200);
303  wifi_config.wait(0);
304  handle();
305  }
306  SD_card.close();
307  return;
308  }
309  }
310  }
311 
312  String content = "cannot find ";
313  content+=path;
314  _webserver->send(404,"text/plain",content.c_str());
315  return;
316  } else
317 #endif
318  if(SPIFFS.exists(pathWithGz) || SPIFFS.exists(path)) {
319  if(SPIFFS.exists(pathWithGz)) {
320  path = pathWithGz;
321  }
322  File file = SPIFFS.open(path, FILE_READ);
323  _webserver->streamFile(file, contentType);
324  file.close();
325  return;
326  } else {
327  page_not_found = true;
328  }
329 
330  if (page_not_found ) {
331 #ifdef ENABLE_CAPTIVE_PORTAL
332  if (WiFi.getMode()!=WIFI_STA ) {
333  String content=PAGE_CAPTIVE;
334  String stmp = WiFi.softAPIP().toString();
335  //Web address = ip + port
336  String KEY_IP = "$WEB_ADDRESS$";
337  String KEY_QUERY = "$QUERY$";
338  if (_port != 80) {
339  stmp+=":";
340  stmp+=String(_port);
341  }
342  content.replace(KEY_IP,stmp);
343  content.replace(KEY_IP,stmp);
344  content.replace(KEY_QUERY,_webserver->uri());
345  _webserver->send(200,"text/html",content);
346  return;
347  }
348 #endif
349  path = "/404.htm";
350  contentType = getContentType(path);
351  pathWithGz = path + ".gz";
352  if(SPIFFS.exists(pathWithGz) || SPIFFS.exists(path)) {
353  if(SPIFFS.exists(pathWithGz)) {
354  path = pathWithGz;
355  }
356  File file = SPIFFS.open(path, FILE_READ);
357  _webserver->streamFile(file, contentType);
358  file.close();
359 
360  } else {
361  //if not template use default page
362  contentType = PAGE_404;
363  String stmp;
364  if (WiFi.getMode()==WIFI_STA ) {
365  stmp=WiFi.localIP().toString();
366  } else {
367  stmp=WiFi.softAPIP().toString();
368  }
369  //Web address = ip + port
370  String KEY_IP = "$WEB_ADDRESS$";
371  String KEY_QUERY = "$QUERY$";
372  if ( _port != 80) {
373  stmp+=":";
374  stmp+=String(_port);
375  }
376  contentType.replace(KEY_IP,stmp);
377  contentType.replace(KEY_QUERY,_webserver->uri());
378  _webserver->send(200,"text/html",contentType);
379  }
380  }
381 }
382 #ifdef ENABLE_SSDP
383 //http SSDP xml presentation
384 void Web_Server::handle_SSDP ()
385 {
386  StreamString sschema ;
387  if (sschema.reserve (1024) ) {
388  String templ = "<?xml version=\"1.0\"?>"
389  "<root xmlns=\"urn:schemas-upnp-org:device-1-0\">"
390  "<specVersion>"
391  "<major>1</major>"
392  "<minor>0</minor>"
393  "</specVersion>"
394  "<URLBase>http://%s:%u/</URLBase>"
395  "<device>"
396  "<deviceType>upnp:rootdevice</deviceType>"
397  "<friendlyName>%s</friendlyName>"
398  "<presentationURL>/</presentationURL>"
399  "<serialNumber>%s</serialNumber>"
400  "<modelName>ESP32</modelName>"
401  "<modelNumber>Marlin</modelNumber>"
402  "<modelURL>http://espressif.com/en/products/hardware/esp-wroom-32/overview</modelURL>"
403  "<manufacturer>Espressif Systems</manufacturer>"
404  "<manufacturerURL>http://espressif.com</manufacturerURL>"
405  "<UDN>uuid:%s</UDN>"
406  "</device>"
407  "</root>\r\n"
408  "\r\n";
409  char uuid[37];
410  String sip = WiFi.localIP().toString();
411  uint32_t chipId = (uint16_t) (ESP.getEfuseMac() >> 32);
412  sprintf (uuid, "38323636-4558-4dda-9188-cda0e6%02x%02x%02x",
413  (uint16_t) ( (chipId >> 16) & 0xff),
414  (uint16_t) ( (chipId >> 8) & 0xff),
415  (uint16_t) chipId & 0xff );
416  String serialNumber = String (chipId);
417  sschema.printf (templ.c_str(),
418  sip.c_str(),
419  _port,
420  _hostname.c_str(),
421  serialNumber.c_str(),
422  uuid);
423  _webserver->send (200, "text/xml", (String) sschema);
424  } else {
425  _webserver->send (500);
426  }
427 }
428 
429 #endif
430 
431 //Handle web command query and send answer//////////////////////////////
432 void Web_Server::handle_web_command ()
433 {
434  //to save time if already disconnected
435  //if (_webserver->hasArg ("PAGEID") ) {
436  // if (_webserver->arg ("PAGEID").length() > 0 ) {
437  // if (_webserver->arg ("PAGEID").toInt() != _id_connection) {
438  // _webserver->send (200, "text/plain", "Invalid command");
439  // return;
440  // }
441  // }
442  //}
443  level_authenticate_type auth_level = is_authenticated();
444  String cmd = "";
445  if (_webserver->hasArg ("plain") || _webserver->hasArg ("commandText") ) {
446  if (_webserver->hasArg ("plain") ) {
447  cmd = _webserver->arg ("plain");
448  } else {
449  cmd = _webserver->arg ("commandText");
450  }
451  } else {
452  _webserver->send (200, "text/plain", "Invalid command");
453  return;
454  }
455  //if it is internal command [ESPXXX]<parameter>
456  cmd.trim();
457  int ESPpos = cmd.indexOf ("[ESP");
458  if (ESPpos > -1) {
459  //is there the second part?
460  int ESPpos2 = cmd.indexOf ("]", ESPpos);
461  if (ESPpos2 > -1) {
462  //Split in command and parameters
463  String cmd_part1 = cmd.substring (ESPpos + 4, ESPpos2);
464  String cmd_part2 = "";
465  //only [ESP800] is allowed login free if authentication is enabled
466  if ( (auth_level == LEVEL_GUEST) && (cmd_part1.toInt() != 800) ) {
467  _webserver->send (401, "text/plain", "Authentication failed!\n");
468  return;
469  }
470  //is there space for parameters?
471  if (ESPpos2 < cmd.length() ) {
472  cmd_part2 = cmd.substring (ESPpos2 + 1);
473  }
474  //if command is a valid number then execute command
475  if (cmd_part1.toInt() != 0) {
476  ESPResponseStream espresponse(_webserver);
477  //commmand is web only
478  execute_internal_command (cmd_part1.toInt(), cmd_part2, auth_level, &espresponse);
479  //flush
480  espresponse.flush();
481  }
482  //if not is not a valid [ESPXXX] command
483  }
484  } else { //execute GCODE
485  if (auth_level == LEVEL_GUEST) {
486  _webserver->send (401, "text/plain", "Authentication failed!\n");
487  return;
488  }
489  //Instead of send several commands one by one by web / send full set and split here
490  String scmd;
491  String res = "Ok";
492  uint8_t sindex = 0;
493  scmd = get_Splited_Value(cmd,'\n', sindex);
494  while ( scmd != "" ){
495  scmd+="\n";
496  Serial2Socket.push(scmd.c_str());
497  //GCodeQueue::enqueue_one_now(scmd.c_str());
498  sindex++;
499  scmd = get_Splited_Value(cmd,'\n', sindex);
500  }
501  _webserver->send (200, "text/plain", res.c_str());
502  }
503 }
504 //Handle web command query and send answer//////////////////////////////
505 void Web_Server::handle_web_command_silent ()
506 {
507  //to save time if already disconnected
508  //if (_webserver->hasArg ("PAGEID") ) {
509  // if (_webserver->arg ("PAGEID").length() > 0 ) {
510  // if (_webserver->arg ("PAGEID").toInt() != _id_connection) {
511  // _webserver->send (200, "text/plain", "Invalid command");
512  // return;
513  // }
514  // }
515  //}
516  level_authenticate_type auth_level = is_authenticated();
517  String cmd = "";
518  if (_webserver->hasArg ("plain") || _webserver->hasArg ("commandText") ) {
519  if (_webserver->hasArg ("plain") ) {
520  cmd = _webserver->arg ("plain");
521  } else {
522  cmd = _webserver->arg ("commandText");
523  }
524  } else {
525  _webserver->send (200, "text/plain", "Invalid command");
526  return;
527  }
528  //if it is internal command [ESPXXX]<parameter>
529  cmd.trim();
530  int ESPpos = cmd.indexOf ("[ESP");
531  if (ESPpos > -1) {
532  //is there the second part?
533  int ESPpos2 = cmd.indexOf ("]", ESPpos);
534  if (ESPpos2 > -1) {
535  //Split in command and parameters
536  String cmd_part1 = cmd.substring (ESPpos + 4, ESPpos2);
537  String cmd_part2 = "";
538  //only [ESP800] is allowed login free if authentication is enabled
539  if ( (auth_level == LEVEL_GUEST) && (cmd_part1.toInt() != 800) ) {
540  _webserver->send (401, "text/plain", "Authentication failed!\n");
541  return;
542  }
543  //is there space for parameters?
544  if (ESPpos2 < cmd.length() ) {
545  cmd_part2 = cmd.substring (ESPpos2 + 1);
546  }
547  //if command is a valid number then execute command
548  if (cmd_part1.toInt() != 0) {
549  //commmand is web only
550  if(execute_internal_command (cmd_part1.toInt(), cmd_part2, auth_level, NULL)) _webserver->send (200, "text/plain", "ok");
551  else _webserver->send (200, "text/plain", "error");
552  }
553  //if not is not a valid [ESPXXX] command
554  }
555  } else { //execute GCODE
556  if (auth_level == LEVEL_GUEST) {
557  _webserver->send (401, "text/plain", "Authentication failed!\n");
558  return;
559  }
560  //Instead of send several commands one by one by web / send full set and split here
561  String scmd;
562  uint8_t sindex = 0;
563  scmd = get_Splited_Value(cmd,'\n', sindex);
564  String res = "Ok";
565  while (scmd != "" ){
566  scmd+="\n";
567  Serial2Socket.push(scmd.c_str());
568  //GCodeQueue::enqueue_one_now(scmd.c_str());
569  sindex++;
570  scmd = get_Splited_Value(cmd,'\n', sindex);
571  }
572  _webserver->send (200, "text/plain", res.c_str());
573  }
574 }
575 
576 
577 bool Web_Server::execute_internal_command (int cmd, String cmd_params, level_authenticate_type auth_level, ESPResponseStream *espresponse)
578 {
579  bool response = true;
580  level_authenticate_type auth_type = auth_level;
581 
582  //manage parameters
583  String parameter;
584  switch (cmd) {
585  //Get SD Card Status
586  //[ESP200]
587  case 200:
588  {
589  if (!espresponse) return false;
590  String resp = "No SD card";
591 #if ENABLED(SDSUPPORT)
592  ESP_SD card;
593  int8_t state = card.card_status();
594  if (state == -1)resp="Busy";
595  else if (state == 1)resp="SD card detected";
596  else resp="No SD card";
597 #endif
598  espresponse->println (resp.c_str());
599  }
600  break;
601  //Get full ESP32 wifi settings content
602  //[ESP400]
603  case 400:
604  {
605  String v;
606  String defV;
607  Preferences prefs;
608  if (!espresponse) return false;
609 #ifdef ENABLE_AUTHENTICATION
610  if (auth_type == LEVEL_GUEST) return false;
611 #endif
612  int8_t vi;
613  espresponse->print("{\"EEPROM\":[");
614  prefs.begin(NAMESPACE, true);
615  //1 - Hostname
616  espresponse->print ("{\"F\":\"network\",\"P\":\"");
617  espresponse->print (HOSTNAME_ENTRY);
618  espresponse->print ("\",\"T\":\"S\",\"V\":\"");
619  espresponse->print (_hostname.c_str());
620  espresponse->print ("\",\"H\":\"Hostname\" ,\"S\":\"");
621  espresponse->print (String(MAX_HOSTNAME_LENGTH).c_str());
622  espresponse->print ("\", \"M\":\"");
623  espresponse->print (String(MIN_HOSTNAME_LENGTH).c_str());
624  espresponse->print ("\"}");
625  espresponse->print (",");
626 
627  //2 - http protocol mode
628  espresponse->print ("{\"F\":\"network\",\"P\":\"");
629  espresponse->print (HTTP_ENABLE_ENTRY);
630  espresponse->print ("\",\"T\":\"B\",\"V\":\"");
631  vi = prefs.getChar(HTTP_ENABLE_ENTRY, 1);
632  espresponse->print (String(vi).c_str());
633  espresponse->print ("\",\"H\":\"HTTP protocol\",\"O\":[{\"Enabled\":\"1\"},{\"Disabled\":\"0\"}]}");
634  espresponse->print (",");
635 
636  //3 - http port
637  espresponse->print ("{\"F\":\"network\",\"P\":\"");
638  espresponse->print (HTTP_PORT_ENTRY);
639  espresponse->print ("\",\"T\":\"I\",\"V\":\"");
640  espresponse->print (String(_port).c_str());
641  espresponse->print ("\",\"H\":\"HTTP Port\",\"S\":\"");
642  espresponse->print (String(MAX_HTTP_PORT).c_str());
643  espresponse->print ("\",\"M\":\"");
644  espresponse->print (String(MIN_HTTP_PORT).c_str());
645  espresponse->print ("\"}");
646  espresponse->print (",");
647 
648  //TODO
649  //4 - telnet protocol mode
650  /* espresponse->print ("{\"F\":\"network\",\"P\":\"");
651  espresponse->print (TELNET_ENABLE_ENTRY);
652  espresponse->print ("\",\"T\":\"B\",\"V\":\"");
653  vi = prefs.getChar(TELNET_ENABLE_ENTRY, 0);
654  espresponse->print (String(vi).c_str());
655  espresponse->print ("\",\"H\":\"Telnet protocol\",\"O\":[{\"Enabled\":\"1\"},{\"Disabled\":\"0\"}]}");
656  espresponse->print (",");*/
657 
658  //5 - telnet Port
659  /* espresponse->print ("{\"F\":\"network\",\"P\":\"");
660  espresponse->print (TELNET_PORT_ENTRY);
661  espresponse->print ("\",\"T\":\"I\",\"V\":\"");
662  espresponse->print (String(_data_port).c_str());
663  espresponse->print ("\",\"H\":\"Telnet Port\",\"S\":\"");
664  espresponse->print (String(MAX_TELNET_PORT).c_str());
665  espresponse->print ("\",\"M\":\"");
666  espresponse->print (String(MIN_TELNET_PORT).c_str());
667  espresponse->print ("\"}");
668  espresponse->print (",");*/
669 
670  //6 - wifi mode
671  espresponse->print ("{\"F\":\"network\",\"P\":\"");
672  espresponse->print (ESP_WIFI_MODE);
673  espresponse->print ("\",\"T\":\"B\",\"V\":\"");
674  vi = prefs.getChar(ESP_WIFI_MODE, ESP_WIFI_OFF);
675  espresponse->print (String(vi).c_str());
676  espresponse->print ("\",\"H\":\"Wifi mode\",\"O\":[{\"STA\":\"1\"},{\"AP\":\"2\"},{\"None\":\"0\"}]}");
677  espresponse->print (",");
678 
679  //7 - STA SSID
680  espresponse->print ("{\"F\":\"network\",\"P\":\"");
681  espresponse->print (STA_SSID_ENTRY);
682  espresponse->print ("\",\"T\":\"S\",\"V\":\"");
683  defV = DEFAULT_STA_SSID;
684  espresponse->print (prefs.getString(STA_SSID_ENTRY, defV).c_str());
685  espresponse->print ("\",\"S\":\"");
686  espresponse->print (String(MAX_SSID_LENGTH).c_str());
687  espresponse->print ("\",\"H\":\"Station SSID\",\"M\":\"");
688  espresponse->print (String(MIN_SSID_LENGTH).c_str());
689  espresponse->print ("\"}");
690  espresponse->print (",");
691 
692  //8 - STA password
693  espresponse->print ("{\"F\":\"network\",\"P\":\"");
694  espresponse->print (STA_PWD_ENTRY);
695  espresponse->print ("\",\"T\":\"S\",\"V\":\"");
696  espresponse->print (HIDDEN_PASSWORD);
697  espresponse->print ("\",\"S\":\"");
698  espresponse->print (String(MAX_PASSWORD_LENGTH).c_str());
699  espresponse->print ("\",\"H\":\"Station Password\",\"M\":\"");
700  espresponse->print (String(MIN_PASSWORD_LENGTH).c_str());
701  espresponse->print ("\"}");
702  espresponse->print (",");
703 
704  // 9 - STA IP mode
705  espresponse->print ("{\"F\":\"network\",\"P\":\"");
706  espresponse->print (STA_IP_MODE_ENTRY);
707  espresponse->print ("\",\"T\":\"B\",\"V\":\"");
708  espresponse->print (String(prefs.getChar(STA_IP_MODE_ENTRY, DHCP_MODE)).c_str());
709  espresponse->print ("\",\"H\":\"Station IP Mode\",\"O\":[{\"DHCP\":\"0\"},{\"Static\":\"1\"}]}");
710  espresponse->print (",");
711 
712  //10-STA static IP
713  espresponse->print ("{\"F\":\"network\",\"P\":\"");
714  espresponse->print (STA_IP_ENTRY);
715  espresponse->print ("\",\"T\":\"A\",\"V\":\"");
716  espresponse->print (wifi_config.IP_string_from_int(prefs.getInt(STA_IP_ENTRY, 0)).c_str());
717  espresponse->print ("\",\"H\":\"Station Static IP\"}");
718  espresponse->print (",");
719 
720  //11-STA static Gateway
721  espresponse->print ("{\"F\":\"network\",\"P\":\"");
722  espresponse->print (STA_GW_ENTRY);
723  espresponse->print ("\",\"T\":\"A\",\"V\":\"");
724  espresponse->print (wifi_config.IP_string_from_int(prefs.getInt(STA_GW_ENTRY, 0)).c_str());
725  espresponse->print ("\",\"H\":\"Station Static Gateway\"}");
726  espresponse->print (",");
727 
728  //12-STA static Mask
729  espresponse->print ("{\"F\":\"network\",\"P\":\"");
730  espresponse->print (STA_MK_ENTRY);
731  espresponse->print ("\",\"T\":\"A\",\"V\":\"");
732  espresponse->print (wifi_config.IP_string_from_int(prefs.getInt(STA_MK_ENTRY, 0)).c_str());
733  espresponse->print ("\",\"H\":\"Station Static Mask\"}");
734  espresponse->print (",");
735 
736  //13 - AP SSID
737  espresponse->print ("{\"F\":\"network\",\"P\":\"");
738  espresponse->print (AP_SSID_ENTRY);
739  espresponse->print ("\",\"T\":\"S\",\"V\":\"");
740  defV = DEFAULT_AP_SSID;
741  espresponse->print (prefs.getString(AP_SSID_ENTRY, defV).c_str());
742  espresponse->print ("\",\"S\":\"");
743  espresponse->print (String(MAX_SSID_LENGTH).c_str());
744  espresponse->print ("\",\"H\":\"AP SSID\",\"M\":\"");
745  espresponse->print (String(MIN_SSID_LENGTH).c_str());
746  espresponse->print ("\"}");
747  espresponse->print (",");
748 
749  //14 - AP password
750  espresponse->print ("{\"F\":\"network\",\"P\":\"");
751  espresponse->print (AP_PWD_ENTRY);
752  espresponse->print ("\",\"T\":\"S\",\"V\":\"");
753  espresponse->print (HIDDEN_PASSWORD);
754  espresponse->print ("\",\"S\":\"");
755  espresponse->print (String(MAX_PASSWORD_LENGTH).c_str());
756  espresponse->print ("\",\"H\":\"AP Password\",\"M\":\"");
757  espresponse->print (String(MIN_PASSWORD_LENGTH).c_str());
758  espresponse->print ("\"}");
759  espresponse->print (",");
760 
761  //15 - AP static IP
762  espresponse->print ("{\"F\":\"network\",\"P\":\"");
763  espresponse->print (AP_IP_ENTRY);
764  espresponse->print ("\",\"T\":\"A\",\"V\":\"");
765  defV = DEFAULT_AP_IP;
766  espresponse->print (wifi_config.IP_string_from_int(prefs.getInt(AP_IP_ENTRY, wifi_config.IP_int_from_string(defV))).c_str());
767  espresponse->print ("\",\"H\":\"AP Static IP\"}");
768  espresponse->print (",");
769 
770  //16 - AP Channel
771  espresponse->print ("{\"F\":\"network\",\"P\":\"");
772  espresponse->print (AP_CHANNEL_ENTRY);
773  espresponse->print ("\",\"T\":\"B\",\"V\":\"");
774  espresponse->print (String(prefs.getChar(AP_CHANNEL_ENTRY, DEFAULT_AP_CHANNEL)).c_str());
775  espresponse->print ("\",\"H\":\"AP Channel\",\"O\":[");
776  for (int i = MIN_CHANNEL; i <= MAX_CHANNEL ; i++) {
777  espresponse->print ("{\"");
778  espresponse->print (String(i).c_str());
779  espresponse->print ("\":\"");
780  espresponse->print (String(i).c_str());
781  espresponse->print ("\"}");
782  if (i < MAX_CHANNEL) {
783  espresponse->print (",");
784  }
785  }
786  espresponse->print ("]}");
787 
788  espresponse->print ("]}");
789  prefs.end();
790  }
791  break;
792  //Set EEPROM setting
793  //[ESP401]P=<position> T=<type> V=<value> pwd=<user/admin password>
794  case 401:
795  {
796 #ifdef ENABLE_AUTHENTICATION
797  if (auth_type != LEVEL_ADMIN) return false;
798 #endif
799  //check validity of parameters
800  String spos = get_param (cmd_params, "P=", false);
801  String styp = get_param (cmd_params, "T=", false);
802  String sval = get_param (cmd_params, "V=", true);
803  spos.trim();
804  sval.trim();
805  if (spos.length() == 0) {
806  response = false;
807  }
808  if (! (styp == "B" || styp == "S" || styp == "A" || styp == "I" || styp == "F") ) {
809  response = false;
810  }
811  if ((sval.length() == 0) && !((spos==AP_PWD_ENTRY) || (spos==STA_PWD_ENTRY))){
812  response = false;
813  }
814 
815  if (response) {
816  Preferences prefs;
817  prefs.begin(NAMESPACE, false);
818  //Byte value
819  if ((styp == "B") || (styp == "F")){
820  int8_t bbuf = sval.toInt();
821  if (prefs.putChar(spos.c_str(), bbuf) ==0 ) {
822  response = false;
823  } else {
824  //dynamique refresh is better than restart the board
825  if (spos == ESP_WIFI_MODE){
826  //TODO
827  }
828  if (spos == AP_CHANNEL_ENTRY) {
829  //TODO
830  }
831  if (spos == HTTP_ENABLE_ENTRY) {
832  //TODO
833  }
834  if (spos == TELNET_ENABLE_ENTRY) {
835  //TODO
836  }
837  }
838  }
839  //Integer value
840  if (styp == "I") {
841  int16_t ibuf = sval.toInt();
842  if (prefs.putUShort(spos.c_str(), ibuf) == 0) {
843  response = false;
844  } else {
845  if (spos == HTTP_PORT_ENTRY){
846  //TODO
847  }
848  if (spos == TELNET_PORT_ENTRY){
849  //TODO
850  //Serial.println(ibuf);
851  }
852  }
853 
854  }
855  //String value
856  if (styp == "S") {
857  if (prefs.putString(spos.c_str(), sval) == 0) {
858  response = false;
859  } else {
860  if (spos == HOSTNAME_ENTRY){
861  //TODO
862  }
863  if (spos == STA_SSID_ENTRY){
864  //TODO
865  }
866  if (spos == STA_PWD_ENTRY){
867  //TODO
868  }
869  if (spos == AP_SSID_ENTRY){
870  //TODO
871  }
872  if (spos == AP_PWD_ENTRY){
873  //TODO
874  }
875  }
876 
877  }
878  //IP address
879  if (styp == "A") {
880  if (prefs.putInt(spos.c_str(), wifi_config.IP_int_from_string(sval)) == 0) {
881  response = false;
882  } else {
883  if (spos == STA_IP_ENTRY){
884  //TODO
885  }
886  if (spos == STA_GW_ENTRY){
887  //TODO
888  }
889  if (spos == STA_MK_ENTRY){
890  //TODO
891  }
892  if (spos == AP_IP_ENTRY){
893  //TODO
894  }
895  }
896  }
897  prefs.end();
898  }
899  if (!response) {
900  if (espresponse) espresponse->println ("Error: Incorrect Command");
901  } else {
902  if (espresponse) espresponse->println ("ok");
903  }
904 
905  }
906  break;
907  //Get available AP list (limited to 30)
908  //output is JSON
909  //[ESP410]
910  case 410: {
911  if (!espresponse)return false;
912 #ifdef ENABLE_AUTHENTICATION
913  if (auth_type == LEVEL_GUEST) return false;
914 #endif
915  espresponse->print("{\"AP_LIST\":[");
916  int n = WiFi.scanNetworks();
917  if (n > 0) {
918  for (int i = 0; i < n; ++i) {
919  if (i > 0) {
920  espresponse->print (",");
921  }
922  espresponse->print ("{\"SSID\":\"");
923  espresponse->print (WiFi.SSID (i).c_str());
924  espresponse->print ("\",\"SIGNAL\":\"");
925  espresponse->print (String(wifi_config.getSignal (WiFi.RSSI (i) )).c_str());
926  espresponse->print ("\",\"IS_PROTECTED\":\"");
927 
928  if (WiFi.encryptionType (i) == WIFI_AUTH_OPEN) {
929  espresponse->print ("0");
930  } else {
931  espresponse->print ("1");
932  }
933  espresponse->print ("\"}");
934  wifi_config.wait(0);
935  }
936  WiFi.scanDelete();
937  }
938  espresponse->print ("]}");
939  //Ugly fix for the AP mode
940  if (WiFi.getMode() == WIFI_AP_STA) {
941  WiFi.enableSTA (false);
942  }
943  }
944  break;
945  //Get ESP current status
946  case 420:
947  {
948 #ifdef ENABLE_AUTHENTICATION
949  if (auth_type == LEVEL_GUEST) return false;
950 #endif
951  if (!espresponse)return false;
952  espresponse->print ("Chip ID: ");
953  espresponse->print (String ( (uint16_t) (ESP.getEfuseMac() >> 32) ).c_str());
954  espresponse->print ("\n");
955  espresponse->print ("CPU Frequency: ");
956  espresponse->print (String (ESP.getCpuFreqMHz() ).c_str());
957  espresponse->print ("Mhz");
958  espresponse->print ("\n");
959  espresponse->print ("CPU Temperature: ");
960  espresponse->print (String (temperatureRead(), 1).c_str());
961  espresponse->print ("&deg;C");
962  espresponse->print ("\n");
963  espresponse->print ("Free memory: ");
964  espresponse->print (formatBytes (ESP.getFreeHeap()).c_str());
965  espresponse->print ("\n");
966  espresponse->print ("SDK: ");
967  espresponse->print (ESP.getSdkVersion());
968  espresponse->print ("\n");
969  espresponse->print ("Flash Size: ");
970  espresponse->print (formatBytes (ESP.getFlashChipSize()).c_str());
971  espresponse->print ("\n");
972  espresponse->print ("Available Size for update: ");
973  //Not OTA on 2Mb board per spec
974  if (ESP.getFlashChipSize() > 0x20000) {
975  espresponse->print (formatBytes (0x140000).c_str());
976  } else {
977  espresponse->print (formatBytes (0x0).c_str());
978  }
979  espresponse->print ("\n");
980  espresponse->print ("Available Size for SPIFFS: ");
981  espresponse->print (formatBytes (SPIFFS.totalBytes()).c_str());
982  espresponse->print ("\n");
983  espresponse->print ("Baud rate: ");
984  long br = Serial.baudRate();
985  //workaround for ESP32
986  if (br == 115201) {
987  br = 115200;
988  }
989  if (br == 230423) {
990  br = 230400;
991  }
992  espresponse->print (String(br).c_str());
993  espresponse->print ("\n");
994  espresponse->print ("Sleep mode: ");
995  if (WiFi.getSleep())espresponse->print ("Modem");
996  else espresponse->print ("None");
997  espresponse->print ("\n");
998  espresponse->print ("Web port: ");
999  espresponse->print (String(_port).c_str());
1000  espresponse->print ("\n");
1001  espresponse->print ("Data port: ");
1002  if (_data_port!=0)espresponse->print (String(_data_port).c_str());
1003  else espresponse->print ("Disabled");
1004  espresponse->print ("\n");
1005  espresponse->print ("Hostname: ");
1006  espresponse->print ( _hostname.c_str());
1007  espresponse->print ("\n");
1008  espresponse->print ("Active Mode: ");
1009  if (WiFi.getMode() == WIFI_STA) {
1010  espresponse->print ("STA (");
1011  espresponse->print ( WiFi.macAddress().c_str());
1012  espresponse->print (")");
1013  espresponse->print ("\n");
1014  espresponse->print ("Connected to: ");
1015  if (WiFi.isConnected()){ //in theory no need but ...
1016  espresponse->print (WiFi.SSID().c_str());
1017  espresponse->print ("\n");
1018  espresponse->print ("Signal: ");
1019  espresponse->print ( String(wifi_config.getSignal (WiFi.RSSI())).c_str());
1020  espresponse->print ("%");
1021  espresponse->print ("\n");
1022  uint8_t PhyMode;
1023  esp_wifi_get_protocol (ESP_IF_WIFI_STA, &PhyMode);
1024  espresponse->print ("Phy Mode: ");
1025  if (PhyMode == (WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N)) espresponse->print ("11n");
1026  else if (PhyMode == (WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G)) espresponse->print ("11g");
1027  else if (PhyMode == (WIFI_PROTOCOL_11B )) espresponse->print ("11b");
1028  else espresponse->print ("???");
1029  espresponse->print ("\n");
1030  espresponse->print ("Channel: ");
1031  espresponse->print (String (WiFi.channel()).c_str());
1032  espresponse->print ("\n");
1033  espresponse->print ("IP Mode: ");
1034  tcpip_adapter_dhcp_status_t dhcp_status;
1035  tcpip_adapter_dhcpc_get_status (TCPIP_ADAPTER_IF_STA, &dhcp_status);
1036  if (dhcp_status == TCPIP_ADAPTER_DHCP_STARTED)espresponse->print ("DHCP");
1037  else espresponse->print ("Static");
1038  espresponse->print ("\n");
1039  espresponse->print ("IP: ");
1040  espresponse->print (WiFi.localIP().toString().c_str());
1041  espresponse->print ("\n");
1042  espresponse->print ("Gateway: ");
1043  espresponse->print (WiFi.gatewayIP().toString().c_str());
1044  espresponse->print ("\n");
1045  espresponse->print ("Mask: ");
1046  espresponse->print (WiFi.subnetMask().toString().c_str());
1047  espresponse->print ("\n");
1048  espresponse->print ("DNS: ");
1049  espresponse->print (WiFi.dnsIP().toString().c_str());
1050  espresponse->print ("\n");
1051  } //this is web command so connection => no command
1052  espresponse->print ("Disabled Mode: ");
1053  espresponse->print ("AP (");
1054  espresponse->print (WiFi.softAPmacAddress().c_str());
1055  espresponse->print (")");
1056  espresponse->print ("\n");
1057  } else if (WiFi.getMode() == WIFI_AP) {
1058  espresponse->print ("AP (");
1059  espresponse->print (WiFi.softAPmacAddress().c_str());
1060  espresponse->print (")");
1061  espresponse->print ("\n");
1062  wifi_config_t conf;
1063  esp_wifi_get_config (ESP_IF_WIFI_AP, &conf);
1064  espresponse->print ("SSID: ");
1065  espresponse->print ((const char*) conf.ap.ssid);
1066  espresponse->print ("\n");
1067  espresponse->print ("Visible: ");
1068  espresponse->print ( (conf.ap.ssid_hidden == 0) ? "Yes" : "No");
1069  espresponse->print ("\n");
1070  espresponse->print ("Authentication: ");
1071  if (conf.ap.authmode == WIFI_AUTH_OPEN) {
1072  espresponse->print ("None");
1073  } else if (conf.ap.authmode == WIFI_AUTH_WEP) {
1074  espresponse->print ("WEP");
1075  } else if (conf.ap.authmode == WIFI_AUTH_WPA_PSK) {
1076  espresponse->print ("WPA");
1077  } else if (conf.ap.authmode == WIFI_AUTH_WPA2_PSK) {
1078  espresponse->print ("WPA2");
1079  } else {
1080  espresponse->print ("WPA/WPA2");
1081  }
1082  espresponse->print ("\n");
1083  espresponse->print ("Max Connections: ");
1084  espresponse->print (String(conf.ap.max_connection).c_str());
1085  espresponse->print ("\n");
1086  espresponse->print ("DHCP Server: ");
1087  tcpip_adapter_dhcp_status_t dhcp_status;
1088  tcpip_adapter_dhcps_get_status (TCPIP_ADAPTER_IF_AP, &dhcp_status);
1089  if (dhcp_status == TCPIP_ADAPTER_DHCP_STARTED)espresponse->print ("Started");
1090  else espresponse->print ("Stopped");
1091  espresponse->print ("\n");
1092  espresponse->print ("IP: ");
1093  espresponse->print (WiFi.softAPIP().toString().c_str());
1094  espresponse->print ("\n");
1095  tcpip_adapter_ip_info_t ip_AP;
1096  tcpip_adapter_get_ip_info (TCPIP_ADAPTER_IF_AP, &ip_AP);
1097  espresponse->print ("Gateway: ");
1098  espresponse->print (IPAddress (ip_AP.gw.addr).toString().c_str());
1099  espresponse->print ("\n");
1100  espresponse->print ("Mask: ");
1101  espresponse->print (IPAddress (ip_AP.netmask.addr).toString().c_str());
1102  espresponse->print ("\n");
1103  espresponse->print ("Connected clients: ");
1104  wifi_sta_list_t station;
1105  tcpip_adapter_sta_list_t tcpip_sta_list;
1106  esp_wifi_ap_get_sta_list (&station);
1107  tcpip_adapter_get_sta_list (&station, &tcpip_sta_list);
1108  espresponse->print (String(station.num).c_str());
1109  espresponse->print ("\n");
1110  for (int i = 0; i < station.num; i++) {
1111  espresponse->print (mac2str(tcpip_sta_list.sta[i].mac));
1112  espresponse->print (" ");
1113  espresponse->print ( IPAddress (tcpip_sta_list.sta[i].ip.addr).toString().c_str());
1114  espresponse->print ("\n");
1115  }
1116  espresponse->print ("Disabled Mode: ");
1117  espresponse->print ("STA (");
1118  espresponse->print (WiFi.macAddress().c_str());
1119  espresponse->print (")");
1120  espresponse->print ("\n");
1121  } else if (WiFi.getMode() == WIFI_AP_STA) //we should not be in this state but just in case ....
1122  {
1123  espresponse->print ("Mixed");
1124  espresponse->print ("\n");
1125  espresponse->print ("STA (");
1126  espresponse->print (WiFi.macAddress().c_str());
1127  espresponse->print (")");
1128  espresponse->print ("\n");
1129  espresponse->print ("AP (");
1130  espresponse->print (WiFi.softAPmacAddress().c_str());
1131  espresponse->print (")");
1132  espresponse->print ("\n");
1133 
1134  } else { //we should not be there if no wifi ....
1135  espresponse->print ("Wifi Off");
1136  espresponse->print ("\n");
1137  }
1138  //TODO to complete
1139  espresponse->print ("FW version: Marlin ");
1140  espresponse->print (SHORT_BUILD_VERSION);
1141  espresponse->print (" (ESP32)");
1142  }
1143  break;
1144  //Set ESP mode
1145  //cmd is RESTART
1146  //[ESP444]<cmd>
1147  case 444:
1148  parameter = get_param(cmd_params,"", true);
1149 #ifdef ENABLE_AUTHENTICATION
1150  if (auth_type != LEVEL_ADMIN) {
1151  response = false;
1152  } else
1153 #endif
1154  {
1155  if (parameter=="RESTART") {
1156  MYSERIAL0.println("Restart ongoing");
1157 #if NUM_SERIAL > 1
1158  MYSERIAL1.println("Restart ongoing");
1159 #endif
1161  } else response = false;
1162  }
1163  if (!response) {
1164  if (espresponse)espresponse->println ("Error: Incorrect Command");
1165  } else {
1166  if (espresponse)espresponse->println ("ok");
1167  }
1168  break;
1169 #ifdef ENABLE_AUTHENTICATION
1170  //Change / Reset user password
1171  //[ESP555]<password>
1172  case 555: {
1173  if (auth_type == LEVEL_ADMIN) {
1174  parameter = get_param (cmd_params, "", true);
1175  if (parameter.length() == 0) {
1176  Preferences prefs;
1177  parameter = DEFAULT_USER_PWD;
1178  prefs.begin(NAMESPACE, false);
1179  if (prefs.putString(USER_PWD_ENTRY, parameter) != parameter.length()){
1180  response = false;
1181  espresponse->println ("error");
1182  } else espresponse->println ("ok");
1183  prefs.end();
1184 
1185  } else {
1186  if (isLocalPasswordValid (parameter.c_str() ) ) {
1187  Preferences prefs;
1188  prefs.begin(NAMESPACE, false);
1189  if (prefs.putString(USER_PWD_ENTRY, parameter) != parameter.length()) {
1190  response = false;
1191  espresponse->println ("error");
1192  } else espresponse->println ("ok");
1193  prefs.end();
1194  } else {
1195  espresponse->println ("error");
1196  response = false;
1197  }
1198  }
1199  } else {
1200  espresponse->println ("error");
1201  response = false;
1202  }
1203  break;
1204  }
1205 #endif
1206  //[ESP700]<filename>
1207  case 700: { //read local file
1208 #ifdef ENABLE_AUTHENTICATION
1209  if (auth_type == LEVEL_GUEST) return false;
1210 #endif
1211  cmd_params.trim() ;
1212  if ( (cmd_params.length() > 0) && (cmd_params[0] != '/') ) {
1213  cmd_params = "/" + cmd_params;
1214  }
1215  File currentfile = SPIFFS.open (cmd_params, FILE_READ);
1216  if (currentfile) {//if file open success
1217  //until no line in file
1218  while (currentfile.available()) {
1219  String currentline = currentfile.readStringUntil('\n');
1220  currentline.replace("\n","");
1221  currentline.replace("\r","");
1222  if (currentline.length() > 0) {
1223  int ESPpos = currentline.indexOf ("[ESP");
1224  if (ESPpos > -1) {
1225  //is there the second part?
1226  int ESPpos2 = currentline.indexOf ("]", ESPpos);
1227  if (ESPpos2 > -1) {
1228  //Split in command and parameters
1229  String cmd_part1 = currentline.substring (ESPpos + 4, ESPpos2);
1230  String cmd_part2 = "";
1231  //is there space for parameters?
1232  if (ESPpos2 < currentline.length() ) {
1233  cmd_part2 = currentline.substring (ESPpos2 + 1);
1234  }
1235  //if command is a valid number then execute command
1236  if(cmd_part1.toInt()!=0) {
1237  if (!execute_internal_command(cmd_part1.toInt(),cmd_part2, auth_type, espresponse)) response = false;
1238  }
1239  //if not is not a valid [ESPXXX] command ignore it
1240  }
1241  } else {
1242  if (currentline.length() > 0){
1243  currentline+="\n";
1244  Serial2Socket.push(currentline.c_str());
1245  //GCodeQueue::enqueue_one_now(currentline.c_str());
1246  }
1247  wifi_config.wait (1);
1248  }
1249  wifi_config.wait (1);
1250  }
1251  }
1252  currentfile.close();
1253  if (espresponse)espresponse->println ("ok");
1254  } else {
1255  if (espresponse)espresponse->println ("error");
1256  response = false;
1257  }
1258  break;
1259  }
1260  //Format SPIFFS
1261  //[ESP710]FORMAT pwd=<admin password>
1262  case 710:
1263 #ifdef ENABLE_AUTHENTICATION
1264  if (auth_type != LEVEL_ADMIN) return false;
1265 #endif
1266  parameter = get_param (cmd_params, "", true);
1267 #ifdef ENABLE_AUTHENTICATION
1268  if (auth_type != LEVEL_ADMIN) {
1269  espresponse->println ("error");
1270  response = false;
1271  break;
1272  } else
1273 #endif
1274  {
1275  if (parameter == "FORMAT") {
1276  if (espresponse)espresponse->print ("Formating");
1277  SPIFFS.format();
1278  if (espresponse)espresponse->println ("...Done");
1279  } else {
1280  if (espresponse)espresponse->println ("error");
1281  response = false;
1282  }
1283  }
1284  break;
1285  //get fw version / fw target / hostname / authentication
1286  //[ESP800]
1287  case 800:
1288  {
1289  if (!espresponse)return false;
1290  String resp;
1291  resp = "FW version:";
1292  resp += SHORT_BUILD_VERSION;
1293  resp += " # FW target:marlin-embedded # FW HW:";
1294  #if ENABLED(SDSUPPORT)
1295  resp += "Direct SD";
1296  #else
1297  resp += "No SD";
1298  #endif
1299  resp += " # primary sd:/sd # secondary sd:none # authentication:";
1300  #ifdef ENABLE_AUTHENTICATION
1301  resp += "yes";
1302  #else
1303  resp += "no";
1304  #endif
1305  resp += " # webcommunication: Sync: ";
1306  resp += String(_port + 1);
1307  resp += "# hostname:";
1308  resp += _hostname;
1309  if (WiFi.getMode() == WIFI_AP)resp += "(AP mode)";
1310  if (espresponse)espresponse->println (resp.c_str());
1311  }
1312  break;
1313  default:
1314  if (espresponse)espresponse->println ("Error: Incorrect Command");
1315  response = false;
1316  break;
1317  }
1318  return response;
1319 }
1320 
1321 //login status check
1322 void Web_Server::handle_login()
1323 {
1324 #ifdef ENABLE_AUTHENTICATION
1325  String smsg;
1326  String sUser,sPassword;
1327  String auths;
1328  int code = 200;
1329  bool msg_alert_error=false;
1330  //disconnect can be done anytime no need to check credential
1331  if (_webserver->hasArg("DISCONNECT")) {
1332  String cookie = _webserver->header("Cookie");
1333  int pos = cookie.indexOf("ESPSESSIONID=");
1334  String sessionID;
1335  if (pos!= -1) {
1336  int pos2 = cookie.indexOf(";",pos);
1337  sessionID = cookie.substring(pos+strlen("ESPSESSIONID="),pos2);
1338  }
1339  ClearAuthIP(_webserver->client().remoteIP(), sessionID.c_str());
1340  _webserver->sendHeader("Set-Cookie","ESPSESSIONID=0");
1341  _webserver->sendHeader("Cache-Control","no-cache");
1342  String buffer2send = "{\"status\":\"Ok\",\"authentication_lvl\":\"guest\"}";
1343  _webserver->send(code, "application/json", buffer2send);
1344  //_webserver->client().stop();
1345  return;
1346  }
1347 
1348  level_authenticate_type auth_level = is_authenticated();
1349  if (auth_level == LEVEL_GUEST) auths = "guest";
1350  else if (auth_level == LEVEL_USER) auths = "user";
1351  else if (auth_level == LEVEL_ADMIN) auths = "admin";
1352  else auths = "???";
1353 
1354  //check is it is a submission or a query
1355  if (_webserver->hasArg("SUBMIT")) {
1356  //is there a correct list of query?
1357  if ( _webserver->hasArg("PASSWORD") && _webserver->hasArg("USER")) {
1358  //USER
1359  sUser = _webserver->arg("USER");
1360  if ( !((sUser == DEFAULT_ADMIN_LOGIN) || (sUser == DEFAULT_USER_LOGIN))) {
1361  msg_alert_error=true;
1362  smsg = "Error : Incorrect User";
1363  code = 401;
1364  }
1365  if (msg_alert_error == false) {
1366  //Password
1367  sPassword = _webserver->arg("PASSWORD");
1368  String sadminPassword;
1369 
1370  Preferences prefs;
1371  prefs.begin(NAMESPACE, true);
1372  String defV = DEFAULT_ADMIN_PWD;
1373  sadminPassword = prefs.getString(ADMIN_PWD_ENTRY, defV);
1374  String suserPassword;
1375  defV = DEFAULT_USER_PWD;
1376  suserPassword = prefs.getString(USER_PWD_ENTRY, defV);
1377  prefs.end();
1378 
1379  if(!(((sUser == DEFAULT_ADMIN_LOGIN) && (strcmp(sPassword.c_str(),sadminPassword.c_str()) == 0)) ||
1380  ((sUser == DEFAULT_USER_LOGIN) && (strcmp(sPassword.c_str(),suserPassword.c_str()) == 0)))) {
1381  msg_alert_error=true;
1382  smsg = "Error: Incorrect password";
1383  code = 401;
1384  }
1385  }
1386  } else {
1387  msg_alert_error=true;
1388  smsg = "Error: Missing data";
1389  code = 500;
1390  }
1391  //change password
1392  if (_webserver->hasArg("PASSWORD") && _webserver->hasArg("USER") && _webserver->hasArg("NEWPASSWORD") && (msg_alert_error==false) ) {
1393  String newpassword = _webserver->arg("NEWPASSWORD");
1394  if (isLocalPasswordValid(newpassword.c_str())) {
1395  String spos;
1396  if(sUser == DEFAULT_ADMIN_LOGIN) spos = ADMIN_PWD_ENTRY;
1397  else spos = USER_PWD_ENTRY;
1398 
1399  Preferences prefs;
1400  prefs.begin(NAMESPACE, false);
1401  if (prefs.putString(spos.c_str(), newpassword) != newpassword.length()) {
1402  msg_alert_error = true;
1403  smsg = "Error: Cannot apply changes";
1404  code = 500;
1405  }
1406  prefs.end();
1407  } else {
1408  msg_alert_error=true;
1409  smsg = "Error: Incorrect password";
1410  code = 500;
1411  }
1412  }
1413  if ((code == 200) || (code == 500)) {
1414  level_authenticate_type current_auth_level;
1415  if(sUser == DEFAULT_ADMIN_LOGIN) {
1416  current_auth_level = LEVEL_ADMIN;
1417  } else if(sUser == DEFAULT_USER_LOGIN){
1418  current_auth_level = LEVEL_USER;
1419  } else {
1420  current_auth_level = LEVEL_GUEST;
1421  }
1422  //create Session
1423  if ((current_auth_level != auth_level) || (auth_level== LEVEL_GUEST)) {
1424  auth_ip * current_auth = new auth_ip;
1425  current_auth->level = current_auth_level;
1426  current_auth->ip=_webserver->client().remoteIP();
1427  strcpy(current_auth->sessionID,create_session_ID());
1428  strcpy(current_auth->userID,sUser.c_str());
1429  current_auth->last_time=millis();
1430  if (AddAuthIP(current_auth)) {
1431  String tmps ="ESPSESSIONID=";
1432  tmps+=current_auth->sessionID;
1433  _webserver->sendHeader("Set-Cookie",tmps);
1434  _webserver->sendHeader("Cache-Control","no-cache");
1435  switch(current_auth->level) {
1436  case LEVEL_ADMIN:
1437  auths = "admin";
1438  break;
1439  case LEVEL_USER:
1440  auths = "user";
1441  break;
1442  default:
1443  auths = "guest";
1444  break;
1445  }
1446  } else {
1447  delete current_auth;
1448  msg_alert_error=true;
1449  code = 500;
1450  smsg = "Error: Too many connections";
1451  }
1452  }
1453  }
1454  if (code == 200) smsg = "Ok";
1455 
1456  //build JSON
1457  String buffer2send = "{\"status\":\"" + smsg + "\",\"authentication_lvl\":\"";
1458  buffer2send += auths;
1459  buffer2send += "\"}";
1460  _webserver->send(code, "application/json", buffer2send);
1461  } else {
1462  if (auth_level != LEVEL_GUEST) {
1463  String cookie = _webserver->header("Cookie");
1464  int pos = cookie.indexOf("ESPSESSIONID=");
1465  String sessionID;
1466  if (pos!= -1) {
1467  int pos2 = cookie.indexOf(";",pos);
1468  sessionID = cookie.substring(pos+strlen("ESPSESSIONID="),pos2);
1469  auth_ip * current_auth_info = GetAuth(_webserver->client().remoteIP(), sessionID.c_str());
1470  if (current_auth_info != NULL){
1471  sUser = current_auth_info->userID;
1472  }
1473  }
1474  }
1475  String buffer2send = "{\"status\":\"200\",\"authentication_lvl\":\"";
1476  buffer2send += auths;
1477  buffer2send += "\",\"user\":\"";
1478  buffer2send += sUser;
1479  buffer2send +="\"}";
1480  _webserver->send(code, "application/json", buffer2send);
1481  }
1482 #else
1483  _webserver->sendHeader("Cache-Control","no-cache");
1484  _webserver->send(200, "application/json", "{\"status\":\"Ok\",\"authentication_lvl\":\"admin\"}");
1485 #endif
1486 }
1487 //SPIFFS
1488 //SPIFFS files list and file commands
1489 void Web_Server::handleFileList ()
1490 {
1491  level_authenticate_type auth_level = is_authenticated();
1492  if (auth_level == LEVEL_GUEST) {
1493  _upload_status = UPLOAD_STATUS_NONE;
1494  _webserver->send (401, "text/plain", "Authentication failed!\n");
1495  return;
1496  }
1497  String path ;
1498  String status = "Ok";
1499  if ( (_upload_status == UPLOAD_STATUS_FAILED) || (_upload_status == UPLOAD_STATUS_CANCELLED) ) {
1500  status = "Upload failed";
1501  }
1502  //be sure root is correct according authentication
1503  if (auth_level == LEVEL_ADMIN) {
1504  path = "/";
1505  } else {
1506  path = "/user";
1507  }
1508  //get current path
1509  if (_webserver->hasArg ("path") ) {
1510  path += _webserver->arg ("path") ;
1511  }
1512  //to have a clean path
1513  path.trim();
1514  path.replace ("//", "/");
1515  if (path[path.length() - 1] != '/') {
1516  path += "/";
1517  }
1518  //check if query need some action
1519  if (_webserver->hasArg ("action") ) {
1520  //delete a file
1521  if (_webserver->arg ("action") == "delete" && _webserver->hasArg ("filename") ) {
1522  String filename;
1523  String shortname = _webserver->arg ("filename");
1524  shortname.replace ("/", "");
1525  filename = path + _webserver->arg ("filename");
1526  filename.replace ("//", "/");
1527  if (!SPIFFS.exists (filename) ) {
1528  status = shortname + " does not exists!";
1529  } else {
1530  if (SPIFFS.remove (filename) ) {
1531  status = shortname + " deleted";
1532  //what happen if no "/." and no other subfiles ?
1533  String ptmp = path;
1534  if ( (path != "/") && (path[path.length() - 1] = '/') ) {
1535  ptmp = path.substring (0, path.length() - 1);
1536  }
1537  File dir = SPIFFS.open (ptmp);
1538  File dircontent = dir.openNextFile();
1539  if (!dircontent) {
1540  //keep directory alive even empty
1541  File r = SPIFFS.open (path + "/.", FILE_WRITE);
1542  if (r) {
1543  r.close();
1544  }
1545  }
1546  } else {
1547  status = "Cannot deleted " ;
1548  status += shortname ;
1549  }
1550  }
1551  }
1552  //delete a directory
1553  if (_webserver->arg ("action") == "deletedir" && _webserver->hasArg ("filename") ) {
1554  String filename;
1555  String shortname = _webserver->arg ("filename");
1556  shortname.replace ("/", "");
1557  filename = path + _webserver->arg ("filename");
1558  filename += "/";
1559  filename.replace ("//", "/");
1560  if (filename != "/") {
1561  bool delete_error = false;
1562  File dir = SPIFFS.open (path + shortname);
1563  {
1564  File file2deleted = dir.openNextFile();
1565  while (file2deleted) {
1566  String fullpath = file2deleted.name();
1567  if (!SPIFFS.remove (fullpath) ) {
1568  delete_error = true;
1569  status = "Cannot deleted " ;
1570  status += fullpath;
1571  }
1572  file2deleted = dir.openNextFile();
1573  }
1574  }
1575  if (!delete_error) {
1576  status = shortname ;
1577  status += " deleted";
1578  }
1579  }
1580  }
1581  //create a directory
1582  if (_webserver->arg ("action") == "createdir" && _webserver->hasArg ("filename") ) {
1583  String filename;
1584  filename = path + _webserver->arg ("filename") + "/.";
1585  String shortname = _webserver->arg ("filename");
1586  shortname.replace ("/", "");
1587  filename.replace ("//", "/");
1588  if (SPIFFS.exists (filename) ) {
1589  status = shortname + " already exists!";
1590  } else {
1591  File r = SPIFFS.open (filename, FILE_WRITE);
1592  if (!r) {
1593  status = "Cannot create ";
1594  status += shortname ;
1595  } else {
1596  r.close();
1597  status = shortname + " created";
1598  }
1599  }
1600  }
1601  }
1602  String jsonfile = "{";
1603  String ptmp = path;
1604  if ( (path != "/") && (path[path.length() - 1] = '/') ) {
1605  ptmp = path.substring (0, path.length() - 1);
1606  }
1607  File dir = SPIFFS.open (ptmp);
1608  jsonfile += "\"files\":[";
1609  bool firstentry = true;
1610  String subdirlist = "";
1611  File fileparsed = dir.openNextFile();
1612  while (fileparsed) {
1613  String filename = fileparsed.name();
1614  String size = "";
1615  bool addtolist = true;
1616  //remove path from name
1617  filename = filename.substring (path.length(), filename.length() );
1618  //check if file or subfile
1619  if (filename.indexOf ("/") > -1) {
1620  //Do not rely on "/." to define directory as SPIFFS upload won't create it but directly files
1621  //and no need to overload SPIFFS if not necessary to create "/." if no need
1622  //it will reduce SPIFFS available space so limit it to creation
1623  filename = filename.substring (0, filename.indexOf ("/") );
1624  String tag = "*";
1625  tag += filename + "*";
1626  if (subdirlist.indexOf (tag) > -1 || filename.length() == 0) { //already in list
1627  addtolist = false; //no need to add
1628  } else {
1629  size = "-1"; //it is subfile so display only directory, size will be -1 to describe it is directory
1630  if (subdirlist.length() == 0) {
1631  subdirlist += "*";
1632  }
1633  subdirlist += filename + "*"; //add to list
1634  }
1635  } else {
1636  //do not add "." file
1637  if (! ( (filename == ".") || (filename == "") ) ) {
1638  size = formatBytes (fileparsed.size() );
1639  } else {
1640  addtolist = false;
1641  }
1642  }
1643  if (addtolist) {
1644  if (!firstentry) {
1645  jsonfile += ",";
1646  } else {
1647  firstentry = false;
1648  }
1649  jsonfile += "{";
1650  jsonfile += "\"name\":\"";
1651  jsonfile += filename;
1652  jsonfile += "\",\"size\":\"";
1653  jsonfile += size;
1654  jsonfile += "\"";
1655  jsonfile += "}";
1656  }
1657  fileparsed = dir.openNextFile();
1658  }
1659  jsonfile += "],";
1660  jsonfile += "\"path\":\"" + path + "\",";
1661  jsonfile += "\"status\":\"" + status + "\",";
1662  size_t totalBytes;
1663  size_t usedBytes;
1664  totalBytes = SPIFFS.totalBytes();
1665  usedBytes = SPIFFS.usedBytes();
1666  jsonfile += "\"total\":\"" + formatBytes (totalBytes) + "\",";
1667  jsonfile += "\"used\":\"" + formatBytes (usedBytes) + "\",";
1668  jsonfile.concat (F ("\"occupation\":\"") );
1669  jsonfile += String (100 * usedBytes / totalBytes);
1670  jsonfile += "\"";
1671  jsonfile += "}";
1672  path = "";
1673  _webserver->sendHeader("Cache-Control", "no-cache");
1674  _webserver->send(200, "application/json", jsonfile);
1675  _upload_status = UPLOAD_STATUS_NONE;
1676 }
1677 
1678 //SPIFFS files uploader handle
1679 void Web_Server::SPIFFSFileupload ()
1680 {
1681  //get authentication status
1682  level_authenticate_type auth_level= is_authenticated();
1683  //Guest cannot upload - only admin
1684  if (auth_level == LEVEL_GUEST) {
1685  _upload_status = UPLOAD_STATUS_CANCELLED;
1686  MYSERIAL0.println("Upload rejected");
1687 #if NUM_SERIAL > 1
1688  MYSERIAL1.println("Upload rejected");
1689 #endif
1690  _webserver->client().stop();
1691  return;
1692  }
1693  static String filename;
1694  static File fsUploadFile = (File)0;
1695 
1696  HTTPUpload& upload = _webserver->upload();
1697  //Upload start
1698  //**************
1699  if(upload.status == UPLOAD_FILE_START) {
1700  String upload_filename = upload.filename;
1701  if (upload_filename[0] != '/') filename = "/" + upload_filename;
1702  else filename = upload.filename;
1703  //according User or Admin the root is different as user is isolate to /user when admin has full access
1704  if(auth_level != LEVEL_ADMIN) {
1705  upload_filename = filename;
1706  filename = "/user" + upload_filename;
1707  }
1708 
1709  if (SPIFFS.exists (filename) ) {
1710  SPIFFS.remove (filename);
1711  }
1712  if (fsUploadFile ) {
1713  fsUploadFile.close();
1714  }
1715  //create file
1716  fsUploadFile = SPIFFS.open(filename, FILE_WRITE);
1717  //check If creation succeed
1718  if (fsUploadFile) {
1719  //if yes upload is started
1720  _upload_status= UPLOAD_STATUS_ONGOING;
1721  } else {
1722  //if no set cancel flag
1723  _upload_status=UPLOAD_STATUS_CANCELLED;
1724  MYSERIAL0.println("Upload error");
1725 #if NUM_SERIAL > 1
1726  MYSERIAL1.println("Upload error");
1727 #endif
1728  _webserver->client().stop();
1729  }
1730  //Upload write
1731  //**************
1732  } else if(upload.status == UPLOAD_FILE_WRITE) {
1733  //check if file is available and no error
1734  if(fsUploadFile && _upload_status == UPLOAD_STATUS_ONGOING) {
1735  //no error so write post date
1736  fsUploadFile.write(upload.buf, upload.currentSize);
1737  } else {
1738  //we have a problem set flag UPLOAD_STATUS_CANCELLED
1739  _upload_status=UPLOAD_STATUS_CANCELLED;
1740  fsUploadFile.close();
1741  if (SPIFFS.exists (filename) ) {
1742  SPIFFS.remove (filename);
1743  }
1744  _webserver->client().stop();
1745  MYSERIAL0.println("Upload error");
1746 #if NUM_SERIAL > 1
1747  MYSERIAL1.println("Upload error");
1748 #endif
1749  }
1750  //Upload end
1751  //**************
1752  } else if(upload.status == UPLOAD_FILE_END) {
1753  //check if file is still open
1754  if(fsUploadFile) {
1755  //close it
1756  fsUploadFile.close();
1757  //check size
1758  String sizeargname = upload.filename + "S";
1759  fsUploadFile = SPIFFS.open (filename, FILE_READ);
1760  uint32_t filesize = fsUploadFile.size();
1761  fsUploadFile.close();
1762  if (_webserver->hasArg (sizeargname.c_str()) ) {
1763  if (_webserver->arg (sizeargname.c_str()) != String(filesize)) {
1764  _upload_status = UPLOAD_STATUS_FAILED;
1765  SPIFFS.remove (filename);
1766  }
1767  }
1768  if (_upload_status == UPLOAD_STATUS_ONGOING) {
1769  _upload_status = UPLOAD_STATUS_SUCCESSFUL;
1770  } else {
1771  MYSERIAL0.println("Upload error");
1772 #if NUM_SERIAL > 1
1773  MYSERIAL1.println("Upload error");
1774 #endif
1775  }
1776  } else {
1777  //we have a problem set flag UPLOAD_STATUS_CANCELLED
1778  _upload_status=UPLOAD_STATUS_CANCELLED;
1779  _webserver->client().stop();
1780  if (SPIFFS.exists (filename) ) {
1781  SPIFFS.remove (filename);
1782  }
1783  MYSERIAL0.println("Upload error");
1784 #if NUM_SERIAL > 1
1785  MYSERIAL1.println("Upload error");
1786 #endif
1787  }
1788  //Upload cancelled
1789  //**************
1790  } else {
1791  if (_upload_status == UPLOAD_STATUS_ONGOING) {
1792  _upload_status = UPLOAD_STATUS_CANCELLED;
1793  }
1794  if(fsUploadFile)fsUploadFile.close();
1795  if (SPIFFS.exists (filename) ) {
1796  SPIFFS.remove (filename);
1797  }
1798  MYSERIAL0.println("Upload error");
1799 #if NUM_SERIAL > 1
1800  MYSERIAL1.println("Upload error");
1801 #endif
1802  }
1803  wifi_config.wait(0);
1804 }
1805 
1806 //Web Update handler
1807 void Web_Server::handleUpdate ()
1808 {
1809  level_authenticate_type auth_level = is_authenticated();
1810  if (auth_level != LEVEL_ADMIN) {
1811  _upload_status = UPLOAD_STATUS_NONE;
1812  _webserver->send (403, "text/plain", "Not allowed, log in first!\n");
1813  return;
1814  }
1815  String jsonfile = "{\"status\":\"" ;
1816  jsonfile += String(_upload_status);
1817  jsonfile += "\"}";
1818  //send status
1819  _webserver->sendHeader("Cache-Control", "no-cache");
1820  _webserver->send(200, "application/json", jsonfile);
1821  //if success restart
1822  if (_upload_status == UPLOAD_STATUS_SUCCESSFUL) {
1823  wifi_config.wait(1000);
1825  } else {
1826  _upload_status = UPLOAD_STATUS_NONE;
1827  }
1828 }
1829 
1830 //File upload for Web update
1831 void Web_Server::WebUpdateUpload ()
1832 {
1833  static size_t last_upload_update;
1834  static uint32_t maxSketchSpace ;
1835  //only admin can update FW
1836  if (is_authenticated() != LEVEL_ADMIN) {
1837  _upload_status = UPLOAD_STATUS_CANCELLED;
1838  _webserver->client().stop();
1839  MYSERIAL0.println("Upload rejected");
1840 #if NUM_SERIAL > 1
1841  MYSERIAL1.println("Upload rejected");
1842 #endif
1843  return;
1844  }
1845 
1846  //get current file ID
1847  HTTPUpload& upload = _webserver->upload();
1848  //Upload start
1849  //**************
1850  if(upload.status == UPLOAD_FILE_START) {
1851  MYSERIAL0.println("Update Firmware");
1852 #if NUM_SERIAL > 1
1853  MYSERIAL1.println("Update Firmware");
1854 #endif
1855  _upload_status= UPLOAD_STATUS_ONGOING;
1856 
1857  //Not sure can do OTA on 2Mb board
1858  maxSketchSpace = (ESP.getFlashChipSize() > 0x20000) ? 0x140000 : 0x140000 / 2;
1859  last_upload_update = 0;
1860  if(!Update.begin(maxSketchSpace)) { //start with max available size
1861  _upload_status=UPLOAD_STATUS_CANCELLED;
1862  MYSERIAL0.println("Update cancelled");
1863 #if NUM_SERIAL > 1
1864  MYSERIAL1.println("Update cancelled");
1865 #endif
1866  _webserver->client().stop();
1867  return;
1868  } else {
1869  MYSERIAL0.println("Update 0%");
1870 #if NUM_SERIAL > 1
1871  MYSERIAL1.println("Update 0%");
1872 #endif
1873  }
1874  //Upload write
1875  //**************
1876  } else if(upload.status == UPLOAD_FILE_WRITE) {
1877  //check if no error
1878  if (_upload_status == UPLOAD_STATUS_ONGOING) {
1879  //we do not know the total file size yet but we know the available space so let's use it
1880  if ( ((100 * upload.totalSize) / maxSketchSpace) !=last_upload_update) {
1881  last_upload_update = (100 * upload.totalSize) / maxSketchSpace;
1882  String s = "Update ";
1883  s+= String(last_upload_update);
1884  s+="%";
1885  MYSERIAL0.println(s.c_str());
1886 #if NUM_SERIAL > 1
1887  MYSERIAL1.println(s.c_str());
1888 #endif
1889  }
1890  if(Update.write(upload.buf, upload.currentSize) != upload.currentSize) {
1891  _upload_status=UPLOAD_STATUS_CANCELLED;
1892  }
1893  }
1894  //Upload end
1895  //**************
1896  } else if(upload.status == UPLOAD_FILE_END) {
1897  if(Update.end(true)) { //true to set the size to the current progress
1898  //Now Reboot
1899  MYSERIAL0.println("Update 100%");
1900 #if NUM_SERIAL > 1
1901  MYSERIAL1.println("Update 100%");
1902 #endif
1903  _upload_status=UPLOAD_STATUS_SUCCESSFUL;
1904  }
1905  } else if(upload.status == UPLOAD_FILE_ABORTED) {
1906  MYSERIAL0.println("Update failed");
1907 #if NUM_SERIAL > 1
1908  MYSERIAL1.println("Update failed");
1909 #endif
1910  Update.end();
1911  _upload_status=UPLOAD_STATUS_CANCELLED;
1912  }
1913  wifi_config.wait(0);
1914 }
1915 
1916 
1917 #if ENABLED(SDSUPPORT)
1918 
1919 //direct SD files list//////////////////////////////////////////////////
1920 void Web_Server::handle_direct_SDFileList()
1921 {
1922  //this is only for admin an user
1923  if (is_authenticated() == LEVEL_GUEST) {
1924  _upload_status=UPLOAD_STATUS_NONE;
1925  _webserver->send(401, "application/json", "{\"status\":\"Authentication failed!\"}");
1926  return;
1927  }
1928 
1929 
1930  String path="/";
1931  String sstatus="Ok";
1932  if ((_upload_status == UPLOAD_STATUS_FAILED) || (_upload_status == UPLOAD_STATUS_CANCELLED)) {
1933  sstatus = "Upload failed";
1934  _upload_status = UPLOAD_STATUS_NONE;
1935  }
1936  bool list_files = true;
1937  ESP_SD card;
1938  int8_t state = card.card_status();
1939  if (state != 1){
1940  _webserver->sendHeader("Cache-Control","no-cache");
1941  _webserver->send(200, "application/json", "{\"status\":\"No SD Card\"}");
1942  return;
1943  }
1944 
1945  //get current path
1946  if(_webserver->hasArg("path")) {
1947  path += _webserver->arg("path") ;
1948  }
1949  //to have a clean path
1950  path.trim();
1951  path.replace("//","/");
1952 
1953  //check if query need some action
1954  if(_webserver->hasArg("action")) {
1955  //delete a file
1956  if(_webserver->arg("action") == "delete" && _webserver->hasArg("filename")) {
1957  String filename;
1958  String shortname = _webserver->arg("filename");
1959  filename = path + shortname;
1960  shortname.replace("/","");
1961  filename.replace("//","/");
1962 
1963  if(!card.exists(filename.c_str())) {
1964  sstatus = shortname + " does not exist!";
1965  } else {
1966  if (card.remove(filename.c_str())) {
1967  sstatus = shortname + " deleted";
1968  } else {
1969  sstatus = "Cannot deleted ";
1970  sstatus+=shortname ;
1971  }
1972  }
1973  }
1974  //delete a directory
1975  if( _webserver->arg("action") == "deletedir" && _webserver->hasArg("filename")) {
1976  String filename;
1977  String shortname = _webserver->arg("filename");
1978  shortname.replace("/","");
1979  filename = path + "/" + shortname;
1980  filename.replace("//","/");
1981  if (filename != "/") {
1982  if(!card.dir_exists(filename.c_str())) {
1983  sstatus = shortname + " does not exist!";
1984  } else {
1985  if (!card.rmdir(filename.c_str())) {
1986  sstatus ="Error deleting: ";
1987  sstatus += shortname ;
1988  } else {
1989  sstatus = shortname ;
1990  sstatus+=" deleted";
1991  }
1992  }
1993  } else {
1994  sstatus ="Cannot delete root";
1995  }
1996  }
1997  //create a directory
1998  if( _webserver->arg("action")=="createdir" && _webserver->hasArg("filename")) {
1999  String filename;
2000  String shortname = _webserver->arg("filename");
2001  filename = path + shortname;
2002  shortname.replace("/","");
2003  filename.replace("//","/");
2004  if(card.exists(filename.c_str())) {
2005  sstatus = shortname + " already exists!";
2006  } else {
2007  if (!card.mkdir(filename.c_str())) {
2008  sstatus = "Cannot create ";
2009  sstatus += shortname ;
2010  } else {
2011  sstatus = shortname + " created";
2012  }
2013  }
2014  }
2015  }
2016 
2017  //check if no need build file list
2018  if( _webserver->hasArg("dontlist")) {
2019  if( _webserver->arg("dontlist") == "yes") {
2020  list_files = false;
2021  }
2022  }
2023  String jsonfile = "{" ;
2024  jsonfile+="\"files\":[";
2025  if (!card.openDir(path)){
2026  String s = "{\"status\":\" ";
2027  s += path;
2028  s+= " does not exist on SD Card\"}";
2029  _webserver->sendHeader("Cache-Control","no-cache");
2030  _webserver->send(200, "application/json", s.c_str());
2031  return;
2032  }
2033  if (list_files) {
2034  char name[13];
2035  uint32_t size;
2036  bool isFile;
2037  uint i = 0;
2038  while (card.readDir(name,&size ,&isFile)) {
2039  if (i>0) {
2040  jsonfile+=",";
2041  }
2042  jsonfile+="{\"name\":\"";
2043  jsonfile+=name;
2044  jsonfile+="\",\"shortname\":\"";
2045  jsonfile+=name;
2046  jsonfile+="\",\"size\":\"";
2047  if (isFile)jsonfile+=formatBytes(size);
2048  else jsonfile+="-1";
2049  jsonfile+="\",\"datetime\":\"";
2050  //TODO datatime
2051  jsonfile+="\"}";
2052  i++;
2053  wifi_config.wait(1);
2054  }
2055  jsonfile+="],\"path\":\"";
2056  jsonfile+=path + "\",";
2057  }
2058  static uint32_t volTotal = card.card_total_space();
2059  static uint32_t volUsed = card.card_used_space();;
2060  //TODO
2061  //Get right values
2062  uint32_t occupedspace = (volUsed/volTotal)*100;
2063  jsonfile+="\"total\":\"";
2064  if ( (occupedspace <= 1) && (volTotal!=volUsed)) {
2065  occupedspace=1;
2066  }
2067  jsonfile+= formatBytes(volTotal); ;
2068 
2069  jsonfile+="\",\"used\":\"";
2070  jsonfile+= formatBytes(volUsed); ;
2071  jsonfile+="\",\"occupation\":\"";
2072  jsonfile+=String(occupedspace);
2073  jsonfile+= "\",";
2074 
2075  jsonfile+= "\"mode\":\"direct\",";
2076  jsonfile+= "\"status\":\"";
2077  jsonfile+=sstatus + "\"";
2078  jsonfile+= "}";
2079 
2080  _webserver->sendHeader("Cache-Control","no-cache");
2081  _webserver->send (200, "application/json", jsonfile.c_str());
2082  _upload_status=UPLOAD_STATUS_NONE;
2083 }
2084 
2085 //SD File upload with direct access to SD///////////////////////////////
2086 void Web_Server::SDFile_direct_upload()
2087 {
2088  static ESP_SD sdfile;
2089  static String upload_filename;
2090  //this is only for admin and user
2091  if (is_authenticated() == LEVEL_GUEST) {
2092  _upload_status=UPLOAD_STATUS_NONE;
2093  _webserver->send(401, "application/json", "{\"status\":\"Authentication failed!\"}");
2094  return;
2095  }
2096  //retrieve current file id
2097  HTTPUpload& upload = _webserver->upload();
2098 
2099  //Upload start
2100  //**************
2101  if(upload.status == UPLOAD_FILE_START) {
2102  upload_filename = upload.filename;
2103  if (upload_filename[0] != '/') {
2104  upload_filename = "/" + upload.filename;
2105  }
2106  upload_filename= sdfile.makepath83(upload_filename);
2107  if ( sdfile.card_status() != 1) {
2108  _upload_status=UPLOAD_STATUS_CANCELLED;
2109  MYSERIAL0.println("Upload cancelled");
2110 #if NUM_SERIAL > 1
2111  MYSERIAL1.println("Upload cancelled");
2112 #endif
2113  _webserver->client().stop();
2114  return;
2115  }
2116  if (sdfile.exists (upload_filename.c_str()) ) {
2117  sdfile.remove (upload_filename.c_str());
2118  }
2119 
2120  if (sdfile.isopen())sdfile.close();
2121  if (!sdfile.open (upload_filename.c_str(),false)) {
2122  MYSERIAL0.println("Upload cancelled");
2123 #if NUM_SERIAL > 1
2124  MYSERIAL1.println("Upload cancelled");
2125 #endif
2126  _webserver->client().stop();
2127  _upload_status = UPLOAD_STATUS_FAILED;
2128  return ;
2129  } else {
2130  _upload_status = UPLOAD_STATUS_ONGOING;
2131  }
2132  //Upload write
2133  //**************
2134  } else if(upload.status == UPLOAD_FILE_WRITE) {
2135  //we need to check SD is inside
2136  if ( sdfile.card_status() != 1) {
2137  sdfile.close();
2138  MYSERIAL0.println("Upload failed");
2139  #if NUM_SERIAL > 1
2140  MYSERIAL1.println("Upload failed");
2141  #endif
2142  if (sdfile.exists (upload_filename.c_str()) ) {
2143  sdfile.remove (upload_filename.c_str());
2144  }
2145  _webserver->client().stop();
2146  return;
2147  }
2148  if (sdfile.isopen()) {
2149  if ( (_upload_status = UPLOAD_STATUS_ONGOING) && (upload.currentSize > 0)) {
2150  sdfile.write (upload.buf, upload.currentSize);
2151  }
2152  }
2153  //Upload end
2154  //**************
2155  } else if(upload.status == UPLOAD_FILE_END) {
2156  sdfile.close();
2157  uint32_t filesize = sdfile.size();
2158  String sizeargname = upload.filename + "S";
2159  if (_webserver->hasArg (sizeargname.c_str()) ) {
2160  if (_webserver->arg (sizeargname.c_str()) != String(filesize)) {
2161  MYSERIAL0.println("Upload failed");
2162  #if NUM_SERIAL > 1
2163  MYSERIAL1.println("Upload failed");
2164  #endif
2165  _upload_status = UPLOAD_STATUS_FAILED;
2166  }
2167  }
2168  if (_upload_status == UPLOAD_STATUS_ONGOING) {
2169  _upload_status = UPLOAD_STATUS_SUCCESSFUL;
2170  }
2171  } else {//Upload cancelled
2172  _upload_status=UPLOAD_STATUS_FAILED;
2173 
2174  MYSERIAL0.println("Upload failed");
2175 #if NUM_SERIAL > 1
2176  MYSERIAL1.println("Upload failed");
2177 #endif
2178  _webserver->client().stop();
2179  sdfile.close();
2180  if (sdfile.exists (upload_filename.c_str()) ) {
2181  sdfile.remove (upload_filename.c_str());
2182  }
2183  }
2184  wifi_config.wait(0);
2185 }
2186 #endif
2187 
2188 void Web_Server::handle(){
2189 static uint32_t timeout = millis();
2190 #ifdef ENABLE_CAPTIVE_PORTAL
2191  if(WiFi.getMode() == WIFI_AP){
2192  dnsServer.processNextRequest();
2193  }
2194 #endif
2195  if (_webserver)_webserver->handleClient();
2196  if (_socket_server && _setupdone) {
2198  _socket_server->loop();
2199  }
2200  if ((millis() - timeout) > 10000) {
2201  if (_socket_server){
2202  String s = "PING:";
2203  s+=String(_id_connection);
2204  _socket_server->broadcastTXT(s);
2205  timeout=millis();
2206  }
2207  }
2208 }
2209 
2210 
2211 void Web_Server::handle_Websocket_Event(uint8_t num, uint8_t type, uint8_t * payload, size_t length) {
2212 
2213  switch(type) {
2214  case WStype_DISCONNECTED:
2215  //USE_SERIAL.printf("[%u] Disconnected!\n", num);
2216  break;
2217  case WStype_CONNECTED:
2218  {
2219  IPAddress ip = _socket_server->remoteIP(num);
2220  //USE_SERIAL.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload);
2221  String s = "CURRENT_ID:" + String(num);
2222  // send message to client
2223  _id_connection = num;
2224  _socket_server->sendTXT(_id_connection, s);
2225  s = "ACTIVE_ID:" + String(_id_connection);
2226  _socket_server->broadcastTXT(s);
2227  }
2228  break;
2229  case WStype_TEXT:
2230  //USE_SERIAL.printf("[%u] get Text: %s\n", num, payload);
2231 
2232  // send message to client
2233  // webSocket.sendTXT(num, "message here");
2234 
2235  // send data to all connected clients
2236  // webSocket.broadcastTXT("message here");
2237  break;
2238  case WStype_BIN:
2239  //USE_SERIAL.printf("[%u] get binary length: %u\n", num, length);
2240  //hexdump(payload, length);
2241 
2242  // send message to client
2243  // webSocket.sendBIN(num, payload, length);
2244  break;
2245  default:
2246  break;
2247  }
2248 
2249 }
2250 
2251 //just simple helper to convert mac address to string
2252 char * Web_Server::mac2str (uint8_t mac [8])
2253 {
2254  static char macstr [18];
2255  if (0 > sprintf (macstr, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]) ) {
2256  strcpy (macstr, "00:00:00:00:00:00");
2257  }
2258  return macstr;
2259 }
2260 
2261 String Web_Server::get_Splited_Value(String data, char separator, int index)
2262 {
2263  int found = 0;
2264  int strIndex[] = {0, -1};
2265  int maxIndex = data.length()-1;
2266 
2267  for(int i=0; i<=maxIndex && found<=index; i++){
2268  if(data.charAt(i)==separator || i==maxIndex){
2269  found++;
2270  strIndex[0] = strIndex[1]+1;
2271  strIndex[1] = (i == maxIndex) ? i+1 : i;
2272  }
2273  }
2274 
2275  return found>index ? data.substring(strIndex[0], strIndex[1]) : "";
2276 }
2277 
2278 
2279 //helper to format size to readable string
2280 String Web_Server::formatBytes (uint32_t bytes)
2281 {
2282  if (bytes < 1024) {
2283  return String (bytes) + " B";
2284  } else if (bytes < (1024 * 1024) ) {
2285  return String (bytes / 1024.0) + " KB";
2286  } else if (bytes < (1024 * 1024 * 1024) ) {
2287  return String (bytes / 1024.0 / 1024.0) + " MB";
2288  } else {
2289  return String (bytes / 1024.0 / 1024.0 / 1024.0) + " GB";
2290  }
2291 }
2292 
2293 //helper to extract content type from file extension
2294 //Check what is the content tye according extension file
2295 String Web_Server::getContentType (String filename)
2296 {
2297  String file_name = filename;
2298  file_name.toLowerCase();
2299  if (filename.endsWith (".htm") ) {
2300  return "text/html";
2301  } else if (file_name.endsWith (".html") ) {
2302  return "text/html";
2303  } else if (file_name.endsWith (".css") ) {
2304  return "text/css";
2305  } else if (file_name.endsWith (".js") ) {
2306  return "application/javascript";
2307  } else if (file_name.endsWith (".png") ) {
2308  return "image/png";
2309  } else if (file_name.endsWith (".gif") ) {
2310  return "image/gif";
2311  } else if (file_name.endsWith (".jpeg") ) {
2312  return "image/jpeg";
2313  } else if (file_name.endsWith (".jpg") ) {
2314  return "image/jpeg";
2315  } else if (file_name.endsWith (".ico") ) {
2316  return "image/x-icon";
2317  } else if (file_name.endsWith (".xml") ) {
2318  return "text/xml";
2319  } else if (file_name.endsWith (".pdf") ) {
2320  return "application/x-pdf";
2321  } else if (file_name.endsWith (".zip") ) {
2322  return "application/x-zip";
2323  } else if (file_name.endsWith (".gz") ) {
2324  return "application/x-gzip";
2325  } else if (file_name.endsWith (".txt") ) {
2326  return "text/plain";
2327  }
2328  return "application/octet-stream";
2329 }
2330 
2331 //check authentification
2332 level_authenticate_type Web_Server::is_authenticated()
2333 {
2334 #ifdef ENABLE_AUTHENTICATION
2335  if (_webserver->hasHeader ("Cookie") ) {
2336  String cookie = _webserver->header ("Cookie");
2337  int pos = cookie.indexOf ("ESPSESSIONID=");
2338  if (pos != -1) {
2339  int pos2 = cookie.indexOf (";", pos);
2340  String sessionID = cookie.substring (pos + strlen ("ESPSESSIONID="), pos2);
2341  IPAddress ip = _webserver->client().remoteIP();
2342  //check if cookie can be reset and clean table in same time
2343  return ResetAuthIP (ip, sessionID.c_str() );
2344  }
2345  }
2346  return LEVEL_GUEST;
2347 #else
2348  return LEVEL_ADMIN;
2349 #endif
2350 }
2351 
2352 #ifdef ENABLE_AUTHENTICATION
2353 
2354 bool Web_Server::isLocalPasswordValid (const char * password)
2355 {
2356  char c;
2357  //limited size
2358  if ( (strlen (password) > MAX_LOCAL_PASSWORD_LENGTH) || (strlen (password) < MIN_LOCAL_PASSWORD_LENGTH) ) {
2359  return false;
2360  }
2361  //no space allowed
2362  for (int i = 0; i < strlen (password); i++) {
2363  c = password[i];
2364  if (c == ' ') {
2365  return false;
2366  }
2367  }
2368  return true;
2369 }
2370 
2371 //add the information in the linked list if possible
2372 bool Web_Server::AddAuthIP (auth_ip * item)
2373 {
2374  if (_nb_ip > MAX_AUTH_IP) {
2375  return false;
2376  }
2377  item->_next = _head;
2378  _head = item;
2379  _nb_ip++;
2380  return true;
2381 }
2382 
2383 //Session ID based on IP and time using 16 char
2384 char * Web_Server::create_session_ID()
2385 {
2386  static char sessionID[17];
2387 //reset SESSIONID
2388  for (int i = 0; i < 17; i++) {
2389  sessionID[i] = '\0';
2390  }
2391 //get time
2392  uint32_t now = millis();
2393 //get remote IP
2394  IPAddress remoteIP = _webserver->client().remoteIP();
2395 //generate SESSIONID
2396  if (0 > sprintf (sessionID, "%02X%02X%02X%02X%02X%02X%02X%02X", remoteIP[0], remoteIP[1], remoteIP[2], remoteIP[3], (uint8_t) ( (now >> 0) & 0xff), (uint8_t) ( (now >> 8) & 0xff), (uint8_t) ( (now >> 16) & 0xff), (uint8_t) ( (now >> 24) & 0xff) ) ) {
2397  strcpy (sessionID, "NONE");
2398  }
2399  return sessionID;
2400 }
2401 
2402 
2403 bool Web_Server::ClearAuthIP (IPAddress ip, const char * sessionID)
2404 {
2405  auth_ip * current = _head;
2406  auth_ip * previous = NULL;
2407  bool done = false;
2408  while (current) {
2409  if ( (ip == current->ip) && (strcmp (sessionID, current->sessionID) == 0) ) {
2410  //remove
2411  done = true;
2412  if (current == _head) {
2413  _head = current->_next;
2414  _nb_ip--;
2415  delete current;
2416  current = _head;
2417  } else {
2418  previous->_next = current->_next;
2419  _nb_ip--;
2420  delete current;
2421  current = previous->_next;
2422  }
2423  } else {
2424  previous = current;
2425  current = current->_next;
2426  }
2427  }
2428  return done;
2429 }
2430 
2431 //Get info
2432 auth_ip * Web_Server::GetAuth (IPAddress ip, const char * sessionID)
2433 {
2434  auth_ip * current = _head;
2435  //auth_ip * previous = NULL;
2436  //get time
2437  //uint32_t now = millis();
2438  while (current) {
2439  if (ip == current->ip) {
2440  if (strcmp (sessionID, current->sessionID) == 0) {
2441  //found
2442  return current;
2443  }
2444  }
2445  //previous = current;
2446  current = current->_next;
2447  }
2448  return NULL;
2449 }
2450 
2451 //Review all IP to reset timers
2452 level_authenticate_type Web_Server::ResetAuthIP (IPAddress ip, const char * sessionID)
2453 {
2454  auth_ip * current = _head;
2455  auth_ip * previous = NULL;
2456  //get time
2457  //uint32_t now = millis();
2458  while (current) {
2459  if ( (millis() - current->last_time) > 360000) {
2460  //remove
2461  if (current == _head) {
2462  _head = current->_next;
2463  _nb_ip--;
2464  delete current;
2465  current = _head;
2466  } else {
2467  previous->_next = current->_next;
2468  _nb_ip--;
2469  delete current;
2470  current = previous->_next;
2471  }
2472  } else {
2473  if (ip == current->ip) {
2474  if (strcmp (sessionID, current->sessionID) == 0) {
2475  //reset time
2476  current->last_time = millis();
2477  return (level_authenticate_type) current->level;
2478  }
2479  }
2480  previous = current;
2481  current = current->_next;
2482  }
2483  }
2484  return LEVEL_GUEST;
2485 }
2486 #endif
2487 
2488 String Web_Server::get_param (String & cmd_params, const char * id, bool withspace)
2489 {
2490  static String parameter;
2491  String sid = id;
2492  int start;
2493  int end = -1;
2494  parameter = "";
2495  //if no id it means it is first part of cmd
2496  if (strlen (id) == 0) {
2497  start = 0;
2498  }
2499  //else find id position
2500  else {
2501  start = cmd_params.indexOf (id);
2502  }
2503  //if no id found and not first part leave
2504  if (start == -1 ) {
2505  return parameter;
2506  }
2507  //password and SSID can have space so handle it
2508  //if no space expected use space as delimiter
2509  if (!withspace) {
2510  end = cmd_params.indexOf (" ", start);
2511  }
2512  //if no end found - take all
2513  if (end == -1) {
2514  end = cmd_params.length();
2515  }
2516  //extract parameter
2517  parameter = cmd_params.substring (start + strlen (id), end);
2518  //be sure no extra space
2519  parameter.trim();
2520  return parameter;
2521 }
2522 
2523 ESPResponseStream::ESPResponseStream(WebServer * webserver){
2524  _header_sent=false;
2525  _webserver = webserver;
2526 }
2527 
2528 void ESPResponseStream::println(const char *data){
2529  print(data);
2530  print("\n");
2531 }
2532 
2533 void ESPResponseStream::print(const char *data){
2534  if (!_header_sent) {
2535  _webserver->setContentLength(CONTENT_LENGTH_UNKNOWN);
2536  _webserver->sendHeader("Content-Type","text/html");
2537  _webserver->sendHeader("Cache-Control","no-cache");
2538  _webserver->send(200);
2539  _header_sent = true;
2540  }
2541  _buffer+=data;
2542  if (_buffer.length() > 1200) {
2543  //send data
2544  _webserver->sendContent(_buffer);
2545  //reset buffer
2546  _buffer = "";
2547  }
2548 
2549 }
2550 
2552  if(_header_sent) {
2553  //send data
2554  if(_buffer.length() > 0)_webserver->sendContent(_buffer);
2555  //close connection
2556  _webserver->sendContent("");
2557  }
2558  _header_sent = false;
2559  _buffer = "";
2560 
2561 }
2562 
2563 #endif // Enable HTTP
2564 
2565 #endif // ENABLE_WIFI
2566 
2567 #endif // ARDUINO_ARCH_ESP32
Web_Server::Web_Server
Web_Server()
STA_SSID_ENTRY
#define STA_SSID_ENTRY
Definition: wificonfig.h:38
MAX_HOSTNAME_LENGTH
#define MAX_HOSTNAME_LENGTH
Definition: wificonfig.h:90
TELNET_PORT_ENTRY
#define TELNET_PORT_ENTRY
Definition: wificonfig.h:51
wifi_config
WiFiConfig wifi_config
sd_ESP32.h
level_authenticate_type
level_authenticate_type
Definition: web_server.h:31
LEVEL_GUEST
@ LEVEL_GUEST
Definition: web_server.h:32
AP_IP_ENTRY
#define AP_IP_ENTRY
Definition: wificonfig.h:46
Serial_2_Socket::attachWS
bool attachWS(void *web_socket)
Web_Server::handle
static void handle()
web_server.h
MAX_HTTP_PORT
#define MAX_HTTP_PORT
Definition: wificonfig.h:92
ESPResponseStream
Definition: web_server.h:52
ESP_SD::card_used_space
uint32_t card_used_space()
Web_Server::begin
bool begin()
MAX_SSID_LENGTH
#define MAX_SSID_LENGTH
Definition: wificonfig.h:84
ESP_SD::makepath83
String makepath83(String longpath)
ESP_SD::read
uint16_t read(uint8_t *buf, uint16_t nbyte)
Web_Server::~Web_Server
~Web_Server()
HIDDEN_PASSWORD
#define HIDDEN_PASSWORD
Definition: wificonfig.h:81
MIN_HTTP_PORT
#define MIN_HTTP_PORT
Definition: wificonfig.h:93
Serial_2_Socket::handle_flush
void handle_flush()
AP_SSID_ENTRY
#define AP_SSID_ENTRY
Definition: wificonfig.h:44
Web_Server::end
void end()
DHCP_MODE
#define DHCP_MODE
Definition: wificonfig.h:59
STA_GW_ENTRY
#define STA_GW_ENTRY
Definition: wificonfig.h:41
LEVEL_ADMIN
@ LEVEL_ADMIN
Definition: web_server.h:34
ESP_SD
Definition: sd_ESP32.h:25
nofile.h
STA_IP_MODE_ENTRY
#define STA_IP_MODE_ENTRY
Definition: wificonfig.h:52
MAX_CHANNEL
#define MAX_CHANNEL
Definition: wificonfig.h:97
ESP_SD::mkdir
bool mkdir(const char *path)
MIN_HOSTNAME_LENGTH
#define MIN_HOSTNAME_LENGTH
Definition: wificonfig.h:91
LEVEL_USER
@ LEVEL_USER
Definition: web_server.h:33
wifiservices.h
Serial_2_Socket::push
bool push(const char *data)
ESP_SD::exists
bool exists(const char *path)
ESP_SD::card_status
int8_t card_status()
ESP_SD::isopen
bool isopen()
ESP_SD::remove
bool remove(const char *path)
ESP_SD::write
int16_t write(const uint8_t *data, uint16_t len)
WiFiConfig::getSignal
static int32_t getSignal(int32_t RSSI)
DEFAULT_HTTP_STATE
#define DEFAULT_HTTP_STATE
Definition: wificonfig.h:80
MIN_CHANNEL
#define MIN_CHANNEL
Definition: wificonfig.h:96
STA_MK_ENTRY
#define STA_MK_ENTRY
Definition: wificonfig.h:42
ESPResponseStream::print
void print(const char *data)
MYSERIAL0
#define MYSERIAL0
Definition: esplibconfig.h:29
esplibconfig.h
ESP_SD::close
void close()
DEFAULT_AP_CHANNEL
#define DEFAULT_AP_CHANNEL
Definition: wificonfig.h:78
Web_Server
Definition: web_server.h:64
MIN_SSID_LENGTH
#define MIN_SSID_LENGTH
Definition: wificonfig.h:85
ESP_SD::dir_exists
bool dir_exists(const char *path)
ESPResponseStream::flush
void flush()
ESP_WIFI_MODE
#define ESP_WIFI_MODE
Definition: wificonfig.h:43
MIN_PASSWORD_LENGTH
#define MIN_PASSWORD_LENGTH
Definition: wificonfig.h:89
ESP_SD::openDir
bool openDir(String path)
serial2socket.h
ESPResponseStream::ESPResponseStream
ESPResponseStream(WebServer *webserver)
Web_Server::get_client_ID
static long get_client_ID()
PAGE_NOFILES_SIZE
#define PAGE_NOFILES_SIZE
Definition: nofile.h:23
ESP_WIFI_OFF
#define ESP_WIFI_OFF
Definition: wificonfig.h:55
TELNET_ENABLE_ENTRY
#define TELNET_ENABLE_ENTRY
Definition: wificonfig.h:50
STA_PWD_ENTRY
#define STA_PWD_ENTRY
Definition: wificonfig.h:39
wificonfig.h
ESP_SD::size
uint32_t size()
NAMESPACE
#define NAMESPACE
Definition: wificonfig.h:36
ESP_SD::rmdir
bool rmdir(const char *path)
DEFAULT_STA_SSID
#define DEFAULT_STA_SSID
Definition: wificonfig.h:68
DEFAULT_AP_IP
#define DEFAULT_AP_IP
Definition: wificonfig.h:76
WiFiConfig::IP_string_from_int
static String IP_string_from_int(uint32_t ip_int)
Serial2Socket
Serial_2_Socket Serial2Socket
WiFiConfig::restart_ESP
static void restart_ESP()
STA_IP_ENTRY
#define STA_IP_ENTRY
Definition: wificonfig.h:40
ESP_SD::card_total_space
uint32_t card_total_space()
HTTP_PORT_ENTRY
#define HTTP_PORT_ENTRY
Definition: wificonfig.h:49
DEFAULT_WEBSERVER_PORT
#define DEFAULT_WEBSERVER_PORT
Definition: wificonfig.h:79
WiFiConfig::wait
static void wait(uint32_t milliseconds)
DEFAULT_HOSTNAME
#define DEFAULT_HOSTNAME
Definition: wificonfig.h:67
ESP_SD::readDir
bool readDir(char name[13], uint32_t *size, bool *isFile)
DEFAULT_AP_SSID
#define DEFAULT_AP_SSID
Definition: wificonfig.h:74
ESP_SD::open
bool open(const char *path, bool readonly=true)
MAX_PASSWORD_LENGTH
#define MAX_PASSWORD_LENGTH
Definition: wificonfig.h:86
AP_PWD_ENTRY
#define AP_PWD_ENTRY
Definition: wificonfig.h:45
HTTP_ENABLE_ENTRY
#define HTTP_ENABLE_ENTRY
Definition: wificonfig.h:48
HOSTNAME_ENTRY
#define HOSTNAME_ENTRY
Definition: wificonfig.h:37
ESPResponseStream::println
void println(const char *data)
AP_CHANNEL_ENTRY
#define AP_CHANNEL_ENTRY
Definition: wificonfig.h:47
WiFiConfig::IP_int_from_string
static uint32_t IP_int_from_string(String &s)
web_server
Web_Server web_server