loolwsd/LOOLSession.cpp | 75 ++++++++++++++++++++++++++++++++------------ loolwsd/LOOLSession.hpp | 9 +++++ loolwsd/LOOLWSD.cpp | 81 +++++++++++++++++++++++++++++++++++++----------- loolwsd/LoadTest.cpp | 2 - loolwsd/Makefile.am | 3 - loolwsd/configure.ac | 2 - loolwsd/protocol.txt | 5 ++ 7 files changed, 136 insertions(+), 41 deletions(-)
New commits: commit 95a29c2a2bc57f641d23c3773ac073f5fe2168da Author: Miklos Vajna <[email protected]> Date: Tue Oct 20 15:41:42 2015 +0200 loolwsd convert-to: implement actual conversion (cherry picked from commit 8f90c38844ba6840acd97c6a72eb104d1171dc8d) diff --git a/loolwsd/LOOLWSD.cpp b/loolwsd/LOOLWSD.cpp index c945251..c241e08 100644 --- a/loolwsd/LOOLWSD.cpp +++ b/loolwsd/LOOLWSD.cpp @@ -252,7 +252,27 @@ public: if (!fromPath.empty() && !format.empty()) { - // TODO implement actual conversion + // Load the document. + std::shared_ptr<WebSocket> ws; + LOOLSession::Kind kind = LOOLSession::Kind::ToClient; + std::shared_ptr<MasterProcessSession> session(new MasterProcessSession(ws, kind)); + const std::string filePrefix("file://"); + std::string load = "load url=" + filePrefix + fromPath; + session->handleInput(load.data(), load.size()); + + // Convert it to the requested format. + Path toPath(fromPath); + toPath.setExtension(format); + std::string toJailURL = filePrefix + LOOLSession::jailDocumentURL + Path::separator() + toPath.getFileName(); + std::string saveas = "saveas url=" + toJailURL + " format=" + format + " options="; + session->handleInput(saveas.data(), saveas.size()); + std::string toURL = session->getSaveAs(); + + // Send it back to the client. + std::string mimeType = "application/octet-stream"; + if (toURL.find(filePrefix) == 0) + toURL = toURL.substr(filePrefix.length()); + response.sendFile(toURL, mimeType); } else { commit 9df7529493c449f8c94645a29f1deb455b4ee264 Author: Miklos Vajna <[email protected]> Date: Tue Oct 20 15:35:43 2015 +0200 loolwsd convert-to: clean up temp directory in case format would be empty (cherry picked from commit 355362f5198da3b51539b77d5d9a03fd451f3cbe) diff --git a/loolwsd/LOOLWSD.cpp b/loolwsd/LOOLWSD.cpp index 21256be..c945251 100644 --- a/loolwsd/LOOLWSD.cpp +++ b/loolwsd/LOOLWSD.cpp @@ -253,15 +253,18 @@ public: if (!fromPath.empty() && !format.empty()) { // TODO implement actual conversion - - Path tempDirectory(fromPath); - tempDirectory.setFileName(""); - File(tempDirectory).remove(/*recursive=*/true); + } + else + { + response.setStatus(HTTPResponse::HTTP_BAD_REQUEST); + response.setContentLength(0); + response.send(); } - response.setStatus(HTTPResponse::HTTP_OK); - response.setContentLength(0); - response.send(); + // Clean up the temporary directory the HTMLForm ctor created. + Path tempDirectory(fromPath); + tempDirectory.setFileName(""); + File(tempDirectory).remove(/*recursive=*/true); } else if (tokens.count() >= 4) { commit 2e0bc2af09bf5565382f57ae40e2f4a1f8215181 Author: Miklos Vajna <[email protected]> Date: Tue Oct 20 15:00:05 2015 +0200 LOOLWSD: put file we get from convert-to to a temp. dir Having a URL like file:///tmp/tmp13630baaaaa/test.txt allows retaining the filename given by the user and still work with a URL. We could try carrying around a memory buffer, but we would still have to send it over the WS, so it's easier if we always work with URLs instead. (cherry picked from commit cdc0783c27a4b2b36c1f5ffc972f618be33f1ed7) diff --git a/loolwsd/LOOLWSD.cpp b/loolwsd/LOOLWSD.cpp index b37c1b3..21256be 100644 --- a/loolwsd/LOOLWSD.cpp +++ b/loolwsd/LOOLWSD.cpp @@ -98,6 +98,8 @@ DEALINGS IN THE SOFTWARE. #include <Poco/ThreadLocal.h> #include <Poco/NamedMutex.h> #include <Poco/FileStream.h> +#include <Poco/TemporaryFile.h> +#include <Poco/StreamCopier.h> #include "LOOLProtocol.hpp" @@ -183,16 +185,15 @@ private: class ConvertToPartHandler : public Poco::Net::PartHandler { std::string& _filename; - std::vector<char>& _buffer; public: - ConvertToPartHandler(std::string& filename, std::vector<char>& buffer) - : _filename(filename), - _buffer(buffer) + ConvertToPartHandler(std::string& filename) + : _filename(filename) { } virtual void handlePart(const Poco::Net::MessageHeader& header, std::istream& stream) override { + // Extract filename and put it to a temporary directory. std::string disp; Poco::Net::NameValueCollection params; if (header.has("Content-Disposition")) @@ -200,12 +201,19 @@ public: std::string cd = header.get("Content-Disposition"); Poco::Net::MessageHeader::splitParameters(cd, disp, params); } - if (params.has("filename")) - _filename = params.get("filename"); + if (!params.has("filename")) + return; + + Path tempPath = Path::forDirectory(Poco::TemporaryFile().tempName() + Path::separator()); + File(tempPath).createDirectories(); + tempPath.setFileName(params.get("filename")); + _filename = tempPath.toString(); - char c; - while (stream.get(c)) - _buffer.push_back(c); + // Copy the stream to _filename. + std::ofstream fileStream; + fileStream.open(_filename); + Poco::StreamCopier::copyStream(stream, fileStream); + fileStream.close(); } }; @@ -235,17 +243,20 @@ public: StringTokenizer tokens(request.getURI(), "/?"); if (tokens.count() >= 2 && tokens[1] == "convert-to") { - std::string filename; - std::vector<char> buffer; - ConvertToPartHandler handler(filename, buffer); + std::string fromPath; + ConvertToPartHandler handler(fromPath); Poco::Net::HTMLForm form(request, request.stream(), handler); std::string format; if (form.has("format")) format = form.get("format"); - if (!format.empty() && !buffer.empty()) + if (!fromPath.empty() && !format.empty()) { // TODO implement actual conversion + + Path tempDirectory(fromPath); + tempDirectory.setFileName(""); + File(tempDirectory).remove(/*recursive=*/true); } response.setStatus(HTTPResponse::HTTP_OK); commit 738fab56aa4b5bfd56bfa93b4ea1532f2ecfff07 Author: Miklos Vajna <[email protected]> Date: Tue Oct 20 14:44:47 2015 +0200 LOOLSession: handle file:// in the ToPrisoner saveas input handler (cherry picked from commit 847c65cb1c4f80e6a0fbec56715ad857d6b78472) diff --git a/loolwsd/LOOLSession.cpp b/loolwsd/LOOLSession.cpp index 4bee505..15a2825 100644 --- a/loolwsd/LOOLSession.cpp +++ b/loolwsd/LOOLSession.cpp @@ -192,9 +192,19 @@ bool MasterProcessSession::handleInput(const char *buffer, int length) return true; if (peer) + { // Save as completed, inform the other (Kind::ToClient) // MasterProcessSession about it. + + const std::string filePrefix("file:///"); + if (url.find(filePrefix) == 0) + { + // Rewrite file:// URLs, as they are visible to the outside world. + Path path(MasterProcessSession::getJailPath(_childId), url.substr(filePrefix.length())); + url = filePrefix + path.toString().substr(1); + } peer->_saveAsQueue.put(url); + } return true; } commit 32827d684f4c81b604466c3541892ecab6ab60ac Author: Miklos Vajna <[email protected]> Date: Tue Oct 20 14:17:58 2015 +0200 loolwsd: don't try to exclude jails from tags Don't pretend that we know where jails will be, the may be elsewhere. If indexing jails/systemplate is problem, configure them outside the build tree instead. (cherry picked from commit dc56637e1133c7b3c5c45158582755a2d85a32cc) diff --git a/loolwsd/Makefile.am b/loolwsd/Makefile.am index 9e1f143..e0e3fb9 100644 --- a/loolwsd/Makefile.am +++ b/loolwsd/Makefile.am @@ -36,5 +36,4 @@ all-local: loolwsd fi tags: - ctags --c++-kinds=+p --fields=+iaS --extra=+q -R --totals=yes \ - --exclude=jails * + ctags --c++-kinds=+p --fields=+iaS --extra=+q -R --totals=yes * commit 688256f5c59586eb6def9dae45d20ba15761cba0 Author: Miklos Vajna <[email protected]> Date: Tue Oct 20 14:03:31 2015 +0200 LOOLSession: inform to-client session about completed save-as (cherry picked from commit 4feb29d1dfaf05a3c1f15dd05bab443a08211f0f) diff --git a/loolwsd/LOOLSession.cpp b/loolwsd/LOOLSession.cpp index 1f1a2da..4bee505 100644 --- a/loolwsd/LOOLSession.cpp +++ b/loolwsd/LOOLSession.cpp @@ -184,6 +184,20 @@ bool MasterProcessSession::handleInput(const char *buffer, int length) { return true; } + + if (tokens.count() == 2 && tokens[0] == "saveas:") + { + std::string url; + if (!getTokenString(tokens[1], "url", url)) + return true; + + if (peer) + // Save as completed, inform the other (Kind::ToClient) + // MasterProcessSession about it. + peer->_saveAsQueue.put(url); + + return true; + } } if (_kind == Kind::ToPrisoner && peer && peer->_tileCache) @@ -486,6 +500,11 @@ bool MasterProcessSession::getPartPageRectangles(const char *buffer, int length) return true; } +std::string MasterProcessSession::getSaveAs() +{ + return _saveAsQueue.get(); +} + void MasterProcessSession::sendTile(const char *buffer, int length, StringTokenizer& tokens) { int part, width, height, tilePosX, tilePosY, tileWidth, tileHeight; @@ -1204,6 +1223,8 @@ bool ChildProcessSession::saveAs(const char* /*buffer*/, int /*length*/, StringT format.size() == 0 ? NULL :format.c_str(), filterOptions.size() == 0 ? NULL : filterOptions.c_str()); + sendTextFrame("saveas: url=" + url); + return true; } diff --git a/loolwsd/LOOLSession.hpp b/loolwsd/LOOLSession.hpp index 70210ae..85d9d5a 100644 --- a/loolwsd/LOOLSession.hpp +++ b/loolwsd/LOOLSession.hpp @@ -30,6 +30,7 @@ #include <Poco/Types.h> #include "TileCache.hpp" +#include "tsqueue.h" // We have three kinds of Websocket sessions // 1) Between the master loolwsd server to the end-user LOOL client @@ -117,6 +118,12 @@ public: virtual bool getPartPageRectangles(const char *buffer, int length) override; + /** + * Return the URL of the saved-as document when it's ready. If called + * before it's ready, the call blocks till then. + */ + std::string getSaveAs(); + protected: bool invalidateTiles(const char *buffer, int length, Poco::StringTokenizer& tokens); @@ -151,6 +158,8 @@ private: static std::mutex _rngMutex; int _curPart; int _loadPart; + /// Kind::ToClient instances store URLs of completed 'save as' documents. + tsqueue<std::string> _saveAsQueue; }; class ChildProcessSession final : public LOOLSession diff --git a/loolwsd/protocol.txt b/loolwsd/protocol.txt index bc7c453..ede153d 100644 --- a/loolwsd/protocol.txt +++ b/loolwsd/protocol.txt @@ -181,3 +181,8 @@ nextmessage: size=<upperlimit> messages that can be "large".) Once we depend on Poco 1.6.1, where one doesn't need to use a pre-allocated buffer when receiving WebSocket messages, this will go away. + +saveas: url=<url> + + <url> is a URL of the destination, encoded. Sent from the child to the + parent after a saveAs() completed. commit 8be342d1da29390be1849430837bcfdb97f72c43 Author: Miklos Vajna <[email protected]> Date: Mon Oct 19 16:03:16 2015 +0200 loolwsd: extraft filename from convert-to parameters (cherry picked from commit cc18cc702f1de1dc2d133c81a0595f7ecf73517c) diff --git a/loolwsd/LOOLWSD.cpp b/loolwsd/LOOLWSD.cpp index 89bc579..b37c1b3 100644 --- a/loolwsd/LOOLWSD.cpp +++ b/loolwsd/LOOLWSD.cpp @@ -182,15 +182,27 @@ private: /// Handles the filename part of the convert-to POST request payload. class ConvertToPartHandler : public Poco::Net::PartHandler { + std::string& _filename; std::vector<char>& _buffer; public: - ConvertToPartHandler(std::vector<char>& buffer) - : _buffer(buffer) + ConvertToPartHandler(std::string& filename, std::vector<char>& buffer) + : _filename(filename), + _buffer(buffer) { } - virtual void handlePart(const Poco::Net::MessageHeader& /*header*/, std::istream& stream) override + virtual void handlePart(const Poco::Net::MessageHeader& header, std::istream& stream) override { + std::string disp; + Poco::Net::NameValueCollection params; + if (header.has("Content-Disposition")) + { + std::string cd = header.get("Content-Disposition"); + Poco::Net::MessageHeader::splitParameters(cd, disp, params); + } + if (params.has("filename")) + _filename = params.get("filename"); + char c; while (stream.get(c)) _buffer.push_back(c); @@ -223,8 +235,9 @@ public: StringTokenizer tokens(request.getURI(), "/?"); if (tokens.count() >= 2 && tokens[1] == "convert-to") { + std::string filename; std::vector<char> buffer; - ConvertToPartHandler handler(buffer); + ConvertToPartHandler handler(filename, buffer); Poco::Net::HTMLForm form(request, request.stream(), handler); std::string format; if (form.has("format")) commit 531161dac6652a5d82525fd33cab5cb2193314d0 Author: Miklos Vajna <[email protected]> Date: Mon Oct 19 10:58:21 2015 +0200 LOOLSession: check for 0 _ws (cherry picked from commit f0ba09f3dda980f46bad9c63b0fef5b8078ea99a) diff --git a/loolwsd/LOOLSession.cpp b/loolwsd/LOOLSession.cpp index 3296139..1f1a2da 100644 --- a/loolwsd/LOOLSession.cpp +++ b/loolwsd/LOOLSession.cpp @@ -106,7 +106,8 @@ LOOLSession::LOOLSession(std::shared_ptr<WebSocket> ws, Kind kind) : LOOLSession::~LOOLSession() { std::cout << Util::logPrefix() << "LOOLSession dtor this=" << this << " " << _kind << std::endl; - Util::shutdownWebSocket(*_ws); + if (_ws) + Util::shutdownWebSocket(*_ws); } void LOOLSession::sendTextFrame(const std::string& text) @@ -123,10 +124,12 @@ void LOOLSession::sendBinaryFrame(const char *buffer, int length) if (length > 1000) { std::string nextmessage = "nextmessage: size=" + std::to_string(length); - _ws->sendFrame(nextmessage.data(), nextmessage.size()); + if (_ws) + _ws->sendFrame(nextmessage.data(), nextmessage.size()); } - _ws->sendFrame(buffer, length, WebSocket::FRAME_BINARY); + if (_ws) + _ws->sendFrame(buffer, length, WebSocket::FRAME_BINARY); } std::map<Process::PID, UInt64> MasterProcessSession::_childProcesses; @@ -149,7 +152,8 @@ MasterProcessSession::MasterProcessSession(std::shared_ptr<WebSocket> ws, Kind k MasterProcessSession::~MasterProcessSession() { std::cout << Util::logPrefix() << "MasterProcessSession dtor this=" << this << " _peer=" << _peer.lock().get() << std::endl; - Util::shutdownWebSocket(*_ws); + if (_ws) + Util::shutdownWebSocket(*_ws); auto peer = _peer.lock(); if (_kind == Kind::ToClient && peer) { commit d9ec17d774d73963f0303c821932b988b1485ce2 Author: Miklos Vajna <[email protected]> Date: Fri Oct 16 17:45:03 2015 +0200 loolwsd: -Werror=unused-parameter (cherry picked from commit fed0cbc77c1c103e46105298c4af456a65d514cb) diff --git a/loolwsd/LOOLSession.cpp b/loolwsd/LOOLSession.cpp index c731bd9..3296139 100644 --- a/loolwsd/LOOLSession.cpp +++ b/loolwsd/LOOLSession.cpp @@ -370,7 +370,7 @@ Path MasterProcessSession::getJailPath(UInt64 childId) return Path::forDirectory(LOOLWSD::childRoot + Path::separator() + std::to_string(childId)); } -bool MasterProcessSession::invalidateTiles(const char *buffer, int length, StringTokenizer& tokens) +bool MasterProcessSession::invalidateTiles(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens) { int part, tilePosX, tilePosY, tileWidth, tileHeight; @@ -393,7 +393,7 @@ bool MasterProcessSession::invalidateTiles(const char *buffer, int length, Strin return true; } -bool MasterProcessSession::loadDocument(const char *buffer, int length, StringTokenizer& tokens) +bool MasterProcessSession::loadDocument(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens) { if (tokens.count() < 2 || tokens.count() > 4) { @@ -912,7 +912,7 @@ bool ChildProcessSession::loadDocument(const char *buffer, int length, StringTok return true; } -bool ChildProcessSession::getStatus(const char *buffer, int length) +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); @@ -925,7 +925,7 @@ bool ChildProcessSession::getStatus(const char *buffer, int length) return true; } -bool ChildProcessSession::getCommandValues(const char *buffer, int length, StringTokenizer& tokens) +bool ChildProcessSession::getCommandValues(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens) { std::string command; if (tokens.count() != 2 || !getTokenString(tokens[1], "command", command)) @@ -943,7 +943,7 @@ bool ChildProcessSession::getPartPageRectangles(const char* /*buffer*/, int /*le return true; } -void ChildProcessSession::sendTile(const char *buffer, int length, StringTokenizer& tokens) +void ChildProcessSession::sendTile(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens) { int part, width, height, tilePosX, tilePosY, tileWidth, tileHeight; @@ -996,7 +996,7 @@ void ChildProcessSession::sendTile(const char *buffer, int length, StringTokeniz sendBinaryFrame(output.data(), output.size()); } -bool ChildProcessSession::downloadAs(const char *buffer, int length, StringTokenizer& tokens) +bool ChildProcessSession::downloadAs(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens) { std::string name, id, format, filterOptions; @@ -1039,7 +1039,7 @@ bool ChildProcessSession::downloadAs(const char *buffer, int length, StringToken return true; } -bool ChildProcessSession::getTextSelection(const char *buffer, int length, StringTokenizer& tokens) +bool ChildProcessSession::getTextSelection(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens) { std::string mimeType; @@ -1056,7 +1056,7 @@ bool ChildProcessSession::getTextSelection(const char *buffer, int length, Strin return true; } -bool ChildProcessSession::keyEvent(const char *buffer, int length, StringTokenizer& tokens) +bool ChildProcessSession::keyEvent(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens) { int type, charcode, keycode; @@ -1076,7 +1076,7 @@ bool ChildProcessSession::keyEvent(const char *buffer, int length, StringTokeniz return true; } -bool ChildProcessSession::mouseEvent(const char *buffer, int length, StringTokenizer& tokens) +bool ChildProcessSession::mouseEvent(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens) { int type, x, y, count, buttons, modifier; @@ -1101,7 +1101,7 @@ bool ChildProcessSession::mouseEvent(const char *buffer, int length, StringToken return true; } -bool ChildProcessSession::unoCommand(const char *buffer, int length, StringTokenizer& tokens) +bool ChildProcessSession::unoCommand(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens) { if (tokens.count() == 1) { @@ -1121,7 +1121,7 @@ bool ChildProcessSession::unoCommand(const char *buffer, int length, StringToken return true; } -bool ChildProcessSession::selectText(const char *buffer, int length, StringTokenizer& tokens) +bool ChildProcessSession::selectText(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens) { int type, x, y; @@ -1143,7 +1143,7 @@ bool ChildProcessSession::selectText(const char *buffer, int length, StringToken return true; } -bool ChildProcessSession::selectGraphic(const char *buffer, int length, StringTokenizer& tokens) +bool ChildProcessSession::selectGraphic(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens) { int type, x, y; @@ -1164,7 +1164,7 @@ bool ChildProcessSession::selectGraphic(const char *buffer, int length, StringTo return true; } -bool ChildProcessSession::resetSelection(const char *buffer, int length, StringTokenizer& tokens) +bool ChildProcessSession::resetSelection(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens) { if (tokens.count() != 1) { @@ -1177,7 +1177,7 @@ bool ChildProcessSession::resetSelection(const char *buffer, int length, StringT return true; } -bool ChildProcessSession::saveAs(const char *buffer, int length, StringTokenizer& tokens) +bool ChildProcessSession::saveAs(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens) { std::string url, format, filterOptions; @@ -1203,7 +1203,7 @@ bool ChildProcessSession::saveAs(const char *buffer, int length, StringTokenizer return true; } -bool ChildProcessSession::setClientPart(const char *buffer, int length, StringTokenizer& tokens) +bool ChildProcessSession::setClientPart(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens) { if (tokens.count() < 2 || !getTokenInteger(tokens[1], "part", _clientPart)) @@ -1213,7 +1213,7 @@ bool ChildProcessSession::setClientPart(const char *buffer, int length, StringTo return true; } -bool ChildProcessSession::setPage(const char *buffer, int length, StringTokenizer& tokens) +bool ChildProcessSession::setPage(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens) { int page; if (tokens.count() < 2 || diff --git a/loolwsd/LOOLWSD.cpp b/loolwsd/LOOLWSD.cpp index 4b2e9c8..89bc579 100644 --- a/loolwsd/LOOLWSD.cpp +++ b/loolwsd/LOOLWSD.cpp @@ -656,9 +656,9 @@ namespace ThreadLocal<Path> destinationForLinkOrCopy; int linkOrCopyFunction(const char *fpath, - const struct stat *sb, + const struct stat* /*sb*/, int typeflag, - struct FTW *ftwbuf) + struct FTW* /*ftwbuf*/) { if (strcmp(fpath, sourceForLinkOrCopy->c_str()) == 0) return 0; @@ -1115,7 +1115,7 @@ void LOOLWSD::startupDesktop(int nDesktops) } } -int LOOLWSD::main(const std::vector<std::string>& args) +int LOOLWSD::main(const std::vector<std::string>& /*args*/) { #ifdef __linux char *locale = setlocale(LC_ALL, NULL); diff --git a/loolwsd/LoadTest.cpp b/loolwsd/LoadTest.cpp index b146ed2..a1f0442 100644 --- a/loolwsd/LoadTest.cpp +++ b/loolwsd/LoadTest.cpp @@ -367,7 +367,7 @@ void LoadTest::displayHelp() helpFormatter.format(std::cout); } -int LoadTest::main(const std::vector<std::string>& args) +int LoadTest::main(const std::vector<std::string>& /*args*/) { Thread *clients[_numClients]; diff --git a/loolwsd/configure.ac b/loolwsd/configure.ac index 87af596..50a5edd 100644 --- a/loolwsd/configure.ac +++ b/loolwsd/configure.ac @@ -57,7 +57,7 @@ AS_IF([test "$enable_debug" = yes], # Test for build environment CXXFLAGS="$CXXFLAGS -std=c++11" -CXXFLAGS="$CXXFLAGS -Wall -Werror" +CXXFLAGS="$CXXFLAGS -Wall -Wextra -Werror" AS_IF([test -n "$with_lokit_path"], [CPPFLAGS="$CPPFLAGS -I${with_lokit_path}"]) _______________________________________________ Libreoffice-commits mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits
