@@ -43,7 +43,7 @@ using namespace httpsserver;
4343
4444static const char *const HTML_ENTITY_FAILED_CROSS = " ❌" ;
4545static const char *const HTML_ENTITY_OK_MARK = " ✅" ;
46-
46+ static const char * const HTML_ENTITY_WASTEBASKED = " 🗑 " ;
4747static const char *const HTTP_GET = " GET" ;
4848static const char *const HTTP_POST = " POST" ;
4949
@@ -70,6 +70,7 @@ static const char* const header =
7070// STYLE
7171 " <style>"
7272 " #file-input,input, button {width:100%;height:44px;border-radius:4px;margin:10px auto;font-size:15px;}"
73+ " .small {height:12px;width:12px;margin:2px}"
7374 " input, button, a.back {background:#f1f1f1;border:0;padding:0;text-align:center;}"
7475 " body {background:#3498db;font-family:sans-serif;font-size:12px;color:#777}"
7576 " #file-input {padding:0 5px;border:1px solid #ddd;line-height:44px;text-align:left;display:block;cursor:pointer}"
@@ -437,6 +438,7 @@ static void handleMakeCurrentLocationPrivate(HTTPRequest * req, HTTPResponse * r
437438static void handlePrivacy (HTTPRequest *req, HTTPResponse *res);
438439static void handlePrivacyDeleteAction (HTTPRequest *req, HTTPResponse *res);
439440static void handleSd (HTTPRequest *req, HTTPResponse *res);
441+ static void handleDeleteFiles (HTTPRequest *req, HTTPResponse *res);
440442static void handleDelete (HTTPRequest *req, HTTPResponse *res);
441443static void handleDeleteAction (HTTPRequest *req, HTTPResponse *res);
442444
@@ -481,6 +483,7 @@ void beginPages() {
481483 server->registerNode (new ResourceNode (" /settings/privacy" , HTTP_GET, handlePrivacy));
482484 server->registerNode (new ResourceNode (" /privacy_delete" , HTTP_GET, handlePrivacyDeleteAction));
483485 server->registerNode (new ResourceNode (" /sd" , HTTP_GET, handleSd));
486+ server->registerNode (new ResourceNode (" /deleteFiles" , HTTP_POST, handleDeleteFiles));
484487
485488 server->addMiddleware (&accessFilter);
486489 server->setDefaultHeader (" Server" , std::string (" OBS/" ) + OBSVersion);
@@ -491,8 +494,8 @@ void beginPages() {
491494
492495
493496void createHttpServer () {
494- server = new HTTPSServer (&obsCert);
495- insecureServer = new HTTPServer ();
497+ server = new HTTPSServer (&obsCert, 443 , 2 );
498+ insecureServer = new HTTPServer (80 , 1 );
496499
497500 log_i (" About to create pages." );
498501 beginPages ();
@@ -1442,6 +1445,57 @@ static void handleFlashFileUpdateAction(HTTPRequest *req, HTTPResponse *res) {
14421445 sensorManager->attachInterrupts ();
14431446}
14441447
1448+ static void handleDeleteFiles (HTTPRequest *req, HTTPResponse * res) {
1449+ const auto params = extractParameters (req);
1450+ String path = getParameter (params, " path" );
1451+ if (path != " trash" ) {
1452+ SD.mkdir (" /trash" );
1453+ }
1454+
1455+ String html = replaceDefault (header, " Delete Files" );
1456+ html += " <h3>Deleting files</h3>" ;
1457+ html += " <div>In: " + ObsUtils::encodeForXmlText (path);
1458+ html += " </div><br /><div>" ;
1459+ sendHtml (res, html);
1460+ html.clear ();
1461+
1462+ for (auto param : params) {
1463+ if (param.first == " delete" ) {
1464+ String file = param.second ;
1465+
1466+ String fullName = path + (path.length () > 1 ? " /" : " " ) + file;
1467+
1468+ html += ObsUtils::encodeForXmlText (file) + " ➜ " ;
1469+ if (path != " trash" ) {
1470+ if (SD.rename (fullName, " /trash/" + file)) {
1471+ log_i (" Moved '%s'." , fullName.c_str ());
1472+ html += HTML_ENTITY_WASTEBASKED;
1473+ } else {
1474+ log_w (" Failed to move '%s'." , fullName.c_str ());
1475+ html += HTML_ENTITY_FAILED_CROSS;
1476+ }
1477+ } else {
1478+ if (SD.remove (fullName)) {
1479+ log_i (" Deleted '%s'." , fullName.c_str ());
1480+ html += HTML_ENTITY_WASTEBASKED;
1481+ } else {
1482+ log_w (" Failed to delete '%s'." , fullName.c_str ());
1483+ html += HTML_ENTITY_FAILED_CROSS;
1484+ }
1485+ }
1486+ html += " <br />\n " ;
1487+ res->print (html);
1488+ html.clear ();
1489+ }
1490+ }
1491+ html += " </div>" ;
1492+ html += " <input type=button onclick=\" window.location.href='/sd?path="
1493+ + ObsUtils::encodeForUrl (path) + " '\" class='btn' value='Back' />" ;
1494+ html += footer;
1495+ res->print (html);
1496+ }
1497+
1498+
14451499static void handleSd (HTTPRequest *req, HTTPResponse *res) {
14461500 String path = getParameter (req, " path" , " /" );
14471501
@@ -1454,7 +1508,9 @@ static void handleSd(HTTPRequest *req, HTTPResponse *res) {
14541508
14551509 if (file.isDirectory ()) {
14561510 String html = header;
1457- html = replaceDefault (html, " SD Card Contents " + String (file.name ()));
1511+ html = replaceDefault (html, " SD Card Contents " + String (file.name ()), " /deleteFiles" );
1512+
1513+ html += " <input type='hidden' name='path' value='" + ObsUtils::encodeForXmlAttribute (path) + " '/>" ;
14581514 html += " <ul class=\" directory-listing\" >" ;
14591515 sendHtml (res, html);
14601516 html.clear ();
@@ -1468,12 +1524,20 @@ static void handleSd(HTTPRequest *req, HTTPResponse *res) {
14681524 displayTest->drawWaitBar (5 , counter++);
14691525
14701526 auto fileName = String (child.name ());
1527+ auto fileTip = ObsUtils::encodeForXmlAttribute (
1528+ ObsUtils::dateTimeToString (child.getLastWrite ())
1529+ + " - " + ObsUtils::toScaledByteString (child.size ()));
1530+
14711531 fileName = fileName.substring (int (fileName.lastIndexOf (" /" ) + 1 ));
1532+ fileName = ObsUtils::encodeForXmlAttribute (fileName);
14721533 bool isDirectory = child.isDirectory ();
14731534 html +=
14741535 (" <li class=\" "
14751536 + String (isDirectory ? " directory" : " file" )
1476- + " \" ><a href=\" /sd?path="
1537+ + " \" title='" + fileTip + " '>"
1538+ + " <input class='small' type='checkbox' value='" + fileName + " ' name='delete'"
1539+ + String (isDirectory ? " disabled" : " " )
1540+ + " ><a href=\" /sd?path="
14771541 + String (child.name ())
14781542 + " \" >"
14791543 + String (isDirectory ? " 📁" : " 📄" )
@@ -1491,6 +1555,26 @@ static void handleSd(HTTPRequest *req, HTTPResponse *res) {
14911555 }
14921556 file.close ();
14931557 html += " </ul>" ;
1558+
1559+ if (path != " /" ) {
1560+ String back = path.substring (0 , path.lastIndexOf (' /' ));
1561+ if (back.isEmpty ()) {
1562+ back = " /" ;
1563+ }
1564+ html += " <input type=button onclick=\" window.location.href='/sd?path="
1565+ + ObsUtils::encodeForUrl (back) + " '\" class='btn' value='Up' />" ;
1566+ } else {
1567+ html += " <input type=button onclick=\" window.location.href='/'\" "
1568+ " class='btn' value='Menu' />" ;
1569+ }
1570+
1571+ if (counter > 0 ) {
1572+ if (path == " /trash" ) {
1573+ html += " <hr /><input type='submit' class='btn' value='Delete Selected' />" ;
1574+ } else {
1575+ html += " <hr /><input type='submit' class='btn' value='Move to Trash' />" ;
1576+ }
1577+ }
14941578 html += footer;
14951579 res->print (html);
14961580 displayTest->clearProgressBar (5 );
0 commit comments