2020-06-03 11:46:42 -05:00
|
|
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
|
|
|
|
/*
|
2023-10-30 16:58:54 -05:00
|
|
|
* Copyright the Collabora Online contributors.
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: MPL-2.0
|
2020-06-03 11:46:42 -05:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include "FileServer.hpp"
|
2022-03-29 20:37:57 -05:00
|
|
|
#include "StringVector.hpp"
|
|
|
|
#include "Util.hpp"
|
|
|
|
|
|
|
|
#include <Poco/JSON/Object.h>
|
2020-06-03 11:46:42 -05:00
|
|
|
|
2023-10-30 17:35:17 -05:00
|
|
|
std::string FileServerRequestHandler::uiDefaultsToJSON(const std::string& uiDefaults, std::string& uiMode, std::string& uiTheme, std::string& savedUIState)
|
2020-06-03 11:46:42 -05:00
|
|
|
{
|
|
|
|
static std::string previousUIDefaults;
|
|
|
|
static std::string previousJSON("{}");
|
2020-12-07 02:02:06 -06:00
|
|
|
static std::string previousUIMode;
|
2020-06-03 11:46:42 -05:00
|
|
|
|
|
|
|
// early exit if we are serving the same thing
|
|
|
|
if (uiDefaults == previousUIDefaults)
|
2020-12-07 02:02:06 -06:00
|
|
|
{
|
|
|
|
uiMode = previousUIMode;
|
2020-06-03 11:46:42 -05:00
|
|
|
return previousJSON;
|
2020-12-07 02:02:06 -06:00
|
|
|
}
|
2020-06-03 11:46:42 -05:00
|
|
|
|
|
|
|
Poco::JSON::Object json;
|
|
|
|
Poco::JSON::Object textDefs;
|
|
|
|
Poco::JSON::Object spreadsheetDefs;
|
|
|
|
Poco::JSON::Object presentationDefs;
|
2021-10-22 11:07:37 -05:00
|
|
|
Poco::JSON::Object drawingDefs;
|
2020-06-03 11:46:42 -05:00
|
|
|
|
2020-12-07 02:02:06 -06:00
|
|
|
uiMode = "";
|
2023-05-25 16:51:17 -05:00
|
|
|
uiTheme = "light";
|
2023-10-30 17:35:17 -05:00
|
|
|
savedUIState = "true";
|
2022-03-29 20:37:57 -05:00
|
|
|
StringVector tokens(StringVector::tokenize(uiDefaults, ';'));
|
2020-06-03 11:46:42 -05:00
|
|
|
for (const auto& token : tokens)
|
|
|
|
{
|
2022-03-29 20:37:57 -05:00
|
|
|
StringVector keyValue(StringVector::tokenize(tokens.getParam(token), '='));
|
2020-06-03 11:46:42 -05:00
|
|
|
Poco::JSON::Object* currentDef = nullptr;
|
|
|
|
std::string key;
|
|
|
|
|
|
|
|
// detect the UIMode or component
|
2021-10-18 09:41:12 -05:00
|
|
|
if (keyValue.equals(0, "UIMode"))
|
2020-06-03 11:46:42 -05:00
|
|
|
{
|
2022-04-22 05:00:00 -05:00
|
|
|
if (keyValue.equals(1, "compact") || keyValue.equals(1, "classic"))
|
2020-12-07 02:02:06 -06:00
|
|
|
{
|
2022-04-22 05:00:00 -05:00
|
|
|
json.set("uiMode", "classic");
|
|
|
|
uiMode = "classic";
|
|
|
|
}
|
|
|
|
else if(keyValue.equals(1, "tabbed") || keyValue.equals(1, "notebookbar"))
|
|
|
|
{
|
|
|
|
json.set("uiMode", "notebookbar");
|
|
|
|
uiMode = "notebookbar";
|
2020-12-07 02:02:06 -06:00
|
|
|
}
|
2020-06-03 11:46:42 -05:00
|
|
|
else
|
2021-02-17 07:50:48 -06:00
|
|
|
LOG_ERR("unknown UIMode value " << keyValue[1]);
|
2020-06-03 11:46:42 -05:00
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
2023-05-25 16:51:17 -05:00
|
|
|
|
|
|
|
// detect the UITheme default, light or dark
|
|
|
|
if (keyValue.equals(0, "UITheme"))
|
|
|
|
{
|
|
|
|
json.set("darkTheme", keyValue.equals(1, "dark"));
|
|
|
|
uiTheme = keyValue[1];
|
|
|
|
}
|
2023-10-30 17:35:17 -05:00
|
|
|
if (keyValue.equals(0, "SavedUIState"))
|
|
|
|
{
|
|
|
|
if (keyValue.equals(1, "false"))
|
|
|
|
{
|
|
|
|
savedUIState = "false";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!keyValue.equals(1, "true"))
|
|
|
|
{
|
|
|
|
LOG_ERR("unknown SavedUIState value " << keyValue[1]);
|
|
|
|
}
|
|
|
|
savedUIState = "true";
|
|
|
|
}
|
|
|
|
}
|
2022-09-06 12:12:07 -05:00
|
|
|
if (keyValue.equals(0, "SaveAsMode"))
|
|
|
|
{
|
|
|
|
if (keyValue.equals(1, "group"))
|
|
|
|
{
|
|
|
|
json.set("saveAsMode", "group");
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
2023-11-03 11:33:43 -05:00
|
|
|
if (keyValue.equals(0, "OnscreenKeyboardHint"))
|
|
|
|
{
|
|
|
|
json.set("onscreenKeyboardHint", keyValue.equals(1, "true"));
|
|
|
|
continue;
|
|
|
|
}
|
2021-10-14 06:38:45 -05:00
|
|
|
else if (keyValue.startsWith(0, "Text"))
|
2020-06-03 11:46:42 -05:00
|
|
|
{
|
|
|
|
currentDef = &textDefs;
|
|
|
|
key = keyValue[0].substr(4);
|
|
|
|
}
|
2021-10-14 06:38:45 -05:00
|
|
|
else if (keyValue.startsWith(0, "Spreadsheet"))
|
2020-06-03 11:46:42 -05:00
|
|
|
{
|
|
|
|
currentDef = &spreadsheetDefs;
|
|
|
|
key = keyValue[0].substr(11);
|
|
|
|
}
|
2021-10-14 06:38:45 -05:00
|
|
|
else if (keyValue.startsWith(0, "Presentation"))
|
2020-06-03 11:46:42 -05:00
|
|
|
{
|
|
|
|
currentDef = &presentationDefs;
|
|
|
|
key = keyValue[0].substr(12);
|
|
|
|
}
|
2021-10-22 11:07:37 -05:00
|
|
|
else if (Util::startsWith(keyValue[0], "Drawing"))
|
|
|
|
{
|
|
|
|
currentDef = &drawingDefs;
|
|
|
|
key = keyValue[0].substr(7);
|
|
|
|
}
|
2020-06-03 11:46:42 -05:00
|
|
|
else
|
|
|
|
{
|
2021-02-17 07:50:48 -06:00
|
|
|
LOG_ERR("unknown UI default's component " << keyValue[0]);
|
2020-06-03 11:46:42 -05:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(currentDef);
|
|
|
|
|
|
|
|
// detect the actual UI widget we want to hide or show
|
2023-11-07 14:15:06 -06:00
|
|
|
if (key == "Ruler" || key == "Sidebar" || key == "Statusbar" || key == "Toolbar")
|
2020-06-03 11:46:42 -05:00
|
|
|
{
|
|
|
|
bool value(true);
|
2021-10-18 09:41:12 -05:00
|
|
|
if (keyValue.equals(1, "false") || keyValue.equals(1, "False") || keyValue.equals(1, "0"))
|
2020-06-03 11:46:42 -05:00
|
|
|
value = false;
|
|
|
|
|
|
|
|
currentDef->set("Show" + key, value);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-02-17 07:50:48 -06:00
|
|
|
LOG_ERR("unknown UI default " << keyValue[0]);
|
2020-06-03 11:46:42 -05:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (textDefs.size() > 0)
|
|
|
|
json.set("text", textDefs);
|
|
|
|
|
|
|
|
if (spreadsheetDefs.size() > 0)
|
|
|
|
json.set("spreadsheet", spreadsheetDefs);
|
|
|
|
|
|
|
|
if (presentationDefs.size() > 0)
|
|
|
|
json.set("presentation", presentationDefs);
|
|
|
|
|
2021-10-22 11:07:37 -05:00
|
|
|
if (drawingDefs.size() > 0)
|
|
|
|
json.set("drawing", drawingDefs);
|
|
|
|
|
2020-06-03 11:46:42 -05:00
|
|
|
std::ostringstream oss;
|
|
|
|
Poco::JSON::Stringifier::stringify(json, oss);
|
|
|
|
|
|
|
|
previousUIDefaults = uiDefaults;
|
|
|
|
previousJSON = oss.str();
|
2020-12-07 02:02:06 -06:00
|
|
|
previousUIMode = uiMode;
|
2020-06-03 11:46:42 -05:00
|
|
|
|
|
|
|
return previousJSON;
|
|
|
|
}
|
|
|
|
|
2022-10-10 10:21:27 -05:00
|
|
|
std::string FileServerRequestHandler::checkFileInfoToJSON(const std::string& checkfileInfo)
|
|
|
|
{
|
|
|
|
static std::string previousCheckFileInfo;
|
|
|
|
static std::string previousCheckFileInfoJSON("{}");
|
|
|
|
|
|
|
|
// early exit if we are serving the same thing
|
|
|
|
if (checkfileInfo == previousCheckFileInfo)
|
|
|
|
return previousCheckFileInfoJSON;
|
|
|
|
|
|
|
|
Poco::JSON::Object json;
|
|
|
|
StringVector tokens(StringVector::tokenize(checkfileInfo, ';'));
|
|
|
|
for (const auto& token : tokens)
|
|
|
|
{
|
|
|
|
StringVector keyValue(StringVector::tokenize(tokens.getParam(token), '='));
|
|
|
|
if (keyValue.equals(0, "DownloadAsPostMessage"))
|
|
|
|
{
|
|
|
|
bool value(false);
|
|
|
|
if (keyValue.equals(1, "true") || keyValue.equals(1, "True") || keyValue.equals(1, "1"))
|
|
|
|
value = true;
|
|
|
|
json.set(keyValue[0], value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
std::ostringstream oss;
|
|
|
|
Poco::JSON::Stringifier::stringify(json, oss);
|
|
|
|
previousCheckFileInfo = checkfileInfo;
|
|
|
|
previousCheckFileInfoJSON = oss.str();
|
|
|
|
return previousCheckFileInfoJSON;
|
|
|
|
}
|
|
|
|
|
2021-06-30 09:51:50 -05:00
|
|
|
namespace
|
|
|
|
{
|
|
|
|
bool isValidCss(const std::string& token)
|
|
|
|
{
|
|
|
|
const std::string forbidden = "<>{}&|\\\"^`'$[]";
|
|
|
|
for (auto c: token)
|
|
|
|
{
|
|
|
|
if (c < 0x20 || c >= 0x7F || forbidden.find(c) != std::string::npos)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-22 06:08:11 -05:00
|
|
|
std::string FileServerRequestHandler::cssVarsToStyle(const std::string& cssVars)
|
|
|
|
{
|
|
|
|
static std::string previousVars;
|
2020-12-03 20:14:30 -06:00
|
|
|
static std::string previousStyle;
|
2020-10-22 06:08:11 -05:00
|
|
|
|
|
|
|
// early exit if we are serving the same thing
|
|
|
|
if (cssVars == previousVars)
|
|
|
|
return previousStyle;
|
|
|
|
|
|
|
|
std::ostringstream styleOSS;
|
|
|
|
styleOSS << "<style>:root {";
|
2022-03-29 20:37:57 -05:00
|
|
|
StringVector tokens(StringVector::tokenize(cssVars, ';'));
|
2020-10-22 06:08:11 -05:00
|
|
|
for (const auto& token : tokens)
|
|
|
|
{
|
2022-03-29 20:37:57 -05:00
|
|
|
StringVector keyValue(StringVector::tokenize(tokens.getParam(token), '='));
|
2020-10-22 06:08:11 -05:00
|
|
|
if (keyValue.size() < 2)
|
|
|
|
{
|
2021-02-17 07:50:48 -06:00
|
|
|
LOG_ERR("Skipping the token [" << tokens.getParam(token) << "] since it does not have '='");
|
2020-10-22 06:08:11 -05:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else if (keyValue.size() > 2)
|
|
|
|
{
|
2021-02-17 07:50:48 -06:00
|
|
|
LOG_ERR("Skipping the token [" << tokens.getParam(token) << "] since it has more than one '=' pair");
|
2020-10-22 06:08:11 -05:00
|
|
|
continue;
|
|
|
|
}
|
2021-06-30 09:51:50 -05:00
|
|
|
|
|
|
|
if (!isValidCss(tokens.getParam(token)))
|
|
|
|
{
|
|
|
|
LOG_WRN("Skipping the token [" << tokens.getParam(token) << "] since it contains forbidden characters");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-12-06 22:01:18 -06:00
|
|
|
styleOSS << keyValue[0] << ':' << keyValue[1] << ';';
|
2020-10-22 06:08:11 -05:00
|
|
|
}
|
|
|
|
styleOSS << "}</style>";
|
|
|
|
|
|
|
|
previousVars = cssVars;
|
|
|
|
previousStyle = styleOSS.str();
|
|
|
|
|
|
|
|
return previousStyle;
|
|
|
|
}
|
|
|
|
|
2021-12-07 04:04:14 -06:00
|
|
|
std::string FileServerRequestHandler::stringifyBoolFromConfig(
|
|
|
|
const Poco::Util::LayeredConfiguration& config,
|
|
|
|
std::string propertyName,
|
|
|
|
bool defaultValue)
|
|
|
|
{
|
|
|
|
std::string value = "false";
|
|
|
|
if (config.getBool(propertyName, defaultValue))
|
|
|
|
value = "true";
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
2020-06-03 11:46:42 -05:00
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|