/* Cgi/template routines for configuring non-wifi settings */ #include #include "cgi_persist.h" #include "persist.h" #include "helpers.h" #include "cgi_logging.h" #include "version.h" #include "screen.h" #include "config_xmacros.h" #include "ini_parser.h" #define SET_REDIR_SUC "/cfg/system" static bool ICACHE_FLASH_ATTR verify_admin_pw(const char *pw) { return streq(pw, persist.admin.pw); } httpd_cgi_state ICACHE_FLASH_ATTR cgiPersistWriteDefaults(HttpdConnData *connData) { char buff[PASSWORD_LEN]; if (connData->conn == NULL) { //Connection aborted. Clean up. return HTTPD_CGI_DONE; } // width and height must always go together so we can do max size validation if (GET_ARG("pw")) { cgi_dbg("Entered password for admin: %s", buff); if (verify_admin_pw(buff)) { cgi_dbg("pw is OK"); persist_set_as_default(); httpdRedirect(connData, SET_REDIR_SUC "?msg=Default%20settings%20updated."); return HTTPD_CGI_DONE; } // if pw failed, show the same error as if it's wrong } httpdRedirect(connData, SET_REDIR_SUC "?err=Password"); // this will show in the "validation errors" box return HTTPD_CGI_DONE; } httpd_cgi_state ICACHE_FLASH_ATTR cgiPersistRestoreDefaults(HttpdConnData *connData) { if (connData->conn == NULL) { //Connection aborted. Clean up. return HTTPD_CGI_DONE; } persist_restore_default(); httpdRedirect(connData, SET_REDIR_SUC "?msg=All%20settings%20restored%20to%20saved%20defaults."); return HTTPD_CGI_DONE; } httpd_cgi_state ICACHE_FLASH_ATTR cgiPersistRestoreHard(HttpdConnData *connData) { if (connData->conn == NULL) { //Connection aborted. Clean up. return HTTPD_CGI_DONE; } // this only changes live settings (and persists it) // Defaults are not changed. persist_load_hard_default(); httpdRedirect(connData, SET_REDIR_SUC "?msg=All%20settings%20restored%20to%20factory%20defaults."); return HTTPD_CGI_DONE; } #define httpdSend_orDie(conn, data, len) do { if (!httpdSend((conn), (data), (len))) return false; } while (0) /* encode for double-quoted string */ int ICACHE_FLASH_ATTR httpdSend_dblquot(HttpdConnData *conn, const char *data, int len) { int start = 0, end = 0; char c; if (conn->conn==NULL) return 0; if (len < 0) len = (int) strlen(data); if (len==0) return 0; for (end = 0; end < len; end++) { c = data[end]; if (c == 0) { // we found EOS break; } if (c == '"' || c == '\'' || c == '\\' || c == '\n' || c == '\r' || c == '\x1b') { if (start < end) httpdSend_orDie(conn, data + start, end - start); start = end + 1; } if (c == '"') httpdSend_orDie(conn, "\\\"", 2); else if (c == '\'') httpdSend_orDie(conn, "\\'", 2); else if (c == '\\') httpdSend_orDie(conn, "\\\\", 2); else if (c == '\n') httpdSend_orDie(conn, "\\n", 2); else if (c == '\r') httpdSend_orDie(conn, "\\r", 2); else if (c == '\x1b') httpdSend_orDie(conn, "\\e", 2); } if (start < end) httpdSend_orDie(conn, data + start, end - start); return 1; } /** * Export settings to INI * * @param connData * @return status */ httpd_cgi_state ICACHE_FLASH_ATTR cgiPersistExport(HttpdConnData *connData) { char buff[256]; u8 mac[6]; int step = (int) connData->cgiData; if (connData->conn == NULL) { //Connection aborted. Clean up. return HTTPD_CGI_DONE; } if (step == 0) { wifi_get_macaddr(SOFTAP_IF, mac); sprintf(buff, "attachment; filename=ESPTerm_%02X%02X%02X_%s.ini", mac[3], mac[4], mac[5], FW_VERSION); httpdStartResponse(connData, 200); httpdHeader(connData, "Content-Disposition", buff); httpdHeader(connData, "Content-Type", "text/plain"); httpdEndHeaders(connData); sprintf(buff, "# == ESPTerm config export ==\r\n" "# Device: %02X%02X%02X - %s\r\n" "# Version: %s\r\n", mac[3], mac[4], mac[5], termconf->title, FW_VERSION); httpdSend(connData, buff, -1); } // do not export SSID if unchanged - embeds unique ID that should // not be overwritten in target. char defSSID[20]; sprintf(defSSID, "TERM-%02X%02X%02X", mac[3], mac[4], mac[5]); bool quoted; #define X(type, name, suffix, deref, xget, xset, xsarg, xnotify, allow) \ do { if (allow) { \ xget(buff, deref XSTRUCT->name); \ if (streq(#name, "ap_ssid") && streq(buff, defSSID)) break; \ \ quoted = false; \ quoted |= streq(#type, "char"); \ quoted |= streq(#type, "uchar"); \ if (strstarts(#name, "bm")) quoted=false; \ \ httpdSend(connData, "\r\n"#name " = ", -1); \ if (quoted) { \ httpdSend(connData, "\"", 1); \ httpdSend_dblquot(connData, buff, -1); \ httpdSend(connData, "\"", 1); \ } else { \ httpdSend(connData, buff, -1); \ } \ } } while(0); #define admin 1 #define tpl 1 if (step == 1) { httpdSend(connData, "\r\n[system]", -1); #define XSTRUCT sysconf XTABLE_SYSCONF #undef XSTRUCT httpdSend(connData, "\r\n", -1); } if (step == 2) { httpdSend(connData, "\r\n[wifi]", -1); #define XSTRUCT wificonf XTABLE_WIFICONF #undef XSTRUCT httpdSend(connData, "\r\n", -1); } if (step == 3) { httpdSend(connData, "\r\n[terminal]", -1); #define XSTRUCT termconf XTABLE_TERMCONF #undef XSTRUCT httpdSend(connData, "\r\n", -1); return HTTPD_CGI_DONE; } #undef X connData->cgiData = (void *) (step + 1); return HTTPD_CGI_MORE; } void iniCb(const char *section, const char *key, const char *value, void *userData) { dbg(">>> SET: [%s] %s = %s", section, key, value); } httpd_cgi_state ICACHE_FLASH_ATTR postRecvHdl(HttpdConnData *connData, char *data, int len) { ini_parse(data, (size_t) len); ini_parse_end(); return HTTPD_CGI_DONE; } /** * Import settings from INI * * @param connData * @return status */ httpd_cgi_state ICACHE_FLASH_ATTR cgiPersistImport(HttpdConnData *connData) { if (connData->conn == NULL) { //Connection aborted. Clean up. return HTTPD_CGI_DONE; } httpdStartResponse(connData, 200); httpdHeader(connData, "Content-Type", "text/plain"); httpdEndHeaders(connData); char *start = strstr(connData->post->buff, "\r\n\r\n"); if (start == NULL) { error("Malformed attachment POST!"); goto end; } ini_parse_begin(iniCb, NULL); ini_parse(start, (size_t) connData->post->buffLen - (start - connData->post->buff)); connData->recvHdl = postRecvHdl; end: // TODO redirect return HTTPD_CGI_DONE; }