From 550d3be172da62544f707191fb04f5a866b78252 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 14 Oct 2024 14:10:51 +0200 Subject: [PATCH 001/177] coda-m: Initial macOS app Introduces the Xcode project, README, ./configure changes, and various build fixes all around the place. Signed-off-by: Jan Holesovsky Change-Id: Idbb4529bb842c7dc4b591de0f6d3943ca70dba33 --- .gitignore | 2 + common/FileUtil-unix.cpp | 4 +- common/FileUtil.cpp | 2 +- common/FileUtil.hpp | 2 +- common/SigUtil-server.cpp | 2 +- configure.ac | 43 +- kit/DeltaSimd.c | 6 +- macos/README.txt | 57 ++ macos/coda/.gitignore | 2 + macos/coda/Config.xcconfig.in | 14 + macos/coda/coda-Bridging-Header.h | 4 + macos/coda/coda.xcodeproj/project.pbxproj | 838 ++++++++++++++++++ macos/coda/coda/AppDelegate.swift | 30 + .../AccentColor.colorset/Contents.json | 11 + .../AppIcon.appiconset/Contents.json | 58 ++ macos/coda/coda/Assets.xcassets/Contents.json | 6 + macos/coda/coda/Base.lproj/Main.storyboard | 717 +++++++++++++++ macos/coda/coda/ViewController.swift | 26 + macos/coda/coda/coda.entitlements | 12 + macos/coda/coda/macos.h | 20 + macos/coda/coda/macos.mm | 18 + macos/coda/codaTests/codaTests.swift | 17 + macos/coda/codaUITests/codaUITests.swift | 43 + .../codaUITests/codaUITestsLaunchTests.swift | 33 + macos/coda/config.h.in | 135 +++ wsd/PlatformMobile.hpp | 2 + wsd/Storage.cpp | 2 + 27 files changed, 2093 insertions(+), 13 deletions(-) create mode 100644 macos/README.txt create mode 100644 macos/coda/.gitignore create mode 100644 macos/coda/Config.xcconfig.in create mode 100644 macos/coda/coda-Bridging-Header.h create mode 100644 macos/coda/coda.xcodeproj/project.pbxproj create mode 100644 macos/coda/coda/AppDelegate.swift create mode 100644 macos/coda/coda/Assets.xcassets/AccentColor.colorset/Contents.json create mode 100644 macos/coda/coda/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 macos/coda/coda/Assets.xcassets/Contents.json create mode 100644 macos/coda/coda/Base.lproj/Main.storyboard create mode 100644 macos/coda/coda/ViewController.swift create mode 100644 macos/coda/coda/coda.entitlements create mode 100644 macos/coda/coda/macos.h create mode 100644 macos/coda/coda/macos.mm create mode 100644 macos/coda/codaTests/codaTests.swift create mode 100644 macos/coda/codaUITests/codaUITests.swift create mode 100644 macos/coda/codaUITests/codaUITestsLaunchTests.swift create mode 100644 macos/coda/config.h.in diff --git a/.gitignore b/.gitignore index 84676ed5f330d..a329713cc0eb8 100644 --- a/.gitignore +++ b/.gitignore @@ -45,6 +45,8 @@ debian/coolwsd.postinst common/support-public-key.hpp compile_commands.json **/gdb.txt +macos/coda/config.h +macos/coda/Config.xcconfig # Test stuff systemplate diff --git a/common/FileUtil-unix.cpp b/common/FileUtil-unix.cpp index 3eec3050339d8..06e5f87e87ccf 100644 --- a/common/FileUtil-unix.cpp +++ b/common/FileUtil-unix.cpp @@ -460,14 +460,14 @@ namespace FileUtil { { tsAccess.tv_sec, -#ifdef IOS +#if defined(IOS) || defined(MACOS) (__darwin_suseconds_t) #endif (tsAccess.tv_nsec / 1000) }, { tsModified.tv_sec, -#ifdef IOS +#if defined(IOS) || defined(MACOS) (__darwin_suseconds_t) #endif (tsModified.tv_nsec / 1000) diff --git a/common/FileUtil.cpp b/common/FileUtil.cpp index fe3a4a73f229d..1beabe3cdfed0 100644 --- a/common/FileUtil.cpp +++ b/common/FileUtil.cpp @@ -177,7 +177,7 @@ namespace FileUtil { const Stat st(fromPath); updateTimestamps(randFilename, -#ifdef IOS +#if defined(IOS) || defined(MACOS) st.sb().st_atimespec, st.sb().st_mtimespec #else st.sb().st_atim, st.sb().st_mtim diff --git a/common/FileUtil.hpp b/common/FileUtil.hpp index 0e66b4f960616..a044db8fb7ae6 100644 --- a/common/FileUtil.hpp +++ b/common/FileUtil.hpp @@ -267,7 +267,7 @@ namespace FileUtil /// nanosecond precision, if/when the filesystem supports it. timespec modifiedTime() const { -#ifdef IOS +#if defined(IOS) || defined(MACOS) return _sb.st_mtimespec; #else return _sb.st_mtim; diff --git a/common/SigUtil-server.cpp b/common/SigUtil-server.cpp index bc0157446d72a..40404c9903dfd 100644 --- a/common/SigUtil-server.cpp +++ b/common/SigUtil-server.cpp @@ -45,7 +45,7 @@ # include #endif -#if !defined(ANDROID) && !defined(IOS) && !defined(__FreeBSD__) +#if !defined(ANDROID) && !defined(IOS) && !defined(MACOS) && !defined(__FreeBSD__) # include #endif #if defined(__FreeBSD__) diff --git a/configure.ac b/configure.ac index 8c822f4038d84..c0d8f9d68f105 100644 --- a/configure.ac +++ b/configure.ac @@ -142,6 +142,10 @@ AC_ARG_ENABLE([iosapp], AS_HELP_STRING([--enable-iosapp], [Use on a Mac where you will build the iOS app.])) +AC_ARG_ENABLE([macosapp], + AS_HELP_STRING([--enable-macosapp], + [Use on a Mac where you will build the macOS app.])) + AC_ARG_WITH([wasm-fallback], AS_HELP_STRING([--with-wasm-fallback=], [Build a COOL where the client can fall back to a WASM implementation if the connection to the server fails. @@ -872,13 +876,13 @@ fi if test "$enable_iosapp" = "yes" -o "$enable_androidapp" = "yes"; then if test -n "$LIBPNG_INCLUDES" ; then - AC_MSG_ERROR([--with-libpng-includes is ignored on Android, please remove the parameter.]) + AC_MSG_ERROR([--with-libpng-includes is ignored on iOS / Android, please remove the parameter.]) fi if test -n "$LIBPNG_LIBS" ; then - AC_MSG_ERROR([--with-libpng-libs is ignored on Android, please remove the parameter.]) + AC_MSG_ERROR([--with-libpng-libs is ignored on iOS / Android, please remove the parameter.]) fi if test -n "$LOKIT_PATH" ; then - AC_MSG_ERROR([--with-lokit-path is ignored on Android, please remove the parameter.]) + AC_MSG_ERROR([--with-lokit-path is ignored on iOS / Android, please remove the parameter.]) LOKIT_PATH=`readlink -f $LOBUILDDIR/include` fi fi @@ -913,8 +917,8 @@ AC_SUBST(APP_NAME) VENDOR= AC_MSG_CHECKING([for vendor]) -if test "$enable_iosapp" = yes -a -z "$with_vendor"; then - AC_MSG_ERROR([You must use --with-vendor when configuring for the iOS app]) +if test \( "$enable_iosapp" = yes -o "$enable_macosapp" = yes \) -a -z "$with_vendor"; then + AC_MSG_ERROR([You must use --with-vendor when configuring for the iOS / macOS app]) fi if test -z "$with_vendor" -o "$with_vendor" = "no"; then VENDOR="$USERNAME" @@ -960,6 +964,24 @@ AM_CONDITIONAL([ENABLE_IOSAPP], [test "$ENABLE_IOSAPP" = "true"]) AC_SUBST(IOSAPP_BUNDLE_SHORT_VERSION) AC_SUBST(IOSAPP_BUNDLE_VERSION) +ENABLE_MACOSAPP= +#MACOSAPP_BUNDLE_VERSION= + +if test "$enable_macosapp" = "yes"; then + ENABLE_MACOSAPP=true + + #if test -f BUNDLE-VERSION; then + # MACOSAPP_BUNDLE_VERSION=$(cat BUNDLE-VERSION) + #else + # MACOSAPP_BUNDLE_VERSION=1 + #fi + #echo $MACOSAPP_BUNDLE_VERSION >BUNDLE-VERSION +fi + +AC_SUBST(ENABLE_MACOSAPP) +AM_CONDITIONAL([ENABLE_MACOSAPP], [test "$ENABLE_MACOSAPP" = "true"]) +#AC_SUBST(MACOSAPP_BUNDLE_VERSION) + AC_MSG_CHECKING([for custom icon theme]) CUSTOM_ICONS_DIRECTORY= if test -d "$with_icon_theme"; then @@ -1269,7 +1291,7 @@ AS_IF([test -n "$LOKIT_PATH"], [CPPFLAGS="$CPPFLAGS -I${LOKIT_PATH}"]) lokit_msg="$LOKIT_PATH" -AS_IF([test "$ENABLE_IOSAPP" != "true" -a "$ENABLE_ANDROIDAPP" != "true"], +AS_IF([test "$ENABLE_IOSAPP" != "true" -a "$ENABLE_MACOSAPP" != "true" -a "$ENABLE_ANDROIDAPP" != "true"], [AC_MSG_CHECKING([for LibreOffice path]) if test -n "$with_lo_path"; then # strip trailing '/' from LO_PATH, 'ln -s' with such path will otherwise fail @@ -1344,7 +1366,7 @@ AS_IF([test `uname -s` != Darwin], [], [AC_MSG_ERROR([dlopen not found])])]) -AS_IF([test "$ENABLE_IOSAPP" != "true" -a "$ENABLE_ANDROIDAPP" != "true" -a "$host_os" != "emscripten"], +AS_IF([test "$ENABLE_IOSAPP" != "true" -a "$ENABLE_MACOSAPP" != "true" -a "$ENABLE_ANDROIDAPP" != "true" -a "$host_os" != "emscripten"], [PKG_CHECK_MODULES([PNG], [libpng]) dnl deflated HTTP / web-page serving PKG_CHECK_MODULES([ZLIB], [zlib]) @@ -1727,6 +1749,8 @@ AS_IF([test "$ENABLE_IOSAPP" = "true"], ]) AC_SUBST(IOSAPP_FONTS) +# TODO MACOSAPP_FONTS? + AC_CHECK_FUNCS(ppoll) AC_CHECK_FUNCS([memrchr]) @@ -1985,6 +2009,11 @@ if test "$enable_iosapp" = "yes"; then ios/Mobile/Resources/Settings.bundle/Root.plist]) fi +if test "$enable_macosapp" = "yes"; then + AC_CONFIG_FILES([macos/coda/config.h + macos/coda/Config.xcconfig]) +fi + if test "$enable_androidapp" = "yes"; then AC_CONFIG_FILES([ $srcdir/android/variables.gradle:android/variables.gradle.in diff --git a/kit/DeltaSimd.c b/kit/DeltaSimd.c index 6ca34b0fd43a6..489420d64ff30 100644 --- a/kit/DeltaSimd.c +++ b/kit/DeltaSimd.c @@ -20,7 +20,11 @@ #include #include #include -#include +#if defined(MACOS) +# include +#else +# include +#endif #include "DeltaSimd.h" diff --git a/macos/README.txt b/macos/README.txt new file mode 100644 index 0000000000000..25fb7427604d8 --- /dev/null +++ b/macos/README.txt @@ -0,0 +1,57 @@ +Building the CODA-M + +Setup + +* Instal node.js + * brew install node +* Install poco + * brew install poco +* zstd + * brew install zstd +* missing from the iOS build instructions (needed for online.git) + * brew install libtool +* install canvas to avoid error during build + * NB. version 3.0 needed, it upgrades the API to fit the new node.js + * npm install canvas@next + +Build LO + +autogen.input: + + # Distro + --with-distro=CPMacOS-LOKit + + # Overrides for the debug builds + --enable-debug + #--enable-dbgutil + + --enable-werror + --enable-symbols + --without-lang + --without-system-dicts + --without-myspell-dicts + +Configure Collabora Online + + ./autogen.sh && ./configure \ + --enable-macosapp \ + --with-app-name="Collabora Office" \ + --enable-experimental \ + --with-vendor="Collabora Productivity" \ + --with-poco-includes=/opt/homebrew/opt/poco/include \ + --with-poco-libs=/opt/homebrew/opt/poco/lib \ + --with-zstd-includes=/opt/homebrew/include \ + --with-zstd-libs=/opt/homebrew/lib \ + --with-lo-path=/Users/kendy/Projects/lo/core/instdir \ + --with-lokit-path=/Users/kendy/Projects/lo/core/include + +Build Collabora Online + +* ( cd browser ; make ) +* open Xcode's project macos/coda/coda.xcodeproj & build from there + +TODO + +* configure.ac + * add sanity check for the lo builddir when configuring with —enable-macosapp + * MACOSAPP_FONTS diff --git a/macos/coda/.gitignore b/macos/coda/.gitignore new file mode 100644 index 0000000000000..038dcd554e149 --- /dev/null +++ b/macos/coda/.gitignore @@ -0,0 +1,2 @@ +/coda.xcodeproj/project.xcworkspace/ +/coda.xcodeproj/xcuserdata/ diff --git a/macos/coda/Config.xcconfig.in b/macos/coda/Config.xcconfig.in new file mode 100644 index 0000000000000..3e5afc251bde1 --- /dev/null +++ b/macos/coda/Config.xcconfig.in @@ -0,0 +1,14 @@ +// +// Copyright the Collabora Online contributors. +// +// SPDX-License-Identifier: MPL-2.0 +// +// 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/. + +// Configuration settings file format documentation can be found at: +// https://help.apple.com/xcode/#/dev745c5c974 + +HEADER_SEARCH_PATHS = "@LOKIT_PATH@" +GCC_PREPROCESSOR_DEFINITIONS = "COOLWSD_CONFIGDIR=\"@COOLWSD_CONFIGDIR@\"" "COOLWSD_LOGLEVEL=\"@COOLWSD_LOGLEVEL@\"" "NUM_PRESPAWN_CHILDREN=\"@NUM_PRESPAWN_CHILDREN@\"" diff --git a/macos/coda/coda-Bridging-Header.h b/macos/coda/coda-Bridging-Header.h new file mode 100644 index 0000000000000..1b2cb5d6d09fe --- /dev/null +++ b/macos/coda/coda-Bridging-Header.h @@ -0,0 +1,4 @@ +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// + diff --git a/macos/coda/coda.xcodeproj/project.pbxproj b/macos/coda/coda.xcodeproj/project.pbxproj new file mode 100644 index 0000000000000..0f3eb828cb9af --- /dev/null +++ b/macos/coda/coda.xcodeproj/project.pbxproj @@ -0,0 +1,838 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 77; + objects = { + +/* Begin PBXBuildFile section */ + BE2231B82CC679DE00385A9C /* Crypto-stub.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE2231B72CC679DE00385A9C /* Crypto-stub.cpp */; }; + BE2231BA2CC67FDE00385A9C /* coolwsd-fork.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE2231B92CC67FDE00385A9C /* coolwsd-fork.cpp */; }; + BE2231BC2CC6804D00385A9C /* Util-mobile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE2231BB2CC6804D00385A9C /* Util-mobile.cpp */; }; + BEA2636D2CBE38E20007435A /* Uri.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA2636A2CBE38E20007435A /* Uri.cpp */; }; + BEA2636E2CBE38E20007435A /* Util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA2636C2CBE38E20007435A /* Util.cpp */; }; + BEA2636F2CBE38E20007435A /* Unit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA263682CBE38E20007435A /* Unit.cpp */; }; + BEA263702CBE38E20007435A /* Log.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA263582CBE38E20007435A /* Log.cpp */; }; + BEA263712CBE38E20007435A /* Simd.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA263612CBE38E20007435A /* Simd.cpp */; }; + BEA263722CBE38E20007435A /* FileUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA263562CBE38E20007435A /* FileUtil.cpp */; }; + BEA263732CBE38E20007435A /* Session.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA2635D2CBE38E20007435A /* Session.cpp */; }; + BEA263742CBE38E20007435A /* TraceEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA263662CBE38E20007435A /* TraceEvent.cpp */; }; + BEA263752CBE38E20007435A /* SigUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA2635F2CBE38E20007435A /* SigUtil.cpp */; }; + BEA263762CBE38E20007435A /* SpookyV2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA263622CBE38E20007435A /* SpookyV2.cpp */; }; + BEA263772CBE38E20007435A /* ConfigUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA263552CBE38E20007435A /* ConfigUtil.cpp */; }; + BEA263782CBE38E20007435A /* StringVector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA263642CBE38E20007435A /* StringVector.cpp */; }; + BEA263792CBE38E20007435A /* Protocol.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA2635B2CBE38E20007435A /* Protocol.cpp */; }; + BEA2637A2CBE38E20007435A /* Authorization.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA263532CBE38E20007435A /* Authorization.cpp */; }; + BEA264162CBE7A770007435A /* Config.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = BEA264152CBE7A770007435A /* Config.xcconfig */; }; + BEA264922CBE986C0007435A /* KitQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA264902CBE986C0007435A /* KitQueue.cpp */; }; + BEA264932CBE986C0007435A /* KitWebSocket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA264912CBE986C0007435A /* KitWebSocket.cpp */; }; + BEA264942CBE986C0007435A /* ChildSession.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA2648D2CBE986C0007435A /* ChildSession.cpp */; }; + BEA264952CBE986C0007435A /* Kit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA2648E2CBE986C0007435A /* Kit.cpp */; }; + BEA264962CBE986C0007435A /* DeltaSimd.c in Sources */ = {isa = PBXBuildFile; fileRef = BEA2648C2CBE986C0007435A /* DeltaSimd.c */; }; + BEA264A02CBE98CD0007435A /* NetUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA2649C2CBE98CD0007435A /* NetUtil.cpp */; }; + BEA264A12CBE98CD0007435A /* Socket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA2649E2CBE98CD0007435A /* Socket.cpp */; }; + BEA264A22CBE98CD0007435A /* HttpRequest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA2649A2CBE98CD0007435A /* HttpRequest.cpp */; }; + BEA264A32CBE98CD0007435A /* FakeSocket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA264982CBE98CD0007435A /* FakeSocket.cpp */; }; + BEA264AD2CBE99340007435A /* Storage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA264AB2CBE99340007435A /* Storage.cpp */; }; + BEA264AE2CBE99340007435A /* TileCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA264AC2CBE99340007435A /* TileCache.cpp */; }; + BEA264AF2CBE99340007435A /* COOLWSD.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA264A62CBE99340007435A /* COOLWSD.cpp */; }; + BEA264B02CBE99340007435A /* ClientSession.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA264A52CBE99340007435A /* ClientSession.cpp */; }; + BEA264B12CBE99340007435A /* RequestDetails.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA264A92CBE99340007435A /* RequestDetails.cpp */; }; + BEA264B22CBE99340007435A /* ClientRequestDispatcher.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA264A42CBE99340007435A /* ClientRequestDispatcher.cpp */; }; + BEA264B32CBE99340007435A /* DocumentBroker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA264A72CBE99340007435A /* DocumentBroker.cpp */; }; + BEA264B42CBE99340007435A /* RequestVettingStation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA264AA2CBE99340007435A /* RequestVettingStation.cpp */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + BECC4BBD2CBD3FA400A120B3 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BECC4BA32CBD3FA300A120B3 /* Project object */; + proxyType = 1; + remoteGlobalIDString = BECC4BAA2CBD3FA300A120B3; + remoteInfo = coda; + }; + BECC4BC72CBD3FA400A120B3 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BECC4BA32CBD3FA300A120B3 /* Project object */; + proxyType = 1; + remoteGlobalIDString = BECC4BAA2CBD3FA300A120B3; + remoteInfo = coda; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + BE2231B72CC679DE00385A9C /* Crypto-stub.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "Crypto-stub.cpp"; path = "/Users/kendy/Projects/collabora/online/common/Crypto-stub.cpp"; sourceTree = ""; }; + BE2231B92CC67FDE00385A9C /* coolwsd-fork.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "coolwsd-fork.cpp"; path = "/Users/kendy/Projects/collabora/online/wsd/coolwsd-fork.cpp"; sourceTree = ""; }; + BE2231BB2CC6804D00385A9C /* Util-mobile.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "Util-mobile.cpp"; path = "/Users/kendy/Projects/collabora/online/common/Util-mobile.cpp"; sourceTree = ""; }; + BEA263522CBE38E20007435A /* Authorization.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Authorization.hpp; path = /Users/kendy/Projects/collabora/online/common/Authorization.hpp; sourceTree = ""; }; + BEA263532CBE38E20007435A /* Authorization.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Authorization.cpp; path = /Users/kendy/Projects/collabora/online/common/Authorization.cpp; sourceTree = ""; }; + BEA263542CBE38E20007435A /* ConfigUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = ConfigUtil.hpp; path = /Users/kendy/Projects/collabora/online/common/ConfigUtil.hpp; sourceTree = ""; }; + BEA263552CBE38E20007435A /* ConfigUtil.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ConfigUtil.cpp; path = /Users/kendy/Projects/collabora/online/common/ConfigUtil.cpp; sourceTree = ""; }; + BEA263562CBE38E20007435A /* FileUtil.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = FileUtil.cpp; path = /Users/kendy/Projects/collabora/online/common/FileUtil.cpp; sourceTree = ""; }; + BEA263572CBE38E20007435A /* Log.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Log.hpp; path = /Users/kendy/Projects/collabora/online/common/Log.hpp; sourceTree = ""; }; + BEA263582CBE38E20007435A /* Log.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Log.cpp; path = /Users/kendy/Projects/collabora/online/common/Log.cpp; sourceTree = ""; }; + BEA263592CBE38E20007435A /* Png.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Png.hpp; path = /Users/kendy/Projects/collabora/online/common/Png.hpp; sourceTree = ""; }; + BEA2635A2CBE38E20007435A /* Protocol.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Protocol.hpp; path = /Users/kendy/Projects/collabora/online/common/Protocol.hpp; sourceTree = ""; }; + BEA2635B2CBE38E20007435A /* Protocol.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Protocol.cpp; path = /Users/kendy/Projects/collabora/online/common/Protocol.cpp; sourceTree = ""; }; + BEA2635C2CBE38E20007435A /* Session.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Session.hpp; path = /Users/kendy/Projects/collabora/online/common/Session.hpp; sourceTree = ""; }; + BEA2635D2CBE38E20007435A /* Session.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Session.cpp; path = /Users/kendy/Projects/collabora/online/common/Session.cpp; sourceTree = ""; }; + BEA2635E2CBE38E20007435A /* SigUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = SigUtil.hpp; path = /Users/kendy/Projects/collabora/online/common/SigUtil.hpp; sourceTree = ""; }; + BEA2635F2CBE38E20007435A /* SigUtil.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SigUtil.cpp; path = /Users/kendy/Projects/collabora/online/common/SigUtil.cpp; sourceTree = ""; }; + BEA263602CBE38E20007435A /* Simd.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Simd.hpp; path = /Users/kendy/Projects/collabora/online/common/Simd.hpp; sourceTree = ""; }; + BEA263612CBE38E20007435A /* Simd.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Simd.cpp; path = /Users/kendy/Projects/collabora/online/common/Simd.cpp; sourceTree = ""; }; + BEA263622CBE38E20007435A /* SpookyV2.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SpookyV2.cpp; path = /Users/kendy/Projects/collabora/online/common/SpookyV2.cpp; sourceTree = ""; }; + BEA263632CBE38E20007435A /* StringVector.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = StringVector.hpp; path = /Users/kendy/Projects/collabora/online/common/StringVector.hpp; sourceTree = ""; }; + BEA263642CBE38E20007435A /* StringVector.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = StringVector.cpp; path = /Users/kendy/Projects/collabora/online/common/StringVector.cpp; sourceTree = ""; }; + BEA263652CBE38E20007435A /* TraceEvent.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = TraceEvent.hpp; path = /Users/kendy/Projects/collabora/online/common/TraceEvent.hpp; sourceTree = ""; }; + BEA263662CBE38E20007435A /* TraceEvent.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = TraceEvent.cpp; path = /Users/kendy/Projects/collabora/online/common/TraceEvent.cpp; sourceTree = ""; }; + BEA263672CBE38E20007435A /* Unit.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Unit.hpp; path = /Users/kendy/Projects/collabora/online/common/Unit.hpp; sourceTree = ""; }; + BEA263682CBE38E20007435A /* Unit.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Unit.cpp; path = /Users/kendy/Projects/collabora/online/common/Unit.cpp; sourceTree = ""; }; + BEA263692CBE38E20007435A /* Uri.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Uri.hpp; path = /Users/kendy/Projects/collabora/online/common/Uri.hpp; sourceTree = ""; }; + BEA2636A2CBE38E20007435A /* Uri.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Uri.cpp; path = /Users/kendy/Projects/collabora/online/common/Uri.cpp; sourceTree = ""; }; + BEA2636B2CBE38E20007435A /* Util.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Util.hpp; path = /Users/kendy/Projects/collabora/online/common/Util.hpp; sourceTree = ""; }; + BEA2636C2CBE38E20007435A /* Util.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Util.cpp; path = /Users/kendy/Projects/collabora/online/common/Util.cpp; sourceTree = ""; }; + BEA2637B2CBE38F50007435A /* coda-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "coda-Bridging-Header.h"; sourceTree = ""; }; + BEA264152CBE7A770007435A /* Config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = ""; }; + BEA2648B2CBE986C0007435A /* DeltaSimd.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = DeltaSimd.h; path = /Users/kendy/Projects/collabora/online/kit/DeltaSimd.h; sourceTree = ""; }; + BEA2648C2CBE986C0007435A /* DeltaSimd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = DeltaSimd.c; path = /Users/kendy/Projects/collabora/online/kit/DeltaSimd.c; sourceTree = ""; }; + BEA2648D2CBE986C0007435A /* ChildSession.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ChildSession.cpp; path = /Users/kendy/Projects/collabora/online/kit/ChildSession.cpp; sourceTree = ""; }; + BEA2648E2CBE986C0007435A /* Kit.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Kit.cpp; path = /Users/kendy/Projects/collabora/online/kit/Kit.cpp; sourceTree = ""; }; + BEA2648F2CBE986C0007435A /* KitQueue.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = KitQueue.hpp; path = /Users/kendy/Projects/collabora/online/kit/KitQueue.hpp; sourceTree = ""; }; + BEA264902CBE986C0007435A /* KitQueue.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = KitQueue.cpp; path = /Users/kendy/Projects/collabora/online/kit/KitQueue.cpp; sourceTree = ""; }; + BEA264912CBE986C0007435A /* KitWebSocket.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = KitWebSocket.cpp; path = /Users/kendy/Projects/collabora/online/kit/KitWebSocket.cpp; sourceTree = ""; }; + BEA264972CBE98CD0007435A /* AsyncDNS.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = AsyncDNS.hpp; path = /Users/kendy/Projects/collabora/online/net/AsyncDNS.hpp; sourceTree = ""; }; + BEA264982CBE98CD0007435A /* FakeSocket.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = FakeSocket.cpp; path = /Users/kendy/Projects/collabora/online/net/FakeSocket.cpp; sourceTree = ""; }; + BEA264992CBE98CD0007435A /* HttpRequest.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = HttpRequest.hpp; path = /Users/kendy/Projects/collabora/online/net/HttpRequest.hpp; sourceTree = ""; }; + BEA2649A2CBE98CD0007435A /* HttpRequest.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = HttpRequest.cpp; path = /Users/kendy/Projects/collabora/online/net/HttpRequest.cpp; sourceTree = ""; }; + BEA2649B2CBE98CD0007435A /* NetUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = NetUtil.hpp; path = /Users/kendy/Projects/collabora/online/net/NetUtil.hpp; sourceTree = ""; }; + BEA2649C2CBE98CD0007435A /* NetUtil.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = NetUtil.cpp; path = /Users/kendy/Projects/collabora/online/net/NetUtil.cpp; sourceTree = ""; }; + BEA2649D2CBE98CD0007435A /* Socket.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Socket.hpp; path = /Users/kendy/Projects/collabora/online/net/Socket.hpp; sourceTree = ""; }; + BEA2649E2CBE98CD0007435A /* Socket.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Socket.cpp; path = /Users/kendy/Projects/collabora/online/net/Socket.cpp; sourceTree = ""; }; + BEA2649F2CBE98CD0007435A /* WebSocketHandler.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = WebSocketHandler.hpp; path = /Users/kendy/Projects/collabora/online/net/WebSocketHandler.hpp; sourceTree = ""; }; + BEA264A42CBE99340007435A /* ClientRequestDispatcher.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ClientRequestDispatcher.cpp; path = /Users/kendy/Projects/collabora/online/wsd/ClientRequestDispatcher.cpp; sourceTree = ""; }; + BEA264A52CBE99340007435A /* ClientSession.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ClientSession.cpp; path = /Users/kendy/Projects/collabora/online/wsd/ClientSession.cpp; sourceTree = ""; }; + BEA264A62CBE99340007435A /* COOLWSD.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = COOLWSD.cpp; path = /Users/kendy/Projects/collabora/online/wsd/COOLWSD.cpp; sourceTree = ""; }; + BEA264A72CBE99340007435A /* DocumentBroker.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = DocumentBroker.cpp; path = /Users/kendy/Projects/collabora/online/wsd/DocumentBroker.cpp; sourceTree = ""; }; + BEA264A82CBE99340007435A /* RequestDetails.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = RequestDetails.hpp; path = /Users/kendy/Projects/collabora/online/wsd/RequestDetails.hpp; sourceTree = ""; }; + BEA264A92CBE99340007435A /* RequestDetails.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = RequestDetails.cpp; path = /Users/kendy/Projects/collabora/online/wsd/RequestDetails.cpp; sourceTree = ""; }; + BEA264AA2CBE99340007435A /* RequestVettingStation.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = RequestVettingStation.cpp; path = /Users/kendy/Projects/collabora/online/wsd/RequestVettingStation.cpp; sourceTree = ""; }; + BEA264AB2CBE99340007435A /* Storage.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Storage.cpp; path = /Users/kendy/Projects/collabora/online/wsd/Storage.cpp; sourceTree = ""; }; + BEA264AC2CBE99340007435A /* TileCache.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = TileCache.cpp; path = /Users/kendy/Projects/collabora/online/wsd/TileCache.cpp; sourceTree = ""; }; + BEA264B52CBE9BEF0007435A /* Storage.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Storage.hpp; path = /Users/kendy/Projects/collabora/online/wsd/Storage.hpp; sourceTree = ""; }; + BECC4BAB2CBD3FA300A120B3 /* coda.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = coda.app; sourceTree = BUILT_PRODUCTS_DIR; }; + BECC4BBC2CBD3FA400A120B3 /* codaTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = codaTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + BECC4BC62CBD3FA400A120B3 /* codaUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = codaUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFileSystemSynchronizedRootGroup section */ + BECC4BAD2CBD3FA300A120B3 /* coda */ = { + isa = PBXFileSystemSynchronizedRootGroup; + path = coda; + sourceTree = ""; + }; + BECC4BBF2CBD3FA400A120B3 /* codaTests */ = { + isa = PBXFileSystemSynchronizedRootGroup; + path = codaTests; + sourceTree = ""; + }; + BECC4BC92CBD3FA400A120B3 /* codaUITests */ = { + isa = PBXFileSystemSynchronizedRootGroup; + path = codaUITests; + sourceTree = ""; + }; +/* End PBXFileSystemSynchronizedRootGroup section */ + +/* Begin PBXFrameworksBuildPhase section */ + BECC4BA82CBD3FA300A120B3 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + BECC4BB92CBD3FA400A120B3 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + BECC4BC32CBD3FA400A120B3 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + BEA2637C2CBE38FE0007435A /* common */ = { + isa = PBXGroup; + children = ( + BEA263522CBE38E20007435A /* Authorization.hpp */, + BEA263532CBE38E20007435A /* Authorization.cpp */, + BEA263542CBE38E20007435A /* ConfigUtil.hpp */, + BEA263552CBE38E20007435A /* ConfigUtil.cpp */, + BE2231B72CC679DE00385A9C /* Crypto-stub.cpp */, + BEA263562CBE38E20007435A /* FileUtil.cpp */, + BEA263572CBE38E20007435A /* Log.hpp */, + BEA263582CBE38E20007435A /* Log.cpp */, + BEA263592CBE38E20007435A /* Png.hpp */, + BEA2635A2CBE38E20007435A /* Protocol.hpp */, + BEA2635B2CBE38E20007435A /* Protocol.cpp */, + BEA2635C2CBE38E20007435A /* Session.hpp */, + BEA2635D2CBE38E20007435A /* Session.cpp */, + BEA2635E2CBE38E20007435A /* SigUtil.hpp */, + BEA2635F2CBE38E20007435A /* SigUtil.cpp */, + BEA263602CBE38E20007435A /* Simd.hpp */, + BEA263612CBE38E20007435A /* Simd.cpp */, + BEA263622CBE38E20007435A /* SpookyV2.cpp */, + BEA263632CBE38E20007435A /* StringVector.hpp */, + BEA263642CBE38E20007435A /* StringVector.cpp */, + BEA263652CBE38E20007435A /* TraceEvent.hpp */, + BEA263662CBE38E20007435A /* TraceEvent.cpp */, + BEA263672CBE38E20007435A /* Unit.hpp */, + BEA263682CBE38E20007435A /* Unit.cpp */, + BEA263692CBE38E20007435A /* Uri.hpp */, + BEA2636A2CBE38E20007435A /* Uri.cpp */, + BEA2636B2CBE38E20007435A /* Util.hpp */, + BEA2636C2CBE38E20007435A /* Util.cpp */, + BE2231BB2CC6804D00385A9C /* Util-mobile.cpp */, + ); + path = common; + sourceTree = ""; + }; + BEA2637D2CBE39C30007435A /* Online */ = { + isa = PBXGroup; + children = ( + BEA2637C2CBE38FE0007435A /* common */, + BEA264882CBE97C30007435A /* kit */, + BEA264892CBE97D40007435A /* net */, + BEA2648A2CBE98010007435A /* wsd */, + ); + path = Online; + sourceTree = ""; + }; + BEA264882CBE97C30007435A /* kit */ = { + isa = PBXGroup; + children = ( + BEA2648B2CBE986C0007435A /* DeltaSimd.h */, + BEA2648C2CBE986C0007435A /* DeltaSimd.c */, + BEA2648D2CBE986C0007435A /* ChildSession.cpp */, + BEA2648E2CBE986C0007435A /* Kit.cpp */, + BEA2648F2CBE986C0007435A /* KitQueue.hpp */, + BEA264902CBE986C0007435A /* KitQueue.cpp */, + BEA264912CBE986C0007435A /* KitWebSocket.cpp */, + ); + path = kit; + sourceTree = ""; + }; + BEA264892CBE97D40007435A /* net */ = { + isa = PBXGroup; + children = ( + BEA264972CBE98CD0007435A /* AsyncDNS.hpp */, + BEA264982CBE98CD0007435A /* FakeSocket.cpp */, + BEA264992CBE98CD0007435A /* HttpRequest.hpp */, + BEA2649A2CBE98CD0007435A /* HttpRequest.cpp */, + BEA2649B2CBE98CD0007435A /* NetUtil.hpp */, + BEA2649C2CBE98CD0007435A /* NetUtil.cpp */, + BEA2649D2CBE98CD0007435A /* Socket.hpp */, + BEA2649E2CBE98CD0007435A /* Socket.cpp */, + BEA2649F2CBE98CD0007435A /* WebSocketHandler.hpp */, + ); + path = net; + sourceTree = ""; + }; + BEA2648A2CBE98010007435A /* wsd */ = { + isa = PBXGroup; + children = ( + BEA264A42CBE99340007435A /* ClientRequestDispatcher.cpp */, + BEA264A52CBE99340007435A /* ClientSession.cpp */, + BEA264A62CBE99340007435A /* COOLWSD.cpp */, + BE2231B92CC67FDE00385A9C /* coolwsd-fork.cpp */, + BEA264A72CBE99340007435A /* DocumentBroker.cpp */, + BEA264A82CBE99340007435A /* RequestDetails.hpp */, + BEA264A92CBE99340007435A /* RequestDetails.cpp */, + BEA264AA2CBE99340007435A /* RequestVettingStation.cpp */, + BEA264AB2CBE99340007435A /* Storage.cpp */, + BEA264B52CBE9BEF0007435A /* Storage.hpp */, + BEA264AC2CBE99340007435A /* TileCache.cpp */, + ); + path = wsd; + sourceTree = ""; + }; + BECC4BA22CBD3FA300A120B3 = { + isa = PBXGroup; + children = ( + BEA2637D2CBE39C30007435A /* Online */, + BECC4BAD2CBD3FA300A120B3 /* coda */, + BECC4BBF2CBD3FA400A120B3 /* codaTests */, + BECC4BC92CBD3FA400A120B3 /* codaUITests */, + BECC4BAC2CBD3FA300A120B3 /* Products */, + BEA2637B2CBE38F50007435A /* coda-Bridging-Header.h */, + BEA264152CBE7A770007435A /* Config.xcconfig */, + ); + sourceTree = ""; + }; + BECC4BAC2CBD3FA300A120B3 /* Products */ = { + isa = PBXGroup; + children = ( + BECC4BAB2CBD3FA300A120B3 /* coda.app */, + BECC4BBC2CBD3FA400A120B3 /* codaTests.xctest */, + BECC4BC62CBD3FA400A120B3 /* codaUITests.xctest */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + BECC4BAA2CBD3FA300A120B3 /* coda */ = { + isa = PBXNativeTarget; + buildConfigurationList = BECC4BD02CBD3FA400A120B3 /* Build configuration list for PBXNativeTarget "coda" */; + buildPhases = ( + BECC4BA72CBD3FA300A120B3 /* Sources */, + BECC4BA82CBD3FA300A120B3 /* Frameworks */, + BECC4BA92CBD3FA300A120B3 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + fileSystemSynchronizedGroups = ( + BECC4BAD2CBD3FA300A120B3 /* coda */, + ); + name = coda; + packageProductDependencies = ( + ); + productName = coda; + productReference = BECC4BAB2CBD3FA300A120B3 /* coda.app */; + productType = "com.apple.product-type.application"; + }; + BECC4BBB2CBD3FA400A120B3 /* codaTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = BECC4BD32CBD3FA400A120B3 /* Build configuration list for PBXNativeTarget "codaTests" */; + buildPhases = ( + BECC4BB82CBD3FA400A120B3 /* Sources */, + BECC4BB92CBD3FA400A120B3 /* Frameworks */, + BECC4BBA2CBD3FA400A120B3 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + BECC4BBE2CBD3FA400A120B3 /* PBXTargetDependency */, + ); + fileSystemSynchronizedGroups = ( + BECC4BBF2CBD3FA400A120B3 /* codaTests */, + ); + name = codaTests; + packageProductDependencies = ( + ); + productName = codaTests; + productReference = BECC4BBC2CBD3FA400A120B3 /* codaTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + BECC4BC52CBD3FA400A120B3 /* codaUITests */ = { + isa = PBXNativeTarget; + buildConfigurationList = BECC4BD62CBD3FA400A120B3 /* Build configuration list for PBXNativeTarget "codaUITests" */; + buildPhases = ( + BECC4BC22CBD3FA400A120B3 /* Sources */, + BECC4BC32CBD3FA400A120B3 /* Frameworks */, + BECC4BC42CBD3FA400A120B3 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + BECC4BC82CBD3FA400A120B3 /* PBXTargetDependency */, + ); + fileSystemSynchronizedGroups = ( + BECC4BC92CBD3FA400A120B3 /* codaUITests */, + ); + name = codaUITests; + packageProductDependencies = ( + ); + productName = codaUITests; + productReference = BECC4BC62CBD3FA400A120B3 /* codaUITests.xctest */; + productType = "com.apple.product-type.bundle.ui-testing"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + BECC4BA32CBD3FA300A120B3 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1600; + LastUpgradeCheck = 1600; + TargetAttributes = { + BECC4BAA2CBD3FA300A120B3 = { + CreatedOnToolsVersion = 16.0; + LastSwiftMigration = 1600; + }; + BECC4BBB2CBD3FA400A120B3 = { + CreatedOnToolsVersion = 16.0; + TestTargetID = BECC4BAA2CBD3FA300A120B3; + }; + BECC4BC52CBD3FA400A120B3 = { + CreatedOnToolsVersion = 16.0; + TestTargetID = BECC4BAA2CBD3FA300A120B3; + }; + }; + }; + buildConfigurationList = BECC4BA62CBD3FA300A120B3 /* Build configuration list for PBXProject "coda" */; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = BECC4BA22CBD3FA300A120B3; + minimizedProjectReferenceProxies = 1; + preferredProjectObjectVersion = 77; + productRefGroup = BECC4BAC2CBD3FA300A120B3 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + BECC4BAA2CBD3FA300A120B3 /* coda */, + BECC4BBB2CBD3FA400A120B3 /* codaTests */, + BECC4BC52CBD3FA400A120B3 /* codaUITests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + BECC4BA92CBD3FA300A120B3 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + BEA264162CBE7A770007435A /* Config.xcconfig in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + BECC4BBA2CBD3FA400A120B3 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + BECC4BC42CBD3FA400A120B3 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + BECC4BA72CBD3FA300A120B3 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + BEA2636D2CBE38E20007435A /* Uri.cpp in Sources */, + BEA264922CBE986C0007435A /* KitQueue.cpp in Sources */, + BEA264932CBE986C0007435A /* KitWebSocket.cpp in Sources */, + BEA264942CBE986C0007435A /* ChildSession.cpp in Sources */, + BEA264952CBE986C0007435A /* Kit.cpp in Sources */, + BEA264962CBE986C0007435A /* DeltaSimd.c in Sources */, + BEA2636E2CBE38E20007435A /* Util.cpp in Sources */, + BE2231B82CC679DE00385A9C /* Crypto-stub.cpp in Sources */, + BEA2636F2CBE38E20007435A /* Unit.cpp in Sources */, + BEA263702CBE38E20007435A /* Log.cpp in Sources */, + BEA263712CBE38E20007435A /* Simd.cpp in Sources */, + BE2231BC2CC6804D00385A9C /* Util-mobile.cpp in Sources */, + BEA263722CBE38E20007435A /* FileUtil.cpp in Sources */, + BEA263732CBE38E20007435A /* Session.cpp in Sources */, + BEA263742CBE38E20007435A /* TraceEvent.cpp in Sources */, + BEA264A02CBE98CD0007435A /* NetUtil.cpp in Sources */, + BEA264A12CBE98CD0007435A /* Socket.cpp in Sources */, + BEA264A22CBE98CD0007435A /* HttpRequest.cpp in Sources */, + BEA264A32CBE98CD0007435A /* FakeSocket.cpp in Sources */, + BEA263752CBE38E20007435A /* SigUtil.cpp in Sources */, + BEA263762CBE38E20007435A /* SpookyV2.cpp in Sources */, + BEA264AD2CBE99340007435A /* Storage.cpp in Sources */, + BEA264AE2CBE99340007435A /* TileCache.cpp in Sources */, + BEA264AF2CBE99340007435A /* COOLWSD.cpp in Sources */, + BEA264B02CBE99340007435A /* ClientSession.cpp in Sources */, + BEA264B12CBE99340007435A /* RequestDetails.cpp in Sources */, + BEA264B22CBE99340007435A /* ClientRequestDispatcher.cpp in Sources */, + BE2231BA2CC67FDE00385A9C /* coolwsd-fork.cpp in Sources */, + BEA264B32CBE99340007435A /* DocumentBroker.cpp in Sources */, + BEA264B42CBE99340007435A /* RequestVettingStation.cpp in Sources */, + BEA263772CBE38E20007435A /* ConfigUtil.cpp in Sources */, + BEA263782CBE38E20007435A /* StringVector.cpp in Sources */, + BEA263792CBE38E20007435A /* Protocol.cpp in Sources */, + BEA2637A2CBE38E20007435A /* Authorization.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + BECC4BB82CBD3FA400A120B3 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + BECC4BC22CBD3FA400A120B3 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + BECC4BBE2CBD3FA400A120B3 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = BECC4BAA2CBD3FA300A120B3 /* coda */; + targetProxy = BECC4BBD2CBD3FA400A120B3 /* PBXContainerItemProxy */; + }; + BECC4BC82CBD3FA400A120B3 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = BECC4BAA2CBD3FA300A120B3 /* coda */; + targetProxy = BECC4BC72CBD3FA400A120B3 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + BECC4BCE2CBD3FA400A120B3 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = BEA264152CBE7A770007435A /* Config.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + "MACOS=MACOS", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(SRCROOT)", + "$(SRCROOT)/coda", + "$(SRCROOT)/../..", + "$(SRCROOT)/../../common", + "$(SRCROOT)/../../kit", + "$(SRCROOT)/../../net", + "$(SRCROOT)/../../wsd", + /opt/homebrew/include, + ); + LIBRARY_SEARCH_PATHS = /opt/homebrew/lib; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 15.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + OTHER_LDFLAGS = ( + "-lPocoFoundation", + "-lPocoUtil", + "-lPocoXML", + "-lPocoJSON", + "-lPocoNet", + "-lzstd", + "-lpng", + ); + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + BECC4BCF2CBD3FA400A120B3 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = BEA264152CBE7A770007435A /* Config.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + "MACOS=MACOS", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(SRCROOT)", + "$(SRCROOT)/coda", + "$(SRCROOT)/../..", + "$(SRCROOT)/../../common", + "$(SRCROOT)/../../kit", + "$(SRCROOT)/../../net", + "$(SRCROOT)/../../wsd", + /opt/homebrew/include, + ); + LIBRARY_SEARCH_PATHS = /opt/homebrew/lib; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 15.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + OTHER_LDFLAGS = ( + "-lPocoFoundation", + "-lPocoUtil", + "-lPocoXML", + "-lPocoJSON", + "-lPocoNet", + "-lzstd", + "-lpng", + ); + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + }; + name = Release; + }; + BECC4BD12CBD3FA400A120B3 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = coda/coda.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = J4FQ687VJK; + ENABLE_HARDENED_RUNTIME = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INFOPLIST_KEY_NSMainStoryboardFile = Main; + INFOPLIST_KEY_NSPrincipalClass = NSApplication; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.collabora.coda; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_OBJC_BRIDGING_HEADER = "coda-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + BECC4BD22CBD3FA400A120B3 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = coda/coda.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = J4FQ687VJK; + ENABLE_HARDENED_RUNTIME = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INFOPLIST_KEY_NSMainStoryboardFile = Main; + INFOPLIST_KEY_NSPrincipalClass = NSApplication; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.collabora.coda; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_OBJC_BRIDGING_HEADER = "coda-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + BECC4BD42CBD3FA400A120B3 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = J4FQ687VJK; + GENERATE_INFOPLIST_FILE = YES; + MACOSX_DEPLOYMENT_TARGET = 15.0; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.collabora.codaTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/coda.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/coda"; + }; + name = Debug; + }; + BECC4BD52CBD3FA400A120B3 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = J4FQ687VJK; + GENERATE_INFOPLIST_FILE = YES; + MACOSX_DEPLOYMENT_TARGET = 15.0; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.collabora.codaTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/coda.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/coda"; + }; + name = Release; + }; + BECC4BD72CBD3FA400A120B3 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = J4FQ687VJK; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.collabora.codaUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TEST_TARGET_NAME = coda; + }; + name = Debug; + }; + BECC4BD82CBD3FA400A120B3 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = J4FQ687VJK; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.collabora.codaUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TEST_TARGET_NAME = coda; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + BECC4BA62CBD3FA300A120B3 /* Build configuration list for PBXProject "coda" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + BECC4BCE2CBD3FA400A120B3 /* Debug */, + BECC4BCF2CBD3FA400A120B3 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + BECC4BD02CBD3FA400A120B3 /* Build configuration list for PBXNativeTarget "coda" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + BECC4BD12CBD3FA400A120B3 /* Debug */, + BECC4BD22CBD3FA400A120B3 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + BECC4BD32CBD3FA400A120B3 /* Build configuration list for PBXNativeTarget "codaTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + BECC4BD42CBD3FA400A120B3 /* Debug */, + BECC4BD52CBD3FA400A120B3 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + BECC4BD62CBD3FA400A120B3 /* Build configuration list for PBXNativeTarget "codaUITests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + BECC4BD72CBD3FA400A120B3 /* Debug */, + BECC4BD82CBD3FA400A120B3 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = BECC4BA32CBD3FA300A120B3 /* Project object */; +} diff --git a/macos/coda/coda/AppDelegate.swift b/macos/coda/coda/AppDelegate.swift new file mode 100644 index 0000000000000..0ffef051febb5 --- /dev/null +++ b/macos/coda/coda/AppDelegate.swift @@ -0,0 +1,30 @@ +// +// AppDelegate.swift +// coda +// +// Created by Jan Holešovský on 14.10.2024. +// + +import Cocoa + +@main +class AppDelegate: NSObject, NSApplicationDelegate { + + + + + func applicationDidFinishLaunching(_ aNotification: Notification) { + // Insert code here to initialize your application + } + + func applicationWillTerminate(_ aNotification: Notification) { + // Insert code here to tear down your application + } + + func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { + return true + } + + +} + diff --git a/macos/coda/coda/Assets.xcassets/AccentColor.colorset/Contents.json b/macos/coda/coda/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000000000..eb87897008164 --- /dev/null +++ b/macos/coda/coda/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/macos/coda/coda/Assets.xcassets/AppIcon.appiconset/Contents.json b/macos/coda/coda/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000000000..3f00db43ec3c8 --- /dev/null +++ b/macos/coda/coda/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,58 @@ +{ + "images" : [ + { + "idiom" : "mac", + "scale" : "1x", + "size" : "16x16" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "16x16" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "32x32" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "32x32" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "128x128" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "128x128" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "256x256" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "256x256" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "512x512" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "512x512" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/macos/coda/coda/Assets.xcassets/Contents.json b/macos/coda/coda/Assets.xcassets/Contents.json new file mode 100644 index 0000000000000..73c00596a7fca --- /dev/null +++ b/macos/coda/coda/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/macos/coda/coda/Base.lproj/Main.storyboard b/macos/coda/coda/Base.lproj/Main.storyboard new file mode 100644 index 0000000000000..7ad7c709db69c --- /dev/null +++ b/macos/coda/coda/Base.lproj/Main.storyboard @@ -0,0 +1,717 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/macos/coda/coda/ViewController.swift b/macos/coda/coda/ViewController.swift new file mode 100644 index 0000000000000..03c58922d473b --- /dev/null +++ b/macos/coda/coda/ViewController.swift @@ -0,0 +1,26 @@ +// +// ViewController.swift +// coda +// +// Created by Jan Holešovský on 14.10.2024. +// + +import Cocoa + +class ViewController: NSViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + } + + override var representedObject: Any? { + didSet { + // Update the view, if already loaded. + } + } + + +} + diff --git a/macos/coda/coda/coda.entitlements b/macos/coda/coda/coda.entitlements new file mode 100644 index 0000000000000..782cf2dedd591 --- /dev/null +++ b/macos/coda/coda/coda.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.disable-library-validation + + com.apple.security.files.user-selected.read-only + + + diff --git a/macos/coda/coda/macos.h b/macos/coda/coda/macos.h new file mode 100644 index 0000000000000..29e1fcbdab35f --- /dev/null +++ b/macos/coda/coda/macos.h @@ -0,0 +1,20 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * Copyright the Collabora Online contributors. + * + * SPDX-License-Identifier: MPL-2.0 + * + * 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 + +extern const char *user_name; + +extern int coolwsd_server_socket_fd; + +extern LibreOfficeKit *lo_kit; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/macos/coda/coda/macos.mm b/macos/coda/coda/macos.mm new file mode 100644 index 0000000000000..bbd6b785e3c81 --- /dev/null +++ b/macos/coda/coda/macos.mm @@ -0,0 +1,18 @@ +// -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- +// +// 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 "macos.h" + +#import +#import + +const char *user_name = nullptr; + +int coolwsd_server_socket_fd = -1; + +LibreOfficeKit *lo_kit; + +// vim:set shiftwidth=4 softtabstop=4 expandtab: diff --git a/macos/coda/codaTests/codaTests.swift b/macos/coda/codaTests/codaTests.swift new file mode 100644 index 0000000000000..df97b7089a5a0 --- /dev/null +++ b/macos/coda/codaTests/codaTests.swift @@ -0,0 +1,17 @@ +// +// codaTests.swift +// codaTests +// +// Created by Jan Holešovský on 14.10.2024. +// + +import Testing +@testable import coda + +struct codaTests { + + @Test func example() async throws { + // Write your test here and use APIs like `#expect(...)` to check expected conditions. + } + +} diff --git a/macos/coda/codaUITests/codaUITests.swift b/macos/coda/codaUITests/codaUITests.swift new file mode 100644 index 0000000000000..ac22c15d88917 --- /dev/null +++ b/macos/coda/codaUITests/codaUITests.swift @@ -0,0 +1,43 @@ +// +// codaUITests.swift +// codaUITests +// +// Created by Jan Holešovský on 14.10.2024. +// + +import XCTest + +final class codaUITests: XCTestCase { + + override func setUpWithError() throws { + // Put setup code here. This method is called before the invocation of each test method in the class. + + // In UI tests it is usually best to stop immediately when a failure occurs. + continueAfterFailure = false + + // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. + } + + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } + + @MainActor + func testExample() throws { + // UI tests must launch the application that they test. + let app = XCUIApplication() + app.launch() + + // Use XCTAssert and related functions to verify your tests produce the correct results. + } + + @MainActor + func testLaunchPerformance() throws { + if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) { + // This measures how long it takes to launch your application. + measure(metrics: [XCTApplicationLaunchMetric()]) { + XCUIApplication().launch() + } + } + } +} diff --git a/macos/coda/codaUITests/codaUITestsLaunchTests.swift b/macos/coda/codaUITests/codaUITestsLaunchTests.swift new file mode 100644 index 0000000000000..acfe81df1a986 --- /dev/null +++ b/macos/coda/codaUITests/codaUITestsLaunchTests.swift @@ -0,0 +1,33 @@ +// +// codaUITestsLaunchTests.swift +// codaUITests +// +// Created by Jan Holešovský on 14.10.2024. +// + +import XCTest + +final class codaUITestsLaunchTests: XCTestCase { + + override class var runsForEachTargetApplicationUIConfiguration: Bool { + true + } + + override func setUpWithError() throws { + continueAfterFailure = false + } + + @MainActor + func testLaunch() throws { + let app = XCUIApplication() + app.launch() + + // Insert steps here to perform after app launch but before taking a screenshot, + // such as logging into a test account or navigating somewhere in the app + + let attachment = XCTAttachment(screenshot: app.screenshot()) + attachment.name = "Launch Screen" + attachment.lifetime = .keepAlways + add(attachment) + } +} diff --git a/macos/coda/config.h.in b/macos/coda/config.h.in new file mode 100644 index 0000000000000..2175d196ba090 --- /dev/null +++ b/macos/coda/config.h.in @@ -0,0 +1,135 @@ +/* config.h. Manually edited from config.h.in. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +#define APP_NAME "@APP_NAME@" + +/* LibreOffice core git hash if present */ +#define CORE_VERSION_HASH "@CORE_VERSION_HASH@" + +/* Whether to disable SECCOMP */ +#define DISABLE_SECCOMP 1 + +/* Whether to compile in some extra debugging support code and disable some + security pieces */ +/* When building with Xcode we define ENABLE_DEBUG when debugging, but not otherwise */ +#if !defined ENABLE_DEBUG +#define ENABLE_DEBUG 0 +#endif + +/* Whether to enable SSL */ +#define ENABLE_SSL 0 + +/* Whether to enable support key */ +#define ENABLE_SUPPORT_KEY 0 + +/* Should the Release notes message on startup should be enabled be default? + */ +#define ENABLE_WELCOME_MESSAGE 0 + +/* Should the Release notes message on startup have a dismiss button instead of an x button to close by default? + */ +#define ENABLE_WELCOME_MESSAGE_BUTTON "false" + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 0 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 0 + +/* Define to 1 if you have the `pam' library (-lpam). */ +#define HAVE_LIBPAM 0 + +/* Define to 1 if you have the header file. + */ +#define HAVE_LIBREOFFICEKIT_LIBREOFFICEKIT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LINUX_SECCOMP_H 0 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Whether OpenSSL has PKCS5_PBKDF2_HMAC() */ +#define HAVE_PKCS5_PBKDF2_HMAC 0 + +/* Define to 1 if you have the header file. */ +#define HAVE_POCO_NET_WEBSOCKET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SECURITY_PAM_APPL_H 0 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 0 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Collabora Online WebSocket server version */ +#define COOLWSD_VERSION "@COOLWSD_VERSION@" + +/* Collabora Online git hash if present */ +#define COOLWSD_VERSION_HASH "@COOLWSD_VERSION_HASH@" + +/* Path to LibreOffice installation */ +#define LO_PATH "." + +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +#undef LT_OBJDIR + +/* Limit the maximum number of open connections */ +#define MAX_CONNECTIONS 100 + +/* Limit the maximum number of open documents */ +#define MAX_DOCUMENTS 100 + +/* Define to 1 if this is a mobileapp (eg. Android) build. */ +#define MOBILEAPP 1 + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Makes config variables conditionally static, only in non-debug builds, to allow for overriding them in unit-tests. */ +#ifdef ENABLE_DEBUG +#define CONFIG_STATIC +#else +#define CONFIG_STATIC static +#endif + +/* Version number of package */ +/* #undef VERSION */ diff --git a/wsd/PlatformMobile.hpp b/wsd/PlatformMobile.hpp index c82e071d70067..122a9cd30338c 100644 --- a/wsd/PlatformMobile.hpp +++ b/wsd/PlatformMobile.hpp @@ -14,6 +14,8 @@ #include #ifdef IOS #include "ios.h" +#elif defined(MACOS) +#include "macos.h" #elif defined(GTKAPP) #include "gtk.hpp" #elif defined(__ANDROID__) diff --git a/wsd/Storage.cpp b/wsd/Storage.cpp index 574037811d821..8e9b5fc2c8dca 100644 --- a/wsd/Storage.cpp +++ b/wsd/Storage.cpp @@ -50,6 +50,8 @@ #ifdef IOS #include +#elif defined(MACOS) +#include #elif defined(__ANDROID__) #include "androidapp.hpp" #elif defined(GTKAPP) From edc1516e6fd3314bae11c9b78fee714a5141b087 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Mon, 21 Oct 2024 18:47:39 +0300 Subject: [PATCH 002/177] Initial CODA-Windows commits squashed together Add initial CODA-Windows support: --enable-windowsapp. Add WINDOWSAPP conditions. Define WINDOWSAPP also when creating the cool.html. Signed-off-by: Tor Lillqvist Change-Id: Id59870a303f10de76e97f33e3d56a7d343196c0c --- browser/Makefile.am | 2 + browser/html/cool.html.m4 | 2 + configure.ac | 78 +++++++++++++++++++++++++++------------ 3 files changed, 59 insertions(+), 23 deletions(-) diff --git a/browser/Makefile.am b/browser/Makefile.am index d2362b2103601..9dcb4e5f34557 100644 --- a/browser/Makefile.am +++ b/browser/Makefile.am @@ -691,6 +691,7 @@ define bundle_cool @touch $@, $(QUIET_M4) m4 -PE -DIOSAPP=$(ENABLE_IOSAPP) \ -DGTKAPP=$(ENABLE_GTKAPP) \ + -DWINDOWSAPP=$(ENABLE_WINDOWSAPP) \ -DANDROIDAPP=$(ENABLE_ANDROIDAPP) \ -DMOBILEAPPNAME="$(APP_NAME)" \ -DVERSION=$(COOL_VERSION) \ @@ -925,6 +926,7 @@ $(DIST_FOLDER)/cool.html: $(srcdir)/html/cool.html.m4 \ -DIOSAPP=$(ENABLE_IOSAPP) \ -DGTKAPP=$(ENABLE_GTKAPP) \ -DDEBUG=$(ENABLE_DEBUG) \ + -DWINDOWSAPP=$(ENABLE_WINDOWSAPP) \ -DANDROIDAPP=$(ENABLE_ANDROIDAPP) \ -DEMSCRIPTENAPP=$(ENABLE_EMSCRIPTENAPP) \ -DMOBILEAPPNAME="$(APP_NAME)" \ diff --git a/browser/html/cool.html.m4 b/browser/html/cool.html.m4 index 29165b303b21d..5c56db1481879 100644 --- a/browser/html/cool.html.m4 +++ b/browser/html/cool.html.m4 @@ -10,6 +10,7 @@ m4_dnl# Define MOBILEAPP as true if this is either for the iOS/Android app or fo m4_define([MOBILEAPP],[])m4_dnl m4_ifelse(IOSAPP,[true],[m4_define([MOBILEAPP],[true])])m4_dnl m4_ifelse(GTKAPP,[true],[m4_define([MOBILEAPP],[true])])m4_dnl +m4_ifelse(WINDOWSAPP,[true],[m4_define([MOBILEAPP],[true])])m4_dnl m4_ifelse(ANDROIDAPP,[true],[m4_define([MOBILEAPP],[true])])m4_dnl m4_dnl m4_dnl# FIXME: This is temporary and not what we actually eventually want. @@ -64,6 +65,7 @@ m4_ifelse(MOBILEAPP, [true], m4_dnl# For use in conditionals in JS: m4_ifelse(IOSAPP, [true], []) m4_ifelse(GTKAPP, [true], []) +m4_ifelse(WINDOWSAPP, [true], []) m4_ifelse(ANDROIDAPP, [true], []) m4_ifelse(EMSCRIPTENAPP, [true], []) diff --git a/configure.ac b/configure.ac index c0d8f9d68f105..df140c6d55563 100644 --- a/configure.ac +++ b/configure.ac @@ -146,6 +146,12 @@ AC_ARG_ENABLE([macosapp], AS_HELP_STRING([--enable-macosapp], [Use on a Mac where you will build the macOS app.])) +AC_ARG_ENABLE([windowsapp], + AS_HELP_STRING([--enable-windowsapp], + [Use in WSL2 on a Windows PC where you will build the Windows app that works + similarly to the iOS app, from the JavaScript and the pseudo WebSocket + message plumbing point of view.])) + AC_ARG_WITH([wasm-fallback], AS_HELP_STRING([--with-wasm-fallback=], [Build a COOL where the client can fall back to a WASM implementation if the connection to the server fails. @@ -629,7 +635,7 @@ ZSTDLIB_X86= ZSTDLIB_X86_64= CORE_VERSION_HASH="" -if test \( "$enable_iosapp" = "yes" -a `uname -s` = "Darwin" \) -o \( "$enable_androidapp" = "yes" \) -o "$host_os" = "emscripten" ; then +if test \( "$enable_iosapp" = "yes" -a `uname -s` = "Darwin" \) -o \( "$enable_windowsapp" = "yes" \) -o \( "$enable_androidapp" = "yes" \) -o "$host_os" = "emscripten" ; then if test "$enable_androidapp" = "yes" ; then AC_MSG_CHECKING([for Android ABI to build for]) if test -n "$with_android_abi" ; then @@ -653,7 +659,7 @@ if test \( "$enable_iosapp" = "yes" -a `uname -s` = "Darwin" \) -o \( "$enable_a AC_MSG_CHECKING([for LibreOffice build tree to build against]) if test -z "$with_lo_builddir"; then - AC_MSG_ERROR([You MUST use the --with-lo-builddir option when configuring the mobile app build tree.]) + AC_MSG_ERROR([You MUST use the --with-lo-builddir option when configuring the mobile or Windows app build tree.]) fi LOBUILDDIR="$with_lo_builddir" @@ -682,16 +688,22 @@ if test \( "$enable_iosapp" = "yes" -a `uname -s` = "Darwin" \) -o \( "$enable_a LOBUILDDIR=`readlink -f "$LOBUILDDIR"` - # Get the git hash of the core build - CORE_VERSION_HASH=`cd $LOBUILDDIR && grep buildid instdir/program/setuprc | sed -e 's/buildid=//' -e 's/............................$//'` + # Get the git hash of the core build. + # Also use the setuprc or setup.ini file existence as a sanity check. + if test "$enable_windowsapp" = "yes"; then + setuprc=setup.ini + else + setuprc=setuprc + fi - # Sanity check, just a random object file in the LibreOffice build tree - if test \( "$enable_iosapp" = "yes" -a -f "$LOBUILDDIR/workdir/CxxObject/vcl/ios/iosinst.o" \) -o \( "$enable_androidapp" = "yes" -a -f "$LOBUILDDIR/workdir/LinkTarget/StaticLibrary/liblibpng.a" \) -o \( "$host_os" = "emscripten" -a -f "${LOBUILDDIR}/workdir/LinkTarget/StaticLibrary/liblibpng.a" \); then - AC_MSG_RESULT([$LOBUILDDIR]) + if test -f "$LOBUILDDIR/instdir/program/$setuprc"; then + AC_MSG_RESULT([$LOBUILDDIR]) else - AC_MSG_ERROR([This is not a LibreOffice core build directory: $LOBUILDDIR]) + AC_MSG_ERROR([This is not a LibreOffice core build directory: $LOBUILDDIR]) fi + CORE_VERSION_HASH=`grep buildid $LOBUILDDIR/instdir/program/$setuprc | sed -e 's/buildid=//' -e 's/............................$//'` + if test -n "$LOBUILDDIR_ARM64_V8A" ; then if test -f "$LOBUILDDIR_ARM64_V8A/workdir/LinkTarget/StaticLibrary/liblibpng.a" ; then AC_MSG_RESULT([$LOBUILDDIR_ARM64_V8A]) @@ -718,7 +730,7 @@ if test \( "$enable_iosapp" = "yes" -a `uname -s` = "Darwin" \) -o \( "$enable_a AC_MSG_CHECKING([for Poco include directory to build against]) if test -z "$with_poco_includes"; then - AC_MSG_ERROR([You MUST use the --with-poco-includes option when configuring the mobile app build tree.]) + AC_MSG_ERROR([You MUST use the --with-poco-includes option when configuring the mobile or Windows app build tree.]) fi POCOINCLUDE="$with_poco_includes" @@ -773,18 +785,26 @@ if test \( "$enable_iosapp" = "yes" -a `uname -s` = "Darwin" \) -o \( "$enable_a fi # Sanity checks - CHK_FILE_VAR(POCOLIB,libPocoFoundation.a,Poco lib) - CHK_FILE_VAR(POCOLIB,libPocoFoundation.a,Poco lib,_ARM64_V8A) - CHK_FILE_VAR(POCOLIB,libPocoFoundation.a,Poco lib,_X86) - CHK_FILE_VAR(POCOLIB,libPocoFoundation.a,Poco lib,_X86_64) + if test "$enable_windowsapp" = "yes"; then + CHK_FILE_VAR(POCOLIB,PocoFoundation.lib,Poco lib) + else + CHK_FILE_VAR(POCOLIB,libPocoFoundation.a,Poco lib) + CHK_FILE_VAR(POCOLIB,libPocoFoundation.a,Poco lib,_ARM64_V8A) + CHK_FILE_VAR(POCOLIB,libPocoFoundation.a,Poco lib,_X86) + CHK_FILE_VAR(POCOLIB,libPocoFoundation.a,Poco lib,_X86_64) + fi if test "$ENABLE_DEBUG" = "true" ; then POCODEBUG=d fi - AC_MSG_CHECKING([for zstd lib directory to build against]) + AC_MSG_CHECKING([for zstd directories to build against]) + if test -z "$with_zstd_includes"; then + AC_MSG_ERROR([You MUST use the --with-zstd-includes option when configuring the mobile or Windows app build tree.]) + fi + if test -z "$with_zstd_libs"; then - AC_MSG_ERROR([You MUST use the --with-zstd-libs option when configuring the mobile app build tree.]) + AC_MSG_ERROR([You MUST use the --with-zstd-libs option when configuring the mobile or Windows app build tree.]) fi ZSTDINCLUDE="$with_zstd_includes" @@ -833,10 +853,14 @@ if test \( "$enable_iosapp" = "yes" -a `uname -s` = "Darwin" \) -o \( "$enable_a fi fi - CHK_FILE_VAR(ZSTDLIB,libzstd.a,Zstd lib) - CHK_FILE_VAR(ZSTDLIB,libzstd.a,Zstd lib,_ARM64_V8A) - CHK_FILE_VAR(ZSTDLIB,libzstd.a,Zstd lib,_X86) - CHK_FILE_VAR(ZSTDLIB,libzstd.a,Zstd lib,_X86_64) + if test "$enable_windowsapp"; then + CHK_FILE_VAR(ZSTDLIB,libzstd_static.lib,Zstd lib) + else + CHK_FILE_VAR(ZSTDLIB,libzstd.a,Zstd lib) + CHK_FILE_VAR(ZSTDLIB,libzstd.a,Zstd lib,_ARM64_V8A) + CHK_FILE_VAR(ZSTDLIB,libzstd.a,Zstd lib,_X86) + CHK_FILE_VAR(ZSTDLIB,libzstd.a,Zstd lib,_X86_64) + fi fi AC_SUBST(LOSOURCEDIR) @@ -870,7 +894,7 @@ AC_DEFINE_UNQUOTED([CORE_VERSION_HASH],[["$CORE_VERSION_HASH"]],[LibreOffice cor LIBPNG_INCLUDES="$with_libpng_includes" LIBPNG_LIBS="$with_libpng_libs" -if test "$enable_iosapp" != yes -a "$enable_androidapp" != yes; then +if test "$enable_iosapp" != yes -a "$enable_windowsapp" != yes -a "$enable_androidapp" != yes; then LOKIT_PATH=`readlink -f $with_lokit_path` fi @@ -982,6 +1006,14 @@ AC_SUBST(ENABLE_MACOSAPP) AM_CONDITIONAL([ENABLE_MACOSAPP], [test "$ENABLE_MACOSAPP" = "true"]) #AC_SUBST(MACOSAPP_BUNDLE_VERSION) +ENABLE_WINDOWSAPP= + +if test "$enable_windowsapp" = "yes"; then + ENABLE_WINDOWSAPP=true +fi +AC_SUBST(ENABLE_WINDOWSAPP) +AM_CONDITIONAL([ENABLE_WINDOWSAPP], [test "$ENABLE_WINDOWSAPP" = "true"]) + AC_MSG_CHECKING([for custom icon theme]) CUSTOM_ICONS_DIRECTORY= if test -d "$with_icon_theme"; then @@ -1291,7 +1323,7 @@ AS_IF([test -n "$LOKIT_PATH"], [CPPFLAGS="$CPPFLAGS -I${LOKIT_PATH}"]) lokit_msg="$LOKIT_PATH" -AS_IF([test "$ENABLE_IOSAPP" != "true" -a "$ENABLE_MACOSAPP" != "true" -a "$ENABLE_ANDROIDAPP" != "true"], +AS_IF([test "$ENABLE_IOSAPP" != "true" -a "$ENABLE_MACOSAPP" != "true" -a "$ENABLE_WINDOWSAPP" != "true" -a "$ENABLE_ANDROIDAPP" != "true"], [AC_MSG_CHECKING([for LibreOffice path]) if test -n "$with_lo_path"; then # strip trailing '/' from LO_PATH, 'ln -s' with such path will otherwise fail @@ -1408,7 +1440,7 @@ mobile_app= ENABLE_MOBILEAPP= MOBILEAPP=0 AC_MSG_CHECKING([if this is a mobile app]) -if test "$enable_gtkapp" = "yes" -o "$enable_iosapp" = "yes" -o "$enable_androidapp" = "yes" -o "$host_os" = "emscripten" ; then +if test "$enable_gtkapp" = "yes" -o "$enable_iosapp" = "yes" -o "$enable_windowsapp" = "yes" -o "$enable_androidapp" = "yes" -o "$host_os" = "emscripten" ; then AC_MSG_RESULT([yes]) mobile_app=true; MOBILEAPP=1 @@ -1523,7 +1555,7 @@ fi AS_IF([test "$ENABLE_SSL" = "true"], [LIBS="$LIBS -lssl -lcrypto"]) -AS_IF([test "$ENABLE_IOSAPP" != "true" -a "$ENABLE_ANDROIDAPP" != "true" -a "$host_os" != "emscripten"], +AS_IF([test "$ENABLE_IOSAPP" != "true" -a "$ENABLE_WINDOWSAPP" != "true" -a "$ENABLE_ANDROIDAPP" != "true" -a "$host_os" != "emscripten"], [AC_CHECK_HEADERS([LibreOfficeKit/LibreOfficeKit.h], [], [AC_MSG_ERROR([header LibreOfficeKit/LibreOfficeKit.h not found, perhaps you want to use --with-lokit-path])]) From adf5259dba7324887e3c95986e391d390256823d Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 22 Oct 2024 07:14:24 +0200 Subject: [PATCH 003/177] A few CODA-M commits squashed together Let JS know that it is a local app. Proof-of-concept webview with a two-way communication. Add the real cool.html to the bundle. Mention that up-to-date Command Line Tools for Xcode might be needed. Signed-off-by: Jan Holesovsky Change-Id: Ic4058f73ce953309e03c1ba0fe482e03979bf7a4 --- browser/Makefile.am | 2 + browser/html/cool.html.m4 | 2 + macos/README.txt | 5 ++ macos/coda/coda.xcodeproj/project.pbxproj | 36 +++++++++++++ macos/coda/coda/AppDelegate.swift | 15 +++--- macos/coda/coda/ViewController.swift | 61 ++++++++++++++++++----- macos/coda/coda/coda.entitlements | 2 + 7 files changed, 104 insertions(+), 19 deletions(-) diff --git a/browser/Makefile.am b/browser/Makefile.am index 9dcb4e5f34557..6d17be179ad8d 100644 --- a/browser/Makefile.am +++ b/browser/Makefile.am @@ -690,6 +690,7 @@ define bundle_cool $(if $(IS_SEPARATE),\ @touch $@, $(QUIET_M4) m4 -PE -DIOSAPP=$(ENABLE_IOSAPP) \ + -DMACOSAPP=$(ENABLE_MACOSAPP) \ -DGTKAPP=$(ENABLE_GTKAPP) \ -DWINDOWSAPP=$(ENABLE_WINDOWSAPP) \ -DANDROIDAPP=$(ENABLE_ANDROIDAPP) \ @@ -924,6 +925,7 @@ $(DIST_FOLDER)/cool.html: $(srcdir)/html/cool.html.m4 \ $(QUIET_M4) m4 -PE -I $(INTERMEDIATE_DIR) \ -DBUNDLE=$(IS_BUNDLE) \ -DIOSAPP=$(ENABLE_IOSAPP) \ + -DMACOSAPP=$(ENABLE_MACOSAPP) \ -DGTKAPP=$(ENABLE_GTKAPP) \ -DDEBUG=$(ENABLE_DEBUG) \ -DWINDOWSAPP=$(ENABLE_WINDOWSAPP) \ diff --git a/browser/html/cool.html.m4 b/browser/html/cool.html.m4 index 5c56db1481879..4e81fd2db1871 100644 --- a/browser/html/cool.html.m4 +++ b/browser/html/cool.html.m4 @@ -9,6 +9,7 @@ m4_dnl------------------------------------------------------------------------ m4_dnl# Define MOBILEAPP as true if this is either for the iOS/Android app or for the gtk+ "app" testbed m4_define([MOBILEAPP],[])m4_dnl m4_ifelse(IOSAPP,[true],[m4_define([MOBILEAPP],[true])])m4_dnl +m4_ifelse(MACOSAPP,[true],[m4_define([MOBILEAPP],[true])])m4_dnl m4_ifelse(GTKAPP,[true],[m4_define([MOBILEAPP],[true])])m4_dnl m4_ifelse(WINDOWSAPP,[true],[m4_define([MOBILEAPP],[true])])m4_dnl m4_ifelse(ANDROIDAPP,[true],[m4_define([MOBILEAPP],[true])])m4_dnl @@ -64,6 +65,7 @@ m4_ifelse(MOBILEAPP, [true], m4_dnl# For use in conditionals in JS: m4_ifelse(IOSAPP, [true], []) +m4_ifelse(MACOSAPP, [true], []) m4_ifelse(GTKAPP, [true], []) m4_ifelse(WINDOWSAPP, [true], []) m4_ifelse(ANDROIDAPP, [true], []) diff --git a/macos/README.txt b/macos/README.txt index 25fb7427604d8..75c5ab5ea2b25 100644 --- a/macos/README.txt +++ b/macos/README.txt @@ -14,6 +14,11 @@ Setup * NB. version 3.0 needed, it upgrades the API to fit the new node.js * npm install canvas@next +* Install and/or update the Command Line Tools for Xcode: + * xcode-select --install + * After that you might need to update them in System Settings > General > Software Updates + * For some reason for me it lists both 15.3 and 16.0 there. As I have Xcode 16.0, I choose just that one. + Build LO autogen.input: diff --git a/macos/coda/coda.xcodeproj/project.pbxproj b/macos/coda/coda.xcodeproj/project.pbxproj index 0f3eb828cb9af..3d88df28f74aa 100644 --- a/macos/coda/coda.xcodeproj/project.pbxproj +++ b/macos/coda/coda.xcodeproj/project.pbxproj @@ -10,6 +10,13 @@ BE2231B82CC679DE00385A9C /* Crypto-stub.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE2231B72CC679DE00385A9C /* Crypto-stub.cpp */; }; BE2231BA2CC67FDE00385A9C /* coolwsd-fork.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE2231B92CC67FDE00385A9C /* coolwsd-fork.cpp */; }; BE2231BC2CC6804D00385A9C /* Util-mobile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE2231BB2CC6804D00385A9C /* Util-mobile.cpp */; }; + BE22492C2CC79AD700385A9C /* cool.html in Resources */ = {isa = PBXBuildFile; fileRef = BE22492B2CC79AD700385A9C /* cool.html */; }; + BE2252292CC79BAE00385A9C /* bundle.js in Resources */ = {isa = PBXBuildFile; fileRef = BE22492E2CC79BAE00385A9C /* bundle.js */; }; + BE22529E2CC79BAE00385A9C /* cool-help.html in Resources */ = {isa = PBXBuildFile; fileRef = BE22492F2CC79BAE00385A9C /* cool-help.html */; }; + BE2253F32CC79BAE00385A9C /* device-desktop.css in Resources */ = {isa = PBXBuildFile; fileRef = BE2249302CC79BAE00385A9C /* device-desktop.css */; }; + BE22557E2CC79BAE00385A9C /* global.js in Resources */ = {isa = PBXBuildFile; fileRef = BE2249312CC79BAE00385A9C /* global.js */; }; + BE2257AD2CC79BAE00385A9C /* bundle.css in Resources */ = {isa = PBXBuildFile; fileRef = BE22492D2CC79BAE00385A9C /* bundle.css */; }; + BE22AA9C2CC7AE7400385A9C /* images in Resources */ = {isa = PBXBuildFile; fileRef = BE22AA9B2CC7AE7400385A9C /* images */; }; BEA2636D2CBE38E20007435A /* Uri.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA2636A2CBE38E20007435A /* Uri.cpp */; }; BEA2636E2CBE38E20007435A /* Util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA2636C2CBE38E20007435A /* Util.cpp */; }; BEA2636F2CBE38E20007435A /* Unit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA263682CBE38E20007435A /* Unit.cpp */; }; @@ -65,6 +72,13 @@ BE2231B72CC679DE00385A9C /* Crypto-stub.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "Crypto-stub.cpp"; path = "/Users/kendy/Projects/collabora/online/common/Crypto-stub.cpp"; sourceTree = ""; }; BE2231B92CC67FDE00385A9C /* coolwsd-fork.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "coolwsd-fork.cpp"; path = "/Users/kendy/Projects/collabora/online/wsd/coolwsd-fork.cpp"; sourceTree = ""; }; BE2231BB2CC6804D00385A9C /* Util-mobile.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "Util-mobile.cpp"; path = "/Users/kendy/Projects/collabora/online/common/Util-mobile.cpp"; sourceTree = ""; }; + BE22492B2CC79AD700385A9C /* cool.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = cool.html; path = /Users/kendy/Projects/collabora/online/browser/dist/cool.html; sourceTree = ""; }; + BE22492D2CC79BAE00385A9C /* bundle.css */ = {isa = PBXFileReference; lastKnownFileType = text.css; name = bundle.css; path = /Users/kendy/Projects/collabora/online/browser/dist/bundle.css; sourceTree = ""; }; + BE22492E2CC79BAE00385A9C /* bundle.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = bundle.js; path = /Users/kendy/Projects/collabora/online/browser/dist/bundle.js; sourceTree = ""; }; + BE22492F2CC79BAE00385A9C /* cool-help.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = "cool-help.html"; path = "/Users/kendy/Projects/collabora/online/browser/dist/cool-help.html"; sourceTree = ""; }; + BE2249302CC79BAE00385A9C /* device-desktop.css */ = {isa = PBXFileReference; lastKnownFileType = text.css; name = "device-desktop.css"; path = "/Users/kendy/Projects/collabora/online/browser/dist/device-desktop.css"; sourceTree = ""; }; + BE2249312CC79BAE00385A9C /* global.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = global.js; path = /Users/kendy/Projects/collabora/online/browser/dist/global.js; sourceTree = ""; }; + BE22AA9B2CC7AE7400385A9C /* images */ = {isa = PBXFileReference; lastKnownFileType = folder; name = images; path = ../../../browser/dist/images; sourceTree = ""; }; BEA263522CBE38E20007435A /* Authorization.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Authorization.hpp; path = /Users/kendy/Projects/collabora/online/common/Authorization.hpp; sourceTree = ""; }; BEA263532CBE38E20007435A /* Authorization.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Authorization.cpp; path = /Users/kendy/Projects/collabora/online/common/Authorization.cpp; sourceTree = ""; }; BEA263542CBE38E20007435A /* ConfigUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = ConfigUtil.hpp; path = /Users/kendy/Projects/collabora/online/common/ConfigUtil.hpp; sourceTree = ""; }; @@ -168,6 +182,20 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + BE22492A2CC79AAC00385A9C /* dist */ = { + isa = PBXGroup; + children = ( + BE22AA9B2CC7AE7400385A9C /* images */, + BE22492D2CC79BAE00385A9C /* bundle.css */, + BE22492E2CC79BAE00385A9C /* bundle.js */, + BE22492B2CC79AD700385A9C /* cool.html */, + BE22492F2CC79BAE00385A9C /* cool-help.html */, + BE2249302CC79BAE00385A9C /* device-desktop.css */, + BE2249312CC79BAE00385A9C /* global.js */, + ); + path = dist; + sourceTree = ""; + }; BEA2637C2CBE38FE0007435A /* common */ = { isa = PBXGroup; children = ( @@ -266,6 +294,7 @@ BECC4BA22CBD3FA300A120B3 = { isa = PBXGroup; children = ( + BE22492A2CC79AAC00385A9C /* dist */, BEA2637D2CBE39C30007435A /* Online */, BECC4BAD2CBD3FA300A120B3 /* coda */, BECC4BBF2CBD3FA400A120B3 /* codaTests */, @@ -407,6 +436,13 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + BE22AA9C2CC7AE7400385A9C /* images in Resources */, + BE2252292CC79BAE00385A9C /* bundle.js in Resources */, + BE22529E2CC79BAE00385A9C /* cool-help.html in Resources */, + BE2253F32CC79BAE00385A9C /* device-desktop.css in Resources */, + BE22557E2CC79BAE00385A9C /* global.js in Resources */, + BE2257AD2CC79BAE00385A9C /* bundle.css in Resources */, + BE22492C2CC79AD700385A9C /* cool.html in Resources */, BEA264162CBE7A770007435A /* Config.xcconfig in Resources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/macos/coda/coda/AppDelegate.swift b/macos/coda/coda/AppDelegate.swift index 0ffef051febb5..b1754dbd1bd79 100644 --- a/macos/coda/coda/AppDelegate.swift +++ b/macos/coda/coda/AppDelegate.swift @@ -1,9 +1,12 @@ -// -// AppDelegate.swift -// coda -// -// Created by Jan Holešovský on 14.10.2024. -// +/* + * Copyright the Collabora Online contributors. + * + * SPDX-License-Identifier: MPL-2.0 + * + * 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/. + */ import Cocoa diff --git a/macos/coda/coda/ViewController.swift b/macos/coda/coda/ViewController.swift index 03c58922d473b..dc0b86a6cca2e 100644 --- a/macos/coda/coda/ViewController.swift +++ b/macos/coda/coda/ViewController.swift @@ -1,26 +1,61 @@ -// -// ViewController.swift -// coda -// -// Created by Jan Holešovský on 14.10.2024. -// +/* + * Copyright the Collabora Online contributors. + * + * SPDX-License-Identifier: MPL-2.0 + * + * 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/. + */ import Cocoa +import WebKit -class ViewController: NSViewController { +class ViewController: NSViewController, WKScriptMessageHandler, WKNavigationDelegate { + + var webView: WKWebView! override func viewDidLoad() { super.viewDidLoad() - // Do any additional setup after loading the view. - } + // setup jsHandler as the entry point co call back from JavaScript + let contentController = WKUserContentController() + contentController.add(self, name: "jsHandler") + + let config = WKWebViewConfiguration() + config.userContentController = contentController + + // create the web view + webView = WKWebView(frame: .zero, configuration: config) + webView.navigationDelegate = self + + // add it to the view controller's view + self.view.addSubview(webView) - override var representedObject: Any? { - didSet { - // Update the view, if already loaded. + webView.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + webView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor), + webView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor), + webView.topAnchor.constraint(equalTo: self.view.topAnchor), + webView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor) + ]) + + // load the local HTML file + if let htmlPath = Bundle.main.path(forResource: "cool", ofType: "html") { + let htmlURL = URL(fileURLWithPath: htmlPath) + webView.loadFileURL(htmlURL, allowingReadAccessTo: htmlURL.deletingLastPathComponent()) } } + // Send 'hello' message once the content finishes loading + func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { + webView.evaluateJavaScript("receiveMessage('hello');", completionHandler: nil) + } + // Receive message from JavaScript + func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { + if message.name == "jsHandler", let response = message.body as? String { + print("Received message from JS: \(response)") + } + } } - diff --git a/macos/coda/coda/coda.entitlements b/macos/coda/coda/coda.entitlements index 782cf2dedd591..581780da164dc 100644 --- a/macos/coda/coda/coda.entitlements +++ b/macos/coda/coda/coda.entitlements @@ -8,5 +8,7 @@ com.apple.security.files.user-selected.read-only + com.apple.security.network.client + From 9c7a803f3040c8a10ae978dc44058f49bd32f62d Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Tue, 29 Oct 2024 17:02:38 +0200 Subject: [PATCH 004/177] A few CODA-W commits squashed together Add WindowsAppInitializer for CODA-W. Don't generate the top-level config.h when it won't be used. Do generate windows/coda/config.h. Configury for CODA-W and make FakeSocket compile for it. Define EXPORT as __declspec(dllexport), for use to export functions that the managed (C#) part of CODA-W needs. Define as empty on all other platforms. Likely could be handled in some more elegant manner. Add Visual Studio solution and project files for CODA-W. Based on what VS produces when you let it create a new .NET app for you. Probably much of the settings are either unnecessary or will have to be tweaked later. Signed-off-by: Tor Lillqvist Change-Id: Iea82c7a81aa8debd342ea9ab715f65625ce8ee43 --- browser/js/global.js | 20 +- config.h.in | 3 + configure.ac | 19 +- ios/config.h.in | 4 + macos/coda/config.h.in | 4 + net/FakeSocket.cpp | 16 + windows/coda/CODA.sln | 31 ++ windows/coda/CODA/App.config | 6 + windows/coda/CODA/App.xaml | 9 + windows/coda/CODA/App.xaml.cs | 14 + windows/coda/CODA/CODA.csproj | 140 ++++++++ windows/coda/CODA/MainWindow.xaml | 28 ++ windows/coda/CODA/MainWindow.xaml.cs | 316 ++++++++++++++++++ windows/coda/CODA/Properties/AssemblyInfo.cs | 52 +++ .../CODA/Properties/Resources.Designer.cs | 63 ++++ windows/coda/CODA/Properties/Resources.resx | 117 +++++++ .../coda/CODA/Properties/Settings.Designer.cs | 26 ++ .../coda/CODA/Properties/Settings.settings | 7 + windows/coda/CODALib/CODALib.vcxproj | 99 ++++++ windows/coda/CODALib/CODALib.vcxproj.filters | 27 ++ windows/coda/README.txt | 26 ++ windows/coda/config.h.in | 158 +++++++++ 22 files changed, 1178 insertions(+), 7 deletions(-) create mode 100644 windows/coda/CODA.sln create mode 100644 windows/coda/CODA/App.config create mode 100644 windows/coda/CODA/App.xaml create mode 100644 windows/coda/CODA/App.xaml.cs create mode 100644 windows/coda/CODA/CODA.csproj create mode 100644 windows/coda/CODA/MainWindow.xaml create mode 100644 windows/coda/CODA/MainWindow.xaml.cs create mode 100644 windows/coda/CODA/Properties/AssemblyInfo.cs create mode 100644 windows/coda/CODA/Properties/Resources.Designer.cs create mode 100644 windows/coda/CODA/Properties/Resources.resx create mode 100644 windows/coda/CODA/Properties/Settings.Designer.cs create mode 100644 windows/coda/CODA/Properties/Settings.settings create mode 100644 windows/coda/CODALib/CODALib.vcxproj create mode 100644 windows/coda/CODALib/CODALib.vcxproj.filters create mode 100644 windows/coda/README.txt create mode 100755 windows/coda/config.h.in diff --git a/browser/js/global.js b/browser/js/global.js index 2baf05ea5f455..82aa72455112c 100644 --- a/browser/js/global.js +++ b/browser/js/global.js @@ -1,4 +1,4 @@ -/* -*- js-indent-level: 8 -*- */ +/* -*- js-indent-level: 8; fill-column: 100 -*- */ /* global Module ArrayBuffer Uint8Array _ */ @@ -488,6 +488,22 @@ class GTKAppInitializer extends MobileAppInitializer { } } +class WindowsAppInitializer extends MobileAppInitializer { + constructor() { + super(); + + window.ThisIsTheWindowsApp = true; + window.postMobileMessage = function(msg) { window.chrome.webview.postMessage(msg); }; + + // FIXME: No registration of separate handlers in Windows WebView2, so just log + // errors and debug messages? Maybe instead send a JSON object with separate name + // and body? But then we would have to parse that JSON object from the string in C# + // anyway. + window.postMobileError = function(msg) { console.log('COOL Error: ' + msg); }; + window.postMobileDebug = function(msg) { console.log('COOL Debug: ' + msg); }; + } +} + class AndroidAppInitializer extends MobileAppInitializer { constructor() { super(); @@ -530,6 +546,8 @@ function getInitializerClass() { return new IOSAppInitializer(); else if (osType === "GTK") return new GTKAppInitializer(); + else if (osType === "WINDOWS") + return new WindowsAppInitializer(); else if (osType === "ANDROID") return new AndroidAppInitializer(); else if (osType === "EMSCRIPTEN") diff --git a/config.h.in b/config.h.in index 47072a7f8fe97..7c86999a647eb 100644 --- a/config.h.in +++ b/config.h.in @@ -138,6 +138,9 @@ /* Makes config variables conditionally static, only in non-debug builds, to allow for overriding them in unit-tests. */ #undef CONFIG_STATIC_TYPE +/* This top-level config.h is used only in "normal" COOL, thus we don't need the Windows version of EXPORT here */ +#define EXPORT /**/ + /* Controls whether or not we allow loading documents from the local filesystem. */ #ifndef ENABLE_LOCAL_FILESYSTEM #if MOBILEAPP || ENABLE_DEBUG diff --git a/configure.ac b/configure.ac index df140c6d55563..45d49cdb6cb34 100644 --- a/configure.ac +++ b/configure.ac @@ -64,12 +64,6 @@ AC_DEFINE_UNQUOTED([COOLWSD_BUILDCONFIG],[["$ac_configure_args"]],[Options passe # don't include config_unused.h anywhere! AC_CONFIG_HEADERS([config_unused.h]) -# maintain config.h.in and config_version.h.in manually -# config.h.in is for configurable variables that are stable if configure parameters are unchanged -AC_CONFIG_HEADERS([config.h]) -# config_version.h.in is for version/hash related variables -AC_CONFIG_HEADERS([config_version.h]) - # Checks for programs. AC_PROG_CXX AC_PROG_CC @@ -2035,6 +2029,15 @@ AC_CONFIG_FILES([Makefile coolwsd.xml debian/coolwsd.postinst]) +# maintain config.h.in and config_version.h.in manually +# config.h.in is for configurable variables that are stable if configure parameters are unchanged +if test "$enable_iosapp" != "yes" -a "$enable_macosapp" != "yes" -a "$enable_windowsapp" != "yes"; then + AC_CONFIG_HEADERS([config.h]) +fi + +# config_version.h.in is for version/hash related variables +AC_CONFIG_HEADERS([config_version.h]) + if test "$enable_iosapp" = "yes"; then AC_CONFIG_FILES([ios/config.h ios/Mobile/Info.plist @@ -2046,6 +2049,10 @@ if test "$enable_macosapp" = "yes"; then macos/coda/Config.xcconfig]) fi +if test "$enable_windowsapp" = "yes"; then + AC_CONFIG_FILES([windows/coda/config.h]) +fi + if test "$enable_androidapp" = "yes"; then AC_CONFIG_FILES([ $srcdir/android/variables.gradle:android/variables.gradle.in diff --git a/ios/config.h.in b/ios/config.h.in index dbb2c99ae0bfe..2d1328d2aab66 100644 --- a/ios/config.h.in +++ b/ios/config.h.in @@ -138,3 +138,7 @@ /* Version number of package */ /* #undef VERSION */ + +/* This config.h is used only in the iOS app, thus we don't need the Windows version of EXPORT here */ + +#define EXPORT /**/ diff --git a/macos/coda/config.h.in b/macos/coda/config.h.in index 2175d196ba090..cf2d2a5caa56f 100644 --- a/macos/coda/config.h.in +++ b/macos/coda/config.h.in @@ -133,3 +133,7 @@ /* Version number of package */ /* #undef VERSION */ + +/* This config.h is used only in CODA for macOS app, thus we don't need the Windows version of EXPORT here */ + +#define EXPORT /**/ diff --git a/net/FakeSocket.cpp b/net/FakeSocket.cpp index 0acb5c593cb1d..d6b6b3ee89719 100644 --- a/net/FakeSocket.cpp +++ b/net/FakeSocket.cpp @@ -12,7 +12,9 @@ #include "config.h" #include +#ifndef _WINDOWS #include +#endif #include #include @@ -105,6 +107,7 @@ static std::string flush() #define FAKESOCKET_LOG(arg) do { if (fakeSocketLogLevel > 0) { loggingBuffer << arg; } } while (false) #endif +EXPORT void fakeSocketSetLoggingCallback(void (*callback)(const std::string&)) { loggingCallback = callback; @@ -138,6 +141,7 @@ static FakeSocketPair& fakeSocketAllocate() return *(fds[i]); } +EXPORT int fakeSocketSocket() { const int result = fakeSocketAllocate().fd[0]; @@ -147,6 +151,7 @@ int fakeSocketSocket() return result; } +EXPORT int fakeSocketPipe2(int pipefd[2]) { FakeSocketPair& pair = fakeSocketAllocate(); @@ -361,6 +366,7 @@ void fakeSocketWaitAny(int timeoutUs) theCV.wait_until(lock, deadline, [](){ return fakeSocketHasAnyPendingActivityGlobal(); }); } +EXPORT int fakeSocketPoll(struct pollfd *pollfds, int nfds, int timeout) { FAKESOCKET_LOG("FakeSocket Poll "); @@ -415,6 +421,7 @@ int fakeSocketPoll(struct pollfd *pollfds, int nfds, int timeout) return result; } +EXPORT int fakeSocketListen(int fd) { std::unique_lock lock(theMutex); @@ -449,6 +456,7 @@ int fakeSocketListen(int fd) return 0; } +EXPORT int fakeSocketConnect(int fd1, int fd2) { std::unique_lock lock(theMutex); @@ -495,6 +503,7 @@ int fakeSocketConnect(int fd1, int fd2) return 0; } +EXPORT int fakeSocketAccept4(int fd) { std::unique_lock lock(theMutex); @@ -547,6 +556,7 @@ int fakeSocketAccept4(int fd) return pair2.fd[1]; } +EXPORT int fakeSocketPeer(int fd) { std::unique_lock lock(theMutex); @@ -567,6 +577,7 @@ int fakeSocketPeer(int fd) return pair.fd[N]; } +EXPORT ssize_t fakeSocketAvailableDataLength(int fd) { std::unique_lock lock(theMutex); @@ -597,6 +608,7 @@ ssize_t fakeSocketAvailableDataLength(int fd) return result; } +EXPORT ssize_t fakeSocketRead(int fd, void *buf, size_t nbytes) { std::unique_lock lock(theMutex); @@ -662,6 +674,7 @@ ssize_t fakeSocketRead(int fd, void *buf, size_t nbytes) return result; } +EXPORT ssize_t fakeSocketWrite(int fd, const void *buf, size_t nbytes) { std::unique_lock lock(theMutex); @@ -704,6 +717,7 @@ ssize_t fakeSocketWrite(int fd, const void *buf, size_t nbytes) return nbytes; } +EXPORT int fakeSocketShutdown(int fd) { std::unique_lock lock(theMutex); @@ -743,6 +757,7 @@ int fakeSocketShutdown(int fd) return 0; } +EXPORT int fakeSocketClose(int fd) { std::unique_lock lock(theMutex); @@ -810,6 +825,7 @@ static void fakeSocketDumpStateImpl() } } +EXPORT void fakeSocketDumpState() { std::unique_lock lock(theMutex); diff --git a/windows/coda/CODA.sln b/windows/coda/CODA.sln new file mode 100644 index 0000000000000..1050ab7495995 --- /dev/null +++ b/windows/coda/CODA.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.11.35327.3 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CODA", "CODA\CODA.csproj", "{4D688348-30C3-4141-B56E-ACAE0D143135}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CODALib", "CODALib\CODALib.vcxproj", "{B0E65DEC-1CB0-4DAA-B3ED-709F8169BC40}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4D688348-30C3-4141-B56E-ACAE0D143135}.Debug|x64.ActiveCfg = Debug|Any CPU + {4D688348-30C3-4141-B56E-ACAE0D143135}.Debug|x64.Build.0 = Debug|Any CPU + {4D688348-30C3-4141-B56E-ACAE0D143135}.Release|x64.ActiveCfg = Release|Any CPU + {4D688348-30C3-4141-B56E-ACAE0D143135}.Release|x64.Build.0 = Release|Any CPU + {B0E65DEC-1CB0-4DAA-B3ED-709F8169BC40}.Debug|x64.ActiveCfg = Debug|x64 + {B0E65DEC-1CB0-4DAA-B3ED-709F8169BC40}.Debug|x64.Build.0 = Debug|x64 + {B0E65DEC-1CB0-4DAA-B3ED-709F8169BC40}.Release|x64.ActiveCfg = Release|x64 + {B0E65DEC-1CB0-4DAA-B3ED-709F8169BC40}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {03736A44-ED48-4967-9357-8809491FFE77} + EndGlobalSection +EndGlobal diff --git a/windows/coda/CODA/App.config b/windows/coda/CODA/App.config new file mode 100644 index 0000000000000..26f16c9fafbda --- /dev/null +++ b/windows/coda/CODA/App.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/windows/coda/CODA/App.xaml b/windows/coda/CODA/App.xaml new file mode 100644 index 0000000000000..dc06bd9b060cd --- /dev/null +++ b/windows/coda/CODA/App.xaml @@ -0,0 +1,9 @@ + + + + + diff --git a/windows/coda/CODA/App.xaml.cs b/windows/coda/CODA/App.xaml.cs new file mode 100644 index 0000000000000..6e6e9238ebe0e --- /dev/null +++ b/windows/coda/CODA/App.xaml.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; + +namespace CODA +{ + public partial class App : Application + { + } +} diff --git a/windows/coda/CODA/CODA.csproj b/windows/coda/CODA/CODA.csproj new file mode 100644 index 0000000000000..db341db94de70 --- /dev/null +++ b/windows/coda/CODA/CODA.csproj @@ -0,0 +1,140 @@ + + + + Collabora Productivity + Collabora Online as a Desktop App + Copyright © 2024 + Debug + AnyCPU + {4D688348-30C3-4141-B56E-ACAE0D143135} + WinExe + CODA + CODA + v4.8 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + true + true + + 11 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0 + false + false + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + CODA.App + + + + + + + + + + + + + 4.0 + + + + + + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + App.xaml + Code + + + MainWindow.xaml + Code + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + ResXFileCodeGenerator + Resources.Designer.cs + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + + + + 1.0.2849.39 + + + + + + False + Microsoft .NET Framework 4.8 %28x86 and x64%29 + true + + + False + .NET Framework 3.5 SP1 + false + + + + diff --git a/windows/coda/CODA/MainWindow.xaml b/windows/coda/CODA/MainWindow.xaml new file mode 100644 index 0000000000000..bb9bec297841b --- /dev/null +++ b/windows/coda/CODA/MainWindow.xaml @@ -0,0 +1,28 @@ + + + + + + + + + + + + diff --git a/windows/coda/CODA/MainWindow.xaml.cs b/windows/coda/CODA/MainWindow.xaml.cs new file mode 100644 index 0000000000000..60ca011441b7a --- /dev/null +++ b/windows/coda/CODA/MainWindow.xaml.cs @@ -0,0 +1,316 @@ +// -*- tab-width: 4; indent-tabs-mode: nil; fill-column: 100 -*- + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using Microsoft.Web.WebView2.Core; +using Microsoft.Web.WebView2.Wpf; + +namespace CODA +{ + public partial class MainWindow : Window + { + // FIXME: Is there some clever way to not have to duplicate the POLL* and struct pollfd + // definitions for the C# and C++ parts of CODA-W? + const int POLLIN = 0x001; + const int POLLPRI = 0x002; + const int POLLOUT = 0x004; + const int POLLERR = 0x008; + const int POLLHUP = 0x010; + const int POLLNVAL = 0x020; + + public struct pollfd { + public int fd; + public short events; + public short revents; + }; + + private IWebView2 _iWebView2; + + private bool _isNavigating = false; + + private int _fakeClientFd; + + private int[] _closeNotificationPipeForForwardingThread = new int[2]; + + [DllImport("CODALib.dll", CharSet = CharSet.Unicode)] + public static extern int get_coolwsd_server_socket_fd(); + + [DllImport("CODALib.dll", CharSet = CharSet.Unicode)] + public static extern int set_coolwsd_server_socket_fd(int fd); + + [DllImport("CODALib.dll", CharSet = CharSet.Unicode)] + public static extern int fakeSocketSocket(); + + [DllImport("CODALib.dll", CharSet = CharSet.Unicode)] + public static extern int fakeSocketPipe2(int[] pipefds); + + [DllImport("CODALib.dll", CharSet = CharSet.Unicode)] + public static extern int fakeSocketPoll(pollfd[] fds, int nfds, int timeout); + + [DllImport("CODALib.dll", CharSet = CharSet.Unicode)] + public static extern int fakeSocketListen(int fd); + + [DllImport("CODALib.dll", CharSet = CharSet.Unicode)] + public static extern int fakeSocketConnect(int fd1, int fd2); + + [DllImport("CODALib.dll", CharSet = CharSet.Unicode)] + public static extern int fakeSocketAccept4(int fd); + + [DllImport("CODALib.dll", CharSet = CharSet.Unicode)] + public static extern int fakeSocketPeer(int fd); + + [DllImport("CODALib.dll", CharSet = CharSet.Unicode)] + public static extern long fakeSocketAvailableDataLength(int fd); + + [DllImport("CODALib.dll", CharSet = CharSet.Unicode)] + public static extern long fakeSocketRead(int fd, byte[] buf, long nbytes); + + [DllImport("CODALib.dll", CharSet = CharSet.Unicode)] + public static extern long fakeSocketWrite(int fd, byte[] buf, long nbytes); + + [DllImport("CODALib.dll", CharSet = CharSet.Unicode)] + public static extern long fakeSocketShutdown(int fd); + + [DllImport("CODALib.dll", CharSet = CharSet.Unicode)] + public static extern long fakeSocketClose(int fd); + + [DllImport("CODALib.dll", CharSet = CharSet.Unicode)] + public static extern long fakeSocketDumpState(); + + private CoreWebView2Settings _webViewSettings; + CoreWebView2Settings WebViewSettings + { + get + { + if (_webViewSettings == null && _iWebView2?.CoreWebView2 != null) + { + _webViewSettings = _iWebView2.CoreWebView2.Settings; + } + return _webViewSettings; + } + } + + CoreWebView2Environment _webViewEnvironment; + CoreWebView2Environment WebViewEnvironment + { + get + { + if (_webViewEnvironment == null && _iWebView2?.CoreWebView2 != null) + { + _webViewEnvironment = _iWebView2.CoreWebView2.Environment; + } + return _webViewEnvironment; + } + } + + CoreWebView2Profile _webViewProfile; + CoreWebView2Profile WebViewProfile + { + get + { + if (_webViewProfile == null && _iWebView2?.CoreWebView2 != null) + { + _webViewProfile = _iWebView2.CoreWebView2.Profile; + } + return _webViewProfile; + } + } + + public MainWindow() + { + Loaded += MainWindow_Loaded; + InitializeComponent(); + } + + private async void MainWindow_Loaded(object sender, RoutedEventArgs e) + { + SetWebView(webView2XamlElement); + await InitializeWebView(webView2XamlElement); + _iWebView2.CoreWebView2.WebMessageReceived += WebView_WebMessageReceived; + } + + void WebView_WebMessageReceived(object sender, CoreWebView2WebMessageReceivedEventArgs args) + { + Debug.WriteLine($"WebView_WebMessageReceived: {args.WebMessageAsJson}"); + + if (args.WebMessageAsJson == "\"HULLO\"") + { + Debug.Assert(get_coolwsd_server_socket_fd() != -1); + _fakeClientFd = fakeSocketSocket(); + + int rc = fakeSocketConnect(_fakeClientFd, get_coolwsd_server_socket_fd()); + Debug.Assert(rc != -1); + + fakeSocketPipe2(_closeNotificationPipeForForwardingThread); + + // Start a thread to read responses and forward them to the JavaScript. + + Task.Run(() => + { + while (true) + { + var p = new pollfd[2]; + p[0].fd = _fakeClientFd; + p[0].events = POLLIN; + p[1].fd = _closeNotificationPipeForForwardingThread[1]; + p[1].events = POLLIN; + if (fakeSocketPoll(p, 2, -1) > 0) + { + if (p[1].revents == POLLIN) + { + // The code below handling the "BYE" fake Websocket message has + // closed the other end of the + // closeNotificationPipeForForwardingThread. Let's close the + // other end too just for cleanliness, even if a FakeSocket as + // such is not a system resource so nothing is saved by closing + // it. + fakeSocketClose(_closeNotificationPipeForForwardingThread[1]); + + // Close our end of the fake socket connection to the + // ClientSession thread, so that it terminates + fakeSocketClose(_fakeClientFd); + + return; + } + if (p[0].revents == POLLIN) + { + long n = fakeSocketAvailableDataLength(_fakeClientFd); + // I don't want to check for n being -1 here, even if that will + // lead to a crash, as n being -1 is a sign of something being + // wrong elsewhere anyway, and I prefer to fix the root cause. + // Let's see how well this works out. + if (n == 0) + return; + var buf = new byte[n]; + n = fakeSocketRead(_fakeClientFd, buf, n); + send2JS(buf, n); + } + } + else + { + break; + } + } + Debug.Assert(false); + }); + } + } + + private void SetWebView(IWebView2 newWebView2) + { + webView2XamlElement = newWebView2 as WebView2; + _iWebView2 = newWebView2; + + // We display the type of control in the window title, so update that now. + UpdateTitle(); + } + + async Task InitializeWebView(IWebView2 webView2) + { + AttachControlEventHandlers(webView2); + webView2.DefaultBackgroundColor = System.Drawing.Color.Transparent; + await webView2.EnsureCoreWebView2Async(); + } + + void AttachControlEventHandlers(IWebView2 control) + { + control.NavigationStarting += WebView_NavigationStarting; + control.NavigationCompleted += WebView_NavigationCompleted; + control.CoreWebView2InitializationCompleted += WebView_CoreWebView2InitializationCompleted; + } + + void WebView_NavigationStarting(object sender, CoreWebView2NavigationStartingEventArgs e) + { + _isNavigating = true; + + CoreWebView2NavigationKind kind = e.NavigationKind; + Debug.WriteLine($"CoreWebView2_NavigationStarting: NavigationKind({kind})"); + } + + void WebView_NavigationCompleted(object sender, CoreWebView2NavigationCompletedEventArgs e) + { + _isNavigating = false; + } + + Action OnWebViewFirstInitialized; + + void WebView_CoreWebView2InitializationCompleted(object sender, CoreWebView2InitializationCompletedEventArgs e) + { + IWebView2 webView = sender as IWebView2; + if (e.IsSuccess) + { + // FIXME: Temporarily when running from /windows/coda/CODA/bin/Debug. + webView.CoreWebView2.SetVirtualHostNameToFolderMapping("appassets", "..\\..\\..\\..\\..\\browser\\dist", CoreWebView2HostResourceAccessKind.DenyCors); + webView.CoreWebView2.Navigate("https://appassets/cool.html?file_path=file:///C:/Users/tml/Sailing%20Yacht.odt&closebutton=1&permission=edit&appdocid=1&userinterfacemode=notebookbar&dir=ltr"); + + OnWebViewFirstInitialized?.Invoke(); + + webView.CoreWebView2.NewWindowRequested += delegate ( + object webview2, CoreWebView2NewWindowRequestedEventArgs args) + { + ProcessStartInfo startInfo = new ProcessStartInfo + { + FileName = args.Uri, + // Open the URI in the default browser. + UseShellExecute = true + }; + Process.Start(startInfo); + args.Handled = true; + }; + return; + } + + MessageBox.Show($"WebView2 creation failed with exception = {e.InitializationException}"); + } + + private bool _isMessageOfType(byte[] message, string type, long lengthOfMessage) + { + int typeLen = type.Length; + return message.SequenceEqual(System.Text.Encoding.UTF8.GetBytes(type)); + } + + void send2JS(byte[] buffer, long length) + { + bool binaryMessage = (_isMessageOfType(buffer, "tile:", length) || + _isMessageOfType(buffer, "tilecombine:", length) || + _isMessageOfType(buffer, "delta:", length) || + _isMessageOfType(buffer, "renderfont:", length) || + _isMessageOfType(buffer, "rendersearchlist:", length) || + _isMessageOfType(buffer, "windowpaint:", length)); + + string pretext = binaryMessage + ? "window.TheFakeWebSocket.onmessage({'data': window.atob('" + : "window.TheFakeWebSocket.onmessage({'data': window.b64d('"; + const string posttext = "')});"; + + string js = pretext + System.Convert.ToBase64String(buffer) + posttext; + + _iWebView2.ExecuteScriptAsync(js); + } + + void UpdateTitle() + { + this.Title = $"{GetDocumentTitle()}"; + } + + string GetDocumentTitle() + { + return _iWebView2?.CoreWebView2?.DocumentTitle ?? string.Empty; + } + + } +} diff --git a/windows/coda/CODA/Properties/AssemblyInfo.cs b/windows/coda/CODA/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000000..6f3ef09e62c80 --- /dev/null +++ b/windows/coda/CODA/Properties/AssemblyInfo.cs @@ -0,0 +1,52 @@ +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("CODA")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("CODA")] +[assembly: AssemblyCopyright("Copyright © 2024")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +//In order to begin building localizable applications, set +//CultureYouAreCodingWith in your .csproj file +//inside a . For example, if you are using US english +//in your source files, set the to en-US. Then uncomment +//the NeutralResourceLanguage attribute below. Update the "en-US" in +//the line below to match the UICulture setting in the project file. + +//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] + + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] + + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/windows/coda/CODA/Properties/Resources.Designer.cs b/windows/coda/CODA/Properties/Resources.Designer.cs new file mode 100644 index 0000000000000..e6bcd0a4a2a7d --- /dev/null +++ b/windows/coda/CODA/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace CODA.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CODA.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/windows/coda/CODA/Properties/Resources.resx b/windows/coda/CODA/Properties/Resources.resx new file mode 100644 index 0000000000000..af7dbebbacef5 --- /dev/null +++ b/windows/coda/CODA/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/windows/coda/CODA/Properties/Settings.Designer.cs b/windows/coda/CODA/Properties/Settings.Designer.cs new file mode 100644 index 0000000000000..07ebf441add14 --- /dev/null +++ b/windows/coda/CODA/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace CODA.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.11.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/windows/coda/CODA/Properties/Settings.settings b/windows/coda/CODA/Properties/Settings.settings new file mode 100644 index 0000000000000..033d7a5e9e226 --- /dev/null +++ b/windows/coda/CODA/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/windows/coda/CODALib/CODALib.vcxproj b/windows/coda/CODALib/CODALib.vcxproj new file mode 100644 index 0000000000000..da9295aa2fe73 --- /dev/null +++ b/windows/coda/CODALib/CODALib.vcxproj @@ -0,0 +1,99 @@ + + + + + Debug + x64 + + + Release + x64 + + + + 17.0 + Win32Proj + {b0e65dec-1cb0-4daa-b3ed-709f8169bc40} + CODALib + 10.0 + + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + + + + + + + + + + + + + $(SolutionDir)CODA\bin\$(Configuration)\ + + + $(SolutionDir)CODA\bin\$(Configuration)\ + + + + Level3 + true + _DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS + true + NotUsing + pch.h + stdcpp20 + stdc11 + ..;..\..\..\common;%(AdditionalIncludeDirectories) + + + Windows + true + false + + + + + Level3 + true + true + true + NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS + true + NotUsing + pch.h + stdcpp20 + stdc11 + ..;..\..\..\common;%(AdditionalIncludeDirectories) + + + Windows + true + true + true + false + + + + + + + + + + \ No newline at end of file diff --git a/windows/coda/CODALib/CODALib.vcxproj.filters b/windows/coda/CODALib/CODALib.vcxproj.filters new file mode 100644 index 0000000000000..c11d94ee50bd5 --- /dev/null +++ b/windows/coda/CODALib/CODALib.vcxproj.filters @@ -0,0 +1,27 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + + + Header Files + + + \ No newline at end of file diff --git a/windows/coda/README.txt b/windows/coda/README.txt new file mode 100644 index 0000000000000..e442c8ce41682 --- /dev/null +++ b/windows/coda/README.txt @@ -0,0 +1,26 @@ +To build CODA for Windows: + +First build LibreOffice core for Windows. Typically you would do that +the traditional way using Cygwin at the outermost level, but the +actual compiler is Visual Studio. + +Then build or install Poco. + +Then install xstd. The win64 prebuilt package should work fine. + +Then you configure online in WSL2, not in Cygwin, something like this: + +./autogen.sh +./configure --enable-windowsapp --with-app-name=CODA --with-lo-builddir=/mnt/c/Users/tml/lo/core-coda-debug --with-poco-includes=/mnt/c/Users/tml/poco-1.13.3/include --with-poco-libs=/mnt/c/Users/tml/poco-1.13.3/lib64 --with-zstd-includes=/mnt/c/Users/tml/zstd-v1.5.6-win64/include --with-zstd-libs=/mnt/c/Users/tml/zstd-v1.5.6-win64/static + +Note that this will run a bunch of checks for compiler features and +libraries (like cppunit, PAM, etc) on the WSL2 side that are +completely irrelevant. You will actually compile the code in Visual +Studio using the supplied project file and windows/coda/config.h.in. +But I haven't bothered adding lots of bypassing checks to +configure.ac. Using the Makefile (generated by all the autocrack) is +useful anyway as that is a convenient way to produce the bundled JS +thing. + +Do *not* run a "make" in the top directory. Instead, to produce the +bundled JS, go to the "browser" subdirectory and run "make" there. diff --git a/windows/coda/config.h.in b/windows/coda/config.h.in new file mode 100755 index 0000000000000..b8cd7f88e3493 --- /dev/null +++ b/windows/coda/config.h.in @@ -0,0 +1,158 @@ +/* config.h. Manually edited from config.h.in. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +#define APP_NAME "@APP_NAME@" + +/* LibreOffice core git hash if present */ +#define CORE_VERSION_HASH "@CORE_VERSION_HASH@" + +/* Whether to disable SECCOMP */ +#define DISABLE_SECCOMP 1 + +/* Whether to compile in some extra debugging support code and disable some + security pieces */ +/* When building with Xcode we define ENABLE_DEBUG when debugging, but not otherwise */ +#if !defined ENABLE_DEBUG +#define ENABLE_DEBUG 0 +#endif + +/* Whether to enable SSL */ +#define ENABLE_SSL 0 + +/* Whether to enable support key */ +#define ENABLE_SUPPORT_KEY 0 + +/* Should the Release notes message on startup should be enabled be default? + */ +#define ENABLE_WELCOME_MESSAGE 0 + +/* Should the Release notes message on startup have a dismiss button instead of an x button to close by default? + */ +#define ENABLE_WELCOME_MESSAGE_BUTTON "false" + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 0 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 0 + +/* Define to 1 if you have the `pam' library (-lpam). */ +#define HAVE_LIBPAM 0 + +/* Define to 1 if you have the header file. + */ +#define HAVE_LIBREOFFICEKIT_LIBREOFFICEKIT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LINUX_SECCOMP_H 0 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Whether OpenSSL has PKCS5_PBKDF2_HMAC() */ +#define HAVE_PKCS5_PBKDF2_HMAC 0 + +/* Define to 1 if you have the header file. */ +#define HAVE_POCO_NET_WEBSOCKET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SECURITY_PAM_APPL_H 0 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 0 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Collabora Online WebSocket server version */ +#define COOLWSD_VERSION "@COOLWSD_VERSION@" + +/* Collabora Online git hash if present */ +#define COOLWSD_VERSION_HASH "@COOLWSD_VERSION_HASH@" + +/* Path to LibreOffice installation */ +#define LO_PATH "." + +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +#undef LT_OBJDIR + +/* Limit the maximum number of open connections */ +#define MAX_CONNECTIONS 100 + +/* Limit the maximum number of open documents */ +#define MAX_DOCUMENTS 100 + +/* Define to 1 if this is a mobileapp (eg. Android) build. */ +#define MOBILEAPP 1 + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Makes config variables conditionally static, only in non-debug builds, to allow for overriding them in unit-tests. */ +#ifdef ENABLE_DEBUG +#define CONFIG_STATIC +#else +#define CONFIG_STATIC static +#endif + +/* Version number of package */ +/* #undef VERSION */ + +/* Stuff manually added just for CODA for Windows */ + +#include + +typedef ptrdiff_t ssize_t; + +#define POLLIN 0x001 +#define POLLPRI 0x002 +#define POLLOUT 0x004 +#define POLLERR 0x008 +#define POLLHUP 0x010 +#define POLLNVAL 0x020 + +struct pollfd { + int fd; + short events; + short revents; +}; + +#define MOBILEAPP 1 + +#define EXPORT extern "C" __declspec(dllexport) From 30595ad16607b4429058479c37dd832fd99ef7bc Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 6 Jan 2026 17:05:52 +0100 Subject: [PATCH 005/177] Typed access to window.ThisIsThe*App Signed-off-by: Jan Holesovsky Change-Id: Ice7a030ef2581be26323e2ca2f48821ec2dc3e16 --- browser/src/global.d.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/browser/src/global.d.ts b/browser/src/global.d.ts index f803842b0e06c..90af6316ea78a 100644 --- a/browser/src/global.d.ts +++ b/browser/src/global.d.ts @@ -357,6 +357,9 @@ interface Window { ThisIsAMobileApp: boolean; ThisIsTheEmscriptenApp: boolean; ThisIsTheGtkApp: boolean; + ThisIsTheiOSApp: boolean; + ThisIsTheMacOSApp: boolean; + ThisIsTheWindowsApp: boolean; wopiSrc: string; zoteroEnabled: boolean; accessToken: string; From f58646c6719a6e07761a1a0e44b42966b4215db6 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Thu, 31 Oct 2024 12:10:06 +0100 Subject: [PATCH 006/177] Various CODA-M commits squashed together Implement wrapper to call C++ from Swift. This even starts some COOLWSD() initialization, it is possible to see logging messages in the terminal. Rename to COWrapper, to be consistent with CODocument from iOS. Copied the webview communication code from the iOS app. Unfortunately hard to share this with the iOS app... Add code to actually instantiate the document. Attempt to load the document. This is a constructor, the fakeClientFd is always 0 here, so it was leading to an early return without trying to load the document. Bundle the example document too. Change all project paths to relative. Use the more appropriate API to load the request. This fixes the "Could not create a sandbox extension for '/'" error in the console. Signed-off-by: Jan Holesovsky Change-Id: I0398365c227e66bc7488f5b3955e3718d943129a --- macos/coda/coda-Bridging-Header.h | 1 + macos/coda/coda.xcodeproj/project.pbxproj | 128 +++++----- macos/coda/coda/AppDelegate.swift | 9 +- macos/coda/coda/CODocument.h | 36 +++ macos/coda/coda/CODocument.mm | 158 ++++++++++++ macos/coda/coda/COWrapper.h | 33 +++ macos/coda/coda/COWrapper.mm | 170 +++++++++++++ macos/coda/coda/ViewController.swift | 278 ++++++++++++++++++++-- 8 files changed, 729 insertions(+), 84 deletions(-) create mode 100644 macos/coda/coda/CODocument.h create mode 100644 macos/coda/coda/CODocument.mm create mode 100644 macos/coda/coda/COWrapper.h create mode 100644 macos/coda/coda/COWrapper.mm diff --git a/macos/coda/coda-Bridging-Header.h b/macos/coda/coda-Bridging-Header.h index 1b2cb5d6d09fe..739b135b2ec94 100644 --- a/macos/coda/coda-Bridging-Header.h +++ b/macos/coda/coda-Bridging-Header.h @@ -2,3 +2,4 @@ // Use this file to import your target's public headers that you would like to expose to Swift. // +#import "COWrapper.h" diff --git a/macos/coda/coda.xcodeproj/project.pbxproj b/macos/coda/coda.xcodeproj/project.pbxproj index 3d88df28f74aa..3b3a3e2da6db1 100644 --- a/macos/coda/coda.xcodeproj/project.pbxproj +++ b/macos/coda/coda.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + BE16C9F02CD51F58005E5960 /* hello.odt in Resources */ = {isa = PBXBuildFile; fileRef = BE16C9EF2CD51F58005E5960 /* hello.odt */; }; BE2231B82CC679DE00385A9C /* Crypto-stub.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE2231B72CC679DE00385A9C /* Crypto-stub.cpp */; }; BE2231BA2CC67FDE00385A9C /* coolwsd-fork.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE2231B92CC67FDE00385A9C /* coolwsd-fork.cpp */; }; BE2231BC2CC6804D00385A9C /* Util-mobile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE2231BB2CC6804D00385A9C /* Util-mobile.cpp */; }; @@ -69,71 +70,72 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - BE2231B72CC679DE00385A9C /* Crypto-stub.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "Crypto-stub.cpp"; path = "/Users/kendy/Projects/collabora/online/common/Crypto-stub.cpp"; sourceTree = ""; }; - BE2231B92CC67FDE00385A9C /* coolwsd-fork.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "coolwsd-fork.cpp"; path = "/Users/kendy/Projects/collabora/online/wsd/coolwsd-fork.cpp"; sourceTree = ""; }; - BE2231BB2CC6804D00385A9C /* Util-mobile.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "Util-mobile.cpp"; path = "/Users/kendy/Projects/collabora/online/common/Util-mobile.cpp"; sourceTree = ""; }; - BE22492B2CC79AD700385A9C /* cool.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = cool.html; path = /Users/kendy/Projects/collabora/online/browser/dist/cool.html; sourceTree = ""; }; - BE22492D2CC79BAE00385A9C /* bundle.css */ = {isa = PBXFileReference; lastKnownFileType = text.css; name = bundle.css; path = /Users/kendy/Projects/collabora/online/browser/dist/bundle.css; sourceTree = ""; }; - BE22492E2CC79BAE00385A9C /* bundle.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = bundle.js; path = /Users/kendy/Projects/collabora/online/browser/dist/bundle.js; sourceTree = ""; }; - BE22492F2CC79BAE00385A9C /* cool-help.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = "cool-help.html"; path = "/Users/kendy/Projects/collabora/online/browser/dist/cool-help.html"; sourceTree = ""; }; - BE2249302CC79BAE00385A9C /* device-desktop.css */ = {isa = PBXFileReference; lastKnownFileType = text.css; name = "device-desktop.css"; path = "/Users/kendy/Projects/collabora/online/browser/dist/device-desktop.css"; sourceTree = ""; }; - BE2249312CC79BAE00385A9C /* global.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = global.js; path = /Users/kendy/Projects/collabora/online/browser/dist/global.js; sourceTree = ""; }; + BE16C9EF2CD51F58005E5960 /* hello.odt */ = {isa = PBXFileReference; lastKnownFileType = file; name = hello.odt; path = ../../../test/data/hello.odt; sourceTree = ""; }; + BE2231B72CC679DE00385A9C /* Crypto-stub.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "Crypto-stub.cpp"; path = "../../../../common/Crypto-stub.cpp"; sourceTree = ""; }; + BE2231B92CC67FDE00385A9C /* coolwsd-fork.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "coolwsd-fork.cpp"; path = "../../../../wsd/coolwsd-fork.cpp"; sourceTree = ""; }; + BE2231BB2CC6804D00385A9C /* Util-mobile.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "Util-mobile.cpp"; path = "../../../../common/Util-mobile.cpp"; sourceTree = ""; }; + BE22492B2CC79AD700385A9C /* cool.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = cool.html; path = ../../../browser/dist/cool.html; sourceTree = ""; }; + BE22492D2CC79BAE00385A9C /* bundle.css */ = {isa = PBXFileReference; lastKnownFileType = text.css; name = bundle.css; path = ../../../browser/dist/bundle.css; sourceTree = ""; }; + BE22492E2CC79BAE00385A9C /* bundle.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = bundle.js; path = ../../../browser/dist/bundle.js; sourceTree = ""; }; + BE22492F2CC79BAE00385A9C /* cool-help.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = "cool-help.html"; path = "../../../browser/dist/cool-help.html"; sourceTree = ""; }; + BE2249302CC79BAE00385A9C /* device-desktop.css */ = {isa = PBXFileReference; lastKnownFileType = text.css; name = "device-desktop.css"; path = "../../../browser/dist/device-desktop.css"; sourceTree = ""; }; + BE2249312CC79BAE00385A9C /* global.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = global.js; path = ../../../browser/dist/global.js; sourceTree = ""; }; BE22AA9B2CC7AE7400385A9C /* images */ = {isa = PBXFileReference; lastKnownFileType = folder; name = images; path = ../../../browser/dist/images; sourceTree = ""; }; - BEA263522CBE38E20007435A /* Authorization.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Authorization.hpp; path = /Users/kendy/Projects/collabora/online/common/Authorization.hpp; sourceTree = ""; }; - BEA263532CBE38E20007435A /* Authorization.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Authorization.cpp; path = /Users/kendy/Projects/collabora/online/common/Authorization.cpp; sourceTree = ""; }; - BEA263542CBE38E20007435A /* ConfigUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = ConfigUtil.hpp; path = /Users/kendy/Projects/collabora/online/common/ConfigUtil.hpp; sourceTree = ""; }; - BEA263552CBE38E20007435A /* ConfigUtil.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ConfigUtil.cpp; path = /Users/kendy/Projects/collabora/online/common/ConfigUtil.cpp; sourceTree = ""; }; - BEA263562CBE38E20007435A /* FileUtil.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = FileUtil.cpp; path = /Users/kendy/Projects/collabora/online/common/FileUtil.cpp; sourceTree = ""; }; - BEA263572CBE38E20007435A /* Log.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Log.hpp; path = /Users/kendy/Projects/collabora/online/common/Log.hpp; sourceTree = ""; }; - BEA263582CBE38E20007435A /* Log.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Log.cpp; path = /Users/kendy/Projects/collabora/online/common/Log.cpp; sourceTree = ""; }; - BEA263592CBE38E20007435A /* Png.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Png.hpp; path = /Users/kendy/Projects/collabora/online/common/Png.hpp; sourceTree = ""; }; - BEA2635A2CBE38E20007435A /* Protocol.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Protocol.hpp; path = /Users/kendy/Projects/collabora/online/common/Protocol.hpp; sourceTree = ""; }; - BEA2635B2CBE38E20007435A /* Protocol.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Protocol.cpp; path = /Users/kendy/Projects/collabora/online/common/Protocol.cpp; sourceTree = ""; }; - BEA2635C2CBE38E20007435A /* Session.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Session.hpp; path = /Users/kendy/Projects/collabora/online/common/Session.hpp; sourceTree = ""; }; - BEA2635D2CBE38E20007435A /* Session.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Session.cpp; path = /Users/kendy/Projects/collabora/online/common/Session.cpp; sourceTree = ""; }; - BEA2635E2CBE38E20007435A /* SigUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = SigUtil.hpp; path = /Users/kendy/Projects/collabora/online/common/SigUtil.hpp; sourceTree = ""; }; - BEA2635F2CBE38E20007435A /* SigUtil.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SigUtil.cpp; path = /Users/kendy/Projects/collabora/online/common/SigUtil.cpp; sourceTree = ""; }; - BEA263602CBE38E20007435A /* Simd.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Simd.hpp; path = /Users/kendy/Projects/collabora/online/common/Simd.hpp; sourceTree = ""; }; - BEA263612CBE38E20007435A /* Simd.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Simd.cpp; path = /Users/kendy/Projects/collabora/online/common/Simd.cpp; sourceTree = ""; }; - BEA263622CBE38E20007435A /* SpookyV2.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SpookyV2.cpp; path = /Users/kendy/Projects/collabora/online/common/SpookyV2.cpp; sourceTree = ""; }; - BEA263632CBE38E20007435A /* StringVector.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = StringVector.hpp; path = /Users/kendy/Projects/collabora/online/common/StringVector.hpp; sourceTree = ""; }; - BEA263642CBE38E20007435A /* StringVector.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = StringVector.cpp; path = /Users/kendy/Projects/collabora/online/common/StringVector.cpp; sourceTree = ""; }; - BEA263652CBE38E20007435A /* TraceEvent.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = TraceEvent.hpp; path = /Users/kendy/Projects/collabora/online/common/TraceEvent.hpp; sourceTree = ""; }; - BEA263662CBE38E20007435A /* TraceEvent.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = TraceEvent.cpp; path = /Users/kendy/Projects/collabora/online/common/TraceEvent.cpp; sourceTree = ""; }; - BEA263672CBE38E20007435A /* Unit.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Unit.hpp; path = /Users/kendy/Projects/collabora/online/common/Unit.hpp; sourceTree = ""; }; - BEA263682CBE38E20007435A /* Unit.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Unit.cpp; path = /Users/kendy/Projects/collabora/online/common/Unit.cpp; sourceTree = ""; }; - BEA263692CBE38E20007435A /* Uri.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Uri.hpp; path = /Users/kendy/Projects/collabora/online/common/Uri.hpp; sourceTree = ""; }; - BEA2636A2CBE38E20007435A /* Uri.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Uri.cpp; path = /Users/kendy/Projects/collabora/online/common/Uri.cpp; sourceTree = ""; }; - BEA2636B2CBE38E20007435A /* Util.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Util.hpp; path = /Users/kendy/Projects/collabora/online/common/Util.hpp; sourceTree = ""; }; - BEA2636C2CBE38E20007435A /* Util.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Util.cpp; path = /Users/kendy/Projects/collabora/online/common/Util.cpp; sourceTree = ""; }; + BEA263522CBE38E20007435A /* Authorization.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Authorization.hpp; path = ../../../../common/Authorization.hpp; sourceTree = ""; }; + BEA263532CBE38E20007435A /* Authorization.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Authorization.cpp; path = ../../../../common/Authorization.cpp; sourceTree = ""; }; + BEA263542CBE38E20007435A /* ConfigUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = ConfigUtil.hpp; path = ../../../../common/ConfigUtil.hpp; sourceTree = ""; }; + BEA263552CBE38E20007435A /* ConfigUtil.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ConfigUtil.cpp; path = ../../../../common/ConfigUtil.cpp; sourceTree = ""; }; + BEA263562CBE38E20007435A /* FileUtil.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = FileUtil.cpp; path = ../../../../common/FileUtil.cpp; sourceTree = ""; }; + BEA263572CBE38E20007435A /* Log.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Log.hpp; path = ../../../../common/Log.hpp; sourceTree = ""; }; + BEA263582CBE38E20007435A /* Log.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Log.cpp; path = ../../../../common/Log.cpp; sourceTree = ""; }; + BEA263592CBE38E20007435A /* Png.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Png.hpp; path = ../../../../common/Png.hpp; sourceTree = ""; }; + BEA2635A2CBE38E20007435A /* Protocol.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Protocol.hpp; path = ../../../../common/Protocol.hpp; sourceTree = ""; }; + BEA2635B2CBE38E20007435A /* Protocol.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Protocol.cpp; path = ../../../../common/Protocol.cpp; sourceTree = ""; }; + BEA2635C2CBE38E20007435A /* Session.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Session.hpp; path = ../../../../common/Session.hpp; sourceTree = ""; }; + BEA2635D2CBE38E20007435A /* Session.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Session.cpp; path = ../../../../common/Session.cpp; sourceTree = ""; }; + BEA2635E2CBE38E20007435A /* SigUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = SigUtil.hpp; path = ../../../../common/SigUtil.hpp; sourceTree = ""; }; + BEA2635F2CBE38E20007435A /* SigUtil.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SigUtil.cpp; path = ../../../../common/SigUtil.cpp; sourceTree = ""; }; + BEA263602CBE38E20007435A /* Simd.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Simd.hpp; path = ../../../../common/Simd.hpp; sourceTree = ""; }; + BEA263612CBE38E20007435A /* Simd.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Simd.cpp; path = ../../../../common/Simd.cpp; sourceTree = ""; }; + BEA263622CBE38E20007435A /* SpookyV2.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SpookyV2.cpp; path = ../../../../common/SpookyV2.cpp; sourceTree = ""; }; + BEA263632CBE38E20007435A /* StringVector.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = StringVector.hpp; path = ../../../../common/StringVector.hpp; sourceTree = ""; }; + BEA263642CBE38E20007435A /* StringVector.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = StringVector.cpp; path = ../../../../common/StringVector.cpp; sourceTree = ""; }; + BEA263652CBE38E20007435A /* TraceEvent.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = TraceEvent.hpp; path = ../../../../common/TraceEvent.hpp; sourceTree = ""; }; + BEA263662CBE38E20007435A /* TraceEvent.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = TraceEvent.cpp; path = ../../../../common/TraceEvent.cpp; sourceTree = ""; }; + BEA263672CBE38E20007435A /* Unit.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Unit.hpp; path = ../../../../common/Unit.hpp; sourceTree = ""; }; + BEA263682CBE38E20007435A /* Unit.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Unit.cpp; path = ../../../../common/Unit.cpp; sourceTree = ""; }; + BEA263692CBE38E20007435A /* Uri.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Uri.hpp; path = ../../../../common/Uri.hpp; sourceTree = ""; }; + BEA2636A2CBE38E20007435A /* Uri.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Uri.cpp; path = ../../../../common/Uri.cpp; sourceTree = ""; }; + BEA2636B2CBE38E20007435A /* Util.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Util.hpp; path = ../../../../common/Util.hpp; sourceTree = ""; }; + BEA2636C2CBE38E20007435A /* Util.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Util.cpp; path = ../../../../common/Util.cpp; sourceTree = ""; }; BEA2637B2CBE38F50007435A /* coda-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "coda-Bridging-Header.h"; sourceTree = ""; }; BEA264152CBE7A770007435A /* Config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = ""; }; - BEA2648B2CBE986C0007435A /* DeltaSimd.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = DeltaSimd.h; path = /Users/kendy/Projects/collabora/online/kit/DeltaSimd.h; sourceTree = ""; }; - BEA2648C2CBE986C0007435A /* DeltaSimd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = DeltaSimd.c; path = /Users/kendy/Projects/collabora/online/kit/DeltaSimd.c; sourceTree = ""; }; - BEA2648D2CBE986C0007435A /* ChildSession.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ChildSession.cpp; path = /Users/kendy/Projects/collabora/online/kit/ChildSession.cpp; sourceTree = ""; }; - BEA2648E2CBE986C0007435A /* Kit.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Kit.cpp; path = /Users/kendy/Projects/collabora/online/kit/Kit.cpp; sourceTree = ""; }; - BEA2648F2CBE986C0007435A /* KitQueue.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = KitQueue.hpp; path = /Users/kendy/Projects/collabora/online/kit/KitQueue.hpp; sourceTree = ""; }; - BEA264902CBE986C0007435A /* KitQueue.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = KitQueue.cpp; path = /Users/kendy/Projects/collabora/online/kit/KitQueue.cpp; sourceTree = ""; }; - BEA264912CBE986C0007435A /* KitWebSocket.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = KitWebSocket.cpp; path = /Users/kendy/Projects/collabora/online/kit/KitWebSocket.cpp; sourceTree = ""; }; - BEA264972CBE98CD0007435A /* AsyncDNS.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = AsyncDNS.hpp; path = /Users/kendy/Projects/collabora/online/net/AsyncDNS.hpp; sourceTree = ""; }; - BEA264982CBE98CD0007435A /* FakeSocket.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = FakeSocket.cpp; path = /Users/kendy/Projects/collabora/online/net/FakeSocket.cpp; sourceTree = ""; }; - BEA264992CBE98CD0007435A /* HttpRequest.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = HttpRequest.hpp; path = /Users/kendy/Projects/collabora/online/net/HttpRequest.hpp; sourceTree = ""; }; - BEA2649A2CBE98CD0007435A /* HttpRequest.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = HttpRequest.cpp; path = /Users/kendy/Projects/collabora/online/net/HttpRequest.cpp; sourceTree = ""; }; - BEA2649B2CBE98CD0007435A /* NetUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = NetUtil.hpp; path = /Users/kendy/Projects/collabora/online/net/NetUtil.hpp; sourceTree = ""; }; - BEA2649C2CBE98CD0007435A /* NetUtil.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = NetUtil.cpp; path = /Users/kendy/Projects/collabora/online/net/NetUtil.cpp; sourceTree = ""; }; - BEA2649D2CBE98CD0007435A /* Socket.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Socket.hpp; path = /Users/kendy/Projects/collabora/online/net/Socket.hpp; sourceTree = ""; }; - BEA2649E2CBE98CD0007435A /* Socket.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Socket.cpp; path = /Users/kendy/Projects/collabora/online/net/Socket.cpp; sourceTree = ""; }; - BEA2649F2CBE98CD0007435A /* WebSocketHandler.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = WebSocketHandler.hpp; path = /Users/kendy/Projects/collabora/online/net/WebSocketHandler.hpp; sourceTree = ""; }; - BEA264A42CBE99340007435A /* ClientRequestDispatcher.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ClientRequestDispatcher.cpp; path = /Users/kendy/Projects/collabora/online/wsd/ClientRequestDispatcher.cpp; sourceTree = ""; }; - BEA264A52CBE99340007435A /* ClientSession.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ClientSession.cpp; path = /Users/kendy/Projects/collabora/online/wsd/ClientSession.cpp; sourceTree = ""; }; - BEA264A62CBE99340007435A /* COOLWSD.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = COOLWSD.cpp; path = /Users/kendy/Projects/collabora/online/wsd/COOLWSD.cpp; sourceTree = ""; }; - BEA264A72CBE99340007435A /* DocumentBroker.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = DocumentBroker.cpp; path = /Users/kendy/Projects/collabora/online/wsd/DocumentBroker.cpp; sourceTree = ""; }; - BEA264A82CBE99340007435A /* RequestDetails.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = RequestDetails.hpp; path = /Users/kendy/Projects/collabora/online/wsd/RequestDetails.hpp; sourceTree = ""; }; - BEA264A92CBE99340007435A /* RequestDetails.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = RequestDetails.cpp; path = /Users/kendy/Projects/collabora/online/wsd/RequestDetails.cpp; sourceTree = ""; }; - BEA264AA2CBE99340007435A /* RequestVettingStation.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = RequestVettingStation.cpp; path = /Users/kendy/Projects/collabora/online/wsd/RequestVettingStation.cpp; sourceTree = ""; }; - BEA264AB2CBE99340007435A /* Storage.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Storage.cpp; path = /Users/kendy/Projects/collabora/online/wsd/Storage.cpp; sourceTree = ""; }; - BEA264AC2CBE99340007435A /* TileCache.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = TileCache.cpp; path = /Users/kendy/Projects/collabora/online/wsd/TileCache.cpp; sourceTree = ""; }; - BEA264B52CBE9BEF0007435A /* Storage.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Storage.hpp; path = /Users/kendy/Projects/collabora/online/wsd/Storage.hpp; sourceTree = ""; }; + BEA2648B2CBE986C0007435A /* DeltaSimd.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = DeltaSimd.h; path = ../../../../kit/DeltaSimd.h; sourceTree = ""; }; + BEA2648C2CBE986C0007435A /* DeltaSimd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = DeltaSimd.c; path = ../../../../kit/DeltaSimd.c; sourceTree = ""; }; + BEA2648D2CBE986C0007435A /* ChildSession.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ChildSession.cpp; path = ../../../../kit/ChildSession.cpp; sourceTree = ""; }; + BEA2648E2CBE986C0007435A /* Kit.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Kit.cpp; path = ../../../../kit/Kit.cpp; sourceTree = ""; }; + BEA2648F2CBE986C0007435A /* KitQueue.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = KitQueue.hpp; path = ../../../../kit/KitQueue.hpp; sourceTree = ""; }; + BEA264902CBE986C0007435A /* KitQueue.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = KitQueue.cpp; path = ../../../../kit/KitQueue.cpp; sourceTree = ""; }; + BEA264912CBE986C0007435A /* KitWebSocket.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = KitWebSocket.cpp; path = ../../../../kit/KitWebSocket.cpp; sourceTree = ""; }; + BEA264972CBE98CD0007435A /* AsyncDNS.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = AsyncDNS.hpp; path = ../../../../net/AsyncDNS.hpp; sourceTree = ""; }; + BEA264982CBE98CD0007435A /* FakeSocket.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = FakeSocket.cpp; path = ../../../../net/FakeSocket.cpp; sourceTree = ""; }; + BEA264992CBE98CD0007435A /* HttpRequest.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = HttpRequest.hpp; path = ../../../../net/HttpRequest.hpp; sourceTree = ""; }; + BEA2649A2CBE98CD0007435A /* HttpRequest.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = HttpRequest.cpp; path = ../../../../net/HttpRequest.cpp; sourceTree = ""; }; + BEA2649B2CBE98CD0007435A /* NetUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = NetUtil.hpp; path = ../../../../net/NetUtil.hpp; sourceTree = ""; }; + BEA2649C2CBE98CD0007435A /* NetUtil.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = NetUtil.cpp; path = ../../../../net/NetUtil.cpp; sourceTree = ""; }; + BEA2649D2CBE98CD0007435A /* Socket.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Socket.hpp; path = ../../../../net/Socket.hpp; sourceTree = ""; }; + BEA2649E2CBE98CD0007435A /* Socket.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Socket.cpp; path = ../../../../net/Socket.cpp; sourceTree = ""; }; + BEA2649F2CBE98CD0007435A /* WebSocketHandler.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = WebSocketHandler.hpp; path = ../../../../net/WebSocketHandler.hpp; sourceTree = ""; }; + BEA264A42CBE99340007435A /* ClientRequestDispatcher.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ClientRequestDispatcher.cpp; path = ../../../../wsd/ClientRequestDispatcher.cpp; sourceTree = ""; }; + BEA264A52CBE99340007435A /* ClientSession.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ClientSession.cpp; path = ../../../../wsd/ClientSession.cpp; sourceTree = ""; }; + BEA264A62CBE99340007435A /* COOLWSD.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = COOLWSD.cpp; path = ../../../../wsd/COOLWSD.cpp; sourceTree = ""; }; + BEA264A72CBE99340007435A /* DocumentBroker.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = DocumentBroker.cpp; path = ../../../../wsd/DocumentBroker.cpp; sourceTree = ""; }; + BEA264A82CBE99340007435A /* RequestDetails.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = RequestDetails.hpp; path = ../../../../wsd/RequestDetails.hpp; sourceTree = ""; }; + BEA264A92CBE99340007435A /* RequestDetails.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = RequestDetails.cpp; path = ../../../../wsd/RequestDetails.cpp; sourceTree = ""; }; + BEA264AA2CBE99340007435A /* RequestVettingStation.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = RequestVettingStation.cpp; path = ../../../../wsd/RequestVettingStation.cpp; sourceTree = ""; }; + BEA264AB2CBE99340007435A /* Storage.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Storage.cpp; path = ../../../../wsd/Storage.cpp; sourceTree = ""; }; + BEA264AC2CBE99340007435A /* TileCache.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = TileCache.cpp; path = ../../../../wsd/TileCache.cpp; sourceTree = ""; }; + BEA264B52CBE9BEF0007435A /* Storage.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Storage.hpp; path = ../../../../wsd/Storage.hpp; sourceTree = ""; }; BECC4BAB2CBD3FA300A120B3 /* coda.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = coda.app; sourceTree = BUILT_PRODUCTS_DIR; }; BECC4BBC2CBD3FA400A120B3 /* codaTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = codaTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; BECC4BC62CBD3FA400A120B3 /* codaUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = codaUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -192,6 +194,7 @@ BE22492F2CC79BAE00385A9C /* cool-help.html */, BE2249302CC79BAE00385A9C /* device-desktop.css */, BE2249312CC79BAE00385A9C /* global.js */, + BE16C9EF2CD51F58005E5960 /* hello.odt */, ); path = dist; sourceTree = ""; @@ -441,6 +444,7 @@ BE22529E2CC79BAE00385A9C /* cool-help.html in Resources */, BE2253F32CC79BAE00385A9C /* device-desktop.css in Resources */, BE22557E2CC79BAE00385A9C /* global.js in Resources */, + BE16C9F02CD51F58005E5960 /* hello.odt in Resources */, BE2257AD2CC79BAE00385A9C /* bundle.css in Resources */, BE22492C2CC79AD700385A9C /* cool.html in Resources */, BEA264162CBE7A770007435A /* Config.xcconfig in Resources */, diff --git a/macos/coda/coda/AppDelegate.swift b/macos/coda/coda/AppDelegate.swift index b1754dbd1bd79..676ca2456607a 100644 --- a/macos/coda/coda/AppDelegate.swift +++ b/macos/coda/coda/AppDelegate.swift @@ -13,21 +13,18 @@ import Cocoa @main class AppDelegate: NSObject, NSApplicationDelegate { - - - func applicationDidFinishLaunching(_ aNotification: Notification) { - // Insert code here to initialize your application + // Initialize the COOLWSD + COWrapper.shared.startServer() } func applicationWillTerminate(_ aNotification: Notification) { // Insert code here to tear down your application + COWrapper.shared.stopServer() } func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { return true } - } - diff --git a/macos/coda/coda/CODocument.h b/macos/coda/coda/CODocument.h new file mode 100644 index 0000000000000..80f8a374eebb4 --- /dev/null +++ b/macos/coda/coda/CODocument.h @@ -0,0 +1,36 @@ +// -*- Mode: ObjC; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- +/* + * Copyright the Collabora Online contributors. + * + * SPDX-License-Identifier: MPL-2.0 + * + * 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/. + */ + +#import + +#define LOK_USE_UNSTABLE_API +#import + +@class WKWebView; + +@interface CODocument : NSObject { +@public + int fakeClientFd; + bool readOnly; +} + +@property NSURL *fileURL; +@property unsigned appDocId; +@property (weak) WKWebView *webView; + +/** Custom initializer */ +- (instancetype)initWithWebView:(WKWebView *)webView fileURL:(NSURL *)fileURL readOnly:(bool)readOnly; + +- (void)send2JS:(const char*)buffer length:(size_t)length; + +@end + +// vim:set shiftwidth=4 softtabstop=4 expandtab: diff --git a/macos/coda/coda/CODocument.mm b/macos/coda/coda/CODocument.mm new file mode 100644 index 0000000000000..0380c2764ba3a --- /dev/null +++ b/macos/coda/coda/CODocument.mm @@ -0,0 +1,158 @@ +// -*- Mode: ObjC; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- +/* + * Copyright the Collabora Online contributors. + * + * SPDX-License-Identifier: MPL-2.0 + * + * 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/. + */ + +#import "config.h" +#import "Foundation/Foundation.h" +#import + +#import + +#import "macos.h" +#import "CODocument.h" + +//#import "ClientSession.hpp" +//#import "DocumentBroker.hpp" +#import "FakeSocket.hpp" +//#import "Kit.hpp" +//#import "KitHelper.hpp" +#import "Log.hpp" +//#import "COOLWSD.hpp" +#import "MobileApp.hpp" +#import "Protocol.hpp" + +static inline bool isMessageOfType(const char *message, const char *type, size_t lengthOfMessage) { + // Note: message is not zero terminated but type is + size_t typeLen = strlen(type); + return (typeLen <= lengthOfMessage && !strncmp(message, type, typeLen)); +} + +@implementation CODocument + +/*- (id)contentsForType:(NSString*)typeName error:(NSError **)errorPtr { + return [NSData dataWithContentsOfFile:[copyFileURL path] options:0 error:errorPtr]; +}*/ + +// We keep a running count of opening documents here. This is not necessarily in sync with the +// DocBrokerId in DocumentBroker due to potential parallelism when opening multiple documents in +// quick succession. + +static std::atomic appDocIdCounter(1); + +- (instancetype)initWithWebView:(WKWebView *)webView fileURL:(NSURL *)fileURL readOnly:(bool)readOnly { + self = [super init]; + self.webView = webView; + self.fileURL = fileURL; + self.appDocId = appDocIdCounter++; + + fakeClientFd = fakeSocketSocket(); + + NSURL *url = [[NSBundle mainBundle] URLForResource:@"cool" withExtension:@"html"]; + NSURLComponents *components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO]; + //DocumentData::allocate(appDocId).coDocument = self; + components.queryItems = @[ [NSURLQueryItem queryItemWithName:@"file_path" value:[fileURL absoluteString]], + [NSURLQueryItem queryItemWithName:@"closebutton" value:@"1"], + [NSURLQueryItem queryItemWithName:@"permission" value:(readOnly ? @"readonly" : @"edit")], + // TODO: [NSURLQueryItem queryItemWithName:@"lang" value:app_locale], + [NSURLQueryItem queryItemWithName:@"appdocid" value:[NSString stringWithFormat:@"%u", self.appDocId]], + [NSURLQueryItem queryItemWithName:@"userinterfacemode" value:@"notebookbar"], + // Related to issue #5841: the iOS app sets the + // base text direction via the "dir" parameter + // TODO: [NSURLQueryItem queryItemWithName:@"dir" value:app_text_direction], + ]; + + NSURLRequest *request = [[NSURLRequest alloc]initWithURL:components.URL]; + [self.webView loadFileRequest:request allowingReadAccessToURL:components.URL]; + + return self; +} + +- (void)send2JS:(const char *)buffer length:(size_t)length { + //LOG_DBG("To JS: " << COOLProtocol::getAbbreviatedMessage(buffer, length).c_str()); + + bool binaryMessage = (isMessageOfType(buffer, "tile:", length) || + isMessageOfType(buffer, "tilecombine:", length) || + isMessageOfType(buffer, "delta:", length) || + isMessageOfType(buffer, "renderfont:", length) || + isMessageOfType(buffer, "rendersearchlist:", length) || + isMessageOfType(buffer, "windowpaint:", length)); + + const char *pretext = binaryMessage ? "window.TheFakeWebSocket.onmessage({'data': window.atob('" + : "window.TheFakeWebSocket.onmessage({'data': window.b64d('"; + const char *posttext = "')});"; + const size_t pretextlen = strlen(pretext); + const size_t posttextlen = strlen(posttext); + + std::vector data; + // Reserve the maxiumum possible length after encoding + // This avoids an excessive number of reallocations. This is overkill + // for non-binary messages, but most non-binary messages appear to be + // under 1K bytes in length. In contrast, it appears that binary + // messags routinely use at least 75% of the maximum possible length. + data.reserve(pretextlen + (length * 4) + posttextlen + 1); + + for (int i = 0; i < pretextlen; i++) + data.push_back(pretext[i]); + + @autoreleasepool { + const NSData * payload = [NSData dataWithBytesNoCopy:const_cast(buffer) length:length freeWhenDone:NO]; + const NSString * encodedPayload = [payload base64EncodedStringWithOptions: 0]; + const std::string_view utf8EncodedPayload = [encodedPayload UTF8String]; + + for (const char& character : utf8EncodedPayload) + data.push_back(character); + } + + for (int i = 0; i < posttextlen; i++) + data.push_back(posttext[i]); + + data.push_back(0); + + // Related to issue #5876: don't autorelease large NSStrings + // The +[NSString string...] selectors won't be released until + // an enclosing autorelease pool is released. But since we use + // ARC, we don't know where the compiler has inserted the + // autorelease pool so JS messages may not be released until + // after a very long time potentially causing an out of memory + // crash. So, use the -[[NSString alloc] init...] selectors + // instead. + NSString *js = [[NSString alloc] initWithUTF8String:data.data()]; + if (!js) { + char outBuf[length + 1]; + memcpy(outBuf, buffer, length); + outBuf[length] = '\0'; + //LOG_ERR("Couldn't create NSString with message: " << outBuf); + return; + } + + NSString *subjs = [js substringToIndex:std::min(100ul, js.length)]; + if (subjs.length < js.length) + subjs = [subjs stringByAppendingString:@"..."]; + + // LOG_TRC("Evaluating JavaScript: " << [subjs UTF8String]); + + dispatch_async(dispatch_get_main_queue(), ^{ + [self.webView evaluateJavaScript:js + completionHandler:^(id _Nullable obj, NSError * _Nullable error) + { + if (error) { + //LOG_ERR("Error after " << [subjs UTF8String] << ": " << [[error localizedDescription] UTF8String]); + NSString *jsException = error.userInfo[@"WKJavaScriptExceptionMessage"]; + //if (jsException != nil) + // LOG_ERR("JavaScript exception: " << [jsException UTF8String]); + } + } + ]; + }); +} + +@end + +// vim:set shiftwidth=4 softtabstop=4 expandtab: diff --git a/macos/coda/coda/COWrapper.h b/macos/coda/coda/COWrapper.h new file mode 100644 index 0000000000000..b52bd6cf0e669 --- /dev/null +++ b/macos/coda/coda/COWrapper.h @@ -0,0 +1,33 @@ +/* + * Copyright the Collabora Online contributors. + * + * SPDX-License-Identifier: MPL-2.0 + * + * 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/. + */ + +#import + +#import "CODocument.h" + +@interface COWrapper : NSObject { + + int closeNotificationPipeForForwardingThread[2]; + +} + +@property (class, nonatomic, readonly) COWrapper *shared; +@property (strong) CODocument *document; + +- (void) startServer; +- (void) stopServer; + +- (void)handleHULLOWithDocumentURL:(NSURL *)documentURL appDocId:(unsigned)appDocId; + ++ (void) LOG_DBG:(NSString *)message NS_SWIFT_NAME(LOG_DBG(_:)); ++ (void) LOG_ERR:(NSString *)message NS_SWIFT_NAME(LOG_ERR(_:)); ++ (void) LOG_TRC:(NSString *)message NS_SWIFT_NAME(LOG_TRC(_:)); + +@end diff --git a/macos/coda/coda/COWrapper.mm b/macos/coda/coda/COWrapper.mm new file mode 100644 index 0000000000000..f27d3572a2ff6 --- /dev/null +++ b/macos/coda/coda/COWrapper.mm @@ -0,0 +1,170 @@ +/* + * Copyright the Collabora Online contributors. + * + * SPDX-License-Identifier: MPL-2.0 + * + * 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 + +#import "COWrapper.h" +#import "macos.h" + +// Include necessary C++ headers +#include +#include +#include "Log.hpp" +#include "Util.hpp" +#include "COOLWSD.hpp" +#include "FakeSocket.hpp" + +// Declare the coolwsd pointer at global scope +COOLWSD *coolwsd = nullptr; + +/** + * Wrapper to be able to call the C++ code from Swift. + * + * The main purpose is to initialize the COOLWSD and interact with it. + */ +@implementation COWrapper + ++ (instancetype)shared { + static COWrapper *sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[self alloc] init]; + }); + return sharedInstance; +} + +- (void) startServer { + // Initialize logging + Log::initialize("Mobile", "trace", false, false, {}); + Util::setThreadName("main"); + + // Set up the logging callback + fakeSocketSetLoggingCallback([](const std::string& line) { + LOG_TRC_NOFILE(line); + }); + + // Start the COOLWSD server in a detached thread + NSLog(@"CollaboraOffice: Starting the thread"); + std::thread([]{ + assert(coolwsd == nullptr); + + // Prepare arguments for COOLWSD + char *argv[2]; + argv[0] = strdup("mobile"); + argv[1] = nullptr; + + Util::setThreadName("app"); + + while (true) { + coolwsd = new COOLWSD(); + coolwsd->run(1, argv); + delete coolwsd; + coolwsd = nullptr; // Reset the pointer after deletion + LOG_TRC("One run of COOLWSD completed"); + } + }).detach(); +} + +- (void) stopServer { + if (coolwsd) { + delete coolwsd; + coolwsd = nullptr; + } +} + +- (void)handleHULLOWithDocumentURL:(NSURL *)documentURL appDocId:(NSInteger)appDocId { + // Contact the permanently (during app lifetime) listening COOLWSD server + // "public" socket + assert(coolwsd_server_socket_fd != -1); + int rc = fakeSocketConnect(self.document->fakeClientFd, coolwsd_server_socket_fd); + assert(rc != -1); + + // Create a socket pair to notify the below thread when the document has been closed + fakeSocketPipe2(closeNotificationPipeForForwardingThread); + + // Start another thread to read responses and forward them to the JavaScript + dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), + ^{ + Util::setThreadName("app2js"); + while (true) { + struct pollfd p[2]; + p[0].fd = self.document->fakeClientFd; + p[0].events = POLLIN; + p[1].fd = self->closeNotificationPipeForForwardingThread[1]; + p[1].events = POLLIN; + if (fakeSocketPoll(p, 2, -1) > 0) { + if (p[1].revents == POLLIN) { + // The code below handling the "BYE" fake Websocket + // message has closed the other end of the + // closeNotificationPipeForForwardingThread. Let's close + // the other end too just for cleanliness, even if a + // FakeSocket as such is not a system resource so nothing + // is saved by closing it. + fakeSocketClose(self->closeNotificationPipeForForwardingThread[1]); + + // Close our end of the fake socket connection to the + // ClientSession thread, so that it terminates + fakeSocketClose(self.document->fakeClientFd); + + return; + } + if (p[0].revents == POLLIN) { + size_t n = fakeSocketAvailableDataLength(self.document->fakeClientFd); + // I don't want to check for n being -1 here, even if + // that will lead to a crash (std::length_error from the + // below std::vector constructor), as n being -1 is a + // sign of something being wrong elsewhere anyway, and I + // prefer to fix the root cause. Let's see how well this + // works out. See tdf#122543 for such a case. + if (n == 0) + return; + std::vector buf(n); + n = fakeSocketRead(self.document->fakeClientFd, buf.data(), n); + [self.document send2JS:buf.data() length:n]; + } + } + else + break; + } + assert(false); + }); + + // First we simply send the Online C++ parts the URL and the appDocId. This corresponds + // to the GET request with Upgrade to WebSocket. + std::string url([[self.document.fileURL absoluteString] UTF8String]); + struct pollfd p; + p.fd = self.document->fakeClientFd; + p.events = POLLOUT; + fakeSocketPoll(&p, 1, -1); + + // This is read in the iOS-specific code in ClientRequestDispatcher::handleIncomingMessage() in COOLWSD.cpp + std::string message(url + " " + std::to_string(self.document.appDocId)); + fakeSocketWrite(self.document->fakeClientFd, message.c_str(), message.size()); +} + +/** + * Convert NSString to std::string & call the C++ version of the logging function. + */ ++ (void) LOG_DBG:(NSString *)message { + std::string stdMessage = [message UTF8String]; + LOG_DBG(stdMessage); +} + ++ (void) LOG_ERR:(NSString *)message { + std::string stdMessage = [message UTF8String]; + LOG_ERR(stdMessage); +} + ++ (void) LOG_TRC:(NSString *)message { + std::string stdMessage = [message UTF8String]; + LOG_TRC(stdMessage); +} + +@end diff --git a/macos/coda/coda/ViewController.swift b/macos/coda/coda/ViewController.swift index dc0b86a6cca2e..3e24659c90441 100644 --- a/macos/coda/coda/ViewController.swift +++ b/macos/coda/coda/ViewController.swift @@ -13,23 +13,26 @@ import WebKit class ViewController: NSViewController, WKScriptMessageHandler, WKNavigationDelegate { + var document: CODocument! var webView: WKWebView! override func viewDidLoad() { super.viewDidLoad() - // setup jsHandler as the entry point co call back from JavaScript + // Setup jsHandler as the entry point co call back from JavaScript let contentController = WKUserContentController() - contentController.add(self, name: "jsHandler") + contentController.add(self, name: "debug") + contentController.add(self, name: "lok") + contentController.add(self, name: "error") let config = WKWebViewConfiguration() config.userContentController = contentController - // create the web view + // Create the web view webView = WKWebView(frame: .zero, configuration: config) webView.navigationDelegate = self - // add it to the view controller's view + // Add it to the view controller's view self.view.addSubview(webView) webView.translatesAutoresizingMaskIntoConstraints = false @@ -40,22 +43,265 @@ class ViewController: NSViewController, WKScriptMessageHandler, WKNavigationDele webView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor) ]) - // load the local HTML file - if let htmlPath = Bundle.main.path(forResource: "cool", ofType: "html") { - let htmlURL = URL(fileURLWithPath: htmlPath) - webView.loadFileURL(htmlURL, allowingReadAccessTo: htmlURL.deletingLastPathComponent()) - } - } - - // Send 'hello' message once the content finishes loading - func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { - webView.evaluateJavaScript("receiveMessage('hello');", completionHandler: nil) + // Load the HTML, and the document itself via that + let testFileURL = Bundle.main.url(forResource: "hello", withExtension: "odt")! + document = CODocument(webView: webView, fileURL: testFileURL, readOnly: false) } // Receive message from JavaScript func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { - if message.name == "jsHandler", let response = message.body as? String { - print("Received message from JS: \(response)") + if message.name == "error" { + if let body = message.body as? String { + COWrapper.LOG_ERR("Error from WebView: \(body)") + } + } + else if message.name == "debug" { + if let body = message.body as? String { + print("==> \(body)") + } + } + else if message.name == "lok" { + if let body = message.body as? String { + var subBody = String(body.prefix(100)) + if subBody.count < body.count { + subBody += "..." + } + COWrapper.LOG_DBG("To Online: \(subBody)") + + if body == "HULLO" { + // Now we know that the JS has started completely + COWrapper.shared.handleHULLO(withDocumentURL: document.fileURL, appDocId: document.appDocId) + return + } + else if body == "BYE" { + COWrapper.LOG_TRC("Document window terminating on JavaScript side. Closing our end of the socket.") + //self.bye() + return + } + else if body == "SLIDESHOW" { + COWrapper.LOG_ERR("TODO: Implement slideshow") + /* + + // Create the SVG for the slideshow + // You need to wrap the C++ functions used here + // Example: + // self.slideshowFile = FileUtil.createRandomTmpDir() + "/slideshow.svg" + // self.slideshowURL = URL(fileURLWithPath: self.slideshowFile) + // DocumentData.get(self.document.appDocId).loKitDocument.saveAs(self.slideshowURL.absoluteString, "svg", nil) + + // Add a new full-screen WebView displaying the slideshow + let configuration = WKWebViewConfiguration() + let userContentController = WKUserContentController() + userContentController.add(self, name: "lok") + configuration.userContentController = userContentController + + self.slideshowWebView = WKWebView(frame: .zero, configuration: configuration) + self.slideshowWebView?.becomeFirstResponder() + self.slideshowWebView?.contentMode = .scaleAspectFit + self.slideshowWebView?.translatesAutoresizingMaskIntoConstraints = false + self.slideshowWebView?.navigationDelegate = self + self.slideshowWebView?.uiDelegate = self + + self.webView.isHidden = true + + self.view.addSubview(self.slideshowWebView!) + self.view.bringSubviewToFront(self.slideshowWebView!) + + // Add constraints + if let slideshowWebView = self.slideshowWebView { + NSLayoutConstraint.activate([ + slideshowWebView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor), + slideshowWebView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor), + slideshowWebView.topAnchor.constraint(equalTo: self.view.topAnchor), + slideshowWebView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor) + ]) + } + + if let slideshowURL = self.slideshowURL { + let request = URLRequest(url: slideshowURL) + self.slideshowWebView?.load(request) + } + */ + + return + } + else if body == "EXITSLIDESHOW" { + COWrapper.LOG_ERR("TODO: Implement EXITSLIDESHOW") + /* + // Remove the slideshow file + do { + try FileManager.default.removeItem(atPath: self.slideshowFile) + } catch { + COOLWrapper.LOG_ERR("Failed to remove slideshow file: \(error)") + } + + self.slideshowWebView?.removeFromSuperview() + self.slideshowWebView = nil + self.webView.isHidden = false + */ + return + } + else if body == "PRINT" { + COWrapper.LOG_ERR("TODO: Implement PRINT") + /* + // Create the PDF to print + // You'll need to wrap the C++ functions used here + // Example: + // let printFile = FileUtil.createRandomTmpDir() + "/print.pdf" + // let printURL = URL(fileURLWithPath: printFile) + // DocumentData.get(self.document.appDocId).loKitDocument.saveAs(printURL.absoluteString, "pdf", nil) + + // Present the print panel + let printInfo = NSPrintInfo.shared + printInfo.jobName = "Document" // Adjust as needed + let printOperation = NSPrintOperation(view: self.webView) // Adjust view as needed + printOperation.printInfo = printInfo + printOperation.run() + + // Remove the temporary print file if needed + // do { + // try FileManager.default.removeItem(at: printURL) + // } catch { + // LOG_ERR("Failed to remove print file: \(error)") + // } + */ + + return + } + else if body == "FOCUSIFHWKBD" { + COWrapper.LOG_ERR("TODO: Implement FOCUSIFHWKBD") + /* + if isExternalKeyboardAttached() { + let hwKeyboardMagic = """ + { + if (window.MagicToGetHWKeyboardWorking) { + window.MagicToGetHWKeyboardWorking(); + } + } + """ + self.webView.evaluateJavaScript(hwKeyboardMagic) { (result, error) in + if let error = error { + COOLWrapper.LOG_ERR("Error after \(hwKeyboardMagic): \(error.localizedDescription)") + if let jsException = (error as NSError).userInfo["WKJavaScriptExceptionMessage"] as? String { + COOLWrapper.LOG_ERR("JavaScript exception: \(jsException)") + } + } + } + } + */ + return + } + else if body.hasPrefix("HYPERLINK") { + COWrapper.LOG_ERR("TODO: Implement HYPERLINK") + /* + let messageBodyItems = body.components(separatedBy: " ") + if messageBodyItems.count >= 2 { + if let url = URL(string: messageBodyItems[1]) { + NSWorkspace.shared.open(url) + return + } + } + */ + return + } + else if body == "FONTPICKER" { + COWrapper.LOG_ERR("TODO: Implement FONTPICKER") + /* + // Font picker is not available on macOS like on iOS, but you can use NSFontPanel + let fontManager = NSFontManager.shared + fontManager.target = self + fontManager.action = #selector(changeFont(_:)) + fontManager.orderFrontFontPanel(self) + */ + return + } + else if body.hasPrefix("downloadas ") { + COWrapper.LOG_ERR("TODO: Implement downloadas") + /* + let messageBodyItems = body.components(separatedBy: " ") + var format: String? + if messageBodyItems.count >= 2 { + for item in messageBodyItems[1...] { + if item.hasPrefix("format=") { + format = String(item.dropFirst("format=".count)) + } + } + guard let format = format else { return } + + // Handle special "direct-" formats + var adjustedFormat = format + if adjustedFormat.hasPrefix("direct-") { + adjustedFormat = String(adjustedFormat.dropFirst("direct-".count)) + } + + // Save the document in the requested format + let tmpFileDirectory = FileManager.default.temporaryDirectory.appendingPathComponent("export") + do { + try FileManager.default.createDirectory(at: tmpFileDirectory, withIntermediateDirectories: true, attributes: nil) + } catch { + COOLWrapper.LOG_ERR("Could not create directory \(tmpFileDirectory.path)") + return + } + let tmpFileName = self.document.copyFileURL.deletingPathExtension().lastPathComponent + "." + adjustedFormat + self.downloadAsTmpURL = tmpFileDirectory.appendingPathComponent(tmpFileName) + + // Remove any existing file + do { + try FileManager.default.removeItem(at: self.downloadAsTmpURL!) + } catch { + // File may not exist, ignore error + } + + // Save the document using your C++ code + // Example: + // DocumentData.get(self.document.appDocId).loKitDocument.saveAs(self.downloadAsTmpURL!.absoluteString, adjustedFormat, nil) + + // Verify the file was saved + let fileExists = FileManager.default.fileExists(atPath: self.downloadAsTmpURL!.path) + if !fileExists { + COOLWrapper.LOG_ERR("Could not save to '\(self.downloadAsTmpURL!.path)'") + return + } + + // Present a save panel to let the user choose where to save the file + let savePanel = NSSavePanel() + savePanel.directoryURL = FileManager.default.homeDirectoryForCurrentUser + savePanel.nameFieldStringValue = tmpFileName + savePanel.begin { (result) in + if result == .OK, let url = savePanel.url { + do { + try FileManager.default.copyItem(at: self.downloadAsTmpURL!, to: url) + // Remove the temporary file + try FileManager.default.removeItem(at: self.downloadAsTmpURL!) + } catch { + COOLWrapper.LOG_ERR("Error during file save: \(error)") + } + } + } + return + } + */ + return + } + else { + COWrapper.LOG_ERR("TODO implement sending to COOLWSD: \(message.name)") + /* + const char *buf = [message.body UTF8String]; + p.fd = self.document->fakeClientFd; + p.events = POLLOUT; + fakeSocketPoll(&p, 1, -1); + fakeSocketWrite(self.document->fakeClientFd, buf, strlen(buf)); + */ + } + } + } + else { + if let body = message.body as? String { + COWrapper.LOG_ERR("Unrecognized kind of message received from WebView: \(message.name):\(body)") + } + else { + COWrapper.LOG_ERR("Unrecognized kind of message received from WebView: \(message.name)") + } } } } From 7602d3c49181a6c85a7a7a91458174fa4aeec9ad Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Tue, 29 Oct 2024 19:33:33 +0200 Subject: [PATCH 007/177] Various CODA-W commits squashed together Make CODA depend on CODALib. We definitely don't have . Handle pid_t, lstat(), and link(). Handle setenv() by using _putenv_s(). Not sure if it is clean to have all these untypical things in this config.h for CODA-W. Might move them to some other header later. Add some more source files to CODALib. Making them compile for Windows requires potentially lots of work so do it a little bit at a time. Here COOLWSD.cpp, ConfigUtil.cpp, Crypto-stub.cpp, and Util-mobile.cpp. We will obviously not be able to link the resulting CODALib.dll until all relevant source files have been added. Add Windows path versions for LOBUILDDIR, POCOINCLUDE, and POCOLIB and use them in the CODALib project through a .props file that is expanded by configury. (Why the .props file uses IncludePath instead of AdditionalIncludeDirectories as the vcxproj file does I have no idea. But that was what I found on the net...) Signed-off-by: Tor Lillqvist Change-Id: Iaebb1f0c444b774e5fa6b45ac0e63b946f41b1ae --- configure.ac | 18 +++++++++++++++++- windows/coda/CODA.sln | 3 +++ windows/coda/CODALib/CODALib.vcxproj | 22 ++++++++++++++++------ windows/coda/config.h.in | 10 +++++++++- windows/coda/config.props.in | 6 ++++++ 5 files changed, 51 insertions(+), 8 deletions(-) create mode 100644 windows/coda/config.props.in diff --git a/configure.ac b/configure.ac index 45d49cdb6cb34..8f5ab3030d264 100644 --- a/configure.ac +++ b/configure.ac @@ -722,6 +722,10 @@ if test \( "$enable_iosapp" = "yes" -a `uname -s` = "Darwin" \) -o \( "$enable_w fi fi + if test "$enable_windowsapp" = "yes" ; then + LOBUILDDIR_WINDOWS=`cd "$LOBUILDDIR" && cmd.exe /c cd | tr '\\' '/' | tr -d '\r'` + fi + AC_MSG_CHECKING([for Poco include directory to build against]) if test -z "$with_poco_includes"; then AC_MSG_ERROR([You MUST use the --with-poco-includes option when configuring the mobile or Windows app build tree.]) @@ -753,6 +757,10 @@ if test \( "$enable_iosapp" = "yes" -a `uname -s` = "Darwin" \) -o \( "$enable_w CHK_FILE_VAR(POCOINCLUDE,Poco/Poco.h,Poco include,_X86) CHK_FILE_VAR(POCOINCLUDE,Poco/Poco.h,Poco include,_X86_64) + if test "$enable_windowsapp" = "yes" ; then + POCOINCLUDE_WINDOWS=`cd "$POCOINCLUDE" && cmd.exe /c cd | tr '\\' '/' | tr -d '\r'` + fi + AC_MSG_CHECKING([for Poco lib directory to build against]) if test -z "$with_poco_libs"; then AC_MSG_ERROR([You MUST use the --with-poco-libs option when configuring the mobile app build tree.]) @@ -788,6 +796,10 @@ if test \( "$enable_iosapp" = "yes" -a `uname -s` = "Darwin" \) -o \( "$enable_w CHK_FILE_VAR(POCOLIB,libPocoFoundation.a,Poco lib,_X86_64) fi + if test "$enable_windowsapp" = "yes" ; then + POCOLIB_WINDOWS=`cd "$POCOLIB" && cmd.exe /c cd | tr '\\' '/' | tr -d '\r'` + fi + if test "$ENABLE_DEBUG" = "true" ; then POCODEBUG=d fi @@ -859,6 +871,7 @@ fi AC_SUBST(LOSOURCEDIR) AC_SUBST(LOBUILDDIR) +AC_SUBST(LOBUILDDIR_WINDOWS) AC_SUBST(ANDROID_ABI) AC_SUBST(ANDROID_ABI_SPLIT) AC_SUBST(LOBUILDDIR_ARM64_V8A) @@ -868,10 +881,12 @@ AC_SUBST(POCOINCLUDE) AC_SUBST(POCOINCLUDE_ARM64_V8A) AC_SUBST(POCOINCLUDE_X86) AC_SUBST(POCOINCLUDE_X86_64) +AC_SUBST(POCOINCLUDE_WINDOWS) AC_SUBST(POCOLIB) AC_SUBST(POCOLIB_ARM64_V8A) AC_SUBST(POCOLIB_X86) AC_SUBST(POCOLIB_X86_64) +AC_SUBST(POCOLIB_WINDOWS) AC_SUBST(POCODEBUG) AC_SUBST(ZSTDINCLUDE) AC_SUBST(ZSTDINCLUDE_ARM64_V8A) @@ -2050,7 +2065,8 @@ if test "$enable_macosapp" = "yes"; then fi if test "$enable_windowsapp" = "yes"; then - AC_CONFIG_FILES([windows/coda/config.h]) + AC_CONFIG_FILES([windows/coda/config.h + windows/coda/config.props]) fi if test "$enable_androidapp" = "yes"; then diff --git a/windows/coda/CODA.sln b/windows/coda/CODA.sln index 1050ab7495995..c58c4ed0a7d44 100644 --- a/windows/coda/CODA.sln +++ b/windows/coda/CODA.sln @@ -4,6 +4,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00 VisualStudioVersion = 17.11.35327.3 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CODA", "CODA\CODA.csproj", "{4D688348-30C3-4141-B56E-ACAE0D143135}" + ProjectSection(ProjectDependencies) = postProject + {B0E65DEC-1CB0-4DAA-B3ED-709F8169BC40} = {B0E65DEC-1CB0-4DAA-B3ED-709F8169BC40} + EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CODALib", "CODALib\CODALib.vcxproj", "{B0E65DEC-1CB0-4DAA-B3ED-709F8169BC40}" EndProject diff --git a/windows/coda/CODALib/CODALib.vcxproj b/windows/coda/CODALib/CODALib.vcxproj index da9295aa2fe73..9effd74801ef5 100644 --- a/windows/coda/CODALib/CODALib.vcxproj +++ b/windows/coda/CODALib/CODALib.vcxproj @@ -21,13 +21,13 @@ DynamicLibrary true - v143 + ClangCL Unicode DynamicLibrary false - v143 + ClangCL true Unicode @@ -38,9 +38,11 @@ + + @@ -53,13 +55,14 @@ Level3 true - _DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS + _DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS;COOLWSD_CONFIGDIR=".";COOLWSD_LOGLEVEL="debug";NUM_PRESPAWN_CHILDREN="1" true NotUsing pch.h stdcpp20 stdc11 - ..;..\..\..\common;%(AdditionalIncludeDirectories) + ..;..\..\..;..\..\..\common;..\..\..\net;..\..\..\kit;..\..\..\wsd;%(AdditionalIncludeDirectories) + false Windows @@ -73,13 +76,14 @@ true true true - NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS + NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS;COOLWSD_CONFIGDIR=".";COOLWSD_LOGLEVEL="warning";NUM_PRESPAWN_CHILDREN="1" true NotUsing pch.h stdcpp20 stdc11 - ..;..\..\..\common;%(AdditionalIncludeDirectories) + ..;..\..\..;..\..\..\common;..\..\..\net;..\..\..\kit;..\..\..\wsd;%(AdditionalIncludeDirectories) + false Windows @@ -90,10 +94,16 @@ + + + + + + \ No newline at end of file diff --git a/windows/coda/config.h.in b/windows/coda/config.h.in index b8cd7f88e3493..771897cb6f61f 100755 --- a/windows/coda/config.h.in +++ b/windows/coda/config.h.in @@ -1,3 +1,4 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ /* config.h. Manually edited from config.h.in. */ /* config.h.in. Generated from configure.ac by autoheader. */ @@ -77,7 +78,7 @@ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ -#define HAVE_UNISTD_H 1 +#undef HAVE_UNISTD_H /* Collabora Online WebSocket server version */ #define COOLWSD_VERSION "@COOLWSD_VERSION@" @@ -139,6 +140,13 @@ #include typedef ptrdiff_t ssize_t; +typedef int pid_t; + +#define lstat(f,s) stat(f,s) +#define link(a, b) -1 + +// MSVC's _putenv_s doesn't do removal of environment variables, but we don't need that anyway +#define setenv(variable, value, one) _putenv_s(variable, value) #define POLLIN 0x001 #define POLLPRI 0x002 diff --git a/windows/coda/config.props.in b/windows/coda/config.props.in new file mode 100644 index 0000000000000..7e5387fb0d4ce --- /dev/null +++ b/windows/coda/config.props.in @@ -0,0 +1,6 @@ + + + @POCOINCLUDE_WINDOWS@;@LOBUILDDIR_WINDOWS@\include;$(IncludePath) + @POCOLIB_WINDOWS@;$(LibraryPath) + + From 266dc446dbd2d56538281c1135f004266256b2a4 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 4 Nov 2024 14:39:48 +0100 Subject: [PATCH 008/177] Various CODA-M commits squashed together We should probably provide the entire dir here. [At least that is how I understand the documentation.] Initializer for macOS. With this, the HULLO is sent to the app (but it crashes it ~immediately). Cosmetics. Keep the 'document' only in the ViewController. The COWrapper is just what its name says - a wrapper (between C++ and Swift, via Objective-C++), so it shouldn't keep a copy of the document. This fixes a crash when the HULLO is sent. Use the 'standard' config.h and bootstrap the lokit. Various things in configure.ac needed tweaking; and when at that, stop maintaining a copy of config.h.in, and rather make sure that the 'standard' one has everything we need for the macOS app. Copy lokit to the bundle and initialize it. Crashes early, but something starts appearing in the webview! Signed-off-by: Jan Holesovsky Change-Id: I6fbe7fccbc04351af216c0ff7b99f8146cafe3ef --- browser/js/global.js | 15 +++ configure.ac | 11 +- kit/Kit.cpp | 5 + macos/coda/coda.xcodeproj/project.pbxproj | 24 ++++ macos/coda/coda/CODocument.mm | 3 +- macos/coda/coda/COWrapper.h | 13 +- macos/coda/coda/COWrapper.mm | 32 ++--- macos/coda/coda/ViewController.swift | 2 +- macos/coda/coda/macos.h | 7 ++ macos/coda/coda/macos.mm | 9 ++ macos/coda/config.h.in | 139 ---------------------- 11 files changed, 90 insertions(+), 170 deletions(-) delete mode 100644 macos/coda/config.h.in diff --git a/browser/js/global.js b/browser/js/global.js index 82aa72455112c..1419cc5dc76a3 100644 --- a/browser/js/global.js +++ b/browser/js/global.js @@ -477,6 +477,19 @@ class IOSAppInitializer extends MobileAppInitializer { } } +class MacOSAppInitializer extends MobileAppInitializer { + constructor() { + super(); + + window.ThisIsTheMacOSApp = true; + window.postMobileMessage = function(msg) { window.webkit.messageHandlers.lok.postMessage(msg); }; + window.postMobileError = function(msg) { window.webkit.messageHandlers.error.postMessage(msg); }; + window.postMobileDebug = function(msg) { window.webkit.messageHandlers.debug.postMessage(msg); }; + + window.userInterfaceMode = window.coolParams.get('userinterfacemode'); + } +} + class GTKAppInitializer extends MobileAppInitializer { constructor() { super(); @@ -544,6 +557,8 @@ function getInitializerClass() { if (osType === "IOS") return new IOSAppInitializer(); + else if (osType === "MACOS") + return new MacOSAppInitializer(); else if (osType === "GTK") return new GTKAppInitializer(); else if (osType === "WINDOWS") diff --git a/configure.ac b/configure.ac index 8f5ab3030d264..73e608987d77b 100644 --- a/configure.ac +++ b/configure.ac @@ -1332,7 +1332,7 @@ AS_IF([test -n "$LOKIT_PATH"], [CPPFLAGS="$CPPFLAGS -I${LOKIT_PATH}"]) lokit_msg="$LOKIT_PATH" -AS_IF([test "$ENABLE_IOSAPP" != "true" -a "$ENABLE_MACOSAPP" != "true" -a "$ENABLE_WINDOWSAPP" != "true" -a "$ENABLE_ANDROIDAPP" != "true"], +AS_IF([test "$ENABLE_IOSAPP" != "true" -a "$ENABLE_WINDOWSAPP" != "true" -a "$ENABLE_ANDROIDAPP" != "true"], [AC_MSG_CHECKING([for LibreOffice path]) if test -n "$with_lo_path"; then # strip trailing '/' from LO_PATH, 'ln -s' with such path will otherwise fail @@ -1448,8 +1448,8 @@ AM_CONDITIONAL([ENABLE_DEBUG], [test "$ENABLE_DEBUG" = "true"]) mobile_app= ENABLE_MOBILEAPP= MOBILEAPP=0 -AC_MSG_CHECKING([if this is a mobile app]) -if test "$enable_gtkapp" = "yes" -o "$enable_iosapp" = "yes" -o "$enable_windowsapp" = "yes" -o "$enable_androidapp" = "yes" -o "$host_os" = "emscripten" ; then +AC_MSG_CHECKING([whether this is a mobile app]) +if test "$enable_gtkapp" = "yes" -o "$enable_iosapp" = "yes" -o "$enable_macosapp" = "yes" -o "$enable_windowsapp" = "yes" -o "$enable_androidapp" = "yes" -o "$host_os" = "emscripten" ; then AC_MSG_RESULT([yes]) mobile_app=true; MOBILEAPP=1 @@ -2046,7 +2046,7 @@ AC_CONFIG_FILES([Makefile # maintain config.h.in and config_version.h.in manually # config.h.in is for configurable variables that are stable if configure parameters are unchanged -if test "$enable_iosapp" != "yes" -a "$enable_macosapp" != "yes" -a "$enable_windowsapp" != "yes"; then +if test "$enable_iosapp" != "yes" -a "$enable_windowsapp" != "yes"; then AC_CONFIG_HEADERS([config.h]) fi @@ -2060,8 +2060,7 @@ if test "$enable_iosapp" = "yes"; then fi if test "$enable_macosapp" = "yes"; then - AC_CONFIG_FILES([macos/coda/config.h - macos/coda/Config.xcconfig]) + AC_CONFIG_FILES([macos/coda/Config.xcconfig]) fi if test "$enable_windowsapp" = "yes"; then diff --git a/kit/Kit.cpp b/kit/Kit.cpp index cd1b8a5a2df5b..3391dfba2f198 100644 --- a/kit/Kit.cpp +++ b/kit/Kit.cpp @@ -113,6 +113,9 @@ #ifdef IOS #include "ios.h" #include "DocumentBroker.hpp" +#elif defined(MACOS) +#include "macos.h" +#include "DocumentBroker.hpp" #endif using Poco::Exception; @@ -3932,6 +3935,8 @@ void lokit_main( #if (defined(__linux__) && !defined(__ANDROID__)) || defined(__FreeBSD__) Poco::URI userInstallationURI("file", LO_PATH); LibreOfficeKit *kit = lok_init_2(LO_PATH "/program", userInstallationURI.toString().c_str()); +#elif defined(MACOS) + LibreOfficeKit *kit = lok_init_2((getBundlePath() + "/Contents/lokit/Frameworks").c_str(), ("file://" + getBundlePath() + "/Contents/lokit").c_str()); #else #ifdef IOS // In the iOS app we call lok_init_2() just once, when the app starts diff --git a/macos/coda/coda.xcodeproj/project.pbxproj b/macos/coda/coda.xcodeproj/project.pbxproj index 3b3a3e2da6db1..be57192ae063e 100644 --- a/macos/coda/coda.xcodeproj/project.pbxproj +++ b/macos/coda/coda.xcodeproj/project.pbxproj @@ -328,6 +328,7 @@ BECC4BA72CBD3FA300A120B3 /* Sources */, BECC4BA82CBD3FA300A120B3 /* Frameworks */, BECC4BA92CBD3FA300A120B3 /* Resources */, + BEE076602CDA3024004111EF /* ShellScript */, ); buildRules = ( ); @@ -467,6 +468,27 @@ }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + BEE076602CDA3024004111EF /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n\nLO_PATH=/Users/kendy/Projects/lo/core/instdir/CollaboraOffice.app\nrsync -a $LO_PATH/Contents/ ${CONFIGURATION_BUILD_DIR}/${TARGET_NAME}.app/Contents/lokit/\n\n"; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ BECC4BA72CBD3FA300A120B3 /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -718,6 +740,7 @@ CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = J4FQ687VJK; ENABLE_HARDENED_RUNTIME = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_NSHumanReadableCopyright = ""; INFOPLIST_KEY_NSMainStoryboardFile = Main; @@ -748,6 +771,7 @@ CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = J4FQ687VJK; ENABLE_HARDENED_RUNTIME = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_NSHumanReadableCopyright = ""; INFOPLIST_KEY_NSMainStoryboardFile = Main; diff --git a/macos/coda/coda/CODocument.mm b/macos/coda/coda/CODocument.mm index 0380c2764ba3a..1a84b6330e7a1 100644 --- a/macos/coda/coda/CODocument.mm +++ b/macos/coda/coda/CODocument.mm @@ -69,7 +69,8 @@ - (instancetype)initWithWebView:(WKWebView *)webView fileURL:(NSURL *)fileURL re ]; NSURLRequest *request = [[NSURLRequest alloc]initWithURL:components.URL]; - [self.webView loadFileRequest:request allowingReadAccessToURL:components.URL]; + NSURL *urlDir = [url URLByDeletingLastPathComponent]; + [self.webView loadFileRequest:request allowingReadAccessToURL:urlDir]; return self; } diff --git a/macos/coda/coda/COWrapper.h b/macos/coda/coda/COWrapper.h index b52bd6cf0e669..7a819cbbbbb1b 100644 --- a/macos/coda/coda/COWrapper.h +++ b/macos/coda/coda/COWrapper.h @@ -19,15 +19,14 @@ } @property (class, nonatomic, readonly) COWrapper *shared; -@property (strong) CODocument *document; -- (void) startServer; -- (void) stopServer; +- (void)startServer; +- (void)stopServer; -- (void)handleHULLOWithDocumentURL:(NSURL *)documentURL appDocId:(unsigned)appDocId; +- (void)handleHULLOWithDocument:(CODocument *)document; -+ (void) LOG_DBG:(NSString *)message NS_SWIFT_NAME(LOG_DBG(_:)); -+ (void) LOG_ERR:(NSString *)message NS_SWIFT_NAME(LOG_ERR(_:)); -+ (void) LOG_TRC:(NSString *)message NS_SWIFT_NAME(LOG_TRC(_:)); ++ (void)LOG_DBG:(NSString *)message NS_SWIFT_NAME(LOG_DBG(_:)); ++ (void)LOG_ERR:(NSString *)message NS_SWIFT_NAME(LOG_ERR(_:)); ++ (void)LOG_TRC:(NSString *)message NS_SWIFT_NAME(LOG_TRC(_:)); @end diff --git a/macos/coda/coda/COWrapper.mm b/macos/coda/coda/COWrapper.mm index f27d3572a2ff6..2d8274360e727 100644 --- a/macos/coda/coda/COWrapper.mm +++ b/macos/coda/coda/COWrapper.mm @@ -40,7 +40,7 @@ + (instancetype)shared { return sharedInstance; } -- (void) startServer { +- (void)startServer { // Initialize logging Log::initialize("Mobile", "trace", false, false, {}); Util::setThreadName("main"); @@ -72,18 +72,18 @@ - (void) startServer { }).detach(); } -- (void) stopServer { +- (void)stopServer { if (coolwsd) { delete coolwsd; coolwsd = nullptr; } } -- (void)handleHULLOWithDocumentURL:(NSURL *)documentURL appDocId:(NSInteger)appDocId { +- (void)handleHULLOWithDocument:(CODocument *)document { // Contact the permanently (during app lifetime) listening COOLWSD server // "public" socket assert(coolwsd_server_socket_fd != -1); - int rc = fakeSocketConnect(self.document->fakeClientFd, coolwsd_server_socket_fd); + int rc = fakeSocketConnect(document->fakeClientFd, coolwsd_server_socket_fd); assert(rc != -1); // Create a socket pair to notify the below thread when the document has been closed @@ -95,7 +95,7 @@ - (void)handleHULLOWithDocumentURL:(NSURL *)documentURL appDocId:(NSInteger)appD Util::setThreadName("app2js"); while (true) { struct pollfd p[2]; - p[0].fd = self.document->fakeClientFd; + p[0].fd = document->fakeClientFd; p[0].events = POLLIN; p[1].fd = self->closeNotificationPipeForForwardingThread[1]; p[1].events = POLLIN; @@ -111,12 +111,12 @@ - (void)handleHULLOWithDocumentURL:(NSURL *)documentURL appDocId:(NSInteger)appD // Close our end of the fake socket connection to the // ClientSession thread, so that it terminates - fakeSocketClose(self.document->fakeClientFd); + fakeSocketClose(document->fakeClientFd); return; } if (p[0].revents == POLLIN) { - size_t n = fakeSocketAvailableDataLength(self.document->fakeClientFd); + size_t n = fakeSocketAvailableDataLength(document->fakeClientFd); // I don't want to check for n being -1 here, even if // that will lead to a crash (std::length_error from the // below std::vector constructor), as n being -1 is a @@ -126,8 +126,8 @@ - (void)handleHULLOWithDocumentURL:(NSURL *)documentURL appDocId:(NSInteger)appD if (n == 0) return; std::vector buf(n); - n = fakeSocketRead(self.document->fakeClientFd, buf.data(), n); - [self.document send2JS:buf.data() length:n]; + n = fakeSocketRead(document->fakeClientFd, buf.data(), n); + [document send2JS:buf.data() length:n]; } } else @@ -138,31 +138,31 @@ - (void)handleHULLOWithDocumentURL:(NSURL *)documentURL appDocId:(NSInteger)appD // First we simply send the Online C++ parts the URL and the appDocId. This corresponds // to the GET request with Upgrade to WebSocket. - std::string url([[self.document.fileURL absoluteString] UTF8String]); + std::string url([[document.fileURL absoluteString] UTF8String]); struct pollfd p; - p.fd = self.document->fakeClientFd; + p.fd = document->fakeClientFd; p.events = POLLOUT; fakeSocketPoll(&p, 1, -1); // This is read in the iOS-specific code in ClientRequestDispatcher::handleIncomingMessage() in COOLWSD.cpp - std::string message(url + " " + std::to_string(self.document.appDocId)); - fakeSocketWrite(self.document->fakeClientFd, message.c_str(), message.size()); + std::string message(url + " " + std::to_string(document.appDocId)); + fakeSocketWrite(document->fakeClientFd, message.c_str(), message.size()); } /** * Convert NSString to std::string & call the C++ version of the logging function. */ -+ (void) LOG_DBG:(NSString *)message { ++ (void)LOG_DBG:(NSString *)message { std::string stdMessage = [message UTF8String]; LOG_DBG(stdMessage); } -+ (void) LOG_ERR:(NSString *)message { ++ (void)LOG_ERR:(NSString *)message { std::string stdMessage = [message UTF8String]; LOG_ERR(stdMessage); } -+ (void) LOG_TRC:(NSString *)message { ++ (void)LOG_TRC:(NSString *)message { std::string stdMessage = [message UTF8String]; LOG_TRC(stdMessage); } diff --git a/macos/coda/coda/ViewController.swift b/macos/coda/coda/ViewController.swift index 3e24659c90441..7d954c0363e3a 100644 --- a/macos/coda/coda/ViewController.swift +++ b/macos/coda/coda/ViewController.swift @@ -70,7 +70,7 @@ class ViewController: NSViewController, WKScriptMessageHandler, WKNavigationDele if body == "HULLO" { // Now we know that the JS has started completely - COWrapper.shared.handleHULLO(withDocumentURL: document.fileURL, appDocId: document.appDocId) + COWrapper.shared.handleHULLO(with: document) return } else if body == "BYE" { diff --git a/macos/coda/coda/macos.h b/macos/coda/coda/macos.h index 29e1fcbdab35f..1fa74c8266416 100644 --- a/macos/coda/coda/macos.h +++ b/macos/coda/coda/macos.h @@ -11,10 +11,17 @@ #include +#include + extern const char *user_name; extern int coolwsd_server_socket_fd; extern LibreOfficeKit *lo_kit; +/** + * Get the own installation path. + */ +std::string getBundlePath(); + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/macos/coda/coda/macos.mm b/macos/coda/coda/macos.mm index bbd6b785e3c81..171374210fca1 100644 --- a/macos/coda/coda/macos.mm +++ b/macos/coda/coda/macos.mm @@ -15,4 +15,13 @@ LibreOfficeKit *lo_kit; +std::string getBundlePath() { + static std::string bundlePath; + if (bundlePath.empty()) { + NSString *path = [[NSBundle mainBundle] bundlePath]; + bundlePath = std::string([path UTF8String]); + } + return bundlePath; +} + // vim:set shiftwidth=4 softtabstop=4 expandtab: diff --git a/macos/coda/config.h.in b/macos/coda/config.h.in deleted file mode 100644 index cf2d2a5caa56f..0000000000000 --- a/macos/coda/config.h.in +++ /dev/null @@ -1,139 +0,0 @@ -/* config.h. Manually edited from config.h.in. */ -/* config.h.in. Generated from configure.ac by autoheader. */ - -#define APP_NAME "@APP_NAME@" - -/* LibreOffice core git hash if present */ -#define CORE_VERSION_HASH "@CORE_VERSION_HASH@" - -/* Whether to disable SECCOMP */ -#define DISABLE_SECCOMP 1 - -/* Whether to compile in some extra debugging support code and disable some - security pieces */ -/* When building with Xcode we define ENABLE_DEBUG when debugging, but not otherwise */ -#if !defined ENABLE_DEBUG -#define ENABLE_DEBUG 0 -#endif - -/* Whether to enable SSL */ -#define ENABLE_SSL 0 - -/* Whether to enable support key */ -#define ENABLE_SUPPORT_KEY 0 - -/* Should the Release notes message on startup should be enabled be default? - */ -#define ENABLE_WELCOME_MESSAGE 0 - -/* Should the Release notes message on startup have a dismiss button instead of an x button to close by default? - */ -#define ENABLE_WELCOME_MESSAGE_BUTTON "false" - -/* Define to 1 if you have the header file. */ -#define HAVE_DLFCN_H 0 - -/* Define to 1 if you have the header file. */ -#define HAVE_INTTYPES_H 0 - -/* Define to 1 if you have the `pam' library (-lpam). */ -#define HAVE_LIBPAM 0 - -/* Define to 1 if you have the header file. - */ -#define HAVE_LIBREOFFICEKIT_LIBREOFFICEKIT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_LINUX_SECCOMP_H 0 - -/* Define to 1 if you have the header file. */ -#define HAVE_MEMORY_H 1 - -/* Whether OpenSSL has PKCS5_PBKDF2_HMAC() */ -#define HAVE_PKCS5_PBKDF2_HMAC 0 - -/* Define to 1 if you have the header file. */ -#define HAVE_POCO_NET_WEBSOCKET_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SECURITY_PAM_APPL_H 0 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRINGS_H 0 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_UNISTD_H 1 - -/* Collabora Online WebSocket server version */ -#define COOLWSD_VERSION "@COOLWSD_VERSION@" - -/* Collabora Online git hash if present */ -#define COOLWSD_VERSION_HASH "@COOLWSD_VERSION_HASH@" - -/* Path to LibreOffice installation */ -#define LO_PATH "." - -/* Define to the sub-directory where libtool stores uninstalled libraries. */ -#undef LT_OBJDIR - -/* Limit the maximum number of open connections */ -#define MAX_CONNECTIONS 100 - -/* Limit the maximum number of open documents */ -#define MAX_DOCUMENTS 100 - -/* Define to 1 if this is a mobileapp (eg. Android) build. */ -#define MOBILEAPP 1 - -/* Name of package */ -#undef PACKAGE - -/* Define to the address where bug reports for this package should be sent. */ -#undef PACKAGE_BUGREPORT - -/* Define to the full name of this package. */ -#undef PACKAGE_NAME - -/* Define to the full name and version of this package. */ -#undef PACKAGE_STRING - -/* Define to the one symbol short name of this package. */ -#undef PACKAGE_TARNAME - -/* Define to the home page for this package. */ -#undef PACKAGE_URL - -/* Define to the version of this package. */ -#undef PACKAGE_VERSION - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Makes config variables conditionally static, only in non-debug builds, to allow for overriding them in unit-tests. */ -#ifdef ENABLE_DEBUG -#define CONFIG_STATIC -#else -#define CONFIG_STATIC static -#endif - -/* Version number of package */ -/* #undef VERSION */ - -/* This config.h is used only in CODA for macOS app, thus we don't need the Windows version of EXPORT here */ - -#define EXPORT /**/ From 8fd14ee2973769fcaed48d2e65734556ba3b2b0a Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Tue, 5 Nov 2024 17:05:47 +0200 Subject: [PATCH 009/177] Various CODA-W commits squashed together Add ZSTDINCLUDE_WINDOWS and ZSTDLIB_WINDOWS. Add zlib include and lib directory setting for Windows. Also improve syntax in the tr invocation to turn backslashes into slashes for the *_WINDOWS substitution variables, to avoid a warning. Apparently we need four backslashes. Also add a missing AC_MSG_CHECKING for the corresponding AC_MSG_RESULT inside the CHK_FILE_VAR function. Handle localtime_r() and gmtime_r(). Add more source files to the CODALib project. Also dos2unixify the project files. The changes to make these files compile on Windows are still very unclean on my local disk only. Will have to clean them up substantially before I commit. And yeah, thre are still several source files missing, so the linking fails. Adding them one by one, fixing compilation errors one file at a time. Signed-off-by: Tor Lillqvist Change-Id: I7593219c23bf0ad3602a9751bdd8e1510e92b67d --- configure.ac | 54 +++++++++++++++++--- windows/coda/CODA.sln | 2 +- windows/coda/CODALib/CODALib.vcxproj | 20 +++++--- windows/coda/CODALib/CODALib.vcxproj.filters | 54 +++++++++++++++++--- windows/coda/config.h.in | 3 ++ windows/coda/config.props.in | 4 +- 6 files changed, 114 insertions(+), 23 deletions(-) diff --git a/configure.ac b/configure.ac index 73e608987d77b..0b383ee9de23f 100644 --- a/configure.ac +++ b/configure.ac @@ -320,6 +320,16 @@ AC_ARG_WITH([libpng-libs], [Path to the "lib" directory with the libpng libraries. Not used on Android.])) +AC_ARG_WITH([zlib-includes], + AS_HELP_STRING([--with-zlib-includes=], + [Path to the "include" directory with the libpng + headers. Only used on Windows.])) + +AC_ARG_WITH([zlib-libs], + AS_HELP_STRING([--with-zlib-libs=], + [Path to the "lib" directory with the zlib + libraries. Only used on Windows.])) + AC_ARG_WITH([cppunit-includes], AS_HELP_STRING([--with-cppunit-includes=], [Path to the "include" directory with the Cppunit headers])) @@ -723,7 +733,7 @@ if test \( "$enable_iosapp" = "yes" -a `uname -s` = "Darwin" \) -o \( "$enable_w fi if test "$enable_windowsapp" = "yes" ; then - LOBUILDDIR_WINDOWS=`cd "$LOBUILDDIR" && cmd.exe /c cd | tr '\\' '/' | tr -d '\r'` + LOBUILDDIR_WINDOWS=`cd "$LOBUILDDIR" && cmd.exe /c cd | tr '\\\\' '/' | tr -d '\r'` fi AC_MSG_CHECKING([for Poco include directory to build against]) @@ -758,7 +768,7 @@ if test \( "$enable_iosapp" = "yes" -a `uname -s` = "Darwin" \) -o \( "$enable_w CHK_FILE_VAR(POCOINCLUDE,Poco/Poco.h,Poco include,_X86_64) if test "$enable_windowsapp" = "yes" ; then - POCOINCLUDE_WINDOWS=`cd "$POCOINCLUDE" && cmd.exe /c cd | tr '\\' '/' | tr -d '\r'` + POCOINCLUDE_WINDOWS=`cd "$POCOINCLUDE" && cmd.exe /c cd | tr '\\\\' '/' | tr -d '\r'` fi AC_MSG_CHECKING([for Poco lib directory to build against]) @@ -797,14 +807,14 @@ if test \( "$enable_iosapp" = "yes" -a `uname -s` = "Darwin" \) -o \( "$enable_w fi if test "$enable_windowsapp" = "yes" ; then - POCOLIB_WINDOWS=`cd "$POCOLIB" && cmd.exe /c cd | tr '\\' '/' | tr -d '\r'` + POCOLIB_WINDOWS=`cd "$POCOLIB" && cmd.exe /c cd | tr '\\\\' '/' | tr -d '\r'` fi if test "$ENABLE_DEBUG" = "true" ; then POCODEBUG=d fi - AC_MSG_CHECKING([for zstd directories to build against]) + AC_MSG_CHECKING([for zstd include directory to build against]) if test -z "$with_zstd_includes"; then AC_MSG_ERROR([You MUST use the --with-zstd-includes option when configuring the mobile or Windows app build tree.]) fi @@ -839,6 +849,12 @@ if test \( "$enable_iosapp" = "yes" -a `uname -s` = "Darwin" \) -o \( "$enable_w CHK_FILE_VAR(ZSTDINCLUDE,zstd.h,Zstd include,_X86) CHK_FILE_VAR(ZSTDINCLUDE,zstd.h,Zstd include,_X86_64) + if test "$enable_windowsapp" = "yes" ; then + ZSTDINCLUDE_WINDOWS=`cd "$ZSTDINCLUDE" && cmd.exe /c cd | tr '\\\\' '/' | tr -d '\r'` + fi + + AC_MSG_CHECKING([for zstd lib directory to build against]) + ZSTDLIB="$with_zstd_libs" if test "$enable_androidapp" = "yes" ; then if echo "$ZSTDLIB" | grep -qs ':' ; then @@ -867,6 +883,10 @@ if test \( "$enable_iosapp" = "yes" -a `uname -s` = "Darwin" \) -o \( "$enable_w CHK_FILE_VAR(ZSTDLIB,libzstd.a,Zstd lib,_X86) CHK_FILE_VAR(ZSTDLIB,libzstd.a,Zstd lib,_X86_64) fi + + if test "$enable_windowsapp" = "yes" ; then + ZSTDLIB_WINDOWS=`cd "$ZSTDLIB" && cmd.exe /c cd | tr '\\\\' '/' | tr -d '\r'` + fi fi AC_SUBST(LOSOURCEDIR) @@ -892,10 +912,12 @@ AC_SUBST(ZSTDINCLUDE) AC_SUBST(ZSTDINCLUDE_ARM64_V8A) AC_SUBST(ZSTDINCLUDE_X86) AC_SUBST(ZSTDINCLUDE_X86_64) +AC_SUBST(ZSTDINCLUDE_WINDOWS) AC_SUBST(ZSTDLIB) AC_SUBST(ZSTDLIB_ARM64_V8A) AC_SUBST(ZSTDLIB_X86) AC_SUBST(ZSTDLIB_X86_64) +AC_SUBST(ZSTDLIB_WINDOWS) AC_SUBST([CORE_VERSION_HASH]) AC_DEFINE_UNQUOTED([CORE_VERSION_HASH],[["$CORE_VERSION_HASH"]],[LibreOffice core git hash if present]) @@ -903,6 +925,27 @@ AC_DEFINE_UNQUOTED([CORE_VERSION_HASH],[["$CORE_VERSION_HASH"]],[LibreOffice cor LIBPNG_INCLUDES="$with_libpng_includes" LIBPNG_LIBS="$with_libpng_libs" +if test "$enable_windowsapp" = "yes" ; then + LIBPNG_INCLUDES_WINDOWS=`cd "$LIBPNG_INCLUDES" && cmd.exe /c cd | tr '\\\\' '/' | tr -d '\r'` + LIBPNG_LIBS_WINDOWS=`cd "$LIBPNG_LIBS" && cmd.exe /c cd | tr '\\\\' '/' | tr -d '\r'` +fi + +AC_SUBST(LIBPNG_INCLUDES) +AC_SUBST(LIBPNG_INCLUDES_WINDOWS) +AC_SUBST(LIBPNG_LIBS) +AC_SUBST(LIBPNG_LIBS_WINDOWS) + +ZLIB_INCLUDES="$with_zlib_includes" +ZLIB_LIBS="$with_zlib_libs" + +if test "$enable_windowsapp" = "yes" ; then + ZLIB_INCLUDES_WINDOWS=`cd "$ZLIB_INCLUDES" && cmd.exe /c cd | tr '\\\\' '/' | tr -d '\r'` + ZLIB_LIBS_WINDOWS=`cd "$ZLIB_LIBS" && cmd.exe /c cd | tr '\\\\' '/' | tr -d '\r'` +fi + +AC_SUBST(ZLIB_INCLUDES_WINDOWS) +AC_SUBST(ZLIB_LIBS_WINDOWS) + if test "$enable_iosapp" != yes -a "$enable_windowsapp" != yes -a "$enable_androidapp" != yes; then LOKIT_PATH=`readlink -f $with_lokit_path` fi @@ -919,8 +962,7 @@ if test "$enable_iosapp" = "yes" -o "$enable_androidapp" = "yes"; then LOKIT_PATH=`readlink -f $LOBUILDDIR/include` fi fi -AC_SUBST(LIBPNG_INCLUDES) -AC_SUBST(LIBPNG_LIBS) + AC_SUBST(LOKIT_PATH) ENABLE_ANDROIDAPP= diff --git a/windows/coda/CODA.sln b/windows/coda/CODA.sln index c58c4ed0a7d44..4efa7cb42c0c2 100644 --- a/windows/coda/CODA.sln +++ b/windows/coda/CODA.sln @@ -1,4 +1,4 @@ - + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.11.35327.3 diff --git a/windows/coda/CODALib/CODALib.vcxproj b/windows/coda/CODALib/CODALib.vcxproj index 9effd74801ef5..7a649f3e894d9 100644 --- a/windows/coda/CODALib/CODALib.vcxproj +++ b/windows/coda/CODALib/CODALib.vcxproj @@ -55,7 +55,7 @@ Level3 true - _DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS;COOLWSD_CONFIGDIR=".";COOLWSD_LOGLEVEL="debug";NUM_PRESPAWN_CHILDREN="1" + _DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);NOMINMAX;_CRT_SECURE_NO_WARNINGS;COOLWSD_CONFIGDIR=".";COOLWSD_LOGLEVEL="debug";NUM_PRESPAWN_CHILDREN="1" true NotUsing pch.h @@ -76,7 +76,7 @@ true true true - NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS;COOLWSD_CONFIGDIR=".";COOLWSD_LOGLEVEL="warning";NUM_PRESPAWN_CHILDREN="1" + NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);NOMINMAX;_CRT_SECURE_NO_WARNINGS;COOLWSD_CONFIGDIR=".";COOLWSD_LOGLEVEL="warning";NUM_PRESPAWN_CHILDREN="1" true NotUsing pch.h @@ -96,14 +96,20 @@ + + + + + + + + + + + - - - - - \ No newline at end of file diff --git a/windows/coda/CODALib/CODALib.vcxproj.filters b/windows/coda/CODALib/CODALib.vcxproj.filters index c11d94ee50bd5..41329092702a5 100644 --- a/windows/coda/CODALib/CODALib.vcxproj.filters +++ b/windows/coda/CODALib/CODALib.vcxproj.filters @@ -15,13 +15,53 @@ - + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + Source Files - - - Header Files - - - \ No newline at end of file + diff --git a/windows/coda/config.h.in b/windows/coda/config.h.in index 771897cb6f61f..bdad58f5e6820 100755 --- a/windows/coda/config.h.in +++ b/windows/coda/config.h.in @@ -145,6 +145,9 @@ typedef int pid_t; #define lstat(f,s) stat(f,s) #define link(a, b) -1 +#define localtime_r(time_t_ptr, struct_tm_ptr) (localtime_s(struct_tm_ptr, time_t_ptr), struct_tm_ptr) +#define gmtime_r(time_t_ptr, struct_tm_ptr) (gmtime_s(struct_tm_ptr, time_t_ptr), struct_tm_ptr) + // MSVC's _putenv_s doesn't do removal of environment variables, but we don't need that anyway #define setenv(variable, value, one) _putenv_s(variable, value) diff --git a/windows/coda/config.props.in b/windows/coda/config.props.in index 7e5387fb0d4ce..f9303978b02fe 100644 --- a/windows/coda/config.props.in +++ b/windows/coda/config.props.in @@ -1,6 +1,6 @@ - @POCOINCLUDE_WINDOWS@;@LOBUILDDIR_WINDOWS@\include;$(IncludePath) - @POCOLIB_WINDOWS@;$(LibraryPath) + @POCOINCLUDE_WINDOWS@;@ZSTDINCLUDE_WINDOWS@;@LIBPNG_INCLUDES_WINDOWS@;@ZLIB_INCLUDES_WINDOWS@;@LOBUILDDIR_WINDOWS@\include;$(IncludePath) + @POCOLIB_WINDOWS@;@ZSTDLIB_WINDOWS@;@LIBPNG_LIBS_WINDOWS@;@ZLIB_LIBS_WINDOWS@;$(LibraryPath) From bc4904d2f3b96d09c085a52b431dc66903507612 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 11 Nov 2024 11:34:29 +0100 Subject: [PATCH 010/177] Various CODA-M commits squashed together Better lokit initialization path. Bundle and find coolkitconfig.xcu. Enable extra logging from the core in the DEVEL builds. Fix bootstrapping of the "/org.openoffice.System/L10N" config. Signed-off-by: Jan Holesovsky Change-Id: I72ffe7db54768dd038ad34d4586cb7d252730304 --- kit/Kit.cpp | 2 +- kit/SetupKitEnvironment.hpp | 11 +++++++++++ macos/coda/coda.xcodeproj/project.pbxproj | 6 ++++++ macos/coda/coda/macos.h | 5 +++++ macos/coda/coda/macos.mm | 5 +++++ wsd/COOLWSD.cpp | 4 ++++ 6 files changed, 32 insertions(+), 1 deletion(-) diff --git a/kit/Kit.cpp b/kit/Kit.cpp index 3391dfba2f198..8e5f9d49fb797 100644 --- a/kit/Kit.cpp +++ b/kit/Kit.cpp @@ -3936,7 +3936,7 @@ void lokit_main( Poco::URI userInstallationURI("file", LO_PATH); LibreOfficeKit *kit = lok_init_2(LO_PATH "/program", userInstallationURI.toString().c_str()); #elif defined(MACOS) - LibreOfficeKit *kit = lok_init_2((getBundlePath() + "/Contents/lokit/Frameworks").c_str(), ("file://" + getBundlePath() + "/Contents/lokit").c_str()); + LibreOfficeKit *kit = lok_init_2((getBundlePath() + "/Contents/lokit/Frameworks").c_str(), ("file://" + getBundlePath() + "/Contents/lokit/Resources").c_str()); #else #ifdef IOS // In the iOS app we call lok_init_2() just once, when the app starts diff --git a/kit/SetupKitEnvironment.hpp b/kit/SetupKitEnvironment.hpp index b265d3fe3b3fb..44ee33ba9821d 100644 --- a/kit/SetupKitEnvironment.hpp +++ b/kit/SetupKitEnvironment.hpp @@ -16,18 +16,29 @@ #include +#if defined(MACOS) +#include +#endif + inline void setupKitEnvironment(const std::string& userInterface) { // Setup & check environment std::string layers( +#if defined(MACOS) + "xcsxcu:${BRAND_BASE_DIR}/Resources/registry " + "res:${BRAND_BASE_DIR}/Resources/registry " +#else "xcsxcu:${BRAND_BASE_DIR}/share/registry " "res:${BRAND_BASE_DIR}/share/registry " +#endif "bundledext:${${BRAND_BASE_DIR}/program/lounorc:BUNDLED_EXTENSIONS_USER}/registry/com.sun.star.comp.deployment.configuration.PackageRegistryBackend/configmgr.ini " "sharedext:${${BRAND_BASE_DIR}/program/lounorc:SHARED_EXTENSIONS_USER}/registry/com.sun.star.comp.deployment.configuration.PackageRegistryBackend/configmgr.ini " "userext:${${BRAND_BASE_DIR}/program/lounorc:UNO_USER_PACKAGES_CACHE}/registry/com.sun.star.comp.deployment.configuration.PackageRegistryBackend/configmgr.ini " ); #ifdef IOS layers += "user:*${BRAND_BASE_DIR}/coolkitconfig.xcu "; +#elif defined(MACOS) + layers += "user:*" + getResourceURL("coolkitconfig", "xcu"); #elif ENABLE_DEBUG && !defined(ANDROID) // '*' denotes non-writable. layers += "user:*file://" DEBUG_ABSSRCDIR "/coolkitconfig.xcu "; #else diff --git a/macos/coda/coda.xcodeproj/project.pbxproj b/macos/coda/coda.xcodeproj/project.pbxproj index be57192ae063e..5eb9354fc679e 100644 --- a/macos/coda/coda.xcodeproj/project.pbxproj +++ b/macos/coda/coda.xcodeproj/project.pbxproj @@ -50,6 +50,7 @@ BEA264B22CBE99340007435A /* ClientRequestDispatcher.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA264A42CBE99340007435A /* ClientRequestDispatcher.cpp */; }; BEA264B32CBE99340007435A /* DocumentBroker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA264A72CBE99340007435A /* DocumentBroker.cpp */; }; BEA264B42CBE99340007435A /* RequestVettingStation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA264AA2CBE99340007435A /* RequestVettingStation.cpp */; }; + BEEF3F862CE2139E00ABE785 /* coolkitconfig.xcu in Resources */ = {isa = PBXBuildFile; fileRef = BEEF3F852CE2139E00ABE785 /* coolkitconfig.xcu */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -139,6 +140,8 @@ BECC4BAB2CBD3FA300A120B3 /* coda.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = coda.app; sourceTree = BUILT_PRODUCTS_DIR; }; BECC4BBC2CBD3FA400A120B3 /* codaTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = codaTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; BECC4BC62CBD3FA400A120B3 /* codaUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = codaUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + BEEF3F822CE20BDD00ABE785 /* SetupKitEnvironment.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = SetupKitEnvironment.hpp; path = ../../../../kit/SetupKitEnvironment.hpp; sourceTree = ""; }; + BEEF3F852CE2139E00ABE785 /* coolkitconfig.xcu */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = coolkitconfig.xcu; path = ../../../coolkitconfig.xcu; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFileSystemSynchronizedRootGroup section */ @@ -192,6 +195,7 @@ BE22492E2CC79BAE00385A9C /* bundle.js */, BE22492B2CC79AD700385A9C /* cool.html */, BE22492F2CC79BAE00385A9C /* cool-help.html */, + BEEF3F852CE2139E00ABE785 /* coolkitconfig.xcu */, BE2249302CC79BAE00385A9C /* device-desktop.css */, BE2249312CC79BAE00385A9C /* global.js */, BE16C9EF2CD51F58005E5960 /* hello.odt */, @@ -256,6 +260,7 @@ BEA2648F2CBE986C0007435A /* KitQueue.hpp */, BEA264902CBE986C0007435A /* KitQueue.cpp */, BEA264912CBE986C0007435A /* KitWebSocket.cpp */, + BEEF3F822CE20BDD00ABE785 /* SetupKitEnvironment.hpp */, ); path = kit; sourceTree = ""; @@ -448,6 +453,7 @@ BE16C9F02CD51F58005E5960 /* hello.odt in Resources */, BE2257AD2CC79BAE00385A9C /* bundle.css in Resources */, BE22492C2CC79AD700385A9C /* cool.html in Resources */, + BEEF3F862CE2139E00ABE785 /* coolkitconfig.xcu in Resources */, BEA264162CBE7A770007435A /* Config.xcconfig in Resources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/macos/coda/coda/macos.h b/macos/coda/coda/macos.h index 1fa74c8266416..d34ccb7d2c8ac 100644 --- a/macos/coda/coda/macos.h +++ b/macos/coda/coda/macos.h @@ -24,4 +24,9 @@ extern LibreOfficeKit *lo_kit; */ std::string getBundlePath(); +/** + * Get URL of a resource in the bundle. + */ +std::string getResourceURL(const char *name, const char *ext); + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/macos/coda/coda/macos.mm b/macos/coda/coda/macos.mm index 171374210fca1..025c8c367e2c3 100644 --- a/macos/coda/coda/macos.mm +++ b/macos/coda/coda/macos.mm @@ -24,4 +24,9 @@ return bundlePath; } +std::string getResourceURL(const char *name, const char *ext) { + NSURL *url = [[NSBundle mainBundle] URLForResource:[NSString stringWithUTF8String:name] withExtension:[NSString stringWithUTF8String:ext]]; + return std::string([[url absoluteString] UTF8String]); +} + // vim:set shiftwidth=4 softtabstop=4 expandtab: diff --git a/wsd/COOLWSD.cpp b/wsd/COOLWSD.cpp index 0dc0bc8d7081d..30663a308f9d4 100644 --- a/wsd/COOLWSD.cpp +++ b/wsd/COOLWSD.cpp @@ -1695,6 +1695,10 @@ void COOLWSD::innerInitialize(Poco::Util::Application& self) #endif // !MOBILEAPP +#if defined(MACOS) && defined(DEBUG) + setenv("SAL_LOG", "+INFO+WARN", 0); +#endif + int pdfResolution = ConfigUtil::getConfigValue(conf, "per_document.pdf_resolution_dpi", 96); if (pdfResolution > 0) From 3baf5dadc0830c5afbf0ecdbc0942fa4c301cd9e Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Mon, 11 Nov 2024 22:27:45 +0200 Subject: [PATCH 011/177] Lots of changes for CODA-W Several individual commits squashed together. Original commit messages: Add all required source files to the CODALib project. With the mass of ugly ifdefs that are not (and won't be) committed, the CODALib DLL actually now builds. I will now start cleaning up those ifdefs into more elegant solutions. Add windows.cpp and windows.hpp. This just contains a few variables. Corresponds to ios.h and ios.mm in the iOS app. Make the CODA-W config.h work better. Don't include as the config.h is included in a C file, too. We need a macro for just 'extern "C"', too. Handle strcasecmp(). Use the once pragma as config.h surprisinly gets included multiple times in at least one compilation unit. Add Util::getProcessId(). Avoid annoying warnings about getpid() when building CODA on Windows. Add a wrapper for it, similar to Util::getThreadId(). Use separate cpp files for the Unix-like and Windows alternatives. Possibly more Util functions will be changed or introduced to have two implementations split up in this way instead of using ifdefs. Use Util::getProcessId() in code that is compiled for both Windows and the others (that are all Unix-like). The idea is that functions that need separate implementations depending on platform will have these in separate files, like this: Foo-unix.cpp vs Foo-windows.cpp Foo-server.cpp vs Foo-mobile.cpp Are there other dichotomies? Util::getThreadId() and getProcessId() can be long on all platforms. Add Util-windows.cpp. Add hack to enable test compiling one header at a time for Windows. Add more ifdefs for non-portable errno codes. Not really any clean way to do this without ifdefs, is there? But yeah, could move this function into a separate source file. memrchr() is needed on Windows, too. Make Log.hpp compile on Windows while keeping things working on Unixes. Use std::chrono instead of the non-portable gettimeofday(). Introduce a new platform-dependent function to call the thread-safe version of localtime(). Pay no attention to the added to FileUtil.hpp, that is temporarily until I get to that header. Start work on FileUtil for CODA-W. Split out platform-dependent code to separate source files. The FileUtil-windows.cpp file does compile, but FileUtil.cpp does not yet, as it drags in so much other stuff that has not yet been handled. Add FileUtil-unix.cpp to the iOS app project. Drop two leftover unnecessary inclusions. I initially tried to use stuff for UTF-8 to/from UTF-16 conversion, but it turned out that was soon deprecated after being introduced. (So I just use Win32 APIs.) Introduce separate Windows implementation of FileUtil::isEmptyDirectory(). Add FileUtil::removeFile() and removeEmptyDirTree() for Windows. Move the Unix implementation to FileUtil-unix.cpp. Split out platform-dependent part of checkDiskSpace(). I already had added that to FileUtil-unix.cpp but not used it. The Windows implementation is dummy and doesn't do anything. Add a FileUtil-apple.mm for the code that is used just on iOS for now. Remove some now unnecesary platform-specific headers from FileUtil.cpp. Make FakeSocket.hpp compile on Windows. Add 'extern "C"' attributes to the function extern declarations, to match the definitions in FakeSocket.cpp. Also remove some weird leftovers defining SOCK_NONBLOCK and SOCK_CLOEXEC (if undefined) on non-Linux. I don't see why such would be needed, and if they are needed on some kind of Unix, they certainly should not be in FakeSocket.hpp. Make Socket.hpp compile on Windows. Define EXTERNC (as empty) for iOS, too. Also fix up iOS compilation problems introduced by earlier commits today. We never create and use any *real* sockets in a mobile app, as far as I can say. And "async upload" is not a thing in a mobile app, it it? Upload from where, to where? Bypass some stuff with #ifdefs for now, should clean up later if possible. Also for Windows. We cannot use compile-time checks like Util::isMobileApp() to bypass calls to code that will cause compilation errors or warnings on Windows. Bypass these two whole functions for MOBILEAPP. They aren't called in the MOBILEAPP case anyway. Make Socket.cpp compile for Windows. While making sure the iOS app still builds, and 'make check' works on Linux. Fix build of mobile apps. Introduce a separate SigUtil-mobile.cpp that is completely no-op. Use that on the mobile platforms (Android, iOS, CODA-M, CODA-W). Rename the current SigUtil.cpp to SigUtil-server.cpp to reflect its intended use only in "normal" server-based COOL. I thought this would enable me to remove a lot of ifdefs around calls to SigUtil functions, but there doesn't seem to be that many of those anyway. Oh well. In any case, good to know for sure that no SIGUSR1, SIGUSR2, signal log file, etc stuff is present in the mobile apps. (Did not actually touch Android or CODA-M projects, somebody else please do that, replace SigUtil.cpp with SigUtil-mobile.cpp. You will notice anyway that there is no SigUtil.cpp any more.) No smaps in the mobile apps. Avoid problematic identifier _timezone. In the Microsoft C library, _timezone is a macro that expands to the value of a call to a function: (*__timezone()). There is a simple heuristic rule: Don't use identifiers starting with an underscore in your own code. There is a risk that they might clash with some implementation-defined thing. But we didn't get that memo. Sure, such identifiers are perhaps supposed to be OK if not in the global namespace, but it is not very productive to argue against the compiler and library if you want to use them to build your code? See https://stackoverflow.com/a/228848/27690443 Make DocumentBroker.cpp compile on Windows. Fix bug in FileUtil::Stat() constructor. I had not noticed and taken into account the effect of the std::move() a few lines above, in this branch. After initialising the _path member with std::move(file), the file parameter is now an empty string. I dislike std::move(). Signed-off-by: Tor Lillqvist Change-Id: Ic6fc914f3bab6f4f569fcca8a36def3c236b58e0 --- common/FileUtil-windows.cpp | 174 +++++++++++++++++++ common/FileUtil.cpp | 4 + common/FileUtil.hpp | 13 +- common/Log.cpp | 2 + common/Util-windows.cpp | 31 ++++ config.h.in | 7 +- ios/config.h.in | 5 +- net/FakeSocket.cpp | 1 + net/FakeSocket.hpp | 17 ++ net/Socket.cpp | 2 + windows/coda/CODALib/CODALib.vcxproj | 25 ++- windows/coda/CODALib/CODALib.vcxproj.filters | 73 +++++++- windows/coda/config.h.in | 11 +- windows/coda/testheader.cpp | 9 + windows/coda/windows.cpp | 15 ++ windows/coda/windows.hpp | 13 ++ 16 files changed, 387 insertions(+), 15 deletions(-) create mode 100644 common/FileUtil-windows.cpp create mode 100644 common/Util-windows.cpp create mode 100755 windows/coda/testheader.cpp create mode 100755 windows/coda/windows.cpp create mode 100755 windows/coda/windows.hpp diff --git a/common/FileUtil-windows.cpp b/common/FileUtil-windows.cpp new file mode 100644 index 0000000000000..7a60b9e5fdf32 --- /dev/null +++ b/common/FileUtil-windows.cpp @@ -0,0 +1,174 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * Copyright the Collabora Online contributors. + * + * SPDX-License-Identifier: MPL-2.0 + * + * 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 + +#include +#include + +#include + +#define WIN32_LEAN_AND_MEAN +#include + +#include + +namespace +{ + std::wstring string_to_wide_string(const std::string& string) + { + if (string.empty()) + { + return L""; + } + + const auto size_needed = MultiByteToWideChar(CP_UTF8, 0, string.data(), (int)string.size(), nullptr, 0); + if (size_needed <= 0) + { + throw std::runtime_error("MultiByteToWideChar() failed: " + std::to_string(size_needed)); + } + + std::wstring result(size_needed, 0); + MultiByteToWideChar(CP_UTF8, 0, string.data(), (int)string.size(), result.data(), size_needed); + + return result; + } + + std::string wide_string_to_string(const std::wstring& wide_string) + { + if (wide_string.empty()) + { + return ""; + } + + const auto size_needed = WideCharToMultiByte(CP_UTF8, 0, wide_string.data(), (int)wide_string.size(), nullptr, 0, nullptr, nullptr); + if (size_needed <= 0) + { + throw std::runtime_error("WideCharToMultiByte() failed: " + std::to_string(size_needed)); + } + + std::string result(size_needed, 0); + WideCharToMultiByte(CP_UTF8, 0, wide_string.data(), (int)wide_string.size(), result.data(), size_needed, nullptr, nullptr); + + return result; + } + +} // anonymous namespace + +namespace FileUtil +{ + void removeFile(const std::string& path, const bool recursive) + { + LOG_DBG("Removing [" << path << "] " << (recursive ? "recursively." : "only.")); + + try + { + if (recursive) + std::filesystem::remove_all(string_to_wide_string(path)); + else + std::filesystem::remove(string_to_wide_string(path)); + } + catch (const std::filesystem::filesystem_error& e) + { + // Don't complain if already non-existant. + if (FileUtil::Stat(path).exists()) + { + // Error only if it still exists. + LOG_ERR("Failed to remove [" + << path << "] " << (recursive ? "recursively: " : "only: ") << e.what()); + } + } + } + + /// Remove directories only, which must be empty for this to work. + static void removeEmptyDirTreeTakingPath(const std::filesystem::path& path) + { + for (auto const& dirent : + std::filesystem::directory_iterator{path, std::filesystem::directory_options::skip_permission_denied}) + { + if (dirent.is_directory()) + { + std::error_code ec; + removeEmptyDirTreeTakingPath(dirent.path()); + std::filesystem::remove(dirent.path(), ec); + } + } + } + + void removeEmptyDirTree(const std::string& path) + { + LOG_DBG("Removing empty directories at [" << path << "] recursively"); + + removeEmptyDirTreeTakingPath(std::filesystem::path(string_to_wide_string(path))); + } + + bool isEmptyDirectory(const char* path) + { + bool empty = true; + for (auto const& dirent : + std::filesystem::directory_iterator{std::filesystem::path(string_to_wide_string(path)), + std::filesystem::directory_options::skip_permission_denied}) + { + (void) dirent; + empty = false; + break; + } + return empty; + } + + bool linkOrCopyFile(const std::string& source, const std::string& newPath) + { + return FileUtil::copy(source, newPath, /*log=*/true, /*throw_on_error=*/false); + } + + std::string realpath(const char* path) + { + return path; + } + + bool platformDependentCheckDiskSpace(const std::string& path, int64_t enoughSpace) + { + // FIXME + return true; + } + + int openFileAsFD(const std::string& file, int oflag, int mode) + { + return _wopen(string_to_wide_string(file).c_str(), oflag | O_BINARY, mode); + } + + int closeFD(int fd) + { + return _close(fd); + } + + void openFileToIFStream(const std::string& file, std::ifstream& stream, std::ios_base::openmode mode) + { + stream.open(string_to_wide_string(file), mode | std::ios_base::binary); + } + + int getStatOfFile(const std::string& file, struct stat& sb) + { + return _wstat64i32(string_to_wide_string(file).c_str(), (struct _stat64i32*) &sb); + } + + int getLStatOfFile(const std::string& file, struct stat& sb) + { + return getStatOfFile(file, sb); + } + + void createDirectory(const std::string& dir) + { + std::filesystem::create_directory(string_to_wide_string(dir)); + } +} // namespace FileUtil + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/common/FileUtil.cpp b/common/FileUtil.cpp index 1beabe3cdfed0..752419b440320 100644 --- a/common/FileUtil.cpp +++ b/common/FileUtil.cpp @@ -29,10 +29,14 @@ #include #include #include +#include #include +#include #include #include #include +#include +#include namespace FileUtil { diff --git a/common/FileUtil.hpp b/common/FileUtil.hpp index a044db8fb7ae6..e3d8932449e6c 100644 --- a/common/FileUtil.hpp +++ b/common/FileUtil.hpp @@ -40,12 +40,15 @@ namespace FileUtil { - // Wrappers for actual file handling library API. + // Wrappers for actual file handling library API. Needed because the file names we handle are in + // UTF-8, and on Windows we can't pass such to C and C++ library APIs. We need to convert to + // UTF-16 strings and call the proper wide character APIs. // Also needed because Visual Studio insists on claiming that some POSIXy functions are "deprecated" and // wants you to call the variant prefixed with an underscore instead, for example _close(). - // As open(). Returns the file descriptor. On error returns -1 and sets errno. + // As open(). Returns the file descriptor (which on Windows is just a thing the C library knows + // about, not the OS). On error returns -1 and sets errno. int openFileAsFD(const std::string& file, int oflag, int mode = 0); // As read() and write(). @@ -187,7 +190,8 @@ namespace FileUtil /// Create a temporary directory in the root provided std::string createTmpDir(const std::string& dirName, std::string root = std::string()); - /// Returns the realpath(3) of the provided path. + /// Returns the realpath(3) of the provided path. This also has a separate implementation for + /// Windows. std::string realpath(const char* path); inline std::string realpath(const std::string& path) @@ -269,6 +273,9 @@ namespace FileUtil { #if defined(IOS) || defined(MACOS) return _sb.st_mtimespec; +#elif defined(_WINDOWS) + timespec result{ _sb.st_mtime, 0 }; + return result; #else return _sb.st_mtim; #endif diff --git a/common/Log.cpp b/common/Log.cpp index 0d082b6cf0211..6c81edfc87e9c 100644 --- a/common/Log.cpp +++ b/common/Log.cpp @@ -29,7 +29,9 @@ #include #include #include +#ifndef _WINDOWS #include +#endif #include namespace diff --git a/common/Util-windows.cpp b/common/Util-windows.cpp new file mode 100644 index 0000000000000..6a3a5c1bc56c6 --- /dev/null +++ b/common/Util-windows.cpp @@ -0,0 +1,31 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * Copyright the Collabora Online contributors. + * + * SPDX-License-Identifier: MPL-2.0 + * + * 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 + +#include + +#include + +namespace Util +{ + long getProcessId() + { + return _getpid(); + } + + void time_t_to_localtime(std::time_t t, std::tm& tm) + { + localtime_s(&tm, &t); + } +} // namespace Util + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/config.h.in b/config.h.in index 7c86999a647eb..0cc710b36d473 100644 --- a/config.h.in +++ b/config.h.in @@ -138,7 +138,12 @@ /* Makes config variables conditionally static, only in non-debug builds, to allow for overriding them in unit-tests. */ #undef CONFIG_STATIC_TYPE -/* This top-level config.h is used only in "normal" COOL, thus we don't need the Windows version of EXPORT here */ +/* This top-level config.h is used only in "normal" COOL, thus we + * don't need the Windows version of EXPORT here, and not EXTERNC + * either. + */ + +#define EXTERNC /**/ #define EXPORT /**/ /* Controls whether or not we allow loading documents from the local filesystem. */ diff --git a/ios/config.h.in b/ios/config.h.in index 2d1328d2aab66..0b0198cbf16bc 100644 --- a/ios/config.h.in +++ b/ios/config.h.in @@ -139,6 +139,9 @@ /* Version number of package */ /* #undef VERSION */ -/* This config.h is used only in the iOS app, thus we don't need the Windows version of EXPORT here */ +/* This config.h is used only for iOS and we don't need the Windows + * version of EXPORT here, and not EXTERNC either. + */ +#define EXTERNC /**/ #define EXPORT /**/ diff --git a/net/FakeSocket.cpp b/net/FakeSocket.cpp index d6b6b3ee89719..e7acfabea253e 100644 --- a/net/FakeSocket.cpp +++ b/net/FakeSocket.cpp @@ -341,6 +341,7 @@ static bool fakeSocketHasAnyPendingActivityGlobal() /** * Wait for any event on any of the fake sockets (theCV is notified on write/close/connect/etc.) */ +EXPORT void fakeSocketWaitAny(int timeoutUs) { if (timeoutUs == 0) diff --git a/net/FakeSocket.hpp b/net/FakeSocket.hpp index b0047abf8837c..8801980781dbc 100644 --- a/net/FakeSocket.hpp +++ b/net/FakeSocket.hpp @@ -17,36 +17,53 @@ #include +#ifndef _WINDOWS #include +#endif +EXTERNC void fakeSocketSetLoggingCallback(void (*)(const std::string&)); +EXTERNC int fakeSocketSocket(); +EXTERNC int fakeSocketPipe2(int pipefd[2]); +EXTERNC void fakeSocketWaitAny(int timeoutUs); +EXTERNC int fakeSocketPoll(struct pollfd *fds, int nfds, int timeout); +EXTERNC int fakeSocketListen(int fd); +EXTERNC int fakeSocketConnect(int fd1, int fd2); +EXTERNC int fakeSocketAccept4(int fd); +EXTERNC int fakeSocketPeer(int fd); +EXTERNC ssize_t fakeSocketAvailableDataLength(int fd); +EXTERNC ssize_t fakeSocketRead(int fd, void *buf, size_t nbytes); +EXTERNC ssize_t fakeSocketWrite(int fd, const void *buf, size_t nbytes); +EXTERNC int fakeSocketShutdown(int fd); +EXTERNC int fakeSocketClose(int fd); +EXTERNC void fakeSocketDumpState(); #else diff --git a/net/Socket.cpp b/net/Socket.cpp index b10a1a7a9e154..2d3507c7f8873 100644 --- a/net/Socket.cpp +++ b/net/Socket.cpp @@ -50,9 +50,11 @@ #include #include +#ifndef _WINDOWS #include #include #include +#endif #ifdef __FreeBSD__ #include diff --git a/windows/coda/CODALib/CODALib.vcxproj b/windows/coda/CODALib/CODALib.vcxproj index 7a649f3e894d9..55066675823e6 100644 --- a/windows/coda/CODALib/CODALib.vcxproj +++ b/windows/coda/CODALib/CODALib.vcxproj @@ -68,6 +68,7 @@ Windows true false + libpng16.lib;zlib.lib;libzstd_static.lib;%(AdditionalDependencies) @@ -91,25 +92,47 @@ true true false + libpng16.lib;zlib.lib;libzstd_static.lib;%(AdditionalDependencies) + + + - + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/windows/coda/CODALib/CODALib.vcxproj.filters b/windows/coda/CODALib/CODALib.vcxproj.filters index 41329092702a5..cab2b88495ac0 100644 --- a/windows/coda/CODALib/CODALib.vcxproj.filters +++ b/windows/coda/CODALib/CODALib.vcxproj.filters @@ -1,4 +1,4 @@ - + @@ -36,9 +36,6 @@ Source Files - - Source Files - Source Files @@ -63,5 +60,71 @@ Source Files + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + - + \ No newline at end of file diff --git a/windows/coda/config.h.in b/windows/coda/config.h.in index bdad58f5e6820..274e135a2fb6c 100755 --- a/windows/coda/config.h.in +++ b/windows/coda/config.h.in @@ -2,6 +2,8 @@ /* config.h. Manually edited from config.h.in. */ /* config.h.in. Generated from configure.ac by autoheader. */ +#pragma once + #define APP_NAME "@APP_NAME@" /* LibreOffice core git hash if present */ @@ -137,9 +139,7 @@ /* Stuff manually added just for CODA for Windows */ -#include - -typedef ptrdiff_t ssize_t; +typedef __int64 ssize_t; typedef int pid_t; #define lstat(f,s) stat(f,s) @@ -151,6 +151,8 @@ typedef int pid_t; // MSVC's _putenv_s doesn't do removal of environment variables, but we don't need that anyway #define setenv(variable, value, one) _putenv_s(variable, value) +#define strcasecmp _stricmp + #define POLLIN 0x001 #define POLLPRI 0x002 #define POLLOUT 0x004 @@ -166,4 +168,5 @@ struct pollfd { #define MOBILEAPP 1 -#define EXPORT extern "C" __declspec(dllexport) +#define EXTERNC extern "C" +#define EXPORT EXTERNC __declspec(dllexport) diff --git a/windows/coda/testheader.cpp b/windows/coda/testheader.cpp new file mode 100755 index 0000000000000..f9259081e8b18 --- /dev/null +++ b/windows/coda/testheader.cpp @@ -0,0 +1,9 @@ +// This is just a temporary hack to make it easier to check one header +// at a time whether it compiles for Windows without having to compile +// a substantial C++ file. + +#include + +#include // Header to check + +int foobar = 42; diff --git a/windows/coda/windows.cpp b/windows/coda/windows.cpp new file mode 100755 index 0000000000000..4f8e92117717e --- /dev/null +++ b/windows/coda/windows.cpp @@ -0,0 +1,15 @@ +// -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- +// +// 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 "windows.hpp" + +const char *user_name = nullptr; + +int coolwsd_server_socket_fd = -1; + +LibreOfficeKit *lo_kit; + +// vim:set shiftwidth=4 softtabstop=4 expandtab: diff --git a/windows/coda/windows.hpp b/windows/coda/windows.hpp new file mode 100755 index 0000000000000..33fe19f0f25ad --- /dev/null +++ b/windows/coda/windows.hpp @@ -0,0 +1,13 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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 + +extern int coolwsd_server_socket_fd; +extern const char *user_name; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ From 8b79de958741f49b0372a90353def399d43f04c0 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 19 Nov 2024 13:46:01 +0100 Subject: [PATCH 012/177] coda-m: Update the project to build after the file splits Signed-off-by: Jan Holesovsky Change-Id: I323064063dc537c42d2f8598d125fb7fbc02af03 --- common/FileUtil-unix.cpp | 3 ++- macos/coda/coda.xcodeproj/project.pbxproj | 20 ++++++++++++++++---- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/common/FileUtil-unix.cpp b/common/FileUtil-unix.cpp index 06e5f87e87ccf..045522adb2840 100644 --- a/common/FileUtil-unix.cpp +++ b/common/FileUtil-unix.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -60,7 +61,7 @@ namespace FileUtil return path; } -#ifndef IOS // iOS-specific implementation in FileUtil-apple.cpp +#if !defined(IOS) && !defined(MACOS) // iOS-specific implementation in FileUtil-apple.cpp bool platformDependentCheckDiskSpace(const std::string& path, int64_t enoughSpace) { diff --git a/macos/coda/coda.xcodeproj/project.pbxproj b/macos/coda/coda.xcodeproj/project.pbxproj index 5eb9354fc679e..305fc3a301296 100644 --- a/macos/coda/coda.xcodeproj/project.pbxproj +++ b/macos/coda/coda.xcodeproj/project.pbxproj @@ -18,6 +18,10 @@ BE22557E2CC79BAE00385A9C /* global.js in Resources */ = {isa = PBXBuildFile; fileRef = BE2249312CC79BAE00385A9C /* global.js */; }; BE2257AD2CC79BAE00385A9C /* bundle.css in Resources */ = {isa = PBXBuildFile; fileRef = BE22492D2CC79BAE00385A9C /* bundle.css */; }; BE22AA9C2CC7AE7400385A9C /* images in Resources */ = {isa = PBXBuildFile; fileRef = BE22AA9B2CC7AE7400385A9C /* images */; }; + BE9115AA2CECBCB200C597B2 /* SigUtil-mobile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE9115A92CECBCB200C597B2 /* SigUtil-mobile.cpp */; }; + BE9115AC2CECBD0100C597B2 /* FileUtil-apple.mm in Sources */ = {isa = PBXBuildFile; fileRef = BE9115AB2CECBD0100C597B2 /* FileUtil-apple.mm */; }; + BE9115AE2CECBD3100C597B2 /* FileUtil-unix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE9115AD2CECBD3100C597B2 /* FileUtil-unix.cpp */; }; + BE9115B02CECBECF00C597B2 /* Util-unix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE9115AF2CECBECF00C597B2 /* Util-unix.cpp */; }; BEA2636D2CBE38E20007435A /* Uri.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA2636A2CBE38E20007435A /* Uri.cpp */; }; BEA2636E2CBE38E20007435A /* Util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA2636C2CBE38E20007435A /* Util.cpp */; }; BEA2636F2CBE38E20007435A /* Unit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA263682CBE38E20007435A /* Unit.cpp */; }; @@ -26,7 +30,6 @@ BEA263722CBE38E20007435A /* FileUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA263562CBE38E20007435A /* FileUtil.cpp */; }; BEA263732CBE38E20007435A /* Session.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA2635D2CBE38E20007435A /* Session.cpp */; }; BEA263742CBE38E20007435A /* TraceEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA263662CBE38E20007435A /* TraceEvent.cpp */; }; - BEA263752CBE38E20007435A /* SigUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA2635F2CBE38E20007435A /* SigUtil.cpp */; }; BEA263762CBE38E20007435A /* SpookyV2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA263622CBE38E20007435A /* SpookyV2.cpp */; }; BEA263772CBE38E20007435A /* ConfigUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA263552CBE38E20007435A /* ConfigUtil.cpp */; }; BEA263782CBE38E20007435A /* StringVector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA263642CBE38E20007435A /* StringVector.cpp */; }; @@ -82,6 +85,10 @@ BE2249302CC79BAE00385A9C /* device-desktop.css */ = {isa = PBXFileReference; lastKnownFileType = text.css; name = "device-desktop.css"; path = "../../../browser/dist/device-desktop.css"; sourceTree = ""; }; BE2249312CC79BAE00385A9C /* global.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = global.js; path = ../../../browser/dist/global.js; sourceTree = ""; }; BE22AA9B2CC7AE7400385A9C /* images */ = {isa = PBXFileReference; lastKnownFileType = folder; name = images; path = ../../../browser/dist/images; sourceTree = ""; }; + BE9115A92CECBCB200C597B2 /* SigUtil-mobile.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "SigUtil-mobile.cpp"; path = "../../../../common/SigUtil-mobile.cpp"; sourceTree = ""; }; + BE9115AB2CECBD0100C597B2 /* FileUtil-apple.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "FileUtil-apple.mm"; path = "../../../../common/FileUtil-apple.mm"; sourceTree = ""; }; + BE9115AD2CECBD3100C597B2 /* FileUtil-unix.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "FileUtil-unix.cpp"; path = "../../../../common/FileUtil-unix.cpp"; sourceTree = ""; }; + BE9115AF2CECBECF00C597B2 /* Util-unix.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "Util-unix.cpp"; path = "../../../../common/Util-unix.cpp"; sourceTree = ""; }; BEA263522CBE38E20007435A /* Authorization.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Authorization.hpp; path = ../../../../common/Authorization.hpp; sourceTree = ""; }; BEA263532CBE38E20007435A /* Authorization.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Authorization.cpp; path = ../../../../common/Authorization.cpp; sourceTree = ""; }; BEA263542CBE38E20007435A /* ConfigUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = ConfigUtil.hpp; path = ../../../../common/ConfigUtil.hpp; sourceTree = ""; }; @@ -95,7 +102,6 @@ BEA2635C2CBE38E20007435A /* Session.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Session.hpp; path = ../../../../common/Session.hpp; sourceTree = ""; }; BEA2635D2CBE38E20007435A /* Session.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Session.cpp; path = ../../../../common/Session.cpp; sourceTree = ""; }; BEA2635E2CBE38E20007435A /* SigUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = SigUtil.hpp; path = ../../../../common/SigUtil.hpp; sourceTree = ""; }; - BEA2635F2CBE38E20007435A /* SigUtil.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SigUtil.cpp; path = ../../../../common/SigUtil.cpp; sourceTree = ""; }; BEA263602CBE38E20007435A /* Simd.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Simd.hpp; path = ../../../../common/Simd.hpp; sourceTree = ""; }; BEA263612CBE38E20007435A /* Simd.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Simd.cpp; path = ../../../../common/Simd.cpp; sourceTree = ""; }; BEA263622CBE38E20007435A /* SpookyV2.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SpookyV2.cpp; path = ../../../../common/SpookyV2.cpp; sourceTree = ""; }; @@ -212,6 +218,8 @@ BEA263552CBE38E20007435A /* ConfigUtil.cpp */, BE2231B72CC679DE00385A9C /* Crypto-stub.cpp */, BEA263562CBE38E20007435A /* FileUtil.cpp */, + BE9115AB2CECBD0100C597B2 /* FileUtil-apple.mm */, + BE9115AD2CECBD3100C597B2 /* FileUtil-unix.cpp */, BEA263572CBE38E20007435A /* Log.hpp */, BEA263582CBE38E20007435A /* Log.cpp */, BEA263592CBE38E20007435A /* Png.hpp */, @@ -220,7 +228,7 @@ BEA2635C2CBE38E20007435A /* Session.hpp */, BEA2635D2CBE38E20007435A /* Session.cpp */, BEA2635E2CBE38E20007435A /* SigUtil.hpp */, - BEA2635F2CBE38E20007435A /* SigUtil.cpp */, + BE9115A92CECBCB200C597B2 /* SigUtil-mobile.cpp */, BEA263602CBE38E20007435A /* Simd.hpp */, BEA263612CBE38E20007435A /* Simd.cpp */, BEA263622CBE38E20007435A /* SpookyV2.cpp */, @@ -235,6 +243,7 @@ BEA2636B2CBE38E20007435A /* Util.hpp */, BEA2636C2CBE38E20007435A /* Util.cpp */, BE2231BB2CC6804D00385A9C /* Util-mobile.cpp */, + BE9115AF2CECBECF00C597B2 /* Util-unix.cpp */, ); path = common; sourceTree = ""; @@ -502,6 +511,7 @@ files = ( BEA2636D2CBE38E20007435A /* Uri.cpp in Sources */, BEA264922CBE986C0007435A /* KitQueue.cpp in Sources */, + BE9115AE2CECBD3100C597B2 /* FileUtil-unix.cpp in Sources */, BEA264932CBE986C0007435A /* KitWebSocket.cpp in Sources */, BEA264942CBE986C0007435A /* ChildSession.cpp in Sources */, BEA264952CBE986C0007435A /* Kit.cpp in Sources */, @@ -509,6 +519,7 @@ BEA2636E2CBE38E20007435A /* Util.cpp in Sources */, BE2231B82CC679DE00385A9C /* Crypto-stub.cpp in Sources */, BEA2636F2CBE38E20007435A /* Unit.cpp in Sources */, + BE9115AC2CECBD0100C597B2 /* FileUtil-apple.mm in Sources */, BEA263702CBE38E20007435A /* Log.cpp in Sources */, BEA263712CBE38E20007435A /* Simd.cpp in Sources */, BE2231BC2CC6804D00385A9C /* Util-mobile.cpp in Sources */, @@ -518,8 +529,8 @@ BEA264A02CBE98CD0007435A /* NetUtil.cpp in Sources */, BEA264A12CBE98CD0007435A /* Socket.cpp in Sources */, BEA264A22CBE98CD0007435A /* HttpRequest.cpp in Sources */, + BE9115B02CECBECF00C597B2 /* Util-unix.cpp in Sources */, BEA264A32CBE98CD0007435A /* FakeSocket.cpp in Sources */, - BEA263752CBE38E20007435A /* SigUtil.cpp in Sources */, BEA263762CBE38E20007435A /* SpookyV2.cpp in Sources */, BEA264AD2CBE99340007435A /* Storage.cpp in Sources */, BEA264AE2CBE99340007435A /* TileCache.cpp in Sources */, @@ -529,6 +540,7 @@ BEA264B22CBE99340007435A /* ClientRequestDispatcher.cpp in Sources */, BE2231BA2CC67FDE00385A9C /* coolwsd-fork.cpp in Sources */, BEA264B32CBE99340007435A /* DocumentBroker.cpp in Sources */, + BE9115AA2CECBCB200C597B2 /* SigUtil-mobile.cpp in Sources */, BEA264B42CBE99340007435A /* RequestVettingStation.cpp in Sources */, BEA263772CBE38E20007435A /* ConfigUtil.cpp in Sources */, BEA263782CBE38E20007435A /* StringVector.cpp in Sources */, From b3ecbb6a9db685c1b88e8339c05ccb14378c2d9a Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 19 Nov 2024 14:00:25 +0100 Subject: [PATCH 013/177] coda-m: Update how the core install is copied to lokit/ subdir Without this, rsync was crashing when copying libcairo.2.dylib, no idea why. Signed-off-by: Jan Holesovsky Change-Id: If5d0a4c87cb09ac26a277830a5b8821ba91eccb4 --- macos/coda/coda.xcodeproj/project.pbxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/macos/coda/coda.xcodeproj/project.pbxproj b/macos/coda/coda.xcodeproj/project.pbxproj index 305fc3a301296..587e1f0e0423b 100644 --- a/macos/coda/coda.xcodeproj/project.pbxproj +++ b/macos/coda/coda.xcodeproj/project.pbxproj @@ -500,7 +500,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n\nLO_PATH=/Users/kendy/Projects/lo/core/instdir/CollaboraOffice.app\nrsync -a $LO_PATH/Contents/ ${CONFIGURATION_BUILD_DIR}/${TARGET_NAME}.app/Contents/lokit/\n\n"; + shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n\nLO_PATH=/Users/kendy/Projects/lo/core/instdir/CollaboraOffice.app\necho \"Copying $LO_PATH/Contents/ to ${CONFIGURATION_BUILD_DIR}/${TARGET_NAME}.app/Contents/lokit/\"\nrsync -avz $LO_PATH/Contents/ ${CONFIGURATION_BUILD_DIR}/${TARGET_NAME}.app/Contents/lokit/\n\n"; }; /* End PBXShellScriptBuildPhase section */ From b23fa216f7265682826b1a143fb57d1c6e2459ff Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Tue, 19 Nov 2024 15:36:31 +0200 Subject: [PATCH 014/177] Make FileUtil.cpp compile on Windows Split more filesystyem-related functions into separate Unix and Windows implementations. Also fix some other issues in my recent commits. Signed-off-by: Tor Lillqvist Change-Id: If50e03658a7e2bf6cfb7c7c23f412d43022cb9f1 --- common/FileUtil-windows.cpp | 49 +++++++++++++++++++++++++++++++++++++ common/FileUtil.cpp | 6 ++--- common/FileUtil.hpp | 3 +++ 3 files changed, 54 insertions(+), 4 deletions(-) diff --git a/common/FileUtil-windows.cpp b/common/FileUtil-windows.cpp index 7a60b9e5fdf32..a1a24666caa96 100644 --- a/common/FileUtil-windows.cpp +++ b/common/FileUtil-windows.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #define WIN32_LEAN_AND_MEAN @@ -145,6 +146,16 @@ namespace FileUtil return _wopen(string_to_wide_string(file).c_str(), oflag | O_BINARY, mode); } + int readFromFD(int fd, void *buf, size_t nbytes) + { + return _read(fd, buf, nbytes); + } + + int writeToFD(int fd, const void *buf, size_t nbytes) + { + return _write(fd, buf, nbytes); + } + int closeFD(int fd) { return _close(fd); @@ -165,10 +176,48 @@ namespace FileUtil return getStatOfFile(file, sb); } + int unlinkFile(const std::string& file) + { + return _wunlink(string_to_wide_string(file).c_str()); + } + + int makeDirectory(const std::string& dir) + { + return _wmkdir(string_to_wide_string(dir).c_str()); + } + void createDirectory(const std::string& dir) { std::filesystem::create_directory(string_to_wide_string(dir)); } + + std::string getSysTempDirectoryPath() + { + std::wstring path = std::filesystem::temp_directory_path().wstring(); + + if (!path.empty()) + return wide_string_to_string(path); + + // Try some fallbacks + const wchar_t *tmp = _wgetenv(L"TEMP"); + if (!tmp) + tmp = _wgetenv(L"TMP"); + + // This folder seems to be protected somehow on modern Windows, but oh well. + if (!tmp) + tmp = L"C:/Windows/Temp"; + + return wide_string_to_string(tmp); + } + + bool isWritable(const char* path) + { + if (_waccess(string_to_wide_string(path).c_str(), 0) == 0) + return true; + + LOG_INF("No write access to path [" << path << "]: " << strerror(errno)); + return false; + } } // namespace FileUtil /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/common/FileUtil.cpp b/common/FileUtil.cpp index 752419b440320..7ba2a6dc6876a 100644 --- a/common/FileUtil.cpp +++ b/common/FileUtil.cpp @@ -29,14 +29,10 @@ #include #include #include -#include #include -#include #include #include #include -#include -#include namespace FileUtil { @@ -180,6 +176,7 @@ namespace FileUtil if (preserveTimestamps) { const Stat st(fromPath); +#ifndef _WINDOWS updateTimestamps(randFilename, #if defined(IOS) || defined(MACOS) st.sb().st_atimespec, st.sb().st_mtimespec @@ -187,6 +184,7 @@ namespace FileUtil st.sb().st_atim, st.sb().st_mtim #endif ); +#endif } // Now rename atomically, replacing any existing files with the same name. diff --git a/common/FileUtil.hpp b/common/FileUtil.hpp index e3d8932449e6c..b9adffbb8feaa 100644 --- a/common/FileUtil.hpp +++ b/common/FileUtil.hpp @@ -77,12 +77,15 @@ namespace FileUtil void createDirectory(const std::string& dir); // Wraps std::filesystem::temp_directory_path(), and if that fails, uses obvious fallbacks. + // Returns as UTF-8 on Windows. (And surely also on any sane Unix?) std::string getSysTempDirectoryPath(); /// Returns true iff the path given is writable by our *real* UID. + /// On Windows "real UID" is meaningless. bool isWritable(const char* path); /// Update the access-time and modified-time metadata for the given file. + /// Not implemented on Windows. bool updateTimestamps(const std::string& filename, timespec tsAccess, timespec tsModified); // End of wrappers for platform-dependent API. From 7138d425a00a4a0a6bd180fb233100e481e41566 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 19 Nov 2024 17:32:38 +0100 Subject: [PATCH 015/177] coda-m: Better error message here The shortened version is unhelpful in many cases, need to know the entire message to be able to debug. Signed-off-by: Jan Holesovsky Change-Id: I435f729909d8fd01c2abb7a97ab810f1541cc6ac --- macos/coda/coda/ViewController.swift | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/macos/coda/coda/ViewController.swift b/macos/coda/coda/ViewController.swift index 7d954c0363e3a..9e2cb724d49fc 100644 --- a/macos/coda/coda/ViewController.swift +++ b/macos/coda/coda/ViewController.swift @@ -62,11 +62,7 @@ class ViewController: NSViewController, WKScriptMessageHandler, WKNavigationDele } else if message.name == "lok" { if let body = message.body as? String { - var subBody = String(body.prefix(100)) - if subBody.count < body.count { - subBody += "..." - } - COWrapper.LOG_DBG("To Online: \(subBody)") + COWrapper.LOG_DBG("To Online: \(message.body)") if body == "HULLO" { // Now we know that the JS has started completely @@ -284,7 +280,7 @@ class ViewController: NSViewController, WKScriptMessageHandler, WKNavigationDele return } else { - COWrapper.LOG_ERR("TODO implement sending to COOLWSD: \(message.name)") + COWrapper.LOG_ERR("TODO implement sending to COOLWSD: \(message.body)") /* const char *buf = [message.body UTF8String]; p.fd = self.document->fakeClientFd; From f6149cee98656ba1b64c3125751932423b35d8ed Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 19 Nov 2024 17:33:47 +0100 Subject: [PATCH 016/177] coda-m: Don't add appDocId, it is iOS-specific Without this, the document name was constructed as "file:///.../hello.odt 1", which obviously didn't exist, and throwed in download(). Signed-off-by: Jan Holesovsky Change-Id: I14f6103d8cb970c802793470ff117aaf6ee8e15a --- macos/coda/coda/COWrapper.mm | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/macos/coda/coda/COWrapper.mm b/macos/coda/coda/COWrapper.mm index 2d8274360e727..73e186aaacd8f 100644 --- a/macos/coda/coda/COWrapper.mm +++ b/macos/coda/coda/COWrapper.mm @@ -144,9 +144,7 @@ - (void)handleHULLOWithDocument:(CODocument *)document { p.events = POLLOUT; fakeSocketPoll(&p, 1, -1); - // This is read in the iOS-specific code in ClientRequestDispatcher::handleIncomingMessage() in COOLWSD.cpp - std::string message(url + " " + std::to_string(document.appDocId)); - fakeSocketWrite(document->fakeClientFd, message.c_str(), message.size()); + fakeSocketWrite(document->fakeClientFd, url.c_str(), url.size()); } /** From 589b3e179d48efe90d3d600d50ba9ebdc1feba4c Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Mon, 25 Nov 2024 16:39:53 +0200 Subject: [PATCH 017/177] Make a bunch of source files compile for Windows Squashed together from several individual commits. Original commit messages: Make Socket.cpp compile for Windows again. Make Log.cpp compile for Windows. Make SpookyV2.h compile for Windows. Make Unit.cpp compile for Windows. Split out server and mobile implementations from Unit.cpp. This reduces the amount of ifdefs a bit. Also just use 0 and 1 instead of EX_OK and EX_SOFTWARE which aren't defined in the Microsoft C library. Remove leftover mobile app checks from SigUtil-server.cpp. Both MOBILEAPP and Util::isMobileApp() ones. This file is not compiled in a mobile app. Make ClientRequestDispatcher.cpp compile for Windows. Make COOLWSD.cpp compile for Windows. We don't seem to need here. Make Kit.cpp compile for Windows. Also, grudgingly define EX_OK and EX_SOFTWARE in windows/coda/config.h.in. They are used in so many places, and I guess it is possible that some server scripts or whatever actually do check for a COOL process exiting specifically with EX_SOFTWARE, and using 1 would break that. Thus revert the recent change to Unit.cpp, return to using EX_OK and EX_SOFTWARE. Make KitWebSocket.cpp compile for Windows. Make Storage.cpp compile for Windows. Make Delta.hpp compile for Windows. Make Util.cpp compile for Windows. Split the random byte source thing out to Unixish and Windows specific implementations. Signed-off-by: Tor Lillqvist Change-Id: I7a6f906a8b245efb4f9540022c81cbc27099e997 --- common/Log.cpp | 9 +++++++- common/Unit.cpp | 2 ++ common/Util-windows.cpp | 24 ++++++++++++++++++++ common/Util.cpp | 15 +++++++----- kit/DeltaSimd.c | 5 ---- kit/Kit.cpp | 2 ++ kit/KitWebSocket.cpp | 2 ++ windows/coda/CODALib/CODALib.vcxproj | 1 + windows/coda/CODALib/CODALib.vcxproj.filters | 3 +++ windows/coda/config.h.in | 4 ++++ wsd/COOLWSD.cpp | 4 +++- wsd/PlatformMobile.hpp | 2 ++ wsd/Storage.cpp | 2 ++ 13 files changed, 62 insertions(+), 13 deletions(-) diff --git a/common/Log.cpp b/common/Log.cpp index 6c81edfc87e9c..0829b4629600b 100644 --- a/common/Log.cpp +++ b/common/Log.cpp @@ -31,6 +31,8 @@ #include #ifndef _WINDOWS #include +#else +#include #endif #include @@ -136,6 +138,7 @@ namespace Log /// Write the given buffer to stderr directly. static inline std::size_t writeRaw(const char* data, std::size_t count) { +#ifndef _WINDOWS #if WASMAPP // In WASM, stdout works best. constexpr int LOG_FILE_FD = STDOUT_FILENO; @@ -161,6 +164,10 @@ namespace Log count -= wrote; } return ptr - data; +#else // _WINDOWS + fwrite(data, size, 1, stderr); + return size; +#endif } template inline void writeRaw(const char (&data)[N]) @@ -476,7 +483,7 @@ namespace Log char* prefix(const std::chrono::time_point& tp, char* buffer, const std::string_view level) { -#if defined(IOS) || defined(__FreeBSD__) +#if defined(IOS) || defined(__FreeBSD__) || defined(_WINDOWS) // Don't bother with the "Source" which would be just "Mobile" always (or whatever the app // process is called depending on platform and configuration) and non-informative as there // is just one process in the app anyway. diff --git a/common/Unit.cpp b/common/Unit.cpp index 58d0f1c0e5bf4..217eeda29d6a8 100644 --- a/common/Unit.cpp +++ b/common/Unit.cpp @@ -25,7 +25,9 @@ #include #include #include +#ifndef _WINDOWS #include +#endif #include std::atomicGlobalKit = nullptr; diff --git a/common/Util-windows.cpp b/common/Util-windows.cpp index 6a3a5c1bc56c6..ad8d4e2c1aea7 100644 --- a/common/Util-windows.cpp +++ b/common/Util-windows.cpp @@ -11,12 +11,36 @@ #include +#include + #include #include namespace Util { + namespace rng + { + std::vector getBytes(const std::size_t length) + { + std::vector v(length); + + static std::random_device rd; + size_t offset; + size_t byteoffset = 0; + std::random_device::result_type buffer; + for (offset = 0; offset < length; offset++) + { + if (offset % sizeof(std::random_device::result_type) == 0) + buffer = rd(); + v[offset] = (buffer >> byteoffset) & 0xFF; + byteoffset = (byteoffset + 8) % (8 * sizeof(std::random_device::result_type)); + } + + return v; + } + } // namespace rng + long getProcessId() { return _getpid(); diff --git a/common/Util.cpp b/common/Util.cpp index 3c43a4f93e3d0..d7d729ec60eb4 100644 --- a/common/Util.cpp +++ b/common/Util.cpp @@ -37,21 +37,16 @@ #include #include #include -#include -#include #include #include #include #include #include -#include #include #include #include #include -#include #include -#include #ifndef COOLWSD_BUILDCONFIG #define COOLWSD_BUILDCONFIG @@ -61,7 +56,7 @@ #include "SigHandlerTrap.hpp" #endif -#if !defined(__ANDROID__) && !defined(__EMSCRIPTEN__) +#if !defined(__ANDROID__) && !defined(__EMSCRIPTEN__) && !defined(_WINDOWS) # include # include #endif @@ -77,6 +72,14 @@ #import #endif +#ifndef _WINDOWS +#include +#include +#include +#include +#include +#endif + #if defined __GLIBC__ #include #if defined(M_TRIM_THRESHOLD) diff --git a/kit/DeltaSimd.c b/kit/DeltaSimd.c index 489420d64ff30..21179765a025f 100644 --- a/kit/DeltaSimd.c +++ b/kit/DeltaSimd.c @@ -20,11 +20,6 @@ #include #include #include -#if defined(MACOS) -# include -#else -# include -#endif #include "DeltaSimd.h" diff --git a/kit/Kit.cpp b/kit/Kit.cpp index 8e5f9d49fb797..97183d095b67f 100644 --- a/kit/Kit.cpp +++ b/kit/Kit.cpp @@ -44,12 +44,14 @@ #define FTW_ACTIONRETVAL 0 #endif +#ifndef _WINDOWS #include #include #include #include #include #include +#endif #include #include diff --git a/kit/KitWebSocket.cpp b/kit/KitWebSocket.cpp index 97329c745cba0..25baa6389dd57 100644 --- a/kit/KitWebSocket.cpp +++ b/kit/KitWebSocket.cpp @@ -17,8 +17,10 @@ #include +#ifndef _WINDOWS #include #include +#endif #include diff --git a/windows/coda/CODALib/CODALib.vcxproj b/windows/coda/CODALib/CODALib.vcxproj index 55066675823e6..8da5ceb29edba 100644 --- a/windows/coda/CODALib/CODALib.vcxproj +++ b/windows/coda/CODALib/CODALib.vcxproj @@ -110,6 +110,7 @@ + diff --git a/windows/coda/CODALib/CODALib.vcxproj.filters b/windows/coda/CODALib/CODALib.vcxproj.filters index cab2b88495ac0..3c4fb4c57356f 100644 --- a/windows/coda/CODALib/CODALib.vcxproj.filters +++ b/windows/coda/CODALib/CODALib.vcxproj.filters @@ -126,5 +126,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/windows/coda/config.h.in b/windows/coda/config.h.in index 274e135a2fb6c..77d84bf386373 100755 --- a/windows/coda/config.h.in +++ b/windows/coda/config.h.in @@ -166,6 +166,10 @@ struct pollfd { short revents; }; +// I give up, let's define these here +#define EX_OK 0 +#define EX_SOFTWARE 1 + #define MOBILEAPP 1 #define EXTERNC extern "C" diff --git a/wsd/COOLWSD.cpp b/wsd/COOLWSD.cpp index 30663a308f9d4..4a08eca44c34a 100644 --- a/wsd/COOLWSD.cpp +++ b/wsd/COOLWSD.cpp @@ -33,10 +33,12 @@ // parent process that listens on the TCP port and accepts connections from COOL clients, and a // number of child processes, each which handles a viewing (editing) session for one document. +#ifndef _WINDOWS #include #include #include #include +#endif #include @@ -2071,7 +2073,7 @@ void COOLWSD::innerInitialize(Poco::Util::Application& self) COOLWSD::MaxDocuments = COOLWSD::MaxConnections; } -#if !WASMAPP +#if !WASMAPP && !defined(_WINDOWS) struct rlimit rlim; ::getrlimit(RLIMIT_NOFILE, &rlim); LOG_INF("Maximum file descriptor supported by the system: " << rlim.rlim_cur - 1); diff --git a/wsd/PlatformMobile.hpp b/wsd/PlatformMobile.hpp index 122a9cd30338c..667bfb627b6b4 100644 --- a/wsd/PlatformMobile.hpp +++ b/wsd/PlatformMobile.hpp @@ -16,6 +16,8 @@ #include "ios.h" #elif defined(MACOS) #include "macos.h" +#elif defined(_WINDOWS) +#include "windows.hpp" #elif defined(GTKAPP) #include "gtk.hpp" #elif defined(__ANDROID__) diff --git a/wsd/Storage.cpp b/wsd/Storage.cpp index 8e9b5fc2c8dca..fd5c9922485fc 100644 --- a/wsd/Storage.cpp +++ b/wsd/Storage.cpp @@ -54,6 +54,8 @@ #include #elif defined(__ANDROID__) #include "androidapp.hpp" +#elif defined(_WINDOWS) +#include "windows.hpp" #elif defined(GTKAPP) #include "gtk.hpp" #endif // IOS From e40d22f8a8a8708139610b8325eb355a6a9b953f Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Thu, 20 Mar 2025 16:25:44 +0200 Subject: [PATCH 018/177] Fix compilation errors on Windows Signed-off-by: Tor Lillqvist Change-Id: Ie428e06a626b11c543bd5c7ec9933a9995be1422 --- wsd/DocumentBroker.cpp | 1 - wsd/RequestVettingStation.cpp | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/wsd/DocumentBroker.cpp b/wsd/DocumentBroker.cpp index 700476c9b9176..1e2168da7fab2 100644 --- a/wsd/DocumentBroker.cpp +++ b/wsd/DocumentBroker.cpp @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/wsd/RequestVettingStation.cpp b/wsd/RequestVettingStation.cpp index ddd9984f06cbb..dc7b0e4528566 100644 --- a/wsd/RequestVettingStation.cpp +++ b/wsd/RequestVettingStation.cpp @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -29,6 +28,7 @@ #include #if !MOBILEAPP +#include #include #endif // !MOBILEAPP From 567e64428e8d1d47e8f33678f9a7f1700a670149 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Tue, 26 Nov 2024 14:34:29 +0200 Subject: [PATCH 019/177] Use 'Multi-processor Compilation' Signed-off-by: Tor Lillqvist Change-Id: Ie7d0e34780d97a08bd92ca6549dfc082dce1f162 --- windows/coda/CODALib/CODALib.vcxproj | 1 + 1 file changed, 1 insertion(+) diff --git a/windows/coda/CODALib/CODALib.vcxproj b/windows/coda/CODALib/CODALib.vcxproj index 8da5ceb29edba..a215c18dae4a7 100644 --- a/windows/coda/CODALib/CODALib.vcxproj +++ b/windows/coda/CODALib/CODALib.vcxproj @@ -63,6 +63,7 @@ stdc11 ..;..\..\..;..\..\..\common;..\..\..\net;..\..\..\kit;..\..\..\wsd;%(AdditionalIncludeDirectories) false + true Windows From 9b26890c2069597455ea477147433c31fedc4cad Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Tue, 26 Nov 2024 15:09:19 +0200 Subject: [PATCH 020/177] I build Poco statically, so adapt to that I build Poco 1.13.3 with: powershell.exe -ExecutionPolicy Bypass -File .\buildwin.ps1 -config both -linkmode static_md -platform x64 -omit ActiveRecord,Crypto,NetSSL_OpenSSL,Zip,Data,Data/SQLite,Data/ODBC,Data/MySQL,MongoDB,PDF,CppParser,PageCompiler,JWT,Prometheus,Redis (After having edited Foundation.h a bit so that the "pragma comment" things match the libraries that actually are produced.) The configure script should thus look for PocoFoundationmd.lib (release) or PocoFoundationmdd.lib (debug). We now then also need to link with the import libraries for the system libraries that the static Poco libraries import, ws2_32.lib (Winsock2) and iphlpapi.lib (some helper library). Signed-off-by: Tor Lillqvist Change-Id: Ia6cac1f7cec37c1d38c9bc42fcbda1e42a6f50a5 --- configure.ac | 3 ++- windows/coda/CODALib/CODALib.vcxproj | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 0b383ee9de23f..54f58b0768e85 100644 --- a/configure.ac +++ b/configure.ac @@ -798,7 +798,8 @@ if test \( "$enable_iosapp" = "yes" -a `uname -s` = "Darwin" \) -o \( "$enable_w # Sanity checks if test "$enable_windowsapp" = "yes"; then - CHK_FILE_VAR(POCOLIB,PocoFoundation.lib,Poco lib) + CHK_FILE_VAR(POCOLIB,PocoFoundationmd.lib,Poco lib) + CHK_FILE_VAR(POCOLIB,PocoFoundationmdd.lib,Poco lib) else CHK_FILE_VAR(POCOLIB,libPocoFoundation.a,Poco lib) CHK_FILE_VAR(POCOLIB,libPocoFoundation.a,Poco lib,_ARM64_V8A) diff --git a/windows/coda/CODALib/CODALib.vcxproj b/windows/coda/CODALib/CODALib.vcxproj index a215c18dae4a7..8762d700e1ac2 100644 --- a/windows/coda/CODALib/CODALib.vcxproj +++ b/windows/coda/CODALib/CODALib.vcxproj @@ -69,7 +69,7 @@ Windows true false - libpng16.lib;zlib.lib;libzstd_static.lib;%(AdditionalDependencies) + libpng16.lib;zlib.lib;libzstd_static.lib;ws2_32.lib;iphlpapi.lib;%(AdditionalDependencies) From 8489f0d078bc39f5c1d95e08d5f270145d9adf08 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Thu, 20 Mar 2025 16:48:38 +0200 Subject: [PATCH 021/177] Misc small changes to make CODA-W build Signed-off-by: Tor Lillqvist Change-Id: I929691c8b61a72104f900209cdb8916f5587ae7e --- windows/coda/CODA/CODA.csproj | 8 ++++---- windows/coda/CODALib/CODALib.vcxproj | 1 + windows/coda/CODALib/CODALib.vcxproj.filters | 3 +++ 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/windows/coda/CODA/CODA.csproj b/windows/coda/CODA/CODA.csproj index db341db94de70..9b2c61507a61f 100644 --- a/windows/coda/CODA/CODA.csproj +++ b/windows/coda/CODA/CODA.csproj @@ -1,4 +1,4 @@ - + Collabora Productivity @@ -120,9 +120,9 @@ - 1.0.2849.39 + 1.0.3124.44 - + @@ -137,4 +137,4 @@ - + \ No newline at end of file diff --git a/windows/coda/CODALib/CODALib.vcxproj b/windows/coda/CODALib/CODALib.vcxproj index 8762d700e1ac2..9ae2136e95e6b 100644 --- a/windows/coda/CODALib/CODALib.vcxproj +++ b/windows/coda/CODALib/CODALib.vcxproj @@ -122,6 +122,7 @@ + diff --git a/windows/coda/CODALib/CODALib.vcxproj.filters b/windows/coda/CODALib/CODALib.vcxproj.filters index 3c4fb4c57356f..a0b783f6611d6 100644 --- a/windows/coda/CODALib/CODALib.vcxproj.filters +++ b/windows/coda/CODALib/CODALib.vcxproj.filters @@ -129,5 +129,8 @@ Source Files + + Source Files + \ No newline at end of file From ac5cac661dfece40bf953c32f7a1bdbc6db4ad60 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Tue, 26 Nov 2024 15:14:45 +0200 Subject: [PATCH 022/177] Add getter and setter functions for coolwsd_server_socket_fd for CODA-W The C# code in windows/coda/CODA/MainWindow.xaml.cs wants them. It is easier to call functions in a DLL from C# than to access variables, I assume. Signed-off-by: Tor Lillqvist Change-Id: Iec28e1d37b9206499b3180ae2042fcd697d086b0 --- windows/coda/windows.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/windows/coda/windows.cpp b/windows/coda/windows.cpp index 4f8e92117717e..740f386542515 100755 --- a/windows/coda/windows.cpp +++ b/windows/coda/windows.cpp @@ -4,6 +4,8 @@ // 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 + #include "windows.hpp" const char *user_name = nullptr; @@ -12,4 +14,17 @@ int coolwsd_server_socket_fd = -1; LibreOfficeKit *lo_kit; +EXPORT +int get_coolwsd_server_socket_fd() +{ + return coolwsd_server_socket_fd; +} + +EXPORT +int set_coolwsd_server_socket_fd(int fd) +{ + coolwsd_server_socket_fd = fd; + return fd; +} + // vim:set shiftwidth=4 softtabstop=4 expandtab: From dd83df4ac01f86fe05b1ee1afec9ac2f8286117f Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Tue, 26 Nov 2024 16:11:31 +0200 Subject: [PATCH 023/177] Don't warn about VLAs in Windows compilation Signed-off-by: Tor Lillqvist Change-Id: I2f3c884165b34cabcc74e8cee54ce5f36208bc64 --- windows/coda/CODALib/CODALib.vcxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/windows/coda/CODALib/CODALib.vcxproj b/windows/coda/CODALib/CODALib.vcxproj index 9ae2136e95e6b..db1303c8a9777 100644 --- a/windows/coda/CODALib/CODALib.vcxproj +++ b/windows/coda/CODALib/CODALib.vcxproj @@ -64,6 +64,7 @@ ..;..\..\..;..\..\..\common;..\..\..\net;..\..\..\kit;..\..\..\wsd;%(AdditionalIncludeDirectories) false true + -Wno-vla-cxx-extension Windows @@ -86,6 +87,7 @@ stdc11 ..;..\..\..;..\..\..\common;..\..\..\net;..\..\..\kit;..\..\..\wsd;%(AdditionalIncludeDirectories) false + -Wno-vla-cxx-extension Windows From bc5daa48cf7d9865205aa94b0bbb293727180121 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Thu, 20 Mar 2025 16:59:20 +0200 Subject: [PATCH 024/177] Avoid warnings in CODA-W build: Use Util::getProcessId() instead of getpid() Signed-off-by: Tor Lillqvist Change-Id: I16d83a67e8f3280e02c2f7fc513df9bc5289fdd8 --- kit/Kit.cpp | 2 +- wsd/COOLWSD.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/kit/Kit.cpp b/kit/Kit.cpp index 97183d095b67f..1419e150f02ca 100644 --- a/kit/Kit.cpp +++ b/kit/Kit.cpp @@ -4316,7 +4316,7 @@ void dump_kit_state() KitSocketPoll::dumpGlobalState(oss); - oss << "\nMalloc info [" << getpid() << "]: \n\t" + oss << "\nMalloc info [" << Util::getProcessId() << "]: \n\t" << Util::replace(Util::getMallocInfo(), "\n", "\n\t") << '\n'; oss << "\nEnd Kit " << getpid() << " Dump State.\n"; diff --git a/wsd/COOLWSD.cpp b/wsd/COOLWSD.cpp index 4a08eca44c34a..0d9d07290c2c8 100644 --- a/wsd/COOLWSD.cpp +++ b/wsd/COOLWSD.cpp @@ -3330,7 +3330,7 @@ void COOLWSDServer::dumpState(std::ostream& os) const << "\n IsProxyPrefixEnabled: " << (COOLWSD::IsProxyPrefixEnabled ? "yes" : "no") << "\n OverrideWatermark: " << COOLWSD::OverrideWatermark << "\n UserInterface: " << COOLWSD::UserInterface - << "\n Total PSS: " << Util::getProcessTreePss(getpid()) << " KB" + << "\n Total PSS: " << Util::getProcessTreePss(Util::getProcessId()) << " KB" << "\n Config: " << LoggableConfigEntries ; THREAD_UNSAFE_DUMP_END @@ -4275,14 +4275,14 @@ static void forwardSignal(int signum); void dump_state() { std::ostringstream oss(Util::makeDumpStateStream()); - oss << "Start WSD " << getpid() << " Dump State:\n"; + oss << "Start WSD " << Util::getProcessId() << " Dump State:\n"; if (COOLWSDServer::Instance) COOLWSDServer::Instance->dumpState(oss); - oss << "\nMalloc info [" << getpid() << "]: \n\t" + oss << "\nMalloc info [" << Util::getProcessId() << "]: \n\t" << Util::replace(Util::getMallocInfo(), "\n", "\n\t") << '\n'; - oss << "\nEnd WSD " << getpid() << " Dump State.\n"; + oss << "\nEnd WSD " << Util::getProcessId() << " Dump State.\n"; const std::string msg = oss.str(); fprintf(stderr, "%s", msg.c_str()); // Log in the journal. From 8133ce1c41c21085302d195c26c68c91a0a9972f Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 26 Nov 2024 11:29:31 +0100 Subject: [PATCH 025/177] A handful of sequential CODA-M commits squashed together Original commit messages: coda-m: Implement sending the message from JS to WSD coda-m: Correct 2nd param of lok_init_2(), should be the user's profile On macOS, let's assume this to be the Application Support Directory. Without this patch, we attempted to write directly to the bundle. coda-m: Allow execution of JIT-compiled code Without this, the pthread_jit_write_protect_np() in bridges crashes (when creating vtables for UCB exceptions). coda-m: Update instructions with dependencies for canvas@next coda-m: Enable the "new" way of collecting fonts The "legacy" way crashes on macOS, but I'm not eager to investigate why, if this is the future. coda-m: Decrease the debug verbosity "trace" might be useful for some debugging, but mostly it just slows everying so much, that very little can be done when it's enabled. Signed-off-by: Jan Holesovsky Change-Id: I9fe92133934b81f9556ac58ef81783cbd0e405cb --- kit/Kit.cpp | 2 +- kit/SetupKitEnvironment.hpp | 6 +++++ macos/README.txt | 9 ++++++- macos/coda/coda/COWrapper.h | 1 + macos/coda/coda/COWrapper.mm | 16 ++++++++++++- macos/coda/coda/ViewController.swift | 10 ++------ macos/coda/coda/coda.entitlements | 2 ++ macos/coda/coda/macos.h | 5 ++++ macos/coda/coda/macos.mm | 35 ++++++++++++++++++++++++++++ 9 files changed, 75 insertions(+), 11 deletions(-) diff --git a/kit/Kit.cpp b/kit/Kit.cpp index 1419e150f02ca..24727a5989e7a 100644 --- a/kit/Kit.cpp +++ b/kit/Kit.cpp @@ -3938,7 +3938,7 @@ void lokit_main( Poco::URI userInstallationURI("file", LO_PATH); LibreOfficeKit *kit = lok_init_2(LO_PATH "/program", userInstallationURI.toString().c_str()); #elif defined(MACOS) - LibreOfficeKit *kit = lok_init_2((getBundlePath() + "/Contents/lokit/Frameworks").c_str(), ("file://" + getBundlePath() + "/Contents/lokit/Resources").c_str()); + LibreOfficeKit *kit = lok_init_2((getBundlePath() + "/Contents/lokit/Frameworks").c_str(), getAppSupportURL().c_str()); #else #ifdef IOS // In the iOS app we call lok_init_2() just once, when the app starts diff --git a/kit/SetupKitEnvironment.hpp b/kit/SetupKitEnvironment.hpp index 44ee33ba9821d..18d9f10e47a0f 100644 --- a/kit/SetupKitEnvironment.hpp +++ b/kit/SetupKitEnvironment.hpp @@ -64,6 +64,12 @@ inline void setupKitEnvironment(const std::string& userInterface) options += ":sc_print_twips_msgs"; +#ifdef MACOS + // The "legacy way" (with repeating fonts) crashes CODA at the moment, + // enable the new behavior + options += ":compact_fonts"; +#endif + ::setenv("SAL_LOK_OPTIONS", options.c_str(), 0); } diff --git a/macos/README.txt b/macos/README.txt index 75c5ab5ea2b25..a35290563fe9c 100644 --- a/macos/README.txt +++ b/macos/README.txt @@ -10,7 +10,14 @@ Setup * brew install zstd * missing from the iOS build instructions (needed for online.git) * brew install libtool -* install canvas to avoid error during build + +* install dependencies for the canvas@next + * brew install cairo + * brew install pango + * /opt/homebrew/bin/pip3 install --break-system-packages lxml + * /opt/homebrew/bin/pip3 install --break-system-packages polib + +* install canvas to avoid error during build (complains about node-pre-gyp) * NB. version 3.0 needed, it upgrades the API to fit the new node.js * npm install canvas@next diff --git a/macos/coda/coda/COWrapper.h b/macos/coda/coda/COWrapper.h index 7a819cbbbbb1b..8da90bf8da23a 100644 --- a/macos/coda/coda/COWrapper.h +++ b/macos/coda/coda/COWrapper.h @@ -24,6 +24,7 @@ - (void)stopServer; - (void)handleHULLOWithDocument:(CODocument *)document; +- (void)handleMessageWith:(CODocument *)document message:(NSString *)message; + (void)LOG_DBG:(NSString *)message NS_SWIFT_NAME(LOG_DBG(_:)); + (void)LOG_ERR:(NSString *)message NS_SWIFT_NAME(LOG_ERR(_:)); diff --git a/macos/coda/coda/COWrapper.mm b/macos/coda/coda/COWrapper.mm index 73e186aaacd8f..584a2173fadf2 100644 --- a/macos/coda/coda/COWrapper.mm +++ b/macos/coda/coda/COWrapper.mm @@ -42,7 +42,12 @@ + (instancetype)shared { - (void)startServer { // Initialize logging - Log::initialize("Mobile", "trace", false, false, {}); + // Use "debug" or potentially even "trace" for debugging +#if DEBUG + Log::initialize("Mobile", "debug", false, false, {}); +#else + Log::initialize("Mobile", "information", false, false, {}); +#endif Util::setThreadName("main"); // Set up the logging callback @@ -147,6 +152,15 @@ - (void)handleHULLOWithDocument:(CODocument *)document { fakeSocketWrite(document->fakeClientFd, url.c_str(), url.size()); } +- (void)handleMessageWith:(CODocument *)document message:(NSString *)message { + const char *buf = [message UTF8String]; + struct pollfd p; + p.fd = document->fakeClientFd; + p.events = POLLOUT; + fakeSocketPoll(&p, 1, -1); + fakeSocketWrite(document->fakeClientFd, buf, strlen(buf)); +} + /** * Convert NSString to std::string & call the C++ version of the logging function. */ diff --git a/macos/coda/coda/ViewController.swift b/macos/coda/coda/ViewController.swift index 9e2cb724d49fc..431d4f2dd6382 100644 --- a/macos/coda/coda/ViewController.swift +++ b/macos/coda/coda/ViewController.swift @@ -280,14 +280,8 @@ class ViewController: NSViewController, WKScriptMessageHandler, WKNavigationDele return } else { - COWrapper.LOG_ERR("TODO implement sending to COOLWSD: \(message.body)") - /* - const char *buf = [message.body UTF8String]; - p.fd = self.document->fakeClientFd; - p.events = POLLOUT; - fakeSocketPoll(&p, 1, -1); - fakeSocketWrite(self.document->fakeClientFd, buf, strlen(buf)); - */ + // Just send the message + COWrapper.shared.handleMessage(with: document, message: body) } } } diff --git a/macos/coda/coda/coda.entitlements b/macos/coda/coda/coda.entitlements index 581780da164dc..20df823f13ace 100644 --- a/macos/coda/coda/coda.entitlements +++ b/macos/coda/coda/coda.entitlements @@ -4,6 +4,8 @@ com.apple.security.app-sandbox + com.apple.security.cs.allow-jit + com.apple.security.cs.disable-library-validation com.apple.security.files.user-selected.read-only diff --git a/macos/coda/coda/macos.h b/macos/coda/coda/macos.h index d34ccb7d2c8ac..d723bab38307a 100644 --- a/macos/coda/coda/macos.h +++ b/macos/coda/coda/macos.h @@ -24,6 +24,11 @@ extern LibreOfficeKit *lo_kit; */ std::string getBundlePath(); +/** + * Get path of the Application Support Directory (app-specific data files that should be preserved between app launches and across updates). + */ +std::string getAppSupportURL(); + /** * Get URL of a resource in the bundle. */ diff --git a/macos/coda/coda/macos.mm b/macos/coda/coda/macos.mm index 025c8c367e2c3..77792524992ca 100644 --- a/macos/coda/coda/macos.mm +++ b/macos/coda/coda/macos.mm @@ -24,6 +24,41 @@ return bundlePath; } +std::string getAppSupportURL() { + @autoreleasepool { + NSFileManager *fileManager = [NSFileManager defaultManager]; + + // Get the URLs for the Application Support directory in the user domain + NSArray *urls = [fileManager URLsForDirectory:NSApplicationSupportDirectory inDomains:NSUserDomainMask]; + NSURL *appSupportURL = [urls firstObject]; + if (!appSupportURL) + return std::string(); + + // Get the app's name from the bundle + NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"]; + if (!appName) { + // Fallback if CFBundleName is not set + appName = @"CODA"; + } + + // Append your app's name to create a unique directory + NSURL *appDirectoryURL = [appSupportURL URLByAppendingPathComponent:appName isDirectory:YES]; + + // Create the directory if it doesn't exist + if (![fileManager fileExistsAtPath:[appDirectoryURL path]]) { + NSError *error = nil; + BOOL success = [fileManager createDirectoryAtURL:appDirectoryURL withIntermediateDirectories:YES attributes:nil error:&error]; + if (!success) { + NSLog(@"Error creating Application Support directory: %@", error.localizedDescription); + return std::string(); + } + } + + // Return the URL as string + return [[appDirectoryURL absoluteString] UTF8String]; + } +} + std::string getResourceURL(const char *name, const char *ext) { NSURL *url = [[NSBundle mainBundle] URLForResource:[NSString stringWithUTF8String:name] withExtension:[NSString stringWithUTF8String:ext]]; return std::string([[url absoluteString] UTF8String]); From 2f009cda22eabb6e742499ae9eae2fc8e7528bf9 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Tue, 26 Nov 2024 16:52:49 +0200 Subject: [PATCH 026/177] Improve Util::time_t_to_localtime() and add Util::time_t_to_gmtime() Make Util::time_t_to_localtime() more like localtime_r() and use it. Add time_t_to_gmtime() and use it, wraps the non-portable gmtime_r(). Signed-off-by: Tor Lillqvist Change-Id: If0865c558cd240d65125af0c60373d36c6b6a25d --- common/Util-windows.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/common/Util-windows.cpp b/common/Util-windows.cpp index ad8d4e2c1aea7..0ef1697efa366 100644 --- a/common/Util-windows.cpp +++ b/common/Util-windows.cpp @@ -46,9 +46,18 @@ namespace Util return _getpid(); } - void time_t_to_localtime(std::time_t t, std::tm& tm) + std::tm *time_t_to_localtime(std::time_t t, std::tm& tm) { - localtime_s(&tm, &t); + if (localtime_s(&tm, &t) != 0) + return nullptr; + return &tm; + } + + std::tm *time_t_to_gmtime(std::time_t t, std::tm& tm) + { + if (gmtime_s(&tm, &t) != 0) + return nullptr; + return &tm; } } // namespace Util From 7edb6ba274eac5aeecac30204311950ef01dc94d Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Wed, 27 Nov 2024 14:05:08 +0200 Subject: [PATCH 027/177] Drop some now unneeded Windows-specific defines We now handle the functionality of lstat(), link(), localtime_r(), and gmtime_r() with platform-specific wrappers. Signed-off-by: Tor Lillqvist Change-Id: I52973a4fc4c742eefc8533f9f4830237027b8dfd --- windows/coda/config.h.in | 6 ------ 1 file changed, 6 deletions(-) diff --git a/windows/coda/config.h.in b/windows/coda/config.h.in index 77d84bf386373..fb3d0783d3ee7 100755 --- a/windows/coda/config.h.in +++ b/windows/coda/config.h.in @@ -142,12 +142,6 @@ typedef __int64 ssize_t; typedef int pid_t; -#define lstat(f,s) stat(f,s) -#define link(a, b) -1 - -#define localtime_r(time_t_ptr, struct_tm_ptr) (localtime_s(struct_tm_ptr, time_t_ptr), struct_tm_ptr) -#define gmtime_r(time_t_ptr, struct_tm_ptr) (gmtime_s(struct_tm_ptr, time_t_ptr), struct_tm_ptr) - // MSVC's _putenv_s doesn't do removal of environment variables, but we don't need that anyway #define setenv(variable, value, one) _putenv_s(variable, value) From 22956393980081f4b1169806ac93ca5b027d2320 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Wed, 27 Nov 2024 14:19:54 +0200 Subject: [PATCH 028/177] Enable debugging of unmanaged (C++) code in CODA-W That will of course be very much needed. Odd that this setting is in a "user" file? Should this file be in version control or not? Signed-off-by: Tor Lillqvist Change-Id: Ia9e5cba3b27a044c46240a15bd8d155ca8623f28 --- windows/coda/CODA/CODA.csproj.user | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 windows/coda/CODA/CODA.csproj.user diff --git a/windows/coda/CODA/CODA.csproj.user b/windows/coda/CODA/CODA.csproj.user new file mode 100644 index 0000000000000..be279c3eb28ed --- /dev/null +++ b/windows/coda/CODA/CODA.csproj.user @@ -0,0 +1,6 @@ + + + + true + + \ No newline at end of file From e2975743820a58de3835c54e3fdf0db9e2567223 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Wed, 27 Nov 2024 18:38:17 +0200 Subject: [PATCH 029/177] Some more baby steps to make CODA-W start up properly Copy things from the Gtk app. If it turns out that we can use lots of identical code snippets as that, they should obviously be factored out into some file common to CODA-W and the Gtk app. Signed-off-by: Tor Lillqvist Change-Id: Ic503faae528ca676535ece6630d182c806ffe3ac --- windows/coda/CODA/MainWindow.xaml.cs | 4 +++ windows/coda/windows.cpp | 40 ++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/windows/coda/CODA/MainWindow.xaml.cs b/windows/coda/CODA/MainWindow.xaml.cs index 60ca011441b7a..7f5fb3d283729 100644 --- a/windows/coda/CODA/MainWindow.xaml.cs +++ b/windows/coda/CODA/MainWindow.xaml.cs @@ -91,6 +91,9 @@ public struct pollfd { [DllImport("CODALib.dll", CharSet = CharSet.Unicode)] public static extern long fakeSocketDumpState(); + [DllImport("CODALib.dll", CharSet = CharSet.Unicode)] + public static extern void initialize_cpp_things(); + private CoreWebView2Settings _webViewSettings; CoreWebView2Settings WebViewSettings { @@ -134,6 +137,7 @@ public MainWindow() { Loaded += MainWindow_Loaded; InitializeComponent(); + initialize_cpp_things(); } private async void MainWindow_Loaded(object sender, RoutedEventArgs e) diff --git a/windows/coda/windows.cpp b/windows/coda/windows.cpp index 740f386542515..a455847d585aa 100755 --- a/windows/coda/windows.cpp +++ b/windows/coda/windows.cpp @@ -8,12 +8,21 @@ #include "windows.hpp" +#include +#include + +#include +#include +#include + const char *user_name = nullptr; int coolwsd_server_socket_fd = -1; LibreOfficeKit *lo_kit; +static COOLWSD *coolwsd = nullptr; + EXPORT int get_coolwsd_server_socket_fd() { @@ -27,4 +36,35 @@ int set_coolwsd_server_socket_fd(int fd) return fd; } +EXPORT +void initialize_cpp_things() +{ + Log::initialize("Mobile", "trace", false, false, {}); + Util::setThreadName("main"); + + fakeSocketSetLoggingCallback([](const std::string& line) + { + LOG_TRC_NOFILE(line); + }); + + std::thread([] + { + assert(coolwsd == nullptr); + char *argv[2]; + // Yes, strdup() is apparently not standard, so MS wants you to call it as + // _strdup(), and warns if you call strdup(). Sure, we could just silence such + // warnings, but let's try to do as they want. + argv[0] = _strdup("mobile"); + argv[1] = nullptr; + Util::setThreadName("app"); + while (true) + { + coolwsd = new COOLWSD(); + coolwsd->run(1, argv); + delete coolwsd; + LOG_TRC("One run of COOLWSD completed"); + } + }).detach(); +} + // vim:set shiftwidth=4 softtabstop=4 expandtab: From eabace722bef2427968b2391d4057abaf1edb7c9 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 2 Dec 2024 11:44:21 +0100 Subject: [PATCH 030/177] coda-m: Enable possibility to debug WKWebView from Safari MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In Safari, enable the Developer tools (Safari -> Preferences -> Advanced -> “Show Develop menu in menu bar”), and then you can see the CODA's console in the "Developer" menu. Signed-off-by: Jan Holesovsky Change-Id: I25c307983bf99db5c91135e4ab80110efb735cd9 --- macos/coda/coda/ViewController.swift | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/macos/coda/coda/ViewController.swift b/macos/coda/coda/ViewController.swift index 431d4f2dd6382..187d93f329cd6 100644 --- a/macos/coda/coda/ViewController.swift +++ b/macos/coda/coda/ViewController.swift @@ -32,6 +32,11 @@ class ViewController: NSViewController, WKScriptMessageHandler, WKNavigationDele webView = WKWebView(frame: .zero, configuration: config) webView.navigationDelegate = self +#if DEBUG + // Enable possibility to debug the webview from Safari + webView.isInspectable = true +#endif + // Add it to the view controller's view self.view.addSubview(webView) From d0d1a78ab18d54cf763ac02c01424910c1568c12 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 2 Dec 2024 12:16:22 +0100 Subject: [PATCH 031/177] coda-m: Get some debug output from send2JS (when enabled) Signed-off-by: Jan Holesovsky Change-Id: Ic891ae925620dabdf61de84a5d56eb2e88c89a61 --- macos/coda/coda/CODocument.mm | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/macos/coda/coda/CODocument.mm b/macos/coda/coda/CODocument.mm index 1a84b6330e7a1..415bb37315209 100644 --- a/macos/coda/coda/CODocument.mm +++ b/macos/coda/coda/CODocument.mm @@ -76,7 +76,7 @@ - (instancetype)initWithWebView:(WKWebView *)webView fileURL:(NSURL *)fileURL re } - (void)send2JS:(const char *)buffer length:(size_t)length { - //LOG_DBG("To JS: " << COOLProtocol::getAbbreviatedMessage(buffer, length).c_str()); + LOG_TRC("To JS: " << COOLProtocol::getAbbreviatedMessage(buffer, static_cast(length)).c_str()); bool binaryMessage = (isMessageOfType(buffer, "tile:", length) || isMessageOfType(buffer, "tilecombine:", length) || @@ -129,7 +129,7 @@ - (void)send2JS:(const char *)buffer length:(size_t)length { char outBuf[length + 1]; memcpy(outBuf, buffer, length); outBuf[length] = '\0'; - //LOG_ERR("Couldn't create NSString with message: " << outBuf); + LOG_ERR("Couldn't create NSString with message: " << outBuf); return; } @@ -137,17 +137,17 @@ - (void)send2JS:(const char *)buffer length:(size_t)length { if (subjs.length < js.length) subjs = [subjs stringByAppendingString:@"..."]; - // LOG_TRC("Evaluating JavaScript: " << [subjs UTF8String]); + LOG_TRC("Evaluating JavaScript: " << [subjs UTF8String]); dispatch_async(dispatch_get_main_queue(), ^{ [self.webView evaluateJavaScript:js completionHandler:^(id _Nullable obj, NSError * _Nullable error) { if (error) { - //LOG_ERR("Error after " << [subjs UTF8String] << ": " << [[error localizedDescription] UTF8String]); + LOG_ERR("Error after " << [subjs UTF8String] << ": " << [[error localizedDescription] UTF8String]); NSString *jsException = error.userInfo[@"WKJavaScriptExceptionMessage"]; - //if (jsException != nil) - // LOG_ERR("JavaScript exception: " << [jsException UTF8String]); + if (jsException != nil) + LOG_ERR("JavaScript exception: " << [jsException UTF8String]); } } ]; From bbe11519013ff85c3b377ac0618748957bbe24c3 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 2 Dec 2024 13:30:08 +0100 Subject: [PATCH 032/177] coda-m: We perform the same restrictions wrt. \n as on iOS Signed-off-by: Jan Holesovsky Change-Id: I67c505068db3856e092c53ed8dd932f000ca80bd --- browser/src/app/Socket.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/browser/src/app/Socket.ts b/browser/src/app/Socket.ts index b8910bf9ce239..5b77e00e0b8ae 100644 --- a/browser/src/app/Socket.ts +++ b/browser/src/app/Socket.ts @@ -1144,7 +1144,7 @@ class Socket { private _extractTextImg(e: SlurpMessageEvent): void { if ( - (window.ThisIsTheiOSApp || window.ThisIsTheEmscriptenApp) && + (window.ThisIsTheiOSApp || window.ThisIsTheMacOSApp || window.ThisIsTheEmscriptenApp) && typeof e.data === 'string' ) { // Another fix for issue #5843 limit splitting on the first newline From 2df3ab83763f910201100241394927536a5752ae Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Mon, 2 Dec 2024 15:25:18 +0200 Subject: [PATCH 033/177] Add experimentation with managed/native code marshalling on Windows Signed-off-by: Tor Lillqvist Change-Id: Ieb4d9ba955c01d1eb8254cbb98d954dc8338f692 --- .../coda/test/DllImportTest/DllImportTest.sln | 51 ++++++ .../DllImportTest/DllImportTest.csproj | 10 ++ .../DllImportTest/DllImportTest/Program.cs | 39 +++++ .../Properties/launchSettings.json | 8 + .../DllImported/DllImported.vcxproj | 147 ++++++++++++++++++ .../DllImportTest/DllImported/dllmain.cpp | 16 ++ 6 files changed, 271 insertions(+) create mode 100644 windows/coda/test/DllImportTest/DllImportTest.sln create mode 100644 windows/coda/test/DllImportTest/DllImportTest/DllImportTest.csproj create mode 100644 windows/coda/test/DllImportTest/DllImportTest/Program.cs create mode 100644 windows/coda/test/DllImportTest/DllImportTest/Properties/launchSettings.json create mode 100644 windows/coda/test/DllImportTest/DllImported/DllImported.vcxproj create mode 100644 windows/coda/test/DllImportTest/DllImported/dllmain.cpp diff --git a/windows/coda/test/DllImportTest/DllImportTest.sln b/windows/coda/test/DllImportTest/DllImportTest.sln new file mode 100644 index 0000000000000..15868ec796e76 --- /dev/null +++ b/windows/coda/test/DllImportTest/DllImportTest.sln @@ -0,0 +1,51 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.12.35506.116 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DllImportTest", "DllImportTest\DllImportTest.csproj", "{70D169E1-AE56-4387-8E3C-6A110981837B}" + ProjectSection(ProjectDependencies) = postProject + {662B5428-CC26-473C-9E3E-CDCEC296B0B5} = {662B5428-CC26-473C-9E3E-CDCEC296B0B5} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DllImported", "DllImported\DllImported.vcxproj", "{662B5428-CC26-473C-9E3E-CDCEC296B0B5}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {70D169E1-AE56-4387-8E3C-6A110981837B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {70D169E1-AE56-4387-8E3C-6A110981837B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {70D169E1-AE56-4387-8E3C-6A110981837B}.Debug|x64.ActiveCfg = Debug|Any CPU + {70D169E1-AE56-4387-8E3C-6A110981837B}.Debug|x64.Build.0 = Debug|Any CPU + {70D169E1-AE56-4387-8E3C-6A110981837B}.Debug|x86.ActiveCfg = Debug|Any CPU + {70D169E1-AE56-4387-8E3C-6A110981837B}.Debug|x86.Build.0 = Debug|Any CPU + {70D169E1-AE56-4387-8E3C-6A110981837B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {70D169E1-AE56-4387-8E3C-6A110981837B}.Release|Any CPU.Build.0 = Release|Any CPU + {70D169E1-AE56-4387-8E3C-6A110981837B}.Release|x64.ActiveCfg = Release|Any CPU + {70D169E1-AE56-4387-8E3C-6A110981837B}.Release|x64.Build.0 = Release|Any CPU + {70D169E1-AE56-4387-8E3C-6A110981837B}.Release|x86.ActiveCfg = Release|Any CPU + {70D169E1-AE56-4387-8E3C-6A110981837B}.Release|x86.Build.0 = Release|Any CPU + {662B5428-CC26-473C-9E3E-CDCEC296B0B5}.Debug|Any CPU.ActiveCfg = Debug|x64 + {662B5428-CC26-473C-9E3E-CDCEC296B0B5}.Debug|Any CPU.Build.0 = Debug|x64 + {662B5428-CC26-473C-9E3E-CDCEC296B0B5}.Debug|x64.ActiveCfg = Debug|x64 + {662B5428-CC26-473C-9E3E-CDCEC296B0B5}.Debug|x64.Build.0 = Debug|x64 + {662B5428-CC26-473C-9E3E-CDCEC296B0B5}.Debug|x86.ActiveCfg = Debug|Win32 + {662B5428-CC26-473C-9E3E-CDCEC296B0B5}.Debug|x86.Build.0 = Debug|Win32 + {662B5428-CC26-473C-9E3E-CDCEC296B0B5}.Release|Any CPU.ActiveCfg = Release|x64 + {662B5428-CC26-473C-9E3E-CDCEC296B0B5}.Release|Any CPU.Build.0 = Release|x64 + {662B5428-CC26-473C-9E3E-CDCEC296B0B5}.Release|x64.ActiveCfg = Release|x64 + {662B5428-CC26-473C-9E3E-CDCEC296B0B5}.Release|x64.Build.0 = Release|x64 + {662B5428-CC26-473C-9E3E-CDCEC296B0B5}.Release|x86.ActiveCfg = Release|Win32 + {662B5428-CC26-473C-9E3E-CDCEC296B0B5}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/windows/coda/test/DllImportTest/DllImportTest/DllImportTest.csproj b/windows/coda/test/DllImportTest/DllImportTest/DllImportTest.csproj new file mode 100644 index 0000000000000..91b464afeacc1 --- /dev/null +++ b/windows/coda/test/DllImportTest/DllImportTest/DllImportTest.csproj @@ -0,0 +1,10 @@ + + + + Exe + net8.0 + enable + enable + + + diff --git a/windows/coda/test/DllImportTest/DllImportTest/Program.cs b/windows/coda/test/DllImportTest/DllImportTest/Program.cs new file mode 100644 index 0000000000000..130c2682d8c82 --- /dev/null +++ b/windows/coda/test/DllImportTest/DllImportTest/Program.cs @@ -0,0 +1,39 @@ +using System.Runtime.InteropServices; + +public class DllImportTest +{ + public delegate void CallbackFunction1Delegate(int a, string s1, IntPtr s2, int s2length); + + [DllImport("DllImported.dll", CharSet = CharSet.Unicode)] + public static extern void set_callback_1(CallbackFunction1Delegate f); + + [DllImport("DllImported.dll", CharSet = CharSet.Unicode)] + public static extern void dllimport_function_1(int a, [MarshalAs(UnmanagedType.LPStr)] string s); + + public static void callbackFunction1(int a, string s1, IntPtr s2, int s2length) + { + Console.WriteLine($"Here is callbackFunction1, a={a}, s1='{s1}', s2='{Marshal.PtrToStringUTF8(s2, s2length)}'"); + Console.Write("s2 bytes:\""); + for (int i = 0; i < s2length; i++) + { + byte b = Marshal.ReadByte(s2, i); + if (b < ' ') + { + Console.Write("\\x"); + Console.Write(BitConverter.ToString([b])); + } + else + Console.Write((char)b); + } + Console.WriteLine("\""); + } + + static void Main(string[] args) + { + set_callback_1(callbackFunction1); + + Console.WriteLine("Hello"); + + dllimport_function_1(42, "HA HA"); + } +} diff --git a/windows/coda/test/DllImportTest/DllImportTest/Properties/launchSettings.json b/windows/coda/test/DllImportTest/DllImportTest/Properties/launchSettings.json new file mode 100644 index 0000000000000..3cce9c636a511 --- /dev/null +++ b/windows/coda/test/DllImportTest/DllImportTest/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "DllImportTest": { + "commandName": "Project", + "nativeDebugging": true + } + } +} \ No newline at end of file diff --git a/windows/coda/test/DllImportTest/DllImported/DllImported.vcxproj b/windows/coda/test/DllImportTest/DllImported/DllImported.vcxproj new file mode 100644 index 0000000000000..e8c351cabd739 --- /dev/null +++ b/windows/coda/test/DllImportTest/DllImported/DllImported.vcxproj @@ -0,0 +1,147 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 17.0 + Win32Proj + {662b5428-cc26-473c-9e3e-cdcec296b0b5} + DllImported + 10.0 + + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + $(SolutionDir)DllImportTest\bin/$(Configuration)\net8.0\ + + + $(SolutionDir)DllImportTest\bin/$(Configuration)\net8.0\ + + + + Level3 + true + WIN32;_DEBUG;DLLIMPORTED_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + + + Windows + true + false + + + + + Level3 + true + true + true + WIN32;NDEBUG;DLLIMPORTED_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + + + Windows + true + true + true + false + + + + + Level3 + true + _DEBUG;DLLIMPORTED_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + stdcpp20 + + + Windows + true + false + + + + + Level3 + true + true + true + NDEBUG;DLLIMPORTED_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + stdcpp20 + + + Windows + true + true + true + false + + + + + + + + + \ No newline at end of file diff --git a/windows/coda/test/DllImportTest/DllImported/dllmain.cpp b/windows/coda/test/DllImportTest/DllImported/dllmain.cpp new file mode 100644 index 0000000000000..91363c25a8c30 --- /dev/null +++ b/windows/coda/test/DllImportTest/DllImported/dllmain.cpp @@ -0,0 +1,16 @@ +typedef void (*callback1)(int a, const char *s1, const char *s2, int s2len); + +static callback1 callback1_function; + +extern "C" __declspec(dllexport) +void set_callback_1(callback1 f) +{ + callback1_function = f; +} + +extern "C" __declspec(dllexport) +void dllimport_function_1(int a, const char *s) +{ + callback1_function(a + 1, s, "Zero:\0:There", 12); +} + From ef920919fa6f3b753a878cefe0380ed8f7853167 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 2 Dec 2024 14:58:47 +0100 Subject: [PATCH 034/177] coda-m: Good to have these debugging possibilities around But no need to have them enabled for the moment. Signed-off-by: Jan Holesovsky Change-Id: I024b70c9b0b4c79fe4fa9597c105578af9d43575 --- wsd/COOLWSD.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/wsd/COOLWSD.cpp b/wsd/COOLWSD.cpp index 0d9d07290c2c8..9cafa7d3dfcf4 100644 --- a/wsd/COOLWSD.cpp +++ b/wsd/COOLWSD.cpp @@ -1697,8 +1697,12 @@ void COOLWSD::innerInitialize(Poco::Util::Application& self) #endif // !MOBILEAPP -#if defined(MACOS) && defined(DEBUG) - setenv("SAL_LOG", "+INFO+WARN", 0); +#if defined(DEBUG) + // Enable if you need more logging from core + //setenv("SAL_LOG", "+INFO+WARN", 0); + + // Enable if you need to see the top left corner of tile that was rendered + //setenv("LOK_DEBUG_TILES", "1", 0); #endif int pdfResolution = From 8ae74b3e6b3c8e8375fe53d46c775780129e30e4 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Mon, 2 Dec 2024 21:24:45 +0200 Subject: [PATCH 035/177] We do need LO_PATH in CODA-W LO_PATH is supposed to be the path to the LibreOffice installation (when developing, the instdir of the build). Signed-off-by: Tor Lillqvist Change-Id: I53aae9f18f2b82955efb83438b7ebdda4cd8ee3a --- configure.ac | 20 +++++++++++++++++--- windows/coda/config.h.in | 2 +- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 54f58b0768e85..b6923d1937078 100644 --- a/configure.ac +++ b/configure.ac @@ -257,7 +257,7 @@ AC_ARG_WITH([lokit-path], AC_ARG_WITH([lo-path], AS_HELP_STRING([--with-lo-path=], - [Path to a working installation directory or instdir of LibreOffice])) + [Path to a working installation directory or instdir of LibreOffice, to be used at runtime])) AC_ARG_WITH([lo-sourcedir], AS_HELP_STRING([--with-lo-sourcedir=], @@ -1375,11 +1375,20 @@ AS_IF([test -n "$LOKIT_PATH"], [CPPFLAGS="$CPPFLAGS -I${LOKIT_PATH}"]) lokit_msg="$LOKIT_PATH" -AS_IF([test "$ENABLE_IOSAPP" != "true" -a "$ENABLE_WINDOWSAPP" != "true" -a "$ENABLE_ANDROIDAPP" != "true"], +AS_IF([test "$ENABLE_IOSAPP" != "true" -a "$ENABLE_ANDROIDAPP" != "true"], [AC_MSG_CHECKING([for LibreOffice path]) if test -n "$with_lo_path"; then # strip trailing '/' from LO_PATH, 'ln -s' with such path will otherwise fail - LO_PATH=`readlink -f ${with_lo_path%/}` + if test "$ENABLE_WINDOWSAPP" != "true"; then + LO_PATH=`readlink -f ${with_lo_path%/}` + else + # LO_PATH is the path used at run-time to find the + # LibreOffice shared libraries. When running configure + # for the CODA-W app it is not used at configure or + # build time. Thus it should be a Windows path and not a + # WSL one. + LO_PATH="$with_lo_path" + fi AC_MSG_RESULT([found]) else AC_MSG_RESULT([not found]) @@ -2107,6 +2116,11 @@ if test "$enable_macosapp" = "yes"; then fi if test "$enable_windowsapp" = "yes"; then + # Don't use AC_CONFIG_HEADERS for windows/coda/config.h because we + # don't want to set random stuff that the configure script thinks + # it has detected, as that is very misleading because it is run on + # WSL. Ideally we shouldn't need to run the configure script when + # building CODA-W at all. Later. AC_CONFIG_FILES([windows/coda/config.h windows/coda/config.props]) fi diff --git a/windows/coda/config.h.in b/windows/coda/config.h.in index fb3d0783d3ee7..82d04bc38396d 100755 --- a/windows/coda/config.h.in +++ b/windows/coda/config.h.in @@ -89,7 +89,7 @@ #define COOLWSD_VERSION_HASH "@COOLWSD_VERSION_HASH@" /* Path to LibreOffice installation */ -#define LO_PATH "." +#define LO_PATH "@LO_PATH@" /* Define to the sub-directory where libtool stores uninstalled libraries. */ #undef LT_OBJDIR From ec6ea48785a3eb5748cd6e98a22ba66b3c7da4b3 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Mon, 2 Dec 2024 21:30:53 +0200 Subject: [PATCH 036/177] Pass non-null args to lok_init_2() for CODA-W Signed-off-by: Tor Lillqvist Change-Id: I58ab6205aa6db82d4dcbac6077d1d39633df9bc3 --- kit/Kit.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/kit/Kit.cpp b/kit/Kit.cpp index 24727a5989e7a..a0301d476e290 100644 --- a/kit/Kit.cpp +++ b/kit/Kit.cpp @@ -3943,7 +3943,12 @@ void lokit_main( #ifdef IOS // In the iOS app we call lok_init_2() just once, when the app starts static LibreOfficeKit *kit = lo_kit; +#elif defined(_WINDOWS) + // LO_PATH is a Windows path starting with a drive letter. For the second parameter to + // lok_init_2() turn it into a file: URI. + LibreOfficeKit *kit = lok_init_2(LO_PATH "/program", "file:///" LO_PATH); #else + // FIXME: I wonder for which platform this is supposed to be? Android? static LibreOfficeKit *kit = lok_init_2(nullptr, nullptr); #endif From 92f6212117f978a0452f058692c4556db99b38d5 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Mon, 2 Dec 2024 21:32:49 +0200 Subject: [PATCH 037/177] Try to get CODA-W to proceed further Move some code from C# to C++, and in fact use the same snippets as in the Gtk app. Keep the send2JS() function as C#, which necessitates various hacks related to calback delegates and avoiding such being garbage collected. Signed-off-by: Tor Lillqvist Change-Id: I8f62de0fa872b5f716c7b1b0b966208e8563a642 --- windows/coda/CODA/MainWindow.xaml.cs | 99 ++++++-------------- windows/coda/windows.cpp | 129 +++++++++++++++++++++++---- 2 files changed, 141 insertions(+), 87 deletions(-) diff --git a/windows/coda/CODA/MainWindow.xaml.cs b/windows/coda/CODA/MainWindow.xaml.cs index 7f5fb3d283729..458204daba386 100644 --- a/windows/coda/CODA/MainWindow.xaml.cs +++ b/windows/coda/CODA/MainWindow.xaml.cs @@ -42,9 +42,7 @@ public struct pollfd { private bool _isNavigating = false; - private int _fakeClientFd; - - private int[] _closeNotificationPipeForForwardingThread = new int[2]; + public delegate void Send2JSDelegate(IntPtr buffer, int length); [DllImport("CODALib.dll", CharSet = CharSet.Unicode)] public static extern int get_coolwsd_server_socket_fd(); @@ -94,6 +92,12 @@ public struct pollfd { [DllImport("CODALib.dll", CharSet = CharSet.Unicode)] public static extern void initialize_cpp_things(); + [DllImport("CODALib.dll", CharSet = CharSet.Unicode)] + public static extern void set_send2JS_function(Send2JSDelegate f); + + [DllImport("CODALib.dll", CharSet = CharSet.Unicode)] + public static extern void do_hullo_handling_things(); + private CoreWebView2Settings _webViewSettings; CoreWebView2Settings WebViewSettings { @@ -133,10 +137,18 @@ CoreWebView2Profile WebViewProfile } } + // Keep a static reference so that the delegate doesn't get garbage collected. Or something + // like that. + // private static Send2JSDelegate _reference; + private static GCHandle _gch; + public MainWindow() { Loaded += MainWindow_Loaded; InitializeComponent(); + Send2JSDelegate fp = new Send2JSDelegate(send2JS); + _gch = GCHandle.Alloc(fp); + set_send2JS_function(fp); initialize_cpp_things(); } @@ -153,64 +165,7 @@ void WebView_WebMessageReceived(object sender, CoreWebView2WebMessageReceivedEve if (args.WebMessageAsJson == "\"HULLO\"") { - Debug.Assert(get_coolwsd_server_socket_fd() != -1); - _fakeClientFd = fakeSocketSocket(); - - int rc = fakeSocketConnect(_fakeClientFd, get_coolwsd_server_socket_fd()); - Debug.Assert(rc != -1); - - fakeSocketPipe2(_closeNotificationPipeForForwardingThread); - - // Start a thread to read responses and forward them to the JavaScript. - - Task.Run(() => - { - while (true) - { - var p = new pollfd[2]; - p[0].fd = _fakeClientFd; - p[0].events = POLLIN; - p[1].fd = _closeNotificationPipeForForwardingThread[1]; - p[1].events = POLLIN; - if (fakeSocketPoll(p, 2, -1) > 0) - { - if (p[1].revents == POLLIN) - { - // The code below handling the "BYE" fake Websocket message has - // closed the other end of the - // closeNotificationPipeForForwardingThread. Let's close the - // other end too just for cleanliness, even if a FakeSocket as - // such is not a system resource so nothing is saved by closing - // it. - fakeSocketClose(_closeNotificationPipeForForwardingThread[1]); - - // Close our end of the fake socket connection to the - // ClientSession thread, so that it terminates - fakeSocketClose(_fakeClientFd); - - return; - } - if (p[0].revents == POLLIN) - { - long n = fakeSocketAvailableDataLength(_fakeClientFd); - // I don't want to check for n being -1 here, even if that will - // lead to a crash, as n being -1 is a sign of something being - // wrong elsewhere anyway, and I prefer to fix the root cause. - // Let's see how well this works out. - if (n == 0) - return; - var buf = new byte[n]; - n = fakeSocketRead(_fakeClientFd, buf, n); - send2JS(buf, n); - } - } - else - { - break; - } - } - Debug.Assert(false); - }); + do_hullo_handling_things(); } } @@ -259,7 +214,7 @@ void WebView_CoreWebView2InitializationCompleted(object sender, CoreWebView2Init { // FIXME: Temporarily when running from /windows/coda/CODA/bin/Debug. webView.CoreWebView2.SetVirtualHostNameToFolderMapping("appassets", "..\\..\\..\\..\\..\\browser\\dist", CoreWebView2HostResourceAccessKind.DenyCors); - webView.CoreWebView2.Navigate("https://appassets/cool.html?file_path=file:///C:/Users/tml/Sailing%20Yacht.odt&closebutton=1&permission=edit&appdocid=1&userinterfacemode=notebookbar&dir=ltr"); + webView.CoreWebView2.Navigate("https://appassets/cool.html?file_path=file:///C:/Users/tml/Sailing%20Yacht.odt&closebutton=1&permission=edit&lang=en-US&appdocid=1&userinterfacemode=notebookbar&dir=ltr"); OnWebViewFirstInitialized?.Invoke(); @@ -281,27 +236,29 @@ void WebView_CoreWebView2InitializationCompleted(object sender, CoreWebView2Init MessageBox.Show($"WebView2 creation failed with exception = {e.InitializationException}"); } - private bool _isMessageOfType(byte[] message, string type, long lengthOfMessage) + private bool _isMessageOfType(byte[] message, string type, int lengthOfMessage) { int typeLen = type.Length; return message.SequenceEqual(System.Text.Encoding.UTF8.GetBytes(type)); } - void send2JS(byte[] buffer, long length) + void send2JS(IntPtr buffer, int length) { - bool binaryMessage = (_isMessageOfType(buffer, "tile:", length) || - _isMessageOfType(buffer, "tilecombine:", length) || - _isMessageOfType(buffer, "delta:", length) || - _isMessageOfType(buffer, "renderfont:", length) || - _isMessageOfType(buffer, "rendersearchlist:", length) || - _isMessageOfType(buffer, "windowpaint:", length)); + byte[] s = new byte[length]; + Marshal.Copy(buffer, s, 0, length); + bool binaryMessage = (_isMessageOfType(s, "tile:", length) || + _isMessageOfType(s, "tilecombine:", length) || + _isMessageOfType(s, "delta:", length) || + _isMessageOfType(s, "renderfont:", length) || + _isMessageOfType(s, "rendersearchlist:", length) || + _isMessageOfType(s, "windowpaint:", length)); string pretext = binaryMessage ? "window.TheFakeWebSocket.onmessage({'data': window.atob('" : "window.TheFakeWebSocket.onmessage({'data': window.b64d('"; const string posttext = "')});"; - string js = pretext + System.Convert.ToBase64String(buffer) + posttext; + string js = pretext + System.Convert.ToBase64String(s) + posttext; _iWebView2.ExecuteScriptAsync(js); } diff --git a/windows/coda/windows.cpp b/windows/coda/windows.cpp index a455847d585aa..48003c5570878 100755 --- a/windows/coda/windows.cpp +++ b/windows/coda/windows.cpp @@ -8,6 +8,7 @@ #include "windows.hpp" +#include #include #include @@ -21,7 +22,14 @@ int coolwsd_server_socket_fd = -1; LibreOfficeKit *lo_kit; +static std::string fileURL = "file:///C:/Users/tml/Sailing%20Yacht.odt"; static COOLWSD *coolwsd = nullptr; +static int fakeClientFd; +static int closeNotificationPipeForForwardingThread[2]; + +typedef void (*send2JS_t)(char *buffer, long length); + +static send2JS_t send2JSfunction; EXPORT int get_coolwsd_server_socket_fd() @@ -39,6 +47,8 @@ int set_coolwsd_server_socket_fd(int fd) EXPORT void initialize_cpp_things() { + // FIXME: Code snippet shared with gtk/mobile.cpp, factor out into separate file. + Log::initialize("Mobile", "trace", false, false, {}); Util::setThreadName("main"); @@ -48,23 +58,110 @@ void initialize_cpp_things() }); std::thread([] + { + assert(coolwsd == nullptr); + char *argv[2]; + // Yes, strdup() is apparently not standard, so MS wants you to call it as + // _strdup(), and warns if you call strdup(). Sure, we could just silence such + // warnings, but let's try to do as they want. + argv[0] = _strdup("mobile"); + argv[1] = nullptr; + Util::setThreadName("app"); + while (true) + { + coolwsd = new COOLWSD(); + coolwsd->run(1, argv); + delete coolwsd; + LOG_TRC("One run of COOLWSD completed"); + } + }).detach(); + + fakeClientFd = fakeSocketSocket(); +} + +EXPORT +void set_send2JS_function(send2JS_t f) +{ + send2JSfunction = f; +} + +EXPORT +void do_hullo_handling_things() +{ + // FIXME: Code snippet shared with gtk/mobile.cpp, factor out into separate file. + + // Now we know that the JS has started completely + + // Contact the permanently (during app lifetime) listening COOLWSD server + // "public" socket + assert(coolwsd_server_socket_fd != -1); + int rc = fakeSocketConnect(fakeClientFd, coolwsd_server_socket_fd); + assert(rc != -1); + + // Create a socket pair to notify the below thread when the document has been closed + fakeSocketPipe2(closeNotificationPipeForForwardingThread); + + // Start another thread to read responses and forward them to the JavaScript + std::thread([] + { + Util::setThreadName("app2js"); + while (true) + { + struct pollfd pollfd[2]; + pollfd[0].fd = fakeClientFd; + pollfd[0].events = POLLIN; + pollfd[1].fd = closeNotificationPipeForForwardingThread[1]; + pollfd[1].events = POLLIN; + if (fakeSocketPoll(pollfd, 2, -1) > 0) + { + if (pollfd[1].revents == POLLIN) { - assert(coolwsd == nullptr); - char *argv[2]; - // Yes, strdup() is apparently not standard, so MS wants you to call it as - // _strdup(), and warns if you call strdup(). Sure, we could just silence such - // warnings, but let's try to do as they want. - argv[0] = _strdup("mobile"); - argv[1] = nullptr; - Util::setThreadName("app"); - while (true) - { - coolwsd = new COOLWSD(); - coolwsd->run(1, argv); - delete coolwsd; - LOG_TRC("One run of COOLWSD completed"); - } - }).detach(); + // The code below handling the "BYE" fake Websocket message has closed the other + // end of the closeNotificationPipeForForwardingThread. Let's close the other + // end too just for cleanliness, even if a FakeSocket as such is not a system + // resource so nothing is saved by closing it. + fakeSocketClose(closeNotificationPipeForForwardingThread[1]); + + // Close our end of the fake socket connection to the ClientSession thread, so + // that it terminates. + fakeSocketClose(fakeClientFd); + + return; + } + if (pollfd[0].revents == POLLIN) + { + int n = fakeSocketAvailableDataLength(fakeClientFd); + // I don't want to check for n being -1 here, even if that will lead to a crash, + // as n being -1 is a sign of something being wrong elsewhere anyway, and I + // prefer to fix the root cause. Let's see how well this works out. + if (n == 0) + return; + std::vector buf(n); + n = fakeSocketRead(fakeClientFd, buf.data(), n); + send2JSfunction(buf.data(), n); + } + } + else + { + break; + } + } + assert(false); + }).detach(); + + // First we simply send it the URL. This corresponds to the GET request with Upgrade to + // WebSocket. + LOG_TRC_NOFILE("Actually sending to Online:" << fileURL); + + // Must do this in a thread, too, so that we can return to the main loop + std::thread([] + { + struct pollfd pollfd; + pollfd.fd = fakeClientFd; + pollfd.events = POLLOUT; + fakeSocketPoll(&pollfd, 1, -1); + fakeSocketWrite(fakeClientFd, fileURL.c_str(), fileURL.size()); + }).detach(); } // vim:set shiftwidth=4 softtabstop=4 expandtab: From 55b33ddc5a0dcd876f2f18455635c6763bbfc342 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Tue, 3 Dec 2024 11:37:28 +0200 Subject: [PATCH 038/177] Re-indent a bit to better match our style Also makes it easier to verify that these two snippets are identical. (Will be factored out into a separate file later. And yes, I will come up with a better name than initialize_cpp_things(). Signed-off-by: Tor Lillqvist Change-Id: Ie4400d82a202c89b31f86c444bd687328c2c2f7b --- windows/coda/windows.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/windows/coda/windows.cpp b/windows/coda/windows.cpp index 48003c5570878..553f613585007 100755 --- a/windows/coda/windows.cpp +++ b/windows/coda/windows.cpp @@ -68,12 +68,12 @@ void initialize_cpp_things() argv[1] = nullptr; Util::setThreadName("app"); while (true) - { - coolwsd = new COOLWSD(); - coolwsd->run(1, argv); - delete coolwsd; - LOG_TRC("One run of COOLWSD completed"); - } + { + coolwsd = new COOLWSD(); + coolwsd->run(1, argv); + delete coolwsd; + LOG_TRC("One run of COOLWSD completed"); + } }).detach(); fakeClientFd = fakeSocketSocket(); From c2801f47bfe9da2642dfb31c45c699928d68cb08 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Tue, 3 Dec 2024 11:40:43 +0200 Subject: [PATCH 039/177] Attempt to handle Windows pathnames better Signed-off-by: Tor Lillqvist Change-Id: Ic21ad95f6d5d8c8fe09bf09d1ad2be49257bd61e --- wsd/RequestDetails.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/wsd/RequestDetails.cpp b/wsd/RequestDetails.cpp index ec2457c589853..5aa0cdf9944ff 100644 --- a/wsd/RequestDetails.cpp +++ b/wsd/RequestDetails.cpp @@ -23,6 +23,7 @@ #include +#include #include #include #include @@ -281,6 +282,11 @@ Poco::URI RequestDetails::sanitizeURI(const std::string& uri) { // TODO: Validate and limit access to local paths! uriPublic.normalize(); +#ifdef _WINDOWS + std::string p = uriPublic.getPath(); + if (p.length() > 4 && p[0] == '/' && std::isalpha(p[1]) && p[2] == ':' && p[3] == '/') + uriPublic.setPath(p.substr(1)); +#endif } if (uriPublic.getPath().empty()) From 6964cc0a3c940e8157dbb4cb30fdb92623377351 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Tue, 3 Dec 2024 14:03:49 +0200 Subject: [PATCH 040/177] Work on CODA-W, intermediate commit Drop unnecessary CharSet fields from the DllImport attributes. They are pointless for imported functions that don't even have any string parameters. Handle also BYE and arbitrary messages. As the latter come in as JSON strings (inside C# strings), we must deserialize them (drop the surrounding double-quotes and expand possible backslash sequences). Bin unneeded using declarations. Adapt to Log::initialize() parameter change Signed-off-by: Tor Lillqvist Change-Id: I694eb9212d71e280172f68861c2445fe5bfacb27 --- windows/coda/CODA/CODA.csproj | 2 + windows/coda/CODA/MainWindow.xaml.cs | 63 +++++++++++++++------------- windows/coda/windows.cpp | 32 ++++++++++++-- 3 files changed, 66 insertions(+), 31 deletions(-) diff --git a/windows/coda/CODA/CODA.csproj b/windows/coda/CODA/CODA.csproj index 9b2c61507a61f..1752d8fdbeddc 100644 --- a/windows/coda/CODA/CODA.csproj +++ b/windows/coda/CODA/CODA.csproj @@ -61,6 +61,8 @@ + + diff --git a/windows/coda/CODA/MainWindow.xaml.cs b/windows/coda/CODA/MainWindow.xaml.cs index 458204daba386..72bf69baa2080 100644 --- a/windows/coda/CODA/MainWindow.xaml.cs +++ b/windows/coda/CODA/MainWindow.xaml.cs @@ -1,21 +1,12 @@ // -*- tab-width: 4; indent-tabs-mode: nil; fill-column: 100 -*- using System; -using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Runtime.InteropServices; -using System.Text; +using System.Text.Json; using System.Threading.Tasks; using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; using Microsoft.Web.WebView2.Core; using Microsoft.Web.WebView2.Wpf; @@ -44,60 +35,66 @@ public struct pollfd { public delegate void Send2JSDelegate(IntPtr buffer, int length); - [DllImport("CODALib.dll", CharSet = CharSet.Unicode)] + [DllImport("CODALib.dll")] public static extern int get_coolwsd_server_socket_fd(); - [DllImport("CODALib.dll", CharSet = CharSet.Unicode)] + [DllImport("CODALib.dll")] public static extern int set_coolwsd_server_socket_fd(int fd); - [DllImport("CODALib.dll", CharSet = CharSet.Unicode)] + [DllImport("CODALib.dll")] public static extern int fakeSocketSocket(); - [DllImport("CODALib.dll", CharSet = CharSet.Unicode)] + [DllImport("CODALib.dll")] public static extern int fakeSocketPipe2(int[] pipefds); - [DllImport("CODALib.dll", CharSet = CharSet.Unicode)] + [DllImport("CODALib.dll")] public static extern int fakeSocketPoll(pollfd[] fds, int nfds, int timeout); - [DllImport("CODALib.dll", CharSet = CharSet.Unicode)] + [DllImport("CODALib.dll")] public static extern int fakeSocketListen(int fd); - [DllImport("CODALib.dll", CharSet = CharSet.Unicode)] + [DllImport("CODALib.dll")] public static extern int fakeSocketConnect(int fd1, int fd2); - [DllImport("CODALib.dll", CharSet = CharSet.Unicode)] + [DllImport("CODALib.dll")] public static extern int fakeSocketAccept4(int fd); - [DllImport("CODALib.dll", CharSet = CharSet.Unicode)] + [DllImport("CODALib.dll")] public static extern int fakeSocketPeer(int fd); - [DllImport("CODALib.dll", CharSet = CharSet.Unicode)] + [DllImport("CODALib.dll")] public static extern long fakeSocketAvailableDataLength(int fd); - [DllImport("CODALib.dll", CharSet = CharSet.Unicode)] + [DllImport("CODALib.dll")] public static extern long fakeSocketRead(int fd, byte[] buf, long nbytes); - [DllImport("CODALib.dll", CharSet = CharSet.Unicode)] + [DllImport("CODALib.dll")] public static extern long fakeSocketWrite(int fd, byte[] buf, long nbytes); - [DllImport("CODALib.dll", CharSet = CharSet.Unicode)] + [DllImport("CODALib.dll")] public static extern long fakeSocketShutdown(int fd); - [DllImport("CODALib.dll", CharSet = CharSet.Unicode)] + [DllImport("CODALib.dll")] public static extern long fakeSocketClose(int fd); - [DllImport("CODALib.dll", CharSet = CharSet.Unicode)] + [DllImport("CODALib.dll")] public static extern long fakeSocketDumpState(); - [DllImport("CODALib.dll", CharSet = CharSet.Unicode)] + [DllImport("CODALib.dll")] public static extern void initialize_cpp_things(); - [DllImport("CODALib.dll", CharSet = CharSet.Unicode)] + [DllImport("CODALib.dll")] public static extern void set_send2JS_function(Send2JSDelegate f); - [DllImport("CODALib.dll", CharSet = CharSet.Unicode)] + [DllImport("CODALib.dll")] public static extern void do_hullo_handling_things(); + [DllImport("CODALib.dll")] + public static extern void do_bye_handling_things(); + + [DllImport("CODALib.dll")] + public static extern void do_other_message_handling_things([MarshalAs(UnmanagedType.LPStr)] string message); + private CoreWebView2Settings _webViewSettings; CoreWebView2Settings WebViewSettings { @@ -144,6 +141,7 @@ CoreWebView2Profile WebViewProfile public MainWindow() { + Environment.SetEnvironmentVariable("SAL_LOG", "+WARN+INFO"); Loaded += MainWindow_Loaded; InitializeComponent(); Send2JSDelegate fp = new Send2JSDelegate(send2JS); @@ -167,6 +165,15 @@ void WebView_WebMessageReceived(object sender, CoreWebView2WebMessageReceivedEve { do_hullo_handling_things(); } + else if (args.WebMessageAsJson == "\"BYE\"") + { + do_bye_handling_things(); + } + else + { + string message = JsonSerializer.Deserialize(args.WebMessageAsJson); + do_other_message_handling_things(message); + } } private void SetWebView(IWebView2 newWebView2) diff --git a/windows/coda/windows.cpp b/windows/coda/windows.cpp index 553f613585007..f03f459f933d6 100755 --- a/windows/coda/windows.cpp +++ b/windows/coda/windows.cpp @@ -49,7 +49,7 @@ void initialize_cpp_things() { // FIXME: Code snippet shared with gtk/mobile.cpp, factor out into separate file. - Log::initialize("Mobile", "trace", false, false, {}); + Log::initialize("Mobile", "trace", false, false, {}, false, {}); Util::setThreadName("main"); fakeSocketSetLoggingCallback([](const std::string& line) @@ -92,8 +92,7 @@ void do_hullo_handling_things() // Now we know that the JS has started completely - // Contact the permanently (during app lifetime) listening COOLWSD server - // "public" socket + // Contact the permanently (during app lifetime) listening COOLWSD server "public" socket assert(coolwsd_server_socket_fd != -1); int rc = fakeSocketConnect(fakeClientFd, coolwsd_server_socket_fd); assert(rc != -1); @@ -164,4 +163,31 @@ void do_hullo_handling_things() }).detach(); } +EXPORT +void do_bye_handling_things() +{ + LOG_TRC_NOFILE("Document window terminating on JavaScript side. Closing our end of the socket."); + + // Close one end of the socket pair, that will wake up the forwarding thread above + fakeSocketClose(closeNotificationPipeForForwardingThread[0]); +} + +EXPORT +void do_other_message_handling_things(const char *message) +{ + LOG_TRC_NOFILE("Handling other message:'" << message << "'"); + + char *string_copy = _strdup(message); + // As above, must do this in a thread + std::thread([=] + { + struct pollfd pollfd; + pollfd.fd = fakeClientFd; + pollfd.events = POLLOUT; + fakeSocketPoll(&pollfd, 1, -1); + fakeSocketWrite(fakeClientFd, string_copy, strlen(string_copy)); + free(string_copy); + }).detach(); +} + // vim:set shiftwidth=4 softtabstop=4 expandtab: From 2c37a8d66a0fc31457d585917a538da8c53b4cda Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 3 Dec 2024 13:52:42 +0100 Subject: [PATCH 041/177] Four commits to coda-m squashed together Add Info.plist and NSDocument handler for ODT/ODS/ODP. Don't load the demo document right away. Trigger the ViewController when we should load the document. No real shell at the moment, so tell the user what to do. "Please open a document from the menu" Signed-off-by: Jan Holesovsky Change-Id: I50c370e36471c1012ec15e2d55ee42260ab7e3ff --- macos/coda/coda.xcodeproj/project.pbxproj | 2 + macos/coda/coda/Base.lproj/Main.storyboard | 70 ++++++++++++++++++---- macos/coda/coda/Document.swift | 70 ++++++++++++++++++++++ macos/coda/coda/Info.plist | 45 ++++++++++++++ 4 files changed, 177 insertions(+), 10 deletions(-) create mode 100644 macos/coda/coda/Document.swift create mode 100644 macos/coda/coda/Info.plist diff --git a/macos/coda/coda.xcodeproj/project.pbxproj b/macos/coda/coda.xcodeproj/project.pbxproj index 587e1f0e0423b..a605562a7b2bd 100644 --- a/macos/coda/coda.xcodeproj/project.pbxproj +++ b/macos/coda/coda.xcodeproj/project.pbxproj @@ -760,6 +760,7 @@ ENABLE_HARDENED_RUNTIME = YES; ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = coda/Info.plist; INFOPLIST_KEY_NSHumanReadableCopyright = ""; INFOPLIST_KEY_NSMainStoryboardFile = Main; INFOPLIST_KEY_NSPrincipalClass = NSApplication; @@ -791,6 +792,7 @@ ENABLE_HARDENED_RUNTIME = YES; ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = coda/Info.plist; INFOPLIST_KEY_NSHumanReadableCopyright = ""; INFOPLIST_KEY_NSMainStoryboardFile = Main; INFOPLIST_KEY_NSPrincipalClass = NSApplication; diff --git a/macos/coda/coda/Base.lproj/Main.storyboard b/macos/coda/coda/Base.lproj/Main.storyboard index 7ad7c709db69c..5c3756d40dc54 100644 --- a/macos/coda/coda/Base.lproj/Main.storyboard +++ b/macos/coda/coda/Base.lproj/Main.storyboard @@ -1,7 +1,8 @@ - - + + - + + @@ -673,7 +674,7 @@ - + @@ -693,25 +694,74 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - + + - + + + + + + + + + + + + + + + + + + + + + + + + + - + diff --git a/macos/coda/coda/Document.swift b/macos/coda/coda/Document.swift new file mode 100644 index 0000000000000..3d9cd5ee0dca4 --- /dev/null +++ b/macos/coda/coda/Document.swift @@ -0,0 +1,70 @@ +/* + * Copyright the Collabora Online contributors. + * + * SPDX-License-Identifier: MPL-2.0 + * + * 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/. + */ + +import Cocoa + +/** + * Represents a document in the application. + */ +class Document: NSDocument { + + // MARK: - Properties + + /// The content of the document, e.g., HTML data. + var documentData: Data? + + // MARK: - Initialization + + override init() { + super.init() + // Initialization code here. + } + + // MARK: - NSDocument Overrides + + /** + * Enables autosaving. + */ + override class var autosavesInPlace: Bool { + return true + } + + /** + * Creates the window controllers for the document. + */ + override func makeWindowControllers() { + // Load the storyboard and get the window controller. + let storyboard = NSStoryboard(name: "Main", bundle: nil) + let identifier = NSStoryboard.SceneIdentifier("DocumentWindowController") + guard let windowController = storyboard.instantiateController(withIdentifier: identifier) as? NSWindowController else { + fatalError("Unable to find DocumentWindowController in storyboard.") + } + self.addWindowController(windowController) + } + + /** + * Returns the document data to be saved. + */ + override func data(ofType typeName: String) throws -> Data { + // Save the document's data. + guard let data = documentData else { + throw NSError(domain: NSOSStatusErrorDomain, code: unimpErr, userInfo: nil) + } + return data + } + + /** + * Loads the document from data. + */ + override func read(from data: Data, ofType typeName: String) throws { + // Load the document's data. + self.documentData = data + } +} diff --git a/macos/coda/coda/Info.plist b/macos/coda/coda/Info.plist new file mode 100644 index 0000000000000..c7a9e499fa224 --- /dev/null +++ b/macos/coda/coda/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDocumentTypes + + + NSDocumentClass + $(PRODUCT_MODULE_NAME).Document + CFBundleTypeName + OpenDocument Text + CFBundleTypeRole + Editor + LSItemContentTypes + + org.oasis-open.opendocument.text + + + + NSDocumentClass + $(PRODUCT_MODULE_NAME).Document + CFBundleTypeName + OpenDocument Spreadsheet + CFBundleTypeRole + Editor + LSItemContentTypes + + org.oasis-open.opendocument.spreadsheet + + + + NSDocumentClass + $(PRODUCT_MODULE_NAME).Document + CFBundleTypeName + OpenDocument Presentation + CFBundleTypeRole + Editor + LSItemContentTypes + + org.oasis-open.opendocument.presentation + + + + + From 8ce74f068c12a647475cf4e4f02c04f358702817 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Tue, 3 Dec 2024 18:12:19 +0200 Subject: [PATCH 042/177] Also check window.ThisIsTheWindowsApp Signed-off-by: Tor Lillqvist Change-Id: I164c1244400b677a29477e98b624629f41a8c5e4 --- browser/src/app/Socket.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/browser/src/app/Socket.ts b/browser/src/app/Socket.ts index 5b77e00e0b8ae..8d26e4f650dfd 100644 --- a/browser/src/app/Socket.ts +++ b/browser/src/app/Socket.ts @@ -1144,7 +1144,10 @@ class Socket { private _extractTextImg(e: SlurpMessageEvent): void { if ( - (window.ThisIsTheiOSApp || window.ThisIsTheMacOSApp || window.ThisIsTheEmscriptenApp) && + (window.ThisIsTheiOSApp || + window.ThisIsTheWindowsApp || + window.ThisIsTheMacOSApp || + window.ThisIsTheEmscriptenApp) && typeof e.data === 'string' ) { // Another fix for issue #5843 limit splitting on the first newline From 8df9bb9aef09e04ea844a7cfbbc7556002bb4dba Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Tue, 3 Dec 2024 18:35:35 +0200 Subject: [PATCH 043/177] Change CODA to use .NET (and not .NET Framework) I wasn't aware of the difference when I created it. But .NET is the current thing, .NET Framework is on its way out. (While forward-porting this in March 2025 I updated the WebView2 version to the current one.) Add some more debugging output Signed-off-by: Tor Lillqvist Change-Id: I8eed09f3cda06a4e8341fdef0bc214226300a495 --- windows/coda/CODA.sln | 28 ++-- windows/coda/CODA/App.xaml.cs | 5 +- windows/coda/CODA/CODA.csproj | 146 ++---------------- windows/coda/CODA/CODA.csproj.user | 14 +- windows/coda/CODA/MainWindow.xaml | 10 +- windows/coda/CODA/MainWindow.xaml.cs | 39 ++++- windows/coda/CODA/Properties/AssemblyInfo.cs | 52 ------- .../CODA/Properties/Resources.Designer.cs | 63 -------- windows/coda/CODA/Properties/Resources.resx | 117 -------------- .../coda/CODA/Properties/Settings.Designer.cs | 26 ---- .../coda/CODA/Properties/Settings.settings | 7 - .../coda/CODA/Properties/launchSettings.json | 11 ++ windows/coda/CODALib/CODALib.vcxproj | 4 +- 13 files changed, 88 insertions(+), 434 deletions(-) delete mode 100644 windows/coda/CODA/Properties/AssemblyInfo.cs delete mode 100644 windows/coda/CODA/Properties/Resources.Designer.cs delete mode 100644 windows/coda/CODA/Properties/Resources.resx delete mode 100644 windows/coda/CODA/Properties/Settings.Designer.cs delete mode 100644 windows/coda/CODA/Properties/Settings.settings create mode 100644 windows/coda/CODA/Properties/launchSettings.json diff --git a/windows/coda/CODA.sln b/windows/coda/CODA.sln index 4efa7cb42c0c2..bbae053a62508 100644 --- a/windows/coda/CODA.sln +++ b/windows/coda/CODA.sln @@ -1,34 +1,38 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 -VisualStudioVersion = 17.11.35327.3 +VisualStudioVersion = 17.12.35521.163 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CODA", "CODA\CODA.csproj", "{4D688348-30C3-4141-B56E-ACAE0D143135}" - ProjectSection(ProjectDependencies) = postProject - {B0E65DEC-1CB0-4DAA-B3ED-709F8169BC40} = {B0E65DEC-1CB0-4DAA-B3ED-709F8169BC40} - EndProjectSection +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CODA", "CODA\CODA.csproj", "{A9AD4426-1615-46E6-AC61-248F9133D6AF}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CODALib", "CODALib\CODALib.vcxproj", "{B0E65DEC-1CB0-4DAA-B3ED-709F8169BC40}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU Debug|x64 = Debug|x64 + Release|Any CPU = Release|Any CPU Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {4D688348-30C3-4141-B56E-ACAE0D143135}.Debug|x64.ActiveCfg = Debug|Any CPU - {4D688348-30C3-4141-B56E-ACAE0D143135}.Debug|x64.Build.0 = Debug|Any CPU - {4D688348-30C3-4141-B56E-ACAE0D143135}.Release|x64.ActiveCfg = Release|Any CPU - {4D688348-30C3-4141-B56E-ACAE0D143135}.Release|x64.Build.0 = Release|Any CPU + {A9AD4426-1615-46E6-AC61-248F9133D6AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A9AD4426-1615-46E6-AC61-248F9133D6AF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A9AD4426-1615-46E6-AC61-248F9133D6AF}.Debug|x64.ActiveCfg = Debug|Any CPU + {A9AD4426-1615-46E6-AC61-248F9133D6AF}.Debug|x64.Build.0 = Debug|Any CPU + {A9AD4426-1615-46E6-AC61-248F9133D6AF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A9AD4426-1615-46E6-AC61-248F9133D6AF}.Release|Any CPU.Build.0 = Release|Any CPU + {A9AD4426-1615-46E6-AC61-248F9133D6AF}.Release|x64.ActiveCfg = Release|Any CPU + {A9AD4426-1615-46E6-AC61-248F9133D6AF}.Release|x64.Build.0 = Release|Any CPU + {B0E65DEC-1CB0-4DAA-B3ED-709F8169BC40}.Debug|Any CPU.ActiveCfg = Debug|x64 + {B0E65DEC-1CB0-4DAA-B3ED-709F8169BC40}.Debug|Any CPU.Build.0 = Debug|x64 {B0E65DEC-1CB0-4DAA-B3ED-709F8169BC40}.Debug|x64.ActiveCfg = Debug|x64 {B0E65DEC-1CB0-4DAA-B3ED-709F8169BC40}.Debug|x64.Build.0 = Debug|x64 + {B0E65DEC-1CB0-4DAA-B3ED-709F8169BC40}.Release|Any CPU.ActiveCfg = Release|x64 + {B0E65DEC-1CB0-4DAA-B3ED-709F8169BC40}.Release|Any CPU.Build.0 = Release|x64 {B0E65DEC-1CB0-4DAA-B3ED-709F8169BC40}.Release|x64.ActiveCfg = Release|x64 {B0E65DEC-1CB0-4DAA-B3ED-709F8169BC40}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {03736A44-ED48-4967-9357-8809491FFE77} - EndGlobalSection EndGlobal diff --git a/windows/coda/CODA/App.xaml.cs b/windows/coda/CODA/App.xaml.cs index 6e6e9238ebe0e..70cf1fbe116d7 100644 --- a/windows/coda/CODA/App.xaml.cs +++ b/windows/coda/CODA/App.xaml.cs @@ -1,9 +1,5 @@ -using System; -using System.Collections.Generic; using System.Configuration; using System.Data; -using System.Linq; -using System.Threading.Tasks; using System.Windows; namespace CODA @@ -11,4 +7,5 @@ namespace CODA public partial class App : Application { } + } diff --git a/windows/coda/CODA/CODA.csproj b/windows/coda/CODA/CODA.csproj index 1752d8fdbeddc..71755ffeb0530 100644 --- a/windows/coda/CODA/CODA.csproj +++ b/windows/coda/CODA/CODA.csproj @@ -1,142 +1,16 @@ - - + + - Collabora Productivity - Collabora Online as a Desktop App - Copyright © 2024 - Debug - AnyCPU - {4D688348-30C3-4141-B56E-ACAE0D143135} WinExe - CODA - CODA - v4.8 - 512 - {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 4 - true - true - - 11 - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0 - false - false - true - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - false - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - + net8.0-windows + enable + enable + true CODA.App + - - - - - - - - - - - - - 4.0 - - - - - - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - App.xaml - Code - - - MainWindow.xaml - Code - - - - - Code - - - True - True - Resources.resx - - - True - Settings.settings - True - - - ResXFileCodeGenerator - Resources.Designer.cs - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - - - - - - 1.0.3124.44 - - - - - - False - Microsoft .NET Framework 4.8 %28x86 and x64%29 - true - - - False - .NET Framework 3.5 SP1 - false - + - - \ No newline at end of file + + diff --git a/windows/coda/CODA/CODA.csproj.user b/windows/coda/CODA/CODA.csproj.user index be279c3eb28ed..466ebea68c370 100644 --- a/windows/coda/CODA/CODA.csproj.user +++ b/windows/coda/CODA/CODA.csproj.user @@ -1,6 +1,14 @@ - - true - + + + + Designer + + + + + Designer + + \ No newline at end of file diff --git a/windows/coda/CODA/MainWindow.xaml b/windows/coda/CODA/MainWindow.xaml index bb9bec297841b..48709425f9254 100644 --- a/windows/coda/CODA/MainWindow.xaml +++ b/windows/coda/CODA/MainWindow.xaml @@ -1,4 +1,4 @@ - + - - diff --git a/windows/coda/CODA/MainWindow.xaml.cs b/windows/coda/CODA/MainWindow.xaml.cs index 72bf69baa2080..d19de30162bd9 100644 --- a/windows/coda/CODA/MainWindow.xaml.cs +++ b/windows/coda/CODA/MainWindow.xaml.cs @@ -1,9 +1,10 @@ -// -*- tab-width: 4; indent-tabs-mode: nil; fill-column: 100 -*- +// -*- tab-width: 4; indent-tabs-mode: nil; fill-column: 100 -*- using System; using System.Diagnostics; using System.Linq; using System.Runtime.InteropServices; +using System.Text; using System.Text.Json; using System.Threading.Tasks; using System.Windows; @@ -219,8 +220,8 @@ void WebView_CoreWebView2InitializationCompleted(object sender, CoreWebView2Init IWebView2 webView = sender as IWebView2; if (e.IsSuccess) { - // FIXME: Temporarily when running from /windows/coda/CODA/bin/Debug. - webView.CoreWebView2.SetVirtualHostNameToFolderMapping("appassets", "..\\..\\..\\..\\..\\browser\\dist", CoreWebView2HostResourceAccessKind.DenyCors); + // FIXME: Temporarily when running from /windows/coda/CODA/bin/Debug/net8.0-windows. + webView.CoreWebView2.SetVirtualHostNameToFolderMapping("appassets", "..\\..\\..\\..\\..\\..\\browser\\dist", CoreWebView2HostResourceAccessKind.DenyCors); webView.CoreWebView2.Navigate("https://appassets/cool.html?file_path=file:///C:/Users/tml/Sailing%20Yacht.odt&closebutton=1&permission=edit&lang=en-US&appdocid=1&userinterfacemode=notebookbar&dir=ltr"); OnWebViewFirstInitialized?.Invoke(); @@ -265,8 +266,40 @@ void send2JS(IntPtr buffer, int length) : "window.TheFakeWebSocket.onmessage({'data': window.b64d('"; const string posttext = "')});"; + if (!binaryMessage) + { + StringBuilder sb = new StringBuilder(s.Length*2); + + for (int i = 0; i < (s.Length > 100 ? 100 : s.Length); i++) + { + if (s[i] >= ' ' && s[i] < 127 && s[i] != '\\') + sb.Append((Char)s[i]); + else if (s[i] == '\\') + sb.Append("\\\\"); + else if (s[i] == '\n') + sb.Append("\\n"); + else + { + string hex = "0123456789abcdef"; + sb.Append("\\" + hex[s[i] >> 4] + hex[s[i] & 0x0F]); + } + } + string subs = sb.ToString(); + if (sb.Length > 100) + subs += "..."; + Debug.WriteLine("Evaluating JavaScript: " + subs); + } + string js = pretext + System.Convert.ToBase64String(s) + posttext; + if (binaryMessage) + { + string subjs = js.Substring(0, (js.Length > 100 ? 100 : js.Length)); + if (js.Length > 100) + subjs += "..."; + Debug.WriteLine("Evaluating JavaScript: " + subjs); + } + _iWebView2.ExecuteScriptAsync(js); } diff --git a/windows/coda/CODA/Properties/AssemblyInfo.cs b/windows/coda/CODA/Properties/AssemblyInfo.cs deleted file mode 100644 index 6f3ef09e62c80..0000000000000 --- a/windows/coda/CODA/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System.Reflection; -using System.Resources; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Windows; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("CODA")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("CODA")] -[assembly: AssemblyCopyright("Copyright © 2024")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -//In order to begin building localizable applications, set -//CultureYouAreCodingWith in your .csproj file -//inside a . For example, if you are using US english -//in your source files, set the to en-US. Then uncomment -//the NeutralResourceLanguage attribute below. Update the "en-US" in -//the line below to match the UICulture setting in the project file. - -//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] - - -[assembly: ThemeInfo( - ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located - //(used if a resource is not found in the page, - // or application resource dictionaries) - ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located - //(used if a resource is not found in the page, - // app, or any theme specific resource dictionaries) -)] - - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/windows/coda/CODA/Properties/Resources.Designer.cs b/windows/coda/CODA/Properties/Resources.Designer.cs deleted file mode 100644 index e6bcd0a4a2a7d..0000000000000 --- a/windows/coda/CODA/Properties/Resources.Designer.cs +++ /dev/null @@ -1,63 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace CODA.Properties { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CODA.Properties.Resources", typeof(Resources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - } -} diff --git a/windows/coda/CODA/Properties/Resources.resx b/windows/coda/CODA/Properties/Resources.resx deleted file mode 100644 index af7dbebbacef5..0000000000000 --- a/windows/coda/CODA/Properties/Resources.resx +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/windows/coda/CODA/Properties/Settings.Designer.cs b/windows/coda/CODA/Properties/Settings.Designer.cs deleted file mode 100644 index 07ebf441add14..0000000000000 --- a/windows/coda/CODA/Properties/Settings.Designer.cs +++ /dev/null @@ -1,26 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace CODA.Properties { - - - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.11.0.0")] - internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { - - private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); - - public static Settings Default { - get { - return defaultInstance; - } - } - } -} diff --git a/windows/coda/CODA/Properties/Settings.settings b/windows/coda/CODA/Properties/Settings.settings deleted file mode 100644 index 033d7a5e9e226..0000000000000 --- a/windows/coda/CODA/Properties/Settings.settings +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/windows/coda/CODA/Properties/launchSettings.json b/windows/coda/CODA/Properties/launchSettings.json new file mode 100644 index 0000000000000..c806d32110d1d --- /dev/null +++ b/windows/coda/CODA/Properties/launchSettings.json @@ -0,0 +1,11 @@ +{ + "profiles": { + "CODA": { + "commandName": "Project", + "environmentVariables": { + "SAL_LOG": "+INFO+WARN" + }, + "nativeDebugging": true + } + } +} \ No newline at end of file diff --git a/windows/coda/CODALib/CODALib.vcxproj b/windows/coda/CODALib/CODALib.vcxproj index db1303c8a9777..01a672b741ee6 100644 --- a/windows/coda/CODALib/CODALib.vcxproj +++ b/windows/coda/CODALib/CODALib.vcxproj @@ -46,10 +46,10 @@ - $(SolutionDir)CODA\bin\$(Configuration)\ + $(SolutionDir)CODA\bin\$(Configuration)\net8.0-windows - $(SolutionDir)CODA\bin\$(Configuration)\ + $(SolutionDir)CODA\bin\$(Configuration)\net8.0-windows From 50e051cb7471c53dc6b0fab4129b84bfc3c3e00c Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 9 Dec 2024 12:24:24 +0100 Subject: [PATCH 044/177] coda-m: Read the document that the user has choser in File -> Open... For the File -> New, we still just open the hello.odt. Signed-off-by: Jan Holesovsky Change-Id: Ifc3223d926b2fe2db2b52744c682297068802150 --- macos/coda/coda/Document.swift | 19 +++++++++++-------- macos/coda/coda/ViewController.swift | 15 +++++++++++---- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/macos/coda/coda/Document.swift b/macos/coda/coda/Document.swift index 3d9cd5ee0dca4..956c4e0a553fd 100644 --- a/macos/coda/coda/Document.swift +++ b/macos/coda/coda/Document.swift @@ -17,8 +17,8 @@ class Document: NSDocument { // MARK: - Properties - /// The content of the document, e.g., HTML data. - var documentData: Data? + /// The location of the document. + var url: URL? // MARK: - Initialization @@ -47,24 +47,27 @@ class Document: NSDocument { fatalError("Unable to find DocumentWindowController in storyboard.") } self.addWindowController(windowController) + + if let viewController = windowController.contentViewController as? ViewController { + viewController.loadDocument(documentURL: url) + } } /** * Returns the document data to be saved. */ - override func data(ofType typeName: String) throws -> Data { + /*override func data(ofType typeName: String) throws -> Data { // Save the document's data. guard let data = documentData else { throw NSError(domain: NSOSStatusErrorDomain, code: unimpErr, userInfo: nil) } return data - } + }*/ /** - * Loads the document from data. + * Just remember the document URL here, will be loaded when the ViewController is created. */ - override func read(from data: Data, ofType typeName: String) throws { - // Load the document's data. - self.documentData = data + override func read(from url: URL, ofType typeName: String) throws { + self.url = url } } diff --git a/macos/coda/coda/ViewController.swift b/macos/coda/coda/ViewController.swift index 187d93f329cd6..7ed4abbffb16e 100644 --- a/macos/coda/coda/ViewController.swift +++ b/macos/coda/coda/ViewController.swift @@ -47,13 +47,20 @@ class ViewController: NSViewController, WKScriptMessageHandler, WKNavigationDele webView.topAnchor.constraint(equalTo: self.view.topAnchor), webView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor) ]) + } - // Load the HTML, and the document itself via that - let testFileURL = Bundle.main.url(forResource: "hello", withExtension: "odt")! - document = CODocument(webView: webView, fileURL: testFileURL, readOnly: false) + /** + * Load the the document; to be called from the Document (NSDocument) instance. + */ + func loadDocument(documentURL: URL?) { + // FIXME: Defaults to the hello.odt if not provided (which happens eg. when created from File -> New) + let fileURL = documentURL ?? Bundle.main.url(forResource: "hello", withExtension: "odt")! + document = CODocument(webView: webView, fileURL: fileURL, readOnly: false) } - // Receive message from JavaScript + /** + * Receive message from JavaScript + */ func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { if message.name == "error" { if let body = message.body as? String { From 701d8de6c8a05a168ecd6ff3cc0d7edf36d8af5d Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Mon, 9 Dec 2024 15:54:11 +0200 Subject: [PATCH 045/177] Three CODA-W commits squashed together Rename hardcoded document to just sailing.odt in case the %20 is a problem. We don't need the POLL* definitions here now. We set SAL_LOG in launchSettings.json now. Signed-off-by: Tor Lillqvist Change-Id: Ib23cd0562e46ea07871a02ac901c1f242c65e20a --- windows/coda/CODA/MainWindow.xaml.cs | 12 +----------- windows/coda/windows.cpp | 2 +- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/windows/coda/CODA/MainWindow.xaml.cs b/windows/coda/CODA/MainWindow.xaml.cs index d19de30162bd9..9b08f5c3f1e92 100644 --- a/windows/coda/CODA/MainWindow.xaml.cs +++ b/windows/coda/CODA/MainWindow.xaml.cs @@ -15,15 +15,6 @@ namespace CODA { public partial class MainWindow : Window { - // FIXME: Is there some clever way to not have to duplicate the POLL* and struct pollfd - // definitions for the C# and C++ parts of CODA-W? - const int POLLIN = 0x001; - const int POLLPRI = 0x002; - const int POLLOUT = 0x004; - const int POLLERR = 0x008; - const int POLLHUP = 0x010; - const int POLLNVAL = 0x020; - public struct pollfd { public int fd; public short events; @@ -142,7 +133,6 @@ CoreWebView2Profile WebViewProfile public MainWindow() { - Environment.SetEnvironmentVariable("SAL_LOG", "+WARN+INFO"); Loaded += MainWindow_Loaded; InitializeComponent(); Send2JSDelegate fp = new Send2JSDelegate(send2JS); @@ -222,7 +212,7 @@ void WebView_CoreWebView2InitializationCompleted(object sender, CoreWebView2Init { // FIXME: Temporarily when running from /windows/coda/CODA/bin/Debug/net8.0-windows. webView.CoreWebView2.SetVirtualHostNameToFolderMapping("appassets", "..\\..\\..\\..\\..\\..\\browser\\dist", CoreWebView2HostResourceAccessKind.DenyCors); - webView.CoreWebView2.Navigate("https://appassets/cool.html?file_path=file:///C:/Users/tml/Sailing%20Yacht.odt&closebutton=1&permission=edit&lang=en-US&appdocid=1&userinterfacemode=notebookbar&dir=ltr"); + webView.CoreWebView2.Navigate("https://appassets/cool.html?file_path=file:///C:/Users/tml/sailing.odt&closebutton=1&permission=edit&lang=en-US&appdocid=1&userinterfacemode=notebookbar&dir=ltr"); OnWebViewFirstInitialized?.Invoke(); diff --git a/windows/coda/windows.cpp b/windows/coda/windows.cpp index f03f459f933d6..398439b4f0519 100755 --- a/windows/coda/windows.cpp +++ b/windows/coda/windows.cpp @@ -22,7 +22,7 @@ int coolwsd_server_socket_fd = -1; LibreOfficeKit *lo_kit; -static std::string fileURL = "file:///C:/Users/tml/Sailing%20Yacht.odt"; +static std::string fileURL = "file:///C:/Users/tml/sailing.odt"; static COOLWSD *coolwsd = nullptr; static int fakeClientFd; static int closeNotificationPipeForForwardingThread[2]; From 84b2c0b0907358a8ec62bda74df4771e8b41305a Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 9 Dec 2024 14:02:02 +0100 Subject: [PATCH 046/177] Six CODA-M commits squashed together Simplify the document loading. No need to duplicate the URL. Implement saving of the file. For the moment, the user has to trigger the Save in the webview first, and only after that, the Save from the app's menu works. Implement MODIFIED status & trigger save when it changes. The NSDocument needs to be notified when the document copy was modified, so that it can trigger the save operation (which only copies the copy back to the original document). Convert CODocument functionality to Swift and merge into Document. It was confusing to have CODocument (in Objective-C) and Document (that is derived from NSDocument). It turned out that it is possible to consolidate them into one file, so let's do that to make things less confusing. Further simplification of COWrapper. Add some purpose comments. Signed-off-by: Jan Holesovsky Change-Id: Ie2be9468caab6842bcfd0356330fc08c03f4110d --- browser/src/map/Map.js | 4 + macos/coda/coda/AppDelegate.swift | 4 +- macos/coda/coda/CODocument.h | 36 ----- macos/coda/coda/CODocument.mm | 159 ---------------------- macos/coda/coda/COWrapper.h | 16 +-- macos/coda/coda/COWrapper.mm | 50 +++---- macos/coda/coda/Document.swift | 192 +++++++++++++++++++++++++-- macos/coda/coda/ViewController.swift | 20 ++- macos/coda/coda/coda.entitlements | 2 +- 9 files changed, 233 insertions(+), 250 deletions(-) delete mode 100644 macos/coda/coda/CODocument.h delete mode 100644 macos/coda/coda/CODocument.mm diff --git a/browser/src/map/Map.js b/browser/src/map/Map.js index 50892813dae14..fc92fe9a6f1c3 100644 --- a/browser/src/map/Map.js +++ b/browser/src/map/Map.js @@ -241,6 +241,10 @@ window.L.Map = window.L.Evented.extend({ // Fire an event to let the client know whether the document needs saving or not. this.fire('postMessage', {msgId: 'Doc_ModifiedStatus', args: { Modified: e.state === 'true' }}); + if (window.ThisIsAMobileApp) { + window.postMobileMessage('MODIFIED ' + e.state); + } + if (this._everModified) { this.fire('updatemodificationindicator', { status: e.state === 'true' ? 'MODIFIED' : 'SAVED' }); } diff --git a/macos/coda/coda/AppDelegate.swift b/macos/coda/coda/AppDelegate.swift index 676ca2456607a..54950d625a1b5 100644 --- a/macos/coda/coda/AppDelegate.swift +++ b/macos/coda/coda/AppDelegate.swift @@ -15,12 +15,12 @@ class AppDelegate: NSObject, NSApplicationDelegate { func applicationDidFinishLaunching(_ aNotification: Notification) { // Initialize the COOLWSD - COWrapper.shared.startServer() + COWrapper.startServer() } func applicationWillTerminate(_ aNotification: Notification) { // Insert code here to tear down your application - COWrapper.shared.stopServer() + COWrapper.stopServer() } func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { diff --git a/macos/coda/coda/CODocument.h b/macos/coda/coda/CODocument.h deleted file mode 100644 index 80f8a374eebb4..0000000000000 --- a/macos/coda/coda/CODocument.h +++ /dev/null @@ -1,36 +0,0 @@ -// -*- Mode: ObjC; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- -/* - * Copyright the Collabora Online contributors. - * - * SPDX-License-Identifier: MPL-2.0 - * - * 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/. - */ - -#import - -#define LOK_USE_UNSTABLE_API -#import - -@class WKWebView; - -@interface CODocument : NSObject { -@public - int fakeClientFd; - bool readOnly; -} - -@property NSURL *fileURL; -@property unsigned appDocId; -@property (weak) WKWebView *webView; - -/** Custom initializer */ -- (instancetype)initWithWebView:(WKWebView *)webView fileURL:(NSURL *)fileURL readOnly:(bool)readOnly; - -- (void)send2JS:(const char*)buffer length:(size_t)length; - -@end - -// vim:set shiftwidth=4 softtabstop=4 expandtab: diff --git a/macos/coda/coda/CODocument.mm b/macos/coda/coda/CODocument.mm deleted file mode 100644 index 415bb37315209..0000000000000 --- a/macos/coda/coda/CODocument.mm +++ /dev/null @@ -1,159 +0,0 @@ -// -*- Mode: ObjC; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- -/* - * Copyright the Collabora Online contributors. - * - * SPDX-License-Identifier: MPL-2.0 - * - * 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/. - */ - -#import "config.h" -#import "Foundation/Foundation.h" -#import - -#import - -#import "macos.h" -#import "CODocument.h" - -//#import "ClientSession.hpp" -//#import "DocumentBroker.hpp" -#import "FakeSocket.hpp" -//#import "Kit.hpp" -//#import "KitHelper.hpp" -#import "Log.hpp" -//#import "COOLWSD.hpp" -#import "MobileApp.hpp" -#import "Protocol.hpp" - -static inline bool isMessageOfType(const char *message, const char *type, size_t lengthOfMessage) { - // Note: message is not zero terminated but type is - size_t typeLen = strlen(type); - return (typeLen <= lengthOfMessage && !strncmp(message, type, typeLen)); -} - -@implementation CODocument - -/*- (id)contentsForType:(NSString*)typeName error:(NSError **)errorPtr { - return [NSData dataWithContentsOfFile:[copyFileURL path] options:0 error:errorPtr]; -}*/ - -// We keep a running count of opening documents here. This is not necessarily in sync with the -// DocBrokerId in DocumentBroker due to potential parallelism when opening multiple documents in -// quick succession. - -static std::atomic appDocIdCounter(1); - -- (instancetype)initWithWebView:(WKWebView *)webView fileURL:(NSURL *)fileURL readOnly:(bool)readOnly { - self = [super init]; - self.webView = webView; - self.fileURL = fileURL; - self.appDocId = appDocIdCounter++; - - fakeClientFd = fakeSocketSocket(); - - NSURL *url = [[NSBundle mainBundle] URLForResource:@"cool" withExtension:@"html"]; - NSURLComponents *components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO]; - //DocumentData::allocate(appDocId).coDocument = self; - components.queryItems = @[ [NSURLQueryItem queryItemWithName:@"file_path" value:[fileURL absoluteString]], - [NSURLQueryItem queryItemWithName:@"closebutton" value:@"1"], - [NSURLQueryItem queryItemWithName:@"permission" value:(readOnly ? @"readonly" : @"edit")], - // TODO: [NSURLQueryItem queryItemWithName:@"lang" value:app_locale], - [NSURLQueryItem queryItemWithName:@"appdocid" value:[NSString stringWithFormat:@"%u", self.appDocId]], - [NSURLQueryItem queryItemWithName:@"userinterfacemode" value:@"notebookbar"], - // Related to issue #5841: the iOS app sets the - // base text direction via the "dir" parameter - // TODO: [NSURLQueryItem queryItemWithName:@"dir" value:app_text_direction], - ]; - - NSURLRequest *request = [[NSURLRequest alloc]initWithURL:components.URL]; - NSURL *urlDir = [url URLByDeletingLastPathComponent]; - [self.webView loadFileRequest:request allowingReadAccessToURL:urlDir]; - - return self; -} - -- (void)send2JS:(const char *)buffer length:(size_t)length { - LOG_TRC("To JS: " << COOLProtocol::getAbbreviatedMessage(buffer, static_cast(length)).c_str()); - - bool binaryMessage = (isMessageOfType(buffer, "tile:", length) || - isMessageOfType(buffer, "tilecombine:", length) || - isMessageOfType(buffer, "delta:", length) || - isMessageOfType(buffer, "renderfont:", length) || - isMessageOfType(buffer, "rendersearchlist:", length) || - isMessageOfType(buffer, "windowpaint:", length)); - - const char *pretext = binaryMessage ? "window.TheFakeWebSocket.onmessage({'data': window.atob('" - : "window.TheFakeWebSocket.onmessage({'data': window.b64d('"; - const char *posttext = "')});"; - const size_t pretextlen = strlen(pretext); - const size_t posttextlen = strlen(posttext); - - std::vector data; - // Reserve the maxiumum possible length after encoding - // This avoids an excessive number of reallocations. This is overkill - // for non-binary messages, but most non-binary messages appear to be - // under 1K bytes in length. In contrast, it appears that binary - // messags routinely use at least 75% of the maximum possible length. - data.reserve(pretextlen + (length * 4) + posttextlen + 1); - - for (int i = 0; i < pretextlen; i++) - data.push_back(pretext[i]); - - @autoreleasepool { - const NSData * payload = [NSData dataWithBytesNoCopy:const_cast(buffer) length:length freeWhenDone:NO]; - const NSString * encodedPayload = [payload base64EncodedStringWithOptions: 0]; - const std::string_view utf8EncodedPayload = [encodedPayload UTF8String]; - - for (const char& character : utf8EncodedPayload) - data.push_back(character); - } - - for (int i = 0; i < posttextlen; i++) - data.push_back(posttext[i]); - - data.push_back(0); - - // Related to issue #5876: don't autorelease large NSStrings - // The +[NSString string...] selectors won't be released until - // an enclosing autorelease pool is released. But since we use - // ARC, we don't know where the compiler has inserted the - // autorelease pool so JS messages may not be released until - // after a very long time potentially causing an out of memory - // crash. So, use the -[[NSString alloc] init...] selectors - // instead. - NSString *js = [[NSString alloc] initWithUTF8String:data.data()]; - if (!js) { - char outBuf[length + 1]; - memcpy(outBuf, buffer, length); - outBuf[length] = '\0'; - LOG_ERR("Couldn't create NSString with message: " << outBuf); - return; - } - - NSString *subjs = [js substringToIndex:std::min(100ul, js.length)]; - if (subjs.length < js.length) - subjs = [subjs stringByAppendingString:@"..."]; - - LOG_TRC("Evaluating JavaScript: " << [subjs UTF8String]); - - dispatch_async(dispatch_get_main_queue(), ^{ - [self.webView evaluateJavaScript:js - completionHandler:^(id _Nullable obj, NSError * _Nullable error) - { - if (error) { - LOG_ERR("Error after " << [subjs UTF8String] << ": " << [[error localizedDescription] UTF8String]); - NSString *jsException = error.userInfo[@"WKJavaScriptExceptionMessage"]; - if (jsException != nil) - LOG_ERR("JavaScript exception: " << [jsException UTF8String]); - } - } - ]; - }); -} - -@end - -// vim:set shiftwidth=4 softtabstop=4 expandtab: diff --git a/macos/coda/coda/COWrapper.h b/macos/coda/coda/COWrapper.h index 8da90bf8da23a..23622ae51f23b 100644 --- a/macos/coda/coda/COWrapper.h +++ b/macos/coda/coda/COWrapper.h @@ -9,22 +9,20 @@ */ #import +#import -#import "CODocument.h" +@class Document; @interface COWrapper : NSObject { - - int closeNotificationPipeForForwardingThread[2]; - } -@property (class, nonatomic, readonly) COWrapper *shared; ++ (void)startServer; ++ (void)stopServer; -- (void)startServer; -- (void)stopServer; ++ (void)handleHULLOWithDocument:(Document *)document; ++ (void)handleMessageWith:(Document *)document message:(NSString *)message; -- (void)handleHULLOWithDocument:(CODocument *)document; -- (void)handleMessageWith:(CODocument *)document message:(NSString *)message; ++ (int)fakeSocketSocket; + (void)LOG_DBG:(NSString *)message NS_SWIFT_NAME(LOG_DBG(_:)); + (void)LOG_ERR:(NSString *)message NS_SWIFT_NAME(LOG_ERR(_:)); diff --git a/macos/coda/coda/COWrapper.mm b/macos/coda/coda/COWrapper.mm index 584a2173fadf2..f28ce6ef83b6e 100644 --- a/macos/coda/coda/COWrapper.mm +++ b/macos/coda/coda/COWrapper.mm @@ -10,6 +10,9 @@ #include +#import "WebKit/WebKit.h" + +#import "coda-Swift.h" #import "COWrapper.h" #import "macos.h" @@ -24,6 +27,8 @@ // Declare the coolwsd pointer at global scope COOLWSD *coolwsd = nullptr; +static int closeNotificationPipeForForwardingThread[2]; + /** * Wrapper to be able to call the C++ code from Swift. * @@ -31,16 +36,7 @@ */ @implementation COWrapper -+ (instancetype)shared { - static COWrapper *sharedInstance = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - sharedInstance = [[self alloc] init]; - }); - return sharedInstance; -} - -- (void)startServer { ++ (void)startServer { // Initialize logging // Use "debug" or potentially even "trace" for debugging #if DEBUG @@ -77,18 +73,18 @@ - (void)startServer { }).detach(); } -- (void)stopServer { ++ (void)stopServer { if (coolwsd) { delete coolwsd; coolwsd = nullptr; } } -- (void)handleHULLOWithDocument:(CODocument *)document { ++ (void)handleHULLOWithDocument:(Document *)document { // Contact the permanently (during app lifetime) listening COOLWSD server // "public" socket assert(coolwsd_server_socket_fd != -1); - int rc = fakeSocketConnect(document->fakeClientFd, coolwsd_server_socket_fd); + int rc = fakeSocketConnect(document.fakeClientFd, coolwsd_server_socket_fd); assert(rc != -1); // Create a socket pair to notify the below thread when the document has been closed @@ -100,9 +96,9 @@ - (void)handleHULLOWithDocument:(CODocument *)document { Util::setThreadName("app2js"); while (true) { struct pollfd p[2]; - p[0].fd = document->fakeClientFd; + p[0].fd = document.fakeClientFd; p[0].events = POLLIN; - p[1].fd = self->closeNotificationPipeForForwardingThread[1]; + p[1].fd = closeNotificationPipeForForwardingThread[1]; p[1].events = POLLIN; if (fakeSocketPoll(p, 2, -1) > 0) { if (p[1].revents == POLLIN) { @@ -112,16 +108,16 @@ - (void)handleHULLOWithDocument:(CODocument *)document { // the other end too just for cleanliness, even if a // FakeSocket as such is not a system resource so nothing // is saved by closing it. - fakeSocketClose(self->closeNotificationPipeForForwardingThread[1]); + fakeSocketClose(closeNotificationPipeForForwardingThread[1]); // Close our end of the fake socket connection to the // ClientSession thread, so that it terminates - fakeSocketClose(document->fakeClientFd); + fakeSocketClose(document.fakeClientFd); return; } if (p[0].revents == POLLIN) { - size_t n = fakeSocketAvailableDataLength(document->fakeClientFd); + size_t n = fakeSocketAvailableDataLength(document.fakeClientFd); // I don't want to check for n being -1 here, even if // that will lead to a crash (std::length_error from the // below std::vector constructor), as n being -1 is a @@ -131,7 +127,7 @@ - (void)handleHULLOWithDocument:(CODocument *)document { if (n == 0) return; std::vector buf(n); - n = fakeSocketRead(document->fakeClientFd, buf.data(), n); + n = fakeSocketRead(document.fakeClientFd, buf.data(), n); [document send2JS:buf.data() length:n]; } } @@ -143,22 +139,26 @@ - (void)handleHULLOWithDocument:(CODocument *)document { // First we simply send the Online C++ parts the URL and the appDocId. This corresponds // to the GET request with Upgrade to WebSocket. - std::string url([[document.fileURL absoluteString] UTF8String]); + std::string url([[document.tempFileURL absoluteString] UTF8String]); struct pollfd p; - p.fd = document->fakeClientFd; + p.fd = document.fakeClientFd; p.events = POLLOUT; fakeSocketPoll(&p, 1, -1); - fakeSocketWrite(document->fakeClientFd, url.c_str(), url.size()); + fakeSocketWrite(document.fakeClientFd, url.c_str(), url.size()); } -- (void)handleMessageWith:(CODocument *)document message:(NSString *)message { ++ (void)handleMessageWith:(Document *)document message:(NSString *)message { const char *buf = [message UTF8String]; struct pollfd p; - p.fd = document->fakeClientFd; + p.fd = document.fakeClientFd; p.events = POLLOUT; fakeSocketPoll(&p, 1, -1); - fakeSocketWrite(document->fakeClientFd, buf, strlen(buf)); + fakeSocketWrite(document.fakeClientFd, buf, strlen(buf)); +} + ++ (int)fakeSocketSocket { + return fakeSocketSocket(); } /** diff --git a/macos/coda/coda/Document.swift b/macos/coda/coda/Document.swift index 956c4e0a553fd..e19f0c83756aa 100644 --- a/macos/coda/coda/Document.swift +++ b/macos/coda/coda/Document.swift @@ -9,6 +9,7 @@ */ import Cocoa +import WebKit /** * Represents a document in the application. @@ -17,8 +18,37 @@ class Document: NSDocument { // MARK: - Properties - /// The location of the document. - var url: URL? + /// For the COWrapper to send the messages to the right file descriptor. + @objc + var fakeClientFd: Int32 = -1 + + /// Currently unused + private var appDocId: Int = -1 + + /// Is this a read-only document? + private var readOnly: Bool = false + + /// The webview that contains the document. + var webView: WKWebView! + + /// The URL of the temporary directory where the document's working files are stored. + private var tempDirectoryURL: URL? + + /// The URL of the temporary file that represents the "live" version of the document. + @objc + var tempFileURL: URL? + + /** + * Modified status mirrored from the core. + * Triggers the saving operation when it was previously marked as modified, but changes to non-modified. + */ + var isModified: Bool = false { + didSet { + if (oldValue && !isModified) { + updateChangeCount(.changeDone) + } + } + } // MARK: - Initialization @@ -49,25 +79,163 @@ class Document: NSDocument { self.addWindowController(windowController) if let viewController = windowController.contentViewController as? ViewController { - viewController.loadDocument(documentURL: url) + viewController.loadDocument(self) } } /** - * Returns the document data to be saved. + * Called by the system when it wants to save or autosave the document. */ - /*override func data(ofType typeName: String) throws -> Data { - // Save the document's data. - guard let data = documentData else { - throw NSError(domain: NSOSStatusErrorDomain, code: unimpErr, userInfo: nil) + override func data(ofType typeName: String) throws -> Data { + guard let tempFileURL = self.tempFileURL else { + // FIXME: handle error? + return Data() } + + // Read the latest data from the temp file + let data = try Data(contentsOf: tempFileURL) return data - }*/ + } + + /** + * Called by the system when the document is opened. The system provides the file contents as `Data`. + * We create a non-predictable temporary directory using a UUID, and store the `data` there. + */ + override func read(from data: Data, ofType typeName: String) throws { + // Create a unique temp directory + let tempDirBase = FileManager.default.temporaryDirectory + let uniqueDirName = UUID().uuidString + let tempDir = tempDirBase.appendingPathComponent(uniqueDirName, isDirectory: true) + + try FileManager.default.createDirectory(at: tempDir, withIntermediateDirectories: true, attributes: nil) + + self.tempDirectoryURL = tempDir + + // If fileURL is available (document opened from a file), preserve the original filename. + // If not available, use a generic name. + let fileName: String + if let fileURL = self.fileURL { + fileName = fileURL.lastPathComponent + } + else { + fileName = "Document-\(UUID().uuidString)" + } + + let tempFile = tempDir.appendingPathComponent(fileName) + try data.write(to: tempFile, options: .atomic) + + self.tempFileURL = tempFile + } + + /** + * Clean up the temporary directory when the document closes. + */ + override func close() { + super.close() + if let tempDir = self.tempDirectoryURL { + try? FileManager.default.removeItem(at: tempDir) + } + } + + /** + * Initiate loading of cool.html, which also triggers loading of the document via lokit. + */ + func loadDocumentInWebView(webView: WKWebView, readOnly: Bool) { + self.webView = webView + self.readOnly = readOnly + + self.appDocId = 1 + + self.fakeClientFd = COWrapper.fakeSocketSocket() + + guard let url = Bundle.main.url(forResource: "cool", withExtension: "html") else { + fatalError("Resource 'cool.html' not found in the main bundle.") + } + + var components = URLComponents(url: url, resolvingAgainstBaseURL: false)! + let permission = readOnly ? "readonly" : "edit" + + components.queryItems = [ + URLQueryItem(name: "file_path", value: tempFileURL!.absoluteString), + URLQueryItem(name: "closebutton", value: "1"), + URLQueryItem(name: "permission", value: permission), + // TODO: add "lang" if needed + URLQueryItem(name: "appdocid", value: "\(self.appDocId)"), + URLQueryItem(name: "userinterfacemode", value: "notebookbar"), + // TODO: add "dir" if needed + ] + + let finalURL = components.url! + let request = URLRequest(url: finalURL) + let urlDir = url.deletingLastPathComponent() + + // If you need read access to a local file, use loadFileURL(_:allowingReadAccessTo:): + // If `finalURL` is a file URL, do: + if finalURL.isFileURL { + webView.loadFileURL(finalURL, allowingReadAccessTo: urlDir) + } else { + // If it's not a file URL, just load the request normally + webView.load(request) + } + } /** - * Just remember the document URL here, will be loaded when the ViewController is created. + * Abbreviated message for debugging. */ - override func read(from url: URL, ofType typeName: String) throws { - self.url = url + private func abbreviatedMessage(buffer: UnsafePointer, length: Int) -> String { + // Implement your logic or return a placeholder: + let msgData = Data(bytes: buffer, count: length) + let msgStr = String(data: msgData, encoding: .utf8) ?? "" + return msgStr.prefix(100) + (msgStr.count > 100 ? "..." : "") + } + + /** + * Check if the message is of the given type. + */ + private func isMessageOfType(_ buffer: UnsafePointer, _ prefix: String, length: Int) -> Bool { + let msgData = Data(bytes: buffer, count: min(length, prefix.count)) + guard let msgStr = String(data: msgData, encoding: .utf8) else { return false } + return msgStr == prefix + } + + @objc + func send2JS(_ buffer: UnsafePointer, length: Int) { + let abbrMsg = abbreviatedMessage(buffer: buffer, length: length) + COWrapper.LOG_TRC("To JS: \(abbrMsg)") + + let binaryMessage = (isMessageOfType(buffer, "tile:", length: length) || + isMessageOfType(buffer, "tilecombine:", length: length) || + isMessageOfType(buffer, "delta:", length: length) || + isMessageOfType(buffer, "renderfont:", length: length) || + isMessageOfType(buffer, "rendersearchlist:", length: length) || + isMessageOfType(buffer, "windowpaint:", length: length)) + + let pretext = binaryMessage + ? "window.TheFakeWebSocket.onmessage({'data': window.atob('" + : "window.TheFakeWebSocket.onmessage({'data': window.b64d('" + let posttext = "')});" + + // Convert the buffer to Data + let payloadData = Data(bytes: buffer, count: length) + let encodedPayload = payloadData.base64EncodedString(options: []) + + // Construct the full JavaScript string + let js = pretext + encodedPayload + posttext + + // Truncate for logging + let truncatedJS = js.count > 100 ? (js.prefix(100) + "...") : js[...] + COWrapper.LOG_TRC("Evaluating JavaScript: \(truncatedJS)") + + // Evaluate on main queue + DispatchQueue.main.async { + self.webView.evaluateJavaScript(js) { (obj, error) in + if let error = error as NSError? { + COWrapper.LOG_ERR("Error after \(truncatedJS): \(error.localizedDescription)") + if let jsException = error.userInfo["WKJavaScriptExceptionMessage"] as? String { + COWrapper.LOG_ERR("JavaScript exception: \(jsException)") + } + } + } + } } } diff --git a/macos/coda/coda/ViewController.swift b/macos/coda/coda/ViewController.swift index 7ed4abbffb16e..caaa7ccb2ead9 100644 --- a/macos/coda/coda/ViewController.swift +++ b/macos/coda/coda/ViewController.swift @@ -13,7 +13,10 @@ import WebKit class ViewController: NSViewController, WKScriptMessageHandler, WKNavigationDelegate { - var document: CODocument! + /// Access to the NSDocument (document loading & saving infrastructure). + var document: Document! + + /// The actual webview holding the document. var webView: WKWebView! override func viewDidLoad() { @@ -52,10 +55,11 @@ class ViewController: NSViewController, WKScriptMessageHandler, WKNavigationDele /** * Load the the document; to be called from the Document (NSDocument) instance. */ - func loadDocument(documentURL: URL?) { + func loadDocument(_ document: Document) { // FIXME: Defaults to the hello.odt if not provided (which happens eg. when created from File -> New) - let fileURL = documentURL ?? Bundle.main.url(forResource: "hello", withExtension: "odt")! - document = CODocument(webView: webView, fileURL: fileURL, readOnly: false) + let fileURL = document.tempFileURL ?? Bundle.main.url(forResource: "hello", withExtension: "odt")! + self.document = document + self.document.loadDocumentInWebView(webView: webView, readOnly: false) } /** @@ -78,7 +82,7 @@ class ViewController: NSViewController, WKScriptMessageHandler, WKNavigationDele if body == "HULLO" { // Now we know that the JS has started completely - COWrapper.shared.handleHULLO(with: document) + COWrapper.handleHULLO(with: document) return } else if body == "BYE" { @@ -86,6 +90,10 @@ class ViewController: NSViewController, WKScriptMessageHandler, WKNavigationDele //self.bye() return } + else if body.starts(with: "MODIFIED ") { + document?.isModified = body.hasSuffix("true") + return + } else if body == "SLIDESHOW" { COWrapper.LOG_ERR("TODO: Implement slideshow") /* @@ -293,7 +301,7 @@ class ViewController: NSViewController, WKScriptMessageHandler, WKNavigationDele } else { // Just send the message - COWrapper.shared.handleMessage(with: document, message: body) + COWrapper.handleMessage(with: document, message: body) } } } diff --git a/macos/coda/coda/coda.entitlements b/macos/coda/coda/coda.entitlements index 20df823f13ace..a2420ac9df92e 100644 --- a/macos/coda/coda/coda.entitlements +++ b/macos/coda/coda/coda.entitlements @@ -8,7 +8,7 @@ com.apple.security.cs.disable-library-validation - com.apple.security.files.user-selected.read-only + com.apple.security.files.user-selected.read-write com.apple.security.network.client From 5a3fd4a9439d42fe9b2fdc06da63d909e2d66847 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Tue, 10 Dec 2024 10:56:54 +0200 Subject: [PATCH 047/177] Tweak SAL_LOG to avoid some verbiage Signed-off-by: Tor Lillqvist Change-Id: I78a67ca995193d102aaad5dbcc0a9b8287daa946 --- windows/coda/CODA/Properties/launchSettings.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/windows/coda/CODA/Properties/launchSettings.json b/windows/coda/CODA/Properties/launchSettings.json index c806d32110d1d..c2831b9a51f44 100644 --- a/windows/coda/CODA/Properties/launchSettings.json +++ b/windows/coda/CODA/Properties/launchSettings.json @@ -3,9 +3,9 @@ "CODA": { "commandName": "Project", "environmentVariables": { - "SAL_LOG": "+INFO+WARN" + "SAL_LOG": "+INFO+WARN-INFO.sal.bootstrap-INFO.i18nlangtag-INFO.vcl.fonts" }, "nativeDebugging": true } } -} \ No newline at end of file +} From 67336092634450c1d40fb2c6fa6adff0e41c9385 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Tue, 10 Dec 2024 16:06:42 +0200 Subject: [PATCH 048/177] Fix logic in handling the flush option when logging to console If the option is missing, or if it is true, we want flushing, i.e. not buffering. Signed-off-by: Tor Lillqvist Change-Id: I7a207aa69c1b314f16cdb7d9de07e012d9b8140d --- common/Log.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/common/Log.cpp b/common/Log.cpp index 0829b4629600b..8db37c2eed034 100644 --- a/common/Log.cpp +++ b/common/Log.cpp @@ -619,13 +619,13 @@ namespace Log const auto it = config.find("flush"); if (it == config.end() || Util::toLower(it->second) != "false") { - // Buffered logging, reduces number of write(2) syscalls. - channel = static_cast(new Log::BufferedConsoleChannel()); + // Unbuffered (flushed) logging, directly writes each entry (to stderr). + channel = static_cast(new Log::ConsoleChannel()); } else { - // Unbuffered logging, directly writes each entry (to stderr). - channel = static_cast(new Log::ConsoleChannel()); + // Buffered logging, reduces number of write(2) syscalls. + channel = static_cast(new Log::BufferedConsoleChannel()); } } From bed7b20c13df97a9761db9bd867d77cb9270932e Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Tue, 10 Dec 2024 16:14:09 +0200 Subject: [PATCH 049/177] Try to make logging work better in CODA-W If running under a debugger (Visual Studio), call OutputDebugStringA(). Otherwise write to stderr, as before. (But note that if you just run the CODA.exe app, even starting it from a console window (like cmd.exe or WSL), stderr is not connected anywhere. You need to explicitly redirect it to a file or pipe. This is how "GUI apps" on Windows always have worked, and still do.) There is still weirdness in logging in CODA-W, though. But this change hopefully is a step in the right direction. Signed-off-by: Tor Lillqvist Change-Id: Ie0f3a29c710af0196dd3620a1a5c7706f2802342 --- common/Log.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/common/Log.cpp b/common/Log.cpp index 8db37c2eed034..e3d0147032a1f 100644 --- a/common/Log.cpp +++ b/common/Log.cpp @@ -32,6 +32,8 @@ #ifndef _WINDOWS #include #else +#define WIN32_LEAN_AND_MEAN +#include #include #endif #include @@ -165,7 +167,16 @@ namespace Log } return ptr - data; #else // _WINDOWS - fwrite(data, size, 1, stderr); + if (!IsDebuggerPresent()) + fwrite(data, size, 1, stderr); + else + { + char *s = (char *)malloc(size + 1); + memcpy(s, data, size); + s[size] = 0; + OutputDebugStringA(s); + free(s); + } return size; #endif } From b8721dfbb1941298883e942d2887488b0311361d Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Tue, 10 Dec 2024 16:41:30 +0200 Subject: [PATCH 050/177] Modify the message passing from JS to C# in CODA-W Mainly in an attempt to handle debug and error messages better Signed-off-by: Tor Lillqvist Change-Id: Ia22e0956c0449a1e8867befdab887b7c876b61c7 --- browser/js/global.js | 6 +++--- windows/coda/CODA/MainWindow.xaml.cs | 32 ++++++++++++++++++++++------ 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/browser/js/global.js b/browser/js/global.js index 1419cc5dc76a3..2965633ffa84f 100644 --- a/browser/js/global.js +++ b/browser/js/global.js @@ -506,14 +506,14 @@ class WindowsAppInitializer extends MobileAppInitializer { super(); window.ThisIsTheWindowsApp = true; - window.postMobileMessage = function(msg) { window.chrome.webview.postMessage(msg); }; + window.postMobileMessage = function(msg) { window.chrome.webview.postMessage('MSG ' + msg); }; // FIXME: No registration of separate handlers in Windows WebView2, so just log // errors and debug messages? Maybe instead send a JSON object with separate name // and body? But then we would have to parse that JSON object from the string in C# // anyway. - window.postMobileError = function(msg) { console.log('COOL Error: ' + msg); }; - window.postMobileDebug = function(msg) { console.log('COOL Debug: ' + msg); }; + window.postMobileError = function(msg) { window.chrome.webview.postMessage('ERR ' + msg); }; + window.postMobileDebug = function(msg) { window.chrome.webview.postMessage('DBG ' + msg); }; } } diff --git a/windows/coda/CODA/MainWindow.xaml.cs b/windows/coda/CODA/MainWindow.xaml.cs index 9b08f5c3f1e92..bb317bc381079 100644 --- a/windows/coda/CODA/MainWindow.xaml.cs +++ b/windows/coda/CODA/MainWindow.xaml.cs @@ -150,20 +150,38 @@ private async void MainWindow_Loaded(object sender, RoutedEventArgs e) void WebView_WebMessageReceived(object sender, CoreWebView2WebMessageReceivedEventArgs args) { - Debug.WriteLine($"WebView_WebMessageReceived: {args.WebMessageAsJson}"); + string s = args.WebMessageAsJson; + Debug.WriteLine($"WebView_WebMessageReceived: {s}"); - if (args.WebMessageAsJson == "\"HULLO\"") + if (s.StartsWith("\"MSG ")) { - do_hullo_handling_things(); + s = s.Substring(5); + if (s == "HULLO\"") + { + do_hullo_handling_things(); + } + else if (s == "BYE\"") + { + do_bye_handling_things(); + } + else + { + string message = JsonSerializer.Deserialize(args.WebMessageAsJson); + message = message.Substring(4); + do_other_message_handling_things(message); + } } - else if (args.WebMessageAsJson == "\"BYE\"") + else if (s.StartsWith("\"ERR ")) { - do_bye_handling_things(); + string message = JsonSerializer.Deserialize(args.WebMessageAsJson); + message = message.Substring(4); + Debug.WriteLine("Error: message"); } - else + else if (s.StartsWith("\"DBG ")) { string message = JsonSerializer.Deserialize(args.WebMessageAsJson); - do_other_message_handling_things(message); + message = message.Substring(4); + Debug.WriteLine("Debug: message"); } } From 06d37d25a47a2af7b93770ed457d303d48a14ecb Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 16 Dec 2024 08:48:01 +0100 Subject: [PATCH 051/177] coda-m: Implement saving from the File -> Save menu in the app Also remove obsolete code and update instdir in the README.md. Signed-off-by: Jan Holesovsky Change-Id: Ic3a1d06be33e7b0d175abf2a4a17b904f163ff85 --- macos/README.txt | 2 +- macos/coda/coda/Document.swift | 54 +++++++++++++++++++++++++--- macos/coda/coda/ViewController.swift | 2 -- 3 files changed, 51 insertions(+), 7 deletions(-) diff --git a/macos/README.txt b/macos/README.txt index a35290563fe9c..b9875d627a3f3 100644 --- a/macos/README.txt +++ b/macos/README.txt @@ -54,7 +54,7 @@ Configure Collabora Online --with-poco-libs=/opt/homebrew/opt/poco/lib \ --with-zstd-includes=/opt/homebrew/include \ --with-zstd-libs=/opt/homebrew/lib \ - --with-lo-path=/Users/kendy/Projects/lo/core/instdir \ + --with-lo-path=/Users/kendy/Projects/lo/core/instdir/CollaboraOffice.app \ --with-lokit-path=/Users/kendy/Projects/lo/core/include Build Collabora Online diff --git a/macos/coda/coda/Document.swift b/macos/coda/coda/Document.swift index e19f0c83756aa..71d120acc58ae 100644 --- a/macos/coda/coda/Document.swift +++ b/macos/coda/coda/Document.swift @@ -38,15 +38,33 @@ class Document: NSDocument { @objc var tempFileURL: URL? + /// Make sure the isModified access can be atomic. + private var modifiedLock = NSLock() + private var _isModified: Bool = false + /** * Modified status mirrored from the core. - * Triggers the saving operation when it was previously marked as modified, but changes to non-modified. */ - var isModified: Bool = false { - didSet { - if (oldValue && !isModified) { + var isModified: Bool { + get { + modifiedLock.lock() + let value = _isModified + modifiedLock.unlock() + + return value + } + set { + modifiedLock.lock() + + let oldValue = _isModified + _isModified = newValue + + // trigger the saving operation when the document was previously marked as modified, but changes to non-modified + if oldValue && !newValue { updateChangeCount(.changeDone) } + + modifiedLock.unlock() } } @@ -97,6 +115,34 @@ class Document: NSDocument { return data } + /** + * We save asynchronously, so that COOL can first write the file, and we can then copy it to the right location. + */ + override func canAsynchronouslyWrite(to url: URL, ofType typeName: String, for saveOperation: NSDocument.SaveOperationType) -> Bool { + return true + } + + /** + * Make sure that we first save by COOL when the user chooses to Save, and only then copy the content to the resulting place. + */ + override func save(to url: URL, ofType typeName: String, for saveOperation: NSDocument.SaveOperationType, completionHandler: @escaping ((any Error)?) -> Void) { + + if isModified { + // we have to wait for COOL to save first + DispatchQueue.main.async { + COWrapper.handleMessage(with: self, message: "save dontTerminateEdit=1 dontSaveIfUnmodified=1") + } + } + else { + // all is good, we can proceed with copying the data from COOL + super.save(to: url, ofType: typeName, for: saveOperation, completionHandler: completionHandler) + } + + DispatchQueue.main.async { + completionHandler(nil) + } + } + /** * Called by the system when the document is opened. The system provides the file contents as `Data`. * We create a non-predictable temporary directory using a UUID, and store the `data` there. diff --git a/macos/coda/coda/ViewController.swift b/macos/coda/coda/ViewController.swift index caaa7ccb2ead9..65b7b03e6c438 100644 --- a/macos/coda/coda/ViewController.swift +++ b/macos/coda/coda/ViewController.swift @@ -56,8 +56,6 @@ class ViewController: NSViewController, WKScriptMessageHandler, WKNavigationDele * Load the the document; to be called from the Document (NSDocument) instance. */ func loadDocument(_ document: Document) { - // FIXME: Defaults to the hello.odt if not provided (which happens eg. when created from File -> New) - let fileURL = document.tempFileURL ?? Bundle.main.url(forResource: "hello", withExtension: "odt")! self.document = document self.document.loadDocumentInWebView(webView: webView, readOnly: false) } From d7e16959823a01b2cca385d562e5383677f345a5 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 17 Dec 2024 15:33:51 +0100 Subject: [PATCH 052/177] Check for the existence of memrchr Instead of growing the list of systems where it is not present. Signed-off-by: Jan Holesovsky Change-Id: I9cb048e6578c49b6b750ec69d169827eed94a249 --- windows/coda/config.h.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/windows/coda/config.h.in b/windows/coda/config.h.in index 82d04bc38396d..58eb4557fa89e 100755 --- a/windows/coda/config.h.in +++ b/windows/coda/config.h.in @@ -82,6 +82,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H +/* Define to 1 if you have the `memrchr' function. */ +#define HAVE_MEMRCHR 0 + /* Collabora Online WebSocket server version */ #define COOLWSD_VERSION "@COOLWSD_VERSION@" From 900a4c42a7ed15a1262914370adf9889df0dfcae Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 17 Dec 2024 15:54:20 +0100 Subject: [PATCH 053/177] coda-m: Fix build of WebSocketHandler on macOS Signed-off-by: Jan Holesovsky Change-Id: I42db35b6b02ad794eb00c79a38eedc33c12cdef7 --- net/WebSocketHandler.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/WebSocketHandler.hpp b/net/WebSocketHandler.hpp index 2cf8879c2c76d..8592b231d22a0 100644 --- a/net/WebSocketHandler.hpp +++ b/net/WebSocketHandler.hpp @@ -817,7 +817,7 @@ class WebSocketHandler : public ProtocolHandlerInterface ssize_t i = 0, toSend; while (true) { - toSend = std::min(sizeof(copy), len - i); + toSend = std::min(static_cast(sizeof(copy)), len - i); if (toSend == 0) break; for (ssize_t j = 0; j < toSend; ++j, ++i) From 00116dc22788af4e0fe001b0024e57ff6e628b2b Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Wed, 18 Dec 2024 18:01:32 +0200 Subject: [PATCH 054/177] Also set window.userInterfaceMode for CODA-W Signed-off-by: Tor Lillqvist Change-Id: If7c8bd479e5a9ea9c7d372da7eab0bc5b536c4db --- browser/js/global.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/browser/js/global.js b/browser/js/global.js index 2965633ffa84f..7dc5d1e1a7f5d 100644 --- a/browser/js/global.js +++ b/browser/js/global.js @@ -514,6 +514,8 @@ class WindowsAppInitializer extends MobileAppInitializer { // anyway. window.postMobileError = function(msg) { window.chrome.webview.postMessage('ERR ' + msg); }; window.postMobileDebug = function(msg) { window.chrome.webview.postMessage('DBG ' + msg); }; + + window.userInterfaceMode = window.coolParams.get('userinterfacemode'); } } From 0a008e8940fae42b7207d4ea417177715d6bd4aa Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Wed, 18 Dec 2024 18:41:02 +0200 Subject: [PATCH 055/177] Execute JavaScript in the main thread Signed-off-by: Tor Lillqvist Change-Id: Ie3953b4bce0af04295704473a57d4fe45feb07bb --- windows/coda/CODA/MainWindow.xaml.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/windows/coda/CODA/MainWindow.xaml.cs b/windows/coda/CODA/MainWindow.xaml.cs index bb317bc381079..8db10e67d93a5 100644 --- a/windows/coda/CODA/MainWindow.xaml.cs +++ b/windows/coda/CODA/MainWindow.xaml.cs @@ -8,6 +8,7 @@ using System.Text.Json; using System.Threading.Tasks; using System.Windows; +using System.Windows.Threading; using Microsoft.Web.WebView2.Core; using Microsoft.Web.WebView2.Wpf; @@ -308,7 +309,9 @@ void send2JS(IntPtr buffer, int length) Debug.WriteLine("Evaluating JavaScript: " + subjs); } - _iWebView2.ExecuteScriptAsync(js); + Application.Current.Dispatcher.Invoke(new Action(() => { + _iWebView2.ExecuteScriptAsync(js); + })); } void UpdateTitle() From 18bea36ca288bc000b107a455d20df1a0ab801d3 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Thu, 19 Dec 2024 14:59:58 +0200 Subject: [PATCH 056/177] CODA-W debugging hacks Also, fix thinkos in a couple of Debug.WriteLine() calls. Signed-off-by: Tor Lillqvist Change-Id: I02a97625344c70dc10c21b9afd2723b59fe7013c --- windows/coda/CODA/MainWindow.xaml.cs | 21 +++++++++++++------ .../coda/CODA/Properties/launchSettings.json | 5 +++-- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/windows/coda/CODA/MainWindow.xaml.cs b/windows/coda/CODA/MainWindow.xaml.cs index 8db10e67d93a5..587a55b60e6da 100644 --- a/windows/coda/CODA/MainWindow.xaml.cs +++ b/windows/coda/CODA/MainWindow.xaml.cs @@ -176,13 +176,13 @@ void WebView_WebMessageReceived(object sender, CoreWebView2WebMessageReceivedEve { string message = JsonSerializer.Deserialize(args.WebMessageAsJson); message = message.Substring(4); - Debug.WriteLine("Error: message"); + Debug.WriteLine($"Error: {message}"); } else if (s.StartsWith("\"DBG ")) { string message = JsonSerializer.Deserialize(args.WebMessageAsJson); message = message.Substring(4); - Debug.WriteLine("Debug: message"); + Debug.WriteLine($"Debug: {message}"); } } @@ -230,8 +230,17 @@ void WebView_CoreWebView2InitializationCompleted(object sender, CoreWebView2Init if (e.IsSuccess) { // FIXME: Temporarily when running from /windows/coda/CODA/bin/Debug/net8.0-windows. - webView.CoreWebView2.SetVirtualHostNameToFolderMapping("appassets", "..\\..\\..\\..\\..\\..\\browser\\dist", CoreWebView2HostResourceAccessKind.DenyCors); - webView.CoreWebView2.Navigate("https://appassets/cool.html?file_path=file:///C:/Users/tml/sailing.odt&closebutton=1&permission=edit&lang=en-US&appdocid=1&userinterfacemode=notebookbar&dir=ltr"); + + // FIXME: Even more temporarily, just use hardcoded pathnames on tml's machine to make debugging the JS easier. + if (true) + { + webView.CoreWebView2.SetVirtualHostNameToFolderMapping("appassets", "..\\..\\..\\..\\..\\..\\browser\\dist", CoreWebView2HostResourceAccessKind.DenyCors); + webView.CoreWebView2.Navigate("https://appassets/cool.html?file_path=file:///C:/Users/tml/sailing.odt&closebutton=1&permission=edit&lang=en-US&appdocid=1&userinterfacemode=notebookbar&dir=ltr"); + } + else + { + webView.CoreWebView2.Navigate("file:///C:/Users/tml/lo/online-gitlab-coda/browser/dist//cool.html?file_path=file:///C:/Users/tml/sailing.odt&closebutton=1&permission=edit&lang=en-US&appdocid=1&userinterfacemode=notebookbar&dir=ltr"); + } OnWebViewFirstInitialized?.Invoke(); @@ -296,7 +305,7 @@ void send2JS(IntPtr buffer, int length) string subs = sb.ToString(); if (sb.Length > 100) subs += "..."; - Debug.WriteLine("Evaluating JavaScript: " + subs); + Debug.WriteLine($"Evaluating JavaScript: {subs}"); } string js = pretext + System.Convert.ToBase64String(s) + posttext; @@ -306,7 +315,7 @@ void send2JS(IntPtr buffer, int length) string subjs = js.Substring(0, (js.Length > 100 ? 100 : js.Length)); if (js.Length > 100) subjs += "..."; - Debug.WriteLine("Evaluating JavaScript: " + subjs); + Debug.WriteLine($"Evaluating JavaScript: {subjs}"); } Application.Current.Dispatcher.Invoke(new Action(() => { diff --git a/windows/coda/CODA/Properties/launchSettings.json b/windows/coda/CODA/Properties/launchSettings.json index c2831b9a51f44..efe5615189826 100644 --- a/windows/coda/CODA/Properties/launchSettings.json +++ b/windows/coda/CODA/Properties/launchSettings.json @@ -5,7 +5,8 @@ "environmentVariables": { "SAL_LOG": "+INFO+WARN-INFO.sal.bootstrap-INFO.i18nlangtag-INFO.vcl.fonts" }, - "nativeDebugging": true + "nativeDebugging": true, + "jsWebView2Debugging": false } } -} +} \ No newline at end of file From 9afe236773a6e085f7d94d6bdecb493ef38f2a1a Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Mon, 30 Dec 2024 12:10:24 +0200 Subject: [PATCH 057/177] Implement Util::setThreadName() for Windows This required moving the Windows-specific conversion functions between string and wide string and vice versa to the Util namespace and making them public. (Not sure why I named them using snake_case, probably should switch to camelCase as is the norm in this code.) Signed-off-by: Tor Lillqvist Change-Id: I3b75fe54a1b0e76a83e82097f3e022983f82311d --- common/FileUtil-windows.cpp | 69 ++++++++----------------------------- common/Util-windows.cpp | 38 ++++++++++++++++++++ common/Util.cpp | 7 ++++ common/Util.hpp | 4 +++ 4 files changed, 63 insertions(+), 55 deletions(-) diff --git a/common/FileUtil-windows.cpp b/common/FileUtil-windows.cpp index a1a24666caa96..da18aa53d697b 100644 --- a/common/FileUtil-windows.cpp +++ b/common/FileUtil-windows.cpp @@ -21,48 +21,7 @@ #include #include - -namespace -{ - std::wstring string_to_wide_string(const std::string& string) - { - if (string.empty()) - { - return L""; - } - - const auto size_needed = MultiByteToWideChar(CP_UTF8, 0, string.data(), (int)string.size(), nullptr, 0); - if (size_needed <= 0) - { - throw std::runtime_error("MultiByteToWideChar() failed: " + std::to_string(size_needed)); - } - - std::wstring result(size_needed, 0); - MultiByteToWideChar(CP_UTF8, 0, string.data(), (int)string.size(), result.data(), size_needed); - - return result; - } - - std::string wide_string_to_string(const std::wstring& wide_string) - { - if (wide_string.empty()) - { - return ""; - } - - const auto size_needed = WideCharToMultiByte(CP_UTF8, 0, wide_string.data(), (int)wide_string.size(), nullptr, 0, nullptr, nullptr); - if (size_needed <= 0) - { - throw std::runtime_error("WideCharToMultiByte() failed: " + std::to_string(size_needed)); - } - - std::string result(size_needed, 0); - WideCharToMultiByte(CP_UTF8, 0, wide_string.data(), (int)wide_string.size(), result.data(), size_needed, nullptr, nullptr); - - return result; - } - -} // anonymous namespace +#include namespace FileUtil { @@ -73,9 +32,9 @@ namespace FileUtil try { if (recursive) - std::filesystem::remove_all(string_to_wide_string(path)); + std::filesystem::remove_all(Util::string_to_wide_string(path)); else - std::filesystem::remove(string_to_wide_string(path)); + std::filesystem::remove(Util::string_to_wide_string(path)); } catch (const std::filesystem::filesystem_error& e) { @@ -108,14 +67,14 @@ namespace FileUtil { LOG_DBG("Removing empty directories at [" << path << "] recursively"); - removeEmptyDirTreeTakingPath(std::filesystem::path(string_to_wide_string(path))); + removeEmptyDirTreeTakingPath(std::filesystem::path(Util::string_to_wide_string(path))); } bool isEmptyDirectory(const char* path) { bool empty = true; for (auto const& dirent : - std::filesystem::directory_iterator{std::filesystem::path(string_to_wide_string(path)), + std::filesystem::directory_iterator{std::filesystem::path(Util::string_to_wide_string(path)), std::filesystem::directory_options::skip_permission_denied}) { (void) dirent; @@ -143,7 +102,7 @@ namespace FileUtil int openFileAsFD(const std::string& file, int oflag, int mode) { - return _wopen(string_to_wide_string(file).c_str(), oflag | O_BINARY, mode); + return _wopen(Util::string_to_wide_string(file).c_str(), oflag | O_BINARY, mode); } int readFromFD(int fd, void *buf, size_t nbytes) @@ -163,12 +122,12 @@ namespace FileUtil void openFileToIFStream(const std::string& file, std::ifstream& stream, std::ios_base::openmode mode) { - stream.open(string_to_wide_string(file), mode | std::ios_base::binary); + stream.open(Util::string_to_wide_string(file), mode | std::ios_base::binary); } int getStatOfFile(const std::string& file, struct stat& sb) { - return _wstat64i32(string_to_wide_string(file).c_str(), (struct _stat64i32*) &sb); + return _wstat64i32(Util::string_to_wide_string(file).c_str(), (struct _stat64i32*) &sb); } int getLStatOfFile(const std::string& file, struct stat& sb) @@ -178,17 +137,17 @@ namespace FileUtil int unlinkFile(const std::string& file) { - return _wunlink(string_to_wide_string(file).c_str()); + return _wunlink(Util::string_to_wide_string(file).c_str()); } int makeDirectory(const std::string& dir) { - return _wmkdir(string_to_wide_string(dir).c_str()); + return _wmkdir(Util::string_to_wide_string(dir).c_str()); } void createDirectory(const std::string& dir) { - std::filesystem::create_directory(string_to_wide_string(dir)); + std::filesystem::create_directory(Util::string_to_wide_string(dir)); } std::string getSysTempDirectoryPath() @@ -196,7 +155,7 @@ namespace FileUtil std::wstring path = std::filesystem::temp_directory_path().wstring(); if (!path.empty()) - return wide_string_to_string(path); + return Util::wide_string_to_string(path); // Try some fallbacks const wchar_t *tmp = _wgetenv(L"TEMP"); @@ -207,12 +166,12 @@ namespace FileUtil if (!tmp) tmp = L"C:/Windows/Temp"; - return wide_string_to_string(tmp); + return Util::wide_string_to_string(tmp); } bool isWritable(const char* path) { - if (_waccess(string_to_wide_string(path).c_str(), 0) == 0) + if (_waccess(Util::string_to_wide_string(path).c_str(), 0) == 0) return true; LOG_INF("No write access to path [" << path << "]: " << strerror(errno)); diff --git a/common/Util-windows.cpp b/common/Util-windows.cpp index 0ef1697efa366..3c6be365ad572 100644 --- a/common/Util-windows.cpp +++ b/common/Util-windows.cpp @@ -59,6 +59,44 @@ namespace Util return nullptr; return &tm; } + + std::wstring string_to_wide_string(const std::string& string) + { + if (string.empty()) + { + return L""; + } + + const auto size_needed = MultiByteToWideChar(CP_UTF8, 0, string.data(), (int)string.size(), nullptr, 0); + if (size_needed <= 0) + { + throw std::runtime_error("MultiByteToWideChar() failed: " + std::to_string(size_needed)); + } + + std::wstring result(size_needed, 0); + MultiByteToWideChar(CP_UTF8, 0, string.data(), (int)string.size(), result.data(), size_needed); + + return result; + } + + std::string wide_string_to_string(const std::wstring& wide_string) + { + if (wide_string.empty()) + { + return ""; + } + + const auto size_needed = WideCharToMultiByte(CP_UTF8, 0, wide_string.data(), (int)wide_string.size(), nullptr, 0, nullptr, nullptr); + if (size_needed <= 0) + { + throw std::runtime_error("WideCharToMultiByte() failed: " + std::to_string(size_needed)); + } + + std::string result(size_needed, 0); + WideCharToMultiByte(CP_UTF8, 0, wide_string.data(), (int)wide_string.size(), result.data(), size_needed, nullptr, nullptr); + + return result; + } } // namespace Util /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/common/Util.cpp b/common/Util.cpp index d7d729ec60eb4..df13000619fb6 100644 --- a/common/Util.cpp +++ b/common/Util.cpp @@ -91,6 +91,10 @@ #include #endif +#ifdef _WINDOWS +#include +#endif + // for version info #include #if ENABLE_SSL @@ -316,6 +320,9 @@ namespace Util LOG_INF("Thread " << getThreadId() << ") is now called [" << s << ']'); #elif defined __EMSCRIPTEN__ emscripten_console_logf("COOL thread name: \"%s\"", s.c_str()); +#elif defined _WINDOWS + SetThreadDescription(GetCurrentThread(), string_to_wide_string(s).c_str()); + LOG_INF("Thread " << getThreadId() << ") is now called [" << s << ']'); #endif // Emit a metadata Trace Event identifying this thread. This will invoke a different function diff --git a/common/Util.hpp b/common/Util.hpp index d057a79953285..6c822aebde094 100644 --- a/common/Util.hpp +++ b/common/Util.hpp @@ -1461,6 +1461,10 @@ int main(int argc, char**argv) /// Base-64 decode the given input. std::string base64Decode(const std::string& input); +#ifdef _WINDOWS + std::wstring string_to_wide_string(const std::string& string); + std::string wide_string_to_string(const std::wstring& wide_string); +#endif } // end namespace Util inline std::ostream& operator<<(std::ostream& os, const std::chrono::system_clock::time_point& ts) From aa5208d6d8e2cdbadbb73a2219d97e73259434e6 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 6 Jan 2025 12:54:21 +0100 Subject: [PATCH 058/177] coda-m: Define MACOS via config.h instead of a project setting Signed-off-by: Jan Holesovsky Change-Id: Ie121369542d75162d143ea1e6c497c0ee35949f8 --- config.h.in | 3 +++ configure.ac | 10 ++++++++++ macos/coda/coda.xcodeproj/project.pbxproj | 4 ++-- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/config.h.in b/config.h.in index 0cc710b36d473..99b366e75e5ea 100644 --- a/config.h.in +++ b/config.h.in @@ -135,6 +135,9 @@ /* Define to 1 if the "fallback to Wasm" capability is enabled: */ #define ENABLE_WASM_SUPPORT 0 +/* Define to 1 if building for macOS */ +#undef MACOS + /* Makes config variables conditionally static, only in non-debug builds, to allow for overriding them in unit-tests. */ #undef CONFIG_STATIC_TYPE diff --git a/configure.ac b/configure.ac index b6923d1937078..0a3f3abbf2ee3 100644 --- a/configure.ac +++ b/configure.ac @@ -1040,6 +1040,16 @@ AM_CONDITIONAL([ENABLE_IOSAPP], [test "$ENABLE_IOSAPP" = "true"]) AC_SUBST(IOSAPP_BUNDLE_SHORT_VERSION) AC_SUBST(IOSAPP_BUNDLE_VERSION) +# Check if we are on macOS (darwin) to define "MACOS" in config.h +# We want this to be general, regardless of using --enable-macosapp, and it +# could be potentially extended to handle the other defines like IOS, WASMAPP +# or _WINDOWS (but at least iOS and Windows are using their own config.h) +case "$host_os" in + darwin*) + AC_DEFINE([MACOS], [1], [Define to 1 if building for macOS]) + ;; +esac + ENABLE_MACOSAPP= #MACOSAPP_BUNDLE_VERSION= diff --git a/macos/coda/coda.xcodeproj/project.pbxproj b/macos/coda/coda.xcodeproj/project.pbxproj index a605562a7b2bd..67649dccc0235 100644 --- a/macos/coda/coda.xcodeproj/project.pbxproj +++ b/macos/coda/coda.xcodeproj/project.pbxproj @@ -85,6 +85,7 @@ BE2249302CC79BAE00385A9C /* device-desktop.css */ = {isa = PBXFileReference; lastKnownFileType = text.css; name = "device-desktop.css"; path = "../../../browser/dist/device-desktop.css"; sourceTree = ""; }; BE2249312CC79BAE00385A9C /* global.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = global.js; path = ../../../browser/dist/global.js; sourceTree = ""; }; BE22AA9B2CC7AE7400385A9C /* images */ = {isa = PBXFileReference; lastKnownFileType = folder; name = images; path = ../../../browser/dist/images; sourceTree = ""; }; + BE5A7A282D2BE28200FE7D60 /* FileUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = FileUtil.hpp; path = ../../../../common/FileUtil.hpp; sourceTree = ""; }; BE9115A92CECBCB200C597B2 /* SigUtil-mobile.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "SigUtil-mobile.cpp"; path = "../../../../common/SigUtil-mobile.cpp"; sourceTree = ""; }; BE9115AB2CECBD0100C597B2 /* FileUtil-apple.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "FileUtil-apple.mm"; path = "../../../../common/FileUtil-apple.mm"; sourceTree = ""; }; BE9115AD2CECBD3100C597B2 /* FileUtil-unix.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "FileUtil-unix.cpp"; path = "../../../../common/FileUtil-unix.cpp"; sourceTree = ""; }; @@ -217,6 +218,7 @@ BEA263542CBE38E20007435A /* ConfigUtil.hpp */, BEA263552CBE38E20007435A /* ConfigUtil.cpp */, BE2231B72CC679DE00385A9C /* Crypto-stub.cpp */, + BE5A7A282D2BE28200FE7D60 /* FileUtil.hpp */, BEA263562CBE38E20007435A /* FileUtil.cpp */, BE9115AB2CECBD0100C597B2 /* FileUtil-apple.mm */, BE9115AD2CECBD3100C597B2 /* FileUtil-unix.cpp */, @@ -625,7 +627,6 @@ GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", - "MACOS=MACOS", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; @@ -708,7 +709,6 @@ GCC_NO_COMMON_BLOCKS = YES; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", - "MACOS=MACOS", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; From 5595da3d8677b57bead2a16073be8e4b696cc659 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 6 Jan 2025 14:57:48 +0100 Subject: [PATCH 059/177] Generalize the check for capabilities to avoid the specific check for FreeBSD Signed-off-by: Jan Holesovsky Change-Id: I551af7554109653aee8717000ad133ab491f6b98 --- kit/ForKit.cpp | 2 ++ kit/Kit.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/kit/ForKit.cpp b/kit/ForKit.cpp index 2240400aadac3..72dac92a9b975 100644 --- a/kit/ForKit.cpp +++ b/kit/ForKit.cpp @@ -346,6 +346,7 @@ void cleanupChildren(const std::string& childRoot) } else if (status == SIGKILL) { +#if !defined(MACOS) // TODO differentiate with docker if (info.si_code == SI_KERNEL) { @@ -354,6 +355,7 @@ void cleanupChildren(const std::string& childRoot) << status); } else +#endif { ++killedCount; LOG_WRN("Child " << exitedChildPid << " was killed, with status " diff --git a/kit/Kit.cpp b/kit/Kit.cpp index a0301d476e290..31baffdae822c 100644 --- a/kit/Kit.cpp +++ b/kit/Kit.cpp @@ -36,7 +36,7 @@ #include #endif -#if defined(__FreeBSD__) +#if defined(__FreeBSD__) || defined(MACOS) #include #define FTW_CONTINUE 0 #define FTW_STOP (-1) From 4e25d6449df3693a11485f8497a1120cbb679eea Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 12 Jan 2026 18:34:29 +0100 Subject: [PATCH 060/177] Move the CPPFLAGS overwriting to the bottom of configure.ac Without this, some checks may fail due to missing plugins.so, unrelated to what they are actually checking. Signed-off-by: Jan Holesovsky Change-Id: I506ea92ff280af993678388d8b9f5423d0104b92 --- configure.ac | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/configure.ac b/configure.ac index 0a3f3abbf2ee3..7fdd0c918e018 100644 --- a/configure.ac +++ b/configure.ac @@ -1747,19 +1747,6 @@ AS_IF([test `uname -s` = "FreeBSD"], AS_IF([test `uname -s` = "FreeBSD"], [LIBS="$LIBS -lexecinfo -lz -liconv"]) -# need this after the other stuff that uses the compiler because we don't want to run configure-tests with the plugins enabled -AS_IF([test -n "$with_compiler_plugins"], - [CPPFLAGS="$CPPFLAGS -Xclang -load -Xclang ${with_compiler_plugins}/compilerplugins/obj/plugin.so -Xclang -add-plugin -Xclang loplugin -Xclang -plugin-arg-loplugin -Xclang --cool-base-path=\${abs_top_srcdir}"]) - -# Clang plugin. -AC_MSG_CHECKING([whether to build a clang plugin]) -if test "$enable_coplugin" = "yes"; then - AC_MSG_RESULT([yes]) - CPPFLAGS="$CPPFLAGS -Xclang -load -Xclang \${abs_top_srcdir}/clang/plugin.so -Xclang -add-plugin -Xclang coplugin" -else - AC_MSG_RESULT([no]) -fi - if test "x${prefix}" = "xNONE"; then prefix=/usr/local fi @@ -2219,6 +2206,23 @@ AS_IF([test "$ENABLE_IOSAPP" = "true"], [ ]) +dnl !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +dnl Set plugins.so in CPPFLAGS as the last thing - not to interfere with other checks +dnl !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +# need this after the other stuff that uses the compiler because we don't want to run configure-tests with the plugins enabled +AS_IF([test -n "$with_compiler_plugins"], + [CPPFLAGS="$CPPFLAGS -Xclang -load -Xclang ${with_compiler_plugins}/compilerplugins/obj/plugin.so -Xclang -add-plugin -Xclang loplugin -Xclang -plugin-arg-loplugin -Xclang --cool-base-path=\${abs_top_srcdir}"]) + +# Clang plugin. +AC_MSG_CHECKING([whether to build a clang plugin]) +if test "$enable_coplugin" = "yes"; then + AC_MSG_RESULT([yes]) + CPPFLAGS="$CPPFLAGS -Xclang -load -Xclang \${abs_top_srcdir}/clang/plugin.so -Xclang -add-plugin -Xclang coplugin" +else + AC_MSG_RESULT([no]) +fi + echo " Configuration: LOKit path ${lokit_msg} From 43993d63898481f121905dbff2691ae1f3d8d152 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 6 Jan 2025 17:06:00 +0100 Subject: [PATCH 061/177] Implement pipe2() for platforms that don't have it (like macOS) Signed-off-by: Jan Holesovsky Change-Id: I20d87b4b1db60fdd7d4e5a9d22bf56792ffc5a9e --- common/Util.hpp | 59 +++++++++++++++++++++++++++++++++++++++++++++++++ config.h.in | 3 +++ configure.ac | 1 + 3 files changed, 63 insertions(+) diff --git a/common/Util.hpp b/common/Util.hpp index 6c822aebde094..3e94e68a14831 100644 --- a/common/Util.hpp +++ b/common/Util.hpp @@ -27,6 +27,13 @@ #include #include #include + +#if !HAVE_PIPE2 +#include +#include +#include +#endif + #include #include @@ -1475,6 +1482,58 @@ inline std::ostream& operator<<(std::ostream& os, const std::chrono::system_cloc inline std::ostream& operator<<(std::ostream& os, const Util::Backtrace& bt) { return bt.send(os); } +#if !HAVE_PIPE2 +/// Implementation of pipe2() for platforms that don't have it (like macOS) +inline int pipe2(int pipefd[2], int flags) +{ + if (pipe(pipefd) < 0) + return -1; + + // If the user wants O_CLOEXEC, set FD_CLOEXEC on both ends + if (flags & O_CLOEXEC) + { + int fd_flags; + for (int i = 0; i < 2; i++) + { + fd_flags = fcntl(pipefd[i], F_GETFD); + if (fd_flags == -1) + goto error; + + fd_flags |= FD_CLOEXEC; + if (fcntl(pipefd[i], F_SETFD, fd_flags) == -1) + goto error; + } + } + + // If the user wants O_NONBLOCK, set O_NONBLOCK on both ends + if (flags & O_NONBLOCK) + { + int fl_flags; + for (int i = 0; i < 2; i++) + { + fl_flags = fcntl(pipefd[i], F_GETFL); + if (fl_flags == -1) + goto error; + + fl_flags |= O_NONBLOCK; + if (fcntl(pipefd[i], F_SETFL, fl_flags) == -1) + goto error; + } + } + + return 0; + +error: + { + int saved_errno = errno; + close(pipefd[0]); + close(pipefd[1]); + errno = saved_errno; + } + return -1; +} +#endif + // std::to_underlying will be available in C++23 template constexpr std::underlying_type_t to_underlying(Enum e) { diff --git a/config.h.in b/config.h.in index 99b366e75e5ea..54225178f1385 100644 --- a/config.h.in +++ b/config.h.in @@ -81,6 +81,9 @@ /* Define to 1 if the `memrchr' function is available, otherwise 0. */ #define HAVE_MEMRCHR 0 +/* Define to 1 if you have the `pipe2' function. */ +#define HAVE_PIPE2 0 + /* Default value of help root URL */ #undef HELP_URL diff --git a/configure.ac b/configure.ac index 7fdd0c918e018..85b044712bb23 100644 --- a/configure.ac +++ b/configure.ac @@ -1843,6 +1843,7 @@ AC_SUBST(IOSAPP_FONTS) AC_CHECK_FUNCS(ppoll) AC_CHECK_FUNCS([memrchr]) +AC_CHECK_FUNCS([pipe2]) ENABLE_CYPRESS=false if test "$enable_cypress" = "yes"; then From 7e7f97fd8a6d4d8f70ba1a44b5baa7ad879abf33 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 6 Jan 2025 19:38:26 +0100 Subject: [PATCH 062/177] Avoid "error: unused function" on macOS Signed-off-by: Jan Holesovsky Change-Id: Ibe6c048c1112c50cb2b48173aa0b4ec59c891eed --- common/JailUtil.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/common/JailUtil.cpp b/common/JailUtil.cpp index 0938ab9820832..6182faff7538c 100644 --- a/common/JailUtil.cpp +++ b/common/JailUtil.cpp @@ -43,6 +43,7 @@ namespace static const std::string CoolTestMountpoint = "cool_test_mount"; +#ifdef __linux__ static void setdeny() { std::ofstream of("/proc/self/setgroups"); @@ -61,6 +62,8 @@ static void mapuser(uid_t origuid, uid_t newuid, gid_t origgid, gid_t newgid) of << newgid << " " << origgid << " 1"; } } +#endif // __linux__ + } // namespace bool enterMountingNS(uid_t uid, gid_t gid) From 821d3c751740afaa8c87626bef74ac16062300e9 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Tue, 7 Jan 2025 10:46:04 +0200 Subject: [PATCH 063/177] Add HAVE_LIBCAP, HAVE_PIPE2, and MACOS here, too Signed-off-by: Tor Lillqvist Change-Id: I44181343c2fd829e8bfc078d35af56e2b1b40e65 --- windows/coda/config.h.in | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/windows/coda/config.h.in b/windows/coda/config.h.in index 58eb4557fa89e..87f7d89799e16 100755 --- a/windows/coda/config.h.in +++ b/windows/coda/config.h.in @@ -52,6 +52,9 @@ /* Define to 1 if you have the header file. */ #define HAVE_MEMORY_H 1 +/* Define to 1 libcap (cap_get_proc) is available, otherwise 0 */ +#define HAVE_LIBCAP 0 + /* Whether OpenSSL has PKCS5_PBKDF2_HMAC() */ #define HAVE_PKCS5_PBKDF2_HMAC 0 @@ -85,6 +88,9 @@ /* Define to 1 if you have the `memrchr' function. */ #define HAVE_MEMRCHR 0 +/* Define to 1 if you have the `pipe2' function. */ +#define HAVE_PIPE2 0 + /* Collabora Online WebSocket server version */ #define COOLWSD_VERSION "@COOLWSD_VERSION@" @@ -130,6 +136,9 @@ /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 +/* Define to 1 if building for macOS */ +#undef MACOS + /* Makes config variables conditionally static, only in non-debug builds, to allow for overriding them in unit-tests. */ #ifdef ENABLE_DEBUG #define CONFIG_STATIC From ee68577169715d0c958eb2a1ca71db5a7e61de97 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Tue, 7 Jan 2025 10:57:52 +0200 Subject: [PATCH 064/177] Fix build of CODA-W Signed-off-by: Tor Lillqvist Change-Id: I42039e121ad99be5d9eaa945bf39ffdbb598d647 --- common/Util.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/common/Util.hpp b/common/Util.hpp index 3e94e68a14831..7cf1ae2cb1fd0 100644 --- a/common/Util.hpp +++ b/common/Util.hpp @@ -31,8 +31,10 @@ #if !HAVE_PIPE2 #include #include +#ifndef _WINDOWS #include #endif +#endif #include #include @@ -1482,7 +1484,7 @@ inline std::ostream& operator<<(std::ostream& os, const std::chrono::system_cloc inline std::ostream& operator<<(std::ostream& os, const Util::Backtrace& bt) { return bt.send(os); } -#if !HAVE_PIPE2 +#if !MOBILEAPP && !HAVE_PIPE2 /// Implementation of pipe2() for platforms that don't have it (like macOS) inline int pipe2(int pipefd[2], int flags) { From 315b47c33a6faf0e26dfbd074fe26c8df4502200 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Tue, 7 Jan 2025 12:09:17 +0200 Subject: [PATCH 065/177] Use the built-in predefined _WIN32 macro instead of an own silly _WINDOWS Signed-off-by: Tor Lillqvist Change-Id: Ifa4a0b82061576e0aee7ff56df13514e5a28a43e --- common/FileUtil.cpp | 2 +- common/FileUtil.hpp | 2 +- common/Log.cpp | 8 ++++---- common/Unit.cpp | 2 +- common/Util.cpp | 8 ++++---- common/Util.hpp | 4 ++-- kit/Kit.cpp | 4 ++-- kit/KitWebSocket.cpp | 2 +- net/FakeSocket.cpp | 2 +- net/FakeSocket.hpp | 2 +- net/Socket.cpp | 2 +- windows/coda/CODALib/CODALib.vcxproj | 6 +++--- .../test/DllImportTest/DllImported/DllImported.vcxproj | 10 +++++----- wsd/COOLWSD.cpp | 4 ++-- wsd/PlatformMobile.hpp | 2 +- wsd/RequestDetails.cpp | 2 +- wsd/Storage.cpp | 2 +- 17 files changed, 32 insertions(+), 32 deletions(-) diff --git a/common/FileUtil.cpp b/common/FileUtil.cpp index 7ba2a6dc6876a..2e1b80bdf6b02 100644 --- a/common/FileUtil.cpp +++ b/common/FileUtil.cpp @@ -176,7 +176,7 @@ namespace FileUtil if (preserveTimestamps) { const Stat st(fromPath); -#ifndef _WINDOWS +#ifndef _WIN32 updateTimestamps(randFilename, #if defined(IOS) || defined(MACOS) st.sb().st_atimespec, st.sb().st_mtimespec diff --git a/common/FileUtil.hpp b/common/FileUtil.hpp index b9adffbb8feaa..a3aed84913cf6 100644 --- a/common/FileUtil.hpp +++ b/common/FileUtil.hpp @@ -276,7 +276,7 @@ namespace FileUtil { #if defined(IOS) || defined(MACOS) return _sb.st_mtimespec; -#elif defined(_WINDOWS) +#elif defined(_WIN32) timespec result{ _sb.st_mtime, 0 }; return result; #else diff --git a/common/Log.cpp b/common/Log.cpp index e3d0147032a1f..c6b4decda0c5a 100644 --- a/common/Log.cpp +++ b/common/Log.cpp @@ -29,7 +29,7 @@ #include #include #include -#ifndef _WINDOWS +#ifndef _WIN32 #include #else #define WIN32_LEAN_AND_MEAN @@ -140,7 +140,7 @@ namespace Log /// Write the given buffer to stderr directly. static inline std::size_t writeRaw(const char* data, std::size_t count) { -#ifndef _WINDOWS +#ifndef _WIN32 #if WASMAPP // In WASM, stdout works best. constexpr int LOG_FILE_FD = STDOUT_FILENO; @@ -166,7 +166,7 @@ namespace Log count -= wrote; } return ptr - data; -#else // _WINDOWS +#else // _WIN32 if (!IsDebuggerPresent()) fwrite(data, size, 1, stderr); else @@ -494,7 +494,7 @@ namespace Log char* prefix(const std::chrono::time_point& tp, char* buffer, const std::string_view level) { -#if defined(IOS) || defined(__FreeBSD__) || defined(_WINDOWS) +#if defined(IOS) || defined(__FreeBSD__) || defined(_WIN32) // Don't bother with the "Source" which would be just "Mobile" always (or whatever the app // process is called depending on platform and configuration) and non-informative as there // is just one process in the app anyway. diff --git a/common/Unit.cpp b/common/Unit.cpp index 217eeda29d6a8..cc60f68a60a80 100644 --- a/common/Unit.cpp +++ b/common/Unit.cpp @@ -25,7 +25,7 @@ #include #include #include -#ifndef _WINDOWS +#ifndef _WIN32 #include #endif #include diff --git a/common/Util.cpp b/common/Util.cpp index df13000619fb6..74779c4491b76 100644 --- a/common/Util.cpp +++ b/common/Util.cpp @@ -56,7 +56,7 @@ #include "SigHandlerTrap.hpp" #endif -#if !defined(__ANDROID__) && !defined(__EMSCRIPTEN__) && !defined(_WINDOWS) +#if !defined(__ANDROID__) && !defined(__EMSCRIPTEN__) && !defined(_WIN32) # include # include #endif @@ -72,7 +72,7 @@ #import #endif -#ifndef _WINDOWS +#ifndef _WIN32 #include #include #include @@ -91,7 +91,7 @@ #include #endif -#ifdef _WINDOWS +#ifdef _WIN32 #include #endif @@ -320,7 +320,7 @@ namespace Util LOG_INF("Thread " << getThreadId() << ") is now called [" << s << ']'); #elif defined __EMSCRIPTEN__ emscripten_console_logf("COOL thread name: \"%s\"", s.c_str()); -#elif defined _WINDOWS +#elif defined _WIN32 SetThreadDescription(GetCurrentThread(), string_to_wide_string(s).c_str()); LOG_INF("Thread " << getThreadId() << ") is now called [" << s << ']'); #endif diff --git a/common/Util.hpp b/common/Util.hpp index 7cf1ae2cb1fd0..00b24ee84fc2e 100644 --- a/common/Util.hpp +++ b/common/Util.hpp @@ -31,7 +31,7 @@ #if !HAVE_PIPE2 #include #include -#ifndef _WINDOWS +#ifndef _WIN32 #include #endif #endif @@ -1470,7 +1470,7 @@ int main(int argc, char**argv) /// Base-64 decode the given input. std::string base64Decode(const std::string& input); -#ifdef _WINDOWS +#ifdef _WIN32 std::wstring string_to_wide_string(const std::string& string); std::string wide_string_to_string(const std::wstring& wide_string); #endif diff --git a/kit/Kit.cpp b/kit/Kit.cpp index 31baffdae822c..a6af6e05f04fb 100644 --- a/kit/Kit.cpp +++ b/kit/Kit.cpp @@ -44,7 +44,7 @@ #define FTW_ACTIONRETVAL 0 #endif -#ifndef _WINDOWS +#ifndef _WIN32 #include #include #include @@ -3943,7 +3943,7 @@ void lokit_main( #ifdef IOS // In the iOS app we call lok_init_2() just once, when the app starts static LibreOfficeKit *kit = lo_kit; -#elif defined(_WINDOWS) +#elif defined(_WIN32) // LO_PATH is a Windows path starting with a drive letter. For the second parameter to // lok_init_2() turn it into a file: URI. LibreOfficeKit *kit = lok_init_2(LO_PATH "/program", "file:///" LO_PATH); diff --git a/kit/KitWebSocket.cpp b/kit/KitWebSocket.cpp index 25baa6389dd57..97dad5b2a7e68 100644 --- a/kit/KitWebSocket.cpp +++ b/kit/KitWebSocket.cpp @@ -17,7 +17,7 @@ #include -#ifndef _WINDOWS +#ifndef _WIN32 #include #include #endif diff --git a/net/FakeSocket.cpp b/net/FakeSocket.cpp index e7acfabea253e..7252532890ce7 100644 --- a/net/FakeSocket.cpp +++ b/net/FakeSocket.cpp @@ -12,7 +12,7 @@ #include "config.h" #include -#ifndef _WINDOWS +#ifndef _WIN32 #include #endif diff --git a/net/FakeSocket.hpp b/net/FakeSocket.hpp index 8801980781dbc..b833b727f17bf 100644 --- a/net/FakeSocket.hpp +++ b/net/FakeSocket.hpp @@ -17,7 +17,7 @@ #include -#ifndef _WINDOWS +#ifndef _WIN32 #include #endif diff --git a/net/Socket.cpp b/net/Socket.cpp index 2d3507c7f8873..88a649baee061 100644 --- a/net/Socket.cpp +++ b/net/Socket.cpp @@ -50,7 +50,7 @@ #include #include -#ifndef _WINDOWS +#ifndef _WIN32 #include #include #include diff --git a/windows/coda/CODALib/CODALib.vcxproj b/windows/coda/CODALib/CODALib.vcxproj index 01a672b741ee6..a3bcaf43f66cb 100644 --- a/windows/coda/CODALib/CODALib.vcxproj +++ b/windows/coda/CODALib/CODALib.vcxproj @@ -55,7 +55,7 @@ Level3 true - _DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);NOMINMAX;_CRT_SECURE_NO_WARNINGS;COOLWSD_CONFIGDIR=".";COOLWSD_LOGLEVEL="debug";NUM_PRESPAWN_CHILDREN="1" + _DEBUG;_USRDLL;%(PreprocessorDefinitions);NOMINMAX;_CRT_SECURE_NO_WARNINGS;COOLWSD_CONFIGDIR=".";COOLWSD_LOGLEVEL="debug";NUM_PRESPAWN_CHILDREN="1" true NotUsing pch.h @@ -79,7 +79,7 @@ true true true - NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);NOMINMAX;_CRT_SECURE_NO_WARNINGS;COOLWSD_CONFIGDIR=".";COOLWSD_LOGLEVEL="warning";NUM_PRESPAWN_CHILDREN="1" + NDEBUG;_USRDLL;%(PreprocessorDefinitions);NOMINMAX;_CRT_SECURE_NO_WARNINGS;COOLWSD_CONFIGDIR=".";COOLWSD_LOGLEVEL="warning";NUM_PRESPAWN_CHILDREN="1" true NotUsing pch.h @@ -140,4 +140,4 @@ - \ No newline at end of file + diff --git a/windows/coda/test/DllImportTest/DllImported/DllImported.vcxproj b/windows/coda/test/DllImportTest/DllImported/DllImported.vcxproj index e8c351cabd739..3983708d8c5a7 100644 --- a/windows/coda/test/DllImportTest/DllImported/DllImported.vcxproj +++ b/windows/coda/test/DllImportTest/DllImported/DllImported.vcxproj @@ -80,7 +80,7 @@ Level3 true - WIN32;_DEBUG;DLLIMPORTED_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + WIN32;_DEBUG;DLLIMPORTED_EXPORTS;_USRDLL;%(PreprocessorDefinitions) true @@ -95,7 +95,7 @@ true true true - WIN32;NDEBUG;DLLIMPORTED_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + WIN32;NDEBUG;DLLIMPORTED_EXPORTS;_USRDLL;%(PreprocessorDefinitions) true @@ -110,7 +110,7 @@ Level3 true - _DEBUG;DLLIMPORTED_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + _DEBUG;DLLIMPORTED_EXPORTS;_USRDLL;%(PreprocessorDefinitions) true stdcpp20 @@ -126,7 +126,7 @@ true true true - NDEBUG;DLLIMPORTED_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + NDEBUG;DLLIMPORTED_EXPORTS;_USRDLL;%(PreprocessorDefinitions) true stdcpp20 @@ -144,4 +144,4 @@ - \ No newline at end of file + diff --git a/wsd/COOLWSD.cpp b/wsd/COOLWSD.cpp index 9cafa7d3dfcf4..22f136067f41d 100644 --- a/wsd/COOLWSD.cpp +++ b/wsd/COOLWSD.cpp @@ -33,7 +33,7 @@ // parent process that listens on the TCP port and accepts connections from COOL clients, and a // number of child processes, each which handles a viewing (editing) session for one document. -#ifndef _WINDOWS +#ifndef _WIN32 #include #include #include @@ -2077,7 +2077,7 @@ void COOLWSD::innerInitialize(Poco::Util::Application& self) COOLWSD::MaxDocuments = COOLWSD::MaxConnections; } -#if !WASMAPP && !defined(_WINDOWS) +#if !WASMAPP && !defined(_WIN32) struct rlimit rlim; ::getrlimit(RLIMIT_NOFILE, &rlim); LOG_INF("Maximum file descriptor supported by the system: " << rlim.rlim_cur - 1); diff --git a/wsd/PlatformMobile.hpp b/wsd/PlatformMobile.hpp index 667bfb627b6b4..4040b1c384222 100644 --- a/wsd/PlatformMobile.hpp +++ b/wsd/PlatformMobile.hpp @@ -16,7 +16,7 @@ #include "ios.h" #elif defined(MACOS) #include "macos.h" -#elif defined(_WINDOWS) +#elif defined(_WIN32) #include "windows.hpp" #elif defined(GTKAPP) #include "gtk.hpp" diff --git a/wsd/RequestDetails.cpp b/wsd/RequestDetails.cpp index 5aa0cdf9944ff..8e962513f20bb 100644 --- a/wsd/RequestDetails.cpp +++ b/wsd/RequestDetails.cpp @@ -282,7 +282,7 @@ Poco::URI RequestDetails::sanitizeURI(const std::string& uri) { // TODO: Validate and limit access to local paths! uriPublic.normalize(); -#ifdef _WINDOWS +#ifdef _WIN32 std::string p = uriPublic.getPath(); if (p.length() > 4 && p[0] == '/' && std::isalpha(p[1]) && p[2] == ':' && p[3] == '/') uriPublic.setPath(p.substr(1)); diff --git a/wsd/Storage.cpp b/wsd/Storage.cpp index fd5c9922485fc..38a682b9f454c 100644 --- a/wsd/Storage.cpp +++ b/wsd/Storage.cpp @@ -54,7 +54,7 @@ #include #elif defined(__ANDROID__) #include "androidapp.hpp" -#elif defined(_WINDOWS) +#elif defined(_WIN32) #include "windows.hpp" #elif defined(GTKAPP) #include "gtk.hpp" From 43c68fe979a222e013164351a04ac3e6ba0fd090 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 7 Jan 2025 11:18:43 +0100 Subject: [PATCH 066/177] Make the HAVE_* defines more consistent and improve the comments Signed-off-by: Jan Holesovsky Change-Id: I4200dd0d9dbe3108e14abaeffd424dc0e61d1dff --- config.h.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.h.in b/config.h.in index 54225178f1385..2703c55b27b44 100644 --- a/config.h.in +++ b/config.h.in @@ -81,7 +81,7 @@ /* Define to 1 if the `memrchr' function is available, otherwise 0. */ #define HAVE_MEMRCHR 0 -/* Define to 1 if you have the `pipe2' function. */ +/* Define to 1 if the `pipe2' function is available, otherwise 0. */ #define HAVE_PIPE2 0 /* Default value of help root URL */ From 212ed93bf3e4e919c694d634ff0e79d4e84c153b Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 7 Jan 2025 12:34:26 +0100 Subject: [PATCH 067/177] This prctl() call is Linux-specific For macOS, we'll probably need to implement periodical checking of the parent pid or something. Signed-off-by: Jan Holesovsky Change-Id: I4ae32804683e36ab96c720d2971b8e9fffca79e6 --- common/SigUtil-server.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/SigUtil-server.cpp b/common/SigUtil-server.cpp index 40404c9903dfd..c86e782d59c21 100644 --- a/common/SigUtil-server.cpp +++ b/common/SigUtil-server.cpp @@ -588,7 +588,7 @@ void resetTerminationFlags() void dieOnParentDeath() { -#if !defined(ANDROID) && !defined(__FreeBSD__) +#if defined(__linux__) && !defined(ANDROID) prctl(PR_SET_PDEATHSIG, SIGKILL); #endif #if defined(__FreeBSD__) From d93b7e68b6601604e72e377fca0a396e8e9ef050 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 7 Jan 2025 13:18:28 +0100 Subject: [PATCH 068/177] Add macOS/iOS implementation of getThreadId() It seems the best would be to turn the getThreadId() to using std::this_thread::get_id(), but it is a larger cleanup. Also includes two trivial fixes for 'error: unused parameter' on macOS. Signed-off-by: Jan Holesovsky Change-Id: I95518ba58ed88234619a1e8f96459bda39120b9d --- common/Util.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/common/Util.cpp b/common/Util.cpp index 74779c4491b76..aea8f3df645b5 100644 --- a/common/Util.cpp +++ b/common/Util.cpp @@ -271,6 +271,14 @@ namespace Util if (!ThreadTid) thr_self(&ThreadTid); return ThreadTid; +#elif defined __APPLE__ + if (!ThreadTid) + { + uint64_t tid; + if (pthread_threadid_np(NULL, &tid) == 0) + ThreadTid = tid; + } + return ThreadTid; #else static long threadCounter = 1; if (!ThreadTid) @@ -284,6 +292,7 @@ namespace Util #if defined __linux__ ::syscall(SYS_tgkill, getpid(), tid, signal); #else + (void) signal; LOG_WRN("No tgkill for thread " << tid); #endif } @@ -955,6 +964,8 @@ namespace Util free(rawSymbols); } } +#else + (void) maxFrames; #endif if (0 == _frames.size()) { From 326abb7ef32bf27e269f6f2d268deb96ef0c9acd Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 7 Jan 2025 16:32:44 +0100 Subject: [PATCH 069/177] Define 'environ' on macOS Signed-off-by: Jan Holesovsky Change-Id: I63532af4e4cfc82389664df1110a0ed9fed0d7ff --- common/Util-server.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/common/Util-server.cpp b/common/Util-server.cpp index 7bca210bed1b4..01b4eb8113f4d 100644 --- a/common/Util-server.cpp +++ b/common/Util-server.cpp @@ -31,6 +31,12 @@ extern char** environ; #endif +// 'environ' is not directly available on macOS, but using _NSGetEnviron() should be good enough +#ifdef __APPLE__ +# include +# define environ (*_NSGetEnviron()) +#endif + namespace { const char* startsWith(const char* line, const char* tag, std::size_t tagLen) From 323441ab03aba7864a6f718a27fcf7ed9a6112ad Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 13 Jan 2025 10:41:20 +0100 Subject: [PATCH 070/177] Trivial implementation of mount() and umount2() for macOS Signed-off-by: Jan Holesovsky Change-Id: I3e9c9f237c3f8ef35f8c4b13297af3548573a91d --- common/CoolMount.cpp | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/common/CoolMount.cpp b/common/CoolMount.cpp index 0dcdfd3311ec1..1d61621a02f3f 100644 --- a/common/CoolMount.cpp +++ b/common/CoolMount.cpp @@ -36,7 +36,19 @@ #define MS_REMOUNT 4 #define MS_NOSUID 16 #define MS_RDONLY 32 +#elif defined(__APPLE__) +#define MOUNT mount_wrapper +#define MS_MGC_VAL 0 // ignored, no mapping to macOS +#define MS_NODEV MNT_NODEV +#define MS_UNBINDABLE 0 // ignored, no mapping to macOS +#define MS_BIND 0 // ignored, no mapping to macOS +#define MS_REC 0 // ignored, no mapping to macOS +#define MS_REMOUNT 0 // ignored, no mapping to macOS +#define MS_NOSUID MNT_NOSUID +#define MS_RDONLY MNT_RDONLY +#endif +#ifdef __FreeBSD__ void build_iovec(struct iovec **iov, int *iovlen, const char *name, const void *val, size_t len) @@ -94,7 +106,32 @@ int mount_wrapper(const char *source, const char *target, return nmount(iov, iovlen, freebsd_flags); } +#elif defined(__APPLE__) +int mount_wrapper(const char *source, const char *target, + const char *filesystemtype, unsigned long mountflags, + const void *data) +{ + // Build some "data" for mount(2) if it's suspected that the FS needs a device=SOURCE string: + char fallback_data[1024]; + if (source && *source) { + // e.g. "device=/dev/disk2s1" or "device=/path/to/something" + snprintf(fallback_data, sizeof(fallback_data), "device=%s", source); + } else { + fallback_data[0] = '\0'; + } + + const char *fs = (filesystemtype ? filesystemtype : "hfs"); + + // It's expected that the mountflags are built using the above defines, + // ie. no translation is needed + return mount(fs, target, mountflags, + fallback_data[0] ? (void*)fallback_data : (void*)data); +} +#else +#define MOUNT mount +#endif +#ifndef __linux__ #define MNT_DETACH 1 int umount2(const char *target, int flags) @@ -123,8 +160,6 @@ int umount2(const char *target, int flags) return unmount(target, flags); } -#else -#define MOUNT mount #endif void usage(const char* program) From 70697820df1585eb7b4c1b424a8ce65ccc10e6b6 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 13 Jan 2025 12:07:35 +0100 Subject: [PATCH 071/177] coda-m: Update readme Signed-off-by: Jan Holesovsky Change-Id: I8dd66c14e089070de4a9a6f19e7a4a09acb5dd42 --- macos/README.txt | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/macos/README.txt b/macos/README.txt index b9875d627a3f3..ad2ec54bed0e7 100644 --- a/macos/README.txt +++ b/macos/README.txt @@ -20,6 +20,8 @@ Setup * install canvas to avoid error during build (complains about node-pre-gyp) * NB. version 3.0 needed, it upgrades the API to fit the new node.js * npm install canvas@next + * It might be that you should run the above in the browser subdirectory + of your online directory: (cd browser && npm install canvas@next) * Install and/or update the Command Line Tools for Xcode: * xcode-select --install @@ -28,15 +30,24 @@ Setup Build LO +You need the 'coda' branch for that, and have to use the following +autogen.input. + +NOTE: I build with stuff installed via 'brew', and not via 'lode'; if you have +too many things installed via 'brew', compilation may fail for you due to +incompatible stuff. + autogen.input: # Distro --with-distro=CPMacOS-LOKit - + --enable-headless + --disable-mergelibs + # Overrides for the debug builds --enable-debug #--enable-dbgutil - + --enable-werror --enable-symbols --without-lang @@ -57,7 +68,13 @@ Configure Collabora Online --with-lo-path=/Users/kendy/Projects/lo/core/instdir/CollaboraOffice.app \ --with-lokit-path=/Users/kendy/Projects/lo/core/include -Build Collabora Online +Obbiously you need to change the /Users/kendy/etc above to match what +you have. Also, in some cases (perhaps on Intel Macs?) homebrew gets +installed in /usr/local, not /opt/homebrew. + +You also need to edit the macos/coda/coda.xcodeproj/project.pbxproj accordingly. Look for /Users/kendy and /opt/homebrew. + +Then you can build CODA-M: * ( cd browser ; make ) * open Xcode's project macos/coda/coda.xcodeproj & build from there From 285c3a2f0347e181793ff810b31e5a3bbd991b9e Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 13 Jan 2025 15:10:22 +0100 Subject: [PATCH 072/177] coda-m: Guard some parts with MOBILEAPP These will likely need changes when making the COOL work on macOS. Signed-off-by: Jan Holesovsky Change-Id: Idb2962e99f3d728ab75d820c6f3536719c11420c --- kit/Kit.cpp | 4 ++-- kit/SetupKitEnvironment.hpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/kit/Kit.cpp b/kit/Kit.cpp index a6af6e05f04fb..8f8112cae4cd8 100644 --- a/kit/Kit.cpp +++ b/kit/Kit.cpp @@ -115,7 +115,7 @@ #ifdef IOS #include "ios.h" #include "DocumentBroker.hpp" -#elif defined(MACOS) +#elif defined(MACOS) && MOBILEAPP #include "macos.h" #include "DocumentBroker.hpp" #endif @@ -3937,7 +3937,7 @@ void lokit_main( #if (defined(__linux__) && !defined(__ANDROID__)) || defined(__FreeBSD__) Poco::URI userInstallationURI("file", LO_PATH); LibreOfficeKit *kit = lok_init_2(LO_PATH "/program", userInstallationURI.toString().c_str()); -#elif defined(MACOS) +#elif defined(MACOS) && MOBILEAPP LibreOfficeKit *kit = lok_init_2((getBundlePath() + "/Contents/lokit/Frameworks").c_str(), getAppSupportURL().c_str()); #else diff --git a/kit/SetupKitEnvironment.hpp b/kit/SetupKitEnvironment.hpp index 18d9f10e47a0f..c64b42f79fefb 100644 --- a/kit/SetupKitEnvironment.hpp +++ b/kit/SetupKitEnvironment.hpp @@ -16,7 +16,7 @@ #include -#if defined(MACOS) +#if defined(MACOS) && MOBILEAPP #include #endif @@ -37,7 +37,7 @@ inline void setupKitEnvironment(const std::string& userInterface) ); #ifdef IOS layers += "user:*${BRAND_BASE_DIR}/coolkitconfig.xcu "; -#elif defined(MACOS) +#elif defined(MACOS) && MOBILEAPP layers += "user:*" + getResourceURL("coolkitconfig", "xcu"); #elif ENABLE_DEBUG && !defined(ANDROID) // '*' denotes non-writable. layers += "user:*file://" DEBUG_ABSSRCDIR "/coolkitconfig.xcu "; From 9ba4968972a3db836a03075b249cb70923043422 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 13 Jan 2025 15:17:15 +0100 Subject: [PATCH 073/177] Create Syscall.hpp/cpp to wrap various platform-dependent syscalls Move pipe2() there, and implement socketpair() with CLOEXEC and NONBLOCK for macOS. Signed-off-by: Jan Holesovsky Change-Id: I7381d3f27651d7dd4277b6b72e56c2189460f410 --- Makefile.am | 2 + common/Syscall.cpp | 113 ++++++++++++++++++++++ common/Syscall.hpp | 30 ++++++ common/Util-server.cpp | 2 +- common/Util.hpp | 60 ------------ kit/Kit.cpp | 3 +- macos/coda/coda.xcodeproj/project.pbxproj | 10 +- net/DelaySocket.cpp | 3 +- 8 files changed, 157 insertions(+), 66 deletions(-) create mode 100644 common/Syscall.cpp create mode 100644 common/Syscall.hpp diff --git a/Makefile.am b/Makefile.am index df41ae1782e24..0c687451e418d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -138,6 +138,7 @@ shared_sources = common/FileUtil.cpp \ common/RegexUtil.cpp \ common/SigUtil-server.cpp \ common/SpookyV2.cpp \ + common/Syscall.cpp \ common/TraceEvent.cpp \ common/Unit.cpp \ common/Unit-server.cpp \ @@ -447,6 +448,7 @@ shared_headers = common/Anonymizer.hpp \ common/StringVector.hpp \ common/Seccomp.hpp \ common/Session.hpp \ + common/Syscall.hpp \ common/Unit.hpp \ common/Uri.hpp \ common/Util.hpp \ diff --git a/common/Syscall.cpp b/common/Syscall.cpp new file mode 100644 index 0000000000000..13bf21390e994 --- /dev/null +++ b/common/Syscall.cpp @@ -0,0 +1,113 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * Copyright the Collabora Online contributors. + * + * SPDX-License-Identifier: MPL-2.0 + * + * 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 + +#include "Syscall.hpp" + +#include +#include + +#if !HAVE_PIPE2 +#include +#else +#include +#endif + +/** + * Internal helper functions. + */ +namespace { + +#if !HAVE_PIPE2 + +/** + * Set FD_CLOEXEC and O_NONBLOCK on one file descriptor. + */ +int set_fd_cloexec_nonblock(int fd, bool cloexec, bool nonblock) { + // Set FD_CLOEXEC if the user wants it + if (cloexec) + { + int fd_flags = fcntl(fd, F_GETFD); + if (fd_flags == -1) + return -1; + + fd_flags |= FD_CLOEXEC; + if (fcntl(fd, F_SETFD, fd_flags) == -1) + return -1; + } + + // Set O_NONBLOCK if the user wants it + if (nonblock) + { + int fl_flags = fcntl(fd, F_GETFL); + if (fl_flags == -1) + return -1; + + fl_flags |= O_NONBLOCK; + if (fcntl(fd, F_SETFL, fl_flags) == -1) + return -1; + } + + return 0; +} + +/** + * Set CLOEXEC or NONBLOCK on both sides of the pipe/socket/... + */ +int set_fds_cloexec_nonblock(int fds[2], bool cloexec, bool nonblock) { + for (int i = 0; i < 2; i++) { + int ret = set_fd_cloexec_nonblock(fds[i], cloexec, nonblock); + if (ret < 0) { + int saved_errno = errno; + close(fds[0]); + close(fds[1]); + errno = saved_errno; + + return -1; + } + } + + return 0; +} + +#endif + +} + +/// Implementation of pipe2() for platforms that don't have it (like macOS) +int Syscall::pipe2(int pipefd[2], int flags) +{ +#if HAVE_PIPE2 + return ::pipe2(pipefd, flags); +#else + if (pipe(pipefd) < 0) + return -1; + + return set_fds_cloexec_nonblock(pipefd, flags & O_CLOEXEC, flags & O_NONBLOCK); +#endif +} + +int Syscall::socketpair_cloexec_nonblock(int domain, int type, int protocol, int socket_vector[2]) +{ +#ifdef __linux__ + return ::socketpair(domain, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol, socket_vector); +#else + int rc = ::socketpair(domain, type, protocol, socket_vector); + if (rc < 0) { + return -1; + } + + return set_fds_cloexec_nonblock(socket_vector, true, true); +#endif +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/common/Syscall.hpp b/common/Syscall.hpp new file mode 100644 index 0000000000000..76026770159e2 --- /dev/null +++ b/common/Syscall.hpp @@ -0,0 +1,30 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * Copyright the Collabora Online contributors. + * + * SPDX-License-Identifier: MPL-2.0 + * + * 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/. + */ + +#pragma once + +/** + * This is a place for platform-dependent syscalls, to be able to extend them conveniently. + */ +namespace Syscall { + + /** + * Implement pipe2() on platforms that don't have it. + */ + int pipe2(int pipefd[2], int flags); + + /** + * Implement socket_pair() with CLOEXEC and NONBLOCK on platforms that don't have those flags. + */ + int socketpair_cloexec_nonblock(int domain, int type, int protocol, int socket_vector[2]); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/common/Util-server.cpp b/common/Util-server.cpp index 01b4eb8113f4d..69336b217fe2d 100644 --- a/common/Util-server.cpp +++ b/common/Util-server.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #ifdef __linux__ #include @@ -27,7 +28,6 @@ #elif defined __FreeBSD__ #include #include -#include extern char** environ; #endif diff --git a/common/Util.hpp b/common/Util.hpp index 00b24ee84fc2e..a6d83dac9cba7 100644 --- a/common/Util.hpp +++ b/common/Util.hpp @@ -28,14 +28,6 @@ #include #include -#if !HAVE_PIPE2 -#include -#include -#ifndef _WIN32 -#include -#endif -#endif - #include #include @@ -1484,58 +1476,6 @@ inline std::ostream& operator<<(std::ostream& os, const std::chrono::system_cloc inline std::ostream& operator<<(std::ostream& os, const Util::Backtrace& bt) { return bt.send(os); } -#if !MOBILEAPP && !HAVE_PIPE2 -/// Implementation of pipe2() for platforms that don't have it (like macOS) -inline int pipe2(int pipefd[2], int flags) -{ - if (pipe(pipefd) < 0) - return -1; - - // If the user wants O_CLOEXEC, set FD_CLOEXEC on both ends - if (flags & O_CLOEXEC) - { - int fd_flags; - for (int i = 0; i < 2; i++) - { - fd_flags = fcntl(pipefd[i], F_GETFD); - if (fd_flags == -1) - goto error; - - fd_flags |= FD_CLOEXEC; - if (fcntl(pipefd[i], F_SETFD, fd_flags) == -1) - goto error; - } - } - - // If the user wants O_NONBLOCK, set O_NONBLOCK on both ends - if (flags & O_NONBLOCK) - { - int fl_flags; - for (int i = 0; i < 2; i++) - { - fl_flags = fcntl(pipefd[i], F_GETFL); - if (fl_flags == -1) - goto error; - - fl_flags |= O_NONBLOCK; - if (fcntl(pipefd[i], F_SETFL, fl_flags) == -1) - goto error; - } - } - - return 0; - -error: - { - int saved_errno = errno; - close(pipefd[0]); - close(pipefd[1]); - errno = saved_errno; - } - return -1; -} -#endif - // std::to_underlying will be available in C++23 template constexpr std::underlying_type_t to_underlying(Enum e) { diff --git a/kit/Kit.cpp b/kit/Kit.cpp index 8f8112cae4cd8..2d12cef60fe51 100644 --- a/kit/Kit.cpp +++ b/kit/Kit.cpp @@ -100,6 +100,7 @@ #include #include #include +#include #include #include #include @@ -3980,7 +3981,7 @@ void lokit_main( if (isURPEnabled()) { - if (pipe2(URPtoLoFDs, O_CLOEXEC) != 0 || pipe2(URPfromLoFDs, O_CLOEXEC | O_NONBLOCK) != 0) + if (Syscall::pipe2(URPtoLoFDs, O_CLOEXEC) != 0 || Syscall::pipe2(URPfromLoFDs, O_CLOEXEC | O_NONBLOCK) != 0) LOG_ERR("Failed to create urp pipe " << strerror(errno)); else { diff --git a/macos/coda/coda.xcodeproj/project.pbxproj b/macos/coda/coda.xcodeproj/project.pbxproj index 67649dccc0235..f2b322ea5e3c9 100644 --- a/macos/coda/coda.xcodeproj/project.pbxproj +++ b/macos/coda/coda.xcodeproj/project.pbxproj @@ -18,6 +18,7 @@ BE22557E2CC79BAE00385A9C /* global.js in Resources */ = {isa = PBXBuildFile; fileRef = BE2249312CC79BAE00385A9C /* global.js */; }; BE2257AD2CC79BAE00385A9C /* bundle.css in Resources */ = {isa = PBXBuildFile; fileRef = BE22492D2CC79BAE00385A9C /* bundle.css */; }; BE22AA9C2CC7AE7400385A9C /* images in Resources */ = {isa = PBXBuildFile; fileRef = BE22AA9B2CC7AE7400385A9C /* images */; }; + BE5A7AE22D354F4000FE7D60 /* Syscall.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5A7AE12D354F4000FE7D60 /* Syscall.cpp */; }; BE9115AA2CECBCB200C597B2 /* SigUtil-mobile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE9115A92CECBCB200C597B2 /* SigUtil-mobile.cpp */; }; BE9115AC2CECBD0100C597B2 /* FileUtil-apple.mm in Sources */ = {isa = PBXBuildFile; fileRef = BE9115AB2CECBD0100C597B2 /* FileUtil-apple.mm */; }; BE9115AE2CECBD3100C597B2 /* FileUtil-unix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE9115AD2CECBD3100C597B2 /* FileUtil-unix.cpp */; }; @@ -86,6 +87,8 @@ BE2249312CC79BAE00385A9C /* global.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = global.js; path = ../../../browser/dist/global.js; sourceTree = ""; }; BE22AA9B2CC7AE7400385A9C /* images */ = {isa = PBXFileReference; lastKnownFileType = folder; name = images; path = ../../../browser/dist/images; sourceTree = ""; }; BE5A7A282D2BE28200FE7D60 /* FileUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = FileUtil.hpp; path = ../../../../common/FileUtil.hpp; sourceTree = ""; }; + BE5A7AE02D354F4000FE7D60 /* Syscall.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Syscall.hpp; path = ../../../../common/Syscall.hpp; sourceTree = ""; }; + BE5A7AE12D354F4000FE7D60 /* Syscall.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Syscall.cpp; path = ../../../../common/Syscall.cpp; sourceTree = ""; }; BE9115A92CECBCB200C597B2 /* SigUtil-mobile.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "SigUtil-mobile.cpp"; path = "../../../../common/SigUtil-mobile.cpp"; sourceTree = ""; }; BE9115AB2CECBD0100C597B2 /* FileUtil-apple.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "FileUtil-apple.mm"; path = "../../../../common/FileUtil-apple.mm"; sourceTree = ""; }; BE9115AD2CECBD3100C597B2 /* FileUtil-unix.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "FileUtil-unix.cpp"; path = "../../../../common/FileUtil-unix.cpp"; sourceTree = ""; }; @@ -236,6 +239,8 @@ BEA263622CBE38E20007435A /* SpookyV2.cpp */, BEA263632CBE38E20007435A /* StringVector.hpp */, BEA263642CBE38E20007435A /* StringVector.cpp */, + BE5A7AE02D354F4000FE7D60 /* Syscall.hpp */, + BE5A7AE12D354F4000FE7D60 /* Syscall.cpp */, BEA263652CBE38E20007435A /* TraceEvent.hpp */, BEA263662CBE38E20007435A /* TraceEvent.cpp */, BEA263672CBE38E20007435A /* Unit.hpp */, @@ -544,6 +549,7 @@ BEA264B32CBE99340007435A /* DocumentBroker.cpp in Sources */, BE9115AA2CECBCB200C597B2 /* SigUtil-mobile.cpp in Sources */, BEA264B42CBE99340007435A /* RequestVettingStation.cpp in Sources */, + BE5A7AE22D354F4000FE7D60 /* Syscall.cpp in Sources */, BEA263772CBE38E20007435A /* ConfigUtil.cpp in Sources */, BEA263782CBE38E20007435A /* StringVector.cpp in Sources */, BEA263792CBE38E20007435A /* Protocol.cpp in Sources */, @@ -707,9 +713,7 @@ ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu17; GCC_NO_COMMON_BLOCKS = YES; - GCC_PREPROCESSOR_DEFINITIONS = ( - "$(inherited)", - ); + GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)"; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; diff --git a/net/DelaySocket.cpp b/net/DelaySocket.cpp index ddc8a384d9ace..17863d1bd836a 100644 --- a/net/DelaySocket.cpp +++ b/net/DelaySocket.cpp @@ -11,6 +11,7 @@ #include +#include #include #include @@ -252,7 +253,7 @@ int Delay::create(int delayMs, int physicalFd) if (delayPoll && delayPoll->isAlive()) { int pair[2]; - int rc = socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, pair); + int rc = Syscall::socketpair_cloexec_nonblock(AF_UNIX, SOCK_STREAM /*| SOCK_NONBLOCK | SOCK_CLOEXEC*/, 0, pair); assert(rc == 0); (void)rc; int internalFd = pair[0]; From db6a7aa0ad38117fce1221d4a0180000f6e35604 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 13 Jan 2025 16:59:05 +0100 Subject: [PATCH 074/177] Use the configured LO_PATH in the Run Script phase, instead of a hardcoded one Signed-off-by: Jan Holesovsky Change-Id: I3f088b72c48d67958180edfdc5fb32092a4f9c99 --- macos/README.txt | 10 ++++++---- macos/coda/Config.xcconfig.in | 1 + macos/coda/coda.xcodeproj/project.pbxproj | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/macos/README.txt b/macos/README.txt index ad2ec54bed0e7..86e89a1f2700b 100644 --- a/macos/README.txt +++ b/macos/README.txt @@ -68,11 +68,13 @@ Configure Collabora Online --with-lo-path=/Users/kendy/Projects/lo/core/instdir/CollaboraOffice.app \ --with-lokit-path=/Users/kendy/Projects/lo/core/include -Obbiously you need to change the /Users/kendy/etc above to match what -you have. Also, in some cases (perhaps on Intel Macs?) homebrew gets -installed in /usr/local, not /opt/homebrew. +Obbiously you need to change the /Users/kendy/... above to match what +you have. Also, on Intel Macs homebrew gets installed in /usr/local, +not /opt/homebrew. -You also need to edit the macos/coda/coda.xcodeproj/project.pbxproj accordingly. Look for /Users/kendy and /opt/homebrew. +You may need to edit the macos/coda/coda.xcodeproj/project.pbxproj too, +particularly look for /opt/homebrew. If you also find an instance of +/Users/kendy, please report that, it's a mistake and should be fixed. Then you can build CODA-M: diff --git a/macos/coda/Config.xcconfig.in b/macos/coda/Config.xcconfig.in index 3e5afc251bde1..4db58723fbe97 100644 --- a/macos/coda/Config.xcconfig.in +++ b/macos/coda/Config.xcconfig.in @@ -12,3 +12,4 @@ HEADER_SEARCH_PATHS = "@LOKIT_PATH@" GCC_PREPROCESSOR_DEFINITIONS = "COOLWSD_CONFIGDIR=\"@COOLWSD_CONFIGDIR@\"" "COOLWSD_LOGLEVEL=\"@COOLWSD_LOGLEVEL@\"" "NUM_PRESPAWN_CHILDREN=\"@NUM_PRESPAWN_CHILDREN@\"" +LO_PATH = @LO_PATH@ diff --git a/macos/coda/coda.xcodeproj/project.pbxproj b/macos/coda/coda.xcodeproj/project.pbxproj index f2b322ea5e3c9..4a4334be9c104 100644 --- a/macos/coda/coda.xcodeproj/project.pbxproj +++ b/macos/coda/coda.xcodeproj/project.pbxproj @@ -507,7 +507,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n\nLO_PATH=/Users/kendy/Projects/lo/core/instdir/CollaboraOffice.app\necho \"Copying $LO_PATH/Contents/ to ${CONFIGURATION_BUILD_DIR}/${TARGET_NAME}.app/Contents/lokit/\"\nrsync -avz $LO_PATH/Contents/ ${CONFIGURATION_BUILD_DIR}/${TARGET_NAME}.app/Contents/lokit/\n\n"; + shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n\nif [ -z \"$LO_PATH\" ]; then\n echo \"Error: LO_PATH is not set. Please configure it in Config.xcconfig.\"\n exit 1\nfi\n\necho \"Copying $LO_PATH/Contents/ to ${CONFIGURATION_BUILD_DIR}/${TARGET_NAME}.app/Contents/lokit/\"\nrsync -avz $LO_PATH/Contents/ ${CONFIGURATION_BUILD_DIR}/${TARGET_NAME}.app/Contents/lokit/\n"; }; /* End PBXShellScriptBuildPhase section */ From 694ba75180cc4687e79d0a52da60e643fcd4f8b7 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 14 Jan 2025 09:30:19 +0100 Subject: [PATCH 075/177] Implement socket() with CLOEXEC and NONBLOCK for macOS Signed-off-by: Jan Holesovsky Change-Id: I889b46b786aabe42d01d945d3e5b60cd4d50ab81 --- common/Syscall.cpp | 17 ++++++++++++++--- common/Syscall.hpp | 5 +++++ net/NetUtil.cpp | 5 +++-- net/Socket.cpp | 9 +++++---- test/Makefile.am | 1 + 5 files changed, 28 insertions(+), 9 deletions(-) diff --git a/common/Syscall.cpp b/common/Syscall.cpp index 13bf21390e994..2c257591e0c5d 100644 --- a/common/Syscall.cpp +++ b/common/Syscall.cpp @@ -96,15 +96,26 @@ int Syscall::pipe2(int pipefd[2], int flags) #endif } +int Syscall::socket_cloexec_nonblock(int domain, int type, int protocol) { +#ifdef __linux__ + return ::socket(domain, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol); +#else + int fd = ::socket(domain, type, protocol); + if (fd < 0) + return fd; + + return set_fd_cloexec_nonblock(fd, true, true); +#endif +} + int Syscall::socketpair_cloexec_nonblock(int domain, int type, int protocol, int socket_vector[2]) { #ifdef __linux__ return ::socketpair(domain, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol, socket_vector); #else int rc = ::socketpair(domain, type, protocol, socket_vector); - if (rc < 0) { - return -1; - } + if (rc < 0) + return rc; return set_fds_cloexec_nonblock(socket_vector, true, true); #endif diff --git a/common/Syscall.hpp b/common/Syscall.hpp index 76026770159e2..8c8b9ab71e863 100644 --- a/common/Syscall.hpp +++ b/common/Syscall.hpp @@ -21,6 +21,11 @@ namespace Syscall { */ int pipe2(int pipefd[2], int flags); + /** + * Implement socket() with CLOEXEC and NONBLOCK on platforms that don't have those flags. + */ + int socket_cloexec_nonblock(int domain, int type, int protocol); + /** * Implement socket_pair() with CLOEXEC and NONBLOCK on platforms that don't have those flags. */ diff --git a/net/NetUtil.cpp b/net/NetUtil.cpp index 0ee20814f704f..fc515173d4322 100644 --- a/net/NetUtil.cpp +++ b/net/NetUtil.cpp @@ -13,6 +13,7 @@ #include "NetUtil.hpp" #include "AsyncDNS.hpp" +#include #include #include #include @@ -480,7 +481,7 @@ asyncConnect(const std::string& host, const std::string& port, const bool isSSL, { if (ai->ai_addrlen && ai->ai_addr) { - int fd = ::socket(ai->ai_addr->sa_family, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); + int fd = Syscall::socket_cloexec_nonblock(ai->ai_addr->sa_family, SOCK_STREAM /*| SOCK_NONBLOCK | SOCK_CLOEXEC*/, 0); if (fd < 0) { result = AsyncConnectResult::SocketError; @@ -574,7 +575,7 @@ connect(const std::string& host, const std::string& port, const bool isSSL, { if (ai->ai_addrlen && ai->ai_addr) { - int fd = ::socket(ai->ai_addr->sa_family, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); + int fd = Syscall::socket_cloexec_nonblock(ai->ai_addr->sa_family, SOCK_STREAM /*| SOCK_NONBLOCK | SOCK_CLOEXEC*/, 0); if (fd < 0) { LOG_SYS("Failed to create socket"); diff --git a/net/Socket.cpp b/net/Socket.cpp index 88a649baee061..a213930160dfb 100644 --- a/net/Socket.cpp +++ b/net/Socket.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -126,7 +127,7 @@ int Socket::createSocket([[maybe_unused]] Socket::Type type) default: assert(!"Unknown Socket::Type"); break; } - return ::socket(domain, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); + return Syscall::socket_cloexec_nonblock(domain, SOCK_STREAM /*| SOCK_NONBLOCK | SOCK_CLOEXEC*/, 0); #else return fakeSocketSocket(); #endif @@ -189,7 +190,7 @@ bool StreamSocket::socketpair(const std::chrono::steady_clock::time_point creati std::shared_ptr& child) { int pair[2]; - int rc = ::socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, pair); + int rc = Syscall::socketpair_cloexec_nonblock(AF_UNIX, SOCK_STREAM /*| SOCK_NONBLOCK | SOCK_CLOEXEC*/, 0, pair); if (rc != 0) return false; child = std::make_shared("save-child", pair[0], Socket::Type::Unix, true, HostType::Other, ReadType::NormalRead, creationTime); @@ -863,7 +864,7 @@ void SocketPoll::createWakeups() // Create the wakeup fd. if ( #if !MOBILEAPP - ::pipe2(_wakeup, O_CLOEXEC | O_NONBLOCK) == -1 + Syscall::pipe2(_wakeup, O_CLOEXEC | O_NONBLOCK) == -1 #else fakeSocketPipe2(_wakeup) == -1 #endif @@ -949,7 +950,7 @@ bool SocketPoll::insertNewUnixSocket( const std::vector* shareFDs) { LOG_DBG("Connecting to local UDS " << location); - const int fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); + const int fd = Syscall::socket_cloexec_nonblock(AF_UNIX, SOCK_STREAM /*| SOCK_NONBLOCK | SOCK_CLOEXEC*/, 0); if (fd < 0) { LOG_SYS("Failed to connect to unix socket at " << location); diff --git a/test/Makefile.am b/test/Makefile.am index bd3570dacdda4..39bc814c26e82 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -173,6 +173,7 @@ common_sources = \ ../common/SigUtil-server.cpp \ ../common/Simd.cpp \ ../common/SpookyV2.cpp \ + ../common/Syscall.cpp \ ../common/StringVector.cpp \ ../common/TraceEvent.cpp \ ../common/Unit.cpp \ From 1114d029251b0a7adbbcd1b721b4c8519326d547 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 6 Jan 2026 18:01:57 +0100 Subject: [PATCH 076/177] iOS: NetUtil.* shouldn't be needed for the app Signed-off-by: Jan Holesovsky Change-Id: I31e5ca62d5bcf150742a4b7045d1d889f4ca545a --- ios/Mobile.xcodeproj/project.pbxproj | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/ios/Mobile.xcodeproj/project.pbxproj b/ios/Mobile.xcodeproj/project.pbxproj index c75f13cb16663..5e815bcd2e87b 100644 --- a/ios/Mobile.xcodeproj/project.pbxproj +++ b/ios/Mobile.xcodeproj/project.pbxproj @@ -11,7 +11,6 @@ 1FCFA28A2B2AF13F007EE2DF /* coolwsd-fork.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1FCFA2892B2AF13C007EE2DF /* coolwsd-fork.cpp */; }; 3F3A77D22C59B04000947249 /* global.js in Resources */ = {isa = PBXBuildFile; fileRef = 3F3A77D12C59B04000947249 /* global.js */; }; 3F3B54DD2A3928D100063C01 /* HttpRequest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3F3B54DB2A39288500063C01 /* HttpRequest.cpp */; }; - 3F3B54E02A392CCB00063C01 /* NetUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3F3B54DE2A392C9C00063C01 /* NetUtil.cpp */; }; A5C2FA5A2AC1BB3900265946 /* Simd.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5C2FA592AC1BB3800265946 /* Simd.cpp */; }; A5C2FA5D2AC1BEC500265946 /* DeltaSimd.c in Sources */ = {isa = PBXBuildFile; fileRef = A5C2FA5B2AC1BEC500265946 /* DeltaSimd.c */; }; BE00F8A021396585001CE2D4 /* cool.html in Resources */ = {isa = PBXBuildFile; fileRef = BE00F89621396585001CE2D4 /* cool.html */; }; @@ -40,9 +39,9 @@ BE5EB5CF213FE2D000E0826C /* ClientSession.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5EB5CC213FE2D000E0826C /* ClientSession.cpp */; }; BE5EB5D0213FE2D000E0826C /* TileCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5EB5CD213FE2D000E0826C /* TileCache.cpp */; }; BE5EB5D22140039100E0826C /* COOLWSD.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5EB5D12140039100E0826C /* COOLWSD.cpp */; }; + BE5EB5D22140039100E0826D /* ClientRequestDispatcher.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5EB5D12140039100E0826D /* ClientRequestDispatcher.cpp */; }; BE5EB5D22140039100E0836C /* KitWSDGlobals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5EB5D12140039100E0836C /* KitWSDGlobals.cpp */; }; BE5EB5D22140039101E0927D /* dumpWsdState.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5EB5D12140039110E0836F /* dumpWsdState.cpp */; }; - BE5EB5D22140039100E0826D /* ClientRequestDispatcher.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5EB5D12140039100E0826D /* ClientRequestDispatcher.cpp */; }; BE5EB5D421400DC100E0826C /* DocumentBroker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5EB5D321400DC100E0826C /* DocumentBroker.cpp */; }; BE5EB5D621401E0F00E0826C /* Storage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5EB5D521401E0F00E0826C /* Storage.cpp */; }; BE5EB5DA2140363100E0826C /* ios.mm in Sources */ = {isa = PBXBuildFile; fileRef = BE5EB5D92140363100E0826C /* ios.mm */; }; @@ -116,8 +115,6 @@ 3F3A77D12C59B04000947249 /* global.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = global.js; path = ../../../browser/dist/global.js; sourceTree = ""; }; 3F3B54DB2A39288500063C01 /* HttpRequest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HttpRequest.cpp; sourceTree = ""; }; 3F3B54DC2A39288500063C01 /* HttpRequest.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = HttpRequest.hpp; sourceTree = ""; }; - 3F3B54DE2A392C9C00063C01 /* NetUtil.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NetUtil.cpp; sourceTree = ""; }; - 3F3B54DF2A392C9C00063C01 /* NetUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = NetUtil.hpp; sourceTree = ""; }; 3F3B54DF2A392C9C00063C02 /* Uri.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Uri.hpp; sourceTree = ""; }; 92414564BE942221FB823CF9 /* AsyncDNS.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = AsyncDNS.hpp; sourceTree = ""; }; A5C2FA582AC1BB3800265946 /* Simd.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Simd.hpp; sourceTree = ""; }; @@ -619,9 +616,9 @@ BE5EB5CC213FE2D000E0826C /* ClientSession.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ClientSession.cpp; sourceTree = ""; }; BE5EB5CD213FE2D000E0826C /* TileCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TileCache.cpp; sourceTree = ""; }; BE5EB5D12140039100E0826C /* COOLWSD.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = COOLWSD.cpp; sourceTree = ""; }; + BE5EB5D12140039100E0826D /* ClientRequestDispatcher.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ClientRequestDispatcher.cpp; sourceTree = ""; }; BE5EB5D12140039100E0836C /* KitWSDGlobals.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = KitWSDGlobals.cpp; sourceTree = ""; }; BE5EB5D12140039110E0836F /* dumpWsdState.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dumpWsdState.cpp; sourceTree = ""; }; - BE5EB5D12140039100E0826D /* ClientRequestDispatcher.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ClientRequestDispatcher.cpp; sourceTree = ""; }; BE5EB5D321400DC100E0826C /* DocumentBroker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DocumentBroker.cpp; sourceTree = ""; }; BE5EB5D521401E0F00E0826C /* Storage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Storage.cpp; sourceTree = ""; }; BE5EB5D92140363100E0826C /* ios.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ios.mm; path = ../../ios/ios.mm; sourceTree = ""; }; @@ -3012,8 +3009,6 @@ 92414564BE942221FB823CF9 /* AsyncDNS.hpp */, 3F3B54DB2A39288500063C01 /* HttpRequest.cpp */, 3F3B54DC2A39288500063C01 /* HttpRequest.hpp */, - 3F3B54DE2A392C9C00063C01 /* NetUtil.cpp */, - 3F3B54DF2A392C9C00063C01 /* NetUtil.hpp */, 3F3B54DF2A392C9C00063C02 /* Uri.hpp */, BEA2835C21498AD400848631 /* Socket.cpp */, BEA2835E214A8E2000848631 /* Socket.hpp */, @@ -3778,12 +3773,11 @@ BE980C592CEB557A00FED7BC /* FileUtil-apple.mm in Sources */, BE5EB5D22140039100E0826C /* COOLWSD.cpp in Sources */, BE5EB5D22140039100E0836C /* KitWSDGlobals.cpp in Sources */, - BE5EB5D22140039101E0927D /* dumpWsdState.cpp in Sources */, + BE5EB5D22140039101E0927D /* dumpWsdState.cpp in Sources */, BE5EB5D22140039100E0826D /* ClientRequestDispatcher.cpp in Sources */, BEFB1EE121C29CC70081D757 /* L10n.mm in Sources */, BEDCC8992456FFAD00FB02BD /* SceneDelegate.mm in Sources */, BE5EB5C6213FE29900E0826C /* SigUtil-dummy.cpp in Sources */, - 3F3B54E02A392CCB00063C01 /* NetUtil.cpp in Sources */, BE5EB5C1213FE29900E0826C /* Log.cpp in Sources */, A5C2FA5A2AC1BB3900265946 /* Simd.cpp in Sources */, BEDCC84E2452F82800FB02BD /* MobileApp.cpp in Sources */, From 801dddff1e730ce55c5367edf0e8d3b8c3dd4624 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Tue, 14 Jan 2025 12:34:55 +0200 Subject: [PATCH 077/177] Adapt to the different Homebrew locations on Intel vs Apple Silicon Mac Signed-off-by: Tor Lillqvist Change-Id: Ia4093aabe3355f1d44b1a978ff27c46222ca7caa --- configure.ac | 9 +++++++++ macos/README.txt | 5 ++--- macos/coda/Config.xcconfig.in | 1 + macos/coda/coda.xcodeproj/project.pbxproj | 8 ++++---- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/configure.ac b/configure.ac index 85b044712bb23..df1311f339714 100644 --- a/configure.ac +++ b/configure.ac @@ -2110,6 +2110,15 @@ if test "$enable_iosapp" = "yes"; then fi if test "$enable_macosapp" = "yes"; then + # Homebrew uses different paths on Intel and Apple Silicon macOS. + # Having a separate /opt/homebrew makes more sense, but I guess + # backward compatibility keeps it as /usr/local on Intel Macs. + if test `uname -m` = "x86_64"; then + HOMEBREW_PATH=/usr/local + else + HOMEBREW_PATH=/opt/homebrew + fi + AC_SUBST(HOMEBREW_PATH) AC_CONFIG_FILES([macos/coda/Config.xcconfig]) fi diff --git a/macos/README.txt b/macos/README.txt index 86e89a1f2700b..e3978819c5fbf 100644 --- a/macos/README.txt +++ b/macos/README.txt @@ -72,9 +72,8 @@ Obbiously you need to change the /Users/kendy/... above to match what you have. Also, on Intel Macs homebrew gets installed in /usr/local, not /opt/homebrew. -You may need to edit the macos/coda/coda.xcodeproj/project.pbxproj too, -particularly look for /opt/homebrew. If you also find an instance of -/Users/kendy, please report that, it's a mistake and should be fixed. +If you find an instance of /Users/kendy hardcoded somewhere, please +report that, it's a mistake and should be fixed. Then you can build CODA-M: diff --git a/macos/coda/Config.xcconfig.in b/macos/coda/Config.xcconfig.in index 4db58723fbe97..671b1ae7138f5 100644 --- a/macos/coda/Config.xcconfig.in +++ b/macos/coda/Config.xcconfig.in @@ -10,6 +10,7 @@ // Configuration settings file format documentation can be found at: // https://help.apple.com/xcode/#/dev745c5c974 +HOMEBREW_PATH = "@HOMEBREW_PATH@" HEADER_SEARCH_PATHS = "@LOKIT_PATH@" GCC_PREPROCESSOR_DEFINITIONS = "COOLWSD_CONFIGDIR=\"@COOLWSD_CONFIGDIR@\"" "COOLWSD_LOGLEVEL=\"@COOLWSD_LOGLEVEL@\"" "NUM_PRESPAWN_CHILDREN=\"@NUM_PRESPAWN_CHILDREN@\"" LO_PATH = @LO_PATH@ diff --git a/macos/coda/coda.xcodeproj/project.pbxproj b/macos/coda/coda.xcodeproj/project.pbxproj index 4a4334be9c104..07b8cd68f4c08 100644 --- a/macos/coda/coda.xcodeproj/project.pbxproj +++ b/macos/coda/coda.xcodeproj/project.pbxproj @@ -649,9 +649,9 @@ "$(SRCROOT)/../../kit", "$(SRCROOT)/../../net", "$(SRCROOT)/../../wsd", - /opt/homebrew/include, + "$(HOMEBREW_PATH)/include", ); - LIBRARY_SEARCH_PATHS = /opt/homebrew/lib; + LIBRARY_SEARCH_PATHS = "$(HOMEBREW_PATH)/lib"; LOCALIZATION_PREFERS_STRING_CATALOGS = YES; MACOSX_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; @@ -729,9 +729,9 @@ "$(SRCROOT)/../../kit", "$(SRCROOT)/../../net", "$(SRCROOT)/../../wsd", - /opt/homebrew/include, + "$(HOMEBREW_PATH)/include", ); - LIBRARY_SEARCH_PATHS = /opt/homebrew/lib; + LIBRARY_SEARCH_PATHS = "$(HOMEBREW_PATH)/lib"; LOCALIZATION_PREFERS_STRING_CATALOGS = YES; MACOSX_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = NO; From 840c5e8d541d7a5fe9146d9083f9cfbf6bf7102d Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 14 Jan 2025 11:56:08 +0100 Subject: [PATCH 078/177] Implement accept() with CLOEXEC and NONBLOCK for macOS Signed-off-by: Jan Holesovsky Change-Id: Ie1f4791a1a386054400017bcbed0ee0b031da5cb --- common/Syscall.cpp | 33 +++++++++++++++++++++++++++++++-- common/Syscall.hpp | 7 +++++++ net/Socket.cpp | 4 ++-- 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/common/Syscall.cpp b/common/Syscall.cpp index 2c257591e0c5d..c0dfacf5117f6 100644 --- a/common/Syscall.cpp +++ b/common/Syscall.cpp @@ -31,8 +31,10 @@ namespace { /** * Set FD_CLOEXEC and O_NONBLOCK on one file descriptor. + * + * Called "unsafe" because it keeps the file descriptor open on error, possibly leading to leaks. */ -int set_fd_cloexec_nonblock(int fd, bool cloexec, bool nonblock) { +int unsafe_set_fd_cloexec_nonblock(int fd, bool cloexec, bool nonblock) { // Set FD_CLOEXEC if the user wants it if (cloexec) { @@ -60,12 +62,26 @@ int set_fd_cloexec_nonblock(int fd, bool cloexec, bool nonblock) { return 0; } +/** + * Set FD_CLOEXEC and O_NONBLOCK on one file descriptor. + */ +int set_fd_cloexec_nonblock(int fd, bool cloexec, bool nonblock) { + int ret = unsafe_set_fd_cloexec_nonblock(fd, cloexec, nonblock); + if (ret < 0) { + int saved_errno = errno; + close(fd); + errno = saved_errno; + } + + return ret; +} + /** * Set CLOEXEC or NONBLOCK on both sides of the pipe/socket/... */ int set_fds_cloexec_nonblock(int fds[2], bool cloexec, bool nonblock) { for (int i = 0; i < 2; i++) { - int ret = set_fd_cloexec_nonblock(fds[i], cloexec, nonblock); + int ret = unsafe_set_fd_cloexec_nonblock(fds[i], cloexec, nonblock); if (ret < 0) { int saved_errno = errno; close(fds[0]); @@ -83,6 +99,19 @@ int set_fds_cloexec_nonblock(int fds[2], bool cloexec, bool nonblock) { } +int Syscall::accept_cloexec_nonblock(int socket, struct sockaddr *address, socklen_t *address_len) +{ +#if defined(__linux__) + return accept4(socket, address, address_len, SOCK_CLOEXEC | SOCK_NONBLOCK); +#else + int fd = ::accept(socket, address, address_len); + if (fd < 0) + return fd; + + return set_fd_cloexec_nonblock(fd, true, true); +#endif +} + /// Implementation of pipe2() for platforms that don't have it (like macOS) int Syscall::pipe2(int pipefd[2], int flags) { diff --git a/common/Syscall.hpp b/common/Syscall.hpp index 8c8b9ab71e863..ce8b4c62e3eae 100644 --- a/common/Syscall.hpp +++ b/common/Syscall.hpp @@ -11,11 +11,18 @@ #pragma once +#include + /** * This is a place for platform-dependent syscalls, to be able to extend them conveniently. */ namespace Syscall { + /** + * Implement an equivalent of accept4() with CLOEXEC and NONBLOCK set. + */ + int accept_cloexec_nonblock(int socket, struct sockaddr *address, socklen_t *address_len); + /** * Implement pipe2() on platforms that don't have it. */ diff --git a/net/Socket.cpp b/net/Socket.cpp index a213930160dfb..4c408efdfe545 100644 --- a/net/Socket.cpp +++ b/net/Socket.cpp @@ -1310,7 +1310,7 @@ std::shared_ptr ServerSocket::accept() struct sockaddr_in6 clientInfo; socklen_t addrlen = sizeof(clientInfo); - const int rc = ::accept4(getFD(), (struct sockaddr *)&clientInfo, &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC); + const int rc = Syscall::accept_cloexec_nonblock(getFD(), (struct sockaddr *)&clientInfo, &addrlen); if (rc < 0) { if (isUnrecoverableAcceptError(errno)) @@ -1416,7 +1416,7 @@ bool Socket::isLocal() const std::shared_ptr LocalServerSocket::accept() { - const int rc = ::accept4(getFD(), nullptr, nullptr, SOCK_NONBLOCK | SOCK_CLOEXEC); + const int rc = Syscall::accept_cloexec_nonblock(getFD(), nullptr, nullptr); if (rc < 0) { if (isUnrecoverableAcceptError(errno)) From cb8b8dcc3a7948ed31df58c353c73a94b9ad4a2b Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 14 Jan 2025 13:13:55 +0100 Subject: [PATCH 079/177] Adapt the getsockopt() calls for macOS Signed-off-by: Jan Holesovsky Change-Id: If3e4206de1d434ec2aa81a9970892eec2ca81802 --- common/Syscall.cpp | 32 ++++++++++++++++++++++++ common/Syscall.hpp | 5 ++++ net/Socket.cpp | 61 +++++++++++++++++++++++++++++----------------- 3 files changed, 76 insertions(+), 22 deletions(-) diff --git a/common/Syscall.cpp b/common/Syscall.cpp index c0dfacf5117f6..f037ace54b46d 100644 --- a/common/Syscall.cpp +++ b/common/Syscall.cpp @@ -15,6 +15,9 @@ #include #include +#ifndef _WIN32 +#include +#endif #if !HAVE_PIPE2 #include @@ -112,6 +115,35 @@ int Syscall::accept_cloexec_nonblock(int socket, struct sockaddr *address, sockl #endif } +int Syscall::get_peer_pid(int socket) { +#ifdef __linux__ + struct ucred creds; + socklen_t credSize = sizeof(struct ucred); + if (getsockopt(socket, SOL_SOCKET, SO_PEERCRED, &creds, &credSize) < 0) + return -1; + + return creds.pid; +#elif defined(__FreeBSD__) + struct xucred creds; + socklen_t credSize = sizeof(struct xucred); + if (getsockopt(socket, SOL_LOCAL, LOCAL_PEERCRED, &creds, &credSize) < 0) + return -1; + + return creds.cr_pid; +#elif defined(__APPLE__) + int pid = -1; + socklen_t pidLen = sizeof(pid); + + // Retrieve the PID of the peer connected on this Unix-domain socket + if (getsockopt(socket, SOL_LOCAL, LOCAL_PEERPID, &pid, &pidLen) < 0) + return -1; + + return pid; +#else +#error Implement for your platform +#endif +} + /// Implementation of pipe2() for platforms that don't have it (like macOS) int Syscall::pipe2(int pipefd[2], int flags) { diff --git a/common/Syscall.hpp b/common/Syscall.hpp index ce8b4c62e3eae..a0ba3d8bcdede 100644 --- a/common/Syscall.hpp +++ b/common/Syscall.hpp @@ -23,6 +23,11 @@ namespace Syscall { */ int accept_cloexec_nonblock(int socket, struct sockaddr *address, socklen_t *address_len); + /** + * Retrieve the PID of the peer connected on this Unix-domain socket. + */ + int get_peer_pid(int socket); + /** * Implement pipe2() on platforms that don't have it. */ diff --git a/net/Socket.cpp b/net/Socket.cpp index 4c408efdfe545..5556ad92468e4 100644 --- a/net/Socket.cpp +++ b/net/Socket.cpp @@ -1378,27 +1378,11 @@ std::shared_ptr ServerSocket::accept() int Socket::getPid() const { -#ifdef __linux__ - struct ucred creds; - socklen_t credSize = sizeof(struct ucred); - if (getsockopt(_fd, SOL_SOCKET, SO_PEERCRED, &creds, &credSize) < 0) - { - LOG_SYS("Failed to get pid via peer creds on " << _fd); - return -1; - } - return creds.pid; -#elif defined(__FreeBSD__) - struct xucred creds; - socklen_t credSize = sizeof(struct xucred); - if (getsockopt(_fd, SOL_LOCAL, LOCAL_PEERCRED, &creds, &credSize) < 0) - { + int pid = Syscall::get_peer_pid(_fd); + if (pid < 0) LOG_SYS("Failed to get pid via peer creds on " << _fd); - return -1; - } - return creds.cr_pid; -#else -#error Implement for your platform -#endif + + return pid; } // Does this socket come from the localhost ? @@ -1429,7 +1413,7 @@ std::shared_ptr LocalServerSocket::accept() std::shared_ptr _socket = createSocketFromAccept(rc, Socket::Type::Unix); // Sanity check this incoming socket -#ifndef __FreeBSD__ +#ifdef __linux__ #define CREDS_UID(c) c.uid #define CREDS_GID(c) c.gid #define CREDS_PID(c) c.pid @@ -1441,7 +1425,7 @@ std::shared_ptr LocalServerSocket::accept() ::close(rc); return std::shared_ptr(nullptr); } -#else +#elif defined(__FreeBSD__) #define CREDS_UID(c) c.cr_uid #define CREDS_GID(c) c.cr_groups[0] #define CREDS_PID(c) c.cr_pid @@ -1453,6 +1437,39 @@ std::shared_ptr LocalServerSocket::accept() ::close(rc); return std::shared_ptr(nullptr); } +#elif defined(__APPLE__) + + // On macOS, there's no single struct for all three, + // so define our own 'apple_creds' combining UID/GID/PID. + struct apple_creds { + uid_t uid; + gid_t gid; + pid_t pid; + } creds; + + // Macros to unify usage in the rest of the code: + #define CREDS_UID(c) ((c).uid) + #define CREDS_GID(c) ((c).gid) + #define CREDS_PID(c) ((c).pid) + + // Get the effective UID/GID via getpeereid(): + if (getpeereid(rc, &creds.uid, &creds.gid) != 0) + { + LOG_SYS("Failed to get peer creds (uid/gid) on " << rc); + ::close(rc); + return std::shared_ptr(nullptr); + } + + // Get the peer PID via LOCAL_PEERPID: + socklen_t pidLen = sizeof(creds.pid); + if (getsockopt(rc, SOL_LOCAL, LOCAL_PEERPID, &creds.pid, &pidLen) < 0) + { + LOG_SYS("Failed to get peer pid on " << rc); + ::close(rc); + return std::shared_ptr(nullptr); + } +#else +#error Implement for your platform #endif uid_t uid = getuid(); From d26c912580afee6605b4a45ad8c6fca417e008ad Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 14 Jan 2025 13:22:13 +0100 Subject: [PATCH 080/177] Obtaining the current thread ID for macOS Signed-off-by: Jan Holesovsky Change-Id: Ie517e7ba571c491c277aa85e2d60f31b80cc0234 --- net/Ssl.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/Ssl.cpp b/net/Ssl.cpp index 6336a23af4843..db38578f650c8 100644 --- a/net/Ssl.cpp +++ b/net/Ssl.cpp @@ -235,6 +235,10 @@ unsigned long SslContext::id() return syscall(SYS_gettid); #elif defined(__FreeBSD__) return pthread_getthreadid_np(); +#elif defined(__APPLE__) + uint64_t tid = 0; + pthread_threadid_np(NULL, &tid); + return tid; #else #error Implement for your platform #endif From 95b96ae0269e85265fcfa3d5e859e5e0464f650b Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 14 Jan 2025 13:58:46 +0100 Subject: [PATCH 081/177] Update linker flags for macOS Signed-off-by: Jan Holesovsky Change-Id: Ic9dc870a66e29fe7eaaae2d2788688dda9bf9235 --- Makefile.am | 7 ++++++- configure.ac | 9 ++++++++- tools/map.cpp | 2 +- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/Makefile.am b/Makefile.am index 0c687451e418d..bf3960e214f58 100644 --- a/Makefile.am +++ b/Makefile.am @@ -106,7 +106,12 @@ if !ENABLE_DEBUG AM_CPPFLAGS += -DNDEBUG endif -AM_LDFLAGS = -Wl,-E -lpam $(ZLIB_LIBS) $(ZSTD_LIBS) ${PNG_LIBS} +AM_LDFLAGS = -lpam $(ZLIB_LIBS) $(ZSTD_LIBS) ${PNG_LIBS} +if !ENABLE_MACOS +AM_LDFLAGS += -Wl,-E +else +AM_LDFLAGS += -lzstd -lpng +endif # Clang's linker doesn't like -pthread. if !HAVE_CLANG diff --git a/configure.ac b/configure.ac index df1311f339714..099b13307c51e 100644 --- a/configure.ac +++ b/configure.ac @@ -1044,12 +1044,18 @@ AC_SUBST(IOSAPP_BUNDLE_VERSION) # We want this to be general, regardless of using --enable-macosapp, and it # could be potentially extended to handle the other defines like IOS, WASMAPP # or _WINDOWS (but at least iOS and Windows are using their own config.h) +ENABLE_MACOS= case "$host_os" in darwin*) + ENABLE_MACOS=true AC_DEFINE([MACOS], [1], [Define to 1 if building for macOS]) ;; esac +# Are we building on macOS at all, but eg. only the coolwsd? +AC_SUBST(ENABLE_MACOS) +AM_CONDITIONAL([ENABLE_MACOS], [test "$ENABLE_MACOS" = "true"]) + ENABLE_MACOSAPP= #MACOSAPP_BUNDLE_VERSION= @@ -1064,6 +1070,7 @@ if test "$enable_macosapp" = "yes"; then #echo $MACOSAPP_BUNDLE_VERSION >BUNDLE-VERSION fi +# Are we building the macOS CODA? AC_SUBST(ENABLE_MACOSAPP) AM_CONDITIONAL([ENABLE_MACOSAPP], [test "$ENABLE_MACOSAPP" = "true"]) #AC_SUBST(MACOSAPP_BUNDLE_VERSION) @@ -1469,7 +1476,7 @@ AS_IF([test `uname -s` != Darwin], [], [AC_MSG_ERROR([dlopen not found])])]) -AS_IF([test "$ENABLE_IOSAPP" != "true" -a "$ENABLE_MACOSAPP" != "true" -a "$ENABLE_ANDROIDAPP" != "true" -a "$host_os" != "emscripten"], +AS_IF([test "$ENABLE_IOSAPP" != "true" -a "$ENABLE_ANDROIDAPP" != "true" -a "$host_os" != "emscripten"], [PKG_CHECK_MODULES([PNG], [libpng]) dnl deflated HTTP / web-page serving PKG_CHECK_MODULES([ZLIB], [zlib]) diff --git a/tools/map.cpp b/tools/map.cpp index 2c01253621cf7..3f28ffe7930f1 100644 --- a/tools/map.cpp +++ b/tools/map.cpp @@ -24,7 +24,7 @@ #include #include #include -#ifndef __FreeBSD__ +#ifdef __linux__ #include #endif #include From 7b4c083ffa0a6597cf4a11a0e165c14d56233581 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 14 Jan 2025 14:20:35 +0100 Subject: [PATCH 082/177] Temporarily don't check the disk space in the macOS coolwsd Signed-off-by: Jan Holesovsky Change-Id: I6c3707e98e103791295e1523b65e2e0550d7162f --- common/FileUtil-unix.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/common/FileUtil-unix.cpp b/common/FileUtil-unix.cpp index 045522adb2840..6fddbfa929d2b 100644 --- a/common/FileUtil-unix.cpp +++ b/common/FileUtil-unix.cpp @@ -89,6 +89,13 @@ namespace FileUtil return false; #endif + return true; + } +#elif defined(MACOS) && !MOBILEAPP + + bool platformDependentCheckDiskSpace(const std::string&, int64_t) + { + // FIXME Use the FileUtil-apple.mm instead return true; } #endif From 6ccf72d7fdc3830456dfed2f7510790e52c8661b Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 14 Jan 2025 14:21:21 +0100 Subject: [PATCH 083/177] Fix linking on macOS Signed-off-by: Jan Holesovsky Change-Id: I93a8896edcd2e8c162bdf87758d74e499113e712 --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index bf3960e214f58..73da385e6c37a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -110,7 +110,7 @@ AM_LDFLAGS = -lpam $(ZLIB_LIBS) $(ZSTD_LIBS) ${PNG_LIBS} if !ENABLE_MACOS AM_LDFLAGS += -Wl,-E else -AM_LDFLAGS += -lzstd -lpng +AM_LDFLAGS += -lz -lzstd -lpng endif # Clang's linker doesn't like -pthread. From 836c88efff5b54e7deea40b1fe4e79bc38c07560 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Mon, 24 Mar 2025 15:34:43 +0200 Subject: [PATCH 084/177] Syscall.hpp is not for the MOBILEAPP case, and does not compile on Windows Signed-off-by: Tor Lillqvist Change-Id: Ie9312c57d322b92dfded3290bedf9cfd3d685f6e --- net/Socket.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/Socket.cpp b/net/Socket.cpp index 5556ad92468e4..c77cae69f4bd9 100644 --- a/net/Socket.cpp +++ b/net/Socket.cpp @@ -17,7 +17,9 @@ #include #include #include +#if !MOBILEAPP #include +#endif #include #include #include From 5d9a1fd4136d9a70ae8cbb75587bcc42d8d553a4 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 14 Jan 2025 14:44:56 +0100 Subject: [PATCH 085/177] This is mobileapp-only Signed-off-by: Jan Holesovsky Change-Id: Ida9fbba7aa485e8d5662b27b48fe187922e99963 --- wsd/Storage.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/wsd/Storage.cpp b/wsd/Storage.cpp index 38a682b9f454c..f3a7aa00a5d64 100644 --- a/wsd/Storage.cpp +++ b/wsd/Storage.cpp @@ -48,6 +48,7 @@ #include #include +#if MOBILEAPP #ifdef IOS #include #elif defined(MACOS) @@ -58,7 +59,10 @@ #include "windows.hpp" #elif defined(GTKAPP) #include "gtk.hpp" -#endif // IOS +#elif WASMAPP +#include "wasmapp.hpp" +#endif +#endif // MOBILEAPP #if ENABLE_LOCAL_FILESYSTEM bool StorageBase::FilesystemEnabled; From 06947d2d585c8fc9d235be86fa075fd56dcaa9ee Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 14 Jan 2025 15:03:19 +0100 Subject: [PATCH 086/177] Fix build on macOS Signed-off-by: Jan Holesovsky Change-Id: I6d1006be23e951129fb062dbe14288a227e34e93 --- tools/map.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/map.cpp b/tools/map.cpp index 3f28ffe7930f1..531cf6b7bc75f 100644 --- a/tools/map.cpp +++ b/tools/map.cpp @@ -38,7 +38,7 @@ #include #include -#ifdef __FreeBSD__ +#ifndef __linux__ void error(int status, int errnum, const char *format, ...) { va_list args; @@ -517,7 +517,7 @@ static std::vector compressBitmap(const std::vector &bitmap) { char num[16]; output.push_back('['); - sprintf(num, "%d", cnt); + snprintf(num, sizeof(num), "%d", cnt); for (int cpy = 0; num[cpy] != '\0'; ++cpy) output.push_back(num[cpy]); output.push_back(']'); From f5daea32d9f987c405c6b877326d6956c172b773 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 14 Jan 2025 15:04:35 +0100 Subject: [PATCH 087/177] We need libiconv for linking too Signed-off-by: Jan Holesovsky Change-Id: Iea1509fc12caecc353a2d09f3cff4813a57ec5da --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 73da385e6c37a..2826828192cd6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -110,7 +110,7 @@ AM_LDFLAGS = -lpam $(ZLIB_LIBS) $(ZSTD_LIBS) ${PNG_LIBS} if !ENABLE_MACOS AM_LDFLAGS += -Wl,-E else -AM_LDFLAGS += -lz -lzstd -lpng +AM_LDFLAGS += -lz -lzstd -lpng -liconv endif # Clang's linker doesn't like -pthread. From a5dfb43e719f98bade2554711cbc428d8d5db0f2 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 14 Jan 2025 15:21:51 +0100 Subject: [PATCH 088/177] It turns out pkg-config was explicitly disabled on macOS Enable it again, and remove hacks from Makefile.am. Don't check for iconv on Linux. It is in glibc. This probably breaks on non-glibc Linux. Signed-off-by: Jan Holesovsky Change-Id: I30c2bf7461dd0b8a3cb4e966ff68637b054d8e3f --- Makefile.am | 2 -- configure.ac | 8 ++++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Makefile.am b/Makefile.am index 2826828192cd6..79276481036f0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -109,8 +109,6 @@ endif AM_LDFLAGS = -lpam $(ZLIB_LIBS) $(ZSTD_LIBS) ${PNG_LIBS} if !ENABLE_MACOS AM_LDFLAGS += -Wl,-E -else -AM_LDFLAGS += -lz -lzstd -lpng -liconv endif # Clang's linker doesn't like -pthread. diff --git a/configure.ac b/configure.ac index 099b13307c51e..6648db98aed11 100644 --- a/configure.ac +++ b/configure.ac @@ -11,7 +11,9 @@ AM_INIT_AUTOMAKE([1.10 foreign subdir-objects tar-pax -Wno-portability]) AC_CONFIG_MACRO_DIR([m4]) # We don't want to require pkg-config and PKG_CHECK_MODULES on macOS -m4_if(m4_esyscmd_s([uname -s]),Darwin,[m4_define([PKG_CHECK_MODULES],[])],[]) +# It may be missing, and then we'd generate broken shell code; but +# let's guard against accidental use. +m4_if(m4_esyscmd_s([uname -s]),Darwin,[m4_define([PKG_CHECK_MODULES],[AC_MSG_ERROR([It's not expected to use [PKG_CHECK_MODULES] on macOS, please fix configure.ac and make pkg-config a requirement if you really need it.])])],[]) COOLWSD_VERSION_MAJOR=`echo $VERSION | awk -F. '{print $1}'` COOLWSD_VERSION_MINOR=`echo $VERSION | awk -F. '{print $2}'` @@ -1749,7 +1751,9 @@ AS_IF([test `uname -s` = "Linux" -o `uname -s` = "FreeBSD" -o `uname -s` = "Darw ]) AS_IF([test `uname -s` = "FreeBSD"], - AC_CHECK_LIB(iconv, libiconv_open, [], [AC_MSG_ERROR([No. Install 3rd-party libiconv.])])) + [AC_CHECK_LIB(iconv, libiconv_open, [], [AC_MSG_ERROR([No. Install 3rd-party libiconv.])])], + [AS_IF([test `uname -s` = "Darwin" -a "$ENABLE_IOSAPP" != "true"], + [AC_CHECK_LIB(iconv, iconv_open, [], [AC_MSG_ERROR([No, please install libiconv.])])])]) AS_IF([test `uname -s` = "FreeBSD"], [LIBS="$LIBS -lexecinfo -lz -liconv"]) From 17b71e57b0d52c4a264e9022e6a8189ed46b2dad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hubert=20Figui=C3=A8re?= Date: Wed, 15 Jan 2025 12:38:19 -0500 Subject: [PATCH 089/177] Syscall: Cleaner way to not build unecessary code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit tml: The Syscall.hpp and cpp files are not supposed to be compiled in the MOBILEAPP case so we don't need ifdefs for non-Unixy platforms in them. Explicitly make sure to error out if they still get compiled for MOBILEAPP to catch such confusion early. Signed-off-by: Hubert Figuière Change-Id: Ia45572134d3165e289498bd8dececa44688ee9c7 --- common/Syscall.cpp | 19 +++++++++---------- common/Syscall.hpp | 4 ++++ 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/common/Syscall.cpp b/common/Syscall.cpp index f037ace54b46d..ffd684a8f9900 100644 --- a/common/Syscall.cpp +++ b/common/Syscall.cpp @@ -11,26 +11,26 @@ #include +#if MOBILEAPP +#error This file is not supposed to be compiled in the MOBILEAPP case +#endif + #include "Syscall.hpp" #include -#include -#ifndef _WIN32 -#include -#endif -#if !HAVE_PIPE2 #include -#else #include -#endif +#include +#include + /** * Internal helper functions. */ +#if !defined(__linux__) namespace { -#if !HAVE_PIPE2 /** * Set FD_CLOEXEC and O_NONBLOCK on one file descriptor. @@ -98,9 +98,8 @@ int set_fds_cloexec_nonblock(int fds[2], bool cloexec, bool nonblock) { return 0; } -#endif - } +#endif int Syscall::accept_cloexec_nonblock(int socket, struct sockaddr *address, socklen_t *address_len) { diff --git a/common/Syscall.hpp b/common/Syscall.hpp index a0ba3d8bcdede..5dd2aaaba23ff 100644 --- a/common/Syscall.hpp +++ b/common/Syscall.hpp @@ -11,6 +11,10 @@ #pragma once +#if MOBILEAPP +#error This file is not supposed to be compiled in the MOBILEAPP case +#endif + #include /** From 57a8756ae27e44090d8822c8ffbd6c4609d1cc2a Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 20 Jan 2025 09:11:52 +0100 Subject: [PATCH 090/177] Fix build of tests on macOS Signed-off-by: Jan Holesovsky Change-Id: I6d346a32de0b79da008d3608b104510fc7130b56 --- test/HttpWhiteBoxTests.cpp | 6 +++--- test/helpers.hpp | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/test/HttpWhiteBoxTests.cpp b/test/HttpWhiteBoxTests.cpp index 6eb7490a90708..01e86e300df63 100644 --- a/test/HttpWhiteBoxTests.cpp +++ b/test/HttpWhiteBoxTests.cpp @@ -180,7 +180,7 @@ void HttpWhiteBoxTests::testHeader() http::Header header; const std::string data = "\r\na=\r\n\r\n"; - LOK_ASSERT_EQUAL(8L, header.parse(data.c_str(), data.size())); + LOK_ASSERT_EQUAL(static_cast(8), header.parse(data.c_str(), data.size())); LOK_ASSERT_EQUAL(0UL, header.size()); } @@ -248,7 +248,7 @@ void HttpWhiteBoxTests::testRequestParserValidIncomplete() for (std::size_t i = 0; i < 33; ++i) { // Should return 0 to signify that data is incomplete. - LOK_ASSERT_EQUAL_MESSAGE("i = " << i << " of " << data.size() - 1, 0L, + LOK_ASSERT_EQUAL_MESSAGE("i = " << i << " of " << data.size() - 1, static_cast(0), req.readData(data.c_str(), i)); } @@ -264,7 +264,7 @@ void HttpWhiteBoxTests::testRequestParserValidIncomplete() for (std::size_t i = off; i < data.size(); ++i) { // Should return 0 to signify that data is incomplete. - LOK_ASSERT_EQUAL_MESSAGE("i = " << i << " of " << data.size() - 1, 0L, + LOK_ASSERT_EQUAL_MESSAGE("i = " << i << " of " << data.size() - 1, static_cast(0), req.readData(data.c_str() + off, i - off)); } diff --git a/test/helpers.hpp b/test/helpers.hpp index 25e98af1d6fc6..cf18385247d07 100644 --- a/test/helpers.hpp +++ b/test/helpers.hpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -352,7 +353,7 @@ inline int connectToLocalServer(int portNumber, int socketTimeOutMS, bool blocki int socketFD = 0; struct sockaddr_in serv_addr; - if ((socketFD = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0)) < 0) + if ((socketFD = Syscall::socket_cloexec_nonblock(AF_INET, 0 /*SOCK_STREAM | SOCK_CLOEXEC*/, 0)) < 0) { LOG_ERR("helpers::connectToLocalServer: Server client could not be created."); return -1; From e4d9004a2b1ca268c67633794258cdb93f1fb5ca Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 20 Jan 2025 10:22:12 +0100 Subject: [PATCH 091/177] Check for different versionrc location on macOS Signed-off-by: Jan Holesovsky Change-Id: Ida3d8679abcb70207ba72009a4bf01f1b952a1da --- configure.ac | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/configure.ac b/configure.ac index 6648db98aed11..aab201ad006f0 100644 --- a/configure.ac +++ b/configure.ac @@ -1421,6 +1421,7 @@ SYSTEMPLATE_PATH=not-set have_lo_path=false AC_MSG_CHECKING([whether to run tests against a LibreOffice]) version_file="$with_lo_path/program/versionrc" +version_file_macos="$with_lo_path/Contents/Resources/versionrc" if test -f $version_file; then JAILS_PATH="\${abs_top_builddir}/jails" CACHE_PATH="\${abs_top_builddir}/cache" @@ -1428,6 +1429,12 @@ if test -f $version_file; then have_lo_path=true lo_msg="test against $LO_PATH" AC_MSG_RESULT([yes]) +elif test `uname -s` = Darwin -a -f "$version_file_macos"; then + JAILS_PATH="\${abs_top_builddir}/jails" + SYSTEMPLATE_PATH="\${abs_top_builddir}/systemplate" + have_lo_path=true + lo_msg="test against $LO_PATH" + AC_MSG_RESULT([yes]) else lo_msg="no integration tests" AC_MSG_RESULT([no]) From 1cd7539722f68efe33ac7ddb195a420b01e8a2eb Mon Sep 17 00:00:00 2001 From: Andras Timar Date: Mon, 20 Jan 2025 15:13:41 +0100 Subject: [PATCH 092/177] No debug POCO liraries on macOS Signed-off-by: Andras Timar Change-Id: Iadc96c1c09a516e2ef1195c0b6e142abdcd40e73 --- configure.ac | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index aab201ad006f0..5f959f88792d1 100644 --- a/configure.ac +++ b/configure.ac @@ -441,8 +441,9 @@ AC_ARG_ENABLE([experimental], AS_HELP_STRING([--enable-experimental], [Enable experimental features and behavior])) -# Handle options -AS_IF([test "$enable_debug" = yes -a -n "$with_poco_libs"], +# Debug POCO libraries are named like 'PocoNetSSLd' instead of just 'PocoNetSSL', +# but Homebrew does not have those, so avoid this suffix for macOS +AS_IF([test "$enable_debug" = yes -a -n "$with_poco_libs" -a `uname -s` != Darwin], [POCO_DEBUG_SUFFIX=d], [POCO_DEBUG_SUFFIX=]) From 3009412dcec4e61d8000532fea1a9da32549c90f Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 21 Jan 2025 09:58:48 +0100 Subject: [PATCH 093/177] Add Xcode project for coolwsd for easier debugging Allow building and debugging coolwsd directly from Xcode. Add instructions. Signed-off-by: Jan Holesovsky Change-Id: I7785bd421392935bb21bc732eaec913114d88038 --- .gitignore | 3 +- configure.ac | 6 +- macos/{README.txt => README.md} | 32 +- .../xcshareddata/xcschemes/coda.xcscheme | 102 +++ macos/coolwsd/.gitignore | 2 + .../coolwsd/coolwsd.xcodeproj/project.pbxproj | 587 ++++++++++++++++++ .../xcshareddata/xcschemes/coolwsd.xcscheme | 131 ++++ macos/coolwsd/gmake-wrapper.sh.in | 6 + 8 files changed, 861 insertions(+), 8 deletions(-) rename macos/{README.txt => README.md} (72%) create mode 100644 macos/coda/coda.xcodeproj/xcshareddata/xcschemes/coda.xcscheme create mode 100644 macos/coolwsd/.gitignore create mode 100644 macos/coolwsd/coolwsd.xcodeproj/project.pbxproj create mode 100644 macos/coolwsd/coolwsd.xcodeproj/xcshareddata/xcschemes/coolwsd.xcscheme create mode 100644 macos/coolwsd/gmake-wrapper.sh.in diff --git a/.gitignore b/.gitignore index a329713cc0eb8..16dd17ad56c6c 100644 --- a/.gitignore +++ b/.gitignore @@ -47,6 +47,7 @@ compile_commands.json **/gdb.txt macos/coda/config.h macos/coda/Config.xcconfig +macos/coolwsd/gmake-wrapper.sh # Test stuff systemplate @@ -106,7 +107,7 @@ coolforkit-nocaps coolforkit-ns connect lokitclient -coolwsd +./coolwsd loolwsd coolmount coolmap diff --git a/configure.ac b/configure.ac index 5f959f88792d1..6f6543ab8924b 100644 --- a/configure.ac +++ b/configure.ac @@ -2128,7 +2128,7 @@ if test "$enable_iosapp" = "yes"; then ios/Mobile/Resources/Settings.bundle/Root.plist]) fi -if test "$enable_macosapp" = "yes"; then +if test `uname -s` = "Darwin"; then # Homebrew uses different paths on Intel and Apple Silicon macOS. # Having a separate /opt/homebrew makes more sense, but I guess # backward compatibility keeps it as /usr/local on Intel Macs. @@ -2138,7 +2138,9 @@ if test "$enable_macosapp" = "yes"; then HOMEBREW_PATH=/opt/homebrew fi AC_SUBST(HOMEBREW_PATH) - AC_CONFIG_FILES([macos/coda/Config.xcconfig]) + AC_CONFIG_FILES([macos/coda/Config.xcconfig + macos/coolwsd/gmake-wrapper.sh], + [chmod +x macos/coolwsd/gmake-wrapper.sh]) fi if test "$enable_windowsapp" = "yes"; then diff --git a/macos/README.txt b/macos/README.md similarity index 72% rename from macos/README.txt rename to macos/README.md index e3978819c5fbf..cab4ef8088b22 100644 --- a/macos/README.txt +++ b/macos/README.md @@ -1,6 +1,6 @@ -Building the CODA-M +# Building the CODA-M -Setup +## Setup * Instal node.js * brew install node @@ -28,7 +28,7 @@ Setup * After that you might need to update them in System Settings > General > Software Updates * For some reason for me it lists both 15.3 and 16.0 there. As I have Xcode 16.0, I choose just that one. -Build LO +## Build LO You need the 'coda' branch for that, and have to use the following autogen.input. @@ -75,12 +75,34 @@ not /opt/homebrew. If you find an instance of /Users/kendy hardcoded somewhere, please report that, it's a mistake and should be fixed. -Then you can build CODA-M: +## Then you can build CODA-M: * ( cd browser ; make ) * open Xcode's project macos/coda/coda.xcodeproj & build from there -TODO +# Building and debugging coolwsd directly in Xcode + +There is an additional Xcode project for easy building and debugging of +coolwsd on macOS directly in Xcode. Configure everything as above, but use +a slightly different ./configure (particularly notice the +missing --enable-macosapp): + + ./autogen.sh && ./configure \ + --with-app-name="Collabora Office" \ + --enable-experimental \ + --enable-debug \ + --with-vendor="Collabora Productivity" \ + --with-poco-includes=/opt/homebrew/opt/poco/include \ + --with-poco-libs=/opt/homebrew/opt/poco/lib \ + --with-zstd-includes=/opt/homebrew/include \ + --with-zstd-libs=/opt/homebrew/lib \ + --with-lo-path=/Users/kendy/Projects/lo/core/instdir/CollaboraOffice.app \ + --with-lokit-path=/Users/kendy/Projects/lo/core/include + +Then open the macos/coolwsd.xcodeproj project in Xcode and you can build, run +and debug directly from Xcode. + +# TODO * configure.ac * add sanity check for the lo builddir when configuring with —enable-macosapp diff --git a/macos/coda/coda.xcodeproj/xcshareddata/xcschemes/coda.xcscheme b/macos/coda/coda.xcodeproj/xcshareddata/xcschemes/coda.xcscheme new file mode 100644 index 0000000000000..66cb7c4100a21 --- /dev/null +++ b/macos/coda/coda.xcodeproj/xcshareddata/xcschemes/coda.xcscheme @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/macos/coolwsd/.gitignore b/macos/coolwsd/.gitignore new file mode 100644 index 0000000000000..a40ccef413542 --- /dev/null +++ b/macos/coolwsd/.gitignore @@ -0,0 +1,2 @@ +/coolwsd.xcodeproj/project.xcworkspace/ +/coolwsd.xcodeproj/xcuserdata/ diff --git a/macos/coolwsd/coolwsd.xcodeproj/project.pbxproj b/macos/coolwsd/coolwsd.xcodeproj/project.pbxproj new file mode 100644 index 0000000000000..8fffcfd9a5e1f --- /dev/null +++ b/macos/coolwsd/coolwsd.xcodeproj/project.pbxproj @@ -0,0 +1,587 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 77; + objects = { + +/* Begin PBXFileReference section */ + BE74B1B52D3F963F009786DF /* Anonymizer.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Anonymizer.hpp; path = ../../../common/Anonymizer.hpp; sourceTree = ""; }; + BE74B1B62D3F963F009786DF /* Authorization.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Authorization.hpp; path = ../../../common/Authorization.hpp; sourceTree = ""; }; + BE74B1B72D3F963F009786DF /* Authorization.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Authorization.cpp; path = ../../../common/Authorization.cpp; sourceTree = ""; }; + BE74B1B82D3F963F009786DF /* Clipboard.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Clipboard.hpp; path = ../../../common/Clipboard.hpp; sourceTree = ""; }; + BE74B1B92D3F963F009786DF /* CommandControl.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = CommandControl.hpp; path = ../../../common/CommandControl.hpp; sourceTree = ""; }; + BE74B1BA2D3F963F009786DF /* CommandControl.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = CommandControl.cpp; path = ../../../common/CommandControl.cpp; sourceTree = ""; }; + BE74B1BB2D3F963F009786DF /* Common.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Common.hpp; path = ../../../common/Common.hpp; sourceTree = ""; }; + BE74B1BC2D3F963F009786DF /* ConfigUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = ConfigUtil.hpp; path = ../../../common/ConfigUtil.hpp; sourceTree = ""; }; + BE74B1BD2D3F963F009786DF /* ConfigUtil.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ConfigUtil.cpp; path = ../../../common/ConfigUtil.cpp; sourceTree = ""; }; + BE74B1BE2D3F963F009786DF /* CoolMount.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = CoolMount.cpp; path = ../../../common/CoolMount.cpp; sourceTree = ""; }; + BE74B1BF2D3F963F009786DF /* Crypto.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Crypto.hpp; path = ../../../common/Crypto.hpp; sourceTree = ""; }; + BE74B1C02D3F963F009786DF /* Crypto.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Crypto.cpp; path = ../../../common/Crypto.cpp; sourceTree = ""; }; + BE74B1C12D3F963F009786DF /* Crypto-stub.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "Crypto-stub.cpp"; path = "../../../common/Crypto-stub.cpp"; sourceTree = ""; }; + BE74B1C22D3F963F009786DF /* DummyTraceEventEmitter.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = DummyTraceEventEmitter.cpp; path = ../../../common/DummyTraceEventEmitter.cpp; sourceTree = ""; }; + BE74B1C32D3F963F009786DF /* FileUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = FileUtil.hpp; path = ../../../common/FileUtil.hpp; sourceTree = ""; }; + BE74B1C42D3F963F009786DF /* FileUtil.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = FileUtil.cpp; path = ../../../common/FileUtil.cpp; sourceTree = ""; }; + BE74B1C52D3F963F009786DF /* FileUtil-apple.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "FileUtil-apple.mm"; path = "../../../common/FileUtil-apple.mm"; sourceTree = ""; }; + BE74B1C62D3F963F009786DF /* FileUtil-unix.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "FileUtil-unix.cpp"; path = "../../../common/FileUtil-unix.cpp"; sourceTree = ""; }; + BE74B1C72D3F963F009786DF /* FileUtil-windows.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "FileUtil-windows.cpp"; path = "../../../common/FileUtil-windows.cpp"; sourceTree = ""; }; + BE74B1C82D3F963F009786DF /* CharacterConverter.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = CharacterConverter.hpp; path = ../../../common/CharacterConverter.hpp; sourceTree = ""; }; + BE74B1C92D3F963F009786DF /* JailUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = JailUtil.hpp; path = ../../../common/JailUtil.hpp; sourceTree = ""; }; + BE74B1CA2D3F963F009786DF /* JailUtil.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = JailUtil.cpp; path = ../../../common/JailUtil.cpp; sourceTree = ""; }; + BE74B1CB2D3F963F009786DF /* JsonUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = JsonUtil.hpp; path = ../../../common/JsonUtil.hpp; sourceTree = ""; }; + BE74B1CC2D3F963F009786DF /* LangUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = LangUtil.hpp; path = ../../../common/LangUtil.hpp; sourceTree = ""; }; + BE74B1CD2D3F963F009786DF /* Log.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Log.hpp; path = ../../../common/Log.hpp; sourceTree = ""; }; + BE74B1CE2D3F963F009786DF /* Log.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Log.cpp; path = ../../../common/Log.cpp; sourceTree = ""; }; + BE74B1CF2D3F963F009786DF /* Message.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Message.hpp; path = ../../../common/Message.hpp; sourceTree = ""; }; + BE74B1D02D3F963F009786DF /* MobileApp.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = MobileApp.hpp; path = ../../../common/MobileApp.hpp; sourceTree = ""; }; + BE74B1D12D3F963F009786DF /* MobileApp.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = MobileApp.cpp; path = ../../../common/MobileApp.cpp; sourceTree = ""; }; + BE74B1D22D3F963F009786DF /* Png.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Png.hpp; path = ../../../common/Png.hpp; sourceTree = ""; }; + BE74B1D32D3F963F009786DF /* Protocol.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Protocol.hpp; path = ../../../common/Protocol.hpp; sourceTree = ""; }; + BE74B1D42D3F963F009786DF /* Protocol.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Protocol.cpp; path = ../../../common/Protocol.cpp; sourceTree = ""; }; + BE74B1D52D3F963F009786DF /* Rectangle.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Rectangle.hpp; path = ../../../common/Rectangle.hpp; sourceTree = ""; }; + BE74B1D62D3F963F009786DF /* RenderTiles.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = RenderTiles.hpp; path = ../../../common/RenderTiles.hpp; sourceTree = ""; }; + BE74B1D72D3F963F009786DF /* Seccomp.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Seccomp.hpp; path = ../../../common/Seccomp.hpp; sourceTree = ""; }; + BE74B1D82D3F963F009786DF /* Seccomp.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Seccomp.cpp; path = ../../../common/Seccomp.cpp; sourceTree = ""; }; + BE74B1D92D3F963F009786DF /* security.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = security.h; path = ../../../common/security.h; sourceTree = ""; }; + BE74B1DA2D3F963F009786DF /* Session.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Session.hpp; path = ../../../common/Session.hpp; sourceTree = ""; }; + BE74B1DB2D3F963F009786DF /* Session.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Session.cpp; path = ../../../common/Session.cpp; sourceTree = ""; }; + BE74B1DC2D3F963F009786DF /* SigHandlerTrap.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = SigHandlerTrap.hpp; path = ../../../common/SigHandlerTrap.hpp; sourceTree = ""; }; + BE74B1DD2D3F963F009786DF /* SigUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = SigUtil.hpp; path = ../../../common/SigUtil.hpp; sourceTree = ""; }; + BE74B1DE2D3F963F009786DF /* SigUtil-mobile.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "SigUtil-mobile.cpp"; path = "../../../common/SigUtil-mobile.cpp"; sourceTree = ""; }; + BE74B1DF2D3F963F009786DF /* SigUtil-server.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "SigUtil-server.cpp"; path = "../../../common/SigUtil-server.cpp"; sourceTree = ""; }; + BE74B1E02D3F963F009786DF /* Simd.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Simd.hpp; path = ../../../common/Simd.hpp; sourceTree = ""; }; + BE74B1E12D3F963F009786DF /* Simd.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Simd.cpp; path = ../../../common/Simd.cpp; sourceTree = ""; }; + BE74B1E22D3F963F009786DF /* SpookyV2.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SpookyV2.h; path = ../../../common/SpookyV2.h; sourceTree = ""; }; + BE74B1E32D3F963F009786DF /* SpookyV2.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SpookyV2.cpp; path = ../../../common/SpookyV2.cpp; sourceTree = ""; }; + BE74B1E42D3F963F009786DF /* StateEnum.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = StateEnum.hpp; path = ../../../common/StateEnum.hpp; sourceTree = ""; }; + BE74B1E52D3F963F009786DF /* StringVector.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = StringVector.hpp; path = ../../../common/StringVector.hpp; sourceTree = ""; }; + BE74B1E62D3F963F009786DF /* StringVector.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = StringVector.cpp; path = ../../../common/StringVector.cpp; sourceTree = ""; }; + BE74B1E72D3F963F009786DF /* Syscall.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Syscall.hpp; path = ../../../common/Syscall.hpp; sourceTree = ""; }; + BE74B1E82D3F963F009786DF /* Syscall.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Syscall.cpp; path = ../../../common/Syscall.cpp; sourceTree = ""; }; + BE74B1E92D3F963F009786DF /* ThreadPool.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = ThreadPool.hpp; path = ../../../common/ThreadPool.hpp; sourceTree = ""; }; + BE74B1EA2D3F963F009786DF /* TraceEvent.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = TraceEvent.hpp; path = ../../../common/TraceEvent.hpp; sourceTree = ""; }; + BE74B1EB2D3F963F009786DF /* TraceEvent.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = TraceEvent.cpp; path = ../../../common/TraceEvent.cpp; sourceTree = ""; }; + BE74B1EC2D3F963F009786DF /* Unit.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Unit.hpp; path = ../../../common/Unit.hpp; sourceTree = ""; }; + BE74B1ED2D3F963F009786DF /* Unit.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Unit.cpp; path = ../../../common/Unit.cpp; sourceTree = ""; }; + BE74B1EE2D3F963F009786DF /* Unit-mobile.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "Unit-mobile.cpp"; path = "../../../common/Unit-mobile.cpp"; sourceTree = ""; }; + BE74B1EF2D3F963F009786DF /* Unit-server.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "Unit-server.cpp"; path = "../../../common/Unit-server.cpp"; sourceTree = ""; }; + BE74B1F02D3F963F009786DF /* Uri.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Uri.hpp; path = ../../../common/Uri.hpp; sourceTree = ""; }; + BE74B1F12D3F963F009786DF /* Uri.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Uri.cpp; path = ../../../common/Uri.cpp; sourceTree = ""; }; + BE74B1F22D3F963F009786DF /* Util.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Util.hpp; path = ../../../common/Util.hpp; sourceTree = ""; }; + BE74B1F32D3F963F009786DF /* Util.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Util.cpp; path = ../../../common/Util.cpp; sourceTree = ""; }; + BE74B1F42D3F963F009786DF /* Util-mobile.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "Util-mobile.cpp"; path = "../../../common/Util-mobile.cpp"; sourceTree = ""; }; + BE74B1F52D3F963F009786DF /* Util-server.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "Util-server.cpp"; path = "../../../common/Util-server.cpp"; sourceTree = ""; }; + BE74B1F62D3F963F009786DF /* Util-unix.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "Util-unix.cpp"; path = "../../../common/Util-unix.cpp"; sourceTree = ""; }; + BE74B1F72D3F963F009786DF /* Util-windows.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "Util-windows.cpp"; path = "../../../common/Util-windows.cpp"; sourceTree = ""; }; + BE74B1F82D3F963F009786DF /* Watchdog.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Watchdog.hpp; path = ../../../common/Watchdog.hpp; sourceTree = ""; }; + BE74B1F92D3F96CB009786DF /* Delta.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Delta.hpp; path = ../../../kit/Delta.hpp; sourceTree = ""; }; + BE74B1FA2D3F96CB009786DF /* DeltaSimd.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = DeltaSimd.h; path = ../../../kit/DeltaSimd.h; sourceTree = ""; }; + BE74B1FB2D3F96CB009786DF /* DeltaSimd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = DeltaSimd.c; path = ../../../kit/DeltaSimd.c; sourceTree = ""; }; + BE74B1FC2D3F96CB009786DF /* DummyLibreOfficeKit.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = DummyLibreOfficeKit.hpp; path = ../../../kit/DummyLibreOfficeKit.hpp; sourceTree = ""; }; + BE74B1FD2D3F96CB009786DF /* DummyLibreOfficeKit.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = DummyLibreOfficeKit.cpp; path = ../../../kit/DummyLibreOfficeKit.cpp; sourceTree = ""; }; + BE74B1FE2D3F96CB009786DF /* ForKit.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ForKit.cpp; path = ../../../kit/ForKit.cpp; sourceTree = ""; }; + BE74B1FF2D3F96CB009786DF /* forkit-main.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "forkit-main.cpp"; path = "../../../kit/forkit-main.cpp"; sourceTree = ""; }; + BE74B2002D3F96CB009786DF /* ChildSession.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = ChildSession.hpp; path = ../../../kit/ChildSession.hpp; sourceTree = ""; }; + BE74B2012D3F96CB009786DF /* ChildSession.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ChildSession.cpp; path = ../../../kit/ChildSession.cpp; sourceTree = ""; }; + BE74B2022D3F96CB009786DF /* Kit.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Kit.hpp; path = ../../../kit/Kit.hpp; sourceTree = ""; }; + BE74B2032D3F96CB009786DF /* Kit.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Kit.cpp; path = ../../../kit/Kit.cpp; sourceTree = ""; }; + BE74B2042D3F96CB009786DF /* KitHelper.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = KitHelper.hpp; path = ../../../kit/KitHelper.hpp; sourceTree = ""; }; + BE74B2052D3F96CB009786DF /* KitQueue.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = KitQueue.hpp; path = ../../../kit/KitQueue.hpp; sourceTree = ""; }; + BE74B2062D3F96CB009786DF /* KitQueue.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = KitQueue.cpp; path = ../../../kit/KitQueue.cpp; sourceTree = ""; }; + BE74B2072D3F96CB009786DF /* KitWebSocket.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = KitWebSocket.hpp; path = ../../../kit/KitWebSocket.hpp; sourceTree = ""; }; + BE74B2082D3F96CB009786DF /* KitWebSocket.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = KitWebSocket.cpp; path = ../../../kit/KitWebSocket.cpp; sourceTree = ""; }; + BE74B2092D3F96CB009786DF /* SetupKitEnvironment.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = SetupKitEnvironment.hpp; path = ../../../kit/SetupKitEnvironment.hpp; sourceTree = ""; }; + BE74B20A2D3F96CB009786DF /* StateRecorder.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = StateRecorder.hpp; path = ../../../kit/StateRecorder.hpp; sourceTree = ""; }; + BE74B20B2D3F96CB009786DF /* TestStubs.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = TestStubs.cpp; path = ../../../kit/TestStubs.cpp; sourceTree = ""; }; + BE74B20C2D3F96CB009786DF /* Watermark.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Watermark.hpp; path = ../../../kit/Watermark.hpp; sourceTree = ""; }; + BE74B20D2D3F971C009786DF /* AsyncDNS.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = AsyncDNS.hpp; path = ../../../net/AsyncDNS.hpp; sourceTree = ""; }; + BE74B20E2D3F971C009786DF /* Buffer.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Buffer.hpp; path = ../../../net/Buffer.hpp; sourceTree = ""; }; + BE74B20F2D3F971C009786DF /* clientnb.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = clientnb.cpp; path = ../../../net/clientnb.cpp; sourceTree = ""; }; + BE74B2102D3F971C009786DF /* DelaySocket.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = DelaySocket.hpp; path = ../../../net/DelaySocket.hpp; sourceTree = ""; }; + BE74B2112D3F971C009786DF /* DelaySocket.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = DelaySocket.cpp; path = ../../../net/DelaySocket.cpp; sourceTree = ""; }; + BE74B2122D3F971C009786DF /* FakeSocket.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = FakeSocket.hpp; path = ../../../net/FakeSocket.hpp; sourceTree = ""; }; + BE74B2132D3F971C009786DF /* FakeSocket.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = FakeSocket.cpp; path = ../../../net/FakeSocket.cpp; sourceTree = ""; }; + BE74B2142D3F971C009786DF /* HttpHelper.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = HttpHelper.hpp; path = ../../../net/HttpHelper.hpp; sourceTree = ""; }; + BE74B2152D3F971C009786DF /* HttpHelper.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = HttpHelper.cpp; path = ../../../net/HttpHelper.cpp; sourceTree = ""; }; + BE74B2162D3F971C009786DF /* HttpRequest.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = HttpRequest.hpp; path = ../../../net/HttpRequest.hpp; sourceTree = ""; }; + BE74B2172D3F971C009786DF /* HttpRequest.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = HttpRequest.cpp; path = ../../../net/HttpRequest.cpp; sourceTree = ""; }; + BE74B2182D3F971C009786DF /* NetUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = NetUtil.hpp; path = ../../../net/NetUtil.hpp; sourceTree = ""; }; + BE74B2192D3F971C009786DF /* NetUtil.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = NetUtil.cpp; path = ../../../net/NetUtil.cpp; sourceTree = ""; }; + BE74B21A2D3F971C009786DF /* ServerSocket.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = ServerSocket.hpp; path = ../../../net/ServerSocket.hpp; sourceTree = ""; }; + BE74B21B2D3F971C009786DF /* Socket.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Socket.hpp; path = ../../../net/Socket.hpp; sourceTree = ""; }; + BE74B21C2D3F971C009786DF /* Socket.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Socket.cpp; path = ../../../net/Socket.cpp; sourceTree = ""; }; + BE74B21D2D3F971C009786DF /* Ssl.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Ssl.hpp; path = ../../../net/Ssl.hpp; sourceTree = ""; }; + BE74B21E2D3F971C009786DF /* Ssl.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Ssl.cpp; path = ../../../net/Ssl.cpp; sourceTree = ""; }; + BE74B21F2D3F971C009786DF /* SslSocket.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = SslSocket.hpp; path = ../../../net/SslSocket.hpp; sourceTree = ""; }; + BE74B2202D3F971C009786DF /* WebSocketHandler.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = WebSocketHandler.hpp; path = ../../../net/WebSocketHandler.hpp; sourceTree = ""; }; + BE74B2212D3F97AB009786DF /* Admin.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Admin.hpp; path = ../../../wsd/Admin.hpp; sourceTree = ""; }; + BE74B2222D3F97AB009786DF /* Admin.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Admin.cpp; path = ../../../wsd/Admin.cpp; sourceTree = ""; }; + BE74B2232D3F97AB009786DF /* AdminModel.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = AdminModel.hpp; path = ../../../wsd/AdminModel.hpp; sourceTree = ""; }; + BE74B2242D3F97AB009786DF /* AdminModel.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = AdminModel.cpp; path = ../../../wsd/AdminModel.cpp; sourceTree = ""; }; + BE74B2252D3F97AB009786DF /* Auth.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Auth.hpp; path = ../../../wsd/Auth.hpp; sourceTree = ""; }; + BE74B2262D3F97AB009786DF /* Auth.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Auth.cpp; path = ../../../wsd/Auth.cpp; sourceTree = ""; }; + BE74B2272D3F97AB009786DF /* ClientRequestDispatcher.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = ClientRequestDispatcher.hpp; path = ../../../wsd/ClientRequestDispatcher.hpp; sourceTree = ""; }; + BE74B2282D3F97AB009786DF /* ClientRequestDispatcher.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ClientRequestDispatcher.cpp; path = ../../../wsd/ClientRequestDispatcher.cpp; sourceTree = ""; }; + BE74B2292D3F97AB009786DF /* ClientSession.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = ClientSession.hpp; path = ../../../wsd/ClientSession.hpp; sourceTree = ""; }; + BE74B22A2D3F97AB009786DF /* ClientSession.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ClientSession.cpp; path = ../../../wsd/ClientSession.cpp; sourceTree = ""; }; + BE74B22B2D3F97AB009786DF /* ContentSecurityPolicy.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = ContentSecurityPolicy.hpp; path = ../../../wsd/ContentSecurityPolicy.hpp; sourceTree = ""; }; + BE74B22C2D3F97AB009786DF /* COOLWSD.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = COOLWSD.hpp; path = ../../../wsd/COOLWSD.hpp; sourceTree = ""; }; + BE74B22D2D3F97AB009786DF /* COOLWSD.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = COOLWSD.cpp; path = ../../../wsd/COOLWSD.cpp; sourceTree = ""; }; + BE74B22E2D3F97AB009786DF /* coolwsd-fork.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "coolwsd-fork.cpp"; path = "../../../wsd/coolwsd-fork.cpp"; sourceTree = ""; }; + BE74B22F2D3F97AB009786DF /* coolwsd-inproc.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "coolwsd-inproc.cpp"; path = "../../../wsd/coolwsd-inproc.cpp"; sourceTree = ""; }; + BE74B2302D3F97AB009786DF /* DocumentBroker.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = DocumentBroker.hpp; path = ../../../wsd/DocumentBroker.hpp; sourceTree = ""; }; + BE74B2312D3F97AB009786DF /* DocumentBroker.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = DocumentBroker.cpp; path = ../../../wsd/DocumentBroker.cpp; sourceTree = ""; }; + BE74B2322D3F97AB009786DF /* Exceptions.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Exceptions.hpp; path = ../../../wsd/Exceptions.hpp; sourceTree = ""; }; + BE74B2332D3F97AB009786DF /* Exceptions.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Exceptions.cpp; path = ../../../wsd/Exceptions.cpp; sourceTree = ""; }; + BE74B2342D3F97AB009786DF /* FileServer.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = FileServer.hpp; path = ../../../wsd/FileServer.hpp; sourceTree = ""; }; + BE74B2352D3F97AB009786DF /* FileServer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = FileServer.cpp; path = ../../../wsd/FileServer.cpp; sourceTree = ""; }; + BE74B2362D3F97AB009786DF /* FileServerUtil.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = FileServerUtil.cpp; path = ../../../wsd/FileServerUtil.cpp; sourceTree = ""; }; + BE74B2372D3F97AB009786DF /* HostUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = HostUtil.hpp; path = ../../../wsd/HostUtil.hpp; sourceTree = ""; }; + BE74B2382D3F97AB009786DF /* HostUtil.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = HostUtil.cpp; path = ../../../wsd/HostUtil.cpp; sourceTree = ""; }; + BE74B2392D3F97AB009786DF /* Process.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Process.hpp; path = ../../../wsd/Process.hpp; sourceTree = ""; }; + BE74B23A2D3F97AB009786DF /* ProofKey.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = ProofKey.hpp; path = ../../../wsd/ProofKey.hpp; sourceTree = ""; }; + BE74B23B2D3F97AB009786DF /* ProofKey.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ProofKey.cpp; path = ../../../wsd/ProofKey.cpp; sourceTree = ""; }; + BE74B23C2D3F97AB009786DF /* ProxyProtocol.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = ProxyProtocol.hpp; path = ../../../wsd/ProxyProtocol.hpp; sourceTree = ""; }; + BE74B23D2D3F97AB009786DF /* ProxyProtocol.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ProxyProtocol.cpp; path = ../../../wsd/ProxyProtocol.cpp; sourceTree = ""; }; + BE74B23E2D3F97AB009786DF /* ProxyRequestHandler.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = ProxyRequestHandler.hpp; path = ../../../wsd/ProxyRequestHandler.hpp; sourceTree = ""; }; + BE74B23F2D3F97AB009786DF /* ProxyRequestHandler.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ProxyRequestHandler.cpp; path = ../../../wsd/ProxyRequestHandler.cpp; sourceTree = ""; }; + BE74B2402D3F97AB009786DF /* QuarantineUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = QuarantineUtil.hpp; path = ../../../wsd/QuarantineUtil.hpp; sourceTree = ""; }; + BE74B2412D3F97AB009786DF /* QuarantineUtil.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = QuarantineUtil.cpp; path = ../../../wsd/QuarantineUtil.cpp; sourceTree = ""; }; + BE74B2422D3F97AB009786DF /* RemoteConfig.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = RemoteConfig.hpp; path = ../../../wsd/RemoteConfig.hpp; sourceTree = ""; }; + BE74B2432D3F97AB009786DF /* RemoteConfig.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = RemoteConfig.cpp; path = ../../../wsd/RemoteConfig.cpp; sourceTree = ""; }; + BE74B2442D3F97AB009786DF /* RequestDetails.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = RequestDetails.hpp; path = ../../../wsd/RequestDetails.hpp; sourceTree = ""; }; + BE74B2452D3F97AB009786DF /* RequestDetails.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = RequestDetails.cpp; path = ../../../wsd/RequestDetails.cpp; sourceTree = ""; }; + BE74B2462D3F97AB009786DF /* RequestVettingStation.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = RequestVettingStation.hpp; path = ../../../wsd/RequestVettingStation.hpp; sourceTree = ""; }; + BE74B2472D3F97AB009786DF /* RequestVettingStation.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = RequestVettingStation.cpp; path = ../../../wsd/RequestVettingStation.cpp; sourceTree = ""; }; + BE74B2482D3F97AB009786DF /* SenderQueue.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = SenderQueue.hpp; path = ../../../wsd/SenderQueue.hpp; sourceTree = ""; }; + BE74B2492D3F97AB009786DF /* ServerAuditUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = ServerAuditUtil.hpp; path = ../../../wsd/ServerAuditUtil.hpp; sourceTree = ""; }; + BE74B24A2D3F97AB009786DF /* ServerAuditUtil.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ServerAuditUtil.cpp; path = ../../../wsd/ServerAuditUtil.cpp; sourceTree = ""; }; + BE74B24B2D3F97AB009786DF /* ServerURL.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = ServerURL.hpp; path = ../../../wsd/ServerURL.hpp; sourceTree = ""; }; + BE74B24C2D3F97AB009786DF /* SpecialBrokers.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = SpecialBrokers.hpp; path = ../../../wsd/SpecialBrokers.hpp; sourceTree = ""; }; + BE74B24D2D3F97AB009786DF /* SpecialBrokers.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SpecialBrokers.cpp; path = ../../../wsd/SpecialBrokers.cpp; sourceTree = ""; }; + BE74B24E2D3F97AB009786DF /* Storage.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Storage.hpp; path = ../../../wsd/Storage.hpp; sourceTree = ""; }; + BE74B24F2D3F97AB009786DF /* Storage.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Storage.cpp; path = ../../../wsd/Storage.cpp; sourceTree = ""; }; + BE74B2502D3F97AB009786DF /* TestStubs.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = TestStubs.cpp; path = ../../../wsd/TestStubs.cpp; sourceTree = ""; }; + BE74B2512D3F97AB009786DF /* TileCache.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = TileCache.hpp; path = ../../../wsd/TileCache.hpp; sourceTree = ""; }; + BE74B2522D3F97AB009786DF /* TileCache.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = TileCache.cpp; path = ../../../wsd/TileCache.cpp; sourceTree = ""; }; + BE74B2532D3F97AB009786DF /* TileDesc.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = TileDesc.hpp; path = ../../../wsd/TileDesc.hpp; sourceTree = ""; }; + BE74B2542D3F97AB009786DF /* TraceFile.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = TraceFile.hpp; path = ../../../wsd/TraceFile.hpp; sourceTree = ""; }; + BE74B2552D3F97AB009786DF /* UserMessages.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = UserMessages.hpp; path = ../../../wsd/UserMessages.hpp; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXGroup section */ + BE74B1A52D3F80AA009786DF = { + isa = PBXGroup; + children = ( + BE74B1B02D3F950A009786DF /* common */, + BE74B1B22D3F953B009786DF /* kit */, + BE74B1B32D3F9541009786DF /* net */, + BE74B1B42D3F9546009786DF /* wsd */, + ); + sourceTree = ""; + }; + BE74B1B02D3F950A009786DF /* common */ = { + isa = PBXGroup; + children = ( + BE74B1B52D3F963F009786DF /* Anonymizer.hpp */, + BE74B1B62D3F963F009786DF /* Authorization.hpp */, + BE74B1B72D3F963F009786DF /* Authorization.cpp */, + BE74B1B82D3F963F009786DF /* Clipboard.hpp */, + BE74B1B92D3F963F009786DF /* CommandControl.hpp */, + BE74B1BA2D3F963F009786DF /* CommandControl.cpp */, + BE74B1BB2D3F963F009786DF /* Common.hpp */, + BE74B1BC2D3F963F009786DF /* ConfigUtil.hpp */, + BE74B1BD2D3F963F009786DF /* ConfigUtil.cpp */, + BE74B1BE2D3F963F009786DF /* CoolMount.cpp */, + BE74B1BF2D3F963F009786DF /* Crypto.hpp */, + BE74B1C02D3F963F009786DF /* Crypto.cpp */, + BE74B1C12D3F963F009786DF /* Crypto-stub.cpp */, + BE74B1C22D3F963F009786DF /* DummyTraceEventEmitter.cpp */, + BE74B1C32D3F963F009786DF /* FileUtil.hpp */, + BE74B1C42D3F963F009786DF /* FileUtil.cpp */, + BE74B1C52D3F963F009786DF /* FileUtil-apple.mm */, + BE74B1C62D3F963F009786DF /* FileUtil-unix.cpp */, + BE74B1C72D3F963F009786DF /* FileUtil-windows.cpp */, + BE74B1C82D3F963F009786DF /* CharacterConverter.hpp */, + BE74B1C92D3F963F009786DF /* JailUtil.hpp */, + BE74B1CA2D3F963F009786DF /* JailUtil.cpp */, + BE74B1CB2D3F963F009786DF /* JsonUtil.hpp */, + BE74B1CC2D3F963F009786DF /* LangUtil.hpp */, + BE74B1CD2D3F963F009786DF /* Log.hpp */, + BE74B1CE2D3F963F009786DF /* Log.cpp */, + BE74B1CF2D3F963F009786DF /* Message.hpp */, + BE74B1D02D3F963F009786DF /* MobileApp.hpp */, + BE74B1D12D3F963F009786DF /* MobileApp.cpp */, + BE74B1D22D3F963F009786DF /* Png.hpp */, + BE74B1D32D3F963F009786DF /* Protocol.hpp */, + BE74B1D42D3F963F009786DF /* Protocol.cpp */, + BE74B1D52D3F963F009786DF /* Rectangle.hpp */, + BE74B1D62D3F963F009786DF /* RenderTiles.hpp */, + BE74B1D72D3F963F009786DF /* Seccomp.hpp */, + BE74B1D82D3F963F009786DF /* Seccomp.cpp */, + BE74B1D92D3F963F009786DF /* security.h */, + BE74B1DA2D3F963F009786DF /* Session.hpp */, + BE74B1DB2D3F963F009786DF /* Session.cpp */, + BE74B1DC2D3F963F009786DF /* SigHandlerTrap.hpp */, + BE74B1DD2D3F963F009786DF /* SigUtil.hpp */, + BE74B1DE2D3F963F009786DF /* SigUtil-mobile.cpp */, + BE74B1DF2D3F963F009786DF /* SigUtil-server.cpp */, + BE74B1E02D3F963F009786DF /* Simd.hpp */, + BE74B1E12D3F963F009786DF /* Simd.cpp */, + BE74B1E22D3F963F009786DF /* SpookyV2.h */, + BE74B1E32D3F963F009786DF /* SpookyV2.cpp */, + BE74B1E42D3F963F009786DF /* StateEnum.hpp */, + BE74B1E52D3F963F009786DF /* StringVector.hpp */, + BE74B1E62D3F963F009786DF /* StringVector.cpp */, + BE74B1E72D3F963F009786DF /* Syscall.hpp */, + BE74B1E82D3F963F009786DF /* Syscall.cpp */, + BE74B1E92D3F963F009786DF /* ThreadPool.hpp */, + BE74B1EA2D3F963F009786DF /* TraceEvent.hpp */, + BE74B1EB2D3F963F009786DF /* TraceEvent.cpp */, + BE74B1EC2D3F963F009786DF /* Unit.hpp */, + BE74B1ED2D3F963F009786DF /* Unit.cpp */, + BE74B1EE2D3F963F009786DF /* Unit-mobile.cpp */, + BE74B1EF2D3F963F009786DF /* Unit-server.cpp */, + BE74B1F02D3F963F009786DF /* Uri.hpp */, + BE74B1F12D3F963F009786DF /* Uri.cpp */, + BE74B1F22D3F963F009786DF /* Util.hpp */, + BE74B1F32D3F963F009786DF /* Util.cpp */, + BE74B1F42D3F963F009786DF /* Util-mobile.cpp */, + BE74B1F52D3F963F009786DF /* Util-server.cpp */, + BE74B1F62D3F963F009786DF /* Util-unix.cpp */, + BE74B1F72D3F963F009786DF /* Util-windows.cpp */, + BE74B1F82D3F963F009786DF /* Watchdog.hpp */, + ); + path = common; + sourceTree = ""; + }; + BE74B1B22D3F953B009786DF /* kit */ = { + isa = PBXGroup; + children = ( + BE74B1F92D3F96CB009786DF /* Delta.hpp */, + BE74B1FA2D3F96CB009786DF /* DeltaSimd.h */, + BE74B1FB2D3F96CB009786DF /* DeltaSimd.c */, + BE74B1FC2D3F96CB009786DF /* DummyLibreOfficeKit.hpp */, + BE74B1FD2D3F96CB009786DF /* DummyLibreOfficeKit.cpp */, + BE74B1FE2D3F96CB009786DF /* ForKit.cpp */, + BE74B1FF2D3F96CB009786DF /* forkit-main.cpp */, + BE74B2002D3F96CB009786DF /* ChildSession.hpp */, + BE74B2012D3F96CB009786DF /* ChildSession.cpp */, + BE74B2022D3F96CB009786DF /* Kit.hpp */, + BE74B2032D3F96CB009786DF /* Kit.cpp */, + BE74B2042D3F96CB009786DF /* KitHelper.hpp */, + BE74B2052D3F96CB009786DF /* KitQueue.hpp */, + BE74B2062D3F96CB009786DF /* KitQueue.cpp */, + BE74B2072D3F96CB009786DF /* KitWebSocket.hpp */, + BE74B2082D3F96CB009786DF /* KitWebSocket.cpp */, + BE74B2092D3F96CB009786DF /* SetupKitEnvironment.hpp */, + BE74B20A2D3F96CB009786DF /* StateRecorder.hpp */, + BE74B20B2D3F96CB009786DF /* TestStubs.cpp */, + BE74B20C2D3F96CB009786DF /* Watermark.hpp */, + ); + path = kit; + sourceTree = ""; + }; + BE74B1B32D3F9541009786DF /* net */ = { + isa = PBXGroup; + children = ( + BE74B20D2D3F971C009786DF /* AsyncDNS.hpp */, + BE74B20E2D3F971C009786DF /* Buffer.hpp */, + BE74B20F2D3F971C009786DF /* clientnb.cpp */, + BE74B2102D3F971C009786DF /* DelaySocket.hpp */, + BE74B2112D3F971C009786DF /* DelaySocket.cpp */, + BE74B2122D3F971C009786DF /* FakeSocket.hpp */, + BE74B2132D3F971C009786DF /* FakeSocket.cpp */, + BE74B2142D3F971C009786DF /* HttpHelper.hpp */, + BE74B2152D3F971C009786DF /* HttpHelper.cpp */, + BE74B2162D3F971C009786DF /* HttpRequest.hpp */, + BE74B2172D3F971C009786DF /* HttpRequest.cpp */, + BE74B2182D3F971C009786DF /* NetUtil.hpp */, + BE74B2192D3F971C009786DF /* NetUtil.cpp */, + BE74B21A2D3F971C009786DF /* ServerSocket.hpp */, + BE74B21B2D3F971C009786DF /* Socket.hpp */, + BE74B21C2D3F971C009786DF /* Socket.cpp */, + BE74B21D2D3F971C009786DF /* Ssl.hpp */, + BE74B21E2D3F971C009786DF /* Ssl.cpp */, + BE74B21F2D3F971C009786DF /* SslSocket.hpp */, + BE74B2202D3F971C009786DF /* WebSocketHandler.hpp */, + ); + path = net; + sourceTree = ""; + }; + BE74B1B42D3F9546009786DF /* wsd */ = { + isa = PBXGroup; + children = ( + BE74B2212D3F97AB009786DF /* Admin.hpp */, + BE74B2222D3F97AB009786DF /* Admin.cpp */, + BE74B2232D3F97AB009786DF /* AdminModel.hpp */, + BE74B2242D3F97AB009786DF /* AdminModel.cpp */, + BE74B2252D3F97AB009786DF /* Auth.hpp */, + BE74B2262D3F97AB009786DF /* Auth.cpp */, + BE74B2272D3F97AB009786DF /* ClientRequestDispatcher.hpp */, + BE74B2282D3F97AB009786DF /* ClientRequestDispatcher.cpp */, + BE74B2292D3F97AB009786DF /* ClientSession.hpp */, + BE74B22A2D3F97AB009786DF /* ClientSession.cpp */, + BE74B22B2D3F97AB009786DF /* ContentSecurityPolicy.hpp */, + BE74B22C2D3F97AB009786DF /* COOLWSD.hpp */, + BE74B22D2D3F97AB009786DF /* COOLWSD.cpp */, + BE74B22E2D3F97AB009786DF /* coolwsd-fork.cpp */, + BE74B22F2D3F97AB009786DF /* coolwsd-inproc.cpp */, + BE74B2302D3F97AB009786DF /* DocumentBroker.hpp */, + BE74B2312D3F97AB009786DF /* DocumentBroker.cpp */, + BE74B2322D3F97AB009786DF /* Exceptions.hpp */, + BE74B2332D3F97AB009786DF /* Exceptions.cpp */, + BE74B2342D3F97AB009786DF /* FileServer.hpp */, + BE74B2352D3F97AB009786DF /* FileServer.cpp */, + BE74B2362D3F97AB009786DF /* FileServerUtil.cpp */, + BE74B2372D3F97AB009786DF /* HostUtil.hpp */, + BE74B2382D3F97AB009786DF /* HostUtil.cpp */, + BE74B2392D3F97AB009786DF /* Process.hpp */, + BE74B23A2D3F97AB009786DF /* ProofKey.hpp */, + BE74B23B2D3F97AB009786DF /* ProofKey.cpp */, + BE74B23C2D3F97AB009786DF /* ProxyProtocol.hpp */, + BE74B23D2D3F97AB009786DF /* ProxyProtocol.cpp */, + BE74B23E2D3F97AB009786DF /* ProxyRequestHandler.hpp */, + BE74B23F2D3F97AB009786DF /* ProxyRequestHandler.cpp */, + BE74B2402D3F97AB009786DF /* QuarantineUtil.hpp */, + BE74B2412D3F97AB009786DF /* QuarantineUtil.cpp */, + BE74B2422D3F97AB009786DF /* RemoteConfig.hpp */, + BE74B2432D3F97AB009786DF /* RemoteConfig.cpp */, + BE74B2442D3F97AB009786DF /* RequestDetails.hpp */, + BE74B2452D3F97AB009786DF /* RequestDetails.cpp */, + BE74B2462D3F97AB009786DF /* RequestVettingStation.hpp */, + BE74B2472D3F97AB009786DF /* RequestVettingStation.cpp */, + BE74B2482D3F97AB009786DF /* SenderQueue.hpp */, + BE74B2492D3F97AB009786DF /* ServerAuditUtil.hpp */, + BE74B24A2D3F97AB009786DF /* ServerAuditUtil.cpp */, + BE74B24B2D3F97AB009786DF /* ServerURL.hpp */, + BE74B24C2D3F97AB009786DF /* SpecialBrokers.hpp */, + BE74B24D2D3F97AB009786DF /* SpecialBrokers.cpp */, + BE74B24E2D3F97AB009786DF /* Storage.hpp */, + BE74B24F2D3F97AB009786DF /* Storage.cpp */, + BE74B2502D3F97AB009786DF /* TestStubs.cpp */, + BE74B2512D3F97AB009786DF /* TileCache.hpp */, + BE74B2522D3F97AB009786DF /* TileCache.cpp */, + BE74B2532D3F97AB009786DF /* TileDesc.hpp */, + BE74B2542D3F97AB009786DF /* TraceFile.hpp */, + BE74B2552D3F97AB009786DF /* UserMessages.hpp */, + ); + path = wsd; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXLegacyTarget section */ + BE74B1AA2D3F80AA009786DF /* coolwsd */ = { + isa = PBXLegacyTarget; + buildArgumentsString = "-j $(ACTION)"; + buildConfigurationList = BE74B1AD2D3F80AA009786DF /* Build configuration list for PBXLegacyTarget "coolwsd" */; + buildPhases = ( + ); + buildToolPath = "$(PROJECT_DIR)/gmake-wrapper.sh"; + buildWorkingDirectory = "$(PROJECT_DIR)/../.."; + dependencies = ( + ); + name = coolwsd; + packageProductDependencies = ( + ); + passBuildSettingsInEnvironment = 1; + productName = coolwsd; + }; +/* End PBXLegacyTarget section */ + +/* Begin PBXProject section */ + BE74B1A62D3F80AA009786DF /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastUpgradeCheck = 1600; + TargetAttributes = { + BE74B1AA2D3F80AA009786DF = { + CreatedOnToolsVersion = 16.0; + }; + }; + }; + buildConfigurationList = BE74B1A92D3F80AA009786DF /* Build configuration list for PBXProject "coolwsd" */; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = BE74B1A52D3F80AA009786DF; + minimizedProjectReferenceProxies = 1; + preferredProjectObjectVersion = 77; + projectDirPath = ""; + projectRoot = ""; + targets = ( + BE74B1AA2D3F80AA009786DF /* coolwsd */, + ); + }; +/* End PBXProject section */ + +/* Begin XCBuildConfiguration section */ + BE74B1AB2D3F80AA009786DF /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + }; + name = Debug; + }; + BE74B1AC2D3F80AA009786DF /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + }; + name = Release; + }; + BE74B1AE2D3F80AA009786DF /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEBUGGING_SYMBOLS = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + DEVELOPMENT_TEAM = J4FQ687VJK; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + BE74B1AF2D3F80AA009786DF /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_TEAM = J4FQ687VJK; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + BE74B1A92D3F80AA009786DF /* Build configuration list for PBXProject "coolwsd" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + BE74B1AB2D3F80AA009786DF /* Debug */, + BE74B1AC2D3F80AA009786DF /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + BE74B1AD2D3F80AA009786DF /* Build configuration list for PBXLegacyTarget "coolwsd" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + BE74B1AE2D3F80AA009786DF /* Debug */, + BE74B1AF2D3F80AA009786DF /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = BE74B1A62D3F80AA009786DF /* Project object */; +} diff --git a/macos/coolwsd/coolwsd.xcodeproj/xcshareddata/xcschemes/coolwsd.xcscheme b/macos/coolwsd/coolwsd.xcodeproj/xcshareddata/xcschemes/coolwsd.xcscheme new file mode 100644 index 0000000000000..698f4abf021ea --- /dev/null +++ b/macos/coolwsd/coolwsd.xcodeproj/xcshareddata/xcschemes/coolwsd.xcscheme @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/macos/coolwsd/gmake-wrapper.sh.in b/macos/coolwsd/gmake-wrapper.sh.in new file mode 100644 index 0000000000000..29cc4ebb09c92 --- /dev/null +++ b/macos/coolwsd/gmake-wrapper.sh.in @@ -0,0 +1,6 @@ +#!/bin/sh + +HOMEBREW_PATH="@HOMEBREW_PATH@" +eval "$(@HOMEBREW_PATH@/bin/brew shellenv)" + +exec "@HOMEBREW_PATH@/bin/gmake" "$@" From 63828886ae4b4bab0f4e51c166bd470154715cbd Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 21 Jan 2025 14:11:20 +0100 Subject: [PATCH 094/177] Fix return values (and document them too) Signed-off-by: Jan Holesovsky Change-Id: I54e42f104b6eaa2a1253916ad108d5d0bc7d6bb5 --- common/Syscall.cpp | 36 ++++++++++++++++++------------------ common/Syscall.hpp | 10 ++++++++++ 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/common/Syscall.cpp b/common/Syscall.cpp index ffd684a8f9900..b676d1bfae833 100644 --- a/common/Syscall.cpp +++ b/common/Syscall.cpp @@ -37,17 +37,17 @@ namespace { * * Called "unsafe" because it keeps the file descriptor open on error, possibly leading to leaks. */ -int unsafe_set_fd_cloexec_nonblock(int fd, bool cloexec, bool nonblock) { +bool unsafe_set_fd_cloexec_nonblock(int fd, bool cloexec, bool nonblock) { // Set FD_CLOEXEC if the user wants it if (cloexec) { int fd_flags = fcntl(fd, F_GETFD); if (fd_flags == -1) - return -1; + return false; fd_flags |= FD_CLOEXEC; if (fcntl(fd, F_SETFD, fd_flags) == -1) - return -1; + return false; } // Set O_NONBLOCK if the user wants it @@ -55,22 +55,22 @@ int unsafe_set_fd_cloexec_nonblock(int fd, bool cloexec, bool nonblock) { { int fl_flags = fcntl(fd, F_GETFL); if (fl_flags == -1) - return -1; + return false; fl_flags |= O_NONBLOCK; if (fcntl(fd, F_SETFL, fl_flags) == -1) - return -1; + return false; } - return 0; + return true; } /** * Set FD_CLOEXEC and O_NONBLOCK on one file descriptor. */ -int set_fd_cloexec_nonblock(int fd, bool cloexec, bool nonblock) { - int ret = unsafe_set_fd_cloexec_nonblock(fd, cloexec, nonblock); - if (ret < 0) { +bool set_fd_cloexec_nonblock(int fd, bool cloexec, bool nonblock) { + bool ret = unsafe_set_fd_cloexec_nonblock(fd, cloexec, nonblock); + if (!ret) { int saved_errno = errno; close(fd); errno = saved_errno; @@ -82,20 +82,20 @@ int set_fd_cloexec_nonblock(int fd, bool cloexec, bool nonblock) { /** * Set CLOEXEC or NONBLOCK on both sides of the pipe/socket/... */ -int set_fds_cloexec_nonblock(int fds[2], bool cloexec, bool nonblock) { +bool set_fds_cloexec_nonblock(int fds[2], bool cloexec, bool nonblock) { for (int i = 0; i < 2; i++) { - int ret = unsafe_set_fd_cloexec_nonblock(fds[i], cloexec, nonblock); - if (ret < 0) { + bool ret = unsafe_set_fd_cloexec_nonblock(fds[i], cloexec, nonblock); + if (!ret) { int saved_errno = errno; close(fds[0]); close(fds[1]); errno = saved_errno; - return -1; + return false; } } - return 0; + return true; } } @@ -110,7 +110,7 @@ int Syscall::accept_cloexec_nonblock(int socket, struct sockaddr *address, sockl if (fd < 0) return fd; - return set_fd_cloexec_nonblock(fd, true, true); + return set_fd_cloexec_nonblock(fd, true, true)? fd: -1; #endif } @@ -152,7 +152,7 @@ int Syscall::pipe2(int pipefd[2], int flags) if (pipe(pipefd) < 0) return -1; - return set_fds_cloexec_nonblock(pipefd, flags & O_CLOEXEC, flags & O_NONBLOCK); + return set_fds_cloexec_nonblock(pipefd, flags & O_CLOEXEC, flags & O_NONBLOCK)? 0: -1; #endif } @@ -164,7 +164,7 @@ int Syscall::socket_cloexec_nonblock(int domain, int type, int protocol) { if (fd < 0) return fd; - return set_fd_cloexec_nonblock(fd, true, true); + return set_fd_cloexec_nonblock(fd, true, true)? fd: -1; #endif } @@ -177,7 +177,7 @@ int Syscall::socketpair_cloexec_nonblock(int domain, int type, int protocol, int if (rc < 0) return rc; - return set_fds_cloexec_nonblock(socket_vector, true, true); + return set_fds_cloexec_nonblock(socket_vector, true, true)? 0: -1; #endif } diff --git a/common/Syscall.hpp b/common/Syscall.hpp index 5dd2aaaba23ff..d8a98d7e0d626 100644 --- a/common/Syscall.hpp +++ b/common/Syscall.hpp @@ -24,26 +24,36 @@ namespace Syscall { /** * Implement an equivalent of accept4() with CLOEXEC and NONBLOCK set. + * + * @return the accepted socket, or -1 on error */ int accept_cloexec_nonblock(int socket, struct sockaddr *address, socklen_t *address_len); /** * Retrieve the PID of the peer connected on this Unix-domain socket. + * + * @return peer's PID, or -1 on error */ int get_peer_pid(int socket); /** * Implement pipe2() on platforms that don't have it. + * + * @return 0 on success, -1 on error */ int pipe2(int pipefd[2], int flags); /** * Implement socket() with CLOEXEC and NONBLOCK on platforms that don't have those flags. + * + * @return file descriptor of the socket, or -1 on error */ int socket_cloexec_nonblock(int domain, int type, int protocol); /** * Implement socket_pair() with CLOEXEC and NONBLOCK on platforms that don't have those flags. + * + * @return 0 on success, -1 on error */ int socketpair_cloexec_nonblock(int domain, int type, int protocol, int socket_vector[2]); } From 0334718c6fab6ac86709b6a9a7cdfc6c8255787f Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 21 Jan 2025 15:01:55 +0100 Subject: [PATCH 095/177] Actually let's experiment with coolwsd-inproc for the moment This saves us trouble with the nocap setting and whatnot. Let's do a prototype first, and then see how we need to set this and that. Signed-off-by: Jan Holesovsky Change-Id: Iebc4ec436cd1d2922c28b987349edb209a44ef8e --- .../coolwsd.xcodeproj/xcshareddata/xcschemes/coolwsd.xcscheme | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/macos/coolwsd/coolwsd.xcodeproj/xcshareddata/xcschemes/coolwsd.xcscheme b/macos/coolwsd/coolwsd.xcodeproj/xcshareddata/xcschemes/coolwsd.xcscheme index 698f4abf021ea..3484fb599fbc1 100644 --- a/macos/coolwsd/coolwsd.xcodeproj/xcshareddata/xcschemes/coolwsd.xcscheme +++ b/macos/coolwsd/coolwsd.xcodeproj/xcshareddata/xcschemes/coolwsd.xcscheme @@ -43,7 +43,7 @@ + FilePath = "../../coolwsd-inproc"> Date: Tue, 21 Jan 2025 15:03:08 +0100 Subject: [PATCH 096/177] Set correct paths for macOS Signed-off-by: Jan Holesovsky Change-Id: I86e47fe655f462f969ff6d44a43dd5c03b3be253 --- kit/Kit.cpp | 41 ++++++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/kit/Kit.cpp b/kit/Kit.cpp index 2d12cef60fe51..a2726c7976a3a 100644 --- a/kit/Kit.cpp +++ b/kit/Kit.cpp @@ -3433,7 +3433,11 @@ void lokit_main( = std::chrono::steady_clock::now(); userdir_url = "file:///tmp/user"; +#ifndef __APPLE__ instdir_path = '/' + std::string(JailUtil::LO_JAIL_SUBPATH) + "/program"; +#else + instdir_path = '/' + std::string(JailUtil::LO_JAIL_SUBPATH) + "/Contents/Frameworks"; +#endif allowedPaths += ":r:/" + std::string(JailUtil::LO_JAIL_SUBPATH); Poco::Path jailLOInstallation(jailPath, JailUtil::LO_JAIL_SUBPATH); @@ -3764,7 +3768,11 @@ void lokit_main( LOG_INF("Using template [" << loTemplate << "] as install subpath directly, without chroot jail setup."); userdir_url = "file://" + jailPathStr + "tmp/user"; +#ifndef __APPLE__ instdir_path = '/' + loTemplate + "/program"; +#else + instdir_path = '/' + loTemplate + "/Contents/Frameworks"; +#endif allowedPaths += ":r:" + loTemplate; JailRoot = jailPathStr; @@ -3938,11 +3946,10 @@ void lokit_main( #if (defined(__linux__) && !defined(__ANDROID__)) || defined(__FreeBSD__) Poco::URI userInstallationURI("file", LO_PATH); LibreOfficeKit *kit = lok_init_2(LO_PATH "/program", userInstallationURI.toString().c_str()); -#elif defined(MACOS) && MOBILEAPP +#elif defined(MACOS) + // this is the MACOS MOBILEAPP case LibreOfficeKit *kit = lok_init_2((getBundlePath() + "/Contents/lokit/Frameworks").c_str(), getAppSupportURL().c_str()); -#else - -#ifdef IOS // In the iOS app we call lok_init_2() just once, when the app starts +#elif defined(IOS) // In the iOS app we call lok_init_2() just once, when the app starts static LibreOfficeKit *kit = lo_kit; #elif defined(_WIN32) // LO_PATH is a Windows path starting with a drive letter. For the second parameter to @@ -3951,8 +3958,6 @@ void lokit_main( #else // FIXME: I wonder for which platform this is supposed to be? Android? static LibreOfficeKit *kit = lok_init_2(nullptr, nullptr); -#endif - #endif assert(kit); @@ -4110,7 +4115,11 @@ void consistencyCheckJail() if ((failedTmp = (!tmp.good() || !tmp.isDirectory()))) LOG_ERR("Fatal system error: Kit jail is missing its /tmp directory"); +#ifndef __APPLE__ FileUtil::Stat lo(InstDirPath + "/unorc"); +#else + FileUtil::Stat lo(InstDirPath + "/../Resources/ure/etc/unorc"); +#endif if ((failedLo = (!lo.good() || !lo.isFile()))) LOG_ERR("Fatal system error: Kit jail is missing its LibreOfficeKit directory at '" << InstDirPath << "'"); @@ -4225,7 +4234,11 @@ bool globalPreinit(const std::string &loTemplate) // we deliberately don't dlclose handle on success, make it // static so static analysis doesn't see this as a leak static void *handle; +#ifndef __APPLE__ std::string libMerged = loTemplate + "/program/libmergedlo.so"; +#else + std::string libMerged = loTemplate + "/Contents/Frameworks/libmergedlo.dylib"; +#endif if (File(libMerged).exists()) { LOG_TRC("dlopen(" << libMerged << ", RTLD_GLOBAL|RTLD_NOW)"); @@ -4239,7 +4252,11 @@ bool globalPreinit(const std::string &loTemplate) } else { +#ifndef __APPLE__ std::string libSofficeapp = loTemplate + "/program/libsofficeapp.so"; +#else + std::string libSofficeapp = loTemplate + "/Contents/Frameworks/libsofficeapp.dylib"; +#endif if (File(libSofficeapp).exists()) { LOG_TRC("dlopen(" << libSofficeapp << ", RTLD_GLOBAL|RTLD_NOW)"); @@ -4284,9 +4301,15 @@ bool globalPreinit(const std::string &loTemplate) "javaloader javavm jdbc rpt rptui rptxml ", 0 /* no overwrite */); - LOG_TRC("Invoking lok_preinit_2(" << loTemplate << "/program\", \"file:///tmp/user\")"); +#ifndef __APPLE__ + const std::string lokProgramDir = loTemplate + "/program"; +#else + const std::string lokProgramDir = loTemplate + "/Contents/Frameworks"; +#endif + + LOG_TRC("Invoking lok_preinit_2(" << lokProgramDir << ", \"file:///tmp/user\")"); const auto start = std::chrono::steady_clock::now(); - if (preInit((loTemplate + "/program").c_str(), "file:///tmp/user", &loKitPtr) != 0) + if (preInit(lokProgramDir.c_str(), "file:///tmp/user", &loKitPtr) != 0) { LOG_FTL("lok_preinit() in " << loadedLibrary << " failed"); dlclose(handle); @@ -4295,7 +4318,7 @@ bool globalPreinit(const std::string &loTemplate) LOG_DBG("After lok_preinit_2: loKitPtr=" << loKitPtr); - LOG_TRC("Finished lok_preinit(" << loTemplate << "/program\", \"file:///tmp/user\") in " + LOG_TRC("Finished lok_preinit(" << lokProgramDir << ", \"file:///tmp/user\") in " << std::chrono::duration_cast( std::chrono::steady_clock::now() - start)); return true; From 823302e7fccb7ba1fafa78bd88e32b2480934791 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 27 Jan 2025 09:20:20 +0100 Subject: [PATCH 097/177] iconv behaves a bit weirdly on macOS That it adds/leaves the traising minus/dash ("-") at the end is OK-ish, from what I read in the spec, this should be fine. But that converting utf8 -> utf7 -> utf8 ends up adding the dash, that's not OK I think; but it is what it returns... Hopefully not a big issue for CODA-M, we'll see. Signed-off-by: Jan Holesovsky Change-Id: I2efec7f90b9871f327aa2433ac701740f07591c4 --- test/UtilTests.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/UtilTests.cpp b/test/UtilTests.cpp index 6241762a16557..85aede8bd3ae7 100644 --- a/test/UtilTests.cpp +++ b/test/UtilTests.cpp @@ -164,7 +164,12 @@ void UtilTests::testCharacterConverter() constexpr std::string_view testname = __func__; const std::string utf8 = "Ḽơᶉëᶆ ȋṕšᶙṁ ḍỡḽǭᵳ ʂǐť"; +#ifndef __APPLE__ const std::string utf7 = "+HjwBoR2JAOsdhg +AgseVQFhHZkeQQ +Hg0e4R49Ae0dcw +AoIB0AFl-"; +#else + // The macOS iconv gives slightly different results + const std::string utf7 = "+HjwBoR2JAOsdhg +AgseVQFhHZkeQQ +Hg0e4R49Ae0dcw +AoIB0AFl"; +#endif { Util::CharacterConverter utf8_to_7("UTF-8", "UTF-7"); LOK_ASSERT_EQUAL_STR(utf7, utf8_to_7.convert(utf8)); @@ -178,8 +183,14 @@ void UtilTests::testCharacterConverter() { const std::string utf8l = R"xxx(ăѣ𝔠ծềſģȟᎥ𝒋ǩľḿꞑȯ𝘱𝑞𝗋𝘴ȶ𝞄𝜈ψ𝒙𝘆𝚣1234567890!@#$%^&*()-_=+[{]};:'",<.>/?~𝘈Ḇ𝖢𝕯٤ḞԍНǏ𝙅ƘԸⲘ𝙉০Ρ𝗤Ɍ𝓢ȚЦ𝒱Ѡ𝓧ƳȤѧᖯć𝗱ễ𝑓𝙜Ⴙ𝞲𝑗𝒌ļṃʼnо𝞎𝒒ᵲꜱ𝙩ừ𝗏ŵ𝒙𝒚ź1234567890!@#$%^&*()-_=+[{]};:'",<.>/?~АḂⲤ𝗗𝖤𝗙ꞠꓧȊ𝐉𝜥ꓡ𝑀𝑵Ǭ𝙿𝑄Ŗ𝑆𝒯𝖴𝘝𝘞ꓫŸ𝜡ả𝘢ƀ𝖼ḋếᵮℊ𝙝Ꭵ𝕛кιṃդⱺ𝓅𝘲𝕣𝖘ŧ𝑢ṽẉ𝘅ყž1234567890!@#$%^&*()-_=+[{]};:'",<.>/?~Ѧ𝙱ƇᗞΣℱԍҤ١𝔍К𝓛𝓜ƝȎ𝚸𝑄Ṛ𝓢ṮṺƲᏔꓫ𝚈𝚭𝜶Ꮟçძ𝑒𝖿𝗀ḧ𝗂𝐣ҝɭḿ𝕟𝐨𝝔𝕢ṛ𝓼тú𝔳ẃ⤬𝝲𝗓1234567890!@#$%^&*()-_=+[{]};:'",<.>/?~𝖠Β𝒞𝘋𝙴𝓕ĢȞỈ𝕵ꓗʟ𝙼ℕ০𝚸𝗤ՀꓢṰǓⅤ𝔚Ⲭ𝑌𝙕𝘢𝕤)xxx"; +#ifndef __APPLE__ const std::string utf7l = R"xxx(+AQMEY9g13SAFbh7BAX8BIwIfE6XYNdyLAekBPh4/p5ECL9g13jHYNdxe2DXdy9g13jQCNtg134TYNd8IA8jYNdyZ2DXeBtg13qM-1234567890+ACEAQAAjACQAJQBeACYAKg()-+AF8APQArAFsAewBdAH0AOw:'+ACI,+ADw.+AD4-/?+AH7YNd4IHgbYNd2i2DXdbwZkHh4FDQQdAc/YNd5FAZgFOCyY2DXeSQnmA6HYNd3kAkzYNdziAhoEJtg13LEEYNg13OcBswIkBGcVrwEH2DXd8R7F2DXcU9g13lwQudg137LYNdxX2DXcjAE8HkMBSQQ+2DXfjtg13JIdcqcx2DXeaR7r2DXdzwF12DXcmdg13JoBeg-1234567890+ACEAQAAjACQAJQBeACYAKg()-+AF8APQArAFsAewBdAH0AOw:'+ACI,+ADw.+AD4-/?+AH4EEB4CLKTYNd3X2DXdpNg13dmnoKTnAgrYNdwJ2DXfJaTh2DXcQNg13HUB7Ng13n/YNdxEAVbYNdxG2DXcr9g13bTYNd4d2DXeHqTrAXjYNd8hHqPYNd4iAYDYNd28Hgsevx1uIQrYNd5dE6XYNd1bBDoDuR5DBWQsetg13MXYNd4y2DXdY9g13ZgBZ9g13GIefR6J2DXeBRDnAX4-1234567890+ACEAQAAjACQAJQBeACYAKg()-+AF8APQArAFsAewBdAH0AOw:'+ACI,+ADw.+AD4-/?+AH4EZtg13nEBhxXeA6MhMQUNBKQGYdg13Q0EGtg13NvYNdzcAZ0CDtg13rjYNdxEHlrYNdziHm4eegGyE9Sk69g13ojYNd6t2DXfNhPPAOcQ69g13FLYNd2/2DXdwB4n2DXdwtg13CMEnQJtHj/YNd1f2DXcKNg131TYNd1iHlvYNdz8BEIA+tg13TMegyks2DXfctg13dM-1234567890+ACEAQAAjACQAJQBeACYAKg()-+AF8APQArAFsAewBdAH0AOw:'+ACI,+ADw.+AD4-/?+AH7YNd2gA5LYNdye2DXeC9g13nTYNdzVASICHh7I2DXddaTXAp/YNd58IRUJ5tg13rjYNd3kBUCk4h5wAdMhZNg13RosrNg13EzYNd5V2DXeItg13WQ-)xxx"; +#else + // The macOS iconv gives slightly different results + const std::string utf7l = + R"xxx(+AQMEY9g13SAFbh7BAX8BIwIfE6XYNdyLAekBPh4/p5ECL9g13jHYNdxe2DXdy9g13jQCNtg134TYNd8IA8jYNdyZ2DXeBtg13qM-1234567890+ACEAQAAjACQAJQBeACYAKg()-+AF8APQ-+-+AFsAewBdAH0AOw:'+ACI,+ADw.+AD4-/?+AH7YNd4IHgbYNd2i2DXdbwZkHh4FDQQdAc/YNd5FAZgFOCyY2DXeSQnmA6HYNd3kAkzYNdziAhoEJtg13LEEYNg13OcBswIkBGcVrwEH2DXd8R7F2DXcU9g13lwQudg137LYNdxX2DXcjAE8HkMBSQQ+2DXfjtg13JIdcqcx2DXeaR7r2DXdzwF12DXcmdg13JoBeg-1234567890+ACEAQAAjACQAJQBeACYAKg()-+AF8APQ-+-+AFsAewBdAH0AOw:'+ACI,+ADw.+AD4-/?+AH4EEB4CLKTYNd3X2DXdpNg13dmnoKTnAgrYNdwJ2DXfJaTh2DXcQNg13HUB7Ng13n/YNdxEAVbYNdxG2DXcr9g13bTYNd4d2DXeHqTrAXjYNd8hHqPYNd4iAYDYNd28Hgsevx1uIQrYNd5dE6XYNd1bBDoDuR5DBWQsetg13MXYNd4y2DXdY9g13ZgBZ9g13GIefR6J2DXeBRDnAX4-1234567890+ACEAQAAjACQAJQBeACYAKg()-+AF8APQ-+-+AFsAewBdAH0AOw:'+ACI,+ADw.+AD4-/?+AH4EZtg13nEBhxXeA6MhMQUNBKQGYdg13Q0EGtg13NvYNdzcAZ0CDtg13rjYNdxEHlrYNdziHm4eegGyE9Sk69g13ojYNd6t2DXfNhPPAOcQ69g13FLYNd2/2DXdwB4n2DXdwtg13CMEnQJtHj/YNd1f2DXcKNg131TYNd1iHlvYNdz8BEIA+tg13TMegyks2DXfctg13dM-1234567890+ACEAQAAjACQAJQBeACYAKg()-+AF8APQ-+-+AFsAewBdAH0AOw:'+ACI,+ADw.+AD4-/?+AH7YNd2gA5LYNdye2DXeC9g13nTYNdzVASICHh7I2DXddaTXAp/YNd58IRUJ5tg13rjYNd3kBUCk4h5wAdMhZNg13RosrNg13EzYNd5V2DXeItg13WQ-)xxx"; +#endif Util::CharacterConverter utf8_to_7("UTF-8", "UTF-7"); LOK_ASSERT_EQUAL_STR(utf7, utf8_to_7.convert(utf8)); @@ -189,9 +200,13 @@ void UtilTests::testCharacterConverter() Util::CharacterConverter utf7_to_8("UTF-7", "UTF-8"); LOK_ASSERT_EQUAL_STR(utf8, utf7_to_8.convert(utf7)); +#ifndef __APPLE__ LOK_ASSERT_EQUAL_STR(utf8l, utf7_to_8.convert(utf7l)); +#endif LOK_ASSERT_EQUAL_STR(utf8, utf7_to_8.convert(utf7)); +#ifndef __APPLE__ LOK_ASSERT_EQUAL_STR(utf8l, utf7_to_8.convert(utf7l)); +#endif } } From e4aa3bf8a6c91c4eec7e2737ae2ea919f00acff1 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 27 Jan 2025 12:56:20 +0100 Subject: [PATCH 098/177] Disable SSL in the debug run from Xcode for easier debugging Signed-off-by: Jan Holesovsky Change-Id: I15df1cfe682ffa52652154ddc8aebb83519dfc8e --- .../coolwsd.xcodeproj/xcshareddata/xcschemes/coolwsd.xcscheme | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/macos/coolwsd/coolwsd.xcodeproj/xcshareddata/xcschemes/coolwsd.xcscheme b/macos/coolwsd/coolwsd.xcodeproj/xcshareddata/xcschemes/coolwsd.xcscheme index 3484fb599fbc1..ecf637057e06e 100644 --- a/macos/coolwsd/coolwsd.xcodeproj/xcshareddata/xcschemes/coolwsd.xcscheme +++ b/macos/coolwsd/coolwsd.xcodeproj/xcshareddata/xcschemes/coolwsd.xcscheme @@ -83,6 +83,10 @@ argument = "--o:trace_event[@enable]=true" isEnabled = "YES"> + + From 7eaea86f9cb2e6fe814753cb82794b44c3f9cc31 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 27 Jan 2025 15:26:59 +0100 Subject: [PATCH 099/177] coda-m: Fix build Signed-off-by: Jan Holesovsky Change-Id: I19969cbdd62f415a1df37a80876d99773b251035 --- macos/coda/coda.xcodeproj/project.pbxproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/macos/coda/coda.xcodeproj/project.pbxproj b/macos/coda/coda.xcodeproj/project.pbxproj index 07b8cd68f4c08..573ab3b6d7ce5 100644 --- a/macos/coda/coda.xcodeproj/project.pbxproj +++ b/macos/coda/coda.xcodeproj/project.pbxproj @@ -55,6 +55,7 @@ BEA264B32CBE99340007435A /* DocumentBroker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA264A72CBE99340007435A /* DocumentBroker.cpp */; }; BEA264B42CBE99340007435A /* RequestVettingStation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA264AA2CBE99340007435A /* RequestVettingStation.cpp */; }; BEEF3F862CE2139E00ABE785 /* coolkitconfig.xcu in Resources */ = {isa = PBXBuildFile; fileRef = BEEF3F852CE2139E00ABE785 /* coolkitconfig.xcu */; }; + BEF9E17F2D47C709004FCEB5 /* Unit-mobile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEF9E17E2D47C709004FCEB5 /* Unit-mobile.cpp */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -152,6 +153,7 @@ BECC4BC62CBD3FA400A120B3 /* codaUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = codaUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; BEEF3F822CE20BDD00ABE785 /* SetupKitEnvironment.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = SetupKitEnvironment.hpp; path = ../../../../kit/SetupKitEnvironment.hpp; sourceTree = ""; }; BEEF3F852CE2139E00ABE785 /* coolkitconfig.xcu */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = coolkitconfig.xcu; path = ../../../coolkitconfig.xcu; sourceTree = ""; }; + BEF9E17E2D47C709004FCEB5 /* Unit-mobile.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "Unit-mobile.cpp"; path = "../../../../common/Unit-mobile.cpp"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFileSystemSynchronizedRootGroup section */ @@ -245,6 +247,7 @@ BEA263662CBE38E20007435A /* TraceEvent.cpp */, BEA263672CBE38E20007435A /* Unit.hpp */, BEA263682CBE38E20007435A /* Unit.cpp */, + BEF9E17E2D47C709004FCEB5 /* Unit-mobile.cpp */, BEA263692CBE38E20007435A /* Uri.hpp */, BEA2636A2CBE38E20007435A /* Uri.cpp */, BEA2636B2CBE38E20007435A /* Util.hpp */, @@ -541,6 +544,7 @@ BEA263762CBE38E20007435A /* SpookyV2.cpp in Sources */, BEA264AD2CBE99340007435A /* Storage.cpp in Sources */, BEA264AE2CBE99340007435A /* TileCache.cpp in Sources */, + BEF9E17F2D47C709004FCEB5 /* Unit-mobile.cpp in Sources */, BEA264AF2CBE99340007435A /* COOLWSD.cpp in Sources */, BEA264B02CBE99340007435A /* ClientSession.cpp in Sources */, BEA264B12CBE99340007435A /* RequestDetails.cpp in Sources */, From dc00d2a90c52835461e7d235b557210b529394b8 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 27 Jan 2025 15:24:45 +0100 Subject: [PATCH 100/177] Refactor in preparation for platform-dependent implementation On macOS, we don't have /proc. Signed-off-by: Jan Holesovsky Change-Id: I4231408abf5921513fb75224653f93b2a26816bd --- common/Util-mobile.cpp | 3 --- common/Util-server.cpp | 59 +++++++++++++++++++++++++++--------------- common/Util.hpp | 29 ++++++--------------- 3 files changed, 46 insertions(+), 45 deletions(-) diff --git a/common/Util-mobile.cpp b/common/Util-mobile.cpp index e0c4c98fcebd3..57c6b8897e190 100644 --- a/common/Util-mobile.cpp +++ b/common/Util-mobile.cpp @@ -15,9 +15,6 @@ namespace Util { /// No-op implementation of desktop only functions -DirectoryCounter::DirectoryCounter(const char*) { (void)_tasks; } -DirectoryCounter::~DirectoryCounter() {} -int DirectoryCounter::count() { return 0; } int spawnProcess(const std::string&, const StringVector&) { return 0; } std::string getHumanizedBytes(unsigned long) { return std::string(); } diff --git a/common/Util-server.cpp b/common/Util-server.cpp index 69336b217fe2d..4bea6224162d8 100644 --- a/common/Util-server.cpp +++ b/common/Util-server.cpp @@ -144,34 +144,51 @@ std::size_t getFromCGroupV2(const std::string& key) namespace Util { -DirectoryCounter::DirectoryCounter(const char* procPath) - : _tasks(opendir(procPath)) -{ - if (!_tasks) - LOG_ERR("No proc mounted, can't count threads"); -} -DirectoryCounter::~DirectoryCounter() { closedir(reinterpret_cast(_tasks)); } +class CounterImpl { +private: + DIR* _dir = nullptr; -int DirectoryCounter::count() -{ - auto dir = reinterpret_cast(_tasks); - - if (!dir) - return -1; +public: + CounterImpl(const char* procPath) + : _dir(opendir(procPath)) + { + if (!_dir) + LOG_ERR("No proc mounted for procPath " << procPath << ", can't count threads"); + } - rewinddir(dir); + ~CounterImpl() { closedir(_dir); } - int tasks = 0; - struct dirent* i; - while ((i = readdir(dir))) + int count() { - if (i->d_name[0] != '.') - tasks++; + if (!_dir) + return -1; + + rewinddir(_dir); + + int tasks = 0; + struct dirent* i; + while ((i = readdir(_dir))) + { + if (i->d_name[0] != '.') + tasks++; + } + + return tasks; } +}; - return tasks; -} +ThreadCounter::ThreadCounter() : _impl(new CounterImpl("/proc/self/task")) {} + +ThreadCounter::~ThreadCounter() = default; + +int ThreadCounter::count() { return _impl->count(); } + +FDCounter::FDCounter() : _impl(new CounterImpl("/proc/self/fd")) {} + +FDCounter::~FDCounter() = default; + +int FDCounter::count() { return _impl->count(); } #ifdef __FreeBSD__ ThreadCounter::ThreadCounter() { pid = getpid(); } diff --git a/common/Util.hpp b/common/Util.hpp index a6d83dac9cba7..981bc0cddeffc 100644 --- a/common/Util.hpp +++ b/common/Util.hpp @@ -173,41 +173,28 @@ namespace Util uint64_t _startSys; }; - class DirectoryCounter - { - void *_tasks; - public: - DirectoryCounter(const char *procPath); - ~DirectoryCounter(); - /// Get number of items in this directory or -1 on error - int count(); - }; + class CounterImpl; - #ifdef __FreeBSD__ /// Needs to open dirent before forking in Kit process class ThreadCounter { - pid_t pid; + std::unique_ptr _impl; public: ThreadCounter(); ~ThreadCounter(); /// Get number of items in this directory or -1 on error int count(); }; - #else - /// Needs to open dirent before forking in Kit process - class ThreadCounter : public DirectoryCounter - { - public: - ThreadCounter() : DirectoryCounter("/proc/self/task") {} - }; - #endif /// Needs to open dirent before forking in Kit process - class FDCounter : public DirectoryCounter + class FDCounter { + std::unique_ptr _impl; public: - FDCounter() : DirectoryCounter("/proc/self/fd") {} + FDCounter(); + ~FDCounter(); + /// Get number of items in this directory or -1 on error + int count(); }; /// Spawn a process. From bd49af9d2e3cef3e96bfb09d3c01b10d65fe1e25 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 27 Jan 2025 16:06:34 +0100 Subject: [PATCH 101/177] Move the (Thread|FD)Counter to Util-linux and provide macOS impl Signed-off-by: Jan Holesovsky Change-Id: I357ccc3f12755725de70c6edd43fa74c5655ec4a --- Makefile.am | 11 ++ common/Util-freebsd.cpp | 113 ++++++++++++++++++ common/Util-linux.cpp | 81 +++++++++++++ common/Util-macos.cpp | 74 ++++++++++++ common/Util-server.cpp | 82 ------------- .../coolwsd/coolwsd.xcodeproj/project.pbxproj | 2 + test/Makefile.am | 9 +- 7 files changed, 289 insertions(+), 83 deletions(-) create mode 100644 common/Util-freebsd.cpp create mode 100644 common/Util-linux.cpp create mode 100644 common/Util-macos.cpp diff --git a/Makefile.am b/Makefile.am index 79276481036f0..e17f68d328b29 100644 --- a/Makefile.am +++ b/Makefile.am @@ -126,6 +126,12 @@ coolwsd_LDADD += ${OPENSSL_LIBS} coolconfig_LDADD += ${OPENSSL_LIBS} endif +if ENABLE_MACOS +util_platform_cpp = common/Util-macos.cpp +else +util_platform_cpp = common/Util-linux.cpp +endif + AM_ETAGSFLAGS = --c++-kinds=+p --fields=+iaS --extra=+q -R --totals=yes --exclude=browser/node_modules --exclude=browser/dist * AM_CTAGSFLAGS = $(AM_ETAGSFLAGS) @@ -148,6 +154,7 @@ shared_sources = common/FileUtil.cpp \ common/Uri.cpp \ common/Util.cpp \ common/Util-server.cpp \ + $(util_platform_cpp) \ common/Util-unix.cpp \ common/ConfigUtil.cpp \ common/Authorization.cpp \ @@ -224,6 +231,7 @@ connect_SOURCES = tools/Connect.cpp \ common/StringVector.cpp \ common/Util.cpp \ common/Util-server.cpp \ + $(util_platform_cpp) \ common/Util-unix.cpp connect_LDADD = libglobals.a @@ -236,6 +244,7 @@ lokitclient_SOURCES = common/Log.cpp \ common/TraceEvent.cpp \ common/Util.cpp \ common/Util-server.cpp \ + $(util_platform_cpp) \ common/Util-unix.cpp lokitclient_LDADD = libglobals.a @@ -342,6 +351,7 @@ clientnb_SOURCES = net/clientnb.cpp \ common/StringVector.cpp \ common/Util.cpp \ common/Util-server.cpp \ + $(util_platform_cpp) \ common/Util-unix.cpp clientnb_LDADD = libsimd.a libglobals.a @@ -357,6 +367,7 @@ coolbench_SOURCES = tools/Benchmark.cpp \ common/StringVector.cpp \ common/Util.cpp \ common/Util-server.cpp \ + $(util_platform_cpp) \ common/Util-unix.cpp \ common/Simd.cpp diff --git a/common/Util-freebsd.cpp b/common/Util-freebsd.cpp new file mode 100644 index 0000000000000..280e4a5498a63 --- /dev/null +++ b/common/Util-freebsd.cpp @@ -0,0 +1,113 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * Copyright the Collabora Online contributors. + * + * SPDX-License-Identifier: MPL-2.0 + * + * 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 + +#include "Util.hpp" + +#ifdef __linux__ +#include +#include +#elif defined __FreeBSD__ +#include +#endif + +#include + +#include +#include +#include + +#include +#include "Log.hpp" + +namespace Util +{ + +// TODO FIXME This should be shared with common/Util-linux.cpp, not a copy of that +class CounterImpl { +private: + DIR* _dir = nullptr; + +public: + CounterImpl(const char* procPath) + : _dir(opendir(procPath)) + { + if (!_dir) + LOG_ERR("No proc mounted for procPath " << procPath << ", can't count threads"); + } + + ~CounterImpl() { closedir(_dir); } + + int count() + { + if (!_dir) + return -1; + + rewinddir(_dir); + + int tasks = 0; + struct dirent* i; + while ((i = readdir(_dir))) + { + if (i->d_name[0] != '.') + tasks++; + } + + return tasks; + } +}; + +// TODO FIXME This is just a copy from a3334b96cdb25e1b6e90bb1a7313222b59658cc9, should be made to work +ThreadCounter::ThreadCounter() { pid = getpid(); } + +ThreadCounter::~ThreadCounter() {} + +int ThreadCounter::count() +{ + size_t len = 0, olen = 0; + struct kinfo_proc* kipp = NULL; + int name[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID | KERN_PROC_INC_THREAD, pid }; + int error = sysctl(name, 4, NULL, &len, NULL, 0); + if (len == 0 || (error < 0 && errno != EPERM)) { + goto fail; + } + do + { + len += len / 10; + kipp = (struct kinfo_proc *) reallocf(kipp, len); + if (kipp == NULL) + { + goto fail; + } + olen = len; + error = sysctl(name, 4, kipp, &len, NULL, 0); + } while (error < 0 && errno == ENOMEM && olen == len); + + if (error < 0 && errno != EPERM) { + goto fail; + } + return len / sizeof(*kipp); + +fail: + if (kipp) + free(kipp); + return 0; +} + +FDCounter::FDCounter() : _impl(new CounterImpl("/proc/self/fd")) {} + +FDCounter::~FDCounter() = default; + +int FDCounter::count() { return _impl->count(); } + +} // namespace Util + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/common/Util-linux.cpp b/common/Util-linux.cpp new file mode 100644 index 0000000000000..34878d307b207 --- /dev/null +++ b/common/Util-linux.cpp @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * Copyright the Collabora Online contributors. + * + * SPDX-License-Identifier: MPL-2.0 + * + * 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 + +#include "Util.hpp" + +#ifdef __linux__ +#include +#include +#elif defined __FreeBSD__ +#include +#endif + +#include + +#include +#include +#include + +#include +#include "Log.hpp" + +namespace Util +{ + +class CounterImpl { +private: + DIR* _dir = nullptr; + +public: + CounterImpl(const char* procPath) + : _dir(opendir(procPath)) + { + if (!_dir) + LOG_ERR("No proc mounted for procPath " << procPath << ", can't count threads"); + } + + ~CounterImpl() { closedir(_dir); } + + int count() + { + if (!_dir) + return -1; + + rewinddir(_dir); + + int tasks = 0; + struct dirent* i; + while ((i = readdir(_dir))) + { + if (i->d_name[0] != '.') + tasks++; + } + + return tasks; + } +}; + +ThreadCounter::ThreadCounter() : _impl(new CounterImpl("/proc/self/task")) {} + +ThreadCounter::~ThreadCounter() = default; + +int ThreadCounter::count() { return _impl->count(); } + +FDCounter::FDCounter() : _impl(new CounterImpl("/proc/self/fd")) {} + +FDCounter::~FDCounter() = default; + +int FDCounter::count() { return _impl->count(); } + +} // namespace Util + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/common/Util-macos.cpp b/common/Util-macos.cpp new file mode 100644 index 0000000000000..894d7dcbf1e11 --- /dev/null +++ b/common/Util-macos.cpp @@ -0,0 +1,74 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * Copyright the Collabora Online contributors. + * + * SPDX-License-Identifier: MPL-2.0 + * + * 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 + +#include "Util.hpp" + +#include +#include +#include + +#include +#include "Log.hpp" + +namespace Util +{ + +/** Nothing to do for macOS, everything is implemented directly in the count() methods. */ +class CounterImpl {}; + +ThreadCounter::ThreadCounter() : _impl(new CounterImpl()) {} + +ThreadCounter::~ThreadCounter() {} + +int ThreadCounter::count() { + // use the Mach task_threads approach: + mach_msg_type_number_t threadCount = 0; + thread_act_array_t threadList; + + kern_return_t kr = task_threads(mach_task_self(), &threadList, &threadCount); + if (kr != KERN_SUCCESS) { + return -1; + } + + // deallocate the array not to leak memory + vm_deallocate(mach_task_self(), (vm_address_t)threadList, threadCount * sizeof(thread_t)); + + return (int)threadCount; +} + +FDCounter::FDCounter() : _impl(new CounterImpl()) {} + +FDCounter::~FDCounter() {} + +int FDCounter::count() { + // there's no /proc/self/fd, let's use the naive approach: + // Iterate from 0..getdtablesize()-1 and call fcntl(fd, F_GETFD). + // NB. a bit slower but hopefully workable for a typical range. + int maxFD = getdtablesize(); + if (maxFD < 0) { + return -1; + } + + int count = 0; + for (int fd = 0; fd < maxFD; ++fd) { + // If fcntl works, the FD is in use + if (fcntl(fd, F_GETFD) != -1) { + count++; + } + } + + return count; +} + +} // namespace Util + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/common/Util-server.cpp b/common/Util-server.cpp index 4bea6224162d8..ee00a0a90068f 100644 --- a/common/Util-server.cpp +++ b/common/Util-server.cpp @@ -145,88 +145,6 @@ std::size_t getFromCGroupV2(const std::string& key) namespace Util { -class CounterImpl { -private: - DIR* _dir = nullptr; - -public: - CounterImpl(const char* procPath) - : _dir(opendir(procPath)) - { - if (!_dir) - LOG_ERR("No proc mounted for procPath " << procPath << ", can't count threads"); - } - - ~CounterImpl() { closedir(_dir); } - - int count() - { - if (!_dir) - return -1; - - rewinddir(_dir); - - int tasks = 0; - struct dirent* i; - while ((i = readdir(_dir))) - { - if (i->d_name[0] != '.') - tasks++; - } - - return tasks; - } -}; - -ThreadCounter::ThreadCounter() : _impl(new CounterImpl("/proc/self/task")) {} - -ThreadCounter::~ThreadCounter() = default; - -int ThreadCounter::count() { return _impl->count(); } - -FDCounter::FDCounter() : _impl(new CounterImpl("/proc/self/fd")) {} - -FDCounter::~FDCounter() = default; - -int FDCounter::count() { return _impl->count(); } - -#ifdef __FreeBSD__ -ThreadCounter::ThreadCounter() { pid = getpid(); } - -ThreadCounter::~ThreadCounter() {} - -int ThreadCounter::count() -{ - size_t len = 0, olen = 0; - struct kinfo_proc* kipp = NULL; - int name[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID | KERN_PROC_INC_THREAD, pid }; - int error = sysctl(name, 4, NULL, &len, NULL, 0); - if (len == 0 || (error < 0 && errno != EPERM)) { - goto fail; - } - do - { - len += len / 10; - kipp = (struct kinfo_proc *) reallocf(kipp, len); - if (kipp == NULL) - { - goto fail; - } - olen = len; - error = sysctl(name, 4, kipp, &len, NULL, 0); - } while (error < 0 && errno == ENOMEM && olen == len); - - if (error < 0 && errno != EPERM) { - goto fail; - } - return len / sizeof(*kipp); - -fail: - if (kipp) - free(kipp); - return 0;} -#endif - int spawnProcess(const std::string& cmd, const StringVector& args) { // Create a vector of zero-terminated strings. diff --git a/macos/coolwsd/coolwsd.xcodeproj/project.pbxproj b/macos/coolwsd/coolwsd.xcodeproj/project.pbxproj index 8fffcfd9a5e1f..4bea0d03a9852 100644 --- a/macos/coolwsd/coolwsd.xcodeproj/project.pbxproj +++ b/macos/coolwsd/coolwsd.xcodeproj/project.pbxproj @@ -168,6 +168,7 @@ BE74B2532D3F97AB009786DF /* TileDesc.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = TileDesc.hpp; path = ../../../wsd/TileDesc.hpp; sourceTree = ""; }; BE74B2542D3F97AB009786DF /* TraceFile.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = TraceFile.hpp; path = ../../../wsd/TraceFile.hpp; sourceTree = ""; }; BE74B2552D3F97AB009786DF /* UserMessages.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = UserMessages.hpp; path = ../../../wsd/UserMessages.hpp; sourceTree = ""; }; + BEF9E2022D47D312004FCEB5 /* Util-macos.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "Util-macos.cpp"; path = "../../../common/Util-macos.cpp"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXGroup section */ @@ -247,6 +248,7 @@ BE74B1F12D3F963F009786DF /* Uri.cpp */, BE74B1F22D3F963F009786DF /* Util.hpp */, BE74B1F32D3F963F009786DF /* Util.cpp */, + BEF9E2022D47D312004FCEB5 /* Util-macos.cpp */, BE74B1F42D3F963F009786DF /* Util-mobile.cpp */, BE74B1F52D3F963F009786DF /* Util-server.cpp */, BE74B1F62D3F963F009786DF /* Util-unix.cpp */, diff --git a/test/Makefile.am b/test/Makefile.am index 39bc814c26e82..84ee7dcc5d260 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -23,6 +23,12 @@ if ENABLE_SSL include_paths += ${OPENSSL_CFLAGS} endif +if ENABLE_MACOS +util_platform_cpp = ../common/Util-macos.cpp +else +util_platform_cpp = ../common/Util-linux.cpp +endif + AM_CXXFLAGS = $(CPPUNIT_CFLAGS) -DTDOC=\"$(abs_top_srcdir)/test/data\" -DTDIST=\"$(DIST_FOLDER)\" \ -I${top_srcdir}/common -I${top_srcdir}/net -I${top_srcdir}/wsd -I${top_srcdir}/kit \ -I${top_srcdir} -I${top_srcdir}/test \ @@ -180,6 +186,7 @@ common_sources = \ ../common/Unit-server.cpp \ ../common/Uri.cpp \ ../common/Util-server.cpp \ + $(util_platform_cpp) \ ../common/Util-unix.cpp \ ../common/Util.cpp \ ../kit/KitQueue.cpp \ @@ -214,7 +221,7 @@ unithttplib_LDADD += -lssl -lcrypto endif fakesockettest_CPPFLAGS = -g -fakesockettest_SOURCES = fakesockettest.cpp ../net/FakeSocket.cpp ../common/DummyTraceEventEmitter.cpp ../common/Log.cpp ../common/Util.cpp ../common/Util-server.cpp ../common/Util-unix.cpp ../common/Globals.cpp +fakesockettest_SOURCES = fakesockettest.cpp ../net/FakeSocket.cpp ../common/DummyTraceEventEmitter.cpp ../common/Log.cpp ../common/Util.cpp ../common/Util-server.cpp $(util_platform_cpp) ../common/Util-unix.cpp ../common/Globals.cpp fakesockettest_LDADD = $(CPPUNIT_LIBS) # old-style unit tests - bootstrapped via UnitClient From d1107d5b8e6d32f8ae654fac6f002398eecba9a3 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 3 Feb 2025 08:57:12 +0100 Subject: [PATCH 102/177] Separate the coolwsd and coolwsd-inproc schemes This is to be able to run one, or the other easily. Signed-off-by: Jan Holesovsky Change-Id: I471dcaf6617ceb21f42da373b75ffa7ac424a3ea --- .gitignore | 2 +- .../xcschemes/coolwsd-inproc.xcscheme | 135 ++++++++++++++++++ .../xcshareddata/xcschemes/coolwsd.xcscheme | 8 +- 3 files changed, 140 insertions(+), 5 deletions(-) create mode 100644 macos/coolwsd/coolwsd.xcodeproj/xcshareddata/xcschemes/coolwsd-inproc.xcscheme diff --git a/.gitignore b/.gitignore index 16dd17ad56c6c..f6fd8b09b6010 100644 --- a/.gitignore +++ b/.gitignore @@ -107,7 +107,7 @@ coolforkit-nocaps coolforkit-ns connect lokitclient -./coolwsd +/coolwsd loolwsd coolmount coolmap diff --git a/macos/coolwsd/coolwsd.xcodeproj/xcshareddata/xcschemes/coolwsd-inproc.xcscheme b/macos/coolwsd/coolwsd.xcodeproj/xcshareddata/xcschemes/coolwsd-inproc.xcscheme new file mode 100644 index 0000000000000..ecf637057e06e --- /dev/null +++ b/macos/coolwsd/coolwsd.xcodeproj/xcshareddata/xcschemes/coolwsd-inproc.xcscheme @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/macos/coolwsd/coolwsd.xcodeproj/xcshareddata/xcschemes/coolwsd.xcscheme b/macos/coolwsd/coolwsd.xcodeproj/xcshareddata/xcschemes/coolwsd.xcscheme index ecf637057e06e..0585216668fa3 100644 --- a/macos/coolwsd/coolwsd.xcodeproj/xcshareddata/xcschemes/coolwsd.xcscheme +++ b/macos/coolwsd/coolwsd.xcodeproj/xcshareddata/xcschemes/coolwsd.xcscheme @@ -43,7 +43,7 @@ + FilePath = "../../coolwsd"> + isEnabled = "NO"> + isEnabled = "NO"> + isEnabled = "NO"> Date: Tue, 4 Feb 2025 11:49:04 +0100 Subject: [PATCH 103/177] Disable capabilities for coolwsd in Xcode on macOS Signed-off-by: Jan Holesovsky Change-Id: I80c3181981874b13f2edd9eaac2beac712bcbb6b --- .../coolwsd.xcodeproj/xcshareddata/xcschemes/coolwsd.xcscheme | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/macos/coolwsd/coolwsd.xcodeproj/xcshareddata/xcschemes/coolwsd.xcscheme b/macos/coolwsd/coolwsd.xcodeproj/xcshareddata/xcschemes/coolwsd.xcscheme index 0585216668fa3..b38260466ef66 100644 --- a/macos/coolwsd/coolwsd.xcodeproj/xcshareddata/xcschemes/coolwsd.xcscheme +++ b/macos/coolwsd/coolwsd.xcodeproj/xcshareddata/xcschemes/coolwsd.xcscheme @@ -63,6 +63,10 @@ argument = "--o:child_root_path="$(PROJECT_DIR)/../../jails"" isEnabled = "YES"> + + From f357cc9fcf7b51976eb42e29a6c0e41c2d876a19 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 4 Feb 2025 14:47:33 +0100 Subject: [PATCH 104/177] coda-m: Introduce ENABLE_CHILDROOTS & guard it by --enable-coda Originally I wanted to introduce just 'ENABLE_CODA', but it was strange to use '#if !ENABLE_CODA' for the 'normal' server coolwsd, so went ahead with more granular ENABLE_CHILDROOTS, meaning that we'll probably need more 'ENABLE_something's for the full CODA functionality. Signed-off-by: Jan Holesovsky Change-Id: Ie2a3df792f51dcc0cdb8e8b60e6058e16712de42 --- common/JailUtil.cpp | 2 ++ common/JailUtil.hpp | 2 ++ config.h.in | 3 +++ configure.ac | 21 +++++++++++++++++++++ kit/ForKit.cpp | 12 +++++++++++- kit/Kit.cpp | 4 ++++ wsd/COOLWSD.cpp | 4 ++++ 7 files changed, 47 insertions(+), 1 deletion(-) diff --git a/common/JailUtil.cpp b/common/JailUtil.cpp index 6182faff7538c..c3eb5e8340ebb 100644 --- a/common/JailUtil.cpp +++ b/common/JailUtil.cpp @@ -525,6 +525,7 @@ bool isMountNamespacesEnabled() } +#if ENABLE_CHILDROOTS namespace SysTemplate { /// The network and other system files we need to keep up-to-date in jails. @@ -732,6 +733,7 @@ void setupRandomDeviceLinks(const std::string& sysTemplate) } } // namespace SysTemplate +#endif // ENABLE_CHILDROOTS } // namespace JailUtil diff --git a/common/JailUtil.hpp b/common/JailUtil.hpp index bfc7214742753..e532a7983a6dc 100644 --- a/common/JailUtil.hpp +++ b/common/JailUtil.hpp @@ -90,6 +90,7 @@ void disableMountNamespaces(); /// Returns true iff namespace-mounting is enabled in this process. bool isMountNamespacesEnabled(); +#if ENABLE_CHILDROOTS namespace SysTemplate { /// Setup links for /dev/random and /dev/urandom in systemplate. @@ -106,6 +107,7 @@ void setupDynamicFiles(const std::string& sysTemplate); bool updateDynamicFiles(const std::string& sysTemplate); } // namespace SysTemplate +#endif // ENABLE_CHILDROOTS } // end namespace JailUtil diff --git a/config.h.in b/config.h.in index 2703c55b27b44..d811b28c5bc32 100644 --- a/config.h.in +++ b/config.h.in @@ -114,6 +114,9 @@ /* Define to 1 if this is a mobileapp (eg. Android) build. */ #undef MOBILEAPP +/* Define to 1 when we should use systemplate and jails (eg. normal coolwsd server), otherwise 0 (eg. CODA). */ +#undef ENABLE_CHILDROOTS + /* Default value of feature_lock.unlock_description */ #undef UNLOCK_DESCRIPTION diff --git a/configure.ac b/configure.ac index 6f6543ab8924b..44de93f31c485 100644 --- a/configure.ac +++ b/configure.ac @@ -148,6 +148,12 @@ AC_ARG_ENABLE([windowsapp], similarly to the iOS app, from the JavaScript and the pseudo WebSocket message plumbing point of view.])) +AC_ARG_ENABLE([coda], + AS_HELP_STRING([--enable-coda], + [Use to build a CODA app. This will build the entire coolwsd, so that it runs under the hood + inside the app. Do NOT use together with --enable-*app, this is supposed to be a + different approach that allows multiple documents open at the same time.])) + AC_ARG_WITH([wasm-fallback], AS_HELP_STRING([--with-wasm-fallback=], [Build a COOL where the client can fall back to a WASM implementation if the connection to the server fails. @@ -1540,6 +1546,21 @@ AC_DEFINE_UNQUOTED([MOBILEAPP],[$MOBILEAPP],[Define to 1 if this is a mobileapp AC_SUBST(ENABLE_MOBILEAPP) AM_CONDITIONAL([ENABLE_MOBILEAPP], [test "$ENABLE_MOBILEAPP" = "true"]) +AC_MSG_CHECKING([whether to enable the CODA build]) +if test "$enable_coda" = "yes"; then + AC_MSG_RESULT([yes]) + if test "$ENABLE_MOBILEAPP" = "true" ; then + AC_MSG_ERROR([--enable-coda conflicts with --enable-(androidapp|gtkapp|iosapp|macosapp|windowsapp), please decide for one or the other.]) + fi + if test "$ENABLE_DEBUG" != "true" ; then + AC_MSG_ERROR([--enable-coda currently depends on --enable-debug, please add it to ./configure. Many things haven't been updated to build a production CODA app yet.]) + fi + AC_DEFINE([ENABLE_CHILDROOTS],0,[Disable systemplate and jails when building CODA.]) +else + AC_MSG_RESULT([no]) + AC_DEFINE([ENABLE_CHILDROOTS],1,[Normal server, enable systemplate and jails.]) +fi + if test "$host_os" = "emscripten" ; then ENABLE_EMSCRIPTENAPP=true fi diff --git a/kit/ForKit.cpp b/kit/ForKit.cpp index 72dac92a9b975..771f47dc277a3 100644 --- a/kit/ForKit.cpp +++ b/kit/ForKit.cpp @@ -531,7 +531,11 @@ int createLibreOfficeKit(const std::string& childRoot, const std::string& sysTem std::string jailId = Util::rng::getFilename(16); // Update the dynamic files as necessary. +#if ENABLE_CHILDROOTS const bool sysTemplateIncomplete = !JailUtil::SysTemplate::updateDynamicFiles(sysTemplate); +#else + const bool sysTemplateIncomplete = false; +#endif // Used to label the spare kit instances static size_t spareKitId = 0; @@ -544,7 +548,11 @@ int createLibreOfficeKit(const std::string& childRoot, const std::string& sysTem if (Util::isKitInProcess()) { std::thread([childRoot, jailId = std::move(jailId), configId, sysTemplate, - loTemplate, queryVersion, sysTemplateIncomplete] { + loTemplate, queryVersion +#if ENABLE_CHILDROOTS + , sysTemplateIncomplete +#endif + ] { sleepForDebugger(); lokit_main(childRoot, jailId, configId, sysTemplate, loTemplate, true, true, false, queryVersion, DisplayVersion, @@ -1021,11 +1029,13 @@ int forkit_main(int argc, char** argv) if (Util::ThreadCounter().count() != 1) LOG_ERR("forkit has more than a single thread after pre-init" << Util::ThreadCounter().count()); +#if ENABLE_CHILDROOTS // Link the network and system files in sysTemplate, if possible. JailUtil::SysTemplate::setupDynamicFiles(sysTemplate); // Make dev/[u]random point to the writable devices in tmp/dev/. JailUtil::SysTemplate::setupRandomDeviceLinks(sysTemplate); +#endif if (!Util::isKitInProcess()) { diff --git a/kit/Kit.cpp b/kit/Kit.cpp index a2726c7976a3a..5de83f9a13754 100644 --- a/kit/Kit.cpp +++ b/kit/Kit.cpp @@ -3463,6 +3463,7 @@ void lokit_main( const std::string sysTemplateSubDir = Poco::Path(tempRoot, "systemplate-" + jailId).toString(); const std::string jailEtcDir = Poco::Path(jailPath, "etc").toString(); +#if ENABLE_CHILDROOTS if (sysTemplateIncomplete && JailUtil::isBindMountingEnabled()) { const std::string sysTemplateEtcDir = Poco::Path(sysTemplate, "etc").toString(); @@ -3481,6 +3482,7 @@ void lokit_main( JailUtil::disableBindMounting(); // We can't mount from incomplete systemplate. } } +#endif // The bind-mount implementation: inlined here to mirror // the fallback link/copy version bellow. @@ -3679,6 +3681,7 @@ void lokit_main( linkGCDAFiles(jailPathStr); #endif +#if ENABLE_CHILDROOTS // Update the dynamic files inside the jail. if (!JailUtil::SysTemplate::updateDynamicFiles(jailPathStr)) { @@ -3689,6 +3692,7 @@ void lokit_main( "read-only, running the installation scripts with the owner's account " "should update these files. Some functionality may be missing."); } +#endif if (usingMountNamespace) { diff --git a/wsd/COOLWSD.cpp b/wsd/COOLWSD.cpp index 22f136067f41d..b3fb0af1ed317 100644 --- a/wsd/COOLWSD.cpp +++ b/wsd/COOLWSD.cpp @@ -1227,6 +1227,7 @@ void COOLWSD::setupChildRoot(const bool UseMountNamespaces) JailUtil::disableBindMounting(); // Default to assume failure JailUtil::disableMountNamespaces(); +#if ENABLE_CHILDROOTS Log::preFork(); pid_t pid = fork(); @@ -1295,6 +1296,9 @@ void COOLWSD::setupChildRoot(const bool UseMountNamespaces) JailUtil::enableBindMounting(); if (EnableMountNamespaces) JailUtil::enableMountNamespaces(); +#else + (void) UseMountNamespaces; +#endif } #endif From 71c58adfbefe627f6a0591adbc7dc7986e15969b Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 10 Feb 2025 09:14:48 +0100 Subject: [PATCH 105/177] coda-m: Add more coolwsd source files to the project Signed-off-by: Jan Holesovsky Change-Id: Ib1c3825ffd81bbdc1d79e8561c0e03dc08347643 --- macos/coda/coda.xcodeproj/project.pbxproj | 208 ++++++++++++++++++++-- 1 file changed, 194 insertions(+), 14 deletions(-) diff --git a/macos/coda/coda.xcodeproj/project.pbxproj b/macos/coda/coda.xcodeproj/project.pbxproj index 573ab3b6d7ce5..14e59b6c8bcdc 100644 --- a/macos/coda/coda.xcodeproj/project.pbxproj +++ b/macos/coda/coda.xcodeproj/project.pbxproj @@ -8,7 +8,6 @@ /* Begin PBXBuildFile section */ BE16C9F02CD51F58005E5960 /* hello.odt in Resources */ = {isa = PBXBuildFile; fileRef = BE16C9EF2CD51F58005E5960 /* hello.odt */; }; - BE2231B82CC679DE00385A9C /* Crypto-stub.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE2231B72CC679DE00385A9C /* Crypto-stub.cpp */; }; BE2231BA2CC67FDE00385A9C /* coolwsd-fork.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE2231B92CC67FDE00385A9C /* coolwsd-fork.cpp */; }; BE2231BC2CC6804D00385A9C /* Util-mobile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE2231BB2CC6804D00385A9C /* Util-mobile.cpp */; }; BE22492C2CC79AD700385A9C /* cool.html in Resources */ = {isa = PBXBuildFile; fileRef = BE22492B2CC79AD700385A9C /* cool.html */; }; @@ -18,8 +17,37 @@ BE22557E2CC79BAE00385A9C /* global.js in Resources */ = {isa = PBXBuildFile; fileRef = BE2249312CC79BAE00385A9C /* global.js */; }; BE2257AD2CC79BAE00385A9C /* bundle.css in Resources */ = {isa = PBXBuildFile; fileRef = BE22492D2CC79BAE00385A9C /* bundle.css */; }; BE22AA9C2CC7AE7400385A9C /* images in Resources */ = {isa = PBXBuildFile; fileRef = BE22AA9B2CC7AE7400385A9C /* images */; }; + BE4C620E2D59E85500047DF2 /* MobileApp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C62062D59E85500047DF2 /* MobileApp.cpp */; }; + BE4C620F2D59E85500047DF2 /* Util-macos.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C620C2D59E85500047DF2 /* Util-macos.cpp */; }; + BE4C62102D59E85500047DF2 /* CoolMount.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C62002D59E85500047DF2 /* CoolMount.cpp */; }; + BE4C62112D59E85500047DF2 /* Unit-server.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C620B2D59E85500047DF2 /* Unit-server.cpp */; }; + BE4C62122D59E85500047DF2 /* JailUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C62042D59E85500047DF2 /* JailUtil.cpp */; }; + BE4C62132D59E85500047DF2 /* Seccomp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C62082D59E85500047DF2 /* Seccomp.cpp */; }; + BE4C62142D59E85500047DF2 /* CommandControl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C61FE2D59E85500047DF2 /* CommandControl.cpp */; }; + BE4C62152D59E85500047DF2 /* Crypto.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C62022D59E85500047DF2 /* Crypto.cpp */; }; + BE4C62162D59E85500047DF2 /* SigUtil-server.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C62092D59E85500047DF2 /* SigUtil-server.cpp */; }; + BE4C62172D59E85500047DF2 /* Util-server.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C620D2D59E85500047DF2 /* Util-server.cpp */; }; + BE4C621C2D59EAA900047DF2 /* DelaySocket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C62192D59EAA900047DF2 /* DelaySocket.cpp */; }; + BE4C621D2D59EAA900047DF2 /* HttpHelper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C621B2D59EAA900047DF2 /* HttpHelper.cpp */; }; + BE4C623F2D59EBAC00047DF2 /* QuarantineUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C62362D59EBAC00047DF2 /* QuarantineUtil.cpp */; }; + BE4C62402D59EBAC00047DF2 /* RemoteConfig.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C62382D59EBAC00047DF2 /* RemoteConfig.cpp */; }; + BE4C62412D59EBAC00047DF2 /* ProxyProtocol.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C62322D59EBAC00047DF2 /* ProxyProtocol.cpp */; }; + BE4C62422D59EBAC00047DF2 /* ProxyRequestHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C62342D59EBAC00047DF2 /* ProxyRequestHandler.cpp */; }; + BE4C62432D59EBAC00047DF2 /* FileServerUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C622C2D59EBAC00047DF2 /* FileServerUtil.cpp */; }; + BE4C62442D59EBAC00047DF2 /* ProofKey.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C62302D59EBAC00047DF2 /* ProofKey.cpp */; }; + BE4C62452D59EBAC00047DF2 /* ServerAuditUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C623B2D59EBAC00047DF2 /* ServerAuditUtil.cpp */; }; + BE4C62462D59EBAC00047DF2 /* AdminModel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C62212D59EBAC00047DF2 /* AdminModel.cpp */; }; + BE4C62472D59EBAC00047DF2 /* Admin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C621F2D59EBAC00047DF2 /* Admin.cpp */; }; + BE4C62482D59EBAC00047DF2 /* Exceptions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C62292D59EBAC00047DF2 /* Exceptions.cpp */; }; + BE4C62492D59EBAC00047DF2 /* SpecialBrokers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C623D2D59EBAC00047DF2 /* SpecialBrokers.cpp */; }; + BE4C624A2D59EBAC00047DF2 /* FileServer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C622B2D59EBAC00047DF2 /* FileServer.cpp */; }; + BE4C624B2D59EBAC00047DF2 /* HostUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C622E2D59EBAC00047DF2 /* HostUtil.cpp */; }; + BE4C624C2D59EBAC00047DF2 /* Auth.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C62232D59EBAC00047DF2 /* Auth.cpp */; }; + BE4C62562D59EC5400047DF2 /* WopiStorage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C62552D59EC5400047DF2 /* WopiStorage.cpp */; }; + BE4C62572D59EC5400047DF2 /* CheckFileInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C624F2D59EC5400047DF2 /* CheckFileInfo.cpp */; }; + BE4C62582D59EC5400047DF2 /* WopiProxy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C62532D59EC5400047DF2 /* WopiProxy.cpp */; }; + BE4C62592D59EC5400047DF2 /* StorageConnectionManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C62512D59EC5400047DF2 /* StorageConnectionManager.cpp */; }; BE5A7AE22D354F4000FE7D60 /* Syscall.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5A7AE12D354F4000FE7D60 /* Syscall.cpp */; }; - BE9115AA2CECBCB200C597B2 /* SigUtil-mobile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE9115A92CECBCB200C597B2 /* SigUtil-mobile.cpp */; }; BE9115AC2CECBD0100C597B2 /* FileUtil-apple.mm in Sources */ = {isa = PBXBuildFile; fileRef = BE9115AB2CECBD0100C597B2 /* FileUtil-apple.mm */; }; BE9115AE2CECBD3100C597B2 /* FileUtil-unix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE9115AD2CECBD3100C597B2 /* FileUtil-unix.cpp */; }; BE9115B02CECBECF00C597B2 /* Util-unix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE9115AF2CECBECF00C597B2 /* Util-unix.cpp */; }; @@ -55,7 +83,6 @@ BEA264B32CBE99340007435A /* DocumentBroker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA264A72CBE99340007435A /* DocumentBroker.cpp */; }; BEA264B42CBE99340007435A /* RequestVettingStation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA264AA2CBE99340007435A /* RequestVettingStation.cpp */; }; BEEF3F862CE2139E00ABE785 /* coolkitconfig.xcu in Resources */ = {isa = PBXBuildFile; fileRef = BEEF3F852CE2139E00ABE785 /* coolkitconfig.xcu */; }; - BEF9E17F2D47C709004FCEB5 /* Unit-mobile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEF9E17E2D47C709004FCEB5 /* Unit-mobile.cpp */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -77,7 +104,6 @@ /* Begin PBXFileReference section */ BE16C9EF2CD51F58005E5960 /* hello.odt */ = {isa = PBXFileReference; lastKnownFileType = file; name = hello.odt; path = ../../../test/data/hello.odt; sourceTree = ""; }; - BE2231B72CC679DE00385A9C /* Crypto-stub.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "Crypto-stub.cpp"; path = "../../../../common/Crypto-stub.cpp"; sourceTree = ""; }; BE2231B92CC67FDE00385A9C /* coolwsd-fork.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "coolwsd-fork.cpp"; path = "../../../../wsd/coolwsd-fork.cpp"; sourceTree = ""; }; BE2231BB2CC6804D00385A9C /* Util-mobile.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "Util-mobile.cpp"; path = "../../../../common/Util-mobile.cpp"; sourceTree = ""; }; BE22492B2CC79AD700385A9C /* cool.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = cool.html; path = ../../../browser/dist/cool.html; sourceTree = ""; }; @@ -87,10 +113,71 @@ BE2249302CC79BAE00385A9C /* device-desktop.css */ = {isa = PBXFileReference; lastKnownFileType = text.css; name = "device-desktop.css"; path = "../../../browser/dist/device-desktop.css"; sourceTree = ""; }; BE2249312CC79BAE00385A9C /* global.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = global.js; path = ../../../browser/dist/global.js; sourceTree = ""; }; BE22AA9B2CC7AE7400385A9C /* images */ = {isa = PBXFileReference; lastKnownFileType = folder; name = images; path = ../../../browser/dist/images; sourceTree = ""; }; + BE4C61FD2D59E85500047DF2 /* CommandControl.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = CommandControl.hpp; path = ../../../../common/CommandControl.hpp; sourceTree = ""; }; + BE4C61FE2D59E85500047DF2 /* CommandControl.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = CommandControl.cpp; path = ../../../../common/CommandControl.cpp; sourceTree = ""; }; + BE4C61FF2D59E85500047DF2 /* Common.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Common.hpp; path = ../../../../common/Common.hpp; sourceTree = ""; }; + BE4C62002D59E85500047DF2 /* CoolMount.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = CoolMount.cpp; path = ../../../../common/CoolMount.cpp; sourceTree = ""; }; + BE4C62012D59E85500047DF2 /* Crypto.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Crypto.hpp; path = ../../../../common/Crypto.hpp; sourceTree = ""; }; + BE4C62022D59E85500047DF2 /* Crypto.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Crypto.cpp; path = ../../../../common/Crypto.cpp; sourceTree = ""; }; + BE4C62032D59E85500047DF2 /* JailUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = JailUtil.hpp; path = ../../../../common/JailUtil.hpp; sourceTree = ""; }; + BE4C62042D59E85500047DF2 /* JailUtil.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = JailUtil.cpp; path = ../../../../common/JailUtil.cpp; sourceTree = ""; }; + BE4C62052D59E85500047DF2 /* MobileApp.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = MobileApp.hpp; path = ../../../../common/MobileApp.hpp; sourceTree = ""; }; + BE4C62062D59E85500047DF2 /* MobileApp.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = MobileApp.cpp; path = ../../../../common/MobileApp.cpp; sourceTree = ""; }; + BE4C62072D59E85500047DF2 /* Seccomp.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Seccomp.hpp; path = ../../../../common/Seccomp.hpp; sourceTree = ""; }; + BE4C62082D59E85500047DF2 /* Seccomp.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Seccomp.cpp; path = ../../../../common/Seccomp.cpp; sourceTree = ""; }; + BE4C62092D59E85500047DF2 /* SigUtil-server.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "SigUtil-server.cpp"; path = "../../../../common/SigUtil-server.cpp"; sourceTree = ""; }; + BE4C620A2D59E85500047DF2 /* SpookyV2.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SpookyV2.h; path = ../../../../common/SpookyV2.h; sourceTree = ""; }; + BE4C620B2D59E85500047DF2 /* Unit-server.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "Unit-server.cpp"; path = "../../../../common/Unit-server.cpp"; sourceTree = ""; }; + BE4C620C2D59E85500047DF2 /* Util-macos.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "Util-macos.cpp"; path = "../../../../common/Util-macos.cpp"; sourceTree = ""; }; + BE4C620D2D59E85500047DF2 /* Util-server.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "Util-server.cpp"; path = "../../../../common/Util-server.cpp"; sourceTree = ""; }; + BE4C62182D59EAA900047DF2 /* DelaySocket.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = DelaySocket.hpp; path = ../../../../net/DelaySocket.hpp; sourceTree = ""; }; + BE4C62192D59EAA900047DF2 /* DelaySocket.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = DelaySocket.cpp; path = ../../../../net/DelaySocket.cpp; sourceTree = ""; }; + BE4C621A2D59EAA900047DF2 /* HttpHelper.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = HttpHelper.hpp; path = ../../../../net/HttpHelper.hpp; sourceTree = ""; }; + BE4C621B2D59EAA900047DF2 /* HttpHelper.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = HttpHelper.cpp; path = ../../../../net/HttpHelper.cpp; sourceTree = ""; }; + BE4C621E2D59EBAC00047DF2 /* Admin.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Admin.hpp; path = ../../../../wsd/Admin.hpp; sourceTree = ""; }; + BE4C621F2D59EBAC00047DF2 /* Admin.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Admin.cpp; path = ../../../../wsd/Admin.cpp; sourceTree = ""; }; + BE4C62202D59EBAC00047DF2 /* AdminModel.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = AdminModel.hpp; path = ../../../../wsd/AdminModel.hpp; sourceTree = ""; }; + BE4C62212D59EBAC00047DF2 /* AdminModel.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = AdminModel.cpp; path = ../../../../wsd/AdminModel.cpp; sourceTree = ""; }; + BE4C62222D59EBAC00047DF2 /* Auth.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Auth.hpp; path = ../../../../wsd/Auth.hpp; sourceTree = ""; }; + BE4C62232D59EBAC00047DF2 /* Auth.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Auth.cpp; path = ../../../../wsd/Auth.cpp; sourceTree = ""; }; + BE4C62242D59EBAC00047DF2 /* ClientRequestDispatcher.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = ClientRequestDispatcher.hpp; path = ../../../../wsd/ClientRequestDispatcher.hpp; sourceTree = ""; }; + BE4C62252D59EBAC00047DF2 /* ClientSession.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = ClientSession.hpp; path = ../../../../wsd/ClientSession.hpp; sourceTree = ""; }; + BE4C62262D59EBAC00047DF2 /* COOLWSD.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = COOLWSD.hpp; path = ../../../../wsd/COOLWSD.hpp; sourceTree = ""; }; + BE4C62272D59EBAC00047DF2 /* DocumentBroker.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = DocumentBroker.hpp; path = ../../../../wsd/DocumentBroker.hpp; sourceTree = ""; }; + BE4C62282D59EBAC00047DF2 /* Exceptions.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Exceptions.hpp; path = ../../../../wsd/Exceptions.hpp; sourceTree = ""; }; + BE4C62292D59EBAC00047DF2 /* Exceptions.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Exceptions.cpp; path = ../../../../wsd/Exceptions.cpp; sourceTree = ""; }; + BE4C622A2D59EBAC00047DF2 /* FileServer.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = FileServer.hpp; path = ../../../../wsd/FileServer.hpp; sourceTree = ""; }; + BE4C622B2D59EBAC00047DF2 /* FileServer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = FileServer.cpp; path = ../../../../wsd/FileServer.cpp; sourceTree = ""; }; + BE4C622C2D59EBAC00047DF2 /* FileServerUtil.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = FileServerUtil.cpp; path = ../../../../wsd/FileServerUtil.cpp; sourceTree = ""; }; + BE4C622D2D59EBAC00047DF2 /* HostUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = HostUtil.hpp; path = ../../../../wsd/HostUtil.hpp; sourceTree = ""; }; + BE4C622E2D59EBAC00047DF2 /* HostUtil.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = HostUtil.cpp; path = ../../../../wsd/HostUtil.cpp; sourceTree = ""; }; + BE4C622F2D59EBAC00047DF2 /* ProofKey.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = ProofKey.hpp; path = ../../../../wsd/ProofKey.hpp; sourceTree = ""; }; + BE4C62302D59EBAC00047DF2 /* ProofKey.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ProofKey.cpp; path = ../../../../wsd/ProofKey.cpp; sourceTree = ""; }; + BE4C62312D59EBAC00047DF2 /* ProxyProtocol.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = ProxyProtocol.hpp; path = ../../../../wsd/ProxyProtocol.hpp; sourceTree = ""; }; + BE4C62322D59EBAC00047DF2 /* ProxyProtocol.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ProxyProtocol.cpp; path = ../../../../wsd/ProxyProtocol.cpp; sourceTree = ""; }; + BE4C62332D59EBAC00047DF2 /* ProxyRequestHandler.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = ProxyRequestHandler.hpp; path = ../../../../wsd/ProxyRequestHandler.hpp; sourceTree = ""; }; + BE4C62342D59EBAC00047DF2 /* ProxyRequestHandler.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ProxyRequestHandler.cpp; path = ../../../../wsd/ProxyRequestHandler.cpp; sourceTree = ""; }; + BE4C62352D59EBAC00047DF2 /* QuarantineUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = QuarantineUtil.hpp; path = ../../../../wsd/QuarantineUtil.hpp; sourceTree = ""; }; + BE4C62362D59EBAC00047DF2 /* QuarantineUtil.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = QuarantineUtil.cpp; path = ../../../../wsd/QuarantineUtil.cpp; sourceTree = ""; }; + BE4C62372D59EBAC00047DF2 /* RemoteConfig.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = RemoteConfig.hpp; path = ../../../../wsd/RemoteConfig.hpp; sourceTree = ""; }; + BE4C62382D59EBAC00047DF2 /* RemoteConfig.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = RemoteConfig.cpp; path = ../../../../wsd/RemoteConfig.cpp; sourceTree = ""; }; + BE4C62392D59EBAC00047DF2 /* RequestVettingStation.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = RequestVettingStation.hpp; path = ../../../../wsd/RequestVettingStation.hpp; sourceTree = ""; }; + BE4C623A2D59EBAC00047DF2 /* ServerAuditUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = ServerAuditUtil.hpp; path = ../../../../wsd/ServerAuditUtil.hpp; sourceTree = ""; }; + BE4C623B2D59EBAC00047DF2 /* ServerAuditUtil.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ServerAuditUtil.cpp; path = ../../../../wsd/ServerAuditUtil.cpp; sourceTree = ""; }; + BE4C623C2D59EBAC00047DF2 /* SpecialBrokers.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = SpecialBrokers.hpp; path = ../../../../wsd/SpecialBrokers.hpp; sourceTree = ""; }; + BE4C623D2D59EBAC00047DF2 /* SpecialBrokers.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SpecialBrokers.cpp; path = ../../../../wsd/SpecialBrokers.cpp; sourceTree = ""; }; + BE4C623E2D59EBAC00047DF2 /* TileCache.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = TileCache.hpp; path = ../../../../wsd/TileCache.hpp; sourceTree = ""; }; + BE4C624E2D59EC5400047DF2 /* CheckFileInfo.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = CheckFileInfo.hpp; path = ../../../../../wsd/wopi/CheckFileInfo.hpp; sourceTree = ""; }; + BE4C624F2D59EC5400047DF2 /* CheckFileInfo.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = CheckFileInfo.cpp; path = ../../../../../wsd/wopi/CheckFileInfo.cpp; sourceTree = ""; }; + BE4C62502D59EC5400047DF2 /* StorageConnectionManager.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = StorageConnectionManager.hpp; path = ../../../../../wsd/wopi/StorageConnectionManager.hpp; sourceTree = ""; }; + BE4C62512D59EC5400047DF2 /* StorageConnectionManager.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = StorageConnectionManager.cpp; path = ../../../../../wsd/wopi/StorageConnectionManager.cpp; sourceTree = ""; }; + BE4C62522D59EC5400047DF2 /* WopiProxy.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = WopiProxy.hpp; path = ../../../../../wsd/wopi/WopiProxy.hpp; sourceTree = ""; }; + BE4C62532D59EC5400047DF2 /* WopiProxy.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = WopiProxy.cpp; path = ../../../../../wsd/wopi/WopiProxy.cpp; sourceTree = ""; }; + BE4C62542D59EC5400047DF2 /* WopiStorage.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = WopiStorage.hpp; path = ../../../../../wsd/wopi/WopiStorage.hpp; sourceTree = ""; }; + BE4C62552D59EC5400047DF2 /* WopiStorage.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = WopiStorage.cpp; path = ../../../../../wsd/wopi/WopiStorage.cpp; sourceTree = ""; }; BE5A7A282D2BE28200FE7D60 /* FileUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = FileUtil.hpp; path = ../../../../common/FileUtil.hpp; sourceTree = ""; }; BE5A7AE02D354F4000FE7D60 /* Syscall.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Syscall.hpp; path = ../../../../common/Syscall.hpp; sourceTree = ""; }; BE5A7AE12D354F4000FE7D60 /* Syscall.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Syscall.cpp; path = ../../../../common/Syscall.cpp; sourceTree = ""; }; - BE9115A92CECBCB200C597B2 /* SigUtil-mobile.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "SigUtil-mobile.cpp"; path = "../../../../common/SigUtil-mobile.cpp"; sourceTree = ""; }; BE9115AB2CECBD0100C597B2 /* FileUtil-apple.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "FileUtil-apple.mm"; path = "../../../../common/FileUtil-apple.mm"; sourceTree = ""; }; BE9115AD2CECBD3100C597B2 /* FileUtil-unix.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "FileUtil-unix.cpp"; path = "../../../../common/FileUtil-unix.cpp"; sourceTree = ""; }; BE9115AF2CECBECF00C597B2 /* Util-unix.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "Util-unix.cpp"; path = "../../../../common/Util-unix.cpp"; sourceTree = ""; }; @@ -153,7 +240,6 @@ BECC4BC62CBD3FA400A120B3 /* codaUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = codaUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; BEEF3F822CE20BDD00ABE785 /* SetupKitEnvironment.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = SetupKitEnvironment.hpp; path = ../../../../kit/SetupKitEnvironment.hpp; sourceTree = ""; }; BEEF3F852CE2139E00ABE785 /* coolkitconfig.xcu */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = coolkitconfig.xcu; path = ../../../coolkitconfig.xcu; sourceTree = ""; }; - BEF9E17E2D47C709004FCEB5 /* Unit-mobile.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "Unit-mobile.cpp"; path = "../../../../common/Unit-mobile.cpp"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFileSystemSynchronizedRootGroup section */ @@ -215,29 +301,56 @@ path = dist; sourceTree = ""; }; + BE4C624D2D59EC1D00047DF2 /* wopi */ = { + isa = PBXGroup; + children = ( + BE4C624E2D59EC5400047DF2 /* CheckFileInfo.hpp */, + BE4C624F2D59EC5400047DF2 /* CheckFileInfo.cpp */, + BE4C62502D59EC5400047DF2 /* StorageConnectionManager.hpp */, + BE4C62512D59EC5400047DF2 /* StorageConnectionManager.cpp */, + BE4C62522D59EC5400047DF2 /* WopiProxy.hpp */, + BE4C62532D59EC5400047DF2 /* WopiProxy.cpp */, + BE4C62542D59EC5400047DF2 /* WopiStorage.hpp */, + BE4C62552D59EC5400047DF2 /* WopiStorage.cpp */, + ); + path = wopi; + sourceTree = ""; + }; BEA2637C2CBE38FE0007435A /* common */ = { isa = PBXGroup; children = ( - BEA263522CBE38E20007435A /* Authorization.hpp */, BEA263532CBE38E20007435A /* Authorization.cpp */, + BEA263522CBE38E20007435A /* Authorization.hpp */, + BE4C61FD2D59E85500047DF2 /* CommandControl.hpp */, + BE4C61FE2D59E85500047DF2 /* CommandControl.cpp */, + BE4C61FF2D59E85500047DF2 /* Common.hpp */, BEA263542CBE38E20007435A /* ConfigUtil.hpp */, BEA263552CBE38E20007435A /* ConfigUtil.cpp */, - BE2231B72CC679DE00385A9C /* Crypto-stub.cpp */, + BE4C62002D59E85500047DF2 /* CoolMount.cpp */, + BE4C62012D59E85500047DF2 /* Crypto.hpp */, + BE4C62022D59E85500047DF2 /* Crypto.cpp */, BE5A7A282D2BE28200FE7D60 /* FileUtil.hpp */, BEA263562CBE38E20007435A /* FileUtil.cpp */, BE9115AB2CECBD0100C597B2 /* FileUtil-apple.mm */, BE9115AD2CECBD3100C597B2 /* FileUtil-unix.cpp */, + BE4C62032D59E85500047DF2 /* JailUtil.hpp */, + BE4C62042D59E85500047DF2 /* JailUtil.cpp */, BEA263572CBE38E20007435A /* Log.hpp */, BEA263582CBE38E20007435A /* Log.cpp */, + BE4C62052D59E85500047DF2 /* MobileApp.hpp */, + BE4C62062D59E85500047DF2 /* MobileApp.cpp */, BEA263592CBE38E20007435A /* Png.hpp */, BEA2635A2CBE38E20007435A /* Protocol.hpp */, BEA2635B2CBE38E20007435A /* Protocol.cpp */, + BE4C62072D59E85500047DF2 /* Seccomp.hpp */, + BE4C62082D59E85500047DF2 /* Seccomp.cpp */, BEA2635C2CBE38E20007435A /* Session.hpp */, BEA2635D2CBE38E20007435A /* Session.cpp */, BEA2635E2CBE38E20007435A /* SigUtil.hpp */, - BE9115A92CECBCB200C597B2 /* SigUtil-mobile.cpp */, + BE4C62092D59E85500047DF2 /* SigUtil-server.cpp */, BEA263602CBE38E20007435A /* Simd.hpp */, BEA263612CBE38E20007435A /* Simd.cpp */, + BE4C620A2D59E85500047DF2 /* SpookyV2.h */, BEA263622CBE38E20007435A /* SpookyV2.cpp */, BEA263632CBE38E20007435A /* StringVector.hpp */, BEA263642CBE38E20007435A /* StringVector.cpp */, @@ -247,12 +360,14 @@ BEA263662CBE38E20007435A /* TraceEvent.cpp */, BEA263672CBE38E20007435A /* Unit.hpp */, BEA263682CBE38E20007435A /* Unit.cpp */, - BEF9E17E2D47C709004FCEB5 /* Unit-mobile.cpp */, + BE4C620B2D59E85500047DF2 /* Unit-server.cpp */, BEA263692CBE38E20007435A /* Uri.hpp */, BEA2636A2CBE38E20007435A /* Uri.cpp */, BEA2636B2CBE38E20007435A /* Util.hpp */, BEA2636C2CBE38E20007435A /* Util.cpp */, + BE4C620C2D59E85500047DF2 /* Util-macos.cpp */, BE2231BB2CC6804D00385A9C /* Util-mobile.cpp */, + BE4C620D2D59E85500047DF2 /* Util-server.cpp */, BE9115AF2CECBECF00C597B2 /* Util-unix.cpp */, ); path = common; @@ -288,7 +403,11 @@ isa = PBXGroup; children = ( BEA264972CBE98CD0007435A /* AsyncDNS.hpp */, + BE4C62182D59EAA900047DF2 /* DelaySocket.hpp */, + BE4C62192D59EAA900047DF2 /* DelaySocket.cpp */, BEA264982CBE98CD0007435A /* FakeSocket.cpp */, + BE4C621A2D59EAA900047DF2 /* HttpHelper.hpp */, + BE4C621B2D59EAA900047DF2 /* HttpHelper.cpp */, BEA264992CBE98CD0007435A /* HttpRequest.hpp */, BEA2649A2CBE98CD0007435A /* HttpRequest.cpp */, BEA2649B2CBE98CD0007435A /* NetUtil.hpp */, @@ -303,16 +422,50 @@ BEA2648A2CBE98010007435A /* wsd */ = { isa = PBXGroup; children = ( + BE4C624D2D59EC1D00047DF2 /* wopi */, + BE4C621E2D59EBAC00047DF2 /* Admin.hpp */, + BE4C621F2D59EBAC00047DF2 /* Admin.cpp */, + BE4C62202D59EBAC00047DF2 /* AdminModel.hpp */, + BE4C62212D59EBAC00047DF2 /* AdminModel.cpp */, + BE4C62222D59EBAC00047DF2 /* Auth.hpp */, + BE4C62232D59EBAC00047DF2 /* Auth.cpp */, + BE4C62252D59EBAC00047DF2 /* ClientSession.hpp */, + BE4C62242D59EBAC00047DF2 /* ClientRequestDispatcher.hpp */, BEA264A42CBE99340007435A /* ClientRequestDispatcher.cpp */, BEA264A52CBE99340007435A /* ClientSession.cpp */, + BE4C62262D59EBAC00047DF2 /* COOLWSD.hpp */, BEA264A62CBE99340007435A /* COOLWSD.cpp */, BE2231B92CC67FDE00385A9C /* coolwsd-fork.cpp */, + BE4C62272D59EBAC00047DF2 /* DocumentBroker.hpp */, BEA264A72CBE99340007435A /* DocumentBroker.cpp */, + BE4C62282D59EBAC00047DF2 /* Exceptions.hpp */, + BE4C62292D59EBAC00047DF2 /* Exceptions.cpp */, + BE4C622A2D59EBAC00047DF2 /* FileServer.hpp */, + BE4C622B2D59EBAC00047DF2 /* FileServer.cpp */, + BE4C622C2D59EBAC00047DF2 /* FileServerUtil.cpp */, + BE4C622D2D59EBAC00047DF2 /* HostUtil.hpp */, + BE4C622E2D59EBAC00047DF2 /* HostUtil.cpp */, + BE4C622F2D59EBAC00047DF2 /* ProofKey.hpp */, + BE4C62302D59EBAC00047DF2 /* ProofKey.cpp */, + BE4C62312D59EBAC00047DF2 /* ProxyProtocol.hpp */, + BE4C62322D59EBAC00047DF2 /* ProxyProtocol.cpp */, + BE4C62332D59EBAC00047DF2 /* ProxyRequestHandler.hpp */, + BE4C62342D59EBAC00047DF2 /* ProxyRequestHandler.cpp */, + BE4C62352D59EBAC00047DF2 /* QuarantineUtil.hpp */, + BE4C62362D59EBAC00047DF2 /* QuarantineUtil.cpp */, + BE4C62372D59EBAC00047DF2 /* RemoteConfig.hpp */, + BE4C62382D59EBAC00047DF2 /* RemoteConfig.cpp */, BEA264A82CBE99340007435A /* RequestDetails.hpp */, BEA264A92CBE99340007435A /* RequestDetails.cpp */, + BE4C62392D59EBAC00047DF2 /* RequestVettingStation.hpp */, BEA264AA2CBE99340007435A /* RequestVettingStation.cpp */, - BEA264AB2CBE99340007435A /* Storage.cpp */, + BE4C623A2D59EBAC00047DF2 /* ServerAuditUtil.hpp */, + BE4C623B2D59EBAC00047DF2 /* ServerAuditUtil.cpp */, + BE4C623C2D59EBAC00047DF2 /* SpecialBrokers.hpp */, + BE4C623D2D59EBAC00047DF2 /* SpecialBrokers.cpp */, BEA264B52CBE9BEF0007435A /* Storage.hpp */, + BEA264AB2CBE99340007435A /* Storage.cpp */, + BE4C623E2D59EBAC00047DF2 /* TileCache.hpp */, BEA264AC2CBE99340007435A /* TileCache.cpp */, ); path = wsd; @@ -519,15 +672,34 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + BE4C623F2D59EBAC00047DF2 /* QuarantineUtil.cpp in Sources */, + BE4C62402D59EBAC00047DF2 /* RemoteConfig.cpp in Sources */, + BE4C62412D59EBAC00047DF2 /* ProxyProtocol.cpp in Sources */, + BE4C62422D59EBAC00047DF2 /* ProxyRequestHandler.cpp in Sources */, + BE4C62432D59EBAC00047DF2 /* FileServerUtil.cpp in Sources */, + BE4C62442D59EBAC00047DF2 /* ProofKey.cpp in Sources */, + BE4C62452D59EBAC00047DF2 /* ServerAuditUtil.cpp in Sources */, + BE4C62462D59EBAC00047DF2 /* AdminModel.cpp in Sources */, + BE4C62472D59EBAC00047DF2 /* Admin.cpp in Sources */, + BE4C62482D59EBAC00047DF2 /* Exceptions.cpp in Sources */, + BE4C62492D59EBAC00047DF2 /* SpecialBrokers.cpp in Sources */, + BE4C624A2D59EBAC00047DF2 /* FileServer.cpp in Sources */, + BE4C624B2D59EBAC00047DF2 /* HostUtil.cpp in Sources */, + BE4C624C2D59EBAC00047DF2 /* Auth.cpp in Sources */, BEA2636D2CBE38E20007435A /* Uri.cpp in Sources */, BEA264922CBE986C0007435A /* KitQueue.cpp in Sources */, + BE4C621C2D59EAA900047DF2 /* DelaySocket.cpp in Sources */, + BE4C621D2D59EAA900047DF2 /* HttpHelper.cpp in Sources */, BE9115AE2CECBD3100C597B2 /* FileUtil-unix.cpp in Sources */, BEA264932CBE986C0007435A /* KitWebSocket.cpp in Sources */, BEA264942CBE986C0007435A /* ChildSession.cpp in Sources */, BEA264952CBE986C0007435A /* Kit.cpp in Sources */, BEA264962CBE986C0007435A /* DeltaSimd.c in Sources */, + BE4C62562D59EC5400047DF2 /* WopiStorage.cpp in Sources */, + BE4C62572D59EC5400047DF2 /* CheckFileInfo.cpp in Sources */, + BE4C62582D59EC5400047DF2 /* WopiProxy.cpp in Sources */, + BE4C62592D59EC5400047DF2 /* StorageConnectionManager.cpp in Sources */, BEA2636E2CBE38E20007435A /* Util.cpp in Sources */, - BE2231B82CC679DE00385A9C /* Crypto-stub.cpp in Sources */, BEA2636F2CBE38E20007435A /* Unit.cpp in Sources */, BE9115AC2CECBD0100C597B2 /* FileUtil-apple.mm in Sources */, BEA263702CBE38E20007435A /* Log.cpp in Sources */, @@ -540,18 +712,26 @@ BEA264A12CBE98CD0007435A /* Socket.cpp in Sources */, BEA264A22CBE98CD0007435A /* HttpRequest.cpp in Sources */, BE9115B02CECBECF00C597B2 /* Util-unix.cpp in Sources */, + BE4C620E2D59E85500047DF2 /* MobileApp.cpp in Sources */, + BE4C620F2D59E85500047DF2 /* Util-macos.cpp in Sources */, + BE4C62102D59E85500047DF2 /* CoolMount.cpp in Sources */, + BE4C62112D59E85500047DF2 /* Unit-server.cpp in Sources */, + BE4C62122D59E85500047DF2 /* JailUtil.cpp in Sources */, + BE4C62132D59E85500047DF2 /* Seccomp.cpp in Sources */, + BE4C62142D59E85500047DF2 /* CommandControl.cpp in Sources */, + BE4C62152D59E85500047DF2 /* Crypto.cpp in Sources */, + BE4C62162D59E85500047DF2 /* SigUtil-server.cpp in Sources */, + BE4C62172D59E85500047DF2 /* Util-server.cpp in Sources */, BEA264A32CBE98CD0007435A /* FakeSocket.cpp in Sources */, BEA263762CBE38E20007435A /* SpookyV2.cpp in Sources */, BEA264AD2CBE99340007435A /* Storage.cpp in Sources */, BEA264AE2CBE99340007435A /* TileCache.cpp in Sources */, - BEF9E17F2D47C709004FCEB5 /* Unit-mobile.cpp in Sources */, BEA264AF2CBE99340007435A /* COOLWSD.cpp in Sources */, BEA264B02CBE99340007435A /* ClientSession.cpp in Sources */, BEA264B12CBE99340007435A /* RequestDetails.cpp in Sources */, BEA264B22CBE99340007435A /* ClientRequestDispatcher.cpp in Sources */, BE2231BA2CC67FDE00385A9C /* coolwsd-fork.cpp in Sources */, BEA264B32CBE99340007435A /* DocumentBroker.cpp in Sources */, - BE9115AA2CECBCB200C597B2 /* SigUtil-mobile.cpp in Sources */, BEA264B42CBE99340007435A /* RequestVettingStation.cpp in Sources */, BE5A7AE22D354F4000FE7D60 /* Syscall.cpp in Sources */, BEA263772CBE38E20007435A /* ConfigUtil.cpp in Sources */, From 2804a0c091562897544f4e3bcf31bcc512ab275c Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 10 Feb 2025 15:01:44 +0100 Subject: [PATCH 106/177] Consolidate the ifdef Signed-off-by: Jan Holesovsky Change-Id: Id51e5304b9df19c837e56fea4aa4efe928a5cca5 --- common/FileUtil-unix.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/FileUtil-unix.cpp b/common/FileUtil-unix.cpp index 6fddbfa929d2b..305ac8e6c01e0 100644 --- a/common/FileUtil-unix.cpp +++ b/common/FileUtil-unix.cpp @@ -61,7 +61,7 @@ namespace FileUtil return path; } -#if !defined(IOS) && !defined(MACOS) // iOS-specific implementation in FileUtil-apple.cpp +#if !defined(__APPLE__) // iOS-specific implementation in FileUtil-apple.cpp bool platformDependentCheckDiskSpace(const std::string& path, int64_t enoughSpace) { From f25629236eaeeae8680fba540b287fa2feaa0877 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 10 Feb 2025 15:02:22 +0100 Subject: [PATCH 107/177] coda-m: Fix most of the linking issues (but some are still left) Signed-off-by: Jan Holesovsky Change-Id: Ia9d09606971c1bbc381fe8ddf581aded8ac64cdf --- macos/coda/coda.xcodeproj/project.pbxproj | 54 ++++++++++++++++++----- 1 file changed, 42 insertions(+), 12 deletions(-) diff --git a/macos/coda/coda.xcodeproj/project.pbxproj b/macos/coda/coda.xcodeproj/project.pbxproj index 14e59b6c8bcdc..86c9992a764f1 100644 --- a/macos/coda/coda.xcodeproj/project.pbxproj +++ b/macos/coda/coda.xcodeproj/project.pbxproj @@ -9,7 +9,6 @@ /* Begin PBXBuildFile section */ BE16C9F02CD51F58005E5960 /* hello.odt in Resources */ = {isa = PBXBuildFile; fileRef = BE16C9EF2CD51F58005E5960 /* hello.odt */; }; BE2231BA2CC67FDE00385A9C /* coolwsd-fork.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE2231B92CC67FDE00385A9C /* coolwsd-fork.cpp */; }; - BE2231BC2CC6804D00385A9C /* Util-mobile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE2231BB2CC6804D00385A9C /* Util-mobile.cpp */; }; BE22492C2CC79AD700385A9C /* cool.html in Resources */ = {isa = PBXBuildFile; fileRef = BE22492B2CC79AD700385A9C /* cool.html */; }; BE2252292CC79BAE00385A9C /* bundle.js in Resources */ = {isa = PBXBuildFile; fileRef = BE22492E2CC79BAE00385A9C /* bundle.js */; }; BE22529E2CC79BAE00385A9C /* cool-help.html in Resources */ = {isa = PBXBuildFile; fileRef = BE22492F2CC79BAE00385A9C /* cool-help.html */; }; @@ -47,8 +46,9 @@ BE4C62572D59EC5400047DF2 /* CheckFileInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C624F2D59EC5400047DF2 /* CheckFileInfo.cpp */; }; BE4C62582D59EC5400047DF2 /* WopiProxy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C62532D59EC5400047DF2 /* WopiProxy.cpp */; }; BE4C62592D59EC5400047DF2 /* StorageConnectionManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C62512D59EC5400047DF2 /* StorageConnectionManager.cpp */; }; + BE4C625C2D5A3C8A00047DF2 /* Ssl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C625B2D5A3C8A00047DF2 /* Ssl.cpp */; }; + BE4C625E2D5A3DDA00047DF2 /* Kit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C625D2D5A3DDA00047DF2 /* Kit.cpp */; }; BE5A7AE22D354F4000FE7D60 /* Syscall.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5A7AE12D354F4000FE7D60 /* Syscall.cpp */; }; - BE9115AC2CECBD0100C597B2 /* FileUtil-apple.mm in Sources */ = {isa = PBXBuildFile; fileRef = BE9115AB2CECBD0100C597B2 /* FileUtil-apple.mm */; }; BE9115AE2CECBD3100C597B2 /* FileUtil-unix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE9115AD2CECBD3100C597B2 /* FileUtil-unix.cpp */; }; BE9115B02CECBECF00C597B2 /* Util-unix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE9115AF2CECBECF00C597B2 /* Util-unix.cpp */; }; BEA2636D2CBE38E20007435A /* Uri.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA2636A2CBE38E20007435A /* Uri.cpp */; }; @@ -68,7 +68,6 @@ BEA264922CBE986C0007435A /* KitQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA264902CBE986C0007435A /* KitQueue.cpp */; }; BEA264932CBE986C0007435A /* KitWebSocket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA264912CBE986C0007435A /* KitWebSocket.cpp */; }; BEA264942CBE986C0007435A /* ChildSession.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA2648D2CBE986C0007435A /* ChildSession.cpp */; }; - BEA264952CBE986C0007435A /* Kit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA2648E2CBE986C0007435A /* Kit.cpp */; }; BEA264962CBE986C0007435A /* DeltaSimd.c in Sources */ = {isa = PBXBuildFile; fileRef = BEA2648C2CBE986C0007435A /* DeltaSimd.c */; }; BEA264A02CBE98CD0007435A /* NetUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA2649C2CBE98CD0007435A /* NetUtil.cpp */; }; BEA264A12CBE98CD0007435A /* Socket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA2649E2CBE98CD0007435A /* Socket.cpp */; }; @@ -105,7 +104,6 @@ /* Begin PBXFileReference section */ BE16C9EF2CD51F58005E5960 /* hello.odt */ = {isa = PBXFileReference; lastKnownFileType = file; name = hello.odt; path = ../../../test/data/hello.odt; sourceTree = ""; }; BE2231B92CC67FDE00385A9C /* coolwsd-fork.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "coolwsd-fork.cpp"; path = "../../../../wsd/coolwsd-fork.cpp"; sourceTree = ""; }; - BE2231BB2CC6804D00385A9C /* Util-mobile.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "Util-mobile.cpp"; path = "../../../../common/Util-mobile.cpp"; sourceTree = ""; }; BE22492B2CC79AD700385A9C /* cool.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = cool.html; path = ../../../browser/dist/cool.html; sourceTree = ""; }; BE22492D2CC79BAE00385A9C /* bundle.css */ = {isa = PBXFileReference; lastKnownFileType = text.css; name = bundle.css; path = ../../../browser/dist/bundle.css; sourceTree = ""; }; BE22492E2CC79BAE00385A9C /* bundle.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = bundle.js; path = ../../../browser/dist/bundle.js; sourceTree = ""; }; @@ -175,10 +173,12 @@ BE4C62532D59EC5400047DF2 /* WopiProxy.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = WopiProxy.cpp; path = ../../../../../wsd/wopi/WopiProxy.cpp; sourceTree = ""; }; BE4C62542D59EC5400047DF2 /* WopiStorage.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = WopiStorage.hpp; path = ../../../../../wsd/wopi/WopiStorage.hpp; sourceTree = ""; }; BE4C62552D59EC5400047DF2 /* WopiStorage.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = WopiStorage.cpp; path = ../../../../../wsd/wopi/WopiStorage.cpp; sourceTree = ""; }; + BE4C625A2D5A3C8A00047DF2 /* Ssl.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Ssl.hpp; path = ../../../../net/Ssl.hpp; sourceTree = ""; }; + BE4C625B2D5A3C8A00047DF2 /* Ssl.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Ssl.cpp; path = ../../../../net/Ssl.cpp; sourceTree = ""; }; + BE4C625D2D5A3DDA00047DF2 /* Kit.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Kit.cpp; path = ../../../../kit/Kit.cpp; sourceTree = ""; }; BE5A7A282D2BE28200FE7D60 /* FileUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = FileUtil.hpp; path = ../../../../common/FileUtil.hpp; sourceTree = ""; }; BE5A7AE02D354F4000FE7D60 /* Syscall.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Syscall.hpp; path = ../../../../common/Syscall.hpp; sourceTree = ""; }; BE5A7AE12D354F4000FE7D60 /* Syscall.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Syscall.cpp; path = ../../../../common/Syscall.cpp; sourceTree = ""; }; - BE9115AB2CECBD0100C597B2 /* FileUtil-apple.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "FileUtil-apple.mm"; path = "../../../../common/FileUtil-apple.mm"; sourceTree = ""; }; BE9115AD2CECBD3100C597B2 /* FileUtil-unix.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "FileUtil-unix.cpp"; path = "../../../../common/FileUtil-unix.cpp"; sourceTree = ""; }; BE9115AF2CECBECF00C597B2 /* Util-unix.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "Util-unix.cpp"; path = "../../../../common/Util-unix.cpp"; sourceTree = ""; }; BEA263522CBE38E20007435A /* Authorization.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Authorization.hpp; path = ../../../../common/Authorization.hpp; sourceTree = ""; }; @@ -212,7 +212,6 @@ BEA2648B2CBE986C0007435A /* DeltaSimd.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = DeltaSimd.h; path = ../../../../kit/DeltaSimd.h; sourceTree = ""; }; BEA2648C2CBE986C0007435A /* DeltaSimd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = DeltaSimd.c; path = ../../../../kit/DeltaSimd.c; sourceTree = ""; }; BEA2648D2CBE986C0007435A /* ChildSession.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ChildSession.cpp; path = ../../../../kit/ChildSession.cpp; sourceTree = ""; }; - BEA2648E2CBE986C0007435A /* Kit.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Kit.cpp; path = ../../../../kit/Kit.cpp; sourceTree = ""; }; BEA2648F2CBE986C0007435A /* KitQueue.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = KitQueue.hpp; path = ../../../../kit/KitQueue.hpp; sourceTree = ""; }; BEA264902CBE986C0007435A /* KitQueue.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = KitQueue.cpp; path = ../../../../kit/KitQueue.cpp; sourceTree = ""; }; BEA264912CBE986C0007435A /* KitWebSocket.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = KitWebSocket.cpp; path = ../../../../kit/KitWebSocket.cpp; sourceTree = ""; }; @@ -331,7 +330,6 @@ BE4C62022D59E85500047DF2 /* Crypto.cpp */, BE5A7A282D2BE28200FE7D60 /* FileUtil.hpp */, BEA263562CBE38E20007435A /* FileUtil.cpp */, - BE9115AB2CECBD0100C597B2 /* FileUtil-apple.mm */, BE9115AD2CECBD3100C597B2 /* FileUtil-unix.cpp */, BE4C62032D59E85500047DF2 /* JailUtil.hpp */, BE4C62042D59E85500047DF2 /* JailUtil.cpp */, @@ -366,7 +364,6 @@ BEA2636B2CBE38E20007435A /* Util.hpp */, BEA2636C2CBE38E20007435A /* Util.cpp */, BE4C620C2D59E85500047DF2 /* Util-macos.cpp */, - BE2231BB2CC6804D00385A9C /* Util-mobile.cpp */, BE4C620D2D59E85500047DF2 /* Util-server.cpp */, BE9115AF2CECBECF00C597B2 /* Util-unix.cpp */, ); @@ -390,7 +387,7 @@ BEA2648B2CBE986C0007435A /* DeltaSimd.h */, BEA2648C2CBE986C0007435A /* DeltaSimd.c */, BEA2648D2CBE986C0007435A /* ChildSession.cpp */, - BEA2648E2CBE986C0007435A /* Kit.cpp */, + BE4C625D2D5A3DDA00047DF2 /* Kit.cpp */, BEA2648F2CBE986C0007435A /* KitQueue.hpp */, BEA264902CBE986C0007435A /* KitQueue.cpp */, BEA264912CBE986C0007435A /* KitWebSocket.cpp */, @@ -414,6 +411,8 @@ BEA2649C2CBE98CD0007435A /* NetUtil.cpp */, BEA2649D2CBE98CD0007435A /* Socket.hpp */, BEA2649E2CBE98CD0007435A /* Socket.cpp */, + BE4C625A2D5A3C8A00047DF2 /* Ssl.hpp */, + BE4C625B2D5A3C8A00047DF2 /* Ssl.cpp */, BEA2649F2CBE98CD0007435A /* WebSocketHandler.hpp */, ); path = net; @@ -672,6 +671,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + BE4C625C2D5A3C8A00047DF2 /* Ssl.cpp in Sources */, + BE4C625E2D5A3DDA00047DF2 /* Kit.cpp in Sources */, BE4C623F2D59EBAC00047DF2 /* QuarantineUtil.cpp in Sources */, BE4C62402D59EBAC00047DF2 /* RemoteConfig.cpp in Sources */, BE4C62412D59EBAC00047DF2 /* ProxyProtocol.cpp in Sources */, @@ -693,7 +694,6 @@ BE9115AE2CECBD3100C597B2 /* FileUtil-unix.cpp in Sources */, BEA264932CBE986C0007435A /* KitWebSocket.cpp in Sources */, BEA264942CBE986C0007435A /* ChildSession.cpp in Sources */, - BEA264952CBE986C0007435A /* Kit.cpp in Sources */, BEA264962CBE986C0007435A /* DeltaSimd.c in Sources */, BE4C62562D59EC5400047DF2 /* WopiStorage.cpp in Sources */, BE4C62572D59EC5400047DF2 /* CheckFileInfo.cpp in Sources */, @@ -701,10 +701,8 @@ BE4C62592D59EC5400047DF2 /* StorageConnectionManager.cpp in Sources */, BEA2636E2CBE38E20007435A /* Util.cpp in Sources */, BEA2636F2CBE38E20007435A /* Unit.cpp in Sources */, - BE9115AC2CECBD0100C597B2 /* FileUtil-apple.mm in Sources */, BEA263702CBE38E20007435A /* Log.cpp in Sources */, BEA263712CBE38E20007435A /* Simd.cpp in Sources */, - BE2231BC2CC6804D00385A9C /* Util-mobile.cpp in Sources */, BEA263722CBE38E20007435A /* FileUtil.cpp in Sources */, BEA263732CBE38E20007435A /* Session.cpp in Sources */, BEA263742CBE38E20007435A /* TraceEvent.cpp in Sources */, @@ -957,6 +955,22 @@ "@executable_path/../Frameworks", ); MARKETING_VERSION = 1.0; + OTHER_LDFLAGS = ( + "-liconv", + "-lpam", + "-lPocoFoundation", + "-lPocoUtil", + "-lPocoXML", + "-lPocoJSON", + "-lPocoNet", + "-lPocoNetSSL", + "-lPocoCrypto", + "-lzstd", + "-lpng", + "-lz", + "-lssl", + "-lcrypto", + ); PRODUCT_BUNDLE_IDENTIFIER = com.collabora.coda; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; @@ -989,6 +1003,22 @@ "@executable_path/../Frameworks", ); MARKETING_VERSION = 1.0; + OTHER_LDFLAGS = ( + "-liconv", + "-lpam", + "-lPocoFoundation", + "-lPocoUtil", + "-lPocoXML", + "-lPocoJSON", + "-lPocoNet", + "-lPocoNetSSL", + "-lPocoCrypto", + "-lzstd", + "-lpng", + "-lz", + "-lssl", + "-lcrypto", + ); PRODUCT_BUNDLE_IDENTIFIER = com.collabora.coda; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; From 5656092e4068645b9f9d1881db80c16e77980388 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 11 Feb 2025 13:59:47 +0100 Subject: [PATCH 108/177] coda-m: COOLWS is not supposed to be run twice When we try to initialize it the second time (after the 1st run() completed), we re-initialize the config file which asserts; so let's not do that, and just finish (at least the thread here). Signed-off-by: Jan Holesovsky Change-Id: I79b611a5df85c969a6dd302707fb504392e842b3 --- macos/coda/coda/COWrapper.mm | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/macos/coda/coda/COWrapper.mm b/macos/coda/coda/COWrapper.mm index f28ce6ef83b6e..10e53f6796232 100644 --- a/macos/coda/coda/COWrapper.mm +++ b/macos/coda/coda/COWrapper.mm @@ -63,13 +63,11 @@ + (void)startServer { Util::setThreadName("app"); - while (true) { - coolwsd = new COOLWSD(); - coolwsd->run(1, argv); - delete coolwsd; - coolwsd = nullptr; // Reset the pointer after deletion - LOG_TRC("One run of COOLWSD completed"); - } + coolwsd = new COOLWSD(); + coolwsd->run(1, argv); + delete coolwsd; + coolwsd = nullptr; // Reset the pointer after deletion + NSLog(@"CollaboraOffice: The COOLWSD thread completed"); }).detach(); } From 76d6044db03e00c765516382be4f287a8b85a4ef Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 11 Feb 2025 14:08:07 +0100 Subject: [PATCH 109/177] coda-m: Read coolwsd.xml from the bundle's Resources Signed-off-by: Jan Holesovsky Change-Id: Iae1c05f9468337efd089f439b123c9312cfa2657 --- macos/coda/coda.xcodeproj/project.pbxproj | 10 +++++++--- macos/coda/coda/macos.h | 5 +++++ macos/coda/coda/macos.mm | 5 +++++ wsd/COOLWSD.cpp | 7 ++++++- wsd/PlatformUnix.hpp | 5 +++++ 5 files changed, 28 insertions(+), 4 deletions(-) diff --git a/macos/coda/coda.xcodeproj/project.pbxproj b/macos/coda/coda.xcodeproj/project.pbxproj index 86c9992a764f1..de7aa5924339d 100644 --- a/macos/coda/coda.xcodeproj/project.pbxproj +++ b/macos/coda/coda.xcodeproj/project.pbxproj @@ -48,6 +48,7 @@ BE4C62592D59EC5400047DF2 /* StorageConnectionManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C62512D59EC5400047DF2 /* StorageConnectionManager.cpp */; }; BE4C625C2D5A3C8A00047DF2 /* Ssl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C625B2D5A3C8A00047DF2 /* Ssl.cpp */; }; BE4C625E2D5A3DDA00047DF2 /* Kit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C625D2D5A3DDA00047DF2 /* Kit.cpp */; }; + BE4C62612D5B736200047DF2 /* coolwsd.xml in Resources */ = {isa = PBXBuildFile; fileRef = BE4C62602D5B736200047DF2 /* coolwsd.xml */; }; BE5A7AE22D354F4000FE7D60 /* Syscall.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5A7AE12D354F4000FE7D60 /* Syscall.cpp */; }; BE9115AE2CECBD3100C597B2 /* FileUtil-unix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE9115AD2CECBD3100C597B2 /* FileUtil-unix.cpp */; }; BE9115B02CECBECF00C597B2 /* Util-unix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE9115AF2CECBECF00C597B2 /* Util-unix.cpp */; }; @@ -176,6 +177,7 @@ BE4C625A2D5A3C8A00047DF2 /* Ssl.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Ssl.hpp; path = ../../../../net/Ssl.hpp; sourceTree = ""; }; BE4C625B2D5A3C8A00047DF2 /* Ssl.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Ssl.cpp; path = ../../../../net/Ssl.cpp; sourceTree = ""; }; BE4C625D2D5A3DDA00047DF2 /* Kit.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Kit.cpp; path = ../../../../kit/Kit.cpp; sourceTree = ""; }; + BE4C62602D5B736200047DF2 /* coolwsd.xml */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = coolwsd.xml; path = ../../../coolwsd.xml; sourceTree = ""; }; BE5A7A282D2BE28200FE7D60 /* FileUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = FileUtil.hpp; path = ../../../../common/FileUtil.hpp; sourceTree = ""; }; BE5A7AE02D354F4000FE7D60 /* Syscall.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Syscall.hpp; path = ../../../../common/Syscall.hpp; sourceTree = ""; }; BE5A7AE12D354F4000FE7D60 /* Syscall.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Syscall.cpp; path = ../../../../common/Syscall.cpp; sourceTree = ""; }; @@ -284,7 +286,7 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - BE22492A2CC79AAC00385A9C /* dist */ = { + BE22492A2CC79AAC00385A9C /* Resources */ = { isa = PBXGroup; children = ( BE22AA9B2CC7AE7400385A9C /* images */, @@ -293,11 +295,12 @@ BE22492B2CC79AD700385A9C /* cool.html */, BE22492F2CC79BAE00385A9C /* cool-help.html */, BEEF3F852CE2139E00ABE785 /* coolkitconfig.xcu */, + BE4C62602D5B736200047DF2 /* coolwsd.xml */, BE2249302CC79BAE00385A9C /* device-desktop.css */, BE2249312CC79BAE00385A9C /* global.js */, BE16C9EF2CD51F58005E5960 /* hello.odt */, ); - path = dist; + path = Resources; sourceTree = ""; }; BE4C624D2D59EC1D00047DF2 /* wopi */ = { @@ -473,7 +476,7 @@ BECC4BA22CBD3FA300A120B3 = { isa = PBXGroup; children = ( - BE22492A2CC79AAC00385A9C /* dist */, + BE22492A2CC79AAC00385A9C /* Resources */, BEA2637D2CBE39C30007435A /* Online */, BECC4BAD2CBD3FA300A120B3 /* coda */, BECC4BBF2CBD3FA400A120B3 /* codaTests */, @@ -617,6 +620,7 @@ buildActionMask = 2147483647; files = ( BE22AA9C2CC7AE7400385A9C /* images in Resources */, + BE4C62612D5B736200047DF2 /* coolwsd.xml in Resources */, BE2252292CC79BAE00385A9C /* bundle.js in Resources */, BE22529E2CC79BAE00385A9C /* cool-help.html in Resources */, BE2253F32CC79BAE00385A9C /* device-desktop.css in Resources */, diff --git a/macos/coda/coda/macos.h b/macos/coda/coda/macos.h index d723bab38307a..f07ee1518bcc3 100644 --- a/macos/coda/coda/macos.h +++ b/macos/coda/coda/macos.h @@ -34,4 +34,9 @@ std::string getAppSupportURL(); */ std::string getResourceURL(const char *name, const char *ext); +/** + * Get (filelystem) path of a resource in the bundle. + */ +std::string getResourcePath(const char *name, const char *ext); + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/macos/coda/coda/macos.mm b/macos/coda/coda/macos.mm index 77792524992ca..093f6908f6e34 100644 --- a/macos/coda/coda/macos.mm +++ b/macos/coda/coda/macos.mm @@ -64,4 +64,9 @@ return std::string([[url absoluteString] UTF8String]); } +std::string getResourcePath(const char *name, const char *ext) { + NSString *path = [[NSBundle mainBundle] pathForResource:[NSString stringWithUTF8String:name] ofType:[NSString stringWithUTF8String:ext]]; + return std::string([path UTF8String]); +} + // vim:set shiftwidth=4 softtabstop=4 expandtab: diff --git a/wsd/COOLWSD.cpp b/wsd/COOLWSD.cpp index b3fb0af1ed317..54b8b33620497 100644 --- a/wsd/COOLWSD.cpp +++ b/wsd/COOLWSD.cpp @@ -784,7 +784,12 @@ std::string COOLWSD::FileServerRoot; std::string COOLWSD::ServiceRoot; std::string COOLWSD::TmpFontDir; std::string COOLWSD::LOKitVersion; -std::string COOLWSD::ConfigFile = COOLWSD_CONFIGDIR "/coolwsd.xml"; +std::string COOLWSD::ConfigFile = +#ifndef MACOS + COOLWSD_CONFIGDIR "/coolwsd.xml"; +#else + getResourcePath("coolwsd", "xml"); +#endif std::string COOLWSD::ConfigDir = COOLWSD_CONFIGDIR "/conf.d"; bool COOLWSD::EnableTraceEventLogging = false; bool COOLWSD::EnableAccessibility = false; diff --git a/wsd/PlatformUnix.hpp b/wsd/PlatformUnix.hpp index 52a1ad46c1645..90625f628b4d8 100644 --- a/wsd/PlatformUnix.hpp +++ b/wsd/PlatformUnix.hpp @@ -9,6 +9,11 @@ */ #pragma once +// macOS can be both server and mobile, so let's include it here, too +#if defined(MACOS) +#include "macos.h" +#endif + #ifdef __linux__ #if !MOBILEAPP From 347c80f2e46d3a28d86c244aced50cc668e0986f Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 11 Feb 2025 14:25:36 +0100 Subject: [PATCH 110/177] coda-m: Disable the COOLWSD main() not to conflict Introduce ENABLE_CODA for that. Signed-off-by: Jan Holesovsky Change-Id: I9752e52d1fd03629e9e4c02f7f8275550ac1f86a --- config.h.in | 3 +++ configure.ac | 2 ++ kit/Kit.cpp | 2 ++ wsd/COOLWSD.cpp | 2 +- 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/config.h.in b/config.h.in index d811b28c5bc32..84815c7454c71 100644 --- a/config.h.in +++ b/config.h.in @@ -117,6 +117,9 @@ /* Define to 1 when we should use systemplate and jails (eg. normal coolwsd server), otherwise 0 (eg. CODA). */ #undef ENABLE_CHILDROOTS +/* Define to 1 when the compiled code is supposed to be part of CODA (the entry point is from the app, not from main() etc.), otherwise 0 (ie. normal server). */ +#undef ENABLE_CODA + /* Default value of feature_lock.unlock_description */ #undef UNLOCK_DESCRIPTION diff --git a/configure.ac b/configure.ac index 44de93f31c485..72495cfad03f5 100644 --- a/configure.ac +++ b/configure.ac @@ -1556,9 +1556,11 @@ if test "$enable_coda" = "yes"; then AC_MSG_ERROR([--enable-coda currently depends on --enable-debug, please add it to ./configure. Many things haven't been updated to build a production CODA app yet.]) fi AC_DEFINE([ENABLE_CHILDROOTS],0,[Disable systemplate and jails when building CODA.]) + AC_DEFINE([ENABLE_CODA],1,[Enable the CODA build - disable the main() function in COOLWSD etc.]) else AC_MSG_RESULT([no]) AC_DEFINE([ENABLE_CHILDROOTS],1,[Normal server, enable systemplate and jails.]) + AC_DEFINE([ENABLE_CODA],0,[Disable the CODA build - normal server, the main() function in COOLWSD is the entry point, etc.]) fi if test "$host_os" = "emscripten" ; then diff --git a/kit/Kit.cpp b/kit/Kit.cpp index 5de83f9a13754..4300a1d23de43 100644 --- a/kit/Kit.cpp +++ b/kit/Kit.cpp @@ -2903,6 +2903,7 @@ static void addRecording(const std::string &recording, bool force) traceEventRecords[force ? 0 : 1].push_back(recording + "\n"); } +#if !ENABLE_CODA // ie. normal server void TraceEvent::emitOneRecordingIfEnabled(const std::string &recording) { addRecording(recording, true); @@ -2912,6 +2913,7 @@ void TraceEvent::emitOneRecording(const std::string &recording) { addRecording(recording, false); } +#endif // !ENABLE_CODA #else diff --git a/wsd/COOLWSD.cpp b/wsd/COOLWSD.cpp index 54b8b33620497..9bc575a1834d8 100644 --- a/wsd/COOLWSD.cpp +++ b/wsd/COOLWSD.cpp @@ -4374,7 +4374,7 @@ void forwardSignal(const int signum) #endif // Avoid this in the Util::isFuzzing() case because libfuzzer defines its own main(). -#if !MOBILEAPP && !LIBFUZZER +#if !MOBILEAPP && !LIBFUZZER && !ENABLE_CODA int main(int argc, char** argv) { From 1c3b7d457670e80f7df54cf6f7350ee9d640d338 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 11 Feb 2025 14:53:28 +0100 Subject: [PATCH 111/177] coda-m: Pass the options needed for the coolwsd-inside-CODA functionality Signed-off-by: Jan Holesovsky Change-Id: I4789f747e8b6d550d75ac22214046d89d60c960c --- macos/coda/coda/COWrapper.mm | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/macos/coda/coda/COWrapper.mm b/macos/coda/coda/COWrapper.mm index 10e53f6796232..0ff61a8e97e7d 100644 --- a/macos/coda/coda/COWrapper.mm +++ b/macos/coda/coda/COWrapper.mm @@ -57,14 +57,29 @@ + (void)startServer { assert(coolwsd == nullptr); // Prepare arguments for COOLWSD - char *argv[2]; - argv[0] = strdup("mobile"); - argv[1] = nullptr; + const int argc = 10; + char *argv[argc + 1]; + argv[0] = strdup("coda"); + //--o:sys_template_path="$(PROJECT_DIR)/../../systemplate" + //--o:child_root_path="$(PROJECT_DIR)/../../jails" + argv[1] = strdup("--o:security.capabilities=false"); + argv[2] = strdup("--o:storage.filesystem[@allow]=true"); + argv[3] = strdup("--o:logging.color=false"); + argv[4] = strdup("--o:logging.file[@enable]=false"); + argv[5] = strdup("--o:logging.level=trace"); + argv[6] = strdup("--o:trace_event[@enable]=true"); + argv[7] = strdup("--o:ssl.enable=false"); + //argv[] = strdup("--o:ssl.cert_file_path="$(PROJECT_DIR)/../../etc/cert.pem" + //argv[] = strdup("--o:ssl.key_file_path="$(PROJECT_DIR)/../../etc/key.pem" + //argv[] = strdup("--o:ssl.ca_file_path="$(PROJECT_DIR)/../../etc/ca-chain.cert.pem" + argv[8] = strdup("--o:admin_console.username=admin"); + argv[9] = strdup("--o:admin_console.password=admin"); + argv[10] = nullptr; Util::setThreadName("app"); coolwsd = new COOLWSD(); - coolwsd->run(1, argv); + coolwsd->run(argc, argv); delete coolwsd; coolwsd = nullptr; // Reset the pointer after deletion NSLog(@"CollaboraOffice: The COOLWSD thread completed"); From 14b1cc599337898b5d8ade9935c133685df6b95e Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 11 Feb 2025 15:06:34 +0100 Subject: [PATCH 112/177] coda-m: Update README to match the current developments Signed-off-by: Jan Holesovsky Change-Id: I2e73feace67663459242e583db1b034330cf9559 --- macos/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/macos/README.md b/macos/README.md index cab4ef8088b22..b1c639d3b8e53 100644 --- a/macos/README.md +++ b/macos/README.md @@ -57,9 +57,9 @@ autogen.input: Configure Collabora Online ./autogen.sh && ./configure \ - --enable-macosapp \ - --with-app-name="Collabora Office" \ + --enable-debug --enable-coda \ --enable-experimental \ + --with-app-name="Collabora Office" \ --with-vendor="Collabora Productivity" \ --with-poco-includes=/opt/homebrew/opt/poco/include \ --with-poco-libs=/opt/homebrew/opt/poco/lib \ From e1ca335b6c9b53519c0245def7b88460ca0bff97 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 17 Feb 2025 11:24:50 +0100 Subject: [PATCH 113/177] coda-m: Handle discovery.xml Signed-off-by: Jan Holesovsky Change-Id: I0fa0c72484302ceefdabdace8926e7cd5fde6e85 --- macos/coda/coda.xcodeproj/project.pbxproj | 4 ++++ macos/coda/coda/COWrapper.mm | 5 +++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/macos/coda/coda.xcodeproj/project.pbxproj b/macos/coda/coda.xcodeproj/project.pbxproj index de7aa5924339d..afb184a9463c1 100644 --- a/macos/coda/coda.xcodeproj/project.pbxproj +++ b/macos/coda/coda.xcodeproj/project.pbxproj @@ -83,6 +83,7 @@ BEA264B32CBE99340007435A /* DocumentBroker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA264A72CBE99340007435A /* DocumentBroker.cpp */; }; BEA264B42CBE99340007435A /* RequestVettingStation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA264AA2CBE99340007435A /* RequestVettingStation.cpp */; }; BEEF3F862CE2139E00ABE785 /* coolkitconfig.xcu in Resources */ = {isa = PBXBuildFile; fileRef = BEEF3F852CE2139E00ABE785 /* coolkitconfig.xcu */; }; + BEF5CE8F2D633CE60006FD77 /* discovery.xml in Resources */ = {isa = PBXBuildFile; fileRef = BEF5CE8E2D633CE60006FD77 /* discovery.xml */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -241,6 +242,7 @@ BECC4BC62CBD3FA400A120B3 /* codaUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = codaUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; BEEF3F822CE20BDD00ABE785 /* SetupKitEnvironment.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = SetupKitEnvironment.hpp; path = ../../../../kit/SetupKitEnvironment.hpp; sourceTree = ""; }; BEEF3F852CE2139E00ABE785 /* coolkitconfig.xcu */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = coolkitconfig.xcu; path = ../../../coolkitconfig.xcu; sourceTree = ""; }; + BEF5CE8E2D633CE60006FD77 /* discovery.xml */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = discovery.xml; path = ../../../discovery.xml; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFileSystemSynchronizedRootGroup section */ @@ -297,6 +299,7 @@ BEEF3F852CE2139E00ABE785 /* coolkitconfig.xcu */, BE4C62602D5B736200047DF2 /* coolwsd.xml */, BE2249302CC79BAE00385A9C /* device-desktop.css */, + BEF5CE8E2D633CE60006FD77 /* discovery.xml */, BE2249312CC79BAE00385A9C /* global.js */, BE16C9EF2CD51F58005E5960 /* hello.odt */, ); @@ -620,6 +623,7 @@ buildActionMask = 2147483647; files = ( BE22AA9C2CC7AE7400385A9C /* images in Resources */, + BEF5CE8F2D633CE60006FD77 /* discovery.xml in Resources */, BE4C62612D5B736200047DF2 /* coolwsd.xml in Resources */, BE2252292CC79BAE00385A9C /* bundle.js in Resources */, BE22529E2CC79BAE00385A9C /* cool-help.html in Resources */, diff --git a/macos/coda/coda/COWrapper.mm b/macos/coda/coda/COWrapper.mm index 0ff61a8e97e7d..4a59af319b79f 100644 --- a/macos/coda/coda/COWrapper.mm +++ b/macos/coda/coda/COWrapper.mm @@ -57,7 +57,7 @@ + (void)startServer { assert(coolwsd == nullptr); // Prepare arguments for COOLWSD - const int argc = 10; + const int argc = 11; char *argv[argc + 1]; argv[0] = strdup("coda"); //--o:sys_template_path="$(PROJECT_DIR)/../../systemplate" @@ -74,7 +74,8 @@ + (void)startServer { //argv[] = strdup("--o:ssl.ca_file_path="$(PROJECT_DIR)/../../etc/ca-chain.cert.pem" argv[8] = strdup("--o:admin_console.username=admin"); argv[9] = strdup("--o:admin_console.password=admin"); - argv[10] = nullptr; + argv[10] = strdup(("--o:file_server_root_path=" + getBundlePath() + "/Contents/Resources").c_str()); + argv[11] = nullptr; Util::setThreadName("app"); From 43e42ac5d6804c0b933a2377027386431c6b84a7 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 17 Feb 2025 12:09:21 +0100 Subject: [PATCH 114/177] coda-m: Add Incoming connections (Server) entitlement Without this, attempting to bind to socket on port 9980 gives EPERM: Operation not permitted. Signed-off-by: Jan Holesovsky Change-Id: If685a4affbf88901a671d8fcdedff42aa71934a5 --- macos/coda/coda/coda.entitlements | 2 ++ 1 file changed, 2 insertions(+) diff --git a/macos/coda/coda/coda.entitlements b/macos/coda/coda/coda.entitlements index a2420ac9df92e..3890e5fb34708 100644 --- a/macos/coda/coda/coda.entitlements +++ b/macos/coda/coda/coda.entitlements @@ -12,5 +12,7 @@ com.apple.security.network.client + com.apple.security.network.server + From 0b353cc61d0dcfa855a4f29635df2aff328d7137 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Wed, 12 Feb 2025 12:26:10 +0200 Subject: [PATCH 115/177] Drop acidental extra slash Signed-off-by: Tor Lillqvist Change-Id: I33166a1b6fb6e3f3b44b38cc4da1992d3338dc55 --- windows/coda/CODA/MainWindow.xaml.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/windows/coda/CODA/MainWindow.xaml.cs b/windows/coda/CODA/MainWindow.xaml.cs index 587a55b60e6da..5edf93bd24f48 100644 --- a/windows/coda/CODA/MainWindow.xaml.cs +++ b/windows/coda/CODA/MainWindow.xaml.cs @@ -239,7 +239,7 @@ void WebView_CoreWebView2InitializationCompleted(object sender, CoreWebView2Init } else { - webView.CoreWebView2.Navigate("file:///C:/Users/tml/lo/online-gitlab-coda/browser/dist//cool.html?file_path=file:///C:/Users/tml/sailing.odt&closebutton=1&permission=edit&lang=en-US&appdocid=1&userinterfacemode=notebookbar&dir=ltr"); + webView.CoreWebView2.Navigate("file:///C:/Users/tml/lo/online-gitlab-coda/browser/dist/cool.html?file_path=file:///C:/Users/tml/sailing.odt&closebutton=1&permission=edit&lang=en-US&appdocid=1&userinterfacemode=notebookbar&dir=ltr"); } OnWebViewFirstInitialized?.Invoke(); From 6fbcd5057921aa0ac5ef0cfddee61dbb0295f097 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Tue, 18 Feb 2025 10:38:52 +0200 Subject: [PATCH 116/177] Construct a file: Poco::URI by passing a Poco::Path Instead of passing a Poco::URI for just file:// and the pathname separately. In such a case Poco will apparently interpret the second parameter, when it is a Windows path that starts with a drive letter, as a URI with the drive letter as the scheme, and ignore the first parameter. Resulting in a bogus URI like c://Users/tml/sailing.odt or something. It seems simple: If you want a file: URI, pass a Poco::Path that by definition is a file. Signed-off-by: Tor Lillqvist Change-Id: I2d8d9cdf233f09decf69b217f5429ad18d9c3df8 --- wsd/DocumentBroker.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wsd/DocumentBroker.cpp b/wsd/DocumentBroker.cpp index 1e2168da7fab2..0307c04824e30 100644 --- a/wsd/DocumentBroker.cpp +++ b/wsd/DocumentBroker.cpp @@ -1316,14 +1316,14 @@ bool DocumentBroker::doDownloadDocument(const Authorization& auth, std::string localPathEncoded; Poco::URI::encode(localPath, "#?", localPathEncoded); - _uriJailed = Poco::URI(Poco::URI("file://"), localPathEncoded).toString(); + _uriJailed = Poco::URI(Poco::Path(localPath)).toString(); _uriJailedAnonym = - Poco::URI(Poco::URI("file://"), COOLWSD::anonymizeUrl(localPathEncoded)).toString(); + Poco::URI(Poco::Path(COOLWSD::anonymizeUrl(localPathEncoded))).toString(); for (const auto& it : additionalFileLocalPaths) { std::string additionalFileLocalPathEncoded; Poco::URI::encode(it.second, "#?", additionalFileLocalPathEncoded); - _additionalFileUrisJailed[it.first] = Poco::URI(Poco::URI("file://"), additionalFileLocalPathEncoded).toString(); + _additionalFileUrisJailed[it.first] = Poco::URI(Poco::Path(additionalFileLocalPathEncoded)).toString(); } _filename = filename; From 6734dbb00536e68bb62f513805dfee428914db49 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Tue, 18 Feb 2025 10:44:55 +0200 Subject: [PATCH 117/177] Windows-specific pathname fixes In some cases we ended up with a monstrosity like "/C:/Users/tml/sailing.odt" which obviously is meaningless, and we then still tried to use it as a filename. In another place we then actually do need to add that prefix slash back before doing something with it. Oh well. Possibly things would be simpler if we rigorously everywhere used either Poco::URI or Poco::Path types, except for at the very last moment when we need an actual local file pathname? Signed-off-by: Tor Lillqvist Change-Id: Idb44f35e014097040a8af2ec3d41e4b1595932da --- wsd/ClientSession.cpp | 10 +++++++++- wsd/RequestDetails.cpp | 6 +++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/wsd/ClientSession.cpp b/wsd/ClientSession.cpp index 1cd185e0c459a..5865199469314 100644 --- a/wsd/ClientSession.cpp +++ b/wsd/ClientSession.cpp @@ -1689,9 +1689,17 @@ bool ClientSession::loadDocument(const char* /*buffer*/, int /*length*/, parseDocOptions(tokens, loadPart, timestamp); overrideDocOption(); + auto publicUri = docBroker->getPublicUri(); +#ifdef _WIN32 + // See comment in RequestDetails::sanitizeURI() + auto p = publicUri.getPath(); + if (p.length() > 3 && isalpha(p[0]) && p[1] == ':' && p[2] == '/') + publicUri.setPath("/" + p); +#endif + std::ostringstream oss; oss << std::boolalpha; - oss << "load url=" << docBroker->getPublicUri().toString(); + oss << "load url=" << publicUri.toString(); #if ENABLE_SSL // if ssl client verification was disabled in online for the wopi server, diff --git a/wsd/RequestDetails.cpp b/wsd/RequestDetails.cpp index 8e962513f20bb..9dc4811b88689 100644 --- a/wsd/RequestDetails.cpp +++ b/wsd/RequestDetails.cpp @@ -275,7 +275,7 @@ void RequestDetails::processURI() Poco::URI RequestDetails::sanitizeURI(const std::string& uri) { - // The URI of the document should be url-encoded. + // The URI of the document is url-encoded, except that in a mobile app it isn't? Poco::URI uriPublic((Util::isMobileApp() ? uri : Uri::decode(uri))); if (uriPublic.isRelative() || uriPublic.getScheme() == "file") @@ -283,6 +283,10 @@ Poco::URI RequestDetails::sanitizeURI(const std::string& uri) // TODO: Validate and limit access to local paths! uriPublic.normalize(); #ifdef _WIN32 + // Change a bogus path like /C:/Users/tml/foo.odt to C:/Users/tml/foo.odt. If this path then + // later is changed back into a file: URI, as in ClientSession::loadDocument(), we can't + // just prefix "file://" but need one more slash. So maybe it would in fact be simpler to + // just keep the seemingly bogus /C:/Users/tml/foo.odt? std::string p = uriPublic.getPath(); if (p.length() > 4 && p[0] == '/' && std::isalpha(p[1]) && p[2] == ':' && p[3] == '/') uriPublic.setPath(p.substr(1)); From 3b712055049f14b019b411d96c0816d20f876248 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Tue, 18 Feb 2025 12:47:21 +0200 Subject: [PATCH 118/177] Silence one more verbose INFO log tag Signed-off-by: Tor Lillqvist Change-Id: Id6b7cea389c4037ecb66a8ed678e347149be384a --- windows/coda/CODA/Properties/launchSettings.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/windows/coda/CODA/Properties/launchSettings.json b/windows/coda/CODA/Properties/launchSettings.json index efe5615189826..bf17ec1467349 100644 --- a/windows/coda/CODA/Properties/launchSettings.json +++ b/windows/coda/CODA/Properties/launchSettings.json @@ -3,10 +3,10 @@ "CODA": { "commandName": "Project", "environmentVariables": { - "SAL_LOG": "+INFO+WARN-INFO.sal.bootstrap-INFO.i18nlangtag-INFO.vcl.fonts" + "SAL_LOG": "+INFO+WARN-INFO.sal.bootstrap-INFO.i18nlangtag-INFO.vcl.fonts-INFO.vcl.gdi.fontmetric" }, "nativeDebugging": true, "jsWebView2Debugging": false } } -} \ No newline at end of file +} From bd7e969b561478a8d53f70a36eb41ed7c979314a Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Thu, 20 Feb 2025 11:53:34 +0100 Subject: [PATCH 119/177] coda-m: Fix the build of normal coolwsd on macOS again Signed-off-by: Jan Holesovsky Change-Id: I98f81fd8233a28289a7498c536f9e134f6eb7221 --- wsd/COOLWSD.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wsd/COOLWSD.cpp b/wsd/COOLWSD.cpp index 9bc575a1834d8..35bb828c9fa23 100644 --- a/wsd/COOLWSD.cpp +++ b/wsd/COOLWSD.cpp @@ -785,10 +785,10 @@ std::string COOLWSD::ServiceRoot; std::string COOLWSD::TmpFontDir; std::string COOLWSD::LOKitVersion; std::string COOLWSD::ConfigFile = -#ifndef MACOS - COOLWSD_CONFIGDIR "/coolwsd.xml"; -#else +#if defined(MACOS) && ENABLE_CODA getResourcePath("coolwsd", "xml"); +#else + COOLWSD_CONFIGDIR "/coolwsd.xml"; #endif std::string COOLWSD::ConfigDir = COOLWSD_CONFIGDIR "/conf.d"; bool COOLWSD::EnableTraceEventLogging = false; From 64de50397be40bbbb4739071a611af11f4a1d50f Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Thu, 20 Feb 2025 16:35:27 +0200 Subject: [PATCH 120/177] It's only CODA-M that handles the MODIFIED message for now Signed-off-by: Tor Lillqvist Change-Id: Ic33a5312492392b05266098a2afa5707d38bbbe9 --- browser/src/map/Map.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/browser/src/map/Map.js b/browser/src/map/Map.js index fc92fe9a6f1c3..2b89c353cdf2b 100644 --- a/browser/src/map/Map.js +++ b/browser/src/map/Map.js @@ -241,7 +241,7 @@ window.L.Map = window.L.Evented.extend({ // Fire an event to let the client know whether the document needs saving or not. this.fire('postMessage', {msgId: 'Doc_ModifiedStatus', args: { Modified: e.state === 'true' }}); - if (window.ThisIsAMobileApp) { + if (window.ThisIsTheMacOSApp) { window.postMobileMessage('MODIFIED ' + e.state); } From c2e0cbda6953c2e8e78a652f3842a7855ef46090 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Fri, 21 Feb 2025 08:59:39 +0100 Subject: [PATCH 121/177] Handle the abstract vs. regular socket names transparently On Linux, there are 'abstract sockets' that don't have a filesystem path. The distinction from regular unx sockets is that their name starts with a null byte '\0', which makes the handling a bit confusing when the code depends on a #define - the length differs, and also it is harder to do debugging printouts. This commit abstracts this by centralizing the adding of '\0' into one place. Signed-off-by: Jan Holesovsky Change-Id: I5279a85c0182620170cf0f23a1249e12837fc87c --- common/Common.hpp | 3 ++- kit/ForKit.cpp | 3 ++- kit/Kit.cpp | 2 +- kit/forkit-main.cpp | 3 ++- net/ServerSocket.hpp | 54 +++++++++++++++++++++++++++++++++++---- net/Socket.cpp | 61 ++++++++++++++++++++------------------------ net/Socket.hpp | 3 ++- wsd/COOLWSD.cpp | 12 ++++----- 8 files changed, 91 insertions(+), 50 deletions(-) diff --git a/common/Common.hpp b/common/Common.hpp index 04bd04ffa1950..196fa68cfc80e 100644 --- a/common/Common.hpp +++ b/common/Common.hpp @@ -86,7 +86,8 @@ constexpr const char UPLOADING_SUFFIX[] = "ing"; /// The client port number, both coolwsd and the kits have this. extern int ClientPortNumber; -extern std::string MasterLocation; +class UnxSocketPath; +extern UnxSocketPath MasterLocation; /// Controls whether experimental features/behavior is enabled or not. extern bool EnableExperimental; diff --git a/kit/ForKit.cpp b/kit/ForKit.cpp index 771f47dc277a3..ee2dd3bbe0562 100644 --- a/kit/ForKit.cpp +++ b/kit/ForKit.cpp @@ -51,6 +51,7 @@ #include #include #include +#include #include namespace @@ -916,7 +917,7 @@ int forkit_main(int argc, char** argv) else if (std::strstr(cmd, "--masterport=") == cmd) { eq = std::strchr(cmd, '='); - MasterLocation = std::string(eq+1); + MasterLocation = UnxSocketPath(std::string(eq+1)); } else if (std::strstr(cmd, "--version") == cmd) { diff --git a/kit/Kit.cpp b/kit/Kit.cpp index 4300a1d23de43..22d709ba5fb85 100644 --- a/kit/Kit.cpp +++ b/kit/Kit.cpp @@ -2875,6 +2875,7 @@ void flushTraceEventRecordings() } } +#if !ENABLE_CODA // ie. normal server static void addRecording(const std::string &recording, bool force) { // This can be called before the config system is initialized. Guard against that, as calling @@ -2903,7 +2904,6 @@ static void addRecording(const std::string &recording, bool force) traceEventRecords[force ? 0 : 1].push_back(recording + "\n"); } -#if !ENABLE_CODA // ie. normal server void TraceEvent::emitOneRecordingIfEnabled(const std::string &recording) { addRecording(recording, true); diff --git a/kit/forkit-main.cpp b/kit/forkit-main.cpp index c405253d6b8fb..6be3829b560fc 100644 --- a/kit/forkit-main.cpp +++ b/kit/forkit-main.cpp @@ -12,9 +12,10 @@ #include "config.h" #include "Common.hpp" #include "Kit.hpp" +#include "ServerSocket.hpp" int ClientPortNumber = DEFAULT_CLIENT_PORT_NUMBER; -std::string MasterLocation; +UnxSocketPath MasterLocation; int main (int argc, char **argv) { diff --git a/net/ServerSocket.hpp b/net/ServerSocket.hpp index 771f794982e85..d352fdd2ae0f4 100644 --- a/net/ServerSocket.hpp +++ b/net/ServerSocket.hpp @@ -11,6 +11,10 @@ #pragma once +#ifndef _WIN32 +#include +#endif + #include "NetUtil.hpp" #include "memory" @@ -128,6 +132,46 @@ class ServerSocket : public Socket #if !MOBILEAPP +/// Class to remember the socket name, and abstract the fact if it's an abstract unix socket, or real one (backed by a file). +class UnxSocketPath { + +private: + std::string _name; + +public: + UnxSocketPath() : _name() {} + UnxSocketPath(const std::string& name) : _name(name) {} + + /// Make sure we construct the name correctly, based on whether we create the + /// abstract socket, or a normal one. + void fillInto(struct sockaddr_un& addrunix) const { + assert(!_name.empty() && "Trying to use an invalid unx socket"); + +#ifdef HAVE_ABSTRACT_UNIX_SOCKETS + std::memcpy(&addrunix.sun_path[1], _name.c_str(), _name.length()); + addrunix.sun_path[0] = '\0'; // this is an abstract name +#else + std::memcpy(addrunix.sun_path, _name.c_str(), _name.length()); +#endif + LOG_ASSERT_MSG(addrunix.sun_path[sizeof(addrunix.sun_path) - 1] == '\0', + "addrunix.sun_path is not null terminated"); + } + + /// Is this a valid path? + bool isValid() const { + return !_name.empty(); + } + + /// Return the name - either for debugging printount, or for passing as --masterport= + const std::string& getName() const { + return _name; + } +}; + +inline std::ostream& operator<<(std::ostream& os, const UnxSocketPath &s) { + return os << s.getName(); +} + /// A non-blocking, streaming Unix Domain Socket for local use class LocalServerSocket : public ServerSocket { @@ -141,13 +185,13 @@ class LocalServerSocket : public ServerSocket bool bind(Type, int) override { assert(false); return false; } std::shared_ptr accept() override; - std::string bind(); -#ifndef HAVE_ABSTRACT_UNIX_SOCKETS - bool link(std::string to); -#endif + UnxSocketPath bind(); + + /// Links the socket to the location 'toPath', in case it is not an abstract socket. For abstract sockets, it return 'true' right away. + bool linkTo(std::string toPath); private: - std::string _name; + UnxSocketPath _id; #ifndef HAVE_ABSTRACT_UNIX_SOCKETS std::string _linkName; #endif diff --git a/net/Socket.cpp b/net/Socket.cpp index c77cae69f4bd9..c250a26952f4d 100644 --- a/net/Socket.cpp +++ b/net/Socket.cpp @@ -90,7 +90,11 @@ namespace ThreadChecks std::unique_ptr SocketPoll::PollWatchdog; -#define SOCKET_ABSTRACT_UNIX_NAME "0coolwsd-" +#ifndef __APPLE__ +#define SOCKET_ABSTRACT_UNIX_NAME "coolwsd-" +#else +#define SOCKET_ABSTRACT_UNIX_NAME "/tmp/coolwsd-" +#endif #endif @@ -946,7 +950,7 @@ void SocketPoll::insertNewWebSocketSync(const Poco::URI& uri, } bool SocketPoll::insertNewUnixSocket( - const std::string &location, + const UnxSocketPath &location, const std::string &pathAndQuery, const std::shared_ptr& websocketHandler, const std::vector* shareFDs) @@ -962,12 +966,7 @@ bool SocketPoll::insertNewUnixSocket( struct sockaddr_un addrunix; std::memset(&addrunix, 0, sizeof(addrunix)); addrunix.sun_family = AF_UNIX; -#ifdef HAVE_ABSTRACT_UNIX_SOCKETS - addrunix.sun_path[0] = '\0'; // abstract name -#else - addrunix.sun_path[0] = '0'; -#endif - std::memcpy(&addrunix.sun_path[1], location.c_str(), location.length()); + location.fillInto(addrunix); const int res = connect(fd, (const struct sockaddr*)&addrunix, sizeof(addrunix)); if (res < 0 && errno != EINPROGRESS) @@ -1499,7 +1498,7 @@ std::shared_ptr LocalServerSocket::accept() } /// Returns true on success only. -std::string LocalServerSocket::bind() +UnxSocketPath LocalServerSocket::bind() { int rc; struct sockaddr_un addrunix; @@ -1508,13 +1507,13 @@ std::string LocalServerSocket::bind() std::string socketAbstractUnixName(SOCKET_ABSTRACT_UNIX_NAME); const char* snapInstanceName = std::getenv("SNAP_INSTANCE_NAME"); if (snapInstanceName && snapInstanceName[0]) - socketAbstractUnixName = std::string("0snap.") + snapInstanceName + ".coolwsd-"; + socketAbstractUnixName = std::string("snap.") + snapInstanceName + ".coolwsd-"; LOG_INF("Binding to Unix socket for local server with base name: " << socketAbstractUnixName); constexpr auto RandomSuffixLength = 8; constexpr auto MaxSocketAbstractUnixNameLength = - sizeof(addrunix.sun_path) - RandomSuffixLength - 1; // 1 byte for null termination. + sizeof(addrunix.sun_path) - RandomSuffixLength - 2; // 1 byte for null termination, 1 byte for abstract's leading \0 LOG_ASSERT_MSG(socketAbstractUnixName.size() < MaxSocketAbstractUnixNameLength, "SocketAbstractUnixName is too long. Max: " << MaxSocketAbstractUnixNameLength << ", actual: " @@ -1525,47 +1524,43 @@ std::string LocalServerSocket::bind() { std::memset(&addrunix, 0, sizeof(addrunix)); addrunix.sun_family = AF_UNIX; - std::memcpy(addrunix.sun_path, socketAbstractUnixName.c_str(), socketAbstractUnixName.length()); -#ifdef HAVE_ABSTRACT_UNIX_SOCKETS - addrunix.sun_path[0] = '\0'; // abstract name -#endif - const std::string rand = Util::rng::getFilename(RandomSuffixLength); - std::memcpy(addrunix.sun_path + socketAbstractUnixName.size(), rand.c_str(), RandomSuffixLength); - LOG_ASSERT_MSG(addrunix.sun_path[sizeof(addrunix.sun_path) - 1] == '\0', - "addrunix.sun_path is not null terminated"); + const std::string socketName = socketAbstractUnixName + Util::rng::getFilename(RandomSuffixLength); + UnxSocketPath socketPath(socketName); + socketPath.fillInto(addrunix); rc = ::bind(getFD(), (const sockaddr *)&addrunix, sizeof(struct sockaddr_un)); last_errno = errno; LOG_TRC("Binding to Unix socket location [" - << &addrunix.sun_path[1] << "], result: " << rc + << socketPath << "], result: " << rc << ((rc >= 0) ? std::string() : '\t' + Util::symbolicErrno(last_errno) + ": " + std::strerror(last_errno))); + if (rc >= 0) + { + _id = socketPath; + return socketPath; + } } while (rc < 0 && errno == EADDRINUSE); - if (rc >= 0) - { - _name = std::string(&addrunix.sun_path[0]); - return std::string(&addrunix.sun_path[1]); - } - - LOG_ERR_ERRNO(last_errno, "Failed to bind to Unix socket at [" << &addrunix.sun_path[1] << ']'); + LOG_ERR_ERRNO(last_errno, "Failed to bind to Unix socket"); return std::string(); } -#ifndef HAVE_ABSTRACT_UNIX_SOCKETS -bool LocalServerSocket::link(std::string to) +bool LocalServerSocket::linkTo([[maybe_unused]] std::string toPath) { - _linkName = std::move(to); - return ::link(_name.c_str(), _linkName.c_str()) == 0; -} +#ifndef HAVE_ABSTRACT_UNIX_SOCKETS + _linkName = toPath + "/" + _id.getName(); + return 0 == ::link(_id.getName().c_str(), _linkName.c_str()); +#else + return true; #endif +} LocalServerSocket::~LocalServerSocket() { #ifndef HAVE_ABSTRACT_UNIX_SOCKETS - ::unlink(_name.c_str()); + ::unlink(_id.getName().c_str()); if (!_linkName.empty()) ::unlink(_linkName.c_str()); #endif diff --git a/net/Socket.hpp b/net/Socket.hpp index 99bc631aa8bdf..9e112769d6834 100644 --- a/net/Socket.hpp +++ b/net/Socket.hpp @@ -73,6 +73,7 @@ std::ostream& operator<<(std::ostream& os, const Socket &s); class Watchdog; class SocketPoll; +class UnxSocketPath; /// Helper to allow us to easily defer the movement of a socket /// between polls to clarify thread ownership. @@ -982,7 +983,7 @@ class SocketPoll const std::shared_ptr& websocketHandler); bool insertNewUnixSocket( - const std::string &location, + const UnxSocketPath &location, const std::string &pathAndQuery, const std::shared_ptr& websocketHandler, const std::vector* shareFDs = nullptr); diff --git a/wsd/COOLWSD.cpp b/wsd/COOLWSD.cpp index 35bb828c9fa23..7793ccc9df5a2 100644 --- a/wsd/COOLWSD.cpp +++ b/wsd/COOLWSD.cpp @@ -117,7 +117,7 @@ int ClientPortNumber = 0; #if !MOBILEAPP /// UDS address for kits to connect to. -std::string MasterLocation; +UnxSocketPath MasterLocation; std::string COOLWSD::BuyProductUrl; std::string COOLWSD::LatestVersion; @@ -2755,7 +2755,7 @@ bool COOLWSD::createForKit() args.push_back("--lotemplate=" + LoTemplate); args.push_back("--childroot=" + ChildRoot); args.push_back("--clientport=" + std::to_string(ClientPortNumber)); - args.push_back("--masterport=" + MasterLocation); + args.push_back("--masterport=" + MasterLocation.getName()); const DocProcSettings& docProcSettings = Admin::instance().getDefDocProcSettings(); std::ostringstream ossRLimits; @@ -3417,8 +3417,8 @@ std::shared_ptr COOLWSDServer::findPrisonerServerPort() auto socket = std::make_shared( std::chrono::steady_clock::now(), *PrisonerPoll, factory); - std::string location = socket->bind(); - if (!location.length()) + const UnxSocketPath location = socket->bind(); + if (!location.isValid()) { LOG_FTL("Failed to create local unix domain socket. Exiting."); Util::forcedExit(EX_SOFTWARE); @@ -3433,13 +3433,11 @@ std::shared_ptr COOLWSDServer::findPrisonerServerPort() LOG_INF("Listening to prisoner connections on " << location); MasterLocation = std::move(location); -#ifndef HAVE_ABSTRACT_UNIX_SOCKETS - if(!socket->link(COOLWSD::SysTemplate + "/0" + MasterLocation)) + if(!socket->linkTo(COOLWSD::SysTemplate)) { LOG_FTL("Failed to hardlink local unix domain socket into a jail. Exiting."); Util::forcedExit(EX_SOFTWARE); } -#endif #else constexpr int UNUSED_PORT_NUMBER = 0; std::shared_ptr socket From fb58a011184ce672455e5fcadf008ee04c0cc43e Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Fri, 21 Feb 2025 15:47:05 +0100 Subject: [PATCH 122/177] coda-m: More places to disable when we don't use childroots Signed-off-by: Jan Holesovsky Change-Id: Ic713bc6bed1bf162527deffc3fabe137cc497bea --- common/JailUtil.cpp | 14 ++++++++++++++ wsd/COOLWSD.cpp | 2 ++ 2 files changed, 16 insertions(+) diff --git a/common/JailUtil.cpp b/common/JailUtil.cpp index c3eb5e8340ebb..923487c7be4eb 100644 --- a/common/JailUtil.cpp +++ b/common/JailUtil.cpp @@ -241,12 +241,15 @@ constexpr const char* COPIED_JAIL_MARKER_FILE = "delete.me"; void markJailCopied(const std::string& root) { +#if ENABLE_CHILDROOTS // The reason we should be able to create this file // is because the jail must be writable. // Failing this will cause an exception, signaling an error. Poco::File(root + '/' + COPIED_JAIL_MARKER_FILE).createFile(); +#endif } +#if ENABLE_CHILDROOTS bool isJailCopied(const std::string& root) { // If the marker file exists, the jail was copied. @@ -291,6 +294,7 @@ void removeAuxFolders(const std::string &root) FileUtil::removeFile(Poco::Path(root, "tmp").toString(), true); FileUtil::removeFile(Poco::Path(root, "linkable").toString(), true); } +#endif /* The tmp dir of a path//tmp is mounted from (or linked to) a @@ -301,6 +305,7 @@ void removeAuxFolders(const std::string &root) */ void removeAssocTmpOfJail(const std::string &root) { +#if ENABLE_CHILDROOTS Poco::Path jailPath(root); jailPath.makeDirectory(); const std::string jailId = jailPath[jailPath.depth() - 1]; @@ -310,12 +315,14 @@ void removeAssocTmpOfJail(const std::string &root) jailPath.pushDirectory(std::string("cool-") + jailId); FileUtil::removeFile(jailPath.toString(), true); +#endif } } // namespace bool tryRemoveJail(const std::string& root) { +#if ENABLE_CHILDROOTS const bool emptyJail = FileUtil::isEmptyDirectory(root); if (!emptyJail && !FileUtil::Stat(root + '/' + LO_JAIL_SUBPATH).exists()) return false; // not a jail. @@ -346,6 +353,7 @@ bool tryRemoveJail(const std::string& root) safeRemoveDir(root); removeAssocTmpOfJail(root); +#endif return true; } @@ -357,6 +365,7 @@ bool tryRemoveJail(const std::string& root) /// inadvertently delete the contents of the mount-points. void cleanupJails(const std::string& root) { +#if ENABLE_CHILDROOTS LOG_INF("Cleaning up childroot directory [" << root << "]."); FileUtil::Stat stRoot(root); @@ -436,18 +445,22 @@ void cleanupJails(const std::string& root) safeRemoveDir(root); else LOG_WRN("Jails root directory [" << root << "] is not empty. Will not remove it."); +#endif } void createJailPath(const std::string& path) { +#if ENABLE_CHILDROOTS LOG_INF("Creating jail path (if missing): " << path); Poco::File(path).createDirectories(); if (chmod(path.c_str(), S_IXUSR | S_IWUSR | S_IRUSR) != 0) LOG_WRN_SYS("chmod(\"" << path << "\") failed"); +#endif } void setupChildRoot(bool bindMount, const std::string& childRoot, const std::string& sysTemplate) { +#if ENABLE_CHILDROOTS // Start with a clean slate. cleanupJails(childRoot); @@ -481,6 +494,7 @@ void setupChildRoot(bool bindMount, const std::string& childRoot, const std::str else LOG_INF("Disabling Bind-Mounting of jail contents per " "mount_jail_tree config in coolwsd.xml."); +#endif } /// The envar name used to control bind-mounting of systemplate/jails. diff --git a/wsd/COOLWSD.cpp b/wsd/COOLWSD.cpp index 7793ccc9df5a2..5ee52807acdf9 100644 --- a/wsd/COOLWSD.cpp +++ b/wsd/COOLWSD.cpp @@ -3433,11 +3433,13 @@ std::shared_ptr COOLWSDServer::findPrisonerServerPort() LOG_INF("Listening to prisoner connections on " << location); MasterLocation = std::move(location); +#if ENABLE_CHILDROOTS if(!socket->linkTo(COOLWSD::SysTemplate)) { LOG_FTL("Failed to hardlink local unix domain socket into a jail. Exiting."); Util::forcedExit(EX_SOFTWARE); } +#endif #else constexpr int UNUSED_PORT_NUMBER = 0; std::shared_ptr socket From 2f6056e1c9eb385c888d224b21cb63ad844cae47 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Fri, 21 Feb 2025 15:47:48 +0100 Subject: [PATCH 123/177] coda-m: Update the Xcode project Signed-off-by: Jan Holesovsky Change-Id: I989fef67d72bf742d4e960e55e926add63bba149 --- macos/coda/coda.xcodeproj/project.pbxproj | 26 +++++++++++++++++------ 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/macos/coda/coda.xcodeproj/project.pbxproj b/macos/coda/coda.xcodeproj/project.pbxproj index afb184a9463c1..ea314d5d05ca7 100644 --- a/macos/coda/coda.xcodeproj/project.pbxproj +++ b/macos/coda/coda.xcodeproj/project.pbxproj @@ -8,7 +8,6 @@ /* Begin PBXBuildFile section */ BE16C9F02CD51F58005E5960 /* hello.odt in Resources */ = {isa = PBXBuildFile; fileRef = BE16C9EF2CD51F58005E5960 /* hello.odt */; }; - BE2231BA2CC67FDE00385A9C /* coolwsd-fork.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE2231B92CC67FDE00385A9C /* coolwsd-fork.cpp */; }; BE22492C2CC79AD700385A9C /* cool.html in Resources */ = {isa = PBXBuildFile; fileRef = BE22492B2CC79AD700385A9C /* cool.html */; }; BE2252292CC79BAE00385A9C /* bundle.js in Resources */ = {isa = PBXBuildFile; fileRef = BE22492E2CC79BAE00385A9C /* bundle.js */; }; BE22529E2CC79BAE00385A9C /* cool-help.html in Resources */ = {isa = PBXBuildFile; fileRef = BE22492F2CC79BAE00385A9C /* cool-help.html */; }; @@ -84,6 +83,9 @@ BEA264B42CBE99340007435A /* RequestVettingStation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA264AA2CBE99340007435A /* RequestVettingStation.cpp */; }; BEEF3F862CE2139E00ABE785 /* coolkitconfig.xcu in Resources */ = {isa = PBXBuildFile; fileRef = BEEF3F852CE2139E00ABE785 /* coolkitconfig.xcu */; }; BEF5CE8F2D633CE60006FD77 /* discovery.xml in Resources */ = {isa = PBXBuildFile; fileRef = BEF5CE8E2D633CE60006FD77 /* discovery.xml */; }; + BEFC03192D64986E009FF7B8 /* ForKit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEFC03172D64986E009FF7B8 /* ForKit.cpp */; }; + BEFC031D2D64D76D009FF7B8 /* coolwsd-inproc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEFC031C2D64D76D009FF7B8 /* coolwsd-inproc.cpp */; }; + BEFC6A492D6737AF009FF7B8 /* dist in Resources */ = {isa = PBXBuildFile; fileRef = BEFC6A482D6737A9009FF7B8 /* dist */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -105,7 +107,6 @@ /* Begin PBXFileReference section */ BE16C9EF2CD51F58005E5960 /* hello.odt */ = {isa = PBXFileReference; lastKnownFileType = file; name = hello.odt; path = ../../../test/data/hello.odt; sourceTree = ""; }; - BE2231B92CC67FDE00385A9C /* coolwsd-fork.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "coolwsd-fork.cpp"; path = "../../../../wsd/coolwsd-fork.cpp"; sourceTree = ""; }; BE22492B2CC79AD700385A9C /* cool.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = cool.html; path = ../../../browser/dist/cool.html; sourceTree = ""; }; BE22492D2CC79BAE00385A9C /* bundle.css */ = {isa = PBXFileReference; lastKnownFileType = text.css; name = bundle.css; path = ../../../browser/dist/bundle.css; sourceTree = ""; }; BE22492E2CC79BAE00385A9C /* bundle.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = bundle.js; path = ../../../browser/dist/bundle.js; sourceTree = ""; }; @@ -243,6 +244,10 @@ BEEF3F822CE20BDD00ABE785 /* SetupKitEnvironment.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = SetupKitEnvironment.hpp; path = ../../../../kit/SetupKitEnvironment.hpp; sourceTree = ""; }; BEEF3F852CE2139E00ABE785 /* coolkitconfig.xcu */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = coolkitconfig.xcu; path = ../../../coolkitconfig.xcu; sourceTree = ""; }; BEF5CE8E2D633CE60006FD77 /* discovery.xml */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = discovery.xml; path = ../../../discovery.xml; sourceTree = ""; }; + BEFC03172D64986E009FF7B8 /* ForKit.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ForKit.cpp; path = ../../../../kit/ForKit.cpp; sourceTree = ""; }; + BEFC03182D64986E009FF7B8 /* Kit.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Kit.hpp; path = ../../../../kit/Kit.hpp; sourceTree = ""; }; + BEFC031C2D64D76D009FF7B8 /* coolwsd-inproc.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "coolwsd-inproc.cpp"; path = "../../../../wsd/coolwsd-inproc.cpp"; sourceTree = ""; }; + BEFC6A482D6737A9009FF7B8 /* dist */ = {isa = PBXFileReference; lastKnownFileType = folder; name = dist; path = ../../../browser/dist; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFileSystemSynchronizedRootGroup section */ @@ -291,6 +296,7 @@ BE22492A2CC79AAC00385A9C /* Resources */ = { isa = PBXGroup; children = ( + BEFC6A482D6737A9009FF7B8 /* dist */, BE22AA9B2CC7AE7400385A9C /* images */, BE22492D2CC79BAE00385A9C /* bundle.css */, BE22492E2CC79BAE00385A9C /* bundle.js */, @@ -392,7 +398,9 @@ children = ( BEA2648B2CBE986C0007435A /* DeltaSimd.h */, BEA2648C2CBE986C0007435A /* DeltaSimd.c */, + BEFC03172D64986E009FF7B8 /* ForKit.cpp */, BEA2648D2CBE986C0007435A /* ChildSession.cpp */, + BEFC03182D64986E009FF7B8 /* Kit.hpp */, BE4C625D2D5A3DDA00047DF2 /* Kit.cpp */, BEA2648F2CBE986C0007435A /* KitQueue.hpp */, BEA264902CBE986C0007435A /* KitQueue.cpp */, @@ -440,7 +448,7 @@ BEA264A52CBE99340007435A /* ClientSession.cpp */, BE4C62262D59EBAC00047DF2 /* COOLWSD.hpp */, BEA264A62CBE99340007435A /* COOLWSD.cpp */, - BE2231B92CC67FDE00385A9C /* coolwsd-fork.cpp */, + BEFC031C2D64D76D009FF7B8 /* coolwsd-inproc.cpp */, BE4C62272D59EBAC00047DF2 /* DocumentBroker.hpp */, BEA264A72CBE99340007435A /* DocumentBroker.cpp */, BE4C62282D59EBAC00047DF2 /* Exceptions.hpp */, @@ -627,6 +635,7 @@ BE4C62612D5B736200047DF2 /* coolwsd.xml in Resources */, BE2252292CC79BAE00385A9C /* bundle.js in Resources */, BE22529E2CC79BAE00385A9C /* cool-help.html in Resources */, + BEFC6A492D6737AF009FF7B8 /* dist in Resources */, BE2253F32CC79BAE00385A9C /* device-desktop.css in Resources */, BE22557E2CC79BAE00385A9C /* global.js in Resources */, BE16C9F02CD51F58005E5960 /* hello.odt in Resources */, @@ -670,7 +679,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n\nif [ -z \"$LO_PATH\" ]; then\n echo \"Error: LO_PATH is not set. Please configure it in Config.xcconfig.\"\n exit 1\nfi\n\necho \"Copying $LO_PATH/Contents/ to ${CONFIGURATION_BUILD_DIR}/${TARGET_NAME}.app/Contents/lokit/\"\nrsync -avz $LO_PATH/Contents/ ${CONFIGURATION_BUILD_DIR}/${TARGET_NAME}.app/Contents/lokit/\n"; + shellScript = "# Copy lokit to the bundle\nif [ -z \"$LO_PATH\" ]; then\n echo \"Error: LO_PATH is not set. Please configure it in Config.xcconfig.\"\n exit 1\nfi\n\necho \"Copying $LO_PATH/Contents/ to ${CONFIGURATION_BUILD_DIR}/${TARGET_NAME}.app/Contents/lokit/\"\nrsync -avz $LO_PATH/Contents/ ${CONFIGURATION_BUILD_DIR}/${TARGET_NAME}.app/Contents/lokit/\n\n# It's impossible to create 'browser/dist' in Resources via a rule directly,\n# we need to create the extra dir manually\nDIST_DIR=\"${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/dist\"\nBROWSER_DIR=\"${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/browser\"\necho \"Moving $DIST_DIR to $BROWSER_DIR\"\nmkdir -p \"$BROWSER_DIR\"\nrm -r \"$BROWSER_DIR/dist\"\nmv \"$DIST_DIR\" \"$BROWSER_DIR/\"\n"; }; /* End PBXShellScriptBuildPhase section */ @@ -685,6 +694,7 @@ BE4C62402D59EBAC00047DF2 /* RemoteConfig.cpp in Sources */, BE4C62412D59EBAC00047DF2 /* ProxyProtocol.cpp in Sources */, BE4C62422D59EBAC00047DF2 /* ProxyRequestHandler.cpp in Sources */, + BEFC031D2D64D76D009FF7B8 /* coolwsd-inproc.cpp in Sources */, BE4C62432D59EBAC00047DF2 /* FileServerUtil.cpp in Sources */, BE4C62442D59EBAC00047DF2 /* ProofKey.cpp in Sources */, BE4C62452D59EBAC00047DF2 /* ServerAuditUtil.cpp in Sources */, @@ -699,6 +709,7 @@ BEA264922CBE986C0007435A /* KitQueue.cpp in Sources */, BE4C621C2D59EAA900047DF2 /* DelaySocket.cpp in Sources */, BE4C621D2D59EAA900047DF2 /* HttpHelper.cpp in Sources */, + BEFC03192D64986E009FF7B8 /* ForKit.cpp in Sources */, BE9115AE2CECBD3100C597B2 /* FileUtil-unix.cpp in Sources */, BEA264932CBE986C0007435A /* KitWebSocket.cpp in Sources */, BEA264942CBE986C0007435A /* ChildSession.cpp in Sources */, @@ -736,7 +747,6 @@ BEA264B02CBE99340007435A /* ClientSession.cpp in Sources */, BEA264B12CBE99340007435A /* RequestDetails.cpp in Sources */, BEA264B22CBE99340007435A /* ClientRequestDispatcher.cpp in Sources */, - BE2231BA2CC67FDE00385A9C /* coolwsd-fork.cpp in Sources */, BEA264B32CBE99340007435A /* DocumentBroker.cpp in Sources */, BEA264B42CBE99340007435A /* RequestVettingStation.cpp in Sources */, BE5A7AE22D354F4000FE7D60 /* Syscall.cpp in Sources */, @@ -951,7 +961,8 @@ COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = J4FQ687VJK; - ENABLE_HARDENED_RUNTIME = YES; + ENABLE_APP_SANDBOX = NO; + ENABLE_HARDENED_RUNTIME = NO; ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = coda/Info.plist; @@ -999,7 +1010,8 @@ COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = J4FQ687VJK; - ENABLE_HARDENED_RUNTIME = YES; + ENABLE_APP_SANDBOX = NO; + ENABLE_HARDENED_RUNTIME = NO; ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = coda/Info.plist; From db8304111b5e929f0291a596970c4c2f0cc6a106 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Fri, 21 Feb 2025 15:53:50 +0100 Subject: [PATCH 124/177] coda-m: No need to guard this by ENABLE_CODA any more Thanks to using coolwsd-inproc.cpp. Signed-off-by: Jan Holesovsky Change-Id: Icf9eb3432e404ca3c4e6aade8f9d48b6d495c4fd --- kit/Kit.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/kit/Kit.cpp b/kit/Kit.cpp index 22d709ba5fb85..5de83f9a13754 100644 --- a/kit/Kit.cpp +++ b/kit/Kit.cpp @@ -2875,7 +2875,6 @@ void flushTraceEventRecordings() } } -#if !ENABLE_CODA // ie. normal server static void addRecording(const std::string &recording, bool force) { // This can be called before the config system is initialized. Guard against that, as calling @@ -2913,7 +2912,6 @@ void TraceEvent::emitOneRecording(const std::string &recording) { addRecording(recording, false); } -#endif // !ENABLE_CODA #else From 8fa193955f05b0ece2c8c9b4020458609e747ad7 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Mon, 24 Feb 2025 13:08:16 +0200 Subject: [PATCH 125/177] Filter out more noisy and presumably pointless INFO and WARN log Signed-off-by: Tor Lillqvist Change-Id: I4d625aca9b2f295eff28ec8f79072d926b46dd06 --- windows/coda/CODA/Properties/launchSettings.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/windows/coda/CODA/Properties/launchSettings.json b/windows/coda/CODA/Properties/launchSettings.json index bf17ec1467349..10256163933a4 100644 --- a/windows/coda/CODA/Properties/launchSettings.json +++ b/windows/coda/CODA/Properties/launchSettings.json @@ -3,10 +3,10 @@ "CODA": { "commandName": "Project", "environmentVariables": { - "SAL_LOG": "+INFO+WARN-INFO.sal.bootstrap-INFO.i18nlangtag-INFO.vcl.fonts-INFO.vcl.gdi.fontmetric" + "SAL_LOG": "+INFO+WARN-INFO.sal.bootstrap-INFO.i18nlangtag-INFO.vcl.fonts-INFO.vcl.gdi.fontmetric-INFO.cppu-INFO.salhelper.thread-INFO.drawinglayer-INFO.vcl.schedule-WARN.xmloff-WARN.unotools.config-WARN.legacy.tools" }, "nativeDebugging": true, "jsWebView2Debugging": false } } -} +} \ No newline at end of file From 86148ca3899261bb41080b9e3591108c461d73b5 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Mon, 24 Feb 2025 15:17:54 +0200 Subject: [PATCH 126/177] Make CODA depend on CODALib Signed-off-by: Tor Lillqvist Change-Id: I2f410b3b6d4d8f11e7515288feca01f4b5473690 --- windows/coda/CODA.sln | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/windows/coda/CODA.sln b/windows/coda/CODA.sln index bbae053a62508..a3da614b3af4f 100644 --- a/windows/coda/CODA.sln +++ b/windows/coda/CODA.sln @@ -1,9 +1,11 @@ - Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.12.35521.163 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CODA", "CODA\CODA.csproj", "{A9AD4426-1615-46E6-AC61-248F9133D6AF}" + ProjectSection(ProjectDependencies) = postProject + {B0E65DEC-1CB0-4DAA-B3ED-709F8169BC40} = {B0E65DEC-1CB0-4DAA-B3ED-709F8169BC40} + EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CODALib", "CODALib\CODALib.vcxproj", "{B0E65DEC-1CB0-4DAA-B3ED-709F8169BC40}" EndProject From ef755e2b99dfab86e19373ba0fdead5b966768ce Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Mon, 24 Feb 2025 21:39:32 +0200 Subject: [PATCH 127/177] Drop final backslash from return value of getSysTempDirectoryPath() Signed-off-by: Tor Lillqvist Change-Id: I40de7889a943b824d1504ca5e9d7ba69411ab06b --- common/FileUtil-windows.cpp | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/common/FileUtil-windows.cpp b/common/FileUtil-windows.cpp index da18aa53d697b..43bbde09753fa 100644 --- a/common/FileUtil-windows.cpp +++ b/common/FileUtil-windows.cpp @@ -154,19 +154,33 @@ namespace FileUtil { std::wstring path = std::filesystem::temp_directory_path().wstring(); + if (!path.empty() && path.back() == L'\\') + path.pop_back(); + if (!path.empty()) return Util::wide_string_to_string(path); // Try some fallbacks - const wchar_t *tmp = _wgetenv(L"TEMP"); + wchar_t *tmp = _wgetenv(L"TEMP"); if (!tmp) tmp = _wgetenv(L"TMP"); + // We don't want to modify the environment string directly. + if (tmp) + { + tmp = _wcsdup(tmp); + if (tmp[wcslen(tmp)-1] == L'\\') + tmp[wcslen(tmp)-1] = L'\0'; + } + // This folder seems to be protected somehow on modern Windows, but oh well. + // Duplicate here, too, so we can free() below. if (!tmp) - tmp = L"C:/Windows/Temp"; + tmp = _wcsdup(L"C:/Windows/Temp"); - return Util::wide_string_to_string(tmp); + auto result = Util::wide_string_to_string(tmp); + free(tmp); + return result; } bool isWritable(const char* path) From 4c33dd775296e78b422be6129a565ee105107fc8 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Mon, 24 Feb 2025 22:58:23 +0200 Subject: [PATCH 128/177] Make the CODA-W config.h.in match the Linux one more closely They had drifted apart. Remove outdated things and add other things. Also, drop NUM_PRESPAWN_CHILDREN from the CODALib project file as we hardcode it anyway (and it doesn't matter anyway as we don't "spawn" any "children" in CODA-W). Signed-off-by: Tor Lillqvist Change-Id: I7fd26aa9344f897018487d93402db2ec7f508746 --- windows/coda/CODALib/CODALib.vcxproj | 4 +- windows/coda/config.h.in | 167 ++++++++++++++------------- 2 files changed, 87 insertions(+), 84 deletions(-) diff --git a/windows/coda/CODALib/CODALib.vcxproj b/windows/coda/CODALib/CODALib.vcxproj index a3bcaf43f66cb..b6a5763dce4af 100644 --- a/windows/coda/CODALib/CODALib.vcxproj +++ b/windows/coda/CODALib/CODALib.vcxproj @@ -55,7 +55,7 @@ Level3 true - _DEBUG;_USRDLL;%(PreprocessorDefinitions);NOMINMAX;_CRT_SECURE_NO_WARNINGS;COOLWSD_CONFIGDIR=".";COOLWSD_LOGLEVEL="debug";NUM_PRESPAWN_CHILDREN="1" + _DEBUG;_USRDLL;%(PreprocessorDefinitions);NOMINMAX;_CRT_SECURE_NO_WARNINGS;COOLWSD_LOGLEVEL="debug" true NotUsing pch.h @@ -79,7 +79,7 @@ true true true - NDEBUG;_USRDLL;%(PreprocessorDefinitions);NOMINMAX;_CRT_SECURE_NO_WARNINGS;COOLWSD_CONFIGDIR=".";COOLWSD_LOGLEVEL="warning";NUM_PRESPAWN_CHILDREN="1" + NDEBUG;_USRDLL;%(PreprocessorDefinitions);NOMINMAX;_CRT_SECURE_NO_WARNINGS;COOLWSD_LOGLEVEL="warning" true NotUsing pch.h diff --git a/windows/coda/config.h.in b/windows/coda/config.h.in index 87f7d89799e16..e2c1c2fcc9e96 100755 --- a/windows/coda/config.h.in +++ b/windows/coda/config.h.in @@ -4,86 +4,80 @@ #pragma once +/* Variables that usually don't change once configured */ + +/* The user-visible name of the app you build. */ #define APP_NAME "@APP_NAME@" -/* LibreOffice core git hash if present */ -#define CORE_VERSION_HASH "@CORE_VERSION_HASH@" +/* Default value of feature_lock.calc_unlock_highlights */ +#define CALC_UNLOCK_HIGHLIGHTS "" -/* Whether to disable SECCOMP */ -#define DISABLE_SECCOMP 1 +/* Define to 1 if this is a code-coverage build. */ +#define CODE_COVERAGE 0 -/* Whether to compile in some extra debugging support code and disable some - security pieces */ -/* When building with Xcode we define ENABLE_DEBUG when debugging, but not otherwise */ -#if !defined ENABLE_DEBUG -#define ENABLE_DEBUG 0 -#endif +/* Enable permanent anonymization in logs */ +#define COOLWSD_ANONYMIZE_USER_DATA false -/* Whether to enable SSL */ -#define ENABLE_SSL 0 +/* Options passed to configure script */ +#undef COOLWSD_BUILDCONFIG -/* Whether to enable support key */ -#define ENABLE_SUPPORT_KEY 0 - -/* Should the Release notes message on startup should be enabled be default? - */ -#define ENABLE_WELCOME_MESSAGE 0 +/* Directory that contains configuration of coolwsd */ +#define COOLWSD_CONFIGDIR "." -/* Should the Release notes message on startup have a dismiss button instead of an x button to close by default? - */ -#define ENABLE_WELCOME_MESSAGE_BUTTON "false" +/* Default coolwsd loglevel */ +/* Set in CODALib.vcxproj differently for Release and Debug */ -/* Define to 1 if you have the header file. */ -#define HAVE_DLFCN_H 0 +/* Destination for Trace Event output */ +#undef COOLWSD_TRACEEVENTFILE -/* Define to 1 if you have the header file. */ -#define HAVE_INTTYPES_H 0 +/* The user-name which is allowed to run coolwsd and its tools */ +#undef COOL_USER_ID -/* Define to 1 if you have the `pam' library (-lpam). */ -#define HAVE_LIBPAM 0 +/* Default number of pre-spawn children */ +#define NUM_PRESPAWN_CHILDREN "1" -/* Define to 1 if you have the header file. - */ -#define HAVE_LIBREOFFICEKIT_LIBREOFFICEKIT_H 1 +/* Absolute path to the top-level source directory */ +#undef DEBUG_ABSSRCDIR -/* Define to 1 if you have the header file. */ -#define HAVE_LINUX_SECCOMP_H 0 +/* Whether to disable SECCOMP */ +#define DISABLE_SECCOMP 1 -/* Define to 1 if you have the header file. */ -#define HAVE_MEMORY_H 1 +/* Default value of feature_lock.draw_unlock_highlights */ +#undef DRAW_UNLOCK_HIGHLIGHTS -/* Define to 1 libcap (cap_get_proc) is available, otherwise 0 */ -#define HAVE_LIBCAP 0 +/* Whether to compile in some extra debugging support code and disable some + security pieces */ +#undef ENABLE_DEBUG -/* Whether OpenSSL has PKCS5_PBKDF2_HMAC() */ -#define HAVE_PKCS5_PBKDF2_HMAC 0 +/* Whether to compile and enable feature locking */ +#undef ENABLE_FEATURE_LOCK -/* Define to 1 if you have the header file. */ -#define HAVE_POCO_NET_WEBSOCKET_H 1 +/* Whether to compile and enable feature restrictions */ +#undef ENABLE_FEATURE_RESTRICTION -/* Define to 1 if you have the header file. */ -#define HAVE_SECURITY_PAM_APPL_H 0 +/* Whether to enable SSL */ +#define ENABLE_SSL 0 -/* Define to 1 if you have the header file. */ -#define HAVE_STDINT_H 1 +/* Whether to default to using SSL_VERIFY_PEER */ +#undef SSL_VERIFY -/* Define to 1 if you have the header file. */ -#define HAVE_STDLIB_H 1 +/* Whether to enable support key */ +#define ENABLE_SUPPORT_KEY 0 -/* Define to 1 if you have the header file. */ -#define HAVE_STRINGS_H 0 +/* Should the Release notes message be shown on upgrade */ +#undef ENABLE_WELCOME_MESSAGE -/* Define to 1 if you have the header file. */ -#define HAVE_STRING_H 1 +/* User feedback URL. */ +#undef FEEDBACK_URL -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H 1 +/* Define to 1 libcap (cap_get_proc) is available, otherwise 0 */ +#define HAVE_LIBCAP 0 -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 +/* Whether OpenSSL has PKCS5_PBKDF2_HMAC() */ +#define HAVE_PKCS5_PBKDF2_HMAC 0 -/* Define to 1 if you have the header file. */ -#undef HAVE_UNISTD_H +/* Define to 1 if the `ppoll' function is available, otherwise 0. */ +#define HAVE_PPOLL 0 /* Define to 1 if you have the `memrchr' function. */ #define HAVE_MEMRCHR 0 @@ -91,18 +85,27 @@ /* Define to 1 if you have the `pipe2' function. */ #define HAVE_PIPE2 0 -/* Collabora Online WebSocket server version */ -#define COOLWSD_VERSION "@COOLWSD_VERSION@" +/* Default value of help root URL */ +#undef HELP_URL + +/* Default value of feature_lock.impress_unlock_highlights */ +#undef IMPRESS_UNLOCK_HIGHLIGHTS + +/* Infobar URL. */ +#undef INFOBAR_URL + +/* Define to 1 if this is a libfuzzer build. */ +#undef LIBFUZZER -/* Collabora Online git hash if present */ -#define COOLWSD_VERSION_HASH "@COOLWSD_VERSION_HASH@" +/* Default value of feature_lock.locked_commands */ +#undef LOCKED_COMMANDS + +/* Enable logging of test assertions */ +#undef LOK_LOG_ASSERTIONS /* Path to LibreOffice installation */ #define LO_PATH "@LO_PATH@" -/* Define to the sub-directory where libtool stores uninstalled libraries. */ -#undef LT_OBJDIR - /* Limit the maximum number of open connections */ #define MAX_CONNECTIONS 100 @@ -112,29 +115,32 @@ /* Define to 1 if this is a mobileapp (eg. Android) build. */ #define MOBILEAPP 1 -/* Name of package */ -#undef PACKAGE +/* Define to 1 when we should use systemplate and jails (eg. normal coolwsd server), otherwise 0 (eg. CODA). */ +#define ENABLE_CHILDROOTS 0 -/* Define to the address where bug reports for this package should be sent. */ -#undef PACKAGE_BUGREPORT +/* Define to 1 when the compiled code is supposed to be part of CODA (the entry point is from the app, not from main() etc.), otherwise 0 (ie. normal server). */ +#define ENABLE_CODA 1 -/* Define to the full name of this package. */ -#undef PACKAGE_NAME +/* Default value of feature_lock.unlock_description */ +#define UNLOCK_DESCRIPTION "" -/* Define to the full name and version of this package. */ -#undef PACKAGE_STRING +/* Default value of feature_lock.unlock_link */ +#define UNLOCK_LINK "" -/* Define to the one symbol short name of this package. */ -#undef PACKAGE_TARNAME +/* Default value of feature_lock.unlock_title */ +#define UNLOCK_TITLE "" -/* Define to the home page for this package. */ -#undef PACKAGE_URL +/* The welcome url of the build. */ +#define WELCOME_URL "" -/* Define to the version of this package. */ -#undef PACKAGE_VERSION +/* Default value of feature_lock.writer_unlock_highlights */ +#define WRITER_UNLOCK_HIGHLIGHTS "" -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 +/* Should we enable SIMD acceleration */ +#define ENABLE_SIMD 0 + +/* Define to 1 if this is the WASM app build. */ +#define WASMAPP 0 /* Define to 1 if building for macOS */ #undef MACOS @@ -146,9 +152,6 @@ #define CONFIG_STATIC static #endif -/* Version number of package */ -/* #undef VERSION */ - /* Stuff manually added just for CODA for Windows */ typedef __int64 ssize_t; From 943f853e0ca5ecd4a691ee547986bea3bd88756f Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Mon, 24 Feb 2025 23:09:52 +0200 Subject: [PATCH 129/177] Add CODA-W specific generated files and project directories Signed-off-by: Tor Lillqvist Change-Id: I5c37469889bcbb348422ae40537d035360f31253 --- .gitignore | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.gitignore b/.gitignore index f6fd8b09b6010..0eeb0dbd46797 100644 --- a/.gitignore +++ b/.gitignore @@ -210,3 +210,12 @@ autogen.input # SBOM collabora-online-sbom.spdx.json + +# Visual Studio projects for CODA-W +windows/coda/.vs +windows/coda/CODA/bin +windows/coda/CODA/obj +windows/coda/CODALib/x64 + +# CODA-W generated files +windows/coda/config.props From fdab4ab99d0cd190890140cc356225e86a91914f Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Tue, 25 Feb 2025 10:31:42 +0200 Subject: [PATCH 130/177] Replace meaningless rubbish with simple code that works Not sure how I thought the original code was supposed to work, but anyway, using much simpler code is better. Signed-off-by: Tor Lillqvist Change-Id: Id119a05d2147be18c5094b9c45bb6ce873e12b0f --- windows/coda/CODA/MainWindow.xaml.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/windows/coda/CODA/MainWindow.xaml.cs b/windows/coda/CODA/MainWindow.xaml.cs index 5edf93bd24f48..c7eef0bf66a76 100644 --- a/windows/coda/CODA/MainWindow.xaml.cs +++ b/windows/coda/CODA/MainWindow.xaml.cs @@ -264,8 +264,12 @@ void WebView_CoreWebView2InitializationCompleted(object sender, CoreWebView2Init private bool _isMessageOfType(byte[] message, string type, int lengthOfMessage) { - int typeLen = type.Length; - return message.SequenceEqual(System.Text.Encoding.UTF8.GetBytes(type)); + if (message.Length < type.Length + 2) + return false; + for (int i = 0; i < type.Length; i++) + if (message[i] != type[i]) + return false; + return true; } void send2JS(IntPtr buffer, int length) From 110bae08fddb8d4516235140d65d4047e8ca8149 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 10 Mar 2025 08:34:04 +0100 Subject: [PATCH 131/177] coda-m: Introduce project for coolforkit Signed-off-by: Jan Holesovsky Change-Id: I2cbe9247926c9fb8f716cc4561694a2f11ff1e63 --- .gitignore | 12 +- macos/coda/.gitignore | 1 + macos/coolforkit/.gitignore | 3 + macos/coolforkit/Config.xcconfig.in | 16 + .../coolforkit.xcodeproj/project.pbxproj | 442 ++++++++++++++++++ 5 files changed, 467 insertions(+), 7 deletions(-) create mode 100644 macos/coolforkit/.gitignore create mode 100644 macos/coolforkit/Config.xcconfig.in create mode 100644 macos/coolforkit/coolforkit.xcodeproj/project.pbxproj diff --git a/.gitignore b/.gitignore index 0eeb0dbd46797..60bb5156d5a30 100644 --- a/.gitignore +++ b/.gitignore @@ -45,8 +45,6 @@ debian/coolwsd.postinst common/support-public-key.hpp compile_commands.json **/gdb.txt -macos/coda/config.h -macos/coda/Config.xcconfig macos/coolwsd/gmake-wrapper.sh # Test stuff @@ -100,11 +98,11 @@ browser/compilets browser/typescript_js browser/src/layer/tile/CanvasTileWorker.js -coolforkit -coolforkitns -coolforkit-caps -coolforkit-nocaps -coolforkit-ns +/coolforkit +/coolforkitns +/coolforkit-caps +/coolforkit-nocaps +/coolforkit-ns connect lokitclient /coolwsd diff --git a/macos/coda/.gitignore b/macos/coda/.gitignore index 038dcd554e149..437884a678219 100644 --- a/macos/coda/.gitignore +++ b/macos/coda/.gitignore @@ -1,2 +1,3 @@ +/Config.xcconfig /coda.xcodeproj/project.xcworkspace/ /coda.xcodeproj/xcuserdata/ diff --git a/macos/coolforkit/.gitignore b/macos/coolforkit/.gitignore new file mode 100644 index 0000000000000..176b3d2ea3277 --- /dev/null +++ b/macos/coolforkit/.gitignore @@ -0,0 +1,3 @@ +/Config.xcconfig +/coolforkit.xcodeproj/project.xcworkspace/ +/coolforkit.xcodeproj/xcuserdata/ diff --git a/macos/coolforkit/Config.xcconfig.in b/macos/coolforkit/Config.xcconfig.in new file mode 100644 index 0000000000000..671b1ae7138f5 --- /dev/null +++ b/macos/coolforkit/Config.xcconfig.in @@ -0,0 +1,16 @@ +// +// Copyright the Collabora Online contributors. +// +// SPDX-License-Identifier: MPL-2.0 +// +// 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/. + +// Configuration settings file format documentation can be found at: +// https://help.apple.com/xcode/#/dev745c5c974 + +HOMEBREW_PATH = "@HOMEBREW_PATH@" +HEADER_SEARCH_PATHS = "@LOKIT_PATH@" +GCC_PREPROCESSOR_DEFINITIONS = "COOLWSD_CONFIGDIR=\"@COOLWSD_CONFIGDIR@\"" "COOLWSD_LOGLEVEL=\"@COOLWSD_LOGLEVEL@\"" "NUM_PRESPAWN_CHILDREN=\"@NUM_PRESPAWN_CHILDREN@\"" +LO_PATH = @LO_PATH@ diff --git a/macos/coolforkit/coolforkit.xcodeproj/project.pbxproj b/macos/coolforkit/coolforkit.xcodeproj/project.pbxproj new file mode 100644 index 0000000000000..64d8755726f8b --- /dev/null +++ b/macos/coolforkit/coolforkit.xcodeproj/project.pbxproj @@ -0,0 +1,442 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 77; + objects = { + +/* Begin PBXBuildFile section */ + BE9998852D7EC1FD00172B83 /* Common.hpp in Sources */ = {isa = PBXBuildFile; fileRef = BE9998732D7EBEE100172B83 /* Common.hpp */; }; + BE9998862D7EC1FD00172B83 /* ConfigUtil.hpp in Sources */ = {isa = PBXBuildFile; fileRef = BE9998742D7EBEE100172B83 /* ConfigUtil.hpp */; }; + BE9998872D7EC1FD00172B83 /* ConfigUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE9998752D7EBEE100172B83 /* ConfigUtil.cpp */; }; + BE9998882D7EC1FD00172B83 /* FileUtil.hpp in Sources */ = {isa = PBXBuildFile; fileRef = BE9998762D7EBEE100172B83 /* FileUtil.hpp */; }; + BE9998892D7EC1FD00172B83 /* FileUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE9998772D7EBEE100172B83 /* FileUtil.cpp */; }; + BE99988A2D7EC1FD00172B83 /* JailUtil.hpp in Sources */ = {isa = PBXBuildFile; fileRef = BE9998782D7EBEE100172B83 /* JailUtil.hpp */; }; + BE99988B2D7EC1FD00172B83 /* JailUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE9998792D7EBEE100172B83 /* JailUtil.cpp */; }; + BE99988C2D7EC1FD00172B83 /* Seccomp.hpp in Sources */ = {isa = PBXBuildFile; fileRef = BE99987A2D7EBEE100172B83 /* Seccomp.hpp */; }; + BE99988D2D7EC1FD00172B83 /* Seccomp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE99987B2D7EBEE100172B83 /* Seccomp.cpp */; }; + BE99988E2D7EC1FD00172B83 /* security.h in Sources */ = {isa = PBXBuildFile; fileRef = BE99987C2D7EBEE100172B83 /* security.h */; }; + BE99988F2D7EC1FD00172B83 /* SigUtil.hpp in Sources */ = {isa = PBXBuildFile; fileRef = BE99987D2D7EBEE100172B83 /* SigUtil.hpp */; }; + BE9998902D7EC1FD00172B83 /* SigUtil-server.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE99987E2D7EBEE100172B83 /* SigUtil-server.cpp */; }; + BE9998912D7EC1FD00172B83 /* Watchdog.hpp in Sources */ = {isa = PBXBuildFile; fileRef = BE99987F2D7EBEE100172B83 /* Watchdog.hpp */; }; + BE9998922D7EC1FD00172B83 /* DeltaSimd.h in Sources */ = {isa = PBXBuildFile; fileRef = BE9998802D7EBF3900172B83 /* DeltaSimd.h */; }; + BE9998932D7EC1FD00172B83 /* DeltaSimd.c in Sources */ = {isa = PBXBuildFile; fileRef = BE9998812D7EBF3900172B83 /* DeltaSimd.c */; }; + BE9998942D7EC1FD00172B83 /* ForKit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE9998712D7EBDF000172B83 /* ForKit.cpp */; }; + BE9998952D7EC1FD00172B83 /* forkit-main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE9998722D7EBDF000172B83 /* forkit-main.cpp */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + BE4679112D775BA900569CBF /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + BE4679132D775BA900569CBF /* coolforkit */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = coolforkit; sourceTree = BUILT_PRODUCTS_DIR; }; + BE9998712D7EBDF000172B83 /* ForKit.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ForKit.cpp; path = ../../../../kit/ForKit.cpp; sourceTree = ""; }; + BE9998722D7EBDF000172B83 /* forkit-main.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "forkit-main.cpp"; path = "../../../../kit/forkit-main.cpp"; sourceTree = ""; }; + BE9998732D7EBEE100172B83 /* Common.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Common.hpp; path = ../../../../common/Common.hpp; sourceTree = ""; }; + BE9998742D7EBEE100172B83 /* ConfigUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = ConfigUtil.hpp; path = ../../../../common/ConfigUtil.hpp; sourceTree = ""; }; + BE9998752D7EBEE100172B83 /* ConfigUtil.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ConfigUtil.cpp; path = ../../../../common/ConfigUtil.cpp; sourceTree = ""; }; + BE9998762D7EBEE100172B83 /* FileUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = FileUtil.hpp; path = ../../../../common/FileUtil.hpp; sourceTree = ""; }; + BE9998772D7EBEE100172B83 /* FileUtil.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = FileUtil.cpp; path = ../../../../common/FileUtil.cpp; sourceTree = ""; }; + BE9998782D7EBEE100172B83 /* JailUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = JailUtil.hpp; path = ../../../../common/JailUtil.hpp; sourceTree = ""; }; + BE9998792D7EBEE100172B83 /* JailUtil.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = JailUtil.cpp; path = ../../../../common/JailUtil.cpp; sourceTree = ""; }; + BE99987A2D7EBEE100172B83 /* Seccomp.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Seccomp.hpp; path = ../../../../common/Seccomp.hpp; sourceTree = ""; }; + BE99987B2D7EBEE100172B83 /* Seccomp.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Seccomp.cpp; path = ../../../../common/Seccomp.cpp; sourceTree = ""; }; + BE99987C2D7EBEE100172B83 /* security.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = security.h; path = ../../../../common/security.h; sourceTree = ""; }; + BE99987D2D7EBEE100172B83 /* SigUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = SigUtil.hpp; path = ../../../../common/SigUtil.hpp; sourceTree = ""; }; + BE99987E2D7EBEE100172B83 /* SigUtil-server.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "SigUtil-server.cpp"; path = "../../../../common/SigUtil-server.cpp"; sourceTree = ""; }; + BE99987F2D7EBEE100172B83 /* Watchdog.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Watchdog.hpp; path = ../../../../common/Watchdog.hpp; sourceTree = ""; }; + BE9998802D7EBF3900172B83 /* DeltaSimd.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = DeltaSimd.h; path = ../../../../kit/DeltaSimd.h; sourceTree = ""; }; + BE9998812D7EBF3900172B83 /* DeltaSimd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = DeltaSimd.c; path = ../../../../kit/DeltaSimd.c; sourceTree = ""; }; + BE9998962D7EC58B00172B83 /* Config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFileSystemSynchronizedRootGroup section */ + BE4679152D775BA900569CBF /* coolforkit */ = { + isa = PBXFileSystemSynchronizedRootGroup; + path = coolforkit; + sourceTree = ""; + }; +/* End PBXFileSystemSynchronizedRootGroup section */ + +/* Begin PBXFrameworksBuildPhase section */ + BE4679102D775BA900569CBF /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + BE46790A2D775BA900569CBF = { + isa = PBXGroup; + children = ( + BE99986E2D7EBDA100172B83 /* Online */, + BE4679152D775BA900569CBF /* coolforkit */, + BE9998962D7EC58B00172B83 /* Config.xcconfig */, + BE4679142D775BA900569CBF /* Products */, + ); + sourceTree = ""; + }; + BE4679142D775BA900569CBF /* Products */ = { + isa = PBXGroup; + children = ( + BE4679132D775BA900569CBF /* coolforkit */, + ); + name = Products; + sourceTree = ""; + }; + BE99986E2D7EBDA100172B83 /* Online */ = { + isa = PBXGroup; + children = ( + BE99986F2D7EBDAD00172B83 /* common */, + BE9998702D7EBDBE00172B83 /* kit */, + ); + path = Online; + sourceTree = ""; + }; + BE99986F2D7EBDAD00172B83 /* common */ = { + isa = PBXGroup; + children = ( + BE9998732D7EBEE100172B83 /* Common.hpp */, + BE9998742D7EBEE100172B83 /* ConfigUtil.hpp */, + BE9998752D7EBEE100172B83 /* ConfigUtil.cpp */, + BE9998762D7EBEE100172B83 /* FileUtil.hpp */, + BE9998772D7EBEE100172B83 /* FileUtil.cpp */, + BE9998782D7EBEE100172B83 /* JailUtil.hpp */, + BE9998792D7EBEE100172B83 /* JailUtil.cpp */, + BE99987A2D7EBEE100172B83 /* Seccomp.hpp */, + BE99987B2D7EBEE100172B83 /* Seccomp.cpp */, + BE99987C2D7EBEE100172B83 /* security.h */, + BE99987D2D7EBEE100172B83 /* SigUtil.hpp */, + BE99987E2D7EBEE100172B83 /* SigUtil-server.cpp */, + BE99987F2D7EBEE100172B83 /* Watchdog.hpp */, + ); + path = common; + sourceTree = ""; + }; + BE9998702D7EBDBE00172B83 /* kit */ = { + isa = PBXGroup; + children = ( + BE9998802D7EBF3900172B83 /* DeltaSimd.h */, + BE9998812D7EBF3900172B83 /* DeltaSimd.c */, + BE9998712D7EBDF000172B83 /* ForKit.cpp */, + BE9998722D7EBDF000172B83 /* forkit-main.cpp */, + ); + path = kit; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + BE4679122D775BA900569CBF /* coolforkit */ = { + isa = PBXNativeTarget; + buildConfigurationList = BE46791A2D775BA900569CBF /* Build configuration list for PBXNativeTarget "coolforkit" */; + buildPhases = ( + BE46790F2D775BA900569CBF /* Sources */, + BE4679102D775BA900569CBF /* Frameworks */, + BE4679112D775BA900569CBF /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + fileSystemSynchronizedGroups = ( + BE4679152D775BA900569CBF /* coolforkit */, + ); + name = coolforkit; + packageProductDependencies = ( + ); + productName = coolforkit; + productReference = BE4679132D775BA900569CBF /* coolforkit */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + BE46790B2D775BA900569CBF /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastUpgradeCheck = 1620; + TargetAttributes = { + BE4679122D775BA900569CBF = { + CreatedOnToolsVersion = 16.2; + }; + }; + }; + buildConfigurationList = BE46790E2D775BA900569CBF /* Build configuration list for PBXProject "coolforkit" */; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = BE46790A2D775BA900569CBF; + minimizedProjectReferenceProxies = 1; + preferredProjectObjectVersion = 77; + productRefGroup = BE4679142D775BA900569CBF /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + BE4679122D775BA900569CBF /* coolforkit */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + BE46790F2D775BA900569CBF /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + BE9998852D7EC1FD00172B83 /* Common.hpp in Sources */, + BE9998862D7EC1FD00172B83 /* ConfigUtil.hpp in Sources */, + BE9998872D7EC1FD00172B83 /* ConfigUtil.cpp in Sources */, + BE9998882D7EC1FD00172B83 /* FileUtil.hpp in Sources */, + BE9998892D7EC1FD00172B83 /* FileUtil.cpp in Sources */, + BE99988A2D7EC1FD00172B83 /* JailUtil.hpp in Sources */, + BE99988B2D7EC1FD00172B83 /* JailUtil.cpp in Sources */, + BE99988C2D7EC1FD00172B83 /* Seccomp.hpp in Sources */, + BE99988D2D7EC1FD00172B83 /* Seccomp.cpp in Sources */, + BE99988E2D7EC1FD00172B83 /* security.h in Sources */, + BE99988F2D7EC1FD00172B83 /* SigUtil.hpp in Sources */, + BE9998902D7EC1FD00172B83 /* SigUtil-server.cpp in Sources */, + BE9998912D7EC1FD00172B83 /* Watchdog.hpp in Sources */, + BE9998922D7EC1FD00172B83 /* DeltaSimd.h in Sources */, + BE9998932D7EC1FD00172B83 /* DeltaSimd.c in Sources */, + BE9998942D7EC1FD00172B83 /* ForKit.cpp in Sources */, + BE9998952D7EC1FD00172B83 /* forkit-main.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + BE4679182D775BA900569CBF /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = BE9998962D7EC58B00172B83 /* Config.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 15.2; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + }; + name = Debug; + }; + BE4679192D775BA900569CBF /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 15.2; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = macosx; + }; + name = Release; + }; + BE46791B2D775BA900569CBF /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = J4FQ687VJK; + ENABLE_HARDENED_RUNTIME = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(SRCROOT)", + "$(SRCROOT)/coda", + "$(SRCROOT)/../..", + "$(SRCROOT)/../../common", + "$(SRCROOT)/../../kit", + "$(SRCROOT)/../../net", + "$(SRCROOT)/../../wsd", + "$(HOMEBREW_PATH)/include", + ); + LIBRARY_SEARCH_PATHS = "$(HOMEBREW_PATH)/lib"; + OTHER_LDFLAGS = ( + "-liconv", + "-lpam", + "-lPocoFoundation", + "-lPocoUtil", + "-lPocoXML", + "-lPocoJSON", + "-lPocoNet", + "-lPocoNetSSL", + "-lPocoCrypto", + "-lzstd", + "-lpng", + "-lz", + "-lssl", + "-lcrypto", + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + BE46791C2D775BA900569CBF /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = J4FQ687VJK; + ENABLE_HARDENED_RUNTIME = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(SRCROOT)", + "$(SRCROOT)/coda", + "$(SRCROOT)/../..", + "$(SRCROOT)/../../common", + "$(SRCROOT)/../../kit", + "$(SRCROOT)/../../net", + "$(SRCROOT)/../../wsd", + "$(HOMEBREW_PATH)/include", + ); + LIBRARY_SEARCH_PATHS = "$(HOMEBREW_PATH)/lib"; + OTHER_LDFLAGS = ( + "-liconv", + "-lpam", + "-lPocoFoundation", + "-lPocoUtil", + "-lPocoXML", + "-lPocoJSON", + "-lPocoNet", + "-lPocoNetSSL", + "-lPocoCrypto", + "-lzstd", + "-lpng", + "-lz", + "-lssl", + "-lcrypto", + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + BE46790E2D775BA900569CBF /* Build configuration list for PBXProject "coolforkit" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + BE4679182D775BA900569CBF /* Debug */, + BE4679192D775BA900569CBF /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + BE46791A2D775BA900569CBF /* Build configuration list for PBXNativeTarget "coolforkit" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + BE46791B2D775BA900569CBF /* Debug */, + BE46791C2D775BA900569CBF /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = BE46790B2D775BA900569CBF /* Project object */; +} From aa46f867d4fd8b145e072d6ec89843ab6baf35df Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 10 Mar 2025 09:05:44 +0100 Subject: [PATCH 132/177] coda-m: Revert back to the --enable-macosapp approach Signed-off-by: Jan Holesovsky Change-Id: I46d6ce6eec317b97287dfb48c3fb7cd5d9f10cb6 --- macos/README.md | 2 +- macos/coda/coda.xcodeproj/project.pbxproj | 272 +++++----------------- macos/coda/coda/COWrapper.mm | 24 +- 3 files changed, 62 insertions(+), 236 deletions(-) diff --git a/macos/README.md b/macos/README.md index b1c639d3b8e53..eb1fa26aa8c7e 100644 --- a/macos/README.md +++ b/macos/README.md @@ -57,7 +57,7 @@ autogen.input: Configure Collabora Online ./autogen.sh && ./configure \ - --enable-debug --enable-coda \ + --enable-macosapp \ --enable-experimental \ --with-app-name="Collabora Office" \ --with-vendor="Collabora Productivity" \ diff --git a/macos/coda/coda.xcodeproj/project.pbxproj b/macos/coda/coda.xcodeproj/project.pbxproj index ea314d5d05ca7..e1e749675c97a 100644 --- a/macos/coda/coda.xcodeproj/project.pbxproj +++ b/macos/coda/coda.xcodeproj/project.pbxproj @@ -15,40 +15,20 @@ BE22557E2CC79BAE00385A9C /* global.js in Resources */ = {isa = PBXBuildFile; fileRef = BE2249312CC79BAE00385A9C /* global.js */; }; BE2257AD2CC79BAE00385A9C /* bundle.css in Resources */ = {isa = PBXBuildFile; fileRef = BE22492D2CC79BAE00385A9C /* bundle.css */; }; BE22AA9C2CC7AE7400385A9C /* images in Resources */ = {isa = PBXBuildFile; fileRef = BE22AA9B2CC7AE7400385A9C /* images */; }; + BE44ACC02D7EFDE900BFA3B2 /* DummyTraceEventEmitter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE44ACBF2D7EFDE900BFA3B2 /* DummyTraceEventEmitter.cpp */; }; + BE44ACC22D7EFF1500BFA3B2 /* Util-mobile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE44ACC12D7EFF1500BFA3B2 /* Util-mobile.cpp */; }; + BE44ACC52D7F00B000BFA3B2 /* ClientRequestDispatcher.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE44ACC42D7F00B000BFA3B2 /* ClientRequestDispatcher.cpp */; }; + BE44ACC72D7F011F00BFA3B2 /* FileUtil-apple.mm in Sources */ = {isa = PBXBuildFile; fileRef = BE44ACC62D7F011F00BFA3B2 /* FileUtil-apple.mm */; }; + BE44ACCA2D7F018700BFA3B2 /* SigUtil-mobile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE44ACC92D7F018700BFA3B2 /* SigUtil-mobile.cpp */; }; + BE44ACCF2D7F067500BFA3B2 /* Crypto-stub.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE44ACCE2D7F067500BFA3B2 /* Crypto-stub.cpp */; }; + BE44ACD12D7F073000BFA3B2 /* Unit-mobile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE44ACD02D7F073000BFA3B2 /* Unit-mobile.cpp */; }; + BE44ACD42D7F07B700BFA3B2 /* HttpRequest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE44ACD32D7F07B700BFA3B2 /* HttpRequest.cpp */; }; + BE44ACD72D7F07D800BFA3B2 /* NetUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE44ACD62D7F07D800BFA3B2 /* NetUtil.cpp */; }; + BE44ACDA2D7F089200BFA3B2 /* RequestVettingStation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE44ACD92D7F089200BFA3B2 /* RequestVettingStation.cpp */; }; BE4C620E2D59E85500047DF2 /* MobileApp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C62062D59E85500047DF2 /* MobileApp.cpp */; }; BE4C620F2D59E85500047DF2 /* Util-macos.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C620C2D59E85500047DF2 /* Util-macos.cpp */; }; - BE4C62102D59E85500047DF2 /* CoolMount.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C62002D59E85500047DF2 /* CoolMount.cpp */; }; - BE4C62112D59E85500047DF2 /* Unit-server.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C620B2D59E85500047DF2 /* Unit-server.cpp */; }; - BE4C62122D59E85500047DF2 /* JailUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C62042D59E85500047DF2 /* JailUtil.cpp */; }; - BE4C62132D59E85500047DF2 /* Seccomp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C62082D59E85500047DF2 /* Seccomp.cpp */; }; - BE4C62142D59E85500047DF2 /* CommandControl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C61FE2D59E85500047DF2 /* CommandControl.cpp */; }; - BE4C62152D59E85500047DF2 /* Crypto.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C62022D59E85500047DF2 /* Crypto.cpp */; }; - BE4C62162D59E85500047DF2 /* SigUtil-server.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C62092D59E85500047DF2 /* SigUtil-server.cpp */; }; - BE4C62172D59E85500047DF2 /* Util-server.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C620D2D59E85500047DF2 /* Util-server.cpp */; }; - BE4C621C2D59EAA900047DF2 /* DelaySocket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C62192D59EAA900047DF2 /* DelaySocket.cpp */; }; - BE4C621D2D59EAA900047DF2 /* HttpHelper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C621B2D59EAA900047DF2 /* HttpHelper.cpp */; }; - BE4C623F2D59EBAC00047DF2 /* QuarantineUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C62362D59EBAC00047DF2 /* QuarantineUtil.cpp */; }; - BE4C62402D59EBAC00047DF2 /* RemoteConfig.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C62382D59EBAC00047DF2 /* RemoteConfig.cpp */; }; - BE4C62412D59EBAC00047DF2 /* ProxyProtocol.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C62322D59EBAC00047DF2 /* ProxyProtocol.cpp */; }; - BE4C62422D59EBAC00047DF2 /* ProxyRequestHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C62342D59EBAC00047DF2 /* ProxyRequestHandler.cpp */; }; - BE4C62432D59EBAC00047DF2 /* FileServerUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C622C2D59EBAC00047DF2 /* FileServerUtil.cpp */; }; - BE4C62442D59EBAC00047DF2 /* ProofKey.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C62302D59EBAC00047DF2 /* ProofKey.cpp */; }; - BE4C62452D59EBAC00047DF2 /* ServerAuditUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C623B2D59EBAC00047DF2 /* ServerAuditUtil.cpp */; }; - BE4C62462D59EBAC00047DF2 /* AdminModel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C62212D59EBAC00047DF2 /* AdminModel.cpp */; }; - BE4C62472D59EBAC00047DF2 /* Admin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C621F2D59EBAC00047DF2 /* Admin.cpp */; }; - BE4C62482D59EBAC00047DF2 /* Exceptions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C62292D59EBAC00047DF2 /* Exceptions.cpp */; }; - BE4C62492D59EBAC00047DF2 /* SpecialBrokers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C623D2D59EBAC00047DF2 /* SpecialBrokers.cpp */; }; - BE4C624A2D59EBAC00047DF2 /* FileServer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C622B2D59EBAC00047DF2 /* FileServer.cpp */; }; - BE4C624B2D59EBAC00047DF2 /* HostUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C622E2D59EBAC00047DF2 /* HostUtil.cpp */; }; - BE4C624C2D59EBAC00047DF2 /* Auth.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C62232D59EBAC00047DF2 /* Auth.cpp */; }; - BE4C62562D59EC5400047DF2 /* WopiStorage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C62552D59EC5400047DF2 /* WopiStorage.cpp */; }; - BE4C62572D59EC5400047DF2 /* CheckFileInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C624F2D59EC5400047DF2 /* CheckFileInfo.cpp */; }; - BE4C62582D59EC5400047DF2 /* WopiProxy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C62532D59EC5400047DF2 /* WopiProxy.cpp */; }; - BE4C62592D59EC5400047DF2 /* StorageConnectionManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C62512D59EC5400047DF2 /* StorageConnectionManager.cpp */; }; - BE4C625C2D5A3C8A00047DF2 /* Ssl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C625B2D5A3C8A00047DF2 /* Ssl.cpp */; }; BE4C625E2D5A3DDA00047DF2 /* Kit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C625D2D5A3DDA00047DF2 /* Kit.cpp */; }; BE4C62612D5B736200047DF2 /* coolwsd.xml in Resources */ = {isa = PBXBuildFile; fileRef = BE4C62602D5B736200047DF2 /* coolwsd.xml */; }; - BE5A7AE22D354F4000FE7D60 /* Syscall.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5A7AE12D354F4000FE7D60 /* Syscall.cpp */; }; BE9115AE2CECBD3100C597B2 /* FileUtil-unix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE9115AD2CECBD3100C597B2 /* FileUtil-unix.cpp */; }; BE9115B02CECBECF00C597B2 /* Util-unix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE9115AF2CECBECF00C597B2 /* Util-unix.cpp */; }; BEA2636D2CBE38E20007435A /* Uri.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA2636A2CBE38E20007435A /* Uri.cpp */; }; @@ -69,23 +49,17 @@ BEA264932CBE986C0007435A /* KitWebSocket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA264912CBE986C0007435A /* KitWebSocket.cpp */; }; BEA264942CBE986C0007435A /* ChildSession.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA2648D2CBE986C0007435A /* ChildSession.cpp */; }; BEA264962CBE986C0007435A /* DeltaSimd.c in Sources */ = {isa = PBXBuildFile; fileRef = BEA2648C2CBE986C0007435A /* DeltaSimd.c */; }; - BEA264A02CBE98CD0007435A /* NetUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA2649C2CBE98CD0007435A /* NetUtil.cpp */; }; BEA264A12CBE98CD0007435A /* Socket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA2649E2CBE98CD0007435A /* Socket.cpp */; }; - BEA264A22CBE98CD0007435A /* HttpRequest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA2649A2CBE98CD0007435A /* HttpRequest.cpp */; }; BEA264A32CBE98CD0007435A /* FakeSocket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA264982CBE98CD0007435A /* FakeSocket.cpp */; }; BEA264AD2CBE99340007435A /* Storage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA264AB2CBE99340007435A /* Storage.cpp */; }; BEA264AE2CBE99340007435A /* TileCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA264AC2CBE99340007435A /* TileCache.cpp */; }; BEA264AF2CBE99340007435A /* COOLWSD.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA264A62CBE99340007435A /* COOLWSD.cpp */; }; BEA264B02CBE99340007435A /* ClientSession.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA264A52CBE99340007435A /* ClientSession.cpp */; }; BEA264B12CBE99340007435A /* RequestDetails.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA264A92CBE99340007435A /* RequestDetails.cpp */; }; - BEA264B22CBE99340007435A /* ClientRequestDispatcher.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA264A42CBE99340007435A /* ClientRequestDispatcher.cpp */; }; BEA264B32CBE99340007435A /* DocumentBroker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA264A72CBE99340007435A /* DocumentBroker.cpp */; }; - BEA264B42CBE99340007435A /* RequestVettingStation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA264AA2CBE99340007435A /* RequestVettingStation.cpp */; }; BEEF3F862CE2139E00ABE785 /* coolkitconfig.xcu in Resources */ = {isa = PBXBuildFile; fileRef = BEEF3F852CE2139E00ABE785 /* coolkitconfig.xcu */; }; BEF5CE8F2D633CE60006FD77 /* discovery.xml in Resources */ = {isa = PBXBuildFile; fileRef = BEF5CE8E2D633CE60006FD77 /* discovery.xml */; }; - BEFC03192D64986E009FF7B8 /* ForKit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEFC03172D64986E009FF7B8 /* ForKit.cpp */; }; - BEFC031D2D64D76D009FF7B8 /* coolwsd-inproc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEFC031C2D64D76D009FF7B8 /* coolwsd-inproc.cpp */; }; - BEFC6A492D6737AF009FF7B8 /* dist in Resources */ = {isa = PBXBuildFile; fileRef = BEFC6A482D6737A9009FF7B8 /* dist */; }; + BEF6F02D2DD1EC0200EA06BF /* RegexUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEF6F02C2DD1EC0200EA06BF /* RegexUtil.cpp */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -114,75 +88,34 @@ BE2249302CC79BAE00385A9C /* device-desktop.css */ = {isa = PBXFileReference; lastKnownFileType = text.css; name = "device-desktop.css"; path = "../../../browser/dist/device-desktop.css"; sourceTree = ""; }; BE2249312CC79BAE00385A9C /* global.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = global.js; path = ../../../browser/dist/global.js; sourceTree = ""; }; BE22AA9B2CC7AE7400385A9C /* images */ = {isa = PBXFileReference; lastKnownFileType = folder; name = images; path = ../../../browser/dist/images; sourceTree = ""; }; - BE4C61FD2D59E85500047DF2 /* CommandControl.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = CommandControl.hpp; path = ../../../../common/CommandControl.hpp; sourceTree = ""; }; - BE4C61FE2D59E85500047DF2 /* CommandControl.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = CommandControl.cpp; path = ../../../../common/CommandControl.cpp; sourceTree = ""; }; + BE44ACBF2D7EFDE900BFA3B2 /* DummyTraceEventEmitter.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = DummyTraceEventEmitter.cpp; path = ../../../../common/DummyTraceEventEmitter.cpp; sourceTree = ""; }; + BE44ACC12D7EFF1500BFA3B2 /* Util-mobile.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "Util-mobile.cpp"; path = "../../../../common/Util-mobile.cpp"; sourceTree = ""; }; + BE44ACC32D7F00B000BFA3B2 /* ClientRequestDispatcher.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = ClientRequestDispatcher.hpp; path = ../../../../wsd/ClientRequestDispatcher.hpp; sourceTree = ""; }; + BE44ACC42D7F00B000BFA3B2 /* ClientRequestDispatcher.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ClientRequestDispatcher.cpp; path = ../../../../wsd/ClientRequestDispatcher.cpp; sourceTree = ""; }; + BE44ACC62D7F011F00BFA3B2 /* FileUtil-apple.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "FileUtil-apple.mm"; path = "../../../../common/FileUtil-apple.mm"; sourceTree = ""; }; + BE44ACC82D7F018700BFA3B2 /* SigHandlerTrap.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = SigHandlerTrap.hpp; path = ../../../../common/SigHandlerTrap.hpp; sourceTree = ""; }; + BE44ACC92D7F018700BFA3B2 /* SigUtil-mobile.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "SigUtil-mobile.cpp"; path = "../../../../common/SigUtil-mobile.cpp"; sourceTree = ""; }; + BE44ACCE2D7F067500BFA3B2 /* Crypto-stub.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "Crypto-stub.cpp"; path = "../../../../common/Crypto-stub.cpp"; sourceTree = ""; }; + BE44ACD02D7F073000BFA3B2 /* Unit-mobile.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "Unit-mobile.cpp"; path = "../../../../common/Unit-mobile.cpp"; sourceTree = ""; }; + BE44ACD22D7F07B700BFA3B2 /* HttpRequest.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = HttpRequest.hpp; path = ../../../../net/HttpRequest.hpp; sourceTree = ""; }; + BE44ACD32D7F07B700BFA3B2 /* HttpRequest.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = HttpRequest.cpp; path = ../../../../net/HttpRequest.cpp; sourceTree = ""; }; + BE44ACD52D7F07D800BFA3B2 /* NetUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = NetUtil.hpp; path = ../../../../net/NetUtil.hpp; sourceTree = ""; }; + BE44ACD62D7F07D800BFA3B2 /* NetUtil.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = NetUtil.cpp; path = ../../../../net/NetUtil.cpp; sourceTree = ""; }; + BE44ACD82D7F089200BFA3B2 /* RequestVettingStation.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = RequestVettingStation.hpp; path = ../../../../wsd/RequestVettingStation.hpp; sourceTree = ""; }; + BE44ACD92D7F089200BFA3B2 /* RequestVettingStation.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = RequestVettingStation.cpp; path = ../../../../wsd/RequestVettingStation.cpp; sourceTree = ""; }; BE4C61FF2D59E85500047DF2 /* Common.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Common.hpp; path = ../../../../common/Common.hpp; sourceTree = ""; }; - BE4C62002D59E85500047DF2 /* CoolMount.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = CoolMount.cpp; path = ../../../../common/CoolMount.cpp; sourceTree = ""; }; BE4C62012D59E85500047DF2 /* Crypto.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Crypto.hpp; path = ../../../../common/Crypto.hpp; sourceTree = ""; }; - BE4C62022D59E85500047DF2 /* Crypto.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Crypto.cpp; path = ../../../../common/Crypto.cpp; sourceTree = ""; }; - BE4C62032D59E85500047DF2 /* JailUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = JailUtil.hpp; path = ../../../../common/JailUtil.hpp; sourceTree = ""; }; - BE4C62042D59E85500047DF2 /* JailUtil.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = JailUtil.cpp; path = ../../../../common/JailUtil.cpp; sourceTree = ""; }; BE4C62052D59E85500047DF2 /* MobileApp.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = MobileApp.hpp; path = ../../../../common/MobileApp.hpp; sourceTree = ""; }; BE4C62062D59E85500047DF2 /* MobileApp.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = MobileApp.cpp; path = ../../../../common/MobileApp.cpp; sourceTree = ""; }; - BE4C62072D59E85500047DF2 /* Seccomp.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Seccomp.hpp; path = ../../../../common/Seccomp.hpp; sourceTree = ""; }; - BE4C62082D59E85500047DF2 /* Seccomp.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Seccomp.cpp; path = ../../../../common/Seccomp.cpp; sourceTree = ""; }; - BE4C62092D59E85500047DF2 /* SigUtil-server.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "SigUtil-server.cpp"; path = "../../../../common/SigUtil-server.cpp"; sourceTree = ""; }; BE4C620A2D59E85500047DF2 /* SpookyV2.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SpookyV2.h; path = ../../../../common/SpookyV2.h; sourceTree = ""; }; - BE4C620B2D59E85500047DF2 /* Unit-server.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "Unit-server.cpp"; path = "../../../../common/Unit-server.cpp"; sourceTree = ""; }; BE4C620C2D59E85500047DF2 /* Util-macos.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "Util-macos.cpp"; path = "../../../../common/Util-macos.cpp"; sourceTree = ""; }; - BE4C620D2D59E85500047DF2 /* Util-server.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "Util-server.cpp"; path = "../../../../common/Util-server.cpp"; sourceTree = ""; }; - BE4C62182D59EAA900047DF2 /* DelaySocket.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = DelaySocket.hpp; path = ../../../../net/DelaySocket.hpp; sourceTree = ""; }; - BE4C62192D59EAA900047DF2 /* DelaySocket.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = DelaySocket.cpp; path = ../../../../net/DelaySocket.cpp; sourceTree = ""; }; - BE4C621A2D59EAA900047DF2 /* HttpHelper.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = HttpHelper.hpp; path = ../../../../net/HttpHelper.hpp; sourceTree = ""; }; - BE4C621B2D59EAA900047DF2 /* HttpHelper.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = HttpHelper.cpp; path = ../../../../net/HttpHelper.cpp; sourceTree = ""; }; - BE4C621E2D59EBAC00047DF2 /* Admin.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Admin.hpp; path = ../../../../wsd/Admin.hpp; sourceTree = ""; }; - BE4C621F2D59EBAC00047DF2 /* Admin.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Admin.cpp; path = ../../../../wsd/Admin.cpp; sourceTree = ""; }; - BE4C62202D59EBAC00047DF2 /* AdminModel.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = AdminModel.hpp; path = ../../../../wsd/AdminModel.hpp; sourceTree = ""; }; - BE4C62212D59EBAC00047DF2 /* AdminModel.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = AdminModel.cpp; path = ../../../../wsd/AdminModel.cpp; sourceTree = ""; }; - BE4C62222D59EBAC00047DF2 /* Auth.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Auth.hpp; path = ../../../../wsd/Auth.hpp; sourceTree = ""; }; - BE4C62232D59EBAC00047DF2 /* Auth.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Auth.cpp; path = ../../../../wsd/Auth.cpp; sourceTree = ""; }; - BE4C62242D59EBAC00047DF2 /* ClientRequestDispatcher.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = ClientRequestDispatcher.hpp; path = ../../../../wsd/ClientRequestDispatcher.hpp; sourceTree = ""; }; BE4C62252D59EBAC00047DF2 /* ClientSession.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = ClientSession.hpp; path = ../../../../wsd/ClientSession.hpp; sourceTree = ""; }; BE4C62262D59EBAC00047DF2 /* COOLWSD.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = COOLWSD.hpp; path = ../../../../wsd/COOLWSD.hpp; sourceTree = ""; }; BE4C62272D59EBAC00047DF2 /* DocumentBroker.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = DocumentBroker.hpp; path = ../../../../wsd/DocumentBroker.hpp; sourceTree = ""; }; - BE4C62282D59EBAC00047DF2 /* Exceptions.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Exceptions.hpp; path = ../../../../wsd/Exceptions.hpp; sourceTree = ""; }; - BE4C62292D59EBAC00047DF2 /* Exceptions.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Exceptions.cpp; path = ../../../../wsd/Exceptions.cpp; sourceTree = ""; }; - BE4C622A2D59EBAC00047DF2 /* FileServer.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = FileServer.hpp; path = ../../../../wsd/FileServer.hpp; sourceTree = ""; }; - BE4C622B2D59EBAC00047DF2 /* FileServer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = FileServer.cpp; path = ../../../../wsd/FileServer.cpp; sourceTree = ""; }; - BE4C622C2D59EBAC00047DF2 /* FileServerUtil.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = FileServerUtil.cpp; path = ../../../../wsd/FileServerUtil.cpp; sourceTree = ""; }; - BE4C622D2D59EBAC00047DF2 /* HostUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = HostUtil.hpp; path = ../../../../wsd/HostUtil.hpp; sourceTree = ""; }; - BE4C622E2D59EBAC00047DF2 /* HostUtil.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = HostUtil.cpp; path = ../../../../wsd/HostUtil.cpp; sourceTree = ""; }; - BE4C622F2D59EBAC00047DF2 /* ProofKey.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = ProofKey.hpp; path = ../../../../wsd/ProofKey.hpp; sourceTree = ""; }; - BE4C62302D59EBAC00047DF2 /* ProofKey.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ProofKey.cpp; path = ../../../../wsd/ProofKey.cpp; sourceTree = ""; }; - BE4C62312D59EBAC00047DF2 /* ProxyProtocol.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = ProxyProtocol.hpp; path = ../../../../wsd/ProxyProtocol.hpp; sourceTree = ""; }; - BE4C62322D59EBAC00047DF2 /* ProxyProtocol.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ProxyProtocol.cpp; path = ../../../../wsd/ProxyProtocol.cpp; sourceTree = ""; }; - BE4C62332D59EBAC00047DF2 /* ProxyRequestHandler.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = ProxyRequestHandler.hpp; path = ../../../../wsd/ProxyRequestHandler.hpp; sourceTree = ""; }; - BE4C62342D59EBAC00047DF2 /* ProxyRequestHandler.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ProxyRequestHandler.cpp; path = ../../../../wsd/ProxyRequestHandler.cpp; sourceTree = ""; }; - BE4C62352D59EBAC00047DF2 /* QuarantineUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = QuarantineUtil.hpp; path = ../../../../wsd/QuarantineUtil.hpp; sourceTree = ""; }; - BE4C62362D59EBAC00047DF2 /* QuarantineUtil.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = QuarantineUtil.cpp; path = ../../../../wsd/QuarantineUtil.cpp; sourceTree = ""; }; - BE4C62372D59EBAC00047DF2 /* RemoteConfig.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = RemoteConfig.hpp; path = ../../../../wsd/RemoteConfig.hpp; sourceTree = ""; }; - BE4C62382D59EBAC00047DF2 /* RemoteConfig.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = RemoteConfig.cpp; path = ../../../../wsd/RemoteConfig.cpp; sourceTree = ""; }; - BE4C62392D59EBAC00047DF2 /* RequestVettingStation.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = RequestVettingStation.hpp; path = ../../../../wsd/RequestVettingStation.hpp; sourceTree = ""; }; - BE4C623A2D59EBAC00047DF2 /* ServerAuditUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = ServerAuditUtil.hpp; path = ../../../../wsd/ServerAuditUtil.hpp; sourceTree = ""; }; - BE4C623B2D59EBAC00047DF2 /* ServerAuditUtil.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ServerAuditUtil.cpp; path = ../../../../wsd/ServerAuditUtil.cpp; sourceTree = ""; }; - BE4C623C2D59EBAC00047DF2 /* SpecialBrokers.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = SpecialBrokers.hpp; path = ../../../../wsd/SpecialBrokers.hpp; sourceTree = ""; }; - BE4C623D2D59EBAC00047DF2 /* SpecialBrokers.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SpecialBrokers.cpp; path = ../../../../wsd/SpecialBrokers.cpp; sourceTree = ""; }; BE4C623E2D59EBAC00047DF2 /* TileCache.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = TileCache.hpp; path = ../../../../wsd/TileCache.hpp; sourceTree = ""; }; - BE4C624E2D59EC5400047DF2 /* CheckFileInfo.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = CheckFileInfo.hpp; path = ../../../../../wsd/wopi/CheckFileInfo.hpp; sourceTree = ""; }; - BE4C624F2D59EC5400047DF2 /* CheckFileInfo.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = CheckFileInfo.cpp; path = ../../../../../wsd/wopi/CheckFileInfo.cpp; sourceTree = ""; }; - BE4C62502D59EC5400047DF2 /* StorageConnectionManager.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = StorageConnectionManager.hpp; path = ../../../../../wsd/wopi/StorageConnectionManager.hpp; sourceTree = ""; }; - BE4C62512D59EC5400047DF2 /* StorageConnectionManager.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = StorageConnectionManager.cpp; path = ../../../../../wsd/wopi/StorageConnectionManager.cpp; sourceTree = ""; }; - BE4C62522D59EC5400047DF2 /* WopiProxy.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = WopiProxy.hpp; path = ../../../../../wsd/wopi/WopiProxy.hpp; sourceTree = ""; }; - BE4C62532D59EC5400047DF2 /* WopiProxy.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = WopiProxy.cpp; path = ../../../../../wsd/wopi/WopiProxy.cpp; sourceTree = ""; }; - BE4C62542D59EC5400047DF2 /* WopiStorage.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = WopiStorage.hpp; path = ../../../../../wsd/wopi/WopiStorage.hpp; sourceTree = ""; }; - BE4C62552D59EC5400047DF2 /* WopiStorage.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = WopiStorage.cpp; path = ../../../../../wsd/wopi/WopiStorage.cpp; sourceTree = ""; }; - BE4C625A2D5A3C8A00047DF2 /* Ssl.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Ssl.hpp; path = ../../../../net/Ssl.hpp; sourceTree = ""; }; - BE4C625B2D5A3C8A00047DF2 /* Ssl.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Ssl.cpp; path = ../../../../net/Ssl.cpp; sourceTree = ""; }; BE4C625D2D5A3DDA00047DF2 /* Kit.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Kit.cpp; path = ../../../../kit/Kit.cpp; sourceTree = ""; }; BE4C62602D5B736200047DF2 /* coolwsd.xml */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = coolwsd.xml; path = ../../../coolwsd.xml; sourceTree = ""; }; BE5A7A282D2BE28200FE7D60 /* FileUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = FileUtil.hpp; path = ../../../../common/FileUtil.hpp; sourceTree = ""; }; - BE5A7AE02D354F4000FE7D60 /* Syscall.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Syscall.hpp; path = ../../../../common/Syscall.hpp; sourceTree = ""; }; - BE5A7AE12D354F4000FE7D60 /* Syscall.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Syscall.cpp; path = ../../../../common/Syscall.cpp; sourceTree = ""; }; BE9115AD2CECBD3100C597B2 /* FileUtil-unix.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "FileUtil-unix.cpp"; path = "../../../../common/FileUtil-unix.cpp"; sourceTree = ""; }; BE9115AF2CECBECF00C597B2 /* Util-unix.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "Util-unix.cpp"; path = "../../../../common/Util-unix.cpp"; sourceTree = ""; }; BEA263522CBE38E20007435A /* Authorization.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Authorization.hpp; path = ../../../../common/Authorization.hpp; sourceTree = ""; }; @@ -221,20 +154,13 @@ BEA264912CBE986C0007435A /* KitWebSocket.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = KitWebSocket.cpp; path = ../../../../kit/KitWebSocket.cpp; sourceTree = ""; }; BEA264972CBE98CD0007435A /* AsyncDNS.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = AsyncDNS.hpp; path = ../../../../net/AsyncDNS.hpp; sourceTree = ""; }; BEA264982CBE98CD0007435A /* FakeSocket.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = FakeSocket.cpp; path = ../../../../net/FakeSocket.cpp; sourceTree = ""; }; - BEA264992CBE98CD0007435A /* HttpRequest.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = HttpRequest.hpp; path = ../../../../net/HttpRequest.hpp; sourceTree = ""; }; - BEA2649A2CBE98CD0007435A /* HttpRequest.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = HttpRequest.cpp; path = ../../../../net/HttpRequest.cpp; sourceTree = ""; }; - BEA2649B2CBE98CD0007435A /* NetUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = NetUtil.hpp; path = ../../../../net/NetUtil.hpp; sourceTree = ""; }; - BEA2649C2CBE98CD0007435A /* NetUtil.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = NetUtil.cpp; path = ../../../../net/NetUtil.cpp; sourceTree = ""; }; BEA2649D2CBE98CD0007435A /* Socket.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Socket.hpp; path = ../../../../net/Socket.hpp; sourceTree = ""; }; BEA2649E2CBE98CD0007435A /* Socket.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Socket.cpp; path = ../../../../net/Socket.cpp; sourceTree = ""; }; - BEA2649F2CBE98CD0007435A /* WebSocketHandler.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = WebSocketHandler.hpp; path = ../../../../net/WebSocketHandler.hpp; sourceTree = ""; }; - BEA264A42CBE99340007435A /* ClientRequestDispatcher.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ClientRequestDispatcher.cpp; path = ../../../../wsd/ClientRequestDispatcher.cpp; sourceTree = ""; }; BEA264A52CBE99340007435A /* ClientSession.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ClientSession.cpp; path = ../../../../wsd/ClientSession.cpp; sourceTree = ""; }; BEA264A62CBE99340007435A /* COOLWSD.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = COOLWSD.cpp; path = ../../../../wsd/COOLWSD.cpp; sourceTree = ""; }; BEA264A72CBE99340007435A /* DocumentBroker.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = DocumentBroker.cpp; path = ../../../../wsd/DocumentBroker.cpp; sourceTree = ""; }; BEA264A82CBE99340007435A /* RequestDetails.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = RequestDetails.hpp; path = ../../../../wsd/RequestDetails.hpp; sourceTree = ""; }; BEA264A92CBE99340007435A /* RequestDetails.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = RequestDetails.cpp; path = ../../../../wsd/RequestDetails.cpp; sourceTree = ""; }; - BEA264AA2CBE99340007435A /* RequestVettingStation.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = RequestVettingStation.cpp; path = ../../../../wsd/RequestVettingStation.cpp; sourceTree = ""; }; BEA264AB2CBE99340007435A /* Storage.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Storage.cpp; path = ../../../../wsd/Storage.cpp; sourceTree = ""; }; BEA264AC2CBE99340007435A /* TileCache.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = TileCache.cpp; path = ../../../../wsd/TileCache.cpp; sourceTree = ""; }; BEA264B52CBE9BEF0007435A /* Storage.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Storage.hpp; path = ../../../../wsd/Storage.hpp; sourceTree = ""; }; @@ -244,10 +170,9 @@ BEEF3F822CE20BDD00ABE785 /* SetupKitEnvironment.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = SetupKitEnvironment.hpp; path = ../../../../kit/SetupKitEnvironment.hpp; sourceTree = ""; }; BEEF3F852CE2139E00ABE785 /* coolkitconfig.xcu */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = coolkitconfig.xcu; path = ../../../coolkitconfig.xcu; sourceTree = ""; }; BEF5CE8E2D633CE60006FD77 /* discovery.xml */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = discovery.xml; path = ../../../discovery.xml; sourceTree = ""; }; - BEFC03172D64986E009FF7B8 /* ForKit.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ForKit.cpp; path = ../../../../kit/ForKit.cpp; sourceTree = ""; }; + BEF6F02B2DD1EC0200EA06BF /* RegexUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = RegexUtil.hpp; path = ../../../../common/RegexUtil.hpp; sourceTree = ""; }; + BEF6F02C2DD1EC0200EA06BF /* RegexUtil.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = RegexUtil.cpp; path = ../../../../common/RegexUtil.cpp; sourceTree = ""; }; BEFC03182D64986E009FF7B8 /* Kit.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Kit.hpp; path = ../../../../kit/Kit.hpp; sourceTree = ""; }; - BEFC031C2D64D76D009FF7B8 /* coolwsd-inproc.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "coolwsd-inproc.cpp"; path = "../../../../wsd/coolwsd-inproc.cpp"; sourceTree = ""; }; - BEFC6A482D6737A9009FF7B8 /* dist */ = {isa = PBXFileReference; lastKnownFileType = folder; name = dist; path = ../../../browser/dist; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFileSystemSynchronizedRootGroup section */ @@ -296,7 +221,6 @@ BE22492A2CC79AAC00385A9C /* Resources */ = { isa = PBXGroup; children = ( - BEFC6A482D6737A9009FF7B8 /* dist */, BE22AA9B2CC7AE7400385A9C /* images */, BE22492D2CC79BAE00385A9C /* bundle.css */, BE22492E2CC79BAE00385A9C /* bundle.js */, @@ -312,39 +236,21 @@ path = Resources; sourceTree = ""; }; - BE4C624D2D59EC1D00047DF2 /* wopi */ = { - isa = PBXGroup; - children = ( - BE4C624E2D59EC5400047DF2 /* CheckFileInfo.hpp */, - BE4C624F2D59EC5400047DF2 /* CheckFileInfo.cpp */, - BE4C62502D59EC5400047DF2 /* StorageConnectionManager.hpp */, - BE4C62512D59EC5400047DF2 /* StorageConnectionManager.cpp */, - BE4C62522D59EC5400047DF2 /* WopiProxy.hpp */, - BE4C62532D59EC5400047DF2 /* WopiProxy.cpp */, - BE4C62542D59EC5400047DF2 /* WopiStorage.hpp */, - BE4C62552D59EC5400047DF2 /* WopiStorage.cpp */, - ); - path = wopi; - sourceTree = ""; - }; BEA2637C2CBE38FE0007435A /* common */ = { isa = PBXGroup; children = ( BEA263532CBE38E20007435A /* Authorization.cpp */, BEA263522CBE38E20007435A /* Authorization.hpp */, - BE4C61FD2D59E85500047DF2 /* CommandControl.hpp */, - BE4C61FE2D59E85500047DF2 /* CommandControl.cpp */, BE4C61FF2D59E85500047DF2 /* Common.hpp */, BEA263542CBE38E20007435A /* ConfigUtil.hpp */, BEA263552CBE38E20007435A /* ConfigUtil.cpp */, - BE4C62002D59E85500047DF2 /* CoolMount.cpp */, BE4C62012D59E85500047DF2 /* Crypto.hpp */, - BE4C62022D59E85500047DF2 /* Crypto.cpp */, + BE44ACCE2D7F067500BFA3B2 /* Crypto-stub.cpp */, + BE44ACBF2D7EFDE900BFA3B2 /* DummyTraceEventEmitter.cpp */, BE5A7A282D2BE28200FE7D60 /* FileUtil.hpp */, BEA263562CBE38E20007435A /* FileUtil.cpp */, + BE44ACC62D7F011F00BFA3B2 /* FileUtil-apple.mm */, BE9115AD2CECBD3100C597B2 /* FileUtil-unix.cpp */, - BE4C62032D59E85500047DF2 /* JailUtil.hpp */, - BE4C62042D59E85500047DF2 /* JailUtil.cpp */, BEA263572CBE38E20007435A /* Log.hpp */, BEA263582CBE38E20007435A /* Log.cpp */, BE4C62052D59E85500047DF2 /* MobileApp.hpp */, @@ -352,31 +258,30 @@ BEA263592CBE38E20007435A /* Png.hpp */, BEA2635A2CBE38E20007435A /* Protocol.hpp */, BEA2635B2CBE38E20007435A /* Protocol.cpp */, - BE4C62072D59E85500047DF2 /* Seccomp.hpp */, - BE4C62082D59E85500047DF2 /* Seccomp.cpp */, + BEF6F02B2DD1EC0200EA06BF /* RegexUtil.hpp */, + BEF6F02C2DD1EC0200EA06BF /* RegexUtil.cpp */, BEA2635C2CBE38E20007435A /* Session.hpp */, BEA2635D2CBE38E20007435A /* Session.cpp */, + BE44ACC82D7F018700BFA3B2 /* SigHandlerTrap.hpp */, BEA2635E2CBE38E20007435A /* SigUtil.hpp */, - BE4C62092D59E85500047DF2 /* SigUtil-server.cpp */, + BE44ACC92D7F018700BFA3B2 /* SigUtil-mobile.cpp */, BEA263602CBE38E20007435A /* Simd.hpp */, BEA263612CBE38E20007435A /* Simd.cpp */, BE4C620A2D59E85500047DF2 /* SpookyV2.h */, BEA263622CBE38E20007435A /* SpookyV2.cpp */, BEA263632CBE38E20007435A /* StringVector.hpp */, BEA263642CBE38E20007435A /* StringVector.cpp */, - BE5A7AE02D354F4000FE7D60 /* Syscall.hpp */, - BE5A7AE12D354F4000FE7D60 /* Syscall.cpp */, BEA263652CBE38E20007435A /* TraceEvent.hpp */, BEA263662CBE38E20007435A /* TraceEvent.cpp */, BEA263672CBE38E20007435A /* Unit.hpp */, BEA263682CBE38E20007435A /* Unit.cpp */, - BE4C620B2D59E85500047DF2 /* Unit-server.cpp */, + BE44ACD02D7F073000BFA3B2 /* Unit-mobile.cpp */, BEA263692CBE38E20007435A /* Uri.hpp */, BEA2636A2CBE38E20007435A /* Uri.cpp */, BEA2636B2CBE38E20007435A /* Util.hpp */, BEA2636C2CBE38E20007435A /* Util.cpp */, BE4C620C2D59E85500047DF2 /* Util-macos.cpp */, - BE4C620D2D59E85500047DF2 /* Util-server.cpp */, + BE44ACC12D7EFF1500BFA3B2 /* Util-mobile.cpp */, BE9115AF2CECBECF00C597B2 /* Util-unix.cpp */, ); path = common; @@ -398,7 +303,6 @@ children = ( BEA2648B2CBE986C0007435A /* DeltaSimd.h */, BEA2648C2CBE986C0007435A /* DeltaSimd.c */, - BEFC03172D64986E009FF7B8 /* ForKit.cpp */, BEA2648D2CBE986C0007435A /* ChildSession.cpp */, BEFC03182D64986E009FF7B8 /* Kit.hpp */, BE4C625D2D5A3DDA00047DF2 /* Kit.cpp */, @@ -414,20 +318,13 @@ isa = PBXGroup; children = ( BEA264972CBE98CD0007435A /* AsyncDNS.hpp */, - BE4C62182D59EAA900047DF2 /* DelaySocket.hpp */, - BE4C62192D59EAA900047DF2 /* DelaySocket.cpp */, BEA264982CBE98CD0007435A /* FakeSocket.cpp */, - BE4C621A2D59EAA900047DF2 /* HttpHelper.hpp */, - BE4C621B2D59EAA900047DF2 /* HttpHelper.cpp */, - BEA264992CBE98CD0007435A /* HttpRequest.hpp */, - BEA2649A2CBE98CD0007435A /* HttpRequest.cpp */, - BEA2649B2CBE98CD0007435A /* NetUtil.hpp */, - BEA2649C2CBE98CD0007435A /* NetUtil.cpp */, + BE44ACD22D7F07B700BFA3B2 /* HttpRequest.hpp */, + BE44ACD32D7F07B700BFA3B2 /* HttpRequest.cpp */, + BE44ACD52D7F07D800BFA3B2 /* NetUtil.hpp */, + BE44ACD62D7F07D800BFA3B2 /* NetUtil.cpp */, BEA2649D2CBE98CD0007435A /* Socket.hpp */, BEA2649E2CBE98CD0007435A /* Socket.cpp */, - BE4C625A2D5A3C8A00047DF2 /* Ssl.hpp */, - BE4C625B2D5A3C8A00047DF2 /* Ssl.cpp */, - BEA2649F2CBE98CD0007435A /* WebSocketHandler.hpp */, ); path = net; sourceTree = ""; @@ -435,47 +332,18 @@ BEA2648A2CBE98010007435A /* wsd */ = { isa = PBXGroup; children = ( - BE4C624D2D59EC1D00047DF2 /* wopi */, - BE4C621E2D59EBAC00047DF2 /* Admin.hpp */, - BE4C621F2D59EBAC00047DF2 /* Admin.cpp */, - BE4C62202D59EBAC00047DF2 /* AdminModel.hpp */, - BE4C62212D59EBAC00047DF2 /* AdminModel.cpp */, - BE4C62222D59EBAC00047DF2 /* Auth.hpp */, - BE4C62232D59EBAC00047DF2 /* Auth.cpp */, + BE44ACC32D7F00B000BFA3B2 /* ClientRequestDispatcher.hpp */, + BE44ACC42D7F00B000BFA3B2 /* ClientRequestDispatcher.cpp */, BE4C62252D59EBAC00047DF2 /* ClientSession.hpp */, - BE4C62242D59EBAC00047DF2 /* ClientRequestDispatcher.hpp */, - BEA264A42CBE99340007435A /* ClientRequestDispatcher.cpp */, BEA264A52CBE99340007435A /* ClientSession.cpp */, BE4C62262D59EBAC00047DF2 /* COOLWSD.hpp */, BEA264A62CBE99340007435A /* COOLWSD.cpp */, - BEFC031C2D64D76D009FF7B8 /* coolwsd-inproc.cpp */, BE4C62272D59EBAC00047DF2 /* DocumentBroker.hpp */, BEA264A72CBE99340007435A /* DocumentBroker.cpp */, - BE4C62282D59EBAC00047DF2 /* Exceptions.hpp */, - BE4C62292D59EBAC00047DF2 /* Exceptions.cpp */, - BE4C622A2D59EBAC00047DF2 /* FileServer.hpp */, - BE4C622B2D59EBAC00047DF2 /* FileServer.cpp */, - BE4C622C2D59EBAC00047DF2 /* FileServerUtil.cpp */, - BE4C622D2D59EBAC00047DF2 /* HostUtil.hpp */, - BE4C622E2D59EBAC00047DF2 /* HostUtil.cpp */, - BE4C622F2D59EBAC00047DF2 /* ProofKey.hpp */, - BE4C62302D59EBAC00047DF2 /* ProofKey.cpp */, - BE4C62312D59EBAC00047DF2 /* ProxyProtocol.hpp */, - BE4C62322D59EBAC00047DF2 /* ProxyProtocol.cpp */, - BE4C62332D59EBAC00047DF2 /* ProxyRequestHandler.hpp */, - BE4C62342D59EBAC00047DF2 /* ProxyRequestHandler.cpp */, - BE4C62352D59EBAC00047DF2 /* QuarantineUtil.hpp */, - BE4C62362D59EBAC00047DF2 /* QuarantineUtil.cpp */, - BE4C62372D59EBAC00047DF2 /* RemoteConfig.hpp */, - BE4C62382D59EBAC00047DF2 /* RemoteConfig.cpp */, BEA264A82CBE99340007435A /* RequestDetails.hpp */, BEA264A92CBE99340007435A /* RequestDetails.cpp */, - BE4C62392D59EBAC00047DF2 /* RequestVettingStation.hpp */, - BEA264AA2CBE99340007435A /* RequestVettingStation.cpp */, - BE4C623A2D59EBAC00047DF2 /* ServerAuditUtil.hpp */, - BE4C623B2D59EBAC00047DF2 /* ServerAuditUtil.cpp */, - BE4C623C2D59EBAC00047DF2 /* SpecialBrokers.hpp */, - BE4C623D2D59EBAC00047DF2 /* SpecialBrokers.cpp */, + BE44ACD82D7F089200BFA3B2 /* RequestVettingStation.hpp */, + BE44ACD92D7F089200BFA3B2 /* RequestVettingStation.cpp */, BEA264B52CBE9BEF0007435A /* Storage.hpp */, BEA264AB2CBE99340007435A /* Storage.cpp */, BE4C623E2D59EBAC00047DF2 /* TileCache.hpp */, @@ -635,7 +503,6 @@ BE4C62612D5B736200047DF2 /* coolwsd.xml in Resources */, BE2252292CC79BAE00385A9C /* bundle.js in Resources */, BE22529E2CC79BAE00385A9C /* cool-help.html in Resources */, - BEFC6A492D6737AF009FF7B8 /* dist in Resources */, BE2253F32CC79BAE00385A9C /* device-desktop.css in Resources */, BE22557E2CC79BAE00385A9C /* global.js in Resources */, BE16C9F02CD51F58005E5960 /* hello.odt in Resources */, @@ -679,7 +546,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "# Copy lokit to the bundle\nif [ -z \"$LO_PATH\" ]; then\n echo \"Error: LO_PATH is not set. Please configure it in Config.xcconfig.\"\n exit 1\nfi\n\necho \"Copying $LO_PATH/Contents/ to ${CONFIGURATION_BUILD_DIR}/${TARGET_NAME}.app/Contents/lokit/\"\nrsync -avz $LO_PATH/Contents/ ${CONFIGURATION_BUILD_DIR}/${TARGET_NAME}.app/Contents/lokit/\n\n# It's impossible to create 'browser/dist' in Resources via a rule directly,\n# we need to create the extra dir manually\nDIST_DIR=\"${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/dist\"\nBROWSER_DIR=\"${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/browser\"\necho \"Moving $DIST_DIR to $BROWSER_DIR\"\nmkdir -p \"$BROWSER_DIR\"\nrm -r \"$BROWSER_DIR/dist\"\nmv \"$DIST_DIR\" \"$BROWSER_DIR/\"\n"; + shellScript = "# Copy lokit to the bundle\nif [ -z \"$LO_PATH\" ]; then\n echo \"Error: LO_PATH is not set. Please configure it in Config.xcconfig.\"\n exit 1\nfi\n\necho \"Copying $LO_PATH/Contents/ to ${CONFIGURATION_BUILD_DIR}/${TARGET_NAME}.app/Contents/lokit/\"\nrsync -avz $LO_PATH/Contents/ ${CONFIGURATION_BUILD_DIR}/${TARGET_NAME}.app/Contents/lokit/\n"; }; /* End PBXShellScriptBuildPhase section */ @@ -688,72 +555,47 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - BE4C625C2D5A3C8A00047DF2 /* Ssl.cpp in Sources */, BE4C625E2D5A3DDA00047DF2 /* Kit.cpp in Sources */, - BE4C623F2D59EBAC00047DF2 /* QuarantineUtil.cpp in Sources */, - BE4C62402D59EBAC00047DF2 /* RemoteConfig.cpp in Sources */, - BE4C62412D59EBAC00047DF2 /* ProxyProtocol.cpp in Sources */, - BE4C62422D59EBAC00047DF2 /* ProxyRequestHandler.cpp in Sources */, - BEFC031D2D64D76D009FF7B8 /* coolwsd-inproc.cpp in Sources */, - BE4C62432D59EBAC00047DF2 /* FileServerUtil.cpp in Sources */, - BE4C62442D59EBAC00047DF2 /* ProofKey.cpp in Sources */, - BE4C62452D59EBAC00047DF2 /* ServerAuditUtil.cpp in Sources */, - BE4C62462D59EBAC00047DF2 /* AdminModel.cpp in Sources */, - BE4C62472D59EBAC00047DF2 /* Admin.cpp in Sources */, - BE4C62482D59EBAC00047DF2 /* Exceptions.cpp in Sources */, - BE4C62492D59EBAC00047DF2 /* SpecialBrokers.cpp in Sources */, - BE4C624A2D59EBAC00047DF2 /* FileServer.cpp in Sources */, - BE4C624B2D59EBAC00047DF2 /* HostUtil.cpp in Sources */, - BE4C624C2D59EBAC00047DF2 /* Auth.cpp in Sources */, BEA2636D2CBE38E20007435A /* Uri.cpp in Sources */, BEA264922CBE986C0007435A /* KitQueue.cpp in Sources */, - BE4C621C2D59EAA900047DF2 /* DelaySocket.cpp in Sources */, - BE4C621D2D59EAA900047DF2 /* HttpHelper.cpp in Sources */, - BEFC03192D64986E009FF7B8 /* ForKit.cpp in Sources */, BE9115AE2CECBD3100C597B2 /* FileUtil-unix.cpp in Sources */, BEA264932CBE986C0007435A /* KitWebSocket.cpp in Sources */, BEA264942CBE986C0007435A /* ChildSession.cpp in Sources */, BEA264962CBE986C0007435A /* DeltaSimd.c in Sources */, - BE4C62562D59EC5400047DF2 /* WopiStorage.cpp in Sources */, - BE4C62572D59EC5400047DF2 /* CheckFileInfo.cpp in Sources */, - BE4C62582D59EC5400047DF2 /* WopiProxy.cpp in Sources */, - BE4C62592D59EC5400047DF2 /* StorageConnectionManager.cpp in Sources */, + BEF6F02D2DD1EC0200EA06BF /* RegexUtil.cpp in Sources */, BEA2636E2CBE38E20007435A /* Util.cpp in Sources */, + BE44ACC22D7EFF1500BFA3B2 /* Util-mobile.cpp in Sources */, + BE44ACD42D7F07B700BFA3B2 /* HttpRequest.cpp in Sources */, BEA2636F2CBE38E20007435A /* Unit.cpp in Sources */, BEA263702CBE38E20007435A /* Log.cpp in Sources */, + BE44ACDA2D7F089200BFA3B2 /* RequestVettingStation.cpp in Sources */, BEA263712CBE38E20007435A /* Simd.cpp in Sources */, BEA263722CBE38E20007435A /* FileUtil.cpp in Sources */, + BE44ACD72D7F07D800BFA3B2 /* NetUtil.cpp in Sources */, BEA263732CBE38E20007435A /* Session.cpp in Sources */, + BE44ACC02D7EFDE900BFA3B2 /* DummyTraceEventEmitter.cpp in Sources */, BEA263742CBE38E20007435A /* TraceEvent.cpp in Sources */, - BEA264A02CBE98CD0007435A /* NetUtil.cpp in Sources */, + BE44ACD12D7F073000BFA3B2 /* Unit-mobile.cpp in Sources */, BEA264A12CBE98CD0007435A /* Socket.cpp in Sources */, - BEA264A22CBE98CD0007435A /* HttpRequest.cpp in Sources */, BE9115B02CECBECF00C597B2 /* Util-unix.cpp in Sources */, BE4C620E2D59E85500047DF2 /* MobileApp.cpp in Sources */, BE4C620F2D59E85500047DF2 /* Util-macos.cpp in Sources */, - BE4C62102D59E85500047DF2 /* CoolMount.cpp in Sources */, - BE4C62112D59E85500047DF2 /* Unit-server.cpp in Sources */, - BE4C62122D59E85500047DF2 /* JailUtil.cpp in Sources */, - BE4C62132D59E85500047DF2 /* Seccomp.cpp in Sources */, - BE4C62142D59E85500047DF2 /* CommandControl.cpp in Sources */, - BE4C62152D59E85500047DF2 /* Crypto.cpp in Sources */, - BE4C62162D59E85500047DF2 /* SigUtil-server.cpp in Sources */, - BE4C62172D59E85500047DF2 /* Util-server.cpp in Sources */, + BE44ACCF2D7F067500BFA3B2 /* Crypto-stub.cpp in Sources */, + BE44ACC72D7F011F00BFA3B2 /* FileUtil-apple.mm in Sources */, BEA264A32CBE98CD0007435A /* FakeSocket.cpp in Sources */, BEA263762CBE38E20007435A /* SpookyV2.cpp in Sources */, + BE44ACCA2D7F018700BFA3B2 /* SigUtil-mobile.cpp in Sources */, BEA264AD2CBE99340007435A /* Storage.cpp in Sources */, BEA264AE2CBE99340007435A /* TileCache.cpp in Sources */, BEA264AF2CBE99340007435A /* COOLWSD.cpp in Sources */, BEA264B02CBE99340007435A /* ClientSession.cpp in Sources */, BEA264B12CBE99340007435A /* RequestDetails.cpp in Sources */, - BEA264B22CBE99340007435A /* ClientRequestDispatcher.cpp in Sources */, BEA264B32CBE99340007435A /* DocumentBroker.cpp in Sources */, - BEA264B42CBE99340007435A /* RequestVettingStation.cpp in Sources */, - BE5A7AE22D354F4000FE7D60 /* Syscall.cpp in Sources */, BEA263772CBE38E20007435A /* ConfigUtil.cpp in Sources */, BEA263782CBE38E20007435A /* StringVector.cpp in Sources */, BEA263792CBE38E20007435A /* Protocol.cpp in Sources */, BEA2637A2CBE38E20007435A /* Authorization.cpp in Sources */, + BE44ACC52D7F00B000BFA3B2 /* ClientRequestDispatcher.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/macos/coda/coda/COWrapper.mm b/macos/coda/coda/COWrapper.mm index 4a59af319b79f..87c05e8b30613 100644 --- a/macos/coda/coda/COWrapper.mm +++ b/macos/coda/coda/COWrapper.mm @@ -57,30 +57,14 @@ + (void)startServer { assert(coolwsd == nullptr); // Prepare arguments for COOLWSD - const int argc = 11; - char *argv[argc + 1]; - argv[0] = strdup("coda"); - //--o:sys_template_path="$(PROJECT_DIR)/../../systemplate" - //--o:child_root_path="$(PROJECT_DIR)/../../jails" - argv[1] = strdup("--o:security.capabilities=false"); - argv[2] = strdup("--o:storage.filesystem[@allow]=true"); - argv[3] = strdup("--o:logging.color=false"); - argv[4] = strdup("--o:logging.file[@enable]=false"); - argv[5] = strdup("--o:logging.level=trace"); - argv[6] = strdup("--o:trace_event[@enable]=true"); - argv[7] = strdup("--o:ssl.enable=false"); - //argv[] = strdup("--o:ssl.cert_file_path="$(PROJECT_DIR)/../../etc/cert.pem" - //argv[] = strdup("--o:ssl.key_file_path="$(PROJECT_DIR)/../../etc/key.pem" - //argv[] = strdup("--o:ssl.ca_file_path="$(PROJECT_DIR)/../../etc/ca-chain.cert.pem" - argv[8] = strdup("--o:admin_console.username=admin"); - argv[9] = strdup("--o:admin_console.password=admin"); - argv[10] = strdup(("--o:file_server_root_path=" + getBundlePath() + "/Contents/Resources").c_str()); - argv[11] = nullptr; + std::vector args = { + "coda" + }; Util::setThreadName("app"); coolwsd = new COOLWSD(); - coolwsd->run(argc, argv); + coolwsd->run(args); delete coolwsd; coolwsd = nullptr; // Reset the pointer after deletion NSLog(@"CollaboraOffice: The COOLWSD thread completed"); From f902c653747ad8644e0cbad6b2321be6c6896869 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 11 Mar 2025 11:48:11 +0100 Subject: [PATCH 133/177] coda-m: Better look via branding.(js,css) Signed-off-by: Jan Holesovsky Change-Id: Ibc34b141893b697d6dce0b91b04e85b5f8007487 --- browser/html/cool.html.m4 | 14 ++++-------- macos/coda/coda.xcodeproj/project.pbxproj | 28 +++++++++++++++++++++++ 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/browser/html/cool.html.m4 b/browser/html/cool.html.m4 index 4e81fd2db1871..a9fc1e89e26c5 100644 --- a/browser/html/cool.html.m4 +++ b/browser/html/cool.html.m4 @@ -78,15 +78,11 @@ m4_ifelse(BUNDLE,[], m4_foreachq([fileCSS],[COOL_CSS],[ ]), []) - - -m4_ifelse(IOSAPP,[true], - []) -m4_ifelse(ANDROIDAPP,[true], - []) -m4_ifelse(EMSCRIPTENAPP,[true], - []) - +m4_dnl +m4_dnl Add branding.css for mobile apps, or the placeholder for server processing +m4_ifelse(MOBILEAPP, [true], [], + [ ]) +m4_dnl m4_dnl Handle localization m4_ifelse(MOBILEAPP,[true], [ diff --git a/macos/coda/coda.xcodeproj/project.pbxproj b/macos/coda/coda.xcodeproj/project.pbxproj index e1e749675c97a..bcaa91583ec22 100644 --- a/macos/coda/coda.xcodeproj/project.pbxproj +++ b/macos/coda/coda.xcodeproj/project.pbxproj @@ -25,6 +25,13 @@ BE44ACD42D7F07B700BFA3B2 /* HttpRequest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE44ACD32D7F07B700BFA3B2 /* HttpRequest.cpp */; }; BE44ACD72D7F07D800BFA3B2 /* NetUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE44ACD62D7F07D800BFA3B2 /* NetUtil.cpp */; }; BE44ACDA2D7F089200BFA3B2 /* RequestVettingStation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE44ACD92D7F089200BFA3B2 /* RequestVettingStation.cpp */; }; + BE44ACFC2D7F1F6B00BFA3B2 /* branding-mobile.css in Resources */ = {isa = PBXBuildFile; fileRef = BE44ACF82D7F1F6B00BFA3B2 /* branding-mobile.css */; }; + BE44ACFD2D7F1F6B00BFA3B2 /* branding-unsupported.js in Resources */ = {isa = PBXBuildFile; fileRef = BE44ACFB2D7F1F6B00BFA3B2 /* branding-unsupported.js */; }; + BE44ACFE2D7F1F6B00BFA3B2 /* branding.js in Resources */ = {isa = PBXBuildFile; fileRef = BE44ACF62D7F1F6B00BFA3B2 /* branding.js */; }; + BE44ACFF2D7F1F6B00BFA3B2 /* branding-desktop.css in Resources */ = {isa = PBXBuildFile; fileRef = BE44ACF72D7F1F6B00BFA3B2 /* branding-desktop.css */; }; + BE44AD002D7F1F6B00BFA3B2 /* branding-tablet.css in Resources */ = {isa = PBXBuildFile; fileRef = BE44ACF92D7F1F6B00BFA3B2 /* branding-tablet.css */; }; + BE44AD012D7F1F6B00BFA3B2 /* branding.css in Resources */ = {isa = PBXBuildFile; fileRef = BE44ACF52D7F1F6B00BFA3B2 /* branding.css */; }; + BE44AD022D7F1F6B00BFA3B2 /* branding-unsupported.css in Resources */ = {isa = PBXBuildFile; fileRef = BE44ACFA2D7F1F6B00BFA3B2 /* branding-unsupported.css */; }; BE4C620E2D59E85500047DF2 /* MobileApp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C62062D59E85500047DF2 /* MobileApp.cpp */; }; BE4C620F2D59E85500047DF2 /* Util-macos.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C620C2D59E85500047DF2 /* Util-macos.cpp */; }; BE4C625E2D5A3DDA00047DF2 /* Kit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C625D2D5A3DDA00047DF2 /* Kit.cpp */; }; @@ -103,6 +110,13 @@ BE44ACD62D7F07D800BFA3B2 /* NetUtil.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = NetUtil.cpp; path = ../../../../net/NetUtil.cpp; sourceTree = ""; }; BE44ACD82D7F089200BFA3B2 /* RequestVettingStation.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = RequestVettingStation.hpp; path = ../../../../wsd/RequestVettingStation.hpp; sourceTree = ""; }; BE44ACD92D7F089200BFA3B2 /* RequestVettingStation.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = RequestVettingStation.cpp; path = ../../../../wsd/RequestVettingStation.cpp; sourceTree = ""; }; + BE44ACF52D7F1F6B00BFA3B2 /* branding.css */ = {isa = PBXFileReference; lastKnownFileType = text.css; name = branding.css; path = ../../../browser/dist/branding.css; sourceTree = ""; }; + BE44ACF62D7F1F6B00BFA3B2 /* branding.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = branding.js; path = ../../../browser/dist/branding.js; sourceTree = ""; }; + BE44ACF72D7F1F6B00BFA3B2 /* branding-desktop.css */ = {isa = PBXFileReference; lastKnownFileType = text.css; name = "branding-desktop.css"; path = "../../../browser/dist/branding-desktop.css"; sourceTree = ""; }; + BE44ACF82D7F1F6B00BFA3B2 /* branding-mobile.css */ = {isa = PBXFileReference; lastKnownFileType = text.css; name = "branding-mobile.css"; path = "../../../browser/dist/branding-mobile.css"; sourceTree = ""; }; + BE44ACF92D7F1F6B00BFA3B2 /* branding-tablet.css */ = {isa = PBXFileReference; lastKnownFileType = text.css; name = "branding-tablet.css"; path = "../../../browser/dist/branding-tablet.css"; sourceTree = ""; }; + BE44ACFA2D7F1F6B00BFA3B2 /* branding-unsupported.css */ = {isa = PBXFileReference; lastKnownFileType = text.css; name = "branding-unsupported.css"; path = "../../../browser/dist/branding-unsupported.css"; sourceTree = ""; }; + BE44ACFB2D7F1F6B00BFA3B2 /* branding-unsupported.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = "branding-unsupported.js"; path = "../../../browser/dist/branding-unsupported.js"; sourceTree = ""; }; BE4C61FF2D59E85500047DF2 /* Common.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Common.hpp; path = ../../../../common/Common.hpp; sourceTree = ""; }; BE4C62012D59E85500047DF2 /* Crypto.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Crypto.hpp; path = ../../../../common/Crypto.hpp; sourceTree = ""; }; BE4C62052D59E85500047DF2 /* MobileApp.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = MobileApp.hpp; path = ../../../../common/MobileApp.hpp; sourceTree = ""; }; @@ -222,6 +236,13 @@ isa = PBXGroup; children = ( BE22AA9B2CC7AE7400385A9C /* images */, + BE44ACF52D7F1F6B00BFA3B2 /* branding.css */, + BE44ACF62D7F1F6B00BFA3B2 /* branding.js */, + BE44ACF72D7F1F6B00BFA3B2 /* branding-desktop.css */, + BE44ACF82D7F1F6B00BFA3B2 /* branding-mobile.css */, + BE44ACF92D7F1F6B00BFA3B2 /* branding-tablet.css */, + BE44ACFA2D7F1F6B00BFA3B2 /* branding-unsupported.css */, + BE44ACFB2D7F1F6B00BFA3B2 /* branding-unsupported.js */, BE22492D2CC79BAE00385A9C /* bundle.css */, BE22492E2CC79BAE00385A9C /* bundle.js */, BE22492B2CC79AD700385A9C /* cool.html */, @@ -508,6 +529,13 @@ BE16C9F02CD51F58005E5960 /* hello.odt in Resources */, BE2257AD2CC79BAE00385A9C /* bundle.css in Resources */, BE22492C2CC79AD700385A9C /* cool.html in Resources */, + BE44ACFC2D7F1F6B00BFA3B2 /* branding-mobile.css in Resources */, + BE44ACFD2D7F1F6B00BFA3B2 /* branding-unsupported.js in Resources */, + BE44ACFE2D7F1F6B00BFA3B2 /* branding.js in Resources */, + BE44ACFF2D7F1F6B00BFA3B2 /* branding-desktop.css in Resources */, + BE44AD002D7F1F6B00BFA3B2 /* branding-tablet.css in Resources */, + BE44AD012D7F1F6B00BFA3B2 /* branding.css in Resources */, + BE44AD022D7F1F6B00BFA3B2 /* branding-unsupported.css in Resources */, BEEF3F862CE2139E00ABE785 /* coolkitconfig.xcu in Resources */, BEA264162CBE7A770007435A /* Config.xcconfig in Resources */, ); From 85413d38692b1fceb12e96cc6eb573fde8dd6ca3 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 11 Mar 2025 17:02:31 +0100 Subject: [PATCH 134/177] coda-m: Icon for the bundle Signed-off-by: Jan Holesovsky Change-Id: If8733c1b1db0797f1a4b1f4a244268cbeb0a5832 --- macos/coda/coda.xcodeproj/project.pbxproj | 2 ++ .../AppIcon.appiconset/Contents.json | 10 ++++++++++ .../AppIcon.appiconset/icon_128x128.png | Bin 0 -> 1680 bytes .../AppIcon.appiconset/icon_128x128@2x.png | Bin 0 -> 3255 bytes .../AppIcon.appiconset/icon_16x16.png | Bin 0 -> 604 bytes .../AppIcon.appiconset/icon_16x16@2x.png | Bin 0 -> 310 bytes .../AppIcon.appiconset/icon_256x256.png | Bin 0 -> 3255 bytes .../AppIcon.appiconset/icon_256x256@2x.png | Bin 0 -> 6633 bytes .../AppIcon.appiconset/icon_32x32.png | Bin 0 -> 310 bytes .../AppIcon.appiconset/icon_32x32@2x.png | Bin 0 -> 902 bytes .../AppIcon.appiconset/icon_512x512.png | Bin 0 -> 6633 bytes .../AppIcon.appiconset/icon_512x512@2x.png | Bin 0 -> 15096 bytes macos/coda/coda/Info.plist | 4 ++++ 13 files changed, 16 insertions(+) create mode 100644 macos/coda/coda/Assets.xcassets/AppIcon.appiconset/icon_128x128.png create mode 100644 macos/coda/coda/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png create mode 100644 macos/coda/coda/Assets.xcassets/AppIcon.appiconset/icon_16x16.png create mode 100644 macos/coda/coda/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png create mode 100644 macos/coda/coda/Assets.xcassets/AppIcon.appiconset/icon_256x256.png create mode 100644 macos/coda/coda/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png create mode 100644 macos/coda/coda/Assets.xcassets/AppIcon.appiconset/icon_32x32.png create mode 100644 macos/coda/coda/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png create mode 100644 macos/coda/coda/Assets.xcassets/AppIcon.appiconset/icon_512x512.png create mode 100644 macos/coda/coda/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png diff --git a/macos/coda/coda.xcodeproj/project.pbxproj b/macos/coda/coda.xcodeproj/project.pbxproj index bcaa91583ec22..b0bba63009e0e 100644 --- a/macos/coda/coda.xcodeproj/project.pbxproj +++ b/macos/coda/coda.xcodeproj/project.pbxproj @@ -825,6 +825,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = coda/coda.entitlements; CODE_SIGN_STYLE = Automatic; @@ -874,6 +875,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = coda/coda.entitlements; CODE_SIGN_STYLE = Automatic; diff --git a/macos/coda/coda/Assets.xcassets/AppIcon.appiconset/Contents.json b/macos/coda/coda/Assets.xcassets/AppIcon.appiconset/Contents.json index 3f00db43ec3c8..64dc11ee7438f 100644 --- a/macos/coda/coda/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/macos/coda/coda/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,51 +1,61 @@ { "images" : [ { + "filename" : "icon_16x16.png", "idiom" : "mac", "scale" : "1x", "size" : "16x16" }, { + "filename" : "icon_16x16@2x.png", "idiom" : "mac", "scale" : "2x", "size" : "16x16" }, { + "filename" : "icon_32x32.png", "idiom" : "mac", "scale" : "1x", "size" : "32x32" }, { + "filename" : "icon_32x32@2x.png", "idiom" : "mac", "scale" : "2x", "size" : "32x32" }, { + "filename" : "icon_128x128.png", "idiom" : "mac", "scale" : "1x", "size" : "128x128" }, { + "filename" : "icon_128x128@2x.png", "idiom" : "mac", "scale" : "2x", "size" : "128x128" }, { + "filename" : "icon_256x256.png", "idiom" : "mac", "scale" : "1x", "size" : "256x256" }, { + "filename" : "icon_256x256@2x.png", "idiom" : "mac", "scale" : "2x", "size" : "256x256" }, { + "filename" : "icon_512x512.png", "idiom" : "mac", "scale" : "1x", "size" : "512x512" }, { + "filename" : "icon_512x512@2x.png", "idiom" : "mac", "scale" : "2x", "size" : "512x512" diff --git a/macos/coda/coda/Assets.xcassets/AppIcon.appiconset/icon_128x128.png b/macos/coda/coda/Assets.xcassets/AppIcon.appiconset/icon_128x128.png new file mode 100644 index 0000000000000000000000000000000000000000..624cdab34e5f81591f6a83e53a26a3ab36c60778 GIT binary patch literal 1680 zcmXw)eKgx?7RR5wsEC(ncG@PPlF?3UycA7mQ6$nOW!jh!0HmWZ@oVkPV^XV0E<@8_QTy`R6Ir~E|p zQAaEZ3jlD8iVTl~r@-2nZ7_eKaejq|T}~t`4*=ItYa=9H+5tEu=0_yv$7g5c^EkPu z0guN!ka;dEFO8FP`apK>nYzUg5&+wFM};%~Tp-s^4Q08WcO5XUEgW~dd#^C@?9h#$ zu|c;R-M@(NeJEZPT8S7x%|BDAvVF-it!W~xiO-Dc#6v29#NE6U2Tf` za9`cRLS@!0-!HRfp$CWFb7vD7F>jui4`l({QZa97%fN8igs zhGjzvG^1!7HJ1%vPOuy))36G5q6lBYyAmIE5K_F8s1Jk3m2HE*NCjx3_INg6enc#3 zudQkDM*o(Iwm~w|3#7w&DyG7=N^fd4Q~XGRdgEW#!`R-S8&XUjW$y*l{?EH4>Ohbo zY0KRuj0I0zQ(x~xrh%)WJ%gcWCQzpFWyu&7N}0u%1!Gi5WgcJVf>9xqMSPhBqcTHf zocu*~-{X$+DfF)U5U+HcM$a>iDi<$5@Oh88?s0g2=x79BjAU!9jEP3V%+gqSEE)wE%Fi{ZoO|3E7k(g)y|rnXXl`zn zA`ktN0KF<#1k`9JD!H@-Ot#5Bc z$?^AgP|Z+E|z=y6tH-Q$F0AHY4ZFMPJ>1>-{V{Gbq*E-o2%i zfv<_Fx7)kbQ~kOB(p^ej4QROI6h?;>+JLNYe!H+wcd4O1Sek4@(U`!H$Lz4=rO-pa zr~mlNuXHyN&OH9u*PVm!R*#&8y=jB15~*G^N>_q<&T`)GTp4G+g5ynJxu08Dv(fN? zKyHk<)Fr74XWrj2M@vX>NzLA>7_alUnAVtj`EekhMUGM{;mP#XF zDMLn%?u@WY@{-Hs#NmFQmq|!u2Xxh{sgn&4y`lzrmJY zEUvAlfBWoDhHq;jF$0Ve=u4#^+d>~$zVBPJIgPFDovRI|5s;K}qka7__gc8WNBr`@ z#~TpZW-3*8X4S+7f=hI*dsUx;dU{3v>$d1UJ?D3X=#rg)-V1}rE!rXwBqO7Kb|T%r)|5YOuVQnxcY@( zsUfrE%->&pdBeYOu*S$h30hiO$gN{%^P8G1{clhK$(hF!KcR6= z5hrdZSsb`sE4+;hl{nHVM9A>QA%}nd{N%AB+h?dP^zzEeAADcc`SccQKh=xgl;l41 z_vyttAq|&%brUpX(&1YT?4M*guf}|fyVGBrK+i4vt@dThur$P=U= z=t7s%RS`3~3`%r4Q>i0riW9l)av5ftdDrf|f4$GUpJ$%EpYQsv&+of_d(X30rvD=E zQ6nrz002gbe1ri2An*|Z_;7d&jy=B)-i%^=evJdbbqDi9`eo+3p=c5Bxja5FdR=_N z>ez6QkdWXM8MQGkY;{byQ*>;^(JnVj0E~qqp~uo~$2yyyL*2g z6EN-utN2>Si9@F4doKGci&5RqNeAtHXL(3HXWuaGbr)eR)CJp}9XX89?u+^@z0ew5I*-*YMgs&Njon3Nwa^$k-SxXc9n|!aV8c23}Ed<7M zX6dX5`2(CHk`)DZXg-ec#5L+TAqcYrspB_m=WwX2EQ;DYhq2Y*g2G8wl6|fF5RQGC>Ir%zzUFi!nBEK9L;e@VK|~kp-OCf}t&kPt$Eu z(B%Q#V%-?(Y@C{Wf+?OW1b2HF2_P|3bD>G_0jCzE?uBJcy?~WbJWP{okG2R}V7*j~ zpz6$hDm@^?jO~Ek8m$3=oW|ui zsrQjm9+((cxR2$CjS-Tf7pLRod@v-|2HK)tENTKNv6WH?)S4lnaG40fy!V15)BIr6R^O z8^%ORA|#QwHn&f8(fPaC-qa6$>y{1XcBh^B*I^J}-cg)M5e-I-E$&n>Yq!;-nB;cpw;XIbs%J zFUmu5VKaq=SncqCOgkr9|6>|)AnCs*9B~z5b++g*Ht=R4aZ>pKT<#*2TXA^9(5D6j zF9Y|Jf?f~CV#WprKP>sUob|&p9Oa=L@o0i15RzcL*%W-Kc>V%xHyea;&{kF|g3B=} zHAh%zg7Rz`@87Aw?}ufdEeQN!vBL!jV`*U__Bcb40`n|9|Mw&e7gWIkkv9bnP*C^{ z3L-}Ef`SwZ!BD7W1WyXM3a~oSBovbq9PuJkf(=F!NZhF$_%F!D^UbzkIAti5A6suH z0B*KutIz^LTVUkLWjG5oK*SP=z+e%xpCOaY2tp{N zNtog`Ore4(512y8q<{zkml0qJZqeJmWc05RWn)7U-yM-Y`0(LFM$Wwc*V8L1OP~Gq zTV-rlXY0E~9hT3u4&c3Q}Uz%NYOip@;P z1o;ouPmH3prU);SK5F(+JrNa;R?VLLn)b!y=8EV=PgRF-$|Ae@SWC4t0n8w1lERsw zS|F&7A$mYiz9l5?gdmsMkcdH0SS%#s^@Vh(=Ht+%kq!F(St^sPMhIowrz!M#>Iij_3cpP!};GGq9HYDrg8^0}Kc zf0u09qPf;Tx4gbS!|W6ZOWz$IsqO4Md^$8bVdaV@ozOHv{gr)$SwV?NQJ^W_;@wgH z%6Fd4BIyPgt7qL2x-IHU(%H`Xbq;O!jh^j=%Lp-dNfEW5KfQ6KWBd6)wZ-NfduF|D zS(cKha}`D7-xiG9%0I^Hg#Bq*`b^busXO`PmHz0TlcCthhb6|PIV)FxjN25yukCmzX=uM#mGD~fZ`{iR3=EFFj*OZz+cu7jEE4?d>bUfyz7 zhD4OtWcY~!VAlnaN!g)!KQ-ODyoq+GGP>w&r<+wmo$97ZM8Nw+oNY-QY59E@Z*C(p=%`mX(R2i4EJZpClv2&2z=C?r-$e(piK?RF}z>fQzXmc?VbGaM@cp%Q?ex}R+w?0c5mv~adMyj zfwE$&Y(t|%b9L-4da)E(g@tR+IbPrJ=hzuRhl5VvDr{^|y8EiXiqxCqa^ilqUwNm-%QXw?AsuxwNKul;TP zQJP&rha?GUwBe_K@)e0kXw7~Gj{frQ#nn*bdk!J}hOkvWLiu!sjdZO6+(H+V5<%W*N{Cs7X;VdfU`oWK z(}wU1;Gjiow5c4pDW(SSbQD2_Nd+fKNeeD85f-wtn*sXNkjNjQn!OVk3$RJ|)T3;{ z0#@o(UP>7Je5G<9QU;GPLZO(gh&D$^1LE&Ydb}4<2(hjz^=-M z2Sf7bpCZIs0&a>6r=Z#H)38F2DWqs`xEXT4;yfL5&hoTG6gDoX{~t9Rx!TSfEbRHv zIQ!q%zI@c@{z)nd0P1h5f)M85HVs+}Sg8NBFh;NiqsdI5TFgRXxIGXiBtQnb7YZa2 zGvyB`JRpDx3LS<>&%-#3bmtP_ikl}ztHxvU>D3T%+YrI2(>O2X7~JfZ#6rt<4nQ0n z&}EX>4Tx04R}tkv&MmKpe$izpO~b!46U!GE^rEMMWI73Pq?8YK2xEOfLO`CWa)% z#ZhoAIQX$xb#QUk)xlK|1V2C=otzY1q{ROvg%&X$9QWhhy~o`(XkQ_hwAN=mtEKQ8NNs$x~da><~5g@z^v>LYkeQevU6Cm&mTxlKuMiZF+B)!qm z;zz*1HgIv>(d0egat9cC(j`N3qySBSsRX>A(Ki)`JTRS0EJtA37C2&+G zcvvWYTquHED1%%ngI6$jXgZB)JB`4+!^XtP$Hd9V$jHV`n&)34mdf`_*`5ZXna%=9xgNy0dx^TbP+*x5kWzIUQ_`-7B&~noTj9%`uuSu|S4aQ1lP6DJJ$diyse3oiKfHP2;fiPVu|QiGOM?7@862M7NCR@ZJY5_^EKaYz zd|Iekfv5H1gV;>z_infM{m(9AlPF!*wt3>){|A|vF793Z)*=0!LqFGbWu=nPH?e}Z zOBmkiANVC}S=GiN(A1)!=)ob>h7xl%P{$w_<|^(%RomlFnGH9xvXP=U= z=t7s%RS`3~3`%r4Q>i0riW9l)av5ftdDrf|f4$GUpJ$%EpYQsv&+of_d(X30rvD=E zQ6nrz002gbe1ri2An*|Z_;7d&jy=B)-i%^=evJdbbqDi9`eo+3p=c5Bxja5FdR=_N z>ez6QkdWXM8MQGkY;{byQ*>;^(JnVj0E~qqp~uo~$2yyyL*2g z6EN-utN2>Si9@F4doKGci&5RqNeAtHXL(3HXWuaGbr)eR)CJp}9XX89?u+^@z0ew5I*-*YMgs&Njon3Nwa^$k-SxXc9n|!aV8c23}Ed<7M zX6dX5`2(CHk`)DZXg-ec#5L+TAqcYrspB_m=WwX2EQ;DYhq2Y*g2G8wl6|fF5RQGC>Ir%zzUFi!nBEK9L;e@VK|~kp-OCf}t&kPt$Eu z(B%Q#V%-?(Y@C{Wf+?OW1b2HF2_P|3bD>G_0jCzE?uBJcy?~WbJWP{okG2R}V7*j~ zpz6$hDm@^?jO~Ek8m$3=oW|ui zsrQjm9+((cxR2$CjS-Tf7pLRod@v-|2HK)tENTKNv6WH?)S4lnaG40fy!V15)BIr6R^O z8^%ORA|#QwHn&f8(fPaC-qa6$>y{1XcBh^B*I^J}-cg)M5e-I-E$&n>Yq!;-nB;cpw;XIbs%J zFUmu5VKaq=SncqCOgkr9|6>|)AnCs*9B~z5b++g*Ht=R4aZ>pKT<#*2TXA^9(5D6j zF9Y|Jf?f~CV#WprKP>sUob|&p9Oa=L@o0i15RzcL*%W-Kc>V%xHyea;&{kF|g3B=} zHAh%zg7Rz`@87Aw?}ufdEeQN!vBL!jV`*U__Bcb40`n|9|Mw&e7gWIkkv9bnP*C^{ z3L-}Ef`SwZ!BD7W1WyXM3a~oSBovbq9PuJkf(=F!NZhF$_%F!D^UbzkIAti5A6suH z0B*KutIz^LTVUkLWjG5oK*SP=z+e%xpCOaY2tp{N zNtog`Ore4(512y8q<{zkml0qJZqeJmWc05RWn)7U-yM-Y`0(LFM$Wwc*V8L1OP~Gq zTV-rlXY0E~9hT3u4&c3Q}Uz%NYOip@;P z1o;ouPmH3prU);SK5F(+JrNa;R?VLLn)b!y=8EV=PgRF-$|Ae@SWC4t0n8w1lERsw zS|F&7A$mYiz9l5?gdmsMkcdH0SS%#s^@Vh(=Ht+%kq!F(St^sPMhIowrz!M#>Iij_3cpP!};GGq9HYDrg8^0}Kc zf0u09qPf;Tx4gbS!|W6ZOWz$IsqO4Md^$8bVdaV@ozOHv{gr)$SwV?NQJ^W_;@wgH z%6Fd4BIyPgt7qL2x-IHU(%H`Xbq;O!jh^j=%Lp-dNfEW5KfQ6KWBd6)wZ-NfduF|D zS(cKha}`D7-xiG9%0I^Hg#Bq*`b^busXO`PmHz0TlcCthhb6|PIV)FxjN25yukCmzX=uM#mGD~fZ`{iR3=EFFj*OZz+cu7jEE4?d>bUfyz7 zhD4OtWcY~!VAlnaN!g)!KQ-ODyoq+GGP>w&r<+wmo$97ZM8Nw+oNY-QY59E@Z*C(p=%`mX(R2i4EJZpClv2&2z=C?r-$e(piK?RF}z>fQzXmc?VbGaM@cp%Q?ex}R+w?0c5mv~adMyj zfwE$&Y(t|%b9L-4da)E(g@tR+IbPrJ=hzuRhl5VvDr{^|y8EiXiqxCqa^ilqUwNm-%QXw?AsuxwNKul;TP zQJP&rha?GUwBe_K@)e0kXw7~Gj{frQ#nn*bdk!J}hOkvWLiu!sjdZO6+(H+V5<%W*N{Cs7X;VdfU`oWK z(}wU1;Gjiow5c4pDW(SSbQD2_Nd+fKNeeD85f-wtn*sXNkjNjQn!OVk3$RJ|)T3;{ z0#@o(UP>7Je5G<9QU;GPLZO(gh&D$^1LE&Ydb}4<2(hjz^=-M z2Sf7bpCZIs0&a>6r=Z#H)38F2DWqs`xEXT4;yfL5&hoTG6gDoX{~t9Rx!TSfEbRHv zIQ!q%zI@c@{z)nd0P1h5f)M85HVs+}Sg8NBFh;NiqsdI5TFgRXxIGXiBtQnb7YZa2 zGvyB`JRpDx3LS<>&%-#3bmtP_ikl}ztHxvU>D3T%+YrI2(>O2X7~JfZ#6rt<4nQ0n z&}@XWr-bIiJt@oO8+yoj+@Y zp`{@JjF=r1xB!4ak^pije)S~Q_u-d8T+otufVj`hABU6Q&BaBFtuq#HT^Jj+H6dcl zT1ZGpa9Ou$L;RYExV0{^TcUsJ^tD9Hw%LKx!xE2nyll#Oldz&nU31 zG5h<~jMMc-u|58_H;t}6FzU<=Q-~#NM4~Z|!d4%DU=-_>oENk%Q*t(Z?p2%bT2t-9 zhx3S++n%3$-eIzB-TTtQBZWueuQvESA8_}4_w@6p0d116OK{XXE3!XnSMApO1{^f< z|Nfzu?$o^eY!$R~h=jBmzEA+CHO+;xq^Fu+55>M5xZjl2vHhK(e^c9b`ho$p-Wb-U zt-tbZh2|`;!pdg&uCC66>s?d%@UtBV&z(~0FWl9~%;3UF1IUO;SIc-D$pQjI&(>%i z10h!mG#O>CH{gSv4anETOZ6!vBsqdSz-W-P2f1zVAZZKoA)jA--<0WQ?Q1i=71tuw2zT_oDXHRwUYAZ!Z#!oEX+}f zZ3z0l0Tcuzvqlwjp=NvwBS7v+KveDxmNX^c*XkI?)G{v)Y_E=E$x$4*Qk}?>ZXEC# zAI_3I4m@>Yv2K$&u*iwUx|wm{@MvGgnt~%hhu&huhC2}S+kbnpi*umvykQk%*Y=U% zb?OykjN%Lz=B*!;YRi$tTUs*CzK}p&-cT0$lm}iXT3G04f_5<1PY48_KQ1aXO%g5; z^kobEicE+(3i72&%9#%%Od;&Hrgkn@a)Jww-F5M%oH`*#@^7iWA`rZ0Lg)xpxfjCt z5Ozb8Fq12><-#pbT_M7NBY7aDyhPya2;=kBIrF)aTU?mop}WTCggS8~o267&AcO@$ z=qQy;O44^o$coS&H06ZyITF5<`Wk=qhg?6E%!&`Ac@WuAbfweB-LiDr82?LtyNK@$5yD6~ z7p^^pFdjj_mQvpb!YB#k=BZ2bNxH@W4!G+cn{sm9Ig*jeatjf7*h6cfI(8pP4>y3M zwc4NT385!JH=66;W`v1 z#6yH;72MGrwBUmk587{Q4m$B6cqFvr8s52JT&vbBB>7-85?&}Y3(b+@!SYJY!ts2F z9|_ANv`$A!dMXM2q*As%0}A#7!p8E!lLy(Jy0AH1#VA4^p_JXpgoZs3lcz4`i(s1# zSVn5sVRWrXT4_#M+7r#*gxp3cQ)a@YEQm=_r}L6YdIDE6L@H(?%7e$Ax-wh7crl$O2Ia-;St>mf%f5mV9rkR=jPG$oa`!*i5r1CbE4_vFFT3UUKsbyTn8SNC>!6N0(azEWc z%7F-X=1bzG(`RgBZ_L6>_;EGqeD*1G=?dm>>xSEg?q0$q0Y#VyuMJ&s&y%@?zmDXD z)%L@vPVJXZGDA#4H)E;pMO24L*Fa%c3h(PH<%YkxF;=H{Uey=Xr%Q$x=?p*bHrdhK zs7}<@pIuYcIH~JtqpnePG07hOd3^|edo!A@7%_Cu4I|g9-D9KgAN}%Hw2FFvh;ABa zYCZ%F*^7vh15mPuq%Q@+V?OlqIK0E8+?kNOh~O2P69DzIxRT`}+L@%iGa)0G8|upm zb>+k6OvrM8HU~oJ!k3)oN(KVqradwK0K^OmyTyl&L1E(w`B$v4Q2}s%P?(6Mzh;Hy z`f=)9SYhWJ;O{|U7r4N}BWD8>%Z5OB#)r8XjPBgg9K~Z+QFR(L)aBd0@|DJ$ZD zDYRqCKx2Q#EXHR%5n6B*m@*KCdA%T&b@Q4j)XZUFD-GZ+-X(M(mJ6RovaXvE^bA%P zuMon&VOaz1VR0JE`hbLdysgMEilALsSlv{PWD#ppYaYmhS%$4Mp>7gulD7?HOlNid zVgRdIlfs<{x`1U^TmZtaS=bm6v<_}tyeag|U>W`*q0f%drKsV;PP~tYNhV*9Vp$93 zKyDUm5@ze42Vt13PqLd@hPm39g>ex3&;d#Y zg&pIMGxagbHSfx9egMj$9YvJ4^~ z)ZyERuzgtZ;0uB#rE_6xFdGb80xml;C#DXyZf2dII2$CstOiWUc!H2Yk<5jgEUXMT zFu-nL!9k#PEJMw7kd(8!qU=CUv8*w-;_aQqvI(ZekeO<{*rApO}S%SU?*Yx>)xp}DRmL_1i zQt!cmFK#;CVRd;H(7xtW#$C;-Ss+PL3SN2We9(h@b^0Z#-h~T4uhH7LsLF?NU>yq! z!HSP!Vd!X`tIA}vh28?UH-}{y$Az9sMgujUfLET3hE+7sm!#sGYqe%rTUxUW_9SEs z!e(O>q8SZM7=@P}3`182(4DNVgdmViW?6k4Ap8ebE1!hL`xsr69RXulR>6LtZ?O!s z5Vnhj;Sq5Yu)2!ybQQ7;Ian+z8RN>Mu|Q;v3z2}Lk=0J*$#x&*QHVsv~9Ym&>XzCNHqi&ozLhPd;eU zc@;6fhQ+Q&hkx2JVpNSLdM?!c)>uWY{;vOC_ebUX8P~tcyQztu4|T^QRpQN?2IeMi z=>Idd+}a~rYb1o2c^}m#Ef2ehqu1j+Hs)N+?~4}(D9f>q%a3%|nf`PlJ8s)Rm?JeN zvO;5qg;v(@O6pa#S#7H9yP^+0wJCv8Dgu)bIw8pL(3wU*ou7K|!OT4I*re53BReQr zF-)a@6QdINlh0MBcJaWh+L`fj@!pIBM$I#HonB!SSMMCj|ze*eVH z9nb8V#zsYIC)hyA><8$p?p1J0_UT0j8sUnYZZsy@<5}wR$Z_|7_Zxj-rrAOPvB*=$ zEdY7g;~a{#kt(0J^rSilbS5mYSFOTioB5-;KJ(9x$(12b zLW-yDxnQnmUWrHbnh>+i9@?l$k9(iMDO%-YF;mr1 zUmQAF)r2jZledN5%_Uar=(6ug<+DE*o~)IxRF=CF^hhtU&a`xs&Q81W)ABaYk{op` zmg)&gy*Cq-y(hBkqeD$pP2=%>lj@BxR4r?%`J0Kxds-cf&+sB8WfJ?{wK4aBX2itwgqxvwrH_R&BCl`Moz+?c z8xlUA(`v*$hkTZzzu6r|Ew_5#Es#y0DitpxVM~P8Z0j!7t#0L$2`6iXlv1_<7sIuO zJ&dED6d5i%vG=5j%_^mAEC~xdbyf|Q-=)2KdM#M!Z(*j$i~$RJAX-aMnVfvhwAQ zsaG%j;L>Y>S#k+B!wxFh?sxx<1TS439YN5GrIf>eBT;_4&78`|R{4e|`t9k{Pb)%P zi!c%|-E|Y^VKJqWojm+x7v74dIXj2m_0(;}N8Mf}JNu1!>Z1*f_GNKO*?kf&;`jJU9GI40J>KYr|ktUv2D`i`n;@oi1zJ*`$N z1h+cV_Cz$4Z<#V~iJztM>Be!!CON-M%e-bm9Ulo3SHD+NnwHX}k2xEg?(B|B?2Van zX^Y*sl?WZ4lQO;SM8P4oqc=x!RZ69OJG3$`F)@CMm#?Mq8EfP8^s0)uW_@F-hpwlh ziC0spiH_j?V`7pPP-)vz*Bvv(7jeT)(we_qAF7l!k`T34Yr4eXR7-aoKjd?-r>^Ht zlc=Ub^Lecs*}up*&9?GHOWhk;)Aq};$?D<+f?g-30wPk*AERjSu4V0{hA9;J$0T1zApvW zwekIXPR**wD&8KoMteIMn%66-VNb;`1s2vulTWvY>>RV!Ll+qUZV_77WmfH1dUk!O z4BpfAzG$C0bxs82vAwvp`$gi0=(TRchka|D9&orR=3RC7;>9cea_U`DU!^%{#gQyj zQ3L42=;bQzx#KN{`LD^AJrGr(`Hq+DIWP&KK*k6_2GRHVNPWU;qL`EHKoJTTDrTV1XOUQRD7%Z z;(8wsEB!@Tr^yJ{Yp05G%6|z}%8p~BGjWoR8gSHW+ih3rmO84+FQ0QAxBRaj&eWpL zlNsvbDZ00(SDC4(=l)$?7gbeFNtcVgl`@e5eYw|LH%*s6)Pl;ghqloP+JqgK#pgAD zhFYsa9&javcv$=O8d=dm+oJ2c?rHip%Pys5j2 zt#gJ^ky@uhD7m{prEjp+e=h9OeSUw1`qEI^|IDv_qfd&OsjVEvvOeD8d?=|x*v%77 z`hSMVw53-}M&z`A=yNN%xs6oi>}pA;)@n~CS6%g<=% zQ>h!6(nRKLKv%rnTxBI*yj5HNMbOlbm6)Fe_1l}To*7QI&WRmi<7@4IX=hRCr`IM6 zasBOJ%j#*9@;Q}PbfkBKR6G|I6)gg1ck7&x6rQ!w!j%SYI=4gWVgo`hdL&Y4D#Mhr zD4hAUkKrfA!fN&0Br#}8sNskl9AJ8!7KU3WeR!rCwR#Qw0!ts#jbTb|Wll%!nEMN3{b;2i8Dg?XP??w#a(5A(W_%!fl;M11x>P(-0%a5U5)M*9Q0B;&D3O{DZih%LY6SVr z?1mKDDh1v`oB@);AxPmAXD=zVQJGkcgqnHWTw0xuoy8at(YjxqPIAG>l+&Zo1lSSu zFBu@hVs<}-uM^RvR2+yirW8_+f^nYIDkbG84*QwbJTlw>DV#eUCBrcoIE%{g=eiA3 znHVtBPfiVr!$z+p5VpJNa`BD!<|~Y)VmlO^DFv1yDA`9Y#*?8W;Wsl znUQTao>wZ?^H5oD)XS1jFlWsc2J{;|y@+G9=GAtuLIWw?!Y!*vgaLMfu(083P zaj6Dd&wm@{Fw|U7d~e9WYG#1K*l;i1G2MK}>;GH^dJ72+Gi>kCj1Zg_^)z2*7`70Qw8e?|w%na;*`+dp5nsBmbou1=G5>)1e|&

vm!jOFW?XYALT)KD)+Wm$ zmtBQwh;gsfVkwoKsI1ZuO*PHu_kNmBzwh_=FZ}lP^6LG0<~-*)&pGEg=eeBS?eF`2 z*Upxm2_aplO!l5Z2oI1)_#N>_W;J9R{&b3%{8J<$Z|mqkP8XXrv=NJ_i2+eF!-J#N zFIuyVtY5!=c-X4tkxLduEE^uaCgeojI7>prWQzCrSsPM5zL^()p(^I3Hsr$Sva(IV z<2v5!G<`5<%68lDyT99-*Wo+!izQ`AogG#V&s6TR9enPL?++ht>?zfXY2=VAl#7-O{KUeBvsPZO6xsglA zbGIe>g588ji{TIFBJy>Lo*)VCM9B8*6~>Q2^yAM;qGsL=yp9sSiq;Q6g4sVFb&lkgY>?)5#ya!oMGXuk)FA7Lpnaxw#_d<*8f zIsV#$H0qH~au|P?+7VJ{p0xM$ugUF%aUuqBh?1k0&GaUu zViuQ3-^DY7C{rsi-DAN_r~W<Vv1@t)C=0UUuaA80-DHy2}EO z=4YjGgyd1Hn**cWe+)2R zqu`+3eZG?j5wgS4(1}h%g@0Tj!=v>6_!q2}(6P)DVZsAizaXfL2e(?fSU-~kb8zu* zl%wIdU0^dF|4f_=za`=?hvHF&-zfVXJ>iOr^~D6Vod*$OrqZR`fKM-YUiERU-!_=a z9{daYYZN=F{6ffWr;Y)1mfV^EvAn>`%E|Dy8|^Da-$bn-1Ozn7Df_D>DLx>I z$G>huCc}{mhJP=X>hp>)zyov$*rpW>fxUx*xJ0!lUKVhIN{R3=J4inv1Vlm%nK3{k zaz}hp5pWtPWD5I&OEknD`al;~2Js5}g9Aq`F`EQ}li*P0Xjl{hnHn%e=H5?D^-Cm2 zf@=1aFJzsS)kL!c!%KZ(k5m z-pjEF4{8Nls9?4n5_(cAcuO%CI9V%L1bH$B03Sg+#XMlpKZogq#&bzwKaJ>IfAHk; zh|)nVnMG9;$tO~$c-dLXe?6k>bVtJ}3&@{>sCOc^Z+B z(*J?+HmD_zu)Tb6Cn9|oFBA6!{(#>u13Lkq13nNhQ<`JK&&`SaA0Z=MgbAM$6Ebn6 zVT%_gyd4qvo}*#Q9g1Q3iNG{G-swT)AHhcmK8YCj{HKlem;KHp#g1yUB0lg$KBD~< zFsT5s7l?*ppdJ`#5ud0kfJXt_04srK0N?9Lg_--XsA* z$sU?*c%(D6glqWs|LFr6+|FJ(qtk{kC(}3LVTJ` zQb!s%b%?bznN)Ar3Np+=gk%!5QY}%foZ(`;J0g+51hHFGY{+KC}iTvg$ z1LsPcpzyVaI@1S`i6)bX!5Wd049u@H`Bj zNG8$=n8GO#sZ-#Wm}?3& zB_;A?z|tLjQs~AZgBR&dG7v14i@0Q#N@p6>$(Be@WAC01+yQtSFiaHG6?lm{OF(9S z`D@NaLy+ZDLvY<#!e1Ua&YHP%-&+4f@i2x@@{Uz{l7O-mE}N}qC7&;dHa8!Y zFnu*iMQNq39P^?bKTMTr`+sVV%xykA$58TejmSiri&27IPIx5EXkIbZA^YDG>#TJT zuE*9}K#`+Moh%b_5KPW02-#9Pu5CNy4vjfuE@I!lZ95z**m|%XX1D&oz6TNM+uj!c z`5l_SedNEs2N3D0+5h$3AL;AGe|=-hi*5-2)8B?j$KUAppKmdd+BE;?_pLpNlEk!a zzvSJpvbJ<0iLcDtHik+Q@Is1P+VHI;T=vPMvGhyhPW_YhF~#{NqNZYz{`Cl%!F3Qe z8$qK%DTVo^k8?gBzNFV44UBD)30kvcmHT79Y!k@pMr1o%rp<{ntRUwu|DU{{fn4_a z^@h(6?Q#eD@N`GQ4G4s)WN#vu^2mcvTj2>vsZw(;NkT*wBV&n?`5)PEi8-R1KfK|Q zEsGt25z5=z?STidSPYCc+18HH9w9=vVQBvm@>mg~UDJ5P9;s$EG~o@prLe|O ztc3&cOp8v$d_Tll3UTn$U6y^~7Lem-N^Uld$p6N2u|*>22t#dVyPCjPX;P+aOw5VW zn#CSa{_u9(gD5@QG3b5UG3Xbv*b4Nk+A-*3+cD_j>uvn4KySt3<)9hXj?wPH;vs0C z-j30}fW zRF%pBk)d6M*U|ANVi#32UF<2}8%Df*XoYPJZo;L0D zz^7RJ7V$07s33VEmPx2lw^AI761N$rYmV$y$$Id1WRNi|%TxH7HMLZT{Dpla)w!65 zgoiLlz0e=q2zweTDaNtOo>jU3P++=kpzQ;Iaf)ffNRIY&OF-Lkw6jlTF%DY0u-fS2 zvfm0%W)~MtjR)A7`~(+pW~Fz*nqk=|Vi)8+(71-oe2tDzjoT52k7w*mwn1`Bmd!RO zXD*Agq44B(3?;vA$CRG!OS9r!7N=7Bc1-EpG3a}^Nv)G5yw_{4r;x5>o!-k7{a^z4vp{XA0TOQeoka7fc8a`-BjG(+=p^9nPO{TI$ zGeMM&U_f}j6Wa_W$=tlL$T?|=*MF0 zmovt(I0@L2#W*2kxU)DO*qX(dcZMg6w_|(WmBrv+h&?tH`YiYt4r4L+7kaQ5{0jvv zrY8^)i^0Ee1dGAHP{LyHcQj)$_&c&P^Whu9BSv@QVIODaXVk-1oGm^Zf^wDjP2D2fLSG1?*_JG+mU7bS&h&GlfNt54x{+9%C83h z!j5b^HEuT}4mbqNiXX5In01T*j8!;@r2+rK;Vec-Ds*A-Rzl=PyA8$6#RJid3>N_Q zD%>~GP?9nM7YV_}=|=S75^|l@rV}3yk24^3cwZYhJS#(H0y@8eut=FIdi{~lW^Gq= z7>ey4?Eo26{}}ZdO7E9Ou{as{3X6{b4`wl?KgZ&I!0s&G1AK$UI|-5YVKL?C5jgVdyCrwnzTE_`Ng=n#A6}OWTQ9_aC#B5 z;pPgQe;3PsC?z*8grEp`0Nv-nxQ^I`$*YZBg@_o^t}NaTJj{rzQ-P|1K=v4m`w&18|2V^jFqLc1rF~pUgXEAkv z$1JAC{g=g9bObiU9%v|9V*>1Ua+ zZ_Q>G^88r*{k|u%_KO8z-g~{y(3s1-EdO${QUBX1iSGF05uRWBmp4V0T&?-&F+m1; zx5;7pROX-co?k_4L|)b~*-+d~h(~EelmQNO=D2pk2@Ht|=PvJH{g-Z3?BKQ^3aHp_ zsW`JORZG^xD=U1}5^}(TX`AOf9R1KC5+_5FbGwbH;wDuF4%W0o6)?_hVi%2qrqgRU zvte8XPM+i%&TJH?(RQ5Z+c0f^V8l=@xn`78ahSH>HMajj+i?`8^ncKH${*Ml?SHZS z^C@Qe`-0{#mVZ9QEdPa+hUH&IG0T4;rD6G(QOxom4;pXWLO@vsLC}dUPXD`}=t6L2 zB0m__;DiH;d{?}T{`Sy|t{#m@{vck~wt86hzoY9fI8dXj-OU7?p;cVkp`>qmgB9}; zHrksdIJGi|L!>pd{pLu6$i?sw8C3~&QoZ*=lu*uMF>Y9t-YlL1?95^~s&W8}=~F;2 z7SlHZo)K>s;|}wL(M*dlx5}kPN3h3yvW$Mvlg7SoEcpN$%Z&4(u}p}2HEQ8gP?6a^ zqY3IUx1Fp%eFxlZbRoad6tnDqq!@Q1)aTYx%+enQzQNM}K`~4JoMM*#E5$5*Pv948 z+nnDOirPBL5Jn@i`+E)J*RAz7gtl@tggu&6XF~WxN_5QUKC;>m1s)Be^@GARTTV&( z%6}Fz&i7rh#wPx$Wgas%%>1UifiWLr3O+836{o!_6bYnO@v`IrSe(EAu3=1b8t>;c zg+|Bd-+z5sbl!A?SqztGEf{C$I>=&TJk!K{e0_UnP0$V31_yF?nZB4lj!gV+v|;Ad zF!vK@Le`B)KQ8J(DmJSnIO>o9@6{UFs!zHL4R;Jq6BHe!L)DT2=<#J)Una2m&ZPyd zePvAtobEHFKBjYuO7340tnE!M3z-Ncb=8}tR*XWIX(8)Ge)q4Q z<_tH%O}U7kCL)gDXkXXdAYM=+J6CX(?7F9mD}kj`2K}W|Y^trl*YNe<5nopuxpv0T zB|C6+P*CS_yj!~If|G3$(Ob}p;8$v9M9f>+1rN-nX2ZIqiys&GJ`C*2FSON&=vgpm z_`f>l)Td1=YPFKaZ_oPHq-|TiK>q`|yGWlm28Nn(E>vIOk;_EA9vglBv80E5jRliI zFyaTbY^uZ4BIgCKWaFL|UHeyJDZhg2YB4T{SN^z<$!gWSiCW1lk7?DC$`E~C5A3_v z{pew+S~zCI@a&BZKbMP4RQ0&JK8Q`snL%o1_fI#jG(L}V_UQLsLxfv#!HtOZy0}m$ zS?!#C@?xE2Oy&37LXk!^8)m(hmIZOuU*{B^k1MFsg_0Xf^m&$a2_MF2uKd6f7YP`MTVPW!iZ)_gaT!6_B9S zYDv_u$4p0&=tX+PKlio`skw04b&Z0fYKoUt`>z%(BT;IdByVV1)Y?y4=TxgI&kpjd z7EIw~ThS8|FfT{Td}2bL!Fmxl6er(o8r*0>Qu1|i*1cLII;y6A-pAyA)7;z7WWBtY zo0t>ZnpPTuBZ)>7-QyolSNV?b91WM^n%6(Ry2By^Xy{LoRsNuTh3*+*K;5U=B= z4UUzYoIR+O$WPaNjath*#NdeCaq;J5yG+jR(n^%B7jq9T^w?|z<%}L_u(=v+T}ie& z8JsfzWM)yzVHO?Ll3vQJxG{2hJTvXgRZYW_x@EG_VpTLA6ub`!qR18@bG+6n_wd5M zbCV&_S+q|s7OW*ZoD5yGMYo+;yP4yfd51R0)PImBS9~?8=y~@2;;3~gExqLS=#dyV zR{mCIf*rQyMp_H-S;%y7PpL~^zRB>jRNg_z_}dFMkYx{D3^Hwb>xZjq=1q2V>%E5N zuSek%{z$}~-`fb3{eHU7OpvwOl`YpRK7A-VR1*=M2$_0VF#c|WXtK=Fu+8nHRoeMY zM~jCx+K^?KGZAbeO%}}UTWcF8MZc?m1sx^b(Zz|!)pIJB=}o^$aT-Au9uY=nYXvQfx<=jK*6y`WZ-ic$N;%lHrSL|9$So?DwE zhGnmAptjt(R6oJrns9b5)6WSxapN$isBw-77uG#xYu%aCyhQIB+NgWl@Q>j+rWAEs7x!p`Bd_{<1n@u!BZ+68 zEOfhdu*@^o3C#Y*LynhqH_nZtYxT0vEzA+EqGZL9iys&I7Qb3u=R;;=O{9$zbE6*X z?9!5o-bP70ZZfkl$0N)16Yh;0z>T`EtLlBpDkpJau3-(@d!zl`ID2kXo~~-voW_%r zU#6R4j&A$4g0A%${0vWx!U@`db6h%;6rAP9aoejEB-E?;8P*y_B*N9#hR?VEfZ!== zUEIzMp}c@pZNZ(BBUae($gaq+(abX>7VQQ8RImH z!~ObwI#bnnGC!sxF8dQclTI1^uoJo!wP9HH##XAA+EIp6i>z%qy+icHTWCP^c28bV z5W_FD)`%>t#`g%qMStp;WUDjhH~Ce1nuJ11WQ8sdTnxV44iVwItSjT z?5dU|&OpA;KeSfQ)HgDBTjH5$B$UBczKw9+zn^zr4-2lo5uq2w|!+(M_A2&8q?7q(Ki!0EW%Es81EsA7?>TS53X~PM++I%ZwS8F zQksRk_{>4N)KELgb@8&cYZg}_vozA}jUOEJaElqXl%h;L;b5ofw~oqcG?M%nsONL> z4&pcdVx7ld%8>hix58VwS!)-utinmwu&*pv5c*?|p@M?>>vo)sHl97>#6hUuWt*kdQy{1f7qtb@5~D=u~|$QLX_w zp3~3bDfs^v98C3;Nyva{AOnQQB4;B@; ztw}zE$S1#9lA3U)TsuP6av<;#T^<0d+~~4|w^*j{f(WSJ`&OP+g-198YAA-FFfaUbkr>_n~Y} zO{J>|ts>Zh^Sv}|)IMeej33gdOK7-r8_S-iUnTCE{SRWUA@QRYepFs1=0A2I1lE-@CJ+v<_80@%f3^U6IJ`xPyf5t?-1Q(d?@RQIa=aT z*R3yJ=8}`XK4tm~Hh%G&=Q62JQQE_GuTxf}KTSxzmVNn9%Ya=tzIoxY_f*qsNkf?P z)T8QoVau1;El6IG?xU%VT7Bhs%iy!SAsc*o0)pID_5jnR@86H z!BCi~BOb?JI8W7}Pg8zL>xGA{HFtDnr6J>oKv>+Q3-7!&^{n4gzPa&c`AY07sWjiz zzOPeCb?&*>TM`ixX>nDvi-?get`@i$b}t>5{OexLg=<-tQ(f%FhHbiX$VJ^}jRMJC zisw+JAKfDB&yNUfc_tcVaCli8-stLD=X1J}nSaU=4)Gn{aDCounPRo%UZ$qjpl%IY z66IHSRelrh^#KQd5thKZMVqyieZD66#g1j}J^XWhi#e48=Q1JVhBF+6wX149QK4XZ4nbzYNG$UW&QsP zX5koouF9cf_15xlejO&&ls!zlHfBuI#F%-9QlnO{aTxfi@l*$d1bA=29FB(h+iOXf z=GuWjSLtWRhBuxH!%t>@?ke|q*+k%u8XD%e9MulBT{d3S*7<4i8mkAn#pT zUHBVaR;y3nlCY1po`qdCB6^)T)VAF-55&d3&|NCr;OyJyeo0v5lCjjaYT+Cwwb@w( z+z&W&4!~=cLhEPuzaEjYIkmhbCP<9xfUbB0cU4PQd)VJ#lDdc;gnVIZ}ntnl!^*UtucIoe+$xmumwruYNsw zo@?w7CM{u@prS-<@@V?CTxy=0@0EsdyiqRj`xGK~5i%AVZVFI3C{mhm z$zKIJkqT>~&;5DS?kh3TZ&ZULU^aS6km8pA>6Pe)ML# zFXg!7i8p)Hent`VDaz%-;_l_zbux|N+Q=JrjX#k;C;^_2Q{$P@^M!%qAhD*lZ+PSN z;s*tFCT7SL)msSpI?`~|(PBDQ&V@slzJ#|s0JEI;0GCqLyVK{N-K&-DI{}TX{P^qM zLn|d&0{?E9!1tIyo-X%k+oEpqjs2lqedKxzS%y)g-%k;K2-2tjaAW-%hn2qcH(2n^ z*jEkfL}Cn(lkj?VZTD-yed zS_o?tXZLGd6I6Z+Y}P^;xRWjWV7E5x13K)>%&vb4B7{Qd8YnQEq(pCo3u$U zn;D{!IZtieHzKVTE8>>6q$&H2=~>igC1T#%?bb}2BP?x6z1~uSh@EunjVVrpg2dgp zWZiDb{I4l#urJ?mGxt^1aYCa5USQ05RKKKx(H*eV2Cx4C`C8`R+|M`tn7sS3hAon7 zO%`7#>F_Wr&xS}b>*~L8vF3>Cp2Q#Oa3l}UZT;4`YSk*kwo{VEn(`QfHjcR?F~s1q zYdNkIw{|DutFKmk^PgICbwbQZSB6C4?vf7;a?QTu;F8Q8Bk|s?CsGc0`=uqtW)>8n zUo|ZnIu?%7k>IPZ>}F1ty!xuZma340fvJ4OYk4e{KS#nPJ1i0=DW*GkyuPPcW~5T~ z$l;J3$xnkNM`lDXea^(-nh;foid0=B+e=jr+qhJ}l3Tshug1y_7UglFsDjbNUwXPTx=ttmjox!iwq ztw=eZOL(Y+pmmbUA5ftr#moPAjGTvff+7di82G2U6Y=kk@b82!SIIC@kIUztK=!l*4(hk?uzG!WOz?oF_sMmEYO+K zw}?=b{P|-ePM@j^QIbbX5!DwBiguplp!5zz%~}Y43q+7j{BcLT!UT>JR0(bXWZbMyLrS^t3^X zQBnTKq1Do*xXpKT0}*cBRaqcHogZnKgy#oaF1{3_9JqH68fc3OI1E9n4rux6Y+M>U!cA$39?H8#@}VGF2_ozs2yWixzTku^ zZVr9Va>wH%Ew-cYT-8Z@5@CuCw%C4EL8kSPiEh!Op;ka9*J{)C%jY}iIo=xfjN8Gy z`+@HL58Ui9cZ+WE#kKfc#e* z)Ea`E1M=U%9d(n5l-wOE1NQ-x9NdS3d^aTrcN>s%DLHnBLR(@^$)j;}+QTP2ko$xC zcBo@An= zCWXmg1SAk0~t?{@4=+03N z0C#Jgdun$P|2<$Mz**#oH?hABHdff=qh?}8q=6G;M^E}Zc@hM3lj454CrA7px^}}g z30~3jm-(Y$+?c*plr~ys86_$S>`JA;2D00A!UpN6bUt;n)S=^5V(U zz%vuCj}dWv;sY@qkre9j%zp;D48p3b;MkIBZ^1~4!jo;@MED4@-3C)D;5)#bfKiZ= znS=pQK}<|{k%&$hU=W1s)`L^gi())K_?mMn%z=C3g50+UC#Vm_5NLS)OPR=1Ute2L zeygOc^;&cn-g^w^h2bU|dUGnQDINL`AAsk4=#B?{%}2#W2n6SQ;ay0|ldmkH9~1H6 z%~Os+2V^GFu?HuV3M+?zx4lU+>>);04B~c|52EC_g*gUtH%bovgL-i6DLD`15537A zN{(m~#KHSE$mtt(fHzM}xgP}g-aR;zDfxDgBXl058Vvhov8@@=h;=(r46=)_8sh2c z;gQXJDKDq&Ac_4XUd0etCSxUD!?8M4cKE2LWhY7e!jo_dx>9-#;$C~FHz6b7BKLNa zS~rHMrehovTWMcPJ{Zp(ow_T>L99$XaD{sF>>oFok}|ldbAN7<23=9m0+Bh7;O_D` zyaG<&O==JzRKvk$iLG=l6@mUg9Vz_8eHgW$EgnRow7d)$J{WU$IrvC!y$3RA$~>*_{>KbulUhcH46MAaCs%a=`F9p)PrC@ zx$ACHOsC?=C6JG^6NZwX;t^s!h-*ff=3#)3w%qyoV0s1v{5_qQ84sq@=m5L;5j1#A zLxhVs#*aYELQ`H?9`ax0Lh^)QlC?pfYOa&YI{ z7`gui@;iJZxd+Joxozb3;4V&)wvj&qcfNy>`wU7xS4d@7_5*ogZ*MBQJ-CZ+?KYBw z`{YH&sTP5}NN6Odvd`++MjlGJr*`R&;Ex!LXXv61ZC&TWqbC3B-8PSP=sIJpdD}=R zlan{BGj^pf+uKcT+qw>dPpeb;RM)jIY|@(kTo|9wB9QTc-f~f@j9@v`9sML@R(wVEHXzTv~c8np| literal 0 HcmV?d00001 diff --git a/macos/coda/coda/Info.plist b/macos/coda/coda/Info.plist index c7a9e499fa224..0c26c42835731 100644 --- a/macos/coda/coda/Info.plist +++ b/macos/coda/coda/Info.plist @@ -2,6 +2,10 @@ + CFBundleIconFile + AppIcon + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleDocumentTypes From 2b3ad29673323390a59194beadeb06ce92674cfd Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 18 Mar 2025 07:53:08 +0100 Subject: [PATCH 135/177] coda-m: Make the hyperlinks work Signed-off-by: Jan Holesovsky Change-Id: I781108b8eabf5c30579f52e01bfb4b37a3a8a119 --- macos/coda/coda/ViewController.swift | 3 --- 1 file changed, 3 deletions(-) diff --git a/macos/coda/coda/ViewController.swift b/macos/coda/coda/ViewController.swift index 65b7b03e6c438..4b79b943b2b5c 100644 --- a/macos/coda/coda/ViewController.swift +++ b/macos/coda/coda/ViewController.swift @@ -206,8 +206,6 @@ class ViewController: NSViewController, WKScriptMessageHandler, WKNavigationDele return } else if body.hasPrefix("HYPERLINK") { - COWrapper.LOG_ERR("TODO: Implement HYPERLINK") - /* let messageBodyItems = body.components(separatedBy: " ") if messageBodyItems.count >= 2 { if let url = URL(string: messageBodyItems[1]) { @@ -215,7 +213,6 @@ class ViewController: NSViewController, WKScriptMessageHandler, WKNavigationDele return } } - */ return } else if body == "FONTPICKER" { From b43220d6f846cab636b7e3348016931fd58e4f04 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Wed, 9 Apr 2025 16:28:13 +0300 Subject: [PATCH 136/177] Enable JS debugging again in the CODA-W project I don't remember if there was some unwanted side-effect of it, let's try. To make VS handle it better, temporarily use hardcoded paths from my machine. Signed-off-by: Tor Lillqvist Change-Id: I3dd5047fc93b3b5260f14c8776e0d93fed23379a --- windows/coda/CODA/MainWindow.xaml.cs | 4 ++-- windows/coda/CODA/Properties/launchSettings.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/windows/coda/CODA/MainWindow.xaml.cs b/windows/coda/CODA/MainWindow.xaml.cs index c7eef0bf66a76..89af04d48b9d2 100644 --- a/windows/coda/CODA/MainWindow.xaml.cs +++ b/windows/coda/CODA/MainWindow.xaml.cs @@ -232,14 +232,14 @@ void WebView_CoreWebView2InitializationCompleted(object sender, CoreWebView2Init // FIXME: Temporarily when running from /windows/coda/CODA/bin/Debug/net8.0-windows. // FIXME: Even more temporarily, just use hardcoded pathnames on tml's machine to make debugging the JS easier. - if (true) + if (false) { webView.CoreWebView2.SetVirtualHostNameToFolderMapping("appassets", "..\\..\\..\\..\\..\\..\\browser\\dist", CoreWebView2HostResourceAccessKind.DenyCors); webView.CoreWebView2.Navigate("https://appassets/cool.html?file_path=file:///C:/Users/tml/sailing.odt&closebutton=1&permission=edit&lang=en-US&appdocid=1&userinterfacemode=notebookbar&dir=ltr"); } else { - webView.CoreWebView2.Navigate("file:///C:/Users/tml/lo/online-gitlab-coda/browser/dist/cool.html?file_path=file:///C:/Users/tml/sailing.odt&closebutton=1&permission=edit&lang=en-US&appdocid=1&userinterfacemode=notebookbar&dir=ltr"); + webView.CoreWebView2.Navigate("file:///C:/Users/tml/lo/online-gitlab-coda25-coda/browser/dist/cool.html?file_path=file:///C:/Users/tml/sailing.odt&closebutton=1&permission=edit&lang=en-US&appdocid=1&userinterfacemode=notebookbar&dir=ltr"); } OnWebViewFirstInitialized?.Invoke(); diff --git a/windows/coda/CODA/Properties/launchSettings.json b/windows/coda/CODA/Properties/launchSettings.json index 10256163933a4..13849584e7fe2 100644 --- a/windows/coda/CODA/Properties/launchSettings.json +++ b/windows/coda/CODA/Properties/launchSettings.json @@ -6,7 +6,7 @@ "SAL_LOG": "+INFO+WARN-INFO.sal.bootstrap-INFO.i18nlangtag-INFO.vcl.fonts-INFO.vcl.gdi.fontmetric-INFO.cppu-INFO.salhelper.thread-INFO.drawinglayer-INFO.vcl.schedule-WARN.xmloff-WARN.unotools.config-WARN.legacy.tools" }, "nativeDebugging": true, - "jsWebView2Debugging": false + "jsWebView2Debugging": true } } } \ No newline at end of file From 28fdd008c95c8171745de31ffb273fe28a18e05f Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Wed, 9 Apr 2025 16:31:49 +0300 Subject: [PATCH 137/177] Add branches for the Windows app, too to the clipboard code Similar as for the iOS app. We'll see whether that is a good idea or not. Corresponding code in the C# bits of CODA-W still needs to be added. Signed-off-by: Tor Lillqvist Change-Id: I08d960592bc1d2d7e7a6b1e62bf325155382fd15 --- browser/src/map/Clipboard.js | 37 ++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/browser/src/map/Clipboard.js b/browser/src/map/Clipboard.js index 5145f646313eb..d538f07e1a292 100644 --- a/browser/src/map/Clipboard.js +++ b/browser/src/map/Clipboard.js @@ -451,6 +451,8 @@ window.L.Clipboard = window.L.Class.extend({ _sendToInternalClipboard: async function (content) { if (window.ThisIsTheiOSApp) { await window.webkit.messageHandlers.clipboard.postMessage(`sendToInternal ${await content.text()}`); // no need to base64 in this direction... + } else if (window.ThisIsTheWindowsApp) { + await window.postMobileMessage(`CLIPBOARDJS sendToInternal ${await content.text()}`); } else { var formData = new FormData(); formData.append('file', content); @@ -710,8 +712,9 @@ window.L.Clipboard = window.L.Class.extend({ } if (!window.ThisIsTheiOSApp && // in mobile apps, we want to drop straight to navigatorClipboardRead as execCommand will require user interaction... - document.execCommand(operation) && - serial !== this._clipboardSerial) { + !window.ThisIsTheWindowsApp && + document.execCommand(operation) && + serial !== this._clipboardSerial) { window.app.console.log('copied successfully'); this._unoCommandForCopyCutPaste = null; return; @@ -867,7 +870,7 @@ window.L.Clipboard = window.L.Class.extend({ // Executes the navigator.clipboard.write() call, if it's available. _navigatorClipboardWrite: function(params) { - if (!window.L.Browser.clipboardApiAvailable && !window.ThisIsTheiOSApp) { + if (!window.L.Browser.clipboardApiAvailable && !window.ThisIsTheiOSApp && !window.ThisIsTheWindowsApp) { return false; } @@ -897,6 +900,8 @@ window.L.Clipboard = window.L.Class.extend({ return; // Either wrong command or a pending event. await window.webkit.messageHandlers.clipboard.postMessage(`write`); + } else if (window.ThisIsTheWindowsApp) { + await window.postMobileMessage(`CLIPBOARDWRITE`); } else { const url = this.getMetaURL() + '&MimeType=text/html,text/plain;charset=utf-8'; @@ -976,7 +981,7 @@ window.L.Clipboard = window.L.Class.extend({ // Executes the navigator.clipboard.read() call, if it's available. _navigatorClipboardRead: function(isSpecial) { - if (!window.L.Browser.clipboardApiAvailable && !window.ThisIsTheiOSApp) { + if (!window.L.Browser.clipboardApiAvailable && !window.ThisIsTheiOSApp && !window.ThisIsTheWindowsApp) { return false; } @@ -984,9 +989,7 @@ window.L.Clipboard = window.L.Class.extend({ return true; }, - _iOSReadClipboard: async function() { - const encodedClipboardData = await window.webkit.messageHandlers.clipboard.postMessage('read'); - + _MobileAppReadClipboard: function(encodedClipboardData) { if (encodedClipboardData === "(internal)") { return null; } @@ -1014,6 +1017,17 @@ window.L.Clipboard = window.L.Class.extend({ return [new ClipboardItem(dataByMimeType)]; }, + _iOSReadClipboard: async function() { + const encodedClipboardData = await window.webkit.messageHandlers.clipboard.postMessage('read'); + return this._MobileAppReadClipboard(encodedClipboardData); + }, + + _WindowsReadClipboard: async function() { + const encodedClipboardData = await window.postMobileMessage('CLIBOARDREAD'); + // FIXME: Is the same code as for iOS OK? Will see. + return this._MobileAppReadClipboard(encodedClipboardData); + }, + _asyncAttemptNavigatorClipboardRead: async function(isSpecial) { var clipboard = navigator.clipboard; if (window.L.Browser.cypressTest) { @@ -1021,9 +1035,12 @@ window.L.Clipboard = window.L.Class.extend({ } let clipboardContents; try { - clipboardContents = window.ThisIsTheiOSApp - ? await this._iOSReadClipboard() - : await clipboard.read(); + if (window.ThisIsTheiOSApp) + clipboardContents = await this._iOSReadClipboard(); + else if (window.ThisIsTheWindowsApp) + clipboardContents = await this._WindowsReadClipboard(); + else + clipboardContents = await clipboard.read(); if (clipboardContents === null) { this._doInternalPaste(this._map, false); From 866ed9bf123db9fe4de021ab1b397ad992d03c46 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 14 Apr 2025 14:51:03 +0200 Subject: [PATCH 138/177] Provide default params for Log::initialize() to simplify callers Signed-off-by: Jan Holesovsky Change-Id: I5d4d26e4b7ebe7f88718deb0a13a8093af66062a --- android/lib/src/main/cpp/androidapp.cpp | 4 ++-- common/Log.hpp | 10 +++++----- gtk/mobile.cpp | 2 +- ios/Mobile/AppDelegate.mm | 2 +- macos/coda/coda/COWrapper.mm | 4 ++-- wasm/wasmapp.cpp | 2 +- windows/coda/windows.cpp | 2 +- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/android/lib/src/main/cpp/androidapp.cpp b/android/lib/src/main/cpp/androidapp.cpp index 6133bba8bf8a3..395814d727a40 100644 --- a/android/lib/src/main/cpp/androidapp.cpp +++ b/android/lib/src/main/cpp/androidapp.cpp @@ -54,9 +54,9 @@ JNI_OnLoad(JavaVM* vm, void*) { // Uncomment the following to see the logs from the core too //setenv("SAL_LOG", "+WARN+INFO", 0); #if ENABLE_DEBUG - Log::initialize("Mobile", "debug", false, false, {}, false, {}); + Log::initialize("Mobile", "debug"); #else - Log::initialize("Mobile", "information", false, false, {}, false, {}); + Log::initialize("Mobile", "information"); #endif return JNI_VERSION_1_6; } diff --git a/common/Log.hpp b/common/Log.hpp index 1f9b19fab8688..4fc91d5f38eca 100644 --- a/common/Log.hpp +++ b/common/Log.hpp @@ -68,11 +68,11 @@ namespace Log /// Initialize the logging system. void initialize(const std::string& name, const std::string& logLevel, - bool withColor, - bool logToFile, - const std::map& config, - bool logToFileUICmd, - const std::map& configUICmd); + bool withColor = false, + bool logToFile = false, + const std::map& config = {}, + bool logToFileUICmd = false, + const std::map& configUICmd = {}); /// Shutdown and release the logging system. void shutdown(); diff --git a/gtk/mobile.cpp b/gtk/mobile.cpp index e0e25d55f0e22..607bd247d107f 100644 --- a/gtk/mobile.cpp +++ b/gtk/mobile.cpp @@ -292,7 +292,7 @@ int main(int argc, char* argv[]) _exit(1); // avoid log cleanup } - Log::initialize("Mobile", "trace", false, false, {}, false, {}); + Log::initialize("Mobile", "trace"); Util::setThreadName("main"); fakeSocketSetLoggingCallback([](const std::string& line) diff --git a/ios/Mobile/AppDelegate.mm b/ios/Mobile/AppDelegate.mm index c65b2c5f3a356..ec50e2fba1ca9 100644 --- a/ios/Mobile/AppDelegate.mm +++ b/ios/Mobile/AppDelegate.mm @@ -51,7 +51,7 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( else setupKitEnvironment(""); - Log::initialize("Mobile", trace, false, false, {}, false, {}); + Log::initialize("Mobile", trace); Util::setThreadName("main"); // Clear the cache directory if it is for another build of the app diff --git a/macos/coda/coda/COWrapper.mm b/macos/coda/coda/COWrapper.mm index 87c05e8b30613..61973f75ef845 100644 --- a/macos/coda/coda/COWrapper.mm +++ b/macos/coda/coda/COWrapper.mm @@ -40,9 +40,9 @@ + (void)startServer { // Initialize logging // Use "debug" or potentially even "trace" for debugging #if DEBUG - Log::initialize("Mobile", "debug", false, false, {}); + Log::initialize("Mobile", "debug"); #else - Log::initialize("Mobile", "information", false, false, {}); + Log::initialize("Mobile", "information"); #endif Util::setThreadName("main"); diff --git a/wasm/wasmapp.cpp b/wasm/wasmapp.cpp index 7994c8020cc78..3fbd5c1ee424b 100644 --- a/wasm/wasmapp.cpp +++ b/wasm/wasmapp.cpp @@ -196,7 +196,7 @@ int main(int argc, char* argv_main[]) assert(argc == 3); - Log::initialize("WASM", "error", false, false, {}, false, {}); + Log::initialize("WASM", "error"); Util::setThreadName("main"); fakeSocketSetLoggingCallback([](const std::string& line) diff --git a/windows/coda/windows.cpp b/windows/coda/windows.cpp index 398439b4f0519..fe8e5dacdc3a0 100755 --- a/windows/coda/windows.cpp +++ b/windows/coda/windows.cpp @@ -49,7 +49,7 @@ void initialize_cpp_things() { // FIXME: Code snippet shared with gtk/mobile.cpp, factor out into separate file. - Log::initialize("Mobile", "trace", false, false, {}, false, {}); + Log::initialize("Mobile", "trace"); Util::setThreadName("main"); fakeSocketSetLoggingCallback([](const std::string& line) From 849b04a0fbaf517d89a612e65e83fa60efee1b12 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 14 Apr 2025 15:04:23 +0200 Subject: [PATCH 139/177] coda-m: Make the Xcode project build against 25.04 Signed-off-by: Jan Holesovsky Change-Id: Iac9ffb6c5576fa8ec02be87a2805f0df8081c93b --- macos/coda/coda.xcodeproj/project.pbxproj | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/macos/coda/coda.xcodeproj/project.pbxproj b/macos/coda/coda.xcodeproj/project.pbxproj index b0bba63009e0e..9143f53395271 100644 --- a/macos/coda/coda.xcodeproj/project.pbxproj +++ b/macos/coda/coda.xcodeproj/project.pbxproj @@ -22,8 +22,6 @@ BE44ACCA2D7F018700BFA3B2 /* SigUtil-mobile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE44ACC92D7F018700BFA3B2 /* SigUtil-mobile.cpp */; }; BE44ACCF2D7F067500BFA3B2 /* Crypto-stub.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE44ACCE2D7F067500BFA3B2 /* Crypto-stub.cpp */; }; BE44ACD12D7F073000BFA3B2 /* Unit-mobile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE44ACD02D7F073000BFA3B2 /* Unit-mobile.cpp */; }; - BE44ACD42D7F07B700BFA3B2 /* HttpRequest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE44ACD32D7F07B700BFA3B2 /* HttpRequest.cpp */; }; - BE44ACD72D7F07D800BFA3B2 /* NetUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE44ACD62D7F07D800BFA3B2 /* NetUtil.cpp */; }; BE44ACDA2D7F089200BFA3B2 /* RequestVettingStation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE44ACD92D7F089200BFA3B2 /* RequestVettingStation.cpp */; }; BE44ACFC2D7F1F6B00BFA3B2 /* branding-mobile.css in Resources */ = {isa = PBXBuildFile; fileRef = BE44ACF82D7F1F6B00BFA3B2 /* branding-mobile.css */; }; BE44ACFD2D7F1F6B00BFA3B2 /* branding-unsupported.js in Resources */ = {isa = PBXBuildFile; fileRef = BE44ACFB2D7F1F6B00BFA3B2 /* branding-unsupported.js */; }; @@ -36,6 +34,7 @@ BE4C620F2D59E85500047DF2 /* Util-macos.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C620C2D59E85500047DF2 /* Util-macos.cpp */; }; BE4C625E2D5A3DDA00047DF2 /* Kit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE4C625D2D5A3DDA00047DF2 /* Kit.cpp */; }; BE4C62612D5B736200047DF2 /* coolwsd.xml in Resources */ = {isa = PBXBuildFile; fileRef = BE4C62602D5B736200047DF2 /* coolwsd.xml */; }; + BE5FDE372DAD3DCF00C48DB2 /* LogUI.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5FDE362DAD3DCF00C48DB2 /* LogUI.cpp */; }; BE9115AE2CECBD3100C597B2 /* FileUtil-unix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE9115AD2CECBD3100C597B2 /* FileUtil-unix.cpp */; }; BE9115B02CECBECF00C597B2 /* Util-unix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE9115AF2CECBECF00C597B2 /* Util-unix.cpp */; }; BEA2636D2CBE38E20007435A /* Uri.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA2636A2CBE38E20007435A /* Uri.cpp */; }; @@ -104,10 +103,6 @@ BE44ACC92D7F018700BFA3B2 /* SigUtil-mobile.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "SigUtil-mobile.cpp"; path = "../../../../common/SigUtil-mobile.cpp"; sourceTree = ""; }; BE44ACCE2D7F067500BFA3B2 /* Crypto-stub.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "Crypto-stub.cpp"; path = "../../../../common/Crypto-stub.cpp"; sourceTree = ""; }; BE44ACD02D7F073000BFA3B2 /* Unit-mobile.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "Unit-mobile.cpp"; path = "../../../../common/Unit-mobile.cpp"; sourceTree = ""; }; - BE44ACD22D7F07B700BFA3B2 /* HttpRequest.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = HttpRequest.hpp; path = ../../../../net/HttpRequest.hpp; sourceTree = ""; }; - BE44ACD32D7F07B700BFA3B2 /* HttpRequest.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = HttpRequest.cpp; path = ../../../../net/HttpRequest.cpp; sourceTree = ""; }; - BE44ACD52D7F07D800BFA3B2 /* NetUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = NetUtil.hpp; path = ../../../../net/NetUtil.hpp; sourceTree = ""; }; - BE44ACD62D7F07D800BFA3B2 /* NetUtil.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = NetUtil.cpp; path = ../../../../net/NetUtil.cpp; sourceTree = ""; }; BE44ACD82D7F089200BFA3B2 /* RequestVettingStation.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = RequestVettingStation.hpp; path = ../../../../wsd/RequestVettingStation.hpp; sourceTree = ""; }; BE44ACD92D7F089200BFA3B2 /* RequestVettingStation.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = RequestVettingStation.cpp; path = ../../../../wsd/RequestVettingStation.cpp; sourceTree = ""; }; BE44ACF52D7F1F6B00BFA3B2 /* branding.css */ = {isa = PBXFileReference; lastKnownFileType = text.css; name = branding.css; path = ../../../browser/dist/branding.css; sourceTree = ""; }; @@ -130,6 +125,8 @@ BE4C625D2D5A3DDA00047DF2 /* Kit.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Kit.cpp; path = ../../../../kit/Kit.cpp; sourceTree = ""; }; BE4C62602D5B736200047DF2 /* coolwsd.xml */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = coolwsd.xml; path = ../../../coolwsd.xml; sourceTree = ""; }; BE5A7A282D2BE28200FE7D60 /* FileUtil.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = FileUtil.hpp; path = ../../../../common/FileUtil.hpp; sourceTree = ""; }; + BE5FDE352DAD3DCF00C48DB2 /* LogUI.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = LogUI.hpp; path = ../../../../kit/LogUI.hpp; sourceTree = ""; }; + BE5FDE362DAD3DCF00C48DB2 /* LogUI.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = LogUI.cpp; path = ../../../../kit/LogUI.cpp; sourceTree = ""; }; BE9115AD2CECBD3100C597B2 /* FileUtil-unix.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "FileUtil-unix.cpp"; path = "../../../../common/FileUtil-unix.cpp"; sourceTree = ""; }; BE9115AF2CECBECF00C597B2 /* Util-unix.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "Util-unix.cpp"; path = "../../../../common/Util-unix.cpp"; sourceTree = ""; }; BEA263522CBE38E20007435A /* Authorization.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Authorization.hpp; path = ../../../../common/Authorization.hpp; sourceTree = ""; }; @@ -330,6 +327,8 @@ BEA2648F2CBE986C0007435A /* KitQueue.hpp */, BEA264902CBE986C0007435A /* KitQueue.cpp */, BEA264912CBE986C0007435A /* KitWebSocket.cpp */, + BE5FDE352DAD3DCF00C48DB2 /* LogUI.hpp */, + BE5FDE362DAD3DCF00C48DB2 /* LogUI.cpp */, BEEF3F822CE20BDD00ABE785 /* SetupKitEnvironment.hpp */, ); path = kit; @@ -340,10 +339,6 @@ children = ( BEA264972CBE98CD0007435A /* AsyncDNS.hpp */, BEA264982CBE98CD0007435A /* FakeSocket.cpp */, - BE44ACD22D7F07B700BFA3B2 /* HttpRequest.hpp */, - BE44ACD32D7F07B700BFA3B2 /* HttpRequest.cpp */, - BE44ACD52D7F07D800BFA3B2 /* NetUtil.hpp */, - BE44ACD62D7F07D800BFA3B2 /* NetUtil.cpp */, BEA2649D2CBE98CD0007435A /* Socket.hpp */, BEA2649E2CBE98CD0007435A /* Socket.cpp */, ); @@ -593,15 +588,14 @@ BEF6F02D2DD1EC0200EA06BF /* RegexUtil.cpp in Sources */, BEA2636E2CBE38E20007435A /* Util.cpp in Sources */, BE44ACC22D7EFF1500BFA3B2 /* Util-mobile.cpp in Sources */, - BE44ACD42D7F07B700BFA3B2 /* HttpRequest.cpp in Sources */, BEA2636F2CBE38E20007435A /* Unit.cpp in Sources */, BEA263702CBE38E20007435A /* Log.cpp in Sources */, BE44ACDA2D7F089200BFA3B2 /* RequestVettingStation.cpp in Sources */, BEA263712CBE38E20007435A /* Simd.cpp in Sources */, BEA263722CBE38E20007435A /* FileUtil.cpp in Sources */, - BE44ACD72D7F07D800BFA3B2 /* NetUtil.cpp in Sources */, BEA263732CBE38E20007435A /* Session.cpp in Sources */, BE44ACC02D7EFDE900BFA3B2 /* DummyTraceEventEmitter.cpp in Sources */, + BE5FDE372DAD3DCF00C48DB2 /* LogUI.cpp in Sources */, BEA263742CBE38E20007435A /* TraceEvent.cpp in Sources */, BE44ACD12D7F073000BFA3B2 /* Unit-mobile.cpp in Sources */, BEA264A12CBE98CD0007435A /* Socket.cpp in Sources */, From 7996f9307e9906f32c0db3a7a8b1c1aafacf6f4c Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 14 Apr 2025 15:30:55 +0200 Subject: [PATCH 140/177] coda-m: Trivial documentation update Signed-off-by: Jan Holesovsky Change-Id: Ida5f52341a27ab2bf60755db07a21965c9961bba --- macos/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/macos/README.md b/macos/README.md index eb1fa26aa8c7e..80841515bb2f7 100644 --- a/macos/README.md +++ b/macos/README.md @@ -77,7 +77,7 @@ report that, it's a mistake and should be fixed. ## Then you can build CODA-M: -* ( cd browser ; make ) +* ( cd browser ; gmake ) * open Xcode's project macos/coda/coda.xcodeproj & build from there # Building and debugging coolwsd directly in Xcode From 7c185ba77253806e63dc33b2e00099a58560d5ad Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Tue, 15 Apr 2025 13:14:44 +0300 Subject: [PATCH 141/177] Tune the launch settings for CODA in Visual Studio a bit Let's drop the verbose core logging for now, and not debug JS. Sadly it seems that you need to choose each time whether you are debugging native code *or* JS. Unless I am misunderstanding. Also, actually not sure whether it makes sense to keep this file in git. Signed-off-by: Tor Lillqvist Change-Id: I90bc5aa7f053051972345d152468b13236ae0039 --- windows/coda/CODA/Properties/launchSettings.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/windows/coda/CODA/Properties/launchSettings.json b/windows/coda/CODA/Properties/launchSettings.json index 13849584e7fe2..ceb2f7cb014a0 100644 --- a/windows/coda/CODA/Properties/launchSettings.json +++ b/windows/coda/CODA/Properties/launchSettings.json @@ -3,10 +3,11 @@ "CODA": { "commandName": "Project", "environmentVariables": { - "SAL_LOG": "+INFO+WARN-INFO.sal.bootstrap-INFO.i18nlangtag-INFO.vcl.fonts-INFO.vcl.gdi.fontmetric-INFO.cppu-INFO.salhelper.thread-INFO.drawinglayer-INFO.vcl.schedule-WARN.xmloff-WARN.unotools.config-WARN.legacy.tools" + "xSAL_LOG": "+INFO+WARN-INFO.sal.bootstrap-INFO.i18nlangtag-INFO.vcl.fonts-INFO.vcl.gdi.fontmetric-INFO.cppu-INFO.salhelper.thread-INFO.drawinglayer-INFO.vcl.schedule-WARN.xmloff-WARN.unotools.config-WARN.legacy.tools" }, "nativeDebugging": true, - "jsWebView2Debugging": true + "jsWebView2Debugging": false, + "hotReloadEnabled": false } } } \ No newline at end of file From 12cdbeb8def20bb7eb8925dffbdbc2754c9cec32 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Tue, 15 Apr 2025 15:41:44 +0300 Subject: [PATCH 142/177] Change libpng library name to match that built in LO Signed-off-by: Tor Lillqvist Change-Id: I278daacde8035fc068539c86ed8824ba78ba0a58 --- windows/coda/CODALib/CODALib.vcxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/windows/coda/CODALib/CODALib.vcxproj b/windows/coda/CODALib/CODALib.vcxproj index b6a5763dce4af..3accdf02e1610 100644 --- a/windows/coda/CODALib/CODALib.vcxproj +++ b/windows/coda/CODALib/CODALib.vcxproj @@ -70,7 +70,7 @@ Windows true false - libpng16.lib;zlib.lib;libzstd_static.lib;ws2_32.lib;iphlpapi.lib;%(AdditionalDependencies) + libpng.lib;zlib.lib;libzstd_static.lib;ws2_32.lib;iphlpapi.lib;%(AdditionalDependencies) @@ -95,7 +95,7 @@ true true false - libpng16.lib;zlib.lib;libzstd_static.lib;%(AdditionalDependencies) + libpng.lib;zlib.lib;libzstd_static.lib;%(AdditionalDependencies) From 209bd6b74d5d9cc1e2cd036d30224a576487c26c Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Tue, 15 Apr 2025 17:28:51 +0300 Subject: [PATCH 143/177] Improve CODA-W build instructions Signed-off-by: Tor Lillqvist Change-Id: I4653e1a09484553443da64c0b8d958378da83fce --- windows/coda/README.md | 176 ++++++++++++++++++++++++++++++++++++++++ windows/coda/README.txt | 26 ------ 2 files changed, 176 insertions(+), 26 deletions(-) create mode 100644 windows/coda/README.md delete mode 100644 windows/coda/README.txt diff --git a/windows/coda/README.md b/windows/coda/README.md new file mode 100644 index 0000000000000..ec0c1af87d6e0 --- /dev/null +++ b/windows/coda/README.md @@ -0,0 +1,176 @@ +# Building CODA-W + +## Requirements + +For starters, the same requirements as for building LibreOffice, see +https://wiki.documentfoundation.org/Development/BuildingOnWindows as +you will do that as part of building CODA-W. Make sure to use Visual +Studio 2022. Using other Visual Studio versions for building the +online bits has not been tested. + +In Visual Studio 2022, also install the .NET desktop development +components. + +## Setup + +Turn on WSL, the Windows Subsystem for Linux, and install a distro. +I use the default, Ubuntu, others presumably work, too. In an +administrator Command Prompt: + + wsl --install Ubuntu + +In that Ubuntu, install various things that will be needed later. Most +of this is needed just to run the configure script in online. That +configure script checks for tons of things that are completely +irrelevant for CODA, but oh well. Patches welcome. + +This is not necessarily a comprehensive list, you might notice more +missing things as you go along. + + sudo apt install libtool python3-lxml python3-polib g++ pkg-config + sudo apt install libpng-dev libzstd-dev libcppunit-dev libpam-dev + +The following things are more essential, for bulding the JavaScript +stuff. This is the main reason we are using WSL. + + sudo apt install nodejs npm + +## Build LibreOffice + +Clone the git@gitlab.collabora.com:productivity/libreoffice/core.git +repo, the coda-25.04 branch. + +Using an autogen.input like this is known to work: + +``` +--with-distro=CODAWindows +--with-visual-studio=2022 +--enable-debug +--enable-msvc-debug-runtime +--enable-headless +--disable-ccache +--disable-opencl +--disable-pch +--without-doxygen +--without-lxml +--without-lang +``` + +The --with-distro, --with-visual-studio, and --enable-headless options +are essential. The other ones you can play with. Note that if you +build the CODA project in Visual Studio in the Debug configuration, +you *must* use a LibreOffice build with either --enable-dbgutil or +--enable-msvc-debug-runtime. + +The LibreOffice build should proceed fairly normally. Note that you +will not end up with a runnable normal desktop LibreOffice. Attempting +to run instdir/program/soffice.exe will just produce the message "no +suitable windowing system found, exiting". + +You can attempt to run "make check" but that will probably run into +some false positives. + +## Build direct dependencies of CODA-W + +Version numbers below are current at the time of writing this. Newer +versions will probably work, too. Except that online might not compile +against Poco 1.14, so use the newest 1.13.*. For zlib and libpng we +use the unpacked sources in the LibreOffice core build directory, and +the static libraries already built there. + +## zstd + +Download and unpack the zstd-1.5.7 tarball. Open the Visual Studio +solution zstd-1.5.7/build/VS2010/zstd.sln. Let Visual Studio retarget +the projects. Build the solution. + +The binary that you are interested in is +zstd-1.5.7/build/VS2010/bin/x64\_Debug/libzstd\_static.lib. + +## Poco + +Download and unpack the poco-poco-1.13.3-release.tar.gz tarball. + +Then build it. Only a subset of it is needed. In a Ubuntu shell +window, run: + + powershell.exe -ExecutionPolicy Bypass -File buildwin.ps1 -action build -config both -linkmode static\_md -platform x64 -components Foundation,Util,JSON,Net,XML + +Then move all the headers into one place: + + mkdir -p include/Poco + cp -a Foundation/include/Poco/* include/Poco + cp -a Util/include/Poco/* include/Poco + cp -a JSON/include/Poco/* include/Poco + cp -a Net/include/Poco/* include/Poco + cp -a XML/include/Poco/* include/Poco + +Then apply this patch to get the proper names for the automatically +imported static Poco libraries: + +``` +--- Foundation/include/Poco/Foundation.h 2024-10-15 13:18:14.020114300 +0300 ++++ include/Poco/Foundation.h 2025-04-15 17:19:54.163644800 +0300 +@@ -29,11 +29,23 @@ + // + // Ensure that POCO_DLL is default unless POCO_STATIC is defined + // ++ ++// TML: For some reason POCO_STATIC is not defined, even though I ++// build statically, and also the POCO_LIB_SUFFIX seems to go wrong ++// compared to what my build produces, so bypass this and just do what I want... ++// I build it like this: ++// powershell.exe -ExecutionPolicy Bypass -File buildwin.ps1 -action build -config both -linkmode static\_md -platform x64 -components Foundation,Util,JSON,Net,XML ++ ++#define POCO_STATIC 1 ++#define POCO_LIB_SUFFIX "mdd.lib" ++ ++#if 0 + #if defined(_WIN32) && defined(_DLL) + #if !defined(POCO_DLL) && !defined(POCO_STATIC) + #define POCO_DLL + #endif + #endif ++#endif + + + // +@@ -66,6 +78,7 @@ + // Automatically link Foundation library. + // + #if defined(_MSC_VER) ++ #if 0 // --tml + #if defined(POCO_DLL) + #if defined(_DEBUG) + #define POCO_LIB_SUFFIX "d.lib" +@@ -85,6 +98,7 @@ + #define POCO_LIB_SUFFIX "mt.lib" + #endif + #endif ++ #endif // --tml + + #if !defined(POCO_NO_AUTOMATIC_LIBS) && !defined(Foundation_EXPORTS) + #pragma comment(lib, "PocoFoundation" POCO_LIB_SUFFIX) +``` + +## Build CODA-W itself + +Clone the git@gitlab.collabora.com:productivity/libreoffice/online.git +repo, the coda-25.04 branch. + +In an Ubuntu shell, run + + ./autogen.sh + +then run the configure script: + + ./configure --enable-windowsapp --enable-debug --with-app-name=CODA --with-lo-builddir=/mnt/c/cygwin64/home/tml/lo/core-gitlab-coda25-coda-debug --with-lo-path=c:/cygwin64/home/tml/lo/core-gitlab-coda25-coda-debug/instdir --with-poco-includes=/mnt/c/Users/tml/poco-poco-1.13.3-release/include --with-poco-libs=/mnt/c/Users/tml/poco-poco-1.13.3-release/lib64 --with-zstd-includes=/mnt/c/Users/tml/zstd-1.5.7/lib --with-zstd-libs=/mnt/c/Users/tml/zstd-1.5.7/build/VS2010/bin/x64\_Debug --with-libpng-includes=/mnt/c/cygwin64/home/tml/lo/core-gitlab-coda25-coda-debug/workdir/UnpackedTarball/libpng --with-libpng-libs=/mnt/c/cygwin64/home/tml/lo/core-gitlab-coda25-coda-debug/workdir/LinkTarget/StaticLibrary --with-zlib-includes=/mnt/c/cygwin64/home/tml/lo/core-gitlab-coda25-coda-debug/workdir/UnpackedTarball/zlib + +Obviously, adapt as necessary to match your username and where you +built LibreOffice, zstd, and Poco. + +Now you can build the JavaScript bits: + + (cd browser && make) + +And then finally, open the windows/coda/CODA/CODA.sln solution in Visual Studio and build it. diff --git a/windows/coda/README.txt b/windows/coda/README.txt deleted file mode 100644 index e442c8ce41682..0000000000000 --- a/windows/coda/README.txt +++ /dev/null @@ -1,26 +0,0 @@ -To build CODA for Windows: - -First build LibreOffice core for Windows. Typically you would do that -the traditional way using Cygwin at the outermost level, but the -actual compiler is Visual Studio. - -Then build or install Poco. - -Then install xstd. The win64 prebuilt package should work fine. - -Then you configure online in WSL2, not in Cygwin, something like this: - -./autogen.sh -./configure --enable-windowsapp --with-app-name=CODA --with-lo-builddir=/mnt/c/Users/tml/lo/core-coda-debug --with-poco-includes=/mnt/c/Users/tml/poco-1.13.3/include --with-poco-libs=/mnt/c/Users/tml/poco-1.13.3/lib64 --with-zstd-includes=/mnt/c/Users/tml/zstd-v1.5.6-win64/include --with-zstd-libs=/mnt/c/Users/tml/zstd-v1.5.6-win64/static - -Note that this will run a bunch of checks for compiler features and -libraries (like cppunit, PAM, etc) on the WSL2 side that are -completely irrelevant. You will actually compile the code in Visual -Studio using the supplied project file and windows/coda/config.h.in. -But I haven't bothered adding lots of bypassing checks to -configure.ac. Using the Makefile (generated by all the autocrack) is -useful anyway as that is a convenient way to produce the bundled JS -thing. - -Do *not* run a "make" in the top directory. Instead, to produce the -bundled JS, go to the "browser" subdirectory and run "make" there. From b31bd66c138171a79cb1e66849287b7044f47001 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Wed, 16 Apr 2025 14:35:41 +0200 Subject: [PATCH 144/177] coda-m: Proof of concept Bold/Italic/Underline menu items It works to toggle them (the format of the selected text actually toggles), but the checkmarks (if toggled or not) are only toggled by choosing from the menu, not synchronized with the core via 'statechanged:' yet. Signed-off-by: Jan Holesovsky Change-Id: Ie02dd3987a6ad9096debec2d420a6801317d17e3 --- macos/coda/coda/Base.lproj/Main.storyboard | 18 +++---- macos/coda/coda/Document.swift | 2 +- macos/coda/coda/WindowController.swift | 63 ++++++++++++++++++++++ 3 files changed, 73 insertions(+), 10 deletions(-) create mode 100644 macos/coda/coda/WindowController.swift diff --git a/macos/coda/coda/Base.lproj/Main.storyboard b/macos/coda/coda/Base.lproj/Main.storyboard index 5c3756d40dc54..1365a3f9110dc 100644 --- a/macos/coda/coda/Base.lproj/Main.storyboard +++ b/macos/coda/coda/Base.lproj/Main.storyboard @@ -1,7 +1,7 @@ - + - + @@ -350,19 +350,19 @@ - + - + - + - + - + - + @@ -704,7 +704,7 @@ - + diff --git a/macos/coda/coda/Document.swift b/macos/coda/coda/Document.swift index 71d120acc58ae..6a6d2a6637b20 100644 --- a/macos/coda/coda/Document.swift +++ b/macos/coda/coda/Document.swift @@ -91,7 +91,7 @@ class Document: NSDocument { // Load the storyboard and get the window controller. let storyboard = NSStoryboard(name: "Main", bundle: nil) let identifier = NSStoryboard.SceneIdentifier("DocumentWindowController") - guard let windowController = storyboard.instantiateController(withIdentifier: identifier) as? NSWindowController else { + guard let windowController = storyboard.instantiateController(withIdentifier: identifier) as? WindowController else { fatalError("Unable to find DocumentWindowController in storyboard.") } self.addWindowController(windowController) diff --git a/macos/coda/coda/WindowController.swift b/macos/coda/coda/WindowController.swift new file mode 100644 index 0000000000000..3bfb75f5e35de --- /dev/null +++ b/macos/coda/coda/WindowController.swift @@ -0,0 +1,63 @@ +/* + * Copyright the Collabora Online contributors. + * + * SPDX-License-Identifier: MPL-2.0 + * + * 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/. + */ + +import Cocoa + +enum FormatMenuCommand: Int { + case bold = 1 + case italic + case underline +} + +let formatMenuUnoCommands: [FormatMenuCommand: String] = [ + .bold: "Bold", + .italic: "Italic", + .underline: "Underline" +] + +/// Window controller that manages the document window & menus +class WindowController: NSWindowController, NSMenuItemValidation { + + /// Track menu states here, to be able to show the state in the menu + var formatStates: [FormatMenuCommand: Bool] = [:] + + /// Single IBAction for all Format commands in the menu + @IBAction func formatMenuAction(_ sender: NSMenuItem) { + guard let command = FormatMenuCommand(rawValue: sender.tag) else { return } + + // Toggle or otherwise update the command state + let oldVal = formatStates[command] ?? false + let newVal = !oldVal + formatStates[command] = newVal + + // Forward to the ViewController so it can actually set bold/italic/... + if let vc = contentViewController as? ViewController { + if let unoCommand = formatMenuUnoCommands[command] ?? nil { + COWrapper.handleMessage(with: vc.document, message: "uno .uno:\(unoCommand)") + } + } + } + + /// Show on/off checkmarks for the particular command(s) like Bold/Italics/... + func validateMenuItem(_ menuItem: NSMenuItem) -> Bool { + if menuItem.action != #selector(formatMenuAction(_:)) { + return true // not our action + } + + guard let command = FormatMenuCommand(rawValue: menuItem.tag) else { + return false + } + + // Show a check if the command is currently ON + let isOn = formatStates[command] ?? false + menuItem.state = isOn ? .on : .off + return true + } +} From fc3bf47b84a91726014d06e2776059886ab4d03a Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 22 Apr 2025 10:19:15 +0200 Subject: [PATCH 145/177] coda-m: Add branding how-to Signed-off-by: Jan Holesovsky Change-Id: I7940509ae82cece4c767af625a25a3f6050d26ed --- macos/README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/macos/README.md b/macos/README.md index 80841515bb2f7..38750e1b386d4 100644 --- a/macos/README.md +++ b/macos/README.md @@ -75,6 +75,13 @@ not /opt/homebrew. If you find an instance of /Users/kendy hardcoded somewhere, please report that, it's a mistake and should be fixed. +## Install branding + +Checkout online-branding, and install the branding like the following (please +update the paths to the core instdir and online repo): + +./brand.sh ~/Projects/lo/core/instdir ../online/browser/dist 1 + ## Then you can build CODA-M: * ( cd browser ; gmake ) From 4962ce94d62e6b54228fc51c3dc7aabd9d8d23ac Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Tue, 22 Apr 2025 11:45:00 +0300 Subject: [PATCH 146/177] We also need zlib, libpng, and cppunit for CODA-M cppunit only because of the check in the configure sript, but I am too lazy now to make it not bother to check in the CODA case. Signed-off-by: Tor Lillqvist Change-Id: I9a950a65e07bd661de442e29d702e238f28d41c2 --- macos/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/macos/README.md b/macos/README.md index 38750e1b386d4..fc1a4b1b39b78 100644 --- a/macos/README.md +++ b/macos/README.md @@ -10,6 +10,12 @@ * brew install zstd * missing from the iOS build instructions (needed for online.git) * brew install libtool +* zlib + * brew install zlib +* libpng + * brew install libpng +* cppunit + * brew install cppunit * install dependencies for the canvas@next * brew install cairo From 714c8f517283ddc01412a0bfc828ef64561796b5 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Tue, 22 Apr 2025 12:28:18 +0300 Subject: [PATCH 147/177] Update WebView2 to the current version, as VS suggests Signed-off-by: Tor Lillqvist Change-Id: I21f36001eb5ae8c706f16eae559f0416679c208a --- windows/coda/CODA/CODA.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/windows/coda/CODA/CODA.csproj b/windows/coda/CODA/CODA.csproj index 71755ffeb0530..b79ed0dc7ce2f 100644 --- a/windows/coda/CODA/CODA.csproj +++ b/windows/coda/CODA/CODA.csproj @@ -10,7 +10,7 @@ - + From 6f2dcf8cdaf41a3fa2ccdf8a60a0513e7bb2bbe4 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Tue, 22 Apr 2025 15:28:05 +0300 Subject: [PATCH 148/177] Start adding a native menu to CODA-W So far just a File menu where the Open... item opens a file selector. The result of that selection is not yet coupled to anything, and we still always open the same sample document right away. The MainWindow XAML now has a StackPanel with the Menu and WebView2 as children. The intent is that only once a document is selected, the cool.html will be loaded, to edit the file in question. Signed-off-by: Tor Lillqvist Change-Id: I14f05aa97afca9c30b48581b167c93e01c9c7829 --- windows/coda/CODA/MainWindow.xaml | 21 +++++++++++++++------ windows/coda/CODA/MainWindow.xaml.cs | 16 ++++++++++++++++ 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/windows/coda/CODA/MainWindow.xaml b/windows/coda/CODA/MainWindow.xaml index 48709425f9254..7e160020deb93 100644 --- a/windows/coda/CODA/MainWindow.xaml +++ b/windows/coda/CODA/MainWindow.xaml @@ -8,13 +8,22 @@ xmlns:local="clr-namespace:CODA" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> - - + +

+ + + + + + + + + + - + - + diff --git a/windows/coda/CODA/MainWindow.xaml.cs b/windows/coda/CODA/MainWindow.xaml.cs index 89af04d48b9d2..eac2ce43afabb 100644 --- a/windows/coda/CODA/MainWindow.xaml.cs +++ b/windows/coda/CODA/MainWindow.xaml.cs @@ -11,6 +11,7 @@ using System.Windows.Threading; using Microsoft.Web.WebView2.Core; using Microsoft.Web.WebView2.Wpf; +using Microsoft.Win32; namespace CODA { @@ -149,6 +150,21 @@ private async void MainWindow_Loaded(object sender, RoutedEventArgs e) _iWebView2.CoreWebView2.WebMessageReceived += WebView_WebMessageReceived; } + private void MainWindow_FileOpen(object sender, RoutedEventArgs e) + { + OpenFileDialog openFileDialog = new OpenFileDialog(); + openFileDialog.Filter = + "Text documents|*.odt;*.docx;*.doc|" + + "Spreadsheets|*.ods;*.xlsx;*.xls|" + + "Presentations|*.odp;*.pptx;*.ppt|" + + "All files|*.*"; + + String file = ""; + if (openFileDialog.ShowDialog() == true) + file = openFileDialog.FileName; + Debug.WriteLine($"MainWindow_FileOpen: {file}"); + } + void WebView_WebMessageReceived(object sender, CoreWebView2WebMessageReceivedEventArgs args) { string s = args.WebMessageAsJson; From c97344073d668347a05374310394bfc9c618d85d Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 22 Apr 2025 14:37:07 +0200 Subject: [PATCH 149/177] coda-m: Show the state of Bold/Italics/Underline in the menu Routes the info about the command state into the app via a new "COMMANDSTATECHANGED" message and handles it accordingly. Signed-off-by: Jan Holesovsky Change-Id: I87bc3ed3c613980123fc8c61e2cead7489fe04f6 --- browser/src/layer/tile/CanvasTileLayer.js | 9 +++++- macos/coda/coda/ViewController.swift | 17 ++++++++++- macos/coda/coda/WindowController.swift | 36 +++++++++++++++-------- 3 files changed, 48 insertions(+), 14 deletions(-) diff --git a/browser/src/layer/tile/CanvasTileLayer.js b/browser/src/layer/tile/CanvasTileLayer.js index 749387b5d2592..8e97ac0993cba 100644 --- a/browser/src/layer/tile/CanvasTileLayer.js +++ b/browser/src/layer/tile/CanvasTileLayer.js @@ -2108,6 +2108,9 @@ window.L.CanvasTileLayer = window.L.Layer.extend({ // when json.commandName is '.uno:RowColSelCount'. if (json.commandName && json.state !== undefined) { this._map.fire('commandstatechanged', json); + if (window.ThisIsTheMacOSApp) { + window.postMobileMessage('COMMANDSTATECHANGED ' + JSON.stringify(json)); + } } } else if (textMsg.startsWith('.uno:Context=') && this._docType === 'presentation') { @@ -2117,7 +2120,11 @@ window.L.CanvasTileLayer = window.L.Layer.extend({ var index = textMsg.indexOf('='); var commandName = index !== -1 ? textMsg.substr(0, index) : ''; var state = index !== -1 ? textMsg.substr(index + 1) : ''; - this._map.fire('commandstatechanged', {commandName : commandName, state : state}); + const json = {commandName : commandName, state : state}; + this._map.fire('commandstatechanged', json); + if (window.ThisIsTheMacOSApp) { + window.postMobileMessage('COMMANDSTATECHANGED ' + JSON.stringify(json)); + } } }, diff --git a/macos/coda/coda/ViewController.swift b/macos/coda/coda/ViewController.swift index 4b79b943b2b5c..c4397887c4c1c 100644 --- a/macos/coda/coda/ViewController.swift +++ b/macos/coda/coda/ViewController.swift @@ -88,7 +88,22 @@ class ViewController: NSViewController, WKScriptMessageHandler, WKNavigationDele //self.bye() return } - else if body.starts(with: "MODIFIED ") { + else if body.hasPrefix("COMMANDSTATECHANGED ") { + if let brace = body.firstIndex(of: "{") { + // substring that shares storage with the original string + let jsonSlice = body[brace...] + + // convert directly to Data and decode. + let data = Data(jsonSlice.utf8) + do { + let state = try JSONDecoder().decode(CommandStateChange.self, from: data) + if let windowController = view.window?.windowController as? WindowController { + windowController.handleCommandStateChange(state) + } + } catch {} + } + } + else if body.hasPrefix("MODIFIED ") { document?.isModified = body.hasSuffix("true") return } diff --git a/macos/coda/coda/WindowController.swift b/macos/coda/coda/WindowController.swift index 3bfb75f5e35de..300d1bc7c256f 100644 --- a/macos/coda/coda/WindowController.swift +++ b/macos/coda/coda/WindowController.swift @@ -16,47 +16,59 @@ enum FormatMenuCommand: Int { case underline } -let formatMenuUnoCommands: [FormatMenuCommand: String] = [ +let formatMenuCommandNames: [FormatMenuCommand: String] = [ .bold: "Bold", .italic: "Italic", .underline: "Underline" ] +/// The structure we expect in the COMMANDSTATECHANGED payload. +struct CommandStateChange: Decodable { + let commandName: String + let state: String +} + /// Window controller that manages the document window & menus class WindowController: NSWindowController, NSMenuItemValidation { /// Track menu states here, to be able to show the state in the menu - var formatStates: [FormatMenuCommand: Bool] = [:] + var formatStates: [String: Bool] = [:] /// Single IBAction for all Format commands in the menu @IBAction func formatMenuAction(_ sender: NSMenuItem) { guard let command = FormatMenuCommand(rawValue: sender.tag) else { return } - // Toggle or otherwise update the command state - let oldVal = formatStates[command] ?? false - let newVal = !oldVal - formatStates[command] = newVal - // Forward to the ViewController so it can actually set bold/italic/... if let vc = contentViewController as? ViewController { - if let unoCommand = formatMenuUnoCommands[command] ?? nil { + if let unoCommand = formatMenuCommandNames[command] ?? nil { COWrapper.handleMessage(with: vc.document, message: "uno .uno:\(unoCommand)") } } } + /// Remember the new command state value as provided by JS. + func handleCommandStateChange(_ stateChange: CommandStateChange) { + // extract the command name from the ".uno:CommandName" form + let unoCommmandName = stateChange.commandName + guard let colon = unoCommmandName.firstIndex(of: ":") else { return } + let commandName = unoCommmandName[unoCommmandName.index(after: colon)...] + + // store it + formatStates[String(commandName)] = stateChange.state == "true" + } + /// Show on/off checkmarks for the particular command(s) like Bold/Italics/... func validateMenuItem(_ menuItem: NSMenuItem) -> Bool { if menuItem.action != #selector(formatMenuAction(_:)) { return true // not our action } - guard let command = FormatMenuCommand(rawValue: menuItem.tag) else { - return false - } + // convert the id to a command name + guard let command = FormatMenuCommand(rawValue: menuItem.tag) else { return false } + guard let commandName = formatMenuCommandNames[command] else { return false } // Show a check if the command is currently ON - let isOn = formatStates[command] ?? false + let isOn = formatStates[commandName] ?? false menuItem.state = isOn ? .on : .off return true } From f05548c370e6f7160464a7cde9fd50bed4d0b777 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Wed, 23 Apr 2025 13:03:25 +0300 Subject: [PATCH 150/177] Don't use a hardcoded document name but make the File>Open menu entry work Also, simplification and refactoring. Remove some dead C# code. Accidental leftovers from the sample code it was based on. Do use a Grid container after all for the Menu and WebView2. Seems to be the simplest way to have the Menu be the fixed height it wants to be, and the WebView2 stretch to fill the rest of the window. Signed-off-by: Tor Lillqvist Change-Id: I0ebe22b9fa87eafecc79d489674a62f4351f1358 --- windows/coda/CODA/MainWindow.xaml | 19 ++++-- windows/coda/CODA/MainWindow.xaml.cs | 94 ++++++++-------------------- windows/coda/windows.cpp | 11 ++-- 3 files changed, 45 insertions(+), 79 deletions(-) diff --git a/windows/coda/CODA/MainWindow.xaml b/windows/coda/CODA/MainWindow.xaml index 7e160020deb93..244beb84e3cfd 100644 --- a/windows/coda/CODA/MainWindow.xaml +++ b/windows/coda/CODA/MainWindow.xaml @@ -8,9 +8,13 @@ xmlns:local="clr-namespace:CODA" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> - + + + + + - + @@ -18,12 +22,15 @@ - - + + + Use the File menu to open a document + + - + diff --git a/windows/coda/CODA/MainWindow.xaml.cs b/windows/coda/CODA/MainWindow.xaml.cs index eac2ce43afabb..baa13d2475bcf 100644 --- a/windows/coda/CODA/MainWindow.xaml.cs +++ b/windows/coda/CODA/MainWindow.xaml.cs @@ -81,7 +81,7 @@ public struct pollfd { public static extern void set_send2JS_function(Send2JSDelegate f); [DllImport("CODALib.dll")] - public static extern void do_hullo_handling_things(); + public static extern void do_hullo_handling_things(String fileURL); [DllImport("CODALib.dll")] public static extern void do_bye_handling_things(); @@ -89,45 +89,6 @@ public struct pollfd { [DllImport("CODALib.dll")] public static extern void do_other_message_handling_things([MarshalAs(UnmanagedType.LPStr)] string message); - private CoreWebView2Settings _webViewSettings; - CoreWebView2Settings WebViewSettings - { - get - { - if (_webViewSettings == null && _iWebView2?.CoreWebView2 != null) - { - _webViewSettings = _iWebView2.CoreWebView2.Settings; - } - return _webViewSettings; - } - } - - CoreWebView2Environment _webViewEnvironment; - CoreWebView2Environment WebViewEnvironment - { - get - { - if (_webViewEnvironment == null && _iWebView2?.CoreWebView2 != null) - { - _webViewEnvironment = _iWebView2.CoreWebView2.Environment; - } - return _webViewEnvironment; - } - } - - CoreWebView2Profile _webViewProfile; - CoreWebView2Profile WebViewProfile - { - get - { - if (_webViewProfile == null && _iWebView2?.CoreWebView2 != null) - { - _webViewProfile = _iWebView2.CoreWebView2.Profile; - } - return _webViewProfile; - } - } - // Keep a static reference so that the delegate doesn't get garbage collected. Or something // like that. // private static Send2JSDelegate _reference; @@ -159,10 +120,8 @@ private void MainWindow_FileOpen(object sender, RoutedEventArgs e) "Presentations|*.odp;*.pptx;*.ppt|" + "All files|*.*"; - String file = ""; if (openFileDialog.ShowDialog() == true) - file = openFileDialog.FileName; - Debug.WriteLine($"MainWindow_FileOpen: {file}"); + openCOOL(_iWebView2, new Uri(openFileDialog.FileName).AbsoluteUri); } void WebView_WebMessageReceived(object sender, CoreWebView2WebMessageReceivedEventArgs args) @@ -175,7 +134,7 @@ void WebView_WebMessageReceived(object sender, CoreWebView2WebMessageReceivedEve s = s.Substring(5); if (s == "HULLO\"") { - do_hullo_handling_things(); + do_hullo_handling_things("file:///C:/Users/tml/sailing.odt"); } else if (s == "BYE\"") { @@ -204,7 +163,6 @@ void WebView_WebMessageReceived(object sender, CoreWebView2WebMessageReceivedEve private void SetWebView(IWebView2 newWebView2) { - webView2XamlElement = newWebView2 as WebView2; _iWebView2 = newWebView2; // We display the type of control in the window title, so update that now. @@ -230,7 +188,6 @@ void WebView_NavigationStarting(object sender, CoreWebView2NavigationStartingEve _isNavigating = true; CoreWebView2NavigationKind kind = e.NavigationKind; - Debug.WriteLine($"CoreWebView2_NavigationStarting: NavigationKind({kind})"); } void WebView_NavigationCompleted(object sender, CoreWebView2NavigationCompletedEventArgs e) @@ -238,30 +195,25 @@ void WebView_NavigationCompleted(object sender, CoreWebView2NavigationCompletedE _isNavigating = false; } - Action OnWebViewFirstInitialized; - - void WebView_CoreWebView2InitializationCompleted(object sender, CoreWebView2InitializationCompletedEventArgs e) + private void openCOOL(IWebView2 webView, String fileURL) { - IWebView2 webView = sender as IWebView2; - if (e.IsSuccess) - { - // FIXME: Temporarily when running from /windows/coda/CODA/bin/Debug/net8.0-windows. + useFileDialogNote.Visibility = Visibility.Collapsed; - // FIXME: Even more temporarily, just use hardcoded pathnames on tml's machine to make debugging the JS easier. - if (false) - { - webView.CoreWebView2.SetVirtualHostNameToFolderMapping("appassets", "..\\..\\..\\..\\..\\..\\browser\\dist", CoreWebView2HostResourceAccessKind.DenyCors); - webView.CoreWebView2.Navigate("https://appassets/cool.html?file_path=file:///C:/Users/tml/sailing.odt&closebutton=1&permission=edit&lang=en-US&appdocid=1&userinterfacemode=notebookbar&dir=ltr"); - } - else - { - webView.CoreWebView2.Navigate("file:///C:/Users/tml/lo/online-gitlab-coda25-coda/browser/dist/cool.html?file_path=file:///C:/Users/tml/sailing.odt&closebutton=1&permission=edit&lang=en-US&appdocid=1&userinterfacemode=notebookbar&dir=ltr"); - } + // FIXME: Temporarily when running from /windows/coda/CODA/bin/Debug/net8.0-windows. - OnWebViewFirstInitialized?.Invoke(); + // FIXME: Even more temporarily, just use hardcoded pathnames on tml's machine to make debugging the JS easier. + if (false) + { + webView.CoreWebView2.SetVirtualHostNameToFolderMapping("appassets", "..\\..\\..\\..\\..\\..\\browser\\dist", CoreWebView2HostResourceAccessKind.DenyCors); + webView.CoreWebView2.Navigate("https://appassets/cool.html?file_path=" + fileURL + "&closebutton=1&permission=edit&lang=en-US&appdocid=1&userinterfacemode=notebookbar&dir=ltr"); + } + else + { + webView.CoreWebView2.Navigate("file:///C:/Users/tml/lo/online-gitlab-coda25-coda/browser/dist/cool.html?file_path=" + fileURL + "&closebutton=1&permission=edit&lang=en-US&appdocid=1&userinterfacemode=notebookbar&dir=ltr"); + } - webView.CoreWebView2.NewWindowRequested += delegate ( - object webview2, CoreWebView2NewWindowRequestedEventArgs args) + webView.CoreWebView2.NewWindowRequested += delegate ( + object webview2, CoreWebView2NewWindowRequestedEventArgs args) { ProcessStartInfo startInfo = new ProcessStartInfo { @@ -272,10 +224,14 @@ void WebView_CoreWebView2InitializationCompleted(object sender, CoreWebView2Init Process.Start(startInfo); args.Handled = true; }; - return; - } + } - MessageBox.Show($"WebView2 creation failed with exception = {e.InitializationException}"); + void WebView_CoreWebView2InitializationCompleted(object sender, CoreWebView2InitializationCompletedEventArgs e) + { + if (e.IsSuccess) + _iWebView2.CoreWebView2.Navigate("about:blank"); + else + MessageBox.Show($"WebView2 creation failed with exception = {e.InitializationException}"); } private bool _isMessageOfType(byte[] message, string type, int lengthOfMessage) diff --git a/windows/coda/windows.cpp b/windows/coda/windows.cpp index fe8e5dacdc3a0..0ec821339d8f4 100755 --- a/windows/coda/windows.cpp +++ b/windows/coda/windows.cpp @@ -9,6 +9,7 @@ #include "windows.hpp" #include +#include #include #include @@ -22,7 +23,6 @@ int coolwsd_server_socket_fd = -1; LibreOfficeKit *lo_kit; -static std::string fileURL = "file:///C:/Users/tml/sailing.odt"; static COOLWSD *coolwsd = nullptr; static int fakeClientFd; static int closeNotificationPipeForForwardingThread[2]; @@ -86,7 +86,7 @@ void set_send2JS_function(send2JS_t f) } EXPORT -void do_hullo_handling_things() +void do_hullo_handling_things(const char *fileURL) { // FIXME: Code snippet shared with gtk/mobile.cpp, factor out into separate file. @@ -153,13 +153,16 @@ void do_hullo_handling_things() LOG_TRC_NOFILE("Actually sending to Online:" << fileURL); // Must do this in a thread, too, so that we can return to the main loop - std::thread([] + // Must duplicate fileURL as it exists only while this function is called from C#. + char *fileURLcopy = _strdup(fileURL); + std::thread([fileURLcopy] { struct pollfd pollfd; pollfd.fd = fakeClientFd; pollfd.events = POLLOUT; fakeSocketPoll(&pollfd, 1, -1); - fakeSocketWrite(fakeClientFd, fileURL.c_str(), fileURL.size()); + fakeSocketWrite(fakeClientFd, fileURLcopy, strlen(fileURLcopy)); + std::free(fileURLcopy); }).detach(); } From 89a6553273b722e2c913310c68bf9b9dfefe3e09 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Wed, 23 Apr 2025 14:33:12 +0300 Subject: [PATCH 151/177] Hide also the XAML menu once cool.html is displayed with its own menu Signed-off-by: Tor Lillqvist Change-Id: I3c63335495e8149e8d361d37bd502880f4c76218 --- windows/coda/CODA/MainWindow.xaml | 2 +- windows/coda/CODA/MainWindow.xaml.cs | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/windows/coda/CODA/MainWindow.xaml b/windows/coda/CODA/MainWindow.xaml index 244beb84e3cfd..d8ec9d4f772a6 100644 --- a/windows/coda/CODA/MainWindow.xaml +++ b/windows/coda/CODA/MainWindow.xaml @@ -13,7 +13,7 @@ - + diff --git a/windows/coda/CODA/MainWindow.xaml.cs b/windows/coda/CODA/MainWindow.xaml.cs index baa13d2475bcf..b5bd9bda19f88 100644 --- a/windows/coda/CODA/MainWindow.xaml.cs +++ b/windows/coda/CODA/MainWindow.xaml.cs @@ -120,7 +120,7 @@ private void MainWindow_FileOpen(object sender, RoutedEventArgs e) "Presentations|*.odp;*.pptx;*.ppt|" + "All files|*.*"; - if (openFileDialog.ShowDialog() == true) + if (openFileDialog.ShowDialog() == true) openCOOL(_iWebView2, new Uri(openFileDialog.FileName).AbsoluteUri); } @@ -197,7 +197,10 @@ void WebView_NavigationCompleted(object sender, CoreWebView2NavigationCompletedE private void openCOOL(IWebView2 webView, String fileURL) { + // Hide the helpful note useFileDialogNote.Visibility = Visibility.Collapsed; + // Also hide the initial menu as COOL has its own + menu.Visibility = Visibility.Collapsed; // FIXME: Temporarily when running from /windows/coda/CODA/bin/Debug/net8.0-windows. From 1e04a55804e50d30af6718b002a8ddaa1e3e6ad5 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Thu, 24 Apr 2025 13:58:34 +0200 Subject: [PATCH 152/177] coda-m: Implement printing from the application's menu From some reason, it still does not print - but the printOperation() is called and succeeds. Signed-off-by: Jan Holesovsky Change-Id: I58da464391a4a35f38968525617c1a932285b93c --- common/MobileApp.hpp | 2 +- kit/Kit.cpp | 4 +- macos/coda/coda/Base.lproj/Main.storyboard | 2 +- macos/coda/coda/COWrapper.h | 2 + macos/coda/coda/COWrapper.mm | 25 +++++++++-- macos/coda/coda/Document.swift | 40 +++++++++++++++-- macos/coda/coda/ViewController.swift | 6 +-- wsd/ClientRequestDispatcher.cpp | 51 ++++++++++++---------- 8 files changed, 93 insertions(+), 39 deletions(-) diff --git a/common/MobileApp.hpp b/common/MobileApp.hpp index b86aaa75ea1f9..4ec1bd11e0181 100644 --- a/common/MobileApp.hpp +++ b/common/MobileApp.hpp @@ -59,8 +59,8 @@ class DocumentData #ifdef IOS CODocument *coDocument; - std::weak_ptr docBroker; #endif + std::weak_ptr docBroker; }; /// Stub/Dummy WOPI types/interface. diff --git a/kit/Kit.cpp b/kit/Kit.cpp index 5de83f9a13754..82313925c8076 100644 --- a/kit/Kit.cpp +++ b/kit/Kit.cpp @@ -833,7 +833,7 @@ Document::~Document() session.second->resetDocManager(); } -#ifdef IOS +#if defined(IOS) || defined(MACOS) DocumentData::deallocate(_mobileAppDocId); #endif @@ -2081,7 +2081,7 @@ std::shared_ptr Document::load(const std::shared_ptr(duration); LOG_DBG("Returned lokit::documentLoad(" << anonymizeUrl(url) << ") in " << elapsed); -#ifdef IOS +#if defined(IOS) || defined(MACOS) DocumentData::get(_mobileAppDocId).loKitDocument = _loKitDocument.get(); { std::unique_lock docBrokersLock(DocBrokersMutex); diff --git a/macos/coda/coda/Base.lproj/Main.storyboard b/macos/coda/coda/Base.lproj/Main.storyboard index 1365a3f9110dc..89b2e59cf49c7 100644 --- a/macos/coda/coda/Base.lproj/Main.storyboard +++ b/macos/coda/coda/Base.lproj/Main.storyboard @@ -112,7 +112,7 @@ - + diff --git a/macos/coda/coda/COWrapper.h b/macos/coda/coda/COWrapper.h index 23622ae51f23b..9bfc9b1a9ed6b 100644 --- a/macos/coda/coda/COWrapper.h +++ b/macos/coda/coda/COWrapper.h @@ -21,7 +21,9 @@ + (void)handleHULLOWithDocument:(Document *)document; + (void)handleMessageWith:(Document *)document message:(NSString *)message; ++ (void)saveAsWith:(Document *)document url:(NSString *)url format:(NSString *)format filterOptions:(NSString *)filterOptions; ++ (int)generateNewAppDocId; + (int)fakeSocketSocket; + (void)LOG_DBG:(NSString *)message NS_SWIFT_NAME(LOG_DBG(_:)); diff --git a/macos/coda/coda/COWrapper.mm b/macos/coda/coda/COWrapper.mm index 61973f75ef845..a8da8f625936b 100644 --- a/macos/coda/coda/COWrapper.mm +++ b/macos/coda/coda/COWrapper.mm @@ -19,10 +19,11 @@ // Include necessary C++ headers #include #include -#include "Log.hpp" -#include "Util.hpp" #include "COOLWSD.hpp" #include "FakeSocket.hpp" +#include "Log.hpp" +#include "MobileApp.hpp" +#include "Util.hpp" // Declare the coolwsd pointer at global scope COOLWSD *coolwsd = nullptr; @@ -143,7 +144,9 @@ + (void)handleHULLOWithDocument:(Document *)document { p.events = POLLOUT; fakeSocketPoll(&p, 1, -1); - fakeSocketWrite(document.fakeClientFd, url.c_str(), url.size()); + // appDocId is read in ClientRequestDispatcher::handleIncomingMessage() in COOLWSD.cpp + std::string message(url + " " + std::to_string(document.appDocId)); + fakeSocketWrite(document.fakeClientFd, message.c_str(), message.size()); } + (void)handleMessageWith:(Document *)document message:(NSString *)message { @@ -155,6 +158,22 @@ + (void)handleMessageWith:(Document *)document message:(NSString *)message { fakeSocketWrite(document.fakeClientFd, buf, strlen(buf)); } ++ (void)saveAsWith:(Document *)document url:(NSString *)url format:(NSString *)format filterOptions:(NSString *)filterOptions { + DocumentData::get(document.appDocId).loKitDocument->saveAs([url UTF8String], [format UTF8String], [filterOptions UTF8String]); +} + +/** + * We keep a running count of opening documents here. This is not necessarily in sync with the + * DocBrokerId in DocumentBroker due to potential parallelism when opening multiple documents in + * quick succession. + */ +static std::atomic appDocIdCounter(1); + ++ (int)generateNewAppDocId { + DocumentData::allocate(appDocIdCounter); + return appDocIdCounter++; +} + + (int)fakeSocketSocket { return fakeSocketSocket(); } diff --git a/macos/coda/coda/Document.swift b/macos/coda/coda/Document.swift index 6a6d2a6637b20..e114150fe8c15 100644 --- a/macos/coda/coda/Document.swift +++ b/macos/coda/coda/Document.swift @@ -9,6 +9,7 @@ */ import Cocoa +import PDFKit import WebKit /** @@ -22,8 +23,9 @@ class Document: NSDocument { @objc var fakeClientFd: Int32 = -1 - /// Currently unused - private var appDocId: Int = -1 + /// ID to identify the document to be able to get access to lok::Document (eg. for printing) + @objc + var appDocId: Int32 = -1 /// Is this a read-only document? private var readOnly: Bool = false @@ -173,6 +175,37 @@ class Document: NSDocument { self.tempFileURL = tempFile } + /** + * Implement printing. + */ + override func printOperation(withSettings printSettings: [NSPrintInfo.AttributeKey : Any]) throws -> NSPrintOperation { + // export to a temporary PDF file + let tmpURL = FileManager.default + .temporaryDirectory + .appendingPathComponent(UUID().uuidString) + .appendingPathExtension("pdf") + + COWrapper.saveAs(with: self, url: tmpURL.absoluteString, format: "pdf", filterOptions: nil) + + // load the PDF into a PDFView + guard let pdfDoc = PDFDocument(url: tmpURL) else { + throw CocoaError(.fileReadCorruptFile, userInfo: [NSURLErrorKey: tmpURL]) + } + + // we no longer need the file + try? FileManager.default.removeItem(at: tmpURL) + + // build the printing view and operation + let pdfView = PDFView() + pdfView.document = pdfDoc + pdfView.autoScales = true + + let op = NSPrintOperation(view: pdfView, printInfo: self.printInfo) + op.showsPrintPanel = true + op.showsProgressPanel = true + return op + } + /** * Clean up the temporary directory when the document closes. */ @@ -190,8 +223,7 @@ class Document: NSDocument { self.webView = webView self.readOnly = readOnly - self.appDocId = 1 - + self.appDocId = COWrapper.generateNewAppDocId() self.fakeClientFd = COWrapper.fakeSocketSocket() guard let url = Bundle.main.url(forResource: "cool", withExtension: "html") else { diff --git a/macos/coda/coda/ViewController.swift b/macos/coda/coda/ViewController.swift index c4397887c4c1c..0583f1ff474bd 100644 --- a/macos/coda/coda/ViewController.swift +++ b/macos/coda/coda/ViewController.swift @@ -174,10 +174,8 @@ class ViewController: NSViewController, WKScriptMessageHandler, WKNavigationDele COWrapper.LOG_ERR("TODO: Implement PRINT") /* // Create the PDF to print - // You'll need to wrap the C++ functions used here - // Example: - // let printFile = FileUtil.createRandomTmpDir() + "/print.pdf" - // let printURL = URL(fileURLWithPath: printFile) + let printFile = FileUtil.createRandomTmpDir() + "/print.pdf" + let printURL = URL(fileURLWithPath: printFile) // DocumentData.get(self.document.appDocId).loKitDocument.saveAs(printURL.absoluteString, "pdf", nil) // Present the print panel diff --git a/wsd/ClientRequestDispatcher.cpp b/wsd/ClientRequestDispatcher.cpp index ce0b1497dab05..7a21c2d69af23 100644 --- a/wsd/ClientRequestDispatcher.cpp +++ b/wsd/ClientRequestDispatcher.cpp @@ -861,36 +861,39 @@ void ClientRequestDispatcher::handleIncomingMessage(SocketDisposition& dispositi #else // !MOBILEAPP Poco::Net::HTTPRequest request; -#ifdef IOS // The URL of the document is sent over the FakeSocket by the code in // -[DocumentViewController userContentController:didReceiveScriptMessage:] when it gets the // HULLO message from the JavaScript in global.js. - // The "app document id", the numeric id of the document, from the appDocIdCounter in CODocument.mm. + // The "app document id", the numeric id of the document, from the appDocIdCounter + // It's currently relevant only for iOS and macOS, so fallback if it is not found char* space = strchr(socket->getInBuffer().data(), ' '); - assert(space != nullptr); - - // The socket buffer is not nul-terminated so we can't just call strtoull() on the number at - // its end, it might be followed in memory by more digits. Is there really no better way to - // parse the number at the end of the buffer than to copy the bytes into a nul-terminated - // buffer? - const size_t appDocIdLen = + if (space != nullptr) + { + // The socket buffer is not nul-terminated so we can't just call strtoull() on the number at + // its end, it might be followed in memory by more digits. Is there really no better way to + // parse the number at the end of the buffer than to copy the bytes into a nul-terminated + // buffer? + const size_t appDocIdLen = (socket->getInBuffer().data() + socket->getInBuffer().size()) - (space + 1); - char* appDocIdBuffer = (char*)malloc(appDocIdLen + 1); - memcpy(appDocIdBuffer, space + 1, appDocIdLen); - appDocIdBuffer[appDocIdLen] = '\0'; - unsigned appDocId = std::strtoul(appDocIdBuffer, nullptr, 10); - free(appDocIdBuffer); - - handleClientWsUpgrade( - request, std::string(socket->getInBuffer().data(), space - socket->getInBuffer().data()), - disposition, socket, appDocId); -#else // IOS - handleClientWsUpgrade( - request, - RequestDetails(std::string(socket->getInBuffer().data(), socket->getInBuffer().size())), - disposition, socket); -#endif // !IOS + char* appDocIdBuffer = (char*)malloc(appDocIdLen + 1); + memcpy(appDocIdBuffer, space + 1, appDocIdLen); + appDocIdBuffer[appDocIdLen] = '\0'; + unsigned appDocId = static_cast(std::strtoul(appDocIdBuffer, nullptr, 10)); + free(appDocIdBuffer); + + handleClientWsUpgrade( + request, std::string(socket->getInBuffer().data(), space - socket->getInBuffer().data()), + disposition, socket, appDocId); + } + else + { + // no appDocId provided + handleClientWsUpgrade( + request, + RequestDetails(std::string(socket->getInBuffer().data(), socket->getInBuffer().size())), + disposition, socket); + } socket->getInBuffer().clear(); #endif // MOBILEAPP } From 16e34b6847c9552605d6f00babedefc36713136a Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Thu, 24 Apr 2025 16:59:12 +0200 Subject: [PATCH 153/177] coda-m: Trigger printing also from the notebookbar Signed-off-by: Jan Holesovsky Change-Id: If18b22efdf6b0fb6e518424fddc551d41a508cfa --- browser/src/control/Toolbar.js | 2 +- macos/coda/coda/ViewController.swift | 23 +---------------------- 2 files changed, 2 insertions(+), 23 deletions(-) diff --git a/browser/src/control/Toolbar.js b/browser/src/control/Toolbar.js index 3b514a173c537..0c36289eee949 100644 --- a/browser/src/control/Toolbar.js +++ b/browser/src/control/Toolbar.js @@ -260,7 +260,7 @@ window.L.Map.include({ }, print: function (options) { - if (window.ThisIsTheiOSApp || window.ThisIsTheAndroidApp) { + if (window.ThisIsTheiOSApp || window.ThisIsTheAndroidApp || window.ThisIsTheMacOSApp) { window.postMobileMessage('PRINT'); } else { this.showBusy(_('Downloading...'), false); diff --git a/macos/coda/coda/ViewController.swift b/macos/coda/coda/ViewController.swift index 0583f1ff474bd..adf39bf0804d3 100644 --- a/macos/coda/coda/ViewController.swift +++ b/macos/coda/coda/ViewController.swift @@ -171,28 +171,7 @@ class ViewController: NSViewController, WKScriptMessageHandler, WKNavigationDele return } else if body == "PRINT" { - COWrapper.LOG_ERR("TODO: Implement PRINT") - /* - // Create the PDF to print - let printFile = FileUtil.createRandomTmpDir() + "/print.pdf" - let printURL = URL(fileURLWithPath: printFile) - // DocumentData.get(self.document.appDocId).loKitDocument.saveAs(printURL.absoluteString, "pdf", nil) - - // Present the print panel - let printInfo = NSPrintInfo.shared - printInfo.jobName = "Document" // Adjust as needed - let printOperation = NSPrintOperation(view: self.webView) // Adjust view as needed - printOperation.printInfo = printInfo - printOperation.run() - - // Remove the temporary print file if needed - // do { - // try FileManager.default.removeItem(at: printURL) - // } catch { - // LOG_ERR("Failed to remove print file: \(error)") - // } - */ - + document.printDocument(self) return } else if body == "FOCUSIFHWKBD" { From 7fa614d5ea86ccd43d0903d2e1e0c2ed3ebfa582 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Mon, 28 Apr 2025 10:52:24 +0300 Subject: [PATCH 154/177] Add File>Quit Also use a more verbose name in XAML for the menu bar. Signed-off-by: Tor Lillqvist Change-Id: I516d0affd4cd7ba32dba2e26d6ccf0452578a7d0 --- windows/coda/CODA/MainWindow.xaml | 8 +++----- windows/coda/CODA/MainWindow.xaml.cs | 9 +++++++-- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/windows/coda/CODA/MainWindow.xaml b/windows/coda/CODA/MainWindow.xaml index d8ec9d4f772a6..38ba5797e55ea 100644 --- a/windows/coda/CODA/MainWindow.xaml +++ b/windows/coda/CODA/MainWindow.xaml @@ -13,18 +13,16 @@ - + - - - + - + Use the File menu to open a document diff --git a/windows/coda/CODA/MainWindow.xaml.cs b/windows/coda/CODA/MainWindow.xaml.cs index b5bd9bda19f88..849ea0c37484f 100644 --- a/windows/coda/CODA/MainWindow.xaml.cs +++ b/windows/coda/CODA/MainWindow.xaml.cs @@ -124,6 +124,11 @@ private void MainWindow_FileOpen(object sender, RoutedEventArgs e) openCOOL(_iWebView2, new Uri(openFileDialog.FileName).AbsoluteUri); } + private void MainWindow_Exit(object sender, RoutedEventArgs e) + { + System.Windows.Application.Current.Shutdown(); + } + void WebView_WebMessageReceived(object sender, CoreWebView2WebMessageReceivedEventArgs args) { string s = args.WebMessageAsJson; @@ -198,9 +203,9 @@ void WebView_NavigationCompleted(object sender, CoreWebView2NavigationCompletedE private void openCOOL(IWebView2 webView, String fileURL) { // Hide the helpful note - useFileDialogNote.Visibility = Visibility.Collapsed; + useFileDialogXamlElement.Visibility = Visibility.Collapsed; // Also hide the initial menu as COOL has its own - menu.Visibility = Visibility.Collapsed; + menuXamlElement.Visibility = Visibility.Collapsed; // FIXME: Temporarily when running from /windows/coda/CODA/bin/Debug/net8.0-windows. From e350d0a5b497164ac418e7c4d9e2f2c51f538015 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Mon, 28 Apr 2025 18:17:41 +0300 Subject: [PATCH 155/177] Send the PRINT message also in the CODA-W case Signed-off-by: Tor Lillqvist Change-Id: Ibd7c0be4f02a9974871588e0a9fb1a5efb957842 --- browser/src/control/Toolbar.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/browser/src/control/Toolbar.js b/browser/src/control/Toolbar.js index 0c36289eee949..539719ec02b43 100644 --- a/browser/src/control/Toolbar.js +++ b/browser/src/control/Toolbar.js @@ -260,7 +260,7 @@ window.L.Map.include({ }, print: function (options) { - if (window.ThisIsTheiOSApp || window.ThisIsTheAndroidApp || window.ThisIsTheMacOSApp) { + if (window.ThisIsTheiOSApp || window.ThisIsTheAndroidApp || window.ThisIsTheMacOSApp || window.ThisIsTheWindowsApp) { window.postMobileMessage('PRINT'); } else { this.showBusy(_('Downloading...'), false); From 20dbff23edd7fe1d8e7897cb90792becca2b0473 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Tue, 29 Apr 2025 10:29:08 +0300 Subject: [PATCH 156/177] Drop unused KitWebSocketHandler::getKitId() The term "kit id" is not used for anything as far as I can see. Signed-off-by: Tor Lillqvist Change-Id: Iefcf9a5a6a6337758fad73c02cda9989efd4b0e3 --- kit/KitWebSocket.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/kit/KitWebSocket.hpp b/kit/KitWebSocket.hpp index fc4d59a558a18..459ec783a9ce7 100644 --- a/kit/KitWebSocket.hpp +++ b/kit/KitWebSocket.hpp @@ -51,8 +51,6 @@ class KitWebSocketHandler final : public WebSocketHandler void shutdownForBackgroundSave(); - int getKitId() const { return _mobileAppDocId; } - protected: virtual void handleMessage(const std::vector& data) override; virtual void enableProcessInput(bool enable = true) override; From f351bf4267dc0c7ef72e9d1ec9b11dcf3c89c11e Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Tue, 29 Apr 2025 13:26:43 +0300 Subject: [PATCH 157/177] Fix comment ClientRequestDispatcher::handleIncomingMessage() is not in COOLWSD.cpp. Signed-off-by: Tor Lillqvist Change-Id: I994de2f256988c7428ec44204b58f98e0bbf3ca8 --- ios/Mobile/DocumentViewController.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/Mobile/DocumentViewController.mm b/ios/Mobile/DocumentViewController.mm index bd37341273102..72fe01811ff09 100644 --- a/ios/Mobile/DocumentViewController.mm +++ b/ios/Mobile/DocumentViewController.mm @@ -594,7 +594,7 @@ - (void)userContentController:(WKUserContentController *)userContentController d p.events = POLLOUT; fakeSocketPoll(&p, 1, -1); - // This is read in the iOS-specific code in ClientRequestDispatcher::handleIncomingMessage() in COOLWSD.cpp + // This is read in the code in ClientRequestDispatcher::handleIncomingMessage() std::string message(url + " " + std::to_string(self.document->appDocId)); fakeSocketWrite(self.document->fakeClientFd, message.c_str(), message.size()); From c37b0e75cb42fe914f20b25a8d575f542dd6d0f4 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Tue, 29 Apr 2025 13:54:54 +0300 Subject: [PATCH 158/177] Improve the "app document id" handling in CODA-W Also drop a leftover use of the old fixed document pathname. It turned out that it was actually that use of the fixed document that had mattered... I had left that file existing, so the code still seemed to work. And the document I tried to open from the file selector when experimenting was just a copy of the same document, so I did not notice. Oh well. Signed-off-by: Tor Lillqvist Change-Id: I0349809135c21a0e55c10db4f932bba517ef8ad6 --- kit/Kit.cpp | 4 +-- windows/coda/CODA/MainWindow.xaml.cs | 43 +++++++++++++++++----------- windows/coda/windows.cpp | 21 ++++++++++++-- wsd/ClientRequestDispatcher.cpp | 2 +- 4 files changed, 47 insertions(+), 23 deletions(-) diff --git a/kit/Kit.cpp b/kit/Kit.cpp index 82313925c8076..592caa4b05f21 100644 --- a/kit/Kit.cpp +++ b/kit/Kit.cpp @@ -833,7 +833,7 @@ Document::~Document() session.second->resetDocManager(); } -#if defined(IOS) || defined(MACOS) +#if defined(IOS) || defined(MACOS) || defined(_WIN32) DocumentData::deallocate(_mobileAppDocId); #endif @@ -2081,7 +2081,7 @@ std::shared_ptr Document::load(const std::shared_ptr(duration); LOG_DBG("Returned lokit::documentLoad(" << anonymizeUrl(url) << ") in " << elapsed); -#if defined(IOS) || defined(MACOS) +#if defined(IOS) || defined(MACOS) || defined(_WIN32) DocumentData::get(_mobileAppDocId).loKitDocument = _loKitDocument.get(); { std::unique_lock docBrokersLock(DocBrokersMutex); diff --git a/windows/coda/CODA/MainWindow.xaml.cs b/windows/coda/CODA/MainWindow.xaml.cs index 849ea0c37484f..b73cc24ed4922 100644 --- a/windows/coda/CODA/MainWindow.xaml.cs +++ b/windows/coda/CODA/MainWindow.xaml.cs @@ -35,6 +35,9 @@ public struct pollfd { [DllImport("CODALib.dll")] public static extern int set_coolwsd_server_socket_fd(int fd); + [DllImport("CODALib.dll")] + public static extern int generate_new_app_doc_id(); + [DllImport("CODALib.dll")] public static extern int fakeSocketSocket(); @@ -81,7 +84,7 @@ public struct pollfd { public static extern void set_send2JS_function(Send2JSDelegate f); [DllImport("CODALib.dll")] - public static extern void do_hullo_handling_things(String fileURL); + public static extern void do_hullo_handling_things(String fileURL, int appDocId); [DllImport("CODALib.dll")] public static extern void do_bye_handling_things(); @@ -94,6 +97,10 @@ public struct pollfd { // private static Send2JSDelegate _reference; private static GCHandle _gch; + private int _appDocId = -1; + + private String _fileURL; + public MainWindow() { Loaded += MainWindow_Loaded; @@ -121,7 +128,11 @@ private void MainWindow_FileOpen(object sender, RoutedEventArgs e) "All files|*.*"; if (openFileDialog.ShowDialog() == true) - openCOOL(_iWebView2, new Uri(openFileDialog.FileName).AbsoluteUri); + { + _appDocId = generate_new_app_doc_id(); + _fileURL = new Uri(openFileDialog.FileName).AbsoluteUri; + openCOOL(); + } } private void MainWindow_Exit(object sender, RoutedEventArgs e) @@ -139,12 +150,20 @@ void WebView_WebMessageReceived(object sender, CoreWebView2WebMessageReceivedEve s = s.Substring(5); if (s == "HULLO\"") { - do_hullo_handling_things("file:///C:/Users/tml/sailing.odt"); + do_hullo_handling_things(_fileURL, _appDocId); } else if (s == "BYE\"") { do_bye_handling_things(); } + else if (s == "PRINT\"") + { + Debug.WriteLine("Not yet implemented: Print"); + } + else if (s.StartsWith("downloadas ")) + { + Debug.WriteLine("Not yet implemented: Save As"); + } else { string message = JsonSerializer.Deserialize(args.WebMessageAsJson); @@ -200,27 +219,17 @@ void WebView_NavigationCompleted(object sender, CoreWebView2NavigationCompletedE _isNavigating = false; } - private void openCOOL(IWebView2 webView, String fileURL) + private void openCOOL() { // Hide the helpful note useFileDialogXamlElement.Visibility = Visibility.Collapsed; // Also hide the initial menu as COOL has its own menuXamlElement.Visibility = Visibility.Collapsed; - // FIXME: Temporarily when running from /windows/coda/CODA/bin/Debug/net8.0-windows. - - // FIXME: Even more temporarily, just use hardcoded pathnames on tml's machine to make debugging the JS easier. - if (false) - { - webView.CoreWebView2.SetVirtualHostNameToFolderMapping("appassets", "..\\..\\..\\..\\..\\..\\browser\\dist", CoreWebView2HostResourceAccessKind.DenyCors); - webView.CoreWebView2.Navigate("https://appassets/cool.html?file_path=" + fileURL + "&closebutton=1&permission=edit&lang=en-US&appdocid=1&userinterfacemode=notebookbar&dir=ltr"); - } - else - { - webView.CoreWebView2.Navigate("file:///C:/Users/tml/lo/online-gitlab-coda25-coda/browser/dist/cool.html?file_path=" + fileURL + "&closebutton=1&permission=edit&lang=en-US&appdocid=1&userinterfacemode=notebookbar&dir=ltr"); - } + // FIXME: Temporarily, just use hardcoded pathnames on tml's machine to make debugging the JS easier. + _iWebView2.CoreWebView2.Navigate("file:///C:/Users/tml/lo/online-gitlab-coda25-coda/browser/dist/cool.html?file_path=" + _fileURL + "&closebutton=1&permission=edit&lang=en-US&appdocid=" + _appDocId + "&userinterfacemode=notebookbar&dir=ltr"); - webView.CoreWebView2.NewWindowRequested += delegate ( + _iWebView2.CoreWebView2.NewWindowRequested += delegate ( object webview2, CoreWebView2NewWindowRequestedEventArgs args) { ProcessStartInfo startInfo = new ProcessStartInfo diff --git a/windows/coda/windows.cpp b/windows/coda/windows.cpp index 0ec821339d8f4..0726c5c5e1820 100755 --- a/windows/coda/windows.cpp +++ b/windows/coda/windows.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -44,6 +45,19 @@ int set_coolwsd_server_socket_fd(int fd) return fd; } +EXPORT +int generate_new_app_doc_id() +{ + // Start with a random document id to catch code that might assume it to be some fixed value, + // like 0 or 1. Also make it obvious that this numeric "app doc id", used by the mobile apps and + // CODA, is not related to the string document ids (usually with several leading zeroes) used in + // the C++ bits of normal COOL. + static int appDocId = 42 + (std::time(nullptr) % 100); + + DocumentData::allocate(appDocId); + return appDocId++; +} + EXPORT void initialize_cpp_things() { @@ -86,7 +100,7 @@ void set_send2JS_function(send2JS_t f) } EXPORT -void do_hullo_handling_things(const char *fileURL) +void do_hullo_handling_things(const char *fileURL, int appDocId) { // FIXME: Code snippet shared with gtk/mobile.cpp, factor out into separate file. @@ -155,13 +169,14 @@ void do_hullo_handling_things(const char *fileURL) // Must do this in a thread, too, so that we can return to the main loop // Must duplicate fileURL as it exists only while this function is called from C#. char *fileURLcopy = _strdup(fileURL); - std::thread([fileURLcopy] + std::thread([fileURLcopy, appDocId] { struct pollfd pollfd; pollfd.fd = fakeClientFd; pollfd.events = POLLOUT; fakeSocketPoll(&pollfd, 1, -1); - fakeSocketWrite(fakeClientFd, fileURLcopy, strlen(fileURLcopy)); + std::string message(fileURLcopy + (" " + std::to_string(appDocId))); + fakeSocketWrite(fakeClientFd, message.c_str(), message.size()); std::free(fileURLcopy); }).detach(); } diff --git a/wsd/ClientRequestDispatcher.cpp b/wsd/ClientRequestDispatcher.cpp index 7a21c2d69af23..b85e7d066cc76 100644 --- a/wsd/ClientRequestDispatcher.cpp +++ b/wsd/ClientRequestDispatcher.cpp @@ -866,7 +866,7 @@ void ClientRequestDispatcher::handleIncomingMessage(SocketDisposition& dispositi // HULLO message from the JavaScript in global.js. // The "app document id", the numeric id of the document, from the appDocIdCounter - // It's currently relevant only for iOS and macOS, so fallback if it is not found + // It's currently relevant only for iOS, macOS, and Windows, so fallback if it is not found char* space = strchr(socket->getInBuffer().data(), ' '); if (space != nullptr) { From dc57e68ba77fb880a0f5a62b8a01438342946f96 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 28 Apr 2025 15:10:55 +0200 Subject: [PATCH 159/177] coda-m: Make the printing work The crucial part is the coda.entitlements; but the simplification of the printing part helps too. Signed-off-by: Jan Holesovsky Change-Id: Id9b412d3e56457b3252796101b82693cbc803f50 --- macos/coda/coda/Document.swift | 12 ++++-------- macos/coda/coda/coda.entitlements | 2 ++ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/macos/coda/coda/Document.swift b/macos/coda/coda/Document.swift index e114150fe8c15..6a0b40a455184 100644 --- a/macos/coda/coda/Document.swift +++ b/macos/coda/coda/Document.swift @@ -188,21 +188,17 @@ class Document: NSDocument { COWrapper.saveAs(with: self, url: tmpURL.absoluteString, format: "pdf", filterOptions: nil) // load the PDF into a PDFView - guard let pdfDoc = PDFDocument(url: tmpURL) else { + guard let pdfDocument = PDFDocument(url: tmpURL) else { throw CocoaError(.fileReadCorruptFile, userInfo: [NSURLErrorKey: tmpURL]) } // we no longer need the file try? FileManager.default.removeItem(at: tmpURL) - // build the printing view and operation - let pdfView = PDFView() - pdfView.document = pdfDoc - pdfView.autoScales = true + guard let op = pdfDocument.printOperation(for: self.printInfo, scalingMode: .pageScaleNone, autoRotate: true) else { + throw CocoaError(.fileReadCorruptFile, userInfo: [NSURLErrorKey: tmpURL]) + } - let op = NSPrintOperation(view: pdfView, printInfo: self.printInfo) - op.showsPrintPanel = true - op.showsProgressPanel = true return op } diff --git a/macos/coda/coda/coda.entitlements b/macos/coda/coda/coda.entitlements index 3890e5fb34708..d0a021865287e 100644 --- a/macos/coda/coda/coda.entitlements +++ b/macos/coda/coda/coda.entitlements @@ -14,5 +14,7 @@ com.apple.security.network.server + com.apple.security.print + From d588d4dc53247f7654eb93f33c9174dbcd37a0f7 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 28 Apr 2025 16:30:14 +0200 Subject: [PATCH 160/177] coda-m: Avoid executables from core & limit resulting architecture Signed-off-by: Jan Holesovsky Change-Id: I403e6cabff25495eae0bdc39819bf85b45722ba9 --- macos/coda/coda.xcodeproj/project.pbxproj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/macos/coda/coda.xcodeproj/project.pbxproj b/macos/coda/coda.xcodeproj/project.pbxproj index 9143f53395271..6caa532640c92 100644 --- a/macos/coda/coda.xcodeproj/project.pbxproj +++ b/macos/coda/coda.xcodeproj/project.pbxproj @@ -569,7 +569,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "# Copy lokit to the bundle\nif [ -z \"$LO_PATH\" ]; then\n echo \"Error: LO_PATH is not set. Please configure it in Config.xcconfig.\"\n exit 1\nfi\n\necho \"Copying $LO_PATH/Contents/ to ${CONFIGURATION_BUILD_DIR}/${TARGET_NAME}.app/Contents/lokit/\"\nrsync -avz $LO_PATH/Contents/ ${CONFIGURATION_BUILD_DIR}/${TARGET_NAME}.app/Contents/lokit/\n"; + shellScript = "# Copy lokit to the bundle\nif [ -z \"$LO_PATH\" ]; then\n echo \"Error: LO_PATH is not set. Please configure it in Config.xcconfig.\"\n exit 1\nfi\n\necho \"Copying $LO_PATH/Contents/ to ${CONFIGURATION_BUILD_DIR}/${TARGET_NAME}.app/Contents/lokit/\"\nrsync -avz --exclude=\"**/gengal\" --exclude=\"**/opencltest\" --exclude=\"**/soffice\" --exclude=\"**/uno\" --exclude=\"**/unopkg\" --exclude=\"**/uri-encode\" --exclude=\"**/QuickLookPreview.appex\" --exclude=\"**/QuickLookThumbnail.appex\" $LO_PATH/Contents/ ${CONFIGURATION_BUILD_DIR}/${TARGET_NAME}.app/Contents/lokit/\n"; }; /* End PBXShellScriptBuildPhase section */ @@ -879,6 +879,7 @@ ENABLE_APP_SANDBOX = NO; ENABLE_HARDENED_RUNTIME = NO; ENABLE_USER_SCRIPT_SANDBOXING = NO; + EXCLUDED_ARCHS = x86_64; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = coda/Info.plist; INFOPLIST_KEY_NSHumanReadableCopyright = ""; From 1cb32cb8a8b9b1540ed2142b381840b1bdb40240 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 29 Apr 2025 15:22:57 +0200 Subject: [PATCH 161/177] coda-m: Enable Hardened runtime, to be able to build a package Signed-off-by: Jan Holesovsky Change-Id: I9a0ca417e90ac61ef96f3121744870dc07ab3074 --- macos/coda/coda.xcodeproj/project.pbxproj | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/macos/coda/coda.xcodeproj/project.pbxproj b/macos/coda/coda.xcodeproj/project.pbxproj index 6caa532640c92..dd1545710ec2a 100644 --- a/macos/coda/coda.xcodeproj/project.pbxproj +++ b/macos/coda/coda.xcodeproj/project.pbxproj @@ -822,12 +822,13 @@ ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = coda/coda.entitlements; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = J4FQ687VJK; ENABLE_APP_SANDBOX = NO; - ENABLE_HARDENED_RUNTIME = NO; + ENABLE_HARDENED_RUNTIME = YES; ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = coda/Info.plist; @@ -872,12 +873,13 @@ ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = coda/coda.entitlements; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = J4FQ687VJK; ENABLE_APP_SANDBOX = NO; - ENABLE_HARDENED_RUNTIME = NO; + ENABLE_HARDENED_RUNTIME = YES; ENABLE_USER_SCRIPT_SANDBOXING = NO; EXCLUDED_ARCHS = x86_64; GENERATE_INFOPLIST_FILE = YES; From 4b9601fb0ec094ee3dd0f4a7338458590d6040cb Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Tue, 29 Apr 2025 23:28:15 +0300 Subject: [PATCH 162/177] Implement File > Print in CODA-W The hardest part was figuring out how to print a PDF file in C#. In the end, once I found useful advice, it was not that hard. For some reason, to be able to use the APIs used by the new code, I have to mark the app as "using Windows Forms", go figure. And mark the TargetFramework as one on Windows 10. That then meant I have to specify which type I meant in some cases where a type with the same name, like Application and OpenFileDialog, exists in two places. Quite possibly am I doing something wrong, and things can be cleaned up. Later. Also, clean out unused code from the C#. For instance I don't call the fakeSocket* functions from C# after all, so those DllImport declarations could go away. Signed-off-by: Tor Lillqvist Change-Id: Ic4d86a0c1a1831956c96994d32776d585e54e523 --- windows/coda/CODA/App.xaml.cs | 2 +- windows/coda/CODA/CODA.csproj | 3 +- windows/coda/CODA/MainWindow.xaml.cs | 151 +++++++++++++++------------ windows/coda/CODALib/CODALib.vcxproj | 4 +- windows/coda/windows.cpp | 12 +++ 5 files changed, 100 insertions(+), 72 deletions(-) diff --git a/windows/coda/CODA/App.xaml.cs b/windows/coda/CODA/App.xaml.cs index 70cf1fbe116d7..9f408b112e570 100644 --- a/windows/coda/CODA/App.xaml.cs +++ b/windows/coda/CODA/App.xaml.cs @@ -4,7 +4,7 @@ namespace CODA { - public partial class App : Application + public partial class App : System.Windows.Application { } diff --git a/windows/coda/CODA/CODA.csproj b/windows/coda/CODA/CODA.csproj index b79ed0dc7ce2f..a5d29be710bc7 100644 --- a/windows/coda/CODA/CODA.csproj +++ b/windows/coda/CODA/CODA.csproj @@ -2,11 +2,12 @@ WinExe - net8.0-windows + net8.0-windows10.0.19041.0 enable enable true CODA.App + True diff --git a/windows/coda/CODA/MainWindow.xaml.cs b/windows/coda/CODA/MainWindow.xaml.cs index b73cc24ed4922..697947acfdc2b 100644 --- a/windows/coda/CODA/MainWindow.xaml.cs +++ b/windows/coda/CODA/MainWindow.xaml.cs @@ -1,9 +1,11 @@ // -*- tab-width: 4; indent-tabs-mode: nil; fill-column: 100 -*- using System; +using System.Collections.Generic; using System.Diagnostics; -using System.Linq; +using System.Drawing.Printing; using System.Runtime.InteropServices; +using System.IO; using System.Text; using System.Text.Json; using System.Threading.Tasks; @@ -17,17 +19,10 @@ namespace CODA { public partial class MainWindow : Window { - public struct pollfd { - public int fd; - public short events; - public short revents; - }; - private IWebView2 _iWebView2; - private bool _isNavigating = false; - public delegate void Send2JSDelegate(IntPtr buffer, int length); + public delegate void ReplyWithStringDelegate(string s); [DllImport("CODALib.dll")] public static extern int get_coolwsd_server_socket_fd(); @@ -38,45 +33,6 @@ public struct pollfd { [DllImport("CODALib.dll")] public static extern int generate_new_app_doc_id(); - [DllImport("CODALib.dll")] - public static extern int fakeSocketSocket(); - - [DllImport("CODALib.dll")] - public static extern int fakeSocketPipe2(int[] pipefds); - - [DllImport("CODALib.dll")] - public static extern int fakeSocketPoll(pollfd[] fds, int nfds, int timeout); - - [DllImport("CODALib.dll")] - public static extern int fakeSocketListen(int fd); - - [DllImport("CODALib.dll")] - public static extern int fakeSocketConnect(int fd1, int fd2); - - [DllImport("CODALib.dll")] - public static extern int fakeSocketAccept4(int fd); - - [DllImport("CODALib.dll")] - public static extern int fakeSocketPeer(int fd); - - [DllImport("CODALib.dll")] - public static extern long fakeSocketAvailableDataLength(int fd); - - [DllImport("CODALib.dll")] - public static extern long fakeSocketRead(int fd, byte[] buf, long nbytes); - - [DllImport("CODALib.dll")] - public static extern long fakeSocketWrite(int fd, byte[] buf, long nbytes); - - [DllImport("CODALib.dll")] - public static extern long fakeSocketShutdown(int fd); - - [DllImport("CODALib.dll")] - public static extern long fakeSocketClose(int fd); - - [DllImport("CODALib.dll")] - public static extern long fakeSocketDumpState(); - [DllImport("CODALib.dll")] public static extern void initialize_cpp_things(); @@ -84,11 +40,14 @@ public struct pollfd { public static extern void set_send2JS_function(Send2JSDelegate f); [DllImport("CODALib.dll")] - public static extern void do_hullo_handling_things(String fileURL, int appDocId); + public static extern void do_hullo_handling_things(string fileURL, int appDocId); [DllImport("CODALib.dll")] public static extern void do_bye_handling_things(); + [DllImport("CODALib.dll")] + public static extern void do_convert_to(string type, int appDocId, ReplyWithStringDelegate response); + [DllImport("CODALib.dll")] public static extern void do_other_message_handling_things([MarshalAs(UnmanagedType.LPStr)] string message); @@ -99,7 +58,7 @@ public struct pollfd { private int _appDocId = -1; - private String _fileURL; + private string _fileURL; public MainWindow() { @@ -120,7 +79,7 @@ private async void MainWindow_Loaded(object sender, RoutedEventArgs e) private void MainWindow_FileOpen(object sender, RoutedEventArgs e) { - OpenFileDialog openFileDialog = new OpenFileDialog(); + var openFileDialog = new Microsoft.Win32.OpenFileDialog(); openFileDialog.Filter = "Text documents|*.odt;*.docx;*.doc|" + "Spreadsheets|*.ods;*.xlsx;*.xls|" + @@ -158,7 +117,10 @@ void WebView_WebMessageReceived(object sender, CoreWebView2WebMessageReceivedEve } else if (s == "PRINT\"") { - Debug.WriteLine("Not yet implemented: Print"); + do_convert_to("pdf", _appDocId, s => + { + PrintPdfDocument(s); + }); } else if (s.StartsWith("downloadas ")) { @@ -202,23 +164,9 @@ async Task InitializeWebView(IWebView2 webView2) void AttachControlEventHandlers(IWebView2 control) { - control.NavigationStarting += WebView_NavigationStarting; - control.NavigationCompleted += WebView_NavigationCompleted; control.CoreWebView2InitializationCompleted += WebView_CoreWebView2InitializationCompleted; } - void WebView_NavigationStarting(object sender, CoreWebView2NavigationStartingEventArgs e) - { - _isNavigating = true; - - CoreWebView2NavigationKind kind = e.NavigationKind; - } - - void WebView_NavigationCompleted(object sender, CoreWebView2NavigationCompletedEventArgs e) - { - _isNavigating = false; - } - private void openCOOL() { // Hide the helpful note @@ -243,12 +191,79 @@ private void openCOOL() }; } + private async void PrintPdfDocument(string path) + { + try + { + var images = await PdfToImage(path); + int index = 0; + + PrintDocument printDocument = new PrintDocument(); + + printDocument.PrintPage += (sender, e) => + { + System.Drawing.Image image = images[index]; + + // Calculate the scaling factor to fit the image within the page size + float X = (float)e.PageSettings.PaperSize.Width / image.Width; + float Y = (float)e.PageSettings.PaperSize.Height / image.Height; + float scaleFactor = Math.Min(X, Y); + + // Draw the image on the page + e.Graphics.DrawImage(image, 0, 0, image.Width * scaleFactor, image.Height * scaleFactor); + + index++; + if (index < images.Count) + { + e.HasMorePages = true; + image.Dispose(); + return; + } + + e.HasMorePages = false; + image.Dispose(); + }; + + printDocument.Print(); + } + catch (System.Exception ex) + { + System.Windows.MessageBox.Show("Error : " + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error); + } + } + + private async Task> PdfToImage(string path) + { + var storagePdfFile = await Windows.Storage.StorageFile.GetFileFromPathAsync(path); + Windows.Data.Pdf.PdfDocument pdfDocument = await Windows.Data.Pdf.PdfDocument.LoadFromFileAsync(storagePdfFile); + + uint index = 0; + List images = new List(); + + while (index < pdfDocument.PageCount) + { + using (Windows.Data.Pdf.PdfPage pdfPage = pdfDocument.GetPage(index)) + { + using (Windows.Storage.Streams.InMemoryRandomAccessStream memStream = new Windows.Storage.Streams.InMemoryRandomAccessStream()) + { + // Windows.Data.Pdf.PdfPageRenderOptions pdfPageRenderOptions = new Windows.Data.Pdf.PdfPageRenderOptions(); + await pdfPage.RenderToStreamAsync(memStream); + System.Drawing.Image image = System.Drawing.Image.FromStream(memStream.AsStream()); + images.Add(image); + } + } + index++; + } + + return images; + } + void WebView_CoreWebView2InitializationCompleted(object sender, CoreWebView2InitializationCompletedEventArgs e) { if (e.IsSuccess) _iWebView2.CoreWebView2.Navigate("about:blank"); else - MessageBox.Show($"WebView2 creation failed with exception = {e.InitializationException}"); + System.Windows.MessageBox.Show($"WebView2 creation failed with exception = {e.InitializationException}"); } private bool _isMessageOfType(byte[] message, string type, int lengthOfMessage) @@ -311,7 +326,7 @@ void send2JS(IntPtr buffer, int length) Debug.WriteLine($"Evaluating JavaScript: {subjs}"); } - Application.Current.Dispatcher.Invoke(new Action(() => { + System.Windows.Application.Current.Dispatcher.Invoke(new Action(() => { _iWebView2.ExecuteScriptAsync(js); })); } diff --git a/windows/coda/CODALib/CODALib.vcxproj b/windows/coda/CODALib/CODALib.vcxproj index 3accdf02e1610..fc06d46b42ace 100644 --- a/windows/coda/CODALib/CODALib.vcxproj +++ b/windows/coda/CODALib/CODALib.vcxproj @@ -46,7 +46,7 @@ - $(SolutionDir)CODA\bin\$(Configuration)\net8.0-windows + $(SolutionDir)CODA\bin\$(Configuration)\net8.0-windows10.0.19041.0 $(SolutionDir)CODA\bin\$(Configuration)\net8.0-windows @@ -140,4 +140,4 @@ - + \ No newline at end of file diff --git a/windows/coda/windows.cpp b/windows/coda/windows.cpp index 0726c5c5e1820..2ec458060efe8 100755 --- a/windows/coda/windows.cpp +++ b/windows/coda/windows.cpp @@ -29,6 +29,7 @@ static int fakeClientFd; static int closeNotificationPipeForForwardingThread[2]; typedef void (*send2JS_t)(char *buffer, long length); +typedef void(*replyWithString_t)(const char *s); static send2JS_t send2JSfunction; @@ -190,6 +191,17 @@ void do_bye_handling_things() fakeSocketClose(closeNotificationPipeForForwardingThread[0]); } +EXPORT +void do_convert_to(const char *type, int appDocId, replyWithString_t response) +{ + const std::string tempFile = FileUtil::createRandomTmpDir() + "/haha." + std::string(type); + const std::string tempFileUri = Poco::URI(Poco::Path(tempFile)).toString(); + + DocumentData::get(appDocId).loKitDocument->saveAs(tempFileUri.c_str(), type, nullptr); + + response(tempFileUri.c_str()); +} + EXPORT void do_other_message_handling_things(const char *message) { From b1164b8d5a6fd4de5aab8ae91780580488399eae Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Tue, 29 Apr 2025 23:57:09 +0300 Subject: [PATCH 163/177] Fix CODA-W build after rebase Document::forkToSave() is not used in the MOBILEAPP case so surround it too with #if !MOBILEAPP. Fixes Windows compilation as it uses fork(). No SMaps in MOBILEAPP. Define ENABLE_LOCAL_FILESYSTEM (as 1) for CODA-W, too. A parameter name had been changed gratuitously. Signed-off-by: Tor Lillqvist Change-Id: I5fc5059c1aa20de765e74e0c62a233bf6c4b2380 --- common/Log.cpp | 10 +++++----- windows/coda/config.h.in | 2 ++ wsd/DocumentBroker.cpp | 2 ++ 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/common/Log.cpp b/common/Log.cpp index c6b4decda0c5a..c5456af4a97c4 100644 --- a/common/Log.cpp +++ b/common/Log.cpp @@ -168,16 +168,16 @@ namespace Log return ptr - data; #else // _WIN32 if (!IsDebuggerPresent()) - fwrite(data, size, 1, stderr); + fwrite(data, count, 1, stderr); else { - char *s = (char *)malloc(size + 1); - memcpy(s, data, size); - s[size] = 0; + char *s = (char *)malloc(count + 1); + memcpy(s, data, count); + s[count] = 0; OutputDebugStringA(s); free(s); } - return size; + return count; #endif } diff --git a/windows/coda/config.h.in b/windows/coda/config.h.in index e2c1c2fcc9e96..689662b16d4f0 100755 --- a/windows/coda/config.h.in +++ b/windows/coda/config.h.in @@ -183,3 +183,5 @@ struct pollfd { #define EXTERNC extern "C" #define EXPORT EXTERNC __declspec(dllexport) + +#define ENABLE_LOCAL_FILESYSTEM 1 diff --git a/wsd/DocumentBroker.cpp b/wsd/DocumentBroker.cpp index 0307c04824e30..104e3eaff8517 100644 --- a/wsd/DocumentBroker.cpp +++ b/wsd/DocumentBroker.cpp @@ -60,7 +60,9 @@ #include #include #include +#ifndef _WIN32 #include +#endif #include using namespace std::literals; From 0f5348588395bfa30576e0657e19949a4a8d94cb Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Tue, 6 May 2025 12:17:03 +0300 Subject: [PATCH 164/177] Show a print dialog Signed-off-by: Tor Lillqvist Change-Id: Icbd014e889fb7b12db32f0aed542f7c2bb8bd6c8 --- windows/coda/CODA/MainWindow.xaml.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/windows/coda/CODA/MainWindow.xaml.cs b/windows/coda/CODA/MainWindow.xaml.cs index 697947acfdc2b..15ede2d9bd832 100644 --- a/windows/coda/CODA/MainWindow.xaml.cs +++ b/windows/coda/CODA/MainWindow.xaml.cs @@ -224,7 +224,14 @@ private async void PrintPdfDocument(string path) image.Dispose(); }; - printDocument.Print(); + PrintDialog printDialog = new PrintDialog(); + printDialog.AllowCurrentPage = true; + printDialog.AllowSomePages = true; + printDialog.Document = printDocument; + if (printDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK) + { + printDocument.Print(); + } } catch (System.Exception ex) { From f201d7d1a8dd01c0b580f5362d279f4d8d4e010b Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 13 May 2025 13:16:34 +0200 Subject: [PATCH 165/177] coda-m: Implement clipboard Copy (no Paste yet) Signed-off-by: Jan Holesovsky Change-Id: I6351ad9cac0638d1deea2ce66790aa4961a14e83 --- browser/src/map/Clipboard.js | 17 ++++--- macos/coda/coda/COWrapper.h | 13 ++--- macos/coda/coda/COWrapper.mm | 69 ++++++++++++++++++++++++- macos/coda/coda/ViewController.swift | 76 +++++++++++++++++++--------- 4 files changed, 136 insertions(+), 39 deletions(-) diff --git a/browser/src/map/Clipboard.js b/browser/src/map/Clipboard.js index d538f07e1a292..1600b51791693 100644 --- a/browser/src/map/Clipboard.js +++ b/browser/src/map/Clipboard.js @@ -449,7 +449,7 @@ window.L.Clipboard = window.L.Class.extend({ }, _sendToInternalClipboard: async function (content) { - if (window.ThisIsTheiOSApp) { + if (window.ThisIsTheiOSApp || window.ThisIsTheMacOSApp) { await window.webkit.messageHandlers.clipboard.postMessage(`sendToInternal ${await content.text()}`); // no need to base64 in this direction... } else if (window.ThisIsTheWindowsApp) { await window.postMobileMessage(`CLIPBOARDJS sendToInternal ${await content.text()}`); @@ -712,9 +712,10 @@ window.L.Clipboard = window.L.Class.extend({ } if (!window.ThisIsTheiOSApp && // in mobile apps, we want to drop straight to navigatorClipboardRead as execCommand will require user interaction... - !window.ThisIsTheWindowsApp && - document.execCommand(operation) && - serial !== this._clipboardSerial) { + !window.ThisIsTheMacOSApp && + !window.ThisIsTheWindowsApp && + document.execCommand(operation) && + serial !== this._clipboardSerial) { window.app.console.log('copied successfully'); this._unoCommandForCopyCutPaste = null; return; @@ -870,7 +871,7 @@ window.L.Clipboard = window.L.Class.extend({ // Executes the navigator.clipboard.write() call, if it's available. _navigatorClipboardWrite: function(params) { - if (!window.L.Browser.clipboardApiAvailable && !window.ThisIsTheiOSApp && !window.ThisIsTheWindowsApp) { + if (!window.L.Browser.clipboardApiAvailable && !window.ThisIsTheiOSApp && !window.ThisIsTheMacOSApp && !window.ThisIsTheWindowsApp) { return false; } @@ -891,7 +892,7 @@ window.L.Clipboard = window.L.Class.extend({ // Deferring like this is kinda horrible - it certainly looks gross in places - but it's absolutely necessary to avoid errors on the clipboard.write line // I don't like it either :). If you change this make sure to thoroughly test cross-browser and cross-device! - if (window.ThisIsTheiOSApp) { + if (window.ThisIsTheiOSApp || window.ThisIsTheMacOSApp) { // This is sent down the fakewebsocket which can race with the // native message - so first step is to wait for the result of // that command so we are sure the clipboard is set before @@ -981,7 +982,7 @@ window.L.Clipboard = window.L.Class.extend({ // Executes the navigator.clipboard.read() call, if it's available. _navigatorClipboardRead: function(isSpecial) { - if (!window.L.Browser.clipboardApiAvailable && !window.ThisIsTheiOSApp && !window.ThisIsTheWindowsApp) { + if (!window.L.Browser.clipboardApiAvailable && !window.ThisIsTheiOSApp && !window.ThisIsTheMacOSApp && !window.ThisIsTheWindowsApp) { return false; } @@ -1035,7 +1036,7 @@ window.L.Clipboard = window.L.Class.extend({ } let clipboardContents; try { - if (window.ThisIsTheiOSApp) + if (window.ThisIsTheiOSApp || window.ThisIsTheMacOSApp) clipboardContents = await this._iOSReadClipboard(); else if (window.ThisIsTheWindowsApp) clipboardContents = await this._WindowsReadClipboard(); diff --git a/macos/coda/coda/COWrapper.h b/macos/coda/coda/COWrapper.h index 9bfc9b1a9ed6b..125e1471e5e07 100644 --- a/macos/coda/coda/COWrapper.h +++ b/macos/coda/coda/COWrapper.h @@ -19,15 +19,16 @@ + (void)startServer; + (void)stopServer; -+ (void)handleHULLOWithDocument:(Document *)document; -+ (void)handleMessageWith:(Document *)document message:(NSString *)message; -+ (void)saveAsWith:(Document *)document url:(NSString *)url format:(NSString *)format filterOptions:(NSString *)filterOptions; ++ (void)handleHULLOWithDocument:(Document *_Nonnull)document; ++ (void)handleMessageWith:(Document *_Nonnull)document message:(NSString *_Nonnull)message; ++ (void)saveAsWith:(Document *_Nonnull)document url:(NSString *_Nonnull)url format:(NSString *_Nonnull)format filterOptions:(NSString *_Nullable)filterOptions; ++ (NSArray> * _Nullable) getClipboardWith:(Document *_Nonnull)document NS_SWIFT_NAME(getClipboard(_:)); + (int)generateNewAppDocId; + (int)fakeSocketSocket; -+ (void)LOG_DBG:(NSString *)message NS_SWIFT_NAME(LOG_DBG(_:)); -+ (void)LOG_ERR:(NSString *)message NS_SWIFT_NAME(LOG_ERR(_:)); -+ (void)LOG_TRC:(NSString *)message NS_SWIFT_NAME(LOG_TRC(_:)); ++ (void)LOG_DBG:(NSString *_Nonnull)message NS_SWIFT_NAME(LOG_DBG(_:)); ++ (void)LOG_ERR:(NSString *_Nonnull)message NS_SWIFT_NAME(LOG_ERR(_:)); ++ (void)LOG_TRC:(NSString *_Nonnull)message NS_SWIFT_NAME(LOG_TRC(_:)); @end diff --git a/macos/coda/coda/COWrapper.mm b/macos/coda/coda/COWrapper.mm index a8da8f625936b..a0ec45913c54e 100644 --- a/macos/coda/coda/COWrapper.mm +++ b/macos/coda/coda/COWrapper.mm @@ -10,7 +10,11 @@ #include -#import "WebKit/WebKit.h" +#define LIBO_INTERNAL_ONLY +#include + +#import +#import #import "coda-Swift.h" #import "COWrapper.h" @@ -162,6 +166,69 @@ + (void)saveAsWith:(Document *)document url:(NSString *)url format:(NSString *)f DocumentData::get(document.appDocId).loKitDocument->saveAs([url UTF8String], [format UTF8String], [filterOptions UTF8String]); } +/** + * Call the LOKit getClipboard and return it so that it can be used in Swift. + */ ++ (NSArray> * _Nullable) getClipboardInternalWith:(Document *_Nonnull)document mimeTypes:(const char**)mimeTypes { + size_t outCount = 0; + char **outMimeTypes = nullptr; + size_t *outSizes = nullptr; + char **outStreams = nullptr; + + if (DocumentData::get(document.appDocId).loKitDocument->getClipboard(mimeTypes, + &outCount, &outMimeTypes, + &outSizes, &outStreams)) + { + // return early + if (outCount == 0) + return nil; + + NSMutableArray> *result = [NSMutableArray array]; + + for (size_t i = 0; i < outCount; ++i) { + NSString * identifier = [NSString stringWithUTF8String:outMimeTypes[i]]; + + // For interop with other apps, if this mime-type is known we can export it + UTType * uti = [UTType typeWithMIMEType:identifier]; + if (uti != nil && !uti.dynamic) { + if ([uti conformsToType:UTTypePlainText] && outStreams[i] != nullptr) { + [result addObject:[NSString stringWithUTF8String:outStreams[i]]]; + } + else if ([uti conformsToType:UTTypeImage]) { + [result addObject:[[NSImage alloc] initWithData:[NSData dataWithBytes:outStreams[i] length:outSizes[i]]]]; + } + } + + // Also preserve the data we need, we'll always also export the raw, unaltered bytes + NSPasteboardItem * item = [[NSPasteboardItem alloc] init]; + [item setData:[NSData dataWithBytes:outStreams[i] length:outSizes[i]] forType:identifier]; + } + + return result; + } + else + LOG_DBG("failed to fetch mime-types"); + + return nil; +} + +/** + * Get the clipboard content. Defaults to fetching text and/or html only, when a generic query fails. + */ ++ (NSArray> * _Nullable) getClipboardWith:(Document *_Nonnull)document { + NSArray> * result = [COWrapper getClipboardInternalWith:document mimeTypes:nullptr]; + if (result != nil) + return result; + + const char* textMimeTypes[] = { + "text/plain;charset=utf-8", + "text/html", + nullptr + }; + + return [COWrapper getClipboardInternalWith:document mimeTypes:textMimeTypes]; +} + /** * We keep a running count of opening documents here. This is not necessarily in sync with the * DocBrokerId in DocumentBroker due to potential parallelism when opening multiple documents in diff --git a/macos/coda/coda/ViewController.swift b/macos/coda/coda/ViewController.swift index adf39bf0804d3..263d9fc73041e 100644 --- a/macos/coda/coda/ViewController.swift +++ b/macos/coda/coda/ViewController.swift @@ -11,7 +11,7 @@ import Cocoa import WebKit -class ViewController: NSViewController, WKScriptMessageHandler, WKNavigationDelegate { +class ViewController: NSViewController, WKScriptMessageHandlerWithReply, WKNavigationDelegate { /// Access to the NSDocument (document loading & saving infrastructure). var document: Document! @@ -24,9 +24,10 @@ class ViewController: NSViewController, WKScriptMessageHandler, WKNavigationDele // Setup jsHandler as the entry point co call back from JavaScript let contentController = WKUserContentController() - contentController.add(self, name: "debug") - contentController.add(self, name: "lok") - contentController.add(self, name: "error") + contentController.addScriptMessageHandler(self, contentWorld: .page, name: "debug") + contentController.addScriptMessageHandler(self, contentWorld: .page, name: "lok") + contentController.addScriptMessageHandler(self, contentWorld: .page, name: "error") + contentController.addScriptMessageHandler(self, contentWorld: .page, name: "clipboard") let config = WKWebViewConfiguration() config.userContentController = contentController @@ -61,32 +62,57 @@ class ViewController: NSViewController, WKScriptMessageHandler, WKNavigationDele } /** - * Receive message from JavaScript + * Receive message from JavaScript, with the possibility to reply */ - func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { - if message.name == "error" { + func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) async -> (Any?, String?) { + switch message.name { + + case "error": if let body = message.body as? String { COWrapper.LOG_ERR("Error from WebView: \(body)") } - } - else if message.name == "debug" { + + case "debug": if let body = message.body as? String { print("==> \(body)") } - } - else if message.name == "lok" { + + case "clipboard": + if let body = message.body as? String { + switch body { + + /*case "read": + setClipboardContent(from: .general)*/ + + case "write": + guard let content = COWrapper.getClipboard(document) else { + COWrapper.LOG_ERR("Failed to get clipboard contents") + return (nil, nil) + } + NSPasteboard.general.clearContents() + NSPasteboard.general.writeObjects(content) + + /*case let s where s.hasPrefix("sendToInternal "): + sendToInternal(String(s.dropFirst("sendToInternal ".count)))*/ + + default: + COWrapper.LOG_ERR("Invalid clipboard action \(body)") + } + } + + case "lok": if let body = message.body as? String { COWrapper.LOG_DBG("To Online: \(message.body)") if body == "HULLO" { // Now we know that the JS has started completely COWrapper.handleHULLO(with: document) - return + return (nil, nil) } else if body == "BYE" { COWrapper.LOG_TRC("Document window terminating on JavaScript side. Closing our end of the socket.") //self.bye() - return + return (nil, nil) } else if body.hasPrefix("COMMANDSTATECHANGED ") { if let brace = body.firstIndex(of: "{") { @@ -105,7 +131,7 @@ class ViewController: NSViewController, WKScriptMessageHandler, WKNavigationDele } else if body.hasPrefix("MODIFIED ") { document?.isModified = body.hasSuffix("true") - return + return (nil, nil) } else if body == "SLIDESHOW" { COWrapper.LOG_ERR("TODO: Implement slideshow") @@ -152,7 +178,7 @@ class ViewController: NSViewController, WKScriptMessageHandler, WKNavigationDele } */ - return + return (nil, nil) } else if body == "EXITSLIDESHOW" { COWrapper.LOG_ERR("TODO: Implement EXITSLIDESHOW") @@ -168,11 +194,11 @@ class ViewController: NSViewController, WKScriptMessageHandler, WKNavigationDele self.slideshowWebView = nil self.webView.isHidden = false */ - return + return (nil, nil) } else if body == "PRINT" { document.printDocument(self) - return + return (nil, nil) } else if body == "FOCUSIFHWKBD" { COWrapper.LOG_ERR("TODO: Implement FOCUSIFHWKBD") @@ -195,17 +221,17 @@ class ViewController: NSViewController, WKScriptMessageHandler, WKNavigationDele } } */ - return + return (nil, nil) } else if body.hasPrefix("HYPERLINK") { let messageBodyItems = body.components(separatedBy: " ") if messageBodyItems.count >= 2 { if let url = URL(string: messageBodyItems[1]) { NSWorkspace.shared.open(url) - return + return (nil, nil) } } - return + return (nil, nil) } else if body == "FONTPICKER" { COWrapper.LOG_ERR("TODO: Implement FONTPICKER") @@ -216,7 +242,7 @@ class ViewController: NSViewController, WKScriptMessageHandler, WKNavigationDele fontManager.action = #selector(changeFont(_:)) fontManager.orderFrontFontPanel(self) */ - return + return (nil, nil) } else if body.hasPrefix("downloadas ") { COWrapper.LOG_ERR("TODO: Implement downloadas") @@ -284,15 +310,15 @@ class ViewController: NSViewController, WKScriptMessageHandler, WKNavigationDele return } */ - return + return (nil, nil) } else { // Just send the message COWrapper.handleMessage(with: document, message: body) } } - } - else { + + default: if let body = message.body as? String { COWrapper.LOG_ERR("Unrecognized kind of message received from WebView: \(message.name):\(body)") } @@ -300,5 +326,7 @@ class ViewController: NSViewController, WKScriptMessageHandler, WKNavigationDele COWrapper.LOG_ERR("Unrecognized kind of message received from WebView: \(message.name)") } } + + return (nil, nil) } } From f32937dceb70d91d5423402caf159377d5f6292f Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 20 May 2025 12:05:09 +0200 Subject: [PATCH 166/177] coda-m: Implement clipboard Paste Signed-off-by: Jan Holesovsky Change-Id: I54de9447a390f5c9a3749179cb0b5f2be868b5fe --- macos/coda/coda/COWrapper.h | 2 + macos/coda/coda/COWrapper.mm | 109 +++++++++++++++++++++++++-- macos/coda/coda/ViewController.swift | 12 ++- 3 files changed, 114 insertions(+), 9 deletions(-) diff --git a/macos/coda/coda/COWrapper.h b/macos/coda/coda/COWrapper.h index 125e1471e5e07..52237cf5e55b5 100644 --- a/macos/coda/coda/COWrapper.h +++ b/macos/coda/coda/COWrapper.h @@ -23,6 +23,8 @@ + (void)handleMessageWith:(Document *_Nonnull)document message:(NSString *_Nonnull)message; + (void)saveAsWith:(Document *_Nonnull)document url:(NSString *_Nonnull)url format:(NSString *_Nonnull)format filterOptions:(NSString *_Nullable)filterOptions; + (NSArray> * _Nullable) getClipboardWith:(Document *_Nonnull)document NS_SWIFT_NAME(getClipboard(_:)); ++ (void)setClipboardWith:(Document *_Nonnull)document from:(NSPasteboard *_Nonnull)pasteboard NS_SWIFT_NAME(setClipboard(_:from:)); ++ (bool)sendToInternalWith:(Document *_Nonnull)document content:(NSString *_Nonnull)content NS_SWIFT_NAME(sendToInternalClipboard(_:content:)); + (int)generateNewAppDocId; + (int)fakeSocketSocket; diff --git a/macos/coda/coda/COWrapper.mm b/macos/coda/coda/COWrapper.mm index a0ec45913c54e..02c46383f01cc 100644 --- a/macos/coda/coda/COWrapper.mm +++ b/macos/coda/coda/COWrapper.mm @@ -23,11 +23,12 @@ // Include necessary C++ headers #include #include -#include "COOLWSD.hpp" -#include "FakeSocket.hpp" -#include "Log.hpp" -#include "MobileApp.hpp" -#include "Util.hpp" +#include +#include +#include +#include +#include +#include // Declare the coolwsd pointer at global scope COOLWSD *coolwsd = nullptr; @@ -229,6 +230,104 @@ + (void)saveAsWith:(Document *)document url:(NSString *)url format:(NSString *)f return [COWrapper getClipboardInternalWith:document mimeTypes:textMimeTypes]; } +/** + * Sets the LOKit internal clipboard with the content of NSPasteboard. + */ ++ (void)setClipboardWith:(Document *_Nonnull)document from:(NSPasteboard *_Nonnull)pasteboard { + NSMutableDictionary * pasteboardItems = [NSMutableDictionary new]; + + if (pasteboard.pasteboardItems.count != 0) { + NSPasteboardItem *item = pasteboard.pasteboardItems.firstObject; + + for (NSPasteboardType identifier in item.types) + { + UTType * uti = [UTType typeWithIdentifier:identifier]; + NSString * mime = uti? uti.preferredMIMEType: identifier; + + if (mime == nil) { + LOG_WRN("UTI " << [identifier UTF8String] << " did not have associated mime type when deserializing clipboard, skipping..."); + continue; + } + + NSData * value = [item dataForType:identifier]; + if (value == nil) + continue; + + if (uti != nil && [pasteboardItems objectForKey:mime] != nil) { + // We export both mime and UTI keys, don't overwrite the mime-type ones with the UTI ones + continue; + } + + [pasteboardItems setObject:value forKey:mime]; + } + } + + const char * pInMimeTypes[pasteboardItems.count]; + size_t pInSizes[pasteboardItems.count]; + const char * pInStreams[pasteboardItems.count]; + + size_t i = 0; + + for (NSString * mime in pasteboardItems) { + pInMimeTypes[i] = [mime UTF8String]; + pInStreams[i] = (const char*)[pasteboardItems[mime] bytes]; + pInSizes[i] = [pasteboardItems[mime] length]; + i++; + } + + DocumentData::get(document.appDocId).loKitDocument->setClipboard(pasteboardItems.count, pInMimeTypes, pInSizes, pInStreams); +} + +/** + * Insert data into the internal clipboard. The content's format is mimeType\nlegth\ndata\n[...repeat for more mimetypes...]. + */ ++ (bool)sendToInternalWith:(Document *_Nonnull)document content:(NSString *_Nonnull)content { + std::vector html; + + ClipboardData data; + size_t nInCount; + + if ([content hasPrefix:@""]) { + // Content is just HTML + const char * _Nullable content_cstr = [content cStringUsingEncoding:NSUTF8StringEncoding]; + html = std::vector(content_cstr, content_cstr + [content lengthOfBytesUsingEncoding:NSUTF8StringEncoding]); + nInCount = 1; + } + else { + // objcString -> std::string (keeps embedded NULs, no extra copy for UTF-8) + std::string buffer(static_cast([content UTF8String]), + [content lengthOfBytesUsingEncoding:NSUTF8StringEncoding]); + + // put the buffer into a std::stringbuf, treated as binary (allow NULs in there), and create the input stream + std::stringbuf sb(buffer, std::ios::in | std::ios::binary); + std::istream stream(&sb); + + // read the data + data.read(stream); + nInCount = data.size(); + // DEBUG: data.dumpState(std::cout); + } + + std::vector pInSizes(nInCount); + std::vector pInMimeTypes(nInCount); + std::vector pInStreams(nInCount); + + if (html.empty()) { + for (size_t i = 0; i < nInCount; ++i) { + pInSizes[i] = data._content[i].length(); + pInStreams[i] = data._content[i].c_str(); + pInMimeTypes[i] = data._mimeTypes[i].c_str(); + } + } + else { + pInSizes[0] = html.size(); + pInStreams[0] = html.data(); + pInMimeTypes[0] = "text/html"; + } + + return DocumentData::get(document.appDocId).loKitDocument->setClipboard(nInCount, pInMimeTypes.data(), pInSizes.data(), pInStreams.data()); +} + /** * We keep a running count of opening documents here. This is not necessarily in sync with the * DocBrokerId in DocumentBroker due to potential parallelism when opening multiple documents in diff --git a/macos/coda/coda/ViewController.swift b/macos/coda/coda/ViewController.swift index 263d9fc73041e..a39b6032afb1c 100644 --- a/macos/coda/coda/ViewController.swift +++ b/macos/coda/coda/ViewController.swift @@ -81,8 +81,9 @@ class ViewController: NSViewController, WKScriptMessageHandlerWithReply, WKNavig if let body = message.body as? String { switch body { - /*case "read": - setClipboardContent(from: .general)*/ + case "read": + COWrapper.setClipboard(document, from: .general) + return ("(internal)", nil); case "write": guard let content = COWrapper.getClipboard(document) else { @@ -92,8 +93,11 @@ class ViewController: NSViewController, WKScriptMessageHandlerWithReply, WKNavig NSPasteboard.general.clearContents() NSPasteboard.general.writeObjects(content) - /*case let s where s.hasPrefix("sendToInternal "): - sendToInternal(String(s.dropFirst("sendToInternal ".count)))*/ + case let s where s.hasPrefix("sendToInternal "): + if !COWrapper.sendToInternalClipboard(document, content: String(s.dropFirst("sendToInternal ".count))) { + COWrapper.LOG_ERR("set clipboard returned failure"); + return (nil, "set clipboard returned failure"); + } default: COWrapper.LOG_ERR("Invalid clipboard action \(body)") From 9fc035db1c9c8364de8856b6a8871eff99fd2a73 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 20 May 2025 23:15:43 +0200 Subject: [PATCH 167/177] coda-m: Enable/disable the Cut/Copy/Paste in the macOS menu Signed-off-by: Jan Holesovsky Change-Id: Ie3b57b53b655561ba0475eed4a1e085d66a522cf --- macos/coda/coda/WindowController.swift | 31 +++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/macos/coda/coda/WindowController.swift b/macos/coda/coda/WindowController.swift index 300d1bc7c256f..827c18b143ecf 100644 --- a/macos/coda/coda/WindowController.swift +++ b/macos/coda/coda/WindowController.swift @@ -9,6 +9,7 @@ */ import Cocoa +import WebKit enum FormatMenuCommand: Int { case bold = 1 @@ -32,7 +33,7 @@ struct CommandStateChange: Decodable { class WindowController: NSWindowController, NSMenuItemValidation { /// Track menu states here, to be able to show the state in the menu - var formatStates: [String: Bool] = [:] + var commandState: [String: String] = [:] /// Single IBAction for all Format commands in the menu @IBAction func formatMenuAction(_ sender: NSMenuItem) { @@ -54,7 +55,7 @@ class WindowController: NSWindowController, NSMenuItemValidation { let commandName = unoCommmandName[unoCommmandName.index(after: colon)...] // store it - formatStates[String(commandName)] = stateChange.state == "true" + commandState[String(commandName)] = stateChange.state } /// Show on/off checkmarks for the particular command(s) like Bold/Italics/... @@ -68,8 +69,32 @@ class WindowController: NSWindowController, NSMenuItemValidation { guard let commandName = formatMenuCommandNames[command] else { return false } // Show a check if the command is currently ON - let isOn = formatStates[commandName] ?? false + let isOn = commandState[commandName] == "true" menuItem.state = isOn ? .on : .off return true } } + +/** + * Extend the WKWebView so that we can set the state of Cut/Copy/Paste in the macOS menu too. + */ +extension WKWebView: @retroactive NSMenuItemValidation { + + public func validateMenuItem(_ menuItem: NSMenuItem) -> Bool { + guard let commandState = (window?.windowController as? WindowController)?.commandState else { + return true + } + + if menuItem.action == #selector(NSText.cut(_:)) { + return commandState["Cut"] != "disabled" + } + else if menuItem.action == #selector(NSText.copy(_:)) { + return commandState["Copy"] != "disabled" + } + else if menuItem.action == #selector(NSText.paste(_:)) { + return commandState["Paste"] != "disabled" + } + + return true + } +} From 4c6a27ac80d7317745c517f04e07f521082954d5 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Thu, 22 May 2025 16:57:06 +0300 Subject: [PATCH 168/177] Use Util::getProcessId() instead of getpid() Signed-off-by: Tor Lillqvist Change-Id: I5e9787a5e6f26a926143e2fd1117112348f537cb --- kit/Kit.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kit/Kit.cpp b/kit/Kit.cpp index 592caa4b05f21..01f6613e46390 100644 --- a/kit/Kit.cpp +++ b/kit/Kit.cpp @@ -4343,7 +4343,7 @@ std::string anonymizeUsername(const std::string& username) void dump_kit_state() { std::ostringstream oss(Util::makeDumpStateStream()); - oss << "Start Kit " << getpid() << " Dump State:\n"; + oss << "Start Kit " << Util::getProcessId() << " Dump State:\n"; SigUtil::signalLogActivity(); @@ -4351,7 +4351,7 @@ void dump_kit_state() oss << "\nMalloc info [" << Util::getProcessId() << "]: \n\t" << Util::replace(Util::getMallocInfo(), "\n", "\n\t") << '\n'; - oss << "\nEnd Kit " << getpid() << " Dump State.\n"; + oss << "\nEnd Kit " << Util::getProcessId() << " Dump State.\n"; const std::string msg = oss.str(); fprintf(stderr, "%s", msg.c_str()); // Log in the journal. From 9c77895883f9298d60d24a081097a63a90446c26 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Thu, 22 May 2025 17:04:46 +0300 Subject: [PATCH 169/177] Add RegexUtil.cpp Signed-off-by: Tor Lillqvist Change-Id: Icd93dfa332d1ef44b1a9527e39cc1335016fad4a --- windows/coda/CODALib/CODALib.vcxproj | 3 ++- windows/coda/CODALib/CODALib.vcxproj.filters | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/windows/coda/CODALib/CODALib.vcxproj b/windows/coda/CODALib/CODALib.vcxproj index fc06d46b42ace..eae4c078b4f64 100644 --- a/windows/coda/CODALib/CODALib.vcxproj +++ b/windows/coda/CODALib/CODALib.vcxproj @@ -107,6 +107,7 @@ + @@ -140,4 +141,4 @@ - \ No newline at end of file + diff --git a/windows/coda/CODALib/CODALib.vcxproj.filters b/windows/coda/CODALib/CODALib.vcxproj.filters index a0b783f6611d6..7b927841f12d5 100644 --- a/windows/coda/CODALib/CODALib.vcxproj.filters +++ b/windows/coda/CODALib/CODALib.vcxproj.filters @@ -48,6 +48,9 @@ Source Files + + Source Files + Source Files @@ -133,4 +136,4 @@ Source Files - \ No newline at end of file + From 1f351173c06c2764e22fc9c3ed61574042a7cf0f Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Thu, 22 May 2025 17:06:37 +0300 Subject: [PATCH 170/177] OutDir should end with a backslash Also, presumably should use the same style for OutDir in the Release configuration. Signed-off-by: Tor Lillqvist Change-Id: I08454ea086de73bb8767b366a3600f0788cd70d9 --- windows/coda/CODALib/CODALib.vcxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/windows/coda/CODALib/CODALib.vcxproj b/windows/coda/CODALib/CODALib.vcxproj index eae4c078b4f64..0655c66274ef5 100644 --- a/windows/coda/CODALib/CODALib.vcxproj +++ b/windows/coda/CODALib/CODALib.vcxproj @@ -46,10 +46,10 @@ - $(SolutionDir)CODA\bin\$(Configuration)\net8.0-windows10.0.19041.0 + $(SolutionDir)CODA\bin\$(Configuration)\net8.0-windows10.0.19041.0\ - $(SolutionDir)CODA\bin\$(Configuration)\net8.0-windows + $(SolutionDir)CODA\bin\$(Configuration)\net8.0-windows10.0.19041.0\ From d4f680fdcc07f345641f48f906554916e87a5022 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Thu, 22 May 2025 18:36:46 +0300 Subject: [PATCH 171/177] Copy browser/dist to the output directory and use it from there Instead of the temporary use of a fixed pathname on my development machine. The LO_PATH given at configure time is still used. Will handle that next. Signed-off-by: Tor Lillqvist Change-Id: I08911067575b9b31eefecd2d7287b4d117b8816d --- windows/coda/CODA/CODA.csproj | 3 +++ windows/coda/CODA/MainWindow.xaml.cs | 3 +-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/windows/coda/CODA/CODA.csproj b/windows/coda/CODA/CODA.csproj index a5d29be710bc7..1e430d5509a4f 100644 --- a/windows/coda/CODA/CODA.csproj +++ b/windows/coda/CODA/CODA.csproj @@ -14,4 +14,7 @@ + + + diff --git a/windows/coda/CODA/MainWindow.xaml.cs b/windows/coda/CODA/MainWindow.xaml.cs index 15ede2d9bd832..580c47783eea3 100644 --- a/windows/coda/CODA/MainWindow.xaml.cs +++ b/windows/coda/CODA/MainWindow.xaml.cs @@ -174,8 +174,7 @@ private void openCOOL() // Also hide the initial menu as COOL has its own menuXamlElement.Visibility = Visibility.Collapsed; - // FIXME: Temporarily, just use hardcoded pathnames on tml's machine to make debugging the JS easier. - _iWebView2.CoreWebView2.Navigate("file:///C:/Users/tml/lo/online-gitlab-coda25-coda/browser/dist/cool.html?file_path=" + _fileURL + "&closebutton=1&permission=edit&lang=en-US&appdocid=" + _appDocId + "&userinterfacemode=notebookbar&dir=ltr"); + _iWebView2.CoreWebView2.Navigate(new System.Uri(System.Windows.Forms.Application.StartupPath).AbsoluteUri + "cool/cool.html?file_path=" + _fileURL + "&closebutton=1&permission=edit&lang=en-US&appdocid=" + _appDocId + "&userinterfacemode=notebookbar&dir=ltr"); _iWebView2.CoreWebView2.NewWindowRequested += delegate ( object webview2, CoreWebView2NewWindowRequestedEventArgs args) From 2bcd748d76019e6de663a65f2b4872a5d92f0b2a Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Thu, 22 May 2025 19:41:12 +0300 Subject: [PATCH 172/177] Copy also the LO instdir into the app folder and use it from there Signed-off-by: Tor Lillqvist Change-Id: I861cf2d26d1808bf92cd5b8b5d576c9b4b7ce13d --- kit/Kit.cpp | 10 +++++++--- windows/coda/CODA/CODA.csproj | 7 ++++++- windows/coda/CODA/MainWindow.xaml.cs | 7 +++++-- windows/coda/config.props.in | 1 + windows/coda/windows.cpp | 17 ++++++++++++++--- windows/coda/windows.hpp | 4 ++++ 6 files changed, 37 insertions(+), 9 deletions(-) diff --git a/kit/Kit.cpp b/kit/Kit.cpp index 01f6613e46390..96d3859225632 100644 --- a/kit/Kit.cpp +++ b/kit/Kit.cpp @@ -121,6 +121,10 @@ #include "DocumentBroker.hpp" #endif +#ifdef _WIN32 +#include "windows.hpp" +#endif + using Poco::Exception; using Poco::File; using Poco::JSON::Object; @@ -3956,9 +3960,9 @@ void lokit_main( #elif defined(IOS) // In the iOS app we call lok_init_2() just once, when the app starts static LibreOfficeKit *kit = lo_kit; #elif defined(_WIN32) - // LO_PATH is a Windows path starting with a drive letter. For the second parameter to - // lok_init_2() turn it into a file: URI. - LibreOfficeKit *kit = lok_init_2(LO_PATH "/program", "file:///" LO_PATH); + LibreOfficeKit *kit = lok_init_2 + ((app_installation_path + "lo\\program").c_str(), + (app_installation_uri + "lo").c_str()); #else // FIXME: I wonder for which platform this is supposed to be? Android? static LibreOfficeKit *kit = lok_init_2(nullptr, nullptr); diff --git a/windows/coda/CODA/CODA.csproj b/windows/coda/CODA/CODA.csproj index 1e430d5509a4f..937da0261c237 100644 --- a/windows/coda/CODA/CODA.csproj +++ b/windows/coda/CODA/CODA.csproj @@ -1,5 +1,9 @@ + + + + WinExe net8.0-windows10.0.19041.0 @@ -16,5 +20,6 @@ - + + diff --git a/windows/coda/CODA/MainWindow.xaml.cs b/windows/coda/CODA/MainWindow.xaml.cs index 580c47783eea3..f1c4eb3421097 100644 --- a/windows/coda/CODA/MainWindow.xaml.cs +++ b/windows/coda/CODA/MainWindow.xaml.cs @@ -25,10 +25,10 @@ public partial class MainWindow : Window public delegate void ReplyWithStringDelegate(string s); [DllImport("CODALib.dll")] - public static extern int get_coolwsd_server_socket_fd(); + public static extern void set_app_installation_path(string path); [DllImport("CODALib.dll")] - public static extern int set_coolwsd_server_socket_fd(int fd); + public static extern void set_app_installation_uri(string uri); [DllImport("CODALib.dll")] public static extern int generate_new_app_doc_id(); @@ -67,6 +67,9 @@ public MainWindow() Send2JSDelegate fp = new Send2JSDelegate(send2JS); _gch = GCHandle.Alloc(fp); set_send2JS_function(fp); + var exeLocation = System.Windows.Forms.Application.StartupPath; + set_app_installation_path(exeLocation); + set_app_installation_uri(new System.Uri(exeLocation).AbsoluteUri); initialize_cpp_things(); } diff --git a/windows/coda/config.props.in b/windows/coda/config.props.in index f9303978b02fe..9654100ed41bc 100644 --- a/windows/coda/config.props.in +++ b/windows/coda/config.props.in @@ -2,5 +2,6 @@ @POCOINCLUDE_WINDOWS@;@ZSTDINCLUDE_WINDOWS@;@LIBPNG_INCLUDES_WINDOWS@;@ZLIB_INCLUDES_WINDOWS@;@LOBUILDDIR_WINDOWS@\include;$(IncludePath) @POCOLIB_WINDOWS@;@ZSTDLIB_WINDOWS@;@LIBPNG_LIBS_WINDOWS@;@ZLIB_LIBS_WINDOWS@;$(LibraryPath) + @LO_PATH@ diff --git a/windows/coda/windows.cpp b/windows/coda/windows.cpp index 2ec458060efe8..a07ee7ea3b532 100755 --- a/windows/coda/windows.cpp +++ b/windows/coda/windows.cpp @@ -19,10 +19,9 @@ #include const char *user_name = nullptr; - int coolwsd_server_socket_fd = -1; - -LibreOfficeKit *lo_kit; +std::string app_installation_path; +std::string app_installation_uri; static COOLWSD *coolwsd = nullptr; static int fakeClientFd; @@ -46,6 +45,18 @@ int set_coolwsd_server_socket_fd(int fd) return fd; } +EXPORT +void set_app_installation_path(const char* path) +{ + app_installation_path = path; +} + +EXPORT +void set_app_installation_uri(const char* uri) +{ + app_installation_uri = uri; +} + EXPORT int generate_new_app_doc_id() { diff --git a/windows/coda/windows.hpp b/windows/coda/windows.hpp index 33fe19f0f25ad..8b794b9b5b2c7 100755 --- a/windows/coda/windows.hpp +++ b/windows/coda/windows.hpp @@ -7,7 +7,11 @@ #include +#include + extern int coolwsd_server_socket_fd; extern const char *user_name; +extern std::string app_installation_path; +extern std::string app_installation_uri; /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ From 8f56390adb08f0dcbd721ff194868c52f99357b6 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Fri, 23 May 2025 22:05:27 +0300 Subject: [PATCH 173/177] Don't use Windows Forms API to get the folder we are running from Using typeof(MainWindow).Assembly.Location seems to be more straightforward. Signed-off-by: Tor Lillqvist Change-Id: Ibe50760748b8ff1fb036beb5c393c271ba6975c0 --- windows/coda/CODA/MainWindow.xaml.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/windows/coda/CODA/MainWindow.xaml.cs b/windows/coda/CODA/MainWindow.xaml.cs index f1c4eb3421097..b219e4cd6f166 100644 --- a/windows/coda/CODA/MainWindow.xaml.cs +++ b/windows/coda/CODA/MainWindow.xaml.cs @@ -60,6 +60,8 @@ public partial class MainWindow : Window private string _fileURL; + private string _exeLocation; + public MainWindow() { Loaded += MainWindow_Loaded; @@ -67,9 +69,11 @@ public MainWindow() Send2JSDelegate fp = new Send2JSDelegate(send2JS); _gch = GCHandle.Alloc(fp); set_send2JS_function(fp); - var exeLocation = System.Windows.Forms.Application.StartupPath; - set_app_installation_path(exeLocation); - set_app_installation_uri(new System.Uri(exeLocation).AbsoluteUri); + _exeLocation = System.IO.Path.GetDirectoryName(typeof(MainWindow).Assembly.Location); + if (!_exeLocation.EndsWith('\\')) + _exeLocation += "\\"; + set_app_installation_path(_exeLocation); + set_app_installation_uri(new System.Uri(_exeLocation).AbsoluteUri); initialize_cpp_things(); } @@ -177,7 +181,7 @@ private void openCOOL() // Also hide the initial menu as COOL has its own menuXamlElement.Visibility = Visibility.Collapsed; - _iWebView2.CoreWebView2.Navigate(new System.Uri(System.Windows.Forms.Application.StartupPath).AbsoluteUri + "cool/cool.html?file_path=" + _fileURL + "&closebutton=1&permission=edit&lang=en-US&appdocid=" + _appDocId + "&userinterfacemode=notebookbar&dir=ltr"); + _iWebView2.CoreWebView2.Navigate(new System.Uri(_exeLocation).AbsoluteUri + "cool/cool.html?file_path=" + _fileURL + "&closebutton=1&permission=edit&lang=en-US&appdocid=" + _appDocId + "&userinterfacemode=notebookbar&dir=ltr"); _iWebView2.CoreWebView2.NewWindowRequested += delegate ( object webview2, CoreWebView2NewWindowRequestedEventArgs args) From 0af5956009be2a68ad5c0e542acdd7d664a5e629 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Sat, 24 May 2025 16:47:53 +0300 Subject: [PATCH 174/177] Bin the temporary DllImportTest thing Signed-off-by: Tor Lillqvist Change-Id: If5541538a3f4fc9a873450a0a848a4485d1284a8 --- .../coda/test/DllImportTest/DllImportTest.sln | 51 ------ .../DllImportTest/DllImportTest.csproj | 10 -- .../DllImportTest/DllImportTest/Program.cs | 39 ----- .../Properties/launchSettings.json | 8 - .../DllImported/DllImported.vcxproj | 147 ------------------ .../DllImportTest/DllImported/dllmain.cpp | 16 -- 6 files changed, 271 deletions(-) delete mode 100644 windows/coda/test/DllImportTest/DllImportTest.sln delete mode 100644 windows/coda/test/DllImportTest/DllImportTest/DllImportTest.csproj delete mode 100644 windows/coda/test/DllImportTest/DllImportTest/Program.cs delete mode 100644 windows/coda/test/DllImportTest/DllImportTest/Properties/launchSettings.json delete mode 100644 windows/coda/test/DllImportTest/DllImported/DllImported.vcxproj delete mode 100644 windows/coda/test/DllImportTest/DllImported/dllmain.cpp diff --git a/windows/coda/test/DllImportTest/DllImportTest.sln b/windows/coda/test/DllImportTest/DllImportTest.sln deleted file mode 100644 index 15868ec796e76..0000000000000 --- a/windows/coda/test/DllImportTest/DllImportTest.sln +++ /dev/null @@ -1,51 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.12.35506.116 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DllImportTest", "DllImportTest\DllImportTest.csproj", "{70D169E1-AE56-4387-8E3C-6A110981837B}" - ProjectSection(ProjectDependencies) = postProject - {662B5428-CC26-473C-9E3E-CDCEC296B0B5} = {662B5428-CC26-473C-9E3E-CDCEC296B0B5} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DllImported", "DllImported\DllImported.vcxproj", "{662B5428-CC26-473C-9E3E-CDCEC296B0B5}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {70D169E1-AE56-4387-8E3C-6A110981837B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {70D169E1-AE56-4387-8E3C-6A110981837B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {70D169E1-AE56-4387-8E3C-6A110981837B}.Debug|x64.ActiveCfg = Debug|Any CPU - {70D169E1-AE56-4387-8E3C-6A110981837B}.Debug|x64.Build.0 = Debug|Any CPU - {70D169E1-AE56-4387-8E3C-6A110981837B}.Debug|x86.ActiveCfg = Debug|Any CPU - {70D169E1-AE56-4387-8E3C-6A110981837B}.Debug|x86.Build.0 = Debug|Any CPU - {70D169E1-AE56-4387-8E3C-6A110981837B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {70D169E1-AE56-4387-8E3C-6A110981837B}.Release|Any CPU.Build.0 = Release|Any CPU - {70D169E1-AE56-4387-8E3C-6A110981837B}.Release|x64.ActiveCfg = Release|Any CPU - {70D169E1-AE56-4387-8E3C-6A110981837B}.Release|x64.Build.0 = Release|Any CPU - {70D169E1-AE56-4387-8E3C-6A110981837B}.Release|x86.ActiveCfg = Release|Any CPU - {70D169E1-AE56-4387-8E3C-6A110981837B}.Release|x86.Build.0 = Release|Any CPU - {662B5428-CC26-473C-9E3E-CDCEC296B0B5}.Debug|Any CPU.ActiveCfg = Debug|x64 - {662B5428-CC26-473C-9E3E-CDCEC296B0B5}.Debug|Any CPU.Build.0 = Debug|x64 - {662B5428-CC26-473C-9E3E-CDCEC296B0B5}.Debug|x64.ActiveCfg = Debug|x64 - {662B5428-CC26-473C-9E3E-CDCEC296B0B5}.Debug|x64.Build.0 = Debug|x64 - {662B5428-CC26-473C-9E3E-CDCEC296B0B5}.Debug|x86.ActiveCfg = Debug|Win32 - {662B5428-CC26-473C-9E3E-CDCEC296B0B5}.Debug|x86.Build.0 = Debug|Win32 - {662B5428-CC26-473C-9E3E-CDCEC296B0B5}.Release|Any CPU.ActiveCfg = Release|x64 - {662B5428-CC26-473C-9E3E-CDCEC296B0B5}.Release|Any CPU.Build.0 = Release|x64 - {662B5428-CC26-473C-9E3E-CDCEC296B0B5}.Release|x64.ActiveCfg = Release|x64 - {662B5428-CC26-473C-9E3E-CDCEC296B0B5}.Release|x64.Build.0 = Release|x64 - {662B5428-CC26-473C-9E3E-CDCEC296B0B5}.Release|x86.ActiveCfg = Release|Win32 - {662B5428-CC26-473C-9E3E-CDCEC296B0B5}.Release|x86.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/windows/coda/test/DllImportTest/DllImportTest/DllImportTest.csproj b/windows/coda/test/DllImportTest/DllImportTest/DllImportTest.csproj deleted file mode 100644 index 91b464afeacc1..0000000000000 --- a/windows/coda/test/DllImportTest/DllImportTest/DllImportTest.csproj +++ /dev/null @@ -1,10 +0,0 @@ - - - - Exe - net8.0 - enable - enable - - - diff --git a/windows/coda/test/DllImportTest/DllImportTest/Program.cs b/windows/coda/test/DllImportTest/DllImportTest/Program.cs deleted file mode 100644 index 130c2682d8c82..0000000000000 --- a/windows/coda/test/DllImportTest/DllImportTest/Program.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System.Runtime.InteropServices; - -public class DllImportTest -{ - public delegate void CallbackFunction1Delegate(int a, string s1, IntPtr s2, int s2length); - - [DllImport("DllImported.dll", CharSet = CharSet.Unicode)] - public static extern void set_callback_1(CallbackFunction1Delegate f); - - [DllImport("DllImported.dll", CharSet = CharSet.Unicode)] - public static extern void dllimport_function_1(int a, [MarshalAs(UnmanagedType.LPStr)] string s); - - public static void callbackFunction1(int a, string s1, IntPtr s2, int s2length) - { - Console.WriteLine($"Here is callbackFunction1, a={a}, s1='{s1}', s2='{Marshal.PtrToStringUTF8(s2, s2length)}'"); - Console.Write("s2 bytes:\""); - for (int i = 0; i < s2length; i++) - { - byte b = Marshal.ReadByte(s2, i); - if (b < ' ') - { - Console.Write("\\x"); - Console.Write(BitConverter.ToString([b])); - } - else - Console.Write((char)b); - } - Console.WriteLine("\""); - } - - static void Main(string[] args) - { - set_callback_1(callbackFunction1); - - Console.WriteLine("Hello"); - - dllimport_function_1(42, "HA HA"); - } -} diff --git a/windows/coda/test/DllImportTest/DllImportTest/Properties/launchSettings.json b/windows/coda/test/DllImportTest/DllImportTest/Properties/launchSettings.json deleted file mode 100644 index 3cce9c636a511..0000000000000 --- a/windows/coda/test/DllImportTest/DllImportTest/Properties/launchSettings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "profiles": { - "DllImportTest": { - "commandName": "Project", - "nativeDebugging": true - } - } -} \ No newline at end of file diff --git a/windows/coda/test/DllImportTest/DllImported/DllImported.vcxproj b/windows/coda/test/DllImportTest/DllImported/DllImported.vcxproj deleted file mode 100644 index 3983708d8c5a7..0000000000000 --- a/windows/coda/test/DllImportTest/DllImported/DllImported.vcxproj +++ /dev/null @@ -1,147 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 17.0 - Win32Proj - {662b5428-cc26-473c-9e3e-cdcec296b0b5} - DllImported - 10.0 - - - - DynamicLibrary - true - v143 - Unicode - - - DynamicLibrary - false - v143 - true - Unicode - - - DynamicLibrary - true - v143 - Unicode - - - DynamicLibrary - false - v143 - true - Unicode - - - - - - - - - - - - - - - - - - - - - $(SolutionDir)DllImportTest\bin/$(Configuration)\net8.0\ - - - $(SolutionDir)DllImportTest\bin/$(Configuration)\net8.0\ - - - - Level3 - true - WIN32;_DEBUG;DLLIMPORTED_EXPORTS;_USRDLL;%(PreprocessorDefinitions) - true - - - Windows - true - false - - - - - Level3 - true - true - true - WIN32;NDEBUG;DLLIMPORTED_EXPORTS;_USRDLL;%(PreprocessorDefinitions) - true - - - Windows - true - true - true - false - - - - - Level3 - true - _DEBUG;DLLIMPORTED_EXPORTS;_USRDLL;%(PreprocessorDefinitions) - true - stdcpp20 - - - Windows - true - false - - - - - Level3 - true - true - true - NDEBUG;DLLIMPORTED_EXPORTS;_USRDLL;%(PreprocessorDefinitions) - true - stdcpp20 - - - Windows - true - true - true - false - - - - - - - - - diff --git a/windows/coda/test/DllImportTest/DllImported/dllmain.cpp b/windows/coda/test/DllImportTest/DllImported/dllmain.cpp deleted file mode 100644 index 91363c25a8c30..0000000000000 --- a/windows/coda/test/DllImportTest/DllImported/dllmain.cpp +++ /dev/null @@ -1,16 +0,0 @@ -typedef void (*callback1)(int a, const char *s1, const char *s2, int s2len); - -static callback1 callback1_function; - -extern "C" __declspec(dllexport) -void set_callback_1(callback1 f) -{ - callback1_function = f; -} - -extern "C" __declspec(dllexport) -void dllimport_function_1(int a, const char *s) -{ - callback1_function(a + 1, s, "Zero:\0:There", 12); -} - From 1e8cc6d86cd0391eedc89ee9fe9b48232a9a2c7e Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 26 May 2025 14:59:49 +0200 Subject: [PATCH 175/177] coda-m: Remove the 'MODIFIED (true|false)' message again It is just the same as watching the .uno:ModifiedStatus state. Signed-off-by: Jan Holesovsky Change-Id: I9eccd051ed6539147caff14d8ad6955e4434cf26 --- browser/src/map/Map.js | 4 ---- macos/coda/coda/ViewController.swift | 12 ++++++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/browser/src/map/Map.js b/browser/src/map/Map.js index 2b89c353cdf2b..50892813dae14 100644 --- a/browser/src/map/Map.js +++ b/browser/src/map/Map.js @@ -241,10 +241,6 @@ window.L.Map = window.L.Evented.extend({ // Fire an event to let the client know whether the document needs saving or not. this.fire('postMessage', {msgId: 'Doc_ModifiedStatus', args: { Modified: e.state === 'true' }}); - if (window.ThisIsTheMacOSApp) { - window.postMobileMessage('MODIFIED ' + e.state); - } - if (this._everModified) { this.fire('updatemodificationindicator', { status: e.state === 'true' ? 'MODIFIED' : 'SAVED' }); } diff --git a/macos/coda/coda/ViewController.swift b/macos/coda/coda/ViewController.swift index a39b6032afb1c..fa35cf238cf86 100644 --- a/macos/coda/coda/ViewController.swift +++ b/macos/coda/coda/ViewController.swift @@ -127,16 +127,20 @@ class ViewController: NSViewController, WKScriptMessageHandlerWithReply, WKNavig let data = Data(jsonSlice.utf8) do { let state = try JSONDecoder().decode(CommandStateChange.self, from: data) + + // Has the modification state of the document changed? + // This is smportant for saving which has to copy the document from the temporary location. + if state.commandName == ".uno:ModifiedStatus" { + document?.isModified = (state.state == "true") + } + + // remember states of the commands for app menu handling if let windowController = view.window?.windowController as? WindowController { windowController.handleCommandStateChange(state) } } catch {} } } - else if body.hasPrefix("MODIFIED ") { - document?.isModified = body.hasSuffix("true") - return (nil, nil) - } else if body == "SLIDESHOW" { COWrapper.LOG_ERR("TODO: Implement slideshow") /* From 6be7f43aaf3fb49500e794310dc83e98744d5901 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 26 May 2025 16:53:25 +0200 Subject: [PATCH 176/177] coda-m: Fix crash when auto-saving non-modified document The completionHandler was called twice in that case. Signed-off-by: Jan Holesovsky Change-Id: Ifd0c23730045fad6b731db3005e419c0f159d02b --- macos/coda/coda/Document.swift | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/macos/coda/coda/Document.swift b/macos/coda/coda/Document.swift index 6a0b40a455184..8b099fe73c8dd 100644 --- a/macos/coda/coda/Document.swift +++ b/macos/coda/coda/Document.swift @@ -134,15 +134,17 @@ class Document: NSDocument { DispatchQueue.main.async { COWrapper.handleMessage(with: self, message: "save dontTerminateEdit=1 dontSaveIfUnmodified=1") } + + // FIXME would be much better to have handleMessage() with some kind of await or completion handler, + // and call the completionHandler() from there, so that we can be 100% sure the save has concluded + DispatchQueue.main.async { + completionHandler(nil) + } } else { // all is good, we can proceed with copying the data from COOL super.save(to: url, ofType: typeName, for: saveOperation, completionHandler: completionHandler) } - - DispatchQueue.main.async { - completionHandler(nil) - } } /** From 1eb4459746e630a2469f566a2d941c5dca3f6a72 Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Mon, 5 Jan 2026 11:27:16 +0100 Subject: [PATCH 177/177] ./g review should use --force-with-lease It is safer in case somebody pushed to the remote ref in the meantime. Signed-off-by: Jan Holesovsky Change-Id: I8e22929402d8aa18253241ff8952b83610c79a0b --- g | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/g b/g index 4856ec591a21f..d15368f400538 100755 --- a/g +++ b/g @@ -81,7 +81,7 @@ if [ "$1" == "review" ]; then exit 1 elif [ -n "$HAS_REMOTE_BRANCH" ] && [ -n "$CUSTOM_BRANCH" ]; then # PR is open, same branch is explicitly specified, just update it. - git push -f $REMOTE HEAD:$REMOTE_BRANCH + git push --force-with-lease $REMOTE HEAD:$REMOTE_BRANCH else # Open a new PR. git push $REMOTE HEAD:$REMOTE_BRANCH

~noTj9%`uuSu|S4aQ1lP6DJJ$diyse3oiKfHP2;fiPVu|QiGOM?7@862M7NCR@ZJY5_^EKaYz zd|Iekfv5H1gV;>z_infM{m(9AlPF!*wt3>){|A|vF793Z)*=0!LqFGbWu=nPH?e}Z zOBmkiANVC}S=GiN(A1)!=)ob>h7xl%P{$w_<|^(%RomlFnGH9xvX6m`!MG81G4Z8< ziyJs;FtV{x5(7;5l5UzX_%aBIG0|3x(LoYLTA)7%yx5|Y_I@vS7yDg0^`7VR>7~s* zzo*biC!N?zZfN2RND+1)^>J(!$_-790V}zax9&wrf|W-0;pLRT5dc!knYpza7ePoH z^_#`GfP?UUq9VblfWzSZL_vZv0Y}0630r~@0jd@`0vaNq#fiCwLd|1MK&@7jgM)(=&+}5V zVuKnQi_IqvhRNz6gfTQ63e5roq`|hT4Jym$nD4gj?94Zi~IzzYODZXap4pL8NaubXMRo=$jB6wm;FX?kz5&eC23s2+}bUgqw#g`Fo0 ztH~ZGjZpY>na^5)lH zpFSTxarzs`vm&M|GD-r#j0BrYQpy5AuLRp`a#{p{9tmMAN@^1TY7)X)mDMT$f=LK- zSz5aQXiq}e>+(hfKx-1hh6jTJpt*!7z=L4{@NWr{XuyL70njJ`xIgzM8t~Q=#XnAV c(#e0GUk~`+?q#HtH2?qr07*qoM6N<$f(D+Q^#A|> literal 0 HcmV?d00001 diff --git a/macos/coda/coda/Assets.xcassets/AppIcon.appiconset/icon_512x512.png b/macos/coda/coda/Assets.xcassets/AppIcon.appiconset/icon_512x512.png new file mode 100644 index 0000000000000000000000000000000000000000..c2f4f21bc2e5981194cbf036f35928f0c508cae2 GIT binary patch literal 6633 zcmbVRdt8k9_doNPFHc3y2wkX|rki5BTXZp_LWElSt~*64msMod=JGt!-K3CYSIuB| z%UX)HShq$og(!q9x)_(F+fZxNH1j*p)A#%P|M#2MtJj>@XWr-bIiJt@oO8+yoj+@Y zp`{@JjF=r1xB!4ak^pije)S~Q_u-d8T+otufVj`hABU6Q&BaBFtuq#HT^Jj+H6dcl zT1ZGpa9Ou$L;RYExV0{^TcUsJ^tD9Hw%LKx!xE2nyll#Oldz&nU31 zG5h<~jMMc-u|58_H;t}6FzU<=Q-~#NM4~Z|!d4%DU=-_>oENk%Q*t(Z?p2%bT2t-9 zhx3S++n%3$-eIzB-TTtQBZWueuQvESA8_}4_w@6p0d116OK{XXE3!XnSMApO1{^f< z|Nfzu?$o^eY!$R~h=jBmzEA+CHO+;xq^Fu+55>M5xZjl2vHhK(e^c9b`ho$p-Wb-U zt-tbZh2|`;!pdg&uCC66>s?d%@UtBV&z(~0FWl9~%;3UF1IUO;SIc-D$pQjI&(>%i z10h!mG#O>CH{gSv4anETOZ6!vBsqdSz-W-P2f1zVAZZKoA)jA--<0WQ?Q1i=71tuw2zT_oDXHRwUYAZ!Z#!oEX+}f zZ3z0l0Tcuzvqlwjp=NvwBS7v+KveDxmNX^c*XkI?)G{v)Y_E=E$x$4*Qk}?>ZXEC# zAI_3I4m@>Yv2K$&u*iwUx|wm{@MvGgnt~%hhu&huhC2}S+kbnpi*umvykQk%*Y=U% zb?OykjN%Lz=B*!;YRi$tTUs*CzK}p&-cT0$lm}iXT3G04f_5<1PY48_KQ1aXO%g5; z^kobEicE+(3i72&%9#%%Od;&Hrgkn@a)Jww-F5M%oH`*#@^7iWA`rZ0Lg)xpxfjCt z5Ozb8Fq12><-#pbT_M7NBY7aDyhPya2;=kBIrF)aTU?mop}WTCggS8~o267&AcO@$ z=qQy;O44^o$coS&H06ZyITF5<`Wk=qhg?6E%!&`Ac@WuAbfweB-LiDr82?LtyNK@$5yD6~ z7p^^pFdjj_mQvpb!YB#k=BZ2bNxH@W4!G+cn{sm9Ig*jeatjf7*h6cfI(8pP4>y3M zwc4NT385!JH=66;W`v1 z#6yH;72MGrwBUmk587{Q4m$B6cqFvr8s52JT&vbBB>7-85?&}Y3(b+@!SYJY!ts2F z9|_ANv`$A!dMXM2q*As%0}A#7!p8E!lLy(Jy0AH1#VA4^p_JXpgoZs3lcz4`i(s1# zSVn5sVRWrXT4_#M+7r#*gxp3cQ)a@YEQm=_r}L6YdIDE6L@H(?%7e$Ax-wh7crl$O2Ia-;St>mf%f5mV9rkR=jPG$oa`!*i5r1CbE4_vFFT3UUKsbyTn8SNC>!6N0(azEWc z%7F-X=1bzG(`RgBZ_L6>_;EGqeD*1G=?dm>>xSEg?q0$q0Y#VyuMJ&s&y%@?zmDXD z)%L@vPVJXZGDA#4H)E;pMO24L*Fa%c3h(PH<%YkxF;=H{Uey=Xr%Q$x=?p*bHrdhK zs7}<@pIuYcIH~JtqpnePG07hOd3^|edo!A@7%_Cu4I|g9-D9KgAN}%Hw2FFvh;ABa zYCZ%F*^7vh15mPuq%Q@+V?OlqIK0E8+?kNOh~O2P69DzIxRT`}+L@%iGa)0G8|upm zb>+k6OvrM8HU~oJ!k3)oN(KVqradwK0K^OmyTyl&L1E(w`B$v4Q2}s%P?(6Mzh;Hy z`f=)9SYhWJ;O{|U7r4N}BWD8>%Z5OB#)r8XjPBgg9K~Z+QFR(L)aBd0@|DJ$ZD zDYRqCKx2Q#EXHR%5n6B*m@*KCdA%T&b@Q4j)XZUFD-GZ+-X(M(mJ6RovaXvE^bA%P zuMon&VOaz1VR0JE`hbLdysgMEilALsSlv{PWD#ppYaYmhS%$4Mp>7gulD7?HOlNid zVgRdIlfs<{x`1U^TmZtaS=bm6v<_}tyeag|U>W`*q0f%drKsV;PP~tYNhV*9Vp$93 zKyDUm5@ze42Vt13PqLd@hPm39g>ex3&;d#Y zg&pIMGxagbHSfx9egMj$9YvJ4^~ z)ZyERuzgtZ;0uB#rE_6xFdGb80xml;C#DXyZf2dII2$CstOiWUc!H2Yk<5jgEUXMT zFu-nL!9k#PEJMw7kd(8!qU=CUv8*w-;_aQqvI(ZekeO<{*rApO}S%SU?*Yx>)xp}DRmL_1i zQt!cmFK#;CVRd;H(7xtW#$C;-Ss+PL3SN2We9(h@b^0Z#-h~T4uhH7LsLF?NU>yq! z!HSP!Vd!X`tIA}vh28?UH-}{y$Az9sMgujUfLET3hE+7sm!#sGYqe%rTUxUW_9SEs z!e(O>q8SZM7=@P}3`182(4DNVgdmViW?6k4Ap8ebE1!hL`xsr69RXulR>6LtZ?O!s z5Vnhj;Sq5Yu)2!ybQQ7;Ian+z8RN>Mu|Q;v3z2}Lk=0J*$#x&*QHVsv~9Ym&>XzCNHqi&ozLhPd;eU zc@;6fhQ+Q&hkx2JVpNSLdM?!c)>uWY{;vOC_ebUX8P~tcyQztu4|T^QRpQN?2IeMi z=>Idd+}a~rYb1o2c^}m#Ef2ehqu1j+Hs)N+?~4}(D9f>q%a3%|nf`PlJ8s)Rm?JeN zvO;5qg;v(@O6pa#S#7H9yP^+0wJCv8Dgu)bIw8pL(3wU*ou7K|!OT4I*re53BReQr zF-)a@6QdINlh0MBcJaWh+L`fj@!pIBM$I#HonB!SSMMCj|ze*eVH z9nb8V#zsYIC)hyA><8$p?p1J0_UT0j8sUnYZZsy@<5}wR$Z_|7_Zxj-rrAOPvB*=$ zEdY7g;~a{#kt(0J^rSilbS5mYSFOTioB5-;KJ(9x$(12b zLW-yDxnQnmUWrHbnh>+i9@?l$k9(iMDO%-YF;mr1 zUmQAF)r2jZledN5%_Uar=(6ug<+DE*o~)IxRF=CF^hhtU&a`xs&Q81W)ABaYk{op` zmg)&gy*Cq-y(hBkqeD$pP2=%>lj@BxR4r?%`J0Kxds-cf&+sB8WfJ?{wK4aBX2itwgqxvwrH_R&BCl`Moz+?c z8xlUA(`v*$hkTZzzu6r|Ew_5#Es#y0DitpxVM~P8Z0j!7t#0L$2`6iXlv1_<7sIuO zJ&dED6d5i%vG=5j%_^mAEC~xdbyf|Q-=)2KdM#M!Z(*j$i~$RJAX-aMnVfvhwAQ zsaG%j;L>Y>S#k+B!wxFh?sxx<1TS439YN5GrIf>eBT;_4&78`|R{4e|`t9k{Pb)%P zi!c%|-E|Y^VKJqWojm+x7v74dIXj2m_0(;}N8Mf}JNu1!>Z1*f_GNKO*?kf&;`jJU9GI40J>KYr|ktUv2D`i`n;@oi1zJ*`$N z1h+cV_Cz$4Z<#V~iJztM>Be!!CON-M%e-bm9Ulo3SHD+NnwHX}k2xEg?(B|B?2Van zX^Y*sl?WZ4lQO;SM8P4oqc=x!RZ69OJG3$`F)@CMm#?Mq8EfP8^s0)uW_@F-hpwlh ziC0spiH_j?V`7pPP-)vz*Bvv(7jeT)(we_qAF7l!k`T34Yr4eXR7-aoKjd?-r>^Ht zlc=Ub^Lecs*}up*&9?GHOWhk;)Aq};$?D<+f?g-30wPk*AERjSu4V0{hA9;J$0T1zApvW zwekIXPR**wD&8KoMteIMn%66-VNb;`1s2vulTWvY>>RV!Ll+qUZV_77WmfH1dUk!O z4BpfAzG$C0bxs82vAwvp`$gi0=(TRchka|D9&orR=3RC7;>9cea_U`DU!^%{#gQyj zQ3L42=;bQzx#KN{`LD^AJrGr(`Hq+DIWP&KK*k6_2GRHVNPWU;qL`EHKoJTTDrTV1XOUQRD7%Z z;(8wsEB!@Tr^yJ{Yp05G%6|z}%8p~BGjWoR8gSHW+ih3rmO84+FQ0QAxBRaj&eWpL zlNsvbDZ00(SDC4(=l)$?7gbeFNtcVgl`@e5eYw|LH%*s6)Pl;ghqloP+JqgK#pgAD zhFYsa9&javcv$=O8d=dm+oJ2c?rHip%Pys5j2 zt#gJ^ky@uhD7m{prEjp+e=h9OeSUw1`qEI^|IDv_qfd&OsjVEvvOeD8d?=|x*v%77 z`hSMVw53-}M&z`A=yNN%xs6oi>}pA;)@n~CS6%g<=% zQ>h!6(nRKLKv%rnTxBI*yj5HNMbOlbm6)Fe_1l}To*7QI&WRmi<7@4IX=hRCr`IM6 zasBOJ%j#*9@;Q}PbfkBKR6G|I6)gg1ck7&x6rQ!w!j%SYI=4gWVgo`hdL&Y4D#Mhr zD4hAUkKrfA!fN&0Br#}8sNskl9AJ8!7KU3WeR!rCwR#Qw0!ts#jbTb|Wll%!nEMN3{b;2i8Dg?XP??w#a(5A(W_%!fl;M11x>P(-0%a5U5)M*9Q0B;&D3O{DZih%LY6SVr z?1mKDDh1v`oB@);AxPmAXD=zVQJGkcgqnHWTw0xuoy8at(YjxqPIAG>l+&Zo1lSSu zFBu@hVs<}-uM^RvR2+yirW8_+f^nYIDkbG84*QwbJTlw>DV#eUCBrcoIE%{g=eiA3 znHVtBPfiVr!$z+p5VpJNa`BD!<|~Y)VmlO^DFv1yDA`9Y#*?8W;Wsl znUQTao>wZ?^H5oD)XS1jFlWsc2J{;|y@+G9=GAtuLIWw?!Y!*vgaLMfu(083P zaj6Dd&wm@{Fw|U7d~e9WYG#1K*l;i1G2MK}>;GH^dJ72+Gi>kCj1Zg_^)z2*7`70Qw8e?|w%na;*`+dp5nsBmbou1=G5>)1e|&