[Libreoffice-commits] online.git: loolwsd/ChildProcessSession.cpp loolwsd/ChildProcessSession.hpp loolwsd/LOKitHelper.hpp loolwsd/LOOLSession.cpp loolwsd/LOOLSession.hpp loolwsd/LOOLWSD.cpp loolwsd/Makefile.am
Henry Castro
hcastro at collabora.com
Wed Dec 23 09:04:01 PST 2015
loolwsd/ChildProcessSession.cpp | 820 ++++++++++++++++++++++++++++++++++++++++
loolwsd/ChildProcessSession.hpp | 64 +++
loolwsd/LOKitHelper.hpp | 2
loolwsd/LOOLSession.cpp | 778 -------------------------------------
loolwsd/LOOLSession.hpp | 48 --
loolwsd/LOOLWSD.cpp | 1
loolwsd/Makefile.am | 4
7 files changed, 889 insertions(+), 828 deletions(-)
New commits:
commit 1f43e99ac7465342d2e0fbff7a313844d45a4807
Author: Henry Castro <hcastro at collabora.com>
Date: Sat Dec 12 14:23:44 2015 -0500
loolwsd: Refactored ChildProcessSession
ChildProcessSession class now moved to own files.
Change-Id: Ic67c8563ada51f23c83e06631ad913af610d395c
Reviewed-on: https://gerrit.libreoffice.org/20895
Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
Tested-by: Henry Castro <hcastro at collabora.com>
diff --git a/loolwsd/ChildProcessSession.cpp b/loolwsd/ChildProcessSession.cpp
new file mode 100644
index 0000000..ab92478
--- /dev/null
+++ b/loolwsd/ChildProcessSession.cpp
@@ -0,0 +1,820 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <iostream>
+
+#include <Poco/File.h>
+#include <Poco/JSON/Object.h>
+#include <Poco/JSON/Parser.h>
+#include <Poco/Net/WebSocket.h>
+#include <Poco/Path.h>
+#include <Poco/Process.h>
+#include <Poco/String.h>
+#include <Poco/StringTokenizer.h>
+#include <Poco/URI.h>
+#include <Poco/Util/Application.h>
+
+#include "ChildProcessSession.hpp"
+#include "LOKitHelper.hpp"
+#include "LOOLProtocol.hpp"
+#include "LOOLWSD.hpp"
+#include "Util.hpp"
+
+using namespace LOOLProtocol;
+
+using Poco::File;
+using Poco::IOException;
+using Poco::JSON::Object;
+using Poco::JSON::Parser;
+using Poco::Net::WebSocket;
+using Poco::Path;
+using Poco::Process;
+using Poco::ProcessHandle;
+using Poco::StringTokenizer;
+using Poco::URI;
+using Poco::Util::Application;
+
+ChildProcessSession::ChildProcessSession(std::shared_ptr<WebSocket> ws, LibreOfficeKit *loKit, std::string childId) :
+ LOOLSession(ws, Kind::ToMaster),
+ _loKitDocument(NULL),
+ _loKit(loKit),
+ _childId(childId),
+ _clientPart(0)
+{
+ std::cout << Util::logPrefix() << "ChildProcessSession ctor this=" << this << " ws=" << _ws.get() << std::endl;
+}
+
+ChildProcessSession::~ChildProcessSession()
+{
+ std::cout << Util::logPrefix() << "ChildProcessSession dtor this=" << this << std::endl;
+ if (LIBREOFFICEKIT_HAS(_loKit, registerCallback))
+ _loKit->pClass->registerCallback(_loKit, 0, 0);
+}
+
+bool ChildProcessSession::handleInput(const char *buffer, int length)
+{
+ std::string firstLine = getFirstLine(buffer, length);
+ StringTokenizer tokens(firstLine, " ", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM);
+
+ Application::instance().logger().information(Util::logPrefix() + _kindString + ",Input," + getAbbreviatedMessage(buffer, length));
+
+ if (tokens[0] == "canceltiles")
+ {
+ // this command makes sense only on the command queue level, nothing
+ // to do here
+ return true;
+ }
+ else if (tokens[0] == "commandvalues")
+ {
+ return getCommandValues(buffer, length, tokens);
+ }
+ else if (tokens[0] == "partpagerectangles")
+ {
+ return getPartPageRectangles(buffer, length);
+ }
+ else if (tokens[0] == "load")
+ {
+ if (_docURL != "")
+ {
+ sendTextFrame("error: cmd=load kind=docalreadyloaded");
+ return false;
+ }
+ return loadDocument(buffer, length, tokens);
+ }
+ else if (_docURL == "")
+ {
+ sendTextFrame("error: cmd=" + tokens[0] + " kind=nodocloaded");
+ return false;
+ }
+ else if (tokens[0] == "renderfont")
+ {
+ sendFontRendering(buffer, length, tokens);
+ }
+ else if (tokens[0] == "setclientpart")
+ {
+ return setClientPart(buffer, length, tokens);
+ }
+ else if (tokens[0] == "setpage")
+ {
+ return setPage(buffer, length, tokens);
+ }
+ else if (tokens[0] == "status")
+ {
+ return getStatus(buffer, length);
+ }
+ else if (tokens[0] == "tile")
+ {
+ sendTile(buffer, length, tokens);
+ }
+ else
+ {
+ // All other commands are such that they always require a LibreOfficeKitDocument session,
+ // i.e. need to be handled in a child process.
+
+ assert(tokens[0] == "clientzoom" ||
+ tokens[0] == "downloadas" ||
+ tokens[0] == "getchildid" ||
+ tokens[0] == "gettextselection" ||
+ tokens[0] == "paste" ||
+ tokens[0] == "insertfile" ||
+ tokens[0] == "key" ||
+ tokens[0] == "mouse" ||
+ tokens[0] == "uno" ||
+ tokens[0] == "selecttext" ||
+ tokens[0] == "selectgraphic" ||
+ tokens[0] == "resetselection" ||
+ tokens[0] == "saveas");
+
+ if (_docType != "text" && _loKitDocument->pClass->getPart(_loKitDocument) != _clientPart)
+ {
+ _loKitDocument->pClass->setPart(_loKitDocument, _clientPart);
+ }
+ if (tokens[0] == "clientzoom")
+ {
+ return clientZoom(buffer, length, tokens);
+ }
+ else if (tokens[0] == "downloadas")
+ {
+ return downloadAs(buffer, length, tokens);
+ }
+ else if (tokens[0] == "getchildid")
+ {
+ return getChildId();
+ }
+ else if (tokens[0] == "gettextselection")
+ {
+ return getTextSelection(buffer, length, tokens);
+ }
+ else if (tokens[0] == "paste")
+ {
+ return paste(buffer, length, tokens);
+ }
+ else if (tokens[0] == "insertfile")
+ {
+ return insertFile(buffer, length, tokens);
+ }
+ else if (tokens[0] == "key")
+ {
+ return keyEvent(buffer, length, tokens);
+ }
+ else if (tokens[0] == "mouse")
+ {
+ return mouseEvent(buffer, length, tokens);
+ }
+ else if (tokens[0] == "uno")
+ {
+ return unoCommand(buffer, length, tokens);
+ }
+ else if (tokens[0] == "selecttext")
+ {
+ return selectText(buffer, length, tokens);
+ }
+ else if (tokens[0] == "selectgraphic")
+ {
+ return selectGraphic(buffer, length, tokens);
+ }
+ else if (tokens[0] == "resetselection")
+ {
+ return resetSelection(buffer, length, tokens);
+ }
+ else if (tokens[0] == "saveas")
+ {
+ return saveAs(buffer, length, tokens);
+ }
+ else
+ {
+ assert(false);
+ }
+ }
+ return true;
+}
+
+extern "C"
+{
+ static void myCallback(int nType, const char* pPayload, void* pData)
+ {
+ ChildProcessSession *srv = reinterpret_cast<ChildProcessSession *>(pData);
+
+ switch ((LibreOfficeKitCallbackType) nType)
+ {
+ case LOK_CALLBACK_INVALIDATE_TILES:
+ {
+ int curPart = srv->_loKitDocument->pClass->getPart(srv->_loKitDocument);
+ srv->sendTextFrame("curpart: part=" + std::to_string(curPart));
+ if (srv->_docType == "text")
+ {
+ curPart = 0;
+ }
+ StringTokenizer tokens(std::string(pPayload), " ", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM);
+ if (tokens.count() == 4)
+ {
+ int x, y, width, height;
+
+ try {
+ x = std::stoi(tokens[0]);
+ y = std::stoi(tokens[1]);
+ width = std::stoi(tokens[2]);
+ height = std::stoi(tokens[3]);
+ }
+ catch (std::out_of_range&)
+ {
+ // something went wrong, invalidate everything
+ Application::instance().logger().information(Util::logPrefix() + "Ignoring integer values out of range: " + pPayload);
+ x = 0;
+ y = 0;
+ width = INT_MAX;
+ height = INT_MAX;
+ }
+
+ srv->sendTextFrame("invalidatetiles:"
+ " part=" + std::to_string(curPart) +
+ " x=" + std::to_string(x) +
+ " y=" + std::to_string(y) +
+ " width=" + std::to_string(width) +
+ " height=" + std::to_string(height));
+ }
+ else
+ {
+ srv->sendTextFrame("invalidatetiles: " + std::string(pPayload));
+ }
+ }
+ break;
+ case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR:
+ srv->sendTextFrame("invalidatecursor: " + std::string(pPayload));
+ break;
+ case LOK_CALLBACK_TEXT_SELECTION:
+ srv->sendTextFrame("textselection: " + std::string(pPayload));
+ break;
+ case LOK_CALLBACK_TEXT_SELECTION_START:
+ srv->sendTextFrame("textselectionstart: " + std::string(pPayload));
+ break;
+ case LOK_CALLBACK_TEXT_SELECTION_END:
+ srv->sendTextFrame("textselectionend: " + std::string(pPayload));
+ break;
+ case LOK_CALLBACK_CURSOR_VISIBLE:
+ srv->sendTextFrame("cursorvisible: " + std::string(pPayload));
+ break;
+ case LOK_CALLBACK_GRAPHIC_SELECTION:
+ srv->sendTextFrame("graphicselection: " + std::string(pPayload));
+ break;
+ case LOK_CALLBACK_CELL_CURSOR:
+ srv->sendTextFrame("cellcursor: " + std::string(pPayload));
+ break;
+ case LOK_CALLBACK_CELL_FORMULA:
+ srv->sendTextFrame("cellformula: " + std::string(pPayload));
+ break;
+ case LOK_CALLBACK_MOUSE_POINTER:
+ srv->sendTextFrame("mousepointer: " + std::string(pPayload));
+ break;
+ case LOK_CALLBACK_HYPERLINK_CLICKED:
+ srv->sendTextFrame("hyperlinkclicked: " + std::string(pPayload));
+ break;
+ case LOK_CALLBACK_STATE_CHANGED:
+ srv->sendTextFrame("statechanged: " + std::string(pPayload));
+ break;
+ case LOK_CALLBACK_STATUS_INDICATOR_START:
+ srv->sendTextFrame("statusindicatorstart:");
+ break;
+ case LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE:
+ srv->sendTextFrame("statusindicatorsetvalue: " + std::string(pPayload));
+ break;
+ case LOK_CALLBACK_STATUS_INDICATOR_FINISH:
+ srv->sendTextFrame("statusindicatorfinish:");
+ break;
+ case LOK_CALLBACK_SEARCH_NOT_FOUND:
+ srv->sendTextFrame("searchnotfound: " + std::string(pPayload));
+ break;
+ case LOK_CALLBACK_SEARCH_RESULT_SELECTION:
+ srv->sendTextFrame("searchresultselection: " + std::string(pPayload));
+ break;
+ case LOK_CALLBACK_DOCUMENT_SIZE_CHANGED:
+ srv->getStatus("", 0);
+ srv->getPartPageRectangles("", 0);
+ break;
+ case LOK_CALLBACK_SET_PART:
+ srv->sendTextFrame("setpart: " + std::string(pPayload));
+ break;
+ case LOK_CALLBACK_UNO_COMMAND_RESULT:
+ srv->sendTextFrame("unocommandresult: " + std::string(pPayload));
+ break;
+ }
+ }
+}
+
+bool ChildProcessSession::loadDocument(const char *buffer, int length, StringTokenizer& tokens)
+{
+ int part = -1;
+ if (tokens.count() < 2)
+ {
+ sendTextFrame("error: cmd=load kind=syntax");
+ return false;
+ }
+
+ std::string timestamp;
+ parseDocOptions(tokens, part, timestamp);
+
+ URI aUri;
+ try
+ {
+ aUri = URI(_docURL);
+ }
+ catch(Poco::SyntaxException&)
+ {
+ sendTextFrame("error: cmd=load kind=uriinvalid");
+ return false;
+ }
+
+ if (aUri.empty())
+ {
+ sendTextFrame("error: cmd=load kind=uriempty");
+ return false;
+ }
+
+ // The URL in the request is the original one, not visible in the chroot jail.
+ // The child process uses the fixed name jailDocumentURL.
+
+ if (LIBREOFFICEKIT_HAS(_loKit, registerCallback))
+ _loKit->pClass->registerCallback(_loKit, myCallback, this);
+
+ if (aUri.isRelative() || aUri.getScheme() == "file")
+ aUri = URI( URI("file://"), Path(jailDocumentURL + Path::separator() + std::to_string(Process::id()),
+ Path(aUri.getPath()).getFileName()).toString() );
+
+ if ((_loKitDocument = _loKit->pClass->documentLoad(_loKit, aUri.toString().c_str())) == NULL)
+ {
+ sendTextFrame("error: cmd=load kind=failed");
+ Application::instance().logger().information(Util::logPrefix() + "Failed to load: " + aUri.toString() + ", error is: " + _loKit->pClass->getError(_loKit));
+ return false;
+ }
+
+ std::string renderingOptions;
+ if (!_docOptions.empty())
+ {
+ Poco::JSON::Parser parser;
+ Poco::Dynamic::Var var = parser.parse(_docOptions);
+ Poco::JSON::Object::Ptr object = var.extract<Poco::JSON::Object::Ptr>();
+ renderingOptions = object->get("rendering").toString();
+ }
+
+ _loKitDocument->pClass->initializeForRendering(_loKitDocument, (renderingOptions.empty() ? nullptr : renderingOptions.c_str()));
+
+ if ( _docType != "text" && part != -1)
+ {
+ _clientPart = part;
+ _loKitDocument->pClass->setPart(_loKitDocument, part);
+ }
+
+ if (!getStatus(buffer, length))
+ return false;
+
+ _loKitDocument->pClass->registerCallback(_loKitDocument, myCallback, this);
+
+ return true;
+}
+
+void ChildProcessSession::sendFontRendering(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens)
+{
+ std::string font, decodedFont;
+ int width, height;
+ unsigned char *pixmap;
+
+ if (tokens.count() < 2 ||
+ !getTokenString(tokens[1], "font", font))
+ {
+ sendTextFrame("error: cmd=renderfont kind=syntax");
+ return;
+ }
+
+ URI::decode(font, decodedFont);
+ std::string response = "renderfont: " + Poco::cat(std::string(" "), tokens.begin() + 1, tokens.end()) + "\n";
+
+ std::vector<char> output;
+ output.resize(response.size());
+ std::memcpy(output.data(), response.data(), response.size());
+
+ Poco::Timestamp timestamp;
+ pixmap = _loKitDocument->pClass->renderFont(_loKitDocument, decodedFont.c_str(), &width, &height);
+ std::cout << Util::logPrefix() << "renderFont called, font[" << font << "] rendered in " << double(timestamp.elapsed())/1000 << "ms" << std::endl;
+
+ if (pixmap != nullptr) {
+ if (!Util::encodePNGAndAppendToBuffer(pixmap, width, height, output, LOK_TILEMODE_RGBA))
+ {
+ sendTextFrame("error: cmd=renderfont kind=failure");
+ delete[] pixmap;
+ return;
+ }
+ delete[] pixmap;
+ }
+
+ sendBinaryFrame(output.data(), output.size());
+}
+
+bool ChildProcessSession::getStatus(const char* /*buffer*/, int /*length*/)
+{
+ std::string status = "status: " + LOKitHelper::documentStatus(_loKitDocument);
+ StringTokenizer tokens(status, " ", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM);
+ if (!getTokenString(tokens[1], "type", _docType))
+ {
+ Application::instance().logger().information(Util::logPrefix() + "failed to get document type from" + status);
+ }
+ sendTextFrame(status);
+
+ return true;
+}
+
+bool ChildProcessSession::getCommandValues(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens)
+{
+ std::string command;
+ if (tokens.count() != 2 || !getTokenString(tokens[1], "command", command))
+ {
+ sendTextFrame("error: cmd=commandvalues kind=syntax");
+ return false;
+ }
+ sendTextFrame("commandvalues: " + std::string(_loKitDocument->pClass->getCommandValues(_loKitDocument, command.c_str())));
+ return true;
+}
+
+bool ChildProcessSession::getPartPageRectangles(const char* /*buffer*/, int /*length*/)
+{
+ sendTextFrame("partpagerectangles: " + std::string(_loKitDocument->pClass->getPartPageRectangles(_loKitDocument)));
+ return true;
+}
+
+void ChildProcessSession::sendTile(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens)
+{
+ int part, width, height, tilePosX, tilePosY, tileWidth, tileHeight;
+
+ if (tokens.count() < 8 ||
+ !getTokenInteger(tokens[1], "part", part) ||
+ !getTokenInteger(tokens[2], "width", width) ||
+ !getTokenInteger(tokens[3], "height", height) ||
+ !getTokenInteger(tokens[4], "tileposx", tilePosX) ||
+ !getTokenInteger(tokens[5], "tileposy", tilePosY) ||
+ !getTokenInteger(tokens[6], "tilewidth", tileWidth) ||
+ !getTokenInteger(tokens[7], "tileheight", tileHeight))
+ {
+ sendTextFrame("error: cmd=tile kind=syntax");
+ return;
+ }
+
+ if (part < 0 ||
+ width <= 0 ||
+ height <= 0 ||
+ tilePosX < 0 ||
+ tilePosY < 0 ||
+ tileWidth <= 0 ||
+ tileHeight <= 0)
+ {
+ sendTextFrame("error: cmd=tile kind=invalid");
+ return;
+ }
+
+ std::string response = "tile: " + Poco::cat(std::string(" "), tokens.begin() + 1, tokens.end()) + "\n";
+
+ std::vector<char> output;
+ output.reserve(4 * width * height);
+ output.resize(response.size());
+ std::memcpy(output.data(), response.data(), response.size());
+
+ unsigned char *pixmap = new unsigned char[4 * width * height];
+ memset(pixmap, 0, 4 * width * height);
+
+ if (_docType != "text" && part != _loKitDocument->pClass->getPart(_loKitDocument))
+ {
+ _loKitDocument->pClass->setPart(_loKitDocument, part);
+ }
+
+ Poco::Timestamp timestamp;
+ _loKitDocument->pClass->paintTile(_loKitDocument, pixmap, width, height, tilePosX, tilePosY, tileWidth, tileHeight);
+ std::cout << Util::logPrefix() << "paintTile called, tile at [" << tilePosX << ", " << tilePosY << "] rendered in " << double(timestamp.elapsed())/1000 << "ms" << std::endl;
+
+ LibreOfficeKitTileMode mode = static_cast<LibreOfficeKitTileMode>(_loKitDocument->pClass->getTileMode(_loKitDocument));
+ if (!Util::encodePNGAndAppendToBuffer(pixmap, width, height, output, mode))
+ {
+ sendTextFrame("error: cmd=tile kind=failure");
+ return;
+ }
+
+ delete[] pixmap;
+
+ sendBinaryFrame(output.data(), output.size());
+}
+
+bool ChildProcessSession::clientZoom(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens)
+{
+ int tilePixelWidth, tilePixelHeight, tileTwipWidth, tileTwipHeight;
+
+ if (tokens.count() != 5 ||
+ !getTokenInteger(tokens[1], "tilepixelwidth", tilePixelWidth) ||
+ !getTokenInteger(tokens[2], "tilepixelheight", tilePixelHeight) ||
+ !getTokenInteger(tokens[3], "tiletwipwidth", tileTwipWidth) ||
+ !getTokenInteger(tokens[4], "tiletwipheight", tileTwipHeight))
+ {
+ sendTextFrame("error: cmd=clientzoom kind=syntax");
+ return false;
+ }
+
+ _loKitDocument->pClass->setClientZoom(_loKitDocument, tilePixelWidth, tilePixelHeight, tileTwipWidth, tileTwipHeight);
+ return true;
+}
+bool ChildProcessSession::downloadAs(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens)
+{
+ std::string name, id, format, filterOptions;
+
+ if (tokens.count() < 5 ||
+ !getTokenString(tokens[1], "name", name) ||
+ !getTokenString(tokens[2], "id", id))
+ {
+ sendTextFrame("error: cmd=downloadas kind=syntax");
+ return false;
+ }
+
+ getTokenString(tokens[3], "format", format);
+
+ if (getTokenString(tokens[4], "options", filterOptions))
+ {
+ if (tokens.count() > 5)
+ {
+ filterOptions += Poco::cat(std::string(" "), tokens.begin() + 5, tokens.end());
+ }
+ }
+
+ std::string tmpDir, url;
+ File *file = NULL;
+ do
+ {
+ if (file != NULL)
+ {
+ delete file;
+ }
+ tmpDir = std::to_string((((Poco::UInt64)LOOLWSD::_rng.next()) << 32) | LOOLWSD::_rng.next() | 1);
+ url = jailDocumentURL + "/" + tmpDir + "/" + name;
+ file = new File(url);
+ } while (file->exists());
+ delete file;
+
+ _loKitDocument->pClass->saveAs(_loKitDocument, url.c_str(),
+ format.size() == 0 ? NULL :format.c_str(),
+ filterOptions.size() == 0 ? NULL : filterOptions.c_str());
+
+ sendTextFrame("downloadas: jail=" + _childId + " dir=" + tmpDir + " name=" + name +
+ " port=" + std::to_string(LOOLWSD::portNumber) + " id=" + id);
+ return true;
+}
+
+bool ChildProcessSession::getChildId()
+{
+ sendTextFrame("getchildid: id=" + _childId);
+ return true;
+}
+
+bool ChildProcessSession::getTextSelection(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens)
+{
+ std::string mimeType;
+
+ if (tokens.count() != 2 ||
+ !getTokenString(tokens[1], "mimetype", mimeType))
+ {
+ sendTextFrame("error: cmd=gettextselection kind=syntax");
+ return false;
+ }
+
+ char *textSelection = _loKitDocument->pClass->getTextSelection(_loKitDocument, mimeType.c_str(), NULL);
+
+ sendTextFrame("textselectioncontent: " + std::string(textSelection));
+ return true;
+}
+
+bool ChildProcessSession::paste(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens)
+{
+ std::string mimeType;
+ std::string data;
+
+ if (tokens.count() < 3 || !getTokenString(tokens[1], "mimetype", mimeType) || !getTokenString(tokens[2], "data", data))
+ {
+ sendTextFrame("error: cmd=paste kind=syntax");
+ return false;
+ }
+
+ data = Poco::cat(std::string(" "), tokens.begin() + 2, tokens.end()).substr(strlen("data="));
+
+ _loKitDocument->pClass->paste(_loKitDocument, mimeType.c_str(), data.c_str(), std::strlen(data.c_str()));
+
+ return true;
+}
+
+bool ChildProcessSession::insertFile(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens)
+{
+ std::string name, type;
+
+ if (tokens.count() != 3 ||
+ !getTokenString(tokens[1], "name", name) ||
+ !getTokenString(tokens[2], "type", type))
+ {
+ sendTextFrame("error: cmd=insertfile kind=syntax");
+ return false;
+ }
+
+ if (type == "graphic")
+ {
+ std::string fileName = "file://" + jailDocumentURL + "/insertfile/" + name;
+ std::string command = ".uno:InsertGraphic";
+ std::string arguments = "{"
+ "\"FileName\":{"
+ "\"type\":\"string\","
+ "\"value\":\"" + fileName + "\""
+ "}}";
+ _loKitDocument->pClass->postUnoCommand(_loKitDocument, command.c_str(), arguments.c_str(), false);
+ }
+
+ return true;
+}
+
+bool ChildProcessSession::keyEvent(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens)
+{
+ int type, charcode, keycode;
+
+ if (tokens.count() != 4 ||
+ !getTokenKeyword(tokens[1], "type",
+ {{"input", LOK_KEYEVENT_KEYINPUT}, {"up", LOK_KEYEVENT_KEYUP}},
+ type) ||
+ !getTokenInteger(tokens[2], "char", charcode) ||
+ !getTokenInteger(tokens[3], "key", keycode))
+ {
+ sendTextFrame("error: cmd=key kind=syntax");
+ return false;
+ }
+
+ _loKitDocument->pClass->postKeyEvent(_loKitDocument, type, charcode, keycode);
+
+ return true;
+}
+
+bool ChildProcessSession::mouseEvent(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens)
+{
+ int type, x, y, count, buttons, modifier;
+
+ if (tokens.count() != 7 ||
+ !getTokenKeyword(tokens[1], "type",
+ {{"buttondown", LOK_MOUSEEVENT_MOUSEBUTTONDOWN},
+ {"buttonup", LOK_MOUSEEVENT_MOUSEBUTTONUP},
+ {"move", LOK_MOUSEEVENT_MOUSEMOVE}},
+ type) ||
+ !getTokenInteger(tokens[2], "x", x) ||
+ !getTokenInteger(tokens[3], "y", y) ||
+ !getTokenInteger(tokens[4], "count", count) ||
+ !getTokenInteger(tokens[5], "buttons", buttons) ||
+ !getTokenInteger(tokens[6], "modifier", modifier))
+ {
+ sendTextFrame("error: cmd=mouse kind=syntax");
+ return false;
+ }
+
+ _loKitDocument->pClass->postMouseEvent(_loKitDocument, type, x, y, count, buttons, modifier);
+
+ return true;
+}
+
+bool ChildProcessSession::unoCommand(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens)
+{
+ if (tokens.count() == 1)
+ {
+ sendTextFrame("error: cmd=uno kind=syntax");
+ return false;
+ }
+
+ // we need to get LOK_CALLBACK_UNO_COMMAND_RESULT callback when saving
+ bool bNotify = (tokens[1] == ".uno:Save");
+
+ if (tokens.count() == 2)
+ {
+ _loKitDocument->pClass->postUnoCommand(_loKitDocument, tokens[1].c_str(), 0, bNotify);
+ }
+ else
+ {
+ _loKitDocument->pClass->postUnoCommand(_loKitDocument, tokens[1].c_str(), Poco::cat(std::string(" "), tokens.begin() + 2, tokens.end()).c_str(), bNotify);
+ }
+
+ return true;
+}
+
+bool ChildProcessSession::selectText(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens)
+{
+ int type, x, y;
+
+ if (tokens.count() != 4 ||
+ !getTokenKeyword(tokens[1], "type",
+ {{"start", LOK_SETTEXTSELECTION_START},
+ {"end", LOK_SETTEXTSELECTION_END},
+ {"reset", LOK_SETTEXTSELECTION_RESET}},
+ type) ||
+ !getTokenInteger(tokens[2], "x", x) ||
+ !getTokenInteger(tokens[3], "y", y))
+ {
+ sendTextFrame("error: cmd=selecttext kind=syntax");
+ return false;
+ }
+
+ _loKitDocument->pClass->setTextSelection(_loKitDocument, type, x, y);
+
+ return true;
+}
+
+bool ChildProcessSession::selectGraphic(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens)
+{
+ int type, x, y;
+
+ if (tokens.count() != 4 ||
+ !getTokenKeyword(tokens[1], "type",
+ {{"start", LOK_SETGRAPHICSELECTION_START},
+ {"end", LOK_SETGRAPHICSELECTION_END}},
+ type) ||
+ !getTokenInteger(tokens[2], "x", x) ||
+ !getTokenInteger(tokens[3], "y", y))
+ {
+ sendTextFrame("error: cmd=selectgraphic kind=syntax");
+ return false;
+ }
+
+ _loKitDocument->pClass->setGraphicSelection(_loKitDocument, type, x, y);
+
+ return true;
+}
+
+bool ChildProcessSession::resetSelection(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens)
+{
+ if (tokens.count() != 1)
+ {
+ sendTextFrame("error: cmd=resetselection kind=syntax");
+ return false;
+ }
+
+ _loKitDocument->pClass->resetSelection(_loKitDocument);
+
+ return true;
+}
+
+bool ChildProcessSession::saveAs(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens)
+{
+ std::string url, format, filterOptions;
+
+ if (tokens.count() < 4 ||
+ !getTokenString(tokens[1], "url", url))
+ {
+ sendTextFrame("error: cmd=saveas kind=syntax");
+ return false;
+ }
+
+ getTokenString(tokens[2], "format", format);
+
+ if (getTokenString(tokens[3], "options", filterOptions))
+ {
+ if (tokens.count() > 4)
+ {
+ filterOptions += Poco::cat(std::string(" "), tokens.begin() + 4, tokens.end());
+ }
+ }
+
+ bool success = _loKitDocument->pClass->saveAs(_loKitDocument, url.c_str(),
+ format.size() == 0 ? NULL :format.c_str(),
+ filterOptions.size() == 0 ? NULL : filterOptions.c_str());
+
+ sendTextFrame("saveas: url=" + url);
+ std::string successStr = success ? "true" : "false";
+ sendTextFrame("unocommandresult: {"
+ "\"commandName\":\"saveas\","
+ "\"success\":\"" + successStr + "\"}");
+
+ return true;
+}
+
+bool ChildProcessSession::setClientPart(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens)
+{
+ if (tokens.count() < 2 ||
+ !getTokenInteger(tokens[1], "part", _clientPart))
+ {
+ return false;
+ }
+ return true;
+}
+
+bool ChildProcessSession::setPage(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens)
+{
+ int page;
+ if (tokens.count() < 2 ||
+ !getTokenInteger(tokens[1], "page", page))
+ {
+ sendTextFrame("error: cmd=setpage kind=invalid");
+ return false;
+ }
+ _loKitDocument->pClass->setPart(_loKitDocument, page);
+ return true;
+}
+
+
diff --git a/loolwsd/ChildProcessSession.hpp b/loolwsd/ChildProcessSession.hpp
new file mode 100644
index 0000000..d2665d0
--- /dev/null
+++ b/loolwsd/ChildProcessSession.hpp
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_CHILDPROCESSSESSION_HPP
+#define INCLUDED_CHILDPROCESSSESSION_HPP
+
+#include "LOOLSession.hpp"
+
+class ChildProcessSession final : public LOOLSession
+{
+public:
+ ChildProcessSession(std::shared_ptr<Poco::Net::WebSocket> ws, LibreOfficeKit *loKit, std::string _childId);
+ virtual ~ChildProcessSession();
+
+ virtual bool handleInput(const char *buffer, int length) override;
+
+ virtual bool getStatus(const char *buffer, int length);
+
+ virtual bool getCommandValues(const char *buffer, int length, Poco::StringTokenizer& tokens);
+
+ virtual bool getPartPageRectangles(const char *buffer, int length) override;
+
+ LibreOfficeKitDocument *_loKitDocument;
+ std::string _docType;
+
+ protected:
+ virtual bool loadDocument(const char *buffer, int length, Poco::StringTokenizer& tokens) override;
+
+ virtual void sendTile(const char *buffer, int length, Poco::StringTokenizer& tokens);
+
+ virtual void sendFontRendering(const char *buffer, int length, Poco::StringTokenizer& tokens);
+
+ bool clientZoom(const char *buffer, int length, Poco::StringTokenizer& tokens);
+ bool downloadAs(const char *buffer, int length, Poco::StringTokenizer& tokens);
+ bool getChildId();
+ bool getTextSelection(const char *buffer, int length, Poco::StringTokenizer& tokens);
+ bool paste(const char *buffer, int length, Poco::StringTokenizer& tokens);
+ bool insertFile(const char *buffer, int length, Poco::StringTokenizer& tokens);
+ bool keyEvent(const char *buffer, int length, Poco::StringTokenizer& tokens);
+ bool mouseEvent(const char *buffer, int length, Poco::StringTokenizer& tokens);
+ bool unoCommand(const char *buffer, int length, Poco::StringTokenizer& tokens);
+ bool selectText(const char *buffer, int length, Poco::StringTokenizer& tokens);
+ bool selectGraphic(const char *buffer, int length, Poco::StringTokenizer& tokens);
+ bool resetSelection(const char *buffer, int length, Poco::StringTokenizer& tokens);
+ bool saveAs(const char *buffer, int length, Poco::StringTokenizer& tokens);
+ bool setClientPart(const char *buffer, int length, Poco::StringTokenizer& tokens);
+ bool setPage(const char *buffer, int length, Poco::StringTokenizer& tokens);
+
+ std::string _loSubPath;
+ LibreOfficeKit *_loKit;
+ std::string _childId;
+
+ private:
+ int _clientPart;
+};
+
+#endif
+
diff --git a/loolwsd/LOKitHelper.hpp b/loolwsd/LOKitHelper.hpp
index 33adeb8..fb0cdbc 100644
--- a/loolwsd/LOKitHelper.hpp
+++ b/loolwsd/LOKitHelper.hpp
@@ -18,6 +18,7 @@
namespace LOKitHelper
{
+ inline
std::string documentTypeToString(LibreOfficeKitDocumentType type)
{
switch (type)
@@ -35,6 +36,7 @@ namespace LOKitHelper
}
}
+ inline
std::string documentStatus(LibreOfficeKitDocument *loKitDocument)
{
std::string typeString(documentTypeToString(static_cast<LibreOfficeKitDocumentType>(loKitDocument->pClass->getDocumentType(loKitDocument))));
diff --git a/loolwsd/LOOLSession.cpp b/loolwsd/LOOLSession.cpp
index 7c208bb..db59e76 100644
--- a/loolwsd/LOOLSession.cpp
+++ b/loolwsd/LOOLSession.cpp
@@ -51,7 +51,6 @@
#include <Poco/Net/SocketAddress.h>
#include <Poco/FileStream.h>
-#include "LOKitHelper.hpp"
#include "LOOLProtocol.hpp"
#include "LOOLSession.hpp"
#include "LOOLWSD.hpp"
@@ -169,781 +168,4 @@ void LOOLSession::parseDocOptions(const StringTokenizer& tokens, int& part, std:
}
}
-ChildProcessSession::ChildProcessSession(std::shared_ptr<WebSocket> ws, LibreOfficeKit *loKit, std::string childId) :
- LOOLSession(ws, Kind::ToMaster),
- _loKitDocument(NULL),
- _loKit(loKit),
- _childId(childId),
- _clientPart(0)
-{
- std::cout << Util::logPrefix() << "ChildProcessSession ctor this=" << this << " ws=" << _ws.get() << std::endl;
-}
-
-ChildProcessSession::~ChildProcessSession()
-{
- std::cout << Util::logPrefix() << "ChildProcessSession dtor this=" << this << std::endl;
- if (LIBREOFFICEKIT_HAS(_loKit, registerCallback))
- _loKit->pClass->registerCallback(_loKit, 0, 0);
-}
-
-bool ChildProcessSession::handleInput(const char *buffer, int length)
-{
- std::string firstLine = getFirstLine(buffer, length);
- StringTokenizer tokens(firstLine, " ", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM);
-
- Application::instance().logger().information(Util::logPrefix() + _kindString + ",Input," + getAbbreviatedMessage(buffer, length));
-
- if (tokens[0] == "canceltiles")
- {
- // this command makes sense only on the command queue level, nothing
- // to do here
- return true;
- }
- else if (tokens[0] == "commandvalues")
- {
- return getCommandValues(buffer, length, tokens);
- }
- else if (tokens[0] == "partpagerectangles")
- {
- return getPartPageRectangles(buffer, length);
- }
- else if (tokens[0] == "load")
- {
- if (_docURL != "")
- {
- sendTextFrame("error: cmd=load kind=docalreadyloaded");
- return false;
- }
- return loadDocument(buffer, length, tokens);
- }
- else if (_docURL == "")
- {
- sendTextFrame("error: cmd=" + tokens[0] + " kind=nodocloaded");
- return false;
- }
- else if (tokens[0] == "renderfont")
- {
- sendFontRendering(buffer, length, tokens);
- }
- else if (tokens[0] == "setclientpart")
- {
- return setClientPart(buffer, length, tokens);
- }
- else if (tokens[0] == "setpage")
- {
- return setPage(buffer, length, tokens);
- }
- else if (tokens[0] == "status")
- {
- return getStatus(buffer, length);
- }
- else if (tokens[0] == "tile")
- {
- sendTile(buffer, length, tokens);
- }
- else
- {
- // All other commands are such that they always require a LibreOfficeKitDocument session,
- // i.e. need to be handled in a child process.
-
- assert(tokens[0] == "clientzoom" ||
- tokens[0] == "downloadas" ||
- tokens[0] == "getchildid" ||
- tokens[0] == "gettextselection" ||
- tokens[0] == "paste" ||
- tokens[0] == "insertfile" ||
- tokens[0] == "key" ||
- tokens[0] == "mouse" ||
- tokens[0] == "uno" ||
- tokens[0] == "selecttext" ||
- tokens[0] == "selectgraphic" ||
- tokens[0] == "resetselection" ||
- tokens[0] == "saveas");
-
- if (_docType != "text" && _loKitDocument->pClass->getPart(_loKitDocument) != _clientPart)
- {
- _loKitDocument->pClass->setPart(_loKitDocument, _clientPart);
- }
- if (tokens[0] == "clientzoom")
- {
- return clientZoom(buffer, length, tokens);
- }
- else if (tokens[0] == "downloadas")
- {
- return downloadAs(buffer, length, tokens);
- }
- else if (tokens[0] == "getchildid")
- {
- return getChildId();
- }
- else if (tokens[0] == "gettextselection")
- {
- return getTextSelection(buffer, length, tokens);
- }
- else if (tokens[0] == "paste")
- {
- return paste(buffer, length, tokens);
- }
- else if (tokens[0] == "insertfile")
- {
- return insertFile(buffer, length, tokens);
- }
- else if (tokens[0] == "key")
- {
- return keyEvent(buffer, length, tokens);
- }
- else if (tokens[0] == "mouse")
- {
- return mouseEvent(buffer, length, tokens);
- }
- else if (tokens[0] == "uno")
- {
- return unoCommand(buffer, length, tokens);
- }
- else if (tokens[0] == "selecttext")
- {
- return selectText(buffer, length, tokens);
- }
- else if (tokens[0] == "selectgraphic")
- {
- return selectGraphic(buffer, length, tokens);
- }
- else if (tokens[0] == "resetselection")
- {
- return resetSelection(buffer, length, tokens);
- }
- else if (tokens[0] == "saveas")
- {
- return saveAs(buffer, length, tokens);
- }
- else
- {
- assert(false);
- }
- }
- return true;
-}
-
-extern "C"
-{
- static void myCallback(int nType, const char* pPayload, void* pData)
- {
- ChildProcessSession *srv = reinterpret_cast<ChildProcessSession *>(pData);
-
- switch ((LibreOfficeKitCallbackType) nType)
- {
- case LOK_CALLBACK_INVALIDATE_TILES:
- {
- int curPart = srv->_loKitDocument->pClass->getPart(srv->_loKitDocument);
- srv->sendTextFrame("curpart: part=" + std::to_string(curPart));
- if (srv->_docType == "text")
- {
- curPart = 0;
- }
- StringTokenizer tokens(std::string(pPayload), " ", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM);
- if (tokens.count() == 4)
- {
- int x, y, width, height;
-
- try {
- x = std::stoi(tokens[0]);
- y = std::stoi(tokens[1]);
- width = std::stoi(tokens[2]);
- height = std::stoi(tokens[3]);
- }
- catch (std::out_of_range&)
- {
- // something went wrong, invalidate everything
- Application::instance().logger().information(Util::logPrefix() + "Ignoring integer values out of range: " + pPayload);
- x = 0;
- y = 0;
- width = INT_MAX;
- height = INT_MAX;
- }
-
- srv->sendTextFrame("invalidatetiles:"
- " part=" + std::to_string(curPart) +
- " x=" + std::to_string(x) +
- " y=" + std::to_string(y) +
- " width=" + std::to_string(width) +
- " height=" + std::to_string(height));
- }
- else
- {
- srv->sendTextFrame("invalidatetiles: " + std::string(pPayload));
- }
- }
- break;
- case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR:
- srv->sendTextFrame("invalidatecursor: " + std::string(pPayload));
- break;
- case LOK_CALLBACK_TEXT_SELECTION:
- srv->sendTextFrame("textselection: " + std::string(pPayload));
- break;
- case LOK_CALLBACK_TEXT_SELECTION_START:
- srv->sendTextFrame("textselectionstart: " + std::string(pPayload));
- break;
- case LOK_CALLBACK_TEXT_SELECTION_END:
- srv->sendTextFrame("textselectionend: " + std::string(pPayload));
- break;
- case LOK_CALLBACK_CURSOR_VISIBLE:
- srv->sendTextFrame("cursorvisible: " + std::string(pPayload));
- break;
- case LOK_CALLBACK_GRAPHIC_SELECTION:
- srv->sendTextFrame("graphicselection: " + std::string(pPayload));
- break;
- case LOK_CALLBACK_CELL_CURSOR:
- srv->sendTextFrame("cellcursor: " + std::string(pPayload));
- break;
- case LOK_CALLBACK_CELL_FORMULA:
- srv->sendTextFrame("cellformula: " + std::string(pPayload));
- break;
- case LOK_CALLBACK_MOUSE_POINTER:
- srv->sendTextFrame("mousepointer: " + std::string(pPayload));
- break;
- case LOK_CALLBACK_HYPERLINK_CLICKED:
- srv->sendTextFrame("hyperlinkclicked: " + std::string(pPayload));
- break;
- case LOK_CALLBACK_STATE_CHANGED:
- srv->sendTextFrame("statechanged: " + std::string(pPayload));
- break;
- case LOK_CALLBACK_STATUS_INDICATOR_START:
- srv->sendTextFrame("statusindicatorstart:");
- break;
- case LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE:
- srv->sendTextFrame("statusindicatorsetvalue: " + std::string(pPayload));
- break;
- case LOK_CALLBACK_STATUS_INDICATOR_FINISH:
- srv->sendTextFrame("statusindicatorfinish:");
- break;
- case LOK_CALLBACK_SEARCH_NOT_FOUND:
- srv->sendTextFrame("searchnotfound: " + std::string(pPayload));
- break;
- case LOK_CALLBACK_SEARCH_RESULT_SELECTION:
- srv->sendTextFrame("searchresultselection: " + std::string(pPayload));
- break;
- case LOK_CALLBACK_DOCUMENT_SIZE_CHANGED:
- srv->getStatus("", 0);
- srv->getPartPageRectangles("", 0);
- break;
- case LOK_CALLBACK_SET_PART:
- srv->sendTextFrame("setpart: " + std::string(pPayload));
- break;
- case LOK_CALLBACK_UNO_COMMAND_RESULT:
- srv->sendTextFrame("unocommandresult: " + std::string(pPayload));
- break;
- }
- }
-}
-
-bool ChildProcessSession::loadDocument(const char *buffer, int length, StringTokenizer& tokens)
-{
- int part = -1;
- if (tokens.count() < 2)
- {
- sendTextFrame("error: cmd=load kind=syntax");
- return false;
- }
-
- std::string timestamp;
- parseDocOptions(tokens, part, timestamp);
-
- URI aUri;
- try
- {
- aUri = URI(_docURL);
- }
- catch(Poco::SyntaxException&)
- {
- sendTextFrame("error: cmd=load kind=uriinvalid");
- return false;
- }
-
- if (aUri.empty())
- {
- sendTextFrame("error: cmd=load kind=uriempty");
- return false;
- }
-
- // The URL in the request is the original one, not visible in the chroot jail.
- // The child process uses the fixed name jailDocumentURL.
-
- if (LIBREOFFICEKIT_HAS(_loKit, registerCallback))
- _loKit->pClass->registerCallback(_loKit, myCallback, this);
-
- if (aUri.isRelative() || aUri.getScheme() == "file")
- aUri = URI( URI("file://"), Path(jailDocumentURL + Path::separator() + std::to_string(Process::id()),
- Path(aUri.getPath()).getFileName()).toString() );
-
- if ((_loKitDocument = _loKit->pClass->documentLoad(_loKit, aUri.toString().c_str())) == NULL)
- {
- sendTextFrame("error: cmd=load kind=failed");
- Application::instance().logger().information(Util::logPrefix() + "Failed to load: " + aUri.toString() + ", error is: " + _loKit->pClass->getError(_loKit));
- return false;
- }
-
- std::string renderingOptions;
- if (!_docOptions.empty())
- {
- Poco::JSON::Parser parser;
- Poco::Dynamic::Var var = parser.parse(_docOptions);
- Poco::JSON::Object::Ptr object = var.extract<Poco::JSON::Object::Ptr>();
- renderingOptions = object->get("rendering").toString();
- }
-
- _loKitDocument->pClass->initializeForRendering(_loKitDocument, (renderingOptions.empty() ? nullptr : renderingOptions.c_str()));
-
- if ( _docType != "text" && part != -1)
- {
- _clientPart = part;
- _loKitDocument->pClass->setPart(_loKitDocument, part);
- }
-
- if (!getStatus(buffer, length))
- return false;
-
- _loKitDocument->pClass->registerCallback(_loKitDocument, myCallback, this);
-
- return true;
-}
-
-void ChildProcessSession::sendFontRendering(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens)
-{
- std::string font, decodedFont;
- int width, height;
- unsigned char *pixmap;
-
- if (tokens.count() < 2 ||
- !getTokenString(tokens[1], "font", font))
- {
- sendTextFrame("error: cmd=renderfont kind=syntax");
- return;
- }
-
- URI::decode(font, decodedFont);
- std::string response = "renderfont: " + Poco::cat(std::string(" "), tokens.begin() + 1, tokens.end()) + "\n";
-
- std::vector<char> output;
- output.resize(response.size());
- std::memcpy(output.data(), response.data(), response.size());
-
- Poco::Timestamp timestamp;
- pixmap = _loKitDocument->pClass->renderFont(_loKitDocument, decodedFont.c_str(), &width, &height);
- std::cout << Util::logPrefix() << "renderFont called, font[" << font << "] rendered in " << double(timestamp.elapsed())/1000 << "ms" << std::endl;
-
- if (pixmap != nullptr) {
- if (!Util::encodePNGAndAppendToBuffer(pixmap, width, height, output, LOK_TILEMODE_RGBA))
- {
- sendTextFrame("error: cmd=renderfont kind=failure");
- delete[] pixmap;
- return;
- }
- delete[] pixmap;
- }
-
- sendBinaryFrame(output.data(), output.size());
-}
-
-bool ChildProcessSession::getStatus(const char* /*buffer*/, int /*length*/)
-{
- std::string status = "status: " + LOKitHelper::documentStatus(_loKitDocument);
- StringTokenizer tokens(status, " ", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM);
- if (!getTokenString(tokens[1], "type", _docType))
- {
- Application::instance().logger().information(Util::logPrefix() + "failed to get document type from" + status);
- }
- sendTextFrame(status);
-
- return true;
-}
-
-bool ChildProcessSession::getCommandValues(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens)
-{
- std::string command;
- if (tokens.count() != 2 || !getTokenString(tokens[1], "command", command))
- {
- sendTextFrame("error: cmd=commandvalues kind=syntax");
- return false;
- }
- sendTextFrame("commandvalues: " + std::string(_loKitDocument->pClass->getCommandValues(_loKitDocument, command.c_str())));
- return true;
-}
-
-bool ChildProcessSession::getPartPageRectangles(const char* /*buffer*/, int /*length*/)
-{
- sendTextFrame("partpagerectangles: " + std::string(_loKitDocument->pClass->getPartPageRectangles(_loKitDocument)));
- return true;
-}
-
-void ChildProcessSession::sendTile(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens)
-{
- int part, width, height, tilePosX, tilePosY, tileWidth, tileHeight;
-
- if (tokens.count() < 8 ||
- !getTokenInteger(tokens[1], "part", part) ||
- !getTokenInteger(tokens[2], "width", width) ||
- !getTokenInteger(tokens[3], "height", height) ||
- !getTokenInteger(tokens[4], "tileposx", tilePosX) ||
- !getTokenInteger(tokens[5], "tileposy", tilePosY) ||
- !getTokenInteger(tokens[6], "tilewidth", tileWidth) ||
- !getTokenInteger(tokens[7], "tileheight", tileHeight))
- {
- sendTextFrame("error: cmd=tile kind=syntax");
- return;
- }
-
- if (part < 0 ||
- width <= 0 ||
- height <= 0 ||
- tilePosX < 0 ||
- tilePosY < 0 ||
- tileWidth <= 0 ||
- tileHeight <= 0)
- {
- sendTextFrame("error: cmd=tile kind=invalid");
- return;
- }
-
- std::string response = "tile: " + Poco::cat(std::string(" "), tokens.begin() + 1, tokens.end()) + "\n";
-
- std::vector<char> output;
- output.reserve(4 * width * height);
- output.resize(response.size());
- std::memcpy(output.data(), response.data(), response.size());
-
- unsigned char *pixmap = new unsigned char[4 * width * height];
- memset(pixmap, 0, 4 * width * height);
-
- if (_docType != "text" && part != _loKitDocument->pClass->getPart(_loKitDocument))
- {
- _loKitDocument->pClass->setPart(_loKitDocument, part);
- }
-
- Poco::Timestamp timestamp;
- _loKitDocument->pClass->paintTile(_loKitDocument, pixmap, width, height, tilePosX, tilePosY, tileWidth, tileHeight);
- std::cout << Util::logPrefix() << "paintTile called, tile at [" << tilePosX << ", " << tilePosY << "] rendered in " << double(timestamp.elapsed())/1000 << "ms" << std::endl;
-
- LibreOfficeKitTileMode mode = static_cast<LibreOfficeKitTileMode>(_loKitDocument->pClass->getTileMode(_loKitDocument));
- if (!Util::encodePNGAndAppendToBuffer(pixmap, width, height, output, mode))
- {
- sendTextFrame("error: cmd=tile kind=failure");
- return;
- }
-
- delete[] pixmap;
-
- sendBinaryFrame(output.data(), output.size());
-}
-
-bool ChildProcessSession::clientZoom(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens)
-{
- int tilePixelWidth, tilePixelHeight, tileTwipWidth, tileTwipHeight;
-
- if (tokens.count() != 5 ||
- !getTokenInteger(tokens[1], "tilepixelwidth", tilePixelWidth) ||
- !getTokenInteger(tokens[2], "tilepixelheight", tilePixelHeight) ||
- !getTokenInteger(tokens[3], "tiletwipwidth", tileTwipWidth) ||
- !getTokenInteger(tokens[4], "tiletwipheight", tileTwipHeight))
- {
- sendTextFrame("error: cmd=clientzoom kind=syntax");
- return false;
- }
-
- _loKitDocument->pClass->setClientZoom(_loKitDocument, tilePixelWidth, tilePixelHeight, tileTwipWidth, tileTwipHeight);
- return true;
-}
-bool ChildProcessSession::downloadAs(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens)
-{
- std::string name, id, format, filterOptions;
-
- if (tokens.count() < 5 ||
- !getTokenString(tokens[1], "name", name) ||
- !getTokenString(tokens[2], "id", id))
- {
- sendTextFrame("error: cmd=downloadas kind=syntax");
- return false;
- }
-
- getTokenString(tokens[3], "format", format);
-
- if (getTokenString(tokens[4], "options", filterOptions))
- {
- if (tokens.count() > 5)
- {
- filterOptions += Poco::cat(std::string(" "), tokens.begin() + 5, tokens.end());
- }
- }
-
- std::string tmpDir, url;
- File *file = NULL;
- do
- {
- if (file != NULL)
- {
- delete file;
- }
- tmpDir = std::to_string((((Poco::UInt64)LOOLWSD::_rng.next()) << 32) | LOOLWSD::_rng.next() | 1);
- url = jailDocumentURL + "/" + tmpDir + "/" + name;
- file = new File(url);
- } while (file->exists());
- delete file;
-
- _loKitDocument->pClass->saveAs(_loKitDocument, url.c_str(),
- format.size() == 0 ? NULL :format.c_str(),
- filterOptions.size() == 0 ? NULL : filterOptions.c_str());
-
- sendTextFrame("downloadas: jail=" + _childId + " dir=" + tmpDir + " name=" + name +
- " port=" + std::to_string(LOOLWSD::portNumber) + " id=" + id);
- return true;
-}
-
-bool ChildProcessSession::getChildId()
-{
- sendTextFrame("getchildid: id=" + _childId);
- return true;
-}
-
-bool ChildProcessSession::getTextSelection(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens)
-{
- std::string mimeType;
-
- if (tokens.count() != 2 ||
- !getTokenString(tokens[1], "mimetype", mimeType))
- {
- sendTextFrame("error: cmd=gettextselection kind=syntax");
- return false;
- }
-
- char *textSelection = _loKitDocument->pClass->getTextSelection(_loKitDocument, mimeType.c_str(), NULL);
-
- sendTextFrame("textselectioncontent: " + std::string(textSelection));
- return true;
-}
-
-bool ChildProcessSession::paste(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens)
-{
- std::string mimeType;
- std::string data;
-
- if (tokens.count() < 3 || !getTokenString(tokens[1], "mimetype", mimeType) || !getTokenString(tokens[2], "data", data))
- {
- sendTextFrame("error: cmd=paste kind=syntax");
- return false;
- }
-
- data = Poco::cat(std::string(" "), tokens.begin() + 2, tokens.end()).substr(strlen("data="));
-
- _loKitDocument->pClass->paste(_loKitDocument, mimeType.c_str(), data.c_str(), std::strlen(data.c_str()));
-
- return true;
-}
-
-bool ChildProcessSession::insertFile(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens)
-{
- std::string name, type;
-
- if (tokens.count() != 3 ||
- !getTokenString(tokens[1], "name", name) ||
- !getTokenString(tokens[2], "type", type))
- {
- sendTextFrame("error: cmd=insertfile kind=syntax");
- return false;
- }
-
- if (type == "graphic")
- {
- std::string fileName = "file://" + jailDocumentURL + "/insertfile/" + name;
- std::string command = ".uno:InsertGraphic";
- std::string arguments = "{"
- "\"FileName\":{"
- "\"type\":\"string\","
- "\"value\":\"" + fileName + "\""
- "}}";
- _loKitDocument->pClass->postUnoCommand(_loKitDocument, command.c_str(), arguments.c_str(), false);
- }
-
- return true;
-}
-
-bool ChildProcessSession::keyEvent(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens)
-{
- int type, charcode, keycode;
-
- if (tokens.count() != 4 ||
- !getTokenKeyword(tokens[1], "type",
- {{"input", LOK_KEYEVENT_KEYINPUT}, {"up", LOK_KEYEVENT_KEYUP}},
- type) ||
- !getTokenInteger(tokens[2], "char", charcode) ||
- !getTokenInteger(tokens[3], "key", keycode))
- {
- sendTextFrame("error: cmd=key kind=syntax");
- return false;
- }
-
- _loKitDocument->pClass->postKeyEvent(_loKitDocument, type, charcode, keycode);
-
- return true;
-}
-
-bool ChildProcessSession::mouseEvent(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens)
-{
- int type, x, y, count, buttons, modifier;
-
- if (tokens.count() != 7 ||
- !getTokenKeyword(tokens[1], "type",
- {{"buttondown", LOK_MOUSEEVENT_MOUSEBUTTONDOWN},
- {"buttonup", LOK_MOUSEEVENT_MOUSEBUTTONUP},
- {"move", LOK_MOUSEEVENT_MOUSEMOVE}},
- type) ||
- !getTokenInteger(tokens[2], "x", x) ||
- !getTokenInteger(tokens[3], "y", y) ||
- !getTokenInteger(tokens[4], "count", count) ||
- !getTokenInteger(tokens[5], "buttons", buttons) ||
- !getTokenInteger(tokens[6], "modifier", modifier))
- {
- sendTextFrame("error: cmd=mouse kind=syntax");
- return false;
- }
-
- _loKitDocument->pClass->postMouseEvent(_loKitDocument, type, x, y, count, buttons, modifier);
-
- return true;
-}
-
-bool ChildProcessSession::unoCommand(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens)
-{
- if (tokens.count() == 1)
- {
- sendTextFrame("error: cmd=uno kind=syntax");
- return false;
- }
-
- // we need to get LOK_CALLBACK_UNO_COMMAND_RESULT callback when saving
- bool bNotify = (tokens[1] == ".uno:Save");
-
- if (tokens.count() == 2)
- {
- _loKitDocument->pClass->postUnoCommand(_loKitDocument, tokens[1].c_str(), 0, bNotify);
- }
- else
- {
- _loKitDocument->pClass->postUnoCommand(_loKitDocument, tokens[1].c_str(), Poco::cat(std::string(" "), tokens.begin() + 2, tokens.end()).c_str(), bNotify);
- }
-
- return true;
-}
-
-bool ChildProcessSession::selectText(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens)
-{
- int type, x, y;
-
- if (tokens.count() != 4 ||
- !getTokenKeyword(tokens[1], "type",
- {{"start", LOK_SETTEXTSELECTION_START},
- {"end", LOK_SETTEXTSELECTION_END},
- {"reset", LOK_SETTEXTSELECTION_RESET}},
- type) ||
- !getTokenInteger(tokens[2], "x", x) ||
- !getTokenInteger(tokens[3], "y", y))
- {
- sendTextFrame("error: cmd=selecttext kind=syntax");
- return false;
- }
-
- _loKitDocument->pClass->setTextSelection(_loKitDocument, type, x, y);
-
- return true;
-}
-
-bool ChildProcessSession::selectGraphic(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens)
-{
- int type, x, y;
-
- if (tokens.count() != 4 ||
- !getTokenKeyword(tokens[1], "type",
- {{"start", LOK_SETGRAPHICSELECTION_START},
- {"end", LOK_SETGRAPHICSELECTION_END}},
- type) ||
- !getTokenInteger(tokens[2], "x", x) ||
- !getTokenInteger(tokens[3], "y", y))
- {
- sendTextFrame("error: cmd=selectgraphic kind=syntax");
- return false;
- }
-
- _loKitDocument->pClass->setGraphicSelection(_loKitDocument, type, x, y);
-
- return true;
-}
-
-bool ChildProcessSession::resetSelection(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens)
-{
- if (tokens.count() != 1)
- {
- sendTextFrame("error: cmd=resetselection kind=syntax");
- return false;
- }
-
- _loKitDocument->pClass->resetSelection(_loKitDocument);
-
- return true;
-}
-
-bool ChildProcessSession::saveAs(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens)
-{
- std::string url, format, filterOptions;
-
- if (tokens.count() < 4 ||
- !getTokenString(tokens[1], "url", url))
- {
- sendTextFrame("error: cmd=saveas kind=syntax");
- return false;
- }
-
- getTokenString(tokens[2], "format", format);
-
- if (getTokenString(tokens[3], "options", filterOptions))
- {
- if (tokens.count() > 4)
- {
- filterOptions += Poco::cat(std::string(" "), tokens.begin() + 4, tokens.end());
- }
- }
-
- bool success = _loKitDocument->pClass->saveAs(_loKitDocument, url.c_str(),
- format.size() == 0 ? NULL :format.c_str(),
- filterOptions.size() == 0 ? NULL : filterOptions.c_str());
-
- sendTextFrame("saveas: url=" + url);
- std::string successStr = success ? "true" : "false";
- sendTextFrame("unocommandresult: {"
- "\"commandName\":\"saveas\","
- "\"success\":\"" + successStr + "\"}");
-
- return true;
-}
-
-bool ChildProcessSession::setClientPart(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens)
-{
- if (tokens.count() < 2 ||
- !getTokenInteger(tokens[1], "part", _clientPart))
- {
- return false;
- }
- return true;
-}
-
-bool ChildProcessSession::setPage(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens)
-{
- int page;
- if (tokens.count() < 2 ||
- !getTokenInteger(tokens[1], "page", page))
- {
- sendTextFrame("error: cmd=setpage kind=invalid");
- return false;
- }
- _loKitDocument->pClass->setPart(_loKitDocument, page);
- return true;
-}
-
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/loolwsd/LOOLSession.hpp b/loolwsd/LOOLSession.hpp
index 8b7175c..22a372f 100644
--- a/loolwsd/LOOLSession.hpp
+++ b/loolwsd/LOOLSession.hpp
@@ -106,54 +106,6 @@ inline std::basic_ostream<charT, traits> & operator <<(std::basic_ostream<charT,
}
}
-class ChildProcessSession final : public LOOLSession
-{
-public:
- ChildProcessSession(std::shared_ptr<Poco::Net::WebSocket> ws, LibreOfficeKit *loKit, std::string _childId);
- virtual ~ChildProcessSession();
-
- virtual bool handleInput(const char *buffer, int length) override;
-
- virtual bool getStatus(const char *buffer, int length);
-
- virtual bool getCommandValues(const char *buffer, int length, Poco::StringTokenizer& tokens);
-
- virtual bool getPartPageRectangles(const char *buffer, int length) override;
-
- LibreOfficeKitDocument *_loKitDocument;
- std::string _docType;
-
- protected:
- virtual bool loadDocument(const char *buffer, int length, Poco::StringTokenizer& tokens) override;
-
- virtual void sendTile(const char *buffer, int length, Poco::StringTokenizer& tokens);
-
- virtual void sendFontRendering(const char *buffer, int length, Poco::StringTokenizer& tokens);
-
- bool clientZoom(const char *buffer, int length, Poco::StringTokenizer& tokens);
- bool downloadAs(const char *buffer, int length, Poco::StringTokenizer& tokens);
- bool getChildId();
- bool getTextSelection(const char *buffer, int length, Poco::StringTokenizer& tokens);
- bool paste(const char *buffer, int length, Poco::StringTokenizer& tokens);
- bool insertFile(const char *buffer, int length, Poco::StringTokenizer& tokens);
- bool keyEvent(const char *buffer, int length, Poco::StringTokenizer& tokens);
- bool mouseEvent(const char *buffer, int length, Poco::StringTokenizer& tokens);
- bool unoCommand(const char *buffer, int length, Poco::StringTokenizer& tokens);
- bool selectText(const char *buffer, int length, Poco::StringTokenizer& tokens);
- bool selectGraphic(const char *buffer, int length, Poco::StringTokenizer& tokens);
- bool resetSelection(const char *buffer, int length, Poco::StringTokenizer& tokens);
- bool saveAs(const char *buffer, int length, Poco::StringTokenizer& tokens);
- bool setClientPart(const char *buffer, int length, Poco::StringTokenizer& tokens);
- bool setPage(const char *buffer, int length, Poco::StringTokenizer& tokens);
-
- std::string _loSubPath;
- LibreOfficeKit *_loKit;
- std::string _childId;
-
- private:
- int _clientPart;
-};
-
#endif
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/loolwsd/LOOLWSD.cpp b/loolwsd/LOOLWSD.cpp
index 42aa0b4..b89fb9c 100644
--- a/loolwsd/LOOLWSD.cpp
+++ b/loolwsd/LOOLWSD.cpp
@@ -106,6 +106,7 @@ DEALINGS IN THE SOFTWARE.
#include "LOOLProtocol.hpp"
#include "LOOLSession.hpp"
#include "MasterProcessSession.hpp"
+#include "ChildProcessSession.hpp"
#include "LOOLWSD.hpp"
#include "MessageQueue.hpp"
#include "Util.hpp"
diff --git a/loolwsd/Makefile.am b/loolwsd/Makefile.am
index 3a81c34..e34292f 100644
--- a/loolwsd/Makefile.am
+++ b/loolwsd/Makefile.am
@@ -7,7 +7,7 @@ dist_bin_SCRIPTS = loolwsd-systemplate-setup
AM_CPPFLAGS = -pthread
AM_LDFLAGS = -pthread
-loolwsd_SOURCES = LOOLWSD.cpp LOOLSession.cpp MasterProcessSession.cpp MessageQueue.cpp TileCache.cpp Util.cpp LOOLProtocol.cpp
+loolwsd_SOURCES = LOOLWSD.cpp LOOLSession.cpp MasterProcessSession.cpp ChildProcessSession.cpp MessageQueue.cpp TileCache.cpp Util.cpp LOOLProtocol.cpp
noinst_PROGRAMS = loadtest connect lokitclient
@@ -17,7 +17,7 @@ connect_SOURCES = Connect.cpp Util.cpp LOOLProtocol.cpp
lokitclient_SOURCES = LOKitClient.cpp Util.cpp
-noinst_HEADERS = LOKitHelper.hpp LOOLProtocol.hpp LOOLSession.hpp MasterProcessSession.hpp LOOLWSD.hpp LoadTest.hpp MessageQueue.hpp TileCache.hpp Util.hpp Png.hpp \
+noinst_HEADERS = LOKitHelper.hpp LOOLProtocol.hpp LOOLSession.hpp MasterProcessSession.hpp ChildProcessSession.hpp LOOLWSD.hpp LoadTest.hpp MessageQueue.hpp TileCache.hpp Util.hpp Png.hpp \
bundled/include/LibreOfficeKit/LibreOfficeKit.h bundled/include/LibreOfficeKit/LibreOfficeKitEnums.h \
bundled/include/LibreOfficeKit/LibreOfficeKitInit.h bundled/include/LibreOfficeKit/LibreOfficeKitTypes.h
More information about the Libreoffice-commits
mailing list